blob: 822a43b63dd795126e5c7b23e239f2e06e74b781 [file] [log] [blame]
Björn Stenberg32125d42002-05-13 15:23:30 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 Daniel Stenberg
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +000019
Daniel Stenberged6c7e42002-06-14 11:00:13 +000020#include <stdio.h>
21#include <stdlib.h>
22#include <string.h>
Daniel Stenberg22b77012005-02-22 12:19:12 +000023#include <stdarg.h>
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +000024#include <sys/stat.h>
Peter D'Hoyef0ed5942007-04-06 23:54:21 +000025#include <time.h>
Björn Stenbergf6ed9702003-07-04 08:30:01 +000026#ifdef __FreeBSD__
27#include <sys/param.h>
28#include <sys/mount.h>
Barry Wardell64f949f2006-09-29 16:15:11 +000029#elif defined(__APPLE__)
30#include <sys/param.h>
31#include <sys/mount.h>
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +000032#elif !defined(WIN32)
Björn Stenberg6fb512a2002-11-12 11:32:26 +000033#include <sys/vfs.h>
Björn Stenbergf6ed9702003-07-04 08:30:01 +000034#endif
Hardeep Sidhufb26bfb2004-06-14 07:00:50 +000035
Daniel Stenberg22b77012005-02-22 12:19:12 +000036#ifdef WIN32
37#include <windows.h>
38#endif
39
Hardeep Sidhufb26bfb2004-06-14 07:00:50 +000040#ifndef _MSC_VER
Daniel Stenberge3a12d32002-05-07 12:25:30 +000041#include <dirent.h>
Björn Stenberg2ba4fed2003-01-28 23:14:41 +000042#include <unistd.h>
Hardeep Sidhufb26bfb2004-06-14 07:00:50 +000043#else
44#include "dir-win32.h"
45#endif
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +000046
Daniel Stenberg22b77012005-02-22 12:19:12 +000047#define MAX_PATH 260
Nicolas Pennequinef9abe42007-10-09 15:15:00 +000048#define MAX_OPEN_FILES 11
Daniel Stenberg22b77012005-02-22 12:19:12 +000049
Daniel Stenberged6c7e42002-06-14 11:00:13 +000050#include <fcntl.h>
Michael Sevakisf64ebb12007-09-08 12:20:53 +000051#include <SDL.h>
52#include <SDL_thread.h>
53#include "thread.h"
54#include "kernel.h"
Daniel Stenberged6c7e42002-06-14 11:00:13 +000055#include "debug.h"
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +000056#include "config.h"
Jens Arnold51280802007-09-13 20:53:32 +000057#include "ata.h" /* for IF_MV2 et al. */
Michael Sevakisa4d19b72007-12-03 14:01:12 +000058#include "thread-sdl.h"
59
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +000060
Jens Arnold67eb1542007-02-01 23:08:15 +000061/* Windows (and potentially other OSes) distinguish binary and text files.
62 * Define a dummy for the others. */
63#ifndef O_BINARY
64#define O_BINARY 0
65#endif
66
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000067/* Unicode compatibility for win32 */
68#if defined __MINGW32__
69/* Rockbox unicode functions */
70extern const unsigned char* utf8decode(const unsigned char *utf8,
71 unsigned short *ucs);
72extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
73
Jens Arnold49be3fa2007-04-20 17:35:05 +000074/* Static buffers for the conversion results. This isn't thread safe,
75 * but it's sufficient for rockbox. */
76static unsigned char convbuf1[3*MAX_PATH];
77static unsigned char convbuf2[3*MAX_PATH];
78
79static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000080{
Jens Arnold49be3fa2007-04-20 17:35:05 +000081 wchar_t *ucs = buffer;
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000082
83 while (*utf8)
84 utf8 = utf8decode(utf8, ucs++);
Steve Bavinf87eb602007-11-08 12:11:34 +000085
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000086 *ucs = 0;
Jens Arnold49be3fa2007-04-20 17:35:05 +000087 return buffer;
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000088}
Jens Arnold49be3fa2007-04-20 17:35:05 +000089static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000090{
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000091 unsigned char *utf8 = buffer;
Jens Arnold49be3fa2007-04-20 17:35:05 +000092
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000093 while (*ucs)
94 utf8 = utf8encode(*ucs++, utf8);
Steve Bavinf87eb602007-11-08 12:11:34 +000095
Jens Arnold2fd7c3c2007-04-19 20:17:24 +000096 *utf8 = 0;
97 return buffer;
98}
99
Jens Arnold49be3fa2007-04-20 17:35:05 +0000100#define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
101#define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000102#define DIR_T _WDIR
103#define DIRENT_T struct _wdirent
104#define STAT_T struct _stat
105extern int _wmkdir(const wchar_t*);
106extern int _wrmdir(const wchar_t*);
107#define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
108#define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
109#define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
110#define READDIR(a) (_wreaddir)(a)
111#define CLOSEDIR(a) (_wclosedir)(a)
112#define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
113#define OPEN(a,b,c) (_wopen)(UTF8_TO_OS(a),b,c)
Jonas Häggqvistb24631c2007-10-09 17:51:02 +0000114#define CLOSE(a) (close)(a)
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000115#define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
Jens Arnold49be3fa2007-04-20 17:35:05 +0000116#define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000117
118#else /* !__MINGW32__ */
119
120#define UTF8_TO_OS(a) (a)
121#define OS_TO_UTF8(a) (a)
122#define DIR_T DIR
123#define DIRENT_T struct dirent
124#define STAT_T struct stat
125#define MKDIR(a,b) (mkdir)(a,b)
126#define RMDIR(a) (rmdir)(a)
127#define OPENDIR(a) (opendir)(a)
128#define READDIR(a) (readdir)(a)
129#define CLOSEDIR(a) (closedir)(a)
130#define STAT(a,b) (stat)(a,b)
131#define OPEN(a,b,c) (open)(a,b,c)
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000132#define CLOSE(x) (close)(x)
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000133#define REMOVE(a) (remove)(a)
134#define RENAME(a,b) (rename)(a,b)
135
136#endif /* !__MINGW32__ */
137
138
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +0000139#ifdef HAVE_DIRCACHE
140void dircache_remove(const char *name);
141void dircache_rename(const char *oldpath, const char *newpath);
142#endif
Daniel Stenberged6c7e42002-06-14 11:00:13 +0000143
Steve Bavin9e05cc52007-11-08 10:15:44 +0000144
145#define SIMULATOR_DEFAULT_ROOT "archos"
146extern const char *sim_root_dir;
Daniel Stenberge3a12d32002-05-07 12:25:30 +0000147
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000148static int num_openfiles = 0;
149
Daniel Stenberg22b77012005-02-22 12:19:12 +0000150struct sim_dirent {
151 unsigned char d_name[MAX_PATH];
152 int attribute;
Jens Arnoldd6cb7162007-04-07 00:14:16 +0000153 long size;
154 long startcluster;
Steve Bavinf87eb602007-11-08 12:11:34 +0000155 unsigned short wrtdate; /* Last write date */
Daniel Stenberg22b77012005-02-22 12:19:12 +0000156 unsigned short wrttime; /* Last write time */
157};
158
159struct dirstruct {
160 void *dir; /* actually a DIR* dir */
Steve Bavinf87eb602007-11-08 12:11:34 +0000161 char *name;
Daniel Stenberg22b77012005-02-22 12:19:12 +0000162} SIM_DIR;
163
Daniel Stenberge3a12d32002-05-07 12:25:30 +0000164struct mydir {
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000165 DIR_T *dir;
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000166 char *name;
Daniel Stenberge3a12d32002-05-07 12:25:30 +0000167};
168
169typedef struct mydir MYDIR;
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +0000170
Jens Arnold527e1212005-02-24 23:11:21 +0000171#if 1 /* maybe this needs disabling for MSVC... */
Daniel Stenberg36c9a952004-06-14 22:22:49 +0000172static unsigned int rockbox2sim(int opt)
173{
Linus Nielsen Feltzingfc72c532006-02-03 15:19:58 +0000174 int newopt = O_BINARY;
Jens Arnold67eb1542007-02-01 23:08:15 +0000175
Daniel Stenberg36c9a952004-06-14 22:22:49 +0000176 if(opt & 1)
177 newopt |= O_WRONLY;
178 if(opt & 2)
179 newopt |= O_RDWR;
180 if(opt & 4)
181 newopt |= O_CREAT;
182 if(opt & 8)
183 newopt |= O_APPEND;
184 if(opt & 0x10)
185 newopt |= O_TRUNC;
186
187 return newopt;
188}
Linus Nielsen Feltzingb6f67a82004-07-08 05:50:20 +0000189#endif
Daniel Stenberg36c9a952004-06-14 22:22:49 +0000190
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000191/** Simulator I/O engine routines **/
Michael Sevakis6a058832007-12-03 15:33:12 +0000192#define IO_YIELD_THRESHOLD 512
193
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000194enum
195{
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000196 IO_READ,
197 IO_WRITE,
198};
199
200struct sim_io
201{
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000202 struct mutex sim_mutex; /* Rockbox mutex */
Michael Sevakis6a058832007-12-03 15:33:12 +0000203 int cmd; /* The command to perform */
204 int ready; /* I/O ready flag - 1= ready */
205 int fd; /* The file to read/write */
206 void *buf; /* The buffer to read/write */
207 size_t count; /* Number of bytes to read/write */
208 size_t accum; /* Acculated bytes transferred */
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000209};
210
211static struct sim_io io;
212
Michael Sevakisc4a76312007-09-10 03:49:12 +0000213int ata_init(void)
214{
215 /* Initialize the rockbox kernel objects on a rockbox thread */
216 mutex_init(&io.sim_mutex);
Michael Sevakis6a058832007-12-03 15:33:12 +0000217 io.accum = 0;
Michael Sevakisc4a76312007-09-10 03:49:12 +0000218 return 1;
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000219}
220
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000221static ssize_t io_trigger_and_wait(int cmd)
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000222{
Michael Sevakis6a058832007-12-03 15:33:12 +0000223 void *mythread = NULL;
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000224 ssize_t result;
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000225
Michael Sevakis6a058832007-12-03 15:33:12 +0000226 if (io.count > IO_YIELD_THRESHOLD ||
227 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
228 {
229 /* Allow other rockbox threads to run */
230 io.accum = 0;
231 mythread = thread_sdl_thread_unlock();
232 }
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000233
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000234 switch (cmd)
235 {
236 case IO_READ:
237 result = read(io.fd, io.buf, io.count);
238 break;
239 case IO_WRITE:
240 result = write(io.fd, io.buf, io.count);
241 break;
242 }
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000243
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000244 /* Regain our status as current */
Michael Sevakis6a058832007-12-03 15:33:12 +0000245 if (mythread != NULL)
246 {
247 thread_sdl_thread_lock(mythread);
248 }
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000249
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000250 return result;
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000251}
252
Steve Bavin9e05cc52007-11-08 10:15:44 +0000253static const char *get_sim_rootdir()
254{
255 if (sim_root_dir != NULL)
256 return sim_root_dir;
257 return SIMULATOR_DEFAULT_ROOT;
258}
259
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000260MYDIR *sim_opendir(const char *name)
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +0000261{
Peter D'Hoye6be61562007-04-12 22:38:54 +0000262 char buffer[MAX_PATH]; /* sufficiently big */
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000263 DIR_T *dir;
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +0000264
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000265#ifndef __PCTOOL__
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000266 if(name[0] == '/')
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000267 {
Steve Bavin9e05cc52007-11-08 10:15:44 +0000268 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000269 dir=(DIR_T *)OPENDIR(buffer);
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000270 }
271 else
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000272#endif
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000273 dir=(DIR_T *)OPENDIR(name);
274
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000275 if(dir) {
276 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
277 my->dir = dir;
278 my->name = (char *)strdup(name);
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000279
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000280 return my;
281 }
282 /* failed open, return NULL */
283 return (MYDIR *)0;
Daniel Stenberg7b3abdc2002-04-30 13:14:59 +0000284}
Daniel Stenberg91f165e2002-05-05 10:28:23 +0000285
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000286struct sim_dirent *sim_readdir(MYDIR *dir)
Daniel Stenberg159d4482002-05-07 11:35:03 +0000287{
Steve Bavinf87eb602007-11-08 12:11:34 +0000288 char buffer[MAX_PATH]; /* sufficiently big */
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000289 static struct sim_dirent secret;
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000290 STAT_T s;
291 DIRENT_T *x11 = READDIR(dir->dir);
Peter D'Hoye832e0df2007-04-06 23:33:33 +0000292 struct tm* tm;
Daniel Stenberg159d4482002-05-07 11:35:03 +0000293
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000294 if(!x11)
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000295 return (struct sim_dirent *)0;
Daniel Stenberg159d4482002-05-07 11:35:03 +0000296
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000297 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000298
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000299 /* build file name */
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000300#ifdef __PCTOOL__
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000301 snprintf(buffer, sizeof(buffer), "%s/%s", dir->name, secret.d_name);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000302#else
Steve Bavin9e05cc52007-11-08 10:15:44 +0000303 snprintf(buffer, sizeof(buffer), "%s/%s/%s",
304 get_sim_rootdir(), dir->name, secret.d_name);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000305#endif
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000306 STAT(buffer, &s); /* get info */
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000307
Daniel Stenberg22b77012005-02-22 12:19:12 +0000308#define ATTR_DIRECTORY 0x10
Steve Bavinf87eb602007-11-08 12:11:34 +0000309
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000310 secret.attribute = S_ISDIR(s.st_mode)?ATTR_DIRECTORY:0;
311 secret.size = s.st_size;
Daniel Stenberg159d4482002-05-07 11:35:03 +0000312
Peter D'Hoye832e0df2007-04-06 23:33:33 +0000313 tm = localtime(&(s.st_mtime));
314 secret.wrtdate = ((tm->tm_year - 80) << 9) |
315 ((tm->tm_mon + 1) << 5) |
316 tm->tm_mday;
317 secret.wrttime = (tm->tm_hour << 11) |
318 (tm->tm_min << 5) |
319 (tm->tm_sec >> 1);
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000320 return &secret;
Daniel Stenberg159d4482002-05-07 11:35:03 +0000321}
322
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000323void sim_closedir(MYDIR *dir)
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000324{
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000325 free(dir->name);
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000326 CLOSEDIR(dir->dir);
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000327
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000328 free(dir);
Daniel Stenberg27dfc7c2002-05-07 12:06:32 +0000329}
330
Daniel Stenberg36c9a952004-06-14 22:22:49 +0000331int sim_open(const char *name, int o)
Daniel Stenberg91f165e2002-05-05 10:28:23 +0000332{
Peter D'Hoye6be61562007-04-12 22:38:54 +0000333 char buffer[MAX_PATH]; /* sufficiently big */
Daniel Stenberg36c9a952004-06-14 22:22:49 +0000334 int opts = rockbox2sim(o);
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000335 int ret;
336
337 if (num_openfiles >= MAX_OPEN_FILES)
338 return -2;
Daniel Stenberg91f165e2002-05-05 10:28:23 +0000339
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000340#ifndef __PCTOOL__
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000341 if(name[0] == '/')
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000342 {
Steve Bavin9e05cc52007-11-08 10:15:44 +0000343 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
Jens Arnold399c0812005-02-28 18:32:57 +0000344
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000345 debugf("We open the real file '%s'\n", buffer);
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000346 if (num_openfiles < MAX_OPEN_FILES)
347 {
348 ret = OPEN(buffer, opts, 0666);
349 if (ret >= 0) num_openfiles++;
350 return ret;
351 }
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000352 }
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000353
Daniel Stenberg56e63352004-06-14 22:32:13 +0000354 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n",
355 name);
356 return -1;
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000357#else
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000358 if (num_openfiles < MAX_OPEN_FILES)
359 {
360 ret = OPEN(buffer, opts, 0666);
361 if (ret >= 0) num_openfiles++;
362 return ret;
363 }
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000364#endif
Nicolas Pennequinef9abe42007-10-09 15:15:00 +0000365}
366
367int sim_close(int fd)
368{
369 int ret;
370 ret = CLOSE(fd);
371 if (ret == 0) num_openfiles--;
372 return ret;
Daniel Stenberg91f165e2002-05-05 10:28:23 +0000373}
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000374
Jens Arnold67eb1542007-02-01 23:08:15 +0000375int sim_creat(const char *name)
Björn Stenbergc78e1b02003-01-09 00:55:00 +0000376{
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000377#ifndef __PCTOOL__
Peter D'Hoye6be61562007-04-12 22:38:54 +0000378 char buffer[MAX_PATH]; /* sufficiently big */
Jens Arnold67eb1542007-02-01 23:08:15 +0000379 if(name[0] == '/')
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000380 {
Steve Bavin9e05cc52007-11-08 10:15:44 +0000381 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
Steve Bavinf87eb602007-11-08 12:11:34 +0000382
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000383 debugf("We create the real file '%s'\n", buffer);
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000384 return OPEN(buffer, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000385 }
Peter D'Hoye6be61562007-04-12 22:38:54 +0000386 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
Daniel Stenberg56e63352004-06-14 22:32:13 +0000387 return -1;
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000388#else
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000389 return OPEN(name, O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, 0666);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000390#endif
Steve Bavinf87eb602007-11-08 12:11:34 +0000391}
Björn Stenbergc78e1b02003-01-09 00:55:00 +0000392
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000393ssize_t sim_read(int fd, void *buf, size_t count)
394{
395 ssize_t result;
396
397 mutex_lock(&io.sim_mutex);
398
399 /* Setup parameters */
400 io.fd = fd;
401 io.buf = buf;
402 io.count = count;
403
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000404 result = io_trigger_and_wait(IO_READ);
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000405
406 mutex_unlock(&io.sim_mutex);
407
408 return result;
409}
410
411ssize_t sim_write(int fd, const void *buf, size_t count)
412{
413 ssize_t result;
414
415 mutex_lock(&io.sim_mutex);
416
417 io.fd = fd;
418 io.buf = (void*)buf;
419 io.count = count;
420
Michael Sevakisa4d19b72007-12-03 14:01:12 +0000421 result = io_trigger_and_wait(IO_WRITE);
Michael Sevakisf64ebb12007-09-08 12:20:53 +0000422
423 mutex_unlock(&io.sim_mutex);
424
425 return result;
426}
427
Jens Arnold6b0fdae2007-02-03 10:28:55 +0000428int sim_mkdir(const char *name)
Linus Nielsen Feltzingef7293f2004-01-21 14:58:40 +0000429{
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000430#ifdef __PCTOOL__
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000431 return MKDIR(name, 0777);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000432#else
Peter D'Hoye6be61562007-04-12 22:38:54 +0000433 char buffer[MAX_PATH]; /* sufficiently big */
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000434
Steve Bavin9e05cc52007-11-08 10:15:44 +0000435 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
Peter D'Hoye6be61562007-04-12 22:38:54 +0000436
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000437 debugf("We create the real directory '%s'\n", buffer);
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000438 return MKDIR(buffer, 0777);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000439#endif
Linus Nielsen Feltzingef7293f2004-01-21 14:58:40 +0000440}
441
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000442int sim_rmdir(const char *name)
Linus Nielsen Feltzing8fa821d2004-04-16 09:24:38 +0000443{
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000444#ifdef __PCTOOL__
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000445 return RMDIR(name);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000446#else
Peter D'Hoye6be61562007-04-12 22:38:54 +0000447 char buffer[MAX_PATH]; /* sufficiently big */
Steve Bavinf87eb602007-11-08 12:11:34 +0000448 if(name[0] == '/')
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000449 {
Steve Bavin9e05cc52007-11-08 10:15:44 +0000450 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
Peter D'Hoye6be61562007-04-12 22:38:54 +0000451
Linus Nielsen Feltzing8fa821d2004-04-16 09:24:38 +0000452 debugf("We remove the real directory '%s'\n", buffer);
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000453 return RMDIR(buffer);
Linus Nielsen Feltzing8fa821d2004-04-16 09:24:38 +0000454 }
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000455 return RMDIR(name);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000456#endif
Linus Nielsen Feltzing8fa821d2004-04-16 09:24:38 +0000457}
458
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000459int sim_remove(const char *name)
Björn Stenbergc78e1b02003-01-09 00:55:00 +0000460{
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000461#ifdef __PCTOOL__
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000462 return REMOVE(name);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000463#else
Peter D'Hoye6be61562007-04-12 22:38:54 +0000464 char buffer[MAX_PATH]; /* sufficiently big */
Björn Stenbergc78e1b02003-01-09 00:55:00 +0000465
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +0000466#ifdef HAVE_DIRCACHE
467 dircache_remove(name);
468#endif
469
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000470 if(name[0] == '/') {
Steve Bavin9e05cc52007-11-08 10:15:44 +0000471 snprintf(buffer, sizeof(buffer), "%s%s", get_sim_rootdir(), name);
Björn Stenbergc78e1b02003-01-09 00:55:00 +0000472
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000473 debugf("We remove the real file '%s'\n", buffer);
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000474 return REMOVE(buffer);
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000475 }
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000476 return REMOVE(name);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000477#endif
Björn Stenbergc78e1b02003-01-09 00:55:00 +0000478}
479
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000480int sim_rename(const char *oldpath, const char* newpath)
Björn Stenberg7d80ba02003-01-15 11:38:03 +0000481{
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000482#ifdef __PCTOOL__
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000483 return RENAME(oldpath, newpath);
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000484#else
Peter D'Hoye6be61562007-04-12 22:38:54 +0000485 char buffer1[MAX_PATH];
486 char buffer2[MAX_PATH];
Björn Stenberg7d80ba02003-01-15 11:38:03 +0000487
Miika Pekkarinend70bd0e2006-08-26 14:19:18 +0000488#ifdef HAVE_DIRCACHE
489 dircache_rename(oldpath, newpath);
490#endif
491
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000492 if(oldpath[0] == '/') {
Steve Bavin9e05cc52007-11-08 10:15:44 +0000493 snprintf(buffer1, sizeof(buffer1), "%s%s", get_sim_rootdir(),
Peter D'Hoye6be61562007-04-12 22:38:54 +0000494 oldpath);
Steve Bavin9e05cc52007-11-08 10:15:44 +0000495 snprintf(buffer2, sizeof(buffer2), "%s%s", get_sim_rootdir(),
Peter D'Hoye6be61562007-04-12 22:38:54 +0000496 newpath);
Björn Stenberg7d80ba02003-01-15 11:38:03 +0000497
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000498 debugf("We rename the real file '%s' to '%s'\n", buffer1, buffer2);
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000499 return RENAME(buffer1, buffer2);
Daniel Stenberg11d9ecb2003-03-05 22:59:36 +0000500 }
501 return -1;
Miika Pekkarinen0dd7ea22006-11-10 08:03:33 +0000502#endif
Björn Stenberg7d80ba02003-01-15 11:38:03 +0000503}
504
Jens Arnold399c0812005-02-28 18:32:57 +0000505/* rockbox off_t may be different from system off_t */
506long sim_lseek(int fildes, long offset, int whence)
Linus Nielsen Feltzinge98bad52003-03-18 00:39:57 +0000507{
Jens Arnold399c0812005-02-28 18:32:57 +0000508 return lseek(fildes, offset, whence);
509}
510
511long sim_filesize(int fd)
512{
Jens Arnoldbb9dfa02005-03-09 19:26:59 +0000513#ifdef WIN32
514 return _filelength(fd);
515#else
516 struct stat buf;
Steve Bavinf87eb602007-11-08 12:11:34 +0000517
Jens Arnoldbb9dfa02005-03-09 19:26:59 +0000518 if (!fstat(fd, &buf))
519 return buf.st_size;
520 else
521 return -1;
522#endif
Linus Nielsen Feltzinge98bad52003-03-18 00:39:57 +0000523}
524
Jens Arnold51280802007-09-13 20:53:32 +0000525void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000526{
Jens Arnold51280802007-09-13 20:53:32 +0000527#ifdef HAVE_MULTIVOLUME
528 if (volume != 0) {
529 debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",
530 volume);
Steve Bavinf87eb602007-11-08 12:11:34 +0000531
Jens Arnold51280802007-09-13 20:53:32 +0000532 if (size) *size = 0;
533 if (free) *free = 0;
534 return;
535 }
536#endif
537
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000538#ifdef WIN32
Jens Arnold78724262005-02-22 21:55:48 +0000539 long secperclus, bytespersec, free_clusters, num_clusters;
540
541 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
542 &num_clusters)) {
543 if (size)
544 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
545 if (free)
546 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
547 }
Linus Nielsen Feltzinga6142ab2004-06-10 13:29:52 +0000548#else
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000549 struct statfs fs;
550
551 if (!statfs(".", &fs)) {
Jens Arnoldbd5c0ad2007-03-17 10:50:58 +0000552 DEBUGF("statfs: bsize=%d blocks=%ld free=%ld\n",
553 (int)fs.f_bsize, fs.f_blocks, fs.f_bfree);
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000554 if (size)
555 *size = fs.f_blocks * (fs.f_bsize / 1024);
556 if (free)
557 *free = fs.f_bfree * (fs.f_bsize / 1024);
558 }
Jens Arnold78724262005-02-22 21:55:48 +0000559#endif
Björn Stenberg6fb512a2002-11-12 11:32:26 +0000560 else {
561 if (size)
562 *size = 0;
563 if (free)
564 *free = 0;
565 }
566}
Daniel Stenberg22b77012005-02-22 12:19:12 +0000567
568int sim_fsync(int fd)
569{
570#ifdef WIN32
571 return _commit(fd);
572#else
573 return fsync(fd);
574#endif
575}
576
577#ifdef WIN32
578/* sim-win32 */
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000579#define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
Jens Arnoldcf208c52005-02-22 18:21:16 +0000580#define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
Daniel Stenberg22b77012005-02-22 12:19:12 +0000581#define dlclose(_x_) FreeLibrary(_x_)
Daniel Stenberg22b77012005-02-22 12:19:12 +0000582#else
583/* sim-x11 */
584#include <dlfcn.h>
585#endif
586
Hardeep Sidhu25377db2006-06-17 09:42:16 +0000587#define TEMP_CODEC_FILE "archos/_temp_codec%d.dll"
588
Nicolas Pennequinc70671b2007-11-02 17:43:37 +0000589void *sim_codec_load_ram(char* codecptr, int size, void **pd)
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000590{
Jens Arnold38b75472006-03-02 01:08:38 +0000591 void *hdr;
Hardeep Sidhu25377db2006-06-17 09:42:16 +0000592 char path[MAX_PATH];
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000593 int fd;
Steve Bavin8c9d5f32006-09-28 08:46:28 +0000594 int codec_count;
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000595#ifdef WIN32
Peter D'Hoye6be61562007-04-12 22:38:54 +0000596 char buf[MAX_PATH];
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000597#endif
598
Jens Arnold38b75472006-03-02 01:08:38 +0000599 *pd = NULL;
Jens Arnoldb8749fd2006-01-18 00:05:14 +0000600
Steve Bavinf87eb602007-11-08 12:11:34 +0000601 /* We have to create the dynamic link library file from ram so we
Steve Bavin8c9d5f32006-09-28 08:46:28 +0000602 can simulate the codec loading. With voice and crossfade,
Steve Bavinf87eb602007-11-08 12:11:34 +0000603 multiple codecs may be loaded at the same time, so we need
Steve Bavin8c9d5f32006-09-28 08:46:28 +0000604 to find an unused filename */
605 for (codec_count = 0; codec_count < 10; codec_count++)
606 {
Peter D'Hoye6be61562007-04-12 22:38:54 +0000607 snprintf(path, sizeof(path), TEMP_CODEC_FILE, codec_count);
Jens Arnoldb8749fd2006-01-18 00:05:14 +0000608
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000609 fd = OPEN(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, S_IRWXU);
Steve Bavin8c9d5f32006-09-28 08:46:28 +0000610 if (fd >= 0)
611 break; /* Created a file ok */
612 }
Jens Arnold67eb1542007-02-01 23:08:15 +0000613 if (fd < 0)
Steve Bavin8c9d5f32006-09-28 08:46:28 +0000614 {
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000615 DEBUGF("failed to open for write: %s\n", path);
616 return NULL;
617 }
618
Nicolas Pennequinc70671b2007-11-02 17:43:37 +0000619 if (write(fd, codecptr, size) != size) {
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000620 DEBUGF("write failed");
621 return NULL;
622 }
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000623 close(fd);
Jens Arnoldb8749fd2006-01-18 00:05:14 +0000624
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000625 /* Now load the library. */
Jens Arnold38b75472006-03-02 01:08:38 +0000626 *pd = dlopen(path, RTLD_NOW);
627 if (*pd == NULL) {
Steve Bavinf87eb602007-11-08 12:11:34 +0000628 DEBUGF("failed to load %s\n", path);
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000629#ifdef WIN32
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000630 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
631 buf, sizeof buf, NULL);
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000632 DEBUGF("dlopen(%s): %s\n", path, buf);
633#else
634 DEBUGF("dlopen(%s): %s\n", path, dlerror());
635#endif
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000636 return NULL;
637 }
638
Jens Arnold38b75472006-03-02 01:08:38 +0000639 hdr = dlsym(*pd, "__header");
Jens Arnoldb8749fd2006-01-18 00:05:14 +0000640 if (!hdr)
Jens Arnold38b75472006-03-02 01:08:38 +0000641 hdr = dlsym(*pd, "___header");
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000642
Jens Arnoldb8749fd2006-01-18 00:05:14 +0000643 return hdr; /* maybe NULL if symbol not present */
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000644}
645
Jens Arnold38b75472006-03-02 01:08:38 +0000646void sim_codec_close(void *pd)
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000647{
Jens Arnold38b75472006-03-02 01:08:38 +0000648 dlclose(pd);
Miika Pekkarinen645a2e12005-07-10 16:33:03 +0000649}
650
Jens Arnold38b75472006-03-02 01:08:38 +0000651void *sim_plugin_load(char *plugin, void **pd)
Daniel Stenberg22b77012005-02-22 12:19:12 +0000652{
Jens Arnold38b75472006-03-02 01:08:38 +0000653 void *hdr;
Peter D'Hoye6be61562007-04-12 22:38:54 +0000654 char path[MAX_PATH];
Jens Arnoldcf208c52005-02-22 18:21:16 +0000655#ifdef WIN32
Peter D'Hoye6be61562007-04-12 22:38:54 +0000656 char buf[MAX_PATH];
Jens Arnoldcf208c52005-02-22 18:21:16 +0000657#endif
658
Peter D'Hoye6be61562007-04-12 22:38:54 +0000659 snprintf(path, sizeof(path), "archos%s", plugin);
660
Jens Arnold38b75472006-03-02 01:08:38 +0000661 *pd = NULL;
Jens Arnolda7902772006-01-16 23:20:58 +0000662
Jens Arnold38b75472006-03-02 01:08:38 +0000663 *pd = dlopen(path, RTLD_NOW);
664 if (*pd == NULL) {
Jens Arnoldcf208c52005-02-22 18:21:16 +0000665 DEBUGF("failed to load %s\n", plugin);
666#ifdef WIN32
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000667 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
668 buf, sizeof(buf), NULL);
Jens Arnoldcf208c52005-02-22 18:21:16 +0000669 DEBUGF("dlopen(%s): %s\n", path, buf);
670#else
671 DEBUGF("dlopen(%s): %s\n", path, dlerror());
672#endif
Daniel Stenberg22b77012005-02-22 12:19:12 +0000673 return NULL;
674 }
675
Jens Arnold38b75472006-03-02 01:08:38 +0000676 hdr = dlsym(*pd, "__header");
Jens Arnolda7902772006-01-16 23:20:58 +0000677 if (!hdr)
Jens Arnold38b75472006-03-02 01:08:38 +0000678 hdr = dlsym(*pd, "___header");
Jens Arnolda7902772006-01-16 23:20:58 +0000679
Jens Arnolda7902772006-01-16 23:20:58 +0000680 return hdr; /* maybe NULL if symbol not present */
Daniel Stenberg22b77012005-02-22 12:19:12 +0000681}
682
Jens Arnold38b75472006-03-02 01:08:38 +0000683void sim_plugin_close(void *pd)
Daniel Stenberg22b77012005-02-22 12:19:12 +0000684{
Jens Arnold38b75472006-03-02 01:08:38 +0000685 dlclose(pd);
Daniel Stenberg22b77012005-02-22 12:19:12 +0000686}
687
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000688#ifdef WIN32
689static unsigned old_cp;
Daniel Stenberg22b77012005-02-22 12:19:12 +0000690
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000691void debug_exit(void)
692{
693 /* Reset console output codepage */
694 SetConsoleOutputCP(old_cp);
695}
696
697void debug_init(void)
698{
699 old_cp = GetConsoleOutputCP();
700 /* Set console output codepage to UTF8. Only works
701 * correctly when the console uses a truetype font. */
702 SetConsoleOutputCP(65001);
703 atexit(debug_exit);
704}
705#else
Daniel Stenberg22b77012005-02-22 12:19:12 +0000706void debug_init(void)
707{
708 /* nothing to be done */
709}
Jens Arnold2fd7c3c2007-04-19 20:17:24 +0000710#endif
Daniel Stenberg22b77012005-02-22 12:19:12 +0000711
712void debugf(const char *fmt, ...)
713{
714 va_list ap;
715 va_start( ap, fmt );
716 vfprintf( stderr, fmt, ap );
717 va_end( ap );
718}
719
720void ldebugf(const char* file, int line, const char *fmt, ...)
721{
722 va_list ap;
723 va_start( ap, fmt );
724 fprintf( stderr, "%s:%d ", file, line );
725 vfprintf( stderr, fmt, ap );
726 va_end( ap );
727}
728
Jens Arnold576d0292005-03-05 21:48:58 +0000729/* rockbox off_t may be different from system off_t */
730int sim_ftruncate(int fd, long length)
Daniel Stenberg22b77012005-02-22 12:19:12 +0000731{
732#ifdef WIN32
733 return _chsize(fd, length);
734#else
735 return ftruncate(fd, length);
736#endif
737}