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;
165 unsigned short wrtdate
;
166 unsigned short wrttime
;
170 unsigned char d_name
[MAX_PATH
];
176 void *dir
; /* actually a DIR* dir */
185 typedef struct mydir MYDIR
;
187 static unsigned int rockbox2sim(int opt
)
190 /* this shouldn't be needed since we use the host's versions */
191 int newopt
= O_BINARY
;
210 /** Simulator I/O engine routines **/
211 #define IO_YIELD_THRESHOLD 512
221 struct mutex sim_mutex
; /* Rockbox mutex */
222 int cmd
; /* The command to perform */
223 int ready
; /* I/O ready flag - 1= ready */
224 int fd
; /* The file to read/write */
225 void *buf
; /* The buffer to read/write */
226 size_t count
; /* Number of bytes to read/write */
227 size_t accum
; /* Acculated bytes transferred */
230 static struct sim_io io
;
234 /* Initialize the rockbox kernel objects on a rockbox thread */
235 mutex_init(&io
.sim_mutex
);
240 int ata_spinup_time(void)
245 static ssize_t
io_trigger_and_wait(enum io_dir cmd
)
247 void *mythread
= NULL
;
250 if (io
.count
> IO_YIELD_THRESHOLD
||
251 (io
.accum
+= io
.count
) >= IO_YIELD_THRESHOLD
)
253 /* Allow other rockbox threads to run */
255 mythread
= sim_thread_unlock();
261 result
= read(io
.fd
, io
.buf
, io
.count
);
264 result
= write(io
.fd
, io
.buf
, io
.count
);
271 /* Regain our status as current */
272 if (mythread
!= NULL
)
274 sim_thread_lock(mythread
);
280 #if !defined(__PCTOOL__) && !defined(APPLICATION)
281 static const char *get_sim_pathname(const char *name
)
283 static char buffer
[MAX_PATH
]; /* sufficiently big */
287 snprintf(buffer
, sizeof(buffer
), "%s%s",
288 sim_root_dir
!= NULL
? sim_root_dir
: SIMULATOR_DEFAULT_ROOT
, name
);
291 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n", name
);
295 #define get_sim_pathname(name) name
298 MYDIR
*sim_opendir(const char *name
)
302 dir
= (DIR_T
*) OPENDIR(get_sim_pathname(name
));
306 MYDIR
*my
= (MYDIR
*)malloc(sizeof(MYDIR
));
308 my
->name
= (char *)malloc(strlen(name
)+1);
309 strcpy(my
->name
, name
);
313 /* failed open, return NULL */
317 struct sim_dirent
*sim_readdir(MYDIR
*dir
)
319 char buffer
[MAX_PATH
]; /* sufficiently big */
320 static struct sim_dirent secret
;
322 DIRENT_T
*x11
= READDIR(dir
->dir
);
326 return (struct sim_dirent
*)0;
328 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
330 /* build file name */
331 snprintf(buffer
, sizeof(buffer
), "%s/%s",
332 get_sim_pathname(dir
->name
), secret
.d_name
);
333 STAT(buffer
, &s
); /* get info */
335 #define ATTR_DIRECTORY 0x10
337 secret
.info
.attribute
= S_ISDIR(s
.st_mode
)?ATTR_DIRECTORY
:0;
338 secret
.info
.size
= s
.st_size
;
340 tm
= localtime(&(s
.st_mtime
));
341 secret
.info
.wrtdate
= ((tm
->tm_year
- 80) << 9) |
342 ((tm
->tm_mon
+ 1) << 5) |
344 secret
.info
.wrttime
= (tm
->tm_hour
<< 11) |
350 struct dirinfo
dir_get_info(DIR* parent
, struct sim_dirent
*entry
)
357 void sim_closedir(MYDIR
*dir
)
365 int sim_open(const char *name
, int o
, ...)
367 int opts
= rockbox2sim(o
);
369 if (num_openfiles
>= MAX_OPEN_FILES
)
376 mode_t mode
= va_arg(ap
, unsigned int);
377 ret
= OPEN(get_sim_pathname(name
), opts
, mode
);
381 ret
= OPEN(get_sim_pathname(name
), opts
);
388 int sim_close(int fd
)
397 int sim_creat(const char *name
, mode_t mode
)
399 return OPEN(get_sim_pathname(name
), O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
402 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
406 mutex_lock(&io
.sim_mutex
);
408 /* Setup parameters */
413 result
= io_trigger_and_wait(IO_READ
);
415 mutex_unlock(&io
.sim_mutex
);
420 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
424 mutex_lock(&io
.sim_mutex
);
430 result
= io_trigger_and_wait(IO_WRITE
);
432 mutex_unlock(&io
.sim_mutex
);
437 int sim_mkdir(const char *name
)
439 return MKDIR(get_sim_pathname(name
), 0777);
442 int sim_rmdir(const char *name
)
444 return RMDIR(get_sim_pathname(name
));
447 int sim_remove(const char *name
)
450 dircache_remove(name
);
452 return REMOVE(get_sim_pathname(name
));
455 int sim_rename(const char *oldname
, const char *newname
)
457 char sim_old
[MAX_PATH
];
458 char sim_new
[MAX_PATH
];
460 dircache_rename(oldname
, newname
);
462 // This is needed as get_sim_pathname() has a static buffer
463 strncpy(sim_old
, get_sim_pathname(oldname
), MAX_PATH
);
464 strncpy(sim_new
, get_sim_pathname(newname
), MAX_PATH
);
465 return RENAME(sim_old
, sim_new
);
468 /* rockbox off_t may be different from system off_t */
469 long sim_lseek(int fildes
, long offset
, int whence
)
471 return lseek(fildes
, offset
, whence
);
474 long sim_filesize(int fd
)
477 return _filelength(fd
);
481 if (!fstat(fd
, &buf
))
488 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
490 #ifdef HAVE_MULTIVOLUME
492 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
501 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
503 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
506 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
508 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
513 if (!statvfs(".", &vfs
)) {
514 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
515 (int)vfs
.f_frsize
, (long)vfs
.f_blocks
, (long)vfs
.f_bfree
);
517 *size
= vfs
.f_blocks
/ 2 * (vfs
.f_frsize
/ 512);
519 *free
= vfs
.f_bfree
/ 2 * (vfs
.f_frsize
/ 512);
530 int sim_fsync(int fd
)
543 #define dlopen(_x_, _y_) LoadLibraryW(UTF8_TO_OS(_x_))
544 #define dlsym(_x_, _y_) (void *)GetProcAddress(_x_, _y_)
545 #define dlclose(_x_) FreeLibrary(_x_)
552 void *lc_open(const char *filename
, char *buf
, size_t buf_size
)
554 const char *sim_path
= get_sim_pathname(filename
);
555 void *handle
= _lc_open(UTF8_TO_OS(sim_path
), buf
, buf_size
);
559 DEBUGF("failed to load %s\n", filename
);
560 DEBUGF("lc_open(%s): %s\n", filename
, lc_last_error());
565 void *lc_get_header(void *handle
)
567 return _lc_get_header(handle
);
570 void lc_close(void *handle
)
575 #endif /* __PCTOOL__ */
577 static unsigned old_cp
;
579 void debug_exit(void)
581 /* Reset console output codepage */
582 SetConsoleOutputCP(old_cp
);
585 void debug_init(void)
587 old_cp
= GetConsoleOutputCP();
588 /* Set console output codepage to UTF8. Only works
589 * correctly when the console uses a truetype font. */
590 SetConsoleOutputCP(65001);
594 void debug_init(void)
596 /* nothing to be done */
600 void debugf(const char *fmt
, ...)
604 vfprintf( stderr
, fmt
, ap
);
608 void ldebugf(const char* file
, int line
, const char *fmt
, ...)
612 fprintf( stderr
, "%s:%d ", file
, line
);
613 vfprintf( stderr
, fmt
, ap
);
617 /* rockbox off_t may be different from system off_t */
618 int sim_ftruncate(int fd
, long length
)
621 return _chsize(fd
, length
);
623 return ftruncate(fd
, length
);