1 /*	$OpenBSD: ext2fs_vnops.c,v 1.41 2005/08/14 12:41:44 pedro Exp $	*/
2 /*	$NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $	*/
3 
4 /*
5  * Copyright (c) 1997 Manuel Bouyer.
6  * Copyright (c) 1982, 1986, 1989, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  * (c) UNIX System Laboratories, Inc.
9  * All or some portions of this file are derived from material licensed
10  * to the University of California by American Telephone and Telegraph
11  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
12  * the permission of UNIX System Laboratories, Inc.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)ufs_vnops.c	8.14 (Berkeley) 10/26/94
39  * Modified for ext2fs by Manuel Bouyer.
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/resourcevar.h>
45 #include <sys/kernel.h>
46 #include <sys/file.h>
47 #include <sys/stat.h>
48 #include <sys/buf.h>
49 #include <sys/proc.h>
50 #include <sys/conf.h>
51 #include <sys/mount.h>
52 #include <sys/namei.h>
53 #include <sys/vnode.h>
54 #include <sys/lockf.h>
55 #include <sys/malloc.h>
56 #include <sys/pool.h>
57 #include <sys/signalvar.h>
58 
59 #include <uvm/uvm_extern.h>
60 
61 #include <miscfs/fifofs/fifo.h>
62 #include <miscfs/specfs/specdev.h>
63 
64 #include <ufs/ufs/quota.h>
65 #include <ufs/ufs/inode.h>
66 #include <ufs/ufs/ufs_extern.h>
67 #include <ufs/ufs/ufsmount.h>
68 
69 #include <ufs/ext2fs/ext2fs.h>
70 #include <ufs/ext2fs/ext2fs_extern.h>
71 #include <ufs/ext2fs/ext2fs_dir.h>
72 
73 
74 static int ext2fs_chmod(struct vnode *, mode_t, struct ucred *, struct proc *);
75 static int ext2fs_chown(struct vnode *, uid_t, gid_t, struct ucred *, struct proc *);
76 
77 union _qcvt {
78 	int64_t	qcvt;
79 	int32_t val[2];
80 };
81 #define SETHIGH(q, h) { \
82 	union _qcvt tmp; \
83 	tmp.qcvt = (q); \
84 	tmp.val[_QUAD_HIGHWORD] = (h); \
85 	(q) = tmp.qcvt; \
86 }
87 #define SETLOW(q, l) { \
88 	union _qcvt tmp; \
89 	tmp.qcvt = (q); \
90 	tmp.val[_QUAD_LOWWORD] = (l); \
91 	(q) = tmp.qcvt; \
92 }
93 
94 /*
95  * Create a regular file
96  */
97 int
ext2fs_create(v)98 ext2fs_create(v)
99 	void *v;
100 {
101 	struct vop_create_args /* {
102 		struct vnode *a_dvp;
103 		struct vnode **a_vpp;
104 		struct componentname *a_cnp;
105 		struct vattr *a_vap;
106 	} */ *ap = v;
107 	return ext2fs_makeinode(MAKEIMODE(ap->a_vap->va_type,
108 					  ap->a_vap->va_mode),
109 			  	ap->a_dvp, ap->a_vpp, ap->a_cnp);
110 }
111 
112 /*
113  * Mknod vnode call
114  */
115 /* ARGSUSED */
116 int
ext2fs_mknod(v)117 ext2fs_mknod(v)
118 	void *v;
119 {
120 	struct vop_mknod_args /* {
121 		struct vnode *a_dvp;
122 		struct vnode **a_vpp;
123 		struct componentname *a_cnp;
124 		struct vattr *a_vap;
125 	} */ *ap = v;
126 	register struct vattr *vap = ap->a_vap;
127 	register struct vnode **vpp = ap->a_vpp;
128 	register struct inode *ip;
129 	int error;
130 
131 	if ((error =
132 		ext2fs_makeinode(MAKEIMODE(vap->va_type, vap->va_mode),
133 		ap->a_dvp, vpp, ap->a_cnp)) != 0)
134 		return (error);
135 	ip = VTOI(*vpp);
136 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
137 	if (vap->va_rdev != VNOVAL) {
138 		/*
139 		 * Want to be able to use this to make badblock
140 		 * inodes, so don't truncate the dev number.
141 		 */
142 		ip->i_e2din.e2di_rdev = h2fs32(vap->va_rdev);
143 	}
144 	/*
145 	 * Remove inode so that it will be reloaded by VFS_VGET and
146 	 * checked to see if it is an alias of an existing entry in
147 	 * the inode cache.
148 	 */
149 	vput(*vpp);
150 	(*vpp)->v_type = VNON;
151 	vgone(*vpp);
152 	*vpp = 0;
153 	return (0);
154 }
155 
156 /*
157  * Open called.
158  *
159  * Just check the APPEND flag.
160  */
161 /* ARGSUSED */
162 int
ext2fs_open(v)163 ext2fs_open(v)
164 	void *v;
165 {
166 	struct vop_open_args /* {
167 		struct vnode *a_vp;
168 		int  a_mode;
169 		struct ucred *a_cred;
170 		struct proc *a_p;
171 	} */ *ap = v;
172 
173 	/*
174 	 * Files marked append-only must be opened for appending.
175 	 */
176 	if ((VTOI(ap->a_vp)->i_e2fs_flags & EXT2_APPEND) &&
177 		(ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
178 		return (EPERM);
179 	return (0);
180 }
181 
182 int
ext2fs_access(v)183 ext2fs_access(v)
184 	void *v;
185 {
186 	struct vop_access_args /* {
187 		struct vnode *a_vp;
188 		int  a_mode;
189 		struct ucred *a_cred;
190 		struct proc *a_p;
191 	} */ *ap = v;
192 	register struct vnode *vp = ap->a_vp;
193 	register struct inode *ip = VTOI(vp);
194 	mode_t mode = ap->a_mode;
195 
196 	/* If immutable bit set, nobody gets to write it. */
197 	if ((mode & VWRITE) && (ip->i_e2fs_flags & EXT2_IMMUTABLE))
198 		return (EPERM);
199 
200 	return (vaccess(ip->i_e2fs_mode, ip->i_e2fs_uid, ip->i_e2fs_gid, mode,
201 			ap->a_cred));
202 }
203 
204 /* ARGSUSED */
205 int
ext2fs_getattr(v)206 ext2fs_getattr(v)
207 	void *v;
208 {
209 	struct vop_getattr_args /* {
210 		struct vnode *a_vp;
211 		struct vattr *a_vap;
212 		struct ucred *a_cred;
213 		struct proc *a_p;
214 	} */ *ap = v;
215 	register struct vnode *vp = ap->a_vp;
216 	register struct inode *ip = VTOI(vp);
217 	register struct vattr *vap = ap->a_vap;
218 
219 	EXT2FS_ITIMES(ip, &time, &time);
220 	/*
221 	 * Copy from inode table
222 	 */
223 	vap->va_fsid = ip->i_dev;
224 	vap->va_fileid = ip->i_number;
225 	vap->va_mode = ip->i_e2fs_mode & ALLPERMS;
226 	vap->va_nlink = ip->i_e2fs_nlink;
227 	vap->va_uid = ip->i_e2fs_uid;
228 	vap->va_gid = ip->i_e2fs_gid;
229 	vap->va_rdev = (dev_t)fs2h32(ip->i_e2din.e2di_rdev);
230 	vap->va_size = ext2fs_size(ip);
231 	vap->va_atime.tv_sec = ip->i_e2fs_atime;
232 	vap->va_atime.tv_nsec = 0;
233 	vap->va_mtime.tv_sec = ip->i_e2fs_mtime;
234 	vap->va_mtime.tv_nsec = 0;
235 	vap->va_ctime.tv_sec = ip->i_e2fs_ctime;
236 	vap->va_ctime.tv_nsec = 0;
237 #ifdef EXT2FS_SYSTEM_FLAGS
238 	vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? SF_APPEND : 0;
239 	vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? SF_IMMUTABLE : 0;
240 #else
241 	vap->va_flags = (ip->i_e2fs_flags & EXT2_APPEND) ? UF_APPEND : 0;
242 	vap->va_flags |= (ip->i_e2fs_flags & EXT2_IMMUTABLE) ? UF_IMMUTABLE : 0;
243 #endif
244 	vap->va_gen = ip->i_e2fs_gen;
245 	/* this doesn't belong here */
246 	if (vp->v_type == VBLK)
247 		vap->va_blocksize = BLKDEV_IOSIZE;
248 	else if (vp->v_type == VCHR)
249 		vap->va_blocksize = MAXBSIZE;
250 	else
251 		vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize;
252 	vap->va_bytes = dbtob((u_quad_t)ip->i_e2fs_nblock);
253 	vap->va_type = vp->v_type;
254 	vap->va_filerev = ip->i_modrev;
255 	return (0);
256 }
257 
258 /*
259  * Set attribute vnode op. called from several syscalls
260  */
261 int
ext2fs_setattr(v)262 ext2fs_setattr(v)
263 	void *v;
264 {
265 	struct vop_setattr_args /* {
266 		struct vnode *a_vp;
267 		struct vattr *a_vap;
268 		struct ucred *a_cred;
269 		struct proc *a_p;
270 	} */ *ap = v;
271 	register struct vattr *vap = ap->a_vap;
272 	register struct vnode *vp = ap->a_vp;
273 	register struct inode *ip = VTOI(vp);
274 	register struct ucred *cred = ap->a_cred;
275 	register struct proc *p = ap->a_p;
276 	int error;
277 
278 	/*
279 	 * Check for unsettable attributes.
280 	 */
281 	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
282 		(vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
283 		(vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
284 		((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
285 		return (EINVAL);
286 	}
287 	if (vap->va_flags != VNOVAL) {
288 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
289 			return (EROFS);
290 		if (cred->cr_uid != ip->i_e2fs_uid &&
291 			(error = suser_ucred(cred)))
292 			return (error);
293 #ifdef EXT2FS_SYSTEM_FLAGS
294 		if (cred->cr_uid == 0) {
295 			if ((ip->i_e2fs_flags &
296 			    (EXT2_APPEND | EXT2_IMMUTABLE)) && securelevel > 0)
297 				return (EPERM);
298 			ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
299 			ip->i_e2fs_flags |=
300 			    (vap->va_flags & SF_APPEND) ? EXT2_APPEND : 0 |
301 			    (vap->va_flags & SF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
302 		} else {
303 			return (EPERM);
304 		}
305 #else
306 		ip->i_e2fs_flags &= ~(EXT2_APPEND | EXT2_IMMUTABLE);
307 		ip->i_e2fs_flags |=
308 		    (vap->va_flags & UF_APPEND) ? EXT2_APPEND : 0 |
309 		    (vap->va_flags & UF_IMMUTABLE) ? EXT2_IMMUTABLE: 0;
310 #endif
311 		ip->i_flag |= IN_CHANGE;
312 		if (vap->va_flags & (IMMUTABLE | APPEND))
313 			return (0);
314 	}
315 	if (ip->i_e2fs_flags & (EXT2_APPEND | EXT2_IMMUTABLE))
316 		return (EPERM);
317 	/*
318 	 * Go through the fields and update iff not VNOVAL.
319 	 */
320 	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
321 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
322 			return (EROFS);
323 		error = ext2fs_chown(vp, vap->va_uid, vap->va_gid, cred, p);
324 		if (error)
325 			return (error);
326 	}
327 	if (vap->va_size != VNOVAL) {
328 		/*
329 		 * Disallow write attempts on read-only file systems;
330 		 * unless the file is a socket, fifo, or a block or
331 		 * character device resident on the file system.
332 		 */
333 		switch (vp->v_type) {
334 		case VDIR:
335 			return (EISDIR);
336 		case VLNK:
337 		case VREG:
338 			if (vp->v_mount->mnt_flag & MNT_RDONLY)
339 				return (EROFS);
340 		default:
341 			break;
342 		}
343 		error = ext2fs_truncate(ip, vap->va_size, 0, cred);
344 		if (error)
345 			return (error);
346 	}
347 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
348 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
349 			return (EROFS);
350 		if (cred->cr_uid != ip->i_e2fs_uid &&
351 			(error = suser_ucred(cred)) &&
352 			((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
353 			(error = VOP_ACCESS(vp, VWRITE, cred, p))))
354 			return (error);
355 		if (vap->va_atime.tv_sec != VNOVAL)
356 			if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
357 				ip->i_flag |= IN_ACCESS;
358 		if (vap->va_mtime.tv_sec != VNOVAL)
359 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
360 		error = ext2fs_update(ip, &vap->va_atime, &vap->va_mtime, 1);
361 		if (error)
362 			return (error);
363 	}
364 	error = 0;
365 	if (vap->va_mode != (mode_t)VNOVAL) {
366 		if (vp->v_mount->mnt_flag & MNT_RDONLY)
367 			return (EROFS);
368 		error = ext2fs_chmod(vp, (int)vap->va_mode, cred, p);
369 	}
370 	return (error);
371 }
372 
373 /*
374  * Change the mode on a file.
375  * Inode must be locked before calling.
376  */
377 static int
ext2fs_chmod(vp,mode,cred,p)378 ext2fs_chmod(vp, mode, cred, p)
379 	register struct vnode *vp;
380 	register mode_t mode;
381 	register struct ucred *cred;
382 	struct proc *p;
383 {
384 	register struct inode *ip = VTOI(vp);
385 	int error;
386 
387 	if (cred->cr_uid != ip->i_e2fs_uid && (error = suser_ucred(cred)))
388 		return (error);
389 	if (cred->cr_uid) {
390 		if (vp->v_type != VDIR && (mode & S_ISTXT))
391 			return (EFTYPE);
392 		if (!groupmember(ip->i_e2fs_gid, cred) && (mode & ISGID))
393 			return (EPERM);
394 	}
395 	ip->i_e2fs_mode &= ~ALLPERMS;
396 	ip->i_e2fs_mode |= (mode & ALLPERMS);
397 	ip->i_flag |= IN_CHANGE;
398 	if ((vp->v_flag & VTEXT) && (ip->i_e2fs_mode & S_ISTXT) == 0)
399 		(void) uvm_vnp_uncache(vp);
400 	return (0);
401 }
402 
403 /*
404  * Perform chown operation on inode ip;
405  * inode must be locked prior to call.
406  */
407 static int
ext2fs_chown(vp,uid,gid,cred,p)408 ext2fs_chown(vp, uid, gid, cred, p)
409 	register struct vnode *vp;
410 	uid_t uid;
411 	gid_t gid;
412 	struct ucred *cred;
413 	struct proc *p;
414 {
415 	register struct inode *ip = VTOI(vp);
416 	uid_t ouid;
417 	gid_t ogid;
418 	int error = 0;
419 
420 	if (uid == (uid_t)VNOVAL)
421 		uid = ip->i_e2fs_uid;
422 	if (gid == (gid_t)VNOVAL)
423 		gid = ip->i_e2fs_gid;
424 	/*
425 	 * If we don't own the file, are trying to change the owner
426 	 * of the file, or are not a member of the target group,
427 	 * the caller must be superuser or the call fails.
428 	 */
429 	if ((cred->cr_uid != ip->i_e2fs_uid || uid != ip->i_e2fs_uid ||
430 		(gid != ip->i_e2fs_gid && !groupmember((gid_t)gid, cred))) &&
431 		(error = suser_ucred(cred)))
432 		return (error);
433 	ogid = ip->i_e2fs_gid;
434 	ouid = ip->i_e2fs_uid;
435 
436 	ip->i_e2fs_gid = gid;
437 	ip->i_e2fs_uid = uid;
438 	if (ouid != uid || ogid != gid)
439 		ip->i_flag |= IN_CHANGE;
440 	if (ouid != uid && cred->cr_uid != 0)
441 		ip->i_e2fs_mode &= ~ISUID;
442 	if (ogid != gid && cred->cr_uid != 0)
443 		ip->i_e2fs_mode &= ~ISGID;
444 	return (0);
445 }
446 
447 int
ext2fs_remove(v)448 ext2fs_remove(v)
449 	void *v;
450 {
451 	struct vop_remove_args /* {
452 		struct vnode *a_dvp;
453 		struct vnode *a_vp;
454 		struct componentname *a_cnp;
455 	} */ *ap = v;
456 	register struct inode *ip;
457 	register struct vnode *vp = ap->a_vp;
458 	register struct vnode *dvp = ap->a_dvp;
459 	int error;
460 
461 	ip = VTOI(vp);
462 	if (vp->v_type == VDIR ||
463 		(ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
464 	    	(VTOI(dvp)->i_e2fs_flags & EXT2_APPEND)) {
465 		error = EPERM;
466 		goto out;
467 	}
468 	error = ext2fs_dirremove(dvp, ap->a_cnp);
469 	if (error == 0) {
470 		ip->i_e2fs_nlink--;
471 		ip->i_flag |= IN_CHANGE;
472 	}
473 out:
474 	if (dvp == vp)
475 		vrele(vp);
476 	else
477 		vput(vp);
478 	vput(dvp);
479 	return (error);
480 }
481 
482 /*
483  * link vnode call
484  */
485 int
ext2fs_link(v)486 ext2fs_link(v)
487 	void *v;
488 {
489 	struct vop_link_args /* {
490 		struct vnode *a_dvp;
491 		struct vnode *a_vp;
492 		struct componentname *a_cnp;
493 	} */ *ap = v;
494 	register struct vnode *dvp = ap->a_dvp;
495 	register struct vnode *vp = ap->a_vp;
496 	register struct componentname *cnp = ap->a_cnp;
497 	struct proc *p = cnp->cn_proc;
498 	register struct inode *ip;
499 	int error;
500 
501 #ifdef DIAGNOSTIC
502 	if ((cnp->cn_flags & HASBUF) == 0)
503 		panic("ext2fs_link: no name");
504 #endif
505 	if (vp->v_type == VDIR) {
506 		VOP_ABORTOP(dvp, cnp);
507 		error = EISDIR;
508 		goto out2;
509 	}
510 	if (dvp->v_mount != vp->v_mount) {
511 		VOP_ABORTOP(dvp, cnp);
512 		error = EXDEV;
513 		goto out2;
514 	}
515 	if (dvp != vp && (error = vn_lock(vp, LK_EXCLUSIVE, p))) {
516 		VOP_ABORTOP(dvp, cnp);
517 		goto out2;
518 	}
519 	ip = VTOI(vp);
520 	if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
521 		VOP_ABORTOP(dvp, cnp);
522 		error = EMLINK;
523 		goto out1;
524 	}
525 	if (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) {
526 		VOP_ABORTOP(dvp, cnp);
527 		error = EPERM;
528 		goto out1;
529 	}
530 	ip->i_e2fs_nlink++;
531 	ip->i_flag |= IN_CHANGE;
532 	error = ext2fs_update(ip, NULL, NULL, 1);
533 	if (!error)
534 		error = ext2fs_direnter(ip, dvp, cnp);
535 	if (error) {
536 		ip->i_e2fs_nlink--;
537 		ip->i_flag |= IN_CHANGE;
538 	}
539 	pool_put(&namei_pool, cnp->cn_pnbuf);
540 out1:
541 	if (dvp != vp)
542 		VOP_UNLOCK(vp, 0, p);
543 out2:
544 	vput(dvp);
545 	return (error);
546 }
547 
548 /*
549  * Rename system call.
550  * 	rename("foo", "bar");
551  * is essentially
552  *	unlink("bar");
553  *	link("foo", "bar");
554  *	unlink("foo");
555  * but ``atomically''.  Can't do full commit without saving state in the
556  * inode on disk which isn't feasible at this time.  Best we can do is
557  * always guarantee the target exists.
558  *
559  * Basic algorithm is:
560  *
561  * 1) Bump link count on source while we're linking it to the
562  *    target.  This also ensure the inode won't be deleted out
563  *    from underneath us while we work (it may be truncated by
564  *    a concurrent `trunc' or `open' for creation).
565  * 2) Link source to destination.  If destination already exists,
566  *    delete it first.
567  * 3) Unlink source reference to inode if still around. If a
568  *    directory was moved and the parent of the destination
569  *    is different from the source, patch the ".." entry in the
570  *    directory.
571  */
572 int
ext2fs_rename(v)573 ext2fs_rename(v)
574 	void *v;
575 {
576 	struct vop_rename_args  /* {
577 		struct vnode *a_fdvp;
578 		struct vnode *a_fvp;
579 		struct componentname *a_fcnp;
580 		struct vnode *a_tdvp;
581 		struct vnode *a_tvp;
582 		struct componentname *a_tcnp;
583 	} */ *ap = v;
584 	struct vnode *tvp = ap->a_tvp;
585 	register struct vnode *tdvp = ap->a_tdvp;
586 	struct vnode *fvp = ap->a_fvp;
587 	register struct vnode *fdvp = ap->a_fdvp;
588 	register struct componentname *tcnp = ap->a_tcnp;
589 	register struct componentname *fcnp = ap->a_fcnp;
590 	register struct inode *ip, *xp, *dp;
591 	struct proc *p = fcnp->cn_proc;
592 	struct ext2fs_dirtemplate dirbuf;
593 	//struct timespec ts;
594 	int doingdirectory = 0, oldparent = 0, newparent = 0;
595 	int error = 0;
596 	u_char namlen;
597 
598 #ifdef DIAGNOSTIC
599 	if ((tcnp->cn_flags & HASBUF) == 0 ||
600 	    (fcnp->cn_flags & HASBUF) == 0)
601 		panic("ext2fs_rename: no name");
602 #endif
603 	/*
604 	 * Check for cross-device rename.
605 	 */
606 	if ((fvp->v_mount != tdvp->v_mount) ||
607 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
608 		error = EXDEV;
609 abortit:
610 		VOP_ABORTOP(tdvp, tcnp); /* XXX, why not in NFS? */
611 		if (tdvp == tvp)
612 			vrele(tdvp);
613 		else
614 			vput(tdvp);
615 		if (tvp)
616 			vput(tvp);
617 		VOP_ABORTOP(fdvp, fcnp); /* XXX, why not in NFS? */
618 		vrele(fdvp);
619 		vrele(fvp);
620 		return (error);
621 	}
622 
623 	/*
624 	 * Check if just deleting a link name.
625 	 */
626 	if (tvp && ((VTOI(tvp)->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
627 	    (VTOI(tdvp)->i_e2fs_flags & EXT2_APPEND))) {
628 		error = EPERM;
629 		goto abortit;
630 	}
631 	if (fvp == tvp) {
632 		if (fvp->v_type == VDIR) {
633 			error = EINVAL;
634 			goto abortit;
635 		}
636 
637 		/* Release destination completely. */
638 		VOP_ABORTOP(tdvp, tcnp);
639 		vput(tdvp);
640 		vput(tvp);
641 
642 		/* Delete source. */
643 		vrele(fdvp);
644 		vrele(fvp);
645 		fcnp->cn_flags &= ~MODMASK;
646 		fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
647 		if ((fcnp->cn_flags & SAVESTART) == 0)
648 			panic("ext2fs_rename: lost from startdir");
649 		fcnp->cn_nameiop = DELETE;
650 		(void) relookup(fdvp, &fvp, fcnp);
651 		return (VOP_REMOVE(fdvp, fvp, fcnp));
652 	}
653 	if ((error = vn_lock(fvp, LK_EXCLUSIVE, p)) != 0)
654 		goto abortit;
655 	dp = VTOI(fdvp);
656 	ip = VTOI(fvp);
657 	if ((nlink_t)ip->i_e2fs_nlink >= LINK_MAX) {
658 		VOP_UNLOCK(fvp, 0, p);
659 		error = EMLINK;
660 		goto abortit;
661 	}
662 	if ((ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND)) ||
663 		(dp->i_e2fs_flags & EXT2_APPEND)) {
664 		VOP_UNLOCK(fvp, 0, p);
665 		error = EPERM;
666 		goto abortit;
667 	}
668 	if ((ip->i_e2fs_mode & IFMT) == IFDIR) {
669         	error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
670         	if (!error && tvp)
671                 	error = VOP_ACCESS(tvp, VWRITE, tcnp->cn_cred,
672 			    tcnp->cn_proc);
673         	if (error) {
674                 	VOP_UNLOCK(fvp, 0, p);
675                 	error = EACCES;
676                 	goto abortit;
677         	}
678 		/*
679 		 * Avoid ".", "..", and aliases of "." for obvious reasons.
680 		 */
681 		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
682 		    dp == ip ||
683 			(fcnp->cn_flags&ISDOTDOT) ||
684 			(tcnp->cn_flags & ISDOTDOT) ||
685 		    (ip->i_flag & IN_RENAME)) {
686 			VOP_UNLOCK(fvp, 0, p);
687 			error = EINVAL;
688 			goto abortit;
689 		}
690 		ip->i_flag |= IN_RENAME;
691 		oldparent = dp->i_number;
692 		doingdirectory++;
693 	}
694 	vrele(fdvp);
695 
696 	/*
697 	 * When the target exists, both the directory
698 	 * and target vnodes are returned locked.
699 	 */
700 	dp = VTOI(tdvp);
701 	xp = NULL;
702 	if (tvp)
703 		xp = VTOI(tvp);
704 
705 	/*
706 	 * 1) Bump link count while we're moving stuff
707 	 *    around.  If we crash somewhere before
708 	 *    completing our work, the link count
709 	 *    may be wrong, but correctable.
710 	 */
711 	ip->i_e2fs_nlink++;
712 	ip->i_flag |= IN_CHANGE;
713 	if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0) {
714 		VOP_UNLOCK(fvp, 0, p);
715 		goto bad;
716 	}
717 
718 	/*
719 	 * If ".." must be changed (ie the directory gets a new
720 	 * parent) then the source directory must not be in the
721 	 * directory hierarchy above the target, as this would
722 	 * orphan everything below the source directory. Also
723 	 * the user must have write permission in the source so
724 	 * as to be able to change "..". We must repeat the call
725 	 * to namei, as the parent directory is unlocked by the
726 	 * call to checkpath().
727 	 */
728 	error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
729 	VOP_UNLOCK(fvp, 0, p);
730 	if (oldparent != dp->i_number)
731 		newparent = dp->i_number;
732 	if (doingdirectory && newparent) {
733 		if (error)	/* write access check above */
734 			goto bad;
735 		if (xp != NULL)
736 			vput(tvp);
737 		error = ext2fs_checkpath(ip, dp, tcnp->cn_cred);
738 		if (error != 0)
739 			goto out;
740 		if ((tcnp->cn_flags & SAVESTART) == 0)
741 			panic("ext2fs_rename: lost to startdir");
742 		if ((error = relookup(tdvp, &tvp, tcnp)) != 0)
743 			goto out;
744 		dp = VTOI(tdvp);
745 		xp = NULL;
746 		if (tvp)
747 			xp = VTOI(tvp);
748 	}
749 	/*
750 	 * 2) If target doesn't exist, link the target
751 	 *    to the source and unlink the source.
752 	 *    Otherwise, rewrite the target directory
753 	 *    entry to reference the source inode and
754 	 *    expunge the original entry's existence.
755 	 */
756 	if (xp == NULL) {
757 		if (dp->i_dev != ip->i_dev)
758 			panic("rename: EXDEV");
759 		/*
760 		 * Account for ".." in new directory.
761 		 * When source and destination have the same
762 		 * parent we don't fool with the link count.
763 		 */
764 		if (doingdirectory && newparent) {
765 			if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
766 				error = EMLINK;
767 				goto bad;
768 			}
769 			dp->i_e2fs_nlink++;
770 			dp->i_flag |= IN_CHANGE;
771 			if ((error = ext2fs_update(dp, NULL, NULL, 1)) != 0)
772 				goto bad;
773 		}
774 		error = ext2fs_direnter(ip, tdvp, tcnp);
775 		if (error != 0) {
776 			if (doingdirectory && newparent) {
777 				dp->i_e2fs_nlink--;
778 				dp->i_flag |= IN_CHANGE;
779 				(void)ext2fs_update(dp, NULL, NULL, 1);
780 			}
781 			goto bad;
782 		}
783 		vput(tdvp);
784 	} else {
785 		if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev)
786 			panic("rename: EXDEV");
787 		/*
788 		 * Short circuit rename(foo, foo).
789 		 */
790 		if (xp->i_number == ip->i_number)
791 			panic("rename: same file");
792 		/*
793 		 * If the parent directory is "sticky", then the user must
794 		 * own the parent directory, or the destination of the rename,
795 		 * otherwise the destination may not be changed (except by
796 		 * root). This implements append-only directories.
797 		 */
798 		if ((dp->i_e2fs_mode & S_ISTXT) && tcnp->cn_cred->cr_uid != 0 &&
799 		    tcnp->cn_cred->cr_uid != dp->i_e2fs_uid &&
800 		    xp->i_e2fs_uid != tcnp->cn_cred->cr_uid) {
801 			error = EPERM;
802 			goto bad;
803 		}
804 		/*
805 		 * Target must be empty if a directory and have no links
806 		 * to it. Also, ensure source and target are compatible
807 		 * (both directories, or both not directories).
808 		 */
809 		if ((xp->i_e2fs_mode & IFMT) == IFDIR) {
810 			if (!ext2fs_dirempty(xp, dp->i_number, tcnp->cn_cred) ||
811 				xp->i_e2fs_nlink > 2) {
812 				error = ENOTEMPTY;
813 				goto bad;
814 			}
815 			if (!doingdirectory) {
816 				error = ENOTDIR;
817 				goto bad;
818 			}
819 			cache_purge(tdvp);
820 		} else if (doingdirectory) {
821 			error = EISDIR;
822 			goto bad;
823 		}
824 		error = ext2fs_dirrewrite(dp, ip, tcnp);
825 		if (error != 0)
826 			goto bad;
827 		/*
828 		 * If the target directory is in the same
829 		 * directory as the source directory,
830 		 * decrement the link count on the parent
831 		 * of the target directory.
832 		 */
833 		 if (doingdirectory && !newparent) {
834 			dp->i_e2fs_nlink--;
835 			dp->i_flag |= IN_CHANGE;
836 		}
837 		vput(tdvp);
838 		/*
839 		 * Adjust the link count of the target to
840 		 * reflect the dirrewrite above.  If this is
841 		 * a directory it is empty and there are
842 		 * no links to it, so we can squash the inode and
843 		 * any space associated with it.  We disallowed
844 		 * renaming over top of a directory with links to
845 		 * it above, as the remaining link would point to
846 		 * a directory without "." or ".." entries.
847 		 */
848 		xp->i_e2fs_nlink--;
849 		if (doingdirectory) {
850 			if (--xp->i_e2fs_nlink != 0)
851 				panic("rename: linked directory");
852 			error = ext2fs_truncate(xp, (off_t)0, IO_SYNC,
853 			    tcnp->cn_cred);
854 		}
855 		xp->i_flag |= IN_CHANGE;
856 		vput(tvp);
857 		xp = NULL;
858 	}
859 
860 	/*
861 	 * 3) Unlink the source.
862 	 */
863 	fcnp->cn_flags &= ~MODMASK;
864 	fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
865 	if ((fcnp->cn_flags & SAVESTART) == 0)
866 		panic("ext2fs_rename: lost from startdir");
867 	(void) relookup(fdvp, &fvp, fcnp);
868 	if (fvp != NULL) {
869 		xp = VTOI(fvp);
870 		dp = VTOI(fdvp);
871 	} else {
872 		/*
873 		 * From name has disappeared.
874 		 */
875 		if (doingdirectory)
876 			panic("ext2fs_rename: lost dir entry");
877 		vrele(ap->a_fvp);
878 		return (0);
879 	}
880 	/*
881 	 * Ensure that the directory entry still exists and has not
882 	 * changed while the new name has been entered. If the source is
883 	 * a file then the entry may have been unlinked or renamed. In
884 	 * either case there is no further work to be done. If the source
885 	 * is a directory then it cannot have been rmdir'ed; its link
886 	 * count of three would cause a rmdir to fail with ENOTEMPTY.
887 	 * The IRENAME flag ensures that it cannot be moved by another
888 	 * rename.
889 	 */
890 	if (xp != ip) {
891 		if (doingdirectory)
892 			panic("ext2fs_rename: lost dir entry");
893 	} else {
894 		/*
895 		 * If the source is a directory with a
896 		 * new parent, the link count of the old
897 		 * parent directory must be decremented
898 		 * and ".." set to point to the new parent.
899 		 */
900 		if (doingdirectory && newparent) {
901 			dp->i_e2fs_nlink--;
902 			dp->i_flag |= IN_CHANGE;
903 			error = vn_rdwr(UIO_READ, fvp, (caddr_t)&dirbuf,
904 				sizeof (struct ext2fs_dirtemplate), (off_t)0,
905 				UIO_SYSSPACE, IO_NODELOCKED,
906 				tcnp->cn_cred, (size_t *)0, (struct proc *)0);
907 			if (error == 0) {
908 					namlen = dirbuf.dotdot_namlen;
909 				if (namlen != 2 ||
910 				    dirbuf.dotdot_name[0] != '.' ||
911 				    dirbuf.dotdot_name[1] != '.') {
912 					ufs_dirbad(xp, (doff_t)12,
913 					    "ext2fs_rename: mangled dir");
914 				} else {
915 					dirbuf.dotdot_ino = h2fs32(newparent);
916 					(void) vn_rdwr(UIO_WRITE, fvp,
917 					    (caddr_t)&dirbuf,
918 					    sizeof (struct dirtemplate),
919 					    (off_t)0, UIO_SYSSPACE,
920 					    IO_NODELOCKED|IO_SYNC,
921 					    tcnp->cn_cred, (size_t *)0,
922 					    (struct proc *)0);
923 					cache_purge(fdvp);
924 				}
925 			}
926 		}
927 		error = ext2fs_dirremove(fdvp, fcnp);
928 		if (!error) {
929 			xp->i_e2fs_nlink--;
930 			xp->i_flag |= IN_CHANGE;
931 		}
932 		xp->i_flag &= ~IN_RENAME;
933 	}
934 	if (dp)
935 		vput(fdvp);
936 	if (xp)
937 		vput(fvp);
938 	vrele(ap->a_fvp);
939 	return (error);
940 
941 bad:
942 	if (xp)
943 		vput(ITOV(xp));
944 	vput(ITOV(dp));
945 out:
946 	if (doingdirectory)
947 		ip->i_flag &= ~IN_RENAME;
948 	if (vn_lock(fvp, LK_EXCLUSIVE, p) == 0) {
949 		ip->i_e2fs_nlink--;
950 		ip->i_flag |= IN_CHANGE;
951 		vput(fvp);
952 	} else
953 		vrele(fvp);
954 	return (error);
955 }
956 
957 /*
958  * Mkdir system call
959  */
960 int
ext2fs_mkdir(v)961 ext2fs_mkdir(v)
962 	void *v;
963 {
964 	struct vop_mkdir_args /* {
965 		struct vnode *a_dvp;
966 		struct vnode **a_vpp;
967 		struct componentname *a_cnp;
968 		struct vattr *a_vap;
969 	} */ *ap = v;
970 	register struct vnode *dvp = ap->a_dvp;
971 	register struct vattr *vap = ap->a_vap;
972 	register struct componentname *cnp = ap->a_cnp;
973 	register struct inode *ip, *dp;
974 	struct vnode *tvp;
975 	struct ext2fs_dirtemplate dirtemplate;
976 	mode_t dmode;
977 	int error;
978 
979 #ifdef DIAGNOSTIC
980 	if ((cnp->cn_flags & HASBUF) == 0)
981 		panic("ext2fs_mkdir: no name");
982 #endif
983 	dp = VTOI(dvp);
984 	if ((nlink_t)dp->i_e2fs_nlink >= LINK_MAX) {
985 		error = EMLINK;
986 		goto out;
987 	}
988 	dmode = vap->va_mode & ACCESSPERMS;
989 	dmode |= IFDIR;
990 	/*
991 	 * Must simulate part of ext2fs_makeinode here to acquire the inode,
992 	 * but not have it entered in the parent directory. The entry is
993 	 * made later after writing "." and ".." entries.
994 	 */
995 	if ((error = ext2fs_inode_alloc(dp, dmode, cnp->cn_cred, &tvp)) != 0)
996 		goto out;
997 	ip = VTOI(tvp);
998 	ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
999 	ip->i_e2fs_gid = dp->i_e2fs_gid;
1000 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1001 	ip->i_e2fs_mode = dmode;
1002 	tvp->v_type = VDIR;	/* Rest init'd in getnewvnode(). */
1003 	ip->i_e2fs_nlink = 2;
1004 	error = ext2fs_update(ip, NULL, NULL, 1);
1005 
1006 	/*
1007 	 * Bump link count in parent directory
1008 	 * to reflect work done below.  Should
1009 	 * be done before reference is created
1010 	 * so reparation is possible if we crash.
1011 	 */
1012 	dp->i_e2fs_nlink++;
1013 	dp->i_flag |= IN_CHANGE;
1014 	if ((error = ext2fs_update(dp, NULL, NULL, 1)) != 0)
1015 		goto bad;
1016 
1017 	/* Initialize directory with "." and ".." from static template. */
1018 	bzero(&dirtemplate, sizeof(dirtemplate));
1019 	dirtemplate.dot_ino = h2fs32(ip->i_number);
1020 	dirtemplate.dot_reclen = h2fs16(12);
1021 	dirtemplate.dot_namlen = 1;
1022 	if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
1023 	    (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
1024 		dirtemplate.dot_type = EXT2_FT_DIR;
1025 	}
1026 	dirtemplate.dot_name[0] = '.';
1027 	dirtemplate.dotdot_ino = h2fs32(dp->i_number);
1028 	dirtemplate.dotdot_reclen = h2fs16(VTOI(dvp)->i_e2fs->e2fs_bsize - 12);
1029 	dirtemplate.dotdot_namlen = 2;
1030 	if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 &&
1031 	    (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) {
1032 		dirtemplate.dotdot_type = EXT2_FT_DIR;
1033 	}
1034 	dirtemplate.dotdot_name[0] = dirtemplate.dotdot_name[1] = '.';
1035 	error = vn_rdwr(UIO_WRITE, tvp, (caddr_t)&dirtemplate,
1036 	    sizeof (dirtemplate), (off_t)0, UIO_SYSSPACE,
1037 	    IO_NODELOCKED|IO_SYNC, cnp->cn_cred, (size_t *)0, (struct proc *)0);
1038 	if (error) {
1039 		dp->i_e2fs_nlink--;
1040 		dp->i_flag |= IN_CHANGE;
1041 		goto bad;
1042 	}
1043 	if (VTOI(dvp)->i_e2fs->e2fs_bsize >
1044 							VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize)
1045 		panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */
1046 	else {
1047 		error = ext2fs_setsize(ip, VTOI(dvp)->i_e2fs->e2fs_bsize);
1048   	        if (error) {
1049   	        	dp->i_e2fs_nlink--;
1050   	        	dp->i_flag |= IN_CHANGE;
1051   	        	goto bad;
1052   	        }
1053 		ip->i_flag |= IN_CHANGE;
1054 	}
1055 
1056 	/* Directory set up, now install it's entry in the parent directory. */
1057 	error = ext2fs_direnter(ip, dvp, cnp);
1058 	if (error != 0) {
1059 		dp->i_e2fs_nlink--;
1060 		dp->i_flag |= IN_CHANGE;
1061 	}
1062 bad:
1063 	/*
1064 	 * No need to do an explicit VOP_TRUNCATE here, vrele will do this
1065 	 * for us because we set the link count to 0.
1066 	 */
1067 	if (error) {
1068 		ip->i_e2fs_nlink = 0;
1069 		ip->i_flag |= IN_CHANGE;
1070 		vput(tvp);
1071 	} else
1072 		*ap->a_vpp = tvp;
1073 out:
1074 	pool_put(&namei_pool, cnp->cn_pnbuf);
1075 	vput(dvp);
1076 	return (error);
1077 }
1078 
1079 /*
1080  * Rmdir system call.
1081  */
1082 int
ext2fs_rmdir(v)1083 ext2fs_rmdir(v)
1084 	void *v;
1085 {
1086 	struct vop_rmdir_args /* {
1087 		struct vnode *a_dvp;
1088 		struct vnode *a_vp;
1089 		struct componentname *a_cnp;
1090 	} */ *ap = v;
1091 	register struct vnode *vp = ap->a_vp;
1092 	register struct vnode *dvp = ap->a_dvp;
1093 	register struct componentname *cnp = ap->a_cnp;
1094 	register struct inode *ip, *dp;
1095 	int error;
1096 
1097 	ip = VTOI(vp);
1098 	dp = VTOI(dvp);
1099 	/*
1100 	 * No rmdir "." please.
1101 	 */
1102 	if (dp == ip) {
1103 		vrele(dvp);
1104 		vput(vp);
1105 		return (EINVAL);
1106 	}
1107 	/*
1108 	 * Verify the directory is empty (and valid).
1109 	 * (Rmdir ".." won't be valid since
1110 	 *  ".." will contain a reference to
1111 	 *  the current directory and thus be
1112 	 *  non-empty.)
1113 	 */
1114 	error = 0;
1115 	if (ip->i_e2fs_nlink != 2 ||
1116 	    !ext2fs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
1117 		error = ENOTEMPTY;
1118 		goto out;
1119 	}
1120 	if ((dp->i_e2fs_flags & EXT2_APPEND) ||
1121 				 (ip->i_e2fs_flags & (EXT2_IMMUTABLE | EXT2_APPEND))) {
1122 		error = EPERM;
1123 		goto out;
1124 	}
1125 	/*
1126 	 * Delete reference to directory before purging
1127 	 * inode.  If we crash in between, the directory
1128 	 * will be reattached to lost+found,
1129 	 */
1130 	error = ext2fs_dirremove(dvp, cnp);
1131 	if (error != 0)
1132 		goto out;
1133 	dp->i_e2fs_nlink--;
1134 	dp->i_flag |= IN_CHANGE;
1135 	cache_purge(dvp);
1136 	vput(dvp);
1137 	dvp = NULL;
1138 	/*
1139 	 * Truncate inode.  The only stuff left
1140 	 * in the directory is "." and "..".  The
1141 	 * "." reference is inconsequential since
1142 	 * we're quashing it.  The ".." reference
1143 	 * has already been adjusted above.  We've
1144 	 * removed the "." reference and the reference
1145 	 * in the parent directory, but there may be
1146 	 * other hard links so decrement by 2 and
1147 	 * worry about them later.
1148 	 */
1149 	ip->i_e2fs_nlink -= 2;
1150 	error = ext2fs_truncate(ip, (off_t)0, IO_SYNC, cnp->cn_cred);
1151 	cache_purge(ITOV(ip));
1152 out:
1153 	if (dvp)
1154 		vput(dvp);
1155 	vput(vp);
1156 	return (error);
1157 }
1158 
1159 /*
1160  * symlink -- make a symbolic link
1161  */
1162 int
ext2fs_symlink(v)1163 ext2fs_symlink(v)
1164 	void *v;
1165 {
1166 	struct vop_symlink_args /* {
1167 		struct vnode *a_dvp;
1168 		struct vnode **a_vpp;
1169 		struct componentname *a_cnp;
1170 		struct vattr *a_vap;
1171 		char *a_target;
1172 	} */ *ap = v;
1173 	register struct vnode *vp, **vpp = ap->a_vpp;
1174 	register struct inode *ip;
1175 	int len, error;
1176 
1177 	error = ext2fs_makeinode(IFLNK | ap->a_vap->va_mode, ap->a_dvp,
1178 			      vpp, ap->a_cnp);
1179 	if (error)
1180 		return (error);
1181 	vp = *vpp;
1182 	len = strlen(ap->a_target);
1183 	if (len < vp->v_mount->mnt_maxsymlinklen) {
1184 		ip = VTOI(vp);
1185 		bcopy(ap->a_target, (char *)ip->i_e2din.e2di_shortlink, len);
1186 		error = ext2fs_setsize(ip, len);
1187 		if (error)
1188 			goto bad;
1189 		ip->i_flag |= IN_CHANGE | IN_UPDATE;
1190 	} else
1191 		error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0,
1192 		    UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL,
1193 		    (struct proc *)0);
1194 bad:
1195 	vput(vp);
1196 	return (error);
1197 }
1198 
1199 /*
1200  * Return target name of a symbolic link
1201  */
1202 int
ext2fs_readlink(v)1203 ext2fs_readlink(v)
1204 	void *v;
1205 {
1206 	struct vop_readlink_args /* {
1207 		struct vnode *a_vp;
1208 		struct uio *a_uio;
1209 		struct ucred *a_cred;
1210 	} */ *ap = v;
1211 	register struct vnode *vp = ap->a_vp;
1212 	register struct inode *ip = VTOI(vp);
1213 	int isize;
1214 
1215 	isize = ext2fs_size(ip);
1216 	if (isize < vp->v_mount->mnt_maxsymlinklen ||
1217 	    (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) {
1218 		uiomove((char *)ip->i_e2din.e2di_shortlink, isize, ap->a_uio);
1219 		return (0);
1220 	}
1221 	return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred));
1222 }
1223 
1224 /*
1225  * Advisory record locking support
1226  */
1227 int
ext2fs_advlock(v)1228 ext2fs_advlock(v)
1229 	void *v;
1230 {
1231 	struct vop_advlock_args /* {
1232 		struct vnode *a_vp;
1233 		caddr_t  a_id;
1234 		int  a_op;
1235 		struct flock *a_fl;
1236 		int  a_flags;
1237 	} */ *ap = v;
1238 	register struct inode *ip = VTOI(ap->a_vp);
1239 
1240 	return (lf_advlock(&ip->i_lockf, ext2fs_size(ip), ap->a_id, ap->a_op,
1241 	    ap->a_fl, ap->a_flags));
1242 }
1243 
1244 /*
1245  * Allocate a new inode.
1246  */
1247 int
ext2fs_makeinode(mode,dvp,vpp,cnp)1248 ext2fs_makeinode(mode, dvp, vpp, cnp)
1249 	int mode;
1250 	struct vnode *dvp;
1251 	struct vnode **vpp;
1252 	struct componentname *cnp;
1253 {
1254 	register struct inode *ip, *pdir;
1255 	struct vnode *tvp;
1256 	int error;
1257 
1258 	pdir = VTOI(dvp);
1259 #ifdef DIAGNOSTIC
1260 	if ((cnp->cn_flags & HASBUF) == 0)
1261 		panic("ext2fs_makeinode: no name");
1262 #endif
1263 	*vpp = NULL;
1264 	if ((mode & IFMT) == 0)
1265 		mode |= IFREG;
1266 
1267 	if ((error = ext2fs_inode_alloc(pdir, mode, cnp->cn_cred, &tvp))
1268 	    != 0) {
1269 		pool_put(&namei_pool, cnp->cn_pnbuf);
1270 		vput(dvp);
1271 		return (error);
1272 	}
1273 	ip = VTOI(tvp);
1274 	ip->i_e2fs_gid = pdir->i_e2fs_gid;
1275 	ip->i_e2fs_uid = cnp->cn_cred->cr_uid;
1276 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
1277 	ip->i_e2fs_mode = mode;
1278 	tvp->v_type = IFTOVT(mode);	/* Rest init'd in getnewvnode(). */
1279 	ip->i_e2fs_nlink = 1;
1280 	if ((ip->i_e2fs_mode & ISGID) &&
1281 		!groupmember(ip->i_e2fs_gid, cnp->cn_cred) &&
1282 	    suser_ucred(cnp->cn_cred))
1283 		ip->i_e2fs_mode &= ~ISGID;
1284 
1285 	/*
1286 	 * Make sure inode goes to disk before directory entry.
1287 	 */
1288 	if ((error = ext2fs_update(ip, NULL, NULL, 1)) != 0)
1289 		goto bad;
1290 	error = ext2fs_direnter(ip, dvp, cnp);
1291 	if (error != 0)
1292 		goto bad;
1293 	if ((cnp->cn_flags & SAVESTART) == 0)
1294 		pool_put(&namei_pool, cnp->cn_pnbuf);
1295 	vput(dvp);
1296 	*vpp = tvp;
1297 	return (0);
1298 
1299 bad:
1300 	/*
1301 	 * Write error occurred trying to update the inode
1302 	 * or the directory so must deallocate the inode.
1303 	 */
1304 	pool_put(&namei_pool, cnp->cn_pnbuf);
1305 	vput(dvp);
1306 	ip->i_e2fs_nlink = 0;
1307 	ip->i_flag |= IN_CHANGE;
1308 	tvp->v_type = VNON;
1309 	vput(tvp);
1310 	return (error);
1311 }
1312 
1313 /*
1314  * Synch an open file.
1315  */
1316 /* ARGSUSED */
1317 int
ext2fs_fsync(v)1318 ext2fs_fsync(v)
1319 	void *v;
1320 {
1321 	struct vop_fsync_args /* {
1322 		struct vnode *a_vp;
1323 		struct ucred *a_cred;
1324 		int a_waitfor;
1325 		struct proc *a_p;
1326 	} */ *ap = v;
1327 	register struct vnode *vp = ap->a_vp;
1328 
1329 	vflushbuf(vp, ap->a_waitfor == MNT_WAIT);
1330 	return (ext2fs_update(VTOI(ap->a_vp), NULL, NULL,
1331 		    ap->a_waitfor == MNT_WAIT));
1332 }
1333 
1334 /*
1335  * Reclaim an inode so that it can be used for other purposes.
1336  */
1337 int
ext2fs_reclaim(v)1338 ext2fs_reclaim(v)
1339 	void *v;
1340 {
1341 	struct vop_reclaim_args /* {
1342 		struct vnode *a_vp;
1343 	} */ *ap = v;
1344 	register struct vnode *vp = ap->a_vp;
1345 	struct inode *ip;
1346 	extern int prtactive;
1347 
1348 	if (prtactive && vp->v_usecount != 0)
1349 		vprint("ext2fs_reclaim: pushing active", vp);
1350 
1351 	/*
1352 	 * Remove the inode from its hash chain.
1353 	 */
1354 	ip = VTOI(vp);
1355 	ufs_ihashrem(ip);
1356 
1357 	/*
1358 	 * Purge old data structures associated with the inode.
1359 	 */
1360 	cache_purge(vp);
1361 	if (ip->i_devvp)
1362 		vrele(ip->i_devvp);
1363 
1364 	FREE(vp->v_data, M_EXT2FSNODE);
1365 	vp->v_data = NULL;
1366 
1367 	return (0);
1368 }
1369 
1370 /* Global vfs data structures for ext2fs. */
1371 int (**ext2fs_vnodeop_p)(void *);
1372 struct vnodeopv_entry_desc ext2fs_vnodeop_entries[] = {
1373 	{ &vop_default_desc, vn_default_error },
1374 	{ &vop_lookup_desc, ext2fs_lookup },	/* lookup */
1375 	{ &vop_create_desc, ext2fs_create },	/* create */
1376 	{ &vop_mknod_desc, ext2fs_mknod },		/* mknod */
1377 	{ &vop_open_desc, ext2fs_open },		/* open */
1378 	{ &vop_close_desc, ufs_close },			/* close */
1379 	{ &vop_access_desc, ext2fs_access },	/* access */
1380 	{ &vop_getattr_desc, ext2fs_getattr },	/* getattr */
1381 	{ &vop_setattr_desc, ext2fs_setattr },	/* setattr */
1382 	{ &vop_read_desc, ext2fs_read },		/* read */
1383 	{ &vop_write_desc, ext2fs_write },		/* write */
1384 	{ &vop_lease_desc, ufs_lease_check },	/* lease */
1385 	{ &vop_ioctl_desc, ufs_ioctl },			/* ioctl */
1386 	{ &vop_poll_desc, ufs_poll },		/* poll */
1387 	{ &vop_kqfilter_desc, vop_generic_kqfilter },	/* kqfilter */
1388 	{ &vop_fsync_desc, ext2fs_fsync },		/* fsync */
1389 	{ &vop_remove_desc, ext2fs_remove },	/* remove */
1390 	{ &vop_link_desc, ext2fs_link },		/* link */
1391 	{ &vop_rename_desc, ext2fs_rename },	/* rename */
1392 	{ &vop_mkdir_desc, ext2fs_mkdir },		/* mkdir */
1393 	{ &vop_rmdir_desc, ext2fs_rmdir },		/* rmdir */
1394 	{ &vop_symlink_desc, ext2fs_symlink },	/* symlink */
1395 	{ &vop_readdir_desc, ext2fs_readdir },	/* readdir */
1396 	{ &vop_readlink_desc, ext2fs_readlink },/* readlink */
1397 	{ &vop_abortop_desc, vop_generic_abortop },		/* abortop */
1398 	{ &vop_inactive_desc, ext2fs_inactive },/* inactive */
1399 	{ &vop_reclaim_desc, ext2fs_reclaim },	/* reclaim */
1400 	{ &vop_lock_desc, ufs_lock },			/* lock */
1401 	{ &vop_unlock_desc, ufs_unlock },		/* unlock */
1402 	{ &vop_bmap_desc, ext2fs_bmap },		/* bmap */
1403 	{ &vop_strategy_desc, ufs_strategy },	/* strategy */
1404 	{ &vop_print_desc, ufs_print },			/* print */
1405 	{ &vop_islocked_desc, ufs_islocked },	/* islocked */
1406 	{ &vop_pathconf_desc, ufs_pathconf },	/* pathconf */
1407 	{ &vop_advlock_desc, ext2fs_advlock },	/* advlock */
1408 	{ &vop_bwrite_desc, vop_generic_bwrite },		/* bwrite */
1409 	{ NULL, NULL }
1410 };
1411 struct vnodeopv_desc ext2fs_vnodeop_opv_desc =
1412 	{ &ext2fs_vnodeop_p, ext2fs_vnodeop_entries };
1413 
1414 int (**ext2fs_specop_p)(void *);
1415 struct vnodeopv_entry_desc ext2fs_specop_entries[] = {
1416 	{ &vop_default_desc, spec_vnoperate },
1417 	{ &vop_close_desc, ufsspec_close },		/* close */
1418 	{ &vop_access_desc, ext2fs_access },	/* access */
1419 	{ &vop_getattr_desc, ext2fs_getattr },	/* getattr */
1420 	{ &vop_setattr_desc, ext2fs_setattr },	/* setattr */
1421 	{ &vop_read_desc, ufsspec_read },		/* read */
1422 	{ &vop_write_desc, ufsspec_write },		/* write */
1423 	{ &vop_fsync_desc, ext2fs_fsync },		/* fsync */
1424 	{ &vop_inactive_desc, ext2fs_inactive },/* inactive */
1425 	{ &vop_reclaim_desc, ext2fs_reclaim },	/* reclaim */
1426 	{ &vop_lock_desc, ufs_lock },			/* lock */
1427 	{ &vop_unlock_desc, ufs_unlock },		/* unlock */
1428 	{ &vop_print_desc, ufs_print },			/* print */
1429 	{ &vop_islocked_desc, ufs_islocked },	/* islocked */
1430 	{ NULL, NULL }
1431 };
1432 struct vnodeopv_desc ext2fs_specop_opv_desc =
1433 	{ &ext2fs_specop_p, ext2fs_specop_entries };
1434 
1435 #ifdef FIFO
1436 int (**ext2fs_fifoop_p)(void *);
1437 struct vnodeopv_entry_desc ext2fs_fifoop_entries[] = {
1438 	{ &vop_default_desc, fifo_vnoperate },
1439 	{ &vop_close_desc, ufsfifo_close },		/* close */
1440 	{ &vop_access_desc, ext2fs_access },	/* access */
1441 	{ &vop_getattr_desc, ext2fs_getattr },	/* getattr */
1442 	{ &vop_setattr_desc, ext2fs_setattr },	/* setattr */
1443 	{ &vop_read_desc, ufsfifo_read },		/* read */
1444 	{ &vop_write_desc, ufsfifo_write },		/* write */
1445 	{ &vop_fsync_desc, ext2fs_fsync },		/* fsync */
1446 	{ &vop_inactive_desc, ext2fs_inactive },/* inactive */
1447 	{ &vop_reclaim_desc, ext2fsfifo_reclaim },	/* reclaim */
1448 	{ &vop_lock_desc, ufs_lock },			/* lock */
1449 	{ &vop_unlock_desc, ufs_unlock },		/* unlock */
1450 	{ &vop_print_desc, ufs_print },			/* print */
1451 	{ &vop_islocked_desc, ufs_islocked },	/* islocked */
1452 	{ &vop_bwrite_desc, vop_generic_bwrite },		/* bwrite */
1453 	{ NULL, NULL }
1454 };
1455 struct vnodeopv_desc ext2fs_fifoop_opv_desc =
1456 	{ &ext2fs_fifoop_p, ext2fs_fifoop_entries };
1457 
1458 int
ext2fsfifo_reclaim(void * v)1459 ext2fsfifo_reclaim(void *v)
1460 {
1461 	fifo_reclaim(v);
1462 	return (ext2fs_reclaim(v));
1463 }
1464 #endif /* FIFO */
1465