summaryrefslogtreecommitdiff
path: root/apps/tagcache.c
diff options
context:
space:
mode:
authorMiika Pekkarinen <miipekk@ihme.org>2009-06-20 16:17:54 +0000
committerMiika Pekkarinen <miipekk@ihme.org>2009-06-20 16:17:54 +0000
commit8e2bdcaab6857daed1174487e4262d1a4c5db9ab (patch)
tree66441264df232454d909ca94bdfdc9a915842e59 /apps/tagcache.c
parentd79d239382e53fc570cf49e8ea4b5150b42c906e (diff)
downloadrockbox-8e2bdcaab6857daed1174487e4262d1a4c5db9ab.tar.gz
rockbox-8e2bdcaab6857daed1174487e4262d1a4c5db9ab.zip
A bunch of stability fixes into tagcache engine and database browser. Mainly data retrieval problems, races, data corruption of sorted index files at the end with junk data, access to unitialized memory and so on. Should fix FS#8710 and may fix FS#8414.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@21402 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/tagcache.c')
-rw-r--r--apps/tagcache.c214
1 files changed, 134 insertions, 80 deletions
diff --git a/apps/tagcache.c b/apps/tagcache.c
index d4ec1078d8..d7a377e7e2 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -410,7 +410,7 @@ static long find_entry_ram(const char *filename,
410} 410}
411#endif 411#endif
412 412
413static long find_entry_disk(const char *filename) 413static long find_entry_disk(const char *filename, bool localfd)
414{ 414{
415 struct tagcache_header tch; 415 struct tagcache_header tch;
416 static long last_pos = -1; 416 static long last_pos = -1;
@@ -427,7 +427,7 @@ static long find_entry_disk(const char *filename)
427 return -2; 427 return -2;
428 428
429 fd = filenametag_fd; 429 fd = filenametag_fd;
430 if (fd < 0) 430 if (fd < 0 || localfd)
431 { 431 {
432 last_pos = -1; 432 last_pos = -1;
433 if ( (fd = open_tag_fd(&tch, tag_filename, false)) < 0) 433 if ( (fd = open_tag_fd(&tch, tag_filename, false)) < 0)
@@ -458,6 +458,8 @@ static long find_entry_disk(const char *filename)
458 { 458 {
459 logf("too long tag #1"); 459 logf("too long tag #1");
460 close(fd); 460 close(fd);
461 if (!localfd)
462 filenametag_fd = -1;
461 last_pos = -1; 463 last_pos = -1;
462 return -2; 464 return -2;
463 } 465 }
@@ -466,6 +468,8 @@ static long find_entry_disk(const char *filename)
466 { 468 {
467 logf("read error #2"); 469 logf("read error #2");
468 close(fd); 470 close(fd);
471 if (!localfd)
472 filenametag_fd = -1;
469 last_pos = -1; 473 last_pos = -1;
470 return -3; 474 return -3;
471 } 475 }
@@ -491,12 +495,12 @@ static long find_entry_disk(const char *filename)
491 goto check_again; 495 goto check_again;
492 } 496 }
493 497
494 if (fd != filenametag_fd) 498 if (fd != filenametag_fd || localfd)
495 close(fd); 499 close(fd);
496 return -4; 500 return -4;
497 } 501 }
498 502
499 if (fd != filenametag_fd) 503 if (fd != filenametag_fd || localfd)
500 close(fd); 504 close(fd);
501 505
502 return tfe.idx_id; 506 return tfe.idx_id;
@@ -512,7 +516,7 @@ static int find_index(const char *filename)
512#endif 516#endif
513 517
514 if (idx_id < 0) 518 if (idx_id < 0)
515 idx_id = find_entry_disk(filename); 519 idx_id = find_entry_disk(filename, true);
516 520
517 return idx_id; 521 return idx_id;
518} 522}
@@ -554,8 +558,14 @@ static bool get_index(int masterfd, int idxid,
554 if (hdr->indices[idxid].flag & FLAG_DELETED) 558 if (hdr->indices[idxid].flag & FLAG_DELETED)
555 return false; 559 return false;
556 560
557 memcpy(idx, &hdr->indices[idxid], sizeof(struct index_entry)); 561# ifdef HAVE_DIRCACHE
558 return true; 562 if (!(hdr->indices[idxid].flag & FLAG_DIRCACHE)
563 || is_dircache_intact())
564#endif
565 {
566 memcpy(idx, &hdr->indices[idxid], sizeof(struct index_entry));
567 return true;
568 }
559 } 569 }
560#else 570#else
561 (void)use_ram; 571 (void)use_ram;
@@ -1006,17 +1016,20 @@ static bool add_uniqbuf(struct tagcache_search *tcs, unsigned long id)
1006static bool build_lookup_list(struct tagcache_search *tcs) 1016static bool build_lookup_list(struct tagcache_search *tcs)
1007{ 1017{
1008 struct index_entry entry; 1018 struct index_entry entry;
1009 int i; 1019 int i, j;
1010 1020
1011 tcs->seek_list_count = 0; 1021 tcs->seek_list_count = 0;
1012 1022
1013#ifdef HAVE_TC_RAMCACHE 1023#ifdef HAVE_TC_RAMCACHE
1014 if (tcs->ramsearch) 1024 if (tcs->ramsearch
1025# ifdef HAVE_DIRCACHE
1026 && (tcs->type != tag_filename || is_dircache_intact())
1027# endif
1028 )
1015 { 1029 {
1016 int j;
1017
1018 for (i = tcs->seek_pos; i < hdr->h.tch.entry_count; i++) 1030 for (i = tcs->seek_pos; i < hdr->h.tch.entry_count; i++)
1019 { 1031 {
1032 struct tagcache_seeklist_entry *seeklist;
1020 struct index_entry *idx = &hdr->indices[i]; 1033 struct index_entry *idx = &hdr->indices[i];
1021 if (tcs->seek_list_count == SEEK_LIST_SIZE) 1034 if (tcs->seek_list_count == SEEK_LIST_SIZE)
1022 break ; 1035 break ;
@@ -1046,26 +1059,37 @@ static bool build_lookup_list(struct tagcache_search *tcs)
1046 continue; 1059 continue;
1047 1060
1048 /* Lets add it. */ 1061 /* Lets add it. */
1049 tcs->seek_list[tcs->seek_list_count] = idx->tag_seek[tcs->type]; 1062 seeklist = &tcs->seeklist[tcs->seek_list_count];
1050 tcs->seek_flags[tcs->seek_list_count] = idx->flag; 1063 seeklist->seek = idx->tag_seek[tcs->type];
1064 seeklist->flag = idx->flag;
1065 seeklist->idx_id = i;
1051 tcs->seek_list_count++; 1066 tcs->seek_list_count++;
1052 } 1067 }
1053 1068
1054 tcs->seek_pos = i; 1069 tcs->seek_pos = i;
1055 1070
1056 return tcs->seek_list_count > 0; 1071 return tcs->seek_list_count > 0;
1057 } 1072 }
1058#endif 1073#endif
1059 1074
1075 if (tcs->masterfd < 0)
1076 {
1077 struct master_header tcmh;
1078 tcs->masterfd = open_master_fd(&tcmh, false);
1079 }
1080
1060 lseek(tcs->masterfd, tcs->seek_pos * sizeof(struct index_entry) + 1081 lseek(tcs->masterfd, tcs->seek_pos * sizeof(struct index_entry) +
1061 sizeof(struct master_header), SEEK_SET); 1082 sizeof(struct master_header), SEEK_SET);
1062 1083
1063 while (ecread(tcs->masterfd, &entry, 1, index_entry_ec, tc_stat.econ) 1084 while (ecread(tcs->masterfd, &entry, 1, index_entry_ec, tc_stat.econ)
1064 == sizeof(struct index_entry)) 1085 == sizeof(struct index_entry))
1065 { 1086 {
1087 struct tagcache_seeklist_entry *seeklist;
1088
1066 if (tcs->seek_list_count == SEEK_LIST_SIZE) 1089 if (tcs->seek_list_count == SEEK_LIST_SIZE)
1067 break ; 1090 break ;
1068 1091
1092 i = tcs->seek_pos;
1069 tcs->seek_pos++; 1093 tcs->seek_pos++;
1070 1094
1071 /* Check if entry has been deleted. */ 1095 /* Check if entry has been deleted. */
@@ -1073,13 +1097,13 @@ static bool build_lookup_list(struct tagcache_search *tcs)
1073 continue; 1097 continue;
1074 1098
1075 /* Go through all filters.. */ 1099 /* Go through all filters.. */
1076 for (i = 0; i < tcs->filter_count; i++) 1100 for (j = 0; j < tcs->filter_count; j++)
1077 { 1101 {
1078 if (entry.tag_seek[tcs->filter_tag[i]] != tcs->filter_seek[i]) 1102 if (entry.tag_seek[tcs->filter_tag[j]] != tcs->filter_seek[j])
1079 break ; 1103 break ;
1080 } 1104 }
1081 1105
1082 if (i < tcs->filter_count) 1106 if (j < tcs->filter_count)
1083 continue ; 1107 continue ;
1084 1108
1085 /* Check for conditions. */ 1109 /* Check for conditions. */
@@ -1091,8 +1115,10 @@ static bool build_lookup_list(struct tagcache_search *tcs)
1091 continue; 1115 continue;
1092 1116
1093 /* Lets add it. */ 1117 /* Lets add it. */
1094 tcs->seek_list[tcs->seek_list_count] = entry.tag_seek[tcs->type]; 1118 seeklist = &tcs->seeklist[tcs->seek_list_count];
1095 tcs->seek_flags[tcs->seek_list_count] = entry.flag; 1119 seeklist->seek = entry.tag_seek[tcs->type];
1120 seeklist->flag = entry.flag;
1121 seeklist->idx_id = i;
1096 tcs->seek_list_count++; 1122 tcs->seek_list_count++;
1097 1123
1098 yield(); 1124 yield();
@@ -1155,15 +1181,17 @@ static bool check_all_headers(void)
1155 return true; 1181 return true;
1156} 1182}
1157 1183
1184bool tagcache_is_busy(void)
1185{
1186 return read_lock || write_lock;
1187}
1188
1158bool tagcache_search(struct tagcache_search *tcs, int tag) 1189bool tagcache_search(struct tagcache_search *tcs, int tag)
1159{ 1190{
1160 struct tagcache_header tag_hdr; 1191 struct tagcache_header tag_hdr;
1161 struct master_header master_hdr; 1192 struct master_header master_hdr;
1162 int i; 1193 int i;
1163 1194
1164 if (tcs->initialized)
1165 tagcache_search_finish(tcs);
1166
1167 while (read_lock) 1195 while (read_lock)
1168 sleep(1); 1196 sleep(1);
1169 1197
@@ -1174,6 +1202,7 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
1174 tcs->position = sizeof(struct tagcache_header); 1202 tcs->position = sizeof(struct tagcache_header);
1175 tcs->type = tag; 1203 tcs->type = tag;
1176 tcs->seek_pos = 0; 1204 tcs->seek_pos = 0;
1205 tcs->list_position = 0;
1177 tcs->seek_list_count = 0; 1206 tcs->seek_list_count = 0;
1178 tcs->filter_count = 0; 1207 tcs->filter_count = 0;
1179 tcs->masterfd = -1; 1208 tcs->masterfd = -1;
@@ -1192,19 +1221,24 @@ bool tagcache_search(struct tagcache_search *tcs, int tag)
1192 else 1221 else
1193#endif 1222#endif
1194 { 1223 {
1224 /* Always open as R/W so we can pass tcs to functions that modify data also
1225 * without failing. */
1226 tcs->masterfd = open_master_fd(&master_hdr, true);
1227 if (tcs->masterfd < 0)
1228 return false;
1229
1195 if (!TAGCACHE_IS_NUMERIC(tcs->type)) 1230 if (!TAGCACHE_IS_NUMERIC(tcs->type))
1196 { 1231 {
1197 tcs->idxfd[tcs->type] = open_tag_fd(&tag_hdr, tcs->type, false); 1232 tcs->idxfd[tcs->type] = open_tag_fd(&tag_hdr, tcs->type, false);
1198 if (tcs->idxfd[tcs->type] < 0) 1233 if (tcs->idxfd[tcs->type] < 0)
1199 return false; 1234 return false;
1235
1236 tcs->entry_count = tag_hdr.entry_count;
1237 }
1238 else
1239 {
1240 tcs->entry_count = master_hdr.tch.entry_count;
1200 } 1241 }
1201
1202 /* Always open as R/W so we can pass tcs to functions that modify data also
1203 * without failing. */
1204 tcs->masterfd = open_master_fd(&master_hdr, true);
1205
1206 if (tcs->masterfd < 0)
1207 return false;
1208 } 1242 }
1209 1243
1210 tcs->valid = true; 1244 tcs->valid = true;
@@ -1272,14 +1306,6 @@ bool tagcache_search_add_clause(struct tagcache_search *tcs,
1272 return true; 1306 return true;
1273} 1307}
1274 1308
1275/* TODO: Remove this mess. */
1276#ifdef HAVE_DIRCACHE
1277#define TAG_FILENAME_RAM(tcs) ((tcs->type == tag_filename) \
1278 ? ((flag & FLAG_DIRCACHE) && is_dircache_intact()) : 1)
1279#else
1280#define TAG_FILENAME_RAM(tcs) (tcs->type != tag_filename)
1281#endif
1282
1283static bool get_next(struct tagcache_search *tcs) 1309static bool get_next(struct tagcache_search *tcs)
1284{ 1310{
1285 static char buf[TAG_MAXLEN+32]; 1311 static char buf[TAG_MAXLEN+32];
@@ -1298,11 +1324,20 @@ static bool get_next(struct tagcache_search *tcs)
1298 1324
1299 /* Relative fetch. */ 1325 /* Relative fetch. */
1300 if (tcs->filter_count > 0 || tcs->clause_count > 0 1326 if (tcs->filter_count > 0 || tcs->clause_count > 0
1301 || TAGCACHE_IS_NUMERIC(tcs->type)) 1327 || TAGCACHE_IS_NUMERIC(tcs->type)
1328#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1329 /* We need to retrieve flag status for dircache. */
1330 || (tcs->ramsearch && tcs->type == tag_filename)
1331#endif
1332 )
1302 { 1333 {
1334 struct tagcache_seeklist_entry *seeklist;
1335
1303 /* Check for end of list. */ 1336 /* Check for end of list. */
1304 if (tcs->seek_list_count == 0) 1337 if (tcs->list_position == tcs->seek_list_count)
1305 { 1338 {
1339 tcs->list_position = 0;
1340
1306 /* Try to fetch more. */ 1341 /* Try to fetch more. */
1307 if (!build_lookup_list(tcs)) 1342 if (!build_lookup_list(tcs))
1308 { 1343 {
@@ -1311,15 +1346,28 @@ static bool get_next(struct tagcache_search *tcs)
1311 } 1346 }
1312 } 1347 }
1313 1348
1314 tcs->seek_list_count--; 1349 seeklist = &tcs->seeklist[tcs->list_position];
1315 flag = tcs->seek_flags[tcs->seek_list_count]; 1350 flag = seeklist->flag;
1316 tcs->position = tcs->seek_list[tcs->seek_list_count]; 1351 tcs->position = seeklist->seek;
1352 tcs->idx_id = seeklist->idx_id;
1353 tcs->list_position++;
1317 } 1354 }
1355 else
1356 {
1357 if (tcs->entry_count == 0)
1358 {
1359 tcs->valid = false;
1360 return false;
1361 }
1362
1363 tcs->entry_count--;
1364 }
1365
1366 tcs->result_seek = tcs->position;
1318 1367
1319 if (TAGCACHE_IS_NUMERIC(tcs->type)) 1368 if (TAGCACHE_IS_NUMERIC(tcs->type))
1320 { 1369 {
1321 snprintf(buf, sizeof(buf), "%d", tcs->position); 1370 snprintf(buf, sizeof(buf), "%d", tcs->position);
1322 tcs->result_seek = tcs->position;
1323 tcs->result = buf; 1371 tcs->result = buf;
1324 tcs->result_len = strlen(buf) + 1; 1372 tcs->result_len = strlen(buf) + 1;
1325 return true; 1373 return true;
@@ -1327,55 +1375,54 @@ static bool get_next(struct tagcache_search *tcs)
1327 1375
1328 /* Direct fetch. */ 1376 /* Direct fetch. */
1329#ifdef HAVE_TC_RAMCACHE 1377#ifdef HAVE_TC_RAMCACHE
1330 if (tcs->ramsearch && TAG_FILENAME_RAM(tcs)) 1378 if (tcs->ramsearch)
1331 { 1379 {
1332 struct tagfile_entry *ep;
1333
1334 if (tcs->entry_count == 0)
1335 {
1336 tcs->valid = false;
1337 return false;
1338 }
1339 tcs->entry_count--;
1340 1380
1341 tcs->result_seek = tcs->position; 1381#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
1342 1382 if (tcs->type == tag_filename && (flag & FLAG_DIRCACHE)
1343# ifdef HAVE_DIRCACHE 1383 && is_dircache_intact())
1344 if (tcs->type == tag_filename)
1345 { 1384 {
1346 dircache_copy_path((struct dirent *)tcs->position, 1385 dircache_copy_path((struct dirent *)tcs->position,
1347 buf, sizeof buf); 1386 buf, sizeof buf);
1348 tcs->result = buf; 1387 tcs->result = buf;
1349 tcs->result_len = strlen(buf) + 1; 1388 tcs->result_len = strlen(buf) + 1;
1350 tcs->idx_id = FLAG_GET_ATTR(flag);
1351 tcs->ramresult = false; 1389 tcs->ramresult = false;
1352 1390
1353 return true; 1391 return true;
1354 } 1392 }
1355# endif 1393 else
1356 1394#endif
1357 ep = (struct tagfile_entry *)&hdr->tags[tcs->type][tcs->position]; 1395 if (tcs->type != tag_filename)
1358 tcs->position += sizeof(struct tagfile_entry) + ep->tag_length; 1396 {
1359 tcs->result = ep->tag_data; 1397 struct tagfile_entry *ep;
1360 tcs->result_len = strlen(tcs->result) + 1; 1398
1361 tcs->idx_id = ep->idx_id; 1399 ep = (struct tagfile_entry *)&hdr->tags[tcs->type][tcs->position];
1362 tcs->ramresult = true; 1400 tcs->result = ep->tag_data;
1363 1401 tcs->result_len = strlen(tcs->result) + 1;
1364 return true; 1402 tcs->idx_id = ep->idx_id;
1403 tcs->ramresult = true;
1404
1405 /* Increase position for the next run. This may get overwritten. */
1406 tcs->position += sizeof(struct tagfile_entry) + ep->tag_length;
1407
1408 return true;
1409 }
1365 } 1410 }
1366#endif 1411#endif
1367 1412
1368 if (!open_files(tcs, tcs->type)) 1413 if (!open_files(tcs, tcs->type))
1414 {
1415 tcs->valid = false;
1369 return false; 1416 return false;
1417 }
1370 1418
1371 /* Seek stream to the correct position and continue to direct fetch. */ 1419 /* Seek stream to the correct position and continue to direct fetch. */
1372 lseek(tcs->idxfd[tcs->type], tcs->position, SEEK_SET); 1420 lseek(tcs->idxfd[tcs->type], tcs->position, SEEK_SET);
1373 tcs->result_seek = tcs->position;
1374 1421
1375 if (ecread(tcs->idxfd[tcs->type], &entry, 1, 1422 if (ecread(tcs->idxfd[tcs->type], &entry, 1,
1376 tagfile_entry_ec, tc_stat.econ) != sizeof(struct tagfile_entry)) 1423 tagfile_entry_ec, tc_stat.econ) != sizeof(struct tagfile_entry))
1377 { 1424 {
1378 /* End of data. */ 1425 logf("read error #5");
1379 tcs->valid = false; 1426 tcs->valid = false;
1380 return false; 1427 return false;
1381 } 1428 }
@@ -1384,6 +1431,7 @@ static bool get_next(struct tagcache_search *tcs)
1384 { 1431 {
1385 tcs->valid = false; 1432 tcs->valid = false;
1386 logf("too long tag #2"); 1433 logf("too long tag #2");
1434 logf("P:%X/%X", tcs->position, entry.tag_length);
1387 return false; 1435 return false;
1388 } 1436 }
1389 1437
@@ -1536,12 +1584,12 @@ bool tagcache_fill_tags(struct mp3entry *id3, const char *filename)
1536 struct index_entry *entry; 1584 struct index_entry *entry;
1537 int idx_id; 1585 int idx_id;
1538 1586
1539 if (!tc_stat.ready) 1587 if (!tc_stat.ready || !tc_stat.ramcache)
1540 return false; 1588 return false;
1541 1589
1542 /* Find the corresponding entry in tagcache. */ 1590 /* Find the corresponding entry in tagcache. */
1543 idx_id = find_entry_ram(filename, NULL); 1591 idx_id = find_entry_ram(filename, NULL);
1544 if (idx_id < 0 || !tc_stat.ramcache) 1592 if (idx_id < 0)
1545 return false; 1593 return false;
1546 1594
1547 entry = &hdr->indices[idx_id]; 1595 entry = &hdr->indices[idx_id];
@@ -1644,14 +1692,11 @@ static void add_tagcache(char *path, unsigned long mtime
1644 { 1692 {
1645 idx_id = find_entry_ram(path, dc); 1693 idx_id = find_entry_ram(path, dc);
1646 } 1694 }
1647 else
1648#endif 1695#endif
1649 { 1696
1650 if (filenametag_fd >= 0) 1697 /* Be sure the entry doesn't exist. */
1651 { 1698 if (filenametag_fd >= 0 && idx_id < 0)
1652 idx_id = find_entry_disk(path); 1699 idx_id = find_entry_disk(path, false);
1653 }
1654 }
1655 1700
1656 /* Check if file has been modified. */ 1701 /* Check if file has been modified. */
1657 if (idx_id >= 0) 1702 if (idx_id >= 0)
@@ -2548,6 +2593,13 @@ static int build_index(int index_type, struct tagcache_header *h, int tmpfd)
2548 2593
2549 /* Sort the buffer data and write it to the index file. */ 2594 /* Sort the buffer data and write it to the index file. */
2550 lseek(fd, sizeof(struct tagcache_header), SEEK_SET); 2595 lseek(fd, sizeof(struct tagcache_header), SEEK_SET);
2596 /**
2597 * We need to truncate the index file now. There can be junk left
2598 * at the end of file (however, we _should_ always follow the
2599 * entry_count and don't crash with that).
2600 */
2601 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
2602
2551 i = tempbuf_sort(fd); 2603 i = tempbuf_sort(fd);
2552 if (i < 0) 2604 if (i < 0)
2553 goto error_exit; 2605 goto error_exit;
@@ -3328,7 +3380,10 @@ bool tagcache_import_changelog(void)
3328 close(masterfd); 3380 close(masterfd);
3329 3381
3330 if (filenametag_fd >= 0) 3382 if (filenametag_fd >= 0)
3383 {
3331 close(filenametag_fd); 3384 close(filenametag_fd);
3385 filenametag_fd = -1;
3386 }
3332 3387
3333 write_lock--; 3388 write_lock--;
3334 3389
@@ -3919,7 +3974,6 @@ static bool load_tagcache(void)
3919 } 3974 }
3920 3975
3921 idx->flag |= FLAG_DIRCACHE; 3976 idx->flag |= FLAG_DIRCACHE;
3922 FLAG_SET_ATTR(idx->flag, fe->idx_id);
3923 idx->tag_seek[tag_filename] = (long)dc; 3977 idx->tag_seek[tag_filename] = (long)dc;
3924 } 3978 }
3925 else 3979 else