summaryrefslogtreecommitdiff
path: root/firmware/target
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target')
-rw-r--r--firmware/target/arm/as3525/sd-as3525.c44
-rw-r--r--firmware/target/arm/as3525/sd-as3525v2.c41
-rw-r--r--firmware/target/arm/imx233/sdmmc-imx233.c45
-rw-r--r--firmware/target/arm/pp/ata-sd-pp.c30
-rw-r--r--firmware/target/arm/rk27xx/sd-rk27xx.c52
-rw-r--r--firmware/target/arm/s3c2440/sd-s3c2440.c34
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c27
-rw-r--r--firmware/target/arm/tcc780x/sd-tcc780x.c32
-rw-r--r--firmware/target/arm/tms320dm320/sdmmc-dm320.c35
-rw-r--r--firmware/target/hosted/filesystem-app.c562
-rw-r--r--firmware/target/hosted/filesystem-app.h117
-rw-r--r--firmware/target/hosted/filesystem-hosted.h74
-rw-r--r--firmware/target/hosted/filesystem-unix.c202
-rw-r--r--firmware/target/hosted/filesystem-unix.h82
-rw-r--r--firmware/target/hosted/filesystem-win32.c479
-rw-r--r--firmware/target/hosted/filesystem-win32.h111
-rw-r--r--firmware/target/hosted/lc-unix.c11
-rw-r--r--firmware/target/hosted/sdl/app/load_code-sdl-app.c36
-rw-r--r--firmware/target/hosted/sdl/filesystem-sdl.c55
-rw-r--r--firmware/target/hosted/sdl/filesystem-sdl.h37
-rw-r--r--firmware/target/hosted/sdl/load_code-sdl.c52
-rw-r--r--firmware/target/hosted/sdl/system-sdl.c4
-rw-r--r--firmware/target/hosted/sdl/system-sim.h32
-rw-r--r--firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c29
24 files changed, 1982 insertions, 241 deletions
diff --git a/firmware/target/arm/as3525/sd-as3525.c b/firmware/target/arm/as3525/sd-as3525.c
index c80c7f7491..ead40eac3c 100644
--- a/firmware/target/arm/as3525/sd-as3525.c
+++ b/firmware/target/arm/as3525/sd-as3525.c
@@ -449,21 +449,12 @@ static void sd_thread(void)
449 { 449 {
450#ifdef HAVE_HOTSWAP 450#ifdef HAVE_HOTSWAP
451 case SYS_HOTSWAP_INSERTED: 451 case SYS_HOTSWAP_INSERTED:
452 case SYS_HOTSWAP_EXTRACTED: 452 case SYS_HOTSWAP_EXTRACTED:;
453 { 453 int success = 1;
454 int microsd_init = 1;
455 fat_lock(); /* lock-out FAT activity first -
456 prevent deadlocking via disk_mount that
457 would cause a reverse-order attempt with
458 another thread */
459 mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
460 into driver that bypass the fat cache */
461 454
462 /* We now have exclusive control of fat cache and ata */ 455 disk_unmount(SD_SLOT_AS3525); /* release "by force" */
463 456
464 disk_unmount(SD_SLOT_AS3525); /* release "by force", ensure file 457 mutex_lock(&sd_mtx); /* lock-out card activity */
465 descriptors aren't leaked and any busy
466 ones are invalid if mounting */
467 458
468 /* Force card init for new card, re-init for re-inserted one or 459 /* Force card init for new card, re-init for re-inserted one or
469 * clear if the last attempt to init failed with an error. */ 460 * clear if the last attempt to init failed with an error. */
@@ -471,29 +462,32 @@ static void sd_thread(void)
471 462
472 if (ev.id == SYS_HOTSWAP_INSERTED) 463 if (ev.id == SYS_HOTSWAP_INSERTED)
473 { 464 {
465 success = 0;
474 sd_enable(true); 466 sd_enable(true);
475 init_pl180_controller(SD_SLOT_AS3525); 467 init_pl180_controller(SD_SLOT_AS3525);
476 microsd_init = sd_init_card(SD_SLOT_AS3525); 468 int rc = sd_init_card(SD_SLOT_AS3525);
477 if (microsd_init < 0) /* initialisation failed */ 469 sd_enable(false);
478 panicf("microSD init failed : %d", microsd_init); 470 if (rc >= 0)
479 471 success = 2;
480 microsd_init = disk_mount(SD_SLOT_AS3525); /* 0 if fail */ 472 else /* initialisation failed */
473 panicf("microSD init failed : %d", rc);
481 } 474 }
482 475
476 mutex_unlock(&sd_mtx);
477
478 if (success > 1)
479 success = disk_mount(SD_SLOT_AS3525); /* 0 if fail */
480
483 /* 481 /*
484 * Mount succeeded, or this was an EXTRACTED event, 482 * Mount succeeded, or this was an EXTRACTED event,
485 * in both cases notify the system about the changed filesystems 483 * in both cases notify the system about the changed filesystems
486 */ 484 */
487 if (microsd_init) 485 if (success)
488 queue_broadcast(SYS_FS_CHANGED, 0); 486 queue_broadcast(SYS_FS_CHANGED, 0);
489 487
490 /* Access is now safe */
491 mutex_unlock(&sd_mtx);
492 fat_unlock();
493 sd_enable(false);
494 }
495 break; 488 break;
496#endif 489#endif /* HAVE_HOTSWAP */
490
497 case SYS_TIMEOUT: 491 case SYS_TIMEOUT:
498 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) 492 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
499 { 493 {
diff --git a/firmware/target/arm/as3525/sd-as3525v2.c b/firmware/target/arm/as3525/sd-as3525v2.c
index ae3dde4495..b4ac40152b 100644
--- a/firmware/target/arm/as3525/sd-as3525v2.c
+++ b/firmware/target/arm/as3525/sd-as3525v2.c
@@ -598,21 +598,13 @@ static void sd_thread(void)
598 { 598 {
599#ifdef HAVE_HOTSWAP 599#ifdef HAVE_HOTSWAP
600 case SYS_HOTSWAP_INSERTED: 600 case SYS_HOTSWAP_INSERTED:
601 case SYS_HOTSWAP_EXTRACTED: 601 case SYS_HOTSWAP_EXTRACTED:;
602 { 602 int success = 1;
603 int changed = 1; 603
604 fat_lock(); /* lock-out FAT activity first - 604 disk_unmount(SD_SLOT_AS3525); /* release "by force" */
605 prevent deadlocking via disk_mount that 605
606 would cause a reverse-order attempt with 606 mutex_lock(&sd_mtx); /* lock-out card activity */
607 another thread */ 607
608 mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
609 into driver that bypass the fat cache */
610
611 /* We now have exclusive control of fat cache and ata */
612
613 disk_unmount(SD_SLOT_AS3525); /* release "by force", ensure file
614 descriptors aren't leaked and any busy
615 ones are invalid if mounting */
616 /* Force card init for new card, re-init for re-inserted one or 608 /* Force card init for new card, re-init for re-inserted one or
617 * clear if the last attempt to init failed with an error. */ 609 * clear if the last attempt to init failed with an error. */
618 card_info[SD_SLOT_AS3525].initialized = 0; 610 card_info[SD_SLOT_AS3525].initialized = 0;
@@ -620,24 +612,25 @@ static void sd_thread(void)
620 if (ev.id == SYS_HOTSWAP_INSERTED) 612 if (ev.id == SYS_HOTSWAP_INSERTED)
621 { 613 {
622 sd_enable(true); 614 sd_enable(true);
623 changed = (sd_init_card(SD_SLOT_AS3525) == 0) && disk_mount(SD_SLOT_AS3525); /* 0 if fail */ 615 success = sd_init_card(SD_SLOT_AS3525) == 0 ? 2 : 0;
616 sd_enable(false);
624 } 617 }
625 618
619 mutex_unlock(&sd_mtx);
620
621 if (success > 1)
622 success = disk_mount(SD_SLOT_AS3525); /* 0 if fail */
623
626 /* 624 /*
627 * Mount succeeded, or this was an EXTRACTED event, 625 * Mount succeeded, or this was an EXTRACTED event,
628 * in both cases notify the system about the changed filesystems 626 * in both cases notify the system about the changed filesystems
629 */ 627 */
630 if (changed) 628 if (success)
631 queue_broadcast(SYS_FS_CHANGED, 0); 629 queue_broadcast(SYS_FS_CHANGED, 0);
632 630
633 sd_enable(false);
634
635 /* Access is now safe */
636 mutex_unlock(&sd_mtx);
637 fat_unlock();
638 }
639 break; 631 break;
640#endif 632#endif /* HAVE_HOTSWAP */
633
641 case SYS_TIMEOUT: 634 case SYS_TIMEOUT:
642 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) 635 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
643 { 636 {
diff --git a/firmware/target/arm/imx233/sdmmc-imx233.c b/firmware/target/arm/imx233/sdmmc-imx233.c
index 8f293543ab..87548aef53 100644
--- a/firmware/target/arm/imx233/sdmmc-imx233.c
+++ b/firmware/target/arm/imx233/sdmmc-imx233.c
@@ -766,14 +766,7 @@ static void sdmmc_thread(void)
766 case SYS_HOTSWAP_INSERTED: 766 case SYS_HOTSWAP_INSERTED:
767 case SYS_HOTSWAP_EXTRACTED: 767 case SYS_HOTSWAP_EXTRACTED:
768 { 768 {
769 int microsd_init = 1; 769 int microsd_init = ev.id == SYS_HOTSWAP_INSERTED ? 0 : 1;
770 /* lock-out FAT activity first -
771 * prevent deadlocking via disk_mount that
772 * would cause a reverse-order attempt with
773 * another thread */
774#ifdef HAVE_HOTSWAP
775 fat_lock();
776#endif
777 770
778 /* We now have exclusive control of fat cache and sd. 771 /* We now have exclusive control of fat cache and sd.
779 * Release "by force", ensure file 772 * Release "by force", ensure file
@@ -785,35 +778,37 @@ static void sdmmc_thread(void)
785 /* Skip non-removable drivers */ 778 /* Skip non-removable drivers */
786 if(!sdmmc_removable(drive)) 779 if(!sdmmc_removable(drive))
787 continue; 780 continue;
788 /* lock-out card activity - direct calls 781
789 * into driver that bypass the fat cache */
790 mutex_lock(&mutex[drive]);
791 disk_unmount(sd_first_drive + sd_drive); 782 disk_unmount(sd_first_drive + sd_drive);
783
784 mutex_lock(&mutex[drive]); /* lock-out card activity */
785
792 /* Force card init for new card, re-init for re-inserted one or 786 /* Force card init for new card, re-init for re-inserted one or
793 * clear if the last attempt to init failed with an error. */ 787 * clear if the last attempt to init failed with an error. */
794 SDMMC_INFO(sd_map[sd_drive]).initialized = 0; 788 SDMMC_INFO(sd_map[sd_drive]).initialized = 0;
795 789
790 int rc = -1;
796 if(ev.id == SYS_HOTSWAP_INSERTED) 791 if(ev.id == SYS_HOTSWAP_INSERTED)
797 { 792 {
798 microsd_init = init_drive(drive); 793 rc = init_drive(drive);
799 if(microsd_init < 0) /* initialisation failed */ 794 if(rc < 0) /* initialisation failed */
800 panicf("%s init failed : %d", SDMMC_CONF(sd_map[sd_drive]).name, microsd_init); 795 panicf("%s init failed : %d", SDMMC_CONF(sd_map[sd_drive]).name, rc);
801
802 microsd_init = disk_mount(sd_first_drive + sd_drive); /* 0 if fail */
803 } 796 }
804 /* 797
805 * Mount succeeded, or this was an EXTRACTED event,
806 * in both cases notify the system about the changed filesystems
807 */
808 if(microsd_init)
809 queue_broadcast(SYS_FS_CHANGED, 0);
810 /* unlock card */ 798 /* unlock card */
811 mutex_unlock(&mutex[drive]); 799 mutex_unlock(&mutex[drive]);
800
801 if (rc >= 0)
802 microsd_init += disk_mount(sd_first_drive + sd_drive); /* 0 if fail */
812 } 803 }
813 /* Access is now safe */ 804 /* Access is now safe */
814#ifdef HAVE_HOTSWAP 805 /*
815 fat_unlock(); 806 * One or more mounts succeeded, or this was an EXTRACTED event,
816#endif 807 * in both cases notify the system about the changed filesystems
808 */
809 if(microsd_init)
810 queue_broadcast(SYS_FS_CHANGED, 0);
811
817 break; 812 break;
818 } 813 }
819#endif 814#endif
diff --git a/firmware/target/arm/pp/ata-sd-pp.c b/firmware/target/arm/pp/ata-sd-pp.c
index bcf8a660c2..2a11b40fee 100644
--- a/firmware/target/arm/pp/ata-sd-pp.c
+++ b/firmware/target/arm/pp/ata-sd-pp.c
@@ -19,7 +19,6 @@
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#include "config.h" /* for HAVE_MULTIDRIVE */ 21#include "config.h" /* for HAVE_MULTIDRIVE */
22#include "fat.h"
23#include "sdmmc.h" 22#include "sdmmc.h"
24#include "gcc_extensions.h" 23#include "gcc_extensions.h"
25#ifdef HAVE_HOTSWAP 24#ifdef HAVE_HOTSWAP
@@ -1125,35 +1124,28 @@ static void sd_thread(void)
1125 { 1124 {
1126#ifdef HAVE_HOTSWAP 1125#ifdef HAVE_HOTSWAP
1127 case SYS_HOTSWAP_INSERTED: 1126 case SYS_HOTSWAP_INSERTED:
1128 case SYS_HOTSWAP_EXTRACTED: 1127 case SYS_HOTSWAP_EXTRACTED:;
1129 fat_lock(); /* lock-out FAT activity first - 1128 int success = 1;
1130 prevent deadlocking via disk_mount that
1131 would cause a reverse-order attempt with
1132 another thread */
1133 mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
1134 into driver that bypass the fat cache */
1135 1129
1136 /* We now have exclusive control of fat cache and ata */ 1130 disk_unmount(sd_first_drive+1); /* release "by force" */
1137 1131
1138 disk_unmount(sd_first_drive+1); /* release "by force", ensure file 1132 mutex_lock(&sd_mtx); /* lock-out card activity */
1139 descriptors aren't leaked and any busy
1140 ones are invalid if mounting */
1141 1133
1142 /* Force card init for new card, re-init for re-inserted one or 1134 /* Force card init for new card, re-init for re-inserted one or
1143 * clear if the last attempt to init failed with an error. */ 1135 * clear if the last attempt to init failed with an error. */
1144 card_info[1].initialized = 0; 1136 card_info[1].initialized = 0;
1145 sd_status[1].retry = 0; 1137 sd_status[1].retry = 0;
1146 1138
1147 if (ev.id == SYS_HOTSWAP_INSERTED)
1148 disk_mount(sd_first_drive+1);
1149
1150 queue_broadcast(SYS_FS_CHANGED, 0);
1151
1152 /* Access is now safe */ 1139 /* Access is now safe */
1153 mutex_unlock(&sd_mtx); 1140 mutex_unlock(&sd_mtx);
1154 fat_unlock(); 1141
1142 if (ev.id == SYS_HOTSWAP_INSERTED)
1143 success = disk_mount(sd_first_drive+1); /* 0 if fail */
1144
1145 if (success)
1146 queue_broadcast(SYS_FS_CHANGED, 0);
1155 break; 1147 break;
1156#endif 1148#endif /* HAVE_HOTSWAP */
1157 case SYS_TIMEOUT: 1149 case SYS_TIMEOUT:
1158 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) 1150 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
1159 { 1151 {
diff --git a/firmware/target/arm/rk27xx/sd-rk27xx.c b/firmware/target/arm/rk27xx/sd-rk27xx.c
index deca8a1fa7..9d6821ee38 100644
--- a/firmware/target/arm/rk27xx/sd-rk27xx.c
+++ b/firmware/target/arm/rk27xx/sd-rk27xx.c
@@ -22,7 +22,6 @@
22 ****************************************************************************/ 22 ****************************************************************************/
23 23
24#include "config.h" /* for HAVE_MULTIVOLUME */ 24#include "config.h" /* for HAVE_MULTIVOLUME */
25#include "fat.h"
26#include "thread.h" 25#include "thread.h"
27#include "gcc_extensions.h" 26#include "gcc_extensions.h"
28#include "led.h" 27#include "led.h"
@@ -331,50 +330,45 @@ static void sd_thread(void)
331 { 330 {
332#ifdef HAVE_HOTSWAP 331#ifdef HAVE_HOTSWAP
333 case SYS_HOTSWAP_INSERTED: 332 case SYS_HOTSWAP_INSERTED:
334 case SYS_HOTSWAP_EXTRACTED: 333 case SYS_HOTSWAP_EXTRACTED:;
335 { 334 int success = 1;
336 int microsd_init = 1; 335
337 fat_lock(); /* lock-out FAT activity first - 336 disk_unmount(sd_first_drive); /* release "by force" */
338 prevent deadlocking via disk_mount that 337
339 would cause a reverse-order attempt with 338 mutex_lock(&sd_mtx); /* lock-out card activity */
340 another thread */ 339
341 mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
342 into driver that bypass the fat cache */
343
344 /* We now have exclusive control of fat cache and ata */
345
346 disk_unmount(sd_first_drive); /* release "by force", ensure file
347 descriptors aren't leaked and any busy
348 ones are invalid if mounting */
349 /* Force card init for new card, re-init for re-inserted one or 340 /* Force card init for new card, re-init for re-inserted one or
350 * clear if the last attempt to init failed with an error. */ 341 * clear if the last attempt to init failed with an error. */
351 card_info.initialized = 0; 342 card_info.initialized = 0;
352 343
353 if (ev.id == SYS_HOTSWAP_INSERTED) 344 if (ev.id == SYS_HOTSWAP_INSERTED)
354 { 345 {
346 success = 0;
355 sd_enable(true); 347 sd_enable(true);
356 microsd_init = sd_init_card(sd_first_drive); 348 int rc = sd_init_card(sd_first_drive);
357 if (microsd_init < 0) /* initialisation failed */ 349 sd_enable(false);
358 panicf("microSD init failed : %d", microsd_init); 350 if (rc >= 0)
359 351 success = 2;
360 microsd_init = disk_mount(sd_first_drive); /* 0 if fail */ 352 else /* initialisation failed */
353 panicf("microSD init failed : %d", rc);
361 } 354 }
362 355
356 /* Access is now safe */
357 mutex_unlock(&sd_mtx);
358
359 if (success > 1)
360 success = disk_mount(sd_first_drive); /* 0 if fail */
361
363 /* 362 /*
364 * Mount succeeded, or this was an EXTRACTED event, 363 * Mount succeeded, or this was an EXTRACTED event,
365 * in both cases notify the system about the changed filesystems 364 * in both cases notify the system about the changed filesystems
366 */ 365 */
367 if (microsd_init) 366 if (success)
368 queue_broadcast(SYS_FS_CHANGED, 0); 367 queue_broadcast(SYS_FS_CHANGED, 0);
369 368
370 sd_enable(false);
371
372 /* Access is now safe */
373 mutex_unlock(&sd_mtx);
374 fat_unlock();
375 }
376 break; 369 break;
377#endif 370#endif /* HAVE_HOTSWAP */
371
378 case SYS_TIMEOUT: 372 case SYS_TIMEOUT:
379 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) 373 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
380 { 374 {
diff --git a/firmware/target/arm/s3c2440/sd-s3c2440.c b/firmware/target/arm/s3c2440/sd-s3c2440.c
index 6658fa1515..e8de3ac78d 100644
--- a/firmware/target/arm/s3c2440/sd-s3c2440.c
+++ b/firmware/target/arm/s3c2440/sd-s3c2440.c
@@ -34,7 +34,6 @@
34#ifdef HAVE_HOTSWAP 34#ifdef HAVE_HOTSWAP
35#include "sdmmc.h" 35#include "sdmmc.h"
36#include "disk.h" 36#include "disk.h"
37#include "fat.h"
38#endif 37#endif
39#include "dma-target.h" 38#include "dma-target.h"
40#include "system-target.h" 39#include "system-target.h"
@@ -585,48 +584,29 @@ static void sd_thread(void)
585 { 584 {
586#ifdef HAVE_HOTSWAP 585#ifdef HAVE_HOTSWAP
587 case SYS_HOTSWAP_INSERTED: 586 case SYS_HOTSWAP_INSERTED:
588 case SYS_HOTSWAP_EXTRACTED: 587 case SYS_HOTSWAP_EXTRACTED:;
589 {
590 int success = 1; 588 int success = 1;
591 fat_lock(); /* lock-out FAT activity first -
592 prevent deadlocking via disk_mount that
593 would cause a reverse-order attempt with
594 another thread */
595 mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
596 into driver that bypass the fat cache */
597 589
598 /* We now have exclusive control of fat cache and ata */ 590 disk_unmount(0); /* release "by force" */
599 591
600 disk_unmount(0); /* release "by force", ensure file 592 mutex_lock(&sd_mtx); /* lock-out card activity */
601 descriptors aren't leaked and any busy
602 ones are invalid if mounting */
603 593
604 /* Force card init for new card, re-init for re-inserted one or 594 /* Force card init for new card, re-init for re-inserted one or
605 * clear if the last attempt to init failed with an error. */ 595 * clear if the last attempt to init failed with an error. */
606 card_info[0].initialized = 0; 596 card_info[0].initialized = 0;
607 597
598 /* Access is now safe */
599 mutex_unlock(&sd_mtx);
600
608 if (ev.id == SYS_HOTSWAP_INSERTED) 601 if (ev.id == SYS_HOTSWAP_INSERTED)
609 {
610 /* FIXME: once sd_enabled is implement properly,
611 * reinitializing the controllers might be needed */
612 sd_enable(true);
613 if (success < 0) /* initialisation failed */
614 panicf("SD init failed : %d", success);
615 success = disk_mount(0); /* 0 if fail */ 602 success = disk_mount(0); /* 0 if fail */
616 }
617 603
618 /* notify the system about the changed filesystems 604 /* notify the system about the changed filesystems
619 */ 605 */
620 if (success) 606 if (success)
621 queue_broadcast(SYS_FS_CHANGED, 0); 607 queue_broadcast(SYS_FS_CHANGED, 0);
622
623 /* Access is now safe */
624 mutex_unlock(&sd_mtx);
625 fat_unlock();
626 sd_enable(false);
627 }
628 break; 608 break;
629#endif 609#endif /* HAVE_HOTSWAP */
630 } 610 }
631 } 611 }
632} 612}
diff --git a/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c
index 395c0f49e6..0fd74787d1 100644
--- a/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c
+++ b/firmware/target/arm/s5l8702/ipod6g/storage_ata-ipod6g.c
@@ -32,7 +32,7 @@
32#include "s5l8702.h" 32#include "s5l8702.h"
33#include "led.h" 33#include "led.h"
34#include "ata_idle_notify.h" 34#include "ata_idle_notify.h"
35#include "fat.h" 35#include "disk_cache.h"
36#include "splash.h" 36#include "splash.h"
37 37
38 38
@@ -68,6 +68,7 @@ static struct semaphore mmc_wakeup;
68static struct semaphore mmc_comp_wakeup; 68static struct semaphore mmc_comp_wakeup;
69static int spinup_time = 0; 69static int spinup_time = 0;
70static int dma_mode = 0; 70static int dma_mode = 0;
71static char aligned_buffer[SECTOR_SIZE] __attribute__((aligned(0x10)));
71 72
72 73
73#ifdef ATA_HAVE_BBT 74#ifdef ATA_HAVE_BBT
@@ -857,8 +858,25 @@ int ata_bbt_translate(uint64_t sector, uint32_t count, uint64_t* phys, uint32_t*
857static int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool write) 858static int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool write)
858{ 859{
859 if (((uint32_t)buffer) & 0xf) 860 if (((uint32_t)buffer) & 0xf)
860 panicf("ATA: Misaligned data buffer at %08X (sector %lu, count %lu)", 861 {
861 (unsigned int)buffer, (long unsigned int)sector, (long unsigned int)count); 862 while (count)
863 {
864 if (write)
865 memcpy(aligned_buffer, buffer, SECTOR_SIZE);
866
867 PASS_RC(ata_rw_sectors(sector, 1, aligned_buffer, write), 0, 0);
868
869 if (!write)
870 memcpy(buffer, aligned_buffer, SECTOR_SIZE);
871
872 buffer += SECTOR_SIZE;
873 sector++;
874 count--;
875 }
876
877 return 0;
878 }
879
862#ifdef ATA_HAVE_BBT 880#ifdef ATA_HAVE_BBT
863 if (sector + count > ata_virtual_sectors) RET_ERR(0); 881 if (sector + count > ata_virtual_sectors) RET_ERR(0);
864 if (ata_bbt) 882 if (ata_bbt)
@@ -1117,14 +1135,13 @@ int ata_init(void)
1117 -- Michael Sparmann (theseven), 2011-10-22 */ 1135 -- Michael Sparmann (theseven), 2011-10-22 */
1118 if (!ceata) 1136 if (!ceata)
1119 { 1137 {
1120 unsigned char* sector = fat_get_sector_buffer(); 1138 unsigned char* sector = aligned_buffer;
1121 ata_rw_sectors(0, 1, sector, false); 1139 ata_rw_sectors(0, 1, sector, false);
1122 if (sector[510] == 0xaa && sector[511] == 0x55) 1140 if (sector[510] == 0xaa && sector[511] == 0x55)
1123 { 1141 {
1124 ata_swap = true; 1142 ata_swap = true;
1125 splashf(5000, "Wrong HDD endianness, please update your emCORE version!"); 1143 splashf(5000, "Wrong HDD endianness, please update your emCORE version!");
1126 } 1144 }
1127 fat_release_sector_buffer();
1128 } 1145 }
1129 1146
1130 create_thread(ata_thread, ata_stack, 1147 create_thread(ata_thread, ata_stack,
diff --git a/firmware/target/arm/tcc780x/sd-tcc780x.c b/firmware/target/arm/tcc780x/sd-tcc780x.c
index 55ae4e7c70..b7abea8be4 100644
--- a/firmware/target/arm/tcc780x/sd-tcc780x.c
+++ b/firmware/target/arm/tcc780x/sd-tcc780x.c
@@ -28,7 +28,6 @@
28#include "led.h" 28#include "led.h"
29#include "thread.h" 29#include "thread.h"
30#include "disk.h" 30#include "disk.h"
31#include "fat.h"
32#include "ata_idle_notify.h" 31#include "ata_idle_notify.h"
33#include "usb.h" 32#include "usb.h"
34 33
@@ -657,35 +656,30 @@ static void sd_thread(void)
657 { 656 {
658#ifdef HAVE_HOTSWAP 657#ifdef HAVE_HOTSWAP
659 case SYS_HOTSWAP_INSERTED: 658 case SYS_HOTSWAP_INSERTED:
660 case SYS_HOTSWAP_EXTRACTED: 659 case SYS_HOTSWAP_EXTRACTED:;
661 fat_lock(); /* lock-out FAT activity first - 660 int success = 1;
662 prevent deadlocking via disk_mount that 661
663 would cause a reverse-order attempt with 662 /* Release "by force" */
664 another thread */
665 mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
666 into driver that bypass the fat cache */
667
668 /* We now have exclusive control of fat cache and ata */
669
670 /* Release "by force", ensure file descriptors aren't leaked and
671 any busy ones are invalid if mounting */
672 disk_unmount(sd_first_drive + CARD_NUM_SLOT); 663 disk_unmount(sd_first_drive + CARD_NUM_SLOT);
673 664
665 mutex_lock(&sd_mtx); /* lock-out card activity */
666
674 /* Force card init for new card, re-init for re-inserted one or 667 /* Force card init for new card, re-init for re-inserted one or
675 * clear if the last attempt to init failed with an error. */ 668 * clear if the last attempt to init failed with an error. */
676 card_info[CARD_NUM_SLOT].initialized = 0; 669 card_info[CARD_NUM_SLOT].initialized = 0;
677 sd_status[CARD_NUM_SLOT].retry = 0; 670 sd_status[CARD_NUM_SLOT].retry = 0;
678 671
672 mutex_unlock(&sd_mtx);
673
679 if (ev.id == SYS_HOTSWAP_INSERTED) 674 if (ev.id == SYS_HOTSWAP_INSERTED)
680 disk_mount(sd_first_drive + CARD_NUM_SLOT); 675 success = disk_mount(sd_first_drive + CARD_NUM_SLOT);
681 676
682 queue_broadcast(SYS_FS_CHANGED, 0); 677 if (success)
678 queue_broadcast(SYS_FS_CHANGED, 0);
683 679
684 /* Access is now safe */
685 mutex_unlock(&sd_mtx);
686 fat_unlock();
687 break; 680 break;
688#endif 681#endif /* HAVE_HOTSWAP */
682
689 case SYS_TIMEOUT: 683 case SYS_TIMEOUT:
690 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) 684 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
691 { 685 {
diff --git a/firmware/target/arm/tms320dm320/sdmmc-dm320.c b/firmware/target/arm/tms320dm320/sdmmc-dm320.c
index 284061e1ad..d46dbf5e40 100644
--- a/firmware/target/arm/tms320dm320/sdmmc-dm320.c
+++ b/firmware/target/arm/tms320dm320/sdmmc-dm320.c
@@ -592,48 +592,29 @@ static void sd_thread(void)
592 { 592 {
593#ifdef HAVE_HOTSWAP 593#ifdef HAVE_HOTSWAP
594 case SYS_HOTSWAP_INSERTED: 594 case SYS_HOTSWAP_INSERTED:
595 case SYS_HOTSWAP_EXTRACTED: 595 case SYS_HOTSWAP_EXTRACTED:;
596 {
597 int success = 1; 596 int success = 1;
598 fat_lock(); /* lock-out FAT activity first -
599 prevent deadlocking via disk_mount that
600 would cause a reverse-order attempt with
601 another thread */
602 mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
603 into driver that bypass the fat cache */
604 597
605 /* We now have exclusive control of fat cache and ata */ 598 disk_unmount(0); /* release "by force" */
606 599
607 disk_unmount(0); /* release "by force", ensure file 600 mutex_lock(&sd_mtx); /* lock-out card activity */
608 descriptors aren't leaked and any busy
609 ones are invalid if mounting */
610 601
611 /* Force card init for new card, re-init for re-inserted one or 602 /* Force card init for new card, re-init for re-inserted one or
612 * clear if the last attempt to init failed with an error. */ 603 * clear if the last attempt to init failed with an error. */
613 card_info[0].initialized = 0; 604 card_info[0].initialized = 0;
614 605
606 mutex_unlock(&sd_mtx);
607
615 if (ev.id == SYS_HOTSWAP_INSERTED) 608 if (ev.id == SYS_HOTSWAP_INSERTED)
616 {
617 /* FIXME: once sd_enabled is implement properly,
618 * reinitializing the controllers might be needed */
619 sd_enable(true);
620 if (success < 0) /* initialisation failed */
621 panicf("SD init failed : %d", success);
622 success = disk_mount(0); /* 0 if fail */ 609 success = disk_mount(0); /* 0 if fail */
623 }
624 610
625 /* notify the system about the changed filesystems 611 /* notify the system about the changed filesystems */
626 */
627 if (success) 612 if (success)
628 queue_broadcast(SYS_FS_CHANGED, 0); 613 queue_broadcast(SYS_FS_CHANGED, 0);
629 614
630 /* Access is now safe */
631 mutex_unlock(&sd_mtx);
632 fat_unlock();
633 sd_enable(false);
634 }
635 break; 615 break;
636#endif 616#endif /* HAVE_HOTSWAP */
617
637 case SYS_TIMEOUT: 618 case SYS_TIMEOUT:
638 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) 619 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
639 { 620 {
diff --git a/firmware/target/hosted/filesystem-app.c b/firmware/target/hosted/filesystem-app.c
new file mode 100644
index 0000000000..7ef8d3109b
--- /dev/null
+++ b/firmware/target/hosted/filesystem-app.c
@@ -0,0 +1,562 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Thomas Martitz
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> /* snprintf */
23#include <stdlib.h>
24#include <stdarg.h>
25#include <time.h>
26#include <errno.h>
27#include <string.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 "rbpaths.h"
37#include "logf.h"
38
39
40#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
41static const char rbhome[] = "/sdcard";
42#elif (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA)) \
43 && !defined(__PCTOOL__)
44const char *rbhome;
45#else
46/* YPR0, YPR1 */
47static const char rbhome[] = HOME_DIR;
48#endif
49
50#if !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1)) && !defined(__PCTOOL__)
51/* Special dirs are user-accessible (and user-writable) dirs which take priority
52 * over the ones where Rockbox is installed to. Classic example would be
53 * $HOME/.config/rockbox.org vs /usr/share/rockbox */
54#define HAVE_SPECIAL_DIRS
55#endif
56
57#ifdef HAVE_MULTIDRIVE
58/* This is to compare any opened directories with the home directory so that
59 the special drive links may be returned for it only */
60static int rbhome_fildes = -1;
61
62/* A special link is created under e.g. HOME_DIR/<microSD1>, e.g. to access
63 * external storage in a convenient location, much similar to the mount
64 * point on our native targets. Here they are treated as symlink (one which
65 * doesn't actually exist in the filesystem and therefore we have to override
66 * readlink() */
67static const char *handle_special_links(const char* link, unsigned flags,
68 char *buf, const size_t bufsize)
69{
70 (void) flags;
71 char vol_string[VOL_MAX_LEN + 1];
72 get_volume_name(-1, vol_string);
73
74 /* link might be passed with or without HOME_DIR expanded. To handle
75 * both perform substring matching (VOL_NAMES is unique enough) */
76 const char *begin = strstr(link, vol_string);
77 if (begin)
78 {
79 /* begin now points to the start of vol_string within link,
80 * we want to copy the remainder of the paths, prefixed by
81 * the actual mount point (the remainder might be "") */
82 snprintf(buf, bufsize, MULTIDRIVE_DIR"%s", begin + len);
83 return buf;
84 }
85
86 return link;
87}
88#endif
89
90#ifdef HAVE_MULTIDRIVE
91/* we keep an open descriptor of the home directory to detect when it has been
92 opened by opendir() so that its "symlinks" may be enumerated */
93static void cleanup_rbhome(void)
94{
95 os_close(rbhome_fildes);
96 rbhome_fildes = -1;
97}
98#endif /* HAVE_MULTIDRIVE */
99
100void paths_init(void)
101{
102#ifdef HAVE_SPECIAL_DIRS
103 /* make sure $HOME/.config/rockbox.org exists, it's needed for config.cfg */
104#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
105 os_mkdir("/sdcard/rockbox" __MKDIR_MODE_ARG);
106 os_mkdir("/sdcard/rockbox/rocks.data" __MKDIR_MODE_ARG);
107#else
108 char config_dir[MAX_PATH];
109
110 const char *home = getenv("RBROOT");
111 if (!home)
112 {
113 home = getenv("HOME");
114 }
115
116 if (!home)
117 {
118 logf("HOME environment var not set. Can't write config");
119 return;
120 }
121
122 rbhome = home;
123 snprintf(config_dir, sizeof(config_dir), "%s/.config", home);
124 os_mkdir(config_dir __MKDIR_MODE_ARG);
125 snprintf(config_dir, sizeof(config_dir), "%s/.config/rockbox.org", home);
126 os_mkdir(config_dir __MKDIR_MODE_ARG);
127 /* Plugin data directory */
128 snprintf(config_dir, sizeof(config_dir), "%s/.config/rockbox.org/rocks.data", home);
129 os_mkdir(config_dir __MKDIR_MODE_ARG);
130#endif
131#endif /* HAVE_SPECIAL_DIRS */
132
133#ifdef HAVE_MULTIDRIVE
134 /* if this fails then alternate volumes will not work, but this function
135 cannot return that fact */
136 rbhome_fildes = os_opendirfd(rbhome);
137 if (rbhome_fildes >= 0)
138 atexit(cleanup_rbhome);
139#endif /* HAVE_MULTIDRIVE */
140}
141
142#ifdef HAVE_SPECIAL_DIRS
143static const char* _get_user_file_path(const char *path,
144 unsigned flags,
145 char* buf,
146 const size_t bufsize)
147{
148 const char *ret = path;
149 const char *pos = path;
150 /* replace ROCKBOX_DIR in path with $HOME/.config/rockbox.org */
151 pos += ROCKBOX_DIR_LEN;
152 if (*pos == '/') pos += 1;
153
154#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
155 if (path_append(buf, "/sdcard/rockbox", pos, bufsize) >= bufsize)
156 return NULL;
157#else
158 if (path_append(buf, rbhome, ".config/rockbox.org", bufsize) >= bufsize ||
159 path_append(buf, PA_SEP_SOFT, pos, bufsize) >= bufsize)
160 return NULL;
161#endif
162
163 /* always return the replacement buffer (pointing to $HOME) if
164 * write access is needed */
165 if (flags & NEED_WRITE)
166 ret = buf;
167 else if (os_file_exists(buf))
168 ret = buf;
169
170 if (ret != buf) /* not found in $HOME, try ROCKBOX_BASE_DIR, !NEED_WRITE only */
171 {
172 if (path_append(buf, ROCKBOX_SHARE_PATH, pos, bufsize) >= bufsize)
173 return NULL;
174
175 if (os_file_exists(buf))
176 ret = buf;
177 }
178
179 return ret;
180}
181
182#endif
183
184const char * handle_special_dirs(const char *dir, unsigned flags,
185 char *buf, const size_t bufsize)
186{
187 (void) flags; (void) buf; (void) bufsize;
188#ifdef HAVE_SPECIAL_DIRS
189 if (!strncmp(HOME_DIR, dir, HOME_DIR_LEN))
190 {
191 const char *p = dir + HOME_DIR_LEN;
192 while (*p == '/') p++;
193 snprintf(buf, bufsize, "%s/%s", rbhome, p);
194 dir = buf;
195 }
196 else if (!strncmp(ROCKBOX_DIR, dir, ROCKBOX_DIR_LEN))
197 dir = _get_user_file_path(dir, flags, buf, bufsize);
198#endif
199#ifdef HAVE_MULTIDRIVE
200 dir = handle_special_links(dir, flags, buf, bufsize);
201#endif
202 return dir;
203}
204
205int app_open(const char *path, int oflag, ...)
206{
207 int flags = IS_FILE;
208 if (oflag & O_ACCMODE)
209 flags |= NEED_WRITE;
210
211 char realpath[MAX_PATH];
212 const char *fpath = handle_special_dirs(path, flags, realpath,
213 sizeof (realpath));
214 if (!fpath)
215 FILE_ERROR_RETURN(ENAMETOOLONG, -1);
216
217 return os_open(fpath, oflag __OPEN_MODE_ARG);
218}
219
220int app_creat(const char *path, mode_t mode)
221{
222 return app_open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
223}
224
225int app_remove(const char *path)
226{
227 char realpath[MAX_PATH];
228 const char *fpath = handle_special_dirs(path, NEED_WRITE, realpath,
229 sizeof (realpath));
230 if (!fpath)
231 FILE_ERROR_RETURN(ENAMETOOLONG, -1);
232
233 return os_remove(fpath);
234}
235
236int app_rename(const char *old, const char *new)
237{
238 char realpath_old[MAX_PATH], realpath_new[MAX_PATH];
239 const char *fold = handle_special_dirs(old, NEED_WRITE, realpath_old,
240 sizeof (realpath_old));
241 const char *fnew = handle_special_dirs(new, NEED_WRITE, realpath_new,
242 sizeof (realpath_new));
243 if (!fold || !fnew)
244 FILE_ERROR_RETURN(ENAMETOOLONG, -1);
245
246 return os_rename(fold, fnew);
247}
248
249#ifdef HAVE_SDL_THREADS
250ssize_t app_read(int fd, void *buf, size_t nbyte)
251{
252 return os_read(fd, buf, nbyte);
253}
254
255ssize_t app_write(int fd, const void *buf, size_t nbyte)
256{
257 return os_write(fd, buf, nbyte);
258}
259#endif /* HAVE_SDL_THREADS */
260
261int app_relate(const char *path1, const char *path2)
262{
263 char realpath_1[MAX_PATH], realpath_2[MAX_PATH];
264 const char *fpath1 = handle_special_dirs(path1, 0, realpath_1,
265 sizeof (realpath_1));
266 const char *fpath2 = handle_special_dirs(path2, 0, realpath_2,
267 sizeof (realpath_2));
268
269 if (!fpath1 || !fpath2)
270 FILE_ERROR_RETURN(ENAMETOOLONG, -1);
271
272 return os_relate(fpath1, fpath2);
273}
274
275bool app_file_exists(const char *path)
276{
277 char realpath[MAX_PATH];
278 const char *fpath = handle_special_dirs(path, NEED_WRITE, realpath,
279 sizeof (realpath));
280 if (!fpath)
281 FILE_ERROR_RETURN(ENAMETOOLONG, false);
282
283 return os_file_exists(fpath);
284}
285
286/* need to wrap around DIR* because we need to save the parent's directory
287 * path in order to determine dirinfo for volumes or convert the path to UTF-8;
288 * also is required to implement get_dir_info() */
289struct __dir
290{
291 OS_DIR_T *osdirp;
292#ifdef HAVE_MULTIDRIVE
293 int volumes_returned;
294#endif
295 int osfd;
296 bool osfd_is_opened;
297#if defined(OS_DIRENT_CONVERT) || defined (HAVE_MULTIDRIVE)
298 #define USE_DIRENTP
299 struct dirent *direntp;
300 size_t d_name_size;
301#endif
302 char path[];
303};
304
305static void __dir_free(struct __dir *this)
306{
307 if (!this)
308 return;
309
310#ifdef USE_DIRENTP
311 free(this->direntp);
312#endif
313
314 if (this->osfd_is_opened)
315 os_close(this->osfd);
316
317 free(this);
318}
319
320DIR * app_opendir(const char *dirname)
321{
322 int rc;
323 char realpath[MAX_PATH];
324 const char *fname = handle_special_dirs(dirname, 0, realpath,
325 sizeof (realpath));
326 if (!fname)
327 FILE_ERROR_RETURN(ENAMETOOLONG, NULL);
328
329 size_t name_len = path_strip_trailing_separators(fname, &fname);
330 struct __dir *this = calloc(1, sizeof (*this) + name_len + 1);
331 if (!this)
332 FILE_ERROR(ENOMEM, RC);
333
334#ifdef USE_DIRENTP
335 /* allocate what we're really going to return to callers, making certain
336 it has at least the d_name size we want */
337 this->d_name_size = MAX(MAX_PATH, sizeof (this->direntp->d_name));
338 this->direntp = calloc(1, offsetof(typeof (*this->direntp), d_name) +
339 this->d_name_size);
340 if (!this->direntp)
341 FILE_ERROR(ENOMEM, RC);
342
343 /* only the d_name field will be valid but that is all that anyone may
344 truely count on portably existing */
345#endif /* USE_DIRENTP */
346
347 strmemcpy(this->path, fname, name_len);
348
349 rc = os_opendir_and_fd(this->path, &this->osdirp, &this->osfd);
350 if (rc < 0)
351 FILE_ERROR(ERRNO, RC);
352
353 this->osfd_is_opened = rc > 0;
354
355#ifdef HAVE_MULTIDRIVE
356 this->volumes_returned = INT_MAX; /* assume NOT $HOME */
357 if (rbhome_fildes >= 0 && os_samefile(rbhome_fildes, fd) > 0)
358 this->volumes_returned = 0; /* there's no place like $HOME */
359#endif /* HAVE_MULTIDRIVE */
360
361 return (DIR *)this;
362file_error:
363 __dir_free(this);
364 return NULL;
365}
366
367int app_closedir(DIR *dirp)
368{
369 struct __dir *this = (struct __dir *)dirp;
370 if (!this)
371 FILE_ERROR_RETURN(EBADF, -1);
372
373 OS_DIR_T *osdirp = this->osdirp;
374 __dir_free(this);
375
376 return os_closedir(osdirp);
377}
378
379struct dirent * app_readdir(DIR *dirp)
380{
381 struct __dir *this = (struct __dir *)dirp;
382 if (!this)
383 FILE_ERROR_RETURN(EBADF, NULL);
384
385#ifdef HAVE_MULTIDRIVE
386 if (this->volumes_returned < NUM_VOLUMES)
387 {
388 while (++this->volumes_returned < NUM_VOLUMES)
389 {
390 if (!volume_present(this->volumes_returned))
391 continue;
392
393 get_volume_name(this->volumes_returned, this->direntp->d_name);
394 return this->direntp;
395 }
396 }
397 /* do normal directory reads */
398#endif /* HAVE_MULTIDRIVE */
399
400 OS_DIRENT_T *osdirent = os_readdir(this->osdirp);
401
402#ifdef OS_DIRENT_CONVERT
403 if (strlcpy_from_os(this->direntp->d_name, osdirent->d_name,
404 this->d_name_size) >= this->d_name_size)
405 {
406 this->direntp->d_name[0] = '\0';
407 errno = EOVERFLOW;
408 return NULL;
409 }
410
411 osdirent = (OS_DIRENT_T *)this->direntp;
412#endif /* OS_DIRENT_CONVERT */
413
414 return (struct dirent *)osdirent;
415}
416
417int app_mkdir(const char *path)
418{
419 char realpath[MAX_PATH];
420 const char *fname = handle_special_dirs(path, NEED_WRITE, realpath,
421 sizeof (realpath));
422 if (!fname)
423 FILE_ERROR_RETURN(ENAMETOOLONG, -1);
424
425 return os_mkdir(fname __MKDIR_MODE_ARG);
426}
427
428int app_rmdir(const char *path)
429{
430 char realpath[MAX_PATH];
431 const char *fname = handle_special_dirs(path, NEED_WRITE, realpath,
432 sizeof (realpath));
433 if (!fname)
434 FILE_ERROR_RETURN(ENAMETOOLONG, -1);
435
436 return os_rmdir(fname);
437}
438
439int app_samedir(DIR *dirp1, DIR *dirp2)
440{
441 struct __dir *this1 = (struct __dir *)dirp1;
442 struct __dir *this2 = (struct __dir *)dirp2;
443
444 if (!this1 || !this2)
445 {
446 errno = EBADF;
447 return -1;
448 }
449
450 return os_fsamefile(this1->osfd, this2->osfd);
451}
452
453bool app_dir_exists(const char *dirname)
454{
455 char realpath[MAX_PATH];
456 const char *fname = handle_special_dirs(dirname, 0, realpath,
457 sizeof (realpath));
458 if (!fname)
459 FILE_ERROR_RETURN(ENAMETOOLONG, false);
460
461 OS_DIR_T *osdirp = os_opendir(fname);
462 if (!osdirp)
463 return false;
464
465 os_closedir(osdirp);
466 return true;
467}
468
469struct dirinfo dir_get_info(DIR *dirp, struct dirent *entry)
470{
471 struct __dir *this = (struct __dir *)dirp;
472 struct dirinfo ret = { .mtime = 0 };
473
474 if (!this)
475 FILE_ERROR_RETURN(EBADF, ret);
476
477 if (!entry || entry->d_name[0] == '\0')
478 FILE_ERROR_RETURN(ENOENT, ret);
479
480 char path[MAX_PATH];
481
482#ifdef HAVE_MULTIDRIVE
483 if (this->volumes_returned < NUM_VOLUMES)
484 {
485 /* last thing read was a "symlink" */
486 ret.attribute = ATTR_LINK;
487 strcpy(path, MULTIDRIVE_DIR);
488 }
489 else
490#endif
491 if (path_append(path, this->path, entry->d_name, sizeof (path))
492 >= sizeof (path))
493 {
494 FILE_ERROR_RETURN(ENAMETOOLONG, ret);
495 }
496
497 struct stat s;
498 if (os_lstat(path, &s) < 0)
499 FILE_ERROR_RETURN(ERRNO, ret);
500
501 int err = 0;
502 if (S_ISLNK(s.st_mode))
503 {
504 ret.attribute |= ATTR_LINK;
505 err = os_stat(path, &s);
506 }
507
508 if (err < 0)
509 FILE_ERROR_RETURN(ERRNO, ret);
510
511 if (S_ISDIR(s.st_mode))
512 ret.attribute |= ATTR_DIRECTORY;
513
514 ret.size = s.st_size;
515
516 struct tm tm;
517 if (!localtime_r(&s.st_mtime, &tm))
518 FILE_ERROR_RETURN(ERRNO, ret);
519
520 ret.mtime = mktime(&tm);
521 return ret;
522}
523
524/* On MD we create a virtual symlink for the external drive,
525 * for this we need to override readlink(). */
526ssize_t app_readlink(const char *path, char *buf, size_t bufsiz)
527{
528 char _buf[MAX_PATH];
529 path = handle_special_dirs(path, 0, _buf, sizeof(_buf));
530#ifdef HAVE_MULTIDRIVE
531 /* if path == _buf then we can be sure handle_special_dir() did something
532 * and path is not an ordinary directory */
533 if (path == _buf && !strncmp(path, MULTIDRIVE_DIR, sizeof(MULTIDRIVE_DIR)-1))
534 {
535 /* copying NUL is not required as per readlink specification */
536 ssize_t len = strlen(path);
537 memcpy(buf, path, len);
538 return len;
539 }
540#endif
541 /* does not append NUL !! */
542 return os_readlink(path, buf, bufsiz);
543 (void) path; (void) buf; (void) bufsiz;
544}
545
546int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize)
547{
548#ifdef HAVE_MULTIVOLUME
549 char volname[VOL_MAX_LEN + 1];
550 get_volume_name(volume, volname);
551#else
552 const char *volname = "/";
553#endif
554
555 if (!handle_special_dirs(volname, NEED_WRITE, buffer, bufsize))
556 {
557 errno = ENAMETOOLONG;
558 return -1;
559 }
560
561 return 0;
562}
diff --git a/firmware/target/hosted/filesystem-app.h b/firmware/target/hosted/filesystem-app.h
new file mode 100644
index 0000000000..68b3f13b6e
--- /dev/null
+++ b/firmware/target/hosted/filesystem-app.h
@@ -0,0 +1,117 @@
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
22#ifndef _FILESYSTEM_APP_H_
23#define _FILESYSTEM_APP_H_
24
25#if defined(PLUGIN) || defined(CODEC)
26/* Prevent often-problematic plugin namespace pollution */
27#define FILEFUNCTIONS_DECLARED
28#define FILEFUNCTIONS_DEFINED
29#define DIRFUNCTIONS_DECLARED
30#define DIRFUNCTIONS_DEFINED
31#define OSFUNCTIONS_DECLARED
32#endif /* PLUGIN || CODEC */
33
34/* flags for get_user_file_path() */
35/* whether you need write access to that file/dir, especially true
36 * for runtime generated files (config.cfg) */
37#define NEED_WRITE (1<<0)
38/* file or directory? */
39#define IS_FILE (1<<1)
40
41#ifndef OSFUNCTIONS_DECLARED
42#define FS_PREFIX(_x_) app_ ## _x_
43
44void paths_init(void);
45const char * handle_special_dirs(const char *dir, unsigned flags,
46 char *buf, const size_t bufsize);
47
48#endif /* !OSFUNCTIONS_DECLARED */
49#endif /* _FILESYSTEM_APP_H_ */
50
51#ifdef HAVE_SDL
52#include "filesystem-sdl.h"
53#endif /* HAVE_SDL */
54#ifdef WIN32
55#include "filesystem-win32.h"
56#else /* !WIN32 */
57#include "filesystem-unix.h"
58#endif /* WIN32 */
59#include "filesystem-hosted.h"
60
61#ifdef _FILE_H_
62#ifndef _FILESYSTEM_APP__FILE_H_
63#define _FILESYSTEM_APP__FILE_H_
64
65#ifdef RB_FILESYSTEM_OS
66#define FILEFUNCTIONS_DEFINED
67#endif
68
69#ifndef FILEFUNCTIONS_DECLARED
70int app_open(const char *name, int oflag, ...);
71int app_creat(const char *name, mode_t mode);
72#define app_close os_close
73#define app_ftruncate os_ftruncate
74#define app_fsync os_fsync
75#define app_lseek os_lseek
76#ifdef HAVE_SDL_THREADS
77ssize_t app_read(int fildes, void *buf, size_t nbyte);
78ssize_t app_write(int fildes, const void *buf, size_t nbyte);
79#else
80#define app_read os_read
81#define app_write os_write
82#endif /* HAVE_SDL_THREADS */
83int app_remove(const char *path);
84int app_rename(const char *old, const char *new);
85#define app_filesize os_filesize
86#define app_fsamefile os_fsamefile
87int app_relate(const char *path1, const char *path2);
88bool app_file_exists(const char *path);
89ssize_t app_readlink(const char *path, char *buf, size_t bufsize);
90#endif /* !FILEFUNCTIONS_DECLARED */
91
92#endif /* _FILESYSTEM_APP__FILE_H_ */
93#endif /* _FILE_H_ */
94
95#ifdef _DIR_H_
96#ifndef _FILESYSTEM_APP__DIR_H_
97#define _FILESYSTEM_APP__DIR_H_
98
99#ifdef RB_FILESYSTEM_OS
100#define DIRFUNCTIONS_DEFINED
101#endif
102
103#define DIRENT dirent
104#define DIRENT_DEFINED
105
106#ifndef DIRFUNCTIONS_DECLARED
107DIR * app_opendir(const char *dirname);
108struct dirent * app_readdir(DIR *dirp);
109int app_closedir(DIR *dirp);
110int app_mkdir(const char *path);
111int app_rmdir(const char *path);
112int app_samedir(DIR *dirp1, DIR *dirp2);
113bool app_dir_exists(const char *dirname);
114#endif /* DIRFUNCTIONS_DECLARED */
115
116#endif /* _FILESYSTEM_APP__DIR_H_ */
117#endif /* _DIR_H_ */
diff --git a/firmware/target/hosted/filesystem-hosted.h b/firmware/target/hosted/filesystem-hosted.h
new file mode 100644
index 0000000000..3d979eb19d
--- /dev/null
+++ b/firmware/target/hosted/filesystem-hosted.h
@@ -0,0 +1,74 @@
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_HOSTED_H_
22#define _FILESYSTEM_HOSTED_H_
23
24#include "mv.h"
25
26int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize);
27void * os_lc_open(const char *ospath);
28
29#endif /* _FILESYSTEM_HOSTED_H_ */
30
31#ifdef _FILE_H_
32#ifndef _FILESYSTEM_HOSTED__FILE_H_
33#define _FILESYSTEM_HOSTED__FILE_H_
34
35#ifndef OSFUNCTIONS_DECLARED
36off_t os_filesize(int osfd);
37int os_fsamefile(int osfd1, int osfd2);
38int os_relate(const char *path1, const char *path2);
39bool os_file_exists(const char *ospath);
40
41#define __OPEN_MODE_ARG \
42 , ({ \
43 mode_t mode = 0; \
44 if (oflag & O_CREAT) \
45 { \
46 va_list ap; \
47 va_start(ap, oflag); \
48 mode = va_arg(ap, unsigned int); \
49 va_end(ap); \
50 } \
51 mode; })
52
53#define __CREAT_MODE_ARG \
54 , mode
55
56#endif /* OSFUNCTIONS_DECLARED */
57
58#endif /* _FILESYSTEM_HOSTED__FILE_H_ */
59#endif /* _FILE_H_ */
60
61#ifdef _DIR_H_
62#ifndef _FILESYSTEM_HOSTED__DIR_H_
63#define _FILESYSTEM_HOSTED__DIR_H_
64
65#ifndef OSFUNCTIONS_DECLARED
66int os_opendir_and_fd(const char *osdirname, OS_DIR_T **osdirpp,
67 int *osfdp);
68
69#define __MKDIR_MODE_ARG \
70 , 0777
71#endif /* OSFUNCTIONS_DECLARED */
72
73#endif /* _FILESYSTEM_HOSTED__DIR_H_ */
74#endif /* _DIR_H_ */
diff --git a/firmware/target/hosted/filesystem-unix.c b/firmware/target/hosted/filesystem-unix.c
index 8ac1d4ada9..907d6ab14e 100644
--- a/firmware/target/hosted/filesystem-unix.c
+++ b/firmware/target/hosted/filesystem-unix.c
@@ -18,24 +18,204 @@
18 * KIND, either express or implied. 18 * KIND, either express or implied.
19 * 19 *
20 ****************************************************************************/ 20 ****************************************************************************/
21#define RB_FILESYSTEM_OS
22#include <sys/statfs.h> /* lowest common denominator */
23#include <sys/stat.h>
24#include <string.h>
25#include <errno.h>
26#include "config.h"
27#include "system.h"
28#include "file.h"
29#include "dir.h"
30#include "mv.h"
31#include "debug.h"
32#include "pathfuncs.h"
33#include "string-extra.h"
21 34
22#include <sys/stat.h> /* stat() */ 35#define SAME_FILE_INFO(sb1p, sb2p) \
23#include "mv.h" /* stat() */ 36 ((sb1p)->st_dev == (sb2p)->st_dev && (sb1p)->st_ino == (sb2p)->st_ino)
24 37
25 38off_t os_filesize(int osfd)
26long filesize(int fd)
27{ 39{
28 struct stat buf; 40 struct stat sb;
29 41
30 if (!fstat(fd, &buf)) 42 if (!os_fstat(osfd, &sb))
31 return buf.st_size; 43 return sb.st_size;
32 else 44 else
33 return -1; 45 return -1;
34} 46}
35 47
36/* do we really need this in the app? */ 48int os_fsamefile(int osfd1, int osfd2)
37void fat_size(IF_MV(int volume,) unsigned long* size, unsigned long* free) 49{
50 struct stat sb1, sb2;
51
52 if (os_fstat(osfd1, &sb1))
53 return -1;
54
55 if (os_fstat(osfd2, &sb2))
56 return -1;
57
58 return SAME_FILE_INFO(&sb1, &sb2);
59}
60
61int os_relate(const char *ospath1, const char *ospath2)
62{
63 DEBUGF("\"%s\" : \"%s\"\n", ospath1, ospath2);
64
65 if (!ospath2 || !*ospath2)
66 {
67 errno = ospath2 ? ENOENT : EFAULT;
68 return -1;
69 }
70
71 /* First file must stay open for duration so that its stats don't change */
72 int fd1 = os_open(ospath1, O_RDONLY);
73 if (fd1 < 0)
74 return -2;
75
76 struct stat sb1;
77 if (os_fstat(fd1, &sb1))
78 {
79 os_close(fd1);
80 return -3;
81 }
82
83 char path2buf[strlen(ospath2) + 1];
84 *path2buf = 0;
85
86 ssize_t len = 0;
87 const char *p = ospath2;
88 const char *sepmo = path_is_absolute(ospath2) ? PA_SEP_HARD : PA_SEP_SOFT;
89
90 int rc = RELATE_DIFFERENT;
91
92 while (1)
93 {
94 if (sepmo != PA_SEP_HARD &&
95 !(len = parse_path_component(&ospath2, &p)))
96 {
97 break;
98 }
99
100 char compname[len + 1];
101 strmemcpy(compname, p, len);
102
103 path_append(path2buf, sepmo, compname, sizeof (path2buf));
104 sepmo = PA_SEP_SOFT;
105
106 int errnum = errno; /* save and restore if not actually failing */
107 struct stat sb2;
108
109 if (!os_stat(path2buf, &sb2))
110 {
111 if (SAME_FILE_INFO(&sb1, &sb2))
112 {
113 rc = RELATE_SAME;
114 }
115 else if (rc == RELATE_SAME)
116 {
117 if (name_is_dot_dot(compname))
118 rc = RELATE_DIFFERENT;
119 else if (!name_is_dot(compname))
120 rc = RELATE_PREFIX;
121 }
122 }
123 else if (errno == ENOENT && !*GOBBLE_PATH_SEPCH(ospath2) &&
124 !name_is_dot_dot(compname))
125 {
126 if (rc == RELATE_SAME)
127 rc = RELATE_PREFIX;
128
129 errno = errnum;
130 break;
131 }
132 else
133 {
134 rc = -4;
135 break;
136 }
137 }
138
139 if (os_close(fd1) && rc >= 0)
140 rc = -5;
141
142 return rc;
143}
144
145bool os_file_exists(const char *ospath)
146{
147 int sim_fd = os_open(ospath, O_RDONLY, 0);
148 if (sim_fd < 0)
149 return false;
150
151 int errnum = errno;
152 os_close(sim_fd);
153 errno = errnum;
154
155 return true;
156}
157
158int os_opendirfd(const char *osdirname)
159{
160 return os_open(osdirname, O_RDONLY);
161}
162
163int os_opendir_and_fd(const char *osdirname, DIR **osdirpp, int *osfdp)
164{
165 /* another possible way is to use open() then fdopendir() */
166 *osdirpp = NULL;
167 *osfdp = -1;
168
169 DIR *dirp = os_opendir(osdirname);
170 if (!dirp)
171 return -1;
172
173 int rc = 0;
174 int errnum = errno;
175
176 int fd = os_dirfd(dirp);
177 if (fd < 0)
178 {
179 fd = os_opendirfd(osdirname);
180 rc = 1;
181 }
182
183 if (fd < 0)
184 {
185 os_closedir(dirp);
186 return -2;
187 }
188
189 errno = errnum;
190
191 *osdirpp = dirp;
192 *osfdp = fd;
193
194 return rc;
195}
196
197/* do we really need this in the app? (in the sim, yes) */
198void volume_size(IF_MV(int volume,) unsigned long *sizep, unsigned long *freep)
38{ 199{
39 IF_MV((void) volume); 200 unsigned long size = 0, free = 0;
40 *size = *free = 0; 201 char volpath[MAX_PATH];
202 struct statfs fs;
203
204 if (os_volume_path(IF_MV(volume,) volpath, sizeof (volpath)) >= 0
205 && !statfs(volpath, &fs))
206 {
207 DEBUGF("statvfs: frsize=%d blocks=%ld bfree=%ld\n",
208 (int)fs.f_frsize, (long)fs.f_blocks, (long)fs.f_bfree);
209 if (sizep)
210 size = (fs.f_blocks / 2) * (fs.f_frsize / 512);
211
212 if (freep)
213 free = (fs.f_bfree / 2) * (fs.f_frsize / 512);
214 }
215
216 if (sizep)
217 *sizep = size;
218
219 if (freep)
220 *freep = free;
41} 221}
diff --git a/firmware/target/hosted/filesystem-unix.h b/firmware/target/hosted/filesystem-unix.h
new file mode 100644
index 0000000000..a09712d8b0
--- /dev/null
+++ b/firmware/target/hosted/filesystem-unix.h
@@ -0,0 +1,82 @@
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_UNIX_H_
22#define _FILESYSTEM_UNIX_H_
23
24/* Include for file.h and dir.h because mkdir and friends may be here */
25#include <sys/stat.h>
26
27#define strlcpy_from_os strlcpy
28#endif
29
30#ifdef _FILE_H_
31#ifndef _FILESYSTEM_UNIX__FILE_H_
32#define _FILESYSTEM_UNIX__FILE_H_
33
34#include <unistd.h>
35
36#define OS_STAT_T struct stat
37
38#ifndef OSFUNCTIONS_DECLARED
39#define os_open open
40#define os_creat creat
41#define os_close close
42#define os_lseek lseek
43#define os_stat stat
44#define os_fstat fstat
45#define os_fstatat fstatat
46#define os_lstat lstat
47#define os_fsync fsync
48#define os_ftruncate ftruncate
49#define os_remove remove
50#define os_rename rename
51#define os_readlink readlink
52#ifndef os_read
53#define os_read read
54#endif
55#ifndef os_write
56#define os_write write
57#endif
58#endif /* !OSFUNCTIONS_DECLARED */
59
60#endif /* _FILESYSTEM_UNIX__FILE_H_ */
61#endif /* _FILE_H_ */
62
63#ifdef _DIR_H_
64#ifndef _FILESYSTEM_UNIX__DIR_H_
65#define _FILESYSTEM_UNIX__DIR_H_
66
67#include <dirent.h>
68
69#define OS_DIR_T DIR
70#define OS_DIRENT_T struct dirent
71
72#ifndef OSFUNCTIONS_DECLARED
73#define os_opendir opendir
74#define os_readdir readdir
75#define os_closedir closedir
76#define os_mkdir mkdir
77#define os_rmdir rmdir
78#define os_dirfd dirfd /* NOTE: might have to wrap on some platforms */
79#endif /* !OSFUNCTIONS_DECLARED */
80
81#endif /* _FILESYSTEM_UNIX__DIR_H_ */
82#endif /* _DIR_H_ */
diff --git a/firmware/target/hosted/filesystem-win32.c b/firmware/target/hosted/filesystem-win32.c
new file mode 100644
index 0000000000..19ef1c0aa7
--- /dev/null
+++ b/firmware/target/hosted/filesystem-win32.c
@@ -0,0 +1,479 @@
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#define RB_FILESYSTEM_OS
22#include <stdio.h>
23#include <errno.h>
24#include <ctype.h>
25#include <stdlib.h>
26#include "config.h"
27#include "system.h"
28#include "file.h"
29#include "dir.h"
30#include "debug.h"
31#include "pathfuncs.h"
32#include "string-extra.h"
33
34#define SAME_FILE_INFO(lpInfo1, lpInfo2) \
35 ((lpInfo1)->dwVolumeSerialNumber == (lpInfo2)->dwVolumeSerialNumber && \
36 (lpInfo1)->nFileIndexHigh == (lpInfo2)->nFileIndexHigh && \
37 (lpInfo1)->nFileIndexLow == (lpInfo2)->nFileIndexLow)
38
39#define WIN32_LEAN_AND_MEAN
40#include <windows.h>
41
42static void win32_last_error_errno(void)
43{
44 switch (GetLastError())
45 {
46 case ERROR_FILE_NOT_FOUND:
47 case ERROR_PATH_NOT_FOUND:
48 errno = ENOENT;
49 break;
50 case ERROR_DIR_NOT_EMPTY:
51 errno = ENOTEMPTY;
52 break;
53 default:
54 errno = EIO;
55 }
56}
57
58#ifdef __MINGW32__
59#include <wchar.h>
60#include "rbunicode.h"
61
62static HANDLE win32_open(const char *ospath);
63static int win32_stat(const char *ospath, LPBY_HANDLE_FILE_INFORMATION lpInfo);
64
65unsigned short * strcpy_utf8ucs2(unsigned short *buffer,
66 const unsigned char *utf8)
67{
68 for (wchar_t *ucs2 = buffer;
69 ((utf8 = utf8decode(utf8, ucs2)), *ucs2); ucs2++);
70 return buffer;
71}
72
73#if 0
74unsigned char * strcpy_ucs2utf8(unsigned char *buffer,
75 const unsigned short *ucs2)
76{
77 for (unsigned char *utf8 = buffer;
78 ((utf8 = utf8encode(*ucs2, utf8)), *ucs2); ucs2++);
79 return buffer;
80}
81
82size_t strlen_utf8ucs2(const unsigned char *utf8)
83{
84 /* This won't properly count multiword ucs2 so use the alternative
85 below for now which doesn't either */
86 size_t length = 0;
87 unsigned short ucschar[2];
88 for (unsigned char c = *utf8; c;
89 ((utf8 = utf8decode(utf8, ucschar)), c = *utf8))
90 length++;
91
92 return length;
93}
94#endif /* 0 */
95
96size_t strlen_utf8ucs2(const unsigned char *utf8)
97{
98 return utf8length(utf8);
99}
100
101size_t strlen_ucs2utf8(const unsigned short *ucs2)
102{
103 size_t length = 0;
104 unsigned char utf8char[4];
105
106 for (unsigned short c = *ucs2; c; (c = *++ucs2))
107 length += utf8encode(c, utf8char) - utf8char;
108
109 return length;
110}
111
112size_t strlcpy_ucs2utf8(char *buffer, const unsigned short *ucs2,
113 size_t bufsize)
114{
115 if (!buffer)
116 bufsize = 0;
117
118 size_t length = 0;
119 unsigned char utf8char[4];
120
121 for (unsigned short c = *ucs2; c; (c = *++ucs2))
122 {
123 /* If the last character won't fit, this won't split it */
124 size_t utf8size = utf8encode(c, utf8char) - utf8char;
125 if ((length += utf8size) < bufsize)
126 buffer = mempcpy(buffer, utf8char, utf8size);
127 }
128
129 /* Above won't ever copy to very end */
130 if (bufsize)
131 *buffer = '\0';
132
133 return length;
134}
135
136#define _toucs2(utf8) \
137 ({ const char *_utf8 = (utf8); \
138 size_t _l = strlen_utf8ucs2(_utf8); \
139 void *_buffer = alloca((_l + 1)*2); \
140 strcpy_utf8ucs2(_buffer, _utf8); })
141
142#define _toutf8(ucs2) \
143 ({ const char *_ucs2 = (ucs2); \
144 size_t _l = strlen_ucs2utf8(_ucs2); \
145 void *_buffer = alloca(_l + 1); \
146 strcpy_ucs2utf8(_buffer, _ucs2); })
147
148int os_open(const char *ospath, int oflag, ...)
149{
150 return _wopen(_toucs2(ospath), oflag __OPEN_MODE_ARG);
151}
152
153int os_creat(const char *ospath, mode_t mode)
154{
155 return _wcreat(_toucs2(ospath), mode);
156}
157
158int os_stat(const char *ospath, struct _stat *s)
159{
160 return _wstat(_toucs2(ospath), s);
161}
162
163int os_remove(const char *ospath)
164{
165 return _wremove(_toucs2(ospath));
166}
167
168int os_rename(const char *osold, const char *osnew)
169{
170 int errnum = errno;
171
172 const wchar_t *wchosold = _toucs2(osold);
173 const wchar_t *wchosnew = _toucs2(osnew);
174
175 int rc = _wrename(wchosold, wchosnew);
176 if (rc < 0 && errno == EEXIST)
177 {
178 /* That didn't work; do cheap POSIX mimic */
179 BY_HANDLE_FILE_INFORMATION info;
180 if (win32_stat(osold, &info))
181 return -1;
182
183 if ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
184 !RemoveDirectoryW(wchosnew))
185 {
186 win32_last_error_errno();
187 return -1;
188 }
189
190 if (MoveFileExW(wchosold, wchosnew, MOVEFILE_REPLACE_EXISTING |
191 MOVEFILE_WRITE_THROUGH))
192 {
193 errno = errnum;
194 return 0;
195 }
196
197 errno = EIO;
198 }
199
200 return rc;
201}
202
203bool os_file_exists(const char *ospath)
204{
205 HANDLE h = win32_open(ospath);
206 if (h == INVALID_HANDLE_VALUE)
207 return false;
208
209 CloseHandle(h);
210 return true;
211}
212
213_WDIR * os_opendir(const char *osdirname)
214{
215 return _wopendir(_toucs2(osdirname));
216}
217
218int os_mkdir(const char *ospath, mode_t mode)
219{
220 return _wmkdir(_toucs2(ospath));
221 (void)mode;
222}
223
224int os_rmdir(const char *ospath)
225{
226 return _wrmdir(_toucs2(ospath));
227}
228
229int os_dirfd(_WDIR *osdirp)
230{
231#ifdef ENOTSUP
232 errno = ENOTSUP
233#else
234 errno = ENOSYS;
235#endif
236 return -1;
237 (void)osdirp;
238}
239
240int os_opendirfd(const char *osdirname)
241{
242 HANDLE h = win32_open(osdirname);
243 if (h == INVALID_HANDLE_VALUE)
244 return -1;
245
246 BY_HANDLE_FILE_INFORMATION info;
247 if (!GetFileInformationByHandle(h, &info))
248 errno = EIO;
249 else if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
250 errno = ENOTDIR;
251 else
252 {
253 /* Convert OS handle to fd; the fd now owns it */
254 int osfd = _open_osfhandle((long)h, O_RDONLY);
255 if (osfd >= 0)
256 return osfd;
257 }
258
259 CloseHandle(h);
260 return -2;
261}
262#endif /* __MINGW32__ */
263
264static size_t win32_path_strip_root(const char *ospath)
265{
266 const char *p = ospath;
267 int c = toupper(*p);
268
269 if (c >= 'A' && c <= 'Z')
270 {
271 /* drive */
272 if ((c = *++p) == ':')
273 return 2;
274 }
275
276 if (c == '\\' && *++p == '\\')
277 {
278 /* UNC */
279 while ((c = *++p) && c != '/' && c != '\\');
280 return p - ospath;
281 }
282
283 return 0;
284}
285
286static HANDLE win32_open(const char *ospath)
287{
288 /* FILE_FLAG_BACKUP_SEMANTICS is required for this to succeed at opening
289 a directory */
290 HANDLE h = CreateFileW(_toucs2(ospath), GENERIC_READ,
291 FILE_SHARE_READ | FILE_SHARE_WRITE |
292 FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
293 FILE_FLAG_BACKUP_SEMANTICS, NULL);
294
295 if (h == INVALID_HANDLE_VALUE)
296 win32_last_error_errno();
297
298 return h;
299}
300
301static int win32_fstat(int osfd, HANDLE hFile,
302 LPBY_HANDLE_FILE_INFORMATION lpInfo)
303{
304 /* The file descriptor takes precedence over the win32 file handle */
305 if (osfd >= 0)
306 hFile = (HANDLE)_get_osfhandle(osfd);
307
308 int rc = GetFileInformationByHandle(hFile, lpInfo) ? 0 : -1;
309 if (rc < 0)
310 win32_last_error_errno();
311
312 return rc;
313}
314
315static int win32_stat(const char *ospath, LPBY_HANDLE_FILE_INFORMATION lpInfo)
316{
317 HANDLE h = win32_open(ospath);
318 if (h == INVALID_HANDLE_VALUE)
319 return -1;
320
321 int rc = win32_fstat(-1, h, lpInfo);
322
323 CloseHandle(h);
324
325 return rc;
326}
327
328int os_opendir_and_fd(const char *osdirname, _WDIR **osdirpp,
329 int *osfdp)
330{
331 /* another possible way is to use open() then fdopendir() */
332 *osdirpp = NULL;
333 *osfdp = -1;
334
335 _WDIR *dirp = os_opendir(osdirname);
336 if (!dirp)
337 return -1;
338
339 int rc = 0;
340 int errnum = errno;
341
342 int fd = os_dirfd(dirp);
343 if (fd < 0)
344 {
345 fd = os_opendirfd(osdirname);
346 rc = 1;
347 }
348
349 if (fd < 0)
350 {
351 os_closedir(dirp);
352 return -2;
353 }
354
355 errno = errnum;
356
357 *osdirpp = dirp;
358 *osfdp = fd;
359
360 return rc;
361}
362
363int os_fsamefile(int osfd1, int osfd2)
364{
365 BY_HANDLE_FILE_INFORMATION info1, info2;
366
367 if (!win32_fstat(osfd1, INVALID_HANDLE_VALUE, &info1) ||
368 !win32_fstat(osfd2, INVALID_HANDLE_VALUE, &info2))
369 return -1;
370
371 return SAME_FILE_INFO(&info1, &info2) ? 1 : 0;
372}
373
374int os_relate(const char *ospath1, const char *ospath2)
375{
376 DEBUGF("\"%s\" : \"%s\"\n", ospath1, ospath2);
377
378 if (!ospath2 || !*ospath2)
379 {
380 errno = ospath2 ? ENOENT : EFAULT;
381 return -1;
382 }
383
384 /* First file must stay open for duration so that its stats don't change */
385 HANDLE h1 = win32_open(ospath1);
386 if (h1 == INVALID_HANDLE_VALUE)
387 return -2;
388
389 BY_HANDLE_FILE_INFORMATION info1;
390 if (win32_fstat(-1, h1, &info1))
391 {
392 CloseHandle(h1);
393 return -3;
394 }
395
396 char path2buf[strlen(ospath2) + 1];
397 *path2buf = 0;
398
399 ssize_t len = 0;
400 const char *p = ospath2;
401 size_t rootlen = win32_path_strip_root(ospath2);
402 const char *sepmo = PA_SEP_SOFT;
403
404 if (rootlen)
405 {
406 strmemcpy(path2buf, ospath2, rootlen);
407 ospath2 += rootlen;
408 sepmo = PA_SEP_HARD;
409 }
410
411 int rc = RELATE_DIFFERENT;
412
413 while (1)
414 {
415 if (sepmo != PA_SEP_HARD &&
416 !(len = parse_path_component(&ospath2, &p)))
417 {
418 break;
419 }
420
421 char compname[len + 1];
422 strmemcpy(compname, p, len);
423
424 path_append(path2buf, sepmo, compname, sizeof (path2buf));
425 sepmo = PA_SEP_SOFT;
426
427 int errnum = errno; /* save and restore if not actually failing */
428 BY_HANDLE_FILE_INFORMATION info2;
429
430 if (!win32_stat(path2buf, &info2))
431 {
432 if (SAME_FILE_INFO(&info1, &info2))
433 {
434 rc = RELATE_SAME;
435 }
436 else if (rc == RELATE_SAME)
437 {
438 if (name_is_dot_dot(compname))
439 rc = RELATE_DIFFERENT;
440 else if (!name_is_dot(compname))
441 rc = RELATE_PREFIX;
442 }
443 }
444 else if (errno == ENOENT && !*GOBBLE_PATH_SEPCH(ospath2) &&
445 !name_is_dot_dot(compname))
446 {
447 if (rc == RELATE_SAME)
448 rc = RELATE_PREFIX;
449
450 errno = errnum;
451 break;
452 }
453 else
454 {
455 rc = -4;
456 break;
457 }
458 }
459
460 CloseHandle(h1);
461
462 return rc;
463}
464
465void volume_size(IF_MV(int volume,) unsigned long *sizep, unsigned long *freep)
466{
467 ULARGE_INTEGER free = { .QuadPart = 0 },
468 size = { .QuadPart = 0 };
469
470 char volpath[MAX_PATH];
471 if (os_volume_path(IF_MV(volume, ) volpath, sizeof (volpath)) >= 0)
472 GetDiskFreeSpaceExW(_toucs2(volpath), &free, &size, NULL);
473
474 if (sizep)
475 *sizep = size.QuadPart / 1024;
476
477 if (freep)
478 *freep = free.QuadPart / 1024;
479}
diff --git a/firmware/target/hosted/filesystem-win32.h b/firmware/target/hosted/filesystem-win32.h
new file mode 100644
index 0000000000..1d8f2749f9
--- /dev/null
+++ b/firmware/target/hosted/filesystem-win32.h
@@ -0,0 +1,111 @@
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_WIN32_H_
22#define _FILESYSTEM_WIN32_H_
23
24#ifndef OSFUNCTIONS_DECLARED
25
26#ifdef __MINGW32__
27/* filesystem-win32.c contains some string functions that could be useful
28 * elsewhere; just move them away to unicode.c or something if they prove
29 * so. */
30size_t strlcpy_ucs2utf8(char *buffer, const unsigned short *ucs,
31 size_t bufsize);
32
33#define strlcpy_from_os strlcpy_ucs2utf8
34#endif /* __MINGW32__ */
35
36#endif /* !OSFUNCTIONS_DECLARED */
37
38#endif /* _FILESYSTEM_WIN32_H_ */
39
40#ifdef __MINGW32__
41
42#ifdef _FILE_H_
43#ifndef _FILESYSTEM_WIN32__FILE_H_
44#define _FILESYSTEM_WIN32__FILE_H_
45
46#include <unistd.h>
47#include <sys/stat.h>
48
49#define OS_STAT_T struct _stat
50
51#ifndef OSFUNCTIONS_DECLARED
52/* Wrap for off_t <=> long conversions */
53static inline off_t os_filesize_(int osfd)
54 { return _filelength(osfd); }
55static inline int os_ftruncate_(int osfd, off_t length)
56 { return _chsize(osfd, length); }
57
58#define os_filesize os_filesize_
59#define os_ftruncate os_ftruncate_
60#define os_fsync _commit
61#define os_fstat _fstat
62#define os_close close
63#define os_lseek lseek
64#ifndef os_read
65#define os_read read
66#endif
67#ifndef os_write
68#define os_write write
69#endif
70
71/* These need string type conversion from utf8 to ucs2; that's done inside */
72int os_open(const char *ospath, int oflag, ...);
73int os_creat(const char *ospath, mode_t mode);
74int os_stat(const char *ospath, struct _stat *s);
75int os_remove(const char *ospath);
76int os_rename(const char *osold, const char *osnew);
77
78#endif /* !OSFUNCTIONS_DECLARED */
79
80#endif /* _FILESYSTEM_WIN32__FILE_H_ */
81#endif /* _FILE_H_ */
82
83#ifdef _DIR_H_
84#ifndef _FILESYSTEM_WIN32__DIR_H_
85#define _FILESYSTEM_WIN32__DIR_H_
86
87#include <dirent.h>
88
89#define OS_DIRENT_CONVERT /* needs string conversion */
90#define OS_DIR_T _WDIR
91#define OS_DIRENT_T struct _wdirent
92
93#ifndef OSFUNCTIONS_DECLARED
94
95_WDIR * os_opendir(const char *osdirname);
96int os_opendirfd(const char *osdirname);
97#define os_readdir _wreaddir
98#define os_closedir _wclosedir
99int os_mkdir(const char *ospath, mode_t mode);
100int os_rmdir(const char *ospath);
101
102#endif /* OSFUNCTIONS_DECLARED */
103
104#endif /* _FILESYSTEM_WIN32__DIR_H_ */
105#endif /* _DIR_H_ */
106
107#else /* !__MINGW32__ */
108
109#include "filesystem-unix.h"
110
111#endif /* __MINGW32__ */
diff --git a/firmware/target/hosted/lc-unix.c b/firmware/target/hosted/lc-unix.c
index 6e5f15ec99..810dc9f92c 100644
--- a/firmware/target/hosted/lc-unix.c
+++ b/firmware/target/hosted/lc-unix.c
@@ -50,14 +50,3 @@ void lc_close(void *handle)
50{ 50{
51 dlclose(handle); 51 dlclose(handle);
52} 52}
53
54void *lc_open_from_mem(void *addr, size_t blob_size)
55{
56 (void)addr;
57 (void)blob_size;
58 /* we don't support loading code from memory on application builds,
59 * it doesn't make sense (since it means writing the blob to disk again and
60 * then falling back to load from disk) and requires the ability to write
61 * to an executable directory */
62 return NULL;
63}
diff --git a/firmware/target/hosted/sdl/app/load_code-sdl-app.c b/firmware/target/hosted/sdl/app/load_code-sdl-app.c
new file mode 100644
index 0000000000..686944343f
--- /dev/null
+++ b/firmware/target/hosted/sdl/app/load_code-sdl-app.c
@@ -0,0 +1,36 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2010 Thomas Martitz
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 "system.h"
23#include "file.h"
24#include "load_code.h"
25
26void *lc_open(const char *filename, unsigned char *buf, size_t buf_size)
27{
28 char realpath[MAX_PATH];
29 const char *fpath = handle_special_dirs(filename, 0, realpath,
30 sizeof (realpath));
31 if (!fpath)
32 return NULL;
33
34 return os_lc_open(fpath);
35 (void)buf; (void)buf_size;
36}
diff --git a/firmware/target/hosted/sdl/filesystem-sdl.c b/firmware/target/hosted/sdl/filesystem-sdl.c
new file mode 100644
index 0000000000..5a8e2c417a
--- /dev/null
+++ b/firmware/target/hosted/sdl/filesystem-sdl.c
@@ -0,0 +1,55 @@
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#define RB_FILESYSTEM_OS
22#include "config.h"
23#include "system.h"
24#include "thread-sdl.h"
25#include "mutex.h"
26#include "file.h"
27
28#ifdef HAVE_SDL_THREADS
29#define YIELD_THRESHOLD 512
30static bool initialized = false;
31static struct mutex readwrite_mtx;
32
33/* Allow other threads to run while performing I/O */
34ssize_t os_sdl_readwrite(int osfd, void *buf, size_t nbyte, bool dowrite)
35{
36 if (!initialized)
37 {
38 mutex_init(&readwrite_mtx);
39 initialized = true;
40 }
41
42 mutex_lock(&readwrite_mtx);
43
44 void *mythread = nbyte > YIELD_THRESHOLD ? sim_thread_unlock() : NULL;
45
46 ssize_t rc = dowrite ? write(osfd, buf, nbyte) : read(osfd, buf, nbyte);
47
48 if (mythread)
49 sim_thread_lock(mythread);
50
51 mutex_unlock(&readwrite_mtx);
52 return rc;
53}
54
55#endif /* HAVE_SDL_THREADS */
diff --git a/firmware/target/hosted/sdl/filesystem-sdl.h b/firmware/target/hosted/sdl/filesystem-sdl.h
new file mode 100644
index 0000000000..934b43b34b
--- /dev/null
+++ b/firmware/target/hosted/sdl/filesystem-sdl.h
@@ -0,0 +1,37 @@
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_SDL_H_
22#define _FILESYSTEM_SDL_H_
23
24#ifdef HAVE_SDL_THREADS
25#undef os_read
26#undef os_write
27
28ssize_t os_sdl_readwrite(int osfd, void *buf, size_t nbyte, bool dowrite);
29
30#define os_read(osfd, buf, nbyte) \
31 os_sdl_readwrite((osfd), (buf), (nbyte), false)
32#define os_write(osfd, buf, nbyte) \
33 os_sdl_readwrite((osfd), (void *)(buf), (nbyte), true)
34
35#endif /* HAVE_SDL_THREADS */
36
37#endif /* _FILESYSTEM_SDL_H_ */
diff --git a/firmware/target/hosted/sdl/load_code-sdl.c b/firmware/target/hosted/sdl/load_code-sdl.c
new file mode 100644
index 0000000000..ee29853ab5
--- /dev/null
+++ b/firmware/target/hosted/sdl/load_code-sdl.c
@@ -0,0 +1,52 @@
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 <SDL_loadso.h>
23#include "system.h"
24#include "load_code.h"
25#include "filesystem-sdl.h"
26#include "debug.h"
27
28void * os_lc_open(const char *ospath)
29{
30 void *handle = SDL_LoadObject(ospath);
31 if (handle == NULL)
32 {
33 DEBUGF("%s(\"%s\") failed\n", __func__, ospath);
34 DEBUGF(" SDL error '%s'\n", SDL_GetError());
35 }
36
37 return handle;
38}
39
40void * lc_get_header(void *handle)
41{
42 char *ret = SDL_LoadFunction(handle, "__header");
43 if (ret == NULL)
44 ret = SDL_LoadFunction(handle, "___header");
45
46 return ret;
47}
48
49void lc_close(void *handle)
50{
51 SDL_UnloadObject(handle);
52}
diff --git a/firmware/target/hosted/sdl/system-sdl.c b/firmware/target/hosted/sdl/system-sdl.c
index fdf79d9333..aa322ddf3a 100644
--- a/firmware/target/hosted/sdl/system-sdl.c
+++ b/firmware/target/hosted/sdl/system-sdl.c
@@ -51,6 +51,8 @@
51 51
52#endif 52#endif
53 53
54#define SIMULATOR_DEFAULT_ROOT "simdisk"
55
54SDL_Surface *gui_surface; 56SDL_Surface *gui_surface;
55 57
56bool background = true; /* use backgrounds by default */ 58bool background = true; /* use backgrounds by default */
@@ -63,7 +65,7 @@ bool debug_buttons = false;
63bool lcd_display_redraw = true; /* Used for player simulator */ 65bool lcd_display_redraw = true; /* Used for player simulator */
64char having_new_lcd = true; /* Used for player simulator */ 66char having_new_lcd = true; /* Used for player simulator */
65bool sim_alarm_wakeup = false; 67bool sim_alarm_wakeup = false;
66const char *sim_root_dir = NULL; 68const char *sim_root_dir = SIMULATOR_DEFAULT_ROOT;
67 69
68static SDL_Thread *evt_thread = NULL; 70static SDL_Thread *evt_thread = NULL;
69 71
diff --git a/firmware/target/hosted/sdl/system-sim.h b/firmware/target/hosted/sdl/system-sim.h
new file mode 100644
index 0000000000..16c0cdde52
--- /dev/null
+++ b/firmware/target/hosted/sdl/system-sim.h
@@ -0,0 +1,32 @@
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 _SYSTEM_SIM_H_
22#define _SYSTEM_SIM_H_
23
24#ifdef WIN32
25#include <time.h>
26struct tm * localtime_r(const time_t *restrict timer,
27 struct tm *restrict result);
28struct tm * gmtime_r(const time_t *restrict timer,
29 struct tm *restrict result);
30#endif /* WIN32 */
31
32#endif /* _SYSTEM_SIM_H_ */
diff --git a/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c b/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c
index 9c0d1982ad..0e74444cf3 100644
--- a/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c
+++ b/firmware/target/mips/ingenic_jz47xx/ata-sd-jz4740.c
@@ -26,7 +26,6 @@
26#include "ata_idle_notify.h" 26#include "ata_idle_notify.h"
27#include "ata-sd-target.h" 27#include "ata-sd-target.h"
28#include "disk.h" 28#include "disk.h"
29#include "fat.h"
30#include "led.h" 29#include "led.h"
31#include "sdmmc.h" 30#include "sdmmc.h"
32#include "logf.h" 31#include "logf.h"
@@ -1467,34 +1466,28 @@ static void sd_thread(void)
1467 { 1466 {
1468#ifdef HAVE_HOTSWAP 1467#ifdef HAVE_HOTSWAP
1469 case SYS_HOTSWAP_INSERTED: 1468 case SYS_HOTSWAP_INSERTED:
1470 case SYS_HOTSWAP_EXTRACTED: 1469 case SYS_HOTSWAP_EXTRACTED:;
1471 fat_lock(); /* lock-out FAT activity first - 1470 int success = 1;
1472 prevent deadlocking via disk_mount that
1473 would cause a reverse-order attempt with
1474 another thread */
1475 mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
1476 into driver that bypass the fat cache */
1477 1471
1478 /* We now have exclusive control of fat cache and ata */ 1472 disk_unmount(sd_drive_nr); /* release "by force" */
1479 1473
1480 disk_unmount(sd_drive_nr); /* release "by force", ensure file 1474 mutex_lock(&sd_mtx); /* lock-out card activity */
1481 descriptors aren't leaked and any busy
1482 ones are invalid if mounting */
1483 1475
1484 /* Force card init for new card, re-init for re-inserted one or 1476 /* Force card init for new card, re-init for re-inserted one or
1485 * clear if the last attempt to init failed with an error. */ 1477 * clear if the last attempt to init failed with an error. */
1486 card.initialized = 0; 1478 card.initialized = 0;
1487 1479
1480 mutex_unlock(&sd_mtx);
1481
1488 if(ev.id == SYS_HOTSWAP_INSERTED) 1482 if(ev.id == SYS_HOTSWAP_INSERTED)
1489 disk_mount(sd_drive_nr); 1483 success = disk_mount(sd_drive_nr); /* 0 if fail */
1490 1484
1491 queue_broadcast(SYS_FS_CHANGED, 0); 1485 if(success)
1486 queue_broadcast(SYS_FS_CHANGED, 0);
1492 1487
1493 /* Access is now safe */
1494 mutex_unlock(&sd_mtx);
1495 fat_unlock();
1496 break; 1488 break;
1497#endif 1489#endif /* HAVE_HOTSWAP */
1490
1498 case SYS_TIMEOUT: 1491 case SYS_TIMEOUT:
1499 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ))) 1492 if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
1500 idle_notified = false; 1493 idle_notified = false;