summaryrefslogtreecommitdiffstats
path: root/firmware/common/dircache.c
diff options
context:
space:
mode:
authorThomas Martitz <kugel@rockbox.org>2011-07-30 23:21:58 +0000
committerThomas Martitz <kugel@rockbox.org>2011-07-30 23:21:58 +0000
commit32b54164d88e9155b5b01a51cad71017ecf7294a (patch)
tree53bebd17ef4767d4fa5641e69a02a2449576c41a /firmware/common/dircache.c
parent564b696500d579972e6bab9afd1bdab0454423a9 (diff)
downloadrockbox-32b54164d88e9155b5b01a51cad71017ecf7294a.tar.gz
rockbox-32b54164d88e9155b5b01a51cad71017ecf7294a.zip
Dircache: Fix 2 nasty bugs introduced with the reworks starting with r30032.
The first is an off-by-one that leads to miscalculation of the dircache size. The format string size was used but dircache size was incremented by the snprintf() result which is smaller. The other forgot to update the location of the "." and ".." strings upon compaction, so that new folders got assigned orphaned pointers for those directory entires. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30224 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/common/dircache.c')
-rw-r--r--firmware/common/dircache.c21
1 files changed, 13 insertions, 8 deletions
diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c
index d5b9af6c07..08fe5098f5 100644
--- a/firmware/common/dircache.c
+++ b/firmware/common/dircache.c
@@ -336,9 +336,12 @@ static int dircache_scan_and_build(IF_MV2(int volume,) struct dircache_entry *ce
#ifdef HAVE_MULTIVOLUME
if (volume > 0)
{
- ce->d_name = (d_names_start -= sizeof(VOL_NAMES));
- size_t len = snprintf(ce->d_name, VOL_ENUM_POS + 3, VOL_NAMES, volume)+1;
- dircache_size += len;
+ /* broken for 100+ volumes because the format string is too small
+ * and we use that for size calculation */
+ const size_t max_len = VOL_ENUM_POS + 3;
+ ce->d_name = (d_names_start -= max_len);
+ snprintf(ce->d_name, max_len, VOL_NAMES, volume);
+ dircache_size += max_len;
ce->info.attribute = FAT_ATTR_DIRECTORY | FAT_ATTR_VOLUME;
ce->info.size = 0;
append_position = dircache_gen_next(ce);
@@ -844,8 +847,7 @@ int dircache_build(int last_size)
allocated_size = last_size + DIRCACHE_RESERVE;
dircache_root = buffer_alloc(allocated_size);
ALIGN_BUFFER(dircache_root, allocated_size, sizeof(struct dircache_entry));
- d_names_start =
- d_names_end = ((char*)dircache_root)+allocated_size-1;
+ d_names_start = d_names_end = ((char*)dircache_root)+allocated_size-1;
dircache_size = 0;
thread_enabled = true;
generate_dot_d_names();
@@ -873,12 +875,13 @@ int dircache_build(int last_size)
/* now compact the dircache buffer */
char* dst = ((char*)&dircache_root[entry_count] + DIRCACHE_RESERVE);
- ptrdiff_t offset = d_names_start - dst, size_to_move;
+ ptrdiff_t offset = d_names_start - dst;
if (offset <= 0) /* something went wrong */
return -1;
- /* memmove d_names down, there's a possibility of overlap */
- size_to_move = dircache_size - entry_count*sizeof(struct dircache_entry);
+ /* memmove d_names down, there's a possibility of overlap
+ * equivaent to dircache_size - entry_count*sizeof(struct dircache_entry) */
+ ptrdiff_t size_to_move = d_names_end - d_names_start;
memmove(dst, d_names_start, size_to_move);
/* fix up pointers to the d_names */
@@ -887,6 +890,8 @@ int dircache_build(int last_size)
d_names_start -= offset;
d_names_end -= offset;
+ dot -= offset;
+ dotdot -= offset;
/* equivalent to dircache_size + DIRCACHE_RESERVE */
allocated_size = (d_names_end - (char*)dircache_root);