|
|
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_vfsutils.c 4.0
23: *
24: * (c) 1997-2000 Apple Computer, Inc. All Rights Reserved
25: *
26: * hfs_vfsutils.c -- Routines that go between the HFS layer and the VFS.
27: *
28: * Change History (most recent first):
29: *
30: * 22-Jan-2000 Don Brady Remove calls to MountCheck.
31: * 7-Sep-1999 Don Brady Add HFS Plus hard-link support.
32: * 25-Aug-1999 Don Brady Dont't use vcbAlBlSt for HFS plus volumes (2350009).
33: * 9-Aug-1999 Pat Dirks Added support for ATTR_VOL_ENCODINGSUSED [#2357367].
34: * 16-Jul-1999 Pat Dirks Fixed PackCommonCatalogInfoAttributeBlock to return full range of possible vnode types [#2317604]
35: * 15-Jun-1999 Pat Dirks Added support for return of mounted device in hfs_getattrlist [#2345297].
36: * 9-Jun-1999 Don Brady Cleanup vcb accesses in hfs_MountHFSVolume.
37: * 3-Jun-1999 Don Brady Remove references to unused/legacy vcb fields (eg vcbXTClpSiz).
38: * 21-May-1999 Don Brady Add call to hfs_vinit in hfsGet to support mknod.
39: * 6-Apr-1999 Don Brady Fixed de-reference of NULL dvp in hfsGet.
40: * 22-Mar-1999 Don Brady Add support for UFS delete semantics.
41: * 1-Mar-1999 Scott Roberts Dont double MALLOC on long names.
42: * 23-Feb-1999 Pat Dirks Change incrementing of meta refcount to be done BEFORE lock is acquired.
43: * 2-Feb-1999 Pat Dirks For volume ATTR_CMN_SCRIPT use vcb->volumeNameEncodingHint instead of 0.
44: * 10-Mar-1999 Don Brady Removing obsolete code.
45: * 2-Feb-1999 Don Brady For volume ATTR_CMN_SCRIPT use vcb->volumeNameEncodingHint instead of 0.
46: * 18-Jan-1999 Pat Dirks Changed CopyCatalogToHFSNode to start with ACCESSPERMS instead of adding
47: * write access only for unlocked files (now handled via IMMUTABLE setting)
48: * 7-Dec-1998 Pat Dirks Changed PackCatalogInfoFileAttributeBlock to return proper I/O block size.
49: * 7-Dec-1998 Don Brady Pack the real text encoding instead of zero.
50: * 16-Dec-1998 Don Brady Use the root's crtime intead of vcb create time for getattrlist.
51: * 16-Dec-1998 Don Brady Use the root's crtime intead of vcb create time for getattrlist.
52: * 2-Dec-1998 Scott Roberts Copy the mdbVN correctly into the vcb.
53: * 3-Dec-1998 Pat Dirks Added support for ATTR_VOL_MOUNTFLAGS.
54: * 20-Nov-1998 Don Brady Add support for UTF-8 names.
55: * 18-Nov-1998 Pat Dirks Changed UnpackCommonAttributeBlock to call wait for hfs_chflags to update catalog entry when changing flags
56: * 13-Nov-1998 Pat Dirks Changed BestBlockSizeFit to try PAGE_SIZE only and skip check for MAXBSIZE.
57: * 10-Nov-1998 Pat Dirks Changed CopyCatalogToHFSNode to ensure consistency between lock flag and IMMUTABLE bits.
58: * 10-Nov-1998 Pat Dirks Added MapFileOffset(), LogicalBlockSize() and UpdateBlockMappingTable() routines.
59: * 18-Nov-1998 Pat Dirks Changed PackVolAttributeBlock to return proper logical block size
60: * for ATTR_VOL_IOBLOCKSIZE attribute.
61: * 3-Nov-1998 Umesh Vaishampayan Changes to deal with "struct timespec"
62: * change in the kernel.
63: * 23-Sep-1998 Don Brady In UnpackCommonAttributeBlock simplified setting of gid, uid and mode.
64: * 10-Nov-1998 Pat Dirks Added MapFileOffset(), LogicalBlockSize() and UpdateBlockMappingTable() routines.
65: * 17-Sep-1998 Pat Dirks Changed BestBlockSizeFit to try MAXBSIZE and PAGE_SIZE first.
66: * 8-Sep-1998 Don Brady Fix CopyVNodeToCatalogNode to use h_mtime for contentModDate (instead of h_ctime).
67: * 4-Sep-1998 Pat Dirks Added BestBlockSizeFit routine.
68: * 18-Aug-1998 Don Brady Change DEBUG_BREAK_MSG to a DBG_UTILS in MacToVFSError (radar #2262802).
69: * 30-Jun-1998 Don Brady Add calls to MacToVFSError to hfs/hfsplus mount routines (for radar #2249539).
70: * 22-Jun-1998 Don Brady Add more error cases to MacToVFSError; all HFS Common errors are negative.
71: * Changed hfsDelete to call DeleteFile for files.
72: * 4-Jun-1998 Pat Dirks Changed incorrect references to 'vcbAlBlkSize' to 'blockSize';
73: * Added hfsCreateFileID.
74: * 4-Jun-1998 Don Brady Add hfsMoveRename to replace hfsMove and hfsRename. Use VPUT/VRELE macros
75: * instead of vput/vrele to catch bad ref counts.
76: * 28-May-1998 Pat Dirks Adjusted for change in definition of ATTR_CMN_NAME and removed ATTR_CMN_RAWDEVICE.
77: * 7-May-1998 Don Brady Added check for NULL vp to hfs_metafilelocking (radar #2233832).
78: * 24-Apr-1998 Pat Dirks Fixed AttributeBlockSize to return only length of variable attribute block.
79: * 4/21/1998 Don Brady Add SUPPORTS_MAC_ALIASES conditional (for radar #2225419).
80: * 4/21/1998 Don Brady Map cmNotEmpty errors to ENOTEMPTY (radar #2229259).
81: * 4/21/1998 Don Brady Fix up time/date conversions.
82: * 4/20/1998 Don Brady Remove course-grained hfs metadata locking.
83: * 4/18/1998 Don Brady Add VCB locking.
84: * 4/17/1998 Pat Dirks Fixed PackFileAttributeBlock to return more up-to-date EOF/PEOF info from vnode.
85: * 4/15/1998 Don Brady Add hasOverflowExtents and hfs_metafilelocking. Use ExtendBTreeFile instead
86: * of SetEndOfForkProc. Set forktype for system files.
87: * 4/14/1998 Deric Horn PackCatalogInfoAttributeBlock(), and related packing routines to
88: * pack attribute data given hfsCatalogInfo, without the objects vnode;
89: * 4/14/1998 Scott Roberts Add execute priviledges to all hfs objects.
90: * 4/9/1998 Don Brady Add MDB/VolumeHeader flushing to hfsUnmount;
91: * 4/8/1998 Don Brady Make sure vcbVRefNum field gets initialized (use MAKE_VREFNUM).
92: * 4/6/1998 Don Brady Removed calls to CreateVolumeCatalogCache (obsolete).
93: * 4/06/1998 Scott Roberts Added complex file support.
94: * 4/02/1998 Don Brady UpdateCatalogNode now takes parID and name as input.
95: * 3/31/1998 Don Brady Sync up with final HFSVolumes.h header file.
96: * 3/31/1998 Don Brady Check result from UFSToHFSStr to make sure hfs/hfs+ names are not greater
97: * than 31 characters.
98: * 3/30/1998 Don Brady In InitMetaFileVNode set VSYSTEM bit in vnode's v_flag.
99: * 3/26/1998 Don Brady Cleaned up hfs_MountXXX routines. Removed CloseBtreeFile and OpenBTreeFile.
100: * Simplified hfsUnmount (removed MacOS specific code).
101: * 3/17/1998 Don Brady AttributeBlockSize calculation did not account for the size field (4bytes).
102: * PackVolCommonAttributes and PackCommonAttributeBlock for ATTR_CMN_NAME
103: * were not setting up the name correctly.
104: * 3/17/1998 Don Brady Changed CreateCatalogNode interface to take kCatalogFolderNode and
105: * kCatalogFileNode as type input. Also, force MountCheck to always run.
106: * 12-nov-1997 Scott Roberts Initially created file.
107: * 17-Mar-98 ser Broke out and created CopyCatalogToHFSNode()
108: *
109: */
110: #include <sys/param.h>
111: #include <sys/systm.h>
112: #include <sys/kernel.h>
113: #include <sys/malloc.h>
114: #include <sys/stat.h>
115: #include <sys/attr.h>
116: #include <sys/mount.h>
117: #include <sys/lock.h>
118: #include <kern/mapfs.h>
119:
120: #include "hfs.h"
121: #include "hfs_dbg.h"
122:
123: #include "hfscommon/headers/FileMgrInternal.h"
124: #include "hfscommon/headers/BTreesInternal.h"
125: #include "hfscommon/headers/HFSUnicodeWrappers.h"
126:
127: #define SUPPORTS_MAC_ALIASES 0
128: #define kMaxSecsForFsync 5
129:
130: #define BYPASSBLOCKINGOPTIMIZATION 0
131:
132: #define kMaxLockedMetaBuffers 32 /* number of locked buffer caches to hold for meta data */
133:
134: extern int (**hfs_vnodeop_p)();
135: extern int (**hfs_specop_p)();
136: extern int (**hfs_fifoop_p)();
137: extern int count_lock_queue __P((void));
138:
139: OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb );
140: UInt16 DivUp( UInt32 byteRun, UInt32 blockSize );
141:
142: /* Externs from vhash */
143: extern void hfs_vhashins_sibling(dev_t dev, UInt32 nodeID, struct hfsnode *hp, struct hfsfilemeta **fm);
144: extern void hfs_vhashins(dev_t dev, UInt32 nodeID,struct hfsnode *hp);
145: extern struct vnode *hfs_vhashget(dev_t dev, UInt32 nodeID, UInt8 forkType);
146:
147: extern int hfs_vinit( struct mount *mntp, int (**specops)(), int (**fifoops)(), struct vnode **vpp);
148: extern int readlinknode(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt32 *nodeID);
149:
150: extern UInt16 CountRootFiles(ExtendedVCB *vcb);
151: extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb);
152:
153: static int InitMetaFileVNode(struct vnode *vp, off_t eof, u_long clumpSize, const HFSPlusExtentRecord extents,
154: HFSCatalogNodeID fileID, void * keyCompareProc);
155:
156: static void ReleaseMetaFileVNode(struct vnode *vp);
157:
158: void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catalogInfo, struct vnode *vp, struct hfsfilemeta *fm);
159: void CopyCatalogToFCB(struct hfsCatalogInfo *catalogInfo, struct vnode *vp);
160: void hfs_set_metaname(char *name, struct hfsfilemeta *fm);
161: u_int32_t GetLogicalBlockSize(struct vnode *vp);
162:
163: /* BTree accessor routines */
164: extern OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block);
165: extern OSStatus SetBTreeBlockSize(FileReference vp, ByteCount blockSize, ItemCount minBlockCount);
166: extern OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF);
167: extern OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlockOptions options);
168:
169:
170: //*******************************************************************************
171: // Routine: hfs_MountHFSVolume
172: //
173: //
174: //*******************************************************************************
175:
176: OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb,
177: u_long sectors, struct proc *p)
178: {
179: ExtendedVCB *vcb = HFSTOVCB(hfsmp);
180: struct vnode *tmpvnode;
181: OSErr err;
182: HFSPlusExtentRecord extents;
183: DBG_FUNC_NAME("hfs_MountHFSVolume");
184: DBG_PRINT_FUNC_NAME();
185:
186: if (hfsmp == nil || mdb == nil) /* exit if bad paramater */
187: return (EINVAL);
188:
189: err = ValidMasterDirectoryBlock( mdb ); /* make sure this is an HFS disk */
190: if (err)
191: return MacToVFSError(err);
192:
193: /* don't mount volume if its dirty, it must be cleaned by fsck_hfs */
194: if ((mdb->drAtrb & kHFSVolumeUnmountedMask) == 0)
195: return (EINVAL);
196:
197: /*
198: * The MDB seems OK: transfer info from it into VCB
199: * Note - the VCB starts out clear (all zeros)
200: *
201: */
202:
203: DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0);
204: vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev);
205:
206: vcb->vcbSigWord = mdb->drSigWord;
207: vcb->vcbCrDate = LocalToUTC(mdb->drCrDate);
208: vcb->vcbLsMod = LocalToUTC(mdb->drLsMod);
209: vcb->vcbAtrb = mdb->drAtrb;
210: vcb->vcbNmFls = mdb->drNmFls;
211: vcb->vcbVBMSt = mdb->drVBMSt;
212: vcb->nextAllocation = mdb->drAllocPtr;
213: vcb->totalBlocks = mdb->drNmAlBlks;
214: vcb->blockSize = mdb->drAlBlkSiz;
215: vcb->vcbClpSiz = mdb->drClpSiz;
216: vcb->vcbAlBlSt= mdb->drAlBlSt;
217: vcb->vcbNxtCNID = mdb->drNxtCNID;
218: vcb->freeBlocks = mdb->drFreeBks;
219: vcb->vcbVolBkUp = LocalToUTC(mdb->drVolBkUp);
220: vcb->vcbVSeqNum = mdb->drVSeqNum;
221: vcb->vcbWrCnt = mdb->drWrCnt;
222: vcb->vcbNmRtDirs = mdb->drNmRtDirs;
223: vcb->vcbFilCnt = mdb->drFilCnt;
224: vcb->vcbDirCnt = mdb->drDirCnt;
225: bcopy(mdb->drFndrInfo, vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo));
226: vcb->nextAllocation = mdb->drAllocPtr;
227: vcb->encodingsBitmap = 0;
228: vcb->vcbWrCnt++; /* Compensate for write of MDB on last flush */
229: /*
230: * Copy the drVN field, which is a Pascal String to the vcb, which is a cstring
231: */
232:
233: /* XXX need to supply real UTF-8 string! */
234: bcopy( &mdb->drVN[1], vcb->vcbVN, mdb->drVN[0]);
235: vcb->vcbVN[mdb->drVN[0]] = '\0';
236:
237: vcb->altIDSector = sectors - 2;
238:
239: // Initialize our dirID/nodePtr cache associated with this volume.
240: err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
241: ReturnIfError( err );
242:
243: hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
244:
245: // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
246:
247:
248: VCB_LOCK_INIT(vcb);
249:
250: /*
251: * Set up Extents B-tree vnode...
252: */
253: err = GetInitializedVNode(hfsmp, &tmpvnode);
254: if (err) goto MtVolErr;
255: HFSToHFSPlusExtents(mdb->drXTExtRec, extents);
256: err = InitMetaFileVNode(tmpvnode, mdb->drXTFlSize, mdb->drXTClpSiz, extents,
257: kHFSExtentsFileID, CompareExtentKeys);
258: if (err) goto MtVolErr;
259:
260: /*
261: * Set up Catalog B-tree vnode...
262: */
263: err = GetInitializedVNode(hfsmp, &tmpvnode);
264: if (err) goto MtVolErr;
265: HFSToHFSPlusExtents(mdb->drCTExtRec, extents);
266: err = InitMetaFileVNode(tmpvnode, mdb->drCTFlSize, mdb->drCTClpSiz, extents,
267: kHFSCatalogFileID, CompareCatalogKeys);
268: if (err) goto MtVolErr;
269:
270: /* mark the volume dirty (clear clean unmount bit) */
271: vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask;
272:
273: /*
274: * all done with b-trees so we can unlock now...
275: */
276: VOP_UNLOCK(vcb->catalogRefNum, 0, p);
277: VOP_UNLOCK(vcb->extentsRefNum, 0, p);
278:
279: err = noErr;
280:
281: if ( err == noErr )
282: {
283: if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected
284: {
285: MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
286: }
287: }
288: goto CmdDone;
289:
290: //-- Release any resources allocated so far before exiting with an error:
291: MtVolErr:;
292: ReleaseMetaFileVNode(vcb->catalogRefNum);
293: ReleaseMetaFileVNode(vcb->extentsRefNum);
294:
295: CmdDone:;
296: return( err );
297:
298: }
299:
300: //*******************************************************************************
301: // Routine: hfs_MountHFSPlusVolume
302: //
303: //
304: //*******************************************************************************
305:
306: OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
307: u_long embBlkOffset, u_long sectors, struct proc *p)
308: {
309: register ExtendedVCB *vcb;
310: HFSPlusForkData *fdp;
311: struct vnode *tmpvnode;
312: OSErr retval;
313:
314: if (hfsmp == nil || vhp == nil) /* exit if bad paramater */
315: return (EINVAL);
316:
317: DBG_VFS(("hfs_MountHFSPlusVolume: signature=0x%x, version=%d, blockSize=%ld\n", vhp->signature, vhp->version, vhp->blockSize));
318:
319: retval = ValidVolumeHeader(vhp); /* make sure this is an HFS Plus disk */
320: if (retval)
321: return MacToVFSError(retval);
322:
323: /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */
324: if (hfsmp->hfs_fs_ronly == 0 && (vhp->attributes & kHFSVolumeUnmountedMask) == 0)
325: return (EINVAL);
326: /*
327: * The VolumeHeader seems OK: transfer info from it into VCB
328: * Note - the VCB starts out clear (all zeros)
329: */
330: vcb = HFSTOVCB(hfsmp);
331:
332: //DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0);
333: vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev);
334: vcb->vcbSigWord = vhp->signature;
335: vcb->vcbCrDate = LocalToUTC(vhp->createDate); // NOTE: local time, not GMT!
336: vcb->vcbLsMod = vhp->modifyDate;
337: vcb->vcbAtrb = (UInt16) vhp->attributes; // VCB only uses lower 16 bits
338: vcb->vcbClpSiz = vhp->rsrcClumpSize;
339: vcb->vcbNxtCNID = vhp->nextCatalogID;
340: vcb->vcbVolBkUp = vhp->backupDate;
341: vcb->vcbWrCnt = vhp->writeCount;
342: vcb->vcbFilCnt = vhp->fileCount;
343: vcb->vcbDirCnt = vhp->folderCount;
344:
345: /* copy 32 bytes of Finder info */
346: bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));
347:
348: vcb->vcbAlBlSt = 0; /* hfs+ allocation blocks start at first block of volume */
349: vcb->vcbWrCnt++; /* compensate for write of Volume Header on last flush */
350:
351: VCB_LOCK_INIT(vcb);
352:
353: /* Now fill in the Extended VCB info */
354: vcb->nextAllocation = vhp->nextAllocation;
355: vcb->totalBlocks = vhp->totalBlocks;
356: vcb->freeBlocks = vhp->freeBlocks;
357: vcb->blockSize = vhp->blockSize;
358: vcb->checkedDate = vhp->checkedDate;
359: vcb->encodingsBitmap = vhp->encodingsBitmap;
360:
361: vcb->hfsPlusIOPosOffset = embBlkOffset * 512;
362:
363: vcb->altIDSector = embBlkOffset + sectors - 2;
364:
365: /* Update the logical block size in the mount struct (currently set up from the wrapper MDB)
366: using the new blocksize value: */
367: hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
368:
369: // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
370: // vcb->vcbAtrb |= kVolumeHardwareLockMask; // XXX this line for debugging only!!!!
371:
372: // Initialize our dirID/nodePtr cache associated with this volume.
373: retval = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
374: if (retval != noErr) goto ErrorExit;
375:
376: /*
377: * Set up Extents B-tree vnode...
378: */
379: retval = GetInitializedVNode(hfsmp, &tmpvnode);
380: if (retval) goto ErrorExit;
381: fdp = &vhp->extentsFile;
382: retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents,
383: kHFSExtentsFileID, CompareExtentKeysPlus);
384: if (retval) goto ErrorExit;
385:
386: /*
387: * Set up Catalog B-tree vnode...
388: */
389: retval = GetInitializedVNode(hfsmp, &tmpvnode);
390: if (retval) goto ErrorExit;
391: fdp = &vhp->catalogFile;
392: retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents,
393: kHFSCatalogFileID, CompareExtendedCatalogKeys);
394: if (retval) goto ErrorExit;
395:
396: /*
397: * Set up Allocation file vnode...
398: */
399: retval = GetInitializedVNode(hfsmp, &tmpvnode);
400: if (retval) goto ErrorExit;
401: fdp = &vhp->allocationFile;
402: retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents,
403: kHFSAllocationFileID, NULL);
404: if (retval) goto ErrorExit;
405:
406: /*
407: * Now that Catalog file is open get the volume name from the catalog
408: */
409: retval = MacToVFSError( GetVolumeNameFromCatalog(vcb) );
410: if (retval != noErr) goto ErrorExit;
411:
412: /* mark the volume dirty (clear clean unmount bit) */
413: vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask;
414:
415: /* setup private/hidden directory for unlinked files */
416: hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb);
417:
418: /*
419: * all done with metadata files so we can unlock now...
420: */
421: VOP_UNLOCK(vcb->allocationsRefNum, 0, p);
422: VOP_UNLOCK(vcb->catalogRefNum, 0, p);
423: VOP_UNLOCK(vcb->extentsRefNum, 0, p);
424:
425: if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected
426: {
427: MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
428: }
429:
430: DBG_VFS(("hfs_MountHFSPlusVolume: returning (%d)\n", retval));
431:
432: return (0);
433:
434:
435: ErrorExit:
436: /*
437: * A fatal error occured and the volume cannot be mounted
438: * release any resources that we aquired...
439: */
440:
441: DBG_VFS(("hfs_MountHFSPlusVolume: fatal error (%d)\n", retval));
442:
443: InvalidateCatalogCache(vcb);
444:
445: ReleaseMetaFileVNode(vcb->allocationsRefNum);
446: ReleaseMetaFileVNode(vcb->catalogRefNum);
447: ReleaseMetaFileVNode(vcb->extentsRefNum);
448:
449: return (retval);
450: }
451:
452:
453: /*
454: * ReleaseMetaFileVNode
455: *
456: * vp L - -
457: */
458: static void ReleaseMetaFileVNode(struct vnode *vp)
459: {
460: if (vp)
461: {
462: FCB *fcb = VTOFCB(vp);
463:
464: if (fcb->fcbBTCBPtr != NULL)
465: (void) BTClosePath(fcb); /* ignore errors since there is only one path open */
466:
467: /* release the node even if BTClosePath fails */
468: if (VOP_ISLOCKED(vp))
469: VPUT(vp);
470: else
471: VRELE(vp);
472: }
473: }
474:
475:
476: /*
477: * InitMetaFileVNode
478: *
479: * vp U L L
480: */
481: static int InitMetaFileVNode(struct vnode *vp, off_t eof, u_long clumpSize, const HFSPlusExtentRecord extents,
482: HFSCatalogNodeID fileID, void * keyCompareProc)
483: {
484: FCB *fcb;
485: ExtendedVCB *vcb;
486: int result = 0;
487:
488: DBG_ASSERT(vp != NULL);
489: DBG_ASSERT(vp->v_data != NULL);
490:
491: vcb = VTOVCB(vp);
492: fcb = VTOFCB(vp);
493:
494: switch (fileID)
495: {
496: case kHFSExtentsFileID:
497: vcb->extentsRefNum = vp;
498: break;
499:
500: case kHFSCatalogFileID:
501: vcb->catalogRefNum = vp;
502: break;
503:
504: case kHFSAllocationFileID:
505: vcb->allocationsRefNum = vp;
506: break;
507:
508: default:
509: panic("InitMetaFileVNode: invalid fileID!");
510: }
511:
512: fcb->fcbEOF = eof;
513: fcb->fcbPLen = eof;
514: fcb->fcbClmpSize = clumpSize;
515: H_FILEID(VTOH(vp)) = fileID;
516: H_DIRID(VTOH(vp)) = kHFSRootParentID;
517: H_FORKTYPE(VTOH(vp)) = kSysFile;
518:
519: bcopy(extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
520:
521: /*
522: * Lock the hfsnode and insert the hfsnode into the hash queue:
523: */
524: hfs_vhashins(H_DEV(VTOH(vp)), fileID, VTOH(vp));
525: vp->v_flag |= VSYSTEM; /* tag our metadata files (used by vflush call) */
526:
527: if (keyCompareProc != NULL) {
528: result = BTOpenPath(fcb,
529: (KeyCompareProcPtr) keyCompareProc,
530: GetBTreeBlock,
531: ReleaseBTreeBlock,
532: ExtendBTreeFile,
533: SetBTreeBlockSize);
534: result = MacToVFSError(result);
535: }
536:
537: return (result);
538: }
539:
540:
541: /*************************************************************
542: *
543: * Unmounts a hfs volume.
544: * At this point vflush() has been called (to dump all non-metadata files)
545: *
546: *************************************************************/
547:
548: short hfsUnmount( register struct hfsmount *hfsmp, struct proc *p)
549: {
550: ExtendedVCB *vcb = HFSTOVCB(hfsmp);
551: int retval = E_NONE;
552:
553: (void) DisposeMRUCache(vcb->hintCachePtr);
554: InvalidateCatalogCache( vcb );
555: // XXX PPD: Should dispose of any allocated volume cache here: call DisposeVolumeCacheBlocks( vcb )?
556:
557: (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
558: (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p);
559:
560: if (vcb->vcbSigWord == kHFSPlusSigWord)
561: ReleaseMetaFileVNode(vcb->allocationsRefNum);
562:
563: ReleaseMetaFileVNode(vcb->catalogRefNum);
564: ReleaseMetaFileVNode(vcb->extentsRefNum);
565:
566: return (retval);
567: }
568:
569:
570: /*
571: * Performs a lookup on the given dirID, name. Returns the catalog info
572: *
573: * If len is -1, then it is a null terminated string, pass it along to MacOS as kUndefinedStrLen
574: */
575:
576: short hfsLookup (ExtendedVCB *vcb, UInt32 parentDirID, char *name, short len, hfsCatalogInfo *catInfo)
577: {
578: OSErr result;
579: UInt32 length;
580: struct FInfo *fip;
581:
582: if (len == -1 ) { /* Convert it to MacOS terms */
583: if (name)
584: length = strlen(name);
585: else
586: length = kUndefinedStrLen;
587: }
588: else
589: length = len;
590:
591: result = GetCatalogNode(vcb, parentDirID, name, length, catInfo->hint, &catInfo->spec, &catInfo->nodeData, &catInfo->hint);
592:
593: #if HFS_HARDLINKS
594: if (result)
595: goto exit;
596:
597: fip = (struct FInfo *) &catInfo->nodeData.cnd_finderInfo;
598:
599: /*
600: * if we encounter a link node (hardlink) then auto resolve it...
601: */
602: if ((catInfo->nodeData.cnd_type == kCatalogFileNode) &&
603: (fip->fdType == kHardLinkFileType) &&
604: (fip->fdCreator == kHardLinkCreator) &&
605: (fip->fdFlags & kIsAlias)
606: ) {
607: FSSpec nodeSpec;
608: UInt32 dataNodeID;
609:
610: result = readlinknode(vcb, catInfo, &dataNodeID);
611: if (result)
612: goto exit;
613: /*
614: * Get nodeData from the data node file.
615: * Use a local spec so that catInfo->spec is preserved
616: */
617: result = GetCatalogNode(vcb, dataNodeID, NULL, 0, 0, &nodeSpec, &catInfo->nodeData, &catInfo->hint);
618:
619: /* make sure there's at lease 1 reference */
620: if (result == 0) {
621: if (catInfo->nodeData.cnd_linkCount == 0)
622: catInfo->nodeData.cnd_linkCount = 1;
623:
624: /* Node should be in private metadata dir */
625: DBG_ASSERT(nodeSpec.parID == VCBTOHFS(vcb)->hfs_private_metadata_dir);
626: }
627: }
628:
629: exit:
630: #endif
631:
632: if (result)
633: DBG_ERR(("on Lookup, GetCatalogNode returned: %d: dirid: %ld name: %s\n", result, parentDirID, name));
634:
635: return MacToVFSError(result);
636: }
637:
638:
639:
640: short hfsDelete (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, short isfile, UInt32 catalogHint)
641: {
642: OSErr result = noErr;
643:
644: /* XXX have all the file's blocks been flushed/trashed? */
645:
646: /*
647: * DeleteFile will delete the catalog node and then
648: * free up any disk space used by the file.
649: */
650: if (isfile)
651: result = DeleteFile(vcb, parentDirID, name, catalogHint);
652: else /* is a directory */
653: result = DeleteCatalogNode(vcb, parentDirID, name, catalogHint);
654:
655: if (result)
656: DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result, parentDirID, name));
657:
658: return MacToVFSError(result);
659: }
660:
661:
662: short hfsMoveRename (ExtendedVCB *vcb, UInt32 oldDirID, char *oldName, UInt32 newDirID, char *newName, UInt32 *hint)
663: {
664: OSErr result = noErr;
665:
666: result = MoveRenameCatalogNode(vcb, oldDirID,oldName, *hint, newDirID, newName, hint);
667:
668: if (result)
669: DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result, newDirID, newName));
670:
671:
672: return MacToVFSError(result);
673: }
674:
675: /* XXX SER pass back the hint so other people can use it */
676:
677:
678: short hfsCreate(ExtendedVCB *vcb, UInt32 dirID, char *name, int mode)
679: {
680: OSErr result = noErr;
681: HFSCatalogNodeID catalogNodeID;
682: UInt32 catalogHint;
683: UInt32 type;
684:
685: /* just test for directories, the default is to create a file (like symlinks) */
686: if ((mode & IFMT) == IFDIR)
687: type = kCatalogFolderNode;
688: else
689: type = kCatalogFileNode;
690:
691: result = CreateCatalogNode (vcb, dirID, name, type, &catalogNodeID, &catalogHint);
692:
693: return MacToVFSError(result);
694: }
695:
696:
697: short hfsCreateFileID (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, UInt32 catalogHint, UInt32 *fileIDPtr)
698: {
699: return MacToVFSError(CreateFileIDRef(vcb, parentDirID, name, catalogHint, fileIDPtr));
700: }
701:
702:
703: /********************************************************************************/
704: /* */
705: /* hfs_vget_catinfo - Returns a vnode derived from a hfs catInfo struct */
706: /* */
707: /********************************************************************************/
708:
709: int hfs_vget_catinfo(struct vnode *parent_vp, struct hfsCatalogInfo *catInfo, u_int32_t forkType, struct vnode **target_vp)
710: {
711: int retval = E_NONE;
712:
713:
714: *target_vp = hfs_vhashget(H_DEV(VTOH(parent_vp)), catInfo->nodeData.cnd_nodeID, forkType);
715:
716: if (*target_vp == NULL) {
717: if (forkType == kAnyFork)
718: if (catInfo->nodeData.cnd_type == kCatalogFolderNode)
719: forkType = kDirectory;
720: else
721: forkType = kDataFork;
722:
723: retval = hfs_vcreate( VTOVCB(parent_vp), catInfo, forkType, target_vp);
724: };
725:
726: return (retval);
727: }
728:
729:
730:
731: /********************************************************************************/
732: /* */
733: /* hfs_vget_fork - Returns a vnode derived from a sibling */
734: /* vp is locked */
735: /* */
736: /********************************************************************************/
737:
738: int hfs_vget_sibling(struct vnode *vp, u_int16_t forkType, struct vnode **vpp)
739: {
740: struct vnode * target_vp = NULL;
741: int retval = E_NONE;
742:
743:
744: DBG_ASSERT(vp != NULL);
745: DBG_ASSERT(VTOH(vp) != NULL);
746: DBG_ASSERT(VTOH(vp)->h_meta != NULL);
747: DBG_ASSERT(forkType==kDataFork || forkType==kRsrcFork);
748:
749: target_vp = hfs_vhashget(H_DEV(VTOH(vp)), H_FILEID(VTOH(vp)), forkType);
750:
751: /*
752: * If not in the hash, then we have to create it
753: */
754: if (target_vp == NULL) {
755: struct proc *p = current_proc();
756: hfsCatalogInfo catInfo;
757:
758: /* lock catalog b-tree */
759: retval = hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, p);
760: if (retval)
761: goto Err_Exit;
762:
763: catInfo.hint = H_HINT(VTOH(vp));
764: retval = hfsLookup (VTOVCB(vp), H_DIRID(VTOH(vp)), H_NAME(VTOH(vp)), VTOH(vp)->h_meta->h_namelen, &catInfo);
765:
766: /* unlock catalog b-tree */
767: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, p);
768: if (retval)
769: goto Err_Exit;
770:
771: retval = hfs_vcreate( VTOVCB(vp), &catInfo, forkType, &target_vp);
772: };
773:
774: Err_Exit:
775:
776: if (!retval) {
777: DBG_ASSERT(target_vp!=NULL);
778: } else {
779: DBG_ASSERT(target_vp==NULL);
780: }
781:
782: *vpp = target_vp;
783: return (retval);
784: }
785:
786:
787: /************************************************************************/
788: /* hfs_vcreate - Returns a vnode derived from hfs */
789: /* */
790: /* When creating the vnode, care must be made to set the */
791: /* correct fields in the correct order. Calls to malloc() */
792: /* and other subroutines, can cause a context switch, */
793: /* and the fields must be ready for the possibility */
794: /* */
795: /* */
796: /************************************************************************/
797:
798: short hfs_vcreate(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, struct vnode **vpp)
799: {
800: struct hfsnode *hp;
801: struct vnode *vp;
802: struct hfsmount *hfsmp;
803: struct hfsfilemeta *fm;
804: struct mount *mp;
805: struct vfsFCB *xfcb;
806: dev_t dev;
807: short retval;
808:
809: #if HFS_DIAGNOSTIC
810: DBG_ASSERT(vcb != NULL);
811: DBG_ASSERT(catInfo != NULL);
812: DBG_ASSERT(vpp != NULL);
813: DBG_ASSERT((forkType == kDirectory) || (forkType == kDataFork) || (forkType == kRsrcFork));
814: if (catInfo->nodeData.cnd_type == kCatalogFolderNode) {
815: DBG_ASSERT(forkType == kDirectory);
816: } else {
817: DBG_ASSERT(forkType != kDirectory);
818: }
819: #endif
820:
821: hfsmp = VCBTOHFS(vcb);
822: mp = HFSTOVFS(hfsmp);
823: dev = hfsmp->hfs_raw_dev;
824:
825: /* Check if unmount in progress */
826: if (mp->mnt_flag & MNT_UNMOUNT) {
827: return (EPERM);
828: }
829: DBG_UTILS(("\thfs_vcreate: On '%s' with forktype of %d, nodeType of 0x%08lX\n", catInfo->spec.name, forkType, (unsigned long)catInfo->nodeData.cnd_type));
830:
831: /* Must malloc() here, since getnewvnode() can sleep */
832: MALLOC(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK);
833: bzero((caddr_t)hp, sizeof(struct hfsnode));
834:
835: /*
836: * Set that this node is in the process of being allocated
837: * Set it as soon as possible, so context switches well always hit upon it.
838: * if this is set then wakeup() MUST be called on hp after the flag is cleared
839: * DO NOT exit without clearing and waking up !!!!
840: */
841: hp->h_nodeflags |= IN_ALLOCATING; /* Mark this as being allocating */
842: lockinit(&hp->h_lock, PINOD, "hfsnode", 0, 0);
843:
844:
845: /* getnewvnode() does a VREF() on the vnode */
846: /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
847: if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &vp))) {
848: wakeup(hp); /* Shouldnt happen, but just to make sure */
849: FREE (hp, M_HFSNODE);
850: *vpp = NULL;
851: return (retval);
852: };
853:
854: /*
855: * Set the essentials before locking it down
856: */
857: hp->h_vp = vp; /* Make HFSTOV work */
858: vp->v_data = hp; /* Make VTOH work */
859: H_FORKTYPE(hp) = forkType;
860: fm = NULL;
861:
862: /*
863: * Lock the hfsnode and insert the hfsnode into the hash queue, also if meta exists
864: * add to sibling list and return the meta address
865: */
866: if (SIBLING_FORKTYPE(forkType))
867: hfs_vhashins_sibling(dev, catInfo->nodeData.cnd_nodeID, hp, &fm);
868: else
869: hfs_vhashins(dev, catInfo->nodeData.cnd_nodeID, hp);
870:
871: /*
872: * If needed allocate and init the object meta data:
873: */
874: if (fm == NULL) {
875: /* Allocate it....remember we can do a context switch here */
876: MALLOC(fm, struct hfsfilemeta *, sizeof(struct hfsfilemeta), M_HFSFMETA, M_WAITOK);
877: bzero(fm, sizeof(struct hfsfilemeta));
878:
879: /* Fill it in */
880: /*
881: * NOTICE: XXX Even though we have added the vnode to the hash so it is alive on TWO
882: * accessable lists, we do not assign it until later,
883: * this helps to make sure we do not use a half initiated meta
884: */
885:
886: /* Init the sibling list if needed */
887: if (SIBLING_FORKTYPE(forkType)) {
888: simple_lock_init(&fm->h_siblinglock);
889: CIRCLEQ_INIT(&fm->h_siblinghead);
890: CIRCLEQ_INSERT_HEAD(&fm->h_siblinghead, hp, h_sibling);
891: };
892:
893: simple_lock_init(&fm->h_metalock);
894: fm->h_dev = dev;
895: CopyCatalogToObjectMeta(catInfo, vp, fm);
896:
897: /*
898: * the vnode is finally alive, with the exception of the FCB below,
899: * It is finally locked and ready for its debutante ball
900: */
901: hp->h_meta = fm;
902: };
903: fm->h_usecount++;
904:
905:
906: /*
907: * Init the File Control Block.
908: */
909: CopyCatalogToFCB(catInfo, vp);
910: if (forkType != kDirectory)
911: UpdateBlockMappingTable(hp);
912:
913: /*
914: * Finish vnode initialization.
915: * Setting the v_type 'stamps' the vnode as 'complete', so should be done almost last.
916: *
917: * At this point the vnode should be locked and fully allocated. And ready to be used
918: * or accessed. (though having it locked prevents most of this, it
919: * can still be accessed through lists and hashs).
920: */
921: vp->v_type = IFTOVT(hp->h_meta->h_mode);
922:
923: /*
924: * Initialize the vnode from the inode, check for aliases, sets the VROOT flag.
925: * Note that the underlying vnode may have changed.
926: */
927: if ((retval = hfs_vinit(mp, hfs_specop_p, hfs_fifoop_p, &vp))) {
928: wakeup((caddr_t)hp);
929: vput(vp);
930: *vpp = NULL;
931: return (retval);
932: }
933:
934: /*
935: * Finish inode initialization now that aliasing has been resolved.
936: */
937: hp->h_meta->h_devvp = hfsmp->hfs_devvp;
938: VREF(hp->h_meta->h_devvp);
939:
940: hp->h_valid = HFS_VNODE_MAGIC;
941: hp->h_nodeflags &= ~IN_ALLOCATING; /* vnode is completely initialized */
942:
943: /* Wake up anybody waiting for us to finish..see hfs_vhash.c */
944: wakeup((caddr_t)hp);
945:
946: #if HFS_DIAGNOSTIC
947:
948: /* Lets do some testing here */
949: DBG_ASSERT(hp->h_meta);
950: DBG_ASSERT(VTOH(vp)==hp);
951: DBG_ASSERT(HTOV(hp)==vp);
952: DBG_ASSERT(hp->h_meta->h_usecount>=1 && hp->h_meta->h_usecount<=2);
953: if (catInfo->nodeData.cnd_type == kCatalogFolderNode) {
954: DBG_ASSERT(vp->v_type == VDIR);
955: DBG_ASSERT(H_FORKTYPE(VTOH(vp)) == kDirectory);
956: }
957: #endif // HFS_DIAGNOSTIC
958:
959:
960: *vpp = vp;
961: return 0;
962:
963: }
964:
965: void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catalogInfo, struct vnode *vp, struct hfsfilemeta *fm)
966: {
967: ExtendedVCB *vcb = VTOVCB(vp);
968: Boolean isHFSPlus, isDirectory;
969: ushort finderFlags;
970:
971: DBG_ASSERT (fm != NULL);
972: DBG_UTILS(("\tCopying to file's meta data: name:%s, nodeid:%ld\n", catalogInfo->spec.name, catalogInfo->nodeData.cnd_nodeID));
973:
974: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
975: isDirectory = (catalogInfo->nodeData.cnd_type == kCatalogFolderNode);
976: finderFlags = ((struct FInfo *)(&catalogInfo->nodeData.cnd_finderInfo))->fdFlags;
977:
978: /* Copy over the dirid, and hint */
979: fm->h_nodeID = catalogInfo->nodeData.cnd_nodeID;
980: fm->h_dirID = catalogInfo->spec.parID;
981: fm->h_hint = catalogInfo->hint;
982:
983: /* Copy over the name */
984: hfs_set_metaname(catalogInfo->spec.name, fm);
985: DBG_ASSERT (fm->h_namelen == strlen(catalogInfo->spec.name));
986: DBG_ASSERT (strcmp(fm->h_namePtr, catalogInfo->spec.name) == 0);
987:
988:
989: /* get dates in BSD format */
990: fm->h_mtime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
991: fm->h_crtime = to_bsd_time(catalogInfo->nodeData.cnd_createDate);
992: fm->h_butime = to_bsd_time(catalogInfo->nodeData.cnd_backupDate);
993: if (isHFSPlus) {
994: fm->h_atime = to_bsd_time(catalogInfo->nodeData.cnd_accessDate);
995: fm->h_ctime = to_bsd_time(catalogInfo->nodeData.cnd_attributeModDate);
996: }
997: else {
998: fm->h_atime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
999: fm->h_ctime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
1000: }
1001:
1002: /* Now the rest */
1003: if (isHFSPlus && (catalogInfo->nodeData.cnd_permissions & IFMT)) {
1004: fm->h_uid = catalogInfo->nodeData.cnd_ownerID;
1005: fm->h_gid = catalogInfo->nodeData.cnd_groupID;
1006: /* The 32-bit permissions field is unpacked to yield the two significant bytes of flags and the
1007: mode as follows:
1008: +------------------------------------+
1009: permissions: | A | B | mode |
1010: +------------------------------------+
1011: |
1012: V
1013: +------------------------------------+
1014: fm->h_pflags: |XXXXXXXX| A |XXXXXXXX| B |
1015: +------------------------------------+
1016:
1017: */
1018: fm->h_pflags = (((catalogInfo->nodeData.cnd_permissions & 0xFF000000) >> 8) | /* A */
1019: ((catalogInfo->nodeData.cnd_permissions & 0x00FF0000) >> 16)); /* B */
1020: fm->h_mode = (mode_t)(catalogInfo->nodeData.cnd_permissions & 0x0000FFFF);
1021: fm->h_rdev = catalogInfo->nodeData.cnd_specialDevice;
1022:
1023: #if HFS_HARDLINKS
1024: if (catalogInfo->nodeData.cnd_type == kCatalogFileNode &&
1025: catalogInfo->nodeData.cnd_linkCount > 0) {
1026: fm->h_nlink = catalogInfo->nodeData.cnd_linkCount;
1027: fm->h_metaflags |= IN_DATANODE;
1028: }
1029: #endif
1030: } else {
1031: /*
1032: * Set the permissions as determined by the mount auguments
1033: * but keep in account if the file or folder is hfs locked
1034: */
1035: fm->h_metaflags |= IN_UNSETACCESS;
1036: fm->h_uid = VTOHFS(vp)->hfs_uid;
1037: fm->h_gid = VTOHFS(vp)->hfs_gid;
1038: /* Default access is full read/write/execute: */
1039: fm->h_mode = ACCESSPERMS; /* 0777: rwxrwxrwx */
1040:
1041: /* ... but no more than that permitted by the mount point's: */
1042: if (isDirectory) {
1043: fm->h_mode &= VTOHFS(vp)->hfs_dir_mask;
1044: }
1045: else {
1046: fm->h_mode &= VTOHFS(vp)->hfs_file_mask;
1047: }
1048:
1049: if(isDirectory)
1050: fm->h_mode |= IFDIR;
1051: else if (SUPPORTS_MAC_ALIASES && (finderFlags & kIsAlias)) /* aliases will be symlinks in the future */
1052: fm->h_mode |= IFLNK;
1053: else
1054: fm->h_mode |= IFREG;
1055:
1056: };
1057:
1058: /* Make sure that there is no nodeType/mode mismatch */
1059: if (isDirectory && ((fm->h_mode & IFMT) != IFDIR)) {
1060: fm->h_mode &= ~IFMT; /* Clear the bad bits */
1061: fm->h_mode |= IFDIR; /* Set the proper one */
1062: };
1063:
1064: /* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */
1065: if (!isDirectory) {
1066: if (catalogInfo->nodeData.cnd_flags & kHFSFileLockedMask) {
1067: /* The file's supposed to be locked:
1068: Make sure at least one of the IMMUTABLE bits is set: */
1069: if ((fm->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) == 0) {
1070: fm->h_pflags |= UF_IMMUTABLE; /* Set the user-changable IMMUTABLE bit */
1071: };
1072: } else {
1073: /* The file's supposed to be unlocked: */
1074: fm->h_pflags &= ~(SF_IMMUTABLE | UF_IMMUTABLE);
1075: };
1076: };
1077:
1078: if (isDirectory) {
1079: fm->h_valence = catalogInfo->nodeData.cnd_valence;
1080: fm->h_size = (2 * sizeof(hfsdotentry)) +
1081: (catalogInfo->nodeData.cnd_valence * AVERAGE_HFSDIRENTRY_SIZE);
1082: if (fm->h_size < MAX_HFSDIRENTRY_SIZE)
1083: fm->h_size = MAX_HFSDIRENTRY_SIZE;
1084: } else {
1085: fm->h_size = vcb->blockSize *
1086: (catalogInfo->nodeData.cnd_rsrcfork.totalBlocks +
1087: catalogInfo->nodeData.cnd_datafork.totalBlocks);
1088: }
1089: }
1090:
1091:
1092: void CopyCatalogToFCB(struct hfsCatalogInfo *catalogInfo, struct vnode *vp)
1093: {
1094: FCB *fcb = VTOFCB(vp);
1095: ExtendedVCB *vcb = VTOVCB(vp);
1096: Boolean isHFSPlus, isDirectory, isResource;
1097: HFSPlusExtentDescriptor *extents;
1098: UInt8 forkType;
1099:
1100: DBG_ASSERT (vp != NULL);
1101: DBG_ASSERT (fcb != NULL);
1102: DBG_ASSERT (vcb != NULL);
1103: DBG_ASSERT (VTOH(vp) != NULL);
1104:
1105: forkType = H_FORKTYPE(VTOH(vp));
1106: isResource = (forkType == kRsrcFork);
1107: isDirectory = (catalogInfo->nodeData.cnd_type == kCatalogFolderNode);
1108: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
1109:
1110: /* Init the fcb */
1111: fcb->fcbFlags = catalogInfo->nodeData.cnd_flags;
1112:
1113: if (forkType != kDirectory) {
1114: fcb->fcbFlags &= kHFSFileLockedMask; /* Clear resource, dirty bits */
1115: if (fcb->fcbFlags != 0) /* if clear, its not locked, then.. */
1116: fcb->fcbFlags = fcbFileLockedMask; /* duplicate the bit for later use */
1117:
1118: fcb->fcbClmpSize = vcb->vcbClpSiz; /*XXX why not use the one in catalogInfo? */
1119:
1120: if (isResource)
1121: extents = catalogInfo->nodeData.cnd_rsrcfork.extents;
1122: else
1123: extents = catalogInfo->nodeData.cnd_datafork.extents;
1124:
1125: /* Copy the extents to their correct location: */
1126: bcopy (extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
1127:
1128: if (isResource) {
1129: fcb->fcbEOF = catalogInfo->nodeData.cnd_rsrcfork.logicalSize;
1130: fcb->fcbPLen = catalogInfo->nodeData.cnd_rsrcfork.totalBlocks * vcb->blockSize;
1131: fcb->fcbFlags |= fcbResourceMask;
1132: } else {
1133: fcb->fcbEOF = catalogInfo->nodeData.cnd_datafork.logicalSize;
1134: fcb->fcbPLen = catalogInfo->nodeData.cnd_datafork.totalBlocks * vcb->blockSize;
1135: };
1136: };
1137:
1138:
1139: }
1140:
1141: int hasOverflowExtents(struct hfsnode *hp)
1142: {
1143: ExtendedVCB *vcb = HTOVCB(hp);
1144: FCB *fcb = HTOFCB(hp);
1145: u_long blocks;
1146:
1147: if (vcb->vcbSigWord == kHFSPlusSigWord)
1148: {
1149:
1150: if (fcb->fcbExtents[7].blockCount == 0)
1151: return false;
1152:
1153: blocks = fcb->fcbExtents[0].blockCount +
1154: fcb->fcbExtents[1].blockCount +
1155: fcb->fcbExtents[2].blockCount +
1156: fcb->fcbExtents[3].blockCount +
1157: fcb->fcbExtents[4].blockCount +
1158: fcb->fcbExtents[5].blockCount +
1159: fcb->fcbExtents[6].blockCount +
1160: fcb->fcbExtents[7].blockCount;
1161: }
1162: else
1163: {
1164: if (fcb->fcbExtents[2].blockCount == 0)
1165: return false;
1166:
1167: blocks = fcb->fcbExtents[0].blockCount +
1168: fcb->fcbExtents[1].blockCount +
1169: fcb->fcbExtents[2].blockCount;
1170: }
1171:
1172: return ((fcb->fcbPLen / vcb->blockSize) > blocks);
1173: }
1174:
1175:
1176: int hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p)
1177: {
1178: ExtendedVCB *vcb;
1179: struct vnode *vp = NULL;
1180: int numOfLockedBuffs;
1181: int retval = 0;
1182:
1183: vcb = HFSTOVCB(hfsmp);
1184:
1185: DBG_UTILS(("hfs_metafilelocking: vol: %d, file: %d %s%s%s\n", vcb->vcbVRefNum, fileID,
1186: ((flags & LK_TYPE_MASK) == LK_RELEASE ? "RELEASE" : ""),
1187: ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE ? "EXCLUSIVE" : ""),
1188: ((flags & LK_TYPE_MASK) == LK_SHARED ? "SHARED" : "") ));
1189:
1190:
1191: switch (fileID)
1192: {
1193: case kHFSExtentsFileID:
1194: vp = vcb->extentsRefNum;
1195: break;
1196:
1197: case kHFSCatalogFileID:
1198: vp = vcb->catalogRefNum;
1199: break;
1200:
1201: case kHFSAllocationFileID:
1202: /* bitmap is covered by Extents B-tree locking */
1203: /* FALL THROUGH */
1204: default:
1205: panic("hfs_lockmetafile: invalid fileID");
1206: }
1207:
1208: if (vp != NULL) {
1209:
1210: /* Release, if necesary any locked buffer caches */
1211: if ((flags & LK_TYPE_MASK) == LK_RELEASE) {
1212: struct timeval tv = time;
1213: u_int32_t lastfsync = tv.tv_sec;
1214:
1215: (void) BTGetLastSync(VTOFCB(vp), &lastfsync);
1216:
1217: numOfLockedBuffs = count_lock_queue();
1218: if ((numOfLockedBuffs > kMaxLockedMetaBuffers) || ((numOfLockedBuffs>1) && ((tv.tv_sec - lastfsync) > kMaxSecsForFsync))) {
1219: DBG_UTILS(("Synching meta deta: %d... # locked buffers = %d, fsync gap = %ld\n", H_FILEID(VTOH(vp)),
1220: numOfLockedBuffs, (tv.tv_sec - lastfsync)));
1221: hfs_fsync_transaction(vp);
1222: };
1223: };
1224:
1225: retval = lockmgr(&VTOH(vp)->h_lock, flags, &vp->v_interlock, p);
1226: };
1227:
1228: return retval;
1229: }
1230:
1231:
1232: void CopyVNodeToCatalogNode (struct vnode *vp, struct CatalogNodeData *nodeData)
1233: {
1234: ExtendedVCB *vcb;
1235: FCB *fcb;
1236: struct hfsnode *hp;
1237: Boolean isHFSPlus, isResource;
1238: HFSPlusExtentDescriptor *extents;
1239:
1240: hp = VTOH(vp);
1241: vcb = HTOVCB(hp);
1242: fcb = HTOFCB(hp);
1243: isResource = (H_FORKTYPE(hp) == kRsrcFork);
1244: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
1245:
1246: /* date and time of last fork modification */
1247: nodeData->cnd_contentModDate = to_hfs_time(hp->h_meta->h_mtime);
1248:
1249: if (isHFSPlus) {
1250: /* Make sure that there is no nodeType/mode mismatch */
1251: if ((nodeData->cnd_type == kCatalogFolderNode)
1252: && ((hp->h_meta->h_mode & IFMT) != IFDIR)) {
1253:
1254: DBG_ASSERT((hp->h_meta->h_mode & IFMT) == IFDIR);
1255: hp->h_meta->h_mode &= ~IFMT; /* Clear the bad bits */
1256: hp->h_meta->h_mode |= IFDIR; /* Set the proper one */
1257: };
1258: /* date and time of last modification (any kind) */
1259: nodeData->cnd_attributeModDate = to_hfs_time(hp->h_meta->h_ctime);
1260: /* date and time of last access (MacOS X only) */
1261: nodeData->cnd_accessDate = to_hfs_time(hp->h_meta->h_atime);
1262: if (! (hp->h_meta->h_metaflags & IN_UNSETACCESS)) {
1263: /* This is a tricky stuff-job: the pflags longword has two bytes of significance and they're
1264: combined with the mode field to yield a 32-bit permissions field as follows:
1265:
1266: +------------------------------------+
1267: hp->h_meta->h_pflags: |XXXXXXXX| A |XXXXXXXX| B |
1268: +------------------------------------+
1269:
1270: |
1271: V
1272:
1273: +------------------------------------+
1274: permissions: | A | B | mode |
1275: +------------------------------------+
1276: */
1277: nodeData->cnd_permissions = (((hp->h_meta->h_pflags << 8) & 0xFF000000) | /* A */
1278: ((hp->h_meta->h_pflags << 16) & 0x00FF0000) | /* B */
1279: (hp->h_meta->h_mode & 0x0000FFFF));
1280: nodeData->cnd_ownerID = hp->h_meta->h_uid;
1281: nodeData->cnd_groupID = hp->h_meta->h_gid;
1282: nodeData->cnd_specialDevice = hp->h_meta->h_rdev;
1283: };
1284: };
1285:
1286: /* the rest only applies to files */
1287: if (nodeData->cnd_type == kCatalogFileNode) {
1288: if (hp->h_meta->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) {
1289: /* The file is locked: set the locked bit in the catalog. */
1290: nodeData->cnd_flags |= kHFSFileLockedMask;
1291: } else {
1292: /* The file is unlocked: make sure the locked bit in the catalog is clear. */
1293: nodeData->cnd_flags &= ~kHFSFileLockedMask;
1294: };
1295: if (isResource) {
1296: extents = nodeData->cnd_rsrcfork.extents;
1297: nodeData->cnd_rsrcfork.logicalSize = fcb->fcbEOF;
1298: nodeData->cnd_rsrcfork.totalBlocks = fcb->fcbPLen / vcb->blockSize;
1299: } else {
1300: extents = nodeData->cnd_datafork.extents;
1301: nodeData->cnd_datafork.logicalSize = fcb->fcbEOF;
1302: nodeData->cnd_datafork.totalBlocks = fcb->fcbPLen / vcb->blockSize;
1303: };
1304:
1305: bcopy ( fcb->fcbExtents, extents, sizeof(HFSPlusExtentRecord));
1306:
1307: if (vp->v_type == VLNK) {
1308: ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdType = kSymLinkFileType;
1309: ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdCreator = kSymLinkCreator;
1310:
1311: /* Set this up as an alias */
1312: #if SUPPORTS_MAC_ALIASES
1313: ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdFlags |= kIsAlias;
1314: #endif
1315: }
1316: #if HFS_HARDLINKS
1317: nodeData->cnd_linkCount = hp->h_meta->h_nlink;
1318: #endif
1319: }
1320: }
1321:
1322:
1323:
1324: void MapFileOffset(struct hfsnode *hp,
1325: off_t filePosition,
1326: daddr_t *logBlockNumber,
1327: long *blockSize,
1328: long *blockOffset) {
1329: off_t extentOffset = filePosition;
1330: daddr_t precedingBlockCount;
1331: unsigned long logicalBlockSize = 0;
1332: unsigned long spaceRemaining;
1333:
1334: DBG_IO(("MapFileOffset: hp = 0x%08lX, vp = 0x%08lX ('%s'):\n", (u_long)hp, (u_long)HTOV(hp), H_NAME(hp)));
1335: // DBG_IO(("\tfilePosition 0x%08lX", (u_long)filePosition));
1336:
1337: if (filePosition < hp->h_optimizedblocksizelimit) {
1338: int extent;
1339:
1340: precedingBlockCount = 0;
1341: for (extent = 0; extent < LOGBLOCKMAPENTRIES; ++extent) {
1342: if ((hp->h_logicalblocktable[extent].logicalBlockCount > 0) &&
1343: (extentOffset < hp->h_logicalblocktable[extent].extentLength)) {
1344: logicalBlockSize = MAXLOGBLOCKSIZE;
1345: spaceRemaining = hp->h_logicalblocktable[extent].extentLength - ((extentOffset / logicalBlockSize) * logicalBlockSize);
1346: *blockSize = MIN(logicalBlockSize, spaceRemaining);
1347: // DBG_IO(("\tUsing entry #%d: preceding blocks = 0x%X, position = 0x%8lX:\n",
1348: // extent, precedingBlockCount, (u_long)extentOffset));
1349: break;
1350: };
1351: precedingBlockCount += hp->h_logicalblocktable[extent].logicalBlockCount;
1352: extentOffset -= hp->h_logicalblocktable[extent].extentLength;
1353: };
1354: DBG_ASSERT(logicalBlockSize > 0);
1355: } else {
1356: // DBG_IO(("\tUsing h_uniformblocksizestart = 0x%X and h_optimizedblocksizelimit = 0x%lX:\n",
1357: // hp->h_uniformblocksizestart, (u_long)hp->h_optimizedblocksizelimit));
1358: precedingBlockCount = hp->h_uniformblocksizestart;
1359: extentOffset -= hp->h_optimizedblocksizelimit;
1360: logicalBlockSize = GetLogicalBlockSize(HTOV(hp));
1361: *blockSize = logicalBlockSize;
1362: };
1363:
1364: *logBlockNumber = precedingBlockCount + (extentOffset / logicalBlockSize);
1365: *blockOffset = extentOffset % logicalBlockSize;
1366: DBG_IO(("\tfilePosition 0x%08lX -> logBlockNo = 0x%X, blockSize = 0x%lX, blockOffset = 0x%lX.\n",
1367: (u_long)filePosition,
1368: *logBlockNumber,
1369: *blockSize,
1370: *blockOffset));
1371: }
1372:
1373:
1374: long LogicalBlockSize(struct hfsnode *hp, daddr_t logicalBlockNumber) {
1375:
1376: if (logicalBlockNumber < hp->h_uniformblocksizestart) {
1377: off_t fragmentOffset = 0;
1378: int extent;
1379:
1380: for (extent = 0; extent < LOGBLOCKMAPENTRIES; ++extent) {
1381: if ((hp->h_logicalblocktable[extent].logicalBlockCount > 0) &&
1382: (logicalBlockNumber < hp->h_logicalblocktable[extent].logicalBlockCount)) {
1383: // *filePosition = fragmentOffset + (logicalBlockNumber * MAXLOGBLOCKSIZE);
1384: return MIN(MAXLOGBLOCKSIZE, hp->h_logicalblocktable[extent].extentLength - (logicalBlockNumber * MAXLOGBLOCKSIZE));
1385: };
1386: logicalBlockNumber -= hp->h_logicalblocktable[extent].logicalBlockCount;
1387: fragmentOffset += hp->h_logicalblocktable[extent].extentLength;
1388: };
1389: } else {
1390: // *filePosition = hp->h_optimizedblocksizelimit + ((logicalBlockNumber - hp->h_uniformblocksizestart) * HTOHFS(hp)->logBlockSize);
1391: return (GetLogicalBlockSize(HTOV(hp)));
1392: };
1393:
1394: DBG_ASSERT(0 /* cannot be reached */);
1395: return 0;
1396: };
1397:
1398:
1399: void UpdateBlockMappingTableEntry(struct hfsnode *hp, int index, daddr_t firstFragmentBlockNumber, off_t newFragmentLength) {
1400:
1401: /* Compute the number of logical blocks, rounding up to include any small trailing fragments: */
1402: hp->h_logicalblocktable[index].logicalBlockCount = (newFragmentLength + MAXLOGBLOCKSIZE - 1) / MAXLOGBLOCKSIZE;
1403:
1404: DBG_IO(("\tblocktable[%d]: length = 0x%lX, # blocks = 0x%lX.\n",
1405: index,
1406: (u_long)newFragmentLength,
1407: (u_long)hp->h_logicalblocktable[index].logicalBlockCount));
1408:
1409: #if 0
1410: currentFragmentLength = hp->h_logicalblocktable[index].extentLength;
1411: if ((newFragmentLength > currentFragmentLength) && (currentFragmentLength > 0)) {
1412: daddr_t currentLastBlockNumber;
1413: long currentLastBlockSize;
1414: long newLastBlockSize;
1415: struct buf *bp;
1416: int retval;
1417:
1418: currentLastBlockNumber = firstFragmentBlockNumber + (currentFragmentLength / MAXLOGBLOCKSIZE);
1419: currentLastBlockSize = currentFragmentLength % MAXLOGBLOCKSIZE;
1420: if (currentLastBlockSize > 0) {
1421: newLastBlockSize = MIN(MAXLOGBLOCKSIZE,
1422: newFragmentLength -
1423: ((currentLastBlockNumber - firstFragmentBlockNumber) * MAXLOGBLOCKSIZE));
1424: if (newLastBlockSize != currentLastBlockSize) {
1425: DBG_IO(("\t\t(Adjusting block 0x%lX from 0x%lX to 0x%lX...)\n",
1426: (unsigned long)currentLastBlockNumber,
1427: currentLastBlockSize,
1428: newLastBlockSize));
1429: retval = bread(HTOV(hp), currentLastBlockNumber, currentLastBlockSize, NOCRED, &bp);
1430: if (retval == 0) {
1431: bexpand(bp, newLastBlockSize, NULL, RELEASE_BUFFER);
1432: } else {
1433: DBG_IO(("\t\terror (%d.) acquiring block 0x%lX; bp = 0x%08lX\n",
1434: retval,
1435: (unsigned long)currentLastBlockNumber,
1436: (unsigned long)bp));
1437: if (bp) brelse(bp);
1438: };
1439: };
1440: };
1441: };
1442: #endif
1443: hp->h_logicalblocktable[index].extentLength = newFragmentLength;
1444: }
1445:
1446:
1447: void UpdateBlockMappingTable(struct hfsnode *hp)
1448: {
1449: ExtendedVCB *vcb = HTOVCB(hp);
1450: FCB *fcb = HTOFCB(hp);
1451: Boolean isHFSPlus;
1452: off_t rangeMappedSoFar;
1453: u_long logicalBlocksMappedSoFar;
1454: int i;
1455: off_t newFragmentLength;
1456:
1457: isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
1458: DBG_IO(("UpdateBlockMappingTable: hp = 0x%08lX, vp = 0x%08lX ('%s'):\n", (u_long)hp, (u_long)HTOV(hp), H_NAME(hp)));
1459: if (H_FORKTYPE(hp) != kDirectory) {
1460: rangeMappedSoFar = 0;
1461: logicalBlocksMappedSoFar = 0;
1462:
1463: if ( ! isHFSPlus) {
1464: DBG_ASSERT(kHFSExtentDensity <= LOGBLOCKMAPENTRIES);
1465: for (i = 0; i < kHFSExtentDensity; ++i) {
1466: newFragmentLength = fcb->fcbExtents[i].blockCount * vcb->blockSize;
1467: UpdateBlockMappingTableEntry(hp, i, logicalBlocksMappedSoFar, newFragmentLength);
1468: rangeMappedSoFar += newFragmentLength;
1469: logicalBlocksMappedSoFar += hp->h_logicalblocktable[i].logicalBlockCount;
1470: }
1471: /* Zero out any remaining entries: */
1472: for (i = kHFSExtentDensity; i < LOGBLOCKMAPENTRIES; ++i) {
1473: hp->h_logicalblocktable[i].extentLength = 0;
1474: };
1475: #if HFS_DIAGNOSTIC
1476: if (rangeMappedSoFar < fcb->fcbPLen) DBG_ASSERT(hp->h_logicalblocktable[kHFSExtentDensity-1].extentLength > 0);
1477: #endif
1478: } else {
1479: for (i = 0; i < kHFSPlusExtentDensity; ++i) {
1480: newFragmentLength = fcb->fcbExtents[i].blockCount * vcb->blockSize;
1481: UpdateBlockMappingTableEntry(hp, i, logicalBlocksMappedSoFar, newFragmentLength);
1482: rangeMappedSoFar += newFragmentLength;
1483: logicalBlocksMappedSoFar += hp->h_logicalblocktable[i].logicalBlockCount;
1484: }
1485: /* No need to zero out the remaining entries [there are none]: */
1486: DBG_ASSERT(LOGBLOCKMAPENTRIES <= kHFSPlusExtentDensity);
1487: #if HFS_DIAGNOSTIC
1488: if (rangeMappedSoFar < fcb->fcbPLen) DBG_ASSERT(hp->h_logicalblocktable[kHFSPlusExtentDensity-1].extentLength > 0);
1489: #endif
1490: };
1491:
1492: hp->h_optimizedblocksizelimit = rangeMappedSoFar;
1493: hp->h_uniformblocksizestart = logicalBlocksMappedSoFar;
1494: DBG_IO(("\th_optimizedblocksizelimit = 0x%lX, h_uniformblocksizestart = 0x%lX.\n",
1495: (u_long)hp->h_optimizedblocksizelimit, (u_long)hp->h_uniformblocksizestart));
1496:
1497: #if BYPASSBLOCKINGOPTIMIZATION
1498: hp->h_optimizedblocksizelimit = 0;
1499: hp->h_uniformblocksizestart = 0;
1500: #endif
1501: };
1502: }
1503:
1504:
1505: /*********************************************************************
1506:
1507: Sets the name in the filemeta structure
1508:
1509: XXX Does not preflight if changing from one size to another
1510: XXX Currently not protected from context switching
1511:
1512: *********************************************************************/
1513:
1514: void hfs_set_metaname(char *name, struct hfsfilemeta *fm)
1515: {
1516: int namelen = strlen(name);
1517: char *tname, *fname;
1518:
1519: #if HFS_DIAGNOSTIC
1520: DBG_ASSERT(name != NULL);
1521: DBG_ASSERT(fm != NULL);
1522: if (fm->h_namePtr) {
1523: DBG_ASSERT(fm->h_namelen == strlen(fm->h_namePtr));
1524: if (strlen(fm->h_namePtr) > MAXHFSVNODELEN)
1525: DBG_ASSERT(fm->h_metaflags & IN_LONGNAME);
1526: };
1527: if (fm->h_metaflags & IN_LONGNAME) {
1528: DBG_ASSERT(fm->h_namePtr != (char *)fm->h_fileName);
1529: DBG_ASSERT(fm->h_namePtr != NULL);
1530: };
1531: #endif //HFS_DIAGNOSTIC
1532:
1533: /*
1534: * Details that have to be dealt with:
1535: * 1. No name is allocated. fm->h_namePtr should be NULL
1536: * 2. A name is being changed and:
1537: * a. it was in static space and now cannot fit
1538: * b. It was malloc'd and now will fit in the static
1539: * c. It did and will fit in the static
1540: * This could be a little smarter:
1541: * - Dont re'malloc if the new name is smaller (but then wasting memory)
1542: * - If its a longname but the same size, we still free and malloc
1543: * -
1544: */
1545:
1546:
1547: /* Allocate the new memory */
1548: if (namelen > MAXHFSVNODELEN) {
1549: /*
1550: * Notice the we ALWAYS allocate, even if the new is less then the old,
1551: * or even if they are the SAME
1552: */
1553: MALLOC(tname, char *, namelen+1, M_TEMP, M_WAITOK);
1554: }
1555: else
1556: tname = fm->h_fileName;
1557:
1558: simple_lock(&fm->h_metalock);
1559:
1560: /* Check to see if there is something to free, if yes, remember it */
1561: if (fm->h_metaflags & IN_LONGNAME)
1562: fname = fm->h_namePtr;
1563: else
1564: fname = NULL;
1565:
1566: /* Set the flag */
1567: if (namelen > MAXHFSVNODELEN) {
1568: fm->h_metaflags |= IN_LONGNAME;
1569: }
1570: else {
1571: fm->h_metaflags &= ~IN_LONGNAME;
1572: };
1573:
1574: /* Now copy it over */
1575: bcopy(name, tname, namelen+1);
1576:
1577: fm->h_namePtr = tname;
1578: fm->h_namelen = namelen;
1579:
1580: simple_unlock(&fm->h_metalock);
1581:
1582: /* Lastly, free the old, if set */
1583: if (fname != NULL)
1584: FREE(fname, M_TEMP);
1585:
1586: }
1587:
1588: int AttributeBlockSize(struct attrlist *attrlist) {
1589: int size;
1590: attrgroup_t a;
1591:
1592: #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1593: ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_PAROBJID | \
1594: ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
1595: ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1596: ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST| \
1597: ATTR_CMN_FLAGS) != ATTR_CMN_VALIDMASK)
1598: #error AttributeBlockSize: Missing bits in common mask computation!
1599: #endif
1600: DBG_ASSERT((attrlist->commonattr & ~ATTR_CMN_VALIDMASK) == 0);
1601:
1602: #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
1603: ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1604: ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | \
1605: ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | \
1606: ATTR_VOL_MOUNTEDDEVICE| ATTR_VOL_ENCODINGSUSED) != ATTR_VOL_VALIDMASK)
1607: #error AttributeBlockSize: Missing bits in volume mask computation!
1608: #endif
1609: DBG_ASSERT((attrlist->volattr & ~ATTR_VOL_VALIDMASK) == 0);
1610:
1611: #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT) != ATTR_DIR_VALIDMASK)
1612: #error AttributeBlockSize: Missing bits in directory mask computation!
1613: #endif
1614: DBG_ASSERT((attrlist->dirattr & ~ATTR_DIR_VALIDMASK) == 0);
1615: #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
1616: ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | \
1617: ATTR_FILE_FORKLIST | ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1618: ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) != ATTR_FILE_VALIDMASK)
1619: #error AttributeBlockSize: Missing bits in file mask computation!
1620: #endif
1621: DBG_ASSERT((attrlist->fileattr & ~ATTR_FILE_VALIDMASK) == 0);
1622:
1623: #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1624: #error AttributeBlockSize: Missing bits in fork mask computation!
1625: #endif
1626: DBG_ASSERT((attrlist->forkattr & ~ATTR_FORK_VALIDMASK) == 0);
1627:
1628: size = 0;
1629:
1630: if ((a = attrlist->commonattr) != 0) {
1631: if (a & ATTR_CMN_NAME) size += sizeof(struct attrreference);
1632: if (a & ATTR_CMN_DEVID) size += sizeof(dev_t);
1633: if (a & ATTR_CMN_FSID) size += sizeof(fsid_t);
1634: if (a & ATTR_CMN_OBJTYPE) size += sizeof(fsobj_type_t);
1635: if (a & ATTR_CMN_OBJTAG) size += sizeof(fsobj_tag_t);
1636: if (a & ATTR_CMN_OBJID) size += sizeof(fsobj_id_t);
1637: if (a & ATTR_CMN_OBJPERMANENTID) size += sizeof(fsobj_id_t);
1638: if (a & ATTR_CMN_PAROBJID) size += sizeof(fsobj_id_t);
1639: if (a & ATTR_CMN_SCRIPT) size += sizeof(text_encoding_t);
1640: if (a & ATTR_CMN_CRTIME) size += sizeof(struct timespec);
1641: if (a & ATTR_CMN_MODTIME) size += sizeof(struct timespec);
1642: if (a & ATTR_CMN_CHGTIME) size += sizeof(struct timespec);
1643: if (a & ATTR_CMN_ACCTIME) size += sizeof(struct timespec);
1644: if (a & ATTR_CMN_BKUPTIME) size += sizeof(struct timespec);
1645: if (a & ATTR_CMN_FNDRINFO) size += 32 * sizeof(UInt8);
1646: if (a & ATTR_CMN_OWNERID) size += sizeof(uid_t);
1647: if (a & ATTR_CMN_GRPID) size += sizeof(gid_t);
1648: if (a & ATTR_CMN_ACCESSMASK) size += sizeof(u_long);
1649: if (a & ATTR_CMN_NAMEDATTRCOUNT) size += sizeof(u_long);
1650: if (a & ATTR_CMN_NAMEDATTRLIST) size += sizeof(struct attrreference);
1651: if (a & ATTR_CMN_FLAGS) size += sizeof(u_long);
1652: };
1653: if ((a = attrlist->volattr) != 0) {
1654: if (a & ATTR_VOL_FSTYPE) size += sizeof(u_long);
1655: if (a & ATTR_VOL_SIGNATURE) size += sizeof(u_long);
1656: if (a & ATTR_VOL_SIZE) size += sizeof(off_t);
1657: if (a & ATTR_VOL_SPACEFREE) size += sizeof(off_t);
1658: if (a & ATTR_VOL_SPACEAVAIL) size += sizeof(off_t);
1659: if (a & ATTR_VOL_MINALLOCATION) size += sizeof(off_t);
1660: if (a & ATTR_VOL_ALLOCATIONCLUMP) size += sizeof(off_t);
1661: if (a & ATTR_VOL_IOBLOCKSIZE) size += sizeof(u_long);
1662: if (a & ATTR_VOL_OBJCOUNT) size += sizeof(u_long);
1663: if (a & ATTR_VOL_FILECOUNT) size += sizeof(u_long);
1664: if (a & ATTR_VOL_DIRCOUNT) size += sizeof(u_long);
1665: if (a & ATTR_VOL_MAXOBJCOUNT) size += sizeof(u_long);
1666: if (a & ATTR_VOL_MOUNTPOINT) size += sizeof(struct attrreference);
1667: if (a & ATTR_VOL_NAME) size += sizeof(struct attrreference);
1668: if (a & ATTR_VOL_MOUNTFLAGS) size += sizeof(u_long);
1669: if (a & ATTR_VOL_MOUNTEDDEVICE) size += sizeof(struct attrreference);
1670: if (a & ATTR_VOL_ENCODINGSUSED) size += sizeof(unsigned long long);
1671: };
1672: if ((a = attrlist->dirattr) != 0) {
1673: if (a & ATTR_DIR_LINKCOUNT) size += sizeof(u_long);
1674: if (a & ATTR_DIR_ENTRYCOUNT) size += sizeof(u_long);
1675: };
1676: if ((a = attrlist->fileattr) != 0) {
1677: if (a & ATTR_FILE_LINKCOUNT) size += sizeof(u_long);
1678: if (a & ATTR_FILE_TOTALSIZE) size += sizeof(off_t);
1679: if (a & ATTR_FILE_ALLOCSIZE) size += sizeof(off_t);
1680: if (a & ATTR_FILE_IOBLOCKSIZE) size += sizeof(size_t);
1681: if (a & ATTR_FILE_CLUMPSIZE) size += sizeof(off_t);
1682: if (a & ATTR_FILE_DEVTYPE) size += sizeof(u_long);
1683: if (a & ATTR_FILE_FILETYPE) size += sizeof(u_long);
1684: if (a & ATTR_FILE_FORKCOUNT) size += sizeof(u_long);
1685: if (a & ATTR_FILE_FORKLIST) size += sizeof(struct attrreference);
1686: if (a & ATTR_FILE_DATALENGTH) size += sizeof(off_t);
1687: if (a & ATTR_FILE_DATAALLOCSIZE) size += sizeof(off_t);
1688: if (a & ATTR_FILE_DATAEXTENTS) size += sizeof(extentrecord);
1689: if (a & ATTR_FILE_RSRCLENGTH) size += sizeof(off_t);
1690: if (a & ATTR_FILE_RSRCALLOCSIZE) size += sizeof(off_t);
1691: if (a & ATTR_FILE_RSRCEXTENTS) size += sizeof(extentrecord);
1692: };
1693: if ((a = attrlist->forkattr) != 0) {
1694: if (a & ATTR_FORK_TOTALSIZE) size += sizeof(off_t);
1695: if (a & ATTR_FORK_ALLOCSIZE) size += sizeof(off_t);
1696: };
1697:
1698: return size;
1699: }
1700:
1701:
1702:
1703: void PackVolCommonAttributes(struct attrlist *alist,
1704: struct vnode *root_vp,
1705: struct hfsCatalogInfo *root_catInfo,
1706: void **attrbufptrptr,
1707: void **varbufptrptr) {
1708: void *attrbufptr;
1709: void *varbufptr;
1710: attrgroup_t a;
1711: struct hfsnode *root_hp = VTOH(root_vp);
1712: struct mount *mp = VTOVFS(root_vp);
1713: struct hfsmount *hfsmp = VTOHFS(root_vp);
1714: ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1715: u_long attrlength;
1716:
1717: attrbufptr = *attrbufptrptr;
1718: varbufptr = *varbufptrptr;
1719:
1720: if ((a = alist->commonattr) != 0) {
1721: if (a & ATTR_CMN_NAME) {
1722: attrlength = root_hp->h_meta->h_namelen+1;
1723: ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
1724: ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1725: (void) strncpy((unsigned char *)varbufptr, H_NAME(root_hp), attrlength);
1726:
1727: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1728: (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1729: ++((struct attrreference *)attrbufptr);
1730: };
1731: if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev;
1732: if (a & ATTR_CMN_FSID) {
1733: *((fsid_t *)attrbufptr) = mp->mnt_stat.f_fsid;
1734: if (vcb->vcbSigWord == kHFSSigWord) ((fsid_t *)attrbufptr)->val[0] |= 0x40000000;
1735: ++((fsid_t *)attrbufptr);
1736: };
1737: if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = 0;
1738: if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = VT_HFS;
1739: if (a & ATTR_CMN_OBJID) {
1740: ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1741: ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1742: ++((fsobj_id_t *)attrbufptr);
1743: };
1744: if (a & ATTR_CMN_OBJPERMANENTID) {
1745: ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1746: ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1747: ++((fsobj_id_t *)attrbufptr);
1748: };
1749: if (a & ATTR_CMN_PAROBJID) {
1750: ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1751: ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1752: ++((fsobj_id_t *)attrbufptr);
1753: };
1754: VCB_LOCK(vcb);
1755: if (a & ATTR_CMN_SCRIPT) *((text_encoding_t *)attrbufptr)++ = vcb->volumeNameEncodingHint;
1756: /* NOTE: all VCB dates are in local Mac OS time */
1757: if (a & ATTR_CMN_CRTIME) {
1758: /*
1759: * HFS Plus stores the volume create date in *local*
1760: * time in the volume header. So don't use the create
1761: * date from the vcb. Use the root's crtime instead.
1762: */
1763: if (vcb->vcbSigWord == kHFSPlusSigWord) {
1764: ((struct timespec *)attrbufptr)->tv_sec = root_hp->h_meta->h_crtime;
1765: } else {
1766: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbCrDate);
1767: }
1768: ((struct timespec *)attrbufptr)->tv_nsec = 0;
1769: ++((struct timespec *)attrbufptr);
1770: };
1771: if (a & ATTR_CMN_MODTIME) {
1772: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod);
1773: ((struct timespec *)attrbufptr)->tv_nsec = 0;
1774: ++((struct timespec *)attrbufptr);
1775: };
1776: if (a & ATTR_CMN_CHGTIME) {
1777: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod);
1778: ((struct timespec *)attrbufptr)->tv_nsec = 0;
1779: ++((struct timespec *)attrbufptr);
1780: };
1781: if (a & ATTR_CMN_ACCTIME) {
1782: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod);
1783: ((struct timespec *)attrbufptr)->tv_nsec = 0;
1784: ++((struct timespec *)attrbufptr);
1785: };
1786: if (a & ATTR_CMN_BKUPTIME) {
1787: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbVolBkUp);
1788: ((struct timespec *)attrbufptr)->tv_nsec = 0;
1789: ++((struct timespec *)attrbufptr);
1790: };
1791: if (a & ATTR_CMN_FNDRINFO) {
1792: bcopy (&vcb->vcbFndrInfo, attrbufptr, sizeof(vcb->vcbFndrInfo));
1793: (char *)attrbufptr += sizeof(vcb->vcbFndrInfo);
1794: };
1795: VCB_UNLOCK(vcb);
1796: if (a & ATTR_CMN_OWNERID) *((uid_t *)attrbufptr)++ = root_hp->h_meta->h_uid;
1797: if (a & ATTR_CMN_GRPID) *((gid_t *)attrbufptr)++ = root_hp->h_meta->h_gid;
1798: if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)root_hp->h_meta->h_mode;
1799: if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */
1800: if (a & ATTR_CMN_NAMEDATTRLIST) {
1801: attrlength = 0;
1802: ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1803: ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1804:
1805: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1806: (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1807: ++((struct attrreference *)attrbufptr);
1808: };
1809: if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = root_hp->h_meta->h_pflags;
1810: };
1811:
1812: *attrbufptrptr = attrbufptr;
1813: *varbufptrptr = varbufptr;
1814: }
1815:
1816:
1817:
1818: void PackVolAttributeBlock(struct attrlist *alist,
1819: struct vnode *root_vp,
1820: struct hfsCatalogInfo *root_catInfo,
1821: void **attrbufptrptr,
1822: void **varbufptrptr) {
1823: void *attrbufptr;
1824: void *varbufptr;
1825: attrgroup_t a;
1826: struct mount *mp = VTOVFS(root_vp);
1827: struct hfsmount *hfsmp = VTOHFS(root_vp);
1828: ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1829: u_long attrlength;
1830:
1831: attrbufptr = *attrbufptrptr;
1832: varbufptr = *varbufptrptr;
1833:
1834: if ((a = alist->volattr) != 0) {
1835: VCB_LOCK(vcb);
1836: if (a & ATTR_VOL_FSTYPE) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_vfc->vfc_typenum;
1837: if (a & ATTR_VOL_SIGNATURE) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbSigWord;
1838: if (a & ATTR_VOL_SIZE) *((off_t *)attrbufptr)++ = (off_t)vcb->totalBlocks * (off_t)vcb->blockSize;
1839: if (a & ATTR_VOL_SPACEFREE) *((off_t *)attrbufptr)++ = (off_t)vcb->freeBlocks * (off_t)vcb->blockSize;
1840: if (a & ATTR_VOL_SPACEAVAIL) *((off_t *)attrbufptr)++ = (off_t)vcb->freeBlocks * (off_t)vcb->blockSize;
1841: if (a & ATTR_VOL_MINALLOCATION) *((off_t *)attrbufptr)++ = (off_t)vcb->blockSize;
1842: if (a & ATTR_VOL_ALLOCATIONCLUMP) *((off_t *)attrbufptr)++ = (off_t)(vcb->vcbClpSiz);
1843: if (a & ATTR_VOL_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = (u_long)hfsmp->hfs_logBlockSize;
1844: if (a & ATTR_VOL_OBJCOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt + (u_long)vcb->vcbDirCnt;
1845: if (a & ATTR_VOL_FILECOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt;
1846: if (a & ATTR_VOL_DIRCOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbDirCnt;
1847: if (a & ATTR_VOL_MAXOBJCOUNT) *((u_long *)attrbufptr)++ = 0xFFFFFFFF;
1848: if (a & ATTR_VOL_MOUNTPOINT) {
1849: ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
1850: ((struct attrreference *)attrbufptr)->attr_length = strlen(mp->mnt_stat.f_mntonname) + 1;
1851: attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1852: attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */
1853: (void) bcopy(mp->mnt_stat.f_mntonname, varbufptr, attrlength);
1854:
1855: /* Advance beyond the space just allocated: */
1856: (char *)varbufptr += attrlength;
1857: ++((struct attrreference *)attrbufptr);
1858: };
1859: if (a & ATTR_VOL_NAME) {
1860: ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
1861: ((struct attrreference *)attrbufptr)->attr_length = VTOH(root_vp)->h_meta->h_namelen + 1;
1862: attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1863: attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */
1864: bcopy(H_NAME(VTOH(root_vp)), varbufptr, attrlength);
1865:
1866: /* Advance beyond the space just allocated: */
1867: (char *)varbufptr += attrlength;
1868: ++((struct attrreference *)attrbufptr);
1869: };
1870: if (a & ATTR_VOL_MOUNTFLAGS) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_flag;
1871: if (a & ATTR_VOL_MOUNTEDDEVICE) {
1872: ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
1873: ((struct attrreference *)attrbufptr)->attr_length = strlen(mp->mnt_stat.f_mntfromname) + 1;
1874: attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1875: attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */
1876: (void) bcopy(mp->mnt_stat.f_mntfromname, varbufptr, attrlength);
1877:
1878: /* Advance beyond the space just allocated: */
1879: (char *)varbufptr += attrlength;
1880: ++((struct attrreference *)attrbufptr);
1881: };
1882: if (a & ATTR_VOL_ENCODINGSUSED) *((unsigned long long *)attrbufptr)++ = (unsigned long long)vcb->encodingsBitmap;
1883: VCB_UNLOCK(vcb);
1884: };
1885:
1886: *attrbufptrptr = attrbufptr;
1887: *varbufptrptr = varbufptr;
1888: }
1889:
1890:
1891:
1892:
1893: void PackVolumeInfo(struct attrlist *alist,
1894: struct vnode *root_vp,
1895: struct hfsCatalogInfo *root_catinfo,
1896: void **attrbufptrptr,
1897: void **varbufptrptr) {
1898:
1899: PackVolCommonAttributes(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr);
1900: PackVolAttributeBlock(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr);
1901: };
1902:
1903: // Pack the common attribute contents of an objects hfsCatalogInfo
1904: void PackCommonCatalogInfoAttributeBlock(struct attrlist *alist,
1905: struct vnode *root_vp,
1906: struct hfsCatalogInfo *catalogInfo,
1907: void **attrbufptrptr,
1908: void **varbufptrptr )
1909: {
1910: struct hfsnode *hp;
1911: void *attrbufptr;
1912: void *varbufptr;
1913: attrgroup_t a;
1914: u_long attrlength;
1915:
1916: hp = VTOH(root_vp);
1917: attrbufptr = *attrbufptrptr;
1918: varbufptr = *varbufptrptr;
1919:
1920: if ((a = alist->commonattr) != 0)
1921: {
1922: if (a & ATTR_CMN_NAME)
1923: {
1924: attrlength = strlen(catalogInfo->spec.name) + 1;
1925: ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
1926: ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1927: (void) strncpy((unsigned char *)varbufptr, (unsigned char *) &(catalogInfo->spec.name), attrlength);
1928: // ((char *) varbufptr)[attrlength-1] = 0; // Now it's a C string
1929:
1930: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1931: (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1932: ++((struct attrreference *)attrbufptr);
1933: };
1934: if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = H_DEV(hp);
1935: if (a & ATTR_CMN_FSID) {
1936: *((fsid_t *)attrbufptr) = VTOVFS(root_vp)->mnt_stat.f_fsid;
1937: if (VTOVCB(root_vp)->vcbSigWord == kHFSSigWord) ((fsid_t *)attrbufptr)->val[0] |= 0x40000000;
1938: ++((fsid_t *)attrbufptr);
1939: };
1940: if (a & ATTR_CMN_OBJTYPE)
1941: {
1942: switch (catalogInfo->nodeData.cnd_type) {
1943: case kCatalogFolderNode:
1944: *((fsobj_type_t *)attrbufptr)++ = VDIR;
1945: break;
1946:
1947: case kCatalogFileNode:
1948: /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ... */
1949: if ((HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) &&
1950: (catalogInfo->nodeData.cnd_permissions & IFMT)) {
1951: *((fsobj_type_t *)attrbufptr)++ =
1952: IFTOVT((mode_t)(catalogInfo->nodeData.cnd_permissions & 0x0000FFFF));
1953: } else {
1954: *((fsobj_type_t *)attrbufptr)++ = VREG;
1955: };
1956: break;
1957:
1958: default:
1959: *((fsobj_type_t *)attrbufptr)++ = VNON;
1960: break;
1961: };
1962: }
1963: if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = root_vp->v_tag;
1964: if (a & ATTR_CMN_OBJID)
1965: {
1966: ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.cnd_nodeID;
1967: ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1968: ++((fsobj_id_t *)attrbufptr);
1969: };
1970: if (a & ATTR_CMN_OBJPERMANENTID)
1971: {
1972: ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.cnd_nodeID;
1973: ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1974: ++((fsobj_id_t *)attrbufptr);
1975: };
1976: if (a & ATTR_CMN_PAROBJID)
1977: {
1978: ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->spec.parID;
1979: ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1980: ++((fsobj_id_t *)attrbufptr);
1981: };
1982: if (a & ATTR_CMN_SCRIPT)
1983: {
1984: if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) {
1985: *((text_encoding_t *)attrbufptr)++ = catalogInfo->nodeData.cnd_textEncoding;
1986: } else {
1987: *((text_encoding_t *)attrbufptr)++ = VTOHFS(root_vp)->hfs_encoding;
1988: }
1989: };
1990: if (a & ATTR_CMN_CRTIME)
1991: {
1992: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_createDate);
1993: ((struct timespec *)attrbufptr)->tv_nsec = 0;
1994: ++((struct timespec *)attrbufptr);
1995: };
1996: if (a & ATTR_CMN_MODTIME)
1997: {
1998: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
1999: ((struct timespec *)attrbufptr)->tv_nsec = 0;
2000: ++((struct timespec *)attrbufptr);
2001: };
2002: if (a & ATTR_CMN_CHGTIME)
2003: {
2004: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_attributeModDate);
2005: ((struct timespec *)attrbufptr)->tv_nsec = 0;
2006: ++((struct timespec *)attrbufptr);
2007: };
2008: if (a & ATTR_CMN_ACCTIME)
2009: {
2010: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_accessDate);
2011: ((struct timespec *)attrbufptr)->tv_nsec = 0;
2012: ++((struct timespec *)attrbufptr);
2013: };
2014: if (a & ATTR_CMN_BKUPTIME)
2015: {
2016: ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_backupDate);
2017: ((struct timespec *)attrbufptr)->tv_nsec = 0;
2018: ++((struct timespec *)attrbufptr);
2019: };
2020: if (a & ATTR_CMN_FNDRINFO)
2021: {
2022: bcopy (&catalogInfo->nodeData.cnd_finderInfo, attrbufptr, sizeof(catalogInfo->nodeData.cnd_finderInfo));
2023: (char *)attrbufptr += sizeof(catalogInfo->nodeData.cnd_finderInfo);
2024: };
2025: if (a & ATTR_CMN_OWNERID) {
2026: *((uid_t *)attrbufptr)++ = catalogInfo->nodeData.cnd_ownerID;
2027: }
2028: if (a & ATTR_CMN_GRPID) {
2029: *((gid_t *)attrbufptr)++ = catalogInfo->nodeData.cnd_groupID;
2030: }
2031: if (a & ATTR_CMN_ACCESSMASK) {
2032: *((u_long *)attrbufptr)++ =
2033: (u_long)(mode_t)(catalogInfo->nodeData.cnd_permissions & 0x0000FFFF);
2034: }
2035: if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */
2036: if (a & ATTR_CMN_NAMEDATTRLIST)
2037: {
2038: attrlength = 0;
2039: ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
2040: ((struct attrreference *)attrbufptr)->attr_length = attrlength;
2041:
2042: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2043: (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
2044: ++((struct attrreference *)attrbufptr);
2045: };
2046: if (a & ATTR_CMN_FLAGS)
2047: *((u_long *)attrbufptr)++ =
2048: (u_long) ((((catalogInfo->nodeData.cnd_permissions & 0xFFFF0000) >> 8) & 0x00FF0000) |
2049: (((catalogInfo->nodeData.cnd_permissions & 0xFFFF0000) >> 24) & 0x000000FF));
2050: };
2051:
2052: *attrbufptrptr = attrbufptr;
2053: *varbufptrptr = varbufptr;
2054: }
2055:
2056:
2057: void PackCommonAttributeBlock(struct attrlist *alist,
2058: struct vnode *vp,
2059: struct hfsCatalogInfo *catInfo,
2060: void **attrbufptrptr,
2061: void **varbufptrptr) {
2062: struct hfsnode *hp;
2063: void *attrbufptr;
2064: void *varbufptr;
2065: attrgroup_t a;
2066: u_long attrlength;
2067:
2068: hp = VTOH(vp);
2069:
2070: attrbufptr = *attrbufptrptr;
2071: varbufptr = *varbufptrptr;
2072:
2073: if ((a = alist->commonattr) != 0) {
2074: if (a & ATTR_CMN_NAME) {
2075: attrlength = hp->h_meta->h_namelen + 1;
2076: ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
2077: ((struct attrreference *)attrbufptr)->attr_length = attrlength;
2078: (void) strncpy((unsigned char *)varbufptr, H_NAME(hp), attrlength);
2079:
2080: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2081: (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
2082: ++((struct attrreference *)attrbufptr);
2083: };
2084: if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = H_DEV(hp);
2085: if (a & ATTR_CMN_FSID) {
2086: *((fsid_t *)attrbufptr) = VTOVFS(vp)->mnt_stat.f_fsid;
2087: if (VTOVCB(vp)->vcbSigWord == kHFSSigWord) ((fsid_t *)attrbufptr)->val[0] |= 0x40000000;
2088: ++((fsid_t *)attrbufptr);
2089: };
2090: if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = vp->v_type;
2091: if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = vp->v_tag;
2092: if (a & ATTR_CMN_OBJID) {
2093: ((fsobj_id_t *)attrbufptr)->fid_objno = H_FILEID(hp);
2094: ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
2095: ++((fsobj_id_t *)attrbufptr);
2096: };
2097: if (a & ATTR_CMN_OBJPERMANENTID) {
2098: ((fsobj_id_t *)attrbufptr)->fid_objno = H_FILEID(hp);
2099: ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
2100: ++((fsobj_id_t *)attrbufptr);
2101: };
2102: if (a & ATTR_CMN_PAROBJID) {
2103: ((fsobj_id_t *)attrbufptr)->fid_objno = H_DIRID(hp);
2104: ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
2105: ++((fsobj_id_t *)attrbufptr);
2106: };
2107: if (a & ATTR_CMN_SCRIPT)
2108: {
2109: if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) {
2110: *((text_encoding_t *)attrbufptr)++ = catInfo->nodeData.cnd_textEncoding;
2111: } else {
2112: *((text_encoding_t *)attrbufptr)++ = VTOHFS(vp)->hfs_encoding;
2113: }
2114: };
2115: if (a & ATTR_CMN_CRTIME) {
2116: ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_crtime;
2117: ((struct timespec *)attrbufptr)->tv_nsec = 0;
2118: ++((struct timespec *)attrbufptr);
2119: };
2120: if (a & ATTR_CMN_MODTIME) {
2121: ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_mtime;
2122: ((struct timespec *)attrbufptr)->tv_nsec = 0;
2123: ++((struct timespec *)attrbufptr);
2124: };
2125: if (a & ATTR_CMN_CHGTIME) {
2126: ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_ctime;
2127: ((struct timespec *)attrbufptr)->tv_nsec = 0;
2128: ++((struct timespec *)attrbufptr);
2129: };
2130: if (a & ATTR_CMN_ACCTIME) {
2131: ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_atime;
2132: ((struct timespec *)attrbufptr)->tv_nsec = 0;
2133: ++((struct timespec *)attrbufptr);
2134: };
2135: if (a & ATTR_CMN_BKUPTIME) {
2136: ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_butime;
2137: ((struct timespec *)attrbufptr)->tv_nsec = 0;
2138: ++((struct timespec *)attrbufptr);
2139: };
2140: if (a & ATTR_CMN_FNDRINFO) {
2141: bcopy (&catInfo->nodeData.cnd_finderInfo, attrbufptr, sizeof(catInfo->nodeData.cnd_finderInfo));
2142: (char *)attrbufptr += sizeof(catInfo->nodeData.cnd_finderInfo);
2143: };
2144: if (a & ATTR_CMN_OWNERID) *((uid_t *)attrbufptr)++ = hp->h_meta->h_uid;
2145: if (a & ATTR_CMN_GRPID) *((gid_t *)attrbufptr)++ = hp->h_meta->h_gid;
2146: if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)hp->h_meta->h_mode;
2147: if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */
2148: if (a & ATTR_CMN_NAMEDATTRLIST) {
2149: attrlength = 0;
2150: ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
2151: ((struct attrreference *)attrbufptr)->attr_length = attrlength;
2152:
2153: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2154: (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
2155: ++((struct attrreference *)attrbufptr);
2156: };
2157: if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = hp->h_meta->h_pflags;
2158: };
2159:
2160: *attrbufptrptr = attrbufptr;
2161: *varbufptrptr = varbufptr;
2162: }
2163:
2164:
2165: // Pack the directory attributes given hfsCatalogInfo
2166: void PackCatalogInfoDirAttributeBlock( struct attrlist *alist, struct vnode *vp,
2167: struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr )
2168: {
2169: void *attrbufptr;
2170: attrgroup_t a;
2171: u_long valence;
2172:
2173: attrbufptr = *attrbufptrptr;
2174: a = alist->dirattr;
2175:
2176: if ( (catInfo->nodeData.cnd_type == kCatalogFolderNode) && (a != 0) ) {
2177: valence = catInfo->nodeData.cnd_valence;
2178: if ((catInfo->spec.parID == kRootParID) &&
2179: (VTOHFS(vp)->hfs_private_metadata_dir != 0)) {
2180: --valence; /* hide private dir */
2181: }
2182: /* The 'link count' is faked */
2183: if (a & ATTR_DIR_LINKCOUNT)
2184: *((u_long *)attrbufptr)++ = 2 + valence;
2185: if (a & ATTR_DIR_ENTRYCOUNT)
2186: *((u_long *)attrbufptr)++ = valence;
2187: };
2188:
2189: *attrbufptrptr = attrbufptr;
2190: }
2191:
2192:
2193: void PackDirAttributeBlock(struct attrlist *alist,
2194: struct vnode *vp,
2195: struct hfsCatalogInfo *catInfo,
2196: void **attrbufptrptr,
2197: void **varbufptrptr) {
2198: void *attrbufptr;
2199: attrgroup_t a;
2200: u_long valence;
2201:
2202: attrbufptr = *attrbufptrptr;
2203:
2204: a = alist->dirattr;
2205: if ((vp->v_type == VDIR) && (a != 0)) {
2206: valence = catInfo->nodeData.cnd_valence;
2207: if ((catInfo->spec.parID == kRootParID) &&
2208: (VTOHFS(vp)->hfs_private_metadata_dir != 0)) {
2209: --valence; /* hide private dir */
2210: }
2211:
2212: /* The 'link count' is faked */
2213: if (a & ATTR_DIR_LINKCOUNT)
2214: *((u_long *)attrbufptr)++ = 2 + valence;
2215: if (a & ATTR_DIR_ENTRYCOUNT)
2216: *((u_long *)attrbufptr)++ = valence;
2217: };
2218:
2219: *attrbufptrptr = attrbufptr;
2220: }
2221:
2222:
2223:
2224: // Pack the file attributes from the hfsCatalogInfo for the file.
2225: void PackCatalogInfoFileAttributeBlock( struct attrlist *alist, struct vnode *root_vp, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr )
2226: {
2227: void *attrbufptr;
2228: void *varbufptr;
2229: attrgroup_t a;
2230: u_long attrlength;
2231: ExtendedVCB *vcb = VTOVCB(root_vp);
2232:
2233: attrbufptr = *attrbufptrptr;
2234: varbufptr = *varbufptrptr;
2235:
2236: a = alist->fileattr;
2237: if ( (catInfo->nodeData.cnd_type == kCatalogFileNode) && (a != 0) )
2238: {
2239: #if HFS_HARDLINKS
2240: if (a & ATTR_FILE_LINKCOUNT) {
2241: u_long linkcnt = catInfo->nodeData.cnd_linkCount;
2242:
2243: if (linkcnt < 1)
2244: linkcnt = 1;
2245: *((u_long *)attrbufptr)++ = linkcnt;
2246: }
2247: #else
2248: if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1;
2249: #endif
2250: if (a & ATTR_FILE_TOTALSIZE) {
2251: *((off_t *)attrbufptr)++ =
2252: (off_t)catInfo->nodeData.cnd_datafork.logicalSize +
2253: (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
2254: }
2255: if (a & ATTR_FILE_ALLOCSIZE) {
2256: *((off_t *)attrbufptr)++ =
2257: (off_t)(catInfo->nodeData.cnd_datafork.totalBlocks * vcb->blockSize) +
2258: (off_t)(catInfo->nodeData.cnd_rsrcfork.totalBlocks * vcb->blockSize);
2259: }
2260: if (a & ATTR_FILE_IOBLOCKSIZE) {
2261: *((u_long *)attrbufptr)++ = (u_long)(VTOHFS(root_vp)->hfs_logBlockSize);
2262: }
2263: if (a & ATTR_FILE_CLUMPSIZE) {
2264: *((u_long *)attrbufptr)++ = vcb->vcbClpSiz;
2265: }
2266: if (a & ATTR_FILE_DEVTYPE) {
2267: *((u_long *)attrbufptr)++ =
2268: (u_long)catInfo->nodeData.cnd_specialDevice;
2269: }
2270: if (a & ATTR_FILE_FILETYPE) {
2271: *((u_long *)attrbufptr)++ = 0; /* XXX PPD */
2272: }
2273: if (a & ATTR_FILE_FORKCOUNT) {
2274: *((u_long *)attrbufptr)++ = 2; /* XXX PPD */
2275: }
2276: if (a & ATTR_FILE_FORKLIST) {
2277: attrlength = 0;
2278: ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
2279: ((struct attrreference *)attrbufptr)->attr_length = attrlength;
2280:
2281: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2282: (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
2283: ++((struct attrreference *)attrbufptr);
2284: };
2285: if (a & ATTR_FILE_DATALENGTH) {
2286: *((off_t *)attrbufptr)++ =
2287: (off_t)catInfo->nodeData.cnd_datafork.logicalSize;
2288: }
2289: if (a & ATTR_FILE_DATAALLOCSIZE) {
2290: *((off_t *)attrbufptr)++ =
2291: (off_t)(catInfo->nodeData.cnd_datafork.totalBlocks * vcb->blockSize);
2292: }
2293: if (a & ATTR_FILE_DATAEXTENTS) {
2294: bcopy(&catInfo->nodeData.cnd_datafork.extents, attrbufptr, sizeof(extentrecord));
2295: (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2296: };
2297: if (a & ATTR_FILE_RSRCLENGTH) {
2298: *((off_t *)attrbufptr)++ =
2299: (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
2300: }
2301: if (a & ATTR_FILE_RSRCALLOCSIZE) {
2302: *((off_t *)attrbufptr)++ =
2303: (off_t)(catInfo->nodeData.cnd_rsrcfork.totalBlocks * vcb->blockSize);
2304: }
2305: if (a & ATTR_FILE_RSRCEXTENTS) {
2306: bcopy(&catInfo->nodeData.cnd_rsrcfork.extents, attrbufptr, sizeof(extentrecord));
2307: (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2308: };
2309: };
2310:
2311: *attrbufptrptr = attrbufptr;
2312: *varbufptrptr = varbufptr;
2313: }
2314:
2315:
2316: void PackFileAttributeBlock(struct attrlist *alist,
2317: struct vnode *vp,
2318: struct hfsCatalogInfo *catInfo,
2319: void **attrbufptrptr,
2320: void **varbufptrptr) {
2321: struct hfsnode *hp = VTOH(vp);
2322: FCB *fcb = HTOFCB(hp);
2323: ExtendedVCB *vcb = HTOVCB(hp);
2324: Boolean isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
2325: void *attrbufptr = *attrbufptrptr;
2326: void *varbufptr = *varbufptrptr;
2327: attrgroup_t a = alist->fileattr;
2328: u_long attrlength;
2329:
2330: if (a != 0) {
2331: #if HFS_HARDLINKS
2332: if (a & ATTR_FILE_LINKCOUNT) {
2333: u_long linkcnt = catInfo->nodeData.cnd_linkCount;
2334:
2335: if (linkcnt < 1)
2336: linkcnt = 1;
2337: *((u_long *)attrbufptr)++ = linkcnt;
2338: }
2339: #else
2340: if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1;
2341: #endif
2342: if (a & ATTR_FILE_TOTALSIZE) {
2343: *((off_t *)attrbufptr)++ =
2344: (off_t)catInfo->nodeData.cnd_datafork.logicalSize +
2345: (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
2346: }
2347: if (a & ATTR_FILE_ALLOCSIZE) {
2348: switch (H_FORKTYPE(hp)) {
2349: case kDataFork:
2350: *((off_t *)attrbufptr)++ =
2351: (off_t)fcb->fcbPLen +
2352: (off_t)(catInfo->nodeData.cnd_rsrcfork.totalBlocks * vcb->blockSize);
2353: break;
2354: case kRsrcFork:
2355: *((off_t *)attrbufptr)++ =
2356: (off_t)fcb->fcbPLen +
2357: (off_t)(catInfo->nodeData.cnd_datafork.totalBlocks * vcb->blockSize);
2358: break;
2359: default:
2360: *((off_t *)attrbufptr)++ =
2361: (off_t)(catInfo->nodeData.cnd_datafork.totalBlocks * vcb->blockSize) +
2362: (off_t)(catInfo->nodeData.cnd_rsrcfork.totalBlocks * vcb->blockSize);
2363: };
2364: };
2365: if (a & ATTR_FILE_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = GetLogicalBlockSize(vp);
2366: if (a & ATTR_FILE_CLUMPSIZE) *((u_long *)attrbufptr)++ = fcb->fcbClmpSize;
2367: if (a & ATTR_FILE_DEVTYPE) {
2368: *((u_long *)attrbufptr)++ = (u_long)catInfo->nodeData.cnd_specialDevice;
2369: }
2370: if (a & ATTR_FILE_FILETYPE) *((u_long *)attrbufptr)++ = 0; /* XXX PPD */
2371: if (a & ATTR_FILE_FORKCOUNT) *((u_long *)attrbufptr)++ = 2; /* XXX PPD */
2372: if (a & ATTR_FILE_FORKLIST) {
2373: attrlength = 0;
2374: ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
2375: ((struct attrreference *)attrbufptr)->attr_length = attrlength;
2376:
2377: /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2378: (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
2379: ++((struct attrreference *)attrbufptr);
2380: };
2381: if (H_FORKTYPE(hp) == kDataFork) {
2382: if (a & ATTR_FILE_DATALENGTH)
2383: #if MACH_NBC
2384: if ((vp->v_type == VREG) && vp->v_vm_info && vp->v_vm_info->mapped &&
2385: (!vp->v_vm_info->filesize)) {
2386: *((off_t *)attrbufptr)++ = vp->v_vm_info->vnode_size;
2387: }
2388: else
2389: #endif /* MACH_NBC */
2390: *((off_t *)attrbufptr)++ = fcb->fcbEOF;
2391: if (a & ATTR_FILE_DATAALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen;
2392: if (a & ATTR_FILE_DATAEXTENTS) {
2393: bcopy ( fcb->fcbExtents, attrbufptr, sizeof(extentrecord));
2394: (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2395: };
2396: } else {
2397: if (a & ATTR_FILE_DATALENGTH) {
2398: *((off_t *)attrbufptr)++ =
2399: (off_t)catInfo->nodeData.cnd_datafork.logicalSize;
2400: }
2401: if (a & ATTR_FILE_DATAALLOCSIZE) {
2402: *((off_t *)attrbufptr)++ =
2403: (off_t)(catInfo->nodeData.cnd_datafork.totalBlocks * vcb->blockSize);
2404: }
2405: if (a & ATTR_FILE_DATAEXTENTS) {
2406: bcopy(&catInfo->nodeData.cnd_datafork.extents, attrbufptr, sizeof(extentrecord));
2407: (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2408: };
2409: };
2410: if (H_FORKTYPE(hp) == kRsrcFork) {
2411: if (a & ATTR_FILE_RSRCLENGTH)
2412: #if MACH_NBC
2413: if ((vp->v_type == VREG) && vp->v_vm_info && vp->v_vm_info->mapped &&
2414: (!vp->v_vm_info->filesize)) {
2415: *((off_t *)attrbufptr)++ = vp->v_vm_info->vnode_size;
2416: }
2417: else
2418: #endif /* MACH_NBC */
2419: *((off_t *)attrbufptr)++ = fcb->fcbEOF;
2420: if (a & ATTR_FILE_RSRCALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen;
2421: if (a & ATTR_FILE_RSRCEXTENTS) {
2422: bcopy ( fcb->fcbExtents, attrbufptr, sizeof(extentrecord));
2423: (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2424: };
2425: } else {
2426: if (a & ATTR_FILE_RSRCLENGTH) {
2427: *((off_t *)attrbufptr)++ =
2428: (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
2429: }
2430: if (a & ATTR_FILE_RSRCALLOCSIZE) {
2431: *((off_t *)attrbufptr)++ =
2432: (off_t)(catInfo->nodeData.cnd_rsrcfork.totalBlocks * vcb->blockSize);
2433: }
2434: if (a & ATTR_FILE_RSRCEXTENTS) {
2435: bcopy(&catInfo->nodeData.cnd_rsrcfork.extents, attrbufptr, sizeof(extentrecord));
2436: (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2437: };
2438: };
2439: };
2440:
2441: *attrbufptrptr = attrbufptr;
2442: *varbufptrptr = varbufptr;
2443: }
2444:
2445: #if 0
2446: void PackForkAttributeBlock(struct attrlist *alist,
2447: struct vnode *vp,
2448: struct hfsCatalogInfo *catInfo,
2449: void **attrbufptrptr,
2450: void **varbufptrptr) {
2451: /* XXX PPD TBC */
2452: }
2453: #endif
2454:
2455:
2456: // This routine takes catInfo, and alist, as inputs and packs it into an attribute block.
2457: void PackCatalogInfoAttributeBlock ( struct attrlist *alist, struct vnode *root_vp, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr)
2458: {
2459: //XXX Preflight that alist only contains bits with fields in catInfo
2460:
2461: PackCommonCatalogInfoAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr );
2462:
2463: switch ( catInfo->nodeData.cnd_type )
2464: {
2465: case kCatalogFolderNode:
2466: PackCatalogInfoDirAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr );
2467: break;
2468:
2469: case kCatalogFileNode:
2470: PackCatalogInfoFileAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr );
2471: break;
2472:
2473: default: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR not being handled... */
2474: /* XXX PPD - Panic? */
2475: break;
2476: }
2477: }
2478:
2479:
2480:
2481: void PackAttributeBlock(struct attrlist *alist,
2482: struct vnode *vp,
2483: struct hfsCatalogInfo *catInfo,
2484: void **attrbufptrptr,
2485: void **varbufptrptr)
2486: {
2487: if (alist->volattr != 0) {
2488: DBG_ASSERT((vp->v_flag & VROOT) != 0);
2489: PackVolumeInfo(alist,vp, catInfo, attrbufptrptr, varbufptrptr);
2490: } else {
2491: PackCommonAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
2492:
2493: switch (vp->v_type) {
2494: case VDIR:
2495: PackDirAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
2496: break;
2497:
2498: case VREG:
2499: case VLNK:
2500: PackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
2501: break;
2502:
2503: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
2504: not being handled...
2505: */
2506: default:
2507: /* XXX PPD - Panic? */
2508: break;
2509: };
2510: };
2511: };
2512:
2513:
2514:
2515: void UnpackVolumeAttributeBlock(struct attrlist *alist,
2516: struct vnode *root_vp,
2517: ExtendedVCB *vcb,
2518: void **attrbufptrptr,
2519: void **varbufptrptr) {
2520: void *attrbufptr = *attrbufptrptr;
2521: attrgroup_t a;
2522: text_encoding_t nameEncoding;
2523:
2524: if ((alist->commonattr == 0) && (alist->volattr == 0)) {
2525: return; /* Get out without dirtying the VCB */
2526: };
2527:
2528: VCB_LOCK(vcb);
2529:
2530: a = alist->commonattr;
2531:
2532: if (a & ATTR_CMN_SCRIPT) {
2533: /* XXX PPD No use for this info right now... */
2534: nameEncoding = *(((text_encoding_t *)attrbufptr)++);
2535: #if HFS_DIAGNOSTIC
2536: a &= ~ATTR_CMN_SCRIPT;
2537: #endif
2538: };
2539: if (a & ATTR_CMN_CRTIME) {
2540: /*
2541: * HFS Plus stores the volume create date in *local*
2542: * time in the volume header. So don't set the create
2543: * date in the vcb. Set the root's crtime instead.
2544: */
2545: if (vcb->vcbSigWord == kHFSPlusSigWord) {
2546: VTOH(root_vp)->h_meta->h_crtime =
2547: (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2548: } else {
2549: vcb->vcbCrDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2550: }
2551: ++((struct timespec *)attrbufptr);
2552: #if HFS_DIAGNOSTIC
2553: a &= ~ATTR_CMN_CRTIME;
2554: #endif
2555: };
2556: if (a & ATTR_CMN_MODTIME) {
2557: vcb->vcbLsMod = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2558: ++((struct timespec *)attrbufptr);
2559: #if HFS_DIAGNOSTIC
2560: a &= ~ATTR_CMN_MODTIME;
2561: #endif
2562: };
2563: if (a & ATTR_CMN_BKUPTIME) {
2564: vcb->vcbVolBkUp = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2565: ++((struct timespec *)attrbufptr);
2566: #if HFS_DIAGNOSTIC
2567: a &= ~ATTR_CMN_BKUPTIME;
2568: #endif
2569: };
2570: if (a & ATTR_CMN_FNDRINFO) {
2571: bcopy (attrbufptr, &vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo));
2572: (char *)attrbufptr += sizeof(vcb->vcbFndrInfo);
2573: #if HFS_DIAGNOSTIC
2574: a &= ~ATTR_CMN_FNDRINFO;
2575: #endif
2576: };
2577:
2578: DBG_ASSERT(a == 0); /* All common attributes for volumes must've been handled by now... */
2579:
2580: a = alist->volattr & ~ATTR_VOL_INFO;
2581: if (a & ATTR_VOL_NAME) {
2582: copystr(((char *)attrbufptr) + *((u_long *)attrbufptr), vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
2583: (char *)attrbufptr += sizeof(struct attrreference);
2584: #if HFS_DIAGNOSTIC
2585: a &= ~ATTR_VOL_NAME;
2586: #endif
2587: };
2588:
2589: DBG_ASSERT(a == 0); /* All common attributes for volumes must've been handled by now... */
2590:
2591: vcb->vcbFlags |= 0xFF00; // Mark the VCB dirty
2592:
2593: VCB_UNLOCK(vcb);
2594: }
2595:
2596:
2597: void UnpackCommonAttributeBlock(struct attrlist *alist,
2598: struct vnode *vp,
2599: struct hfsCatalogInfo *catInfo,
2600: void **attrbufptrptr,
2601: void **varbufptrptr) {
2602: struct hfsnode *hp = VTOH(vp);
2603: void *attrbufptr;
2604: attrgroup_t a;
2605:
2606: attrbufptr = *attrbufptrptr;
2607:
2608: DBG_ASSERT(catInfo != NULL);
2609:
2610: a = alist->commonattr;
2611: if (a & ATTR_CMN_SCRIPT) {
2612: /* XXX PPD No use for this info right now... */
2613: ++((text_encoding_t *)attrbufptr);
2614: #if HFS_DIAGNOSTIC
2615: a &= ~ATTR_CMN_SCRIPT;
2616: #endif
2617: };
2618: if (a & ATTR_CMN_CRTIME) {
2619: catInfo->nodeData.cnd_createDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2620: VTOH(vp)->h_meta->h_crtime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2621: ++((struct timespec *)attrbufptr);
2622: #if HFS_DIAGNOSTIC
2623: a &= ~ATTR_CMN_CRTIME;
2624: #endif
2625: };
2626: if (a & ATTR_CMN_MODTIME) {
2627: catInfo->nodeData.cnd_contentModDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2628: VTOH(vp)->h_meta->h_mtime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2629: ++((struct timespec *)attrbufptr);
2630: #if HFS_DIAGNOSTIC
2631: a &= ~ATTR_CMN_MODTIME;
2632: #endif
2633: };
2634: if (a & ATTR_CMN_CHGTIME) {
2635: catInfo->nodeData.cnd_attributeModDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2636: VTOH(vp)->h_meta->h_ctime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2637: ++((struct timespec *)attrbufptr);
2638: #if HFS_DIAGNOSTIC
2639: a &= ~ATTR_CMN_CHGTIME;
2640: #endif
2641: };
2642: if (a & ATTR_CMN_ACCTIME) {
2643: catInfo->nodeData.cnd_accessDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2644: VTOH(vp)->h_meta->h_atime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2645: ++((struct timespec *)attrbufptr);
2646: #if HFS_DIAGNOSTIC
2647: a &= ~ATTR_CMN_ACCTIME;
2648: #endif
2649: };
2650: if (a & ATTR_CMN_BKUPTIME) {
2651: catInfo->nodeData.cnd_backupDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2652: VTOH(vp)->h_meta->h_butime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2653: ++((struct timespec *)attrbufptr);
2654: #if HFS_DIAGNOSTIC
2655: a &= ~ATTR_CMN_BKUPTIME;
2656: #endif
2657: };
2658: if (a & ATTR_CMN_FNDRINFO) {
2659: bcopy (attrbufptr, &catInfo->nodeData.cnd_finderInfo, sizeof(catInfo->nodeData.cnd_finderInfo));
2660: (char *)attrbufptr += sizeof(catInfo->nodeData.cnd_finderInfo);
2661: #if HFS_DIAGNOSTIC
2662: a &= ~ATTR_CMN_FNDRINFO;
2663: #endif
2664: };
2665: if (a & ATTR_CMN_OWNERID) {
2666: if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
2667: u_int32_t uid = (u_int32_t)*((uid_t *)attrbufptr)++;
2668: if (uid != (uid_t)VNOVAL)
2669: hp->h_meta->h_uid = uid; /* catalog will get updated by hfs_chown() */
2670: }
2671: else {
2672: ((uid_t *)attrbufptr)++;
2673: }
2674: #if HFS_DIAGNOSTIC
2675: a &= ~ATTR_CMN_OWNERID;
2676: #endif
2677: };
2678: if (a & ATTR_CMN_GRPID) {
2679: u_int32_t gid = (u_int32_t)*((gid_t *)attrbufptr)++;
2680: if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
2681: if (gid != (gid_t)VNOVAL)
2682: hp->h_meta->h_gid = gid; /* catalog will get updated by hfs_chown() */
2683: };
2684: #if HFS_DIAGNOSTIC
2685: a &= ~ATTR_CMN_GRPID;
2686: #endif
2687: };
2688: if (a & ATTR_CMN_ACCESSMASK) {
2689: u_int16_t mode = (u_int16_t)*((u_long *)attrbufptr)++;
2690: if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
2691: if (mode != (mode_t)VNOVAL) {
2692: hp->h_meta->h_mode &= ~ALLPERMS;
2693: hp->h_meta->h_mode |= (mode & ALLPERMS); /* catalog will get updated by hfs_chmod() */
2694: }
2695: };
2696: #if HFS_DIAGNOSTIC
2697: a &= ~ATTR_CMN_ACCESSMASK;
2698: #endif
2699: };
2700: if (a & ATTR_CMN_FLAGS) {
2701: u_long flags = *((u_long *)attrbufptr)++;
2702: /* Flags are settable only on HFS+ volumes. A special exception is made for the IMMUTABLE
2703: flags (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on HFS volumes as well: */
2704: if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) ||
2705: ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && ((flags & ~IMMUTABLE) == 0))) {
2706: if (flags != (u_long)VNOVAL) {
2707: hp->h_meta->h_pflags = flags; /* catalog will get updated by hfs_chflags */
2708: };
2709: };
2710: #if HFS_DIAGNOSTIC
2711: a &= ~ATTR_CMN_FLAGS;
2712: #endif
2713: };
2714:
2715: #if HFS_DIAGNOSTIC
2716: if (a != 0) {
2717: DEBUG_BREAK_MSG(("UnpackCommonAttributes: unhandled bit: 0x%08X\n", a));
2718: };
2719: #endif
2720:
2721: *attrbufptrptr = attrbufptr;
2722: // *varbufptrptr = varbufptr;
2723: }
2724:
2725:
2726:
2727: #if 0
2728: void UnpackDirAttributeBlock(struct attrlist *alist,
2729: struct vnode *vp,
2730: struct hfsCatalogInfo *catInfo,
2731: void **attrbufptrptr,
2732: void **varbufptrptr) {
2733: void *attrbufptr;
2734: void *varbufptr;
2735: attrgroup_t a;
2736: u_long attrlength;
2737:
2738: attrbufptr = *attrbufptrptr;
2739: varbufptr = *varbufptrptr;
2740:
2741: /* XXX PPD TBC */
2742:
2743: *attrbufptrptr = attrbufptr;
2744: *varbufptrptr = varbufptr;
2745: }
2746: #endif
2747:
2748:
2749:
2750: #if 0
2751: void UnpackFileAttributeBlock(struct attrlist *alist,
2752: struct vnode *vp,
2753: struct hfsCatalogInfo *catInfo,
2754: void **attrbufptrptr,
2755: void **varbufptrptr) {
2756: void *attrbufptr;
2757: void *varbufptr;
2758: attrgroup_t a;
2759: u_long attrlength;
2760:
2761: attrbufptr = *attrbufptrptr;
2762: varbufptr = *varbufptrptr;
2763:
2764: /* XXX PPD TBC */
2765:
2766: *attrbufptrptr = attrbufptr;
2767: *varbufptrptr = varbufptr;
2768: }
2769: #endif
2770:
2771:
2772:
2773: #if 0
2774: void UnpackForkAttributeBlock(struct attrlist *alist,
2775: struct vnode *vp,
2776: struct hfsCatalogInfo *catInfo,
2777: void **attrbufptrptr,
2778: void **varbufptrptr) {
2779: void *attrbufptr;
2780: void *varbufptr;
2781: attrgroup_t a;
2782: u_long attrlength;
2783:
2784: attrbufptr = *attrbufptrptr;
2785: varbufptr = *varbufptrptr;
2786:
2787: /* XXX PPD TBC */
2788:
2789: *attrbufptrptr = attrbufptr;
2790: *varbufptrptr = varbufptr;
2791: }
2792: #endif
2793:
2794:
2795:
2796: void UnpackAttributeBlock(struct attrlist *alist,
2797: struct vnode *vp,
2798: struct hfsCatalogInfo *catInfo,
2799: void **attrbufptrptr,
2800: void **varbufptrptr) {
2801:
2802:
2803: if (alist->volattr != 0) {
2804: UnpackVolumeAttributeBlock(alist, vp, VTOVCB(vp), attrbufptrptr, varbufptrptr);
2805: return;
2806: };
2807:
2808: /* We're dealing with a vnode object here: */
2809: UnpackCommonAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
2810:
2811: #if 0
2812: switch (vp->v_type) {
2813: case VDIR:
2814: UnpackDirAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
2815: break;
2816:
2817: case VREG:
2818: /* case VCPLX: */ /* XXX PPD TBC */
2819: UnpackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
2820: break;
2821:
2822: case VFORK:
2823: UnpackForkAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
2824: break;
2825:
2826: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
2827: not being handled...
2828: */
2829: default:
2830: /* XXX PPD - Panic? */
2831: break;
2832: };
2833: #endif
2834:
2835: };
2836:
2837:
2838: unsigned long BestBlockSizeFit(unsigned long allocationBlockSize,
2839: unsigned long blockSizeLimit,
2840: unsigned long baseMultiple) {
2841: /*
2842: Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the
2843: specified limit but still an even multiple of the baseMultiple.
2844: */
2845: int baseBlockCount, blockCount;
2846: unsigned long trialBlockSize;
2847:
2848: if (allocationBlockSize % baseMultiple != 0) {
2849: /*
2850: Whoops: the allocation blocks aren't even multiples of the specified base:
2851: no amount of dividing them into even parts will be a multiple, either then!
2852: */
2853: return 512; /* Hope for the best */
2854: };
2855:
2856: /* Try the obvious winner first, to prevent 12K allocation blocks, for instance,
2857: from being handled as two 6K logical blocks instead of 3 4K logical blocks.
2858: Even though the former (the result of the loop below) is the larger allocation
2859: block size, the latter is more efficient: */
2860: if (allocationBlockSize % PAGE_SIZE == 0) return PAGE_SIZE;
2861:
2862: /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */
2863: baseBlockCount = allocationBlockSize / baseMultiple; /* Now guaranteed to be an even multiple */
2864:
2865: for (blockCount = baseBlockCount; blockCount > 0; --blockCount) {
2866: trialBlockSize = blockCount * baseMultiple;
2867: if (allocationBlockSize % trialBlockSize == 0) { /* An even multiple? */
2868: if ((trialBlockSize <= blockSizeLimit) &&
2869: (trialBlockSize % baseMultiple == 0)) {
2870: return trialBlockSize;
2871: };
2872: };
2873: };
2874:
2875: /* Note: we should never get here, since blockCount = 1 should always work,
2876: but this is nice and safe and makes the compiler happy, too ... */
2877: return 512;
2878: }
2879:
2880:
2881: /*
2882: * To make the HFS filesystem follow UFS unlink semantics, a remove of
2883: * an active vnode is translated to a move/rename so the file appears
2884: * deleted. The destination folder for these move/renames is setup here
2885: * and a reference to it is place in hfsmp->hfs_private_metadata_dir.
2886: */
2887: u_long
2888: FindMetaDataDirectory(ExtendedVCB *vcb)
2889: {
2890: char namep[32];
2891: hfsCatalogInfo catInfo;
2892: HFSCatalogNodeID dirID;
2893: int retval;
2894:
2895: dirID = 0;
2896: strncpy(namep, HFSPLUSMETADATAFOLDER, sizeof(namep));
2897:
2898: /* lock catalog b-tree */
2899: retval = hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_SHARED, current_proc());
2900: if (retval)
2901: goto Err_Exit;
2902:
2903: catInfo.hint = kNoHint;
2904: if (hfsLookup(vcb, kRootDirID, namep, -1, &catInfo) == 0)
2905: dirID = catInfo.nodeData.cnd_nodeID;
2906: else if (VCBTOHFS(vcb)->hfs_fs_ronly == 0) {
2907: if (CreateCatalogNode(vcb, kRootDirID, namep, kCatalogFolderNode, &dirID, &catInfo.hint) == 0) {
2908: catInfo.hint = kNoHint;
2909: if (hfsLookup(vcb, kRootDirID, namep, -1, &catInfo) == 0) {
2910:
2911: /* directory with no permissions owned by root */
2912: catInfo.nodeData.cnd_permissions = IFDIR;
2913:
2914: /* hidden and off the desktop view */
2915: ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frLocation.v = 22460;
2916: ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frLocation.h = 22460;
2917: ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frFlags |= (kIsInvisible + kNameLocked);
2918:
2919: (void) UpdateCatalogNode(vcb, kRootDirID, namep, catInfo.hint, &catInfo.nodeData);
2920: }
2921: }
2922: }
2923:
2924: /* unlock catalog b-tree */
2925: (void) hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_RELEASE, current_proc());
2926:
2927:
2928: Err_Exit:
2929:
2930: return dirID;
2931: }
2932:
2933: /*
2934: * This will return the correct logical block size for a given vnode.
2935: * For most files, it is the allocation block size, for meta data like
2936: * BTrees, this is kept as part of the BTree private nodeSize
2937: */
2938: u_int32_t
2939: GetLogicalBlockSize(struct vnode *vp)
2940: {
2941: u_int32_t logBlockSize;
2942:
2943: DBG_ASSERT(vp != NULL);
2944:
2945: if ((vp->v_flag & VSYSTEM) && (VTOH(vp)->fcbBTCBPtr!=NULL)) {
2946: BTreeInfoRec bTreeInfo;
2947: int retval;
2948:
2949: /*
2950: * We do not lock the BTrees, because if we are getting block..then the tree
2951: * should be locked in the first place.
2952: * We just want the nodeSize wich will NEVER change..so even if the world
2953: * is changing..the nodeSize should remain the same. Which argues why lock
2954: * it in the first place??
2955: */
2956:
2957: (void) BTGetInformation (VTOFCB(vp), kBTreeInfoVersion, &bTreeInfo);
2958:
2959: logBlockSize = bTreeInfo.nodeSize;
2960: }
2961: else
2962: logBlockSize = VTOHFS(vp)->hfs_logBlockSize;
2963:
2964:
2965: DBG_ASSERT(logBlockSize > 0);
2966:
2967: return logBlockSize;
2968: }
2969:
2970: /*
2971: * Map HFS Common errors (negative) to BSD error codes (positive).
2972: * Positive errors (ie BSD errors) are passed through unchanged.
2973: */
2974: short MacToVFSError(OSErr err)
2975: {
2976: if (err >= 0) {
2977: if (err > 0) {
2978: DBG_ERR(("MacToVFSError: passing error #%d unchanged...\n", err));
2979: };
2980: return err;
2981: };
2982:
2983: if (err != 0) {
2984: DBG_ERR(("MacToVFSError: mapping error code %d...\n", err));
2985: };
2986:
2987: switch (err) {
2988: case dirFulErr: /* -33 */
2989: case dskFulErr: /* -34 */
2990: case btNoSpaceAvail: /* -32733 */
2991: case fxOvFlErr: /* -32750 */
2992: return ENOSPC; /* +28 */
2993:
2994: case btBadNode: /* -32731 */
2995: case ioErr: /* -36 */
2996: return EIO; /* +5 */
2997:
2998: case mFulErr: /* -41 */
2999: case memFullErr: /* -108 */
3000: return ENOMEM; /* +12 */
3001:
3002: case tmfoErr: /* -42 */
3003: /* Consider EMFILE (Too many open files, 24)? */
3004: return ENFILE; /* +23 */
3005:
3006: case nsvErr: /* -35 */
3007: case fnfErr: /* -43 */
3008: case dirNFErr: /* -120 */
3009: case fidNotFound: /* -1300 */
3010: return ENOENT; /* +2 */
3011:
3012: case wPrErr: /* -44 */
3013: case vLckdErr: /* -46 */
3014: case fsDSIntErr: /* -127 */
3015: return EROFS; /* +30 */
3016:
3017: case opWrErr: /* -49 */
3018: case fLckdErr: /* -45 */
3019: return EACCES; /* +13 */
3020:
3021: case permErr: /* -54 */
3022: case wrPermErr: /* -61 */
3023: return EPERM; /* +1 */
3024:
3025: case fBsyErr: /* -47 */
3026: return EBUSY; /* +16 */
3027:
3028: case dupFNErr: /* -48 */
3029: case fidExists: /* -1301 */
3030: case cmExists: /* -32718 */
3031: case btExists: /* -32734 */
3032: return EEXIST; /* +17 */
3033:
3034: case rfNumErr: /* -51 */
3035: return EBADF; /* +9 */
3036:
3037: case notAFileErr: /* -1302 */
3038: return EISDIR; /* +21 */
3039:
3040: case cmNotFound: /* -32719 */
3041: case btNotFound: /* -32735 */
3042: return ENOENT; /* 28 */
3043:
3044: case cmNotEmpty: /* -32717 */
3045: return ENOTEMPTY; /* 66 */
3046:
3047: case cmFThdDirErr: /* -32714 */
3048: return EISDIR; /* 21 */
3049:
3050: case fxRangeErr: /* -32751 */
3051: return EIO; /* 5 */
3052:
3053: case bdNamErr: /* -37 */
3054: return ENAMETOOLONG; /* 63 */
3055:
3056: case fnOpnErr: /* -38 */
3057: case eofErr: /* -39 */
3058: case posErr: /* -40 */
3059: case paramErr: /* -50 */
3060: case badMDBErr: /* -60 */
3061: case badMovErr: /* -122 */
3062: case sameFileErr: /* -1306 */
3063: case badFidErr: /* -1307 */
3064: case fileBoundsErr: /* -1309 */
3065: return EINVAL; /* +22 */
3066:
3067: default:
3068: DBG_UTILS(("Unmapped MacOS error: %d\n", err));
3069: return EIO; /* +5 */
3070: }
3071: }
3072:
3073:
3074: /*
3075: * All of our debugging functions
3076: */
3077:
3078: #if HFS_DIAGNOSTIC
3079:
3080: void debug_vn_status (char* introStr, struct vnode *vn)
3081: {
3082: DBG_VOP(("%s:\t",introStr));
3083: if (vn != NULL)
3084: {
3085: if (vn->v_tag != VT_HFS)
3086: {
3087: DBG_VOP(("NON-HFS VNODE Ox%08lX\n", (unsigned long)vn));
3088: }
3089: else if(vn->v_tag==VT_HFS && (vn->v_data==NULL || VTOH((vn))->h_valid != HFS_VNODE_MAGIC))
3090: {
3091: DBG_VOP(("BAD VNODE PRIVATE DATA!!!!\n"));
3092: }
3093: else
3094: {
3095: DBG_VOP(("r: %d & ", vn->v_usecount));
3096: if (lockstatus(&VTOH(vn)->h_lock))
3097: {
3098: DBG_VOP_CONT(("is L\n"));
3099: }
3100: else
3101: {
3102: DBG_VOP_CONT(("is U\n"));
3103: }
3104: }
3105: }
3106: else
3107: {
3108: DBG_VOP(("vnode is NULL\n"));
3109: };
3110: }
3111:
3112: void debug_vn_print (char* introStr, struct vnode *vn)
3113: {
3114: // DBG_FUNC_NAME("DBG_VN_PRINT");
3115: DBG_ASSERT (vn != NULL);
3116: DBG_VFS(("%s: ",introStr));
3117: DBG_VFS_CONT(("vnode: 0x%x is a ", (uint)vn));
3118: switch (vn->v_tag)
3119: {
3120: case VT_UFS:
3121: DBG_VFS_CONT(("%s","UFS"));
3122: break;
3123: case VT_HFS:
3124: DBG_VFS_CONT(("%s","HFS"));
3125: break;
3126: default:
3127: DBG_VFS_CONT(("%s","UNKNOWN"));
3128: break;
3129: }
3130:
3131: DBG_VFS_CONT((" vnode\n"));
3132: if (vn->v_tag==VT_HFS)
3133: {
3134: if (vn->v_data==NULL)
3135: {
3136: DBG_VFS(("BAD VNODE PRIVATE DATA!!!!\n"));
3137: }
3138: else
3139: {
3140: DBG_VFS((" Name: %s Id: %ld ",H_NAME(VTOH(vn)), H_FILEID(VTOH(vn))));
3141: }
3142: }
3143: else
3144: DBG_VFS((" "));
3145:
3146: DBG_VFS_CONT(("Refcount: %d\n", vn->v_usecount));
3147: if (VOP_ISLOCKED(vn))
3148: {
3149: DBG_VFS((" The vnode is locked\n"));
3150: }
3151: else
3152: {
3153: DBG_VFS((" The vnode is not locked\n"));
3154: }
3155: }
3156:
3157: void debug_rename_test_locks (char* introStr,
3158: struct vnode *fvp,
3159: struct vnode *fdvp,
3160: struct vnode *tvp,
3161: struct vnode *tdvp,
3162: int fstatus,
3163: int fdstatus,
3164: int tstatus,
3165: int tdstatus
3166: )
3167: {
3168: DBG_VOP(("\t%s: ", introStr));
3169: if (fvp) {if(lockstatus(&VTOH(fvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3170: if (fdvp) {if(lockstatus(&VTOH(fdvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3171: if (tvp) {if(lockstatus(&VTOH(tvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3172: if (tdvp) {if(lockstatus(&VTOH(tdvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3173: DBG_VFS_CONT(("\n"));
3174:
3175: if (fvp) {
3176: if (lockstatus(&VTOH(fvp)->h_lock)) {
3177: if (fstatus==VOPDBG_UNLOCKED) {
3178: DBG_VOP(("\tfvp should be NOT LOCKED and it is\n"));
3179: }
3180: } else if (fstatus == VOPDBG_LOCKED) {
3181: DBG_VOP(("\tfvp should be LOCKED and it isnt\n"));
3182: }
3183: }
3184:
3185: if (fdvp) {
3186: if (lockstatus(&VTOH(fdvp)->h_lock)) {
3187: if (fdstatus==VOPDBG_UNLOCKED) {
3188: DBG_VOP(("\tfdvp should be NOT LOCKED and it is\n"));
3189: }
3190: } else if (fdstatus == VOPDBG_LOCKED) {
3191: DBG_VOP(("\tfdvp should be LOCKED and it isnt\n"));
3192: }
3193: }
3194:
3195: if (tvp) {
3196: if (lockstatus(&VTOH(tvp)->h_lock)) {
3197: if (tstatus==VOPDBG_UNLOCKED) {
3198: DBG_VOP(("\ttvp should be NOT LOCKED and it is\n"));
3199: }
3200: } else if (tstatus == VOPDBG_LOCKED) {
3201: DBG_VOP(("\ttvp should be LOCKED and it isnt\n"));
3202: }
3203: }
3204:
3205: if (tdvp) {
3206: if (lockstatus(&VTOH(tdvp)->h_lock)) {
3207: if (tdstatus==VOPDBG_UNLOCKED) {
3208: DBG_VOP(("\ttdvp should be NOT LOCKED and it is\n"));
3209: }
3210: } else if (tdstatus == VOPDBG_LOCKED) {
3211: DBG_VOP(("\ttdvp should be LOCKED and it isnt\n"));
3212:
3213: }
3214: }
3215:
3216: }
3217: #endif /* HFS_DIAGNOSTIC */
3218:
3219:
3220: #if HFS_DIAGNOSTIC
3221: void debug_check_buffersizes(struct vnode *vp, struct hfsnode *hp, struct buf *bp) {
3222: DBG_ASSERT(bp->b_validoff == 0);
3223: DBG_ASSERT(bp->b_dirtyoff == 0);
3224: if (bp->b_lblkno < hp->h_uniformblocksizestart) {
3225: DBG_ASSERT((bp->b_bcount == MAXLOGBLOCKSIZE) ||
3226: (bp->b_bcount == LogicalBlockSize(hp, bp->b_lblkno)) ||
3227: ((bp->b_bcount % 512 == 0) &&
3228: (bp->b_validend > 0) &&
3229: (bp->b_dirtyend >= 0) && /* Could be partial block due to file growth */
3230: (bp->b_bcount < LogicalBlockSize(hp, bp->b_lblkno))));
3231: } else {
3232: DBG_ASSERT((bp->b_bcount == HTOHFS(hp)->hfs_logBlockSize) ||
3233: ((bp->b_bcount % 512 == 0) &&
3234: (bp->b_validend > 0) &&
3235: (bp->b_dirtyend > 0) &&
3236: (bp->b_bcount < HTOHFS(hp)->hfs_logBlockSize)));
3237: };
3238:
3239: if (bp->b_validend == 0) {
3240: DBG_ASSERT(bp->b_dirtyend == 0);
3241: } else {
3242: DBG_ASSERT(bp->b_validend == bp->b_bcount);
3243: DBG_ASSERT(bp->b_dirtyend <= bp->b_bcount);
3244: };
3245:
3246: if ((bp->b_lblkno == 0x21) || (bp->b_lblkno == 0x22)) DBG_ASSERT((hp->h_uniformblocksizestart > 0x21) || (bp->b_bcount != MAXLOGBLOCKSIZE));
3247: }
3248:
3249:
3250: void debug_check_blocksizes(struct vnode *vp) {
3251: struct hfsnode *hp = VTOH(vp);
3252: struct buf *bp;
3253:
3254: if (vp->v_flag & VSYSTEM) return;
3255:
3256: for (bp = vp->v_cleanblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) {
3257: debug_check_buffersizes(vp, hp, bp);
3258: };
3259:
3260: for (bp = vp->v_dirtyblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) {
3261: debug_check_buffersizes(vp, hp, bp);
3262: };
3263: }
3264:
3265: extern void hfs_vhash_dbg(struct hfsnode *hp);
3266:
3267: /* Checks the valicity of a hfs vnode */
3268: void debug_check_vnode(struct vnode *vp, int stage) {
3269: struct hfsnode *hp;
3270: u_long size;
3271: int i;
3272:
3273: /* vcb stuff */
3274: if (VTOHFS(vp)->hfs_mount_flags & kHFSBootVolumeInconsistentMask)
3275: DEBUG_BREAK_MSG(("Volume is damaged!"));
3276:
3277: /* vnode stuff */
3278: if (vp==NULL)
3279: DEBUG_BREAK_MSG(("Null vnode"));
3280: if (vp->v_tag != VT_HFS)
3281: DEBUG_BREAK_MSG(("Not a HFS vnode, it is a %d", vp->v_tag));
3282: if (vp->v_data==NULL)
3283: DEBUG_BREAK_MSG(("v_data is NULL"));
3284:
3285: /* hfsnode stuff */
3286: hp = VTOH(vp);
3287: if (hp->h_valid != HFS_VNODE_MAGIC)
3288: DEBUG_BREAK_MSG(("Bad Formed HFS node"));
3289: if (hp->h_vp==NULL || hp->h_vp!=vp)
3290: DEBUG_BREAK_MSG(("Bad hfsnode vnode pte"));
3291: if (hp->h_meta == NULL)
3292: DEBUG_BREAK_MSG(("Bad hfsnode meta ptr"));
3293: switch (H_FORKTYPE(hp)) {
3294: case kDataFork:
3295: case kRsrcFork:
3296: if ((hp->h_meta->h_siblinghead.cqh_first == NULL) || (hp->h_meta->h_siblinghead.cqh_last == NULL))
3297: DEBUG_BREAK_MSG(("Null sibling header"));
3298: if ((hp->h_sibling.cqe_next==NULL) || (hp->h_sibling.cqe_prev==NULL))
3299: DEBUG_BREAK_MSG(("Null sibling list"));
3300: if (hp->h_meta->h_usecount<1 || hp->h_meta->h_usecount>2)
3301: DEBUG_BREAK_MSG(("Bad sibling usecount"));
3302: break;
3303: case kDirectory:
3304: case kSysFile:
3305: if ((hp->h_meta->h_siblinghead.cqh_first != NULL) || (hp->h_meta->h_siblinghead.cqh_last != NULL))
3306: DEBUG_BREAK_MSG(("Non Null sibling header"));
3307: if ((hp->h_sibling.cqe_next!=NULL) || (hp->h_sibling.cqe_prev!=NULL))
3308: DEBUG_BREAK_MSG(("Null sibling list"));
3309: if (hp->h_meta->h_usecount!=1)
3310: DEBUG_BREAK_MSG(("Bad usecount"));
3311:
3312: break;
3313: default:
3314: DEBUG_BREAK_MSG(("Bad hfsnode fork type"));
3315: }
3316:
3317: /* hfsmeta stuff */
3318: if (hp->h_meta->h_devvp == NULL)
3319: DEBUG_BREAK_MSG(("Bad hfsnode dev vnode"));
3320: if (H_DEV(hp) == 0)
3321: DEBUG_BREAK_MSG(("Bad dev id"));
3322: if (H_FILEID(hp) == 0)
3323: DEBUG_BREAK_MSG(("Bad file id"));
3324:
3325: if (((hp->h_meta->h_metaflags & IN_DATANODE)==0) && (H_DIRID(hp) == 0) && (H_FILEID(hp) != 1))
3326: DEBUG_BREAK_MSG(("Bad dir id"));
3327:
3328: if (hp->h_meta->h_namePtr == NULL && hp->h_meta->h_namelen!=0)
3329: DEBUG_BREAK_MSG(("hfs meta h_namelen is not 0"));
3330: if (hp->h_meta->h_namePtr != NULL && strlen(hp->h_meta->h_namePtr) != hp->h_meta->h_namelen)
3331: DEBUG_BREAK_MSG(("Bad hfs meta h_namelen"));
3332:
3333: /* Check the hash */
3334: hfs_vhash_dbg(hp);
3335:
3336: /* Check to see if we want to compare with the disk */
3337: if (stage > 200) {
3338: int retval;
3339: hfsCatalogInfo catInfo;
3340:
3341: if (hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, current_proc()))
3342: return;
3343:
3344: catInfo.hint = 0;
3345: if (hfsLookup(VTOVCB(vp), H_DIRID(hp), hp->h_meta->h_namePtr, hp->h_meta->h_namelen, &catInfo))
3346: DEBUG_BREAK_MSG(("Could not find hfsnode Catalog record"));
3347:
3348: (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, current_proc());
3349:
3350: if (H_FILEID(hp) != catInfo.nodeData.cnd_nodeID)
3351: DEBUG_BREAK_MSG(("hfsnode catalog node id mismatch"));
3352: if (H_DIRID(hp) != catInfo.spec.parID)
3353: DEBUG_BREAK_MSG(("hfsnode catalog dir id mismatch"));
3354: if (strcmp(hp->h_meta->h_namePtr, catInfo.spec.name) != 0)
3355: DEBUG_BREAK_MSG(("hfsnode catalog name mismatch"));
3356: /* Check dates too??? */
3357:
3358:
3359:
3360: }
3361:
3362: for(i = 0, size = 0; i < kHFSPlusExtentDensity; i++)
3363: {
3364: size += hp->fcbExtents[i].blockCount;
3365: }
3366: if (size*VTOVCB(vp)->blockSize < hp->fcbPLen)
3367: DEBUG_BREAK_MSG(("fcbPLen too large"));
3368: if (hp->fcbEOF > hp->fcbPLen)
3369: DEBUG_BREAK_MSG(("fcbPLen is smaller than fcbEOF"));
3370: if (hp->fcbExtents[kHFSPlusExtentDensity-1].blockCount == 0) {
3371: if (size*VTOVCB(vp)->blockSize != hp->fcbPLen)
3372: DEBUG_BREAK_MSG(("fcbPLen does not match extents"));
3373: } else {
3374: if ( hp->fcbPLen < size*VTOVCB(vp)->blockSize)
3375: DEBUG_BREAK_MSG(("fcbPLen is smaller than extents"));
3376: }
3377: for(i = 0; i < kHFSPlusExtentDensity; i++)
3378: {
3379: if (hp->fcbExtents[i].blockCount == 0 || hp->fcbExtents[i].startBlock == 0)
3380: break;
3381: }
3382: if ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && i > kHFSExtentDensity)
3383: DEBUG_BREAK_MSG(("Illegal value in extents for ordinary HFS"));
3384: if (i > kHFSPlusExtentDensity) {
3385: for(; i < kHFSPlusExtentDensity; i++)
3386: {
3387: if (hp->fcbExtents[i].blockCount != 0 || hp->fcbExtents[i].startBlock != 0)
3388: DEBUG_BREAK_MSG(("Illegal value in extents"));
3389: }
3390: }
3391:
3392: /* BTree stuff */
3393: if (vp->v_flag & VSYSTEM) {
3394: BTreeInfoRec info;
3395:
3396: BTGetInformation(hp, 0, &info);
3397: if (hp->fcbBTCBPtr == NULL)
3398: DEBUG_BREAK_MSG(("Null fcbBTCBPtr"));
3399: if (H_HINT(hp) == 0)
3400: DEBUG_BREAK_MSG(("hint is 0"));
3401: if (H_HINT(hp) > info.numNodes)
3402: DEBUG_BREAK_MSG(("hint > numNodes"));
3403: }
3404:
3405: }
3406:
3407: #endif /* HFS_DIAGNOSTIC */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.