xref: /illumos-gate/usr/src/uts/common/fs/udfs/udf_dir.c (revision b39a0235a975290e229a1bf1de8031578ab2d98d)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5df2381bfSpraks  * Common Development and Distribution License (the "License").
6df2381bfSpraks  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*b39a0235SMilan Cermak  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate 
257c478bd9Sstevel@tonic-gate #include <sys/types.h>
267c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
277c478bd9Sstevel@tonic-gate #include <sys/param.h>
287c478bd9Sstevel@tonic-gate #include <sys/time.h>
297c478bd9Sstevel@tonic-gate #include <sys/systm.h>
307c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
317c478bd9Sstevel@tonic-gate #include <sys/resource.h>
327c478bd9Sstevel@tonic-gate #include <sys/signal.h>
337c478bd9Sstevel@tonic-gate #include <sys/cred.h>
347c478bd9Sstevel@tonic-gate #include <sys/user.h>
357c478bd9Sstevel@tonic-gate #include <sys/buf.h>
367c478bd9Sstevel@tonic-gate #include <sys/vfs.h>
377c478bd9Sstevel@tonic-gate #include <sys/stat.h>
387c478bd9Sstevel@tonic-gate #include <sys/vnode.h>
397c478bd9Sstevel@tonic-gate #include <sys/mode.h>
407c478bd9Sstevel@tonic-gate #include <sys/proc.h>
417c478bd9Sstevel@tonic-gate #include <sys/disp.h>
427c478bd9Sstevel@tonic-gate #include <sys/file.h>
437c478bd9Sstevel@tonic-gate #include <sys/fcntl.h>
447c478bd9Sstevel@tonic-gate #include <sys/flock.h>
457c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
467c478bd9Sstevel@tonic-gate #include <sys/uio.h>
477c478bd9Sstevel@tonic-gate #include <sys/dnlc.h>
487c478bd9Sstevel@tonic-gate #include <sys/conf.h>
497c478bd9Sstevel@tonic-gate #include <sys/errno.h>
507c478bd9Sstevel@tonic-gate #include <sys/mman.h>
517c478bd9Sstevel@tonic-gate #include <sys/fbuf.h>
527c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
537c478bd9Sstevel@tonic-gate #include <sys/debug.h>
547c478bd9Sstevel@tonic-gate #include <sys/vmsystm.h>
557c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
567c478bd9Sstevel@tonic-gate #include <sys/dirent.h>
577c478bd9Sstevel@tonic-gate #include <sys/errno.h>
587c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
597c478bd9Sstevel@tonic-gate #include <sys/statvfs.h>
607c478bd9Sstevel@tonic-gate #include <sys/mount.h>
617c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
627c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
637c478bd9Sstevel@tonic-gate #include <sys/policy.h>
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate #include <vm/hat.h>
667c478bd9Sstevel@tonic-gate #include <vm/page.h>
677c478bd9Sstevel@tonic-gate #include <vm/pvn.h>
687c478bd9Sstevel@tonic-gate #include <vm/as.h>
697c478bd9Sstevel@tonic-gate #include <vm/seg.h>
707c478bd9Sstevel@tonic-gate #include <vm/seg_map.h>
717c478bd9Sstevel@tonic-gate #include <vm/seg_kmem.h>
727c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
737c478bd9Sstevel@tonic-gate #include <vm/rm.h>
747c478bd9Sstevel@tonic-gate #include <vm/page.h>
757c478bd9Sstevel@tonic-gate #include <sys/swap.h>
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate #include <fs/fs_subr.h>
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate #include <sys/fs/udf_volume.h>
827c478bd9Sstevel@tonic-gate #include <sys/fs/udf_inode.h>
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate struct slot {
867c478bd9Sstevel@tonic-gate 	enum	{NONE, COMPACT, FOUND, EXIST} status;
877c478bd9Sstevel@tonic-gate 	off_t	offset;		/* offset of area with free space */
887c478bd9Sstevel@tonic-gate 	int	size;		/* size of area at slotoffset */
897c478bd9Sstevel@tonic-gate 	struct	fbuf *fbp;	/* dir buf where slot is */
907c478bd9Sstevel@tonic-gate 	struct file_id *ep;	/* pointer to slot */
917c478bd9Sstevel@tonic-gate 	off_t	endoff;		/* last useful location found in search */
927c478bd9Sstevel@tonic-gate };
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate int32_t ud_dircheckforname(struct ud_inode *, char *, int,
967c478bd9Sstevel@tonic-gate 		struct slot *, struct ud_inode **, uint8_t *, struct cred *);
977c478bd9Sstevel@tonic-gate int32_t ud_dirempty(struct ud_inode *, uint64_t, struct cred *);
987c478bd9Sstevel@tonic-gate int32_t str2cmp(char *, int32_t, char *, int32_t, char *, int32_t);
997c478bd9Sstevel@tonic-gate int32_t ud_dircheckpath(int32_t, struct ud_inode *, struct cred *);
1007c478bd9Sstevel@tonic-gate int32_t ud_dirmakeinode(struct ud_inode *, struct ud_inode **,
1017c478bd9Sstevel@tonic-gate 	struct vattr *, enum de_op, struct cred *);
1027c478bd9Sstevel@tonic-gate int32_t ud_diraddentry(struct ud_inode *, char *,
1037c478bd9Sstevel@tonic-gate 	enum de_op, int, struct slot *, struct ud_inode *,
1047c478bd9Sstevel@tonic-gate 	struct ud_inode *, struct cred *);
1057c478bd9Sstevel@tonic-gate int32_t ud_dirmakedirect(struct ud_inode *, struct ud_inode *, struct cred *);
1067c478bd9Sstevel@tonic-gate int32_t ud_dirrename(struct ud_inode *, struct ud_inode *,
1077c478bd9Sstevel@tonic-gate 	struct ud_inode *, struct ud_inode *, char *, uint8_t *,
1087c478bd9Sstevel@tonic-gate 	struct slot *, struct cred *);
1097c478bd9Sstevel@tonic-gate int32_t ud_dirprepareentry(struct ud_inode *,
1107c478bd9Sstevel@tonic-gate 	struct slot *, uint8_t *, struct cred *);
1117c478bd9Sstevel@tonic-gate int32_t ud_dirfixdotdot(struct ud_inode *, struct ud_inode *,
1127c478bd9Sstevel@tonic-gate 		struct ud_inode *);
1137c478bd9Sstevel@tonic-gate int32_t ud_write_fid(struct ud_inode *, struct slot *, uint8_t *);
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate int
1167c478bd9Sstevel@tonic-gate ud_dirlook(struct ud_inode *dip,
1177c478bd9Sstevel@tonic-gate 	char *namep, struct ud_inode **ipp, struct cred *cr, int32_t skipdnlc)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
1207c478bd9Sstevel@tonic-gate 	int32_t error = 0, namelen, adhoc_search;
1217c478bd9Sstevel@tonic-gate 	u_offset_t offset, adhoc_offset, dirsize, end;
1227c478bd9Sstevel@tonic-gate 	struct vnode *dvp, *vp;
1237c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
1247c478bd9Sstevel@tonic-gate 	struct file_id *fid;
1257c478bd9Sstevel@tonic-gate 	uint8_t *fname, dummy[3];
1267c478bd9Sstevel@tonic-gate 	int32_t id_len, doingchk;
1277c478bd9Sstevel@tonic-gate 	uint32_t old_loc;
1287c478bd9Sstevel@tonic-gate 	uint16_t old_prn;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	uint8_t *dname;
1317c478bd9Sstevel@tonic-gate 	uint8_t *buf = NULL;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	ud_printf("ud_dirlook\n");
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	udf_vfsp = dip->i_udf;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate restart:
1387c478bd9Sstevel@tonic-gate 	doingchk = 0;
1397c478bd9Sstevel@tonic-gate 	old_prn = 0xFFFF;
1407c478bd9Sstevel@tonic-gate 	old_loc = 0;
1417c478bd9Sstevel@tonic-gate 	dvp = ITOV(dip);
1427c478bd9Sstevel@tonic-gate 	/*
1437c478bd9Sstevel@tonic-gate 	 * Check accessibility of directory.
1447c478bd9Sstevel@tonic-gate 	 */
1457c478bd9Sstevel@tonic-gate 	if (dip->i_type != VDIR) {
1467c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
1477c478bd9Sstevel@tonic-gate 	}
148*b39a0235SMilan Cermak 	if (error = ud_iaccess(dip, IEXEC, cr, 1)) {
1497c478bd9Sstevel@tonic-gate 		return (error);
1507c478bd9Sstevel@tonic-gate 	}
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/*
1537c478bd9Sstevel@tonic-gate 	 * Null component name is synonym for directory being searched.
1547c478bd9Sstevel@tonic-gate 	 */
1557c478bd9Sstevel@tonic-gate 	if (*namep == '\0') {
1567c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
1577c478bd9Sstevel@tonic-gate 		*ipp = dip;
1587c478bd9Sstevel@tonic-gate 		return (0);
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 	namelen = strlen(namep);
1617c478bd9Sstevel@tonic-gate 	if ((namelen == 1) &&
162*b39a0235SMilan Cermak 	    (namep[0] == '.') && (namep[1] == '\0')) {
1637c478bd9Sstevel@tonic-gate 		/* Current directory */
1647c478bd9Sstevel@tonic-gate 		VN_HOLD(dvp);
1657c478bd9Sstevel@tonic-gate 		*ipp = dip;
1667c478bd9Sstevel@tonic-gate 		dnlc_enter(dvp, namep, ITOV(*ipp));
1677c478bd9Sstevel@tonic-gate 		return (0);
1687c478bd9Sstevel@tonic-gate 	}
1697c478bd9Sstevel@tonic-gate 
1707c478bd9Sstevel@tonic-gate 	if ((!skipdnlc) && (vp = dnlc_lookup(dvp, namep))) {
1717c478bd9Sstevel@tonic-gate 		/* vp is already held from dnlc_lookup */
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 		*ipp = VTOI(vp);
1747c478bd9Sstevel@tonic-gate 		return (0);
1757c478bd9Sstevel@tonic-gate 	}
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	dname = kmem_zalloc(1024, KM_SLEEP);
1787c478bd9Sstevel@tonic-gate 	buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/*
1817c478bd9Sstevel@tonic-gate 	 * Read lock the inode we are searching.  You will notice that we
1827c478bd9Sstevel@tonic-gate 	 * didn't hold the read lock while searching the dnlc.  This means
1837c478bd9Sstevel@tonic-gate 	 * that the entry could now be in the dnlc.  This doesn't cause any
1847c478bd9Sstevel@tonic-gate 	 * problems because dnlc_enter won't add an entry if it is already
1857c478bd9Sstevel@tonic-gate 	 * there.
1867c478bd9Sstevel@tonic-gate 	 */
1877c478bd9Sstevel@tonic-gate 	rw_enter(&dip->i_rwlock, RW_READER);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	/*
1907c478bd9Sstevel@tonic-gate 	 * Take care to look at dip->i_diroff only once, as it
1917c478bd9Sstevel@tonic-gate 	 * may be changing due to other threads/cpus.
1927c478bd9Sstevel@tonic-gate 	 */
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate recheck:
1957c478bd9Sstevel@tonic-gate 	offset = dip->i_diroff;
1967c478bd9Sstevel@tonic-gate 	end = dirsize = dip->i_size;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	if (offset > dirsize) {
1997c478bd9Sstevel@tonic-gate 		offset = 0;
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 	adhoc_offset = offset;
2027c478bd9Sstevel@tonic-gate 	adhoc_search = (offset == 0) ? 1 : 2;
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	fbp = NULL;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	while (adhoc_search--) {
2077c478bd9Sstevel@tonic-gate 		while (offset < end) {
2087c478bd9Sstevel@tonic-gate 			error = ud_get_next_fid(dip, &fbp,
209*b39a0235SMilan Cermak 			    offset, &fid, &fname, buf);
2107c478bd9Sstevel@tonic-gate 			if (error != 0) {
2117c478bd9Sstevel@tonic-gate 				break;
2127c478bd9Sstevel@tonic-gate 			}
2137c478bd9Sstevel@tonic-gate 			if ((fid->fid_flags & FID_DELETED) == 0) {
2147c478bd9Sstevel@tonic-gate 				if (fid->fid_flags & FID_PARENT) {
2157c478bd9Sstevel@tonic-gate 					id_len = 2;
2167c478bd9Sstevel@tonic-gate 					fname = dummy;
2177c478bd9Sstevel@tonic-gate 					dummy[0] = '.';
2187c478bd9Sstevel@tonic-gate 					dummy[1] = '.';
2197c478bd9Sstevel@tonic-gate 					dummy[2] = '\0';
2207c478bd9Sstevel@tonic-gate 				} else {
2217c478bd9Sstevel@tonic-gate 					if ((error = ud_uncompress(
222*b39a0235SMilan Cermak 					    fid->fid_idlen, &id_len,
223*b39a0235SMilan Cermak 					    fname, dname)) != 0) {
2247c478bd9Sstevel@tonic-gate 						break;
2257c478bd9Sstevel@tonic-gate 					}
2267c478bd9Sstevel@tonic-gate 					fname = (uint8_t *)dname;
2277c478bd9Sstevel@tonic-gate 					fname[id_len] = '\0';
2287c478bd9Sstevel@tonic-gate 				}
2297c478bd9Sstevel@tonic-gate 				if ((namelen == id_len) &&
230*b39a0235SMilan Cermak 				    (strncmp(namep, (caddr_t)fname,
231*b39a0235SMilan Cermak 				    namelen) == 0)) {
2327c478bd9Sstevel@tonic-gate 					uint32_t loc;
2337c478bd9Sstevel@tonic-gate 					uint16_t prn;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 					loc = SWAP_32(fid->fid_icb.lad_ext_loc);
2377c478bd9Sstevel@tonic-gate 					prn = SWAP_16(fid->fid_icb.lad_ext_prn);
238*b39a0235SMilan Cermak 					dip->i_diroff = offset + FID_LEN(fid);
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 					if (doingchk) {
2417c478bd9Sstevel@tonic-gate 						if ((loc == old_loc) &&
242*b39a0235SMilan Cermak 						    (prn == old_prn)) {
2437c478bd9Sstevel@tonic-gate 							goto checkok;
2447c478bd9Sstevel@tonic-gate 						} else {
2457c478bd9Sstevel@tonic-gate 							if (fbp != NULL) {
2467c478bd9Sstevel@tonic-gate 								fbrelse(fbp,
247*b39a0235SMilan Cermak 								    S_READ);
2487c478bd9Sstevel@tonic-gate 								fbp = NULL;
2497c478bd9Sstevel@tonic-gate 							}
2507c478bd9Sstevel@tonic-gate 							VN_RELE(ITOV(*ipp));
2517c478bd9Sstevel@tonic-gate 							rw_exit(&dip->i_rwlock);
2527c478bd9Sstevel@tonic-gate 							goto restart;
2537c478bd9Sstevel@tonic-gate 						}
2547c478bd9Sstevel@tonic-gate 						/* NOTREACHED */
2557c478bd9Sstevel@tonic-gate 					}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 					if (namelen == 2 &&
258*b39a0235SMilan Cermak 					    fname[0] == '.' &&
259*b39a0235SMilan Cermak 					    fname[1] == '.') {
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 						struct timespec32 omtime;
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 						omtime = dip->i_mtime;
2647c478bd9Sstevel@tonic-gate 						rw_exit(&dip->i_rwlock);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 						error = ud_iget(dip->i_vfs, prn,
267*b39a0235SMilan Cermak 						    loc, ipp, NULL, cr);
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 						rw_enter(&dip->i_rwlock,
270*b39a0235SMilan Cermak 						    RW_READER);
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 						if (error) {
2737c478bd9Sstevel@tonic-gate 							goto done;
2747c478bd9Sstevel@tonic-gate 						}
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 						if ((omtime.tv_sec !=
277*b39a0235SMilan Cermak 						    dip->i_mtime.tv_sec) ||
278*b39a0235SMilan Cermak 						    (omtime.tv_nsec !=
279*b39a0235SMilan Cermak 						    dip->i_mtime.tv_nsec)) {
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 							doingchk = 1;
2827c478bd9Sstevel@tonic-gate 							old_prn = prn;
2837c478bd9Sstevel@tonic-gate 							old_loc = loc;
2847c478bd9Sstevel@tonic-gate 							dip->i_diroff = 0;
2857c478bd9Sstevel@tonic-gate 							if (fbp != NULL) {
2867c478bd9Sstevel@tonic-gate 								fbrelse(fbp,
287*b39a0235SMilan Cermak 								    S_READ);
2887c478bd9Sstevel@tonic-gate 								fbp = NULL;
2897c478bd9Sstevel@tonic-gate 							}
2907c478bd9Sstevel@tonic-gate 							goto recheck;
2917c478bd9Sstevel@tonic-gate 						}
2927c478bd9Sstevel@tonic-gate 					} else {
2937c478bd9Sstevel@tonic-gate 
2947c478bd9Sstevel@tonic-gate 						error = ud_iget(dip->i_vfs, prn,
295*b39a0235SMilan Cermak 						    loc, ipp, NULL, cr);
2967c478bd9Sstevel@tonic-gate 					}
2977c478bd9Sstevel@tonic-gate checkok:
2987c478bd9Sstevel@tonic-gate 					if (error == 0) {
2997c478bd9Sstevel@tonic-gate 						dnlc_enter(dvp, namep,
300*b39a0235SMilan Cermak 						    ITOV(*ipp));
3017c478bd9Sstevel@tonic-gate 					}
3027c478bd9Sstevel@tonic-gate 					goto done;
3037c478bd9Sstevel@tonic-gate 				}
3047c478bd9Sstevel@tonic-gate 			}
3057c478bd9Sstevel@tonic-gate 			offset += FID_LEN(fid);
3067c478bd9Sstevel@tonic-gate 		}
3077c478bd9Sstevel@tonic-gate 		if (fbp != NULL) {
3087c478bd9Sstevel@tonic-gate 			fbrelse(fbp, S_READ);
3097c478bd9Sstevel@tonic-gate 			fbp = NULL;
3107c478bd9Sstevel@tonic-gate 		}
3117c478bd9Sstevel@tonic-gate 		end = adhoc_offset;
3127c478bd9Sstevel@tonic-gate 		offset = 0;
3137c478bd9Sstevel@tonic-gate 	}
3147c478bd9Sstevel@tonic-gate 	error = ENOENT;
3157c478bd9Sstevel@tonic-gate done:
3167c478bd9Sstevel@tonic-gate 	kmem_free(buf, udf_vfsp->udf_lbsize);
3177c478bd9Sstevel@tonic-gate 	kmem_free(dname, 1024);
3187c478bd9Sstevel@tonic-gate 	if (fbp != NULL) {
3197c478bd9Sstevel@tonic-gate 		fbrelse(fbp, S_READ);
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 	rw_exit(&dip->i_rwlock);
3227c478bd9Sstevel@tonic-gate 	return (error);
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate int
326da6c28aaSamw ud_direnter(
327da6c28aaSamw 	struct ud_inode *tdp,
328da6c28aaSamw 	char *namep,
329da6c28aaSamw 	enum de_op op,
330da6c28aaSamw 	struct ud_inode *sdp,
331da6c28aaSamw 	struct ud_inode *sip,
332da6c28aaSamw 	struct vattr *vap,
333da6c28aaSamw 	struct ud_inode **ipp,
334da6c28aaSamw 	struct cred *cr,
335da6c28aaSamw 	caller_context_t *ctp)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
3387c478bd9Sstevel@tonic-gate 	struct ud_inode *tip;
3397c478bd9Sstevel@tonic-gate 	struct slot slot;
3407c478bd9Sstevel@tonic-gate 	int32_t namlen, err;
3417c478bd9Sstevel@tonic-gate 	char *s;
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate 	uint8_t *buf = NULL;
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	ud_printf("ud_direnter\n");
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	udf_vfsp = tdp->i_udf;
3487c478bd9Sstevel@tonic-gate 	/* don't allow '/' characters in pathname component */
3497c478bd9Sstevel@tonic-gate 	for (s = namep, namlen = 0; *s; s++, namlen++) {
3507c478bd9Sstevel@tonic-gate 		if (*s == '/') {
3517c478bd9Sstevel@tonic-gate 			return (EACCES);
3527c478bd9Sstevel@tonic-gate 		}
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	if (namlen == 0) {
3567c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "name length == 0 in ud_direnter");
3577c478bd9Sstevel@tonic-gate 		return (EINVAL);
3587c478bd9Sstevel@tonic-gate 	}
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
3617c478bd9Sstevel@tonic-gate 	/*
3627c478bd9Sstevel@tonic-gate 	 * If name is "." or ".." then if this is a create look it up
3637c478bd9Sstevel@tonic-gate 	 * and return EEXIST.  Rename or link TO "." or ".." is forbidden.
3647c478bd9Sstevel@tonic-gate 	 */
3657c478bd9Sstevel@tonic-gate 	if (namep[0] == '.' &&
3667c478bd9Sstevel@tonic-gate 	    (namlen == 1 || (namlen == 2 && namep[1] == '.'))) {
3677c478bd9Sstevel@tonic-gate 		if (op == DE_RENAME) {
3687c478bd9Sstevel@tonic-gate 			return (EINVAL);	/* *SIGH* should be ENOTEMPTY */
3697c478bd9Sstevel@tonic-gate 		}
3707c478bd9Sstevel@tonic-gate 		if (ipp) {
3717c478bd9Sstevel@tonic-gate 			/*
3727c478bd9Sstevel@tonic-gate 			 * ud_dirlook will acquire the i_rwlock
3737c478bd9Sstevel@tonic-gate 			 */
3747c478bd9Sstevel@tonic-gate 			rw_exit(&tdp->i_rwlock);
3757c478bd9Sstevel@tonic-gate 			if (err = ud_dirlook(tdp, namep, ipp, cr, 0)) {
3767c478bd9Sstevel@tonic-gate 				rw_enter(&tdp->i_rwlock, RW_WRITER);
3777c478bd9Sstevel@tonic-gate 				return (err);
3787c478bd9Sstevel@tonic-gate 			}
3797c478bd9Sstevel@tonic-gate 			rw_enter(&tdp->i_rwlock, RW_WRITER);
3807c478bd9Sstevel@tonic-gate 		}
3817c478bd9Sstevel@tonic-gate 		return (EEXIST);
3827c478bd9Sstevel@tonic-gate 	}
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	tip = NULL;
3857c478bd9Sstevel@tonic-gate 	slot.status = NONE;
3867c478bd9Sstevel@tonic-gate 	slot.offset = 0;
3877c478bd9Sstevel@tonic-gate 	slot.size = 0;
3887c478bd9Sstevel@tonic-gate 	slot.fbp = NULL;
3897c478bd9Sstevel@tonic-gate 	slot.ep = NULL;
3907c478bd9Sstevel@tonic-gate 	slot.endoff = 0;
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	/*
3937c478bd9Sstevel@tonic-gate 	 * For link and rename lock the source entry and check the link count
3947c478bd9Sstevel@tonic-gate 	 * to see if it has been removed while it was unlocked.  If not, we
3957c478bd9Sstevel@tonic-gate 	 * increment the link count and force the inode to disk to make sure
3967c478bd9Sstevel@tonic-gate 	 * that it is there before any directory entry that points to it.
3977c478bd9Sstevel@tonic-gate 	 */
3987c478bd9Sstevel@tonic-gate 	if (op == DE_LINK || op == DE_RENAME) {
3997c478bd9Sstevel@tonic-gate 		rw_enter(&sip->i_contents, RW_WRITER);
4007c478bd9Sstevel@tonic-gate 		if (sip->i_nlink == 0) {
4017c478bd9Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
4027c478bd9Sstevel@tonic-gate 			return (ENOENT);
4037c478bd9Sstevel@tonic-gate 		}
4047c478bd9Sstevel@tonic-gate 		if (sip->i_nlink == MAXLINK) {
4057c478bd9Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
4067c478bd9Sstevel@tonic-gate 			return (EMLINK);
4077c478bd9Sstevel@tonic-gate 		}
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 		sip->i_nlink++;
4107c478bd9Sstevel@tonic-gate 		mutex_enter(&sip->i_tlock);
4117c478bd9Sstevel@tonic-gate 		sip->i_flag |= ICHG;
4127c478bd9Sstevel@tonic-gate 		mutex_exit(&sip->i_tlock);
4137c478bd9Sstevel@tonic-gate 		ud_iupdat(sip, 1);
4147c478bd9Sstevel@tonic-gate 		rw_exit(&sip->i_contents);
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate 	/*
4177c478bd9Sstevel@tonic-gate 	 * If target directory has not been removed, then we can consider
4187c478bd9Sstevel@tonic-gate 	 * allowing file to be created.
4197c478bd9Sstevel@tonic-gate 	 */
4207c478bd9Sstevel@tonic-gate 	if (tdp->i_nlink == 0) {
4217c478bd9Sstevel@tonic-gate 		err = ENOENT;
4227c478bd9Sstevel@tonic-gate 		goto out2;
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate 	/*
4257c478bd9Sstevel@tonic-gate 	 * Check accessibility of directory.
4267c478bd9Sstevel@tonic-gate 	 */
4277c478bd9Sstevel@tonic-gate 	if (tdp->i_type != VDIR) {
4287c478bd9Sstevel@tonic-gate 		err = ENOTDIR;
4297c478bd9Sstevel@tonic-gate 		goto out2;
4307c478bd9Sstevel@tonic-gate 	}
4317c478bd9Sstevel@tonic-gate 	/*
4327c478bd9Sstevel@tonic-gate 	 * Execute access is required to search the directory.
4337c478bd9Sstevel@tonic-gate 	 */
434*b39a0235SMilan Cermak 	if (err = ud_iaccess(tdp, IEXEC, cr, 1)) {
4357c478bd9Sstevel@tonic-gate 		goto out2;
4367c478bd9Sstevel@tonic-gate 	}
4377c478bd9Sstevel@tonic-gate 	/*
4387c478bd9Sstevel@tonic-gate 	 * If this is a rename of a directory and the parent is
4397c478bd9Sstevel@tonic-gate 	 * different (".." must be changed), then the source
4407c478bd9Sstevel@tonic-gate 	 * directory must not be in the directory hierarchy
4417c478bd9Sstevel@tonic-gate 	 * above the target, as this would orphan everything
4427c478bd9Sstevel@tonic-gate 	 * below the source directory.  Also the user must have
4437c478bd9Sstevel@tonic-gate 	 * write permission in the source so as to be able to
4447c478bd9Sstevel@tonic-gate 	 * change "..".
4457c478bd9Sstevel@tonic-gate 	 */
4467c478bd9Sstevel@tonic-gate 	if (op == DE_RENAME) {
4477c478bd9Sstevel@tonic-gate 		if (sip == tdp) {
4487c478bd9Sstevel@tonic-gate 			err = EINVAL;
4497c478bd9Sstevel@tonic-gate 			goto out2;
4507c478bd9Sstevel@tonic-gate 		}
4517c478bd9Sstevel@tonic-gate 		rw_enter(&sip->i_contents, RW_READER);
4527c478bd9Sstevel@tonic-gate 		if ((sip->i_type == VDIR) && (sdp != tdp)) {
4537c478bd9Sstevel@tonic-gate 			uint32_t blkno;
4547c478bd9Sstevel@tonic-gate 
455*b39a0235SMilan Cermak 			if ((err = ud_iaccess(sip, IWRITE, cr, 0))) {
4567c478bd9Sstevel@tonic-gate 				rw_exit(&sip->i_contents);
4577c478bd9Sstevel@tonic-gate 				goto out2;
4587c478bd9Sstevel@tonic-gate 			}
4597c478bd9Sstevel@tonic-gate 			blkno = sip->i_icb_lbano;
4607c478bd9Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
4617c478bd9Sstevel@tonic-gate 			if ((err = ud_dircheckpath(blkno, tdp, cr))) {
4627c478bd9Sstevel@tonic-gate 				goto out2;
4637c478bd9Sstevel@tonic-gate 			}
4647c478bd9Sstevel@tonic-gate 		} else {
4657c478bd9Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
4667c478bd9Sstevel@tonic-gate 		}
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	/*
4707c478bd9Sstevel@tonic-gate 	 * Search for the entry. Return VN_HELD tip if found.
4717c478bd9Sstevel@tonic-gate 	 */
4727c478bd9Sstevel@tonic-gate 	buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
4737c478bd9Sstevel@tonic-gate 	rw_enter(&tdp->i_contents, RW_WRITER);
4747c478bd9Sstevel@tonic-gate 	if (err = ud_dircheckforname(tdp,
475*b39a0235SMilan Cermak 	    namep, namlen, &slot, &tip, buf, cr)) {
4767c478bd9Sstevel@tonic-gate 		goto out;
4777c478bd9Sstevel@tonic-gate 	}
4787c478bd9Sstevel@tonic-gate 	if (tip) {
4797c478bd9Sstevel@tonic-gate 		switch (op) {
4807c478bd9Sstevel@tonic-gate 			case DE_CREATE :
4817c478bd9Sstevel@tonic-gate 			case DE_MKDIR :
4827c478bd9Sstevel@tonic-gate 				if (ipp) {
4837c478bd9Sstevel@tonic-gate 					*ipp = tip;
4847c478bd9Sstevel@tonic-gate 					err = EEXIST;
4857c478bd9Sstevel@tonic-gate 				} else {
4867c478bd9Sstevel@tonic-gate 					VN_RELE(ITOV(tip));
4877c478bd9Sstevel@tonic-gate 				}
4887c478bd9Sstevel@tonic-gate 				break;
4897c478bd9Sstevel@tonic-gate 			case DE_RENAME :
4907c478bd9Sstevel@tonic-gate 				err = ud_dirrename(sdp, sip, tdp, tip,
491*b39a0235SMilan Cermak 				    namep, buf, &slot, cr);
4927c478bd9Sstevel@tonic-gate 				/*
4937c478bd9Sstevel@tonic-gate 				 * We used to VN_RELE() here, but this
4947c478bd9Sstevel@tonic-gate 				 * was moved down so that we could send
4957c478bd9Sstevel@tonic-gate 				 * a vnevent after the locks were dropped.
4967c478bd9Sstevel@tonic-gate 				 */
4977c478bd9Sstevel@tonic-gate 				break;
4987c478bd9Sstevel@tonic-gate 			case DE_LINK :
4997c478bd9Sstevel@tonic-gate 				/*
5007c478bd9Sstevel@tonic-gate 				 * Can't link to an existing file.
5017c478bd9Sstevel@tonic-gate 				 */
5027c478bd9Sstevel@tonic-gate 				VN_RELE(ITOV(tip));
5037c478bd9Sstevel@tonic-gate 				err = EEXIST;
5047c478bd9Sstevel@tonic-gate 				break;
5057c478bd9Sstevel@tonic-gate 		}
5067c478bd9Sstevel@tonic-gate 	} else {
5077c478bd9Sstevel@tonic-gate 		/*
5087c478bd9Sstevel@tonic-gate 		 * The entry does not exist. Check write permission in
5097c478bd9Sstevel@tonic-gate 		 * directory to see if entry can be created.
5107c478bd9Sstevel@tonic-gate 		 */
511*b39a0235SMilan Cermak 		if (err = ud_iaccess(tdp, IWRITE, cr, 0)) {
5127c478bd9Sstevel@tonic-gate 			goto out;
5137c478bd9Sstevel@tonic-gate 		}
5147c478bd9Sstevel@tonic-gate 		if ((op == DE_CREATE) || (op == DE_MKDIR)) {
5157c478bd9Sstevel@tonic-gate 			/*
5167c478bd9Sstevel@tonic-gate 			 * Make new inode and directory entry as required.
5177c478bd9Sstevel@tonic-gate 			 */
5187c478bd9Sstevel@tonic-gate 			if (err = ud_dirmakeinode(tdp, &sip, vap, op, cr))
5197c478bd9Sstevel@tonic-gate 				goto out;
5207c478bd9Sstevel@tonic-gate 		}
5217c478bd9Sstevel@tonic-gate 		if (err = ud_diraddentry(tdp, namep, op,
5227c478bd9Sstevel@tonic-gate 		    namlen, &slot, sip, sdp, cr)) {
5237c478bd9Sstevel@tonic-gate 			if ((op == DE_CREATE) || (op == DE_MKDIR)) {
5247c478bd9Sstevel@tonic-gate 				/*
5257c478bd9Sstevel@tonic-gate 				 * Unmake the inode we just made.
5267c478bd9Sstevel@tonic-gate 				 */
5277c478bd9Sstevel@tonic-gate 				rw_enter(&sip->i_contents, RW_WRITER);
5287c478bd9Sstevel@tonic-gate 				if (sip->i_type == VDIR) {
5297c478bd9Sstevel@tonic-gate 					tdp->i_nlink--;
5307c478bd9Sstevel@tonic-gate 				}
5317c478bd9Sstevel@tonic-gate 				sip->i_nlink = 0;
5327c478bd9Sstevel@tonic-gate 				mutex_enter(&sip->i_tlock);
5337c478bd9Sstevel@tonic-gate 				sip->i_flag |= ICHG;
5347c478bd9Sstevel@tonic-gate 				mutex_exit(&sip->i_tlock);
5357c478bd9Sstevel@tonic-gate 				rw_exit(&sip->i_contents);
5367c478bd9Sstevel@tonic-gate 				VN_RELE(ITOV(sip));
5377c478bd9Sstevel@tonic-gate 				sip = NULL;
5387c478bd9Sstevel@tonic-gate 			}
5397c478bd9Sstevel@tonic-gate 		} else if (ipp) {
5407c478bd9Sstevel@tonic-gate 			*ipp = sip;
5417c478bd9Sstevel@tonic-gate 		} else if ((op == DE_CREATE) || (op == DE_MKDIR)) {
5427c478bd9Sstevel@tonic-gate 			VN_RELE(ITOV(sip));
5437c478bd9Sstevel@tonic-gate 		}
5447c478bd9Sstevel@tonic-gate 	}
5457c478bd9Sstevel@tonic-gate out:
5467c478bd9Sstevel@tonic-gate 	if (buf != NULL) {
5477c478bd9Sstevel@tonic-gate 		kmem_free(buf, udf_vfsp->udf_lbsize);
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate 	if (slot.fbp) {
5507c478bd9Sstevel@tonic-gate 		fbrelse(slot.fbp, S_OTHER);
5517c478bd9Sstevel@tonic-gate 	}
5527c478bd9Sstevel@tonic-gate 	rw_exit(&tdp->i_contents);
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	if (op == DE_RENAME) {
5557c478bd9Sstevel@tonic-gate 		/*
5567c478bd9Sstevel@tonic-gate 		 * If it's all good, send events after locks are dropped
5577c478bd9Sstevel@tonic-gate 		 * but before vnodes are released.
5587c478bd9Sstevel@tonic-gate 		 */
5597c478bd9Sstevel@tonic-gate 		if (err == 0) {
5607c478bd9Sstevel@tonic-gate 			if (tip) {
561df2381bfSpraks 				vnevent_rename_dest(ITOV(tip), ITOV(tdp),
562da6c28aaSamw 				    namep, ctp);
563df2381bfSpraks 			}
564df2381bfSpraks 
565df2381bfSpraks 			if (sdp != tdp) {
566da6c28aaSamw 				vnevent_rename_dest_dir(ITOV(tdp), ctp);
5677c478bd9Sstevel@tonic-gate 			}
5687c478bd9Sstevel@tonic-gate 		}
5697c478bd9Sstevel@tonic-gate 
5707c478bd9Sstevel@tonic-gate 		/*
5717c478bd9Sstevel@tonic-gate 		 * The following VN_RELE() was moved from the
5727c478bd9Sstevel@tonic-gate 		 * DE_RENAME case above
5737c478bd9Sstevel@tonic-gate 		 */
5747c478bd9Sstevel@tonic-gate 		if (tip) {
5757c478bd9Sstevel@tonic-gate 			VN_RELE(ITOV(tip));
5767c478bd9Sstevel@tonic-gate 		}
5777c478bd9Sstevel@tonic-gate 	}
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate out2:
5807c478bd9Sstevel@tonic-gate 	if (err && ((op == DE_LINK) || (op == DE_RENAME))) {
5817c478bd9Sstevel@tonic-gate 		/*
5827c478bd9Sstevel@tonic-gate 		 * Undo bumped link count.
5837c478bd9Sstevel@tonic-gate 		 */
5847c478bd9Sstevel@tonic-gate 		rw_enter(&sip->i_contents, RW_WRITER);
5857c478bd9Sstevel@tonic-gate 		sip->i_nlink--;
5867c478bd9Sstevel@tonic-gate 		rw_exit(&sip->i_contents);
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 		mutex_enter(&sip->i_tlock);
5897c478bd9Sstevel@tonic-gate 		sip->i_flag |= ICHG;
5907c478bd9Sstevel@tonic-gate 		mutex_exit(&sip->i_tlock);
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate 	return (err);
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate  * Locking i_contents in this
5977c478bd9Sstevel@tonic-gate  * function seems to be really weird
5987c478bd9Sstevel@tonic-gate  */
5997c478bd9Sstevel@tonic-gate int
600da6c28aaSamw ud_dirremove(
601da6c28aaSamw 	struct ud_inode *dp,
602da6c28aaSamw 	char *namep,
603da6c28aaSamw 	struct ud_inode *oip,
604da6c28aaSamw 	struct vnode *cdir,
605da6c28aaSamw 	enum dr_op op,
606da6c28aaSamw 	struct cred *cr,
607da6c28aaSamw 	caller_context_t *ctp)
6087c478bd9Sstevel@tonic-gate {
6097c478bd9Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
6107c478bd9Sstevel@tonic-gate 	int32_t namelen, err = 0;
6117c478bd9Sstevel@tonic-gate 	struct slot slot;
6127c478bd9Sstevel@tonic-gate 	struct ud_inode *ip;
6137c478bd9Sstevel@tonic-gate 	mode_t mode;
6147c478bd9Sstevel@tonic-gate 	struct file_id *fid;
6157c478bd9Sstevel@tonic-gate 	uint8_t *buf = NULL;
6167c478bd9Sstevel@tonic-gate 	uint32_t tbno;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	ud_printf("ud_dirremove\n");
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	udf_vfsp = dp->i_udf;
6237c478bd9Sstevel@tonic-gate 	namelen = (int)strlen(namep);
6247c478bd9Sstevel@tonic-gate 	if (namelen == 0) {
6257c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "name length == 0 in ud_dirremove");
6267c478bd9Sstevel@tonic-gate 		return (EINVAL);
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	/*
6307c478bd9Sstevel@tonic-gate 	 * return err when removing . and ..
6317c478bd9Sstevel@tonic-gate 	 */
6327c478bd9Sstevel@tonic-gate 	if (namep[0] == '.') {
6337c478bd9Sstevel@tonic-gate 		if (namelen == 1) {
6347c478bd9Sstevel@tonic-gate 			return (EINVAL);
6357c478bd9Sstevel@tonic-gate 		} else if (namelen == 2 && namep[1] == '.') {
6367c478bd9Sstevel@tonic-gate 			return (EEXIST);	/* SIGH should be ENOTEMPTY */
6377c478bd9Sstevel@tonic-gate 		}
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	/*
6437c478bd9Sstevel@tonic-gate 	 * Check accessibility of directory.
6447c478bd9Sstevel@tonic-gate 	 */
6457c478bd9Sstevel@tonic-gate 	if (dp->i_type != VDIR) {
6467c478bd9Sstevel@tonic-gate 		return (ENOTDIR);
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate 	ip = NULL;
6507c478bd9Sstevel@tonic-gate 	slot.status = FOUND;	/* don't need to look for empty slot */
6517c478bd9Sstevel@tonic-gate 	slot.offset = 0;
6527c478bd9Sstevel@tonic-gate 	slot.size = 0;
6537c478bd9Sstevel@tonic-gate 	slot.fbp = NULL;
6547c478bd9Sstevel@tonic-gate 	slot.ep = NULL;
6557c478bd9Sstevel@tonic-gate 	slot.endoff = 0;
6567c478bd9Sstevel@tonic-gate 	/*
6577c478bd9Sstevel@tonic-gate 	 * Execute access is required to search the directory.
6587c478bd9Sstevel@tonic-gate 	 * Access for write is interpreted as allowing
6597c478bd9Sstevel@tonic-gate 	 * deletion of files in the directory.
6607c478bd9Sstevel@tonic-gate 	 */
661*b39a0235SMilan Cermak 	if (err = ud_iaccess(dp, IEXEC|IWRITE, cr, 1)) {
6627c478bd9Sstevel@tonic-gate 		return (err);
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 	buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	rw_enter(&dp->i_contents, RW_WRITER);
6687c478bd9Sstevel@tonic-gate 
669*b39a0235SMilan Cermak 	if (err = ud_dircheckforname(dp, namep, namelen, &slot, &ip,
670*b39a0235SMilan Cermak 	    buf, cr)) {
6717c478bd9Sstevel@tonic-gate 		goto out_novfs;
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 	if (ip == NULL) {
6747c478bd9Sstevel@tonic-gate 		err = ENOENT;
6757c478bd9Sstevel@tonic-gate 		goto out_novfs;
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 	if (oip && oip != ip) {
6787c478bd9Sstevel@tonic-gate 		err = ENOENT;
6797c478bd9Sstevel@tonic-gate 		goto out_novfs;
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	if ((mode = ip->i_type) == VDIR) {
6837c478bd9Sstevel@tonic-gate 		/*
684d5dbd18dSbatschul 		 * vn_vfswlock() prevents races between mount and rmdir.
6857c478bd9Sstevel@tonic-gate 		 */
686d5dbd18dSbatschul 		if (vn_vfswlock(ITOV(ip))) {
6877c478bd9Sstevel@tonic-gate 			err = EBUSY;
6887c478bd9Sstevel@tonic-gate 			goto out_novfs;
6897c478bd9Sstevel@tonic-gate 		}
6907c478bd9Sstevel@tonic-gate 		if (vn_mountedvfs(ITOV(ip)) != NULL && op != DR_RENAME) {
6917c478bd9Sstevel@tonic-gate 			err = EBUSY;
6927c478bd9Sstevel@tonic-gate 			goto out;
6937c478bd9Sstevel@tonic-gate 		}
6947c478bd9Sstevel@tonic-gate 		/*
6957c478bd9Sstevel@tonic-gate 		 * If we are removing a directory, get a lock on it.
6967c478bd9Sstevel@tonic-gate 		 * If the directory is empty, it will stay empty until
6977c478bd9Sstevel@tonic-gate 		 * we can remove it.
6987c478bd9Sstevel@tonic-gate 		 */
6997c478bd9Sstevel@tonic-gate 		rw_enter(&ip->i_rwlock, RW_READER);
7007c478bd9Sstevel@tonic-gate 	}
7017c478bd9Sstevel@tonic-gate 	/* We must be holding i_contents */
7027c478bd9Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_READER);
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	if (err = ud_sticky_remove_access(dp, ip, cr)) {
7057c478bd9Sstevel@tonic-gate 		rw_exit(&ip->i_contents);
7067c478bd9Sstevel@tonic-gate 		if (mode == VDIR) {
7077c478bd9Sstevel@tonic-gate 			rw_exit(&ip->i_rwlock);
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 		goto out;
7107c478bd9Sstevel@tonic-gate 	}
7117c478bd9Sstevel@tonic-gate 	if (op == DR_RMDIR) {
7127c478bd9Sstevel@tonic-gate 		/*
7137c478bd9Sstevel@tonic-gate 		 * For rmdir(2), some special checks are required.
7147c478bd9Sstevel@tonic-gate 		 * (a) Don't remove any alias of the parent (e.g. ".").
7157c478bd9Sstevel@tonic-gate 		 * (b) Don't remove the current directory.
7167c478bd9Sstevel@tonic-gate 		 * (c) Make sure the entry is (still) a directory.
7177c478bd9Sstevel@tonic-gate 		 * (d) Make sure the directory is empty.
7187c478bd9Sstevel@tonic-gate 		 */
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 		if (dp == ip || ITOV(ip) == cdir) {
7217c478bd9Sstevel@tonic-gate 			err = EINVAL;
7227c478bd9Sstevel@tonic-gate 		} else if (ip->i_type != VDIR) {
7237c478bd9Sstevel@tonic-gate 			err = ENOTDIR;
7247c478bd9Sstevel@tonic-gate 		} else if ((ip->i_nlink != 1) ||
725*b39a0235SMilan Cermak 		    (!ud_dirempty(ip, dp->i_uniqid, cr))) {
7267c478bd9Sstevel@tonic-gate 			/*
7277c478bd9Sstevel@tonic-gate 			 * Directories do not have an
7287c478bd9Sstevel@tonic-gate 			 * entry for "." so only one link
7297c478bd9Sstevel@tonic-gate 			 * will be there
7307c478bd9Sstevel@tonic-gate 			 */
7317c478bd9Sstevel@tonic-gate 			err = EEXIST;	/* SIGH should be ENOTEMPTY */
7327c478bd9Sstevel@tonic-gate 		}
7337c478bd9Sstevel@tonic-gate 		if (err) {
7347c478bd9Sstevel@tonic-gate 			rw_exit(&ip->i_contents);
7357c478bd9Sstevel@tonic-gate 			if (mode == VDIR) {
7367c478bd9Sstevel@tonic-gate 				rw_exit(&ip->i_rwlock);
7377c478bd9Sstevel@tonic-gate 			}
7387c478bd9Sstevel@tonic-gate 			goto out;
7397c478bd9Sstevel@tonic-gate 		}
7407c478bd9Sstevel@tonic-gate 	} else if (op == DR_REMOVE)  {
7417c478bd9Sstevel@tonic-gate 		/*
7427c478bd9Sstevel@tonic-gate 		 * unlink(2) requires a different check: allow only
7437c478bd9Sstevel@tonic-gate 		 * privileged processes to unlink a directory.
7447c478bd9Sstevel@tonic-gate 		 */
7457c478bd9Sstevel@tonic-gate 		struct vnode *vp = ITOV(ip);
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate 		if (vp->v_type == VDIR &&
7487c478bd9Sstevel@tonic-gate 		    secpolicy_fs_linkdir(cr, vp->v_vfsp)) {
7497c478bd9Sstevel@tonic-gate 			err = EPERM;
7507c478bd9Sstevel@tonic-gate 			rw_exit(&ip->i_contents);
7517c478bd9Sstevel@tonic-gate 			rw_exit(&ip->i_rwlock);
7527c478bd9Sstevel@tonic-gate 			goto out;
7537c478bd9Sstevel@tonic-gate 		}
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
7567c478bd9Sstevel@tonic-gate 
7577c478bd9Sstevel@tonic-gate 	/*
7587c478bd9Sstevel@tonic-gate 	 * Remove the cache'd entry, if any.
7597c478bd9Sstevel@tonic-gate 	 */
7607c478bd9Sstevel@tonic-gate 	dnlc_remove(ITOV(dp), namep);
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	/*
7637c478bd9Sstevel@tonic-gate 	 * We can collapse all the directory
7647c478bd9Sstevel@tonic-gate 	 * entries that are deleted into one big entry
7657c478bd9Sstevel@tonic-gate 	 * but the better way is to
7667c478bd9Sstevel@tonic-gate 	 * defer it till next directory entry
7677c478bd9Sstevel@tonic-gate 	 * creation. where we can do this
7687c478bd9Sstevel@tonic-gate 	 * in a more efficient way
7697c478bd9Sstevel@tonic-gate 	 */
7707c478bd9Sstevel@tonic-gate 	fid = slot.ep;
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	/*
7737c478bd9Sstevel@tonic-gate 	 * If this is the last entry
7747c478bd9Sstevel@tonic-gate 	 * just truncate the file instead
7757c478bd9Sstevel@tonic-gate 	 * of marking it deleted
7767c478bd9Sstevel@tonic-gate 	 */
7777c478bd9Sstevel@tonic-gate 	if ((slot.offset + FID_LEN(fid)) == dp->i_size) {
7787c478bd9Sstevel@tonic-gate 		fbrelse(slot.fbp, S_OTHER);
7797c478bd9Sstevel@tonic-gate 		if ((err = ud_itrunc(dp, slot.offset, 0, cr)) != 0) {
7807c478bd9Sstevel@tonic-gate 			goto out;
7817c478bd9Sstevel@tonic-gate 		}
7827c478bd9Sstevel@tonic-gate 	} else {
7837c478bd9Sstevel@tonic-gate 		fid->fid_flags |= FID_DELETED;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 		if ((err = ud_ip_off2bno(dp, slot.offset, &tbno)) != 0) {
7867c478bd9Sstevel@tonic-gate 			goto out;
7877c478bd9Sstevel@tonic-gate 		}
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 		ud_make_tag(dp->i_udf, &fid->fid_tag,
790*b39a0235SMilan Cermak 		    UD_FILE_ID_DESC, tbno, FID_LEN(fid));
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 		err = ud_write_fid(dp, &slot, buf);
7937c478bd9Sstevel@tonic-gate 	}
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	slot.fbp = NULL;
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	/*
7987c478bd9Sstevel@tonic-gate 	 * If we were removing a directory, it is 'gone' now so we can
7997c478bd9Sstevel@tonic-gate 	 * unlock it.
8007c478bd9Sstevel@tonic-gate 	 */
8017c478bd9Sstevel@tonic-gate 	if (mode == VDIR) {
8027c478bd9Sstevel@tonic-gate 		rw_exit(&ip->i_rwlock);
8037c478bd9Sstevel@tonic-gate 	}
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	mutex_enter(&dp->i_tlock);
8067c478bd9Sstevel@tonic-gate 	dp->i_flag |= IUPD|ICHG;
8077c478bd9Sstevel@tonic-gate 	mutex_exit(&dp->i_tlock);
8087c478bd9Sstevel@tonic-gate 	mutex_enter(&ip->i_tlock);
8097c478bd9Sstevel@tonic-gate 	ip->i_flag |= ICHG;
8107c478bd9Sstevel@tonic-gate 	mutex_exit(&ip->i_tlock);
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	if (err != 0) {
8137c478bd9Sstevel@tonic-gate 		goto out;
8147c478bd9Sstevel@tonic-gate 	}
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_WRITER);
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	/*
8197c478bd9Sstevel@tonic-gate 	 * Now dispose of the inode.
8207c478bd9Sstevel@tonic-gate 	 */
8217c478bd9Sstevel@tonic-gate 	if (ip->i_nlink > 0) {
8227c478bd9Sstevel@tonic-gate 		if ((op == DR_RMDIR) && (ip->i_type == VDIR)) {
8237c478bd9Sstevel@tonic-gate 			/*
8247c478bd9Sstevel@tonic-gate 			 * Decrement by 1 because there is no "."
8257c478bd9Sstevel@tonic-gate 			 * Clear the inode, but there may be other hard
8267c478bd9Sstevel@tonic-gate 			 * links so don't free the inode.
8277c478bd9Sstevel@tonic-gate 			 * Decrement the dp linkcount because we're
8287c478bd9Sstevel@tonic-gate 			 * trashing the ".." entry.
8297c478bd9Sstevel@tonic-gate 			 */
8307c478bd9Sstevel@tonic-gate 			ip->i_nlink --;
8317c478bd9Sstevel@tonic-gate 			dp->i_nlink--;
8327c478bd9Sstevel@tonic-gate 			dnlc_remove(ITOV(ip), ".");
8337c478bd9Sstevel@tonic-gate 			dnlc_remove(ITOV(ip), "..");
8347c478bd9Sstevel@tonic-gate /*
8357c478bd9Sstevel@tonic-gate  *			(void) ud_itrunc(ip, 0, 0, cr);
8367c478bd9Sstevel@tonic-gate  */
8377c478bd9Sstevel@tonic-gate 		} else {
8387c478bd9Sstevel@tonic-gate 			ip->i_nlink--;
8397c478bd9Sstevel@tonic-gate 		}
8407c478bd9Sstevel@tonic-gate 	}
8417c478bd9Sstevel@tonic-gate 	ITIMES_NOLOCK(dp);
8427c478bd9Sstevel@tonic-gate 	ITIMES_NOLOCK(ip);
8437c478bd9Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
8447c478bd9Sstevel@tonic-gate out:
8457c478bd9Sstevel@tonic-gate 	if (mode == VDIR) {
8467c478bd9Sstevel@tonic-gate 		vn_vfsunlock(ITOV(ip));
8477c478bd9Sstevel@tonic-gate 	}
8487c478bd9Sstevel@tonic-gate out_novfs:
8497c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&dp->i_contents));
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	if (slot.fbp != NULL) {
8527c478bd9Sstevel@tonic-gate 		fbrelse(slot.fbp, S_OTHER);
8537c478bd9Sstevel@tonic-gate 	}
8547c478bd9Sstevel@tonic-gate 	rw_exit(&dp->i_contents);
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	if (ip) {
8577c478bd9Sstevel@tonic-gate 		/*
8587c478bd9Sstevel@tonic-gate 		 * If no errors, send any events after locks are dropped,
8597c478bd9Sstevel@tonic-gate 		 * but before the VN_RELE().
8607c478bd9Sstevel@tonic-gate 		 */
8617c478bd9Sstevel@tonic-gate 		if (err == 0) {
8627c478bd9Sstevel@tonic-gate 			if (op == DR_REMOVE) {
863da6c28aaSamw 				vnevent_remove(ITOV(ip), ITOV(dp), namep, ctp);
8647c478bd9Sstevel@tonic-gate 			} else if (op == DR_RMDIR) {
865da6c28aaSamw 				vnevent_rmdir(ITOV(ip), ITOV(dp), namep, ctp);
8667c478bd9Sstevel@tonic-gate 			}
8677c478bd9Sstevel@tonic-gate 		}
8687c478bd9Sstevel@tonic-gate 		VN_RELE(ITOV(ip));
8697c478bd9Sstevel@tonic-gate 	}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	kmem_free(buf, udf_vfsp->udf_lbsize);
8727c478bd9Sstevel@tonic-gate 	return (err);
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate int
8767c478bd9Sstevel@tonic-gate ud_dircheckforname(struct ud_inode *tdp,
8777c478bd9Sstevel@tonic-gate 	char *namep, int32_t namelen, struct slot *slotp,
8787c478bd9Sstevel@tonic-gate 	struct ud_inode **ipp, uint8_t *buf, struct cred *cr)
8797c478bd9Sstevel@tonic-gate {
8807c478bd9Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
8817c478bd9Sstevel@tonic-gate 	uint32_t dirsize, offset;
8827c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
8837c478bd9Sstevel@tonic-gate 	struct file_id *fid;
8847c478bd9Sstevel@tonic-gate 	int32_t sz, error = 0, sz_req, matched = 0;
8857c478bd9Sstevel@tonic-gate 	uint8_t *nm;
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 	uint8_t *dname;
8887c478bd9Sstevel@tonic-gate 	int32_t id_len;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	ud_printf("ud_dircheckforname\n");
8917c478bd9Sstevel@tonic-gate 
8927c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
8937c478bd9Sstevel@tonic-gate 	fbp = NULL;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	dname = (uint8_t *)kmem_zalloc(1024, KM_SLEEP);
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	udf_vfsp = tdp->i_udf;
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	offset = 0;
9007c478bd9Sstevel@tonic-gate 	dirsize = tdp->i_size;
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	if (slotp->status != FOUND) {
9037c478bd9Sstevel@tonic-gate 		int32_t temp;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 		temp = 1024; /* set to size of dname allocated above */
9067c478bd9Sstevel@tonic-gate 		if ((error = ud_compress(namelen, &temp,
907*b39a0235SMilan Cermak 		    (uint8_t *)namep, dname)) != 0) {
9087c478bd9Sstevel@tonic-gate 			goto end;
9097c478bd9Sstevel@tonic-gate 		}
9107c478bd9Sstevel@tonic-gate 		sz_req = F_LEN + temp;
9117c478bd9Sstevel@tonic-gate 		sz_req  = (sz_req + 3) & ~3;
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	while (offset < dirsize) {
9157c478bd9Sstevel@tonic-gate 		if ((error = ud_get_next_fid(tdp, &fbp,
916*b39a0235SMilan Cermak 		    offset, &fid, &nm, buf)) != 0) {
9177c478bd9Sstevel@tonic-gate 			break;
9187c478bd9Sstevel@tonic-gate 		}
9197c478bd9Sstevel@tonic-gate 		if ((error = ud_uncompress(fid->fid_idlen,
920*b39a0235SMilan Cermak 		    &id_len, nm, dname)) != 0) {
9217c478bd9Sstevel@tonic-gate 			break;
9227c478bd9Sstevel@tonic-gate 		}
9237c478bd9Sstevel@tonic-gate 		if ((fid->fid_flags & FID_DELETED) == 0) {
9247c478bd9Sstevel@tonic-gate 			/* Check for name match */
9257c478bd9Sstevel@tonic-gate 			if (((namelen == id_len) &&
926*b39a0235SMilan Cermak 			    (strncmp(namep, (caddr_t)dname, namelen) == 0)) ||
927*b39a0235SMilan Cermak 			    ((fid->fid_flags & FID_PARENT) &&
928*b39a0235SMilan Cermak 			    (namep[0] == '.' &&
929*b39a0235SMilan Cermak 			    (namelen == 1 ||
930*b39a0235SMilan Cermak 			    (namelen == 2 && namep[1] == '.'))))) {
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 				tdp->i_diroff = offset;
9337c478bd9Sstevel@tonic-gate 				if ((fid->fid_flags & FID_PARENT) &&
934*b39a0235SMilan Cermak 				    (namelen == 1) && (namep[0] == '.')) {
9357c478bd9Sstevel@tonic-gate 					struct vnode *vp = ITOV(tdp);
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 					*ipp = tdp;
9387c478bd9Sstevel@tonic-gate 					VN_HOLD(vp);
9397c478bd9Sstevel@tonic-gate 				} else {
9407c478bd9Sstevel@tonic-gate 					uint16_t prn;
9417c478bd9Sstevel@tonic-gate 					uint32_t loc;
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate 					prn = SWAP_16(fid->fid_icb.lad_ext_prn);
9447c478bd9Sstevel@tonic-gate 					loc = SWAP_32(fid->fid_icb.lad_ext_loc);
9457c478bd9Sstevel@tonic-gate 					if ((error = ud_iget(tdp->i_vfs, prn,
946*b39a0235SMilan Cermak 					    loc, ipp, NULL, cr)) != 0) {
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 						fbrelse(fbp, S_OTHER);
9497c478bd9Sstevel@tonic-gate 						goto end;
9507c478bd9Sstevel@tonic-gate 					}
9517c478bd9Sstevel@tonic-gate 				}
9527c478bd9Sstevel@tonic-gate 				slotp->status = EXIST;
9537c478bd9Sstevel@tonic-gate 				slotp->offset = offset;
9547c478bd9Sstevel@tonic-gate 				slotp->size = FID_LEN(fid);
9557c478bd9Sstevel@tonic-gate 				slotp->fbp = fbp;
9567c478bd9Sstevel@tonic-gate 				slotp->ep = fid;
9577c478bd9Sstevel@tonic-gate 				slotp->endoff = 0;
9587c478bd9Sstevel@tonic-gate 				goto end;
9597c478bd9Sstevel@tonic-gate 			}
9607c478bd9Sstevel@tonic-gate 		} else {
9617c478bd9Sstevel@tonic-gate 			/*
9627c478bd9Sstevel@tonic-gate 			 * see if we need to find an
9637c478bd9Sstevel@tonic-gate 			 * empty slot and the current slot
9647c478bd9Sstevel@tonic-gate 			 * matches
9657c478bd9Sstevel@tonic-gate 			 */
966*b39a0235SMilan Cermak 			if ((slotp->status != FOUND) || (matched == 0)) {
9677c478bd9Sstevel@tonic-gate 				sz = FID_LEN(fid);
9687c478bd9Sstevel@tonic-gate 				if (sz == sz_req) {
9697c478bd9Sstevel@tonic-gate 					slotp->status = FOUND;
9707c478bd9Sstevel@tonic-gate 					slotp->offset = offset;
9717c478bd9Sstevel@tonic-gate 					slotp->size = sz;
9727c478bd9Sstevel@tonic-gate 				}
9737c478bd9Sstevel@tonic-gate 				if (matched == 0) {
9747c478bd9Sstevel@tonic-gate 					if ((namelen == id_len) &&
975*b39a0235SMilan Cermak 					    (strncmp(namep, (caddr_t)dname,
976*b39a0235SMilan Cermak 					    namelen) == 0)) {
9777c478bd9Sstevel@tonic-gate 						matched = 1;
9787c478bd9Sstevel@tonic-gate 						slotp->status = FOUND;
9797c478bd9Sstevel@tonic-gate 						slotp->offset = offset;
9807c478bd9Sstevel@tonic-gate 						slotp->size = sz;
9817c478bd9Sstevel@tonic-gate 					}
9827c478bd9Sstevel@tonic-gate 				}
9837c478bd9Sstevel@tonic-gate 			}
9847c478bd9Sstevel@tonic-gate 		}
9857c478bd9Sstevel@tonic-gate 		offset += FID_LEN(fid);
9867c478bd9Sstevel@tonic-gate 	}
9877c478bd9Sstevel@tonic-gate 	if (fbp) {
9887c478bd9Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate 	if (slotp->status == NONE) {
9917c478bd9Sstevel@tonic-gate 		/*
9927c478bd9Sstevel@tonic-gate 		 * We didn't find a slot; the new directory entry should be put
9937c478bd9Sstevel@tonic-gate 		 * at the end of the directory.  Return an indication of where
9947c478bd9Sstevel@tonic-gate 		 * this is, and set "endoff" to zero; since we're going to have
9957c478bd9Sstevel@tonic-gate 		 * to extend the directory, we're certainly not going to
9967c478bd9Sstevel@tonic-gate 		 * trucate it.
9977c478bd9Sstevel@tonic-gate 		 */
9987c478bd9Sstevel@tonic-gate 		slotp->offset = dirsize;
9997c478bd9Sstevel@tonic-gate 		if (tdp->i_desc_type == ICB_FLAG_ONE_AD) {
10007c478bd9Sstevel@tonic-gate 			slotp->size = tdp->i_max_emb - tdp->i_size;
10017c478bd9Sstevel@tonic-gate 		} else {
10027c478bd9Sstevel@tonic-gate 			slotp->size = udf_vfsp->udf_lbsize -
1003*b39a0235SMilan Cermak 			    slotp->offset & udf_vfsp->udf_lbmask;
10047c478bd9Sstevel@tonic-gate 		}
10057c478bd9Sstevel@tonic-gate 		slotp->endoff = 0;
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	*ipp = NULL;
10097c478bd9Sstevel@tonic-gate end:
10107c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)dname, 1024);
10117c478bd9Sstevel@tonic-gate 	return (error);
10127c478bd9Sstevel@tonic-gate }
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate /*
10157c478bd9Sstevel@tonic-gate  * Return 1 if the dir has all files
10167c478bd9Sstevel@tonic-gate  * deleted except the parent
10177c478bd9Sstevel@tonic-gate  * else return 0
10187c478bd9Sstevel@tonic-gate  */
10197c478bd9Sstevel@tonic-gate /* ARGSUSED */
10207c478bd9Sstevel@tonic-gate int
10217c478bd9Sstevel@tonic-gate ud_dirempty(struct ud_inode *ip, uint64_t ino, struct cred *cr)
10227c478bd9Sstevel@tonic-gate {
10237c478bd9Sstevel@tonic-gate 	offset_t off;
10247c478bd9Sstevel@tonic-gate 	int32_t empty = 1, error, count, entry_len, rcount;
10257c478bd9Sstevel@tonic-gate 	struct file_id *fid;
10267c478bd9Sstevel@tonic-gate 	caddr_t addr;
10277c478bd9Sstevel@tonic-gate 	uint32_t tbno;
10287c478bd9Sstevel@tonic-gate 	int32_t	desc_len;
10297c478bd9Sstevel@tonic-gate 
10307c478bd9Sstevel@tonic-gate 	ud_printf("ud_dirempty\n");
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	ASSERT(RW_LOCK_HELD(&ip->i_contents));
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	if (ip->i_size == 0) {
10357c478bd9Sstevel@tonic-gate 		return (empty);
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	desc_len = 1024;
10397c478bd9Sstevel@tonic-gate 	addr = kmem_zalloc(desc_len, KM_SLEEP);
10407c478bd9Sstevel@tonic-gate 	fid = (struct file_id *)addr;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 	for (off = 0; off < ip->i_size; off += entry_len) {
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 		/*
10457c478bd9Sstevel@tonic-gate 		 * First read fid
10467c478bd9Sstevel@tonic-gate 		 * and verify checksum
10477c478bd9Sstevel@tonic-gate 		 */
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 		rcount = sizeof (struct file_id);
1050*b39a0235SMilan Cermak 		error = ud_rdwri(UIO_READ, FREAD, ip, addr, rcount, off,
1051*b39a0235SMilan Cermak 		    UIO_SYSSPACE, &count, cr);
10527c478bd9Sstevel@tonic-gate 		if ((error != 0) || (count != 0)) {
10537c478bd9Sstevel@tonic-gate 			empty = 0;
10547c478bd9Sstevel@tonic-gate 			break;
10557c478bd9Sstevel@tonic-gate 		}
10567c478bd9Sstevel@tonic-gate 
10577c478bd9Sstevel@tonic-gate 		if ((error = ud_ip_off2bno(ip, off, &tbno)) != 0) {
10587c478bd9Sstevel@tonic-gate 			empty = 0;
10597c478bd9Sstevel@tonic-gate 			break;
10607c478bd9Sstevel@tonic-gate 		}
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 		/*
10637c478bd9Sstevel@tonic-gate 		 * We verify the tag id and also the FID_LEN.
10647c478bd9Sstevel@tonic-gate 		 * FID_LEN should be <= desc_len.
10657c478bd9Sstevel@tonic-gate 		 */
10667c478bd9Sstevel@tonic-gate 		if (ud_verify_tag_and_desc(&fid->fid_tag,
10677c478bd9Sstevel@tonic-gate 		    UD_FILE_ID_DESC,
10687c478bd9Sstevel@tonic-gate 		    tbno, 0, desc_len) != 0) {
10697c478bd9Sstevel@tonic-gate 		/* Corrupted directory */
10707c478bd9Sstevel@tonic-gate 			empty = 0;
10717c478bd9Sstevel@tonic-gate 			break;
10727c478bd9Sstevel@tonic-gate 		}
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 		/*
10757c478bd9Sstevel@tonic-gate 		 * Read the fid + iulen + len
10767c478bd9Sstevel@tonic-gate 		 * Now verify both checksum andCRC
10777c478bd9Sstevel@tonic-gate 		 */
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 		rcount = FID_LEN(fid);
1080*b39a0235SMilan Cermak 		error = ud_rdwri(UIO_READ, FREAD, ip, addr, rcount, off,
1081*b39a0235SMilan Cermak 		    UIO_SYSSPACE, &count, cr);
10827c478bd9Sstevel@tonic-gate 		if ((error != 0) || (count != 0)) {
10837c478bd9Sstevel@tonic-gate 			empty = 0;
10847c478bd9Sstevel@tonic-gate 			break;
10857c478bd9Sstevel@tonic-gate 		}
10867c478bd9Sstevel@tonic-gate 		/*
10877c478bd9Sstevel@tonic-gate 		 * Now that the entire decsriptor is read we verify the
10887c478bd9Sstevel@tonic-gate 		 * crc.
10897c478bd9Sstevel@tonic-gate 		 */
10907c478bd9Sstevel@tonic-gate 		if (ud_verify_tag_and_desc(&fid->fid_tag,
10917c478bd9Sstevel@tonic-gate 		    UD_FILE_ID_DESC,
10927c478bd9Sstevel@tonic-gate 		    tbno,
10937c478bd9Sstevel@tonic-gate 		    1, rcount) != 0) {
10947c478bd9Sstevel@tonic-gate 			/* Corrupted directory */
10957c478bd9Sstevel@tonic-gate 			empty = 0;
10967c478bd9Sstevel@tonic-gate 			break;
10977c478bd9Sstevel@tonic-gate 		}
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 		/*
11007c478bd9Sstevel@tonic-gate 		 * Is the file deleted
11017c478bd9Sstevel@tonic-gate 		 */
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 		if ((fid->fid_flags & FID_DELETED) == 0) {
11047c478bd9Sstevel@tonic-gate 			if ((fid->fid_flags & FID_PARENT) == 0) {
11057c478bd9Sstevel@tonic-gate 				empty = 0;
11067c478bd9Sstevel@tonic-gate 				break;
11077c478bd9Sstevel@tonic-gate 			}
11087c478bd9Sstevel@tonic-gate 		}
11097c478bd9Sstevel@tonic-gate 		entry_len = FID_LEN(fid);
11107c478bd9Sstevel@tonic-gate 	}
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	kmem_free(addr, 1024);
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	return (empty);
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate int
11197c478bd9Sstevel@tonic-gate ud_dircheckpath(int32_t blkno,
11207c478bd9Sstevel@tonic-gate 	struct ud_inode *target, struct cred *cr)
11217c478bd9Sstevel@tonic-gate {
11227c478bd9Sstevel@tonic-gate 	int32_t err = 0;
11237c478bd9Sstevel@tonic-gate 	struct vfs *vfsp;
11247c478bd9Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
11257c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
11267c478bd9Sstevel@tonic-gate 	struct file_id *fid;
11277c478bd9Sstevel@tonic-gate 	struct ud_inode *ip, *tip;
11287c478bd9Sstevel@tonic-gate 	uint16_t prn;
11297c478bd9Sstevel@tonic-gate 	uint32_t lbno, dummy, tbno;
11307c478bd9Sstevel@tonic-gate 	daddr_t parent_icb_loc;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	ud_printf("ud_dircheckpath\n");
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 	udf_vfsp = target->i_udf;
11357c478bd9Sstevel@tonic-gate 	ip = target;
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate 	ASSERT(udf_vfsp != NULL);
11387c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&target->i_udf->udf_rename_lck));
11397c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&ip->i_rwlock));
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 	if (ip->i_icb_lbano == blkno) {
11427c478bd9Sstevel@tonic-gate 		err = EINVAL;
11437c478bd9Sstevel@tonic-gate 		goto out;
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate 	if (ip->i_icb_lbano == udf_vfsp->udf_root_blkno) {
11467c478bd9Sstevel@tonic-gate 		goto out;
11477c478bd9Sstevel@tonic-gate 	}
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	/*
11507c478bd9Sstevel@tonic-gate 	 * Search back through the directory tree, using the PARENT entries
11517c478bd9Sstevel@tonic-gate 	 * Fail any attempt to move a directory into an ancestor directory.
11527c478bd9Sstevel@tonic-gate 	 */
11537c478bd9Sstevel@tonic-gate 	for (;;) {
11547c478bd9Sstevel@tonic-gate 		if ((err = fbread(ITOV(ip), 0,
1155*b39a0235SMilan Cermak 		    udf_vfsp->udf_lbsize, S_READ, &fbp)) != 0) {
11567c478bd9Sstevel@tonic-gate 			break;
11577c478bd9Sstevel@tonic-gate 		}
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 		if ((err = ud_ip_off2bno(ip, 0, &tbno)) != 0) {
11607c478bd9Sstevel@tonic-gate 			break;
11617c478bd9Sstevel@tonic-gate 		}
11627c478bd9Sstevel@tonic-gate 		fid = (struct file_id *)fbp->fb_addr;
11637c478bd9Sstevel@tonic-gate 		/* IS this a valid file_identifier */
11647c478bd9Sstevel@tonic-gate 		if (ud_verify_tag_and_desc(&fid->fid_tag,
11657c478bd9Sstevel@tonic-gate 		    UD_FILE_ID_DESC,
11667c478bd9Sstevel@tonic-gate 		    tbno,
11677c478bd9Sstevel@tonic-gate 		    1, udf_vfsp->udf_lbsize) != 0) {
11687c478bd9Sstevel@tonic-gate 			break;
11697c478bd9Sstevel@tonic-gate 		}
11707c478bd9Sstevel@tonic-gate 		if ((fid->fid_flags & FID_DELETED) != 0) {
11717c478bd9Sstevel@tonic-gate 			break;
11727c478bd9Sstevel@tonic-gate 		}
11737c478bd9Sstevel@tonic-gate 		if ((fid->fid_flags & FID_PARENT) == 0) {
11747c478bd9Sstevel@tonic-gate 			/*
11757c478bd9Sstevel@tonic-gate 			 * This cannot happen unless
11767c478bd9Sstevel@tonic-gate 			 * something is grossly wrong
11777c478bd9Sstevel@tonic-gate 			 * First entry has to be parent
11787c478bd9Sstevel@tonic-gate 			 */
11797c478bd9Sstevel@tonic-gate 			break;
11807c478bd9Sstevel@tonic-gate 		}
11817c478bd9Sstevel@tonic-gate 		prn = SWAP_16(fid->fid_icb.lad_ext_prn);
11827c478bd9Sstevel@tonic-gate 		lbno = SWAP_32(fid->fid_icb.lad_ext_loc);
1183*b39a0235SMilan Cermak 		parent_icb_loc =
1184*b39a0235SMilan Cermak 		    ud_xlate_to_daddr(udf_vfsp, prn, lbno, 1, &dummy);
11857c478bd9Sstevel@tonic-gate 		ASSERT(dummy == 1);
11867c478bd9Sstevel@tonic-gate 		if (parent_icb_loc == blkno) {
11877c478bd9Sstevel@tonic-gate 			err = EINVAL;
11887c478bd9Sstevel@tonic-gate 			break;
11897c478bd9Sstevel@tonic-gate 		}
11907c478bd9Sstevel@tonic-gate 		vfsp = ip->i_vfs;
11917c478bd9Sstevel@tonic-gate 		udf_vfsp = ip->i_udf;
11927c478bd9Sstevel@tonic-gate 		if (parent_icb_loc == udf_vfsp->udf_root_blkno) {
11937c478bd9Sstevel@tonic-gate 			break;
11947c478bd9Sstevel@tonic-gate 		}
11957c478bd9Sstevel@tonic-gate 		if (fbp != NULL) {
11967c478bd9Sstevel@tonic-gate 			fbrelse(fbp, S_OTHER);
11977c478bd9Sstevel@tonic-gate 			fbp = NULL;
11987c478bd9Sstevel@tonic-gate 		}
11997c478bd9Sstevel@tonic-gate 		if (ip != target) {
12007c478bd9Sstevel@tonic-gate 			rw_exit(&ip->i_rwlock);
12017c478bd9Sstevel@tonic-gate 			VN_RELE(ITOV(ip));
12027c478bd9Sstevel@tonic-gate 		}
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate 		/*
12057c478bd9Sstevel@tonic-gate 		 * Race to get the inode.
12067c478bd9Sstevel@tonic-gate 		 */
12077c478bd9Sstevel@tonic-gate 		if (err = ud_iget(vfsp, prn, lbno, &tip, NULL, cr)) {
12087c478bd9Sstevel@tonic-gate 			ip = NULL;
12097c478bd9Sstevel@tonic-gate 			break;
12107c478bd9Sstevel@tonic-gate 		}
12117c478bd9Sstevel@tonic-gate 		ip = tip;
12127c478bd9Sstevel@tonic-gate 		rw_enter(&ip->i_rwlock, RW_READER);
12137c478bd9Sstevel@tonic-gate 	}
12147c478bd9Sstevel@tonic-gate 	if (fbp) {
12157c478bd9Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
12167c478bd9Sstevel@tonic-gate 	}
12177c478bd9Sstevel@tonic-gate out:
12187c478bd9Sstevel@tonic-gate 	if (ip) {
12197c478bd9Sstevel@tonic-gate 		if (ip != target) {
12207c478bd9Sstevel@tonic-gate 			rw_exit(&ip->i_rwlock);
12217c478bd9Sstevel@tonic-gate 			VN_RELE(ITOV(ip));
12227c478bd9Sstevel@tonic-gate 		}
12237c478bd9Sstevel@tonic-gate 	}
12247c478bd9Sstevel@tonic-gate 	return (err);
12257c478bd9Sstevel@tonic-gate }
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate int
12287c478bd9Sstevel@tonic-gate ud_dirmakeinode(struct ud_inode *tdp, struct ud_inode **ipp,
12297c478bd9Sstevel@tonic-gate 	struct vattr *vap, enum de_op op, struct cred *cr)
12307c478bd9Sstevel@tonic-gate {
12317c478bd9Sstevel@tonic-gate 	struct ud_inode *ip;
12327c478bd9Sstevel@tonic-gate 	int32_t error;
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	ASSERT(vap != NULL);
12357c478bd9Sstevel@tonic-gate 	ASSERT(op == DE_CREATE || op == DE_MKDIR);
12367c478bd9Sstevel@tonic-gate 	ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
12377c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 	/*
12407c478bd9Sstevel@tonic-gate 	 * Allocate a new inode.
12417c478bd9Sstevel@tonic-gate 	 */
12427c478bd9Sstevel@tonic-gate 	if ((error = ud_ialloc(tdp, &ip, vap, cr)) != 0) {
12437c478bd9Sstevel@tonic-gate 		return (error);
12447c478bd9Sstevel@tonic-gate 	}
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	ASSERT(ip != NULL);
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_WRITER);
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	if (op == DE_MKDIR) {
12517c478bd9Sstevel@tonic-gate 		error = ud_dirmakedirect(ip, tdp, cr);
12527c478bd9Sstevel@tonic-gate 	}
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	ip->i_flag |= IACC|IUPD|ICHG;
12557c478bd9Sstevel@tonic-gate 	/*
12567c478bd9Sstevel@tonic-gate 	 * Clear IACC and/or IUPD if the caller specified the atime and/or
12577c478bd9Sstevel@tonic-gate 	 * mtime fields.  They were set from the passed in attributes in
12587c478bd9Sstevel@tonic-gate 	 * ud_ialloc().
12597c478bd9Sstevel@tonic-gate 	 */
12607c478bd9Sstevel@tonic-gate 	if (vap->va_mask & AT_ATIME)
12617c478bd9Sstevel@tonic-gate 		ip->i_flag &= ~IACC;
12627c478bd9Sstevel@tonic-gate 	if (vap->va_mask & AT_MTIME)
12637c478bd9Sstevel@tonic-gate 		ip->i_flag &= ~IUPD;
12647c478bd9Sstevel@tonic-gate 	/*
12657c478bd9Sstevel@tonic-gate 	 * push inode before it's name appears in a directory
12667c478bd9Sstevel@tonic-gate 	 */
12677c478bd9Sstevel@tonic-gate 	ud_iupdat(ip, 1);
12687c478bd9Sstevel@tonic-gate 	*ipp = ip;
12697c478bd9Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
12707c478bd9Sstevel@tonic-gate 	return (error);
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate /*
12747c478bd9Sstevel@tonic-gate  * Enter the file sip in the directory tdp with name namep.
12757c478bd9Sstevel@tonic-gate  */
12767c478bd9Sstevel@tonic-gate int
12777c478bd9Sstevel@tonic-gate ud_diraddentry(struct ud_inode *tdp, char *namep,
12787c478bd9Sstevel@tonic-gate 	enum de_op op, int32_t namelen, struct slot *slotp,
12797c478bd9Sstevel@tonic-gate 	struct ud_inode *sip, struct ud_inode *sdp, struct cred *cr)
12807c478bd9Sstevel@tonic-gate {
12817c478bd9Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
12827c478bd9Sstevel@tonic-gate 	int32_t error, temp;
12837c478bd9Sstevel@tonic-gate 	struct file_id *fid;
12847c478bd9Sstevel@tonic-gate 	uint8_t *buf = NULL;
12857c478bd9Sstevel@tonic-gate 
12867c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	ud_printf("ud_diraddentry\n");
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 	udf_vfsp = sip->i_udf;
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 	/*
12937c478bd9Sstevel@tonic-gate 	 * Check inode to be linked to see if it is in the
12947c478bd9Sstevel@tonic-gate 	 * same filesystem.
12957c478bd9Sstevel@tonic-gate 	 */
12967c478bd9Sstevel@tonic-gate 	if (ITOV(tdp)->v_vfsp != ITOV(sip)->v_vfsp) {
12977c478bd9Sstevel@tonic-gate 		error = EXDEV;
12987c478bd9Sstevel@tonic-gate 		goto bad;
12997c478bd9Sstevel@tonic-gate 	}
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 	if ((op == DE_RENAME) && (sip->i_type == VDIR)) {
13027c478bd9Sstevel@tonic-gate 		if ((error = ud_dirfixdotdot(sip, sdp, tdp)) != 0) {
13037c478bd9Sstevel@tonic-gate 			goto bad;
13047c478bd9Sstevel@tonic-gate 		}
13057c478bd9Sstevel@tonic-gate 	}
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
13087c478bd9Sstevel@tonic-gate 
13097c478bd9Sstevel@tonic-gate 	/*
13107c478bd9Sstevel@tonic-gate 	 * Fill in entry data.
13117c478bd9Sstevel@tonic-gate 	 */
13127c478bd9Sstevel@tonic-gate 	fid = (struct file_id *)buf;
13137c478bd9Sstevel@tonic-gate 	fid->fid_ver = SWAP_16(1);
13147c478bd9Sstevel@tonic-gate 	if (sip->i_type == VDIR) {
13157c478bd9Sstevel@tonic-gate 		fid->fid_flags = FID_DIR;
13167c478bd9Sstevel@tonic-gate 	} else {
13177c478bd9Sstevel@tonic-gate 		fid->fid_flags = 0;
13187c478bd9Sstevel@tonic-gate 	}
13197c478bd9Sstevel@tonic-gate 	fid->fid_iulen = 0;
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	fid->fid_icb.lad_ext_len = SWAP_32(sip->i_udf->udf_lbsize);
13227c478bd9Sstevel@tonic-gate 	fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
13237c478bd9Sstevel@tonic-gate 	fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
13247c478bd9Sstevel@tonic-gate 	fid->fid_iulen = 0;
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	temp = udf_vfsp->udf_lbsize - F_LEN;
13277c478bd9Sstevel@tonic-gate 	if ((error = ud_compress(namelen, &temp,
1328*b39a0235SMilan Cermak 	    (uint8_t *)namep, fid->fid_spec)) == 0) {
13297c478bd9Sstevel@tonic-gate 		fid->fid_idlen = (uint8_t)temp;
13307c478bd9Sstevel@tonic-gate 		error = ud_dirprepareentry(tdp, slotp, buf, cr);
13317c478bd9Sstevel@tonic-gate 	}
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	kmem_free(buf, udf_vfsp->udf_lbsize);
13347c478bd9Sstevel@tonic-gate 
13357c478bd9Sstevel@tonic-gate bad:
13367c478bd9Sstevel@tonic-gate 	return (error);
13377c478bd9Sstevel@tonic-gate }
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate /*
13407c478bd9Sstevel@tonic-gate  * Write a prototype directory into the empty inode ip, whose parent is dp.
13417c478bd9Sstevel@tonic-gate  */
13427c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
13437c478bd9Sstevel@tonic-gate int
13447c478bd9Sstevel@tonic-gate ud_dirmakedirect(struct ud_inode *ip,
13457c478bd9Sstevel@tonic-gate 	struct ud_inode *dp, struct cred *cr)
13467c478bd9Sstevel@tonic-gate {
13477c478bd9Sstevel@tonic-gate 	int32_t err;
13487c478bd9Sstevel@tonic-gate 	uint32_t blkno, size, parent_len, tbno;
13497c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
13507c478bd9Sstevel@tonic-gate 	struct file_id *fid;
13517c478bd9Sstevel@tonic-gate 	struct icb_ext *iext;
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	ud_printf("ud_dirmakedirect\n");
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&ip->i_contents));
13567c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 	parent_len = sizeof (struct file_id);
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 	if ((ip->i_desc_type != ICB_FLAG_ONE_AD) ||
1361*b39a0235SMilan Cermak 	    (parent_len > ip->i_max_emb)) {
13627c478bd9Sstevel@tonic-gate 		ASSERT(ip->i_ext);
13637c478bd9Sstevel@tonic-gate 		/*
13647c478bd9Sstevel@tonic-gate 		 * Allocate space for the directory we're creating.
13657c478bd9Sstevel@tonic-gate 		 */
13667c478bd9Sstevel@tonic-gate 		if ((err = ud_alloc_space(ip->i_vfs, ip->i_icb_prn,
1367*b39a0235SMilan Cermak 		    0, 1, &blkno, &size, 0, 0)) != 0) {
13687c478bd9Sstevel@tonic-gate 			return (err);
13697c478bd9Sstevel@tonic-gate 		}
13707c478bd9Sstevel@tonic-gate 		/*
13717c478bd9Sstevel@tonic-gate 		 * init with the size of
13727c478bd9Sstevel@tonic-gate 		 * directory with just the
13737c478bd9Sstevel@tonic-gate 		 * parent
13747c478bd9Sstevel@tonic-gate 		 */
13757c478bd9Sstevel@tonic-gate 		ip->i_size = sizeof (struct file_id);
13767c478bd9Sstevel@tonic-gate 		ip->i_flag |= IUPD|ICHG|IATTCHG;
13777c478bd9Sstevel@tonic-gate 		iext = ip->i_ext;
13787c478bd9Sstevel@tonic-gate 		iext->ib_prn = ip->i_icb_prn;
13797c478bd9Sstevel@tonic-gate 		iext->ib_block = blkno;
13807c478bd9Sstevel@tonic-gate 		iext->ib_count = ip->i_size;
13817c478bd9Sstevel@tonic-gate 		iext->ib_offset = 0;
13827c478bd9Sstevel@tonic-gate 		ip->i_ext_used = 1;
13837c478bd9Sstevel@tonic-gate 	} else {
13847c478bd9Sstevel@tonic-gate 		ip->i_size = sizeof (struct file_id);
13857c478bd9Sstevel@tonic-gate 		ip->i_flag |= IUPD|ICHG|IATTCHG;
13867c478bd9Sstevel@tonic-gate 	}
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate 	ITIMES_NOLOCK(ip);
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	/*
13917c478bd9Sstevel@tonic-gate 	 * Update the dp link count and write out the change.
13927c478bd9Sstevel@tonic-gate 	 * This reflects the ".." entry we'll soon write.
13937c478bd9Sstevel@tonic-gate 	 */
13947c478bd9Sstevel@tonic-gate 	if (dp->i_nlink == MAXLINK) {
13957c478bd9Sstevel@tonic-gate 		return (EMLINK);
13967c478bd9Sstevel@tonic-gate 	}
13977c478bd9Sstevel@tonic-gate 	dp->i_nlink++;
13987c478bd9Sstevel@tonic-gate 	dp->i_flag |= ICHG;
13997c478bd9Sstevel@tonic-gate 	ud_iupdat(dp, 1);
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	/*
14027c478bd9Sstevel@tonic-gate 	 * Initialize directory with ".."
14037c478bd9Sstevel@tonic-gate 	 * Since the parent directory is locked, we don't have to
14047c478bd9Sstevel@tonic-gate 	 * worry about anything changing when we drop the write
14057c478bd9Sstevel@tonic-gate 	 * lock on (ip).
14067c478bd9Sstevel@tonic-gate 	 */
14077c478bd9Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
14087c478bd9Sstevel@tonic-gate 	if ((err = fbread(ITOV(ip), (offset_t)0,
1409*b39a0235SMilan Cermak 	    ip->i_udf->udf_lbsize, S_WRITE, &fbp)) != 0) {
14107c478bd9Sstevel@tonic-gate 		rw_enter(&ip->i_contents, RW_WRITER);
14117c478bd9Sstevel@tonic-gate 		return (err);
14127c478bd9Sstevel@tonic-gate 	}
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 	bzero(fbp->fb_addr, ip->i_udf->udf_lbsize);
14157c478bd9Sstevel@tonic-gate 
14167c478bd9Sstevel@tonic-gate 	fid = (struct file_id *)fbp->fb_addr;
14177c478bd9Sstevel@tonic-gate 	fid->fid_ver = SWAP_16(1);
14187c478bd9Sstevel@tonic-gate 	fid->fid_flags = FID_DIR | FID_PARENT;
14197c478bd9Sstevel@tonic-gate 	fid->fid_icb.lad_ext_len = SWAP_32(dp->i_udf->udf_lbsize);
14207c478bd9Sstevel@tonic-gate 	fid->fid_icb.lad_ext_loc = SWAP_32(dp->i_icb_block);
14217c478bd9Sstevel@tonic-gate 	fid->fid_icb.lad_ext_prn = SWAP_16(dp->i_icb_prn);
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	/*
14247c478bd9Sstevel@tonic-gate 	 * fid_idlen, fid_iulen and fid_spec are zero
14257c478bd9Sstevel@tonic-gate 	 * due to bzero above
14267c478bd9Sstevel@tonic-gate 	 */
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	if ((err = ud_ip_off2bno(ip, 0, &tbno)) == 0) {
14297c478bd9Sstevel@tonic-gate 		ud_make_tag(ip->i_udf, &fid->fid_tag,
1430*b39a0235SMilan Cermak 		    UD_FILE_ID_DESC, tbno, FID_LEN(fid));
14317c478bd9Sstevel@tonic-gate 	}
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	err = ud_fbwrite(fbp, ip);
14347c478bd9Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_WRITER);
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 	return (err);
14377c478bd9Sstevel@tonic-gate }
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate int
14407c478bd9Sstevel@tonic-gate ud_dirrename(struct ud_inode *sdp, struct ud_inode *sip,
14417c478bd9Sstevel@tonic-gate 	struct ud_inode *tdp, struct ud_inode *tip, char *namep,
14427c478bd9Sstevel@tonic-gate 	uint8_t *buf, struct slot *slotp, struct cred *cr)
14437c478bd9Sstevel@tonic-gate {
14447c478bd9Sstevel@tonic-gate 	int32_t error = 0, doingdirectory;
14457c478bd9Sstevel@tonic-gate 	struct file_id *fid;
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	ud_printf("ud_dirrename\n");
14487c478bd9Sstevel@tonic-gate 	ASSERT(sdp->i_udf != NULL);
14497c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&sdp->i_udf->udf_rename_lck));
14507c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
1451*b39a0235SMilan Cermak 	ASSERT(RW_WRITE_HELD(&tdp->i_contents));
14527c478bd9Sstevel@tonic-gate 	ASSERT(buf);
14537c478bd9Sstevel@tonic-gate 	ASSERT(slotp->ep);
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 	fid = slotp->ep;
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	/*
14587c478bd9Sstevel@tonic-gate 	 * Short circuit rename of something to itself.
14597c478bd9Sstevel@tonic-gate 	 */
14607c478bd9Sstevel@tonic-gate 	if (sip->i_icb_lbano == tip->i_icb_lbano) {
14617c478bd9Sstevel@tonic-gate 		return (ESAME);		/* special KLUDGE error code */
14627c478bd9Sstevel@tonic-gate 	}
14637c478bd9Sstevel@tonic-gate 	/*
14647c478bd9Sstevel@tonic-gate 	 * Everything is protected under the vfs_rename_lock so the ordering
14657c478bd9Sstevel@tonic-gate 	 * of i_contents locks doesn't matter here.
14667c478bd9Sstevel@tonic-gate 	 */
14677c478bd9Sstevel@tonic-gate 	rw_enter(&sip->i_contents, RW_READER);
14687c478bd9Sstevel@tonic-gate 	rw_enter(&tip->i_contents, RW_READER);
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate 	/*
14717c478bd9Sstevel@tonic-gate 	 * Check that everything is on the same filesystem.
14727c478bd9Sstevel@tonic-gate 	 */
14737c478bd9Sstevel@tonic-gate 	if ((ITOV(tip)->v_vfsp != ITOV(tdp)->v_vfsp) ||
14747c478bd9Sstevel@tonic-gate 	    (ITOV(tip)->v_vfsp != ITOV(sip)->v_vfsp)) {
14757c478bd9Sstevel@tonic-gate 		error = EXDEV;		/* XXX archaic */
14767c478bd9Sstevel@tonic-gate 		goto out;
14777c478bd9Sstevel@tonic-gate 	}
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate 	/*
14807c478bd9Sstevel@tonic-gate 	 * Must have write permission to rewrite target entry.
14817c478bd9Sstevel@tonic-gate 	 */
1482*b39a0235SMilan Cermak 	if ((error = ud_iaccess(tdp, IWRITE, cr, 0)) != 0 ||
14837c478bd9Sstevel@tonic-gate 	    (error = ud_sticky_remove_access(tdp, tip, cr)) != 0)
14847c478bd9Sstevel@tonic-gate 		goto out;
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 	/*
14877c478bd9Sstevel@tonic-gate 	 * Ensure source and target are compatible (both directories
14887c478bd9Sstevel@tonic-gate 	 * or both not directories).  If target is a directory it must
14897c478bd9Sstevel@tonic-gate 	 * be empty and have no links to it; in addition it must not
14907c478bd9Sstevel@tonic-gate 	 * be a mount point, and both the source and target must be
14917c478bd9Sstevel@tonic-gate 	 * writable.
14927c478bd9Sstevel@tonic-gate 	 */
14937c478bd9Sstevel@tonic-gate 	doingdirectory = (sip->i_type == VDIR);
14947c478bd9Sstevel@tonic-gate 	if (tip->i_type == VDIR) {
14957c478bd9Sstevel@tonic-gate 		if (!doingdirectory) {
14967c478bd9Sstevel@tonic-gate 			error = EISDIR;
14977c478bd9Sstevel@tonic-gate 			goto out;
14987c478bd9Sstevel@tonic-gate 		}
14997c478bd9Sstevel@tonic-gate 		/*
1500d5dbd18dSbatschul 		 * vn_vfswlock will prevent mounts from using the directory
1501d5dbd18dSbatschul 		 * until we are done.
15027c478bd9Sstevel@tonic-gate 		 */
1503d5dbd18dSbatschul 		if (vn_vfswlock(ITOV(tip))) {
15047c478bd9Sstevel@tonic-gate 			error = EBUSY;
15057c478bd9Sstevel@tonic-gate 			goto out;
15067c478bd9Sstevel@tonic-gate 		}
15077c478bd9Sstevel@tonic-gate 		if (vn_mountedvfs(ITOV(tip)) != NULL) {
15087c478bd9Sstevel@tonic-gate 			vn_vfsunlock(ITOV(tip));
15097c478bd9Sstevel@tonic-gate 			error = EBUSY;
15107c478bd9Sstevel@tonic-gate 			goto out;
15117c478bd9Sstevel@tonic-gate 		}
15127c478bd9Sstevel@tonic-gate 		if (!ud_dirempty(tip, tdp->i_uniqid, cr) || tip->i_nlink > 2) {
15137c478bd9Sstevel@tonic-gate 			vn_vfsunlock(ITOV(tip));
15147c478bd9Sstevel@tonic-gate 			error = EEXIST;	/* SIGH should be ENOTEMPTY */
15157c478bd9Sstevel@tonic-gate 			goto out;
15167c478bd9Sstevel@tonic-gate 		}
15177c478bd9Sstevel@tonic-gate 	} else if (doingdirectory) {
15187c478bd9Sstevel@tonic-gate 		error = ENOTDIR;
15197c478bd9Sstevel@tonic-gate 		goto out;
15207c478bd9Sstevel@tonic-gate 	}
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 	/*
15237c478bd9Sstevel@tonic-gate 	 * Rewrite the inode pointer for target name entry
15247c478bd9Sstevel@tonic-gate 	 * from the target inode (ip) to the source inode (sip).
15257c478bd9Sstevel@tonic-gate 	 * This prevents the target entry from disappearing
15267c478bd9Sstevel@tonic-gate 	 * during a crash. Mark the directory inode to reflect the changes.
15277c478bd9Sstevel@tonic-gate 	 */
15287c478bd9Sstevel@tonic-gate 	dnlc_remove(ITOV(tdp), namep);
15297c478bd9Sstevel@tonic-gate 	fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
15307c478bd9Sstevel@tonic-gate 	fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
15317c478bd9Sstevel@tonic-gate 	dnlc_enter(ITOV(tdp), namep, ITOV(sip));
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	ud_make_tag(tdp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1534*b39a0235SMilan Cermak 	    SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 	error = ud_write_fid(tdp, slotp, buf);
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	if (error) {
15397c478bd9Sstevel@tonic-gate 		if (doingdirectory) {
15407c478bd9Sstevel@tonic-gate 			vn_vfsunlock(ITOV(tip));
15417c478bd9Sstevel@tonic-gate 		}
15427c478bd9Sstevel@tonic-gate 		goto out;
15437c478bd9Sstevel@tonic-gate 	}
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 	/*
15467c478bd9Sstevel@tonic-gate 	 * Upgrade to write lock on tip
15477c478bd9Sstevel@tonic-gate 	 */
15487c478bd9Sstevel@tonic-gate 	rw_exit(&tip->i_contents);
15497c478bd9Sstevel@tonic-gate 	rw_enter(&tip->i_contents, RW_WRITER);
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	mutex_enter(&tdp->i_tlock);
15527c478bd9Sstevel@tonic-gate 	tdp->i_flag |= IUPD|ICHG;
15537c478bd9Sstevel@tonic-gate 	mutex_exit(&tdp->i_tlock);
15547c478bd9Sstevel@tonic-gate 	/*
15557c478bd9Sstevel@tonic-gate 	 * Decrement the link count of the target inode.
15567c478bd9Sstevel@tonic-gate 	 * Fix the ".." entry in sip to point to dp.
15577c478bd9Sstevel@tonic-gate 	 * This is done after the new entry is on the disk.
15587c478bd9Sstevel@tonic-gate 	 */
15597c478bd9Sstevel@tonic-gate 	tip->i_nlink--;
15607c478bd9Sstevel@tonic-gate 	mutex_enter(&tip->i_tlock);
15617c478bd9Sstevel@tonic-gate 	tip->i_flag |= ICHG;
15627c478bd9Sstevel@tonic-gate 	mutex_exit(&tip->i_tlock);
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 	if (doingdirectory) {
15657c478bd9Sstevel@tonic-gate 		/*
15667c478bd9Sstevel@tonic-gate 		 * The entry for tip no longer exists so I can unlock the
15677c478bd9Sstevel@tonic-gate 		 * vfslock.
15687c478bd9Sstevel@tonic-gate 		 */
15697c478bd9Sstevel@tonic-gate 		vn_vfsunlock(ITOV(tip));
15707c478bd9Sstevel@tonic-gate 		/*
15717c478bd9Sstevel@tonic-gate 		 * Decrement target link count once more if it was a directory.
15727c478bd9Sstevel@tonic-gate 		 */
15737c478bd9Sstevel@tonic-gate 		if (tip->i_nlink != 0) {
15747c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
15757c478bd9Sstevel@tonic-gate 			"ud_direnter: target directory link count != 0");
15767c478bd9Sstevel@tonic-gate 			rw_exit(&tip->i_contents);
15777c478bd9Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
15787c478bd9Sstevel@tonic-gate 			return (EINVAL);
15797c478bd9Sstevel@tonic-gate 		}
15807c478bd9Sstevel@tonic-gate 		/*
15817c478bd9Sstevel@tonic-gate 		 * Renaming a directory with the parent different
15827c478bd9Sstevel@tonic-gate 		 * requires that ".." be rewritten.  The window is
15837c478bd9Sstevel@tonic-gate 		 * still there for ".." to be inconsistent, but this
15847c478bd9Sstevel@tonic-gate 		 * is unavoidable, and a lot shorter than when it was
15857c478bd9Sstevel@tonic-gate 		 * done in a user process.  We decrement the link
15867c478bd9Sstevel@tonic-gate 		 * count in the new parent as appropriate to reflect
15877c478bd9Sstevel@tonic-gate 		 * the just-removed target.  If the parent is the
15887c478bd9Sstevel@tonic-gate 		 * same, this is appropriate since the original
15897c478bd9Sstevel@tonic-gate 		 * directory is going away.  If the new parent is
15907c478bd9Sstevel@tonic-gate 		 * different, dirfixdotdot() will bump the link count
15917c478bd9Sstevel@tonic-gate 		 * back.
15927c478bd9Sstevel@tonic-gate 		 */
15937c478bd9Sstevel@tonic-gate 		tdp->i_nlink--;
15947c478bd9Sstevel@tonic-gate 		mutex_enter(&tdp->i_tlock);
15957c478bd9Sstevel@tonic-gate 		tdp->i_flag |= ICHG;
15967c478bd9Sstevel@tonic-gate 		mutex_exit(&tdp->i_tlock);
15977c478bd9Sstevel@tonic-gate 		ITIMES_NOLOCK(tdp);
15987c478bd9Sstevel@tonic-gate 		if (sdp != tdp) {
15997c478bd9Sstevel@tonic-gate 			rw_exit(&tip->i_contents);
16007c478bd9Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
16017c478bd9Sstevel@tonic-gate 			error = ud_dirfixdotdot(sip, sdp, tdp);
16027c478bd9Sstevel@tonic-gate 			return (error);
16037c478bd9Sstevel@tonic-gate 		}
16047c478bd9Sstevel@tonic-gate 	}
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate out:
16077c478bd9Sstevel@tonic-gate 	rw_exit(&tip->i_contents);
16087c478bd9Sstevel@tonic-gate 	rw_exit(&sip->i_contents);
16097c478bd9Sstevel@tonic-gate 	return (error);
16107c478bd9Sstevel@tonic-gate }
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate /*
16147c478bd9Sstevel@tonic-gate  * 1. When we find a slot that belonged to a file which was deleted
16157c478bd9Sstevel@tonic-gate  *      and is in the middle of the directory
16167c478bd9Sstevel@tonic-gate  * 2. There is not empty slot available. The new entry
16177c478bd9Sstevel@tonic-gate  *      will be at the end of the directory and fits in the same block.
16187c478bd9Sstevel@tonic-gate  * 3. There is no empty slot available. The new
16197c478bd9Sstevel@tonic-gate  *      entry will not fit the left over directory
16207c478bd9Sstevel@tonic-gate  *      so we need to allocate a new block. If
16217c478bd9Sstevel@tonic-gate  *      we cannot allocate a proximity block we need
16227c478bd9Sstevel@tonic-gate  *      to allocate a new icb, and data block.
16237c478bd9Sstevel@tonic-gate  */
16247c478bd9Sstevel@tonic-gate int
16257c478bd9Sstevel@tonic-gate ud_dirprepareentry(struct ud_inode *dp,
16267c478bd9Sstevel@tonic-gate 	struct slot *slotp, uint8_t *buf, struct cred *cr)
16277c478bd9Sstevel@tonic-gate {
16287c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
16297c478bd9Sstevel@tonic-gate 	uint16_t old_dtype;
16307c478bd9Sstevel@tonic-gate 	int32_t error = 0;
16317c478bd9Sstevel@tonic-gate 	uint32_t entrysize, count, offset, tbno, old_size, off;
16327c478bd9Sstevel@tonic-gate 	struct file_id *fid;
16337c478bd9Sstevel@tonic-gate 	int32_t lbsize, lbmask, mask;
16347c478bd9Sstevel@tonic-gate 
16357c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
16367c478bd9Sstevel@tonic-gate 
1637*b39a0235SMilan Cermak 	ASSERT((slotp->status == NONE) || (slotp->status == FOUND));
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 	ud_printf("ud_dirprepareentry\n");
16407c478bd9Sstevel@tonic-gate 	lbsize = dp->i_udf->udf_lbsize;
16417c478bd9Sstevel@tonic-gate 	lbmask = dp->i_udf->udf_lbmask;
16427c478bd9Sstevel@tonic-gate 	mask = ~lbmask;
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	fid = (struct file_id *)buf;
16457c478bd9Sstevel@tonic-gate 	entrysize = FID_LEN(fid);
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	/*
16487c478bd9Sstevel@tonic-gate 	 * If we didn't find a slot, then indicate that the
16497c478bd9Sstevel@tonic-gate 	 * new slot belongs at the end of the directory.
16507c478bd9Sstevel@tonic-gate 	 * If we found a slot, then the new entry can be
16517c478bd9Sstevel@tonic-gate 	 * put at slotp->offset.
16527c478bd9Sstevel@tonic-gate 	 */
16537c478bd9Sstevel@tonic-gate 	if (slotp->status == NONE) {
16547c478bd9Sstevel@tonic-gate 		/*
16557c478bd9Sstevel@tonic-gate 		 * We did not find a slot, the next
16567c478bd9Sstevel@tonic-gate 		 * entry will be in the end of the directory
16577c478bd9Sstevel@tonic-gate 		 * see if we can fit the new entry inside
16587c478bd9Sstevel@tonic-gate 		 * the old block. If not allocate a new block.
16597c478bd9Sstevel@tonic-gate 		 */
16607c478bd9Sstevel@tonic-gate 		if (entrysize > slotp->size) {
16617c478bd9Sstevel@tonic-gate 			/*
16627c478bd9Sstevel@tonic-gate 			 * extend the directory
16637c478bd9Sstevel@tonic-gate 			 * size by one new block
16647c478bd9Sstevel@tonic-gate 			 */
16657c478bd9Sstevel@tonic-gate 			old_dtype = dp->i_desc_type;
16667c478bd9Sstevel@tonic-gate 			old_size = (uint32_t)dp->i_size;
16677c478bd9Sstevel@tonic-gate 			error = ud_bmap_write(dp, slotp->offset,
1668*b39a0235SMilan Cermak 			    blkoff(dp->i_udf, slotp->offset) + entrysize,
1669*b39a0235SMilan Cermak 			    0, cr);
16707c478bd9Sstevel@tonic-gate 			if (error != 0) {
16717c478bd9Sstevel@tonic-gate 				return (error);
16727c478bd9Sstevel@tonic-gate 			}
16737c478bd9Sstevel@tonic-gate 			if (old_dtype != dp->i_desc_type) {
16747c478bd9Sstevel@tonic-gate 				/*
16757c478bd9Sstevel@tonic-gate 				 * oops we changed the astrat
16767c478bd9Sstevel@tonic-gate 				 * of the file, we have to
16777c478bd9Sstevel@tonic-gate 				 * recaliculate tags
16787c478bd9Sstevel@tonic-gate 				 * fortunately we donot have more
16797c478bd9Sstevel@tonic-gate 				 * than one lbsize to handle here
16807c478bd9Sstevel@tonic-gate 				 */
16817c478bd9Sstevel@tonic-gate 				if ((error = ud_ip_off2bno(dp,
1682*b39a0235SMilan Cermak 				    0, &tbno)) != 0) {
16837c478bd9Sstevel@tonic-gate 					return (error);
16847c478bd9Sstevel@tonic-gate 				}
16857c478bd9Sstevel@tonic-gate 				if ((error = fbread(ITOV(dp), 0,
1686*b39a0235SMilan Cermak 				    dp->i_udf->udf_lbsize,
1687*b39a0235SMilan Cermak 				    S_WRITE, &fbp)) != 0) {
16887c478bd9Sstevel@tonic-gate 					return (error);
16897c478bd9Sstevel@tonic-gate 				}
16907c478bd9Sstevel@tonic-gate 				off = 0;
16917c478bd9Sstevel@tonic-gate 				while (off < old_size) {
16927c478bd9Sstevel@tonic-gate 					struct file_id *tfid;
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 					tfid = (struct file_id *)
1695*b39a0235SMilan Cermak 					    (fbp->fb_addr + off);
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 					ud_make_tag(dp->i_udf, &tfid->fid_tag,
1698*b39a0235SMilan Cermak 					    UD_FILE_ID_DESC, tbno,
1699*b39a0235SMilan Cermak 					    FID_LEN(tfid));
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 					off += FID_LEN(tfid);
17027c478bd9Sstevel@tonic-gate 				}
17037c478bd9Sstevel@tonic-gate 				if (error = ud_fbwrite(fbp, dp)) {
17047c478bd9Sstevel@tonic-gate 					return (error);
17057c478bd9Sstevel@tonic-gate 				}
17067c478bd9Sstevel@tonic-gate 			}
17077c478bd9Sstevel@tonic-gate 		} else {
17087c478bd9Sstevel@tonic-gate 			/* Extend the directory size */
17097c478bd9Sstevel@tonic-gate 			if (dp->i_desc_type != ICB_FLAG_ONE_AD) {
17107c478bd9Sstevel@tonic-gate 				ASSERT(dp->i_ext);
17117c478bd9Sstevel@tonic-gate 				dp->i_ext[dp->i_ext_used - 1].ib_count +=
1712*b39a0235SMilan Cermak 				    entrysize;
17137c478bd9Sstevel@tonic-gate 			}
17147c478bd9Sstevel@tonic-gate 		}
17157c478bd9Sstevel@tonic-gate 		dp->i_size += entrysize;
17167c478bd9Sstevel@tonic-gate 		dp->i_flag |= IUPD|ICHG|IATTCHG;
17177c478bd9Sstevel@tonic-gate 		ITIMES_NOLOCK(dp);
17187c478bd9Sstevel@tonic-gate 	} else if (slotp->status != FOUND) {
17197c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "status is not NONE/FOUND");
17207c478bd9Sstevel@tonic-gate 		return (EINVAL);
17217c478bd9Sstevel@tonic-gate 	}
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	if ((error = ud_ip_off2bno(dp, slotp->offset, &tbno)) != 0) {
17247c478bd9Sstevel@tonic-gate 		return (error);
17257c478bd9Sstevel@tonic-gate 	}
1726*b39a0235SMilan Cermak 	ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1727*b39a0235SMilan Cermak 	    tbno, FID_LEN(fid));
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 	/*
17307c478bd9Sstevel@tonic-gate 	 * fbread cannot cross a
17317c478bd9Sstevel@tonic-gate 	 * MAXBSIZE boundary so handle it here
17327c478bd9Sstevel@tonic-gate 	 */
17337c478bd9Sstevel@tonic-gate 	offset = slotp->offset;
17347c478bd9Sstevel@tonic-gate 	if ((error = fbread(ITOV(dp), offset & mask, lbsize,
1735*b39a0235SMilan Cermak 	    S_WRITE, &fbp)) != 0) {
17367c478bd9Sstevel@tonic-gate 		return (error);
17377c478bd9Sstevel@tonic-gate 	}
17387c478bd9Sstevel@tonic-gate 	if ((offset & mask) != ((offset + entrysize) & mask)) {
17397c478bd9Sstevel@tonic-gate 		count = entrysize - ((offset + entrysize) & lbmask);
17407c478bd9Sstevel@tonic-gate 	} else {
17417c478bd9Sstevel@tonic-gate 		count = entrysize;
17427c478bd9Sstevel@tonic-gate 	}
17437c478bd9Sstevel@tonic-gate 	bcopy((caddr_t)buf, fbp->fb_addr + (offset & lbmask), count);
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 	if (error = ud_fbwrite(fbp, dp)) {
17467c478bd9Sstevel@tonic-gate 		return (error);
17477c478bd9Sstevel@tonic-gate 	}
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 	if (entrysize > count) {
17507c478bd9Sstevel@tonic-gate 		if ((error = fbread(ITOV(dp), (offset + entrysize) & mask,
1751*b39a0235SMilan Cermak 		    lbsize, S_WRITE, &fbp)) != 0) {
17527c478bd9Sstevel@tonic-gate 			return (error);
17537c478bd9Sstevel@tonic-gate 		}
17547c478bd9Sstevel@tonic-gate 		bcopy((caddr_t)(buf + count), fbp->fb_addr, entrysize - count);
17557c478bd9Sstevel@tonic-gate 		if (error = ud_fbwrite(fbp, dp)) {
17567c478bd9Sstevel@tonic-gate 			return (error);
17577c478bd9Sstevel@tonic-gate 		}
17587c478bd9Sstevel@tonic-gate 	}
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 	dp->i_flag |= IUPD|ICHG|IATTCHG;
17617c478bd9Sstevel@tonic-gate 	ITIMES_NOLOCK(dp);
17627c478bd9Sstevel@tonic-gate 	return (error);
17637c478bd9Sstevel@tonic-gate }
17647c478bd9Sstevel@tonic-gate 
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate /*
17677c478bd9Sstevel@tonic-gate  * Fix the FID_PARENT entry of the child directory so that it points
17687c478bd9Sstevel@tonic-gate  * to the new parent directory instead of the old one.  Routine
17697c478bd9Sstevel@tonic-gate  * assumes that dp is a directory and that all the inodes are on
17707c478bd9Sstevel@tonic-gate  * the same file system.
17717c478bd9Sstevel@tonic-gate  */
17727c478bd9Sstevel@tonic-gate int
17737c478bd9Sstevel@tonic-gate ud_dirfixdotdot(struct ud_inode *dp,
17747c478bd9Sstevel@tonic-gate 	struct ud_inode *opdp, struct ud_inode *npdp)
17757c478bd9Sstevel@tonic-gate {
17767c478bd9Sstevel@tonic-gate 	int32_t err = 0;
17777c478bd9Sstevel@tonic-gate 	struct fbuf *fbp;
17787c478bd9Sstevel@tonic-gate 	struct file_id *fid;
17797c478bd9Sstevel@tonic-gate 	uint32_t loc, dummy, tbno;
17807c478bd9Sstevel@tonic-gate 
17817c478bd9Sstevel@tonic-gate 	ud_printf("ud_dirfixdotdot\n");
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate 	ASSERT(opdp->i_type == VDIR);
17847c478bd9Sstevel@tonic-gate 	ASSERT(npdp->i_type == VDIR);
17857c478bd9Sstevel@tonic-gate 
17867c478bd9Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&npdp->i_rwlock));
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate 	err = fbread(ITOV(dp), (offset_t)0,
1789*b39a0235SMilan Cermak 	    dp->i_udf->udf_lbsize, S_WRITE, &fbp);
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	if (err || dp->i_nlink == 0 ||
1792*b39a0235SMilan Cermak 	    dp->i_size < sizeof (struct file_id)) {
17937c478bd9Sstevel@tonic-gate 		goto bad;
17947c478bd9Sstevel@tonic-gate 	}
17957c478bd9Sstevel@tonic-gate 
17967c478bd9Sstevel@tonic-gate 	if ((err = ud_ip_off2bno(dp, 0, &tbno)) != 0) {
17977c478bd9Sstevel@tonic-gate 		goto bad;
17987c478bd9Sstevel@tonic-gate 	}
17997c478bd9Sstevel@tonic-gate 
18007c478bd9Sstevel@tonic-gate 	fid = (struct file_id *)fbp->fb_addr;
18017c478bd9Sstevel@tonic-gate 	if ((ud_verify_tag_and_desc(&fid->fid_tag, UD_FILE_ID_DESC,
18027c478bd9Sstevel@tonic-gate 	    tbno,
18037c478bd9Sstevel@tonic-gate 	    1, dp->i_udf->udf_lbsize) != 0) ||
18047c478bd9Sstevel@tonic-gate 	    ((fid->fid_flags & (FID_DIR | FID_PARENT)) !=
18057c478bd9Sstevel@tonic-gate 	    (FID_DIR | FID_PARENT))) {
18067c478bd9Sstevel@tonic-gate 		err = ENOTDIR;
18077c478bd9Sstevel@tonic-gate 		goto bad;
18087c478bd9Sstevel@tonic-gate 	}
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	loc = ud_xlate_to_daddr(dp->i_udf,
1811*b39a0235SMilan Cermak 	    SWAP_16(fid->fid_icb.lad_ext_prn),
1812*b39a0235SMilan Cermak 	    SWAP_32(fid->fid_icb.lad_ext_loc), 1, &dummy);
18137c478bd9Sstevel@tonic-gate 	ASSERT(dummy == 1);
18147c478bd9Sstevel@tonic-gate 	if (loc == npdp->i_icb_lbano) {
18157c478bd9Sstevel@tonic-gate 		goto bad;
18167c478bd9Sstevel@tonic-gate 	}
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 	/*
18197c478bd9Sstevel@tonic-gate 	 * Increment the link count in the new parent inode and force it out.
18207c478bd9Sstevel@tonic-gate 	 */
18217c478bd9Sstevel@tonic-gate 	if (npdp->i_nlink == MAXLINK) {
18227c478bd9Sstevel@tonic-gate 		err = EMLINK;
18237c478bd9Sstevel@tonic-gate 		goto bad;
18247c478bd9Sstevel@tonic-gate 	}
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate 	npdp->i_nlink++;
18277c478bd9Sstevel@tonic-gate 	mutex_enter(&npdp->i_tlock);
18287c478bd9Sstevel@tonic-gate 	npdp->i_flag |= ICHG;
18297c478bd9Sstevel@tonic-gate 	mutex_exit(&npdp->i_tlock);
18307c478bd9Sstevel@tonic-gate 	ud_iupdat(npdp, 1);
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate 	/*
18337c478bd9Sstevel@tonic-gate 	 * Rewrite the child FID_PARENT entry and force it out.
18347c478bd9Sstevel@tonic-gate 	 */
18357c478bd9Sstevel@tonic-gate 	dnlc_remove(ITOV(dp), "..");
18367c478bd9Sstevel@tonic-gate 	fid->fid_icb.lad_ext_loc = SWAP_32(npdp->i_icb_block);
18377c478bd9Sstevel@tonic-gate 	fid->fid_icb.lad_ext_prn = SWAP_16(npdp->i_icb_prn);
18387c478bd9Sstevel@tonic-gate 	ud_make_tag(npdp->i_udf, &fid->fid_tag,
1839*b39a0235SMilan Cermak 	    UD_FILE_ID_DESC, tbno, FID_LEN(fid));
18407c478bd9Sstevel@tonic-gate 	dnlc_enter(ITOV(dp), "..", ITOV(npdp));
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	err = ud_fbwrite(fbp, dp);
18437c478bd9Sstevel@tonic-gate 	fbp = NULL;
18447c478bd9Sstevel@tonic-gate 	if (err != 0) {
18457c478bd9Sstevel@tonic-gate 		goto bad;
18467c478bd9Sstevel@tonic-gate 	}
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate 	/*
18497c478bd9Sstevel@tonic-gate 	 * Decrement the link count of the old parent inode and force
18507c478bd9Sstevel@tonic-gate 	 * it out.  If opdp is NULL, then this is a new directory link;
18517c478bd9Sstevel@tonic-gate 	 * it has no parent, so we need not do anything.
18527c478bd9Sstevel@tonic-gate 	 */
18537c478bd9Sstevel@tonic-gate 	if (opdp != NULL) {
18547c478bd9Sstevel@tonic-gate 		rw_enter(&opdp->i_contents, RW_WRITER);
18557c478bd9Sstevel@tonic-gate 		if (opdp->i_nlink != 0) {
18567c478bd9Sstevel@tonic-gate 			opdp->i_nlink--;
18577c478bd9Sstevel@tonic-gate 			mutex_enter(&opdp->i_tlock);
18587c478bd9Sstevel@tonic-gate 			opdp->i_flag |= ICHG;
18597c478bd9Sstevel@tonic-gate 			mutex_exit(&opdp->i_tlock);
18607c478bd9Sstevel@tonic-gate 			ud_iupdat(opdp, 1);
18617c478bd9Sstevel@tonic-gate 		}
18627c478bd9Sstevel@tonic-gate 		rw_exit(&opdp->i_contents);
18637c478bd9Sstevel@tonic-gate 	}
18647c478bd9Sstevel@tonic-gate 	return (0);
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate bad:
18677c478bd9Sstevel@tonic-gate 	if (fbp) {
18687c478bd9Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
18697c478bd9Sstevel@tonic-gate 	}
18707c478bd9Sstevel@tonic-gate 	return (err);
18717c478bd9Sstevel@tonic-gate }
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate int32_t
18747c478bd9Sstevel@tonic-gate ud_write_fid(struct ud_inode *dp, struct slot *slot, uint8_t *buf)
18757c478bd9Sstevel@tonic-gate {
18767c478bd9Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
18777c478bd9Sstevel@tonic-gate 	struct fbuf *lfbp;
18787c478bd9Sstevel@tonic-gate 	struct file_id *fid;
18797c478bd9Sstevel@tonic-gate 	int32_t error = 0;
18807c478bd9Sstevel@tonic-gate 	uint32_t lbsize, lbmask, count, old_count;
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate 	ASSERT(slot->fbp);
18847c478bd9Sstevel@tonic-gate 	ASSERT(slot->ep);
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 	udf_vfsp = dp->i_udf;
18877c478bd9Sstevel@tonic-gate 	fid = slot->ep;
18887c478bd9Sstevel@tonic-gate 	lbsize = dp->i_udf->udf_lbsize;
18897c478bd9Sstevel@tonic-gate 	lbmask = dp->i_udf->udf_lbmask;
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 	if (((uint8_t *)fid >= buf) &&
1892*b39a0235SMilan Cermak 	    ((uint8_t *)fid < &buf[udf_vfsp->udf_lbsize])) {
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@tonic-gate 		if ((error = fbread(ITOV(dp),
1895*b39a0235SMilan Cermak 		    (offset_t)(slot->offset & ~lbmask),
1896*b39a0235SMilan Cermak 		    lbsize, S_WRITE, &lfbp)) != 0) {
18977c478bd9Sstevel@tonic-gate 			goto out;
18987c478bd9Sstevel@tonic-gate 		}
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 		/*
19027c478bd9Sstevel@tonic-gate 		 * We do not need to write the
19037c478bd9Sstevel@tonic-gate 		 * file name. So check if the entry
19047c478bd9Sstevel@tonic-gate 		 * does not cross a block boundary
19057c478bd9Sstevel@tonic-gate 		 * and write only required portions
19067c478bd9Sstevel@tonic-gate 		 */
19077c478bd9Sstevel@tonic-gate 		if (((slot->offset & lbmask) +
19087c478bd9Sstevel@tonic-gate 			sizeof (struct file_id)) > lbsize) {
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 			if ((slot->offset & lbmask) != 0) {
19117c478bd9Sstevel@tonic-gate 				old_count = lbsize -
19127c478bd9Sstevel@tonic-gate 					(slot->offset & lbmask);
19137c478bd9Sstevel@tonic-gate 				count = (slot->offset +
19147c478bd9Sstevel@tonic-gate 					sizeof (struct file_id)) &
19157c478bd9Sstevel@tonic-gate 					lbmask;
19167c478bd9Sstevel@tonic-gate 			} else {
19177c478bd9Sstevel@tonic-gate 				old_count = 0;
19187c478bd9Sstevel@tonic-gate 				count = sizeof (struct file_id);
19197c478bd9Sstevel@tonic-gate 			}
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 			bcopy(buf, lfbp->fb_addr +
19227c478bd9Sstevel@tonic-gate 				(slot->offset & lbmask), old_count);
19237c478bd9Sstevel@tonic-gate 			bcopy(buf + old_count,
19247c478bd9Sstevel@tonic-gate 				slot->fbp->fb_addr, count);
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 			error = ud_fbwrite(lfbp, dp);
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 			error = ud_fbwrite(slot->fbp, dp);
19297c478bd9Sstevel@tonic-gate 		} else {
19307c478bd9Sstevel@tonic-gate 			bcopy(buf, lfbp->fb_addr +
19317c478bd9Sstevel@tonic-gate 				(slot->offset & lbmask),
19327c478bd9Sstevel@tonic-gate 				sizeof (struct file_id));
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 			error = ud_fbwrite(lfbp, dp);
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 			fbrelse(slot->fbp, S_OTHER);
19377c478bd9Sstevel@tonic-gate 		}
19387c478bd9Sstevel@tonic-gate 	} else {
19397c478bd9Sstevel@tonic-gate 		if ((error = ud_fbwrite(slot->fbp, dp)) != 0) {
19407c478bd9Sstevel@tonic-gate 			fid->fid_flags &= ~FID_DELETED;
19417c478bd9Sstevel@tonic-gate 			ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
1942*b39a0235SMilan Cermak 			    SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
19437c478bd9Sstevel@tonic-gate 		}
19447c478bd9Sstevel@tonic-gate 	}
19457c478bd9Sstevel@tonic-gate 	slot->fbp = NULL;
19467c478bd9Sstevel@tonic-gate 
19477c478bd9Sstevel@tonic-gate out:
19487c478bd9Sstevel@tonic-gate 	return (error);
19497c478bd9Sstevel@tonic-gate }
1950