xref: /onnv-gate/usr/src/uts/common/fs/udfs/udf_dir.c (revision 12451:39b0738596da)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54863Spraks  * Common Development and Distribution License (the "License").
64863Spraks  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
2212196SMilan.Cermak@Sun.COM  * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <sys/types.h>
260Sstevel@tonic-gate #include <sys/t_lock.h>
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/time.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/sysmacros.h>
310Sstevel@tonic-gate #include <sys/resource.h>
320Sstevel@tonic-gate #include <sys/signal.h>
330Sstevel@tonic-gate #include <sys/cred.h>
340Sstevel@tonic-gate #include <sys/user.h>
350Sstevel@tonic-gate #include <sys/buf.h>
360Sstevel@tonic-gate #include <sys/vfs.h>
370Sstevel@tonic-gate #include <sys/stat.h>
380Sstevel@tonic-gate #include <sys/vnode.h>
390Sstevel@tonic-gate #include <sys/mode.h>
400Sstevel@tonic-gate #include <sys/proc.h>
410Sstevel@tonic-gate #include <sys/disp.h>
420Sstevel@tonic-gate #include <sys/file.h>
430Sstevel@tonic-gate #include <sys/fcntl.h>
440Sstevel@tonic-gate #include <sys/flock.h>
450Sstevel@tonic-gate #include <sys/kmem.h>
460Sstevel@tonic-gate #include <sys/uio.h>
470Sstevel@tonic-gate #include <sys/dnlc.h>
480Sstevel@tonic-gate #include <sys/conf.h>
490Sstevel@tonic-gate #include <sys/errno.h>
500Sstevel@tonic-gate #include <sys/mman.h>
510Sstevel@tonic-gate #include <sys/fbuf.h>
520Sstevel@tonic-gate #include <sys/pathname.h>
530Sstevel@tonic-gate #include <sys/debug.h>
540Sstevel@tonic-gate #include <sys/vmsystm.h>
550Sstevel@tonic-gate #include <sys/cmn_err.h>
560Sstevel@tonic-gate #include <sys/dirent.h>
570Sstevel@tonic-gate #include <sys/errno.h>
580Sstevel@tonic-gate #include <sys/modctl.h>
590Sstevel@tonic-gate #include <sys/statvfs.h>
600Sstevel@tonic-gate #include <sys/mount.h>
610Sstevel@tonic-gate #include <sys/sunddi.h>
620Sstevel@tonic-gate #include <sys/bootconf.h>
630Sstevel@tonic-gate #include <sys/policy.h>
640Sstevel@tonic-gate 
650Sstevel@tonic-gate #include <vm/hat.h>
660Sstevel@tonic-gate #include <vm/page.h>
670Sstevel@tonic-gate #include <vm/pvn.h>
680Sstevel@tonic-gate #include <vm/as.h>
690Sstevel@tonic-gate #include <vm/seg.h>
700Sstevel@tonic-gate #include <vm/seg_map.h>
710Sstevel@tonic-gate #include <vm/seg_kmem.h>
720Sstevel@tonic-gate #include <vm/seg_vn.h>
730Sstevel@tonic-gate #include <vm/rm.h>
740Sstevel@tonic-gate #include <vm/page.h>
750Sstevel@tonic-gate #include <sys/swap.h>
760Sstevel@tonic-gate 
770Sstevel@tonic-gate 
780Sstevel@tonic-gate #include <fs/fs_subr.h>
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 
810Sstevel@tonic-gate #include <sys/fs/udf_volume.h>
820Sstevel@tonic-gate #include <sys/fs/udf_inode.h>
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 
850Sstevel@tonic-gate struct slot {
860Sstevel@tonic-gate 	enum	{NONE, COMPACT, FOUND, EXIST} status;
870Sstevel@tonic-gate 	off_t	offset;		/* offset of area with free space */
880Sstevel@tonic-gate 	int	size;		/* size of area at slotoffset */
890Sstevel@tonic-gate 	struct	fbuf *fbp;	/* dir buf where slot is */
900Sstevel@tonic-gate 	struct file_id *ep;	/* pointer to slot */
910Sstevel@tonic-gate 	off_t	endoff;		/* last useful location found in search */
920Sstevel@tonic-gate };
930Sstevel@tonic-gate 
940Sstevel@tonic-gate 
950Sstevel@tonic-gate int32_t ud_dircheckforname(struct ud_inode *, char *, int,
960Sstevel@tonic-gate 		struct slot *, struct ud_inode **, uint8_t *, struct cred *);
970Sstevel@tonic-gate int32_t ud_dirempty(struct ud_inode *, uint64_t, struct cred *);
980Sstevel@tonic-gate int32_t str2cmp(char *, int32_t, char *, int32_t, char *, int32_t);
990Sstevel@tonic-gate int32_t ud_dircheckpath(int32_t, struct ud_inode *, struct cred *);
1000Sstevel@tonic-gate int32_t ud_dirmakeinode(struct ud_inode *, struct ud_inode **,
1010Sstevel@tonic-gate 	struct vattr *, enum de_op, struct cred *);
1020Sstevel@tonic-gate int32_t ud_diraddentry(struct ud_inode *, char *,
1030Sstevel@tonic-gate 	enum de_op, int, struct slot *, struct ud_inode *,
1040Sstevel@tonic-gate 	struct ud_inode *, struct cred *);
1050Sstevel@tonic-gate int32_t ud_dirmakedirect(struct ud_inode *, struct ud_inode *, struct cred *);
1060Sstevel@tonic-gate int32_t ud_dirrename(struct ud_inode *, struct ud_inode *,
1070Sstevel@tonic-gate 	struct ud_inode *, struct ud_inode *, char *, uint8_t *,
1080Sstevel@tonic-gate 	struct slot *, struct cred *);
1090Sstevel@tonic-gate int32_t ud_dirprepareentry(struct ud_inode *,
1100Sstevel@tonic-gate 	struct slot *, uint8_t *, struct cred *);
1110Sstevel@tonic-gate int32_t ud_dirfixdotdot(struct ud_inode *, struct ud_inode *,
1120Sstevel@tonic-gate 		struct ud_inode *);
1130Sstevel@tonic-gate int32_t ud_write_fid(struct ud_inode *, struct slot *, uint8_t *);
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate int
ud_dirlook(struct ud_inode * dip,char * namep,struct ud_inode ** ipp,struct cred * cr,int32_t skipdnlc)1160Sstevel@tonic-gate ud_dirlook(struct ud_inode *dip,
1170Sstevel@tonic-gate 	char *namep, struct ud_inode **ipp, struct cred *cr, int32_t skipdnlc)
1180Sstevel@tonic-gate {
1190Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
1200Sstevel@tonic-gate 	int32_t error = 0, namelen, adhoc_search;
1210Sstevel@tonic-gate 	u_offset_t offset, adhoc_offset, dirsize, end;
1220Sstevel@tonic-gate 	struct vnode *dvp, *vp;
1230Sstevel@tonic-gate 	struct fbuf *fbp;
1240Sstevel@tonic-gate 	struct file_id *fid;
1250Sstevel@tonic-gate 	uint8_t *fname, dummy[3];
1260Sstevel@tonic-gate 	int32_t id_len, doingchk;
1270Sstevel@tonic-gate 	uint32_t old_loc;
1280Sstevel@tonic-gate 	uint16_t old_prn;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	uint8_t *dname;
1310Sstevel@tonic-gate 	uint8_t *buf = NULL;
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	ud_printf("ud_dirlook\n");
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	udf_vfsp = dip->i_udf;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate restart:
1380Sstevel@tonic-gate 	doingchk = 0;
1390Sstevel@tonic-gate 	old_prn = 0xFFFF;
1400Sstevel@tonic-gate 	old_loc = 0;
1410Sstevel@tonic-gate 	dvp = ITOV(dip);
1420Sstevel@tonic-gate 	/*
1430Sstevel@tonic-gate 	 * Check accessibility of directory.
1440Sstevel@tonic-gate 	 */
1450Sstevel@tonic-gate 	if (dip->i_type != VDIR) {
1460Sstevel@tonic-gate 		return (ENOTDIR);
1470Sstevel@tonic-gate 	}
14812196SMilan.Cermak@Sun.COM 	if (error = ud_iaccess(dip, IEXEC, cr, 1)) {
1490Sstevel@tonic-gate 		return (error);
1500Sstevel@tonic-gate 	}
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	/*
1530Sstevel@tonic-gate 	 * Null component name is synonym for directory being searched.
1540Sstevel@tonic-gate 	 */
1550Sstevel@tonic-gate 	if (*namep == '\0') {
1560Sstevel@tonic-gate 		VN_HOLD(dvp);
1570Sstevel@tonic-gate 		*ipp = dip;
1580Sstevel@tonic-gate 		return (0);
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 	namelen = strlen(namep);
1610Sstevel@tonic-gate 	if ((namelen == 1) &&
16212196SMilan.Cermak@Sun.COM 	    (namep[0] == '.') && (namep[1] == '\0')) {
1630Sstevel@tonic-gate 		/* Current directory */
1640Sstevel@tonic-gate 		VN_HOLD(dvp);
1650Sstevel@tonic-gate 		*ipp = dip;
1660Sstevel@tonic-gate 		dnlc_enter(dvp, namep, ITOV(*ipp));
1670Sstevel@tonic-gate 		return (0);
1680Sstevel@tonic-gate 	}
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate 	if ((!skipdnlc) && (vp = dnlc_lookup(dvp, namep))) {
1710Sstevel@tonic-gate 		/* vp is already held from dnlc_lookup */
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 		*ipp = VTOI(vp);
1740Sstevel@tonic-gate 		return (0);
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	dname = kmem_zalloc(1024, KM_SLEEP);
1780Sstevel@tonic-gate 	buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate 	/*
1810Sstevel@tonic-gate 	 * Read lock the inode we are searching.  You will notice that we
1820Sstevel@tonic-gate 	 * didn't hold the read lock while searching the dnlc.  This means
1830Sstevel@tonic-gate 	 * that the entry could now be in the dnlc.  This doesn't cause any
1840Sstevel@tonic-gate 	 * problems because dnlc_enter won't add an entry if it is already
1850Sstevel@tonic-gate 	 * there.
1860Sstevel@tonic-gate 	 */
1870Sstevel@tonic-gate 	rw_enter(&dip->i_rwlock, RW_READER);
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	/*
1900Sstevel@tonic-gate 	 * Take care to look at dip->i_diroff only once, as it
1910Sstevel@tonic-gate 	 * may be changing due to other threads/cpus.
1920Sstevel@tonic-gate 	 */
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate recheck:
1950Sstevel@tonic-gate 	offset = dip->i_diroff;
1960Sstevel@tonic-gate 	end = dirsize = dip->i_size;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	if (offset > dirsize) {
1990Sstevel@tonic-gate 		offset = 0;
2000Sstevel@tonic-gate 	}
2010Sstevel@tonic-gate 	adhoc_offset = offset;
2020Sstevel@tonic-gate 	adhoc_search = (offset == 0) ? 1 : 2;
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	fbp = NULL;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	while (adhoc_search--) {
2070Sstevel@tonic-gate 		while (offset < end) {
2080Sstevel@tonic-gate 			error = ud_get_next_fid(dip, &fbp,
20912196SMilan.Cermak@Sun.COM 			    offset, &fid, &fname, buf);
2100Sstevel@tonic-gate 			if (error != 0) {
2110Sstevel@tonic-gate 				break;
2120Sstevel@tonic-gate 			}
2130Sstevel@tonic-gate 			if ((fid->fid_flags & FID_DELETED) == 0) {
2140Sstevel@tonic-gate 				if (fid->fid_flags & FID_PARENT) {
2150Sstevel@tonic-gate 					id_len = 2;
2160Sstevel@tonic-gate 					fname = dummy;
2170Sstevel@tonic-gate 					dummy[0] = '.';
2180Sstevel@tonic-gate 					dummy[1] = '.';
2190Sstevel@tonic-gate 					dummy[2] = '\0';
2200Sstevel@tonic-gate 				} else {
2210Sstevel@tonic-gate 					if ((error = ud_uncompress(
22212196SMilan.Cermak@Sun.COM 					    fid->fid_idlen, &id_len,
22312196SMilan.Cermak@Sun.COM 					    fname, dname)) != 0) {
2240Sstevel@tonic-gate 						break;
2250Sstevel@tonic-gate 					}
2260Sstevel@tonic-gate 					fname = (uint8_t *)dname;
2270Sstevel@tonic-gate 					fname[id_len] = '\0';
2280Sstevel@tonic-gate 				}
2290Sstevel@tonic-gate 				if ((namelen == id_len) &&
23012196SMilan.Cermak@Sun.COM 				    (strncmp(namep, (caddr_t)fname,
23112196SMilan.Cermak@Sun.COM 				    namelen) == 0)) {
2320Sstevel@tonic-gate 					uint32_t loc;
2330Sstevel@tonic-gate 					uint16_t prn;
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 					loc = SWAP_32(fid->fid_icb.lad_ext_loc);
2370Sstevel@tonic-gate 					prn = SWAP_16(fid->fid_icb.lad_ext_prn);
23812196SMilan.Cermak@Sun.COM 					dip->i_diroff = offset + FID_LEN(fid);
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 					if (doingchk) {
2410Sstevel@tonic-gate 						if ((loc == old_loc) &&
24212196SMilan.Cermak@Sun.COM 						    (prn == old_prn)) {
2430Sstevel@tonic-gate 							goto checkok;
2440Sstevel@tonic-gate 						} else {
2450Sstevel@tonic-gate 							if (fbp != NULL) {
2460Sstevel@tonic-gate 								fbrelse(fbp,
24712196SMilan.Cermak@Sun.COM 								    S_READ);
2480Sstevel@tonic-gate 								fbp = NULL;
2490Sstevel@tonic-gate 							}
2500Sstevel@tonic-gate 							VN_RELE(ITOV(*ipp));
2510Sstevel@tonic-gate 							rw_exit(&dip->i_rwlock);
2520Sstevel@tonic-gate 							goto restart;
2530Sstevel@tonic-gate 						}
2540Sstevel@tonic-gate 						/* NOTREACHED */
2550Sstevel@tonic-gate 					}
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 					if (namelen == 2 &&
25812196SMilan.Cermak@Sun.COM 					    fname[0] == '.' &&
25912196SMilan.Cermak@Sun.COM 					    fname[1] == '.') {
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate 						struct timespec32 omtime;
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 						omtime = dip->i_mtime;
2640Sstevel@tonic-gate 						rw_exit(&dip->i_rwlock);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 						error = ud_iget(dip->i_vfs, prn,
26712196SMilan.Cermak@Sun.COM 						    loc, ipp, NULL, cr);
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 						rw_enter(&dip->i_rwlock,
27012196SMilan.Cermak@Sun.COM 						    RW_READER);
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 						if (error) {
2730Sstevel@tonic-gate 							goto done;
2740Sstevel@tonic-gate 						}
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate 						if ((omtime.tv_sec !=
27712196SMilan.Cermak@Sun.COM 						    dip->i_mtime.tv_sec) ||
27812196SMilan.Cermak@Sun.COM 						    (omtime.tv_nsec !=
27912196SMilan.Cermak@Sun.COM 						    dip->i_mtime.tv_nsec)) {
2800Sstevel@tonic-gate 
2810Sstevel@tonic-gate 							doingchk = 1;
2820Sstevel@tonic-gate 							old_prn = prn;
2830Sstevel@tonic-gate 							old_loc = loc;
2840Sstevel@tonic-gate 							dip->i_diroff = 0;
2850Sstevel@tonic-gate 							if (fbp != NULL) {
2860Sstevel@tonic-gate 								fbrelse(fbp,
28712196SMilan.Cermak@Sun.COM 								    S_READ);
2880Sstevel@tonic-gate 								fbp = NULL;
2890Sstevel@tonic-gate 							}
2900Sstevel@tonic-gate 							goto recheck;
2910Sstevel@tonic-gate 						}
2920Sstevel@tonic-gate 					} else {
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 						error = ud_iget(dip->i_vfs, prn,
29512196SMilan.Cermak@Sun.COM 						    loc, ipp, NULL, cr);
2960Sstevel@tonic-gate 					}
2970Sstevel@tonic-gate checkok:
2980Sstevel@tonic-gate 					if (error == 0) {
2990Sstevel@tonic-gate 						dnlc_enter(dvp, namep,
30012196SMilan.Cermak@Sun.COM 						    ITOV(*ipp));
3010Sstevel@tonic-gate 					}
3020Sstevel@tonic-gate 					goto done;
3030Sstevel@tonic-gate 				}
3040Sstevel@tonic-gate 			}
3050Sstevel@tonic-gate 			offset += FID_LEN(fid);
3060Sstevel@tonic-gate 		}
3070Sstevel@tonic-gate 		if (fbp != NULL) {
3080Sstevel@tonic-gate 			fbrelse(fbp, S_READ);
3090Sstevel@tonic-gate 			fbp = NULL;
3100Sstevel@tonic-gate 		}
3110Sstevel@tonic-gate 		end = adhoc_offset;
3120Sstevel@tonic-gate 		offset = 0;
3130Sstevel@tonic-gate 	}
3140Sstevel@tonic-gate 	error = ENOENT;
3150Sstevel@tonic-gate done:
3160Sstevel@tonic-gate 	kmem_free(buf, udf_vfsp->udf_lbsize);
3170Sstevel@tonic-gate 	kmem_free(dname, 1024);
3180Sstevel@tonic-gate 	if (fbp != NULL) {
3190Sstevel@tonic-gate 		fbrelse(fbp, S_READ);
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 	rw_exit(&dip->i_rwlock);
3220Sstevel@tonic-gate 	return (error);
3230Sstevel@tonic-gate }
3240Sstevel@tonic-gate 
3250Sstevel@tonic-gate int
ud_direnter(struct ud_inode * tdp,char * namep,enum de_op op,struct ud_inode * sdp,struct ud_inode * sip,struct vattr * vap,struct ud_inode ** ipp,struct cred * cr,caller_context_t * ctp)3265331Samw ud_direnter(
3275331Samw 	struct ud_inode *tdp,
3285331Samw 	char *namep,
3295331Samw 	enum de_op op,
3305331Samw 	struct ud_inode *sdp,
3315331Samw 	struct ud_inode *sip,
3325331Samw 	struct vattr *vap,
3335331Samw 	struct ud_inode **ipp,
3345331Samw 	struct cred *cr,
3355331Samw 	caller_context_t *ctp)
3360Sstevel@tonic-gate {
3370Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
3380Sstevel@tonic-gate 	struct ud_inode *tip;
3390Sstevel@tonic-gate 	struct slot slot;
3400Sstevel@tonic-gate 	int32_t namlen, err;
3410Sstevel@tonic-gate 	char *s;
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	uint8_t *buf = NULL;
3440Sstevel@tonic-gate 
3450Sstevel@tonic-gate 	ud_printf("ud_direnter\n");
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	udf_vfsp = tdp->i_udf;
3480Sstevel@tonic-gate 	/* don't allow '/' characters in pathname component */
3490Sstevel@tonic-gate 	for (s = namep, namlen = 0; *s; s++, namlen++) {
3500Sstevel@tonic-gate 		if (*s == '/') {
3510Sstevel@tonic-gate 			return (EACCES);
3520Sstevel@tonic-gate 		}
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	if (namlen == 0) {
3560Sstevel@tonic-gate 		cmn_err(CE_WARN, "name length == 0 in ud_direnter");
3570Sstevel@tonic-gate 		return (EINVAL);
3580Sstevel@tonic-gate 	}
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
3610Sstevel@tonic-gate 	/*
3620Sstevel@tonic-gate 	 * If name is "." or ".." then if this is a create look it up
3630Sstevel@tonic-gate 	 * and return EEXIST.  Rename or link TO "." or ".." is forbidden.
3640Sstevel@tonic-gate 	 */
3650Sstevel@tonic-gate 	if (namep[0] == '.' &&
3660Sstevel@tonic-gate 	    (namlen == 1 || (namlen == 2 && namep[1] == '.'))) {
3670Sstevel@tonic-gate 		if (op == DE_RENAME) {
3680Sstevel@tonic-gate 			return (EINVAL);	/* *SIGH* should be ENOTEMPTY */
3690Sstevel@tonic-gate 		}
3700Sstevel@tonic-gate 		if (ipp) {
3710Sstevel@tonic-gate 			/*
3720Sstevel@tonic-gate 			 * ud_dirlook will acquire the i_rwlock
3730Sstevel@tonic-gate 			 */
3740Sstevel@tonic-gate 			rw_exit(&tdp->i_rwlock);
3750Sstevel@tonic-gate 			if (err = ud_dirlook(tdp, namep, ipp, cr, 0)) {
3760Sstevel@tonic-gate 				rw_enter(&tdp->i_rwlock, RW_WRITER);
3770Sstevel@tonic-gate 				return (err);
3780Sstevel@tonic-gate 			}
3790Sstevel@tonic-gate 			rw_enter(&tdp->i_rwlock, RW_WRITER);
3800Sstevel@tonic-gate 		}
3810Sstevel@tonic-gate 		return (EEXIST);
3820Sstevel@tonic-gate 	}
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	tip = NULL;
3850Sstevel@tonic-gate 	slot.status = NONE;
3860Sstevel@tonic-gate 	slot.offset = 0;
3870Sstevel@tonic-gate 	slot.size = 0;
3880Sstevel@tonic-gate 	slot.fbp = NULL;
3890Sstevel@tonic-gate 	slot.ep = NULL;
3900Sstevel@tonic-gate 	slot.endoff = 0;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	/*
3930Sstevel@tonic-gate 	 * For link and rename lock the source entry and check the link count
3940Sstevel@tonic-gate 	 * to see if it has been removed while it was unlocked.  If not, we
3950Sstevel@tonic-gate 	 * increment the link count and force the inode to disk to make sure
3960Sstevel@tonic-gate 	 * that it is there before any directory entry that points to it.
3970Sstevel@tonic-gate 	 */
3980Sstevel@tonic-gate 	if (op == DE_LINK || op == DE_RENAME) {
3990Sstevel@tonic-gate 		rw_enter(&sip->i_contents, RW_WRITER);
4000Sstevel@tonic-gate 		if (sip->i_nlink == 0) {
4010Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
4020Sstevel@tonic-gate 			return (ENOENT);
4030Sstevel@tonic-gate 		}
4040Sstevel@tonic-gate 		if (sip->i_nlink == MAXLINK) {
4050Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
4060Sstevel@tonic-gate 			return (EMLINK);
4070Sstevel@tonic-gate 		}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 		sip->i_nlink++;
4100Sstevel@tonic-gate 		mutex_enter(&sip->i_tlock);
4110Sstevel@tonic-gate 		sip->i_flag |= ICHG;
4120Sstevel@tonic-gate 		mutex_exit(&sip->i_tlock);
4130Sstevel@tonic-gate 		ud_iupdat(sip, 1);
4140Sstevel@tonic-gate 		rw_exit(&sip->i_contents);
4150Sstevel@tonic-gate 	}
4160Sstevel@tonic-gate 	/*
4170Sstevel@tonic-gate 	 * If target directory has not been removed, then we can consider
4180Sstevel@tonic-gate 	 * allowing file to be created.
4190Sstevel@tonic-gate 	 */
4200Sstevel@tonic-gate 	if (tdp->i_nlink == 0) {
4210Sstevel@tonic-gate 		err = ENOENT;
4220Sstevel@tonic-gate 		goto out2;
4230Sstevel@tonic-gate 	}
4240Sstevel@tonic-gate 	/*
4250Sstevel@tonic-gate 	 * Check accessibility of directory.
4260Sstevel@tonic-gate 	 */
4270Sstevel@tonic-gate 	if (tdp->i_type != VDIR) {
4280Sstevel@tonic-gate 		err = ENOTDIR;
4290Sstevel@tonic-gate 		goto out2;
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 	/*
4320Sstevel@tonic-gate 	 * Execute access is required to search the directory.
4330Sstevel@tonic-gate 	 */
43412196SMilan.Cermak@Sun.COM 	if (err = ud_iaccess(tdp, IEXEC, cr, 1)) {
4350Sstevel@tonic-gate 		goto out2;
4360Sstevel@tonic-gate 	}
4370Sstevel@tonic-gate 	/*
4380Sstevel@tonic-gate 	 * If this is a rename of a directory and the parent is
4390Sstevel@tonic-gate 	 * different (".." must be changed), then the source
4400Sstevel@tonic-gate 	 * directory must not be in the directory hierarchy
4410Sstevel@tonic-gate 	 * above the target, as this would orphan everything
4420Sstevel@tonic-gate 	 * below the source directory.  Also the user must have
4430Sstevel@tonic-gate 	 * write permission in the source so as to be able to
4440Sstevel@tonic-gate 	 * change "..".
4450Sstevel@tonic-gate 	 */
4460Sstevel@tonic-gate 	if (op == DE_RENAME) {
4470Sstevel@tonic-gate 		if (sip == tdp) {
4480Sstevel@tonic-gate 			err = EINVAL;
4490Sstevel@tonic-gate 			goto out2;
4500Sstevel@tonic-gate 		}
4510Sstevel@tonic-gate 		rw_enter(&sip->i_contents, RW_READER);
4520Sstevel@tonic-gate 		if ((sip->i_type == VDIR) && (sdp != tdp)) {
4530Sstevel@tonic-gate 			uint32_t blkno;
4540Sstevel@tonic-gate 
45512196SMilan.Cermak@Sun.COM 			if ((err = ud_iaccess(sip, IWRITE, cr, 0))) {
4560Sstevel@tonic-gate 				rw_exit(&sip->i_contents);
4570Sstevel@tonic-gate 				goto out2;
4580Sstevel@tonic-gate 			}
4590Sstevel@tonic-gate 			blkno = sip->i_icb_lbano;
4600Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
4610Sstevel@tonic-gate 			if ((err = ud_dircheckpath(blkno, tdp, cr))) {
4620Sstevel@tonic-gate 				goto out2;
4630Sstevel@tonic-gate 			}
4640Sstevel@tonic-gate 		} else {
4650Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
4660Sstevel@tonic-gate 		}
4670Sstevel@tonic-gate 	}
4680Sstevel@tonic-gate 
4690Sstevel@tonic-gate 	/*
4700Sstevel@tonic-gate 	 * Search for the entry. Return VN_HELD tip if found.
4710Sstevel@tonic-gate 	 */
4720Sstevel@tonic-gate 	buf = kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
4730Sstevel@tonic-gate 	rw_enter(&tdp->i_contents, RW_WRITER);
4740Sstevel@tonic-gate 	if (err = ud_dircheckforname(tdp,
47512196SMilan.Cermak@Sun.COM 	    namep, namlen, &slot, &tip, buf, cr)) {
4760Sstevel@tonic-gate 		goto out;
4770Sstevel@tonic-gate 	}
4780Sstevel@tonic-gate 	if (tip) {
4790Sstevel@tonic-gate 		switch (op) {
4800Sstevel@tonic-gate 			case DE_CREATE :
4810Sstevel@tonic-gate 			case DE_MKDIR :
4820Sstevel@tonic-gate 				if (ipp) {
4830Sstevel@tonic-gate 					*ipp = tip;
4840Sstevel@tonic-gate 					err = EEXIST;
4850Sstevel@tonic-gate 				} else {
4860Sstevel@tonic-gate 					VN_RELE(ITOV(tip));
4870Sstevel@tonic-gate 				}
4880Sstevel@tonic-gate 				break;
4890Sstevel@tonic-gate 			case DE_RENAME :
4900Sstevel@tonic-gate 				err = ud_dirrename(sdp, sip, tdp, tip,
49112196SMilan.Cermak@Sun.COM 				    namep, buf, &slot, cr);
4920Sstevel@tonic-gate 				/*
4930Sstevel@tonic-gate 				 * We used to VN_RELE() here, but this
4940Sstevel@tonic-gate 				 * was moved down so that we could send
4950Sstevel@tonic-gate 				 * a vnevent after the locks were dropped.
4960Sstevel@tonic-gate 				 */
4970Sstevel@tonic-gate 				break;
4980Sstevel@tonic-gate 			case DE_LINK :
4990Sstevel@tonic-gate 				/*
5000Sstevel@tonic-gate 				 * Can't link to an existing file.
5010Sstevel@tonic-gate 				 */
5020Sstevel@tonic-gate 				VN_RELE(ITOV(tip));
5030Sstevel@tonic-gate 				err = EEXIST;
5040Sstevel@tonic-gate 				break;
5050Sstevel@tonic-gate 		}
5060Sstevel@tonic-gate 	} else {
5070Sstevel@tonic-gate 		/*
5080Sstevel@tonic-gate 		 * The entry does not exist. Check write permission in
5090Sstevel@tonic-gate 		 * directory to see if entry can be created.
5100Sstevel@tonic-gate 		 */
51112196SMilan.Cermak@Sun.COM 		if (err = ud_iaccess(tdp, IWRITE, cr, 0)) {
5120Sstevel@tonic-gate 			goto out;
5130Sstevel@tonic-gate 		}
5140Sstevel@tonic-gate 		if ((op == DE_CREATE) || (op == DE_MKDIR)) {
5150Sstevel@tonic-gate 			/*
5160Sstevel@tonic-gate 			 * Make new inode and directory entry as required.
5170Sstevel@tonic-gate 			 */
5180Sstevel@tonic-gate 			if (err = ud_dirmakeinode(tdp, &sip, vap, op, cr))
5190Sstevel@tonic-gate 				goto out;
5200Sstevel@tonic-gate 		}
5210Sstevel@tonic-gate 		if (err = ud_diraddentry(tdp, namep, op,
5220Sstevel@tonic-gate 		    namlen, &slot, sip, sdp, cr)) {
5230Sstevel@tonic-gate 			if ((op == DE_CREATE) || (op == DE_MKDIR)) {
5240Sstevel@tonic-gate 				/*
5250Sstevel@tonic-gate 				 * Unmake the inode we just made.
5260Sstevel@tonic-gate 				 */
5270Sstevel@tonic-gate 				rw_enter(&sip->i_contents, RW_WRITER);
5280Sstevel@tonic-gate 				if (sip->i_type == VDIR) {
5290Sstevel@tonic-gate 					tdp->i_nlink--;
5300Sstevel@tonic-gate 				}
5310Sstevel@tonic-gate 				sip->i_nlink = 0;
5320Sstevel@tonic-gate 				mutex_enter(&sip->i_tlock);
5330Sstevel@tonic-gate 				sip->i_flag |= ICHG;
5340Sstevel@tonic-gate 				mutex_exit(&sip->i_tlock);
5350Sstevel@tonic-gate 				rw_exit(&sip->i_contents);
5360Sstevel@tonic-gate 				VN_RELE(ITOV(sip));
5370Sstevel@tonic-gate 				sip = NULL;
5380Sstevel@tonic-gate 			}
5390Sstevel@tonic-gate 		} else if (ipp) {
5400Sstevel@tonic-gate 			*ipp = sip;
5410Sstevel@tonic-gate 		} else if ((op == DE_CREATE) || (op == DE_MKDIR)) {
5420Sstevel@tonic-gate 			VN_RELE(ITOV(sip));
5430Sstevel@tonic-gate 		}
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate out:
5460Sstevel@tonic-gate 	if (buf != NULL) {
5470Sstevel@tonic-gate 		kmem_free(buf, udf_vfsp->udf_lbsize);
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate 	if (slot.fbp) {
5500Sstevel@tonic-gate 		fbrelse(slot.fbp, S_OTHER);
5510Sstevel@tonic-gate 	}
5520Sstevel@tonic-gate 	rw_exit(&tdp->i_contents);
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	if (op == DE_RENAME) {
5550Sstevel@tonic-gate 		/*
5560Sstevel@tonic-gate 		 * If it's all good, send events after locks are dropped
5570Sstevel@tonic-gate 		 * but before vnodes are released.
5580Sstevel@tonic-gate 		 */
5590Sstevel@tonic-gate 		if (err == 0) {
5600Sstevel@tonic-gate 			if (tip) {
5614863Spraks 				vnevent_rename_dest(ITOV(tip), ITOV(tdp),
5625331Samw 				    namep, ctp);
5630Sstevel@tonic-gate 			}
5644863Spraks 
5654863Spraks 			if (sdp != tdp) {
5665331Samw 				vnevent_rename_dest_dir(ITOV(tdp), ctp);
5674863Spraks 			}
5680Sstevel@tonic-gate 		}
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 		/*
5710Sstevel@tonic-gate 		 * The following VN_RELE() was moved from the
5720Sstevel@tonic-gate 		 * DE_RENAME case above
5730Sstevel@tonic-gate 		 */
5740Sstevel@tonic-gate 		if (tip) {
5750Sstevel@tonic-gate 			VN_RELE(ITOV(tip));
5760Sstevel@tonic-gate 		}
5770Sstevel@tonic-gate 	}
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate out2:
5800Sstevel@tonic-gate 	if (err && ((op == DE_LINK) || (op == DE_RENAME))) {
5810Sstevel@tonic-gate 		/*
5820Sstevel@tonic-gate 		 * Undo bumped link count.
5830Sstevel@tonic-gate 		 */
5840Sstevel@tonic-gate 		rw_enter(&sip->i_contents, RW_WRITER);
5850Sstevel@tonic-gate 		sip->i_nlink--;
5860Sstevel@tonic-gate 		rw_exit(&sip->i_contents);
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 		mutex_enter(&sip->i_tlock);
5890Sstevel@tonic-gate 		sip->i_flag |= ICHG;
5900Sstevel@tonic-gate 		mutex_exit(&sip->i_tlock);
5910Sstevel@tonic-gate 	}
5920Sstevel@tonic-gate 	return (err);
5930Sstevel@tonic-gate }
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate /*
5960Sstevel@tonic-gate  * Locking i_contents in this
5970Sstevel@tonic-gate  * function seems to be really weird
5980Sstevel@tonic-gate  */
5990Sstevel@tonic-gate int
ud_dirremove(struct ud_inode * dp,char * namep,struct ud_inode * oip,struct vnode * cdir,enum dr_op op,struct cred * cr,caller_context_t * ctp)6005331Samw ud_dirremove(
6015331Samw 	struct ud_inode *dp,
6025331Samw 	char *namep,
6035331Samw 	struct ud_inode *oip,
6045331Samw 	struct vnode *cdir,
6055331Samw 	enum dr_op op,
6065331Samw 	struct cred *cr,
6075331Samw 	caller_context_t *ctp)
6080Sstevel@tonic-gate {
6090Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
6100Sstevel@tonic-gate 	int32_t namelen, err = 0;
6110Sstevel@tonic-gate 	struct slot slot;
6120Sstevel@tonic-gate 	struct ud_inode *ip;
6130Sstevel@tonic-gate 	mode_t mode;
6140Sstevel@tonic-gate 	struct file_id *fid;
6150Sstevel@tonic-gate 	uint8_t *buf = NULL;
6160Sstevel@tonic-gate 	uint32_t tbno;
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	ud_printf("ud_dirremove\n");
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	udf_vfsp = dp->i_udf;
6230Sstevel@tonic-gate 	namelen = (int)strlen(namep);
6240Sstevel@tonic-gate 	if (namelen == 0) {
6250Sstevel@tonic-gate 		cmn_err(CE_WARN, "name length == 0 in ud_dirremove");
6260Sstevel@tonic-gate 		return (EINVAL);
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	/*
6300Sstevel@tonic-gate 	 * return err when removing . and ..
6310Sstevel@tonic-gate 	 */
6320Sstevel@tonic-gate 	if (namep[0] == '.') {
6330Sstevel@tonic-gate 		if (namelen == 1) {
6340Sstevel@tonic-gate 			return (EINVAL);
6350Sstevel@tonic-gate 		} else if (namelen == 2 && namep[1] == '.') {
6360Sstevel@tonic-gate 			return (EEXIST);	/* SIGH should be ENOTEMPTY */
6370Sstevel@tonic-gate 		}
6380Sstevel@tonic-gate 	}
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate 	/*
6430Sstevel@tonic-gate 	 * Check accessibility of directory.
6440Sstevel@tonic-gate 	 */
6450Sstevel@tonic-gate 	if (dp->i_type != VDIR) {
6460Sstevel@tonic-gate 		return (ENOTDIR);
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	ip = NULL;
6500Sstevel@tonic-gate 	slot.status = FOUND;	/* don't need to look for empty slot */
6510Sstevel@tonic-gate 	slot.offset = 0;
6520Sstevel@tonic-gate 	slot.size = 0;
6530Sstevel@tonic-gate 	slot.fbp = NULL;
6540Sstevel@tonic-gate 	slot.ep = NULL;
6550Sstevel@tonic-gate 	slot.endoff = 0;
6560Sstevel@tonic-gate 	/*
6570Sstevel@tonic-gate 	 * Execute access is required to search the directory.
6580Sstevel@tonic-gate 	 * Access for write is interpreted as allowing
6590Sstevel@tonic-gate 	 * deletion of files in the directory.
6600Sstevel@tonic-gate 	 */
66112196SMilan.Cermak@Sun.COM 	if (err = ud_iaccess(dp, IEXEC|IWRITE, cr, 1)) {
6620Sstevel@tonic-gate 		return (err);
6630Sstevel@tonic-gate 	}
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	rw_enter(&dp->i_contents, RW_WRITER);
6680Sstevel@tonic-gate 
66912196SMilan.Cermak@Sun.COM 	if (err = ud_dircheckforname(dp, namep, namelen, &slot, &ip,
67012196SMilan.Cermak@Sun.COM 	    buf, cr)) {
6710Sstevel@tonic-gate 		goto out_novfs;
6720Sstevel@tonic-gate 	}
6730Sstevel@tonic-gate 	if (ip == NULL) {
6740Sstevel@tonic-gate 		err = ENOENT;
6750Sstevel@tonic-gate 		goto out_novfs;
6760Sstevel@tonic-gate 	}
6770Sstevel@tonic-gate 	if (oip && oip != ip) {
6780Sstevel@tonic-gate 		err = ENOENT;
6790Sstevel@tonic-gate 		goto out_novfs;
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	if ((mode = ip->i_type) == VDIR) {
6830Sstevel@tonic-gate 		/*
684569Sbatschul 		 * vn_vfswlock() prevents races between mount and rmdir.
6850Sstevel@tonic-gate 		 */
686569Sbatschul 		if (vn_vfswlock(ITOV(ip))) {
6870Sstevel@tonic-gate 			err = EBUSY;
6880Sstevel@tonic-gate 			goto out_novfs;
6890Sstevel@tonic-gate 		}
6900Sstevel@tonic-gate 		if (vn_mountedvfs(ITOV(ip)) != NULL && op != DR_RENAME) {
6910Sstevel@tonic-gate 			err = EBUSY;
6920Sstevel@tonic-gate 			goto out;
6930Sstevel@tonic-gate 		}
6940Sstevel@tonic-gate 		/*
6950Sstevel@tonic-gate 		 * If we are removing a directory, get a lock on it.
6960Sstevel@tonic-gate 		 * If the directory is empty, it will stay empty until
6970Sstevel@tonic-gate 		 * we can remove it.
6980Sstevel@tonic-gate 		 */
6990Sstevel@tonic-gate 		rw_enter(&ip->i_rwlock, RW_READER);
7000Sstevel@tonic-gate 	}
7010Sstevel@tonic-gate 	/* We must be holding i_contents */
7020Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_READER);
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate 	if (err = ud_sticky_remove_access(dp, ip, cr)) {
7050Sstevel@tonic-gate 		rw_exit(&ip->i_contents);
7060Sstevel@tonic-gate 		if (mode == VDIR) {
7070Sstevel@tonic-gate 			rw_exit(&ip->i_rwlock);
7080Sstevel@tonic-gate 		}
7090Sstevel@tonic-gate 		goto out;
7100Sstevel@tonic-gate 	}
7110Sstevel@tonic-gate 	if (op == DR_RMDIR) {
7120Sstevel@tonic-gate 		/*
7130Sstevel@tonic-gate 		 * For rmdir(2), some special checks are required.
7140Sstevel@tonic-gate 		 * (a) Don't remove any alias of the parent (e.g. ".").
7150Sstevel@tonic-gate 		 * (b) Don't remove the current directory.
7160Sstevel@tonic-gate 		 * (c) Make sure the entry is (still) a directory.
7170Sstevel@tonic-gate 		 * (d) Make sure the directory is empty.
7180Sstevel@tonic-gate 		 */
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 		if (dp == ip || ITOV(ip) == cdir) {
7210Sstevel@tonic-gate 			err = EINVAL;
7220Sstevel@tonic-gate 		} else if (ip->i_type != VDIR) {
7230Sstevel@tonic-gate 			err = ENOTDIR;
7240Sstevel@tonic-gate 		} else if ((ip->i_nlink != 1) ||
72512196SMilan.Cermak@Sun.COM 		    (!ud_dirempty(ip, dp->i_uniqid, cr))) {
7260Sstevel@tonic-gate 			/*
7270Sstevel@tonic-gate 			 * Directories do not have an
7280Sstevel@tonic-gate 			 * entry for "." so only one link
7290Sstevel@tonic-gate 			 * will be there
7300Sstevel@tonic-gate 			 */
7310Sstevel@tonic-gate 			err = EEXIST;	/* SIGH should be ENOTEMPTY */
7320Sstevel@tonic-gate 		}
7330Sstevel@tonic-gate 		if (err) {
7340Sstevel@tonic-gate 			rw_exit(&ip->i_contents);
7350Sstevel@tonic-gate 			if (mode == VDIR) {
7360Sstevel@tonic-gate 				rw_exit(&ip->i_rwlock);
7370Sstevel@tonic-gate 			}
7380Sstevel@tonic-gate 			goto out;
7390Sstevel@tonic-gate 		}
7400Sstevel@tonic-gate 	} else if (op == DR_REMOVE)  {
7410Sstevel@tonic-gate 		/*
7420Sstevel@tonic-gate 		 * unlink(2) requires a different check: allow only
7430Sstevel@tonic-gate 		 * privileged processes to unlink a directory.
7440Sstevel@tonic-gate 		 */
7450Sstevel@tonic-gate 		struct vnode *vp = ITOV(ip);
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 		if (vp->v_type == VDIR &&
7480Sstevel@tonic-gate 		    secpolicy_fs_linkdir(cr, vp->v_vfsp)) {
7490Sstevel@tonic-gate 			err = EPERM;
7500Sstevel@tonic-gate 			rw_exit(&ip->i_contents);
7510Sstevel@tonic-gate 			rw_exit(&ip->i_rwlock);
7520Sstevel@tonic-gate 			goto out;
7530Sstevel@tonic-gate 		}
7540Sstevel@tonic-gate 	}
7550Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
7560Sstevel@tonic-gate 
7570Sstevel@tonic-gate 	/*
7580Sstevel@tonic-gate 	 * Remove the cache'd entry, if any.
7590Sstevel@tonic-gate 	 */
7600Sstevel@tonic-gate 	dnlc_remove(ITOV(dp), namep);
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 	/*
7630Sstevel@tonic-gate 	 * We can collapse all the directory
7640Sstevel@tonic-gate 	 * entries that are deleted into one big entry
7650Sstevel@tonic-gate 	 * but the better way is to
7660Sstevel@tonic-gate 	 * defer it till next directory entry
7670Sstevel@tonic-gate 	 * creation. where we can do this
7680Sstevel@tonic-gate 	 * in a more efficient way
7690Sstevel@tonic-gate 	 */
7700Sstevel@tonic-gate 	fid = slot.ep;
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate 	/*
7730Sstevel@tonic-gate 	 * If this is the last entry
7740Sstevel@tonic-gate 	 * just truncate the file instead
7750Sstevel@tonic-gate 	 * of marking it deleted
7760Sstevel@tonic-gate 	 */
7770Sstevel@tonic-gate 	if ((slot.offset + FID_LEN(fid)) == dp->i_size) {
7780Sstevel@tonic-gate 		fbrelse(slot.fbp, S_OTHER);
7790Sstevel@tonic-gate 		if ((err = ud_itrunc(dp, slot.offset, 0, cr)) != 0) {
7800Sstevel@tonic-gate 			goto out;
7810Sstevel@tonic-gate 		}
7820Sstevel@tonic-gate 	} else {
7830Sstevel@tonic-gate 		fid->fid_flags |= FID_DELETED;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 		if ((err = ud_ip_off2bno(dp, slot.offset, &tbno)) != 0) {
7860Sstevel@tonic-gate 			goto out;
7870Sstevel@tonic-gate 		}
7880Sstevel@tonic-gate 
7890Sstevel@tonic-gate 		ud_make_tag(dp->i_udf, &fid->fid_tag,
79012196SMilan.Cermak@Sun.COM 		    UD_FILE_ID_DESC, tbno, FID_LEN(fid));
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 		err = ud_write_fid(dp, &slot, buf);
7930Sstevel@tonic-gate 	}
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	slot.fbp = NULL;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	/*
7980Sstevel@tonic-gate 	 * If we were removing a directory, it is 'gone' now so we can
7990Sstevel@tonic-gate 	 * unlock it.
8000Sstevel@tonic-gate 	 */
8010Sstevel@tonic-gate 	if (mode == VDIR) {
8020Sstevel@tonic-gate 		rw_exit(&ip->i_rwlock);
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	mutex_enter(&dp->i_tlock);
8060Sstevel@tonic-gate 	dp->i_flag |= IUPD|ICHG;
8070Sstevel@tonic-gate 	mutex_exit(&dp->i_tlock);
8080Sstevel@tonic-gate 	mutex_enter(&ip->i_tlock);
8090Sstevel@tonic-gate 	ip->i_flag |= ICHG;
8100Sstevel@tonic-gate 	mutex_exit(&ip->i_tlock);
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	if (err != 0) {
8130Sstevel@tonic-gate 		goto out;
8140Sstevel@tonic-gate 	}
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_WRITER);
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	/*
8190Sstevel@tonic-gate 	 * Now dispose of the inode.
8200Sstevel@tonic-gate 	 */
8210Sstevel@tonic-gate 	if (ip->i_nlink > 0) {
8220Sstevel@tonic-gate 		if ((op == DR_RMDIR) && (ip->i_type == VDIR)) {
8230Sstevel@tonic-gate 			/*
8240Sstevel@tonic-gate 			 * Decrement by 1 because there is no "."
8250Sstevel@tonic-gate 			 * Clear the inode, but there may be other hard
8260Sstevel@tonic-gate 			 * links so don't free the inode.
8270Sstevel@tonic-gate 			 * Decrement the dp linkcount because we're
8280Sstevel@tonic-gate 			 * trashing the ".." entry.
8290Sstevel@tonic-gate 			 */
8300Sstevel@tonic-gate 			ip->i_nlink --;
8310Sstevel@tonic-gate 			dp->i_nlink--;
8320Sstevel@tonic-gate 			dnlc_remove(ITOV(ip), ".");
8330Sstevel@tonic-gate 			dnlc_remove(ITOV(ip), "..");
8340Sstevel@tonic-gate /*
8350Sstevel@tonic-gate  *			(void) ud_itrunc(ip, 0, 0, cr);
8360Sstevel@tonic-gate  */
8370Sstevel@tonic-gate 		} else {
8380Sstevel@tonic-gate 			ip->i_nlink--;
8390Sstevel@tonic-gate 		}
8400Sstevel@tonic-gate 	}
8410Sstevel@tonic-gate 	ITIMES_NOLOCK(dp);
8420Sstevel@tonic-gate 	ITIMES_NOLOCK(ip);
8430Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
8440Sstevel@tonic-gate out:
8450Sstevel@tonic-gate 	if (mode == VDIR) {
8460Sstevel@tonic-gate 		vn_vfsunlock(ITOV(ip));
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate out_novfs:
8490Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&dp->i_contents));
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	if (slot.fbp != NULL) {
8520Sstevel@tonic-gate 		fbrelse(slot.fbp, S_OTHER);
8530Sstevel@tonic-gate 	}
8540Sstevel@tonic-gate 	rw_exit(&dp->i_contents);
8550Sstevel@tonic-gate 
8560Sstevel@tonic-gate 	if (ip) {
8570Sstevel@tonic-gate 		/*
8580Sstevel@tonic-gate 		 * If no errors, send any events after locks are dropped,
8590Sstevel@tonic-gate 		 * but before the VN_RELE().
8600Sstevel@tonic-gate 		 */
8610Sstevel@tonic-gate 		if (err == 0) {
8620Sstevel@tonic-gate 			if (op == DR_REMOVE) {
8635331Samw 				vnevent_remove(ITOV(ip), ITOV(dp), namep, ctp);
8640Sstevel@tonic-gate 			} else if (op == DR_RMDIR) {
8655331Samw 				vnevent_rmdir(ITOV(ip), ITOV(dp), namep, ctp);
8660Sstevel@tonic-gate 			}
8670Sstevel@tonic-gate 		}
8680Sstevel@tonic-gate 		VN_RELE(ITOV(ip));
8690Sstevel@tonic-gate 	}
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	kmem_free(buf, udf_vfsp->udf_lbsize);
8720Sstevel@tonic-gate 	return (err);
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate int
ud_dircheckforname(struct ud_inode * tdp,char * namep,int32_t namelen,struct slot * slotp,struct ud_inode ** ipp,uint8_t * buf,struct cred * cr)8760Sstevel@tonic-gate ud_dircheckforname(struct ud_inode *tdp,
8770Sstevel@tonic-gate 	char *namep, int32_t namelen, struct slot *slotp,
8780Sstevel@tonic-gate 	struct ud_inode **ipp, uint8_t *buf, struct cred *cr)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
8810Sstevel@tonic-gate 	uint32_t dirsize, offset;
8820Sstevel@tonic-gate 	struct fbuf *fbp;
8830Sstevel@tonic-gate 	struct file_id *fid;
8840Sstevel@tonic-gate 	int32_t sz, error = 0, sz_req, matched = 0;
8850Sstevel@tonic-gate 	uint8_t *nm;
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 	uint8_t *dname;
8880Sstevel@tonic-gate 	int32_t id_len;
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 	ud_printf("ud_dircheckforname\n");
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
8930Sstevel@tonic-gate 	fbp = NULL;
8940Sstevel@tonic-gate 
8950Sstevel@tonic-gate 	dname = (uint8_t *)kmem_zalloc(1024, KM_SLEEP);
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	udf_vfsp = tdp->i_udf;
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 	offset = 0;
9000Sstevel@tonic-gate 	dirsize = tdp->i_size;
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 	if (slotp->status != FOUND) {
9030Sstevel@tonic-gate 		int32_t temp;
9040Sstevel@tonic-gate 
9050Sstevel@tonic-gate 		temp = 1024; /* set to size of dname allocated above */
9060Sstevel@tonic-gate 		if ((error = ud_compress(namelen, &temp,
90712196SMilan.Cermak@Sun.COM 		    (uint8_t *)namep, dname)) != 0) {
9080Sstevel@tonic-gate 			goto end;
9090Sstevel@tonic-gate 		}
9100Sstevel@tonic-gate 		sz_req = F_LEN + temp;
9110Sstevel@tonic-gate 		sz_req  = (sz_req + 3) & ~3;
9120Sstevel@tonic-gate 	}
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	while (offset < dirsize) {
9150Sstevel@tonic-gate 		if ((error = ud_get_next_fid(tdp, &fbp,
91612196SMilan.Cermak@Sun.COM 		    offset, &fid, &nm, buf)) != 0) {
9170Sstevel@tonic-gate 			break;
9180Sstevel@tonic-gate 		}
9190Sstevel@tonic-gate 		if ((error = ud_uncompress(fid->fid_idlen,
92012196SMilan.Cermak@Sun.COM 		    &id_len, nm, dname)) != 0) {
9210Sstevel@tonic-gate 			break;
9220Sstevel@tonic-gate 		}
9230Sstevel@tonic-gate 		if ((fid->fid_flags & FID_DELETED) == 0) {
9240Sstevel@tonic-gate 			/* Check for name match */
9250Sstevel@tonic-gate 			if (((namelen == id_len) &&
92612196SMilan.Cermak@Sun.COM 			    (strncmp(namep, (caddr_t)dname, namelen) == 0)) ||
92712196SMilan.Cermak@Sun.COM 			    ((fid->fid_flags & FID_PARENT) &&
92812196SMilan.Cermak@Sun.COM 			    (namep[0] == '.' &&
92912196SMilan.Cermak@Sun.COM 			    (namelen == 1 ||
93012196SMilan.Cermak@Sun.COM 			    (namelen == 2 && namep[1] == '.'))))) {
9310Sstevel@tonic-gate 
9320Sstevel@tonic-gate 				tdp->i_diroff = offset;
9330Sstevel@tonic-gate 				if ((fid->fid_flags & FID_PARENT) &&
93412196SMilan.Cermak@Sun.COM 				    (namelen == 1) && (namep[0] == '.')) {
9350Sstevel@tonic-gate 					struct vnode *vp = ITOV(tdp);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 					*ipp = tdp;
9380Sstevel@tonic-gate 					VN_HOLD(vp);
9390Sstevel@tonic-gate 				} else {
9400Sstevel@tonic-gate 					uint16_t prn;
9410Sstevel@tonic-gate 					uint32_t loc;
9420Sstevel@tonic-gate 
9430Sstevel@tonic-gate 					prn = SWAP_16(fid->fid_icb.lad_ext_prn);
9440Sstevel@tonic-gate 					loc = SWAP_32(fid->fid_icb.lad_ext_loc);
9450Sstevel@tonic-gate 					if ((error = ud_iget(tdp->i_vfs, prn,
94612196SMilan.Cermak@Sun.COM 					    loc, ipp, NULL, cr)) != 0) {
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 						fbrelse(fbp, S_OTHER);
9490Sstevel@tonic-gate 						goto end;
9500Sstevel@tonic-gate 					}
9510Sstevel@tonic-gate 				}
9520Sstevel@tonic-gate 				slotp->status = EXIST;
9530Sstevel@tonic-gate 				slotp->offset = offset;
9540Sstevel@tonic-gate 				slotp->size = FID_LEN(fid);
9550Sstevel@tonic-gate 				slotp->fbp = fbp;
9560Sstevel@tonic-gate 				slotp->ep = fid;
9570Sstevel@tonic-gate 				slotp->endoff = 0;
9580Sstevel@tonic-gate 				goto end;
9590Sstevel@tonic-gate 			}
9600Sstevel@tonic-gate 		} else {
9610Sstevel@tonic-gate 			/*
9620Sstevel@tonic-gate 			 * see if we need to find an
9630Sstevel@tonic-gate 			 * empty slot and the current slot
9640Sstevel@tonic-gate 			 * matches
9650Sstevel@tonic-gate 			 */
96612196SMilan.Cermak@Sun.COM 			if ((slotp->status != FOUND) || (matched == 0)) {
9670Sstevel@tonic-gate 				sz = FID_LEN(fid);
9680Sstevel@tonic-gate 				if (sz == sz_req) {
9690Sstevel@tonic-gate 					slotp->status = FOUND;
9700Sstevel@tonic-gate 					slotp->offset = offset;
9710Sstevel@tonic-gate 					slotp->size = sz;
9720Sstevel@tonic-gate 				}
9730Sstevel@tonic-gate 				if (matched == 0) {
9740Sstevel@tonic-gate 					if ((namelen == id_len) &&
97512196SMilan.Cermak@Sun.COM 					    (strncmp(namep, (caddr_t)dname,
97612196SMilan.Cermak@Sun.COM 					    namelen) == 0)) {
9770Sstevel@tonic-gate 						matched = 1;
9780Sstevel@tonic-gate 						slotp->status = FOUND;
9790Sstevel@tonic-gate 						slotp->offset = offset;
9800Sstevel@tonic-gate 						slotp->size = sz;
9810Sstevel@tonic-gate 					}
9820Sstevel@tonic-gate 				}
9830Sstevel@tonic-gate 			}
9840Sstevel@tonic-gate 		}
9850Sstevel@tonic-gate 		offset += FID_LEN(fid);
9860Sstevel@tonic-gate 	}
9870Sstevel@tonic-gate 	if (fbp) {
9880Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
9890Sstevel@tonic-gate 	}
9900Sstevel@tonic-gate 	if (slotp->status == NONE) {
9910Sstevel@tonic-gate 		/*
9920Sstevel@tonic-gate 		 * We didn't find a slot; the new directory entry should be put
9930Sstevel@tonic-gate 		 * at the end of the directory.  Return an indication of where
9940Sstevel@tonic-gate 		 * this is, and set "endoff" to zero; since we're going to have
9950Sstevel@tonic-gate 		 * to extend the directory, we're certainly not going to
9960Sstevel@tonic-gate 		 * trucate it.
9970Sstevel@tonic-gate 		 */
9980Sstevel@tonic-gate 		slotp->offset = dirsize;
9990Sstevel@tonic-gate 		if (tdp->i_desc_type == ICB_FLAG_ONE_AD) {
10000Sstevel@tonic-gate 			slotp->size = tdp->i_max_emb - tdp->i_size;
10010Sstevel@tonic-gate 		} else {
10020Sstevel@tonic-gate 			slotp->size = udf_vfsp->udf_lbsize -
100312196SMilan.Cermak@Sun.COM 			    slotp->offset & udf_vfsp->udf_lbmask;
10040Sstevel@tonic-gate 		}
10050Sstevel@tonic-gate 		slotp->endoff = 0;
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 
10080Sstevel@tonic-gate 	*ipp = NULL;
10090Sstevel@tonic-gate end:
10100Sstevel@tonic-gate 	kmem_free((caddr_t)dname, 1024);
10110Sstevel@tonic-gate 	return (error);
10120Sstevel@tonic-gate }
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate /*
10150Sstevel@tonic-gate  * Return 1 if the dir has all files
10160Sstevel@tonic-gate  * deleted except the parent
10170Sstevel@tonic-gate  * else return 0
10180Sstevel@tonic-gate  */
10190Sstevel@tonic-gate /* ARGSUSED */
10200Sstevel@tonic-gate int
ud_dirempty(struct ud_inode * ip,uint64_t ino,struct cred * cr)10210Sstevel@tonic-gate ud_dirempty(struct ud_inode *ip, uint64_t ino, struct cred *cr)
10220Sstevel@tonic-gate {
10230Sstevel@tonic-gate 	offset_t off;
10240Sstevel@tonic-gate 	int32_t empty = 1, error, count, entry_len, rcount;
10250Sstevel@tonic-gate 	struct file_id *fid;
10260Sstevel@tonic-gate 	caddr_t addr;
10270Sstevel@tonic-gate 	uint32_t tbno;
10280Sstevel@tonic-gate 	int32_t	desc_len;
10290Sstevel@tonic-gate 
10300Sstevel@tonic-gate 	ud_printf("ud_dirempty\n");
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	ASSERT(RW_LOCK_HELD(&ip->i_contents));
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	if (ip->i_size == 0) {
10350Sstevel@tonic-gate 		return (empty);
10360Sstevel@tonic-gate 	}
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	desc_len = 1024;
10390Sstevel@tonic-gate 	addr = kmem_zalloc(desc_len, KM_SLEEP);
10400Sstevel@tonic-gate 	fid = (struct file_id *)addr;
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	for (off = 0; off < ip->i_size; off += entry_len) {
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 		/*
10450Sstevel@tonic-gate 		 * First read fid
10460Sstevel@tonic-gate 		 * and verify checksum
10470Sstevel@tonic-gate 		 */
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 		rcount = sizeof (struct file_id);
105012196SMilan.Cermak@Sun.COM 		error = ud_rdwri(UIO_READ, FREAD, ip, addr, rcount, off,
105112196SMilan.Cermak@Sun.COM 		    UIO_SYSSPACE, &count, cr);
10520Sstevel@tonic-gate 		if ((error != 0) || (count != 0)) {
10530Sstevel@tonic-gate 			empty = 0;
10540Sstevel@tonic-gate 			break;
10550Sstevel@tonic-gate 		}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 		if ((error = ud_ip_off2bno(ip, off, &tbno)) != 0) {
10580Sstevel@tonic-gate 			empty = 0;
10590Sstevel@tonic-gate 			break;
10600Sstevel@tonic-gate 		}
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 		/*
10630Sstevel@tonic-gate 		 * We verify the tag id and also the FID_LEN.
10640Sstevel@tonic-gate 		 * FID_LEN should be <= desc_len.
10650Sstevel@tonic-gate 		 */
10660Sstevel@tonic-gate 		if (ud_verify_tag_and_desc(&fid->fid_tag,
10670Sstevel@tonic-gate 		    UD_FILE_ID_DESC,
10680Sstevel@tonic-gate 		    tbno, 0, desc_len) != 0) {
10690Sstevel@tonic-gate 		/* Corrupted directory */
10700Sstevel@tonic-gate 			empty = 0;
10710Sstevel@tonic-gate 			break;
10720Sstevel@tonic-gate 		}
10730Sstevel@tonic-gate 
10740Sstevel@tonic-gate 		/*
10750Sstevel@tonic-gate 		 * Read the fid + iulen + len
10760Sstevel@tonic-gate 		 * Now verify both checksum andCRC
10770Sstevel@tonic-gate 		 */
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 		rcount = FID_LEN(fid);
108012196SMilan.Cermak@Sun.COM 		error = ud_rdwri(UIO_READ, FREAD, ip, addr, rcount, off,
108112196SMilan.Cermak@Sun.COM 		    UIO_SYSSPACE, &count, cr);
10820Sstevel@tonic-gate 		if ((error != 0) || (count != 0)) {
10830Sstevel@tonic-gate 			empty = 0;
10840Sstevel@tonic-gate 			break;
10850Sstevel@tonic-gate 		}
10860Sstevel@tonic-gate 		/*
10870Sstevel@tonic-gate 		 * Now that the entire decsriptor is read we verify the
10880Sstevel@tonic-gate 		 * crc.
10890Sstevel@tonic-gate 		 */
10900Sstevel@tonic-gate 		if (ud_verify_tag_and_desc(&fid->fid_tag,
10910Sstevel@tonic-gate 		    UD_FILE_ID_DESC,
10920Sstevel@tonic-gate 		    tbno,
10930Sstevel@tonic-gate 		    1, rcount) != 0) {
10940Sstevel@tonic-gate 			/* Corrupted directory */
10950Sstevel@tonic-gate 			empty = 0;
10960Sstevel@tonic-gate 			break;
10970Sstevel@tonic-gate 		}
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 		/*
11000Sstevel@tonic-gate 		 * Is the file deleted
11010Sstevel@tonic-gate 		 */
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 		if ((fid->fid_flags & FID_DELETED) == 0) {
11040Sstevel@tonic-gate 			if ((fid->fid_flags & FID_PARENT) == 0) {
11050Sstevel@tonic-gate 				empty = 0;
11060Sstevel@tonic-gate 				break;
11070Sstevel@tonic-gate 			}
11080Sstevel@tonic-gate 		}
11090Sstevel@tonic-gate 		entry_len = FID_LEN(fid);
11100Sstevel@tonic-gate 	}
11110Sstevel@tonic-gate 
11120Sstevel@tonic-gate 	kmem_free(addr, 1024);
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	return (empty);
11150Sstevel@tonic-gate }
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate int
ud_dircheckpath(int32_t blkno,struct ud_inode * target,struct cred * cr)11190Sstevel@tonic-gate ud_dircheckpath(int32_t blkno,
11200Sstevel@tonic-gate 	struct ud_inode *target, struct cred *cr)
11210Sstevel@tonic-gate {
11220Sstevel@tonic-gate 	int32_t err = 0;
11230Sstevel@tonic-gate 	struct vfs *vfsp;
11240Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
11250Sstevel@tonic-gate 	struct fbuf *fbp;
11260Sstevel@tonic-gate 	struct file_id *fid;
11270Sstevel@tonic-gate 	struct ud_inode *ip, *tip;
11280Sstevel@tonic-gate 	uint16_t prn;
11290Sstevel@tonic-gate 	uint32_t lbno, dummy, tbno;
11300Sstevel@tonic-gate 	daddr_t parent_icb_loc;
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	ud_printf("ud_dircheckpath\n");
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	udf_vfsp = target->i_udf;
11350Sstevel@tonic-gate 	ip = target;
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 	ASSERT(udf_vfsp != NULL);
11380Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&target->i_udf->udf_rename_lck));
11390Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&ip->i_rwlock));
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	if (ip->i_icb_lbano == blkno) {
11420Sstevel@tonic-gate 		err = EINVAL;
11430Sstevel@tonic-gate 		goto out;
11440Sstevel@tonic-gate 	}
11450Sstevel@tonic-gate 	if (ip->i_icb_lbano == udf_vfsp->udf_root_blkno) {
11460Sstevel@tonic-gate 		goto out;
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	/*
11500Sstevel@tonic-gate 	 * Search back through the directory tree, using the PARENT entries
11510Sstevel@tonic-gate 	 * Fail any attempt to move a directory into an ancestor directory.
11520Sstevel@tonic-gate 	 */
11530Sstevel@tonic-gate 	for (;;) {
11540Sstevel@tonic-gate 		if ((err = fbread(ITOV(ip), 0,
115512196SMilan.Cermak@Sun.COM 		    udf_vfsp->udf_lbsize, S_READ, &fbp)) != 0) {
11560Sstevel@tonic-gate 			break;
11570Sstevel@tonic-gate 		}
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 		if ((err = ud_ip_off2bno(ip, 0, &tbno)) != 0) {
11600Sstevel@tonic-gate 			break;
11610Sstevel@tonic-gate 		}
11620Sstevel@tonic-gate 		fid = (struct file_id *)fbp->fb_addr;
11630Sstevel@tonic-gate 		/* IS this a valid file_identifier */
11640Sstevel@tonic-gate 		if (ud_verify_tag_and_desc(&fid->fid_tag,
11650Sstevel@tonic-gate 		    UD_FILE_ID_DESC,
11660Sstevel@tonic-gate 		    tbno,
11670Sstevel@tonic-gate 		    1, udf_vfsp->udf_lbsize) != 0) {
11680Sstevel@tonic-gate 			break;
11690Sstevel@tonic-gate 		}
11700Sstevel@tonic-gate 		if ((fid->fid_flags & FID_DELETED) != 0) {
11710Sstevel@tonic-gate 			break;
11720Sstevel@tonic-gate 		}
11730Sstevel@tonic-gate 		if ((fid->fid_flags & FID_PARENT) == 0) {
11740Sstevel@tonic-gate 			/*
11750Sstevel@tonic-gate 			 * This cannot happen unless
11760Sstevel@tonic-gate 			 * something is grossly wrong
11770Sstevel@tonic-gate 			 * First entry has to be parent
11780Sstevel@tonic-gate 			 */
11790Sstevel@tonic-gate 			break;
11800Sstevel@tonic-gate 		}
11810Sstevel@tonic-gate 		prn = SWAP_16(fid->fid_icb.lad_ext_prn);
11820Sstevel@tonic-gate 		lbno = SWAP_32(fid->fid_icb.lad_ext_loc);
118312196SMilan.Cermak@Sun.COM 		parent_icb_loc =
118412196SMilan.Cermak@Sun.COM 		    ud_xlate_to_daddr(udf_vfsp, prn, lbno, 1, &dummy);
11850Sstevel@tonic-gate 		ASSERT(dummy == 1);
11860Sstevel@tonic-gate 		if (parent_icb_loc == blkno) {
11870Sstevel@tonic-gate 			err = EINVAL;
11880Sstevel@tonic-gate 			break;
11890Sstevel@tonic-gate 		}
11900Sstevel@tonic-gate 		vfsp = ip->i_vfs;
11910Sstevel@tonic-gate 		udf_vfsp = ip->i_udf;
11920Sstevel@tonic-gate 		if (parent_icb_loc == udf_vfsp->udf_root_blkno) {
11930Sstevel@tonic-gate 			break;
11940Sstevel@tonic-gate 		}
11950Sstevel@tonic-gate 		if (fbp != NULL) {
11960Sstevel@tonic-gate 			fbrelse(fbp, S_OTHER);
11970Sstevel@tonic-gate 			fbp = NULL;
11980Sstevel@tonic-gate 		}
11990Sstevel@tonic-gate 		if (ip != target) {
12000Sstevel@tonic-gate 			rw_exit(&ip->i_rwlock);
12010Sstevel@tonic-gate 			VN_RELE(ITOV(ip));
12020Sstevel@tonic-gate 		}
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate 		/*
12050Sstevel@tonic-gate 		 * Race to get the inode.
12060Sstevel@tonic-gate 		 */
12070Sstevel@tonic-gate 		if (err = ud_iget(vfsp, prn, lbno, &tip, NULL, cr)) {
12080Sstevel@tonic-gate 			ip = NULL;
12090Sstevel@tonic-gate 			break;
12100Sstevel@tonic-gate 		}
12110Sstevel@tonic-gate 		ip = tip;
12120Sstevel@tonic-gate 		rw_enter(&ip->i_rwlock, RW_READER);
12130Sstevel@tonic-gate 	}
12140Sstevel@tonic-gate 	if (fbp) {
12150Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
12160Sstevel@tonic-gate 	}
12170Sstevel@tonic-gate out:
12180Sstevel@tonic-gate 	if (ip) {
12190Sstevel@tonic-gate 		if (ip != target) {
12200Sstevel@tonic-gate 			rw_exit(&ip->i_rwlock);
12210Sstevel@tonic-gate 			VN_RELE(ITOV(ip));
12220Sstevel@tonic-gate 		}
12230Sstevel@tonic-gate 	}
12240Sstevel@tonic-gate 	return (err);
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate int
ud_dirmakeinode(struct ud_inode * tdp,struct ud_inode ** ipp,struct vattr * vap,enum de_op op,struct cred * cr)12280Sstevel@tonic-gate ud_dirmakeinode(struct ud_inode *tdp, struct ud_inode **ipp,
12290Sstevel@tonic-gate 	struct vattr *vap, enum de_op op, struct cred *cr)
12300Sstevel@tonic-gate {
12310Sstevel@tonic-gate 	struct ud_inode *ip;
12320Sstevel@tonic-gate 	int32_t error;
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	ASSERT(vap != NULL);
12350Sstevel@tonic-gate 	ASSERT(op == DE_CREATE || op == DE_MKDIR);
12360Sstevel@tonic-gate 	ASSERT((vap->va_mask & (AT_TYPE|AT_MODE)) == (AT_TYPE|AT_MODE));
12370Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 	/*
12400Sstevel@tonic-gate 	 * Allocate a new inode.
12410Sstevel@tonic-gate 	 */
12420Sstevel@tonic-gate 	if ((error = ud_ialloc(tdp, &ip, vap, cr)) != 0) {
12430Sstevel@tonic-gate 		return (error);
12440Sstevel@tonic-gate 	}
12450Sstevel@tonic-gate 
12460Sstevel@tonic-gate 	ASSERT(ip != NULL);
12470Sstevel@tonic-gate 
12480Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_WRITER);
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	if (op == DE_MKDIR) {
12510Sstevel@tonic-gate 		error = ud_dirmakedirect(ip, tdp, cr);
12520Sstevel@tonic-gate 	}
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 	ip->i_flag |= IACC|IUPD|ICHG;
12550Sstevel@tonic-gate 	/*
12560Sstevel@tonic-gate 	 * Clear IACC and/or IUPD if the caller specified the atime and/or
12570Sstevel@tonic-gate 	 * mtime fields.  They were set from the passed in attributes in
12580Sstevel@tonic-gate 	 * ud_ialloc().
12590Sstevel@tonic-gate 	 */
12600Sstevel@tonic-gate 	if (vap->va_mask & AT_ATIME)
12610Sstevel@tonic-gate 		ip->i_flag &= ~IACC;
12620Sstevel@tonic-gate 	if (vap->va_mask & AT_MTIME)
12630Sstevel@tonic-gate 		ip->i_flag &= ~IUPD;
12640Sstevel@tonic-gate 	/*
12650Sstevel@tonic-gate 	 * push inode before it's name appears in a directory
12660Sstevel@tonic-gate 	 */
12670Sstevel@tonic-gate 	ud_iupdat(ip, 1);
12680Sstevel@tonic-gate 	*ipp = ip;
12690Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
12700Sstevel@tonic-gate 	return (error);
12710Sstevel@tonic-gate }
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate /*
12740Sstevel@tonic-gate  * Enter the file sip in the directory tdp with name namep.
12750Sstevel@tonic-gate  */
12760Sstevel@tonic-gate int
ud_diraddentry(struct ud_inode * tdp,char * namep,enum de_op op,int32_t namelen,struct slot * slotp,struct ud_inode * sip,struct ud_inode * sdp,struct cred * cr)12770Sstevel@tonic-gate ud_diraddentry(struct ud_inode *tdp, char *namep,
12780Sstevel@tonic-gate 	enum de_op op, int32_t namelen, struct slot *slotp,
12790Sstevel@tonic-gate 	struct ud_inode *sip, struct ud_inode *sdp, struct cred *cr)
12800Sstevel@tonic-gate {
12810Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
12820Sstevel@tonic-gate 	int32_t error, temp;
12830Sstevel@tonic-gate 	struct file_id *fid;
12840Sstevel@tonic-gate 	uint8_t *buf = NULL;
12850Sstevel@tonic-gate 
12860Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	ud_printf("ud_diraddentry\n");
12890Sstevel@tonic-gate 
12900Sstevel@tonic-gate 	udf_vfsp = sip->i_udf;
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	/*
12930Sstevel@tonic-gate 	 * Check inode to be linked to see if it is in the
12940Sstevel@tonic-gate 	 * same filesystem.
12950Sstevel@tonic-gate 	 */
12960Sstevel@tonic-gate 	if (ITOV(tdp)->v_vfsp != ITOV(sip)->v_vfsp) {
12970Sstevel@tonic-gate 		error = EXDEV;
12980Sstevel@tonic-gate 		goto bad;
12990Sstevel@tonic-gate 	}
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate 	if ((op == DE_RENAME) && (sip->i_type == VDIR)) {
13020Sstevel@tonic-gate 		if ((error = ud_dirfixdotdot(sip, sdp, tdp)) != 0) {
13030Sstevel@tonic-gate 			goto bad;
13040Sstevel@tonic-gate 		}
13050Sstevel@tonic-gate 	}
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	buf = (uint8_t *)kmem_zalloc(udf_vfsp->udf_lbsize, KM_SLEEP);
13080Sstevel@tonic-gate 
13090Sstevel@tonic-gate 	/*
13100Sstevel@tonic-gate 	 * Fill in entry data.
13110Sstevel@tonic-gate 	 */
13120Sstevel@tonic-gate 	fid = (struct file_id *)buf;
13130Sstevel@tonic-gate 	fid->fid_ver = SWAP_16(1);
13140Sstevel@tonic-gate 	if (sip->i_type == VDIR) {
13150Sstevel@tonic-gate 		fid->fid_flags = FID_DIR;
13160Sstevel@tonic-gate 	} else {
13170Sstevel@tonic-gate 		fid->fid_flags = 0;
13180Sstevel@tonic-gate 	}
13190Sstevel@tonic-gate 	fid->fid_iulen = 0;
13200Sstevel@tonic-gate 
13210Sstevel@tonic-gate 	fid->fid_icb.lad_ext_len = SWAP_32(sip->i_udf->udf_lbsize);
13220Sstevel@tonic-gate 	fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
13230Sstevel@tonic-gate 	fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
13240Sstevel@tonic-gate 	fid->fid_iulen = 0;
13250Sstevel@tonic-gate 
1326*12451SMilan.Cermak@Sun.COM 	temp = MIN(udf_vfsp->udf_lbsize - F_LEN, MAXNAMELEN);
13270Sstevel@tonic-gate 	if ((error = ud_compress(namelen, &temp,
132812196SMilan.Cermak@Sun.COM 	    (uint8_t *)namep, fid->fid_spec)) == 0) {
13290Sstevel@tonic-gate 		fid->fid_idlen = (uint8_t)temp;
13300Sstevel@tonic-gate 		error = ud_dirprepareentry(tdp, slotp, buf, cr);
13310Sstevel@tonic-gate 	}
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	kmem_free(buf, udf_vfsp->udf_lbsize);
13340Sstevel@tonic-gate 
13350Sstevel@tonic-gate bad:
13360Sstevel@tonic-gate 	return (error);
13370Sstevel@tonic-gate }
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate /*
13400Sstevel@tonic-gate  * Write a prototype directory into the empty inode ip, whose parent is dp.
13410Sstevel@tonic-gate  */
13420Sstevel@tonic-gate /* ARGSUSED2 */
13430Sstevel@tonic-gate int
ud_dirmakedirect(struct ud_inode * ip,struct ud_inode * dp,struct cred * cr)13440Sstevel@tonic-gate ud_dirmakedirect(struct ud_inode *ip,
13450Sstevel@tonic-gate 	struct ud_inode *dp, struct cred *cr)
13460Sstevel@tonic-gate {
13470Sstevel@tonic-gate 	int32_t err;
13480Sstevel@tonic-gate 	uint32_t blkno, size, parent_len, tbno;
13490Sstevel@tonic-gate 	struct fbuf *fbp;
13500Sstevel@tonic-gate 	struct file_id *fid;
13510Sstevel@tonic-gate 	struct icb_ext *iext;
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	ud_printf("ud_dirmakedirect\n");
13540Sstevel@tonic-gate 
13550Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&ip->i_contents));
13560Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	parent_len = sizeof (struct file_id);
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	if ((ip->i_desc_type != ICB_FLAG_ONE_AD) ||
136112196SMilan.Cermak@Sun.COM 	    (parent_len > ip->i_max_emb)) {
13620Sstevel@tonic-gate 		ASSERT(ip->i_ext);
13630Sstevel@tonic-gate 		/*
13640Sstevel@tonic-gate 		 * Allocate space for the directory we're creating.
13650Sstevel@tonic-gate 		 */
13660Sstevel@tonic-gate 		if ((err = ud_alloc_space(ip->i_vfs, ip->i_icb_prn,
136712196SMilan.Cermak@Sun.COM 		    0, 1, &blkno, &size, 0, 0)) != 0) {
13680Sstevel@tonic-gate 			return (err);
13690Sstevel@tonic-gate 		}
13700Sstevel@tonic-gate 		/*
13710Sstevel@tonic-gate 		 * init with the size of
13720Sstevel@tonic-gate 		 * directory with just the
13730Sstevel@tonic-gate 		 * parent
13740Sstevel@tonic-gate 		 */
13750Sstevel@tonic-gate 		ip->i_size = sizeof (struct file_id);
13760Sstevel@tonic-gate 		ip->i_flag |= IUPD|ICHG|IATTCHG;
13770Sstevel@tonic-gate 		iext = ip->i_ext;
13780Sstevel@tonic-gate 		iext->ib_prn = ip->i_icb_prn;
13790Sstevel@tonic-gate 		iext->ib_block = blkno;
13800Sstevel@tonic-gate 		iext->ib_count = ip->i_size;
13810Sstevel@tonic-gate 		iext->ib_offset = 0;
13820Sstevel@tonic-gate 		ip->i_ext_used = 1;
13830Sstevel@tonic-gate 	} else {
13840Sstevel@tonic-gate 		ip->i_size = sizeof (struct file_id);
13850Sstevel@tonic-gate 		ip->i_flag |= IUPD|ICHG|IATTCHG;
13860Sstevel@tonic-gate 	}
13870Sstevel@tonic-gate 
13880Sstevel@tonic-gate 	ITIMES_NOLOCK(ip);
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 	/*
13910Sstevel@tonic-gate 	 * Update the dp link count and write out the change.
13920Sstevel@tonic-gate 	 * This reflects the ".." entry we'll soon write.
13930Sstevel@tonic-gate 	 */
13940Sstevel@tonic-gate 	if (dp->i_nlink == MAXLINK) {
13950Sstevel@tonic-gate 		return (EMLINK);
13960Sstevel@tonic-gate 	}
13970Sstevel@tonic-gate 	dp->i_nlink++;
13980Sstevel@tonic-gate 	dp->i_flag |= ICHG;
13990Sstevel@tonic-gate 	ud_iupdat(dp, 1);
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 	/*
14020Sstevel@tonic-gate 	 * Initialize directory with ".."
14030Sstevel@tonic-gate 	 * Since the parent directory is locked, we don't have to
14040Sstevel@tonic-gate 	 * worry about anything changing when we drop the write
14050Sstevel@tonic-gate 	 * lock on (ip).
14060Sstevel@tonic-gate 	 */
14070Sstevel@tonic-gate 	rw_exit(&ip->i_contents);
14080Sstevel@tonic-gate 	if ((err = fbread(ITOV(ip), (offset_t)0,
140912196SMilan.Cermak@Sun.COM 	    ip->i_udf->udf_lbsize, S_WRITE, &fbp)) != 0) {
14100Sstevel@tonic-gate 		rw_enter(&ip->i_contents, RW_WRITER);
14110Sstevel@tonic-gate 		return (err);
14120Sstevel@tonic-gate 	}
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	bzero(fbp->fb_addr, ip->i_udf->udf_lbsize);
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	fid = (struct file_id *)fbp->fb_addr;
14170Sstevel@tonic-gate 	fid->fid_ver = SWAP_16(1);
14180Sstevel@tonic-gate 	fid->fid_flags = FID_DIR | FID_PARENT;
14190Sstevel@tonic-gate 	fid->fid_icb.lad_ext_len = SWAP_32(dp->i_udf->udf_lbsize);
14200Sstevel@tonic-gate 	fid->fid_icb.lad_ext_loc = SWAP_32(dp->i_icb_block);
14210Sstevel@tonic-gate 	fid->fid_icb.lad_ext_prn = SWAP_16(dp->i_icb_prn);
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	/*
14240Sstevel@tonic-gate 	 * fid_idlen, fid_iulen and fid_spec are zero
14250Sstevel@tonic-gate 	 * due to bzero above
14260Sstevel@tonic-gate 	 */
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	if ((err = ud_ip_off2bno(ip, 0, &tbno)) == 0) {
14290Sstevel@tonic-gate 		ud_make_tag(ip->i_udf, &fid->fid_tag,
143012196SMilan.Cermak@Sun.COM 		    UD_FILE_ID_DESC, tbno, FID_LEN(fid));
14310Sstevel@tonic-gate 	}
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	err = ud_fbwrite(fbp, ip);
14340Sstevel@tonic-gate 	rw_enter(&ip->i_contents, RW_WRITER);
14350Sstevel@tonic-gate 
14360Sstevel@tonic-gate 	return (err);
14370Sstevel@tonic-gate }
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate int
ud_dirrename(struct ud_inode * sdp,struct ud_inode * sip,struct ud_inode * tdp,struct ud_inode * tip,char * namep,uint8_t * buf,struct slot * slotp,struct cred * cr)14400Sstevel@tonic-gate ud_dirrename(struct ud_inode *sdp, struct ud_inode *sip,
14410Sstevel@tonic-gate 	struct ud_inode *tdp, struct ud_inode *tip, char *namep,
14420Sstevel@tonic-gate 	uint8_t *buf, struct slot *slotp, struct cred *cr)
14430Sstevel@tonic-gate {
14440Sstevel@tonic-gate 	int32_t error = 0, doingdirectory;
14450Sstevel@tonic-gate 	struct file_id *fid;
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate 	ud_printf("ud_dirrename\n");
14480Sstevel@tonic-gate 	ASSERT(sdp->i_udf != NULL);
14490Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&sdp->i_udf->udf_rename_lck));
14500Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&tdp->i_rwlock));
145112196SMilan.Cermak@Sun.COM 	ASSERT(RW_WRITE_HELD(&tdp->i_contents));
14520Sstevel@tonic-gate 	ASSERT(buf);
14530Sstevel@tonic-gate 	ASSERT(slotp->ep);
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate 	fid = slotp->ep;
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate 	/*
14580Sstevel@tonic-gate 	 * Short circuit rename of something to itself.
14590Sstevel@tonic-gate 	 */
14600Sstevel@tonic-gate 	if (sip->i_icb_lbano == tip->i_icb_lbano) {
14610Sstevel@tonic-gate 		return (ESAME);		/* special KLUDGE error code */
14620Sstevel@tonic-gate 	}
14630Sstevel@tonic-gate 	/*
14640Sstevel@tonic-gate 	 * Everything is protected under the vfs_rename_lock so the ordering
14650Sstevel@tonic-gate 	 * of i_contents locks doesn't matter here.
14660Sstevel@tonic-gate 	 */
14670Sstevel@tonic-gate 	rw_enter(&sip->i_contents, RW_READER);
14680Sstevel@tonic-gate 	rw_enter(&tip->i_contents, RW_READER);
14690Sstevel@tonic-gate 
14700Sstevel@tonic-gate 	/*
14710Sstevel@tonic-gate 	 * Check that everything is on the same filesystem.
14720Sstevel@tonic-gate 	 */
14730Sstevel@tonic-gate 	if ((ITOV(tip)->v_vfsp != ITOV(tdp)->v_vfsp) ||
14740Sstevel@tonic-gate 	    (ITOV(tip)->v_vfsp != ITOV(sip)->v_vfsp)) {
14750Sstevel@tonic-gate 		error = EXDEV;		/* XXX archaic */
14760Sstevel@tonic-gate 		goto out;
14770Sstevel@tonic-gate 	}
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate 	/*
14800Sstevel@tonic-gate 	 * Must have write permission to rewrite target entry.
14810Sstevel@tonic-gate 	 */
148212196SMilan.Cermak@Sun.COM 	if ((error = ud_iaccess(tdp, IWRITE, cr, 0)) != 0 ||
14830Sstevel@tonic-gate 	    (error = ud_sticky_remove_access(tdp, tip, cr)) != 0)
14840Sstevel@tonic-gate 		goto out;
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	/*
14870Sstevel@tonic-gate 	 * Ensure source and target are compatible (both directories
14880Sstevel@tonic-gate 	 * or both not directories).  If target is a directory it must
14890Sstevel@tonic-gate 	 * be empty and have no links to it; in addition it must not
14900Sstevel@tonic-gate 	 * be a mount point, and both the source and target must be
14910Sstevel@tonic-gate 	 * writable.
14920Sstevel@tonic-gate 	 */
14930Sstevel@tonic-gate 	doingdirectory = (sip->i_type == VDIR);
14940Sstevel@tonic-gate 	if (tip->i_type == VDIR) {
14950Sstevel@tonic-gate 		if (!doingdirectory) {
14960Sstevel@tonic-gate 			error = EISDIR;
14970Sstevel@tonic-gate 			goto out;
14980Sstevel@tonic-gate 		}
14990Sstevel@tonic-gate 		/*
1500569Sbatschul 		 * vn_vfswlock will prevent mounts from using the directory
1501569Sbatschul 		 * until we are done.
15020Sstevel@tonic-gate 		 */
1503569Sbatschul 		if (vn_vfswlock(ITOV(tip))) {
15040Sstevel@tonic-gate 			error = EBUSY;
15050Sstevel@tonic-gate 			goto out;
15060Sstevel@tonic-gate 		}
15070Sstevel@tonic-gate 		if (vn_mountedvfs(ITOV(tip)) != NULL) {
15080Sstevel@tonic-gate 			vn_vfsunlock(ITOV(tip));
15090Sstevel@tonic-gate 			error = EBUSY;
15100Sstevel@tonic-gate 			goto out;
15110Sstevel@tonic-gate 		}
15120Sstevel@tonic-gate 		if (!ud_dirempty(tip, tdp->i_uniqid, cr) || tip->i_nlink > 2) {
15130Sstevel@tonic-gate 			vn_vfsunlock(ITOV(tip));
15140Sstevel@tonic-gate 			error = EEXIST;	/* SIGH should be ENOTEMPTY */
15150Sstevel@tonic-gate 			goto out;
15160Sstevel@tonic-gate 		}
15170Sstevel@tonic-gate 	} else if (doingdirectory) {
15180Sstevel@tonic-gate 		error = ENOTDIR;
15190Sstevel@tonic-gate 		goto out;
15200Sstevel@tonic-gate 	}
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 	/*
15230Sstevel@tonic-gate 	 * Rewrite the inode pointer for target name entry
15240Sstevel@tonic-gate 	 * from the target inode (ip) to the source inode (sip).
15250Sstevel@tonic-gate 	 * This prevents the target entry from disappearing
15260Sstevel@tonic-gate 	 * during a crash. Mark the directory inode to reflect the changes.
15270Sstevel@tonic-gate 	 */
15280Sstevel@tonic-gate 	dnlc_remove(ITOV(tdp), namep);
15290Sstevel@tonic-gate 	fid->fid_icb.lad_ext_prn = SWAP_16(sip->i_icb_prn);
15300Sstevel@tonic-gate 	fid->fid_icb.lad_ext_loc = SWAP_32(sip->i_icb_block);
15310Sstevel@tonic-gate 	dnlc_enter(ITOV(tdp), namep, ITOV(sip));
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 	ud_make_tag(tdp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
153412196SMilan.Cermak@Sun.COM 	    SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 	error = ud_write_fid(tdp, slotp, buf);
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate 	if (error) {
15390Sstevel@tonic-gate 		if (doingdirectory) {
15400Sstevel@tonic-gate 			vn_vfsunlock(ITOV(tip));
15410Sstevel@tonic-gate 		}
15420Sstevel@tonic-gate 		goto out;
15430Sstevel@tonic-gate 	}
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	/*
15460Sstevel@tonic-gate 	 * Upgrade to write lock on tip
15470Sstevel@tonic-gate 	 */
15480Sstevel@tonic-gate 	rw_exit(&tip->i_contents);
15490Sstevel@tonic-gate 	rw_enter(&tip->i_contents, RW_WRITER);
15500Sstevel@tonic-gate 
15510Sstevel@tonic-gate 	mutex_enter(&tdp->i_tlock);
15520Sstevel@tonic-gate 	tdp->i_flag |= IUPD|ICHG;
15530Sstevel@tonic-gate 	mutex_exit(&tdp->i_tlock);
15540Sstevel@tonic-gate 	/*
15550Sstevel@tonic-gate 	 * Decrement the link count of the target inode.
15560Sstevel@tonic-gate 	 * Fix the ".." entry in sip to point to dp.
15570Sstevel@tonic-gate 	 * This is done after the new entry is on the disk.
15580Sstevel@tonic-gate 	 */
15590Sstevel@tonic-gate 	tip->i_nlink--;
15600Sstevel@tonic-gate 	mutex_enter(&tip->i_tlock);
15610Sstevel@tonic-gate 	tip->i_flag |= ICHG;
15620Sstevel@tonic-gate 	mutex_exit(&tip->i_tlock);
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	if (doingdirectory) {
15650Sstevel@tonic-gate 		/*
15660Sstevel@tonic-gate 		 * The entry for tip no longer exists so I can unlock the
15670Sstevel@tonic-gate 		 * vfslock.
15680Sstevel@tonic-gate 		 */
15690Sstevel@tonic-gate 		vn_vfsunlock(ITOV(tip));
15700Sstevel@tonic-gate 		/*
15710Sstevel@tonic-gate 		 * Decrement target link count once more if it was a directory.
15720Sstevel@tonic-gate 		 */
15730Sstevel@tonic-gate 		if (tip->i_nlink != 0) {
15740Sstevel@tonic-gate 			cmn_err(CE_WARN,
15750Sstevel@tonic-gate 			"ud_direnter: target directory link count != 0");
15760Sstevel@tonic-gate 			rw_exit(&tip->i_contents);
15770Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
15780Sstevel@tonic-gate 			return (EINVAL);
15790Sstevel@tonic-gate 		}
15800Sstevel@tonic-gate 		/*
15810Sstevel@tonic-gate 		 * Renaming a directory with the parent different
15820Sstevel@tonic-gate 		 * requires that ".." be rewritten.  The window is
15830Sstevel@tonic-gate 		 * still there for ".." to be inconsistent, but this
15840Sstevel@tonic-gate 		 * is unavoidable, and a lot shorter than when it was
15850Sstevel@tonic-gate 		 * done in a user process.  We decrement the link
15860Sstevel@tonic-gate 		 * count in the new parent as appropriate to reflect
15870Sstevel@tonic-gate 		 * the just-removed target.  If the parent is the
15880Sstevel@tonic-gate 		 * same, this is appropriate since the original
15890Sstevel@tonic-gate 		 * directory is going away.  If the new parent is
15900Sstevel@tonic-gate 		 * different, dirfixdotdot() will bump the link count
15910Sstevel@tonic-gate 		 * back.
15920Sstevel@tonic-gate 		 */
15930Sstevel@tonic-gate 		tdp->i_nlink--;
15940Sstevel@tonic-gate 		mutex_enter(&tdp->i_tlock);
15950Sstevel@tonic-gate 		tdp->i_flag |= ICHG;
15960Sstevel@tonic-gate 		mutex_exit(&tdp->i_tlock);
15970Sstevel@tonic-gate 		ITIMES_NOLOCK(tdp);
15980Sstevel@tonic-gate 		if (sdp != tdp) {
15990Sstevel@tonic-gate 			rw_exit(&tip->i_contents);
16000Sstevel@tonic-gate 			rw_exit(&sip->i_contents);
16010Sstevel@tonic-gate 			error = ud_dirfixdotdot(sip, sdp, tdp);
16020Sstevel@tonic-gate 			return (error);
16030Sstevel@tonic-gate 		}
16040Sstevel@tonic-gate 	}
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate out:
16070Sstevel@tonic-gate 	rw_exit(&tip->i_contents);
16080Sstevel@tonic-gate 	rw_exit(&sip->i_contents);
16090Sstevel@tonic-gate 	return (error);
16100Sstevel@tonic-gate }
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate /*
16140Sstevel@tonic-gate  * 1. When we find a slot that belonged to a file which was deleted
16150Sstevel@tonic-gate  *      and is in the middle of the directory
16160Sstevel@tonic-gate  * 2. There is not empty slot available. The new entry
16170Sstevel@tonic-gate  *      will be at the end of the directory and fits in the same block.
16180Sstevel@tonic-gate  * 3. There is no empty slot available. The new
16190Sstevel@tonic-gate  *      entry will not fit the left over directory
16200Sstevel@tonic-gate  *      so we need to allocate a new block. If
16210Sstevel@tonic-gate  *      we cannot allocate a proximity block we need
16220Sstevel@tonic-gate  *      to allocate a new icb, and data block.
16230Sstevel@tonic-gate  */
16240Sstevel@tonic-gate int
ud_dirprepareentry(struct ud_inode * dp,struct slot * slotp,uint8_t * buf,struct cred * cr)16250Sstevel@tonic-gate ud_dirprepareentry(struct ud_inode *dp,
16260Sstevel@tonic-gate 	struct slot *slotp, uint8_t *buf, struct cred *cr)
16270Sstevel@tonic-gate {
16280Sstevel@tonic-gate 	struct fbuf *fbp;
16290Sstevel@tonic-gate 	uint16_t old_dtype;
16300Sstevel@tonic-gate 	int32_t error = 0;
16310Sstevel@tonic-gate 	uint32_t entrysize, count, offset, tbno, old_size, off;
16320Sstevel@tonic-gate 	struct file_id *fid;
16330Sstevel@tonic-gate 	int32_t lbsize, lbmask, mask;
16340Sstevel@tonic-gate 
16350Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&dp->i_rwlock));
16360Sstevel@tonic-gate 
163712196SMilan.Cermak@Sun.COM 	ASSERT((slotp->status == NONE) || (slotp->status == FOUND));
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 	ud_printf("ud_dirprepareentry\n");
16400Sstevel@tonic-gate 	lbsize = dp->i_udf->udf_lbsize;
16410Sstevel@tonic-gate 	lbmask = dp->i_udf->udf_lbmask;
16420Sstevel@tonic-gate 	mask = ~lbmask;
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 	fid = (struct file_id *)buf;
16450Sstevel@tonic-gate 	entrysize = FID_LEN(fid);
16460Sstevel@tonic-gate 
16470Sstevel@tonic-gate 	/*
16480Sstevel@tonic-gate 	 * If we didn't find a slot, then indicate that the
16490Sstevel@tonic-gate 	 * new slot belongs at the end of the directory.
16500Sstevel@tonic-gate 	 * If we found a slot, then the new entry can be
16510Sstevel@tonic-gate 	 * put at slotp->offset.
16520Sstevel@tonic-gate 	 */
16530Sstevel@tonic-gate 	if (slotp->status == NONE) {
16540Sstevel@tonic-gate 		/*
16550Sstevel@tonic-gate 		 * We did not find a slot, the next
16560Sstevel@tonic-gate 		 * entry will be in the end of the directory
16570Sstevel@tonic-gate 		 * see if we can fit the new entry inside
16580Sstevel@tonic-gate 		 * the old block. If not allocate a new block.
16590Sstevel@tonic-gate 		 */
16600Sstevel@tonic-gate 		if (entrysize > slotp->size) {
16610Sstevel@tonic-gate 			/*
16620Sstevel@tonic-gate 			 * extend the directory
16630Sstevel@tonic-gate 			 * size by one new block
16640Sstevel@tonic-gate 			 */
16650Sstevel@tonic-gate 			old_dtype = dp->i_desc_type;
16660Sstevel@tonic-gate 			old_size = (uint32_t)dp->i_size;
16670Sstevel@tonic-gate 			error = ud_bmap_write(dp, slotp->offset,
166812196SMilan.Cermak@Sun.COM 			    blkoff(dp->i_udf, slotp->offset) + entrysize,
166912196SMilan.Cermak@Sun.COM 			    0, cr);
16700Sstevel@tonic-gate 			if (error != 0) {
16710Sstevel@tonic-gate 				return (error);
16720Sstevel@tonic-gate 			}
16730Sstevel@tonic-gate 			if (old_dtype != dp->i_desc_type) {
16740Sstevel@tonic-gate 				/*
16750Sstevel@tonic-gate 				 * oops we changed the astrat
16760Sstevel@tonic-gate 				 * of the file, we have to
16770Sstevel@tonic-gate 				 * recaliculate tags
16780Sstevel@tonic-gate 				 * fortunately we donot have more
16790Sstevel@tonic-gate 				 * than one lbsize to handle here
16800Sstevel@tonic-gate 				 */
16810Sstevel@tonic-gate 				if ((error = ud_ip_off2bno(dp,
168212196SMilan.Cermak@Sun.COM 				    0, &tbno)) != 0) {
16830Sstevel@tonic-gate 					return (error);
16840Sstevel@tonic-gate 				}
16850Sstevel@tonic-gate 				if ((error = fbread(ITOV(dp), 0,
168612196SMilan.Cermak@Sun.COM 				    dp->i_udf->udf_lbsize,
168712196SMilan.Cermak@Sun.COM 				    S_WRITE, &fbp)) != 0) {
16880Sstevel@tonic-gate 					return (error);
16890Sstevel@tonic-gate 				}
16900Sstevel@tonic-gate 				off = 0;
16910Sstevel@tonic-gate 				while (off < old_size) {
16920Sstevel@tonic-gate 					struct file_id *tfid;
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 					tfid = (struct file_id *)
169512196SMilan.Cermak@Sun.COM 					    (fbp->fb_addr + off);
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 					ud_make_tag(dp->i_udf, &tfid->fid_tag,
169812196SMilan.Cermak@Sun.COM 					    UD_FILE_ID_DESC, tbno,
169912196SMilan.Cermak@Sun.COM 					    FID_LEN(tfid));
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 					off += FID_LEN(tfid);
17020Sstevel@tonic-gate 				}
17030Sstevel@tonic-gate 				if (error = ud_fbwrite(fbp, dp)) {
17040Sstevel@tonic-gate 					return (error);
17050Sstevel@tonic-gate 				}
17060Sstevel@tonic-gate 			}
17070Sstevel@tonic-gate 		} else {
17080Sstevel@tonic-gate 			/* Extend the directory size */
17090Sstevel@tonic-gate 			if (dp->i_desc_type != ICB_FLAG_ONE_AD) {
17100Sstevel@tonic-gate 				ASSERT(dp->i_ext);
17110Sstevel@tonic-gate 				dp->i_ext[dp->i_ext_used - 1].ib_count +=
171212196SMilan.Cermak@Sun.COM 				    entrysize;
17130Sstevel@tonic-gate 			}
17140Sstevel@tonic-gate 		}
17150Sstevel@tonic-gate 		dp->i_size += entrysize;
17160Sstevel@tonic-gate 		dp->i_flag |= IUPD|ICHG|IATTCHG;
17170Sstevel@tonic-gate 		ITIMES_NOLOCK(dp);
17180Sstevel@tonic-gate 	} else if (slotp->status != FOUND) {
17190Sstevel@tonic-gate 		cmn_err(CE_WARN, "status is not NONE/FOUND");
17200Sstevel@tonic-gate 		return (EINVAL);
17210Sstevel@tonic-gate 	}
17220Sstevel@tonic-gate 
17230Sstevel@tonic-gate 	if ((error = ud_ip_off2bno(dp, slotp->offset, &tbno)) != 0) {
17240Sstevel@tonic-gate 		return (error);
17250Sstevel@tonic-gate 	}
172612196SMilan.Cermak@Sun.COM 	ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
172712196SMilan.Cermak@Sun.COM 	    tbno, FID_LEN(fid));
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	/*
17300Sstevel@tonic-gate 	 * fbread cannot cross a
17310Sstevel@tonic-gate 	 * MAXBSIZE boundary so handle it here
17320Sstevel@tonic-gate 	 */
17330Sstevel@tonic-gate 	offset = slotp->offset;
17340Sstevel@tonic-gate 	if ((error = fbread(ITOV(dp), offset & mask, lbsize,
173512196SMilan.Cermak@Sun.COM 	    S_WRITE, &fbp)) != 0) {
17360Sstevel@tonic-gate 		return (error);
17370Sstevel@tonic-gate 	}
17380Sstevel@tonic-gate 	if ((offset & mask) != ((offset + entrysize) & mask)) {
17390Sstevel@tonic-gate 		count = entrysize - ((offset + entrysize) & lbmask);
17400Sstevel@tonic-gate 	} else {
17410Sstevel@tonic-gate 		count = entrysize;
17420Sstevel@tonic-gate 	}
17430Sstevel@tonic-gate 	bcopy((caddr_t)buf, fbp->fb_addr + (offset & lbmask), count);
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 	if (error = ud_fbwrite(fbp, dp)) {
17460Sstevel@tonic-gate 		return (error);
17470Sstevel@tonic-gate 	}
17480Sstevel@tonic-gate 
17490Sstevel@tonic-gate 	if (entrysize > count) {
17500Sstevel@tonic-gate 		if ((error = fbread(ITOV(dp), (offset + entrysize) & mask,
175112196SMilan.Cermak@Sun.COM 		    lbsize, S_WRITE, &fbp)) != 0) {
17520Sstevel@tonic-gate 			return (error);
17530Sstevel@tonic-gate 		}
17540Sstevel@tonic-gate 		bcopy((caddr_t)(buf + count), fbp->fb_addr, entrysize - count);
17550Sstevel@tonic-gate 		if (error = ud_fbwrite(fbp, dp)) {
17560Sstevel@tonic-gate 			return (error);
17570Sstevel@tonic-gate 		}
17580Sstevel@tonic-gate 	}
17590Sstevel@tonic-gate 
17600Sstevel@tonic-gate 	dp->i_flag |= IUPD|ICHG|IATTCHG;
17610Sstevel@tonic-gate 	ITIMES_NOLOCK(dp);
17620Sstevel@tonic-gate 	return (error);
17630Sstevel@tonic-gate }
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate /*
17670Sstevel@tonic-gate  * Fix the FID_PARENT entry of the child directory so that it points
17680Sstevel@tonic-gate  * to the new parent directory instead of the old one.  Routine
17690Sstevel@tonic-gate  * assumes that dp is a directory and that all the inodes are on
17700Sstevel@tonic-gate  * the same file system.
17710Sstevel@tonic-gate  */
17720Sstevel@tonic-gate int
ud_dirfixdotdot(struct ud_inode * dp,struct ud_inode * opdp,struct ud_inode * npdp)17730Sstevel@tonic-gate ud_dirfixdotdot(struct ud_inode *dp,
17740Sstevel@tonic-gate 	struct ud_inode *opdp, struct ud_inode *npdp)
17750Sstevel@tonic-gate {
17760Sstevel@tonic-gate 	int32_t err = 0;
17770Sstevel@tonic-gate 	struct fbuf *fbp;
17780Sstevel@tonic-gate 	struct file_id *fid;
17790Sstevel@tonic-gate 	uint32_t loc, dummy, tbno;
17800Sstevel@tonic-gate 
17810Sstevel@tonic-gate 	ud_printf("ud_dirfixdotdot\n");
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 	ASSERT(opdp->i_type == VDIR);
17840Sstevel@tonic-gate 	ASSERT(npdp->i_type == VDIR);
17850Sstevel@tonic-gate 
17860Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&npdp->i_rwlock));
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	err = fbread(ITOV(dp), (offset_t)0,
178912196SMilan.Cermak@Sun.COM 	    dp->i_udf->udf_lbsize, S_WRITE, &fbp);
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	if (err || dp->i_nlink == 0 ||
179212196SMilan.Cermak@Sun.COM 	    dp->i_size < sizeof (struct file_id)) {
17930Sstevel@tonic-gate 		goto bad;
17940Sstevel@tonic-gate 	}
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate 	if ((err = ud_ip_off2bno(dp, 0, &tbno)) != 0) {
17970Sstevel@tonic-gate 		goto bad;
17980Sstevel@tonic-gate 	}
17990Sstevel@tonic-gate 
18000Sstevel@tonic-gate 	fid = (struct file_id *)fbp->fb_addr;
18010Sstevel@tonic-gate 	if ((ud_verify_tag_and_desc(&fid->fid_tag, UD_FILE_ID_DESC,
18020Sstevel@tonic-gate 	    tbno,
18030Sstevel@tonic-gate 	    1, dp->i_udf->udf_lbsize) != 0) ||
18040Sstevel@tonic-gate 	    ((fid->fid_flags & (FID_DIR | FID_PARENT)) !=
18050Sstevel@tonic-gate 	    (FID_DIR | FID_PARENT))) {
18060Sstevel@tonic-gate 		err = ENOTDIR;
18070Sstevel@tonic-gate 		goto bad;
18080Sstevel@tonic-gate 	}
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate 	loc = ud_xlate_to_daddr(dp->i_udf,
181112196SMilan.Cermak@Sun.COM 	    SWAP_16(fid->fid_icb.lad_ext_prn),
181212196SMilan.Cermak@Sun.COM 	    SWAP_32(fid->fid_icb.lad_ext_loc), 1, &dummy);
18130Sstevel@tonic-gate 	ASSERT(dummy == 1);
18140Sstevel@tonic-gate 	if (loc == npdp->i_icb_lbano) {
18150Sstevel@tonic-gate 		goto bad;
18160Sstevel@tonic-gate 	}
18170Sstevel@tonic-gate 
18180Sstevel@tonic-gate 	/*
18190Sstevel@tonic-gate 	 * Increment the link count in the new parent inode and force it out.
18200Sstevel@tonic-gate 	 */
18210Sstevel@tonic-gate 	if (npdp->i_nlink == MAXLINK) {
18220Sstevel@tonic-gate 		err = EMLINK;
18230Sstevel@tonic-gate 		goto bad;
18240Sstevel@tonic-gate 	}
18250Sstevel@tonic-gate 
18260Sstevel@tonic-gate 	npdp->i_nlink++;
18270Sstevel@tonic-gate 	mutex_enter(&npdp->i_tlock);
18280Sstevel@tonic-gate 	npdp->i_flag |= ICHG;
18290Sstevel@tonic-gate 	mutex_exit(&npdp->i_tlock);
18300Sstevel@tonic-gate 	ud_iupdat(npdp, 1);
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate 	/*
18330Sstevel@tonic-gate 	 * Rewrite the child FID_PARENT entry and force it out.
18340Sstevel@tonic-gate 	 */
18350Sstevel@tonic-gate 	dnlc_remove(ITOV(dp), "..");
18360Sstevel@tonic-gate 	fid->fid_icb.lad_ext_loc = SWAP_32(npdp->i_icb_block);
18370Sstevel@tonic-gate 	fid->fid_icb.lad_ext_prn = SWAP_16(npdp->i_icb_prn);
18380Sstevel@tonic-gate 	ud_make_tag(npdp->i_udf, &fid->fid_tag,
183912196SMilan.Cermak@Sun.COM 	    UD_FILE_ID_DESC, tbno, FID_LEN(fid));
18400Sstevel@tonic-gate 	dnlc_enter(ITOV(dp), "..", ITOV(npdp));
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate 	err = ud_fbwrite(fbp, dp);
18430Sstevel@tonic-gate 	fbp = NULL;
18440Sstevel@tonic-gate 	if (err != 0) {
18450Sstevel@tonic-gate 		goto bad;
18460Sstevel@tonic-gate 	}
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 	/*
18490Sstevel@tonic-gate 	 * Decrement the link count of the old parent inode and force
18500Sstevel@tonic-gate 	 * it out.  If opdp is NULL, then this is a new directory link;
18510Sstevel@tonic-gate 	 * it has no parent, so we need not do anything.
18520Sstevel@tonic-gate 	 */
18530Sstevel@tonic-gate 	if (opdp != NULL) {
18540Sstevel@tonic-gate 		rw_enter(&opdp->i_contents, RW_WRITER);
18550Sstevel@tonic-gate 		if (opdp->i_nlink != 0) {
18560Sstevel@tonic-gate 			opdp->i_nlink--;
18570Sstevel@tonic-gate 			mutex_enter(&opdp->i_tlock);
18580Sstevel@tonic-gate 			opdp->i_flag |= ICHG;
18590Sstevel@tonic-gate 			mutex_exit(&opdp->i_tlock);
18600Sstevel@tonic-gate 			ud_iupdat(opdp, 1);
18610Sstevel@tonic-gate 		}
18620Sstevel@tonic-gate 		rw_exit(&opdp->i_contents);
18630Sstevel@tonic-gate 	}
18640Sstevel@tonic-gate 	return (0);
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate bad:
18670Sstevel@tonic-gate 	if (fbp) {
18680Sstevel@tonic-gate 		fbrelse(fbp, S_OTHER);
18690Sstevel@tonic-gate 	}
18700Sstevel@tonic-gate 	return (err);
18710Sstevel@tonic-gate }
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate int32_t
ud_write_fid(struct ud_inode * dp,struct slot * slot,uint8_t * buf)18740Sstevel@tonic-gate ud_write_fid(struct ud_inode *dp, struct slot *slot, uint8_t *buf)
18750Sstevel@tonic-gate {
18760Sstevel@tonic-gate 	struct udf_vfs *udf_vfsp;
18770Sstevel@tonic-gate 	struct fbuf *lfbp;
18780Sstevel@tonic-gate 	struct file_id *fid;
18790Sstevel@tonic-gate 	int32_t error = 0;
18800Sstevel@tonic-gate 	uint32_t lbsize, lbmask, count, old_count;
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 	ASSERT(slot->fbp);
18840Sstevel@tonic-gate 	ASSERT(slot->ep);
18850Sstevel@tonic-gate 
18860Sstevel@tonic-gate 	udf_vfsp = dp->i_udf;
18870Sstevel@tonic-gate 	fid = slot->ep;
18880Sstevel@tonic-gate 	lbsize = dp->i_udf->udf_lbsize;
18890Sstevel@tonic-gate 	lbmask = dp->i_udf->udf_lbmask;
18900Sstevel@tonic-gate 
18910Sstevel@tonic-gate 	if (((uint8_t *)fid >= buf) &&
189212196SMilan.Cermak@Sun.COM 	    ((uint8_t *)fid < &buf[udf_vfsp->udf_lbsize])) {
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate 		if ((error = fbread(ITOV(dp),
189512196SMilan.Cermak@Sun.COM 		    (offset_t)(slot->offset & ~lbmask),
189612196SMilan.Cermak@Sun.COM 		    lbsize, S_WRITE, &lfbp)) != 0) {
18970Sstevel@tonic-gate 			goto out;
18980Sstevel@tonic-gate 		}
18990Sstevel@tonic-gate 
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 		/*
19020Sstevel@tonic-gate 		 * We do not need to write the
19030Sstevel@tonic-gate 		 * file name. So check if the entry
19040Sstevel@tonic-gate 		 * does not cross a block boundary
19050Sstevel@tonic-gate 		 * and write only required portions
19060Sstevel@tonic-gate 		 */
19070Sstevel@tonic-gate 		if (((slot->offset & lbmask) +
19080Sstevel@tonic-gate 			sizeof (struct file_id)) > lbsize) {
19090Sstevel@tonic-gate 
19100Sstevel@tonic-gate 			if ((slot->offset & lbmask) != 0) {
19110Sstevel@tonic-gate 				old_count = lbsize -
19120Sstevel@tonic-gate 					(slot->offset & lbmask);
19130Sstevel@tonic-gate 				count = (slot->offset +
19140Sstevel@tonic-gate 					sizeof (struct file_id)) &
19150Sstevel@tonic-gate 					lbmask;
19160Sstevel@tonic-gate 			} else {
19170Sstevel@tonic-gate 				old_count = 0;
19180Sstevel@tonic-gate 				count = sizeof (struct file_id);
19190Sstevel@tonic-gate 			}
19200Sstevel@tonic-gate 
19210Sstevel@tonic-gate 			bcopy(buf, lfbp->fb_addr +
19220Sstevel@tonic-gate 				(slot->offset & lbmask), old_count);
19230Sstevel@tonic-gate 			bcopy(buf + old_count,
19240Sstevel@tonic-gate 				slot->fbp->fb_addr, count);
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 			error = ud_fbwrite(lfbp, dp);
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 			error = ud_fbwrite(slot->fbp, dp);
19290Sstevel@tonic-gate 		} else {
19300Sstevel@tonic-gate 			bcopy(buf, lfbp->fb_addr +
19310Sstevel@tonic-gate 				(slot->offset & lbmask),
19320Sstevel@tonic-gate 				sizeof (struct file_id));
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 			error = ud_fbwrite(lfbp, dp);
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 			fbrelse(slot->fbp, S_OTHER);
19370Sstevel@tonic-gate 		}
19380Sstevel@tonic-gate 	} else {
19390Sstevel@tonic-gate 		if ((error = ud_fbwrite(slot->fbp, dp)) != 0) {
19400Sstevel@tonic-gate 			fid->fid_flags &= ~FID_DELETED;
19410Sstevel@tonic-gate 			ud_make_tag(dp->i_udf, &fid->fid_tag, UD_FILE_ID_DESC,
194212196SMilan.Cermak@Sun.COM 			    SWAP_32(fid->fid_tag.tag_loc), FID_LEN(fid));
19430Sstevel@tonic-gate 		}
19440Sstevel@tonic-gate 	}
19450Sstevel@tonic-gate 	slot->fbp = NULL;
19460Sstevel@tonic-gate 
19470Sstevel@tonic-gate out:
19480Sstevel@tonic-gate 	return (error);
19490Sstevel@tonic-gate }
1950