summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/bookmark.c8
-rw-r--r--apps/codecs.c2
-rw-r--r--apps/debug_menu.c86
-rw-r--r--apps/filetree.c4
-rw-r--r--apps/main.c102
-rw-r--r--apps/menus/display_menu.c20
-rw-r--r--apps/menus/main_menu.c18
-rw-r--r--apps/menus/settings_menu.c6
-rw-r--r--apps/misc.c16
-rw-r--r--apps/onplay.c844
-rwxr-xr-xapps/playlist.c237
-rw-r--r--apps/playlist_catalog.c2
-rw-r--r--apps/plugin.c264
-rw-r--r--apps/plugin.h45
-rw-r--r--apps/plugins/properties.c14
-rw-r--r--apps/radio/presets.c2
-rw-r--r--apps/radio/radioart.c2
-rw-r--r--apps/recorder/albumart.c2
-rw-r--r--apps/recorder/recording.c2
-rw-r--r--apps/root_menu.c5
-rw-r--r--apps/scrobbler.c2
-rw-r--r--apps/settings.c8
-rw-r--r--apps/settings_list.c6
-rw-r--r--apps/shortcuts.c2
-rw-r--r--apps/tagcache.c21
-rw-r--r--apps/tree.c55
26 files changed, 964 insertions, 811 deletions
diff --git a/apps/bookmark.c b/apps/bookmark.c
index 3234e77d9b..567f98ac29 100644
--- a/apps/bookmark.c
+++ b/apps/bookmark.c
@@ -41,7 +41,7 @@
#include "list.h"
#include "plugin.h"
#include "file.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#define MAX_BOOKMARKS 10
#define MAX_BOOKMARK_SIZE 350
@@ -1090,10 +1090,10 @@ static bool generate_bookmark_file_name(const char *in)
{
#ifdef HAVE_MULTIVOLUME
/* The "root" of an extra volume need special handling too. */
- bool volume_root = (strip_volume(in, global_bookmark_file_name) &&
- !strcmp("/", global_bookmark_file_name));
+ const char *filename;
+ path_strip_volume(in, &filename, true);
+ bool volume_root = *filename == '\0';
#endif
-
strcpy(global_bookmark_file_name, in);
if(global_bookmark_file_name[len-1] == '/')
len--;
diff --git a/apps/codecs.c b/apps/codecs.c
index e84cdf88aa..cabc9ba993 100644
--- a/apps/codecs.c
+++ b/apps/codecs.c
@@ -128,7 +128,7 @@ struct codec_api ci = {
logf,
#endif
- (qsort_func)qsort,
+ (void *)qsort,
#ifdef RB_PROFILE
profile_thread,
diff --git a/apps/debug_menu.c b/apps/debug_menu.c
index 61698f5025..75e23b3945 100644
--- a/apps/debug_menu.c
+++ b/apps/debug_menu.c
@@ -528,14 +528,19 @@ static const char* dbg_partitions_getname(int selected_item, void *data,
{
(void)data;
int partition = selected_item/2;
- struct partinfo* p = disk_partinfo(partition);
+
+ struct partinfo p;
+ if (!disk_partinfo(partition, &p))
+ return buffer;
+
if (selected_item%2)
{
- snprintf(buffer, buffer_len, " T:%x %ld MB", p->type, p->size / ( 2048 / ( SECTOR_SIZE / 512 )));
+ snprintf(buffer, buffer_len, " T:%x %ld MB", p.type,
+ p.size / ( 2048 / ( SECTOR_SIZE / 512 )));
}
else
{
- snprintf(buffer, buffer_len, "P%d: S:%lx", partition, p->start);
+ snprintf(buffer, buffer_len, "P%d: S:%lx", partition, p.start);
}
return buffer;
}
@@ -1377,7 +1382,7 @@ static int disk_callback(int btn, struct gui_synclist *lists)
simplelist_addline(
"Size: %s", buf);
unsigned long free;
- fat_size( IF_MV(0,) NULL, &free );
+ volume_size( IF_MV(0,) NULL, &free );
simplelist_addline(
"Free: %ld MB", free / 1024);
simplelist_addline(
@@ -1469,7 +1474,7 @@ static int disk_callback(int btn, struct gui_synclist *lists)
"No timing info");
}
simplelist_addline(
- "Cluster size: %d bytes", fat_get_cluster_size(IF_MV(0)));
+ "Cluster size: %d bytes", volume_get_cluster_size(IF_MV(0)));
#ifdef HAVE_ATA_DMA
i = ata_get_dma_mode();
if (i == 0) {
@@ -1496,11 +1501,11 @@ static int disk_callback(int btn, struct gui_synclist *lists)
simplelist_addline(
"Size: %ld MB", info.num_sectors*(info.sector_size/512)/2024);
unsigned long free;
- fat_size( IF_MV(0,) NULL, &free );
+ volume_size( IF_MV(0,) NULL, &free );
simplelist_addline(
"Free: %ld MB", free / 1024);
simplelist_addline(
- "Cluster size: %d bytes", fat_get_cluster_size(IF_MV(0)));
+ "Cluster size: %d bytes", volume_get_cluster_size(IF_MV(0)));
return btn;
}
#endif
@@ -1542,29 +1547,64 @@ static bool dbg_disk_info(void)
#ifdef HAVE_DIRCACHE
static int dircache_callback(int btn, struct gui_synclist *lists)
{
- (void)lists;
+ struct dircache_info info;
+ dircache_get_info(&info);
+
+ if (global_settings.dircache)
+ {
+ switch (btn)
+ {
+ case ACTION_STD_CONTEXT:
+ splash(HZ/2, "Rebuilding cache");
+ dircache_suspend();
+ *(int *)lists->data = dircache_resume();
+ case ACTION_UNKNOWN:
+ btn = ACTION_NONE;
+ break;
+ #ifdef DIRCACHE_DUMPSTER
+ case ACTION_STD_OK:
+ splash(0, "Dumping cache");
+ dircache_dump();
+ btn = ACTION_NONE;
+ break;
+ #endif /* DIRCACHE_DUMPSTER */
+ case ACTION_STD_CANCEL:
+ if (*(int *)lists->data > 0 && info.status == DIRCACHE_SCANNING)
+ {
+ splash(HZ, str(LANG_SCANNING_DISK));
+ btn = ACTION_NONE;
+ }
+ break;
+ }
+ }
+
simplelist_set_line_count(0);
- simplelist_addline("Cache initialized: %s",
- dircache_is_enabled() ? "Yes" : "No");
- simplelist_addline("Cache size: %d B",
- dircache_get_cache_size());
- simplelist_addline("Last size: %d B",
- global_status.dircache_size);
- simplelist_addline("Limit: %d B",
- DIRCACHE_LIMIT);
- simplelist_addline("Reserve: %d/%d B",
- dircache_get_reserve_used(), DIRCACHE_RESERVE);
- simplelist_addline("Scanning took: %d s",
- dircache_get_build_ticks() / HZ);
- simplelist_addline("Entry count: %d",
- dircache_get_entry_count());
+
+ simplelist_addline("Cache status: %s", info.statusdesc);
+ simplelist_addline("Last size: %lu B", info.last_size);
+ simplelist_addline("Size: %lu B", info.size);
+ unsigned int utilized = info.size ? 1000ull*info.sizeused / info.size : 0;
+ simplelist_addline("Used: %lu B (%u.%u%%)", info.sizeused,
+ utilized / 10, utilized % 10);
+ simplelist_addline("Limit: %lu B", info.size_limit);
+ simplelist_addline("Reserve: %lu/%lu B", info.reserve_used, info.reserve);
+ long ticks = ALIGN_UP(info.build_ticks, HZ / 10);
+ simplelist_addline("Scanning took: %ld.%ld s",
+ ticks / HZ, (ticks*10 / HZ) % 10);
+ simplelist_addline("Entry count: %u", info.entry_count);
+
+ if (btn == ACTION_NONE)
+ btn = ACTION_REDRAW;
+
return btn;
+ (void)lists;
}
static bool dbg_dircache_info(void)
{
struct simplelist_info info;
- simplelist_info_init(&info, "Dircache Info", 7, NULL);
+ int syncbuild = 0;
+ simplelist_info_init(&info, "Dircache Info", 8, &syncbuild);
info.action_callback = dircache_callback;
info.hide_selection = true;
info.scroll_all = true;
diff --git a/apps/filetree.c b/apps/filetree.c
index 319b5f4a77..64283b274b 100644
--- a/apps/filetree.c
+++ b/apps/filetree.c
@@ -376,9 +376,7 @@ int ft_load(struct tree_context* c, const char* tempdir)
++files_in_dir;
dptr->name = core_get_data(c->cache.name_buffer_handle)+name_buffer_used;
- dptr->time_write =
- (long)info.wrtdate<<16 |
- (long)info.wrttime; /* in one # */
+ dptr->time_write = info.mtime;
strcpy(dptr->name, (char *)entry->d_name);
name_buffer_used += len + 1;
diff --git a/apps/main.c b/apps/main.c
index 6c6f0d6aba..9098180fb8 100644
--- a/apps/main.c
+++ b/apps/main.c
@@ -19,11 +19,12 @@
*
****************************************************************************/
#include "config.h"
+#include "system.h"
#include "gcc_extensions.h"
#include "storage.h"
#include "disk.h"
-#include "fat.h"
+#include "file_internal.h"
#include "lcd.h"
#include "rtc.h"
#include "debug.h"
@@ -34,7 +35,6 @@
#include "filetypes.h"
#include "panic.h"
#include "menu.h"
-#include "system.h"
#include "usb.h"
#include "powermgmt.h"
#include "adc.h"
@@ -203,80 +203,53 @@ int main(void)
root_menu();
}
-static int init_dircache(bool preinit) INIT_ATTR;
-static int init_dircache(bool preinit)
-{
#ifdef HAVE_DIRCACHE
- int result = 0;
- bool clear = false;
-
+static int INIT_ATTR init_dircache(bool preinit)
+{
if (preinit)
- dircache_init();
+ dircache_init(MAX(global_status.dircache_size, 0));
if (!global_settings.dircache)
- return 0;
+ return -1;
+
+ int result = -1;
-# ifdef HAVE_EEPROM_SETTINGS
- if (firmware_settings.initialized && firmware_settings.disk_clean
- && preinit)
+#ifdef HAVE_EEPROM_SETTINGS
+ if (firmware_settings.initialized &&
+ firmware_settings.disk_clean &&
+ preinit)
{
result = dircache_load();
-
if (result < 0)
- {
firmware_settings.disk_clean = false;
- if (global_status.dircache_size <= 0)
- {
- /* This will be in default language, settings are not
- applied yet. Not really any easy way to fix that. */
- splash(0, str(LANG_SCANNING_DISK));
- clear = true;
- }
-
- dircache_build(global_status.dircache_size);
- }
}
else
-# endif
+#endif /* HAVE_EEPROM_SETTINGS */
+ if (!preinit)
{
- if (preinit)
- return -1;
-
- if (!dircache_is_enabled()
- && !dircache_is_initializing())
+ result = dircache_enable();
+ if (result != 0)
{
- if (global_status.dircache_size <= 0)
+ if (result > 0)
{
+ /* Print "Scanning disk..." to the display. */
splash(0, str(LANG_SCANNING_DISK));
- clear = true;
+ dircache_wait();
+ backlight_on();
+ show_logo();
}
- result = dircache_build(global_status.dircache_size);
- }
- if (result < 0)
- {
- /* Initialization of dircache failed. Manual action is
- * necessary to enable dircache again.
- */
- splashf(0, "Dircache failed, disabled. Result: %d", result);
- global_settings.dircache = false;
+ struct dircache_info info;
+ dircache_get_info(&info);
+ global_status.dircache_size = info.size;
+ status_save();
}
- }
-
- if (clear)
- {
- backlight_on();
- show_logo();
- global_status.dircache_size = dircache_get_cache_size();
- status_save();
+ /* else don't wait or already enabled by load */
}
return result;
-#else
- (void)preinit;
- return 0;
-#endif
}
+#endif /* HAVE_DIRCACHE */
#ifdef HAVE_TAGCACHE
static void init_tagcache(void) INIT_ATTR;
@@ -363,6 +336,7 @@ static void init(void)
button_init();
powermgmt_init();
backlight_init();
+ unicode_init();
#ifdef SIMULATOR
sim_tasks_init();
#endif
@@ -392,8 +366,10 @@ static void init(void)
settings_reset();
settings_load(SETTINGS_ALL);
settings_apply(true);
+#ifdef HAVE_DIRCACHE
init_dircache(true);
init_dircache(false);
+#endif
#ifdef HAVE_TAGCACHE
init_tagcache();
#endif
@@ -429,6 +405,8 @@ static void init(void)
#else
+#include "errno.h"
+
static void init(void) INIT_ATTR;
static void init(void)
{
@@ -443,6 +421,9 @@ static void init(void)
core_allocator_init();
kernel_init();
+ /* early early early! */
+ filesystem_init();
+
#ifdef HAVE_ADJUSTABLE_CPU_FREQ
set_cpu_frequency(CPUFREQ_NORMAL);
#ifdef CPU_COLDFIRE
@@ -462,6 +443,7 @@ static void init(void)
/* current_tick should be ticking by now */
CHART("ticking");
+ unicode_init();
lcd_init();
#ifdef HAVE_REMOTE_LCD
lcd_remote_init();
@@ -558,8 +540,6 @@ static void init(void)
}
#endif
-
- disk_init_subsystem();
CHART(">storage_init");
rc = storage_init();
CHART("<storage_init");
@@ -661,22 +641,24 @@ static void init(void)
CHART("<settings_load(ALL)");
}
+#ifdef HAVE_DIRCACHE
CHART(">init_dircache(true)");
rc = init_dircache(true);
CHART("<init_dircache(true)");
- if (rc < 0)
- {
#ifdef HAVE_TAGCACHE
+ if (rc < 0)
remove(TAGCACHE_STATEFILE);
-#endif
- }
+#endif /* HAVE_TAGCACHE */
+#endif /* HAVE_DIRCACHE */
CHART(">settings_apply(true)");
settings_apply(true);
CHART("<settings_apply(true)");
+#ifdef HAVE_DIRCACHE
CHART(">init_dircache(false)");
init_dircache(false);
CHART("<init_dircache(false)");
+#endif
#ifdef HAVE_TAGCACHE
CHART(">init_tagcache");
init_tagcache();
diff --git a/apps/menus/display_menu.c b/apps/menus/display_menu.c
index 3e1443d02e..948dcede00 100644
--- a/apps/menus/display_menu.c
+++ b/apps/menus/display_menu.c
@@ -43,6 +43,7 @@
#endif
#include "viewport.h"
#include "statusbar.h" /* statusbar_vals enum*/
+#include "rbunicode.h"
#ifdef HAVE_BACKLIGHT
static int filterfirstkeypress_callback(int action,const struct menu_item_ex *this_item)
@@ -524,8 +525,25 @@ MAKE_MENU(touchscreen_menu, ID2P(LANG_TOUCHSCREEN_SETTINGS), NULL, Icon_NOICON,
&touchscreen_menu_calibrate, &touchscreen_menu_reset_calibration);
#endif
+static int codepage_callback(int action, const struct menu_item_ex *this_item)
+{
+ static int old_codepage;
+ int new_codepage = global_settings.default_codepage;
+ (void)this_item;
+ switch (action)
+ {
+ case ACTION_ENTER_MENUITEM:
+ old_codepage = new_codepage;
+ break;
+ case ACTION_EXIT_MENUITEM:
+ if (new_codepage != old_codepage)
+ set_codepage(new_codepage);
+ break;
+ }
+ return action;
+}
-MENUITEM_SETTING(codepage_setting, &global_settings.default_codepage, NULL);
+MENUITEM_SETTING(codepage_setting, &global_settings.default_codepage, codepage_callback);
MAKE_MENU(display_menu, ID2P(LANG_DISPLAY),
diff --git a/apps/menus/main_menu.c b/apps/menus/main_menu.c
index 6a1295996c..8764101f73 100644
--- a/apps/menus/main_menu.c
+++ b/apps/menus/main_menu.c
@@ -48,6 +48,7 @@
#include "time.h"
#include "wps.h"
#include "skin_buffer.h"
+#include "disk.h"
static const struct browse_folder_info config = {ROCKBOX_DIR, SHOW_CFG};
@@ -160,14 +161,14 @@ static const char* info_getname(int selected_item, void *data,
#endif
if (info->new_data)
{
- fat_size(IF_MV(0,) &info->size, &info->free);
+ volume_size(IF_MV(0,) &info->size, &info->free);
#ifdef HAVE_MULTIVOLUME
#ifndef APPLICATION
- if (fat_ismounted(1))
- fat_size(1, &info->size2, &info->free2);
- else
+ volume_size(1, &info->size2, &info->free2);
+#else
+ info->size2 = 0;
#endif
- info->size2 = 0;
+
#endif
info->new_data = false;
}
@@ -347,12 +348,7 @@ static int info_action_callback(int action, struct gui_synclist *lists)
info->new_data = true;
splash(0, ID2P(LANG_SCANNING_DISK));
for (i = 0; i < NUM_VOLUMES; i++)
- {
-#ifdef HAVE_HOTSWAP
- if (fat_ismounted(i))
-#endif
- fat_recalc_free(IF_MV(i));
- }
+ volume_recalc_free(IF_MV(i));
#else
(void) lists;
#endif
diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c
index 95423a20fa..0d2a7febf1 100644
--- a/apps/menus/settings_menu.c
+++ b/apps/menus/settings_menu.c
@@ -209,12 +209,12 @@ static int dircache_callback(int action,const struct menu_item_ex *this_item)
switch (action)
{
case ACTION_EXIT_MENUITEM: /* on exit */
- if (global_settings.dircache && !dircache_is_enabled())
+ if (global_settings.dircache)
{
- if (dircache_build(0) < 0)
+ if (dircache_enable() < 0)
splash(HZ*2, ID2P(LANG_PLEASE_REBOOT));
}
- else if (!global_settings.dircache && dircache_is_enabled())
+ else
{
dircache_disable();
}
diff --git a/apps/misc.c b/apps/misc.c
index f847023c31..b6eaafb599 100644
--- a/apps/misc.c
+++ b/apps/misc.c
@@ -28,9 +28,12 @@
#include "misc.h"
#include "system.h"
#include "lcd.h"
+#ifdef HAVE_DIRCACHE
+#include "dircache.h"
+#endif
#include "file.h"
#ifndef __PCTOOL__
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "lang.h"
#include "dir.h"
#ifdef HAVE_REMOTE_LCD
@@ -744,8 +747,7 @@ int show_logo( void )
*/
void check_bootfile(bool do_rolo)
{
- static unsigned short wrtdate = 0;
- static unsigned short wrttime = 0;
+ static time_t mtime = 0;
DIR* dir = NULL;
struct dirent* entry = NULL;
@@ -761,10 +763,9 @@ void check_bootfile(bool do_rolo)
{
struct dirinfo info = dir_get_info(dir, entry);
/* found the bootfile */
- if(wrtdate && do_rolo)
+ if(mtime && do_rolo)
{
- if((info.wrtdate != wrtdate) ||
- (info.wrttime != wrttime))
+ if(info.mtime != mtime)
{
static const char *lines[] = { ID2P(LANG_BOOT_CHANGED),
ID2P(LANG_REBOOT_NOW) };
@@ -777,8 +778,7 @@ void check_bootfile(bool do_rolo)
}
}
}
- wrtdate = info.wrtdate;
- wrttime = info.wrttime;
+ mtime = info.mtime;
}
}
closedir(dir);
diff --git a/apps/onplay.c b/apps/onplay.c
index 7c5f517090..091680e949 100644
--- a/apps/onplay.c
+++ b/apps/onplay.c
@@ -62,16 +62,13 @@
#include "statusbar-skinned.h"
#include "pitchscreen.h"
#include "viewport.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "shortcuts.h"
static int context;
-static const char* selected_file = NULL;
+static const char *selected_file = NULL;
static int selected_file_attr = 0;
static int onplay_result = ONPLAY_OK;
-static char clipboard_selection[MAX_PATH];
-static int clipboard_selection_attr = 0;
-static bool clipboard_is_copy = false;
/* redefine MAKE_MENU so the MENU_EXITAFTERTHISMENU flag can be added easily */
#define MAKE_ONPLAYMENU( name, str, callback, icon, ... ) \
@@ -82,6 +79,63 @@ static bool clipboard_is_copy = false;
MENU_ITEM_COUNT(sizeof( name##_)/sizeof(*name##_)), \
{ (void*)name##_},{.callback_and_desc = & name##__}};
+/* Used for directory move, copy and delete */
+struct dirrecurse_params
+{
+ char path[MAX_PATH]; /* Buffer for full path */
+ size_t append; /* Append position in 'path' for stack push */
+};
+
+enum clipboard_op_flags
+{
+ PASTE_CUT = 0x00, /* Is a move (cut) operation (default) */
+ PASTE_COPY = 0x01, /* Is a copy operation */
+ PASTE_OVERWRITE = 0x02, /* Overwrite destination */
+ PASTE_EXDEV = 0x04, /* Actually copy/move across volumes */
+};
+
+/* result codec of various onplay operations */
+enum onplay_result_code
+{
+ /* Anything < 0 is failure */
+ OPRC_SUCCESS = 0, /* All operations completed successfully */
+ OPRC_NOOP = 1, /* Operation didn't need to do anything */
+ OPRC_CANCELLED = 2, /* Operation was cancelled by user */
+ OPRC_NOOVERWRT = 3,
+};
+
+static struct clipboard
+{
+ char path[MAX_PATH]; /* Clipped file's path */
+ unsigned int attr; /* Clipped file's attributes */
+ unsigned int flags; /* Operation type flags */
+} clipboard;
+
+/* Empty the clipboard */
+static void clipboard_clear_selection(struct clipboard *clip)
+{
+ clip->path[0] = '\0';
+ clip->attr = 0;
+ clip->flags = 0;
+}
+
+/* Store the selection in the clipboard */
+static bool clipboard_clip(struct clipboard *clip, const char *path,
+ unsigned int attr, unsigned int flags)
+{
+ /* if it fits it clips */
+ if (strlcpy(clip->path, path, sizeof (clip->path))
+ < sizeof (clip->path)) {
+ clip->attr = attr;
+ clip->flags = flags;
+ return true;
+ }
+ else {
+ clipboard_clear_selection(clip);
+ return false;
+ }
+}
+
/* ----------------------------------------------------------------------- */
/* Displays the bookmark menu options for the user to decide. This is an */
/* interface function. */
@@ -492,438 +546,578 @@ static void draw_slider(void)
#define draw_slider()
#endif
-/* helper function to remove a non-empty directory */
-static int remove_dir(char* dirname, int len)
+static void clear_display(bool update)
{
- int result = 0;
- DIR* dir;
- int dirlen = strlen(dirname);
+ struct viewport vp;
- dir = opendir(dirname);
- if (!dir)
+ FOR_NB_SCREENS(i)
+ {
+ struct screen * screen = &screens[i];
+ viewport_set_defaults(&vp, screen->screen_type);
+ screen->set_viewport(&vp);
+ screen->clear_viewport();
+ if (update) {
+ screen->update_viewport();
+ }
+ screen->set_viewport(NULL);
+ }
+}
+
+static void splash_path(const char *path)
+{
+ clear_display(false);
+ path_basename(path, &path);
+ splash(0, path);
+ draw_slider();
+}
+
+/* Splashes the path and checks the keys */
+static bool poll_cancel_action(const char *path)
+{
+ splash_path(path);
+ return ACTION_STD_CANCEL == get_action(CONTEXT_STD, TIMEOUT_NOBLOCK);
+}
+
+static int confirm_overwrite(void)
+{
+ static const char *lines[] = { ID2P(LANG_REALLY_OVERWRITE) };
+ static const struct text_message message = { lines, 1 };
+ return gui_syncyesno_run(&message, NULL, NULL);
+}
+
+static int confirm_delete(const char *file)
+{
+ const char *lines[] = { ID2P(LANG_REALLY_DELETE), file };
+ const char *yes_lines[] = { ID2P(LANG_DELETING), file };
+ const struct text_message message = { lines, 2 };
+ const struct text_message yes_message = { yes_lines, 2 };
+ return gui_syncyesno_run(&message, &yes_message, NULL);
+}
+
+static bool check_new_name(const char *basename)
+{
+ /* at least prevent escapes out of the base directory from keyboard-
+ entered filenames; the file code should reject other invalidities */
+ return *basename != '\0' && !strchr(basename, PATH_SEPCH) &&
+ !is_dotdir_name(basename);
+}
+
+static void splash_cancelled(void)
+{
+ clear_display(true);
+ splash(HZ, ID2P(LANG_CANCEL));
+}
+
+static void splash_failed(int lang_what)
+{
+ cond_talk_ids_fq(lang_what, LANG_FAILED);
+ clear_display(true);
+ splashf(HZ*2, "%s %s", str(lang_what), str(LANG_FAILED));
+}
+
+/* helper function to remove a non-empty directory */
+static int remove_dir(struct dirrecurse_params *parm)
+{
+ DIR *dir = opendir(parm->path);
+ if (!dir) {
return -1; /* open error */
+ }
- while(true)
- {
- struct dirent* entry;
- /* walk through the directory content */
- entry = readdir(dir);
- if (!entry)
+ size_t append = parm->append;
+ int rc = OPRC_SUCCESS;
+
+ /* walk through the directory content */
+ while (rc == OPRC_SUCCESS) {
+ errno = 0; /* distinguish failure from eod */
+ struct dirent *entry = readdir(dir);
+ if (!entry) {
+ if (errno) {
+ rc = -1;
+ }
break;
+ }
+
struct dirinfo info = dir_get_info(dir, entry);
- dirname[dirlen] ='\0';
- /* inform the user which dir we're deleting */
- splash(0, dirname);
+ if ((info.attribute & ATTR_DIRECTORY) &&
+ is_dotdir_name(entry->d_name)) {
+ continue; /* skip these */
+ }
/* append name to current directory */
- snprintf(dirname+dirlen, len-dirlen, "/%s", entry->d_name);
- if (info.attribute & ATTR_DIRECTORY)
- { /* remove a subdirectory */
- if (!strcmp((char *)entry->d_name, ".") ||
- !strcmp((char *)entry->d_name, ".."))
- continue; /* skip these */
-
- result = remove_dir(dirname, len); /* recursion */
- if (result)
- break; /* or better continue, delete what we can? */
- }
- else
- { /* remove a file */
- draw_slider();
- result = remove(dirname);
+ parm->append = append + path_append(&parm->path[append],
+ PA_SEP_HARD, entry->d_name,
+ sizeof (parm->path) - append);
+ if (parm->append >= sizeof (parm->path)) {
+ rc = -1;
+ break; /* no space left in buffer */
}
- if(ACTION_STD_CANCEL == get_action(CONTEXT_STD,TIMEOUT_NOBLOCK))
- {
- splash(HZ, ID2P(LANG_CANCEL));
- result = -1;
- break;
+
+ if (info.attribute & ATTR_DIRECTORY) {
+ /* remove a subdirectory */
+ rc = remove_dir(parm);
+ } else {
+ /* remove a file */
+ if (poll_cancel_action(parm->path)) {
+ rc = OPRC_CANCELLED;
+ break;
+ }
+
+ rc = remove(parm->path);
}
+
+ /* Remove basename we added above */
+ parm->path[append] = '\0';
}
- closedir(dir);
- if (!result)
- { /* remove the now empty directory */
- dirname[dirlen] = '\0'; /* terminate to original length */
+ closedir(dir);
- result = rmdir(dirname);
+ if (rc == 0) {
+ /* remove the now empty directory */
+ if (poll_cancel_action(parm->path)) {
+ rc = OPRC_CANCELLED;
+ } else {
+ rc = rmdir(parm->path);
+ }
}
- return result;
+ return rc;
}
-
/* share code for file and directory deletion, saves space */
-static bool delete_file_dir(void)
+static int delete_file_dir(void)
{
- char file_to_delete[MAX_PATH];
- strcpy(file_to_delete, selected_file);
+ if (confirm_delete(selected_file) != YESNO_YES) {
+ return 1;
+ }
- const char *lines[]={
- ID2P(LANG_REALLY_DELETE),
- file_to_delete
- };
- const char *yes_lines[]={
- ID2P(LANG_DELETING),
- file_to_delete
- };
+ clear_display(true);
+ splash(HZ/2, str(LANG_DELETING));
- const struct text_message message={lines, 2};
- const struct text_message yes_message={yes_lines, 2};
+ int rc = -1;
- if(gui_syncyesno_run(&message, &yes_message, NULL)!=YESNO_YES)
- return false;
+ if (selected_file_attr & ATTR_DIRECTORY) { /* true if directory */
+ struct dirrecurse_params parm;
+ parm.append = strlcpy(parm.path, selected_file, sizeof (parm.path));
- splash(0, str(LANG_DELETING));
+ if (parm.append < sizeof (parm.path)) {
+ cpu_boost(true);
+ rc = remove_dir(&parm);
+ cpu_boost(false);
+ }
+ } else {
+ rc = remove(selected_file);
+ }
- int res;
- if (selected_file_attr & ATTR_DIRECTORY) /* true if directory */
- {
- char pathname[MAX_PATH]; /* space to go deep */
- cpu_boost(true);
- strlcpy(pathname, file_to_delete, sizeof(pathname));
- res = remove_dir(pathname, sizeof(pathname));
- cpu_boost(false);
+ if (rc < OPRC_SUCCESS) {
+ splash_failed(LANG_DELETE);
+ } else if (rc == OPRC_CANCELLED) {
+ splash_cancelled();
}
- else
- res = remove(file_to_delete);
- if (!res)
+ if (rc != OPRC_NOOP) {
+ /* Could have failed after some but not all needed changes; reload */
onplay_result = ONPLAY_RELOAD_DIR;
+ }
- return (res == 0);
+ return 1;
}
-static bool rename_file(void)
+static int rename_file(void)
{
+ int rc = -1;
char newname[MAX_PATH];
- char* ptr = strrchr(selected_file, '/') + 1;
- int pathlen = (ptr - selected_file);
- strlcpy(newname, selected_file, sizeof(newname));
- if (!kbd_input(newname + pathlen, (sizeof newname)-pathlen)) {
- if (!strlen(newname + pathlen) ||
- (rename(selected_file, newname) < 0)) {
- cond_talk_ids_fq(LANG_RENAME, LANG_FAILED);
- splashf(HZ*2, "%s %s", str(LANG_RENAME), str(LANG_FAILED));
+ const char *oldbase, *selection = selected_file;
+
+ path_basename(selection, &oldbase);
+ size_t pathlen = oldbase - selection;
+ char *newbase = newname + pathlen;
+
+ if (strlcpy(newname, selection, sizeof (newname)) >= sizeof (newname)) {
+ /* Too long */
+ } else if (kbd_input(newbase, sizeof (newname) - pathlen) < 0) {
+ rc = OPRC_CANCELLED;
+ } else if (!strcmp(oldbase, newbase)) {
+ rc = OPRC_NOOP; /* No change at all */
+ } else if (check_new_name(newbase)) {
+ switch (relate(selection, newname))
+ {
+ case RELATE_DIFFERENT:
+ if (file_exists(newname)) {
+ break; /* don't overwrite */
+ }
+ /* Fall-through */
+ case RELATE_SAME:
+ rc = rename(selection, newname);
+ break;
+ case RELATE_PREFIX:
+ default:
+ break;
}
- else
- onplay_result = ONPLAY_RELOAD_DIR;
}
- return false;
+ if (rc < OPRC_SUCCESS) {
+ splash_failed(LANG_RENAME);
+ } else if (rc == OPRC_CANCELLED) {
+ /* splash_cancelled(); kbd_input() splashes it */
+ } else if (rc == OPRC_SUCCESS) {
+ onplay_result = ONPLAY_RELOAD_DIR;
+ }
+
+ return 1;
}
-static bool create_dir(void)
+static int create_dir(void)
{
+ int rc = -1;
char dirname[MAX_PATH];
- char *cwd;
- int rc;
- int pathlen;
-
- cwd = getcwd(NULL, 0);
- memset(dirname, 0, sizeof dirname);
-
- snprintf(dirname, sizeof dirname, "%s/", cwd[1] ? cwd : "");
-
- pathlen = strlen(dirname);
- rc = kbd_input(dirname + pathlen, (sizeof dirname)-pathlen);
- if (rc < 0)
- return false;
+ size_t pathlen = path_append(dirname, getcwd(NULL, 0), PA_SEP_HARD,
+ sizeof (dirname));
+ char *basename = dirname + pathlen;
+
+ if (pathlen >= sizeof (dirname)) {
+ /* Too long */
+ } else if (kbd_input(basename, sizeof (dirname) - pathlen) < 0) {
+ rc = OPRC_CANCELLED;
+ } else if (check_new_name(basename)) {
+ rc = mkdir(dirname);
+ }
- rc = mkdir(dirname);
- if (rc < 0) {
- cond_talk_ids_fq(LANG_CREATE_DIR, LANG_FAILED);
- splashf(HZ, (unsigned char *)"%s %s", str(LANG_CREATE_DIR),
- str(LANG_FAILED));
- } else {
+ if (rc < OPRC_SUCCESS) {
+ splash_failed(LANG_CREATE_DIR);
+ } else if (rc == OPRC_CANCELLED) {
+ /* splash_cancelled(); kbd_input() splashes it */
+ } else if (rc == OPRC_SUCCESS) {
onplay_result = ONPLAY_RELOAD_DIR;
}
- return true;
+ return 1;
}
-/* Store the current selection in the clipboard */
-static bool clipboard_clip(bool copy)
+/* Paste a file */
+static int clipboard_pastefile(const char *src, const char *target,
+ unsigned int flags)
{
- clipboard_selection[0] = 0;
- strlcpy(clipboard_selection, selected_file, sizeof(clipboard_selection));
- clipboard_selection_attr = selected_file_attr;
- clipboard_is_copy = copy;
-
- return true;
-}
+ int rc = -1;
+
+ while (!(flags & (PASTE_COPY | PASTE_EXDEV))) {
+ if ((flags & PASTE_OVERWRITE) || !file_exists(target)) {
+ /* Rename and possibly overwrite the file */
+ if (poll_cancel_action(src)) {
+ rc = OPRC_CANCELLED;
+ } else {
+ rc = rename(src, target);
+ }
-static bool clipboard_cut(void)
-{
- return clipboard_clip(false);
-}
+ #ifdef HAVE_MULTIVOLUME
+ if (rc < 0 && errno == EXDEV) {
+ /* Failed because cross volume rename doesn't work; force
+ a move instead */
+ flags |= PASTE_EXDEV;
+ break;
+ }
+ #endif /* HAVE_MULTIVOLUME */
+ }
-static bool clipboard_copy(void)
-{
- return clipboard_clip(true);
-}
+ return rc;
+ }
-/* Paste a file to a new directory. Will overwrite always. */
-static bool clipboard_pastefile(const char *src, const char *target, bool copy)
-{
- int src_fd, target_fd;
+ /* See if we can get the plugin buffer for the file copy buffer */
size_t buffersize;
- ssize_t size, bytesread, byteswritten;
- char *buffer;
- bool result = false;
-
- if (copy) {
- /* See if we can get the plugin buffer for the file copy buffer */
- buffer = (char *) plugin_get_buffer(&buffersize);
- if (buffer == NULL || buffersize < 512) {
- /* Not large enough, try for a disk sector worth of stack
- instead */
- buffersize = 512;
- buffer = (char *) __builtin_alloca(buffersize);
- }
+ char *buffer = (char *) plugin_get_buffer(&buffersize);
+ if (buffer == NULL || buffersize < 512) {
+ /* Not large enough, try for a disk sector worth of stack
+ instead */
+ buffersize = 512;
+ buffer = (char *)alloca(buffersize);
+ }
- if (buffer == NULL) {
- return false;
- }
+ if (buffer == NULL) {
+ return -1;
+ }
- buffersize &= ~0x1ff; /* Round buffer size to multiple of sector
- size */
+ buffersize &= ~0x1ff; /* Round buffer size to multiple of sector
+ size */
- src_fd = open(src, O_RDONLY);
+ int src_fd = open(src, O_RDONLY);
+ if (src_fd >= 0) {
+ int oflag = O_WRONLY|O_CREAT;
- if (src_fd >= 0) {
- target_fd = creat(target, 0666);
+ if (!(flags & PASTE_OVERWRITE)) {
+ oflag |= O_EXCL;
+ }
- if (target_fd >= 0) {
- result = true;
+ int target_fd = open(target, oflag, 0666);
+ if (target_fd >= 0) {
+ off_t total_size = 0;
+ off_t next_cancel_test = 0; /* No excessive button polling */
- size = filesize(src_fd);
+ rc = OPRC_SUCCESS;
- if (size == -1) {
- result = false;
+ while (rc == OPRC_SUCCESS) {
+ if (total_size >= next_cancel_test) {
+ next_cancel_test = total_size + 0x10000;
+ if (poll_cancel_action(src)) {
+ rc = OPRC_CANCELLED;
+ break;
+ }
}
- while(size > 0) {
- bytesread = read(src_fd, buffer, buffersize);
-
- if (bytesread == -1) {
- result = false;
- break;
+ ssize_t bytesread = read(src_fd, buffer, buffersize);
+ if (bytesread <= 0) {
+ if (bytesread < 0) {
+ rc = -1;
}
+ /* else eof on buffer boundary; nothing to write */
+ break;
+ }
- size -= bytesread;
-
- while(bytesread > 0) {
- byteswritten = write(target_fd, buffer, bytesread);
-
- if (byteswritten < 0) {
- result = false;
- size = 0;
- break;
- }
-
- bytesread -= byteswritten;
- draw_slider();
- }
+ ssize_t byteswritten = write(target_fd, buffer, bytesread);
+ if (byteswritten < bytesread) {
+ /* Some I/O error */
+ rc = -1;
+ break;
}
- close(target_fd);
+ total_size += byteswritten;
- /* Copy failed. Cleanup. */
- if (!result) {
- remove(target);
+ if (bytesread < (ssize_t)buffersize) {
+ /* EOF with trailing bytes */
+ break;
}
}
- close(src_fd);
- }
- } else {
- result = rename(src, target) == 0;
-#ifdef HAVE_MULTIVOLUME
- if (!result) {
- if (errno == EXDEV) {
- /* Failed because cross volume rename doesn't work. Copy
- instead */
- result = clipboard_pastefile(src, target, true);
-
- if (result) {
- result = remove(src) == 0;
- }
+ if (rc == OPRC_SUCCESS) {
+ /* If overwriting, set the correct length if original was
+ longer */
+ rc = ftruncate(target_fd, total_size);
+ }
+
+ close(target_fd);
+
+ if (rc != OPRC_SUCCESS) {
+ /* Copy failed. Cleanup. */
+ remove(target);
}
}
-#endif
+
+ close(src_fd);
}
- return result;
+ if (rc == OPRC_SUCCESS && !(flags & PASTE_COPY)) {
+ /* Remove the source file */
+ rc = remove(src);
+ }
+
+ return rc;
}
-/* Paste a directory to a new location. Designed to be called by
- clipboard_paste */
-static bool clipboard_pastedirectory(char *src, int srclen, char *target,
- int targetlen, bool copy)
+/* Paste a directory */
+static int clipboard_pastedirectory(struct dirrecurse_params *src,
+ struct dirrecurse_params *target,
+ unsigned int flags)
{
- DIR *srcdir;
- int srcdirlen = strlen(src);
- int targetdirlen = strlen(target);
- bool result = true;
-
- if (!file_exists(target)) {
- if (!copy) {
- /* Just move the directory */
- result = rename(src, target) == 0;
+ int rc = -1;
+
+ while (!(flags & (PASTE_COPY | PASTE_EXDEV))) {
+ if ((flags & PASTE_OVERWRITE) || !file_exists(target->path)) {
+ /* Just try to move the directory */
+ if (poll_cancel_action(src->path)) {
+ rc = OPRC_CANCELLED;
+ } else {
+ rc = rename(src->path, target->path);
+ }
-#ifdef HAVE_MULTIVOLUME
- if (!result && errno == EXDEV) {
- /* Try a copy as we're going across devices */
- result = clipboard_pastedirectory(src, srclen, target,
- targetlen, true);
-
- /* If it worked, remove the source directory */
- if (result) {
- remove_dir(src, srclen);
+ if (rc < 0) {
+ int errnum = errno;
+ if (errnum == ENOTEMPTY && (flags & PASTE_OVERWRITE)) {
+ /* Directory is not empty thus rename() will not do a quick
+ overwrite */
+ break;
}
+ #ifdef HAVE_MULTIVOLUME
+ else if (errnum == EXDEV) {
+ /* Failed because cross volume rename doesn't work; force
+ a move instead */
+ flags |= PASTE_EXDEV;
+ break;
+ }
+ #endif /* HAVE_MULTIVOLUME */
}
-#endif
- return result;
- } else {
- /* Make a directory to copy things to */
- result = mkdir(target) == 0;
}
- }
- /* Check if something went wrong already */
- if (!result) {
- return result;
+ return rc;
}
- srcdir = opendir(src);
- if (!srcdir) {
- return false;
+ DIR *srcdir = opendir(src->path);
+
+ if (srcdir) {
+ /* Make a directory to copy things to */
+ rc = mkdir(target->path);
+ if (rc < 0 && errno == EEXIST && (flags & PASTE_OVERWRITE)) {
+ /* Exists and overwrite was approved */
+ rc = OPRC_SUCCESS;
+ }
}
- /* This loop will exit as soon as there's a problem */
- while(result)
- {
- struct dirent* entry;
- /* walk through the directory content */
- entry = readdir(srcdir);
- if (!entry)
+ size_t srcap = src->append, targetap = target->append;
+
+ /* Walk through the directory content; this loop will exit as soon as
+ there's a problem */
+ while (rc == OPRC_SUCCESS) {
+ errno = 0; /* Distinguish failure from eod */
+ struct dirent *entry = readdir(srcdir);
+ if (!entry) {
+ if (errno) {
+ rc = -1;
+ }
break;
+ }
struct dirinfo info = dir_get_info(srcdir, entry);
- /* append name to current directory */
- snprintf(src+srcdirlen, srclen-srcdirlen, "/%s", entry->d_name);
- snprintf(target+targetdirlen, targetlen-targetdirlen, "/%s",
- entry->d_name);
+ if ((info.attribute & ATTR_DIRECTORY) &&
+ is_dotdir_name(entry->d_name)) {
+ continue; /* Skip these */
+ }
- DEBUGF("Copy %s to %s\n", src, target);
+ /* Append names to current directories */
+ src->append = srcap +
+ path_append(&src->path[srcap], PA_SEP_HARD, entry->d_name,
+ sizeof(src->path) - srcap);
- if (info.attribute & ATTR_DIRECTORY)
- { /* copy/move a subdirectory */
- if (!strcmp((char *)entry->d_name, ".") ||
- !strcmp((char *)entry->d_name, ".."))
- continue; /* skip these */
+ target->append = targetap +
+ path_append(&target->path[targetap], PA_SEP_HARD, entry->d_name,
+ sizeof (target->path) - targetap);
- result = clipboard_pastedirectory(src, srclen, target, targetlen,
- copy); /* recursion */
+ if (src->append >= sizeof (src->path) ||
+ target->append >= sizeof (target->path)) {
+ rc = -1; /* No space left in buffer */
+ break;
}
- else
- { /* copy/move a file */
- draw_slider();
- result = clipboard_pastefile(src, target, copy);
+
+ if (poll_cancel_action(src->path)) {
+ rc = OPRC_CANCELLED;
+ break;
+ }
+
+ DEBUGF("Copy %s to %s\n", src->path, target->path);
+
+ if (info.attribute & ATTR_DIRECTORY) {
+ /* Copy/move a subdirectory */
+ rc = clipboard_pastedirectory(src, target, flags); /* recursion */
+ } else {
+ /* Copy/move a file */
+ rc = clipboard_pastefile(src->path, target->path, flags);
}
+
+ /* Remove basenames we added above */
+ src->path[srcap] = target->path[targetap] = '\0';
+ }
+
+ if (rc == OPRC_SUCCESS && !(flags & PASTE_COPY)) {
+ /* Remove the now empty directory */
+ rc = rmdir(src->path);
}
closedir(srcdir);
+ return rc;
+}
- if (result) {
- src[srcdirlen] = '\0'; /* terminate to original length */
- target[targetdirlen] = '\0'; /* terminate to original length */
- }
+static bool clipboard_cut(void)
+{
+ return clipboard_clip(&clipboard, selected_file, selected_file_attr,
+ PASTE_CUT);
+}
- return result;
+static bool clipboard_copy(void)
+{
+ return clipboard_clip(&clipboard, selected_file, selected_file_attr,
+ PASTE_COPY);
}
/* Paste the clipboard to the current directory */
-static bool clipboard_paste(void)
+static int clipboard_paste(void)
{
- char target[MAX_PATH];
- char *cwd, *nameptr;
- bool success;
+ if (!clipboard.path[0])
+ return 1;
- static const char *lines[]={ID2P(LANG_REALLY_OVERWRITE)};
- static const struct text_message message={lines, 1};
+ int rc = -1;
- /* Get the name of the current directory */
- cwd = getcwd(NULL, 0);
+ struct dirrecurse_params src, target;
+ unsigned int flags = clipboard.flags;
/* Figure out the name of the selection */
- nameptr = strrchr(clipboard_selection, '/');
+ const char *nameptr;
+ path_basename(clipboard.path, &nameptr);
/* Final target is current directory plus name of selection */
- snprintf(target, sizeof(target), "%s%s", cwd[1] ? cwd : "", nameptr);
-
- /* If the target existed but they choose not to overwite, exit */
- if (file_exists(target) &&
- (gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO)) {
- return false;
- }
+ target.append = path_append(target.path, getcwd(NULL, 0),
+ nameptr, sizeof (target.path));
- if (clipboard_is_copy) {
- splash(0, ID2P(LANG_COPYING));
- }
- else
+ switch (target.append < sizeof (target.path) ?
+ relate(clipboard.path, target.path) : -1)
{
- splash(0, ID2P(LANG_MOVING));
- }
+ case RELATE_SAME:
+ rc = OPRC_NOOP;
+ break;
+
+ case RELATE_DIFFERENT:
+ if (file_exists(target.path)) {
+ /* If user chooses not to overwrite, cancel */
+ if (confirm_overwrite() == YESNO_NO) {
+ rc = OPRC_NOOVERWRT;
+ break;
+ }
- /* Now figure out what we're doing */
- cpu_boost(true);
- if (clipboard_selection_attr & ATTR_DIRECTORY) {
- /* Recursion. Set up external stack */
- char srcpath[MAX_PATH];
- char targetpath[MAX_PATH];
- if (!strncmp(clipboard_selection, target, strlen(clipboard_selection)))
- {
- /* Do not allow the user to paste a directory into a dir they are
- copying */
- success = 0;
+ flags |= PASTE_OVERWRITE;
}
- else
- {
- strlcpy(srcpath, clipboard_selection, sizeof(srcpath));
- strlcpy(targetpath, target, sizeof(targetpath));
- success = clipboard_pastedirectory(srcpath, sizeof(srcpath),
- target, sizeof(targetpath), clipboard_is_copy);
+ clear_display(true);
+ splash(HZ/2, (flags & PASTE_COPY) ? ID2P(LANG_COPYING) :
+ ID2P(LANG_MOVING));
- if (success && !clipboard_is_copy)
- {
- strlcpy(srcpath, clipboard_selection, sizeof(srcpath));
- remove_dir(srcpath, sizeof(srcpath));
+ /* Now figure out what we're doing */
+ cpu_boost(true);
+
+ if (clipboard.attr & ATTR_DIRECTORY) {
+ /* Copy or move a subdirectory */
+ src.append = strlcpy(src.path, clipboard.path,
+ sizeof (src.path));
+ if (src.append < sizeof (src.path)) {
+ rc = clipboard_pastedirectory(&src, &target, flags);
}
+ } else {
+ /* Copy or move a file */
+ rc = clipboard_pastefile(clipboard.path, target.path, flags);
}
- } else {
- success = clipboard_pastefile(clipboard_selection, target,
- clipboard_is_copy);
+
+ cpu_boost(false);
+ break;
+
+ case RELATE_PREFIX:
+ default: /* Some other relation / failure */
+ break;
}
- cpu_boost(false);
- /* Did it work? */
- if (success) {
- /* Reset everything */
- clipboard_selection[0] = 0;
- clipboard_selection_attr = 0;
- clipboard_is_copy = false;
+ clear_display(true);
- /* Force reload of the current directory */
+ switch (rc)
+ {
+ case OPRC_CANCELLED:
+ splash_cancelled();
+ case OPRC_SUCCESS:
onplay_result = ONPLAY_RELOAD_DIR;
- } else {
- cond_talk_ids_fq(LANG_PASTE, LANG_FAILED);
- splashf(HZ, (unsigned char *)"%s %s", str(LANG_PASTE),
- str(LANG_FAILED));
+ case OPRC_NOOP:
+ clipboard_clear_selection(&clipboard);
+ case OPRC_NOOVERWRT:
+ break;
+ default:
+ if (rc < OPRC_SUCCESS) {
+ splash_failed(LANG_PASTE);
+ onplay_result = ONPLAY_RELOAD_DIR;
+ }
}
- return true;
+ return 1;
}
#ifdef HAVE_TAGCACHE
@@ -1094,15 +1288,12 @@ static int clipboard_callback(int action,const struct menu_item_ex *this_item)
{
case ACTION_REQUEST_MENUITEM:
#ifdef HAVE_MULTIVOLUME
- if ((selected_file_attr & FAT_ATTR_VOLUME) &&
- (this_item == &rename_file_item ||
- this_item == &delete_dir_item ||
- this_item == &clipboard_cut_item) )
- return ACTION_EXIT_MENUITEM;
/* no rename+delete for volumes */
if ((selected_file_attr & ATTR_VOLUME) &&
- (this_item == &delete_file_item ||
- this_item == &list_viewers_item))
+ (this_item == &rename_file_item ||
+ this_item == &delete_dir_item ||
+ this_item == &clipboard_cut_item ||
+ this_item == &list_viewers_item))
return ACTION_EXIT_MENUITEM;
#endif
#ifdef HAVE_TAGCACHE
@@ -1117,7 +1308,7 @@ static int clipboard_callback(int action,const struct menu_item_ex *this_item)
#endif
if (this_item == &clipboard_paste_item)
{ /* visible if there is something to paste */
- return (clipboard_selection[0] != 0) ?
+ return (clipboard.path[0] != 0) ?
action : ACTION_EXIT_MENUITEM;
}
else if (this_item == &create_dir_item)
@@ -1232,8 +1423,7 @@ static bool delete_item(void)
{
#ifdef HAVE_MULTIVOLUME
/* no delete for volumes */
- if ((selected_file_attr & FAT_ATTR_VOLUME) ||
- (selected_file_attr & ATTR_VOLUME))
+ if (selected_file_attr & ATTR_VOLUME)
return false;
#endif
return delete_file_dir();
diff --git a/apps/playlist.c b/apps/playlist.c
index 43aa97790b..db93344ef1 100755
--- a/apps/playlist.c
+++ b/apps/playlist.c
@@ -86,7 +86,7 @@
#include "screens.h"
#include "core_alloc.h"
#include "misc.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "button.h"
#include "filetree.h"
#include "abrepeat.h"
@@ -107,6 +107,8 @@
#include "panic.h"
#include "logdiskf.h"
+#undef HAVE_DIRCACHE
+
#define PLAYLIST_CONTROL_FILE_VERSION 2
/*
@@ -180,8 +182,8 @@ static int get_next_directory(char *dir);
static int get_next_dir(char *dir, bool is_forward);
static int get_previous_directory(char *dir);
static int check_subdir_for_music(char *dir, const char *subdir, bool recurse);
-static int format_track_path(char *dest, char *src, int buf_length, int max,
- const char *dir);
+static ssize_t format_track_path(char *dest, char *src, int buf_length,
+ const char *dir);
static void display_playlist_count(int count, const unsigned char *fmt,
bool final);
static void display_buffer_full(void);
@@ -526,7 +528,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist,
int result = 0;
/* get emergency buffer so we don't fail horribly */
if (!buflen)
- buffer = __builtin_alloca((buflen = 64));
+ buffer = alloca((buflen = 64));
if(-1 == playlist->fd)
playlist->fd = open_utf8(playlist->filename, O_RDONLY);
@@ -1429,7 +1431,7 @@ static int get_filename(struct playlist_info* playlist, int index, int seek,
strlcpy(dir_buf, playlist->filename, playlist->dirlen);
- return (format_track_path(buf, tmp_buf, buf_length, max, dir_buf));
+ return format_track_path(buf, tmp_buf, buf_length, dir_buf);
}
static int get_next_directory(char *dir){
@@ -1629,7 +1631,7 @@ static int get_next_dir(char *dir, bool is_forward)
static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
{
int result = -1;
- int dirlen = strlen(dir);
+ size_t dirlen = strlen(dir);
int num_files = 0;
int i;
struct entry *files;
@@ -1637,12 +1639,11 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
bool has_subdir = false;
struct tree_context* tc = tree_get_context();
- snprintf(
- dir + dirlen, MAX_PATH - dirlen,
- /* only add a trailing slash if we need one */
- dirlen && dir[dirlen - 1] == '/' ? "%s" : "/%s",
- subdir
- );
+ if (path_append(dir + dirlen, PA_SEP_HARD, subdir, MAX_PATH - dirlen) >=
+ MAX_PATH - dirlen)
+ {
+ return 0;
+ }
if (ft_load(tc, dir) < 0)
{
@@ -1695,7 +1696,7 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
}
else
{
- strcpy(dir, "/");
+ strcpy(dir, PATH_ROOTSTR);
}
/* we now need to reload our current directory */
@@ -1708,79 +1709,31 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse)
/*
* Returns absolute path of track
*/
-static int format_track_path(char *dest, char *src, int buf_length, int max,
- const char *dir)
+static ssize_t format_track_path(char *dest, char *src, int buf_length,
+ const char *dir)
{
- int i = 0;
- int j;
- char *temp_ptr;
-
- /* Look for the end of the string */
- while((i < max) &&
- (src[i] != '\n') &&
- (src[i] != '\r') &&
- (src[i] != '\0'))
- i++;
-
- /* Now work back killing white space */
- while((i > 0) &&
- ((src[i-1] == ' ') ||
- (src[i-1] == '\t')))
- i--;
+ size_t len;
- /* Zero-terminate the file name */
- src[i]=0;
+ /* strip whitespace at beginning and end */
+ len = path_trim_whitespace(src, (const char **)&src);
+ src[len] = '\0';
/* replace backslashes with forward slashes */
- for ( j=0; j<i; j++ )
- if ( src[j] == '\\' )
- src[j] = '/';
+ path_correct_separators(src, src);
- if('/' == src[0])
- {
- strlcpy(dest, src, buf_length);
- }
- else
- {
- /* handle dos style drive letter */
- if (':' == src[1])
- strlcpy(dest, &src[2], buf_length);
- else if (!strncmp(src, "../", 3))
- {
- /* handle relative paths */
- i=3;
- while(!strncmp(&src[i], "../", 3))
- i += 3;
- for (j=0; j<i/3; j++) {
- temp_ptr = strrchr(dir, '/');
- if (temp_ptr)
- *temp_ptr = '\0';
- else
- break;
- }
- snprintf(dest, buf_length, "%s/%s", dir, &src[i]);
- }
- else if ( '.' == src[0] && '/' == src[1] ) {
- snprintf(dest, buf_length, "%s/%s", dir, &src[2]);
- }
- else {
- snprintf(dest, buf_length, "%s/%s", dir, src);
- }
- }
-#ifdef HAVE_MULTIVOLUME
+ /* handle DOS style drive letter and parse non-greedily so that:
+ * 1) "c:/foo" becomes "/foo" and the result is absolute
+ * 2) "c:foo becomes "foo" and the result is relative
+ * This is how Windows seems to handle it except drive letters are of no
+ * meaning here. */
+ path_strip_drive(src, (const char **)&src, false);
- char vol_string[VOL_ENUM_POS + 8];
- snprintf(vol_string, sizeof(vol_string), "/"VOL_NAMES, 1);
+ /* prepends directory only if src is relative */
+ len = path_append(dest, *dir ? dir : PATH_ROOTSTR, src, buf_length);
+ if (len >= (size_t)buf_length)
+ return -1; /* buffer too small */
- /*check if the playlist is on a external card, and correct path if needed */
- if(strstr(dir, vol_string) && (strstr(dest, vol_string) == NULL)){
- char temp[buf_length];
- strlcpy(temp, dest, buf_length);
- snprintf(dest, buf_length, "%s%s", vol_string, temp);
- }
-#endif
-
- return 0;
+ return len;
}
/*
@@ -3113,8 +3066,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
{
int fd;
int max;
- char *temp_ptr;
- const char *dir;
+ char *dir;
unsigned char *count_str;
char temp_buf[MAX_PATH+1];
char trackname[MAX_PATH+1];
@@ -3139,13 +3091,8 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
}
/* we need the directory name for formatting purposes */
- dir = filename;
-
- temp_ptr = strrchr(filename+1,'/');
- if (temp_ptr)
- *temp_ptr = 0;
- else
- dir = "/";
+ size_t dirlen = path_dirname(filename, (const char **)&dir);
+ dir = strmemdupa(dir, dirlen);
if (queue)
count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT);
@@ -3183,8 +3130,8 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
/* we need to format so that relative paths are correctly
handled */
- if (format_track_path(trackname, temp_buf, sizeof(trackname), max,
- dir) < 0)
+ if (format_track_path(trackname, temp_buf, sizeof(trackname),
+ dir) < 0)
{
result = -1;
break;
@@ -3223,9 +3170,6 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam
close(fd);
- if (temp_ptr)
- *temp_ptr = '/';
-
sync_control(playlist, false);
cpu_boost(false);
@@ -3537,9 +3481,9 @@ int playlist_save(struct playlist_info* playlist, char *filename,
char path[MAX_PATH+1];
char tmp_buf[MAX_PATH+1];
int result = 0;
- bool overwrite_current = false;
int *seek_buf;
bool reparse;
+ ssize_t pathlen;
ALIGN_BUFFER(temp_buffer, temp_buffer_size, sizeof(int));
seek_buf = temp_buffer;
@@ -3557,22 +3501,18 @@ int playlist_save(struct playlist_info* playlist, char *filename,
return -1;
/* use current working directory as base for pathname */
- if (format_track_path(path, filename, sizeof(tmp_buf),
- strlen(filename)+1, "/") < 0)
+ pathlen = format_track_path(path, filename, sizeof(path), PATH_ROOTSTR);
+ if (pathlen < 0)
+ return -1;
+
+ /* Use temporary pathname and overwrite/rename later */
+ if (strlcat(path, "_temp", sizeof(path)) >= sizeof (path))
return -1;
/* can ignore volatile here, because core_get_data() is called later */
char* old_buffer = (char*)playlist->buffer;
size_t old_buffer_size = playlist->buffer_size;
- if (!strncmp(playlist->filename, path, strlen(path)))
- {
- /* Attempting to overwrite current playlist file.
- * use temporary pathname and overwrite later */
- strlcat(path, "_temp", sizeof(path));
- overwrite_current = true;
- }
-
if (is_m3u8(path))
{
fd = open_utf8(path, O_CREAT|O_WRONLY|O_TRUNC);
@@ -3621,8 +3561,8 @@ int playlist_save(struct playlist_info* playlist, char *filename,
break;
}
- if (overwrite_current && !reparse)
- seek_buf[count] = lseek(fd, 0, SEEK_CUR);
+ if (!reparse)
+ seek_buf[count] = filesize(fd);
if (fdprintf(fd, "%s\n", tmp_buf) < 0)
{
@@ -3647,57 +3587,61 @@ int playlist_save(struct playlist_info* playlist, char *filename,
index = (index+1)%playlist->amount;
}
- display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true);
-
close(fd);
+ fd = -1;
- if (overwrite_current && result >= 0)
+ display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true);
+
+ if (result >= 0)
{
- result = -1;
+ strmemcpy(tmp_buf, path, pathlen); /* remove "_temp" */
mutex_lock(playlist->control_mutex);
- /* Replace the current playlist with the new one and update indices */
- close(playlist->fd);
- playlist->fd = -1;
- if (remove(playlist->filename) >= 0)
+ if (!rename(path, tmp_buf))
{
- if (rename(path, playlist->filename) >= 0)
+ fd = open_utf8(tmp_buf, O_RDONLY);
+ if (fsamefile(fd, playlist->fd) > 0)
{
- playlist->fd = open_utf8(playlist->filename, O_RDONLY);
- if (playlist->fd >= 0)
+ /* Replace the current playlist with the new one and update
+ indices */
+ close(playlist->fd);
+ playlist->fd = fd;
+ fd = -1;
+
+ if (!reparse)
{
- if (!reparse)
+ index = playlist->first_index;
+ for (i=0, count=0; i<playlist->amount; i++)
{
- index = playlist->first_index;
- for (i=0, count=0; i<playlist->amount; i++)
+ if (!(playlist->indices[index] & PLAYLIST_QUEUE_MASK))
{
- if (!(playlist->indices[index] & PLAYLIST_QUEUE_MASK))
- {
- playlist->indices[index] = seek_buf[count];
- count++;
- }
- index = (index+1)%playlist->amount;
+ playlist->indices[index] = seek_buf[count];
+ count++;
}
+ index = (index+1)%playlist->amount;
}
- else
- {
- NOTEF("reparsing current playlist (slow)");
- playlist->amount = 0;
- add_indices_to_playlist(playlist, temp_buffer, temp_buffer_size);
- }
- /* we need to recreate control because inserted tracks are
- now part of the playlist and shuffle has been
- invalidated */
- result = recreate_control(playlist);
}
- }
- }
+ else
+ {
+ NOTEF("reparsing current playlist (slow)");
+ playlist->amount = 0;
+ add_indices_to_playlist(playlist, temp_buffer,
+ temp_buffer_size);
+ }
- mutex_unlock(playlist->control_mutex);
+ /* we need to recreate control because inserted tracks are
+ now part of the playlist and shuffle has been invalidated */
+ result = recreate_control(playlist);
+ }
+ }
+ mutex_unlock(playlist->control_mutex);
}
+ if (fd >= 0)
+ close(fd);
+
cpu_boost(false);
reset_old_buffer:
@@ -3759,8 +3703,12 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
if (recurse)
{
/* recursively add directories */
- snprintf(buf, sizeof(buf), "%s/%s",
- dirname[1]? dirname: "", files[i].name);
+ if (path_append(buf, dirname, files[i].name, sizeof(buf))
+ >= sizeof(buf))
+ {
+ continue;
+ }
+
result = playlist_directory_tracksearch(buf, recurse,
callback, context);
if (result < 0)
@@ -3785,8 +3733,11 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse,
}
else if ((files[i].attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO)
{
- snprintf(buf, sizeof(buf), "%s/%s",
- dirname[1]? dirname: "", files[i].name);
+ if (path_append(buf, dirname, files[i].name, sizeof(buf))
+ >= sizeof(buf))
+ {
+ continue;
+ }
if (callback(buf, context) != 0)
{
diff --git a/apps/playlist_catalog.c b/apps/playlist_catalog.c
index 3687681b66..5741d11258 100644
--- a/apps/playlist_catalog.c
+++ b/apps/playlist_catalog.c
@@ -32,7 +32,7 @@
#include "lang.h"
#include "list.h"
#include "misc.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "onplay.h"
#include "playlist.h"
#include "settings.h"
diff --git a/apps/plugin.c b/apps/plugin.c
index 8edc773239..8a6c577f69 100644
--- a/apps/plugin.c
+++ b/apps/plugin.c
@@ -18,6 +18,8 @@
* KIND, either express or implied.
*
****************************************************************************/
+#define DIRFUNCTIONS_DEFINED
+#define FILEFUNCTIONS_DEFINED
#include "plugin.h"
#include <ctype.h>
#include <string.h>
@@ -40,8 +42,9 @@
#include "pcmbuf.h"
#include "errno.h"
#include "diacritic.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "load_code.h"
+#include "file.h"
#if CONFIG_CHARGING
#include "power.h"
@@ -58,80 +61,119 @@
#include "usbstack/usb_hid.h"
#endif
-#if defined (SIMULATOR)
-#define PREFIX(_x_) sim_ ## _x_
-#elif defined (APPLICATION)
-#define PREFIX(_x_) app_ ## _x_
+#define WRAPPER(_x_) _x_ ## _wrapper
+
+#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
+static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE];
+void sim_lcd_ex_init(unsigned long (*getpixel)(int, int));
+void sim_lcd_ex_update_rect(int x, int y, int width, int height);
#else
-#define PREFIX(_x_) _x_
+extern unsigned char pluginbuf[];
+#include "bitswap.h"
#endif
-#if defined (APPLICATION)
-/* For symmetry reasons (we want app_ and sim_ to behave similarly), some
- * wrappers are needed */
-static int app_close(int fd)
+/* for actual plugins only, not for codecs */
+static int plugin_size = 0;
+static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */
+static char current_plugin[MAX_PATH];
+/* NULL if no plugin is loaded, otherwise the handle that lc_open() returned */
+static void *current_plugin_handle;
+
+char *plugin_get_current_filename(void);
+
+static void* plugin_get_audio_buffer(size_t *buffer_size);
+static void plugin_release_audio_buffer(void);
+static void plugin_tsr(bool (*exit_callback)(bool));
+
+
+#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
+/* File handle leak prophylaxis */
+#include "bitarray.h"
+#include "file_internal.h" /* for MAX_OPEN_FILES */
+
+#define PCOC_WRAPPER(_x_) WRAPPER(_x_)
+
+BITARRAY_TYPE_DECLARE(plugin_check_open_close_bitmap_t, open_files_bitmap,
+ MAX_OPEN_FILES)
+
+static plugin_check_open_close_bitmap_t open_files_bitmap;
+
+static void plugin_check_open_close__enter(void)
{
- return close(fd);
+ if (!current_plugin_handle)
+ open_files_bitmap_clear(&open_files_bitmap);
}
-static ssize_t app_read(int fd, void *buf, size_t count)
+static void plugin_check_open_close__open(int fildes)
{
- return read(fd,buf,count);
+ if (fildes >= 0)
+ open_files_bitmap_set_bit(&open_files_bitmap, fildes);
}
-static off_t app_lseek(int fd, off_t offset, int whence)
+static void plugin_check_open_close__close(int fildes)
{
- return lseek(fd,offset,whence);
+ if (fildes < 0)
+ return;
+
+ if (!open_files_bitmap_test_bit(&open_files_bitmap, fildes))
+ {
+ logf("double close from plugin");
+ }
+
+ open_files_bitmap_clear_bit(&open_files_bitmap, fildes);
}
-static ssize_t app_write(int fd, const void *buf, size_t count)
+static int WRAPPER(open)(const char *path, int oflag, ...)
{
- return write(fd,buf,count);
+ int fildes = FS_PREFIX(open)(path, oflag __OPEN_MODE_ARG);
+ plugin_check_open_close__open(fildes);
+ return fildes;
}
-static int app_ftruncate(int fd, off_t length)
+static int WRAPPER(creat)(const char *path, mode_t mode)
{
- return ftruncate(fd,length);
+ int fildes = FS_PREFIX(creat)(path __CREAT_MODE_ARG);
+ plugin_check_open_close__open(fildes);
+ return fildes;
+ (void)mode;
}
-#endif
-#if defined(HAVE_PLUGIN_CHECK_OPEN_CLOSE) && (MAX_OPEN_FILES>32)
-#warning "MAX_OPEN_FILES>32, disabling plugin file open/close checking"
-#undef HAVE_PLUGIN_CHECK_OPEN_CLOSE
-#endif
+static int WRAPPER(close)(int fildes)
+{
+ int rc = FS_PREFIX(close)(fildes);
+ if (rc >= 0)
+ plugin_check_open_close__close(fildes);
-#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
-static unsigned int open_files;
-#endif
+ return rc;
+}
-#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
-static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE];
-void sim_lcd_ex_init(unsigned long (*getpixel)(int, int));
-void sim_lcd_ex_update_rect(int x, int y, int width, int height);
-#else
-extern unsigned char pluginbuf[];
-#include "bitswap.h"
-#endif
+static void plugin_check_open_close__exit(void)
+{
+ if (current_plugin_handle)
+ return;
-/* for actual plugins only, not for codecs */
-static int plugin_size = 0;
-static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */
-static char current_plugin[MAX_PATH];
-/* NULL if no plugin is loaded, otherwise the handle that lc_open() returned */
-static void *current_plugin_handle;
+ if (open_files_bitmap_is_clear(&open_files_bitmap))
+ return;
-char *plugin_get_current_filename(void);
+ logf("Plugin '%s' leaks file handles", plugin);
-/* Some wrappers used to monitor open and close and detect leaks*/
-static int open_wrapper(const char* pathname, int flags, ...);
-#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
-static int close_wrapper(int fd);
-static int creat_wrapper(const char *pathname, mode_t mode);
-#endif
+ static const char *lines[] =
+ { ID2P(LANG_PLUGIN_ERROR), "#leak-file-handles" };
+ static const struct text_message message = { lines, 2 };
+ button_clear_queue(); /* Empty the keyboard buffer */
+ gui_syncyesno_run(&message, NULL, NULL);
-static void* plugin_get_audio_buffer(size_t *buffer_size);
-static void plugin_release_audio_buffer(void);
-static void plugin_tsr(bool (*exit_callback)(bool));
+ FOR_EACH_BITARRAY_SET_BIT(&open_files_bitmap, fildes)
+ WRAPPER(close)(fildes);
+}
+
+#else /* !HAVE_PLUGIN_CHECK_OPEN_CLOSE */
+
+#define PCOC_WRAPPER(_x_) FS_PREFIX(_x_)
+#define plugin_check_open_close__enter()
+#define plugin_check_open_close__exit()
+
+#endif /* HAVE_PLUGIN_CHECK_OPEN_CLOSE */
static const struct plugin_api rockbox_api = {
@@ -339,24 +381,16 @@ static const struct plugin_api rockbox_api = {
/* file */
open_utf8,
- (open_func)open_wrapper,
-#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
- close_wrapper,
-#else
- PREFIX(close),
-#endif
- (read_func)PREFIX(read),
- PREFIX(lseek),
-#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
- (creat_func)creat_wrapper,
-#else
- PREFIX(creat),
-#endif
- (write_func)PREFIX(write),
- PREFIX(remove),
- PREFIX(rename),
- PREFIX(ftruncate),
- filesize,
+ PCOC_WRAPPER(open),
+ PCOC_WRAPPER(creat),
+ PCOC_WRAPPER(close),
+ FS_PREFIX(read),
+ FS_PREFIX(lseek),
+ FS_PREFIX(write),
+ FS_PREFIX(remove),
+ FS_PREFIX(rename),
+ FS_PREFIX(ftruncate),
+ FS_PREFIX(filesize),
fdprintf,
read_line,
settings_parseline,
@@ -369,18 +403,18 @@ static const struct plugin_api rockbox_api = {
#endif /* USING_STORAGE_CALLBACK */
reload_directory,
create_numbered_filename,
- file_exists,
+ FS_PREFIX(file_exists),
strip_extension,
crc_32,
filetype_get_attr,
/* dir */
- (opendir_func)opendir,
- (closedir_func)closedir,
- (readdir_func)readdir,
- mkdir,
- rmdir,
- dir_exists,
+ FS_PREFIX(opendir),
+ FS_PREFIX(closedir),
+ FS_PREFIX(readdir),
+ FS_PREFIX(mkdir),
+ FS_PREFIX(rmdir),
+ FS_PREFIX(dir_exists),
dir_get_info,
/* browsing */
@@ -688,10 +722,11 @@ static const struct plugin_api rockbox_api = {
#endif
srand,
rand,
- (qsort_func)qsort,
+ (void *)qsort,
kbd_input,
get_time,
set_time,
+ gmtime_r,
#if CONFIG_RTC
mktime,
#endif
@@ -891,9 +926,7 @@ int plugin_load(const char* plugin, const void* parameter)
/* allow voice to back off if the plugin needs lots of memory */
talk_buffer_set_policy(TALK_BUFFER_LOOSE);
-#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
- open_files = 0;
-#endif
+ plugin_check_open_close__enter();
int rc = p_hdr->entry_point(parameter);
@@ -947,24 +980,7 @@ int plugin_load(const char* plugin, const void* parameter)
FOR_NB_SCREENS(i)
viewportmanager_theme_undo(i, true);
-#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
- if(open_files != 0 && !current_plugin_handle)
- {
- int fd;
- logf("Plugin '%s' leaks file handles", plugin);
-
- static const char *lines[] =
- { ID2P(LANG_PLUGIN_ERROR),
- "#leak-file-handles" };
- static const struct text_message message={ lines, 2 };
- button_clear_queue(); /* Empty the keyboard buffer */
- gui_syncyesno_run(&message, NULL, NULL);
-
- for(fd=0; fd < MAX_OPEN_FILES; fd++)
- if(open_files & (1<<fd))
- close_wrapper(fd);
- }
-#endif
+ plugin_check_open_close__exit();
if (rc == PLUGIN_ERROR)
splash(HZ*2, str(LANG_PLUGIN_ERROR));
@@ -1027,55 +1043,3 @@ char *plugin_get_current_filename(void)
{
return current_plugin;
}
-
-static int open_wrapper(const char* pathname, int flags, ...)
-{
-/* we don't have an 'open' function. it's a define. and we need
- * the real file_open, hence PREFIX() doesn't work here */
- int fd;
-#if (CONFIG_PLATFORM & PLATFORM_HOSTED)
- if (flags & O_CREAT)
- {
- va_list ap;
- va_start(ap, flags);
- fd = open(pathname, flags, va_arg(ap, unsigned int));
- va_end(ap);
- }
- else
- fd = open(pathname, flags);
-#else
- fd = file_open(pathname,flags);
-#endif
-
-#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
- if(fd >= 0)
- open_files |= 1<<fd;
-#endif
- return fd;
-}
-
-#ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE
-static int close_wrapper(int fd)
-{
- if((~open_files) & (1<<fd))
- {
- logf("double close from plugin");
- }
- if(fd >= 0)
- open_files &= (~(1<<fd));
-
- return PREFIX(close)(fd);
-}
-
-static int creat_wrapper(const char *pathname, mode_t mode)
-{
- (void)mode;
-
- int fd = PREFIX(creat)(pathname, mode);
-
- if(fd >= 0)
- open_files |= (1<<fd);
-
- return fd;
-}
-#endif /* HAVE_PLUGIN_CHECK_OPEN_CLOSE */
diff --git a/apps/plugin.h b/apps/plugin.h
index 8b8481b6ac..e55dcf13cb 100644
--- a/apps/plugin.h
+++ b/apps/plugin.h
@@ -75,7 +75,7 @@ void* plugin_get_buffer(size_t *buffer_size);
#include "profile.h"
#endif
#include "misc.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#if (CONFIG_CODEC == SWCODEC)
#include "pcm_mixer.h"
#include "dsp-util.h"
@@ -160,12 +160,12 @@ void* plugin_get_buffer(size_t *buffer_size);
#define PLUGIN_MAGIC 0x526F634B /* RocK */
/* increase this every time the api struct changes */
-#define PLUGIN_API_VERSION 231
+#define PLUGIN_API_VERSION 232
/* update this to latest version if a change to the api struct breaks
backwards compatibility (and please take the opportunity to sort in any
new function which are "waiting" at the end of the function table) */
-#define PLUGIN_MIN_API_VERSION 231
+#define PLUGIN_MIN_API_VERSION 232
/* plugin return codes */
/* internal returns start at 0x100 to make exit(1..255) work */
@@ -433,17 +433,17 @@ struct plugin_api {
/* file */
int (*open_utf8)(const char* pathname, int flags);
- int (*open)(const char* pathname, int flags, ...);
- int (*close)(int fd);
- ssize_t (*read)(int fd, void* buf, size_t count);
- off_t (*lseek)(int fd, off_t offset, int whence);
- int (*creat)(const char *pathname, mode_t mode);
- ssize_t (*write)(int fd, const void* buf, size_t count);
- int (*remove)(const char* pathname);
- int (*rename)(const char* path, const char* newname);
- int (*ftruncate)(int fd, off_t length);
- off_t (*filesize)(int fd);
- int (*fdprintf)(int fd, const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3);
+ int (*open)(const char *path, int oflag, ...);
+ int (*creat)(const char *path, mode_t mode);
+ int (*close)(int fildes);
+ ssize_t (*read)(int fildes, void *buf, size_t nbyte);
+ off_t (*lseek)(int fildes, off_t offset, int whence);
+ ssize_t (*write)(int fildes, const void *buf, size_t nbyte);
+ int (*remove)(const char *path);
+ int (*rename)(const char *old, const char *new);
+ int (*ftruncate)(int fildes, off_t length);
+ off_t (*filesize)(int fildes);
+ int (*fdprintf)(int fildes, const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3);
int (*read_line)(int fd, char* buffer, int buffer_size);
bool (*settings_parseline)(char* line, char** name, char** value);
void (*storage_sleep)(void);
@@ -457,7 +457,7 @@ struct plugin_api {
char *(*create_numbered_filename)(char *buffer, const char *path,
const char *prefix, const char *suffix,
int numberlen IF_CNFN_NUM_(, int *num));
- bool (*file_exists)(const char *file);
+ bool (*file_exists)(const char *path);
char* (*strip_extension)(char* buffer, int buffer_size, const char *filename);
uint32_t (*crc_32)(const void *src, uint32_t len, uint32_t crc32);
@@ -466,13 +466,13 @@ struct plugin_api {
/* dir */
- DIR* (*opendir)(const char* name);
- int (*closedir)(DIR* dir);
- struct dirent* (*readdir)(DIR* dir);
- int (*mkdir)(const char *name);
- int (*rmdir)(const char *name);
- bool (*dir_exists)(const char *path);
- struct dirinfo (*dir_get_info)(DIR* parent, struct dirent *entry);
+ DIR * (*opendir)(const char *dirname);
+ int (*closedir)(DIR *dirp);
+ struct dirent * (*readdir)(DIR *dirp);
+ int (*mkdir)(const char *path);
+ int (*rmdir)(const char *path);
+ bool (*dir_exists)(const char *dirname);
+ struct dirinfo (*dir_get_info)(DIR *dirp, struct dirent *entry);
/* browsing */
void (*browse_context_init)(struct browse_context *browse,
@@ -838,6 +838,7 @@ struct plugin_api {
int (*kbd_input)(char* buffer, int buflen);
struct tm* (*get_time)(void);
int (*set_time)(const struct tm *tm);
+ struct tm * (*gmtime_r)(const time_t *timep, struct tm *tm);
#if CONFIG_RTC
time_t (*mktime)(struct tm *t);
#endif
diff --git a/apps/plugins/properties.c b/apps/plugins/properties.c
index 0f3ec5c458..3115da94a4 100644
--- a/apps/plugins/properties.c
+++ b/apps/plugins/properties.c
@@ -99,13 +99,12 @@ static bool file_properties(char* selected_file)
log = human_size_log((unsigned long)info.size);
rb->snprintf(str_size, sizeof str_size, "%lu %cB",
((unsigned long)info.size) >> (log*10), human_size_prefix[log]);
+ struct tm tm;
+ rb->gmtime_r(&info.mtime, &tm);
rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d",
- ((info.wrtdate >> 9 ) & 0x7F) + 1980, /* year */
- ((info.wrtdate >> 5 ) & 0x0F), /* month */
- ((info.wrtdate ) & 0x1F)); /* day */
- rb->snprintf(str_time, sizeof str_time, "%02d:%02d",
- ((info.wrttime >> 11) & 0x1F), /* hour */
- ((info.wrttime >> 5 ) & 0x3F)); /* minutes */
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+ rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d",
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
num_properties = 5;
@@ -175,7 +174,10 @@ static bool _dir_properties(DPS* dps)
dirlen = rb->strlen(dps->dirname);
dir = rb->opendir(dps->dirname);
if (!dir)
+ {
+ rb->splashf(HZ*2, "%s", dps->dirname);
return false; /* open error */
+ }
/* walk through the directory content */
while(result && (0 != (entry = rb->readdir(dir))))
diff --git a/apps/radio/presets.c b/apps/radio/presets.c
index 9eab4901f1..d9a2aa9bcd 100644
--- a/apps/radio/presets.c
+++ b/apps/radio/presets.c
@@ -30,7 +30,7 @@
#include "file.h"
#include "string-extra.h"
#include "misc.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "lang.h"
#include "action.h"
#include "list.h"
diff --git a/apps/radio/radioart.c b/apps/radio/radioart.c
index 283815167a..5e1a0ad5cf 100644
--- a/apps/radio/radioart.c
+++ b/apps/radio/radioart.c
@@ -31,7 +31,7 @@
#include "file.h"
#include "kernel.h"
#include "string-extra.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "core_alloc.h"
#define MAX_RADIOART_IMAGES 10
diff --git a/apps/recorder/albumart.c b/apps/recorder/albumart.c
index 4cbabbc8ce..c561e36ae2 100644
--- a/apps/recorder/albumart.c
+++ b/apps/recorder/albumart.c
@@ -27,7 +27,7 @@
#include "buffering.h"
#include "dircache.h"
#include "misc.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "settings.h"
#include "wps.h"
diff --git a/apps/recorder/recording.c b/apps/recorder/recording.c
index 5b341fd141..1c53c8026f 100644
--- a/apps/recorder/recording.c
+++ b/apps/recorder/recording.c
@@ -56,7 +56,7 @@
#include "timefuncs.h"
#include "debug.h"
#include "misc.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "tree.h"
#include "string.h"
#include "dir.h"
diff --git a/apps/root_menu.c b/apps/root_menu.c
index 189b2ec35c..7ec803f585 100644
--- a/apps/root_menu.c
+++ b/apps/root_menu.c
@@ -146,11 +146,10 @@ static int browser(void* param)
int i;
for (i = 0; i < NUM_VOLUMES; i++)
{
- char vol_string[VOL_ENUM_POS + 8];
+ char vol_string[VOL_MAX_LEN + 1];
if (!volume_removable(i))
continue;
- /* VOL_NAMES contains a %d */
- snprintf(vol_string, sizeof(vol_string), "/"VOL_NAMES, i);
+ get_volume_name(i, vol_string);
/* test whether we would browse the external card */
if (!volume_present(i) &&
(strstr(last_folder, vol_string)
diff --git a/apps/scrobbler.c b/apps/scrobbler.c
index b8a95f85cb..4f3693e716 100644
--- a/apps/scrobbler.c
+++ b/apps/scrobbler.c
@@ -33,7 +33,7 @@ http://www.audioscrobbler.net/wiki/Portable_Player_Logging
#include "core_alloc.h"
#include "settings.h"
#include "ata_idle_notify.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "appevents.h"
#if CONFIG_RTC
diff --git a/apps/settings.c b/apps/settings.c
index f2a923e24d..819924a421 100644
--- a/apps/settings.c
+++ b/apps/settings.c
@@ -822,6 +822,10 @@ void settings_apply(bool read_disk)
#ifdef HAVE_LCD_BITMAP
int rc;
#endif
+ CHART(">set_codepage");
+ set_codepage(global_settings.default_codepage);
+ CHART("<set_codepage");
+
sound_settings_apply();
#ifdef HAVE_DISK_STORAGE
@@ -1008,10 +1012,6 @@ void settings_apply(bool read_disk)
lcd_scroll_delay(global_settings.scroll_delay);
- CHART(">set_codepage");
- set_codepage(global_settings.default_codepage);
- CHART("<set_codepage");
-
#ifdef HAVE_PLAY_FREQ
settings_apply_play_freq(global_settings.play_frequency, false);
#endif
diff --git a/apps/settings_list.c b/apps/settings_list.c
index af83866356..53acb78d98 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -1724,13 +1724,13 @@ const struct settings_list settings[] = {
OFFON_SETTING(F_BANFROMQS, tagcache_autoupdate, LANG_TAGCACHE_AUTOUPDATE, false,
"tagcache_autoupdate", NULL),
#endif
- CHOICE_SETTING(0, default_codepage, LANG_DEFAULT_CODEPAGE, 0,
+ CHOICE_SETTING(F_TEMPVAR, default_codepage, LANG_DEFAULT_CODEPAGE, 0,
"default codepage",
#ifdef HAVE_LCD_BITMAP
/* The order must match with that in unicode.c */
"iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256,"
"iso8859-9,iso8859-2,cp1250,cp1252,sjis,gb2312,ksx1001,big5,utf-8",
- set_codepage, 15,
+ NULL, 15,
ID2P(LANG_CODEPAGE_LATIN1),
ID2P(LANG_CODEPAGE_GREEK),
ID2P(LANG_CODEPAGE_HEBREW), ID2P(LANG_CODEPAGE_CYRILLIC),
@@ -1745,7 +1745,7 @@ const struct settings_list settings[] = {
#else /* !HAVE_LCD_BITMAP */
/* The order must match with that in unicode.c */
"iso8859-1,iso8859-7,cp1251,iso8859-9,iso8859-2,cp1250,cp1252,utf-8",
- set_codepage, 8,
+ NULL, 8,
ID2P(LANG_CODEPAGE_LATIN1), ID2P(LANG_CODEPAGE_GREEK),
ID2P(LANG_CODEPAGE_CYRILLIC), ID2P(LANG_CODEPAGE_TURKISH),
ID2P(LANG_CODEPAGE_LATIN_EXTENDED),
diff --git a/apps/shortcuts.c b/apps/shortcuts.c
index a9ae8248f1..1153edd2ad 100644
--- a/apps/shortcuts.c
+++ b/apps/shortcuts.c
@@ -37,7 +37,7 @@
#include "misc.h"
#include "tree.h"
#include "splash.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "filetypes.h"
#include "shortcuts.h"
#include "onplay.h"
diff --git a/apps/tagcache.c b/apps/tagcache.c
index b7d5516e81..2b6041227b 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -79,7 +79,7 @@
#include "misc.h"
#include "settings.h"
#include "dir.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "structec.h"
#include "debug.h"
@@ -88,6 +88,8 @@
#include "eeprom_settings.h"
#endif
+#undef HAVE_DIRCACHE
+
#ifdef __PCTOOL__
#define yield() do { } while(0)
#define sim_sleep(timeout) do { } while(0)
@@ -2986,20 +2988,21 @@ static bool commit(void)
/* Try to steal every buffer we can :) */
if (tempbuf_size == 0)
local_allocation = true;
-
+
+#if 0 /* FIXME: How much big? dircache buffer can no longer be taken but
+ may be freed to make room and the cache resumed. --jethead71 */
#ifdef HAVE_DIRCACHE
if (tempbuf_size == 0)
{
- /* Try to steal the dircache buffer. */
- tempbuf = dircache_steal_buffer(&tempbuf_size);
- tempbuf_size &= ~0x03;
-
+ /* Shut down dircache to free its allocation. */
+ dircache_free_buffer();
if (tempbuf_size > 0)
{
dircache_buffer_stolen = true;
}
}
-#endif
+#endif
+#endif
#ifdef HAVE_TC_RAMCACHE
if (tempbuf_size == 0 && tc_stat.ramcache_allocated > 0)
@@ -4462,7 +4465,7 @@ static bool check_dir(const char *dirname, int add_files)
tc_stat.curentry = curpath;
/* Add a new entry to the temporary db file. */
- add_tagcache(curpath, (info.wrtdate << 16) | info.wrttime
+ add_tagcache(curpath, info.mtime
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
, dir->internal_entry
#endif
@@ -4780,7 +4783,7 @@ void tagcache_shutdown(void)
/* Flush the command queue. */
run_command_queue(true);
-#ifdef HAVE_EEPROM_SETTINGS
+#if defined(HAVE_EEPROM_SETTINGS) && defined(HAVE_TC_RAMCACHE)
if (tc_stat.ramcache)
tagcache_dumpsave();
#endif
diff --git a/apps/tree.c b/apps/tree.c
index f72774fe1e..938e44d350 100644
--- a/apps/tree.c
+++ b/apps/tree.c
@@ -52,7 +52,7 @@
#include "talk.h"
#include "filetypes.h"
#include "misc.h"
-#include "filefuncs.h"
+#include "pathfuncs.h"
#include "filetree.h"
#include "tagtree.h"
#ifdef HAVE_RECORDING
@@ -1205,26 +1205,36 @@ void tree_flush(void)
#endif
#ifdef HAVE_DIRCACHE
+ int old_val = global_status.dircache_size;
+#ifdef HAVE_EEPROM_SETTINGS
+ bool savecache = false;
+#endif
+
+ if (global_settings.dircache)
{
- int old_val = global_status.dircache_size;
- if (global_settings.dircache)
- {
- if (!dircache_is_initializing())
- global_status.dircache_size = dircache_get_cache_size();
-# ifdef HAVE_EEPROM_SETTINGS
- if (firmware_settings.initialized)
- dircache_save();
-# endif
- dircache_suspend();
- }
- else
- {
- global_status.dircache_size = 0;
- }
- if (old_val != global_status.dircache_size)
- status_save();
+ dircache_suspend();
+
+ struct dircache_info info;
+ dircache_get_info(&info);
+
+ global_status.dircache_size = info.last_size;
+ #ifdef HAVE_EEPROM_SETTINGS
+ savecache = firmware_settings.initialized;
+ #endif
}
-#endif
+ else
+ {
+ global_status.dircache_size = 0;
+ }
+
+ if (old_val != global_status.dircache_size)
+ status_save();
+
+ #ifdef HAVE_EEPROM_SETTINGS
+ if (savecache)
+ dircache_save();
+ #endif
+#endif /* HAVE_DIRCACHE */
}
void tree_restore(void)
@@ -1238,15 +1248,14 @@ void tree_restore(void)
#endif
#ifdef HAVE_DIRCACHE
- remove(DIRCACHE_FILE);
- if (global_settings.dircache)
+ if (global_settings.dircache && dircache_resume() > 0)
{
/* Print "Scanning disk..." to the display. */
splash(0, str(LANG_SCANNING_DISK));
-
- dircache_build(global_status.dircache_size);
+ dircache_wait();
}
#endif
+
#ifdef HAVE_TAGCACHE
tagcache_start_scan();
#endif