+ register struct inode *ip = VTOI(vp);
+#ifdef QUOTA
+ register long change;
+#endif
+ int error;
+
+ if (uid == (u_short)VNOVAL)
+ uid = ip->i_uid;
+ if (gid == (u_short)VNOVAL)
+ gid = ip->i_gid;
+ /*
+ * If we don't own the file, are trying to change the owner
+ * of the file, or are not a member of the target group,
+ * the caller must be superuser or the call fails.
+ */
+ if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
+ !groupmember((gid_t)gid, cred)) &&
+ (error = suser(cred, &u.u_acflag)))
+ return (error);
+#ifdef QUOTA
+ if (ip->i_uid == uid) /* this just speeds things a little */
+ change = 0;
+ else
+ change = ip->i_blocks;
+ (void) chkdq(ip, -change, 1);
+ (void) chkiq(ip->i_dev, ip, ip->i_uid, 1);
+ dqrele(ip->i_dquot);
+#endif
+ if (ip->i_uid != uid && cred->cr_uid != 0)
+ ip->i_mode &= ~ISUID;
+ if (ip->i_gid != gid && cred->cr_uid != 0)
+ ip->i_mode &= ~ISGID;
+ ip->i_uid = uid;
+ ip->i_gid = gid;
+ ip->i_flag |= ICHG;
+#ifdef QUOTA
+ ip->i_dquot = inoquota(ip);
+ (void) chkdq(ip, change, 1);
+ (void) chkiq(ip->i_dev, (struct inode *)NULL, (uid_t)uid, 1);
+ return (u.u_error); /* should == 0 ALWAYS !! */
+#else
+ return (0);
+#endif
+}
+
+/*
+ * Vnode op for reading.
+ */
+/* ARGSUSED */
+ufs_read(vp, uio, ioflag, cred)
+ struct vnode *vp;
+ register struct uio *uio;
+ int ioflag;
+ struct ucred *cred;
+{
+ register struct inode *ip = VTOI(vp);
+ register struct fs *fs;
+ struct buf *bp;
+ daddr_t lbn, bn, rablock;
+ int size, rasize, diff, error = 0;
+ long n, on, type;
+
+ if (uio->uio_rw != UIO_READ)
+ panic("ufs_read mode");
+ type = ip->i_mode & IFMT;
+ if (type != IFDIR && type != IFREG && type != IFLNK)
+ panic("ufs_read type");
+ if (uio->uio_resid == 0)
+ return (0);
+ if (uio->uio_offset < 0)
+ return (EINVAL);
+ ip->i_flag |= IACC;
+ fs = ip->i_fs;
+ 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;
+ if (error = bmap(ip, lbn, &bn, &rablock, &rasize))
+ return (error);
+ size = blksize(fs, ip, lbn);
+ if ((long)bn < 0) {
+ bp = geteblk(size);
+ clrbuf(bp);
+ } else if (ip->i_lastr + 1 == lbn)
+ error = breada(ip->i_devvp, bn, size, rablock, rasize,
+ NOCRED, &bp);
+ else
+ error = bread(ip->i_devvp, bn, size, NOCRED, &bp);
+ ip->i_lastr = lbn;
+ n = MIN(n, size - bp->b_resid);
+ if (error) {
+ brelse(bp);
+ return (error);