diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2017-01-18 04:39:35 -0500 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2017-02-10 05:05:23 -0500 |
commit | 7373cf518f4d4c47f49693690c2ab8ec29bb8510 (patch) | |
tree | 0a3c025749be24561e952078e83c5f2e8b838900 /firmware | |
parent | abd75a17d18c0779b59f64a612f9226b62af5823 (diff) |
Restore dircache hookup in the database ramcache.
Do a few other changes to dircache and file code flags to
accomodate its demands.
Change-Id: I4742a54e8cfbe4d8b9cffb75faaf920dd907cf8a
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/common/dir.c | 3 | ||||
-rw-r--r-- | firmware/common/dircache.c | 209 | ||||
-rw-r--r-- | firmware/common/file.c | 10 | ||||
-rw-r--r-- | firmware/common/file_internal.c | 10 | ||||
-rw-r--r-- | firmware/include/dircache.h | 11 | ||||
-rw-r--r-- | firmware/include/file_internal.h | 27 |
6 files changed, 184 insertions, 86 deletions
diff --git a/firmware/common/dir.c b/firmware/common/dir.c index 59f7bd747a..f89129ae34 100644 --- a/firmware/common/dir.c +++ b/firmware/common/dir.c @@ -311,7 +311,8 @@ int mkdir(const char *path) struct filestr_base stream; struct path_component_info compinfo; - rc = open_stream_internal(path, FF_DIR, &stream, &compinfo); + rc = open_stream_internal(path, FF_DIR | FF_PARENTINFO, &stream, + &compinfo); if (rc < 0) { DEBUGF("Can't open parent dir or path is not a directory\n"); diff --git a/firmware/common/dircache.c b/firmware/common/dircache.c index 0761f837e1..8a75f3bbad 100644 --- a/firmware/common/dircache.c +++ b/firmware/common/dircache.c @@ -610,6 +610,19 @@ static int get_index(const struct dircache_entry *ce) } /** + * return the frontier flags for the index + */ +static uint32_t get_frontier(int idx) +{ + if (idx == 0) + return UINT32_MAX; + else if (idx > 0) + return get_entry(idx)->frontier; + else /* idx < 0 */ + return get_idx_dcvolp(idx)->frontier; +} + +/** * return the sublist down pointer for the sublist that contains entry 'idx' */ static int * get_downidxp(int idx) @@ -2515,30 +2528,41 @@ static ssize_t get_path_sub(int idx, struct get_path_sub_data *data) } /** - * retrieve and validate the file's entry/binding serial number + * validate the file's entry/binding serial number * the dircache file's serial number must match the indexed entry's or the * file reference is stale */ -static dc_serial_t get_file_serialnum(const struct dircache_file *dcfilep) +static int check_file_serialnum(const struct dircache_file *dcfilep) { int idx = dcfilep->idx; if (idx == 0 || idx < -NUM_VOLUMES) - return 0; + return -EBADF; + + dc_serial_t serialnum = dcfilep->serialnum; - dc_serial_t serialnum; + if (serialnum == 0) + return -EBADF; + + dc_serial_t s; if (idx > 0) { struct dircache_entry *ce = get_entry(idx); - serialnum = ce ? ce->serialnum : 0; + if (!ce || !(s = ce->serialnum)) + return -EBADF; } - else + else /* idx < 0 */ { - serialnum = get_idx_dcvolp(idx)->serialnum; + struct dircache_volume *dcvolp = get_idx_dcvolp(idx); + if (!(s = dcvolp->serialnum)) + return -EBADF; } - return serialnum == dcfilep->serialnum ? serialnum : 0; + if (serialnum != s) + return -EBADF; + + return 0; } /** @@ -2582,6 +2606,8 @@ void dircache_fileref_init(struct dircache_fileref *dcfrefp) * failure - a negative value * * errors: + * EBADF - Bad file number + * EFAULT - Bad address * ENOENT - No such file or directory */ ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char *buf, @@ -2589,6 +2615,9 @@ ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char * { ssize_t rc; + if (!dcfrefp) + FILE_ERROR_RETURN(EFAULT, -1); + /* if missing buffer space, still return what's needed a la strlcpy */ if (!buf) size = 0; @@ -2600,10 +2629,11 @@ ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char * /* first and foremost, there must be a cache and the serial number must check out */ if (!dircache_runinfo.handle) - FILE_ERROR(ENOENT, -1); + FILE_ERROR(EBADF, -2); - if (get_file_serialnum(&dcfrefp->dcfile) == 0) - FILE_ERROR(ENOENT, -2); + rc = check_file_serialnum(&dcfrefp->dcfile); + if (rc < 0) + FILE_ERROR(-rc, -3); struct get_path_sub_data data = { @@ -2614,10 +2644,10 @@ ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp, char * rc = get_path_sub(dcfrefp->dcfile.idx, &data); if (rc < 0) - FILE_ERROR(ENOENT, rc * 10 - 3); + FILE_ERROR(ENOENT, rc * 10 - 4); if (data.serialhash != dcfrefp->serialhash) - FILE_ERROR(ENOENT, -4); + FILE_ERROR(ENOENT, -5); file_error: dircache_unlock(); @@ -2626,11 +2656,19 @@ file_error: /** * Test a path to various levels of rigor and optionally return dircache file - * info for the given path + * info for the given path. + * + * If the file reference is used, it is checked first and the path is checked + * only if all specified file reference checks fail. * * returns: - * success: 0 + * success: 0 = not cached (very weak) + * 1 = serial number checks out for the reference (weak) + * 2 = serial number and hash check out for the reference (medium) + * 3 = path is valid; reference updated if specified (strong) * failure: a negative value + * if file definitely doesn't exist (errno = ENOENT) + * other error * * errors (including but not limited to): * EFAULT - Bad address @@ -2638,78 +2676,121 @@ file_error: * ENAMETOOLONG - File or path name too long * ENOENT - No such file or directory * ENOTDIR - Not a directory - * ENXIO - No such device or address */ -int dircache_search(unsigned int flags, struct dircache_fileref *dcfrefp, const char *path) +int dircache_search(unsigned int flags, struct dircache_fileref *dcfrefp, + const char *path) { - int rc; - if (!(flags & (DCS_FILEREF | DCS_CACHED_PATH))) FILE_ERROR_RETURN(EINVAL, -1); /* search nothing? */ - dircache_lock(); + if (!dcfrefp && (flags & (DCS_FILEREF | DCS_UPDATE_FILEREF))) + FILE_ERROR_RETURN(EFAULT, -2); /* bad! */ - if (!dircache_runinfo.handle) - FILE_ERROR(ENOENT, -2); + int rc = 0; - if (flags & DCS_FILEREF) - { - if (!dcfrefp) - FILE_ERROR(EFAULT, -3); + dircache_lock(); - if (get_file_serialnum(&dcfrefp->dcfile) != 0) + /* -- File reference search -- */ + if (!dircache_runinfo.handle) + ; /* cache not enabled; not cached */ + else if (!(flags & DCS_FILEREF)) + ; /* don't use fileref */ + else if (check_file_serialnum(&dcfrefp->dcfile) < 0) + ; /* serial number bad */ + else if (!(flags & _DCS_VERIFY_FLAG)) + rc = 1; /* only check idx and serialnum */ + else if (get_file_serialhash(&dcfrefp->dcfile) == dcfrefp->serialhash) + rc = 2; /* reference is most likely still valid */ + + /* -- Path cache and storage search -- */ + if (rc > 0) + ; /* rc > 0 */ /* found by file reference */ + else if (!(flags & DCS_CACHED_PATH)) + ; /* rc = 0 */ /* reference bad/unused and no path */ + else + { /* rc = 0 */ /* check path with cache and/or storage */ + struct path_component_info compinfo; + struct filestr_base stream; + unsigned int ffcache = (flags & _DCS_STORAGE_FLAG) ? 0 : FF_CACHEONLY; + int err = errno; + int rc2 = open_stream_internal(path, ffcache | FF_ANYTYPE | FF_PROBE | + FF_INFO | FF_PARENTINFO, &stream, + &compinfo); + if (rc2 <= 0) { - if (!(flags & _DCS_VERIFY_FLAG)) - goto file_success; /* no robust verification wanted */ - - if (get_file_serialhash(&dcfrefp->dcfile) == dcfrefp->serialhash) - goto file_success; /* reference is most likely still valid */ - } - - if (!(flags & DCS_CACHED_PATH)) - FILE_ERROR(ENOENT, -4); /* no path search wanted */ - } + if (ffcache == 0) + { + /* checked storage too: absent for sure */ + FILE_ERROR(rc2 ? ERRNO : ENOENT, rc2 * 10 - 5); + } - if (flags & DCS_CACHED_PATH) - { - const bool update = flags & DCS_UPDATE_FILEREF; - struct path_component_info *compinfop = NULL; + if (rc2 < 0) + { + /* no base info available */ + if (errno != ENOENT) + FILE_ERROR(ERRNO, rc2 * 10 - 6); - if (update) - { - if (!dcfrefp) - FILE_ERROR(EFAULT, -5); + /* only cache; something didn't exist: indecisive */ + errno = err; + FILE_ERROR(ERRNO, RC); /* rc = 0 */ + } - compinfop = alloca(sizeof (*compinfop)); + struct dircache_file *dcfp = &compinfo.parentinfo.dcfile; + if (get_frontier(dcfp->idx) == FRONTIER_SETTLED) + FILE_ERROR(ENOENT, -7); /* parent not a frontier; absent */ + /* else checked only cache; parent is incomplete: indecisive */ } - - struct filestr_base stream; - rc = open_stream_internal(path, FF_ANYTYPE | FF_PROBE | FF_SELFINFO | - ((flags & _DCS_STORAGE_FLAG) ? 0 : FF_CACHEONLY), - &stream, compinfop); - if (rc <= 0) + else { - if (update) - dircache_fileref_init(dcfrefp); - - FILE_ERROR(rc ? ERRNO : ENOENT, rc * 10 - 6); - } + struct dircache_file *dcfp = &compinfo.info.dcfile; + if (dcfp->serialnum != 0) + { + /* found by path in the cache afterall */ + if (flags & DCS_UPDATE_FILEREF) + { + dcfrefp->dcfile = *dcfp; + dcfrefp->serialhash = get_file_serialhash(dcfp); + } - if (update) - { - dcfrefp->dcfile = compinfop->info.dcfile; - dcfrefp->serialhash = get_file_serialhash(&compinfop->info.dcfile); + rc = 3; + } } } -file_success: - rc = 0; - file_error: + if (rc <= 0 && (flags & DCS_UPDATE_FILEREF)) + dircache_fileref_init(dcfrefp); + dircache_unlock(); return rc; } +/** + * Compare dircache file references (no validity check is made) + * + * returns: 0 - no match + * 1 - indexes match + * 2 - serial numbers match + * 3 - serial and hashes match + */ +int dircache_fileref_cmp(const struct dircache_fileref *dcfrefp1, + const struct dircache_fileref *dcfrefp2) +{ + int cmp = 0; + + if (dcfrefp1->dcfile.idx == dcfrefp2->dcfile.idx) + { + cmp++; + if (dcfrefp1->dcfile.serialnum == dcfrefp2->dcfile.serialnum) + { + cmp++; + if (dcfrefp1->serialhash == dcfrefp2->serialhash) + cmp++; + } + } + + return cmp; +} /** Debug screen/info stuff **/ diff --git a/firmware/common/file.c b/firmware/common/file.c index 1f93824dc8..028bdbe9f0 100644 --- a/firmware/common/file.c +++ b/firmware/common/file.c @@ -354,6 +354,10 @@ static int open_internal_inner2(const char *path, int rc; struct path_component_info compinfo; + + if (callflags & FF_CREAT) + callflags |= FF_PARENTINFO; + rc = open_stream_internal(path, callflags, &file->stream, &compinfo); if (rc < 0) { @@ -989,7 +993,8 @@ int rename(const char *old, const char *new) file_internal_lock_WRITER(); /* open 'old'; it must exist */ - open1rc = open_stream_internal(old, FF_ANYTYPE, &oldstr, &oldinfo); + open1rc = open_stream_internal(old, FF_ANYTYPE | FF_PARENTINFO, &oldstr, + &oldinfo); if (open1rc <= 0) { DEBUGF("Failed opening old: %d\n", open1rc); @@ -1014,7 +1019,8 @@ int rename(const char *old, const char *new) newinfo.prefixp = oldstr.infop; } - open2rc = open_stream_internal(new, callflags, &newstr, &newinfo); + open2rc = open_stream_internal(new, callflags | FF_PARENTINFO, &newstr, + &newinfo); if (open2rc < 0) { DEBUGF("Failed opening new file: %d\n", open2rc); diff --git a/firmware/common/file_internal.c b/firmware/common/file_internal.c index 75fb21e8a6..8fee802f6f 100644 --- a/firmware/common/file_internal.c +++ b/firmware/common/file_internal.c @@ -351,10 +351,10 @@ static int fill_path_compinfo(struct pathwalk *walkp, compinfo->length = compp->length; compinfo->attr = compp->attr; compinfo->filesize = walkp->filesize; - if (!(walkp->callflags & FF_SELFINFO)) - compinfo->parentinfo = (compp->nextp ?: compp)->info; - else + if (walkp->callflags & FF_INFO) compinfo->info = compp->info; + if (walkp->callflags & FF_PARENTINFO) + compinfo->parentinfo = (compp->nextp ?: compp)->info; } return rc; @@ -571,9 +571,9 @@ int open_stream_internal(const char *path, unsigned int callflags, FILE_ERROR(path ? ENOENT : EFAULT, -1); } - /* if !compinfo, then the result of this check is not visible anyway */ + /* if !compinfo then these cannot be returned anyway */ if (!compinfo) - callflags &= ~FF_CHECKPREFIX; + callflags &= ~(FF_INFO | FF_PARENTINFO | FF_CHECKPREFIX); /* This lets it be passed quietly to directory scanning */ stream->flags = callflags & FF_MASK; diff --git a/firmware/include/dircache.h b/firmware/include/dircache.h index d73c6f6e81..2cf838e539 100644 --- a/firmware/include/dircache.h +++ b/firmware/include/dircache.h @@ -69,6 +69,9 @@ typedef uint32_t dc_serial_t; /** ****************************************************************************/ +#define IF_DIRCACHE(...) __VA_ARGS__ +#define IFN_DIRCACHE(...) + #if CONFIG_PLATFORM & PLATFORM_NATIVE /* native dircache is lower-level than on a hosted target */ #define DIRCACHE_NATIVE @@ -169,6 +172,9 @@ enum dircache_search_flags int dircache_search(unsigned int flags, struct dircache_fileref *dcfrefp, const char *path); +int dircache_fileref_cmp(const struct dircache_fileref *dcfrefp1, + const struct dircache_fileref *dcfrefp2); + /** Debug screen/info stuff **/ @@ -202,6 +208,11 @@ int dircache_save(void); void dircache_init(size_t last_size) INIT_ATTR; +#else /* !HAVE_DIRCACHE */ + +#define IF_DIRCACHE(...) +#define IFN_DIRCACHE(...) __VA_ARGS__ + #endif /* HAVE_DIRCACHE */ #endif /* _DIRCACHE_H */ diff --git a/firmware/include/file_internal.h b/firmware/include/file_internal.h index acec81206e..e7edb3a441 100644 --- a/firmware/include/file_internal.h +++ b/firmware/include/file_internal.h @@ -136,8 +136,9 @@ enum fildes_and_obj_flags FF_NOISO = 0x00200000, /* do not decode ISO filenames to UTF-8 */ FF_PROBE = 0x00400000, /* only test existence; don't open */ FF_CACHEONLY = 0x00800000, /* succeed only if in dircache */ - FF_SELFINFO = 0x01000000, /* return info on self as well */ - FF_MASK = 0x01ff0000, + FF_INFO = 0x01000000, /* return info on self */ + FF_PARENTINFO = 0x02000000, /* return info on parent */ + FF_MASK = 0x03ff0000, }; /** Common data structures used throughout **/ @@ -244,18 +245,16 @@ static inline void filestr_unlock(struct filestr_base *stream) /* structure to return detailed information about what you opened */ struct path_component_info { - const char *name; /* pointer to name within 'path' (OUT) */ - size_t length; /* length of component within 'path' */ - file_size_t filesize; /* size of the opened file (0 if dir) */ - unsigned int attr; /* attributes of this component */ - struct file_base_info *prefixp; /* base info to check as prefix - (IN if FF_CHECKPREFIX) */ - union { - struct file_base_info parentinfo; /* parent directory base info of file - (if not FF_SELFINFO) */ - struct file_base_info info; /* base info of file itself - (if FF_SELFINFO) */ - }; + const char *name; /* OUT: pointer to name within 'path' */ + size_t length; /* OUT: length of component within 'path' */ + file_size_t filesize; /* OUT: size of the opened file (0 if dir) */ + unsigned int attr; /* OUT: attributes of this component */ + struct file_base_info info; /* OUT: base info on file + (FF_INFO) */ + struct file_base_info parentinfo; /* OUT: base parent directory info + (FF_PARENTINFO) */ + struct file_base_info *prefixp; /* IN: base info to check as prefix + (FF_CHECKPREFIX) */ }; int open_stream_internal(const char *path, unsigned int callflags, |