libpuffs: use libfsdriver

Change-Id: I26651578066e1098dc275a9cfbe5710870a13811
This commit is contained in:
David van Moolenbroek 2014-08-24 09:51:35 +00:00
parent a99c939dee
commit 81db4f2cff
20 changed files with 398 additions and 1245 deletions

View file

@ -25,7 +25,6 @@ SRCS+= inode.c link.c misc.c mount.c open.c path.c path_puffs.c \
CPPFLAGS+= -D_MINIX_SYSTEM
NOGCCERROR=yes
NOCLANGERROR=yes
.endif # defined(__MINIX)
.include <bsd.lib.mk>

View file

@ -14,7 +14,6 @@
#include <sys/types.h>
#include <minix/const.h>
#include <minix/type.h>
#include <minix/dmap.h>
#include <lib.h>
#include <limits.h>
@ -23,6 +22,8 @@
#include <minix/syslib.h>
#include <minix/sysutil.h>
#include <minix/fsdriver.h>
#include "proto.h"
#include "glo.h"

View file

@ -8,48 +8,30 @@
#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 */

View file

@ -6,7 +6,6 @@
#include "fs.h"
#include <string.h>
#include <assert.h>
#include <minix/vfsif.h>
#include "puffs.h"
#include "puffs_priv.h"
@ -31,22 +30,20 @@ void release_node(struct puffs_usermount *pu, struct puffs_node *pn)
/*===========================================================================*
* 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;
}
@ -55,8 +52,8 @@ int fs_putnode(void)
}
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");
}
@ -82,7 +79,9 @@ int fs_putnode(void)
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);

View file

@ -6,25 +6,19 @@
#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;
@ -68,13 +62,11 @@ int fs_ftrunc(void)
/*===========================================================================*
* 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;
@ -84,28 +76,18 @@ int fs_link(void)
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) {
@ -114,7 +96,7 @@ int fs_link(void)
}
/* 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 {
@ -124,9 +106,9 @@ int fs_link(void)
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)
@ -152,20 +134,17 @@ int fs_link(void)
/*===========================================================================*
* 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))
@ -174,26 +153,23 @@ int fs_rdlink(void)
if (global_pu->pu_ops.puffs_node_readlink == NULL)
return(EINVAL);
r = global_pu->pu_ops.puffs_node_readlink(global_pu, pn, pcr, path,
&copylen);
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 */
@ -207,55 +183,35 @@ int fs_rename(void)
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 */
@ -264,14 +220,11 @@ int fs_rename(void)
}
/* 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 */
@ -280,42 +233,25 @@ int fs_rename(void)
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
@ -372,7 +308,6 @@ int fs_rename(void)
}
}
rename_out:
cur_time = clock_timespec();
update_timens(old_dirp, MTIME | CTIME, &cur_time);
update_timens(new_dirp, MTIME | CTIME, &cur_time);
@ -391,13 +326,12 @@ static int unlink_file(struct puffs_node *dirp, struct puffs_node *pn,
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;
@ -405,43 +339,28 @@ int fs_unlink(void)
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);
pcn.pcn_namelen = strlen(name);
assert(pcn.pcn_namelen <= NAME_MAX);
strcpy(pcn.pcn_name, name);
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)
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 */
}
@ -502,9 +421,6 @@ static int remove_dir(
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' */
@ -541,7 +457,7 @@ static int unlink_file(
return(EINVAL);
if (S_ISDIR(pn->pn_va.va_mode))
return(EINVAL);
return(EPERM);
if (buildpath) {
r = puffs_path_pcnbuild(global_pu, pcn, dirp);

View file

@ -4,7 +4,6 @@
#include "fs.h"
#include <assert.h>
#include <minix/vfsif.h>
#include "puffs.h"
#include "puffs_priv.h"
@ -12,7 +11,7 @@
/*===========================================================================*
* 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.
@ -21,44 +20,10 @@ int fs_sync(void)
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);
}

View file

@ -5,44 +5,45 @@
#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.
@ -51,15 +52,9 @@ int fs_mountpoint(void)
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. */
@ -76,14 +71,13 @@ int fs_mountpoint(void)
/*===========================================================================*
* 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");
}
@ -92,8 +86,6 @@ int fs_unmount(void)
/* Finish off the unmount. */
PU_SETSTATE(global_pu, PUFFS_STATE_UNMOUNTED);
unmountdone = TRUE;
mounted = FALSE;
global_pu->pu_pn_root->pn_count--;
return(OK);
}

View file

@ -3,11 +3,8 @@
*/
#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"
@ -16,44 +13,31 @@
/*===========================================================================*
* 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));
@ -63,9 +47,9 @@ int fs_create(void)
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) {
@ -99,13 +83,12 @@ int fs_create(void)
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);
}
@ -114,7 +97,8 @@ int fs_create(void)
/*===========================================================================*
* 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;
@ -125,30 +109,19 @@ int fs_mknod(void)
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));
@ -158,10 +131,10 @@ int fs_mknod(void)
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) {
@ -197,7 +170,7 @@ int fs_mknod(void)
/*===========================================================================*
* 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;
@ -208,30 +181,19 @@ int fs_mkdir(void)
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();
@ -241,9 +203,9 @@ int fs_mkdir(void)
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) {
@ -280,7 +242,8 @@ int fs_mkdir(void)
/*===========================================================================*
* 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 */
@ -291,34 +254,22 @@ int fs_slink(void)
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;
if (strlen(target) != (size_t) fs_m_in.m_vfs_fs_slink.mem_size) {
target[bytes] = '\0';
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
@ -330,7 +281,7 @@ int fs_slink(void)
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));
@ -339,8 +290,8 @@ int fs_slink(void)
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) {
@ -367,12 +318,3 @@ int fs_slink(void)
return(r);
}
/*===========================================================================*
* fs_inhibread *
*===========================================================================*/
int fs_inhibread(void)
{
return(OK);
}

