libsffs: use libfsdriver

Change-Id: Id8377873455771c614371e115643cd906d05f12c
This commit is contained in:
David van Moolenbroek 2014-08-24 09:47:41 +00:00
parent ebd3c0673d
commit a99c939dee
20 changed files with 224 additions and 750 deletions

View file

@ -2,7 +2,7 @@
PROG= hgfs
SRCS= hgfs.c
DPADD+= ${LIBSFFS} ${LIBHGFS} ${LIBSYS}
LDADD+= -lsffs -lhgfs -lsys
DPADD+= ${LIBSFFS} ${LIBHGFS} ${LIBFSDRIVER} ${LIBSYS}
LDADD+= -lsffs -lhgfs -lfsdriver -lsys
.include <minix.service.mk>

View file

@ -2,7 +2,7 @@
PROG= vbfs
SRCS= vbfs.c
DPADD+= ${LIBSFFS} ${LIBVBOXFS} ${LIBSYS}
LDADD+= -lsffs -lvboxfs -lsys
DPADD+= ${LIBSFFS} ${LIBVBOXFS} ${LIBFSDRIVER} ${LIBSYS}
LDADD+= -lsffs -lvboxfs -lfsdriver -lsys
.include <minix.service.mk>

View file

@ -1,13 +1,13 @@
NOGCCERROR=yes
NOCLANGERROR=yes
CPPFLAGS+= -D_MINIX_SYSTEM
# Makefile for libsffs
.include <bsd.own.mk>
NOGCCERROR=yes
CPPFLAGS+= -D_MINIX_SYSTEM
LIB= sffs
SRCS= dentry.c handle.c inode.c link.c lookup.c main.c misc.c mount.c \
name.c path.c read.c stat.c table.c util.c verify.c write.c
name.c path.c read.c stat.c table.c verify.c write.c
.include <bsd.lib.mk>

View file

@ -14,7 +14,6 @@
static LIST_HEAD(hash_head, inode) hash_table[NUM_HASH_SLOTS];
static void del_one_dentry(struct inode *ino);
static unsigned int hash_dentry(struct inode *parent, char *name);
/*===========================================================================*

View file

@ -10,10 +10,8 @@ EXTERN char *sffs_name; /* file server name */
EXTERN const struct sffs_table *sffs_table; /* call table */
EXTERN struct sffs_params *sffs_params; /* parameters */
EXTERN message m_in; /* request message */
EXTERN message m_out; /* reply message */
EXTERN struct state state; /* global state */
extern int(*call_vec[]) (void);
extern struct fsdriver sffs_dtable; /* driver table */
#endif /* _SFFS_GLO_H */

View file

@ -2,6 +2,7 @@
#define _SFFS_INC_H
#include <minix/drivers.h>
#include <minix/fsdriver.h>
#include <minix/vfsif.h>
#include <minix/optset.h>
#include <minix/sffs.h>

View file

