minix/servers/fs/stadir.c

304 lines
9.7 KiB
C
Raw Normal View History

2005-04-21 16:53:53 +02:00
/* 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
* do_rdlink: perform the RDLNK system call
2005-04-21 16:53:53 +02:00
*/
#include "fs.h"
#include <sys/stat.h>
#include <sys/statfs.h>
#include <minix/com.h>
#include <string.h>
#include "buf.h"
2005-04-21 16:53:53 +02:00
#include "file.h"
#include "fproc.h"
#include "inode.h"
#include "param.h"
#include "super.h"
FORWARD _PROTOTYPE( int change, (struct inode **iip, char *name_ptr, int len));
FORWARD _PROTOTYPE( int change_into, (struct inode **iip, struct inode *ip));
2005-04-21 16:53:53 +02:00
FORWARD _PROTOTYPE( int stat_inode, (struct inode *rip, struct filp *fil_ptr,
char *user_addr) );
/*===========================================================================*
* do_fchdir *
*===========================================================================*/
PUBLIC int do_fchdir()
{
/* Change directory on already-opened fd. */
struct filp *rfilp;
/* Is the file descriptor valid? */
if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
2006-01-20 13:43:35 +01:00
dup_inode(rfilp->filp_ino);
return change_into(&fp->fp_workdir, rfilp->filp_ino);
}
2005-04-21 16:53:53 +02:00
/*===========================================================================*
* 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;
endpoint-aware conversion of servers. 'who', indicating caller number in pm and fs and some other servers, has been removed in favour of 'who_e' (endpoint) and 'who_p' (proc nr.). In both PM and FS, isokendpt() convert endpoints to process slot numbers, returning OK if it was a valid and consistent endpoint number. okendpt() does the same but panic()s if it doesn't succeed. (In PM, this is pm_isok..) pm and fs keep their own records of process endpoints in their proc tables, which are needed to make kernel calls about those processes. message field names have changed. fs drivers are endpoints. fs now doesn't try to get out of driver deadlock, as the protocol isn't supposed to let that happen any more. (A warning is printed if ELOCKED is detected though.) fproc[].fp_task (indicating which driver the process is suspended on) became an int. PM and FS now get endpoint numbers of initial boot processes from the kernel. These happen to be the same as the old proc numbers, to let user processes reach them with the old numbers, but FS and PM don't know that. All new processes after INIT, even after the generation number wraps around, get endpoint numbers with generation 1 and higher, so the first instances of the boot processes are the only processes ever to have endpoint numbers in the old proc number range. More return code checks of sys_* functions have been added. IS has become endpoint-aware. Ditched the 'text' and 'data' fields in the kernel dump (which show locations, not sizes, so aren't terribly useful) in favour of the endpoint number. Proc number is still visible. Some other dumps (e.g. dmap, rs) show endpoint numbers now too which got the formatting changed. PM reading segments using rw_seg() has changed - it uses other fields in the message now instead of encoding the segment and process number and fd in the fd field. For that it uses _read_pm() and _write_pm() which to _taskcall()s directly in pm/misc.c. PM now sys_exit()s itself on panic(), instead of sys_abort(). RS also talks in endpoints instead of process numbers.
2006-03-03 11:20:58 +01:00
if (who_e == PM_PROC_NR) {
int slot;
if(isokendpt(m_in.endpt1, &slot) != OK)
return EINVAL;
rfp = &fproc[slot];
2005-04-21 16:53:53 +02:00
put_inode(fp->fp_rootdir);
dup_inode(fp->fp_rootdir = rfp->fp_rootdir);
put_inode(fp->fp_workdir);
dup_inode(fp->fp_workdir = rfp->fp_workdir);
/* 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_workdir, 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_rootdir, m_in.name, m_in.name_length);
return(r);
}
/*===========================================================================*
* change *
*===========================================================================*/
PRIVATE int change(iip, name_ptr, len)
struct inode **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 inode *rip;
/* Try to open the new directory. */
if (fetch_name(name_ptr, len, M3) != OK) return(err_code);
if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
return change_into(iip, rip);
}
/*===========================================================================*
2005-09-11 18:45:46 +02:00
* change_into *
*===========================================================================*/
PRIVATE int change_into(iip, rip)
struct inode **iip; /* pointer to the inode pointer for the dir */
struct inode *rip; /* this is what the inode has to become */
{
register int r;
2005-04-21 16:53:53 +02:00
/* It must be a directory and also be searchable. */
if ( (rip->i_mode & I_TYPE) != I_DIRECTORY)
r = ENOTDIR;
else
r = forbidden(rip, X_BIT); /* check if dir is searchable */
/* If error, return inode. */
if (r != OK) {
put_inode(rip);
return(r);
}
/* Everything is OK. Make the change. */
put_inode(*iip); /* release the old directory */
*iip = rip; /* acquire the new one */
return(OK);
}
/*===========================================================================*
* do_stat *
*===========================================================================*/
PUBLIC int do_stat()
{
/* Perform the stat(name, buf) system call. */
register struct inode *rip;
register int r;
/* Both stat() and fstat() use the same routine to do the real work. That
* routine expects an inode, so acquire it temporarily.
*/
if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
if ( (rip = eat_path(user_path)) == NIL_INODE) return(err_code);
r = stat_inode(rip, NIL_FILP, m_in.name2); /* actually do the work.*/
put_inode(rip); /* release the inode */
return(r);
}
/*===========================================================================*
* do_fstat *
*===========================================================================*/
PUBLIC int do_fstat()
{
/* Perform the fstat(fd, buf) system call. */
register struct filp *rfilp;
/* Is the file descriptor valid? */
if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
return(stat_inode(rfilp->filp_ino, rfilp, m_in.buffer));
}
/*===========================================================================*
* stat_inode *
*===========================================================================*/
PRIVATE int stat_inode(rip, fil_ptr, user_addr)
register struct inode *rip; /* pointer to inode to stat */
struct filp *fil_ptr; /* filp pointer, supplied by 'fstat' */
char *user_addr; /* user space address where stat buf goes */
{
/* Common code for stat and fstat system calls. */
struct stat statbuf;
mode_t mo;
int r, s;
/* Update the atime, ctime, and mtime fields in the inode, if need be. */
if (rip->i_update) update_times(rip);
/* Fill in the statbuf struct. */
mo = rip->i_mode & I_TYPE;
2005-08-29 18:47:18 +02:00
/* true iff special */
s = (mo == I_CHAR_SPECIAL || mo == I_BLOCK_SPECIAL);
2005-04-21 16:53:53 +02:00
statbuf.st_dev = rip->i_dev;
statbuf.st_ino = rip->i_num;
statbuf.st_mode = rip->i_mode;
statbuf.st_nlink = rip->i_nlinks;
statbuf.st_uid = rip->i_uid;
statbuf.st_gid = rip->i_gid;
statbuf.st_rdev = (dev_t) (s ? rip->i_zone[0] : NO_DEV);
statbuf.st_size = rip->i_size;
if (rip->i_pipe == I_PIPE) {
statbuf.st_mode &= ~I_REGULAR; /* wipe out I_REGULAR bit for pipes */
if (fil_ptr != NIL_FILP && fil_ptr->filp_mode & R_BIT)
statbuf.st_size -= fil_ptr->filp_pos;
}
statbuf.st_atime = rip->i_atime;
statbuf.st_mtime = rip->i_mtime;
statbuf.st_ctime = rip->i_ctime;
/* Copy the struct to user space. */
r = sys_datacopy(FS_PROC_NR, (vir_bytes) &statbuf,
endpoint-aware conversion of servers. 'who', indicating caller number in pm and fs and some other servers, has been removed in favour of 'who_e' (endpoint) and 'who_p' (proc nr.). In both PM and FS, isokendpt() convert endpoints to process slot numbers, returning OK if it was a valid and consistent endpoint number. okendpt() does the same but panic()s if it doesn't succeed. (In PM, this is pm_isok..) pm and fs keep their own records of process endpoints in their proc tables, which are needed to make kernel calls about those processes. message field names have changed. fs drivers are endpoints. fs now doesn't try to get out of driver deadlock, as the protocol isn't supposed to let that happen any more. (A warning is printed if ELOCKED is detected though.) fproc[].fp_task (indicating which driver the process is suspended on) became an int. PM and FS now get endpoint numbers of initial boot processes from the kernel. These happen to be the same as the old proc numbers, to let user processes reach them with the old numbers, but FS and PM don't know that. All new processes after INIT, even after the generation number wraps around, get endpoint numbers with generation 1 and higher, so the first instances of the boot processes are the only processes ever to have endpoint numbers in the old proc number range. More return code checks of sys_* functions have been added. IS has become endpoint-aware. Ditched the 'text' and 'data' fields in the kernel dump (which show locations, not sizes, so aren't terribly useful) in favour of the endpoint number. Proc number is still visible. Some other dumps (e.g. dmap, rs) show endpoint numbers now too which got the formatting changed. PM reading segments using rw_seg() has changed - it uses other fields in the message now instead of encoding the segment and process number and fd in the fd field. For that it uses _read_pm() and _write_pm() which to _taskcall()s directly in pm/misc.c. PM now sys_exit()s itself on panic(), instead of sys_abort(). RS also talks in endpoints instead of process numbers.
2006-03-03 11:20:58 +01:00
who_e, (vir_bytes) user_addr, (phys_bytes) sizeof(statbuf));
2005-04-21 16:53:53 +02:00
return(r);
}
/*===========================================================================*
* do_fstatfs *
*===========================================================================*/
PUBLIC int do_fstatfs()
{
/* Perform the fstatfs(fd, buf) system call. */
struct statfs st;
register struct filp *rfilp;
int r;
/* Is the file descriptor valid? */
if ( (rfilp = get_filp(m_in.fd)) == NIL_FILP) return(err_code);
st.f_bsize = rfilp->filp_ino->i_sp->s_block_size;
r = sys_datacopy(FS_PROC_NR, (vir_bytes) &st,
endpoint-aware conversion of servers. 'who', indicating caller number in pm and fs and some other servers, has been removed in favour of 'who_e' (endpoint) and 'who_p' (proc nr.). In both PM and FS, isokendpt() convert endpoints to process slot numbers, returning OK if it was a valid and consistent endpoint number. okendpt() does the same but panic()s if it doesn't succeed. (In PM, this is pm_isok..) pm and fs keep their own records of process endpoints in their proc tables, which are needed to make kernel calls about those processes. message field names have changed. fs drivers are endpoints. fs now doesn't try to get out of driver deadlock, as the protocol isn't supposed to let that happen any more. (A warning is printed if ELOCKED is detected though.) fproc[].fp_task (indicating which driver the process is suspended on) became an int. PM and FS now get endpoint numbers of initial boot processes from the kernel. These happen to be the same as the old proc numbers, to let user processes reach them with the old numbers, but FS and PM don't know that. All new processes after INIT, even after the generation number wraps around, get endpoint numbers with generation 1 and higher, so the first instances of the boot processes are the only processes ever to have endpoint numbers in the old proc number range. More return code checks of sys_* functions have been added. IS has become endpoint-aware. Ditched the 'text' and 'data' fields in the kernel dump (which show locations, not sizes, so aren't terribly useful) in favour of the endpoint number. Proc number is still visible. Some other dumps (e.g. dmap, rs) show endpoint numbers now too which got the formatting changed. PM reading segments using rw_seg() has changed - it uses other fields in the message now instead of encoding the segment and process number and fd in the fd field. For that it uses _read_pm() and _write_pm() which to _taskcall()s directly in pm/misc.c. PM now sys_exit()s itself on panic(), instead of sys_abort(). RS also talks in endpoints instead of process numbers.
2006-03-03 11:20:58 +01:00
who_e, (vir_bytes) m_in.buffer, (phys_bytes) sizeof(st));
2005-04-21 16:53:53 +02:00
return(r);
}
/*===========================================================================*
* do_lstat *
*===========================================================================*/
PUBLIC int do_lstat()
{
/* Perform the lstat(name, buf) system call. */
register int r; /* return value */
register struct inode *rip; /* target inode */
if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
if ((rip = parse_path(user_path, (char *) 0, EAT_PATH_OPAQUE)) == NIL_INODE)
return(err_code);
r = stat_inode(rip, NIL_FILP, m_in.name2);
put_inode(rip);
return(r);
}
/*===========================================================================*
* do_rdlink *
*===========================================================================*/
PUBLIC int do_rdlink()
{
/* Perform the readlink(name, buf) system call. */
register int r; /* return value */
block_t b; /* block containing link text */
struct buf *bp; /* buffer containing link text */
register struct inode *rip; /* target inode */
int copylen;
copylen = m_in.m1_i2;
if(copylen < 0) return EINVAL;
if (fetch_name(m_in.name1, m_in.name1_length, M1) != OK) return(err_code);
if ((rip = parse_path(user_path, (char *) 0, EAT_PATH_OPAQUE)) == NIL_INODE)
return(err_code);
r = EACCES;
if (S_ISLNK(rip->i_mode) && (b = read_map(rip, (off_t) 0)) != NO_BLOCK) {
if (m_in.name2_length <= 0) r = EINVAL;
else if (m_in.name2_length < rip->i_size) r = ERANGE;
else {
if(rip->i_size < copylen) copylen = rip->i_size;
bp = get_block(rip->i_dev, b, NORMAL);
r = sys_vircopy(SELF, D, (vir_bytes) bp->b_data,
who_e, D, (vir_bytes) m_in.name2, (vir_bytes) copylen);
if (r == OK) r = copylen;
put_block(bp, DIRECTORY_BLOCK);
}
}
put_inode(rip);
return(r);
}