ufs_vnops.c revision 43958
1184610Salfred/*
2184610Salfred * Copyright (c) 1982, 1986, 1989, 1993, 1995
3184610Salfred *	The Regents of the University of California.  All rights reserved.
4184610Salfred * (c) UNIX System Laboratories, Inc.
5184610Salfred * All or some portions of this file are derived from material licensed
6184610Salfred * to the University of California by American Telephone and Telegraph
7184610Salfred * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8184610Salfred * the permission of UNIX System Laboratories, Inc.
9184610Salfred *
10184610Salfred * Redistribution and use in source and binary forms, with or without
11184610Salfred * modification, are permitted provided that the following conditions
12184610Salfred * are met:
13184610Salfred * 1. Redistributions of source code must retain the above copyright
14184610Salfred *    notice, this list of conditions and the following disclaimer.
15184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
16184610Salfred *    notice, this list of conditions and the following disclaimer in the
17184610Salfred *    documentation and/or other materials provided with the distribution.
18184610Salfred * 3. All advertising materials mentioning features or use of this software
19184610Salfred *    must display the following acknowledgement:
20184610Salfred *	This product includes software developed by the University of
21184610Salfred *	California, Berkeley and its contributors.
22184610Salfred * 4. Neither the name of the University nor the names of its contributors
23184610Salfred *    may be used to endorse or promote products derived from this software
24184610Salfred *    without specific prior written permission.
25184610Salfred *
26184610Salfred * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29184610Salfred * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36184610Salfred * SUCH DAMAGE.
37189002Sed *
38184610Salfred *	@(#)ufs_vnops.c	8.27 (Berkeley) 5/27/95
39184610Salfred * $Id: ufs_vnops.c,v 1.106 1999/01/28 00:57:56 dillon Exp $
40184610Salfred */
41184610Salfred
42184610Salfred#include "opt_quota.h"
43184610Salfred#include "opt_suiddir.h"
44184610Salfred
45184610Salfred#include <sys/param.h>
46184610Salfred#include <sys/systm.h>
47194677Sthompsa#include <sys/namei.h>
48194677Sthompsa#include <sys/kernel.h>
49194677Sthompsa#include <sys/fcntl.h>
50194677Sthompsa#include <sys/stat.h>
51194677Sthompsa#include <sys/buf.h>
52194677Sthompsa#include <sys/proc.h>
53194677Sthompsa#include <sys/mount.h>
54194677Sthompsa#include <sys/unistd.h>
55194677Sthompsa#include <sys/vnode.h>
56194677Sthompsa#include <sys/malloc.h>
57194677Sthompsa#include <sys/dirent.h>
58194677Sthompsa#include <sys/lockf.h>
59194677Sthompsa#include <sys/poll.h>
60194677Sthompsa
61194677Sthompsa#include <vm/vm_zone.h>
62194677Sthompsa#include <vm/vm.h>
63194677Sthompsa#include <vm/vm_extern.h>
64194677Sthompsa
65194677Sthompsa#include <miscfs/specfs/specdev.h>
66194677Sthompsa#include <miscfs/fifofs/fifo.h>
67194677Sthompsa
68194677Sthompsa#include <ufs/ufs/quota.h>
69188746Sthompsa#include <ufs/ufs/inode.h>
70184610Salfred#include <ufs/ufs/dir.h>
71194228Sthompsa#include <ufs/ufs/ufsmount.h>
72188942Sthompsa#include <ufs/ufs/ufs_extern.h>
73188942Sthompsa
74184610Salfredstatic int ufs_abortop __P((struct vop_abortop_args *));
75188942Sthompsastatic int ufs_access __P((struct vop_access_args *));
76184610Salfredstatic int ufs_advlock __P((struct vop_advlock_args *));
77184610Salfredstatic int ufs_chmod __P((struct vnode *, int, struct ucred *, struct proc *));
78184610Salfredstatic int ufs_chown __P((struct vnode *, uid_t, gid_t, struct ucred *, struct proc *));
79184610Salfredstatic int ufs_close __P((struct vop_close_args *));
80184610Salfredstatic int ufs_create __P((struct vop_create_args *));
81184610Salfredstatic int ufs_getattr __P((struct vop_getattr_args *));
82184610Salfredstatic int ufs_link __P((struct vop_link_args *));
83184610Salfredstatic int ufs_makeinode __P((int mode, struct vnode *, struct vnode **, struct componentname *));
84184610Salfredstatic int ufs_missingop __P((struct vop_generic_args *ap));
85184610Salfredstatic int ufs_mkdir __P((struct vop_mkdir_args *));
86184610Salfredstatic int ufs_mknod __P((struct vop_mknod_args *));
87184610Salfredstatic int ufs_mmap __P((struct vop_mmap_args *));
88184610Salfredstatic int ufs_open __P((struct vop_open_args *));
89184610Salfredstatic int ufs_pathconf __P((struct vop_pathconf_args *));
90184610Salfredstatic int ufs_print __P((struct vop_print_args *));
91192556Sthompsastatic int ufs_readdir __P((struct vop_readdir_args *));
92184610Salfredstatic int ufs_readlink __P((struct vop_readlink_args *));
93187259Sthompsastatic int ufs_remove __P((struct vop_remove_args *));
94187259Sthompsastatic int ufs_rename __P((struct vop_rename_args *));
95187259Sthompsastatic int ufs_rmdir __P((struct vop_rmdir_args *));
96187259Sthompsastatic int ufs_setattr __P((struct vop_setattr_args *));
97188413Sthompsastatic int ufs_strategy __P((struct vop_strategy_args *));
98187259Sthompsastatic int ufs_symlink __P((struct vop_symlink_args *));
99184610Salfredstatic int ufs_whiteout __P((struct vop_whiteout_args *));
100184610Salfredstatic int ufsfifo_close __P((struct vop_close_args *));
101192984Sthompsastatic int ufsfifo_read __P((struct vop_read_args *));
102192984Sthompsastatic int ufsfifo_write __P((struct vop_write_args *));
103184610Salfredstatic int ufsspec_close __P((struct vop_close_args *));
104192984Sthompsastatic int ufsspec_read __P((struct vop_read_args *));
105192984Sthompsastatic int ufsspec_write __P((struct vop_write_args *));
106189265Sthompsa
107184610Salfredunion _qcvt {
108184610Salfred	int64_t qcvt;
109184610Salfred	int32_t val[2];
110184610Salfred};
111184610Salfred#define SETHIGH(q, h) { \
112184610Salfred	union _qcvt tmp; \
113184610Salfred	tmp.qcvt = (q); \
114184610Salfred	tmp.val[_QUAD_HIGHWORD] = (h); \
115184610Salfred	(q) = tmp.qcvt; \
116188413Sthompsa}
117197573Sthompsa#define SETLOW(q, l) { \
118184610Salfred	union _qcvt tmp; \
119184610Salfred	tmp.qcvt = (q); \
120184610Salfred	tmp.val[_QUAD_LOWWORD] = (l); \
121184610Salfred	(q) = tmp.qcvt; \
122184610Salfred}
123184610Salfred
124184610Salfred/*
125239299Shselasky * A virgin directory (no blushing please).
126184610Salfred */
127193045Sthompsastatic struct dirtemplate mastertemplate = {
128197573Sthompsa	0, 12, DT_DIR, 1, ".",
129197573Sthompsa	0, DIRBLKSIZ - 12, DT_DIR, 2, ".."
130197573Sthompsa};
131193045Sthompsastatic struct odirtemplate omastertemplate = {
132184610Salfred	0, 12, 1, ".",
133188413Sthompsa	0, DIRBLKSIZ - 12, 2, ".."
134188413Sthompsa};
135239180Shselasky
136192984Sthompsavoid
137185948Sthompsaufs_itimes(vp)
138192984Sthompsa	struct vnode *vp;
139192984Sthompsa{
140192984Sthompsa	struct inode *ip;
141185948Sthompsa	time_t tv_sec;
142192984Sthompsa
143192984Sthompsa	ip = VTOI(vp);
144192984Sthompsa	if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0)
145192984Sthompsa		return;
146192984Sthompsa	if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
147192984Sthompsa		tv_sec = time_second;
148197570Sthompsa		if ((vp->v_type == VBLK || vp->v_type == VCHR) &&
149184610Salfred		    !DOINGSOFTDEP(vp))
150192984Sthompsa			ip->i_flag |= IN_LAZYMOD;
151184610Salfred		else
152187259Sthompsa			ip->i_flag |= IN_MODIFIED;
153184610Salfred		if (ip->i_flag & IN_ACCESS)
154184610Salfred			ip->i_atime = tv_sec;
155184610Salfred		if (ip->i_flag & IN_UPDATE) {
156190734Sthompsa			ip->i_mtime = tv_sec;
157190734Sthompsa			ip->i_modrev++;
158190734Sthompsa		}
159184610Salfred		if (ip->i_flag & IN_CHANGE)
160184610Salfred			ip->i_ctime = tv_sec;
161187259Sthompsa	}
162184610Salfred	ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE);
163184610Salfred}
164184610Salfred
165190734Sthompsa/*
166190734Sthompsa * Create a regular file
167190734Sthompsa */
168184610Salfredint
169184610Salfredufs_create(ap)
170184610Salfred	struct vop_create_args /* {
171187259Sthompsa		struct vnode *a_dvp;
172184610Salfred		struct vnode **a_vpp;
173184610Salfred		struct componentname *a_cnp;
174184610Salfred		struct vattr *a_vap;
175190734Sthompsa	} */ *ap;
176190734Sthompsa{
177190734Sthompsa	int error;
178184610Salfred
179184610Salfred	error =
180184610Salfred	    ufs_makeinode(MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode),
181184610Salfred	    ap->a_dvp, ap->a_vpp, ap->a_cnp);
182192984Sthompsa	if (error)
183194228Sthompsa		return (error);
184194228Sthompsa	VN_POLLEVENT(ap->a_dvp, POLLWRITE);
185194228Sthompsa	return (0);
186194228Sthompsa}
187194228Sthompsa
188194228Sthompsa/*
189194228Sthompsa * Mknod vnode call
190194228Sthompsa */
191194228Sthompsa/* ARGSUSED */
192194228Sthompsaint
193197570Sthompsaufs_mknod(ap)
194239180Shselasky	struct vop_mknod_args /* {
195184610Salfred		struct vnode *a_dvp;
196184610Salfred		struct vnode **a_vpp;
197223486Shselasky		struct componentname *a_cnp;
198184610Salfred		struct vattr *a_vap;
199184610Salfred	} */ *ap;
200184610Salfred{
201184610Salfred	struct vattr *vap = ap->a_vap;
202184610Salfred	struct vnode **vpp = ap->a_vpp;
203184610Salfred	struct inode *ip;
204184610Salfred	int error;
205184610Salfred
206184610Salfred	error = ufs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
207184610Salfred	    ap->a_dvp, vpp, ap->a_cnp);
208184610Salfred	if (error)
209239180Shselasky		return (error);
210184610Salfred	VN_POLLEVENT(ap->a_dvp, POLLWRITE);
211184610Salfred	ip = VTOI(*vpp);
212184610Salfred	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
213184610Salfred	if (vap->va_rdev != VNOVAL) {
214184610Salfred		/*
215184610Salfred		 * Want to be able to use this to make badblock
216184610Salfred		 * inodes, so don't truncate the dev number.
217184610Salfred		 */
218184610Salfred		ip->i_rdev = vap->va_rdev;
219184610Salfred	}
220189275Sthompsa	/*
221188942Sthompsa	 * Remove inode so that it will be reloaded by VFS_VGET and
222188942Sthompsa	 * checked to see if it is an alias of an existing entry in
223212122Sthompsa	 * the inode cache.
224184610Salfred	 */
225184610Salfred	vput(*vpp);
226184610Salfred	(*vpp)->v_type = VNON;
227184610Salfred	vgone(*vpp);
228192984Sthompsa	*vpp = 0;
229184610Salfred	return (0);
230192499Sthompsa}
231184610Salfred
232184610Salfred/*
233184610Salfred * Open called.
234184610Salfred *
235184610Salfred * Nothing to do.
236184610Salfred */
237184610Salfred/* ARGSUSED */
238184610Salfredint
239194228Sthompsaufs_open(ap)
240184610Salfred	struct vop_open_args /* {
241184610Salfred		struct vnode *a_vp;
242184610Salfred		int  a_mode;
243184610Salfred		struct ucred *a_cred;
244184610Salfred		struct proc *a_p;
245192984Sthompsa	} */ *ap;
246184610Salfred{
247184610Salfred
248197573Sthompsa	/*
249184610Salfred	 * Files marked append-only must be opened for appending.
250184610Salfred	 */
251184610Salfred	if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
252184610Salfred	    (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
253184610Salfred		return (EPERM);
254194228Sthompsa	return (0);
255189265Sthompsa}
256239180Shselasky
257184610Salfred/*
258184610Salfred * Close called.
259184610Salfred *
260184610Salfred * Update the times on the inode.
261194228Sthompsa */
262189265Sthompsa/* ARGSUSED */
263184610Salfredint
264184610Salfredufs_close(ap)
265184610Salfred	struct vop_close_args /* {
266199816Sthompsa		struct vnode *a_vp;
267184610Salfred		int  a_fflag;
268184610Salfred		struct ucred *a_cred;
269197573Sthompsa		struct proc *a_p;
270184610Salfred	} */ *ap;
271184610Salfred{
272184610Salfred	register struct vnode *vp = ap->a_vp;
273184610Salfred
274184610Salfred	simple_lock(&vp->v_interlock);
275197573Sthompsa	if (vp->v_usecount > 1)
276184610Salfred		ufs_itimes(vp);
277184610Salfred	simple_unlock(&vp->v_interlock);
278184610Salfred	return (0);
279184610Salfred}
280192984Sthompsa
281184610Salfredint
282187259Sthompsaufs_access(ap)
283187259Sthompsa	struct vop_access_args /* {
284197573Sthompsa		struct vnode *a_vp;
285197573Sthompsa		int  a_mode;
286184610Salfred		struct ucred *a_cred;
287194677Sthompsa		struct proc *a_p;
288184610Salfred	} */ *ap;
289184610Salfred{
290184610Salfred	struct vnode *vp = ap->a_vp;
291184610Salfred	struct inode *ip = VTOI(vp);
292184610Salfred	struct ucred *cred = ap->a_cred;
293184610Salfred	mode_t mask, mode = ap->a_mode;
294194228Sthompsa	register gid_t *gp;
295189265Sthompsa	int i;
296184610Salfred#ifdef QUOTA
297184610Salfred	int error;
298184610Salfred#endif
299214843Sn_hibma
300214843Sn_hibma	/*
301184610Salfred	 * Disallow write attempts on read-only file systems;
302184610Salfred	 * unless the file is a socket, fifo, or a block or
303184610Salfred	 * character device resident on the file system.
304184610Salfred	 */
305184610Salfred	if (mode & VWRITE) {
306184610Salfred		switch (vp->v_type) {
307184610Salfred		case VDIR:
308184610Salfred		case VLNK:
309184610Salfred		case VREG:
310184610Salfred			if (vp->v_mount->mnt_flag & MNT_RDONLY)
311184610Salfred				return (EROFS);
312184610Salfred#ifdef QUOTA
313214761Sn_hibma			if ((error = getinoquota(ip)) != 0)
314194228Sthompsa				return (error);
315184610Salfred#endif
316239299Shselasky			break;
317239299Shselasky		default:
318239299Shselasky			break;
319239299Shselasky		}
320184610Salfred	}
321184610Salfred
322184610Salfred	/* If immutable bit set, nobody gets to write it. */
323239180Shselasky	if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
324239180Shselasky		return (EPERM);
325184610Salfred
326239299Shselasky	/* Otherwise, user id 0 always gets access. */
327239180Shselasky	if (cred->cr_uid == 0)
328239180Shselasky		return (0);
329239299Shselasky
330239299Shselasky	mask = 0;
331239180Shselasky
332239180Shselasky	/* Otherwise, check the owner. */
333239180Shselasky	if (cred->cr_uid == ip->i_uid) {
334239180Shselasky		if (mode & VEXEC)
335239180Shselasky			mask |= S_IXUSR;
336239180Shselasky		if (mode & VREAD)
337239299Shselasky			mask |= S_IRUSR;
338239180Shselasky		if (mode & VWRITE)
339239180Shselasky			mask |= S_IWUSR;
340239180Shselasky		return ((ip->i_mode & mask) == mask ? 0 : EACCES);
341184610Salfred	}
342184610Salfred
343184610Salfred	/* Otherwise, check the groups. */
344192984Sthompsa	for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
345193045Sthompsa		if (ip->i_gid == *gp) {
346184610Salfred			if (mode & VEXEC)
347184610Salfred				mask |= S_IXGRP;
348188413Sthompsa			if (mode & VREAD)
349184610Salfred				mask |= S_IRGRP;
350184610Salfred			if (mode & VWRITE)
351184610Salfred				mask |= S_IWGRP;
352184610Salfred			return ((ip->i_mode & mask) == mask ? 0 : EACCES);
353184610Salfred		}
354184610Salfred
355184610Salfred	/* Otherwise, check everyone else. */
356184610Salfred	if (mode & VEXEC)
357184610Salfred		mask |= S_IXOTH;
358194228Sthompsa	if (mode & VREAD)
359188413Sthompsa		mask |= S_IROTH;
360184610Salfred	if (mode & VWRITE)
361184610Salfred		mask |= S_IWOTH;
362194228Sthompsa	return ((ip->i_mode & mask) == mask ? 0 : EACCES);
363184610Salfred}
364184610Salfred
365184610Salfred/* ARGSUSED */
366184610Salfredint
367184610Salfredufs_getattr(ap)
368197573Sthompsa	struct vop_getattr_args /* {
369184610Salfred		struct vnode *a_vp;
370194677Sthompsa		struct vattr *a_vap;
371194677Sthompsa		struct ucred *a_cred;
372184610Salfred		struct proc *a_p;
373194677Sthompsa	} */ *ap;
374184610Salfred{
375194677Sthompsa	register struct vnode *vp = ap->a_vp;
376194677Sthompsa	register struct inode *ip = VTOI(vp);
377184610Salfred	register struct vattr *vap = ap->a_vap;
378184610Salfred
379194677Sthompsa	ufs_itimes(vp);
380184610Salfred	/*
381184610Salfred	 * Copy from inode table
382184610Salfred	 */
383194677Sthompsa	vap->va_fsid = ip->i_dev;
384194677Sthompsa	vap->va_fileid = ip->i_number;
385184610Salfred	vap->va_mode = ip->i_mode & ~IFMT;
386184610Salfred	vap->va_nlink = ip->i_effnlink;
387184610Salfred	vap->va_uid = ip->i_uid;
388184610Salfred	vap->va_gid = ip->i_gid;
389194228Sthompsa	vap->va_rdev = (dev_t)ip->i_rdev;
390184610Salfred	vap->va_size = ip->i_din.di_size;
391184610Salfred	vap->va_atime.tv_sec = ip->i_atime;
392184610Salfred	vap->va_atime.tv_nsec = ip->i_atimensec;
393194677Sthompsa	vap->va_mtime.tv_sec = ip->i_mtime;
394194228Sthompsa	vap->va_mtime.tv_nsec = ip->i_mtimensec;
395184610Salfred	vap->va_ctime.tv_sec = ip->i_ctime;
396184610Salfred	vap->va_ctime.tv_nsec = ip->i_ctimensec;
397184610Salfred	vap->va_flags = ip->i_flags;
398194677Sthompsa	vap->va_gen = ip->i_gen;
399188413Sthompsa	/* this doesn't belong here */
400194677Sthompsa	if (vp->v_type == VBLK)
401188413Sthompsa		vap->va_blocksize = BLKDEV_IOSIZE;
402184610Salfred	else if (vp->v_type == VCHR)
403184610Salfred		vap->va_blocksize = MAXBSIZE;
404184610Salfred	else
405184610Salfred		vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
406184610Salfred	vap->va_bytes = dbtob((u_quad_t)ip->i_blocks);
407184610Salfred	vap->va_type = IFTOVT(ip->i_mode);
408192984Sthompsa	vap->va_filerev = ip->i_modrev;
409184610Salfred	return (0);
410184610Salfred}
411184610Salfred
412184610Salfred/*
413184610Salfred * Set attribute vnode op. called from several syscalls
414184610Salfred */
415184610Salfredint
416184610Salfredufs_setattr(ap)
417192984Sthompsa	struct vop_setattr_args /* {
418184610Salfred		struct vnode *a_vp;
419184610Salfred		struct vattr *a_vap;
420184610Salfred		struct ucred *a_cred;
421184610Salfred		struct proc *a_p;
422184610Salfred	} */ *ap;
423184610Salfred{
424184610Salfred	struct vattr *vap = ap->a_vap;
425184610Salfred	struct vnode *vp = ap->a_vp;
426184610Salfred	struct inode *ip = VTOI(vp);
427184610Salfred	struct ucred *cred = ap->a_cred;
428184610Salfred	struct proc *p = ap->a_p;
429184610Salfred	int error;
430192984Sthompsa
431184610Salfred	/*
432184610Salfred	 * Check for unsettable attributes.
433184610Salfred	 */
434184610Salfred	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
435184610Salfred	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
436184610Salfred	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
437184610Salfred	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
438184610Salfred		return (EINVAL);
439184610Salfred	}
440184610Salfred	if (vap->va_flags != VNOVAL) {
441184610Salfred		if (vp->v_mount->mnt_flag & MNT_RDONLY)
442184610Salfred			return (EROFS);
443192984Sthompsa		if (cred->cr_uid != ip->i_uid &&
444184610Salfred		    (error = suser(cred, &p->p_acflag)))
445184610Salfred			return (error);
446184610Salfred		if (cred->cr_uid == 0) {
447184610Salfred			if ((ip->i_flags
448184610Salfred			    & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) &&
449184610Salfred			    securelevel > 0)
450184610Salfred				return (EPERM);
451184610Salfred			ip->i_flags = vap->va_flags;
452184610Salfred		} else {
453184610Salfred			if (ip->i_flags
454184610Salfred			    & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) ||
455184610Salfred			    (vap->va_flags & UF_SETTABLE) != vap->va_flags)
456184610Salfred				return (EPERM);
457184610Salfred			ip->i_flags &= SF_SETTABLE;
458184610Salfred			ip->i_flags |= (vap->va_flags & UF_SETTABLE);
459184610Salfred		}
460184610Salfred		ip->i_flag |= IN_CHANGE;
461184610Salfred		if (vap->va_flags & (IMMUTABLE | APPEND))
462184610Salfred			return (0);
463184610Salfred	}
464184610Salfred	if (ip->i_flags & (IMMUTABLE | APPEND))
465184610Salfred		return (EPERM);
466184610Salfred	/*
467184610Salfred	 * Go through the fields and update iff not VNOVAL.
468184610Salfred	 */
469184610Salfred	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
470184610Salfred		if (vp->v_mount->mnt_flag & MNT_RDONLY)
471184610Salfred			return (EROFS);
472184610Salfred		if ((error = ufs_chown(vp, vap->va_uid, vap->va_gid, cred, p)) != 0)
473184610Salfred			return (error);
474184610Salfred	}
475184610Salfred	if (vap->va_size != VNOVAL) {
476184610Salfred		/*
477184610Salfred		 * Disallow write attempts on read-only file systems;
478184610Salfred		 * unless the file is a socket, fifo, or a block or
479184610Salfred		 * character device resident on the file system.
480184610Salfred		 */
481184610Salfred		switch (vp->v_type) {
482184610Salfred		case VDIR:
483184610Salfred			return (EISDIR);
484184610Salfred		case VLNK:
485184610Salfred		case VREG:
486192984Sthompsa			if (vp->v_mount->mnt_flag & MNT_RDONLY)
487184610Salfred				return (EROFS);
488184610Salfred			break;
489184610Salfred		default:
490184610Salfred			break;
491184610Salfred		}
492192984Sthompsa		if ((error = UFS_TRUNCATE(vp, vap->va_size, 0, cred, p)) != 0)
493184610Salfred			return (error);
494184610Salfred	}
495184610Salfred	ip = VTOI(vp);
496184610Salfred	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
497184610Salfred		if (vp->v_mount->mnt_flag & MNT_RDONLY)
498184610Salfred			return (EROFS);
499184610Salfred		if (cred->cr_uid != ip->i_uid &&
500184610Salfred		    (error = suser(cred, &p->p_acflag)) &&
501184610Salfred		    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
502184610Salfred		    (error = VOP_ACCESS(vp, VWRITE, cred, p))))
503184610Salfred			return (error);
504184610Salfred		if (vap->va_atime.tv_sec != VNOVAL)
505184610Salfred			ip->i_flag |= IN_ACCESS;
506184610Salfred		if (vap->va_mtime.tv_sec != VNOVAL)
507184610Salfred			ip->i_flag |= IN_CHANGE | IN_UPDATE;
508184610Salfred		ufs_itimes(vp);
509184610Salfred		if (vap->va_atime.tv_sec != VNOVAL)
510184610Salfred			ip->i_atime = vap->va_atime.tv_sec;
511184610Salfred		if (vap->va_mtime.tv_sec != VNOVAL)
512184610Salfred			ip->i_mtime = vap->va_mtime.tv_sec;
513184610Salfred		error = UFS_UPDATE(vp, 0);
514184610Salfred		if (error)
515184610Salfred			return (error);
516184610Salfred	}
517184610Salfred	error = 0;
518184610Salfred	if (vap->va_mode != (mode_t)VNOVAL) {
519184610Salfred		if (vp->v_mount->mnt_flag & MNT_RDONLY)
520184610Salfred			return (EROFS);
521184610Salfred		error = ufs_chmod(vp, (int)vap->va_mode, cred, p);
522184610Salfred	}
523184610Salfred	VN_POLLEVENT(vp, POLLATTRIB);
524184610Salfred	return (error);
525184610Salfred}
526184610Salfred
527184610Salfred/*
528184610Salfred * Change the mode on a file.
529184610Salfred * Inode must be locked before calling.
530184610Salfred */
531184610Salfredstatic int
532184610Salfredufs_chmod(vp, mode, cred, p)
533192984Sthompsa	register struct vnode *vp;
534184610Salfred	register int mode;
535184610Salfred	register struct ucred *cred;
536184610Salfred	struct proc *p;
537184610Salfred{
538194228Sthompsa	register struct inode *ip = VTOI(vp);
539184610Salfred	int error;
540184610Salfred
541194228Sthompsa	if (cred->cr_uid != ip->i_uid) {
542184610Salfred	    error = suser(cred, &p->p_acflag);
543184610Salfred	    if (error)
544184610Salfred		return (error);
545192984Sthompsa	}
546184610Salfred	if (cred->cr_uid) {
547184610Salfred		if (vp->v_type != VDIR && (mode & S_ISTXT))
548184610Salfred			return (EFTYPE);
549184610Salfred		if (!groupmember(ip->i_gid, cred) && (mode & ISGID))
550194228Sthompsa			return (EPERM);
551184610Salfred	}
552184610Salfred	ip->i_mode &= ~ALLPERMS;
553194228Sthompsa	ip->i_mode |= (mode & ALLPERMS);
554184610Salfred	ip->i_flag |= IN_CHANGE;
555184610Salfred	return (0);
556184610Salfred}
557192984Sthompsa
558184610Salfred/*
559184610Salfred * Perform chown operation on inode ip;
560184610Salfred * inode must be locked prior to call.
561194228Sthompsa */
562184610Salfredstatic int
563184610Salfredufs_chown(vp, uid, gid, cred, p)
564184610Salfred	register struct vnode *vp;
565192984Sthompsa	uid_t uid;
566184610Salfred	gid_t gid;
567184610Salfred	struct ucred *cred;
568184610Salfred	struct proc *p;
569194228Sthompsa{
570184610Salfred	register struct inode *ip = VTOI(vp);
571184610Salfred	uid_t ouid;
572184610Salfred	gid_t ogid;
573197573Sthompsa	int error = 0;
574197573Sthompsa#ifdef QUOTA
575197573Sthompsa	register int i;
576197573Sthompsa	long change;
577197573Sthompsa#endif
578197573Sthompsa
579197573Sthompsa	if (uid == (uid_t)VNOVAL)
580197573Sthompsa		uid = ip->i_uid;
581197573Sthompsa	if (gid == (gid_t)VNOVAL)
582197573Sthompsa		gid = ip->i_gid;
583197573Sthompsa	/*
584197573Sthompsa	 * If we don't own the file, are trying to change the owner
585197573Sthompsa	 * of the file, or are not a member of the target group,
586197573Sthompsa	 * the caller must be superuser or the call fails.
587197573Sthompsa	 */
588197573Sthompsa	if ((cred->cr_uid != ip->i_uid || uid != ip->i_uid ||
589197573Sthompsa	    (gid != ip->i_gid && !groupmember((gid_t)gid, cred))) &&
590197573Sthompsa	    (error = suser(cred, &p->p_acflag)))
591197573Sthompsa		return (error);
592197573Sthompsa	ogid = ip->i_gid;
593197573Sthompsa	ouid = ip->i_uid;
594197573Sthompsa#ifdef QUOTA
595194677Sthompsa	if ((error = getinoquota(ip)) != 0)
596184610Salfred		return (error);
597194677Sthompsa	if (ouid == uid) {
598194677Sthompsa		dqrele(vp, ip->i_dquot[USRQUOTA]);
599184610Salfred		ip->i_dquot[USRQUOTA] = NODQUOT;
600184610Salfred	}
601184610Salfred	if (ogid == gid) {
602184610Salfred		dqrele(vp, ip->i_dquot[GRPQUOTA]);
603184610Salfred		ip->i_dquot[GRPQUOTA] = NODQUOT;
604188413Sthompsa	}
605194677Sthompsa	change = ip->i_blocks;
606194677Sthompsa	(void) chkdq(ip, -change, cred, CHOWN);
607184610Salfred	(void) chkiq(ip, -1, cred, CHOWN);
608184610Salfred	for (i = 0; i < MAXQUOTAS; i++) {
609194677Sthompsa		dqrele(vp, ip->i_dquot[i]);
610194228Sthompsa		ip->i_dquot[i] = NODQUOT;
611184610Salfred	}
612184610Salfred#endif
613184610Salfred	ip->i_gid = gid;
614184610Salfred	ip->i_uid = uid;
615194677Sthompsa#ifdef QUOTA
616188413Sthompsa	if ((error = getinoquota(ip)) == 0) {
617194677Sthompsa		if (ouid == uid) {
618188413Sthompsa			dqrele(vp, ip->i_dquot[USRQUOTA]);
619184610Salfred			ip->i_dquot[USRQUOTA] = NODQUOT;
620184610Salfred		}
621184610Salfred		if (ogid == gid) {
622184610Salfred			dqrele(vp, ip->i_dquot[GRPQUOTA]);
623184610Salfred			ip->i_dquot[GRPQUOTA] = NODQUOT;
624184610Salfred		}
625197573Sthompsa		if ((error = chkdq(ip, change, cred, CHOWN)) == 0) {
626184610Salfred			if ((error = chkiq(ip, 1, cred, CHOWN)) == 0)
627194677Sthompsa				goto good;
628194677Sthompsa			else
629194677Sthompsa				(void) chkdq(ip, -change, cred, CHOWN|FORCE);
630184610Salfred		}
631194677Sthompsa		for (i = 0; i < MAXQUOTAS; i++) {
632194677Sthompsa			dqrele(vp, ip->i_dquot[i]);
633184610Salfred			ip->i_dquot[i] = NODQUOT;
634184610Salfred		}
635194677Sthompsa	}
636194677Sthompsa	ip->i_gid = ogid;
637184610Salfred	ip->i_uid = ouid;
638184610Salfred	if (getinoquota(ip) == 0) {
639188413Sthompsa		if (ouid == uid) {
640194677Sthompsa			dqrele(vp, ip->i_dquot[USRQUOTA]);
641194228Sthompsa			ip->i_dquot[USRQUOTA] = NODQUOT;
642184610Salfred		}
643184610Salfred		if (ogid == gid) {
644184610Salfred			dqrele(vp, ip->i_dquot[GRPQUOTA]);
645194677Sthompsa			ip->i_dquot[GRPQUOTA] = NODQUOT;
646188413Sthompsa		}
647194677Sthompsa		(void) chkdq(ip, change, cred, FORCE|CHOWN);
648188413Sthompsa		(void) chkiq(ip, 1, cred, FORCE|CHOWN);
649184610Salfred		(void) getinoquota(ip);
650184610Salfred	}
651184610Salfred	return (error);
652184610Salfredgood:
653197570Sthompsa	if (getinoquota(ip))
654197570Sthompsa		panic("ufs_chown: lost quota");
655197570Sthompsa#endif /* QUOTA */
656197570Sthompsa	ip->i_flag |= IN_CHANGE;
657197570Sthompsa	if (cred->cr_uid != 0 && (ouid != uid || ogid != gid))
658197570Sthompsa		ip->i_mode &= ~(ISUID | ISGID);
659197570Sthompsa	return (0);
660}
661
662/*
663 * Mmap a file
664 *
665 * NB Currently unsupported.
666 */
667/* ARGSUSED */
668int
669ufs_mmap(ap)
670	struct vop_mmap_args /* {
671		struct vnode *a_vp;
672		int  a_fflags;
673		struct ucred *a_cred;
674		struct proc *a_p;
675	} */ *ap;
676{
677
678	return (EINVAL);
679}
680
681int
682ufs_remove(ap)
683	struct vop_remove_args /* {
684		struct vnode *a_dvp;
685		struct vnode *a_vp;
686		struct componentname *a_cnp;
687	} */ *ap;
688{
689	struct inode *ip;
690	struct vnode *vp = ap->a_vp;
691	struct vnode *dvp = ap->a_dvp;
692	int error;
693
694	ip = VTOI(vp);
695	if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
696	    (VTOI(dvp)->i_flags & APPEND)) {
697		error = EPERM;
698		goto out;
699	}
700	error = ufs_dirremove(dvp, ip, ap->a_cnp->cn_flags, 0);
701	VN_POLLEVENT(vp, POLLNLINK);
702	VN_POLLEVENT(dvp, POLLWRITE);
703out:
704	return (error);
705}
706
707/*
708 * link vnode call
709 */
710int
711ufs_link(ap)
712	struct vop_link_args /* {
713		struct vnode *a_tdvp;
714		struct vnode *a_vp;
715		struct componentname *a_cnp;
716	} */ *ap;
717{
718	struct vnode *vp = ap->a_vp;
719	struct vnode *tdvp = ap->a_tdvp;
720	struct componentname *cnp = ap->a_cnp;
721	struct proc *p = cnp->cn_proc;
722	struct inode *ip;
723	struct direct newdir;
724	int error;
725
726#ifdef DIAGNOSTIC
727	if ((cnp->cn_flags & HASBUF) == 0)
728		panic("ufs_link: no name");
729#endif
730	if (tdvp->v_mount != vp->v_mount) {
731		VOP_ABORTOP(tdvp, cnp);
732		error = EXDEV;
733		goto out2;
734	}
735	if (tdvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
736		VOP_ABORTOP(tdvp, cnp);
737		goto out2;
738	}
739	ip = VTOI(vp);
740	if ((nlink_t)ip->i_nlink >= LINK_MAX) {
741		VOP_ABORTOP(tdvp, cnp);
742		error = EMLINK;
743		goto out1;
744	}
745	if (ip->i_flags & (IMMUTABLE | APPEND)) {
746		VOP_ABORTOP(tdvp, cnp);
747		error = EPERM;
748		goto out1;
749	}
750	ip->i_effnlink++;
751	ip->i_nlink++;
752	ip->i_flag |= IN_CHANGE;
753	if (DOINGSOFTDEP(vp))
754		softdep_increase_linkcnt(ip);
755	error = UFS_UPDATE(vp, !DOINGSOFTDEP(vp));
756	if (!error) {
757		ufs_makedirentry(ip, cnp, &newdir);
758		error = ufs_direnter(tdvp, vp, &newdir, cnp, NULL);
759	}
760
761	if (error) {
762		ip->i_effnlink--;
763		ip->i_nlink--;
764		ip->i_flag |= IN_CHANGE;
765	}
766	zfree(namei_zone, cnp->cn_pnbuf);
767out1:
768	if (tdvp != vp)
769		VOP_UNLOCK(vp, 0, p);
770out2:
771	VN_POLLEVENT(vp, POLLNLINK);
772	VN_POLLEVENT(tdvp, POLLWRITE);
773	return (error);
774}
775
776/*
777 * whiteout vnode call
778 */
779int
780ufs_whiteout(ap)
781	struct vop_whiteout_args /* {
782		struct vnode *a_dvp;
783		struct componentname *a_cnp;
784		int a_flags;
785	} */ *ap;
786{
787	struct vnode *dvp = ap->a_dvp;
788	struct componentname *cnp = ap->a_cnp;
789	struct direct newdir;
790	int error = 0;
791
792	switch (ap->a_flags) {
793	case LOOKUP:
794		/* 4.4 format directories support whiteout operations */
795		if (dvp->v_mount->mnt_maxsymlinklen > 0)
796			return (0);
797		return (EOPNOTSUPP);
798
799	case CREATE:
800		/* create a new directory whiteout */
801#ifdef DIAGNOSTIC
802		if ((cnp->cn_flags & SAVENAME) == 0)
803			panic("ufs_whiteout: missing name");
804		if (dvp->v_mount->mnt_maxsymlinklen <= 0)
805			panic("ufs_whiteout: old format filesystem");
806#endif
807
808		newdir.d_ino = WINO;
809		newdir.d_namlen = cnp->cn_namelen;
810		bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1);
811		newdir.d_type = DT_WHT;
812		error = ufs_direnter(dvp, NULL, &newdir, cnp, NULL);
813		break;
814
815	case DELETE:
816		/* remove an existing directory whiteout */
817#ifdef DIAGNOSTIC
818		if (dvp->v_mount->mnt_maxsymlinklen <= 0)
819			panic("ufs_whiteout: old format filesystem");
820#endif
821
822		cnp->cn_flags &= ~DOWHITEOUT;
823		error = ufs_dirremove(dvp, NULL, cnp->cn_flags, 0);
824		break;
825	default:
826		panic("ufs_whiteout: unknown op");
827	}
828	if (cnp->cn_flags & HASBUF) {
829		zfree(namei_zone, cnp->cn_pnbuf);
830		cnp->cn_flags &= ~HASBUF;
831	}
832	return (error);
833}
834
835/*
836 * Rename system call.
837 * 	rename("foo", "bar");
838 * is essentially
839 *	unlink("bar");
840 *	link("foo", "bar");
841 *	unlink("foo");
842 * but ``atomically''.  Can't do full commit without saving state in the
843 * inode on disk which isn't feasible at this time.  Best we can do is
844 * always guarantee the target exists.
845 *
846 * Basic algorithm is:
847 *
848 * 1) Bump link count on source while we're linking it to the
849 *    target.  This also ensure the inode won't be deleted out
850 *    from underneath us while we work (it may be truncated by
851 *    a concurrent `trunc' or `open' for creation).
852 * 2) Link source to destination.  If destination already exists,
853 *    delete it first.
854 * 3) Unlink source reference to inode if still around. If a
855 *    directory was moved and the parent of the destination
856 *    is different from the source, patch the ".." entry in the
857 *    directory.
858 */
859int
860ufs_rename(ap)
861	struct vop_rename_args  /* {
862		struct vnode *a_fdvp;
863		struct vnode *a_fvp;
864		struct componentname *a_fcnp;
865		struct vnode *a_tdvp;
866		struct vnode *a_tvp;
867		struct componentname *a_tcnp;
868	} */ *ap;
869{
870	struct vnode *tvp = ap->a_tvp;
871	register struct vnode *tdvp = ap->a_tdvp;
872	struct vnode *fvp = ap->a_fvp;
873	struct vnode *fdvp = ap->a_fdvp;
874	struct componentname *tcnp = ap->a_tcnp;
875	struct componentname *fcnp = ap->a_fcnp;
876	struct proc *p = fcnp->cn_proc;
877	struct inode *ip, *xp, *dp;
878	struct direct newdir;
879	int doingdirectory = 0, oldparent = 0, newparent = 0;
880	int error = 0;
881
882#ifdef DIAGNOSTIC
883	if ((tcnp->cn_flags & HASBUF) == 0 ||
884	    (fcnp->cn_flags & HASBUF) == 0)
885		panic("ufs_rename: no name");
886#endif
887	/*
888	 * Check for cross-device rename.
889	 */
890	if ((fvp->v_mount != tdvp->v_mount) ||
891	    (tvp && (fvp->v_mount != tvp->v_mount))) {
892		error = EXDEV;
893abortit:
894		VOP_ABORTOP(tdvp, tcnp);
895		if (tdvp == tvp)
896			vrele(tdvp);
897		else
898			vput(tdvp);
899		if (tvp)
900			vput(tvp);
901		VOP_ABORTOP(fdvp, fcnp);
902		vrele(fdvp);
903		vrele(fvp);
904		return (error);
905	}
906
907	if (tvp && ((VTOI(tvp)->i_flags & (NOUNLINK | IMMUTABLE | APPEND)) ||
908	    (VTOI(tdvp)->i_flags & APPEND))) {
909		error = EPERM;
910		goto abortit;
911	}
912
913	/*
914	 * Check if just deleting a link name or if we've lost a race.
915	 * If another process completes the same rename after we've looked
916	 * up the source and have blocked looking up the target, then the
917	 * source and target inodes may be identical now although the
918	 * names were never linked.
919	 */
920	if (fvp == tvp) {
921		if (fvp->v_type == VDIR) {
922			/*
923			 * Linked directories are impossible, so we must
924			 * have lost the race.  Pretend that the rename
925			 * completed before the lookup.
926			 */
927#ifdef UFS_RENAME_DEBUG
928			printf("ufs_rename: fvp == tvp for directories\n");
929#endif
930			error = ENOENT;
931			goto abortit;
932		}
933
934		/* Release destination completely. */
935		VOP_ABORTOP(tdvp, tcnp);
936		vput(tdvp);
937		vput(tvp);
938
939		/*
940		 * Delete source.  There is another race now that everything
941		 * is unlocked, but this doesn't cause any new complications.
942		 * Relookup() may find a file that is unrelated to the
943		 * original one, or it may fail.  Too bad.
944		 */
945		vrele(fdvp);
946		vrele(fvp);
947		fcnp->cn_flags &= ~MODMASK;
948		fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
949		if ((fcnp->cn_flags & SAVESTART) == 0)
950			panic("ufs_rename: lost from startdir");
951		fcnp->cn_nameiop = DELETE;
952		VREF(fdvp);
953		error = relookup(fdvp, &fvp, fcnp);
954		if (error == 0)
955			vrele(fdvp);
956		if (fvp == NULL) {
957#ifdef UFS_RENAME_DEBUG
958			printf("ufs_rename: from name disappeared\n");
959#endif
960			return (ENOENT);
961		}
962		error = VOP_REMOVE(fdvp, fvp, fcnp);
963		if (fdvp == fvp)
964			vrele(fdvp);
965		else
966			vput(fdvp);
967		vput(fvp);
968		return (error);
969	}
970	if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
971		goto abortit;
972	dp = VTOI(fdvp);
973	ip = VTOI(fvp);
974	if ((ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))
975	    || (dp->i_flags & APPEND)) {
976		VOP_UNLOCK(fvp, 0, p);
977		error = EPERM;
978		goto abortit;
979	}
980	if ((ip->i_mode & IFMT) == IFDIR) {
981		/*
982		 * Avoid ".", "..", and aliases of "." for obvious reasons.
983		 */
984		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
985		    dp == ip || (fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT ||
986		    (ip->i_flag & IN_RENAME)) {
987			VOP_UNLOCK(fvp, 0, p);
988			error = EINVAL;
989			goto abortit;
990		}
991		ip->i_flag |= IN_RENAME;
992		oldparent = dp->i_number;
993		doingdirectory = 1;
994	}
995	VN_POLLEVENT(fdvp, POLLWRITE);
996	vrele(fdvp);
997
998	/*
999	 * When the target exists, both the directory
1000	 * and target vnodes are returned locked.
1001	 */
1002	dp = VTOI(tdvp);
1003	xp = NULL;
1004	if (tvp)
1005		xp = VTOI(tvp);
1006
1007	/*
1008	 * 1) Bump link count while we're moving stuff
1009	 *    around.  If we crash somewhere before
1010	 *    completing our work, the link count
1011	 *    may be wrong, but correctable.
1012	 */
1013	ip->i_effnlink++;
1014	ip->i_nlink++;
1015	ip->i_flag |= IN_CHANGE;
1016	if (DOINGSOFTDEP(fvp))
1017		softdep_increase_linkcnt(ip);
1018	if ((error = UFS_UPDATE(fvp, !DOINGSOFTDEP(fvp))) != 0) {
1019		VOP_UNLOCK(fvp, 0, p);
1020		goto bad;
1021	}
1022
1023	/*
1024	 * If ".." must be changed (ie the directory gets a new
1025	 * parent) then the source directory must not be in the
1026	 * directory heirarchy above the target, as this would
1027	 * orphan everything below the source directory. Also
1028	 * the user must have write permission in the source so
1029	 * as to be able to change "..". We must repeat the call
1030	 * to namei, as the parent directory is unlocked by the
1031	 * call to checkpath().
1032	 */
1033	error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
1034	VOP_UNLOCK(fvp, 0, p);
1035	if (oldparent != dp->i_number)
1036		newparent = dp->i_number;
1037	if (doingdirectory && newparent) {
1038		if (error)	/* write access check above */
1039			goto bad;
1040		if (xp != NULL)
1041			vput(tvp);
1042		error = ufs_checkpath(ip, dp, tcnp->cn_cred);
1043		if (error)
1044			goto out;
1045		if ((tcnp->cn_flags & SAVESTART) == 0)
1046			panic("ufs_rename: lost to startdir");
1047		VREF(tdvp);
1048		error = relookup(tdvp, &tvp, tcnp);
1049		if (error)
1050			goto out;
1051		vrele(tdvp);
1052		dp = VTOI(tdvp);
1053		xp = NULL;
1054		if (tvp)
1055			xp = VTOI(tvp);
1056	}
1057	/*
1058	 * 2) If target doesn't exist, link the target
1059	 *    to the source and unlink the source.
1060	 *    Otherwise, rewrite the target directory
1061	 *    entry to reference the source inode and
1062	 *    expunge the original entry's existence.
1063	 */
1064	if (xp == NULL) {
1065		if (dp->i_dev != ip->i_dev)
1066			panic("ufs_rename: EXDEV");
1067		/*
1068		 * Account for ".." in new directory.
1069		 * When source and destination have the same
1070		 * parent we don't fool with the link count.
1071		 */
1072		if (doingdirectory && newparent) {
1073			if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1074				error = EMLINK;
1075				goto bad;
1076			}
1077			dp->i_effnlink++;
1078			dp->i_nlink++;
1079			dp->i_flag |= IN_CHANGE;
1080			if (DOINGSOFTDEP(tdvp))
1081				softdep_increase_linkcnt(dp);
1082			error = UFS_UPDATE(tdvp, !DOINGSOFTDEP(tdvp));
1083			if (error)
1084				goto bad;
1085		}
1086		ufs_makedirentry(ip, tcnp, &newdir);
1087		error = ufs_direnter(tdvp, NULL, &newdir, tcnp, NULL);
1088		if (error) {
1089			if (doingdirectory && newparent) {
1090				dp->i_effnlink--;
1091				dp->i_nlink--;
1092				dp->i_flag |= IN_CHANGE;
1093				(void)UFS_UPDATE(tdvp, 1);
1094			}
1095			goto bad;
1096		}
1097		VN_POLLEVENT(tdvp, POLLWRITE);
1098		vput(tdvp);
1099	} else {
1100		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
1101			panic("ufs_rename: EXDEV");
1102		/*
1103		 * Short circuit rename(foo, foo).
1104		 */
1105		if (xp->i_number == ip->i_number)
1106			panic("ufs_rename: same file");
1107		/*
1108		 * If the parent directory is "sticky", then the user must
1109		 * own the parent directory, or the destination of the rename,
1110		 * otherwise the destination may not be changed (except by
1111		 * root). This implements append-only directories.
1112		 */
1113		if ((dp->i_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
1114		    tcnp->cn_cred->cr_uid != dp->i_uid &&
1115		    xp->i_uid != tcnp->cn_cred->cr_uid) {
1116			error = EPERM;
1117			goto bad;
1118		}
1119		/*
1120		 * Target must be empty if a directory and have no links
1121		 * to it. Also, ensure source and target are compatible
1122		 * (both directories, or both not directories).
1123		 */
1124		if ((xp->i_mode&IFMT) == IFDIR) {
1125			if ((xp->i_effnlink > 2) ||
1126			    !ufs_dirempty(xp, dp->i_number, tcnp->cn_cred)) {
1127				error = ENOTEMPTY;
1128				goto bad;
1129			}
1130			if (!doingdirectory) {
1131				error = ENOTDIR;
1132				goto bad;
1133			}
1134			cache_purge(tdvp);
1135		} else if (doingdirectory) {
1136			error = EISDIR;
1137			goto bad;
1138		}
1139		error = ufs_dirrewrite(dp, xp, ip->i_number,
1140		    IFTODT(ip->i_mode),
1141		    (doingdirectory && newparent) ? newparent : doingdirectory);
1142		if (error)
1143			goto bad;
1144		if (doingdirectory) {
1145			if (!newparent) {
1146				dp->i_effnlink--;
1147				dp->i_flag |= IN_CHANGE;
1148			}
1149			xp->i_effnlink--;
1150			xp->i_flag |= IN_CHANGE;
1151		}
1152		VN_POLLEVENT(tdvp, POLLWRITE);
1153		if (doingdirectory && !DOINGSOFTDEP(tvp)) {
1154			/*
1155			 * Truncate inode. The only stuff left in the directory
1156			 * is "." and "..". The "." reference is inconsequential
1157			 * since we are quashing it. We have removed the "."
1158			 * reference and the reference in the parent directory,
1159			 * but there may be other hard links. The soft
1160			 * dependency code will arrange to do these operations
1161			 * after the parent directory entry has been deleted on
1162			 * disk, so when running with that code we avoid doing
1163			 * them now.
1164			 */
1165			if (!newparent)
1166				dp->i_nlink--;
1167			xp->i_nlink--;
1168			if ((error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC,
1169			    tcnp->cn_cred, tcnp->cn_proc)) != 0)
1170				goto bad;
1171		}
1172		vput(tdvp);
1173		VN_POLLEVENT(tvp, POLLNLINK); /* XXX this right? */
1174		vput(tvp);
1175		xp = NULL;
1176	}
1177
1178	/*
1179	 * 3) Unlink the source.
1180	 */
1181	fcnp->cn_flags &= ~MODMASK;
1182	fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
1183	if ((fcnp->cn_flags & SAVESTART) == 0)
1184		panic("ufs_rename: lost from startdir");
1185	VREF(fdvp);
1186	error = relookup(fdvp, &fvp, fcnp);
1187	if (error == 0)
1188		vrele(fdvp);
1189	if (fvp != NULL) {
1190		xp = VTOI(fvp);
1191		dp = VTOI(fdvp);
1192	} else {
1193		/*
1194		 * From name has disappeared.
1195		 */
1196		if (doingdirectory)
1197			panic("ufs_rename: lost dir entry");
1198		vrele(ap->a_fvp);
1199		return (0);
1200	}
1201	/*
1202	 * Ensure that the directory entry still exists and has not
1203	 * changed while the new name has been entered. If the source is
1204	 * a file then the entry may have been unlinked or renamed. In
1205	 * either case there is no further work to be done. If the source
1206	 * is a directory then it cannot have been rmdir'ed; the IN_RENAME
1207	 * flag ensures that it cannot be moved by another rename or removed
1208	 * by a rmdir.
1209	 */
1210	if (xp != ip) {
1211		if (doingdirectory)
1212			panic("ufs_rename: lost dir entry");
1213	} else {
1214		/*
1215		 * If the source is a directory with a
1216		 * new parent, the link count of the old
1217		 * parent directory must be decremented
1218		 * and ".." set to point to the new parent.
1219		 */
1220		if (doingdirectory && newparent) {
1221			xp->i_offset = mastertemplate.dot_reclen;
1222			ufs_dirrewrite(xp, dp, newparent, DT_DIR, 0);
1223			cache_purge(fdvp);
1224		}
1225		error = ufs_dirremove(fdvp, xp, fcnp->cn_flags, 0);
1226		xp->i_flag &= ~IN_RENAME;
1227	}
1228	if (dp)
1229		vput(fdvp);
1230	if (xp)
1231		vput(fvp);
1232	vrele(ap->a_fvp);
1233	return (error);
1234
1235bad:
1236	if (xp)
1237		vput(ITOV(xp));
1238	vput(ITOV(dp));
1239out:
1240	if (doingdirectory)
1241		ip->i_flag &= ~IN_RENAME;
1242	if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
1243		ip->i_effnlink--;
1244		ip->i_nlink--;
1245		ip->i_flag |= IN_CHANGE;
1246		ip->i_flag &= ~IN_RENAME;
1247		vput(fvp);
1248	} else
1249		vrele(fvp);
1250	return (error);
1251}
1252
1253/*
1254 * Mkdir system call
1255 */
1256int
1257ufs_mkdir(ap)
1258	struct vop_mkdir_args /* {
1259		struct vnode *a_dvp;
1260		struct vnode **a_vpp;
1261		struct componentname *a_cnp;
1262		struct vattr *a_vap;
1263	} */ *ap;
1264{
1265	register struct vnode *dvp = ap->a_dvp;
1266	register struct vattr *vap = ap->a_vap;
1267	register struct componentname *cnp = ap->a_cnp;
1268	register struct inode *ip, *dp;
1269	struct vnode *tvp;
1270	struct buf *bp;
1271	struct dirtemplate dirtemplate, *dtp;
1272	struct direct newdir;
1273	int error, dmode;
1274	long blkoff;
1275
1276#ifdef DIAGNOSTIC
1277	if ((cnp->cn_flags & HASBUF) == 0)
1278		panic("ufs_mkdir: no name");
1279#endif
1280	dp = VTOI(dvp);
1281	if ((nlink_t)dp->i_nlink >= LINK_MAX) {
1282		error = EMLINK;
1283		goto out;
1284	}
1285	dmode = vap->va_mode & 0777;
1286	dmode |= IFDIR;
1287	/*
1288	 * Must simulate part of ufs_makeinode here to acquire the inode,
1289	 * but not have it entered in the parent directory. The entry is
1290	 * made later after writing "." and ".." entries.
1291	 */
1292	error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp);
1293	if (error)
1294		goto out;
1295	ip = VTOI(tvp);
1296	ip->i_gid = dp->i_gid;
1297#ifdef SUIDDIR
1298	{
1299#ifdef QUOTA
1300		struct ucred ucred, *ucp;
1301		ucp = cnp->cn_cred;
1302#endif			I
1303		/*
1304		 * If we are hacking owners here, (only do this where told to)
1305		 * and we are not giving it TOO root, (would subvert quotas)
1306		 * then go ahead and give it to the other user.
1307		 * The new directory also inherits the SUID bit.
1308		 * If user's UID and dir UID are the same,
1309		 * 'give it away' so that the SUID is still forced on.
1310		 */
1311		if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
1312		    (dp->i_mode & ISUID) && dp->i_uid) {
1313			dmode |= ISUID;
1314			ip->i_uid = dp->i_uid;
1315#ifdef QUOTA
1316			if (dp->i_uid != cnp->cn_cred->cr_uid) {
1317				/*
1318				 * Make sure the correct user gets charged
1319				 * for the space.
1320				 * Make a dummy credential for the victim.
1321				 * XXX This seems to never be accessed out of
1322				 * our context so a stack variable is ok.
1323				 */
1324				ucred.cr_ref = 1;
1325				ucred.cr_uid = ip->i_uid;
1326				ucred.cr_ngroups = 1;
1327				ucred.cr_groups[0] = dp->i_gid;
1328				ucp = &ucred;
1329			}
1330#endif
1331		} else
1332			ip->i_uid = cnp->cn_cred->cr_uid;
1333#ifdef QUOTA
1334		if ((error = getinoquota(ip)) ||
1335	    	    (error = chkiq(ip, 1, ucp, 0))) {
1336			zfree(namei_zone, cnp->cn_pnbuf);
1337			UFS_VFREE(tvp, ip->i_number, dmode);
1338			vput(tvp);
1339			return (error);
1340		}
1341#endif
1342	}
1343#else	/* !SUIDDIR */
1344	ip->i_uid = cnp->cn_cred->cr_uid;
1345#ifdef QUOTA
1346	if ((error = getinoquota(ip)) ||
1347	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
1348		zfree(namei_zone, cnp->cn_pnbuf);
1349		UFS_VFREE(tvp, ip->i_number, dmode);
1350		vput(tvp);
1351		return (error);
1352	}
1353#endif
1354#endif	/* !SUIDDIR */
1355	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1356	ip->i_mode = dmode;
1357	tvp->v_type = VDIR;	/* Rest init'd in getnewvnode(). */
1358	ip->i_effnlink = 2;
1359	ip->i_nlink = 2;
1360	if (DOINGSOFTDEP(tvp))
1361		softdep_increase_linkcnt(ip);
1362	if (cnp->cn_flags & ISWHITEOUT)
1363		ip->i_flags |= UF_OPAQUE;
1364
1365	/*
1366	 * Bump link count in parent directory to reflect work done below.
1367	 * Should be done before reference is created so cleanup is
1368	 * possible if we crash.
1369	 */
1370	dp->i_effnlink++;
1371	dp->i_nlink++;
1372	dp->i_flag |= IN_CHANGE;
1373	if (DOINGSOFTDEP(dvp))
1374		softdep_increase_linkcnt(dp);
1375	error = UFS_UPDATE(tvp, !DOINGSOFTDEP(dvp));
1376	if (error)
1377		goto bad;
1378
1379	/*
1380	 * Initialize directory with "." and ".." from static template.
1381	 */
1382	if (dvp->v_mount->mnt_maxsymlinklen > 0
1383	)
1384		dtp = &mastertemplate;
1385	else
1386		dtp = (struct dirtemplate *)&omastertemplate;
1387	dirtemplate = *dtp;
1388	dirtemplate.dot_ino = ip->i_number;
1389	dirtemplate.dotdot_ino = dp->i_number;
1390	if ((error = VOP_BALLOC(tvp, (off_t)0, DIRBLKSIZ, cnp->cn_cred,
1391	    B_CLRBUF, &bp)) != 0)
1392		goto bad;
1393	ip->i_size = DIRBLKSIZ;
1394	ip->i_flag |= IN_CHANGE | IN_UPDATE;
1395	vnode_pager_setsize(tvp, (u_long)ip->i_size);
1396	bcopy((caddr_t)&dirtemplate, (caddr_t)bp->b_data, sizeof dirtemplate);
1397	if (DOINGSOFTDEP(tvp)) {
1398		/*
1399		 * Ensure that the entire newly allocated block is a
1400		 * valid directory so that future growth within the
1401		 * block does not have to ensure that the block is
1402		 * written before the inode.
1403		 */
1404		blkoff = DIRBLKSIZ;
1405		while (blkoff < bp->b_bcount) {
1406			((struct direct *)
1407			   (bp->b_data + blkoff))->d_reclen = DIRBLKSIZ;
1408			blkoff += DIRBLKSIZ;
1409		}
1410	}
1411	if ((error = UFS_UPDATE(tvp, !DOINGSOFTDEP(tvp))) != 0) {
1412		(void)VOP_BWRITE(bp);
1413		goto bad;
1414	}
1415	VN_POLLEVENT(dvp, POLLWRITE); /* XXX right place? */
1416	/*
1417	 * Directory set up, now install its entry in the parent directory.
1418	 *
1419	 * If we are not doing soft dependencies, then we must write out the
1420	 * buffer containing the new directory body before entering the new
1421	 * name in the parent. If we are doing soft dependencies, then the
1422	 * buffer containing the new directory body will be passed to and
1423	 * released in the soft dependency code after the code has attached
1424	 * an appropriate ordering dependency to the buffer which ensures that
1425	 * the buffer is written before the new name is written in the parent.
1426	 */
1427	if (!DOINGSOFTDEP(dvp) && ((error = VOP_BWRITE(bp)) != 0))
1428		goto bad;
1429	ufs_makedirentry(ip, cnp, &newdir);
1430	error = ufs_direnter(dvp, tvp, &newdir, cnp, bp);
1431
1432bad:
1433	if (error == 0) {
1434		*ap->a_vpp = tvp;
1435	} else {
1436		dp->i_effnlink--;
1437		dp->i_nlink--;
1438		dp->i_flag |= IN_CHANGE;
1439		/*
1440		 * No need to do an explicit VOP_TRUNCATE here, vrele will
1441		 * do this for us because we set the link count to 0.
1442		 */
1443		ip->i_effnlink = 0;
1444		ip->i_nlink = 0;
1445		ip->i_flag |= IN_CHANGE;
1446		vput(tvp);
1447	}
1448out:
1449	zfree(namei_zone, cnp->cn_pnbuf);
1450	return (error);
1451}
1452
1453/*
1454 * Rmdir system call.
1455 */
1456int
1457ufs_rmdir(ap)
1458	struct vop_rmdir_args /* {
1459		struct vnode *a_dvp;
1460		struct vnode *a_vp;
1461		struct componentname *a_cnp;
1462	} */ *ap;
1463{
1464	struct vnode *vp = ap->a_vp;
1465	struct vnode *dvp = ap->a_dvp;
1466	struct componentname *cnp = ap->a_cnp;
1467	struct inode *ip, *dp;
1468	int error;
1469
1470	ip = VTOI(vp);
1471	dp = VTOI(dvp);
1472
1473	/*
1474	 * Do not remove a directory that is in the process of being renamed.
1475	 * Verify the directory is empty (and valid). Rmdir ".." will not be
1476	 * valid since ".." will contain a reference to the current directory
1477	 * and thus be non-empty. Do not allow the removal of mounted on
1478	 * directories (this can happen when an NFS exported filesystem
1479	 * tries to remove a locally mounted on directory).
1480	 */
1481	error = 0;
1482	if (ip->i_flag & IN_RENAME) {
1483		error = EINVAL;
1484		goto out;
1485	}
1486	if (ip->i_effnlink != 2 ||
1487	    !ufs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1488		error = ENOTEMPTY;
1489		goto out;
1490	}
1491	if ((dp->i_flags & APPEND)
1492	    || (ip->i_flags & (NOUNLINK | IMMUTABLE | APPEND))) {
1493		error = EPERM;
1494		goto out;
1495	}
1496	if (vp->v_mountedhere != 0) {
1497		error = EINVAL;
1498		goto out;
1499	}
1500	/*
1501	 * Delete reference to directory before purging
1502	 * inode.  If we crash in between, the directory
1503	 * will be reattached to lost+found,
1504	 */
1505	error = ufs_dirremove(dvp, ip, cnp->cn_flags, 1);
1506	if (error)
1507		goto out;
1508	VN_POLLEVENT(dvp, POLLWRITE|POLLNLINK);
1509	cache_purge(dvp);
1510	/*
1511	 * Truncate inode. The only stuff left in the directory is "." and
1512	 * "..". The "." reference is inconsequential since we are quashing
1513	 * it. We have removed the "." reference and the reference in the
1514	 * parent directory, but there may be other hard links. So,
1515	 * ufs_dirremove will set the UF_IMMUTABLE flag to ensure that no
1516	 * new entries are made. The soft dependency code will arrange to
1517	 * do these operations after the parent directory entry has been
1518	 * deleted on disk, so when running with that code we avoid doing
1519	 * them now.
1520	 */
1521	dp->i_effnlink--;
1522	dp->i_flag |= IN_CHANGE;
1523	ip->i_effnlink--;
1524	ip->i_flag |= IN_CHANGE;
1525	if (!DOINGSOFTDEP(vp)) {
1526		dp->i_nlink--;
1527		ip->i_nlink--;
1528		error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred,
1529		    cnp->cn_proc);
1530	}
1531	cache_purge(vp);
1532out:
1533	VN_POLLEVENT(vp, POLLNLINK);
1534	return (error);
1535}
1536
1537/*
1538 * symlink -- make a symbolic link
1539 */
1540int
1541ufs_symlink(ap)
1542	struct vop_symlink_args /* {
1543		struct vnode *a_dvp;
1544		struct vnode **a_vpp;
1545		struct componentname *a_cnp;
1546		struct vattr *a_vap;
1547		char *a_target;
1548	} */ *ap;
1549{
1550	register struct vnode *vp, **vpp = ap->a_vpp;
1551	register struct inode *ip;
1552	int len, error;
1553
1554	error = ufs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1555	    vpp, ap->a_cnp);
1556	if (error)
1557		return (error);
1558	VN_POLLEVENT(ap->a_dvp, POLLWRITE);
1559	vp = *vpp;
1560	len = strlen(ap->a_target);
1561	if (len < vp->v_mount->mnt_maxsymlinklen) {
1562		ip = VTOI(vp);
1563		bcopy(ap->a_target, (char *)ip->i_shortlink, len);
1564		ip->i_size = len;
1565		ip->i_flag |= IN_CHANGE | IN_UPDATE;
1566	} else
1567		error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1568		    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0,
1569		    (struct proc *)0);
1570	vput(vp);
1571	return (error);
1572}
1573
1574/*
1575 * Vnode op for reading directories.
1576 *
1577 * The routine below assumes that the on-disk format of a directory
1578 * is the same as that defined by <sys/dirent.h>. If the on-disk
1579 * format changes, then it will be necessary to do a conversion
1580 * from the on-disk format that read returns to the format defined
1581 * by <sys/dirent.h>.
1582 */
1583int
1584ufs_readdir(ap)
1585	struct vop_readdir_args /* {
1586		struct vnode *a_vp;
1587		struct uio *a_uio;
1588		struct ucred *a_cred;
1589		int *a_eofflag;
1590		int *ncookies;
1591		u_long **a_cookies;
1592	} */ *ap;
1593{
1594	register struct uio *uio = ap->a_uio;
1595	int error;
1596	size_t count, lost;
1597	off_t off;
1598
1599	if (ap->a_ncookies != NULL)
1600		/*
1601		 * Ensure that the block is aligned.  The caller can use
1602		 * the cookies to determine where in the block to start.
1603		 */
1604		uio->uio_offset &= ~(DIRBLKSIZ - 1);
1605	off = uio->uio_offset;
1606	count = uio->uio_resid;
1607	/* Make sure we don't return partial entries. */
1608	if (count <= ((uio->uio_offset + count) & (DIRBLKSIZ -1)))
1609		return (EINVAL);
1610	count -= (uio->uio_offset + count) & (DIRBLKSIZ -1);
1611	lost = uio->uio_resid - count;
1612	uio->uio_resid = count;
1613	uio->uio_iov->iov_len = count;
1614#	if (BYTE_ORDER == LITTLE_ENDIAN)
1615		if (ap->a_vp->v_mount->mnt_maxsymlinklen > 0) {
1616			error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
1617		} else {
1618			struct dirent *dp, *edp;
1619			struct uio auio;
1620			struct iovec aiov;
1621			caddr_t dirbuf;
1622			int readcnt;
1623			u_char tmp;
1624
1625			auio = *uio;
1626			auio.uio_iov = &aiov;
1627			auio.uio_iovcnt = 1;
1628			auio.uio_segflg = UIO_SYSSPACE;
1629			aiov.iov_len = count;
1630			MALLOC(dirbuf, caddr_t, count, M_TEMP, M_WAITOK);
1631			aiov.iov_base = dirbuf;
1632			error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred);
1633			if (error == 0) {
1634				readcnt = count - auio.uio_resid;
1635				edp = (struct dirent *)&dirbuf[readcnt];
1636				for (dp = (struct dirent *)dirbuf; dp < edp; ) {
1637					tmp = dp->d_namlen;
1638					dp->d_namlen = dp->d_type;
1639					dp->d_type = tmp;
1640					if (dp->d_reclen > 0) {
1641						dp = (struct dirent *)
1642						    ((char *)dp + dp->d_reclen);
1643					} else {
1644						error = EIO;
1645						break;
1646					}
1647				}
1648				if (dp >= edp)
1649					error = uiomove(dirbuf, readcnt, uio);
1650			}
1651			FREE(dirbuf, M_TEMP);
1652		}
1653#	else
1654		error = VOP_READ(ap->a_vp, uio, 0, ap->a_cred);
1655#	endif
1656	if (!error && ap->a_ncookies != NULL) {
1657		struct dirent* dpStart;
1658		struct dirent* dpEnd;
1659		struct dirent* dp;
1660		int ncookies;
1661		u_long *cookies;
1662		u_long *cookiep;
1663
1664		if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
1665			panic("ufs_readdir: unexpected uio from NFS server");
1666		dpStart = (struct dirent *)
1667		     (uio->uio_iov->iov_base - (uio->uio_offset - off));
1668		dpEnd = (struct dirent *) uio->uio_iov->iov_base;
1669		for (dp = dpStart, ncookies = 0;
1670		     dp < dpEnd;
1671		     dp = (struct dirent *)((caddr_t) dp + dp->d_reclen))
1672			ncookies++;
1673		MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
1674		    M_WAITOK);
1675		for (dp = dpStart, cookiep = cookies;
1676		     dp < dpEnd;
1677		     dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
1678			off += dp->d_reclen;
1679			*cookiep++ = (u_long) off;
1680		}
1681		*ap->a_ncookies = ncookies;
1682		*ap->a_cookies = cookies;
1683	}
1684	uio->uio_resid += lost;
1685	if (ap->a_eofflag)
1686	    *ap->a_eofflag = VTOI(ap->a_vp)->i_size <= uio->uio_offset;
1687	return (error);
1688}
1689
1690/*
1691 * Return target name of a symbolic link
1692 */
1693int
1694ufs_readlink(ap)
1695	struct vop_readlink_args /* {
1696		struct vnode *a_vp;
1697		struct uio *a_uio;
1698		struct ucred *a_cred;
1699	} */ *ap;
1700{
1701	register struct vnode *vp = ap->a_vp;
1702	register struct inode *ip = VTOI(vp);
1703	int isize;
1704
1705	isize = ip->i_size;
1706	if ((isize < vp->v_mount->mnt_maxsymlinklen) ||
1707	    (ip->i_din.di_blocks == 0)) {	/* XXX - for old fastlink support */
1708		uiomove((char *)ip->i_shortlink, isize, ap->a_uio);
1709		return (0);
1710	}
1711	return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1712}
1713
1714/*
1715 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
1716 * done. If a buffer has been saved in anticipation of a CREATE, delete it.
1717 */
1718/* ARGSUSED */
1719int
1720ufs_abortop(ap)
1721	struct vop_abortop_args /* {
1722		struct vnode *a_dvp;
1723		struct componentname *a_cnp;
1724	} */ *ap;
1725{
1726	if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
1727		zfree(namei_zone, ap->a_cnp->cn_pnbuf);
1728	return (0);
1729}
1730
1731/*
1732 * Calculate the logical to physical mapping if not done already,
1733 * then call the device strategy routine.
1734 *
1735 * In order to be able to swap to a file, the VOP_BMAP operation may not
1736 * deadlock on memory.  See ufs_bmap() for details.
1737 */
1738int
1739ufs_strategy(ap)
1740	struct vop_strategy_args /* {
1741		struct vnode *a_vp;
1742		struct buf *a_bp;
1743	} */ *ap;
1744{
1745	register struct buf *bp = ap->a_bp;
1746	register struct vnode *vp = ap->a_vp;
1747	register struct inode *ip;
1748	int error;
1749
1750	ip = VTOI(vp);
1751	if (vp->v_type == VBLK || vp->v_type == VCHR)
1752		panic("ufs_strategy: spec");
1753	if (bp->b_blkno == bp->b_lblkno) {
1754		error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL);
1755		if (error) {
1756			bp->b_error = error;
1757			bp->b_flags |= B_ERROR;
1758			biodone(bp);
1759			return (error);
1760		}
1761		if ((long)bp->b_blkno == -1)
1762			vfs_bio_clrbuf(bp);
1763	}
1764	if ((long)bp->b_blkno == -1) {
1765		biodone(bp);
1766		return (0);
1767	}
1768	vp = ip->i_devvp;
1769	bp->b_dev = vp->v_rdev;
1770	VOP_STRATEGY(vp, bp);
1771	return (0);
1772}
1773
1774/*
1775 * Print out the contents of an inode.
1776 */
1777int
1778ufs_print(ap)
1779	struct vop_print_args /* {
1780		struct vnode *a_vp;
1781	} */ *ap;
1782{
1783	register struct vnode *vp = ap->a_vp;
1784	register struct inode *ip = VTOI(vp);
1785
1786	printf("tag VT_UFS, ino %lu, on dev %#lx (%d, %d)",
1787	    (u_long)ip->i_number, (u_long)ip->i_dev, major(ip->i_dev),
1788	    minor(ip->i_dev));
1789	if (vp->v_type == VFIFO)
1790		fifo_printinfo(vp);
1791	lockmgr_printinfo(&ip->i_lock);
1792	printf("\n");
1793	return (0);
1794}
1795
1796/*
1797 * Read wrapper for special devices.
1798 */
1799int
1800ufsspec_read(ap)
1801	struct vop_read_args /* {
1802		struct vnode *a_vp;
1803		struct uio *a_uio;
1804		int  a_ioflag;
1805		struct ucred *a_cred;
1806	} */ *ap;
1807{
1808	int error, resid;
1809	struct inode *ip;
1810	struct uio *uio;
1811
1812	uio = ap->a_uio;
1813	resid = uio->uio_resid;
1814	error = VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap);
1815	/*
1816	 * The inode may have been revoked during the call, so it must not
1817	 * be accessed blindly here or in the other wrapper functions.
1818	 */
1819	ip = VTOI(ap->a_vp);
1820	if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
1821		ip->i_flag |= IN_ACCESS;
1822	return (error);
1823}
1824
1825/*
1826 * Write wrapper for special devices.
1827 */
1828int
1829ufsspec_write(ap)
1830	struct vop_write_args /* {
1831		struct vnode *a_vp;
1832		struct uio *a_uio;
1833		int  a_ioflag;
1834		struct ucred *a_cred;
1835	} */ *ap;
1836{
1837	int error, resid;
1838	struct inode *ip;
1839	struct uio *uio;
1840
1841	uio = ap->a_uio;
1842	resid = uio->uio_resid;
1843	error = VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap);
1844	ip = VTOI(ap->a_vp);
1845	if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
1846		VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1847	return (error);
1848}
1849
1850/*
1851 * Close wrapper for special devices.
1852 *
1853 * Update the times on the inode then do device close.
1854 */
1855int
1856ufsspec_close(ap)
1857	struct vop_close_args /* {
1858		struct vnode *a_vp;
1859		int  a_fflag;
1860		struct ucred *a_cred;
1861		struct proc *a_p;
1862	} */ *ap;
1863{
1864	struct vnode *vp = ap->a_vp;
1865
1866	simple_lock(&vp->v_interlock);
1867	if (vp->v_usecount > 1)
1868		ufs_itimes(vp);
1869	simple_unlock(&vp->v_interlock);
1870	return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap));
1871}
1872
1873/*
1874 * Read wrapper for fifos.
1875 */
1876int
1877ufsfifo_read(ap)
1878	struct vop_read_args /* {
1879		struct vnode *a_vp;
1880		struct uio *a_uio;
1881		int  a_ioflag;
1882		struct ucred *a_cred;
1883	} */ *ap;
1884{
1885	int error, resid;
1886	struct inode *ip;
1887	struct uio *uio;
1888
1889	uio = ap->a_uio;
1890	resid = uio->uio_resid;
1891	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap);
1892	ip = VTOI(ap->a_vp);
1893	if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL &&
1894	    (uio->uio_resid != resid || (error == 0 && resid != 0)))
1895		VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
1896	return (error);
1897}
1898
1899/*
1900 * Write wrapper for fifos.
1901 */
1902int
1903ufsfifo_write(ap)
1904	struct vop_write_args /* {
1905		struct vnode *a_vp;
1906		struct uio *a_uio;
1907		int  a_ioflag;
1908		struct ucred *a_cred;
1909	} */ *ap;
1910{
1911	int error, resid;
1912	struct inode *ip;
1913	struct uio *uio;
1914
1915	uio = ap->a_uio;
1916	resid = uio->uio_resid;
1917	error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap);
1918	ip = VTOI(ap->a_vp);
1919	if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0)))
1920		VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE;
1921	return (error);
1922}
1923
1924/*
1925 * Close wrapper for fifos.
1926 *
1927 * Update the times on the inode then do device close.
1928 */
1929int
1930ufsfifo_close(ap)
1931	struct vop_close_args /* {
1932		struct vnode *a_vp;
1933		int  a_fflag;
1934		struct ucred *a_cred;
1935		struct proc *a_p;
1936	} */ *ap;
1937{
1938	struct vnode *vp = ap->a_vp;
1939
1940	simple_lock(&vp->v_interlock);
1941	if (vp->v_usecount > 1)
1942		ufs_itimes(vp);
1943	simple_unlock(&vp->v_interlock);
1944	return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
1945}
1946
1947/*
1948 * Return POSIX pathconf information applicable to ufs filesystems.
1949 */
1950int
1951ufs_pathconf(ap)
1952	struct vop_pathconf_args /* {
1953		struct vnode *a_vp;
1954		int a_name;
1955		int *a_retval;
1956	} */ *ap;
1957{
1958
1959	switch (ap->a_name) {
1960	case _PC_LINK_MAX:
1961		*ap->a_retval = LINK_MAX;
1962		return (0);
1963	case _PC_NAME_MAX:
1964		*ap->a_retval = NAME_MAX;
1965		return (0);
1966	case _PC_PATH_MAX:
1967		*ap->a_retval = PATH_MAX;
1968		return (0);
1969	case _PC_PIPE_BUF:
1970		*ap->a_retval = PIPE_BUF;
1971		return (0);
1972	case _PC_CHOWN_RESTRICTED:
1973		*ap->a_retval = 1;
1974		return (0);
1975	case _PC_NO_TRUNC:
1976		*ap->a_retval = 1;
1977		return (0);
1978	default:
1979		return (EINVAL);
1980	}
1981	/* NOTREACHED */
1982}
1983
1984/*
1985 * Advisory record locking support
1986 */
1987int
1988ufs_advlock(ap)
1989	struct vop_advlock_args /* {
1990		struct vnode *a_vp;
1991		caddr_t  a_id;
1992		int  a_op;
1993		struct flock *a_fl;
1994		int  a_flags;
1995	} */ *ap;
1996{
1997	register struct inode *ip = VTOI(ap->a_vp);
1998
1999	return (lf_advlock(ap, &(ip->i_lockf), ip->i_size));
2000}
2001
2002/*
2003 * Initialize the vnode associated with a new inode, handle aliased
2004 * vnodes.
2005 */
2006int
2007ufs_vinit(mntp, specops, fifoops, vpp)
2008	struct mount *mntp;
2009	vop_t **specops;
2010	vop_t **fifoops;
2011	struct vnode **vpp;
2012{
2013	struct inode *ip;
2014	struct vnode *vp, *nvp;
2015	struct timeval tv;
2016
2017	vp = *vpp;
2018	ip = VTOI(vp);
2019	switch(vp->v_type = IFTOVT(ip->i_mode)) {
2020	case VCHR:
2021	case VBLK:
2022		vp->v_op = specops;
2023		nvp = checkalias(vp, ip->i_rdev, mntp);
2024		if (nvp) {
2025			/*
2026			 * Discard unneeded vnode, but save its inode.
2027			 * Note that the lock is carried over in the inode
2028			 * to the replacement vnode.
2029			 */
2030			nvp->v_data = vp->v_data;
2031			vp->v_data = NULL;
2032			vp->v_op = spec_vnodeop_p;
2033			vrele(vp);
2034			vgone(vp);
2035			/*
2036			 * Reinitialize aliased inode.
2037			 */
2038			vp = nvp;
2039			ip->i_vnode = vp;
2040		}
2041		break;
2042	case VFIFO:
2043		vp->v_op = fifoops;
2044		break;
2045	default:
2046		break;
2047
2048	}
2049	if (ip->i_number == ROOTINO)
2050		vp->v_flag |= VROOT;
2051	/*
2052	 * Initialize modrev times
2053	 */
2054	getmicrouptime(&tv);
2055	SETHIGH(ip->i_modrev, tv.tv_sec);
2056	SETLOW(ip->i_modrev, tv.tv_usec * 4294);
2057	*vpp = vp;
2058	return (0);
2059}
2060
2061/*
2062 * Allocate a new inode.
2063 */
2064int
2065ufs_makeinode(mode, dvp, vpp, cnp)
2066	int mode;
2067	struct vnode *dvp;
2068	struct vnode **vpp;
2069	struct componentname *cnp;
2070{
2071	register struct inode *ip, *pdir;
2072	struct direct newdir;
2073	struct vnode *tvp;
2074	int error;
2075
2076	pdir = VTOI(dvp);
2077#ifdef DIAGNOSTIC
2078	if ((cnp->cn_flags & HASBUF) == 0)
2079		panic("ufs_makeinode: no name");
2080#endif
2081	*vpp = NULL;
2082	if ((mode & IFMT) == 0)
2083		mode |= IFREG;
2084
2085	error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp);
2086	if (error) {
2087		zfree(namei_zone, cnp->cn_pnbuf);
2088		return (error);
2089	}
2090	ip = VTOI(tvp);
2091	ip->i_gid = pdir->i_gid;
2092#ifdef SUIDDIR
2093	{
2094#ifdef QUOTA
2095		struct ucred ucred, *ucp;
2096		ucp = cnp->cn_cred;
2097#endif			I
2098		/*
2099		 * If we are not the owner of the directory,
2100		 * and we are hacking owners here, (only do this where told to)
2101		 * and we are not giving it TOO root, (would subvert quotas)
2102		 * then go ahead and give it to the other user.
2103		 * Note that this drops off the execute bits for security.
2104		 */
2105		if ((dvp->v_mount->mnt_flag & MNT_SUIDDIR) &&
2106		    (pdir->i_mode & ISUID) &&
2107		    (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) {
2108			ip->i_uid = pdir->i_uid;
2109			mode &= ~07111;
2110#ifdef QUOTA
2111			/*
2112			 * Make sure the correct user gets charged
2113			 * for the space.
2114			 * Quickly knock up a dummy credential for the victim.
2115			 * XXX This seems to never be accessed out of our
2116			 * context so a stack variable is ok.
2117			 */
2118			ucred.cr_ref = 1;
2119			ucred.cr_uid = ip->i_uid;
2120			ucred.cr_ngroups = 1;
2121			ucred.cr_groups[0] = pdir->i_gid;
2122			ucp = &ucred;
2123#endif
2124		} else
2125			ip->i_uid = cnp->cn_cred->cr_uid;
2126
2127#ifdef QUOTA
2128		if ((error = getinoquota(ip)) ||
2129	    	    (error = chkiq(ip, 1, ucp, 0))) {
2130			zfree(namei_zone, cnp->cn_pnbuf);
2131			UFS_VFREE(tvp, ip->i_number, mode);
2132			vput(tvp);
2133			return (error);
2134		}
2135#endif
2136	}
2137#else	/* !SUIDDIR */
2138	ip->i_uid = cnp->cn_cred->cr_uid;
2139#ifdef QUOTA
2140	if ((error = getinoquota(ip)) ||
2141	    (error = chkiq(ip, 1, cnp->cn_cred, 0))) {
2142		zfree(namei_zone, cnp->cn_pnbuf);
2143		UFS_VFREE(tvp, ip->i_number, mode);
2144		vput(tvp);
2145		return (error);
2146	}
2147#endif
2148#endif	/* !SUIDDIR */
2149	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
2150	ip->i_mode = mode;
2151	tvp->v_type = IFTOVT(mode);	/* Rest init'd in getnewvnode(). */
2152	ip->i_effnlink = 1;
2153	ip->i_nlink = 1;
2154	if (DOINGSOFTDEP(tvp))
2155		softdep_increase_linkcnt(ip);
2156	if ((ip->i_mode & ISGID) && !groupmember(ip->i_gid, cnp->cn_cred) &&
2157	    suser(cnp->cn_cred, NULL))
2158		ip->i_mode &= ~ISGID;
2159
2160	if (cnp->cn_flags & ISWHITEOUT)
2161		ip->i_flags |= UF_OPAQUE;
2162
2163	/*
2164	 * Make sure inode goes to disk before directory entry.
2165	 */
2166	error = UFS_UPDATE(tvp, !DOINGSOFTDEP(tvp));
2167	if (error)
2168		goto bad;
2169	ufs_makedirentry(ip, cnp, &newdir);
2170	error = ufs_direnter(dvp, tvp, &newdir, cnp, NULL);
2171	if (error)
2172		goto bad;
2173
2174	if ((cnp->cn_flags & SAVESTART) == 0)
2175		zfree(namei_zone, cnp->cn_pnbuf);
2176	*vpp = tvp;
2177	return (0);
2178
2179bad:
2180	/*
2181	 * Write error occurred trying to update the inode
2182	 * or the directory so must deallocate the inode.
2183	 */
2184	zfree(namei_zone, cnp->cn_pnbuf);
2185	ip->i_effnlink = 0;
2186	ip->i_nlink = 0;
2187	ip->i_flag |= IN_CHANGE;
2188	vput(tvp);
2189	return (error);
2190}
2191
2192static int
2193ufs_missingop(ap)
2194	struct vop_generic_args *ap;
2195{
2196
2197	panic("no vop function for %s in ufs child", ap->a_desc->vdesc_name);
2198	return (EOPNOTSUPP);
2199}
2200
2201/* Global vfs data structures for ufs. */
2202static vop_t **ufs_vnodeop_p;
2203static struct vnodeopv_entry_desc ufs_vnodeop_entries[] = {
2204	{ &vop_default_desc,		(vop_t *) vop_defaultop },
2205	{ &vop_fsync_desc,		(vop_t *) ufs_missingop },
2206	{ &vop_read_desc,		(vop_t *) ufs_missingop },
2207	{ &vop_reallocblks_desc,	(vop_t *) ufs_missingop },
2208	{ &vop_write_desc,		(vop_t *) ufs_missingop },
2209	{ &vop_abortop_desc,		(vop_t *) ufs_abortop },
2210	{ &vop_access_desc,		(vop_t *) ufs_access },
2211	{ &vop_advlock_desc,		(vop_t *) ufs_advlock },
2212	{ &vop_bmap_desc,		(vop_t *) ufs_bmap },
2213	{ &vop_cachedlookup_desc,	(vop_t *) ufs_lookup },
2214	{ &vop_close_desc,		(vop_t *) ufs_close },
2215	{ &vop_create_desc,		(vop_t *) ufs_create },
2216	{ &vop_getattr_desc,		(vop_t *) ufs_getattr },
2217	{ &vop_inactive_desc,		(vop_t *) ufs_inactive },
2218	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
2219	{ &vop_link_desc,		(vop_t *) ufs_link },
2220	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
2221	{ &vop_lookup_desc,		(vop_t *) vfs_cache_lookup },
2222	{ &vop_mkdir_desc,		(vop_t *) ufs_mkdir },
2223	{ &vop_mknod_desc,		(vop_t *) ufs_mknod },
2224	{ &vop_mmap_desc,		(vop_t *) ufs_mmap },
2225	{ &vop_open_desc,		(vop_t *) ufs_open },
2226	{ &vop_pathconf_desc,		(vop_t *) ufs_pathconf },
2227	{ &vop_poll_desc,		(vop_t *) vop_stdpoll },
2228	{ &vop_print_desc,		(vop_t *) ufs_print },
2229	{ &vop_readdir_desc,		(vop_t *) ufs_readdir },
2230	{ &vop_readlink_desc,		(vop_t *) ufs_readlink },
2231	{ &vop_reclaim_desc,		(vop_t *) ufs_reclaim },
2232	{ &vop_remove_desc,		(vop_t *) ufs_remove },
2233	{ &vop_rename_desc,		(vop_t *) ufs_rename },
2234	{ &vop_rmdir_desc,		(vop_t *) ufs_rmdir },
2235	{ &vop_setattr_desc,		(vop_t *) ufs_setattr },
2236	{ &vop_strategy_desc,		(vop_t *) ufs_strategy },
2237	{ &vop_symlink_desc,		(vop_t *) ufs_symlink },
2238	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
2239	{ &vop_whiteout_desc,		(vop_t *) ufs_whiteout },
2240	{ NULL, NULL }
2241};
2242static struct vnodeopv_desc ufs_vnodeop_opv_desc =
2243	{ &ufs_vnodeop_p, ufs_vnodeop_entries };
2244
2245static vop_t **ufs_specop_p;
2246static struct vnodeopv_entry_desc ufs_specop_entries[] = {
2247	{ &vop_default_desc,		(vop_t *) spec_vnoperate },
2248	{ &vop_fsync_desc,		(vop_t *) ufs_missingop },
2249	{ &vop_access_desc,		(vop_t *) ufs_access },
2250	{ &vop_close_desc,		(vop_t *) ufsspec_close },
2251	{ &vop_getattr_desc,		(vop_t *) ufs_getattr },
2252	{ &vop_inactive_desc,		(vop_t *) ufs_inactive },
2253	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
2254	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
2255	{ &vop_print_desc,		(vop_t *) ufs_print },
2256	{ &vop_read_desc,		(vop_t *) ufsspec_read },
2257	{ &vop_reclaim_desc,		(vop_t *) ufs_reclaim },
2258	{ &vop_setattr_desc,		(vop_t *) ufs_setattr },
2259	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
2260	{ &vop_write_desc,		(vop_t *) ufsspec_write },
2261	{ NULL, NULL }
2262};
2263static struct vnodeopv_desc ufs_specop_opv_desc =
2264	{ &ufs_specop_p, ufs_specop_entries };
2265
2266static vop_t **ufs_fifoop_p;
2267static struct vnodeopv_entry_desc ufs_fifoop_entries[] = {
2268	{ &vop_default_desc,		(vop_t *) fifo_vnoperate },
2269	{ &vop_fsync_desc,		(vop_t *) ufs_missingop },
2270	{ &vop_access_desc,		(vop_t *) ufs_access },
2271	{ &vop_close_desc,		(vop_t *) ufsfifo_close },
2272	{ &vop_getattr_desc,		(vop_t *) ufs_getattr },
2273	{ &vop_inactive_desc,		(vop_t *) ufs_inactive },
2274	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
2275	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
2276	{ &vop_print_desc,		(vop_t *) ufs_print },
2277	{ &vop_read_desc,		(vop_t *) ufsfifo_read },
2278	{ &vop_reclaim_desc,		(vop_t *) ufs_reclaim },
2279	{ &vop_setattr_desc,		(vop_t *) ufs_setattr },
2280	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
2281	{ &vop_write_desc,		(vop_t *) ufsfifo_write },
2282	{ NULL, NULL }
2283};
2284static struct vnodeopv_desc ufs_fifoop_opv_desc =
2285	{ &ufs_fifoop_p, ufs_fifoop_entries };
2286
2287VNODEOP_SET(ufs_vnodeop_opv_desc);
2288VNODEOP_SET(ufs_specop_opv_desc);
2289VNODEOP_SET(ufs_fifoop_opv_desc);
2290
2291int
2292ufs_vnoperate(ap)
2293	struct vop_generic_args /* {
2294		struct vnodeop_desc *a_desc;
2295	} */ *ap;
2296{
2297	return (VOCALL(ufs_vnodeop_p, ap->a_desc->vdesc_offset, ap));
2298}
2299
2300int
2301ufs_vnoperatefifo(ap)
2302	struct vop_generic_args /* {
2303		struct vnodeop_desc *a_desc;
2304	} */ *ap;
2305{
2306	return (VOCALL(ufs_fifoop_p, ap->a_desc->vdesc_offset, ap));
2307}
2308
2309int
2310ufs_vnoperatespec(ap)
2311	struct vop_generic_args /* {
2312		struct vnodeop_desc *a_desc;
2313	} */ *ap;
2314{
2315	return (VOCALL(ufs_specop_p, ap->a_desc->vdesc_offset, ap));
2316}
2317
2318
2319