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))
31 #define HAVE_LSTAT (!defined(WIN32))
34 #include <sys/statvfs.h>
45 #include "dir-win32.h"
49 #ifdef HAVE_SDL_THREADS
50 #include "thread-sdl.h"
52 #define sim_thread_unlock() NULL
53 #define sim_thread_lock(a)
58 #include "ata.h" /* for IF_MV2 et al. */
60 #include "load_code.h"
62 /* keep this in sync with file.h! */
63 #undef MAX_PATH /* this avoids problems when building simulator */
65 #define MAX_OPEN_FILES 11
67 /* Windows (and potentially other OSes) distinguish binary and text files.
68 * Define a dummy for the others. */
73 /* Unicode compatibility for win32 */
74 #if defined __MINGW32__
75 /* Rockbox unicode functions */
76 extern const unsigned char* utf8decode(const unsigned char *utf8
,
78 extern unsigned char* utf8encode(unsigned long ucs
, unsigned char *utf8
);
80 /* Static buffers for the conversion results. This isn't thread safe,
81 * but it's sufficient for rockbox. */
82 static unsigned char convbuf1
[3*MAX_PATH
];
83 static unsigned char convbuf2
[3*MAX_PATH
];
85 static wchar_t* utf8_to_ucs2(const unsigned char *utf8
, void *buffer
)
87 wchar_t *ucs
= buffer
;
90 utf8
= utf8decode(utf8
, ucs
++);
95 static unsigned char *ucs2_to_utf8(const wchar_t *ucs
, unsigned char *buffer
)
97 unsigned char *utf8
= buffer
;
100 utf8
= utf8encode(*ucs
++, utf8
);
106 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
107 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
109 #define DIRENT_T struct _wdirent
110 #define STAT_T struct _stat
111 extern int _wmkdir(const wchar_t*);
112 extern int _wrmdir(const wchar_t*);
113 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
114 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
115 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
116 #define READDIR(a) (_wreaddir)(a)
117 #define CLOSEDIR(a) (_wclosedir)(a)
118 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
119 /* empty variable parameter list doesn't work for variadic macros,
120 * so pretend the second parameter is variable too */
121 #define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
122 #define CLOSE(a) (close)(a)
123 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
124 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
126 #else /* !__MINGW32__ */
128 #define UTF8_TO_OS(a) (a)
129 #define OS_TO_UTF8(a) (a)
131 #define DIRENT_T struct dirent
132 #define STAT_T struct stat
133 #define MKDIR(a,b) (mkdir)(a,b)
134 #define RMDIR(a) (rmdir)(a)
135 #define OPENDIR(a) (opendir)(a)
136 #define READDIR(a) (readdir)(a)
137 #define CLOSEDIR(a) (closedir)(a)
138 #define STAT(a,b) (stat)(a,b)
139 /* empty variable parameter list doesn't work for variadic macros,
140 * so pretend the second parameter is variable too */
141 #define OPEN(a, ...) (open)(a, __VA_ARGS__)
142 #define CLOSE(x) (close)(x)
143 #define REMOVE(a) (remove)(a)
144 #define RENAME(a,b) (rename)(a,b)
146 #endif /* !__MINGW32__ */
150 struct dircache_entry
;
151 const struct dircache_entry
*dircache_get_entry_ptr(const char *filename
);
152 void dircache_add_file(const char *name
, long startcluster
);
153 void dircache_remove(const char *name
);
154 void dircache_rename(const char *oldname
, const char *newname
);
158 #define SIMULATOR_DEFAULT_ROOT "simdisk"
159 extern const char *sim_root_dir
;
161 static int num_openfiles
= 0;
167 unsigned short wrtdate
;
168 unsigned short wrttime
;
172 unsigned char d_name
[MAX_PATH
];
178 void *dir
; /* actually a DIR* dir */
187 typedef struct mydir MYDIR
;
189 static unsigned int rockbox2sim(int opt
)
192 /* this shouldn't be needed since we use the host's versions */
193 int newopt
= O_BINARY
;
212 /** Simulator I/O engine routines **/
213 #define IO_YIELD_THRESHOLD 512
223 struct mutex sim_mutex
; /* Rockbox mutex */
224 int cmd
; /* The command to perform */
225 int ready
; /* I/O ready flag - 1= ready */
226 int fd
; /* The file to read/write */
227 void *buf
; /* The buffer to read/write */
228 size_t count
; /* Number of bytes to read/write */
229 size_t accum
; /* Acculated bytes transferred */
232 static struct sim_io io
;
236 /* Initialize the rockbox kernel objects on a rockbox thread */
237 mutex_init(&io
.sim_mutex
);
242 int ata_spinup_time(void)
247 static ssize_t
io_trigger_and_wait(enum io_dir cmd
)
249 void *mythread
= NULL
;
252 if (io
.count
> IO_YIELD_THRESHOLD
||
253 (io
.accum
+= io
.count
) >= IO_YIELD_THRESHOLD
)
255 /* Allow other rockbox threads to run */
257 mythread
= sim_thread_unlock();
263 result
= read(io
.fd
, io
.buf
, io
.count
);
266 result
= write(io
.fd
, io
.buf
, io
.count
);
273 /* Regain our status as current */
274 if (mythread
!= NULL
)
276 sim_thread_lock(mythread
);
282 #if !defined(__PCTOOL__) && !defined(APPLICATION)
283 static const char *get_sim_pathname(const char *name
)
285 static char buffer
[MAX_PATH
]; /* sufficiently big */
289 snprintf(buffer
, sizeof(buffer
), "%s%s",
290 sim_root_dir
!= NULL
? sim_root_dir
: SIMULATOR_DEFAULT_ROOT
, name
);
293 fprintf(stderr
, "WARNING, bad file name lacks slash: %s\n", name
);
297 #define get_sim_pathname(name) name
300 MYDIR
*sim_opendir(const char *name
)
303 dir
= (DIR_T
*) OPENDIR(get_sim_pathname(name
));
307 MYDIR
*my
= (MYDIR
*)malloc(sizeof(MYDIR
));
309 my
->name
= (char *)malloc(strlen(name
)+1);
310 strcpy(my
->name
, name
);
314 /* failed open, return NULL */
319 static inline struct tm
* localtime_r (const time_t *clock
, struct tm
*result
) {
320 if (!clock
|| !result
) return NULL
;
321 memcpy(result
,localtime(clock
),sizeof(*result
));
326 struct sim_dirent
*sim_readdir(MYDIR
*dir
)
328 char buffer
[MAX_PATH
]; /* sufficiently big */
329 static struct sim_dirent secret
;
331 DIRENT_T
*x11
= READDIR(dir
->dir
);
335 return (struct sim_dirent
*)0;
337 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
339 /* build file name */
340 snprintf(buffer
, sizeof(buffer
), "%s/%s",
341 get_sim_pathname(dir
->name
), secret
.d_name
);
342 if (STAT(buffer
, &s
)) /* get info */
345 #define ATTR_DIRECTORY 0x10
347 secret
.info
.attribute
= 0;
349 if (S_ISDIR(s
.st_mode
))
350 secret
.info
.attribute
= ATTR_DIRECTORY
;
352 secret
.info
.size
= s
.st_size
;
354 if (localtime_r(&(s
.st_mtime
), &tm
) == NULL
)
356 secret
.info
.wrtdate
= ((tm
.tm_year
- 80) << 9) |
357 ((tm
.tm_mon
+ 1) << 5) |
359 secret
.info
.wrttime
= (tm
.tm_hour
<< 11) |
364 #define ATTR_LINK 0x80
365 if (!lstat(buffer
, &s
) && S_ISLNK(s
.st_mode
))
367 secret
.info
.attribute
|= ATTR_LINK
;
374 void sim_closedir(MYDIR
*dir
)
382 int sim_open(const char *name
, int o
, ...)
384 int opts
= rockbox2sim(o
);
386 if (num_openfiles
>= MAX_OPEN_FILES
)
393 mode_t mode
= va_arg(ap
, unsigned int);
394 ret
= OPEN(get_sim_pathname(name
), opts
, mode
);
396 if (ret
>= 0 && !dircache_get_entry_ptr(name
))
397 dircache_add_file(name
, 0);
402 ret
= OPEN(get_sim_pathname(name
), opts
);
409 int sim_close(int fd
)
418 int sim_creat(const char *name
, mode_t mode
)
420 int ret
= OPEN(get_sim_pathname(name
),
421 O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
423 if (ret
>= 0 && !dircache_get_entry_ptr(name
))
424 dircache_add_file(name
, 0);
429 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
433 mutex_lock(&io
.sim_mutex
);
435 /* Setup parameters */
440 result
= io_trigger_and_wait(IO_READ
);
442 mutex_unlock(&io
.sim_mutex
);
447 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
451 mutex_lock(&io
.sim_mutex
);
457 result
= io_trigger_and_wait(IO_WRITE
);
459 mutex_unlock(&io
.sim_mutex
);
464 int sim_mkdir(const char *name
)
466 return MKDIR(get_sim_pathname(name
), 0777);
469 int sim_rmdir(const char *name
)
471 return RMDIR(get_sim_pathname(name
));
474 int sim_remove(const char *name
)
476 int ret
= REMOVE(get_sim_pathname(name
));
479 dircache_remove(name
);
484 int sim_rename(const char *oldname
, const char *newname
)
486 char sim_old
[MAX_PATH
];
487 char sim_new
[MAX_PATH
];
489 dircache_rename(oldname
, newname
);
491 // This is needed as get_sim_pathname() has a static buffer
492 strncpy(sim_old
, get_sim_pathname(oldname
), MAX_PATH
);
493 strncpy(sim_new
, get_sim_pathname(newname
), MAX_PATH
);
494 return RENAME(sim_old
, sim_new
);
497 /* rockbox off_t may be different from system off_t */
498 long sim_lseek(int fildes
, long offset
, int whence
)
500 return lseek(fildes
, offset
, whence
);
503 long sim_filesize(int fd
)
506 return _filelength(fd
);
510 if (!fstat(fd
, &buf
))
517 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
519 #ifdef HAVE_MULTIVOLUME
521 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
530 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
532 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
535 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
537 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
542 if (!statvfs(".", &vfs
)) {
543 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
544 (int)vfs
.f_frsize
, (long)vfs
.f_blocks
, (long)vfs
.f_bfree
);
546 *size
= vfs
.f_blocks
/ 2 * (vfs
.f_frsize
/ 512);
548 *free
= vfs
.f_bfree
/ 2 * (vfs
.f_frsize
/ 512);
559 int sim_fsync(int fd
)
570 void *lc_open(const char *filename
, unsigned char *buf
, size_t buf_size
)
572 const char *sim_path
= get_sim_pathname(filename
);
573 void *handle
= _lc_open(UTF8_TO_OS(sim_path
), buf
, buf_size
);
577 DEBUGF("failed to load %s\n", filename
);
578 DEBUGF("lc_open(%s): %s\n", filename
, lc_last_error());
583 void *lc_get_header(void *handle
)
585 return _lc_get_header(handle
);
588 void lc_close(void *handle
)
593 #endif /* __PCTOOL__ */
595 static unsigned old_cp
;
597 void debug_exit(void)
599 /* Reset console output codepage */
600 SetConsoleOutputCP(old_cp
);
603 void debug_init(void)
605 old_cp
= GetConsoleOutputCP();
606 /* Set console output codepage to UTF8. Only works
607 * correctly when the console uses a truetype font. */
608 SetConsoleOutputCP(65001);
612 void debug_init(void)
614 /* nothing to be done */
618 void debugf(const char *fmt
, ...)
622 vfprintf( stderr
, fmt
, ap
);
626 void ldebugf(const char* file
, int line
, const char *fmt
, ...)
630 fprintf( stderr
, "%s:%d ", file
, line
);
631 vfprintf( stderr
, fmt
, ap
);
635 /* rockbox off_t may be different from system off_t */
636 int sim_ftruncate(int fd
, long length
)
639 return _chsize(fd
, length
);
641 return ftruncate(fd
, length
);