diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2013-08-05 22:02:45 -0400 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2014-08-30 03:48:23 +0200 |
commit | 7d1a47cf13726c95ac46027156cc12dd9da5b855 (patch) | |
tree | eb20d07656806479a8e1fea25887a490ea30d1d8 /apps | |
parent | 95a4c3afcd53a1f8b835dec33de51f9c304de4d9 (diff) | |
download | rockbox-7d1a47cf13726c95ac46027156cc12dd9da5b855.tar.gz rockbox-7d1a47cf13726c95ac46027156cc12dd9da5b855.zip |
Rewrite filesystem code (WIP)
This patch redoes the filesystem code from the FAT driver up to the
clipboard code in onplay.c.
Not every aspect of this is finished therefore it is still "WIP". I
don't wish to do too much at once (haha!). What is left to do is get
dircache back in the sim and find an implementation for the dircache
indicies in the tagcache and playlist code or do something else that
has the same benefit. Leaving these out for now does not make anything
unusable. All the basics are done.
Phone app code should probably get vetted (and app path handling
just plain rewritten as environment expansions); the SDL app and
Android run well.
Main things addressed:
1) Thread safety: There is none right now in the trunk code. Most of
what currently works is luck when multiple threads are involved or
multiple descriptors to the same file are open.
2) POSIX compliance: Many of the functions behave nothing like their
counterparts on a host system. This leads to inconsistent code or very
different behavior from native to hosted. One huge offender was
rename(). Going point by point would fill a book.
3) Actual running RAM usage: Many targets will use less RAM and less
stack space (some more RAM because I upped the number of cache buffers
for large memory). There's very little memory lying fallow in rarely-used
areas (see 'Key core changes' below). Also, all targets may open the same
number of directory streams whereas before those with less than 8MB RAM
were limited to 8, not 12 implying those targets will save slightly
less.
4) Performance: The test_disk plugin shows markedly improved performance,
particularly in the area of (uncached) directory scanning, due partly to
more optimal directory reading and to a better sector cache algorithm.
Uncached times tend to be better while there is a bit of a slowdown in
dircache due to it being a bit heavier of an implementation. It's not
noticeable by a human as far as I can say.
Key core changes:
1) Files and directories share core code and data structures.
2) The filesystem code knows which descriptors refer to same file.
This ensures that changes from one stream are appropriately reflected
in every open descriptor for that file (fileobj_mgr.c).
3) File and directory cache buffers are borrowed from the main sector
cache. This means that when they are not in use by a file, they are not
wasted, but used for the cache. Most of the time, only a few of them
are needed. It also means that adding more file and directory handles
is less expensive. All one must do in ensure a large enough cache to
borrow from.
4) Relative path components are supported and the namespace is unified.
It does not support full relative paths to an implied current directory;
what is does support is use of "." and "..". Adding the former would
not be very difficult. The namespace is unified in the sense that
volumes may be specified several times along with relative parts, e.g.:
"/<0>/foo/../../<1>/bar" :<=> "/<1>/bar".
5) Stack usage is down due to sharing of data, static allocation and
less duplication of strings on the stack. This requires more
serialization than I would like but since the number of threads is
limited to a low number, the tradoff in favor of the stack seems
reasonable.
6) Separates and heirarchicalizes (sic) the SIM and APP filesystem
code. SIM path and volume handling is just like the target. Some
aspects of the APP file code get more straightforward (e.g. no path
hashing is needed).
Dircache:
Deserves its own section. Dircache is new but pays homage to the old.
The old one was not compatible and so it, since it got redone, does
all the stuff it always should have done such as:
1) It may be update and used at any time during the build process.
No longer has one to wait for it to finish building to do basic file
management (create, remove, rename, etc.).
2) It does not need to be either fully scanned or completely disabled;
it can be incomplete (i.e. overfilled, missing paths), still be
of benefit and be correct.
3) Handles mounting and dismounting of individual volumes which means
a full rebuild is not needed just because you pop a new SD card in the
slot. Now, because it reuses its freed entry data, may rebuild only
that volume.
4) Much more fundamental to the file code. When it is built, it is
the keeper of the master file list whether enabled or not ("disabled"
is just a state of the cache). Its must always to ready to be started
and bind all streams opened prior to being enabled.
5) Maintains any short filenames in OEM format which means that it does
not need to be rebuilt when changing the default codepage.
Miscellaneous Compatibility:
1) Update any other code that would otherwise not work such as the
hotswap mounting code in various card drivers.
2) File management: Clipboard needed updating because of the behavioral
changes. Still needs a little more work on some finer points.
3) Remove now-obsolete functionality such as the mutex's "no preempt"
flag (which was only for the prior FAT driver).
4) struct dirinfo uses time_t rather than raw FAT directory entry
time fields. I plan to follow up on genericizing everything there
(i.e. no FAT attributes).
5) unicode.c needed some redoing so that the file code does not try
try to load codepages during a scan, which is actually a problem with
the current code. The default codepage, if any is required, is now
kept in RAM separarately (bufalloced) from codepages specified to
iso_decode() (which must not be bufalloced because the conversion
may be done by playback threads).
Brings with it some additional reusable core code:
1) Revised file functions: Reusable code that does things such as
safe path concatenation and parsing without buffer limitations or
data duplication. Variants that copy or alter the input path may be
based off these.
To do:
1) Put dircache functionality back in the sim. Treating it internally
as a different kind of file system seems the best approach at this
time.
2) Restore use of dircache indexes in the playlist and database or
something effectively the same. Since the cache doesn't have to be
complete in order to be used, not getting a hit on the cache doesn't
unambiguously say if the path exists or not.
Change-Id: Ia30f3082a136253e3a0eae0784e3091d138915c8
Reviewed-on: http://gerrit.rockbox.org/566
Reviewed-by: Michael Sevakis <jethead71@rockbox.org>
Tested: Michael Sevakis <jethead71@rockbox.org>
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 |