1 /*	$NetBSD: ufs_lookup.c,v 1.145 2016/04/29 02:38:19 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * (c) UNIX System Laboratories, Inc.
7  * All or some portions of this file are derived from material licensed
8  * to the University of California by American Telephone and Telegraph
9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10  * the permission of UNIX System Laboratories, Inc.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)ufs_lookup.c	8.9 (Berkeley) 8/11/94
37  */
38 
39 #include <sys/cdefs.h>
40 __KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.145 2016/04/29 02:38:19 christos Exp $");
41 
42 #ifdef _KERNEL_OPT
43 #include "opt_ffs.h"
44 #endif
45 
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/namei.h>
49 #include <sys/buf.h>
50 #include <sys/file.h>
51 #include <sys/stat.h>
52 #include <sys/mount.h>
53 #include <sys/vnode.h>
54 #include <sys/kernel.h>
55 #include <sys/kauth.h>
56 #include <sys/wapbl.h>
57 #include <sys/fstrans.h>
58 #include <sys/proc.h>
59 #include <sys/kmem.h>
60 
61 #include <ufs/ufs/inode.h>
62 #include <ufs/ufs/dir.h>
63 #ifdef UFS_DIRHASH
64 #include <ufs/ufs/dirhash.h>
65 #endif
66 #include <ufs/ufs/ufsmount.h>
67 #include <ufs/ufs/ufs_extern.h>
68 #include <ufs/ufs/ufs_bswap.h>
69 #include <ufs/ufs/ufs_wapbl.h>
70 
71 #include <miscfs/genfs/genfs.h>
72 
73 #ifdef DIAGNOSTIC
74 int	dirchk = 1;
75 #else
76 int	dirchk = 0;
77 #endif
78 
79 #if BYTE_ORDER == LITTLE_ENDIAN
80 # define ENDIANSWAP(needswap) ((needswap) == 0)
81 #else
82 # define ENDIANSWAP(needswap) ((needswap) != 0)
83 #endif
84 
85 #define NAMLEN(fsfmt, needswap, dp) \
86     ((fsfmt) && ENDIANSWAP(needswap) ? (dp)->d_type : (dp)->d_namlen)
87 
88 static void
ufs_dirswap(struct direct * dirp)89 ufs_dirswap(struct direct *dirp)
90 {
91 	uint8_t tmp = dirp->d_namlen;
92 	dirp->d_namlen = dirp->d_type;
93 	dirp->d_type = tmp;
94 }
95 
96 struct slotinfo {
97 	enum {
98 		NONE,		/* need to search a slot for our new entry */
99 		COMPACT,	/* a compaction can make a slot in the current
100 				   DIRBLKSIZ block */
101 		FOUND,		/* found a slot (or no need to search) */
102 	} status;
103 	doff_t offset;		/* offset of area with free space.
104 				   a special value -1 for invalid */
105 	int size;		/* size of area at slotoffset */
106 	int freespace;		/* accumulated amount of space free in
107 				   the current DIRBLKSIZ block */
108 	int needed;		/* size of the entry we're seeking */
109 };
110 
111 static void
calc_count(struct ufs_lookup_results * results,int dirblksiz,doff_t prevoff)112 calc_count(struct ufs_lookup_results *results, int dirblksiz, doff_t prevoff)
113 {
114 	if ((results->ulr_offset & (dirblksiz - 1)) == 0)
115 		results->ulr_count = 0;
116 	else
117 		results->ulr_count = results->ulr_offset - prevoff;
118 }
119 
120 static void
slot_init(struct slotinfo * slot)121 slot_init(struct slotinfo *slot)
122 {
123 	slot->status = FOUND;
124 	slot->offset = -1;
125 	slot->freespace = slot->size = slot->needed = 0;
126 }
127 
128 #ifdef UFS_DIRHASH
129 static doff_t
slot_findfree(struct slotinfo * slot,struct inode * dp)130 slot_findfree(struct slotinfo *slot, struct inode *dp)
131 {
132 	if (slot->status == FOUND)
133 		return dp->i_size;
134 
135 	slot->offset = ufsdirhash_findfree(dp, slot->needed, &slot->size);
136 	if (slot->offset < 0)
137 		return dp->i_size;
138 
139 	slot->status = COMPACT;
140 	doff_t enduseful = ufsdirhash_enduseful(dp);
141 	if (enduseful < 0)
142 		return dp->i_size;
143 	return enduseful;
144 }
145 #endif
146 
147 static void
slot_white(struct slotinfo * slot,uint16_t reclen,struct ufs_lookup_results * results)148 slot_white(struct slotinfo *slot, uint16_t reclen,
149     struct ufs_lookup_results *results)
150 {
151 	slot->status = FOUND;
152 	slot->offset = results->ulr_offset;
153 	slot->size = reclen;
154 	results->ulr_reclen = slot->size;
155 }
156 
157 static void
slot_update(struct slotinfo * slot,int size,uint16_t reclen,doff_t offset)158 slot_update(struct slotinfo *slot, int size, uint16_t reclen, doff_t offset)
159 {
160 	if (size >= slot->needed) {
161 		slot->status = FOUND;
162 		slot->offset = offset;
163 		slot->size = reclen;
164 	} else if (slot->status == NONE) {
165 		slot->freespace += size;
166 		if (slot->offset == -1)
167 			slot->offset = offset;
168 		if (slot->freespace >= slot->needed) {
169 			slot->status = COMPACT;
170 			slot->size = offset + reclen - slot->offset;
171 		}
172 	}
173 }
174 
175 /*
176  * Return an indication of where the new directory entry should be put.
177  * If we didn't find a slot, then set results->ulr_count to 0 indicating
178  * that the new slot belongs at the end of the directory. If we found a slot,
179  * then the new entry can be put in the range from results->ulr_offset to
180  * results->ulr_offset + results->ulr_count.
181  */
182 static int
slot_estimate(const struct slotinfo * slot,int dirblksiz,int nameiop,doff_t prevoff,doff_t enduseful,const struct inode * ip,struct ufs_lookup_results * results)183 slot_estimate(const struct slotinfo *slot, int dirblksiz, int nameiop,
184     doff_t prevoff, doff_t enduseful, const struct inode *ip,
185     struct ufs_lookup_results *results)
186 {
187 	if (slot->status == NONE) {
188 		results->ulr_offset = roundup(ip->i_size, dirblksiz);
189 		results->ulr_count = 0;
190 		enduseful = results->ulr_offset;
191 	} else if (nameiop == DELETE) {
192 		results->ulr_offset = slot->offset;
193 		calc_count(results, dirblksiz, prevoff);
194 	} else {
195 		results->ulr_offset = slot->offset;
196 		results->ulr_count = slot->size;
197 		if (enduseful < slot->offset + slot->size)
198 			enduseful = slot->offset + slot->size;
199 	}
200 	results->ulr_endoff = roundup(enduseful, dirblksiz);
201 #if 0 /* commented out by dbj. none of the on disk fields changed */
202 	ip->i_flag |= IN_CHANGE | IN_UPDATE;
203 #endif
204 	return EJUSTRETURN;
205 }
206 
207 /*
208  * Check if we can delete inode tdp in directory vdp with inode ip and creds.
209  */
210 static int
ufs_can_delete(struct vnode * tdp,struct vnode * vdp,struct inode * ip,kauth_cred_t cred)211 ufs_can_delete(struct vnode *tdp, struct vnode *vdp, struct inode *ip,
212     kauth_cred_t cred)
213 {
214 	int error;
215 	/*
216 	 * Write access to directory required to delete files.
217 	 */
218 	error = VOP_ACCESS(vdp, VWRITE, cred);
219 	if (error)
220 		goto out;
221 
222 	if (!(ip->i_mode & ISVTX))
223 		return 0;
224 
225 	/*
226 	 * If directory is "sticky", then user must own
227 	 * the directory, or the file in it, else she
228 	 * may not delete it (unless she's root). This
229 	 * implements append-only directories.
230 	 */
231 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, tdp, vdp,
232 	    genfs_can_sticky(cred, ip->i_uid, VTOI(tdp)->i_uid));
233 	if (error) {
234 		error = EPERM;	// Why override?
235 		goto out;
236 	}
237 	return 0;
238 out:
239 	vrele(tdp);
240 	return error;
241 }
242 
243 static int
ufs_getino(struct vnode * vdp,struct inode * ip,ino_t foundino,struct vnode ** tdp,bool same)244 ufs_getino(struct vnode *vdp, struct inode *ip, ino_t foundino,
245     struct vnode **tdp, bool same)
246 {
247 	if (ip->i_number == foundino) {
248 		if (same)
249 			return EISDIR;
250 		vref(vdp);
251 		*tdp = vdp;
252 		return 0;
253 	}
254 	return vcache_get(vdp->v_mount, &foundino, sizeof(foundino), tdp);
255 }
256 
257 
258 /*
259  * Convert a component of a pathname into a pointer to a locked inode.
260  * This is a very central and rather complicated routine.
261  * If the file system is not maintained in a strict tree hierarchy,
262  * this can result in a deadlock situation (see comments in code below).
263  *
264  * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending
265  * on whether the name is to be looked up, created, renamed, or deleted.
266  * When CREATE, RENAME, or DELETE is specified, information usable in
267  * creating, renaming, or deleting a directory entry may be calculated.
268  * If flag has LOCKPARENT or'ed into it and the target of the pathname
269  * exists, lookup returns both the target and its parent directory locked.
270  * When creating or renaming and LOCKPARENT is specified, the target may
271  * not be ".".  When deleting and LOCKPARENT is specified, the target may
272  * be "."., but the caller must check to ensure it does an vrele and vput
273  * instead of two vputs.
274  *
275  * Overall outline of ufs_lookup:
276  *
277  *	check accessibility of directory
278  *	look for name in cache, if found, then if at end of path
279  *	  and deleting or creating, drop it, else return name
280  *	search for name in directory, to found or notfound
281  * notfound:
282  *	if creating, return locked directory, leaving info on available slots
283  *	else return error
284  * found:
285  *	if at end of path and deleting, return information to allow delete
286  *	if at end of path and rewriting (RENAME and LOCKPARENT), lock target
287  *	  inode and return info to allow rewrite
288  *	if not at end, add name to cache; if at end and neither creating
289  *	  nor deleting, add name to cache
290  */
291 int
ufs_lookup(void * v)292 ufs_lookup(void *v)
293 {
294 	struct vop_lookup_v2_args /* {
295 		struct vnode *a_dvp;
296 		struct vnode **a_vpp;
297 		struct componentname *a_cnp;
298 	} */ *ap = v;
299 	struct vnode *vdp = ap->a_dvp;	/* vnode for directory being searched */
300 	struct inode *dp = VTOI(vdp);	/* inode for directory being searched */
301 	struct buf *bp;			/* a buffer of directory entries */
302 	struct direct *ep;		/* the current directory entry */
303 	int entryoffsetinblock;		/* offset of ep in bp's buffer */
304 	struct slotinfo slot;
305 	int numdirpasses;		/* strategy for directory search */
306 	doff_t endsearch;		/* offset to end directory search */
307 	doff_t prevoff;			/* previous value of ulr_offset */
308 	struct vnode *tdp;		/* returned by vcache_get */
309 	doff_t enduseful;		/* pointer past last used dir slot.
310 					   used for directory truncation. */
311 	u_long bmask;			/* block offset mask */
312 	int error;
313 	struct vnode **vpp = ap->a_vpp;
314 	struct componentname *cnp = ap->a_cnp;
315 	kauth_cred_t cred = cnp->cn_cred;
316 	int flags;
317 	int nameiop = cnp->cn_nameiop;
318 	struct ufsmount *ump = dp->i_ump;
319 	const int needswap = UFS_MPNEEDSWAP(ump);
320 	int dirblksiz = ump->um_dirblksiz;
321 	ino_t foundino;
322 	struct ufs_lookup_results *results;
323 	int iswhiteout;			/* temp result from cache_lookup() */
324 	const int fsfmt = FSFMT(vdp);
325 	uint16_t reclen;
326 
327 	flags = cnp->cn_flags;
328 
329 	bp = NULL;
330 	*vpp = NULL;
331 	endsearch = 0; /* silence compiler warning */
332 
333 	/*
334 	 * Produce the auxiliary lookup results into i_crap. Increment
335 	 * its serial number so elsewhere we can tell if we're using
336 	 * stale results. This should not be done this way. XXX.
337 	 */
338 	results = &dp->i_crap;
339 	dp->i_crapcounter++;
340 
341 	/*
342 	 * Check accessiblity of directory.
343 	 */
344 	if ((error = VOP_ACCESS(vdp, VEXEC, cred)) != 0)
345 		return (error);
346 
347 	if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) &&
348 	    (nameiop == DELETE || nameiop == RENAME))
349 		return (EROFS);
350 
351 	/*
352 	 * We now have a segment name to search for, and a directory to search.
353 	 *
354 	 * Before tediously performing a linear scan of the directory,
355 	 * check the name cache to see if the directory/name pair
356 	 * we are looking for is known already.
357 	 */
358 	if (cache_lookup(vdp, cnp->cn_nameptr, cnp->cn_namelen,
359 	    cnp->cn_nameiop, cnp->cn_flags, &iswhiteout, vpp)) {
360 		if (iswhiteout) {
361 			cnp->cn_flags |= ISWHITEOUT;
362 		}
363 		return *vpp == NULLVP ? ENOENT : 0;
364 	}
365 	if (iswhiteout) {
366 		/*
367 		 * The namecache set iswhiteout without finding a
368 		 * cache entry. As of this writing (20121014), this
369 		 * can happen if there was a whiteout entry that has
370 		 * been invalidated by the lookup. It is not clear if
371 		 * it is correct to set ISWHITEOUT in this case or
372 		 * not; however, doing so retains the prior behavior,
373 		 * so we'll go with that until some clearer answer
374 		 * appears. XXX
375 		 */
376 		cnp->cn_flags |= ISWHITEOUT;
377 	}
378 
379 	fstrans_start(vdp->v_mount, FSTRANS_SHARED);
380 
381 	/*
382 	 * Suppress search for slots unless creating
383 	 * file and at end of pathname, in which case
384 	 * we watch for a place to put the new file in
385 	 * case it doesn't already exist.
386 	 */
387 	slot_init(&slot);
388 
389 	if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) {
390 		slot.status = NONE;
391 		slot.needed = UFS_DIRECTSIZ(cnp->cn_namelen);
392 	}
393 
394 	/*
395 	 * If there is cached information on a previous search of
396 	 * this directory, pick up where we last left off.
397 	 * We cache only lookups as these are the most common
398 	 * and have the greatest payoff. Caching CREATE has little
399 	 * benefit as it usually must search the entire directory
400 	 * to determine that the entry does not exist. Caching the
401 	 * location of the last DELETE or RENAME has not reduced
402 	 * profiling time and hence has been removed in the interest
403 	 * of simplicity.
404 	 */
405 	bmask = vdp->v_mount->mnt_stat.f_iosize - 1;
406 
407 #ifdef UFS_DIRHASH
408 	/*
409 	 * Use dirhash for fast operations on large directories. The logic
410 	 * to determine whether to hash the directory is contained within
411 	 * ufsdirhash_build(); a zero return means that it decided to hash
412 	 * this directory and it successfully built up the hash table.
413 	 */
414 	if (ufsdirhash_build(dp) == 0) {
415 		/* Look for a free slot if needed. */
416 		enduseful = slot_findfree(&slot, dp);
417 		/* Look up the component. */
418 		numdirpasses = 1;
419 		entryoffsetinblock = 0; /* silence compiler warning */
420 		switch (ufsdirhash_lookup(dp, cnp->cn_nameptr, cnp->cn_namelen,
421 		    &results->ulr_offset, &bp,
422 		    nameiop == DELETE ? &prevoff : NULL)) {
423 		case 0:
424 			ep = (void *)((char *)bp->b_data +
425 			    (results->ulr_offset & bmask));
426 			reclen = ufs_rw16(ep->d_reclen, needswap);
427 			goto foundentry;
428 		case ENOENT:
429 			results->ulr_offset = roundup(dp->i_size, dirblksiz);
430 			goto notfound;
431 		default:
432 			/* Something failed; just do a linear search. */
433 			break;
434 		}
435 	}
436 #endif /* UFS_DIRHASH */
437 
438 	if (nameiop != LOOKUP || results->ulr_diroff == 0 ||
439 	    results->ulr_diroff >= dp->i_size) {
440 		entryoffsetinblock = 0;
441 		results->ulr_offset = 0;
442 		numdirpasses = 1;
443 	} else {
444 		results->ulr_offset = results->ulr_diroff;
445 		entryoffsetinblock = results->ulr_offset & bmask;
446 		if (entryoffsetinblock != 0 &&
447 		    (error = ufs_blkatoff(vdp, (off_t)results->ulr_offset,
448 		    NULL, &bp, false)))
449 			goto out;
450 		numdirpasses = 2;
451 		namecache_count_2passes();
452 	}
453 	prevoff = results->ulr_offset;
454 	endsearch = roundup(dp->i_size, dirblksiz);
455 	enduseful = 0;
456 
457 searchloop:
458 	while (results->ulr_offset < endsearch) {
459 		if (curcpu()->ci_schedstate.spc_flags & SPCF_SHOULDYIELD)
460 			preempt();
461 		/*
462 		 * If necessary, get the next directory block.
463 		 */
464 		if ((results->ulr_offset & bmask) == 0) {
465 			if (bp != NULL)
466 				brelse(bp, 0);
467 			error = ufs_blkatoff(vdp, (off_t)results->ulr_offset,
468 			    NULL, &bp, false);
469 			if (error)
470 				goto out;
471 			entryoffsetinblock = 0;
472 		}
473 		/*
474 		 * If still looking for a slot, and at a DIRBLKSIZ
475 		 * boundary, have to start looking for free space again.
476 		 */
477 		if (slot.status == NONE &&
478 		    (entryoffsetinblock & (dirblksiz - 1)) == 0) {
479 			slot.offset = -1;
480 			slot.freespace = 0;
481 		}
482 		/*
483 		 * Get pointer to next entry.
484 		 * Full validation checks are slow, so we only check
485 		 * enough to insure forward progress through the
486 		 * directory. Complete checks can be run by patching
487 		 * "dirchk" to be true.
488 		 */
489 		KASSERT(bp != NULL);
490 		ep = (void *)((char *)bp->b_data + entryoffsetinblock);
491 		const char *msg;
492 		reclen = ufs_rw16(ep->d_reclen, needswap);
493 		if ((reclen == 0 && (msg = "null entry")) || (dirchk &&
494 		    (msg = ufs_dirbadentry(vdp, ep, entryoffsetinblock)))) {
495 			ufs_dirbad(dp, results->ulr_offset, msg);
496 			reclen = dirblksiz -
497 			    (entryoffsetinblock & (dirblksiz - 1));
498 			goto next;
499 		}
500 
501 		/*
502 		 * If an appropriate sized slot has not yet been found,
503 		 * check to see if one is available. Also accumulate space
504 		 * in the current block so that we can determine if
505 		 * compaction is viable.
506 		 */
507 		if (slot.status != FOUND) {
508 			int size = reclen;
509 			if (ep->d_ino != 0)
510 				size -= UFS_DIRSIZ(fsfmt, ep, needswap);
511 			if (size > 0)
512 				slot_update(&slot, size, reclen,
513 				    results->ulr_offset);
514 		}
515 
516 		if (ep->d_ino == 0)
517 			goto next;
518 
519 		/*
520 		 * Check for a name match.
521 		 */
522 		const uint16_t namlen = NAMLEN(fsfmt, needswap, ep);
523 		if (namlen != cnp->cn_namelen ||
524 		    memcmp(cnp->cn_nameptr, ep->d_name, (size_t)namlen))
525 			goto next;
526 
527 #ifdef UFS_DIRHASH
528 foundentry:
529 #endif
530 		/*
531 		 * Save directory entry's inode number and
532 		 * reclen, and release directory buffer.
533 		 */
534 		if (!fsfmt && ep->d_type == DT_WHT) {
535 			slot_white(&slot, reclen, results);
536 			/*
537 			 * This is used to set results->ulr_endoff, which may
538 			 * be used by ufs_direnter() as a length to truncate
539 			 * the directory to. Therefore, it must point past the
540 			 * end of the last non-empty directory entry. We don't
541 			 * know where that is in this case, so we effectively
542 			 * disable shrinking by using the existing size of the
543 			 * directory.
544 			 *
545 			 * Note that we wouldn't expect to shrink the
546 			 * directory while rewriting an existing entry anyway.
547 			 */
548 			enduseful = endsearch;
549 			cnp->cn_flags |= ISWHITEOUT;
550 			numdirpasses--;
551 			goto notfound;
552 		}
553 		foundino = ufs_rw32(ep->d_ino, needswap);
554 		results->ulr_reclen = reclen;
555 		goto found;
556 next:
557 		prevoff = results->ulr_offset;
558 		results->ulr_offset += reclen;
559 		entryoffsetinblock += reclen;
560 		if (ep->d_ino)
561 			enduseful = results->ulr_offset;
562 	}
563 notfound:
564 	/*
565 	 * If we started in the middle of the directory and failed
566 	 * to find our target, we must check the beginning as well.
567 	 */
568 	if (numdirpasses == 2) {
569 		numdirpasses--;
570 		results->ulr_offset = 0;
571 		endsearch = results->ulr_diroff;
572 		goto searchloop;
573 	}
574 	if (bp != NULL)
575 		brelse(bp, 0);
576 	/*
577 	 * If creating, and at end of pathname and current
578 	 * directory has not been removed, then can consider
579 	 * allowing file to be created.
580 	 */
581 	if ((nameiop == CREATE || nameiop == RENAME ||
582 	     (nameiop == DELETE &&
583 	      (cnp->cn_flags & DOWHITEOUT) &&
584 	      (cnp->cn_flags & ISWHITEOUT))) &&
585 	    (flags & ISLASTCN) && dp->i_nlink != 0) {
586 		/*
587 		 * Access for write is interpreted as allowing
588 		 * creation of files in the directory.
589 		 */
590 		error = VOP_ACCESS(vdp, VWRITE, cred);
591 		if (error)
592 			goto out;
593 		error = slot_estimate(&slot, dirblksiz, nameiop,
594 		    prevoff, enduseful, dp, results);
595 		/*
596 		 * We return with the directory locked, so that
597 		 * the parameters we set up above will still be
598 		 * valid if we actually decide to do a direnter().
599 		 * We return ni_vp == NULL to indicate that the entry
600 		 * does not currently exist; we leave a pointer to
601 		 * the (locked) directory inode in ndp->ni_dvp.
602 		 *
603 		 * NB - if the directory is unlocked, then this
604 		 * information cannot be used.
605 		 */
606 		goto out;
607 	}
608 	/*
609 	 * Insert name into cache (as non-existent) if appropriate.
610 	 */
611 	if (nameiop != CREATE) {
612 		cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
613 			    cnp->cn_flags);
614 	}
615 	error = ENOENT;
616 	goto out;
617 
618 found:
619 	if (numdirpasses == 2)
620 		namecache_count_pass2();
621 	/*
622 	 * Check that directory length properly reflects presence
623 	 * of this entry.
624 	 */
625 	const uint64_t newisize =
626 	    results->ulr_offset + UFS_DIRSIZ(fsfmt, ep, needswap);
627 	if (newisize > dp->i_size) {
628 		ufs_dirbad(dp, results->ulr_offset, "i_size too small");
629 		dp->i_size = newisize;
630 		DIP_ASSIGN(dp, size, dp->i_size);
631 		dp->i_flag |= IN_CHANGE | IN_UPDATE;
632 		UFS_WAPBL_UPDATE(vdp, NULL, NULL, UPDATE_DIROP);
633 	}
634 	brelse(bp, 0);
635 
636 	/*
637 	 * Found component in pathname.
638 	 * If the final component of path name, save information
639 	 * in the cache as to where the entry was found.
640 	 */
641 	if ((flags & ISLASTCN) && nameiop == LOOKUP)
642 		results->ulr_diroff = results->ulr_offset & ~(dirblksiz - 1);
643 
644 	/*
645 	 * If deleting, and at end of pathname, return
646 	 * parameters which can be used to remove file.
647 	 * Lock the inode, being careful with ".".
648 	 */
649 	if (nameiop == DELETE && (flags & ISLASTCN)) {
650 		/*
651 		 * Return pointer to current entry in results->ulr_offset,
652 		 * and distance past previous entry (if there
653 		 * is a previous entry in this block) in results->ulr_count.
654 		 * Save directory inode pointer in ndp->ni_dvp for dirremove().
655 		 */
656 		calc_count(results, dirblksiz, prevoff);
657 
658 		if ((error = ufs_getino(vdp, dp, foundino, &tdp, false)) != 0)
659 			goto out;
660 
661 		if ((error = ufs_can_delete(tdp, vdp, dp, cred)) != 0)
662 			goto out;
663 
664 		*vpp = tdp;
665 		goto out;
666 	}
667 
668 	/*
669 	 * If rewriting (RENAME), return the inode and the
670 	 * information required to rewrite the present directory
671 	 * Must get inode of directory entry to verify it's a
672 	 * regular file, or empty directory.
673 	 */
674 	if (nameiop == RENAME && (flags & ISLASTCN)) {
675 		if ((error = VOP_ACCESS(vdp, VWRITE, cred)) != 0)
676 			goto out;
677 		/*
678 		 * Careful about locking second inode.
679 		 * This can only occur if the target is ".".
680 		 */
681 		if ((error = ufs_getino(vdp, dp, foundino, &tdp, true)) != 0)
682 			goto out;
683 		*vpp = tdp;
684 		goto out;
685 	}
686 
687 	if ((error = ufs_getino(vdp, dp, foundino, &tdp, false)) != 0)
688 		goto out;
689 
690 	*vpp = tdp;
691 	/*
692 	 * Insert name into cache if appropriate.
693 	 */
694 	cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags);
695 	error = 0;
696 
697 out:
698 	fstrans_done(vdp->v_mount);
699 	return error;
700 }
701 
702 void
ufs_dirbad(struct inode * ip,doff_t offset,const char * how)703 ufs_dirbad(struct inode *ip, doff_t offset, const char *how)
704 {
705 	struct mount *mp = ITOV(ip)->v_mount;
706 	void (*p)(const char  *, ...) __printflike(1, 2) =
707 	    (mp->mnt_flag & MNT_RDONLY) == 0 ? panic : printf;
708 
709 	(*p)("%s: bad dir ino %ju at offset %d: %s\n",
710 	    mp->mnt_stat.f_mntonname, (uintmax_t)ip->i_number,
711 	    offset, how);
712 }
713 
714 /*
715  * Do consistency checking on a directory entry:
716  *	record length must be multiple of 4
717  *	entry must fit in rest of its DIRBLKSIZ block
718  *	record must be large enough to contain entry
719  *	name is not longer than FFS_MAXNAMLEN
720  *	name must be as long as advertised, and null terminated
721  */
722 const char *
ufs_dirbadentry(const struct vnode * dp,const struct direct * ep,int entryoffsetinblock)723 ufs_dirbadentry(const struct vnode *dp, const struct direct *ep,
724     int entryoffsetinblock)
725 {
726 	const struct ufsmount *ump = VFSTOUFS(dp->v_mount);
727 	const int needswap = UFS_MPNEEDSWAP(ump);
728 	const int dirblksiz = ump->um_dirblksiz;
729 	const int maxsize = dirblksiz - (entryoffsetinblock & (dirblksiz - 1));
730 	const int fsfmt = FSFMT(dp);
731 	const uint8_t namlen = NAMLEN(fsfmt, needswap, ep);
732 	const uint16_t reclen = ufs_rw16(ep->d_reclen, needswap);
733 	const int dirsiz = (int)UFS_DIRSIZ(fsfmt, ep, needswap);
734 	const char *name = ep->d_name;
735 	const char *str;
736 #ifdef DIAGNOSTIC
737 	static char buf[512];
738 #endif
739 
740 	if ((reclen & 0x3) != 0)
741 		str = "not rounded";
742 	else if (reclen > maxsize)
743 		str = "too big";
744 	else if (reclen < dirsiz)
745 		str = "too small";
746 #if FFS_MAXNAMLEN < 255
747 	else if (namlen > FFS_MAXNAMLEN)
748 		str = "long name";
749 #endif
750 	else
751 		str = NULL;
752 
753 	if (str) {
754 #ifdef DIAGNOSTIC
755 		snprintf(buf, sizeof(buf), "Bad dir (%s), reclen=%#x, "
756 		    "namlen=%d, dirsiz=%d <= reclen=%d <= maxsize=%d, "
757 		    "flags=%#x, entryoffsetinblock=%d, dirblksiz=%d",
758 		    str, reclen, namlen, dirsiz, reclen, maxsize,
759 		    dp->v_mount->mnt_flag, entryoffsetinblock, dirblksiz);
760 		str = buf;
761 #endif
762 		return str;
763 	}
764 
765 	if (ep->d_ino == 0)
766 		return NULL;
767 
768 	for (uint8_t i = 0; i < namlen; i++)
769 		if (name[i] == '\0') {
770 			str = "NUL in name";
771 #ifdef DIAGNOSTIC
772 			snprintf(buf, sizeof(buf), "%s [%s] i=%d, namlen=%d",
773 			    str, name, i, namlen);
774 			str = buf;
775 #endif
776 			return str;
777 		}
778 
779 	if (name[namlen]) {
780 		str = "missing NUL in name";
781 #ifdef DIAGNOSTIC
782 		snprintf(buf, sizeof(buf), "%s [%*.*s] namlen=%d", str,
783 		    namlen, namlen, name, namlen);
784 		str = buf;
785 #endif
786 		return str;
787 	}
788 	return NULL;
789 }
790 
791 /*
792  * Construct a new directory entry after a call to namei, using the
793  * name in the componentname argument cnp. The argument ip is the
794  * inode to which the new directory entry will refer.
795  */
796 void
ufs_makedirentry(struct inode * ip,struct componentname * cnp,struct direct * newdirp)797 ufs_makedirentry(struct inode *ip, struct componentname *cnp,
798     struct direct *newdirp)
799 {
800 	newdirp->d_ino = ip->i_number;
801 	newdirp->d_namlen = cnp->cn_namelen;
802 	memcpy(newdirp->d_name, cnp->cn_nameptr, (size_t)cnp->cn_namelen);
803 	newdirp->d_name[cnp->cn_namelen] = '\0';
804 	if (FSFMT(ITOV(ip)))
805 		newdirp->d_type = 0;
806 	else
807 		newdirp->d_type = IFTODT(ip->i_mode);
808 }
809 
810 
811 static int
ufs_dirgrow(struct vnode * dvp,const struct ufs_lookup_results * ulr,struct vnode * tvp,struct direct * dirp,struct componentname * cnp,struct buf * newdirbp)812 ufs_dirgrow(struct vnode *dvp, const struct ufs_lookup_results *ulr,
813     struct vnode *tvp, struct direct *dirp,
814     struct componentname *cnp, struct buf *newdirbp)
815 {
816 	const kauth_cred_t cr = cnp->cn_cred;
817 	const struct ufsmount *ump = VFSTOUFS(dvp->v_mount);
818 	const int needswap = UFS_MPNEEDSWAP(ump);
819 	const int dirblksiz = ump->um_dirblksiz;
820 	const int fsfmt = FSFMT(dvp);
821 	const u_int newentrysize = UFS_DIRSIZ(0, dirp, 0);
822 	struct inode *dp = VTOI(dvp);
823 	int error, ret, blkoff;
824 	struct timespec ts;
825 	struct buf *bp;
826 
827 	/*
828 	 * If ulr_count is 0, then namei could find no
829 	 * space in the directory. Here, ulr_offset will
830 	 * be on a directory block boundary and we will write the
831 	 * new entry into a fresh block.
832 	 */
833 	if (ulr->ulr_offset & (dirblksiz - 1))
834 		panic("%s: newblk", __func__);
835 	if ((error = UFS_BALLOC(dvp, (off_t)ulr->ulr_offset, dirblksiz,
836 	    cr, B_CLRBUF | B_SYNC, &bp)) != 0) {
837 		return error;
838 	}
839 
840 	dp->i_size = ulr->ulr_offset + dirblksiz;
841 	DIP_ASSIGN(dp, size, dp->i_size);
842 	dp->i_flag |= IN_CHANGE | IN_UPDATE;
843 	uvm_vnp_setsize(dvp, dp->i_size);
844 	dirp->d_reclen = ufs_rw16(dirblksiz, needswap);
845 	dirp->d_ino = ufs_rw32(dirp->d_ino, needswap);
846 	if (fsfmt && ENDIANSWAP(needswap))
847 		ufs_dirswap(dirp);
848 	blkoff = ulr->ulr_offset & (ump->um_mountp->mnt_stat.f_iosize - 1);
849 	memcpy((char *)bp->b_data + blkoff, dirp, newentrysize);
850 #ifdef UFS_DIRHASH
851 	if (dp->i_dirhash != NULL) {
852 		ufsdirhash_newblk(dp, ulr->ulr_offset);
853 		ufsdirhash_add(dp, dirp, ulr->ulr_offset);
854 		ufsdirhash_checkblock(dp, (char *)bp->b_data + blkoff,
855 		    ulr->ulr_offset);
856 	}
857 #endif
858 	error = VOP_BWRITE(bp->b_vp, bp);
859 	vfs_timestamp(&ts);
860 	ret = UFS_UPDATE(dvp, &ts, &ts, UPDATE_DIROP);
861 	if (error == 0)
862 		return ret;
863 	return error;
864 }
865 
866 static int
867 #if __GNUC_PREREQ__(5, 3)
868 /* This gets miscompiled by gcc 5.3 PR/51094 */
869 __attribute__((__optimize__("no-tree-vrp")))
870 #endif
ufs_dircompact(struct vnode * dvp,const struct ufs_lookup_results * ulr,struct vnode * tvp,struct direct * dirp,struct componentname * cnp,struct buf * newdirbp)871 ufs_dircompact(struct vnode *dvp, const struct ufs_lookup_results *ulr,
872     struct vnode *tvp, struct direct *dirp,
873     struct componentname *cnp, struct buf *newdirbp)
874 {
875 	const struct ufsmount *ump = VFSTOUFS(dvp->v_mount);
876 	const int needswap = UFS_MPNEEDSWAP(ump);
877 	const int fsfmt = FSFMT(dvp);
878 	const u_int newentrysize = UFS_DIRSIZ(0, dirp, 0);
879 	struct inode *dp = VTOI(dvp);
880 	struct buf *bp;
881 	u_int dsize;
882 	struct direct *ep, *nep;
883 	int error, loc, spacefree;
884 	char *dirbuf;
885 	uint16_t reclen;
886 
887 	UFS_WAPBL_JLOCK_ASSERT(dvp->v_mount);
888 
889 	/*
890 	 * If ulr_count is non-zero, then namei found space for the new
891 	 * entry in the range ulr_offset to ulr_offset + ulr_count
892 	 * in the directory. To use this space, we may have to compact
893 	 * the entries located there, by copying them together towards the
894 	 * beginning of the block, leaving the free space in one usable
895 	 * chunk at the end.
896 	 */
897 
898 	/*
899 	 * Increase size of directory if entry eats into new space.
900 	 * This should never push the size past a new multiple of
901 	 * DIRBLKSIZ.
902 	 *
903 	 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
904 	 */
905 	if (ulr->ulr_offset + ulr->ulr_count > dp->i_size) {
906 #ifdef DIAGNOSTIC
907 		printf("%s: reached 4.2-only block, not supposed to happen\n",
908 		    __func__);
909 #endif
910 		dp->i_size = ulr->ulr_offset + ulr->ulr_count;
911 		DIP_ASSIGN(dp, size, dp->i_size);
912 		dp->i_flag |= IN_CHANGE | IN_UPDATE;
913 		UFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP);
914 	}
915 	/*
916 	 * Get the block containing the space for the new directory entry.
917 	 */
918 	error = ufs_blkatoff(dvp, (off_t)ulr->ulr_offset, &dirbuf, &bp, true);
919 	if (error)
920 		return error;
921 
922 	/*
923 	 * Find space for the new entry. In the simple case, the entry at
924 	 * offset base will have the space. If it does not, then namei
925 	 * arranged that compacting the region ulr_offset to
926 	 * ulr_offset + ulr_count would yield the space.
927 	 */
928 	ep = (void *)dirbuf;
929 	dsize = (ep->d_ino != 0) ? UFS_DIRSIZ(fsfmt, ep, needswap) : 0;
930 	reclen = ufs_rw16(ep->d_reclen, needswap);
931 	spacefree = reclen - dsize;
932 	for (loc = reclen; loc < ulr->ulr_count; ) {
933 		nep = (void *)(dirbuf + loc);
934 
935 		/* Trim the existing slot (NB: dsize may be zero). */
936 		ep->d_reclen = ufs_rw16(dsize, needswap);
937 		ep = (void *)((char *)ep + dsize);
938 
939 		reclen = ufs_rw16(nep->d_reclen, needswap);
940 		loc += reclen;
941 		if (nep->d_ino == 0) {
942 			/*
943 			 * A mid-block unused entry. Such entries are
944 			 * never created by the kernel, but fsck_ffs
945 			 * can create them (and it doesn't fix them).
946 			 *
947 			 * Add up the free space, and initialise the
948 			 * relocated entry since we don't memcpy it.
949 			 */
950 			spacefree += reclen;
951 			ep->d_ino = 0;
952 			dsize = 0;
953 			continue;
954 		}
955 		dsize = UFS_DIRSIZ(fsfmt, nep, needswap);
956 		spacefree += reclen - dsize;
957 #ifdef UFS_DIRHASH
958 		if (dp->i_dirhash != NULL)
959 			ufsdirhash_move(dp, nep,
960 			    ulr->ulr_offset + ((char *)nep - dirbuf),
961 			    ulr->ulr_offset + ((char *)ep - dirbuf));
962 #endif
963 		memcpy(ep, nep, dsize);
964 	}
965 	/*
966 	 * Here, `ep' points to a directory entry containing `dsize' in-use
967 	 * bytes followed by `spacefree' unused bytes. If ep->d_ino == 0,
968 	 * then the entry is completely unused (dsize == 0). The value
969 	 * of ep->d_reclen is always indeterminate.
970 	 *
971 	 * Update the pointer fields in the previous entry (if any),
972 	 * copy in the new entry, and write out the block.
973 	 */
974 	if (ep->d_ino == 0 ||
975 	    (ufs_rw32(ep->d_ino, needswap) == UFS_WINO &&
976 	     memcmp(ep->d_name, dirp->d_name, dirp->d_namlen) == 0)) {
977 		if (spacefree + dsize < newentrysize)
978 			panic("%s: too big", __func__);
979 		dirp->d_reclen = spacefree + dsize;
980 	} else {
981 		if (spacefree < newentrysize)
982 			panic("%s: nospace", __func__);
983 		dirp->d_reclen = spacefree;
984 		ep->d_reclen = ufs_rw16(dsize, needswap);
985 		ep = (void *)((char *)ep + dsize);
986 	}
987 
988 	dirp->d_reclen = ufs_rw16(dirp->d_reclen, needswap);
989 	dirp->d_ino = ufs_rw32(dirp->d_ino, needswap);
990 	if (fsfmt && ENDIANSWAP(needswap))
991 		ufs_dirswap(dirp);
992 #ifdef UFS_DIRHASH
993 	if (dp->i_dirhash != NULL && (ep->d_ino == 0 ||
994 	    dirp->d_reclen == spacefree))
995 		ufsdirhash_add(dp, dirp, ulr->ulr_offset + ((char *)ep - dirbuf));
996 #endif
997 	memcpy(ep, dirp, newentrysize);
998 #ifdef UFS_DIRHASH
999 	if (dp->i_dirhash != NULL) {
1000 		const int dirblkmsk = ump->um_dirblksiz - 1;
1001 		ufsdirhash_checkblock(dp, dirbuf -
1002 		    (ulr->ulr_offset & dirblkmsk),
1003 		    ulr->ulr_offset & ~dirblkmsk);
1004 	}
1005 #endif
1006 	error = VOP_BWRITE(bp->b_vp, bp);
1007 	dp->i_flag |= IN_CHANGE | IN_UPDATE;
1008 	/*
1009 	 * If all went well, and the directory can be shortened, proceed
1010 	 * with the truncation. Note that we have to unlock the inode for
1011 	 * the entry that we just entered, as the truncation may need to
1012 	 * lock other inodes which can lead to deadlock if we also hold a
1013 	 * lock on the newly entered node.
1014 	 */
1015 	if (error == 0 && ulr->ulr_endoff && ulr->ulr_endoff < dp->i_size) {
1016 		const kauth_cred_t cr = cnp->cn_cred;
1017 #ifdef UFS_DIRHASH
1018 		if (dp->i_dirhash != NULL)
1019 			ufsdirhash_dirtrunc(dp, ulr->ulr_endoff);
1020 #endif
1021 		(void) UFS_TRUNCATE(dvp, (off_t)ulr->ulr_endoff, IO_SYNC, cr);
1022 	}
1023 	UFS_WAPBL_UPDATE(dvp, NULL, NULL, UPDATE_DIROP);
1024 	return error;
1025 }
1026 
1027 /*
1028  * Write a directory entry after a call to namei, using the parameters
1029  * that ufs_lookup left in nameidata and in the ufs_lookup_results.
1030  *
1031  * DVP is the directory to be updated. It must be locked.
1032  * ULR is the ufs_lookup_results structure from the final lookup step.
1033  * TVP is not used. (XXX: why is it here? remove it)
1034  * DIRP is the new directory entry contents.
1035  * CNP is the componentname from the final lookup step.
1036  * NEWDIRBP is not used and (XXX) should be removed. The previous
1037  * comment here said it was used by the now-removed softupdates code.
1038  *
1039  * The link count of the target inode is *not* incremented; the
1040  * caller does that.
1041  *
1042  * If ulr->ulr_count is 0, ufs_lookup did not find space to insert the
1043  * directory entry. ulr_offset, which is the place to put the entry,
1044  * should be on a block boundary (and should be at the end of the
1045  * directory AFAIK) and a fresh block is allocated to put the new
1046  * directory entry in.
1047  *
1048  * If ulr->ulr_count is not zero, ufs_lookup found a slot to insert
1049  * the entry into. This slot ranges from ulr_offset to ulr_offset +
1050  * ulr_count. However, this slot may already be partially populated
1051  * requiring compaction. See notes below.
1052  *
1053  * Furthermore, if ulr_count is not zero and ulr_endoff is not the
1054  * same as i_size, the directory is truncated to size ulr_endoff.
1055  */
1056 int
ufs_direnter(struct vnode * dvp,const struct ufs_lookup_results * ulr,struct vnode * tvp,struct direct * dirp,struct componentname * cnp,struct buf * newdirbp)1057 ufs_direnter(struct vnode *dvp, const struct ufs_lookup_results *ulr,
1058     struct vnode *tvp, struct direct *dirp,
1059     struct componentname *cnp, struct buf *newdirbp)
1060 {
1061 	if (ulr->ulr_count == 0)
1062 		return ufs_dirgrow(dvp, ulr, tvp, dirp, cnp, newdirbp);
1063 	else
1064 		return ufs_dircompact(dvp, ulr, tvp, dirp, cnp, newdirbp);
1065 }
1066 
1067 /*
1068  * Remove a directory entry after a call to namei, using the
1069  * parameters that ufs_lookup left in nameidata and in the
1070  * ufs_lookup_results.
1071  *
1072  * DVP is the directory to be updated. It must be locked.
1073  * ULR is the ufs_lookup_results structure from the final lookup step.
1074  * IP, if not null, is the inode being unlinked.
1075  * FLAGS may contain DOWHITEOUT.
1076  * ISRMDIR is not used and (XXX) should be removed.
1077  *
1078  * If FLAGS contains DOWHITEOUT the entry is replaced with a whiteout
1079  * instead of being cleared.
1080  *
1081  * ulr->ulr_offset contains the position of the directory entry
1082  * to be removed.
1083  *
1084  * ulr->ulr_reclen contains the size of the directory entry to be
1085  * removed.
1086  *
1087  * ulr->ulr_count contains the size of the *previous* directory
1088  * entry. This allows finding it, for free space management. If
1089  * ulr_count is 0, the target entry is at the beginning of the
1090  * directory. (Does this ever happen? The first entry should be ".",
1091  * which should only be removed at rmdir time. Does rmdir come here
1092  * to clear out the "." and ".." entries? Perhaps, but I doubt it.)
1093  *
1094  * The space is marked free by adding it to the record length (not
1095  * name length) of the preceding entry. If the first entry becomes
1096  * free, it is marked free by setting the inode number to 0.
1097  *
1098  * The link count of IP is decremented. Note that this is not the
1099  * inverse behavior of ufs_direnter, which does not adjust link
1100  * counts. Sigh.
1101  */
1102 int
ufs_dirremove(struct vnode * dvp,const struct ufs_lookup_results * ulr,struct inode * ip,int flags,int isrmdir)1103 ufs_dirremove(struct vnode *dvp, const struct ufs_lookup_results *ulr,
1104     struct inode *ip, int flags, int isrmdir)
1105 {
1106 	struct inode *dp = VTOI(dvp);
1107 	struct direct *ep;
1108 	struct buf *bp;
1109 	int error;
1110 	const int needswap = UFS_MPNEEDSWAP(dp->i_ump);
1111 	uint16_t reclen;
1112 
1113 	UFS_WAPBL_JLOCK_ASSERT(dvp->v_mount);
1114 
1115 	if (flags & DOWHITEOUT) {
1116 		/*
1117 		 * Whiteout entry: set d_ino to UFS_WINO.
1118 		 */
1119 		error = ufs_blkatoff(dvp, (off_t)ulr->ulr_offset, &ep,
1120 				     &bp, true);
1121 		if (error)
1122 			return (error);
1123 		ep->d_ino = ufs_rw32(UFS_WINO, needswap);
1124 		ep->d_type = DT_WHT;
1125 		goto out;
1126 	}
1127 
1128 	if ((error = ufs_blkatoff(dvp,
1129 	    (off_t)(ulr->ulr_offset - ulr->ulr_count), &ep, &bp, true)) != 0)
1130 		return (error);
1131 
1132 	reclen = ufs_rw16(ep->d_reclen, needswap);
1133 #ifdef UFS_DIRHASH
1134 	/*
1135 	 * Remove the dirhash entry. This is complicated by the fact
1136 	 * that `ep' is the previous entry when ulr_count != 0.
1137 	 */
1138 	if (dp->i_dirhash != NULL)
1139 		ufsdirhash_remove(dp, (ulr->ulr_count == 0) ? ep :
1140 		   (void *)((char *)ep + reclen), ulr->ulr_offset);
1141 #endif
1142 
1143 	if (ulr->ulr_count == 0) {
1144 		/*
1145 		 * First entry in block: set d_ino to zero.
1146 		 */
1147 		ep->d_ino = 0;
1148 	} else {
1149 		/*
1150 		 * Collapse new free space into previous entry.
1151 		 */
1152 		ep->d_reclen = ufs_rw16(reclen + ulr->ulr_reclen, needswap);
1153 	}
1154 
1155 #ifdef UFS_DIRHASH
1156 	if (dp->i_dirhash != NULL) {
1157 		int dirblksiz = ip->i_ump->um_dirblksiz;
1158 		ufsdirhash_checkblock(dp, (char *)ep -
1159 		    ((ulr->ulr_offset - ulr->ulr_count) & (dirblksiz - 1)),
1160 		    ulr->ulr_offset & ~(dirblksiz - 1));
1161 	}
1162 #endif
1163 
1164 out:
1165 	if (ip) {
1166 		ip->i_nlink--;
1167 		DIP_ASSIGN(ip, nlink, ip->i_nlink);
1168 		ip->i_flag |= IN_CHANGE;
1169 		UFS_WAPBL_UPDATE(ITOV(ip), NULL, NULL, 0);
1170 	}
1171 	/*
1172 	 * XXX did it ever occur to anyone that it might be a good
1173 	 * idea to restore ip->i_nlink if this fails? Or something?
1174 	 * Currently on error return from this function the state of
1175 	 * ip->i_nlink depends on what happened, and callers
1176 	 * definitely do not take this into account.
1177 	 */
1178 	error = VOP_BWRITE(bp->b_vp, bp);
1179 	dp->i_flag |= IN_CHANGE | IN_UPDATE;
1180 	/*
1181 	 * If the last named reference to a snapshot goes away,
1182 	 * drop its snapshot reference so that it will be reclaimed
1183 	 * when last open reference goes away.
1184 	 */
1185 	if (ip != 0 && (ip->i_flags & SF_SNAPSHOT) != 0 &&
1186 	    ip->i_nlink == 0)
1187 		UFS_SNAPGONE(ITOV(ip));
1188 	UFS_WAPBL_UPDATE(dvp, NULL, NULL, 0);
1189 	return (error);
1190 }
1191 
1192 /*
1193  * Rewrite an existing directory entry to point at the inode supplied.
1194  *
1195  * DP is the directory to update.
1196  * OFFSET is the position of the entry in question. It may come
1197  * from ulr_offset of a ufs_lookup_results.
1198  * OIP is the old inode the directory previously pointed to.
1199  * NEWINUM is the number of the new inode.
1200  * NEWTYPE is the new value for the type field of the directory entry.
1201  * (This is ignored if the fs doesn't support that.)
1202  * ISRMDIR is not used and (XXX) should be removed.
1203  * IFLAGS are added to DP's inode flags.
1204  *
1205  * The link count of OIP is decremented. Note that the link count of
1206  * the new inode is *not* incremented. Yay for symmetry.
1207  */
1208 int
ufs_dirrewrite(struct inode * dp,off_t offset,struct inode * oip,ino_t newinum,int newtype,int isrmdir,int iflags)1209 ufs_dirrewrite(struct inode *dp, off_t offset,
1210     struct inode *oip, ino_t newinum, int newtype,
1211     int isrmdir, int iflags)
1212 {
1213 	struct buf *bp;
1214 	struct direct *ep;
1215 	struct vnode *vdp = ITOV(dp);
1216 	int error;
1217 
1218 	error = ufs_blkatoff(vdp, offset, &ep, &bp, true);
1219 	if (error)
1220 		return (error);
1221 	ep->d_ino = ufs_rw32(newinum, UFS_MPNEEDSWAP(dp->i_ump));
1222 	if (!FSFMT(vdp))
1223 		ep->d_type = newtype;
1224 	oip->i_nlink--;
1225 	DIP_ASSIGN(oip, nlink, oip->i_nlink);
1226 	oip->i_flag |= IN_CHANGE;
1227 	UFS_WAPBL_UPDATE(ITOV(oip), NULL, NULL, UPDATE_DIROP);
1228 	error = VOP_BWRITE(bp->b_vp, bp);
1229 	dp->i_flag |= iflags;
1230 	/*
1231 	 * If the last named reference to a snapshot goes away,
1232 	 * drop its snapshot reference so that it will be reclaimed
1233 	 * when last open reference goes away.
1234 	 */
1235 	if ((oip->i_flags & SF_SNAPSHOT) != 0 && oip->i_nlink == 0)
1236 		UFS_SNAPGONE(ITOV(oip));
1237 	UFS_WAPBL_UPDATE(vdp, NULL, NULL, UPDATE_DIROP);
1238 	return (error);
1239 }
1240 
1241 /*
1242  * Check if a directory is empty or not.
1243  * Inode supplied must be locked.
1244  *
1245  * Using a struct dirtemplate here is not precisely
1246  * what we want, but better than using a struct direct.
1247  *
1248  * NB: does not handle corrupted directories.
1249  */
1250 int
ufs_dirempty(struct inode * ip,ino_t parentino,kauth_cred_t cred)1251 ufs_dirempty(struct inode *ip, ino_t parentino, kauth_cred_t cred)
1252 {
1253 	doff_t off;
1254 	struct dirtemplate dbuf;
1255 	struct direct *dp = (void *)&dbuf;
1256 	int error;
1257 	size_t count;
1258 	const int needswap = UFS_IPNEEDSWAP(ip);
1259 	const int fsfmt = FSFMT(ITOV(ip));
1260 #define	MINDIRSIZ (sizeof (struct dirtemplate) / 2)
1261 
1262 	for (off = 0; off < ip->i_size;
1263 	    off += ufs_rw16(dp->d_reclen, needswap)) {
1264 		error = ufs_bufio(UIO_READ, ITOV(ip), dp, MINDIRSIZ,
1265 		    off, IO_NODELOCKED, cred, &count, NULL);
1266 		/*
1267 		 * Since we read MINDIRSIZ, residual must
1268 		 * be 0 unless we're at end of file.
1269 		 */
1270 		if (error || count != 0)
1271 			return (0);
1272 		/* avoid infinite loops */
1273 		if (dp->d_reclen == 0)
1274 			return (0);
1275 		/* skip empty entries */
1276 		ino_t ino = ufs_rw32(dp->d_ino, needswap);
1277 		if (ino == 0 || ino == UFS_WINO)
1278 			continue;
1279 		/* accept only "." and ".." */
1280 		const uint8_t namlen = NAMLEN(fsfmt, needswap, dp);
1281 		if (namlen > 2)
1282 			return (0);
1283 		if (dp->d_name[0] != '.')
1284 			return (0);
1285 		/*
1286 		 * At this point namlen must be 1 or 2.
1287 		 * 1 implies ".", 2 implies ".." if second
1288 		 * char is also "."
1289 		 */
1290 		if (namlen == 1 && ino == ip->i_number)
1291 			continue;
1292 		if (dp->d_name[1] == '.' && ino == parentino)
1293 			continue;
1294 		return (0);
1295 	}
1296 	return (1);
1297 }
1298 
1299 #define	UFS_DIRRABLKS 0
1300 int ufs_dirrablks = UFS_DIRRABLKS;
1301 
1302 /*
1303  * ufs_blkatoff: Return buffer with the contents of block "offset" from
1304  * the beginning of directory "vp".  If "res" is non-NULL, fill it in with
1305  * a pointer to the remaining space in the directory.  If the caller intends
1306  * to modify the buffer returned, "modify" must be true.
1307  */
1308 
1309 int
ufs_blkatoff(struct vnode * vp,off_t offset,void * v,struct buf ** bpp,bool modify)1310 ufs_blkatoff(struct vnode *vp, off_t offset, void *v, struct buf **bpp,
1311     bool modify)
1312 {
1313 	char **res = v;
1314 	struct inode *ip __diagused;
1315 	struct buf *bp;
1316 	daddr_t lbn;
1317 	const int dirrablks = ufs_dirrablks;
1318 	daddr_t *blks;
1319 	int *blksizes;
1320 	int run, error;
1321 	struct mount *mp = vp->v_mount;
1322 	const int bshift = mp->mnt_fs_bshift;
1323 	const int bsize = 1 << bshift;
1324 	off_t eof;
1325 
1326 	blks = kmem_alloc((1 + dirrablks) * sizeof(daddr_t), KM_SLEEP);
1327 	blksizes = kmem_alloc((1 + dirrablks) * sizeof(int), KM_SLEEP);
1328 	ip = VTOI(vp);
1329 	KASSERT(vp->v_size == ip->i_size);
1330 	GOP_SIZE(vp, vp->v_size, &eof, 0);
1331 	lbn = offset >> bshift;
1332 
1333 	for (run = 0; run <= dirrablks;) {
1334 		const off_t curoff = lbn << bshift;
1335 		const int size = MIN(eof - curoff, bsize);
1336 
1337 		if (size == 0) {
1338 			break;
1339 		}
1340 		KASSERT(curoff < eof);
1341 		blks[run] = lbn;
1342 		blksizes[run] = size;
1343 		lbn++;
1344 		run++;
1345 		if (size != bsize) {
1346 			break;
1347 		}
1348 	}
1349 	KASSERT(run >= 1);
1350 	error = breadn(vp, blks[0], blksizes[0], &blks[1], &blksizes[1],
1351 	    run - 1, (modify ? B_MODIFY : 0), &bp);
1352 	if (error != 0) {
1353 		*bpp = NULL;
1354 		goto out;
1355 	}
1356 	if (res) {
1357 		*res = (char *)bp->b_data + (offset & (bsize - 1));
1358 	}
1359 	*bpp = bp;
1360 
1361  out:
1362 	kmem_free(blks, (1 + dirrablks) * sizeof(daddr_t));
1363 	kmem_free(blksizes, (1 + dirrablks) * sizeof(int));
1364 	return error;
1365 }
1366