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 ****************************************************************************/
31 #define HAVE_STATVFS (!defined(WIN32))
32 #define HAVE_LSTAT (!defined(WIN32))
35 #include <sys/statvfs.h>
46 #include "dir-win32.h"
50 #ifdef HAVE_SDL_THREADS
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 int dircache_get_entry_id(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
;
337 x11
= READDIR(dir
->dir
);
340 return (struct sim_dirent
*)0;
342 strcpy((char *)secret
.d_name
, OS_TO_UTF8(x11
->d_name
));
344 /* build file name */
345 snprintf(buffer
, sizeof(buffer
), "%s/%s",
346 get_sim_pathname(dir
->name
), secret
.d_name
);
348 if (STAT(buffer
, &s
)) /* get info */
351 /* File size larger than 2 GB? */
352 if (errno
== EOVERFLOW
)
354 DEBUGF("stat() overflow for %s. Skipping\n", buffer
);
362 #define ATTR_DIRECTORY 0x10
364 secret
.info
.attribute
= 0;
366 if (S_ISDIR(s
.st_mode
))
367 secret
.info
.attribute
= ATTR_DIRECTORY
;
369 secret
.info
.size
= s
.st_size
;
371 if (localtime_r(&(s
.st_mtime
), &tm
) == NULL
)
373 secret
.info
.wrtdate
= ((tm
.tm_year
- 80) << 9) |
374 ((tm
.tm_mon
+ 1) << 5) |
376 secret
.info
.wrttime
= (tm
.tm_hour
<< 11) |
381 #define ATTR_LINK 0x80
382 if (!lstat(buffer
, &s
) && S_ISLNK(s
.st_mode
))
384 secret
.info
.attribute
|= ATTR_LINK
;
391 void sim_closedir(MYDIR
*dir
)
399 int sim_open(const char *name
, int o
, ...)
401 int opts
= rockbox2sim(o
);
403 if (num_openfiles
>= MAX_OPEN_FILES
)
410 mode_t mode
= va_arg(ap
, unsigned int);
411 ret
= OPEN(get_sim_pathname(name
), opts
, mode
);
413 if (ret
>= 0 && (dircache_get_entry_id(name
) < 0))
414 dircache_add_file(name
, 0);
419 ret
= OPEN(get_sim_pathname(name
), opts
);
426 int sim_close(int fd
)
435 int sim_creat(const char *name
, mode_t mode
)
437 int ret
= OPEN(get_sim_pathname(name
),
438 O_BINARY
| O_WRONLY
| O_CREAT
| O_TRUNC
, mode
);
440 if (ret
>= 0 && (dircache_get_entry_id(name
) < 0))
441 dircache_add_file(name
, 0);
446 ssize_t
sim_read(int fd
, void *buf
, size_t count
)
450 mutex_lock(&io
.sim_mutex
);
452 /* Setup parameters */
457 result
= io_trigger_and_wait(IO_READ
);
459 mutex_unlock(&io
.sim_mutex
);
464 ssize_t
sim_write(int fd
, const void *buf
, size_t count
)
468 mutex_lock(&io
.sim_mutex
);
474 result
= io_trigger_and_wait(IO_WRITE
);
476 mutex_unlock(&io
.sim_mutex
);
481 int sim_mkdir(const char *name
)
483 return MKDIR(get_sim_pathname(name
), 0777);
486 int sim_rmdir(const char *name
)
488 return RMDIR(get_sim_pathname(name
));
491 int sim_remove(const char *name
)
493 int ret
= REMOVE(get_sim_pathname(name
));
496 dircache_remove(name
);
501 int sim_rename(const char *oldname
, const char *newname
)
503 char sim_old
[MAX_PATH
];
504 char sim_new
[MAX_PATH
];
506 dircache_rename(oldname
, newname
);
508 // This is needed as get_sim_pathname() has a static buffer
509 strncpy(sim_old
, get_sim_pathname(oldname
), MAX_PATH
);
510 strncpy(sim_new
, get_sim_pathname(newname
), MAX_PATH
);
511 return RENAME(sim_old
, sim_new
);
514 /* rockbox off_t may be different from system off_t */
515 long sim_lseek(int fildes
, long offset
, int whence
)
517 return lseek(fildes
, offset
, whence
);
520 long filesize(int fd
)
523 return _filelength(fd
);
527 if (!fstat(fd
, &buf
))
534 void fat_size(IF_MV2(int volume
,) unsigned long* size
, unsigned long* free
)
536 #ifdef HAVE_MULTIVOLUME
538 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
547 long secperclus
, bytespersec
, free_clusters
, num_clusters
;
549 if (GetDiskFreeSpace(NULL
, &secperclus
, &bytespersec
, &free_clusters
,
552 *size
= num_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
554 *free
= free_clusters
* secperclus
/ 2 * (bytespersec
/ 512);
559 if (!statvfs(".", &vfs
)) {
560 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
561 (int)vfs
.f_frsize
, (long)vfs
.f_blocks
, (long)vfs
.f_bfree
);
563 *size
= vfs
.f_blocks
/ 2 * (vfs
.f_frsize
/ 512);
565 *free
= vfs
.f_bfree
/ 2 * (vfs
.f_frsize
/ 512);
576 int sim_fsync(int fd
)
587 void *lc_open(const char *filename
, unsigned char *buf
, size_t buf_size
)
589 const char *sim_path
= get_sim_pathname(filename
);
590 void *handle
= _lc_open(UTF8_TO_OS(sim_path
), buf
, buf_size
);
594 DEBUGF("failed to load %s\n", filename
);
595 DEBUGF("lc_open(%s): %s\n", filename
, lc_last_error());
600 void *lc_get_header(void *handle
)
602 return _lc_get_header(handle
);
605 void lc_close(void *handle
)
610 #endif /* __PCTOOL__ */
612 /* rockbox off_t may be different from system off_t */
613 int sim_ftruncate(int fd
, long length
)
616 return _chsize(fd
, length
);
618 return ftruncate(fd
, length
);