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