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