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