340 lines
9.2 KiB
C
340 lines
9.2 KiB
C
/* This file contains the code for performing four system calls relating to
|
|
* status and directories.
|
|
*
|
|
* The entry points into this file are
|
|
* do_chdir: perform the CHDIR system call
|
|
* do_chroot: perform the CHROOT system call
|
|
* do_stat: perform the STAT system call
|
|
* do_fstat: perform the FSTAT system call
|
|
* do_fstatfs: perform the FSTATFS system call
|
|
* do_lstat: perform the LSTAT system call
|
|
*
|
|
* Changes for VFS:
|
|
* Jul 2006 (Balazs Gerofi)
|
|
*/
|
|
|
|
#include "fs.h"
|
|
#include <sys/stat.h>
|
|
#include <sys/statfs.h>
|
|
#include <minix/com.h>
|
|
#include <minix/u64.h>
|
|
#include <string.h>
|
|
#include "file.h"
|
|
#include "fproc.h"
|
|
#include "param.h"
|
|
|
|
#include <minix/vfsif.h>
|
|
#include "vnode.h"
|
|
#include "vmnt.h"
|
|
|
|
FORWARD _PROTOTYPE( int change, (struct vnode **iip, char *name_ptr, int len));
|
|
FORWARD _PROTOTYPE( int change_into, (struct vnode **iip, struct vnode *vp));
|
|
|
|
/*===========================================================================*
|
|
* do_fchdir *
|
|
*===========================================================================*/
|
|
PUBLIC int do_fchdir()
|
|
{
|
|
/* Change directory on already-opened fd. */
|
|
struct filp *rfilp;
|
|
struct getdir_req req;
|
|
struct node_details res;
|
|
int r;
|
|
|
|
/* Is the file descriptor valid? */
|
|
if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
|
|
|
|
/* Is it a dir? */
|
|
if ((rfilp->filp_vno->v_mode & I_TYPE) != I_DIRECTORY)
|
|
return ENOTDIR;
|
|
|
|
/* Fill in request message fields.*/
|
|
req.fs_e = rfilp->filp_vno->v_fs_e;
|
|
req.inode_nr = rfilp->filp_vno->v_inode_nr;
|
|
req.uid = fp->fp_effuid;
|
|
req.gid = fp->fp_effgid;
|
|
|
|
/* Issue request and handle error */
|
|
if ((r = req_getdir(&req, &res)) != OK) return r;
|
|
|
|
/* GETDIR increased the counter in the FS proc */
|
|
rfilp->filp_vno->v_count++;
|
|
|
|
return change_into(&fp->fp_wd, rfilp->filp_vno);
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* do_chdir *
|
|
*===========================================================================*/
|
|
PUBLIC int do_chdir()
|
|
{
|
|
/* Change directory. This function is also called by MM to simulate a chdir
|
|
* in order to do EXEC, etc. It also changes the root directory, the uids and
|
|
* gids, and the umask.
|
|
*/
|
|
int r;
|
|
register struct fproc *rfp;
|
|
|
|
if (who_e == PM_PROC_NR) {
|
|
int slot;
|
|
if(isokendpt(m_in.endpt1, &slot) != OK)
|
|
return EINVAL;
|
|
rfp = &fproc[slot];
|
|
|
|
put_vnode(fp->fp_rd);
|
|
dup_vnode(fp->fp_rd = rfp->fp_rd);
|
|
put_vnode(fp->fp_wd);
|
|
dup_vnode(fp->fp_wd = rfp->fp_wd);
|
|
|
|
/* MM uses access() to check permissions. To make this work, pretend
|
|
* that the user's real ids are the same as the user's effective ids.
|
|
* FS calls other than access() do not use the real ids, so are not
|
|
* affected.
|
|
*/
|
|
fp->fp_realuid =
|
|
fp->fp_effuid = rfp->fp_effuid;
|
|
fp->fp_realgid =
|
|
fp->fp_effgid = rfp->fp_effgid;
|
|
fp->fp_umask = rfp->fp_umask;
|
|
return(OK);
|
|
}
|
|
|
|
/* Perform the chdir(name) system call. */
|
|
r = change(&fp->fp_wd, m_in.name, m_in.name_length);
|
|
return(r);
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* do_chroot *
|
|
*===========================================================================*/
|
|
PUBLIC int do_chroot()
|
|
{
|
|
/* Perform the chroot(name) system call. */
|
|
|
|
register int r;
|
|
|
|
if (!super_user) return(EPERM); /* only su may chroot() */
|
|
|
|
r = change(&fp->fp_rd, m_in.name, m_in.name_length);
|
|
return(r);
|
|
}
|
|
|
|
|
|
/*===========================================================================*
|
|
* change *
|
|
*===========================================================================*/
|
|
PRIVATE int change(iip, name_ptr, len)
|
|
struct vnode **iip; /* pointer to the inode pointer for the dir */
|
|
char *name_ptr; /* pointer to the directory name to change to */
|
|
int len; /* length of the directory name string */
|
|
{
|
|
/* Do the actual work for chdir() and chroot(). */
|
|
struct vnode *vp, *vp2;
|
|
struct vmnt *vmp;
|
|
struct getdir_req req;
|
|
struct node_details res;
|
|
struct lookup_req lookup_req;
|
|
int r;
|
|
|
|
if (fetch_name(name_ptr, len, M3) != OK) return(err_code);
|
|
|
|
/* See if free vnode is available */
|
|
if ((vp = get_free_vnode()) == NIL_VNODE) {
|
|
printf("VFSchange: no free vnode available\n");
|
|
return EINVAL;
|
|
}
|
|
|
|
/* Fill in lookup request fields */
|
|
lookup_req.path = user_fullpath;
|
|
lookup_req.lastc = NULL;
|
|
lookup_req.flags = EAT_PATH;
|
|
|
|
/* Request lookup */
|
|
if ((r = lookup(&lookup_req, &res)) != OK) return r;
|
|
|
|
/* Is it a dir? */
|
|
if ((res.fmode & I_TYPE) != I_DIRECTORY)
|
|
return ENOTDIR;
|
|
|
|
/* Fill in request message fields.*/
|
|
req.fs_e = res.fs_e;
|
|
req.inode_nr = res.inode_nr;
|
|
req.uid = fp->fp_effuid;
|
|
req.gid = fp->fp_effgid;
|
|
|
|
/* Issue request */
|
|
if ((r = req_getdir(&req, &res)) != OK) return r;
|
|
|
|
/* Check whether vnode is already in use or not */
|
|
if ((vp2 = find_vnode(res.fs_e, res.inode_nr))
|
|
!= NIL_VNODE) {
|
|
vp2->v_count++;
|
|
vp = vp2;
|
|
}
|
|
else {
|
|
/* Fill in the free vnode's fields */
|
|
vp->v_fs_e = res.fs_e;
|
|
vp->v_inode_nr = res.inode_nr;
|
|
vp->v_mode = res.fmode;
|
|
vp->v_size = res.fsize;
|
|
|
|
if ( (vmp = find_vmnt(vp->v_fs_e)) == NIL_VMNT)
|
|
printf("VFSchange: vmnt not found");
|
|
|
|
vp->v_vmnt = vmp;
|
|
vp->v_dev = vmp->m_dev;
|
|
vp->v_count = 1;
|
|
}
|
|
|
|
return change_into(iip, vp);
|
|
}
|
|
|
|
|
|
/*===========================================================================*
|
|
* change_into *
|
|
*===========================================================================*/
|
|
PRIVATE int change_into(iip, vp)
|
|
struct vnode **iip; /* pointer to the inode pointer for the dir */
|
|
struct vnode *vp; /* this is what the inode has to become */
|
|
{
|
|
/* Everything is OK. Make the change. */
|
|
put_vnode(*iip); /* release the old directory */
|
|
*iip = vp; /* acquire the new one */
|
|
|
|
return(OK);
|
|
}
|
|
|
|
|
|
/*===========================================================================*
|
|
* do_stat *
|
|
*===========================================================================*/
|
|
PUBLIC int do_stat()
|
|
{
|
|
/* Perform the stat(name, buf) system call. */
|
|
struct stat_req req;
|
|
struct node_details res;
|
|
struct lookup_req lookup_req;
|
|
int r;
|
|
|
|
if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
|
|
|
|
/* Fill in lookup request fields */
|
|
lookup_req.path = user_fullpath;
|
|
lookup_req.lastc = NULL;
|
|
lookup_req.flags = EAT_PATH;
|
|
|
|
/* Request lookup */
|
|
if ((r = lookup(&lookup_req, &res)) != OK) return r;
|
|
|
|
/* Fill in request message fields.*/
|
|
req.fs_e = res.fs_e;
|
|
req.who_e = who_e;
|
|
req.buf = m_in.name2;
|
|
req.inode_nr = res.inode_nr;
|
|
req.uid = fp->fp_effuid;
|
|
req.gid = fp->fp_effgid;
|
|
|
|
/* Issue request */
|
|
return req_stat(&req);
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
* do_fstat *
|
|
*===========================================================================*/
|
|
PUBLIC int do_fstat()
|
|
{
|
|
/* Perform the fstat(fd, buf) system call. */
|
|
register struct filp *rfilp;
|
|
int pipe_pos = 0;
|
|
struct stat_req req;
|
|
|
|
/* Is the file descriptor valid? */
|
|
if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) {
|
|
return(err_code);
|
|
}
|
|
|
|
/* If we read from a pipe, send position too */
|
|
if (rfilp->filp_vno->v_pipe == I_PIPE) {
|
|
if (rfilp->filp_mode & R_BIT)
|
|
if (ex64hi(rfilp->filp_pos) != 0)
|
|
{
|
|
panic(__FILE__, "do_fstat: bad position in pipe",
|
|
NO_NUM);
|
|
}
|
|
pipe_pos = ex64lo(rfilp->filp_pos);
|
|
}
|
|
|
|
/* Fill in request message */
|
|
req.fs_e = rfilp->filp_vno->v_fs_e;
|
|
req.inode_nr = rfilp->filp_vno->v_inode_nr;
|
|
req.pos = pipe_pos;
|
|
req.who_e = who_e;
|
|
req.buf = m_in.buffer;
|
|
|
|
/* Issue request */
|
|
return req_fstat(&req);
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
* do_fstatfs *
|
|
*===========================================================================*/
|
|
PUBLIC int do_fstatfs()
|
|
{
|
|
/* Perform the fstatfs(fd, buf) system call. */
|
|
register struct filp *rfilp;
|
|
struct stat_req req;
|
|
|
|
/* Is the file descriptor valid? */
|
|
if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
|
|
|
|
/* Send FS request */
|
|
req.fs_e = rfilp->filp_vno->v_fs_e;
|
|
req.inode_nr = rfilp->filp_vno->v_inode_nr;
|
|
req.who_e = who_e;
|
|
req.buf = m_in.buffer;
|
|
|
|
/* Issue request */
|
|
return req_fstatfs(&req);
|
|
}
|
|
|
|
|
|
|
|
/*===========================================================================*
|
|
* do_lstat *
|
|
*===========================================================================*/
|
|
PUBLIC int do_lstat()
|
|
{
|
|
/* Perform the lstat(name, buf) system call. */
|
|
struct stat_req req;
|
|
struct node_details res;
|
|
struct lookup_req lookup_req;
|
|
int r;
|
|
|
|
if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
|
|
|
|
/* Fill in lookup request fields */
|
|
lookup_req.path = user_fullpath;
|
|
lookup_req.lastc = NULL;
|
|
lookup_req.flags = EAT_PATH_OPAQUE;
|
|
|
|
/* Request lookup */
|
|
if ((r = lookup(&lookup_req, &res)) != OK) return r;
|
|
|
|
/* Fill in request message fields.*/
|
|
req.fs_e = res.fs_e;
|
|
req.who_e = who_e;
|
|
req.buf = m_in.name2;
|
|
req.inode_nr = res.inode_nr;
|
|
req.uid = fp->fp_effuid;
|
|
req.gid = fp->fp_effgid;
|
|
|
|
/* Issue request */
|
|
return req_stat(&req);
|
|
}
|
|
|
|
|
|
|