Fix warnings and errors in sdl builds.
[maemo-rb.git] / uisimulator / common / io.c
blobbca5c27a173990eeb20a5272b8f2c5d0a0a77d9a
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdarg.h>
26 #include <sys/stat.h>
27 #include <time.h>
28 #include <errno.h>
29 #include "config.h"
30 #include "ata_idle_notify.h"
32 #define HAVE_STATVFS (!defined(WIN32))
33 #define HAVE_LSTAT (!defined(WIN32))
35 #if HAVE_STATVFS
36 #include <sys/statvfs.h>
37 #endif
39 #ifdef WIN32
40 #include <windows.h>
41 #endif
43 #ifndef _MSC_VER
44 #include <dirent.h>
45 #include <unistd.h>
46 #else
47 #include "dir-win32.h"
48 #endif
50 #include <fcntl.h>
51 #ifdef HAVE_SDL_THREADS
52 #include "thread-sdl.h"
53 #else
54 #define sim_thread_unlock() NULL
55 #define sim_thread_lock(a)
56 #endif
57 #include "thread.h"
58 #include "kernel.h"
59 #include "debug.h"
60 #include "ata.h" /* for IF_MV2 et al. */
61 #include "rbpaths.h"
62 #include "load_code.h"
64 /* keep this in sync with file.h! */
65 #undef MAX_PATH /* this avoids problems when building simulator */
66 #define MAX_PATH 260
67 #define MAX_OPEN_FILES 11
69 /* Windows (and potentially other OSes) distinguish binary and text files.
70 * Define a dummy for the others. */
71 #ifndef O_BINARY
72 #define O_BINARY 0
73 #endif
75 /* Unicode compatibility for win32 */
76 #if defined __MINGW32__
77 /* Rockbox unicode functions */
78 extern const unsigned char* utf8decode(const unsigned char *utf8,
79 unsigned short *ucs);
80 extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8);
82 /* Static buffers for the conversion results. This isn't thread safe,
83 * but it's sufficient for rockbox. */
84 static unsigned char convbuf1[3*MAX_PATH];
85 static unsigned char convbuf2[3*MAX_PATH];
87 static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer)
89 wchar_t *ucs = buffer;
91 while (*utf8)
92 utf8 = utf8decode(utf8, ucs++);
94 *ucs = 0;
95 return buffer;
97 static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer)
99 unsigned char *utf8 = buffer;
101 while (*ucs)
102 utf8 = utf8encode(*ucs++, utf8);
104 *utf8 = 0;
105 return buffer;
108 #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1)
109 #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1)
110 #define DIR_T _WDIR
111 #define DIRENT_T struct _wdirent
112 #define STAT_T struct _stat
113 extern int _wmkdir(const wchar_t*);
114 extern int _wrmdir(const wchar_t*);
115 #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a))
116 #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a))
117 #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a))
118 #define READDIR(a) (_wreaddir)(a)
119 #define CLOSEDIR(a) (_wclosedir)(a)
120 #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b)
121 /* empty variable parameter list doesn't work for variadic macros,
122 * so pretend the second parameter is variable too */
123 #define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__)
124 #define CLOSE(a) (close)(a)
125 #define REMOVE(a) (_wremove)(UTF8_TO_OS(a))
126 #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2))
128 #else /* !__MINGW32__ */
130 #define UTF8_TO_OS(a) (a)
131 #define OS_TO_UTF8(a) (a)
132 #define DIR_T DIR
133 #define DIRENT_T struct dirent
134 #define STAT_T struct stat
135 #define MKDIR(a,b) (mkdir)(a,b)
136 #define RMDIR(a) (rmdir)(a)
137 #define OPENDIR(a) (opendir)(a)
138 #define READDIR(a) (readdir)(a)
139 #define CLOSEDIR(a) (closedir)(a)
140 #define STAT(a,b) (stat)(a,b)
141 /* empty variable parameter list doesn't work for variadic macros,
142 * so pretend the second parameter is variable too */
143 #define OPEN(a, ...) (open)(a, __VA_ARGS__)
144 #define CLOSE(x) (close)(x)
145 #define REMOVE(a) (remove)(a)
146 #define RENAME(a,b) (rename)(a,b)
148 #endif /* !__MINGW32__ */
151 #ifdef HAVE_DIRCACHE
152 int dircache_get_entry_id(const char *filename);
153 void dircache_add_file(const char *name, long startcluster);
154 void dircache_remove(const char *name);
155 void dircache_rename(const char *oldname, const char *newname);
156 #endif
159 #define SIMULATOR_DEFAULT_ROOT "simdisk"
160 extern const char *sim_root_dir;
162 static int num_openfiles = 0;
164 /* from dir.h */
165 struct dirinfo {
166 int attribute;
167 long size;
168 unsigned short wrtdate;
169 unsigned short wrttime;
172 struct sim_dirent {
173 unsigned char d_name[MAX_PATH];
174 struct dirinfo info;
175 long startcluster;
178 struct dirstruct {
179 void *dir; /* actually a DIR* dir */
180 char *name;
181 } SIM_DIR;
183 struct mydir {
184 DIR_T *dir;
185 char *name;
188 typedef struct mydir MYDIR;
190 static unsigned int rockbox2sim(int opt)
192 #if 0
193 /* this shouldn't be needed since we use the host's versions */
194 int newopt = O_BINARY;
196 if(opt & 1)
197 newopt |= O_WRONLY;
198 if(opt & 2)
199 newopt |= O_RDWR;
200 if(opt & 4)
201 newopt |= O_CREAT;
202 if(opt & 8)
203 newopt |= O_APPEND;
204 if(opt & 0x10)
205 newopt |= O_TRUNC;
207 return newopt;
208 #else
209 return opt|O_BINARY;
210 #endif
213 /** Simulator I/O engine routines **/
214 #define IO_YIELD_THRESHOLD 512
216 enum io_dir
218 IO_READ,
219 IO_WRITE,
222 struct sim_io
224 struct mutex sim_mutex; /* Rockbox mutex */
225 int cmd; /* The command to perform */
226 int ready; /* I/O ready flag - 1= ready */
227 int fd; /* The file to read/write */
228 void *buf; /* The buffer to read/write */
229 size_t count; /* Number of bytes to read/write */
230 size_t accum; /* Acculated bytes transferred */
233 static struct sim_io io;
235 int ata_init(void)
237 /* Initialize the rockbox kernel objects on a rockbox thread */
238 mutex_init(&io.sim_mutex);
239 io.accum = 0;
240 return 1;
243 int ata_spinup_time(void)
245 return HZ;
248 static ssize_t io_trigger_and_wait(enum io_dir cmd)
250 void *mythread = NULL;
251 ssize_t result;
253 if (io.count > IO_YIELD_THRESHOLD ||
254 (io.accum += io.count) >= IO_YIELD_THRESHOLD)
256 /* Allow other rockbox threads to run */
257 io.accum = 0;
258 mythread = sim_thread_unlock();
261 switch (cmd)
263 case IO_READ:
264 result = read(io.fd, io.buf, io.count);
265 break;
266 case IO_WRITE:
267 result = write(io.fd, io.buf, io.count);
268 break;
269 /* shut up gcc */
270 default:
271 result = -1;
274 call_storage_idle_notifys(false);
276 /* Regain our status as current */
277 if (mythread != NULL)
279 sim_thread_lock(mythread);
282 return result;
285 #if !defined(__PCTOOL__) && !defined(APPLICATION)
286 static const char *get_sim_pathname(const char *name)
288 static char buffer[MAX_PATH]; /* sufficiently big */
290 if(name[0] == '/')
292 snprintf(buffer, sizeof(buffer), "%s%s",
293 sim_root_dir != NULL ? sim_root_dir : SIMULATOR_DEFAULT_ROOT, name);
294 return buffer;
296 fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name);
297 return name;
299 #else
300 #define get_sim_pathname(name) name
301 #endif
303 MYDIR *sim_opendir(const char *name)
305 DIR_T *dir;
306 dir = (DIR_T *) OPENDIR(get_sim_pathname(name));
308 if (dir)
310 MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR));
311 my->dir = dir;
312 my->name = (char *)malloc(strlen(name)+1);
313 strcpy(my->name, name);
315 return my;
317 /* failed open, return NULL */
318 return (MYDIR *)0;
321 #if defined(WIN32)
322 static inline struct tm* localtime_r (const time_t *clock, struct tm *result) {
323 if (!clock || !result) return NULL;
324 memcpy(result,localtime(clock),sizeof(*result));
325 return result;
327 #endif
329 struct sim_dirent *sim_readdir(MYDIR *dir)
331 char buffer[MAX_PATH]; /* sufficiently big */
332 static struct sim_dirent secret;
333 STAT_T s;
334 struct tm tm;
335 DIRENT_T *x11;
337 #ifdef EOVERFLOW
338 read_next:
339 #endif
340 x11 = READDIR(dir->dir);
342 if(!x11)
343 return (struct sim_dirent *)0;
345 strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name));
347 /* build file name */
348 snprintf(buffer, sizeof(buffer), "%s/%s",
349 get_sim_pathname(dir->name), secret.d_name);
351 if (STAT(buffer, &s)) /* get info */
353 #ifdef EOVERFLOW
354 /* File size larger than 2 GB? */
355 if (errno == EOVERFLOW)
357 DEBUGF("stat() overflow for %s. Skipping\n", buffer);
358 goto read_next;
360 #endif
362 return NULL;
365 #define ATTR_DIRECTORY 0x10
367 secret.info.attribute = 0;
369 if (S_ISDIR(s.st_mode))
370 secret.info.attribute = ATTR_DIRECTORY;
372 secret.info.size = s.st_size;
374 if (localtime_r(&(s.st_mtime), &tm) == NULL)
375 return NULL;
376 secret.info.wrtdate = ((tm.tm_year - 80) << 9) |
377 ((tm.tm_mon + 1) << 5) |
378 tm.tm_mday;
379 secret.info.wrttime = (tm.tm_hour << 11) |
380 (tm.tm_min << 5) |
381 (tm.tm_sec >> 1);
383 #if HAVE_LSTAT
384 #define ATTR_LINK 0x80
385 if (!lstat(buffer, &s) && S_ISLNK(s.st_mode))
387 secret.info.attribute |= ATTR_LINK;
389 #endif
391 return &secret;
394 void sim_closedir(MYDIR *dir)
396 free(dir->name);
397 CLOSEDIR(dir->dir);
399 free(dir);
402 int sim_open(const char *name, int o, ...)
404 int opts = rockbox2sim(o);
405 int ret;
406 if (num_openfiles >= MAX_OPEN_FILES)
407 return -2;
409 if (opts & O_CREAT)
411 va_list ap;
412 va_start(ap, o);
413 mode_t mode = va_arg(ap, unsigned int);
414 ret = OPEN(get_sim_pathname(name), opts, mode);
415 #ifdef HAVE_DIRCACHE
416 if (ret >= 0 && (dircache_get_entry_id(name) < 0))
417 dircache_add_file(name, 0);
418 #endif
419 va_end(ap);
421 else
422 ret = OPEN(get_sim_pathname(name), opts);
424 if (ret >= 0)
425 num_openfiles++;
426 return ret;
429 int sim_close(int fd)
431 int ret;
432 ret = CLOSE(fd);
433 if (ret == 0)
434 num_openfiles--;
435 return ret;
438 int sim_creat(const char *name, mode_t mode)
440 int ret = OPEN(get_sim_pathname(name),
441 O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, mode);
442 #ifdef HAVE_DIRCACHE
443 if (ret >= 0 && (dircache_get_entry_id(name) < 0))
444 dircache_add_file(name, 0);
445 #endif
446 return ret;
449 ssize_t sim_read(int fd, void *buf, size_t count)
451 ssize_t result;
453 mutex_lock(&io.sim_mutex);
455 /* Setup parameters */
456 io.fd = fd;
457 io.buf = buf;
458 io.count = count;
460 result = io_trigger_and_wait(IO_READ);
462 mutex_unlock(&io.sim_mutex);
464 return result;
467 ssize_t sim_write(int fd, const void *buf, size_t count)
469 ssize_t result;
471 mutex_lock(&io.sim_mutex);
473 io.fd = fd;
474 io.buf = (void*)buf;
475 io.count = count;
477 result = io_trigger_and_wait(IO_WRITE);
479 mutex_unlock(&io.sim_mutex);
481 return result;
484 int sim_mkdir(const char *name)
486 return MKDIR(get_sim_pathname(name), 0777);
489 int sim_rmdir(const char *name)
491 return RMDIR(get_sim_pathname(name));
494 int sim_remove(const char *name)
496 int ret = REMOVE(get_sim_pathname(name));
497 #ifdef HAVE_DIRCACHE
498 if (ret >= 0)
499 dircache_remove(name);
500 #endif
501 return ret;
504 int sim_rename(const char *oldname, const char *newname)
506 char sim_old[MAX_PATH];
507 char sim_new[MAX_PATH];
508 #ifdef HAVE_DIRCACHE
509 dircache_rename(oldname, newname);
510 #endif
511 // This is needed as get_sim_pathname() has a static buffer
512 strncpy(sim_old, get_sim_pathname(oldname), MAX_PATH);
513 strncpy(sim_new, get_sim_pathname(newname), MAX_PATH);
514 return RENAME(sim_old, sim_new);
517 /* rockbox off_t may be different from system off_t */
518 long sim_lseek(int fildes, long offset, int whence)
520 return lseek(fildes, offset, whence);
523 long filesize(int fd)
525 #ifdef WIN32
526 return _filelength(fd);
527 #else
528 struct stat buf;
530 if (!fstat(fd, &buf))
531 return buf.st_size;
532 else
533 return -1;
534 #endif
537 void fat_size(IF_MV2(int volume,) unsigned long* size, unsigned long* free)
539 #ifdef HAVE_MULTIVOLUME
540 if (volume != 0) {
541 /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */
543 if (size) *size = 0;
544 if (free) *free = 0;
545 return;
547 #endif
549 #ifdef WIN32
550 long secperclus, bytespersec, free_clusters, num_clusters;
552 if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters,
553 &num_clusters)) {
554 if (size)
555 *size = num_clusters * secperclus / 2 * (bytespersec / 512);
556 if (free)
557 *free = free_clusters * secperclus / 2 * (bytespersec / 512);
558 } else
559 #elif HAVE_STATVFS
560 struct statvfs vfs;
562 if (!statvfs(".", &vfs)) {
563 DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n",
564 (int)vfs.f_frsize, (long)vfs.f_blocks, (long)vfs.f_bfree);
565 if (size)
566 *size = vfs.f_blocks / 2 * (vfs.f_frsize / 512);
567 if (free)
568 *free = vfs.f_bfree / 2 * (vfs.f_frsize / 512);
569 } else
570 #endif
572 if (size)
573 *size = 0;
574 if (free)
575 *free = 0;
579 int sim_fsync(int fd)
581 #ifdef WIN32
582 return _commit(fd);
583 #else
584 return fsync(fd);
585 #endif
588 #ifndef __PCTOOL__
590 #include <SDL_loadso.h>
591 void *lc_open(const char *filename, unsigned char *buf, size_t buf_size)
593 (void)buf;
594 (void)buf_size;
595 void *handle = SDL_LoadObject(get_sim_pathname(filename));
596 if (handle == NULL)
598 DEBUGF("failed to load %s\n", filename);
599 DEBUGF("lc_open(%s): %s\n", filename, SDL_GetError());
601 return handle;
604 void *lc_get_header(void *handle)
606 char *ret = SDL_LoadFunction(handle, "__header");
607 if (ret == NULL)
608 ret = SDL_LoadFunction(handle, "___header");
610 return ret;
613 void lc_close(void *handle)
615 SDL_UnloadObject(handle);
618 void *lc_open_from_mem(void *addr, size_t blob_size)
620 #ifndef SIMULATOR
621 (void)addr;
622 (void)blob_size;
623 /* we don't support loading code from memory on application builds,
624 * it doesn't make sense (since it means writing the blob to disk again and
625 * then falling back to load from disk) and requires the ability to write
626 * to an executable directory */
627 return NULL;
628 #else
629 /* support it in the sim for the sake of simulating */
630 int fd, i;
631 char temp_filename[MAX_PATH];
633 /* We have to create the dynamic link library file from ram so we
634 can simulate the codec loading. With voice and crossfade,
635 multiple codecs may be loaded at the same time, so we need
636 to find an unused filename */
637 for (i = 0; i < 10; i++)
639 snprintf(temp_filename, sizeof(temp_filename),
640 ROCKBOX_DIR "/libtemp_binary_%d.dll", i);
641 fd = open(temp_filename, O_WRONLY|O_CREAT|O_TRUNC, 0700);
642 if (fd >= 0)
643 break; /* Created a file ok */
646 if (fd < 0)
648 DEBUGF("open failed\n");
649 return NULL;
652 if (write(fd, addr, blob_size) < (ssize_t)blob_size)
654 DEBUGF("Write failed\n");
655 close(fd);
656 remove(temp_filename);
657 return NULL;
660 close(fd);
661 return lc_open(temp_filename, NULL, 0);
662 #endif
665 #endif /* __PCTOOL__ */
667 /* rockbox off_t may be different from system off_t */
668 int sim_ftruncate(int fd, long length)
670 #ifdef WIN32
671 return _chsize(fd, length);
672 #else
673 return ftruncate(fd, length);
674 #endif