This library provides new abstractions for the upper (VFS) side of
file system services, and should be used for all file system service
implementations from now on. It provides the following functionality:
- a function call table abstraction, hiding the details of the
VFS-FS protocol with simple parameters;
- a (currently limited) number of per-function steps required for
all file system implementations, such as copying in and out path
names and result buffers;
- a default implementation for multicomponent path lookups, such
that the file system merely has to implement resolution of single
components at a time;
- an abstraction for copying data from and to the file system, which
allows transparent intraprocess copying as required for the lookup
implementation;
- a set of functions to simplify getdents implementations.
The message loop provided by the library is currently for use by
single-threaded file system implementations only. Multithreaded file
system services may use the more low-level message processing
functionality.
Protocol-level optimizations such as including names in protocol
messages may be hidden entirely in this library. In addition, in the
future, the lookup implementation may be replaced by a single-
component lookup VFS/FS protocol request as part of a VFS name cache
implementation; this, too, can be hidden entirely in this library.
Change-Id: Ib34f0d0e021dfa3426ce8826efcf3eaa94d3ef3e
100 lines
2.4 KiB
C
100 lines
2.4 KiB
C
|
|
#include "fsdriver.h"
|
|
#include <sys/dirent.h>
|
|
|
|
/*
|
|
* Initialize a directory entry listing.
|
|
*/
|
|
void
|
|
fsdriver_dentry_init(struct fsdriver_dentry * __restrict dentry,
|
|
const struct fsdriver_data * __restrict data, size_t bytes,
|
|
char * __restrict buf, size_t bufsize)
|
|
{
|
|
|
|
dentry->data = data;
|
|
dentry->data_size = bytes;
|
|
dentry->data_off = 0;
|
|
dentry->buf = buf;
|
|
dentry->buf_size = bufsize;
|
|
dentry->buf_off = 0;
|
|
}
|
|
|
|
/*
|
|
* Add an entry to a directory entry listing. Return the entry size if it was
|
|
* added, zero if no more entries could be added and the listing should stop,
|
|
* or an error code in case of an error.
|
|
*/
|
|
ssize_t
|
|
fsdriver_dentry_add(struct fsdriver_dentry * __restrict dentry, ino_t ino_nr,
|
|
const char * __restrict name, size_t namelen, unsigned int type)
|
|
{
|
|
struct dirent *dirent;
|
|
size_t len, used;
|
|
int r;
|
|
|
|
/* We could do several things here, but it should never happen.. */
|
|
if (namelen > MAXNAMLEN)
|
|
panic("fsdriver: directory entry name excessively long");
|
|
|
|
len = _DIRENT_RECLEN(dirent, namelen);
|
|
|
|
if (dentry->data_off + dentry->buf_off + len > dentry->data_size) {
|
|
if (dentry->data_off == 0 && dentry->buf_off == 0)
|
|
return EINVAL;
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (dentry->buf_off + len > dentry->buf_size) {
|
|
if (dentry->buf_off == 0)
|
|
panic("fsdriver: getdents buffer too small");
|
|
|
|
if ((r = fsdriver_copyout(dentry->data, dentry->data_off,
|
|
dentry->buf, dentry->buf_off)) != OK)
|
|
return r;
|
|
|
|
dentry->data_off += dentry->buf_off;
|
|
dentry->buf_off = 0;
|
|
}
|
|
|
|
dirent = (struct dirent *)&dentry->buf[dentry->buf_off];
|
|
dirent->d_fileno = ino_nr;
|
|
dirent->d_reclen = len;
|
|
dirent->d_namlen = namelen;
|
|
dirent->d_type = type;
|
|
memcpy(dirent->d_name, name, namelen);
|
|
|
|
/*
|
|
* Null-terminate the name, and zero out any alignment bytes after it,
|
|
* so as not to leak any data.
|
|
*/
|
|
used = _DIRENT_NAMEOFF(dirent) + namelen;
|
|
if (used >= len)
|
|
panic("fsdriver: inconsistency in dirent record");
|
|
memset(&dirent->d_name[namelen], 0, len - used);
|
|
|
|
dentry->buf_off += len;
|
|
|
|
return len;
|
|
}
|
|
|
|
/*
|
|
* Finish a directory entry listing operation. Return the total number of
|
|
* bytes copied to the caller, or an error code in case of an error.
|
|
*/
|
|
ssize_t
|
|
fsdriver_dentry_finish(struct fsdriver_dentry *dentry)
|
|
{
|
|
int r;
|
|
|
|
if (dentry->buf_off > 0) {
|
|
if ((r = fsdriver_copyout(dentry->data, dentry->data_off,
|
|
dentry->buf, dentry->buf_off)) != OK)
|
|
return r;
|
|
|
|
dentry->data_off += dentry->buf_off;
|
|
}
|
|
|
|
return dentry->data_off;
|
|
}
|