diff options
Diffstat (limited to 'uisimulator/common')
-rw-r--r-- | uisimulator/common/SOURCES | 17 | ||||
-rw-r--r-- | uisimulator/common/dummylib.c | 1 | ||||
-rw-r--r-- | uisimulator/common/filesystem-sim.c | 833 | ||||
-rw-r--r-- | uisimulator/common/filesystem-sim.h | 108 | ||||
-rw-r--r-- | uisimulator/common/io.c | 729 | ||||
-rw-r--r-- | uisimulator/common/load_code-sim.c | 72 | ||||
-rw-r--r-- | uisimulator/common/sim_tasks.c | 34 | ||||
-rw-r--r-- | uisimulator/common/stubs.c | 5 | ||||
-rw-r--r-- | uisimulator/common/time-win32.c | 61 |
9 files changed, 1120 insertions, 740 deletions
diff --git a/uisimulator/common/SOURCES b/uisimulator/common/SOURCES index 939f1638c3..9833753236 100644 --- a/uisimulator/common/SOURCES +++ b/uisimulator/common/SOURCES | |||
@@ -1,4 +1,5 @@ | |||
1 | #ifdef SIMULATOR | 1 | #ifdef SIMULATOR |
2 | |||
2 | lcd-common.c | 3 | lcd-common.c |
3 | #ifdef HAVE_LCD_CHARCELLS | 4 | #ifdef HAVE_LCD_CHARCELLS |
4 | font-player.c | 5 | font-player.c |
@@ -8,8 +9,20 @@ sim_icons.c | |||
8 | sim_tasks.c | 9 | sim_tasks.c |
9 | fmradio.c | 10 | fmradio.c |
10 | backlight-sim.c | 11 | backlight-sim.c |
11 | stubs.c | ||
12 | powermgmt-sim.c | 12 | powermgmt-sim.c |
13 | filesystem-sim.c | ||
14 | |||
15 | #ifdef WIN32 | ||
16 | time-win32.c | ||
17 | #endif | ||
18 | |||
19 | #ifndef __PCTOOL__ | ||
20 | load_code-sim.c | ||
13 | #endif | 21 | #endif |
14 | 22 | ||
15 | io.c | 23 | stubs.c |
24 | |||
25 | #else | ||
26 | dummylib.c /* for now, so the lib actually builds */ | ||
27 | #endif /* SIMULATOR */ | ||
28 | |||
diff --git a/uisimulator/common/dummylib.c b/uisimulator/common/dummylib.c new file mode 100644 index 0000000000..9747edf3a1 --- /dev/null +++ b/uisimulator/common/dummylib.c | |||
@@ -0,0 +1 @@ | |||
/* this exists to get libuisimulator to make so that the sdl app may link */ | |||
diff --git a/uisimulator/common/filesystem-sim.c b/uisimulator/common/filesystem-sim.c new file mode 100644 index 0000000000..766beb3fda --- /dev/null +++ b/uisimulator/common/filesystem-sim.c | |||
@@ -0,0 +1,833 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 Daniel Stenberg | ||
11 | * Copyright (C) 2014 Michael Sevakis | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #define RB_FILESYSTEM_OS | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <stdarg.h> | ||
26 | #include <time.h> | ||
27 | #include <errno.h> | ||
28 | #include <limits.h> | ||
29 | #include "config.h" | ||
30 | #include "system.h" | ||
31 | #include "file.h" | ||
32 | #include "dir.h" | ||
33 | #include "file_internal.h" | ||
34 | #include "pathfuncs.h" | ||
35 | #include "string-extra.h" | ||
36 | #include "debug.h" | ||
37 | |||
38 | #ifndef os_fstatat | ||
39 | #define USE_OSDIRNAME /* we need to remember the open directory path */ | ||
40 | #endif | ||
41 | |||
42 | extern const char *sim_root_dir; | ||
43 | |||
44 | /* Windows (and potentially other OSes) distinguish binary and text files. | ||
45 | * Define a dummy for the others. */ | ||
46 | #ifndef O_BINARY | ||
47 | #define O_BINARY 0 | ||
48 | #endif | ||
49 | |||
50 | struct filestr_desc | ||
51 | { | ||
52 | int osfd; /* The host OS file descriptor */ | ||
53 | bool mounted; /* Is host volume still mounted? */ | ||
54 | #ifdef HAVE_MULTIVOLUME | ||
55 | int volume; /* The virtual volume number */ | ||
56 | #endif | ||
57 | } openfiles[MAX_OPEN_FILES] = | ||
58 | { | ||
59 | [0 ... MAX_OPEN_FILES-1] = { .osfd = -1 } | ||
60 | }; | ||
61 | |||
62 | static struct filestr_desc * alloc_filestr(int *fildesp) | ||
63 | { | ||
64 | for (unsigned int i = 0; i < MAX_OPEN_FILES; i++) | ||
65 | { | ||
66 | struct filestr_desc *filestr = &openfiles[i]; | ||
67 | if (filestr->osfd < 0) | ||
68 | { | ||
69 | *fildesp = i; | ||
70 | return filestr; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | return NULL; | ||
75 | } | ||
76 | |||
77 | static struct filestr_desc * get_filestr(int fildes) | ||
78 | { | ||
79 | struct filestr_desc *filestr = &openfiles[fildes]; | ||
80 | |||
81 | if ((unsigned int)fildes >= MAX_OPEN_FILES || filestr->osfd < 0) | ||
82 | filestr = NULL; | ||
83 | else if (filestr->mounted) | ||
84 | return filestr; | ||
85 | |||
86 | errno = filestr ? ENXIO : EBADF; | ||
87 | DEBUGF("fildes %d: %s\n", fildes, strerror(errno)); | ||
88 | return NULL; | ||
89 | } | ||
90 | |||
91 | struct dirstr_desc | ||
92 | { | ||
93 | int osfd; /* Host OS directory file descriptor */ | ||
94 | bool osfd_opened; /* Host fd is another open file */ | ||
95 | OS_DIR_T *osdirp; /* Host OS directory stream */ | ||
96 | #ifdef USE_OSDIRNAME | ||
97 | char *osdirname; /* Host OS directory path */ | ||
98 | #endif | ||
99 | struct sim_dirent entry; /* Rockbox directory entry */ | ||
100 | #ifdef HAVE_MULTIVOLUME | ||
101 | int volume; /* Virtual volume number */ | ||
102 | int volumecounter; /* Counter for root volume entries */ | ||
103 | #endif | ||
104 | bool mounted; /* Is the virtual volume still mounted? */ | ||
105 | } opendirs[MAX_OPEN_DIRS]; | ||
106 | |||
107 | static struct dirstr_desc * alloc_dirstr(void) | ||
108 | { | ||
109 | for (unsigned int i = 0; i < MAX_OPEN_DIRS; i++) | ||
110 | { | ||
111 | struct dirstr_desc *dirstr = &opendirs[i]; | ||
112 | if (dirstr->osdirp == NULL) | ||
113 | return dirstr; | ||
114 | } | ||
115 | |||
116 | return NULL; | ||
117 | } | ||
118 | |||
119 | static struct dirstr_desc * get_dirstr(DIR *dirp) | ||
120 | { | ||
121 | struct dirstr_desc *dirstr = (struct dirstr_desc *)dirp; | ||
122 | |||
123 | if (!PTR_IN_ARRAY(opendirs, dirstr, MAX_OPEN_DIRS) || !dirstr->osdirp) | ||
124 | dirstr = NULL; | ||
125 | else if (dirstr->mounted) | ||
126 | return dirstr; | ||
127 | |||
128 | errno = dirstr ? ENXIO : EBADF; | ||
129 | DEBUGF("dir #%d: %s\n", (int)(dirstr - opendirs), strerror(errno)); | ||
130 | return NULL; | ||
131 | } | ||
132 | |||
133 | static int close_dirstr(struct dirstr_desc *dirstr) | ||
134 | { | ||
135 | OS_DIR_T *osdirp = dirstr->osdirp; | ||
136 | |||
137 | dirstr->mounted = false; | ||
138 | |||
139 | #ifdef USE_OSDIRNAME | ||
140 | free(dirstr->osdirname); | ||
141 | #endif | ||
142 | if (dirstr->osfd_opened) | ||
143 | { | ||
144 | os_close(dirstr->osfd); | ||
145 | dirstr->osfd_opened = false; | ||
146 | } | ||
147 | |||
148 | int rc = os_closedir(osdirp); | ||
149 | dirstr->osdirp = NULL; | ||
150 | |||
151 | return rc; | ||
152 | } | ||
153 | |||
154 | #ifdef HAVE_MULTIVOLUME | ||
155 | static int readdir_volume_inner(struct dirstr_desc *dirstr, | ||
156 | struct sim_dirent *entry) | ||
157 | { | ||
158 | /* Volumes (secondary file systems) get inserted into the system root | ||
159 | * directory. If the path specified volume 0, enumeration will not | ||
160 | * include other volumes, but just its own files and directories. | ||
161 | * | ||
162 | * Fake special directories, which don't really exist, that will get | ||
163 | * redirected upon opendir() | ||
164 | */ | ||
165 | while (++dirstr->volumecounter < NUM_VOLUMES) | ||
166 | { | ||
167 | /* on the system root */ | ||
168 | if (!volume_present(dirstr->volumecounter)) | ||
169 | continue; | ||
170 | |||
171 | get_volume_name(dirstr->volumecounter, entry->d_name); | ||
172 | return 1; | ||
173 | } | ||
174 | |||
175 | /* do normal directory entry fetching */ | ||
176 | return 0; | ||
177 | } | ||
178 | #endif /* HAVE_MULTIVOLUME */ | ||
179 | |||
180 | static inline int readdir_volume(struct dirstr_desc *dirstr, | ||
181 | struct sim_dirent *entry) | ||
182 | { | ||
183 | #ifdef HAVE_MULTIVOLUME | ||
184 | if (dirstr->volumecounter < NUM_VOLUMES) | ||
185 | return readdir_volume_inner(dirstr, entry); | ||
186 | #endif /* HAVE_MULTIVOLUME */ | ||
187 | |||
188 | /* do normal directory entry fetching */ | ||
189 | return 0; | ||
190 | (void)dirstr; (void)entry; | ||
191 | } | ||
192 | |||
193 | |||
194 | /** Internal functions **/ | ||
195 | |||
196 | #ifdef HAVE_MULTIDRIVE | ||
197 | /** | ||
198 | * Handle drive extraction by pretending the files' volumes no longer exist | ||
199 | * and invalidating their I/O for the remainder of their lifetimes as would | ||
200 | * happen on a native target | ||
201 | */ | ||
202 | void sim_ext_extracted(int drive) | ||
203 | { | ||
204 | for (unsigned int i = 0; i < MAX_OPEN_FILES; i++) | ||
205 | { | ||
206 | struct filestr_desc *filestr = &openfiles[i]; | ||
207 | if (filestr->osfd >= 0 && volume_drive(filestr->volume) == drive) | ||
208 | filestr->mounted = false; | ||
209 | } | ||
210 | |||
211 | for (unsigned int i = 0; i < MAX_OPEN_DIRS; i++) | ||
212 | { | ||
213 | struct dirstr_desc *dirstr = &opendirs[i]; | ||
214 | if (dirstr->osdirp && volume_drive(dirstr->volume) == drive) | ||
215 | dirstr->mounted = false; | ||
216 | } | ||
217 | |||
218 | (void)drive; | ||
219 | } | ||
220 | #endif /* HAVE_MULTIDRIVE */ | ||
221 | |||
222 | /** | ||
223 | * Provides target-like path parsing behavior with single and multiple volumes | ||
224 | * while performing minimal transforming of the input. | ||
225 | * | ||
226 | * Paths are sandboxed to the simulated namespace: | ||
227 | * e.g. "{simdir}/foo/../../../../bar" becomes "{simdir}/foo/../bar" | ||
228 | */ | ||
229 | int sim_get_os_path(char *buffer, const char *path, size_t bufsize) | ||
230 | { | ||
231 | #define ADVBUF(amt) \ | ||
232 | ({ buffer += (amt); bufsize -= (amt); }) | ||
233 | |||
234 | #define PPP_SHOWPATHS 0 | ||
235 | |||
236 | if (!path_is_absolute(path)) | ||
237 | { | ||
238 | DEBUGF("ERROR: path is not absolute: \"%s\"\n", path); | ||
239 | errno = ENOENT; | ||
240 | return -1; | ||
241 | } | ||
242 | |||
243 | #if PPP_SHOWPATHS | ||
244 | const char *const buffer0 = buffer; | ||
245 | DEBUGF("PPP (pre): \"%s\"\n", path); | ||
246 | #endif | ||
247 | |||
248 | /* Prepend sim root */ | ||
249 | size_t size = strlcpy(buffer, sim_root_dir, bufsize); | ||
250 | if (size >= bufsize) | ||
251 | { | ||
252 | errno = ENAMETOOLONG; | ||
253 | return -1; | ||
254 | } | ||
255 | ADVBUF(size); | ||
256 | |||
257 | #ifdef HAVE_MULTIVOLUME | ||
258 | /* Track the last valid volume spec encountered */ | ||
259 | int volume = -1; | ||
260 | bool sysroot = true; | ||
261 | |||
262 | /* Basename of sim dir to switch back to simdisk from ext */ | ||
263 | #define DIRBASE_FMT ".." PATH_SEPSTR "%s" | ||
264 | ssize_t dirbase_len = 0; | ||
265 | char dirbase[size + 3 + 1]; | ||
266 | |||
267 | /* Basename of ext directory to switch to alternate volume */ | ||
268 | #define SIMEXT_FMT ".." PATH_SEPSTR "simext%d" | ||
269 | char extbuf[sizeof (SIMEXT_FMT) + 20 + 1]; | ||
270 | #endif /* HAVE_MULTIVOLUME */ | ||
271 | |||
272 | int level = 0; | ||
273 | bool done = false; | ||
274 | while (!done) | ||
275 | { | ||
276 | const char *p; | ||
277 | ssize_t len = parse_path_component(&path, &p); | ||
278 | |||
279 | |||
280 | switch (len) | ||
281 | { | ||
282 | case 0: | ||
283 | done = true; | ||
284 | if (path[-1] != PATH_SEPCH) | ||
285 | continue; | ||
286 | |||
287 | /* Path ends with a separator; preserve that */ | ||
288 | p = &path[-1]; | ||
289 | len = 1; | ||
290 | break; | ||
291 | |||
292 | case 1: | ||
293 | case 2: | ||
294 | if (p[0] == '.') | ||
295 | { | ||
296 | if (len == 1) | ||
297 | break; | ||
298 | |||
299 | if (p[1] == '.') | ||
300 | goto is_dot_dot; | ||
301 | } | ||
302 | |||
303 | default: | ||
304 | level++; | ||
305 | |||
306 | #ifdef HAVE_MULTIVOLUME | ||
307 | if (level != 1) | ||
308 | break; /* Volume spec only valid @ root level */ | ||
309 | |||
310 | const char *next; | ||
311 | volume = path_strip_volume(p, &next, true); | ||
312 | |||
313 | if (next > p) | ||
314 | { | ||
315 | #ifdef HAVE_MULTIDRIVE | ||
316 | /* Feign failure if the volume isn't "mounted" */ | ||
317 | if (!volume_present(volume)) | ||
318 | { | ||
319 | errno = ENXIO; | ||
320 | return -1; | ||
321 | } | ||
322 | #endif /* HAVE_MULTIDRIVE */ | ||
323 | |||
324 | sysroot = false; | ||
325 | |||
326 | if (volume == 0) | ||
327 | continue; | ||
328 | |||
329 | p = extbuf; | ||
330 | len = snprintf(extbuf, sizeof (extbuf), SIMEXT_FMT, volume); | ||
331 | } | ||
332 | #endif /* HAVE_MULTIVOLUME */ | ||
333 | break; | ||
334 | |||
335 | is_dot_dot: | ||
336 | if (level <= 0) | ||
337 | continue; /* Can't go above root; erase */ | ||
338 | |||
339 | level--; | ||
340 | |||
341 | #ifdef HAVE_MULTIVOLUME | ||
342 | if (level == 0) | ||
343 | { | ||
344 | int v = volume; | ||
345 | bool sr = sysroot; | ||
346 | volume = -1; | ||
347 | sysroot = true; | ||
348 | |||
349 | if (v <= 0) | ||
350 | { | ||
351 | if (sr) | ||
352 | break; | ||
353 | |||
354 | continue; | ||
355 | } | ||
356 | |||
357 | /* Going up from a volume root and back down to the sys root */ | ||
358 | if (dirbase_len == 0) | ||
359 | { | ||
360 | /* Get the main simdisk directory so it can be reentered */ | ||
361 | char tmpbuf[sizeof (dirbase)]; | ||
362 | #ifdef WIN32 | ||
363 | path_correct_separators(tmpbuf, sim_root_dir); | ||
364 | path_strip_drive(tmpbuf, &p, false); | ||
365 | #else | ||
366 | p = tmpbuf; | ||
367 | strcpy(tmpbuf, sim_root_dir); | ||
368 | #endif | ||
369 | size = path_basename(p, &p); | ||
370 | ((char *)p)[size] = '\0'; | ||
371 | |||
372 | if (size == 0 || is_dotdir_name(p)) | ||
373 | { | ||
374 | /* This is nonsense and won't work */ | ||
375 | DEBUGF("ERROR: sim root dir basname is dotdir or" | ||
376 | " empty: \"%s\"\n", sim_root_dir); | ||
377 | errno = ENOENT; | ||
378 | return -1; | ||
379 | } | ||
380 | |||
381 | dirbase_len = snprintf(dirbase, sizeof (dirbase), | ||
382 | DIRBASE_FMT, p); | ||
383 | } | ||
384 | |||
385 | p = dirbase; | ||
386 | len = dirbase_len; | ||
387 | break; | ||
388 | } | ||
389 | #endif /* HAVE_MULTIVOLUME */ | ||
390 | break; | ||
391 | } /* end switch */ | ||
392 | |||
393 | char compname[len + 1]; | ||
394 | strmemcpy(compname, p, len); | ||
395 | |||
396 | size = path_append(buffer, PA_SEP_HARD, compname, bufsize); | ||
397 | if (size >= bufsize) | ||
398 | { | ||
399 | errno = ENAMETOOLONG; | ||
400 | return -1; | ||
401 | } | ||
402 | ADVBUF(size); | ||
403 | } | ||
404 | |||
405 | #if PPP_SHOWPATHS | ||
406 | DEBUGF("PPP (post): \"%s\"" IF_MV(" vol:%d") "\n", | ||
407 | buffer0 IF_MV(, volume)); | ||
408 | #endif | ||
409 | |||
410 | return IF_MV(volume) +1; | ||
411 | } | ||
412 | |||
413 | |||
414 | /** File functions **/ | ||
415 | |||
416 | int sim_open(const char *path, int oflag, ...) | ||
417 | { | ||
418 | int fildes; | ||
419 | struct filestr_desc *filestr = alloc_filestr(&fildes); | ||
420 | if (!filestr) | ||
421 | { | ||
422 | errno = EMFILE; | ||
423 | return -1; | ||
424 | } | ||
425 | |||
426 | char ospath[SIM_TMPBUF_MAX_PATH]; | ||
427 | int pprc = sim_get_os_path(ospath, path, sizeof (ospath)); | ||
428 | if (pprc < 0) | ||
429 | return -2; | ||
430 | |||
431 | filestr->osfd = os_open(ospath, oflag | O_BINARY __OPEN_MODE_ARG); | ||
432 | if (filestr->osfd < 0) | ||
433 | return -3; | ||
434 | |||
435 | #ifdef HAVE_MULTIVOLUME | ||
436 | filestr->volume = MAX(pprc - 1, 0); | ||
437 | #endif | ||
438 | filestr->mounted = true; | ||
439 | return fildes; | ||
440 | } | ||
441 | |||
442 | int sim_creat(const char *path, mode_t mode) | ||
443 | { | ||
444 | return sim_open(path, O_WRONLY|O_CREAT|O_TRUNC, mode); | ||
445 | } | ||
446 | |||
447 | int sim_close(int fildes) | ||
448 | { | ||
449 | struct filestr_desc *filestr = &openfiles[fildes]; | ||
450 | if ((unsigned int)fildes >= MAX_OPEN_FILES || filestr->osfd < 0) | ||
451 | { | ||
452 | errno = EBADF; | ||
453 | return -1; | ||
454 | } | ||
455 | |||
456 | int osfd = filestr->osfd; | ||
457 | filestr->osfd = -1; | ||
458 | return os_close(osfd); | ||
459 | } | ||
460 | |||
461 | int sim_ftruncate(int fildes, off_t length) | ||
462 | { | ||
463 | struct filestr_desc *filestr = get_filestr(fildes); | ||
464 | if (!filestr) | ||
465 | return -1; | ||
466 | |||
467 | off_t size = os_filesize(filestr->osfd); | ||
468 | if (size < 0) | ||
469 | return -1; | ||
470 | |||
471 | if (length >= size) | ||
472 | return 0; | ||
473 | |||
474 | int rc = os_ftruncate(filestr->osfd, length); | ||
475 | |||
476 | #ifdef HAVE_DIRCACHE | ||
477 | if (rc >= 0) | ||
478 | dircache_ftruncate(xxxxxx); | ||
479 | #endif | ||
480 | |||
481 | return rc; | ||
482 | } | ||
483 | |||
484 | int sim_fsync(int fildes) | ||
485 | { | ||
486 | struct filestr_desc *filestr = get_filestr(fildes); | ||
487 | if (!filestr) | ||
488 | return -1; | ||
489 | |||
490 | int rc = os_fsync(filestr->osfd); | ||
491 | |||
492 | #ifdef HAVE_DIRCACHE | ||
493 | if (rc >= 0) | ||
494 | dircache_fsync(xxxxxx); | ||
495 | #endif | ||
496 | |||
497 | return rc; | ||
498 | } | ||
499 | |||
500 | off_t sim_lseek(int fildes, off_t offset, int whence) | ||
501 | { | ||
502 | struct filestr_desc *filestr = get_filestr(fildes); | ||
503 | if (!filestr) | ||
504 | return -1; | ||
505 | |||
506 | return os_lseek(filestr->osfd, offset, whence); | ||
507 | } | ||
508 | |||
509 | ssize_t sim_read(int fildes, void *buf, size_t nbyte) | ||
510 | { | ||
511 | struct filestr_desc *filestr = get_filestr(fildes); | ||
512 | if (!filestr) | ||
513 | return -1; | ||
514 | |||
515 | return os_read(filestr->osfd, buf, nbyte); | ||
516 | } | ||
517 | |||
518 | ssize_t sim_write(int fildes, const void *buf, size_t nbyte) | ||
519 | { | ||
520 | struct filestr_desc *filestr = get_filestr(fildes); | ||
521 | if (!filestr) | ||
522 | return -1; | ||
523 | |||
524 | return os_write(filestr->osfd, buf, nbyte); | ||
525 | } | ||
526 | |||
527 | int sim_remove(const char *path) | ||
528 | { | ||
529 | char ospath[SIM_TMPBUF_MAX_PATH]; | ||
530 | if (sim_get_os_path(ospath, path, sizeof (ospath)) < 0) | ||
531 | return -1; | ||
532 | |||
533 | int rc = os_remove(ospath); | ||
534 | |||
535 | #ifdef HAVE_DIRCACHE | ||
536 | if (rc >= 0) | ||
537 | dircache_remove(xxxxxx); | ||
538 | #endif | ||
539 | |||
540 | return rc; | ||
541 | } | ||
542 | |||
543 | int sim_rename(const char *old, const char *new) | ||
544 | { | ||
545 | char osold[SIM_TMPBUF_MAX_PATH]; | ||
546 | int pprc1 = sim_get_os_path(osold, old, sizeof (osold)); | ||
547 | if (pprc1 < 0) | ||
548 | return -1; | ||
549 | |||
550 | char osnew[SIM_TMPBUF_MAX_PATH]; | ||
551 | int pprc2 = sim_get_os_path(osnew, new, sizeof (osnew)); | ||
552 | if (pprc2 < 0) | ||
553 | return -1; | ||
554 | |||
555 | if (MAX(pprc1 - 1, 0) != MAX(pprc2 - 1, 0)) | ||
556 | { | ||
557 | /* Pretend they're different devices */ | ||
558 | errno = EXDEV; | ||
559 | return -1; | ||
560 | } | ||
561 | |||
562 | int rc = os_rename(osold, osnew); | ||
563 | |||
564 | #ifdef HAVE_DIRCACHE | ||
565 | if (rc >= 0) | ||
566 | dircache_rename(xxxxxx); | ||
567 | #endif | ||
568 | |||
569 | return rc; | ||
570 | } | ||
571 | |||
572 | off_t sim_filesize(int fildes) | ||
573 | { | ||
574 | struct filestr_desc *filestr = get_filestr(fildes); | ||
575 | if (!filestr) | ||
576 | return -1; | ||
577 | |||
578 | return os_filesize(filestr->osfd); | ||
579 | } | ||
580 | |||
581 | int sim_fsamefile(int fildes1, int fildes2) | ||
582 | { | ||
583 | struct filestr_desc *filestr1 = get_filestr(fildes1); | ||
584 | if (!filestr1) | ||
585 | return -1; | ||
586 | |||
587 | struct filestr_desc *filestr2 = get_filestr(fildes2); | ||
588 | if (!filestr2) | ||
589 | return -1; | ||
590 | |||
591 | if (filestr1 == filestr2) | ||
592 | return 1; | ||
593 | |||
594 | return os_fsamefile(filestr1->osfd, filestr2->osfd); | ||
595 | } | ||
596 | |||
597 | int sim_relate(const char *path1, const char *path2) | ||
598 | { | ||
599 | char ospath1[SIM_TMPBUF_MAX_PATH]; | ||
600 | if (sim_get_os_path(ospath1, path1, sizeof (ospath1)) < 0) | ||
601 | return -1; | ||
602 | |||
603 | char ospath2[SIM_TMPBUF_MAX_PATH]; | ||
604 | if (sim_get_os_path(ospath2, path2, sizeof (ospath2)) < 0) | ||
605 | return -1; | ||
606 | |||
607 | return os_relate(ospath1, ospath2); | ||
608 | } | ||
609 | |||
610 | bool sim_file_exists(const char *path) | ||
611 | { | ||
612 | char ospath[SIM_TMPBUF_MAX_PATH]; | ||
613 | if (sim_get_os_path(ospath, path, sizeof (ospath)) < 0) | ||
614 | return false; | ||
615 | |||
616 | return os_file_exists(ospath); | ||
617 | } | ||
618 | |||
619 | |||
620 | /** Directory functions **/ | ||
621 | DIR * sim_opendir(const char *dirname) | ||
622 | { | ||
623 | struct dirstr_desc *dirstr = alloc_dirstr(); | ||
624 | if (!dirstr) | ||
625 | { | ||
626 | errno = EMFILE; | ||
627 | return NULL; | ||
628 | } | ||
629 | |||
630 | char osdirname[SIM_TMPBUF_MAX_PATH]; | ||
631 | int pprc = sim_get_os_path(osdirname, dirname, sizeof (osdirname)); | ||
632 | if (pprc < 0) | ||
633 | return NULL; | ||
634 | |||
635 | int rc = os_opendir_and_fd(osdirname, &dirstr->osdirp, &dirstr->osfd); | ||
636 | if (rc < 0) | ||
637 | return NULL; | ||
638 | |||
639 | dirstr->osfd_opened = rc > 0; | ||
640 | |||
641 | #ifdef USE_OSDIRNAME | ||
642 | dirstr->osdirname = strdup(osdirname); | ||
643 | if (!dirstr->osdirname) | ||
644 | { | ||
645 | close_dirstr(dirstr); | ||
646 | return NULL; | ||
647 | } | ||
648 | #endif | ||
649 | |||
650 | dirstr->entry.d_name[0] = 0; /* Mark as invalid */ | ||
651 | #ifdef HAVE_MULTIVOLUME | ||
652 | dirstr->volume = MAX(pprc - 1, 0); | ||
653 | dirstr->volumecounter = pprc == 0 ? 0 : INT_MAX; | ||
654 | #endif | ||
655 | dirstr->mounted = true; | ||
656 | return (DIR *)dirstr; /* A-Okay */ | ||
657 | } | ||
658 | |||
659 | int sim_closedir(DIR *dirp) | ||
660 | { | ||
661 | struct dirstr_desc *dirstr = (struct dirstr_desc *)dirp; | ||
662 | if (!PTR_IN_ARRAY(opendirs, dirstr, MAX_OPEN_DIRS) || !dirstr->osdirp) | ||
663 | { | ||
664 | errno = EBADF; | ||
665 | return -1; | ||
666 | } | ||
667 | |||
668 | return close_dirstr(dirstr); | ||
669 | } | ||
670 | |||
671 | struct sim_dirent * sim_readdir(DIR *dirp) | ||
672 | { | ||
673 | struct dirstr_desc *dirstr = get_dirstr(dirp); | ||
674 | if (!dirstr) | ||
675 | return NULL; | ||
676 | |||
677 | struct sim_dirent *entry = &dirstr->entry; | ||
678 | entry->info.osdirent = NULL; | ||
679 | |||
680 | if (readdir_volume(dirstr, entry)) | ||
681 | return entry; | ||
682 | |||
683 | OS_DIRENT_T *osdirent = os_readdir(dirstr->osdirp); | ||
684 | if (!osdirent) | ||
685 | return NULL; | ||
686 | |||
687 | size_t size = sizeof (entry->d_name); | ||
688 | if (strlcpy_from_os(entry->d_name, osdirent->d_name, size) >= size) | ||
689 | FILE_ERROR_RETURN(ENAMETOOLONG, NULL); | ||
690 | |||
691 | entry->info.osdirent = osdirent; | ||
692 | return entry; | ||
693 | } | ||
694 | |||
695 | int sim_mkdir(const char *path) | ||
696 | { | ||
697 | char ospath[SIM_TMPBUF_MAX_PATH]; | ||
698 | if (sim_get_os_path(ospath, path, sizeof (ospath)) < 0) | ||
699 | return -1; | ||
700 | |||
701 | int rc = os_mkdir(ospath __MKDIR_MODE_ARG); | ||
702 | |||
703 | #ifdef HAVE_DIRCACHE | ||
704 | if (rc >= 0) | ||
705 | dircache_mkdir(xxxxxx); | ||
706 | #endif | ||
707 | |||
708 | return rc; | ||
709 | } | ||
710 | |||
711 | int sim_rmdir(const char *path) | ||
712 | { | ||
713 | char ospath[SIM_TMPBUF_MAX_PATH]; | ||
714 | if (sim_get_os_path(ospath, path, sizeof (ospath)) < 0) | ||
715 | return -1; | ||
716 | |||
717 | int rc = os_rmdir(ospath); | ||
718 | |||
719 | #ifdef HAVE_DIRCACHE | ||
720 | if (rc >= 0) | ||
721 | dircache_rmdir(xxxxxx); | ||
722 | #endif | ||
723 | |||
724 | return rc; | ||
725 | } | ||
726 | |||
727 | int sim_samedir(DIR *dirp1, DIR *dirp2) | ||
728 | { | ||
729 | struct dirstr_desc *dirstr1 = get_dirstr(dirp1); | ||
730 | if (!dirstr1) | ||
731 | return -1; | ||
732 | |||
733 | struct dirstr_desc *dirstr2 = get_dirstr(dirp2); | ||
734 | if (!dirstr2) | ||
735 | return -1; | ||
736 | |||
737 | return os_fsamefile(dirstr1->osfd, dirstr2->osfd); | ||
738 | } | ||
739 | |||
740 | bool sim_dir_exists(const char *dirname) | ||
741 | { | ||
742 | char osdirname[SIM_TMPBUF_MAX_PATH]; | ||
743 | if (sim_get_os_path(osdirname, dirname, sizeof (osdirname)) < 0) | ||
744 | return false; | ||
745 | |||
746 | OS_DIR_T *dirp = os_opendir(osdirname); | ||
747 | if (!dirp) | ||
748 | return false; | ||
749 | |||
750 | os_closedir(dirp); | ||
751 | return true; | ||
752 | } | ||
753 | |||
754 | struct dirinfo dir_get_info(DIR *dirp, struct sim_dirent *entry) | ||
755 | { | ||
756 | int rc; | ||
757 | struct dirstr_desc *dirstr = get_dirstr(dirp); | ||
758 | if (!dirstr) | ||
759 | FILE_ERROR(ERRNO, RC); | ||
760 | |||
761 | if (entry->d_name[0] == 0) | ||
762 | FILE_ERROR(ENOENT, RC); | ||
763 | |||
764 | OS_DIRENT_T *osdirent = entry->info.osdirent; | ||
765 | if (osdirent == NULL) | ||
766 | return (struct dirinfo){ .attribute = ATTR_MOUNT_POINT }; | ||
767 | |||
768 | struct dirinfo info; | ||
769 | info.attribute = 0; | ||
770 | |||
771 | OS_STAT_T s; | ||
772 | |||
773 | #ifdef os_fstatat | ||
774 | if (os_fstatat(dirstr->osfd, entry->d_name, &s, 0)) | ||
775 | #else /* no fstatat; build file name for stat() */ | ||
776 | char statpath[SIM_TMPBUF_MAX_PATH]; | ||
777 | if (path_append(statpath, dirstr->osdirname, entry->d_name, | ||
778 | sizeof (statpath)) >= sizeof (statpath)) | ||
779 | { | ||
780 | FILE_ERROR(ENAMETOOLONG, RC); | ||
781 | } | ||
782 | |||
783 | if (os_stat(statpath, &s)) /* get info */ | ||
784 | #endif /* os_fstatat */ | ||
785 | { | ||
786 | /* File size larger than 2 GB? */ | ||
787 | #ifdef EOVERFLOW | ||
788 | if (errno == EOVERFLOW) | ||
789 | DEBUGF("stat overflow for \"%s\"\n", entry->d_name); | ||
790 | #endif | ||
791 | FILE_ERROR(ERRNO, RC); | ||
792 | } | ||
793 | |||
794 | if (S_ISDIR(s.st_mode)) | ||
795 | info.attribute |= ATTR_DIRECTORY; | ||
796 | |||
797 | info.size = s.st_size; | ||
798 | |||
799 | struct tm tm; | ||
800 | if (localtime_r(&s.st_mtime, &tm) == NULL) | ||
801 | FILE_ERROR(ERRNO, RC); | ||
802 | |||
803 | info.mtime = mktime(&tm); | ||
804 | |||
805 | return info; | ||
806 | |||
807 | file_error: | ||
808 | return (struct dirinfo){ .size = 0 }; | ||
809 | } | ||
810 | |||
811 | int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize) | ||
812 | { | ||
813 | if (!buffer || !bufsize IF_MV( || !volume_present(volume) )) | ||
814 | return -1; | ||
815 | |||
816 | char tmpbuf[SIM_TMPBUF_MAX_PATH]; | ||
817 | tmpbuf[0] = '\0'; | ||
818 | |||
819 | #ifdef HAVE_MULTIVOLUME | ||
820 | char volname[VOL_MAX_LEN + 1]; | ||
821 | get_volume_name(volume, volname); | ||
822 | |||
823 | if (path_append(tmpbuf, PA_SEP_HARD, volname, sizeof (volname)) | ||
824 | >= sizeof (volname)) | ||
825 | return -1; | ||
826 | #endif /* HAVE_MULTIVOLUME */ | ||
827 | |||
828 | if (path_append(tmpbuf, PA_SEP_HARD, ".", sizeof (tmpbuf)) | ||
829 | >= sizeof (tmpbuf)) | ||
830 | return -1; | ||
831 | |||
832 | return sim_get_os_path(buffer, tmpbuf, bufsize); | ||
833 | } | ||
diff --git a/uisimulator/common/filesystem-sim.h b/uisimulator/common/filesystem-sim.h new file mode 100644 index 0000000000..7c46c449d8 --- /dev/null +++ b/uisimulator/common/filesystem-sim.h | |||
@@ -0,0 +1,108 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2014 by Michael Sevakis | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #ifndef _FILESYSTEM_SIM_H_ | ||
22 | #define _FILESYSTEM_SIM_H_ | ||
23 | |||
24 | #if defined(PLUGIN) || defined(CODEC) | ||
25 | /* Prevent often-problematic plugin namespace pollution */ | ||
26 | #define FILEFUNCTIONS_DECLARED | ||
27 | #define FILEFUNCTIONS_DEFINED | ||
28 | #define DIRFUNCTIONS_DECLARED | ||
29 | #define DIRFUNCTIONS_DEFINED | ||
30 | #define OSFUNCTIONS_DECLARED | ||
31 | #endif /* PLUGIN || CODEC */ | ||
32 | |||
33 | #ifndef OSFUNCTIONS_DECLARED | ||
34 | #define FS_PREFIX(_x_) sim_ ## _x_ | ||
35 | |||
36 | /* path sandboxing and volume redirector */ | ||
37 | int sim_get_os_path(char *buffer, const char *path, size_t bufsize); | ||
38 | #define SIM_TMPBUF_MAX_PATH (MAX_PATH+1) | ||
39 | |||
40 | #endif /* !OSFUNCTIONS_DECLARED */ | ||
41 | |||
42 | #endif /* _FILESYSTEM_SIM_H_ */ | ||
43 | |||
44 | #include "filesystem-sdl.h" | ||
45 | #ifdef WIN32 | ||
46 | #include "filesystem-win32.h" | ||
47 | #else /* !WIN32 */ | ||
48 | #include "filesystem-unix.h" | ||
49 | #endif /* WIN32 */ | ||
50 | #include "filesystem-hosted.h" | ||
51 | |||
52 | #ifdef _FILE_H_ | ||
53 | #ifndef _FILESYSTEM_SIM_H__FILE_H_ | ||
54 | #define _FILESYSTEM_SIM_H__FILE_H_ | ||
55 | |||
56 | #ifdef RB_FILESYSTEM_OS | ||
57 | #define FILEFUNCTIONS_DEFINED | ||
58 | #endif | ||
59 | |||
60 | #ifndef FILEFUNCTIONS_DECLARED | ||
61 | int sim_open(const char *name, int oflag, ...); | ||
62 | int sim_creat(const char *name, mode_t mode); | ||
63 | int sim_close(int fildes); | ||
64 | int sim_ftruncate(int fildes, off_t length); | ||
65 | int sim_fsync(int fildes); | ||
66 | off_t sim_lseek(int fildes, off_t offset, int whence); | ||
67 | ssize_t sim_read(int fildes, void *buf, size_t nbyte); | ||
68 | ssize_t sim_write(int fildes, const void *buf, size_t nbyte); | ||
69 | int sim_remove(const char *path); | ||
70 | int sim_rename(const char *old, const char *new); | ||
71 | off_t sim_filesize(int fildes); | ||
72 | int sim_fsamefile(int fildes1, int fildes2); | ||
73 | int sim_relate(const char *path1, const char *path2); | ||
74 | bool sim_file_exists(const char *path); | ||
75 | #endif /* !FILEFUNCTIONS_DECLARED */ | ||
76 | |||
77 | #endif /* _FILESYSTEM_SIM_H__FILE_H_ */ | ||
78 | #endif /* _FILE_H_ */ | ||
79 | |||
80 | #ifdef _DIR_H_ | ||
81 | #ifndef _FILESYSTEM_SIM_H__DIR_H_ | ||
82 | #define _FILESYSTEM_SIM_H__DIR_H_ | ||
83 | |||
84 | #ifdef RB_FILESYSTEM_OS | ||
85 | #define DIRFUNCTIONS_DEFINED | ||
86 | #else | ||
87 | #define dirent DIRENT | ||
88 | #endif | ||
89 | |||
90 | #define DIRENT sim_dirent | ||
91 | |||
92 | struct dirinfo_native | ||
93 | { | ||
94 | void *osdirent; | ||
95 | }; | ||
96 | |||
97 | #ifndef DIRFUNCTIONS_DECLARED | ||
98 | DIR * sim_opendir(const char *dirname); | ||
99 | struct sim_dirent * sim_readdir(DIR *dirp); | ||
100 | int sim_closedir(DIR *dirp); | ||
101 | int sim_mkdir(const char *path); | ||
102 | int sim_rmdir(const char *path); | ||
103 | int sim_samedir(DIR *dirp1, DIR *dirp2); | ||
104 | bool sim_dir_exists(const char *dirname); | ||
105 | #endif /* !DIRFUNCTIONS_DECLARED */ | ||
106 | |||
107 | #endif /* _FILESYSTEM_SIM_H__DIR_H_ */ | ||
108 | #endif /* _DIR_H_ */ | ||
diff --git a/uisimulator/common/io.c b/uisimulator/common/io.c deleted file mode 100644 index 6662e9ffda..0000000000 --- a/uisimulator/common/io.c +++ /dev/null | |||
@@ -1,729 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 Daniel Stenberg | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
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 "system.h" | ||
31 | #include "ata_idle_notify.h" | ||
32 | #include "mv.h" | ||
33 | |||
34 | #define HAVE_STATVFS (!defined(WIN32)) | ||
35 | #define HAVE_LSTAT (!defined(WIN32)) | ||
36 | |||
37 | #if HAVE_STATVFS | ||
38 | #include <sys/statvfs.h> | ||
39 | #endif | ||
40 | |||
41 | #ifdef WIN32 | ||
42 | #include <windows.h> | ||
43 | #endif | ||
44 | |||
45 | #ifndef _MSC_VER | ||
46 | #include <dirent.h> | ||
47 | #include <unistd.h> | ||
48 | #else | ||
49 | #include "dir-win32.h" | ||
50 | #endif | ||
51 | |||
52 | #include <fcntl.h> | ||
53 | #ifdef HAVE_SDL_THREADS | ||
54 | #include "thread-sdl.h" | ||
55 | #else | ||
56 | #define sim_thread_unlock() NULL | ||
57 | #define sim_thread_lock(a) | ||
58 | #endif | ||
59 | #include "thread.h" | ||
60 | #include "kernel.h" | ||
61 | #include "debug.h" | ||
62 | #include "ata.h" /* for IF_MV et al. */ | ||
63 | #include "rbpaths.h" | ||
64 | #include "load_code.h" | ||
65 | |||
66 | /* keep this in sync with file.h! */ | ||
67 | #undef MAX_PATH /* this avoids problems when building simulator */ | ||
68 | #define MAX_PATH 260 | ||
69 | #define MAX_OPEN_FILES 11 | ||
70 | |||
71 | /* Windows (and potentially other OSes) distinguish binary and text files. | ||
72 | * Define a dummy for the others. */ | ||
73 | #ifndef O_BINARY | ||
74 | #define O_BINARY 0 | ||
75 | #endif | ||
76 | |||
77 | /* Unicode compatibility for win32 */ | ||
78 | #if defined __MINGW32__ | ||
79 | /* Rockbox unicode functions */ | ||
80 | extern const unsigned char* utf8decode(const unsigned char *utf8, | ||
81 | unsigned short *ucs); | ||
82 | extern unsigned char* utf8encode(unsigned long ucs, unsigned char *utf8); | ||
83 | |||
84 | /* Static buffers for the conversion results. This isn't thread safe, | ||
85 | * but it's sufficient for rockbox. */ | ||
86 | static unsigned char convbuf1[3*MAX_PATH]; | ||
87 | static unsigned char convbuf2[3*MAX_PATH]; | ||
88 | |||
89 | static wchar_t* utf8_to_ucs2(const unsigned char *utf8, void *buffer) | ||
90 | { | ||
91 | wchar_t *ucs = buffer; | ||
92 | |||
93 | while (*utf8) | ||
94 | utf8 = utf8decode(utf8, ucs++); | ||
95 | |||
96 | *ucs = 0; | ||
97 | return buffer; | ||
98 | } | ||
99 | static unsigned char *ucs2_to_utf8(const wchar_t *ucs, unsigned char *buffer) | ||
100 | { | ||
101 | unsigned char *utf8 = buffer; | ||
102 | |||
103 | while (*ucs) | ||
104 | utf8 = utf8encode(*ucs++, utf8); | ||
105 | |||
106 | *utf8 = 0; | ||
107 | return buffer; | ||
108 | } | ||
109 | |||
110 | #define UTF8_TO_OS(a) utf8_to_ucs2(a,convbuf1) | ||
111 | #define OS_TO_UTF8(a) ucs2_to_utf8(a,convbuf1) | ||
112 | #define DIR_T _WDIR | ||
113 | #define DIRENT_T struct _wdirent | ||
114 | #define STAT_T struct _stat | ||
115 | extern int _wmkdir(const wchar_t*); | ||
116 | extern int _wrmdir(const wchar_t*); | ||
117 | #define MKDIR(a,b) (_wmkdir)(UTF8_TO_OS(a)) | ||
118 | #define RMDIR(a) (_wrmdir)(UTF8_TO_OS(a)) | ||
119 | #define OPENDIR(a) (_wopendir)(UTF8_TO_OS(a)) | ||
120 | #define READDIR(a) (_wreaddir)(a) | ||
121 | #define CLOSEDIR(a) (_wclosedir)(a) | ||
122 | #define STAT(a,b) (_wstat)(UTF8_TO_OS(a),b) | ||
123 | /* empty variable parameter list doesn't work for variadic macros, | ||
124 | * so pretend the second parameter is variable too */ | ||
125 | #define OPEN(a,...) (_wopen)(UTF8_TO_OS(a), __VA_ARGS__) | ||
126 | #define CLOSE(a) (close)(a) | ||
127 | #define REMOVE(a) (_wremove)(UTF8_TO_OS(a)) | ||
128 | #define RENAME(a,b) (_wrename)(UTF8_TO_OS(a),utf8_to_ucs2(b,convbuf2)) | ||
129 | /* readlink isn't used in the sim yet (FIXME) */ | ||
130 | #define READLINK(a,b,c) ({ fprintf(stderr, "no readlink on windows yet"); abort(); }) | ||
131 | #else /* !__MINGW32__ */ | ||
132 | |||
133 | #define UTF8_TO_OS(a) (a) | ||
134 | #define OS_TO_UTF8(a) (a) | ||
135 | #define DIR_T DIR | ||
136 | #define DIRENT_T struct dirent | ||
137 | #define STAT_T struct stat | ||
138 | #define MKDIR(a,b) (mkdir)(a,b) | ||
139 | #define RMDIR(a) (rmdir)(a) | ||
140 | #define OPENDIR(a) (opendir)(a) | ||
141 | #define READDIR(a) (readdir)(a) | ||
142 | #define CLOSEDIR(a) (closedir)(a) | ||
143 | #define STAT(a,b) (stat)(a,b) | ||
144 | /* empty variable parameter list doesn't work for variadic macros, | ||
145 | * so pretend the second parameter is variable too */ | ||
146 | #define OPEN(a, ...) (open)(a, __VA_ARGS__) | ||
147 | #define CLOSE(x) (close)(x) | ||
148 | #define REMOVE(a) (remove)(a) | ||
149 | #define RENAME(a,b) (rename)(a,b) | ||
150 | #define READLINK(a,b,c) (readlink)(a,b,c) | ||
151 | |||
152 | #endif /* !__MINGW32__ */ | ||
153 | |||
154 | |||
155 | #ifdef HAVE_DIRCACHE | ||
156 | int dircache_get_entry_id(const char *filename); | ||
157 | void dircache_add_file(const char *name, long startcluster); | ||
158 | void dircache_remove(const char *name); | ||
159 | void dircache_rename(const char *oldname, const char *newname); | ||
160 | #endif | ||
161 | |||
162 | #ifndef APPLICATION | ||
163 | |||
164 | #define SIMULATOR_DEFAULT_ROOT "simdisk" | ||
165 | extern const char *sim_root_dir; | ||
166 | |||
167 | static int num_openfiles = 0; | ||
168 | |||
169 | /* from dir.h */ | ||
170 | struct dirinfo { | ||
171 | int attribute; | ||
172 | long size; | ||
173 | unsigned short wrtdate; | ||
174 | unsigned short wrttime; | ||
175 | }; | ||
176 | |||
177 | struct sim_dirent { | ||
178 | unsigned char d_name[MAX_PATH]; | ||
179 | struct dirinfo info; | ||
180 | long startcluster; | ||
181 | }; | ||
182 | |||
183 | struct dirstruct { | ||
184 | void *dir; /* actually a DIR* dir */ | ||
185 | char *name; | ||
186 | } SIM_DIR; | ||
187 | |||
188 | struct mydir { | ||
189 | DIR_T *dir; | ||
190 | IF_MV(int volumes_returned); | ||
191 | char *name; | ||
192 | }; | ||
193 | |||
194 | typedef struct mydir MYDIR; | ||
195 | |||
196 | static unsigned int rockbox2sim(int opt) | ||
197 | { | ||
198 | #if 0 | ||
199 | /* this shouldn't be needed since we use the host's versions */ | ||
200 | int newopt = O_BINARY; | ||
201 | |||
202 | if(opt & 1) | ||
203 | newopt |= O_WRONLY; | ||
204 | if(opt & 2) | ||
205 | newopt |= O_RDWR; | ||
206 | if(opt & 4) | ||
207 | newopt |= O_CREAT; | ||
208 | if(opt & 8) | ||
209 | newopt |= O_APPEND; | ||
210 | if(opt & 0x10) | ||
211 | newopt |= O_TRUNC; | ||
212 | |||
213 | return newopt; | ||
214 | #else | ||
215 | return opt|O_BINARY; | ||
216 | #endif | ||
217 | } | ||
218 | |||
219 | #endif /* APPLICATION */ | ||
220 | |||
221 | /** Simulator I/O engine routines **/ | ||
222 | #define IO_YIELD_THRESHOLD 512 | ||
223 | |||
224 | enum io_dir | ||
225 | { | ||
226 | IO_READ, | ||
227 | IO_WRITE, | ||
228 | }; | ||
229 | |||
230 | struct sim_io | ||
231 | { | ||
232 | struct mutex sim_mutex; /* Rockbox mutex */ | ||
233 | int cmd; /* The command to perform */ | ||
234 | int ready; /* I/O ready flag - 1= ready */ | ||
235 | int fd; /* The file to read/write */ | ||
236 | void *buf; /* The buffer to read/write */ | ||
237 | size_t count; /* Number of bytes to read/write */ | ||
238 | size_t accum; /* Acculated bytes transferred */ | ||
239 | }; | ||
240 | |||
241 | static struct sim_io io; | ||
242 | |||
243 | int ata_init(void) | ||
244 | { | ||
245 | /* Initialize the rockbox kernel objects on a rockbox thread */ | ||
246 | mutex_init(&io.sim_mutex); | ||
247 | io.accum = 0; | ||
248 | return 1; | ||
249 | } | ||
250 | |||
251 | int ata_spinup_time(void) | ||
252 | { | ||
253 | return HZ; | ||
254 | } | ||
255 | |||
256 | static ssize_t io_trigger_and_wait(enum io_dir cmd) | ||
257 | { | ||
258 | void *mythread = NULL; | ||
259 | ssize_t result; | ||
260 | |||
261 | if (io.count > IO_YIELD_THRESHOLD || | ||
262 | (io.accum += io.count) >= IO_YIELD_THRESHOLD) | ||
263 | { | ||
264 | /* Allow other rockbox threads to run */ | ||
265 | io.accum = 0; | ||
266 | mythread = sim_thread_unlock(); | ||
267 | } | ||
268 | |||
269 | switch (cmd) | ||
270 | { | ||
271 | case IO_READ: | ||
272 | result = read(io.fd, io.buf, io.count); | ||
273 | break; | ||
274 | case IO_WRITE: | ||
275 | result = write(io.fd, io.buf, io.count); | ||
276 | break; | ||
277 | /* shut up gcc */ | ||
278 | default: | ||
279 | result = -1; | ||
280 | } | ||
281 | |||
282 | call_storage_idle_notifys(false); | ||
283 | |||
284 | /* Regain our status as current */ | ||
285 | if (mythread != NULL) | ||
286 | { | ||
287 | sim_thread_lock(mythread); | ||
288 | } | ||
289 | |||
290 | return result; | ||
291 | } | ||
292 | |||
293 | |||
294 | ssize_t sim_read(int fd, void *buf, size_t count) | ||
295 | { | ||
296 | ssize_t result; | ||
297 | |||
298 | mutex_lock(&io.sim_mutex); | ||
299 | |||
300 | /* Setup parameters */ | ||
301 | io.fd = fd; | ||
302 | io.buf = buf; | ||
303 | io.count = count; | ||
304 | |||
305 | result = io_trigger_and_wait(IO_READ); | ||
306 | |||
307 | mutex_unlock(&io.sim_mutex); | ||
308 | |||
309 | return result; | ||
310 | } | ||
311 | |||
312 | |||
313 | ssize_t sim_write(int fd, const void *buf, size_t count) | ||
314 | { | ||
315 | ssize_t result; | ||
316 | |||
317 | mutex_lock(&io.sim_mutex); | ||
318 | |||
319 | io.fd = fd; | ||
320 | io.buf = (void*)buf; | ||
321 | io.count = count; | ||
322 | |||
323 | result = io_trigger_and_wait(IO_WRITE); | ||
324 | |||
325 | mutex_unlock(&io.sim_mutex); | ||
326 | |||
327 | return result; | ||
328 | } | ||
329 | |||
330 | #if !defined(APPLICATION) | ||
331 | |||
332 | static const char *handle_special_links(const char* link) | ||
333 | { | ||
334 | #ifdef HAVE_MULTIDRIVE | ||
335 | static char buffer[MAX_PATH]; /* sufficiently big */ | ||
336 | char vol_string[VOL_ENUM_POS + 8]; | ||
337 | int len = sprintf(vol_string, VOL_NAMES, 1); | ||
338 | |||
339 | /* link might be passed with or without HOME_DIR expanded. To handle | ||
340 | * both perform substring matching (VOL_NAMES is unique enough) */ | ||
341 | const char *begin = strstr(link, vol_string); | ||
342 | if (begin) | ||
343 | { | ||
344 | /* begin now points to the start of vol_string within link, | ||
345 | * we want to copy the remainder of the paths, prefixed by | ||
346 | * the actual mount point (the remainder might be "") */ | ||
347 | snprintf(buffer, sizeof(buffer), "%s/../simext/%s", | ||
348 | sim_root_dir ?: SIMULATOR_DEFAULT_ROOT, begin + len); | ||
349 | return buffer; | ||
350 | } | ||
351 | else | ||
352 | #endif | ||
353 | return link; | ||
354 | } | ||
355 | |||
356 | |||
357 | static const char *get_sim_pathname(const char *name) | ||
358 | { | ||
359 | static char buffer[MAX_PATH]; /* sufficiently big */ | ||
360 | |||
361 | if(name[0] == '/') | ||
362 | { | ||
363 | snprintf(buffer, sizeof(buffer), "%s%s", | ||
364 | sim_root_dir ?: SIMULATOR_DEFAULT_ROOT, name); | ||
365 | return handle_special_links(buffer); | ||
366 | } | ||
367 | fprintf(stderr, "WARNING, bad file name lacks slash: %s\n", name); | ||
368 | return name; | ||
369 | } | ||
370 | |||
371 | |||
372 | MYDIR *sim_opendir(const char *name) | ||
373 | { | ||
374 | DIR_T *dir; | ||
375 | dir = (DIR_T *) OPENDIR(get_sim_pathname(name)); | ||
376 | |||
377 | if (dir) | ||
378 | { | ||
379 | MYDIR *my = (MYDIR *)malloc(sizeof(MYDIR)); | ||
380 | my->dir = dir; | ||
381 | my->name = (char *)malloc(strlen(name)+1); | ||
382 | strcpy(my->name, name); | ||
383 | IF_MV(my->volumes_returned = 0); | ||
384 | |||
385 | return my; | ||
386 | } | ||
387 | /* failed open, return NULL */ | ||
388 | return (MYDIR *)0; | ||
389 | } | ||
390 | |||
391 | #if defined(WIN32) | ||
392 | static inline struct tm* localtime_r (const time_t *clock, struct tm *result) { | ||
393 | if (!clock || !result) return NULL; | ||
394 | memcpy(result,localtime(clock),sizeof(*result)); | ||
395 | return result; | ||
396 | } | ||
397 | #endif | ||
398 | |||
399 | struct sim_dirent *sim_readdir(MYDIR *dir) | ||
400 | { | ||
401 | char buffer[MAX_PATH]; /* sufficiently big */ | ||
402 | static struct sim_dirent secret; | ||
403 | STAT_T s; | ||
404 | struct tm tm; | ||
405 | DIRENT_T *x11; | ||
406 | |||
407 | #ifdef EOVERFLOW | ||
408 | read_next: | ||
409 | #endif | ||
410 | |||
411 | #define ATTR_LINK 0x80 /* see dir.h */ | ||
412 | |||
413 | secret.info.attribute = 0; | ||
414 | #ifdef HAVE_MULTIVOLUME | ||
415 | if (dir->name[0] == '/' && dir->name[1] == '\0' | ||
416 | && dir->volumes_returned++ < (NUM_VOLUMES-1) | ||
417 | && volume_present(dir->volumes_returned)) | ||
418 | { | ||
419 | sprintf((char *)secret.d_name, VOL_NAMES, dir->volumes_returned); | ||
420 | secret.info.attribute = ATTR_LINK; | ||
421 | /* build file name for stat() which is the actual mount point */ | ||
422 | snprintf(buffer, sizeof(buffer), "%s/../simext", | ||
423 | sim_root_dir ?: SIMULATOR_DEFAULT_ROOT); | ||
424 | } | ||
425 | else | ||
426 | #endif | ||
427 | { | ||
428 | x11 = READDIR(dir->dir); | ||
429 | |||
430 | if(!x11) | ||
431 | return (struct sim_dirent *)0; | ||
432 | |||
433 | strcpy((char *)secret.d_name, OS_TO_UTF8(x11->d_name)); | ||
434 | /* build file name for stat() */ | ||
435 | snprintf(buffer, sizeof(buffer), "%s/%s", | ||
436 | get_sim_pathname(dir->name), secret.d_name); | ||
437 | } | ||
438 | |||
439 | if (STAT(buffer, &s)) /* get info */ | ||
440 | { | ||
441 | #ifdef EOVERFLOW | ||
442 | /* File size larger than 2 GB? */ | ||
443 | if (errno == EOVERFLOW) | ||
444 | { | ||
445 | DEBUGF("stat() overflow for %s. Skipping\n", buffer); | ||
446 | goto read_next; | ||
447 | } | ||
448 | #endif | ||
449 | |||
450 | return NULL; | ||
451 | } | ||
452 | |||
453 | #define ATTR_DIRECTORY 0x10 | ||
454 | |||
455 | if (S_ISDIR(s.st_mode)) | ||
456 | secret.info.attribute = ATTR_DIRECTORY; | ||
457 | |||
458 | secret.info.size = s.st_size; | ||
459 | |||
460 | if (localtime_r(&(s.st_mtime), &tm) == NULL) | ||
461 | return NULL; | ||
462 | secret.info.wrtdate = ((tm.tm_year - 80) << 9) | | ||
463 | ((tm.tm_mon + 1) << 5) | | ||
464 | tm.tm_mday; | ||
465 | secret.info.wrttime = (tm.tm_hour << 11) | | ||
466 | (tm.tm_min << 5) | | ||
467 | (tm.tm_sec >> 1); | ||
468 | |||
469 | #if HAVE_LSTAT | ||
470 | if (!lstat(buffer, &s) && S_ISLNK(s.st_mode)) | ||
471 | { | ||
472 | secret.info.attribute |= ATTR_LINK; | ||
473 | } | ||
474 | #endif | ||
475 | |||
476 | return &secret; | ||
477 | } | ||
478 | |||
479 | void sim_closedir(MYDIR *dir) | ||
480 | { | ||
481 | free(dir->name); | ||
482 | CLOSEDIR(dir->dir); | ||
483 | |||
484 | free(dir); | ||
485 | } | ||
486 | |||
487 | int sim_open(const char *name, int o, ...) | ||
488 | { | ||
489 | int opts = rockbox2sim(o); | ||
490 | int ret; | ||
491 | if (num_openfiles >= MAX_OPEN_FILES) | ||
492 | return -2; | ||
493 | |||
494 | if (opts & O_CREAT) | ||
495 | { | ||
496 | va_list ap; | ||
497 | va_start(ap, o); | ||
498 | mode_t mode = va_arg(ap, unsigned int); | ||
499 | ret = OPEN(get_sim_pathname(name), opts, mode); | ||
500 | #ifdef HAVE_DIRCACHE | ||
501 | if (ret >= 0 && (dircache_get_entry_id(name) < 0)) | ||
502 | dircache_add_file(name, 0); | ||
503 | #endif | ||
504 | va_end(ap); | ||
505 | } | ||
506 | else | ||
507 | ret = OPEN(get_sim_pathname(name), opts); | ||
508 | |||
509 | if (ret >= 0) | ||
510 | num_openfiles++; | ||
511 | return ret; | ||
512 | } | ||
513 | |||
514 | int sim_close(int fd) | ||
515 | { | ||
516 | int ret; | ||
517 | ret = CLOSE(fd); | ||
518 | if (ret == 0) | ||
519 | num_openfiles--; | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | int sim_creat(const char *name, mode_t mode) | ||
524 | { | ||
525 | int ret = OPEN(get_sim_pathname(name), | ||
526 | O_BINARY | O_WRONLY | O_CREAT | O_TRUNC, mode); | ||
527 | #ifdef HAVE_DIRCACHE | ||
528 | if (ret >= 0 && (dircache_get_entry_id(name) < 0)) | ||
529 | dircache_add_file(name, 0); | ||
530 | #endif | ||
531 | return ret; | ||
532 | } | ||
533 | |||
534 | int sim_mkdir(const char *name) | ||
535 | { | ||
536 | return MKDIR(get_sim_pathname(name), 0777); | ||
537 | } | ||
538 | |||
539 | int sim_rmdir(const char *name) | ||
540 | { | ||
541 | return RMDIR(get_sim_pathname(name)); | ||
542 | } | ||
543 | |||
544 | int sim_remove(const char *name) | ||
545 | { | ||
546 | int ret = REMOVE(get_sim_pathname(name)); | ||
547 | #ifdef HAVE_DIRCACHE | ||
548 | if (ret >= 0) | ||
549 | dircache_remove(name); | ||
550 | #endif | ||
551 | return ret; | ||
552 | } | ||
553 | |||
554 | int sim_rename(const char *oldname, const char *newname) | ||
555 | { | ||
556 | char sim_old[MAX_PATH]; | ||
557 | char sim_new[MAX_PATH]; | ||
558 | #ifdef HAVE_DIRCACHE | ||
559 | dircache_rename(oldname, newname); | ||
560 | #endif | ||
561 | // This is needed as get_sim_pathname() has a static buffer | ||
562 | strncpy(sim_old, get_sim_pathname(oldname), MAX_PATH); | ||
563 | strncpy(sim_new, get_sim_pathname(newname), MAX_PATH); | ||
564 | return RENAME(sim_old, sim_new); | ||
565 | } | ||
566 | |||
567 | /* rockbox off_t may be different from system off_t */ | ||
568 | long sim_lseek(int fildes, long offset, int whence) | ||
569 | { | ||
570 | return lseek(fildes, offset, whence); | ||
571 | } | ||
572 | |||
573 | #else | ||
574 | #define get_sim_pathname(x) x | ||
575 | #endif | ||
576 | |||
577 | long filesize(int fd) | ||
578 | { | ||
579 | #ifdef WIN32 | ||
580 | return _filelength(fd); | ||
581 | #else | ||
582 | struct stat buf; | ||
583 | |||
584 | if (!fstat(fd, &buf)) | ||
585 | return buf.st_size; | ||
586 | else | ||
587 | return -1; | ||
588 | #endif | ||
589 | } | ||
590 | |||
591 | void fat_size(IF_MV(int volume,) unsigned long* size, unsigned long* free) | ||
592 | { | ||
593 | #ifdef HAVE_MULTIVOLUME | ||
594 | if (volume != 0) { | ||
595 | /* debugf("io.c: fat_size(volume=%d); simulator only supports volume 0\n",volume); */ | ||
596 | |||
597 | if (size) *size = 0; | ||
598 | if (free) *free = 0; | ||
599 | return; | ||
600 | } | ||
601 | #endif | ||
602 | |||
603 | #ifdef WIN32 | ||
604 | long secperclus, bytespersec, free_clusters, num_clusters; | ||
605 | |||
606 | if (GetDiskFreeSpace(NULL, &secperclus, &bytespersec, &free_clusters, | ||
607 | &num_clusters)) { | ||
608 | if (size) | ||
609 | *size = num_clusters * secperclus / 2 * (bytespersec / 512); | ||
610 | if (free) | ||
611 | *free = free_clusters * secperclus / 2 * (bytespersec / 512); | ||
612 | } else | ||
613 | #elif HAVE_STATVFS | ||
614 | struct statvfs vfs; | ||
615 | |||
616 | if (!statvfs(".", &vfs)) { | ||
617 | DEBUGF("statvfs: frsize=%d blocks=%ld free=%ld\n", | ||
618 | (int)vfs.f_frsize, (long)vfs.f_blocks, (long)vfs.f_bfree); | ||
619 | if (size) | ||
620 | *size = vfs.f_blocks / 2 * (vfs.f_frsize / 512); | ||
621 | if (free) | ||
622 | *free = vfs.f_bfree / 2 * (vfs.f_frsize / 512); | ||
623 | } else | ||
624 | #endif | ||
625 | { | ||
626 | if (size) | ||
627 | *size = 0; | ||
628 | if (free) | ||
629 | *free = 0; | ||
630 | } | ||
631 | } | ||
632 | |||
633 | int sim_fsync(int fd) | ||
634 | { | ||
635 | #ifdef WIN32 | ||
636 | return _commit(fd); | ||
637 | #else | ||
638 | return fsync(fd); | ||
639 | #endif | ||
640 | } | ||
641 | |||
642 | #ifndef __PCTOOL__ | ||
643 | |||
644 | #include <SDL_loadso.h> | ||
645 | void *lc_open(const char *filename, unsigned char *buf, size_t buf_size) | ||
646 | { | ||
647 | (void)buf; | ||
648 | (void)buf_size; | ||
649 | void *handle = SDL_LoadObject(get_sim_pathname(filename)); | ||
650 | if (handle == NULL) | ||
651 | { | ||
652 | DEBUGF("failed to load %s\n", filename); | ||
653 | DEBUGF("lc_open(%s): %s\n", filename, SDL_GetError()); | ||
654 | } | ||
655 | return handle; | ||
656 | } | ||
657 | |||
658 | void *lc_get_header(void *handle) | ||
659 | { | ||
660 | char *ret = SDL_LoadFunction(handle, "__header"); | ||
661 | if (ret == NULL) | ||
662 | ret = SDL_LoadFunction(handle, "___header"); | ||
663 | |||
664 | return ret; | ||
665 | } | ||
666 | |||
667 | void lc_close(void *handle) | ||
668 | { | ||
669 | SDL_UnloadObject(handle); | ||
670 | } | ||
671 | |||
672 | void *lc_open_from_mem(void *addr, size_t blob_size) | ||
673 | { | ||
674 | #ifndef SIMULATOR | ||
675 | (void)addr; | ||
676 | (void)blob_size; | ||
677 | /* we don't support loading code from memory on application builds, | ||
678 | * it doesn't make sense (since it means writing the blob to disk again and | ||
679 | * then falling back to load from disk) and requires the ability to write | ||
680 | * to an executable directory */ | ||
681 | return NULL; | ||
682 | #else | ||
683 | /* support it in the sim for the sake of simulating */ | ||
684 | int fd, i; | ||
685 | char temp_filename[MAX_PATH]; | ||
686 | |||
687 | /* We have to create the dynamic link library file from ram so we | ||
688 | can simulate the codec loading. With voice and crossfade, | ||
689 | multiple codecs may be loaded at the same time, so we need | ||
690 | to find an unused filename */ | ||
691 | for (i = 0; i < 10; i++) | ||
692 | { | ||
693 | snprintf(temp_filename, sizeof(temp_filename), | ||
694 | ROCKBOX_DIR "/libtemp_binary_%d.dll", i); | ||
695 | fd = open(temp_filename, O_WRONLY|O_CREAT|O_TRUNC, 0700); | ||
696 | if (fd >= 0) | ||
697 | break; /* Created a file ok */ | ||
698 | } | ||
699 | |||
700 | if (fd < 0) | ||
701 | { | ||
702 | DEBUGF("open failed\n"); | ||
703 | return NULL; | ||
704 | } | ||
705 | |||
706 | if (write(fd, addr, blob_size) < (ssize_t)blob_size) | ||
707 | { | ||
708 | DEBUGF("Write failed\n"); | ||
709 | close(fd); | ||
710 | remove(temp_filename); | ||
711 | return NULL; | ||
712 | } | ||
713 | |||
714 | close(fd); | ||
715 | return lc_open(temp_filename, NULL, 0); | ||
716 | #endif | ||
717 | } | ||
718 | |||
719 | #endif /* __PCTOOL__ */ | ||
720 | |||
721 | /* rockbox off_t may be different from system off_t */ | ||
722 | int sim_ftruncate(int fd, long length) | ||
723 | { | ||
724 | #ifdef WIN32 | ||
725 | return _chsize(fd, length); | ||
726 | #else | ||
727 | return ftruncate(fd, length); | ||
728 | #endif | ||
729 | } | ||
diff --git a/uisimulator/common/load_code-sim.c b/uisimulator/common/load_code-sim.c new file mode 100644 index 0000000000..59ca97a259 --- /dev/null +++ b/uisimulator/common/load_code-sim.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2002 Daniel Stenberg | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #define RB_FILESYSTEM_OS | ||
22 | #include <stdio.h> | ||
23 | #include "config.h" | ||
24 | #include "system.h" | ||
25 | #include "file.h" | ||
26 | #include "load_code.h" | ||
27 | #include "rbpaths.h" | ||
28 | #include "debug.h" | ||
29 | |||
30 | void * lc_open(const char *filename, unsigned char *buf, size_t buf_size) | ||
31 | { | ||
32 | char osfilename[SIM_TMPBUF_MAX_PATH]; | ||
33 | if (sim_get_os_path(osfilename, filename, sizeof (osfilename)) < 0) | ||
34 | return NULL; | ||
35 | |||
36 | return os_lc_open(osfilename); | ||
37 | (void)buf; (void)buf_size; | ||
38 | } | ||
39 | |||
40 | void * lc_open_from_mem(void *addr, size_t blob_size) | ||
41 | { | ||
42 | /* We have to create the dynamic link library file from ram so we can | ||
43 | simulate code loading. Multiple binaries may be loaded at the same | ||
44 | time, so we need to find an unused filename. */ | ||
45 | int fd; | ||
46 | char tempfile[SIM_TMPBUF_MAX_PATH]; | ||
47 | for (unsigned int i = 0; i < 10; i++) | ||
48 | { | ||
49 | snprintf(tempfile, sizeof(tempfile), | ||
50 | ROCKBOX_DIR "/libtemp_binary_%d.dll", i); | ||
51 | fd = sim_open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0700); | ||
52 | if (fd >= 0) | ||
53 | break; /* Created a file ok */ | ||
54 | } | ||
55 | |||
56 | if (fd < 0) | ||
57 | { | ||
58 | DEBUGF("open failed\n"); | ||
59 | return NULL; | ||
60 | } | ||
61 | |||
62 | if (sim_write(fd, addr, blob_size) != (ssize_t)blob_size) | ||
63 | { | ||
64 | DEBUGF("Write failed\n"); | ||
65 | sim_close(fd); | ||
66 | sim_remove(tempfile); | ||
67 | return NULL; | ||
68 | } | ||
69 | |||
70 | sim_close(fd); | ||
71 | return lc_open(tempfile, NULL, 0); | ||
72 | } | ||
diff --git a/uisimulator/common/sim_tasks.c b/uisimulator/common/sim_tasks.c index 1299a69302..003b993740 100644 --- a/uisimulator/common/sim_tasks.c +++ b/uisimulator/common/sim_tasks.c | |||
@@ -28,6 +28,11 @@ | |||
28 | #include "thread.h" | 28 | #include "thread.h" |
29 | #include "debug.h" | 29 | #include "debug.h" |
30 | #include "usb.h" | 30 | #include "usb.h" |
31 | #include "mv.h" | ||
32 | #include "ata_idle_notify.h" | ||
33 | #ifdef WIN32 | ||
34 | #include <windows.h> | ||
35 | #endif | ||
31 | 36 | ||
32 | static void sim_thread(void); | 37 | static void sim_thread(void); |
33 | static long sim_thread_stack[DEFAULT_STACK_SIZE/sizeof(long)]; | 38 | static long sim_thread_stack[DEFAULT_STACK_SIZE/sizeof(long)]; |
@@ -46,6 +51,10 @@ enum { | |||
46 | #endif | 51 | #endif |
47 | }; | 52 | }; |
48 | 53 | ||
54 | #ifdef HAVE_MULTIDRIVE | ||
55 | extern void sim_ext_extracted(int drive); | ||
56 | #endif | ||
57 | |||
49 | void sim_thread(void) | 58 | void sim_thread(void) |
50 | { | 59 | { |
51 | struct queue_event ev; | 60 | struct queue_event ev; |
@@ -54,9 +63,13 @@ void sim_thread(void) | |||
54 | 63 | ||
55 | while (1) | 64 | while (1) |
56 | { | 65 | { |
57 | queue_wait(&sim_queue, &ev); | 66 | queue_wait_w_tmo(&sim_queue, &ev, 5*HZ); |
58 | switch(ev.id) | 67 | switch(ev.id) |
59 | { | 68 | { |
69 | case SYS_TIMEOUT: | ||
70 | call_storage_idle_notifys(false); | ||
71 | break; | ||
72 | |||
60 | case SIM_SCREENDUMP: | 73 | case SIM_SCREENDUMP: |
61 | screen_dump(); | 74 | screen_dump(); |
62 | #ifdef HAVE_REMOTE_LCD | 75 | #ifdef HAVE_REMOTE_LCD |
@@ -102,6 +115,7 @@ void sim_thread(void) | |||
102 | #ifdef HAVE_MULTIDRIVE | 115 | #ifdef HAVE_MULTIDRIVE |
103 | case SIM_EXT_INSERTED: | 116 | case SIM_EXT_INSERTED: |
104 | case SIM_EXT_EXTRACTED: | 117 | case SIM_EXT_EXTRACTED: |
118 | sim_ext_extracted(ev.data); | ||
105 | queue_broadcast(ev.id == SIM_EXT_INSERTED ? | 119 | queue_broadcast(ev.id == SIM_EXT_INSERTED ? |
106 | SYS_HOTSWAP_INSERTED : SYS_HOTSWAP_EXTRACTED, 0); | 120 | SYS_HOTSWAP_INSERTED : SYS_HOTSWAP_EXTRACTED, 0); |
107 | sleep(HZ/20); | 121 | sleep(HZ/20); |
@@ -174,11 +188,13 @@ static bool is_ext_inserted; | |||
174 | 188 | ||
175 | void sim_trigger_external(bool inserted) | 189 | void sim_trigger_external(bool inserted) |
176 | { | 190 | { |
191 | is_ext_inserted = inserted; | ||
192 | |||
193 | int drive = 1; /* Can do others! */ | ||
177 | if (inserted) | 194 | if (inserted) |
178 | queue_post(&sim_queue, SIM_EXT_INSERTED, 0); | 195 | queue_post(&sim_queue, SIM_EXT_INSERTED, drive); |
179 | else | 196 | else |
180 | queue_post(&sim_queue, SIM_EXT_EXTRACTED, 0); | 197 | queue_post(&sim_queue, SIM_EXT_EXTRACTED, drive); |
181 | is_ext_inserted = inserted; | ||
182 | } | 198 | } |
183 | 199 | ||
184 | bool hostfs_present(int drive) | 200 | bool hostfs_present(int drive) |
@@ -203,7 +219,13 @@ bool volume_present(int volume) | |||
203 | /* volume == drive for now */ | 219 | /* volume == drive for now */ |
204 | return hostfs_present(volume); | 220 | return hostfs_present(volume); |
205 | } | 221 | } |
206 | #endif | 222 | |
223 | int volume_drive(int volume) | ||
224 | { | ||
225 | /* volume == drive for now */ | ||
226 | return volume; | ||
227 | } | ||
228 | #endif /* HAVE_MULTIVOLUME */ | ||
207 | 229 | ||
208 | #if (CONFIG_STORAGE & STORAGE_MMC) | 230 | #if (CONFIG_STORAGE & STORAGE_MMC) |
209 | bool mmc_touched(void) | 231 | bool mmc_touched(void) |
@@ -212,4 +234,4 @@ bool mmc_touched(void) | |||
212 | } | 234 | } |
213 | #endif | 235 | #endif |
214 | 236 | ||
215 | #endif | 237 | #endif /* CONFIG_STORAGE & STORAGE_MMC */ |
diff --git a/uisimulator/common/stubs.c b/uisimulator/common/stubs.c index 18f60ce6b3..922b9e8da0 100644 --- a/uisimulator/common/stubs.c +++ b/uisimulator/common/stubs.c | |||
@@ -153,10 +153,9 @@ int fat_startsector(void) | |||
153 | return 63; | 153 | return 63; |
154 | } | 154 | } |
155 | 155 | ||
156 | bool fat_ismounted(int volume) | 156 | int ata_spinup_time(void) |
157 | { | 157 | { |
158 | (void)volume; | 158 | return 100; |
159 | return true; | ||
160 | } | 159 | } |
161 | 160 | ||
162 | int storage_spinup_time(void) | 161 | int storage_spinup_time(void) |
diff --git a/uisimulator/common/time-win32.c b/uisimulator/common/time-win32.c new file mode 100644 index 0000000000..1de69c35e6 --- /dev/null +++ b/uisimulator/common/time-win32.c | |||
@@ -0,0 +1,61 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2014 by Michael Sevakis | ||
11 | * | ||
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. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include <time.h> | ||
22 | #include <errno.h> | ||
23 | #include "system.h" | ||
24 | #include "debug.h" | ||
25 | |||
26 | /* These functions we like but Windows doesn't because it implements the | ||
27 | non-"_r" versions with thread-local storage in its multithreaded libs */ | ||
28 | |||
29 | struct tm * localtime_r(const time_t *restrict timer, | ||
30 | struct tm *restrict result) | ||
31 | { | ||
32 | if (!timer || !result) | ||
33 | { | ||
34 | errno = EINVAL; | ||
35 | return NULL; | ||
36 | } | ||
37 | |||
38 | struct tm *tm = localtime(timer); | ||
39 | if (!tm) | ||
40 | return NULL; | ||
41 | |||
42 | *result = *tm; | ||
43 | return result; | ||
44 | } | ||
45 | |||
46 | struct tm * gmtime_r(const time_t *restrict timer, | ||
47 | struct tm *restrict result) | ||
48 | { | ||
49 | if (!timer || !result) | ||
50 | { | ||
51 | errno = EINVAL; | ||
52 | return NULL; | ||
53 | } | ||
54 | |||
55 | struct tm *tm = gmtime(timer); | ||
56 | if (!tm) | ||
57 | return NULL; | ||
58 | |||
59 | *result = *tm; | ||
60 | return result; | ||
61 | } | ||