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