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 (!defined(WIN32))
33 #include <sys/statvfs.h>
44 #include "dir-win32.h"
49 #include <SDL_thread.h>
50 #include "thread-sdl.h"
54 #include "ata.h" /* for IF_MV2 et al. */
56 #include "load_code.h"
58 /* keep this in sync with file.h! */
59 #undef MAX_PATH /* this avoids problems when building simulator */
61 #define MAX_OPEN_FILES 11
63 /* Windows (and potentially other OSes) distinguish binary and text files.
64 * Define a dummy for the others. */
69 /* Unicode compatibility for win32 */
70 #if defined __MINGW32__
71 /* Rockbox unicode functions */
72 extern const unsigned char* utf8decode(const unsigned char *utf8
,
74 extern unsigned char* utf8encode(unsigned long ucs
, unsigned char *utf8
);
76 /* Static buffers for the conversion results. This isn't thread safe,
77 * but it's sufficient for rockbox. */
78 static unsigned char convbuf1
[3*MAX_PATH
];
79 static unsigned char convbuf2
[3*MAX_PATH
];
81 static wchar_t* utf8_to_ucs2(const unsigned char *utf8
, void *buffer
)
83 wchar_t *ucs
= buffer
;
86 utf8
= utf8decode(utf8
, ucs
++);
91 static unsigned char *ucs2_to_utf8(const wchar_t *ucs
, unsigned char *buffer
)
93 unsigned char *utf8
= buffer
;
96 utf8
= utf8encode(*ucs
++, utf8
);
102 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
103 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
105 #define DIRENT_T struct _wdirent
106 #define STAT_T struct _stat
107 extern int _wmkdir(const wchar_t*);
108 extern int _wrmdir(const wchar_t*);
109 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
110 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
111 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
112 #define READDIR(a) (_wreaddir)(a)
113 #define CLOSEDIR(a) (_wclosedir)(a)
114 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
115 /* empty variable parameter list doesn't work for variadic macros,
116 * so pretend the second parameter is variable too */
117 #define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
118 #define CLOSE(a) (close)(a)
119 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
120 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
122 #else /* !__MINGW32__ */
124 #define UTF8_TO_OS(a) (a)
125 #define OS_TO_UTF8(a) (a)
127 #define DIRENT_T struct dirent
128 #define STAT_T struct stat
129 #define MKDIR(a,b) (mkdir)(a,b)
130 #define RMDIR(a) (rmdir)(a)
131 #define OPENDIR(a) (opendir)(a)
132 #define READDIR(a) (readdir)(a)
133 #define CLOSEDIR(a) (closedir)(a)
134 #define STAT(a,b) (stat)(a,b)
135 /* empty variable parameter list doesn't work for variadic macros,
136 * so pretend the second parameter is variable too */
137 #define OPEN(a, ...) (open)(a, __VA_ARGS__)
138 #define CLOSE(x) (close)(x)
139 #define REMOVE(a) (remove)(a)
140 #define RENAME(a,b) (rename)(a,b)
142 #endif /* !__MINGW32__ */
146 void dircache_remove(const char *name
);
147 void dircache_rename(const char *oldname
, const char *newname
);
151 #define SIMULATOR_DEFAULT_ROOT "simdisk"
152 extern const char *sim_root_dir
;
154 static int num_openfiles
= 0;
160 unsigned short wrtdate
;
161 unsigned short wrttime
;
165 unsigned char d_name
[MAX_PATH
];
171 void *dir
; /* actually a DIR* dir */
180 typedef struct mydir MYDIR
;
182 static unsigned int rockbox2sim(int opt
)
185 /* this shouldn't be needed since we use the host's versions */
186 int newopt
= O_BINARY
;
205 /** Simulator I/O engine routines **/
206 #define IO_YIELD_THRESHOLD 512
216 struct mutex sim_mutex
; /* Rockbox mutex */
217 int cmd
; /* The command to perform */
218 int ready
; /* I/O ready flag - 1= ready */
219 int fd
; /* The file to read/write */
220 void *buf
; /* The buffer to read/write */
221 size_t count
; /* Number of bytes to read/write */
222 size_t accum
; /* Acculated bytes transferred */
225 static struct sim_io io
;
229 /* Initialize the rockbox kernel objects on a rockbox thread */
230 mutex_init(&io
.sim_mutex
);
235 int ata_spinup_time(void)
240 static ssize_t
io_trigger_and_wait(enum io_dir cmd
)
242 void *mythread
= NULL
;
245 if (io
.count
> IO_YIELD_THRESHOLD
||
246 (io
.accum
+= io
.count
) >= IO_YIELD_THRESHOLD
)
248 /* Allow other rockbox threads to run */
250 mythread
= sim_thread_unlock();
256 result
= read(io
.fd
, io
.buf
, io
.count
);
259 result
= write(io
.fd
, io
.buf
, io
.count
);
266 /* Regain our status as current */
267 if (mythread
!= NULL
)
269 sim_thread_lock(mythread
);
275 #if !defined(__PCTOOL__) && !defined(APPLICATION)
276 static const char *get_sim_pathname(const char *name
)
278 static char buffer
[MAX_PATH
]; /* sufficiently big */
282 snprintf(buffer
, sizeof(buffer
), "%s%s",
283 sim_root_dir
!= NULL
? sim_root_dir
: SIMULATOR_DEFAULT_ROOT
, name
);
286 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n", name
);
290 #define get_sim_pathname(name) name
293 MYDIR
*sim_opendir(const char *name
)
297 dir
= (DIR_T
*) OPENDIR(get_sim_pathname(name
));
301 MYDIR
*my
= (MYDIR
*)malloc(sizeof(MYDIR
));
303 my
->name
= (char *)malloc(strlen(name
)+1);
304 strcpy(my
->name
, name
);
308 /* failed open, return NULL */
312 struct sim_dirent
*sim_readdir(MYDIR
*dir
)
314 char buffer
[MAX_PATH
]; /* sufficiently big */
315 static struct sim_dirent secret
;
317 DIRENT_T
*x11
= READDIR(dir
->dir
);
321 return (struct sim_dirent
*)0;
323 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
325 /* build file name */
326 snprintf(buffer
, sizeof(buffer
), "%s/%s",
327 get_sim_pathname(dir
->name
), secret
.d_name
);
328 STAT(buffer
, &s
); /* get info */
330 #define ATTR_DIRECTORY 0x10
332 secret
.info
.attribute
= S_ISDIR(s
.st_mode
)?ATTR_DIRECTORY
:0;
333 secret
.info
.size
= s
.st_size
;
335 tm
= localtime(&(s
.st_mtime
));
336 secret
.info
.wrtdate
= ((tm
->tm_year
- 80) << 9) |
337 ((tm
->tm_mon
+ 1) << 5) |
339 secret
.info
.wrttime
= (tm
->tm_hour
<< 11) |
345 struct dirinfo
dir_get_info(DIR* parent
, struct sim_dirent
*entry
)
352 void sim_closedir(MYDIR
*dir
)
360 int sim_open(const char *name
, int o
, ...)
362 int opts
= rockbox2sim(o
);
364 if (num_openfiles
>= MAX_OPEN_FILES
)
371 mode_t mode
= va_arg(ap
, unsigned int);
372 ret
= OPEN(get_sim_pathname(name
), opts
, mode
);
376 ret
= OPEN(get_sim_pathname(name
), opts
);
383 int sim_close(int fd
)
392 int sim_creat(const char *name
, mode_t mode
)
394 return OPEN(get_sim_pathname(name
), O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
397 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
401 mutex_lock(&io
.sim_mutex
);
403 /* Setup parameters */
408 result
= io_trigger_and_wait(IO_READ
);
410 mutex_unlock(&io
.sim_mutex
);
415 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
419 mutex_lock(&io
.sim_mutex
);
425 result
= io_trigger_and_wait(IO_WRITE
);
427 mutex_unlock(&io
.sim_mutex
);
432 int sim_mkdir(const char *name
)
434 return MKDIR(get_sim_pathname(name
), 0777);
437 int sim_rmdir(const char *name
)
439 return RMDIR(get_sim_pathname(name
));
442 int sim_remove(const char *name
)
445 dircache_remove(name
);
447 return REMOVE(get_sim_pathname(name
));
450 int sim_rename(const char *oldname
, const char *newname
)
452 char sim_old
[MAX_PATH
];
453 char sim_new
[MAX_PATH
];
455 dircache_rename(oldname
, newname
);
457 // This is needed as get_sim_pathname() has a static buffer
458 strncpy(sim_old
, get_sim_pathname(oldname
), MAX_PATH
);
459 strncpy(sim_new
, get_sim_pathname(newname
), MAX_PATH
);
460 return RENAME(sim_old
, sim_new
);
463 /* rockbox off_t may be different from system off_t */
464 long sim_lseek(int fildes
, long offset
, int whence
)
466 return lseek(fildes
, offset
, whence
);
469 long sim_filesize(int fd
)
472 return _filelength(fd
);
476 if (!fstat(fd
, &buf
))
483 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
485 #ifdef HAVE_MULTIVOLUME
487 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
496 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
498 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
501 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
503 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
508 if (!statvfs(".", &vfs
)) {
509 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
510 (int)vfs
.f_frsize
, (long)vfs
.f_blocks
, (long)vfs
.f_bfree
);
512 *size
= vfs
.f_blocks
/ 2 * (vfs
.f_frsize
/ 512);
514 *free
= vfs
.f_bfree
/ 2 * (vfs
.f_frsize
/ 512);
525 int sim_fsync(int fd
)
536 void *lc_open(const char *filename
, char *buf
, size_t buf_size
)
538 const char *sim_path
= get_sim_pathname(filename
);
539 void *handle
= _lc_open(UTF8_TO_OS(sim_path
), buf
, buf_size
);
543 DEBUGF("failed to load %s\n", filename
);
544 DEBUGF("lc_open(%s): %s\n", filename
, lc_last_error());
549 void *lc_get_header(void *handle
)
551 return _lc_get_header(handle
);
554 void lc_close(void *handle
)
559 #endif /* __PCTOOL__ */
561 static unsigned old_cp
;
563 void debug_exit(void)
565 /* Reset console output codepage */
566 SetConsoleOutputCP(old_cp
);
569 void debug_init(void)
571 old_cp
= GetConsoleOutputCP();
572 /* Set console output codepage to UTF8. Only works
573 * correctly when the console uses a truetype font. */
574 SetConsoleOutputCP(65001);
578 void debug_init(void)
580 /* nothing to be done */
584 void debugf(const char *fmt
, ...)
588 vfprintf( stderr
, fmt
, ap
);
592 void ldebugf(const char* file
, int line
, const char *fmt
, ...)
596 fprintf( stderr
, "%s:%d ", file
, line
);
597 vfprintf( stderr
, fmt
, ap
);
601 /* rockbox off_t may be different from system off_t */
602 int sim_ftruncate(int fd
, long length
)
605 return _chsize(fd
, length
);
607 return ftruncate(fd
, length
);