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