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>
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>
-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>
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);
/*===========================================================================*
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 */
#define _SFFS_INC_H
#include <minix/drivers.h>
+#include <minix/fsdriver.h>
#include <minix/vfsif.h>
#include <minix/optset.h>
#include <minix/sffs.h>
/*===========================================================================*
* 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;
#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;
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)
}
/* 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
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;
}
/*===========================================================================*
* 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;
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)
/*===========================================================================*
* 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;
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)
/*===========================================================================*
* 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;
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)
/*===========================================================================*
* 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;
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)
#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 *
*===========================================================================*/
/*===========================================================================*
* 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;
-
- /* 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);
+ dprintf(("%s: lookup: got query for %"PRIu64", '%s'\n",
+ sffs_name, dir_nr, name));
- /* 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;
}
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;
/* 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;
-
- if (state.s_mounted) {
- dprintf(("%s: got SIGTERM, still mounted\n", sffs_name));
- } else {
- dprintf(("%s: got SIGTERM, shutting down\n", sffs_name));
+ dprintf(("%s: got SIGTERM\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();
}
/*===========================================================================*
*===========================================================================*/
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);
}
/*===========================================================================*
* 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;
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;
-
- return sys_safecopyto(m_in.m_source, m_in.m_vfs_fs_statvfs.grant, 0,
- (vir_bytes) &statvfs, sizeof(statvfs));
+ 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 OK;
}
/* 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:
#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.
*/
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();
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;
}
/*===========================================================================*
* 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;
}
if (sffs_params->p_case_insens) {
for (i = 0; i < size; i++)
- *dst++ = tolower(*src++);
+ *dst++ = tolower((int)*src++);
}
else memcpy(dst, src, size);
}
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);
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,
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 */
#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;
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. */
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;
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;
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;
}
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);
}
}
- /* 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);
}
/*===========================================================================*
* 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;
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.
*/
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)
/* 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;
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;
}
/*===========================================================================*
* do_utime *
*===========================================================================*/
-int do_utime(void)
+int do_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime)
{
/* Set file times.
*/
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)
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);
}
#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];
/* 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 */
+++ /dev/null
-/* 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;
-}
*
* 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)
#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. */
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. */
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)
/* Write zeroes to the file. We can't create holes. */
if (end <= start) return EINVAL;
- delta = end - start;
-
- if (ex64hi(delta) != 0) return EINVAL;
+ delta = (uint64_t)end - (uint64_t)start;
- count = ex64lo(delta);
+ if (delta > SSIZE_MAX) return EINVAL;
- r = write_file(ino, &start, &count, NULL);
+ if ((r = write_file(ino, start, (size_t)delta, NULL)) >= 0)
+ r = OK;
}
return r;