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