diff options
Diffstat (limited to 'apps')
-rw-r--r-- | apps/bookmark.c | 8 | ||||
-rw-r--r-- | apps/codecs.c | 2 | ||||
-rw-r--r-- | apps/debug_menu.c | 86 | ||||
-rw-r--r-- | apps/filetree.c | 4 | ||||
-rw-r--r-- | apps/main.c | 102 | ||||
-rw-r--r-- | apps/menus/display_menu.c | 20 | ||||
-rw-r--r-- | apps/menus/main_menu.c | 18 | ||||
-rw-r--r-- | apps/menus/settings_menu.c | 6 | ||||
-rw-r--r-- | apps/misc.c | 16 | ||||
-rw-r--r-- | apps/onplay.c | 844 | ||||
-rwxr-xr-x | apps/playlist.c | 237 | ||||
-rw-r--r-- | apps/playlist_catalog.c | 2 | ||||
-rw-r--r-- | apps/plugin.c | 264 | ||||
-rw-r--r-- | apps/plugin.h | 45 | ||||
-rw-r--r-- | apps/plugins/properties.c | 14 | ||||
-rw-r--r-- | apps/radio/presets.c | 2 | ||||
-rw-r--r-- | apps/radio/radioart.c | 2 | ||||
-rw-r--r-- | apps/recorder/albumart.c | 2 | ||||
-rw-r--r-- | apps/recorder/recording.c | 2 | ||||
-rw-r--r-- | apps/root_menu.c | 5 | ||||
-rw-r--r-- | apps/scrobbler.c | 2 | ||||
-rw-r--r-- | apps/settings.c | 8 | ||||
-rw-r--r-- | apps/settings_list.c | 6 | ||||
-rw-r--r-- | apps/shortcuts.c | 2 | ||||
-rw-r--r-- | apps/tagcache.c | 21 | ||||
-rw-r--r-- | apps/tree.c | 55 |
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 @@ | |||
41 | #include "list.h" | 41 | #include "list.h" |
42 | #include "plugin.h" | 42 | #include "plugin.h" |
43 | #include "file.h" | 43 | #include "file.h" |
44 | #include "filefuncs.h" | 44 | #include "pathfuncs.h" |
45 | 45 | ||
46 | #define MAX_BOOKMARKS 10 | 46 | #define MAX_BOOKMARKS 10 |
47 | #define MAX_BOOKMARK_SIZE 350 | 47 | #define MAX_BOOKMARK_SIZE 350 |
@@ -1090,10 +1090,10 @@ static bool generate_bookmark_file_name(const char *in) | |||
1090 | { | 1090 | { |
1091 | #ifdef HAVE_MULTIVOLUME | 1091 | #ifdef HAVE_MULTIVOLUME |
1092 | /* The "root" of an extra volume need special handling too. */ | 1092 | /* The "root" of an extra volume need special handling too. */ |
1093 | bool volume_root = (strip_volume(in, global_bookmark_file_name) && | 1093 | const char *filename; |
1094 | !strcmp("/", global_bookmark_file_name)); | 1094 | path_strip_volume(in, &filename, true); |
1095 | bool volume_root = *filename == '\0'; | ||
1095 | #endif | 1096 | #endif |
1096 | |||
1097 | strcpy(global_bookmark_file_name, in); | 1097 | strcpy(global_bookmark_file_name, in); |
1098 | if(global_bookmark_file_name[len-1] == '/') | 1098 | if(global_bookmark_file_name[len-1] == '/') |
1099 | len--; | 1099 | 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 = { | |||
128 | logf, | 128 | logf, |
129 | #endif | 129 | #endif |
130 | 130 | ||
131 | (qsort_func)qsort, | 131 | (void *)qsort, |
132 | 132 | ||
133 | #ifdef RB_PROFILE | 133 | #ifdef RB_PROFILE |
134 | profile_thread, | 134 | 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, | |||
528 | { | 528 | { |
529 | (void)data; | 529 | (void)data; |
530 | int partition = selected_item/2; | 530 | int partition = selected_item/2; |
531 | struct partinfo* p = disk_partinfo(partition); | 531 | |
532 | struct partinfo p; | ||
533 | if (!disk_partinfo(partition, &p)) | ||
534 | return buffer; | ||
535 | |||
532 | if (selected_item%2) | 536 | if (selected_item%2) |
533 | { | 537 | { |
534 | snprintf(buffer, buffer_len, " T:%x %ld MB", p->type, p->size / ( 2048 / ( SECTOR_SIZE / 512 ))); | 538 | snprintf(buffer, buffer_len, " T:%x %ld MB", p.type, |
539 | p.size / ( 2048 / ( SECTOR_SIZE / 512 ))); | ||
535 | } | 540 | } |
536 | else | 541 | else |
537 | { | 542 | { |
538 | snprintf(buffer, buffer_len, "P%d: S:%lx", partition, p->start); | 543 | snprintf(buffer, buffer_len, "P%d: S:%lx", partition, p.start); |
539 | } | 544 | } |
540 | return buffer; | 545 | return buffer; |
541 | } | 546 | } |
@@ -1377,7 +1382,7 @@ static int disk_callback(int btn, struct gui_synclist *lists) | |||
1377 | simplelist_addline( | 1382 | simplelist_addline( |
1378 | "Size: %s", buf); | 1383 | "Size: %s", buf); |
1379 | unsigned long free; | 1384 | unsigned long free; |
1380 | fat_size( IF_MV(0,) NULL, &free ); | 1385 | volume_size( IF_MV(0,) NULL, &free ); |
1381 | simplelist_addline( | 1386 | simplelist_addline( |
1382 | "Free: %ld MB", free / 1024); | 1387 | "Free: %ld MB", free / 1024); |
1383 | simplelist_addline( | 1388 | simplelist_addline( |
@@ -1469,7 +1474,7 @@ static int disk_callback(int btn, struct gui_synclist *lists) | |||
1469 | "No timing info"); | 1474 | "No timing info"); |
1470 | } | 1475 | } |
1471 | simplelist_addline( | 1476 | simplelist_addline( |
1472 | "Cluster size: %d bytes", fat_get_cluster_size(IF_MV(0))); | 1477 | "Cluster size: %d bytes", volume_get_cluster_size(IF_MV(0))); |
1473 | #ifdef HAVE_ATA_DMA | 1478 | #ifdef HAVE_ATA_DMA |
1474 | i = ata_get_dma_mode(); | 1479 | i = ata_get_dma_mode(); |
1475 | if (i == 0) { | 1480 | if (i == 0) { |
@@ -1496,11 +1501,11 @@ static int disk_callback(int btn, struct gui_synclist *lists) | |||
1496 | simplelist_addline( | 1501 | simplelist_addline( |
1497 | "Size: %ld MB", info.num_sectors*(info.sector_size/512)/2024); | 1502 | "Size: %ld MB", info.num_sectors*(info.sector_size/512)/2024); |
1498 | unsigned long free; | 1503 | unsigned long free; |
1499 | fat_size( IF_MV(0,) NULL, &free ); | 1504 | volume_size( IF_MV(0,) NULL, &free ); |
1500 | simplelist_addline( | 1505 | simplelist_addline( |
1501 | "Free: %ld MB", free / 1024); | 1506 | "Free: %ld MB", free / 1024); |
1502 | simplelist_addline( | 1507 | simplelist_addline( |
1503 | "Cluster size: %d bytes", fat_get_cluster_size(IF_MV(0))); | 1508 | "Cluster size: %d bytes", volume_get_cluster_size(IF_MV(0))); |
1504 | return btn; | 1509 | return btn; |
1505 | } | 1510 | } |
1506 | #endif | 1511 | #endif |
@@ -1542,29 +1547,64 @@ static bool dbg_disk_info(void) | |||
1542 | #ifdef HAVE_DIRCACHE | 1547 | #ifdef HAVE_DIRCACHE |
1543 | static int dircache_callback(int btn, struct gui_synclist *lists) | 1548 | static int dircache_callback(int btn, struct gui_synclist *lists) |
1544 | { | 1549 | { |
1545 | (void)lists; | 1550 | struct dircache_info info; |
1551 | dircache_get_info(&info); | ||
1552 | |||
1553 | if (global_settings.dircache) | ||
1554 | { | ||
1555 | switch (btn) | ||
1556 | { | ||
1557 | case ACTION_STD_CONTEXT: | ||
1558 | splash(HZ/2, "Rebuilding cache"); | ||
1559 | dircache_suspend(); | ||
1560 | *(int *)lists->data = dircache_resume(); | ||
1561 | case ACTION_UNKNOWN: | ||
1562 | btn = ACTION_NONE; | ||
1563 | break; | ||
1564 | #ifdef DIRCACHE_DUMPSTER | ||
1565 | case ACTION_STD_OK: | ||
1566 | splash(0, "Dumping cache"); | ||
1567 | dircache_dump(); | ||
1568 | btn = ACTION_NONE; | ||
1569 | break; | ||
1570 | #endif /* DIRCACHE_DUMPSTER */ | ||
1571 | case ACTION_STD_CANCEL: | ||
1572 | if (*(int *)lists->data > 0 && info.status == DIRCACHE_SCANNING) | ||
1573 | { | ||
1574 | splash(HZ, str(LANG_SCANNING_DISK)); | ||
1575 | btn = ACTION_NONE; | ||
1576 | } | ||
1577 | break; | ||
1578 | } | ||
1579 | } | ||
1580 | |||
1546 | simplelist_set_line_count(0); | 1581 | simplelist_set_line_count(0); |
1547 | simplelist_addline("Cache initialized: %s", | 1582 | |
1548 | dircache_is_enabled() ? "Yes" : "No"); | 1583 | simplelist_addline("Cache status: %s", info.statusdesc); |
1549 | simplelist_addline("Cache size: %d B", | 1584 | simplelist_addline("Last size: %lu B", info.last_size); |
1550 | dircache_get_cache_size()); | 1585 | simplelist_addline("Size: %lu B", info.size); |
1551 | simplelist_addline("Last size: %d B", | 1586 | unsigned int utilized = info.size ? 1000ull*info.sizeused / info.size : 0; |
1552 | global_status.dircache_size); | 1587 | simplelist_addline("Used: %lu B (%u.%u%%)", info.sizeused, |
1553 | simplelist_addline("Limit: %d B", | 1588 | utilized / 10, utilized % 10); |
1554 | DIRCACHE_LIMIT); | 1589 | simplelist_addline("Limit: %lu B", info.size_limit); |
1555 | simplelist_addline("Reserve: %d/%d B", | 1590 | simplelist_addline("Reserve: %lu/%lu B", info.reserve_used, info.reserve); |
1556 | dircache_get_reserve_used(), DIRCACHE_RESERVE); | 1591 | long ticks = ALIGN_UP(info.build_ticks, HZ / 10); |
1557 | simplelist_addline("Scanning took: %d s", | 1592 | simplelist_addline("Scanning took: %ld.%ld s", |
1558 | dircache_get_build_ticks() / HZ); | 1593 | ticks / HZ, (ticks*10 / HZ) % 10); |
1559 | simplelist_addline("Entry count: %d", | 1594 | simplelist_addline("Entry count: %u", info.entry_count); |
1560 | dircache_get_entry_count()); | 1595 | |
1596 | if (btn == ACTION_NONE) | ||
1597 | btn = ACTION_REDRAW; | ||
1598 | |||
1561 | return btn; | 1599 | return btn; |
1600 | (void)lists; | ||
1562 | } | 1601 | } |
1563 | 1602 | ||
1564 | static bool dbg_dircache_info(void) | 1603 | static bool dbg_dircache_info(void) |
1565 | { | 1604 | { |
1566 | struct simplelist_info info; | 1605 | struct simplelist_info info; |
1567 | simplelist_info_init(&info, "Dircache Info", 7, NULL); | 1606 | int syncbuild = 0; |
1607 | simplelist_info_init(&info, "Dircache Info", 8, &syncbuild); | ||
1568 | info.action_callback = dircache_callback; | 1608 | info.action_callback = dircache_callback; |
1569 | info.hide_selection = true; | 1609 | info.hide_selection = true; |
1570 | info.scroll_all = true; | 1610 | 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) | |||
376 | ++files_in_dir; | 376 | ++files_in_dir; |
377 | 377 | ||
378 | dptr->name = core_get_data(c->cache.name_buffer_handle)+name_buffer_used; | 378 | dptr->name = core_get_data(c->cache.name_buffer_handle)+name_buffer_used; |
379 | dptr->time_write = | 379 | dptr->time_write = info.mtime; |
380 | (long)info.wrtdate<<16 | | ||
381 | (long)info.wrttime; /* in one # */ | ||
382 | strcpy(dptr->name, (char *)entry->d_name); | 380 | strcpy(dptr->name, (char *)entry->d_name); |
383 | name_buffer_used += len + 1; | 381 | name_buffer_used += len + 1; |
384 | 382 | ||
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 @@ | |||
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #include "config.h" | 21 | #include "config.h" |
22 | #include "system.h" | ||
22 | 23 | ||
23 | #include "gcc_extensions.h" | 24 | #include "gcc_extensions.h" |
24 | #include "storage.h" | 25 | #include "storage.h" |
25 | #include "disk.h" | 26 | #include "disk.h" |
26 | #include "fat.h" | 27 | #include "file_internal.h" |
27 | #include "lcd.h" | 28 | #include "lcd.h" |
28 | #include "rtc.h" | 29 | #include "rtc.h" |
29 | #include "debug.h" | 30 | #include "debug.h" |
@@ -34,7 +35,6 @@ | |||
34 | #include "filetypes.h" | 35 | #include "filetypes.h" |
35 | #include "panic.h" | 36 | #include "panic.h" |
36 | #include "menu.h" | 37 | #include "menu.h" |
37 | #include "system.h" | ||
38 | #include "usb.h" | 38 | #include "usb.h" |
39 | #include "powermgmt.h" | 39 | #include "powermgmt.h" |
40 | #include "adc.h" | 40 | #include "adc.h" |
@@ -203,80 +203,53 @@ int main(void) | |||
203 | root_menu(); | 203 | root_menu(); |
204 | } | 204 | } |
205 | 205 | ||
206 | static int init_dircache(bool preinit) INIT_ATTR; | ||
207 | static int init_dircache(bool preinit) | ||
208 | { | ||
209 | #ifdef HAVE_DIRCACHE | 206 | #ifdef HAVE_DIRCACHE |
210 | int result = 0; | 207 | static int INIT_ATTR init_dircache(bool preinit) |
211 | bool clear = false; | 208 | { |
212 | |||
213 | if (preinit) | 209 | if (preinit) |
214 | dircache_init(); | 210 | dircache_init(MAX(global_status.dircache_size, 0)); |
215 | 211 | ||
216 | if (!global_settings.dircache) | 212 | if (!global_settings.dircache) |
217 | return 0; | 213 | return -1; |
214 | |||
215 | int result = -1; | ||
218 | 216 | ||
219 | # ifdef HAVE_EEPROM_SETTINGS | 217 | #ifdef HAVE_EEPROM_SETTINGS |
220 | if (firmware_settings.initialized && firmware_settings.disk_clean | 218 | if (firmware_settings.initialized && |
221 | && preinit) | 219 | firmware_settings.disk_clean && |
220 | preinit) | ||
222 | { | 221 | { |
223 | result = dircache_load(); | 222 | result = dircache_load(); |
224 | |||
225 | if (result < 0) | 223 | if (result < 0) |
226 | { | ||
227 | firmware_settings.disk_clean = false; | 224 | firmware_settings.disk_clean = false; |
228 | if (global_status.dircache_size <= 0) | ||
229 | { | ||
230 | /* This will be in default language, settings are not | ||
231 | applied yet. Not really any easy way to fix that. */ | ||
232 | splash(0, str(LANG_SCANNING_DISK)); | ||
233 | clear = true; | ||
234 | } | ||
235 | |||
236 | dircache_build(global_status.dircache_size); | ||
237 | } | ||
238 | } | 225 | } |
239 | else | 226 | else |
240 | # endif | 227 | #endif /* HAVE_EEPROM_SETTINGS */ |
228 | if (!preinit) | ||
241 | { | 229 | { |
242 | if (preinit) | 230 | result = dircache_enable(); |
243 | return -1; | 231 | if (result != 0) |
244 | |||
245 | if (!dircache_is_enabled() | ||
246 | && !dircache_is_initializing()) | ||
247 | { | 232 | { |
248 | if (global_status.dircache_size <= 0) | 233 | if (result > 0) |
249 | { | 234 | { |
235 | /* Print "Scanning disk..." to the display. */ | ||
250 | splash(0, str(LANG_SCANNING_DISK)); | 236 | splash(0, str(LANG_SCANNING_DISK)); |
251 | clear = true; | 237 | dircache_wait(); |
238 | backlight_on(); | ||
239 | show_logo(); | ||
252 | } | 240 | } |
253 | result = dircache_build(global_status.dircache_size); | ||
254 | } | ||
255 | 241 | ||
256 | if (result < 0) | 242 | struct dircache_info info; |
257 | { | 243 | dircache_get_info(&info); |
258 | /* Initialization of dircache failed. Manual action is | 244 | global_status.dircache_size = info.size; |
259 | * necessary to enable dircache again. | 245 | status_save(); |
260 | */ | ||
261 | splashf(0, "Dircache failed, disabled. Result: %d", result); | ||
262 | global_settings.dircache = false; | ||
263 | } | 246 | } |
264 | } | 247 | /* else don't wait or already enabled by load */ |
265 | |||
266 | if (clear) | ||
267 | { | ||
268 | backlight_on(); | ||
269 | show_logo(); | ||
270 | global_status.dircache_size = dircache_get_cache_size(); | ||
271 | status_save(); | ||
272 | } | 248 | } |
273 | 249 | ||
274 | return result; | 250 | return result; |
275 | #else | ||
276 | (void)preinit; | ||
277 | return 0; | ||
278 | #endif | ||
279 | } | 251 | } |
252 | #endif /* HAVE_DIRCACHE */ | ||
280 | 253 | ||
281 | #ifdef HAVE_TAGCACHE | 254 | #ifdef HAVE_TAGCACHE |
282 | static void init_tagcache(void) INIT_ATTR; | 255 | static void init_tagcache(void) INIT_ATTR; |
@@ -363,6 +336,7 @@ static void init(void) | |||
363 | button_init(); | 336 | button_init(); |
364 | powermgmt_init(); | 337 | powermgmt_init(); |
365 | backlight_init(); | 338 | backlight_init(); |
339 | unicode_init(); | ||
366 | #ifdef SIMULATOR | 340 | #ifdef SIMULATOR |
367 | sim_tasks_init(); | 341 | sim_tasks_init(); |
368 | #endif | 342 | #endif |
@@ -392,8 +366,10 @@ static void init(void) | |||
392 | settings_reset(); | 366 | settings_reset(); |
393 | settings_load(SETTINGS_ALL); | 367 | settings_load(SETTINGS_ALL); |
394 | settings_apply(true); | 368 | settings_apply(true); |
369 | #ifdef HAVE_DIRCACHE | ||
395 | init_dircache(true); | 370 | init_dircache(true); |
396 | init_dircache(false); | 371 | init_dircache(false); |
372 | #endif | ||
397 | #ifdef HAVE_TAGCACHE | 373 | #ifdef HAVE_TAGCACHE |
398 | init_tagcache(); | 374 | init_tagcache(); |
399 | #endif | 375 | #endif |
@@ -429,6 +405,8 @@ static void init(void) | |||
429 | 405 | ||
430 | #else | 406 | #else |
431 | 407 | ||
408 | #include "errno.h" | ||
409 | |||
432 | static void init(void) INIT_ATTR; | 410 | static void init(void) INIT_ATTR; |
433 | static void init(void) | 411 | static void init(void) |
434 | { | 412 | { |
@@ -443,6 +421,9 @@ static void init(void) | |||
443 | core_allocator_init(); | 421 | core_allocator_init(); |
444 | kernel_init(); | 422 | kernel_init(); |
445 | 423 | ||
424 | /* early early early! */ | ||
425 | filesystem_init(); | ||
426 | |||
446 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | 427 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ |
447 | set_cpu_frequency(CPUFREQ_NORMAL); | 428 | set_cpu_frequency(CPUFREQ_NORMAL); |
448 | #ifdef CPU_COLDFIRE | 429 | #ifdef CPU_COLDFIRE |
@@ -462,6 +443,7 @@ static void init(void) | |||
462 | /* current_tick should be ticking by now */ | 443 | /* current_tick should be ticking by now */ |
463 | CHART("ticking"); | 444 | CHART("ticking"); |
464 | 445 | ||
446 | unicode_init(); | ||
465 | lcd_init(); | 447 | lcd_init(); |
466 | #ifdef HAVE_REMOTE_LCD | 448 | #ifdef HAVE_REMOTE_LCD |
467 | lcd_remote_init(); | 449 | lcd_remote_init(); |
@@ -558,8 +540,6 @@ static void init(void) | |||
558 | } | 540 | } |
559 | #endif | 541 | #endif |
560 | 542 | ||
561 | |||
562 | disk_init_subsystem(); | ||
563 | CHART(">storage_init"); | 543 | CHART(">storage_init"); |
564 | rc = storage_init(); | 544 | rc = storage_init(); |
565 | CHART("<storage_init"); | 545 | CHART("<storage_init"); |
@@ -661,22 +641,24 @@ static void init(void) | |||
661 | CHART("<settings_load(ALL)"); | 641 | CHART("<settings_load(ALL)"); |
662 | } | 642 | } |
663 | 643 | ||
644 | #ifdef HAVE_DIRCACHE | ||
664 | CHART(">init_dircache(true)"); | 645 | CHART(">init_dircache(true)"); |
665 | rc = init_dircache(true); | 646 | rc = init_dircache(true); |
666 | CHART("<init_dircache(true)"); | 647 | CHART("<init_dircache(true)"); |
667 | if (rc < 0) | ||
668 | { | ||
669 | #ifdef HAVE_TAGCACHE | 648 | #ifdef HAVE_TAGCACHE |
649 | if (rc < 0) | ||
670 | remove(TAGCACHE_STATEFILE); | 650 | remove(TAGCACHE_STATEFILE); |
671 | #endif | 651 | #endif /* HAVE_TAGCACHE */ |
672 | } | 652 | #endif /* HAVE_DIRCACHE */ |
673 | 653 | ||
674 | CHART(">settings_apply(true)"); | 654 | CHART(">settings_apply(true)"); |
675 | settings_apply(true); | 655 | settings_apply(true); |
676 | CHART("<settings_apply(true)"); | 656 | CHART("<settings_apply(true)"); |
657 | #ifdef HAVE_DIRCACHE | ||
677 | CHART(">init_dircache(false)"); | 658 | CHART(">init_dircache(false)"); |
678 | init_dircache(false); | 659 | init_dircache(false); |
679 | CHART("<init_dircache(false)"); | 660 | CHART("<init_dircache(false)"); |
661 | #endif | ||
680 | #ifdef HAVE_TAGCACHE | 662 | #ifdef HAVE_TAGCACHE |
681 | CHART(">init_tagcache"); | 663 | CHART(">init_tagcache"); |
682 | init_tagcache(); | 664 | 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 @@ | |||
43 | #endif | 43 | #endif |
44 | #include "viewport.h" | 44 | #include "viewport.h" |
45 | #include "statusbar.h" /* statusbar_vals enum*/ | 45 | #include "statusbar.h" /* statusbar_vals enum*/ |
46 | #include "rbunicode.h" | ||
46 | 47 | ||
47 | #ifdef HAVE_BACKLIGHT | 48 | #ifdef HAVE_BACKLIGHT |
48 | static int filterfirstkeypress_callback(int action,const struct menu_item_ex *this_item) | 49 | 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, | |||
524 | &touchscreen_menu_calibrate, &touchscreen_menu_reset_calibration); | 525 | &touchscreen_menu_calibrate, &touchscreen_menu_reset_calibration); |
525 | #endif | 526 | #endif |
526 | 527 | ||
528 | static int codepage_callback(int action, const struct menu_item_ex *this_item) | ||
529 | { | ||
530 | static int old_codepage; | ||
531 | int new_codepage = global_settings.default_codepage; | ||
532 | (void)this_item; | ||
533 | switch (action) | ||
534 | { | ||
535 | case ACTION_ENTER_MENUITEM: | ||
536 | old_codepage = new_codepage; | ||
537 | break; | ||
538 | case ACTION_EXIT_MENUITEM: | ||
539 | if (new_codepage != old_codepage) | ||
540 | set_codepage(new_codepage); | ||
541 | break; | ||
542 | } | ||
543 | return action; | ||
544 | } | ||
527 | 545 | ||
528 | MENUITEM_SETTING(codepage_setting, &global_settings.default_codepage, NULL); | 546 | MENUITEM_SETTING(codepage_setting, &global_settings.default_codepage, codepage_callback); |
529 | 547 | ||
530 | 548 | ||
531 | MAKE_MENU(display_menu, ID2P(LANG_DISPLAY), | 549 | 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 @@ | |||
48 | #include "time.h" | 48 | #include "time.h" |
49 | #include "wps.h" | 49 | #include "wps.h" |
50 | #include "skin_buffer.h" | 50 | #include "skin_buffer.h" |
51 | #include "disk.h" | ||
51 | 52 | ||
52 | static const struct browse_folder_info config = {ROCKBOX_DIR, SHOW_CFG}; | 53 | static const struct browse_folder_info config = {ROCKBOX_DIR, SHOW_CFG}; |
53 | 54 | ||
@@ -160,14 +161,14 @@ static const char* info_getname(int selected_item, void *data, | |||
160 | #endif | 161 | #endif |
161 | if (info->new_data) | 162 | if (info->new_data) |
162 | { | 163 | { |
163 | fat_size(IF_MV(0,) &info->size, &info->free); | 164 | volume_size(IF_MV(0,) &info->size, &info->free); |
164 | #ifdef HAVE_MULTIVOLUME | 165 | #ifdef HAVE_MULTIVOLUME |
165 | #ifndef APPLICATION | 166 | #ifndef APPLICATION |
166 | if (fat_ismounted(1)) | 167 | volume_size(1, &info->size2, &info->free2); |
167 | fat_size(1, &info->size2, &info->free2); | 168 | #else |
168 | else | 169 | info->size2 = 0; |
169 | #endif | 170 | #endif |
170 | info->size2 = 0; | 171 | |
171 | #endif | 172 | #endif |
172 | info->new_data = false; | 173 | info->new_data = false; |
173 | } | 174 | } |
@@ -347,12 +348,7 @@ static int info_action_callback(int action, struct gui_synclist *lists) | |||
347 | info->new_data = true; | 348 | info->new_data = true; |
348 | splash(0, ID2P(LANG_SCANNING_DISK)); | 349 | splash(0, ID2P(LANG_SCANNING_DISK)); |
349 | for (i = 0; i < NUM_VOLUMES; i++) | 350 | for (i = 0; i < NUM_VOLUMES; i++) |
350 | { | 351 | volume_recalc_free(IF_MV(i)); |
351 | #ifdef HAVE_HOTSWAP | ||
352 | if (fat_ismounted(i)) | ||
353 | #endif | ||
354 | fat_recalc_free(IF_MV(i)); | ||
355 | } | ||
356 | #else | 352 | #else |
357 | (void) lists; | 353 | (void) lists; |
358 | #endif | 354 | #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) | |||
209 | switch (action) | 209 | switch (action) |
210 | { | 210 | { |
211 | case ACTION_EXIT_MENUITEM: /* on exit */ | 211 | case ACTION_EXIT_MENUITEM: /* on exit */ |
212 | if (global_settings.dircache && !dircache_is_enabled()) | 212 | if (global_settings.dircache) |
213 | { | 213 | { |
214 | if (dircache_build(0) < 0) | 214 | if (dircache_enable() < 0) |
215 | splash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); | 215 | splash(HZ*2, ID2P(LANG_PLEASE_REBOOT)); |
216 | } | 216 | } |
217 | else if (!global_settings.dircache && dircache_is_enabled()) | 217 | else |
218 | { | 218 | { |
219 | dircache_disable(); | 219 | dircache_disable(); |
220 | } | 220 | } |
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 @@ | |||
28 | #include "misc.h" | 28 | #include "misc.h" |
29 | #include "system.h" | 29 | #include "system.h" |
30 | #include "lcd.h" | 30 | #include "lcd.h" |
31 | #ifdef HAVE_DIRCACHE | ||
32 | #include "dircache.h" | ||
33 | #endif | ||
31 | #include "file.h" | 34 | #include "file.h" |
32 | #ifndef __PCTOOL__ | 35 | #ifndef __PCTOOL__ |
33 | #include "filefuncs.h" | 36 | #include "pathfuncs.h" |
34 | #include "lang.h" | 37 | #include "lang.h" |
35 | #include "dir.h" | 38 | #include "dir.h" |
36 | #ifdef HAVE_REMOTE_LCD | 39 | #ifdef HAVE_REMOTE_LCD |
@@ -744,8 +747,7 @@ int show_logo( void ) | |||
744 | */ | 747 | */ |
745 | void check_bootfile(bool do_rolo) | 748 | void check_bootfile(bool do_rolo) |
746 | { | 749 | { |
747 | static unsigned short wrtdate = 0; | 750 | static time_t mtime = 0; |
748 | static unsigned short wrttime = 0; | ||
749 | DIR* dir = NULL; | 751 | DIR* dir = NULL; |
750 | struct dirent* entry = NULL; | 752 | struct dirent* entry = NULL; |
751 | 753 | ||
@@ -761,10 +763,9 @@ void check_bootfile(bool do_rolo) | |||
761 | { | 763 | { |
762 | struct dirinfo info = dir_get_info(dir, entry); | 764 | struct dirinfo info = dir_get_info(dir, entry); |
763 | /* found the bootfile */ | 765 | /* found the bootfile */ |
764 | if(wrtdate && do_rolo) | 766 | if(mtime && do_rolo) |
765 | { | 767 | { |
766 | if((info.wrtdate != wrtdate) || | 768 | if(info.mtime != mtime) |
767 | (info.wrttime != wrttime)) | ||
768 | { | 769 | { |
769 | static const char *lines[] = { ID2P(LANG_BOOT_CHANGED), | 770 | static const char *lines[] = { ID2P(LANG_BOOT_CHANGED), |
770 | ID2P(LANG_REBOOT_NOW) }; | 771 | ID2P(LANG_REBOOT_NOW) }; |
@@ -777,8 +778,7 @@ void check_bootfile(bool do_rolo) | |||
777 | } | 778 | } |
778 | } | 779 | } |
779 | } | 780 | } |
780 | wrtdate = info.wrtdate; | 781 | mtime = info.mtime; |
781 | wrttime = info.wrttime; | ||
782 | } | 782 | } |
783 | } | 783 | } |
784 | closedir(dir); | 784 | 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 @@ | |||
62 | #include "statusbar-skinned.h" | 62 | #include "statusbar-skinned.h" |
63 | #include "pitchscreen.h" | 63 | #include "pitchscreen.h" |
64 | #include "viewport.h" | 64 | #include "viewport.h" |
65 | #include "filefuncs.h" | 65 | #include "pathfuncs.h" |
66 | #include "shortcuts.h" | 66 | #include "shortcuts.h" |
67 | 67 | ||
68 | static int context; | 68 | static int context; |
69 | static const char* selected_file = NULL; | 69 | static const char *selected_file = NULL; |
70 | static int selected_file_attr = 0; | 70 | static int selected_file_attr = 0; |
71 | static int onplay_result = ONPLAY_OK; | 71 | static int onplay_result = ONPLAY_OK; |
72 | static char clipboard_selection[MAX_PATH]; | ||
73 | static int clipboard_selection_attr = 0; | ||
74 | static bool clipboard_is_copy = false; | ||
75 | 72 | ||
76 | /* redefine MAKE_MENU so the MENU_EXITAFTERTHISMENU flag can be added easily */ | 73 | /* redefine MAKE_MENU so the MENU_EXITAFTERTHISMENU flag can be added easily */ |
77 | #define MAKE_ONPLAYMENU( name, str, callback, icon, ... ) \ | 74 | #define MAKE_ONPLAYMENU( name, str, callback, icon, ... ) \ |
@@ -82,6 +79,63 @@ static bool clipboard_is_copy = false; | |||
82 | MENU_ITEM_COUNT(sizeof( name##_)/sizeof(*name##_)), \ | 79 | MENU_ITEM_COUNT(sizeof( name##_)/sizeof(*name##_)), \ |
83 | { (void*)name##_},{.callback_and_desc = & name##__}}; | 80 | { (void*)name##_},{.callback_and_desc = & name##__}}; |
84 | 81 | ||
82 | /* Used for directory move, copy and delete */ | ||
83 | struct dirrecurse_params | ||
84 | { | ||
85 | char path[MAX_PATH]; /* Buffer for full path */ | ||
86 | size_t append; /* Append position in 'path' for stack push */ | ||
87 | }; | ||
88 | |||
89 | enum clipboard_op_flags | ||
90 | { | ||
91 | PASTE_CUT = 0x00, /* Is a move (cut) operation (default) */ | ||
92 | PASTE_COPY = 0x01, /* Is a copy operation */ | ||
93 | PASTE_OVERWRITE = 0x02, /* Overwrite destination */ | ||
94 | PASTE_EXDEV = 0x04, /* Actually copy/move across volumes */ | ||
95 | }; | ||
96 | |||
97 | /* result codec of various onplay operations */ | ||
98 | enum onplay_result_code | ||
99 | { | ||
100 | /* Anything < 0 is failure */ | ||
101 | OPRC_SUCCESS = 0, /* All operations completed successfully */ | ||
102 | OPRC_NOOP = 1, /* Operation didn't need to do anything */ | ||
103 | OPRC_CANCELLED = 2, /* Operation was cancelled by user */ | ||
104 | OPRC_NOOVERWRT = 3, | ||
105 | }; | ||
106 | |||
107 | static struct clipboard | ||
108 | { | ||
109 | char path[MAX_PATH]; /* Clipped file's path */ | ||
110 | unsigned int attr; /* Clipped file's attributes */ | ||
111 | unsigned int flags; /* Operation type flags */ | ||
112 | } clipboard; | ||
113 | |||
114 | /* Empty the clipboard */ | ||
115 | static void clipboard_clear_selection(struct clipboard *clip) | ||
116 | { | ||
117 | clip->path[0] = '\0'; | ||
118 | clip->attr = 0; | ||
119 | clip->flags = 0; | ||
120 | } | ||
121 | |||
122 | /* Store the selection in the clipboard */ | ||
123 | static bool clipboard_clip(struct clipboard *clip, const char *path, | ||
124 | unsigned int attr, unsigned int flags) | ||
125 | { | ||
126 | /* if it fits it clips */ | ||
127 | if (strlcpy(clip->path, path, sizeof (clip->path)) | ||
128 | < sizeof (clip->path)) { | ||
129 | clip->attr = attr; | ||
130 | clip->flags = flags; | ||
131 | return true; | ||
132 | } | ||
133 | else { | ||
134 | clipboard_clear_selection(clip); | ||
135 | return false; | ||
136 | } | ||
137 | } | ||
138 | |||
85 | /* ----------------------------------------------------------------------- */ | 139 | /* ----------------------------------------------------------------------- */ |
86 | /* Displays the bookmark menu options for the user to decide. This is an */ | 140 | /* Displays the bookmark menu options for the user to decide. This is an */ |
87 | /* interface function. */ | 141 | /* interface function. */ |
@@ -492,438 +546,578 @@ static void draw_slider(void) | |||
492 | #define draw_slider() | 546 | #define draw_slider() |
493 | #endif | 547 | #endif |
494 | 548 | ||
495 | /* helper function to remove a non-empty directory */ | 549 | static void clear_display(bool update) |
496 | static int remove_dir(char* dirname, int len) | ||
497 | { | 550 | { |
498 | int result = 0; | 551 | struct viewport vp; |
499 | DIR* dir; | ||
500 | int dirlen = strlen(dirname); | ||
501 | 552 | ||
502 | dir = opendir(dirname); | 553 | FOR_NB_SCREENS(i) |
503 | if (!dir) | 554 | { |
555 | struct screen * screen = &screens[i]; | ||
556 | viewport_set_defaults(&vp, screen->screen_type); | ||
557 | screen->set_viewport(&vp); | ||
558 | screen->clear_viewport(); | ||
559 | if (update) { | ||
560 | screen->update_viewport(); | ||
561 | } | ||
562 | screen->set_viewport(NULL); | ||
563 | } | ||
564 | } | ||
565 | |||
566 | static void splash_path(const char *path) | ||
567 | { | ||
568 | clear_display(false); | ||
569 | path_basename(path, &path); | ||
570 | splash(0, path); | ||
571 | draw_slider(); | ||
572 | } | ||
573 | |||
574 | /* Splashes the path and checks the keys */ | ||
575 | static bool poll_cancel_action(const char *path) | ||
576 | { | ||
577 | splash_path(path); | ||
578 | return ACTION_STD_CANCEL == get_action(CONTEXT_STD, TIMEOUT_NOBLOCK); | ||
579 | } | ||
580 | |||
581 | static int confirm_overwrite(void) | ||
582 | { | ||
583 | static const char *lines[] = { ID2P(LANG_REALLY_OVERWRITE) }; | ||
584 | static const struct text_message message = { lines, 1 }; | ||
585 | return gui_syncyesno_run(&message, NULL, NULL); | ||
586 | } | ||
587 | |||
588 | static int confirm_delete(const char *file) | ||
589 | { | ||
590 | const char *lines[] = { ID2P(LANG_REALLY_DELETE), file }; | ||
591 | const char *yes_lines[] = { ID2P(LANG_DELETING), file }; | ||
592 | const struct text_message message = { lines, 2 }; | ||
593 | const struct text_message yes_message = { yes_lines, 2 }; | ||
594 | return gui_syncyesno_run(&message, &yes_message, NULL); | ||
595 | } | ||
596 | |||
597 | static bool check_new_name(const char *basename) | ||
598 | { | ||
599 | /* at least prevent escapes out of the base directory from keyboard- | ||
600 | entered filenames; the file code should reject other invalidities */ | ||
601 | return *basename != '\0' && !strchr(basename, PATH_SEPCH) && | ||
602 | !is_dotdir_name(basename); | ||
603 | } | ||
604 | |||
605 | static void splash_cancelled(void) | ||
606 | { | ||
607 | clear_display(true); | ||
608 | splash(HZ, ID2P(LANG_CANCEL)); | ||
609 | } | ||
610 | |||
611 | static void splash_failed(int lang_what) | ||
612 | { | ||
613 | cond_talk_ids_fq(lang_what, LANG_FAILED); | ||
614 | clear_display(true); | ||
615 | splashf(HZ*2, "%s %s", str(lang_what), str(LANG_FAILED)); | ||
616 | } | ||
617 | |||
618 | /* helper function to remove a non-empty directory */ | ||
619 | static int remove_dir(struct dirrecurse_params *parm) | ||
620 | { | ||
621 | DIR *dir = opendir(parm->path); | ||
622 | if (!dir) { | ||
504 | return -1; /* open error */ | 623 | return -1; /* open error */ |
624 | } | ||
505 | 625 | ||
506 | while(true) | 626 | size_t append = parm->append; |
507 | { | 627 | int rc = OPRC_SUCCESS; |
508 | struct dirent* entry; | 628 | |
509 | /* walk through the directory content */ | 629 | /* walk through the directory content */ |
510 | entry = readdir(dir); | 630 | while (rc == OPRC_SUCCESS) { |
511 | if (!entry) | 631 | errno = 0; /* distinguish failure from eod */ |
632 | struct dirent *entry = readdir(dir); | ||
633 | if (!entry) { | ||
634 | if (errno) { | ||
635 | rc = -1; | ||
636 | } | ||
512 | break; | 637 | break; |
638 | } | ||
639 | |||
513 | struct dirinfo info = dir_get_info(dir, entry); | 640 | struct dirinfo info = dir_get_info(dir, entry); |
514 | dirname[dirlen] ='\0'; | 641 | if ((info.attribute & ATTR_DIRECTORY) && |
515 | /* inform the user which dir we're deleting */ | 642 | is_dotdir_name(entry->d_name)) { |
516 | splash(0, dirname); | 643 | continue; /* skip these */ |
644 | } | ||
517 | 645 | ||
518 | /* append name to current directory */ | 646 | /* append name to current directory */ |
519 | snprintf(dirname+dirlen, len-dirlen, "/%s", entry->d_name); | 647 | parm->append = append + path_append(&parm->path[append], |
520 | if (info.attribute & ATTR_DIRECTORY) | 648 | PA_SEP_HARD, entry->d_name, |
521 | { /* remove a subdirectory */ | 649 | sizeof (parm->path) - append); |
522 | if (!strcmp((char *)entry->d_name, ".") || | 650 | if (parm->append >= sizeof (parm->path)) { |
523 | !strcmp((char *)entry->d_name, "..")) | 651 | rc = -1; |
524 | continue; /* skip these */ | 652 | break; /* no space left in buffer */ |
525 | |||
526 | result = remove_dir(dirname, len); /* recursion */ | ||
527 | if (result) | ||
528 | break; /* or better continue, delete what we can? */ | ||
529 | } | ||
530 | else | ||
531 | { /* remove a file */ | ||
532 | draw_slider(); | ||
533 | result = remove(dirname); | ||
534 | } | 653 | } |
535 | if(ACTION_STD_CANCEL == get_action(CONTEXT_STD,TIMEOUT_NOBLOCK)) | 654 | |
536 | { | 655 | if (info.attribute & ATTR_DIRECTORY) { |
537 | splash(HZ, ID2P(LANG_CANCEL)); | 656 | /* remove a subdirectory */ |
538 | result = -1; | 657 | rc = remove_dir(parm); |
539 | break; | 658 | } else { |
659 | /* remove a file */ | ||
660 | if (poll_cancel_action(parm->path)) { | ||
661 | rc = OPRC_CANCELLED; | ||
662 | break; | ||
663 | } | ||
664 | |||
665 | rc = remove(parm->path); | ||
540 | } | 666 | } |
667 | |||
668 | /* Remove basename we added above */ | ||
669 | parm->path[append] = '\0'; | ||
541 | } | 670 | } |
542 | closedir(dir); | ||
543 | 671 | ||
544 | if (!result) | 672 | closedir(dir); |
545 | { /* remove the now empty directory */ | ||
546 | dirname[dirlen] = '\0'; /* terminate to original length */ | ||
547 | 673 | ||
548 | result = rmdir(dirname); | 674 | if (rc == 0) { |
675 | /* remove the now empty directory */ | ||
676 | if (poll_cancel_action(parm->path)) { | ||
677 | rc = OPRC_CANCELLED; | ||
678 | } else { | ||
679 | rc = rmdir(parm->path); | ||
680 | } | ||
549 | } | 681 | } |
550 | 682 | ||
551 | return result; | 683 | return rc; |
552 | } | 684 | } |
553 | 685 | ||
554 | |||
555 | /* share code for file and directory deletion, saves space */ | 686 | /* share code for file and directory deletion, saves space */ |
556 | static bool delete_file_dir(void) | 687 | static int delete_file_dir(void) |
557 | { | 688 | { |
558 | char file_to_delete[MAX_PATH]; | 689 | if (confirm_delete(selected_file) != YESNO_YES) { |
559 | strcpy(file_to_delete, selected_file); | 690 | return 1; |
691 | } | ||
560 | 692 | ||
561 | const char *lines[]={ | 693 | clear_display(true); |
562 | ID2P(LANG_REALLY_DELETE), | 694 | splash(HZ/2, str(LANG_DELETING)); |
563 | file_to_delete | ||
564 | }; | ||
565 | const char *yes_lines[]={ | ||
566 | ID2P(LANG_DELETING), | ||
567 | file_to_delete | ||
568 | }; | ||
569 | 695 | ||
570 | const struct text_message message={lines, 2}; | 696 | int rc = -1; |
571 | const struct text_message yes_message={yes_lines, 2}; | ||
572 | 697 | ||
573 | if(gui_syncyesno_run(&message, &yes_message, NULL)!=YESNO_YES) | 698 | if (selected_file_attr & ATTR_DIRECTORY) { /* true if directory */ |
574 | return false; | 699 | struct dirrecurse_params parm; |
700 | parm.append = strlcpy(parm.path, selected_file, sizeof (parm.path)); | ||
575 | 701 | ||
576 | splash(0, str(LANG_DELETING)); | 702 | if (parm.append < sizeof (parm.path)) { |
703 | cpu_boost(true); | ||
704 | rc = remove_dir(&parm); | ||
705 | cpu_boost(false); | ||
706 | } | ||
707 | } else { | ||
708 | rc = remove(selected_file); | ||
709 | } | ||
577 | 710 | ||
578 | int res; | 711 | if (rc < OPRC_SUCCESS) { |
579 | if (selected_file_attr & ATTR_DIRECTORY) /* true if directory */ | 712 | splash_failed(LANG_DELETE); |
580 | { | 713 | } else if (rc == OPRC_CANCELLED) { |
581 | char pathname[MAX_PATH]; /* space to go deep */ | 714 | splash_cancelled(); |
582 | cpu_boost(true); | ||
583 | strlcpy(pathname, file_to_delete, sizeof(pathname)); | ||
584 | res = remove_dir(pathname, sizeof(pathname)); | ||
585 | cpu_boost(false); | ||
586 | } | 715 | } |
587 | else | ||
588 | res = remove(file_to_delete); | ||
589 | 716 | ||
590 | if (!res) | 717 | if (rc != OPRC_NOOP) { |
718 | /* Could have failed after some but not all needed changes; reload */ | ||
591 | onplay_result = ONPLAY_RELOAD_DIR; | 719 | onplay_result = ONPLAY_RELOAD_DIR; |
720 | } | ||
592 | 721 | ||
593 | return (res == 0); | 722 | return 1; |
594 | } | 723 | } |
595 | 724 | ||
596 | static bool rename_file(void) | 725 | static int rename_file(void) |
597 | { | 726 | { |
727 | int rc = -1; | ||
598 | char newname[MAX_PATH]; | 728 | char newname[MAX_PATH]; |
599 | char* ptr = strrchr(selected_file, '/') + 1; | 729 | const char *oldbase, *selection = selected_file; |
600 | int pathlen = (ptr - selected_file); | 730 | |
601 | strlcpy(newname, selected_file, sizeof(newname)); | 731 | path_basename(selection, &oldbase); |
602 | if (!kbd_input(newname + pathlen, (sizeof newname)-pathlen)) { | 732 | size_t pathlen = oldbase - selection; |
603 | if (!strlen(newname + pathlen) || | 733 | char *newbase = newname + pathlen; |
604 | (rename(selected_file, newname) < 0)) { | 734 | |
605 | cond_talk_ids_fq(LANG_RENAME, LANG_FAILED); | 735 | if (strlcpy(newname, selection, sizeof (newname)) >= sizeof (newname)) { |
606 | splashf(HZ*2, "%s %s", str(LANG_RENAME), str(LANG_FAILED)); | 736 | /* Too long */ |
737 | } else if (kbd_input(newbase, sizeof (newname) - pathlen) < 0) { | ||
738 | rc = OPRC_CANCELLED; | ||
739 | } else if (!strcmp(oldbase, newbase)) { | ||
740 | rc = OPRC_NOOP; /* No change at all */ | ||
741 | } else if (check_new_name(newbase)) { | ||
742 | switch (relate(selection, newname)) | ||
743 | { | ||
744 | case RELATE_DIFFERENT: | ||
745 | if (file_exists(newname)) { | ||
746 | break; /* don't overwrite */ | ||
747 | } | ||
748 | /* Fall-through */ | ||
749 | case RELATE_SAME: | ||
750 | rc = rename(selection, newname); | ||
751 | break; | ||
752 | case RELATE_PREFIX: | ||
753 | default: | ||
754 | break; | ||
607 | } | 755 | } |
608 | else | ||
609 | onplay_result = ONPLAY_RELOAD_DIR; | ||
610 | } | 756 | } |
611 | 757 | ||
612 | return false; | 758 | if (rc < OPRC_SUCCESS) { |
759 | splash_failed(LANG_RENAME); | ||
760 | } else if (rc == OPRC_CANCELLED) { | ||
761 | /* splash_cancelled(); kbd_input() splashes it */ | ||
762 | } else if (rc == OPRC_SUCCESS) { | ||
763 | onplay_result = ONPLAY_RELOAD_DIR; | ||
764 | } | ||
765 | |||
766 | return 1; | ||
613 | } | 767 | } |
614 | 768 | ||
615 | static bool create_dir(void) | 769 | static int create_dir(void) |
616 | { | 770 | { |
771 | int rc = -1; | ||
617 | char dirname[MAX_PATH]; | 772 | char dirname[MAX_PATH]; |
618 | char *cwd; | 773 | size_t pathlen = path_append(dirname, getcwd(NULL, 0), PA_SEP_HARD, |
619 | int rc; | 774 | sizeof (dirname)); |
620 | int pathlen; | 775 | char *basename = dirname + pathlen; |
621 | 776 | ||
622 | cwd = getcwd(NULL, 0); | 777 | if (pathlen >= sizeof (dirname)) { |
623 | memset(dirname, 0, sizeof dirname); | 778 | /* Too long */ |
624 | 779 | } else if (kbd_input(basename, sizeof (dirname) - pathlen) < 0) { | |
625 | snprintf(dirname, sizeof dirname, "%s/", cwd[1] ? cwd : ""); | 780 | rc = OPRC_CANCELLED; |
626 | 781 | } else if (check_new_name(basename)) { | |
627 | pathlen = strlen(dirname); | 782 | rc = mkdir(dirname); |
628 | rc = kbd_input(dirname + pathlen, (sizeof dirname)-pathlen); | 783 | } |
629 | if (rc < 0) | ||
630 | return false; | ||
631 | 784 | ||
632 | rc = mkdir(dirname); | 785 | if (rc < OPRC_SUCCESS) { |
633 | if (rc < 0) { | 786 | splash_failed(LANG_CREATE_DIR); |
634 | cond_talk_ids_fq(LANG_CREATE_DIR, LANG_FAILED); | 787 | } else if (rc == OPRC_CANCELLED) { |
635 | splashf(HZ, (unsigned char *)"%s %s", str(LANG_CREATE_DIR), | 788 | /* splash_cancelled(); kbd_input() splashes it */ |
636 | str(LANG_FAILED)); | 789 | } else if (rc == OPRC_SUCCESS) { |
637 | } else { | ||
638 | onplay_result = ONPLAY_RELOAD_DIR; | 790 | onplay_result = ONPLAY_RELOAD_DIR; |
639 | } | 791 | } |
640 | 792 | ||
641 | return true; | 793 | return 1; |
642 | } | 794 | } |
643 | 795 | ||
644 | /* Store the current selection in the clipboard */ | 796 | /* Paste a file */ |
645 | static bool clipboard_clip(bool copy) | 797 | static int clipboard_pastefile(const char *src, const char *target, |
798 | unsigned int flags) | ||
646 | { | 799 | { |
647 | clipboard_selection[0] = 0; | 800 | int rc = -1; |
648 | strlcpy(clipboard_selection, selected_file, sizeof(clipboard_selection)); | 801 | |
649 | clipboard_selection_attr = selected_file_attr; | 802 | while (!(flags & (PASTE_COPY | PASTE_EXDEV))) { |
650 | clipboard_is_copy = copy; | 803 | if ((flags & PASTE_OVERWRITE) || !file_exists(target)) { |
651 | 804 | /* Rename and possibly overwrite the file */ | |
652 | return true; | 805 | if (poll_cancel_action(src)) { |
653 | } | 806 | rc = OPRC_CANCELLED; |
807 | } else { | ||
808 | rc = rename(src, target); | ||
809 | } | ||
654 | 810 | ||
655 | static bool clipboard_cut(void) | 811 | #ifdef HAVE_MULTIVOLUME |
656 | { | 812 | if (rc < 0 && errno == EXDEV) { |
657 | return clipboard_clip(false); | 813 | /* Failed because cross volume rename doesn't work; force |
658 | } | 814 | a move instead */ |
815 | flags |= PASTE_EXDEV; | ||
816 | break; | ||
817 | } | ||
818 | #endif /* HAVE_MULTIVOLUME */ | ||
819 | } | ||
659 | 820 | ||
660 | static bool clipboard_copy(void) | 821 | return rc; |
661 | { | 822 | } |
662 | return clipboard_clip(true); | ||
663 | } | ||
664 | 823 | ||
665 | /* Paste a file to a new directory. Will overwrite always. */ | 824 | /* See if we can get the plugin buffer for the file copy buffer */ |
666 | static bool clipboard_pastefile(const char *src, const char *target, bool copy) | ||
667 | { | ||
668 | int src_fd, target_fd; | ||
669 | size_t buffersize; | 825 | size_t buffersize; |
670 | ssize_t size, bytesread, byteswritten; | 826 | char *buffer = (char *) plugin_get_buffer(&buffersize); |
671 | char *buffer; | 827 | if (buffer == NULL || buffersize < 512) { |
672 | bool result = false; | 828 | /* Not large enough, try for a disk sector worth of stack |
673 | 829 | instead */ | |
674 | if (copy) { | 830 | buffersize = 512; |
675 | /* See if we can get the plugin buffer for the file copy buffer */ | 831 | buffer = (char *)alloca(buffersize); |
676 | buffer = (char *) plugin_get_buffer(&buffersize); | 832 | } |
677 | if (buffer == NULL || buffersize < 512) { | ||
678 | /* Not large enough, try for a disk sector worth of stack | ||
679 | instead */ | ||
680 | buffersize = 512; | ||
681 | buffer = (char *) __builtin_alloca(buffersize); | ||
682 | } | ||
683 | 833 | ||
684 | if (buffer == NULL) { | 834 | if (buffer == NULL) { |
685 | return false; | 835 | return -1; |
686 | } | 836 | } |
687 | 837 | ||
688 | buffersize &= ~0x1ff; /* Round buffer size to multiple of sector | 838 | buffersize &= ~0x1ff; /* Round buffer size to multiple of sector |
689 | size */ | 839 | size */ |
690 | 840 | ||
691 | src_fd = open(src, O_RDONLY); | 841 | int src_fd = open(src, O_RDONLY); |
842 | if (src_fd >= 0) { | ||
843 | int oflag = O_WRONLY|O_CREAT; | ||
692 | 844 | ||
693 | if (src_fd >= 0) { | 845 | if (!(flags & PASTE_OVERWRITE)) { |
694 | target_fd = creat(target, 0666); | 846 | oflag |= O_EXCL; |
847 | } | ||
695 | 848 | ||
696 | if (target_fd >= 0) { | 849 | int target_fd = open(target, oflag, 0666); |
697 | result = true; | 850 | if (target_fd >= 0) { |
851 | off_t total_size = 0; | ||
852 | off_t next_cancel_test = 0; /* No excessive button polling */ | ||
698 | 853 | ||
699 | size = filesize(src_fd); | 854 | rc = OPRC_SUCCESS; |
700 | 855 | ||
701 | if (size == -1) { | 856 | while (rc == OPRC_SUCCESS) { |
702 | result = false; | 857 | if (total_size >= next_cancel_test) { |
858 | next_cancel_test = total_size + 0x10000; | ||
859 | if (poll_cancel_action(src)) { | ||
860 | rc = OPRC_CANCELLED; | ||
861 | break; | ||
862 | } | ||
703 | } | 863 | } |
704 | 864 | ||
705 | while(size > 0) { | 865 | ssize_t bytesread = read(src_fd, buffer, buffersize); |
706 | bytesread = read(src_fd, buffer, buffersize); | 866 | if (bytesread <= 0) { |
707 | 867 | if (bytesread < 0) { | |
708 | if (bytesread == -1) { | 868 | rc = -1; |
709 | result = false; | ||
710 | break; | ||
711 | } | 869 | } |
870 | /* else eof on buffer boundary; nothing to write */ | ||
871 | break; | ||
872 | } | ||
712 | 873 | ||
713 | size -= bytesread; | 874 | ssize_t byteswritten = write(target_fd, buffer, bytesread); |
714 | 875 | if (byteswritten < bytesread) { | |
715 | while(bytesread > 0) { | 876 | /* Some I/O error */ |
716 | byteswritten = write(target_fd, buffer, bytesread); | 877 | rc = -1; |
717 | 878 | break; | |
718 | if (byteswritten < 0) { | ||
719 | result = false; | ||
720 | size = 0; | ||
721 | break; | ||
722 | } | ||
723 | |||
724 | bytesread -= byteswritten; | ||
725 | draw_slider(); | ||
726 | } | ||
727 | } | 879 | } |
728 | 880 | ||
729 | close(target_fd); | 881 | total_size += byteswritten; |
730 | 882 | ||
731 | /* Copy failed. Cleanup. */ | 883 | if (bytesread < (ssize_t)buffersize) { |
732 | if (!result) { | 884 | /* EOF with trailing bytes */ |
733 | remove(target); | 885 | break; |
734 | } | 886 | } |
735 | } | 887 | } |
736 | 888 | ||
737 | close(src_fd); | 889 | if (rc == OPRC_SUCCESS) { |
738 | } | 890 | /* If overwriting, set the correct length if original was |
739 | } else { | 891 | longer */ |
740 | result = rename(src, target) == 0; | 892 | rc = ftruncate(target_fd, total_size); |
741 | #ifdef HAVE_MULTIVOLUME | 893 | } |
742 | if (!result) { | 894 | |
743 | if (errno == EXDEV) { | 895 | close(target_fd); |
744 | /* Failed because cross volume rename doesn't work. Copy | 896 | |
745 | instead */ | 897 | if (rc != OPRC_SUCCESS) { |
746 | result = clipboard_pastefile(src, target, true); | 898 | /* Copy failed. Cleanup. */ |
747 | 899 | remove(target); | |
748 | if (result) { | ||
749 | result = remove(src) == 0; | ||
750 | } | ||
751 | } | 900 | } |
752 | } | 901 | } |
753 | #endif | 902 | |
903 | close(src_fd); | ||
754 | } | 904 | } |
755 | 905 | ||
756 | return result; | 906 | if (rc == OPRC_SUCCESS && !(flags & PASTE_COPY)) { |
907 | /* Remove the source file */ | ||
908 | rc = remove(src); | ||
909 | } | ||
910 | |||
911 | return rc; | ||
757 | } | 912 | } |
758 | 913 | ||
759 | /* Paste a directory to a new location. Designed to be called by | 914 | /* Paste a directory */ |
760 | clipboard_paste */ | 915 | static int clipboard_pastedirectory(struct dirrecurse_params *src, |
761 | static bool clipboard_pastedirectory(char *src, int srclen, char *target, | 916 | struct dirrecurse_params *target, |
762 | int targetlen, bool copy) | 917 | unsigned int flags) |
763 | { | 918 | { |
764 | DIR *srcdir; | 919 | int rc = -1; |
765 | int srcdirlen = strlen(src); | 920 | |
766 | int targetdirlen = strlen(target); | 921 | while (!(flags & (PASTE_COPY | PASTE_EXDEV))) { |
767 | bool result = true; | 922 | if ((flags & PASTE_OVERWRITE) || !file_exists(target->path)) { |
768 | 923 | /* Just try to move the directory */ | |
769 | if (!file_exists(target)) { | 924 | if (poll_cancel_action(src->path)) { |
770 | if (!copy) { | 925 | rc = OPRC_CANCELLED; |
771 | /* Just move the directory */ | 926 | } else { |
772 | result = rename(src, target) == 0; | 927 | rc = rename(src->path, target->path); |
928 | } | ||
773 | 929 | ||
774 | #ifdef HAVE_MULTIVOLUME | 930 | if (rc < 0) { |
775 | if (!result && errno == EXDEV) { | 931 | int errnum = errno; |
776 | /* Try a copy as we're going across devices */ | 932 | if (errnum == ENOTEMPTY && (flags & PASTE_OVERWRITE)) { |
777 | result = clipboard_pastedirectory(src, srclen, target, | 933 | /* Directory is not empty thus rename() will not do a quick |
778 | targetlen, true); | 934 | overwrite */ |
779 | 935 | break; | |
780 | /* If it worked, remove the source directory */ | ||
781 | if (result) { | ||
782 | remove_dir(src, srclen); | ||
783 | } | 936 | } |
937 | #ifdef HAVE_MULTIVOLUME | ||
938 | else if (errnum == EXDEV) { | ||
939 | /* Failed because cross volume rename doesn't work; force | ||
940 | a move instead */ | ||
941 | flags |= PASTE_EXDEV; | ||
942 | break; | ||
943 | } | ||
944 | #endif /* HAVE_MULTIVOLUME */ | ||
784 | } | 945 | } |
785 | #endif | ||
786 | return result; | ||
787 | } else { | ||
788 | /* Make a directory to copy things to */ | ||
789 | result = mkdir(target) == 0; | ||
790 | } | 946 | } |
791 | } | ||
792 | 947 | ||
793 | /* Check if something went wrong already */ | 948 | return rc; |
794 | if (!result) { | ||
795 | return result; | ||
796 | } | 949 | } |
797 | 950 | ||
798 | srcdir = opendir(src); | 951 | DIR *srcdir = opendir(src->path); |
799 | if (!srcdir) { | 952 | |
800 | return false; | 953 | if (srcdir) { |
954 | /* Make a directory to copy things to */ | ||
955 | rc = mkdir(target->path); | ||
956 | if (rc < 0 && errno == EEXIST && (flags & PASTE_OVERWRITE)) { | ||
957 | /* Exists and overwrite was approved */ | ||
958 | rc = OPRC_SUCCESS; | ||
959 | } | ||
801 | } | 960 | } |
802 | 961 | ||
803 | /* This loop will exit as soon as there's a problem */ | 962 | size_t srcap = src->append, targetap = target->append; |
804 | while(result) | 963 | |
805 | { | 964 | /* Walk through the directory content; this loop will exit as soon as |
806 | struct dirent* entry; | 965 | there's a problem */ |
807 | /* walk through the directory content */ | 966 | while (rc == OPRC_SUCCESS) { |
808 | entry = readdir(srcdir); | 967 | errno = 0; /* Distinguish failure from eod */ |
809 | if (!entry) | 968 | struct dirent *entry = readdir(srcdir); |
969 | if (!entry) { | ||
970 | if (errno) { | ||
971 | rc = -1; | ||
972 | } | ||
810 | break; | 973 | break; |
974 | } | ||
811 | 975 | ||
812 | struct dirinfo info = dir_get_info(srcdir, entry); | 976 | struct dirinfo info = dir_get_info(srcdir, entry); |
813 | /* append name to current directory */ | 977 | if ((info.attribute & ATTR_DIRECTORY) && |
814 | snprintf(src+srcdirlen, srclen-srcdirlen, "/%s", entry->d_name); | 978 | is_dotdir_name(entry->d_name)) { |
815 | snprintf(target+targetdirlen, targetlen-targetdirlen, "/%s", | 979 | continue; /* Skip these */ |
816 | entry->d_name); | 980 | } |
817 | 981 | ||
818 | DEBUGF("Copy %s to %s\n", src, target); | 982 | /* Append names to current directories */ |
983 | src->append = srcap + | ||
984 | path_append(&src->path[srcap], PA_SEP_HARD, entry->d_name, | ||
985 | sizeof(src->path) - srcap); | ||
819 | 986 | ||
820 | if (info.attribute & ATTR_DIRECTORY) | 987 | target->append = targetap + |
821 | { /* copy/move a subdirectory */ | 988 | path_append(&target->path[targetap], PA_SEP_HARD, entry->d_name, |
822 | if (!strcmp((char *)entry->d_name, ".") || | 989 | sizeof (target->path) - targetap); |
823 | !strcmp((char *)entry->d_name, "..")) | ||
824 | continue; /* skip these */ | ||
825 | 990 | ||
826 | result = clipboard_pastedirectory(src, srclen, target, targetlen, | 991 | if (src->append >= sizeof (src->path) || |
827 | copy); /* recursion */ | 992 | target->append >= sizeof (target->path)) { |
993 | rc = -1; /* No space left in buffer */ | ||
994 | break; | ||
828 | } | 995 | } |
829 | else | 996 | |
830 | { /* copy/move a file */ | 997 | if (poll_cancel_action(src->path)) { |
831 | draw_slider(); | 998 | rc = OPRC_CANCELLED; |
832 | result = clipboard_pastefile(src, target, copy); | 999 | break; |
1000 | } | ||
1001 | |||
1002 | DEBUGF("Copy %s to %s\n", src->path, target->path); | ||
1003 | |||
1004 | if (info.attribute & ATTR_DIRECTORY) { | ||
1005 | /* Copy/move a subdirectory */ | ||
1006 | rc = clipboard_pastedirectory(src, target, flags); /* recursion */ | ||
1007 | } else { | ||
1008 | /* Copy/move a file */ | ||
1009 | rc = clipboard_pastefile(src->path, target->path, flags); | ||
833 | } | 1010 | } |
1011 | |||
1012 | /* Remove basenames we added above */ | ||
1013 | src->path[srcap] = target->path[targetap] = '\0'; | ||
1014 | } | ||
1015 | |||
1016 | if (rc == OPRC_SUCCESS && !(flags & PASTE_COPY)) { | ||
1017 | /* Remove the now empty directory */ | ||
1018 | rc = rmdir(src->path); | ||
834 | } | 1019 | } |
835 | 1020 | ||
836 | closedir(srcdir); | 1021 | closedir(srcdir); |
1022 | return rc; | ||
1023 | } | ||
837 | 1024 | ||
838 | if (result) { | 1025 | static bool clipboard_cut(void) |
839 | src[srcdirlen] = '\0'; /* terminate to original length */ | 1026 | { |
840 | target[targetdirlen] = '\0'; /* terminate to original length */ | 1027 | return clipboard_clip(&clipboard, selected_file, selected_file_attr, |
841 | } | 1028 | PASTE_CUT); |
1029 | } | ||
842 | 1030 | ||
843 | return result; | 1031 | static bool clipboard_copy(void) |
1032 | { | ||
1033 | return clipboard_clip(&clipboard, selected_file, selected_file_attr, | ||
1034 | PASTE_COPY); | ||
844 | } | 1035 | } |
845 | 1036 | ||
846 | /* Paste the clipboard to the current directory */ | 1037 | /* Paste the clipboard to the current directory */ |
847 | static bool clipboard_paste(void) | 1038 | static int clipboard_paste(void) |
848 | { | 1039 | { |
849 | char target[MAX_PATH]; | 1040 | if (!clipboard.path[0]) |
850 | char *cwd, *nameptr; | 1041 | return 1; |
851 | bool success; | ||
852 | 1042 | ||
853 | static const char *lines[]={ID2P(LANG_REALLY_OVERWRITE)}; | 1043 | int rc = -1; |
854 | static const struct text_message message={lines, 1}; | ||
855 | 1044 | ||
856 | /* Get the name of the current directory */ | 1045 | struct dirrecurse_params src, target; |
857 | cwd = getcwd(NULL, 0); | 1046 | unsigned int flags = clipboard.flags; |
858 | 1047 | ||
859 | /* Figure out the name of the selection */ | 1048 | /* Figure out the name of the selection */ |
860 | nameptr = strrchr(clipboard_selection, '/'); | 1049 | const char *nameptr; |
1050 | path_basename(clipboard.path, &nameptr); | ||
861 | 1051 | ||
862 | /* Final target is current directory plus name of selection */ | 1052 | /* Final target is current directory plus name of selection */ |
863 | snprintf(target, sizeof(target), "%s%s", cwd[1] ? cwd : "", nameptr); | 1053 | target.append = path_append(target.path, getcwd(NULL, 0), |
864 | 1054 | nameptr, sizeof (target.path)); | |
865 | /* If the target existed but they choose not to overwite, exit */ | ||
866 | if (file_exists(target) && | ||
867 | (gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO)) { | ||
868 | return false; | ||
869 | } | ||
870 | 1055 | ||
871 | if (clipboard_is_copy) { | 1056 | switch (target.append < sizeof (target.path) ? |
872 | splash(0, ID2P(LANG_COPYING)); | 1057 | relate(clipboard.path, target.path) : -1) |
873 | } | ||
874 | else | ||
875 | { | 1058 | { |
876 | splash(0, ID2P(LANG_MOVING)); | 1059 | case RELATE_SAME: |
877 | } | 1060 | rc = OPRC_NOOP; |
1061 | break; | ||
1062 | |||
1063 | case RELATE_DIFFERENT: | ||
1064 | if (file_exists(target.path)) { | ||
1065 | /* If user chooses not to overwrite, cancel */ | ||
1066 | if (confirm_overwrite() == YESNO_NO) { | ||
1067 | rc = OPRC_NOOVERWRT; | ||
1068 | break; | ||
1069 | } | ||
878 | 1070 | ||
879 | /* Now figure out what we're doing */ | 1071 | flags |= PASTE_OVERWRITE; |
880 | cpu_boost(true); | ||
881 | if (clipboard_selection_attr & ATTR_DIRECTORY) { | ||
882 | /* Recursion. Set up external stack */ | ||
883 | char srcpath[MAX_PATH]; | ||
884 | char targetpath[MAX_PATH]; | ||
885 | if (!strncmp(clipboard_selection, target, strlen(clipboard_selection))) | ||
886 | { | ||
887 | /* Do not allow the user to paste a directory into a dir they are | ||
888 | copying */ | ||
889 | success = 0; | ||
890 | } | 1072 | } |
891 | else | ||
892 | { | ||
893 | strlcpy(srcpath, clipboard_selection, sizeof(srcpath)); | ||
894 | strlcpy(targetpath, target, sizeof(targetpath)); | ||
895 | 1073 | ||
896 | success = clipboard_pastedirectory(srcpath, sizeof(srcpath), | 1074 | clear_display(true); |
897 | target, sizeof(targetpath), clipboard_is_copy); | 1075 | splash(HZ/2, (flags & PASTE_COPY) ? ID2P(LANG_COPYING) : |
1076 | ID2P(LANG_MOVING)); | ||
898 | 1077 | ||
899 | if (success && !clipboard_is_copy) | 1078 | /* Now figure out what we're doing */ |
900 | { | 1079 | cpu_boost(true); |
901 | strlcpy(srcpath, clipboard_selection, sizeof(srcpath)); | 1080 | |
902 | remove_dir(srcpath, sizeof(srcpath)); | 1081 | if (clipboard.attr & ATTR_DIRECTORY) { |
1082 | /* Copy or move a subdirectory */ | ||
1083 | src.append = strlcpy(src.path, clipboard.path, | ||
1084 | sizeof (src.path)); | ||
1085 | if (src.append < sizeof (src.path)) { | ||
1086 | rc = clipboard_pastedirectory(&src, &target, flags); | ||
903 | } | 1087 | } |
1088 | } else { | ||
1089 | /* Copy or move a file */ | ||
1090 | rc = clipboard_pastefile(clipboard.path, target.path, flags); | ||
904 | } | 1091 | } |
905 | } else { | 1092 | |
906 | success = clipboard_pastefile(clipboard_selection, target, | 1093 | cpu_boost(false); |
907 | clipboard_is_copy); | 1094 | break; |
1095 | |||
1096 | case RELATE_PREFIX: | ||
1097 | default: /* Some other relation / failure */ | ||
1098 | break; | ||
908 | } | 1099 | } |
909 | cpu_boost(false); | ||
910 | 1100 | ||
911 | /* Did it work? */ | 1101 | clear_display(true); |
912 | if (success) { | ||
913 | /* Reset everything */ | ||
914 | clipboard_selection[0] = 0; | ||
915 | clipboard_selection_attr = 0; | ||
916 | clipboard_is_copy = false; | ||
917 | 1102 | ||
918 | /* Force reload of the current directory */ | 1103 | switch (rc) |
1104 | { | ||
1105 | case OPRC_CANCELLED: | ||
1106 | splash_cancelled(); | ||
1107 | case OPRC_SUCCESS: | ||
919 | onplay_result = ONPLAY_RELOAD_DIR; | 1108 | onplay_result = ONPLAY_RELOAD_DIR; |
920 | } else { | 1109 | case OPRC_NOOP: |
921 | cond_talk_ids_fq(LANG_PASTE, LANG_FAILED); | 1110 | clipboard_clear_selection(&clipboard); |
922 | splashf(HZ, (unsigned char *)"%s %s", str(LANG_PASTE), | 1111 | case OPRC_NOOVERWRT: |
923 | str(LANG_FAILED)); | 1112 | break; |
1113 | default: | ||
1114 | if (rc < OPRC_SUCCESS) { | ||
1115 | splash_failed(LANG_PASTE); | ||
1116 | onplay_result = ONPLAY_RELOAD_DIR; | ||
1117 | } | ||
924 | } | 1118 | } |
925 | 1119 | ||
926 | return true; | 1120 | return 1; |
927 | } | 1121 | } |
928 | 1122 | ||
929 | #ifdef HAVE_TAGCACHE | 1123 | #ifdef HAVE_TAGCACHE |
@@ -1094,15 +1288,12 @@ static int clipboard_callback(int action,const struct menu_item_ex *this_item) | |||
1094 | { | 1288 | { |
1095 | case ACTION_REQUEST_MENUITEM: | 1289 | case ACTION_REQUEST_MENUITEM: |
1096 | #ifdef HAVE_MULTIVOLUME | 1290 | #ifdef HAVE_MULTIVOLUME |
1097 | if ((selected_file_attr & FAT_ATTR_VOLUME) && | ||
1098 | (this_item == &rename_file_item || | ||
1099 | this_item == &delete_dir_item || | ||
1100 | this_item == &clipboard_cut_item) ) | ||
1101 | return ACTION_EXIT_MENUITEM; | ||
1102 | /* no rename+delete for volumes */ | 1291 | /* no rename+delete for volumes */ |
1103 | if ((selected_file_attr & ATTR_VOLUME) && | 1292 | if ((selected_file_attr & ATTR_VOLUME) && |
1104 | (this_item == &delete_file_item || | 1293 | (this_item == &rename_file_item || |
1105 | this_item == &list_viewers_item)) | 1294 | this_item == &delete_dir_item || |
1295 | this_item == &clipboard_cut_item || | ||
1296 | this_item == &list_viewers_item)) | ||
1106 | return ACTION_EXIT_MENUITEM; | 1297 | return ACTION_EXIT_MENUITEM; |
1107 | #endif | 1298 | #endif |
1108 | #ifdef HAVE_TAGCACHE | 1299 | #ifdef HAVE_TAGCACHE |
@@ -1117,7 +1308,7 @@ static int clipboard_callback(int action,const struct menu_item_ex *this_item) | |||
1117 | #endif | 1308 | #endif |
1118 | if (this_item == &clipboard_paste_item) | 1309 | if (this_item == &clipboard_paste_item) |
1119 | { /* visible if there is something to paste */ | 1310 | { /* visible if there is something to paste */ |
1120 | return (clipboard_selection[0] != 0) ? | 1311 | return (clipboard.path[0] != 0) ? |
1121 | action : ACTION_EXIT_MENUITEM; | 1312 | action : ACTION_EXIT_MENUITEM; |
1122 | } | 1313 | } |
1123 | else if (this_item == &create_dir_item) | 1314 | else if (this_item == &create_dir_item) |
@@ -1232,8 +1423,7 @@ static bool delete_item(void) | |||
1232 | { | 1423 | { |
1233 | #ifdef HAVE_MULTIVOLUME | 1424 | #ifdef HAVE_MULTIVOLUME |
1234 | /* no delete for volumes */ | 1425 | /* no delete for volumes */ |
1235 | if ((selected_file_attr & FAT_ATTR_VOLUME) || | 1426 | if (selected_file_attr & ATTR_VOLUME) |
1236 | (selected_file_attr & ATTR_VOLUME)) | ||
1237 | return false; | 1427 | return false; |
1238 | #endif | 1428 | #endif |
1239 | return delete_file_dir(); | 1429 | 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 @@ | |||
86 | #include "screens.h" | 86 | #include "screens.h" |
87 | #include "core_alloc.h" | 87 | #include "core_alloc.h" |
88 | #include "misc.h" | 88 | #include "misc.h" |
89 | #include "filefuncs.h" | 89 | #include "pathfuncs.h" |
90 | #include "button.h" | 90 | #include "button.h" |
91 | #include "filetree.h" | 91 | #include "filetree.h" |
92 | #include "abrepeat.h" | 92 | #include "abrepeat.h" |
@@ -107,6 +107,8 @@ | |||
107 | #include "panic.h" | 107 | #include "panic.h" |
108 | #include "logdiskf.h" | 108 | #include "logdiskf.h" |
109 | 109 | ||
110 | #undef HAVE_DIRCACHE | ||
111 | |||
110 | #define PLAYLIST_CONTROL_FILE_VERSION 2 | 112 | #define PLAYLIST_CONTROL_FILE_VERSION 2 |
111 | 113 | ||
112 | /* | 114 | /* |
@@ -180,8 +182,8 @@ static int get_next_directory(char *dir); | |||
180 | static int get_next_dir(char *dir, bool is_forward); | 182 | static int get_next_dir(char *dir, bool is_forward); |
181 | static int get_previous_directory(char *dir); | 183 | static int get_previous_directory(char *dir); |
182 | static int check_subdir_for_music(char *dir, const char *subdir, bool recurse); | 184 | static int check_subdir_for_music(char *dir, const char *subdir, bool recurse); |
183 | static int format_track_path(char *dest, char *src, int buf_length, int max, | 185 | static ssize_t format_track_path(char *dest, char *src, int buf_length, |
184 | const char *dir); | 186 | const char *dir); |
185 | static void display_playlist_count(int count, const unsigned char *fmt, | 187 | static void display_playlist_count(int count, const unsigned char *fmt, |
186 | bool final); | 188 | bool final); |
187 | static void display_buffer_full(void); | 189 | static void display_buffer_full(void); |
@@ -526,7 +528,7 @@ static int add_indices_to_playlist(struct playlist_info* playlist, | |||
526 | int result = 0; | 528 | int result = 0; |
527 | /* get emergency buffer so we don't fail horribly */ | 529 | /* get emergency buffer so we don't fail horribly */ |
528 | if (!buflen) | 530 | if (!buflen) |
529 | buffer = __builtin_alloca((buflen = 64)); | 531 | buffer = alloca((buflen = 64)); |
530 | 532 | ||
531 | if(-1 == playlist->fd) | 533 | if(-1 == playlist->fd) |
532 | playlist->fd = open_utf8(playlist->filename, O_RDONLY); | 534 | playlist->fd = open_utf8(playlist->filename, O_RDONLY); |
@@ -1429,7 +1431,7 @@ static int get_filename(struct playlist_info* playlist, int index, int seek, | |||
1429 | 1431 | ||
1430 | strlcpy(dir_buf, playlist->filename, playlist->dirlen); | 1432 | strlcpy(dir_buf, playlist->filename, playlist->dirlen); |
1431 | 1433 | ||
1432 | return (format_track_path(buf, tmp_buf, buf_length, max, dir_buf)); | 1434 | return format_track_path(buf, tmp_buf, buf_length, dir_buf); |
1433 | } | 1435 | } |
1434 | 1436 | ||
1435 | static int get_next_directory(char *dir){ | 1437 | static int get_next_directory(char *dir){ |
@@ -1629,7 +1631,7 @@ static int get_next_dir(char *dir, bool is_forward) | |||
1629 | static int check_subdir_for_music(char *dir, const char *subdir, bool recurse) | 1631 | static int check_subdir_for_music(char *dir, const char *subdir, bool recurse) |
1630 | { | 1632 | { |
1631 | int result = -1; | 1633 | int result = -1; |
1632 | int dirlen = strlen(dir); | 1634 | size_t dirlen = strlen(dir); |
1633 | int num_files = 0; | 1635 | int num_files = 0; |
1634 | int i; | 1636 | int i; |
1635 | struct entry *files; | 1637 | struct entry *files; |
@@ -1637,12 +1639,11 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse) | |||
1637 | bool has_subdir = false; | 1639 | bool has_subdir = false; |
1638 | struct tree_context* tc = tree_get_context(); | 1640 | struct tree_context* tc = tree_get_context(); |
1639 | 1641 | ||
1640 | snprintf( | 1642 | if (path_append(dir + dirlen, PA_SEP_HARD, subdir, MAX_PATH - dirlen) >= |
1641 | dir + dirlen, MAX_PATH - dirlen, | 1643 | MAX_PATH - dirlen) |
1642 | /* only add a trailing slash if we need one */ | 1644 | { |
1643 | dirlen && dir[dirlen - 1] == '/' ? "%s" : "/%s", | 1645 | return 0; |
1644 | subdir | 1646 | } |
1645 | ); | ||
1646 | 1647 | ||
1647 | if (ft_load(tc, dir) < 0) | 1648 | if (ft_load(tc, dir) < 0) |
1648 | { | 1649 | { |
@@ -1695,7 +1696,7 @@ static int check_subdir_for_music(char *dir, const char *subdir, bool recurse) | |||
1695 | } | 1696 | } |
1696 | else | 1697 | else |
1697 | { | 1698 | { |
1698 | strcpy(dir, "/"); | 1699 | strcpy(dir, PATH_ROOTSTR); |
1699 | } | 1700 | } |
1700 | 1701 | ||
1701 | /* we now need to reload our current directory */ | 1702 | /* 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) | |||
1708 | /* | 1709 | /* |
1709 | * Returns absolute path of track | 1710 | * Returns absolute path of track |
1710 | */ | 1711 | */ |
1711 | static int format_track_path(char *dest, char *src, int buf_length, int max, | 1712 | static ssize_t format_track_path(char *dest, char *src, int buf_length, |
1712 | const char *dir) | 1713 | const char *dir) |
1713 | { | 1714 | { |
1714 | int i = 0; | 1715 | size_t len; |
1715 | int j; | ||
1716 | char *temp_ptr; | ||
1717 | |||
1718 | /* Look for the end of the string */ | ||
1719 | while((i < max) && | ||
1720 | (src[i] != '\n') && | ||
1721 | (src[i] != '\r') && | ||
1722 | (src[i] != '\0')) | ||
1723 | i++; | ||
1724 | |||
1725 | /* Now work back killing white space */ | ||
1726 | while((i > 0) && | ||
1727 | ((src[i-1] == ' ') || | ||
1728 | (src[i-1] == '\t'))) | ||
1729 | i--; | ||
1730 | 1716 | ||
1731 | /* Zero-terminate the file name */ | 1717 | /* strip whitespace at beginning and end */ |
1732 | src[i]=0; | 1718 | len = path_trim_whitespace(src, (const char **)&src); |
1719 | src[len] = '\0'; | ||
1733 | 1720 | ||
1734 | /* replace backslashes with forward slashes */ | 1721 | /* replace backslashes with forward slashes */ |
1735 | for ( j=0; j<i; j++ ) | 1722 | path_correct_separators(src, src); |
1736 | if ( src[j] == '\\' ) | ||
1737 | src[j] = '/'; | ||
1738 | 1723 | ||
1739 | if('/' == src[0]) | 1724 | /* handle DOS style drive letter and parse non-greedily so that: |
1740 | { | 1725 | * 1) "c:/foo" becomes "/foo" and the result is absolute |
1741 | strlcpy(dest, src, buf_length); | 1726 | * 2) "c:foo becomes "foo" and the result is relative |
1742 | } | 1727 | * This is how Windows seems to handle it except drive letters are of no |
1743 | else | 1728 | * meaning here. */ |
1744 | { | 1729 | path_strip_drive(src, (const char **)&src, false); |
1745 | /* handle dos style drive letter */ | ||
1746 | if (':' == src[1]) | ||
1747 | strlcpy(dest, &src[2], buf_length); | ||
1748 | else if (!strncmp(src, "../", 3)) | ||
1749 | { | ||
1750 | /* handle relative paths */ | ||
1751 | i=3; | ||
1752 | while(!strncmp(&src[i], "../", 3)) | ||
1753 | i += 3; | ||
1754 | for (j=0; j<i/3; j++) { | ||
1755 | temp_ptr = strrchr(dir, '/'); | ||
1756 | if (temp_ptr) | ||
1757 | *temp_ptr = '\0'; | ||
1758 | else | ||
1759 | break; | ||
1760 | } | ||
1761 | snprintf(dest, buf_length, "%s/%s", dir, &src[i]); | ||
1762 | } | ||
1763 | else if ( '.' == src[0] && '/' == src[1] ) { | ||
1764 | snprintf(dest, buf_length, "%s/%s", dir, &src[2]); | ||
1765 | } | ||
1766 | else { | ||
1767 | snprintf(dest, buf_length, "%s/%s", dir, src); | ||
1768 | } | ||
1769 | } | ||
1770 | #ifdef HAVE_MULTIVOLUME | ||
1771 | 1730 | ||
1772 | char vol_string[VOL_ENUM_POS + 8]; | 1731 | /* prepends directory only if src is relative */ |
1773 | snprintf(vol_string, sizeof(vol_string), "/"VOL_NAMES, 1); | 1732 | len = path_append(dest, *dir ? dir : PATH_ROOTSTR, src, buf_length); |
1733 | if (len >= (size_t)buf_length) | ||
1734 | return -1; /* buffer too small */ | ||
1774 | 1735 | ||
1775 | /*check if the playlist is on a external card, and correct path if needed */ | 1736 | return len; |
1776 | if(strstr(dir, vol_string) && (strstr(dest, vol_string) == NULL)){ | ||
1777 | char temp[buf_length]; | ||
1778 | strlcpy(temp, dest, buf_length); | ||
1779 | snprintf(dest, buf_length, "%s%s", vol_string, temp); | ||
1780 | } | ||
1781 | #endif | ||
1782 | |||
1783 | return 0; | ||
1784 | } | 1737 | } |
1785 | 1738 | ||
1786 | /* | 1739 | /* |
@@ -3113,8 +3066,7 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam | |||
3113 | { | 3066 | { |
3114 | int fd; | 3067 | int fd; |
3115 | int max; | 3068 | int max; |
3116 | char *temp_ptr; | 3069 | char *dir; |
3117 | const char *dir; | ||
3118 | unsigned char *count_str; | 3070 | unsigned char *count_str; |
3119 | char temp_buf[MAX_PATH+1]; | 3071 | char temp_buf[MAX_PATH+1]; |
3120 | char trackname[MAX_PATH+1]; | 3072 | char trackname[MAX_PATH+1]; |
@@ -3139,13 +3091,8 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam | |||
3139 | } | 3091 | } |
3140 | 3092 | ||
3141 | /* we need the directory name for formatting purposes */ | 3093 | /* we need the directory name for formatting purposes */ |
3142 | dir = filename; | 3094 | size_t dirlen = path_dirname(filename, (const char **)&dir); |
3143 | 3095 | dir = strmemdupa(dir, dirlen); | |
3144 | temp_ptr = strrchr(filename+1,'/'); | ||
3145 | if (temp_ptr) | ||
3146 | *temp_ptr = 0; | ||
3147 | else | ||
3148 | dir = "/"; | ||
3149 | 3096 | ||
3150 | if (queue) | 3097 | if (queue) |
3151 | count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT); | 3098 | count_str = ID2P(LANG_PLAYLIST_QUEUE_COUNT); |
@@ -3183,8 +3130,8 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam | |||
3183 | 3130 | ||
3184 | /* we need to format so that relative paths are correctly | 3131 | /* we need to format so that relative paths are correctly |
3185 | handled */ | 3132 | handled */ |
3186 | if (format_track_path(trackname, temp_buf, sizeof(trackname), max, | 3133 | if (format_track_path(trackname, temp_buf, sizeof(trackname), |
3187 | dir) < 0) | 3134 | dir) < 0) |
3188 | { | 3135 | { |
3189 | result = -1; | 3136 | result = -1; |
3190 | break; | 3137 | break; |
@@ -3223,9 +3170,6 @@ int playlist_insert_playlist(struct playlist_info* playlist, const char *filenam | |||
3223 | 3170 | ||
3224 | close(fd); | 3171 | close(fd); |
3225 | 3172 | ||
3226 | if (temp_ptr) | ||
3227 | *temp_ptr = '/'; | ||
3228 | |||
3229 | sync_control(playlist, false); | 3173 | sync_control(playlist, false); |
3230 | 3174 | ||
3231 | cpu_boost(false); | 3175 | cpu_boost(false); |
@@ -3537,9 +3481,9 @@ int playlist_save(struct playlist_info* playlist, char *filename, | |||
3537 | char path[MAX_PATH+1]; | 3481 | char path[MAX_PATH+1]; |
3538 | char tmp_buf[MAX_PATH+1]; | 3482 | char tmp_buf[MAX_PATH+1]; |
3539 | int result = 0; | 3483 | int result = 0; |
3540 | bool overwrite_current = false; | ||
3541 | int *seek_buf; | 3484 | int *seek_buf; |
3542 | bool reparse; | 3485 | bool reparse; |
3486 | ssize_t pathlen; | ||
3543 | 3487 | ||
3544 | ALIGN_BUFFER(temp_buffer, temp_buffer_size, sizeof(int)); | 3488 | ALIGN_BUFFER(temp_buffer, temp_buffer_size, sizeof(int)); |
3545 | seek_buf = temp_buffer; | 3489 | seek_buf = temp_buffer; |
@@ -3557,22 +3501,18 @@ int playlist_save(struct playlist_info* playlist, char *filename, | |||
3557 | return -1; | 3501 | return -1; |
3558 | 3502 | ||
3559 | /* use current working directory as base for pathname */ | 3503 | /* use current working directory as base for pathname */ |
3560 | if (format_track_path(path, filename, sizeof(tmp_buf), | 3504 | pathlen = format_track_path(path, filename, sizeof(path), PATH_ROOTSTR); |
3561 | strlen(filename)+1, "/") < 0) | 3505 | if (pathlen < 0) |
3506 | return -1; | ||
3507 | |||
3508 | /* Use temporary pathname and overwrite/rename later */ | ||
3509 | if (strlcat(path, "_temp", sizeof(path)) >= sizeof (path)) | ||
3562 | return -1; | 3510 | return -1; |
3563 | 3511 | ||
3564 | /* can ignore volatile here, because core_get_data() is called later */ | 3512 | /* can ignore volatile here, because core_get_data() is called later */ |
3565 | char* old_buffer = (char*)playlist->buffer; | 3513 | char* old_buffer = (char*)playlist->buffer; |
3566 | size_t old_buffer_size = playlist->buffer_size; | 3514 | size_t old_buffer_size = playlist->buffer_size; |
3567 | 3515 | ||
3568 | if (!strncmp(playlist->filename, path, strlen(path))) | ||
3569 | { | ||
3570 | /* Attempting to overwrite current playlist file. | ||
3571 | * use temporary pathname and overwrite later */ | ||
3572 | strlcat(path, "_temp", sizeof(path)); | ||
3573 | overwrite_current = true; | ||
3574 | } | ||
3575 | |||
3576 | if (is_m3u8(path)) | 3516 | if (is_m3u8(path)) |
3577 | { | 3517 | { |
3578 | fd = open_utf8(path, O_CREAT|O_WRONLY|O_TRUNC); | 3518 | fd = open_utf8(path, O_CREAT|O_WRONLY|O_TRUNC); |
@@ -3621,8 +3561,8 @@ int playlist_save(struct playlist_info* playlist, char *filename, | |||
3621 | break; | 3561 | break; |
3622 | } | 3562 | } |
3623 | 3563 | ||
3624 | if (overwrite_current && !reparse) | 3564 | if (!reparse) |
3625 | seek_buf[count] = lseek(fd, 0, SEEK_CUR); | 3565 | seek_buf[count] = filesize(fd); |
3626 | 3566 | ||
3627 | if (fdprintf(fd, "%s\n", tmp_buf) < 0) | 3567 | if (fdprintf(fd, "%s\n", tmp_buf) < 0) |
3628 | { | 3568 | { |
@@ -3647,57 +3587,61 @@ int playlist_save(struct playlist_info* playlist, char *filename, | |||
3647 | index = (index+1)%playlist->amount; | 3587 | index = (index+1)%playlist->amount; |
3648 | } | 3588 | } |
3649 | 3589 | ||
3650 | display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true); | ||
3651 | |||
3652 | close(fd); | 3590 | close(fd); |
3591 | fd = -1; | ||
3653 | 3592 | ||
3654 | if (overwrite_current && result >= 0) | 3593 | display_playlist_count(count, ID2P(LANG_PLAYLIST_SAVE_COUNT), true); |
3594 | |||
3595 | if (result >= 0) | ||
3655 | { | 3596 | { |
3656 | result = -1; | 3597 | strmemcpy(tmp_buf, path, pathlen); /* remove "_temp" */ |
3657 | 3598 | ||
3658 | mutex_lock(playlist->control_mutex); | 3599 | mutex_lock(playlist->control_mutex); |
3659 | 3600 | ||
3660 | /* Replace the current playlist with the new one and update indices */ | 3601 | if (!rename(path, tmp_buf)) |
3661 | close(playlist->fd); | ||
3662 | playlist->fd = -1; | ||
3663 | if (remove(playlist->filename) >= 0) | ||
3664 | { | 3602 | { |
3665 | if (rename(path, playlist->filename) >= 0) | 3603 | fd = open_utf8(tmp_buf, O_RDONLY); |
3604 | if (fsamefile(fd, playlist->fd) > 0) | ||
3666 | { | 3605 | { |
3667 | playlist->fd = open_utf8(playlist->filename, O_RDONLY); | 3606 | /* Replace the current playlist with the new one and update |
3668 | if (playlist->fd >= 0) | 3607 | indices */ |
3608 | close(playlist->fd); | ||
3609 | playlist->fd = fd; | ||
3610 | fd = -1; | ||
3611 | |||
3612 | if (!reparse) | ||
3669 | { | 3613 | { |
3670 | if (!reparse) | 3614 | index = playlist->first_index; |
3615 | for (i=0, count=0; i<playlist->amount; i++) | ||
3671 | { | 3616 | { |
3672 | index = playlist->first_index; | 3617 | if (!(playlist->indices[index] & PLAYLIST_QUEUE_MASK)) |
3673 | for (i=0, count=0; i<playlist->amount; i++) | ||
3674 | { | 3618 | { |
3675 | if (!(playlist->indices[index] & PLAYLIST_QUEUE_MASK)) | 3619 | playlist->indices[index] = seek_buf[count]; |
3676 | { | 3620 | count++; |
3677 | playlist->indices[index] = seek_buf[count]; | ||
3678 | count++; | ||
3679 | } | ||
3680 | index = (index+1)%playlist->amount; | ||
3681 | } | 3621 | } |
3622 | index = (index+1)%playlist->amount; | ||
3682 | } | 3623 | } |
3683 | else | ||
3684 | { | ||
3685 | NOTEF("reparsing current playlist (slow)"); | ||
3686 | playlist->amount = 0; | ||
3687 | add_indices_to_playlist(playlist, temp_buffer, temp_buffer_size); | ||
3688 | } | ||
3689 | /* we need to recreate control because inserted tracks are | ||
3690 | now part of the playlist and shuffle has been | ||
3691 | invalidated */ | ||
3692 | result = recreate_control(playlist); | ||
3693 | } | 3624 | } |
3694 | } | 3625 | else |
3695 | } | 3626 | { |
3627 | NOTEF("reparsing current playlist (slow)"); | ||
3628 | playlist->amount = 0; | ||
3629 | add_indices_to_playlist(playlist, temp_buffer, | ||
3630 | temp_buffer_size); | ||
3631 | } | ||
3696 | 3632 | ||
3697 | mutex_unlock(playlist->control_mutex); | 3633 | /* we need to recreate control because inserted tracks are |
3634 | now part of the playlist and shuffle has been invalidated */ | ||
3635 | result = recreate_control(playlist); | ||
3636 | } | ||
3637 | } | ||
3698 | 3638 | ||
3639 | mutex_unlock(playlist->control_mutex); | ||
3699 | } | 3640 | } |
3700 | 3641 | ||
3642 | if (fd >= 0) | ||
3643 | close(fd); | ||
3644 | |||
3701 | cpu_boost(false); | 3645 | cpu_boost(false); |
3702 | 3646 | ||
3703 | reset_old_buffer: | 3647 | reset_old_buffer: |
@@ -3759,8 +3703,12 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse, | |||
3759 | if (recurse) | 3703 | if (recurse) |
3760 | { | 3704 | { |
3761 | /* recursively add directories */ | 3705 | /* recursively add directories */ |
3762 | snprintf(buf, sizeof(buf), "%s/%s", | 3706 | if (path_append(buf, dirname, files[i].name, sizeof(buf)) |
3763 | dirname[1]? dirname: "", files[i].name); | 3707 | >= sizeof(buf)) |
3708 | { | ||
3709 | continue; | ||
3710 | } | ||
3711 | |||
3764 | result = playlist_directory_tracksearch(buf, recurse, | 3712 | result = playlist_directory_tracksearch(buf, recurse, |
3765 | callback, context); | 3713 | callback, context); |
3766 | if (result < 0) | 3714 | if (result < 0) |
@@ -3785,8 +3733,11 @@ int playlist_directory_tracksearch(const char* dirname, bool recurse, | |||
3785 | } | 3733 | } |
3786 | else if ((files[i].attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO) | 3734 | else if ((files[i].attr & FILE_ATTR_MASK) == FILE_ATTR_AUDIO) |
3787 | { | 3735 | { |
3788 | snprintf(buf, sizeof(buf), "%s/%s", | 3736 | if (path_append(buf, dirname, files[i].name, sizeof(buf)) |
3789 | dirname[1]? dirname: "", files[i].name); | 3737 | >= sizeof(buf)) |
3738 | { | ||
3739 | continue; | ||
3740 | } | ||
3790 | 3741 | ||
3791 | if (callback(buf, context) != 0) | 3742 | if (callback(buf, context) != 0) |
3792 | { | 3743 | { |
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 @@ | |||
32 | #include "lang.h" | 32 | #include "lang.h" |
33 | #include "list.h" | 33 | #include "list.h" |
34 | #include "misc.h" | 34 | #include "misc.h" |
35 | #include "filefuncs.h" | 35 | #include "pathfuncs.h" |
36 | #include "onplay.h" | 36 | #include "onplay.h" |
37 | #include "playlist.h" | 37 | #include "playlist.h" |
38 | #include "settings.h" | 38 | #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 @@ | |||
18 | * KIND, either express or implied. | 18 | * KIND, either express or implied. |
19 | * | 19 | * |
20 | ****************************************************************************/ | 20 | ****************************************************************************/ |
21 | #define DIRFUNCTIONS_DEFINED | ||
22 | #define FILEFUNCTIONS_DEFINED | ||
21 | #include "plugin.h" | 23 | #include "plugin.h" |
22 | #include <ctype.h> | 24 | #include <ctype.h> |
23 | #include <string.h> | 25 | #include <string.h> |
@@ -40,8 +42,9 @@ | |||
40 | #include "pcmbuf.h" | 42 | #include "pcmbuf.h" |
41 | #include "errno.h" | 43 | #include "errno.h" |
42 | #include "diacritic.h" | 44 | #include "diacritic.h" |
43 | #include "filefuncs.h" | 45 | #include "pathfuncs.h" |
44 | #include "load_code.h" | 46 | #include "load_code.h" |
47 | #include "file.h" | ||
45 | 48 | ||
46 | #if CONFIG_CHARGING | 49 | #if CONFIG_CHARGING |
47 | #include "power.h" | 50 | #include "power.h" |
@@ -58,80 +61,119 @@ | |||
58 | #include "usbstack/usb_hid.h" | 61 | #include "usbstack/usb_hid.h" |
59 | #endif | 62 | #endif |
60 | 63 | ||
61 | #if defined (SIMULATOR) | 64 | #define WRAPPER(_x_) _x_ ## _wrapper |
62 | #define PREFIX(_x_) sim_ ## _x_ | 65 | |
63 | #elif defined (APPLICATION) | 66 | #if (CONFIG_PLATFORM & PLATFORM_HOSTED) |
64 | #define PREFIX(_x_) app_ ## _x_ | 67 | static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE]; |
68 | void sim_lcd_ex_init(unsigned long (*getpixel)(int, int)); | ||
69 | void sim_lcd_ex_update_rect(int x, int y, int width, int height); | ||
65 | #else | 70 | #else |
66 | #define PREFIX(_x_) _x_ | 71 | extern unsigned char pluginbuf[]; |
72 | #include "bitswap.h" | ||
67 | #endif | 73 | #endif |
68 | 74 | ||
69 | #if defined (APPLICATION) | 75 | /* for actual plugins only, not for codecs */ |
70 | /* For symmetry reasons (we want app_ and sim_ to behave similarly), some | 76 | static int plugin_size = 0; |
71 | * wrappers are needed */ | 77 | static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */ |
72 | static int app_close(int fd) | 78 | static char current_plugin[MAX_PATH]; |
79 | /* NULL if no plugin is loaded, otherwise the handle that lc_open() returned */ | ||
80 | static void *current_plugin_handle; | ||
81 | |||
82 | char *plugin_get_current_filename(void); | ||
83 | |||
84 | static void* plugin_get_audio_buffer(size_t *buffer_size); | ||
85 | static void plugin_release_audio_buffer(void); | ||
86 | static void plugin_tsr(bool (*exit_callback)(bool)); | ||
87 | |||
88 | |||
89 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | ||
90 | /* File handle leak prophylaxis */ | ||
91 | #include "bitarray.h" | ||
92 | #include "file_internal.h" /* for MAX_OPEN_FILES */ | ||
93 | |||
94 | #define PCOC_WRAPPER(_x_) WRAPPER(_x_) | ||
95 | |||
96 | BITARRAY_TYPE_DECLARE(plugin_check_open_close_bitmap_t, open_files_bitmap, | ||
97 | MAX_OPEN_FILES) | ||
98 | |||
99 | static plugin_check_open_close_bitmap_t open_files_bitmap; | ||
100 | |||
101 | static void plugin_check_open_close__enter(void) | ||
73 | { | 102 | { |
74 | return close(fd); | 103 | if (!current_plugin_handle) |
104 | open_files_bitmap_clear(&open_files_bitmap); | ||
75 | } | 105 | } |
76 | 106 | ||
77 | static ssize_t app_read(int fd, void *buf, size_t count) | 107 | static void plugin_check_open_close__open(int fildes) |
78 | { | 108 | { |
79 | return read(fd,buf,count); | 109 | if (fildes >= 0) |
110 | open_files_bitmap_set_bit(&open_files_bitmap, fildes); | ||
80 | } | 111 | } |
81 | 112 | ||
82 | static off_t app_lseek(int fd, off_t offset, int whence) | 113 | static void plugin_check_open_close__close(int fildes) |
83 | { | 114 | { |
84 | return lseek(fd,offset,whence); | 115 | if (fildes < 0) |
116 | return; | ||
117 | |||
118 | if (!open_files_bitmap_test_bit(&open_files_bitmap, fildes)) | ||
119 | { | ||
120 | logf("double close from plugin"); | ||
121 | } | ||
122 | |||
123 | open_files_bitmap_clear_bit(&open_files_bitmap, fildes); | ||
85 | } | 124 | } |
86 | 125 | ||
87 | static ssize_t app_write(int fd, const void *buf, size_t count) | 126 | static int WRAPPER(open)(const char *path, int oflag, ...) |
88 | { | 127 | { |
89 | return write(fd,buf,count); | 128 | int fildes = FS_PREFIX(open)(path, oflag __OPEN_MODE_ARG); |
129 | plugin_check_open_close__open(fildes); | ||
130 | return fildes; | ||
90 | } | 131 | } |
91 | 132 | ||
92 | static int app_ftruncate(int fd, off_t length) | 133 | static int WRAPPER(creat)(const char *path, mode_t mode) |
93 | { | 134 | { |
94 | return ftruncate(fd,length); | 135 | int fildes = FS_PREFIX(creat)(path __CREAT_MODE_ARG); |
136 | plugin_check_open_close__open(fildes); | ||
137 | return fildes; | ||
138 | (void)mode; | ||
95 | } | 139 | } |
96 | #endif | ||
97 | 140 | ||
98 | #if defined(HAVE_PLUGIN_CHECK_OPEN_CLOSE) && (MAX_OPEN_FILES>32) | 141 | static int WRAPPER(close)(int fildes) |
99 | #warning "MAX_OPEN_FILES>32, disabling plugin file open/close checking" | 142 | { |
100 | #undef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 143 | int rc = FS_PREFIX(close)(fildes); |
101 | #endif | 144 | if (rc >= 0) |
145 | plugin_check_open_close__close(fildes); | ||
102 | 146 | ||
103 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 147 | return rc; |
104 | static unsigned int open_files; | 148 | } |
105 | #endif | ||
106 | 149 | ||
107 | #if (CONFIG_PLATFORM & PLATFORM_HOSTED) | 150 | static void plugin_check_open_close__exit(void) |
108 | static unsigned char pluginbuf[PLUGIN_BUFFER_SIZE]; | 151 | { |
109 | void sim_lcd_ex_init(unsigned long (*getpixel)(int, int)); | 152 | if (current_plugin_handle) |
110 | void sim_lcd_ex_update_rect(int x, int y, int width, int height); | 153 | return; |
111 | #else | ||
112 | extern unsigned char pluginbuf[]; | ||
113 | #include "bitswap.h" | ||
114 | #endif | ||
115 | 154 | ||
116 | /* for actual plugins only, not for codecs */ | 155 | if (open_files_bitmap_is_clear(&open_files_bitmap)) |
117 | static int plugin_size = 0; | 156 | return; |
118 | static bool (*pfn_tsr_exit)(bool reenter) = NULL; /* TSR exit callback */ | ||
119 | static char current_plugin[MAX_PATH]; | ||
120 | /* NULL if no plugin is loaded, otherwise the handle that lc_open() returned */ | ||
121 | static void *current_plugin_handle; | ||
122 | 157 | ||
123 | char *plugin_get_current_filename(void); | 158 | logf("Plugin '%s' leaks file handles", plugin); |
124 | 159 | ||
125 | /* Some wrappers used to monitor open and close and detect leaks*/ | 160 | static const char *lines[] = |
126 | static int open_wrapper(const char* pathname, int flags, ...); | 161 | { ID2P(LANG_PLUGIN_ERROR), "#leak-file-handles" }; |
127 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 162 | static const struct text_message message = { lines, 2 }; |
128 | static int close_wrapper(int fd); | 163 | button_clear_queue(); /* Empty the keyboard buffer */ |
129 | static int creat_wrapper(const char *pathname, mode_t mode); | 164 | gui_syncyesno_run(&message, NULL, NULL); |
130 | #endif | ||
131 | 165 | ||
132 | static void* plugin_get_audio_buffer(size_t *buffer_size); | 166 | FOR_EACH_BITARRAY_SET_BIT(&open_files_bitmap, fildes) |
133 | static void plugin_release_audio_buffer(void); | 167 | WRAPPER(close)(fildes); |
134 | static void plugin_tsr(bool (*exit_callback)(bool)); | 168 | } |
169 | |||
170 | #else /* !HAVE_PLUGIN_CHECK_OPEN_CLOSE */ | ||
171 | |||
172 | #define PCOC_WRAPPER(_x_) FS_PREFIX(_x_) | ||
173 | #define plugin_check_open_close__enter() | ||
174 | #define plugin_check_open_close__exit() | ||
175 | |||
176 | #endif /* HAVE_PLUGIN_CHECK_OPEN_CLOSE */ | ||
135 | 177 | ||
136 | static const struct plugin_api rockbox_api = { | 178 | static const struct plugin_api rockbox_api = { |
137 | 179 | ||
@@ -339,24 +381,16 @@ static const struct plugin_api rockbox_api = { | |||
339 | 381 | ||
340 | /* file */ | 382 | /* file */ |
341 | open_utf8, | 383 | open_utf8, |
342 | (open_func)open_wrapper, | 384 | PCOC_WRAPPER(open), |
343 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 385 | PCOC_WRAPPER(creat), |
344 | close_wrapper, | 386 | PCOC_WRAPPER(close), |
345 | #else | 387 | FS_PREFIX(read), |
346 | PREFIX(close), | 388 | FS_PREFIX(lseek), |
347 | #endif | 389 | FS_PREFIX(write), |
348 | (read_func)PREFIX(read), | 390 | FS_PREFIX(remove), |
349 | PREFIX(lseek), | 391 | FS_PREFIX(rename), |
350 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 392 | FS_PREFIX(ftruncate), |
351 | (creat_func)creat_wrapper, | 393 | FS_PREFIX(filesize), |
352 | #else | ||
353 | PREFIX(creat), | ||
354 | #endif | ||
355 | (write_func)PREFIX(write), | ||
356 | PREFIX(remove), | ||
357 | PREFIX(rename), | ||
358 | PREFIX(ftruncate), | ||
359 | filesize, | ||
360 | fdprintf, | 394 | fdprintf, |
361 | read_line, | 395 | read_line, |
362 | settings_parseline, | 396 | settings_parseline, |
@@ -369,18 +403,18 @@ static const struct plugin_api rockbox_api = { | |||
369 | #endif /* USING_STORAGE_CALLBACK */ | 403 | #endif /* USING_STORAGE_CALLBACK */ |
370 | reload_directory, | 404 | reload_directory, |
371 | create_numbered_filename, | 405 | create_numbered_filename, |
372 | file_exists, | 406 | FS_PREFIX(file_exists), |
373 | strip_extension, | 407 | strip_extension, |
374 | crc_32, | 408 | crc_32, |
375 | filetype_get_attr, | 409 | filetype_get_attr, |
376 | 410 | ||
377 | /* dir */ | 411 | /* dir */ |
378 | (opendir_func)opendir, | 412 | FS_PREFIX(opendir), |
379 | (closedir_func)closedir, | 413 | FS_PREFIX(closedir), |
380 | (readdir_func)readdir, | 414 | FS_PREFIX(readdir), |
381 | mkdir, | 415 | FS_PREFIX(mkdir), |
382 | rmdir, | 416 | FS_PREFIX(rmdir), |
383 | dir_exists, | 417 | FS_PREFIX(dir_exists), |
384 | dir_get_info, | 418 | dir_get_info, |
385 | 419 | ||
386 | /* browsing */ | 420 | /* browsing */ |
@@ -688,10 +722,11 @@ static const struct plugin_api rockbox_api = { | |||
688 | #endif | 722 | #endif |
689 | srand, | 723 | srand, |
690 | rand, | 724 | rand, |
691 | (qsort_func)qsort, | 725 | (void *)qsort, |
692 | kbd_input, | 726 | kbd_input, |
693 | get_time, | 727 | get_time, |
694 | set_time, | 728 | set_time, |
729 | gmtime_r, | ||
695 | #if CONFIG_RTC | 730 | #if CONFIG_RTC |
696 | mktime, | 731 | mktime, |
697 | #endif | 732 | #endif |
@@ -891,9 +926,7 @@ int plugin_load(const char* plugin, const void* parameter) | |||
891 | /* allow voice to back off if the plugin needs lots of memory */ | 926 | /* allow voice to back off if the plugin needs lots of memory */ |
892 | talk_buffer_set_policy(TALK_BUFFER_LOOSE); | 927 | talk_buffer_set_policy(TALK_BUFFER_LOOSE); |
893 | 928 | ||
894 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 929 | plugin_check_open_close__enter(); |
895 | open_files = 0; | ||
896 | #endif | ||
897 | 930 | ||
898 | int rc = p_hdr->entry_point(parameter); | 931 | int rc = p_hdr->entry_point(parameter); |
899 | 932 | ||
@@ -947,24 +980,7 @@ int plugin_load(const char* plugin, const void* parameter) | |||
947 | FOR_NB_SCREENS(i) | 980 | FOR_NB_SCREENS(i) |
948 | viewportmanager_theme_undo(i, true); | 981 | viewportmanager_theme_undo(i, true); |
949 | 982 | ||
950 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | 983 | plugin_check_open_close__exit(); |
951 | if(open_files != 0 && !current_plugin_handle) | ||
952 | { | ||
953 | int fd; | ||
954 | logf("Plugin '%s' leaks file handles", plugin); | ||
955 | |||
956 | static const char *lines[] = | ||
957 | { ID2P(LANG_PLUGIN_ERROR), | ||
958 | "#leak-file-handles" }; | ||
959 | static const struct text_message message={ lines, 2 }; | ||
960 | button_clear_queue(); /* Empty the keyboard buffer */ | ||
961 | gui_syncyesno_run(&message, NULL, NULL); | ||
962 | |||
963 | for(fd=0; fd < MAX_OPEN_FILES; fd++) | ||
964 | if(open_files & (1<<fd)) | ||
965 | close_wrapper(fd); | ||
966 | } | ||
967 | #endif | ||
968 | 984 | ||
969 | if (rc == PLUGIN_ERROR) | 985 | if (rc == PLUGIN_ERROR) |
970 | splash(HZ*2, str(LANG_PLUGIN_ERROR)); | 986 | splash(HZ*2, str(LANG_PLUGIN_ERROR)); |
@@ -1027,55 +1043,3 @@ char *plugin_get_current_filename(void) | |||
1027 | { | 1043 | { |
1028 | return current_plugin; | 1044 | return current_plugin; |
1029 | } | 1045 | } |
1030 | |||
1031 | static int open_wrapper(const char* pathname, int flags, ...) | ||
1032 | { | ||
1033 | /* we don't have an 'open' function. it's a define. and we need | ||
1034 | * the real file_open, hence PREFIX() doesn't work here */ | ||
1035 | int fd; | ||
1036 | #if (CONFIG_PLATFORM & PLATFORM_HOSTED) | ||
1037 | if (flags & O_CREAT) | ||
1038 | { | ||
1039 | va_list ap; | ||
1040 | va_start(ap, flags); | ||
1041 | fd = open(pathname, flags, va_arg(ap, unsigned int)); | ||
1042 | va_end(ap); | ||
1043 | } | ||
1044 | else | ||
1045 | fd = open(pathname, flags); | ||
1046 | #else | ||
1047 | fd = file_open(pathname,flags); | ||
1048 | #endif | ||
1049 | |||
1050 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | ||
1051 | if(fd >= 0) | ||
1052 | open_files |= 1<<fd; | ||
1053 | #endif | ||
1054 | return fd; | ||
1055 | } | ||
1056 | |||
1057 | #ifdef HAVE_PLUGIN_CHECK_OPEN_CLOSE | ||
1058 | static int close_wrapper(int fd) | ||
1059 | { | ||
1060 | if((~open_files) & (1<<fd)) | ||
1061 | { | ||
1062 | logf("double close from plugin"); | ||
1063 | } | ||
1064 | if(fd >= 0) | ||
1065 | open_files &= (~(1<<fd)); | ||
1066 | |||
1067 | return PREFIX(close)(fd); | ||
1068 | } | ||
1069 | |||
1070 | static int creat_wrapper(const char *pathname, mode_t mode) | ||
1071 | { | ||
1072 | (void)mode; | ||
1073 | |||
1074 | int fd = PREFIX(creat)(pathname, mode); | ||
1075 | |||
1076 | if(fd >= 0) | ||
1077 | open_files |= (1<<fd); | ||
1078 | |||
1079 | return fd; | ||
1080 | } | ||
1081 | #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); | |||
75 | #include "profile.h" | 75 | #include "profile.h" |
76 | #endif | 76 | #endif |
77 | #include "misc.h" | 77 | #include "misc.h" |
78 | #include "filefuncs.h" | 78 | #include "pathfuncs.h" |
79 | #if (CONFIG_CODEC == SWCODEC) | 79 | #if (CONFIG_CODEC == SWCODEC) |
80 | #include "pcm_mixer.h" | 80 | #include "pcm_mixer.h" |
81 | #include "dsp-util.h" | 81 | #include "dsp-util.h" |
@@ -160,12 +160,12 @@ void* plugin_get_buffer(size_t *buffer_size); | |||
160 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ | 160 | #define PLUGIN_MAGIC 0x526F634B /* RocK */ |
161 | 161 | ||
162 | /* increase this every time the api struct changes */ | 162 | /* increase this every time the api struct changes */ |
163 | #define PLUGIN_API_VERSION 231 | 163 | #define PLUGIN_API_VERSION 232 |
164 | 164 | ||
165 | /* update this to latest version if a change to the api struct breaks | 165 | /* update this to latest version if a change to the api struct breaks |
166 | backwards compatibility (and please take the opportunity to sort in any | 166 | backwards compatibility (and please take the opportunity to sort in any |
167 | new function which are "waiting" at the end of the function table) */ | 167 | new function which are "waiting" at the end of the function table) */ |
168 | #define PLUGIN_MIN_API_VERSION 231 | 168 | #define PLUGIN_MIN_API_VERSION 232 |
169 | 169 | ||
170 | /* plugin return codes */ | 170 | /* plugin return codes */ |
171 | /* internal returns start at 0x100 to make exit(1..255) work */ | 171 | /* internal returns start at 0x100 to make exit(1..255) work */ |
@@ -433,17 +433,17 @@ struct plugin_api { | |||
433 | 433 | ||
434 | /* file */ | 434 | /* file */ |
435 | int (*open_utf8)(const char* pathname, int flags); | 435 | int (*open_utf8)(const char* pathname, int flags); |
436 | int (*open)(const char* pathname, int flags, ...); | 436 | int (*open)(const char *path, int oflag, ...); |
437 | int (*close)(int fd); | 437 | int (*creat)(const char *path, mode_t mode); |
438 | ssize_t (*read)(int fd, void* buf, size_t count); | 438 | int (*close)(int fildes); |
439 | off_t (*lseek)(int fd, off_t offset, int whence); | 439 | ssize_t (*read)(int fildes, void *buf, size_t nbyte); |
440 | int (*creat)(const char *pathname, mode_t mode); | 440 | off_t (*lseek)(int fildes, off_t offset, int whence); |
441 | ssize_t (*write)(int fd, const void* buf, size_t count); | 441 | ssize_t (*write)(int fildes, const void *buf, size_t nbyte); |
442 | int (*remove)(const char* pathname); | 442 | int (*remove)(const char *path); |
443 | int (*rename)(const char* path, const char* newname); | 443 | int (*rename)(const char *old, const char *new); |
444 | int (*ftruncate)(int fd, off_t length); | 444 | int (*ftruncate)(int fildes, off_t length); |
445 | off_t (*filesize)(int fd); | 445 | off_t (*filesize)(int fildes); |
446 | int (*fdprintf)(int fd, const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); | 446 | int (*fdprintf)(int fildes, const char *fmt, ...) ATTRIBUTE_PRINTF(2, 3); |
447 | int (*read_line)(int fd, char* buffer, int buffer_size); | 447 | int (*read_line)(int fd, char* buffer, int buffer_size); |
448 | bool (*settings_parseline)(char* line, char** name, char** value); | 448 | bool (*settings_parseline)(char* line, char** name, char** value); |
449 | void (*storage_sleep)(void); | 449 | void (*storage_sleep)(void); |
@@ -457,7 +457,7 @@ struct plugin_api { | |||
457 | char *(*create_numbered_filename)(char *buffer, const char *path, | 457 | char *(*create_numbered_filename)(char *buffer, const char *path, |
458 | const char *prefix, const char *suffix, | 458 | const char *prefix, const char *suffix, |
459 | int numberlen IF_CNFN_NUM_(, int *num)); | 459 | int numberlen IF_CNFN_NUM_(, int *num)); |
460 | bool (*file_exists)(const char *file); | 460 | bool (*file_exists)(const char *path); |
461 | char* (*strip_extension)(char* buffer, int buffer_size, const char *filename); | 461 | char* (*strip_extension)(char* buffer, int buffer_size, const char *filename); |
462 | uint32_t (*crc_32)(const void *src, uint32_t len, uint32_t crc32); | 462 | uint32_t (*crc_32)(const void *src, uint32_t len, uint32_t crc32); |
463 | 463 | ||
@@ -466,13 +466,13 @@ struct plugin_api { | |||
466 | 466 | ||
467 | 467 | ||
468 | /* dir */ | 468 | /* dir */ |
469 | DIR* (*opendir)(const char* name); | 469 | DIR * (*opendir)(const char *dirname); |
470 | int (*closedir)(DIR* dir); | 470 | int (*closedir)(DIR *dirp); |
471 | struct dirent* (*readdir)(DIR* dir); | 471 | struct dirent * (*readdir)(DIR *dirp); |
472 | int (*mkdir)(const char *name); | 472 | int (*mkdir)(const char *path); |
473 | int (*rmdir)(const char *name); | 473 | int (*rmdir)(const char *path); |
474 | bool (*dir_exists)(const char *path); | 474 | bool (*dir_exists)(const char *dirname); |
475 | struct dirinfo (*dir_get_info)(DIR* parent, struct dirent *entry); | 475 | struct dirinfo (*dir_get_info)(DIR *dirp, struct dirent *entry); |
476 | 476 | ||
477 | /* browsing */ | 477 | /* browsing */ |
478 | void (*browse_context_init)(struct browse_context *browse, | 478 | void (*browse_context_init)(struct browse_context *browse, |
@@ -838,6 +838,7 @@ struct plugin_api { | |||
838 | int (*kbd_input)(char* buffer, int buflen); | 838 | int (*kbd_input)(char* buffer, int buflen); |
839 | struct tm* (*get_time)(void); | 839 | struct tm* (*get_time)(void); |
840 | int (*set_time)(const struct tm *tm); | 840 | int (*set_time)(const struct tm *tm); |
841 | struct tm * (*gmtime_r)(const time_t *timep, struct tm *tm); | ||
841 | #if CONFIG_RTC | 842 | #if CONFIG_RTC |
842 | time_t (*mktime)(struct tm *t); | 843 | time_t (*mktime)(struct tm *t); |
843 | #endif | 844 | #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) | |||
99 | log = human_size_log((unsigned long)info.size); | 99 | log = human_size_log((unsigned long)info.size); |
100 | rb->snprintf(str_size, sizeof str_size, "%lu %cB", | 100 | rb->snprintf(str_size, sizeof str_size, "%lu %cB", |
101 | ((unsigned long)info.size) >> (log*10), human_size_prefix[log]); | 101 | ((unsigned long)info.size) >> (log*10), human_size_prefix[log]); |
102 | struct tm tm; | ||
103 | rb->gmtime_r(&info.mtime, &tm); | ||
102 | rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d", | 104 | rb->snprintf(str_date, sizeof str_date, "%04d/%02d/%02d", |
103 | ((info.wrtdate >> 9 ) & 0x7F) + 1980, /* year */ | 105 | tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); |
104 | ((info.wrtdate >> 5 ) & 0x0F), /* month */ | 106 | rb->snprintf(str_time, sizeof str_time, "%02d:%02d:%02d", |
105 | ((info.wrtdate ) & 0x1F)); /* day */ | 107 | tm.tm_hour, tm.tm_min, tm.tm_sec); |
106 | rb->snprintf(str_time, sizeof str_time, "%02d:%02d", | ||
107 | ((info.wrttime >> 11) & 0x1F), /* hour */ | ||
108 | ((info.wrttime >> 5 ) & 0x3F)); /* minutes */ | ||
109 | 108 | ||
110 | num_properties = 5; | 109 | num_properties = 5; |
111 | 110 | ||
@@ -175,7 +174,10 @@ static bool _dir_properties(DPS* dps) | |||
175 | dirlen = rb->strlen(dps->dirname); | 174 | dirlen = rb->strlen(dps->dirname); |
176 | dir = rb->opendir(dps->dirname); | 175 | dir = rb->opendir(dps->dirname); |
177 | if (!dir) | 176 | if (!dir) |
177 | { | ||
178 | rb->splashf(HZ*2, "%s", dps->dirname); | ||
178 | return false; /* open error */ | 179 | return false; /* open error */ |
180 | } | ||
179 | 181 | ||
180 | /* walk through the directory content */ | 182 | /* walk through the directory content */ |
181 | while(result && (0 != (entry = rb->readdir(dir)))) | 183 | 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 @@ | |||
30 | #include "file.h" | 30 | #include "file.h" |
31 | #include "string-extra.h" | 31 | #include "string-extra.h" |
32 | #include "misc.h" | 32 | #include "misc.h" |
33 | #include "filefuncs.h" | 33 | #include "pathfuncs.h" |
34 | #include "lang.h" | 34 | #include "lang.h" |
35 | #include "action.h" | 35 | #include "action.h" |
36 | #include "list.h" | 36 | #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 @@ | |||
31 | #include "file.h" | 31 | #include "file.h" |
32 | #include "kernel.h" | 32 | #include "kernel.h" |
33 | #include "string-extra.h" | 33 | #include "string-extra.h" |
34 | #include "filefuncs.h" | 34 | #include "pathfuncs.h" |
35 | #include "core_alloc.h" | 35 | #include "core_alloc.h" |
36 | 36 | ||
37 | #define MAX_RADIOART_IMAGES 10 | 37 | #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 @@ | |||
27 | #include "buffering.h" | 27 | #include "buffering.h" |
28 | #include "dircache.h" | 28 | #include "dircache.h" |
29 | #include "misc.h" | 29 | #include "misc.h" |
30 | #include "filefuncs.h" | 30 | #include "pathfuncs.h" |
31 | #include "settings.h" | 31 | #include "settings.h" |
32 | #include "wps.h" | 32 | #include "wps.h" |
33 | 33 | ||
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 @@ | |||
56 | #include "timefuncs.h" | 56 | #include "timefuncs.h" |
57 | #include "debug.h" | 57 | #include "debug.h" |
58 | #include "misc.h" | 58 | #include "misc.h" |
59 | #include "filefuncs.h" | 59 | #include "pathfuncs.h" |
60 | #include "tree.h" | 60 | #include "tree.h" |
61 | #include "string.h" | 61 | #include "string.h" |
62 | #include "dir.h" | 62 | #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) | |||
146 | int i; | 146 | int i; |
147 | for (i = 0; i < NUM_VOLUMES; i++) | 147 | for (i = 0; i < NUM_VOLUMES; i++) |
148 | { | 148 | { |
149 | char vol_string[VOL_ENUM_POS + 8]; | 149 | char vol_string[VOL_MAX_LEN + 1]; |
150 | if (!volume_removable(i)) | 150 | if (!volume_removable(i)) |
151 | continue; | 151 | continue; |
152 | /* VOL_NAMES contains a %d */ | 152 | get_volume_name(i, vol_string); |
153 | snprintf(vol_string, sizeof(vol_string), "/"VOL_NAMES, i); | ||
154 | /* test whether we would browse the external card */ | 153 | /* test whether we would browse the external card */ |
155 | if (!volume_present(i) && | 154 | if (!volume_present(i) && |
156 | (strstr(last_folder, vol_string) | 155 | (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 | |||
33 | #include "core_alloc.h" | 33 | #include "core_alloc.h" |
34 | #include "settings.h" | 34 | #include "settings.h" |
35 | #include "ata_idle_notify.h" | 35 | #include "ata_idle_notify.h" |
36 | #include "filefuncs.h" | 36 | #include "pathfuncs.h" |
37 | #include "appevents.h" | 37 | #include "appevents.h" |
38 | 38 | ||
39 | #if CONFIG_RTC | 39 | #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) | |||
822 | #ifdef HAVE_LCD_BITMAP | 822 | #ifdef HAVE_LCD_BITMAP |
823 | int rc; | 823 | int rc; |
824 | #endif | 824 | #endif |
825 | CHART(">set_codepage"); | ||
826 | set_codepage(global_settings.default_codepage); | ||
827 | CHART("<set_codepage"); | ||
828 | |||
825 | sound_settings_apply(); | 829 | sound_settings_apply(); |
826 | 830 | ||
827 | #ifdef HAVE_DISK_STORAGE | 831 | #ifdef HAVE_DISK_STORAGE |
@@ -1008,10 +1012,6 @@ void settings_apply(bool read_disk) | |||
1008 | lcd_scroll_delay(global_settings.scroll_delay); | 1012 | lcd_scroll_delay(global_settings.scroll_delay); |
1009 | 1013 | ||
1010 | 1014 | ||
1011 | CHART(">set_codepage"); | ||
1012 | set_codepage(global_settings.default_codepage); | ||
1013 | CHART("<set_codepage"); | ||
1014 | |||
1015 | #ifdef HAVE_PLAY_FREQ | 1015 | #ifdef HAVE_PLAY_FREQ |
1016 | settings_apply_play_freq(global_settings.play_frequency, false); | 1016 | settings_apply_play_freq(global_settings.play_frequency, false); |
1017 | #endif | 1017 | #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[] = { | |||
1724 | OFFON_SETTING(F_BANFROMQS, tagcache_autoupdate, LANG_TAGCACHE_AUTOUPDATE, false, | 1724 | OFFON_SETTING(F_BANFROMQS, tagcache_autoupdate, LANG_TAGCACHE_AUTOUPDATE, false, |
1725 | "tagcache_autoupdate", NULL), | 1725 | "tagcache_autoupdate", NULL), |
1726 | #endif | 1726 | #endif |
1727 | CHOICE_SETTING(0, default_codepage, LANG_DEFAULT_CODEPAGE, 0, | 1727 | CHOICE_SETTING(F_TEMPVAR, default_codepage, LANG_DEFAULT_CODEPAGE, 0, |
1728 | "default codepage", | 1728 | "default codepage", |
1729 | #ifdef HAVE_LCD_BITMAP | 1729 | #ifdef HAVE_LCD_BITMAP |
1730 | /* The order must match with that in unicode.c */ | 1730 | /* The order must match with that in unicode.c */ |
1731 | "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256," | 1731 | "iso8859-1,iso8859-7,iso8859-8,cp1251,iso8859-11,cp1256," |
1732 | "iso8859-9,iso8859-2,cp1250,cp1252,sjis,gb2312,ksx1001,big5,utf-8", | 1732 | "iso8859-9,iso8859-2,cp1250,cp1252,sjis,gb2312,ksx1001,big5,utf-8", |
1733 | set_codepage, 15, | 1733 | NULL, 15, |
1734 | ID2P(LANG_CODEPAGE_LATIN1), | 1734 | ID2P(LANG_CODEPAGE_LATIN1), |
1735 | ID2P(LANG_CODEPAGE_GREEK), | 1735 | ID2P(LANG_CODEPAGE_GREEK), |
1736 | ID2P(LANG_CODEPAGE_HEBREW), ID2P(LANG_CODEPAGE_CYRILLIC), | 1736 | ID2P(LANG_CODEPAGE_HEBREW), ID2P(LANG_CODEPAGE_CYRILLIC), |
@@ -1745,7 +1745,7 @@ const struct settings_list settings[] = { | |||
1745 | #else /* !HAVE_LCD_BITMAP */ | 1745 | #else /* !HAVE_LCD_BITMAP */ |
1746 | /* The order must match with that in unicode.c */ | 1746 | /* The order must match with that in unicode.c */ |
1747 | "iso8859-1,iso8859-7,cp1251,iso8859-9,iso8859-2,cp1250,cp1252,utf-8", | 1747 | "iso8859-1,iso8859-7,cp1251,iso8859-9,iso8859-2,cp1250,cp1252,utf-8", |
1748 | set_codepage, 8, | 1748 | NULL, 8, |
1749 | ID2P(LANG_CODEPAGE_LATIN1), ID2P(LANG_CODEPAGE_GREEK), | 1749 | ID2P(LANG_CODEPAGE_LATIN1), ID2P(LANG_CODEPAGE_GREEK), |
1750 | ID2P(LANG_CODEPAGE_CYRILLIC), ID2P(LANG_CODEPAGE_TURKISH), | 1750 | ID2P(LANG_CODEPAGE_CYRILLIC), ID2P(LANG_CODEPAGE_TURKISH), |
1751 | ID2P(LANG_CODEPAGE_LATIN_EXTENDED), | 1751 | 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 @@ | |||
37 | #include "misc.h" | 37 | #include "misc.h" |
38 | #include "tree.h" | 38 | #include "tree.h" |
39 | #include "splash.h" | 39 | #include "splash.h" |
40 | #include "filefuncs.h" | 40 | #include "pathfuncs.h" |
41 | #include "filetypes.h" | 41 | #include "filetypes.h" |
42 | #include "shortcuts.h" | 42 | #include "shortcuts.h" |
43 | #include "onplay.h" | 43 | #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 @@ | |||
79 | #include "misc.h" | 79 | #include "misc.h" |
80 | #include "settings.h" | 80 | #include "settings.h" |
81 | #include "dir.h" | 81 | #include "dir.h" |
82 | #include "filefuncs.h" | 82 | #include "pathfuncs.h" |
83 | #include "structec.h" | 83 | #include "structec.h" |
84 | #include "debug.h" | 84 | #include "debug.h" |
85 | 85 | ||
@@ -88,6 +88,8 @@ | |||
88 | #include "eeprom_settings.h" | 88 | #include "eeprom_settings.h" |
89 | #endif | 89 | #endif |
90 | 90 | ||
91 | #undef HAVE_DIRCACHE | ||
92 | |||
91 | #ifdef __PCTOOL__ | 93 | #ifdef __PCTOOL__ |
92 | #define yield() do { } while(0) | 94 | #define yield() do { } while(0) |
93 | #define sim_sleep(timeout) do { } while(0) | 95 | #define sim_sleep(timeout) do { } while(0) |
@@ -2986,20 +2988,21 @@ static bool commit(void) | |||
2986 | /* Try to steal every buffer we can :) */ | 2988 | /* Try to steal every buffer we can :) */ |
2987 | if (tempbuf_size == 0) | 2989 | if (tempbuf_size == 0) |
2988 | local_allocation = true; | 2990 | local_allocation = true; |
2989 | 2991 | ||
2992 | #if 0 /* FIXME: How much big? dircache buffer can no longer be taken but | ||
2993 | may be freed to make room and the cache resumed. --jethead71 */ | ||
2990 | #ifdef HAVE_DIRCACHE | 2994 | #ifdef HAVE_DIRCACHE |
2991 | if (tempbuf_size == 0) | 2995 | if (tempbuf_size == 0) |
2992 | { | 2996 | { |
2993 | /* Try to steal the dircache buffer. */ | 2997 | /* Shut down dircache to free its allocation. */ |
2994 | tempbuf = dircache_steal_buffer(&tempbuf_size); | 2998 | dircache_free_buffer(); |
2995 | tempbuf_size &= ~0x03; | ||
2996 | |||
2997 | if (tempbuf_size > 0) | 2999 | if (tempbuf_size > 0) |
2998 | { | 3000 | { |
2999 | dircache_buffer_stolen = true; | 3001 | dircache_buffer_stolen = true; |
3000 | } | 3002 | } |
3001 | } | 3003 | } |
3002 | #endif | 3004 | #endif |
3005 | #endif | ||
3003 | 3006 | ||
3004 | #ifdef HAVE_TC_RAMCACHE | 3007 | #ifdef HAVE_TC_RAMCACHE |
3005 | if (tempbuf_size == 0 && tc_stat.ramcache_allocated > 0) | 3008 | if (tempbuf_size == 0 && tc_stat.ramcache_allocated > 0) |
@@ -4462,7 +4465,7 @@ static bool check_dir(const char *dirname, int add_files) | |||
4462 | tc_stat.curentry = curpath; | 4465 | tc_stat.curentry = curpath; |
4463 | 4466 | ||
4464 | /* Add a new entry to the temporary db file. */ | 4467 | /* Add a new entry to the temporary db file. */ |
4465 | add_tagcache(curpath, (info.wrtdate << 16) | info.wrttime | 4468 | add_tagcache(curpath, info.mtime |
4466 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) | 4469 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) |
4467 | , dir->internal_entry | 4470 | , dir->internal_entry |
4468 | #endif | 4471 | #endif |
@@ -4780,7 +4783,7 @@ void tagcache_shutdown(void) | |||
4780 | /* Flush the command queue. */ | 4783 | /* Flush the command queue. */ |
4781 | run_command_queue(true); | 4784 | run_command_queue(true); |
4782 | 4785 | ||
4783 | #ifdef HAVE_EEPROM_SETTINGS | 4786 | #if defined(HAVE_EEPROM_SETTINGS) && defined(HAVE_TC_RAMCACHE) |
4784 | if (tc_stat.ramcache) | 4787 | if (tc_stat.ramcache) |
4785 | tagcache_dumpsave(); | 4788 | tagcache_dumpsave(); |
4786 | #endif | 4789 | #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 @@ | |||
52 | #include "talk.h" | 52 | #include "talk.h" |
53 | #include "filetypes.h" | 53 | #include "filetypes.h" |
54 | #include "misc.h" | 54 | #include "misc.h" |
55 | #include "filefuncs.h" | 55 | #include "pathfuncs.h" |
56 | #include "filetree.h" | 56 | #include "filetree.h" |
57 | #include "tagtree.h" | 57 | #include "tagtree.h" |
58 | #ifdef HAVE_RECORDING | 58 | #ifdef HAVE_RECORDING |
@@ -1205,26 +1205,36 @@ void tree_flush(void) | |||
1205 | #endif | 1205 | #endif |
1206 | 1206 | ||
1207 | #ifdef HAVE_DIRCACHE | 1207 | #ifdef HAVE_DIRCACHE |
1208 | int old_val = global_status.dircache_size; | ||
1209 | #ifdef HAVE_EEPROM_SETTINGS | ||
1210 | bool savecache = false; | ||
1211 | #endif | ||
1212 | |||
1213 | if (global_settings.dircache) | ||
1208 | { | 1214 | { |
1209 | int old_val = global_status.dircache_size; | 1215 | dircache_suspend(); |
1210 | if (global_settings.dircache) | 1216 | |
1211 | { | 1217 | struct dircache_info info; |
1212 | if (!dircache_is_initializing()) | 1218 | dircache_get_info(&info); |
1213 | global_status.dircache_size = dircache_get_cache_size(); | 1219 | |
1214 | # ifdef HAVE_EEPROM_SETTINGS | 1220 | global_status.dircache_size = info.last_size; |
1215 | if (firmware_settings.initialized) | 1221 | #ifdef HAVE_EEPROM_SETTINGS |
1216 | dircache_save(); | 1222 | savecache = firmware_settings.initialized; |
1217 | # endif | 1223 | #endif |
1218 | dircache_suspend(); | ||
1219 | } | ||
1220 | else | ||
1221 | { | ||
1222 | global_status.dircache_size = 0; | ||
1223 | } | ||
1224 | if (old_val != global_status.dircache_size) | ||
1225 | status_save(); | ||
1226 | } | 1224 | } |
1227 | #endif | 1225 | else |
1226 | { | ||
1227 | global_status.dircache_size = 0; | ||
1228 | } | ||
1229 | |||
1230 | if (old_val != global_status.dircache_size) | ||
1231 | status_save(); | ||
1232 | |||
1233 | #ifdef HAVE_EEPROM_SETTINGS | ||
1234 | if (savecache) | ||
1235 | dircache_save(); | ||
1236 | #endif | ||
1237 | #endif /* HAVE_DIRCACHE */ | ||
1228 | } | 1238 | } |
1229 | 1239 | ||
1230 | void tree_restore(void) | 1240 | void tree_restore(void) |
@@ -1238,15 +1248,14 @@ void tree_restore(void) | |||
1238 | #endif | 1248 | #endif |
1239 | 1249 | ||
1240 | #ifdef HAVE_DIRCACHE | 1250 | #ifdef HAVE_DIRCACHE |
1241 | remove(DIRCACHE_FILE); | 1251 | if (global_settings.dircache && dircache_resume() > 0) |
1242 | if (global_settings.dircache) | ||
1243 | { | 1252 | { |
1244 | /* Print "Scanning disk..." to the display. */ | 1253 | /* Print "Scanning disk..." to the display. */ |
1245 | splash(0, str(LANG_SCANNING_DISK)); | 1254 | splash(0, str(LANG_SCANNING_DISK)); |
1246 | 1255 | dircache_wait(); | |
1247 | dircache_build(global_status.dircache_size); | ||
1248 | } | 1256 | } |
1249 | #endif | 1257 | #endif |
1258 | |||
1250 | #ifdef HAVE_TAGCACHE | 1259 | #ifdef HAVE_TAGCACHE |
1251 | tagcache_start_scan(); | 1260 | tagcache_start_scan(); |
1252 | #endif | 1261 | #endif |