diff options
author | Miika Pekkarinen <miipekk@ihme.org> | 2007-12-16 21:10:26 +0000 |
---|---|---|
committer | Miika Pekkarinen <miipekk@ihme.org> | 2007-12-16 21:10:26 +0000 |
commit | f6039466fb275f55be16113bbbf46872f90862c8 (patch) | |
tree | 5ab33d8b5b933266f5dcdcffe8e7711e25e5b6a8 /apps/tagcache.c | |
parent | 646d39ec4e51c2736737a5689f37256e31db2620 (diff) | |
download | rockbox-f6039466fb275f55be16113bbbf46872f90862c8.tar.gz rockbox-f6039466fb275f55be16113bbbf46872f90862c8.zip |
Added file modify time field to the DB. Now metadata changes should be detected with database autoupdate enabled. Runtime statistics are not yet preserved. Preserving statistics over moving of files and altering metadata is going to be implemented next. IMPORTANT: Export database before upgrading.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@15946 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'apps/tagcache.c')
-rw-r--r-- | apps/tagcache.c | 195 |
1 files changed, 131 insertions, 64 deletions
diff --git a/apps/tagcache.c b/apps/tagcache.c index bf2df7cc0b..1f4521168e 100644 --- a/apps/tagcache.c +++ b/apps/tagcache.c | |||
@@ -85,7 +85,6 @@ | |||
85 | #define do_timed_yield() do { } while(0) | 85 | #define do_timed_yield() do { } while(0) |
86 | #endif | 86 | #endif |
87 | 87 | ||
88 | |||
89 | #ifndef __PCTOOL__ | 88 | #ifndef __PCTOOL__ |
90 | /* Tag Cache thread. */ | 89 | /* Tag Cache thread. */ |
91 | static struct event_queue tagcache_queue; | 90 | static struct event_queue tagcache_queue; |
@@ -115,16 +114,18 @@ static const int unique_tags[] = { tag_artist, tag_album, tag_genre, | |||
115 | tag_composer, tag_comment, tag_albumartist, tag_grouping }; | 114 | tag_composer, tag_comment, tag_albumartist, tag_grouping }; |
116 | 115 | ||
117 | /* Numeric tags (we can use these tags with conditional clauses). */ | 116 | /* Numeric tags (we can use these tags with conditional clauses). */ |
118 | static const int numeric_tags[] = { tag_year, tag_discnumber, tag_tracknumber, tag_length, | 117 | static const int numeric_tags[] = { tag_year, tag_discnumber, |
119 | tag_bitrate, tag_playcount, tag_rating, tag_playtime, tag_lastplayed, tag_commitid, | 118 | tag_tracknumber, tag_length, tag_bitrate, tag_playcount, tag_rating, |
119 | tag_playtime, tag_lastplayed, tag_commitid, tag_mtime, | ||
120 | tag_virt_length_min, tag_virt_length_sec, | 120 | tag_virt_length_min, tag_virt_length_sec, |
121 | tag_virt_playtime_min, tag_virt_playtime_sec, | 121 | tag_virt_playtime_min, tag_virt_playtime_sec, |
122 | tag_virt_entryage, tag_virt_autoscore }; | 122 | tag_virt_entryage, tag_virt_autoscore }; |
123 | 123 | ||
124 | /* String presentation of the tags defined in tagcache.h. Must be in correct order! */ | 124 | /* String presentation of the tags defined in tagcache.h. Must be in correct order! */ |
125 | static const char *tags_str[] = { "artist", "album", "genre", "title", | 125 | static const char *tags_str[] = { "artist", "album", "genre", "title", |
126 | "filename", "composer", "comment", "albumartist", "grouping", "year", "discnumber", "tracknumber", | 126 | "filename", "composer", "comment", "albumartist", "grouping", "year", |
127 | "bitrate", "length", "playcount", "rating", "playtime", "lastplayed", "commitid" }; | 127 | "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating", |
128 | "playtime", "lastplayed", "commitid", "mtime" }; | ||
128 | 129 | ||
129 | /* Status information of the tagcache. */ | 130 | /* Status information of the tagcache. */ |
130 | static struct tagcache_stat tc_stat; | 131 | static struct tagcache_stat tc_stat; |
@@ -188,7 +189,7 @@ struct master_header { | |||
188 | 189 | ||
189 | /* For the endianess correction */ | 190 | /* For the endianess correction */ |
190 | static const char *tagfile_entry_ec = "ss"; | 191 | static const char *tagfile_entry_ec = "ss"; |
191 | static const char *index_entry_ec = "llllllllllllllllllll"; /* (1 + TAG_COUNT) * l */ | 192 | static const char *index_entry_ec = "lllllllllllllllllllll"; /* (1 + TAG_COUNT) * l */ |
192 | static const char *tagcache_header_ec = "lll"; | 193 | static const char *tagcache_header_ec = "lll"; |
193 | static const char *master_header_ec = "llllll"; | 194 | static const char *master_header_ec = "llllll"; |
194 | 195 | ||
@@ -252,6 +253,8 @@ static int processed_dir_count; | |||
252 | static volatile int write_lock; | 253 | static volatile int write_lock; |
253 | static volatile int read_lock; | 254 | static volatile int read_lock; |
254 | 255 | ||
256 | static bool delete_entry(long idx_id); | ||
257 | |||
255 | const char* tagcache_tag_to_str(int tag) | 258 | const char* tagcache_tag_to_str(int tag) |
256 | { | 259 | { |
257 | return tags_str[tag]; | 260 | return tags_str[tag]; |
@@ -328,6 +331,46 @@ static int open_tag_fd(struct tagcache_header *hdr, int tag, bool write) | |||
328 | return fd; | 331 | return fd; |
329 | } | 332 | } |
330 | 333 | ||
334 | static int open_master_fd(struct master_header *hdr, bool write) | ||
335 | { | ||
336 | int fd; | ||
337 | int rc; | ||
338 | |||
339 | fd = open(TAGCACHE_FILE_MASTER, write ? O_RDWR : O_RDONLY); | ||
340 | if (fd < 0) | ||
341 | { | ||
342 | logf("master file open failed for R/W"); | ||
343 | tc_stat.ready = false; | ||
344 | return fd; | ||
345 | } | ||
346 | |||
347 | tc_stat.econ = false; | ||
348 | |||
349 | /* Check the header. */ | ||
350 | rc = read(fd, hdr, sizeof(struct master_header)); | ||
351 | if (hdr->tch.magic == TAGCACHE_MAGIC && rc == sizeof(struct master_header)) | ||
352 | { | ||
353 | /* Success. */ | ||
354 | return fd; | ||
355 | } | ||
356 | |||
357 | /* Trying to read again, this time with endianess correction enabled. */ | ||
358 | lseek(fd, 0, SEEK_SET); | ||
359 | |||
360 | rc = ecread(fd, hdr, 1, master_header_ec, true); | ||
361 | if (hdr->tch.magic != TAGCACHE_MAGIC || rc != sizeof(struct master_header)) | ||
362 | { | ||
363 | logf("header error"); | ||
364 | tc_stat.ready = false; | ||
365 | close(fd); | ||
366 | return -2; | ||
367 | } | ||
368 | |||
369 | tc_stat.econ = true; | ||
370 | |||
371 | return fd; | ||
372 | } | ||
373 | |||
331 | #ifndef __PCTOOL__ | 374 | #ifndef __PCTOOL__ |
332 | static bool do_timed_yield(void) | 375 | static bool do_timed_yield(void) |
333 | { | 376 | { |
@@ -521,6 +564,8 @@ bool tagcache_find_index(struct tagcache_search *tcs, const char *filename) | |||
521 | static bool get_index(int masterfd, int idxid, | 564 | static bool get_index(int masterfd, int idxid, |
522 | struct index_entry *idx, bool use_ram) | 565 | struct index_entry *idx, bool use_ram) |
523 | { | 566 | { |
567 | bool localfd = false; | ||
568 | |||
524 | if (idxid < 0) | 569 | if (idxid < 0) |
525 | { | 570 | { |
526 | logf("Incorrect idxid: %d", idxid); | 571 | logf("Incorrect idxid: %d", idxid); |
@@ -540,15 +585,31 @@ static bool get_index(int masterfd, int idxid, | |||
540 | (void)use_ram; | 585 | (void)use_ram; |
541 | #endif | 586 | #endif |
542 | 587 | ||
588 | if (masterfd < 0) | ||
589 | { | ||
590 | struct master_header tcmh; | ||
591 | |||
592 | localfd = true; | ||
593 | masterfd = open_master_fd(&tcmh, false); | ||
594 | if (masterfd < 0) | ||
595 | return false; | ||
596 | } | ||
597 | |||
543 | lseek(masterfd, idxid * sizeof(struct index_entry) | 598 | lseek(masterfd, idxid * sizeof(struct index_entry) |
544 | + sizeof(struct master_header), SEEK_SET); | 599 | + sizeof(struct master_header), SEEK_SET); |
545 | if (ecread(masterfd, idx, 1, index_entry_ec, tc_stat.econ) | 600 | if (ecread(masterfd, idx, 1, index_entry_ec, tc_stat.econ) |
546 | != sizeof(struct index_entry)) | 601 | != sizeof(struct index_entry)) |
547 | { | 602 | { |
548 | logf("read error #3"); | 603 | logf("read error #3"); |
604 | if (localfd) | ||
605 | close(masterfd); | ||
606 | |||
549 | return false; | 607 | return false; |
550 | } | 608 | } |
551 | 609 | ||
610 | if (localfd) | ||
611 | close(masterfd); | ||
612 | |||
552 | if (idx->flag & FLAG_DELETED) | 613 | if (idx->flag & FLAG_DELETED) |
553 | return false; | 614 | return false; |
554 | 615 | ||
@@ -1080,46 +1141,6 @@ static void remove_files(void) | |||
1080 | } | 1141 | } |
1081 | 1142 | ||
1082 | 1143 | ||
1083 | static int open_master_fd(struct master_header *hdr, bool write) | ||
1084 | { | ||
1085 | int fd; | ||
1086 | int rc; | ||
1087 | |||
1088 | fd = open(TAGCACHE_FILE_MASTER, write ? O_RDWR : O_RDONLY); | ||
1089 | if (fd < 0) | ||
1090 | { | ||
1091 | logf("master file open failed for R/W"); | ||
1092 | tc_stat.ready = false; | ||
1093 | return fd; | ||
1094 | } | ||
1095 | |||
1096 | tc_stat.econ = false; | ||
1097 | |||
1098 | /* Check the header. */ | ||
1099 | rc = read(fd, hdr, sizeof(struct master_header)); | ||
1100 | if (hdr->tch.magic == TAGCACHE_MAGIC && rc == sizeof(struct master_header)) | ||
1101 | { | ||
1102 | /* Success. */ | ||
1103 | return fd; | ||
1104 | } | ||
1105 | |||
1106 | /* Trying to read again, this time with endianess correction enabled. */ | ||
1107 | lseek(fd, 0, SEEK_SET); | ||
1108 | |||
1109 | rc = ecread(fd, hdr, 1, master_header_ec, true); | ||
1110 | if (hdr->tch.magic != TAGCACHE_MAGIC || rc != sizeof(struct master_header)) | ||
1111 | { | ||
1112 | logf("header error"); | ||
1113 | tc_stat.ready = false; | ||
1114 | close(fd); | ||
1115 | return -2; | ||
1116 | } | ||
1117 | |||
1118 | tc_stat.econ = true; | ||
1119 | |||
1120 | return fd; | ||
1121 | } | ||
1122 | |||
1123 | static bool check_all_headers(void) | 1144 | static bool check_all_headers(void) |
1124 | { | 1145 | { |
1125 | struct master_header myhdr; | 1146 | struct master_header myhdr; |
@@ -1602,16 +1623,17 @@ static int check_if_empty(char **tag) | |||
1602 | entry.tag_length[tag] = check_if_empty(data); \ | 1623 | entry.tag_length[tag] = check_if_empty(data); \ |
1603 | offset += entry.tag_length[tag] | 1624 | offset += entry.tag_length[tag] |
1604 | 1625 | ||
1626 | static void add_tagcache(char *path, unsigned long mtime | ||
1605 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) | 1627 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) |
1606 | static void add_tagcache(char *path, const struct dirent *dc) | 1628 | ,const struct dirent *dc |
1607 | #else | ||
1608 | static void add_tagcache(char *path) | ||
1609 | #endif | 1629 | #endif |
1630 | ) | ||
1610 | { | 1631 | { |
1611 | struct mp3entry id3; | 1632 | struct mp3entry id3; |
1612 | struct temp_file_entry entry; | 1633 | struct temp_file_entry entry; |
1613 | bool ret; | 1634 | bool ret; |
1614 | int fd; | 1635 | int fd; |
1636 | int idx_id = -1; | ||
1615 | char tracknumfix[3]; | 1637 | char tracknumfix[3]; |
1616 | int offset = 0; | 1638 | int offset = 0; |
1617 | int path_length = strlen(path); | 1639 | int path_length = strlen(path); |
@@ -1637,16 +1659,40 @@ static void add_tagcache(char *path) | |||
1637 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) | 1659 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) |
1638 | if (tc_stat.ramcache && dircache_is_enabled()) | 1660 | if (tc_stat.ramcache && dircache_is_enabled()) |
1639 | { | 1661 | { |
1640 | if (find_entry_ram(path, dc) >= 0) | 1662 | idx_id = find_entry_ram(path, dc); |
1641 | return ; | ||
1642 | } | 1663 | } |
1643 | else | 1664 | else |
1644 | #endif | 1665 | #endif |
1645 | { | 1666 | { |
1646 | if (filenametag_fd >= 0) | 1667 | if (filenametag_fd >= 0) |
1647 | { | 1668 | { |
1648 | if (find_entry_disk(path) >= 0) | 1669 | idx_id = find_entry_disk(path); |
1649 | return ; | 1670 | } |
1671 | } | ||
1672 | |||
1673 | /* Check if file has been modified. */ | ||
1674 | if (idx_id >= 0) | ||
1675 | { | ||
1676 | struct index_entry idx; | ||
1677 | |||
1678 | if (!get_index(-1, idx_id, &idx, true)) | ||
1679 | { | ||
1680 | logf("failed to retrieve index entry"); | ||
1681 | return ; | ||
1682 | } | ||
1683 | |||
1684 | if ((unsigned long)idx.tag_seek[tag_mtime] == mtime) | ||
1685 | { | ||
1686 | /* No changes to file. */ | ||
1687 | return ; | ||
1688 | } | ||
1689 | |||
1690 | /* Metadata might have been changed. Delete the entry. */ | ||
1691 | logf("Re-adding: %s", path); | ||
1692 | if (!delete_entry(idx_id)) | ||
1693 | { | ||
1694 | logf("delete_entry failed: %d", idx_id); | ||
1695 | return ; | ||
1650 | } | 1696 | } |
1651 | } | 1697 | } |
1652 | 1698 | ||
@@ -1706,6 +1752,7 @@ static void add_tagcache(char *path) | |||
1706 | entry.tag_offset[tag_tracknumber] = id3.tracknum; | 1752 | entry.tag_offset[tag_tracknumber] = id3.tracknum; |
1707 | entry.tag_offset[tag_length] = id3.length; | 1753 | entry.tag_offset[tag_length] = id3.length; |
1708 | entry.tag_offset[tag_bitrate] = id3.bitrate; | 1754 | entry.tag_offset[tag_bitrate] = id3.bitrate; |
1755 | entry.tag_offset[tag_mtime] = mtime; | ||
1709 | 1756 | ||
1710 | /* String tags. */ | 1757 | /* String tags. */ |
1711 | has_albumartist = id3.albumartist != NULL | 1758 | has_albumartist = id3.albumartist != NULL |
@@ -3241,7 +3288,8 @@ bool tagcache_create_changelog(struct tagcache_search *tcs) | |||
3241 | 3288 | ||
3242 | static bool delete_entry(long idx_id) | 3289 | static bool delete_entry(long idx_id) |
3243 | { | 3290 | { |
3244 | int fd; | 3291 | int fd = -1; |
3292 | /*int dbdel_fd = -1;*/ | ||
3245 | int tag, i; | 3293 | int tag, i; |
3246 | struct index_entry idx, myidx; | 3294 | struct index_entry idx, myidx; |
3247 | struct master_header myhdr; | 3295 | struct master_header myhdr; |
@@ -3259,13 +3307,23 @@ static bool delete_entry(long idx_id) | |||
3259 | if ( (fd = open_master_fd(&myhdr, true) ) < 0) | 3307 | if ( (fd = open_master_fd(&myhdr, true) ) < 0) |
3260 | return false; | 3308 | return false; |
3261 | 3309 | ||
3310 | /* | ||
3311 | TODO: Implement soon. | ||
3312 | dbdel_fd = open(TAGCACHE_FILE_DELETED, O_RDWR | O_APPEND | O_CREAT); | ||
3313 | if (dbdel_fd < 0) | ||
3314 | { | ||
3315 | logf("delete_entry(): DBDEL open failed"); | ||
3316 | goto cleanup; | ||
3317 | } | ||
3318 | close(dbdel_fd); | ||
3319 | dbdel_fd = -1; | ||
3320 | */ | ||
3262 | lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR); | 3321 | lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR); |
3263 | if (ecread(fd, &myidx, 1, index_entry_ec, tc_stat.econ) | 3322 | if (ecread(fd, &myidx, 1, index_entry_ec, tc_stat.econ) |
3264 | != sizeof(struct index_entry)) | 3323 | != sizeof(struct index_entry)) |
3265 | { | 3324 | { |
3266 | logf("delete_entry(): read error"); | 3325 | logf("delete_entry(): read error"); |
3267 | close(fd); | 3326 | goto cleanup; |
3268 | return false; | ||
3269 | } | 3327 | } |
3270 | 3328 | ||
3271 | myidx.flag |= FLAG_DELETED; | 3329 | myidx.flag |= FLAG_DELETED; |
@@ -3274,8 +3332,7 @@ static bool delete_entry(long idx_id) | |||
3274 | != sizeof(struct index_entry)) | 3332 | != sizeof(struct index_entry)) |
3275 | { | 3333 | { |
3276 | logf("delete_entry(): write_error"); | 3334 | logf("delete_entry(): write_error"); |
3277 | close(fd); | 3335 | goto cleanup; |
3278 | return false; | ||
3279 | } | 3336 | } |
3280 | 3337 | ||
3281 | /* Now check which tags are no longer in use (if any) */ | 3338 | /* Now check which tags are no longer in use (if any) */ |
@@ -3298,8 +3355,7 @@ static bool delete_entry(long idx_id) | |||
3298 | != sizeof(struct index_entry)) | 3355 | != sizeof(struct index_entry)) |
3299 | { | 3356 | { |
3300 | logf("delete_entry(): read error #2"); | 3357 | logf("delete_entry(): read error #2"); |
3301 | close(fd); | 3358 | goto cleanup; |
3302 | return false; | ||
3303 | } | 3359 | } |
3304 | idxp = &idx; | 3360 | idxp = &idx; |
3305 | } | 3361 | } |
@@ -3318,6 +3374,7 @@ static bool delete_entry(long idx_id) | |||
3318 | } | 3374 | } |
3319 | 3375 | ||
3320 | close(fd); | 3376 | close(fd); |
3377 | fd = -1; | ||
3321 | 3378 | ||
3322 | /* Now delete all tags no longer in use. */ | 3379 | /* Now delete all tags no longer in use. */ |
3323 | for (tag = 0; tag < TAG_COUNT; tag++) | 3380 | for (tag = 0; tag < TAG_COUNT; tag++) |
@@ -3347,7 +3404,7 @@ static bool delete_entry(long idx_id) | |||
3347 | if (fd < 0) | 3404 | if (fd < 0) |
3348 | { | 3405 | { |
3349 | logf("open failed"); | 3406 | logf("open failed"); |
3350 | return false; | 3407 | goto cleanup; |
3351 | } | 3408 | } |
3352 | 3409 | ||
3353 | /* Skip the header block */ | 3410 | /* Skip the header block */ |
@@ -3368,6 +3425,14 @@ static bool delete_entry(long idx_id) | |||
3368 | } | 3425 | } |
3369 | 3426 | ||
3370 | return true; | 3427 | return true; |
3428 | |||
3429 | cleanup: | ||
3430 | if (fd >= 0) | ||
3431 | close(fd); | ||
3432 | /* if (dbdel_fd >= 0) | ||
3433 | close(dbdel_fd); | ||
3434 | */ | ||
3435 | return false; | ||
3371 | } | 3436 | } |
3372 | 3437 | ||
3373 | #ifndef __PCTOOL__ | 3438 | #ifndef __PCTOOL__ |
@@ -3846,11 +3911,13 @@ static bool check_dir(const char *dirname) | |||
3846 | else | 3911 | else |
3847 | { | 3912 | { |
3848 | tc_stat.curentry = curpath; | 3913 | tc_stat.curentry = curpath; |
3914 | |||
3915 | /* Add a new entry to the temporary db file. */ | ||
3916 | add_tagcache(curpath, (entry->wrtdate << 16) | entry->wrttime | ||
3849 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) | 3917 | #if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE) |
3850 | add_tagcache(curpath, dir->internal_entry); | 3918 | , dir->internal_entry |
3851 | #else | ||
3852 | add_tagcache(curpath); | ||
3853 | #endif | 3919 | #endif |
3920 | ); | ||
3854 | 3921 | ||
3855 | /* Wait until current path for debug screen is read and unset. */ | 3922 | /* Wait until current path for debug screen is read and unset. */ |
3856 | while (tc_stat.syncscreen && tc_stat.curentry != NULL) | 3923 | while (tc_stat.syncscreen && tc_stat.curentry != NULL) |