Home | History | Annotate | Download | only in udfs
      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