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