summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Hohmuth <sideral@rockbox.org>2011-08-04 10:23:18 +0000
committerMichael Hohmuth <sideral@rockbox.org>2011-08-04 10:23:18 +0000
commit8207a4a26731424a4a3f912a0fc2b9b6bf6c4f89 (patch)
tree9079de40937d169911ee0e8a240a128a0d59f893
parente7c2449d076a93cde988f6569c6bacd6e2d4562b (diff)
downloadrockbox-8207a4a26731424a4a3f912a0fc2b9b6bf6c4f89.tar.gz
rockbox-8207a4a26731424a4a3f912a0fc2b9b6bf6c4f89.zip
FS#12132 patch 8: retrieve_entries: Decrease binsize by reenabling
inlining format_str() and avoiding a string copy by printing directly into the name buffer. Also uses quite a bit less stack space. En passant, made basename printing more robust by not limiting the buffer into which the file pathname is fetched by the max size of the resulting basename string. Also, fixed a potential buffer overrun in format_str. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30248 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/tagtree.c61
1 files changed, 34 insertions, 27 deletions
diff --git a/apps/tagtree.c b/apps/tagtree.c
index 31470722d5..5012c084d0 100644
--- a/apps/tagtree.c
+++ b/apps/tagtree.c
@@ -1096,10 +1096,10 @@ static int format_str(struct tagcache_search *tcs, struct display_format *fmt,
1096 } 1096 }
1097 } 1097 }
1098 1098
1099 char formatchar = fmt->formatstr[i];
1100
1099 if (read_format) 1101 if (read_format)
1100 { 1102 {
1101 char formatchar = fmt->formatstr[i];
1102
1103 fmtbuf[fmtbuf_pos++] = formatchar; 1103 fmtbuf[fmtbuf_pos++] = formatchar;
1104 if (fmtbuf_pos >= sizeof fmtbuf) 1104 if (fmtbuf_pos >= sizeof fmtbuf)
1105 { 1105 {
@@ -1110,7 +1110,7 @@ static int format_str(struct tagcache_search *tcs, struct display_format *fmt,
1110 if (formatchar == 's' || formatchar == 'd') 1110 if (formatchar == 's' || formatchar == 'd')
1111 { 1111 {
1112 unsigned space_left = buf_size - buf_pos; 1112 unsigned space_left = buf_size - buf_pos;
1113 char tmpbuf[space_left + 1]; 1113 char tmpbuf[MAX_PATH];
1114 char *result; 1114 char *result;
1115 1115
1116 fmtbuf[fmtbuf_pos] = '\0'; 1116 fmtbuf[fmtbuf_pos] = '\0';
@@ -1131,7 +1131,7 @@ static int format_str(struct tagcache_search *tcs, struct display_format *fmt,
1131 if (!tagcache_retrieve(tcs, tcs->idx_id, 1131 if (!tagcache_retrieve(tcs, tcs->idx_id,
1132 (tag == tag_virt_basename ? 1132 (tag == tag_virt_basename ?
1133 tag_filename : tag), 1133 tag_filename : tag),
1134 tmpbuf, space_left)) 1134 tmpbuf, sizeof tmpbuf))
1135 { 1135 {
1136 logf("retrieve failed"); 1136 logf("retrieve failed");
1137 return -3; 1137 return -3;
@@ -1145,22 +1145,23 @@ static int format_str(struct tagcache_search *tcs, struct display_format *fmt,
1145 else 1145 else
1146 result = tmpbuf; 1146 result = tmpbuf;
1147 } 1147 }
1148 snprintf(&buf[buf_pos], space_left, fmtbuf, result); 1148 buf_pos +=
1149 snprintf(&buf[buf_pos], space_left, fmtbuf, result);
1149 break; 1150 break;
1150 1151
1151 case 'd': 1152 case 'd':
1152 snprintf(&buf[buf_pos], space_left, fmtbuf, 1153 buf_pos +=
1153 tagcache_get_numeric(tcs, fmt->tags[parpos])); 1154 snprintf(&buf[buf_pos], space_left, fmtbuf,
1155 tagcache_get_numeric(tcs, fmt->tags[parpos]));
1154 } 1156 }
1155 1157
1156 buf_pos += strlen(&buf[buf_pos]);
1157 parpos++; 1158 parpos++;
1158 } 1159 }
1159 } 1160 }
1160 else 1161 else
1161 buf[buf_pos++] = fmt->formatstr[i]; 1162 buf[buf_pos++] = formatchar;
1162 1163
1163 if (buf_pos - 1 >= buf_size) 1164 if (buf_pos >= buf_size - 1) /* need at least one more byte for \0 */
1164 { 1165 {
1165 logf("buffer overflow"); 1166 logf("buffer overflow");
1166 return -4; 1167 return -4;
@@ -1328,35 +1329,41 @@ static int retrieve_entries(struct tree_context *c, int offset, bool init)
1328 1329
1329 if (!tcs.ramresult || fmt) 1330 if (!tcs.ramresult || fmt)
1330 { 1331 {
1331 char buf[MAX_PATH]; 1332 dptr->name = &c->cache.name_buffer[namebufused];
1332 1333
1333 if (fmt) 1334 if (fmt)
1334 { 1335 {
1335 if (format_str(&tcs, fmt, buf, sizeof buf) < 0) 1336 int ret = format_str(&tcs, fmt, dptr->name,
1337 c->cache.name_buffer_size - namebufused);
1338 if (ret == -4) /* buffer full */
1339 {
1340 logf("chunk mode #2: %d", current_entry_count);
1341 c->dirfull = true;
1342 sort = false;
1343 break ;
1344 }
1345 else if (ret < 0)
1336 { 1346 {
1337 logf("format_str() failed"); 1347 logf("format_str() failed");
1338 tagcache_search_finish(&tcs); 1348 tagcache_search_finish(&tcs);
1339 return 0; 1349 return 0;
1340 } 1350 }
1351 else
1352 namebufused += strlen(dptr->name)+1;
1341 } 1353 }
1342
1343 dptr->name = &c->cache.name_buffer[namebufused];
1344 if (fmt)
1345 namebufused += strlen(buf)+1;
1346 else 1354 else
1347 namebufused += tcs.result_len;
1348
1349 if (namebufused >= c->cache.name_buffer_size)
1350 { 1355 {
1351 logf("chunk mode #2: %d", current_entry_count); 1356 namebufused += tcs.result_len;
1352 c->dirfull = true; 1357 if (namebufused < c->cache.name_buffer_size)
1353 sort = false; 1358 strcpy(dptr->name, tcs.result);
1354 break ; 1359 else
1360 {
1361 logf("chunk mode #2a: %d", current_entry_count);
1362 c->dirfull = true;
1363 sort = false;
1364 break ;
1365 }
1355 } 1366 }
1356 if (fmt)
1357 strcpy(dptr->name, buf);
1358 else
1359 strcpy(dptr->name, tcs.result);
1360 } 1367 }
1361 else 1368 else
1362 dptr->name = tcs.result; 1369 dptr->name = tcs.result;