summaryrefslogtreecommitdiffstats
path: root/firmware/common
diff options
context:
space:
mode:
authorMichael Sevakis <jethead71@rockbox.org>2017-01-18 04:39:35 -0500
committerMichael Sevakis <jethead71@rockbox.org>2017-02-10 05:05:23 -0500
commit7373cf518f4d4c47f49693690c2ab8ec29bb8510 (patch)
tree0a3c025749be24561e952078e83c5f2e8b838900 /firmware/common
parentabd75a17d18c0779b59f64a612f9226b62af5823 (diff)
downloadrockbox-7373cf518f4d4c47f49693690c2ab8ec29bb8510.tar.gz
rockbox-7373cf518f4d4c47f49693690c2ab8ec29bb8510.tar.bz2
rockbox-7373cf518f4d4c47f49693690c2ab8ec29bb8510.zip
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/common')
-rw-r--r--firmware/common/dir.c3
-rw-r--r--firmware/common/dircache.c209
-rw-r--r--firmware/common/file.c10
-rw-r--r--firmware/common/file_internal.c10
4 files changed, 160 insertions, 72 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;