From 81db4f2cff1f4a2dcfe4623b0e9d9d41072b9672 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Sun, 24 Aug 2014 09:51:35 +0000 Subject: [PATCH] libpuffs: use libfsdriver Change-Id: I26651578066e1098dc275a9cfbe5710870a13811 --- lib/libpuffs/Makefile | 1 - lib/libpuffs/fs.h | 3 +- lib/libpuffs/glo.h | 24 +- lib/libpuffs/inode.c | 17 +- lib/libpuffs/link.c | 202 +++++------------ lib/libpuffs/misc.c | 39 +--- lib/libpuffs/mount.c | 52 ++--- lib/libpuffs/open.c | 156 ++++--------- lib/libpuffs/path.c | 454 +++----------------------------------- lib/libpuffs/pnode.c | 4 - lib/libpuffs/protect.c | 102 ++------- lib/libpuffs/proto.h | 74 +++---- lib/libpuffs/puffs.c | 155 +++---------- lib/libpuffs/puffs.h | 2 +- lib/libpuffs/puffs_priv.h | 9 - lib/libpuffs/read.c | 178 +++++++-------- lib/libpuffs/stadir.c | 67 ++---- lib/libpuffs/table.c | 60 +++-- lib/libpuffs/time.c | 20 +- lib/libpuffs/utility.c | 24 -- 20 files changed, 398 insertions(+), 1245 deletions(-) diff --git a/lib/libpuffs/Makefile b/lib/libpuffs/Makefile index 138d7a504..1c29729fd 100644 --- a/lib/libpuffs/Makefile +++ b/lib/libpuffs/Makefile @@ -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 diff --git a/lib/libpuffs/fs.h b/lib/libpuffs/fs.h index 15b076144..d7ac39298 100644 --- a/lib/libpuffs/fs.h +++ b/lib/libpuffs/fs.h @@ -14,7 +14,6 @@ #include #include #include -#include #include #include @@ -23,6 +22,8 @@ #include #include +#include + #include "proto.h" #include "glo.h" diff --git a/lib/libpuffs/glo.h b/lib/libpuffs/glo.h index b38c76346..6e4645216 100644 --- a/lib/libpuffs/glo.h +++ b/lib/libpuffs/glo.h @@ -8,48 +8,30 @@ #define EXTERN #endif -#include - #include 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 */ diff --git a/lib/libpuffs/inode.c b/lib/libpuffs/inode.c index 629ea8dca..e62149dc7 100644 --- a/lib/libpuffs/inode.c +++ b/lib/libpuffs/inode.c @@ -6,7 +6,6 @@ #include "fs.h" #include #include -#include #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); diff --git a/lib/libpuffs/link.c b/lib/libpuffs/link.c index 99740ade2..a3bb7991d 100644 --- a/lib/libpuffs/link.c +++ b/lib/libpuffs/link.c @@ -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, - ©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 */ @@ -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); diff --git a/lib/libpuffs/misc.c b/lib/libpuffs/misc.c index 9b80632a2..f58c225ed 100644 --- a/lib/libpuffs/misc.c +++ b/lib/libpuffs/misc.c @@ -4,7 +4,6 @@ #include "fs.h" #include -#include #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); } diff --git a/lib/libpuffs/mount.c b/lib/libpuffs/mount.c index 036c5bd90..05272e9f8 100644 --- a/lib/libpuffs/mount.c +++ b/lib/libpuffs/mount.c @@ -5,44 +5,45 @@ #include "fs.h" #include #include -#include -#include -#include #include #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); } diff --git a/lib/libpuffs/open.c b/lib/libpuffs/open.c index e516dfcb7..855bc27a6 100644 --- a/lib/libpuffs/open.c +++ b/lib/libpuffs/open.c @@ -3,11 +3,8 @@ */ #include "fs.h" -#include #include #include -#include -#include #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); -} diff --git a/lib/libpuffs/path.c b/lib/libpuffs/path.c index eece52592..76a4de60b 100644 --- a/lib/libpuffs/path.c +++ b/lib/libpuffs/path.c @@ -18,339 +18,42 @@ #include #include -#include -#include -#include - #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/ or - * /already/processed/path//not/yet/processed/path - * After expanding the , the path will look like - * or - * /not/yet/processed - * In both cases user_path must have enough room to hold . - * However, in the latter case we have to move /not/yet/processed to the - * right place first, before we expand . When strlen() is - * smaller than strlen(/already/processes/path), we move the suffix to the - * left. Is strlen() 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 , we have to move the 'suffix' - * to the right place. - */ - if (slen + llen + 1 > sizeof(user_path)) - return(ENAMETOOLONG);/* +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); /* + \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); -} diff --git a/lib/libpuffs/pnode.c b/lib/libpuffs/pnode.c index b82830915..49438cf96 100644 --- a/lib/libpuffs/pnode.c +++ b/lib/libpuffs/pnode.c @@ -39,10 +39,6 @@ __RCSID("$NetBSD: pnode.c,v 1.13 2012/08/16 09:25:43 manu Exp $"); #include #include "puffs_priv.h" -#if defined(__minix) -#include -#include "proto.h" -#endif /* defined(__minix) */ /* * Well, you're probably wondering why this isn't optimized. diff --git a/lib/libpuffs/protect.c b/lib/libpuffs/protect.c index 6a127f513..818180692 100644 --- a/lib/libpuffs/protect.c +++ b/lib/libpuffs/protect.c @@ -3,43 +3,37 @@ */ #include "fs.h" -#include #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); -} diff --git a/lib/libpuffs/proto.h b/lib/libpuffs/proto.h index 10ecfcd49..e67b7b4a4 100644 --- a/lib/libpuffs/proto.h +++ b/lib/libpuffs/proto.h @@ -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 */ diff --git a/lib/libpuffs/puffs.c b/lib/libpuffs/puffs.c index 1d5bfe32c..d419631f9 100644 --- a/lib/libpuffs/puffs.c +++ b/lib/libpuffs/puffs.c @@ -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 -#include #endif /* defined(__minix) */ #include @@ -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) */ diff --git a/lib/libpuffs/puffs.h b/lib/libpuffs/puffs.h index 7e8817574..9b165b8f0 100644 --- a/lib/libpuffs/puffs.h +++ b/lib/libpuffs/puffs.h @@ -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 */ diff --git a/lib/libpuffs/puffs_priv.h b/lib/libpuffs/puffs_priv.h index 4eaa14dbf..39bc9826d 100644 --- a/lib/libpuffs/puffs_priv.h +++ b/lib/libpuffs/puffs_priv.h @@ -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) diff --git a/lib/libpuffs/read.c b/lib/libpuffs/read.c index 84ee644b6..f7484033d 100644 --- a/lib/libpuffs/read.c +++ b/lib/libpuffs/read.c @@ -7,9 +7,6 @@ #include #include #include -#include -#include -#include #include #include @@ -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; } diff --git a/lib/libpuffs/stadir.c b/lib/libpuffs/stadir.c index 291b098c4..a5be843bb 100644 --- a/lib/libpuffs/stadir.c +++ b/lib/libpuffs/stadir.c @@ -5,7 +5,6 @@ #include "fs.h" #include #include -#include #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); } diff --git a/lib/libpuffs/table.c b/lib/libpuffs/table.c index d00ede2c4..90f5a48b9 100644 --- a/lib/libpuffs/table.c +++ b/lib/libpuffs/table.c @@ -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 }; diff --git a/lib/libpuffs/time.c b/lib/libpuffs/time.c index e752036f9..bc57ab07a 100644 --- a/lib/libpuffs/time.c +++ b/lib/libpuffs/time.c @@ -3,10 +3,6 @@ */ #include "fs.h" -#include -#include -#include - #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) diff --git a/lib/libpuffs/utility.c b/lib/libpuffs/utility.c index 2f41cb76a..e4607344b 100644 --- a/lib/libpuffs/utility.c +++ b/lib/libpuffs/utility.c @@ -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 * *===========================================================================*/