libpuffs: use libfsdriver
Change-Id: I26651578066e1098dc275a9cfbe5710870a13811
This commit is contained in:
parent
a99c939dee
commit
81db4f2cff
20 changed files with 398 additions and 1245 deletions
|
@ -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>
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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) */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 *
|
||||
*===========================================================================*/
|
||||
|
|
Loading…
Reference in a new issue