|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: /* ! 25: * Copyright (c) 1982, 1986, 1989, 1993, 1995 ! 26: * The Regents of the University of California. All rights reserved. ! 27: * (c) UNIX System Laboratories, Inc. ! 28: * All or some portions of this file are derived from material licensed ! 29: * to the University of California by American Telephone and Telegraph ! 30: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 31: * the permission of UNIX System Laboratories, Inc. ! 32: * ! 33: * Redistribution and use in source and binary forms, with or without ! 34: * modification, are permitted provided that the following conditions ! 35: * are met: ! 36: * 1. Redistributions of source code must retain the above copyright ! 37: * notice, this list of conditions and the following disclaimer. ! 38: * 2. Redistributions in binary form must reproduce the above copyright ! 39: * notice, this list of conditions and the following disclaimer in the ! 40: * documentation and/or other materials provided with the distribution. ! 41: * 3. All advertising materials mentioning features or use of this software ! 42: * must display the following acknowledgement: ! 43: * This product includes software developed by the University of ! 44: * California, Berkeley and its contributors. ! 45: * 4. Neither the name of the University nor the names of its contributors ! 46: * may be used to endorse or promote products derived from this software ! 47: * without specific prior written permission. ! 48: * ! 49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 59: * SUCH DAMAGE. ! 60: * ! 61: * @(#)hfs_vnodeops.c 3.0 ! 62: * derived from @(#)ufs_vnops.c 8.27 (Berkeley) 5/27/95 ! 63: * ! 64: * (c) 1997-1999 Apple Computer, Inc. All Rights Reserved ! 65: * (c) 1990, 1992 NeXT Computer, Inc. All Rights Reserved ! 66: * ! 67: * ! 68: * hfs_vnodeops.c -- vnode layer for loadable Macintosh file system ! 69: * ! 70: * MODIFICATION HISTORY: ! 71: * 1-Mar-1999 Scott Roberts h_meta is now released when the complex vnode is relesed ! 72: * 26-Feb-1999 Pat Dirks (copied by Chw) Fixed hfs_lookup to check for ! 73: * error return on vget. ! 74: * 25-Feb-1999 Pat Dirks Fixed hfs_remove to use a local copy of the h_sibling pointer around vnode_uncache. ! 75: * 3-Feb-1999 Pat Dirks Changed to stop updating wrapper volume name in MDB since wrapper volume's ! 76: * catalog isn't updated and this inconsistency trips Disk First Aid's checks. ! 77: * 22-Jan-1999 Pat Dirks Changed hfs_rename, hfs_remove, and hfs_rmdir to call cache_purge. ! 78: * 22-Jan-1999 Don Brady After calling hfsMoveRename call hfsLookup to get new name. ! 79: * 12-Jan-1999 Don Brady Fixed the size of ATTR_CMN_NAME buffer to NAME_MAX + 1. ! 80: * 8-Jan-1999 Pat Dirks Added hfs_writepermission and change hfs_setattrlist to use it instead of ! 81: * including an incorrect derivative of hfs_access in-line. ! 82: * 15-Dec-1998 Pat Dirks Changed setattrlist to do permission checking as appropriate (Radar #2290212). ! 83: * 17-Nov-1998 Scott Roberts Added support for long volume names in SetAttrList(). ! 84: * 6-Nov-1998 Don Brady Add support for UTF-8 names. ! 85: * 3-Nov-1998 Umesh Vaishampayan Changes to deal with "struct timespec" ! 86: * change in the kernel. ! 87: * 21-Oct-1998 Scott Roberts Added support for advisory locking (Radar #2237914). ! 88: * 25-Sep-1998 Don Brady Changed hfs_exchange to call hfs_chid after updating catalog (radar #2276605). ! 89: * 23-Sep-1998 Don Brady hfs_setattrlist now calls hfs_chown and hfs_chmod to change values. ! 90: * 15-Sep-1998 Pat Dirks Cleaned up vnode unlocking on various error exit paths and changed ! 91: * to use new error stub routines in place of hfs_mknod and hfs_link. ! 92: * 16-Sep-1998 Don Brady When renaming a volume in hfs_setattrlist, also update hfs+ wrapper name (radar #2272925). ! 93: * 1-Sep-1998 Don Brady Fix uninitiazed time variable in hfs_makenode (radar #2270372). ! 94: * 31-Aug-1998 Don Brady Adjust change time for DST in hfs_update (radar #2265075). ! 95: * 12-Aug-1998 Don Brady Update complex node name in hfs_rename (radar #2262111). ! 96: * 5-Aug-1998 Don Brady In hfs_setattrlist call MacToVFSError after calling UpdateCatalogNode (radar #2261247). ! 97: * 21-Jul-1998 Don Brady Fixed broken preflight in hfs_getattrlist. ! 98: * 17-Jul-1998 Clark Warner Fixed the one left out case of freeing M_NAMEI in hfs_abort ! 99: * 13-Jul-1998 Don Brady Add uio_resid preflight check to hfs_search (radar #2251855). ! 100: * 30-Jun-1998 Scott Roberts Changed hfs_makenode and its callers to free M_NAMEI. ! 101: * 29-Jun-1998 Don Brady Fix unpacking order in UnpackSearchAttributeBlock (radar #2249248). ! 102: * 13-Jun-1998 Scott Roberts Integrated changes to hfs_lock (radar #2237243). ! 103: * 4-Jun-1998 Pat Dirks Split off hfs_lookup.c and hfs_readwrite.c ! 104: * 3-Jun-1998 Don Brady Fix hfs_rename bugs (radar #2229259, #2239823, 2231108 and #2237380). ! 105: * Removed extra vputs in hfs_rmdir (radar #2240309). ! 106: * 28-May-1998 Don Brady Fix hfs_truncate to correctly extend files (radar #2237242). ! 107: * 20-May-1998 Don Brady In hfs_close shrink the peof to the smallest size neccessary (radar #2230094). ! 108: * 5-May-1998 Don Brady Fixed typo in hfs_rename (apply H_FILEID macro to VTOH result). ! 109: * 29-Apr-1998 Joe Sokol Don't do cluster I/O when logical block size is not 4K multiple. ! 110: * 28-Apr-1998 Pat Dirks Cleaned up unused variable physBlockNo in hfs_write. ! 111: * 28-Apr-1998 Joe Sokol Touched up support for cluster_read/cluster_write and enabled it. ! 112: * 27-Apr-1998 Don Brady Remove some DEBUG_BREAK calls in DbgVopTest. ! 113: * 24-Apr-1998 Pat Dirks Fixed read logic to read-ahead only ONE block, and of only logBlockSize instead of 64K... ! 114: * Added calls to brelse() on errors from bread[n](). ! 115: * Changed logic to add overall length field to AttrBlockSize only on attribute return operations. ! 116: * 23-Apr-1998 Don Brady The hfs_symlink call is only supported on HFS Plus disks. ! 117: * 23-Apr-1998 Deric Horn Fixed hfs_search bug where matches were skipped when buffer was full. ! 118: * 22-Apr-1998 Scott Roberts Return on error if catalog mgr returns an error in truncate. ! 119: * 21-Apr-1998 Don Brady Fix up time/date conversions. ! 120: * 20-Apr-1998 Don Brady Remove course-grained hfs metadata locking. ! 121: * 17-Apr-1998 Pat Dirks Officially enabled searchfs in vops table. ! 122: * 17-Apr-1998 Deric Horn Bug fixes to hfs_search, reenabled searchfs trap for upcoming kernel build. ! 123: * 15-Apr-1998 Don Brady Add locking for HFS B-trees. Don't lock file meta lock for VSYSTEM files. ! 124: * Don't call VOP_UPDATE for system files. Roll set_time into hfs_update. ! 125: * 14-Apr-1998 Pat Dirks Cleaned up fsync to skip complex nodes and not hit sibling nodes. ! 126: * 14-Apr-1998 Deric Horn Added hfs_search() and related routines for searchfs() support. ! 127: * 14-Apr-1998 Scott Roberts Fixed paramaters to ExchangeFileIDs() ! 128: * 13-Apr-1998 Pat Dirks Changed to update H_HINT whenever hfsLookup was called. ! 129: * 8-Apr-1998 Pat Dirks Added page-in and page-out passthrough routines to keep MapFS happy. ! 130: * 6-Apr-1998 Pat Dirks Changed hfs_write to clean up code and fix bug that caused ! 131: * zeroes to be interspersed in data. Added debug printf to hfs_read. ! 132: * 6-Apr-1998 Scott Roberts Added complex file support. ! 133: * 02-apr-1998 Don Brady UpdateCatalogNode now takes parID and name as input. ! 134: * 31-mar-1998 Don Brady Sync up with final HFSVolumes.h header file. ! 135: * 27-mar-1998 Don Brady Check result from UFSToHFSStr to make sure hfs/hfs+ names are not greater than 31 characters. ! 136: * 27-mar-1998 chw minor link fixes. ! 137: * 19-Mar-1998 ser Added hfs_readdirattr. ! 138: * 17-Mar-1998 ser Removed CheckUserAccess. Added code to implement ExchangeFileIDs ! 139: * 16-Mar-1998 Pat Dirks Fixed logic in hfs_read to properly account for space ! 140: * remaining past selected offset and avoid premature panic. ! 141: * 16-jun-1997 Scott Roberts ! 142: * Dec-1991 Kevin Wells at NeXT: ! 143: * Significantly modified for Macintosh file system. ! 144: * Added support for NFS exportability. ! 145: * 25-Jun-1990 Doug Mitchell at NeXT: ! 146: * Created (for DOS file system). ! 147: */ ! 148: ! 149: #include <sys/param.h> ! 150: #include <sys/systm.h> ! 151: #include <sys/kernel.h> ! 152: #include <sys/file.h> ! 153: #include <sys/stat.h> ! 154: #include <sys/buf.h> ! 155: #include <sys/proc.h> ! 156: #include <sys/conf.h> ! 157: #include <sys/mount.h> ! 158: #include <mach/machine/vm_types.h> ! 159: #include <sys/vnode.h> ! 160: #include <sys/malloc.h> ! 161: #include <sys/namei.h> ! 162: #include <sys/signalvar.h> ! 163: #include <sys/attr.h> ! 164: #include <miscfs/specfs/specdev.h> ! 165: #include <vfs/vfs_support.h> ! 166: ! 167: #include <libkern/libkern.h> ! 168: #include <mach/machine/simple_lock.h> ! 169: #include <machine/spl.h> ! 170: #include <mach/features.h> ! 171: #include <kern/mapfs.h> ! 172: ! 173: #include "hfs.h" ! 174: #include "hfs_lockf.h" ! 175: #include "hfs_dbg.h" ! 176: #include "hfscommon/headers/FileMgrInternal.h" ! 177: #include "hfscommon/headers/CatalogPrivate.h" ! 178: #include "hfscommon/headers/system/HFSUnicodeWrappers.h" ! 179: ! 180: // Private description used in hfs_search ! 181: struct SearchState { ! 182: long searchBits; ! 183: BTreeIterator btreeIterator; ! 184: short vRefNum; // Volume reference of volume being searched ! 185: char isHFSPlus; // True if volume is HFS ! 186: char pad1[3]; // long align the structure ! 187: }; ! 188: typedef struct SearchState SearchState; ! 189: ! 190: ! 191: enum { ! 192: MAXHFSFILESIZE = 0x7FFFFFFF /* this needs to go in the mount structure */ ! 193: }; ! 194: ! 195: #define OWNERSHIP_ONLY_ATTRS (ATTR_CMN_OWNERID | ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_FLAGS) ! 196: ! 197: /* Global vfs data structures for hfs */ ! 198: int (**hfs_vnodeop_p)(); ! 199: ! 200: /* external routines defined in vfs_cache.c */ ! 201: ! 202: void hfs_vhashrem(struct hfsnode *hp); ! 203: ! 204: extern void cache_purge (struct vnode *vp); ! 205: extern int cache_lookup (struct vnode *dvp, struct vnode **vpp, struct componentname *cnp); ! 206: extern void cache_enter (struct vnode *dvp, struct vnode *vpp, struct componentname *cnp); ! 207: ! 208: extern void vnode_pager_setsize( struct vnode *vp, u_long nsize); ! 209: extern int vnode_uncache( struct vnode *vp); ! 210: ! 211: extern groupmember(gid_t gid, struct ucred *cred); ! 212: ! 213: static int hfs_makenode( int mode, struct vnode *dvp, struct vnode **vpp, struct componentname *cnp); ! 214: ! 215: static void hfs_chid(struct hfsnode *hp, u_int32_t fid, u_int32_t pid, char* name); ! 216: ! 217: static int UnpackSearchAttributeBlock(struct vnode *vp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer); ! 218: ! 219: Boolean CheckCriteria( ExtendedVCB *vcb, const SearchState *searchState, u_long searchBits, struct attrlist *attrList, CatalogRecord *catalogRecord, CatalogKey *key, searchinfospec_t *searchInfo1, searchinfospec_t *searchInfo2 ); ! 220: ! 221: static int InsertMatch( struct vnode *vp, struct uio *a_uio, CatalogRecord *catalogRecord, CatalogKey *key, struct attrlist *returnAttrList, void *attributesBuffer, void *variableBuffer, u_long bufferSize, u_long * nummatches ); ! 222: ! 223: extern Boolean ComparePartialName(ConstStr31Param thisName, ConstStr31Param substring); ! 224: extern Boolean CompareFullName(ConstStr31Param thisName, ConstStr31Param testName); ! 225: extern Boolean CompareMasked(const UInt32 *thisValue, const UInt32 *compareData, const UInt32 *compareMask, UInt32 count); ! 226: ! 227: static Boolean CompareRange(u_long val, u_long low, u_long high); ! 228: ! 229: static Boolean CompareRange( u_long val, u_long low, u_long high ) ! 230: { ! 231: return( (val >= low) && (val <= high) ); ! 232: } ! 233: //#define CompareRange(val, low, high) ((val >= low) && (val <= high)) ! 234: ! 235: ! 236: static int hfs_chown( struct vnode *vp, uid_t uid, gid_t gid, struct ucred *cred, struct proc *p); ! 237: static int hfs_chmod( struct vnode *vp, int mode, struct ucred *cred, struct proc *p); ! 238: static int hfs_chflags( struct vnode *vp, u_long flags, struct ucred *cred, struct proc *p); ! 239: ! 240: /* ! 241: * Enabling cluster read/write operations. ! 242: */ ! 243: extern int doclusterread; ! 244: extern int doclusterwrite; ! 245: ! 246: int hfs_lookup(); /* in hfs_lookup.c */ ! 247: int hfs_read(); /* in hfs_readwrite.c */ ! 248: int hfs_write(); /* in hfs_readwrite.c */ ! 249: int hfs_ioctl(); /* in hfs_readwrite.c */ ! 250: int hfs_select(); /* in hfs_readwrite.c */ ! 251: int hfs_mmap(); /* in hfs_readwrite.c */ ! 252: int hfs_seek(); /* in hfs_readwrite.c */ ! 253: int hfs_bmap(); /* in hfs_readwrite.c */ ! 254: int hfs_strategy(); /* in hfs_readwrite.c */ ! 255: int hfs_reallocblks(); /* in hfs_readwrite.c */ ! 256: int hfs_truncate(); /* in hfs_readwrite.c */ ! 257: int hfs_allocate(); /* in hfs_readwrite.c */ ! 258: int hfs_pagein(); /* in hfs_readwrite.c */ ! 259: int hfs_pageout(); /* in hfs_readwrite.c */ ! 260: ! 261: /***************************************************************************** ! 262: * ! 263: * Operations on vnodes ! 264: * ! 265: *****************************************************************************/ ! 266: ! 267: /* ! 268: * Create a regular file ! 269: #% create dvp L U U ! 270: #% create vpp - L - ! 271: # ! 272: vop_create { ! 273: IN WILLRELE struct vnode *dvp; ! 274: OUT struct vnode **vpp; ! 275: IN struct componentname *cnp; ! 276: IN struct vattr *vap; ! 277: ! 278: We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is ! 279: a previous error. ! 280: ! 281: */ ! 282: ! 283: static int ! 284: hfs_create(ap) ! 285: struct vop_create_args /* { ! 286: struct vnode *a_dvp; ! 287: struct vnode **a_vpp; ! 288: struct componentname *a_cnp; ! 289: struct vattr *a_vap; ! 290: } */ *ap; ! 291: { ! 292: struct proc *p = CURRENT_PROC; ! 293: int retval; ! 294: int mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); ! 295: DBG_FUNC_NAME("create"); ! 296: DBG_VOP_LOCKS_DECL(2); ! 297: DBG_VOP_PRINT_FUNCNAME(); ! 298: DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp); ! 299: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp); ! 300: ! 301: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 302: DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS); ! 303: DBG_VOP_CONT(("\tva_type %d va_mode 0x%x\n", ! 304: ap->a_vap->va_type, ap->a_vap->va_mode)); ! 305: ! 306: #if DIAGNOSTIC ! 307: DBG_HFS_NODE_CHECK(ap->a_dvp); ! 308: DBG_ASSERT(ap->a_dvp->v_type == VDIR); ! 309: if(ap->a_vap == NULL) { ! 310: panic("NULL attr on create"); ! 311: } ! 312: ! 313: switch(ap->a_vap->va_type) { ! 314: case VDIR: ! 315: VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ! 316: VPUT(ap->a_dvp); ! 317: DBG_VOP_LOCKS_TEST(EISDIR); ! 318: return (EISDIR); /* use hfs_mkdir instead */ ! 319: case VREG: ! 320: case VLNK: ! 321: break; ! 322: default: ! 323: DBG_ERR(("%s: INVALID va_type: %d, %s, %s\n", funcname, ap->a_vap->va_type, H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr)); ! 324: VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ! 325: VPUT(ap->a_dvp); ! 326: DBG_VOP_LOCKS_TEST(EINVAL); ! 327: return (EINVAL); ! 328: } ! 329: // if(ap->a_vap->va_mode & (VSUID | VSGID | VSVTX)) { ! 330: // DBG_ERR(("%s: INVALID va_mode (%o): %s, %s\n", funcname, ap->a_vap->va_mode, H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr)); ! 331: // DBG_VOP_LOCKS_TEST(EINVAL); ! 332: // VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ! 333: // VPUT(ap->a_dvp); ! 334: // return (EINVAL); /* Can't do these */ ! 335: // }; ! 336: #endif ! 337: ! 338: /* lock catalog b-tree */ ! 339: retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p); ! 340: if (retval != E_NONE) { ! 341: VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ! 342: VPUT(ap->a_dvp); ! 343: DBG_VOP_LOCKS_TEST( retval); ! 344: return (retval); ! 345: } ! 346: ! 347: /* Create the vnode */ ! 348: retval = hfs_makenode(mode, ap->a_dvp, ap->a_vpp, ap->a_cnp); ! 349: DBG_VOP_UPDATE_VP(1, *ap->a_vpp); ! 350: ! 351: /* unlock catalog b-tree */ ! 352: (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p); ! 353: ! 354: if (retval != E_NONE) { ! 355: DBG_ERR(("%s: hfs_makenode FAILED: %s, %s\n", funcname, ap->a_cnp->cn_nameptr, H_NAME(VTOH(ap->a_dvp)))); ! 356: } ! 357: DBG_VOP_LOCKS_TEST(retval); ! 358: return (retval); ! 359: } ! 360: ! 361: ! 362: ! 363: #if 0 /* Now stubbed out in the vnode ops table with err_mknod */ ! 364: /* ! 365: * Mknod vnode call ! 366: ! 367: #% mknod dvp L U U ! 368: #% mknod vpp - X - ! 369: # ! 370: vop_mknod { ! 371: IN WILLRELE struct vnode *dvp; ! 372: OUT WILLRELE struct vnode **vpp; ! 373: IN struct componentname *cnp; ! 374: IN struct vattr *vap; ! 375: */ ! 376: /* ARGSUSED */ ! 377: ! 378: static int ! 379: hfs_mknod(ap) ! 380: struct vop_mknod_args /* { ! 381: struct vnode *a_dvp; ! 382: struct vnode **a_vpp; ! 383: struct componentname *a_cnp; ! 384: struct vattr *a_vap; ! 385: } */ *ap; ! 386: { ! 387: DBG_FUNC_NAME("mknod"); ! 388: DBG_VOP_LOCKS_DECL(2); ! 389: DBG_VOP_PRINT_FUNCNAME(); ! 390: DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp); ! 391: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); ! 392: ! 393: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 394: DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKNOTNIL, VOPDBG_IGNORE, VOPDBG_POS); ! 395: ! 396: DBG_VOP(("%s: parent 0x%x name %s\n", funcname, (u_int)ap->a_dvp, ap->a_cnp->cn_nameptr)); ! 397: ! 398: VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ! 399: VPUT(ap->a_dvp); ! 400: ! 401: DBG_VOP_LOCKS_TEST(EOPNOTSUPP); ! 402: return (EOPNOTSUPP); ! 403: } ! 404: #endif ! 405: ! 406: ! 407: /* ! 408: * mkcomplex vnode call ! 409: * ! 410: ! 411: #% mkcomplex dvp L U U ! 412: #% mkcomplex vpp - L - ! 413: # ! 414: vop_mkcomplex { ! 415: IN WILLRELE struct vnode *dvp; ! 416: OUT struct vnode **vpp; ! 417: IN struct componentname *cnp; ! 418: IN struct vattr *vap; ! 419: IN u_long type; ! 420: } ! 421: ! 422: */ ! 423: ! 424: static int ! 425: hfs_mkcomplex(ap) ! 426: struct vop_mkcomplex_args /* { ! 427: struct vnode *a_dvp; ! 428: struct vnode **a_vpp; ! 429: struct componentname *a_cnp; ! 430: struct vattr *a_vap; ! 431: u_long a_type; ! 432: } */ *ap; ! 433: { ! 434: int retval = E_NONE; ! 435: DBG_FUNC_NAME("make_complex"); ! 436: DBG_VOP_LOCKS_DECL(2); ! 437: DBG_VOP_PRINT_FUNCNAME(); ! 438: DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp); ! 439: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); ! 440: ! 441: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 442: DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS); ! 443: ! 444: retval = VOP_CREATE(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap); ! 445: ! 446: DBG_VOP_LOCKS_TEST(retval); ! 447: return retval; ! 448: } ! 449: ! 450: ! 451: /* ! 452: * Open called. ! 453: #% open vp L L L ! 454: # ! 455: vop_open { ! 456: IN struct vnode *vp; ! 457: IN int mode; ! 458: IN struct ucred *cred; ! 459: IN struct proc *p; ! 460: */ ! 461: ! 462: ! 463: static int ! 464: hfs_open(ap) ! 465: struct vop_open_args /* { ! 466: struct vnode *a_vp; ! 467: int a_mode; ! 468: struct ucred *a_cred; ! 469: struct proc *a_p; ! 470: } */ *ap; ! 471: { ! 472: struct hfsnode *hp = VTOH(ap->a_vp); ! 473: int retval = E_NONE; ! 474: DBG_FUNC_NAME("open"); ! 475: DBG_VOP_LOCKS_DECL(1); ! 476: DBG_VOP_PRINT_FUNCNAME(); ! 477: DBG_VOP_CONT(("\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 478: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); ! 479: ! 480: if (ap->a_vp->v_type == VREG) /* Only files */ ! 481: { ! 482: /* ! 483: * Files marked append-only must be opened for appending. ! 484: */ ! 485: if ((hp->h_meta->h_pflags & APPEND) && ! 486: (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) ! 487: retval = EPERM; ! 488: } ! 489: ! 490: ! 491: DBG_VOP_LOCKS_TEST(retval); ! 492: return (retval); ! 493: } ! 494: ! 495: /* ! 496: * Close called. ! 497: * ! 498: * Update the times on the hfsnode. ! 499: #% close vp U U U ! 500: # ! 501: vop_close { ! 502: IN struct vnode *vp; ! 503: IN int fflag; ! 504: IN struct ucred *cred; ! 505: IN struct proc *p; ! 506: */ ! 507: ! 508: ! 509: static int ! 510: hfs_close(ap) ! 511: struct vop_close_args /* { ! 512: struct vnode *a_vp; ! 513: int a_fflag; ! 514: struct ucred *a_cred; ! 515: struct proc *a_p; ! 516: } */ *ap; ! 517: { ! 518: register struct vnode *vp = ap->a_vp; ! 519: struct hfsnode *hp = VTOH(vp); ! 520: struct proc *p = ap->a_p; ! 521: FCB *fcb; ! 522: struct timeval tv; ! 523: off_t leof; ! 524: u_long blks, blocksize; ! 525: int retval = E_NONE; ! 526: ! 527: DBG_FUNC_NAME("close"); ! 528: DBG_VOP_LOCKS_DECL(1); ! 529: DBG_VOP_PRINT_FUNCNAME(); ! 530: DBG_VOP_CONT(("\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 531: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 532: ! 533: simple_lock(&vp->v_interlock); ! 534: if (vp->v_usecount > 1) { ! 535: tv = time; ! 536: HFSTIMES(hp, &tv, &tv); ! 537: } ! 538: simple_unlock(&vp->v_interlock); ! 539: ! 540: /* ! 541: * VOP_CLOSE can be called with vp locked (from vclean). ! 542: * We check for this case using VOP_ISLOCKED and bail. ! 543: * ! 544: * also, ignore complex nodes; there's no data associated with them. ! 545: */ ! 546: if (H_FORKTYPE(hp) == kDirCmplx || VOP_ISLOCKED(vp)) { ! 547: DBG_VOP_LOCKS_TEST(E_NONE); ! 548: return E_NONE; ! 549: }; ! 550: ! 551: fcb = HTOFCB(hp); ! 552: leof = fcb->fcbEOF; ! 553: ! 554: if (leof != 0) { ! 555: blocksize = HTOVCB(hp)->blockSize; ! 556: blks = leof / blocksize; ! 557: if ((blks * blocksize) != leof) ! 558: blks++; ! 559: ! 560: /* ! 561: * Shrink the peof to the smallest size neccessary to contain the leof. ! 562: */ ! 563: if ((blks * blocksize) < fcb->fcbPLen) { ! 564: vn_lock(vp, LK_EXCLUSIVE | LK_CANRECURSE, p); ! 565: retval = VOP_TRUNCATE(vp, leof, 0, ap->a_cred, p); ! 566: VOP_UNLOCK(vp, 0, p); ! 567: } ! 568: } ! 569: ! 570: /* File is already flushed, so just reset values */ ! 571: H_HINT(hp) = kNoHint; /* reset catalog hint */ ! 572: ! 573: if (doclusterwrite) { ! 574: long devBlockSize = 0; ! 575: ! 576: vn_lock(vp, LK_EXCLUSIVE | LK_CANRECURSE, p); ! 577: ! 578: VOP_DEVBLOCKSIZE(hp->h_devvp, &devBlockSize); ! 579: cluster_close(vp, PAGE_SIZE, devBlockSize); ! 580: ! 581: VOP_UNLOCK(vp, 0, p); ! 582: } ! 583: ! 584: DBG_VOP_LOCKS_TEST(retval); ! 585: return (retval); ! 586: } ! 587: ! 588: /* ! 589: #% access vp L L L ! 590: # ! 591: vop_access { ! 592: IN struct vnode *vp; ! 593: IN int mode; ! 594: IN struct ucred *cred; ! 595: IN struct proc *p; ! 596: ! 597: */ ! 598: ! 599: static int ! 600: hfs_access(ap) ! 601: struct vop_access_args /* { ! 602: struct vnode *a_vp; ! 603: int a_mode; ! 604: struct ucred *a_cred; ! 605: struct proc *a_p; ! 606: } */ *ap; ! 607: { ! 608: struct vnode *vp = ap->a_vp; ! 609: struct ucred *cred = ap->a_cred; ! 610: struct hfsnode *hp = VTOH(vp); ! 611: ExtendedVCB *vcb = HTOVCB(hp); ! 612: register gid_t *gp; ! 613: mode_t mask, mode; ! 614: Boolean isHFSPlus; ! 615: int retval = E_NONE; ! 616: int i; ! 617: DBG_FUNC_NAME("access"); ! 618: DBG_VOP_LOCKS_DECL(1); ! 619: // DBG_VOP_PRINT_FUNCNAME(); ! 620: // DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 621: ! 622: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); ! 623: ! 624: mode = ap->a_mode; ! 625: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord ); ! 626: ! 627: /* ! 628: * Disallow write attempts on read-only file systems; ! 629: * unless the file is a socket, fifo, or a block or ! 630: * character device resident on the file system. ! 631: */ ! 632: if (mode & VWRITE) { ! 633: switch (vp->v_type) { ! 634: case VDIR: ! 635: case VLNK: ! 636: case VREG: ! 637: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) ! 638: return (EROFS); ! 639: break; ! 640: default: ! 641: break; ! 642: } ! 643: } ! 644: ! 645: /* If immutable bit set, nobody gets to write it. */ ! 646: if ((mode & VWRITE) && (hp->h_meta->h_pflags & IMMUTABLE)) ! 647: return (EPERM); ! 648: ! 649: /* Otherwise, user id 0 always gets access. */ ! 650: if (ap->a_cred->cr_uid == 0) { ! 651: retval = 0; ! 652: goto Exit; ! 653: }; ! 654: ! 655: mask = 0; ! 656: ! 657: /* Otherwise, check the owner. */ ! 658: if (cred->cr_uid == hp->h_meta->h_uid) { ! 659: if (mode & VEXEC) ! 660: mask |= S_IXUSR; ! 661: if (mode & VREAD) ! 662: mask |= S_IRUSR; ! 663: if (mode & VWRITE) ! 664: mask |= S_IWUSR; ! 665: retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES); ! 666: goto Exit; ! 667: } ! 668: ! 669: /* Otherwise, check the groups. */ ! 670: for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) ! 671: if (hp->h_meta->h_gid == *gp) { ! 672: if (mode & VEXEC) ! 673: mask |= S_IXGRP; ! 674: if (mode & VREAD) ! 675: mask |= S_IRGRP; ! 676: if (mode & VWRITE) ! 677: mask |= S_IWGRP; ! 678: retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES); ! 679: goto Exit; ! 680: } ! 681: ! 682: /* Otherwise, check everyone else. */ ! 683: if (mode & VEXEC) ! 684: mask |= S_IXOTH; ! 685: if (mode & VREAD) ! 686: mask |= S_IROTH; ! 687: if (mode & VWRITE) ! 688: mask |= S_IWOTH; ! 689: retval = ((hp->h_meta->h_mode & mask) == mask ? 0 : EACCES); ! 690: ! 691: Exit: ! 692: DBG_VOP_LOCKS_TEST(retval); ! 693: return (retval); ! 694: } ! 695: ! 696: ! 697: ! 698: /* ! 699: #% getattr vp = = = ! 700: # ! 701: vop_getattr { ! 702: IN struct vnode *vp; ! 703: IN struct vattr *vap; ! 704: IN struct ucred *cred; ! 705: IN struct proc *p; ! 706: ! 707: */ ! 708: ! 709: ! 710: /* ARGSUSED */ ! 711: static int ! 712: hfs_getattr(ap) ! 713: struct vop_getattr_args /* { ! 714: struct vnode *a_vp; ! 715: struct vattr *a_vap; ! 716: struct ucred *a_cred; ! 717: struct proc *a_p; ! 718: } */ *ap; ! 719: { ! 720: register struct vnode *vp = ap->a_vp; ! 721: register struct hfsnode *hp = VTOH(vp); ! 722: register struct vattr *vap = ap->a_vap; ! 723: struct timeval tv; ! 724: DBG_FUNC_NAME("getattr"); ! 725: DBG_VOP_LOCKS_DECL(1); ! 726: DBG_VOP_PRINT_FUNCNAME(); ! 727: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 728: ! 729: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS); ! 730: ! 731: DBG_HFS_NODE_CHECK(ap->a_vp); ! 732: ! 733: tv = time; ! 734: HFSTIMES(hp, &tv, &tv); ! 735: ! 736: vap->va_fsid = hp->h_dev; ! 737: vap->va_fileid = H_FILEID(hp); ! 738: vap->va_mode = hp->h_meta->h_mode; ! 739: vap->va_nlink = 1; ! 740: vap->va_uid = hp->h_meta->h_uid; ! 741: vap->va_gid = hp->h_meta->h_gid; ! 742: vap->va_rdev = hp->h_meta->h_rdev; ! 743: #if MACH_NBC ! 744: if ((vp->v_type == VREG) && vp->v_vm_info && vp->v_vm_info->mapped && ! 745: (!vp->v_vm_info->filesize)) { ! 746: vap->va_size = vp->v_vm_info->vnode_size; ! 747: } ! 748: else ! 749: #endif /* MACH_NBC */ ! 750: if (vp->v_type == VDIR) { ! 751: vap->va_size = hp->h_size; ! 752: vap->va_bytes = 0; ! 753: } ! 754: else { ! 755: vap->va_size = hp->h_xfcb->fcb_fcb.fcbEOF; ! 756: vap->va_bytes = hp->h_size; ! 757: } ! 758: vap->va_atime.tv_nsec = 0; ! 759: vap->va_atime.tv_sec = hp->h_meta->h_atime; ! 760: vap->va_mtime.tv_nsec = 0; ! 761: vap->va_mtime.tv_sec = hp->h_meta->h_mtime; ! 762: vap->va_ctime.tv_nsec = 0; ! 763: vap->va_ctime.tv_sec = hp->h_meta->h_ctime; ! 764: vap->va_flags = hp->h_meta->h_pflags; ! 765: vap->va_gen = 0; ! 766: /* this doesn't belong here */ ! 767: if (vp->v_type == VBLK) ! 768: vap->va_blocksize = BLKDEV_IOSIZE; ! 769: else if (vp->v_type == VCHR) ! 770: vap->va_blocksize = MAXPHYSIO; ! 771: else ! 772: vap->va_blocksize = VTOVFS(vp)->mnt_stat.f_iosize; ! 773: vap->va_type = vp->v_type; ! 774: vap->va_filerev = 0; ! 775: ! 776: DBG_VOP_LOCKS_TEST(E_NONE); ! 777: return (E_NONE); ! 778: } ! 779: ! 780: /* ! 781: * Set attribute vnode op. called from several syscalls ! 782: #% setattr vp L L L ! 783: # ! 784: vop_setattr { ! 785: IN struct vnode *vp; ! 786: IN struct vattr *vap; ! 787: IN struct ucred *cred; ! 788: IN struct proc *p; ! 789: ! 790: */ ! 791: ! 792: static int ! 793: hfs_setattr(ap) ! 794: struct vop_setattr_args /* { ! 795: struct vnode *a_vp; ! 796: struct vattr *a_vap; ! 797: struct ucred *a_cred; ! 798: struct proc *a_p; ! 799: } */ *ap; ! 800: { ! 801: struct vnode *vp = ap->a_vp; ! 802: struct hfsnode *hp = VTOH(vp); ! 803: struct vattr *vap = ap->a_vap; ! 804: struct ucred *cred = ap->a_cred; ! 805: struct proc *p = ap->a_p; ! 806: struct timeval atimeval, mtimeval; ! 807: int retval; ! 808: DBG_FUNC_NAME("setattr"); ! 809: DBG_VOP_LOCKS_DECL(1); ! 810: DBG_VOP_PRINT_FUNCNAME(); ! 811: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 812: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); ! 813: WRITE_CK(vp, funcname); ! 814: DBG_HFS_NODE_CHECK(ap->a_vp); ! 815: ! 816: /* ! 817: * Check for unsettable attributes. ! 818: */ ! 819: if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || ! 820: (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || ! 821: (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || ! 822: ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { ! 823: retval = EINVAL; ! 824: goto ErrorExit; ! 825: } ! 826: ! 827: if (vap->va_flags != VNOVAL) { ! 828: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { ! 829: retval = EROFS; ! 830: goto ErrorExit; ! 831: }; ! 832: if ((retval = hfs_chflags(vp, vap->va_flags, cred, p))) { ! 833: goto ErrorExit; ! 834: }; ! 835: if (vap->va_flags & (IMMUTABLE | APPEND)) { ! 836: retval = 0; ! 837: goto ErrorExit; ! 838: }; ! 839: } ! 840: ! 841: if (hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) { ! 842: retval = EPERM; ! 843: goto ErrorExit; ! 844: }; ! 845: /* ! 846: * Go through the fields and update iff not VNOVAL. ! 847: */ ! 848: if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { ! 849: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { ! 850: retval = EROFS; ! 851: goto ErrorExit; ! 852: }; ! 853: if ((retval = hfs_chown(vp, vap->va_uid, vap->va_gid, cred, p))) { ! 854: goto ErrorExit; ! 855: }; ! 856: } ! 857: if (vap->va_size != VNOVAL) { ! 858: /* ! 859: * Disallow write attempts on read-only file systems; ! 860: * unless the file is a socket, fifo, or a block or ! 861: * character device resident on the file system. ! 862: */ ! 863: switch (vp->v_type) { ! 864: case VDIR: ! 865: retval = EISDIR; ! 866: goto ErrorExit; ! 867: case VLNK: ! 868: case VREG: ! 869: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { ! 870: retval = EROFS; ! 871: goto ErrorExit; ! 872: }; ! 873: break; ! 874: default: ! 875: break; ! 876: } ! 877: if ((retval = VOP_TRUNCATE(vp, vap->va_size, 0, cred, p))) { ! 878: goto ErrorExit; ! 879: }; ! 880: } ! 881: hp = VTOH(vp); ! 882: if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { ! 883: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { ! 884: retval = EROFS; ! 885: goto ErrorExit; ! 886: }; ! 887: if (cred->cr_uid != hp->h_meta->h_uid && ! 888: (retval = suser(cred, &p->p_acflag)) && ! 889: ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || ! 890: (retval = VOP_ACCESS(vp, VWRITE, cred, p)))) { ! 891: goto ErrorExit; ! 892: }; ! 893: if (vap->va_atime.tv_sec != VNOVAL) ! 894: hp->h_meta->h_nodeflags |= IN_ACCESS; ! 895: if (vap->va_mtime.tv_sec != VNOVAL) ! 896: hp->h_meta->h_nodeflags |= IN_CHANGE | IN_UPDATE; ! 897: atimeval.tv_sec = vap->va_atime.tv_sec; ! 898: atimeval.tv_usec = 0; ! 899: mtimeval.tv_sec = vap->va_mtime.tv_sec; ! 900: mtimeval.tv_usec = 0; ! 901: if ((retval = VOP_UPDATE(vp, &atimeval, &mtimeval, 1))) { ! 902: goto ErrorExit; ! 903: }; ! 904: } ! 905: retval = 0; ! 906: if (vap->va_mode != (mode_t)VNOVAL) { ! 907: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { ! 908: retval = EROFS; ! 909: goto ErrorExit; ! 910: }; ! 911: retval = hfs_chmod(vp, (int)vap->va_mode, cred, p); ! 912: }; ! 913: ! 914: ErrorExit: ; ! 915: ! 916: DBG_VOP(("hfs_setattr: returning %d...\n", retval)); ! 917: DBG_VOP_LOCKS_TEST(retval); ! 918: return (retval); ! 919: } ! 920: ! 921: ! 922: /* ! 923: ! 924: # ! 925: #% getattrlist vp = = = ! 926: # ! 927: vop_getattrlist { ! 928: IN struct vnode *vp; ! 929: IN struct attrlist *alist; ! 930: INOUT struct uio *uio; ! 931: IN struct ucred *cred; ! 932: IN struct proc *p; ! 933: }; ! 934: ! 935: */ ! 936: ! 937: static int ! 938: hfs_getattrlist(ap) ! 939: struct vop_getattrlist_args /* { ! 940: struct vnode *a_vp; ! 941: struct attrlist *a_alist ! 942: struct uio *a_uio; ! 943: struct ucred *a_cred; ! 944: struct proc *a_p; ! 945: } */ *ap; ! 946: { ! 947: struct vnode *vp = ap->a_vp; ! 948: struct hfsnode *hp = VTOH(vp); ! 949: struct attrlist *alist = ap->a_alist; ! 950: int error = 0; ! 951: struct hfsCatalogInfo catalogInfo; ! 952: struct hfsCatalogInfo *catInfoPtr = NULL; ! 953: int fixedblocksize; ! 954: int attrblocksize; ! 955: int attrbufsize; ! 956: void *attrbufptr; ! 957: void *attrptr; ! 958: void *varptr; ! 959: u_long fileID; ! 960: DBG_FUNC_NAME("getattrlist"); ! 961: DBG_VOP_LOCKS_DECL(1); ! 962: ! 963: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS); ! 964: DBG_HFS_NODE_CHECK(ap->a_vp); ! 965: DBG_VOP(("%s: Common attr:0x%lx, buff size Ox%lX,\n",funcname, (u_long)alist->commonattr,(u_long)ap->a_uio->uio_resid)); ! 966: ! 967: DBG_ASSERT(ap->a_uio->uio_rw == UIO_READ); ! 968: ! 969: if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || ! 970: ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) || ! 971: ((alist->volattr & ~ATTR_VOL_VALIDMASK) != 0) || ! 972: ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) || ! 973: ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0) || ! 974: ((alist->forkattr & ~ATTR_FORK_VALIDMASK) != 0)) { ! 975: DBG_ERR(("%s: bad attrlist\n", funcname)); ! 976: DBG_VOP_LOCKS_TEST(EINVAL); ! 977: return EINVAL; ! 978: }; ! 979: ! 980: /* Requesting volume information requires setting the ATTR_VOL_INFO bit and ! 981: volume info requests are mutually exclusive with all other info requests: */ ! 982: if ((alist->volattr != 0) && (((alist->volattr & ATTR_VOL_INFO) == 0) || ! 983: (alist->dirattr != 0) || (alist->fileattr != 0) || (alist->forkattr != 0) ! 984: )) { ! 985: DBG_ERR(("%s: conflicting information requested\n", funcname)); ! 986: DBG_VOP_LOCKS_TEST(EINVAL); ! 987: return EINVAL; ! 988: }; ! 989: ! 990: /* Reject requests for unsupported options for now: */ ! 991: if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) || ! 992: (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST))) { ! 993: DBG_ERR(("%s: illegal bits in attlist\n", funcname)); ! 994: DBG_VOP_LOCKS_TEST(EINVAL); ! 995: return EINVAL; ! 996: }; ! 997: ! 998: /* Requesting volume information requires root vnode */ ! 999: if ((alist->volattr) && (H_FILEID(hp) != kRootDirID)) { ! 1000: DBG_ERR(("%s: not root vnode\n", funcname)); ! 1001: DBG_VOP_LOCKS_TEST(EINVAL); ! 1002: return EINVAL; ! 1003: }; ! 1004: ! 1005: /* If a FileID (ATTR_CMN_OBJPERMANENTID) is requested on an HFS volume we must be sure ! 1006: to create the thread record before returning it: ! 1007: */ ! 1008: if (((vp->v_type == VREG) || (vp->v_type == VCPLX)) && ! 1009: (alist->commonattr & ATTR_CMN_OBJPERMANENTID)) { ! 1010: /* Only HFS-Plus volumes are guaranteed to have a thread record in place already: */ ! 1011: if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) { ! 1012: /* Create a thread record and return the FileID [which is the file's fileNumber] */ ! 1013: /* lock catalog b-tree */ ! 1014: error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, ap->a_p); ! 1015: error = hfsCreateFileID(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &fileID); ! 1016: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, ap->a_p); ! 1017: if (error) { ! 1018: DBG_VOP_LOCKS_TEST(error); ! 1019: DBG_ERR(("hfs_getattrlist: error %d on CreateFileIDRef.\n", error)); ! 1020: return error; ! 1021: }; ! 1022: ASSERT(fileID == H_FILEID(hp)); ! 1023: }; ! 1024: }; ! 1025: ! 1026: /* ! 1027: * Avoid unnecessary catalog lookups for volume info which is available directly ! 1028: * in the VCB and root vnode, or can be synthesized. ! 1029: */ ! 1030: if (((alist->volattr == 0) && ((alist->commonattr & HFS_ATTR_CMN_LOOKUPMASK) != 0)) || ! 1031: ((alist->dirattr & HFS_ATTR_DIR_LOOKUPMASK) != 0) || ! 1032: ((alist->fileattr & HFS_ATTR_FILE_LOOKUPMASK) != 0)) { ! 1033: ! 1034: /* lock catalog b-tree */ ! 1035: error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, ap->a_p); ! 1036: if (error) { ! 1037: DBG_VOP_LOCKS_TEST(error); ! 1038: return (error); ! 1039: } ! 1040: ! 1041: if (alist->volattr != 0) { ! 1042: /* Look up the root info, regardless of the vnode provided */ ! 1043: error = hfsLookup(VTOVCB(vp), 2, NULL, -1, 0, &catalogInfo); ! 1044: } else { ! 1045: error = hfsLookup(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), -1, 0, &catalogInfo); ! 1046: if (error == 0) H_HINT(hp) = catalogInfo.hint; /* Remember the last valid hint */ ! 1047: }; ! 1048: catInfoPtr = &catalogInfo; ! 1049: ! 1050: /* unlock catalog b-tree */ ! 1051: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, ap->a_p); ! 1052: }; ! 1053: ! 1054: fixedblocksize = AttributeBlockSize(alist); ! 1055: attrblocksize = fixedblocksize + (sizeof(u_long)); /* u_long for length longword */ ! 1056: if (alist->commonattr & ATTR_CMN_NAME) attrblocksize += NAME_MAX + 1; ! 1057: if (alist->commonattr & ATTR_CMN_NAMEDATTRLIST) attrblocksize += 0; /* XXX PPD */ ! 1058: if (alist->volattr & ATTR_VOL_MOUNTPOINT) attrblocksize += PATH_MAX; ! 1059: if (alist->volattr & ATTR_VOL_NAME) attrblocksize += NAME_MAX + 1; ! 1060: if (alist->fileattr & ATTR_FILE_FORKLIST) attrblocksize += 0; /* XXX PPD */ ! 1061: ! 1062: attrbufsize = MIN(ap->a_uio->uio_resid, attrblocksize); ! 1063: DBG_VOP(("hfs_getattrlist: allocating Ox%X byte buffer (Ox%X + Ox%X) for attributes...\n", ! 1064: attrblocksize, ! 1065: fixedblocksize, ! 1066: attrblocksize - fixedblocksize)); ! 1067: MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK); ! 1068: attrptr = attrbufptr; ! 1069: *((u_long *)attrptr) = 0; /* Set buffer length in case of errors */ ! 1070: ++((u_long *)attrptr); /* Reserve space for length field */ ! 1071: varptr = ((char *)attrptr) + fixedblocksize; /* Point to variable-length storage */ ! 1072: DBG_VOP(("hfs_getattrlist: attrptr = 0x%08X, varptr = 0x%08X...\n", (u_int)attrptr, (u_int)varptr)); ! 1073: ! 1074: PackAttributeBlock(alist, vp, catInfoPtr, &attrptr, &varptr); ! 1075: *((u_long *)attrbufptr) = (varptr - attrbufptr); /* Store length of fixed + var block */ ! 1076: attrbufsize = MIN(attrbufsize, varptr - attrbufptr); /* Don't copy out more data than was generated */ ! 1077: DBG_VOP(("hfs_getattrlist: copying Ox%X bytes to user address 0x%08X.\n", attrbufsize, (u_int)ap->a_uio->uio_iov->iov_base)); ! 1078: error = uiomove((caddr_t)attrbufptr, attrbufsize, ap->a_uio); ! 1079: if (error != E_NONE) { ! 1080: DBG_ERR(("hfs_getattrlist: error %d on uiomove.\n", error)); ! 1081: }; ! 1082: ! 1083: FREE(attrbufptr, M_TEMP); ! 1084: ! 1085: DBG_VOP_LOCKS_TEST(error); ! 1086: return error; ! 1087: } ! 1088: ! 1089: ! 1090: ! 1091: /* This is a special permission-checking routine that tests for "write" access without ! 1092: regard for the UF_IMMUTABLE or SF_IMMUTABLE bits in the flags. hfs_setattrlist cannot ! 1093: use VOP_ACCESS for this check so this is a derivative of that code that does this check. ! 1094: */ ! 1095: static int hfs_writepermission(struct vnode *vp, struct ucred *cred, struct proc *p) { ! 1096: struct hfsnode *hp = VTOH(vp); ! 1097: int i; ! 1098: register gid_t *gp; ! 1099: ! 1100: /* Start by checking for root */ ! 1101: if (suser(cred, &p->p_acflag) == 0) return 0; ! 1102: ! 1103: /* Check the owner: */ ! 1104: if (cred->cr_uid == hp->h_meta->h_uid) { ! 1105: return (hp->h_meta->h_mode & S_IWUSR) ? 0 : EACCES; ! 1106: }; ! 1107: ! 1108: /* Otherwise, check the groups: */ ! 1109: for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) { ! 1110: if (hp->h_meta->h_gid == *gp) { ! 1111: return (hp->h_meta->h_mode & S_IWGRP) ? 0 : EACCES; ! 1112: }; ! 1113: }; ! 1114: ! 1115: /* Otherwise, check everyone else. */ ! 1116: return (hp->h_meta->h_mode & S_IWOTH) ? 0 : EACCES; ! 1117: } ! 1118: ! 1119: ! 1120: ! 1121: /* ! 1122: ! 1123: # ! 1124: #% setattrlist vp L L L ! 1125: # ! 1126: vop_setattrlist { ! 1127: IN struct vnode *vp; ! 1128: IN struct attrlist *alist; ! 1129: INOUT struct uio *uio; ! 1130: IN struct ucred *cred; ! 1131: IN struct proc *p; ! 1132: }; ! 1133: ! 1134: */ ! 1135: ! 1136: static int ! 1137: hfs_setattrlist(ap) ! 1138: struct vop_setattrlist_args /* { ! 1139: struct vnode *a_vp; ! 1140: struct attrlist *a_alist ! 1141: struct uio *a_uio; ! 1142: struct ucred *a_cred; ! 1143: struct proc *a_p; ! 1144: } */ *ap; ! 1145: { ! 1146: struct vnode *vp = ap->a_vp; ! 1147: struct hfsnode *hp = VTOH(vp); ! 1148: struct attrlist *alist = ap->a_alist; ! 1149: struct ucred *cred = ap->a_cred; ! 1150: struct proc *p = ap->a_p; ! 1151: int error; ! 1152: struct hfsCatalogInfo catalogInfo; ! 1153: int attrblocksize; ! 1154: void *attrbufptr = NULL; ! 1155: void *attrptr; ! 1156: void *varptr = NULL; ! 1157: uid_t saved_uid; ! 1158: gid_t saved_gid; ! 1159: mode_t saved_mode; ! 1160: u_long saved_flags; ! 1161: int retval = 0; ! 1162: ! 1163: DBG_FUNC_NAME("setattrlist"); ! 1164: DBG_VOP_LOCKS_DECL(1); ! 1165: ! 1166: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_SAME, VOPDBG_POS); ! 1167: DBG_HFS_NODE_CHECK(ap->a_vp); ! 1168: DBG_VOP(("%s: Common attr:0x%x, buff size Ox%X,\n",funcname, (u_int)alist->commonattr,(u_int)ap->a_uio->uio_resid)); ! 1169: ! 1170: DBG_ASSERT(ap->a_uio->uio_rw == UIO_WRITE); ! 1171: ! 1172: if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || ! 1173: ((alist->commonattr & ~ATTR_CMN_SETMASK) != 0) || ! 1174: ((alist->volattr & ~ATTR_VOL_SETMASK) != 0) || ! 1175: ((alist->dirattr & ~ATTR_DIR_SETMASK) != 0) || ! 1176: ((alist->fileattr & ~ATTR_FILE_SETMASK) != 0) || ! 1177: ((alist->forkattr & ~ATTR_FORK_SETMASK) != 0)) { ! 1178: DBG_ERR(("%s: Bad attrlist\n", funcname)); ! 1179: DBG_VOP_LOCKS_TEST(EINVAL); ! 1180: return EINVAL; ! 1181: }; ! 1182: ! 1183: if ((alist->volattr != 0) && /* Setting volume info */ ! 1184: (((alist->volattr & ATTR_VOL_INFO) == 0) || /* Not explicitly indicating this or ... */ ! 1185: (alist->commonattr & ~ATTR_CMN_VOLSETMASK))) /* ... setting invalid attributes for volume */ ! 1186: { ! 1187: DBG_ERR(("%s: Bad attrlist\n", funcname)); ! 1188: DBG_VOP_LOCKS_TEST(EINVAL); ! 1189: return EINVAL; ! 1190: }; ! 1191: ! 1192: if (VTOVFS(vp)->mnt_flag & MNT_RDONLY) { ! 1193: DBG_VOP_LOCKS_TEST(EROFS); ! 1194: return EROFS; ! 1195: }; ! 1196: ! 1197: /* NOTE: The following isn't ENTIRELY complete: even if you're the superuser ! 1198: you cannot change the flags as long as SF_IMMUTABLE or SF_APPEND is ! 1199: set and securelevel > 0. This is verified in hfs_chflags which gets ! 1200: invoked to do the actual flags field change so this check is sufficient ! 1201: for now. ! 1202: */ ! 1203: if (alist->commonattr & (OWNERSHIP_ONLY_ATTRS)) { ! 1204: /* Check to see if the user owns the object [or is superuser]: */ ! 1205: if (cred->cr_uid != hp->h_meta->h_uid && ! 1206: (retval = suser(cred, &p->p_acflag))) { ! 1207: DBG_VOP_LOCKS_TEST(retval); ! 1208: return retval; ! 1209: }; ! 1210: }; ! 1211: ! 1212: /* For any other attributes, check to see if the user has write access to ! 1213: the object in question [unlike VOP_ACCESS, ignore IMMUTABLE here]: */ ! 1214: ! 1215: if ((((alist->commonattr & ~(OWNERSHIP_ONLY_ATTRS)) != 0) || ! 1216: (alist->volattr != 0) || ! 1217: (alist->dirattr != 0) || ! 1218: (alist->fileattr != 0) || ! 1219: (alist->forkattr != 0)) && ! 1220: ((retval = hfs_writepermission(vp, cred, p)) != 0)) { ! 1221: DBG_VOP_LOCKS_TEST(retval); ! 1222: return retval; ! 1223: }; /* end of if ownership attr */ ! 1224: ! 1225: /* Allocate the buffer now to minimize the time we might be blocked holding the catalog lock */ ! 1226: attrblocksize = ap->a_uio->uio_resid; ! 1227: if (attrblocksize < AttributeBlockSize(alist)) { ! 1228: DBG_ERR(("%s: bad attrblocksize\n", funcname)); ! 1229: DBG_VOP_LOCKS_TEST(EINVAL); ! 1230: return EINVAL; ! 1231: }; ! 1232: ! 1233: MALLOC(attrbufptr, void *, attrblocksize, M_TEMP, M_WAITOK); ! 1234: ! 1235: /* lock catalog b-tree */ ! 1236: error = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p); ! 1237: if (error != E_NONE) { ! 1238: goto FreeBuffer; ! 1239: }; ! 1240: ! 1241: error = hfsLookup(VTOVCB(vp), H_DIRID(hp), H_NAME(hp), -1, 0, &catalogInfo); ! 1242: if (error != E_NONE) { ! 1243: DBG_ERR(("%s: Lookup failed on file '%s'\n", funcname, H_NAME(hp))); ! 1244: goto ErrorExit; ! 1245: }; ! 1246: H_HINT(hp) = catalogInfo.hint; /* Remember the last valid hint */ ! 1247: ! 1248: error = uiomove((caddr_t)attrbufptr, attrblocksize, ap->a_uio); ! 1249: if (error) goto ErrorExit; ! 1250: ! 1251: if ((alist->volattr) && (H_FILEID(hp) != kRootDirID)) { ! 1252: error = EINVAL; ! 1253: goto ErrorExit; ! 1254: }; ! 1255: ! 1256: /* do we have permission to change the dates? */ ! 1257: // if (alist->commonattr & (ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME)) { ! 1258: if (alist->commonattr & (ATTR_CMN_CHGTIME | ATTR_CMN_ACCTIME)) { ! 1259: if (cred->cr_uid != hp->h_meta->h_uid && (error = suser(cred, &p->p_acflag))) { ! 1260: goto ErrorExit; ! 1261: }; ! 1262: }; ! 1263: ! 1264: /* save these in case hfs_chown() or hfs_chmod() fail */ ! 1265: saved_uid = hp->h_meta->h_uid; ! 1266: saved_gid = hp->h_meta->h_gid; ! 1267: saved_mode = hp->h_meta->h_mode; ! 1268: saved_flags = hp->h_meta->h_pflags; ! 1269: ! 1270: attrptr = attrbufptr; ! 1271: UnpackAttributeBlock(alist, vp, &catalogInfo, &attrptr, &varptr); ! 1272: ! 1273: /* if unpacking changed the owner or group then call hfs_chown() */ ! 1274: if (saved_uid != hp->h_meta->h_uid || saved_gid != hp->h_meta->h_gid) { ! 1275: uid_t uid; ! 1276: gid_t gid; ! 1277: ! 1278: uid = hp->h_meta->h_uid; ! 1279: hp->h_meta->h_uid = saved_uid; ! 1280: gid = hp->h_meta->h_gid; ! 1281: hp->h_meta->h_gid = saved_gid; ! 1282: if ((error = hfs_chown(vp, uid, gid, cred, p))) ! 1283: goto ErrorExit; ! 1284: } ! 1285: ! 1286: /* if unpacking changed the mode then call hfs_chmod() */ ! 1287: if (saved_mode != hp->h_meta->h_mode) { ! 1288: mode_t mode; ! 1289: ! 1290: mode = hp->h_meta->h_mode; ! 1291: hp->h_meta->h_mode = saved_mode; ! 1292: if ((error = hfs_chmod(vp, mode, cred, p))) ! 1293: goto ErrorExit; ! 1294: }; ! 1295: ! 1296: /* if unpacking changed the flags then call hfs_chflags */ ! 1297: if (saved_flags != hp->h_meta->h_pflags) { ! 1298: u_long flags; ! 1299: ! 1300: flags = hp->h_meta->h_pflags; ! 1301: hp->h_meta->h_pflags = saved_flags; ! 1302: if ((error = hfs_chflags(vp, flags, cred, p))) ! 1303: goto ErrorExit; ! 1304: }; ! 1305: ! 1306: if (alist->volattr == 0) { ! 1307: error = MacToVFSError( UpdateCatalogNode(HTOVCB(hp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &catalogInfo.nodeData)); ! 1308: } ! 1309: ! 1310: if (alist->volattr & ATTR_VOL_NAME) { ! 1311: ExtendedVCB *vcb = VTOVCB(vp); ! 1312: int namelen = strlen(vcb->vcbVN); ! 1313: ! 1314: error = MoveRenameCatalogNode(vcb, kRootParID, H_NAME(hp), H_HINT(hp), kRootParID, vcb->vcbVN, &H_HINT(hp)); ! 1315: if (error) { ! 1316: VCB_LOCK(vcb); ! 1317: copystr(H_NAME(hp), vcb->vcbVN, sizeof(vcb->vcbVN), NULL); /* Restore the old name in the VCB */ ! 1318: vcb->vcbFlags |= 0xFF00; // Mark the VCB dirty ! 1319: VCB_UNLOCK(vcb); ! 1320: goto ErrorExit; ! 1321: }; ! 1322: ! 1323: if (namelen > hp->h_meta->h_namelen) { ! 1324: if (hp->h_meta->h_nodeflags & IN_LONGNAME) ! 1325: { ! 1326: FREE(H_NAME(hp), M_HFSNODE); ! 1327: MALLOC(H_NAME(hp), char *, namelen+1, M_HFSNODE, M_WAITOK); ! 1328: } ! 1329: else if (namelen > MAXHFSVNODELEN) { ! 1330: MALLOC(H_NAME(hp), char *, namelen+1, M_HFSNODE, M_WAITOK); ! 1331: hp->h_meta->h_nodeflags |= IN_LONGNAME; ! 1332: } ! 1333: }; ! 1334: hp->h_meta->h_namelen = namelen; ! 1335: copystr(vcb->vcbVN, H_NAME(hp), hp->h_meta->h_namelen+1, NULL); ! 1336: hp->h_meta->h_nodeflags |= IN_CHANGE; ! 1337: ! 1338: #if 0 ! 1339: /* if hfs wrapper exists, update its name too */ ! 1340: if (vcb->vcbSigWord == kHFSPlusSigWord && vcb->vcbAlBlSt != 0) { ! 1341: HFSMasterDirectoryBlock *mdb; ! 1342: struct buf *bp = NULL; ! 1343: int size = kMDBSize; /* 512 */ ! 1344: int volnamelen = MIN(sizeof(Str27), namelen); ! 1345: ! 1346: if ( bread(VTOHFS(vp)->hfs_devvp, IOBLKNOFORBLK(kMasterDirectoryBlock, size), ! 1347: IOBYTECCNTFORBLK(kMasterDirectoryBlock, kMDBSize, size), NOCRED, &bp) == 0) { ! 1348: ! 1349: mdb = (HFSMasterDirectoryBlock *)((char *)bp->b_data + IOBYTEOFFSETFORBLK(kMasterDirectoryBlock, size)); ! 1350: if (mdb->drSigWord == kHFSSigWord) { ! 1351: /* Convert the string to MacRoman, ignoring any errors, */ ! 1352: (void) ConvertUTF8ToMacRoman(volnamelen, vcb->vcbVN, mdb->drVN); ! 1353: bawrite(bp); ! 1354: bp = NULL; ! 1355: } ! 1356: } ! 1357: ! 1358: if (bp) brelse(bp); ! 1359: } ! 1360: #endif ! 1361: }; ! 1362: ! 1363: ErrorExit: ! 1364: /* unlock catalog b-tree */ ! 1365: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p); ! 1366: ! 1367: FreeBuffer: ! 1368: if (attrbufptr) FREE(attrbufptr, M_TEMP); ! 1369: ! 1370: DBG_VOP_LOCKS_TEST(error); ! 1371: return error; ! 1372: } ! 1373: ! 1374: /* ! 1375: * Change the mode on a file. ! 1376: * Inode must be locked before calling. ! 1377: */ ! 1378: static int ! 1379: hfs_chmod(vp, mode, cred, p) ! 1380: register struct vnode *vp; ! 1381: register int mode; ! 1382: register struct ucred *cred; ! 1383: struct proc *p; ! 1384: { ! 1385: register struct hfsnode *hp = VTOH(vp); ! 1386: int retval; ! 1387: ! 1388: if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) ! 1389: return E_NONE; ! 1390: ! 1391: if (cred->cr_uid != hp->h_meta->h_uid && ! 1392: (retval = suser(cred, &p->p_acflag))) ! 1393: return (retval); ! 1394: if (cred->cr_uid) { ! 1395: if (vp->v_type != VDIR && (mode & S_ISTXT)) ! 1396: return (EFTYPE); ! 1397: if (!groupmember(hp->h_meta->h_gid, cred) && (mode & ISGID)) ! 1398: return (EPERM); ! 1399: } ! 1400: hp->h_meta->h_mode &= ~ALLPERMS; ! 1401: hp->h_meta->h_mode |= (mode & ALLPERMS); ! 1402: hp->h_meta->h_nodeflags &= ~IN_UNSETACCESS; ! 1403: hp->h_meta->h_nodeflags |= IN_CHANGE; ! 1404: if ((vp->v_flag & VTEXT) && (hp->h_meta->h_mode & S_ISTXT) == 0) ! 1405: (void) vnode_uncache(vp); ! 1406: return (0); ! 1407: } ! 1408: ! 1409: ! 1410: /* ! 1411: * Change the flags on a file or directory. ! 1412: * Inode must be locked before calling. ! 1413: */ ! 1414: static int ! 1415: hfs_chflags(vp, flags, cred, p) ! 1416: register struct vnode *vp; ! 1417: register u_long flags; ! 1418: register struct ucred *cred; ! 1419: struct proc *p; ! 1420: { ! 1421: register struct hfsnode *hp = VTOH(vp); ! 1422: int retval; ! 1423: ! 1424: if (cred->cr_uid != hp->h_meta->h_uid && ! 1425: (retval = suser(cred, &p->p_acflag))) ! 1426: return retval; ! 1427: ! 1428: if (cred->cr_uid == 0) { ! 1429: if ((hp->h_meta->h_pflags & (SF_IMMUTABLE | SF_APPEND)) && ! 1430: securelevel > 0) { ! 1431: return EPERM; ! 1432: }; ! 1433: hp->h_meta->h_pflags = flags; ! 1434: } else { ! 1435: if (hp->h_meta->h_pflags & (SF_IMMUTABLE | SF_APPEND) || ! 1436: (flags & UF_SETTABLE) != flags) { ! 1437: return EPERM; ! 1438: }; ! 1439: hp->h_meta->h_pflags &= SF_SETTABLE; ! 1440: hp->h_meta->h_pflags |= (flags & UF_SETTABLE); ! 1441: } ! 1442: hp->h_meta->h_nodeflags &= ~IN_UNSETACCESS; ! 1443: hp->h_meta->h_nodeflags |= IN_CHANGE; ! 1444: ! 1445: return 0; ! 1446: } ! 1447: ! 1448: ! 1449: /* ! 1450: * Perform chown operation on hfsnode hp; ! 1451: * hfsnode must be locked prior to call. ! 1452: */ ! 1453: static int ! 1454: hfs_chown(vp, uid, gid, cred, p) ! 1455: register struct vnode *vp; ! 1456: uid_t uid; ! 1457: gid_t gid; ! 1458: struct ucred *cred; ! 1459: struct proc *p; ! 1460: { ! 1461: register struct hfsnode *hp = VTOH(vp); ! 1462: uid_t ouid; ! 1463: gid_t ogid; ! 1464: int retval = 0; ! 1465: ! 1466: if (VTOVCB(vp)->vcbSigWord != kHFSPlusSigWord) ! 1467: return EOPNOTSUPP; ! 1468: ! 1469: if (uid == (uid_t)VNOVAL) ! 1470: uid = hp->h_meta->h_uid; ! 1471: if (gid == (gid_t)VNOVAL) ! 1472: gid = hp->h_meta->h_gid; ! 1473: /* ! 1474: * If we don't own the file, are trying to change the owner ! 1475: * of the file, or are not a member of the target group, ! 1476: * the caller must be superuser or the call fails. ! 1477: */ ! 1478: if ((cred->cr_uid != hp->h_meta->h_uid || uid != hp->h_meta->h_uid || ! 1479: (gid != hp->h_meta->h_gid && !groupmember((gid_t)gid, cred))) && ! 1480: (retval = suser(cred, &p->p_acflag))) ! 1481: return (retval); ! 1482: ogid = hp->h_meta->h_gid; ! 1483: ouid = hp->h_meta->h_uid; ! 1484: ! 1485: hp->h_meta->h_gid = gid; ! 1486: hp->h_meta->h_uid = uid; ! 1487: ! 1488: hp->h_meta->h_nodeflags &= ~IN_UNSETACCESS; ! 1489: if (ouid != uid || ogid != gid) ! 1490: hp->h_meta->h_nodeflags |= IN_CHANGE; ! 1491: if (ouid != uid && cred->cr_uid != 0) ! 1492: hp->h_meta->h_mode &= ~ISUID; ! 1493: if (ogid != gid && cred->cr_uid != 0) ! 1494: hp->h_meta->h_mode &= ~ISGID; ! 1495: return (0); ! 1496: } ! 1497: ! 1498: ! 1499: ! 1500: /* ! 1501: # ! 1502: #% exchange fvp L L L ! 1503: #% exchange tvp L L L ! 1504: # ! 1505: vop_exchange { ! 1506: IN struct vnode *fvp; ! 1507: IN struct vnode *tvp; ! 1508: IN struct ucred *cred; ! 1509: IN struct proc *p; ! 1510: }; ! 1511: ! 1512: */ ! 1513: static int ! 1514: hfs_exchange(ap) ! 1515: struct vop_exchange_args /* { ! 1516: struct vnode *a_fvp; ! 1517: struct vnode *a_tvp; ! 1518: struct ucred *a_cred; ! 1519: struct proc *a_p; ! 1520: } */ *ap; ! 1521: { ! 1522: struct hfsnode *fromhp, *tohp; ! 1523: struct hfsmount *hfsmp; ! 1524: // struct hfsCatalogInfo catalogInfo; ! 1525: u_char tmp_name[NAME_MAX+1]; /* 256 bytes! */ ! 1526: ExtendedVCB *vcb; ! 1527: u_int32_t fromFileID; ! 1528: u_int32_t fromParID; ! 1529: u_int32_t tmpLong; ! 1530: Boolean isHFSPlus; ! 1531: int retval = E_NONE; ! 1532: DBG_FUNC_NAME("exchange"); ! 1533: DBG_VOP_LOCKS_DECL(2); ! 1534: DBG_VOP_PRINT_FUNCNAME(); ! 1535: DBG_VOP_PRINT_VNODE_INFO(ap->a_fvp);DBG_VOP_CONT(("\n")); ! 1536: DBG_VOP_PRINT_VNODE_INFO(ap->a_tvp);DBG_VOP_CONT(("\n")); ! 1537: ! 1538: DBG_VOP_LOCKS_INIT(0,ap->a_fvp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); ! 1539: DBG_VOP_LOCKS_INIT(1,ap->a_tvp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); ! 1540: ! 1541: fromhp = VTOH(ap->a_fvp); ! 1542: tohp = VTOH(ap->a_tvp); ! 1543: hfsmp = VTOHFS(ap->a_fvp); ! 1544: vcb = HTOVCB(fromhp); ! 1545: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord); ! 1546: ! 1547: if (ap->a_fvp->v_mount != ap->a_tvp->v_mount) { ! 1548: DBG_VOP_LOCKS_TEST(EXDEV); ! 1549: return EXDEV; ! 1550: } ! 1551: ! 1552: /* Can only exchange file objects */ ! 1553: if (ap->a_fvp->v_type != VREG || ap->a_tvp->v_type != VREG) { ! 1554: DBG_VOP_LOCKS_TEST(EINVAL); ! 1555: return EINVAL; ! 1556: } ! 1557: ! 1558: ! 1559: /* Make sure buffers are written out and trashed */ ! 1560: if ((retval = vinvalbuf(ap->a_fvp, V_SAVE, ap->a_cred, ap->a_p, 0, 0))) ! 1561: goto Err_Exit; ! 1562: ! 1563: if ((retval = vinvalbuf(ap->a_tvp, V_SAVE, ap->a_cred, ap->a_p, 0, 0))) ! 1564: goto Err_Exit; ! 1565: ! 1566: if (VTOH(ap->a_fvp)->h_sibling) { ! 1567: if ((retval = vinvalbuf(VTOH(ap->a_fvp)->h_sibling, V_SAVE, ap->a_cred, ap->a_p, 0, 0))) ! 1568: goto Err_Exit; ! 1569: } ! 1570: ! 1571: if (VTOH(ap->a_tvp)->h_sibling) { ! 1572: if ((retval = vinvalbuf(VTOH(ap->a_tvp)->h_sibling, V_SAVE, ap->a_cred, ap->a_p, 0, 0))) ! 1573: goto Err_Exit; ! 1574: } ! 1575: ! 1576: /* lock catalog b-tree */ ! 1577: retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, ap->a_p); ! 1578: if (retval) goto Err_Exit; ! 1579: ! 1580: /* lock extents b-tree iff there are overflow extents */ ! 1581: /* XXX SER ExchangeFileIDs() always tries to delete the virtual extent id for exchanging files ! 1582: so we neeed the tree to be always locked. ! 1583: */ ! 1584: retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, ap->a_p); ! 1585: if (retval) goto Err_Exit_Relse; ! 1586: ! 1587: /* Do the exchange */ ! 1588: retval = MacToVFSError( ExchangeFileIDs(vcb, H_NAME(fromhp), H_NAME(tohp), H_DIRID(fromhp), H_DIRID(tohp), H_HINT(fromhp), H_HINT(tohp) )); ! 1589: ! 1590: (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, ap->a_p); ! 1591: ! 1592: if (retval != E_NONE) { ! 1593: DBG_ERR(("/tError trying to exchange: %d\n", retval)); ! 1594: goto Err_Exit_Relse; ! 1595: } ! 1596: ! 1597: ! 1598: /* Now exchange fileID, parID, name for the vnode itself */ ! 1599: fromFileID = H_FILEID(fromhp); ! 1600: fromParID = H_DIRID(fromhp); ! 1601: copystr(H_NAME(fromhp), (char*) tmp_name, strlen(H_NAME(fromhp))+1, NULL); ! 1602: hfs_chid(fromhp, H_FILEID(tohp), H_DIRID(tohp), H_NAME(tohp)); ! 1603: hfs_chid(tohp, fromFileID, fromParID, (char*) tmp_name); ! 1604: ! 1605: /* copy rest */ ! 1606: tmpLong = HTOFCB(fromhp)->fcbFlags; ! 1607: HTOFCB(fromhp)->fcbFlags = HTOFCB(tohp)->fcbFlags; ! 1608: HTOFCB(tohp)->fcbFlags = tmpLong; ! 1609: ! 1610: tmpLong = fromhp->h_meta->h_crtime; ! 1611: fromhp->h_meta->h_crtime = tohp->h_meta->h_crtime; ! 1612: tohp->h_meta->h_crtime = tmpLong; ! 1613: ! 1614: tmpLong = fromhp->h_meta->h_butime; ! 1615: fromhp->h_meta->h_butime = tohp->h_meta->h_butime; ! 1616: tohp->h_meta->h_butime = tmpLong; ! 1617: ! 1618: tmpLong = fromhp->h_meta->h_atime; ! 1619: fromhp->h_meta->h_atime = tohp->h_meta->h_atime; ! 1620: tohp->h_meta->h_atime = tmpLong; ! 1621: ! 1622: tmpLong = fromhp->h_meta->h_ctime; ! 1623: fromhp->h_meta->h_ctime = tohp->h_meta->h_ctime; ! 1624: tohp->h_meta->h_ctime = tmpLong; ! 1625: ! 1626: ! 1627: tmpLong = fromhp->h_meta->h_gid; ! 1628: fromhp->h_meta->h_gid = tohp->h_meta->h_gid; ! 1629: tohp->h_meta->h_gid = tmpLong; ! 1630: ! 1631: tmpLong = fromhp->h_meta->h_uid; ! 1632: fromhp->h_meta->h_uid = tohp->h_meta->h_uid; ! 1633: tohp->h_meta->h_uid = tmpLong; ! 1634: ! 1635: tmpLong = fromhp->h_meta->h_pflags; ! 1636: fromhp->h_meta->h_pflags = tohp->h_meta->h_pflags; ! 1637: tohp->h_meta->h_pflags = tmpLong; ! 1638: ! 1639: tmpLong = fromhp->h_meta->h_mode; ! 1640: fromhp->h_meta->h_mode = tohp->h_meta->h_mode; ! 1641: tohp->h_meta->h_mode = tmpLong; ! 1642: ! 1643: tmpLong = fromhp->h_meta->h_rdev; ! 1644: fromhp->h_meta->h_rdev = tohp->h_meta->h_rdev; ! 1645: tohp->h_meta->h_rdev = tmpLong; ! 1646: ! 1647: tmpLong = fromhp->h_size; ! 1648: fromhp->h_size = tohp->h_size; ! 1649: tohp->h_size = tmpLong; ! 1650: ! 1651: ! 1652: ! 1653: Err_Exit_Relse:; ! 1654: /* unlock catalog b-tree */ ! 1655: (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, ap->a_p); ! 1656: ! 1657: Err_Exit:; ! 1658: ! 1659: DBG_VOP_LOCKS_TEST(retval); ! 1660: return (retval); ! 1661: } ! 1662: ! 1663: ! 1664: /* ! 1665: * Change a vnode's file id, parent id and name ! 1666: * ! 1667: * Assumes the vnode is locked and is of type VREG ! 1668: */ ! 1669: static void ! 1670: hfs_chid(struct hfsnode *hp, u_int32_t fid, u_int32_t pid, char* name) ! 1671: { ! 1672: struct hfsnode *tp; ! 1673: int namelen = strlen(name); ! 1674: ! 1675: DBG_ASSERT(HTOV(hp)->v_type == VREG); ! 1676: ! 1677: hfs_vhashrem(hp); ! 1678: H_HINT(hp) = 0; ! 1679: H_FILEID(hp) = fid; /* change h_nodeID */ ! 1680: hp->h_xfcb->fcb_fcb.fcbFlNm = fid; /* and this one too */ ! 1681: H_DIRID(hp) = pid; ! 1682: if (namelen > hp->h_meta->h_namelen) { ! 1683: if (hp->h_meta->h_nodeflags & IN_LONGNAME) ! 1684: { ! 1685: FREE(H_NAME(hp), M_HFSNODE); ! 1686: MALLOC(H_NAME(hp), char *, namelen+1, M_HFSNODE, M_WAITOK); ! 1687: } ! 1688: else if (namelen > MAXHFSVNODELEN) { ! 1689: MALLOC(H_NAME(hp), char *, namelen+1, M_HFSNODE, M_WAITOK); ! 1690: hp->h_meta->h_nodeflags |= IN_LONGNAME; ! 1691: } ! 1692: }; ! 1693: hp->h_meta->h_namelen = namelen; ! 1694: copystr(name, H_NAME(hp), hp->h_meta->h_namelen+1, NULL); ! 1695: hfs_vhashinslocked(hp); ! 1696: ! 1697: /* Change complex node also */ ! 1698: tp = VTOH(hp->h_relative); ! 1699: if (tp) { ! 1700: cache_purge(HTOV(tp)); ! 1701: ! 1702: hfs_vhashrem(tp); ! 1703: H_HINT(tp) = 0; ! 1704: H_FILEID(tp) = fid; ! 1705: tp->h_xfcb->fcb_fcb.fcbFlNm = fid; ! 1706: hfs_vhashinslocked(tp); ! 1707: } ! 1708: ! 1709: /* Now change sibling */ ! 1710: tp = VTOH(hp->h_sibling); ! 1711: if (tp) { ! 1712: hfs_vhashrem(tp); ! 1713: H_HINT(tp) = 0; ! 1714: H_FILEID(tp) = fid; ! 1715: tp->h_xfcb->fcb_fcb.fcbFlNm = fid; ! 1716: hfs_vhashinslocked(tp); ! 1717: } ! 1718: } ! 1719: ! 1720: ! 1721: /* ! 1722: ! 1723: #% fsync vp L L L ! 1724: # ! 1725: vop_fsync { ! 1726: IN struct vnode *vp; ! 1727: IN struct ucred *cred; ! 1728: IN int waitfor; ! 1729: IN struct proc *p; ! 1730: ! 1731: */ ! 1732: ! 1733: ! 1734: static int ! 1735: hfs_fsync(ap) ! 1736: struct vop_fsync_args /* { ! 1737: struct vnode *a_vp; ! 1738: struct ucred *a_cred; ! 1739: int a_waitfor; ! 1740: struct proc *a_p; ! 1741: } */ *ap; ! 1742: { ! 1743: struct vnode *vp = ap->a_vp ; ! 1744: struct hfsnode *hp; ! 1745: int retval = 0; ! 1746: register struct buf *bp; ! 1747: struct timeval tv; ! 1748: struct buf *nbp; ! 1749: int s; ! 1750: ! 1751: DBG_FUNC_NAME("fsync"); ! 1752: DBG_VOP_LOCKS_DECL(1); ! 1753: DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT((" ")); ! 1754: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 1755: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_ZERO); ! 1756: DBG_HFS_NODE_CHECK(ap->a_vp); ! 1757: ! 1758: #if DIAGNOSTIC ! 1759: DBG_ASSERT(*((int*)&vp->v_interlock) == 0); ! 1760: #endif ! 1761: ! 1762: if (vp->v_type == VCPLX) { ! 1763: /* Ignore complex nodes; there's no data associated with them. */ ! 1764: DBG_ASSERT(vp->v_dirtyblkhd.lh_first == NULL); ! 1765: DBG_VOP_LOCKS_TEST(E_NONE); ! 1766: return E_NONE; ! 1767: }; ! 1768: ! 1769: ! 1770: /* ! 1771: * Flush all dirty buffers associated with a vnode. ! 1772: */ ! 1773: loop: ! 1774: hp = VTOH(vp); ! 1775: s = splbio(); ! 1776: for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) { ! 1777: nbp = bp->b_vnbufs.le_next; ! 1778: if ((bp->b_flags & B_BUSY)) ! 1779: continue; ! 1780: if ((bp->b_flags & B_DELWRI) == 0) ! 1781: panic("hfs_fsync: not dirty"); ! 1782: bremfree(bp); ! 1783: bp->b_flags |= B_BUSY; ! 1784: bp->b_flags &= ~B_LOCKED; /* Clear flag, should only be set on meta files */ ! 1785: splx(s); ! 1786: /* ! 1787: * Wait for I/O associated with indirect blocks to complete, ! 1788: * since there is no way to quickly wait for them below. ! 1789: */ ! 1790: DBG_VOP(("\t\t\tFlushing out phys block %d == log block %d\n", bp->b_blkno, bp->b_lblkno)); ! 1791: if (bp->b_vp == vp || ap->a_waitfor == MNT_NOWAIT) ! 1792: (void) bawrite(bp); ! 1793: else ! 1794: (void) bwrite(bp); ! 1795: goto loop; ! 1796: } ! 1797: ! 1798: if (ap->a_waitfor == MNT_WAIT) { ! 1799: while (vp->v_numoutput) { ! 1800: vp->v_flag |= VBWAIT; ! 1801: tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "hfs_fsync", 0); ! 1802: } ! 1803: ! 1804: /* I have seen this happen for swapfile. So it is safer to ! 1805: * check for dirty buffers again. --Umesh ! 1806: */ ! 1807: if (vp->v_dirtyblkhd.lh_first) { ! 1808: vprint("hfs_fsync: dirty", vp); ! 1809: splx(s); ! 1810: goto loop; ! 1811: } ! 1812: } ! 1813: splx(s); ! 1814: ! 1815: #if DIAGNOSTIC ! 1816: DBG_ASSERT(*((int*)&vp->v_interlock) == 0); ! 1817: #endif ! 1818: ! 1819: tv = time; ! 1820: hp->h_lastfsync = tv.tv_sec; ! 1821: if (H_FORKTYPE(hp) != kSysFile) { ! 1822: retval = VOP_UPDATE(ap->a_vp, &tv, &tv, ap->a_waitfor == MNT_WAIT); ! 1823: ! 1824: if (retval != E_NONE) { ! 1825: DBG_ERR(("%s: FLUSH FAILED: %s\n", funcname, H_NAME(hp))); ! 1826: } ! 1827: } ! 1828: else ! 1829: hp->h_meta->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); ! 1830: ! 1831: if (ap->a_waitfor == MNT_WAIT) { ! 1832: DBG_ASSERT(vp->v_dirtyblkhd.lh_first == NULL); ! 1833: }; ! 1834: DBG_VOP_LOCKS_TEST(retval); ! 1835: DBG_ASSERT(*((int*)&vp->v_interlock) == 0); ! 1836: return (retval); ! 1837: } ! 1838: ! 1839: ! 1840: ! 1841: /* ! 1842: ! 1843: #% remove dvp L U U ! 1844: #% remove vp L U U ! 1845: # ! 1846: vop_remove { ! 1847: IN WILLRELE struct vnode *dvp; ! 1848: IN WILLRELE struct vnode *vp; ! 1849: IN struct componentname *cnp; ! 1850: ! 1851: */ ! 1852: ! 1853: int ! 1854: hfs_remove(ap) ! 1855: struct vop_remove_args /* { ! 1856: struct vnode *a_dvp; ! 1857: struct vnode *a_vp; ! 1858: struct componentname *a_cnp; ! 1859: } */ *ap; ! 1860: { ! 1861: struct vnode *vp = ap->a_vp; ! 1862: struct vnode *dvp = ap->a_dvp; ! 1863: struct vnode *ttp,*tp = NULL; ! 1864: struct hfsnode *hp = VTOH(ap->a_vp); ! 1865: struct hfsmount *hfsmp = HTOHFS(hp); ! 1866: struct proc *p = CURRENT_PROC; ! 1867: struct timeval tv; ! 1868: int retval; ! 1869: struct vnode *sibling_vp; ! 1870: DBG_FUNC_NAME("remove"); ! 1871: ! 1872: DBG_VOP_LOCKS_DECL(2); ! 1873: DBG_VOP_PRINT_FUNCNAME(); ! 1874: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); ! 1875: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); ! 1876: ! 1877: /* see if they really meant to call VOP_RMDIR */ ! 1878: if (vp->v_type == VDIR) ! 1879: return VOP_RMDIR(dvp, vp, ap->a_cnp); ! 1880: ! 1881: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 1882: DBG_VOP_LOCKS_INIT(1,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 1883: ! 1884: if ((hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) || ! 1885: (VTOH(dvp)->h_meta->h_pflags & APPEND)) { ! 1886: retval = EPERM; ! 1887: goto out; ! 1888: } ! 1889: ! 1890: /* HFS does not have unlinking, do we cannot delete a file that is inuse */ ! 1891: DBG_VOP(("\tusecount = %d", vp->v_usecount)); ! 1892: if (VTOH(vp)->h_sibling) { ! 1893: DBG_VOP_CONT((", sibling usecount = %d\n", VTOH(vp)->h_sibling->v_usecount)); ! 1894: } ! 1895: else { ! 1896: DBG_VOP_CONT(("\n")); ! 1897: } ! 1898: if (vp->v_usecount > 1) { ! 1899: retval = EBUSY; ! 1900: goto out; ! 1901: } ! 1902: /* Check other siblings for in use also */ ! 1903: tp = vp; ! 1904: /* XXX SER Process all siblings here */ ! 1905: /* XXX SER MUST BE CHANGED BY MACOS X */ ! 1906: /* This unlocks the vnode!!!! Because vnode_uncache does the same ! 1907: * so it depends on no context switches. ! 1908: * See the comment in vnode_uncache() ! 1909: */ ! 1910: /* Uncache everything */ ! 1911: sibling_loop: ! 1912: sibling_vp = VTOH(tp)->h_sibling; /* Note - this is a local copy for good reason! */ ! 1913: if (sibling_vp) { ! 1914: VOP_UNLOCK(vp, 0, p); ! 1915: if (vget(sibling_vp, LK_EXCLUSIVE | LK_RETRY, p)) { ! 1916: /* Couldn't get the sibling - it might have gone away. ! 1917: Clean up to try again from scratch */ ! 1918: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1919: goto sibling_loop; ! 1920: }; ! 1921: (void) vnode_uncache(sibling_vp); ! 1922: vput(sibling_vp); ! 1923: vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); ! 1924: }; ! 1925: ! 1926: while (VTOH(tp)->h_sibling && (VTOH(tp)->h_sibling != vp)) { ! 1927: simple_lock(&tp->v_interlock); ! 1928: if (VTOH(tp)->h_sibling->v_usecount > 0) { ! 1929: retval = EBUSY; ! 1930: simple_unlock(&tp->v_interlock); ! 1931: goto out; ! 1932: } ! 1933: ttp = tp; ! 1934: tp = VTOH(tp)->h_sibling; ! 1935: simple_unlock(&ttp->v_interlock); ! 1936: } ! 1937: ! 1938: /* Flush out any catalog changes */ ! 1939: /* XXX SER: This is a hack, becasue hfsDelete reads the data from the disk ! 1940: * and not from memory which is more correct ! 1941: */ ! 1942: if ((hp->h_meta->h_nodeflags & IN_MODIFIED) || (HTOFCB(hp)->fcbFlags & fcbModifiedMask)) ! 1943: { ! 1944: DBG_ASSERT((hp->h_meta->h_nodeflags & IN_MODIFIED) != 0); ! 1945: tv = time; ! 1946: VOP_UPDATE(vp, &tv, &tv, 0); ! 1947: } ! 1948: ! 1949: /* lock catalog b-tree */ ! 1950: retval = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p); ! 1951: if (retval != E_NONE) { ! 1952: retval = EBUSY; ! 1953: goto out; ! 1954: } ! 1955: ! 1956: /* lock extents b-tree (also protects volume bitmap) */ ! 1957: retval = hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p); ! 1958: if (retval != E_NONE) { ! 1959: retval = EBUSY; ! 1960: goto out2; /* unlock catalog b-tree on the way out */ ! 1961: } ! 1962: ! 1963: /* remove the entry from the namei cache: */ ! 1964: cache_purge(VTOH(vp)->h_relative); ! 1965: ! 1966: /* remove entry from catalog and free any blocks used */ ! 1967: retval = hfsDelete (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), TRUE, H_HINT(hp)); ! 1968: ! 1969: hp->h_meta->h_mode = 0; /* Makes the node go away...see inactive */ ! 1970: tp = VTOH(vp)->h_sibling; /* Remember any siblings, to inactivate later */ ! 1971: ! 1972: (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_RELEASE, p); ! 1973: out2: ! 1974: (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p); ! 1975: ! 1976: out:; ! 1977: ! 1978: if (! retval) ! 1979: VTOH(dvp)->h_meta->h_nodeflags |= IN_CHANGE | IN_UPDATE; ! 1980: ! 1981: if (dvp == vp) { ! 1982: VRELE(vp); ! 1983: } else { ! 1984: VPUT(vp); ! 1985: }; ! 1986: ! 1987: /* Before leaving, remove any siblings also */ ! 1988: /* Note: vp and all its values are gone, so do not use */ ! 1989: if ((! retval) && (tp != NULL)) { ! 1990: if (! vget (tp, LK_EXCLUSIVE, p)) { ! 1991: VTOH(tp)->h_meta->h_mode = 0; /* Makes the node go away...see inactive */ ! 1992: VPUT(tp); ! 1993: } ! 1994: } ! 1995: ! 1996: VPUT(dvp); ! 1997: DBG_VOP_LOCKS_TEST(retval); ! 1998: return (retval); ! 1999: } ! 2000: ! 2001: ! 2002: #if 0 /* Now stubbed out in the vnode ops table with err_mknod */ ! 2003: /* ! 2004: * link vnode call ! 2005: */ ! 2006: /* ! 2007: * HFS filesystems don't know what links are. But since we already called ! 2008: * lookup() with create and lockparent, the parent is locked so we ! 2009: * have to free it before we return the retval. ! 2010: #% link vp U U U ! 2011: #% link targetPar_vp L U U ! 2012: # ! 2013: vop_link { ! 2014: IN WILLRELE struct vnode *vp; ! 2015: IN struct vnode *targetPar_vp; ! 2016: IN struct componentname *cnp; ! 2017: ! 2018: */ ! 2019: static int ! 2020: hfs_link(ap) ! 2021: struct vop_link_args /* { ! 2022: struct vnode *a_vp; ! 2023: struct vnode *a_tdvp; ! 2024: struct componentname *a_cnp; ! 2025: } */ *ap; ! 2026: { ! 2027: DBG_FUNC_NAME("link"); ! 2028: DBG_VOP_LOCKS_DECL(1); ! 2029: DBG_VOP_PRINT_FUNCNAME(); ! 2030: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); ! 2031: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); ! 2032: ! 2033: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 2034: DBG_VOP_LOCKS_INIT(1,ap->a_tdvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 2035: ! 2036: VOP_UNLOCK(ap->a_vp, 0, ap->a_cnp->cn_proc); ! 2037: ! 2038: VOP_ABORTOP(ap->a_tdvp, ap->a_cnp); ! 2039: VPUT(ap->a_tdvp); ! 2040: ! 2041: DBG_VOP_LOCKS_TEST(EOPNOTSUPP); ! 2042: return (EOPNOTSUPP); ! 2043: } ! 2044: #endif ! 2045: ! 2046: /* ! 2047: ! 2048: #% rename sourcePar_vp U U U ! 2049: #% rename source_vp U U U ! 2050: #% rename targetPar_vp L U U ! 2051: #% rename target_vp X U U ! 2052: # ! 2053: vop_rename { ! 2054: IN WILLRELE struct vnode *sourcePar_vp; ! 2055: IN WILLRELE struct vnode *source_vp; ! 2056: IN struct componentname *source_cnp; ! 2057: IN WILLRELE struct vnode *targetPar_vp; ! 2058: IN WILLRELE struct vnode *target_vp; ! 2059: IN struct componentname *target_cnp; ! 2060: ! 2061: ! 2062: */ ! 2063: /* ! 2064: * On entry: ! 2065: * source's parent directory is unlocked ! 2066: * source file or directory is unlocked ! 2067: * destination's parent directory is locked ! 2068: * destination file or directory is locked if it exists ! 2069: * ! 2070: * On exit: ! 2071: * all denodes should be released ! 2072: * ! 2073: */ ! 2074: ! 2075: static int ! 2076: hfs_rename(ap) ! 2077: struct vop_rename_args /* { ! 2078: struct vnode *a_fdvp; ! 2079: struct vnode *a_fvp; ! 2080: struct componentname *a_fcnp; ! 2081: struct vnode *a_tdvp; ! 2082: struct vnode *a_tvp; ! 2083: struct componentname *a_tcnp; ! 2084: } */ *ap; ! 2085: { ! 2086: struct vnode *target_vp = ap->a_tvp; ! 2087: struct vnode *targetPar_vp = ap->a_tdvp; ! 2088: struct vnode *source_vp = ap->a_fvp; ! 2089: struct vnode *sourcePar_vp = ap->a_fdvp; ! 2090: struct vnode *tp; ! 2091: struct componentname *target_cnp = ap->a_tcnp; ! 2092: struct componentname *source_cnp = ap->a_fcnp; ! 2093: struct proc *p = source_cnp->cn_proc; ! 2094: struct hfsnode *target_hp, *targetPar_hp, *source_hp, *sourcePar_hp; ! 2095: u_short doingdirectory = 0, oldparent = 0, newparent = 0; ! 2096: int retval = 0; ! 2097: struct timeval tv; ! 2098: struct hfsCatalogInfo catInfo; ! 2099: int targetnamelen; ! 2100: DBG_VOP_LOCKS_DECL(4); ! 2101: ! 2102: DBG_FUNC_NAME("rename");DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\n")); ! 2103: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("Source:\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_fvp);DBG_VOP_CONT(("\n")); ! 2104: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("SourcePar: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_fdvp);DBG_VOP_CONT(("\n")); ! 2105: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("Target:\t"));DBG_VOP_PRINT_VNODE_INFO(ap->a_tvp);DBG_VOP_CONT(("\n")); ! 2106: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("TargetPar: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_tdvp);DBG_VOP_CONT(("\n")); ! 2107: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("SourceName:\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_fcnp);DBG_VOP_CONT(("\n")); ! 2108: DBG_VOP_CONT(("\t"));DBG_VOP_CONT(("TargetName:\t"));DBG_VOP_PRINT_CPN_INFO(ap->a_tcnp);DBG_VOP_CONT(("\n")); ! 2109: DBG_VOP_LOCKS_INIT(0,ap->a_fdvp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 2110: DBG_VOP_LOCKS_INIT(1,ap->a_fvp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 2111: DBG_VOP_LOCKS_INIT(2,ap->a_tdvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 2112: DBG_VOP_LOCKS_INIT(3,ap->a_tvp, VOPDBG_LOCKNOTNIL, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 2113: WRITE_CK(ap->a_fdvp, funcname); ! 2114: DBG_HFS_NODE_CHECK(ap->a_fdvp); ! 2115: DBG_HFS_NODE_CHECK(ap->a_tdvp); ! 2116: ! 2117: #if DIAGNOSTIC ! 2118: if ((target_cnp->cn_flags & HASBUF) == 0 || ! 2119: (source_cnp->cn_flags & HASBUF) == 0) ! 2120: panic("hfs_rename: no name"); ! 2121: #endif ! 2122: ! 2123: ASSERT((ap->a_fdvp->v_type == VDIR) && (ap->a_tdvp->v_type == VDIR)); ! 2124: target_hp = targetPar_hp = source_hp = sourcePar_hp = 0; ! 2125: targetnamelen = target_cnp->cn_namelen; ! 2126: ! 2127: /* ! 2128: * Check for cross-device rename. ! 2129: */ ! 2130: if ((source_vp->v_mount != targetPar_vp->v_mount) || ! 2131: (target_vp && (source_vp->v_mount != target_vp->v_mount))) { ! 2132: retval = EXDEV; ! 2133: goto abortit; ! 2134: } ! 2135: ! 2136: /* ! 2137: * Check for access permissions ! 2138: */ ! 2139: if (target_vp && ((VTOH(target_vp)->h_meta->h_pflags & (IMMUTABLE | APPEND)) || ! 2140: (VTOH(targetPar_vp)->h_meta->h_pflags & APPEND))) { ! 2141: retval = EPERM; ! 2142: goto abortit; ! 2143: } ! 2144: ! 2145: if ((retval = vn_lock(source_vp, LK_EXCLUSIVE, p))) ! 2146: goto abortit; ! 2147: ! 2148: sourcePar_hp = VTOH(sourcePar_vp); ! 2149: source_hp = VTOH(source_vp); ! 2150: oldparent = H_FILEID(sourcePar_hp); ! 2151: if ((source_hp->h_meta->h_pflags & (IMMUTABLE | APPEND)) || (sourcePar_hp->h_meta->h_pflags & APPEND)) { ! 2152: VOP_UNLOCK(source_vp, 0, p); ! 2153: retval = EPERM; ! 2154: goto abortit; ! 2155: } ! 2156: ! 2157: /* ! 2158: * Be sure we are not renaming ".", "..", or an alias of ".". This ! 2159: * leads to a crippled directory tree. It's pretty tough to do a ! 2160: * "ls" or "pwd" with the "." directory entry missing, and "cd .." ! 2161: * doesn't work if the ".." entry is missing. ! 2162: */ ! 2163: if ((source_hp->h_meta->h_mode & IFMT) == IFDIR) { ! 2164: if ((source_cnp->cn_namelen == 1 && source_cnp->cn_nameptr[0] == '.') ! 2165: || sourcePar_hp == source_hp ! 2166: || (source_cnp->cn_flags&ISDOTDOT) ! 2167: || (source_hp->h_meta->h_nodeflags & IN_RENAME)) { ! 2168: VOP_UNLOCK(source_vp, 0, p); ! 2169: retval = EINVAL; ! 2170: goto abortit; ! 2171: } ! 2172: source_hp->h_meta->h_nodeflags |= IN_RENAME; ! 2173: doingdirectory = TRUE; ! 2174: } ! 2175: ! 2176: // Transit between abort and bad ! 2177: ! 2178: targetPar_hp = VTOH(targetPar_vp); ! 2179: target_hp = target_vp ? VTOH(target_vp) : NULL; ! 2180: newparent = H_FILEID(targetPar_hp); ! 2181: ! 2182: retval = VOP_ACCESS(source_vp, VWRITE, target_cnp->cn_cred, target_cnp->cn_proc); ! 2183: if (doingdirectory && (newparent != oldparent)) { ! 2184: if (retval) /* write access check above */ ! 2185: goto bad; ! 2186: } ! 2187: ! 2188: /* ! 2189: * If the destination exists, then be sure its type (file or dir) ! 2190: * matches that of the source. And, if it is a directory make sure ! 2191: * it is empty. Then delete the destination. ! 2192: */ ! 2193: if (target_vp) { ! 2194: if (target_hp->h_dev != targetPar_hp->h_dev || target_hp->h_dev != source_hp->h_dev) ! 2195: panic("rename: EXDEV"); ! 2196: ! 2197: /* ! 2198: * If the parent directory is "sticky", then the user must ! 2199: * own the parent directory, or the destination of the rename, ! 2200: * otherwise the destination may not be changed (except by ! 2201: * root). This implements append-only directories. ! 2202: */ ! 2203: if ((targetPar_hp->h_meta->h_mode & S_ISTXT) && target_cnp->cn_cred->cr_uid != 0 && ! 2204: target_cnp->cn_cred->cr_uid != targetPar_hp->h_meta->h_uid && ! 2205: target_hp->h_meta->h_uid != target_cnp->cn_cred->cr_uid) { ! 2206: retval = EPERM; ! 2207: goto bad; ! 2208: } ! 2209: ! 2210: /* ! 2211: * VOP_REMOVE will vput targetPar_vp so we better bump ! 2212: * its ref count and relockit, always set target_vp to ! 2213: * NULL afterwards to indicate that were done with it. ! 2214: */ ! 2215: VREF(targetPar_vp); ! 2216: if (target_vp->v_type == VREG) cache_purge(VTOH(target_vp)->h_relative); ! 2217: retval = VOP_REMOVE(targetPar_vp, target_vp, target_cnp); ! 2218: (void) vn_lock(targetPar_vp, LK_EXCLUSIVE, p); ! 2219: ! 2220: target_vp = NULL; ! 2221: target_hp = NULL; ! 2222: ! 2223: if (retval) goto bad; ! 2224: ! 2225: } else { ! 2226: if (targetPar_hp->h_dev != source_hp->h_dev) ! 2227: panic("rename: EXDEV"); ! 2228: }; ! 2229: ! 2230: ! 2231: if (newparent != oldparent) ! 2232: vn_lock(sourcePar_vp, LK_EXCLUSIVE | LK_RETRY, p); ! 2233: ! 2234: /* lock catalog b-tree */ ! 2235: retval = hfs_metafilelocking(VTOHFS(source_vp), kHFSCatalogFileID, LK_EXCLUSIVE, p); ! 2236: if (retval) goto badcataloglock; ! 2237: ! 2238: /* remove the existing entry from the namei cache: */ ! 2239: if (source_vp->v_type == VREG) cache_purge(VTOH(source_vp)->h_relative); ! 2240: ! 2241: retval = hfsMoveRename( HTOVCB(source_hp), H_DIRID(source_hp), H_NAME(source_hp), ! 2242: H_FILEID(VTOH(targetPar_vp)), target_cnp->cn_nameptr, &H_HINT(source_hp)); ! 2243: ! 2244: if (retval == 0) { ! 2245: /* Look up the catalog entry just renamed since it might have been auto-decomposed */ ! 2246: catInfo.hint = H_HINT(source_hp); ! 2247: retval = hfsLookup(HTOVCB(source_hp), H_FILEID(VTOH(targetPar_vp)), target_cnp->cn_nameptr, -1, 0, &catInfo); ! 2248: targetnamelen = strlen(catInfo.spec.name); ! 2249: } ! 2250: ! 2251: /* unlock catalog b-tree */ ! 2252: (void) hfs_metafilelocking(VTOHFS(source_vp), kHFSCatalogFileID, LK_RELEASE, p); ! 2253: ! 2254: if (newparent != oldparent) ! 2255: VOP_UNLOCK(sourcePar_vp, 0, p); ! 2256: ! 2257: if (retval) goto bad; ! 2258: ! 2259: H_DIRID(source_hp) = H_FILEID(VTOH(targetPar_vp)); ! 2260: ! 2261: if (targetnamelen > source_hp->h_meta->h_namelen) { ! 2262: if (source_hp->h_meta->h_nodeflags & IN_LONGNAME) ! 2263: { ! 2264: FREE(H_NAME(source_hp), M_HFSNODE); ! 2265: MALLOC(H_NAME(source_hp), char *, targetnamelen+1, M_HFSNODE, M_WAITOK); ! 2266: } ! 2267: else if (targetnamelen > MAXHFSVNODELEN) { ! 2268: MALLOC(H_NAME(source_hp), char *, targetnamelen+1, M_HFSNODE, M_WAITOK); ! 2269: source_hp->h_meta->h_nodeflags |= IN_LONGNAME; ! 2270: } ! 2271: }; ! 2272: ! 2273: source_hp->h_meta->h_namelen = targetnamelen; ! 2274: copystr(catInfo.spec.name, H_NAME(source_hp), targetnamelen+1, NULL); ! 2275: source_hp->h_meta->h_nodeflags &= ~IN_RENAME; ! 2276: ! 2277: #if 0 ! 2278: source_hp->h_meta->h_nodeflags |= IN_CHANGE; ! 2279: tv = time; ! 2280: if ((retval = VOP_UPDATE(source_vp, &tv, &tv, 1))) { ! 2281: VOP_UNLOCK(source_vp, 0, p); ! 2282: goto bad; ! 2283: } ! 2284: #endif ! 2285: ! 2286: /* Copy common fcb info to complex node */ ! 2287: tp = source_hp->h_relative; ! 2288: if (tp) { ! 2289: H_FILEID(VTOH(tp)) = H_FILEID(source_hp); ! 2290: } ! 2291: ! 2292: /* Now copy common fcb info to siblings */ ! 2293: tp = source_hp->h_sibling; ! 2294: while (tp) { ! 2295: H_FILEID(VTOH(tp)) = H_FILEID(source_hp); ! 2296: tp = VTOH(tp)->h_sibling; ! 2297: if (tp == source_vp) ! 2298: break; ! 2299: } ! 2300: ! 2301: /* Timestamp the parents, if this is a move */ ! 2302: if (newparent != oldparent) { ! 2303: targetPar_hp->h_meta->h_nodeflags |= IN_UPDATE; ! 2304: sourcePar_hp->h_meta->h_nodeflags |= IN_UPDATE; ! 2305: tv = time; ! 2306: HFSTIMES(targetPar_hp, &tv, &tv); ! 2307: HFSTIMES(sourcePar_hp, &tv, &tv); ! 2308: }; ! 2309: ! 2310: VPUT(targetPar_vp); ! 2311: VRELE(sourcePar_vp); ! 2312: VPUT(source_vp); ! 2313: ! 2314: DBG_VOP_LOCKS_TEST(retval); ! 2315: if (retval != E_NONE) { ! 2316: DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval)); ! 2317: } ! 2318: return (retval); ! 2319: ! 2320: badcataloglock: ! 2321: if (newparent != oldparent) ! 2322: VOP_UNLOCK(sourcePar_vp, 0, p); ! 2323: ! 2324: bad:; ! 2325: if (retval && doingdirectory) ! 2326: source_hp->h_meta->h_nodeflags &= ~IN_RENAME; ! 2327: ! 2328: if (targetPar_vp == target_vp) ! 2329: VRELE(targetPar_vp); ! 2330: else ! 2331: VPUT(targetPar_vp); ! 2332: ! 2333: if (target_vp) ! 2334: VPUT(target_vp); ! 2335: ! 2336: VRELE(sourcePar_vp); ! 2337: ! 2338: if (VOP_ISLOCKED(source_vp)) ! 2339: VPUT(source_vp); ! 2340: else ! 2341: VRELE(source_vp); ! 2342: ! 2343: DBG_VOP_LOCKS_TEST(retval); ! 2344: if (retval != E_NONE) { ! 2345: DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval)); ! 2346: } ! 2347: return (retval); ! 2348: ! 2349: abortit:; ! 2350: ! 2351: VOP_ABORTOP(targetPar_vp, target_cnp); /* XXX, why not in NFS? */ ! 2352: ! 2353: if (targetPar_vp == target_vp) ! 2354: VRELE(targetPar_vp); ! 2355: else ! 2356: VPUT(targetPar_vp); ! 2357: ! 2358: if (target_vp) ! 2359: VPUT(target_vp); ! 2360: ! 2361: VOP_ABORTOP(sourcePar_vp, source_cnp); /* XXX, why not in NFS? */ ! 2362: ! 2363: VRELE(sourcePar_vp); ! 2364: VRELE(source_vp); ! 2365: ! 2366: DBG_VOP_LOCKS_TEST(retval); ! 2367: if (retval != E_NONE) { ! 2368: DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT(("\tReturning with error %d\n",retval)); ! 2369: } ! 2370: return (retval); ! 2371: } ! 2372: ! 2373: ! 2374: ! 2375: /* ! 2376: * Mkdir system call ! 2377: #% mkdir dvp L U U ! 2378: #% mkdir vpp - L - ! 2379: # ! 2380: vop_mkdir { ! 2381: IN WILLRELE struct vnode *dvp; ! 2382: OUT struct vnode **vpp; ! 2383: IN struct componentname *cnp; ! 2384: IN struct vattr *vap; ! 2385: ! 2386: We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is ! 2387: a previous error. ! 2388: ! 2389: */ ! 2390: ! 2391: int ! 2392: hfs_mkdir(ap) ! 2393: struct vop_mkdir_args /* { ! 2394: struct vnode *a_dvp; ! 2395: struct vnode **a_vpp; ! 2396: struct componentname *a_cnp; ! 2397: struct vattr *a_vap; ! 2398: } */ *ap; ! 2399: { ! 2400: struct proc *p = CURRENT_PROC; ! 2401: int retval; ! 2402: int mode = MAKEIMODE(ap->a_vap->va_type, ap->a_vap->va_mode); ! 2403: ! 2404: DBG_FUNC_NAME("mkdir"); ! 2405: DBG_VOP_LOCKS_DECL(2); ! 2406: DBG_VOP_PRINT_FUNCNAME(); ! 2407: DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp); ! 2408: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); ! 2409: ! 2410: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 2411: DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_LOCKED, VOPDBG_IGNORE, VOPDBG_POS); ! 2412: ! 2413: DBG_VOP(("%s: parent 0x%x (%s) ap->a_cnp->cn_nameptr %s\n", funcname, (u_int)VTOH(ap->a_dvp), H_NAME(VTOH(ap->a_dvp)), ap->a_cnp->cn_nameptr)); ! 2414: WRITE_CK( ap->a_dvp, funcname); ! 2415: DBG_HFS_NODE_CHECK(ap->a_dvp); ! 2416: ASSERT(ap->a_dvp->v_type == VDIR); ! 2417: ! 2418: /* lock catalog b-tree */ ! 2419: retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p); ! 2420: if (retval != E_NONE) { ! 2421: VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ! 2422: VPUT(ap->a_dvp); ! 2423: DBG_VOP_LOCKS_TEST( retval); ! 2424: return (retval); ! 2425: } ! 2426: ! 2427: /* Create the vnode */ ! 2428: DBG_ASSERT((ap->a_cnp->cn_flags & SAVESTART) == 0); ! 2429: retval = hfs_makenode(mode, ap->a_dvp, ap->a_vpp, ap->a_cnp); ! 2430: DBG_VOP_UPDATE_VP(1, *ap->a_vpp); ! 2431: ! 2432: /* unlock catalog b-tree */ ! 2433: (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p); ! 2434: ! 2435: if (retval != E_NONE) { ! 2436: DBG_ERR(("%s: hfs_makenode FAILED: %s, %s\n", funcname, ap->a_cnp->cn_nameptr, H_NAME(VTOH(ap->a_dvp)))); ! 2437: DBG_VOP_LOCKS_TEST(retval); ! 2438: return (retval); ! 2439: } ! 2440: ! 2441: DBG_VOP_LOCKS_TEST(E_NONE); ! 2442: return (E_NONE); ! 2443: } ! 2444: ! 2445: /* ! 2446: * Rmdir system call. ! 2447: #% rmdir dvp L U U ! 2448: #% rmdir vp L U U ! 2449: # ! 2450: vop_rmdir { ! 2451: IN WILLRELE struct vnode *dvp; ! 2452: IN WILLRELE struct vnode *vp; ! 2453: IN struct componentname *cnp; ! 2454: ! 2455: */ ! 2456: ! 2457: int ! 2458: hfs_rmdir(ap) ! 2459: struct vop_rmdir_args /* { ! 2460: struct vnode *a_dvp; ! 2461: struct vnode *a_vp; ! 2462: struct componentname *a_cnp; ! 2463: } */ *ap; ! 2464: { ! 2465: struct vnode *vp = ap->a_vp; ! 2466: struct vnode *dvp = ap->a_dvp; ! 2467: struct hfsnode *hp = VTOH(vp); ! 2468: struct proc *p = CURRENT_PROC; ! 2469: int retval; ! 2470: DBG_FUNC_NAME("rmdir"); ! 2471: DBG_VOP_LOCKS_DECL(2); ! 2472: DBG_VOP_PRINT_FUNCNAME(); ! 2473: DBG_VOP(("\tParent: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp);DBG_VOP_CONT(("\n")); ! 2474: DBG_VOP(("\tTarget: "));DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 2475: DBG_VOP(("\tTarget Name: "));DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); ! 2476: ! 2477: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 2478: DBG_VOP_LOCKS_INIT(1,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 2479: ! 2480: if (dvp == vp) { ! 2481: VRELE(vp); ! 2482: VPUT(vp); ! 2483: DBG_VOP_LOCKS_TEST(EINVAL); ! 2484: return (EINVAL); ! 2485: } ! 2486: ! 2487: if (vp->v_usecount > 2) { ! 2488: DBG_ERR(("%s: dir is busy, usecount is %d\n", funcname, vp->v_usecount )); ! 2489: retval = EBUSY; ! 2490: goto Err_Exit; ! 2491: } ! 2492: ! 2493: /* lock catalog b-tree */ ! 2494: retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_EXCLUSIVE, p); ! 2495: if (retval != E_NONE) { ! 2496: goto Err_Exit; ! 2497: } ! 2498: ! 2499: /* remove the entry from the namei cache: */ ! 2500: cache_purge(vp); ! 2501: ! 2502: /* remove entry from catalog */ ! 2503: retval = hfsDelete (HTOVCB(hp), H_DIRID(hp), H_NAME(hp), FALSE, H_HINT(hp)); ! 2504: hp->h_meta->h_mode = 0; /* Makes the vnode go away...see inactive */ ! 2505: ! 2506: /* unlock catalog b-tree */ ! 2507: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p); ! 2508: ! 2509: /* Set the parent to be updated */ ! 2510: if (! retval) ! 2511: VTOH(dvp)->h_meta->h_nodeflags |= IN_CHANGE | IN_UPDATE; ! 2512: ! 2513: Err_Exit:; ! 2514: if (dvp != 0) ! 2515: VPUT(dvp); ! 2516: VPUT(vp); ! 2517: ! 2518: DBG_VOP_LOCKS_TEST(retval); ! 2519: return (retval); ! 2520: } ! 2521: ! 2522: /* ! 2523: * symlink -- make a symbolic link ! 2524: #% symlink dvp L U U ! 2525: #% symlink vpp - U - ! 2526: # ! 2527: # XXX - note that the return vnode has already been VRELE'ed ! 2528: # by the filesystem layer. To use it you must use vget, ! 2529: # possibly with a further namei. ! 2530: # ! 2531: vop_symlink { ! 2532: IN WILLRELE struct vnode *dvp; ! 2533: OUT WILLRELE struct vnode **vpp; ! 2534: IN struct componentname *cnp; ! 2535: IN struct vattr *vap; ! 2536: IN char *target; ! 2537: ! 2538: We are responsible for freeing the namei buffer, it is done in hfs_makenode(), unless there is ! 2539: a previous error. ! 2540: ! 2541: ! 2542: */ ! 2543: ! 2544: int ! 2545: hfs_symlink(ap) ! 2546: struct vop_symlink_args /* { ! 2547: struct vnode *a_dvp; ! 2548: struct vnode **a_vpp; ! 2549: struct componentname *a_cnp; ! 2550: struct vattr *a_vap; ! 2551: char *a_target; ! 2552: } */ *ap; ! 2553: { ! 2554: register struct vnode *vp, **vpp = ap->a_vpp; ! 2555: struct proc *p = CURRENT_PROC; ! 2556: int len, retval; ! 2557: DBG_FUNC_NAME("symlink"); ! 2558: DBG_VOP_LOCKS_DECL(2); ! 2559: DBG_VOP_PRINT_FUNCNAME(); ! 2560: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 2561: DBG_VOP_LOCKS_INIT(1,*ap->a_vpp, VOPDBG_IGNORE, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_POS); ! 2562: ! 2563: if (VTOVCB(ap->a_dvp)->vcbSigWord != kHFSPlusSigWord) { ! 2564: VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ! 2565: VPUT(ap->a_dvp); ! 2566: DBG_VOP((" ...sorry HFS disks don't support symbolic links.\n")); ! 2567: DBG_VOP_LOCKS_TEST(EOPNOTSUPP); ! 2568: return (EOPNOTSUPP); ! 2569: } ! 2570: ! 2571: /* lock catalog b-tree */ ! 2572: retval = hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_EXCLUSIVE, p); ! 2573: if (retval != E_NONE) { ! 2574: VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ! 2575: VPUT(ap->a_dvp); ! 2576: DBG_VOP_LOCKS_TEST( retval); ! 2577: return (retval); ! 2578: } ! 2579: ! 2580: /* Create the vnode */ ! 2581: retval = hfs_makenode(IFLNK | ap->a_vap->va_mode, ap->a_dvp, vpp, ap->a_cnp); ! 2582: DBG_VOP_UPDATE_VP(1, *ap->a_vpp); ! 2583: ! 2584: /* unlock catalog b-tree */ ! 2585: (void) hfs_metafilelocking(VTOHFS(ap->a_dvp), kHFSCatalogFileID, LK_RELEASE, p); ! 2586: ! 2587: if (retval != E_NONE) { ! 2588: DBG_VOP_LOCKS_TEST(retval); ! 2589: return (retval); ! 2590: } ! 2591: ! 2592: ! 2593: vp = *vpp; ! 2594: len = strlen(ap->a_target); ! 2595: retval = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, ! 2596: UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, (int *)0, ! 2597: (struct proc *)0); ! 2598: ! 2599: ! 2600: VPUT(vp); ! 2601: DBG_VOP_LOCKS_TEST(retval); ! 2602: return (retval); ! 2603: } ! 2604: ! 2605: /* ! 2606: * Dummy dirents to simulate the "." and ".." entries of the directory ! 2607: * in a hfs filesystem. HFS doesn't provide these. Note that each entry ! 2608: * must be the same size as a hfs directory entry (44 bytes). ! 2609: */ ! 2610: static hfsdirentry rootdots[2] = { ! 2611: { ! 2612: 1, /* d_fileno */ ! 2613: sizeof(struct hfsdirentry), /* d_reclen */ ! 2614: DT_DIR, /* d_type */ ! 2615: 1, /* d_namlen */ ! 2616: "." /* d_name */ ! 2617: }, ! 2618: { ! 2619: 1, /* d_fileno */ ! 2620: sizeof(struct hfsdirentry), /* d_reclen */ ! 2621: DT_DIR, /* d_type */ ! 2622: 2, /* d_namlen */ ! 2623: ".." /* d_name */ ! 2624: } ! 2625: }; ! 2626: ! 2627: ! 2628: /* 4.3 Note: ! 2629: * There is some confusion as to what the semantics of uio_offset are. ! 2630: * In ufs, it represents the actual byte offset within the directory ! 2631: * "file." HFS, however, just uses it as an entry counter - essentially ! 2632: * assuming that it has no meaning except to the hfs_readdir function. ! 2633: * This approach would be more efficient here, but some callers may ! 2634: * assume the uio_offset acts like a byte offset. NFS in fact ! 2635: * monkeys around with the offset field a lot between readdir calls. ! 2636: * ! 2637: * We could also speed things up by remembering the last offset position, ! 2638: * but its not clear that that would buy us much (do readdirs need to ! 2639: * be fast?) ?? ! 2640: * ! 2641: * The use of the resid uiop->uio_resid and uiop->uio_iov->iov_len ! 2642: * fields is a mess as well. The libc function readdir() returns ! 2643: * NULL (indicating the end of a directory) when either ! 2644: * the getdirentries() syscall (which calls this and returns ! 2645: * the size of the buffer passed in less the value of uiop->uio_resid) ! 2646: * returns 0, or a direct record with a d_reclen of zero. ! 2647: * nfs_server.c:rfs_readdir(), on the other hand, checks for the end ! 2648: * of the directory by testing uiop->uio_resid == 0. The solution ! 2649: * is to pad the size of the last struct direct in a given ! 2650: * block to fill the block if we are not at the end of the directory. ! 2651: */ ! 2652: ! 2653: /* ! 2654: * NOTE: We require a minimal buffer size of DIRBLKSIZ for two reasons. One, it is the same value ! 2655: * returned be stat() call as the block size. This is mentioned in the man page for getdirentries(): ! 2656: * "Nbytes must be greater than or equal to the block size associated with the file, ! 2657: * see stat(2)". Might as well settle on the same size of ufs. Second, this makes sure there is enough ! 2658: * room for the . and .. entries that have to added manually. ! 2659: */ ! 2660: ! 2661: /* ! 2662: #% readdir vp L L L ! 2663: # ! 2664: vop_readdir { ! 2665: IN struct vnode *vp; ! 2666: INOUT struct uio *uio; ! 2667: IN struct ucred *cred; ! 2668: INOUT int *eofflag; ! 2669: OUT int *ncookies; ! 2670: INOUT u_long **cookies; ! 2671: */ ! 2672: ! 2673: ! 2674: static int ! 2675: hfs_readdir(ap) ! 2676: struct vop_readdir_args /* { ! 2677: struct vnode *vp; ! 2678: struct uio *uio; ! 2679: struct ucred *cred; ! 2680: int *eofflag; ! 2681: int *ncookies; ! 2682: u_long **cookies; ! 2683: } */ *ap; ! 2684: { ! 2685: register struct uio *uio = ap->a_uio; ! 2686: struct hfsnode *hp = VTOH(ap->a_vp); ! 2687: struct proc *p = CURRENT_PROC; ! 2688: ExtendedVCB *vcb = HTOVCB(hp); ! 2689: off_t off = uio->uio_offset; ! 2690: size_t count; ! 2691: size_t lost = 0; ! 2692: CatalogNodeData nodeData; ! 2693: struct hfsdirentry catalogEntry; ! 2694: FSSpec fileSpec; /* 264 bytes */ ! 2695: UInt32 dirID = H_FILEID(hp); ! 2696: UInt32 index = 0; ! 2697: UInt32 origOffset; ! 2698: UInt32 hint; ! 2699: Boolean eofReached = FALSE; ! 2700: int retval = 0; ! 2701: OSErr result = noErr; ! 2702: ! 2703: DBG_FUNC_NAME("readdir"); ! 2704: DBG_VOP_LOCKS_DECL(1); ! 2705: ! 2706: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); ! 2707: DBG_VOP_PRINT_FUNCNAME(); ! 2708: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 2709: DBG_HFS_NODE_CHECK(ap->a_vp); ! 2710: ! 2711: /* We assume it's all one big buffer... */ ! 2712: if (uio->uio_iovcnt > 1) DEBUG_BREAK_MSG(("hfs_readdir: uio->uio_iovcnt = %d?\n", uio->uio_iovcnt)); ! 2713: ! 2714: origOffset = uio->uio_offset; ! 2715: count = uio->uio_resid; ! 2716: /* Make sure we don't return partial entries. */ ! 2717: count -= ((uio->uio_offset + count) % sizeof(hfsdirentry)); ! 2718: if (count <= 0) { ! 2719: DBG_ERR(("%s: Not enough buffer to read in entries\n",funcname)); ! 2720: DBG_VOP_LOCKS_TEST(EINVAL); ! 2721: return (EINVAL); ! 2722: } ! 2723: ! 2724: /* Adjust uio to be on correct boundaries */ ! 2725: lost = uio->uio_resid - count; ! 2726: uio->uio_resid = count; ! 2727: uio->uio_iov->iov_len = count; ! 2728: ! 2729: DBG_VOP(("%s: offset Ox%lX, bytes Ox%lX\n",funcname, ! 2730: (u_long)uio->uio_offset, uio->uio_iov->iov_len)); ! 2731: ! 2732: /* Create the entries for . and .. ! 2733: * We do it here since we are assuming that the directory is guarenteed to exist ! 2734: */ ! 2735: index = 0; ! 2736: if (uio->uio_offset < (2 * sizeof(struct hfsdirentry))) { ! 2737: if ((uio->uio_offset > 0) && (uio->uio_offset != sizeof(struct hfsdirentry))) { ! 2738: retval = EINVAL; ! 2739: goto Exit; ! 2740: } ! 2741: index = 2; ! 2742: if (uio->uio_offset == sizeof(struct hfsdirentry)) { ! 2743: index = 1; ! 2744: } ! 2745: retval = uiomove((caddr_t) (rootdots + uio->uio_offset), index * sizeof(struct hfsdirentry), uio); ! 2746: }; ! 2747: ! 2748: /* Compute the starting index in the directory */ ! 2749: index = (uio->uio_offset - sizeof(struct hfsdirentry)) / sizeof(struct hfsdirentry); ! 2750: ! 2751: /* lock catalog b-tree */ ! 2752: retval = hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p); ! 2753: if (retval != E_NONE) { ! 2754: goto Exit; ! 2755: }; ! 2756: ! 2757: hint = kNoHint; ! 2758: while (uio->uio_resid > sizeof(struct hfsdirentry)) ! 2759: { ! 2760: result = GetCatalogOffspring(vcb, dirID, index, &fileSpec, &nodeData, &hint); ! 2761: if (result != noErr) { ! 2762: if (result == cmNotFound) { ! 2763: eofReached = TRUE; ! 2764: if (origOffset == uio->uio_offset) { /* we were already past eof */ ! 2765: uio->uio_offset = 0; ! 2766: retval = E_NONE; ! 2767: /* unlock catalog b-tree */ ! 2768: (void) hfs_metafilelocking(VTOHFS(ap->a_vp), ! 2769: kHFSCatalogFileID, LK_RELEASE, p); ! 2770: goto Exit; ! 2771: } ! 2772: result = noErr; ! 2773: } ! 2774: retval = MacToVFSError(result); ! 2775: break; ! 2776: } ! 2777: ! 2778: /* Copy entry into the buffer */ ! 2779: catalogEntry.fileno = nodeData.nodeID; ! 2780: catalogEntry.reclen = sizeof(struct hfsdirentry); ! 2781: catalogEntry.type = (nodeData.nodeType == kCatalogFolderNode) ? DT_DIR : DT_REG; ! 2782: catalogEntry.namelen = strlen(fileSpec.name); ! 2783: (void) strncpy(catalogEntry.name, fileSpec.name, sizeof(catalogEntry.name)); ! 2784: ! 2785: /* copy this entry into the user's buffer: */ ! 2786: retval = uiomove((caddr_t) &catalogEntry, sizeof(struct hfsdirentry), uio); ! 2787: if (retval != E_NONE) { ! 2788: DBG_ERR(("%s: uiomove returned %d.\n", funcname, retval)); ! 2789: break; ! 2790: }; ! 2791: ++index; ! 2792: }; ! 2793: ! 2794: /* unlock catalog b-tree */ ! 2795: (void) hfs_metafilelocking(VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p); ! 2796: ! 2797: if (retval != E_NONE) { ! 2798: DBG_ERR(("%s: retval %d when trying to read directory %ld: %s\n",funcname, retval, ! 2799: H_FILEID(hp), H_NAME(hp))); ! 2800: goto Exit; ! 2801: } ! 2802: else if (vcb->vcbSigWord == kHFSPlusSigWord) ! 2803: hp->h_meta->h_nodeflags |= IN_ACCESS; ! 2804: ! 2805: /* Bake any cookies */ ! 2806: if (!retval && ap->a_ncookies != NULL) { ! 2807: struct dirent* dpStart; ! 2808: struct dirent* dpEnd; ! 2809: struct dirent* dp; ! 2810: int ncookies; ! 2811: u_long *cookies; ! 2812: u_long *cookiep; ! 2813: ! 2814: /* ! 2815: * Only the NFS server uses cookies, and it loads the ! 2816: * directory block into system space, so we can just look at ! 2817: * it directly. ! 2818: */ ! 2819: if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) ! 2820: panic("hfs_readdir: unexpected uio from NFS server"); ! 2821: dpStart = (struct dirent *) ! 2822: (uio->uio_iov->iov_base - (uio->uio_offset - off)); ! 2823: dpEnd = (struct dirent *) uio->uio_iov->iov_base; ! 2824: for (dp = dpStart, ncookies = 0; ! 2825: dp < dpEnd && dp->d_reclen != 0; ! 2826: dp = (struct dirent *)((caddr_t)dp + dp->d_reclen)) ! 2827: ncookies++; ! 2828: MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP, ! 2829: M_WAITOK); ! 2830: for (dp = dpStart, cookiep = cookies; ! 2831: dp < dpEnd; ! 2832: dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { ! 2833: off += dp->d_reclen; ! 2834: *cookiep++ = (u_long) off; ! 2835: } ! 2836: *ap->a_ncookies = ncookies; ! 2837: *ap->a_cookies = cookies; ! 2838: } ! 2839: ! 2840: Exit:; ! 2841: uio->uio_resid += lost; ! 2842: ! 2843: if (ap->a_eofflag) ! 2844: *ap->a_eofflag = eofReached; ! 2845: ! 2846: DBG_VOP_LOCKS_TEST(retval); ! 2847: return (retval); ! 2848: } ! 2849: ! 2850: ! 2851: /* ! 2852: * readdirattr operation ! 2853: */ ! 2854: ! 2855: /* ! 2856: ! 2857: # ! 2858: #% readdirattr vp L L L ! 2859: # ! 2860: vop_readdirattr { ! 2861: IN struct vnode *vp; ! 2862: IN struct attrlist *alist; ! 2863: INOUT struct uio *uio; ! 2864: INOUT int index; ! 2865: INOUT int *eofflag; ! 2866: OUT u_long *ncookies; ! 2867: INOUT u_long **cookies; ! 2868: IN struct ucred *cred; ! 2869: }; ! 2870: ! 2871: */ ! 2872: ! 2873: ! 2874: static int ! 2875: hfs_readdirattr(ap) ! 2876: struct vop_readdirattr_args /* { ! 2877: struct vnode *vp; ! 2878: struct attrlist *alist; ! 2879: struct uio *uio; ! 2880: int index; ! 2881: int *eofflag; ! 2882: u_long *ncookies; ! 2883: u_long **cookies; ! 2884: struct ucred *cred; ! 2885: } */ *ap; ! 2886: { ! 2887: struct vnode *vp = ap->a_vp; ! 2888: struct attrlist *alist = ap->a_alist; ! 2889: register struct uio *uio = ap->a_uio; ! 2890: struct hfsnode *hp = VTOH(ap->a_vp); ! 2891: ExtendedVCB *vcb = HTOVCB(hp); ! 2892: off_t off = uio->uio_offset; ! 2893: size_t count; ! 2894: struct hfsCatalogInfo catalogInfo; ! 2895: struct hfsCatalogInfo *catInfoPtr = NULL; ! 2896: UInt32 dirID = H_FILEID(hp); ! 2897: UInt32 index = 0; ! 2898: OSErr result = noErr; ! 2899: UInt32 origOffset; ! 2900: Boolean eofReached = FALSE; ! 2901: int retval = 0; ! 2902: u_long fixedblocksize; ! 2903: u_long maxattrblocksize; ! 2904: u_long currattrbufsize; ! 2905: void *attrbufptr = NULL; ! 2906: void *attrptr; ! 2907: void *varptr; ! 2908: DBG_FUNC_NAME("readdirattr"); ! 2909: DBG_VOP_LOCKS_DECL(1); ! 2910: ! 2911: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); ! 2912: DBG_VOP_PRINT_FUNCNAME(); ! 2913: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 2914: DBG_HFS_NODE_CHECK(ap->a_vp); ! 2915: ! 2916: if ((alist->bitmapcount != ATTR_BIT_MAP_COUNT) || ! 2917: ((alist->commonattr & ~ATTR_CMN_VALIDMASK) != 0) || ! 2918: ((alist->dirattr & ~ATTR_DIR_VALIDMASK) != 0) || ! 2919: ((alist->fileattr & ~ATTR_FILE_VALIDMASK) != 0) || ! 2920: ((alist->forkattr & ~ATTR_FORK_VALIDMASK) != 0)) { ! 2921: DBG_ERR(("%s: bad attrlist\n", funcname)); ! 2922: DBG_VOP_LOCKS_TEST(EINVAL); ! 2923: return EINVAL; ! 2924: }; ! 2925: ! 2926: /* Requesting volume information is illegal : */ ! 2927: if (alist->volattr != 0) { ! 2928: DBG_ERR(("%s: requesting volume attribute is illegal\n", funcname)); ! 2929: DBG_VOP_LOCKS_TEST(EINVAL); ! 2930: return EINVAL; ! 2931: }; ! 2932: ! 2933: /* Reject requests for unsupported options for now: */ ! 2934: if ((alist->commonattr & (ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST)) || ! 2935: (alist->fileattr & (ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | ATTR_FILE_FORKLIST))) { ! 2936: DBG_ERR(("%s: illegal bits in attlist\n", funcname)); ! 2937: DBG_VOP_LOCKS_TEST(EINVAL); ! 2938: return EINVAL; ! 2939: }; ! 2940: ! 2941: origOffset = uio->uio_offset; ! 2942: count = uio->uio_resid; ! 2943: ! 2944: /* Make sure we don't return partial entries. */ ! 2945: count -= ((uio->uio_offset + count) % sizeof(hfsdirentry)); ! 2946: if (count <= 0) { ! 2947: DBG_ERR(("%s: Not enough buffer to read in entries\n",funcname)); ! 2948: DBG_VOP_LOCKS_TEST(EINVAL); ! 2949: return (EINVAL); ! 2950: } ! 2951: ! 2952: DBG_VOP(("%s: offset Ox%lX, bytes Ox%lX\n",funcname, ! 2953: (u_long)uio->uio_offset, (u_long)uio->uio_iov->iov_len)); ! 2954: ! 2955: /* Preflight and alloc buffer to do packings */ ! 2956: maxattrblocksize = fixedblocksize = (sizeof(u_long) + AttributeBlockSize(alist)); /* u_long for length longword */ ! 2957: if (alist->commonattr & ATTR_CMN_NAME) maxattrblocksize += NAME_MAX + 1; ! 2958: if (alist->commonattr & ATTR_CMN_NAMEDATTRLIST) maxattrblocksize += 0; /* XXX PPD */ ! 2959: if (alist->fileattr & ATTR_FILE_FORKLIST) maxattrblocksize += 0; /* XXX PPD */ ! 2960: ! 2961: DBG_VOP(("%s: allocating Ox%lX byte buffer (Ox%lX + Ox%lX) for attributes...\n", ! 2962: funcname, ! 2963: maxattrblocksize, ! 2964: fixedblocksize, ! 2965: maxattrblocksize - fixedblocksize)); ! 2966: MALLOC(attrbufptr, void *, maxattrblocksize, M_TEMP, M_WAITOK); ! 2967: attrptr = attrbufptr; ! 2968: varptr = attrbufptr + fixedblocksize; /* Point to variable-length storage */ ! 2969: DBG_VOP(("%s: attrptr = 0x%08X, varptr = 0x%08X...\n", funcname, (u_int)attrptr, (u_int)varptr)); ! 2970: ! 2971: #if 0 ! 2972: /* Create the entries for . and .. ! 2973: * We do it here since we are assuming that the directory is guarenteed to exist ! 2974: */ ! 2975: index = 0; ! 2976: if (uio->uio_offset < (2 * sizeof(struct hfsdirentry))) { ! 2977: if ((uio->uio_offset > 0) && (uio->uio_offset != sizeof(struct hfsdirentry))) { ! 2978: retval = EINVAL; ! 2979: goto Exit; ! 2980: } ! 2981: index = 2; ! 2982: if (uio->uio_offset == sizeof(struct hfsdirentry)) { ! 2983: index = 1; ! 2984: } ! 2985: retval = uiomove((caddr_t) (rootdots + uio->uio_offset), index * sizeof(struct hfsdirentry), uio); ! 2986: }; ! 2987: #endif ! 2988: ! 2989: /* Compute the starting index in the directory */ ! 2990: index = (uio->uio_offset - sizeof(struct hfsdirentry)) / sizeof(struct hfsdirentry); ! 2991: ! 2992: catalogInfo.hint = kNoHint; ! 2993: while (uio->uio_resid > sizeof(struct hfsdirentry)) ! 2994: { ! 2995: ! 2996: result = GetCatalogOffspring(vcb, dirID, index, &catalogInfo.spec, &catalogInfo.nodeData, &catalogInfo.hint); ! 2997: if (result != noErr) { ! 2998: if (result == cmNotFound) { ! 2999: eofReached = TRUE; ! 3000: if (origOffset == uio->uio_offset) { /* we were already past eof */ ! 3001: uio->uio_offset = 0; ! 3002: retval = E_NONE; ! 3003: goto Err_Exit; ! 3004: } ! 3005: result = noErr; ! 3006: } ! 3007: retval = MacToVFSError(result); ! 3008: break; ! 3009: } ! 3010: catInfoPtr = &catalogInfo; ! 3011: ! 3012: *((u_long *)attrptr)++ = 0; /* Reserve space for length field */ ! 3013: PackAttributeBlock(alist, vp, catInfoPtr, &attrptr, &varptr); ! 3014: currattrbufsize = *((u_long *)attrbufptr) = (varptr - attrbufptr); /* Store length of fixed + var block */ ! 3015: ! 3016: /* Make sure that there is enough room to copy to */ ! 3017: if (currattrbufsize > uio->uio_resid) ! 3018: { ! 3019: if (uio->uio_offset == origOffset) ! 3020: { ! 3021: DBG_ERR(("%s: Not enough buffer to read in entries\n",funcname)); ! 3022: retval = EINVAL; ! 3023: goto Err_Exit; ! 3024: } ! 3025: break; ! 3026: } ! 3027: ! 3028: DBG_VOP(("%s: copying Ox%lX bytes to user address 0x%08X.\n",funcname, currattrbufsize, (u_int)ap->a_uio->uio_iov->iov_base)); ! 3029: retval = uiomove((caddr_t)attrbufptr, currattrbufsize, ap->a_uio); ! 3030: if (retval != E_NONE) { ! 3031: DBG_ERR(("%s: error %d on uiomove.\n",funcname, retval)); ! 3032: break; ! 3033: }; ! 3034: attrptr = (void *)((u_long)attrptr + currattrbufsize); ! 3035: ++index; ! 3036: }; ! 3037: ! 3038: if (retval != E_NONE) { ! 3039: DBG_ERR(("%s: retval %d when trying to read directory %ld: %s\n",funcname, retval, ! 3040: H_FILEID(hp), H_NAME(hp))); ! 3041: retval = EINVAL; ! 3042: }; ! 3043: ! 3044: /* Bake any cookies */ ! 3045: if (!retval && ap->a_ncookies != NULL) { ! 3046: struct dirent* dpStart; ! 3047: struct dirent* dpEnd; ! 3048: struct dirent* dp; ! 3049: int ncookies; ! 3050: u_long *cookies; ! 3051: u_long *cookiep; ! 3052: ! 3053: /* ! 3054: * Only the NFS server uses cookies, and it loads the ! 3055: * directory block into system space, so we can just look at ! 3056: * it directly. ! 3057: */ ! 3058: if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1) ! 3059: panic("hfs_readdir: unexpected uio from NFS server"); ! 3060: dpStart = (struct dirent *) ! 3061: (uio->uio_iov->iov_base - (uio->uio_offset - off)); ! 3062: dpEnd = (struct dirent *) uio->uio_iov->iov_base; ! 3063: for (dp = dpStart, ncookies = 0; ! 3064: dp < dpEnd && dp->d_reclen != 0; ! 3065: dp = (struct dirent *)((caddr_t)dp + dp->d_reclen)) ! 3066: ncookies++; ! 3067: MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP, ! 3068: M_WAITOK); ! 3069: for (dp = dpStart, cookiep = cookies; ! 3070: dp < dpEnd; ! 3071: dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) { ! 3072: off += dp->d_reclen; ! 3073: *cookiep++ = (u_long) off; ! 3074: } ! 3075: *ap->a_ncookies = ncookies; ! 3076: *ap->a_cookies = cookies; ! 3077: } ! 3078: ! 3079: Err_Exit:; ! 3080: ! 3081: if (attrbufptr != NULL) ! 3082: FREE(attrbufptr, M_TEMP); ! 3083: ! 3084: if (ap->a_eofflag) ! 3085: *ap->a_eofflag = eofReached; ! 3086: ! 3087: DBG_VOP_LOCKS_TEST(retval); ! 3088: return (retval); ! 3089: } ! 3090: ! 3091: ! 3092: /* ! 3093: * Return target name of a symbolic link ! 3094: #% readlink vp L L L ! 3095: # ! 3096: vop_readlink { ! 3097: IN struct vnode *vp; ! 3098: INOUT struct uio *uio; ! 3099: IN struct ucred *cred; ! 3100: */ ! 3101: ! 3102: int ! 3103: hfs_readlink(ap) ! 3104: struct vop_readlink_args /* { ! 3105: struct vnode *a_vp; ! 3106: struct uio *a_uio; ! 3107: struct ucred *a_cred; ! 3108: } */ *ap; ! 3109: { ! 3110: int retval; ! 3111: DBG_FUNC_NAME("readlink"); ! 3112: DBG_VOP_LOCKS_DECL(1); ! 3113: DBG_VOP_PRINT_FUNCNAME(); ! 3114: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 3115: ! 3116: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); ! 3117: retval = VOP_READ(ap->a_vp, ap->a_uio, 0, ap->a_cred); ! 3118: DBG_VOP_LOCKS_TEST(retval); ! 3119: return (retval); ! 3120: ! 3121: } ! 3122: ! 3123: ! 3124: /* ! 3125: * hfs abort op, called after namei() when a CREATE/DELETE isn't actually ! 3126: * done. If a buffer has been saved in anticipation of a CREATE, delete it. ! 3127: #% abortop dvp = = = ! 3128: # ! 3129: vop_abortop { ! 3130: IN struct vnode *dvp; ! 3131: IN struct componentname *cnp; ! 3132: ! 3133: */ ! 3134: ! 3135: /* ARGSUSED */ ! 3136: ! 3137: static int ! 3138: hfs_abortop(ap) ! 3139: struct vop_abortop_args /* { ! 3140: struct vnode *a_dvp; ! 3141: struct componentname *a_cnp; ! 3142: } */ *ap; ! 3143: { ! 3144: DBG_FUNC_NAME("abortop"); ! 3145: DBG_VOP_LOCKS_DECL(1); ! 3146: DBG_VOP_PRINT_FUNCNAME(); ! 3147: DBG_VOP_PRINT_VNODE_INFO(ap->a_dvp); ! 3148: DBG_VOP_PRINT_CPN_INFO(ap->a_cnp);DBG_VOP_CONT(("\n")); ! 3149: ! 3150: ! 3151: DBG_VOP_LOCKS_INIT(0,ap->a_dvp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); ! 3152: ! 3153: if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { ! 3154: FREE_ZONE(ap->a_cnp->cn_pnbuf, ap->a_cnp->cn_pnlen, M_NAMEI); ! 3155: } ! 3156: DBG_VOP_LOCKS_TEST(E_NONE); ! 3157: return (E_NONE); ! 3158: } ! 3159: ! 3160: // int prthfsactive = 0; /* 1 => print out reclaim of active vnodes */ ! 3161: ! 3162: /* ! 3163: #% inactive vp L U U ! 3164: # ! 3165: vop_inactive { ! 3166: IN struct vnode *vp; ! 3167: IN struct proc *p; ! 3168: ! 3169: */ ! 3170: ! 3171: static int ! 3172: hfs_inactive(ap) ! 3173: struct vop_inactive_args /* { ! 3174: struct vnode *a_vp; ! 3175: } */ *ap; ! 3176: { ! 3177: struct vnode *vp = ap->a_vp; ! 3178: struct hfsnode *hp = VTOH(vp); ! 3179: struct proc *p = ap->a_p; ! 3180: struct timeval tv; ! 3181: extern int prtactive; ! 3182: ! 3183: DBG_FUNC_NAME("inactive"); ! 3184: DBG_VOP_LOCKS_DECL(1); ! 3185: DBG_VOP_PRINT_FUNCNAME(); ! 3186: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 3187: ! 3188: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO); ! 3189: ! 3190: /* ! 3191: NOTE: vnodes need careful handling because fork vnodes that failed to be created ! 3192: in their entirity could be getting cleaned up here, in which case h_meta == NULL... ! 3193: */ ! 3194: if (prtactive && vp->v_usecount <= 0) ! 3195: vprint("hfs_inactive: pushing active", vp); ! 3196: ! 3197: if (vp->v_usecount != 0) ! 3198: DBG_VOP(("%s: bad usecount = %d\n",funcname,vp->v_usecount )); ! 3199: ! 3200: /* ! 3201: * Skip all complex nodes ! 3202: * At this point, there should be no fork nodes existing for its complex ! 3203: */ ! 3204: if (vp->v_type == VCPLX) { ! 3205: #if DIAGNOSTIC ! 3206: if (vp->v_usecount == 0) { ! 3207: struct vnode *tvp; ! 3208: tvp = hfs_vhashget(hp->h_dev, H_FILEID(hp), kDataFork); ! 3209: DBG_ASSERT(tvp == NULL); ! 3210: if (tvp) ! 3211: vput (tvp); ! 3212: tvp = hfs_vhashget(hp->h_dev, H_FILEID(hp), kRsrcFork); ! 3213: DBG_ASSERT(tvp == NULL); ! 3214: if (tvp) ! 3215: vput (tvp); ! 3216: } ! 3217: #endif /* DIAGNOSTIC */ ! 3218: hp->h_meta->h_mode = 0; /* Makes the node go away */ ! 3219: goto out; ! 3220: } ! 3221: ! 3222: /* ! 3223: * Ignore inodes related to stale file handles. ! 3224: */ ! 3225: if ((vp->v_type == VNON) || (hp->h_meta->h_mode == 0)) ! 3226: goto out; ! 3227: ! 3228: if (hp->h_meta->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { ! 3229: tv = time; ! 3230: VOP_UPDATE(vp, &tv, &tv, 0); ! 3231: } ! 3232: ! 3233: out: ! 3234: VOP_UNLOCK(vp, 0, p); ! 3235: /* ! 3236: * If we are done with the inode, reclaim it ! 3237: * so that it can be reused immediately. ! 3238: */ ! 3239: if ((vp->v_type == VNON) || (hp->h_meta->h_mode == 0)) ! 3240: vrecycle(vp, (struct slock *)0, p); ! 3241: ! 3242: DBG_VOP_LOCKS_TEST(E_NONE); ! 3243: return (E_NONE); ! 3244: } ! 3245: ! 3246: /* ! 3247: Ignored since the locks are gone...... ! 3248: #% reclaim vp U I I ! 3249: # ! 3250: vop_reclaim { ! 3251: IN struct vnode *vp; ! 3252: IN struct proc *p; ! 3253: ! 3254: */ ! 3255: ! 3256: static int ! 3257: hfs_reclaim(ap) ! 3258: struct vop_reclaim_args /* { ! 3259: struct vnode *a_vp; ! 3260: } */ *ap; ! 3261: { ! 3262: struct vnode *vp = ap->a_vp; ! 3263: struct vnode *tp = NULL; ! 3264: struct hfsnode *hp = VTOH(vp); ! 3265: extern int prtactive; ! 3266: DBG_FUNC_NAME("reclaim"); ! 3267: DBG_VOP_LOCKS_DECL(1); ! 3268: DBG_VOP_PRINT_FUNCNAME(); ! 3269: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 3270: ! 3271: DBG_VOP_LOCKS_INIT(0, ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO); ! 3272: ! 3273: /* ! 3274: NOTE: vnodes need careful handling because fork vnodes that failed to be ! 3275: created in their entirity could be getting cleaned up here, in which ! 3276: case v_type == VNON and h_meta == NULL... ! 3277: */ ! 3278: ! 3279: if (prtactive && vp->v_usecount != 0) ! 3280: vprint("hfs_reclaim(): pushing active", vp); ! 3281: ! 3282: hfs_vhashrem(hp); ! 3283: ! 3284: /* release the file meta */ ! 3285: if ((vp->v_type == VREG) || (vp->v_type == VLNK)) { ! 3286: DBG_ASSERT(hp->h_meta != NULL); ! 3287: ! 3288: if (H_FORKTYPE(hp) == kSysFile) { ! 3289: /* XXX SER Here we release meta for kSysFile, which do not need it!!! */ ! 3290: FREE(hp->h_meta, M_HFSNODE); ! 3291: hp->h_meta = NULL; ! 3292: } ! 3293: else { ! 3294: HFSFILEMETA_LOCK_EXCLUSIVE(hp, CURRENT_PROC); ! 3295: hp->h_meta->h_usecount--; /* XXX SER eventually remove h_usecount */ ! 3296: ! 3297: /* ! 3298: * if there are still more forks, make the fork ptr point to another ! 3299: */ ! 3300: if ((hp->h_meta->h_usecount > 0) && (hp->h_meta->h_fork == vp)) { ! 3301: hp->h_meta->h_fork = hp->h_sibling; ! 3302: } ! 3303: ! 3304: ! 3305: if ((H_FORKTYPE(hp) == kDataFork) && hp->h_relative) { ! 3306: DBG_ASSERT(VTOH(hp->h_relative)->h_relative != NULL); ! 3307: VTOH(hp->h_relative)->h_relative = NULL; /* Mark the default node as NULL from a complex view */ ! 3308: }; ! 3309: ! 3310: if (hp->h_sibling) { ! 3311: tp = vp; ! 3312: do { ! 3313: tp = VTOH(tp)->h_sibling; ! 3314: } while (VTOH(tp)->h_sibling != vp); ! 3315: VTOH(tp)->h_sibling = hp->h_sibling; ! 3316: if (VTOH(tp)->h_sibling == tp) /* pointing to ourselves */ ! 3317: VTOH(tp)->h_sibling = NULL; ! 3318: hp->h_sibling = NULL; ! 3319: }; ! 3320: ! 3321: HFSFILEMETA_UNLOCK(hp, CURRENT_PROC); ! 3322: hp->h_meta = NULL; ! 3323: ! 3324: /* h_relative could be NULL, if a force unmount was done, and the complex node is already gone */ ! 3325: if (hp->h_relative) { ! 3326: DBG_ASSERT(H_FORKTYPE(VTOH(hp->h_relative)) == kDirCmplx); ! 3327: DBG_ASSERT((hp->h_relative)->v_type == VCPLX); ! 3328: VRELE (hp->h_relative); /* release the complex node */ ! 3329: hp->h_relative = NULL; ! 3330: } ! 3331: } ! 3332: } ! 3333: else if (vp->v_type == VCPLX) { ! 3334: #if DIAGNOSTIC ! 3335: /* Unless a force unmount, no other forks should exist */ ! 3336: if (vp->v_usecount == 0) { ! 3337: struct vnode *tvp; ! 3338: tvp = hfs_vhashget(hp->h_dev, H_FILEID(hp), kDataFork); ! 3339: DBG_ASSERT(tvp == NULL); ! 3340: if (tvp) ! 3341: vput (tvp); ! 3342: tvp = hfs_vhashget(hp->h_dev, H_FILEID(hp), kRsrcFork); ! 3343: DBG_ASSERT(tvp == NULL); ! 3344: if (tvp) ! 3345: vput (tvp); ! 3346: } ! 3347: #endif /* DIAGNOSTIC */ ! 3348: ! 3349: DBG_ASSERT(hp->h_meta != NULL); ! 3350: tp = hp->h_meta->h_fork; ! 3351: if (tp == NULL) { ! 3352: /* No more forks, so do nothing here */ ! 3353: } ! 3354: else { ! 3355: /* This should only occur when a force unmount occurs */ ! 3356: /* so, usually, no other forks should exist */ ! 3357: VTOH(tp)->h_relative = NULL; ! 3358: if (VTOH(tp)->h_sibling) ! 3359: VTOH(VTOH(tp)->h_sibling)->h_relative = NULL; ! 3360: } ! 3361: ! 3362: if (hp->h_meta->h_nodeflags & IN_LONGNAME) { ! 3363: DBG_ASSERT(H_NAME(hp) != NULL); ! 3364: FREE(H_NAME(hp), M_HFSNODE); ! 3365: } ! 3366: ! 3367: FREE(hp->h_meta, M_HFSNODE); ! 3368: hp->h_meta = NULL; ! 3369: hp->h_relative = NULL; ! 3370: ! 3371: } ! 3372: else if (vp->v_type == VDIR) { ! 3373: if (hp->h_meta->h_nodeflags & IN_LONGNAME) ! 3374: FREE(H_NAME(hp), M_HFSNODE); ! 3375: ! 3376: FREE(hp->h_meta, M_HFSNODE); ! 3377: hp->h_meta = NULL; ! 3378: } ! 3379: else ! 3380: DBG_ASSERT(0); /* Unexpected v_type !!!! XXX SER Change to panic */ ! 3381: ! 3382: /* ! 3383: * Purge old data structures associated with the inode. ! 3384: */ ! 3385: cache_purge(vp); ! 3386: if ((vp->v_type != VNON) && hp->h_devvp) { ! 3387: VRELE(hp->h_devvp); ! 3388: hp->h_devvp = 0; ! 3389: } ! 3390: ! 3391: /* Free our data structs */ ! 3392: if (vp->v_type != VNON) { ! 3393: DBG_ASSERT(hp->h_sibling == NULL); ! 3394: DBG_ASSERT(hp->h_relative == NULL); ! 3395: DBG_ASSERT(hp->h_meta == NULL); ! 3396: FREE(hp->h_xfcb, M_HFSNODE); ! 3397: FREE(vp->v_data, M_HFSNODE); ! 3398: }; ! 3399: vp->v_data = NULL; ! 3400: ! 3401: DBG_VOP_LOCKS_TEST(E_NONE); ! 3402: return (E_NONE); ! 3403: } ! 3404: ! 3405: ! 3406: /* ! 3407: * Lock an hfsnode. If its already locked, set the WANT bit and sleep. ! 3408: #% lock vp U L U ! 3409: # ! 3410: vop_lock { ! 3411: IN struct vnode *vp; ! 3412: IN int flags; ! 3413: IN struct proc *p; ! 3414: */ ! 3415: ! 3416: static int ! 3417: hfs_lock(ap) ! 3418: struct vop_lock_args /* { ! 3419: struct vnode *a_vp; ! 3420: int a_flags; ! 3421: struct proc *a_p; ! 3422: } */ *ap; ! 3423: { ! 3424: struct vnode * vp = ap->a_vp; ! 3425: struct hfsnode *hp = VTOH(ap->a_vp); ! 3426: int retval; ! 3427: ! 3428: DBG_FUNC_NAME("lock"); ! 3429: DBG_VOP_LOCKS_DECL(1); ! 3430: DBG_VOP_PRINT_FUNCNAME();DBG_VOP_CONT((" ")); ! 3431: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags)); ! 3432: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_ZERO); ! 3433: ! 3434: #if DIAGNOSTIC ! 3435: DBG_ASSERT(hp != (struct hfsnode *)NULL); ! 3436: if (ap->a_flags & LK_INTERLOCK) { ! 3437: DBG_ASSERT(*((int*)&vp->v_interlock) != 0); ! 3438: } else { ! 3439: DBG_ASSERT(*((int*)&vp->v_interlock) == 0); ! 3440: }; ! 3441: if (H_FORKTYPE(hp) != kDirCmplx && (vp->v_flag & VSYSTEM) == 0) { ! 3442: DBG_ASSERT(hp->h_meta != NULL); ! 3443: if ((lockstatus(&hp->h_meta->h_fmetalock)) != (lockstatus(&hp->h_lock))) ! 3444: DBG_VOP(("hfs_lock: Warning, mismatched locks. h_lock = %d.meta = %d\n", lockstatus(&hp->h_lock), lockstatus(&hp->h_meta->h_fmetalock))); ! 3445: } ! 3446: ! 3447: /* Attempting to lock the vnode */ ! 3448: if (lockstatus(&hp->h_lock) && ((ap->a_flags & LK_NOWAIT) == 0)) { ! 3449: DBG_VOP(("hfs_lock: waiting for vnode lock (forkype = %d)...\n", H_FORKTYPE(hp))); ! 3450: }; ! 3451: #endif /* DIAGNOSTIC */ ! 3452: ! 3453: retval = lockmgr(&hp->h_lock, ap->a_flags, &vp->v_interlock, ap->a_p); ! 3454: if (retval != E_NONE) { ! 3455: if ((ap->a_flags & LK_NOWAIT) == 0) ! 3456: DBG_ERR(("hfs_lock: error %d trying to lock vnode (flags = 0x%08X).\n", retval, ap->a_flags)); ! 3457: goto Err_Exit; ! 3458: }; ! 3459: ! 3460: /* Now get a lock on the file meta lock if necessary */ ! 3461: if (H_FORKTYPE(hp) != kDirCmplx && (vp->v_flag & VSYSTEM) == 0) { ! 3462: if (lockstatus(&hp->h_meta->h_fmetalock) && ((ap->a_flags & LK_NOWAIT) == 0)) ! 3463: DBG_VOP(("hfs_lock: waiting for meta-data lock...\n")); ! 3464: ! 3465: retval = lockmgr(&hp->h_meta->h_fmetalock, ap->a_flags & ~LK_INTERLOCK, (simple_lock_t) 0, ap->a_p); ! 3466: if (retval != E_NONE) { ! 3467: if ((ap->a_flags & LK_NOWAIT) == 0) { ! 3468: DBG_ERR(("hfs_lock: error %d trying to lock meta-data (flags = 0x%08X).\n", retval, ap->a_flags)); ! 3469: }; ! 3470: (void)lockmgr(&hp->h_lock, LK_RELEASE, (simple_lock_t) 0, ap->a_p); ! 3471: }; ! 3472: }; ! 3473: ! 3474: Err_Exit:; ! 3475: DBG_ASSERT(*((int*)&vp->v_interlock) == 0); ! 3476: DBG_VOP_LOCKS_TEST(retval); ! 3477: return (retval); ! 3478: } ! 3479: ! 3480: /* ! 3481: * Unlock an hfsnode. ! 3482: #% unlock vp L U L ! 3483: # ! 3484: vop_unlock { ! 3485: IN struct vnode *vp; ! 3486: IN int flags; ! 3487: IN struct proc *p; ! 3488: ! 3489: */ ! 3490: int ! 3491: hfs_unlock(ap) ! 3492: struct vop_unlock_args /* { ! 3493: struct vnode *a_vp; ! 3494: int a_flags; ! 3495: struct proc *a_p; ! 3496: } */ *ap; ! 3497: { ! 3498: struct hfsnode *hp = VTOH(ap->a_vp); ! 3499: struct vnode *vp = ap->a_vp; ! 3500: int retval = E_NONE; ! 3501: ! 3502: DBG_FUNC_NAME("unlock"); ! 3503: DBG_VOP_LOCKS_DECL(1); ! 3504: DBG_VOP_PRINT_FUNCNAME(); ! 3505: DBG_VOP_PRINT_VNODE_INFO(vp);DBG_VOP_CONT((" flags = 0x%08X.\n", ap->a_flags)); ! 3506: DBG_VOP_LOCKS_INIT(0,vp, VOPDBG_LOCKED, VOPDBG_UNLOCKED, VOPDBG_LOCKED, VOPDBG_ZERO); ! 3507: ! 3508: #if DIAGNOSTIC ! 3509: DBG_ASSERT(hp != (struct hfsnode *)NULL); ! 3510: if (ap->a_flags & LK_INTERLOCK) { ! 3511: DBG_ASSERT(*((int*)&vp->v_interlock) != 0); ! 3512: } else { ! 3513: DBG_ASSERT(*((int*)&vp->v_interlock) == 0); ! 3514: }; ! 3515: if (H_FORKTYPE(hp) != kDirCmplx && (vp->v_flag & VSYSTEM) == 0) { ! 3516: DBG_ASSERT(hp->h_meta != NULL); ! 3517: }; ! 3518: #endif /* DIAGNOSTIC */ ! 3519: ! 3520: DBG_ASSERT((ap->a_flags & (LK_EXCLUSIVE|LK_SHARED)) == 0); ! 3521: retval = lockmgr(&hp->h_lock, ap->a_flags | LK_RELEASE, &vp->v_interlock, ap->a_p); ! 3522: if (retval != E_NONE) { ! 3523: DEBUG_BREAK_MSG(("hfs_unlock: error %d trying to unlock vnode (forktype = %d).\n", retval, H_FORKTYPE(hp))); ! 3524: }; ! 3525: ! 3526: DBG_ASSERT(*((int*)&vp->v_interlock) == 0); ! 3527: ! 3528: /* Release lock on the file meta lock */ ! 3529: if ((retval == E_NONE) && (H_FORKTYPE(hp) != kDirCmplx) && ((vp->v_flag & VSYSTEM) == 0)) { ! 3530: retval = lockmgr(&hp->h_meta->h_fmetalock, (ap->a_flags & ~LK_INTERLOCK) | LK_RELEASE, (simple_lock_t) 0, ap->a_p); ! 3531: if (retval != E_NONE) { ! 3532: /* XXX PPD Wouldn't this be the perfect time to panic? We're now half-unlocked! */ ! 3533: DEBUG_BREAK_MSG(("hfs_unlock: error %d trying to unlock meta-data (forktype = %d).\n", retval, H_FORKTYPE(hp))); ! 3534: }; ! 3535: }; ! 3536: ! 3537: DBG_ASSERT(*((int*)&vp->v_interlock) == 0); ! 3538: DBG_VOP_LOCKS_TEST(retval); ! 3539: return (retval); ! 3540: } ! 3541: ! 3542: ! 3543: /* ! 3544: * Print out the contents of an hfsnode. ! 3545: #% print vp = = = ! 3546: # ! 3547: vop_print { ! 3548: IN struct vnode *vp; ! 3549: */ ! 3550: int ! 3551: hfs_print(ap) ! 3552: struct vop_print_args /* { ! 3553: struct vnode *a_vp; ! 3554: } */ *ap; ! 3555: { ! 3556: register struct vnode * vp = ap->a_vp; ! 3557: register struct hfsnode *hp = VTOH( vp); ! 3558: DBG_FUNC_NAME("print"); ! 3559: DBG_VOP_LOCKS_DECL(1); ! 3560: DBG_VOP_PRINT_FUNCNAME(); ! 3561: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); ! 3562: ! 3563: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_POS); ! 3564: ! 3565: printf("tag VT_HFS, dirID %ld, on dev %d, %d", H_DIRID(hp), ! 3566: major(hp->h_dev), minor(hp->h_dev)); ! 3567: /* lockmgr_printinfo(&hp->h_lock); */ ! 3568: printf("\n"); ! 3569: DBG_VOP_LOCKS_TEST(E_NONE); ! 3570: return (E_NONE); ! 3571: } ! 3572: ! 3573: ! 3574: /* ! 3575: * Check for a locked hfsnode. ! 3576: #% islocked vp = = = ! 3577: # ! 3578: vop_islocked { ! 3579: IN struct vnode *vp; ! 3580: ! 3581: */ ! 3582: int ! 3583: hfs_islocked(ap) ! 3584: struct vop_islocked_args /* { ! 3585: struct vnode *a_vp; ! 3586: } */ *ap; ! 3587: { ! 3588: int lockStatus; ! 3589: //DBG_FUNC_NAME("islocked"); ! 3590: //DBG_VOP_LOCKS_DECL(1); ! 3591: //DBG_VOP_PRINT_FUNCNAME(); ! 3592: //DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); ! 3593: ! 3594: //DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_IGNORE, VOPDBG_ZERO); ! 3595: ! 3596: lockStatus = lockstatus(&VTOH( ap->a_vp)->h_lock); ! 3597: //DBG_VOP_LOCKS_TEST(E_NONE); ! 3598: return (lockStatus); ! 3599: } ! 3600: ! 3601: /* ! 3602: ! 3603: #% pathconf vp L L L ! 3604: # ! 3605: vop_pathconf { ! 3606: IN struct vnode *vp; ! 3607: IN int name; ! 3608: OUT register_t *retval; ! 3609: ! 3610: */ ! 3611: static int ! 3612: hfs_pathconf(ap) ! 3613: struct vop_pathconf_args /* { ! 3614: struct vnode *a_vp; ! 3615: int a_name; ! 3616: int *a_retval; ! 3617: } */ *ap; ! 3618: { ! 3619: int retval = E_NONE; ! 3620: DBG_FUNC_NAME("pathconf"); ! 3621: DBG_VOP_LOCKS_DECL(1); ! 3622: DBG_VOP_PRINT_FUNCNAME(); ! 3623: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp); ! 3624: ! 3625: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_POS); ! 3626: ! 3627: DBG_HFS_NODE_CHECK (ap->a_vp); ! 3628: ! 3629: switch (ap->a_name) { ! 3630: case _PC_LINK_MAX: ! 3631: *ap->a_retval = 1; ! 3632: break; ! 3633: case _PC_NAME_MAX: ! 3634: *ap->a_retval = NAME_MAX; ! 3635: break; ! 3636: case _PC_PATH_MAX: ! 3637: *ap->a_retval = PATH_MAX; /* 1024 */ ! 3638: break; ! 3639: case _PC_CHOWN_RESTRICTED: ! 3640: *ap->a_retval = 1; ! 3641: break; ! 3642: case _PC_NO_TRUNC: ! 3643: *ap->a_retval = 0; ! 3644: break; ! 3645: default: ! 3646: retval = EINVAL; ! 3647: } ! 3648: ! 3649: DBG_VOP_LOCKS_TEST(retval); ! 3650: return (retval); ! 3651: } ! 3652: ! 3653: ! 3654: ! 3655: ! 3656: ! 3657: /* ! 3658: * Advisory record locking support ! 3659: #% advlock vp U U U ! 3660: # ! 3661: vop_advlock { ! 3662: IN struct vnode *vp; ! 3663: IN caddr_t id; ! 3664: IN int op; ! 3665: IN struct flock *fl; ! 3666: IN int flags; ! 3667: ! 3668: */ ! 3669: int ! 3670: hfs_advlock(ap) ! 3671: struct vop_advlock_args /* { ! 3672: struct vnode *a_vp; ! 3673: caddr_t a_id; ! 3674: int a_op; ! 3675: struct flock *a_fl; ! 3676: int a_flags; ! 3677: } */ *ap; ! 3678: { ! 3679: register struct hfsnode *hp = VTOH(ap->a_vp); ! 3680: register struct flock *fl = ap->a_fl; ! 3681: register struct hfslockf *lock; ! 3682: off_t start, end; ! 3683: int retval; ! 3684: DBG_FUNC_NAME("advlock"); ! 3685: DBG_VOP_LOCKS_DECL(1); ! 3686: DBG_VOP_PRINT_FUNCNAME(); ! 3687: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP(("\n")); ! 3688: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_UNLOCKED, VOPDBG_POS); ! 3689: /* ! 3690: * Avoid the common case of unlocking when inode has no locks. ! 3691: */ ! 3692: if (hp->h_lockf == (struct hfslockf *)0) { ! 3693: if (ap->a_op != F_SETLK) { ! 3694: fl->l_type = F_UNLCK; ! 3695: return (0); ! 3696: } ! 3697: } ! 3698: /* ! 3699: * Convert the flock structure into a start and end. ! 3700: */ ! 3701: start = 0; ! 3702: switch (fl->l_whence) { ! 3703: case SEEK_SET: ! 3704: case SEEK_CUR: ! 3705: /* ! 3706: * Caller is responsible for adding any necessary offset ! 3707: * when SEEK_CUR is used. ! 3708: */ ! 3709: start = fl->l_start; ! 3710: break; ! 3711: ! 3712: case SEEK_END: ! 3713: start = HTOFCB(hp)->fcbEOF + fl->l_start; ! 3714: break; ! 3715: ! 3716: default: ! 3717: return (EINVAL); ! 3718: } ! 3719: ! 3720: if (start < 0) ! 3721: return (EINVAL); ! 3722: if (fl->l_len == 0) ! 3723: end = -1; ! 3724: else ! 3725: end = start + fl->l_len - 1; ! 3726: ! 3727: /* ! 3728: * Create the hfslockf structure ! 3729: */ ! 3730: MALLOC(lock, struct hfslockf *, sizeof *lock, M_LOCKF, M_WAITOK); ! 3731: lock->lf_start = start; ! 3732: lock->lf_end = end; ! 3733: lock->lf_id = ap->a_id; ! 3734: lock->lf_hfsnode = hp; ! 3735: lock->lf_type = fl->l_type; ! 3736: lock->lf_next = (struct hfslockf *)0; ! 3737: TAILQ_INIT(&lock->lf_blkhd); ! 3738: lock->lf_flags = ap->a_flags; ! 3739: /* ! 3740: * Do the requested operation. ! 3741: */ ! 3742: switch(ap->a_op) { ! 3743: case F_SETLK: ! 3744: retval = hfs_setlock(lock); ! 3745: break; ! 3746: ! 3747: case F_UNLCK: ! 3748: retval = hfs_clearlock(lock); ! 3749: FREE(lock, M_LOCKF); ! 3750: break; ! 3751: ! 3752: case F_GETLK: ! 3753: retval = hfs_getlock(lock, fl); ! 3754: FREE(lock, M_LOCKF); ! 3755: break; ! 3756: ! 3757: default: ! 3758: retval = EINVAL; ! 3759: _FREE(lock, M_LOCKF); ! 3760: break; ! 3761: } ! 3762: ! 3763: DBG_VOP_LOCKS_TEST(retval); ! 3764: return (retval); ! 3765: } ! 3766: ! 3767: ! 3768: ! 3769: /* ! 3770: * Update the access, modified, and node change times as specified by the ! 3771: * IACCESS, IUPDATE, and ICHANGE flags respectively. The IMODIFIED flag is ! 3772: * used to specify that the node needs to be updated but that the times have ! 3773: * already been set. The access and modified times are taken from the second ! 3774: * and third parameters; the node change time is always taken from the current ! 3775: * time. If waitfor is set, then wait for the disk write of the node to ! 3776: * complete. ! 3777: */ ! 3778: /* ! 3779: #% update vp L L L ! 3780: IN struct vnode *vp; ! 3781: IN struct timeval *access; ! 3782: IN struct timeval *modify; ! 3783: IN int waitfor; ! 3784: */ ! 3785: ! 3786: int ! 3787: hfs_update(ap) ! 3788: struct vop_update_args /* { ! 3789: struct vnode *a_vp; ! 3790: struct timeval *a_access; ! 3791: struct timeval *a_modify; ! 3792: int a_waitfor; ! 3793: } */ *ap; ! 3794: { ! 3795: struct hfsnode *hp; ! 3796: struct proc *p; ! 3797: CatalogNodeData nodeData; ! 3798: FSSpec nodeSpec; /* 264 bytes */ ! 3799: int retval; ! 3800: DBG_FUNC_NAME("update"); ! 3801: DBG_VOP_LOCKS_DECL(1); ! 3802: DBG_VOP_PRINT_FUNCNAME(); ! 3803: DBG_VOP_PRINT_VNODE_INFO(ap->a_vp);DBG_VOP_CONT(("\n")); ! 3804: DBG_VOP_LOCKS_INIT(0,ap->a_vp, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_LOCKED, VOPDBG_ZERO); ! 3805: ! 3806: hp = VTOH(ap->a_vp); ! 3807: ! 3808: DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0); ! 3809: DBG_ASSERT(ap->a_vp->v_type != VCPLX); ! 3810: if (ap->a_vp->v_type == VCPLX) { //XXX SER Shoulf never be true, change to a panic before ship ! 3811: DBG_VOP_LOCKS_TEST(0); ! 3812: return (0); ! 3813: }; ! 3814: ! 3815: if (H_FORKTYPE(hp) == kSysFile) { ! 3816: hp->h_meta->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); ! 3817: DBG_VOP_LOCKS_TEST(0); ! 3818: return (0); ! 3819: } ! 3820: ! 3821: if (VTOVFS(ap->a_vp)->mnt_flag & MNT_RDONLY) { ! 3822: hp->h_meta->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); ! 3823: DBG_VOP_LOCKS_TEST(0); ! 3824: DBG_VOP(("hfs_update: returning 0 (all flags were cleared because the volume is read-only.\n")); ! 3825: return (0); ! 3826: } ! 3827: ! 3828: /* Check to see if MacOS set the fcb to be dirty, if so, translate it to IN_MODIFIED */ ! 3829: if (HTOFCB(hp)->fcbFlags &fcbModifiedMask) ! 3830: hp->h_meta->h_nodeflags |= IN_MODIFIED; ! 3831: ! 3832: if ((hp->h_meta->h_nodeflags & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0) { ! 3833: DBG_VOP_LOCKS_TEST(0); ! 3834: DBG_VOP(("hfs_update: returning 0 because the metadata is unchanged.\n")); ! 3835: return (0); ! 3836: }; ! 3837: ! 3838: if (hp->h_meta->h_nodeflags & IN_ACCESS) ! 3839: hp->h_meta->h_atime = ap->a_access->tv_sec; ! 3840: if (hp->h_meta->h_nodeflags & IN_UPDATE) ! 3841: hp->h_meta->h_mtime = ap->a_modify->tv_sec; ! 3842: if (hp->h_meta->h_nodeflags & IN_CHANGE) { ! 3843: hp->h_meta->h_ctime = time.tv_sec; ! 3844: /* ! 3845: * HFS dates that WE set must be adjusted for DST ! 3846: */ ! 3847: if ((HTOVCB(hp)->vcbSigWord == kHFSSigWord) && gTimeZone.tz_dsttime) { ! 3848: hp->h_meta->h_ctime += 3600; ! 3849: hp->h_meta->h_mtime = hp->h_meta->h_ctime; ! 3850: } ! 3851: } ! 3852: ! 3853: p = CURRENT_PROC; ! 3854: /* ! 3855: * Since VOP_UPDATE can be called from withing another VOP (eg VOP_RENAME), ! 3856: * the Catalog b-tree may aready be locked by the current thread. So we ! 3857: * allow recursive locking of the Catalog from within VOP_UPDATE. ! 3858: */ ! 3859: ! 3860: /* Lock the Catalog b-tree file */ ! 3861: retval = hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_EXCLUSIVE | LK_CANRECURSE, p); ! 3862: if (retval) { ! 3863: DBG_VOP_LOCKS_TEST(retval); ! 3864: DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0); ! 3865: return (retval); ! 3866: }; ! 3867: DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0); ! 3868: ! 3869: retval = GetCatalogNode(HTOVCB(hp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &nodeSpec, &nodeData, &(H_HINT(hp))); ! 3870: if (retval != noErr) { ! 3871: DBG_ERR(("hfs_update: error %d on GetCatalogNode...\n", retval)); ! 3872: retval = MacToVFSError(retval); ! 3873: goto exit_relse; ! 3874: }; ! 3875: ! 3876: /* If there is a sibling (resource fork), copy its contents first */ ! 3877: /* This makes sure all changes in the FCB are reflected. i.e. LEOF, etc */ ! 3878: if (hp->h_sibling) ! 3879: CopyVNodeToCatalogNode (hp->h_sibling, &nodeData); ! 3880: ! 3881: CopyVNodeToCatalogNode (HTOV(hp), &nodeData); ! 3882: ! 3883: retval = UpdateCatalogNode(HTOVCB(hp), H_DIRID(hp), H_NAME(hp), H_HINT(hp), &nodeData); ! 3884: if (retval != noErr) { ! 3885: DBG_ERR(("hfs_update: error %d on UpdateCatalogNode...\n", retval)); ! 3886: retval = MacToVFSError(retval); ! 3887: goto exit_relse; ! 3888: }; ! 3889: ! 3890: /* After the updates are finished, clear the flags */ ! 3891: hp->h_meta->h_nodeflags &= ~(IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE); ! 3892: HTOFCB(hp)->fcbFlags &= ~fcbModifiedMask; ! 3893: ! 3894: /* Update general data */ ! 3895: if (ap->a_vp->v_type == VDIR) { ! 3896: hp->h_size = sizeof (hfsdirentry) * (nodeData.valence + 2); ! 3897: } ! 3898: else { ! 3899: hp->h_size = nodeData.rsrcPhysicalSize + nodeData.dataPhysicalSize; ! 3900: } ! 3901: ! 3902: ! 3903: exit_relse: ! 3904: /* unlock the Catalog b-tree file */ ! 3905: (void) hfs_metafilelocking(HTOHFS(hp), kHFSCatalogFileID, LK_RELEASE, p); ! 3906: ! 3907: DBG_VOP(("hfs_update: returning %d.\n", retval)); ! 3908: DBG_VOP_LOCKS_TEST(retval); ! 3909: DBG_ASSERT(*((int*)&ap->a_vp->v_interlock) == 0); ! 3910: return (retval); ! 3911: } ! 3912: ! 3913: ! 3914: ! 3915: ! 3916: /* ! 3917: * Allocate a new node ! 3918: * ! 3919: * Assumes that the catalog b-tree is locked ! 3920: * ! 3921: * Upon leaving, namei buffer must be freed. ! 3922: * ! 3923: */ ! 3924: static int ! 3925: hfs_makenode(mode, dvp, vpp, cnp) ! 3926: int mode; ! 3927: struct vnode *dvp; ! 3928: struct vnode **vpp; ! 3929: struct componentname *cnp; ! 3930: { ! 3931: register struct hfsnode *hp, *parhp; ! 3932: struct timeval tv; ! 3933: struct vnode *tvp; ! 3934: struct hfsCatalogInfo catInfo; ! 3935: ExtendedVCB *vcb; ! 3936: UInt8 forkType; ! 3937: int retval; ! 3938: DBG_FUNC_NAME("makenode"); ! 3939: ! 3940: parhp = VTOH(dvp); ! 3941: vcb = HTOVCB(parhp); ! 3942: *vpp = NULL; ! 3943: tvp = NULL; ! 3944: if ((mode & IFMT) == 0) ! 3945: mode |= IFREG; ! 3946: ! 3947: #if DIAGNOSTIC ! 3948: if ((cnp->cn_flags & HASBUF) == 0) ! 3949: panic("hfs_makenode: no name"); ! 3950: #endif ! 3951: ! 3952: /* Create the Catalog B*-Tree entry */ ! 3953: retval = hfsCreate(vcb, H_FILEID(parhp), cnp->cn_nameptr, mode); ! 3954: if (retval != E_NONE) { ! 3955: DBG_ERR(("%s: hfsCreate FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp))); ! 3956: goto bad1; ! 3957: } ! 3958: ! 3959: /* Look up the catalog entry just created: */ ! 3960: retval = hfsLookup(vcb, H_FILEID(parhp), cnp->cn_nameptr, cnp->cn_namelen, 0, &catInfo); ! 3961: if (retval != E_NONE) { ! 3962: DBG_ERR(("%s: hfsLookup FAILED: %s, %s\n", funcname, cnp->cn_nameptr, H_NAME(parhp))); ! 3963: goto bad1; ! 3964: } ! 3965: ! 3966: /* Create a vnode for the object just created: */ ! 3967: forkType = (catInfo.nodeData.nodeType == kCatalogFolderNode) ? kDirCmplx : kDataFork; ! 3968: if ((retval = hfsGet(vcb, &catInfo, forkType, dvp, &tvp))) { ! 3969: goto bad1; ! 3970: } ! 3971: ! 3972: /* Set other vnode values not init'd in getnewvnode(). */ ! 3973: tvp->v_type = IFTOVT(mode); ! 3974: ! 3975: /* reinit hp from the passed in mode, only if hfsplus */ ! 3976: if (vcb->vcbSigWord == kHFSPlusSigWord) { ! 3977: hp = VTOH(tvp); ! 3978: hp->h_meta->h_gid = parhp->h_meta->h_gid; ! 3979: if ((mode & IFMT) == IFLNK) ! 3980: hp->h_meta->h_uid = parhp->h_meta->h_uid; ! 3981: else ! 3982: hp->h_meta->h_uid = cnp->cn_cred->cr_uid; ! 3983: ! 3984: hp->h_meta->h_nodeflags &= ~IN_UNSETACCESS; ! 3985: hp->h_meta->h_nodeflags |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ! 3986: ! 3987: hp->h_meta->h_mode = mode; ! 3988: if ((hp->h_meta->h_mode & ISGID) && !groupmember(hp->h_meta->h_gid, cnp->cn_cred) && ! 3989: suser(cnp->cn_cred, NULL)) ! 3990: hp->h_meta->h_mode &= ~ISGID; ! 3991: ! 3992: if (cnp->cn_flags & ISWHITEOUT) ! 3993: hp->h_meta->h_pflags |= UF_OPAQUE; ! 3994: ! 3995: /* Write out the new values */ ! 3996: tv = time; ! 3997: if ((retval = VOP_UPDATE(tvp, &tv, &tv, 1))) ! 3998: goto bad2; ! 3999: } ! 4000: ! 4001: VTOH(dvp)->h_meta->h_nodeflags |= IN_CHANGE | IN_UPDATE; ! 4002: tv = time; ! 4003: if ((retval = VOP_UPDATE(dvp, &tv, &tv, 1))) ! 4004: goto bad2; ! 4005: ! 4006: if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { ! 4007: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); ! 4008: }; ! 4009: VPUT(dvp); ! 4010: #if MACH_NBC ! 4011: if ((tvp->v_type == VREG) && !(tvp->v_vm_info)){ ! 4012: vm_info_init(tvp); ! 4013: } ! 4014: #endif /* MACH_NBC */ ! 4015: *vpp = tvp; ! 4016: return (0); ! 4017: ! 4018: bad2: ! 4019: /* ! 4020: * Write retval occurred trying to update the node ! 4021: * or the directory so must deallocate the node. ! 4022: */ ! 4023: /* XXX SER In the future maybe set *vpp to 0xdeadbeef for testing */ ! 4024: VPUT(tvp); ! 4025: ! 4026: bad1: ! 4027: if ((cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) { ! 4028: FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI); ! 4029: }; ! 4030: VPUT(dvp); ! 4031: ! 4032: return (retval); ! 4033: ! 4034: } ! 4035: ! 4036: ! 4037: /************************************************************************/ ! 4038: /* Entry for searchfs() */ ! 4039: /************************************************************************/ ! 4040: ! 4041: #define errSearchBufferFull 101 // Internal search errors ! 4042: /* ! 4043: # ! 4044: #% searchfs vp L L L ! 4045: # ! 4046: vop_searchfs { ! 4047: IN struct vnode *vp; ! 4048: IN off_t length; ! 4049: IN int flags; ! 4050: IN struct ucred *cred; ! 4051: IN struct proc *p; ! 4052: }; ! 4053: */ ! 4054: ! 4055: //XXX Optimize this call for calls being made from VDI ! 4056: int hfs_search( ap ) ! 4057: struct vop_searchfs_args *ap; /* ! 4058: struct vnodeop_desc *a_desc; ! 4059: struct vnode *a_vp; ! 4060: void *a_searchparams1; ! 4061: void *a_searchparams2; ! 4062: struct attrlist *a_searchattrs; ! 4063: u_long a_maxmatches; ! 4064: struct timeval *a_timelimit; ! 4065: struct attrlist *a_returnattrs; ! 4066: u_long *a_nummatches; ! 4067: u_long a_scriptcode; ! 4068: u_long a_options; ! 4069: struct uio *a_uio; ! 4070: struct searchstate *a_searchstate; ! 4071: */ ! 4072: { ! 4073: CatalogRecord catalogRecord; ! 4074: BTreeKey *key; ! 4075: FSBufferDescriptor btRecord; ! 4076: FCB* catalogFCB; ! 4077: SearchState *searchState; ! 4078: searchinfospec_t searchInfo1; ! 4079: searchinfospec_t searchInfo2; ! 4080: void *attributesBuffer; ! 4081: void *variableBuffer; ! 4082: short recordSize; ! 4083: short operation; ! 4084: u_long fixedBlockSize; ! 4085: u_long eachReturnBufferSize; ! 4086: struct proc *p = CURRENT_PROC; ! 4087: u_long nodesToCheck = 30; // After we search 30 nodes we must give up time ! 4088: u_long lastNodeNum = 0XFFFFFFFF; ! 4089: ExtendedVCB *vcb = VTOVCB(ap->a_vp); ! 4090: int err = E_NONE; ! 4091: ! 4092: DBG_FUNC_NAME("hfs_search"); ! 4093: DBG_VOP_LOCKS_DECL(1); ! 4094: ! 4095: //XXX Parameter check a_searchattrs ! 4096: ! 4097: *(ap->a_nummatches) = 0; ! 4098: ! 4099: if ( ap->a_options & ~SRCHFS_VALIDOPTIONSMASK ) ! 4100: return( EINVAL ); ! 4101: ! 4102: if (ap->a_uio->uio_resid <= 0) ! 4103: return (EINVAL); ! 4104: ! 4105: searchState = (SearchState *)ap->a_searchstate; ! 4106: ! 4107: // Check if this is the first time we are being called. ! 4108: // If it is, allocate SearchState and we'll move it to the users space on exit ! 4109: if ( ap->a_options & SRCHFS_START ) ! 4110: { ! 4111: bzero( (caddr_t)searchState, sizeof(SearchState) ); ! 4112: searchState->isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord ); ! 4113: operation = kBTreeFirstRecord; ! 4114: ap->a_options &= ~SRCHFS_START; // clear the bit ! 4115: } ! 4116: else ! 4117: { ! 4118: operation = kBTreeCurrentRecord; ! 4119: } ! 4120: ! 4121: // UnPack the search boundries, searchInfo1, searchInfo2 ! 4122: err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo1, ap->a_searchparams1 ); ! 4123: if (err) return err; ! 4124: err = UnpackSearchAttributeBlock( ap->a_vp, ap->a_searchattrs, &searchInfo2, ap->a_searchparams2 ); ! 4125: if (err) return err; ! 4126: ! 4127: btRecord.itemCount = 1; ! 4128: btRecord.itemSize = sizeof( catalogRecord ); ! 4129: btRecord.bufferAddress = &catalogRecord; ! 4130: catalogFCB = VTOFCB( vcb->catalogRefNum ); ! 4131: key = (BTreeKey*) &(searchState->btreeIterator.key); ! 4132: fixedBlockSize = sizeof(u_long) + AttributeBlockSize( ap->a_returnattrs ); /* u_long for length longword */ ! 4133: eachReturnBufferSize = fixedBlockSize; ! 4134: ! 4135: if ( ap->a_returnattrs->commonattr & ATTR_CMN_NAME ) //XXX should be more robust ! 4136: eachReturnBufferSize += NAME_MAX + 1; ! 4137: ! 4138: MALLOC( attributesBuffer, void *, eachReturnBufferSize, M_TEMP, M_WAITOK ); ! 4139: variableBuffer = attributesBuffer + fixedBlockSize; ! 4140: ! 4141: // Lock catalog b-tree ! 4142: err = hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_SHARED, p ); ! 4143: if ( err != E_NONE ) ! 4144: { ! 4145: DBG_VOP_LOCKS_TEST( err ); ! 4146: goto ExitThisRoutine; ! 4147: }; ! 4148: ! 4149: // ! 4150: // Iterate over all the catalog btree records ! 4151: // ! 4152: ! 4153: err = BTIterateRecord( catalogFCB, operation, &(searchState->btreeIterator), &btRecord, &recordSize ); ! 4154: ! 4155: while( err == E_NONE ) ! 4156: { ! 4157: if ( CheckCriteria( vcb, searchState, ap->a_options, ap->a_searchattrs, &catalogRecord, (CatalogKey *)key, &searchInfo1, &searchInfo2 ) == true ) ! 4158: { ! 4159: err = InsertMatch( ap->a_vp, ap->a_uio, &catalogRecord, (CatalogKey *)key, ap->a_returnattrs, attributesBuffer, variableBuffer, eachReturnBufferSize, ap->a_nummatches ); ! 4160: if ( err != E_NONE ) ! 4161: break; ! 4162: } ! 4163: ! 4164: err = BTIterateRecord( catalogFCB, kBTreeNextRecord, &(searchState->btreeIterator), &btRecord, &recordSize ); ! 4165: ! 4166: if ( *(ap->a_nummatches) >= ap->a_maxmatches ) ! 4167: break; ! 4168: ! 4169: if ( searchState->btreeIterator.hint.nodeNum != lastNodeNum ) ! 4170: { ! 4171: lastNodeNum = searchState->btreeIterator.hint.nodeNum; ! 4172: if ( --nodesToCheck == 0 ) ! 4173: break; // We must leave the kernel to give up time ! 4174: } ! 4175: } ! 4176: ! 4177: // Unlock catalog b-tree ! 4178: (void) hfs_metafilelocking( VTOHFS(ap->a_vp), kHFSCatalogFileID, LK_RELEASE, p ); ! 4179: ! 4180: ! 4181: if ( err == E_NONE ) ! 4182: { ! 4183: err = EAGAIN; // signal to the user to call searchfs again ! 4184: } ! 4185: else if ( err == errSearchBufferFull ) ! 4186: { ! 4187: if ( *(ap->a_nummatches) > 0 ) ! 4188: err = EAGAIN; ! 4189: else ! 4190: err = ENOBUFS; ! 4191: } ! 4192: else if ( err == btNotFound ) ! 4193: { ! 4194: err = E_NONE; // the entire disk has been searched ! 4195: } ! 4196: ! 4197: ExitThisRoutine: ! 4198: FREE( attributesBuffer, M_TEMP ); ! 4199: ! 4200: return( err ); ! 4201: } ! 4202: ! 4203: ! 4204: static Boolean ! 4205: ComparePartialUnicodeName ( register ConstUniCharArrayPtr str, register ItemCount s_len, ! 4206: register ConstUniCharArrayPtr find, register ItemCount f_len ) ! 4207: { ! 4208: if (f_len == 0 || s_len == 0) ! 4209: return FALSE; ! 4210: ! 4211: do { ! 4212: if (s_len-- < f_len) ! 4213: return FALSE; ! 4214: } while (FastUnicodeCompare(str++, f_len, find, f_len) != 0); ! 4215: ! 4216: return TRUE; ! 4217: } ! 4218: ! 4219: ! 4220: static Boolean ! 4221: ComparePartialPascalName ( register ConstStr31Param str, register ConstStr31Param find ) ! 4222: { ! 4223: register u_char s_len = str[0]; ! 4224: register u_char f_len = find[0]; ! 4225: register u_char *tsp; ! 4226: Str31 tmpstr; ! 4227: ! 4228: if (f_len == 0 || s_len == 0) ! 4229: return FALSE; ! 4230: ! 4231: bcopy(str, tmpstr, s_len + 1); ! 4232: tsp = &tmpstr[0]; ! 4233: ! 4234: while (s_len-- >= f_len) { ! 4235: *tsp = f_len; ! 4236: ! 4237: if (FastRelString(tsp++, find) == 0) ! 4238: return TRUE; ! 4239: } ! 4240: ! 4241: return FALSE; ! 4242: } ! 4243: ! 4244: // ! 4245: // CheckCriteria() ! 4246: // ! 4247: Boolean CheckCriteria( ExtendedVCB *vcb, const SearchState *searchState, u_long searchBits, ! 4248: struct attrlist *attrList, CatalogRecord *catalogRecord, CatalogKey *key, ! 4249: searchinfospec_t *searchInfo1, searchinfospec_t *searchInfo2 ) ! 4250: { ! 4251: Boolean matched; ! 4252: CatalogNodeData catData; ! 4253: attrgroup_t searchAttributes; ! 4254: ! 4255: switch ( catalogRecord->recordType ) ! 4256: { ! 4257: case kHFSFolderRecord: ! 4258: case kHFSPlusFolderRecord: ! 4259: if ( (searchBits & SRCHFS_MATCHDIRS) == 0 ) // If we are NOT searching folders ! 4260: { ! 4261: matched = false; ! 4262: goto TestDone; ! 4263: } ! 4264: break; ! 4265: ! 4266: case kHFSFileRecord: ! 4267: case kHFSPlusFileRecord: ! 4268: if ( (searchBits & SRCHFS_MATCHFILES) == 0 ) // If we are NOT searching files ! 4269: { ! 4270: matched = false; ! 4271: goto TestDone; ! 4272: } ! 4273: break; ! 4274: ! 4275: default: // Never match a thread record or any other type. ! 4276: return( false ); // Not a file or folder record, so can't search it ! 4277: } ! 4278: ! 4279: // Change the catalog record data into a single common form ! 4280: matched = true; // Assume we got a match ! 4281: catData.nodeType = 0; // mark this record as not in use ! 4282: CopyCatalogNodeData( vcb, catalogRecord, &catData ); ! 4283: ! 4284: /* First, attempt to match the name -- either partial or complete */ ! 4285: if ( attrList->commonattr & ATTR_CMN_NAME ) { ! 4286: if ( searchState->isHFSPlus ) { ! 4287: /* Check for partial/full HFS Plus name match */ ! 4288: ! 4289: if ( searchBits & SRCHFS_MATCHPARTIALNAMES ) { ! 4290: matched = ComparePartialUnicodeName( key->hfsPlus.nodeName.unicode, ! 4291: key->hfsPlus.nodeName.length, ! 4292: (UniChar*)searchInfo1->name, ! 4293: searchInfo1->nameLength ); ! 4294: } else /* full HFS Plus name match */ { ! 4295: matched = (FastUnicodeCompare( key->hfsPlus.nodeName.unicode, ! 4296: key->hfsPlus.nodeName.length, ! 4297: (UniChar*)searchInfo1->name, ! 4298: searchInfo1->nameLength ) == 0); ! 4299: } ! 4300: } else { ! 4301: /* Check for partial/full HFS name match */ ! 4302: ! 4303: if ( searchBits & SRCHFS_MATCHPARTIALNAMES ) ! 4304: matched = ComparePartialPascalName(key->hfs.nodeName, (u_char*)searchInfo1->name); ! 4305: else /* full HFS name match */ ! 4306: matched = (FastRelString(key->hfs.nodeName, (u_char*)searchInfo1->name) == 0); ! 4307: } ! 4308: ! 4309: if ( matched == false || (searchBits & ~SRCHFS_MATCHPARTIALNAMES) == 0 ) ! 4310: goto TestDone; /* no match, or nothing more to compare */ ! 4311: } ! 4312: ! 4313: ! 4314: // Now that we have a record worth searching, see if it matches the search attributes ! 4315: if ( (catData.nodeType == kCatalogFileNode) && ((attrList->fileattr & ATTR_FILE_VALIDMASK) != 0) ) ! 4316: { ! 4317: searchAttributes = attrList->fileattr; ! 4318: // ! 4319: // File logical length (data fork) ! 4320: // ! 4321: if ( searchAttributes & ATTR_FILE_DATALENGTH ) ! 4322: { ! 4323: matched = CompareRange( catData.dataLogicalSize, searchInfo1->f.dataLogicalLength, searchInfo2->f.dataLogicalLength ); ! 4324: if (matched == false) goto TestDone; ! 4325: } ! 4326: ! 4327: // ! 4328: // File physical length (data fork) ! 4329: // ! 4330: if ( searchAttributes & ATTR_FILE_DATAALLOCSIZE ) ! 4331: { ! 4332: matched = CompareRange( catData.dataPhysicalSize, searchInfo1->f.dataPhysicalLength, searchInfo2->f.dataPhysicalLength ); ! 4333: if (matched == false) goto TestDone; ! 4334: } ! 4335: ! 4336: // ! 4337: // File logical length (resource fork) ! 4338: // ! 4339: if ( searchAttributes & ATTR_FILE_RSRCLENGTH ) ! 4340: { ! 4341: matched = CompareRange( catData.rsrcLogicalSize, searchInfo1->f.resourceLogicalLength, searchInfo2->f.resourceLogicalLength ); ! 4342: if (matched == false) goto TestDone; ! 4343: } ! 4344: ! 4345: // ! 4346: // File physical length (resource fork) ! 4347: // ! 4348: if ( searchAttributes & ATTR_FILE_RSRCALLOCSIZE ) ! 4349: { ! 4350: matched = CompareRange( catData.rsrcPhysicalSize, searchInfo1->f.resourcePhysicalLength, searchInfo2->f.resourcePhysicalLength ); ! 4351: if (matched == false) goto TestDone; ! 4352: } ! 4353: ! 4354: // ! 4355: // File logical length (resource + data fork) ! 4356: // ! 4357: if ( searchAttributes & ATTR_FILE_TOTALSIZE ) ! 4358: { ! 4359: matched = CompareRange( catData.rsrcLogicalSize + catData.dataLogicalSize, ! 4360: searchInfo1->f.resourceLogicalLength + searchInfo1->f.dataLogicalLength, ! 4361: searchInfo2->f.resourceLogicalLength + searchInfo2->f.dataLogicalLength ); ! 4362: if (matched == false) goto TestDone; ! 4363: } ! 4364: ! 4365: // ! 4366: // File physical length (resource + data fork) ! 4367: // ! 4368: if ( searchAttributes & ATTR_FILE_TOTALSIZE ) ! 4369: { ! 4370: matched = CompareRange( catData.rsrcPhysicalSize + catData.dataPhysicalSize, ! 4371: searchInfo1->f.resourcePhysicalLength + searchInfo1->f.dataPhysicalLength, ! 4372: searchInfo2->f.resourcePhysicalLength + searchInfo2->f.dataPhysicalLength ); ! 4373: if (matched == false) goto TestDone; ! 4374: } ! 4375: } ! 4376: // ! 4377: // Check the directory attributes ! 4378: // ! 4379: else if ( (catData.nodeType == kCatalogFolderNode) && ((attrList->dirattr & ATTR_DIR_VALIDMASK) != 0) ) ! 4380: { ! 4381: searchAttributes = attrList->dirattr; ! 4382: ! 4383: // ! 4384: // Directory valence ! 4385: // ! 4386: if ( searchAttributes & ATTR_DIR_ENTRYCOUNT ) ! 4387: { ! 4388: matched = CompareRange( catData.valence, searchInfo1->d.numFiles, searchInfo2->d.numFiles ); ! 4389: if (matched == false) goto TestDone; ! 4390: } ! 4391: } ! 4392: ! 4393: // ! 4394: // Check the common attributes ! 4395: // ! 4396: searchAttributes = attrList->commonattr; ! 4397: if ( (searchAttributes & ATTR_CMN_VALIDMASK) != 0 ) ! 4398: { ! 4399: // ! 4400: // Parent ID ! 4401: // ! 4402: if ( searchAttributes & ATTR_CMN_PAROBJID ) ! 4403: { ! 4404: HFSCatalogNodeID parentID; ! 4405: ! 4406: if (searchState->isHFSPlus) ! 4407: parentID = key->hfsPlus.parentID; ! 4408: else ! 4409: parentID = key->hfs.parentID; ! 4410: ! 4411: matched = CompareRange( parentID, searchInfo1->parentDirID, searchInfo2->parentDirID ); ! 4412: if (matched == false) goto TestDone; ! 4413: } ! 4414: ! 4415: // ! 4416: // Finder Info & Extended Finder Info where extFinderInfo is last 32 bytes ! 4417: // ! 4418: if ( searchAttributes & ATTR_CMN_FNDRINFO ) ! 4419: { ! 4420: UInt32 *thisValue; ! 4421: thisValue = (UInt32 *) &catData.finderInfo[0]; ! 4422: ! 4423: // Note: ioFlFndrInfo and ioDrUsrWds have the same offset in search info, so ! 4424: // no need to test the object type here. ! 4425: matched = CompareMasked( thisValue, (UInt32 *) &searchInfo1->finderInfo, (UInt32 *) &searchInfo2->finderInfo, 8 ); // 8 * UInt32 ! 4426: if (matched == false) goto TestDone; ! 4427: } ! 4428: ! 4429: // ! 4430: // Create date ! 4431: // ! 4432: if ( searchAttributes & ATTR_CMN_CRTIME ) ! 4433: { ! 4434: matched = CompareRange( to_bsd_time(catData.createDate), searchInfo1->creationDate.tv_sec, searchInfo2->creationDate.tv_sec ); ! 4435: if (matched == false) goto TestDone; ! 4436: } ! 4437: ! 4438: // ! 4439: // Mod date ! 4440: // ! 4441: if ( searchAttributes & ATTR_CMN_MODTIME ) ! 4442: { ! 4443: matched = CompareRange( to_bsd_time(catData.contentModDate), searchInfo1->modificationDate.tv_sec, searchInfo2->modificationDate.tv_sec ); ! 4444: if (matched == false) goto TestDone; ! 4445: } ! 4446: ! 4447: // ! 4448: // Backup date ! 4449: // ! 4450: if ( searchAttributes & ATTR_CMN_BKUPTIME ) ! 4451: { ! 4452: matched = CompareRange( to_bsd_time(catData.backupDate), searchInfo1->lastBackupDate.tv_sec, searchInfo2->lastBackupDate.tv_sec ); ! 4453: if (matched == false) goto TestDone; ! 4454: } ! 4455: ! 4456: } ! 4457: ! 4458: ! 4459: TestDone: ! 4460: // ! 4461: // Finally, determine whether we need to negate the sense of the match (i.e. find ! 4462: // all objects that DON'T match). ! 4463: // ! 4464: if ( searchBits & SRCHFS_NEGATEPARAMS ) ! 4465: matched = !matched; ! 4466: ! 4467: return( matched ); ! 4468: } ! 4469: ! 4470: ! 4471: // ! 4472: // Adds another record to the packed array for output ! 4473: // ! 4474: static int InsertMatch( struct vnode *root_vp, struct uio *a_uio, CatalogRecord *catalogRecord, ! 4475: CatalogKey *key, struct attrlist *returnAttrList, void *attributesBuffer, ! 4476: void *variableBuffer, u_long bufferSize, u_long * nummatches ) ! 4477: { ! 4478: int err; ! 4479: void *rovingAttributesBuffer; ! 4480: void *rovingVariableBuffer; ! 4481: struct hfsCatalogInfo catalogInfo; ! 4482: u_long packedBufferSize; ! 4483: ExtendedVCB *vcb = VTOVCB(root_vp); ! 4484: Boolean isHFSPlus = vcb->vcbSigWord == kHFSPlusSigWord; ! 4485: ! 4486: rovingAttributesBuffer = attributesBuffer + sizeof(u_long); // Reserve space for length field ! 4487: rovingVariableBuffer = variableBuffer; ! 4488: ! 4489: CopyCatalogNodeData( vcb, catalogRecord, &catalogInfo.nodeData ); ! 4490: ! 4491: catalogInfo.spec.parID = isHFSPlus ? key->hfsPlus.parentID : key->hfs.parentID; ! 4492: ! 4493: if ( returnAttrList->commonattr & ATTR_CMN_NAME ) ! 4494: { ! 4495: u_long actualDstLen; ! 4496: ! 4497: /* Return result in UTF-8 */ ! 4498: if ( isHFSPlus ) { ! 4499: err = ConvertUnicodeToUTF8( key->hfsPlus.nodeName.length * sizeof(UniChar), ! 4500: key->hfsPlus.nodeName.unicode, ! 4501: sizeof(catalogInfo.spec.name), ! 4502: &actualDstLen, ! 4503: catalogInfo.spec.name); ! 4504: } else { ! 4505: err = ConvertMacRomanToUTF8( key->hfs.nodeName, ! 4506: sizeof(catalogInfo.spec.name), ! 4507: &actualDstLen, ! 4508: catalogInfo.spec.name); ! 4509: } ! 4510: } ! 4511: ! 4512: PackCatalogInfoAttributeBlock( returnAttrList,root_vp, &catalogInfo, &rovingAttributesBuffer, &rovingVariableBuffer ); ! 4513: ! 4514: packedBufferSize = rovingVariableBuffer - attributesBuffer; ! 4515: ! 4516: if ( packedBufferSize > a_uio->uio_resid ) ! 4517: return( errSearchBufferFull ); ! 4518: ! 4519: (* nummatches)++; ! 4520: ! 4521: *((u_long *)attributesBuffer) = packedBufferSize; // Store length of fixed + var block ! 4522: ! 4523: err = uiomove( (caddr_t)attributesBuffer, packedBufferSize, a_uio ); // XXX should be packedBufferSize ! 4524: ! 4525: if (err != E_NONE) ! 4526: DBG_ERR(("InsertMatch: error %d on uiomove.\n", err)); ! 4527: ! 4528: return( err ); ! 4529: } ! 4530: ! 4531: ! 4532: static int ! 4533: UnpackSearchAttributeBlock( struct vnode *vp, struct attrlist *alist, searchinfospec_t *searchInfo, void *attributeBuffer ) ! 4534: { ! 4535: attrgroup_t a; ! 4536: u_long bufferSize; ! 4537: ! 4538: ASSERT(searchInfo != NULL); ! 4539: ! 4540: bufferSize = *((u_long *)attributeBuffer); ! 4541: if (bufferSize == 0) ! 4542: return (EINVAL); /* XXX -DJB is a buffer size of zero ever valid for searchfs? */ ! 4543: ! 4544: ++((u_long *)attributeBuffer); // advance past the size ! 4545: ! 4546: // ! 4547: // UnPack common attributes ! 4548: // ! 4549: a = alist->commonattr; ! 4550: if ( a != 0 ) ! 4551: { ! 4552: if ( a & ATTR_CMN_NAME ) ! 4553: { ! 4554: char *s = attributeBuffer + ((attrreference_t *) attributeBuffer)->attr_dataoffset; ! 4555: size_t len = ((attrreference_t *) attributeBuffer)->attr_length; ! 4556: ! 4557: if (len > sizeof(searchInfo->name)) ! 4558: return (EINVAL); ! 4559: ! 4560: if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) { ! 4561: ByteCount actualDstLen; ! 4562: /* Convert name to Unicode to match HFS Plus B-Tree names */ ! 4563: ! 4564: if (len > 0) { ! 4565: if (ConvertUTF8ToUnicode(len-1, s, sizeof(searchInfo->name), ! 4566: &actualDstLen, (UniChar*)searchInfo->name) != 0) ! 4567: return (EINVAL); ! 4568: ! 4569: ! 4570: searchInfo->nameLength = actualDstLen / sizeof(UniChar); ! 4571: } else { ! 4572: searchInfo->nameLength = 0; ! 4573: } ! 4574: ++((attrreference_t *)attributeBuffer); ! 4575: ! 4576: } else { ! 4577: /* Convert name to pascal string to match HFS B-Tree names */ ! 4578: ! 4579: if (len > 0) { ! 4580: if (ConvertUTF8ToMacRoman(len-1, s, (u_char*)searchInfo->name) != 0) ! 4581: return (EINVAL); ! 4582: ! 4583: searchInfo->nameLength = searchInfo->name[0]; ! 4584: } else { ! 4585: searchInfo->name[0] = searchInfo->nameLength = 0; ! 4586: } ! 4587: ++((attrreference_t *)attributeBuffer); ! 4588: } ! 4589: } ! 4590: if ( a & ATTR_CMN_PAROBJID ) ! 4591: { ! 4592: searchInfo->parentDirID = ((fsobj_id_t *) attributeBuffer)->fid_objno; /* ignore fid_generation */ ! 4593: ++((fsobj_id_t *)attributeBuffer); ! 4594: } ! 4595: if ( a & ATTR_CMN_CRTIME ) ! 4596: { ! 4597: searchInfo->creationDate = *((struct timespec *)attributeBuffer); ! 4598: ++((struct timespec *)attributeBuffer); ! 4599: } ! 4600: if ( a & ATTR_CMN_MODTIME ) ! 4601: { ! 4602: searchInfo->modificationDate = *((struct timespec *)attributeBuffer); ! 4603: ++((struct timespec *)attributeBuffer); ! 4604: } ! 4605: if ( a & ATTR_CMN_BKUPTIME ) ! 4606: { ! 4607: searchInfo->lastBackupDate = *((struct timespec *)attributeBuffer); ! 4608: ++((struct timespec *)attributeBuffer); ! 4609: } ! 4610: if ( a & ATTR_CMN_FNDRINFO ) ! 4611: { ! 4612: bcopy( attributeBuffer, searchInfo->finderInfo, sizeof(u_long) * 8 ); ! 4613: attributeBuffer += (sizeof(u_long) * 8 ); ! 4614: } ! 4615: } ! 4616: ! 4617: a = alist->dirattr; ! 4618: if ( a != 0 ) ! 4619: { ! 4620: if ( a & ATTR_DIR_ENTRYCOUNT ) ! 4621: { ! 4622: searchInfo->d.numFiles = *((u_long *)attributeBuffer); ! 4623: ++((u_long *)attributeBuffer); ! 4624: } ! 4625: } ! 4626: ! 4627: a = alist->fileattr; ! 4628: if ( a != 0 ) ! 4629: { ! 4630: if ( a & ATTR_FILE_DATALENGTH ) ! 4631: { ! 4632: searchInfo->f.dataLogicalLength = *((off_t *)attributeBuffer); ! 4633: ++((off_t *)attributeBuffer); ! 4634: } ! 4635: if ( a & ATTR_FILE_DATAALLOCSIZE ) ! 4636: { ! 4637: searchInfo->f.dataPhysicalLength = *((off_t *)attributeBuffer); ! 4638: ++((off_t *)attributeBuffer); ! 4639: } ! 4640: if ( a & ATTR_FILE_RSRCLENGTH ) ! 4641: { ! 4642: searchInfo->f.resourceLogicalLength = *((off_t *)attributeBuffer); ! 4643: ++((off_t *)attributeBuffer); ! 4644: } ! 4645: if ( a & ATTR_FILE_RSRCALLOCSIZE ) ! 4646: { ! 4647: searchInfo->f.resourcePhysicalLength = *((off_t *)attributeBuffer); ! 4648: ++((off_t *)attributeBuffer); ! 4649: } ! 4650: } ! 4651: ! 4652: return (0); ! 4653: } ! 4654: ! 4655: ! 4656: ! 4657: ! 4658: #if DBG_VOP_TEST_LOCKS ! 4659: ! 4660: ! 4661: void DbgVopTest( int maxSlots, ! 4662: int retval, ! 4663: VopDbgStoreRec *VopDbgStore, ! 4664: char *funcname) ! 4665: { ! 4666: int index; ! 4667: ! 4668: for (index = 0; index < maxSlots; index++) ! 4669: { ! 4670: if (VopDbgStore[index].id != index) { ! 4671: DEBUG_BREAK_MSG(("%s: DBG_VOP_LOCK: invalid id field (%d) in target entry (#%d).\n", funcname, VopDbgStore[index].id, index)); ! 4672: }; ! 4673: ! 4674: if ((VopDbgStore[index].vp != NULL) && ! 4675: ((VopDbgStore[index].vp->v_data==NULL) || (VTOH(VopDbgStore[index].vp)->h_valid != HFS_VNODE_MAGIC))) ! 4676: continue; ! 4677: ! 4678: switch (VopDbgStore[index].inState) ! 4679: { ! 4680: case VOPDBG_IGNORE: ! 4681: case VOPDBG_SAME: ! 4682: /* Do Nothing !!! */ ! 4683: break; ! 4684: case VOPDBG_LOCKED: ! 4685: case VOPDBG_UNLOCKED: ! 4686: case VOPDBG_LOCKNOTNIL: ! 4687: { ! 4688: if (VopDbgStore[index].vp == NULL && (VopDbgStore[index].inState != VOPDBG_LOCKNOTNIL)) { ! 4689: DBG_ERR (("%s: InState check: Null vnode ptr in entry #%d\n", funcname, index)); ! 4690: } else if (VopDbgStore[index].vp != NULL) { ! 4691: switch (VopDbgStore[index].inState) ! 4692: { ! 4693: case VOPDBG_LOCKED: ! 4694: case VOPDBG_LOCKNOTNIL: ! 4695: if (VopDbgStore[index].inValue == 0) ! 4696: { ! 4697: kprintf ("%s: Entry: not LOCKED:", funcname); ! 4698: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n"); ! 4699: } ! 4700: break; ! 4701: case VOPDBG_UNLOCKED: ! 4702: if (VopDbgStore[index].inValue != 0) ! 4703: { ! 4704: kprintf ("%s: Entry: not UNLOCKED:", funcname); ! 4705: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n"); ! 4706: } ! 4707: break; ! 4708: } ! 4709: } ! 4710: break; ! 4711: } ! 4712: default: ! 4713: DBG_ERR (("%s: DBG_VOP_LOCK on entry: bad lock test value: %d\n", funcname, VopDbgStore[index].errState)); ! 4714: } ! 4715: ! 4716: ! 4717: if (retval != 0) ! 4718: { ! 4719: switch (VopDbgStore[index].errState) ! 4720: { ! 4721: case VOPDBG_IGNORE: ! 4722: /* Do Nothing !!! */ ! 4723: break; ! 4724: case VOPDBG_LOCKED: ! 4725: case VOPDBG_UNLOCKED: ! 4726: case VOPDBG_SAME: ! 4727: { ! 4728: if (VopDbgStore[index].vp == NULL) { ! 4729: DBG_ERR (("%s: ErrState check: Null vnode ptr in entry #%d\n", funcname, index)); ! 4730: } else { ! 4731: VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock); ! 4732: switch (VopDbgStore[index].errState) ! 4733: { ! 4734: case VOPDBG_LOCKED: ! 4735: if (VopDbgStore[index].outValue == 0) ! 4736: { ! 4737: kprintf ("%s: Error: not LOCKED:", funcname); ! 4738: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n"); ! 4739: } ! 4740: break; ! 4741: case VOPDBG_UNLOCKED: ! 4742: if (VopDbgStore[index].outValue != 0) ! 4743: { ! 4744: kprintf ("%s: Error: not UNLOCKED:", funcname); ! 4745: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n"); ! 4746: } ! 4747: break; ! 4748: case VOPDBG_SAME: ! 4749: if (VopDbgStore[index].outValue != VopDbgStore[index].inValue) ! 4750: DBG_ERR (("%s: Error: In/Out locks are DIFFERENT: 0x%x, inis %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue)); ! 4751: break; ! 4752: } ! 4753: } ! 4754: break; ! 4755: } ! 4756: case VOPDBG_LOCKNOTNIL: ! 4757: if (VopDbgStore[index].vp != NULL) { ! 4758: VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock); ! 4759: if (VopDbgStore[index].outValue == 0) ! 4760: DBG_ERR (("%s: Error: Not LOCKED: 0x%x\n", funcname, (u_int)VopDbgStore[index].vp)); ! 4761: } ! 4762: break; ! 4763: default: ! 4764: DBG_ERR (("%s: Error: bad lock test value: %d\n", funcname, VopDbgStore[index].errState)); ! 4765: } ! 4766: } ! 4767: else ! 4768: { ! 4769: switch (VopDbgStore[index].outState) ! 4770: { ! 4771: case VOPDBG_IGNORE: ! 4772: /* Do Nothing !!! */ ! 4773: break; ! 4774: case VOPDBG_LOCKED: ! 4775: case VOPDBG_UNLOCKED: ! 4776: case VOPDBG_SAME: ! 4777: if (VopDbgStore[index].vp == NULL) { ! 4778: DBG_ERR (("%s: OutState: Null vnode ptr in entry #%d\n", funcname, index)); ! 4779: }; ! 4780: if (VopDbgStore[index].vp != NULL) ! 4781: { ! 4782: VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock); ! 4783: switch (VopDbgStore[index].outState) ! 4784: { ! 4785: case VOPDBG_LOCKED: ! 4786: if (VopDbgStore[index].outValue == 0) ! 4787: { ! 4788: kprintf ("%s: Out: not LOCKED:", funcname); ! 4789: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n"); ! 4790: } ! 4791: break; ! 4792: case VOPDBG_UNLOCKED: ! 4793: if (VopDbgStore[index].outValue != 0) ! 4794: { ! 4795: kprintf ("%s: Out: not UNLOCKED:", funcname); ! 4796: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n"); ! 4797: } ! 4798: break; ! 4799: case VOPDBG_SAME: ! 4800: if (VopDbgStore[index].outValue != VopDbgStore[index].inValue) ! 4801: DBG_ERR (("%s: Out: In/Out locks are DIFFERENT: 0x%x, in is %d and out is %d\n", funcname, (u_int)VopDbgStore[index].vp, VopDbgStore[index].inValue, VopDbgStore[index].outValue)); ! 4802: break; ! 4803: } ! 4804: } ! 4805: break; ! 4806: case VOPDBG_LOCKNOTNIL: ! 4807: if (VopDbgStore[index].vp != NULL) { ! 4808: if (&VTOH(VopDbgStore[index].vp)->h_lock == NULL) { ! 4809: DBG_ERR (("%s: DBG_VOP_LOCK on out: Null lock on vnode 0x%x\n", funcname, (u_int)VopDbgStore[index].vp)); ! 4810: } ! 4811: else { ! 4812: VopDbgStore[index].outValue = lockstatus(&VTOH(VopDbgStore[index].vp)->h_lock); ! 4813: if (VopDbgStore[index].outValue == 0) ! 4814: { ! 4815: kprintf ("%s: DBG_VOP_LOCK on out: Should be LOCKED:", funcname); ! 4816: DBG_VOP_PRINT_VNODE_INFO(VopDbgStore[index].vp); kprintf ("\n"); ! 4817: } ! 4818: } ! 4819: } ! 4820: break; ! 4821: default: ! 4822: DBG_ERR (("%s: DBG_VOP_LOCK on out: bad lock test value: %d\n", funcname, VopDbgStore[index].outState)); ! 4823: } ! 4824: } ! 4825: ! 4826: VopDbgStore[index].id = -1; /* Invalidate the entry to allow panic-free re-use */ ! 4827: } ! 4828: } ! 4829: ! 4830: #endif /* DBG_VOP_TEST_LOCKS */ ! 4831: ! 4832: /***************************************************************************** ! 4833: * ! 4834: * VOP Table ! 4835: * ! 4836: *****************************************************************************/ ! 4837: ! 4838: ! 4839: struct vnodeopv_entry_desc hfs_vnodeop_entries[] = { ! 4840: { &vop_default_desc, vn_default_error }, ! 4841: { &vop_lookup_desc, hfs_lookup }, /* lookup */ ! 4842: { &vop_create_desc, hfs_create }, /* create */ ! 4843: { &vop_mknod_desc, err_mknod }, /* mknod (NOT SUPPORTED) */ ! 4844: { &vop_open_desc, hfs_open }, /* open */ ! 4845: { &vop_close_desc, hfs_close }, /* close */ ! 4846: { &vop_access_desc, hfs_access }, /* access */ ! 4847: { &vop_getattr_desc, hfs_getattr }, /* getattr */ ! 4848: { &vop_setattr_desc, hfs_setattr }, /* setattr */ ! 4849: { &vop_read_desc, hfs_read }, /* read */ ! 4850: { &vop_write_desc, hfs_write }, /* write */ ! 4851: { &vop_ioctl_desc, hfs_ioctl }, /* ioctl */ ! 4852: { &vop_select_desc, hfs_select }, /* select */ ! 4853: { &vop_exchange_desc, hfs_exchange }, /* exchange */ ! 4854: { &vop_mmap_desc, hfs_mmap }, /* mmap */ ! 4855: { &vop_fsync_desc, hfs_fsync }, /* fsync */ ! 4856: { &vop_seek_desc, hfs_seek }, /* seek */ ! 4857: { &vop_remove_desc, hfs_remove }, /* remove */ ! 4858: { &vop_link_desc, err_link }, /* link (NOT SUPPORTED) */ ! 4859: { &vop_rename_desc, hfs_rename }, /* rename */ ! 4860: { &vop_mkdir_desc, hfs_mkdir }, /* mkdir */ ! 4861: { &vop_rmdir_desc, hfs_rmdir }, /* rmdir */ ! 4862: { &vop_mkcomplex_desc,hfs_mkcomplex }, /* mkcomplex */ ! 4863: { &vop_getattrlist_desc,hfs_getattrlist }, /* getattrlist */ ! 4864: { &vop_setattrlist_desc,hfs_setattrlist }, /* setattrlist */ ! 4865: { &vop_symlink_desc, hfs_symlink }, /* symlink */ ! 4866: { &vop_readdir_desc, hfs_readdir }, /* readdir */ ! 4867: { &vop_readdirattr_desc, hfs_readdirattr }, /* readdirattr */ ! 4868: { &vop_readlink_desc, hfs_readlink }, /* readlink */ ! 4869: { &vop_abortop_desc, hfs_abortop }, /* abortop */ ! 4870: { &vop_inactive_desc, hfs_inactive }, /* inactive */ ! 4871: { &vop_reclaim_desc, hfs_reclaim }, /* reclaim */ ! 4872: { &vop_lock_desc, hfs_lock }, /* lock */ ! 4873: { &vop_unlock_desc, hfs_unlock }, /* unlock */ ! 4874: { &vop_bmap_desc, hfs_bmap }, /* bmap */ ! 4875: { &vop_strategy_desc, hfs_strategy }, /* strategy */ ! 4876: { &vop_print_desc, hfs_print }, /* print */ ! 4877: { &vop_islocked_desc, hfs_islocked }, /* islocked */ ! 4878: { &vop_pathconf_desc, hfs_pathconf }, /* pathconf */ ! 4879: { &vop_advlock_desc, hfs_advlock }, /* advlock */ ! 4880: { &vop_reallocblks_desc, hfs_reallocblks }, /* reallocblks */ ! 4881: { &vop_truncate_desc, hfs_truncate }, /* truncate */ ! 4882: { &vop_allocate_desc, hfs_allocate }, /* allocate */ ! 4883: { &vop_update_desc, hfs_update }, /* update */ ! 4884: { &vop_searchfs_desc,hfs_search }, /* search fs */ ! 4885: { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ ! 4886: { &vop_pagein_desc, hfs_pagein }, /* pagein */ ! 4887: { &vop_pageout_desc, hfs_pageout }, /* pageout */ ! 4888: { NULL, NULL } ! 4889: }; ! 4890: ! 4891: struct vnodeopv_desc hfs_vnodeop_opv_desc = ! 4892: { &hfs_vnodeop_p, hfs_vnodeop_entries };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.