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
This commit is contained in:
parent
abd75a17d1
commit
7373cf518f
|
@ -1324,7 +1324,7 @@ static void playlist_thread(void)
|
|||
&& queue_empty(&playlist_queue); index++)
|
||||
{
|
||||
/* Process only pointers that are superficially stale. */
|
||||
if (dircache_search(DCS_FILEREF, &playlist->dcfrefs[index], NULL) == 0)
|
||||
if (dircache_search(DCS_FILEREF, &playlist->dcfrefs[index], NULL) > 0)
|
||||
continue ;
|
||||
|
||||
control_file = playlist->indices[index] & PLAYLIST_INSERT_TYPE_MASK;
|
||||
|
|
847
apps/tagcache.c
847
apps/tagcache.c
File diff suppressed because it is too large
Load Diff
|
@ -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");
|
||||
|
|
|
@ -609,6 +609,19 @@ static int get_index(const struct dircache_entry *ce)
|
|||
return ce - dircache_runinfo.pentry;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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'
|
||||
*/
|
||||
|
@ -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;
|
||||
dc_serial_t serialnum = dcfilep->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? */
|
||||
|
||||
if (!dcfrefp && (flags & (DCS_FILEREF | DCS_UPDATE_FILEREF)))
|
||||
FILE_ERROR_RETURN(EFAULT, -2); /* bad! */
|
||||
|
||||
int rc = 0;
|
||||
|
||||
dircache_lock();
|
||||
|
||||
/* -- File reference search -- */
|
||||
if (!dircache_runinfo.handle)
|
||||
FILE_ERROR(ENOENT, -2);
|
||||
|
||||
if (flags & DCS_FILEREF)
|
||||
{
|
||||
if (!dcfrefp)
|
||||
FILE_ERROR(EFAULT, -3);
|
||||
|
||||
if (get_file_serialnum(&dcfrefp->dcfile) != 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 (flags & DCS_CACHED_PATH)
|
||||
{
|
||||
const bool update = flags & DCS_UPDATE_FILEREF;
|
||||
struct path_component_info *compinfop = NULL;
|
||||
|
||||
if (update)
|
||||
{
|
||||
if (!dcfrefp)
|
||||
FILE_ERROR(EFAULT, -5);
|
||||
|
||||
compinfop = alloca(sizeof (*compinfop));
|
||||
}
|
||||
; /* 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;
|
||||
rc = open_stream_internal(path, FF_ANYTYPE | FF_PROBE | FF_SELFINFO |
|
||||
((flags & _DCS_STORAGE_FLAG) ? 0 : FF_CACHEONLY),
|
||||
&stream, compinfop);
|
||||
if (rc <= 0)
|
||||
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 (update)
|
||||
dircache_fileref_init(dcfrefp);
|
||||
|
||||
FILE_ERROR(rc ? ERRNO : ENOENT, rc * 10 - 6);
|
||||
}
|
||||
if (ffcache == 0)
|
||||
{
|
||||
/* checked storage too: absent for sure */
|
||||
FILE_ERROR(rc2 ? ERRNO : ENOENT, rc2 * 10 - 5);
|
||||
}
|
||||
|
||||
if (update)
|
||||
if (rc2 < 0)
|
||||
{
|
||||
/* no base info available */
|
||||
if (errno != ENOENT)
|
||||
FILE_ERROR(ERRNO, rc2 * 10 - 6);
|
||||
|
||||
/* only cache; something didn't exist: indecisive */
|
||||
errno = err;
|
||||
FILE_ERROR(ERRNO, RC); /* rc = 0 */
|
||||
}
|
||||
|
||||
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 */
|
||||
}
|
||||
else
|
||||
{
|
||||
dcfrefp->dcfile = compinfop->info.dcfile;
|
||||
dcfrefp->serialhash = get_file_serialhash(&compinfop->info.dcfile);
|
||||
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);
|
||||
}
|
||||
|
||||
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 **/
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue