BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / kern / vfs_syscalls.c
index aa6233f..30732f1 100644 (file)
@@ -2,9 +2,35 @@
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1989 The Regents of the University of California.
  * All rights reserved.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
  *
  *
- *     @(#)vfs_syscalls.c      7.67 (Berkeley) %G%
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)vfs_syscalls.c      7.74 (Berkeley) 6/21/91
  */
 
 #include "param.h"
  */
 
 #include "param.h"
@@ -25,7 +51,7 @@
  */
 
 /*
  */
 
 /*
- * mount system call
+ * Mount system call.
  */
 /* ARGSUSED */
 mount(p, uap, retval)
  */
 /* ARGSUSED */
 mount(p, uap, retval)
@@ -235,11 +261,7 @@ dounmount(mp, flags, p)
        if (error = vfs_lock(mp))
                return (error);
 
        if (error = vfs_lock(mp))
                return (error);
 
-#ifdef NVM
        vnode_pager_umount(mp); /* release cached vnodes */
        vnode_pager_umount(mp); /* release cached vnodes */
-#else
-       xumount(mp);            /* remove unused sticky files from text table */
-#endif
        cache_purgevfs(mp);     /* remove cache entries for this file sys */
        if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
                error = VFS_UNMOUNT(mp, flags, p);
        cache_purgevfs(mp);     /* remove cache entries for this file sys */
        if ((error = VFS_SYNC(mp, MNT_WAIT)) == 0 || (flags & MNT_FORCE))
                error = VFS_UNMOUNT(mp, flags, p);
@@ -287,7 +309,7 @@ sync(p, uap, retval)
 }
 
 /*
 }
 
 /*
- * operate on filesystem quotas
+ * Operate on filesystem quotas.
  */
 /* ARGSUSED */
 quotactl(p, uap, retval)
  */
 /* ARGSUSED */
 quotactl(p, uap, retval)
@@ -317,7 +339,7 @@ quotactl(p, uap, retval)
 }
 
 /*
 }
 
 /*
- * get filesystem statistics
+ * Get filesystem statistics.
  */
 /* ARGSUSED */
 statfs(p, uap, retval)
  */
 /* ARGSUSED */
 statfs(p, uap, retval)
@@ -350,7 +372,7 @@ statfs(p, uap, retval)
 }
 
 /*
 }
 
 /*
- * get filesystem statistics
+ * Get filesystem statistics.
  */
 /* ARGSUSED */
 fstatfs(p, uap, retval)
  */
 /* ARGSUSED */
 fstatfs(p, uap, retval)
@@ -377,7 +399,7 @@ fstatfs(p, uap, retval)
 }
 
 /*
 }
 
 /*
- * get statistics on all filesystems
+ * Get statistics on all filesystems.
  */
 getfsstat(p, uap, retval)
        struct proc *p;
  */
 getfsstat(p, uap, retval)
        struct proc *p;
@@ -556,9 +578,11 @@ open(p, uap, retval)
        struct nameidata *ndp;
        register struct filedesc *fdp = p->p_fd;
        register struct file *fp;
        struct nameidata *ndp;
        register struct filedesc *fdp = p->p_fd;
        register struct file *fp;
+       register struct vnode *vp;
        int fmode, cmode;
        struct file *nfp;
        int fmode, cmode;
        struct file *nfp;
-       int indx, error;
+       int type, indx, error;
+       struct flock lf;
        struct nameidata nd;
        extern struct fileops vnops;
 
        struct nameidata nd;
        extern struct fileops vnops;
 
@@ -572,8 +596,7 @@ open(p, uap, retval)
        ndp->ni_dirp = uap->fname;
        p->p_dupfd = -indx - 1;                 /* XXX check for fdopen */
        if (error = vn_open(ndp, p, fmode, cmode)) {
        ndp->ni_dirp = uap->fname;
        p->p_dupfd = -indx - 1;                 /* XXX check for fdopen */
        if (error = vn_open(ndp, p, fmode, cmode)) {
-               crfree(fp->f_cred);
-               fp->f_count--;
+               ffree(fp);
                if (error == ENODEV &&          /* XXX from fdopen */
                    p->p_dupfd >= 0 &&
                    (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
                if (error == ENODEV &&          /* XXX from fdopen */
                    p->p_dupfd >= 0 &&
                    (error = dupfdopen(fdp, indx, p->p_dupfd, fmode)) == 0) {
@@ -585,10 +608,32 @@ open(p, uap, retval)
                fdp->fd_ofiles[indx] = NULL;
                return (error);
        }
                fdp->fd_ofiles[indx] = NULL;
                return (error);
        }
+       vp = ndp->ni_vp;
        fp->f_flag = fmode & FMASK;
        fp->f_flag = fmode & FMASK;
+       if (fmode & (O_EXLOCK | O_SHLOCK)) {
+               lf.l_whence = SEEK_SET;
+               lf.l_start = 0;
+               lf.l_len = 0;
+               if (fmode & O_EXLOCK)
+                       lf.l_type = F_WRLCK;
+               else
+                       lf.l_type = F_RDLCK;
+               type = F_FLOCK;
+               if ((fmode & FNONBLOCK) == 0)
+                       type |= F_WAIT;
+               if (error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, type)) {
+                       VOP_UNLOCK(vp);
+                       (void) vn_close(vp, fp->f_flag, fp->f_cred, p);
+                       ffree(fp);
+                       fdp->fd_ofiles[indx] = NULL;
+                       return (error);
+               }
+               fp->f_flag |= FHASLOCK;
+       }
+       VOP_UNLOCK(vp);
        fp->f_type = DTYPE_VNODE;
        fp->f_ops = &vnops;
        fp->f_type = DTYPE_VNODE;
        fp->f_ops = &vnops;
-       fp->f_data = (caddr_t)ndp->ni_vp;
+       fp->f_data = (caddr_t)vp;
        *retval = indx;
        return (0);
 }
        *retval = indx;
        return (0);
 }
@@ -619,7 +664,7 @@ ocreat(p, uap, retval)
 #endif /* COMPAT_43 */
 
 /*
 #endif /* COMPAT_43 */
 
 /*
- * Mknod system call
+ * Mknod system call.
  */
 /* ARGSUSED */
 mknod(p, uap, retval)
  */
 /* ARGSUSED */
 mknod(p, uap, retval)
@@ -684,7 +729,7 @@ out:
 }
 
 /*
 }
 
 /*
- * Mkfifo system call
+ * Mkfifo system call.
  */
 /* ARGSUSED */
 mkfifo(p, uap, retval)
  */
 /* ARGSUSED */
 mkfifo(p, uap, retval)
@@ -726,7 +771,7 @@ mkfifo(p, uap, retval)
 }
 
 /*
 }
 
 /*
- * link system call
+ * Link system call.
  */
 /* ARGSUSED */
 link(p, uap, retval)
  */
 /* ARGSUSED */
 link(p, uap, retval)
@@ -782,7 +827,7 @@ out1:
 }
 
 /*
 }
 
 /*
- * symlink -- make a symbolic link
+ * Make a symbolic link.
  */
 /* ARGSUSED */
 symlink(p, uap, retval)
  */
 /* ARGSUSED */
 symlink(p, uap, retval)
@@ -827,9 +872,7 @@ out:
 }
 
 /*
 }
 
 /*
- * Unlink system call.
- * Hard to avoid races here, especially
- * in unlinking directories.
+ * Delete a name from the filesystem.
  */
 /* ARGSUSED */
 unlink(p, uap, retval)
  */
 /* ARGSUSED */
 unlink(p, uap, retval)
