rockbox/firmware/include/dircache.h

219 lines
7.7 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 by Miika Pekkarinen
* Copyright (C) 2014 by Michael Sevakis
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#ifndef _DIRCACHE_H
#define _DIRCACHE_H
#include "mv.h"
#include <string.h> /* size_t */
#include <sys/types.h> /* ssize_t */
#ifdef HAVE_DIRCACHE
/****************************************************************************
** Configurable values
**/
#if 0
/* enable dumping code */
#define DIRCACHE_DUMPSTER
#define DIRCACHE_DUMPSTER_BIN "/dircache_dump.bin"
#define DIRCACHE_DUMPSTER_CSV "/dircache_dump.csv"
#endif
/* dircache builds won't search below this but will work down to this point
while below it the cache will just pass requests through to the storage;
the limiting factor is the scanning thread stack size, not the
implementation -- tune the two together */
#define DIRCACHE_MAX_DEPTH 15
#define DIRCACHE_STACK_SIZE (DEFAULT_STACK_SIZE + 0x100)
/* memory buffer constants that control allocation */
#define DIRCACHE_RESERVE (1024*64) /* 64 KB - new entry slack */
#define DIRCACHE_MIN (1024*1024*1) /* 1 MB - provision min size */
#define DIRCACHE_LIMIT (1024*1024*6) /* 6 MB - provision max size */
/* make it easy to change serialnumber size without modifying anything else;
32 bits allows 21845 builds before wrapping in a 6MB cache that is filled
exclusively with entries and nothing else (32 byte entries), making that
figure pessimistic */
typedef uint32_t dc_serial_t;
/* these should agree with size of dc_serial_t */
#define DC_SERHASH_START 0xffffffff
/* I was originally using FNV hash but decided this is probably okay
(for now) */
#define dc_hash_serialnum(s, h) \
({ dc_serial_t __x = (s); crc_32(&(__x), sizeof(dc_serial_t), (h)); })
#define DC_SERIAL_FMT "0x%08lX"
/**
****************************************************************************/
#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
#endif
struct dircache_file
{
int idx; /* this file's cache index */
dc_serial_t serialnum; /* this file's serial number */
};
enum dircache_status
{
DIRCACHE_IDLE = 0, /* no volume is initialized */
DIRCACHE_SCANNING = 1, /* dircache is scanning a volume */
DIRCACHE_READY = 2, /* dircache is ready to be used */
};
/** Dircache control **/
void dircache_wait(void);
void dircache_suspend(void);
int dircache_resume(void);
int dircache_enable(void);
void dircache_disable(void);
void dircache_free_buffer(void);
/** Volume mounting **/
void dircache_mount(void); /* always tries building everything it can */
void dircache_unmount(IF_MV_NONVOID(int volume));
/** File API service functions **/
/* avoid forcing #include of file_internal.h, fat.h and dir.h */
struct filestr_base;
struct file_base_info;
struct file_base_binding;
struct dirent;
struct dirscan_info;
struct dirinfo_native;
int dircache_readdir_dirent(struct filestr_base *stream,
struct dirscan_info *scanp,
struct dirent *entry);
void dircache_rewinddir_dirent(struct dirscan_info *scanp);
#ifdef DIRCACHE_NATIVE
struct fat_direntry;
int dircache_readdir_internal(struct filestr_base *stream,
struct file_base_info *infop,
struct fat_direntry *fatent);
void dircache_rewinddir_internal(struct file_base_info *info);
#endif /* DIRCACHE_NATIVE */
/** Dircache live updating **/
void dircache_get_rootinfo(struct file_base_info *infop);
void dircache_bind_file(struct file_base_binding *bindp);
void dircache_unbind_file(struct file_base_binding *bindp);
void dircache_fileop_create(struct file_base_info *dirinfop,
struct file_base_binding *bindp,
const char *basename,
const struct dirinfo_native *dinp);
void dircache_fileop_rename(struct file_base_info *dirinfop,
struct file_base_binding *bindp,
const char *basename);
void dircache_fileop_remove(struct file_base_binding *bindp);
void dircache_fileop_sync(struct file_base_binding *infop,
const struct dirinfo_native *dinp);
/** Dircache paths, files and shortcuts **/
struct dircache_fileref
{
struct dircache_file dcfile;
dc_serial_t serialhash; /* Hash of serialnumbers to root */
};
void dircache_fileref_init(struct dircache_fileref *dcfrefp);
ssize_t dircache_get_fileref_path(const struct dircache_fileref *dcfrefp,
char *buf, size_t size);
/* Bitflags for dircache_search() */
enum dircache_search_flags
{
DCS_FILEREF = 0x01, /* Check fileref existence and serial number */
_DCS_VERIFY_FLAG = 0x02, /* Internal: Only valid with DCS_FILEREF */
DCS_FILEREF_VERIFY = 0x03, /* Do DCS_FILEREF check + verify serial hash */
DCS_CACHED_PATH = 0x04, /* Check only cache for provided path */
_DCS_STORAGE_FLAG = 0x08, /* Internal: Only valid with DCS_CACHED_PATH */
DCS_STORAGE_PATH = 0x0c, /* Read-through if needed for provided path */
DCS_UPDATE_FILEREF = 0x10, /* If fileref is not valid but path is found or
searching a path, update the reference
information */
};
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 **/
struct dircache_info
{
enum dircache_status status; /* current composite status value */
const char *statusdesc; /* pointer to string describing 'status' */
size_t last_size; /* cache size after last build */
size_t size; /* total size of entries (with holes) */
size_t sizeused; /* bytes of 'size' actually utilized */
size_t size_limit; /* maximum possible size */
size_t reserve; /* size of reserve area */
size_t reserve_used; /* amount of reserve used */
unsigned int entry_count; /* number of cache entries */
long build_ticks; /* total time used to build cache */
};
void dircache_get_info(struct dircache_info *info);
#ifdef DIRCACHE_DUMPSTER
void dircache_dump(void);
#endif /* DIRCACHE_DUMPSTER */
/** Misc. stuff **/
void dircache_dcfile_init(struct dircache_file *dcfilep);
#ifdef HAVE_EEPROM_SETTINGS
int dircache_load(void);
int dircache_save(void);
#endif /* HAVE_EEPROM_SETTINGS */
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 */