@ -273,19 +273,16 @@ int have_used_inode(void)
/*===========================================================================*
* do_putnode *
*===========================================================================*/
int do_putnode(void)
int do_putnode(ino_t ino_nr, unsigned int count)
{
/* Decrease an inode's reference count.
*/
struct inode *ino;
int count;
if ((ino = find_inode(m_in.m_vfs_fs_putnode.inode)) == NULL)
if ((ino = find_inode(ino_nr)) == NULL)
return EINVAL;
count = m_in.m_vfs_fs_putnode.count;
if (count <= 0 || count > ino->i_ref) return EINVAL;
if (count > ino->i_ref) return EINVAL;
ino->i_ref -= count - 1;

View file

@ -15,16 +15,15 @@
#include <fcntl.h>
static int force_remove(char *path, int dir);
/*===========================================================================*
* do_create *
*===========================================================================*/
int do_create(void)
int do_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
struct fsdriver_node *node)
{
/* Create a new file.
*/
char path[PATH_MAX], name[NAME_MAX+1];
char path[PATH_MAX];
struct inode *parent, *ino;
struct sffs_attr attr;
sffs_file_t handle;
@ -34,13 +33,7 @@ int do_create(void)
if (state.s_read_only)
return EROFS;
/* Get path, name, parent inode and possibly inode for the given path. */
if ((r = get_name(m_in.m_vfs_fs_create.grant, m_in.m_vfs_fs_create.path_len, name)) != OK)
return r;
if (!strcmp(name, ".") || !strcmp(name, "..")) return EEXIST;
if ((parent = find_inode(m_in.m_vfs_fs_create.inode)) == NULL)
if ((parent = find_inode(dir_nr)) == NULL)
return EINVAL;
if ((r = verify_dentry(parent, name, path, &ino)) != OK)
@ -59,8 +52,7 @@ int do_create(void)
}
/* Perform the actual create call. */
r = sffs_table->t_open(path, O_CREAT | O_EXCL | O_RDWR, m_in.m_vfs_fs_create.mode,
&handle);
r = sffs_table->t_open(path, O_CREAT | O_EXCL | O_RDWR, mode, &handle);
if (r != OK) {
/* Let's not try to be too clever with error codes here. If something
@ -115,11 +107,12 @@ int do_create(void)
add_dentry(parent, name, ino);
m_out.m_fs_vfs_create.inode = INODE_NR(ino);
m_out.m_fs_vfs_create.mode = get_mode(ino, attr.a_mode);
m_out.m_fs_vfs_create.file_size = attr.a_size;
m_out.m_fs_vfs_create.uid = sffs_params->p_uid;
m_out.m_fs_vfs_create.gid = sffs_params->p_gid;
node->fn_ino_nr = INODE_NR(ino);
node->fn_mode = get_mode(ino, attr.a_mode);
node->fn_size = attr.a_size;
node->fn_uid = sffs_params->p_uid;
node->fn_gid = sffs_params->p_gid;
node->fn_dev = NO_DEV;
return OK;
}
@ -127,11 +120,11 @@ int do_create(void)
/*===========================================================================*
* do_mkdir *
*===========================================================================*/
int do_mkdir(void)
int do_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
{
/* Make a new directory.
*/
char path[PATH_MAX], name[NAME_MAX+1];
char path[PATH_MAX];
struct inode *parent, *ino;
int r;
@ -139,20 +132,14 @@ int do_mkdir(void)
if (state.s_read_only)
return EROFS;
/* Get the path string and possibly an inode for the given path. */
if ((r = get_name(m_in.m_vfs_fs_mkdir.grant, m_in.m_vfs_fs_mkdir.path_len, name)) != OK)
return r;
if (!strcmp(name, ".") || !strcmp(name, "..")) return EEXIST;
if ((parent = find_inode(m_in.m_vfs_fs_mkdir.inode)) == NULL)
if ((parent = find_inode(dir_nr)) == NULL)
return EINVAL;
if ((r = verify_dentry(parent, name, path, &ino)) != OK)
return r;
/* Perform the actual mkdir call. */
r = sffs_table->t_mkdir(path, m_in.m_vfs_fs_mkdir.mode);
r = sffs_table->t_mkdir(path, mode);
if (r != OK) {
if (ino != NULL)
@ -232,11 +219,11 @@ static int force_remove(
/*===========================================================================*
* do_unlink *
*===========================================================================*/
int do_unlink(void)
int do_unlink(ino_t dir_nr, char *name, int call)
{
/* Delete a file.
*/
char path[PATH_MAX], name[NAME_MAX+1];
char path[PATH_MAX];
struct inode *parent, *ino;
int r;
@ -244,13 +231,7 @@ int do_unlink(void)
if (state.s_read_only)
return EROFS;
/* Get the path string and possibly preexisting inode for the given path. */
if ((r = get_name(m_in.m_vfs_fs_unlink.grant, m_in.m_vfs_fs_unlink.path_len, name)) != OK)
return r;
if (!strcmp(name, ".") || !strcmp(name, "..")) return EPERM;
if ((parent = find_inode(m_in.m_vfs_fs_unlink.inode)) == NULL)
if ((parent = find_inode(dir_nr)) == NULL)
return EINVAL;
if ((r = verify_dentry(parent, name, path, &ino)) != OK)
@ -279,11 +260,11 @@ int do_unlink(void)
/*===========================================================================*
* do_rmdir *
*===========================================================================*/
int do_rmdir(void)
int do_rmdir(ino_t dir_nr, char *name, int call)
{
/* Remove an empty directory.
*/
char path[PATH_MAX], name[NAME_MAX+1];
char path[PATH_MAX];
struct inode *parent, *ino;
int r;
@ -291,14 +272,7 @@ int do_rmdir(void)
if (state.s_read_only)
return EROFS;
/* Get the path string and possibly preexisting inode for the given path. */
if ((r = get_name(m_in.m_vfs_fs_unlink.grant, m_in.m_vfs_fs_unlink.path_len, name)) != OK)
return r;
if (!strcmp(name, ".")) return EINVAL;
if (!strcmp(name, "..")) return ENOTEMPTY;
if ((parent = find_inode(m_in.m_vfs_fs_unlink.inode)) == NULL)
if ((parent = find_inode(dir_nr)) == NULL)
return EINVAL;
if ((r = verify_dentry(parent, name, path, &ino)) != OK)
@ -327,12 +301,12 @@ int do_rmdir(void)
/*===========================================================================*
* do_rename *
*===========================================================================*/
int do_rename(void)
int do_rename(ino_t old_dir_nr, char *old_name, ino_t new_dir_nr,
char *new_name)
{
/* Rename a file or directory.
*/
char old_path[PATH_MAX], new_path[PATH_MAX];
char old_name[NAME_MAX+1], new_name[NAME_MAX+1];
struct inode *old_parent, *new_parent;
struct inode *old_ino, *new_ino;
int r;
@ -341,20 +315,9 @@ int do_rename(void)
if (state.s_read_only)
return EROFS;
/* Get path strings, names, directory inodes and possibly preexisting inodes
* for the old and new paths.
*/
if ((r = get_name(m_in.m_vfs_fs_rename.grant_old, m_in.m_vfs_fs_rename.len_old,
old_name)) != OK) return r;
if ((r = get_name(m_in.m_vfs_fs_rename.grant_new, m_in.m_vfs_fs_rename.len_new,
new_name)) != OK) return r;
if (!strcmp(old_name, ".") || !strcmp(old_name, "..") ||
!strcmp(new_name, ".") || !strcmp(new_name, "..")) return EINVAL;
if ((old_parent = find_inode(m_in.m_vfs_fs_rename.dir_old)) == NULL ||
(new_parent = find_inode(m_in.m_vfs_fs_rename.dir_new)) == NULL)
/* Get possibly preexisting inodes for the old and new paths. */
if ((old_parent = find_inode(old_dir_nr)) == NULL ||
(new_parent = find_inode(new_dir_nr)) == NULL)
return EINVAL;
if ((r = verify_dentry(old_parent, old_name, old_path, &old_ino)) != OK)

View file

@ -9,103 +9,6 @@
#include "inc.h"
static int get_mask(vfs_ucred_t *ucred);
static int access_as_dir(struct inode *ino, struct sffs_attr *attr,
int uid, int mask);
static int next_name(char **ptr, char **start, char name[NAME_MAX+1]);
static int go_up(char path[PATH_MAX], struct inode *ino,
struct inode **res_ino, struct sffs_attr *attr);
static int go_down(char path[PATH_MAX], struct inode *ino, char *name,
struct inode **res_ino, struct sffs_attr *attr);
/*===========================================================================*
* get_mask *
*===========================================================================*/
static int get_mask(
vfs_ucred_t *ucred /* credentials of the caller */
)
{
/* Given the caller's credentials, precompute a search access mask to test
* against directory modes.
*/
int i;
if (ucred->vu_uid == sffs_params->p_uid) return S_IXUSR;
if (ucred->vu_gid == sffs_params->p_gid) return S_IXGRP;
for (i = 0; i < ucred->vu_ngroups; i++)
if (ucred->vu_sgroups[i] == sffs_params->p_gid) return S_IXGRP;
return S_IXOTH;
}
/*===========================================================================*
* access_as_dir *
*===========================================================================*/
static int access_as_dir(
struct inode *ino, /* the inode to test */
struct sffs_attr *attr, /* attributes of the inode */
int uid, /* UID of the caller */
int mask /* search access mask of the caller */
)
{
/* Check whether the given inode may be accessed as directory.
* Return OK or an appropriate error code.
*/
mode_t mode;
assert(attr->a_mask & SFFS_ATTR_MODE);
/* The inode must be a directory to begin with. */
if (!IS_DIR(ino)) return ENOTDIR;
/* The caller must have search access to the directory. Root always does. */
if (uid == 0) return OK;
mode = get_mode(ino, attr->a_mode);
return (mode & mask) ? OK : EACCES;
}
/*===========================================================================*
* next_name *
*===========================================================================*/
static int next_name(
char **ptr, /* cursor pointer into path (in, out) */
char **start, /* place to store start of name */
char name[NAME_MAX+1] /* place to store name */
)
{
/* Get the next path component from a path.
*/
char *p;
int i;
for (p = *ptr; *p == '/'; p++);
*start = p;
if (*p) {
for (i = 0; *p && *p != '/' && i <= NAME_MAX; p++, i++)
name[i] = *p;
if (i > NAME_MAX)
return ENAMETOOLONG;
name[i] = 0;
} else {
strcpy(name, ".");
}
*ptr = p;
return OK;
}
/*===========================================================================*
* go_up *
*===========================================================================*/
@ -199,142 +102,49 @@ static int go_down(
/*===========================================================================*
* do_lookup *
*===========================================================================*/
int do_lookup(void)
int do_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
int *is_mountpt)
{
/* Resolve a path string to an inode.
*/
ino_t dir_ino_nr, root_ino_nr;
struct inode *cur_ino, *root_ino;
struct inode *next_ino = NULL;
struct inode *dir_ino, *ino;
struct sffs_attr attr;
char buf[PATH_MAX], path[PATH_MAX];
char name[NAME_MAX+1];
char *ptr, *last;
vfs_ucred_t ucred;
mode_t mask;
size_t len;
char path[PATH_MAX];
int r;
dir_ino_nr = m_in.m_vfs_fs_lookup.dir_ino;
root_ino_nr = m_in.m_vfs_fs_lookup.root_ino;
len = m_in.m_vfs_fs_lookup.path_len;
dprintf(("%s: lookup: got query for %"PRIu64", '%s'\n",
sffs_name, dir_nr, name));
/* Fetch the path name. */
if (len < 1 || len > PATH_MAX)
return EINVAL;
r = sys_safecopyfrom(m_in.m_source, m_in.m_vfs_fs_lookup.grant_path, 0,
(vir_bytes) buf, len);
if (r != OK)
return r;
if (buf[len-1] != 0) {
printf("%s: VFS did not zero-terminate path!\n", sffs_name);
return EINVAL;
}
/* Fetch the credentials, and generate a search access mask to test against
* directory modes.
*/
if (m_in.m_vfs_fs_lookup.flags & PATH_GET_UCRED) {
if (m_in.m_vfs_fs_lookup.ucred_size != sizeof(ucred)) {
printf("%s: bad credential structure size\n", sffs_name);
return EINVAL;
}
r = sys_safecopyfrom(m_in.m_source, m_in.m_vfs_fs_lookup.grant_ucred, 0,
(vir_bytes) &ucred, m_in.m_vfs_fs_lookup.ucred_size);
if (r != OK)
return r;
}
else {
ucred.vu_uid = m_in.m_vfs_fs_lookup.uid;
ucred.vu_gid = m_in.m_vfs_fs_lookup.gid;
ucred.vu_ngroups = 0;
}
mask = get_mask(&ucred);
/* Start the actual lookup. */
dprintf(("%s: lookup: got query '%s'\n", sffs_name, buf));
if ((cur_ino = find_inode(dir_ino_nr)) == NULL)
if ((dir_ino = find_inode(dir_nr)) == NULL)
return EINVAL;
attr.a_mask = SFFS_ATTR_MODE | SFFS_ATTR_SIZE;
if ((r = verify_inode(cur_ino, path, &attr)) != OK)
if ((r = verify_inode(dir_ino, path, &attr)) != OK)
return r;
get_inode(cur_ino);
if (!IS_DIR(dir_ino))
return ENOTDIR;
if (root_ino_nr > 0)
root_ino = find_inode(root_ino_nr);
r = OK;
if (!strcmp(name, "."))
get_inode(ino = dir_ino);
else if (!strcmp(name, ".."))
r = go_up(path, dir_ino, &ino, &attr);
else
root_ino = NULL;
/* One possible optimization would be to check a path only right before the
* first ".." in a row, and at the very end (if still necessary). This would
* have consequences for inode validation, though.
*/
for (ptr = last = buf; *ptr != 0; ) {
if ((r = access_as_dir(cur_ino, &attr, ucred.vu_uid, mask)) != OK)
break;
if ((r = next_name(&ptr, &last, name)) != OK)
break;
dprintf(("%s: lookup: next name '%s'\n", sffs_name, name));
if (!strcmp(name, ".") ||
(cur_ino == root_ino && !strcmp(name, "..")))
continue;
if (!strcmp(name, "..")) {
if (IS_ROOT(cur_ino))
r = ELEAVEMOUNT;
else
r = go_up(path, cur_ino, &next_ino, &attr);
} else {
r = go_down(path, cur_ino, name, &next_ino, &attr);
}
if (r != OK)
break;
assert(next_ino != NULL);
put_inode(cur_ino);
cur_ino = next_ino;
}
dprintf(("%s: lookup: result %d\n", sffs_name, r));
if (r != OK) {
put_inode(cur_ino);
/* We'd need support for these here. We don't have such support. */
assert(r != EENTERMOUNT && r != ESYMLINK);
if (r == ELEAVEMOUNT) {
m_out.m_fs_vfs_lookup.offset = (last - buf);
m_out.m_fs_vfs_lookup.symloop = 0;
}
r = go_down(path, dir_ino, name, &ino, &attr);
if (r != OK)
return r;
}
m_out.m_fs_vfs_lookup.inode = INODE_NR(cur_ino);
m_out.m_fs_vfs_lookup.mode = get_mode(cur_ino, attr.a_mode);
m_out.m_fs_vfs_lookup.file_size = attr.a_size;
m_out.m_fs_vfs_lookup.uid = sffs_params->p_uid;
m_out.m_fs_vfs_lookup.gid = sffs_params->p_gid;
m_out.m_fs_vfs_lookup.device = NO_DEV;
node->fn_ino_nr = INODE_NR(ino);
node->fn_mode = get_mode(ino, attr.a_mode);
node->fn_size = attr.a_size;
node->fn_uid = sffs_params->p_uid;
node->fn_gid = sffs_params->p_gid;
node->fn_dev = NO_DEV;
*is_mountpt = FALSE;
return OK;
}

View file

@ -26,9 +26,6 @@ int sffs_init(char *name, const struct sffs_table *table,
while (i > 0 && params->p_prefix[i - 1] == '/') i--;
params->p_prefix[i] = 0;
state.s_mounted = FALSE;
state.s_signaled = FALSE;
sffs_name = name;
sffs_table = table;
sffs_params = params;
@ -45,62 +42,9 @@ void sffs_signal(int signo)
/* Only check for termination signal, ignore anything else. */
if (signo != SIGTERM) return;
/* We can now terminate if we have also been unmounted. */
state.s_signaled = TRUE;
dprintf(("%s: got SIGTERM\n", sffs_name));
if (state.s_mounted) {
dprintf(("%s: got SIGTERM, still mounted\n", sffs_name));
} else {
dprintf(("%s: got SIGTERM, shutting down\n", sffs_name));
/* Break out of the main loop, giving the main program the chance to
* perform further cleanup. This causes sef_receive() to return with
* an EINTR error code.
*/
sef_cancel();
}
}
/*===========================================================================*
* get_work *
*===========================================================================*/
static int get_work(endpoint_t *who_e)
{
/* Receive a request message from VFS. Return TRUE if a new message is ready
* to be processed, or FALSE if sef_stop() was called from the signal handler.
*/
int r;
if ((r = sef_receive(ANY, &m_in)) != OK) {
if (r != EINTR)
panic("receive failed: %d", r);
return FALSE;
}
*who_e = m_in.m_source;
return TRUE;
}
/*===========================================================================*
* send_reply *
*===========================================================================*/
static void send_reply(
int err, /* resulting error code */
int transid
)
{
/* Send a reply message to the requesting party, with the given error code.
*/
int r;
m_out.m_type = err;
if (IS_VFS_FS_TRANSID(transid)) {
/* If a transaction ID was set, reset it */
m_out.m_type = TRNS_ADD_ID(m_out.m_type, transid);
}
if ((r = ipc_send(m_in.m_source, &m_out)) != OK)
printf("%s: ipc_send failed (%d)\n", sffs_name, r);
fsdriver_terminate();
}
/*===========================================================================*
@ -108,47 +52,8 @@ static void send_reply(
*===========================================================================*/
void sffs_loop(void)
{
/* The main function of this file server. After initializing, loop, receiving
* one request from VFS at a time, processing it, and sending a reply back to
* VFS. Termination occurs when we both have been unmounted and have received
* a termination signal.
/* The main function of this file server. Libfsdriver does the real work.
*/
endpoint_t who_e;
int call_nr, err, transid;
while (state.s_mounted || !state.s_signaled) {
if (!get_work(&who_e))
continue; /* Recheck running conditions */
transid = TRNS_GET_ID(m_in.m_type);
m_in.m_type = TRNS_DEL_ID(m_in.m_type);
if (m_in.m_type == 0) {
assert(!IS_VFS_FS_TRANSID(transid));
m_in.m_type = transid; /* Backwards compat. */
transid = 0;
} else
assert(IS_VFS_FS_TRANSID(transid));
call_nr = m_in.m_type;
if (who_e != VFS_PROC_NR) {
continue;
}
if (state.s_mounted || call_nr == REQ_READSUPER) {
call_nr -= FS_BASE;
dprintf(("%s: call %d\n", sffs_name, call_nr));
if (call_nr >= 0 && call_nr < NREQS) {
err = (*call_vec[call_nr])();
} else {
err = ENOSYS;
}
dprintf(("%s: call %d result %d\n", sffs_name, call_nr, err));
}
else err = EINVAL;
send_reply(err, transid);
}
fsdriver_task(&sffs_dtable);
}

View file

@ -14,11 +14,10 @@
/*===========================================================================*
* do_statvfs *
*===========================================================================*/
int do_statvfs(void)
int do_statvfs(struct statvfs *statvfs)
{
/* Retrieve file system statistics.
*/
struct statvfs statvfs;
struct inode *ino;
char path[PATH_MAX];
u64_t free, total;
@ -38,20 +37,17 @@ int do_statvfs(void)
if ((r = sffs_table->t_queryvol(path, &free, &total)) != OK)
return r;
memset(&statvfs, 0, sizeof(statvfs));
/* Returning zero for unknown values seems to be the convention. However, we
* do have to use a nonzero block size, even though it is entirely arbitrary.
*/
statvfs.f_flag = ST_NOTRUNC;
statvfs.f_bsize = BLOCK_SIZE;
statvfs.f_frsize = BLOCK_SIZE;
statvfs.f_iosize = BLOCK_SIZE;
statvfs.f_blocks = (unsigned long)(total / BLOCK_SIZE);
statvfs.f_bfree = (unsigned long)(free / BLOCK_SIZE);
statvfs.f_bavail = statvfs.f_bfree;
statvfs.f_namemax = NAME_MAX;
statvfs->f_flag = ST_NOTRUNC;
statvfs->f_bsize = BLOCK_SIZE;
statvfs->f_frsize = BLOCK_SIZE;
statvfs->f_iosize = BLOCK_SIZE;
statvfs->f_blocks = (fsblkcnt_t)(total / BLOCK_SIZE);
statvfs->f_bfree = (fsblkcnt_t)(free / BLOCK_SIZE);
statvfs->f_bavail = statvfs->f_bfree;
statvfs->f_namemax = NAME_MAX;
return sys_safecopyto(m_in.m_source, m_in.m_vfs_fs_statvfs.grant, 0,
(vir_bytes) &statvfs, sizeof(statvfs));
return OK;
}

View file

@ -1,7 +1,7 @@
/* This file contains mount and unmount functionality.
*
* The entry points into this file are:
* do_readsuper perform the READSUPER file system call
* do_mount perform the READSUPER file system call
* do_unmount perform the UNMOUNT file system call
*
* Created:
@ -11,9 +11,10 @@
#include "inc.h"
/*===========================================================================*
* do_readsuper *
* do_mount *
*===========================================================================*/
int do_readsuper(void)
int do_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
unsigned int *res_flags)
{
/* Mount the file system.
*/
@ -22,17 +23,16 @@ int do_readsuper(void)
struct sffs_attr attr;
int r;
dprintf(("%s: readsuper (dev %x, flags %x)\n",
sffs_name, m_in.m_vfs_fs_readsuper.device, m_in.vfs_fs_readsuper.flags));
dprintf(("%s: mount (dev %"PRIx64", flags %x)\n", sffs_name, dev, flags));
if (m_in.m_vfs_fs_readsuper.flags & REQ_ISROOT) {
if (flags & REQ_ISROOT) {
printf("%s: attempt to mount as root device\n", sffs_name);
return EINVAL;
}
state.s_read_only = !!(m_in.m_vfs_fs_readsuper.flags & REQ_RDONLY);
state.s_dev = m_in.m_vfs_fs_readsuper.device;
state.s_read_only = !!(flags & REQ_RDONLY);
state.s_dev = dev;
init_dentry();
ino = init_inode();
@ -55,15 +55,14 @@ int do_readsuper(void)
return r;
}
m_out.m_fs_vfs_readsuper.inode = INODE_NR(ino);
m_out.m_fs_vfs_readsuper.mode = get_mode(ino, attr.a_mode);
m_out.m_fs_vfs_readsuper.file_size = attr.a_size;
m_out.m_fs_vfs_readsuper.uid = sffs_params->p_uid;
m_out.m_fs_vfs_readsuper.gid = sffs_params->p_gid;
m_out.m_fs_vfs_readsuper.device = NO_DEV;
m_out.m_fs_vfs_readsuper.flags = RES_64BIT;
root_node->fn_ino_nr = INODE_NR(ino);
root_node->fn_mode = get_mode(ino, attr.a_mode);
root_node->fn_size = attr.a_size;
root_node->fn_uid = sffs_params->p_uid;
root_node->fn_gid = sffs_params->p_gid;
root_node->fn_dev = NO_DEV;
state.s_mounted = TRUE;
*res_flags = RES_64BIT;
return OK;
}
@ -71,25 +70,21 @@ int do_readsuper(void)
/*===========================================================================*
* do_unmount *
*===========================================================================*/
int do_unmount(void)
void do_unmount(void)
{
/* Unmount the file system.
*/
struct inode *ino;
dprintf(("%s: do_unmount\n", sffs_name));
dprintf(("%s: unmount\n", sffs_name));
/* Decrease the reference count of the root inode. */
if ((ino = find_inode(ROOT_INODE_NR)) == NULL)
return EINVAL;
return;
put_inode(ino);
/* There should not be any referenced inodes anymore now. */
if (have_used_inode())
printf("%s: in-use inodes left at unmount time!\n", sffs_name);
state.s_mounted = FALSE;
return OK;
}

View file

@ -28,7 +28,7 @@ void normalize_name(char dst[NAME_MAX+1], char *src)
if (sffs_params->p_case_insens) {
for (i = 0; i < size; i++)
*dst++ = tolower(*src++);
*dst++ = tolower((int)*src++);
}
else memcpy(dst, src, size);
}

View file

@ -21,27 +21,31 @@ void unlink_inode(struct inode *ino);
struct inode *get_free_inode(void);
int have_free_inode(void);
int have_used_inode(void);
int do_putnode(void);
int do_putnode(ino_t ino_nr, unsigned int count);
/* link.c */
int do_create(void);
int do_mkdir(void);
int do_unlink(void);
int do_rmdir(void);
int do_rename(void);
int do_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
struct fsdriver_node *node);
int do_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid);
int do_unlink(ino_t dir_nr, char *name, int call);
int do_rmdir(ino_t dir_nr, char *name, int call);
int do_rename(ino_t old_dir_nr, char *old_name, ino_t new_dir_nr,
char *new_name);
/* lookup.c */
int do_lookup(void);
int do_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
int *is_mountpt);
/* main.c */
int main(int argc, char *argv[]);
/* misc.c */
int do_statvfs(void);
int do_statvfs(struct statvfs *statvfs);
/* mount.c */
int do_readsuper(void);
int do_unmount(void);
int do_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
unsigned int *res_flags);
void do_unmount(void);
/* name.c */
void normalize_name(char dst[NAME_MAX+1], char *src);
@ -53,19 +57,16 @@ int push_path(char path[PATH_MAX], char *name);
void pop_path(char path[PATH_MAX]);
/* read.c */
int do_read(void);
int do_getdents(void);
ssize_t do_read(ino_t ino_nr, struct fsdriver_data *data, size_t count,
off_t pos, int call);
ssize_t do_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
off_t *pos);
/* stat.c */
mode_t get_mode(struct inode *ino, int mode);
int do_stat(void);
int do_chmod(void);
int do_utime(void);
/* util.c */
int get_name(cp_grant_id_t grant, size_t len, char name[NAME_MAX+1]);
int do_noop(void);
int no_sys(void);
int do_stat(ino_t ino_nr, struct stat *stat);
int do_chmod(ino_t ino_nr, mode_t *mode);
int do_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime);
/* verify.c */
int verify_path(char *path, struct inode *ino, struct sffs_attr *attr,
@ -76,7 +77,8 @@ int verify_dentry(struct inode *parent, char name[NAME_MAX+1],
char path[PATH_MAX], struct inode **res_ino);
/* write.c */
int do_write(void);
int do_ftrunc(void);
ssize_t do_write(ino_t ino_nr, struct fsdriver_data *data, size_t count,
off_t pos, int call);
int do_trunc(ino_t ino_nr, off_t start, off_t end);
#endif /* _SFFS_PROTO_H */

View file

@ -12,23 +12,20 @@
#include <dirent.h>
#define DWORD_ALIGN(len) (((len) + sizeof(long) - 1) & ~(sizeof(long) - 1))
/*===========================================================================*
* do_read *
*===========================================================================*/
int do_read(void)
ssize_t do_read(ino_t ino_nr, struct fsdriver_data *data, size_t count,
off_t pos, int call)
{
/* Read data from a file.
*/
struct inode *ino;
off_t pos;
size_t count, size;
vir_bytes off;
size_t size, off;
char *ptr;
int r, chunk;
if ((ino = find_inode(m_in.m_vfs_fs_readwrite.inode)) == NULL)
if ((ino = find_inode(ino_nr)) == NULL)
return EINVAL;
if (IS_DIR(ino)) return EISDIR;
@ -36,9 +33,6 @@ int do_read(void)
if ((r = get_handle(ino)) != OK)
return r;
pos = m_in.m_vfs_fs_readwrite.seek_pos;
count = m_in.m_vfs_fs_readwrite.nbytes;
assert(count > 0);
/* Use the buffer from below to eliminate extra copying. */
@ -53,10 +47,7 @@ int do_read(void)
chunk = r;
r = sys_safecopyto(m_in.m_source, m_in.m_vfs_fs_readwrite.grant, off,
(vir_bytes) ptr, chunk);
if (r != OK)
if ((r = fsdriver_copyout(data, off, ptr, chunk)) != OK)
break;
count -= chunk;
@ -67,38 +58,33 @@ int do_read(void)
if (r < 0)
return r;
m_out.m_fs_vfs_readwrite.seek_pos = pos;
m_out.m_fs_vfs_readwrite.nbytes = off;
return OK;
return off;
}
/*===========================================================================*
* do_getdents *
*===========================================================================*/
int do_getdents(void)
ssize_t do_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
off_t *posp)
{
/* Retrieve directory entries.
*/
struct fsdriver_dentry fsdentry;
char name[NAME_MAX+1];
struct inode *ino, *child;
struct dirent *dent;
struct sffs_attr attr;
size_t len, off, user_off, user_left;
off_t pos;
int r, namelen;
int r;
/* must be at least sizeof(struct dirent) + NAME_MAX */
static char buf[BLOCK_SIZE];
attr.a_mask = SFFS_ATTR_MODE;
if ((ino = find_inode(m_in.m_vfs_fs_getdents.inode)) == NULL)
if ((ino = find_inode(ino_nr)) == NULL)
return EINVAL;
if(m_in.m_vfs_fs_getdents.seek_pos >= ULONG_MAX) return EINVAL;
if (!IS_DIR(ino)) return ENOTDIR;
if (*posp < 0 || *posp >= ULONG_MAX) return EINVAL;
/* We are going to need at least one free inode to store children in. */
if (!have_free_inode()) return ENFILE;
@ -106,19 +92,19 @@ int do_getdents(void)
if ((r = get_handle(ino)) != OK)
return r;
off = 0;
user_off = 0;
user_left = m_in.m_vfs_fs_getdents.mem_size;
fsdriver_dentry_init(&fsdentry, data, bytes, buf, sizeof(buf));
/* We use the seek position as file index number. The first position is for
* the "." entry, the second position is for the ".." entry, and the next
* position numbers each represent a file in the directory.
*/
for (pos = m_in.m_vfs_fs_getdents.seek_pos; ; pos++) {
do {
/* Determine which inode and name to use for this entry.
* We have no idea whether the host will give us "." and/or "..",
* so generate our own and skip those from the host.
*/
pos = (*posp)++;
if (pos == 0) {
/* Entry for ".". */
child = ino;
@ -140,6 +126,8 @@ int do_getdents(void)
}
else {
/* Any other entry, not being "." or "..". */
attr.a_mask = SFFS_ATTR_MODE;
r = sffs_table->t_readdir(ino->i_dir, pos - 2, name,
sizeof(name), &attr);
@ -170,66 +158,14 @@ int do_getdents(void)
}
}
/* record length incl. alignment. */
namelen = strlen(name);
len = _DIRENT_RECLEN(dent, namelen);
/* Is the user buffer too small to store another record?
* Note that we will be rerequesting the same dentry upon a subsequent
* getdents call this way, but we really need the name length for this.
*/
if (user_off + off + len > user_left) {
put_inode(child);
/* Is the user buffer too small for even a single record? */
if (user_off == 0 && off == 0)
return EINVAL;
break;
}
/* If our own buffer cannot contain the new record, copy out first. */
if (off + len > sizeof(buf)) {
r = sys_safecopyto(m_in.m_source, m_in.m_vfs_fs_getdents.grant,
user_off, (vir_bytes) buf, off);
if (r != OK) {
put_inode(child);
return r;
}
user_off += off;
user_left -= off;
off = 0;
}
/* Fill in the actual directory entry. */
dent = (struct dirent *) &buf[off];
dent->d_ino = INODE_NR(child);
dent->d_reclen = len;
dent->d_namlen = namelen;
dent->d_type = IS_DIR(child) ? DT_DIR : DT_REG;
strcpy(dent->d_name, name);
off += len;
r = fsdriver_dentry_add(&fsdentry, INODE_NR(child), name, strlen(name),
IS_DIR(child) ? DT_DIR : DT_REG);
put_inode(child);
}
/* If there is anything left in our own buffer, copy that out now. */
if (off > 0) {
r = sys_safecopyto(m_in.m_source, m_in.m_vfs_fs_getdents.grant, user_off,
(vir_bytes) buf, off);
if (r != OK)
if (r < 0)
return r;
} while (r > 0);
user_off += off;
}
m_out.m_fs_vfs_getdents.seek_pos = pos;
m_out.m_fs_vfs_getdents.nbytes = user_off;
return OK;
return fsdriver_dentry_finish(&fsdentry);
}

