summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apps/tagcache.c195
-rw-r--r--apps/tagcache.h19
2 files changed, 147 insertions, 67 deletions
diff --git a/apps/tagcache.c b/apps/tagcache.c
index bf2df7c..1f45211 100644
--- a/apps/tagcache.c
+++ b/apps/tagcache.c
@@ -85,7 +85,6 @@
#define do_timed_yield() do { } while(0)
#endif
-
#ifndef __PCTOOL__
/* Tag Cache thread. */
static struct event_queue tagcache_queue;
@@ -115,16 +114,18 @@ static const int unique_tags[] = { tag_artist, tag_album, tag_genre,
tag_composer, tag_comment, tag_albumartist, tag_grouping };
/* Numeric tags (we can use these tags with conditional clauses). */
-static const int numeric_tags[] = { tag_year, tag_discnumber, tag_tracknumber, tag_length,
- tag_bitrate, tag_playcount, tag_rating, tag_playtime, tag_lastplayed, tag_commitid,
+static const int numeric_tags[] = { tag_year, tag_discnumber,
+ tag_tracknumber, tag_length, tag_bitrate, tag_playcount, tag_rating,
+ tag_playtime, tag_lastplayed, tag_commitid, tag_mtime,
tag_virt_length_min, tag_virt_length_sec,
tag_virt_playtime_min, tag_virt_playtime_sec,
tag_virt_entryage, tag_virt_autoscore };
/* String presentation of the tags defined in tagcache.h. Must be in correct order! */
static const char *tags_str[] = { "artist", "album", "genre", "title",
- "filename", "composer", "comment", "albumartist", "grouping", "year", "discnumber", "tracknumber",
- "bitrate", "length", "playcount", "rating", "playtime", "lastplayed", "commitid" };
+ "filename", "composer", "comment", "albumartist", "grouping", "year",
+ "discnumber", "tracknumber", "bitrate", "length", "playcount", "rating",
+ "playtime", "lastplayed", "commitid", "mtime" };
/* Status information of the tagcache. */
static struct tagcache_stat tc_stat;
@@ -188,7 +189,7 @@ struct master_header {
/* For the endianess correction */
static const char *tagfile_entry_ec = "ss";
-static const char *index_entry_ec = "llllllllllllllllllll"; /* (1 + TAG_COUNT) * l */
+static const char *index_entry_ec = "lllllllllllllllllllll"; /* (1 + TAG_COUNT) * l */
static const char *tagcache_header_ec = "lll";
static const char *master_header_ec = "llllll";
@@ -252,6 +253,8 @@ static int processed_dir_count;
static volatile int write_lock;
static volatile int read_lock;
+static bool delete_entry(long idx_id);
+
const char* tagcache_tag_to_str(int tag)
{
return tags_str[tag];
@@ -328,6 +331,46 @@ static int open_tag_fd(struct tagcache_header *hdr, int tag, bool write)
return fd;
}
+static int open_master_fd(struct master_header *hdr, bool write)
+{
+ int fd;
+ int rc;
+
+ fd = open(TAGCACHE_FILE_MASTER, write ? O_RDWR : O_RDONLY);
+ if (fd < 0)
+ {
+ logf("master file open failed for R/W");
+ tc_stat.ready = false;
+ return fd;
+ }
+
+ tc_stat.econ = false;
+
+ /* Check the header. */
+ rc = read(fd, hdr, sizeof(struct master_header));
+ if (hdr->tch.magic == TAGCACHE_MAGIC && rc == sizeof(struct master_header))
+ {
+ /* Success. */
+ return fd;
+ }
+
+ /* Trying to read again, this time with endianess correction enabled. */
+ lseek(fd, 0, SEEK_SET);
+
+ rc = ecread(fd, hdr, 1, master_header_ec, true);
+ if (hdr->tch.magic != TAGCACHE_MAGIC || rc != sizeof(struct master_header))
+ {
+ logf("header error");
+ tc_stat.ready = false;
+ close(fd);
+ return -2;
+ }
+
+ tc_stat.econ = true;
+
+ return fd;
+}
+
#ifndef __PCTOOL__
static bool do_timed_yield(void)
{
@@ -521,6 +564,8 @@ bool tagcache_find_index(struct tagcache_search *tcs, const char *filename)
static bool get_index(int masterfd, int idxid,
struct index_entry *idx, bool use_ram)
{
+ bool localfd = false;
+
if (idxid < 0)
{
logf("Incorrect idxid: %d", idxid);
@@ -540,15 +585,31 @@ static bool get_index(int masterfd, int idxid,
(void)use_ram;
#endif
+ if (masterfd < 0)
+ {
+ struct master_header tcmh;
+
+ localfd = true;
+ masterfd = open_master_fd(&tcmh, false);
+ if (masterfd < 0)
+ return false;
+ }
+
lseek(masterfd, idxid * sizeof(struct index_entry)
+ sizeof(struct master_header), SEEK_SET);
if (ecread(masterfd, idx, 1, index_entry_ec, tc_stat.econ)
!= sizeof(struct index_entry))
{
logf("read error #3");
+ if (localfd)
+ close(masterfd);
+
return false;
}
+ if (localfd)
+ close(masterfd);
+
if (idx->flag & FLAG_DELETED)
return false;
@@ -1080,46 +1141,6 @@ static void remove_files(void)
}
-static int open_master_fd(struct master_header *hdr, bool write)
-{
- int fd;
- int rc;
-
- fd = open(TAGCACHE_FILE_MASTER, write ? O_RDWR : O_RDONLY);
- if (fd < 0)
- {
- logf("master file open failed for R/W");
- tc_stat.ready = false;
- return fd;
- }
-
- tc_stat.econ = false;
-
- /* Check the header. */
- rc = read(fd, hdr, sizeof(struct master_header));
- if (hdr->tch.magic == TAGCACHE_MAGIC && rc == sizeof(struct master_header))
- {
- /* Success. */
- return fd;
- }
-
- /* Trying to read again, this time with endianess correction enabled. */
- lseek(fd, 0, SEEK_SET);
-
- rc = ecread(fd, hdr, 1, master_header_ec, true);
- if (hdr->tch.magic != TAGCACHE_MAGIC || rc != sizeof(struct master_header))
- {
- logf("header error");
- tc_stat.ready = false;
- close(fd);
- return -2;
- }
-
- tc_stat.econ = true;
-
- return fd;
-}
-
static bool check_all_headers(void)
{
struct master_header myhdr;
@@ -1602,16 +1623,17 @@ static int check_if_empty(char **tag)
entry.tag_length[tag] = check_if_empty(data); \
offset += entry.tag_length[tag]
+static void add_tagcache(char *path, unsigned long mtime
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
-static void add_tagcache(char *path, const struct dirent *dc)
-#else
-static void add_tagcache(char *path)
+ ,const struct dirent *dc
#endif
+ )
{
struct mp3entry id3;
struct temp_file_entry entry;
bool ret;
int fd;
+ int idx_id = -1;
char tracknumfix[3];
int offset = 0;
int path_length = strlen(path);
@@ -1637,16 +1659,40 @@ static void add_tagcache(char *path)
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
if (tc_stat.ramcache && dircache_is_enabled())
{
- if (find_entry_ram(path, dc) >= 0)
- return ;
+ idx_id = find_entry_ram(path, dc);
}
else
#endif
{
if (filenametag_fd >= 0)
{
- if (find_entry_disk(path) >= 0)
- return ;
+ idx_id = find_entry_disk(path);
+ }
+ }
+
+ /* Check if file has been modified. */
+ if (idx_id >= 0)
+ {
+ struct index_entry idx;
+
+ if (!get_index(-1, idx_id, &idx, true))
+ {
+ logf("failed to retrieve index entry");
+ return ;
+ }
+
+ if ((unsigned long)idx.tag_seek[tag_mtime] == mtime)
+ {
+ /* No changes to file. */
+ return ;
+ }
+
+ /* Metadata might have been changed. Delete the entry. */
+ logf("Re-adding: %s", path);
+ if (!delete_entry(idx_id))
+ {
+ logf("delete_entry failed: %d", idx_id);
+ return ;
}
}
@@ -1706,6 +1752,7 @@ static void add_tagcache(char *path)
entry.tag_offset[tag_tracknumber] = id3.tracknum;
entry.tag_offset[tag_length] = id3.length;
entry.tag_offset[tag_bitrate] = id3.bitrate;
+ entry.tag_offset[tag_mtime] = mtime;
/* String tags. */
has_albumartist = id3.albumartist != NULL
@@ -3241,7 +3288,8 @@ bool tagcache_create_changelog(struct tagcache_search *tcs)
static bool delete_entry(long idx_id)
{
- int fd;
+ int fd = -1;
+ /*int dbdel_fd = -1;*/
int tag, i;
struct index_entry idx, myidx;
struct master_header myhdr;
@@ -3259,13 +3307,23 @@ static bool delete_entry(long idx_id)
if ( (fd = open_master_fd(&myhdr, true) ) < 0)
return false;
+ /*
+ TODO: Implement soon.
+ dbdel_fd = open(TAGCACHE_FILE_DELETED, O_RDWR | O_APPEND | O_CREAT);
+ if (dbdel_fd < 0)
+ {
+ logf("delete_entry(): DBDEL open failed");
+ goto cleanup;
+ }
+ close(dbdel_fd);
+ dbdel_fd = -1;
+ */
lseek(fd, idx_id * sizeof(struct index_entry), SEEK_CUR);
if (ecread(fd, &myidx, 1, index_entry_ec, tc_stat.econ)
!= sizeof(struct index_entry))
{
logf("delete_entry(): read error");
- close(fd);
- return false;
+ goto cleanup;
}
myidx.flag |= FLAG_DELETED;
@@ -3274,8 +3332,7 @@ static bool delete_entry(long idx_id)
!= sizeof(struct index_entry))
{
logf("delete_entry(): write_error");
- close(fd);
- return false;
+ goto cleanup;
}
/* Now check which tags are no longer in use (if any) */
@@ -3298,8 +3355,7 @@ static bool delete_entry(long idx_id)
!= sizeof(struct index_entry))
{
logf("delete_entry(): read error #2");
- close(fd);
- return false;
+ goto cleanup;
}
idxp = &idx;
}
@@ -3318,6 +3374,7 @@ static bool delete_entry(long idx_id)
}
close(fd);
+ fd = -1;
/* Now delete all tags no longer in use. */
for (tag = 0; tag < TAG_COUNT; tag++)
@@ -3347,7 +3404,7 @@ static bool delete_entry(long idx_id)
if (fd < 0)
{
logf("open failed");
- return false;
+ goto cleanup;
}
/* Skip the header block */
@@ -3368,6 +3425,14 @@ static bool delete_entry(long idx_id)
}
return true;
+
+ cleanup:
+ if (fd >= 0)
+ close(fd);
+/* if (dbdel_fd >= 0)
+ close(dbdel_fd);
+ */
+ return false;
}
#ifndef __PCTOOL__
@@ -3846,11 +3911,13 @@ static bool check_dir(const char *dirname)
else
{
tc_stat.curentry = curpath;
+
+ /* Add a new entry to the temporary db file. */
+ add_tagcache(curpath, (entry->wrtdate << 16) | entry->wrttime
#if defined(HAVE_TC_RAMCACHE) && defined(HAVE_DIRCACHE)
- add_tagcache(curpath, dir->internal_entry);
-#else
- add_tagcache(curpath);
+ , dir->internal_entry
#endif
+ );
/* Wait until current path for debug screen is read and unset. */
while (tc_stat.syncscreen && tc_stat.curentry != NULL)
diff --git a/apps/tagcache.h b/apps/tagcache.h
index 39f0c61f..879cf66 100644
--- a/apps/tagcache.h
+++ b/apps/tagcache.h
@@ -25,13 +25,13 @@
enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
tag_filename, tag_composer, tag_comment, tag_albumartist, tag_grouping, tag_year,
tag_discnumber, tag_tracknumber, tag_bitrate, tag_length, tag_playcount, tag_rating,
- tag_playtime, tag_lastplayed, tag_commitid,
+ tag_playtime, tag_lastplayed, tag_commitid, tag_mtime,
/* Virtual tags */
tag_virt_length_min, tag_virt_length_sec,
tag_virt_playtime_min, tag_virt_playtime_sec,
tag_virt_entryage, tag_virt_autoscore };
-#define TAG_COUNT 19
+#define TAG_COUNT 20
/* Maximum length of a single tag. */
#define TAG_MAXLEN (MAX_PATH*2)
@@ -43,7 +43,7 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
#define IDX_BUF_DEPTH 64
/* Tag Cache Header version 'TCHxx'. Increment when changing internal structures. */
-#define TAGCACHE_MAGIC 0x5443480b
+#define TAGCACHE_MAGIC 0x5443480c
/* How much to allocate extra space for ramcache. */
#define TAGCACHE_RESERVE 32768
@@ -72,10 +72,23 @@ enum tag_type { tag_artist = 0, tag_album, tag_genre, tag_title,
#define TAGCACHE_MAX_CLAUSES 32
/* Tag database files. */
+
+/* Temporary database containing new tags to be committed to the main db. */
#define TAGCACHE_FILE_TEMP ROCKBOX_DIR "/database_tmp.tcd"
+
+/* Database containing deleted entries with runtime statistics. */
+#define TAGCACHE_FILE_DELETED ROCKBOX_DIR "/database_del.tcd"
+
+/* The main database master index and numeric data. */
#define TAGCACHE_FILE_MASTER ROCKBOX_DIR "/database_idx.tcd"
+
+/* The main database string data. */
#define TAGCACHE_FILE_INDEX ROCKBOX_DIR "/database_%d.tcd"
+
+/* ASCII dumpfile of the DB contents. */
#define TAGCACHE_FILE_CHANGELOG ROCKBOX_DIR "/database_changelog.txt"
+
+/* Serialized DB. */
#define TAGCACHE_STATEFILE ROCKBOX_DIR "/database_state.tcd"
/* Flags */