summaryrefslogtreecommitdiffstats
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)
{
#ifdef HAVE_HOTSWAP
case SYS_HOTSWAP_INSERTED:
- case SYS_HOTSWAP_EXTRACTED:
- {
- int microsd_init = 1;
- fat_lock(); /* lock-out FAT activity first -
- prevent deadlocking via disk_mount that
- would cause a reverse-order attempt with
- another thread */
- mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
- into driver that bypass the fat cache */
+ case SYS_HOTSWAP_EXTRACTED:;
+ int success = 1;
- /* We now have exclusive control of fat cache and ata */
+ disk_unmount(SD_SLOT_AS3525); /* release "by force" */
- disk_unmount(SD_SLOT_AS3525); /* release "by force", ensure file
- descriptors aren't leaked and any busy
- ones are invalid if mounting */
+ mutex_lock(&sd_mtx); /* lock-out card activity */
/* Force card init for new card, re-init for re-inserted one or
* clear if the last attempt to init failed with an error. */
@@ -471,29 +462,32 @@ static void sd_thread(void)
if (ev.id == SYS_HOTSWAP_INSERTED)
{
+ success = 0;
sd_enable(true);
init_pl180_controller(SD_SLOT_AS3525);
- microsd_init = sd_init_card(SD_SLOT_AS3525);
- if (microsd_init < 0) /* initialisation failed */
- panicf("microSD init failed : %d", microsd_init);
-
- microsd_init = disk_mount(SD_SLOT_AS3525); /* 0 if fail */
+ int rc = sd_init_card(SD_SLOT_AS3525);
+ sd_enable(false);
+ if (rc >= 0)
+ success = 2;
+ else /* initialisation failed */
+ panicf("microSD init failed : %d", rc);
}
+ mutex_unlock(&sd_mtx);
+
+ if (success > 1)
+ success = disk_mount(SD_SLOT_AS3525); /* 0 if fail */
+
/*
* Mount succeeded, or this was an EXTRACTED event,
* in both cases notify the system about the changed filesystems
*/
- if (microsd_init)
+ if (success)
queue_broadcast(SYS_FS_CHANGED, 0);
- /* Access is now safe */
- mutex_unlock(&sd_mtx);
- fat_unlock();
- sd_enable(false);
- }
break;
-#endif
+#endif /* HAVE_HOTSWAP */
+
case SYS_TIMEOUT:
if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
{
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)
{
#ifdef HAVE_HOTSWAP
case SYS_HOTSWAP_INSERTED:
- case SYS_HOTSWAP_EXTRACTED:
- {
- int changed = 1;
- fat_lock(); /* lock-out FAT activity first -
- prevent deadlocking via disk_mount that
- would cause a reverse-order attempt with
- another thread */
- mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
- into driver that bypass the fat cache */
-
- /* We now have exclusive control of fat cache and ata */
-
- disk_unmount(SD_SLOT_AS3525); /* release "by force", ensure file
- descriptors aren't leaked and any busy
- ones are invalid if mounting */
+ case SYS_HOTSWAP_EXTRACTED:;
+ int success = 1;
+
+ disk_unmount(SD_SLOT_AS3525); /* release "by force" */
+
+ mutex_lock(&sd_mtx); /* lock-out card activity */
+
/* Force card init for new card, re-init for re-inserted one or
* clear if the last attempt to init failed with an error. */
card_info[SD_SLOT_AS3525].initialized = 0;
@@ -620,24 +612,25 @@ static void sd_thread(void)
if (ev.id == SYS_HOTSWAP_INSERTED)
{
sd_enable(true);
- changed = (sd_init_card(SD_SLOT_AS3525) == 0) && disk_mount(SD_SLOT_AS3525); /* 0 if fail */
+ success = sd_init_card(SD_SLOT_AS3525) == 0 ? 2 : 0;
+ sd_enable(false);
}
+ mutex_unlock(&sd_mtx);
+
+ if (success > 1)
+ success = disk_mount(SD_SLOT_AS3525); /* 0 if fail */
+
/*
* Mount succeeded, or this was an EXTRACTED event,
* in both cases notify the system about the changed filesystems
*/
- if (changed)
+ if (success)
queue_broadcast(SYS_FS_CHANGED, 0);
- sd_enable(false);
-
- /* Access is now safe */
- mutex_unlock(&sd_mtx);
- fat_unlock();
- }
break;
-#endif
+#endif /* HAVE_HOTSWAP */
+
case SYS_TIMEOUT:
if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
{
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)
case SYS_HOTSWAP_INSERTED:
case SYS_HOTSWAP_EXTRACTED:
{
- int microsd_init = 1;
- /* lock-out FAT activity first -
- * prevent deadlocking via disk_mount that
- * would cause a reverse-order attempt with
- * another thread */
-#ifdef HAVE_HOTSWAP
- fat_lock();
-#endif
+ int microsd_init = ev.id == SYS_HOTSWAP_INSERTED ? 0 : 1;
/* We now have exclusive control of fat cache and sd.
* Release "by force", ensure file
@@ -785,35 +778,37 @@ static void sdmmc_thread(void)
/* Skip non-removable drivers */
if(!sdmmc_removable(drive))
continue;
- /* lock-out card activity - direct calls
- * into driver that bypass the fat cache */
- mutex_lock(&mutex[drive]);
+
disk_unmount(sd_first_drive + sd_drive);
+
+ mutex_lock(&mutex[drive]); /* lock-out card activity */
+
/* Force card init for new card, re-init for re-inserted one or
* clear if the last attempt to init failed with an error. */
SDMMC_INFO(sd_map[sd_drive]).initialized = 0;
+ int rc = -1;
if(ev.id == SYS_HOTSWAP_INSERTED)
{
- microsd_init = init_drive(drive);
- if(microsd_init < 0) /* initialisation failed */
- panicf("%s init failed : %d", SDMMC_CONF(sd_map[sd_drive]).name, microsd_init);
-
- microsd_init = disk_mount(sd_first_drive + sd_drive); /* 0 if fail */
+ rc = init_drive(drive);
+ if(rc < 0) /* initialisation failed */
+ panicf("%s init failed : %d", SDMMC_CONF(sd_map[sd_drive]).name, rc);
}
- /*
- * Mount succeeded, or this was an EXTRACTED event,
- * in both cases notify the system about the changed filesystems
- */
- if(microsd_init)
- queue_broadcast(SYS_FS_CHANGED, 0);
+
/* unlock card */
mutex_unlock(&mutex[drive]);
+
+ if (rc >= 0)
+ microsd_init += disk_mount(sd_first_drive + sd_drive); /* 0 if fail */
}
/* Access is now safe */
-#ifdef HAVE_HOTSWAP
- fat_unlock();
-#endif
+ /*
+ * One or more mounts succeeded, or this was an EXTRACTED event,
+ * in both cases notify the system about the changed filesystems
+ */
+ if(microsd_init)
+ queue_broadcast(SYS_FS_CHANGED, 0);
+
break;
}
#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 @@
*
****************************************************************************/
#include "config.h" /* for HAVE_MULTIDRIVE */
-#include "fat.h"
#include "sdmmc.h"
#include "gcc_extensions.h"
#ifdef HAVE_HOTSWAP
@@ -1125,35 +1124,28 @@ static void sd_thread(void)
{
#ifdef HAVE_HOTSWAP
case SYS_HOTSWAP_INSERTED:
- case SYS_HOTSWAP_EXTRACTED:
- fat_lock(); /* lock-out FAT activity first -
- prevent deadlocking via disk_mount that
- would cause a reverse-order attempt with
- another thread */
- mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
- into driver that bypass the fat cache */
+ case SYS_HOTSWAP_EXTRACTED:;
+ int success = 1;
- /* We now have exclusive control of fat cache and ata */
+ disk_unmount(sd_first_drive+1); /* release "by force" */
- disk_unmount(sd_first_drive+1); /* release "by force", ensure file
- descriptors aren't leaked and any busy
- ones are invalid if mounting */
+ mutex_lock(&sd_mtx); /* lock-out card activity */
/* Force card init for new card, re-init for re-inserted one or
* clear if the last attempt to init failed with an error. */
card_info[1].initialized = 0;
sd_status[1].retry = 0;
- if (ev.id == SYS_HOTSWAP_INSERTED)
- disk_mount(sd_first_drive+1);
-
- queue_broadcast(SYS_FS_CHANGED, 0);
-
/* Access is now safe */
mutex_unlock(&sd_mtx);
- fat_unlock();
+
+ if (ev.id == SYS_HOTSWAP_INSERTED)
+ success = disk_mount(sd_first_drive+1); /* 0 if fail */
+
+ if (success)
+ queue_broadcast(SYS_FS_CHANGED, 0);
break;
-#endif
+#endif /* HAVE_HOTSWAP */
case SYS_TIMEOUT:
if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
{
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 @@
****************************************************************************/
#include "config.h" /* for HAVE_MULTIVOLUME */
-#include "fat.h"
#include "thread.h"
#include "gcc_extensions.h"
#include "led.h"
@@ -331,50 +330,45 @@ static void sd_thread(void)
{
#ifdef HAVE_HOTSWAP
case SYS_HOTSWAP_INSERTED:
- case SYS_HOTSWAP_EXTRACTED:
- {
- int microsd_init = 1;
- fat_lock(); /* lock-out FAT activity first -
- prevent deadlocking via disk_mount that
- would cause a reverse-order attempt with
- another thread */
- mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
- into driver that bypass the fat cache */
-
- /* We now have exclusive control of fat cache and ata */
-
- disk_unmount(sd_first_drive); /* release "by force", ensure file
- descriptors aren't leaked and any busy
- ones are invalid if mounting */
+ case SYS_HOTSWAP_EXTRACTED:;
+ int success = 1;
+
+ disk_unmount(sd_first_drive); /* release "by force" */
+
+ mutex_lock(&sd_mtx); /* lock-out card activity */
+
/* Force card init for new card, re-init for re-inserted one or
* clear if the last attempt to init failed with an error. */
card_info.initialized = 0;
if (ev.id == SYS_HOTSWAP_INSERTED)
{
+ success = 0;
sd_enable(true);
- microsd_init = sd_init_card(sd_first_drive);
- if (microsd_init < 0) /* initialisation failed */
- panicf("microSD init failed : %d", microsd_init);
-
- microsd_init = disk_mount(sd_first_drive); /* 0 if fail */
+ int rc = sd_init_card(sd_first_drive);
+ sd_enable(false);
+ if (rc >= 0)
+ success = 2;
+ else /* initialisation failed */
+ panicf("microSD init failed : %d", rc);
}
+ /* Access is now safe */
+ mutex_unlock(&sd_mtx);
+
+ if (success > 1)
+ success = disk_mount(sd_first_drive); /* 0 if fail */
+
/*
* Mount succeeded, or this was an EXTRACTED event,
* in both cases notify the system about the changed filesystems
*/
- if (microsd_init)
+ if (success)
queue_broadcast(SYS_FS_CHANGED, 0);
- sd_enable(false);
-
- /* Access is now safe */
- mutex_unlock(&sd_mtx);
- fat_unlock();
- }
break;
-#endif
+#endif /* HAVE_HOTSWAP */
+
case SYS_TIMEOUT:
if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
{
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 @@
#ifdef HAVE_HOTSWAP
#include "sdmmc.h"
#include "disk.h"
-#include "fat.h"
#endif
#include "dma-target.h"
#include "system-target.h"
@@ -585,48 +584,29 @@ static void sd_thread(void)
{
#ifdef HAVE_HOTSWAP
case SYS_HOTSWAP_INSERTED:
- case SYS_HOTSWAP_EXTRACTED:
- {
+ case SYS_HOTSWAP_EXTRACTED:;
int success = 1;
- fat_lock(); /* lock-out FAT activity first -
- prevent deadlocking via disk_mount that
- would cause a reverse-order attempt with
- another thread */
- mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
- into driver that bypass the fat cache */
- /* We now have exclusive control of fat cache and ata */
+ disk_unmount(0); /* release "by force" */
- disk_unmount(0); /* release "by force", ensure file
- descriptors aren't leaked and any busy
- ones are invalid if mounting */
+ mutex_lock(&sd_mtx); /* lock-out card activity */
/* Force card init for new card, re-init for re-inserted one or
* clear if the last attempt to init failed with an error. */
card_info[0].initialized = 0;
+ /* Access is now safe */
+ mutex_unlock(&sd_mtx);
+
if (ev.id == SYS_HOTSWAP_INSERTED)
- {
- /* FIXME: once sd_enabled is implement properly,
- * reinitializing the controllers might be needed */
- sd_enable(true);
- if (success < 0) /* initialisation failed */
- panicf("SD init failed : %d", success);
success = disk_mount(0); /* 0 if fail */
- }
/* notify the system about the changed filesystems
*/
if (success)
queue_broadcast(SYS_FS_CHANGED, 0);
-
- /* Access is now safe */
- mutex_unlock(&sd_mtx);
- fat_unlock();
- sd_enable(false);
- }
break;
-#endif
+#endif /* HAVE_HOTSWAP */
}
}
}
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 @@
#include "s5l8702.h"
#include "led.h"
#include "ata_idle_notify.h"
-#include "fat.h"
+#include "disk_cache.h"
#include "splash.h"
@@ -68,6 +68,7 @@ static struct semaphore mmc_wakeup;
static struct semaphore mmc_comp_wakeup;
static int spinup_time = 0;
static int dma_mode = 0;
+static char aligned_buffer[SECTOR_SIZE] __attribute__((aligned(0x10)));
#ifdef ATA_HAVE_BBT
@@ -857,8 +858,25 @@ int ata_bbt_translate(uint64_t sector, uint32_t count, uint64_t* phys, uint32_t*
static int ata_rw_sectors(uint64_t sector, uint32_t count, void* buffer, bool write)
{
if (((uint32_t)buffer) & 0xf)
- panicf("ATA: Misaligned data buffer at %08X (sector %lu, count %lu)",
- (unsigned int)buffer, (long unsigned int)sector, (long unsigned int)count);
+ {
+ while (count)
+ {
+ if (write)
+ memcpy(aligned_buffer, buffer, SECTOR_SIZE);
+
+ PASS_RC(ata_rw_sectors(sector, 1, aligned_buffer, write), 0, 0);
+
+ if (!write)
+ memcpy(buffer, aligned_buffer, SECTOR_SIZE);
+
+ buffer += SECTOR_SIZE;
+ sector++;
+ count--;
+ }
+
+ return 0;
+ }
+
#ifdef ATA_HAVE_BBT
if (sector + count > ata_virtual_sectors) RET_ERR(0);
if (ata_bbt)
@@ -1117,14 +1135,13 @@ int ata_init(void)
-- Michael Sparmann (theseven), 2011-10-22 */
if (!ceata)
{
- unsigned char* sector = fat_get_sector_buffer();
+ unsigned char* sector = aligned_buffer;
ata_rw_sectors(0, 1, sector, false);
if (sector[510] == 0xaa && sector[511] == 0x55)
{
ata_swap = true;
splashf(5000, "Wrong HDD endianness, please update your emCORE version!");
}
- fat_release_sector_buffer();
}
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 @@
#include "led.h"
#include "thread.h"
#include "disk.h"
-#include "fat.h"
#include "ata_idle_notify.h"
#include "usb.h"
@@ -657,35 +656,30 @@ static void sd_thread(void)
{
#ifdef HAVE_HOTSWAP
case SYS_HOTSWAP_INSERTED:
- case SYS_HOTSWAP_EXTRACTED:
- fat_lock(); /* lock-out FAT activity first -
- prevent deadlocking via disk_mount that
- would cause a reverse-order attempt with
- another thread */
- mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
- into driver that bypass the fat cache */
-
- /* We now have exclusive control of fat cache and ata */
-
- /* Release "by force", ensure file descriptors aren't leaked and
- any busy ones are invalid if mounting */
+ case SYS_HOTSWAP_EXTRACTED:;
+ int success = 1;
+
+ /* Release "by force" */
disk_unmount(sd_first_drive + CARD_NUM_SLOT);
+ mutex_lock(&sd_mtx); /* lock-out card activity */
+
/* Force card init for new card, re-init for re-inserted one or
* clear if the last attempt to init failed with an error. */
card_info[CARD_NUM_SLOT].initialized = 0;
sd_status[CARD_NUM_SLOT].retry = 0;
+ mutex_unlock(&sd_mtx);
+
if (ev.id == SYS_HOTSWAP_INSERTED)
- disk_mount(sd_first_drive + CARD_NUM_SLOT);
+ success = disk_mount(sd_first_drive + CARD_NUM_SLOT);
- queue_broadcast(SYS_FS_CHANGED, 0);
+ if (success)
+ queue_broadcast(SYS_FS_CHANGED, 0);
- /* Access is now safe */
- mutex_unlock(&sd_mtx);
- fat_unlock();
break;
-#endif
+#endif /* HAVE_HOTSWAP */
+
case SYS_TIMEOUT:
if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
{
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)
{
#ifdef HAVE_HOTSWAP
case SYS_HOTSWAP_INSERTED:
- case SYS_HOTSWAP_EXTRACTED:
- {
+ case SYS_HOTSWAP_EXTRACTED:;
int success = 1;
- fat_lock(); /* lock-out FAT activity first -
- prevent deadlocking via disk_mount that
- would cause a reverse-order attempt with
- another thread */
- mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
- into driver that bypass the fat cache */
- /* We now have exclusive control of fat cache and ata */
+ disk_unmount(0); /* release "by force" */
- disk_unmount(0); /* release "by force", ensure file
- descriptors aren't leaked and any busy
- ones are invalid if mounting */
+ mutex_lock(&sd_mtx); /* lock-out card activity */
/* Force card init for new card, re-init for re-inserted one or
* clear if the last attempt to init failed with an error. */
card_info[0].initialized = 0;
+ mutex_unlock(&sd_mtx);
+
if (ev.id == SYS_HOTSWAP_INSERTED)
- {
- /* FIXME: once sd_enabled is implement properly,
- * reinitializing the controllers might be needed */
- sd_enable(true);
- if (success < 0) /* initialisation failed */
- panicf("SD init failed : %d", success);
success = disk_mount(0); /* 0 if fail */
- }
- /* notify the system about the changed filesystems
- */
+ /* notify the system about the changed filesystems */
if (success)
queue_broadcast(SYS_FS_CHANGED, 0);
- /* Access is now safe */
- mutex_unlock(&sd_mtx);
- fat_unlock();
- sd_enable(false);
- }
break;
-#endif
+#endif /* HAVE_HOTSWAP */
+
case SYS_TIMEOUT:
if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
{
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Thomas Martitz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#define RB_FILESYSTEM_OS
+#include <stdio.h> /* snprintf */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include "config.h"
+#include "system.h"
+#include "file.h"
+#include "dir.h"
+#include "file_internal.h"
+#include "pathfuncs.h"
+#include "string-extra.h"
+#include "rbpaths.h"
+#include "logf.h"
+
+
+#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
+static const char rbhome[] = "/sdcard";
+#elif (CONFIG_PLATFORM & (PLATFORM_SDL|PLATFORM_MAEMO|PLATFORM_PANDORA)) \
+ && !defined(__PCTOOL__)
+const char *rbhome;
+#else
+/* YPR0, YPR1 */
+static const char rbhome[] = HOME_DIR;
+#endif
+
+#if !(defined(SAMSUNG_YPR0) || defined(SAMSUNG_YPR1)) && !defined(__PCTOOL__)
+/* Special dirs are user-accessible (and user-writable) dirs which take priority
+ * over the ones where Rockbox is installed to. Classic example would be
+ * $HOME/.config/rockbox.org vs /usr/share/rockbox */
+#define HAVE_SPECIAL_DIRS
+#endif
+
+#ifdef HAVE_MULTIDRIVE
+/* This is to compare any opened directories with the home directory so that
+ the special drive links may be returned for it only */
+static int rbhome_fildes = -1;
+
+/* A special link is created under e.g. HOME_DIR/<microSD1>, e.g. to access
+ * external storage in a convenient location, much similar to the mount
+ * point on our native targets. Here they are treated as symlink (one which
+ * doesn't actually exist in the filesystem and therefore we have to override
+ * readlink() */
+static const char *handle_special_links(const char* link, unsigned flags,
+ char *buf, const size_t bufsize)
+{
+ (void) flags;
+ char vol_string[VOL_MAX_LEN + 1];
+ get_volume_name(-1, vol_string);
+
+ /* link might be passed with or without HOME_DIR expanded. To handle
+ * both perform substring matching (VOL_NAMES is unique enough) */
+ const char *begin = strstr(link, vol_string);
+ if (begin)
+ {
+ /* begin now points to the start of vol_string within link,
+ * we want to copy the remainder of the paths, prefixed by
+ * the actual mount point (the remainder might be "") */
+ snprintf(buf, bufsize, MULTIDRIVE_DIR"%s", begin + len);
+ return buf;
+ }
+
+ return link;
+}
+#endif
+
+#ifdef HAVE_MULTIDRIVE
+/* we keep an open descriptor of the home directory to detect when it has been
+ opened by opendir() so that its "symlinks" may be enumerated */
+static void cleanup_rbhome(void)
+{
+ os_close(rbhome_fildes);
+ rbhome_fildes = -1;
+}
+#endif /* HAVE_MULTIDRIVE */
+
+void paths_init(void)
+{
+#ifdef HAVE_SPECIAL_DIRS
+ /* make sure $HOME/.config/rockbox.org exists, it's needed for config.cfg */
+#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
+ os_mkdir("/sdcard/rockbox" __MKDIR_MODE_ARG);
+ os_mkdir("/sdcard/rockbox/rocks.data" __MKDIR_MODE_ARG);
+#else
+ char config_dir[MAX_PATH];
+
+ const char *home = getenv("RBROOT");
+ if (!home)
+ {
+ home = getenv("HOME");
+ }
+
+ if (!home)
+ {
+ logf("HOME environment var not set. Can't write config");
+ return;
+ }
+
+ rbhome = home;
+ snprintf(config_dir, sizeof(config_dir), "%s/.config", home);
+ os_mkdir(config_dir __MKDIR_MODE_ARG);
+ snprintf(config_dir, sizeof(config_dir), "%s/.config/rockbox.org", home);
+ os_mkdir(config_dir __MKDIR_MODE_ARG);
+ /* Plugin data directory */
+ snprintf(config_dir, sizeof(config_dir), "%s/.config/rockbox.org/rocks.data", home);
+ os_mkdir(config_dir __MKDIR_MODE_ARG);
+#endif
+#endif /* HAVE_SPECIAL_DIRS */
+
+#ifdef HAVE_MULTIDRIVE
+ /* if this fails then alternate volumes will not work, but this function
+ cannot return that fact */
+ rbhome_fildes = os_opendirfd(rbhome);
+ if (rbhome_fildes >= 0)
+ atexit(cleanup_rbhome);
+#endif /* HAVE_MULTIDRIVE */
+}
+
+#ifdef HAVE_SPECIAL_DIRS
+static const char* _get_user_file_path(const char *path,
+ unsigned flags,
+ char* buf,
+ const size_t bufsize)
+{
+ const char *ret = path;
+ const char *pos = path;
+ /* replace ROCKBOX_DIR in path with $HOME/.config/rockbox.org */
+ pos += ROCKBOX_DIR_LEN;
+ if (*pos == '/') pos += 1;
+
+#if (CONFIG_PLATFORM & PLATFORM_ANDROID)
+ if (path_append(buf, "/sdcard/rockbox", pos, bufsize) >= bufsize)
+ return NULL;
+#else
+ if (path_append(buf, rbhome, ".config/rockbox.org", bufsize) >= bufsize ||
+ path_append(buf, PA_SEP_SOFT, pos, bufsize) >= bufsize)
+ return NULL;
+#endif
+
+ /* always return the replacement buffer (pointing to $HOME) if
+ * write access is needed */
+ if (flags & NEED_WRITE)
+ ret = buf;
+ else if (os_file_exists(buf))
+ ret = buf;
+
+ if (ret != buf) /* not found in $HOME, try ROCKBOX_BASE_DIR, !NEED_WRITE only */
+ {
+ if (path_append(buf, ROCKBOX_SHARE_PATH, pos, bufsize) >= bufsize)
+ return NULL;
+
+ if (os_file_exists(buf))
+ ret = buf;
+ }
+
+ return ret;
+}
+
+#endif
+
+const char * handle_special_dirs(const char *dir, unsigned flags,
+ char *buf, const size_t bufsize)
+{
+ (void) flags; (void) buf; (void) bufsize;
+#ifdef HAVE_SPECIAL_DIRS
+ if (!strncmp(HOME_DIR, dir, HOME_DIR_LEN))
+ {
+ const char *p = dir + HOME_DIR_LEN;
+ while (*p == '/') p++;
+ snprintf(buf, bufsize, "%s/%s", rbhome, p);
+ dir = buf;
+ }
+ else if (!strncmp(ROCKBOX_DIR, dir, ROCKBOX_DIR_LEN))
+ dir = _get_user_file_path(dir, flags, buf, bufsize);
+#endif
+#ifdef HAVE_MULTIDRIVE
+ dir = handle_special_links(dir, flags, buf, bufsize);
+#endif
+ return dir;
+}
+
+int app_open(const char *path, int oflag, ...)
+{
+ int flags = IS_FILE;
+ if (oflag & O_ACCMODE)
+ flags |= NEED_WRITE;
+
+ char realpath[MAX_PATH];
+ const char *fpath = handle_special_dirs(path, flags, realpath,
+ sizeof (realpath));
+ if (!fpath)
+ FILE_ERROR_RETURN(ENAMETOOLONG, -1);
+
+ return os_open(fpath, oflag __OPEN_MODE_ARG);
+}
+
+int app_creat(const char *path, mode_t mode)
+{
+ return app_open(path, O_CREAT|O_WRONLY|O_TRUNC, mode);
+}
+
+int app_remove(const char *path)
+{
+ char realpath[MAX_PATH];
+ const char *fpath = handle_special_dirs(path, NEED_WRITE, realpath,
+ sizeof (realpath));
+ if (!fpath)
+ FILE_ERROR_RETURN(ENAMETOOLONG, -1);
+
+ return os_remove(fpath);
+}
+
+int app_rename(const char *old, const char *new)
+{
+ char realpath_old[MAX_PATH], realpath_new[MAX_PATH];
+ const char *fold = handle_special_dirs(old, NEED_WRITE, realpath_old,
+ sizeof (realpath_old));
+ const char *fnew = handle_special_dirs(new, NEED_WRITE, realpath_new,
+ sizeof (realpath_new));
+ if (!fold || !fnew)
+ FILE_ERROR_RETURN(ENAMETOOLONG, -1);
+
+ return os_rename(fold, fnew);
+}
+
+#ifdef HAVE_SDL_THREADS
+ssize_t app_read(int fd, void *buf, size_t nbyte)
+{
+ return os_read(fd, buf, nbyte);
+}
+
+ssize_t app_write(int fd, const void *buf, size_t nbyte)
+{
+ return os_write(fd, buf, nbyte);
+}
+#endif /* HAVE_SDL_THREADS */
+
+int app_relate(const char *path1, const char *path2)
+{
+ char realpath_1[MAX_PATH], realpath_2[MAX_PATH];
+ const char *fpath1 = handle_special_dirs(path1, 0, realpath_1,
+ sizeof (realpath_1));
+ const char *fpath2 = handle_special_dirs(path2, 0, realpath_2,
+ sizeof (realpath_2));
+
+ if (!fpath1 || !fpath2)
+ FILE_ERROR_RETURN(ENAMETOOLONG, -1);
+
+ return os_relate(fpath1, fpath2);
+}
+
+bool app_file_exists(const char *path)
+{
+ char realpath[MAX_PATH];
+ const char *fpath = handle_special_dirs(path, NEED_WRITE, realpath,
+ sizeof (realpath));
+ if (!fpath)
+ FILE_ERROR_RETURN(ENAMETOOLONG, false);
+
+ return os_file_exists(fpath);
+}
+
+/* need to wrap around DIR* because we need to save the parent's directory
+ * path in order to determine dirinfo for volumes or convert the path to UTF-8;
+ * also is required to implement get_dir_info() */
+struct __dir
+{
+ OS_DIR_T *osdirp;
+#ifdef HAVE_MULTIDRIVE
+ int volumes_returned;
+#endif
+ int osfd;
+ bool osfd_is_opened;
+#if defined(OS_DIRENT_CONVERT) || defined (HAVE_MULTIDRIVE)
+ #define USE_DIRENTP
+ struct dirent *direntp;
+ size_t d_name_size;
+#endif
+ char path[];
+};
+
+static void __dir_free(struct __dir *this)
+{
+ if (!this)
+ return;
+
+#ifdef USE_DIRENTP
+ free(this->direntp);
+#endif
+
+ if (this->osfd_is_opened)
+ os_close(this->osfd);
+
+ free(this);
+}
+
+DIR * app_opendir(const char *dirname)
+{
+ int rc;
+ char realpath[MAX_PATH];
+ const char *fname = handle_special_dirs(dirname, 0, realpath,
+ sizeof (realpath));
+ if (!fname)
+ FILE_ERROR_RETURN(ENAMETOOLONG, NULL);
+
+ size_t name_len = path_strip_trailing_separators(fname, &fname);
+ struct __dir *this = calloc(1, sizeof (*this) + name_len + 1);
+ if (!this)
+ FILE_ERROR(ENOMEM, RC);
+
+#ifdef USE_DIRENTP
+ /* allocate what we're really going to return to callers, making certain
+ it has at least the d_name size we want */
+ this->d_name_size = MAX(MAX_PATH, sizeof (this->direntp->d_name));
+ this->direntp = calloc(1, offsetof(typeof (*this->direntp), d_name) +
+ this->d_name_size);
+ if (!this->direntp)
+ FILE_ERROR(ENOMEM, RC);
+
+ /* only the d_name field will be valid but that is all that anyone may
+ truely count on portably existing */
+#endif /* USE_DIRENTP */
+
+ strmemcpy(this->path, fname, name_len);
+
+ rc = os_opendir_and_fd(this->path, &this->osdirp, &this->osfd);
+ if (rc < 0)
+ FILE_ERROR(ERRNO, RC);
+
+ this->osfd_is_opened = rc > 0;
+
+#ifdef HAVE_MULTIDRIVE
+ this->volumes_returned = INT_MAX; /* assume NOT $HOME */
+ if (rbhome_fildes >= 0 && os_samefile(rbhome_fildes, fd) > 0)
+ this->volumes_returned = 0; /* there's no place like $HOME */
+#endif /* HAVE_MULTIDRIVE */
+
+ return (DIR *)this;
+file_error:
+ __dir_free(this);
+ return NULL;
+}
+
+int app_closedir(DIR *dirp)
+{
+ struct __dir *this = (struct __dir *)dirp;
+ if (!this)
+ FILE_ERROR_RETURN(EBADF, -1);
+
+ OS_DIR_T *osdirp = this->osdirp;
+ __dir_free(this);
+
+ return os_closedir(osdirp);
+}
+
+struct dirent * app_readdir(DIR *dirp)
+{
+ struct __dir *this = (struct __dir *)dirp;
+ if (!this)
+ FILE_ERROR_RETURN(EBADF, NULL);
+
+#ifdef HAVE_MULTIDRIVE
+ if (this->volumes_returned < NUM_VOLUMES)
+ {
+ while (++this->volumes_returned < NUM_VOLUMES)
+ {
+ if (!volume_present(this->volumes_returned))
+ continue;
+
+ get_volume_name(this->volumes_returned, this->direntp->d_name);
+ return this->direntp;
+ }
+ }
+ /* do normal directory reads */
+#endif /* HAVE_MULTIDRIVE */
+
+ OS_DIRENT_T *osdirent = os_readdir(this->osdirp);
+
+#ifdef OS_DIRENT_CONVERT
+ if (strlcpy_from_os(this->direntp->d_name, osdirent->d_name,
+ this->d_name_size) >= this->d_name_size)
+ {
+ this->direntp->d_name[0] = '\0';
+ errno = EOVERFLOW;
+ return NULL;
+ }
+
+ osdirent = (OS_DIRENT_T *)this->direntp;
+#endif /* OS_DIRENT_CONVERT */
+
+ return (struct dirent *)osdirent;
+}
+
+int app_mkdir(const char *path)
+{
+ char realpath[MAX_PATH];
+ const char *fname = handle_special_dirs(path, NEED_WRITE, realpath,
+ sizeof (realpath));
+ if (!fname)
+ FILE_ERROR_RETURN(ENAMETOOLONG, -1);
+
+ return os_mkdir(fname __MKDIR_MODE_ARG);
+}
+
+int app_rmdir(const char *path)
+{
+ char realpath[MAX_PATH];
+ const char *fname = handle_special_dirs(path, NEED_WRITE, realpath,
+ sizeof (realpath));
+ if (!fname)
+ FILE_ERROR_RETURN(ENAMETOOLONG, -1);
+
+ return os_rmdir(fname);
+}
+
+int app_samedir(DIR *dirp1, DIR *dirp2)
+{
+ struct __dir *this1 = (struct __dir *)dirp1;
+ struct __dir *this2 = (struct __dir *)dirp2;
+
+ if (!this1 || !this2)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ return os_fsamefile(this1->osfd, this2->osfd);
+}
+
+bool app_dir_exists(const char *dirname)
+{
+ char realpath[MAX_PATH];
+ const char *fname = handle_special_dirs(dirname, 0, realpath,
+ sizeof (realpath));
+ if (!fname)
+ FILE_ERROR_RETURN(ENAMETOOLONG, false);
+
+ OS_DIR_T *osdirp = os_opendir(fname);
+ if (!osdirp)
+ return false;
+
+ os_closedir(osdirp);
+ return true;
+}
+
+struct dirinfo dir_get_info(DIR *dirp, struct dirent *entry)
+{
+ struct __dir *this = (struct __dir *)dirp;
+ struct dirinfo ret = { .mtime = 0 };
+
+ if (!this)
+ FILE_ERROR_RETURN(EBADF, ret);
+
+ if (!entry || entry->d_name[0] == '\0')
+ FILE_ERROR_RETURN(ENOENT, ret);
+
+ char path[MAX_PATH];
+
+#ifdef HAVE_MULTIDRIVE
+ if (this->volumes_returned < NUM_VOLUMES)
+ {
+ /* last thing read was a "symlink" */
+ ret.attribute = ATTR_LINK;
+ strcpy(path, MULTIDRIVE_DIR);
+ }
+ else
+#endif
+ if (path_append(path, this->path, entry->d_name, sizeof (path))
+ >= sizeof (path))
+ {
+ FILE_ERROR_RETURN(ENAMETOOLONG, ret);
+ }
+
+ struct stat s;
+ if (os_lstat(path, &s) < 0)
+ FILE_ERROR_RETURN(ERRNO, ret);
+
+ int err = 0;
+ if (S_ISLNK(s.st_mode))
+ {
+ ret.attribute |= ATTR_LINK;
+ err = os_stat(path, &s);
+ }
+
+ if (err < 0)
+ FILE_ERROR_RETURN(ERRNO, ret);
+
+ if (S_ISDIR(s.st_mode))
+ ret.attribute |= ATTR_DIRECTORY;
+
+ ret.size = s.st_size;
+
+ struct tm tm;
+ if (!localtime_r(&s.st_mtime, &tm))
+ FILE_ERROR_RETURN(ERRNO, ret);
+
+ ret.mtime = mktime(&tm);
+ return ret;
+}
+
+/* On MD we create a virtual symlink for the external drive,
+ * for this we need to override readlink(). */
+ssize_t app_readlink(const char *path, char *buf, size_t bufsiz)
+{
+ char _buf[MAX_PATH];
+ path = handle_special_dirs(path, 0, _buf, sizeof(_buf));
+#ifdef HAVE_MULTIDRIVE
+ /* if path == _buf then we can be sure handle_special_dir() did something
+ * and path is not an ordinary directory */
+ if (path == _buf && !strncmp(path, MULTIDRIVE_DIR, sizeof(MULTIDRIVE_DIR)-1))
+ {
+ /* copying NUL is not required as per readlink specification */
+ ssize_t len = strlen(path);
+ memcpy(buf, path, len);
+ return len;
+ }
+#endif
+ /* does not append NUL !! */
+ return os_readlink(path, buf, bufsiz);
+ (void) path; (void) buf; (void) bufsiz;
+}
+
+int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize)
+{
+#ifdef HAVE_MULTIVOLUME
+ char volname[VOL_MAX_LEN + 1];
+ get_volume_name(volume, volname);
+#else
+ const char *volname = "/";
+#endif
+
+ if (!handle_special_dirs(volname, NEED_WRITE, buffer, bufsize))
+ {
+ errno = ENAMETOOLONG;
+ return -1;
+ }
+
+ return 0;
+}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2014 by Michael Sevakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _FILESYSTEM_APP_H_
+#define _FILESYSTEM_APP_H_
+
+#if defined(PLUGIN) || defined(CODEC)
+/* Prevent often-problematic plugin namespace pollution */
+#define FILEFUNCTIONS_DECLARED
+#define FILEFUNCTIONS_DEFINED
+#define DIRFUNCTIONS_DECLARED
+#define DIRFUNCTIONS_DEFINED
+#define OSFUNCTIONS_DECLARED
+#endif /* PLUGIN || CODEC */
+
+/* flags for get_user_file_path() */
+/* whether you need write access to that file/dir, especially true
+ * for runtime generated files (config.cfg) */
+#define NEED_WRITE (1<<0)
+/* file or directory? */
+#define IS_FILE (1<<1)
+
+#ifndef OSFUNCTIONS_DECLARED
+#define FS_PREFIX(_x_) app_ ## _x_
+
+void paths_init(void);
+const char * handle_special_dirs(const char *dir, unsigned flags,
+ char *buf, const size_t bufsize);
+
+#endif /* !OSFUNCTIONS_DECLARED */
+#endif /* _FILESYSTEM_APP_H_ */
+
+#ifdef HAVE_SDL
+#include "filesystem-sdl.h"
+#endif /* HAVE_SDL */
+#ifdef WIN32
+#include "filesystem-win32.h"
+#else /* !WIN32 */
+#include "filesystem-unix.h"
+#endif /* WIN32 */
+#include "filesystem-hosted.h"
+
+#ifdef _FILE_H_
+#ifndef _FILESYSTEM_APP__FILE_H_
+#define _FILESYSTEM_APP__FILE_H_
+
+#ifdef RB_FILESYSTEM_OS
+#define FILEFUNCTIONS_DEFINED
+#endif
+
+#ifndef FILEFUNCTIONS_DECLARED
+int app_open(const char *name, int oflag, ...);
+int app_creat(const char *name, mode_t mode);
+#define app_close os_close
+#define app_ftruncate os_ftruncate
+#define app_fsync os_fsync
+#define app_lseek os_lseek
+#ifdef HAVE_SDL_THREADS
+ssize_t app_read(int fildes, void *buf, size_t nbyte);
+ssize_t app_write(int fildes, const void *buf, size_t nbyte);
+#else
+#define app_read os_read
+#define app_write os_write
+#endif /* HAVE_SDL_THREADS */
+int app_remove(const char *path);
+int app_rename(const char *old, const char *new);
+#define app_filesize os_filesize
+#define app_fsamefile os_fsamefile
+int app_relate(const char *path1, const char *path2);
+bool app_file_exists(const char *path);
+ssize_t app_readlink(const char *path, char *buf, size_t bufsize);
+#endif /* !FILEFUNCTIONS_DECLARED */
+
+#endif /* _FILESYSTEM_APP__FILE_H_ */
+#endif /* _FILE_H_ */
+
+#ifdef _DIR_H_
+#ifndef _FILESYSTEM_APP__DIR_H_
+#define _FILESYSTEM_APP__DIR_H_
+
+#ifdef RB_FILESYSTEM_OS
+#define DIRFUNCTIONS_DEFINED
+#endif
+
+#define DIRENT dirent
+#define DIRENT_DEFINED
+
+#ifndef DIRFUNCTIONS_DECLARED
+DIR * app_opendir(const char *dirname);
+struct dirent * app_readdir(DIR *dirp);
+int app_closedir(DIR *dirp);
+int app_mkdir(const char *path);
+int app_rmdir(const char *path);
+int app_samedir(DIR *dirp1, DIR *dirp2);
+bool app_dir_exists(const char *dirname);
+#endif /* DIRFUNCTIONS_DECLARED */
+
+#endif /* _FILESYSTEM_APP__DIR_H_ */
+#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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2014 by Michael Sevakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _FILESYSTEM_HOSTED_H_
+#define _FILESYSTEM_HOSTED_H_
+
+#include "mv.h"
+
+int os_volume_path(IF_MV(int volume, ) char *buffer, size_t bufsize);
+void * os_lc_open(const char *ospath);
+
+#endif /* _FILESYSTEM_HOSTED_H_ */
+
+#ifdef _FILE_H_
+#ifndef _FILESYSTEM_HOSTED__FILE_H_
+#define _FILESYSTEM_HOSTED__FILE_H_
+
+#ifndef OSFUNCTIONS_DECLARED
+off_t os_filesize(int osfd);
+int os_fsamefile(int osfd1, int osfd2);
+int os_relate(const char *path1, const char *path2);
+bool os_file_exists(const char *ospath);
+
+#define __OPEN_MODE_ARG \
+ , ({ \
+ mode_t mode = 0; \
+ if (oflag & O_CREAT) \
+ { \
+ va_list ap; \
+ va_start(ap, oflag); \
+ mode = va_arg(ap, unsigned int); \
+ va_end(ap); \
+ } \
+ mode; })
+
+#define __CREAT_MODE_ARG \
+ , mode
+
+#endif /* OSFUNCTIONS_DECLARED */
+
+#endif /* _FILESYSTEM_HOSTED__FILE_H_ */
+#endif /* _FILE_H_ */
+
+#ifdef _DIR_H_
+#ifndef _FILESYSTEM_HOSTED__DIR_H_
+#define _FILESYSTEM_HOSTED__DIR_H_
+
+#ifndef OSFUNCTIONS_DECLARED
+int os_opendir_and_fd(const char *osdirname, OS_DIR_T **osdirpp,
+ int *osfdp);
+
+#define __MKDIR_MODE_ARG \
+ , 0777
+#endif /* OSFUNCTIONS_DECLARED */
+
+#endif /* _FILESYSTEM_HOSTED__DIR_H_ */
+#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 @@
* KIND, either express or implied.
*
****************************************************************************/
+#define RB_FILESYSTEM_OS
+#include <sys/statfs.h> /* lowest common denominator */
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include "config.h"
+#include "system.h"
+#include "file.h"
+#include "dir.h"
+#include "mv.h"
+#include "debug.h"
+#include "pathfuncs.h"
+#include "string-extra.h"
-#include <sys/stat.h> /* stat() */
-#include "mv.h" /* stat() */
+#define SAME_FILE_INFO(sb1p, sb2p) \
+ ((sb1p)->st_dev == (sb2p)->st_dev && (sb1p)->st_ino == (sb2p)->st_ino)
-
-long filesize(int fd)
+off_t os_filesize(int osfd)
{
- struct stat buf;
+ struct stat sb;
- if (!fstat(fd, &buf))
- return buf.st_size;
+ if (!os_fstat(osfd, &sb))
+ return sb.st_size;
else
return -1;
}
-/* do we really need this in the app? */
-void fat_size(IF_MV(int volume,) unsigned long* size, unsigned long* free)
+int os_fsamefile(int osfd1, int osfd2)
+{
+ struct stat sb1, sb2;
+
+ if (os_fstat(osfd1, &sb1))
+ return -1;
+
+ if (os_fstat(osfd2, &sb2))
+ return -1;
+
+ return SAME_FILE_INFO(&sb1, &sb2);
+}
+
+int os_relate(const char *ospath1, const char *ospath2)
+{
+ DEBUGF("\"%s\" : \"%s\"\n", ospath1, ospath2);
+
+ if (!ospath2 || !*ospath2)
+ {
+ errno = ospath2 ? ENOENT : EFAULT;
+ return -1;
+ }
+
+ /* First file must stay open for duration so that its stats don't change */
+ int fd1 = os_open(ospath1, O_RDONLY);
+ if (fd1 < 0)
+ return -2;
+
+ struct stat sb1;
+ if (os_fstat(fd1, &sb1))
+ {
+ os_close(fd1);
+ return -3;
+ }
+
+ char path2buf[strlen(ospath2) + 1];
+ *path2buf = 0;
+
+ ssize_t len = 0;
+ const char *p = ospath2;
+ const char *sepmo = path_is_absolute(ospath2) ? PA_SEP_HARD : PA_SEP_SOFT;
+
+ int rc = RELATE_DIFFERENT;
+
+ while (1)
+ {
+ if (sepmo != PA_SEP_HARD &&
+ !(len = parse_path_component(&ospath2, &p)))
+ {
+ break;
+ }
+
+ char compname[len + 1];
+ strmemcpy(compname, p, len);
+
+ path_append(path2buf, sepmo, compname, sizeof (path2buf));
+ sepmo = PA_SEP_SOFT;
+
+ int errnum = errno; /* save and restore if not actually failing */
+ struct stat sb2;
+
+ if (!os_stat(path2buf, &sb2))
+ {
+ if (SAME_FILE_INFO(&sb1, &sb2))
+ {
+ rc = RELATE_SAME;
+ }
+ else if (rc == RELATE_SAME)
+ {
+ if (name_is_dot_dot(compname))
+ rc = RELATE_DIFFERENT;
+ else if (!name_is_dot(compname))
+ rc = RELATE_PREFIX;
+ }
+ }
+ else if (errno == ENOENT && !*GOBBLE_PATH_SEPCH(ospath2) &&
+ !name_is_dot_dot(compname))
+ {
+ if (rc == RELATE_SAME)
+ rc = RELATE_PREFIX;
+
+ errno = errnum;
+ break;
+ }
+ else
+ {
+ rc = -4;
+ break;
+ }
+ }
+
+ if (os_close(fd1) && rc >= 0)
+ rc = -5;
+
+ return rc;
+}
+
+bool os_file_exists(const char *ospath)
+{
+ int sim_fd = os_open(ospath, O_RDONLY, 0);
+ if (sim_fd < 0)
+ return false;
+
+ int errnum = errno;
+ os_close(sim_fd);
+ errno = errnum;
+
+ return true;
+}
+
+int os_opendirfd(const char *osdirname)
+{
+ return os_open(osdirname, O_RDONLY);
+}
+
+int os_opendir_and_fd(const char *osdirname, DIR **osdirpp, int *osfdp)
+{
+ /* another possible way is to use open() then fdopendir() */
+ *osdirpp = NULL;
+ *osfdp = -1;
+
+ DIR *dirp = os_opendir(osdirname);
+ if (!dirp)
+ return -1;
+
+ int rc = 0;
+ int errnum = errno;
+
+ int fd = os_dirfd(dirp);
+ if (fd < 0)
+ {
+ fd = os_opendirfd(osdirname);
+ rc = 1;
+ }
+
+ if (fd < 0)
+ {
+ os_closedir(dirp);
+ return -2;
+ }
+
+ errno = errnum;
+
+ *osdirpp = dirp;
+ *osfdp = fd;
+
+ return rc;
+}
+
+/* do we really need this in the app? (in the sim, yes) */
+void volume_size(IF_MV(int volume,) unsigned long *sizep, unsigned long *freep)
{
- IF_MV((void) volume);
- *size = *free = 0;
+ unsigned long size = 0, free = 0;
+ char volpath[MAX_PATH];
+ struct statfs fs;
+
+ if (os_volume_path(IF_MV(volume,) volpath, sizeof (volpath)) >= 0
+ && !statfs(volpath, &fs))
+ {
+ DEBUGF("statvfs: frsize=%d blocks=%ld bfree=%ld\n",
+ (int)fs.f_frsize, (long)fs.f_blocks, (long)fs.f_bfree);
+ if (sizep)
+ size = (fs.f_blocks / 2) * (fs.f_frsize / 512);
+
+ if (freep)
+ free = (fs.f_bfree / 2) * (fs.f_frsize / 512);
+ }
+
+ if (sizep)
+ *sizep = size;
+
+ if (freep)
+ *freep = free;
}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2014 by Michael Sevakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _FILESYSTEM_UNIX_H_
+#define _FILESYSTEM_UNIX_H_
+
+/* Include for file.h and dir.h because mkdir and friends may be here */
+#include <sys/stat.h>
+
+#define strlcpy_from_os strlcpy
+#endif
+
+#ifdef _FILE_H_
+#ifndef _FILESYSTEM_UNIX__FILE_H_
+#define _FILESYSTEM_UNIX__FILE_H_
+
+#include <unistd.h>
+
+#define OS_STAT_T struct stat
+
+#ifndef OSFUNCTIONS_DECLARED
+#define os_open open
+#define os_creat creat
+#define os_close close
+#define os_lseek lseek
+#define os_stat stat
+#define os_fstat fstat
+#define os_fstatat fstatat
+#define os_lstat lstat
+#define os_fsync fsync
+#define os_ftruncate ftruncate
+#define os_remove remove
+#define os_rename rename
+#define os_readlink readlink
+#ifndef os_read
+#define os_read read
+#endif
+#ifndef os_write
+#define os_write write
+#endif
+#endif /* !OSFUNCTIONS_DECLARED */
+
+#endif /* _FILESYSTEM_UNIX__FILE_H_ */
+#endif /* _FILE_H_ */
+
+#ifdef _DIR_H_
+#ifndef _FILESYSTEM_UNIX__DIR_H_
+#define _FILESYSTEM_UNIX__DIR_H_
+
+#include <dirent.h>
+
+#define OS_DIR_T DIR
+#define OS_DIRENT_T struct dirent
+
+#ifndef OSFUNCTIONS_DECLARED
+#define os_opendir opendir
+#define os_readdir readdir
+#define os_closedir closedir
+#define os_mkdir mkdir
+#define os_rmdir rmdir
+#define os_dirfd dirfd /* NOTE: might have to wrap on some platforms */
+#endif /* !OSFUNCTIONS_DECLARED */
+
+#endif /* _FILESYSTEM_UNIX__DIR_H_ */
+#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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2014 by Michael Sevakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#define RB_FILESYSTEM_OS
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "config.h"
+#include "system.h"
+#include "file.h"
+#include "dir.h"
+#include "debug.h"
+#include "pathfuncs.h"
+#include "string-extra.h"
+
+#define SAME_FILE_INFO(lpInfo1, lpInfo2) \
+ ((lpInfo1)->dwVolumeSerialNumber == (lpInfo2)->dwVolumeSerialNumber && \
+ (lpInfo1)->nFileIndexHigh == (lpInfo2)->nFileIndexHigh && \
+ (lpInfo1)->nFileIndexLow == (lpInfo2)->nFileIndexLow)
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+static void win32_last_error_errno(void)
+{
+ switch (GetLastError())
+ {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ errno = ENOENT;
+ break;
+ case ERROR_DIR_NOT_EMPTY:
+ errno = ENOTEMPTY;
+ break;
+ default:
+ errno = EIO;
+ }
+}
+
+#ifdef __MINGW32__
+#include <wchar.h>
+#include "rbunicode.h"
+
+static HANDLE win32_open(const char *ospath);
+static int win32_stat(const char *ospath, LPBY_HANDLE_FILE_INFORMATION lpInfo);
+
+unsigned short * strcpy_utf8ucs2(unsigned short *buffer,
+ const unsigned char *utf8)
+{
+ for (wchar_t *ucs2 = buffer;
+ ((utf8 = utf8decode(utf8, ucs2)), *ucs2); ucs2++);
+ return buffer;
+}
+
+#if 0
+unsigned char * strcpy_ucs2utf8(unsigned char *buffer,
+ const unsigned short *ucs2)
+{
+ for (unsigned char *utf8 = buffer;
+ ((utf8 = utf8encode(*ucs2, utf8)), *ucs2); ucs2++);
+ return buffer;
+}
+
+size_t strlen_utf8ucs2(const unsigned char *utf8)
+{
+ /* This won't properly count multiword ucs2 so use the alternative
+ below for now which doesn't either */
+ size_t length = 0;
+ unsigned short ucschar[2];
+ for (unsigned char c = *utf8; c;
+ ((utf8 = utf8decode(utf8, ucschar)), c = *utf8))
+ length++;
+
+ return length;
+}
+#endif /* 0 */
+
+size_t strlen_utf8ucs2(const unsigned char *utf8)
+{
+ return utf8length(utf8);
+}
+
+size_t strlen_ucs2utf8(const unsigned short *ucs2)
+{
+ size_t length = 0;
+ unsigned char utf8char[4];
+
+ for (unsigned short c = *ucs2; c; (c = *++ucs2))
+ length += utf8encode(c, utf8char) - utf8char;
+
+ return length;
+}
+
+size_t strlcpy_ucs2utf8(char *buffer, const unsigned short *ucs2,
+ size_t bufsize)
+{
+ if (!buffer)
+ bufsize = 0;
+
+ size_t length = 0;
+ unsigned char utf8char[4];
+
+ for (unsigned short c = *ucs2; c; (c = *++ucs2))
+ {
+ /* If the last character won't fit, this won't split it */
+ size_t utf8size = utf8encode(c, utf8char) - utf8char;
+ if ((length += utf8size) < bufsize)
+ buffer = mempcpy(buffer, utf8char, utf8size);
+ }
+
+ /* Above won't ever copy to very end */
+ if (bufsize)
+ *buffer = '\0';
+
+ return length;
+}
+
+#define _toucs2(utf8) \
+ ({ const char *_utf8 = (utf8); \
+ size_t _l = strlen_utf8ucs2(_utf8); \
+ void *_buffer = alloca((_l + 1)*2); \
+ strcpy_utf8ucs2(_buffer, _utf8); })
+
+#define _toutf8(ucs2) \
+ ({ const char *_ucs2 = (ucs2); \
+ size_t _l = strlen_ucs2utf8(_ucs2); \
+ void *_buffer = alloca(_l + 1); \
+ strcpy_ucs2utf8(_buffer, _ucs2); })
+
+int os_open(const char *ospath, int oflag, ...)
+{
+ return _wopen(_toucs2(ospath), oflag __OPEN_MODE_ARG);
+}
+
+int os_creat(const char *ospath, mode_t mode)
+{
+ return _wcreat(_toucs2(ospath), mode);
+}
+
+int os_stat(const char *ospath, struct _stat *s)
+{
+ return _wstat(_toucs2(ospath), s);
+}
+
+int os_remove(const char *ospath)
+{
+ return _wremove(_toucs2(ospath));
+}
+
+int os_rename(const char *osold, const char *osnew)
+{
+ int errnum = errno;
+
+ const wchar_t *wchosold = _toucs2(osold);
+ const wchar_t *wchosnew = _toucs2(osnew);
+
+ int rc = _wrename(wchosold, wchosnew);
+ if (rc < 0 && errno == EEXIST)
+ {
+ /* That didn't work; do cheap POSIX mimic */
+ BY_HANDLE_FILE_INFORMATION info;
+ if (win32_stat(osold, &info))
+ return -1;
+
+ if ((info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
+ !RemoveDirectoryW(wchosnew))
+ {
+ win32_last_error_errno();
+ return -1;
+ }
+
+ if (MoveFileExW(wchosold, wchosnew, MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_WRITE_THROUGH))
+ {
+ errno = errnum;
+ return 0;
+ }
+
+ errno = EIO;
+ }
+
+ return rc;
+}
+
+bool os_file_exists(const char *ospath)
+{
+ HANDLE h = win32_open(ospath);
+ if (h == INVALID_HANDLE_VALUE)
+ return false;
+
+ CloseHandle(h);
+ return true;
+}
+
+_WDIR * os_opendir(const char *osdirname)
+{
+ return _wopendir(_toucs2(osdirname));
+}
+
+int os_mkdir(const char *ospath, mode_t mode)
+{
+ return _wmkdir(_toucs2(ospath));
+ (void)mode;
+}
+
+int os_rmdir(const char *ospath)
+{
+ return _wrmdir(_toucs2(ospath));
+}
+
+int os_dirfd(_WDIR *osdirp)
+{
+#ifdef ENOTSUP
+ errno = ENOTSUP
+#else
+ errno = ENOSYS;
+#endif
+ return -1;
+ (void)osdirp;
+}
+
+int os_opendirfd(const char *osdirname)
+{
+ HANDLE h = win32_open(osdirname);
+ if (h == INVALID_HANDLE_VALUE)
+ return -1;
+
+ BY_HANDLE_FILE_INFORMATION info;
+ if (!GetFileInformationByHandle(h, &info))
+ errno = EIO;
+ else if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+ errno = ENOTDIR;
+ else
+ {
+ /* Convert OS handle to fd; the fd now owns it */
+ int osfd = _open_osfhandle((long)h, O_RDONLY);
+ if (osfd >= 0)
+ return osfd;
+ }
+
+ CloseHandle(h);
+ return -2;
+}
+#endif /* __MINGW32__ */
+
+static size_t win32_path_strip_root(const char *ospath)
+{
+ const char *p = ospath;
+ int c = toupper(*p);
+
+ if (c >= 'A' && c <= 'Z')
+ {
+ /* drive */
+ if ((c = *++p) == ':')
+ return 2;
+ }
+
+ if (c == '\\' && *++p == '\\')
+ {
+ /* UNC */
+ while ((c = *++p) && c != '/' && c != '\\');
+ return p - ospath;
+ }
+
+ return 0;
+}
+
+static HANDLE win32_open(const char *ospath)
+{
+ /* FILE_FLAG_BACKUP_SEMANTICS is required for this to succeed at opening
+ a directory */
+ HANDLE h = CreateFileW(_toucs2(ospath), GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE |
+ FILE_SHARE_DELETE, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+
+ if (h == INVALID_HANDLE_VALUE)
+ win32_last_error_errno();
+
+ return h;
+}
+
+static int win32_fstat(int osfd, HANDLE hFile,
+ LPBY_HANDLE_FILE_INFORMATION lpInfo)
+{
+ /* The file descriptor takes precedence over the win32 file handle */
+ if (osfd >= 0)
+ hFile = (HANDLE)_get_osfhandle(osfd);
+
+ int rc = GetFileInformationByHandle(hFile, lpInfo) ? 0 : -1;
+ if (rc < 0)
+ win32_last_error_errno();
+
+ return rc;
+}
+
+static int win32_stat(const char *ospath, LPBY_HANDLE_FILE_INFORMATION lpInfo)
+{
+ HANDLE h = win32_open(ospath);
+ if (h == INVALID_HANDLE_VALUE)
+ return -1;
+
+ int rc = win32_fstat(-1, h, lpInfo);
+
+ CloseHandle(h);
+
+ return rc;
+}
+
+int os_opendir_and_fd(const char *osdirname, _WDIR **osdirpp,
+ int *osfdp)
+{
+ /* another possible way is to use open() then fdopendir() */
+ *osdirpp = NULL;
+ *osfdp = -1;
+
+ _WDIR *dirp = os_opendir(osdirname);
+ if (!dirp)
+ return -1;
+
+ int rc = 0;
+ int errnum = errno;
+
+ int fd = os_dirfd(dirp);
+ if (fd < 0)
+ {
+ fd = os_opendirfd(osdirname);
+ rc = 1;
+ }
+
+ if (fd < 0)
+ {
+ os_closedir(dirp);
+ return -2;
+ }
+
+ errno = errnum;
+
+ *osdirpp = dirp;
+ *osfdp = fd;
+
+ return rc;
+}
+
+int os_fsamefile(int osfd1, int osfd2)
+{
+ BY_HANDLE_FILE_INFORMATION info1, info2;
+
+ if (!win32_fstat(osfd1, INVALID_HANDLE_VALUE, &info1) ||
+ !win32_fstat(osfd2, INVALID_HANDLE_VALUE, &info2))
+ return -1;
+
+ return SAME_FILE_INFO(&info1, &info2) ? 1 : 0;
+}
+
+int os_relate(const char *ospath1, const char *ospath2)
+{
+ DEBUGF("\"%s\" : \"%s\"\n", ospath1, ospath2);
+
+ if (!ospath2 || !*ospath2)
+ {
+ errno = ospath2 ? ENOENT : EFAULT;
+ return -1;
+ }
+
+ /* First file must stay open for duration so that its stats don't change */
+ HANDLE h1 = win32_open(ospath1);
+ if (h1 == INVALID_HANDLE_VALUE)
+ return -2;
+
+ BY_HANDLE_FILE_INFORMATION info1;
+ if (win32_fstat(-1, h1, &info1))
+ {
+ CloseHandle(h1);
+ return -3;
+ }
+
+ char path2buf[strlen(ospath2) + 1];
+ *path2buf = 0;
+
+ ssize_t len = 0;
+ const char *p = ospath2;
+ size_t rootlen = win32_path_strip_root(ospath2);
+ const char *sepmo = PA_SEP_SOFT;
+
+ if (rootlen)
+ {
+ strmemcpy(path2buf, ospath2, rootlen);
+ ospath2 += rootlen;
+ sepmo = PA_SEP_HARD;
+ }
+
+ int rc = RELATE_DIFFERENT;
+
+ while (1)
+ {
+ if (sepmo != PA_SEP_HARD &&
+ !(len = parse_path_component(&ospath2, &p)))
+ {
+ break;
+ }
+
+ char compname[len + 1];
+ strmemcpy(compname, p, len);
+
+ path_append(path2buf, sepmo, compname, sizeof (path2buf));
+ sepmo = PA_SEP_SOFT;
+
+ int errnum = errno; /* save and restore if not actually failing */
+ BY_HANDLE_FILE_INFORMATION info2;
+
+ if (!win32_stat(path2buf, &info2))
+ {
+ if (SAME_FILE_INFO(&info1, &info2))
+ {
+ rc = RELATE_SAME;
+ }
+ else if (rc == RELATE_SAME)
+ {
+ if (name_is_dot_dot(compname))
+ rc = RELATE_DIFFERENT;
+ else if (!name_is_dot(compname))
+ rc = RELATE_PREFIX;
+ }
+ }
+ else if (errno == ENOENT && !*GOBBLE_PATH_SEPCH(ospath2) &&
+ !name_is_dot_dot(compname))
+ {
+ if (rc == RELATE_SAME)
+ rc = RELATE_PREFIX;
+
+ errno = errnum;
+ break;
+ }
+ else
+ {
+ rc = -4;
+ break;
+ }
+ }
+
+ CloseHandle(h1);
+
+ return rc;
+}
+
+void volume_size(IF_MV(int volume,) unsigned long *sizep, unsigned long *freep)
+{
+ ULARGE_INTEGER free = { .QuadPart = 0 },
+ size = { .QuadPart = 0 };
+
+ char volpath[MAX_PATH];
+ if (os_volume_path(IF_MV(volume, ) volpath, sizeof (volpath)) >= 0)
+ GetDiskFreeSpaceExW(_toucs2(volpath), &free, &size, NULL);
+
+ if (sizep)
+ *sizep = size.QuadPart / 1024;
+
+ if (freep)
+ *freep = free.QuadPart / 1024;
+}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2014 by Michael Sevakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _FILESYSTEM_WIN32_H_
+#define _FILESYSTEM_WIN32_H_
+
+#ifndef OSFUNCTIONS_DECLARED
+
+#ifdef __MINGW32__
+/* filesystem-win32.c contains some string functions that could be useful
+ * elsewhere; just move them away to unicode.c or something if they prove
+ * so. */
+size_t strlcpy_ucs2utf8(char *buffer, const unsigned short *ucs,
+ size_t bufsize);
+
+#define strlcpy_from_os strlcpy_ucs2utf8
+#endif /* __MINGW32__ */
+
+#endif /* !OSFUNCTIONS_DECLARED */
+
+#endif /* _FILESYSTEM_WIN32_H_ */
+
+#ifdef __MINGW32__
+
+#ifdef _FILE_H_
+#ifndef _FILESYSTEM_WIN32__FILE_H_
+#define _FILESYSTEM_WIN32__FILE_H_
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+#define OS_STAT_T struct _stat
+
+#ifndef OSFUNCTIONS_DECLARED
+/* Wrap for off_t <=> long conversions */
+static inline off_t os_filesize_(int osfd)
+ { return _filelength(osfd); }
+static inline int os_ftruncate_(int osfd, off_t length)
+ { return _chsize(osfd, length); }
+
+#define os_filesize os_filesize_
+#define os_ftruncate os_ftruncate_
+#define os_fsync _commit
+#define os_fstat _fstat
+#define os_close close
+#define os_lseek lseek
+#ifndef os_read
+#define os_read read
+#endif
+#ifndef os_write
+#define os_write write
+#endif
+
+/* These need string type conversion from utf8 to ucs2; that's done inside */
+int os_open(const char *ospath, int oflag, ...);
+int os_creat(const char *ospath, mode_t mode);
+int os_stat(const char *ospath, struct _stat *s);
+int os_remove(const char *ospath);
+int os_rename(const char *osold, const char *osnew);
+
+#endif /* !OSFUNCTIONS_DECLARED */
+
+#endif /* _FILESYSTEM_WIN32__FILE_H_ */
+#endif /* _FILE_H_ */
+
+#ifdef _DIR_H_
+#ifndef _FILESYSTEM_WIN32__DIR_H_
+#define _FILESYSTEM_WIN32__DIR_H_
+
+#include <dirent.h>
+
+#define OS_DIRENT_CONVERT /* needs string conversion */
+#define OS_DIR_T _WDIR
+#define OS_DIRENT_T struct _wdirent
+
+#ifndef OSFUNCTIONS_DECLARED
+
+_WDIR * os_opendir(const char *osdirname);
+int os_opendirfd(const char *osdirname);
+#define os_readdir _wreaddir
+#define os_closedir _wclosedir
+int os_mkdir(const char *ospath, mode_t mode);
+int os_rmdir(const char *ospath);
+
+#endif /* OSFUNCTIONS_DECLARED */
+
+#endif /* _FILESYSTEM_WIN32__DIR_H_ */
+#endif /* _DIR_H_ */
+
+#else /* !__MINGW32__ */
+
+#include "filesystem-unix.h"
+
+#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)
{
dlclose(handle);
}
-
-void *lc_open_from_mem(void *addr, size_t blob_size)
-{
- (void)addr;
- (void)blob_size;
- /* we don't support loading code from memory on application builds,
- * it doesn't make sense (since it means writing the blob to disk again and
- * then falling back to load from disk) and requires the ability to write
- * to an executable directory */
- return NULL;
-}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2010 Thomas Martitz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#define RB_FILESYSTEM_OS
+#include "system.h"
+#include "file.h"
+#include "load_code.h"
+
+void *lc_open(const char *filename, unsigned char *buf, size_t buf_size)
+{
+ char realpath[MAX_PATH];
+ const char *fpath = handle_special_dirs(filename, 0, realpath,
+ sizeof (realpath));
+ if (!fpath)
+ return NULL;
+
+ return os_lc_open(fpath);
+ (void)buf; (void)buf_size;
+}
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2014 by Michael Sevakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#define RB_FILESYSTEM_OS
+#include "config.h"
+#include "system.h"
+#include "thread-sdl.h"
+#include "mutex.h"
+#include "file.h"
+
+#ifdef HAVE_SDL_THREADS
+#define YIELD_THRESHOLD 512
+static bool initialized = false;
+static struct mutex readwrite_mtx;
+
+/* Allow other threads to run while performing I/O */
+ssize_t os_sdl_readwrite(int osfd, void *buf, size_t nbyte, bool dowrite)
+{
+ if (!initialized)
+ {
+ mutex_init(&readwrite_mtx);
+ initialized = true;
+ }
+
+ mutex_lock(&readwrite_mtx);
+
+ void *mythread = nbyte > YIELD_THRESHOLD ? sim_thread_unlock() : NULL;
+
+ ssize_t rc = dowrite ? write(osfd, buf, nbyte) : read(osfd, buf, nbyte);
+
+ if (mythread)
+ sim_thread_lock(mythread);
+
+ mutex_unlock(&readwrite_mtx);
+ return rc;
+}
+
+#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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2014 by Michael Sevakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _FILESYSTEM_SDL_H_
+#define _FILESYSTEM_SDL_H_
+
+#ifdef HAVE_SDL_THREADS
+#undef os_read
+#undef os_write
+
+ssize_t os_sdl_readwrite(int osfd, void *buf, size_t nbyte, bool dowrite);
+
+#define os_read(osfd, buf, nbyte) \
+ os_sdl_readwrite((osfd), (buf), (nbyte), false)
+#define os_write(osfd, buf, nbyte) \
+ os_sdl_readwrite((osfd), (void *)(buf), (nbyte), true)
+
+#endif /* HAVE_SDL_THREADS */
+
+#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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2002 Daniel Stenberg
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#define RB_FILESYSTEM_OS
+#include <SDL_loadso.h>
+#include "system.h"
+#include "load_code.h"
+#include "filesystem-sdl.h"
+#include "debug.h"
+
+void * os_lc_open(const char *ospath)
+{
+ void *handle = SDL_LoadObject(ospath);
+ if (handle == NULL)
+ {
+ DEBUGF("%s(\"%s\") failed\n", __func__, ospath);
+ DEBUGF(" SDL error '%s'\n", SDL_GetError());
+ }
+
+ return handle;
+}
+
+void * lc_get_header(void *handle)
+{
+ char *ret = SDL_LoadFunction(handle, "__header");
+ if (ret == NULL)
+ ret = SDL_LoadFunction(handle, "___header");
+
+ return ret;
+}
+
+void lc_close(void *handle)
+{
+ SDL_UnloadObject(handle);
+}
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 @@
#endif
+#define SIMULATOR_DEFAULT_ROOT "simdisk"
+
SDL_Surface *gui_surface;
bool background = true; /* use backgrounds by default */
@@ -63,7 +65,7 @@ bool debug_buttons = false;
bool lcd_display_redraw = true; /* Used for player simulator */
char having_new_lcd = true; /* Used for player simulator */
bool sim_alarm_wakeup = false;
-const char *sim_root_dir = NULL;
+const char *sim_root_dir = SIMULATOR_DEFAULT_ROOT;
static SDL_Thread *evt_thread = NULL;
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 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2014 by Michael Sevakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _SYSTEM_SIM_H_
+#define _SYSTEM_SIM_H_
+
+#ifdef WIN32
+#include <time.h>
+struct tm * localtime_r(const time_t *restrict timer,
+ struct tm *restrict result);
+struct tm * gmtime_r(const time_t *restrict timer,
+ struct tm *restrict result);
+#endif /* WIN32 */
+
+#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 @@
#include "ata_idle_notify.h"
#include "ata-sd-target.h"
#include "disk.h"
-#include "fat.h"
#include "led.h"
#include "sdmmc.h"
#include "logf.h"
@@ -1467,34 +1466,28 @@ static void sd_thread(void)
{
#ifdef HAVE_HOTSWAP
case SYS_HOTSWAP_INSERTED:
- case SYS_HOTSWAP_EXTRACTED:
- fat_lock(); /* lock-out FAT activity first -
- prevent deadlocking via disk_mount that
- would cause a reverse-order attempt with
- another thread */
- mutex_lock(&sd_mtx); /* lock-out card activity - direct calls
- into driver that bypass the fat cache */
+ case SYS_HOTSWAP_EXTRACTED:;
+ int success = 1;
- /* We now have exclusive control of fat cache and ata */
+ disk_unmount(sd_drive_nr); /* release "by force" */
- disk_unmount(sd_drive_nr); /* release "by force", ensure file
- descriptors aren't leaked and any busy
- ones are invalid if mounting */
+ mutex_lock(&sd_mtx); /* lock-out card activity */
/* Force card init for new card, re-init for re-inserted one or
* clear if the last attempt to init failed with an error. */
card.initialized = 0;
+ mutex_unlock(&sd_mtx);
+
if(ev.id == SYS_HOTSWAP_INSERTED)
- disk_mount(sd_drive_nr);
+ success = disk_mount(sd_drive_nr); /* 0 if fail */
- queue_broadcast(SYS_FS_CHANGED, 0);
+ if(success)
+ queue_broadcast(SYS_FS_CHANGED, 0);
- /* Access is now safe */
- mutex_unlock(&sd_mtx);
- fat_unlock();
break;
-#endif
+#endif /* HAVE_HOTSWAP */
+
case SYS_TIMEOUT:
if (TIME_BEFORE(current_tick, last_disk_activity+(3*HZ)))
idle_notified = false;