📄 gfs_syscalls.c
字号:
#ifndef lintstatic char *sccsid = "@(#)gfs_syscalls.c 4.13 (ULTRIX) 5/2/91";#endif lint/************************************************************************ * * * Copyright (c) 1986, 1987, 1988 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//*********************************************************************** * * Modification History * * 02 May 91 -- darrell * Fixed a missing ")" in copen(); * * 01 May 91 -- sue * Back out previous change which was to fix copen() to prevent * disappearing tape drives. On VAX, caused problems using * file command on /dev/tty*. * * 10 Apr 91 -- prs * The setjmp case of copen() cannot call closef(). Simply * deallocate the file table entry. * * 28 Feb 91 -- prs * Added support for a configurable number of open * file descriptors. * * 27 Feb 91 -- chet * Fix filesystem timestamping. * * 21 Jan 91 -- prs * Added zeroing the f_data field to the error case in copen(). * Also removed some obsolete vhangup() leftovers. * * 15 Oct 90 -- dws * Fixed saccess() to handle 'noexec' filesystems correctly. * * 27 Sep 90 -- prs * Prevented rename(from, ".") in rename(). * * 17 May 90 -- prs * Fixed bug in copen() which left an unreferenced file descriptor * in the uarea. * * 17 Jan 90 -- prs * Added the restriction that a POSIX process cannot link to * a directory. * * 12 Jan 90 -- prs * Fixed saccess() to restore euid and egid before returning. * * 08 Dec 89 -- cb * Fixed getmnt to exit syscall after a ^C. * * 08 Dec 89 -- prs * Checked u.u_error after a call to GUPDATE in link(). * If the gupdate failed, don't bother doing the namei * on the target. * * 14 Nov 89 -- prs * Added POSIX check to prevent unlinking of TEXT gnodes. * * 25 Jul 89 -- chet * New sync() system call * * 08 Jun 89 -- lebel * Fixed BLKANDSET code in copen - open always returned fd of 0 * for character special files * * 04 Apr 89 -- prs * Added SMP quota locking. * * 16 Feb 89 -- prs * Added XOPEN check to prevent unlinking of TEXT gnodes. * * 08 Dec 88 -- prs * Added POSIX mode access time setting * in getdirentries(). * * 09 Jan 89 -- condylis * Modified sync and getmnt to run on any processor. * * 11 Oct 88 -- prs * Changed rmdir() to pass the sfs a directory gp, and properly * fixed the GNOFUNC error leg. * * 14 Sep 88 -- chet * Fix another bug in link() due to GUPDATE calls on a readonly * remote filesystem. * * 22 Aug 88 -- prs * Changed copen() to only allow root to create a file with the * sticky bit set. * * 04 Aug 88 -- chet * Fix problems in link() due to GUPDATE calls that destroy u.u_error. * * 28 Jul 88 -- prs * SMP - All system calls except sync() and rename() are safe. * * 23 Feb 88 -- map * Fix problem in chown(). In some cases it would fail but not return * an errno. * * 10 Feb 88 -- map * Rewrite utimes() to allow POSIX and SVID utime() behavior. The utime() * library routine calls utimes(). A NULL time parameter will now default * to the current time as specified in the utime() function. If the time * parameter is NULL EITHER the owner(or su) OR a process with write * access can update the time. This is not a security hole as a user * with write access can update the time through other means prior to * this change. * * 10 Feb 88 -- prs * Modified to handle new fifo code. * * 08 Feb 88 -- prs * Fixed lseek to return an error if the target offset is negative * for a regular file. * * 26 Jan 88 -- chet * Removed access check in gfs_getdirentries(). This * check has been moved down to the specific filesystems. * * 08 Jan 88 -- prs * Removed lseek change that checked for a negative offset. * * 04 Jan 88 -- prs * Added a check to link() that verified link count of gnode * did not exceed LINK_MAX. * * 12 Dec 87 -- prs * Fixed lseek to return an error if the target offset is negative. * * 12-11-87 Robin L. and Larry C. * Added new kmalloc memory allocation to system. * * 17 Nov 87 -- map * Allow user to chown the group id of a file to another group * to which they belong. Allows chgrp to not be suid. POSIX requirement. * * 15 Sep 87 -- prs * Changed copen to validate the fp after GOPEN call. * * 09 Sep 87 -- map * saccess() changed to check for invalid mode. POSIX requirement * * 19 Aug 87 -- cb * getmnt() returned to original state. readlink changed to return * EINVAL if file is not a symbolic link. * * 13 Aug 87 -- cb * Fixed getmnt so it will parse a block device path correctly * * 14 Jul 87 -- cb * Changed mknod interface: added a dev_t. * * 11 Jun 87 -- prs * Free cred if call to GOPEN fails in copen routine. * * 12 May 87 -- chet * Added new getmnt() interface code. * * 03 Mar 87 -- chet * Unlocked gnode before doing GSTAT so that locks won't * propagate up file tree when a slow operation takes place. * * 13 Feb 87 -- prs * Removed check for m_dev to be null in sync. The check prevented * sync on a device with major number 0. * * 15 January 86 -- Chase * added code to check for failure on truncate in copen() * * 11 Sept 86 -- koehler * changes for new namei interface * * 12 Sept 86 -- koehler * symlink errno change * * 2 Oct 86 -- Larry Cohen * refix shared line bug in copen ***********************************************************************/#include "../h/param.h"#include "../h/systm.h"#include "../h/dir.h"#include "../h/user.h"#include "../h/kernel.h"#include "../h/file.h"#include "../h/stat.h"#include "../h/gnode.h"#include "../h/buf.h"#include "../h/proc.h"#include "../h/quota.h"#include "../h/uio.h"#include "../h/socket.h"#include "../h/socketvar.h"#include "../h/mount.h"#include "../h/ioctl.h"#include "../h/kmalloc.h"#include "../h/exec.h"#include "../h/limits.h"extern struct gnode *fref();link() { register struct gnode *source_gp, *target_pgp; register struct a { char *source; char *target; } *uap = (struct a *)u.u_ap; register struct nameidata *ndp = &u.u_nd; int error = 0; ndp->ni_nameiop = LOOKUP | FOLLOW; KM_ALLOC(ndp->ni_dirp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (ndp->ni_dirp == NULL) { u.u_error = EIO; return; } if (u.u_error = copyinstr(uap->source, ndp->ni_dirp, MAXPATHLEN, (u_int *) 0)) goto free; source_gp = gfs_namei(ndp); if (source_gp == NULL) goto free; if (source_gp->g_nlink >= LINK_MAX) { gput(source_gp); u.u_error = EMLINK; goto free; } if (((source_gp->g_mode & GFMT) == GFDIR) && (!suser() || (u.u_procp->p_progenv == A_POSIX))) { gput(source_gp); u.u_error = EPERM; goto free; } if (u.u_error = copyinstr(uap->target, ndp->ni_dirp, MAXPATHLEN, (u_int *) 0)) { gput(source_gp); goto free; } /* this stuff is done here to avoid races in the fs */ source_gp->g_nlink++; /* * A lot of games are played here * with error and u.u_error because of the GUPDATE calls * that don't do anything useful except for UFS, and are guaranteed * to clobber u.u_error for NFS. * There is a subtle UFS case as well, where an I/O error * on the inode update clobbers an already failing syscall's * u.u_error with EIO. * * I finally decided to bite the bullet and put ISLOCAL * checks around the GUPDATE calls - 9/8/88 - chet */ if (ISLOCAL(source_gp->g_mp)) { source_gp->g_flag |= GCHG; (void) GUPDATE(source_gp, timepick, timepick, 1, u.u_cred); if (u.u_error) { error = u.u_error; gfs_unlock(source_gp); goto errout; } } gfs_unlock(source_gp); ndp->ni_nameiop = CREATE; target_pgp = gfs_namei(ndp); if (u.u_error) { error = u.u_error; /* save the error code */ goto errout; } if (target_pgp != NULL) { gput(target_pgp); error = EEXIST; /* save the error code */ goto errout; } target_pgp = ndp->ni_pdir; if (target_pgp->g_mp != source_gp->g_mp) { gput(target_pgp); error = EXDEV; /* save the error code */ goto errout; } /* * LINK should take three arguments, gp of source, gp of parent * of source, and source component. */ /* The fs specific routine does all de-referencing */ if (GLINK(source_gp, ndp) == GNOFUNC) { u.u_error = EOPNOTSUPP; gput(target_pgp); grele(source_gp); } goto free;errout: gfs_lock(source_gp); source_gp->g_nlink--; if (ISLOCAL(source_gp->g_mp)) { source_gp->g_flag |= GCHG; (void) GUPDATE(source_gp, timepick, timepick, 1, u.u_cred); } gput(source_gp); u.u_error = error; /* restore the error code after GUPDATE*/free: KM_FREE(ndp->ni_dirp, KM_NAMEI);}unlink(){ register struct a { char *fname; } *uap = (struct a *)u.u_ap; register struct gnode *gp, *dp; register struct nameidata *ndp = &u.u_nd; register int ret; ndp->ni_nameiop = DELETE | LOCKPARENT; KM_ALLOC(ndp->ni_dirp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (ndp->ni_dirp == NULL) { u.u_error = EIO; return; } if (u.u_error = copyinstr(uap->fname, ndp->ni_dirp, MAXPATHLEN, (u_int *) 0)) { goto out2; } gp = gfs_namei(ndp); if (gp == NULL) { goto out2; } dp = (struct gnode *)ndp->ni_pdir; /* only non POSIX root can unlink a directory */ if ((gp->g_mode&GFMT) == GFDIR) { if ((u.u_procp->p_progenv == A_POSIX) || !suser()) { if (u.u_error == 0) u.u_error = EPERM; goto out; } } /* * Don't unlink a mounted file. */ if (gp->g_dev != dp->g_dev) { u.u_error = EBUSY; goto out; } if (gp->g_flag>EXT) { xrele(gp); /* try once to free text */ } /* * SysV and POSIX cannot remove the last link to a shared text file. */ if ((u.u_procp->p_progenv & (A_POSIX|A_SYSV)) && (gp->g_flag>EXT) && (gp->g_nlink == 1)) { u.u_error = ETXTBSY; goto out; } if (GUNLINK(gp, ndp) == GNOFUNC) u.u_error = EOPNOTSUPP;out: if (dp == gp) { grele(gp); gput(gp); } else { gput(dp); gput(gp); }out2: KM_FREE(ndp->ni_dirp, KM_NAMEI);}/* * Mkdir system call */mkdir(){ register struct a { char *name; int dmode; } *uap = (struct a *) u.u_ap; register struct gnode *gp; register struct nameidata *ndp = &u.u_nd; uap = (struct a *)u.u_ap; ndp->ni_nameiop = CREATE; KM_ALLOC(ndp->ni_dirp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (ndp->ni_dirp == NULL) { u.u_error = EIO; return; } if (u.u_error = copyinstr(uap->name, ndp->ni_dirp, MAXPATHLEN, (u_int *)0)) { goto out; } gp = gfs_namei(ndp); if (u.u_error) { goto out; } if (gp != NULL) { u.u_error = EEXIST; gput(gp); goto out; } if ((gp = GMKDIR(ndp->ni_pdir, ndp->ni_dirp, uap->dmode)) == (struct gnode *) GNOFUNC) u.u_error = EOPNOTSUPP; else if (!u.u_error) grele(gp);out: KM_FREE(ndp->ni_dirp, KM_NAMEI);}/* * Rmdir system call. */rmdir(){ register struct a { char *name; } *uap = (struct a *)u.u_ap; register struct gnode *gp; register struct nameidata *ndp = &u.u_nd; ndp->ni_nameiop = DELETE | LOCKPARENT; KM_ALLOC(ndp->ni_dirp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (ndp->ni_dirp == NULL) { u.u_error = EIO; return; } if (u.u_error = copyinstr(uap->name, ndp->ni_dirp, MAXPATHLEN, (u_int *)0)) { goto out; } gp = gfs_namei(ndp); if (gp == NULL) { goto out; } /* * GFS assures the sfs gp is a directory. */ if ((gp->g_mode & GFMT) != GFDIR) { u.u_error = ENOTDIR; goto bad; } if (GRMDIR(gp, ndp) == GNOFUNC) { u.u_error = EOPNOTSUPP; goto bad; } goto out;bad: if (ndp->ni_pdir == gp) grele(ndp->ni_pdir); else gput(ndp->ni_pdir); gput(gp);out: KM_FREE(ndp->ni_dirp, KM_NAMEI);}/* * mode mask for creation of files */umask(){ register struct a { int mask; } *uap = (struct a *)u.u_ap; u.u_r.r_val1 = u.u_cmask; u.u_cmask = uap->mask & 07777;}struct gnode *maknode(mode, ndp) register int mode; register struct nameidata *ndp;{ if (GMAKNODE(mode, (dev_t) 0, ndp) == (struct gnode *) GNOFUNC) u.u_error = EOPNOTSUPP;}/* * Rename system call. * rename("foo", "bar"); * is essentially * unlink("bar"); * link("foo", "bar"); * unlink("foo"); * but ``atomically''. Can't do full commit without saving state in the * inode on disk which isn't feasible at this time. Best we can do is * always guarantee the target exists. * * Basic algorithm is: * * 1) Bump link count on source while we're linking it to the * target. This also insure the gnode won't be deleted out * from underneath us while we work (it may be truncated by * a concurrent `trunc' or `open' for creation). * 2) Link source to destination. If destination already exists, * delete it first. * 3) Unlink source reference to gnode if still around. * If a directory was moved and the parent of the destination * is different from the source, patch the ".." entry in the * directory. * * Source and destination must either both be directories, or both * not be directories. If target is a directory, it must be empty. */rename(){ register struct a { char *from; char *to; } *uap; register struct gnode *source_gp; register struct nameidata *source_ndp = &u.u_nd; struct nameidata target_ndp; /* get us a pointer to the from name */ uap = (struct a *)u.u_ap; source_ndp->ni_nameiop = DELETE | LOCKPARENT; KM_ALLOC(source_ndp->ni_dirp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (source_ndp->ni_dirp == NULL) { u.u_error = EIO; return; } if (u.u_error = copyinstr(uap->from, source_ndp->ni_dirp, MAXPATHLEN, (u_int *) 0)) { goto out1; } KM_ALLOC(target_ndp.ni_dirp, char *, MAXPATHLEN, KM_NAMEI, KM_NOARG); if (target_ndp.ni_dirp == NULL) { u.u_error = EIO; goto out1; } if (u.u_error = copyinstr(uap->to, target_ndp.ni_dirp, MAXPATHLEN, (u_int *) 0)) { goto out2; } /* * Prevent rename(from, ".") */ if (!strcmp(target_ndp.ni_dirp, ".")) { u.u_error = EINVAL; goto out2; } source_gp = gfs_namei(source_ndp); if (source_gp == NULL || u.u_error) { goto out2; } /* XXX */ /* this is UFS specific */ if (ISLOCAL(source_gp->g_mp)) { if (u.u_error = copyinstr(uap->from, source_ndp->ni_dirp, MAXPATHLEN, (u_int *) 0)) { goto out2; } } target_ndp.ni_nameiop = CREATE | LOCKPARENT | NOCACHE; if (GRENAMEG(source_gp, u.u_cdir, source_ndp, u.u_cdir, &target_ndp, 0) == GNOFUNC) { u.u_error = EOPNOTSUPP; gput(source_gp); gput(source_ndp->ni_pdir); }out2: KM_FREE(target_ndp.ni_dirp, KM_NAMEI);out1: KM_FREE(source_ndp->ni_dirp, KM_NAMEI);}extern struct fileops gnodeops;extern int soo_rw(), soo_ioctl(), soo_select(), gno_close();struct fileops portops = { soo_rw, soo_ioctl, soo_select, gno_close };struct file *getgnode();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -