CPPFLAGS+= -D_MINIX_SYSTEM
NOGCCERROR=yes
-NOCLANGERROR=yes
.endif # defined(__MINIX)
.include <bsd.lib.mk>
#include <sys/types.h>
#include <minix/const.h>
#include <minix/type.h>
-#include <minix/dmap.h>
#include <lib.h>
#include <limits.h>
#include <minix/syslib.h>
#include <minix/sysutil.h>
+#include <minix/fsdriver.h>
+
#include "proto.h"
#include "glo.h"
#define EXTERN
#endif
-#include <minix/vfsif.h>
-
#include <fs/puffs/puffs_msgif.h>
EXTERN struct puffs_usermount *global_pu;
EXTERN int is_readonly_fs;
-EXTERN int is_root_fs;
EXTERN int buildpath;
/* Sometimes user can call exit. If we received a message,
* report a failure to VFS before exiting. Especially on mount
* and unmount.
- *
- * Either transid of last request or 0.
*/
-EXTERN int last_request_transid;
/* The following variables are used for returning results to the caller. */
EXTERN int err_code; /* temporary storage for error number */
-/* TODO: it duplicates caller_uid and caller_gid */
EXTERN struct puffs_kcred global_kcred;
-extern int(*fs_call_vec[]) (void);
-
-EXTERN message fs_m_in;
-EXTERN message fs_m_out;
-EXTERN vfs_ucred_t credentials;
-
-EXTERN uid_t caller_uid;
-EXTERN gid_t caller_gid;
-
-EXTERN int req_nr;
-
-EXTERN char user_path[PATH_MAX+1]; /* pathname to be processed */
-
EXTERN dev_t fs_dev; /* The device that is handled by this FS proc
*/
EXTERN char fs_name[PATH_MAX+1];
-EXTERN int unmountdone;
+EXTERN int mounted;
EXTERN int exitsignaled;
+extern struct fsdriver puffs_table;
+
#endif /* LIBPUFFS_GLO_H */
#include "fs.h"
#include <string.h>
#include <assert.h>
-#include <minix/vfsif.h>
#include "puffs.h"
#include "puffs_priv.h"
/*===========================================================================*
* fs_putnode *
*===========================================================================*/
-int fs_putnode(void)
+int fs_putnode(ino_t ino_nr, unsigned int count)
{
/* Find the pnode specified by the request message and decrease its counter.
* Release unused pnode.
*/
struct puffs_node *pn;
- int count = fs_m_in.m_vfs_fs_putnode.count;
- ino_t inum = fs_m_in.m_vfs_fs_putnode.inode;
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &inum)) == NULL) {
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) {
/* XXX Probably removed from the list, see puffs_pn_remove() */
struct puffs_node *pn_cur, *pn_next;
pn_cur = LIST_FIRST(&global_pu->pu_pnode_removed_lst);
while (pn_cur) {
pn_next = LIST_NEXT(pn_cur, pn_entries);
- if (pn_cur->pn_va.va_fileid == inum) {
+ if (pn_cur->pn_va.va_fileid == ino_nr) {
pn = pn_cur;
break;
}
}
if (pn == NULL) {
- lpuffs_debug("%s:%d putnode: pnode #%ld dev: %d not found\n", __FILE__,
- __LINE__, inum, fs_dev);
+ lpuffs_debug("%s:%d putnode: pnode #%"PRIu64" dev: %"PRIu64
+ " not found\n", __FILE__, __LINE__, ino_nr, fs_dev);
panic("fs_putnode failed");
}
while (pn_cur) {
pn_next = LIST_NEXT(pn_cur, pn_entries);
if (pn_cur->pn_va.va_fileid == ino) {
- lpuffs_debug("%ld: %d %s %u %u\n", ino, pn_cur->pn_count,
+ lpuffs_debug("%"PRIu64": %d %s %u %u\n",
+ ino,
+ pn_cur->pn_count,
pn_cur->pn_po.po_path,
pn_cur->pn_po.po_len,
pn_cur->pn_po.po_hash);
#include "puffs.h"
#include "puffs_priv.h"
-#define SAME 1000
-
/*===========================================================================*
- * fs_ftrunc *
+ * fs_trunc *
*===========================================================================*/
-int fs_ftrunc(void)
+int fs_trunc(ino_t ino_nr, off_t start, off_t end)
{
int r;
struct puffs_node *pn;
- off_t start, end;
PUFFS_MAKECRED(pcr, &global_kcred);
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_ftrunc.inode)) == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
return(EINVAL);
- start = fs_m_in.m_vfs_fs_ftrunc.trc_start;
- end = fs_m_in.m_vfs_fs_ftrunc.trc_end;
-
if (end == 0) {
struct vattr va;
/*===========================================================================*
* fs_link *
*===========================================================================*/
-int fs_link(void)
+int fs_link(ino_t dir_nr, char *name, ino_t ino_nr)
{
/* Perform the link(name1, name2) system call. */
register int r;
- char string[NAME_MAX + 1];
- phys_bytes len;
struct puffs_node *pn, *pn_dir, *new_pn;
struct timespec cur_time;
struct puffs_kcn pkcnp;
if (global_pu->pu_ops.puffs_node_link == NULL)
return(OK);
- /* Copy the link name's last component */
- len = fs_m_in.m_vfs_fs_link.path_len;
- if (len > NAME_MAX + 1)
- return(ENAMETOOLONG);
-
- r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_link.grant, 0,
- (vir_bytes) string, (size_t) len);
- if (r != OK) return(r);
- NUL(string, len, sizeof(string));
-
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_link.inode)) == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
return(EINVAL);
/* Check to see if the file has maximum number of links already. */
if (pn->pn_va.va_nlink >= LINK_MAX)
return(EMLINK);
- /* Only super_user may link to directories. */
- if ((pn->pn_va.va_mode & I_TYPE) == I_DIRECTORY && caller_uid != SU_UID)
+ /* Linking directories is too dangerous to allow. */
+ if (S_ISDIR(pn->pn_va.va_mode))
return(EPERM);
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_link.dir_ino)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
return(EINVAL);
if (pn_dir->pn_va.va_nlink == NO_LINK) {
}
/* If 'name2' exists in full (even if no space) set 'r' to error. */
- if ((new_pn = advance(pn_dir, string, IGN_PERM)) == NULL) {
+ if ((new_pn = advance(pn_dir, name)) == NULL) {
r = err_code;
if (r == ENOENT) r = OK;
} else {
if (r != OK) return(r);
/* Try to link. */
- pcn.pcn_namelen = strlen(string);
- assert(pcn.pcn_namelen <= MAXPATHLEN);
- strcpy(pcn.pcn_name, string);
+ pcn.pcn_namelen = strlen(name);
+ assert(pcn.pcn_namelen <= NAME_MAX);
+ strcpy(pcn.pcn_name, name);
if (buildpath) {
if (puffs_path_pcnbuild(global_pu, &pcn, pn_dir) != 0)
/*===========================================================================*
* fs_rdlink *
*===========================================================================*/
-int fs_rdlink(void)
+ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes)
{
register int r; /* return value */
- size_t copylen;
struct puffs_node *pn;
char path[PATH_MAX];
PUFFS_MAKECRED(pcr, &global_kcred);
- copylen = fs_m_in.m_vfs_fs_rdlink.mem_size < UMAX_FILE_POS ?
- fs_m_in.m_vfs_fs_rdlink.mem_size : UMAX_FILE_POS;
+ if (bytes > sizeof(path))
+ bytes = sizeof(path);
- assert(copylen <= PATH_MAX);
-
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_rdlink.inode)) == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
return(EINVAL);
if (!S_ISLNK(pn->pn_va.va_mode))
if (global_pu->pu_ops.puffs_node_readlink == NULL)
return(EINVAL);
- r = global_pu->pu_ops.puffs_node_readlink(global_pu, pn, pcr, path,
- ©len);
+ r = global_pu->pu_ops.puffs_node_readlink(global_pu, pn, pcr, path, &bytes);
if (r != OK) {
if (r > 0) r = -r;
return(r);
}
- r = sys_safecopyto(VFS_PROC_NR, fs_m_in.m_vfs_fs_rdlink.grant,
- (vir_bytes) 0, (vir_bytes) path, (size_t) copylen);
- if (r == OK)
- fs_m_out.m_fs_vfs_rdlink.nbytes = copylen;
+ r = fsdriver_copyout(data, 0, path, bytes);
- return(r);
+ return (r == OK) ? bytes : r;
}
/*===========================================================================*
* fs_rename *
*===========================================================================*/
-int fs_rename(void)
+int fs_rename(ino_t old_dir_nr, char *old_name, ino_t new_dir_nr,
+ char *new_name)
{
/* Perform the rename(name1, name2) system call. */
struct puffs_node *old_dirp, *old_ip; /* ptrs to old dir, file pnodes */
int r = OK; /* error flag; initially no error */
int odir, ndir; /* TRUE iff {old|new} file is dir */
int same_pdir; /* TRUE iff parent dirs are the same */
- phys_bytes len;
struct timespec cur_time;
if (global_pu->pu_ops.puffs_node_rename == NULL)
return(EINVAL);
/* Copy the last component of the old name */
- len = fs_m_in.m_vfs_fs_rename.len_old; /* including trailing '\0' */
- if (len > NAME_MAX + 1)
- return(ENAMETOOLONG);
-
- r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_rename.grant_old,
- (vir_bytes) 0, (vir_bytes) pcn_src.pcn_name, (size_t) len);
- if (r != OK) return(r);
- NUL(pcn_src.pcn_name, len, sizeof(pcn_src.pcn_name));
- pcn_src.pcn_namelen = len - 1;
+ pcn_src.pcn_namelen = strlen(old_name);
+ assert(pcn_src.pcn_namelen <= NAME_MAX);
+ strcpy(pcn_src.pcn_name, old_name);
/* Copy the last component of the new name */
- len = fs_m_in.m_vfs_fs_rename.len_new; /* including trailing '\0' */
- if (len > NAME_MAX + 1)
- return(ENAMETOOLONG);
-
- r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_rename.grant_new,
- (vir_bytes) 0, (vir_bytes) pcn_targ.pcn_name, (size_t) len);
- if (r != OK) return(r);
- NUL(pcn_targ.pcn_name, len, sizeof(pcn_targ.pcn_name));
- pcn_targ.pcn_namelen = len - 1;
+ pcn_targ.pcn_namelen = strlen(new_name);
+ assert(pcn_targ.pcn_namelen <= NAME_MAX);
+ strcpy(pcn_targ.pcn_name, new_name);
/* Get old dir pnode */
- if ((old_dirp = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_rename.dir_old))
- == NULL)
+ if ((old_dirp = puffs_pn_nodewalk(global_pu, 0, &old_dir_nr)) == NULL)
return(ENOENT);
- old_ip = advance(old_dirp, pcn_src.pcn_name, IGN_PERM);
- if (!old_ip) {
- return(ENOENT);
- }
- r = err_code;
+ old_ip = advance(old_dirp, pcn_src.pcn_name);
+ if (!old_ip)
+ return(err_code);
- if (r == EENTERMOUNT || r == ELEAVEMOUNT) {
- old_ip = NULL;
- if (r == EENTERMOUNT) r = EXDEV; /* should this fail at all? */
- else if (r == ELEAVEMOUNT) r = EINVAL; /* rename on dot-dot */
- }
+ if (old_ip->pn_mountpoint)
+ return(EBUSY);
/* Get new dir pnode */
- if ((new_dirp = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_rename.dir_new))
- == NULL) {
- r = ENOENT;
+ if ((new_dirp = puffs_pn_nodewalk(global_pu, 0, &new_dir_nr)) == NULL) {
+ return(ENOENT);
} else {
if (new_dirp->pn_va.va_nlink == NO_LINK) {
/* Dir does not actually exist */
}
/* not required to exist */
- new_ip = advance(new_dirp, pcn_targ.pcn_name, IGN_PERM);
+ new_ip = advance(new_dirp, pcn_targ.pcn_name);
- /* However, if the check failed because the file does exist, don't continue.
- * Note that ELEAVEMOUNT is covered by the dot-dot check later. */
- if (err_code == EENTERMOUNT) {
- new_ip = NULL;
- r = EBUSY;
- }
+ /* If the node does exist, make sure it's not a mountpoint. */
+ if (new_ip != NULL && new_ip->pn_mountpoint)
+ return(EBUSY);
if (old_ip != NULL) {
/* TRUE iff dir */
odir = FALSE;
}
- if (r != OK) return(r);
-
/* Check for a variety of possible errors. */
same_pdir = (old_dirp == new_dirp);
- /* The old or new name must not be . or .. */
- if (strcmp(pcn_src.pcn_name, ".") == 0 ||
- strcmp(pcn_src.pcn_name, "..") == 0 ||
- strcmp(pcn_targ.pcn_name, ".") == 0 ||
- strcmp(pcn_targ.pcn_name, "..") == 0) {
- r = EINVAL;
- }
-
/* Some tests apply only if the new path exists. */
if (new_ip == NULL) {
if (odir && (new_dirp->pn_va.va_nlink >= SHRT_MAX ||
- new_dirp->pn_va.va_nlink >= LINK_MAX) &&
- !same_pdir && r == OK) {
- r = EMLINK;
+ new_dirp->pn_va.va_nlink >= LINK_MAX) && !same_pdir) {
+ return(EMLINK);
}
} else {
- if (old_ip == new_ip) r = SAME; /* old=new */
+ if (old_ip == new_ip) /* old=new */
+ return(OK); /* do NOT update directory times in this case */
/* dir ? */
ndir = ((new_ip->pn_va.va_mode & I_TYPE) == I_DIRECTORY);
- if (odir == TRUE && ndir == FALSE) r = ENOTDIR;
- if (odir == FALSE && ndir == TRUE) r = EISDIR;
+ if (odir == TRUE && ndir == FALSE) return(ENOTDIR);
+ if (odir == FALSE && ndir == TRUE) return(EISDIR);
}
- if (r == SAME) {
- r = OK;
- goto rename_out;
- }
-
- if (r != OK) return(r);
-
/* If a process has another root directory than the system root, we might
* "accidently" be moving it's working directory to a place where it's
* root directory isn't a super directory of it anymore. This can make
}
}
-rename_out:
cur_time = clock_timespec();
update_timens(old_dirp, MTIME | CTIME, &cur_time);
update_timens(new_dirp, MTIME | CTIME, &cur_time);
struct puffs_cn *pcn);
/*===========================================================================*
- * fs_unlink *
+ * fs_unlink *
*===========================================================================*/
-int fs_unlink(void)
+int fs_unlink(ino_t dir_nr, char *name, int call)
{
/* Perform the unlink(name) or rmdir(name) system call. The code for these two
- * is almost the same. They differ only in some condition testing. Unlink()
- * may be used by the superuser to do dangerous things; rmdir() may not.
+ * is almost the same. They differ only in some condition testing.
*/
int r;
struct puffs_node *pn, *pn_dir;
struct puffs_kcn pkcnp;
struct puffs_cn pcn = {&pkcnp, 0, {0,0,0}};
PUFFS_KCREDTOCRED(pcn.pcn_cred, &global_kcred);
- int len;
/* Copy the last component */
- len = fs_m_in.m_vfs_fs_unlink.path_len;
- pcn.pcn_namelen = len - 1;
- if (pcn.pcn_namelen > NAME_MAX)
- return(ENAMETOOLONG);
-
- r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_unlink.grant,
- (vir_bytes) 0, (vir_bytes) pcn.pcn_name,
- (size_t) len);
- if (r != OK) return (r);
- NUL(pcn.pcn_name, len, sizeof(pcn.pcn_name));
-
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_unlink.inode)) == NULL)
+ pcn.pcn_namelen = strlen(name);
+ assert(pcn.pcn_namelen <= NAME_MAX);
+ strcpy(pcn.pcn_name, name);
+
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
return(EINVAL);
/* The last directory exists. Does the file also exist? */
- pn = advance(pn_dir, pcn.pcn_name, IGN_PERM);
+ pn = advance(pn_dir, pcn.pcn_name);
r = err_code;
/* If error, return pnode. */
- if (r != OK) {
- /* Mount point? */
- if (r == EENTERMOUNT || r == ELEAVEMOUNT) {
- r = EBUSY;
- }
+ if (r != OK)
return(r);
- }
+ if (pn->pn_mountpoint)
+ return EBUSY;
/* Now test if the call is allowed, separately for unlink() and rmdir(). */
- if (fs_m_in.m_type == REQ_UNLINK) {
- /* Only the su may unlink directories, but the su can unlink any dir */
- if ((pn->pn_va.va_mode & I_TYPE) == I_DIRECTORY)
- r = EPERM;
- if (r == OK)
- r = unlink_file(pn_dir, pn, &pcn);
+ if (call == FSC_UNLINK) {
+ r = unlink_file(pn_dir, pn, &pcn);
} else {
r = remove_dir(pn_dir, pn, &pcn); /* call is RMDIR */
}
if (r) return(EINVAL);
if (!eofflag) return(ENOTEMPTY);
- if (strcmp(pcn->pcn_name, ".") == 0 || strcmp(pcn->pcn_name, "..") == 0)
- return(EINVAL);
-
if (pn->pn_va.va_fileid == global_pu->pu_pn_root->pn_va.va_fileid)
return(EBUSY); /* can't remove 'root' */
return(EINVAL);
if (S_ISDIR(pn->pn_va.va_mode))
- return(EINVAL);
+ return(EPERM);
if (buildpath) {
r = puffs_path_pcnbuild(global_pu, pcn, dirp);
#include "fs.h"
#include <assert.h>
-#include <minix/vfsif.h>
#include "puffs.h"
#include "puffs_priv.h"
/*===========================================================================*
* fs_sync *
*===========================================================================*/
-int fs_sync(void)
+void fs_sync(void)
{
/* Perform the sync() system call. Flush all the tables.
* The order in which the various tables are flushed is critical.
PUFFS_MAKECRED(pcr, &global_kcred);
if (is_readonly_fs)
- return(OK); /* nothing to sync */
+ return; /* nothing to sync */
r = global_pu->pu_ops.puffs_fs_sync(global_pu, MNT_WAIT, pcr);
if (r) {
lpuffs_debug("Warning: sync failed!\n");
}
-
- return(OK); /* sync() can't fail */
-}
-
-
-/*===========================================================================*
- * fs_flush *
- *===========================================================================*/
-int fs_flush(void)
-{
-/* Flush the blocks of a device from the cache after writing any dirty blocks
- * to disk.
- */
-#if 0
- dev_t dev = fs_m_in.m_vfs_fs_flush.device;
-
- if(dev == fs_dev) return(EBUSY);
-
- flushall(dev);
- invalidate(dev);
-#endif
-
- return(OK);
-}
-
-
-/*===========================================================================*
- * fs_new_driver *
- *===========================================================================*/
-int fs_new_driver(void)
-{
-/* Do not do anything. */
-
- return(OK);
}
#include "fs.h"
#include <fcntl.h>
#include <string.h>
-#include <minix/com.h>
-#include <sys/stat.h>
-#include <minix/ds.h>
#include <minix/vfsif.h>
#include "puffs_priv.h"
/*===========================================================================*
- * fs_readsuper *
+ * fs_mount *
*===========================================================================*/
-int fs_readsuper(void)
+int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
+ unsigned int *res_flags)
{
struct vattr *root_va;
- fs_dev = fs_m_in.m_vfs_fs_readsuper.device;
- is_readonly_fs = (fs_m_in.m_vfs_fs_readsuper.flags & REQ_RDONLY) ? 1 : 0;
- is_root_fs = (fs_m_in.m_vfs_fs_readsuper.flags & REQ_ISROOT) ? 1 : 0;
+ fs_dev = dev;
+ is_readonly_fs = !!(flags & REQ_RDONLY);
/* Open root pnode */
global_pu->pu_pn_root->pn_count = 1;
/* Root pnode properties */
root_va = &global_pu->pu_pn_root->pn_va;
- fs_m_out.m_fs_vfs_readsuper.inode = root_va->va_fileid;
- fs_m_out.m_fs_vfs_readsuper.mode = root_va->va_mode;
- fs_m_out.m_fs_vfs_readsuper.file_size = root_va->va_size;
- fs_m_out.m_fs_vfs_readsuper.uid = root_va->va_uid;
- fs_m_out.m_fs_vfs_readsuper.gid = root_va->va_gid;
- fs_m_out.m_fs_vfs_readsuper.flags = RES_NOFLAGS;
+ root_node->fn_ino_nr = root_va->va_fileid;
+ root_node->fn_mode = root_va->va_mode;
+ root_node->fn_size = root_va->va_size;
+ root_node->fn_uid = root_va->va_uid;
+ root_node->fn_gid = root_va->va_gid;
+ root_node->fn_dev = NO_DEV;
+
+ *res_flags = RES_NOFLAGS;
+
+ mounted = TRUE;
return(OK);
}
/*===========================================================================*
- * fs_mountpoint *
+ * fs_mountpt *
*===========================================================================*/
-int fs_mountpoint(void)
+int fs_mountpt(ino_t ino_nr)
{
/* This function looks up the mount point, it checks the condition whether
* the partition can be mounted on the pnode or not.
struct puffs_node *pn;
mode_t bits;
- /*
- * XXX: we assume that lookup was done first, so pnode can be found with
- * puffs_pn_nodewalk.
- */
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_mountpoint.inode))
- == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
return(EINVAL);
-
if (pn->pn_mountpoint) r = EBUSY;
/* It may not be special. */
/*===========================================================================*
* fs_unmount *
*===========================================================================*/
-int fs_unmount(void)
+void fs_unmount(void)
{
int error;
- /* XXX there is no information about flags, 0 should be safe enough */
- error = global_pu->pu_ops.puffs_fs_unmount(global_pu, 0);
+ /* Always force unmounting, as VFS will not tolerate failure. */
+ error = global_pu->pu_ops.puffs_fs_unmount(global_pu, MNT_FORCE);
if (error) {
- /* XXX we can't return any error to VFS */
lpuffs_debug("user handler failed to unmount filesystem!\
Force unmount!\n");
}
/* Finish off the unmount. */
PU_SETSTATE(global_pu, PUFFS_STATE_UNMOUNTED);
- unmountdone = TRUE;
+ mounted = FALSE;
global_pu->pu_pn_root->pn_count--;
-
- return(OK);
}
*/
#include "fs.h"
-#include <sys/stat.h>
#include <string.h>
#include <assert.h>
-#include <minix/com.h>
-#include <minix/vfsif.h>
#include "puffs.h"
#include "puffs_priv.h"
/*===========================================================================*
* fs_create *
*===========================================================================*/
-int fs_create(void)
+int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
+ struct fsdriver_node *node)
{
int r;
struct puffs_node *pn_dir;
struct puffs_node *pn;
- mode_t omode;
struct puffs_newinfo pni;
struct puffs_kcn pkcnp;
PUFFS_MAKECRED(pcr, &global_kcred);
struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
struct vattr va;
struct timespec cur_time;
- int len;
if (global_pu->pu_ops.puffs_node_create == NULL) {
lpuffs_debug("No puffs_node_create");
return(ENFILE);
}
- /* Read request message */
- omode = fs_m_in.m_vfs_fs_create.mode;
- caller_uid = fs_m_in.m_vfs_fs_create.uid;
- caller_gid = fs_m_in.m_vfs_fs_create.gid;
-
/* Copy the last component (i.e., file name) */
- len = fs_m_in.m_vfs_fs_create.path_len;
- pcn.pcn_namelen = len - 1;
- if (pcn.pcn_namelen > NAME_MAX)
- return(ENAMETOOLONG);
-
- err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_create.grant,
- (vir_bytes) 0, (vir_bytes) pcn.pcn_name,
- (size_t) len);
- if (err_code != OK) return(err_code);
- NUL(pcn.pcn_name, len, sizeof(pcn.pcn_name));
+ pcn.pcn_namelen = strlen(name);
+ assert(pcn.pcn_namelen <= NAME_MAX);
+ strcpy(pcn.pcn_name, name);
/* Get last directory pnode (i.e., directory that will hold the new pnode) */
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_create.inode)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
return(ENOENT);
memset(&pni, 0, sizeof(pni));
memset(&va, 0, sizeof(va));
va.va_type = VREG;
- va.va_mode = omode;
- va.va_uid = caller_uid;
- va.va_gid = caller_gid;
+ va.va_mode = mode;
+ va.va_uid = uid;
+ va.va_gid = gid;
va.va_atime = va.va_mtime = va.va_ctime = cur_time;
if (buildpath) {
update_timens(pn_dir, MTIME | CTIME, &cur_time);
/* Reply message */
- fs_m_out.m_fs_vfs_create.inode = pn->pn_va.va_fileid;
- fs_m_out.m_fs_vfs_create.mode = pn->pn_va.va_mode;
- fs_m_out.m_fs_vfs_create.file_size = pn->pn_va.va_size;
-
- /* This values are needed for the execution */
- fs_m_out.m_fs_vfs_create.uid = pn->pn_va.va_uid;
- fs_m_out.m_fs_vfs_create.gid = pn->pn_va.va_gid;
+ node->fn_ino_nr = pn->pn_va.va_fileid;
+ node->fn_mode = pn->pn_va.va_mode;
+ node->fn_size = pn->pn_va.va_size;
+ node->fn_uid = pn->pn_va.va_uid;
+ node->fn_gid = pn->pn_va.va_gid;
+ node->fn_dev = NO_DEV;
return(OK);
}
/*===========================================================================*
* fs_mknod *
*===========================================================================*/
-int fs_mknod(void)
+int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
+ dev_t dev)
{
int r;
struct puffs_node *pn_dir;
struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
struct vattr va;
struct timespec cur_time;
- int len;
if (global_pu->pu_ops.puffs_node_mknod == NULL) {
lpuffs_debug("No puffs_node_mknod");
return(ENFILE);
}
- /* Copy the last component and set up caller's user and group id */
- len = fs_m_in.m_vfs_fs_mknod.path_len;
- pcn.pcn_namelen = len - 1;
- if (pcn.pcn_namelen > NAME_MAX)
- return(ENAMETOOLONG);
-
- err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_mknod.grant,
- (vir_bytes) 0, (vir_bytes) pcn.pcn_name,
- (size_t) len);
- if (err_code != OK) return(err_code);
- NUL(pcn.pcn_name, len, sizeof(pcn.pcn_name));
-
- caller_uid = fs_m_in.m_vfs_fs_mknod.uid;
- caller_gid = fs_m_in.m_vfs_fs_mknod.gid;
+ /* Copy the last component */
+ pcn.pcn_namelen = strlen(name);
+ assert(pcn.pcn_namelen <= NAME_MAX);
+ strcpy(pcn.pcn_name, name);
/* Get last directory pnode */
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_mknod.inode)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
return(ENOENT);
memset(&pni, 0, sizeof(pni));
memset(&va, 0, sizeof(va));
va.va_type = VDIR;
- va.va_mode = fs_m_in.m_vfs_fs_mknod.mode;
- va.va_uid = caller_uid;
- va.va_gid = caller_gid;
- va.va_rdev = fs_m_in.m_vfs_fs_mknod.device;
+ va.va_mode = mode;
+ va.va_uid = uid;
+ va.va_gid = gid;
+ va.va_rdev = dev;
va.va_atime = va.va_mtime = va.va_ctime = cur_time;
if (buildpath) {
/*===========================================================================*
* fs_mkdir *
*===========================================================================*/
-int fs_mkdir(void)
+int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid)
{
int r;
struct puffs_node *pn_dir;
struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
struct vattr va;
struct timespec cur_time;
- int len;
if (global_pu->pu_ops.puffs_node_mkdir == NULL) {
lpuffs_debug("No puffs_node_mkdir");
return(ENFILE);
}
- /* Copy the last component and set up caller's user and group id */
- len = fs_m_in.m_vfs_fs_mkdir.path_len;
- pcn.pcn_namelen = len - 1;
- if (pcn.pcn_namelen > NAME_MAX)
- return(ENAMETOOLONG);
-
- err_code = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_mkdir.grant,
- (vir_bytes) 0, (vir_bytes) pcn.pcn_name,
- (phys_bytes) len);
- if (err_code != OK) return(err_code);
- NUL(pcn.pcn_name, len, sizeof(pcn.pcn_name));
-
- caller_uid = fs_m_in.m_vfs_fs_mkdir.uid;
- caller_gid = fs_m_in.m_vfs_fs_mkdir.gid;
+ /* Copy the last component */
+ pcn.pcn_namelen = strlen(name);
+ assert(pcn.pcn_namelen <= NAME_MAX);
+ strcpy(pcn.pcn_name, name);
/* Get last directory pnode */
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_mkdir.inode)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
return(ENOENT);
cur_time = clock_timespec();
memset(&va, 0, sizeof(va));
va.va_type = VDIR;
- va.va_mode = fs_m_in.m_vfs_fs_mkdir.mode;
- va.va_uid = caller_uid;
- va.va_gid = caller_gid;
+ va.va_mode = mode;
+ va.va_uid = uid;
+ va.va_gid = gid;
va.va_atime = va.va_mtime = va.va_ctime = cur_time;
if (buildpath) {
/*===========================================================================*
* fs_slink *
*===========================================================================*/
-int fs_slink(void)
+int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
+ struct fsdriver_data *data, size_t bytes)
{
int r;
struct pnode *pn; /* pnode containing symbolic link */
PUFFS_MAKECRED(pcr, &global_kcred);
struct puffs_cn pcn = {&pkcnp, (struct puffs_cred *) __UNCONST(pcr), {0,0,0}};
struct vattr va;
- int len;
-
- caller_uid = fs_m_in.m_vfs_fs_slink.uid;
- caller_gid = fs_m_in.m_vfs_fs_slink.gid;
/* Copy the link name's last component */
- len = fs_m_in.m_vfs_fs_slink.path_len;
- pcn.pcn_namelen = len - 1;
- if (pcn.pcn_namelen > NAME_MAX)
- return(ENAMETOOLONG);
+ pcn.pcn_namelen = strlen(name);
+ if (pcn.pcn_namelen <= NAME_MAX);
+ strcpy(pcn.pcn_name, name);
- if (fs_m_in.m_vfs_fs_slink.mem_size >= PATH_MAX)
+ if (bytes >= PATH_MAX)
return(ENAMETOOLONG);
- r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_slink.grant_path,
- (vir_bytes) 0, (vir_bytes) pcn.pcn_name,
- (size_t) len);
- if (r != OK) return(r);
- NUL(pcn.pcn_name, len, sizeof(pcn.pcn_name));
-
/* Copy the target path (note that it's not null terminated) */
- r = sys_safecopyfrom(VFS_PROC_NR, fs_m_in.m_vfs_fs_slink.grant_target,
- (vir_bytes) 0, (vir_bytes) target,
- fs_m_in.m_vfs_fs_slink.mem_size);
- if (r != OK) return(r);
- target[fs_m_in.m_vfs_fs_slink.mem_size] = '\0';
+ if ((r = fsdriver_copyin(data, 0, target, bytes)) != OK)
+ return r;
+
+ target[bytes] = '\0';
- if (strlen(target) != (size_t) fs_m_in.m_vfs_fs_slink.mem_size) {
+ if (strlen(target) != bytes) {
/* This can happen if the user provides a buffer
* with a \0 in it. This can cause a lot of trouble
* when the symlink is used later. We could just use
return(ENAMETOOLONG);
}
- if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_slink.inode)) == NULL)
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL)
return(EINVAL);
memset(&pni, 0, sizeof(pni));
memset(&va, 0, sizeof(va));
va.va_type = VLNK;
va.va_mode = (I_SYMBOLIC_LINK | RWX_MODES);
- va.va_uid = caller_uid;
- va.va_gid = caller_gid;
+ va.va_uid = uid;
+ va.va_gid = gid;
va.va_atime = va.va_mtime = va.va_ctime = clock_timespec();
if (buildpath) {
return(r);
}
-
-
-/*===========================================================================*
- * fs_inhibread *
- *===========================================================================*/
-int fs_inhibread(void)
-{
- return(OK);
-}
#include <stdlib.h>
#include <string.h>
-#include <minix/endpoint.h>
-#include <minix/vfsif.h>
-#include <minix/libminixfs.h>
-
#include "puffs.h"
#include "puffs_priv.h"
-char dot2[3] = ".."; /* permissions for . and .. */
-
-static char *get_name(char *name, char string[NAME_MAX+1]);
-static int ltraverse(struct puffs_node *pn, char *suffix);
-static int parse_path(ino_t dir_ino, ino_t root_ino, int flags, struct
- puffs_node **res_inop, size_t *offsetp, int *symlinkp);
-
-/*===========================================================================*
- * fs_lookup *
- *===========================================================================*/
-int fs_lookup(void)
-{
- cp_grant_id_t grant;
- int r, r1, flags, symlinks;
- unsigned int len;
- size_t offset = 0, path_size;
- ino_t dir_ino, root_ino;
- struct puffs_node *pn;
-
- grant = fs_m_in.m_vfs_fs_lookup.grant_path;
- path_size = fs_m_in.m_vfs_fs_lookup.path_size; /* Size of the buffer */
- len = fs_m_in.m_vfs_fs_lookup.path_len; /* including terminating nul */
- dir_ino = fs_m_in.m_vfs_fs_lookup.dir_ino;
- root_ino = fs_m_in.m_vfs_fs_lookup.root_ino;
- flags = fs_m_in.m_vfs_fs_lookup.flags;
-
- /* Check length. */
- if (len > sizeof(user_path)) return(E2BIG); /* too big for buffer */
- if (len == 0) return(EINVAL); /* too small */
-
- /* Copy the pathname and set up caller's user and group id */
- r = sys_safecopyfrom(VFS_PROC_NR, grant, /*offset*/ 0,
- (vir_bytes) user_path, (size_t) len);
- if (r != OK) return(r);
-
- /* Verify this is a null-terminated path. */
- if (user_path[len - 1] != '\0') return(EINVAL);
-
- memset(&credentials, 0, sizeof(credentials));
- if(!(flags & PATH_GET_UCRED)) { /* Do we have to copy uid/gid credentials? */
- caller_uid = fs_m_in.m_vfs_fs_lookup.uid;
- caller_gid = fs_m_in.m_vfs_fs_lookup.gid;
- } else {
- if((r=fs_lookup_credentials(&credentials,
- &caller_uid, &caller_gid,
- fs_m_in.m_vfs_fs_lookup.grant_ucred,
- fs_m_in.m_vfs_fs_lookup.ucred_size)) != OK)
- return r;
- }
-
-
- /* Lookup pnode */
- pn = NULL;
- r = parse_path(dir_ino, root_ino, flags, &pn, &offset, &symlinks);
-
- if (symlinks != 0 && (r == ELEAVEMOUNT || r == EENTERMOUNT || r == ESYMLINK)){
- len = strlen(user_path)+1;
- if (len > path_size) return(ENAMETOOLONG);
-
- r1 = sys_safecopyto(VFS_PROC_NR, grant, (vir_bytes) 0,
- (vir_bytes) user_path, (size_t) len);
- if (r1 != OK) return(r1);
- }
-
- if (r == ELEAVEMOUNT || r == ESYMLINK) {
- /* Report offset and the error */
- fs_m_out.m_fs_vfs_lookup.offset = offset;
- fs_m_out.m_fs_vfs_lookup.symloop = symlinks;
-
- return(r);
- }
-
- if (r != OK && r != EENTERMOUNT) {
- return(r);
- }
-
- if (r == OK) {
- /* Open pnode */
- pn->pn_count++;
- }
-
- fs_m_out.m_fs_vfs_lookup.inode = pn->pn_va.va_fileid;
- fs_m_out.m_fs_vfs_lookup.mode = pn->pn_va.va_mode;
- fs_m_out.m_fs_vfs_lookup.file_size = pn->pn_va.va_size;
- fs_m_out.m_fs_vfs_lookup.symloop = symlinks;
- fs_m_out.m_fs_vfs_lookup.uid = pn->pn_va.va_uid;
- fs_m_out.m_fs_vfs_lookup.gid = pn->pn_va.va_gid;
-
- /* This is only valid for block and character specials. But it doesn't
- * cause any harm to always set the device field. */
- fs_m_out.m_fs_vfs_lookup.device = pn->pn_va.va_rdev;
-
- if (r == EENTERMOUNT) {
- fs_m_out.m_fs_vfs_lookup.offset = offset;
- }
-
- return(r);
-}
-
/*===========================================================================*
- * parse_path *
+ * fs_lookup *
*===========================================================================*/
-static int parse_path(
- ino_t dir_ino,
- ino_t root_ino,
- int flags,
- struct puffs_node **res_inop,
- size_t *offsetp,
- int *symlinkp
-)
+int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
+ int *is_mountpt)
{
- /* Parse the path in user_path, starting at dir_ino. If the path is the empty
- * string, just return dir_ino. It is upto the caller to treat an empty
- * path in a special way. Otherwise, if the path consists of just one or
- * more slash ('/') characters, the path is replaced with ".". Otherwise,
- * just look up the first (or only) component in path after skipping any
- * leading slashes.
- */
- int r, leaving_mount;
struct puffs_node *pn, *pn_dir;
- char *cp, *next_cp; /* component and next component */
- char component[NAME_MAX+1];
-
- /* Start parsing path at the first component in user_path */
- cp = user_path;
- /* No symlinks encountered yet */
- *symlinkp = 0;
-
- /* Find starting pnode according to the request message */
- /* XXX it's deffinitely OK to use nodewalk here */
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &dir_ino)) == NULL) {
+ /* Find the pnode of the directory node. */
+ if ((pn_dir = puffs_pn_nodewalk(global_pu, 0, &dir_nr)) == NULL) {
lpuffs_debug("nodewalk failed\n");
- return(ENOENT);
- }
-
- /* If dir has been removed return ENOENT. */
- if (pn->pn_va.va_nlink == NO_LINK) return(ENOENT);
-
- /* If the given start pnode is a mountpoint, we must be here because the file
- * system mounted on top returned an ELEAVEMOUNT error. In this case, we must
- * only accept ".." as the first path component.
- */
- leaving_mount = pn->pn_mountpoint; /* True iff pn is a mountpoint */
-
- /* Scan the path component by component. */
- while (TRUE) {
- if (cp[0] == '\0') {
- /* We're done; either the path was empty or we've parsed all
- components of the path */
-
- *res_inop = pn;
- *offsetp += cp - user_path;
-
- /* Return EENTERMOUNT if we are at a mount point */
- if (pn->pn_mountpoint) return(EENTERMOUNT);
-
- return(OK);
- }
-
- while(cp[0] == '/') cp++;
- next_cp = get_name(cp, component);
- if (next_cp == NULL) {
- return(err_code);
- }
-
- /* Special code for '..'. A process is not allowed to leave a chrooted
- * environment. A lookup of '..' at the root of a mounted filesystem
- * has to return ELEAVEMOUNT. In both cases, the caller needs search
- * permission for the current pnode, as it is used as directory.
- */
- if (strcmp(component, "..") == 0) {
- /* 'pn' is now accessed as directory */
- if ((r = forbidden(pn, X_BIT)) != OK) {
- return(r);
- }
-
- if (pn->pn_va.va_fileid == root_ino) {
- cp = next_cp;
- continue; /* Ignore the '..' at a process' root
- and move on to the next component */
- }
-
- if (pn->pn_va.va_fileid == global_pu->pu_pn_root->pn_va.va_fileid
- && !is_root_fs) {
- /* Climbing up to parent FS */
- *offsetp += cp - user_path;
- return(ELEAVEMOUNT);
- }
- }
-
- /* Only check for a mount point if we are not coming from one. */
- if (!leaving_mount && pn->pn_mountpoint) {
- /* Going to enter a child FS */
-
- *res_inop = pn;
- *offsetp += cp - user_path;
- return(EENTERMOUNT);
- }
-
- /* There is more path. Keep parsing.
- * If we're leaving a mountpoint, skip directory permission checks.
- */
- pn_dir = pn;
- if ((pn_dir->pn_va.va_mode & I_TYPE) != I_DIRECTORY) {
- return(ENOTDIR);
- }
- pn = advance(pn_dir, leaving_mount ? dot2 : component, CHK_PERM);
- if (err_code == ELEAVEMOUNT || err_code == EENTERMOUNT)
- err_code = OK;
-
- if (err_code != OK) {
- return(err_code);
- }
-
- assert(pn != NULL);
-
- leaving_mount = 0;
-
- /* The call to advance() succeeded. Fetch next component. */
- if (S_ISLNK(pn->pn_va.va_mode)) {
- if (next_cp[0] == '\0' && (flags & PATH_RET_SYMLINK)) {
- *res_inop = pn;
- *offsetp += next_cp - user_path;
- return(OK);
- }
-
- /* Extract path name from the symlink file */
- r = ltraverse(pn, next_cp);
- next_cp = user_path;
- *offsetp = 0;
-
- /* Symloop limit reached? */
- if (++(*symlinkp) > _POSIX_SYMLOOP_MAX)
- r = ELOOP;
-
- if (r != OK)
- return(r);
-
- if (next_cp[0] == '/')
- return(ESYMLINK);
-
- pn = pn_dir;
- }
-
- cp = next_cp; /* Process subsequent component in next round */
- }
-
-}
-
-
-/*===========================================================================*
- * ltraverse *
- *===========================================================================*/
-static int ltraverse(
- struct puffs_node *pn, /* symbolic link */
- char *suffix /* current remaining path. Has to point in the
- * user_path buffer
- */
-)
-{
-/* Traverse a symbolic link. Copy the link text from the pnode and insert
- * the text into the path. Return error code or report success. Base
- * directory has to be determined according to the first character of the
- * new pathname.
- */
- int r;
- char sp[PATH_MAX];
- size_t llen = PATH_MAX; /* length of link */
- size_t slen; /* length of suffix */
- PUFFS_MAKECRED(pcr, &global_kcred);
-
-
- if (!S_ISLNK(pn->pn_va.va_mode))
- r = EACCES;
-
- if (global_pu->pu_ops.puffs_node_readlink == NULL)
return(EINVAL);
+ }
- if (global_pu->pu_ops.puffs_node_readlink(global_pu, pn, pcr, sp, &llen) != 0)
- return(EINVAL);
+ if (!S_ISDIR(pn_dir->pn_va.va_mode))
+ return ENOTDIR;
- slen = strlen(suffix);
-
- /* The path we're parsing looks like this:
- * /already/processed/path/<link> or
- * /already/processed/path/<link>/not/yet/processed/path
- * After expanding the <link>, the path will look like
- * <expandedlink> or
- * <expandedlink>/not/yet/processed
- * In both cases user_path must have enough room to hold <expandedlink>.
- * However, in the latter case we have to move /not/yet/processed to the
- * right place first, before we expand <link>. When strlen(<expandedlink>) is
- * smaller than strlen(/already/processes/path), we move the suffix to the
- * left. Is strlen(<expandedlink>) greater then we move it to the right. Else
- * we do nothing.
- */
-
- if (slen > 0) { /* Do we have path after the link? */
- /* For simplicity we require that suffix starts with a slash */
- if (suffix[0] != '/') {
- panic("ltraverse: suffix does not start with a slash");
- }
+ if ((pn = advance(pn_dir, name)) == NULL)
+ return err_code;
- /* To be able to expand the <link>, we have to move the 'suffix'
- * to the right place.
- */
- if (slen + llen + 1 > sizeof(user_path))
- return(ENAMETOOLONG);/* <expandedlink>+suffix+\0 does not fit*/
- if ((unsigned)(suffix - user_path) != llen) {
- /* Move suffix left or right if needed */
- memmove(&user_path[llen], suffix, slen+1);
- }
- } else {
- if (llen + 1 > sizeof(user_path))
- return(ENAMETOOLONG); /* <expandedlink> + \0 does not fit */
+ pn->pn_count++; /* open pnode */
- /* Set terminating nul */
- user_path[llen]= '\0';
- }
+ node->fn_ino_nr = pn->pn_va.va_fileid;
+ node->fn_mode = pn->pn_va.va_mode;
+ node->fn_size = pn->pn_va.va_size;
+ node->fn_uid = pn->pn_va.va_uid;
+ node->fn_gid = pn->pn_va.va_gid;
+ node->fn_dev = pn->pn_va.va_rdev;
- /* Everything is set, now copy the expanded link to user_path */
- memmove(user_path, sp, llen);
+ *is_mountpt = pn->pn_mountpoint;
- return(OK);
+ return OK;
}
*===========================================================================*/
struct puffs_node *advance(
struct puffs_node *pn_dir, /* pnode for directory to be searched */
- char string[NAME_MAX + 1], /* component name to look for */
- int chk_perm /* check permissions when string is
- * looked up*/
+ char string[NAME_MAX + 1] /* component name to look for */
)
{
/* Given a directory and a component of a path, look up the component in
dev_t rdev;
int error;
+ assert(pn_dir != NULL);
+
err_code = OK;
/* If 'string' is empty, return an error. */
return(NULL);
}
- /* Check for NULL. */
- if (pn_dir == NULL)
+ /* If dir has been removed return ENOENT. */
+ if (pn_dir->pn_va.va_nlink == NO_LINK) {
+ err_code = ENOENT;
return(NULL);
-
- if (chk_perm) {
- /* Just search permission is checked */
- if (forbidden(pn_dir, X_BIT)) {
- err_code = EACCES;
- return(NULL);
- }
}
if (strcmp(string, ".") == 0) {
* will be parent path (same pnode as the one to be looked up) +
* requested path. E.g. after several lookups we might get advance
* for "." with parent path "/././././././././.".
+ * FIXME: how is ".." handled then?
*
* Another problem is that after lookup pnode will be added
* to the pu_pnodelst, which already contains pnode instance for this
* pnode. It will cause lot of troubles.
+ * FIXME: check if this is actually correct, because if it is, we are
+ * in lots of trouble; there are many ways to reach already-open pnodes
*/
return pn_dir;
}
}
/* lookup *must* be present */
- error = global_pu->pu_ops.puffs_node_lookup(global_pu, pn_dir,
- &pni, &pcn);
+ error = global_pu->pu_ops.puffs_node_lookup(global_pu, pn_dir, &pni, &pcn);
if (buildpath) {
if (error) {
if (error) {
err_code = error < 0 ? error : -error;
return(NULL);
- } else {
- /* In MFS/ext2 it's set by search_dir, puffs_node_lookup error codes are unclear,
- * so we use error variable there
- */
- err_code = OK;
}
- assert(pn != NULL);
-
- /* The following test is for "mountpoint/.." where mountpoint is a
- * mountpoint. ".." will refer to the root of the mounted filesystem,
- * but has to become a reference to the parent of the 'mountpoint'
- * directory.
- *
- * This case is recognized by the looked up name pointing to a
- * root pnode, and the directory in which it is held being a
- * root pnode, _and_ the name[1] being '.'. (This is a test for '..'
- * and excludes '.'.)
- */
- if (pn->pn_va.va_fileid == global_pu->pu_pn_root->pn_va.va_fileid) {
- if (pn_dir->pn_va.va_fileid == global_pu->pu_pn_root->pn_va.va_fileid) {
- if (string[1] == '.') {
- if (!is_root_fs) {
- /* Climbing up mountpoint */
- err_code = ELEAVEMOUNT;
- }
- }
- }
- }
+ err_code = OK;
- /* See if the pnode is mounted on. If so, switch to root directory of the
- * mounted file system. The super_block provides the linkage between the
- * pnode mounted on and the root directory of the mounted file system.
- */
- if (pn->pn_mountpoint) {
- /* Mountpoint encountered, report it */
- err_code = EENTERMOUNT;
- }
+ assert(pn != NULL);
return(pn);
}
-
-
-/*===========================================================================*
- * get_name *
- *===========================================================================*/
-static char *get_name(
- char *path_name, /* path name to parse */
- char string[NAME_MAX+1] /* component extracted from 'old_name' */
-)
-{
-/* Given a pointer to a path name in fs space, 'path_name', copy the first
- * component to 'string' (truncated if necessary, always nul terminated).
- * A pointer to the string after the first component of the name as yet
- * unparsed is returned. Roughly speaking,
- * 'get_name' = 'path_name' - 'string'.
- *
- * This routine follows the standard convention that /usr/ast, /usr//ast,
- * //usr///ast and /usr/ast/ are all equivalent.
- *
- * If len of component is greater, than allowed, then return 0.
- */
- size_t len;
- char *cp, *ep;
-
- cp = path_name;
-
- /* Skip leading slashes */
- while (cp[0] == '/') cp++;
-
- /* Find the end of the first component */
- ep = cp;
- while (ep[0] != '\0' && ep[0] != '/')
- ep++;
-
- len = (size_t) (ep - cp);
-
- /* XXX we don't check name_max of fileserver (probably we can't) */
- if (len > NAME_MAX) {
- err_code = ENAMETOOLONG;
- return(NULL);
- }
-
- /* Special case of the string at cp is empty */
- if (len == 0)
- strcpy(string, "."); /* Return "." */
- else {
- memcpy(string, cp, len);
- string[len]= '\0';
- }
-
- return(ep);
-}
#include <string.h>
#include "puffs_priv.h"
-#if defined(__minix)
-#include <minix/type.h>
-#include "proto.h"
-#endif /* defined(__minix) */
/*
* Well, you're probably wondering why this isn't optimized.
*/
#include "fs.h"
-#include <minix/vfsif.h>
#include "puffs.h"
#include "puffs_priv.h"
-static int in_group(gid_t grp);
-
/*===========================================================================*
* fs_chmod *
*===========================================================================*/
-int fs_chmod(void)
+int fs_chmod(ino_t ino_nr, mode_t *mode)
{
/* Perform the chmod(name, mode) system call. */
struct puffs_node *pn;
- mode_t mode;
struct vattr va;
PUFFS_MAKECRED(pcr, &global_kcred);
if (global_pu->pu_ops.puffs_node_setattr == NULL)
return(EINVAL);
- mode = fs_m_in.m_vfs_fs_chmod.mode;
-
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_chmod.inode)) == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
return(EINVAL);
puffs_vattr_null(&va);
/* Clear setgid bit if file is not in caller's grp */
- va.va_mode = (pn->pn_va.va_mode & ~ALL_MODES) | (mode & ALL_MODES);
+ va.va_mode = (pn->pn_va.va_mode & ~ALL_MODES) | (*mode & ALL_MODES);
va.va_ctime = clock_timespec();
if (global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr) != 0)
return(EINVAL);
/* Return full new mode to caller. */
- fs_m_out.m_fs_vfs_chmod.mode = pn->pn_va.va_mode;
+ *mode = pn->pn_va.va_mode;
return(OK);
}
/*===========================================================================*
* fs_chown *
*===========================================================================*/
-int fs_chown(void)
+int fs_chown(ino_t ino_nr, uid_t uid, gid_t gid, mode_t *mode)
{
struct puffs_node *pn;
struct vattr va;
PUFFS_MAKECRED(pcr, &global_kcred);
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_chown.inode)) == NULL)
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
return(EINVAL);
- /* Not permitted to change the owner of a file on a read-only file sys. */
- if (!is_readonly_fs) {
- puffs_vattr_null(&va);
- va.va_uid = fs_m_in.m_vfs_fs_chown.uid;
- va.va_gid = fs_m_in.m_vfs_fs_chown.gid;
- va.va_mode = pn->pn_va.va_mode & ~(I_SET_UID_BIT | I_SET_GID_BIT);
- va.va_ctime = clock_timespec();
+ puffs_vattr_null(&va);
+ va.va_uid = uid;
+ va.va_gid = gid;
+ va.va_mode = pn->pn_va.va_mode & ~(I_SET_UID_BIT | I_SET_GID_BIT);
+ va.va_ctime = clock_timespec();
- if (global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr) != 0)
- return(EINVAL);
- }
+ if (global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr) != 0)
+ return(EINVAL);
/* Update caller on current mode, as it may have changed. */
- fs_m_out.m_fs_vfs_chown.mode = pn->pn_va.va_mode;
+ *mode = pn->pn_va.va_mode;
return(OK);
}
-
-
-/*===========================================================================*
- * forbidden *
- *===========================================================================*/
-int forbidden(register struct puffs_node *pn, mode_t access_desired)
-{
-/* Given a pointer to an pnode, 'pn', and the access desired, determine
- * if the access is allowed, and if not why not. The routine looks up the
- * caller's uid in the 'fproc' table. If access is allowed, OK is returned
- * if it is forbidden, EACCES is returned.
- */
-
- register mode_t bits, perm_bits;
- int r, shift;
-
- /* Isolate the relevant rwx bits from the mode. */
- bits = pn->pn_va.va_mode;
- if (caller_uid == SU_UID) {
- /* Grant read and write permission. Grant search permission for
- * directories. Grant execute permission (for non-directories) if
- * and only if one of the 'X' bits is set.
- */
- if ( (bits & I_TYPE) == I_DIRECTORY ||
- bits & ((X_BIT << 6) | (X_BIT << 3) | X_BIT))
- perm_bits = R_BIT | W_BIT | X_BIT;
- else
- perm_bits = R_BIT | W_BIT;
- } else {
- if (caller_uid == pn->pn_va.va_uid) shift = 6; /* owner */
- else if (caller_gid == pn->pn_va.va_gid) shift = 3; /* group */
- else if (in_group(pn->pn_va.va_gid) == OK) shift = 3; /* other groups */
- else shift = 0; /* other */
- perm_bits = (bits >> shift) & (R_BIT | W_BIT | X_BIT);
- }
-
- /* If access desired is not a subset of what is allowed, it is refused. */
- r = OK;
- if ((perm_bits | access_desired) != perm_bits) r = EACCES;
-
- /* Check to see if someone is trying to write on a file system that is
- * mounted read-only.
- */
- if (r == OK) {
- if (access_desired & W_BIT) {
- r = is_readonly_fs ? EROFS : OK;
- }
- }
-
- return(r);
-}
-
-
-/*===========================================================================*
- * in_group *
- *===========================================================================*/
-static int in_group(gid_t grp)
-{
- int i;
- for(i = 0; i < credentials.vu_ngroups; i++)
- if (credentials.vu_sgroups[i] == grp)
- return(OK);
-
- return(EINVAL);
-}
/* Function prototypes. */
-int fs_new_driver(void);
-
/* inode.c */
-int fs_putnode(void);
+int fs_putnode(ino_t ino_nr, unsigned int count);
void release_node(struct puffs_usermount *pu, struct puffs_node *pn );
-/* device.c */
-int dev_open(endpoint_t driver_e, dev_t dev, endpoint_t proc_e, int
- flags);
-void dev_close(endpoint_t driver_e, dev_t dev);
-
/* link.c */
-int fs_ftrunc(void);
-int fs_link(void);
-int fs_rdlink(void);
-int fs_rename(void);
-int fs_unlink(void);
+int fs_trunc(ino_t ino_nr, off_t start, off_t end);
+int fs_link(ino_t dir_nr, char *name, ino_t ino_nr);
+ssize_t fs_rdlink(ino_t ino_nr, struct fsdriver_data *data, size_t bytes);
+int fs_rename(ino_t old_dir_nr, char *old_name, ino_t new_dir_nr,
+ char *new_name);
+int fs_unlink(ino_t dir_nr, char *name, int call);
/* misc.c */
-int fs_flush(void);
-int fs_sync(void);
+void fs_sync(void);
/* mount.c */
-int fs_mountpoint(void);
-int fs_readsuper(void);
-int fs_unmount(void);
+int fs_mount(dev_t dev, unsigned int flags, struct fsdriver_node *root_node,
+ unsigned int *res_flags);
+void fs_unmount(void);
+int fs_mountpt(ino_t ino_nr);
/* open.c */
-int fs_create(void);
-int fs_inhibread(void);
-int fs_mkdir(void);
-int fs_mknod(void);
-int fs_slink(void);
+int fs_create(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
+ struct fsdriver_node *node);
+int fs_mkdir(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid);
+int fs_mknod(ino_t dir_nr, char *name, mode_t mode, uid_t uid, gid_t gid,
+ dev_t dev);
+int fs_slink(ino_t dir_nr, char *name, uid_t uid, gid_t gid,
+ struct fsdriver_data *data, size_t bytes);
/* path.c */
-int fs_lookup(void);
-struct puffs_node *advance(struct puffs_node *dirp, char string[NAME_MAX
- + 1], int chk_perm);
+int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
+ int *is_mountpt);
+struct puffs_node *advance(struct puffs_node *dirp, char string[NAME_MAX + 1]);
/* protect.c */
-int fs_chmod(void);
-int fs_chown(void);
-int fs_getdents(void);
-int forbidden(struct puffs_node *rip, mode_t access_desired);
+int fs_chmod(ino_t ino_nr, mode_t *mode);
+int fs_chown(ino_t ino_nr, uid_t uid, gid_t gid, mode_t *mode);
/* read.c */
-int fs_breadwrite(void);
-int fs_readwrite(void);
+ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
+ off_t pos, int call);
+ssize_t fs_write(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
+ off_t pos, int call);
+ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
+ off_t *pos);
/* stadir.c */
-int fs_stat(void);
-int fs_statvfs(void);
+int fs_stat(ino_t ino, struct stat *statbuf);
+int fs_statvfs(struct statvfs *st);
/* time.c */
-int fs_utime(void);
+int fs_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime);
/* utility.c */
-int no_sys(void);
-void mfs_nul_f(const char *file, int line, char *str, unsigned int len,
- unsigned int maxlen);
struct timespec clock_timespec(void);
int update_timens(struct puffs_node *pn, int fl, struct timespec *);
-void lpuffs_debug(const char *format, ...);
+void lpuffs_debug(const char *format, ...)
+ __attribute__((__format__(__printf__, 1, 2)));
#endif /* PUFFS_PROTO_H */
#if defined(__minix)
#include "fs.h"
-#include <minix/endpoint.h>
-#include <minix/vfsif.h>
#endif /* defined(__minix) */
#include <assert.h>
pthread_mutex_t pu_lock = PTHREAD_MUTEX_INITIALIZER;
#endif
+#if defined(__minix)
+static message fs_msg;
+static int fs_ipc_status;
+#endif
/* Declare some local functions. */
-static void get_work(message *m_in);
-static void reply(endpoint_t who, message *m_out);
+static int get_work(message *msg, int *ipc_status);
/* SEF functions and variables. */
static void sef_local_startup(void);
assert(new_argc > 0);
- get_work(&fs_m_in);
+ /* Get the mount request from VFS, so we can deal with it later. */
+ (void)get_work(&fs_msg, &fs_ipc_status);
return __real_main(new_argc, new_argv);
}
puffs_cookie_t cookie)
{
#if defined(__minix)
- endpoint_t src;
- int error, ind;
-
pu->pu_kargp->pa_root_cookie = cookie;
-
- src = fs_m_in.m_source;
- error = OK;
- caller_uid = INVAL_UID; /* To trap errors */
- caller_gid = INVAL_GID;
- req_nr = fs_m_in.m_type;
-
- if (req_nr < FS_BASE) {
- fs_m_in.m_type += FS_BASE;
- req_nr = fs_m_in.m_type;
- }
- ind = req_nr - FS_BASE;
-
- assert(ind == REQ_READ_SUPER);
-
- if (ind < 0 || ind >= NREQS) {
- error = EINVAL;
- } else {
- error = (*fs_call_vec[ind])();
- }
- fs_m_out.m_type = error;
- if (IS_VFS_FS_TRANSID(last_request_transid)) {
- /* If a transaction ID was set, reset it */
- fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type,
- last_request_transid);
- }
- reply(src, &fs_m_out);
+ /* Process the already-received mount request. */
+ fsdriver_process(&puffs_table, &fs_msg, fs_ipc_status, FALSE);
- if (error) {
+ if (!mounted) {
+ /* This should never happen, unless VFS misbehaves.. */
free(pu->pu_kargp);
pu->pu_kargp = NULL;
- errno = error;
+ errno = -EINVAL;
return -1;
}
/*ARGSUSED*/
struct puffs_usermount *
-_puffs_init(int dummy, struct puffs_ops *pops, const char *mntfromname,
+puffs_init(struct puffs_ops *pops, const char *mntfromname,
const char *puffsname, void *priv, uint32_t pflags)
{
struct puffs_usermount *pu;
pargs->pa_vers = PUFFSVERSION;
pargs->pa_flags = PUFFS_FLAG_KERN(pflags);
- fillvnopmask(pops, pargs->pa_vnopmask);
+ fillvnopmask(pops, pargs);
puffs_setmntinfo(pu, mntfromname, puffsname);
puffs_zerostatvfs(&pargs->pa_svfsb);
puffs__theloop(struct puffs_cc *pcc)
{
struct puffs_usermount *pu = pcc->pcc_pu;
- int error, ind;
-
- while (!unmountdone || !exitsignaled) {
- endpoint_t src;
+ while (mounted || !exitsignaled) {
/*
* Schedule existing requests.
*/
}
/* Wait for request message. */
- get_work(&fs_m_in);
+ if (get_work(&fs_msg, &fs_ipc_status) != OK)
+ continue; /* recheck loop conditions */
- src = fs_m_in.m_source;
- error = OK;
- caller_uid = INVAL_UID; /* To trap errors */
- caller_gid = INVAL_GID;
- req_nr = fs_m_in.m_type;
-
- if (req_nr < FS_BASE) {
- fs_m_in.m_type += FS_BASE;
- req_nr = fs_m_in.m_type;
- }
- ind = req_nr - FS_BASE;
-
- if (ind < 0 || ind >= NREQS) {
- error = EINVAL;
- } else {
- error = (*fs_call_vec[ind])();
- }
-
- fs_m_out.m_type = error;
- if (IS_VFS_FS_TRANSID(last_request_transid)) {
- /* If a transaction ID was set, reset it */
- fs_m_out.m_type = TRNS_ADD_ID(fs_m_out.m_type, last_request_transid);
- }
- reply(src, &fs_m_out);
+ /* Process it, and send a reply. */
+ fsdriver_process(&puffs_table, &fs_msg, fs_ipc_status, FALSE);
}
if (puffs__cc_restoremain(pu) == -1)
exitsignaled = 1;
fs_sync();
- /* If unmounting has already been performed, exit immediately.
- * We might not get another message.
- */
- if (unmountdone) {
- if (puffs__cc_restoremain(global_pu) == -1)
- warn("cannot restore main context. impending doom");
- /* May happen if puffs_fakecc is set to 1. Currently librefuse sets it.
- * There is a chance, that main loop hangs in receive() and we will
- * never get any new message, so we have to exit() here.
- */
- exit(0);
- }
+ sef_cancel();
}
/*===========================================================================*
* get_work *
*===========================================================================*/
-static void get_work(
- message *m_in /* pointer to message */
-)
+static int get_work(message *msg, int *ipc_status)
{
- int r, srcok = 0;
- endpoint_t src;
+ int r;
- do {
- if ((r = sef_receive(ANY, m_in)) != OK) /* wait for message */
+ for (;;) {
+ if ((r = sef_receive_status(ANY, msg, ipc_status)) != OK) {
+ if (r == EINTR) /* sef_cancel from signal handler? */
+ break; /* see if we can exit the main loop */
panic("sef_receive failed: %d", r);
- src = m_in->m_source;
-
- if(src == VFS_PROC_NR) {
- if(unmountdone)
- lpuffs_debug("libpuffs: unmounted: unexpected message from FS\n");
- else
- srcok = 1; /* Normal FS request. */
-
- } else
- lpuffs_debug("libpuffs: unexpected source %d\n", src);
- } while(!srcok);
-
- assert((src == VFS_PROC_NR && !unmountdone));
-
- last_request_transid = TRNS_GET_ID(fs_m_in.m_type);
- fs_m_in.m_type = TRNS_DEL_ID(fs_m_in.m_type);
- if (fs_m_in.m_type == 0) {
- assert(!IS_VFS_FS_TRANSID(last_request_transid));
- fs_m_in.m_type = last_request_transid; /* Backwards compat. */
- last_request_transid = 0;
- } else
- assert(IS_VFS_FS_TRANSID(last_request_transid));
-}
-
-
-/*===========================================================================*
- * reply *
- *===========================================================================*/
-static void reply(
- endpoint_t who,
- message *m_out /* report result */
-)
-{
- if (OK != ipc_send(who, m_out)) /* send the message */
- lpuffs_debug("libpuffs(%d) was unable to send reply\n", sef_self());
+ }
+ if (msg->m_source == VFS_PROC_NR)
+ break;
+ lpuffs_debug("libpuffs: unexpected source %d\n", msg->m_source);
+ }
- last_request_transid = 0;
+ return r;
}
#endif /* defined(__minix) */
#if defined(__minix)
/* MINIX fields */
char pn_mountpoint; /* true if mounted on */
- int pn_count; /* # times inode used */
+ unsigned int pn_count; /* # times inode used */
#endif /* defined(__minix) */
};
#define PUFFS_NODE_REMOVED 0x01 /* not on entry list */
#if defined(__minix)
-/* XXX: MINIX */
-#define IGN_PERM 0
-#define CHK_PERM 1
-#define SU_UID ((uid_t) 0) /* super_user's uid_t */
-
/* XXX: MINIX */
#define ATIME 002 /* set if atime field needs updating */
#define CTIME 004 /* set if ctime field needs updating */
#define MTIME 010 /* set if mtime field needs updating */
-#define REQ_READ_SUPER 28
-
-#define NUL(str,l,m) mfs_nul_f(__FILE__,__LINE__,(str), (l), (m))
-
#else
extern pthread_mutex_t pu_lock;
#define PU_LOCK() pthread_mutex_lock(&pu_lock)
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
-#include <minix/com.h>
-#include <minix/u64.h>
-#include <minix/vfsif.h>
#include <assert.h>
#include <sys/param.h>
#define GETDENTS_BUFSIZ 4096
static char getdents_buf[GETDENTS_BUFSIZ];
-#define RW_BUFSIZ (128 << 10)
+#define RW_BUFSIZ (128 * 1024)
static char rw_buf[RW_BUFSIZ];
/*===========================================================================*
- * fs_readwrite *
+ * fs_read *
*===========================================================================*/
-int fs_readwrite(void)
+ssize_t fs_read(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
+ off_t pos, int call)
{
- int r = OK, rw_flag;
- cp_grant_id_t gid;
- off_t pos;
- size_t nrbytes, bytes_left, bytes_done = 0;
+ int r;
+ size_t bytes_left, bytes_done;
struct puffs_node *pn;
- struct vattr va;
PUFFS_MAKECRED(pcr, &global_kcred);
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_readwrite.inode)) == NULL) {
- lpuffs_debug("walk failed...\n");
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) {
+ lpuffs_debug("walk failed...\n");
return(EINVAL);
}
- /* Get the values from the request message */
- rw_flag = (fs_m_in.m_type == REQ_READ ? READING : WRITING);
- gid = fs_m_in.m_vfs_fs_readwrite.grant;
- pos = fs_m_in.m_vfs_fs_readwrite.seek_pos;
- nrbytes = bytes_left = fs_m_in.m_vfs_fs_readwrite.nbytes;
-
- if (nrbytes > RW_BUFSIZ)
- nrbytes = bytes_left = RW_BUFSIZ;
-
- memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
+ if (bytes > sizeof(rw_buf))
+ bytes = sizeof(rw_buf);
+ bytes_left = bytes;
- if (rw_flag == READING) {
- if (global_pu->pu_ops.puffs_node_read == NULL)
- return(EINVAL);
+ if (global_pu->pu_ops.puffs_node_read == NULL)
+ return(EINVAL);
- r = global_pu->pu_ops.puffs_node_read(global_pu, pn, (uint8_t *)rw_buf,
- pos, &bytes_left, pcr, 0);
- if (r) {
- lpuffs_debug("puffs_node_read failed\n");
- return(EINVAL);
- }
-
- bytes_done = nrbytes - bytes_left;
- if (bytes_done) {
- r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) 0,
- (vir_bytes) rw_buf, bytes_done);
- update_timens(pn, ATIME, NULL);
- }
- } else if (rw_flag == WRITING) {
- /* At first try to change vattr */
- if (global_pu->pu_ops.puffs_node_setattr == NULL)
- return(EINVAL);
-
- puffs_vattr_null(&va);
- if ((u_quad_t)(pos + bytes_left) > pn->pn_va.va_size)
- va.va_size = bytes_left + pos;
- va.va_ctime = va.va_mtime = clock_timespec();
- va.va_atime = pn->pn_va.va_atime;
-
- r = global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr);
- if (r) return(EINVAL);
-
- r = sys_safecopyfrom(VFS_PROC_NR, gid, (vir_bytes) 0,
- (vir_bytes) rw_buf, nrbytes);
- if (r != OK) return(EINVAL);
-
- if (global_pu->pu_ops.puffs_node_write == NULL)
- return(EINVAL);
-
- r = global_pu->pu_ops.puffs_node_write(global_pu, pn, (uint8_t *)rw_buf,
+ r = global_pu->pu_ops.puffs_node_read(global_pu, pn, (uint8_t *)rw_buf,
pos, &bytes_left, pcr, 0);
- bytes_done = nrbytes - bytes_left;
+ if (r) {
+ lpuffs_debug("puffs_node_read failed\n");
+ return(EINVAL);
}
- if (r != OK) return(EINVAL);
+ bytes_done = bytes - bytes_left;
- fs_m_out.m_fs_vfs_readwrite.seek_pos = pos + bytes_done;
- fs_m_out.m_fs_vfs_readwrite.nbytes = bytes_done;
+ if (bytes_done > 0) {
+ if ((r = fsdriver_copyout(data, 0, rw_buf, bytes_done)) != OK)
+ return r;
+ update_timens(pn, ATIME, NULL);
+ }
- return(r);
+ return (ssize_t)bytes_done;
}
/*===========================================================================*
- * fs_breadwrite *
+ * fs_write *
*===========================================================================*/
-int fs_breadwrite(void)
+ssize_t fs_write(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
+ off_t pos, int call)
{
- /* We do not support breads/writes */
- panic("bread write requested, but FS doesn't support it!\n");
- return(OK);
+ int r;
+ size_t bytes_left;
+ struct puffs_node *pn;
+ struct vattr va;
+ PUFFS_MAKECRED(pcr, &global_kcred);
+
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) {
+ lpuffs_debug("walk failed...\n");
+ return(EINVAL);
+ }
+
+ if (bytes > sizeof(rw_buf))
+ bytes = sizeof(rw_buf);
+ bytes_left = bytes;
+
+ /* At first try to change vattr */
+ if (global_pu->pu_ops.puffs_node_setattr == NULL)
+ return(EINVAL);
+
+ puffs_vattr_null(&va);
+ if ((u_quad_t)(pos + bytes_left) > pn->pn_va.va_size)
+ va.va_size = bytes_left + pos;
+ va.va_ctime = va.va_mtime = clock_timespec();
+ va.va_atime = pn->pn_va.va_atime;
+
+ r = global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr);
+ if (r) return(EINVAL);
+
+ if ((r = fsdriver_copyin(data, 0, rw_buf, bytes)) != OK)
+ return r;
+
+ if (global_pu->pu_ops.puffs_node_write == NULL)
+ return(EINVAL);
+
+ r = global_pu->pu_ops.puffs_node_write(global_pu, pn, (uint8_t *)rw_buf,
+ pos, &bytes_left, pcr, 0);
+ if (r != OK) return(EINVAL);
+
+ return (ssize_t)(bytes - bytes_left);
}
/*===========================================================================*
* fs_getdents *
*===========================================================================*/
-int fs_getdents(void)
+ssize_t fs_getdents(ino_t ino_nr, struct fsdriver_data *data, size_t bytes,
+ off_t *pos)
{
int r;
register struct puffs_node *pn;
- ino_t ino;
- cp_grant_id_t gid;
- size_t size, buf_left;
- off_t pos;
+ size_t buf_left, written;
struct dirent *dent;
int eofflag = 0;
- size_t written;
PUFFS_MAKECRED(pcr, &global_kcred);
- ino = fs_m_in.m_vfs_fs_getdents.inode;
- gid = fs_m_in.m_vfs_fs_getdents.grant;
- size = buf_left = fs_m_in.m_vfs_fs_getdents.mem_size;
- pos = fs_m_in.m_vfs_fs_getdents.seek_pos;
-
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino)) == NULL) {
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) {
lpuffs_debug("walk failed...\n");
return(EINVAL);
}
- if (GETDENTS_BUFSIZ < size)
- size = buf_left = GETDENTS_BUFSIZ;
- memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
+ if (bytes > sizeof(getdents_buf))
+ bytes = sizeof(getdents_buf);
+ memset(getdents_buf, 0, sizeof(getdents_buf)); /* Avoid leaking any data */
+
+ buf_left = bytes;
dent = (struct dirent*) getdents_buf;
- r = global_pu->pu_ops.puffs_node_readdir(global_pu, pn, dent, &pos,
+ r = global_pu->pu_ops.puffs_node_readdir(global_pu, pn, dent, pos,
&buf_left, pcr, &eofflag, 0, 0);
if (r) {
lpuffs_debug("puffs_node_readdir returned error\n");
return(EINVAL);
}
- assert(buf_left <= size);
- written = size - buf_left;
+ assert(buf_left <= bytes);
+ written = bytes - buf_left;
if (written == 0 && !eofflag) {
lpuffs_debug("The user's buffer is too small\n");
}
if (written) {
- r = sys_safecopyto(VFS_PROC_NR, gid, (vir_bytes) 0,
- (vir_bytes) getdents_buf, written);
- if (r != OK) return(r);
+ if ((r = fsdriver_copyout(data, 0, getdents_buf, written)) != OK)
+ return r;
}
update_timens(pn, ATIME, NULL);
- fs_m_out.m_fs_vfs_getdents.nbytes = written;
- fs_m_out.m_fs_vfs_getdents.seek_pos = pos;
-
- return(OK);
+ /* The puffs readdir call has already updated the position. */
+ return written;
}
#include "fs.h"
#include <sys/stat.h>
#include <sys/statvfs.h>
-#include <minix/vfsif.h>
#include "puffs.h"
#include "puffs_priv.h"
/*===========================================================================*
* fs_stat *
*===========================================================================*/
-int fs_stat(void)
+int fs_stat(ino_t ino_nr, struct stat *statbuf)
{
- register int r; /* return value */
register struct puffs_node *pn; /* target pnode */
struct vattr va;
- struct stat statbuf;
mode_t mo;
int s;
PUFFS_MAKECRED(pcr, &global_kcred);
return(EINVAL);
}
- if ((pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_stat.inode)) == NULL) {
+ if ((pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL) {
lpuffs_debug("walk failed...\n");
return(EINVAL);
}
/* true iff special */
s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL);
- statbuf.st_dev = fs_dev;
- statbuf.st_ino = va.va_fileid;
- statbuf.st_mode = va.va_mode;
- statbuf.st_nlink = va.va_nlink;
- statbuf.st_uid = va.va_uid;
- statbuf.st_gid = va.va_gid;
- statbuf.st_rdev = (s ? va.va_rdev : NO_DEV);
- statbuf.st_size = va.va_size;
- statbuf.st_atimespec = va.va_atime;
- statbuf.st_mtimespec = va.va_mtime;
- statbuf.st_ctimespec = va.va_ctime;
-
- statbuf.st_birthtimespec = va.va_birthtime;
- statbuf.st_blksize = va.va_blocksize;
- statbuf.st_blocks = va.va_bytes / va.va_blocksize;
- statbuf.st_flags = va.va_flags;
- statbuf.st_gen = va.va_gen;
-
- /* Copy the struct to user space. */
- r = sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_stat.grant,
- (vir_bytes) 0, (vir_bytes) &statbuf,
- (size_t) sizeof(statbuf));
-
- return(r);
+ statbuf->st_dev = fs_dev;
+ statbuf->st_ino = va.va_fileid;
+ statbuf->st_mode = va.va_mode;
+ statbuf->st_nlink = va.va_nlink;
+ statbuf->st_uid = va.va_uid;
+ statbuf->st_gid = va.va_gid;
+ statbuf->st_rdev = (s ? va.va_rdev : NO_DEV);
+ statbuf->st_size = va.va_size;
+ statbuf->st_atimespec = va.va_atime;
+ statbuf->st_mtimespec = va.va_mtime;
+ statbuf->st_ctimespec = va.va_ctime;
+
+ statbuf->st_birthtimespec = va.va_birthtime;
+ statbuf->st_blksize = va.va_blocksize;
+ statbuf->st_blocks = va.va_bytes / va.va_blocksize;
+ statbuf->st_flags = va.va_flags;
+ statbuf->st_gen = va.va_gen;
+
+ return(OK);
}
/*===========================================================================*
* fs_statvfs *
*===========================================================================*/
-int fs_statvfs(void)
+int fs_statvfs(struct statvfs *st)
{
- int r;
- struct statvfs st;
- memset(&st, 0, sizeof(st));
-
- if (global_pu->pu_ops.puffs_fs_statvfs(global_pu, &st) != 0) {
+ if (global_pu->pu_ops.puffs_fs_statvfs(global_pu, st) != 0) {
lpuffs_debug("statvfs failed\n");
return(EINVAL);
}
- /* XXX libpuffs doesn't truncate filenames and returns ENAMETOOLONG,
- * though some servers would like to behave differently.
- * See subtest 2.18-19 of test23 and test/common.c:does_fs_truncate().
- */
- st.f_flag |= ST_NOTRUNC;
-
- /* Copy the struct to user space. */
- r = sys_safecopyto(fs_m_in.m_source, fs_m_in.m_vfs_fs_statvfs.grant, 0,
- (vir_bytes) &st, (phys_bytes) sizeof(st));
+ /* libpuffs doesn't truncate filenames */
+ st->f_flag |= ST_NOTRUNC;
- return(r);
+ return(OK);
}
#include "fs.h"
-int (*fs_call_vec[])(void) = {
- no_sys, /* 0 not used */
- no_sys, /* 1 */ /* Was: fs_getnode */
- fs_putnode, /* 2 */
- fs_slink, /* 3 */
- fs_ftrunc, /* 4 */
- fs_chown, /* 5 */
- fs_chmod, /* 6 */
- fs_inhibread, /* 7 */
- fs_stat, /* 8 */
- fs_utime, /* 9 */
- fs_statvfs, /* 10 */
- fs_breadwrite, /* 11 */
- fs_breadwrite, /* 12 */
- fs_unlink, /* 13 */
- fs_unlink, /* 14 */
- fs_unmount, /* 15 */
- fs_sync, /* 16 */
- fs_new_driver, /* 17 */
- fs_flush, /* 18 */
- fs_readwrite, /* 19 */
- fs_readwrite, /* 20 */
- fs_mknod, /* 21 */
- fs_mkdir, /* 22 */
- fs_create, /* 23 */
- fs_link, /* 24 */
- fs_rename, /* 25 */
- fs_lookup, /* 26 */
- fs_mountpoint, /* 27 */
- fs_readsuper, /* 28 */
- no_sys, /* 29 */ /* Was: fs_newnode */
- fs_rdlink, /* 30 */
- fs_getdents, /* 31 */
- no_sys, /* 32 peek */
- no_sys, /* 33 bpeek */
+struct fsdriver puffs_table = {
+ .fdr_mount = fs_mount,
+ .fdr_unmount = fs_unmount,
+ .fdr_lookup = fs_lookup,
+ .fdr_putnode = fs_putnode,
+ .fdr_read = fs_read,
+ .fdr_write = fs_write,
+ .fdr_getdents = fs_getdents,
+ .fdr_trunc = fs_trunc,
+ .fdr_create = fs_create,
+ .fdr_mkdir = fs_mkdir,
+ .fdr_mknod = fs_mknod,
+ .fdr_link = fs_link,
+ .fdr_unlink = fs_unlink,
+ .fdr_rmdir = fs_unlink,
+ .fdr_rename = fs_rename,
+ .fdr_slink = fs_slink,
+ .fdr_rdlink = fs_rdlink,
+ .fdr_stat = fs_stat,
+ .fdr_chown = fs_chown,
+ .fdr_chmod = fs_chmod,
+ .fdr_utime = fs_utime,
+ .fdr_mountpt = fs_mountpt,
+ .fdr_statvfs = fs_statvfs,
+ .fdr_sync = fs_sync
};
*/
#include "fs.h"
-#include <minix/callnr.h>
-#include <minix/com.h>
-#include <minix/vfsif.h>
-
#include "puffs.h"
#include "puffs_priv.h"
/*===========================================================================*
* fs_utime *
*===========================================================================*/
-int fs_utime(void)
+int fs_utime(ino_t ino_nr, struct timespec *atime, struct timespec *mtime)
{
struct puffs_node *pn;
struct vattr va;
PUFFS_MAKECRED(pcr, &global_kcred);
- if (is_readonly_fs)
- return(EROFS);
-
if (global_pu->pu_ops.puffs_node_setattr == NULL)
return(EINVAL);
- if( (pn = puffs_pn_nodewalk(global_pu, 0, &fs_m_in.m_vfs_fs_utime.inode)) == NULL)
+ if( (pn = puffs_pn_nodewalk(global_pu, 0, &ino_nr)) == NULL)
return(EINVAL);
-
+
+ /* FIXME: shouldn't this check the special UTIME_ values? */
puffs_vattr_null(&va);
- va.va_atime.tv_sec = fs_m_in.m_vfs_fs_utime.actime;
- va.va_atime.tv_nsec = fs_m_in.m_vfs_fs_utime.acnsec;
- va.va_mtime.tv_sec = fs_m_in.m_vfs_fs_utime.modtime;
- va.va_mtime.tv_nsec = fs_m_in.m_vfs_fs_utime.modnsec;
+ va.va_atime = *atime;
+ va.va_mtime = *mtime;
va.va_ctime = clock_timespec();
if (global_pu->pu_ops.puffs_node_setattr(global_pu, pn, &va, pcr) != 0)
#include "puffs_priv.h"
-/*===========================================================================*
- * no_sys *
- *===========================================================================*/
-int no_sys(void)
-{
-/* Somebody has used an illegal system call number */
- lpuffs_debug("no_sys: invalid call %d\n", req_nr);
- return(EINVAL);
-}
-
-
-/*===========================================================================*
- * mfs_nul *
- *===========================================================================*/
-void mfs_nul_f(const char *file, int line, char *str, unsigned int len,
- unsigned int maxlen)
-{
- if (len < maxlen && str[len-1] != '\0') {
- lpuffs_debug("%s:%d string (length %d,maxlen %d) not null-terminated\n",
- file, line, len, maxlen);
- }
-}
-
-
/*===========================================================================*
* clock_timespec *
*===========================================================================*/