2 * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
22 /* @(#)hfs_vfsutils.c 4.0
24 * (c) 1997-2000 Apple Computer, Inc. All Rights Reserved
26 * hfs_vfsutils.c -- Routines that go between the HFS layer and the VFS.
28 * Change History (most recent first):
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
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()
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>
120 #include <sys/unistd.h>
124 #include "hfs_mount.h"
125 #include "hfs_endian.h"
127 #include "hfscommon/headers/FileMgrInternal.h"
128 #include "hfscommon/headers/BTreesInternal.h"
129 #include "hfscommon/headers/HFSUnicodeWrappers.h"
131 #define SUPPORTS_MAC_ALIASES 0
132 #define kMaxSecsForFsync 5
134 #define BYPASSBLOCKINGOPTIMIZATION 0
136 #define kMaxLockedMetaBuffers 32 /* number of locked buffer caches to hold for meta data */
138 extern int (**hfs_vnodeop_p
)(void *);
139 extern int (**hfs_specop_p
)(void *);
140 extern int (**hfs_fifoop_p
)(void *);
141 extern int count_lock_queue
__P((void));
142 extern uid_t console_user
;
144 OSErr
ValidMasterDirectoryBlock( HFSMasterDirectoryBlock
*mdb
);
145 UInt16
DivUp( UInt32 byteRun
, UInt32 blockSize
);
147 /* Externs from vhash */
148 extern void hfs_vhashins_sibling(dev_t dev
, UInt32 nodeID
, struct hfsnode
*hp
, struct hfsfilemeta
**fm
);
149 extern void hfs_vhashins(dev_t dev
, UInt32 nodeID
,struct hfsnode
*hp
);
150 extern struct vnode
*hfs_vhashget(dev_t dev
, UInt32 nodeID
, UInt8 forkType
);
152 extern int hfs_vinit( struct mount
*mntp
, int (**specops
)(void *), int (**fifoops
)(), struct vnode
**vpp
);
154 extern UInt16
CountRootFiles(ExtendedVCB
*vcb
);
155 extern OSErr
GetVolumeNameFromCatalog(ExtendedVCB
*vcb
);
157 static int InitMetaFileVNode(struct vnode
*vp
, off_t eof
, u_long clumpSize
, const HFSPlusExtentRecord extents
,
158 HFSCatalogNodeID fileID
, void * keyCompareProc
);
160 static void ReleaseMetaFileVNode(struct vnode
*vp
);
162 static void RemovedMetaDataDirectory(ExtendedVCB
*vcb
);
164 void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
);
165 void CopyCatalogToFCB(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
);
166 void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
);
167 u_int32_t
GetLogicalBlockSize(struct vnode
*vp
);
169 /* BTree accessor routines */
170 extern OSStatus
GetBTreeBlock(FileReference vp
, UInt32 blockNum
, GetBlockOptions options
, BlockDescriptor
*block
);
171 extern OSStatus
SetBTreeBlockSize(FileReference vp
, ByteCount blockSize
, ItemCount minBlockCount
);
172 extern OSStatus
ExtendBTreeFile(FileReference vp
, FSSize minEOF
, FSSize maxEOF
);
173 extern OSStatus
ReleaseBTreeBlock(FileReference vp
, BlockDescPtr blockPtr
, ReleaseBlockOptions options
);
175 //*******************************************************************************
176 // Note: Finder information in the HFS/HFS+ metadata are considered opaque and
177 // hence are not in the right byte order on little endian machines. It is
178 // the responsibility of the finder and other clients to swap the data.
179 //*******************************************************************************
181 //*******************************************************************************
182 // Routine: hfs_MountHFSVolume
185 //*******************************************************************************
187 OSErr
hfs_MountHFSVolume(struct hfsmount
*hfsmp
, HFSMasterDirectoryBlock
*mdb
,
188 u_long sectors
, struct proc
*p
)
190 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
191 struct vnode
*tmpvnode
;
193 HFSPlusExtentRecord extents
;
195 DBG_FUNC_NAME("hfs_MountHFSVolume");
196 DBG_PRINT_FUNC_NAME();
198 if (hfsmp
== nil
|| mdb
== nil
) /* exit if bad paramater */
201 err
= ValidMasterDirectoryBlock( mdb
); /* make sure this is an HFS disk */
203 return MacToVFSError(err
);
205 /* don't mount a writeable volume if its dirty, it must be cleaned by fsck_hfs */
206 if ((hfsmp
->hfs_fs_ronly
== 0) && ((SWAP_BE16 (mdb
->drAtrb
) & kHFSVolumeUnmountedMask
) == 0))
210 * The MDB seems OK: transfer info from it into VCB
211 * Note - the VCB starts out clear (all zeros)
214 vcb
->vcbVRefNum
= MAKE_VREFNUM(hfsmp
->hfs_raw_dev
);
216 vcb
->vcbSigWord
= SWAP_BE16 (mdb
->drSigWord
);
217 vcb
->vcbCrDate
= LocalToUTC (SWAP_BE32 (mdb
->drCrDate
));
218 vcb
->vcbLsMod
= LocalToUTC (SWAP_BE32 (mdb
->drLsMod
));
219 vcb
->vcbAtrb
= SWAP_BE16 (mdb
->drAtrb
);
220 vcb
->vcbNmFls
= SWAP_BE16 (mdb
->drNmFls
);
221 vcb
->vcbVBMSt
= SWAP_BE16 (mdb
->drVBMSt
);
222 vcb
->nextAllocation
= SWAP_BE16 (mdb
->drAllocPtr
);
223 vcb
->totalBlocks
= SWAP_BE16 (mdb
->drNmAlBlks
);
224 vcb
->blockSize
= SWAP_BE32 (mdb
->drAlBlkSiz
);
225 vcb
->vcbClpSiz
= SWAP_BE32 (mdb
->drClpSiz
);
226 vcb
->vcbAlBlSt
= SWAP_BE16 (mdb
->drAlBlSt
);
227 vcb
->vcbNxtCNID
= SWAP_BE32 (mdb
->drNxtCNID
);
228 vcb
->freeBlocks
= SWAP_BE16 (mdb
->drFreeBks
);
229 vcb
->vcbVolBkUp
= LocalToUTC (SWAP_BE32 (mdb
->drVolBkUp
));
230 vcb
->vcbVSeqNum
= SWAP_BE16 (mdb
->drVSeqNum
);
231 vcb
->vcbWrCnt
= SWAP_BE32 (mdb
->drWrCnt
);
232 vcb
->vcbNmRtDirs
= SWAP_BE16 (mdb
->drNmRtDirs
);
233 vcb
->vcbFilCnt
= SWAP_BE32 (mdb
->drFilCnt
);
234 vcb
->vcbDirCnt
= SWAP_BE32 (mdb
->drDirCnt
);
235 bcopy(mdb
->drFndrInfo
, vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
236 vcb
->nextAllocation
= SWAP_BE16 ( mdb
->drAllocPtr
); /* Duplicate?!?!?! */
237 vcb
->encodingsBitmap
= 0;
238 vcb
->vcbWrCnt
++; /* Compensate for write of MDB on last flush */
240 * Copy the drVN field, which is a Pascal String to the vcb, which is a cstring
243 /* convert hfs encoded name into UTF-8 string */
244 err
= hfs_to_utf8(vcb
, mdb
->drVN
, NAME_MAX
, &utf8chars
, vcb
->vcbVN
);
246 * When an HFS name cannot be encoded with the current
247 * volume encoding we use MacRoman as a fallback.
249 if (err
|| (utf8chars
== 0))
250 (void) mac_roman_to_utf8(mdb
->drVN
, NAME_MAX
, &utf8chars
, vcb
->vcbVN
);
252 vcb
->altIDSector
= sectors
- 2;
254 // Initialize our dirID/nodePtr cache associated with this volume.
255 err
= InitMRUCache( sizeof(UInt32
), kDefaultNumMRUCacheBlocks
, &(vcb
->hintCachePtr
) );
256 ReturnIfError( err
);
258 hfsmp
->hfs_logBlockSize
= BestBlockSizeFit(vcb
->blockSize
, MAXBSIZE
, hfsmp
->hfs_phys_block_size
);
260 // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
264 * Set up Extents B-tree vnode...
266 err
= GetInitializedVNode(hfsmp
, &tmpvnode
, 0);
267 if (err
) goto MtVolErr
;
268 /* HFSToHFSPlusExtents(mdb->drXTExtRec, extents); */ /* ASDFADSFSD */
269 extents
[0].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[0].startBlock
);
270 extents
[0].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[0].blockCount
);
271 extents
[1].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[1].startBlock
);
272 extents
[1].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[1].blockCount
);
273 extents
[2].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[2].startBlock
);
274 extents
[2].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[2].blockCount
);
276 err
= InitMetaFileVNode(tmpvnode
, SWAP_BE32 (mdb
->drXTFlSize
), SWAP_BE32 (mdb
->drXTClpSiz
), extents
,
277 kHFSExtentsFileID
, CompareExtentKeys
);
278 if (err
) goto MtVolErr
;
281 * Set up Catalog B-tree vnode...
283 err
= GetInitializedVNode(hfsmp
, &tmpvnode
, 0);
284 if (err
) goto MtVolErr
;
285 /* HFSToHFSPlusExtents(mdb->drCTExtRec, extents); */
286 extents
[0].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[0].startBlock
);
287 extents
[0].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[0].blockCount
);
288 extents
[1].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[1].startBlock
);
289 extents
[1].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[1].blockCount
);
290 extents
[2].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[2].startBlock
);
291 extents
[2].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[2].blockCount
);
293 err
= InitMetaFileVNode(tmpvnode
, SWAP_BE32 (mdb
->drCTFlSize
), SWAP_BE32 (mdb
->drCTClpSiz
), extents
,
294 kHFSCatalogFileID
, CompareCatalogKeys
);
295 if (err
) goto MtVolErr
;
297 /* mark the volume dirty (clear clean unmount bit) */
298 vcb
->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
300 /* Remove any MetaDataDirectory from hfs disks */
301 if (hfsmp
->hfs_fs_ronly
== 0)
302 RemovedMetaDataDirectory(vcb
);
305 * all done with b-trees so we can unlock now...
307 VOP_UNLOCK(vcb
->catalogRefNum
, 0, p
);
308 VOP_UNLOCK(vcb
->extentsRefNum
, 0, p
);
314 if ( !(vcb
->vcbAtrb
& kHFSVolumeHardwareLockMask
) ) // if the disk is not write protected
316 MarkVCBDirty( vcb
); // mark VCB dirty so it will be written
321 //-- Release any resources allocated so far before exiting with an error:
323 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
324 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
330 //*******************************************************************************
331 // Routine: hfs_MountHFSPlusVolume
334 //*******************************************************************************
336 OSErr
hfs_MountHFSPlusVolume(struct hfsmount
*hfsmp
, HFSPlusVolumeHeader
*vhp
,
337 u_long embBlkOffset
, u_long sectors
, struct proc
*p
)
339 register ExtendedVCB
*vcb
;
340 HFSPlusForkData
*fdp
;
341 struct vnode
*tmpvnode
;
344 if (hfsmp
== nil
|| vhp
== nil
) /* exit if bad paramater */
347 DBG_VFS(("hfs_MountHFSPlusVolume: signature=0x%x, version=%d, blockSize=%ld\n",
348 SWAP_BE16 (vhp
->signature
),
349 SWAP_BE16 (vhp
->version
),
350 SWAP_BE32 (vhp
->blockSize
)));
352 retval
= ValidVolumeHeader(vhp
); /* make sure this is an HFS Plus disk */
354 return MacToVFSError(retval
);
356 /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */
357 if (hfsmp
->hfs_fs_ronly
== 0 && (SWAP_BE32 (vhp
->attributes
) & kHFSVolumeUnmountedMask
) == 0)
360 * The VolumeHeader seems OK: transfer info from it into VCB
361 * Note - the VCB starts out clear (all zeros)
363 vcb
= HFSTOVCB(hfsmp
);
365 //DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0);
366 vcb
->vcbVRefNum
= MAKE_VREFNUM(hfsmp
->hfs_raw_dev
);
367 vcb
->vcbSigWord
= SWAP_BE16 (vhp
->signature
);
368 vcb
->vcbLsMod
= SWAP_BE32 (vhp
->modifyDate
);
369 vcb
->vcbAtrb
= (UInt16
) SWAP_BE32 (vhp
->attributes
); // VCB only uses lower 16 bits
370 vcb
->vcbClpSiz
= SWAP_BE32 (vhp
->rsrcClumpSize
);
371 vcb
->vcbNxtCNID
= SWAP_BE32 (vhp
->nextCatalogID
);
372 vcb
->vcbVolBkUp
= SWAP_BE32 (vhp
->backupDate
);
373 vcb
->vcbWrCnt
= SWAP_BE32 (vhp
->writeCount
);
374 vcb
->vcbFilCnt
= SWAP_BE32 (vhp
->fileCount
);
375 vcb
->vcbDirCnt
= SWAP_BE32 (vhp
->folderCount
);
377 /* copy 32 bytes of Finder info */
378 bcopy(vhp
->finderInfo
, vcb
->vcbFndrInfo
, sizeof(vhp
->finderInfo
));
380 vcb
->vcbAlBlSt
= 0; /* hfs+ allocation blocks start at first block of volume */
381 vcb
->vcbWrCnt
++; /* compensate for write of Volume Header on last flush */
385 /* Now fill in the Extended VCB info */
386 vcb
->nextAllocation
= SWAP_BE32 (vhp
->nextAllocation
);
387 vcb
->totalBlocks
= SWAP_BE32 (vhp
->totalBlocks
);
388 vcb
->freeBlocks
= SWAP_BE32 (vhp
->freeBlocks
);
389 vcb
->blockSize
= SWAP_BE32 (vhp
->blockSize
);
390 vcb
->checkedDate
= SWAP_BE32 (vhp
->checkedDate
);
391 vcb
->encodingsBitmap
= SWAP_BE64 (vhp
->encodingsBitmap
);
393 vcb
->hfsPlusIOPosOffset
= embBlkOffset
* 512;
395 vcb
->altIDSector
= embBlkOffset
+ sectors
- 2;
397 vcb
->localCreateDate
= SWAP_BE32 (vhp
->createDate
); /* in local time, not GMT! */
399 /* Update the logical block size in the mount struct (currently set up from the wrapper MDB)
400 using the new blocksize value: */
401 hfsmp
->hfs_logBlockSize
= BestBlockSizeFit(vcb
->blockSize
, MAXBSIZE
, hfsmp
->hfs_phys_block_size
);
403 // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
404 // vcb->vcbAtrb |= kVolumeHardwareLockMask; // XXX this line for debugging only!!!!
406 // Initialize our dirID/nodePtr cache associated with this volume.
407 retval
= InitMRUCache( sizeof(UInt32
), kDefaultNumMRUCacheBlocks
, &(vcb
->hintCachePtr
) );
408 if (retval
!= noErr
) goto ErrorExit
;
411 * Set up Extents B-tree vnode...
413 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
, 0);
414 if (retval
) goto ErrorExit
;
415 fdp
= &vhp
->extentsFile
;
416 SWAP_HFS_PLUS_FORK_DATA (fdp
);
417 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
418 kHFSExtentsFileID
, CompareExtentKeysPlus
);
419 SWAP_HFS_PLUS_FORK_DATA (fdp
);
420 if (retval
) goto ErrorExit
;
423 * Set up Catalog B-tree vnode...
425 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
, 0);
426 if (retval
) goto ErrorExit
;
427 fdp
= &vhp
->catalogFile
;
428 SWAP_HFS_PLUS_FORK_DATA (fdp
);
429 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
430 kHFSCatalogFileID
, CompareExtendedCatalogKeys
);
431 SWAP_HFS_PLUS_FORK_DATA (fdp
);
432 if (retval
) goto ErrorExit
;
435 * Set up Allocation file vnode...
437 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
, 0);
438 if (retval
) goto ErrorExit
;
439 fdp
= &vhp
->allocationFile
;
440 SWAP_HFS_PLUS_FORK_DATA (fdp
);
441 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
442 kHFSAllocationFileID
, NULL
);
443 SWAP_HFS_PLUS_FORK_DATA (fdp
);
444 if (retval
) goto ErrorExit
;
447 * Now that Catalog file is open get the volume name from the catalog
449 retval
= MacToVFSError( GetVolumeNameFromCatalog(vcb
) );
450 if (retval
!= noErr
) goto ErrorExit
;
452 /* mark the volume dirty (clear clean unmount bit) */
453 vcb
->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
455 /* setup private/hidden directory for unlinked files */
456 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(vcb
);
459 * all done with metadata files so we can unlock now...
461 VOP_UNLOCK(vcb
->allocationsRefNum
, 0, p
);
462 VOP_UNLOCK(vcb
->catalogRefNum
, 0, p
);
463 VOP_UNLOCK(vcb
->extentsRefNum
, 0, p
);
465 if ( !(vcb
->vcbAtrb
& kHFSVolumeHardwareLockMask
) ) // if the disk is not write protected
467 MarkVCBDirty( vcb
); // mark VCB dirty so it will be written
470 DBG_VFS(("hfs_MountHFSPlusVolume: returning (%d)\n", retval
));
477 * A fatal error occured and the volume cannot be mounted
478 * release any resources that we aquired...
481 DBG_VFS(("hfs_MountHFSPlusVolume: fatal error (%d)\n", retval
));
483 InvalidateCatalogCache(vcb
);
485 ReleaseMetaFileVNode(vcb
->allocationsRefNum
);
486 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
487 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
494 * ReleaseMetaFileVNode
498 static void ReleaseMetaFileVNode(struct vnode
*vp
)
502 FCB
*fcb
= VTOFCB(vp
);
504 if (fcb
->fcbBTCBPtr
!= NULL
)
505 (void) BTClosePath(fcb
); /* ignore errors since there is only one path open */
507 /* release the node even if BTClosePath fails */
508 if (VOP_ISLOCKED(vp
))
521 static int InitMetaFileVNode(struct vnode
*vp
, off_t eof
, u_long clumpSize
, const HFSPlusExtentRecord extents
,
522 HFSCatalogNodeID fileID
, void * keyCompareProc
)
528 DBG_ASSERT(vp
!= NULL
);
529 DBG_ASSERT(vp
->v_data
!= NULL
);
536 case kHFSExtentsFileID
:
537 vcb
->extentsRefNum
= vp
;
540 case kHFSCatalogFileID
:
541 vcb
->catalogRefNum
= vp
;
544 case kHFSAllocationFileID
:
545 vcb
->allocationsRefNum
= vp
;
549 panic("InitMetaFileVNode: invalid fileID!");
554 fcb
->fcbClmpSize
= clumpSize
;
555 H_FILEID(VTOH(vp
)) = fileID
;
556 H_DIRID(VTOH(vp
)) = kHFSRootParentID
;
557 H_FORKTYPE(VTOH(vp
)) = kSysFile
;
559 bcopy(extents
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
562 * Lock the hfsnode and insert the hfsnode into the hash queue:
564 hfs_vhashins(H_DEV(VTOH(vp
)), fileID
, VTOH(vp
));
565 vp
->v_flag
|= VSYSTEM
; /* tag our metadata files (used by vflush call) */
567 /* As the vnode is a system vnode we don't need UBC */
568 if(UBCINFOEXISTS(vp
)) {
569 /* So something is wrong if the it exists */
570 panic("ubc exists for system vnode");
573 if (keyCompareProc
!= NULL
) {
574 result
= BTOpenPath(fcb
,
575 (KeyCompareProcPtr
) keyCompareProc
,
580 result
= MacToVFSError(result
);
587 /*************************************************************
589 * Unmounts a hfs volume.
590 * At this point vflush() has been called (to dump all non-metadata files)
592 *************************************************************/
594 short hfsUnmount( register struct hfsmount
*hfsmp
, struct proc
*p
)
596 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
599 (void) DisposeMRUCache(vcb
->hintCachePtr
);
600 InvalidateCatalogCache( vcb
);
601 // XXX PPD: Should dispose of any allocated volume cache here: call DisposeVolumeCacheBlocks( vcb )?
603 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_EXCLUSIVE
, p
);
604 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
, p
);
606 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
607 ReleaseMetaFileVNode(vcb
->allocationsRefNum
);
609 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
610 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
617 * Performs a lookup on the given dirID, name. Returns the catalog info
619 * If len is -1, then it is a null terminated string, pass it along to MacOS as kUndefinedStrLen
622 short hfs_getcatalog (ExtendedVCB
*vcb
, UInt32 parentDirID
, char *name
, short len
, hfsCatalogInfo
*catInfo
)
628 if (len
== -1 ) { /* Convert it to MacOS terms */
630 length
= strlen(name
);
632 length
= kUndefinedStrLen
;
637 result
= GetCatalogNode(vcb
, parentDirID
, name
, length
, catInfo
->hint
, &catInfo
->nodeData
, &catInfo
->hint
);
640 if (catInfo
->nodeData
.cnm_nameptr
) {
641 DBG_ASSERT(strlen(catInfo
->nodeData
.cnm_nameptr
) == catInfo
->nodeData
.cnm_length
);
649 fip
= (struct FInfo
*) &catInfo
->nodeData
.cnd_finderInfo
;
652 * if we encounter an indirect link (hardlink) then auto resolve it...
654 if ((catInfo
->nodeData
.cnd_type
== kCatalogFileNode
) &&
655 (fip
->fdType
== kHardLinkFileType
) &&
656 (fip
->fdCreator
== kHFSPlusCreator
) &&
657 ((catInfo
->nodeData
.cnd_createDate
== vcb
->vcbCrDate
) ||
658 (catInfo
->nodeData
.cnd_createDate
== VCBTOHFS(vcb
)->hfs_metadata_createdate
))) {
662 UInt32 privDir
= VCBTOHFS(vcb
)->hfs_private_metadata_dir
;
664 indlinkno
= catInfo
->nodeData
.cnd_iNodeNum
;
665 MAKE_INODE_NAME(iNodeName
, indlinkno
);
668 * Get nodeData from the data node file.
669 * Flag the node data to NOT copy the name, perserver the original
671 catInfo
->nodeData
.cnm_flags
|= kCatNameNoCopyName
;
672 result
= GetCatalogNode(vcb
, privDir
, iNodeName
, 0, 0, &catInfo
->nodeData
, &catInfo
->hint
);
673 catInfo
->nodeData
.cnm_flags
&= ~kCatNameNoCopyName
; /* Just to keep things like they should be */
675 /* make sure there's at lease 1 reference */
677 if (catInfo
->nodeData
.cnd_linkCount
== 0)
678 catInfo
->nodeData
.cnd_linkCount
= 2;
679 /* keep a copy of iNodeNum to put into h_indnodeno */
680 catInfo
->nodeData
.cnd_iNodeNumCopy
= indlinkno
;
683 /* if we can not resolve the link, allow the link to be
684 * exposed (as an empty file) so it can be deleted
686 if (result
== cmNotFound
)
694 DBG_ERR(("on Lookup, GetCatalogNode returned: %d: dirid: %ld name: %s\n", result
, parentDirID
, name
));
696 return MacToVFSError(result
);
701 short hfsDelete (ExtendedVCB
*vcb
, UInt32 parentDirID
, StringPtr name
, short isfile
, UInt32 catalogHint
)
703 OSErr result
= noErr
;
705 /* XXX have all the file's blocks been flushed/trashed? */
708 * DeleteFile will delete the catalog node and then
709 * free up any disk space used by the file.
712 result
= DeleteFile(vcb
, parentDirID
, name
, catalogHint
);
713 else /* is a directory */
714 result
= DeleteCatalogNode(vcb
, parentDirID
, name
, catalogHint
);
717 DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result
, parentDirID
, name
));
719 return MacToVFSError(result
);
723 short hfsMoveRename (ExtendedVCB
*vcb
, UInt32 oldDirID
, char *oldName
, UInt32 newDirID
, char *newName
, UInt32
*hint
)
725 OSErr result
= noErr
;
727 result
= MoveRenameCatalogNode(vcb
, oldDirID
,oldName
, *hint
, newDirID
, newName
, hint
);
730 DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result
, newDirID
, newName
));
733 return MacToVFSError(result
);
736 /* XXX SER pass back the hint so other people can use it */
739 short hfsCreate(ExtendedVCB
*vcb
, UInt32 dirID
, char *name
, int mode
)
741 OSErr result
= noErr
;
742 HFSCatalogNodeID catalogNodeID
;
746 /* just test for directories, the default is to create a file (like symlinks) */
747 if ((mode
& IFMT
) == IFDIR
)
748 type
= kCatalogFolderNode
;
750 type
= kCatalogFileNode
;
752 result
= CreateCatalogNode (vcb
, dirID
, name
, type
, &catalogNodeID
, &catalogHint
);
754 return MacToVFSError(result
);
758 short hfsCreateFileID (ExtendedVCB
*vcb
, UInt32 parentDirID
, StringPtr name
, UInt32 catalogHint
, UInt32
*fileIDPtr
)
760 return MacToVFSError(CreateFileIDRef(vcb
, parentDirID
, name
, catalogHint
, fileIDPtr
));
764 /********************************************************************************/
766 /* hfs_vget_catinfo - Returns a vnode derived from a hfs catInfo struct */
768 /********************************************************************************/
770 int hfs_vget_catinfo(struct vnode
*parent_vp
, struct hfsCatalogInfo
*catInfo
, u_int32_t forkType
, struct vnode
**target_vp
)
775 *target_vp
= hfs_vhashget(H_DEV(VTOH(parent_vp
)), catInfo
->nodeData
.cnd_nodeID
, forkType
);
777 if (*target_vp
== NULL
) {
778 if (forkType
== kAnyFork
)
779 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
)
780 forkType
= kDirectory
;
782 forkType
= kDataFork
;
784 retval
= hfs_vcreate( VTOVCB(parent_vp
), catInfo
, forkType
, target_vp
);
792 /********************************************************************************/
794 /* hfs_vget_fork - Returns a vnode derived from a sibling */
797 /********************************************************************************/
799 int hfs_vget_sibling(struct vnode
*vp
, u_int16_t forkType
, struct vnode
**vpp
)
801 struct vnode
* target_vp
= NULL
;
805 DBG_ASSERT(vp
!= NULL
);
806 DBG_ASSERT(VTOH(vp
) != NULL
);
807 DBG_ASSERT(VTOH(vp
)->h_meta
!= NULL
);
808 DBG_ASSERT(forkType
==kDataFork
|| forkType
==kRsrcFork
);
810 target_vp
= hfs_vhashget(H_DEV(VTOH(vp
)), H_FILEID(VTOH(vp
)), forkType
);
813 * If not in the hash, then we have to create it
815 if (target_vp
== NULL
) {
816 struct proc
*p
= current_proc();
817 hfsCatalogInfo catInfo
;
819 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
820 catInfo
.hint
= H_HINT(VTOH(vp
));
822 /* lock catalog b-tree */
823 retval
= hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_SHARED
, p
);
824 if (retval
) goto GetCatErr_Exit
;
826 retval
= hfs_getcatalog (VTOVCB(vp
), H_DIRID(VTOH(vp
)), H_NAME(VTOH(vp
)), VTOH(vp
)->h_meta
->h_namelen
, &catInfo
);
828 /* unlock catalog b-tree */
829 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_RELEASE
, p
);
830 if (retval
) goto GetCatErr_Exit
;
832 retval
= hfs_vcreate( VTOVCB(vp
), &catInfo
, forkType
, &target_vp
);
835 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
841 DBG_ASSERT(target_vp
!=NULL
);
843 DBG_ASSERT(target_vp
==NULL
);
851 /************************************************************************/
852 /* hfs_vcreate - Returns a vnode derived from hfs */
854 /* When creating the vnode, care must be made to set the */
855 /* correct fields in the correct order. Calls to malloc() */
856 /* and other subroutines, can cause a context switch, */
857 /* and the fields must be ready for the possibility */
860 /************************************************************************/
862 short hfs_vcreate(ExtendedVCB
*vcb
, hfsCatalogInfo
*catInfo
, UInt8 forkType
, struct vnode
**vpp
)
866 struct hfsmount
*hfsmp
;
867 struct hfsfilemeta
*fm
;
874 DBG_ASSERT(vcb
!= NULL
);
875 DBG_ASSERT(catInfo
!= NULL
);
876 DBG_ASSERT(vpp
!= NULL
);
877 DBG_ASSERT((forkType
== kDirectory
) || (forkType
== kDataFork
) || (forkType
== kRsrcFork
));
878 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) {
879 DBG_ASSERT(forkType
== kDirectory
);
881 DBG_ASSERT(forkType
!= kDirectory
);
885 hfsmp
= VCBTOHFS(vcb
);
886 mp
= HFSTOVFS(hfsmp
);
887 dev
= hfsmp
->hfs_raw_dev
;
889 /* Check if unmount in progress */
890 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
894 DBG_UTILS(("\thfs_vcreate: On '%s' with forktype of %d, nodeType of 0x%08lX\n", catInfo
->nodeData
.cnm_nameptr
, forkType
, (unsigned long)catInfo
->nodeData
.cnd_type
));
896 /* Must malloc() here, since getnewvnode() can sleep */
897 MALLOC_ZONE(hp
, struct hfsnode
*, sizeof(struct hfsnode
), M_HFSNODE
, M_WAITOK
);
898 bzero((caddr_t
)hp
, sizeof(struct hfsnode
));
901 * Set that this node is in the process of being allocated
902 * Set it as soon as possible, so context switches well always hit upon it.
903 * if this is set then wakeup() MUST be called on hp after the flag is cleared
904 * DO NOT exit without clearing and waking up !!!!
906 hp
->h_nodeflags
|= IN_ALLOCATING
; /* Mark this as being allocating */
907 lockinit(&hp
->h_lock
, PINOD
, "hfsnode", 0, 0);
910 /* getnewvnode() does a VREF() on the vnode */
911 /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
912 if ((retval
= getnewvnode(VT_HFS
, mp
, hfs_vnodeop_p
, &vp
))) {
913 wakeup(hp
); /* Shouldnt happen, but just to make sure */
914 FREE_ZONE(hp
, sizeof(struct hfsnode
), M_HFSNODE
);
920 * Set the essentials before locking it down
922 hp
->h_vp
= vp
; /* Make HFSTOV work */
923 vp
->v_data
= hp
; /* Make VTOH work */
924 H_FORKTYPE(hp
) = forkType
;
928 * Lock the hfsnode and insert the hfsnode into the hash queue, also if meta exists
929 * add to sibling list and return the meta address
931 if (SIBLING_FORKTYPE(forkType
))
932 hfs_vhashins_sibling(dev
, catInfo
->nodeData
.cnd_nodeID
, hp
, &fm
);
934 hfs_vhashins(dev
, catInfo
->nodeData
.cnd_nodeID
, hp
);
937 * If needed allocate and init the object meta data:
940 /* Allocate it....remember we can do a context switch here */
941 MALLOC_ZONE(fm
, struct hfsfilemeta
*, sizeof(struct hfsfilemeta
), M_HFSFMETA
, M_WAITOK
);
942 bzero(fm
, sizeof(struct hfsfilemeta
));
946 * NOTICE: XXX Even though we have added the vnode to the hash so it is alive on TWO
947 * accessable lists, we do not assign it until later,
948 * this helps to make sure we do not use a half initiated meta
951 /* Init the sibling list if needed */
952 if (SIBLING_FORKTYPE(forkType
)) {
953 simple_lock_init(&fm
->h_siblinglock
);
954 CIRCLEQ_INIT(&fm
->h_siblinghead
);
955 CIRCLEQ_INSERT_HEAD(&fm
->h_siblinghead
, hp
, h_sibling
);
959 CopyCatalogToObjectMeta(catInfo
, vp
, fm
);
962 * the vnode is finally alive, with the exception of the FCB below,
963 * It is finally locked and ready for its debutante ball
971 * Init the File Control Block.
973 CopyCatalogToFCB(catInfo
, vp
);
976 * Finish vnode initialization.
977 * Setting the v_type 'stamps' the vnode as 'complete', so should be done almost last.
979 * At this point the vnode should be locked and fully allocated. And ready to be used
980 * or accessed. (though having it locked prevents most of this, it
981 * can still be accessed through lists and hashs).
983 vp
->v_type
= IFTOVT(hp
->h_meta
->h_mode
);
984 if ((vp
->v_type
== VREG
)
985 && (UBCINFOMISSING(vp
) || UBCINFORECLAIMED(vp
))) {
990 * Initialize the vnode from the inode, check for aliases, sets the VROOT flag.
991 * Note that the underlying vnode may have changed.
993 if ((retval
= hfs_vinit(mp
, hfs_specop_p
, hfs_fifoop_p
, &vp
))) {
1001 * Finish inode initialization now that aliasing has been resolved.
1003 hp
->h_meta
->h_devvp
= hfsmp
->hfs_devvp
;
1004 VREF(hp
->h_meta
->h_devvp
);
1007 hp
->h_valid
= HFS_VNODE_MAGIC
;
1009 hp
->h_nodeflags
&= ~IN_ALLOCATING
; /* vnode is completely initialized */
1011 /* Wake up anybody waiting for us to finish..see hfs_vhash.c */
1012 wakeup((caddr_t
)hp
);
1016 /* Lets do some testing here */
1017 DBG_ASSERT(hp
->h_meta
);
1018 DBG_ASSERT(VTOH(vp
)==hp
);
1019 DBG_ASSERT(HTOV(hp
)==vp
);
1020 DBG_ASSERT(hp
->h_meta
->h_usecount
>=1 && hp
->h_meta
->h_usecount
<=2);
1021 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) {
1022 DBG_ASSERT(vp
->v_type
== VDIR
);
1023 DBG_ASSERT(H_FORKTYPE(VTOH(vp
)) == kDirectory
);
1025 #endif // HFS_DIAGNOSTIC
1033 void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
)
1035 ExtendedVCB
*vcb
= VTOVCB(vp
);
1036 struct mount
*mp
= VTOVFS(vp
);
1037 Boolean isHFSPlus
, isDirectory
;
1041 DBG_ASSERT (fm
!= NULL
);
1042 DBG_ASSERT (fm
->h_namelen
== 0);
1043 DBG_ASSERT (fm
->h_namePtr
== 0);
1045 DBG_UTILS(("\tCopying to file's meta data: name:%s, nodeid:%ld\n", catalogInfo
->nodeData
.cnm_nameptr
, catalogInfo
->nodeData
.cnd_nodeID
));
1047 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1048 isDirectory
= (catalogInfo
->nodeData
.cnd_type
== kCatalogFolderNode
);
1049 finderFlags
= SWAP_BE16 (((struct FInfo
*)(&catalogInfo
->nodeData
.cnd_finderInfo
))->fdFlags
);
1051 /* Copy over the dirid, and hint */
1052 fm
->h_nodeID
= catalogInfo
->nodeData
.cnd_nodeID
;
1053 fm
->h_dirID
= catalogInfo
->nodeData
.cnm_parID
;
1054 fm
->h_hint
= catalogInfo
->hint
;
1056 /* Copy over the name */
1057 hfs_name_CatToMeta(&catalogInfo
->nodeData
, fm
);
1060 /* get dates in BSD format */
1061 fm
->h_mtime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1062 fm
->h_crtime
= to_bsd_time(catalogInfo
->nodeData
.cnd_createDate
);
1063 fm
->h_butime
= to_bsd_time(catalogInfo
->nodeData
.cnd_backupDate
);
1065 fm
->h_atime
= to_bsd_time(catalogInfo
->nodeData
.cnd_accessDate
);
1066 fm
->h_ctime
= to_bsd_time(catalogInfo
->nodeData
.cnd_attributeModDate
);
1069 fm
->h_atime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1070 fm
->h_ctime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1074 if (isHFSPlus
&& (catalogInfo
->nodeData
.cnd_mode
& IFMT
)) {
1075 fm
->h_uid
= catalogInfo
->nodeData
.cnd_ownerID
;
1076 fm
->h_gid
= catalogInfo
->nodeData
.cnd_groupID
;
1077 fm
->h_pflags
= catalogInfo
->nodeData
.cnd_ownerFlags
|
1078 (catalogInfo
->nodeData
.cnd_adminFlags
<< 16);
1079 fm
->h_mode
= (mode_t
)catalogInfo
->nodeData
.cnd_mode
;
1081 if (fm
->h_uid
== 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1082 fm
->h_uid
= UNKNOWNUID
;
1083 fm
->h_metaflags
|= IN_CHANGE
;
1084 vcb
->vcbFlags
|= kHFS_DamagedVolume
; /* Trigger fsck on next mount */
1086 if (fm
->h_gid
== 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1087 fm
->h_gid
= UNKNOWNGID
;
1088 fm
->h_metaflags
|= IN_CHANGE
;
1089 vcb
->vcbFlags
|= kHFS_DamagedVolume
; /* Trigger fsck on next mount */
1092 filetype
= fm
->h_mode
& IFMT
;
1093 if (filetype
== IFCHR
|| filetype
== IFBLK
)
1094 fm
->h_rdev
= catalogInfo
->nodeData
.cnd_rawDevice
;
1098 if (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
&&
1099 catalogInfo
->nodeData
.cnd_linkCount
> 0) {
1100 fm
->h_nlink
= catalogInfo
->nodeData
.cnd_linkCount
;
1101 fm
->h_indnodeno
= catalogInfo
->nodeData
.cnd_iNodeNumCopy
;
1102 fm
->h_metaflags
|= IN_DATANODE
;
1107 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1109 * Override the permissions as determined by the mount auguments
1110 * in ALMOST the same way unset permissions are treated but keep
1111 * track of whether or not the file or folder is hfs locked
1112 * by leaving the h_pflags field unchanged from what was unpacked
1113 * out of the catalog.
1115 fm
->h_metaflags
|= IN_UNSETACCESS
;
1116 fm
->h_uid
= VTOHFS(vp
)->hfs_uid
;
1117 fm
->h_gid
= VTOHFS(vp
)->hfs_gid
;
1118 #if OVERRIDE_UNKNOWN_PERMISSIONS
1119 /* Default access is full read/write/execute: */
1120 /* XXX won't this smash IFCHR, IFBLK and IFLNK (for no-follow lookups)? */
1121 fm
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
1124 /* ... but no more than that permitted by the mount point's: */
1126 fm
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
1129 fm
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
1133 fm
->h_mode
|= IFDIR
;
1134 else if (SUPPORTS_MAC_ALIASES
&& (finderFlags
& kIsAlias
)) /* aliases will be symlinks in the future */
1135 fm
->h_mode
|= IFLNK
;
1137 fm
->h_mode
|= IFREG
;
1142 * Set the permissions as determined by the mount auguments
1143 * but keep in account if the file or folder is hfs locked
1145 fm
->h_metaflags
|= IN_UNSETACCESS
;
1146 fm
->h_uid
= VTOHFS(vp
)->hfs_uid
;
1147 fm
->h_gid
= VTOHFS(vp
)->hfs_gid
;
1148 fm
->h_pflags
= 0; /* No valid pflags on disk (IMMUTABLE is synced from lock flag later) */
1149 fm
->h_rdev
= 0; /* No valid rdev on disk */
1150 /* Default access is full read/write/execute: */
1151 fm
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
1153 /* ... but no more than that permitted by the mount point's: */
1155 fm
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
1158 fm
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
1162 fm
->h_mode
|= IFDIR
;
1163 else if (SUPPORTS_MAC_ALIASES
&& (finderFlags
& kIsAlias
)) /* aliases will be symlinks in the future */
1164 fm
->h_mode
|= IFLNK
;
1166 fm
->h_mode
|= IFREG
;
1169 /* Make sure that there is no nodeType/mode mismatch */
1170 if (isDirectory
&& ((fm
->h_mode
& IFMT
) != IFDIR
)) {
1171 fm
->h_mode
&= ~IFMT
; /* Clear the bad bits */
1172 fm
->h_mode
|= IFDIR
; /* Set the proper one */
1175 /* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */
1177 if (catalogInfo
->nodeData
.cnd_flags
& kHFSFileLockedMask
) {
1178 /* The file's supposed to be locked:
1179 Make sure at least one of the IMMUTABLE bits is set: */
1180 if ((fm
->h_pflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
)) == 0) {
1181 fm
->h_pflags
|= UF_IMMUTABLE
; /* Set the user-changable IMMUTABLE bit */
1184 /* The file's supposed to be unlocked: */
1185 fm
->h_pflags
&= ~(SF_IMMUTABLE
| UF_IMMUTABLE
);
1190 fm
->h_nlink
= 2 + catalogInfo
->nodeData
.cnd_valence
;
1191 fm
->h_size
= (2 * sizeof(hfsdotentry
)) +
1192 (catalogInfo
->nodeData
.cnd_valence
* AVERAGE_HFSDIRENTRY_SIZE
);
1193 if (fm
->h_size
< MAX_HFSDIRENTRY_SIZE
)
1194 fm
->h_size
= MAX_HFSDIRENTRY_SIZE
;
1196 fm
->h_size
= (off_t
)vcb
->blockSize
*
1197 (off_t
)(catalogInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
+
1198 catalogInfo
->nodeData
.cnd_datafork
.totalBlocks
);
1203 void CopyCatalogToFCB(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
)
1205 FCB
*fcb
= VTOFCB(vp
);
1206 ExtendedVCB
*vcb
= VTOVCB(vp
);
1207 Boolean isHFSPlus
, isDirectory
, isResource
;
1208 HFSPlusExtentDescriptor
*extents
;
1211 DBG_ASSERT (vp
!= NULL
);
1212 DBG_ASSERT (fcb
!= NULL
);
1213 DBG_ASSERT (vcb
!= NULL
);
1214 DBG_ASSERT (VTOH(vp
) != NULL
);
1216 forkType
= H_FORKTYPE(VTOH(vp
));
1217 isResource
= (forkType
== kRsrcFork
);
1218 isDirectory
= (catalogInfo
->nodeData
.cnd_type
== kCatalogFolderNode
);
1219 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1222 fcb
->fcbFlags
= catalogInfo
->nodeData
.cnd_flags
;
1224 if (forkType
!= kDirectory
) {
1225 fcb
->fcbFlags
&= kHFSFileLockedMask
; /* Clear resource, dirty bits */
1226 if (fcb
->fcbFlags
!= 0) /* if clear, its not locked, then.. */
1227 fcb
->fcbFlags
= fcbFileLockedMask
; /* duplicate the bit for later use */
1229 fcb
->fcbClmpSize
= vcb
->vcbClpSiz
; /*XXX why not use the one in catalogInfo? */
1232 extents
= catalogInfo
->nodeData
.cnd_rsrcfork
.extents
;
1234 extents
= catalogInfo
->nodeData
.cnd_datafork
.extents
;
1236 /* Copy the extents to their correct location: */
1237 bcopy (extents
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
1240 fcb
->fcbEOF
= catalogInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
1241 fcb
->fcbPLen
= (off_t
)((off_t
)catalogInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
1242 fcb
->fcbFlags
|= fcbResourceMask
;
1244 fcb
->fcbEOF
= catalogInfo
->nodeData
.cnd_datafork
.logicalSize
;
1245 fcb
->fcbPLen
= (off_t
)((off_t
)catalogInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
1252 int hasOverflowExtents(struct hfsnode
*hp
)
1254 ExtendedVCB
*vcb
= HTOVCB(hp
);
1255 FCB
*fcb
= HTOFCB(hp
);
1258 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1261 if (fcb
->fcbExtents
[7].blockCount
== 0)
1264 blocks
= fcb
->fcbExtents
[0].blockCount
+
1265 fcb
->fcbExtents
[1].blockCount
+
1266 fcb
->fcbExtents
[2].blockCount
+
1267 fcb
->fcbExtents
[3].blockCount
+
1268 fcb
->fcbExtents
[4].blockCount
+
1269 fcb
->fcbExtents
[5].blockCount
+
1270 fcb
->fcbExtents
[6].blockCount
+
1271 fcb
->fcbExtents
[7].blockCount
;
1275 if (fcb
->fcbExtents
[2].blockCount
== 0)
1278 blocks
= fcb
->fcbExtents
[0].blockCount
+
1279 fcb
->fcbExtents
[1].blockCount
+
1280 fcb
->fcbExtents
[2].blockCount
;
1283 return ((fcb
->fcbPLen
/ vcb
->blockSize
) > blocks
);
1287 int hfs_metafilelocking(struct hfsmount
*hfsmp
, u_long fileID
, u_int flags
, struct proc
*p
)
1290 struct vnode
*vp
= NULL
;
1291 int numOfLockedBuffs
;
1294 vcb
= HFSTOVCB(hfsmp
);
1296 DBG_UTILS(("hfs_metafilelocking: vol: %d, file: %d %s%s%s\n", vcb
->vcbVRefNum
, fileID
,
1297 ((flags
& LK_TYPE_MASK
) == LK_RELEASE
? "RELEASE" : ""),
1298 ((flags
& LK_TYPE_MASK
) == LK_EXCLUSIVE
? "EXCLUSIVE" : ""),
1299 ((flags
& LK_TYPE_MASK
) == LK_SHARED
? "SHARED" : "") ));
1304 case kHFSExtentsFileID
:
1305 vp
= vcb
->extentsRefNum
;
1308 case kHFSCatalogFileID
:
1309 vp
= vcb
->catalogRefNum
;
1312 case kHFSAllocationFileID
:
1313 /* bitmap is covered by Extents B-tree locking */
1316 panic("hfs_lockmetafile: invalid fileID");
1321 /* Release, if necesary any locked buffer caches */
1322 if ((flags
& LK_TYPE_MASK
) == LK_RELEASE
) {
1323 struct timeval tv
= time
;
1324 u_int32_t lastfsync
= tv
.tv_sec
;
1326 (void) BTGetLastSync(VTOFCB(vp
), &lastfsync
);
1328 numOfLockedBuffs
= count_lock_queue();
1329 if ((numOfLockedBuffs
> kMaxLockedMetaBuffers
) || ((numOfLockedBuffs
>1) && ((tv
.tv_sec
- lastfsync
) > kMaxSecsForFsync
))) {
1330 DBG_UTILS(("Synching meta deta: %d... # locked buffers = %d, fsync gap = %ld\n", H_FILEID(VTOH(vp
)),
1331 numOfLockedBuffs
, (tv
.tv_sec
- lastfsync
)));
1332 hfs_fsync_transaction(vp
);
1336 retval
= lockmgr(&VTOH(vp
)->h_lock
, flags
, &vp
->v_interlock
, p
);
1344 * There are three ways to qualify for ownership rights on an object:
1346 * 1. (a) Your UID matches the UID of the vnode
1347 * (b) The object in question is owned by "unknown" and your UID matches the console user's UID
1348 * 2. Permissions on the filesystem are being ignored and your UID matches the replacement UID
1352 int hfs_owner_rights(struct vnode
*vp
, struct ucred
*cred
, struct proc
*p
, Boolean invokesuperuserstatus
) {
1353 return ((cred
->cr_uid
== VTOH(vp
)->h_meta
->h_uid
) || /* [1a] */
1354 ((VTOH(vp
)->h_meta
->h_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)) || /* [1b] */
1355 ((VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) && /* [2] */
1356 (cred
->cr_uid
== VTOHFS(vp
)->hfs_uid
)) || /* [2] */
1357 (invokesuperuserstatus
&& (suser(cred
, &p
->p_acflag
) == 0))) ? 0 : EPERM
;
1362 int hfs_catalogentry_owner_rights(uid_t obj_uid
, struct mount
*mp
, struct ucred
*cred
, struct proc
*p
, Boolean invokesuperuserstatus
) {
1363 return ((cred
->cr_uid
== obj_uid
) || /* [1a] */
1364 ((VFSTOHFS(mp
)->hfs_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)) || /* [1b] */
1365 ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) && /* [2] */
1366 (cred
->cr_uid
== VFSTOHFS(mp
)->hfs_uid
)) || /* [2] */
1367 (invokesuperuserstatus
&& (suser(cred
, &p
->p_acflag
) == 0))) ? 0 : EPERM
;
1372 void CopyVNodeToCatalogNode (struct vnode
*vp
, struct CatalogNodeData
*nodeData
)
1377 Boolean isHFSPlus
, isResource
;
1378 HFSPlusExtentDescriptor
*extents
;
1383 isResource
= (H_FORKTYPE(hp
) == kRsrcFork
);
1384 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1386 /* date and time of last fork modification */
1387 if (hp
->h_meta
->h_mtime
!= 0)
1388 nodeData
->cnd_contentModDate
= to_hfs_time(hp
->h_meta
->h_mtime
);
1391 /* Make sure that there is no nodeType/mode mismatch */
1392 if ((nodeData
->cnd_type
== kCatalogFolderNode
)
1393 && ((hp
->h_meta
->h_mode
& IFMT
) != IFDIR
)) {
1395 DBG_ASSERT((hp
->h_meta
->h_mode
& IFMT
) == IFDIR
);
1396 hp
->h_meta
->h_mode
&= ~IFMT
; /* Clear the bad bits */
1397 hp
->h_meta
->h_mode
|= IFDIR
; /* Set the proper one */
1399 /* date and time of last modification (any kind) */
1400 if (hp
->h_meta
->h_ctime
!= 0)
1401 nodeData
->cnd_attributeModDate
= to_hfs_time(hp
->h_meta
->h_ctime
);
1402 /* date and time of last access (MacOS X only) */
1403 if (hp
->h_meta
->h_atime
!= 0)
1404 nodeData
->cnd_accessDate
= to_hfs_time(hp
->h_meta
->h_atime
);
1405 /* hfs_setattr can change the create date */
1406 if (hp
->h_meta
->h_crtime
!= 0)
1407 nodeData
->cnd_createDate
= to_hfs_time(hp
->h_meta
->h_crtime
);
1408 if (! (hp
->h_meta
->h_metaflags
& IN_UNSETACCESS
)) {
1409 nodeData
->cnd_adminFlags
= hp
->h_meta
->h_pflags
>> 16;
1410 nodeData
->cnd_ownerFlags
= hp
->h_meta
->h_pflags
& 0x000000FF;
1411 nodeData
->cnd_mode
= hp
->h_meta
->h_mode
;
1412 nodeData
->cnd_ownerID
= hp
->h_meta
->h_uid
;
1413 nodeData
->cnd_groupID
= hp
->h_meta
->h_gid
;
1417 /* the rest only applies to files */
1418 if (nodeData
->cnd_type
== kCatalogFileNode
) {
1419 if (hp
->h_meta
->h_pflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
)) {
1420 /* The file is locked: set the locked bit in the catalog. */
1421 nodeData
->cnd_flags
|= kHFSFileLockedMask
;
1423 /* The file is unlocked: make sure the locked bit in the catalog is clear. */
1424 nodeData
->cnd_flags
&= ~kHFSFileLockedMask
;
1427 extents
= nodeData
->cnd_rsrcfork
.extents
;
1428 nodeData
->cnd_rsrcfork
.logicalSize
= fcb
->fcbEOF
;
1429 nodeData
->cnd_rsrcfork
.totalBlocks
= fcb
->fcbPLen
/ vcb
->blockSize
;
1431 extents
= nodeData
->cnd_datafork
.extents
;
1432 nodeData
->cnd_datafork
.logicalSize
= fcb
->fcbEOF
;
1433 nodeData
->cnd_datafork
.totalBlocks
= fcb
->fcbPLen
/ vcb
->blockSize
;
1436 bcopy ( fcb
->fcbExtents
, extents
, sizeof(HFSPlusExtentRecord
));
1438 if ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))
1439 nodeData
->cnd_rawDevice
= hp
->h_meta
->h_rdev
;
1440 else if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
1441 nodeData
->cnd_linkCount
= hp
->h_meta
->h_nlink
;
1443 if (vp
->v_type
== VLNK
) {
1444 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdType
= SWAP_BE32 (kSymLinkFileType
);
1445 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdCreator
= SWAP_BE32 (kSymLinkCreator
);
1447 /* Set this up as an alias */
1448 #if SUPPORTS_MAC_ALIASES
1449 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdFlags
|= SWAP_BE16 (kIsAlias
);
1456 /*********************************************************************
1458 Sets the name in the filemeta structure
1460 XXX Does not preflight if changing from one size to another
1461 XXX Currently not protected from context switching
1463 *********************************************************************/
1465 void hfs_set_metaname(char *name
, struct hfsfilemeta
*fm
, struct hfsmount
*hfsmp
)
1467 int namelen
= strlen(name
);
1468 char *tname
, *fname
;
1471 DBG_ASSERT(name
!= NULL
);
1472 DBG_ASSERT(fm
!= NULL
);
1473 if (fm
->h_namePtr
) {
1474 DBG_ASSERT(fm
->h_namelen
== strlen(fm
->h_namePtr
));
1475 if (strlen(fm
->h_namePtr
) > MAXHFSVNODELEN
)
1476 DBG_ASSERT(fm
->h_metaflags
& IN_LONGNAME
);
1478 if (fm
->h_metaflags
& IN_LONGNAME
) {
1479 DBG_ASSERT(fm
->h_namePtr
!= (char *)fm
->h_fileName
);
1480 DBG_ASSERT(fm
->h_namePtr
!= NULL
);
1482 #endif //HFS_DIAGNOSTIC
1485 * Details that have to be dealt with:
1486 * 1. No name is allocated. fm->h_namePtr should be NULL
1487 * 2. A name is being changed and:
1488 * a. it was in static space and now cannot fit
1489 * b. It was malloc'd and now will fit in the static
1490 * c. It did and will fit in the static
1491 * This could be a little smarter:
1492 * - Dont re'malloc if the new name is smaller (but then wasting memory)
1493 * - If its a longname but the same size, we still free and malloc
1498 /* Allocate the new memory */
1499 if (namelen
> MAXHFSVNODELEN
) {
1501 * Notice the we ALWAYS allocate, even if the new is less then the old,
1502 * or even if they are the SAME
1504 MALLOC(tname
, char *, namelen
+1, M_TEMP
, M_WAITOK
);
1507 tname
= fm
->h_fileName
;
1509 simple_lock(&hfsmp
->hfs_renamelock
);
1511 /* Check to see if there is something to free, if yes, remember it */
1512 if (fm
->h_metaflags
& IN_LONGNAME
)
1513 fname
= fm
->h_namePtr
;
1518 if (namelen
> MAXHFSVNODELEN
) {
1519 fm
->h_metaflags
|= IN_LONGNAME
;
1522 fm
->h_metaflags
&= ~IN_LONGNAME
;
1525 /* Now copy it over */
1526 bcopy(name
, tname
, namelen
+1);
1528 fm
->h_namePtr
= tname
;
1529 fm
->h_namelen
= namelen
;
1531 simple_unlock(&hfsmp
->hfs_renamelock
);
1533 /* Lastly, free the old, if set */
1535 FREE(fname
, M_TEMP
);
1539 void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
)
1544 DBG_ASSERT(nodeData
!= NULL
);
1545 DBG_ASSERT(fm
!= NULL
);
1546 if (fm
->h_namePtr
) {
1547 DBG_ASSERT(fm
->h_namelen
== strlen(fm
->h_namePtr
));
1548 if (strlen(fm
->h_namePtr
) > MAXHFSVNODELEN
)
1549 DBG_ASSERT(fm
->h_metaflags
& IN_LONGNAME
);
1551 if (fm
->h_metaflags
& IN_LONGNAME
) {
1552 DBG_ASSERT(fm
->h_namePtr
!= (char *)fm
->h_fileName
);
1553 DBG_ASSERT(fm
->h_namePtr
!= NULL
);
1556 DBG_ASSERT(nodeData
->cnm_nameptr
!= NULL
);
1558 if (nodeData
->cnm_length
) {
1559 DBG_ASSERT(strlen(nodeData
->cnm_nameptr
) == nodeData
->cnm_length
);
1562 if (nodeData
->cnm_length
> MAXHFSVNODELEN
)
1563 { DBG_ASSERT(nodeData
->cnm_nameptr
!= nodeData
->cnm_namespace
); }
1564 else if (nodeData
->cnm_nameptr
)
1565 { DBG_ASSERT(nodeData
->cnm_nameptr
== nodeData
->cnm_namespace
); }
1567 #endif //HFS_DIAGNOSTIC
1570 /* Check to see if there is something to free, if yes, remember it */
1571 if (fm
->h_metaflags
& IN_LONGNAME
)
1572 fname
= fm
->h_namePtr
;
1577 if (nodeData
->cnm_length
> MAXHFSVNODELEN
) {
1578 fm
->h_metaflags
|= IN_LONGNAME
;
1580 fm
->h_metaflags
&= ~IN_LONGNAME
;
1583 /* Copy over the name */
1584 if (nodeData
->cnm_nameptr
== nodeData
->cnm_namespace
) {
1585 bcopy(nodeData
->cnm_namespace
, fm
->h_fileName
, nodeData
->cnm_length
+1);
1586 fm
->h_namePtr
= fm
->h_fileName
;
1589 fm
->h_namePtr
= nodeData
->cnm_nameptr
;
1592 fm
->h_namelen
= nodeData
->cnm_length
;
1594 nodeData
->cnm_flags
|= kCatNameIsConsumed
;
1595 nodeData
->cnm_flags
&= ~kCatNameIsAllocated
;
1596 nodeData
->cnm_length
= 0;
1597 nodeData
->cnm_nameptr
= (char *)0;
1598 nodeData
->cnm_namespace
[0] = 0;
1600 /* Lastly, free the old, if set */
1602 FREE(fname
, M_TEMP
);
1607 unsigned long DerivePermissionSummary(uid_t obj_uid
, gid_t obj_gid
, mode_t obj_mode
, struct mount
*mp
, struct ucred
*cred
, struct proc
*p
) {
1609 unsigned long permissions
;
1612 /* User id 0 (root) always gets access. */
1613 if (cred
->cr_uid
== 0) {
1614 permissions
= R_OK
| W_OK
| X_OK
;
1618 /* Otherwise, check the owner. */
1619 if (hfs_catalogentry_owner_rights(obj_uid
, mp
, cred
, p
, false) == 0) {
1620 permissions
= ((unsigned long)obj_mode
& S_IRWXU
) >> 6;
1624 /* Otherwise, check the groups. */
1625 if (! (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
1626 for (i
= 0, gp
= cred
->cr_groups
; i
< cred
->cr_ngroups
; i
++, gp
++) {
1627 if (obj_gid
== *gp
) {
1628 permissions
= ((unsigned long)obj_mode
& S_IRWXG
) >> 3;
1634 /* Otherwise, settle for 'others' access. */
1635 permissions
= (unsigned long)obj_mode
& S_IRWXO
;
1643 int AttributeBlockSize(struct attrlist
*attrlist
) {
1647 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1648 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_PAROBJID | \
1649 ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
1650 ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1651 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST| \
1652 ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) != ATTR_CMN_VALIDMASK)
1653 #error AttributeBlockSize: Missing bits in common mask computation!
1655 DBG_ASSERT((attrlist
->commonattr
& ~ATTR_CMN_VALIDMASK
) == 0);
1657 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
1658 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1659 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | \
1660 ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | \
1661 ATTR_VOL_MOUNTEDDEVICE| ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) != ATTR_VOL_VALIDMASK)
1662 #error AttributeBlockSize: Missing bits in volume mask computation!
1664 DBG_ASSERT((attrlist
->volattr
& ~ATTR_VOL_VALIDMASK
) == 0);
1666 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) != ATTR_DIR_VALIDMASK)
1667 #error AttributeBlockSize: Missing bits in directory mask computation!
1669 DBG_ASSERT((attrlist
->dirattr
& ~ATTR_DIR_VALIDMASK
) == 0);
1670 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
1671 ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | \
1672 ATTR_FILE_FORKLIST | ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1673 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) != ATTR_FILE_VALIDMASK)
1674 #error AttributeBlockSize: Missing bits in file mask computation!
1676 DBG_ASSERT((attrlist
->fileattr
& ~ATTR_FILE_VALIDMASK
) == 0);
1678 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1679 #error AttributeBlockSize: Missing bits in fork mask computation!
1681 DBG_ASSERT((attrlist
->forkattr
& ~ATTR_FORK_VALIDMASK
) == 0);
1685 if ((a
= attrlist
->commonattr
) != 0) {
1686 if (a
& ATTR_CMN_NAME
) size
+= sizeof(struct attrreference
);
1687 if (a
& ATTR_CMN_DEVID
) size
+= sizeof(dev_t
);
1688 if (a
& ATTR_CMN_FSID
) size
+= sizeof(fsid_t
);
1689 if (a
& ATTR_CMN_OBJTYPE
) size
+= sizeof(fsobj_type_t
);
1690 if (a
& ATTR_CMN_OBJTAG
) size
+= sizeof(fsobj_tag_t
);
1691 if (a
& ATTR_CMN_OBJID
) size
+= sizeof(fsobj_id_t
);
1692 if (a
& ATTR_CMN_OBJPERMANENTID
) size
+= sizeof(fsobj_id_t
);
1693 if (a
& ATTR_CMN_PAROBJID
) size
+= sizeof(fsobj_id_t
);
1694 if (a
& ATTR_CMN_SCRIPT
) size
+= sizeof(text_encoding_t
);
1695 if (a
& ATTR_CMN_CRTIME
) size
+= sizeof(struct timespec
);
1696 if (a
& ATTR_CMN_MODTIME
) size
+= sizeof(struct timespec
);
1697 if (a
& ATTR_CMN_CHGTIME
) size
+= sizeof(struct timespec
);
1698 if (a
& ATTR_CMN_ACCTIME
) size
+= sizeof(struct timespec
);
1699 if (a
& ATTR_CMN_BKUPTIME
) size
+= sizeof(struct timespec
);
1700 if (a
& ATTR_CMN_FNDRINFO
) size
+= 32 * sizeof(UInt8
);
1701 if (a
& ATTR_CMN_OWNERID
) size
+= sizeof(uid_t
);
1702 if (a
& ATTR_CMN_GRPID
) size
+= sizeof(gid_t
);
1703 if (a
& ATTR_CMN_ACCESSMASK
) size
+= sizeof(u_long
);
1704 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) size
+= sizeof(u_long
);
1705 if (a
& ATTR_CMN_NAMEDATTRLIST
) size
+= sizeof(struct attrreference
);
1706 if (a
& ATTR_CMN_FLAGS
) size
+= sizeof(u_long
);
1707 if (a
& ATTR_CMN_USERACCESS
) size
+= sizeof(u_long
);
1709 if ((a
= attrlist
->volattr
) != 0) {
1710 if (a
& ATTR_VOL_FSTYPE
) size
+= sizeof(u_long
);
1711 if (a
& ATTR_VOL_SIGNATURE
) size
+= sizeof(u_long
);
1712 if (a
& ATTR_VOL_SIZE
) size
+= sizeof(off_t
);
1713 if (a
& ATTR_VOL_SPACEFREE
) size
+= sizeof(off_t
);
1714 if (a
& ATTR_VOL_SPACEAVAIL
) size
+= sizeof(off_t
);
1715 if (a
& ATTR_VOL_MINALLOCATION
) size
+= sizeof(off_t
);
1716 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) size
+= sizeof(off_t
);
1717 if (a
& ATTR_VOL_IOBLOCKSIZE
) size
+= sizeof(u_long
);
1718 if (a
& ATTR_VOL_OBJCOUNT
) size
+= sizeof(u_long
);
1719 if (a
& ATTR_VOL_FILECOUNT
) size
+= sizeof(u_long
);
1720 if (a
& ATTR_VOL_DIRCOUNT
) size
+= sizeof(u_long
);
1721 if (a
& ATTR_VOL_MAXOBJCOUNT
) size
+= sizeof(u_long
);
1722 if (a
& ATTR_VOL_MOUNTPOINT
) size
+= sizeof(struct attrreference
);
1723 if (a
& ATTR_VOL_NAME
) size
+= sizeof(struct attrreference
);
1724 if (a
& ATTR_VOL_MOUNTFLAGS
) size
+= sizeof(u_long
);
1725 if (a
& ATTR_VOL_MOUNTEDDEVICE
) size
+= sizeof(struct attrreference
);
1726 if (a
& ATTR_VOL_ENCODINGSUSED
) size
+= sizeof(unsigned long long);
1727 if (a
& ATTR_VOL_CAPABILITIES
) size
+= sizeof(vol_capabilities_attr_t
);
1728 if (a
& ATTR_VOL_ATTRIBUTES
) size
+= sizeof(vol_attributes_attr_t
);
1730 if ((a
= attrlist
->dirattr
) != 0) {
1731 if (a
& ATTR_DIR_LINKCOUNT
) size
+= sizeof(u_long
);
1732 if (a
& ATTR_DIR_ENTRYCOUNT
) size
+= sizeof(u_long
);
1733 if (a
& ATTR_DIR_MOUNTSTATUS
) size
+= sizeof(u_long
);
1735 if ((a
= attrlist
->fileattr
) != 0) {
1736 if (a
& ATTR_FILE_LINKCOUNT
) size
+= sizeof(u_long
);
1737 if (a
& ATTR_FILE_TOTALSIZE
) size
+= sizeof(off_t
);
1738 if (a
& ATTR_FILE_ALLOCSIZE
) size
+= sizeof(off_t
);
1739 if (a
& ATTR_FILE_IOBLOCKSIZE
) size
+= sizeof(size_t);
1740 if (a
& ATTR_FILE_CLUMPSIZE
) size
+= sizeof(off_t
);
1741 if (a
& ATTR_FILE_DEVTYPE
) size
+= sizeof(u_long
);
1742 if (a
& ATTR_FILE_FILETYPE
) size
+= sizeof(u_long
);
1743 if (a
& ATTR_FILE_FORKCOUNT
) size
+= sizeof(u_long
);
1744 if (a
& ATTR_FILE_FORKLIST
) size
+= sizeof(struct attrreference
);
1745 if (a
& ATTR_FILE_DATALENGTH
) size
+= sizeof(off_t
);
1746 if (a
& ATTR_FILE_DATAALLOCSIZE
) size
+= sizeof(off_t
);
1747 if (a
& ATTR_FILE_DATAEXTENTS
) size
+= sizeof(extentrecord
);
1748 if (a
& ATTR_FILE_RSRCLENGTH
) size
+= sizeof(off_t
);
1749 if (a
& ATTR_FILE_RSRCALLOCSIZE
) size
+= sizeof(off_t
);
1750 if (a
& ATTR_FILE_RSRCEXTENTS
) size
+= sizeof(extentrecord
);
1752 if ((a
= attrlist
->forkattr
) != 0) {
1753 if (a
& ATTR_FORK_TOTALSIZE
) size
+= sizeof(off_t
);
1754 if (a
& ATTR_FORK_ALLOCSIZE
) size
+= sizeof(off_t
);
1762 char* FindMountpointName(struct mount
*mp
) {
1763 size_t namelength
= strlen(mp
->mnt_stat
.f_mntonname
);
1767 if (namelength
== 0) return NULL
;
1769 /* Look backwards through the name string, looking for the first slash
1770 encountered (which must precede the last part of the pathname)
1772 for (c
= mp
->mnt_stat
.f_mntonname
+ namelength
- 1; namelength
> 0; --c
, --namelength
) {
1775 } else if (foundchars
) {
1780 return mp
->mnt_stat
.f_mntonname
;
1785 void PackObjectName(struct vnode
*vp
,
1788 void **attrbufptrptr
,
1789 void **varbufptrptr
) {
1794 /* The name of an object may be incorrect for the root of a mounted filesystem
1795 because it may be mounted on a different directory name than the name of the
1796 volume (such as "blah-1". For the root directory, it's best to return the
1797 last element of the location where the volume's mounted:
1799 if ((vp
->v_flag
& VROOT
) && (mpname
= FindMountpointName(vp
->v_mount
))) {
1800 mpnamelen
= strlen(mpname
);
1802 /* Trim off any trailing slashes: */
1803 while ((mpnamelen
> 0) && (mpname
[mpnamelen
-1] == '/')) {
1807 /* If there's anything left, use it instead of the volume's name */
1808 if (mpnamelen
> 0) {
1810 namelen
= mpnamelen
;
1814 attrlength
= namelen
+ 1;
1815 ((struct attrreference
*)(*attrbufptrptr
))->attr_dataoffset
= (char *)(*varbufptrptr
) - (char *)(*attrbufptrptr
);
1816 ((struct attrreference
*)(*attrbufptrptr
))->attr_length
= attrlength
;
1817 (void) strncpy((unsigned char *)(*varbufptrptr
), name
, attrlength
);
1819 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1820 (char *)(*varbufptrptr
) += attrlength
+ ((4 - (attrlength
& 3)) & 3);
1821 ++((struct attrreference
*)(*attrbufptrptr
));
1826 void PackVolCommonAttributes(struct attrlist
*alist
,
1827 struct vnode
*root_vp
,
1828 struct hfsCatalogInfo
*root_catInfo
,
1829 void **attrbufptrptr
,
1830 void **varbufptrptr
) {
1834 struct hfsnode
*root_hp
= VTOH(root_vp
);
1835 struct mount
*mp
= VTOVFS(root_vp
);
1836 struct hfsmount
*hfsmp
= VTOHFS(root_vp
);
1837 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1840 attrbufptr
= *attrbufptrptr
;
1841 varbufptr
= *varbufptrptr
;
1843 if ((a
= alist
->commonattr
) != 0) {
1844 if (a
& ATTR_CMN_NAME
) {
1845 PackObjectName(root_vp
, H_NAME(root_hp
), root_hp
->h_meta
->h_namelen
, &attrbufptr
, &varbufptr
);
1847 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1848 if (a
& ATTR_CMN_FSID
) {
1849 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1850 ++((fsid_t
*)attrbufptr
);
1852 if (a
& ATTR_CMN_OBJTYPE
) *((fsobj_type_t
*)attrbufptr
)++ = 0;
1853 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1854 if (a
& ATTR_CMN_OBJID
) {
1855 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1856 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1857 ++((fsobj_id_t
*)attrbufptr
);
1859 if (a
& ATTR_CMN_OBJPERMANENTID
) {
1860 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1861 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1862 ++((fsobj_id_t
*)attrbufptr
);
1864 if (a
& ATTR_CMN_PAROBJID
) {
1865 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1866 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1867 ++((fsobj_id_t
*)attrbufptr
);
1870 if (a
& ATTR_CMN_SCRIPT
) *((text_encoding_t
*)attrbufptr
)++ = vcb
->volumeNameEncodingHint
;
1871 /* NOTE: all VCB dates are in Mac OS time */
1872 if (a
& ATTR_CMN_CRTIME
) {
1873 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(LocalToUTC(vcb
->localCreateDate
));
1874 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1875 ++((struct timespec
*)attrbufptr
);
1877 if (a
& ATTR_CMN_MODTIME
) {
1878 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1879 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1880 ++((struct timespec
*)attrbufptr
);
1882 if (a
& ATTR_CMN_CHGTIME
) {
1883 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1884 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1885 ++((struct timespec
*)attrbufptr
);
1887 if (a
& ATTR_CMN_ACCTIME
) {
1888 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1889 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1890 ++((struct timespec
*)attrbufptr
);
1892 if (a
& ATTR_CMN_BKUPTIME
) {
1893 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbVolBkUp
);
1894 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1895 ++((struct timespec
*)attrbufptr
);
1897 if (a
& ATTR_CMN_FNDRINFO
) {
1898 bcopy (&vcb
->vcbFndrInfo
, attrbufptr
, sizeof(vcb
->vcbFndrInfo
));
1899 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1902 if (a
& ATTR_CMN_OWNERID
) {
1903 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1904 *((uid_t
*)attrbufptr
)++ =
1905 (VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
;
1907 *((uid_t
*)attrbufptr
)++ =
1908 (root_hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: root_hp
->h_meta
->h_uid
;
1911 if (a
& ATTR_CMN_GRPID
) {
1912 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1913 *((gid_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_gid
;
1915 *((gid_t
*)attrbufptr
)++ = root_hp
->h_meta
->h_gid
;
1918 if (a
& ATTR_CMN_ACCESSMASK
) *((u_long
*)attrbufptr
)++ = (u_long
)root_hp
->h_meta
->h_mode
;
1919 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
1920 if (a
& ATTR_CMN_NAMEDATTRLIST
) {
1922 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1923 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1925 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1926 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1927 ++((struct attrreference
*)attrbufptr
);
1929 if (a
& ATTR_CMN_FLAGS
) *((u_long
*)attrbufptr
)++ = root_hp
->h_meta
->h_pflags
;
1930 if (a
& ATTR_CMN_USERACCESS
) {
1931 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1932 *((u_long
*)attrbufptr
)++ =
1933 DerivePermissionSummary((VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
,
1934 VTOHFS(root_vp
)->hfs_gid
,
1935 root_hp
->h_meta
->h_mode
,
1937 current_proc()->p_ucred
,
1940 *((u_long
*)attrbufptr
)++ =
1941 DerivePermissionSummary((root_hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: root_hp
->h_meta
->h_uid
,
1942 root_hp
->h_meta
->h_gid
,
1943 root_hp
->h_meta
->h_mode
,
1945 current_proc()->p_ucred
,
1951 *attrbufptrptr
= attrbufptr
;
1952 *varbufptrptr
= varbufptr
;
1957 void PackVolAttributeBlock(struct attrlist
*alist
,
1958 struct vnode
*root_vp
,
1959 struct hfsCatalogInfo
*root_catInfo
,
1960 void **attrbufptrptr
,
1961 void **varbufptrptr
) {
1965 struct mount
*mp
= VTOVFS(root_vp
);
1966 struct hfsmount
*hfsmp
= VTOHFS(root_vp
);
1967 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1970 attrbufptr
= *attrbufptrptr
;
1971 varbufptr
= *varbufptrptr
;
1973 if ((a
= alist
->volattr
) != 0) {
1975 if (a
& ATTR_VOL_FSTYPE
) *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_vfc
->vfc_typenum
;
1976 if (a
& ATTR_VOL_SIGNATURE
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbSigWord
;
1977 if (a
& ATTR_VOL_SIZE
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->totalBlocks
* (off_t
)vcb
->blockSize
;
1978 if (a
& ATTR_VOL_SPACEFREE
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->freeBlocks
* (off_t
)vcb
->blockSize
;
1979 if (a
& ATTR_VOL_SPACEAVAIL
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->freeBlocks
* (off_t
)vcb
->blockSize
;
1980 if (a
& ATTR_VOL_MINALLOCATION
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->blockSize
;
1981 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) *((off_t
*)attrbufptr
)++ = (off_t
)(vcb
->vcbClpSiz
);
1982 if (a
& ATTR_VOL_IOBLOCKSIZE
) *((u_long
*)attrbufptr
)++ = (u_long
)hfsmp
->hfs_logBlockSize
;
1983 if (a
& ATTR_VOL_OBJCOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
+ (u_long
)vcb
->vcbDirCnt
;
1984 if (a
& ATTR_VOL_FILECOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
;
1985 if (a
& ATTR_VOL_DIRCOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbDirCnt
;
1986 if (a
& ATTR_VOL_MAXOBJCOUNT
) *((u_long
*)attrbufptr
)++ = 0xFFFFFFFF;
1987 if (a
& ATTR_VOL_MOUNTPOINT
) {
1988 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1989 ((struct attrreference
*)attrbufptr
)->attr_length
= strlen(mp
->mnt_stat
.f_mntonname
) + 1;
1990 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1991 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1992 (void) bcopy(mp
->mnt_stat
.f_mntonname
, varbufptr
, attrlength
);
1994 /* Advance beyond the space just allocated: */
1995 (char *)varbufptr
+= attrlength
;
1996 ++((struct attrreference
*)attrbufptr
);
1998 if (a
& ATTR_VOL_NAME
) {
1999 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
2000 ((struct attrreference
*)attrbufptr
)->attr_length
= VTOH(root_vp
)->h_meta
->h_namelen
+ 1;
2001 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
2002 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
2003 bcopy(H_NAME(VTOH(root_vp
)), varbufptr
, attrlength
);
2005 /* Advance beyond the space just allocated: */
2006 (char *)varbufptr
+= attrlength
;
2007 ++((struct attrreference
*)attrbufptr
);
2009 if (a
& ATTR_VOL_MOUNTFLAGS
) *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_flag
;
2010 if (a
& ATTR_VOL_MOUNTEDDEVICE
) {
2011 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
2012 ((struct attrreference
*)attrbufptr
)->attr_length
= strlen(mp
->mnt_stat
.f_mntfromname
) + 1;
2013 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
2014 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
2015 (void) bcopy(mp
->mnt_stat
.f_mntfromname
, varbufptr
, attrlength
);
2017 /* Advance beyond the space just allocated: */
2018 (char *)varbufptr
+= attrlength
;
2019 ++((struct attrreference
*)attrbufptr
);
2021 if (a
& ATTR_VOL_ENCODINGSUSED
) *((unsigned long long *)attrbufptr
)++ = (unsigned long long)vcb
->encodingsBitmap
;
2022 if (a
& ATTR_VOL_CAPABILITIES
) {
2023 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_FORMAT
] =
2024 VOL_CAP_FMT_PERSISTENTOBJECTIDS
| VOL_CAP_FMT_SYMBOLICLINKS
| VOL_CAP_FMT_HARDLINKS
;
2025 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_INTERFACES
] =
2026 VOL_CAP_INT_SEARCHFS
| VOL_CAP_INT_ATTRLIST
| VOL_CAP_INT_NFSEXPORT
;
2027 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
2028 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
2030 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_FORMAT
] =
2031 VOL_CAP_FMT_PERSISTENTOBJECTIDS
| VOL_CAP_FMT_SYMBOLICLINKS
| VOL_CAP_FMT_HARDLINKS
;
2032 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_INTERFACES
] =
2033 VOL_CAP_INT_SEARCHFS
| VOL_CAP_INT_ATTRLIST
| VOL_CAP_INT_NFSEXPORT
;
2034 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
2035 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
2037 ++((vol_capabilities_attr_t
*)attrbufptr
);
2039 if (a
& ATTR_VOL_ATTRIBUTES
) {
2040 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.commonattr
= ATTR_CMN_VALIDMASK
;
2041 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.volattr
= ATTR_VOL_VALIDMASK
;
2042 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.dirattr
= ATTR_DIR_VALIDMASK
;
2043 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.fileattr
= ATTR_FILE_VALIDMASK
;
2044 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.forkattr
= ATTR_FORK_VALIDMASK
;
2046 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.commonattr
= ATTR_CMN_VALIDMASK
;
2047 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.volattr
= ATTR_VOL_VALIDMASK
;
2048 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.dirattr
= ATTR_DIR_VALIDMASK
;
2049 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.fileattr
= ATTR_FILE_VALIDMASK
;
2050 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.forkattr
= ATTR_FORK_VALIDMASK
;
2052 ++((vol_attributes_attr_t
*)attrbufptr
);
2057 *attrbufptrptr
= attrbufptr
;
2058 *varbufptrptr
= varbufptr
;
2064 void PackVolumeInfo(struct attrlist
*alist
,
2065 struct vnode
*root_vp
,
2066 struct hfsCatalogInfo
*root_catinfo
,
2067 void **attrbufptrptr
,
2068 void **varbufptrptr
) {
2070 PackVolCommonAttributes(alist
, root_vp
, root_catinfo
, attrbufptrptr
, varbufptrptr
);
2071 PackVolAttributeBlock(alist
, root_vp
, root_catinfo
, attrbufptrptr
, varbufptrptr
);
2074 // Pack the common attribute contents of an objects hfsCatalogInfo
2075 void PackCommonCatalogInfoAttributeBlock(struct attrlist
*alist
,
2076 struct vnode
*root_vp
,
2077 struct hfsCatalogInfo
*catalogInfo
,
2078 void **attrbufptrptr
,
2079 void **varbufptrptr
)
2088 attrbufptr
= *attrbufptrptr
;
2089 varbufptr
= *varbufptrptr
;
2091 if ((a
= alist
->commonattr
) != 0)
2093 if (a
& ATTR_CMN_NAME
)
2095 attrlength
= strlen(catalogInfo
->nodeData
.cnm_nameptr
) + 1;
2096 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
2097 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2098 (void) strncpy((unsigned char *)varbufptr
,
2099 catalogInfo
->nodeData
.cnm_nameptr
, attrlength
);
2101 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2102 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2103 ++((struct attrreference
*)attrbufptr
);
2105 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = H_DEV(hp
);
2106 if (a
& ATTR_CMN_FSID
) {
2107 *((fsid_t
*)attrbufptr
) = VTOVFS(root_vp
)->mnt_stat
.f_fsid
;
2108 ++((fsid_t
*)attrbufptr
);
2110 if (a
& ATTR_CMN_OBJTYPE
)
2112 switch (catalogInfo
->nodeData
.cnd_type
) {
2113 case kCatalogFolderNode
:
2114 *((fsobj_type_t
*)attrbufptr
)++ = VDIR
;
2117 case kCatalogFileNode
:
2118 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2119 if ((HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) &&
2120 (catalogInfo
->nodeData
.cnd_mode
& IFMT
)) {
2121 *((fsobj_type_t
*)attrbufptr
)++ =
2122 IFTOVT((mode_t
)catalogInfo
->nodeData
.cnd_mode
);
2124 *((fsobj_type_t
*)attrbufptr
)++ = VREG
;
2129 *((fsobj_type_t
*)attrbufptr
)++ = VNON
;
2133 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = root_vp
->v_tag
;
2134 if (a
& ATTR_CMN_OBJID
)
2136 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= catalogInfo
->nodeData
.cnd_nodeID
;
2137 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2138 ++((fsobj_id_t
*)attrbufptr
);
2140 if (a
& ATTR_CMN_OBJPERMANENTID
)
2142 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= catalogInfo
->nodeData
.cnd_nodeID
;
2143 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2144 ++((fsobj_id_t
*)attrbufptr
);
2146 if (a
& ATTR_CMN_PAROBJID
)
2148 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= catalogInfo
->nodeData
.cnm_parID
;
2149 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2150 ++((fsobj_id_t
*)attrbufptr
);
2152 if (a
& ATTR_CMN_SCRIPT
)
2154 if (HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) {
2155 *((text_encoding_t
*)attrbufptr
)++ = catalogInfo
->nodeData
.cnd_textEncoding
;
2157 *((text_encoding_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_encoding
;
2160 if (a
& ATTR_CMN_CRTIME
)
2162 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_createDate
);
2163 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2164 ++((struct timespec
*)attrbufptr
);
2166 if (a
& ATTR_CMN_MODTIME
)
2168 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
2169 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2170 ++((struct timespec
*)attrbufptr
);
2172 if (a
& ATTR_CMN_CHGTIME
)
2174 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_attributeModDate
);
2175 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2176 ++((struct timespec
*)attrbufptr
);
2178 if (a
& ATTR_CMN_ACCTIME
)
2180 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_accessDate
);
2181 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2182 ++((struct timespec
*)attrbufptr
);
2184 if (a
& ATTR_CMN_BKUPTIME
)
2186 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_backupDate
);
2187 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2188 ++((struct timespec
*)attrbufptr
);
2190 if (a
& ATTR_CMN_FNDRINFO
)
2192 bcopy (&catalogInfo
->nodeData
.cnd_finderInfo
, attrbufptr
, sizeof(catalogInfo
->nodeData
.cnd_finderInfo
));
2193 (char *)attrbufptr
+= sizeof(catalogInfo
->nodeData
.cnd_finderInfo
);
2195 if (a
& ATTR_CMN_OWNERID
) {
2196 if (VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2197 *((uid_t
*)attrbufptr
)++ =
2198 (VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
;
2200 *((uid_t
*)attrbufptr
)++ =
2201 (catalogInfo
->nodeData
.cnd_ownerID
== UNKNOWNUID
) ? console_user
: catalogInfo
->nodeData
.cnd_ownerID
;
2204 if (a
& ATTR_CMN_GRPID
) {
2205 if (VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2206 *((gid_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_gid
;
2208 *((gid_t
*)attrbufptr
)++ = catalogInfo
->nodeData
.cnd_groupID
;
2211 if (a
& ATTR_CMN_ACCESSMASK
) {
2212 #if OVERRIDE_UNKNOWN_PERMISSIONS
2213 if (VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2214 switch (catalogInfo
->nodeData
.cnd_type
) {
2215 case kCatalogFileNode
:
2216 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2217 *((fsobj_type_t
*)attrbufptr
)++ = (u_long
)(VTOHFS(root_vp
)->hfs_file_mask
);
2220 case kCatalogFolderNode
:
2221 /* Fall through to default case */
2224 *((u_long
*)attrbufptr
)++ = (u_long
)(VTOHFS(root_vp
)->hfs_dir_mask
);
2228 *((u_long
*)attrbufptr
)++ =
2229 (u_long
)catalogInfo
->nodeData
.cnd_mode
;
2230 #if OVERRIDE_UNKNOWN_PERMISSIONS
2234 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
2235 if (a
& ATTR_CMN_NAMEDATTRLIST
)
2238 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2239 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2241 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2242 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2243 ++((struct attrreference
*)attrbufptr
);
2245 if (a
& ATTR_CMN_FLAGS
)
2246 *((u_long
*)attrbufptr
)++ =
2247 (u_long
) (catalogInfo
->nodeData
.cnd_ownerFlags
|
2248 (catalogInfo
->nodeData
.cnd_adminFlags
<< 16));
2249 if (a
& ATTR_CMN_USERACCESS
) {
2250 if (VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2251 *((u_long
*)attrbufptr
)++ =
2252 DerivePermissionSummary((VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
,
2253 VTOHFS(root_vp
)->hfs_gid
,
2254 (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) ? VTOHFS(root_vp
)->hfs_file_mask
: VTOHFS(root_vp
)->hfs_dir_mask
,
2256 current_proc()->p_ucred
,
2259 *((u_long
*)attrbufptr
)++ =
2260 DerivePermissionSummary((catalogInfo
->nodeData
.cnd_ownerID
== UNKNOWNUID
) ? console_user
: catalogInfo
->nodeData
.cnd_ownerID
,
2261 catalogInfo
->nodeData
.cnd_groupID
,
2262 (mode_t
)catalogInfo
->nodeData
.cnd_mode
,
2264 current_proc()->p_ucred
,
2270 *attrbufptrptr
= attrbufptr
;
2271 *varbufptrptr
= varbufptr
;
2275 void PackCommonAttributeBlock(struct attrlist
*alist
,
2277 struct hfsCatalogInfo
*catInfo
,
2278 void **attrbufptrptr
,
2279 void **varbufptrptr
) {
2288 attrbufptr
= *attrbufptrptr
;
2289 varbufptr
= *varbufptrptr
;
2291 if ((a
= alist
->commonattr
) != 0) {
2292 if (a
& ATTR_CMN_NAME
) {
2293 PackObjectName(vp
, H_NAME(hp
), hp
->h_meta
->h_namelen
, &attrbufptr
, &varbufptr
);
2295 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = H_DEV(hp
);
2296 if (a
& ATTR_CMN_FSID
) {
2297 *((fsid_t
*)attrbufptr
) = VTOVFS(vp
)->mnt_stat
.f_fsid
;
2298 ++((fsid_t
*)attrbufptr
);
2300 if (a
& ATTR_CMN_OBJTYPE
) *((fsobj_type_t
*)attrbufptr
)++ = vp
->v_type
;
2301 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = vp
->v_tag
;
2302 if (a
& ATTR_CMN_OBJID
) {
2303 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= H_FILEID(hp
);
2304 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2305 ++((fsobj_id_t
*)attrbufptr
);
2307 if (a
& ATTR_CMN_OBJPERMANENTID
) {
2308 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= H_FILEID(hp
);
2309 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2310 ++((fsobj_id_t
*)attrbufptr
);
2312 if (a
& ATTR_CMN_PAROBJID
) {
2313 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= H_DIRID(hp
);
2314 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2315 ++((fsobj_id_t
*)attrbufptr
);
2317 if (a
& ATTR_CMN_SCRIPT
)
2319 if (HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) {
2320 *((text_encoding_t
*)attrbufptr
)++ = catInfo
->nodeData
.cnd_textEncoding
;
2322 *((text_encoding_t
*)attrbufptr
)++ = VTOHFS(vp
)->hfs_encoding
;
2325 if (a
& ATTR_CMN_CRTIME
) {
2326 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_crtime
;
2327 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2328 ++((struct timespec
*)attrbufptr
);
2330 if (a
& ATTR_CMN_MODTIME
) {
2331 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_mtime
;
2332 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2333 ++((struct timespec
*)attrbufptr
);
2335 if (a
& ATTR_CMN_CHGTIME
) {
2336 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_ctime
;
2337 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2338 ++((struct timespec
*)attrbufptr
);
2340 if (a
& ATTR_CMN_ACCTIME
) {
2341 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_atime
;
2342 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2343 ++((struct timespec
*)attrbufptr
);
2345 if (a
& ATTR_CMN_BKUPTIME
) {
2346 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_butime
;
2347 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2348 ++((struct timespec
*)attrbufptr
);
2350 if (a
& ATTR_CMN_FNDRINFO
) {
2351 bcopy (&catInfo
->nodeData
.cnd_finderInfo
, attrbufptr
, sizeof(catInfo
->nodeData
.cnd_finderInfo
));
2352 (char *)attrbufptr
+= sizeof(catInfo
->nodeData
.cnd_finderInfo
);
2354 if (a
& ATTR_CMN_OWNERID
) {
2355 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2356 *((uid_t
*)attrbufptr
)++ =
2357 (VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(vp
)->hfs_uid
;
2359 *((uid_t
*)attrbufptr
)++ =
2360 (hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: hp
->h_meta
->h_uid
;
2363 if (a
& ATTR_CMN_GRPID
) {
2364 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2365 *((gid_t
*)attrbufptr
)++ = VTOHFS(vp
)->hfs_gid
;
2367 *((gid_t
*)attrbufptr
)++ = hp
->h_meta
->h_gid
;
2370 if (a
& ATTR_CMN_ACCESSMASK
) *((u_long
*)attrbufptr
)++ = (u_long
)hp
->h_meta
->h_mode
;
2371 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
2372 if (a
& ATTR_CMN_NAMEDATTRLIST
) {
2374 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2375 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
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
);
2381 if (a
& ATTR_CMN_FLAGS
) *((u_long
*)attrbufptr
)++ = hp
->h_meta
->h_pflags
;
2382 if (a
& ATTR_CMN_USERACCESS
) {
2383 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2384 *((u_long
*)attrbufptr
)++ =
2385 DerivePermissionSummary((VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(vp
)->hfs_uid
,
2386 VTOHFS(vp
)->hfs_gid
,
2389 current_proc()->p_ucred
,
2392 *((u_long
*)attrbufptr
)++ =
2393 DerivePermissionSummary((hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: hp
->h_meta
->h_uid
,
2397 current_proc()->p_ucred
,
2403 *attrbufptrptr
= attrbufptr
;
2404 *varbufptrptr
= varbufptr
;
2408 // Pack the directory attributes given hfsCatalogInfo
2409 void PackCatalogInfoDirAttributeBlock( struct attrlist
*alist
, struct vnode
*vp
,
2410 struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2416 attrbufptr
= *attrbufptrptr
;
2419 if ( (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) && (a
!= 0) ) {
2420 valence
= catInfo
->nodeData
.cnd_valence
;
2421 if ((catInfo
->nodeData
.cnm_parID
== kRootParID
) &&
2422 (VTOHFS(vp
)->hfs_private_metadata_dir
!= 0)) {
2423 --valence
; /* hide private dir */
2425 /* The 'link count' is faked */
2426 if (a
& ATTR_DIR_LINKCOUNT
)
2427 *((u_long
*)attrbufptr
)++ = 2 + valence
;
2428 if (a
& ATTR_DIR_ENTRYCOUNT
)
2429 *((u_long
*)attrbufptr
)++ = valence
;
2430 if (a
& ATTR_DIR_MOUNTSTATUS
)
2431 *((u_long
*)attrbufptr
)++ = 0;
2434 *attrbufptrptr
= attrbufptr
;
2438 void PackDirAttributeBlock(struct attrlist
*alist
,
2440 struct hfsCatalogInfo
*catInfo
,
2441 void **attrbufptrptr
,
2442 void **varbufptrptr
) {
2447 attrbufptr
= *attrbufptrptr
;
2450 if ((vp
->v_type
== VDIR
) && (a
!= 0)) {
2451 valence
= catInfo
->nodeData
.cnd_valence
;
2452 if ((catInfo
->nodeData
.cnm_parID
== kRootParID
) &&
2453 (VTOHFS(vp
)->hfs_private_metadata_dir
!= 0)) {
2454 --valence
; /* hide private dir */
2457 /* The 'link count' is faked */
2458 if (a
& ATTR_DIR_LINKCOUNT
)
2459 *((u_long
*)attrbufptr
)++ = 2 + valence
;
2460 if (a
& ATTR_DIR_ENTRYCOUNT
)
2461 *((u_long
*)attrbufptr
)++ = valence
;
2462 if (a
& ATTR_DIR_MOUNTSTATUS
) {
2463 if (vp
->v_mountedhere
) {
2464 *((u_long
*)attrbufptr
)++ = DIR_MNTSTATUS_MNTPOINT
;
2466 *((u_long
*)attrbufptr
)++ = 0;
2471 *attrbufptrptr
= attrbufptr
;
2476 // Pack the file attributes from the hfsCatalogInfo for the file.
2477 void PackCatalogInfoFileAttributeBlock( struct attrlist
*alist
, struct vnode
*root_vp
, struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2483 ExtendedVCB
*vcb
= VTOVCB(root_vp
);
2485 attrbufptr
= *attrbufptrptr
;
2486 varbufptr
= *varbufptrptr
;
2488 a
= alist
->fileattr
;
2489 if ( (catInfo
->nodeData
.cnd_type
== kCatalogFileNode
) && (a
!= 0) )
2492 if (a
& ATTR_FILE_LINKCOUNT
) {
2493 u_long linkcnt
= catInfo
->nodeData
.cnd_linkCount
;
2497 *((u_long
*)attrbufptr
)++ = linkcnt
;
2500 if (a
& ATTR_FILE_LINKCOUNT
) *((u_long
*)attrbufptr
)++ = 1;
2502 if (a
& ATTR_FILE_TOTALSIZE
) {
2503 *((off_t
*)attrbufptr
)++ =
2504 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
+
2505 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2507 if (a
& ATTR_FILE_ALLOCSIZE
) {
2508 *((off_t
*)attrbufptr
)++ =
2509 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
) +
2510 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2512 if (a
& ATTR_FILE_IOBLOCKSIZE
) {
2513 *((u_long
*)attrbufptr
)++ = (u_long
)(VTOHFS(root_vp
)->hfs_logBlockSize
);
2515 if (a
& ATTR_FILE_CLUMPSIZE
) {
2516 *((u_long
*)attrbufptr
)++ = vcb
->vcbClpSiz
;
2518 if (a
& ATTR_FILE_DEVTYPE
) {
2522 filetype
= (catInfo
->nodeData
.cnd_mode
& IFMT
);
2523 if (filetype
== IFCHR
|| filetype
== IFBLK
)
2524 rawdev
= (u_long
)catInfo
->nodeData
.cnd_rawDevice
;
2528 *((u_long
*)attrbufptr
)++ = rawdev
;
2530 if (a
& ATTR_FILE_FILETYPE
) {
2531 *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD */
2533 if (a
& ATTR_FILE_FORKCOUNT
) {
2534 *((u_long
*)attrbufptr
)++ = 2; /* XXX PPD */
2536 if (a
& ATTR_FILE_FORKLIST
) {
2538 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2539 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2541 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2542 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2543 ++((struct attrreference
*)attrbufptr
);
2545 if (a
& ATTR_FILE_DATALENGTH
) {
2546 *((off_t
*)attrbufptr
)++ =
2547 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
;
2549 if (a
& ATTR_FILE_DATAALLOCSIZE
) {
2550 *((off_t
*)attrbufptr
)++ =
2551 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2553 if (a
& ATTR_FILE_DATAEXTENTS
) {
2554 bcopy(&catInfo
->nodeData
.cnd_datafork
.extents
, attrbufptr
, sizeof(extentrecord
));
2555 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2557 if (a
& ATTR_FILE_RSRCLENGTH
) {
2558 *((off_t
*)attrbufptr
)++ =
2559 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2561 if (a
& ATTR_FILE_RSRCALLOCSIZE
) {
2562 *((off_t
*)attrbufptr
)++ =
2563 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2565 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2566 bcopy(&catInfo
->nodeData
.cnd_rsrcfork
.extents
, attrbufptr
, sizeof(extentrecord
));
2567 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2571 *attrbufptrptr
= attrbufptr
;
2572 *varbufptrptr
= varbufptr
;
2576 void PackFileAttributeBlock(struct attrlist
*alist
,
2578 struct hfsCatalogInfo
*catInfo
,
2579 void **attrbufptrptr
,
2580 void **varbufptrptr
) {
2581 struct hfsnode
*hp
= VTOH(vp
);
2582 FCB
*fcb
= HTOFCB(hp
);
2583 ExtendedVCB
*vcb
= HTOVCB(hp
);
2584 Boolean isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
2585 void *attrbufptr
= *attrbufptrptr
;
2586 void *varbufptr
= *varbufptrptr
;
2587 attrgroup_t a
= alist
->fileattr
;
2592 if (a
& ATTR_FILE_LINKCOUNT
) {
2593 u_long linkcnt
= catInfo
->nodeData
.cnd_linkCount
;
2597 *((u_long
*)attrbufptr
)++ = linkcnt
;
2600 if (a
& ATTR_FILE_LINKCOUNT
) *((u_long
*)attrbufptr
)++ = 1;
2602 if (a
& ATTR_FILE_TOTALSIZE
) {
2603 *((off_t
*)attrbufptr
)++ =
2604 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
+
2605 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2607 if (a
& ATTR_FILE_ALLOCSIZE
) {
2608 switch (H_FORKTYPE(hp
)) {
2610 *((off_t
*)attrbufptr
)++ =
2611 (off_t
)fcb
->fcbPLen
+
2612 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2615 *((off_t
*)attrbufptr
)++ =
2616 (off_t
)fcb
->fcbPLen
+
2617 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2620 *((off_t
*)attrbufptr
)++ =
2621 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
) +
2622 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2625 if (a
& ATTR_FILE_IOBLOCKSIZE
) *((u_long
*)attrbufptr
)++ = GetLogicalBlockSize(vp
);
2626 if (a
& ATTR_FILE_CLUMPSIZE
) *((u_long
*)attrbufptr
)++ = fcb
->fcbClmpSize
;
2627 if (a
& ATTR_FILE_DEVTYPE
) {
2630 if ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))
2631 rawdev
= (u_long
)catInfo
->nodeData
.cnd_rawDevice
;
2634 *((u_long
*)attrbufptr
)++ = rawdev
;
2636 if (a
& ATTR_FILE_FILETYPE
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD */
2637 if (a
& ATTR_FILE_FORKCOUNT
) *((u_long
*)attrbufptr
)++ = 2; /* XXX PPD */
2638 if (a
& ATTR_FILE_FORKLIST
) {
2640 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2641 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2643 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2644 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2645 ++((struct attrreference
*)attrbufptr
);
2647 if (H_FORKTYPE(hp
) == kDataFork
) {
2648 if (a
& ATTR_FILE_DATALENGTH
)
2649 *((off_t
*)attrbufptr
)++ = fcb
->fcbEOF
;
2650 if (a
& ATTR_FILE_DATAALLOCSIZE
) *((off_t
*)attrbufptr
)++ = fcb
->fcbPLen
;
2651 if (a
& ATTR_FILE_DATAEXTENTS
) {
2652 bcopy ( fcb
->fcbExtents
, attrbufptr
, sizeof(extentrecord
));
2653 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2656 if (a
& ATTR_FILE_DATALENGTH
) {
2657 *((off_t
*)attrbufptr
)++ =
2658 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
;
2660 if (a
& ATTR_FILE_DATAALLOCSIZE
) {
2661 *((off_t
*)attrbufptr
)++ =
2662 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2664 if (a
& ATTR_FILE_DATAEXTENTS
) {
2665 bcopy(&catInfo
->nodeData
.cnd_datafork
.extents
, attrbufptr
, sizeof(extentrecord
));
2666 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2669 if (H_FORKTYPE(hp
) == kRsrcFork
) {
2670 if (a
& ATTR_FILE_RSRCLENGTH
)
2671 *((off_t
*)attrbufptr
)++ = fcb
->fcbEOF
;
2672 if (a
& ATTR_FILE_RSRCALLOCSIZE
) *((off_t
*)attrbufptr
)++ = fcb
->fcbPLen
;
2673 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2674 bcopy ( fcb
->fcbExtents
, attrbufptr
, sizeof(extentrecord
));
2675 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2678 if (a
& ATTR_FILE_RSRCLENGTH
) {
2679 *((off_t
*)attrbufptr
)++ =
2680 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2682 if (a
& ATTR_FILE_RSRCALLOCSIZE
) {
2683 *((off_t
*)attrbufptr
)++ =
2684 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2686 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2687 bcopy(&catInfo
->nodeData
.cnd_rsrcfork
.extents
, attrbufptr
, sizeof(extentrecord
));
2688 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2693 *attrbufptrptr
= attrbufptr
;
2694 *varbufptrptr
= varbufptr
;
2698 void PackForkAttributeBlock(struct attrlist
*alist
,
2700 struct hfsCatalogInfo
*catInfo
,
2701 void **attrbufptrptr
,
2702 void **varbufptrptr
) {
2708 // This routine takes catInfo, and alist, as inputs and packs it into an attribute block.
2709 void PackCatalogInfoAttributeBlock ( struct attrlist
*alist
, struct vnode
*root_vp
, struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2711 //XXX Preflight that alist only contains bits with fields in catInfo
2713 PackCommonCatalogInfoAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2715 switch ( catInfo
->nodeData
.cnd_type
)
2717 case kCatalogFolderNode
:
2718 PackCatalogInfoDirAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2721 case kCatalogFileNode
:
2722 PackCatalogInfoFileAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2725 default: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR not being handled... */
2726 /* XXX PPD - Panic? */
2733 void PackAttributeBlock(struct attrlist
*alist
,
2735 struct hfsCatalogInfo
*catInfo
,
2736 void **attrbufptrptr
,
2737 void **varbufptrptr
)
2739 if (alist
->volattr
!= 0) {
2740 DBG_ASSERT((vp
->v_flag
& VROOT
) != 0);
2741 PackVolumeInfo(alist
,vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2743 PackCommonAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2745 switch (vp
->v_type
) {
2747 PackDirAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2752 PackFileAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2755 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
2756 not being handled...
2759 /* XXX PPD - Panic? */
2767 void UnpackVolumeAttributeBlock(struct attrlist
*alist
,
2768 struct vnode
*root_vp
,
2770 void **attrbufptrptr
,
2771 void **varbufptrptr
) {
2772 void *attrbufptr
= *attrbufptrptr
;
2775 if ((alist
->commonattr
== 0) && (alist
->volattr
== 0)) {
2776 return; /* Get out without dirtying the VCB */
2781 a
= alist
->commonattr
;
2783 if (a
& ATTR_CMN_SCRIPT
) {
2784 vcb
->volumeNameEncodingHint
= (u_int32_t
)*(((text_encoding_t
*)attrbufptr
)++);
2786 a
&= ~ATTR_CMN_SCRIPT
;
2789 if (a
& ATTR_CMN_CRTIME
) {
2790 vcb
->localCreateDate
= UTCToLocal(to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
));
2791 ++((struct timespec
*)attrbufptr
);
2793 a
&= ~ATTR_CMN_CRTIME
;
2796 if (a
& ATTR_CMN_MODTIME
) {
2797 vcb
->vcbLsMod
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2798 ++((struct timespec
*)attrbufptr
);
2800 a
&= ~ATTR_CMN_MODTIME
;
2803 if (a
& ATTR_CMN_BKUPTIME
) {
2804 vcb
->vcbVolBkUp
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2805 ++((struct timespec
*)attrbufptr
);
2807 a
&= ~ATTR_CMN_BKUPTIME
;
2810 if (a
& ATTR_CMN_FNDRINFO
) {
2811 bcopy (attrbufptr
, &vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
2812 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
2814 a
&= ~ATTR_CMN_FNDRINFO
;
2818 DBG_ASSERT(a
== 0); /* All common attributes for volumes must've been handled by now... */
2820 a
= alist
->volattr
& ~ATTR_VOL_INFO
;
2821 if (a
& ATTR_VOL_NAME
) {
2822 copystr(((char *)attrbufptr
) + *((u_long
*)attrbufptr
), vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
2823 (char *)attrbufptr
+= sizeof(struct attrreference
);
2825 a
&= ~ATTR_VOL_NAME
;
2829 DBG_ASSERT(a
== 0); /* All common attributes for volumes must've been handled by now... */
2831 vcb
->vcbFlags
|= 0xFF00; // Mark the VCB dirty
2837 void UnpackCommonAttributeBlock(struct attrlist
*alist
,
2839 struct hfsCatalogInfo
*catInfo
,
2840 void **attrbufptrptr
,
2841 void **varbufptrptr
) {
2842 struct hfsnode
*hp
= VTOH(vp
);
2846 attrbufptr
= *attrbufptrptr
;
2848 DBG_ASSERT(catInfo
!= NULL
);
2850 a
= alist
->commonattr
;
2851 if (a
& ATTR_CMN_SCRIPT
) {
2852 catInfo
->nodeData
.cnd_textEncoding
= (u_int32_t
)*((text_encoding_t
*)attrbufptr
)++;
2854 a
&= ~ATTR_CMN_SCRIPT
;
2857 if (a
& ATTR_CMN_CRTIME
) {
2858 catInfo
->nodeData
.cnd_createDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2859 VTOH(vp
)->h_meta
->h_crtime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2860 ++((struct timespec
*)attrbufptr
);
2862 a
&= ~ATTR_CMN_CRTIME
;
2865 if (a
& ATTR_CMN_MODTIME
) {
2866 catInfo
->nodeData
.cnd_contentModDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2867 VTOH(vp
)->h_meta
->h_mtime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2868 ++((struct timespec
*)attrbufptr
);
2869 hp
->h_nodeflags
&= ~IN_UPDATE
;
2871 a
&= ~ATTR_CMN_MODTIME
;
2874 if (a
& ATTR_CMN_CHGTIME
) {
2875 catInfo
->nodeData
.cnd_attributeModDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2876 VTOH(vp
)->h_meta
->h_ctime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2877 ++((struct timespec
*)attrbufptr
);
2878 hp
->h_nodeflags
&= ~IN_CHANGE
;
2880 a
&= ~ATTR_CMN_CHGTIME
;
2883 if (a
& ATTR_CMN_ACCTIME
) {
2884 catInfo
->nodeData
.cnd_accessDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2885 VTOH(vp
)->h_meta
->h_atime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2886 ++((struct timespec
*)attrbufptr
);
2887 hp
->h_nodeflags
&= ~IN_ACCESS
;
2889 a
&= ~ATTR_CMN_ACCTIME
;
2892 if (a
& ATTR_CMN_BKUPTIME
) {
2893 catInfo
->nodeData
.cnd_backupDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2894 VTOH(vp
)->h_meta
->h_butime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2895 ++((struct timespec
*)attrbufptr
);
2897 a
&= ~ATTR_CMN_BKUPTIME
;
2900 if (a
& ATTR_CMN_FNDRINFO
) {
2901 bcopy (attrbufptr
, &catInfo
->nodeData
.cnd_finderInfo
, sizeof(catInfo
->nodeData
.cnd_finderInfo
));
2902 (char *)attrbufptr
+= sizeof(catInfo
->nodeData
.cnd_finderInfo
);
2904 a
&= ~ATTR_CMN_FNDRINFO
;
2907 if (a
& ATTR_CMN_OWNERID
) {
2908 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2909 u_int32_t uid
= (u_int32_t
)*((uid_t
*)attrbufptr
)++;
2910 if (uid
!= (uid_t
)VNOVAL
)
2911 hp
->h_meta
->h_uid
= uid
; /* catalog will get updated by hfs_chown() */
2914 ((uid_t
*)attrbufptr
)++;
2917 a
&= ~ATTR_CMN_OWNERID
;
2920 if (a
& ATTR_CMN_GRPID
) {
2921 u_int32_t gid
= (u_int32_t
)*((gid_t
*)attrbufptr
)++;
2922 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2923 if (gid
!= (gid_t
)VNOVAL
)
2924 hp
->h_meta
->h_gid
= gid
; /* catalog will get updated by hfs_chown() */
2927 a
&= ~ATTR_CMN_GRPID
;
2930 if (a
& ATTR_CMN_ACCESSMASK
) {
2931 u_int16_t mode
= (u_int16_t
)*((u_long
*)attrbufptr
)++;
2932 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2933 if (mode
!= (mode_t
)VNOVAL
) {
2934 hp
->h_meta
->h_mode
&= ~ALLPERMS
;
2935 hp
->h_meta
->h_mode
|= (mode
& ALLPERMS
); /* catalog will get updated by hfs_chmod() */
2939 a
&= ~ATTR_CMN_ACCESSMASK
;
2942 if (a
& ATTR_CMN_FLAGS
) {
2943 u_long flags
= *((u_long
*)attrbufptr
)++;
2944 /* Flags are settable only on HFS+ volumes. A special exception is made for the IMMUTABLE
2945 flags (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on HFS volumes as well: */
2946 if ((VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) ||
2947 ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) && ((flags
& ~IMMUTABLE
) == 0))) {
2948 if (flags
!= (u_long
)VNOVAL
) {
2949 hp
->h_meta
->h_pflags
= flags
; /* catalog will get updated by hfs_chflags */
2953 a
&= ~ATTR_CMN_FLAGS
;
2959 DEBUG_BREAK_MSG(("UnpackCommonAttributes: unhandled bit: 0x%08X\n", a
));
2963 *attrbufptrptr
= attrbufptr
;
2964 // *varbufptrptr = varbufptr;
2970 void UnpackDirAttributeBlock(struct attrlist
*alist
,
2972 struct hfsCatalogInfo
*catInfo
,
2973 void **attrbufptrptr
,
2974 void **varbufptrptr
) {
2980 attrbufptr
= *attrbufptrptr
;
2981 varbufptr
= *varbufptrptr
;
2985 *attrbufptrptr
= attrbufptr
;
2986 *varbufptrptr
= varbufptr
;
2993 void UnpackFileAttributeBlock(struct attrlist
*alist
,
2995 struct hfsCatalogInfo
*catInfo
,
2996 void **attrbufptrptr
,
2997 void **varbufptrptr
) {
3003 attrbufptr
= *attrbufptrptr
;
3004 varbufptr
= *varbufptrptr
;
3008 *attrbufptrptr
= attrbufptr
;
3009 *varbufptrptr
= varbufptr
;
3016 void UnpackForkAttributeBlock(struct attrlist
*alist
,
3018 struct hfsCatalogInfo
*catInfo
,
3019 void **attrbufptrptr
,
3020 void **varbufptrptr
) {
3026 attrbufptr
= *attrbufptrptr
;
3027 varbufptr
= *varbufptrptr
;
3031 *attrbufptrptr
= attrbufptr
;
3032 *varbufptrptr
= varbufptr
;
3038 void UnpackAttributeBlock(struct attrlist
*alist
,
3040 struct hfsCatalogInfo
*catInfo
,
3041 void **attrbufptrptr
,
3042 void **varbufptrptr
) {
3045 if (alist
->volattr
!= 0) {
3046 UnpackVolumeAttributeBlock(alist
, vp
, VTOVCB(vp
), attrbufptrptr
, varbufptrptr
);
3050 /* We're dealing with a vnode object here: */
3051 UnpackCommonAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3054 switch (vp
->v_type
) {
3056 UnpackDirAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3060 /* case VCPLX: */ /* XXX PPD TBC */
3061 UnpackFileAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3065 UnpackForkAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3068 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
3069 not being handled...
3072 /* XXX PPD - Panic? */
3080 unsigned long BestBlockSizeFit(unsigned long allocationBlockSize
,
3081 unsigned long blockSizeLimit
,
3082 unsigned long baseMultiple
) {
3084 Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the
3085 specified limit but still an even multiple of the baseMultiple.
3087 int baseBlockCount
, blockCount
;
3088 unsigned long trialBlockSize
;
3090 if (allocationBlockSize
% baseMultiple
!= 0) {
3092 Whoops: the allocation blocks aren't even multiples of the specified base:
3093 no amount of dividing them into even parts will be a multiple, either then!
3095 return 512; /* Hope for the best */
3098 /* Try the obvious winner first, to prevent 12K allocation blocks, for instance,
3099 from being handled as two 6K logical blocks instead of 3 4K logical blocks.
3100 Even though the former (the result of the loop below) is the larger allocation
3101 block size, the latter is more efficient: */
3102 if (allocationBlockSize
% PAGE_SIZE
== 0) return PAGE_SIZE
;
3104 /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */
3105 baseBlockCount
= allocationBlockSize
/ baseMultiple
; /* Now guaranteed to be an even multiple */
3107 for (blockCount
= baseBlockCount
; blockCount
> 0; --blockCount
) {
3108 trialBlockSize
= blockCount
* baseMultiple
;
3109 if (allocationBlockSize
% trialBlockSize
== 0) { /* An even multiple? */
3110 if ((trialBlockSize
<= blockSizeLimit
) &&
3111 (trialBlockSize
% baseMultiple
== 0)) {
3112 return trialBlockSize
;
3117 /* Note: we should never get here, since blockCount = 1 should always work,
3118 but this is nice and safe and makes the compiler happy, too ... */
3124 * To make the HFS Plus filesystem follow UFS unlink semantics, a remove
3125 * of an active vnode is translated to a move/rename so the file appears
3126 * deleted. The destination folder for these move/renames is setup here
3127 * and a reference to it is place in hfsmp->hfs_private_metadata_dir.
3130 FindMetaDataDirectory(ExtendedVCB
*vcb
)
3133 hfsCatalogInfo catInfo
;
3134 HFSCatalogNodeID dirID
;
3135 u_int32_t metadata_createdate
;
3138 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
3142 metadata_createdate
= 0;
3143 strncpy(namep
, HFSPLUSMETADATAFOLDER
, sizeof(namep
));
3144 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
3145 catInfo
.hint
= kNoHint
;
3147 /* lock catalog b-tree */
3148 retval
= hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_SHARED
, current_proc());
3149 if (retval
) goto Err_Exit
;
3151 if (hfs_getcatalog(vcb
, kRootDirID
, namep
, -1, &catInfo
) == 0) {
3152 dirID
= catInfo
.nodeData
.cnd_nodeID
;
3153 metadata_createdate
= catInfo
.nodeData
.cnd_createDate
;
3154 } else if (VCBTOHFS(vcb
)->hfs_fs_ronly
== 0) {
3155 if (CreateCatalogNode(vcb
, kRootDirID
, namep
, kCatalogFolderNode
, &dirID
, &catInfo
.hint
) == 0) {
3156 catInfo
.hint
= kNoHint
;
3157 if (hfs_getcatalog(vcb
, kRootDirID
, namep
, -1, &catInfo
) == 0) {
3159 /* create date is later used for validation */
3160 catInfo
.nodeData
.cnd_createDate
= vcb
->vcbCrDate
;
3161 metadata_createdate
= catInfo
.nodeData
.cnd_createDate
;
3163 /* directory with no permissions owned by root */
3164 catInfo
.nodeData
.cnd_mode
= IFDIR
;
3165 catInfo
.nodeData
.cnd_adminFlags
= (SF_IMMUTABLE
>> 16);
3167 /* hidden and off the desktop view */
3168 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frLocation
.v
= SWAP_BE16 (22460);
3169 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frLocation
.h
= SWAP_BE16 (22460);
3170 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frFlags
|= SWAP_BE16 (kIsInvisible
+ kNameLocked
);
3172 (void) UpdateCatalogNode(vcb
, kRootDirID
, namep
, catInfo
.hint
, &catInfo
.nodeData
);
3177 /* unlock catalog b-tree */
3178 (void) hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3180 VCBTOHFS(vcb
)->hfs_metadata_createdate
= metadata_createdate
;
3182 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3189 RemovedMetaDataDirectory(ExtendedVCB
*vcb
)
3192 hfsCatalogInfo catInfo
;
3195 strncpy(name
, HFSPLUSMETADATAFOLDER
, sizeof(name
));
3196 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
3198 /* lock catalog b-tree */
3199 retval
= hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_SHARED
, current_proc());
3200 if (retval
) goto Err_Exit
;
3202 /* If the HFSPLUSMETADATAFOLDER exists then delete it. */
3203 retval
= GetCatalogNode(vcb
, kRootDirID
, name
, strlen(name
), kNoHint
,
3204 &catInfo
.nodeData
, &catInfo
.hint
);
3205 if (retval
== 0 && (catInfo
.nodeData
.cnd_type
== kCatalogFolderNode
)) {
3206 (void) DeleteCatalogNode(vcb
, kRootDirID
, name
, catInfo
.hint
);
3207 printf("hfs_mount: removed \"%s\" from hfs volume \"%s\"\n", name
, vcb
->vcbVN
);
3210 /* unlock catalog b-tree */
3211 (void) hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3214 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3218 * This will return the correct logical block size for a given vnode.
3219 * For most files, it is the allocation block size, for meta data like
3220 * BTrees, this is kept as part of the BTree private nodeSize
3223 GetLogicalBlockSize(struct vnode
*vp
)
3225 u_int32_t logBlockSize
;
3227 DBG_ASSERT(vp
!= NULL
);
3229 if ((vp
->v_flag
& VSYSTEM
) && (VTOH(vp
)->fcbBTCBPtr
!=NULL
)) {
3230 BTreeInfoRec bTreeInfo
;
3234 * We do not lock the BTrees, because if we are getting block..then the tree
3235 * should be locked in the first place.
3236 * We just want the nodeSize wich will NEVER change..so even if the world
3237 * is changing..the nodeSize should remain the same. Which argues why lock
3238 * it in the first place??
3241 (void) BTGetInformation (VTOFCB(vp
), kBTreeInfoVersion
, &bTreeInfo
);
3243 logBlockSize
= bTreeInfo
.nodeSize
;
3246 logBlockSize
= VTOHFS(vp
)->hfs_logBlockSize
;
3249 DBG_ASSERT(logBlockSize
> 0);
3251 return logBlockSize
;
3255 * Map HFS Common errors (negative) to BSD error codes (positive).
3256 * Positive errors (ie BSD errors) are passed through unchanged.
3258 short MacToVFSError(OSErr err
)
3262 DBG_ERR(("MacToVFSError: passing error #%d unchanged...\n", err
));
3268 DBG_ERR(("MacToVFSError: mapping error code %d...\n", err
));
3272 case dirFulErr
: /* -33 */
3273 case dskFulErr
: /* -34 */
3274 case btNoSpaceAvail
: /* -32733 */
3275 case fxOvFlErr
: /* -32750 */
3276 return ENOSPC
; /* +28 */
3278 case btBadNode
: /* -32731 */
3279 case ioErr
: /* -36 */
3280 return EIO
; /* +5 */
3282 case mFulErr
: /* -41 */
3283 case memFullErr
: /* -108 */
3284 return ENOMEM
; /* +12 */
3286 case tmfoErr
: /* -42 */
3287 /* Consider EMFILE (Too many open files, 24)? */
3288 return ENFILE
; /* +23 */
3290 case nsvErr
: /* -35 */
3291 case fnfErr
: /* -43 */
3292 case dirNFErr
: /* -120 */
3293 case fidNotFound
: /* -1300 */
3294 return ENOENT
; /* +2 */
3296 case wPrErr
: /* -44 */
3297 case vLckdErr
: /* -46 */
3298 case fsDSIntErr
: /* -127 */
3299 return EROFS
; /* +30 */
3301 case opWrErr
: /* -49 */
3302 case fLckdErr
: /* -45 */
3303 return EACCES
; /* +13 */
3305 case permErr
: /* -54 */
3306 case wrPermErr
: /* -61 */
3307 return EPERM
; /* +1 */
3309 case fBsyErr
: /* -47 */
3310 return EBUSY
; /* +16 */
3312 case dupFNErr
: /* -48 */
3313 case fidExists
: /* -1301 */
3314 case cmExists
: /* -32718 */
3315 case btExists
: /* -32734 */
3316 return EEXIST
; /* +17 */
3318 case rfNumErr
: /* -51 */
3319 return EBADF
; /* +9 */
3321 case notAFileErr
: /* -1302 */
3322 return EISDIR
; /* +21 */
3324 case cmNotFound
: /* -32719 */
3325 case btNotFound
: /* -32735 */
3326 return ENOENT
; /* 28 */
3328 case cmNotEmpty
: /* -32717 */
3329 return ENOTEMPTY
; /* 66 */
3331 case cmFThdDirErr
: /* -32714 */
3332 return EISDIR
; /* 21 */
3334 case fxRangeErr
: /* -32751 */
3337 case bdNamErr
: /* -37 */
3338 return ENAMETOOLONG
; /* 63 */
3340 case fnOpnErr
: /* -38 */
3341 case eofErr
: /* -39 */
3342 case posErr
: /* -40 */
3343 case paramErr
: /* -50 */
3344 case badMDBErr
: /* -60 */
3345 case badMovErr
: /* -122 */
3346 case sameFileErr
: /* -1306 */
3347 case badFidErr
: /* -1307 */
3348 case fileBoundsErr
: /* -1309 */
3349 return EINVAL
; /* +22 */
3352 DBG_UTILS(("Unmapped MacOS error: %d\n", err
));
3353 return EIO
; /* +5 */
3359 * All of our debugging functions
3364 void debug_vn_status (char* introStr
, struct vnode
*vn
)
3366 DBG_VOP(("%s:\t",introStr
));
3369 if (vn
->v_tag
!= VT_HFS
)
3371 DBG_VOP(("NON-HFS VNODE Ox%08lX\n", (unsigned long)vn
));
3373 else if(vn
->v_tag
==VT_HFS
&& (vn
->v_data
==NULL
|| VTOH((vn
))->h_valid
!= HFS_VNODE_MAGIC
))
3375 DBG_VOP(("BAD VNODE PRIVATE DATA!!!!\n"));
3379 DBG_VOP(("r: %d & ", vn
->v_usecount
));
3380 if (lockstatus(&VTOH(vn
)->h_lock
))
3382 DBG_VOP_CONT(("is L\n"));
3386 DBG_VOP_CONT(("is U\n"));
3392 DBG_VOP(("vnode is NULL\n"));
3396 void debug_vn_print (char* introStr
, struct vnode
*vn
)
3398 // DBG_FUNC_NAME("DBG_VN_PRINT");
3399 DBG_ASSERT (vn
!= NULL
);
3400 DBG_VFS(("%s: ",introStr
));
3401 DBG_VFS_CONT(("vnode: 0x%x is a ", (uint
)vn
));
3405 DBG_VFS_CONT(("%s","UFS"));
3408 DBG_VFS_CONT(("%s","HFS"));
3411 DBG_VFS_CONT(("%s","UNKNOWN"));
3415 DBG_VFS_CONT((" vnode\n"));
3416 if (vn
->v_tag
==VT_HFS
)
3418 if (vn
->v_data
==NULL
)
3420 DBG_VFS(("BAD VNODE PRIVATE DATA!!!!\n"));
3424 DBG_VFS((" Name: %s Id: %ld ",H_NAME(VTOH(vn
)), H_FILEID(VTOH(vn
))));
3430 DBG_VFS_CONT(("Refcount: %d\n", vn
->v_usecount
));
3431 if (VOP_ISLOCKED(vn
))
3433 DBG_VFS((" The vnode is locked\n"));
3437 DBG_VFS((" The vnode is not locked\n"));
3441 void debug_rename_test_locks (char* introStr
,
3452 DBG_VOP(("\t%s: ", introStr
));
3453 if (fvp
) {if(lockstatus(&VTOH(fvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3454 if (fdvp
) {if(lockstatus(&VTOH(fdvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3455 if (tvp
) {if(lockstatus(&VTOH(tvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3456 if (tdvp
) {if(lockstatus(&VTOH(tdvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3457 DBG_VFS_CONT(("\n"));
3460 if (lockstatus(&VTOH(fvp
)->h_lock
)) {
3461 if (fstatus
==VOPDBG_UNLOCKED
) {
3462 DBG_VOP(("\tfvp should be NOT LOCKED and it is\n"));
3464 } else if (fstatus
== VOPDBG_LOCKED
) {
3465 DBG_VOP(("\tfvp should be LOCKED and it isnt\n"));
3470 if (lockstatus(&VTOH(fdvp
)->h_lock
)) {
3471 if (fdstatus
==VOPDBG_UNLOCKED
) {
3472 DBG_VOP(("\tfdvp should be NOT LOCKED and it is\n"));
3474 } else if (fdstatus
== VOPDBG_LOCKED
) {
3475 DBG_VOP(("\tfdvp should be LOCKED and it isnt\n"));
3480 if (lockstatus(&VTOH(tvp
)->h_lock
)) {
3481 if (tstatus
==VOPDBG_UNLOCKED
) {
3482 DBG_VOP(("\ttvp should be NOT LOCKED and it is\n"));
3484 } else if (tstatus
== VOPDBG_LOCKED
) {
3485 DBG_VOP(("\ttvp should be LOCKED and it isnt\n"));
3490 if (lockstatus(&VTOH(tdvp
)->h_lock
)) {
3491 if (tdstatus
==VOPDBG_UNLOCKED
) {
3492 DBG_VOP(("\ttdvp should be NOT LOCKED and it is\n"));
3494 } else if (tdstatus
== VOPDBG_LOCKED
) {
3495 DBG_VOP(("\ttdvp should be LOCKED and it isnt\n"));
3501 #endif /* HFS_DIAGNOSTIC */
3505 void debug_check_buffersizes(struct vnode
*vp
, struct hfsnode
*hp
, struct buf
*bp
) {
3506 DBG_ASSERT(bp
->b_validoff
== 0);
3507 DBG_ASSERT(bp
->b_dirtyoff
== 0);
3508 DBG_ASSERT((bp
->b_bcount
== HTOHFS(hp
)->hfs_logBlockSize
) ||
3509 ((bp
->b_bcount
% 512 == 0) &&
3510 (bp
->b_validend
> 0) &&
3511 (bp
->b_dirtyend
> 0) &&
3512 (bp
->b_bcount
< HTOHFS(hp
)->hfs_logBlockSize
)));
3514 if (bp
->b_validend
== 0) {
3515 DBG_ASSERT(bp
->b_dirtyend
== 0);
3517 DBG_ASSERT(bp
->b_validend
== bp
->b_bcount
);
3518 DBG_ASSERT(bp
->b_dirtyend
<= bp
->b_bcount
);
3523 void debug_check_blocksizes(struct vnode
*vp
) {
3524 struct hfsnode
*hp
= VTOH(vp
);
3527 if (vp
->v_flag
& VSYSTEM
) return;
3529 for (bp
= vp
->v_cleanblkhd
.lh_first
; bp
!= NULL
; bp
= bp
->b_vnbufs
.le_next
) {
3530 debug_check_buffersizes(vp
, hp
, bp
);
3533 for (bp
= vp
->v_dirtyblkhd
.lh_first
; bp
!= NULL
; bp
= bp
->b_vnbufs
.le_next
) {
3534 debug_check_buffersizes(vp
, hp
, bp
);
3538 void debug_check_catalogdata(struct CatalogNodeData
*cat
) {
3540 if (cat
->cnm_nameptr
== NULL
) {
3541 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3543 else if (cat
->cnm_nameptr
== cat
->cnm_namespace
) {
3544 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3547 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == kCatNameIsAllocated
);
3550 if (cat
->cnm_nameptr
) {
3551 DBG_ASSERT(strlen(cat
->cnm_nameptr
) == cat
->cnm_length
);
3554 if (cat
->cnm_flags
& kCatNameIsConsumed
) {
3555 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3558 if (cat
->cnm_flags
& kCatNameNoCopyName
) {
3559 DBG_ASSERT((cat
->cnm_flags
& (kCatNameIsAllocated
|kCatNameIsConsumed
|kCatNameIsMangled
)) == 0);
3560 DBG_ASSERT(cat
->cnm_length
== 0);
3561 DBG_ASSERT(cat
->cnm_nameptr
== 0);
3562 DBG_ASSERT(strlen(cat
->cnm_namespace
) == 0);
3567 extern void hfs_vhash_dbg(struct hfsnode
*hp
);
3569 /* Checks the valicity of a hfs vnode */
3570 void debug_check_vnode(struct vnode
*vp
, int stage
) {
3576 if (VTOHFS(vp
)->hfs_mount_flags
& kHFSBootVolumeInconsistentMask
)
3577 DEBUG_BREAK_MSG(("Volume is damaged!"));
3581 DEBUG_BREAK_MSG(("Null vnode"));
3582 if (vp
->v_tag
!= VT_HFS
)
3583 DEBUG_BREAK_MSG(("Not a HFS vnode, it is a %d", vp
->v_tag
));
3584 if (vp
->v_data
==NULL
)
3585 DEBUG_BREAK_MSG(("v_data is NULL"));
3589 if (hp
->h_valid
!= HFS_VNODE_MAGIC
)
3590 DEBUG_BREAK_MSG(("Bad Formed HFS node"));
3591 if (hp
->h_vp
==NULL
|| hp
->h_vp
!=vp
)
3592 DEBUG_BREAK_MSG(("Bad hfsnode vnode pte"));
3593 if (hp
->h_meta
== NULL
)
3594 DEBUG_BREAK_MSG(("Bad hfsnode meta ptr"));
3595 switch (H_FORKTYPE(hp
)) {
3598 if ((hp
->h_meta
->h_siblinghead
.cqh_first
== NULL
) || (hp
->h_meta
->h_siblinghead
.cqh_last
== NULL
))
3599 DEBUG_BREAK_MSG(("Null sibling header"));
3600 if ((hp
->h_sibling
.cqe_next
==NULL
) || (hp
->h_sibling
.cqe_prev
==NULL
))
3601 DEBUG_BREAK_MSG(("Null sibling list"));
3602 if (hp
->h_meta
->h_usecount
<1 || hp
->h_meta
->h_usecount
>2)
3603 DEBUG_BREAK_MSG(("Bad sibling usecount"));
3607 if ((hp
->h_meta
->h_siblinghead
.cqh_first
!= NULL
) || (hp
->h_meta
->h_siblinghead
.cqh_last
!= NULL
))
3608 DEBUG_BREAK_MSG(("Non Null sibling header"));
3609 if ((hp
->h_sibling
.cqe_next
!=NULL
) || (hp
->h_sibling
.cqe_prev
!=NULL
))
3610 DEBUG_BREAK_MSG(("Null sibling list"));
3611 if (hp
->h_meta
->h_usecount
!=1)
3612 DEBUG_BREAK_MSG(("Bad usecount"));
3616 DEBUG_BREAK_MSG(("Bad hfsnode fork type"));
3620 if (hp
->h_meta
->h_devvp
== NULL
)
3621 DEBUG_BREAK_MSG(("Bad hfsnode dev vnode"));
3623 DEBUG_BREAK_MSG(("Bad dev id"));
3624 if (H_FILEID(hp
) == 0)
3625 DEBUG_BREAK_MSG(("Bad file id"));
3627 if (((hp
->h_meta
->h_metaflags
& IN_DATANODE
)==0) && (H_DIRID(hp
) == 0) && (H_FILEID(hp
) != 1))
3628 DEBUG_BREAK_MSG(("Bad dir id"));
3630 if (hp
->h_meta
->h_namePtr
== NULL
&& hp
->h_meta
->h_namelen
!=0)
3631 DEBUG_BREAK_MSG(("hfs meta h_namelen is not 0"));
3632 if (hp
->h_meta
->h_namePtr
!= NULL
&& strlen(hp
->h_meta
->h_namePtr
) != hp
->h_meta
->h_namelen
)
3633 DEBUG_BREAK_MSG(("Bad hfs meta h_namelen"));
3635 /* Check the hash */
3638 /* Check to see if we want to compare with the disk */
3641 hfsCatalogInfo catInfo
;
3643 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
3646 if (hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_SHARED
, current_proc()))
3649 if (hfs_getcatalog(VTOVCB(vp
), H_DIRID(hp
), hp
->h_meta
->h_namePtr
, hp
->h_meta
->h_namelen
, &catInfo
))
3650 DEBUG_BREAK_MSG(("Could not find hfsnode Catalog record"));
3652 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3654 if (H_FILEID(hp
) != catInfo
.nodeData
.cnd_nodeID
)
3655 DEBUG_BREAK_MSG(("hfsnode catalog node id mismatch"));
3656 if (H_DIRID(hp
) != catInfo
.nodeData
.cnm_parID
)
3657 DEBUG_BREAK_MSG(("hfsnode catalog dir id mismatch"));
3658 if (strcmp(hp
->h_meta
->h_namePtr
, catInfo
.nodeData
.cnm_nameptr
) != 0)
3659 DEBUG_BREAK_MSG(("hfsnode catalog name mismatch"));
3660 /* Check dates too??? */
3662 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3669 for(i
= 0, size
= 0; i
< kHFSPlusExtentDensity
; i
++)
3671 size
+= hp
->fcbExtents
[i
].blockCount
;
3674 if (hp
->fcbEOF
> hp
->fcbPLen
)
3675 DEBUG_BREAK_MSG(("fcbPLen is smaller than fcbEOF"));
3677 if (hp
->fcbExtents
[kHFSPlusExtentDensity
-1].blockCount
== 0) {
3678 if ((off_t
)size
* (off_t
)VTOVCB(vp
)->blockSize
!= hp
->fcbPLen
)
3679 DEBUG_BREAK_MSG(("fcbPLen does not match extents"));
3681 if ( hp
->fcbPLen
< (off_t
)size
* (off_t
)VTOVCB(vp
)->blockSize
)
3682 DEBUG_BREAK_MSG(("fcbPLen is smaller than extents"));
3684 for(i
= 0; i
< kHFSPlusExtentDensity
; i
++)
3686 if (hp
->fcbExtents
[i
].blockCount
== 0 || hp
->fcbExtents
[i
].startBlock
== 0)
3689 if ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) && i
> kHFSExtentDensity
)
3690 DEBUG_BREAK_MSG(("Illegal value in extents for ordinary HFS"));
3691 if (i
> kHFSPlusExtentDensity
) {
3692 for(; i
< kHFSPlusExtentDensity
; i
++)
3694 if (hp
->fcbExtents
[i
].blockCount
!= 0 || hp
->fcbExtents
[i
].startBlock
!= 0)
3695 DEBUG_BREAK_MSG(("Illegal value in extents"));
3702 if (0 && vp
->v_flag
& VSYSTEM
) {
3705 BTGetInformation(hp
, 0, &info
);
3706 if (hp
->fcbBTCBPtr
== NULL
)
3707 DEBUG_BREAK_MSG(("Null fcbBTCBPtr"));
3708 if (H_HINT(hp
) == 0)
3709 DEBUG_BREAK_MSG(("hint is 0"));
3710 if (H_HINT(hp
) > info
.numNodes
)
3711 DEBUG_BREAK_MSG(("hint > numNodes"));
3716 #endif /* HFS_DIAGNOSTIC */