123405Smckusick /*
263377Sbostic * Copyright (c) 1982, 1986, 1989, 1993
363377Sbostic * The Regents of the University of California. All rights reserved.
465774Sbostic * (c) UNIX System Laboratories, Inc.
565774Sbostic * All or some portions of this file are derived from material licensed
665774Sbostic * to the University of California by American Telephone and Telegraph
765774Sbostic * Co. or Unix System Laboratories, Inc. and are reproduced herein with
865774Sbostic * the permission of UNIX System Laboratories, Inc.
923405Smckusick *
1044539Sbostic * %sccs.include.redist.c%
1137737Smckusick *
12*67371Smckusick * @(#)ufs_vnops.c 8.11 (Berkeley) 06/04/94
1323405Smckusick */
1437Sbill
1551514Sbostic #include <sys/param.h>
1651514Sbostic #include <sys/systm.h>
1751514Sbostic #include <sys/namei.h>
1851514Sbostic #include <sys/resourcevar.h>
1951514Sbostic #include <sys/kernel.h>
2051514Sbostic #include <sys/file.h>
2151514Sbostic #include <sys/stat.h>
2251514Sbostic #include <sys/buf.h>
2351514Sbostic #include <sys/proc.h>
2451514Sbostic #include <sys/conf.h>
2551514Sbostic #include <sys/mount.h>
2651514Sbostic #include <sys/vnode.h>
2751514Sbostic #include <sys/malloc.h>
2854608Smckusick #include <sys/dirent.h>
2937Sbill
3053476Smckusick #include <vm/vm.h>
3153476Smckusick
3255040Smckusick #include <miscfs/specfs/specdev.h>
3355040Smckusick
3451514Sbostic #include <ufs/ufs/lockf.h>
3551514Sbostic #include <ufs/ufs/quota.h>
3651514Sbostic #include <ufs/ufs/inode.h>
3751514Sbostic #include <ufs/ufs/dir.h>
3851514Sbostic #include <ufs/ufs/ufsmount.h>
3951514Sbostic #include <ufs/ufs/ufs_extern.h>
4047571Skarels
4154123Storek static int ufs_chmod __P((struct vnode *, int, struct ucred *, struct proc *));
4254123Storek static int ufs_chown
4353476Smckusick __P((struct vnode *, uid_t, gid_t, struct ucred *, struct proc *));
4451514Sbostic
4552022Smckusick union _qcvt {
4652022Smckusick quad_t qcvt;
4752022Smckusick long val[2];
4852022Smckusick };
4952022Smckusick #define SETHIGH(q, h) { \
5052022Smckusick union _qcvt tmp; \
5152022Smckusick tmp.qcvt = (q); \
5252022Smckusick tmp.val[_QUAD_HIGHWORD] = (h); \
5352022Smckusick (q) = tmp.qcvt; \
5452022Smckusick }
5552022Smckusick #define SETLOW(q, l) { \
5652022Smckusick union _qcvt tmp; \
5752022Smckusick tmp.qcvt = (q); \
5852022Smckusick tmp.val[_QUAD_LOWWORD] = (l); \
5952022Smckusick (q) = tmp.qcvt; \
6052022Smckusick }
6152022Smckusick
629167Ssam /*
6337737Smckusick * Create a regular file
649167Ssam */
6551514Sbostic int
ufs_create(ap)6653812Smckusick ufs_create(ap)
6754455Smckusick struct vop_create_args /* {
6854455Smckusick struct vnode *a_dvp;
6954455Smckusick struct vnode **a_vpp;
7054455Smckusick struct componentname *a_cnp;
7154455Smckusick struct vattr *a_vap;
7254455Smckusick } */ *ap;
736254Sroot {
7437737Smckusick int error;
756254Sroot
7651514Sbostic if (error =
7753812Smckusick ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
7853812Smckusick ap->a_dvp, ap->a_vpp, ap->a_cnp))
7937737Smckusick return (error);
8037737Smckusick return (0);
816254Sroot }
826254Sroot
8337Sbill /*
8437737Smckusick * Mknod vnode call
856254Sroot */
8637737Smckusick /* ARGSUSED */
8751514Sbostic int
ufs_mknod(ap)8853812Smckusick ufs_mknod(ap)
8954455Smckusick struct vop_mknod_args /* {
9054455Smckusick struct vnode *a_dvp;
9154455Smckusick struct vnode **a_vpp;
9254455Smckusick struct componentname *a_cnp;
9354455Smckusick struct vattr *a_vap;
9454455Smckusick } */ *ap;
956254Sroot {
9653812Smckusick register struct vattr *vap = ap->a_vap;
9753812Smckusick register struct vnode **vpp = ap->a_vpp;
9851551Smckusick register struct inode *ip;
9937737Smckusick int error;
1006254Sroot
10151514Sbostic if (error =
10253812Smckusick ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
10353812Smckusick ap->a_dvp, vpp, ap->a_cnp))
10437737Smckusick return (error);
10553812Smckusick ip = VTOI(*vpp);
10664600Sbostic ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
10753812Smckusick if (vap->va_rdev != VNOVAL) {
10837737Smckusick /*
10937737Smckusick * Want to be able to use this to make badblock
11037737Smckusick * inodes, so don't truncate the dev number.
11137737Smckusick */
11253812Smckusick ip->i_rdev = vap->va_rdev;
11312756Ssam }
11437737Smckusick /*
11566594Sbostic * Remove inode so that it will be reloaded by VFS_VGET and
11666594Sbostic * checked to see if it is an alias of an existing entry in
11766594Sbostic * the inode cache.
11837737Smckusick */
11953812Smckusick vput(*vpp);
12053812Smckusick (*vpp)->v_type = VNON;
12153812Smckusick vgone(*vpp);
12253812Smckusick *vpp = 0;
12337737Smckusick return (0);
1246254Sroot }
1256254Sroot
1266254Sroot /*
12737737Smckusick * Open called.
12837737Smckusick *
12937737Smckusick * Nothing to do.
1306254Sroot */
13137737Smckusick /* ARGSUSED */
13251514Sbostic int
ufs_open(ap)13353812Smckusick ufs_open(ap)
13454455Smckusick struct vop_open_args /* {
13554455Smckusick struct vnode *a_vp;
13654455Smckusick int a_mode;
13754455Smckusick struct ucred *a_cred;
13854455Smckusick struct proc *a_p;
13954455Smckusick } */ *ap;
1406254Sroot {
1416254Sroot
14259316Smckusick /*
14359316Smckusick * Files marked append-only must be opened for appending.
14459316Smckusick */
14559316Smckusick if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
14659316Smckusick (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
14759316Smckusick return (EPERM);
14837737Smckusick return (0);
1496254Sroot }
1506254Sroot
1516254Sroot /*
15264517Sbostic * Close called.
15337737Smckusick *
15437737Smckusick * Update the times on the inode.
1556254Sroot */
15637737Smckusick /* ARGSUSED */
15751514Sbostic int
ufs_close(ap)15853812Smckusick ufs_close(ap)
15954455Smckusick struct vop_close_args /* {
16054455Smckusick struct vnode *a_vp;
16154455Smckusick int a_fflag;
16254455Smckusick struct ucred *a_cred;
16354455Smckusick struct proc *a_p;
16454455Smckusick } */ *ap;
1656254Sroot {
16653812Smckusick register struct vnode *vp = ap->a_vp;
16753812Smckusick register struct inode *ip = VTOI(vp);
1686254Sroot
16964600Sbostic if (vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED))
17037737Smckusick ITIMES(ip, &time, &time);
17137737Smckusick return (0);
1726254Sroot }
1736254Sroot
17451514Sbostic int
ufs_access(ap)17553812Smckusick ufs_access(ap)
17654455Smckusick struct vop_access_args /* {
17754455Smckusick struct vnode *a_vp;
17854455Smckusick int a_mode;
17954455Smckusick struct ucred *a_cred;
18054455Smckusick struct proc *a_p;
18154455Smckusick } */ *ap;
1826254Sroot {
18353812Smckusick register struct vnode *vp = ap->a_vp;
18453812Smckusick register struct inode *ip = VTOI(vp);
18553812Smckusick register struct ucred *cred = ap->a_cred;
18664870Sbostic mode_t mask, mode = ap->a_mode;
18741312Smckusick register gid_t *gp;
18841312Smckusick int i, error;
1896254Sroot
19041312Smckusick #ifdef DIAGNOSTIC
19153812Smckusick if (!VOP_ISLOCKED(vp)) {
19253812Smckusick vprint("ufs_access: not locked", vp);
19341312Smckusick panic("ufs_access: not locked");
19441312Smckusick }
19541312Smckusick #endif
19641312Smckusick #ifdef QUOTA
19764517Sbostic if (mode & VWRITE)
19853812Smckusick switch (vp->v_type) {
19964517Sbostic case VDIR:
20064517Sbostic case VLNK:
20164517Sbostic case VREG:
20241312Smckusick if (error = getinoquota(ip))
20341312Smckusick return (error);
20464517Sbostic break;
20541312Smckusick }
20664517Sbostic #endif
20764517Sbostic
20864517Sbostic /* If immutable bit set, nobody gets to write it. */
20959316Smckusick if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
21059316Smckusick return (EPERM);
21164517Sbostic
21264517Sbostic /* Otherwise, user id 0 always gets access. */
21353812Smckusick if (cred->cr_uid == 0)
21441312Smckusick return (0);
21564517Sbostic
21664870Sbostic mask = 0;
21764870Sbostic
21864517Sbostic /* Otherwise, check the owner. */
21964870Sbostic if (cred->cr_uid == ip->i_uid) {
22064870Sbostic if (mode & VEXEC)
22164870Sbostic mask |= S_IXUSR;
22264870Sbostic if (mode & VREAD)
22364870Sbostic mask |= S_IRUSR;
22464870Sbostic if (mode & VWRITE)
22564870Sbostic mask |= S_IWUSR;
22664870Sbostic return ((ip->i_mode & mask) == mask ? 0 : EACCES);
22764870Sbostic }
22864517Sbostic
22964517Sbostic /* Otherwise, check the groups. */
23064517Sbostic for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
23164870Sbostic if (ip->i_gid == *gp) {
23264870Sbostic if (mode & VEXEC)
23364870Sbostic mask |= S_IXGRP;
23464870Sbostic if (mode & VREAD)
23564870Sbostic mask |= S_IRGRP;
23664870Sbostic if (mode & VWRITE)
23764870Sbostic mask |= S_IWGRP;
23864870Sbostic return ((ip->i_mode & mask) == mask ? 0 : EACCES);
23964870Sbostic }
24064517Sbostic
24164517Sbostic /* Otherwise, check everyone else. */
24264870Sbostic if (mode & VEXEC)
24364870Sbostic mask |= S_IXOTH;
24464870Sbostic if (mode & VREAD)
24564870Sbostic mask |= S_IROTH;
24664870Sbostic if (mode & VWRITE)
24764870Sbostic mask |= S_IWOTH;
24864870Sbostic return ((ip->i_mode & mask) == mask ? 0 : EACCES);
2496254Sroot }
2506254Sroot
25137737Smckusick /* ARGSUSED */
25251514Sbostic int
ufs_getattr(ap)25353812Smckusick ufs_getattr(ap)
25454455Smckusick struct vop_getattr_args /* {
25554455Smckusick struct vnode *a_vp;
25654455Smckusick struct vattr *a_vap;
25754455Smckusick struct ucred *a_cred;
25854455Smckusick struct proc *a_p;
25954455Smckusick } */ *ap;
2606254Sroot {
26153812Smckusick register struct vnode *vp = ap->a_vp;
26253812Smckusick register struct inode *ip = VTOI(vp);
26353812Smckusick register struct vattr *vap = ap->a_vap;
2646254Sroot
26537737Smckusick ITIMES(ip, &time, &time);
2666254Sroot /*
26737737Smckusick * Copy from inode table
2686254Sroot */
26953812Smckusick vap->va_fsid = ip->i_dev;
27053812Smckusick vap->va_fileid = ip->i_number;
27153812Smckusick vap->va_mode = ip->i_mode & ~IFMT;
27253812Smckusick vap->va_nlink = ip->i_nlink;
27353812Smckusick vap->va_uid = ip->i_uid;
27453812Smckusick vap->va_gid = ip->i_gid;
27553812Smckusick vap->va_rdev = (dev_t)ip->i_rdev;
27654129Smckusick vap->va_size = ip->i_din.di_size;
27753812Smckusick vap->va_atime = ip->i_atime;
27853812Smckusick vap->va_mtime = ip->i_mtime;
27953812Smckusick vap->va_ctime = ip->i_ctime;
28053812Smckusick vap->va_flags = ip->i_flags;
28153812Smckusick vap->va_gen = ip->i_gen;
28237737Smckusick /* this doesn't belong here */
28353812Smckusick if (vp->v_type == VBLK)
28453812Smckusick vap->va_blocksize = BLKDEV_IOSIZE;
28553812Smckusick else if (vp->v_type == VCHR)
28653812Smckusick vap->va_blocksize = MAXBSIZE;
2877142Smckusick else
28853812Smckusick vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
28953812Smckusick vap->va_bytes = dbtob(ip->i_blocks);
29053812Smckusick vap->va_type = vp->v_type;
29153812Smckusick vap->va_filerev = ip->i_modrev;
29237737Smckusick return (0);
2936254Sroot }
2946254Sroot
2956254Sroot /*
29637737Smckusick * Set attribute vnode op. called from several syscalls
2976254Sroot */
29851514Sbostic int
ufs_setattr(ap)29953812Smckusick ufs_setattr(ap)
30054455Smckusick struct vop_setattr_args /* {
30154455Smckusick struct vnode *a_vp;
30254455Smckusick struct vattr *a_vap;
30354455Smckusick struct ucred *a_cred;
30454455Smckusick struct proc *a_p;
30554455Smckusick } */ *ap;
3066254Sroot {
30753812Smckusick register struct vattr *vap = ap->a_vap;
30853812Smckusick register struct vnode *vp = ap->a_vp;
30953812Smckusick register struct inode *ip = VTOI(vp);
31053812Smckusick register struct ucred *cred = ap->a_cred;
31153812Smckusick register struct proc *p = ap->a_p;
31254104Smckusick struct timeval atimeval, mtimeval;
31351514Sbostic int error;
3146254Sroot
31537737Smckusick /*
31651514Sbostic * Check for unsettable attributes.
31737737Smckusick */
31853812Smckusick if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
31953812Smckusick (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
32053812Smckusick (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
32153812Smckusick ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
32237737Smckusick return (EINVAL);
32316540Ssam }
32459316Smckusick if (vap->va_flags != VNOVAL) {
32559316Smckusick if (cred->cr_uid != ip->i_uid &&
32659316Smckusick (error = suser(cred, &p->p_acflag)))
32759316Smckusick return (error);
32859316Smckusick if (cred->cr_uid == 0) {
32959316Smckusick if ((ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) &&
33059316Smckusick securelevel > 0)
33159316Smckusick return (EPERM);
33259316Smckusick ip->i_flags = vap->va_flags;
33359316Smckusick } else {
33459316Smckusick if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND))
33559316Smckusick return (EPERM);
33659873Smckusick ip->i_flags &= SF_SETTABLE;
33759873Smckusick ip->i_flags |= (vap->va_flags & UF_SETTABLE);
33859316Smckusick }
33964600Sbostic ip->i_flag |= IN_CHANGE;
34059316Smckusick if (vap->va_flags & (IMMUTABLE | APPEND))
34159316Smckusick return (0);
34259316Smckusick }
34359316Smckusick if (ip->i_flags & (IMMUTABLE | APPEND))
34459316Smckusick return (EPERM);
34537737Smckusick /*
34637737Smckusick * Go through the fields and update iff not VNOVAL.
34737737Smckusick */
34853812Smckusick if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL)
34953812Smckusick if (error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p))
35037737Smckusick return (error);
35153812Smckusick if (vap->va_size != VNOVAL) {
35253812Smckusick if (vp->v_type == VDIR)
35337737Smckusick return (EISDIR);
35454455Smckusick if (error = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p))
35537737Smckusick return (error);
35613878Ssam }
35753812Smckusick ip = VTOI(vp);
35854104Smckusick if (vap->va_atime.ts_sec != VNOVAL || vap->va_mtime.ts_sec != VNOVAL) {
35953812Smckusick if (cred->cr_uid != ip->i_uid &&
36059316Smckusick (error = suser(cred, &p->p_acflag)) &&
36159316Smckusick ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
36259316Smckusick (error = VOP_ACCESS(vp, VWRITE, cred, p))))
36337773Smckusick return (error);
36454104Smckusick if (vap->va_atime.ts_sec != VNOVAL)
36564600Sbostic ip->i_flag |= IN_ACCESS;
36654104Smckusick if (vap->va_mtime.ts_sec != VNOVAL)
36764600Sbostic ip->i_flag |= IN_CHANGE | IN_UPDATE;
36854104Smckusick atimeval.tv_sec = vap->va_atime.ts_sec;
36954104Smckusick atimeval.tv_usec = vap->va_atime.ts_nsec / 1000;
37054104Smckusick mtimeval.tv_sec = vap->va_mtime.ts_sec;
37154104Smckusick mtimeval.tv_usec = vap->va_mtime.ts_nsec / 1000;
37254104Smckusick if (error = VOP_UPDATE(vp, &atimeval, &mtimeval, 1))
37337737Smckusick return (error);
3746254Sroot }
37551514Sbostic error = 0;
37653812Smckusick if (vap->va_mode != (mode_t)VNOVAL)
37753812Smckusick error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
37837737Smckusick return (error);
3796254Sroot }
3806254Sroot
3816254Sroot /*
3829167Ssam * Change the mode on a file.
3839167Ssam * Inode must be locked before calling.
3849167Ssam */
38551780Smarc static int
ufs_chmod(vp,mode,cred,p)38653229Smckusick ufs_chmod(vp, mode, cred, p)
38737737Smckusick register struct vnode *vp;
3887701Ssam register int mode;
38953229Smckusick register struct ucred *cred;
39047571Skarels struct proc *p;
3917701Ssam {
39237737Smckusick register struct inode *ip = VTOI(vp);
39337773Smckusick int error;
3947868Sroot
39537773Smckusick if (cred->cr_uid != ip->i_uid &&
39647571Skarels (error = suser(cred, &p->p_acflag)))
39737773Smckusick return (error);
39837737Smckusick if (cred->cr_uid) {
39964429Sbostic if (vp->v_type != VDIR && (mode & S_ISTXT))
40045783Sbostic return (EFTYPE);
40146206Smckusick if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
40245783Sbostic return (EPERM);
4037439Sroot }
40464429Sbostic ip->i_mode &= ~ALLPERMS;
40564871Smckusick ip->i_mode |= (mode & ALLPERMS);
40664871Smckusick ip->i_flag |= IN_CHANGE;
40764429Sbostic if ((vp->v_flag & VTEXT) && (ip->i_mode & S_ISTXT) == 0)
40845722Smckusick (void) vnode_pager_uncache(vp);
40921015Smckusick return (0);
4105992Swnj }
4115992Swnj
4129167Ssam /*
4137701Ssam * Perform chown operation on inode ip;
4147701Ssam * inode must be locked prior to call.
4157701Ssam */
41651780Smarc static int
ufs_chown(vp,uid,gid,cred,p)41753229Smckusick ufs_chown(vp, uid, gid, cred, p)
41837737Smckusick register struct vnode *vp;
41953476Smckusick uid_t uid;
42053476Smckusick gid_t gid;
42153229Smckusick struct ucred *cred;
42247571Skarels struct proc *p;
4237701Ssam {
42437737Smckusick register struct inode *ip = VTOI(vp);
42541312Smckusick uid_t ouid;
42641312Smckusick gid_t ogid;
42741312Smckusick int error = 0;
4287701Ssam #ifdef QUOTA
42941312Smckusick register int i;
43041312Smckusick long change;
43111811Ssam #endif
4327701Ssam
43353476Smckusick if (uid == (uid_t)VNOVAL)
43411811Ssam uid = ip->i_uid;
43553476Smckusick if (gid == (gid_t)VNOVAL)
43611811Ssam gid = ip->i_gid;
43736614Sbostic /*
43836614Sbostic * If we don't own the file, are trying to change the owner
43936614Sbostic * of the file, or are not a member of the target group,
44036614Sbostic * the caller must be superuser or the call fails.
44136614Sbostic */
44237737Smckusick if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
44337737Smckusick !groupmember((gid_t)gid, cred)) &&
44447571Skarels (error = suser(cred, &p->p_acflag)))
44537737Smckusick return (error);
44664517Sbostic ogid = ip->i_gid;
44741312Smckusick ouid = ip->i_uid;
44811811Ssam #ifdef QUOTA
44941312Smckusick if (error = getinoquota(ip))
45041312Smckusick return (error);
45141312Smckusick if (ouid == uid) {
45241312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]);
45341312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT;
45441312Smckusick }
45541312Smckusick if (ogid == gid) {
45641312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]);
45741312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT;
45841312Smckusick }
45941312Smckusick change = ip->i_blocks;
46041312Smckusick (void) chkdq(ip, -change, cred, CHOWN);
46141312Smckusick (void) chkiq(ip, -1, cred, CHOWN);
46241312Smckusick for (i = 0; i < MAXQUOTAS; i++) {
46341312Smckusick dqrele(vp, ip->i_dquot[i]);
46441312Smckusick ip->i_dquot[i] = NODQUOT;
46541312Smckusick }
4667482Skre #endif
46764517Sbostic ip->i_gid = gid;
46811811Ssam ip->i_uid = uid;
4697701Ssam #ifdef QUOTA
47041312Smckusick if ((error = getinoquota(ip)) == 0) {
47141312Smckusick if (ouid == uid) {
47241312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]);
47341312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT;
47441312Smckusick }
47541312Smckusick if (ogid == gid) {
47641312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]);
47741312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT;
47841312Smckusick }
47941312Smckusick if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
48041312Smckusick if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
48141927Smckusick goto good;
48241312Smckusick else
48341312Smckusick (void) chkdq(ip, -change, cred, CHOWN|FORCE);
48441312Smckusick }
48541312Smckusick for (i = 0; i < MAXQUOTAS; i++) {
48641312Smckusick dqrele(vp, ip->i_dquot[i]);
48741312Smckusick ip->i_dquot[i] = NODQUOT;
48841312Smckusick }
48941312Smckusick }
49064517Sbostic ip->i_gid = ogid;
49141312Smckusick ip->i_uid = ouid;
49241312Smckusick if (getinoquota(ip) == 0) {
49341312Smckusick if (ouid == uid) {
49441312Smckusick dqrele(vp, ip->i_dquot[USRQUOTA]);
49541312Smckusick ip->i_dquot[USRQUOTA] = NODQUOT;
49641312Smckusick }
49741312Smckusick if (ogid == gid) {
49841312Smckusick dqrele(vp, ip->i_dquot[GRPQUOTA]);
49941312Smckusick ip->i_dquot[GRPQUOTA] = NODQUOT;
50041312Smckusick }
50141927Smckusick (void) chkdq(ip, change, cred, FORCE|CHOWN);
50241927Smckusick (void) chkiq(ip, 1, cred, FORCE|CHOWN);
50342440Smckusick (void) getinoquota(ip);
50441312Smckusick }
50542440Smckusick return (error);
50641927Smckusick good:
50742440Smckusick if (getinoquota(ip))
50842440Smckusick panic("chown: lost quota");
50942440Smckusick #endif /* QUOTA */
51041312Smckusick if (ouid != uid || ogid != gid)
51164600Sbostic ip->i_flag |= IN_CHANGE;
51241312Smckusick if (ouid != uid && cred->cr_uid != 0)
51341312Smckusick ip->i_mode &= ~ISUID;
51441312Smckusick if (ogid != gid && cred->cr_uid != 0)
51541312Smckusick ip->i_mode &= ~ISGID;
51612646Ssam return (0);
51737Sbill }
51837Sbill
51937737Smckusick /* ARGSUSED */
52051514Sbostic int
ufs_ioctl(ap)52153812Smckusick ufs_ioctl(ap)
52254455Smckusick struct vop_ioctl_args /* {
52354455Smckusick struct vnode *a_vp;
52454455Smckusick int a_command;
52554455Smckusick caddr_t a_data;
52654455Smckusick int a_fflag;
52754455Smckusick struct ucred *a_cred;
52854455Smckusick struct proc *a_p;
52954455Smckusick } */ *ap;
53011811Ssam {
53111811Ssam
53237737Smckusick return (ENOTTY);
53311811Ssam }
53411811Ssam
53537737Smckusick /* ARGSUSED */
53651514Sbostic int
ufs_select(ap)53753812Smckusick ufs_select(ap)
53854455Smckusick struct vop_select_args /* {
53954455Smckusick struct vnode *a_vp;
54054455Smckusick int a_which;
54154455Smckusick int a_fflags;
54254455Smckusick struct ucred *a_cred;
54354455Smckusick struct proc *a_p;
54454455Smckusick } */ *ap;
54537737Smckusick {
54637737Smckusick
54748039Smckusick /*
54848039Smckusick * We should really check to see if I/O is possible.
54948039Smckusick */
55048039Smckusick return (1);
55137737Smckusick }
55237737Smckusick
5539167Ssam /*
55437737Smckusick * Mmap a file
55537737Smckusick *
55637737Smckusick * NB Currently unsupported.
5579167Ssam */
55837737Smckusick /* ARGSUSED */
55951514Sbostic int
ufs_mmap(ap)56053812Smckusick ufs_mmap(ap)
56154455Smckusick struct vop_mmap_args /* {
56254455Smckusick struct vnode *a_vp;
56354455Smckusick int a_fflags;
56454455Smckusick struct ucred *a_cred;
56554455Smckusick struct proc *a_p;
56654455Smckusick } */ *ap;
56737Sbill {
56837Sbill
56937737Smckusick return (EINVAL);
57037Sbill }
5717535Sroot
5729167Ssam /*
57337737Smckusick * Seek on a file
57437737Smckusick *
57537737Smckusick * Nothing to do, so just return.
5769167Ssam */
57737737Smckusick /* ARGSUSED */
57851514Sbostic int
ufs_seek(ap)57953812Smckusick ufs_seek(ap)
58054455Smckusick struct vop_seek_args /* {
58154455Smckusick struct vnode *a_vp;
58254455Smckusick off_t a_oldoff;
58354455Smckusick off_t a_newoff;
58454455Smckusick struct ucred *a_cred;
58554455Smckusick } */ *ap;
5867701Ssam {
5877701Ssam
58837737Smckusick return (0);
58937737Smckusick }
59037737Smckusick
59151514Sbostic int
ufs_remove(ap)59253812Smckusick ufs_remove(ap)
59354455Smckusick struct vop_remove_args /* {
59454455Smckusick struct vnode *a_dvp;
59554455Smckusick struct vnode *a_vp;
59654455Smckusick struct componentname *a_cnp;
59754455Smckusick } */ *ap;
59837737Smckusick {
59956804Smckusick register struct inode *ip;
60056804Smckusick register struct vnode *vp = ap->a_vp;
60156804Smckusick register struct vnode *dvp = ap->a_dvp;
60237737Smckusick int error;
60337737Smckusick
60456804Smckusick ip = VTOI(vp);
60559316Smckusick if ((ip->i_flags & (IMMUTABLE | APPEND)) ||
60659316Smckusick (VTOI(dvp)->i_flags & APPEND)) {
60759316Smckusick error = EPERM;
60859316Smckusick goto out;
60959316Smckusick }
61059316Smckusick if ((error = ufs_dirremove(dvp, ap->a_cnp)) == 0) {
61137737Smckusick ip->i_nlink--;
61264600Sbostic ip->i_flag |= IN_CHANGE;
6137701Ssam }
61459316Smckusick out:
61556804Smckusick if (dvp == vp)
61656804Smckusick vrele(vp);
61737737Smckusick else
61856804Smckusick vput(vp);
61956804Smckusick vput(dvp);
62037737Smckusick return (error);
6217701Ssam }
6227701Ssam
6239167Ssam /*
62437737Smckusick * link vnode call
6259167Ssam */
62651514Sbostic int
ufs_link(ap)62753812Smckusick ufs_link(ap)
62854455Smckusick struct vop_link_args /* {
62954455Smckusick struct vnode *a_vp;
63054455Smckusick struct vnode *a_tdvp;
63154455Smckusick struct componentname *a_cnp;
63254455Smckusick } */ *ap;
6339167Ssam {
63453812Smckusick register struct vnode *vp = ap->a_vp;
63553812Smckusick register struct vnode *tdvp = ap->a_tdvp;
63653812Smckusick register struct componentname *cnp = ap->a_cnp;
63751514Sbostic register struct inode *ip;
63854762Storek struct timeval tv;
63937737Smckusick int error;
6409167Ssam
64153476Smckusick #ifdef DIAGNOSTIC
64253812Smckusick if ((cnp->cn_flags & HASBUF) == 0)
64349737Smckusick panic("ufs_link: no name");
64449737Smckusick #endif
64556804Smckusick if (vp->v_mount != tdvp->v_mount) {
64656804Smckusick VOP_ABORTOP(vp, cnp);
64756804Smckusick error = EXDEV;
64856804Smckusick goto out2;
64956804Smckusick }
65056804Smckusick if (vp != tdvp && (error = VOP_LOCK(tdvp))) {
65156804Smckusick VOP_ABORTOP(vp, cnp);
65256804Smckusick goto out2;
65356804Smckusick }
65453812Smckusick ip = VTOI(tdvp);
65553476Smckusick if ((nlink_t)ip->i_nlink >= LINK_MAX) {
65656804Smckusick VOP_ABORTOP(vp, cnp);
65756804Smckusick error = EMLINK;
65856804Smckusick goto out1;
65949737Smckusick }
66059316Smckusick if (ip->i_flags & (IMMUTABLE | APPEND)) {
66159316Smckusick VOP_ABORTOP(vp, cnp);
66259316Smckusick error = EPERM;
66359316Smckusick goto out1;
66459316Smckusick }
66537737Smckusick ip->i_nlink++;
66664600Sbostic ip->i_flag |= IN_CHANGE;
66754762Storek tv = time;
66854762Storek error = VOP_UPDATE(tdvp, &tv, &tv, 1);
66937737Smckusick if (!error)
67053812Smckusick error = ufs_direnter(ip, vp, cnp);
67137737Smckusick if (error) {
67237737Smckusick ip->i_nlink--;
67364600Sbostic ip->i_flag |= IN_CHANGE;
67437737Smckusick }
67556804Smckusick FREE(cnp->cn_pnbuf, M_NAMEI);
67656804Smckusick out1:
67756804Smckusick if (vp != tdvp)
67856804Smckusick VOP_UNLOCK(tdvp);
67956804Smckusick out2:
68056804Smckusick vput(vp);
68137737Smckusick return (error);
6829167Ssam }
6839167Ssam
68452232Sheideman
68552232Sheideman
6869167Ssam /*
68752232Sheideman * relookup - lookup a path name component
68852232Sheideman * Used by lookup to re-aquire things.
68952232Sheideman */
69052232Sheideman int
relookup(dvp,vpp,cnp)69152293Sheideman relookup(dvp, vpp, cnp)
69252232Sheideman struct vnode *dvp, **vpp;
69352232Sheideman struct componentname *cnp;
69452232Sheideman {
69552232Sheideman register struct vnode *dp = 0; /* the directory we are searching */
69652232Sheideman int docache; /* == 0 do not cache last component */
69752232Sheideman int wantparent; /* 1 => wantparent or lockparent flag */
69852232Sheideman int rdonly; /* lookup read-only flag bit */
69965719Sbostic int error = 0;
70065719Sbostic #ifdef NAMEI_DIAGNOSTIC
70165719Sbostic int newhash; /* DEBUG: check name hash */
70252336Smckusick char *cp; /* DEBUG: check name ptr/len */
70365719Sbostic #endif
70452232Sheideman
70552232Sheideman /*
70652232Sheideman * Setup: break out flag bits into variables.
70752232Sheideman */
70852232Sheideman wantparent = cnp->cn_flags & (LOCKPARENT|WANTPARENT);
70952232Sheideman docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE;
71052301Sheideman if (cnp->cn_nameiop == DELETE ||
71152301Sheideman (wantparent && cnp->cn_nameiop != CREATE))
71252232Sheideman docache = 0;
71352232Sheideman rdonly = cnp->cn_flags & RDONLY;
71452232Sheideman cnp->cn_flags &= ~ISSYMLINK;
71552232Sheideman dp = dvp;
71652232Sheideman VOP_LOCK(dp);
71752232Sheideman
71852232Sheideman /* dirloop: */
71952232Sheideman /*
72052232Sheideman * Search a new directory.
72152232Sheideman *
72252232Sheideman * The cn_hash value is for use by vfs_cache.
72352232Sheideman * The last component of the filename is left accessible via
72452232Sheideman * cnp->cn_nameptr for callers that need the name. Callers needing
72552232Sheideman * the name set the SAVENAME flag. When done, they assume
72652232Sheideman * responsibility for freeing the pathname buffer.
72752232Sheideman */
72852293Sheideman #ifdef NAMEI_DIAGNOSTIC
72952336Smckusick for (newhash = 0, cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++)
73052232Sheideman newhash += (unsigned char)*cp;
73152232Sheideman if (newhash != cnp->cn_hash)
73252232Sheideman panic("relookup: bad hash");
73352232Sheideman if (cnp->cn_namelen != cp - cnp->cn_nameptr)
73452232Sheideman panic ("relookup: bad len");
73552336Smckusick if (*cp != 0)
73652336Smckusick panic("relookup: not last component");
73752232Sheideman printf("{%s}: ", cnp->cn_nameptr);
73852232Sheideman #endif
73952232Sheideman
74052232Sheideman /*
74152232Sheideman * Check for degenerate name (e.g. / or "")
74252232Sheideman * which is a way of talking about a directory,
74352232Sheideman * e.g. like "/." or ".".
74452232Sheideman */
74552232Sheideman if (cnp->cn_nameptr[0] == '\0') {
74652232Sheideman if (cnp->cn_nameiop != LOOKUP || wantparent) {
74752232Sheideman error = EISDIR;
74852232Sheideman goto bad;
74952232Sheideman }
75052232Sheideman if (dp->v_type != VDIR) {
75152232Sheideman error = ENOTDIR;
75252232Sheideman goto bad;
75352232Sheideman }
75452232Sheideman if (!(cnp->cn_flags & LOCKLEAF))
75552232Sheideman VOP_UNLOCK(dp);
75652232Sheideman *vpp = dp;
75752232Sheideman if (cnp->cn_flags & SAVESTART)
75852232Sheideman panic("lookup: SAVESTART");
75952232Sheideman return (0);
76052232Sheideman }
76152232Sheideman
76252232Sheideman if (cnp->cn_flags & ISDOTDOT)
76352232Sheideman panic ("relookup: lookup on dot-dot");
76452232Sheideman
76552232Sheideman /*
76652232Sheideman * We now have a segment name to search for, and a directory to search.
76752232Sheideman */
76852232Sheideman if (error = VOP_LOOKUP(dp, vpp, cnp)) {
76952232Sheideman #ifdef DIAGNOSTIC
77052232Sheideman if (*vpp != NULL)
77152232Sheideman panic("leaf should be empty");
77252232Sheideman #endif
77352800Smckusick if (error != EJUSTRETURN)
77452232Sheideman goto bad;
77552232Sheideman /*
77652232Sheideman * If creating and at end of pathname, then can consider
77752232Sheideman * allowing file to be created.
77852232Sheideman */
77952232Sheideman if (rdonly || (dvp->v_mount->mnt_flag & MNT_RDONLY)) {
78052232Sheideman error = EROFS;
78152232Sheideman goto bad;
78252232Sheideman }
78352336Smckusick /* ASSERT(dvp == ndp->ni_startdir) */
78452336Smckusick if (cnp->cn_flags & SAVESTART)
78552336Smckusick VREF(dvp);
78652232Sheideman /*
78752232Sheideman * We return with ni_vp NULL to indicate that the entry
78852232Sheideman * doesn't currently exist, leaving a pointer to the
78952232Sheideman * (possibly locked) directory inode in ndp->ni_dvp.
79052232Sheideman */
79152232Sheideman return (0);
79252232Sheideman }
79352636Smckusick dp = *vpp;
79452232Sheideman
79552293Sheideman #ifdef DIAGNOSTIC
79652232Sheideman /*
79752232Sheideman * Check for symbolic link
79852232Sheideman */
79952636Smckusick if (dp->v_type == VLNK && (cnp->cn_flags & FOLLOW))
80052232Sheideman panic ("relookup: symlink found.\n");
80152232Sheideman #endif
80252232Sheideman
80352232Sheideman /*
80452232Sheideman * Check for read-only file systems.
80552232Sheideman */
80652232Sheideman if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) {
80752232Sheideman /*
80852232Sheideman * Disallow directory write attempts on read-only
80952232Sheideman * file systems.
81052232Sheideman */
81152232Sheideman if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) ||
81252232Sheideman (wantparent &&
81352232Sheideman (dvp->v_mount->mnt_flag & MNT_RDONLY))) {
81452232Sheideman error = EROFS;
81552232Sheideman goto bad2;
81652232Sheideman }
81752232Sheideman }
81852336Smckusick /* ASSERT(dvp == ndp->ni_startdir) */
81952336Smckusick if (cnp->cn_flags & SAVESTART)
82052232Sheideman VREF(dvp);
82152232Sheideman
82252232Sheideman if (!wantparent)
82352232Sheideman vrele(dvp);
82452232Sheideman if ((cnp->cn_flags & LOCKLEAF) == 0)
82552232Sheideman VOP_UNLOCK(dp);
82652232Sheideman return (0);
82752232Sheideman
82852232Sheideman bad2:
82952232Sheideman if ((cnp->cn_flags & LOCKPARENT) && (cnp->cn_flags & ISLASTCN))
83052232Sheideman VOP_UNLOCK(dvp);
83152232Sheideman vrele(dvp);
83252232Sheideman bad:
83352232Sheideman vput(dp);
83452232Sheideman *vpp = NULL;
83552232Sheideman return (error);
83652232Sheideman }
83752232Sheideman
83852232Sheideman
83952232Sheideman /*
8409167Ssam * Rename system call.
8419167Ssam * rename("foo", "bar");
8429167Ssam * is essentially
8439167Ssam * unlink("bar");
8449167Ssam * link("foo", "bar");
8459167Ssam * unlink("foo");
8469167Ssam * but ``atomically''. Can't do full commit without saving state in the
8479167Ssam * inode on disk which isn't feasible at this time. Best we can do is
8489167Ssam * always guarantee the target exists.
8499167Ssam *
8509167Ssam * Basic algorithm is:
8519167Ssam *
8529167Ssam * 1) Bump link count on source while we're linking it to the
85337737Smckusick * target. This also ensure the inode won't be deleted out
85416776Smckusick * from underneath us while we work (it may be truncated by
85516776Smckusick * a concurrent `trunc' or `open' for creation).
8569167Ssam * 2) Link source to destination. If destination already exists,
8579167Ssam * delete it first.
85816776Smckusick * 3) Unlink source reference to inode if still around. If a
85916776Smckusick * directory was moved and the parent of the destination
8609167Ssam * is different from the source, patch the ".." entry in the
8619167Ssam * directory.
8629167Ssam */
86351514Sbostic int
ufs_rename(ap)86453812Smckusick ufs_rename(ap)
86554455Smckusick struct vop_rename_args /* {
86654455Smckusick struct vnode *a_fdvp;
86754455Smckusick struct vnode *a_fvp;
86854455Smckusick struct componentname *a_fcnp;
86954455Smckusick struct vnode *a_tdvp;
87054455Smckusick struct vnode *a_tvp;
87154455Smckusick struct componentname *a_tcnp;
87254455Smckusick } */ *ap;
8737701Ssam {
87453812Smckusick struct vnode *tvp = ap->a_tvp;
87553812Smckusick register struct vnode *tdvp = ap->a_tdvp;
87653812Smckusick struct vnode *fvp = ap->a_fvp;
87753812Smckusick register struct vnode *fdvp = ap->a_fdvp;
87853812Smckusick register struct componentname *tcnp = ap->a_tcnp;
87953812Smckusick register struct componentname *fcnp = ap->a_fcnp;
8809167Ssam register struct inode *ip, *xp, *dp;
88116776Smckusick struct dirtemplate dirbuf;
88254762Storek struct timeval tv;
88316776Smckusick int doingdirectory = 0, oldparent = 0, newparent = 0;
88410051Ssam int error = 0;
88554608Smckusick u_char namlen;
8867701Ssam
88756804Smckusick #ifdef DIAGNOSTIC
88856804Smckusick if ((tcnp->cn_flags & HASBUF) == 0 ||
88956804Smckusick (fcnp->cn_flags & HASBUF) == 0)
89056804Smckusick panic("ufs_rename: no name");
89156804Smckusick #endif
89256804Smckusick /*
89356804Smckusick * Check for cross-device rename.
89456804Smckusick */
89553812Smckusick if ((fvp->v_mount != tdvp->v_mount) ||
89653812Smckusick (tvp && (fvp->v_mount != tvp->v_mount))) {
89756804Smckusick error = EXDEV;
89856804Smckusick abortit:
89953812Smckusick VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
90053812Smckusick if (tdvp == tvp)
90153812Smckusick vrele(tdvp);
90253807Spendry else
90353812Smckusick vput(tdvp);
90453812Smckusick if (tvp)
90553812Smckusick vput(tvp);
90653812Smckusick VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
90753812Smckusick vrele(fdvp);
90853812Smckusick vrele(fvp);
90956804Smckusick return (error);
91053807Spendry }
91153807Spendry
91249737Smckusick /*
91349737Smckusick * Check if just deleting a link name.
91449737Smckusick */
91559316Smckusick if (tvp && ((VTOI(tvp)->i_flags & (IMMUTABLE | APPEND)) ||
91659316Smckusick (VTOI(tdvp)->i_flags & APPEND))) {
91759316Smckusick error = EPERM;
91859316Smckusick goto abortit;
91959316Smckusick }
92053812Smckusick if (fvp == tvp) {
92156804Smckusick if (fvp->v_type == VDIR) {
92256804Smckusick error = EINVAL;
92356804Smckusick goto abortit;
92456804Smckusick }
92556804Smckusick VOP_ABORTOP(fdvp, fcnp);
92656804Smckusick vrele(fdvp);
92756804Smckusick vrele(fvp);
92853812Smckusick vput(tdvp);
92953812Smckusick vput(tvp);
93056804Smckusick tcnp->cn_flags &= ~MODMASK;
93156804Smckusick tcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
93256804Smckusick if ((tcnp->cn_flags & SAVESTART) == 0)
93356804Smckusick panic("ufs_rename: lost from startdir");
93456804Smckusick tcnp->cn_nameiop = DELETE;
93556804Smckusick (void) relookup(tdvp, &tvp, tcnp);
93656804Smckusick return (VOP_REMOVE(tdvp, tvp, tcnp));
93749737Smckusick }
93856804Smckusick if (error = VOP_LOCK(fvp))
93956804Smckusick goto abortit;
94056804Smckusick dp = VTOI(fdvp);
94156804Smckusick ip = VTOI(fvp);
94259316Smckusick if ((ip->i_flags & (IMMUTABLE | APPEND)) || (dp->i_flags & APPEND)) {
94359316Smckusick VOP_UNLOCK(fvp);
94459316Smckusick error = EPERM;
94559316Smckusick goto abortit;
94659316Smckusick }
94756804Smckusick if ((ip->i_mode & IFMT) == IFDIR) {
9489167Ssam /*
94911641Ssam * Avoid ".", "..", and aliases of "." for obvious reasons.
9509167Ssam */
95153812Smckusick if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
95253812Smckusick dp == ip || (fcnp->cn_flags&ISDOTDOT) ||
95364600Sbostic (ip->i_flag & IN_RENAME)) {
95456804Smckusick VOP_UNLOCK(fvp);
95556804Smckusick error = EINVAL;
95656804Smckusick goto abortit;
9579167Ssam }
95864600Sbostic ip->i_flag |= IN_RENAME;
9599167Ssam oldparent = dp->i_number;
9609167Ssam doingdirectory++;
9619167Ssam }
96253812Smckusick vrele(fdvp);
9639167Ssam
9649167Ssam /*
96556804Smckusick * When the target exists, both the directory
96656804Smckusick * and target vnodes are returned locked.
96756804Smckusick */
96856804Smckusick dp = VTOI(tdvp);
96956804Smckusick xp = NULL;
97056804Smckusick if (tvp)
97156804Smckusick xp = VTOI(tvp);
97256804Smckusick
97356804Smckusick /*
9749167Ssam * 1) Bump link count while we're moving stuff
9759167Ssam * around. If we crash somewhere before
9769167Ssam * completing our work, the link count
9779167Ssam * may be wrong, but correctable.
9789167Ssam */
9799167Ssam ip->i_nlink++;
98064600Sbostic ip->i_flag |= IN_CHANGE;
98154762Storek tv = time;
98256804Smckusick if (error = VOP_UPDATE(fvp, &tv, &tv, 1)) {
98356804Smckusick VOP_UNLOCK(fvp);
98456804Smckusick goto bad;
98556804Smckusick }
9869167Ssam
9879167Ssam /*
98811641Ssam * If ".." must be changed (ie the directory gets a new
98912816Smckusick * parent) then the source directory must not be in the
99012816Smckusick * directory heirarchy above the target, as this would
99112816Smckusick * orphan everything below the source directory. Also
99212816Smckusick * the user must have write permission in the source so
99312816Smckusick * as to be able to change "..". We must repeat the call
99412816Smckusick * to namei, as the parent directory is unlocked by the
99512816Smckusick * call to checkpath().
99611641Ssam */
99756804Smckusick error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
99856804Smckusick VOP_UNLOCK(fvp);
99916776Smckusick if (oldparent != dp->i_number)
100016776Smckusick newparent = dp->i_number;
100116776Smckusick if (doingdirectory && newparent) {
100256804Smckusick if (error) /* write access check above */
100312816Smckusick goto bad;
100449737Smckusick if (xp != NULL)
100556804Smckusick vput(tvp);
100653812Smckusick if (error = ufs_checkpath(ip, dp, tcnp->cn_cred))
100749737Smckusick goto out;
100853812Smckusick if ((tcnp->cn_flags & SAVESTART) == 0)
100949737Smckusick panic("ufs_rename: lost to startdir");
101053812Smckusick if (error = relookup(tdvp, &tvp, tcnp))
101149737Smckusick goto out;
101253812Smckusick dp = VTOI(tdvp);
101349737Smckusick xp = NULL;
101453812Smckusick if (tvp)
101553812Smckusick xp = VTOI(tvp);
101612816Smckusick }
101711641Ssam /*
10189167Ssam * 2) If target doesn't exist, link the target
10199167Ssam * to the source and unlink the source.
10209167Ssam * Otherwise, rewrite the target directory
10219167Ssam * entry to reference the source inode and
10229167Ssam * expunge the original entry's existence.
10239167Ssam */
10249167Ssam if (xp == NULL) {
102537737Smckusick if (dp->i_dev != ip->i_dev)
102637737Smckusick panic("rename: EXDEV");
10279167Ssam /*
102816776Smckusick * Account for ".." in new directory.
102916776Smckusick * When source and destination have the same
103016776Smckusick * parent we don't fool with the link count.
10319167Ssam */
103216776Smckusick if (doingdirectory && newparent) {
103353476Smckusick if ((nlink_t)dp->i_nlink >= LINK_MAX) {
103446251Smckusick error = EMLINK;
103546251Smckusick goto bad;
103646251Smckusick }
10379167Ssam dp->i_nlink++;
103864600Sbostic dp->i_flag |= IN_CHANGE;
103956804Smckusick if (error = VOP_UPDATE(tdvp, &tv, &tv, 1))
104046251Smckusick goto bad;
10419167Ssam }
104253812Smckusick if (error = ufs_direnter(ip, tdvp, tcnp)) {
104347219Smckusick if (doingdirectory && newparent) {
104447219Smckusick dp->i_nlink--;
104564600Sbostic dp->i_flag |= IN_CHANGE;
104656804Smckusick (void)VOP_UPDATE(tdvp, &tv, &tv, 1);
104747219Smckusick }
104847219Smckusick goto bad;
104947219Smckusick }
105056804Smckusick vput(tdvp);
10519167Ssam } else {
105237737Smckusick if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
105337737Smckusick panic("rename: EXDEV");
10549167Ssam /*
105510590Ssam * Short circuit rename(foo, foo).
105610590Ssam */
105710590Ssam if (xp->i_number == ip->i_number)
105837737Smckusick panic("rename: same file");
105910590Ssam /*
106024433Sbloom * If the parent directory is "sticky", then the user must
106124433Sbloom * own the parent directory, or the destination of the rename,
106224433Sbloom * otherwise the destination may not be changed (except by
106324433Sbloom * root). This implements append-only directories.
106424433Sbloom */
106564429Sbostic if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
106653812Smckusick tcnp->cn_cred->cr_uid != dp->i_uid &&
106753812Smckusick xp->i_uid != tcnp->cn_cred->cr_uid) {
106824433Sbloom error = EPERM;
106924433Sbloom goto bad;
107024433Sbloom }
107124433Sbloom /*
107249737Smckusick * Target must be empty if a directory and have no links
107349737Smckusick * to it. Also, ensure source and target are compatible
107449737Smckusick * (both directories, or both not directories).
10759167Ssam */
10769167Ssam if ((xp->i_mode&IFMT) == IFDIR) {
107753812Smckusick if (!ufs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
107837737Smckusick xp->i_nlink > 2) {
107910051Ssam error = ENOTEMPTY;
10809167Ssam goto bad;
10819167Ssam }
10829167Ssam if (!doingdirectory) {
108310051Ssam error = ENOTDIR;
10849167Ssam goto bad;
10859167Ssam }
108656804Smckusick cache_purge(tdvp);
10879167Ssam } else if (doingdirectory) {
108810051Ssam error = EISDIR;
10899167Ssam goto bad;
10909167Ssam }
109153812Smckusick if (error = ufs_dirrewrite(dp, ip, tcnp))
109237737Smckusick goto bad;
109345354Smckusick /*
109445354Smckusick * If the target directory is in the same
109545354Smckusick * directory as the source directory,
109645354Smckusick * decrement the link count on the parent
109745354Smckusick * of the target directory.
109845354Smckusick */
109945354Smckusick if (doingdirectory && !newparent) {
110045354Smckusick dp->i_nlink--;
110164600Sbostic dp->i_flag |= IN_CHANGE;
110245354Smckusick }
110356804Smckusick vput(tdvp);
11049167Ssam /*
110510051Ssam * Adjust the link count of the target to
110610051Ssam * reflect the dirrewrite above. If this is
110710051Ssam * a directory it is empty and there are
110810051Ssam * no links to it, so we can squash the inode and
110910051Ssam * any space associated with it. We disallowed
111010051Ssam * renaming over top of a directory with links to
111116776Smckusick * it above, as the remaining link would point to
111216776Smckusick * a directory without "." or ".." entries.
11139167Ssam */
111410051Ssam xp->i_nlink--;
11159167Ssam if (doingdirectory) {
111610051Ssam if (--xp->i_nlink != 0)
111710051Ssam panic("rename: linked directory");
111856804Smckusick error = VOP_TRUNCATE(tvp, (off_t)0, IO_SYNC,
111954455Smckusick tcnp->cn_cred, tcnp->cn_proc);
112010051Ssam }
112164600Sbostic xp->i_flag |= IN_CHANGE;
112256804Smckusick vput(tvp);
112310246Ssam xp = NULL;
11249167Ssam }
11259167Ssam
11269167Ssam /*
11279167Ssam * 3) Unlink the source.
11289167Ssam */
112953812Smckusick fcnp->cn_flags &= ~MODMASK;
113053812Smckusick fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
113153812Smckusick if ((fcnp->cn_flags & SAVESTART) == 0)
113249737Smckusick panic("ufs_rename: lost from startdir");
113353812Smckusick (void) relookup(fdvp, &fvp, fcnp);
113453812Smckusick if (fvp != NULL) {
113553812Smckusick xp = VTOI(fvp);
113653812Smckusick dp = VTOI(fdvp);
113737737Smckusick } else {
113846250Smckusick /*
113946250Smckusick * From name has disappeared.
114046250Smckusick */
114146250Smckusick if (doingdirectory)
114246250Smckusick panic("rename: lost dir entry");
114356804Smckusick vrele(ap->a_fvp);
114446250Smckusick return (0);
114537737Smckusick }
11469167Ssam /*
114737737Smckusick * Ensure that the directory entry still exists and has not
114816776Smckusick * changed while the new name has been entered. If the source is
114916776Smckusick * a file then the entry may have been unlinked or renamed. In
115016776Smckusick * either case there is no further work to be done. If the source
115116776Smckusick * is a directory then it cannot have been rmdir'ed; its link
115216776Smckusick * count of three would cause a rmdir to fail with ENOTEMPTY.
115337737Smckusick * The IRENAME flag ensures that it cannot be moved by another
115416776Smckusick * rename.
11559167Ssam */
115617758Smckusick if (xp != ip) {
115716776Smckusick if (doingdirectory)
115817758Smckusick panic("rename: lost dir entry");
115916776Smckusick } else {
11609167Ssam /*
116116776Smckusick * If the source is a directory with a
116216776Smckusick * new parent, the link count of the old
116316776Smckusick * parent directory must be decremented
116416776Smckusick * and ".." set to point to the new parent.
11659167Ssam */
116616776Smckusick if (doingdirectory && newparent) {
11679167Ssam dp->i_nlink--;
116864600Sbostic dp->i_flag |= IN_CHANGE;
116956804Smckusick error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
117037737Smckusick sizeof (struct dirtemplate), (off_t)0,
117139597Smckusick UIO_SYSSPACE, IO_NODELOCKED,
117253812Smckusick tcnp->cn_cred, (int *)0, (struct proc *)0);
117316776Smckusick if (error == 0) {
117454608Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN)
117554608Smckusick if (fvp->v_mount->mnt_maxsymlinklen <= 0)
117654608Smckusick namlen = dirbuf.dotdot_type;
117754608Smckusick else
117854608Smckusick namlen = dirbuf.dotdot_namlen;
117954608Smckusick # else
118054608Smckusick namlen = dirbuf.dotdot_namlen;
118154608Smckusick # endif
118254608Smckusick if (namlen != 2 ||
118316776Smckusick dirbuf.dotdot_name[0] != '.' ||
118416776Smckusick dirbuf.dotdot_name[1] != '.') {
118553062Smckusick ufs_dirbad(xp, (doff_t)12,
118651514Sbostic "rename: mangled dir");
118716776Smckusick } else {
118816776Smckusick dirbuf.dotdot_ino = newparent;
118956804Smckusick (void) vn_rdwr(UIO_WRITE, fvp,
119016776Smckusick (caddr_t)&dirbuf,
119116776Smckusick sizeof (struct dirtemplate),
119237740Smckusick (off_t)0, UIO_SYSSPACE,
119339597Smckusick IO_NODELOCKED|IO_SYNC,
119453812Smckusick tcnp->cn_cred, (int *)0,
119548039Smckusick (struct proc *)0);
119656804Smckusick cache_purge(fdvp);
119716776Smckusick }
119816776Smckusick }
11999167Ssam }
120053812Smckusick error = ufs_dirremove(fdvp, fcnp);
120137737Smckusick if (!error) {
120216776Smckusick xp->i_nlink--;
120364600Sbostic xp->i_flag |= IN_CHANGE;
12049167Ssam }
120564600Sbostic xp->i_flag &= ~IN_RENAME;
12069167Ssam }
12079167Ssam if (dp)
120856804Smckusick vput(fdvp);
120916776Smckusick if (xp)
121056804Smckusick vput(fvp);
121156804Smckusick vrele(ap->a_fvp);
121237737Smckusick return (error);
12139167Ssam
12149167Ssam bad:
12159167Ssam if (xp)
121637737Smckusick vput(ITOV(xp));
121737737Smckusick vput(ITOV(dp));
12189167Ssam out:
121956804Smckusick if (VOP_LOCK(fvp) == 0) {
122056804Smckusick ip->i_nlink--;
122164600Sbostic ip->i_flag |= IN_CHANGE;
122256804Smckusick vput(fvp);
122356804Smckusick } else
122456804Smckusick vrele(fvp);
122537737Smckusick return (error);
12267701Ssam }
12277701Ssam
12287535Sroot /*
122912756Ssam * A virgin directory (no blushing please).
123012756Ssam */
123151514Sbostic static struct dirtemplate mastertemplate = {
123254608Smckusick 0, 12, DT_DIR, 1, ".",
123354608Smckusick 0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
123454608Smckusick };
123554608Smckusick static struct odirtemplate omastertemplate = {
123612756Ssam 0, 12, 1, ".",
123712756Ssam 0, DIRBLKSIZ - 12, 2, ".."
123812756Ssam };
123912756Ssam
124012756Ssam /*
124112756Ssam * Mkdir system call
124212756Ssam */
124351514Sbostic int
ufs_mkdir(ap)124453812Smckusick ufs_mkdir(ap)
124554455Smckusick struct vop_mkdir_args /* {
124654455Smckusick struct vnode *a_dvp;
124754455Smckusick struct vnode **a_vpp;
124854455Smckusick struct componentname *a_cnp;
124954455Smckusick struct vattr *a_vap;
125054455Smckusick } */ *ap;
125112756Ssam {
125253812Smckusick register struct vnode *dvp = ap->a_dvp;
125353812Smckusick register struct vattr *vap = ap->a_vap;
125453812Smckusick register struct componentname *cnp = ap->a_cnp;
125512756Ssam register struct inode *ip, *dp;
125651551Smckusick struct vnode *tvp;
125754608Smckusick struct dirtemplate dirtemplate, *dtp;
125854762Storek struct timeval tv;
125954762Storek int error, dmode;
126012756Ssam
126153476Smckusick #ifdef DIAGNOSTIC
126253812Smckusick if ((cnp->cn_flags & HASBUF) == 0)
126349737Smckusick panic("ufs_mkdir: no name");
126449737Smckusick #endif
126553812Smckusick dp = VTOI(dvp);
126653476Smckusick if ((nlink_t)dp->i_nlink >= LINK_MAX) {
126759316Smckusick error = EMLINK;
126859316Smckusick goto out;
126946251Smckusick }
127059316Smckusick dmode = vap->va_mode & 0777;
127137737Smckusick dmode |= IFDIR;
127212756Ssam /*
127359316Smckusick * Must simulate part of ufs_makeinode here to acquire the inode,
127459316Smckusick * but not have it entered in the parent directory. The entry is
127559316Smckusick * made later after writing "." and ".." entries.
127612756Ssam */
127759316Smckusick if (error = VOP_VALLOC(dvp, dmode, cnp->cn_cred, &tvp))
127859316Smckusick goto out;
127951551Smckusick ip = VTOI(tvp);
128053812Smckusick ip->i_uid = cnp->cn_cred->cr_uid;
128141312Smckusick ip->i_gid = dp->i_gid;
128212756Ssam #ifdef QUOTA
128341312Smckusick if ((error = getinoquota(ip)) ||
128453812Smckusick (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
128553812Smckusick free(cnp->cn_pnbuf, M_NAMEI);
128651551Smckusick VOP_VFREE(tvp, ip->i_number, dmode);
128756804Smckusick vput(tvp);
128856804Smckusick vput(dvp);
128941312Smckusick return (error);
129041312Smckusick }
129112756Ssam #endif
129264600Sbostic ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
129337737Smckusick ip->i_mode = dmode;
129466594Sbostic tvp->v_type = VDIR; /* Rest init'd in getnewvnode(). */
129512756Ssam ip->i_nlink = 2;
129654762Storek tv = time;
129756804Smckusick error = VOP_UPDATE(tvp, &tv, &tv, 1);
129812756Ssam
129912756Ssam /*
130012756Ssam * Bump link count in parent directory
130112756Ssam * to reflect work done below. Should
130212756Ssam * be done before reference is created
130312756Ssam * so reparation is possible if we crash.
130412756Ssam */
130512756Ssam dp->i_nlink++;
130664600Sbostic dp->i_flag |= IN_CHANGE;
130756804Smckusick if (error = VOP_UPDATE(dvp, &tv, &tv, 1))
130847219Smckusick goto bad;
130912756Ssam
131051514Sbostic /* Initialize directory with "." and ".." from static template. */
131154608Smckusick if (dvp->v_mount->mnt_maxsymlinklen > 0)
131254608Smckusick dtp = &mastertemplate;
131354608Smckusick else
131454608Smckusick dtp = (struct dirtemplate *)&omastertemplate;
131554608Smckusick dirtemplate = *dtp;
131612756Ssam dirtemplate.dot_ino = ip->i_number;
131712756Ssam dirtemplate.dotdot_ino = dp->i_number;
131856804Smckusick error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
131948039Smckusick sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
132053812Smckusick IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (int *)0, (struct proc *)0);
132137737Smckusick if (error) {
132212756Ssam dp->i_nlink--;
132364600Sbostic dp->i_flag |= IN_CHANGE;
132412756Ssam goto bad;
132512756Ssam }
132653812Smckusick if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
132751514Sbostic panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */
132851514Sbostic else {
132918103Smckusick ip->i_size = DIRBLKSIZ;
133064600Sbostic ip->i_flag |= IN_CHANGE;
133143288Smckusick }
133251514Sbostic
133351514Sbostic /* Directory set up, now install it's entry in the parent directory. */
133453812Smckusick if (error = ufs_direnter(ip, dvp, cnp)) {
133547657Smckusick dp->i_nlink--;
133664600Sbostic dp->i_flag |= IN_CHANGE;
133712756Ssam }
133812756Ssam bad:
133912756Ssam /*
134051551Smckusick * No need to do an explicit VOP_TRUNCATE here, vrele will do this
134151551Smckusick * for us because we set the link count to 0.
134212756Ssam */
134337737Smckusick if (error) {
134412756Ssam ip->i_nlink = 0;
134564600Sbostic ip->i_flag |= IN_CHANGE;
134656804Smckusick vput(tvp);
134738144Smckusick } else
134856804Smckusick *ap->a_vpp = tvp;
134959316Smckusick out:
135053812Smckusick FREE(cnp->cn_pnbuf, M_NAMEI);
135156804Smckusick vput(dvp);
135237737Smckusick return (error);
135312756Ssam }
135412756Ssam
135512756Ssam /*
135612756Ssam * Rmdir system call.
135712756Ssam */
135851514Sbostic int
ufs_rmdir(ap)135953812Smckusick ufs_rmdir(ap)
136054455Smckusick struct vop_rmdir_args /* {
136154455Smckusick struct vnode *a_dvp;
136254455Smckusick struct vnode *a_vp;
136354455Smckusick struct componentname *a_cnp;
136454455Smckusick } */ *ap;
136512756Ssam {
136656804Smckusick register struct vnode *vp = ap->a_vp;
136753812Smckusick register struct vnode *dvp = ap->a_dvp;
136853812Smckusick register struct componentname *cnp = ap->a_cnp;
136912756Ssam register struct inode *ip, *dp;
137051514Sbostic int error;
137112756Ssam
137256804Smckusick ip = VTOI(vp);
137353812Smckusick dp = VTOI(dvp);
137412756Ssam /*
137512756Ssam * No rmdir "." please.
137612756Ssam */
137712756Ssam if (dp == ip) {
137853812Smckusick vrele(dvp);
137956804Smckusick vput(vp);
138037737Smckusick return (EINVAL);
138112756Ssam }
138212756Ssam /*
138312756Ssam * Verify the directory is empty (and valid).
138412756Ssam * (Rmdir ".." won't be valid since
138512756Ssam * ".." will contain a reference to
138612756Ssam * the current directory and thus be
138712756Ssam * non-empty.)
138812756Ssam */
138951514Sbostic error = 0;
139051514Sbostic if (ip->i_nlink != 2 ||
139153812Smckusick !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
139237737Smckusick error = ENOTEMPTY;
139312756Ssam goto out;
139412756Ssam }
139559316Smckusick if ((dp->i_flags & APPEND) || (ip->i_flags & (IMMUTABLE | APPEND))) {
139659316Smckusick error = EPERM;
139759316Smckusick goto out;
139859316Smckusick }
139912756Ssam /*
140012756Ssam * Delete reference to directory before purging
140112756Ssam * inode. If we crash in between, the directory
140212756Ssam * will be reattached to lost+found,
140312756Ssam */
140453812Smckusick if (error = ufs_dirremove(dvp, cnp))
140512756Ssam goto out;
140612756Ssam dp->i_nlink--;
140764600Sbostic dp->i_flag |= IN_CHANGE;
140853812Smckusick cache_purge(dvp);
140956804Smckusick vput(dvp);
141053812Smckusick dvp = NULL;
141112756Ssam /*
141212756Ssam * Truncate inode. The only stuff left
141312756Ssam * in the directory is "." and "..". The
141412756Ssam * "." reference is inconsequential since
141512756Ssam * we're quashing it. The ".." reference
141612756Ssam * has already been adjusted above. We've
141712756Ssam * removed the "." reference and the reference
141812756Ssam * in the parent directory, but there may be
141912756Ssam * other hard links so decrement by 2 and
142012756Ssam * worry about them later.
142112756Ssam */
142212756Ssam ip->i_nlink -= 2;
142356804Smckusick error = VOP_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred,
142454455Smckusick cnp->cn_proc);
142537737Smckusick cache_purge(ITOV(ip));
142612756Ssam out:
142753812Smckusick if (dvp)
142856804Smckusick vput(dvp);
142956804Smckusick vput(vp);
143037737Smckusick return (error);
143112756Ssam }
143212756Ssam
143337737Smckusick /*
143437737Smckusick * symlink -- make a symbolic link
143537737Smckusick */
143651514Sbostic int
ufs_symlink(ap)143753812Smckusick ufs_symlink(ap)
143854455Smckusick struct vop_symlink_args /* {
143954455Smckusick struct vnode *a_dvp;
144054455Smckusick struct vnode **a_vpp;
144154455Smckusick struct componentname *a_cnp;
144254455Smckusick struct vattr *a_vap;
144354455Smckusick char *a_target;
144454455Smckusick } */ *ap;
144512756Ssam {
144654303Smckusick register struct vnode *vp, **vpp = ap->a_vpp;
144754303Smckusick register struct inode *ip;
144854303Smckusick int len, error;
144912756Ssam
145053812Smckusick if (error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
145153812Smckusick vpp, ap->a_cnp))
145237737Smckusick return (error);
145354303Smckusick vp = *vpp;
145454303Smckusick len = strlen(ap->a_target);
145554303Smckusick if (len < vp->v_mount->mnt_maxsymlinklen) {
145654303Smckusick ip = VTOI(vp);
145754303Smckusick bcopy(ap->a_target, (char *)ip->i_shortlink, len);
145854303Smckusick ip->i_size = len;
145964600Sbostic ip->i_flag |= IN_CHANGE | IN_UPDATE;
146054303Smckusick } else
146154303Smckusick error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
146254303Smckusick UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
146354303Smckusick (struct proc *)0);
146454303Smckusick vput(vp);
146537737Smckusick return (error);
146637737Smckusick }
146737737Smckusick
146837737Smckusick /*
146952440Smckusick * Vnode op for reading directories.
147052440Smckusick *
147152440Smckusick * The routine below assumes that the on-disk format of a directory
147252440Smckusick * is the same as that defined by <sys/dirent.h>. If the on-disk
147352440Smckusick * format changes, then it will be necessary to do a conversion
147452440Smckusick * from the on-disk format that read returns to the format defined
147552440Smckusick * by <sys/dirent.h>.
147637737Smckusick */
147751514Sbostic int
ufs_readdir(ap)147853812Smckusick ufs_readdir(ap)
147954455Smckusick struct vop_readdir_args /* {
148054455Smckusick struct vnode *a_vp;
148154455Smckusick struct uio *a_uio;
148254455Smckusick struct ucred *a_cred;
1483*67371Smckusick int *a_eofflag;
1484*67371Smckusick u_long *a_cookies;
1485*67371Smckusick int ncookies;
148654455Smckusick } */ *ap;
148737737Smckusick {
148853812Smckusick register struct uio *uio = ap->a_uio;
1489*67371Smckusick int error;
1490*67371Smckusick size_t count, lost;
1491*67371Smckusick off_t off = uio->uio_offset;
149237737Smckusick
149353812Smckusick count = uio->uio_resid;
1494*67371Smckusick /* Make sure we don't return partial entries. */
1495*67371Smckusick count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
1496*67371Smckusick if (count <= 0)
1497*67371Smckusick return (EINVAL);
149853812Smckusick lost = uio->uio_resid - count;
149953812Smckusick uio->uio_resid = count;
150053812Smckusick uio->uio_iov->iov_len = count;
150154608Smckusick # if (BYTE_ORDER == LITTLE_ENDIAN)
150254608Smckusick if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) {
150354608Smckusick error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
150454608Smckusick } else {
150554608Smckusick struct dirent *dp, *edp;
150654608Smckusick struct uio auio;
150754608Smckusick struct iovec aiov;
150854608Smckusick caddr_t dirbuf;
150954608Smckusick int readcnt;
151054608Smckusick u_char tmp;
151154608Smckusick
151254608Smckusick auio = *uio;
151354608Smckusick auio.uio_iov = &aiov;
151454608Smckusick auio.uio_iovcnt = 1;
151554608Smckusick auio.uio_segflg = UIO_SYSSPACE;
151654608Smckusick aiov.iov_len = count;
151754608Smckusick MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
151854608Smckusick aiov.iov_base = dirbuf;
151956225Sralph error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
152054608Smckusick if (error == 0) {
152154608Smckusick readcnt = count - auio.uio_resid;
152254608Smckusick edp = (struct dirent *)&dirbuf[readcnt];
152354608Smckusick for (dp = (struct dirent *)dirbuf; dp < edp; ) {
152454608Smckusick tmp = dp->d_namlen;
152554608Smckusick dp->d_namlen = dp->d_type;
152654608Smckusick dp->d_type = tmp;
152754608Smckusick if (dp->d_reclen > 0) {
152854608Smckusick dp = (struct dirent *)
152954608Smckusick ((char *)dp + dp->d_reclen);
153054608Smckusick } else {
153154608Smckusick error = EIO;
153254608Smckusick break;
153354608Smckusick }
153454608Smckusick }
153554608Smckusick if (dp >= edp)
153654608Smckusick error = uiomove(dirbuf, readcnt, uio);
153754608Smckusick }
153854608Smckusick FREE(dirbuf, M_TEMP);
153954608Smckusick }
154054608Smckusick # else
154154608Smckusick error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
154254608Smckusick # endif
1543*67371Smckusick if (!error && ap->a_ncookies) {
1544*67371Smckusick register struct dirent *dp;
1545*67371Smckusick register u_long *cookies = ap->a_cookies;
1546*67371Smckusick register int ncookies = ap->a_ncookies;
1547*67371Smckusick
1548*67371Smckusick /*
1549*67371Smckusick * Only the NFS server uses cookies, and it loads the
1550*67371Smckusick * directory block into system space, so we can just look at
1551*67371Smckusick * it directly.
1552*67371Smckusick */
1553*67371Smckusick if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1554*67371Smckusick panic("ufs_readdir: lost in space");
1555*67371Smckusick dp = (struct dirent *)
1556*67371Smckusick (uio->uio_iov->iov_base - (uio->uio_offset - off));
1557*67371Smckusick while (ncookies-- && off < uio->uio_offset) {
1558*67371Smckusick if (dp->d_reclen == 0)
1559*67371Smckusick break;
1560*67371Smckusick off += dp->d_reclen;
1561*67371Smckusick *(cookies++) = off;
1562*67371Smckusick dp = (struct dirent *)((caddr_t)dp + dp->d_reclen);
1563*67371Smckusick }
1564*67371Smckusick lost += uio->uio_offset - off;
1565*67371Smckusick uio->uio_offset = off;
1566*67371Smckusick }
156753812Smckusick uio->uio_resid += lost;
1568*67371Smckusick *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
156937737Smckusick return (error);
157037737Smckusick }
157137737Smckusick
157237737Smckusick /*
157337737Smckusick * Return target name of a symbolic link
157437737Smckusick */
157551514Sbostic int
ufs_readlink(ap)157653812Smckusick ufs_readlink(ap)
157754455Smckusick struct vop_readlink_args /* {
157854455Smckusick struct vnode *a_vp;
157954455Smckusick struct uio *a_uio;
158054455Smckusick struct ucred *a_cred;
158154455Smckusick } */ *ap;
158237737Smckusick {
158354303Smckusick register struct vnode *vp = ap->a_vp;
158454303Smckusick register struct inode *ip = VTOI(vp);
158555309Smckusick int isize;
158637737Smckusick
158755309Smckusick isize = ip->i_size;
158855309Smckusick if (isize < vp->v_mount->mnt_maxsymlinklen) {
158955309Smckusick uiomove((char *)ip->i_shortlink, isize, ap->a_uio);
159054303Smckusick return (0);
159154303Smckusick }
159254303Smckusick return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
159337737Smckusick }
159437737Smckusick
159537737Smckusick /*
159637737Smckusick * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
159749737Smckusick * done. If a buffer has been saved in anticipation of a CREATE, delete it.
159837737Smckusick */
159942466Smckusick /* ARGSUSED */
160051514Sbostic int
ufs_abortop(ap)160153812Smckusick ufs_abortop(ap)
160254455Smckusick struct vop_abortop_args /* {
160354455Smckusick struct vnode *a_dvp;
160454455Smckusick struct componentname *a_cnp;
160554455Smckusick } */ *ap;
160637737Smckusick {
160753590Sheideman if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
160853590Sheideman FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
160942466Smckusick return (0);
161012756Ssam }
161112756Ssam
161239909Smckusick /*
161356804Smckusick * Lock an inode. If its already locked, set the WANT bit and sleep.
161439909Smckusick */
161551514Sbostic int
ufs_lock(ap)161653812Smckusick ufs_lock(ap)
161754455Smckusick struct vop_lock_args /* {
161854455Smckusick struct vnode *a_vp;
161954455Smckusick } */ *ap;
162037737Smckusick {
162156804Smckusick register struct vnode *vp = ap->a_vp;
162256804Smckusick register struct inode *ip;
162356804Smckusick struct proc *p = curproc; /* XXX */
162437737Smckusick
162556804Smckusick start:
162656804Smckusick while (vp->v_flag & VXLOCK) {
162756804Smckusick vp->v_flag |= VXWANT;
162856804Smckusick sleep((caddr_t)vp, PINOD);
162956804Smckusick }
163056804Smckusick if (vp->v_tag == VT_NON)
163156804Smckusick return (ENOENT);
163256804Smckusick ip = VTOI(vp);
163364600Sbostic if (ip->i_flag & IN_LOCKED) {
163464600Sbostic ip->i_flag |= IN_WANTED;
163556804Smckusick #ifdef DIAGNOSTIC
163656804Smckusick if (p) {
163756804Smckusick if (p->p_pid == ip->i_lockholder)
163856804Smckusick panic("locking against myself");
163956804Smckusick ip->i_lockwaiter = p->p_pid;
164057053Smckusick } else
164157053Smckusick ip->i_lockwaiter = -1;
164256804Smckusick #endif
164356804Smckusick (void) sleep((caddr_t)ip, PINOD);
164456804Smckusick goto start;
164556804Smckusick }
164656804Smckusick #ifdef DIAGNOSTIC
164756804Smckusick ip->i_lockwaiter = 0;
164857053Smckusick if (ip->i_lockholder != 0)
164957053Smckusick panic("lockholder (%d) != 0", ip->i_lockholder);
165057053Smckusick if (p && p->p_pid == 0)
165157053Smckusick printf("locking by process 0\n");
165256804Smckusick if (p)
165356804Smckusick ip->i_lockholder = p->p_pid;
165457053Smckusick else
165557053Smckusick ip->i_lockholder = -1;
165656804Smckusick #endif
165764600Sbostic ip->i_flag |= IN_LOCKED;
165837737Smckusick return (0);
165937737Smckusick }
166037737Smckusick
166139909Smckusick /*
166256804Smckusick * Unlock an inode. If WANT bit is on, wakeup.
166339909Smckusick */
166457053Smckusick int lockcount = 90;
166551514Sbostic int
ufs_unlock(ap)166653812Smckusick ufs_unlock(ap)
166754455Smckusick struct vop_unlock_args /* {
166854455Smckusick struct vnode *a_vp;
166954455Smckusick } */ *ap;
167037737Smckusick {
167153590Sheideman register struct inode *ip = VTOI(ap->a_vp);
167257053Smckusick struct proc *p = curproc; /* XXX */
167337737Smckusick
167457053Smckusick #ifdef DIAGNOSTIC
167564600Sbostic if ((ip->i_flag & IN_LOCKED) == 0) {
167656804Smckusick vprint("ufs_unlock: unlocked inode", ap->a_vp);
167737737Smckusick panic("ufs_unlock NOT LOCKED");
167856804Smckusick }
167957053Smckusick if (p && p->p_pid != ip->i_lockholder && p->p_pid > -1 &&
168057053Smckusick ip->i_lockholder > -1 && lockcount++ < 100)
168157053Smckusick panic("unlocker (%d) != lock holder (%d)",
168257053Smckusick p->p_pid, ip->i_lockholder);
168356804Smckusick ip->i_lockholder = 0;
168456804Smckusick #endif
168564600Sbostic ip->i_flag &= ~IN_LOCKED;
168664600Sbostic if (ip->i_flag & IN_WANTED) {
168764600Sbostic ip->i_flag &= ~IN_WANTED;
168856804Smckusick wakeup((caddr_t)ip);
168956804Smckusick }
169037737Smckusick return (0);
169137737Smckusick }
169237737Smckusick
169312756Ssam /*
169439909Smckusick * Check for a locked inode.
169539909Smckusick */
169651514Sbostic int
ufs_islocked(ap)169753812Smckusick ufs_islocked(ap)
169854455Smckusick struct vop_islocked_args /* {
169954455Smckusick struct vnode *a_vp;
170054455Smckusick } */ *ap;
170139909Smckusick {
170239909Smckusick
170364600Sbostic if (VTOI(ap->a_vp)->i_flag & IN_LOCKED)
170439909Smckusick return (1);
170539909Smckusick return (0);
170639909Smckusick }
170739909Smckusick
170839909Smckusick /*
170941538Smckusick * Calculate the logical to physical mapping if not done already,
171041538Smckusick * then call the device strategy routine.
171137737Smckusick */
171251514Sbostic int
ufs_strategy(ap)171353812Smckusick ufs_strategy(ap)
171454455Smckusick struct vop_strategy_args /* {
171554455Smckusick struct buf *a_bp;
171654455Smckusick } */ *ap;
171737737Smckusick {
171853812Smckusick register struct buf *bp = ap->a_bp;
171953812Smckusick register struct vnode *vp = bp->b_vp;
172051514Sbostic register struct inode *ip;
172139674Smckusick int error;
172239674Smckusick
172353812Smckusick ip = VTOI(vp);
172453812Smckusick if (vp->v_type == VBLK || vp->v_type == VCHR)
172539674Smckusick panic("ufs_strategy: spec");
172659316Smckusick if (bp->b_blkno == bp->b_lblkno) {
172759316Smckusick if (error =
172859316Smckusick VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL)) {
172953812Smckusick bp->b_error = error;
173053812Smckusick bp->b_flags |= B_ERROR;
173153812Smckusick biodone(bp);
173239674Smckusick return (error);
173352658Smckusick }
173453812Smckusick if ((long)bp->b_blkno == -1)
173559316Smckusick clrbuf(bp);
173639674Smckusick }
173753812Smckusick if ((long)bp->b_blkno == -1) {
173853812Smckusick biodone(bp);
173939674Smckusick return (0);
174039896Smckusick }
174139674Smckusick vp = ip->i_devvp;
174253812Smckusick bp->b_dev = vp->v_rdev;
174353570Sheideman VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
174437737Smckusick return (0);
174537737Smckusick }
174637737Smckusick
174737737Smckusick /*
174839674Smckusick * Print out the contents of an inode.
174939674Smckusick */
175051514Sbostic int
ufs_print(ap)175153812Smckusick ufs_print(ap)
175254455Smckusick struct vop_print_args /* {
175354455Smckusick struct vnode *a_vp;
175454455Smckusick } */ *ap;
175539674Smckusick {
175653812Smckusick register struct vnode *vp = ap->a_vp;
175753812Smckusick register struct inode *ip = VTOI(vp);
175839674Smckusick
175940293Smckusick printf("tag VT_UFS, ino %d, on dev %d, %d", ip->i_number,
176040293Smckusick major(ip->i_dev), minor(ip->i_dev));
176140293Smckusick #ifdef FIFO
176253812Smckusick if (vp->v_type == VFIFO)
176353812Smckusick fifo_printinfo(vp);
176440293Smckusick #endif /* FIFO */
176564600Sbostic printf("%s\n", (ip->i_flag & IN_LOCKED) ? " (LOCKED)" : "");
176651988Smckusick if (ip->i_lockholder == 0)
176751514Sbostic return (0);
176851988Smckusick printf("\towner pid %d", ip->i_lockholder);
176951988Smckusick if (ip->i_lockwaiter)
177051988Smckusick printf(" waiting pid %d", ip->i_lockwaiter);
177139900Smckusick printf("\n");
177251514Sbostic return (0);
177339674Smckusick }
177439674Smckusick
177539674Smckusick /*
177639628Smckusick * Read wrapper for special devices.
177739628Smckusick */
177851514Sbostic int
ufsspec_read(ap)177953812Smckusick ufsspec_read(ap)
178054455Smckusick struct vop_read_args /* {
178154455Smckusick struct vnode *a_vp;
178254455Smckusick struct uio *a_uio;
178354455Smckusick int a_ioflag;
178454455Smckusick struct ucred *a_cred;
178554455Smckusick } */ *ap;
178639628Smckusick {
178739628Smckusick
178839628Smckusick /*
178939628Smckusick * Set access flag.
179039628Smckusick */
179164600Sbostic VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
179253570Sheideman return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
179339628Smckusick }
179439628Smckusick
179539628Smckusick /*
179639628Smckusick * Write wrapper for special devices.
179739628Smckusick */
179851514Sbostic int
ufsspec_write(ap)179953812Smckusick ufsspec_write(ap)
180054455Smckusick struct vop_write_args /* {
180154455Smckusick struct vnode *a_vp;
180254455Smckusick struct uio *a_uio;
180354455Smckusick int a_ioflag;
180454455Smckusick struct ucred *a_cred;
180554455Smckusick } */ *ap;
180639628Smckusick {
180739628Smckusick
180839628Smckusick /*
180939628Smckusick * Set update and change flags.
181039628Smckusick */
181164600Sbostic VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
181253570Sheideman return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
181339628Smckusick }
181439628Smckusick
181539628Smckusick /*
181639628Smckusick * Close wrapper for special devices.
181739628Smckusick *
181839628Smckusick * Update the times on the inode then do device close.
181939628Smckusick */
182051514Sbostic int
ufsspec_close(ap)182153812Smckusick ufsspec_close(ap)
182254455Smckusick struct vop_close_args /* {
182354455Smckusick struct vnode *a_vp;
182454455Smckusick int a_fflag;
182554455Smckusick struct ucred *a_cred;
182654455Smckusick struct proc *a_p;
182754455Smckusick } */ *ap;
182839628Smckusick {
182953590Sheideman register struct inode *ip = VTOI(ap->a_vp);
183039628Smckusick
183164600Sbostic if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED))
183239628Smckusick ITIMES(ip, &time, &time);
183353570Sheideman return (VOCALL (spec_vnodeop_p, VOFFSET(vop_close), ap));
183439628Smckusick }
183539628Smckusick
183640290Smckusick #ifdef FIFO
183739628Smckusick /*
183840290Smckusick * Read wrapper for fifo's
183940290Smckusick */
184051514Sbostic int
ufsfifo_read(ap)184153812Smckusick ufsfifo_read(ap)
184254455Smckusick struct vop_read_args /* {
184354455Smckusick struct vnode *a_vp;
184454455Smckusick struct uio *a_uio;
184554455Smckusick int a_ioflag;
184654455Smckusick struct ucred *a_cred;
184754455Smckusick } */ *ap;
184840290Smckusick {
184953570Sheideman extern int (**fifo_vnodeop_p)();
185040290Smckusick
185140290Smckusick /*
185240290Smckusick * Set access flag.
185340290Smckusick */
185464600Sbostic VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
185553570Sheideman return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
185640290Smckusick }
185740290Smckusick
185840290Smckusick /*
185940290Smckusick * Write wrapper for fifo's.
186040290Smckusick */
186151514Sbostic int
ufsfifo_write(ap)186253812Smckusick ufsfifo_write(ap)
186354455Smckusick struct vop_write_args /* {
186454455Smckusick struct vnode *a_vp;
186554455Smckusick struct uio *a_uio;
186654455Smckusick int a_ioflag;
186754455Smckusick struct ucred *a_cred;
186854455Smckusick } */ *ap;
186940290Smckusick {
187053570Sheideman extern int (**fifo_vnodeop_p)();
187140290Smckusick
187240290Smckusick /*
187340290Smckusick * Set update and change flags.
187440290Smckusick */
187564600Sbostic VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
187653570Sheideman return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
187740290Smckusick }
187840290Smckusick
187940290Smckusick /*
188040290Smckusick * Close wrapper for fifo's.
188140290Smckusick *
188240290Smckusick * Update the times on the inode then do device close.
188340290Smckusick */
188453812Smckusick ufsfifo_close(ap)
188554455Smckusick struct vop_close_args /* {
188654455Smckusick struct vnode *a_vp;
188754455Smckusick int a_fflag;
188854455Smckusick struct ucred *a_cred;
188954455Smckusick struct proc *a_p;
189054455Smckusick } */ *ap;
189140290Smckusick {
189253570Sheideman extern int (**fifo_vnodeop_p)();
189353590Sheideman register struct inode *ip = VTOI(ap->a_vp);
189440290Smckusick
189564600Sbostic if (ap->a_vp->v_usecount > 1 && !(ip->i_flag & IN_LOCKED))
189640290Smckusick ITIMES(ip, &time, &time);
189753570Sheideman return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_close), ap));
189840290Smckusick }
189940290Smckusick #endif /* FIFO */
190040290Smckusick
190140290Smckusick /*
190260394Smckusick * Return POSIX pathconf information applicable to ufs filesystems.
190360394Smckusick */
190460394Smckusick ufs_pathconf(ap)
190560394Smckusick struct vop_pathconf_args /* {
190660394Smckusick struct vnode *a_vp;
190760394Smckusick int a_name;
190860394Smckusick int *a_retval;
190960394Smckusick } */ *ap;
191060394Smckusick {
191160394Smckusick
191260394Smckusick switch (ap->a_name) {
191360394Smckusick case _PC_LINK_MAX:
191460394Smckusick *ap->a_retval = LINK_MAX;
191560394Smckusick return (0);
191660394Smckusick case _PC_NAME_MAX:
191760394Smckusick *ap->a_retval = NAME_MAX;
191860394Smckusick return (0);
191960394Smckusick case _PC_PATH_MAX:
192060394Smckusick *ap->a_retval = PATH_MAX;
192160394Smckusick return (0);
192260394Smckusick case _PC_PIPE_BUF:
192360394Smckusick *ap->a_retval = PIPE_BUF;
192460394Smckusick return (0);
192560394Smckusick case _PC_CHOWN_RESTRICTED:
192660394Smckusick *ap->a_retval = 1;
192760394Smckusick return (0);
192860394Smckusick case _PC_NO_TRUNC:
192960394Smckusick *ap->a_retval = 1;
193060394Smckusick return (0);
193160394Smckusick default:
193260394Smckusick return (EINVAL);
193360394Smckusick }
193460394Smckusick /* NOTREACHED */
193560394Smckusick }
193660394Smckusick
193760394Smckusick /*
193846207Smckusick * Advisory record locking support
193946207Smckusick */
194051514Sbostic int
ufs_advlock(ap)194153812Smckusick ufs_advlock(ap)
194254455Smckusick struct vop_advlock_args /* {
194354455Smckusick struct vnode *a_vp;
194454455Smckusick caddr_t a_id;
194554455Smckusick int a_op;
194654455Smckusick struct flock *a_fl;
194754455Smckusick int a_flags;
194854455Smckusick } */ *ap;
194946207Smckusick {
195053590Sheideman register struct inode *ip = VTOI(ap->a_vp);
195153812Smckusick register struct flock *fl = ap->a_fl;
195246207Smckusick register struct lockf *lock;
195346207Smckusick off_t start, end;
195446207Smckusick int error;
195546207Smckusick
195646207Smckusick /*
195746207Smckusick * Avoid the common case of unlocking when inode has no locks.
195846207Smckusick */
195946207Smckusick if (ip->i_lockf == (struct lockf *)0) {
196053590Sheideman if (ap->a_op != F_SETLK) {
196153812Smckusick fl->l_type = F_UNLCK;
196246207Smckusick return (0);
196346207Smckusick }
196446207Smckusick }
196546207Smckusick /*
196646207Smckusick * Convert the flock structure into a start and end.
196746207Smckusick */
196853812Smckusick switch (fl->l_whence) {
196946207Smckusick
197046207Smckusick case SEEK_SET:
197146207Smckusick case SEEK_CUR:
197246207Smckusick /*
197346207Smckusick * Caller is responsible for adding any necessary offset
197446207Smckusick * when SEEK_CUR is used.
197546207Smckusick */
197653812Smckusick start = fl->l_start;
197746207Smckusick break;
197846207Smckusick
197946207Smckusick case SEEK_END:
198053812Smckusick start = ip->i_size + fl->l_start;
198146207Smckusick break;
198246207Smckusick
198346207Smckusick default:
198446207Smckusick return (EINVAL);
198546207Smckusick }
198646207Smckusick if (start < 0)
198746207Smckusick return (EINVAL);
198853812Smckusick if (fl->l_len == 0)
198946207Smckusick end = -1;
199046207Smckusick else
199153812Smckusick end = start + fl->l_len - 1;
199246207Smckusick /*
199346207Smckusick * Create the lockf structure
199446207Smckusick */
199546207Smckusick MALLOC(lock, struct lockf *, sizeof *lock, M_LOCKF, M_WAITOK);
199646207Smckusick lock->lf_start = start;
199746207Smckusick lock->lf_end = end;
199853590Sheideman lock->lf_id = ap->a_id;
199946207Smckusick lock->lf_inode = ip;
200053812Smckusick lock->lf_type = fl->l_type;
200146207Smckusick lock->lf_next = (struct lockf *)0;
200246207Smckusick lock->lf_block = (struct lockf *)0;
200353590Sheideman lock->lf_flags = ap->a_flags;
200446207Smckusick /*
200546207Smckusick * Do the requested operation.
200646207Smckusick */
200753590Sheideman switch(ap->a_op) {
200846207Smckusick case F_SETLK:
200946679Smckusick return (lf_setlock(lock));
201046207Smckusick
201146207Smckusick case F_UNLCK:
201246679Smckusick error = lf_clearlock(lock);
201346679Smckusick FREE(lock, M_LOCKF);
201446679Smckusick return (error);
201546207Smckusick
201646207Smckusick case F_GETLK:
201753812Smckusick error = lf_getlock(lock, fl);
201846679Smckusick FREE(lock, M_LOCKF);
201946679Smckusick return (error);
202046207Smckusick
202146207Smckusick default:
202246207Smckusick free(lock, M_LOCKF);
202346207Smckusick return (EINVAL);
202446207Smckusick }
202546207Smckusick /* NOTREACHED */
202646207Smckusick }
202748039Smckusick
202848039Smckusick /*
202951514Sbostic * Initialize the vnode associated with a new inode, handle aliased
203051514Sbostic * vnodes.
203148039Smckusick */
203251514Sbostic int
ufs_vinit(mntp,specops,fifoops,vpp)203351551Smckusick ufs_vinit(mntp, specops, fifoops, vpp)
203451514Sbostic struct mount *mntp;
203553502Sheideman int (**specops)();
203653502Sheideman int (**fifoops)();
203751514Sbostic struct vnode **vpp;
203851514Sbostic {
203955412Smckusick struct inode *ip;
204051514Sbostic struct vnode *vp, *nvp;
204148039Smckusick
204251514Sbostic vp = *vpp;
204351514Sbostic ip = VTOI(vp);
204451514Sbostic switch(vp->v_type = IFTOVT(ip->i_mode)) {
204551514Sbostic case VCHR:
204651514Sbostic case VBLK:
204751551Smckusick vp->v_op = specops;
204851514Sbostic if (nvp = checkalias(vp, ip->i_rdev, mntp)) {
204951551Smckusick /*
205051988Smckusick * Discard unneeded vnode, but save its inode.
205151988Smckusick */
205255412Smckusick ufs_ihashrem(ip);
205356804Smckusick VOP_UNLOCK(vp);
205451988Smckusick nvp->v_data = vp->v_data;
205551988Smckusick vp->v_data = NULL;
205653527Sheideman vp->v_op = spec_vnodeop_p;
205751988Smckusick vrele(vp);
205851988Smckusick vgone(vp);
205951988Smckusick /*
206051551Smckusick * Reinitialize aliased inode.
206151551Smckusick */
206251514Sbostic vp = nvp;
206351988Smckusick ip->i_vnode = vp;
206451988Smckusick ufs_ihashins(ip);
206551514Sbostic }
206651514Sbostic break;
206751514Sbostic case VFIFO:
206848039Smckusick #ifdef FIFO
206951551Smckusick vp->v_op = fifoops;
207051514Sbostic break;
207151514Sbostic #else
207251514Sbostic return (EOPNOTSUPP);
207351514Sbostic #endif
207451514Sbostic }
207551514Sbostic if (ip->i_number == ROOTINO)
207651514Sbostic vp->v_flag |= VROOT;
207752022Smckusick /*
207852022Smckusick * Initialize modrev times
207952022Smckusick */
208052022Smckusick SETHIGH(ip->i_modrev, mono_time.tv_sec);
208152022Smckusick SETLOW(ip->i_modrev, mono_time.tv_usec * 4294);
208251514Sbostic *vpp = vp;
208351514Sbostic return (0);
208451514Sbostic }
208551514Sbostic
208651514Sbostic /*
208751514Sbostic * Allocate a new inode.
208851514Sbostic */
208951514Sbostic int
ufs_makeinode(mode,dvp,vpp,cnp)209052293Sheideman ufs_makeinode(mode, dvp, vpp, cnp)
209151514Sbostic int mode;
209252232Sheideman struct vnode *dvp;
209351551Smckusick struct vnode **vpp;
209452232Sheideman struct componentname *cnp;
209551514Sbostic {
209651514Sbostic register struct inode *ip, *pdir;
209754762Storek struct timeval tv;
209851551Smckusick struct vnode *tvp;
209951514Sbostic int error;
210051514Sbostic
210152232Sheideman pdir = VTOI(dvp);
210253476Smckusick #ifdef DIAGNOSTIC
210352232Sheideman if ((cnp->cn_flags & HASBUF) == 0)
210451514Sbostic panic("ufs_makeinode: no name");
210551514Sbostic #endif
210651551Smckusick *vpp = NULL;
210751514Sbostic if ((mode & IFMT) == 0)
210851514Sbostic mode |= IFREG;
210951514Sbostic
211052232Sheideman if (error = VOP_VALLOC(dvp, mode, cnp->cn_cred, &tvp)) {
211152232Sheideman free(cnp->cn_pnbuf, M_NAMEI);
211256804Smckusick vput(dvp);
211351514Sbostic return (error);
211451514Sbostic }
211551551Smckusick ip = VTOI(tvp);
211651514Sbostic ip->i_gid = pdir->i_gid;
211759316Smckusick if ((mode & IFMT) == IFLNK)
211859316Smckusick ip->i_uid = pdir->i_uid;
211959316Smckusick else
212059316Smckusick ip->i_uid = cnp->cn_cred->cr_uid;
212151514Sbostic #ifdef QUOTA
212251514Sbostic if ((error = getinoquota(ip)) ||
212352232Sheideman (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
212452232Sheideman free(cnp->cn_pnbuf, M_NAMEI);
212551551Smckusick VOP_VFREE(tvp, ip->i_number, mode);
212656804Smckusick vput(tvp);
212756804Smckusick vput(dvp);
212851514Sbostic return (error);
212951514Sbostic }
213051514Sbostic #endif
213164600Sbostic ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
213251514Sbostic ip->i_mode = mode;
213366594Sbostic tvp->v_type = IFTOVT(mode); /* Rest init'd in getnewvnode(). */
213451514Sbostic ip->i_nlink = 1;
213552232Sheideman if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
213652232Sheideman suser(cnp->cn_cred, NULL))
213751514Sbostic ip->i_mode &= ~ISGID;
213851514Sbostic
213951514Sbostic /*
214051514Sbostic * Make sure inode goes to disk before directory entry.
214151514Sbostic */
214254762Storek tv = time;
214354762Storek if (error = VOP_UPDATE(tvp, &tv, &tv, 1))
214451514Sbostic goto bad;
214552232Sheideman if (error = ufs_direnter(ip, dvp, cnp))
214651514Sbostic goto bad;
214752232Sheideman if ((cnp->cn_flags & SAVESTART) == 0)
214852232Sheideman FREE(cnp->cn_pnbuf, M_NAMEI);
214956804Smckusick vput(dvp);
215051551Smckusick *vpp = tvp;
215151514Sbostic return (0);
215251514Sbostic
215351514Sbostic bad:
215451514Sbostic /*
215551514Sbostic * Write error occurred trying to update the inode
215651514Sbostic * or the directory so must deallocate the inode.
215751514Sbostic */
215852232Sheideman free(cnp->cn_pnbuf, M_NAMEI);
215956804Smckusick vput(dvp);
216051514Sbostic ip->i_nlink = 0;
216164600Sbostic ip->i_flag |= IN_CHANGE;
216256804Smckusick vput(tvp);
216351514Sbostic return (error);
216451514Sbostic }
2165