xref: /titanic_44/usr/src/uts/common/fs/udfs/udf_dir.c (revision 0398691684c2596072212e4ca9d7033ad7ccfa54)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/t_lock.h>
30 #include <sys/param.h>
31 #include <sys/time.h>
32 #include <sys/systm.h>
33 #include <sys/sysmacros.h>
34 #include <sys/resource.h>
35 #include <sys/signal.h>
36 #include <sys/cred.h>
37 #include <sys/user.h>
38 #include <sys/buf.h>
39 #include <sys/vfs.h>
40 #include <sys/stat.h>
41 #include <sys/vnode.h>
42 #include <sys/mode.h>
43 #include <sys/proc.h>
44 #include <sys/disp.h>
45 #include <sys/file.h>
46 #include <sys/fcntl.h>
47 #include <sys/flock.h>
48 #include <sys/kmem.h>
49 #include <sys/uio.h>
50 #include <sys/dnlc.h>
51 #include <sys/conf.h>
52 #include <sys/errno.h>
53 #include <sys/mman.h>
54 #include <sys/fbuf.h>
55 #include <sys/pathname.h>
56 #include <sys/debug.h>
57 #include <sys/vmsystm.h>
58 #include <sys/cmn_err.h>
59 #include <sys/dirent.h>
60 #include <sys/errno.h>
61 #include <sys/modctl.h>
62 #include <sys/statvfs.h>
63 #include <sys/mount.h>
64 #include <sys/sunddi.h>
65 #include <sys/bootconf.h>
66 #include <sys/policy.h>
67 
68 #include <vm/hat.h>
69 #include <vm/page.h>
70 #include <vm/pvn.h>
71 #include <vm/as.h>
72 #include <vm/seg.h>
73 #include <vm/seg_map.h>
74 #include <vm/seg_kmem.h>
75 #include <vm/seg_vn.h>
76 #include <vm/rm.h>
77 #include <vm/page.h>
78 #include <sys/swap.h>
79 
80 
81 #include <fs/fs_subr.h>
82 
83 
84 #include <sys/fs/udf_volume.h>
85 #include <sys/fs/udf_inode.h>
86 
87 
88 struct slot {
89 	enum	{NONE, COMPACT, FOUND, EXIST} status;
90 	off_t	offset;		/* offset of area with free space */
91 	int	size;		/* size of area at slotoffset */
92 	struct	fbuf *fbp;	/* dir buf where slot is */
93 	struct file_id *ep;	/* pointer to slot */
94 	off_t	endoff;		/* last useful location found in search */
95 };
96 
97 
98 int32_t ud_dircheckforname(struct ud_inode *, char *, int,
99 		struct slot *, struct ud_inode **, uint8_t *, struct cred *);
100 int32_t ud_dirempty(struct ud_inode *, uint64_t, struct cred *);
101 int32_t str2cmp(char *, int32_t, char *, int32_t, char *, int32_t);
102 int32_t ud_dircheckpath(int32_t, struct ud_inode *, struct cred *);
103 int32_t ud_dirmakeinode(struct ud_inode *, struct ud_inode **,
104 	struct vattr *, enum de_op, struct cred *);
105 int32_t ud_diraddentry(struct ud_inode *, char *,
106 	enum de_op, int, struct slot *, struct ud_inode *,
107 	struct ud_inode *, struct cred *);
108 int32_t ud_dirmakedirect(struct ud_inode *, struct ud_inode *, struct cred *);
109 int32_t ud_dirrename(struct ud_inode *, struct ud_inode *,
110 	struct ud_inode *, struct ud_inode *, char *, uint8_t *,
111 	struct slot *, struct cred *);
112 int32_t ud_dirprepareentry(struct ud_inode *,
113 	struct slot *, uint8_t *, struct cred *);
114 int32_t ud_dirfixdotdot(struct ud_inode *, struct ud_inode *,
115 		struct ud_inode *);
116 int32_t ud_write_fid(struct ud_inode *, struct slot *, uint8_t *);
117 
118 int
119 ud_dirlook(struct ud_inode *dip,
120 	char *namep, struct ud_inode **ipp, struct cred *cr, int32_t skipdnlc)
121 {
122 	struct udf_vfs *udf_vfsp;
123 	int32_t error = 0, namelen, adhoc_search;
124 	u_offset_t offset, adhoc_offset, dirsize, end;
125 	struct vnode *dvp, *vp;
126 	struct fbuf *fbp;
127 	struct file_id *fid;
128 	uint8_t *fname, dummy[3];
129 	int32_t id_len, doingchk;
130 	uint32_t old_loc;
131 	uint16_t old_prn;
132 
133 	uint8_t *dname;
134 	uint8_t *buf = NULL;
135 
136 	ud_printf("ud_dirlook\n");
137 
138 	udf_vfsp = dip->i_udf;
139 
140 restart:
141 	doingchk = 0;
142 	old_prn = 0xFFFF;
143 	old_loc = 0;
144 	dvp = ITOV(dip);
145 	/*
146 	 * Check accessibility of directory.
147 	 */
148 	if (dip->i_type != VDIR) {
149 		return (ENOTDIR);
150 	}
151 	if (error = ud_iaccess(dip, IEXEC, cr)) {
152 		return (error);
153 	}
154 
155 	/*
156 	 * Null component name is synonym for directory being searched.
157 	 */
158 	if (*namep == '\0') {
159 		VN_HOLD(dvp);
160 		*ipp = dip;
161 		return (0);
162 	}
163 	namelen = strlen(namep);
164 	if ((namelen == 1) &&
165 		(namep[0] == '.') && (namep[1] == '\0')) {
166 		/* Current directory */
167 		VN_HOLD(dvp);
168 		*ipp = dip;
169 		dnlc_enter(dvp, namep, ITOV(*ipp));
170 		return (0);
171 	}
172 
173 	if ((!skipdnlc) && (vp = dnlc_lookup(dvp, namep))) {
174 		/* vp is already held from dnlc_lookup */
175 
176 		*ipp = VTOI(vp);
177 		return (0);
178 	}
179 
180 	dname = kmem_zalloc(1024, KM_SLEEP);
181 	buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
182 
183 	/*
184 	 * Read lock the inode we are searching.  You will notice that we
185 	 * didn't hold the read lock while searching the dnlc.  This means
186 	 * that the entry could now be in the dnlc.  This doesn't cause any
187 	 * problems because dnlc_enter won't add an entry if it is already
188 	 * there.
189 	 */
190 	rw_enter(&dip->i_rwlock, RW_READER);
191 
192 	/*
193 	 * Take care to look at dip->i_diroff only once, as it
194 	 * may be changing due to other threads/cpus.
195 	 */
196 
197 recheck:
198 	offset = dip->i_diroff;
199 	end = dirsize = dip->i_size;
200 
201 	if (offset > dirsize) {
202 		offset = 0;
203 	}
204 	adhoc_offset = offset;
205 	adhoc_search = (offset == 0) ? 1 : 2;
206 
207 	fbp = NULL;
208 
209 	while (adhoc_search--) {
210 		while (offset < end) {
211 			error = ud_get_next_fid(dip, &fbp,
212 					offset, &fid, &fname, buf);
213 			if (error != 0) {
214 				break;
215 			}
216 			if ((fid->fid_flags & FID_DELETED) == 0) {
217 				if (fid->fid_flags & FID_PARENT) {
218 					id_len = 2;
219 					fname = dummy;
220 					dummy[0] = '.';
221 					dummy[1] = '.';
222 					dummy[2] = '\0';
223 				} else {
224 					if ((error = ud_uncompress(
225 						fid->fid_idlen, &id_len,
226 						fname, dname)) != 0) {
227 						break;
228 					}
229 					fname = (uint8_t *)dname;
230 					fname[id_len] = '\0';
231 				}
232 				if ((namelen == id_len) &&
233 					(strncmp(namep, (caddr_t)fname,
234 							namelen) == 0)) {
235 					uint32_t loc;
236 					uint16_t prn;
237 
238 
239 					loc = SWAP_32(fid->fid_icb.lad_ext_loc);
240 					prn = SWAP_16(fid->fid_icb.lad_ext_prn);
241 					dip->i_diroff = offset +
242 							FID_LEN(fid);
243 
244 					if (doingchk) {
245 						if ((loc == old_loc) &&
246 							(prn == old_prn)) {
247 							goto checkok;
248 						} else {
249 							if (fbp != NULL) {
250 								fbrelse(fbp,
251 								S_READ);
252 								fbp = NULL;
253 							}
254 							VN_RELE(ITOV(*ipp));
255 							rw_exit(&dip->i_rwlock);
256 							goto restart;
257 						}
258 						/* NOTREACHED */
259 					}
260 
261 					if (namelen == 2 &&
262 						fname[0] == '.' &&
263 						fname[1] == '.') {
264 
265 						struct timespec32 omtime;
266 
267 						omtime = dip->i_mtime;
268 						rw_exit(&dip->i_rwlock);
269 
270 						error = ud_iget(dip->i_vfs, prn,
271 							loc, ipp, NULL, cr);
272 
273 						rw_enter(&dip->i_rwlock,
274 							RW_READER);
275 
276 						if (error) {
277 							goto done;
278 						}
279 
280 						if ((omtime.tv_sec !=
281 							dip->i_mtime.tv_sec) ||
282 							(omtime.tv_nsec !=
283 							dip->i_mtime.tv_nsec)) {
284 
285 							doingchk = 1;
286 							old_prn = prn;
287 							old_loc = loc;
288 							dip->i_diroff = 0;
289 							if (fbp != NULL) {
290 								fbrelse(fbp,
291 								S_READ);
292 								fbp = NULL;
293 							}
294 							goto recheck;
295 						}
296 					} else {
297 
298 						error = ud_iget(dip->i_vfs, prn,
299 							loc, ipp, NULL, cr);
300 					}
301 checkok:
302 					if (error == 0) {
303 						dnlc_enter(dvp, namep,
304 							ITOV(*ipp));
305 					}
306 					goto done;
307 				}
308 			}
309 			offset += FID_LEN(fid);
310 		}
311 		if (fbp != NULL) {
312 			fbrelse(fbp, S_READ);
313 			fbp = NULL;
314 		}
315 		end = adhoc_offset;
316 		offset = 0;
317 	}
318 	error = ENOENT;
319 done:
320 	kmem_free(buf, udf_vfsp->udf_lbsize);
321 	kmem_free(dname, 1024);
322 	if (fbp != NULL) {
323 		fbrelse(fbp, S_READ);
324 	}
325 	rw_exit(&dip->i_rwlock);
326 	return (error);
327 }
328 
329 int
330 ud_direnter(struct ud_inode *tdp,
331 	char *namep, enum de_op op, struct ud_inode *sdp, struct ud_inode *sip,
332 	struct vattr *vap, struct ud_inode **ipp, struct cred *cr)
333 {
334 	struct udf_vfs *udf_vfsp;
335 	struct ud_inode *tip;
336 	struct slot slot;
337 	int32_t namlen, err;
338 	char *s;
339 
340 	uint8_t *buf = NULL;
341 
342 	ud_printf("ud_direnter\n");
343 
344 	udf_vfsp = tdp->i_udf;
345 	/* don't allow '/' characters in pathname component */
346 	for (s = namep, namlen = 0; *s; s++, namlen++) {
347 		if (*s == '/') {
348 			return (EACCES);
349 		}
350 	}
351 
352 	if (namlen == 0) {
353 		cmn_err(CE_WARN, "name length == 0 in ud_direnter");
354 		return (EINVAL);
355 	}
356 
357 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
358 	/*
359 	 * If name is "." or ".." then if this is a create look it up
360 	 * and return EEXIST.  Rename or link TO "." or ".." is forbidden.
361 	 */
362 	if (namep[0] == '.' &&
363 	    (namlen == 1 || (namlen == 2 && namep[1] == '.'))) {
364 		if (op == DE_RENAME) {
365 			return (EINVAL);	/* *SIGH* should be ENOTEMPTY */
366 		}
367 		if (ipp) {
368 			/*
369 			 * ud_dirlook will acquire the i_rwlock
370 			 */
371 			rw_exit(&tdp->i_rwlock);
372 			if (err = ud_dirlook(tdp, namep, ipp, cr, 0)) {
373 				rw_enter(&tdp->i_rwlock, RW_WRITER);
374 				return (err);
375 			}
376 			rw_enter(&tdp->i_rwlock, RW_WRITER);
377 		}
378 		return (EEXIST);
379 	}
380 
381 	tip = NULL;
382 	slot.status = NONE;
383 	slot.offset = 0;
384 	slot.size = 0;
385 	slot.fbp = NULL;
386 	slot.ep = NULL;
387 	slot.endoff = 0;
388 
389 	/*
390 	 * For link and rename lock the source entry and check the link count
391 	 * to see if it has been removed while it was unlocked.  If not, we
392 	 * increment the link count and force the inode to disk to make sure
393 	 * that it is there before any directory entry that points to it.
394 	 */
395 	if (op == DE_LINK || op == DE_RENAME) {
396 		rw_enter(&sip->i_contents, RW_WRITER);
397 		if (sip->i_nlink == 0) {
398 			rw_exit(&sip->i_contents);
399 			return (ENOENT);
400 		}
401 		if (sip->i_nlink == MAXLINK) {
402 			rw_exit(&sip->i_contents);
403 			return (EMLINK);
404 		}
405 
406 		sip->i_nlink++;
407 		mutex_enter(&sip->i_tlock);
408 		sip->i_flag |= ICHG;
409 		mutex_exit(&sip->i_tlock);
410 		ud_iupdat(sip, 1);
411 		rw_exit(&sip->i_contents);
412 	}
413 	/*
414 	 * If target directory has not been removed, then we can consider
415 	 * allowing file to be created.
416 	 */
417 	if (tdp->i_nlink == 0) {
418 		err = ENOENT;
419 		goto out2;
420 	}
421 	/*
422 	 * Check accessibility of directory.
423 	 */
424 	if (tdp->i_type != VDIR) {
425 		err = ENOTDIR;
426 		goto out2;
427 	}
428 	/*
429 	 * Execute access is required to search the directory.
430 	 */
431 	if (err = ud_iaccess(tdp, IEXEC, cr)) {
432 		goto out2;
433 	}
434 	/*
435 	 * If this is a rename of a directory and the parent is
436 	 * different (".." must be changed), then the source
437 	 * directory must not be in the directory hierarchy
438 	 * above the target, as this would orphan everything
439 	 * below the source directory.  Also the user must have
440 	 * write permission in the source so as to be able to
441 	 * change "..".
442 	 */
443 	if (op == DE_RENAME) {
444 		if (sip == tdp) {
445 			err = EINVAL;
446 			goto out2;
447 		}
448 		rw_enter(&sip->i_contents, RW_READER);
449 		if ((sip->i_type == VDIR) && (sdp != tdp)) {
450 			uint32_t blkno;
451 
452 			if ((err = ud_iaccess(sip, IWRITE, cr))) {
453 				rw_exit(&sip->i_contents);
454 				goto out2;
455 			}
456 			blkno = sip->i_icb_lbano;
457 			rw_exit(&sip->i_contents);
458 			if ((err = ud_dircheckpath(blkno, tdp, cr))) {
459 				goto out2;
460 			}
461 		} else {
462 			rw_exit(&sip->i_contents);
463 		}
464 	}
465 
466 	/*
467 	 * Search for the entry. Return VN_HELD tip if found.
468 	 */
469 	buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
470 	rw_enter(&tdp->i_contents, RW_WRITER);
471 	if (err = ud_dircheckforname(tdp,
472 			namep, namlen, &slot, &tip, buf, cr)) {
473 		goto out;
474 	}
475 	if (tip) {
476 		switch (op) {
477 			case DE_CREATE :
478 			case DE_MKDIR :
479 				if (ipp) {
480 					*ipp = tip;
481 					err = EEXIST;
482 				} else {
483 					VN_RELE(ITOV(tip));
484 				}
485 				break;
486 			case DE_RENAME :
487 				err = ud_dirrename(sdp, sip, tdp, tip,
488 						namep, buf, &slot, cr);
489 				/*
490 				 * We used to VN_RELE() here, but this
491 				 * was moved down so that we could send
492 				 * a vnevent after the locks were dropped.
493 				 */
494 				break;
495 			case DE_LINK :
496 				/*
497 				 * Can't link to an existing file.
498 				 */
499 				VN_RELE(ITOV(tip));
500 				err = EEXIST;
501 				break;
502 		}
503 	} else {
504 		/*
505 		 * The entry does not exist. Check write permission in
506 		 * directory to see if entry can be created.
507 		 */
508 		if (err = ud_iaccess(tdp, IWRITE, cr)) {
509 			goto out;
510 		}
511 		if ((op == DE_CREATE) || (op == DE_MKDIR)) {
512 			/*
513 			 * Make new inode and directory entry as required.
514 			 */
515 			if (err = ud_dirmakeinode(tdp, &sip, vap, op, cr))
516 				goto out;
517 		}
518 		if (err = ud_diraddentry(tdp, namep, op,
519 		    namlen, &slot, sip, sdp, cr)) {
520 			if ((op == DE_CREATE) || (op == DE_MKDIR)) {
521 				/*
522 				 * Unmake the inode we just made.
523 				 */
524 				rw_enter(&sip->i_contents, RW_WRITER);
525 				if (sip->i_type == VDIR) {
526 					tdp->i_nlink--;
527 				}
528 				sip->i_nlink = 0;
529 				mutex_enter(&sip->i_tlock);
530 				sip->i_flag |= ICHG;
531 				mutex_exit(&sip->i_tlock);
532 				rw_exit(&sip->i_contents);
533 				VN_RELE(ITOV(sip));
534 				sip = NULL;
535 			}
536 		} else if (ipp) {
537 			*ipp = sip;
538 		} else if ((op == DE_CREATE) || (op == DE_MKDIR)) {
539 			VN_RELE(ITOV(sip));
540 		}
541 	}
542 out:
543 	if (buf != NULL) {
544 		kmem_free(buf, udf_vfsp->udf_lbsize);
545 	}
546 	if (slot.fbp) {
547 		fbrelse(slot.fbp, S_OTHER);
548 	}
549 	rw_exit(&tdp->i_contents);
550 
551 	if (op == DE_RENAME) {
552 		/*
553 		 * If it's all good, send events after locks are dropped
554 		 * but before vnodes are released.
555 		 */
556 		if (err == 0) {
557 			if (tip) {
558 				vnevent_rename_dest(ITOV(tip), ITOV(tdp),
559 				    namep);
560 			}
561 
562 			if (sdp != tdp) {
563 				vnevent_rename_dest_dir(ITOV(tdp));
564 			}
565 		}
566 
567 		/*
568 		 * The following VN_RELE() was moved from the
569 		 * DE_RENAME case above
570 		 */
571 		if (tip) {
572 			VN_RELE(ITOV(tip));
573 		}
574 	}
575 
576 out2:
577 	if (err && ((op == DE_LINK) || (op == DE_RENAME))) {
578 		/*
579 		 * Undo bumped link count.
580 		 */
581 		rw_enter(&sip->i_contents, RW_WRITER);
582 		sip->i_nlink--;
583 		rw_exit(&sip->i_contents);
584 
585 		mutex_enter(&sip->i_tlock);
586 		sip->i_flag |= ICHG;
587 		mutex_exit(&sip->i_tlock);
588 	}
589 	return (err);
590 }
591 
592 /*
593  * Locking i_contents in this
594  * function seems to be really weird
595  */
596 int
597 ud_dirremove(struct ud_inode *dp,
598 	char *namep, struct ud_inode *oip, struct vnode *cdir,
599 	enum dr_op op, struct cred *cr)
600 {
601 	struct udf_vfs *udf_vfsp;
602 	int32_t namelen, err = 0;
603 	struct slot slot;
604 	struct ud_inode *ip;
605 	mode_t mode;
606 	struct file_id *fid;
607 	uint8_t *buf = NULL;
608 	uint32_t tbno;
609 
610 	ud_printf("ud_dirremove\n");
611 
612 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
613 
614 	udf_vfsp = dp->i_udf;
615 	namelen = (int)strlen(namep);
616 	if (namelen == 0) {
617 		cmn_err(CE_WARN, "name length == 0 in ud_dirremove");
618 		return (EINVAL);
619 	}
620 
621 	/*
622 	 * return err when removing . and ..
623 	 */
624 	if (namep[0] == '.') {
625 		if (namelen == 1) {
626 			return (EINVAL);
627 		} else if (namelen == 2 && namep[1] == '.') {
628 			return (EEXIST);	/* SIGH should be ENOTEMPTY */
629 		}
630 	}
631 
632 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
633 
634 	/*
635 	 * Check accessibility of directory.
636 	 */
637 	if (dp->i_type != VDIR) {
638 		return (ENOTDIR);
639 	}
640 
641 	ip = NULL;
642 	slot.status = FOUND;	/* don't need to look for empty slot */
643 	slot.offset = 0;
644 	slot.size = 0;
645 	slot.fbp = NULL;
646 	slot.ep = NULL;
647 	slot.endoff = 0;
648 	/*
649 	 * Execute access is required to search the directory.
650 	 * Access for write is interpreted as allowing
651 	 * deletion of files in the directory.
652 	 */
653 	if (err = ud_iaccess(dp, IEXEC|IWRITE, cr)) {
654 		return (err);
655 	}
656 
657 	buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
658 
659 	rw_enter(&dp->i_contents, RW_WRITER);
660 
661 	if (err = ud_dircheckforname(dp,
662 			namep, namelen, &slot, &ip, buf, cr)) {
663 		goto out_novfs;
664 	}
665 	if (ip == NULL) {
666 		err = ENOENT;
667 		goto out_novfs;
668 	}
669 	if (oip && oip != ip) {
670 		err = ENOENT;
671 		goto out_novfs;
672 	}
673 
674 	if ((mode = ip->i_type) == VDIR) {
675 		/*
676 		 * vn_vfswlock() prevents races between mount and rmdir.
677 		 */
678 		if (vn_vfswlock(ITOV(ip))) {
679 			err = EBUSY;
680 			goto out_novfs;
681 		}
682 		if (vn_mountedvfs(ITOV(ip)) != NULL && op != DR_RENAME) {
683 			err = EBUSY;
684 			goto out;
685 		}
686 		/*
687 		 * If we are removing a directory, get a lock on it.
688 		 * If the directory is empty, it will stay empty until
689 		 * we can remove it.
690 		 */
691 		rw_enter(&ip->i_rwlock, RW_READER);
692 	}
693 	/* We must be holding i_contents */
694 	rw_enter(&ip->i_contents, RW_READER);
695 
696 	if (err = ud_sticky_remove_access(dp, ip, cr)) {
697 		rw_exit(&ip->i_contents);
698 		if (mode == VDIR) {
699 			rw_exit(&ip->i_rwlock);
700 		}
701 		goto out;
702 	}
703 	if (op == DR_RMDIR) {
704 		/*
705 		 * For rmdir(2), some special checks are required.
706 		 * (a) Don't remove any alias of the parent (e.g. ".").
707 		 * (b) Don't remove the current directory.
708 		 * (c) Make sure the entry is (still) a directory.
709 		 * (d) Make sure the directory is empty.
710 		 */
711 
712 		if (dp == ip || ITOV(ip) == cdir) {
713 			err = EINVAL;
714 		} else if (ip->i_type != VDIR) {
715 			err = ENOTDIR;
716 		} else if ((ip->i_nlink != 1) ||
717 			(!ud_dirempty(ip, dp->i_uniqid, cr))) {
718 			/*
719 			 * Directories do not have an
720 			 * entry for "." so only one link
721 			 * will be there
722 			 */
723 			err = EEXIST;	/* SIGH should be ENOTEMPTY */
724 		}
725 		if (err) {
726 			rw_exit(&ip->i_contents);
727 			if (mode == VDIR) {
728 				rw_exit(&ip->i_rwlock);
729 			}
730 			goto out;
731 		}
732 	} else if (op == DR_REMOVE)  {
733 		/*
734 		 * unlink(2) requires a different check: allow only
735 		 * privileged processes to unlink a directory.
736 		 */
737 		struct vnode *vp = ITOV(ip);
738 
739 		if (vp->v_type == VDIR &&
740 		    secpolicy_fs_linkdir(cr, vp->v_vfsp)) {
741 			err = EPERM;
742 			rw_exit(&ip->i_contents);
743 			rw_exit(&ip->i_rwlock);
744 			goto out;
745 		}
746 	}
747 	rw_exit(&ip->i_contents);
748 
749 	/*
750 	 * Remove the cache'd entry, if any.
751 	 */
752 	dnlc_remove(ITOV(dp), namep);
753 
754 	/*
755 	 * We can collapse all the directory
756 	 * entries that are deleted into one big entry
757 	 * but the better way is to
758 	 * defer it till next directory entry
759 	 * creation. where we can do this
760 	 * in a more efficient way
761 	 */
762 	fid = slot.ep;
763 
764 	/*
765 	 * If this is the last entry
766 	 * just truncate the file instead
767 	 * of marking it deleted
768 	 */
769 	if ((slot.offset + FID_LEN(fid)) == dp->i_size) {
770 		fbrelse(slot.fbp, S_OTHER);
771 		if ((err = ud_itrunc(dp, slot.offset, 0, cr)) != 0) {
772 			goto out;
773 		}
774 	} else {
775 		fid->fid_flags |= FID_DELETED;
776 
777 		if ((err = ud_ip_off2bno(dp, slot.offset, &tbno)) != 0) {
778 			goto out;
779 		}
780 
781 		ud_make_tag(dp->i_udf, &fid->fid_tag,
782 			UD_FILE_ID_DESC, tbno, FID_LEN(fid));
783 
784 		err = ud_write_fid(dp, &slot, buf);
785 	}
786 
787 	slot.fbp = NULL;
788 
789 	/*
790 	 * If we were removing a directory, it is 'gone' now so we can
791 	 * unlock it.
792 	 */
793 	if (mode == VDIR) {
794 		rw_exit(&ip->i_rwlock);
795 	}
796 
797 	mutex_enter(&dp->i_tlock);
798 	dp->i_flag |= IUPD|ICHG;
799 	mutex_exit(&dp->i_tlock);
800 	mutex_enter(&ip->i_tlock);
801 	ip->i_flag |= ICHG;
802 	mutex_exit(&ip->i_tlock);
803 
804 	if (err != 0) {
805 		goto out;
806 	}
807 
808 	rw_enter(&ip->i_contents, RW_WRITER);
809 
810 	/*
811 	 * Now dispose of the inode.
812 	 */
813 	if (ip->i_nlink > 0) {
814 		if ((op == DR_RMDIR) && (ip->i_type == VDIR)) {
815 			/*
816 			 * Decrement by 1 because there is no "."
817 			 * Clear the inode, but there may be other hard
818 			 * links so don't free the inode.
819 			 * Decrement the dp linkcount because we're
820 			 * trashing the ".." entry.
821 			 */
822 			ip->i_nlink --;
823 			dp->i_nlink--;
824 			dnlc_remove(ITOV(ip), ".");
825 			dnlc_remove(ITOV(ip), "..");
826 /*
827  *			(void) ud_itrunc(ip, 0, 0, cr);
828  */
829 		} else {
830 			ip->i_nlink--;
831 		}
832 	}
833 	ITIMES_NOLOCK(dp);
834 	ITIMES_NOLOCK(ip);
835 	rw_exit(&ip->i_contents);
836 out:
837 	if (mode == VDIR) {
838 		vn_vfsunlock(ITOV(ip));
839 	}
840 out_novfs:
841 	ASSERT(RW_WRITE_HELD(&dp->i_contents));
842 
843 	if (slot.fbp != NULL) {
844 		fbrelse(slot.fbp, S_OTHER);
845 	}
846 	rw_exit(&dp->i_contents);
847 
848 	if (ip) {
849 		/*
850 		 * If no errors, send any events after locks are dropped,
851 		 * but before the VN_RELE().
852 		 */
853 		if (err == 0) {
854 			if (op == DR_REMOVE) {
855 				vnevent_remove(ITOV(ip), ITOV(dp), namep);
856 			} else if (op == DR_RMDIR) {
857 				vnevent_rmdir(ITOV(ip), ITOV(dp), namep);
858 			}
859 		}
860 		VN_RELE(ITOV(ip));
861 	}
862 
863 	kmem_free(buf, udf_vfsp->udf_lbsize);
864 	return (err);
865 }
866 
867 int
868 ud_dircheckforname(struct ud_inode *tdp,
869 	char *namep, int32_t namelen, struct slot *slotp,
870 	struct ud_inode **ipp, uint8_t *buf, struct cred *cr)
871 {
872 	struct udf_vfs *udf_vfsp;
873 	uint32_t dirsize, offset;
874 	struct fbuf *fbp;
875 	struct file_id *fid;
876 	int32_t sz, error = 0, sz_req, matched = 0;
877 	uint8_t *nm;
878 
879 	uint8_t *dname;
880 	int32_t id_len;
881 
882 	ud_printf("ud_dircheckforname\n");
883 
884 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
885 	fbp = NULL;
886 
887 	dname = (uint8_t *)kmem_zalloc(1024, KM_SLEEP);
888 
889 	udf_vfsp = tdp->i_udf;
890 
891 	offset = 0;
892 	dirsize = tdp->i_size;
893 
894 	if (slotp->status != FOUND) {
895 		int32_t temp;
896 
897 		temp = 1024; /* set to size of dname allocated above */
898 		if ((error = ud_compress(namelen, &temp,
899 				(uint8_t *)namep, dname)) != 0) {
900 			goto end;
901 		}
902 		sz_req = F_LEN + temp;
903 		sz_req  = (sz_req + 3) & ~3;
904 	}
905 
906 	while (offset < dirsize) {
907 		if ((error = ud_get_next_fid(tdp, &fbp,
908 				offset, &fid, &nm, buf)) != 0) {
909 			break;
910 		}
911 		if ((error = ud_uncompress(fid->fid_idlen,
912 				&id_len, nm, dname)) != 0) {
913 			break;
914 		}
915 		if ((fid->fid_flags & FID_DELETED) == 0) {
916 			/* Check for name match */
917 			if (((namelen == id_len) &&
918 				(strncmp(namep, (caddr_t)dname, namelen) ==
919 							0)) ||
920 				((fid->fid_flags & FID_PARENT) &&
921 				(namep[0] == '.' &&
922 					(namelen == 1 ||
923 					(namelen == 2 && namep[1] == '.'))))) {
924 
925 				tdp->i_diroff = offset;
926 				if ((fid->fid_flags & FID_PARENT) &&
927 					(namelen == 1) && (namep[0] == '.')) {
928 					struct vnode *vp = ITOV(tdp);
929 
930 					*ipp = tdp;
931 					VN_HOLD(vp);
932 				} else {
933 					uint16_t prn;
934 					uint32_t loc;
935 
936 					prn = SWAP_16(fid->fid_icb.lad_ext_prn);
937 					loc = SWAP_32(fid->fid_icb.lad_ext_loc);
938 					if ((error = ud_iget(tdp->i_vfs, prn,
939 						loc, ipp, NULL, cr)) != 0) {
940 
941 						fbrelse(fbp, S_OTHER);
942 						goto end;
943 					}
944 				}
945 				slotp->status = EXIST;
946 				slotp->offset = offset;
947 				slotp->size = FID_LEN(fid);
948 				slotp->fbp = fbp;
949 				slotp->ep = fid;
950 				slotp->endoff = 0;
951 				goto end;
952 			}
953 		} else {
954 			/*
955 			 * see if we need to find an
956 			 * empty slot and the current slot
957 			 * matches
958 			 */
959 			if ((slotp->status != FOUND) ||
960 				(matched == 0)) {
961 				sz = FID_LEN(fid);
962 				if (sz == sz_req) {
963 					slotp->status = FOUND;
964 					slotp->offset = offset;
965 					slotp->size = sz;
966 				}
967 				if (matched == 0) {
968 					if ((namelen == id_len) &&
969 						(strncmp(namep, (caddr_t)dname,
970 						namelen) == 0)) {
971 						matched = 1;
972 						slotp->status = FOUND;
973 						slotp->offset = offset;
974 						slotp->size = sz;
975 					}
976 				}
977 			}
978 		}
979 		offset += FID_LEN(fid);
980 	}
981 	if (fbp) {
982 		fbrelse(fbp, S_OTHER);
983 	}
984 	if (slotp->status == NONE) {
985 		/*
986 		 * We didn't find a slot; the new directory entry should be put
987 		 * at the end of the directory.  Return an indication of where
988 		 * this is, and set "endoff" to zero; since we're going to have
989 		 * to extend the directory, we're certainly not going to
990 		 * trucate it.
991 		 */
992 		slotp->offset = dirsize;
993 		if (tdp->i_desc_type == ICB_FLAG_ONE_AD) {
994 			slotp->size = tdp->i_max_emb - tdp->i_size;
995 		} else {
996 			slotp->size = udf_vfsp->udf_lbsize -
997 				slotp->offset & udf_vfsp->udf_lbmask;
998 		}
999 		slotp->endoff = 0;
1000 	}
1001 
1002 	*ipp = NULL;
1003 end:
1004 	kmem_free((caddr_t)dname, 1024);
1005 	return (error);
1006 }
1007 
1008 /*
1009  * Return 1 if the dir has all files
1010  * deleted except the parent
1011  * else return 0
1012  */
1013 /* ARGSUSED */
1014 int
1015 ud_dirempty(struct ud_inode *ip, uint64_t ino, struct cred *cr)
1016 {
1017 	offset_t off;
1018 	int32_t empty = 1, error, count, entry_len, rcount;
1019 	struct file_id *fid;
1020 	caddr_t addr;
1021 	uint32_t tbno;
1022 	int32_t	desc_len;
1023 
1024 	ud_printf("ud_dirempty\n");
1025 
1026 	ASSERT(RW_LOCK_HELD(&ip->i_contents));
1027 
1028 	if (ip->i_size == 0) {
1029 		return (empty);
1030 	}
1031 
1032 	desc_len = 1024;
1033 	addr = kmem_zalloc(desc_len, KM_SLEEP);
1034 	fid = (struct file_id *)addr;
1035 
1036 	for (off = 0; off < ip->i_size; off += entry_len) {
1037 
1038 		/*
1039 		 * First read fid
1040 		 * and verify checksum
1041 		 */
1042 
1043 		rcount = sizeof (struct file_id);
1044 		error = ud_rdwri(UIO_READ, FREAD,
1045 				ip, addr, rcount, off,
1046 				UIO_SYSSPACE, &count, cr);
1047 		if ((error != 0) || (count != 0)) {
1048 			empty = 0;
1049 			break;
1050 		}
1051 
1052 		if ((error = ud_ip_off2bno(ip, off, &tbno)) != 0) {
1053 			empty = 0;
1054 			break;
1055 		}
1056 
1057 		/*
1058 		 * We verify the tag id and also the FID_LEN.
1059 		 * FID_LEN should be <= desc_len.
1060 		 */
1061 		if (ud_verify_tag_and_desc(&fid->fid_tag,
1062 		    UD_FILE_ID_DESC,
1063 		    tbno, 0, desc_len) != 0) {
1064 		/* Corrupted directory */
1065 			empty = 0;
1066 			break;
1067 		}
1068 
1069 		/*
1070 		 * Read the fid + iulen + len
1071 		 * Now verify both checksum andCRC
1072 		 */
1073 
1074 		rcount = FID_LEN(fid);
1075 		error = ud_rdwri(UIO_READ, FREAD,
1076 				ip, addr, rcount, off,
1077 				UIO_SYSSPACE, &count, cr);
1078 		if ((error != 0) || (count != 0)) {
1079 			empty = 0;
1080 			break;
1081 		}
1082 		/*
1083 		 * Now that the entire decsriptor is read we verify the
1084 		 * crc.
1085 		 */
1086 		if (ud_verify_tag_and_desc(&fid->fid_tag,
1087 		    UD_FILE_ID_DESC,
1088 		    tbno,
1089 		    1, rcount) != 0) {
1090 			/* Corrupted directory */
1091 			empty = 0;
1092 			break;
1093 		}
1094 
1095 		/*
1096 		 * Is the file deleted
1097 		 */
1098 
1099 		if ((fid->fid_flags & FID_DELETED) == 0) {
1100 			if ((fid->fid_flags & FID_PARENT) == 0) {
1101 				empty = 0;
1102 				break;
1103 			}
1104 		}
1105 		entry_len = FID_LEN(fid);
1106 	}
1107 
1108 	kmem_free(addr, 1024);
1109 
1110 	return (empty);
1111 }
1112 
1113 
1114 int
1115 ud_dircheckpath(int32_t blkno,
1116 	struct ud_inode *target, struct cred *cr)
1117 {
1118 	int32_t err = 0;
1119 	struct vfs *vfsp;
1120 	struct udf_vfs *udf_vfsp;
1121 	struct fbuf *fbp;
1122 	struct file_id *fid;
1123 	struct ud_inode *ip, *tip;
1124 	uint16_t prn;
1125 	uint32_t lbno, dummy, tbno;
1126 	daddr_t parent_icb_loc;
1127 
1128 	ud_printf("ud_dircheckpath\n");
1129 
1130 	udf_vfsp = target->i_udf;
1131 	ip = target;
1132 
1133 	ASSERT(udf_vfsp != NULL);
1134 	ASSERT(MUTEX_HELD(&target->i_udf->udf_rename_lck));
1135 	ASSERT(RW_WRITE_HELD(&ip->i_rwlock));
1136 
1137 	if (ip->i_icb_lbano == blkno) {
1138 		err = EINVAL;
1139 		goto out;
1140 	}
1141 	if (ip->i_icb_lbano == udf_vfsp->udf_root_blkno) {
1142 		goto out;
1143 	}
1144 
1145 	/*
1146 	 * Search back through the directory tree, using the PARENT entries
1147 	 * Fail any attempt to move a directory into an ancestor directory.
1148 	 */
1149 	for (;;) {
1150 		if ((err = fbread(ITOV(ip), 0,
1151 			udf_vfsp->udf_lbsize, S_READ, &fbp)) != 0) {
1152 			break;
1153 		}
1154 
1155 		if ((err = ud_ip_off2bno(ip, 0, &tbno)) != 0) {
1156 			break;
1157 		}
1158 		fid = (struct file_id *)fbp->fb_addr;
1159 		/* IS this a valid file_identifier */
1160 		if (ud_verify_tag_and_desc(&fid->fid_tag,
1161 		    UD_FILE_ID_DESC,
1162 		    tbno,
1163 		    1, udf_vfsp->udf_lbsize) != 0) {
1164 			break;
1165 		}
1166 		if ((fid->fid_flags & FID_DELETED) != 0) {
1167 			break;
1168 		}
1169 		if ((fid->fid_flags & FID_PARENT) == 0) {
1170 			/*
1171 			 * This cannot happen unless
1172 			 * something is grossly wrong
1173 			 * First entry has to be parent
1174 			 */
1175 			break;
1176 		}
1177 		prn = SWAP_16(fid->fid_icb.lad_ext_prn);
1178 		lbno = SWAP_32(fid->fid_icb.lad_ext_loc);
1179 		parent_icb_loc = ud_xlate_to_daddr(udf_vfsp,
1180 				prn, lbno, 1, &dummy);
1181 		ASSERT(dummy == 1);
1182 		if (parent_icb_loc == blkno) {
1183 			err = EINVAL;
1184 			break;
1185 		}
1186 		vfsp = ip->i_vfs;
1187 		udf_vfsp = ip->i_udf;
1188 		if (parent_icb_loc == udf_vfsp->udf_root_blkno) {
1189 			break;
1190 		}
1191 		if (fbp != NULL) {
1192 			fbrelse(fbp, S_OTHER);
1193 			fbp = NULL;
1194 		}
1195 		if (ip != target) {
1196 			rw_exit(&ip->i_rwlock);
1197 			VN_RELE(ITOV(ip));
1198 		}
1199 
1200 		/*
1201 		 * Race to get the inode.
1202 		 */
1203 		if (err = ud_iget(vfsp, prn, lbno, &tip, NULL, cr)) {
1204 			ip = NULL;
1205 			break;
1206 		}
1207 		ip = tip;
1208 		rw_enter(&ip->i_rwlock, RW_READER);
1209 	}
1210 	if (fbp) {
1211 		fbrelse(fbp, S_OTHER);
1212 	}
1213 out:
1214 	if (ip) {
1215 		if (ip != target) {
1216 			rw_exit(&ip->i_rwlock);
1217 			VN_RELE(ITOV(ip));
1218 		}
1219 	}
1220 	return (err);
1221 }
1222 
1223 int
1224 ud_dirmakeinode(struct ud_inode *tdp, struct ud_inode **ipp,
1225 	struct vattr *vap, enum de_op op, struct cred *cr)
1226 {
1227 	struct ud_inode *ip;
1228 	int32_t error;
1229 
1230 	ASSERT(vap != NULL);
1231 	ASSERT(op == DE_CREATE || op == DE_MKDIR);
1232 	ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
1233 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1234 
1235 	/*
1236 	 * Allocate a new inode.
1237 	 */
1238 	if ((error = ud_ialloc(tdp, &ip, vap, cr)) != 0) {
1239 		return (error);
1240 	}
1241 
1242 	ASSERT(ip != NULL);
1243 
1244 	rw_enter(&ip->i_contents, RW_WRITER);
1245 
1246 	if (op == DE_MKDIR) {
1247 		error = ud_dirmakedirect(ip, tdp, cr);
1248 	}
1249 
1250 	ip->i_flag |= IACC|IUPD|ICHG;
1251 	/*
1252 	 * Clear IACC and/or IUPD if the caller specified the atime and/or
1253 	 * mtime fields.  They were set from the passed in attributes in
1254 	 * ud_ialloc().
1255 	 */
1256 	if (vap->va_mask & AT_ATIME)
1257 		ip->i_flag &= ~IACC;
1258 	if (vap->va_mask & AT_MTIME)
1259 		ip->i_flag &= ~IUPD;
1260 	/*
1261 	 * push inode before it's name appears in a directory
1262 	 */
1263 	ud_iupdat(ip, 1);
1264 	*ipp = ip;
1265 	rw_exit(&ip->i_contents);
1266 	return (error);
1267 }
1268 
1269 /*
1270  * Enter the file sip in the directory tdp with name namep.
1271  */
1272 int
1273 ud_diraddentry(struct ud_inode *tdp, char *namep,
1274 	enum de_op op, int32_t namelen, struct slot *slotp,
1275 	struct ud_inode *sip, struct ud_inode *sdp, struct cred *cr)
1276 {
1277 	struct udf_vfs *udf_vfsp;
1278 	int32_t error, temp;
1279 	struct file_id *fid;
1280 	uint8_t *buf = NULL;
1281 
1282 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1283 
1284 	ud_printf("ud_diraddentry\n");
1285 
1286 	udf_vfsp = sip->i_udf;
1287 
1288 	/*
1289 	 * Check inode to be linked to see if it is in the
1290 	 * same filesystem.
1291 	 */
1292 	if (ITOV(tdp)->v_vfsp != ITOV(sip)->v_vfsp) {
1293 		error = EXDEV;
1294 		goto bad;
1295 	}
1296 
1297 	if ((op == DE_RENAME) && (sip->i_type == VDIR)) {
1298 		if ((error = ud_dirfixdotdot(sip, sdp, tdp)) != 0) {
1299 			goto bad;
1300 		}
1301 	}
1302 
1303 	buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
1304 
1305 	/*
1306 	 * Fill in entry data.
1307 	 */
1308 	fid = (struct file_id *)buf;
1309 	fid->fid_ver = SWAP_16(1);
1310 	if (sip->i_type == VDIR) {
1311 		fid->fid_flags = FID_DIR;
1312 	} else {
1313 		fid->fid_flags = 0;
1314 	}
1315 	fid->fid_iulen = 0;
1316 
1317 	fid->fid_icb.lad_ext_len = SWAP_32(sip->i_udf->udf_lbsize);
1318 	fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
1319 	fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
1320 	fid->fid_iulen = 0;
1321 
1322 	temp = udf_vfsp->udf_lbsize - F_LEN;
1323 	if ((error = ud_compress(namelen, &temp,
1324 			(uint8_t *)namep, fid->fid_spec)) == 0) {
1325 		fid->fid_idlen = (uint8_t)temp;
1326 		error = ud_dirprepareentry(tdp, slotp, buf, cr);
1327 	}
1328 
1329 	kmem_free(buf, udf_vfsp->udf_lbsize);
1330 
1331 bad:
1332 	return (error);
1333 }
1334 
1335 /*
1336  * Write a prototype directory into the empty inode ip, whose parent is dp.
1337  */
1338 /* ARGSUSED2 */
1339 int
1340 ud_dirmakedirect(struct ud_inode *ip,
1341 	struct ud_inode *dp, struct cred *cr)
1342 {
1343 	int32_t err;
1344 	uint32_t blkno, size, parent_len, tbno;
1345 	struct fbuf *fbp;
1346 	struct file_id *fid;
1347 	struct icb_ext *iext;
1348 
1349 	ud_printf("ud_dirmakedirect\n");
1350 
1351 	ASSERT(RW_WRITE_HELD(&ip->i_contents));
1352 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
1353 
1354 	parent_len = sizeof (struct file_id);
1355 
1356 	if ((ip->i_desc_type != ICB_FLAG_ONE_AD) ||
1357 		(parent_len > ip->i_max_emb)) {
1358 		ASSERT(ip->i_ext);
1359 		/*
1360 		 * Allocate space for the directory we're creating.
1361 		 */
1362 		if ((err = ud_alloc_space(ip->i_vfs, ip->i_icb_prn,
1363 				0, 1, &blkno, &size, 0, 0)) != 0) {
1364 			return (err);
1365 		}
1366 		/*
1367 		 * init with the size of
1368 		 * directory with just the
1369 		 * parent
1370 		 */
1371 		ip->i_size = sizeof (struct file_id);
1372 		ip->i_flag |= IUPD|ICHG|IATTCHG;
1373 		iext = ip->i_ext;
1374 		iext->ib_prn = ip->i_icb_prn;
1375 		iext->ib_block = blkno;
1376 		iext->ib_count = ip->i_size;
1377 		iext->ib_offset = 0;
1378 		ip->i_ext_used = 1;
1379 	} else {
1380 		ip->i_size = sizeof (struct file_id);
1381 		ip->i_flag |= IUPD|ICHG|IATTCHG;
1382 	}
1383 
1384 	ITIMES_NOLOCK(ip);
1385 
1386 	/*
1387 	 * Update the dp link count and write out the change.
1388 	 * This reflects the ".." entry we'll soon write.
1389 	 */
1390 	if (dp->i_nlink == MAXLINK) {
1391 		return (EMLINK);
1392 	}
1393 	dp->i_nlink++;
1394 	dp->i_flag |= ICHG;
1395 	ud_iupdat(dp, 1);
1396 
1397 	/*
1398 	 * Initialize directory with ".."
1399 	 * Since the parent directory is locked, we don't have to
1400 	 * worry about anything changing when we drop the write
1401 	 * lock on (ip).
1402 	 */
1403 	rw_exit(&ip->i_contents);
1404 	if ((err = fbread(ITOV(ip), (offset_t)0,
1405 			ip->i_udf->udf_lbsize, S_WRITE, &fbp)) != 0) {
1406 		rw_enter(&ip->i_contents, RW_WRITER);
1407 		return (err);
1408 	}
1409 
1410 	bzero(fbp->fb_addr, ip->i_udf->udf_lbsize);
1411 
1412 	fid = (struct file_id *)fbp->fb_addr;
1413 	fid->fid_ver = SWAP_16(1);
1414 	fid->fid_flags = FID_DIR | FID_PARENT;
1415 	fid->fid_icb.lad_ext_len = SWAP_32(dp->i_udf->udf_lbsize);
1416 	fid->fid_icb.lad_ext_loc = SWAP_32(dp->i_icb_block);
1417 	fid->fid_icb.lad_ext_prn = SWAP_16(dp->i_icb_prn);
1418 
1419 	/*
1420 	 * fid_idlen, fid_iulen and fid_spec are zero
1421 	 * due to bzero above
1422 	 */
1423 
1424 	if ((err = ud_ip_off2bno(ip, 0, &tbno)) == 0) {
1425 		ud_make_tag(ip->i_udf, &fid->fid_tag,
1426 			UD_FILE_ID_DESC, tbno, FID_LEN(fid));
1427 	}
1428 
1429 	err = ud_fbwrite(fbp, ip);
1430 	rw_enter(&ip->i_contents, RW_WRITER);
1431 
1432 	return (err);
1433 }
1434 
1435 int
1436 ud_dirrename(struct ud_inode *sdp, struct ud_inode *sip,
1437 	struct ud_inode *tdp, struct ud_inode *tip, char *namep,
1438 	uint8_t *buf, struct slot *slotp, struct cred *cr)
1439 {
1440 	int32_t error = 0, doingdirectory;
1441 	struct file_id *fid;
1442 
1443 	ud_printf("ud_dirrename\n");
1444 	ASSERT(sdp->i_udf != NULL);
1445 	ASSERT(MUTEX_HELD(&sdp->i_udf->udf_rename_lck));
1446 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1447 	ASSERT(buf);
1448 	ASSERT(slotp->ep);
1449 
1450 	fid = slotp->ep;
1451 
1452 	/*
1453 	 * Short circuit rename of something to itself.
1454 	 */
1455 	if (sip->i_icb_lbano == tip->i_icb_lbano) {
1456 		return (ESAME);		/* special KLUDGE error code */
1457 	}
1458 	/*
1459 	 * Everything is protected under the vfs_rename_lock so the ordering
1460 	 * of i_contents locks doesn't matter here.
1461 	 */
1462 	rw_enter(&sip->i_contents, RW_READER);
1463 	rw_enter(&tip->i_contents, RW_READER);
1464 
1465 	/*
1466 	 * Check that everything is on the same filesystem.
1467 	 */
1468 	if ((ITOV(tip)->v_vfsp != ITOV(tdp)->v_vfsp) ||
1469 	    (ITOV(tip)->v_vfsp != ITOV(sip)->v_vfsp)) {
1470 		error = EXDEV;		/* XXX archaic */
1471 		goto out;
1472 	}
1473 
1474 	/*
1475 	 * Must have write permission to rewrite target entry.
1476 	 */
1477 	if ((error = ud_iaccess(tdp, IWRITE, cr)) != 0 ||
1478 	    (error = ud_sticky_remove_access(tdp, tip, cr)) != 0)
1479 		goto out;
1480 
1481 	/*
1482 	 * Ensure source and target are compatible (both directories
1483 	 * or both not directories).  If target is a directory it must
1484 	 * be empty and have no links to it; in addition it must not
1485 	 * be a mount point, and both the source and target must be
1486 	 * writable.
1487 	 */
1488 	doingdirectory = (sip->i_type == VDIR);
1489 	if (tip->i_type == VDIR) {
1490 		if (!doingdirectory) {
1491 			error = EISDIR;
1492 			goto out;
1493 		}
1494 		/*
1495 		 * vn_vfswlock will prevent mounts from using the directory
1496 		 * until we are done.
1497 		 */
1498 		if (vn_vfswlock(ITOV(tip))) {
1499 			error = EBUSY;
1500 			goto out;
1501 		}
1502 		if (vn_mountedvfs(ITOV(tip)) != NULL) {
1503 			vn_vfsunlock(ITOV(tip));
1504 			error = EBUSY;
1505 			goto out;
1506 		}
1507 		if (!ud_dirempty(tip, tdp->i_uniqid, cr) || tip->i_nlink > 2) {
1508 			vn_vfsunlock(ITOV(tip));
1509 			error = EEXIST;	/* SIGH should be ENOTEMPTY */
1510 			goto out;
1511 		}
1512 	} else if (doingdirectory) {
1513 		error = ENOTDIR;
1514 		goto out;
1515 	}
1516 
1517 	/*
1518 	 * Rewrite the inode pointer for target name entry
1519 	 * from the target inode (ip) to the source inode (sip).
1520 	 * This prevents the target entry from disappearing
1521 	 * during a crash. Mark the directory inode to reflect the changes.
1522 	 */
1523 	dnlc_remove(ITOV(tdp), namep);
1524 	fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
1525 	fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
1526 	dnlc_enter(ITOV(tdp), namep, ITOV(sip));
1527 
1528 	ud_make_tag(tdp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1529 			SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
1530 
1531 	error = ud_write_fid(tdp, slotp, buf);
1532 
1533 	if (error) {
1534 		if (doingdirectory) {
1535 			vn_vfsunlock(ITOV(tip));
1536 		}
1537 		goto out;
1538 	}
1539 
1540 	/*
1541 	 * Upgrade to write lock on tip
1542 	 */
1543 	rw_exit(&tip->i_contents);
1544 	rw_enter(&tip->i_contents, RW_WRITER);
1545 
1546 	mutex_enter(&tdp->i_tlock);
1547 	tdp->i_flag |= IUPD|ICHG;
1548 	mutex_exit(&tdp->i_tlock);
1549 	/*
1550 	 * Decrement the link count of the target inode.
1551 	 * Fix the ".." entry in sip to point to dp.
1552 	 * This is done after the new entry is on the disk.
1553 	 */
1554 	tip->i_nlink--;
1555 	mutex_enter(&tip->i_tlock);
1556 	tip->i_flag |= ICHG;
1557 	mutex_exit(&tip->i_tlock);
1558 
1559 	if (doingdirectory) {
1560 		/*
1561 		 * The entry for tip no longer exists so I can unlock the
1562 		 * vfslock.
1563 		 */
1564 		vn_vfsunlock(ITOV(tip));
1565 		/*
1566 		 * Decrement target link count once more if it was a directory.
1567 		 */
1568 		if (tip->i_nlink != 0) {
1569 			cmn_err(CE_WARN,
1570 			"ud_direnter: target directory link count != 0");
1571 			rw_exit(&tip->i_contents);
1572 			rw_exit(&sip->i_contents);
1573 			return (EINVAL);
1574 		}
1575 		/*
1576 		 * Renaming a directory with the parent different
1577 		 * requires that ".." be rewritten.  The window is
1578 		 * still there for ".." to be inconsistent, but this
1579 		 * is unavoidable, and a lot shorter than when it was
1580 		 * done in a user process.  We decrement the link
1581 		 * count in the new parent as appropriate to reflect
1582 		 * the just-removed target.  If the parent is the
1583 		 * same, this is appropriate since the original
1584 		 * directory is going away.  If the new parent is
1585 		 * different, dirfixdotdot() will bump the link count
1586 		 * back.
1587 		 */
1588 		tdp->i_nlink--;
1589 		mutex_enter(&tdp->i_tlock);
1590 		tdp->i_flag |= ICHG;
1591 		mutex_exit(&tdp->i_tlock);
1592 		ITIMES_NOLOCK(tdp);
1593 		if (sdp != tdp) {
1594 			rw_exit(&tip->i_contents);
1595 			rw_exit(&sip->i_contents);
1596 			error = ud_dirfixdotdot(sip, sdp, tdp);
1597 			return (error);
1598 		}
1599 	}
1600 
1601 out:
1602 	rw_exit(&tip->i_contents);
1603 	rw_exit(&sip->i_contents);
1604 	return (error);
1605 }
1606 
1607 
1608 /*
1609  * 1. When we find a slot that belonged to a file which was deleted
1610  *      and is in the middle of the directory
1611  * 2. There is not empty slot available. The new entry
1612  *      will be at the end of the directory and fits in the same block.
1613  * 3. There is no empty slot available. The new
1614  *      entry will not fit the left over directory
1615  *      so we need to allocate a new block. If
1616  *      we cannot allocate a proximity block we need
1617  *      to allocate a new icb, and data block.
1618  */
1619 int
1620 ud_dirprepareentry(struct ud_inode *dp,
1621 	struct slot *slotp, uint8_t *buf, struct cred *cr)
1622 {
1623 	struct fbuf *fbp;
1624 	uint16_t old_dtype;
1625 	int32_t error = 0;
1626 	uint32_t entrysize, count, offset, tbno, old_size, off;
1627 	struct file_id *fid;
1628 	int32_t lbsize, lbmask, mask;
1629 
1630 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
1631 
1632 	ASSERT((slotp->status == NONE) ||
1633 		(slotp->status == FOUND));
1634 
1635 	ud_printf("ud_dirprepareentry\n");
1636 	lbsize = dp->i_udf->udf_lbsize;
1637 	lbmask = dp->i_udf->udf_lbmask;
1638 	mask = ~lbmask;
1639 
1640 	fid = (struct file_id *)buf;
1641 	entrysize = FID_LEN(fid);
1642 
1643 	/*
1644 	 * If we didn't find a slot, then indicate that the
1645 	 * new slot belongs at the end of the directory.
1646 	 * If we found a slot, then the new entry can be
1647 	 * put at slotp->offset.
1648 	 */
1649 	if (slotp->status == NONE) {
1650 		/*
1651 		 * We did not find a slot, the next
1652 		 * entry will be in the end of the directory
1653 		 * see if we can fit the new entry inside
1654 		 * the old block. If not allocate a new block.
1655 		 */
1656 		if (entrysize > slotp->size) {
1657 			/*
1658 			 * extend the directory
1659 			 * size by one new block
1660 			 */
1661 			old_dtype = dp->i_desc_type;
1662 			old_size = (uint32_t)dp->i_size;
1663 			error = ud_bmap_write(dp, slotp->offset,
1664 				blkoff(dp->i_udf, slotp->offset) + entrysize,
1665 				0, cr);
1666 			if (error != 0) {
1667 				return (error);
1668 			}
1669 			if (old_dtype != dp->i_desc_type) {
1670 				/*
1671 				 * oops we changed the astrat
1672 				 * of the file, we have to
1673 				 * recaliculate tags
1674 				 * fortunately we donot have more
1675 				 * than one lbsize to handle here
1676 				 */
1677 				if ((error = ud_ip_off2bno(dp,
1678 						0, &tbno)) != 0) {
1679 					return (error);
1680 				}
1681 				if ((error = fbread(ITOV(dp), 0,
1682 						dp->i_udf->udf_lbsize,
1683 						S_WRITE, &fbp)) != 0) {
1684 					return (error);
1685 				}
1686 				off = 0;
1687 				while (off < old_size) {
1688 					struct file_id *tfid;
1689 
1690 					tfid = (struct file_id *)
1691 						(fbp->fb_addr + off);
1692 
1693 					ud_make_tag(dp->i_udf, &tfid->fid_tag,
1694 					UD_FILE_ID_DESC, tbno, FID_LEN(tfid));
1695 
1696 					off += FID_LEN(tfid);
1697 				}
1698 				if (error = ud_fbwrite(fbp, dp)) {
1699 					return (error);
1700 				}
1701 			}
1702 		} else {
1703 			/* Extend the directory size */
1704 			if (dp->i_desc_type != ICB_FLAG_ONE_AD) {
1705 				ASSERT(dp->i_ext);
1706 				dp->i_ext[dp->i_ext_used - 1].ib_count +=
1707 						entrysize;
1708 			}
1709 		}
1710 		dp->i_size += entrysize;
1711 		dp->i_flag |= IUPD|ICHG|IATTCHG;
1712 		ITIMES_NOLOCK(dp);
1713 	} else if (slotp->status != FOUND) {
1714 		cmn_err(CE_WARN, "status is not NONE/FOUND");
1715 		return (EINVAL);
1716 	}
1717 
1718 	if ((error = ud_ip_off2bno(dp, slotp->offset, &tbno)) != 0) {
1719 		return (error);
1720 	}
1721 	ud_make_tag(dp->i_udf, &fid->fid_tag,
1722 			UD_FILE_ID_DESC, tbno, FID_LEN(fid));
1723 
1724 	/*
1725 	 * fbread cannot cross a
1726 	 * MAXBSIZE boundary so handle it here
1727 	 */
1728 	offset = slotp->offset;
1729 	if ((error = fbread(ITOV(dp), offset & mask, lbsize,
1730 				S_WRITE, &fbp)) != 0) {
1731 		return (error);
1732 	}
1733 	if ((offset & mask) != ((offset + entrysize) & mask)) {
1734 		count = entrysize - ((offset + entrysize) & lbmask);
1735 	} else {
1736 		count = entrysize;
1737 	}
1738 	bcopy((caddr_t)buf, fbp->fb_addr + (offset & lbmask), count);
1739 
1740 	if (error = ud_fbwrite(fbp, dp)) {
1741 		return (error);
1742 	}
1743 
1744 	if (entrysize > count) {
1745 		if ((error = fbread(ITOV(dp), (offset + entrysize) & mask,
1746 				lbsize, S_WRITE, &fbp)) != 0) {
1747 			return (error);
1748 		}
1749 		bcopy((caddr_t)(buf + count), fbp->fb_addr, entrysize - count);
1750 		if (error = ud_fbwrite(fbp, dp)) {
1751 			return (error);
1752 		}
1753 	}
1754 
1755 	dp->i_flag |= IUPD|ICHG|IATTCHG;
1756 	ITIMES_NOLOCK(dp);
1757 	return (error);
1758 }
1759 
1760 
1761 /*
1762  * Fix the FID_PARENT entry of the child directory so that it points
1763  * to the new parent directory instead of the old one.  Routine
1764  * assumes that dp is a directory and that all the inodes are on
1765  * the same file system.
1766  */
1767 int
1768 ud_dirfixdotdot(struct ud_inode *dp,
1769 	struct ud_inode *opdp, struct ud_inode *npdp)
1770 {
1771 	int32_t err = 0;
1772 	struct fbuf *fbp;
1773 	struct file_id *fid;
1774 	uint32_t loc, dummy, tbno;
1775 
1776 	ud_printf("ud_dirfixdotdot\n");
1777 
1778 	ASSERT(opdp->i_type == VDIR);
1779 	ASSERT(npdp->i_type == VDIR);
1780 
1781 	ASSERT(RW_WRITE_HELD(&npdp->i_rwlock));
1782 
1783 	err = fbread(ITOV(dp), (offset_t)0,
1784 			dp->i_udf->udf_lbsize, S_WRITE, &fbp);
1785 
1786 	if (err || dp->i_nlink == 0 ||
1787 		dp->i_size < sizeof (struct file_id)) {
1788 		goto bad;
1789 	}
1790 
1791 	if ((err = ud_ip_off2bno(dp, 0, &tbno)) != 0) {
1792 		goto bad;
1793 	}
1794 
1795 	fid = (struct file_id *)fbp->fb_addr;
1796 	if ((ud_verify_tag_and_desc(&fid->fid_tag, UD_FILE_ID_DESC,
1797 	    tbno,
1798 	    1, dp->i_udf->udf_lbsize) != 0) ||
1799 	    ((fid->fid_flags & (FID_DIR | FID_PARENT)) !=
1800 	    (FID_DIR | FID_PARENT))) {
1801 		err = ENOTDIR;
1802 		goto bad;
1803 	}
1804 
1805 	loc = ud_xlate_to_daddr(dp->i_udf,
1806 		SWAP_16(fid->fid_icb.lad_ext_prn),
1807 		SWAP_32(fid->fid_icb.lad_ext_loc), 1, &dummy);
1808 	ASSERT(dummy == 1);
1809 	if (loc == npdp->i_icb_lbano) {
1810 		goto bad;
1811 	}
1812 
1813 	/*
1814 	 * Increment the link count in the new parent inode and force it out.
1815 	 */
1816 	if (npdp->i_nlink == MAXLINK) {
1817 		err = EMLINK;
1818 		goto bad;
1819 	}
1820 
1821 	npdp->i_nlink++;
1822 	mutex_enter(&npdp->i_tlock);
1823 	npdp->i_flag |= ICHG;
1824 	mutex_exit(&npdp->i_tlock);
1825 	ud_iupdat(npdp, 1);
1826 
1827 	/*
1828 	 * Rewrite the child FID_PARENT entry and force it out.
1829 	 */
1830 	dnlc_remove(ITOV(dp), "..");
1831 	fid->fid_icb.lad_ext_loc = SWAP_32(npdp->i_icb_block);
1832 	fid->fid_icb.lad_ext_prn = SWAP_16(npdp->i_icb_prn);
1833 	ud_make_tag(npdp->i_udf, &fid->fid_tag,
1834 		UD_FILE_ID_DESC, tbno, FID_LEN(fid));
1835 	dnlc_enter(ITOV(dp), "..", ITOV(npdp));
1836 
1837 	err = ud_fbwrite(fbp, dp);
1838 	fbp = NULL;
1839 	if (err != 0) {
1840 		goto bad;
1841 	}
1842 
1843 	/*
1844 	 * Decrement the link count of the old parent inode and force
1845 	 * it out.  If opdp is NULL, then this is a new directory link;
1846 	 * it has no parent, so we need not do anything.
1847 	 */
1848 	if (opdp != NULL) {
1849 		rw_enter(&opdp->i_contents, RW_WRITER);
1850 		if (opdp->i_nlink != 0) {
1851 			opdp->i_nlink--;
1852 			mutex_enter(&opdp->i_tlock);
1853 			opdp->i_flag |= ICHG;
1854 			mutex_exit(&opdp->i_tlock);
1855 			ud_iupdat(opdp, 1);
1856 		}
1857 		rw_exit(&opdp->i_contents);
1858 	}
1859 	return (0);
1860 
1861 bad:
1862 	if (fbp) {
1863 		fbrelse(fbp, S_OTHER);
1864 	}
1865 	return (err);
1866 }
1867 
1868 int32_t
1869 ud_write_fid(struct ud_inode *dp, struct slot *slot, uint8_t *buf)
1870 {
1871 	struct udf_vfs *udf_vfsp;
1872 	struct fbuf *lfbp;
1873 	struct file_id *fid;
1874 	int32_t error = 0;
1875 	uint32_t lbsize, lbmask, count, old_count;
1876 
1877 
1878 	ASSERT(slot->fbp);
1879 	ASSERT(slot->ep);
1880 
1881 	udf_vfsp = dp->i_udf;
1882 	fid = slot->ep;
1883 	lbsize = dp->i_udf->udf_lbsize;
1884 	lbmask = dp->i_udf->udf_lbmask;
1885 
1886 	if (((uint8_t *)fid >= buf) &&
1887 		((uint8_t *)fid < &buf[udf_vfsp->udf_lbsize])) {
1888 
1889 
1890 		if ((error = fbread(ITOV(dp),
1891 			(offset_t)(slot->offset & ~lbmask),
1892 			lbsize, S_WRITE, &lfbp)) != 0) {
1893 			goto out;
1894 		}
1895 
1896 
1897 		/*
1898 		 * We do not need to write the
1899 		 * file name. So check if the entry
1900 		 * does not cross a block boundary
1901 		 * and write only required portions
1902 		 */
1903 		if (((slot->offset & lbmask) +
1904 			sizeof (struct file_id)) > lbsize) {
1905 
1906 			if ((slot->offset & lbmask) != 0) {
1907 				old_count = lbsize -
1908 					(slot->offset & lbmask);
1909 				count = (slot->offset +
1910 					sizeof (struct file_id)) &
1911 					lbmask;
1912 			} else {
1913 				old_count = 0;
1914 				count = sizeof (struct file_id);
1915 			}
1916 
1917 			bcopy(buf, lfbp->fb_addr +
1918 				(slot->offset & lbmask), old_count);
1919 			bcopy(buf + old_count,
1920 				slot->fbp->fb_addr, count);
1921 
1922 			error = ud_fbwrite(lfbp, dp);
1923 
1924 			error = ud_fbwrite(slot->fbp, dp);
1925 		} else {
1926 			bcopy(buf, lfbp->fb_addr +
1927 				(slot->offset & lbmask),
1928 				sizeof (struct file_id));
1929 
1930 			error = ud_fbwrite(lfbp, dp);
1931 
1932 			fbrelse(slot->fbp, S_OTHER);
1933 		}
1934 	} else {
1935 		if ((error = ud_fbwrite(slot->fbp, dp)) != 0) {
1936 			fid->fid_flags &= ~FID_DELETED;
1937 			ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1938 				SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
1939 		}
1940 	}
1941 	slot->fbp = NULL;
1942 
1943 out:
1944 	return (error);
1945 }
1946