
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
936 lines
20 KiB
C
936 lines
20 KiB
C
|
|
#include "fsdriver.h"
|
|
#include <minix/ds.h>
|
|
|
|
/*
|
|
* Process a READSUPER request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_readsuper(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
struct fsdriver_node root_node;
|
|
char label[DS_MAX_KEYLEN];
|
|
cp_grant_id_t label_grant;
|
|
size_t label_len;
|
|
unsigned int flags, res_flags;
|
|
dev_t dev;
|
|
int r;
|
|
|
|
dev = m_in->m_vfs_fs_readsuper.device;
|
|
label_grant = m_in->m_vfs_fs_readsuper.grant;
|
|
label_len = m_in->m_vfs_fs_readsuper.path_len;
|
|
flags = m_in->m_vfs_fs_readsuper.flags;
|
|
|
|
if (fdp->fdr_mount == NULL)
|
|
return ENOSYS;
|
|
|
|
if (fsdriver_mounted) {
|
|
printf("fsdriver: attempt to mount multiple times\n");
|
|
return EBUSY;
|
|
}
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, label_grant, label_len,
|
|
label, sizeof(label), FALSE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
if (fdp->fdr_driver != NULL)
|
|
fdp->fdr_driver(dev, label);
|
|
|
|
res_flags = RES_NOFLAGS;
|
|
|
|
r = fdp->fdr_mount(dev, flags, &root_node, &res_flags);
|
|
|
|
if (r == OK) {
|
|
/* This one we can set on the file system's behalf. */
|
|
if (fdp->fdr_peek != NULL && fdp->fdr_bpeek != NULL)
|
|
res_flags |= RES_HASPEEK;
|
|
|
|
m_out->m_fs_vfs_readsuper.inode = root_node.fn_ino_nr;
|
|
m_out->m_fs_vfs_readsuper.mode = root_node.fn_mode;
|
|
m_out->m_fs_vfs_readsuper.file_size = root_node.fn_size;
|
|
m_out->m_fs_vfs_readsuper.uid = root_node.fn_uid;
|
|
m_out->m_fs_vfs_readsuper.gid = root_node.fn_gid;
|
|
m_out->m_fs_vfs_readsuper.flags = res_flags;
|
|
|
|
/* Update library-local state. */
|
|
fsdriver_mounted = TRUE;
|
|
fsdriver_root = root_node.fn_ino_nr;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process an UNMOUNT request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_unmount(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict __unused m_in,
|
|
message * __restrict __unused m_out)
|
|
{
|
|
|
|
if (fdp->fdr_unmount != NULL)
|
|
fdp->fdr_unmount();
|
|
|
|
/* Update library-local state. */
|
|
fsdriver_mounted = FALSE;
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
* Process a PUTNODE request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_putnode(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
ino_t ino_nr;
|
|
unsigned int count;
|
|
|
|
ino_nr = m_in->m_vfs_fs_putnode.inode;
|
|
count = m_in->m_vfs_fs_putnode.count;
|
|
|
|
if (fdp->fdr_putnode == NULL)
|
|
return ENOSYS;
|
|
|
|
if (count == 0 || count > INT_MAX) {
|
|
printf("fsdriver: invalid reference count\n");
|
|
return EINVAL;
|
|
}
|
|
|
|
return fdp->fdr_putnode(ino_nr, count);
|
|
}
|
|
|
|
/*
|
|
* Process a NEWNODE request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_newnode(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
struct fsdriver_node node;
|
|
mode_t mode;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
dev_t dev;
|
|
int r;
|
|
|
|
mode = m_in->m_vfs_fs_newnode.mode;
|
|
uid = m_in->m_vfs_fs_newnode.uid;
|
|
gid = m_in->m_vfs_fs_newnode.gid;
|
|
dev = m_in->m_vfs_fs_newnode.device;
|
|
|
|
if (fdp->fdr_newnode == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fdp->fdr_newnode(mode, uid, gid, dev, &node)) == OK) {
|
|
m_out->m_fs_vfs_newnode.inode = node.fn_ino_nr;
|
|
m_out->m_fs_vfs_newnode.mode = node.fn_mode;
|
|
m_out->m_fs_vfs_newnode.file_size = node.fn_size;
|
|
m_out->m_fs_vfs_newnode.uid = node.fn_uid;
|
|
m_out->m_fs_vfs_newnode.gid = node.fn_gid;
|
|
m_out->m_fs_vfs_newnode.device = node.fn_dev;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a read or write request from VFS.
|
|
*/
|
|
static int
|
|
read_write(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out, int call)
|
|
{
|
|
struct fsdriver_data data;
|
|
ino_t ino_nr;
|
|
off_t pos;
|
|
size_t nbytes;
|
|
ssize_t r;
|
|
|
|
ino_nr = m_in->m_vfs_fs_readwrite.inode;
|
|
pos = m_in->m_vfs_fs_readwrite.seek_pos;
|
|
nbytes = m_in->m_vfs_fs_readwrite.nbytes;
|
|
|
|
if (pos < 0 || nbytes > SSIZE_MAX)
|
|
return EINVAL;
|
|
|
|
data.endpt = m_in->m_source;
|
|
data.grant = m_in->m_vfs_fs_readwrite.grant;
|
|
data.size = nbytes;
|
|
|
|
if (call == FSC_WRITE)
|
|
r = fdp->fdr_write(ino_nr, &data, nbytes, pos, call);
|
|
else
|
|
r = fdp->fdr_read(ino_nr, &data, nbytes, pos, call);
|
|
|
|
if (r >= 0) {
|
|
pos += r;
|
|
|
|
m_out->m_fs_vfs_readwrite.seek_pos = pos;
|
|
m_out->m_fs_vfs_readwrite.nbytes = r;
|
|
r = OK;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a READ request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_read(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
|
|
if (fdp->fdr_read == NULL)
|
|
return ENOSYS;
|
|
|
|
return read_write(fdp, m_in, m_out, FSC_READ);
|
|
}
|
|
|
|
/*
|
|
* Process a WRITE request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_write(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
|
|
if (fdp->fdr_write == NULL)
|
|
return ENOSYS;
|
|
|
|
return read_write(fdp, m_in, m_out, FSC_WRITE);
|
|
}
|
|
|
|
/*
|
|
* Process a PEEK request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_peek(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
ino_t ino_nr;
|
|
off_t pos;
|
|
size_t nbytes;
|
|
ssize_t r;
|
|
|
|
ino_nr = m_in->m_vfs_fs_readwrite.inode;
|
|
pos = m_in->m_vfs_fs_readwrite.seek_pos;
|
|
nbytes = m_in->m_vfs_fs_readwrite.nbytes;
|
|
|
|
if (fdp->fdr_peek == NULL)
|
|
return ENOSYS;
|
|
|
|
if (pos < 0 || nbytes > SSIZE_MAX)
|
|
return EINVAL;
|
|
|
|
r = fdp->fdr_peek(ino_nr, NULL /*data*/, nbytes, pos, FSC_PEEK);
|
|
|
|
/* Do not return a new position. */
|
|
if (r >= 0) {
|
|
m_out->m_fs_vfs_readwrite.nbytes = r;
|
|
r = OK;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a GETDENTS request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_getdents(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
struct fsdriver_data data;
|
|
ino_t ino_nr;
|
|
off_t pos;
|
|
size_t nbytes;
|
|
ssize_t r;
|
|
|
|
ino_nr = m_in->m_vfs_fs_getdents.inode;
|
|
pos = m_in->m_vfs_fs_getdents.seek_pos;
|
|
nbytes = m_in->m_vfs_fs_getdents.mem_size;
|
|
|
|
if (fdp->fdr_getdents == NULL)
|
|
return ENOSYS;
|
|
|
|
if (pos < 0 || nbytes > SSIZE_MAX)
|
|
return EINVAL;
|
|
|
|
data.endpt = m_in->m_source;
|
|
data.grant = m_in->m_vfs_fs_getdents.grant;
|
|
data.size = nbytes;
|
|
|
|
r = fdp->fdr_getdents(ino_nr, &data, nbytes, &pos);
|
|
|
|
if (r >= 0) {
|
|
m_out->m_fs_vfs_getdents.seek_pos = pos;
|
|
m_out->m_fs_vfs_getdents.nbytes = r;
|
|
r = OK;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a FTRUNC request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_trunc(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
ino_t ino_nr;
|
|
off_t start_pos, end_pos;
|
|
|
|
ino_nr = m_in->m_vfs_fs_ftrunc.inode;
|
|
start_pos = m_in->m_vfs_fs_ftrunc.trc_start;
|
|
end_pos = m_in->m_vfs_fs_ftrunc.trc_end;
|
|
|
|
if (start_pos < 0 || end_pos < 0)
|
|
return EINVAL;
|
|
|
|
if (fdp->fdr_trunc == NULL)
|
|
return ENOSYS;
|
|
|
|
return fdp->fdr_trunc(ino_nr, start_pos, end_pos);
|
|
}
|
|
|
|
/*
|
|
* Process a INHIBREAD request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_inhibread(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
ino_t ino_nr;
|
|
|
|
ino_nr = m_in->m_vfs_fs_inhibread.inode;
|
|
|
|
if (fdp->fdr_seek != NULL)
|
|
fdp->fdr_seek(ino_nr);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
* Process a CREATE request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_create(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
struct fsdriver_node node;
|
|
char name[NAME_MAX+1];
|
|
cp_grant_id_t grant;
|
|
size_t len;
|
|
ino_t dir_nr;
|
|
mode_t mode;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
int r;
|
|
|
|
grant = m_in->m_vfs_fs_create.grant;
|
|
len = m_in->m_vfs_fs_create.path_len;
|
|
dir_nr = m_in->m_vfs_fs_create.inode;
|
|
mode = m_in->m_vfs_fs_create.mode;
|
|
uid = m_in->m_vfs_fs_create.uid;
|
|
gid = m_in->m_vfs_fs_create.gid;
|
|
|
|
if (fdp->fdr_create == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, grant, len, name,
|
|
sizeof(name), TRUE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
if (!strcmp(name, ".") || !strcmp(name, ".."))
|
|
return EEXIST;
|
|
|
|
if ((r = fdp->fdr_create(dir_nr, name, mode, uid, gid, &node)) == OK) {
|
|
m_out->m_fs_vfs_create.inode = node.fn_ino_nr;
|
|
m_out->m_fs_vfs_create.mode = node.fn_mode;
|
|
m_out->m_fs_vfs_create.file_size = node.fn_size;
|
|
m_out->m_fs_vfs_create.uid = node.fn_uid;
|
|
m_out->m_fs_vfs_create.gid = node.fn_gid;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a MKDIR request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_mkdir(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
char name[NAME_MAX+1];
|
|
cp_grant_id_t grant;
|
|
size_t path_len;
|
|
ino_t dir_nr;
|
|
mode_t mode;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
int r;
|
|
|
|
grant = m_in->m_vfs_fs_mkdir.grant;
|
|
path_len = m_in->m_vfs_fs_mkdir.path_len;
|
|
dir_nr = m_in->m_vfs_fs_mkdir.inode;
|
|
mode = m_in->m_vfs_fs_mkdir.mode;
|
|
uid = m_in->m_vfs_fs_mkdir.uid;
|
|
gid = m_in->m_vfs_fs_mkdir.gid;
|
|
|
|
if (fdp->fdr_mkdir == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
|
|
sizeof(name), TRUE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
if (!strcmp(name, ".") || !strcmp(name, ".."))
|
|
return EEXIST;
|
|
|
|
return fdp->fdr_mkdir(dir_nr, name, mode, uid, gid);
|
|
}
|
|
|
|
/*
|
|
* Process a MKNOD request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_mknod(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
char name[NAME_MAX+1];
|
|
cp_grant_id_t grant;
|
|
size_t path_len;
|
|
ino_t dir_nr;
|
|
mode_t mode;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
dev_t dev;
|
|
int r;
|
|
|
|
grant = m_in->m_vfs_fs_mknod.grant;
|
|
path_len = m_in->m_vfs_fs_mknod.path_len;
|
|
dir_nr = m_in->m_vfs_fs_mknod.inode;
|
|
mode = m_in->m_vfs_fs_mknod.mode;
|
|
uid = m_in->m_vfs_fs_mknod.uid;
|
|
gid = m_in->m_vfs_fs_mknod.gid;
|
|
dev = m_in->m_vfs_fs_mknod.device;
|
|
|
|
if (fdp->fdr_mknod == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
|
|
sizeof(name), TRUE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
if (!strcmp(name, ".") || !strcmp(name, ".."))
|
|
return EEXIST;
|
|
|
|
return fdp->fdr_mknod(dir_nr, name, mode, uid, gid, dev);
|
|
}
|
|
|
|
/*
|
|
* Process a LINK request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_link(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
char name[NAME_MAX+1];
|
|
cp_grant_id_t grant;
|
|
size_t path_len;
|
|
ino_t dir_nr, ino_nr;
|
|
int r;
|
|
|
|
grant = m_in->m_vfs_fs_link.grant;
|
|
path_len = m_in->m_vfs_fs_link.path_len;
|
|
dir_nr = m_in->m_vfs_fs_link.dir_ino;
|
|
ino_nr = m_in->m_vfs_fs_link.inode;
|
|
|
|
if (fdp->fdr_link == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
|
|
sizeof(name), TRUE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
if (!strcmp(name, ".") || !strcmp(name, ".."))
|
|
return EEXIST;
|
|
|
|
return fdp->fdr_link(dir_nr, name, ino_nr);
|
|
}
|
|
|
|
/*
|
|
* Process an UNLINK request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_unlink(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
char name[NAME_MAX+1];
|
|
cp_grant_id_t grant;
|
|
size_t path_len;
|
|
ino_t dir_nr;
|
|
int r;
|
|
|
|
grant = m_in->m_vfs_fs_unlink.grant;
|
|
path_len = m_in->m_vfs_fs_unlink.path_len;
|
|
dir_nr = m_in->m_vfs_fs_unlink.inode;
|
|
|
|
if (fdp->fdr_unlink == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
|
|
sizeof(name), TRUE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
if (!strcmp(name, ".") || !strcmp(name, ".."))
|
|
return EPERM;
|
|
|
|
return fdp->fdr_unlink(dir_nr, name, FSC_UNLINK);
|
|
}
|
|
|
|
/*
|
|
* Process a RMDIR request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_rmdir(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
char name[NAME_MAX+1];
|
|
cp_grant_id_t grant;
|
|
size_t path_len;
|
|
ino_t dir_nr;
|
|
int r;
|
|
|
|
grant = m_in->m_vfs_fs_unlink.grant;
|
|
path_len = m_in->m_vfs_fs_unlink.path_len;
|
|
dir_nr = m_in->m_vfs_fs_unlink.inode;
|
|
|
|
if (fdp->fdr_rmdir == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
|
|
sizeof(name), TRUE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
if (!strcmp(name, "."))
|
|
return EINVAL;
|
|
|
|
if (!strcmp(name, ".."))
|
|
return ENOTEMPTY;
|
|
|
|
return fdp->fdr_rmdir(dir_nr, name, FSC_RMDIR);
|
|
}
|
|
|
|
/*
|
|
* Process a RENAME request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_rename(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
char old_name[NAME_MAX+1], new_name[NAME_MAX+1];
|
|
cp_grant_id_t old_grant, new_grant;
|
|
size_t old_len, new_len;
|
|
ino_t old_dir_nr, new_dir_nr;
|
|
int r;
|
|
|
|
old_grant = m_in->m_vfs_fs_rename.grant_old;
|
|
old_len = m_in->m_vfs_fs_rename.len_old;
|
|
old_dir_nr = m_in->m_vfs_fs_rename.dir_old;
|
|
new_grant = m_in->m_vfs_fs_rename.grant_new;
|
|
new_len = m_in->m_vfs_fs_rename.len_new;
|
|
new_dir_nr = m_in->m_vfs_fs_rename.dir_new;
|
|
|
|
if (fdp->fdr_rename == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, old_grant, old_len, old_name,
|
|
sizeof(old_name), TRUE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
if (!strcmp(old_name, ".") || !strcmp(old_name, ".."))
|
|
return EINVAL;
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, new_grant, new_len, new_name,
|
|
sizeof(new_name), TRUE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
if (!strcmp(new_name, ".") || !strcmp(new_name, ".."))
|
|
return EINVAL;
|
|
|
|
return fdp->fdr_rename(old_dir_nr, old_name, new_dir_nr, new_name);
|
|
}
|
|
|
|
/*
|
|
* Process a SLINK request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_slink(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
struct fsdriver_data data;
|
|
char name[NAME_MAX+1];
|
|
cp_grant_id_t grant;
|
|
size_t path_len;
|
|
ino_t dir_nr;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
int r;
|
|
|
|
grant = m_in->m_vfs_fs_slink.grant_path;
|
|
path_len = m_in->m_vfs_fs_slink.path_len;
|
|
dir_nr = m_in->m_vfs_fs_slink.inode;
|
|
uid = m_in->m_vfs_fs_slink.uid;
|
|
gid = m_in->m_vfs_fs_slink.gid;
|
|
|
|
if (fdp->fdr_slink == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, grant, path_len, name,
|
|
sizeof(name), TRUE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
if (!strcmp(name, ".") || !strcmp(name, ".."))
|
|
return EEXIST;
|
|
|
|
data.endpt = m_in->m_source;
|
|
data.grant = m_in->m_vfs_fs_slink.grant_target;
|
|
data.size = m_in->m_vfs_fs_slink.mem_size;
|
|
|
|
return fdp->fdr_slink(dir_nr, name, uid, gid, &data, data.size);
|
|
}
|
|
|
|
/*
|
|
* Process a RDLINK request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_rdlink(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
struct fsdriver_data data;
|
|
ssize_t r;
|
|
|
|
if (fdp->fdr_rdlink == NULL)
|
|
return ENOSYS;
|
|
|
|
data.endpt = m_in->m_source;
|
|
data.grant = m_in->m_vfs_fs_rdlink.grant;
|
|
data.size = m_in->m_vfs_fs_rdlink.mem_size;
|
|
|
|
r = fdp->fdr_rdlink(m_in->m_vfs_fs_rdlink.inode, &data, data.size);
|
|
|
|
if (r >= 0) {
|
|
m_out->m_fs_vfs_rdlink.nbytes = r;
|
|
r = OK;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a STAT request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_stat(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
struct stat buf;
|
|
cp_grant_id_t grant;
|
|
ino_t ino_nr;
|
|
int r;
|
|
|
|
ino_nr = m_in->m_vfs_fs_stat.inode;
|
|
grant = m_in->m_vfs_fs_stat.grant;
|
|
|
|
if (fdp->fdr_stat == NULL)
|
|
return ENOSYS;
|
|
|
|
memset(&buf, 0, sizeof(buf));
|
|
|
|
if ((r = fdp->fdr_stat(ino_nr, &buf)) == OK)
|
|
r = sys_safecopyto(m_in->m_source, grant, 0, (vir_bytes)&buf,
|
|
(phys_bytes)sizeof(buf));
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a CHOWN request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_chown(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
ino_t ino_nr;
|
|
uid_t uid;
|
|
gid_t gid;
|
|
mode_t mode;
|
|
int r;
|
|
|
|
ino_nr = m_in->m_vfs_fs_chown.inode;
|
|
uid = m_in->m_vfs_fs_chown.uid;
|
|
gid = m_in->m_vfs_fs_chown.gid;
|
|
|
|
if (fdp->fdr_chown == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fdp->fdr_chown(ino_nr, uid, gid, &mode)) == OK)
|
|
m_out->m_fs_vfs_chown.mode = mode;
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a CHMOD request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_chmod(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
ino_t ino_nr;
|
|
mode_t mode;
|
|
int r;
|
|
|
|
ino_nr = m_in->m_vfs_fs_chmod.inode;
|
|
mode = m_in->m_vfs_fs_chmod.mode;
|
|
|
|
if (fdp->fdr_chmod == NULL)
|
|
return ENOSYS;
|
|
|
|
if ((r = fdp->fdr_chmod(ino_nr, &mode)) == OK)
|
|
m_out->m_fs_vfs_chmod.mode = mode;
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a UTIME request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_utime(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
ino_t ino_nr;
|
|
struct timespec atime, mtime;
|
|
|
|
ino_nr = m_in->m_vfs_fs_utime.inode;
|
|
atime.tv_sec = m_in->m_vfs_fs_utime.actime;
|
|
atime.tv_nsec = m_in->m_vfs_fs_utime.acnsec;
|
|
mtime.tv_sec = m_in->m_vfs_fs_utime.modtime;
|
|
mtime.tv_nsec = m_in->m_vfs_fs_utime.modnsec;
|
|
|
|
if (fdp->fdr_utime == NULL)
|
|
return ENOSYS;
|
|
|
|
return fdp->fdr_utime(ino_nr, &atime, &mtime);
|
|
}
|
|
|
|
/*
|
|
* Process a MOUNTPOINT request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_mountpoint(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
ino_t ino_nr;
|
|
|
|
ino_nr = m_in->m_vfs_fs_mountpoint.inode;
|
|
|
|
if (fdp->fdr_mountpt == NULL)
|
|
return ENOSYS;
|
|
|
|
return fdp->fdr_mountpt(ino_nr);
|
|
}
|
|
|
|
/*
|
|
* Process a STATVFS request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_statvfs(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
struct statvfs buf;
|
|
int r;
|
|
|
|
if (fdp->fdr_statvfs == NULL)
|
|
return ENOSYS;
|
|
|
|
memset(&buf, 0, sizeof(buf));
|
|
|
|
if ((r = fdp->fdr_statvfs(&buf)) != OK)
|
|
return r;
|
|
|
|
return sys_safecopyto(m_in->m_source, m_in->m_vfs_fs_statvfs.grant, 0,
|
|
(vir_bytes)&buf, (phys_bytes)sizeof(buf));
|
|
}
|
|
|
|
/*
|
|
* Process a SYNC request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_sync(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict __unused m_in,
|
|
message * __restrict __unused m_out)
|
|
{
|
|
|
|
if (fdp->fdr_sync != NULL)
|
|
fdp->fdr_sync();
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
* Process a NEW_DRIVER request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_newdriver(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
char label[DS_MAX_KEYLEN];
|
|
cp_grant_id_t grant;
|
|
size_t path_len;
|
|
dev_t dev;
|
|
int r;
|
|
|
|
dev = m_in->m_vfs_fs_new_driver.device;
|
|
grant = m_in->m_vfs_fs_new_driver.grant;
|
|
path_len = m_in->m_vfs_fs_new_driver.path_len;
|
|
|
|
if (fdp->fdr_driver == NULL)
|
|
return OK;
|
|
|
|
if ((r = fsdriver_getname(m_in->m_source, grant, path_len, label,
|
|
sizeof(label), FALSE /*not_empty*/)) != OK)
|
|
return r;
|
|
|
|
fdp->fdr_driver(dev, label);
|
|
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
* Process a block read or write request from VFS.
|
|
*/
|
|
static ssize_t
|
|
bread_bwrite(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out, int call)
|
|
{
|
|
struct fsdriver_data data;
|
|
dev_t dev;
|
|
off_t pos;
|
|
size_t nbytes;
|
|
ssize_t r;
|
|
|
|
dev = m_in->m_vfs_fs_breadwrite.device;
|
|
pos = m_in->m_vfs_fs_breadwrite.seek_pos;
|
|
nbytes = m_in->m_vfs_fs_breadwrite.nbytes;
|
|
|
|
if (pos < 0 || nbytes > SSIZE_MAX)
|
|
return EINVAL;
|
|
|
|
data.endpt = m_in->m_source;
|
|
data.grant = m_in->m_vfs_fs_breadwrite.grant;
|
|
data.size = nbytes;
|
|
|
|
if (call == FSC_WRITE)
|
|
r = fdp->fdr_bwrite(dev, &data, nbytes, pos, call);
|
|
else
|
|
r = fdp->fdr_bread(dev, &data, nbytes, pos, call);
|
|
|
|
if (r >= 0) {
|
|
pos += r;
|
|
|
|
m_out->m_fs_vfs_breadwrite.seek_pos = pos;
|
|
m_out->m_fs_vfs_breadwrite.nbytes = r;
|
|
r = OK;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a BREAD request from VFS.
|
|
*/
|
|
ssize_t
|
|
fsdriver_bread(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
|
|
if (fdp->fdr_bread == NULL)
|
|
return ENOSYS;
|
|
|
|
return bread_bwrite(fdp, m_in, m_out, FSC_READ);
|
|
}
|
|
|
|
/*
|
|
* Process a BWRITE request from VFS.
|
|
*/
|
|
ssize_t
|
|
fsdriver_bwrite(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict m_out)
|
|
{
|
|
|
|
if (fdp->fdr_bwrite == NULL)
|
|
return ENOSYS;
|
|
|
|
return bread_bwrite(fdp, m_in, m_out, FSC_WRITE);
|
|
}
|
|
|
|
/*
|
|
* Process a BPEEK request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_bpeek(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
dev_t dev;
|
|
off_t pos;
|
|
size_t nbytes;
|
|
ssize_t r;
|
|
|
|
dev = m_in->m_vfs_fs_breadwrite.device;
|
|
pos = m_in->m_vfs_fs_breadwrite.seek_pos;
|
|
nbytes = m_in->m_vfs_fs_breadwrite.nbytes;
|
|
|
|
if (fdp->fdr_bpeek == NULL)
|
|
return ENOSYS;
|
|
|
|
if (pos < 0 || nbytes > SSIZE_MAX)
|
|
return EINVAL;
|
|
|
|
r = fdp->fdr_bpeek(dev, NULL /*data*/, nbytes, pos, FSC_PEEK);
|
|
|
|
/* Do not return a new position. */
|
|
if (r >= 0) {
|
|
m_out->m_fs_vfs_breadwrite.nbytes = r;
|
|
r = OK;
|
|
}
|
|
|
|
return r;
|
|
}
|
|
|
|
/*
|
|
* Process a FLUSH request from VFS.
|
|
*/
|
|
int
|
|
fsdriver_flush(const struct fsdriver * __restrict fdp,
|
|
const message * __restrict m_in, message * __restrict __unused m_out)
|
|
{
|
|
dev_t dev;
|
|
|
|
dev = m_in->m_vfs_fs_flush.device;
|
|
|
|
if (fdp->fdr_bflush != NULL)
|
|
fdp->fdr_bflush(dev);
|
|
|
|
return OK;
|
|
}
|