View file

@ -37,19 +37,15 @@ mode_t get_mode(struct inode *ino, int mode)
/*===========================================================================*
* do_stat *
*===========================================================================*/
int do_stat(void)
int do_stat(ino_t ino_nr, struct stat *stat)
{
/* Retrieve inode status.
*/
struct inode *ino;
struct sffs_attr attr;
struct stat stat;
char path[PATH_MAX];
ino_t ino_nr;
int r;
ino_nr = m_in.m_vfs_fs_stat.inode;
/* Don't increase the inode refcount: it's already open anyway */
if ((ino = find_inode(ino_nr)) == NULL)
return EINVAL;
@ -60,45 +56,42 @@ int do_stat(void)
if ((r = verify_inode(ino, path, &attr)) != OK)
return r;
memset(&stat, 0, sizeof(struct stat));
stat->st_dev = state.s_dev;
stat->st_ino = ino_nr;
stat->st_mode = get_mode(ino, attr.a_mode);
stat->st_uid = sffs_params->p_uid;
stat->st_gid = sffs_params->p_gid;
stat->st_rdev = NO_DEV;
stat->st_size = attr.a_size;
stat->st_atimespec = attr.a_atime;
stat->st_mtimespec = attr.a_mtime;
stat->st_ctimespec = attr.a_ctime;
stat->st_birthtimespec = attr.a_crtime;
stat.st_dev = state.s_dev;
stat.st_ino = ino_nr;
stat.st_mode = get_mode(ino, attr.a_mode);
stat.st_uid = sffs_params->p_uid;
stat.st_gid = sffs_params->p_gid;
stat.st_rdev = NO_DEV;
stat.st_size = attr.a_size;
stat.st_atimespec = attr.a_atime;
stat.st_mtimespec = attr.a_mtime;
stat.st_ctimespec = attr.a_ctime;
stat.st_birthtimespec = attr.a_crtime;
stat->st_blocks = stat->st_size / S_BLKSIZE;
if (stat->st_size % S_BLKSIZE != 0)
stat->st_blocks += 1;
stat.st_blocks = stat.st_size / S_BLKSIZE;
if (stat.st_size % S_BLKSIZE != 0)
stat.st_blocks += 1;
stat.st_blksize = BLOCK_SIZE;
stat->st_blksize = BLOCK_SIZE;
/* We could make this more accurate by iterating over directory inodes'
* children, counting how many of those are directories as well.
* It's just not worth it.
*/
stat.st_nlink = 0;
if (ino->i_parent != NULL) stat.st_nlink++;
stat->st_nlink = 0;
if (ino->i_parent != NULL) stat->st_nlink++;
if (IS_DIR(ino)) {
stat.st_nlink++;
if (HAS_CHILDREN(ino)) stat.st_nlink++;
stat->st_nlink++;
if (HAS_CHILDREN(ino)) stat->st_nlink++;
}
return sys_safecopyto(m_in.m_source, m_in.m_vfs_fs_stat.grant, 0,
(vir_bytes) &stat, sizeof(stat));
return OK;
}
/*===========================================================================*
* do_chmod *
*===========================================================================*/
int do_chmod(void)
int do_chmod(ino_t ino_nr, mode_t *mode)
{
/* Change file mode.
*/
@ -110,7 +103,7 @@ int do_chmod(void)
if (state.s_read_only)
return EROFS;
if ((ino = find_inode(m_in.m_vfs_fs_chmod.inode)) == NULL)
if ((ino = find_inode(ino_nr)) == NULL)
return EINVAL;
if ((r = verify_inode(ino, path, NULL)) != OK)
@ -118,7 +111,7 @@ int do_chmod(void)
/* Set the new file mode. */
attr.a_mask = SFFS_ATTR_MODE;
attr.a_mode = m_in.m_vfs_fs_chmod.mode; /* no need to convert in this direction */
attr.a_mode = *mode; /* no need to convert in this direction */
if ((r = sffs_table->t_setattr(path, &attr)) != OK)
return r;
@ -127,7 +120,7 @@ int do_chmod(void)
if ((r = verify_path(path, ino, &attr, NULL)) != OK)
return r;
m_out.m_fs_vfs_chmod.mode = get_mode(ino, attr.a_mode);
*mode = get_mode(ino, attr.a_mode);
return OK;
}
@ -135,7 +128,7 @@ int do_chmod(void)
/*===========================================================================*
* do_utime *
*===========================================================================*/
int do_utime(void)
int do_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime)
{
/* Set file times.
*/
@ -147,7 +140,7 @@ int do_utime(void)
if (state.s_read_only)
return EROFS;
if ((ino = find_inode(m_in.m_vfs_fs_utime.inode)) == NULL)
if ((ino = find_inode(ino_nr)) == NULL)
return EINVAL;
if ((r = verify_inode(ino, path, NULL)) != OK)
@ -155,37 +148,31 @@ int do_utime(void)
attr.a_mask = 0;
switch(m_in.m_vfs_fs_utime.acnsec) {
switch (atime->tv_nsec) {
case UTIME_OMIT: /* do not touch */
break;
case UTIME_NOW:
/* XXX VFS should have time() into ACTIME, for compat; we trust it! */
m_in.m_vfs_fs_utime.acnsec = 0;
atime->tv_nsec = 0;
/*FALLTHROUGH*/
default:
/* cases m_in.m_vfs_fs_utime.acnsec < 0 || m_in.m_vfs_fs_utime.acnsec >= 1E9
* are caught by VFS to cooperate with old instances of EXT2
*/
attr.a_atime.tv_sec = m_in.m_vfs_fs_utime.actime;
attr.a_atime.tv_nsec = m_in.m_vfs_fs_utime.acnsec;
attr.a_atime = *atime;
attr.a_mask |= SFFS_ATTR_ATIME;
break;
}
switch(m_in.m_vfs_fs_utime.modnsec) {
switch (mtime->tv_nsec) {
case UTIME_OMIT: /* do not touch */
break;
case UTIME_NOW:
/* XXX VFS should have time() into MODTIME, for compat; we trust it! */
m_in.m_vfs_fs_utime.modnsec = 0;
mtime->tv_nsec = 0;
/*FALLTHROUGH*/
default:
/* cases m_in.m_vfs_fs_utime.modnsec < 0 || m_in.m_vfs_fs_utime.modnsec >= 1E9
* are caught by VFS to cooperate with old instances
*/
attr.a_mtime.tv_sec = m_in.m_vfs_fs_utime.modtime;
attr.a_mtime.tv_nsec = m_in.m_vfs_fs_utime.modnsec;
attr.a_mtime = *mtime;
attr.a_mask |= SFFS_ATTR_MTIME;
break;
}
return sffs_table->t_setattr(path, &attr);
}

View file

@ -7,42 +7,22 @@
#define _TABLE
#include "inc.h"
int (*call_vec[])(void) = {
no_sys, /* 0 */
no_sys, /* 1 getnode */
do_putnode, /* 2 putnode */
no_sys, /* 3 slink */
do_ftrunc, /* 4 ftrunc */
no_sys, /* 5 chown */
do_chmod, /* 6 chmod */
do_noop, /* 7 inhibread */
do_stat, /* 8 stat */
do_utime, /* 9 utime */
do_statvfs, /* 10 statvfs */
no_sys, /* 11 bread */
no_sys, /* 12 bwrite */
do_unlink, /* 13 unlink */
do_rmdir, /* 14 rmdir */
do_unmount, /* 15 unmount */
do_noop, /* 16 sync */
do_noop, /* 17 new_driver */
do_noop, /* 18 flush */
do_read, /* 19 read */
do_write, /* 20 write */
no_sys, /* 21 mknod */
do_mkdir, /* 22 mkdir */
do_create, /* 23 create */
no_sys, /* 24 link */
do_rename, /* 25 rename */
do_lookup, /* 26 lookup */
no_sys, /* 27 mountpoint */
do_readsuper, /* 28 readsuper */
no_sys, /* 29 newnode */
no_sys, /* 30 rdlink */
do_getdents, /* 31 getdents */
no_sys, /* 32 peek */
no_sys, /* 33 bpeek */
struct fsdriver sffs_dtable = {
.fdr_mount = do_mount,
.fdr_unmount = do_unmount,
.fdr_lookup = do_lookup,
.fdr_putnode = do_putnode,
.fdr_read = do_read,
.fdr_write = do_write,
.fdr_getdents = do_getdents,
.fdr_trunc = do_trunc,
.fdr_create = do_create,
.fdr_mkdir = do_mkdir,
.fdr_unlink = do_unlink,
.fdr_rmdir = do_rmdir,
.fdr_rename = do_rename,
.fdr_stat = do_stat,
.fdr_chmod = do_chmod,
.fdr_utime = do_utime,
.fdr_statvfs = do_statvfs
};
/* This should not fail with "array size is negative": */
extern int dummy[sizeof(call_vec) == NREQS * sizeof(call_vec[0]) ? 1 : -1];

View file

@ -3,8 +3,6 @@
/* Structure with global file system state. */
struct state {
int s_mounted; /* is the file system mounted? */
int s_signaled; /* have we received a SIGTERM? */
int s_read_only; /* is the file system mounted read-only? note,
* has no relation to the shared folder mode */
dev_t s_dev; /* device the file system is mounted on */

View file

@ -1,64 +0,0 @@
/* This file contains various utility functions.
*
* The entry points into this file are:
* get_name retrieve a path component string from VFS
* do_noop handle file system calls that do nothing and succeed
* no_sys handle file system calls that are not implemented
*
* Created:
* April 2009 (D.C. van Moolenbroek)
*/
#include "inc.h"
/*===========================================================================*
* get_name *
*===========================================================================*/
int get_name(
cp_grant_id_t grant, /* memory grant for the path component */
size_t len, /* length of the name, including '\0' */
char name[NAME_MAX+1] /* buffer in which store the result */
)
{
/* Retrieve a path component from the caller, using a given grant.
*/
int r;
/* Copy in the name of the directory entry. */
if (len <= 1) return EINVAL;
if (len > NAME_MAX+1) return ENAMETOOLONG;
r = sys_safecopyfrom(m_in.m_source, grant, 0, (vir_bytes) name, len);
if (r != OK) return r;
if (name[len-1] != 0) {
printf("%s: VFS did not zero-terminate path component!\n", sffs_name);
return EINVAL;
}
return OK;
}
/*===========================================================================*
* do_noop *
*===========================================================================*/
int do_noop(void)
{
/* Generic handler for no-op system calls.
*/
return OK;
}
/*===========================================================================*
* no_sys *
*===========================================================================*/
int no_sys(void)
{
/* Generic handler for unimplemented system calls.
*/
return ENOSYS;
}

View file

@ -2,7 +2,7 @@
*
* The entry points into this file are:
* do_write perform the WRITE file system call
* do_ftrunc perform the FTRUNC file system call
* do_trunc perform the TRUNC file system call
*
* Created:
* April 2009 (D.C. van Moolenbroek)
@ -10,32 +10,27 @@
#include "inc.h"
static int write_file(struct inode *ino, u64_t *posp, size_t *countp,
cp_grant_id_t *grantp);
/*===========================================================================*
* write_file *
*===========================================================================*/
static int write_file(struct inode *ino, u64_t *posp, size_t *countp,
cp_grant_id_t *grantp)
static ssize_t write_file(struct inode *ino, off_t pos, size_t count,
struct fsdriver_data *data)
{
/* Write data or zeroes to a file, depending on whether a valid pointer to
* a data grant was provided.
*/
u64_t pos;
size_t count, size;
vir_bytes off;
size_t size, off, chunk;
char *ptr;
int r, chunk;
int r;
if (pos < 0)
return EINVAL;
assert(!IS_DIR(ino));
if ((r = get_handle(ino)) != OK)
return r;
pos = *posp;
count = *countp;
assert(count > 0);
/* Use the buffer from below to eliminate extra copying. */
@ -45,11 +40,8 @@ static int write_file(struct inode *ino, u64_t *posp, size_t *countp,
while (count > 0) {
chunk = MIN(count, size);
if (grantp != NULL) {
r = sys_safecopyfrom(m_in.m_source, *grantp,
off, (vir_bytes) ptr, chunk);
if (r != OK)
if (data != NULL) {
if ((r = fsdriver_copyin(data, off, ptr, chunk)) != OK)
break;
} else {
/* Do this every time. We don't know what happens below. */
@ -67,73 +59,53 @@ static int write_file(struct inode *ino, u64_t *posp, size_t *countp,
if (r < 0)
return r;
*posp = pos;
*countp = off;
return OK;
return off;
}
/*===========================================================================*
* do_write *
*===========================================================================*/
int do_write(void)
ssize_t do_write(ino_t ino_nr, struct fsdriver_data *data, size_t count,
off_t pos, int call)
{
/* Write data to a file.
*/
struct inode *ino;
off_t pos;
size_t count;
cp_grant_id_t grant;
int r;
if (state.s_read_only)
return EROFS;
if ((ino = find_inode(m_in.m_vfs_fs_readwrite.inode)) == NULL)
if ((ino = find_inode(ino_nr)) == NULL)
return EINVAL;
if (IS_DIR(ino)) return EISDIR;
pos = m_in.m_vfs_fs_readwrite.seek_pos;
count = m_in.m_vfs_fs_readwrite.nbytes;
grant = m_in.m_vfs_fs_readwrite.grant;
if (count == 0) return 0;
if (count == 0) return EINVAL;
if ((r = write_file(ino, &pos, &count, &grant)) != OK)
return r;
m_out.m_fs_vfs_readwrite.seek_pos = pos;
m_out.m_fs_vfs_readwrite.nbytes = count;
return OK;
return write_file(ino, pos, count, data);
}
/*===========================================================================*
* do_ftrunc *
* do_trunc *
*===========================================================================*/
int do_ftrunc(void)
int do_trunc(ino_t ino_nr, off_t start, off_t end)
{
/* Change file size or create file holes.
*/
char path[PATH_MAX];
struct inode *ino;
struct sffs_attr attr;
u64_t start, end, delta;
size_t count;
int r;
uint64_t delta;
ssize_t r;
if (state.s_read_only)
return EROFS;
if ((ino = find_inode(m_in.m_vfs_fs_ftrunc.inode)) == NULL)
if ((ino = find_inode(ino_nr)) == NULL)
return EINVAL;
if (IS_DIR(ino)) return EISDIR;
start = m_in.m_vfs_fs_ftrunc.trc_start;
end = m_in.m_vfs_fs_ftrunc.trc_end;
if (end == 0) {
/* Truncate or expand the file. */
if ((r = verify_inode(ino, path, NULL)) != OK)
@ -147,13 +119,12 @@ int do_ftrunc(void)
/* Write zeroes to the file. We can't create holes. */
if (end <= start) return EINVAL;
delta = end - start;
delta = (uint64_t)end - (uint64_t)start;
if (ex64hi(delta) != 0) return EINVAL;
if (delta > SSIZE_MAX) return EINVAL;
count = ex64lo(delta);
r = write_file(ino, &start, &count, NULL);
if ((r = write_file(ino, start, (size_t)delta, NULL)) >= 0)
r = OK;
}
return r;