xref: /original-bsd/sys/ufs/ffs/ufs_lookup.c (revision 05598ce3)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)ufs_lookup.c	7.25 (Berkeley) 02/21/91
8  */
9 
10 #include "param.h"
11 #include "user.h"
12 #include "buf.h"
13 #include "file.h"
14 #include "vnode.h"
15 #include "../ufs/quota.h"
16 #include "../ufs/inode.h"
17 #include "../ufs/fs.h"
18 
19 struct	nchstats nchstats;
20 int	dirchk = 1;
21 
22 /*
23  * Convert a component of a pathname into a pointer to a locked inode.
24  * This is a very central and rather complicated routine.
25  * If the file system is not maintained in a strict tree hierarchy,
26  * this can result in a deadlock situation (see comments in code below).
27  *
28  * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on
29  * whether the name is to be looked up, created, renamed, or deleted.
30  * When CREATE, RENAME, or DELETE is specified, information usable in
31  * creating, renaming, or deleting a directory entry may be calculated.
32  * If flag has LOCKPARENT or'ed into it and the target of the pathname
33  * exists, lookup returns both the target and its parent directory locked.
34  * When creating or renaming and LOCKPARENT is specified, the target may
35  * not be ".".  When deleting and LOCKPARENT is specified, the target may
36  * be "."., but the caller must check to ensure it does an vrele and iput
37  * instead of two iputs.
38  *
39  * Overall outline of ufs_lookup:
40  *
41  *	check accessibility of directory
42  *	look for name in cache, if found, then if at end of path
43  *	  and deleting or creating, drop it, else return name
44  *	search for name in directory, to found or notfound
45  * notfound:
46  *	if creating, return locked directory, leaving info on available slots
47  *	else return error
48  * found:
49  *	if at end of path and deleting, return information to allow delete
50  *	if at end of path and rewriting (RENAME and LOCKPARENT), lock target
51  *	  inode and return info to allow rewrite
52  *	if not at end, add name to cache; if at end and neither creating
53  *	  nor deleting, add name to cache
54  *
55  * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked.
56  */
57 ufs_lookup(vdp, ndp)
58 	register struct vnode *vdp;
59 	register struct nameidata *ndp;
60 {
61 	register struct inode *dp;	/* the directory we are searching */
62 	register struct fs *fs;		/* file system that directory is in */
63 	struct buf *bp = 0;		/* a buffer of directory entries */
64 	register struct direct *ep;	/* the current directory entry */
65 	int entryoffsetinblock;		/* offset of ep in bp's buffer */
66 	enum {NONE, COMPACT, FOUND} slotstatus;
67 	int slotoffset = -1;		/* offset of area with free space */
68 	int slotsize;			/* size of area at slotoffset */
69 	int slotfreespace;		/* amount of space free in slot */
70 	int slotneeded;			/* size of the entry we're seeking */
71 	int numdirpasses;		/* strategy for directory search */
72 	int endsearch;			/* offset to end directory search */
73 	int prevoff;			/* ndp->ni_offset of previous entry */
74 	struct inode *pdp;		/* saved dp during symlink work */
75 	struct inode *tdp;		/* returned by iget */
76 	off_t enduseful;		/* pointer past last used dir slot */
77 	int flag;			/* LOOKUP, CREATE, RENAME, or DELETE */
78 	int lockparent;			/* 1 => lockparent flag is set */
79 	int wantparent;			/* 1 => wantparent or lockparent flag */
80 	int error;
81 
82 	ndp->ni_dvp = vdp;
83 	ndp->ni_vp = NULL;
84 	dp = VTOI(vdp);
85 	fs = dp->i_fs;
86 	lockparent = ndp->ni_nameiop & LOCKPARENT;
87 	flag = ndp->ni_nameiop & OPMASK;
88 	wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT);
89 
90 	/*
91 	 * Check accessiblity of directory.
92 	 */
93 	if ((dp->i_mode&IFMT) != IFDIR)
94 		return (ENOTDIR);
95 	if (error = ufs_access(vdp, VEXEC, ndp->ni_cred))
96 		return (error);
97 
98 	/*
99 	 * We now have a segment name to search for, and a directory to search.
100 	 *
101 	 * Before tediously performing a linear scan of the directory,
102 	 * check the name cache to see if the directory/name pair
103 	 * we are looking for is known already.
104 	 */
105 	if (error = cache_lookup(ndp)) {
106 		int vpid;	/* capability number of vnode */
107 
108 		if (error == ENOENT)
109 			return (error);
110 #ifdef PARANOID
111 		if (vdp == ndp->ni_rdir && ndp->ni_isdotdot)
112 			panic("ufs_lookup: .. through root");
113 #endif
114 		/*
115 		 * Get the next vnode in the path.
116 		 * See comment below starting `Step through' for
117 		 * an explaination of the locking protocol.
118 		 */
119 		pdp = dp;
120 		dp = VTOI(ndp->ni_vp);
121 		vdp = ndp->ni_vp;
122 		vpid = vdp->v_id;
123 		if (pdp == dp) {
124 			VREF(vdp);
125 			error = 0;
126 		} else if (ndp->ni_isdotdot) {
127 			IUNLOCK(pdp);
128 			error = vget(vdp);
129 		} else {
130 			error = vget(vdp);
131 			IUNLOCK(pdp);
132 		}
133 		/*
134 		 * Check that the capability number did not change
135 		 * while we were waiting for the lock.
136 		 */
137 		if (!error) {
138 			if (vpid == vdp->v_id)
139 				return (0);
140 			else
141 				iput(dp);
142 		}
143 		ILOCK(pdp);
144 		dp = pdp;
145 		vdp = ITOV(dp);
146 		ndp->ni_vp = NULL;
147 	}
148 
149 	/*
150 	 * Suppress search for slots unless creating
151 	 * file and at end of pathname, in which case
152 	 * we watch for a place to put the new file in
153 	 * case it doesn't already exist.
154 	 */
155 	slotstatus = FOUND;
156 	if ((flag == CREATE || flag == RENAME) && *ndp->ni_next == 0) {
157 		slotstatus = NONE;
158 		slotfreespace = 0;
159 		slotneeded = DIRSIZ(&ndp->ni_dent);
160 	}
161 
162 	/*
163 	 * If there is cached information on a previous search of
164 	 * this directory, pick up where we last left off.
165 	 * We cache only lookups as these are the most common
166 	 * and have the greatest payoff. Caching CREATE has little
167 	 * benefit as it usually must search the entire directory
168 	 * to determine that the entry does not exist. Caching the
169 	 * location of the last DELETE or RENAME has not reduced
170 	 * profiling time and hence has been removed in the interest
171 	 * of simplicity.
172 	 */
173 	if (flag != LOOKUP || dp->i_diroff == 0 || dp->i_diroff > dp->i_size) {
174 		ndp->ni_offset = 0;
175 		numdirpasses = 1;
176 	} else {
177 		ndp->ni_offset = dp->i_diroff;
178 		entryoffsetinblock = blkoff(fs, ndp->ni_offset);
179 		if (entryoffsetinblock != 0) {
180 			error = blkatoff(dp, ndp->ni_offset, (char **)0, &bp);
181 			if (error)
182 				return (error);
183 		}
184 		numdirpasses = 2;
185 		nchstats.ncs_2passes++;
186 	}
187 	endsearch = roundup(dp->i_size, DIRBLKSIZ);
188 	enduseful = 0;
189 
190 searchloop:
191 	while (ndp->ni_offset < endsearch) {
192 		/*
193 		 * If offset is on a block boundary,
194 		 * read the next directory block.
195 		 * Release previous if it exists.
196 		 */
197 		if (blkoff(fs, ndp->ni_offset) == 0) {
198 			if (bp != NULL)
199 				brelse(bp);
200 			error = blkatoff(dp, ndp->ni_offset, (char **)0, &bp);
201 			if (error)
202 				return (error);
203 			entryoffsetinblock = 0;
204 		}
205 		/*
206 		 * If still looking for a slot, and at a DIRBLKSIZE
207 		 * boundary, have to start looking for free space again.
208 		 */
209 		if (slotstatus == NONE &&
210 		    (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) {
211 			slotoffset = -1;
212 			slotfreespace = 0;
213 		}
214 		/*
215 		 * Get pointer to next entry.
216 		 * Full validation checks are slow, so we only check
217 		 * enough to insure forward progress through the
218 		 * directory. Complete checks can be run by patching
219 		 * "dirchk" to be true.
220 		 */
221 		ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock);
222 		if (ep->d_reclen == 0 ||
223 		    dirchk && dirbadentry(ep, entryoffsetinblock)) {
224 			int i;
225 
226 			dirbad(dp, ndp->ni_offset, "mangled entry");
227 			i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1));
228 			ndp->ni_offset += i;
229 			entryoffsetinblock += i;
230 			continue;
231 		}
232 
233 		/*
234 		 * If an appropriate sized slot has not yet been found,
235 		 * check to see if one is available. Also accumulate space
236 		 * in the current block so that we can determine if
237 		 * compaction is viable.
238 		 */
239 		if (slotstatus != FOUND) {
240 			int size = ep->d_reclen;
241 
242 			if (ep->d_ino != 0)
243 				size -= DIRSIZ(ep);
244 			if (size > 0) {
245 				if (size >= slotneeded) {
246 					slotstatus = FOUND;
247 					slotoffset = ndp->ni_offset;
248 					slotsize = ep->d_reclen;
249 				} else if (slotstatus == NONE) {
250 					slotfreespace += size;
251 					if (slotoffset == -1)
252 						slotoffset = ndp->ni_offset;
253 					if (slotfreespace >= slotneeded) {
254 						slotstatus = COMPACT;
255 						slotsize = ndp->ni_offset +
256 						      ep->d_reclen - slotoffset;
257 					}
258 				}
259 			}
260 		}
261 
262 		/*
263 		 * Check for a name match.
264 		 */
265 		if (ep->d_ino) {
266 			if (ep->d_namlen == ndp->ni_dent.d_namlen &&
267 			    !bcmp(ndp->ni_ptr, ep->d_name,
268 				(unsigned)ep->d_namlen)) {
269 				/*
270 				 * Save directory entry's inode number and
271 				 * reclen in ndp->ni_dent, and release
272 				 * directory buffer.
273 				 */
274 				ndp->ni_dent.d_ino = ep->d_ino;
275 				ndp->ni_dent.d_reclen = ep->d_reclen;
276 				brelse(bp);
277 				goto found;
278 			}
279 		}
280 		prevoff = ndp->ni_offset;
281 		ndp->ni_offset += ep->d_reclen;
282 		entryoffsetinblock += ep->d_reclen;
283 		if (ep->d_ino)
284 			enduseful = ndp->ni_offset;
285 	}
286 /* notfound: */
287 	/*
288 	 * If we started in the middle of the directory and failed
289 	 * to find our target, we must check the beginning as well.
290 	 */
291 	if (numdirpasses == 2) {
292 		numdirpasses--;
293 		ndp->ni_offset = 0;
294 		endsearch = dp->i_diroff;
295 		goto searchloop;
296 	}
297 	if (bp != NULL)
298 		brelse(bp);
299 	/*
300 	 * If creating, and at end of pathname and current
301 	 * directory has not been removed, then can consider
302 	 * allowing file to be created.
303 	 */
304 	if ((flag == CREATE || flag == RENAME) &&
305 	    *ndp->ni_next == 0 && dp->i_nlink != 0) {
306 		/*
307 		 * Access for write is interpreted as allowing
308 		 * creation of files in the directory.
309 		 */
310 		if (error = ufs_access(vdp, VWRITE, ndp->ni_cred))
311 			return (error);
312 		/*
313 		 * Return an indication of where the new directory
314 		 * entry should be put.  If we didn't find a slot,
315 		 * then set ndp->ni_count to 0 indicating that the new
316 		 * slot belongs at the end of the directory. If we found
317 		 * a slot, then the new entry can be put in the range
318 		 * [ndp->ni_offset .. ndp->ni_offset + ndp->ni_count)
319 		 */
320 		if (slotstatus == NONE) {
321 			ndp->ni_offset = roundup(dp->i_size, DIRBLKSIZ);
322 			ndp->ni_count = 0;
323 			enduseful = ndp->ni_offset;
324 		} else {
325 			ndp->ni_offset = slotoffset;
326 			ndp->ni_count = slotsize;
327 			if (enduseful < slotoffset + slotsize)
328 				enduseful = slotoffset + slotsize;
329 		}
330 		ndp->ni_endoff = roundup(enduseful, DIRBLKSIZ);
331 		dp->i_flag |= IUPD|ICHG;
332 		/*
333 		 * We return with the directory locked, so that
334 		 * the parameters we set up above will still be
335 		 * valid if we actually decide to do a direnter().
336 		 * We return ni_vp == NULL to indicate that the entry
337 		 * does not currently exist; we leave a pointer to
338 		 * the (locked) directory inode in ndp->ni_dvp.
339 		 *
340 		 * NB - if the directory is unlocked, then this
341 		 * information cannot be used.
342 		 */
343 		if (!lockparent)
344 			IUNLOCK(dp);
345 	}
346 	/*
347 	 * Insert name into cache (as non-existent) if appropriate.
348 	 */
349 	if (ndp->ni_makeentry)
350 		cache_enter(ndp);
351 	return (ENOENT);
352 
353 found:
354 	if (numdirpasses == 2)
355 		nchstats.ncs_pass2++;
356 	/*
357 	 * Check that directory length properly reflects presence
358 	 * of this entry.
359 	 */
360 	if (entryoffsetinblock + DIRSIZ(ep) > dp->i_size) {
361 		dirbad(dp, ndp->ni_offset, "i_size too small");
362 		dp->i_size = entryoffsetinblock + DIRSIZ(ep);
363 		dp->i_flag |= IUPD|ICHG;
364 	}
365 
366 	/*
367 	 * Found component in pathname.
368 	 * If the final component of path name, save information
369 	 * in the cache as to where the entry was found.
370 	 */
371 	if (*ndp->ni_next == '\0' && flag == LOOKUP)
372 		dp->i_diroff = ndp->ni_offset &~ (DIRBLKSIZ - 1);
373 
374 	/*
375 	 * If deleting, and at end of pathname, return
376 	 * parameters which can be used to remove file.
377 	 * If the wantparent flag isn't set, we return only
378 	 * the directory (in ndp->ni_dvp), otherwise we go
379 	 * on and lock the inode, being careful with ".".
380 	 */
381 	if (flag == DELETE && *ndp->ni_next == 0) {
382 		/*
383 		 * Write access to directory required to delete files.
384 		 */
385 		if (error = ufs_access(vdp, VWRITE, ndp->ni_cred))
386 			return (error);
387 		/*
388 		 * Return pointer to current entry in ndp->ni_offset,
389 		 * and distance past previous entry (if there
390 		 * is a previous entry in this block) in ndp->ni_count.
391 		 * Save directory inode pointer in ndp->ni_dvp for dirremove().
392 		 */
393 		if ((ndp->ni_offset&(DIRBLKSIZ-1)) == 0)
394 			ndp->ni_count = 0;
395 		else
396 			ndp->ni_count = ndp->ni_offset - prevoff;
397 		if (dp->i_number == ndp->ni_dent.d_ino) {
398 			VREF(vdp);
399 			ndp->ni_vp = vdp;
400 			return (0);
401 		}
402 		if (error = iget(dp, ndp->ni_dent.d_ino, &tdp))
403 			return (error);
404 		/*
405 		 * If directory is "sticky", then user must own
406 		 * the directory, or the file in it, else she
407 		 * may not delete it (unless she's root). This
408 		 * implements append-only directories.
409 		 */
410 		if ((dp->i_mode & ISVTX) &&
411 		    ndp->ni_cred->cr_uid != 0 &&
412 		    ndp->ni_cred->cr_uid != dp->i_uid &&
413 		    tdp->i_uid != ndp->ni_cred->cr_uid) {
414 			iput(tdp);
415 			return (EPERM);
416 		}
417 		ndp->ni_vp = ITOV(tdp);
418 		if (!lockparent)
419 			IUNLOCK(dp);
420 		return (0);
421 	}
422 
423 	/*
424 	 * If rewriting (RENAME), return the inode and the
425 	 * information required to rewrite the present directory
426 	 * Must get inode of directory entry to verify it's a
427 	 * regular file, or empty directory.
428 	 */
429 	if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
430 		if (error = ufs_access(vdp, VWRITE, ndp->ni_cred))
431 			return (error);
432 		/*
433 		 * Careful about locking second inode.
434 		 * This can only occur if the target is ".".
435 		 */
436 		if (dp->i_number == ndp->ni_dent.d_ino)
437 			return (EISDIR);
438 		if (error = iget(dp, ndp->ni_dent.d_ino, &tdp))
439 			return (error);
440 		ndp->ni_vp = ITOV(tdp);
441 		if (!lockparent)
442 			IUNLOCK(dp);
443 		return (0);
444 	}
445 
446 	/*
447 	 * Step through the translation in the name.  We do not `iput' the
448 	 * directory because we may need it again if a symbolic link
449 	 * is relative to the current directory.  Instead we save it
450 	 * unlocked as "pdp".  We must get the target inode before unlocking
451 	 * the directory to insure that the inode will not be removed
452 	 * before we get it.  We prevent deadlock by always fetching
453 	 * inodes from the root, moving down the directory tree. Thus
454 	 * when following backward pointers ".." we must unlock the
455 	 * parent directory before getting the requested directory.
456 	 * There is a potential race condition here if both the current
457 	 * and parent directories are removed before the `iget' for the
458 	 * inode associated with ".." returns.  We hope that this occurs
459 	 * infrequently since we cannot avoid this race condition without
460 	 * implementing a sophisticated deadlock detection algorithm.
461 	 * Note also that this simple deadlock detection scheme will not
462 	 * work if the file system has any hard links other than ".."
463 	 * that point backwards in the directory structure.
464 	 */
465 	pdp = dp;
466 	if (ndp->ni_isdotdot) {
467 		IUNLOCK(pdp);	/* race to get the inode */
468 		if (error = iget(dp, ndp->ni_dent.d_ino, &tdp)) {
469 			ILOCK(pdp);
470 			return (error);
471 		}
472 		if (lockparent && *ndp->ni_next == '\0')
473 			ILOCK(pdp);
474 		ndp->ni_vp = ITOV(tdp);
475 	} else if (dp->i_number == ndp->ni_dent.d_ino) {
476 		VREF(vdp);	/* we want ourself, ie "." */
477 		ndp->ni_vp = vdp;
478 	} else {
479 		if (error = iget(dp, ndp->ni_dent.d_ino, &tdp))
480 			return (error);
481 		if (!lockparent || *ndp->ni_next != '\0')
482 			IUNLOCK(pdp);
483 		ndp->ni_vp = ITOV(tdp);
484 	}
485 
486 	/*
487 	 * Insert name into cache if appropriate.
488 	 */
489 	if (ndp->ni_makeentry)
490 		cache_enter(ndp);
491 	return (0);
492 }
493 
494 
495 dirbad(ip, offset, how)
496 	struct inode *ip;
497 	off_t offset;
498 	char *how;
499 {
500 
501 	printf("%s: bad dir ino %d at offset %d: %s\n",
502 	    ip->i_fs->fs_fsmnt, ip->i_number, offset, how);
503 	panic("bad dir");
504 }
505 
506 /*
507  * Do consistency checking on a directory entry:
508  *	record length must be multiple of 4
509  *	entry must fit in rest of its DIRBLKSIZ block
510  *	record must be large enough to contain entry
511  *	name is not longer than MAXNAMLEN
512  *	name must be as long as advertised, and null terminated
513  */
514 dirbadentry(ep, entryoffsetinblock)
515 	register struct direct *ep;
516 	int entryoffsetinblock;
517 {
518 	register int i;
519 
520 	if ((ep->d_reclen & 0x3) != 0 ||
521 	    ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) ||
522 	    ep->d_reclen < DIRSIZ(ep) || ep->d_namlen > MAXNAMLEN)
523 		return (1);
524 	for (i = 0; i < ep->d_namlen; i++)
525 		if (ep->d_name[i] == '\0')
526 			return (1);
527 	return (ep->d_name[i]);
528 }
529 
530 /*
531  * Write a directory entry after a call to namei, using the parameters
532  * which it left in nameidata.  The argument ip is the inode which the
533  * new directory entry will refer to.  The nameidata field ndp->ni_dvp
534  * is a pointer to the directory to be written, which was left locked by
535  * namei.  Remaining parameters (ndp->ni_offset, ndp->ni_count) indicate
536  * how the space for the new entry is to be gotten.
537  */
538 direnter(ip, ndp)
539 	struct inode *ip;
540 	register struct nameidata *ndp;
541 {
542 	register struct direct *ep, *nep;
543 	register struct inode *dp = VTOI(ndp->ni_dvp);
544 	struct buf *bp;
545 	int loc, spacefree, error = 0;
546 	u_int dsize;
547 	int newentrysize;
548 	char *dirbuf;
549 
550 	ndp->ni_dent.d_ino = ip->i_number;
551 	newentrysize = DIRSIZ(&ndp->ni_dent);
552 	if (ndp->ni_count == 0) {
553 		/*
554 		 * If ndp->ni_count is 0, then namei could find no space in the
555 		 * directory. In this case ndp->ni_offset will be on a directory
556 		 * block boundary and we will write the new entry into a fresh
557 		 * block.
558 		 */
559 		if (ndp->ni_offset&(DIRBLKSIZ-1))
560 			panic("wdir: newblk");
561 		ndp->ni_dent.d_reclen = DIRBLKSIZ;
562 		ndp->ni_count = newentrysize;
563 		ndp->ni_resid = newentrysize;
564 		ndp->ni_base = (caddr_t)&ndp->ni_dent;
565 		ndp->ni_uioseg = UIO_SYSSPACE;
566 		error =
567 		    ufs_write(ndp->ni_dvp, &ndp->ni_uio, IO_SYNC, ndp->ni_cred);
568 		if (DIRBLKSIZ > dp->i_fs->fs_fsize) {
569 			panic("wdir: blksize"); /* XXX - should grow w/balloc */
570 		} else {
571 			dp->i_size = roundup(dp->i_size, DIRBLKSIZ);
572 			dp->i_flag |= ICHG;
573 		}
574 		iput(dp);
575 		return (error);
576 	}
577 
578 	/*
579 	 * If ndp->ni_count is non-zero, then namei found space for the new
580 	 * entry in the range ndp->ni_offset to ndp->ni_offset + ndp->ni_count.
581 	 * in the directory.  To use this space, we may have to compact
582 	 * the entries located there, by copying them together towards
583 	 * the beginning of the block, leaving the free space in
584 	 * one usable chunk at the end.
585 	 */
586 
587 	/*
588 	 * Increase size of directory if entry eats into new space.
589 	 * This should never push the size past a new multiple of
590 	 * DIRBLKSIZE.
591 	 *
592 	 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN.
593 	 */
594 	if (ndp->ni_offset + ndp->ni_count > dp->i_size)
595 		dp->i_size = ndp->ni_offset + ndp->ni_count;
596 	/*
597 	 * Get the block containing the space for the new directory entry.
598 	 */
599 	if (error = blkatoff(dp, ndp->ni_offset, (char **)&dirbuf, &bp)) {
600 		iput(dp);
601 		return (error);
602 	}
603 	/*
604 	 * Find space for the new entry.  In the simple case, the
605 	 * entry at offset base will have the space.  If it does
606 	 * not, then namei arranged that compacting the region
607 	 * ndp->ni_offset to ndp->ni_offset+ndp->ni_count would yield the space.
608 	 */
609 	ep = (struct direct *)dirbuf;
610 	dsize = DIRSIZ(ep);
611 	spacefree = ep->d_reclen - dsize;
612 	for (loc = ep->d_reclen; loc < ndp->ni_count; ) {
613 		nep = (struct direct *)(dirbuf + loc);
614 		if (ep->d_ino) {
615 			/* trim the existing slot */
616 			ep->d_reclen = dsize;
617 			ep = (struct direct *)((char *)ep + dsize);
618 		} else {
619 			/* overwrite; nothing there; header is ours */
620 			spacefree += dsize;
621 		}
622 		dsize = DIRSIZ(nep);
623 		spacefree += nep->d_reclen - dsize;
624 		loc += nep->d_reclen;
625 		bcopy((caddr_t)nep, (caddr_t)ep, dsize);
626 	}
627 	/*
628 	 * Update the pointer fields in the previous entry (if any),
629 	 * copy in the new entry, and write out the block.
630 	 */
631 	if (ep->d_ino == 0) {
632 		if (spacefree + dsize < newentrysize)
633 			panic("wdir: compact1");
634 		ndp->ni_dent.d_reclen = spacefree + dsize;
635 	} else {
636 		if (spacefree < newentrysize)
637 			panic("wdir: compact2");
638 		ndp->ni_dent.d_reclen = spacefree;
639 		ep->d_reclen = dsize;
640 		ep = (struct direct *)((char *)ep + dsize);
641 	}
642 	bcopy((caddr_t)&ndp->ni_dent, (caddr_t)ep, (u_int)newentrysize);
643 	error = bwrite(bp);
644 	dp->i_flag |= IUPD|ICHG;
645 	if (!error && ndp->ni_endoff && ndp->ni_endoff < dp->i_size)
646 		error = itrunc(dp, (u_long)ndp->ni_endoff, IO_SYNC);
647 	iput(dp);
648 	return (error);
649 }
650 
651 /*
652  * Remove a directory entry after a call to namei, using
653  * the parameters which it left in nameidata. The entry
654  * ni_offset contains the offset into the directory of the
655  * entry to be eliminated.  The ni_count field contains the
656  * size of the previous record in the directory.  If this
657  * is 0, the first entry is being deleted, so we need only
658  * zero the inode number to mark the entry as free.  If the
659  * entry isn't the first in the directory, we must reclaim
660  * the space of the now empty record by adding the record size
661  * to the size of the previous entry.
662  */
663 dirremove(ndp)
664 	register struct nameidata *ndp;
665 {
666 	register struct inode *dp = VTOI(ndp->ni_dvp);
667 	struct direct *ep;
668 	struct buf *bp;
669 	int error;
670 
671 	if (ndp->ni_count == 0) {
672 		/*
673 		 * First entry in block: set d_ino to zero.
674 		 */
675 		ndp->ni_dent.d_ino = 0;
676 		ndp->ni_count = ndp->ni_resid = DIRSIZ(&ndp->ni_dent);
677 		ndp->ni_base = (caddr_t)&ndp->ni_dent;
678 		ndp->ni_uioseg = UIO_SYSSPACE;
679 		error =
680 		    ufs_write(ndp->ni_dvp, &ndp->ni_uio, IO_SYNC, ndp->ni_cred);
681 	} else {
682 		/*
683 		 * Collapse new free space into previous entry.
684 		 */
685 		if (error = blkatoff(dp, ndp->ni_offset - ndp->ni_count,
686 		    (char **)&ep, &bp)) {
687 			return (error);
688 		}
689 		ep->d_reclen += ndp->ni_dent.d_reclen;
690 		error = bwrite(bp);
691 		dp->i_flag |= IUPD|ICHG;
692 	}
693 	return (error);
694 }
695 
696 /*
697  * Rewrite an existing directory entry to point at the inode
698  * supplied.  The parameters describing the directory entry are
699  * set up by a call to namei.
700  */
701 dirrewrite(dp, ip, ndp)
702 	struct inode *dp, *ip;
703 	struct nameidata *ndp;
704 {
705 
706 	ndp->ni_dent.d_ino = ip->i_number;
707 	ndp->ni_count = ndp->ni_resid = DIRSIZ(&ndp->ni_dent);
708 	ndp->ni_base = (caddr_t)&ndp->ni_dent;
709 	ndp->ni_uioseg = UIO_SYSSPACE;
710 	return (ufs_write(ITOV(dp), &ndp->ni_uio, IO_SYNC, ndp->ni_cred));
711 }
712 
713 /*
714  * Return buffer with contents of block "offset"
715  * from the beginning of directory "ip".  If "res"
716  * is non-zero, fill it in with a pointer to the
717  * remaining space in the directory.
718  */
719 blkatoff(ip, offset, res, bpp)
720 	struct inode *ip;
721 	off_t offset;
722 	char **res;
723 	struct buf **bpp;
724 {
725 	register struct fs *fs = ip->i_fs;
726 	daddr_t lbn = lblkno(fs, offset);
727 	int bsize = blksize(fs, ip, lbn);
728 	struct buf *bp;
729 	daddr_t bn;
730 	int error;
731 
732 	*bpp = 0;
733 	if (error = bread(ITOV(ip), lbn, bsize, NOCRED, &bp)) {
734 		brelse(bp);
735 		return (error);
736 	}
737 	if (res)
738 		*res = bp->b_un.b_addr + blkoff(fs, offset);
739 	*bpp = bp;
740 	return (0);
741 }
742 
743 /*
744  * Check if a directory is empty or not.
745  * Inode supplied must be locked.
746  *
747  * Using a struct dirtemplate here is not precisely
748  * what we want, but better than using a struct direct.
749  *
750  * NB: does not handle corrupted directories.
751  */
752 dirempty(ip, parentino, cred)
753 	register struct inode *ip;
754 	ino_t parentino;
755 	struct ucred *cred;
756 {
757 	register off_t off;
758 	struct dirtemplate dbuf;
759 	register struct direct *dp = (struct direct *)&dbuf;
760 	int error, count;
761 #define	MINDIRSIZ (sizeof (struct dirtemplate) / 2)
762 
763 	for (off = 0; off < ip->i_size; off += dp->d_reclen) {
764 		error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ,
765 		    off, UIO_SYSSPACE, IO_NODELOCKED, cred, &count);
766 		/*
767 		 * Since we read MINDIRSIZ, residual must
768 		 * be 0 unless we're at end of file.
769 		 */
770 		if (error || count != 0)
771 			return (0);
772 		/* avoid infinite loops */
773 		if (dp->d_reclen == 0)
774 			return (0);
775 		/* skip empty entries */
776 		if (dp->d_ino == 0)
777 			continue;
778 		/* accept only "." and ".." */
779 		if (dp->d_namlen > 2)
780 			return (0);
781 		if (dp->d_name[0] != '.')
782 			return (0);
783 		/*
784 		 * At this point d_namlen must be 1 or 2.
785 		 * 1 implies ".", 2 implies ".." if second
786 		 * char is also "."
787 		 */
788 		if (dp->d_namlen == 1)
789 			continue;
790 		if (dp->d_name[1] == '.' && dp->d_ino == parentino)
791 			continue;
792 		return (0);
793 	}
794 	return (1);
795 }
796 
797 /*
798  * Check if source directory is in the path of the target directory.
799  * Target is supplied locked, source is unlocked.
800  * The target is always iput() before returning.
801  */
802 checkpath(source, target, cred)
803 	struct inode *source, *target;
804 	struct ucred *cred;
805 {
806 	struct dirtemplate dirbuf;
807 	struct inode *ip;
808 	int error = 0;
809 
810 	ip = target;
811 	if (ip->i_number == source->i_number) {
812 		error = EEXIST;
813 		goto out;
814 	}
815 	if (ip->i_number == ROOTINO)
816 		goto out;
817 
818 	for (;;) {
819 		if ((ip->i_mode&IFMT) != IFDIR) {
820 			error = ENOTDIR;
821 			break;
822 		}
823 		error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)&dirbuf,
824 			sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE,
825 			IO_NODELOCKED, cred, (int *)0);
826 		if (error != 0)
827 			break;
828 		if (dirbuf.dotdot_namlen != 2 ||
829 		    dirbuf.dotdot_name[0] != '.' ||
830 		    dirbuf.dotdot_name[1] != '.') {
831 			error = ENOTDIR;
832 			break;
833 		}
834 		if (dirbuf.dotdot_ino == source->i_number) {
835 			error = EINVAL;
836 			break;
837 		}
838 		if (dirbuf.dotdot_ino == ROOTINO)
839 			break;
840 		iput(ip);
841 		if (error = iget(ip, dirbuf.dotdot_ino, &ip))
842 			break;
843 	}
844 
845 out:
846 	if (error == ENOTDIR)
847 		printf("checkpath: .. not a directory\n");
848 	if (ip != NULL)
849 		iput(ip);
850 	return (error);
851 }
852