1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 Daniel Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
30 #define HAVE_STATVFS (0 == (CONFIG_PLATFORM & PLATFORM_ANDROID) && !defined(WIN32))
33 #include <sys/statvfs.h>
44 #include "dir-win32.h"
48 #if (CONFIG_PLATFORM & PLATFORM_SDL)
50 #include <SDL_thread.h>
51 #include "thread-sdl.h"
53 #define sim_thread_unlock() NULL
54 #define sim_thread_lock(a)
59 #include "ata.h" /* for IF_MV2 et al. */
61 #include "load_code.h"
63 /* keep this in sync with file.h! */
64 #undef MAX_PATH /* this avoids problems when building simulator */
66 #define MAX_OPEN_FILES 11
68 /* Windows (and potentially other OSes) distinguish binary and text files.
69 * Define a dummy for the others. */
74 /* Unicode compatibility for win32 */
75 #if defined __MINGW32__
76 /* Rockbox unicode functions */
77 extern const unsigned char* utf8decode(const unsigned char *utf8
,
79 extern unsigned char* utf8encode(unsigned long ucs
, unsigned char *utf8
);
81 /* Static buffers for the conversion results. This isn't thread safe,
82 * but it's sufficient for rockbox. */
83 static unsigned char convbuf1
[3*MAX_PATH
];
84 static unsigned char convbuf2
[3*MAX_PATH
];
86 static wchar_t* utf8_to_ucs2(const unsigned char *utf8
, void *buffer
)
88 wchar_t *ucs
= buffer
;
91 utf8
= utf8decode(utf8
, ucs
++);
96 static unsigned char *ucs2_to_utf8(const wchar_t *ucs
, unsigned char *buffer
)
98 unsigned char *utf8
= buffer
;
101 utf8
= utf8encode(*ucs
++, utf8
);
107 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
108 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
110 #define DIRENT_T struct _wdirent
111 #define STAT_T struct _stat
112 extern int _wmkdir(const wchar_t*);
113 extern int _wrmdir(const wchar_t*);
114 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
115 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
116 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
117 #define READDIR(a) (_wreaddir)(a)
118 #define CLOSEDIR(a) (_wclosedir)(a)
119 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
120 /* empty variable parameter list doesn't work for variadic macros,
121 * so pretend the second parameter is variable too */
122 #define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
123 #define CLOSE(a) (close)(a)
124 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
125 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
127 #else /* !__MINGW32__ */
129 #define UTF8_TO_OS(a) (a)
130 #define OS_TO_UTF8(a) (a)
132 #define DIRENT_T struct dirent
133 #define STAT_T struct stat
134 #define MKDIR(a,b) (mkdir)(a,b)
135 #define RMDIR(a) (rmdir)(a)
136 #define OPENDIR(a) (opendir)(a)
137 #define READDIR(a) (readdir)(a)
138 #define CLOSEDIR(a) (closedir)(a)
139 #define STAT(a,b) (stat)(a,b)
140 /* empty variable parameter list doesn't work for variadic macros,
141 * so pretend the second parameter is variable too */
142 #define OPEN(a, ...) (open)(a, __VA_ARGS__)
143 #define CLOSE(x) (close)(x)
144 #define REMOVE(a) (remove)(a)
145 #define RENAME(a,b) (rename)(a,b)
147 #endif /* !__MINGW32__ */
151 void dircache_remove(const char *name
);
152 void dircache_rename(const char *oldname
, const char *newname
);
156 #define SIMULATOR_DEFAULT_ROOT "simdisk"
157 extern const char *sim_root_dir
;
159 static int num_openfiles
= 0;
162 unsigned char d_name
[MAX_PATH
];
166 unsigned short wrtdate
; /* Last write date */
167 unsigned short wrttime
; /* Last write time */
171 void *dir
; /* actually a DIR* dir */
180 typedef struct mydir MYDIR
;
182 #if 1 /* maybe this needs disabling for MSVC... */
183 static unsigned int rockbox2sim(int opt
)
185 int newopt
= O_BINARY
;
202 /** Simulator I/O engine routines **/
203 #define IO_YIELD_THRESHOLD 512
213 struct mutex sim_mutex
; /* Rockbox mutex */
214 int cmd
; /* The command to perform */
215 int ready
; /* I/O ready flag - 1= ready */
216 int fd
; /* The file to read/write */
217 void *buf
; /* The buffer to read/write */
218 size_t count
; /* Number of bytes to read/write */
219 size_t accum
; /* Acculated bytes transferred */
222 static struct sim_io io
;
226 /* Initialize the rockbox kernel objects on a rockbox thread */
227 mutex_init(&io
.sim_mutex
);
232 int ata_spinup_time(void)
237 static ssize_t
io_trigger_and_wait(enum io_dir cmd
)
239 void *mythread
= NULL
;
242 if (io
.count
> IO_YIELD_THRESHOLD
||
243 (io
.accum
+= io
.count
) >= IO_YIELD_THRESHOLD
)
245 /* Allow other rockbox threads to run */
247 mythread
= sim_thread_unlock();
253 result
= read(io
.fd
, io
.buf
, io
.count
);
256 result
= write(io
.fd
, io
.buf
, io
.count
);
263 /* Regain our status as current */
264 if (mythread
!= NULL
)
266 sim_thread_lock(mythread
);
272 #if !defined(__PCTOOL__) && !defined(APPLICATION)
273 static const char *get_sim_pathname(const char *name
)
275 static char buffer
[MAX_PATH
]; /* sufficiently big */
279 snprintf(buffer
, sizeof(buffer
), "%s%s",
280 sim_root_dir
!= NULL
? sim_root_dir
: SIMULATOR_DEFAULT_ROOT
, name
);
283 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n", name
);
287 #define get_sim_pathname(name) name
290 MYDIR
*sim_opendir(const char *name
)
294 dir
= (DIR_T
*) OPENDIR(get_sim_pathname(name
));
298 MYDIR
*my
= (MYDIR
*)malloc(sizeof(MYDIR
));
300 my
->name
= (char *)malloc(strlen(name
)+1);
301 strcpy(my
->name
, name
);
305 /* failed open, return NULL */
309 struct sim_dirent
*sim_readdir(MYDIR
*dir
)
311 char buffer
[MAX_PATH
]; /* sufficiently big */
312 static struct sim_dirent secret
;
314 DIRENT_T
*x11
= READDIR(dir
->dir
);
318 return (struct sim_dirent
*)0;
320 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
322 /* build file name */
323 snprintf(buffer
, sizeof(buffer
), "%s/%s",
324 get_sim_pathname(dir
->name
), secret
.d_name
);
325 STAT(buffer
, &s
); /* get info */
327 #define ATTR_DIRECTORY 0x10
329 secret
.attribute
= S_ISDIR(s
.st_mode
)?ATTR_DIRECTORY
:0;
330 secret
.size
= s
.st_size
;
332 tm
= localtime(&(s
.st_mtime
));
333 secret
.wrtdate
= ((tm
->tm_year
- 80) << 9) |
334 ((tm
->tm_mon
+ 1) << 5) |
336 secret
.wrttime
= (tm
->tm_hour
<< 11) |
342 void sim_closedir(MYDIR
*dir
)
350 int sim_open(const char *name
, int o
, ...)
352 int opts
= rockbox2sim(o
);
354 if (num_openfiles
>= MAX_OPEN_FILES
)
361 mode_t mode
= va_arg(ap
, unsigned int);
362 ret
= OPEN(get_sim_pathname(name
), opts
, mode
);
366 ret
= OPEN(get_sim_pathname(name
), opts
);
373 int sim_close(int fd
)
382 int sim_creat(const char *name
, mode_t mode
)
384 return OPEN(get_sim_pathname(name
), O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
387 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
391 mutex_lock(&io
.sim_mutex
);
393 /* Setup parameters */
398 result
= io_trigger_and_wait(IO_READ
);
400 mutex_unlock(&io
.sim_mutex
);
405 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
409 mutex_lock(&io
.sim_mutex
);
415 result
= io_trigger_and_wait(IO_WRITE
);
417 mutex_unlock(&io
.sim_mutex
);
422 int sim_mkdir(const char *name
)
424 return MKDIR(get_sim_pathname(name
), 0777);
427 int sim_rmdir(const char *name
)
429 return RMDIR(get_sim_pathname(name
));
432 int sim_remove(const char *name
)
435 dircache_remove(name
);
437 return REMOVE(get_sim_pathname(name
));
440 int sim_rename(const char *oldname
, const char *newname
)
442 char sim_old
[MAX_PATH
];
443 char sim_new
[MAX_PATH
];
445 dircache_rename(oldname
, newname
);
447 // This is needed as get_sim_pathname() has a static buffer
448 strncpy(sim_old
, get_sim_pathname(oldname
), MAX_PATH
);
449 strncpy(sim_new
, get_sim_pathname(newname
), MAX_PATH
);
450 return RENAME(sim_old
, sim_new
);
453 /* rockbox off_t may be different from system off_t */
454 long sim_lseek(int fildes
, long offset
, int whence
)
456 return lseek(fildes
, offset
, whence
);
459 long sim_filesize(int fd
)
462 return _filelength(fd
);
466 if (!fstat(fd
, &buf
))
473 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
475 #ifdef HAVE_MULTIVOLUME
477 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
486 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
488 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
491 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
493 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
498 if (!statvfs(".", &vfs
)) {
499 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
500 (int)vfs
.f_frsize
, (long)vfs
.f_blocks
, (long)vfs
.f_bfree
);
502 *size
= vfs
.f_blocks
/ 2 * (vfs
.f_frsize
/ 512);
504 *free
= vfs
.f_bfree
/ 2 * (vfs
.f_frsize
/ 512);
515 int sim_fsync(int fd
)
526 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
527 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
528 #define dlclose(_x_) FreeLibrary(_x_)
535 void *lc_open(const char *filename
, char *buf
, size_t buf_size
)
537 const char *sim_path
= get_sim_pathname(filename
);
538 void *handle
= _lc_open((const char*)UTF8_TO_OS(sim_path
), buf
, buf_size
);
542 DEBUGF("failed to load %s\n", filename
);
543 DEBUGF("lc_open(%s): %s\n", filename
, lc_last_error());
548 void *lc_get_header(void *handle
)
550 return _lc_get_header(handle
);
553 void lc_close(void *handle
)
559 static unsigned old_cp
;
561 void debug_exit(void)
563 /* Reset console output codepage */
564 SetConsoleOutputCP(old_cp
);
567 void debug_init(void)
569 old_cp
= GetConsoleOutputCP();
570 /* Set console output codepage to UTF8. Only works
571 * correctly when the console uses a truetype font. */
572 SetConsoleOutputCP(65001);
576 void debug_init(void)
578 /* nothing to be done */
582 void debugf(const char *fmt
, ...)
586 vfprintf( stderr
, fmt
, ap
);
590 void ldebugf(const char* file
, int line
, const char *fmt
, ...)
594 fprintf( stderr
, "%s:%d ", file
, line
);
595 vfprintf( stderr
, fmt
, ap
);
599 /* rockbox off_t may be different from system off_t */
600 int sim_ftruncate(int fd
, long length
)
603 return _chsize(fd
, length
);
605 return ftruncate(fd
, length
);