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 extern int (**hfs_vnodeop_p
)(void *);
137 extern int (**hfs_specop_p
)(void *);
138 extern int (**hfs_fifoop_p
)(void *);
139 extern int count_lock_queue
__P((void));
140 extern uid_t console_user
;
142 OSErr
ValidMasterDirectoryBlock( HFSMasterDirectoryBlock
*mdb
);
144 /* Externs from vhash */
145 extern void hfs_vhashins_sibling(dev_t dev
, UInt32 nodeID
, struct hfsnode
*hp
, struct hfsfilemeta
**fm
);
146 extern void hfs_vhashins(dev_t dev
, UInt32 nodeID
,struct hfsnode
*hp
);
147 extern struct vnode
*hfs_vhashget(dev_t dev
, UInt32 nodeID
, UInt8 forkType
);
149 extern int hfs_vinit( struct mount
*mntp
, int (**specops
)(void *), int (**fifoops
)(), struct vnode
**vpp
);
151 extern OSErr
GetVolumeNameFromCatalog(ExtendedVCB
*vcb
);
153 static int InitMetaFileVNode(struct vnode
*vp
, off_t eof
, u_long clumpSize
, const HFSPlusExtentRecord extents
,
154 HFSCatalogNodeID fileID
, void * keyCompareProc
);
156 static void ReleaseMetaFileVNode(struct vnode
*vp
);
158 static void RemovedMetaDataDirectory(ExtendedVCB
*vcb
);
160 void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
);
161 void CopyCatalogToFCB(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
);
162 void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
);
163 u_int32_t
GetLogicalBlockSize(struct vnode
*vp
);
165 /* BTree accessor routines */
166 extern OSStatus
GetBTreeBlock(FileReference vp
, UInt32 blockNum
, GetBlockOptions options
, BlockDescriptor
*block
);
167 extern OSStatus
SetBTreeBlockSize(FileReference vp
, ByteCount blockSize
, ItemCount minBlockCount
);
168 extern OSStatus
ExtendBTreeFile(FileReference vp
, FSSize minEOF
, FSSize maxEOF
);
169 extern OSStatus
ReleaseBTreeBlock(FileReference vp
, BlockDescPtr blockPtr
, ReleaseBlockOptions options
);
171 //*******************************************************************************
172 // Note: Finder information in the HFS/HFS+ metadata are considered opaque and
173 // hence are not in the right byte order on little endian machines. It is
174 // the responsibility of the finder and other clients to swap the data.
175 //*******************************************************************************
177 //*******************************************************************************
178 // Routine: hfs_MountHFSVolume
181 //*******************************************************************************
183 OSErr
hfs_MountHFSVolume(struct hfsmount
*hfsmp
, HFSMasterDirectoryBlock
*mdb
,
184 u_long sectors
, struct proc
*p
)
186 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
187 struct vnode
*tmpvnode
;
189 HFSPlusExtentRecord extents
;
191 DBG_FUNC_NAME("hfs_MountHFSVolume");
192 DBG_PRINT_FUNC_NAME();
194 if (hfsmp
== nil
|| mdb
== nil
) /* exit if bad paramater */
197 err
= ValidMasterDirectoryBlock( mdb
); /* make sure this is an HFS disk */
199 return MacToVFSError(err
);
201 /* don't mount a writeable volume if its dirty, it must be cleaned by fsck_hfs */
202 if ((hfsmp
->hfs_fs_ronly
== 0) && ((SWAP_BE16 (mdb
->drAtrb
) & kHFSVolumeUnmountedMask
) == 0))
206 * The MDB seems OK: transfer info from it into VCB
207 * Note - the VCB starts out clear (all zeros)
210 vcb
->vcbVRefNum
= MAKE_VREFNUM(hfsmp
->hfs_raw_dev
);
212 vcb
->vcbSigWord
= SWAP_BE16 (mdb
->drSigWord
);
213 vcb
->vcbCrDate
= LocalToUTC (SWAP_BE32 (mdb
->drCrDate
));
214 vcb
->localCreateDate
= SWAP_BE32 (mdb
->drCrDate
);
215 vcb
->vcbLsMod
= LocalToUTC (SWAP_BE32 (mdb
->drLsMod
));
216 vcb
->vcbAtrb
= SWAP_BE16 (mdb
->drAtrb
);
217 vcb
->vcbNmFls
= SWAP_BE16 (mdb
->drNmFls
);
218 vcb
->vcbVBMSt
= SWAP_BE16 (mdb
->drVBMSt
);
219 vcb
->nextAllocation
= SWAP_BE16 (mdb
->drAllocPtr
);
220 vcb
->totalBlocks
= SWAP_BE16 (mdb
->drNmAlBlks
);
221 vcb
->blockSize
= SWAP_BE32 (mdb
->drAlBlkSiz
);
222 vcb
->vcbClpSiz
= SWAP_BE32 (mdb
->drClpSiz
);
223 vcb
->vcbAlBlSt
= SWAP_BE16 (mdb
->drAlBlSt
);
224 vcb
->vcbNxtCNID
= SWAP_BE32 (mdb
->drNxtCNID
);
225 vcb
->freeBlocks
= SWAP_BE16 (mdb
->drFreeBks
);
226 vcb
->vcbVolBkUp
= LocalToUTC (SWAP_BE32 (mdb
->drVolBkUp
));
227 vcb
->vcbWrCnt
= SWAP_BE32 (mdb
->drWrCnt
);
228 vcb
->vcbNmRtDirs
= SWAP_BE16 (mdb
->drNmRtDirs
);
229 vcb
->vcbFilCnt
= SWAP_BE32 (mdb
->drFilCnt
);
230 vcb
->vcbDirCnt
= SWAP_BE32 (mdb
->drDirCnt
);
231 bcopy(mdb
->drFndrInfo
, vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
232 vcb
->nextAllocation
= SWAP_BE16 ( mdb
->drAllocPtr
); /* Duplicate?!?!?! */
233 vcb
->encodingsBitmap
= 0;
234 vcb
->vcbWrCnt
++; /* Compensate for write of MDB on last flush */
236 * Copy the drVN field, which is a Pascal String to the vcb, which is a cstring
239 /* convert hfs encoded name into UTF-8 string */
240 err
= hfs_to_utf8(vcb
, mdb
->drVN
, NAME_MAX
, &utf8chars
, vcb
->vcbVN
);
242 * When an HFS name cannot be encoded with the current
243 * volume encoding we use MacRoman as a fallback.
245 if (err
|| (utf8chars
== 0))
246 (void) mac_roman_to_utf8(mdb
->drVN
, NAME_MAX
, &utf8chars
, vcb
->vcbVN
);
248 vcb
->altIDSector
= sectors
- 2;
250 // Initialize our dirID/nodePtr cache associated with this volume.
251 err
= InitMRUCache( sizeof(UInt32
), kDefaultNumMRUCacheBlocks
, &(vcb
->hintCachePtr
) );
252 ReturnIfError( err
);
254 hfsmp
->hfs_logBlockSize
= BestBlockSizeFit(vcb
->blockSize
, MAXBSIZE
, hfsmp
->hfs_phys_block_size
);
255 vcb
->vcbVBMIOSize
= kHFSBlockSize
;
257 // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
261 * Set up Extents B-tree vnode...
263 err
= GetInitializedVNode(hfsmp
, &tmpvnode
);
264 if (err
) goto MtVolErr
;
265 /* HFSToHFSPlusExtents(mdb->drXTExtRec, extents); */ /* ASDFADSFSD */
266 extents
[0].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[0].startBlock
);
267 extents
[0].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[0].blockCount
);
268 extents
[1].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[1].startBlock
);
269 extents
[1].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[1].blockCount
);
270 extents
[2].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[2].startBlock
);
271 extents
[2].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[2].blockCount
);
273 err
= InitMetaFileVNode(tmpvnode
, SWAP_BE32 (mdb
->drXTFlSize
), SWAP_BE32 (mdb
->drXTClpSiz
), extents
,
274 kHFSExtentsFileID
, CompareExtentKeys
);
275 if (err
) goto MtVolErr
;
278 * Set up Catalog B-tree vnode...
280 err
= GetInitializedVNode(hfsmp
, &tmpvnode
);
281 if (err
) goto MtVolErr
;
282 /* HFSToHFSPlusExtents(mdb->drCTExtRec, extents); */
283 extents
[0].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[0].startBlock
);
284 extents
[0].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[0].blockCount
);
285 extents
[1].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[1].startBlock
);
286 extents
[1].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[1].blockCount
);
287 extents
[2].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[2].startBlock
);
288 extents
[2].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[2].blockCount
);
290 err
= InitMetaFileVNode(tmpvnode
, SWAP_BE32 (mdb
->drCTFlSize
), SWAP_BE32 (mdb
->drCTClpSiz
), extents
,
291 kHFSCatalogFileID
, CompareCatalogKeys
);
292 if (err
) goto MtVolErr
;
294 /* mark the volume dirty (clear clean unmount bit) */
295 vcb
->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
297 /* Remove any MetaDataDirectory from hfs disks */
298 if (hfsmp
->hfs_fs_ronly
== 0)
299 RemovedMetaDataDirectory(vcb
);
302 * all done with b-trees so we can unlock now...
304 VOP_UNLOCK(vcb
->catalogRefNum
, 0, p
);
305 VOP_UNLOCK(vcb
->extentsRefNum
, 0, p
);
311 if ( !(vcb
->vcbAtrb
& kHFSVolumeHardwareLockMask
) ) // if the disk is not write protected
313 MarkVCBDirty( vcb
); // mark VCB dirty so it will be written
318 //-- Release any resources allocated so far before exiting with an error:
320 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
321 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
327 //*******************************************************************************
328 // Routine: hfs_MountHFSPlusVolume
331 //*******************************************************************************
333 OSErr
hfs_MountHFSPlusVolume(struct hfsmount
*hfsmp
, HFSPlusVolumeHeader
*vhp
,
334 u_long embBlkOffset
, u_long sectors
, struct proc
*p
)
336 register ExtendedVCB
*vcb
;
337 HFSPlusForkData
*fdp
;
338 struct vnode
*tmpvnode
;
341 if (hfsmp
== nil
|| vhp
== nil
) /* exit if bad paramater */
344 DBG_VFS(("hfs_MountHFSPlusVolume: signature=0x%x, version=%d, blockSize=%ld\n",
345 SWAP_BE16 (vhp
->signature
),
346 SWAP_BE16 (vhp
->version
),
347 SWAP_BE32 (vhp
->blockSize
)));
349 retval
= ValidVolumeHeader(vhp
); /* make sure this is an HFS Plus disk */
351 return MacToVFSError(retval
);
353 /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */
354 if (hfsmp
->hfs_fs_ronly
== 0 && (SWAP_BE32 (vhp
->attributes
) & kHFSVolumeUnmountedMask
) == 0)
357 * The VolumeHeader seems OK: transfer info from it into VCB
358 * Note - the VCB starts out clear (all zeros)
360 vcb
= HFSTOVCB(hfsmp
);
362 //DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0);
363 vcb
->vcbVRefNum
= MAKE_VREFNUM(hfsmp
->hfs_raw_dev
);
364 vcb
->vcbSigWord
= SWAP_BE16 (vhp
->signature
);
365 vcb
->vcbLsMod
= SWAP_BE32 (vhp
->modifyDate
);
366 vcb
->vcbAtrb
= (UInt16
) SWAP_BE32 (vhp
->attributes
); // VCB only uses lower 16 bits
367 vcb
->vcbClpSiz
= SWAP_BE32 (vhp
->rsrcClumpSize
);
368 vcb
->vcbNxtCNID
= SWAP_BE32 (vhp
->nextCatalogID
);
369 vcb
->vcbVolBkUp
= SWAP_BE32 (vhp
->backupDate
);
370 vcb
->vcbWrCnt
= SWAP_BE32 (vhp
->writeCount
);
371 vcb
->vcbFilCnt
= SWAP_BE32 (vhp
->fileCount
);
372 vcb
->vcbDirCnt
= SWAP_BE32 (vhp
->folderCount
);
374 /* copy 32 bytes of Finder info */
375 bcopy(vhp
->finderInfo
, vcb
->vcbFndrInfo
, sizeof(vhp
->finderInfo
));
377 vcb
->vcbAlBlSt
= 0; /* hfs+ allocation blocks start at first block of volume */
378 vcb
->vcbWrCnt
++; /* compensate for write of Volume Header on last flush */
382 /* Now fill in the Extended VCB info */
383 vcb
->nextAllocation
= SWAP_BE32 (vhp
->nextAllocation
);
384 vcb
->totalBlocks
= SWAP_BE32 (vhp
->totalBlocks
);
385 vcb
->freeBlocks
= SWAP_BE32 (vhp
->freeBlocks
);
386 vcb
->blockSize
= SWAP_BE32 (vhp
->blockSize
);
387 vcb
->checkedDate
= SWAP_BE32 (vhp
->checkedDate
);
388 vcb
->encodingsBitmap
= SWAP_BE64 (vhp
->encodingsBitmap
);
390 vcb
->hfsPlusIOPosOffset
= embBlkOffset
* 512;
392 vcb
->altIDSector
= embBlkOffset
+ sectors
- 2;
394 vcb
->localCreateDate
= SWAP_BE32 (vhp
->createDate
); /* in local time, not GMT! */
396 /* Update the logical block size in the mount struct (currently set up from the wrapper MDB)
397 using the new blocksize value: */
398 hfsmp
->hfs_logBlockSize
= BestBlockSizeFit(vcb
->blockSize
, MAXBSIZE
, hfsmp
->hfs_phys_block_size
);
399 vcb
->vcbVBMIOSize
= min(vcb
->blockSize
, MAXPHYSIO
);
401 // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
402 // vcb->vcbAtrb |= kVolumeHardwareLockMask; // XXX this line for debugging only!!!!
404 // Initialize our dirID/nodePtr cache associated with this volume.
405 retval
= InitMRUCache( sizeof(UInt32
), kDefaultNumMRUCacheBlocks
, &(vcb
->hintCachePtr
) );
406 if (retval
!= noErr
) goto ErrorExit
;
409 * Set up Extents B-tree vnode...
411 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
);
412 if (retval
) goto ErrorExit
;
413 fdp
= &vhp
->extentsFile
;
414 SWAP_HFS_PLUS_FORK_DATA (fdp
);
415 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
416 kHFSExtentsFileID
, CompareExtentKeysPlus
);
417 SWAP_HFS_PLUS_FORK_DATA (fdp
);
418 if (retval
) goto ErrorExit
;
421 * Set up Catalog B-tree vnode...
423 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
);
424 if (retval
) goto ErrorExit
;
425 fdp
= &vhp
->catalogFile
;
426 SWAP_HFS_PLUS_FORK_DATA (fdp
);
427 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
428 kHFSCatalogFileID
, CompareExtendedCatalogKeys
);
429 SWAP_HFS_PLUS_FORK_DATA (fdp
);
430 if (retval
) goto ErrorExit
;
433 * Set up Allocation file vnode...
435 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
);
436 if (retval
) goto ErrorExit
;
437 fdp
= &vhp
->allocationFile
;
438 SWAP_HFS_PLUS_FORK_DATA (fdp
);
439 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
440 kHFSAllocationFileID
, NULL
);
441 SWAP_HFS_PLUS_FORK_DATA (fdp
);
442 if (retval
) goto ErrorExit
;
445 * Now that Catalog file is open get the volume name from the catalog
447 retval
= MacToVFSError( GetVolumeNameFromCatalog(vcb
) );
448 if (retval
!= noErr
) goto ErrorExit
;
450 /* mark the volume dirty (clear clean unmount bit) */
451 vcb
->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
453 /* setup private/hidden directory for unlinked files */
454 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(vcb
);
457 * all done with metadata files so we can unlock now...
459 VOP_UNLOCK(vcb
->allocationsRefNum
, 0, p
);
460 VOP_UNLOCK(vcb
->catalogRefNum
, 0, p
);
461 VOP_UNLOCK(vcb
->extentsRefNum
, 0, p
);
463 if ( !(vcb
->vcbAtrb
& kHFSVolumeHardwareLockMask
) ) // if the disk is not write protected
465 MarkVCBDirty( vcb
); // mark VCB dirty so it will be written
468 DBG_VFS(("hfs_MountHFSPlusVolume: returning (%d)\n", retval
));
475 * A fatal error occured and the volume cannot be mounted
476 * release any resources that we aquired...
479 DBG_VFS(("hfs_MountHFSPlusVolume: fatal error (%d)\n", retval
));
481 InvalidateCatalogCache(vcb
);
483 ReleaseMetaFileVNode(vcb
->allocationsRefNum
);
484 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
485 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
492 * ReleaseMetaFileVNode
496 static void ReleaseMetaFileVNode(struct vnode
*vp
)
500 FCB
*fcb
= VTOFCB(vp
);
502 if (fcb
->fcbBTCBPtr
!= NULL
)
503 (void) BTClosePath(fcb
); /* ignore errors since there is only one path open */
505 /* release the node even if BTClosePath fails */
506 if (VOP_ISLOCKED(vp
))
519 static int InitMetaFileVNode(struct vnode
*vp
, off_t eof
, u_long clumpSize
, const HFSPlusExtentRecord extents
,
520 HFSCatalogNodeID fileID
, void * keyCompareProc
)
526 DBG_ASSERT(vp
!= NULL
);
527 DBG_ASSERT(vp
->v_data
!= NULL
);
534 case kHFSExtentsFileID
:
535 vcb
->extentsRefNum
= vp
;
538 case kHFSCatalogFileID
:
539 vcb
->catalogRefNum
= vp
;
542 case kHFSAllocationFileID
:
543 vcb
->allocationsRefNum
= vp
;
547 panic("InitMetaFileVNode: invalid fileID!");
552 fcb
->fcbClmpSize
= clumpSize
;
553 H_FILEID(VTOH(vp
)) = fileID
;
554 H_DIRID(VTOH(vp
)) = kHFSRootParentID
;
555 H_FORKTYPE(VTOH(vp
)) = kSysFile
;
557 bcopy(extents
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
560 * Lock the hfsnode and insert the hfsnode into the hash queue:
562 hfs_vhashins(H_DEV(VTOH(vp
)), fileID
, VTOH(vp
));
563 vp
->v_flag
|= VSYSTEM
; /* tag our metadata files (used by vflush call) */
565 /* As the vnode is a system vnode we don't need UBC */
566 if(UBCINFOEXISTS(vp
)) {
567 /* So something is wrong if the it exists */
568 panic("ubc exists for system vnode");
571 if (keyCompareProc
!= NULL
) {
572 result
= BTOpenPath(fcb
,
573 (KeyCompareProcPtr
) keyCompareProc
,
578 result
= MacToVFSError(result
);
585 /*************************************************************
587 * Unmounts a hfs volume.
588 * At this point vflush() has been called (to dump all non-metadata files)
590 *************************************************************/
592 short hfsUnmount( register struct hfsmount
*hfsmp
, struct proc
*p
)
594 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
597 (void) DisposeMRUCache(vcb
->hintCachePtr
);
598 InvalidateCatalogCache( vcb
);
599 // XXX PPD: Should dispose of any allocated volume cache here: call DisposeVolumeCacheBlocks( vcb )?
601 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_EXCLUSIVE
, p
);
602 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
, p
);
604 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
605 ReleaseMetaFileVNode(vcb
->allocationsRefNum
);
607 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
608 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
615 * hfs_resolvelink - auto resolve HFS+ hardlinks
617 * Used after calling GetCatalogNode or GetCatalogOffspring
619 void hfs_resolvelink(ExtendedVCB
*vcb
, CatalogNodeData
*cndp
)
627 fip
= (struct FInfo
*) &cndp
->cnd_finderInfo
;
630 * if this is an indirect link (hardlink) then auto resolve it...
632 if ((vcb
->vcbSigWord
== kHFSPlusSigWord
)
633 && (cndp
->cnd_type
== kCatalogFileNode
)
634 && (fip
->fdType
== kHardLinkFileType
)
635 && (fip
->fdCreator
== kHFSPlusCreator
)
636 && ((cndp
->cnd_createDate
== vcb
->vcbCrDate
) ||
637 (cndp
->cnd_createDate
== VCBTOHFS(vcb
)->hfs_metadata_createdate
))) {
639 indlinkno
= cndp
->cnd_iNodeNum
;
640 MAKE_INODE_NAME(iNodeName
, indlinkno
);
642 * Get nodeData from the data node file.
643 * Flag the node data to NOT copy the name (ie preserve the original)
645 cndp
->cnm_flags
|= kCatNameNoCopyName
;
646 result
= GetCatalogNode(vcb
, VCBTOHFS(vcb
)->hfs_private_metadata_dir
,
647 iNodeName
, 0, 0, cndp
, &hint
);
648 cndp
->cnm_flags
&= ~kCatNameNoCopyName
;
650 /* Make sure there's a reference */
652 if (cndp
->cnd_linkCount
== 0) cndp
->cnd_linkCount
= 2;
654 /* Keep a copy of iNodeNum to put into h_indnodeno */
655 cndp
->cnd_iNodeNumCopy
= indlinkno
;
662 * Performs a lookup on the given dirID, name. Returns the catalog info
664 * If len is -1, then it is a null terminated string, pass it along to MacOS as kUndefinedStrLen
667 short hfs_getcatalog (ExtendedVCB
*vcb
, UInt32 parentDirID
, char *name
, short len
, hfsCatalogInfo
*catInfo
)
672 if (len
== -1 ) { /* Convert it to MacOS terms */
674 length
= strlen(name
);
676 length
= kUndefinedStrLen
;
681 result
= GetCatalogNode(vcb
, parentDirID
, name
, length
, catInfo
->hint
, &catInfo
->nodeData
, &catInfo
->hint
);
684 if (catInfo
->nodeData
.cnm_nameptr
) {
685 DBG_ASSERT(strlen(catInfo
->nodeData
.cnm_nameptr
) == catInfo
->nodeData
.cnm_length
);
690 hfs_resolvelink(vcb
, &catInfo
->nodeData
);
692 return MacToVFSError(result
);
697 short hfsDelete (ExtendedVCB
*vcb
, UInt32 parentDirID
, StringPtr name
, short isfile
, UInt32 catalogHint
)
699 OSErr result
= noErr
;
701 /* XXX have all the file's blocks been flushed/trashed? */
704 * DeleteFile will delete the catalog node and then
705 * free up any disk space used by the file.
708 result
= DeleteFile(vcb
, parentDirID
, name
, catalogHint
);
709 else /* is a directory */
710 result
= DeleteCatalogNode(vcb
, parentDirID
, name
, catalogHint
);
713 DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result
, parentDirID
, name
));
715 return MacToVFSError(result
);
719 short hfsMoveRename (ExtendedVCB
*vcb
, UInt32 oldDirID
, char *oldName
, UInt32 newDirID
, char *newName
, UInt32
*hint
)
721 OSErr result
= noErr
;
723 result
= MoveRenameCatalogNode(vcb
, oldDirID
,oldName
, *hint
, newDirID
, newName
, hint
, 0);
726 DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result
, newDirID
, newName
));
729 return MacToVFSError(result
);
732 /* XXX SER pass back the hint so other people can use it */
735 short hfsCreate(ExtendedVCB
*vcb
, UInt32 dirID
, char *name
, int mode
, UInt32 tehint
)
737 OSErr result
= noErr
;
738 HFSCatalogNodeID catalogNodeID
;
742 /* just test for directories, the default is to create a file (like symlinks) */
743 if ((mode
& IFMT
) == IFDIR
)
744 type
= kCatalogFolderNode
;
746 type
= kCatalogFileNode
;
748 result
= CreateCatalogNode (vcb
, dirID
, name
, type
, &catalogNodeID
, &catalogHint
, tehint
);
750 return MacToVFSError(result
);
754 short hfsCreateFileID (ExtendedVCB
*vcb
, UInt32 parentDirID
, StringPtr name
, UInt32 catalogHint
, UInt32
*fileIDPtr
)
756 return MacToVFSError(CreateFileIDRef(vcb
, parentDirID
, name
, catalogHint
, fileIDPtr
));
760 /********************************************************************************/
762 /* hfs_vget_catinfo - Returns a vnode derived from a hfs catInfo struct */
764 /********************************************************************************/
766 int hfs_vget_catinfo(struct vnode
*parent_vp
, struct hfsCatalogInfo
*catInfo
, u_int32_t forkType
, struct vnode
**target_vp
)
770 if (forkType
== kDefault
) {
771 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
)
772 forkType
= kDirectory
;
774 forkType
= kDataFork
;
777 *target_vp
= hfs_vhashget(H_DEV(VTOH(parent_vp
)), catInfo
->nodeData
.cnd_nodeID
, forkType
);
779 if (*target_vp
== NULL
)
780 retval
= hfs_vcreate( VTOVCB(parent_vp
), catInfo
, forkType
, target_vp
);
787 /************************************************************************/
788 /* hfs_vcreate - Returns a vnode derived from hfs */
790 /* When creating the vnode, care must be made to set the */
791 /* correct fields in the correct order. Calls to malloc() */
792 /* and other subroutines, can cause a context switch, */
793 /* and the fields must be ready for the possibility */
796 /************************************************************************/
798 short hfs_vcreate(ExtendedVCB
*vcb
, hfsCatalogInfo
*catInfo
, UInt8 forkType
, struct vnode
**vpp
)
802 struct hfsmount
*hfsmp
;
803 struct hfsfilemeta
*fm
;
810 DBG_ASSERT(vcb
!= NULL
);
811 DBG_ASSERT(catInfo
!= NULL
);
812 DBG_ASSERT(vpp
!= NULL
);
813 DBG_ASSERT((forkType
== kDirectory
) || (forkType
== kDataFork
) || (forkType
== kRsrcFork
));
814 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) {
815 DBG_ASSERT(forkType
== kDirectory
);
817 DBG_ASSERT(forkType
!= kDirectory
);
821 if ( ! ((forkType
== kDirectory
) || (forkType
== kDataFork
) || (forkType
== kRsrcFork
)))
822 panic("Bad fork type");
823 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) {
824 if (forkType
!= kDirectory
)
825 panic("non directory type");
827 if (forkType
!= kDataFork
&& forkType
!= kRsrcFork
)
828 panic("non fork type");
831 hfsmp
= VCBTOHFS(vcb
);
832 mp
= HFSTOVFS(hfsmp
);
833 dev
= hfsmp
->hfs_raw_dev
;
835 /* Check if unmount in progress */
836 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
840 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
));
842 /* Must malloc() here, since getnewvnode() can sleep */
843 MALLOC_ZONE(hp
, struct hfsnode
*, sizeof(struct hfsnode
), M_HFSNODE
, M_WAITOK
);
844 bzero((caddr_t
)hp
, sizeof(struct hfsnode
));
847 * Set that this node is in the process of being allocated
848 * Set it as soon as possible, so context switches well always hit upon it.
849 * if this is set then wakeup() MUST be called on hp after the flag is cleared
850 * DO NOT exit without clearing and waking up !!!!
852 hp
->h_nodeflags
|= IN_ALLOCATING
; /* Mark this as being allocating */
853 lockinit(&hp
->h_lock
, PINOD
, "hfsnode", 0, 0);
856 /* getnewvnode() does a VREF() on the vnode */
857 /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
858 if ((retval
= getnewvnode(VT_HFS
, mp
, hfs_vnodeop_p
, &vp
))) {
859 wakeup(hp
); /* Shouldnt happen, but just to make sure */
860 FREE_ZONE(hp
, sizeof(struct hfsnode
), M_HFSNODE
);
866 * Set the essentials before locking it down
868 hp
->h_vp
= vp
; /* Make HFSTOV work */
869 vp
->v_data
= hp
; /* Make VTOH work */
870 H_FORKTYPE(hp
) = forkType
;
871 rl_init(&hp
->h_invalidranges
);
875 * Lock the hfsnode and insert the hfsnode into the hash queue, also if meta exists
876 * add to sibling list and return the meta address
878 if (SIBLING_FORKTYPE(forkType
))
879 hfs_vhashins_sibling(dev
, catInfo
->nodeData
.cnd_nodeID
, hp
, &fm
);
881 hfs_vhashins(dev
, catInfo
->nodeData
.cnd_nodeID
, hp
);
884 * If needed allocate and init the object meta data:
887 /* Allocate it....remember we can do a context switch here */
888 MALLOC_ZONE(fm
, struct hfsfilemeta
*, sizeof(struct hfsfilemeta
), M_HFSFMETA
, M_WAITOK
);
889 bzero(fm
, sizeof(struct hfsfilemeta
));
893 * NOTICE: XXX Even though we have added the vnode to the hash so it is alive on TWO
894 * accessable lists, we do not assign it until later,
895 * this helps to make sure we do not use a half initiated meta
898 /* Init the sibling list if needed */
899 if (SIBLING_FORKTYPE(forkType
)) {
900 simple_lock_init(&fm
->h_siblinglock
);
901 CIRCLEQ_INIT(&fm
->h_siblinghead
);
902 CIRCLEQ_INSERT_HEAD(&fm
->h_siblinghead
, hp
, h_sibling
);
906 CopyCatalogToObjectMeta(catInfo
, vp
, fm
);
909 * the vnode is finally alive, with the exception of the FCB below,
910 * It is finally locked and ready for its debutante ball
918 * Init the File Control Block.
920 CopyCatalogToFCB(catInfo
, vp
);
923 * Finish vnode initialization.
924 * Setting the v_type 'stamps' the vnode as 'complete', so should be done almost last.
926 * At this point the vnode should be locked and fully allocated. And ready to be used
927 * or accessed. (though having it locked prevents most of this, it
928 * can still be accessed through lists and hashs).
930 vp
->v_type
= IFTOVT(hp
->h_meta
->h_mode
);
931 if ((vp
->v_type
== VREG
)
932 && (UBCINFOMISSING(vp
) || UBCINFORECLAIMED(vp
))) {
937 * Initialize the vnode from the inode, check for aliases, sets the VROOT flag.
938 * Note that the underlying vnode may have changed.
940 if ((retval
= hfs_vinit(mp
, hfs_specop_p
, hfs_fifoop_p
, &vp
))) {
948 * Finish inode initialization now that aliasing has been resolved.
950 hp
->h_meta
->h_devvp
= hfsmp
->hfs_devvp
;
951 VREF(hp
->h_meta
->h_devvp
);
954 hp
->h_valid
= HFS_VNODE_MAGIC
;
956 hp
->h_nodeflags
&= ~IN_ALLOCATING
; /* vnode is completely initialized */
958 /* Wake up anybody waiting for us to finish..see hfs_vhash.c */
963 /* Lets do some testing here */
964 DBG_ASSERT(hp
->h_meta
);
965 DBG_ASSERT(VTOH(vp
)==hp
);
966 DBG_ASSERT(HTOV(hp
)==vp
);
967 DBG_ASSERT(hp
->h_meta
->h_usecount
>=1 && hp
->h_meta
->h_usecount
<=2);
968 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) {
969 DBG_ASSERT(vp
->v_type
== VDIR
);
970 DBG_ASSERT(H_FORKTYPE(VTOH(vp
)) == kDirectory
);
972 #endif // HFS_DIAGNOSTIC
980 void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
)
982 ExtendedVCB
*vcb
= VTOVCB(vp
);
983 struct mount
*mp
= VTOVFS(vp
);
984 Boolean isHFSPlus
, isDirectory
;
988 DBG_ASSERT (fm
!= NULL
);
989 DBG_ASSERT (fm
->h_namelen
== 0);
990 DBG_ASSERT (fm
->h_namePtr
== 0);
992 DBG_UTILS(("\tCopying to file's meta data: name:%s, nodeid:%ld\n", catalogInfo
->nodeData
.cnm_nameptr
, catalogInfo
->nodeData
.cnd_nodeID
));
994 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
995 isDirectory
= (catalogInfo
->nodeData
.cnd_type
== kCatalogFolderNode
);
996 finderFlags
= SWAP_BE16 (((struct FInfo
*)(&catalogInfo
->nodeData
.cnd_finderInfo
))->fdFlags
);
998 /* Copy over the dirid, and hint */
999 fm
->h_nodeID
= catalogInfo
->nodeData
.cnd_nodeID
;
1000 fm
->h_dirID
= catalogInfo
->nodeData
.cnm_parID
;
1001 fm
->h_hint
= catalogInfo
->hint
;
1003 /* Copy over the name */
1004 hfs_name_CatToMeta(&catalogInfo
->nodeData
, fm
);
1007 /* get dates in BSD format */
1008 fm
->h_mtime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1009 fm
->h_crtime
= to_bsd_time(catalogInfo
->nodeData
.cnd_createDate
);
1010 fm
->h_butime
= to_bsd_time(catalogInfo
->nodeData
.cnd_backupDate
);
1012 fm
->h_atime
= to_bsd_time(catalogInfo
->nodeData
.cnd_accessDate
);
1013 fm
->h_ctime
= to_bsd_time(catalogInfo
->nodeData
.cnd_attributeModDate
);
1016 fm
->h_atime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1017 fm
->h_ctime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1021 if (isHFSPlus
&& (catalogInfo
->nodeData
.cnd_mode
& IFMT
)) {
1022 fm
->h_uid
= catalogInfo
->nodeData
.cnd_ownerID
;
1023 fm
->h_gid
= catalogInfo
->nodeData
.cnd_groupID
;
1024 fm
->h_pflags
= catalogInfo
->nodeData
.cnd_ownerFlags
|
1025 (catalogInfo
->nodeData
.cnd_adminFlags
<< 16);
1026 fm
->h_mode
= (mode_t
)catalogInfo
->nodeData
.cnd_mode
;
1028 if (fm
->h_uid
== 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1029 fm
->h_uid
= UNKNOWNUID
;
1030 fm
->h_metaflags
|= IN_CHANGE
;
1031 vcb
->vcbFlags
|= kHFS_DamagedVolume
; /* Trigger fsck on next mount */
1033 if (fm
->h_gid
== 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1034 fm
->h_gid
= UNKNOWNGID
;
1035 fm
->h_metaflags
|= IN_CHANGE
;
1036 vcb
->vcbFlags
|= kHFS_DamagedVolume
; /* Trigger fsck on next mount */
1039 filetype
= fm
->h_mode
& IFMT
;
1040 if (filetype
== IFCHR
|| filetype
== IFBLK
)
1041 fm
->h_rdev
= catalogInfo
->nodeData
.cnd_rawDevice
;
1045 if (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
&&
1046 catalogInfo
->nodeData
.cnd_linkCount
> 0) {
1047 fm
->h_nlink
= catalogInfo
->nodeData
.cnd_linkCount
;
1048 fm
->h_indnodeno
= catalogInfo
->nodeData
.cnd_iNodeNumCopy
;
1049 fm
->h_metaflags
|= IN_DATANODE
;
1054 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1056 * Override the permissions as determined by the mount auguments
1057 * in ALMOST the same way unset permissions are treated but keep
1058 * track of whether or not the file or folder is hfs locked
1059 * by leaving the h_pflags field unchanged from what was unpacked
1060 * out of the catalog.
1062 fm
->h_metaflags
|= IN_UNSETACCESS
;
1063 fm
->h_uid
= VTOHFS(vp
)->hfs_uid
;
1064 fm
->h_gid
= VTOHFS(vp
)->hfs_gid
;
1065 #if OVERRIDE_UNKNOWN_PERMISSIONS
1066 /* Default access is full read/write/execute: */
1067 /* XXX won't this smash IFCHR, IFBLK and IFLNK (for no-follow lookups)? */
1068 fm
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
1071 /* ... but no more than that permitted by the mount point's: */
1073 fm
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
1076 fm
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
1080 fm
->h_mode
|= IFDIR
;
1081 else if (SUPPORTS_MAC_ALIASES
&& (finderFlags
& kIsAlias
)) /* aliases will be symlinks in the future */
1082 fm
->h_mode
|= IFLNK
;
1084 fm
->h_mode
|= IFREG
;
1089 * Set the permissions as determined by the mount auguments
1090 * but keep in account if the file or folder is hfs locked
1092 fm
->h_metaflags
|= IN_UNSETACCESS
;
1093 fm
->h_uid
= VTOHFS(vp
)->hfs_uid
;
1094 fm
->h_gid
= VTOHFS(vp
)->hfs_gid
;
1095 fm
->h_pflags
= 0; /* No valid pflags on disk (IMMUTABLE is synced from lock flag later) */
1096 fm
->h_rdev
= 0; /* No valid rdev on disk */
1097 /* Default access is full read/write/execute: */
1098 fm
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
1100 /* ... but no more than that permitted by the mount point's: */
1102 fm
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
1105 fm
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
1109 fm
->h_mode
|= IFDIR
;
1110 else if (SUPPORTS_MAC_ALIASES
&& (finderFlags
& kIsAlias
)) /* aliases will be symlinks in the future */
1111 fm
->h_mode
|= IFLNK
;
1113 fm
->h_mode
|= IFREG
;
1116 /* Make sure that there is no nodeType/mode mismatch */
1117 if (isDirectory
&& ((fm
->h_mode
& IFMT
) != IFDIR
)) {
1118 fm
->h_mode
&= ~IFMT
; /* Clear the bad bits */
1119 fm
->h_mode
|= IFDIR
; /* Set the proper one */
1122 /* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */
1124 if (catalogInfo
->nodeData
.cnd_flags
& kHFSFileLockedMask
) {
1125 /* The file's supposed to be locked:
1126 Make sure at least one of the IMMUTABLE bits is set: */
1127 if ((fm
->h_pflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
)) == 0) {
1128 fm
->h_pflags
|= UF_IMMUTABLE
; /* Set the user-changable IMMUTABLE bit */
1131 /* The file's supposed to be unlocked: */
1132 fm
->h_pflags
&= ~(SF_IMMUTABLE
| UF_IMMUTABLE
);
1137 fm
->h_nlink
= 2 + catalogInfo
->nodeData
.cnd_valence
;
1138 fm
->h_size
= (2 * sizeof(hfsdotentry
)) +
1139 (catalogInfo
->nodeData
.cnd_valence
* AVERAGE_HFSDIRENTRY_SIZE
);
1140 if (fm
->h_size
< MAX_HFSDIRENTRY_SIZE
)
1141 fm
->h_size
= MAX_HFSDIRENTRY_SIZE
;
1143 fm
->h_size
= (off_t
)vcb
->blockSize
*
1144 (off_t
)(catalogInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
+
1145 catalogInfo
->nodeData
.cnd_datafork
.totalBlocks
);
1150 void CopyCatalogToFCB(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
)
1152 FCB
*fcb
= VTOFCB(vp
);
1153 ExtendedVCB
*vcb
= VTOVCB(vp
);
1154 Boolean isHFSPlus
, isDirectory
, isResource
;
1155 HFSPlusExtentDescriptor
*extents
;
1158 DBG_ASSERT (vp
!= NULL
);
1159 DBG_ASSERT (fcb
!= NULL
);
1160 DBG_ASSERT (vcb
!= NULL
);
1161 DBG_ASSERT (VTOH(vp
) != NULL
);
1163 forkType
= H_FORKTYPE(VTOH(vp
));
1164 isResource
= (forkType
== kRsrcFork
);
1165 isDirectory
= (catalogInfo
->nodeData
.cnd_type
== kCatalogFolderNode
);
1166 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1169 fcb
->fcbFlags
= catalogInfo
->nodeData
.cnd_flags
;
1171 if (forkType
!= kDirectory
) {
1172 fcb
->fcbFlags
&= kHFSFileLockedMask
; /* Clear resource, dirty bits */
1173 if (fcb
->fcbFlags
!= 0) /* if clear, its not locked, then.. */
1174 fcb
->fcbFlags
= fcbFileLockedMask
; /* duplicate the bit for later use */
1176 fcb
->fcbClmpSize
= vcb
->vcbClpSiz
; /*XXX why not use the one in catalogInfo? */
1179 extents
= catalogInfo
->nodeData
.cnd_rsrcfork
.extents
;
1181 extents
= catalogInfo
->nodeData
.cnd_datafork
.extents
;
1183 /* Copy the extents to their correct location: */
1184 bcopy (extents
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
1187 fcb
->fcbEOF
= catalogInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
1188 fcb
->fcbPLen
= (off_t
)((off_t
)catalogInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
1189 fcb
->fcbFlags
|= fcbResourceMask
;
1191 fcb
->fcbEOF
= catalogInfo
->nodeData
.cnd_datafork
.logicalSize
;
1192 fcb
->fcbPLen
= (off_t
)((off_t
)catalogInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
1199 int hasOverflowExtents(struct hfsnode
*hp
)
1201 ExtendedVCB
*vcb
= HTOVCB(hp
);
1202 FCB
*fcb
= HTOFCB(hp
);
1205 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1208 if (fcb
->fcbExtents
[7].blockCount
== 0)
1211 blocks
= fcb
->fcbExtents
[0].blockCount
+
1212 fcb
->fcbExtents
[1].blockCount
+
1213 fcb
->fcbExtents
[2].blockCount
+
1214 fcb
->fcbExtents
[3].blockCount
+
1215 fcb
->fcbExtents
[4].blockCount
+
1216 fcb
->fcbExtents
[5].blockCount
+
1217 fcb
->fcbExtents
[6].blockCount
+
1218 fcb
->fcbExtents
[7].blockCount
;
1222 if (fcb
->fcbExtents
[2].blockCount
== 0)
1225 blocks
= fcb
->fcbExtents
[0].blockCount
+
1226 fcb
->fcbExtents
[1].blockCount
+
1227 fcb
->fcbExtents
[2].blockCount
;
1230 return ((fcb
->fcbPLen
/ vcb
->blockSize
) > blocks
);
1234 int hfs_metafilelocking(struct hfsmount
*hfsmp
, u_long fileID
, u_int flags
, struct proc
*p
)
1237 struct vnode
*vp
= NULL
;
1238 int numOfLockedBuffs
;
1241 vcb
= HFSTOVCB(hfsmp
);
1243 DBG_UTILS(("hfs_metafilelocking: vol: %d, file: %d %s%s%s\n", vcb
->vcbVRefNum
, fileID
,
1244 ((flags
& LK_TYPE_MASK
) == LK_RELEASE
? "RELEASE" : ""),
1245 ((flags
& LK_TYPE_MASK
) == LK_EXCLUSIVE
? "EXCLUSIVE" : ""),
1246 ((flags
& LK_TYPE_MASK
) == LK_SHARED
? "SHARED" : "") ));
1251 case kHFSExtentsFileID
:
1252 vp
= vcb
->extentsRefNum
;
1255 case kHFSCatalogFileID
:
1256 vp
= vcb
->catalogRefNum
;
1259 case kHFSAllocationFileID
:
1260 /* bitmap is covered by Extents B-tree locking */
1263 panic("hfs_lockmetafile: invalid fileID");
1268 /* Release, if necesary any locked buffer caches */
1269 if ((flags
& LK_TYPE_MASK
) == LK_RELEASE
) {
1270 struct timeval tv
= time
;
1271 u_int32_t lastfsync
= tv
.tv_sec
;
1273 (void) BTGetLastSync(VTOFCB(vp
), &lastfsync
);
1275 numOfLockedBuffs
= count_lock_queue();
1276 if ((numOfLockedBuffs
> kMaxLockedMetaBuffers
) || ((numOfLockedBuffs
>1) && ((tv
.tv_sec
- lastfsync
) > kMaxSecsForFsync
))) {
1277 DBG_UTILS(("Synching meta deta: %d... # locked buffers = %d, fsync gap = %ld\n", H_FILEID(VTOH(vp
)),
1278 numOfLockedBuffs
, (tv
.tv_sec
- lastfsync
)));
1279 hfs_fsync_transaction(vp
);
1283 retval
= lockmgr(&VTOH(vp
)->h_lock
, flags
, &vp
->v_interlock
, p
);
1291 * There are three ways to qualify for ownership rights on an object:
1293 * 1. (a) Your UID matches the UID of the vnode
1294 * (b) The object in question is owned by "unknown" and your UID matches the console user's UID
1295 * 2. (a) Permissions on the filesystem are being ignored and your UID matches the replacement UID
1296 * (b) Permissions on the filesystem are being ignored and the replacement UID is "unknown" and
1297 * your UID matches the console user UID
1301 int hfs_owner_rights(struct vnode
*vp
, struct ucred
*cred
, struct proc
*p
, Boolean invokesuperuserstatus
) {
1302 return ((cred
->cr_uid
== VTOH(vp
)->h_meta
->h_uid
) || /* [1a] */
1303 ((VTOH(vp
)->h_meta
->h_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)) || /* [1b] */
1304 ((VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) && /* [2] */
1305 ((cred
->cr_uid
== VTOHFS(vp
)->hfs_uid
) || /* [2a] */
1306 ((VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)))) || /* [2b] */
1307 (invokesuperuserstatus
&& (suser(cred
, &p
->p_acflag
) == 0))) ? 0 : EPERM
;
1312 int hfs_catalogentry_owner_rights(uid_t obj_uid
, struct mount
*mp
, struct ucred
*cred
, struct proc
*p
, Boolean invokesuperuserstatus
) {
1313 return ((cred
->cr_uid
== obj_uid
) || /* [1a] */
1314 ((obj_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)) || /* [1b] */
1315 ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) && /* [2] */
1316 ((cred
->cr_uid
== VFSTOHFS(mp
)->hfs_uid
) || /* [2a] */
1317 ((VFSTOHFS(mp
)->hfs_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)))) || /* [2b] */
1318 (invokesuperuserstatus
&& (suser(cred
, &p
->p_acflag
) == 0))) ? 0 : EPERM
;
1323 void CopyVNodeToCatalogNode (struct vnode
*vp
, struct CatalogNodeData
*nodeData
)
1328 Boolean isHFSPlus
, isResource
;
1329 HFSPlusExtentDescriptor
*extents
;
1330 off_t fileReadLimit
;
1335 isResource
= (H_FORKTYPE(hp
) == kRsrcFork
);
1336 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1338 /* date and time of last fork modification */
1339 if (hp
->h_meta
->h_mtime
!= 0)
1340 nodeData
->cnd_contentModDate
= to_hfs_time(hp
->h_meta
->h_mtime
);
1343 /* Make sure that there is no nodeType/mode mismatch */
1344 if ((nodeData
->cnd_type
== kCatalogFolderNode
)
1345 && ((hp
->h_meta
->h_mode
& IFMT
) != IFDIR
)) {
1347 DBG_ASSERT((hp
->h_meta
->h_mode
& IFMT
) == IFDIR
);
1348 hp
->h_meta
->h_mode
&= ~IFMT
; /* Clear the bad bits */
1349 hp
->h_meta
->h_mode
|= IFDIR
; /* Set the proper one */
1351 /* date and time of last modification (any kind) */
1352 if (hp
->h_meta
->h_ctime
!= 0)
1353 nodeData
->cnd_attributeModDate
= to_hfs_time(hp
->h_meta
->h_ctime
);
1354 /* date and time of last access (MacOS X only) */
1355 if (hp
->h_meta
->h_atime
!= 0)
1356 nodeData
->cnd_accessDate
= to_hfs_time(hp
->h_meta
->h_atime
);
1357 /* hfs_setattr can change the create date */
1358 if (hp
->h_meta
->h_crtime
!= 0)
1359 nodeData
->cnd_createDate
= to_hfs_time(hp
->h_meta
->h_crtime
);
1360 if (! (hp
->h_meta
->h_metaflags
& IN_UNSETACCESS
)) {
1361 nodeData
->cnd_adminFlags
= hp
->h_meta
->h_pflags
>> 16;
1362 nodeData
->cnd_ownerFlags
= hp
->h_meta
->h_pflags
& 0x000000FF;
1363 nodeData
->cnd_mode
= hp
->h_meta
->h_mode
;
1364 nodeData
->cnd_ownerID
= hp
->h_meta
->h_uid
;
1365 nodeData
->cnd_groupID
= hp
->h_meta
->h_gid
;
1369 /* the rest only applies to files */
1370 if (nodeData
->cnd_type
== kCatalogFileNode
) {
1371 if (hp
->h_meta
->h_pflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
)) {
1372 /* The file is locked: set the locked bit in the catalog. */
1373 nodeData
->cnd_flags
|= kHFSFileLockedMask
;
1375 /* The file is unlocked: make sure the locked bit in the catalog is clear. */
1376 nodeData
->cnd_flags
&= ~kHFSFileLockedMask
;
1378 if (CIRCLEQ_EMPTY(&hp
->h_invalidranges
)) {
1379 fileReadLimit
= fcb
->fcbEOF
;
1381 fileReadLimit
= CIRCLEQ_FIRST(&hp
->h_invalidranges
)->rl_start
;
1384 extents
= nodeData
->cnd_rsrcfork
.extents
;
1385 nodeData
->cnd_rsrcfork
.logicalSize
= fileReadLimit
;
1386 nodeData
->cnd_rsrcfork
.totalBlocks
= fcb
->fcbPLen
/ vcb
->blockSize
;
1388 extents
= nodeData
->cnd_datafork
.extents
;
1389 nodeData
->cnd_datafork
.logicalSize
= fileReadLimit
;
1390 nodeData
->cnd_datafork
.totalBlocks
= fcb
->fcbPLen
/ vcb
->blockSize
;
1393 bcopy ( fcb
->fcbExtents
, extents
, sizeof(HFSPlusExtentRecord
));
1395 if ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))
1396 nodeData
->cnd_rawDevice
= hp
->h_meta
->h_rdev
;
1397 else if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
1398 nodeData
->cnd_linkCount
= hp
->h_meta
->h_nlink
;
1400 if (vp
->v_type
== VLNK
) {
1401 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdType
= SWAP_BE32 (kSymLinkFileType
);
1402 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdCreator
= SWAP_BE32 (kSymLinkCreator
);
1404 /* Set this up as an alias */
1405 #if SUPPORTS_MAC_ALIASES
1406 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdFlags
|= SWAP_BE16 (kIsAlias
);
1413 /*********************************************************************
1415 Sets the name in the filemeta structure
1417 XXX Does not preflight if changing from one size to another
1418 XXX Currently not protected from context switching
1420 *********************************************************************/
1422 void hfs_set_metaname(char *name
, struct hfsfilemeta
*fm
, struct hfsmount
*hfsmp
)
1424 int namelen
= strlen(name
);
1425 char *tname
, *fname
;
1428 DBG_ASSERT(name
!= NULL
);
1429 DBG_ASSERT(fm
!= NULL
);
1430 if (fm
->h_namePtr
) {
1431 DBG_ASSERT(fm
->h_namelen
== strlen(fm
->h_namePtr
));
1432 if (strlen(fm
->h_namePtr
) > MAXHFSVNODELEN
)
1433 DBG_ASSERT(fm
->h_metaflags
& IN_LONGNAME
);
1435 if (fm
->h_metaflags
& IN_LONGNAME
) {
1436 DBG_ASSERT(fm
->h_namePtr
!= (char *)fm
->h_fileName
);
1437 DBG_ASSERT(fm
->h_namePtr
!= NULL
);
1439 #endif //HFS_DIAGNOSTIC
1442 * Details that have to be dealt with:
1443 * 1. No name is allocated. fm->h_namePtr should be NULL
1444 * 2. A name is being changed and:
1445 * a. it was in static space and now cannot fit
1446 * b. It was malloc'd and now will fit in the static
1447 * c. It did and will fit in the static
1448 * This could be a little smarter:
1449 * - Dont re'malloc if the new name is smaller (but then wasting memory)
1450 * - If its a longname but the same size, we still free and malloc
1455 /* Allocate the new memory */
1456 if (namelen
> MAXHFSVNODELEN
) {
1458 * Notice the we ALWAYS allocate, even if the new is less then the old,
1459 * or even if they are the SAME
1461 MALLOC(tname
, char *, namelen
+1, M_TEMP
, M_WAITOK
);
1464 tname
= fm
->h_fileName
;
1466 simple_lock(&hfsmp
->hfs_renamelock
);
1468 /* Check to see if there is something to free, if yes, remember it */
1469 if (fm
->h_metaflags
& IN_LONGNAME
)
1470 fname
= fm
->h_namePtr
;
1475 if (namelen
> MAXHFSVNODELEN
) {
1476 fm
->h_metaflags
|= IN_LONGNAME
;
1479 fm
->h_metaflags
&= ~IN_LONGNAME
;
1482 /* Now copy it over */
1483 bcopy(name
, tname
, namelen
+1);
1485 fm
->h_namePtr
= tname
;
1486 fm
->h_namelen
= namelen
;
1488 simple_unlock(&hfsmp
->hfs_renamelock
);
1490 /* Lastly, free the old, if set */
1492 FREE(fname
, M_TEMP
);
1496 void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
)
1501 DBG_ASSERT(nodeData
!= NULL
);
1502 DBG_ASSERT(fm
!= NULL
);
1503 if (fm
->h_namePtr
) {
1504 DBG_ASSERT(fm
->h_namelen
== strlen(fm
->h_namePtr
));
1505 if (strlen(fm
->h_namePtr
) > MAXHFSVNODELEN
)
1506 DBG_ASSERT(fm
->h_metaflags
& IN_LONGNAME
);
1508 if (fm
->h_metaflags
& IN_LONGNAME
) {
1509 DBG_ASSERT(fm
->h_namePtr
!= (char *)fm
->h_fileName
);
1510 DBG_ASSERT(fm
->h_namePtr
!= NULL
);
1513 DBG_ASSERT(nodeData
->cnm_nameptr
!= NULL
);
1515 if (nodeData
->cnm_length
) {
1516 DBG_ASSERT(strlen(nodeData
->cnm_nameptr
) == nodeData
->cnm_length
);
1519 if (nodeData
->cnm_length
> MAXHFSVNODELEN
)
1520 { DBG_ASSERT(nodeData
->cnm_nameptr
!= nodeData
->cnm_namespace
); }
1521 else if (nodeData
->cnm_nameptr
)
1522 { DBG_ASSERT(nodeData
->cnm_nameptr
== nodeData
->cnm_namespace
); }
1524 #endif //HFS_DIAGNOSTIC
1527 /* Check to see if there is something to free, if yes, remember it */
1528 if (fm
->h_metaflags
& IN_LONGNAME
)
1529 fname
= fm
->h_namePtr
;
1534 if (nodeData
->cnm_length
> MAXHFSVNODELEN
) {
1535 fm
->h_metaflags
|= IN_LONGNAME
;
1537 fm
->h_metaflags
&= ~IN_LONGNAME
;
1540 /* Copy over the name */
1541 if (nodeData
->cnm_nameptr
== nodeData
->cnm_namespace
) {
1542 bcopy(nodeData
->cnm_namespace
, fm
->h_fileName
, nodeData
->cnm_length
+1);
1543 fm
->h_namePtr
= fm
->h_fileName
;
1546 fm
->h_namePtr
= nodeData
->cnm_nameptr
;
1549 fm
->h_namelen
= nodeData
->cnm_length
;
1551 nodeData
->cnm_flags
|= kCatNameIsConsumed
;
1552 nodeData
->cnm_flags
&= ~kCatNameIsAllocated
;
1553 nodeData
->cnm_length
= 0;
1554 nodeData
->cnm_nameptr
= (char *)0;
1555 nodeData
->cnm_namespace
[0] = 0;
1557 /* Lastly, free the old, if set */
1559 FREE(fname
, M_TEMP
);
1564 unsigned long DerivePermissionSummary(uid_t obj_uid
, gid_t obj_gid
, mode_t obj_mode
, struct mount
*mp
, struct ucred
*cred
, struct proc
*p
) {
1566 unsigned long permissions
;
1569 /* User id 0 (root) always gets access. */
1570 if (cred
->cr_uid
== 0) {
1571 permissions
= R_OK
| W_OK
| X_OK
;
1575 /* Otherwise, check the owner. */
1576 if (hfs_catalogentry_owner_rights(obj_uid
, mp
, cred
, p
, false) == 0) {
1577 permissions
= ((unsigned long)obj_mode
& S_IRWXU
) >> 6;
1581 /* Otherwise, check the groups. */
1582 if (! (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
1583 for (i
= 0, gp
= cred
->cr_groups
; i
< cred
->cr_ngroups
; i
++, gp
++) {
1584 if (obj_gid
== *gp
) {
1585 permissions
= ((unsigned long)obj_mode
& S_IRWXG
) >> 3;
1591 /* Otherwise, settle for 'others' access. */
1592 permissions
= (unsigned long)obj_mode
& S_IRWXO
;
1600 int AttributeBlockSize(struct attrlist
*attrlist
) {
1604 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1605 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_PAROBJID | \
1606 ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
1607 ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1608 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST| \
1609 ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) != ATTR_CMN_VALIDMASK)
1610 #error AttributeBlockSize: Missing bits in common mask computation!
1612 DBG_ASSERT((attrlist
->commonattr
& ~ATTR_CMN_VALIDMASK
) == 0);
1614 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
1615 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1616 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | \
1617 ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | \
1618 ATTR_VOL_MOUNTEDDEVICE| ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) != ATTR_VOL_VALIDMASK)
1619 #error AttributeBlockSize: Missing bits in volume mask computation!
1621 DBG_ASSERT((attrlist
->volattr
& ~ATTR_VOL_VALIDMASK
) == 0);
1623 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) != ATTR_DIR_VALIDMASK)
1624 #error AttributeBlockSize: Missing bits in directory mask computation!
1626 DBG_ASSERT((attrlist
->dirattr
& ~ATTR_DIR_VALIDMASK
) == 0);
1627 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
1628 ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | \
1629 ATTR_FILE_FORKLIST | ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1630 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) != ATTR_FILE_VALIDMASK)
1631 #error AttributeBlockSize: Missing bits in file mask computation!
1633 DBG_ASSERT((attrlist
->fileattr
& ~ATTR_FILE_VALIDMASK
) == 0);
1635 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1636 #error AttributeBlockSize: Missing bits in fork mask computation!
1638 DBG_ASSERT((attrlist
->forkattr
& ~ATTR_FORK_VALIDMASK
) == 0);
1642 if ((a
= attrlist
->commonattr
) != 0) {
1643 if (a
& ATTR_CMN_NAME
) size
+= sizeof(struct attrreference
);
1644 if (a
& ATTR_CMN_DEVID
) size
+= sizeof(dev_t
);
1645 if (a
& ATTR_CMN_FSID
) size
+= sizeof(fsid_t
);
1646 if (a
& ATTR_CMN_OBJTYPE
) size
+= sizeof(fsobj_type_t
);
1647 if (a
& ATTR_CMN_OBJTAG
) size
+= sizeof(fsobj_tag_t
);
1648 if (a
& ATTR_CMN_OBJID
) size
+= sizeof(fsobj_id_t
);
1649 if (a
& ATTR_CMN_OBJPERMANENTID
) size
+= sizeof(fsobj_id_t
);
1650 if (a
& ATTR_CMN_PAROBJID
) size
+= sizeof(fsobj_id_t
);
1651 if (a
& ATTR_CMN_SCRIPT
) size
+= sizeof(text_encoding_t
);
1652 if (a
& ATTR_CMN_CRTIME
) size
+= sizeof(struct timespec
);
1653 if (a
& ATTR_CMN_MODTIME
) size
+= sizeof(struct timespec
);
1654 if (a
& ATTR_CMN_CHGTIME
) size
+= sizeof(struct timespec
);
1655 if (a
& ATTR_CMN_ACCTIME
) size
+= sizeof(struct timespec
);
1656 if (a
& ATTR_CMN_BKUPTIME
) size
+= sizeof(struct timespec
);
1657 if (a
& ATTR_CMN_FNDRINFO
) size
+= 32 * sizeof(UInt8
);
1658 if (a
& ATTR_CMN_OWNERID
) size
+= sizeof(uid_t
);
1659 if (a
& ATTR_CMN_GRPID
) size
+= sizeof(gid_t
);
1660 if (a
& ATTR_CMN_ACCESSMASK
) size
+= sizeof(u_long
);
1661 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) size
+= sizeof(u_long
);
1662 if (a
& ATTR_CMN_NAMEDATTRLIST
) size
+= sizeof(struct attrreference
);
1663 if (a
& ATTR_CMN_FLAGS
) size
+= sizeof(u_long
);
1664 if (a
& ATTR_CMN_USERACCESS
) size
+= sizeof(u_long
);
1666 if ((a
= attrlist
->volattr
) != 0) {
1667 if (a
& ATTR_VOL_FSTYPE
) size
+= sizeof(u_long
);
1668 if (a
& ATTR_VOL_SIGNATURE
) size
+= sizeof(u_long
);
1669 if (a
& ATTR_VOL_SIZE
) size
+= sizeof(off_t
);
1670 if (a
& ATTR_VOL_SPACEFREE
) size
+= sizeof(off_t
);
1671 if (a
& ATTR_VOL_SPACEAVAIL
) size
+= sizeof(off_t
);
1672 if (a
& ATTR_VOL_MINALLOCATION
) size
+= sizeof(off_t
);
1673 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) size
+= sizeof(off_t
);
1674 if (a
& ATTR_VOL_IOBLOCKSIZE
) size
+= sizeof(u_long
);
1675 if (a
& ATTR_VOL_OBJCOUNT
) size
+= sizeof(u_long
);
1676 if (a
& ATTR_VOL_FILECOUNT
) size
+= sizeof(u_long
);
1677 if (a
& ATTR_VOL_DIRCOUNT
) size
+= sizeof(u_long
);
1678 if (a
& ATTR_VOL_MAXOBJCOUNT
) size
+= sizeof(u_long
);
1679 if (a
& ATTR_VOL_MOUNTPOINT
) size
+= sizeof(struct attrreference
);
1680 if (a
& ATTR_VOL_NAME
) size
+= sizeof(struct attrreference
);
1681 if (a
& ATTR_VOL_MOUNTFLAGS
) size
+= sizeof(u_long
);
1682 if (a
& ATTR_VOL_MOUNTEDDEVICE
) size
+= sizeof(struct attrreference
);
1683 if (a
& ATTR_VOL_ENCODINGSUSED
) size
+= sizeof(unsigned long long);
1684 if (a
& ATTR_VOL_CAPABILITIES
) size
+= sizeof(vol_capabilities_attr_t
);
1685 if (a
& ATTR_VOL_ATTRIBUTES
) size
+= sizeof(vol_attributes_attr_t
);
1687 if ((a
= attrlist
->dirattr
) != 0) {
1688 if (a
& ATTR_DIR_LINKCOUNT
) size
+= sizeof(u_long
);
1689 if (a
& ATTR_DIR_ENTRYCOUNT
) size
+= sizeof(u_long
);
1690 if (a
& ATTR_DIR_MOUNTSTATUS
) size
+= sizeof(u_long
);
1692 if ((a
= attrlist
->fileattr
) != 0) {
1693 if (a
& ATTR_FILE_LINKCOUNT
) size
+= sizeof(u_long
);
1694 if (a
& ATTR_FILE_TOTALSIZE
) size
+= sizeof(off_t
);
1695 if (a
& ATTR_FILE_ALLOCSIZE
) size
+= sizeof(off_t
);
1696 if (a
& ATTR_FILE_IOBLOCKSIZE
) size
+= sizeof(size_t);
1697 if (a
& ATTR_FILE_CLUMPSIZE
) size
+= sizeof(off_t
);
1698 if (a
& ATTR_FILE_DEVTYPE
) size
+= sizeof(u_long
);
1699 if (a
& ATTR_FILE_FILETYPE
) size
+= sizeof(u_long
);
1700 if (a
& ATTR_FILE_FORKCOUNT
) size
+= sizeof(u_long
);
1701 if (a
& ATTR_FILE_FORKLIST
) size
+= sizeof(struct attrreference
);
1702 if (a
& ATTR_FILE_DATALENGTH
) size
+= sizeof(off_t
);
1703 if (a
& ATTR_FILE_DATAALLOCSIZE
) size
+= sizeof(off_t
);
1704 if (a
& ATTR_FILE_DATAEXTENTS
) size
+= sizeof(extentrecord
);
1705 if (a
& ATTR_FILE_RSRCLENGTH
) size
+= sizeof(off_t
);
1706 if (a
& ATTR_FILE_RSRCALLOCSIZE
) size
+= sizeof(off_t
);
1707 if (a
& ATTR_FILE_RSRCEXTENTS
) size
+= sizeof(extentrecord
);
1709 if ((a
= attrlist
->forkattr
) != 0) {
1710 if (a
& ATTR_FORK_TOTALSIZE
) size
+= sizeof(off_t
);
1711 if (a
& ATTR_FORK_ALLOCSIZE
) size
+= sizeof(off_t
);
1719 char* FindMountpointName(struct mount
*mp
) {
1720 size_t namelength
= strlen(mp
->mnt_stat
.f_mntonname
);
1724 if (namelength
== 0) return NULL
;
1726 /* Look backwards through the name string, looking for the first slash
1727 encountered (which must precede the last part of the pathname)
1729 for (c
= mp
->mnt_stat
.f_mntonname
+ namelength
- 1; namelength
> 0; --c
, --namelength
) {
1732 } else if (foundchars
) {
1737 return mp
->mnt_stat
.f_mntonname
;
1742 void PackObjectName(struct vnode
*vp
,
1745 void **attrbufptrptr
,
1746 void **varbufptrptr
) {
1751 /* The name of an object may be incorrect for the root of a mounted filesystem
1752 because it may be mounted on a different directory name than the name of the
1753 volume (such as "blah-1". For the root directory, it's best to return the
1754 last element of the location where the volume's mounted:
1756 if ((vp
->v_flag
& VROOT
) && (mpname
= FindMountpointName(vp
->v_mount
))) {
1757 mpnamelen
= strlen(mpname
);
1759 /* Trim off any trailing slashes: */
1760 while ((mpnamelen
> 0) && (mpname
[mpnamelen
-1] == '/')) {
1764 /* If there's anything left, use it instead of the volume's name */
1765 if (mpnamelen
> 0) {
1767 namelen
= mpnamelen
;
1771 attrlength
= namelen
+ 1;
1772 ((struct attrreference
*)(*attrbufptrptr
))->attr_dataoffset
= (char *)(*varbufptrptr
) - (char *)(*attrbufptrptr
);
1773 ((struct attrreference
*)(*attrbufptrptr
))->attr_length
= attrlength
;
1774 (void) strncpy((unsigned char *)(*varbufptrptr
), name
, attrlength
);
1776 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1777 (char *)(*varbufptrptr
) += attrlength
+ ((4 - (attrlength
& 3)) & 3);
1778 ++((struct attrreference
*)(*attrbufptrptr
));
1783 void PackVolCommonAttributes(struct attrlist
*alist
,
1784 struct vnode
*root_vp
,
1785 struct hfsCatalogInfo
*root_catInfo
,
1786 void **attrbufptrptr
,
1787 void **varbufptrptr
) {
1791 struct hfsnode
*root_hp
= VTOH(root_vp
);
1792 struct mount
*mp
= VTOVFS(root_vp
);
1793 struct hfsmount
*hfsmp
= VTOHFS(root_vp
);
1794 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1797 attrbufptr
= *attrbufptrptr
;
1798 varbufptr
= *varbufptrptr
;
1800 if ((a
= alist
->commonattr
) != 0) {
1801 if (a
& ATTR_CMN_NAME
) {
1802 PackObjectName(root_vp
, H_NAME(root_hp
), root_hp
->h_meta
->h_namelen
, &attrbufptr
, &varbufptr
);
1804 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1805 if (a
& ATTR_CMN_FSID
) {
1806 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1807 ++((fsid_t
*)attrbufptr
);
1809 if (a
& ATTR_CMN_OBJTYPE
) *((fsobj_type_t
*)attrbufptr
)++ = 0;
1810 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1811 if (a
& ATTR_CMN_OBJID
) {
1812 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1813 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1814 ++((fsobj_id_t
*)attrbufptr
);
1816 if (a
& ATTR_CMN_OBJPERMANENTID
) {
1817 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1818 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1819 ++((fsobj_id_t
*)attrbufptr
);
1821 if (a
& ATTR_CMN_PAROBJID
) {
1822 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1823 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1824 ++((fsobj_id_t
*)attrbufptr
);
1827 if (a
& ATTR_CMN_SCRIPT
) *((text_encoding_t
*)attrbufptr
)++ = vcb
->volumeNameEncodingHint
;
1828 /* NOTE: all VCB dates are in Mac OS time */
1829 if (a
& ATTR_CMN_CRTIME
) {
1830 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbCrDate
);
1831 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1832 ++((struct timespec
*)attrbufptr
);
1834 if (a
& ATTR_CMN_MODTIME
) {
1835 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1836 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1837 ++((struct timespec
*)attrbufptr
);
1839 if (a
& ATTR_CMN_CHGTIME
) {
1840 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1841 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1842 ++((struct timespec
*)attrbufptr
);
1844 if (a
& ATTR_CMN_ACCTIME
) {
1845 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1846 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1847 ++((struct timespec
*)attrbufptr
);
1849 if (a
& ATTR_CMN_BKUPTIME
) {
1850 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbVolBkUp
);
1851 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1852 ++((struct timespec
*)attrbufptr
);
1854 if (a
& ATTR_CMN_FNDRINFO
) {
1855 bcopy (&vcb
->vcbFndrInfo
, attrbufptr
, sizeof(vcb
->vcbFndrInfo
));
1856 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1859 if (a
& ATTR_CMN_OWNERID
) {
1860 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1861 *((uid_t
*)attrbufptr
)++ =
1862 (VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
;
1864 *((uid_t
*)attrbufptr
)++ =
1865 (root_hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: root_hp
->h_meta
->h_uid
;
1868 if (a
& ATTR_CMN_GRPID
) {
1869 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1870 *((gid_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_gid
;
1872 *((gid_t
*)attrbufptr
)++ = root_hp
->h_meta
->h_gid
;
1875 if (a
& ATTR_CMN_ACCESSMASK
) *((u_long
*)attrbufptr
)++ = (u_long
)root_hp
->h_meta
->h_mode
;
1876 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
1877 if (a
& ATTR_CMN_NAMEDATTRLIST
) {
1879 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1880 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1882 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1883 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1884 ++((struct attrreference
*)attrbufptr
);
1886 if (a
& ATTR_CMN_FLAGS
) *((u_long
*)attrbufptr
)++ = root_hp
->h_meta
->h_pflags
;
1887 if (a
& ATTR_CMN_USERACCESS
) {
1888 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1889 *((u_long
*)attrbufptr
)++ =
1890 DerivePermissionSummary((VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
,
1891 VTOHFS(root_vp
)->hfs_gid
,
1892 root_hp
->h_meta
->h_mode
,
1894 current_proc()->p_ucred
,
1897 *((u_long
*)attrbufptr
)++ =
1898 DerivePermissionSummary((root_hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: root_hp
->h_meta
->h_uid
,
1899 root_hp
->h_meta
->h_gid
,
1900 root_hp
->h_meta
->h_mode
,
1902 current_proc()->p_ucred
,
1908 *attrbufptrptr
= attrbufptr
;
1909 *varbufptrptr
= varbufptr
;
1914 void PackVolAttributeBlock(struct attrlist
*alist
,
1915 struct vnode
*root_vp
,
1916 struct hfsCatalogInfo
*root_catInfo
,
1917 void **attrbufptrptr
,
1918 void **varbufptrptr
) {
1922 struct mount
*mp
= VTOVFS(root_vp
);
1923 struct hfsmount
*hfsmp
= VTOHFS(root_vp
);
1924 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1927 attrbufptr
= *attrbufptrptr
;
1928 varbufptr
= *varbufptrptr
;
1930 if ((a
= alist
->volattr
) != 0) {
1932 if (a
& ATTR_VOL_FSTYPE
) *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_vfc
->vfc_typenum
;
1933 if (a
& ATTR_VOL_SIGNATURE
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbSigWord
;
1934 if (a
& ATTR_VOL_SIZE
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->totalBlocks
* (off_t
)vcb
->blockSize
;
1935 if (a
& ATTR_VOL_SPACEFREE
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->freeBlocks
* (off_t
)vcb
->blockSize
;
1936 if (a
& ATTR_VOL_SPACEAVAIL
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->freeBlocks
* (off_t
)vcb
->blockSize
;
1937 if (a
& ATTR_VOL_MINALLOCATION
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->blockSize
;
1938 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) *((off_t
*)attrbufptr
)++ = (off_t
)(vcb
->vcbClpSiz
);
1939 if (a
& ATTR_VOL_IOBLOCKSIZE
) *((u_long
*)attrbufptr
)++ = (u_long
)hfsmp
->hfs_logBlockSize
;
1940 if (a
& ATTR_VOL_OBJCOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
+ (u_long
)vcb
->vcbDirCnt
;
1941 if (a
& ATTR_VOL_FILECOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
;
1942 if (a
& ATTR_VOL_DIRCOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbDirCnt
;
1943 if (a
& ATTR_VOL_MAXOBJCOUNT
) *((u_long
*)attrbufptr
)++ = 0xFFFFFFFF;
1944 if (a
& ATTR_VOL_MOUNTPOINT
) {
1945 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1946 ((struct attrreference
*)attrbufptr
)->attr_length
= strlen(mp
->mnt_stat
.f_mntonname
) + 1;
1947 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1948 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1949 (void) bcopy(mp
->mnt_stat
.f_mntonname
, varbufptr
, attrlength
);
1951 /* Advance beyond the space just allocated: */
1952 (char *)varbufptr
+= attrlength
;
1953 ++((struct attrreference
*)attrbufptr
);
1955 if (a
& ATTR_VOL_NAME
) {
1956 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1957 ((struct attrreference
*)attrbufptr
)->attr_length
= VTOH(root_vp
)->h_meta
->h_namelen
+ 1;
1958 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1959 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1960 bcopy(H_NAME(VTOH(root_vp
)), varbufptr
, attrlength
);
1962 /* Advance beyond the space just allocated: */
1963 (char *)varbufptr
+= attrlength
;
1964 ++((struct attrreference
*)attrbufptr
);
1966 if (a
& ATTR_VOL_MOUNTFLAGS
) *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_flag
;
1967 if (a
& ATTR_VOL_MOUNTEDDEVICE
) {
1968 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1969 ((struct attrreference
*)attrbufptr
)->attr_length
= strlen(mp
->mnt_stat
.f_mntfromname
) + 1;
1970 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1971 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1972 (void) bcopy(mp
->mnt_stat
.f_mntfromname
, varbufptr
, attrlength
);
1974 /* Advance beyond the space just allocated: */
1975 (char *)varbufptr
+= attrlength
;
1976 ++((struct attrreference
*)attrbufptr
);
1978 if (a
& ATTR_VOL_ENCODINGSUSED
) *((unsigned long long *)attrbufptr
)++ = (unsigned long long)vcb
->encodingsBitmap
;
1979 if (a
& ATTR_VOL_CAPABILITIES
) {
1980 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
1981 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1982 VOL_CAP_FMT_PERSISTENTOBJECTIDS
| VOL_CAP_FMT_SYMBOLICLINKS
| VOL_CAP_FMT_HARDLINKS
;
1983 } else { /* Plain HFS */
1984 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1985 VOL_CAP_FMT_PERSISTENTOBJECTIDS
;
1987 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_INTERFACES
] =
1988 VOL_CAP_INT_SEARCHFS
| VOL_CAP_INT_ATTRLIST
| VOL_CAP_INT_NFSEXPORT
| VOL_CAP_INT_READDIRATTR
;
1989 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
1990 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
1992 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_FORMAT
] =
1993 VOL_CAP_FMT_PERSISTENTOBJECTIDS
| VOL_CAP_FMT_SYMBOLICLINKS
| VOL_CAP_FMT_HARDLINKS
;
1994 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_INTERFACES
] =
1995 VOL_CAP_INT_SEARCHFS
| VOL_CAP_INT_ATTRLIST
| VOL_CAP_INT_NFSEXPORT
| VOL_CAP_INT_READDIRATTR
;
1996 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
1997 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
1999 ++((vol_capabilities_attr_t
*)attrbufptr
);
2001 if (a
& ATTR_VOL_ATTRIBUTES
) {
2002 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.commonattr
= ATTR_CMN_VALIDMASK
;
2003 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.volattr
= ATTR_VOL_VALIDMASK
;
2004 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.dirattr
= ATTR_DIR_VALIDMASK
;
2005 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.fileattr
= ATTR_FILE_VALIDMASK
;
2006 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.forkattr
= ATTR_FORK_VALIDMASK
;
2008 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.commonattr
= ATTR_CMN_VALIDMASK
;
2009 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.volattr
= ATTR_VOL_VALIDMASK
;
2010 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.dirattr
= ATTR_DIR_VALIDMASK
;
2011 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.fileattr
= ATTR_FILE_VALIDMASK
;
2012 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.forkattr
= ATTR_FORK_VALIDMASK
;
2014 ++((vol_attributes_attr_t
*)attrbufptr
);
2019 *attrbufptrptr
= attrbufptr
;
2020 *varbufptrptr
= varbufptr
;
2026 void PackVolumeInfo(struct attrlist
*alist
,
2027 struct vnode
*root_vp
,
2028 struct hfsCatalogInfo
*root_catinfo
,
2029 void **attrbufptrptr
,
2030 void **varbufptrptr
) {
2032 PackVolCommonAttributes(alist
, root_vp
, root_catinfo
, attrbufptrptr
, varbufptrptr
);
2033 PackVolAttributeBlock(alist
, root_vp
, root_catinfo
, attrbufptrptr
, varbufptrptr
);
2036 // Pack the common attribute contents of an objects hfsCatalogInfo
2037 void PackCommonCatalogInfoAttributeBlock(struct attrlist
*alist
,
2038 struct vnode
*root_vp
,
2039 struct hfsCatalogInfo
*catalogInfo
,
2040 void **attrbufptrptr
,
2041 void **varbufptrptr
)
2051 attrbufptr
= *attrbufptrptr
;
2052 varbufptr
= *varbufptrptr
;
2053 isHFSPlus
= (VTOVCB(root_vp
)->vcbSigWord
== kHFSPlusSigWord
);
2055 if ((a
= alist
->commonattr
) != 0)
2057 if (a
& ATTR_CMN_NAME
)
2059 attrlength
= strlen(catalogInfo
->nodeData
.cnm_nameptr
) + 1;
2060 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
2061 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2062 (void) strncpy((unsigned char *)varbufptr
,
2063 catalogInfo
->nodeData
.cnm_nameptr
, attrlength
);
2065 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2066 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2067 ++((struct attrreference
*)attrbufptr
);
2069 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = H_DEV(hp
);
2070 if (a
& ATTR_CMN_FSID
) {
2071 *((fsid_t
*)attrbufptr
) = VTOVFS(root_vp
)->mnt_stat
.f_fsid
;
2072 ++((fsid_t
*)attrbufptr
);
2074 if (a
& ATTR_CMN_OBJTYPE
)
2076 switch (catalogInfo
->nodeData
.cnd_type
) {
2077 case kCatalogFolderNode
:
2078 *((fsobj_type_t
*)attrbufptr
)++ = VDIR
;
2081 case kCatalogFileNode
:
2082 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2083 if ((HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) &&
2084 (catalogInfo
->nodeData
.cnd_mode
& IFMT
)) {
2085 *((fsobj_type_t
*)attrbufptr
)++ =
2086 IFTOVT((mode_t
)catalogInfo
->nodeData
.cnd_mode
);
2088 *((fsobj_type_t
*)attrbufptr
)++ = VREG
;
2093 *((fsobj_type_t
*)attrbufptr
)++ = VNON
;
2097 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = root_vp
->v_tag
;
2098 if (a
& ATTR_CMN_OBJID
)
2100 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= catalogInfo
->nodeData
.cnd_nodeID
;
2101 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2102 ++((fsobj_id_t
*)attrbufptr
);
2104 if (a
& ATTR_CMN_OBJPERMANENTID
)
2106 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= catalogInfo
->nodeData
.cnd_nodeID
;
2107 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2108 ++((fsobj_id_t
*)attrbufptr
);
2110 if (a
& ATTR_CMN_PAROBJID
)
2112 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= catalogInfo
->nodeData
.cnm_parID
;
2113 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2114 ++((fsobj_id_t
*)attrbufptr
);
2116 if (a
& ATTR_CMN_SCRIPT
)
2118 if (HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) {
2119 *((text_encoding_t
*)attrbufptr
)++ = catalogInfo
->nodeData
.cnd_textEncoding
;
2121 *((text_encoding_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_encoding
;
2124 if (a
& ATTR_CMN_CRTIME
)
2126 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_createDate
);
2127 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2128 ++((struct timespec
*)attrbufptr
);
2130 if (a
& ATTR_CMN_MODTIME
)
2132 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
2133 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2134 ++((struct timespec
*)attrbufptr
);
2136 if (a
& ATTR_CMN_CHGTIME
)
2138 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_attributeModDate
);
2139 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2140 ++((struct timespec
*)attrbufptr
);
2142 if (a
& ATTR_CMN_ACCTIME
)
2144 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_accessDate
);
2145 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2146 ++((struct timespec
*)attrbufptr
);
2148 if (a
& ATTR_CMN_BKUPTIME
)
2150 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_backupDate
);
2151 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2152 ++((struct timespec
*)attrbufptr
);
2154 if (a
& ATTR_CMN_FNDRINFO
)
2156 bcopy (&catalogInfo
->nodeData
.cnd_finderInfo
, attrbufptr
, sizeof(catalogInfo
->nodeData
.cnd_finderInfo
));
2157 (char *)attrbufptr
+= sizeof(catalogInfo
->nodeData
.cnd_finderInfo
);
2159 if (a
& ATTR_CMN_OWNERID
) {
2160 if ((VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) ||
2161 ((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)) {
2162 *((uid_t
*)attrbufptr
)++ =
2163 (VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
;
2165 *((uid_t
*)attrbufptr
)++ =
2166 (catalogInfo
->nodeData
.cnd_ownerID
== UNKNOWNUID
) ? console_user
: catalogInfo
->nodeData
.cnd_ownerID
;
2169 if (a
& ATTR_CMN_GRPID
) {
2170 if ((VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) ||
2171 ((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)) {
2172 *((gid_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_gid
;
2174 *((gid_t
*)attrbufptr
)++ = catalogInfo
->nodeData
.cnd_groupID
;
2177 if (a
& ATTR_CMN_ACCESSMASK
) {
2178 if (((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)
2179 #if OVERRIDE_UNKNOWN_PERMISSIONS
2180 || (VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)
2183 switch (catalogInfo
->nodeData
.cnd_type
) {
2184 case kCatalogFileNode
:
2185 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2186 *((u_long
*)attrbufptr
)++ = (u_long
)(IFREG
| (ACCESSPERMS
& (u_long
)(VTOHFS(root_vp
)->hfs_file_mask
)));
2189 case kCatalogFolderNode
:
2190 *((u_long
*)attrbufptr
)++ = (u_long
)(IFDIR
| (ACCESSPERMS
& (u_long
)(VTOHFS(root_vp
)->hfs_dir_mask
)));
2194 *((u_long
*)attrbufptr
)++ = (u_long
)((catalogInfo
->nodeData
.cnd_mode
& IFMT
) |
2195 VTOHFS(root_vp
)->hfs_dir_mask
);
2198 *((u_long
*)attrbufptr
)++ =
2199 (u_long
)catalogInfo
->nodeData
.cnd_mode
;
2202 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
2203 if (a
& ATTR_CMN_NAMEDATTRLIST
)
2206 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2207 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2209 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2210 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2211 ++((struct attrreference
*)attrbufptr
);
2213 if (a
& ATTR_CMN_FLAGS
) {
2214 if (catalogInfo
->nodeData
.cnd_mode
& IFMT
) {
2215 if (catalogInfo
->nodeData
.cnd_flags
& kHFSFileLockedMask
) {
2216 *((u_long
*)attrbufptr
)++ =
2217 (u_long
) (catalogInfo
->nodeData
.cnd_ownerFlags
|
2218 (catalogInfo
->nodeData
.cnd_adminFlags
<< 16)) |
2221 *((u_long
*)attrbufptr
)++ =
2222 (u_long
) (catalogInfo
->nodeData
.cnd_ownerFlags
|
2223 (catalogInfo
->nodeData
.cnd_adminFlags
<< 16)) & ~UF_IMMUTABLE
;
2226 /* The information in the node flag fields is not valid: */
2227 *((u_long
*)attrbufptr
)++ =
2228 (catalogInfo
->nodeData
.cnd_flags
& kHFSFileLockedMask
) ? UF_IMMUTABLE
: 0;
2231 if (a
& ATTR_CMN_USERACCESS
) {
2232 if ((VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) ||
2233 ((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)) {
2234 *((u_long
*)attrbufptr
)++ =
2235 DerivePermissionSummary((VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
,
2236 VTOHFS(root_vp
)->hfs_gid
,
2237 #if OVERRIDE_UNKNOWN_PERMISSIONS
2238 (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) ? VTOHFS(root_vp
)->hfs_file_mask
: VTOHFS(root_vp
)->hfs_dir_mask
,
2240 (catalogInfo
->nodeData
.cnd_mode
& IFMT
) ?
2241 (u_long
)catalogInfo
->nodeData
.cnd_mode
:
2242 ((catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) ?
2243 VTOHFS(root_vp
)->hfs_file_mask
:
2244 VTOHFS(root_vp
)->hfs_dir_mask
),
2247 current_proc()->p_ucred
,
2250 *((u_long
*)attrbufptr
)++ =
2251 DerivePermissionSummary((catalogInfo
->nodeData
.cnd_ownerID
== UNKNOWNUID
) ? console_user
: catalogInfo
->nodeData
.cnd_ownerID
,
2252 catalogInfo
->nodeData
.cnd_groupID
,
2253 (mode_t
)catalogInfo
->nodeData
.cnd_mode
,
2255 current_proc()->p_ucred
,
2261 *attrbufptrptr
= attrbufptr
;
2262 *varbufptrptr
= varbufptr
;
2266 void PackCommonAttributeBlock(struct attrlist
*alist
,
2268 struct hfsCatalogInfo
*catInfo
,
2269 void **attrbufptrptr
,
2270 void **varbufptrptr
) {
2279 attrbufptr
= *attrbufptrptr
;
2280 varbufptr
= *varbufptrptr
;
2282 if ((a
= alist
->commonattr
) != 0) {
2283 if (a
& ATTR_CMN_NAME
) {
2284 PackObjectName(vp
, H_NAME(hp
), hp
->h_meta
->h_namelen
, &attrbufptr
, &varbufptr
);
2286 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = H_DEV(hp
);
2287 if (a
& ATTR_CMN_FSID
) {
2288 *((fsid_t
*)attrbufptr
) = VTOVFS(vp
)->mnt_stat
.f_fsid
;
2289 ++((fsid_t
*)attrbufptr
);
2291 if (a
& ATTR_CMN_OBJTYPE
) *((fsobj_type_t
*)attrbufptr
)++ = vp
->v_type
;
2292 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = vp
->v_tag
;
2293 if (a
& ATTR_CMN_OBJID
) {
2294 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= H_FILEID(hp
);
2295 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2296 ++((fsobj_id_t
*)attrbufptr
);
2298 if (a
& ATTR_CMN_OBJPERMANENTID
) {
2299 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= H_FILEID(hp
);
2300 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2301 ++((fsobj_id_t
*)attrbufptr
);
2303 if (a
& ATTR_CMN_PAROBJID
) {
2304 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= H_DIRID(hp
);
2305 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2306 ++((fsobj_id_t
*)attrbufptr
);
2308 if (a
& ATTR_CMN_SCRIPT
)
2310 if (HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) {
2311 *((text_encoding_t
*)attrbufptr
)++ = catInfo
->nodeData
.cnd_textEncoding
;
2313 *((text_encoding_t
*)attrbufptr
)++ = VTOHFS(vp
)->hfs_encoding
;
2316 if (a
& ATTR_CMN_CRTIME
) {
2317 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_crtime
;
2318 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2319 ++((struct timespec
*)attrbufptr
);
2321 if (a
& ATTR_CMN_MODTIME
) {
2322 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_mtime
;
2323 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2324 ++((struct timespec
*)attrbufptr
);
2326 if (a
& ATTR_CMN_CHGTIME
) {
2327 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_ctime
;
2328 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2329 ++((struct timespec
*)attrbufptr
);
2331 if (a
& ATTR_CMN_ACCTIME
) {
2332 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_atime
;
2333 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2334 ++((struct timespec
*)attrbufptr
);
2336 if (a
& ATTR_CMN_BKUPTIME
) {
2337 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_butime
;
2338 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2339 ++((struct timespec
*)attrbufptr
);
2341 if (a
& ATTR_CMN_FNDRINFO
) {
2342 bcopy (&catInfo
->nodeData
.cnd_finderInfo
, attrbufptr
, sizeof(catInfo
->nodeData
.cnd_finderInfo
));
2343 (char *)attrbufptr
+= sizeof(catInfo
->nodeData
.cnd_finderInfo
);
2345 if (a
& ATTR_CMN_OWNERID
) {
2346 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2347 *((uid_t
*)attrbufptr
)++ =
2348 (VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(vp
)->hfs_uid
;
2350 *((uid_t
*)attrbufptr
)++ =
2351 (hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: hp
->h_meta
->h_uid
;
2354 if (a
& ATTR_CMN_GRPID
) {
2355 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2356 *((gid_t
*)attrbufptr
)++ = VTOHFS(vp
)->hfs_gid
;
2358 *((gid_t
*)attrbufptr
)++ = hp
->h_meta
->h_gid
;
2361 if (a
& ATTR_CMN_ACCESSMASK
) *((u_long
*)attrbufptr
)++ = (u_long
)hp
->h_meta
->h_mode
;
2362 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
2363 if (a
& ATTR_CMN_NAMEDATTRLIST
) {
2365 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2366 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2368 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2369 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2370 ++((struct attrreference
*)attrbufptr
);
2372 if (a
& ATTR_CMN_FLAGS
) *((u_long
*)attrbufptr
)++ = hp
->h_meta
->h_pflags
;
2373 if (a
& ATTR_CMN_USERACCESS
) {
2374 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2375 *((u_long
*)attrbufptr
)++ =
2376 DerivePermissionSummary((VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(vp
)->hfs_uid
,
2377 VTOHFS(vp
)->hfs_gid
,
2380 current_proc()->p_ucred
,
2383 *((u_long
*)attrbufptr
)++ =
2384 DerivePermissionSummary((hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: hp
->h_meta
->h_uid
,
2388 current_proc()->p_ucred
,
2394 *attrbufptrptr
= attrbufptr
;
2395 *varbufptrptr
= varbufptr
;
2399 // Pack the directory attributes given hfsCatalogInfo
2400 void PackCatalogInfoDirAttributeBlock( struct attrlist
*alist
, struct vnode
*vp
,
2401 struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2407 attrbufptr
= *attrbufptrptr
;
2410 if ( (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) && (a
!= 0) ) {
2411 valence
= catInfo
->nodeData
.cnd_valence
;
2412 if ((catInfo
->nodeData
.cnm_parID
== kRootParID
) &&
2413 (VTOHFS(vp
)->hfs_private_metadata_dir
!= 0)) {
2414 --valence
; /* hide private dir */
2416 /* The 'link count' is faked */
2417 if (a
& ATTR_DIR_LINKCOUNT
)
2418 *((u_long
*)attrbufptr
)++ = 2 + valence
;
2419 if (a
& ATTR_DIR_ENTRYCOUNT
)
2420 *((u_long
*)attrbufptr
)++ = valence
;
2421 if (a
& ATTR_DIR_MOUNTSTATUS
)
2422 *((u_long
*)attrbufptr
)++ = 0;
2425 *attrbufptrptr
= attrbufptr
;
2429 void PackDirAttributeBlock(struct attrlist
*alist
,
2431 struct hfsCatalogInfo
*catInfo
,
2432 void **attrbufptrptr
,
2433 void **varbufptrptr
) {
2438 attrbufptr
= *attrbufptrptr
;
2441 if ((vp
->v_type
== VDIR
) && (a
!= 0)) {
2442 valence
= catInfo
->nodeData
.cnd_valence
;
2443 if ((catInfo
->nodeData
.cnm_parID
== kRootParID
) &&
2444 (VTOHFS(vp
)->hfs_private_metadata_dir
!= 0)) {
2445 --valence
; /* hide private dir */
2448 /* The 'link count' is faked */
2449 if (a
& ATTR_DIR_LINKCOUNT
)
2450 *((u_long
*)attrbufptr
)++ = 2 + valence
;
2451 if (a
& ATTR_DIR_ENTRYCOUNT
)
2452 *((u_long
*)attrbufptr
)++ = valence
;
2453 if (a
& ATTR_DIR_MOUNTSTATUS
) {
2454 if (vp
->v_mountedhere
) {
2455 *((u_long
*)attrbufptr
)++ = DIR_MNTSTATUS_MNTPOINT
;
2457 *((u_long
*)attrbufptr
)++ = 0;
2462 *attrbufptrptr
= attrbufptr
;
2467 // Pack the file attributes from the hfsCatalogInfo for the file.
2468 void PackCatalogInfoFileAttributeBlock( struct attrlist
*alist
, struct vnode
*root_vp
, struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2474 ExtendedVCB
*vcb
= VTOVCB(root_vp
);
2476 attrbufptr
= *attrbufptrptr
;
2477 varbufptr
= *varbufptrptr
;
2479 a
= alist
->fileattr
;
2480 if ( (catInfo
->nodeData
.cnd_type
== kCatalogFileNode
) && (a
!= 0) )
2483 if (a
& ATTR_FILE_LINKCOUNT
) {
2484 u_long linkcnt
= catInfo
->nodeData
.cnd_linkCount
;
2488 *((u_long
*)attrbufptr
)++ = linkcnt
;
2491 if (a
& ATTR_FILE_LINKCOUNT
) *((u_long
*)attrbufptr
)++ = 1;
2493 if (a
& ATTR_FILE_TOTALSIZE
) {
2494 *((off_t
*)attrbufptr
)++ =
2495 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
+
2496 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2498 if (a
& ATTR_FILE_ALLOCSIZE
) {
2499 *((off_t
*)attrbufptr
)++ =
2500 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
) +
2501 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2503 if (a
& ATTR_FILE_IOBLOCKSIZE
) {
2504 *((u_long
*)attrbufptr
)++ = (u_long
)(VTOHFS(root_vp
)->hfs_logBlockSize
);
2506 if (a
& ATTR_FILE_CLUMPSIZE
) {
2507 *((u_long
*)attrbufptr
)++ = vcb
->vcbClpSiz
;
2509 if (a
& ATTR_FILE_DEVTYPE
) {
2513 filetype
= (catInfo
->nodeData
.cnd_mode
& IFMT
);
2514 if (filetype
== IFCHR
|| filetype
== IFBLK
)
2515 rawdev
= (u_long
)catInfo
->nodeData
.cnd_rawDevice
;
2519 *((u_long
*)attrbufptr
)++ = rawdev
;
2521 if (a
& ATTR_FILE_FILETYPE
) {
2522 *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD */
2524 if (a
& ATTR_FILE_FORKCOUNT
) {
2525 *((u_long
*)attrbufptr
)++ = 2; /* XXX PPD */
2527 if (a
& ATTR_FILE_FORKLIST
) {
2529 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2530 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2532 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2533 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2534 ++((struct attrreference
*)attrbufptr
);
2536 if (a
& ATTR_FILE_DATALENGTH
) {
2537 *((off_t
*)attrbufptr
)++ =
2538 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
;
2540 if (a
& ATTR_FILE_DATAALLOCSIZE
) {
2541 *((off_t
*)attrbufptr
)++ =
2542 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2544 if (a
& ATTR_FILE_DATAEXTENTS
) {
2545 bcopy(&catInfo
->nodeData
.cnd_datafork
.extents
, attrbufptr
, sizeof(extentrecord
));
2546 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2548 if (a
& ATTR_FILE_RSRCLENGTH
) {
2549 *((off_t
*)attrbufptr
)++ =
2550 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2552 if (a
& ATTR_FILE_RSRCALLOCSIZE
) {
2553 *((off_t
*)attrbufptr
)++ =
2554 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2556 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2557 bcopy(&catInfo
->nodeData
.cnd_rsrcfork
.extents
, attrbufptr
, sizeof(extentrecord
));
2558 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2562 *attrbufptrptr
= attrbufptr
;
2563 *varbufptrptr
= varbufptr
;
2567 void PackFileAttributeBlock(struct attrlist
*alist
,
2569 struct hfsCatalogInfo
*catInfo
,
2570 void **attrbufptrptr
,
2571 void **varbufptrptr
) {
2572 struct hfsnode
*hp
= VTOH(vp
);
2573 FCB
*fcb
= HTOFCB(hp
);
2574 ExtendedVCB
*vcb
= HTOVCB(hp
);
2575 Boolean isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
2576 void *attrbufptr
= *attrbufptrptr
;
2577 void *varbufptr
= *varbufptrptr
;
2578 attrgroup_t a
= alist
->fileattr
;
2583 if (a
& ATTR_FILE_LINKCOUNT
) {
2584 u_long linkcnt
= catInfo
->nodeData
.cnd_linkCount
;
2588 *((u_long
*)attrbufptr
)++ = linkcnt
;
2591 if (a
& ATTR_FILE_LINKCOUNT
) *((u_long
*)attrbufptr
)++ = 1;
2593 if (a
& ATTR_FILE_TOTALSIZE
) {
2594 *((off_t
*)attrbufptr
)++ =
2595 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
+
2596 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2598 if (a
& ATTR_FILE_ALLOCSIZE
) {
2599 switch (H_FORKTYPE(hp
)) {
2601 *((off_t
*)attrbufptr
)++ =
2602 (off_t
)fcb
->fcbPLen
+
2603 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2606 *((off_t
*)attrbufptr
)++ =
2607 (off_t
)fcb
->fcbPLen
+
2608 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2611 *((off_t
*)attrbufptr
)++ =
2612 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
) +
2613 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2616 if (a
& ATTR_FILE_IOBLOCKSIZE
) *((u_long
*)attrbufptr
)++ = GetLogicalBlockSize(vp
);
2617 if (a
& ATTR_FILE_CLUMPSIZE
) *((u_long
*)attrbufptr
)++ = fcb
->fcbClmpSize
;
2618 if (a
& ATTR_FILE_DEVTYPE
) {
2621 if ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))
2622 rawdev
= (u_long
)catInfo
->nodeData
.cnd_rawDevice
;
2625 *((u_long
*)attrbufptr
)++ = rawdev
;
2627 if (a
& ATTR_FILE_FILETYPE
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD */
2628 if (a
& ATTR_FILE_FORKCOUNT
) *((u_long
*)attrbufptr
)++ = 2; /* XXX PPD */
2629 if (a
& ATTR_FILE_FORKLIST
) {
2631 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2632 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2634 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2635 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2636 ++((struct attrreference
*)attrbufptr
);
2638 if (H_FORKTYPE(hp
) == kDataFork
) {
2639 if (a
& ATTR_FILE_DATALENGTH
)
2640 *((off_t
*)attrbufptr
)++ = fcb
->fcbEOF
;
2641 if (a
& ATTR_FILE_DATAALLOCSIZE
) *((off_t
*)attrbufptr
)++ = fcb
->fcbPLen
;
2642 if (a
& ATTR_FILE_DATAEXTENTS
) {
2643 bcopy ( fcb
->fcbExtents
, attrbufptr
, sizeof(extentrecord
));
2644 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2647 if (a
& ATTR_FILE_DATALENGTH
) {
2648 *((off_t
*)attrbufptr
)++ =
2649 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
;
2651 if (a
& ATTR_FILE_DATAALLOCSIZE
) {
2652 *((off_t
*)attrbufptr
)++ =
2653 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2655 if (a
& ATTR_FILE_DATAEXTENTS
) {
2656 bcopy(&catInfo
->nodeData
.cnd_datafork
.extents
, attrbufptr
, sizeof(extentrecord
));
2657 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2660 if (H_FORKTYPE(hp
) == kRsrcFork
) {
2661 if (a
& ATTR_FILE_RSRCLENGTH
)
2662 *((off_t
*)attrbufptr
)++ = fcb
->fcbEOF
;
2663 if (a
& ATTR_FILE_RSRCALLOCSIZE
) *((off_t
*)attrbufptr
)++ = fcb
->fcbPLen
;
2664 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2665 bcopy ( fcb
->fcbExtents
, attrbufptr
, sizeof(extentrecord
));
2666 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2669 if (a
& ATTR_FILE_RSRCLENGTH
) {
2670 *((off_t
*)attrbufptr
)++ =
2671 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2673 if (a
& ATTR_FILE_RSRCALLOCSIZE
) {
2674 *((off_t
*)attrbufptr
)++ =
2675 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2677 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2678 bcopy(&catInfo
->nodeData
.cnd_rsrcfork
.extents
, attrbufptr
, sizeof(extentrecord
));
2679 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2684 *attrbufptrptr
= attrbufptr
;
2685 *varbufptrptr
= varbufptr
;
2689 void PackForkAttributeBlock(struct attrlist
*alist
,
2691 struct hfsCatalogInfo
*catInfo
,
2692 void **attrbufptrptr
,
2693 void **varbufptrptr
) {
2699 // This routine takes catInfo, and alist, as inputs and packs it into an attribute block.
2700 void PackCatalogInfoAttributeBlock ( struct attrlist
*alist
, struct vnode
*root_vp
, struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2702 //XXX Preflight that alist only contains bits with fields in catInfo
2704 PackCommonCatalogInfoAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2706 switch ( catInfo
->nodeData
.cnd_type
)
2708 case kCatalogFolderNode
:
2709 PackCatalogInfoDirAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2712 case kCatalogFileNode
:
2713 PackCatalogInfoFileAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2716 default: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR not being handled... */
2717 /* XXX PPD - Panic? */
2724 void PackAttributeBlock(struct attrlist
*alist
,
2726 struct hfsCatalogInfo
*catInfo
,
2727 void **attrbufptrptr
,
2728 void **varbufptrptr
)
2730 if (alist
->volattr
!= 0) {
2731 DBG_ASSERT((vp
->v_flag
& VROOT
) != 0);
2732 PackVolumeInfo(alist
,vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2734 PackCommonAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2736 switch (vp
->v_type
) {
2738 PackDirAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2743 PackFileAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2746 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
2747 not being handled...
2750 /* XXX PPD - Panic? */
2758 void UnpackVolumeAttributeBlock(struct attrlist
*alist
,
2759 struct vnode
*root_vp
,
2761 void **attrbufptrptr
,
2762 void **varbufptrptr
) {
2763 void *attrbufptr
= *attrbufptrptr
;
2766 if ((alist
->commonattr
== 0) && (alist
->volattr
== 0)) {
2767 return; /* Get out without dirtying the VCB */
2772 a
= alist
->commonattr
;
2774 if (a
& ATTR_CMN_SCRIPT
) {
2775 vcb
->volumeNameEncodingHint
= (u_int32_t
)*(((text_encoding_t
*)attrbufptr
)++);
2777 a
&= ~ATTR_CMN_SCRIPT
;
2780 if (a
& ATTR_CMN_CRTIME
) {
2781 vcb
->vcbCrDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2782 /* Need to update the local time also */
2783 vcb
->localCreateDate
= UTCToLocal(vcb
->vcbCrDate
);
2784 ++((struct timespec
*)attrbufptr
);
2786 a
&= ~ATTR_CMN_CRTIME
;
2789 if (a
& ATTR_CMN_MODTIME
) {
2790 vcb
->vcbLsMod
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2791 ++((struct timespec
*)attrbufptr
);
2793 a
&= ~ATTR_CMN_MODTIME
;
2796 if (a
& ATTR_CMN_BKUPTIME
) {
2797 vcb
->vcbVolBkUp
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2798 ++((struct timespec
*)attrbufptr
);
2800 a
&= ~ATTR_CMN_BKUPTIME
;
2803 if (a
& ATTR_CMN_FNDRINFO
) {
2804 bcopy (attrbufptr
, &vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
2805 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
2807 a
&= ~ATTR_CMN_FNDRINFO
;
2811 DBG_ASSERT(a
== 0); /* All common attributes for volumes must've been handled by now... */
2813 a
= alist
->volattr
& ~ATTR_VOL_INFO
;
2814 if (a
& ATTR_VOL_NAME
) {
2815 copystr(((char *)attrbufptr
) + *((u_long
*)attrbufptr
), vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
2816 (char *)attrbufptr
+= sizeof(struct attrreference
);
2818 a
&= ~ATTR_VOL_NAME
;
2822 DBG_ASSERT(a
== 0); /* All common attributes for volumes must've been handled by now... */
2824 vcb
->vcbFlags
|= 0xFF00; // Mark the VCB dirty
2830 void UnpackCommonAttributeBlock(struct attrlist
*alist
,
2832 struct hfsCatalogInfo
*catInfo
,
2833 void **attrbufptrptr
,
2834 void **varbufptrptr
) {
2835 struct hfsnode
*hp
= VTOH(vp
);
2839 attrbufptr
= *attrbufptrptr
;
2841 DBG_ASSERT(catInfo
!= NULL
);
2843 a
= alist
->commonattr
;
2844 if (a
& ATTR_CMN_SCRIPT
) {
2845 catInfo
->nodeData
.cnd_textEncoding
= (u_int32_t
)*((text_encoding_t
*)attrbufptr
)++;
2846 UpdateVolumeEncodings(VTOVCB(vp
), catInfo
->nodeData
.cnd_textEncoding
); /* Update the volume encoding */
2848 a
&= ~ATTR_CMN_SCRIPT
;
2851 if (a
& ATTR_CMN_CRTIME
) {
2852 catInfo
->nodeData
.cnd_createDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2853 VTOH(vp
)->h_meta
->h_crtime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2854 ++((struct timespec
*)attrbufptr
);
2856 a
&= ~ATTR_CMN_CRTIME
;
2859 if (a
& ATTR_CMN_MODTIME
) {
2860 catInfo
->nodeData
.cnd_contentModDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2861 VTOH(vp
)->h_meta
->h_mtime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2862 ++((struct timespec
*)attrbufptr
);
2863 hp
->h_nodeflags
&= ~IN_UPDATE
;
2865 a
&= ~ATTR_CMN_MODTIME
;
2868 if (a
& ATTR_CMN_CHGTIME
) {
2869 catInfo
->nodeData
.cnd_attributeModDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2870 VTOH(vp
)->h_meta
->h_ctime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2871 ++((struct timespec
*)attrbufptr
);
2872 hp
->h_nodeflags
&= ~IN_CHANGE
;
2874 a
&= ~ATTR_CMN_CHGTIME
;
2877 if (a
& ATTR_CMN_ACCTIME
) {
2878 catInfo
->nodeData
.cnd_accessDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2879 VTOH(vp
)->h_meta
->h_atime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2880 ++((struct timespec
*)attrbufptr
);
2881 hp
->h_nodeflags
&= ~IN_ACCESS
;
2883 a
&= ~ATTR_CMN_ACCTIME
;
2886 if (a
& ATTR_CMN_BKUPTIME
) {
2887 catInfo
->nodeData
.cnd_backupDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2888 VTOH(vp
)->h_meta
->h_butime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2889 ++((struct timespec
*)attrbufptr
);
2891 a
&= ~ATTR_CMN_BKUPTIME
;
2894 if (a
& ATTR_CMN_FNDRINFO
) {
2895 bcopy (attrbufptr
, &catInfo
->nodeData
.cnd_finderInfo
, sizeof(catInfo
->nodeData
.cnd_finderInfo
));
2896 (char *)attrbufptr
+= sizeof(catInfo
->nodeData
.cnd_finderInfo
);
2898 a
&= ~ATTR_CMN_FNDRINFO
;
2901 if (a
& ATTR_CMN_OWNERID
) {
2902 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2903 u_int32_t uid
= (u_int32_t
)*((uid_t
*)attrbufptr
)++;
2904 if (uid
!= (uid_t
)VNOVAL
)
2905 hp
->h_meta
->h_uid
= uid
; /* catalog will get updated by hfs_chown() */
2908 ((uid_t
*)attrbufptr
)++;
2911 a
&= ~ATTR_CMN_OWNERID
;
2914 if (a
& ATTR_CMN_GRPID
) {
2915 u_int32_t gid
= (u_int32_t
)*((gid_t
*)attrbufptr
)++;
2916 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2917 if (gid
!= (gid_t
)VNOVAL
)
2918 hp
->h_meta
->h_gid
= gid
; /* catalog will get updated by hfs_chown() */
2921 a
&= ~ATTR_CMN_GRPID
;
2924 if (a
& ATTR_CMN_ACCESSMASK
) {
2925 u_int16_t mode
= (u_int16_t
)*((u_long
*)attrbufptr
)++;
2926 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2927 if (mode
!= (mode_t
)VNOVAL
) {
2928 hp
->h_meta
->h_mode
&= ~ALLPERMS
;
2929 hp
->h_meta
->h_mode
|= (mode
& ALLPERMS
); /* catalog will get updated by hfs_chmod() */
2933 a
&= ~ATTR_CMN_ACCESSMASK
;
2936 if (a
& ATTR_CMN_FLAGS
) {
2937 u_long flags
= *((u_long
*)attrbufptr
)++;
2938 /* Flags are settable only on HFS+ volumes. A special exception is made for the IMMUTABLE
2939 flags (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on HFS volumes as well: */
2940 if ((VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) ||
2941 ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) && ((flags
& ~IMMUTABLE
) == 0))) {
2942 if (flags
!= (u_long
)VNOVAL
) {
2943 hp
->h_meta
->h_pflags
= flags
; /* catalog will get updated by hfs_chflags */
2947 a
&= ~ATTR_CMN_FLAGS
;
2953 DEBUG_BREAK_MSG(("UnpackCommonAttributes: unhandled bit: 0x%08X\n", a
));
2957 *attrbufptrptr
= attrbufptr
;
2958 // *varbufptrptr = varbufptr;
2964 void UnpackDirAttributeBlock(struct attrlist
*alist
,
2966 struct hfsCatalogInfo
*catInfo
,
2967 void **attrbufptrptr
,
2968 void **varbufptrptr
) {
2974 attrbufptr
= *attrbufptrptr
;
2975 varbufptr
= *varbufptrptr
;
2979 *attrbufptrptr
= attrbufptr
;
2980 *varbufptrptr
= varbufptr
;
2987 void UnpackFileAttributeBlock(struct attrlist
*alist
,
2989 struct hfsCatalogInfo
*catInfo
,
2990 void **attrbufptrptr
,
2991 void **varbufptrptr
) {
2997 attrbufptr
= *attrbufptrptr
;
2998 varbufptr
= *varbufptrptr
;
3002 *attrbufptrptr
= attrbufptr
;
3003 *varbufptrptr
= varbufptr
;
3010 void UnpackForkAttributeBlock(struct attrlist
*alist
,
3012 struct hfsCatalogInfo
*catInfo
,
3013 void **attrbufptrptr
,
3014 void **varbufptrptr
) {
3020 attrbufptr
= *attrbufptrptr
;
3021 varbufptr
= *varbufptrptr
;
3025 *attrbufptrptr
= attrbufptr
;
3026 *varbufptrptr
= varbufptr
;
3032 void UnpackAttributeBlock(struct attrlist
*alist
,
3034 struct hfsCatalogInfo
*catInfo
,
3035 void **attrbufptrptr
,
3036 void **varbufptrptr
) {
3039 if (alist
->volattr
!= 0) {
3040 UnpackVolumeAttributeBlock(alist
, vp
, VTOVCB(vp
), attrbufptrptr
, varbufptrptr
);
3044 /* We're dealing with a vnode object here: */
3045 UnpackCommonAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3048 switch (vp
->v_type
) {
3050 UnpackDirAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3054 /* case VCPLX: */ /* XXX PPD TBC */
3055 UnpackFileAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3059 UnpackForkAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3062 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
3063 not being handled...
3066 /* XXX PPD - Panic? */
3074 unsigned long BestBlockSizeFit(unsigned long allocationBlockSize
,
3075 unsigned long blockSizeLimit
,
3076 unsigned long baseMultiple
) {
3078 Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the
3079 specified limit but still an even multiple of the baseMultiple.
3081 int baseBlockCount
, blockCount
;
3082 unsigned long trialBlockSize
;
3084 if (allocationBlockSize
% baseMultiple
!= 0) {
3086 Whoops: the allocation blocks aren't even multiples of the specified base:
3087 no amount of dividing them into even parts will be a multiple, either then!
3089 return 512; /* Hope for the best */
3092 /* Try the obvious winner first, to prevent 12K allocation blocks, for instance,
3093 from being handled as two 6K logical blocks instead of 3 4K logical blocks.
3094 Even though the former (the result of the loop below) is the larger allocation
3095 block size, the latter is more efficient: */
3096 if (allocationBlockSize
% PAGE_SIZE
== 0) return PAGE_SIZE
;
3098 /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */
3099 baseBlockCount
= allocationBlockSize
/ baseMultiple
; /* Now guaranteed to be an even multiple */
3101 for (blockCount
= baseBlockCount
; blockCount
> 0; --blockCount
) {
3102 trialBlockSize
= blockCount
* baseMultiple
;
3103 if (allocationBlockSize
% trialBlockSize
== 0) { /* An even multiple? */
3104 if ((trialBlockSize
<= blockSizeLimit
) &&
3105 (trialBlockSize
% baseMultiple
== 0)) {
3106 return trialBlockSize
;
3111 /* Note: we should never get here, since blockCount = 1 should always work,
3112 but this is nice and safe and makes the compiler happy, too ... */
3118 * To make the HFS Plus filesystem follow UFS unlink semantics, a remove
3119 * of an active vnode is translated to a move/rename so the file appears
3120 * deleted. The destination folder for these move/renames is setup here
3121 * and a reference to it is place in hfsmp->hfs_private_metadata_dir.
3124 FindMetaDataDirectory(ExtendedVCB
*vcb
)
3127 hfsCatalogInfo catInfo
;
3128 HFSCatalogNodeID dirID
;
3129 u_int32_t metadata_createdate
;
3132 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
3136 metadata_createdate
= 0;
3137 strncpy(namep
, HFSPLUS_PRIVATE_DIR
, sizeof(namep
));
3138 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
3139 catInfo
.hint
= kNoHint
;
3141 /* lock catalog b-tree */
3142 retval
= hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_SHARED
, current_proc());
3143 if (retval
) goto Err_Exit
;
3145 if (hfs_getcatalog(vcb
, kRootDirID
, namep
, -1, &catInfo
) == 0) {
3146 dirID
= catInfo
.nodeData
.cnd_nodeID
;
3147 metadata_createdate
= catInfo
.nodeData
.cnd_createDate
;
3148 } else if (VCBTOHFS(vcb
)->hfs_fs_ronly
== 0) {
3149 if (CreateCatalogNode(vcb
, kRootDirID
, namep
, kCatalogFolderNode
, &dirID
, &catInfo
.hint
, 0) == 0) {
3150 catInfo
.hint
= kNoHint
;
3151 if (hfs_getcatalog(vcb
, kRootDirID
, namep
, -1, &catInfo
) == 0) {
3153 /* create date is later used for validation */
3154 catInfo
.nodeData
.cnd_createDate
= vcb
->vcbCrDate
;
3155 metadata_createdate
= catInfo
.nodeData
.cnd_createDate
;
3157 /* directory with no permissions owned by root */
3158 catInfo
.nodeData
.cnd_mode
= IFDIR
;
3159 catInfo
.nodeData
.cnd_adminFlags
= (SF_IMMUTABLE
>> 16);
3161 /* hidden and off the desktop view */
3162 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frLocation
.v
= SWAP_BE16 (22460);
3163 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frLocation
.h
= SWAP_BE16 (22460);
3164 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frFlags
|= SWAP_BE16 (kIsInvisible
+ kNameLocked
);
3166 (void) UpdateCatalogNode(vcb
, kRootDirID
, namep
, catInfo
.hint
, &catInfo
.nodeData
);
3171 /* unlock catalog b-tree */
3172 (void) hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3174 VCBTOHFS(vcb
)->hfs_metadata_createdate
= metadata_createdate
;
3176 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3183 RemovedMetaDataDirectory(ExtendedVCB
*vcb
)
3186 hfsCatalogInfo catInfo
;
3189 strncpy(name
, HFSPLUS_PRIVATE_DIR
, sizeof(name
));
3190 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
3192 /* lock catalog b-tree */
3193 retval
= hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_SHARED
, current_proc());
3194 if (retval
) goto Err_Exit
;
3196 /* If the HFSPLUSMETADATAFOLDER exists then delete it. */
3197 retval
= GetCatalogNode(vcb
, kRootDirID
, name
, strlen(name
), kNoHint
,
3198 &catInfo
.nodeData
, &catInfo
.hint
);
3199 if (retval
== 0 && (catInfo
.nodeData
.cnd_type
== kCatalogFolderNode
)) {
3200 (void) DeleteCatalogNode(vcb
, kRootDirID
, name
, catInfo
.hint
);
3201 printf("hfs_mount: removed \"%s\" from hfs volume \"%s\"\n", name
, vcb
->vcbVN
);
3204 /* unlock catalog b-tree */
3205 (void) hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3208 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3212 * This will return the correct logical block size for a given vnode.
3213 * For most files, it is the allocation block size, for meta data like
3214 * BTrees, this is kept as part of the BTree private nodeSize
3217 GetLogicalBlockSize(struct vnode
*vp
)
3219 u_int32_t logBlockSize
;
3221 DBG_ASSERT(vp
!= NULL
);
3223 /* start with default */
3224 logBlockSize
= VTOHFS(vp
)->hfs_logBlockSize
;
3226 if (vp
->v_flag
& VSYSTEM
) {
3227 if (VTOH(vp
)->fcbBTCBPtr
!= NULL
) {
3228 BTreeInfoRec bTreeInfo
;
3231 * We do not lock the BTrees, because if we are getting block..then the tree
3232 * should be locked in the first place.
3233 * We just want the nodeSize wich will NEVER change..so even if the world
3234 * is changing..the nodeSize should remain the same. Which argues why lock
3235 * it in the first place??
3238 (void) BTGetInformation (VTOFCB(vp
), kBTreeInfoVersion
, &bTreeInfo
);
3240 logBlockSize
= bTreeInfo
.nodeSize
;
3242 } else if (H_FILEID(VTOH(vp
)) == kHFSAllocationFileID
) {
3243 logBlockSize
= VTOVCB(vp
)->vcbVBMIOSize
;
3247 DBG_ASSERT(logBlockSize
> 0);
3249 return logBlockSize
;
3253 * Map HFS Common errors (negative) to BSD error codes (positive).
3254 * Positive errors (ie BSD errors) are passed through unchanged.
3256 short MacToVFSError(OSErr err
)
3260 DBG_ERR(("MacToVFSError: passing error #%d unchanged...\n", err
));
3266 DBG_ERR(("MacToVFSError: mapping error code %d...\n", err
));
3270 case dirFulErr
: /* -33 */
3271 case dskFulErr
: /* -34 */
3272 case btNoSpaceAvail
: /* -32733 */
3273 case fxOvFlErr
: /* -32750 */
3274 return ENOSPC
; /* +28 */
3276 case btBadNode
: /* -32731 */
3277 case ioErr
: /* -36 */
3278 return EIO
; /* +5 */
3280 case mFulErr
: /* -41 */
3281 case memFullErr
: /* -108 */
3282 return ENOMEM
; /* +12 */
3284 case tmfoErr
: /* -42 */
3285 /* Consider EMFILE (Too many open files, 24)? */
3286 return ENFILE
; /* +23 */
3288 case nsvErr
: /* -35 */
3289 case fnfErr
: /* -43 */
3290 case dirNFErr
: /* -120 */
3291 case fidNotFound
: /* -1300 */
3292 return ENOENT
; /* +2 */
3294 case wPrErr
: /* -44 */
3295 case vLckdErr
: /* -46 */
3296 case fsDSIntErr
: /* -127 */
3297 return EROFS
; /* +30 */
3299 case opWrErr
: /* -49 */
3300 case fLckdErr
: /* -45 */
3301 return EACCES
; /* +13 */
3303 case permErr
: /* -54 */
3304 case wrPermErr
: /* -61 */
3305 return EPERM
; /* +1 */
3307 case fBsyErr
: /* -47 */
3308 return EBUSY
; /* +16 */
3310 case dupFNErr
: /* -48 */
3311 case fidExists
: /* -1301 */
3312 case cmExists
: /* -32718 */
3313 case btExists
: /* -32734 */
3314 return EEXIST
; /* +17 */
3316 case rfNumErr
: /* -51 */
3317 return EBADF
; /* +9 */
3319 case notAFileErr
: /* -1302 */
3320 return EISDIR
; /* +21 */
3322 case cmNotFound
: /* -32719 */
3323 case btNotFound
: /* -32735 */
3324 return ENOENT
; /* 28 */
3326 case cmNotEmpty
: /* -32717 */
3327 return ENOTEMPTY
; /* 66 */
3329 case cmFThdDirErr
: /* -32714 */
3330 return EISDIR
; /* 21 */
3332 case fxRangeErr
: /* -32751 */
3335 case bdNamErr
: /* -37 */
3336 return ENAMETOOLONG
; /* 63 */
3338 case fnOpnErr
: /* -38 */
3339 case eofErr
: /* -39 */
3340 case posErr
: /* -40 */
3341 case paramErr
: /* -50 */
3342 case badMDBErr
: /* -60 */
3343 case badMovErr
: /* -122 */
3344 case sameFileErr
: /* -1306 */
3345 case badFidErr
: /* -1307 */
3346 case fileBoundsErr
: /* -1309 */
3347 return EINVAL
; /* +22 */
3350 DBG_UTILS(("Unmapped MacOS error: %d\n", err
));
3351 return EIO
; /* +5 */
3357 * All of our debugging functions
3362 void debug_vn_status (char* introStr
, struct vnode
*vn
)
3364 DBG_VOP(("%s:\t",introStr
));
3367 if (vn
->v_tag
!= VT_HFS
)
3369 DBG_VOP(("NON-HFS VNODE Ox%08lX\n", (unsigned long)vn
));
3371 else if(vn
->v_tag
==VT_HFS
&& (vn
->v_data
==NULL
|| VTOH((vn
))->h_valid
!= HFS_VNODE_MAGIC
))
3373 DBG_VOP(("BAD VNODE PRIVATE DATA!!!!\n"));
3377 DBG_VOP(("r: %d & ", vn
->v_usecount
));
3378 if (lockstatus(&VTOH(vn
)->h_lock
))
3380 DBG_VOP_CONT(("is L\n"));
3384 DBG_VOP_CONT(("is U\n"));
3390 DBG_VOP(("vnode is NULL\n"));
3394 void debug_vn_print (char* introStr
, struct vnode
*vn
)
3396 // DBG_FUNC_NAME("DBG_VN_PRINT");
3397 DBG_ASSERT (vn
!= NULL
);
3398 DBG_VFS(("%s: ",introStr
));
3399 DBG_VFS_CONT(("vnode: 0x%x is a ", (uint
)vn
));
3403 DBG_VFS_CONT(("%s","UFS"));
3406 DBG_VFS_CONT(("%s","HFS"));
3409 DBG_VFS_CONT(("%s","UNKNOWN"));
3413 DBG_VFS_CONT((" vnode\n"));
3414 if (vn
->v_tag
==VT_HFS
)
3416 if (vn
->v_data
==NULL
)
3418 DBG_VFS(("BAD VNODE PRIVATE DATA!!!!\n"));
3422 DBG_VFS((" Name: %s Id: %ld ",H_NAME(VTOH(vn
)), H_FILEID(VTOH(vn
))));
3428 DBG_VFS_CONT(("Refcount: %d\n", vn
->v_usecount
));
3429 if (VOP_ISLOCKED(vn
))
3431 DBG_VFS((" The vnode is locked\n"));
3435 DBG_VFS((" The vnode is not locked\n"));
3439 void debug_rename_test_locks (char* introStr
,
3450 DBG_VOP(("\t%s: ", introStr
));
3451 if (fvp
) {if(lockstatus(&VTOH(fvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3452 if (fdvp
) {if(lockstatus(&VTOH(fdvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3453 if (tvp
) {if(lockstatus(&VTOH(tvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3454 if (tdvp
) {if(lockstatus(&VTOH(tdvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3455 DBG_VFS_CONT(("\n"));
3458 if (lockstatus(&VTOH(fvp
)->h_lock
)) {
3459 if (fstatus
==VOPDBG_UNLOCKED
) {
3460 DBG_VOP(("\tfvp should be NOT LOCKED and it is\n"));
3462 } else if (fstatus
== VOPDBG_LOCKED
) {
3463 DBG_VOP(("\tfvp should be LOCKED and it isnt\n"));
3468 if (lockstatus(&VTOH(fdvp
)->h_lock
)) {
3469 if (fdstatus
==VOPDBG_UNLOCKED
) {
3470 DBG_VOP(("\tfdvp should be NOT LOCKED and it is\n"));
3472 } else if (fdstatus
== VOPDBG_LOCKED
) {
3473 DBG_VOP(("\tfdvp should be LOCKED and it isnt\n"));
3478 if (lockstatus(&VTOH(tvp
)->h_lock
)) {
3479 if (tstatus
==VOPDBG_UNLOCKED
) {
3480 DBG_VOP(("\ttvp should be NOT LOCKED and it is\n"));
3482 } else if (tstatus
== VOPDBG_LOCKED
) {
3483 DBG_VOP(("\ttvp should be LOCKED and it isnt\n"));
3488 if (lockstatus(&VTOH(tdvp
)->h_lock
)) {
3489 if (tdstatus
==VOPDBG_UNLOCKED
) {
3490 DBG_VOP(("\ttdvp should be NOT LOCKED and it is\n"));
3492 } else if (tdstatus
== VOPDBG_LOCKED
) {
3493 DBG_VOP(("\ttdvp should be LOCKED and it isnt\n"));
3499 #endif /* HFS_DIAGNOSTIC */
3503 void debug_check_buffersizes(struct vnode
*vp
, struct hfsnode
*hp
, struct buf
*bp
) {
3504 DBG_ASSERT(bp
->b_validoff
== 0);
3505 DBG_ASSERT(bp
->b_dirtyoff
== 0);
3506 DBG_ASSERT((bp
->b_bcount
== HTOHFS(hp
)->hfs_logBlockSize
) ||
3507 ((bp
->b_bcount
% 512 == 0) &&
3508 (bp
->b_validend
> 0) &&
3509 (bp
->b_dirtyend
> 0) &&
3510 (bp
->b_bcount
< HTOHFS(hp
)->hfs_logBlockSize
)));
3512 if (bp
->b_validend
== 0) {
3513 DBG_ASSERT(bp
->b_dirtyend
== 0);
3515 DBG_ASSERT(bp
->b_validend
== bp
->b_bcount
);
3516 DBG_ASSERT(bp
->b_dirtyend
<= bp
->b_bcount
);
3521 void debug_check_blocksizes(struct vnode
*vp
) {
3522 struct hfsnode
*hp
= VTOH(vp
);
3525 if (vp
->v_flag
& VSYSTEM
) return;
3527 for (bp
= vp
->v_cleanblkhd
.lh_first
; bp
!= NULL
; bp
= bp
->b_vnbufs
.le_next
) {
3528 debug_check_buffersizes(vp
, hp
, bp
);
3531 for (bp
= vp
->v_dirtyblkhd
.lh_first
; bp
!= NULL
; bp
= bp
->b_vnbufs
.le_next
) {
3532 debug_check_buffersizes(vp
, hp
, bp
);
3536 void debug_check_catalogdata(struct CatalogNodeData
*cat
) {
3538 if (cat
->cnm_nameptr
== NULL
) {
3539 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3541 else if (cat
->cnm_nameptr
== cat
->cnm_namespace
) {
3542 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3545 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == kCatNameIsAllocated
);
3548 if (cat
->cnm_nameptr
) {
3549 DBG_ASSERT(strlen(cat
->cnm_nameptr
) == cat
->cnm_length
);
3552 if (cat
->cnm_flags
& kCatNameIsConsumed
) {
3553 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3556 if (cat
->cnm_flags
& kCatNameNoCopyName
) {
3557 DBG_ASSERT((cat
->cnm_flags
& (kCatNameIsAllocated
|kCatNameIsConsumed
|kCatNameIsMangled
)) == 0);
3558 DBG_ASSERT(cat
->cnm_length
== 0);
3559 DBG_ASSERT(cat
->cnm_nameptr
== 0);
3560 DBG_ASSERT(strlen(cat
->cnm_namespace
) == 0);
3565 extern void hfs_vhash_dbg(struct hfsnode
*hp
);
3567 /* Checks the valicity of a hfs vnode */
3568 void debug_check_vnode(struct vnode
*vp
, int stage
) {
3574 if (VTOHFS(vp
)->hfs_mount_flags
& kHFSBootVolumeInconsistentMask
)
3575 DEBUG_BREAK_MSG(("Volume is damaged!"));
3579 DEBUG_BREAK_MSG(("Null vnode"));
3580 if (vp
->v_tag
!= VT_HFS
)
3581 DEBUG_BREAK_MSG(("Not a HFS vnode, it is a %d", vp
->v_tag
));
3582 if (vp
->v_data
==NULL
)
3583 DEBUG_BREAK_MSG(("v_data is NULL"));
3587 if (hp
->h_valid
!= HFS_VNODE_MAGIC
)
3588 DEBUG_BREAK_MSG(("Bad Formed HFS node"));
3589 if (hp
->h_vp
==NULL
|| hp
->h_vp
!=vp
)
3590 DEBUG_BREAK_MSG(("Bad hfsnode vnode pte"));
3591 if (hp
->h_meta
== NULL
)
3592 DEBUG_BREAK_MSG(("Bad hfsnode meta ptr"));
3593 switch (H_FORKTYPE(hp
)) {
3596 if ((hp
->h_meta
->h_siblinghead
.cqh_first
== NULL
) || (hp
->h_meta
->h_siblinghead
.cqh_last
== NULL
))
3597 DEBUG_BREAK_MSG(("Null sibling header"));
3598 if ((hp
->h_sibling
.cqe_next
==NULL
) || (hp
->h_sibling
.cqe_prev
==NULL
))
3599 DEBUG_BREAK_MSG(("Null sibling list"));
3600 if (hp
->h_meta
->h_usecount
<1 || hp
->h_meta
->h_usecount
>2)
3601 DEBUG_BREAK_MSG(("Bad sibling usecount"));
3605 if ((hp
->h_meta
->h_siblinghead
.cqh_first
!= NULL
) || (hp
->h_meta
->h_siblinghead
.cqh_last
!= NULL
))
3606 DEBUG_BREAK_MSG(("Non Null sibling header"));
3607 if ((hp
->h_sibling
.cqe_next
!=NULL
) || (hp
->h_sibling
.cqe_prev
!=NULL
))
3608 DEBUG_BREAK_MSG(("Null sibling list"));
3609 if (hp
->h_meta
->h_usecount
!=1)
3610 DEBUG_BREAK_MSG(("Bad usecount"));
3614 DEBUG_BREAK_MSG(("Bad hfsnode fork type"));
3618 if (hp
->h_meta
->h_devvp
== NULL
)
3619 DEBUG_BREAK_MSG(("Bad hfsnode dev vnode"));
3621 DEBUG_BREAK_MSG(("Bad dev id"));
3622 if (H_FILEID(hp
) == 0)
3623 DEBUG_BREAK_MSG(("Bad file id"));
3625 if (((hp
->h_meta
->h_metaflags
& IN_DATANODE
)==0) && (H_DIRID(hp
) == 0) && (H_FILEID(hp
) != 1))
3626 DEBUG_BREAK_MSG(("Bad dir id"));
3628 if (hp
->h_meta
->h_namePtr
== NULL
&& hp
->h_meta
->h_namelen
!=0)
3629 DEBUG_BREAK_MSG(("hfs meta h_namelen is not 0"));
3630 if (hp
->h_meta
->h_namePtr
!= NULL
&& strlen(hp
->h_meta
->h_namePtr
) != hp
->h_meta
->h_namelen
)
3631 DEBUG_BREAK_MSG(("Bad hfs meta h_namelen"));
3633 /* Check the hash */
3636 /* Check to see if we want to compare with the disk */
3639 hfsCatalogInfo catInfo
;
3641 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
3644 if (hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_SHARED
, current_proc()))
3647 if (hfs_getcatalog(VTOVCB(vp
), H_DIRID(hp
), hp
->h_meta
->h_namePtr
, hp
->h_meta
->h_namelen
, &catInfo
))
3648 DEBUG_BREAK_MSG(("Could not find hfsnode Catalog record"));
3650 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3652 if (H_FILEID(hp
) != catInfo
.nodeData
.cnd_nodeID
)
3653 DEBUG_BREAK_MSG(("hfsnode catalog node id mismatch"));
3654 if (H_DIRID(hp
) != catInfo
.nodeData
.cnm_parID
)
3655 DEBUG_BREAK_MSG(("hfsnode catalog dir id mismatch"));
3656 if (strcmp(hp
->h_meta
->h_namePtr
, catInfo
.nodeData
.cnm_nameptr
) != 0)
3657 DEBUG_BREAK_MSG(("hfsnode catalog name mismatch"));
3658 /* Check dates too??? */
3660 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3667 for(i
= 0, size
= 0; i
< kHFSPlusExtentDensity
; i
++)
3669 size
+= hp
->fcbExtents
[i
].blockCount
;
3672 if (hp
->fcbEOF
> hp
->fcbPLen
)
3673 DEBUG_BREAK_MSG(("fcbPLen is smaller than fcbEOF"));
3675 if (hp
->fcbExtents
[kHFSPlusExtentDensity
-1].blockCount
== 0) {
3676 if ((off_t
)size
* (off_t
)VTOVCB(vp
)->blockSize
!= hp
->fcbPLen
)
3677 DEBUG_BREAK_MSG(("fcbPLen does not match extents"));
3679 if ( hp
->fcbPLen
< (off_t
)size
* (off_t
)VTOVCB(vp
)->blockSize
)
3680 DEBUG_BREAK_MSG(("fcbPLen is smaller than extents"));
3682 for(i
= 0; i
< kHFSPlusExtentDensity
; i
++)
3684 if (hp
->fcbExtents
[i
].blockCount
== 0 || hp
->fcbExtents
[i
].startBlock
== 0)
3687 if ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) && i
> kHFSExtentDensity
)
3688 DEBUG_BREAK_MSG(("Illegal value in extents for ordinary HFS"));
3689 if (i
> kHFSPlusExtentDensity
) {
3690 for(; i
< kHFSPlusExtentDensity
; i
++)
3692 if (hp
->fcbExtents
[i
].blockCount
!= 0 || hp
->fcbExtents
[i
].startBlock
!= 0)
3693 DEBUG_BREAK_MSG(("Illegal value in extents"));
3700 if (0 && vp
->v_flag
& VSYSTEM
) {
3703 BTGetInformation(hp
, 0, &info
);
3704 if (hp
->fcbBTCBPtr
== NULL
)
3705 DEBUG_BREAK_MSG(("Null fcbBTCBPtr"));
3706 if (H_HINT(hp
) == 0)
3707 DEBUG_BREAK_MSG(("hint is 0"));
3708 if (H_HINT(hp
) > info
.numNodes
)
3709 DEBUG_BREAK_MSG(("hint > numNodes"));
3714 #endif /* HFS_DIAGNOSTIC */