View file

@ -18,339 +18,42 @@
#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 *
* fs_lookup *
*===========================================================================*/
int fs_lookup(void)
int fs_lookup(ino_t dir_nr, char *name, struct fsdriver_node *node,
int *is_mountpt)
{
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 *
*===========================================================================*/
static int parse_path(
ino_t dir_ino,
ino_t root_ino,
int flags,
struct puffs_node **res_inop,
size_t *offsetp,
int *symlinkp
)
{
/* 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);
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");
}
/* 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 */
/* Set terminating nul */
user_path[llen]= '\0';
}
/* Everything is set, now copy the expanded link to user_path */
memmove(user_path, sp, llen);
if (!S_ISDIR(pn_dir->pn_va.va_mode))
return ENOTDIR;
return(OK);
if ((pn = advance(pn_dir, name)) == NULL)
return err_code;
pn->pn_count++; /* open pnode */
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;
*is_mountpt = pn->pn_mountpoint;
return OK;
}
@ -359,9 +62,7 @@ static int ltraverse(
*===========================================================================*/
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
@ -382,6 +83,8 @@ struct puffs_node *advance(
dev_t rdev;
int error;
assert(pn_dir != NULL);
err_code = OK;
/* If 'string' is empty, return an error. */
@ -390,16 +93,10 @@ struct puffs_node *advance(
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) {
@ -407,10 +104,13 @@ struct puffs_node *advance(
* 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;
}
@ -433,8 +133,7 @@ struct puffs_node *advance(
}
/* 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) {
@ -459,96 +158,11 @@ struct puffs_node *advance(
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;
}
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;
}
}
}
}
/* 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;
}
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);
}

View file

@ -39,10 +39,6 @@ __RCSID("$NetBSD: pnode.c,v 1.13 2012/08/16 09:25:43 manu Exp $");
#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.

View file

@ -3,43 +3,37 @@
*/
#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);
}
@ -48,94 +42,26 @@ int fs_chmod(void)
/*===========================================================================*
* 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);
}

View file

@ -7,68 +7,64 @@ struct timespec;
/* 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 */

View file

@ -39,8 +39,6 @@ __RCSID("$NetBSD: puffs.c,v 1.117 2011/11/14 01:27:42 chs Exp $");
#if defined(__minix)
#include "fs.h"
#include <minix/endpoint.h>
#include <minix/vfsif.h>
#endif /* defined(__minix) */
#include <assert.h>
@ -69,10 +67,13 @@ const struct mntopt puffsmopts[] = {
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);
@ -126,7 +127,8 @@ int __wrap_main(int argc, char *argv[])
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);
}
@ -419,43 +421,16 @@ puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags,
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;
/* Process the already-received mount request. */
fsdriver_process(&puffs_table, &fs_msg, fs_ipc_status, FALSE);
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);
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;
}
@ -466,7 +441,7 @@ puffs_mount(struct puffs_usermount *pu, const char *dir, int mntflags,
/*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;
@ -492,7 +467,7 @@ _puffs_init(int dummy, struct puffs_ops *pops, const char *mntfromname,
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);
@ -584,11 +559,8 @@ void
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.
*/
@ -604,32 +576,11 @@ puffs__theloop(struct puffs_cc *pcc)
}
/* 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)
@ -718,69 +669,27 @@ static void sef_cb_signal_handler(int signo)
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 (msg->m_source == VFS_PROC_NR)
break;
lpuffs_debug("libpuffs: unexpected source %d\n", msg->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());
last_request_transid = 0;
return r;
}
#endif /* defined(__minix) */

View file

@ -93,7 +93,7 @@ struct puffs_node {
#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 */

View file

@ -39,20 +39,11 @@
#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)

View file

@ -7,9 +7,6 @@
#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>
@ -20,143 +17,135 @@
#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 (bytes > sizeof(rw_buf))
bytes = sizeof(rw_buf);
bytes_left = bytes;
if (nrbytes > RW_BUFSIZ)
nrbytes = bytes_left = RW_BUFSIZ;
if (global_pu->pu_ops.puffs_node_read == NULL)
return(EINVAL);
memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
if (rw_flag == READING) {
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,
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,
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");
@ -164,15 +153,12 @@ int fs_getdents(void)
}
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;
}

View file

@ -5,7 +5,6 @@
#include "fs.h"
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <minix/vfsif.h>
#include "puffs.h"
#include "puffs_priv.h"
@ -14,12 +13,10 @@
/*===========================================================================*
* 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);
@ -29,7 +26,7 @@ int fs_stat(void)
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);
}
@ -48,57 +45,41 @@ int fs_stat(void)
/* 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_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;
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);
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;
/* libpuffs doesn't truncate filenames */
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));
return(r);
return(OK);
}

View file

@ -9,39 +9,29 @@
#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
};

View file

@ -3,10 +3,6 @@
*/
#include "fs.h"
#include <minix/callnr.h>
#include <minix/com.h>
#include <minix/vfsif.h>
#include "puffs.h"
#include "puffs_priv.h"
@ -14,26 +10,22 @@
/*===========================================================================*
* 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)

View file

@ -11,30 +11,6 @@
#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 *
*===========================================================================*/