@@ -855,18 +898,13 @@ unlink(p, uap, retval)
            (error = suser(p->p_ucred, &p->p_acflag)))
                goto out;
        /*
            (error = suser(p->p_ucred, &p->p_acflag)))
                goto out;
        /*
-        * Don't unlink a mounted file.
+        * The root of a mounted filesystem cannot be deleted.
         */
        if (vp->v_flag & VROOT) {
                error = EBUSY;
                goto out;
        }
         */
        if (vp->v_flag & VROOT) {
                error = EBUSY;
                goto out;
        }
-#ifdef NVM
        (void) vnode_pager_uncache(vp);
        (void) vnode_pager_uncache(vp);
-#else
-       if (vp->v_flag & VTEXT)
-               xrele(vp);      /* try once to free text */
-#endif
 out:
        if (!error) {
                error = VOP_REMOVE(ndp, p);
 out:
        if (!error) {
                error = VOP_REMOVE(ndp, p);
@@ -882,7 +920,7 @@ out:
 }
 
 /*
 }
 
 /*
- * Seek system call
+ * Seek system call.
  */
 lseek(p, uap, retval)
        struct proc *p;
  */
 lseek(p, uap, retval)
        struct proc *p;
@@ -929,7 +967,7 @@ lseek(p, uap, retval)
 }
 
 /*
 }
 
 /*
- * Access system call
+ * Check access permissions.
  */
 /* ARGSUSED */
 saccess(p, uap, retval)
  */
 /* ARGSUSED */
 saccess(p, uap, retval)
@@ -979,7 +1017,8 @@ out1:
 }
 
 /*
 }
 
 /*
- * Stat system call.  This version follows links.
+ * Stat system call.
+ * This version follows links.
  */
 /* ARGSUSED */
 stat(p, uap, retval)
  */
 /* ARGSUSED */
 stat(p, uap, retval)
@@ -1010,7 +1049,8 @@ stat(p, uap, retval)
 }
 
 /*
 }
 
 /*
- * Lstat system call.  This version does not follow links.
+ * Lstat system call.
+ * This version does not follow links.
  */
 /* ARGSUSED */
 lstat(p, uap, retval)
  */
 /* ARGSUSED */
 lstat(p, uap, retval)
@@ -1041,7 +1081,7 @@ lstat(p, uap, retval)
 }
 
 /*
 }
 
 /*
- * Return target name of a symbolic link
+ * Return target name of a symbolic link.
  */
 /* ARGSUSED */
 readlink(p, uap, retval)
  */
 /* ARGSUSED */
 readlink(p, uap, retval)
@@ -1459,24 +1499,21 @@ rename(p, uap, retval)
        int *retval;
 {
        register struct vnode *tvp, *fvp, *tdvp;
        int *retval;
 {
        register struct vnode *tvp, *fvp, *tdvp;
-       register struct nameidata *ndp;
+       struct nameidata fromnd, tond;
        int error;
        int error;
-       struct nameidata nd, tond;
 
 
-       ndp = &nd;
-       ndp->ni_nameiop = DELETE | WANTPARENT;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = uap->from;
-       if (error = namei(ndp, p))
+       fromnd.ni_nameiop = DELETE | WANTPARENT | SAVESTART;
+       fromnd.ni_segflg = UIO_USERSPACE;
+       fromnd.ni_dirp = uap->from;
+       if (error = namei(&fromnd, p))
                return (error);
                return (error);
-       fvp = ndp->ni_vp;
-       nddup(ndp, &tond);
-       tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE;
+       fvp = fromnd.ni_vp;
+       tond.ni_nameiop = RENAME | LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
        tond.ni_segflg = UIO_USERSPACE;
        tond.ni_dirp = uap->to;
        if (error = namei(&tond, p)) {
        tond.ni_segflg = UIO_USERSPACE;
        tond.ni_dirp = uap->to;
        if (error = namei(&tond, p)) {
-               VOP_ABORTOP(ndp);
-               vrele(ndp->ni_dvp);
+               VOP_ABORTOP(&fromnd);
+               vrele(fromnd.ni_dvp);
                vrele(fvp);
                goto out1;
        }
                vrele(fvp);
                goto out1;
        }
@@ -1502,14 +1539,17 @@ rename(p, uap, retval)
        if (fvp == tdvp)
                error = EINVAL;
        /*
        if (fvp == tdvp)
                error = EINVAL;
        /*
-        * If source is the same as the destination,
+        * If source is the same as the destination (that is the
+        * same inode number with the same name in the same directory),
         * then there is nothing to do.
         */
         * then there is nothing to do.
         */
-       if (fvp == tvp)
+       if (fvp == tvp && fromnd.ni_dvp == tdvp &&
+           fromnd.ni_namelen == tond.ni_namelen &&
+           !bcmp(fromnd.ni_ptr, tond.ni_ptr, fromnd.ni_namelen))
                error = -1;
 out:
        if (!error) {
                error = -1;
 out:
        if (!error) {
-               error = VOP_RENAME(ndp, &tond, p);
+               error = VOP_RENAME(&fromnd, &tond, p);
        } else {
                VOP_ABORTOP(&tond);
                if (tdvp == tvp)
        } else {
                VOP_ABORTOP(&tond);
                if (tdvp == tvp)
@@ -1518,19 +1558,22 @@ out:
                        vput(tdvp);
                if (tvp)
                        vput(tvp);
                        vput(tdvp);
                if (tvp)
                        vput(tvp);
-               VOP_ABORTOP(ndp);
-               vrele(ndp->ni_dvp);
+               VOP_ABORTOP(&fromnd);
+               vrele(fromnd.ni_dvp);
                vrele(fvp);
        }
                vrele(fvp);
        }
+       vrele(tond.ni_startdir);
+       FREE(tond.ni_pnbuf, M_NAMEI);
 out1:
 out1:
-       ndrele(&tond);
+       vrele(fromnd.ni_startdir);
+       FREE(fromnd.ni_pnbuf, M_NAMEI);
        if (error == -1)
                return (0);
        return (error);
 }
 
 /*
        if (error == -1)
                return (0);
        return (error);
 }
 
 /*
- * Mkdir system call
+ * Mkdir system call.
  */
 /* ARGSUSED */
 mkdir(p, uap, retval)
  */
 /* ARGSUSED */
 mkdir(p, uap, retval)
@@ -1607,7 +1650,7 @@ rmdir(p, uap, retval)
                goto out;
        }
        /*
                goto out;
        }
        /*
-        * Don't unlink a mounted file.
+        * The root of a mounted filesystem cannot be deleted.
         */
        if (vp->v_flag & VROOT)
                error = EBUSY;
         */
        if (vp->v_flag & VROOT)
                error = EBUSY;
@@ -1626,7 +1669,7 @@ out:
 }
 
 /*
 }
 
 /*
- * Read a block of directory entries in a file system independent format
+ * Read a block of directory entries in a file system independent format.
  */
 getdirentries(p, uap, retval)
        struct proc *p;
  */
 getdirentries(p, uap, retval)
        struct proc *p;
@@ -1673,7 +1716,7 @@ getdirentries(p, uap, retval)
 }
 
 /*
 }
 
 /*
- * mode mask for creation of files
+ * Set the mode mask for creation of filesystem nodes.
  */
 mode_t
 umask(p, uap, retval)
  */
 mode_t
 umask(p, uap, retval)
@@ -1731,6 +1774,9 @@ out:
        return (error);
 }
 
        return (error);
 }
 
+/*
+ * Convert a user file descriptor to a kernel file entry.
+ */
 getvnode(fdp, fdes, fpp)
        struct filedesc *fdp;
        struct file **fpp;
 getvnode(fdp, fdes, fpp)
        struct filedesc *fdp;
        struct file **fpp;