- * @(#)ffs_vnops.c 7.1 (Berkeley) %G%
- */
-
-#include "param.h"
-#include "systm.h"
-#include "dir.h"
-#include "user.h"
-#include "kernel.h"
-#include "file.h"
-#include "stat.h"
-#include "inode.h"
-#include "fs.h"
-#include "buf.h"
-#include "proc.h"
-#include "quota.h"
-#include "uio.h"
-#include "socket.h"
-#include "socketvar.h"
-#include "mount.h"
-
-extern struct fileops inodeops;
-struct file *getinode();
-
-/*
- * Change current working directory (``.'').
- */
-chdir()
-{
-
- chdirec(&u.u_cdir);
-}
-
-/*
- * Change notion of root (``/'') directory.
- */
-chroot()
-{
-
- if (suser())
- chdirec(&u.u_rdir);
-}
-
-/*
- * Common routine for chroot and chdir.
- */
-chdirec(ipp)
- register struct inode **ipp;
-{
- register struct inode *ip;
- struct a {
- char *fname;
- } *uap = (struct a *)u.u_ap;
- register struct nameidata *ndp = &u.u_nd;
-
- ndp->ni_nameiop = LOOKUP | FOLLOW;
- ndp->ni_segflg = UIO_USERSPACE;
- ndp->ni_dirp = uap->fname;
- ip = namei(ndp);
- if (ip == NULL)
- return;
- if ((ip->i_mode&IFMT) != IFDIR) {
- u.u_error = ENOTDIR;
- goto bad;
- }
- if (access(ip, IEXEC))
- goto bad;
- IUNLOCK(ip);
- if (*ipp)
- irele(*ipp);
- *ipp = ip;
- return;
-
-bad:
- iput(ip);
-}
-
-/*
- * Open system call.
- */
-open()
-{
- struct a {
- char *fname;
- int mode;
- int crtmode;
- } *uap = (struct a *) u.u_ap;
-
- copen(uap->mode-FOPEN, uap->crtmode, uap->fname);
-}
-
-/*
- * Creat system call.
- */
-creat()
-{
- struct a {
- char *fname;
- int fmode;
- } *uap = (struct a *)u.u_ap;
-
- copen(FWRITE|FCREAT|FTRUNC, uap->fmode, uap->fname);
-}
-
-/*
- * Common code for open and creat.
- * Check permissions, allocate an open file structure,
- * and call the device open routine if any.
- */
-copen(mode, arg, fname)
- register int mode;
- int arg;
- caddr_t fname;
-{
- register struct inode *ip;
- register struct file *fp;
- register struct nameidata *ndp = &u.u_nd;
- int indx;
-
- fp = falloc();
- if (fp == NULL)
- return;
- indx = u.u_r.r_val1;
- ndp->ni_segflg = UIO_USERSPACE;
- ndp->ni_dirp = fname;
- if (mode&FCREAT) {
- if (mode & FEXCL)
- ndp->ni_nameiop = CREATE;
- else
- ndp->ni_nameiop = CREATE | FOLLOW;
- ip = namei(ndp);
- if (ip == NULL) {
- if (u.u_error)
- goto bad1;
- ip = maknode(arg&07777&(~ISVTX), ndp);
- if (ip == NULL)
- goto bad1;
- mode &= ~FTRUNC;
- } else {
- if (mode&FEXCL) {
- u.u_error = EEXIST;
- goto bad;
- }
- mode &= ~FCREAT;
- }
- } else {
- ndp->ni_nameiop = LOOKUP | FOLLOW;
- ip = namei(ndp);
- if (ip == NULL)
- goto bad1;
- }
- if ((ip->i_mode & IFMT) == IFSOCK) {
- u.u_error = EOPNOTSUPP;
- goto bad;
- }
- if ((mode&FCREAT) == 0) {
- if (mode&FREAD)
- if (access(ip, IREAD))
- goto bad;
- if (mode&(FWRITE|FTRUNC)) {
- if (access(ip, IWRITE))
- goto bad;
- if ((ip->i_mode&IFMT) == IFDIR) {
- u.u_error = EISDIR;
- goto bad;
- }
- }
- }
- if (mode&FTRUNC)
- itrunc(ip, (u_long)0);
- IUNLOCK(ip);
- fp->f_flag = mode&FMASK;
- fp->f_type = DTYPE_INODE;
- fp->f_ops = &inodeops;
- fp->f_data = (caddr_t)ip;
- if (setjmp(&u.u_qsave)) {
- if (u.u_error == 0)
- u.u_error = EINTR;
- u.u_ofile[indx] = NULL;
- closef(fp);
- return;
- }
- u.u_error = openi(ip, mode);
- if (u.u_error == 0)
- return;
- ILOCK(ip);
-bad:
- iput(ip);
-bad1:
- u.u_ofile[indx] = NULL;
- fp->f_count--;
-}
-
-/*
- * Mknod system call
- */
-mknod()
-{
- register struct inode *ip;
- register struct a {
- char *fname;
- int fmode;
- int dev;
- } *uap = (struct a *)u.u_ap;
- register struct nameidata *ndp = &u.u_nd;
-
- if (!suser())
- return;
- ndp->ni_nameiop = CREATE;
- ndp->ni_segflg = UIO_USERSPACE;
- ndp->ni_dirp = uap->fname;
- ip = namei(ndp);
- if (ip != NULL) {
- u.u_error = EEXIST;
- goto out;
- }
- if (u.u_error)
- return;
- ip = maknode(uap->fmode, ndp);
- if (ip == NULL)
- return;
- switch (ip->i_mode & IFMT) {
-
- case IFMT: /* used by badsect to flag bad sectors */
- case IFCHR:
- case IFBLK:
- if (uap->dev) {
- /*
- * Want to be able to use this to make badblock
- * inodes, so don't truncate the dev number.
- */
- ip->i_rdev = uap->dev;
- ip->i_flag |= IACC|IUPD|ICHG;
- }
- }
-
-out:
- iput(ip);
-}
-
-/*
- * link system call
- */
-link()
-{
- register struct inode *ip, *xp;
- register struct a {
- char *target;
- char *linkname;
- } *uap = (struct a *)u.u_ap;
- register struct nameidata *ndp = &u.u_nd;
-
- ndp->ni_nameiop = LOOKUP | FOLLOW;
- ndp->ni_segflg = UIO_USERSPACE;
- ndp->ni_dirp = uap->target;
- ip = namei(ndp); /* well, this routine is doomed anyhow */
- if (ip == NULL)
- return;
- if ((ip->i_mode&IFMT) == IFDIR && !suser()) {
- iput(ip);
- return;
- }
- ip->i_nlink++;
- ip->i_flag |= ICHG;
- iupdat(ip, &time, &time, 1);
- IUNLOCK(ip);
- ndp->ni_nameiop = CREATE;
- ndp->ni_segflg = UIO_USERSPACE;
- ndp->ni_dirp = (caddr_t)uap->linkname;
- xp = namei(ndp);
- if (xp != NULL) {
- u.u_error = EEXIST;
- iput(xp);
- goto out;
- }
- if (u.u_error)
- goto out;
- if (ndp->ni_pdir->i_dev != ip->i_dev) {
- iput(ndp->ni_pdir);
- u.u_error = EXDEV;
- goto out;
- }
- u.u_error = direnter(ip, ndp);
-out:
- if (u.u_error) {
- ip->i_nlink--;
- ip->i_flag |= ICHG;
- }
- irele(ip);
-}
-
-/*
- * symlink -- make a symbolic link
- */
-symlink()
-{
- register struct a {
- char *target;
- char *linkname;
- } *uap = (struct a *)u.u_ap;
- register struct inode *ip;
- register char *tp;
- register c, nc;
- register struct nameidata *ndp = &u.u_nd;
-
- tp = uap->target;
- nc = 0;
- while (c = fubyte(tp)) {
- if (c < 0) {
- u.u_error = EFAULT;
- return;
+ * %sccs.include.redist.c%
+ *
+ * @(#)ffs_vnops.c 7.93 (Berkeley) %G%
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/resourcevar.h>
+#include <sys/kernel.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/conf.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/malloc.h>
+
+#include <vm/vm.h>
+
+#include <miscfs/specfs/specdev.h>
+#include <miscfs/fifofs/fifo.h>
+
+#include <ufs/ufs/lockf.h>
+#include <ufs/ufs/quota.h>
+#include <ufs/ufs/inode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ufs/ufs_extern.h>
+
+#include <ufs/ffs/fs.h>
+#include <ufs/ffs/ffs_extern.h>
+
+/* Global vfs data structures for ufs. */
+int (**ffs_vnodeop_p)();
+struct vnodeopv_entry_desc ffs_vnodeop_entries[] = {
+ { &vop_default_desc, vn_default_error },
+ { &vop_lookup_desc, ufs_lookup }, /* lookup */
+ { &vop_create_desc, ufs_create }, /* create */
+ { &vop_mknod_desc, ufs_mknod }, /* mknod */
+ { &vop_open_desc, ufs_open }, /* open */
+ { &vop_close_desc, ufs_close }, /* close */
+ { &vop_access_desc, ufs_access }, /* access */
+ { &vop_getattr_desc, ufs_getattr }, /* getattr */
+ { &vop_setattr_desc, ufs_setattr }, /* setattr */
+ { &vop_read_desc, ffs_read }, /* read */
+ { &vop_write_desc, ffs_write }, /* write */
+ { &vop_ioctl_desc, ufs_ioctl }, /* ioctl */
+ { &vop_select_desc, ufs_select }, /* select */
+ { &vop_mmap_desc, ufs_mmap }, /* mmap */
+ { &vop_fsync_desc, ffs_fsync }, /* fsync */
+ { &vop_seek_desc, ufs_seek }, /* seek */
+ { &vop_remove_desc, ufs_remove }, /* remove */
+ { &vop_link_desc, ufs_link }, /* link */
+ { &vop_rename_desc, ufs_rename }, /* rename */
+ { &vop_mkdir_desc, ufs_mkdir }, /* mkdir */
+ { &vop_rmdir_desc, ufs_rmdir }, /* rmdir */
+ { &vop_symlink_desc, ufs_symlink }, /* symlink */
+ { &vop_readdir_desc, ufs_readdir }, /* readdir */
+ { &vop_readlink_desc, ufs_readlink }, /* readlink */
+ { &vop_abortop_desc, ufs_abortop }, /* abortop */
+ { &vop_inactive_desc, ffs_inactive }, /* inactive */
+ { &vop_reclaim_desc, ufs_reclaim }, /* reclaim */
+ { &vop_lock_desc, ufs_lock }, /* lock */
+ { &vop_unlock_desc, ufs_unlock }, /* unlock */
+ { &vop_bmap_desc, ufs_bmap }, /* bmap */
+ { &vop_strategy_desc, ufs_strategy }, /* strategy */
+ { &vop_print_desc, ufs_print }, /* print */
+ { &vop_islocked_desc, ufs_islocked }, /* islocked */
+ { &vop_advlock_desc, ufs_advlock }, /* advlock */
+ { &vop_blkatoff_desc, ffs_blkatoff }, /* blkatoff */
+ { &vop_valloc_desc, ffs_valloc }, /* valloc */
+ { &vop_vfree_desc, ffs_vfree }, /* vfree */
+ { &vop_truncate_desc, ffs_truncate }, /* truncate */
+ { &vop_update_desc, ffs_update }, /* update */
+ { &vop_bwrite_desc, vn_bwrite },
+ { (struct vnodeop_desc*)NULL, (int(*)())NULL }
+};
+struct vnodeopv_desc ffs_vnodeop_opv_desc =
+ { &ffs_vnodeop_p, ffs_vnodeop_entries };
+
+int (**ffs_specop_p)();
+struct vnodeopv_entry_desc ffs_specop_entries[] = {
+ { &vop_default_desc, vn_default_error },
+ { &vop_lookup_desc, spec_lookup }, /* lookup */
+ { &vop_create_desc, spec_create }, /* create */
+ { &vop_mknod_desc, spec_mknod }, /* mknod */
+ { &vop_open_desc, spec_open }, /* open */
+ { &vop_close_desc, ufsspec_close }, /* close */
+ { &vop_access_desc, ufs_access }, /* access */
+ { &vop_getattr_desc, ufs_getattr }, /* getattr */
+ { &vop_setattr_desc, ufs_setattr }, /* setattr */
+ { &vop_read_desc, ufsspec_read }, /* read */
+ { &vop_write_desc, ufsspec_write }, /* write */
+ { &vop_ioctl_desc, spec_ioctl }, /* ioctl */
+ { &vop_select_desc, spec_select }, /* select */
+ { &vop_mmap_desc, spec_mmap }, /* mmap */
+ { &vop_fsync_desc, ffs_fsync }, /* fsync */
+ { &vop_seek_desc, spec_seek }, /* seek */
+ { &vop_remove_desc, spec_remove }, /* remove */
+ { &vop_link_desc, spec_link }, /* link */
+ { &vop_rename_desc, spec_rename }, /* rename */
+ { &vop_mkdir_desc, spec_mkdir }, /* mkdir */
+ { &vop_rmdir_desc, spec_rmdir }, /* rmdir */
+ { &vop_symlink_desc, spec_symlink }, /* symlink */
+ { &vop_readdir_desc, spec_readdir }, /* readdir */
+ { &vop_readlink_desc, spec_readlink }, /* readlink */
+ { &vop_abortop_desc, spec_abortop }, /* abortop */
+ { &vop_inactive_desc, ffs_inactive }, /* inactive */
+ { &vop_reclaim_desc, ufs_reclaim }, /* reclaim */
+ { &vop_lock_desc, ufs_lock }, /* lock */
+ { &vop_unlock_desc, ufs_unlock }, /* unlock */
+ { &vop_bmap_desc, spec_bmap }, /* bmap */
+ { &vop_strategy_desc, spec_strategy }, /* strategy */
+ { &vop_print_desc, ufs_print }, /* print */
+ { &vop_islocked_desc, ufs_islocked }, /* islocked */
+ { &vop_advlock_desc, spec_advlock }, /* advlock */
+ { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */
+ { &vop_valloc_desc, spec_valloc }, /* valloc */
+ { &vop_vfree_desc, ffs_vfree }, /* vfree */
+ { &vop_truncate_desc, spec_truncate }, /* truncate */
+ { &vop_update_desc, ffs_update }, /* update */
+ { &vop_bwrite_desc, vn_bwrite },
+ { (struct vnodeop_desc*)NULL, (int(*)())NULL }
+};
+struct vnodeopv_desc ffs_specop_opv_desc =
+ { &ffs_specop_p, ffs_specop_entries };
+
+#ifdef FIFO
+int (**ffs_fifoop_p)();
+struct vnodeopv_entry_desc ffs_fifoop_entries[] = {
+ { &vop_default_desc, vn_default_error },
+ { &vop_lookup_desc, fifo_lookup }, /* lookup */
+ { &vop_create_desc, fifo_create }, /* create */
+ { &vop_mknod_desc, fifo_mknod }, /* mknod */
+ { &vop_open_desc, fifo_open }, /* open */
+ { &vop_close_desc, ufsfifo_close }, /* close */
+ { &vop_access_desc, ufs_access }, /* access */
+ { &vop_getattr_desc, ufs_getattr }, /* getattr */
+ { &vop_setattr_desc, ufs_setattr }, /* setattr */
+ { &vop_read_desc, ufsfifo_read }, /* read */
+ { &vop_write_desc, ufsfifo_write }, /* write */
+ { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */
+ { &vop_select_desc, fifo_select }, /* select */
+ { &vop_mmap_desc, fifo_mmap }, /* mmap */
+ { &vop_fsync_desc, ffs_fsync }, /* fsync */
+ { &vop_seek_desc, fifo_seek }, /* seek */
+ { &vop_remove_desc, fifo_remove }, /* remove */
+ { &vop_link_desc, fifo_link }, /* link */
+ { &vop_rename_desc, fifo_rename }, /* rename */
+ { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */
+ { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */
+ { &vop_symlink_desc, fifo_symlink }, /* symlink */
+ { &vop_readdir_desc, fifo_readdir }, /* readdir */
+ { &vop_readlink_desc, fifo_readlink }, /* readlink */
+ { &vop_abortop_desc, fifo_abortop }, /* abortop */
+ { &vop_inactive_desc, ffs_inactive }, /* inactive */
+ { &vop_reclaim_desc, ufs_reclaim }, /* reclaim */
+ { &vop_lock_desc, ufs_lock }, /* lock */
+ { &vop_unlock_desc, ufs_unlock }, /* unlock */
+ { &vop_bmap_desc, fifo_bmap }, /* bmap */
+ { &vop_strategy_desc, fifo_strategy }, /* strategy */
+ { &vop_print_desc, ufs_print }, /* print */
+ { &vop_islocked_desc, ufs_islocked }, /* islocked */
+ { &vop_advlock_desc, fifo_advlock }, /* advlock */
+ { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */
+ { &vop_valloc_desc, fifo_valloc }, /* valloc */
+ { &vop_vfree_desc, ffs_vfree }, /* vfree */
+ { &vop_truncate_desc, fifo_truncate }, /* truncate */
+ { &vop_update_desc, ffs_update }, /* update */
+ { &vop_bwrite_desc, vn_bwrite },
+ { (struct vnodeop_desc*)NULL, (int(*)())NULL }
+};
+struct vnodeopv_desc ffs_fifoop_opv_desc =
+ { &ffs_fifoop_p, ffs_fifoop_entries };
+#endif /* FIFO */
+
+
+/*
+ * Vnode op for reading.
+ */
+/* ARGSUSED */
+ffs_read(ap)
+ struct vop_read_args /* {
+ struct vnode *a_vp;
+ struct uio *a_uio;
+ int a_ioflag;
+ struct ucred *a_cred;
+ } */ *ap;
+{
+ register struct vnode *vp = ap->a_vp;
+ register struct inode *ip = VTOI(vp);
+ register struct uio *uio = ap->a_uio;
+ register struct fs *fs;
+ struct buf *bp;
+ daddr_t lbn, bn, rablock;
+ off_t diff;
+ int rasize, error = 0;
+ long size, n, on;
+
+#ifdef DIAGNOSTIC
+ int type;
+ if (uio->uio_rw != UIO_READ)
+ panic("ffs_read mode");
+ type = ip->i_mode & IFMT;
+ if (type != IFDIR && type != IFREG && type != IFLNK)
+ panic("ffs_read type");
+ if (type == IFLNK && (int)ip->i_size < vp->v_mount->mnt_maxsymlinklen)
+ panic("read short symlink");
+#endif
+ if (uio->uio_resid == 0)
+ return (0);
+ fs = ip->i_fs;
+ if ((u_quad_t)uio->uio_offset > fs->fs_maxfilesize)
+ return (EFBIG);
+ ip->i_flag |= IACC;
+ do {
+ lbn = lblkno(fs, uio->uio_offset);
+ on = blkoff(fs, uio->uio_offset);
+ n = min((unsigned)(fs->fs_bsize - on), uio->uio_resid);
+ diff = ip->i_size - uio->uio_offset;
+ if (diff <= 0)
+ return (0);
+ if (diff < n)
+ n = diff;
+ size = blksize(fs, ip, lbn);
+ rablock = lbn + 1;
+ if (vp->v_lastr + 1 == lbn &&
+ lblktosize(fs, rablock) < ip->i_size) {
+ rasize = blksize(fs, ip, rablock);
+ error = breadn(vp, lbn, size, &rablock,
+ &rasize, 1, NOCRED, &bp);
+ } else
+ error = bread(vp, lbn, size, NOCRED, &bp);
+ vp->v_lastr = lbn;
+ n = min(n, size - bp->b_resid);
+ if (error) {
+ brelse(bp);
+ return (error);