Commit 4879a26b authored by Alessandro Rubini's avatar Alessandro Rubini

sdbfs/userspace/lib: support subdirectories

Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent 08c1cc62
......@@ -80,37 +80,91 @@ static struct sdb_device *sdbfs_readentry(struct sdbfs *fs,
return &fs->current_record;
}
/* Helper for scanning: we enter a new directory, and we must validate */
static struct sdb_device *scan_newdir(struct sdbfs *fs, int depth)
{
struct sdb_device *dev;
struct sdb_interconnect *intercon;
dev = fs->currentp = sdbfs_readentry(fs, fs->this[depth]);
if (dev->sdb_component.product.record_type != sdb_type_interconnect)
return NULL;
intercon = (typeof(intercon))dev;
if (ntohl(intercon->sdb_magic) != SDB_MAGIC)
return NULL;
fs->nleft[depth] = ntohs(intercon->sdb_records) - 1;
fs->this[depth] += sizeof(*intercon);
fs->depth = depth;
return dev;
}
struct sdb_device *sdbfs_scan(struct sdbfs *fs, int newscan)
{
/*
* This returns a pointer to the next sdb record, or a new one.
* Subdirectories are not supported. Uses all internal fields
* This returns a pointer to the next sdb record, or the first one.
* Subdirectories (bridges) are returned before their contents.
* It only uses internal fields.
*/
struct sdb_device *ret;
struct sdb_interconnect *i;
struct sdb_device *dev;
struct sdb_bridge *bridge;
int depth, type, newdir = 0; /* check there's the magic */
if (newscan) {
fs->f_offset = fs->entrypoint;
} else {
fs->f_offset += sizeof(struct sdb_device);
if (!fs->nleft)
return NULL;
fs->base[0] = 0;
fs->this[0] = fs->entrypoint;
depth = fs->depth = 0;
newdir = 1;
goto scan;
}
ret = sdbfs_readentry(fs, fs->f_offset);
if (newscan) {
i = (typeof(i))ret;
fs->nleft = ntohs(i->sdb_records) - 1;
} else {
fs->nleft--;
/* If we already returned a bridge, go inside it (check type) */
depth = fs->depth;
type = fs->currentp->sdb_component.product.record_type;
if (type == sdb_type_bridge && depth + 1 < SDBFS_DEPTH) {
bridge = (typeof(bridge))fs->currentp;
fs->this[depth + 1] = fs->base[depth]
+ ntohll(bridge->sdb_child);
fs->base[depth + 1] = fs->base[depth]
+ ntohll(bridge->sdb_component.addr_first);
depth++;
newdir++;
}
scan:
/* If entering a new directory, verify magic and set nleft */
if (newdir) {
dev = scan_newdir(fs, depth);
if (dev)
return dev;
/* Otherwise the directory is not there: no intercon */
if (!depth)
return NULL; /* no entries at all */
depth--;
}
return ret;
while (fs->nleft[depth] == 0) {
/* No more at this level, "cd .." if possible */
if (!depth)
return NULL;
fs->depth = --depth;
}
/* so, read the next entry */
dev = fs->currentp = sdbfs_readentry(fs, fs->this[depth]);
fs->this[depth] += sizeof(*dev);
fs->nleft[depth]--;
return dev;
}
static void __open(struct sdbfs *fs)
{
fs->f_offset = htonll(fs->currentp->sdb_component.addr_first);
fs->f_offset = fs->base[fs->depth]
+ htonll(fs->currentp->sdb_component.addr_first);
fs->f_len = htonll(fs->currentp->sdb_component.addr_last)
+ 1 - fs->f_offset;
+ 1 - htonll(fs->currentp->sdb_component.addr_first);
fs->read_offset = 0;
}
......
......@@ -12,6 +12,7 @@
#include <sdb.h> /* Please point your "-I" to some sensible place */
#define SDBFS_DEPTH 4 /* Max number of subdirectory depth */
/*
* Data structures: please not that the library intself doesn't use
* malloc, so it's the caller who must deal withallocation/removal.
......@@ -24,7 +25,7 @@ struct sdbfs {
/* Some fields are informative */
char *name; /* may be null */
void *drvdata; /* driver may need some detail.. */
int blocksize;
unsigned long blocksize;
unsigned long entrypoint;
/* The "driver" must offer some methods */
......@@ -34,15 +35,19 @@ struct sdbfs {
int (*write)(struct sdbfs *fs, int offset, void *buf, int count);
int (*erase)(struct sdbfs *fs, int offset, int count);
/* The following fields are library-private */
struct sdb_device current_record;
/* All fields from here onwards are library-private */
struct sdb_device *currentp;
int nleft;
unsigned long f_offset;
struct sdb_device current_record;
unsigned long f_len;
unsigned long read_offset;
unsigned long f_offset; /* start of file */
unsigned long read_offset; /* current location */
unsigned long flags;
struct sdbfs *next;
/* The following ones are directory-aware */
unsigned long base[SDBFS_DEPTH]; /* for relative addresses */
unsigned long this[SDBFS_DEPTH]; /* current sdb record */
int nleft[SDBFS_DEPTH];
int depth;
};
#define SDBFS_F_VERBOSE 0x0001
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment