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
)
625 UInt32 linkparid
, linkcnid
;
628 fip
= (struct FInfo
*) &cndp
->cnd_finderInfo
;
631 * if this is an indirect link (hardlink) then auto resolve it...
633 if ((vcb
->vcbSigWord
== kHFSPlusSigWord
)
634 && (cndp
->cnd_type
== kCatalogFileNode
)
635 && (fip
->fdType
== kHardLinkFileType
)
636 && (fip
->fdCreator
== kHFSPlusCreator
)
637 && ((cndp
->cnd_createDate
== vcb
->vcbCrDate
) ||
638 (cndp
->cnd_createDate
== VCBTOHFS(vcb
)->hfs_metadata_createdate
))) {
640 indlinkno
= cndp
->cnd_iNodeNum
;
641 MAKE_INODE_NAME(iNodeName
, indlinkno
);
643 * Get nodeData from the data node file.
644 * Flag the node data to NOT copy the name (ie preserve the original)
645 * Also preserve the parent directory ID.
647 linkparid
= cndp
->cnm_parID
;
648 linkcnid
= cndp
->cnd_nodeID
;
649 cndp
->cnm_flags
|= kCatNameNoCopyName
;
650 result
= GetCatalogNode(vcb
, VCBTOHFS(vcb
)->hfs_private_metadata_dir
,
651 iNodeName
, 0, 0, cndp
, &hint
);
652 cndp
->cnm_flags
&= ~kCatNameNoCopyName
;
654 /* Make sure there's a reference */
656 if (cndp
->cnd_linkCount
== 0) cndp
->cnd_linkCount
= 2;
658 /* Keep a copy of iNodeNum to put into h_indnodeno */
659 cndp
->cnd_iNodeNumCopy
= indlinkno
;
660 cndp
->cnm_parID
= linkparid
;
661 cndp
->cnd_linkCNID
= linkcnid
;
668 * Performs a lookup on the given dirID, name. Returns the catalog info
670 * If len is -1, then it is a null terminated string, pass it along to MacOS as kUndefinedStrLen
673 short hfs_getcatalog (ExtendedVCB
*vcb
, UInt32 parentDirID
, char *name
, short len
, hfsCatalogInfo
*catInfo
)
678 if (len
== -1 ) { /* Convert it to MacOS terms */
680 length
= strlen(name
);
682 length
= kUndefinedStrLen
;
687 result
= GetCatalogNode(vcb
, parentDirID
, name
, length
, catInfo
->hint
, &catInfo
->nodeData
, &catInfo
->hint
);
690 if (catInfo
->nodeData
.cnm_nameptr
) {
691 DBG_ASSERT(strlen(catInfo
->nodeData
.cnm_nameptr
) == catInfo
->nodeData
.cnm_length
);
696 hfs_resolvelink(vcb
, &catInfo
->nodeData
);
698 return MacToVFSError(result
);
703 short hfsDelete (ExtendedVCB
*vcb
, UInt32 parentDirID
, StringPtr name
, short isfile
, UInt32 catalogHint
)
705 OSErr result
= noErr
;
707 /* XXX have all the file's blocks been flushed/trashed? */
710 * DeleteFile will delete the catalog node and then
711 * free up any disk space used by the file.
714 result
= DeleteFile(vcb
, parentDirID
, name
, catalogHint
);
715 else /* is a directory */
716 result
= DeleteCatalogNode(vcb
, parentDirID
, name
, catalogHint
);
719 DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result
, parentDirID
, name
));
721 return MacToVFSError(result
);
725 short hfsMoveRename (ExtendedVCB
*vcb
, UInt32 oldDirID
, char *oldName
, UInt32 newDirID
, char *newName
, UInt32
*hint
)
727 OSErr result
= noErr
;
729 result
= MoveRenameCatalogNode(vcb
, oldDirID
,oldName
, *hint
, newDirID
, newName
, hint
, 0);
732 DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result
, newDirID
, newName
));
735 return MacToVFSError(result
);
738 /* XXX SER pass back the hint so other people can use it */
741 short hfsCreate(ExtendedVCB
*vcb
, UInt32 dirID
, char *name
, int mode
, UInt32 tehint
)
743 OSErr result
= noErr
;
744 HFSCatalogNodeID catalogNodeID
;
748 /* just test for directories, the default is to create a file (like symlinks) */
749 if ((mode
& IFMT
) == IFDIR
)
750 type
= kCatalogFolderNode
;
752 type
= kCatalogFileNode
;
754 result
= CreateCatalogNode (vcb
, dirID
, name
, type
, &catalogNodeID
, &catalogHint
, tehint
);
756 return MacToVFSError(result
);
760 short hfsCreateFileID (ExtendedVCB
*vcb
, UInt32 parentDirID
, StringPtr name
, UInt32 catalogHint
, UInt32
*fileIDPtr
)
762 return MacToVFSError(CreateFileIDRef(vcb
, parentDirID
, name
, catalogHint
, fileIDPtr
));
766 /********************************************************************************/
768 /* hfs_vget_catinfo - Returns a vnode derived from a hfs catInfo struct */
770 /********************************************************************************/
772 int hfs_vget_catinfo(struct vnode
*parent_vp
, struct hfsCatalogInfo
*catInfo
, u_int32_t forkType
, struct vnode
**target_vp
)
776 if (forkType
== kDefault
) {
777 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
)
778 forkType
= kDirectory
;
780 forkType
= kDataFork
;
783 *target_vp
= hfs_vhashget(H_DEV(VTOH(parent_vp
)), catInfo
->nodeData
.cnd_nodeID
, forkType
);
785 if (*target_vp
== NULL
)
786 retval
= hfs_vcreate( VTOVCB(parent_vp
), catInfo
, forkType
, target_vp
);
793 /************************************************************************/
794 /* hfs_vcreate - Returns a vnode derived from hfs */
796 /* When creating the vnode, care must be made to set the */
797 /* correct fields in the correct order. Calls to malloc() */
798 /* and other subroutines, can cause a context switch, */
799 /* and the fields must be ready for the possibility */
802 /************************************************************************/
804 short hfs_vcreate(ExtendedVCB
*vcb
, hfsCatalogInfo
*catInfo
, UInt8 forkType
, struct vnode
**vpp
)
808 struct hfsmount
*hfsmp
;
809 struct hfsfilemeta
*fm
;
815 hfsmp
= VCBTOHFS(vcb
);
816 mp
= HFSTOVFS(hfsmp
);
817 dev
= hfsmp
->hfs_raw_dev
;
819 /* Check if unmount in progress */
820 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
826 * If this is a hard link then check if the
827 * data node already exists in our hash.
829 if ((forkType
== kDataFork
)
830 && (catInfo
->nodeData
.cnd_type
== kCatalogFileNode
)
831 && ((catInfo
->nodeData
.cnd_mode
& IFMT
) == IFREG
)
832 && (catInfo
->nodeData
.cnd_linkCount
> 0)) {
833 vp
= hfs_vhashget(dev
, catInfo
->nodeData
.cnd_nodeID
, kDataFork
);
835 /* Use the name of the link and it's parent ID. */
837 H_DIRID(hp
) = catInfo
->nodeData
.cnm_parID
;
838 hfs_set_metaname(catInfo
->nodeData
.cnm_nameptr
, hp
->h_meta
, hfsmp
);
844 MALLOC_ZONE(hp
, struct hfsnode
*, sizeof(struct hfsnode
), M_HFSNODE
, M_WAITOK
);
845 bzero((caddr_t
)hp
, sizeof(struct hfsnode
));
846 hp
->h_nodeflags
|= IN_ALLOCATING
;
847 lockinit(&hp
->h_lock
, PINOD
, "hfsnode", 0, 0);
848 H_FORKTYPE(hp
) = forkType
;
849 rl_init(&hp
->h_invalidranges
);
852 * There were several blocking points since we first
853 * checked the hash. Now that we're through blocking,
854 * check the hash again in case we're racing for the
857 vp
= hfs_vhashget(dev
, catInfo
->nodeData
.cnd_nodeID
, forkType
);
859 /* We lost the race, use the winner's vnode */
860 FREE_ZONE(hp
, sizeof(struct hfsnode
), M_HFSNODE
);
862 UBCINFOCHECK("hfs_vcreate", vp
);
867 * Insert the hfsnode into the hash queue, also if meta exists
868 * add to sibling list and return the meta address
871 if (SIBLING_FORKTYPE(forkType
))
872 hfs_vhashins_sibling(dev
, catInfo
->nodeData
.cnd_nodeID
, hp
, &fm
);
874 hfs_vhashins(dev
, catInfo
->nodeData
.cnd_nodeID
, hp
);
876 /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
877 if ((retval
= getnewvnode(VT_HFS
, mp
, hfs_vnodeop_p
, &vp
))) {
879 if (hp
->h_nodeflags
& IN_WANT
) {
880 hp
->h_nodeflags
&= ~IN_WANT
;
883 FREE_ZONE(hp
, sizeof(struct hfsnode
), M_HFSNODE
);
890 hp
->h_nodeflags
&= ~IN_ALLOCATING
;
891 if (hp
->h_nodeflags
& IN_WANT
) {
892 hp
->h_nodeflags
&= ~IN_WANT
;
897 * If needed allocate and init the object meta data:
900 /* Allocate it....remember we can do a context switch here */
901 MALLOC_ZONE(fm
, struct hfsfilemeta
*, sizeof(struct hfsfilemeta
), M_HFSFMETA
, M_WAITOK
);
902 bzero(fm
, sizeof(struct hfsfilemeta
));
906 * NOTICE: XXX Even though we have added the vnode to the hash so it is alive on TWO
907 * accessable lists, we do not assign it until later,
908 * this helps to make sure we do not use a half initiated meta
911 /* Init the sibling list if needed */
912 if (SIBLING_FORKTYPE(forkType
)) {
913 simple_lock_init(&fm
->h_siblinglock
);
914 CIRCLEQ_INIT(&fm
->h_siblinghead
);
915 CIRCLEQ_INSERT_HEAD(&fm
->h_siblinghead
, hp
, h_sibling
);
919 CopyCatalogToObjectMeta(catInfo
, vp
, fm
);
922 * the vnode is finally alive, with the exception of the FCB below,
923 * It is finally locked and ready for its debutante ball
930 * Init the File Control Block.
932 CopyCatalogToFCB(catInfo
, vp
);
935 * Finish vnode initialization.
936 * Setting the v_type 'stamps' the vnode as 'complete', so should be done almost last.
938 * At this point the vnode should be locked and fully allocated. And ready to be used
939 * or accessed. (though having it locked prevents most of this, it
940 * can still be accessed through lists and hashs).
942 vp
->v_type
= IFTOVT(hp
->h_meta
->h_mode
);
943 if ((vp
->v_type
== VREG
)
944 && (UBCINFOMISSING(vp
) || UBCINFORECLAIMED(vp
))) {
949 * Initialize the vnode from the inode, check for aliases, sets the VROOT flag.
950 * Note that the underlying vnode may have changed.
952 if ((retval
= hfs_vinit(mp
, hfs_specop_p
, hfs_fifoop_p
, &vp
))) {
959 * Finish inode initialization now that aliasing has been resolved.
961 hp
->h_meta
->h_devvp
= hfsmp
->hfs_devvp
;
962 VREF(hp
->h_meta
->h_devvp
);
968 void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
)
970 ExtendedVCB
*vcb
= VTOVCB(vp
);
971 struct mount
*mp
= VTOVFS(vp
);
972 Boolean isHFSPlus
, isDirectory
;
976 DBG_ASSERT (fm
!= NULL
);
977 DBG_ASSERT (fm
->h_namelen
== 0);
978 DBG_ASSERT (fm
->h_namePtr
== 0);
980 DBG_UTILS(("\tCopying to file's meta data: name:%s, nodeid:%ld\n", catalogInfo
->nodeData
.cnm_nameptr
, catalogInfo
->nodeData
.cnd_nodeID
));
982 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
983 isDirectory
= (catalogInfo
->nodeData
.cnd_type
== kCatalogFolderNode
);
984 finderFlags
= SWAP_BE16 (((struct FInfo
*)(&catalogInfo
->nodeData
.cnd_finderInfo
))->fdFlags
);
986 /* Copy over the dirid, and hint */
987 fm
->h_nodeID
= catalogInfo
->nodeData
.cnd_nodeID
;
988 fm
->h_dirID
= catalogInfo
->nodeData
.cnm_parID
;
989 fm
->h_hint
= catalogInfo
->hint
;
991 /* Copy over the name */
992 hfs_name_CatToMeta(&catalogInfo
->nodeData
, fm
);
995 /* get dates in BSD format */
996 fm
->h_mtime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
997 fm
->h_crtime
= to_bsd_time(catalogInfo
->nodeData
.cnd_createDate
);
998 fm
->h_butime
= to_bsd_time(catalogInfo
->nodeData
.cnd_backupDate
);
1000 fm
->h_atime
= to_bsd_time(catalogInfo
->nodeData
.cnd_accessDate
);
1001 fm
->h_ctime
= to_bsd_time(catalogInfo
->nodeData
.cnd_attributeModDate
);
1004 fm
->h_atime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1005 fm
->h_ctime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1009 if (isHFSPlus
&& (catalogInfo
->nodeData
.cnd_mode
& IFMT
)) {
1010 fm
->h_uid
= catalogInfo
->nodeData
.cnd_ownerID
;
1011 fm
->h_gid
= catalogInfo
->nodeData
.cnd_groupID
;
1012 fm
->h_pflags
= catalogInfo
->nodeData
.cnd_ownerFlags
|
1013 (catalogInfo
->nodeData
.cnd_adminFlags
<< 16);
1014 fm
->h_mode
= (mode_t
)catalogInfo
->nodeData
.cnd_mode
;
1016 if (fm
->h_uid
== 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1017 fm
->h_uid
= UNKNOWNUID
;
1018 fm
->h_metaflags
|= IN_CHANGE
;
1019 vcb
->vcbFlags
|= kHFS_DamagedVolume
; /* Trigger fsck on next mount */
1021 if (fm
->h_gid
== 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1022 fm
->h_gid
= UNKNOWNGID
;
1023 fm
->h_metaflags
|= IN_CHANGE
;
1024 vcb
->vcbFlags
|= kHFS_DamagedVolume
; /* Trigger fsck on next mount */
1027 filetype
= fm
->h_mode
& IFMT
;
1028 if (filetype
== IFCHR
|| filetype
== IFBLK
)
1029 fm
->h_rdev
= catalogInfo
->nodeData
.cnd_rawDevice
;
1033 if (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
&&
1034 catalogInfo
->nodeData
.cnd_linkCount
> 0) {
1035 fm
->h_nlink
= catalogInfo
->nodeData
.cnd_linkCount
;
1036 fm
->h_indnodeno
= catalogInfo
->nodeData
.cnd_iNodeNumCopy
;
1037 fm
->h_metaflags
|= IN_DATANODE
;
1042 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1044 * Override the permissions as determined by the mount auguments
1045 * in ALMOST the same way unset permissions are treated but keep
1046 * track of whether or not the file or folder is hfs locked
1047 * by leaving the h_pflags field unchanged from what was unpacked
1048 * out of the catalog.
1050 fm
->h_metaflags
|= IN_UNSETACCESS
;
1051 fm
->h_uid
= VTOHFS(vp
)->hfs_uid
;
1052 fm
->h_gid
= VTOHFS(vp
)->hfs_gid
;
1053 #if OVERRIDE_UNKNOWN_PERMISSIONS
1054 /* Default access is full read/write/execute: */
1055 /* XXX won't this smash IFCHR, IFBLK and IFLNK (for no-follow lookups)? */
1056 fm
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
1059 /* ... but no more than that permitted by the mount point's: */
1061 fm
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
1064 fm
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
1068 fm
->h_mode
|= IFDIR
;
1069 else if (SUPPORTS_MAC_ALIASES
&& (finderFlags
& kIsAlias
)) /* aliases will be symlinks in the future */
1070 fm
->h_mode
|= IFLNK
;
1072 fm
->h_mode
|= IFREG
;
1077 * Set the permissions as determined by the mount auguments
1078 * but keep in account if the file or folder is hfs locked
1080 fm
->h_metaflags
|= IN_UNSETACCESS
;
1081 fm
->h_uid
= VTOHFS(vp
)->hfs_uid
;
1082 fm
->h_gid
= VTOHFS(vp
)->hfs_gid
;
1083 fm
->h_pflags
= 0; /* No valid pflags on disk (IMMUTABLE is synced from lock flag later) */
1084 fm
->h_rdev
= 0; /* No valid rdev on disk */
1085 /* Default access is full read/write/execute: */
1086 fm
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
1088 /* ... but no more than that permitted by the mount point's: */
1090 fm
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
1093 fm
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
1097 fm
->h_mode
|= IFDIR
;
1098 else if (SUPPORTS_MAC_ALIASES
&& (finderFlags
& kIsAlias
)) /* aliases will be symlinks in the future */
1099 fm
->h_mode
|= IFLNK
;
1101 fm
->h_mode
|= IFREG
;
1104 /* Make sure that there is no nodeType/mode mismatch */
1105 if (isDirectory
&& ((fm
->h_mode
& IFMT
) != IFDIR
)) {
1106 fm
->h_mode
&= ~IFMT
; /* Clear the bad bits */
1107 fm
->h_mode
|= IFDIR
; /* Set the proper one */
1110 /* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */
1112 if (catalogInfo
->nodeData
.cnd_flags
& kHFSFileLockedMask
) {
1113 /* The file's supposed to be locked:
1114 Make sure at least one of the IMMUTABLE bits is set: */
1115 if ((fm
->h_pflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
)) == 0) {
1116 fm
->h_pflags
|= UF_IMMUTABLE
; /* Set the user-changable IMMUTABLE bit */
1119 /* The file's supposed to be unlocked: */
1120 fm
->h_pflags
&= ~(SF_IMMUTABLE
| UF_IMMUTABLE
);
1125 fm
->h_nlink
= 2 + catalogInfo
->nodeData
.cnd_valence
;
1126 fm
->h_size
= (2 * sizeof(hfsdotentry
)) +
1127 (catalogInfo
->nodeData
.cnd_valence
* AVERAGE_HFSDIRENTRY_SIZE
);
1128 if (fm
->h_size
< MAX_HFSDIRENTRY_SIZE
)
1129 fm
->h_size
= MAX_HFSDIRENTRY_SIZE
;
1131 fm
->h_size
= (off_t
)vcb
->blockSize
*
1132 (off_t
)(catalogInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
+
1133 catalogInfo
->nodeData
.cnd_datafork
.totalBlocks
);
1138 void CopyCatalogToFCB(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
)
1140 FCB
*fcb
= VTOFCB(vp
);
1141 ExtendedVCB
*vcb
= VTOVCB(vp
);
1142 Boolean isHFSPlus
, isDirectory
, isResource
;
1143 HFSPlusExtentDescriptor
*extents
;
1146 DBG_ASSERT (vp
!= NULL
);
1147 DBG_ASSERT (fcb
!= NULL
);
1148 DBG_ASSERT (vcb
!= NULL
);
1149 DBG_ASSERT (VTOH(vp
) != NULL
);
1151 forkType
= H_FORKTYPE(VTOH(vp
));
1152 isResource
= (forkType
== kRsrcFork
);
1153 isDirectory
= (catalogInfo
->nodeData
.cnd_type
== kCatalogFolderNode
);
1154 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1157 fcb
->fcbFlags
= catalogInfo
->nodeData
.cnd_flags
;
1159 if (forkType
!= kDirectory
) {
1160 fcb
->fcbFlags
&= kHFSFileLockedMask
; /* Clear resource, dirty bits */
1161 if (fcb
->fcbFlags
!= 0) /* if clear, its not locked, then.. */
1162 fcb
->fcbFlags
= fcbFileLockedMask
; /* duplicate the bit for later use */
1164 fcb
->fcbClmpSize
= vcb
->vcbClpSiz
; /*XXX why not use the one in catalogInfo? */
1167 extents
= catalogInfo
->nodeData
.cnd_rsrcfork
.extents
;
1169 extents
= catalogInfo
->nodeData
.cnd_datafork
.extents
;
1171 /* Copy the extents to their correct location: */
1172 bcopy (extents
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
1175 fcb
->fcbEOF
= catalogInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
1176 fcb
->fcbPLen
= (off_t
)((off_t
)catalogInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
1177 fcb
->fcbFlags
|= fcbResourceMask
;
1179 fcb
->fcbEOF
= catalogInfo
->nodeData
.cnd_datafork
.logicalSize
;
1180 fcb
->fcbPLen
= (off_t
)((off_t
)catalogInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
1187 int hasOverflowExtents(struct hfsnode
*hp
)
1189 ExtendedVCB
*vcb
= HTOVCB(hp
);
1190 FCB
*fcb
= HTOFCB(hp
);
1193 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1196 if (fcb
->fcbExtents
[7].blockCount
== 0)
1199 blocks
= fcb
->fcbExtents
[0].blockCount
+
1200 fcb
->fcbExtents
[1].blockCount
+
1201 fcb
->fcbExtents
[2].blockCount
+
1202 fcb
->fcbExtents
[3].blockCount
+
1203 fcb
->fcbExtents
[4].blockCount
+
1204 fcb
->fcbExtents
[5].blockCount
+
1205 fcb
->fcbExtents
[6].blockCount
+
1206 fcb
->fcbExtents
[7].blockCount
;
1210 if (fcb
->fcbExtents
[2].blockCount
== 0)
1213 blocks
= fcb
->fcbExtents
[0].blockCount
+
1214 fcb
->fcbExtents
[1].blockCount
+
1215 fcb
->fcbExtents
[2].blockCount
;
1218 return ((fcb
->fcbPLen
/ vcb
->blockSize
) > blocks
);
1222 int hfs_metafilelocking(struct hfsmount
*hfsmp
, u_long fileID
, u_int flags
, struct proc
*p
)
1225 struct vnode
*vp
= NULL
;
1226 int numOfLockedBuffs
;
1229 vcb
= HFSTOVCB(hfsmp
);
1231 DBG_UTILS(("hfs_metafilelocking: vol: %d, file: %d %s%s%s\n", vcb
->vcbVRefNum
, fileID
,
1232 ((flags
& LK_TYPE_MASK
) == LK_RELEASE
? "RELEASE" : ""),
1233 ((flags
& LK_TYPE_MASK
) == LK_EXCLUSIVE
? "EXCLUSIVE" : ""),
1234 ((flags
& LK_TYPE_MASK
) == LK_SHARED
? "SHARED" : "") ));
1239 case kHFSExtentsFileID
:
1240 vp
= vcb
->extentsRefNum
;
1243 case kHFSCatalogFileID
:
1244 vp
= vcb
->catalogRefNum
;
1247 case kHFSAllocationFileID
:
1248 /* bitmap is covered by Extents B-tree locking */
1251 panic("hfs_lockmetafile: invalid fileID");
1256 /* Release, if necesary any locked buffer caches */
1257 if ((flags
& LK_TYPE_MASK
) == LK_RELEASE
) {
1258 struct timeval tv
= time
;
1259 u_int32_t lastfsync
= tv
.tv_sec
;
1261 (void) BTGetLastSync(VTOFCB(vp
), &lastfsync
);
1263 numOfLockedBuffs
= count_lock_queue();
1264 if ((numOfLockedBuffs
> kMaxLockedMetaBuffers
) || ((numOfLockedBuffs
>1) && ((tv
.tv_sec
- lastfsync
) > kMaxSecsForFsync
))) {
1265 DBG_UTILS(("Synching meta deta: %d... # locked buffers = %d, fsync gap = %ld\n", H_FILEID(VTOH(vp
)),
1266 numOfLockedBuffs
, (tv
.tv_sec
- lastfsync
)));
1267 hfs_fsync_transaction(vp
);
1271 retval
= lockmgr(&VTOH(vp
)->h_lock
, flags
, &vp
->v_interlock
, p
);
1279 * There are three ways to qualify for ownership rights on an object:
1281 * 1. (a) Your UID matches the UID of the vnode
1282 * (b) The object in question is owned by "unknown" and your UID matches the console user's UID
1283 * 2. (a) Permissions on the filesystem are being ignored and your UID matches the replacement UID
1284 * (b) Permissions on the filesystem are being ignored and the replacement UID is "unknown" and
1285 * your UID matches the console user UID
1289 int hfs_owner_rights(struct vnode
*vp
, struct ucred
*cred
, struct proc
*p
, Boolean invokesuperuserstatus
) {
1290 return ((cred
->cr_uid
== VTOH(vp
)->h_meta
->h_uid
) || /* [1a] */
1291 ((VTOH(vp
)->h_meta
->h_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)) || /* [1b] */
1292 ((VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) && /* [2] */
1293 ((cred
->cr_uid
== VTOHFS(vp
)->hfs_uid
) || /* [2a] */
1294 ((VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)))) || /* [2b] */
1295 (invokesuperuserstatus
&& (suser(cred
, &p
->p_acflag
) == 0))) ? 0 : EPERM
;
1300 int hfs_catalogentry_owner_rights(uid_t obj_uid
, struct mount
*mp
, struct ucred
*cred
, struct proc
*p
, Boolean invokesuperuserstatus
) {
1301 return ((cred
->cr_uid
== obj_uid
) || /* [1a] */
1302 ((obj_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)) || /* [1b] */
1303 ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) && /* [2] */
1304 ((cred
->cr_uid
== VFSTOHFS(mp
)->hfs_uid
) || /* [2a] */
1305 ((VFSTOHFS(mp
)->hfs_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)))) || /* [2b] */
1306 (invokesuperuserstatus
&& (suser(cred
, &p
->p_acflag
) == 0))) ? 0 : EPERM
;
1311 void CopyVNodeToCatalogNode (struct vnode
*vp
, struct CatalogNodeData
*nodeData
)
1316 Boolean isHFSPlus
, isResource
;
1317 HFSPlusExtentDescriptor
*extents
;
1318 off_t fileReadLimit
;
1323 isResource
= (H_FORKTYPE(hp
) == kRsrcFork
);
1324 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1326 /* date and time of last fork modification */
1327 if (hp
->h_meta
->h_mtime
!= 0)
1328 nodeData
->cnd_contentModDate
= to_hfs_time(hp
->h_meta
->h_mtime
);
1331 /* Make sure that there is no nodeType/mode mismatch */
1332 if ((nodeData
->cnd_type
== kCatalogFolderNode
)
1333 && ((hp
->h_meta
->h_mode
& IFMT
) != IFDIR
)) {
1335 DBG_ASSERT((hp
->h_meta
->h_mode
& IFMT
) == IFDIR
);
1336 hp
->h_meta
->h_mode
&= ~IFMT
; /* Clear the bad bits */
1337 hp
->h_meta
->h_mode
|= IFDIR
; /* Set the proper one */
1339 /* date and time of last modification (any kind) */
1340 if (hp
->h_meta
->h_ctime
!= 0)
1341 nodeData
->cnd_attributeModDate
= to_hfs_time(hp
->h_meta
->h_ctime
);
1342 /* date and time of last access (MacOS X only) */
1343 if (hp
->h_meta
->h_atime
!= 0)
1344 nodeData
->cnd_accessDate
= to_hfs_time(hp
->h_meta
->h_atime
);
1345 /* hfs_setattr can change the create date */
1346 if (hp
->h_meta
->h_crtime
!= 0)
1347 nodeData
->cnd_createDate
= to_hfs_time(hp
->h_meta
->h_crtime
);
1348 if (! (hp
->h_meta
->h_metaflags
& IN_UNSETACCESS
)) {
1349 nodeData
->cnd_adminFlags
= hp
->h_meta
->h_pflags
>> 16;
1350 nodeData
->cnd_ownerFlags
= hp
->h_meta
->h_pflags
& 0x000000FF;
1351 nodeData
->cnd_mode
= hp
->h_meta
->h_mode
;
1352 nodeData
->cnd_ownerID
= hp
->h_meta
->h_uid
;
1353 nodeData
->cnd_groupID
= hp
->h_meta
->h_gid
;
1357 /* the rest only applies to files */
1358 if (nodeData
->cnd_type
== kCatalogFileNode
) {
1359 if (hp
->h_meta
->h_pflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
)) {
1360 /* The file is locked: set the locked bit in the catalog. */
1361 nodeData
->cnd_flags
|= kHFSFileLockedMask
;
1363 /* The file is unlocked: make sure the locked bit in the catalog is clear. */
1364 nodeData
->cnd_flags
&= ~kHFSFileLockedMask
;
1366 if (CIRCLEQ_EMPTY(&hp
->h_invalidranges
)) {
1367 fileReadLimit
= fcb
->fcbEOF
;
1369 fileReadLimit
= CIRCLEQ_FIRST(&hp
->h_invalidranges
)->rl_start
;
1372 extents
= nodeData
->cnd_rsrcfork
.extents
;
1373 nodeData
->cnd_rsrcfork
.logicalSize
= fileReadLimit
;
1374 nodeData
->cnd_rsrcfork
.totalBlocks
= fcb
->fcbPLen
/ vcb
->blockSize
;
1376 extents
= nodeData
->cnd_datafork
.extents
;
1377 nodeData
->cnd_datafork
.logicalSize
= fileReadLimit
;
1378 nodeData
->cnd_datafork
.totalBlocks
= fcb
->fcbPLen
/ vcb
->blockSize
;
1381 bcopy ( fcb
->fcbExtents
, extents
, sizeof(HFSPlusExtentRecord
));
1383 if ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))
1384 nodeData
->cnd_rawDevice
= hp
->h_meta
->h_rdev
;
1385 else if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
1386 nodeData
->cnd_linkCount
= hp
->h_meta
->h_nlink
;
1388 if (vp
->v_type
== VLNK
) {
1389 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdType
= SWAP_BE32 (kSymLinkFileType
);
1390 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdCreator
= SWAP_BE32 (kSymLinkCreator
);
1392 /* Set this up as an alias */
1393 #if SUPPORTS_MAC_ALIASES
1394 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdFlags
|= SWAP_BE16 (kIsAlias
);
1401 /*********************************************************************
1403 Sets the name in the filemeta structure
1405 XXX Does not preflight if changing from one size to another
1406 XXX Currently not protected from context switching
1408 *********************************************************************/
1410 void hfs_set_metaname(char *name
, struct hfsfilemeta
*fm
, struct hfsmount
*hfsmp
)
1412 int namelen
= strlen(name
);
1413 char *tname
, *fname
;
1416 DBG_ASSERT(name
!= NULL
);
1417 DBG_ASSERT(fm
!= NULL
);
1418 if (fm
->h_namePtr
) {
1419 DBG_ASSERT(fm
->h_namelen
== strlen(fm
->h_namePtr
));
1420 if (strlen(fm
->h_namePtr
) > MAXHFSVNODELEN
)
1421 DBG_ASSERT(fm
->h_metaflags
& IN_LONGNAME
);
1423 if (fm
->h_metaflags
& IN_LONGNAME
) {
1424 DBG_ASSERT(fm
->h_namePtr
!= (char *)fm
->h_fileName
);
1425 DBG_ASSERT(fm
->h_namePtr
!= NULL
);
1427 #endif //HFS_DIAGNOSTIC
1430 * Details that have to be dealt with:
1431 * 1. No name is allocated. fm->h_namePtr should be NULL
1432 * 2. A name is being changed and:
1433 * a. it was in static space and now cannot fit
1434 * b. It was malloc'd and now will fit in the static
1435 * c. It did and will fit in the static
1436 * This could be a little smarter:
1437 * - Dont re'malloc if the new name is smaller (but then wasting memory)
1438 * - If its a longname but the same size, we still free and malloc
1443 /* Allocate the new memory */
1444 if (namelen
> MAXHFSVNODELEN
) {
1446 * Notice the we ALWAYS allocate, even if the new is less then the old,
1447 * or even if they are the SAME
1449 MALLOC(tname
, char *, namelen
+1, M_TEMP
, M_WAITOK
);
1452 tname
= fm
->h_fileName
;
1454 simple_lock(&hfsmp
->hfs_renamelock
);
1456 /* Check to see if there is something to free, if yes, remember it */
1457 if (fm
->h_metaflags
& IN_LONGNAME
)
1458 fname
= fm
->h_namePtr
;
1463 if (namelen
> MAXHFSVNODELEN
) {
1464 fm
->h_metaflags
|= IN_LONGNAME
;
1467 fm
->h_metaflags
&= ~IN_LONGNAME
;
1470 /* Now copy it over */
1471 bcopy(name
, tname
, namelen
+1);
1473 fm
->h_namePtr
= tname
;
1474 fm
->h_namelen
= namelen
;
1476 simple_unlock(&hfsmp
->hfs_renamelock
);
1478 /* Lastly, free the old, if set */
1480 FREE(fname
, M_TEMP
);
1484 void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
)
1489 DBG_ASSERT(nodeData
!= NULL
);
1490 DBG_ASSERT(fm
!= NULL
);
1491 if (fm
->h_namePtr
) {
1492 DBG_ASSERT(fm
->h_namelen
== strlen(fm
->h_namePtr
));
1493 if (strlen(fm
->h_namePtr
) > MAXHFSVNODELEN
)
1494 DBG_ASSERT(fm
->h_metaflags
& IN_LONGNAME
);
1496 if (fm
->h_metaflags
& IN_LONGNAME
) {
1497 DBG_ASSERT(fm
->h_namePtr
!= (char *)fm
->h_fileName
);
1498 DBG_ASSERT(fm
->h_namePtr
!= NULL
);
1501 DBG_ASSERT(nodeData
->cnm_nameptr
!= NULL
);
1503 if (nodeData
->cnm_length
) {
1504 DBG_ASSERT(strlen(nodeData
->cnm_nameptr
) == nodeData
->cnm_length
);
1507 if (nodeData
->cnm_length
> MAXHFSVNODELEN
)
1508 { DBG_ASSERT(nodeData
->cnm_nameptr
!= nodeData
->cnm_namespace
); }
1509 else if (nodeData
->cnm_nameptr
)
1510 { DBG_ASSERT(nodeData
->cnm_nameptr
== nodeData
->cnm_namespace
); }
1512 #endif //HFS_DIAGNOSTIC
1515 /* Check to see if there is something to free, if yes, remember it */
1516 if (fm
->h_metaflags
& IN_LONGNAME
)
1517 fname
= fm
->h_namePtr
;
1522 if (nodeData
->cnm_length
> MAXHFSVNODELEN
) {
1523 fm
->h_metaflags
|= IN_LONGNAME
;
1525 fm
->h_metaflags
&= ~IN_LONGNAME
;
1528 /* Copy over the name */
1529 if (nodeData
->cnm_nameptr
== nodeData
->cnm_namespace
) {
1530 bcopy(nodeData
->cnm_namespace
, fm
->h_fileName
, nodeData
->cnm_length
+1);
1531 fm
->h_namePtr
= fm
->h_fileName
;
1534 fm
->h_namePtr
= nodeData
->cnm_nameptr
;
1537 fm
->h_namelen
= nodeData
->cnm_length
;
1539 nodeData
->cnm_flags
|= kCatNameIsConsumed
;
1540 nodeData
->cnm_flags
&= ~kCatNameIsAllocated
;
1541 nodeData
->cnm_length
= 0;
1542 nodeData
->cnm_nameptr
= (char *)0;
1543 nodeData
->cnm_namespace
[0] = 0;
1545 /* Lastly, free the old, if set */
1547 FREE(fname
, M_TEMP
);
1552 unsigned long DerivePermissionSummary(uid_t obj_uid
, gid_t obj_gid
, mode_t obj_mode
, struct mount
*mp
, struct ucred
*cred
, struct proc
*p
) {
1554 unsigned long permissions
;
1557 /* User id 0 (root) always gets access. */
1558 if (cred
->cr_uid
== 0) {
1559 permissions
= R_OK
| W_OK
| X_OK
;
1563 /* Otherwise, check the owner. */
1564 if (hfs_catalogentry_owner_rights(obj_uid
, mp
, cred
, p
, false) == 0) {
1565 permissions
= ((unsigned long)obj_mode
& S_IRWXU
) >> 6;
1569 /* Otherwise, check the groups. */
1570 if (! (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
1571 for (i
= 0, gp
= cred
->cr_groups
; i
< cred
->cr_ngroups
; i
++, gp
++) {
1572 if (obj_gid
== *gp
) {
1573 permissions
= ((unsigned long)obj_mode
& S_IRWXG
) >> 3;
1579 /* Otherwise, settle for 'others' access. */
1580 permissions
= (unsigned long)obj_mode
& S_IRWXO
;
1588 int AttributeBlockSize(struct attrlist
*attrlist
) {
1592 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1593 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_PAROBJID | \
1594 ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
1595 ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1596 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST| \
1597 ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) != ATTR_CMN_VALIDMASK)
1598 #error AttributeBlockSize: Missing bits in common mask computation!
1600 DBG_ASSERT((attrlist
->commonattr
& ~ATTR_CMN_VALIDMASK
) == 0);
1602 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
1603 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1604 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | \
1605 ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | \
1606 ATTR_VOL_MOUNTEDDEVICE| ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) != ATTR_VOL_VALIDMASK)
1607 #error AttributeBlockSize: Missing bits in volume mask computation!
1609 DBG_ASSERT((attrlist
->volattr
& ~ATTR_VOL_VALIDMASK
) == 0);
1611 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) != ATTR_DIR_VALIDMASK)
1612 #error AttributeBlockSize: Missing bits in directory mask computation!
1614 DBG_ASSERT((attrlist
->dirattr
& ~ATTR_DIR_VALIDMASK
) == 0);
1615 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
1616 ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | \
1617 ATTR_FILE_FORKLIST | ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1618 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) != ATTR_FILE_VALIDMASK)
1619 #error AttributeBlockSize: Missing bits in file mask computation!
1621 DBG_ASSERT((attrlist
->fileattr
& ~ATTR_FILE_VALIDMASK
) == 0);
1623 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1624 #error AttributeBlockSize: Missing bits in fork mask computation!
1626 DBG_ASSERT((attrlist
->forkattr
& ~ATTR_FORK_VALIDMASK
) == 0);
1630 if ((a
= attrlist
->commonattr
) != 0) {
1631 if (a
& ATTR_CMN_NAME
) size
+= sizeof(struct attrreference
);
1632 if (a
& ATTR_CMN_DEVID
) size
+= sizeof(dev_t
);
1633 if (a
& ATTR_CMN_FSID
) size
+= sizeof(fsid_t
);
1634 if (a
& ATTR_CMN_OBJTYPE
) size
+= sizeof(fsobj_type_t
);
1635 if (a
& ATTR_CMN_OBJTAG
) size
+= sizeof(fsobj_tag_t
);
1636 if (a
& ATTR_CMN_OBJID
) size
+= sizeof(fsobj_id_t
);
1637 if (a
& ATTR_CMN_OBJPERMANENTID
) size
+= sizeof(fsobj_id_t
);
1638 if (a
& ATTR_CMN_PAROBJID
) size
+= sizeof(fsobj_id_t
);
1639 if (a
& ATTR_CMN_SCRIPT
) size
+= sizeof(text_encoding_t
);
1640 if (a
& ATTR_CMN_CRTIME
) size
+= sizeof(struct timespec
);
1641 if (a
& ATTR_CMN_MODTIME
) size
+= sizeof(struct timespec
);
1642 if (a
& ATTR_CMN_CHGTIME
) size
+= sizeof(struct timespec
);
1643 if (a
& ATTR_CMN_ACCTIME
) size
+= sizeof(struct timespec
);
1644 if (a
& ATTR_CMN_BKUPTIME
) size
+= sizeof(struct timespec
);
1645 if (a
& ATTR_CMN_FNDRINFO
) size
+= 32 * sizeof(UInt8
);
1646 if (a
& ATTR_CMN_OWNERID
) size
+= sizeof(uid_t
);
1647 if (a
& ATTR_CMN_GRPID
) size
+= sizeof(gid_t
);
1648 if (a
& ATTR_CMN_ACCESSMASK
) size
+= sizeof(u_long
);
1649 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) size
+= sizeof(u_long
);
1650 if (a
& ATTR_CMN_NAMEDATTRLIST
) size
+= sizeof(struct attrreference
);
1651 if (a
& ATTR_CMN_FLAGS
) size
+= sizeof(u_long
);
1652 if (a
& ATTR_CMN_USERACCESS
) size
+= sizeof(u_long
);
1654 if ((a
= attrlist
->volattr
) != 0) {
1655 if (a
& ATTR_VOL_FSTYPE
) size
+= sizeof(u_long
);
1656 if (a
& ATTR_VOL_SIGNATURE
) size
+= sizeof(u_long
);
1657 if (a
& ATTR_VOL_SIZE
) size
+= sizeof(off_t
);
1658 if (a
& ATTR_VOL_SPACEFREE
) size
+= sizeof(off_t
);
1659 if (a
& ATTR_VOL_SPACEAVAIL
) size
+= sizeof(off_t
);
1660 if (a
& ATTR_VOL_MINALLOCATION
) size
+= sizeof(off_t
);
1661 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) size
+= sizeof(off_t
);
1662 if (a
& ATTR_VOL_IOBLOCKSIZE
) size
+= sizeof(u_long
);
1663 if (a
& ATTR_VOL_OBJCOUNT
) size
+= sizeof(u_long
);
1664 if (a
& ATTR_VOL_FILECOUNT
) size
+= sizeof(u_long
);
1665 if (a
& ATTR_VOL_DIRCOUNT
) size
+= sizeof(u_long
);
1666 if (a
& ATTR_VOL_MAXOBJCOUNT
) size
+= sizeof(u_long
);
1667 if (a
& ATTR_VOL_MOUNTPOINT
) size
+= sizeof(struct attrreference
);
1668 if (a
& ATTR_VOL_NAME
) size
+= sizeof(struct attrreference
);
1669 if (a
& ATTR_VOL_MOUNTFLAGS
) size
+= sizeof(u_long
);
1670 if (a
& ATTR_VOL_MOUNTEDDEVICE
) size
+= sizeof(struct attrreference
);
1671 if (a
& ATTR_VOL_ENCODINGSUSED
) size
+= sizeof(unsigned long long);
1672 if (a
& ATTR_VOL_CAPABILITIES
) size
+= sizeof(vol_capabilities_attr_t
);
1673 if (a
& ATTR_VOL_ATTRIBUTES
) size
+= sizeof(vol_attributes_attr_t
);
1675 if ((a
= attrlist
->dirattr
) != 0) {
1676 if (a
& ATTR_DIR_LINKCOUNT
) size
+= sizeof(u_long
);
1677 if (a
& ATTR_DIR_ENTRYCOUNT
) size
+= sizeof(u_long
);
1678 if (a
& ATTR_DIR_MOUNTSTATUS
) size
+= sizeof(u_long
);
1680 if ((a
= attrlist
->fileattr
) != 0) {
1681 if (a
& ATTR_FILE_LINKCOUNT
) size
+= sizeof(u_long
);
1682 if (a
& ATTR_FILE_TOTALSIZE
) size
+= sizeof(off_t
);
1683 if (a
& ATTR_FILE_ALLOCSIZE
) size
+= sizeof(off_t
);
1684 if (a
& ATTR_FILE_IOBLOCKSIZE
) size
+= sizeof(size_t);
1685 if (a
& ATTR_FILE_CLUMPSIZE
) size
+= sizeof(off_t
);
1686 if (a
& ATTR_FILE_DEVTYPE
) size
+= sizeof(u_long
);
1687 if (a
& ATTR_FILE_FILETYPE
) size
+= sizeof(u_long
);
1688 if (a
& ATTR_FILE_FORKCOUNT
) size
+= sizeof(u_long
);
1689 if (a
& ATTR_FILE_FORKLIST
) size
+= sizeof(struct attrreference
);
1690 if (a
& ATTR_FILE_DATALENGTH
) size
+= sizeof(off_t
);
1691 if (a
& ATTR_FILE_DATAALLOCSIZE
) size
+= sizeof(off_t
);
1692 if (a
& ATTR_FILE_DATAEXTENTS
) size
+= sizeof(extentrecord
);
1693 if (a
& ATTR_FILE_RSRCLENGTH
) size
+= sizeof(off_t
);
1694 if (a
& ATTR_FILE_RSRCALLOCSIZE
) size
+= sizeof(off_t
);
1695 if (a
& ATTR_FILE_RSRCEXTENTS
) size
+= sizeof(extentrecord
);
1697 if ((a
= attrlist
->forkattr
) != 0) {
1698 if (a
& ATTR_FORK_TOTALSIZE
) size
+= sizeof(off_t
);
1699 if (a
& ATTR_FORK_ALLOCSIZE
) size
+= sizeof(off_t
);
1707 char* FindMountpointName(struct mount
*mp
) {
1708 size_t namelength
= strlen(mp
->mnt_stat
.f_mntonname
);
1712 if (namelength
== 0) return NULL
;
1714 /* Look backwards through the name string, looking for the first slash
1715 encountered (which must precede the last part of the pathname)
1717 for (c
= mp
->mnt_stat
.f_mntonname
+ namelength
- 1; namelength
> 0; --c
, --namelength
) {
1720 } else if (foundchars
) {
1725 return mp
->mnt_stat
.f_mntonname
;
1730 void PackObjectName(struct vnode
*vp
,
1733 void **attrbufptrptr
,
1734 void **varbufptrptr
) {
1739 /* The name of an object may be incorrect for the root of a mounted filesystem
1740 because it may be mounted on a different directory name than the name of the
1741 volume (such as "blah-1". For the root directory, it's best to return the
1742 last element of the location where the volume's mounted:
1744 if ((vp
->v_flag
& VROOT
) && (mpname
= FindMountpointName(vp
->v_mount
))) {
1745 mpnamelen
= strlen(mpname
);
1747 /* Trim off any trailing slashes: */
1748 while ((mpnamelen
> 0) && (mpname
[mpnamelen
-1] == '/')) {
1752 /* If there's anything left, use it instead of the volume's name */
1753 if (mpnamelen
> 0) {
1755 namelen
= mpnamelen
;
1759 attrlength
= namelen
+ 1;
1760 ((struct attrreference
*)(*attrbufptrptr
))->attr_dataoffset
= (char *)(*varbufptrptr
) - (char *)(*attrbufptrptr
);
1761 ((struct attrreference
*)(*attrbufptrptr
))->attr_length
= attrlength
;
1762 (void) strncpy((unsigned char *)(*varbufptrptr
), name
, attrlength
);
1764 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1765 (char *)(*varbufptrptr
) += attrlength
+ ((4 - (attrlength
& 3)) & 3);
1766 ++((struct attrreference
*)(*attrbufptrptr
));
1771 void PackVolCommonAttributes(struct attrlist
*alist
,
1772 struct vnode
*root_vp
,
1773 struct hfsCatalogInfo
*root_catInfo
,
1774 void **attrbufptrptr
,
1775 void **varbufptrptr
) {
1779 struct hfsnode
*root_hp
= VTOH(root_vp
);
1780 struct mount
*mp
= VTOVFS(root_vp
);
1781 struct hfsmount
*hfsmp
= VTOHFS(root_vp
);
1782 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1785 attrbufptr
= *attrbufptrptr
;
1786 varbufptr
= *varbufptrptr
;
1788 if ((a
= alist
->commonattr
) != 0) {
1789 if (a
& ATTR_CMN_NAME
) {
1790 PackObjectName(root_vp
, H_NAME(root_hp
), root_hp
->h_meta
->h_namelen
, &attrbufptr
, &varbufptr
);
1792 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1793 if (a
& ATTR_CMN_FSID
) {
1794 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1795 ++((fsid_t
*)attrbufptr
);
1797 if (a
& ATTR_CMN_OBJTYPE
) *((fsobj_type_t
*)attrbufptr
)++ = 0;
1798 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1799 if (a
& ATTR_CMN_OBJID
) {
1800 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1801 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1802 ++((fsobj_id_t
*)attrbufptr
);
1804 if (a
& ATTR_CMN_OBJPERMANENTID
) {
1805 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1806 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1807 ++((fsobj_id_t
*)attrbufptr
);
1809 if (a
& ATTR_CMN_PAROBJID
) {
1810 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1811 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1812 ++((fsobj_id_t
*)attrbufptr
);
1815 if (a
& ATTR_CMN_SCRIPT
) *((text_encoding_t
*)attrbufptr
)++ = vcb
->volumeNameEncodingHint
;
1816 /* NOTE: all VCB dates are in Mac OS time */
1817 if (a
& ATTR_CMN_CRTIME
) {
1818 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbCrDate
);
1819 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1820 ++((struct timespec
*)attrbufptr
);
1822 if (a
& ATTR_CMN_MODTIME
) {
1823 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1824 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1825 ++((struct timespec
*)attrbufptr
);
1827 if (a
& ATTR_CMN_CHGTIME
) {
1828 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1829 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1830 ++((struct timespec
*)attrbufptr
);
1832 if (a
& ATTR_CMN_ACCTIME
) {
1833 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1834 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1835 ++((struct timespec
*)attrbufptr
);
1837 if (a
& ATTR_CMN_BKUPTIME
) {
1838 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbVolBkUp
);
1839 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1840 ++((struct timespec
*)attrbufptr
);
1842 if (a
& ATTR_CMN_FNDRINFO
) {
1843 bcopy (&vcb
->vcbFndrInfo
, attrbufptr
, sizeof(vcb
->vcbFndrInfo
));
1844 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1847 if (a
& ATTR_CMN_OWNERID
) {
1848 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1849 *((uid_t
*)attrbufptr
)++ =
1850 (VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
;
1852 *((uid_t
*)attrbufptr
)++ =
1853 (root_hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: root_hp
->h_meta
->h_uid
;
1856 if (a
& ATTR_CMN_GRPID
) {
1857 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1858 *((gid_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_gid
;
1860 *((gid_t
*)attrbufptr
)++ = root_hp
->h_meta
->h_gid
;
1863 if (a
& ATTR_CMN_ACCESSMASK
) *((u_long
*)attrbufptr
)++ = (u_long
)root_hp
->h_meta
->h_mode
;
1864 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
1865 if (a
& ATTR_CMN_NAMEDATTRLIST
) {
1867 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1868 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1870 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1871 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1872 ++((struct attrreference
*)attrbufptr
);
1874 if (a
& ATTR_CMN_FLAGS
) *((u_long
*)attrbufptr
)++ = root_hp
->h_meta
->h_pflags
;
1875 if (a
& ATTR_CMN_USERACCESS
) {
1876 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1877 *((u_long
*)attrbufptr
)++ =
1878 DerivePermissionSummary((VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
,
1879 VTOHFS(root_vp
)->hfs_gid
,
1880 root_hp
->h_meta
->h_mode
,
1882 current_proc()->p_ucred
,
1885 *((u_long
*)attrbufptr
)++ =
1886 DerivePermissionSummary((root_hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: root_hp
->h_meta
->h_uid
,
1887 root_hp
->h_meta
->h_gid
,
1888 root_hp
->h_meta
->h_mode
,
1890 current_proc()->p_ucred
,
1896 *attrbufptrptr
= attrbufptr
;
1897 *varbufptrptr
= varbufptr
;
1902 void PackVolAttributeBlock(struct attrlist
*alist
,
1903 struct vnode
*root_vp
,
1904 struct hfsCatalogInfo
*root_catInfo
,
1905 void **attrbufptrptr
,
1906 void **varbufptrptr
) {
1910 struct mount
*mp
= VTOVFS(root_vp
);
1911 struct hfsmount
*hfsmp
= VTOHFS(root_vp
);
1912 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1915 attrbufptr
= *attrbufptrptr
;
1916 varbufptr
= *varbufptrptr
;
1918 if ((a
= alist
->volattr
) != 0) {
1920 if (a
& ATTR_VOL_FSTYPE
) *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_vfc
->vfc_typenum
;
1921 if (a
& ATTR_VOL_SIGNATURE
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbSigWord
;
1922 if (a
& ATTR_VOL_SIZE
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->totalBlocks
* (off_t
)vcb
->blockSize
;
1923 if (a
& ATTR_VOL_SPACEFREE
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->freeBlocks
* (off_t
)vcb
->blockSize
;
1924 if (a
& ATTR_VOL_SPACEAVAIL
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->freeBlocks
* (off_t
)vcb
->blockSize
;
1925 if (a
& ATTR_VOL_MINALLOCATION
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->blockSize
;
1926 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) *((off_t
*)attrbufptr
)++ = (off_t
)(vcb
->vcbClpSiz
);
1927 if (a
& ATTR_VOL_IOBLOCKSIZE
) *((u_long
*)attrbufptr
)++ = (u_long
)hfsmp
->hfs_logBlockSize
;
1928 if (a
& ATTR_VOL_OBJCOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
+ (u_long
)vcb
->vcbDirCnt
;
1929 if (a
& ATTR_VOL_FILECOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
;
1930 if (a
& ATTR_VOL_DIRCOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbDirCnt
;
1931 if (a
& ATTR_VOL_MAXOBJCOUNT
) *((u_long
*)attrbufptr
)++ = 0xFFFFFFFF;
1932 if (a
& ATTR_VOL_MOUNTPOINT
) {
1933 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1934 ((struct attrreference
*)attrbufptr
)->attr_length
= strlen(mp
->mnt_stat
.f_mntonname
) + 1;
1935 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1936 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1937 (void) bcopy(mp
->mnt_stat
.f_mntonname
, varbufptr
, attrlength
);
1939 /* Advance beyond the space just allocated: */
1940 (char *)varbufptr
+= attrlength
;
1941 ++((struct attrreference
*)attrbufptr
);
1943 if (a
& ATTR_VOL_NAME
) {
1944 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1945 ((struct attrreference
*)attrbufptr
)->attr_length
= VTOH(root_vp
)->h_meta
->h_namelen
+ 1;
1946 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1947 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1948 bcopy(H_NAME(VTOH(root_vp
)), varbufptr
, attrlength
);
1950 /* Advance beyond the space just allocated: */
1951 (char *)varbufptr
+= attrlength
;
1952 ++((struct attrreference
*)attrbufptr
);
1954 if (a
& ATTR_VOL_MOUNTFLAGS
) *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_flag
;
1955 if (a
& ATTR_VOL_MOUNTEDDEVICE
) {
1956 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1957 ((struct attrreference
*)attrbufptr
)->attr_length
= strlen(mp
->mnt_stat
.f_mntfromname
) + 1;
1958 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1959 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1960 (void) bcopy(mp
->mnt_stat
.f_mntfromname
, varbufptr
, attrlength
);
1962 /* Advance beyond the space just allocated: */
1963 (char *)varbufptr
+= attrlength
;
1964 ++((struct attrreference
*)attrbufptr
);
1966 if (a
& ATTR_VOL_ENCODINGSUSED
) *((unsigned long long *)attrbufptr
)++ = (unsigned long long)vcb
->encodingsBitmap
;
1967 if (a
& ATTR_VOL_CAPABILITIES
) {
1968 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
1969 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1970 VOL_CAP_FMT_PERSISTENTOBJECTIDS
| VOL_CAP_FMT_SYMBOLICLINKS
| VOL_CAP_FMT_HARDLINKS
;
1971 } else { /* Plain HFS */
1972 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1973 VOL_CAP_FMT_PERSISTENTOBJECTIDS
;
1975 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_INTERFACES
] =
1976 VOL_CAP_INT_SEARCHFS
| VOL_CAP_INT_ATTRLIST
| VOL_CAP_INT_NFSEXPORT
| VOL_CAP_INT_READDIRATTR
;
1977 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
1978 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
1980 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_FORMAT
] =
1981 VOL_CAP_FMT_PERSISTENTOBJECTIDS
| VOL_CAP_FMT_SYMBOLICLINKS
| VOL_CAP_FMT_HARDLINKS
;
1982 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_INTERFACES
] =
1983 VOL_CAP_INT_SEARCHFS
| VOL_CAP_INT_ATTRLIST
| VOL_CAP_INT_NFSEXPORT
| VOL_CAP_INT_READDIRATTR
;
1984 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
1985 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
1987 ++((vol_capabilities_attr_t
*)attrbufptr
);
1989 if (a
& ATTR_VOL_ATTRIBUTES
) {
1990 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1991 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.volattr
= ATTR_VOL_VALIDMASK
;
1992 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1993 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1994 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.forkattr
= ATTR_FORK_VALIDMASK
;
1996 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1997 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.volattr
= ATTR_VOL_VALIDMASK
;
1998 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1999 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.fileattr
= ATTR_FILE_VALIDMASK
;
2000 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.forkattr
= ATTR_FORK_VALIDMASK
;
2002 ++((vol_attributes_attr_t
*)attrbufptr
);
2007 *attrbufptrptr
= attrbufptr
;
2008 *varbufptrptr
= varbufptr
;
2014 void PackVolumeInfo(struct attrlist
*alist
,
2015 struct vnode
*root_vp
,
2016 struct hfsCatalogInfo
*root_catinfo
,
2017 void **attrbufptrptr
,
2018 void **varbufptrptr
) {
2020 PackVolCommonAttributes(alist
, root_vp
, root_catinfo
, attrbufptrptr
, varbufptrptr
);
2021 PackVolAttributeBlock(alist
, root_vp
, root_catinfo
, attrbufptrptr
, varbufptrptr
);
2024 // Pack the common attribute contents of an objects hfsCatalogInfo
2025 void PackCommonCatalogInfoAttributeBlock(struct attrlist
*alist
,
2026 struct vnode
*root_vp
,
2027 struct hfsCatalogInfo
*catalogInfo
,
2028 void **attrbufptrptr
,
2029 void **varbufptrptr
)
2039 attrbufptr
= *attrbufptrptr
;
2040 varbufptr
= *varbufptrptr
;
2041 isHFSPlus
= (VTOVCB(root_vp
)->vcbSigWord
== kHFSPlusSigWord
);
2043 if ((a
= alist
->commonattr
) != 0)
2045 if (a
& ATTR_CMN_NAME
)
2047 attrlength
= strlen(catalogInfo
->nodeData
.cnm_nameptr
) + 1;
2048 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
2049 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2050 (void) strncpy((unsigned char *)varbufptr
,
2051 catalogInfo
->nodeData
.cnm_nameptr
, attrlength
);
2053 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2054 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2055 ++((struct attrreference
*)attrbufptr
);
2057 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = H_DEV(hp
);
2058 if (a
& ATTR_CMN_FSID
) {
2059 *((fsid_t
*)attrbufptr
) = VTOVFS(root_vp
)->mnt_stat
.f_fsid
;
2060 ++((fsid_t
*)attrbufptr
);
2062 if (a
& ATTR_CMN_OBJTYPE
)
2064 switch (catalogInfo
->nodeData
.cnd_type
) {
2065 case kCatalogFolderNode
:
2066 *((fsobj_type_t
*)attrbufptr
)++ = VDIR
;
2069 case kCatalogFileNode
:
2070 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2071 if ((HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) &&
2072 (catalogInfo
->nodeData
.cnd_mode
& IFMT
)) {
2073 *((fsobj_type_t
*)attrbufptr
)++ =
2074 IFTOVT((mode_t
)catalogInfo
->nodeData
.cnd_mode
);
2076 *((fsobj_type_t
*)attrbufptr
)++ = VREG
;
2081 *((fsobj_type_t
*)attrbufptr
)++ = VNON
;
2085 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = root_vp
->v_tag
;
2086 if (a
& ATTR_CMN_OBJID
) {
2089 /* For hard links use the link's cnid */
2090 if (catalogInfo
->nodeData
.cnd_iNodeNumCopy
!= 0)
2091 cnid
= catalogInfo
->nodeData
.cnd_linkCNID
;
2093 cnid
= catalogInfo
->nodeData
.cnd_nodeID
;
2094 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2095 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2096 ++((fsobj_id_t
*)attrbufptr
);
2098 if (a
& ATTR_CMN_OBJPERMANENTID
) {
2101 /* For hard links use the link's cnid */
2102 if (catalogInfo
->nodeData
.cnd_iNodeNumCopy
!= 0)
2103 cnid
= catalogInfo
->nodeData
.cnd_linkCNID
;
2105 cnid
= catalogInfo
->nodeData
.cnd_nodeID
;
2106 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
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
) {
2216 if (catalogInfo
->nodeData
.cnd_mode
& IFMT
)
2217 flags
= catalogInfo
->nodeData
.cnd_ownerFlags
|
2218 catalogInfo
->nodeData
.cnd_adminFlags
<< 16;
2222 if (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) {
2223 if (catalogInfo
->nodeData
.cnd_flags
& kHFSFileLockedMask
)
2224 flags
|= UF_IMMUTABLE
;
2226 flags
&= ~UF_IMMUTABLE
;
2228 *((u_long
*)attrbufptr
)++ = flags
;
2230 if (a
& ATTR_CMN_USERACCESS
) {
2231 if ((VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) ||
2232 ((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)) {
2233 *((u_long
*)attrbufptr
)++ =
2234 DerivePermissionSummary((VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
,
2235 VTOHFS(root_vp
)->hfs_gid
,
2236 #if OVERRIDE_UNKNOWN_PERMISSIONS
2237 (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) ? VTOHFS(root_vp
)->hfs_file_mask
: VTOHFS(root_vp
)->hfs_dir_mask
,
2239 (catalogInfo
->nodeData
.cnd_mode
& IFMT
) ?
2240 (u_long
)catalogInfo
->nodeData
.cnd_mode
:
2241 ((catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) ?
2242 VTOHFS(root_vp
)->hfs_file_mask
:
2243 VTOHFS(root_vp
)->hfs_dir_mask
),
2246 current_proc()->p_ucred
,
2249 *((u_long
*)attrbufptr
)++ =
2250 DerivePermissionSummary((catalogInfo
->nodeData
.cnd_ownerID
== UNKNOWNUID
) ? console_user
: catalogInfo
->nodeData
.cnd_ownerID
,
2251 catalogInfo
->nodeData
.cnd_groupID
,
2252 (mode_t
)catalogInfo
->nodeData
.cnd_mode
,
2254 current_proc()->p_ucred
,
2260 *attrbufptrptr
= attrbufptr
;
2261 *varbufptrptr
= varbufptr
;
2265 void PackCommonAttributeBlock(struct attrlist
*alist
,
2267 struct hfsCatalogInfo
*catInfo
,
2268 void **attrbufptrptr
,
2269 void **varbufptrptr
) {
2278 attrbufptr
= *attrbufptrptr
;
2279 varbufptr
= *varbufptrptr
;
2281 if ((a
= alist
->commonattr
) != 0) {
2282 if (a
& ATTR_CMN_NAME
) {
2283 PackObjectName(vp
, H_NAME(hp
), hp
->h_meta
->h_namelen
, &attrbufptr
, &varbufptr
);
2285 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = H_DEV(hp
);
2286 if (a
& ATTR_CMN_FSID
) {
2287 *((fsid_t
*)attrbufptr
) = VTOVFS(vp
)->mnt_stat
.f_fsid
;
2288 ++((fsid_t
*)attrbufptr
);
2290 if (a
& ATTR_CMN_OBJTYPE
) *((fsobj_type_t
*)attrbufptr
)++ = vp
->v_type
;
2291 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = vp
->v_tag
;
2292 if (a
& ATTR_CMN_OBJID
) {
2295 /* For hard links use the link's cnid */
2296 if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
2297 cnid
= catInfo
->nodeData
.cnd_linkCNID
;
2299 cnid
= H_FILEID(hp
);
2300 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2301 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2302 ++((fsobj_id_t
*)attrbufptr
);
2304 if (a
& ATTR_CMN_OBJPERMANENTID
) {
2307 /* For hard links use the link's cnid */
2308 if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
2309 cnid
= catInfo
->nodeData
.cnd_linkCNID
;
2311 cnid
= H_FILEID(hp
);
2312 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2313 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2314 ++((fsobj_id_t
*)attrbufptr
);
2316 if (a
& ATTR_CMN_PAROBJID
) {
2317 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= H_DIRID(hp
);
2318 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2319 ++((fsobj_id_t
*)attrbufptr
);
2321 if (a
& ATTR_CMN_SCRIPT
)
2323 if (HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) {
2324 *((text_encoding_t
*)attrbufptr
)++ = catInfo
->nodeData
.cnd_textEncoding
;
2326 *((text_encoding_t
*)attrbufptr
)++ = VTOHFS(vp
)->hfs_encoding
;
2329 if (a
& ATTR_CMN_CRTIME
) {
2330 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_crtime
;
2331 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2332 ++((struct timespec
*)attrbufptr
);
2334 if (a
& ATTR_CMN_MODTIME
) {
2335 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_mtime
;
2336 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2337 ++((struct timespec
*)attrbufptr
);
2339 if (a
& ATTR_CMN_CHGTIME
) {
2340 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_ctime
;
2341 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2342 ++((struct timespec
*)attrbufptr
);
2344 if (a
& ATTR_CMN_ACCTIME
) {
2345 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_atime
;
2346 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2347 ++((struct timespec
*)attrbufptr
);
2349 if (a
& ATTR_CMN_BKUPTIME
) {
2350 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_butime
;
2351 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2352 ++((struct timespec
*)attrbufptr
);
2354 if (a
& ATTR_CMN_FNDRINFO
) {
2355 bcopy (&catInfo
->nodeData
.cnd_finderInfo
, attrbufptr
, sizeof(catInfo
->nodeData
.cnd_finderInfo
));
2356 (char *)attrbufptr
+= sizeof(catInfo
->nodeData
.cnd_finderInfo
);
2358 if (a
& ATTR_CMN_OWNERID
) {
2359 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2360 *((uid_t
*)attrbufptr
)++ =
2361 (VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(vp
)->hfs_uid
;
2363 *((uid_t
*)attrbufptr
)++ =
2364 (hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: hp
->h_meta
->h_uid
;
2367 if (a
& ATTR_CMN_GRPID
) {
2368 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2369 *((gid_t
*)attrbufptr
)++ = VTOHFS(vp
)->hfs_gid
;
2371 *((gid_t
*)attrbufptr
)++ = hp
->h_meta
->h_gid
;
2374 if (a
& ATTR_CMN_ACCESSMASK
) *((u_long
*)attrbufptr
)++ = (u_long
)hp
->h_meta
->h_mode
;
2375 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
2376 if (a
& ATTR_CMN_NAMEDATTRLIST
) {
2378 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2379 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2381 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2382 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2383 ++((struct attrreference
*)attrbufptr
);
2385 if (a
& ATTR_CMN_FLAGS
) *((u_long
*)attrbufptr
)++ = hp
->h_meta
->h_pflags
;
2386 if (a
& ATTR_CMN_USERACCESS
) {
2387 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2388 *((u_long
*)attrbufptr
)++ =
2389 DerivePermissionSummary((VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(vp
)->hfs_uid
,
2390 VTOHFS(vp
)->hfs_gid
,
2393 current_proc()->p_ucred
,
2396 *((u_long
*)attrbufptr
)++ =
2397 DerivePermissionSummary((hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: hp
->h_meta
->h_uid
,
2401 current_proc()->p_ucred
,
2407 *attrbufptrptr
= attrbufptr
;
2408 *varbufptrptr
= varbufptr
;
2412 // Pack the directory attributes given hfsCatalogInfo
2413 void PackCatalogInfoDirAttributeBlock( struct attrlist
*alist
, struct vnode
*vp
,
2414 struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2420 attrbufptr
= *attrbufptrptr
;
2423 if ( (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) && (a
!= 0) ) {
2424 valence
= catInfo
->nodeData
.cnd_valence
;
2425 if ((catInfo
->nodeData
.cnm_parID
== kRootParID
) &&
2426 (VTOHFS(vp
)->hfs_private_metadata_dir
!= 0)) {
2427 --valence
; /* hide private dir */
2429 /* The 'link count' is faked */
2430 if (a
& ATTR_DIR_LINKCOUNT
)
2431 *((u_long
*)attrbufptr
)++ = 2 + valence
;
2432 if (a
& ATTR_DIR_ENTRYCOUNT
)
2433 *((u_long
*)attrbufptr
)++ = valence
;
2434 if (a
& ATTR_DIR_MOUNTSTATUS
)
2435 *((u_long
*)attrbufptr
)++ = 0;
2438 *attrbufptrptr
= attrbufptr
;
2442 void PackDirAttributeBlock(struct attrlist
*alist
,
2444 struct hfsCatalogInfo
*catInfo
,
2445 void **attrbufptrptr
,
2446 void **varbufptrptr
) {
2451 attrbufptr
= *attrbufptrptr
;
2454 if ((vp
->v_type
== VDIR
) && (a
!= 0)) {
2455 valence
= catInfo
->nodeData
.cnd_valence
;
2456 if ((catInfo
->nodeData
.cnm_parID
== kRootParID
) &&
2457 (VTOHFS(vp
)->hfs_private_metadata_dir
!= 0)) {
2458 --valence
; /* hide private dir */
2461 /* The 'link count' is faked */
2462 if (a
& ATTR_DIR_LINKCOUNT
)
2463 *((u_long
*)attrbufptr
)++ = 2 + valence
;
2464 if (a
& ATTR_DIR_ENTRYCOUNT
)
2465 *((u_long
*)attrbufptr
)++ = valence
;
2466 if (a
& ATTR_DIR_MOUNTSTATUS
) {
2467 if (vp
->v_mountedhere
) {
2468 *((u_long
*)attrbufptr
)++ = DIR_MNTSTATUS_MNTPOINT
;
2470 *((u_long
*)attrbufptr
)++ = 0;
2475 *attrbufptrptr
= attrbufptr
;
2480 // Pack the file attributes from the hfsCatalogInfo for the file.
2481 void PackCatalogInfoFileAttributeBlock( struct attrlist
*alist
, struct vnode
*root_vp
, struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2487 ExtendedVCB
*vcb
= VTOVCB(root_vp
);
2489 attrbufptr
= *attrbufptrptr
;
2490 varbufptr
= *varbufptrptr
;
2492 a
= alist
->fileattr
;
2493 if ( (catInfo
->nodeData
.cnd_type
== kCatalogFileNode
) && (a
!= 0) )
2496 if (a
& ATTR_FILE_LINKCOUNT
) {
2497 u_long linkcnt
= catInfo
->nodeData
.cnd_linkCount
;
2501 *((u_long
*)attrbufptr
)++ = linkcnt
;
2504 if (a
& ATTR_FILE_LINKCOUNT
) *((u_long
*)attrbufptr
)++ = 1;
2506 if (a
& ATTR_FILE_TOTALSIZE
) {
2507 *((off_t
*)attrbufptr
)++ =
2508 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
+
2509 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2511 if (a
& ATTR_FILE_ALLOCSIZE
) {
2512 *((off_t
*)attrbufptr
)++ =
2513 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
) +
2514 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2516 if (a
& ATTR_FILE_IOBLOCKSIZE
) {
2517 *((u_long
*)attrbufptr
)++ = (u_long
)(VTOHFS(root_vp
)->hfs_logBlockSize
);
2519 if (a
& ATTR_FILE_CLUMPSIZE
) {
2520 *((u_long
*)attrbufptr
)++ = vcb
->vcbClpSiz
;
2522 if (a
& ATTR_FILE_DEVTYPE
) {
2526 filetype
= (catInfo
->nodeData
.cnd_mode
& IFMT
);
2527 if (filetype
== IFCHR
|| filetype
== IFBLK
)
2528 rawdev
= (u_long
)catInfo
->nodeData
.cnd_rawDevice
;
2532 *((u_long
*)attrbufptr
)++ = rawdev
;
2534 if (a
& ATTR_FILE_FILETYPE
) {
2535 *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD */
2537 if (a
& ATTR_FILE_FORKCOUNT
) {
2538 *((u_long
*)attrbufptr
)++ = 2; /* XXX PPD */
2540 if (a
& ATTR_FILE_FORKLIST
) {
2542 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2543 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2545 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2546 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2547 ++((struct attrreference
*)attrbufptr
);
2549 if (a
& ATTR_FILE_DATALENGTH
) {
2550 *((off_t
*)attrbufptr
)++ =
2551 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
;
2553 if (a
& ATTR_FILE_DATAALLOCSIZE
) {
2554 *((off_t
*)attrbufptr
)++ =
2555 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2557 if (a
& ATTR_FILE_DATAEXTENTS
) {
2558 bcopy(&catInfo
->nodeData
.cnd_datafork
.extents
, attrbufptr
, sizeof(extentrecord
));
2559 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2561 if (a
& ATTR_FILE_RSRCLENGTH
) {
2562 *((off_t
*)attrbufptr
)++ =
2563 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2565 if (a
& ATTR_FILE_RSRCALLOCSIZE
) {
2566 *((off_t
*)attrbufptr
)++ =
2567 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2569 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2570 bcopy(&catInfo
->nodeData
.cnd_rsrcfork
.extents
, attrbufptr
, sizeof(extentrecord
));
2571 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2575 *attrbufptrptr
= attrbufptr
;
2576 *varbufptrptr
= varbufptr
;
2580 void PackFileAttributeBlock(struct attrlist
*alist
,
2582 struct hfsCatalogInfo
*catInfo
,
2583 void **attrbufptrptr
,
2584 void **varbufptrptr
) {
2585 struct hfsnode
*hp
= VTOH(vp
);
2586 FCB
*fcb
= HTOFCB(hp
);
2587 ExtendedVCB
*vcb
= HTOVCB(hp
);
2588 Boolean isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
2589 void *attrbufptr
= *attrbufptrptr
;
2590 void *varbufptr
= *varbufptrptr
;
2591 attrgroup_t a
= alist
->fileattr
;
2596 if (a
& ATTR_FILE_LINKCOUNT
) {
2597 u_long linkcnt
= catInfo
->nodeData
.cnd_linkCount
;
2601 *((u_long
*)attrbufptr
)++ = linkcnt
;
2604 if (a
& ATTR_FILE_LINKCOUNT
) *((u_long
*)attrbufptr
)++ = 1;
2606 if (a
& ATTR_FILE_TOTALSIZE
) {
2607 *((off_t
*)attrbufptr
)++ =
2608 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
+
2609 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2611 if (a
& ATTR_FILE_ALLOCSIZE
) {
2612 switch (H_FORKTYPE(hp
)) {
2614 *((off_t
*)attrbufptr
)++ =
2615 (off_t
)fcb
->fcbPLen
+
2616 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2619 *((off_t
*)attrbufptr
)++ =
2620 (off_t
)fcb
->fcbPLen
+
2621 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2624 *((off_t
*)attrbufptr
)++ =
2625 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
) +
2626 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2629 if (a
& ATTR_FILE_IOBLOCKSIZE
) *((u_long
*)attrbufptr
)++ = GetLogicalBlockSize(vp
);
2630 if (a
& ATTR_FILE_CLUMPSIZE
) *((u_long
*)attrbufptr
)++ = fcb
->fcbClmpSize
;
2631 if (a
& ATTR_FILE_DEVTYPE
) {
2634 if ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))
2635 rawdev
= (u_long
)catInfo
->nodeData
.cnd_rawDevice
;
2638 *((u_long
*)attrbufptr
)++ = rawdev
;
2640 if (a
& ATTR_FILE_FILETYPE
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD */
2641 if (a
& ATTR_FILE_FORKCOUNT
) *((u_long
*)attrbufptr
)++ = 2; /* XXX PPD */
2642 if (a
& ATTR_FILE_FORKLIST
) {
2644 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2645 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2647 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2648 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2649 ++((struct attrreference
*)attrbufptr
);
2651 if (H_FORKTYPE(hp
) == kDataFork
) {
2652 if (a
& ATTR_FILE_DATALENGTH
)
2653 *((off_t
*)attrbufptr
)++ = fcb
->fcbEOF
;
2654 if (a
& ATTR_FILE_DATAALLOCSIZE
) *((off_t
*)attrbufptr
)++ = fcb
->fcbPLen
;
2655 if (a
& ATTR_FILE_DATAEXTENTS
) {
2656 bcopy ( fcb
->fcbExtents
, attrbufptr
, sizeof(extentrecord
));
2657 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2660 if (a
& ATTR_FILE_DATALENGTH
) {
2661 *((off_t
*)attrbufptr
)++ =
2662 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
;
2664 if (a
& ATTR_FILE_DATAALLOCSIZE
) {
2665 *((off_t
*)attrbufptr
)++ =
2666 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2668 if (a
& ATTR_FILE_DATAEXTENTS
) {
2669 bcopy(&catInfo
->nodeData
.cnd_datafork
.extents
, attrbufptr
, sizeof(extentrecord
));
2670 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2673 if (H_FORKTYPE(hp
) == kRsrcFork
) {
2674 if (a
& ATTR_FILE_RSRCLENGTH
)
2675 *((off_t
*)attrbufptr
)++ = fcb
->fcbEOF
;
2676 if (a
& ATTR_FILE_RSRCALLOCSIZE
) *((off_t
*)attrbufptr
)++ = fcb
->fcbPLen
;
2677 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2678 bcopy ( fcb
->fcbExtents
, attrbufptr
, sizeof(extentrecord
));
2679 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2682 if (a
& ATTR_FILE_RSRCLENGTH
) {
2683 *((off_t
*)attrbufptr
)++ =
2684 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2686 if (a
& ATTR_FILE_RSRCALLOCSIZE
) {
2687 *((off_t
*)attrbufptr
)++ =
2688 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2690 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2691 bcopy(&catInfo
->nodeData
.cnd_rsrcfork
.extents
, attrbufptr
, sizeof(extentrecord
));
2692 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2697 *attrbufptrptr
= attrbufptr
;
2698 *varbufptrptr
= varbufptr
;
2702 void PackForkAttributeBlock(struct attrlist
*alist
,
2704 struct hfsCatalogInfo
*catInfo
,
2705 void **attrbufptrptr
,
2706 void **varbufptrptr
) {
2712 // This routine takes catInfo, and alist, as inputs and packs it into an attribute block.
2713 void PackCatalogInfoAttributeBlock ( struct attrlist
*alist
, struct vnode
*root_vp
, struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2715 //XXX Preflight that alist only contains bits with fields in catInfo
2717 PackCommonCatalogInfoAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2719 switch ( catInfo
->nodeData
.cnd_type
)
2721 case kCatalogFolderNode
:
2722 PackCatalogInfoDirAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2725 case kCatalogFileNode
:
2726 PackCatalogInfoFileAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2729 default: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR not being handled... */
2730 /* XXX PPD - Panic? */
2737 void PackAttributeBlock(struct attrlist
*alist
,
2739 struct hfsCatalogInfo
*catInfo
,
2740 void **attrbufptrptr
,
2741 void **varbufptrptr
)
2743 if (alist
->volattr
!= 0) {
2744 DBG_ASSERT((vp
->v_flag
& VROOT
) != 0);
2745 PackVolumeInfo(alist
,vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2747 PackCommonAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2749 switch (vp
->v_type
) {
2751 PackDirAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2756 PackFileAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2759 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
2760 not being handled...
2763 /* XXX PPD - Panic? */
2771 void UnpackVolumeAttributeBlock(struct attrlist
*alist
,
2772 struct vnode
*root_vp
,
2774 void **attrbufptrptr
,
2775 void **varbufptrptr
) {
2776 void *attrbufptr
= *attrbufptrptr
;
2779 if ((alist
->commonattr
== 0) && (alist
->volattr
== 0)) {
2780 return; /* Get out without dirtying the VCB */
2785 a
= alist
->commonattr
;
2787 if (a
& ATTR_CMN_SCRIPT
) {
2788 vcb
->volumeNameEncodingHint
= (u_int32_t
)*(((text_encoding_t
*)attrbufptr
)++);
2790 a
&= ~ATTR_CMN_SCRIPT
;
2793 if (a
& ATTR_CMN_CRTIME
) {
2794 vcb
->vcbCrDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2795 /* Need to update the local time also */
2796 vcb
->localCreateDate
= UTCToLocal(vcb
->vcbCrDate
);
2797 ++((struct timespec
*)attrbufptr
);
2799 a
&= ~ATTR_CMN_CRTIME
;
2802 if (a
& ATTR_CMN_MODTIME
) {
2803 vcb
->vcbLsMod
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2804 ++((struct timespec
*)attrbufptr
);
2806 a
&= ~ATTR_CMN_MODTIME
;
2809 if (a
& ATTR_CMN_BKUPTIME
) {
2810 vcb
->vcbVolBkUp
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2811 ++((struct timespec
*)attrbufptr
);
2813 a
&= ~ATTR_CMN_BKUPTIME
;
2816 if (a
& ATTR_CMN_FNDRINFO
) {
2817 bcopy (attrbufptr
, &vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
2818 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
2820 a
&= ~ATTR_CMN_FNDRINFO
;
2824 DBG_ASSERT(a
== 0); /* All common attributes for volumes must've been handled by now... */
2826 a
= alist
->volattr
& ~ATTR_VOL_INFO
;
2827 if (a
& ATTR_VOL_NAME
) {
2828 copystr(((char *)attrbufptr
) + *((u_long
*)attrbufptr
), vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
2829 (char *)attrbufptr
+= sizeof(struct attrreference
);
2831 a
&= ~ATTR_VOL_NAME
;
2835 DBG_ASSERT(a
== 0); /* All common attributes for volumes must've been handled by now... */
2837 vcb
->vcbFlags
|= 0xFF00; // Mark the VCB dirty
2843 void UnpackCommonAttributeBlock(struct attrlist
*alist
,
2845 struct hfsCatalogInfo
*catInfo
,
2846 void **attrbufptrptr
,
2847 void **varbufptrptr
) {
2848 struct hfsnode
*hp
= VTOH(vp
);
2852 attrbufptr
= *attrbufptrptr
;
2854 DBG_ASSERT(catInfo
!= NULL
);
2856 a
= alist
->commonattr
;
2857 if (a
& ATTR_CMN_SCRIPT
) {
2858 catInfo
->nodeData
.cnd_textEncoding
= (u_int32_t
)*((text_encoding_t
*)attrbufptr
)++;
2859 UpdateVolumeEncodings(VTOVCB(vp
), catInfo
->nodeData
.cnd_textEncoding
); /* Update the volume encoding */
2861 a
&= ~ATTR_CMN_SCRIPT
;
2864 if (a
& ATTR_CMN_CRTIME
) {
2865 catInfo
->nodeData
.cnd_createDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2866 VTOH(vp
)->h_meta
->h_crtime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2867 ++((struct timespec
*)attrbufptr
);
2869 a
&= ~ATTR_CMN_CRTIME
;
2872 if (a
& ATTR_CMN_MODTIME
) {
2873 catInfo
->nodeData
.cnd_contentModDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2874 VTOH(vp
)->h_meta
->h_mtime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2875 ++((struct timespec
*)attrbufptr
);
2876 hp
->h_nodeflags
&= ~IN_UPDATE
;
2878 a
&= ~ATTR_CMN_MODTIME
;
2881 if (a
& ATTR_CMN_CHGTIME
) {
2882 catInfo
->nodeData
.cnd_attributeModDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2883 VTOH(vp
)->h_meta
->h_ctime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2884 ++((struct timespec
*)attrbufptr
);
2885 hp
->h_nodeflags
&= ~IN_CHANGE
;
2887 a
&= ~ATTR_CMN_CHGTIME
;
2890 if (a
& ATTR_CMN_ACCTIME
) {
2891 catInfo
->nodeData
.cnd_accessDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2892 VTOH(vp
)->h_meta
->h_atime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2893 ++((struct timespec
*)attrbufptr
);
2894 hp
->h_nodeflags
&= ~IN_ACCESS
;
2896 a
&= ~ATTR_CMN_ACCTIME
;
2899 if (a
& ATTR_CMN_BKUPTIME
) {
2900 catInfo
->nodeData
.cnd_backupDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2901 VTOH(vp
)->h_meta
->h_butime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2902 ++((struct timespec
*)attrbufptr
);
2904 a
&= ~ATTR_CMN_BKUPTIME
;
2907 if (a
& ATTR_CMN_FNDRINFO
) {
2908 bcopy (attrbufptr
, &catInfo
->nodeData
.cnd_finderInfo
, sizeof(catInfo
->nodeData
.cnd_finderInfo
));
2909 (char *)attrbufptr
+= sizeof(catInfo
->nodeData
.cnd_finderInfo
);
2911 a
&= ~ATTR_CMN_FNDRINFO
;
2914 if (a
& ATTR_CMN_OWNERID
) {
2915 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2916 u_int32_t uid
= (u_int32_t
)*((uid_t
*)attrbufptr
)++;
2917 if (uid
!= (uid_t
)VNOVAL
)
2918 hp
->h_meta
->h_uid
= uid
; /* catalog will get updated by hfs_chown() */
2921 ((uid_t
*)attrbufptr
)++;
2924 a
&= ~ATTR_CMN_OWNERID
;
2927 if (a
& ATTR_CMN_GRPID
) {
2928 u_int32_t gid
= (u_int32_t
)*((gid_t
*)attrbufptr
)++;
2929 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2930 if (gid
!= (gid_t
)VNOVAL
)
2931 hp
->h_meta
->h_gid
= gid
; /* catalog will get updated by hfs_chown() */
2934 a
&= ~ATTR_CMN_GRPID
;
2937 if (a
& ATTR_CMN_ACCESSMASK
) {
2938 u_int16_t mode
= (u_int16_t
)*((u_long
*)attrbufptr
)++;
2939 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2940 if (mode
!= (mode_t
)VNOVAL
) {
2941 hp
->h_meta
->h_mode
&= ~ALLPERMS
;
2942 hp
->h_meta
->h_mode
|= (mode
& ALLPERMS
); /* catalog will get updated by hfs_chmod() */
2946 a
&= ~ATTR_CMN_ACCESSMASK
;
2949 if (a
& ATTR_CMN_FLAGS
) {
2950 u_long flags
= *((u_long
*)attrbufptr
)++;
2951 /* Flags are settable only on HFS+ volumes. A special exception is made for the IMMUTABLE
2952 flags (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on HFS volumes as well: */
2953 if ((VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) ||
2954 ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) && ((flags
& ~IMMUTABLE
) == 0))) {
2955 if (flags
!= (u_long
)VNOVAL
) {
2956 hp
->h_meta
->h_pflags
= flags
; /* catalog will get updated by hfs_chflags */
2960 a
&= ~ATTR_CMN_FLAGS
;
2966 DEBUG_BREAK_MSG(("UnpackCommonAttributes: unhandled bit: 0x%08X\n", a
));
2970 *attrbufptrptr
= attrbufptr
;
2971 // *varbufptrptr = varbufptr;
2977 void UnpackDirAttributeBlock(struct attrlist
*alist
,
2979 struct hfsCatalogInfo
*catInfo
,
2980 void **attrbufptrptr
,
2981 void **varbufptrptr
) {
2987 attrbufptr
= *attrbufptrptr
;
2988 varbufptr
= *varbufptrptr
;
2992 *attrbufptrptr
= attrbufptr
;
2993 *varbufptrptr
= varbufptr
;
3000 void UnpackFileAttributeBlock(struct attrlist
*alist
,
3002 struct hfsCatalogInfo
*catInfo
,
3003 void **attrbufptrptr
,
3004 void **varbufptrptr
) {
3010 attrbufptr
= *attrbufptrptr
;
3011 varbufptr
= *varbufptrptr
;
3015 *attrbufptrptr
= attrbufptr
;
3016 *varbufptrptr
= varbufptr
;
3023 void UnpackForkAttributeBlock(struct attrlist
*alist
,
3025 struct hfsCatalogInfo
*catInfo
,
3026 void **attrbufptrptr
,
3027 void **varbufptrptr
) {
3033 attrbufptr
= *attrbufptrptr
;
3034 varbufptr
= *varbufptrptr
;
3038 *attrbufptrptr
= attrbufptr
;
3039 *varbufptrptr
= varbufptr
;
3045 void UnpackAttributeBlock(struct attrlist
*alist
,
3047 struct hfsCatalogInfo
*catInfo
,
3048 void **attrbufptrptr
,
3049 void **varbufptrptr
) {
3052 if (alist
->volattr
!= 0) {
3053 UnpackVolumeAttributeBlock(alist
, vp
, VTOVCB(vp
), attrbufptrptr
, varbufptrptr
);
3057 /* We're dealing with a vnode object here: */
3058 UnpackCommonAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3061 switch (vp
->v_type
) {
3063 UnpackDirAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3067 /* case VCPLX: */ /* XXX PPD TBC */
3068 UnpackFileAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3072 UnpackForkAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3075 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
3076 not being handled...
3079 /* XXX PPD - Panic? */
3087 unsigned long BestBlockSizeFit(unsigned long allocationBlockSize
,
3088 unsigned long blockSizeLimit
,
3089 unsigned long baseMultiple
) {
3091 Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the
3092 specified limit but still an even multiple of the baseMultiple.
3094 int baseBlockCount
, blockCount
;
3095 unsigned long trialBlockSize
;
3097 if (allocationBlockSize
% baseMultiple
!= 0) {
3099 Whoops: the allocation blocks aren't even multiples of the specified base:
3100 no amount of dividing them into even parts will be a multiple, either then!
3102 return 512; /* Hope for the best */
3105 /* Try the obvious winner first, to prevent 12K allocation blocks, for instance,
3106 from being handled as two 6K logical blocks instead of 3 4K logical blocks.
3107 Even though the former (the result of the loop below) is the larger allocation
3108 block size, the latter is more efficient: */
3109 if (allocationBlockSize
% PAGE_SIZE
== 0) return PAGE_SIZE
;
3111 /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */
3112 baseBlockCount
= allocationBlockSize
/ baseMultiple
; /* Now guaranteed to be an even multiple */
3114 for (blockCount
= baseBlockCount
; blockCount
> 0; --blockCount
) {
3115 trialBlockSize
= blockCount
* baseMultiple
;
3116 if (allocationBlockSize
% trialBlockSize
== 0) { /* An even multiple? */
3117 if ((trialBlockSize
<= blockSizeLimit
) &&
3118 (trialBlockSize
% baseMultiple
== 0)) {
3119 return trialBlockSize
;
3124 /* Note: we should never get here, since blockCount = 1 should always work,
3125 but this is nice and safe and makes the compiler happy, too ... */
3131 * To make the HFS Plus filesystem follow UFS unlink semantics, a remove
3132 * of an active vnode is translated to a move/rename so the file appears
3133 * deleted. The destination folder for these move/renames is setup here
3134 * and a reference to it is place in hfsmp->hfs_private_metadata_dir.
3137 FindMetaDataDirectory(ExtendedVCB
*vcb
)
3140 hfsCatalogInfo catInfo
;
3141 HFSCatalogNodeID dirID
;
3142 u_int32_t metadata_createdate
;
3145 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
3149 metadata_createdate
= 0;
3150 strncpy(namep
, HFSPLUS_PRIVATE_DIR
, sizeof(namep
));
3151 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
3152 catInfo
.hint
= kNoHint
;
3154 /* lock catalog b-tree */
3155 retval
= hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_SHARED
, current_proc());
3156 if (retval
) goto Err_Exit
;
3158 if (hfs_getcatalog(vcb
, kRootDirID
, namep
, -1, &catInfo
) == 0) {
3159 dirID
= catInfo
.nodeData
.cnd_nodeID
;
3160 metadata_createdate
= catInfo
.nodeData
.cnd_createDate
;
3161 } else if (VCBTOHFS(vcb
)->hfs_fs_ronly
== 0) {
3162 if (CreateCatalogNode(vcb
, kRootDirID
, namep
, kCatalogFolderNode
, &dirID
, &catInfo
.hint
, 0) == 0) {
3163 catInfo
.hint
= kNoHint
;
3164 if (hfs_getcatalog(vcb
, kRootDirID
, namep
, -1, &catInfo
) == 0) {
3166 /* create date is later used for validation */
3167 catInfo
.nodeData
.cnd_createDate
= vcb
->vcbCrDate
;
3168 metadata_createdate
= catInfo
.nodeData
.cnd_createDate
;
3170 /* directory with no permissions owned by root */
3171 catInfo
.nodeData
.cnd_mode
= IFDIR
;
3172 catInfo
.nodeData
.cnd_adminFlags
= (SF_IMMUTABLE
>> 16);
3174 /* hidden and off the desktop view */
3175 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frLocation
.v
= SWAP_BE16 (22460);
3176 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frLocation
.h
= SWAP_BE16 (22460);
3177 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frFlags
|= SWAP_BE16 (kIsInvisible
+ kNameLocked
);
3179 (void) UpdateCatalogNode(vcb
, kRootDirID
, namep
, catInfo
.hint
, &catInfo
.nodeData
);
3184 /* unlock catalog b-tree */
3185 (void) hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3187 VCBTOHFS(vcb
)->hfs_metadata_createdate
= metadata_createdate
;
3189 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3196 RemovedMetaDataDirectory(ExtendedVCB
*vcb
)
3199 hfsCatalogInfo catInfo
;
3202 strncpy(name
, HFSPLUS_PRIVATE_DIR
, sizeof(name
));
3203 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
3205 /* lock catalog b-tree */
3206 retval
= hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_SHARED
, current_proc());
3207 if (retval
) goto Err_Exit
;
3209 /* If the HFSPLUSMETADATAFOLDER exists then delete it. */
3210 retval
= GetCatalogNode(vcb
, kRootDirID
, name
, strlen(name
), kNoHint
,
3211 &catInfo
.nodeData
, &catInfo
.hint
);
3212 if (retval
== 0 && (catInfo
.nodeData
.cnd_type
== kCatalogFolderNode
)) {
3213 (void) DeleteCatalogNode(vcb
, kRootDirID
, name
, catInfo
.hint
);
3214 printf("hfs_mount: removed \"%s\" from hfs volume \"%s\"\n", name
, vcb
->vcbVN
);
3217 /* unlock catalog b-tree */
3218 (void) hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3221 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3225 * This will return the correct logical block size for a given vnode.
3226 * For most files, it is the allocation block size, for meta data like
3227 * BTrees, this is kept as part of the BTree private nodeSize
3230 GetLogicalBlockSize(struct vnode
*vp
)
3232 u_int32_t logBlockSize
;
3234 DBG_ASSERT(vp
!= NULL
);
3236 /* start with default */
3237 logBlockSize
= VTOHFS(vp
)->hfs_logBlockSize
;
3239 if (vp
->v_flag
& VSYSTEM
) {
3240 if (VTOH(vp
)->fcbBTCBPtr
!= NULL
) {
3241 BTreeInfoRec bTreeInfo
;
3244 * We do not lock the BTrees, because if we are getting block..then the tree
3245 * should be locked in the first place.
3246 * We just want the nodeSize wich will NEVER change..so even if the world
3247 * is changing..the nodeSize should remain the same. Which argues why lock
3248 * it in the first place??
3251 (void) BTGetInformation (VTOFCB(vp
), kBTreeInfoVersion
, &bTreeInfo
);
3253 logBlockSize
= bTreeInfo
.nodeSize
;
3255 } else if (H_FILEID(VTOH(vp
)) == kHFSAllocationFileID
) {
3256 logBlockSize
= VTOVCB(vp
)->vcbVBMIOSize
;
3260 DBG_ASSERT(logBlockSize
> 0);
3262 return logBlockSize
;
3266 * Map HFS Common errors (negative) to BSD error codes (positive).
3267 * Positive errors (ie BSD errors) are passed through unchanged.
3269 short MacToVFSError(OSErr err
)
3273 DBG_ERR(("MacToVFSError: passing error #%d unchanged...\n", err
));
3279 DBG_ERR(("MacToVFSError: mapping error code %d...\n", err
));
3283 case dirFulErr
: /* -33 */
3284 case dskFulErr
: /* -34 */
3285 case btNoSpaceAvail
: /* -32733 */
3286 case fxOvFlErr
: /* -32750 */
3287 return ENOSPC
; /* +28 */
3289 case btBadNode
: /* -32731 */
3290 case ioErr
: /* -36 */
3291 return EIO
; /* +5 */
3293 case mFulErr
: /* -41 */
3294 case memFullErr
: /* -108 */
3295 return ENOMEM
; /* +12 */
3297 case tmfoErr
: /* -42 */
3298 /* Consider EMFILE (Too many open files, 24)? */
3299 return ENFILE
; /* +23 */
3301 case nsvErr
: /* -35 */
3302 case fnfErr
: /* -43 */
3303 case dirNFErr
: /* -120 */
3304 case fidNotFound
: /* -1300 */
3305 return ENOENT
; /* +2 */
3307 case wPrErr
: /* -44 */
3308 case vLckdErr
: /* -46 */
3309 case fsDSIntErr
: /* -127 */
3310 return EROFS
; /* +30 */
3312 case opWrErr
: /* -49 */
3313 case fLckdErr
: /* -45 */
3314 return EACCES
; /* +13 */
3316 case permErr
: /* -54 */
3317 case wrPermErr
: /* -61 */
3318 return EPERM
; /* +1 */
3320 case fBsyErr
: /* -47 */
3321 return EBUSY
; /* +16 */
3323 case dupFNErr
: /* -48 */
3324 case fidExists
: /* -1301 */
3325 case cmExists
: /* -32718 */
3326 case btExists
: /* -32734 */
3327 return EEXIST
; /* +17 */
3329 case rfNumErr
: /* -51 */
3330 return EBADF
; /* +9 */
3332 case notAFileErr
: /* -1302 */
3333 return EISDIR
; /* +21 */
3335 case cmNotFound
: /* -32719 */
3336 case btNotFound
: /* -32735 */
3337 return ENOENT
; /* 28 */
3339 case cmNotEmpty
: /* -32717 */
3340 return ENOTEMPTY
; /* 66 */
3342 case cmFThdDirErr
: /* -32714 */
3343 return EISDIR
; /* 21 */
3345 case fxRangeErr
: /* -32751 */
3348 case bdNamErr
: /* -37 */
3349 return ENAMETOOLONG
; /* 63 */
3351 case fnOpnErr
: /* -38 */
3352 case eofErr
: /* -39 */
3353 case posErr
: /* -40 */
3354 case paramErr
: /* -50 */
3355 case badMDBErr
: /* -60 */
3356 case badMovErr
: /* -122 */
3357 case sameFileErr
: /* -1306 */
3358 case badFidErr
: /* -1307 */
3359 case fileBoundsErr
: /* -1309 */
3360 return EINVAL
; /* +22 */
3363 DBG_UTILS(("Unmapped MacOS error: %d\n", err
));
3364 return EIO
; /* +5 */
3370 * All of our debugging functions
3375 void debug_vn_status (char* introStr
, struct vnode
*vn
)
3377 DBG_VOP(("%s:\t",introStr
));
3380 if (vn
->v_tag
!= VT_HFS
)
3382 DBG_VOP(("NON-HFS VNODE Ox%08lX\n", (unsigned long)vn
));
3384 else if(vn
->v_tag
==VT_HFS
&& (vn
->v_data
==NULL
|| VTOH((vn
))->h_valid
!= HFS_VNODE_MAGIC
))
3386 DBG_VOP(("BAD VNODE PRIVATE DATA!!!!\n"));
3390 DBG_VOP(("r: %d & ", vn
->v_usecount
));
3391 if (lockstatus(&VTOH(vn
)->h_lock
))
3393 DBG_VOP_CONT(("is L\n"));
3397 DBG_VOP_CONT(("is U\n"));
3403 DBG_VOP(("vnode is NULL\n"));
3407 void debug_vn_print (char* introStr
, struct vnode
*vn
)
3409 // DBG_FUNC_NAME("DBG_VN_PRINT");
3410 DBG_ASSERT (vn
!= NULL
);
3411 DBG_VFS(("%s: ",introStr
));
3412 DBG_VFS_CONT(("vnode: 0x%x is a ", (uint
)vn
));
3416 DBG_VFS_CONT(("%s","UFS"));
3419 DBG_VFS_CONT(("%s","HFS"));
3422 DBG_VFS_CONT(("%s","UNKNOWN"));
3426 DBG_VFS_CONT((" vnode\n"));
3427 if (vn
->v_tag
==VT_HFS
)
3429 if (vn
->v_data
==NULL
)
3431 DBG_VFS(("BAD VNODE PRIVATE DATA!!!!\n"));
3435 DBG_VFS((" Name: %s Id: %ld ",H_NAME(VTOH(vn
)), H_FILEID(VTOH(vn
))));
3441 DBG_VFS_CONT(("Refcount: %d\n", vn
->v_usecount
));
3442 if (VOP_ISLOCKED(vn
))
3444 DBG_VFS((" The vnode is locked\n"));
3448 DBG_VFS((" The vnode is not locked\n"));
3452 void debug_rename_test_locks (char* introStr
,
3463 DBG_VOP(("\t%s: ", introStr
));
3464 if (fvp
) {if(lockstatus(&VTOH(fvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3465 if (fdvp
) {if(lockstatus(&VTOH(fdvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3466 if (tvp
) {if(lockstatus(&VTOH(tvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3467 if (tdvp
) {if(lockstatus(&VTOH(tdvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3468 DBG_VFS_CONT(("\n"));
3471 if (lockstatus(&VTOH(fvp
)->h_lock
)) {
3472 if (fstatus
==VOPDBG_UNLOCKED
) {
3473 DBG_VOP(("\tfvp should be NOT LOCKED and it is\n"));
3475 } else if (fstatus
== VOPDBG_LOCKED
) {
3476 DBG_VOP(("\tfvp should be LOCKED and it isnt\n"));
3481 if (lockstatus(&VTOH(fdvp
)->h_lock
)) {
3482 if (fdstatus
==VOPDBG_UNLOCKED
) {
3483 DBG_VOP(("\tfdvp should be NOT LOCKED and it is\n"));
3485 } else if (fdstatus
== VOPDBG_LOCKED
) {
3486 DBG_VOP(("\tfdvp should be LOCKED and it isnt\n"));
3491 if (lockstatus(&VTOH(tvp
)->h_lock
)) {
3492 if (tstatus
==VOPDBG_UNLOCKED
) {
3493 DBG_VOP(("\ttvp should be NOT LOCKED and it is\n"));
3495 } else if (tstatus
== VOPDBG_LOCKED
) {
3496 DBG_VOP(("\ttvp should be LOCKED and it isnt\n"));
3501 if (lockstatus(&VTOH(tdvp
)->h_lock
)) {
3502 if (tdstatus
==VOPDBG_UNLOCKED
) {
3503 DBG_VOP(("\ttdvp should be NOT LOCKED and it is\n"));
3505 } else if (tdstatus
== VOPDBG_LOCKED
) {
3506 DBG_VOP(("\ttdvp should be LOCKED and it isnt\n"));
3512 #endif /* HFS_DIAGNOSTIC */
3516 void debug_check_buffersizes(struct vnode
*vp
, struct hfsnode
*hp
, struct buf
*bp
) {
3517 DBG_ASSERT(bp
->b_validoff
== 0);
3518 DBG_ASSERT(bp
->b_dirtyoff
== 0);
3519 DBG_ASSERT((bp
->b_bcount
== HTOHFS(hp
)->hfs_logBlockSize
) ||
3520 ((bp
->b_bcount
% 512 == 0) &&
3521 (bp
->b_validend
> 0) &&
3522 (bp
->b_dirtyend
> 0) &&
3523 (bp
->b_bcount
< HTOHFS(hp
)->hfs_logBlockSize
)));
3525 if (bp
->b_validend
== 0) {
3526 DBG_ASSERT(bp
->b_dirtyend
== 0);
3528 DBG_ASSERT(bp
->b_validend
== bp
->b_bcount
);
3529 DBG_ASSERT(bp
->b_dirtyend
<= bp
->b_bcount
);
3534 void debug_check_blocksizes(struct vnode
*vp
) {
3535 struct hfsnode
*hp
= VTOH(vp
);
3538 if (vp
->v_flag
& VSYSTEM
) return;
3540 for (bp
= vp
->v_cleanblkhd
.lh_first
; bp
!= NULL
; bp
= bp
->b_vnbufs
.le_next
) {
3541 debug_check_buffersizes(vp
, hp
, bp
);
3544 for (bp
= vp
->v_dirtyblkhd
.lh_first
; bp
!= NULL
; bp
= bp
->b_vnbufs
.le_next
) {
3545 debug_check_buffersizes(vp
, hp
, bp
);
3549 void debug_check_catalogdata(struct CatalogNodeData
*cat
) {
3551 if (cat
->cnm_nameptr
== NULL
) {
3552 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3554 else if (cat
->cnm_nameptr
== cat
->cnm_namespace
) {
3555 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3558 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == kCatNameIsAllocated
);
3561 if (cat
->cnm_nameptr
) {
3562 DBG_ASSERT(strlen(cat
->cnm_nameptr
) == cat
->cnm_length
);
3565 if (cat
->cnm_flags
& kCatNameIsConsumed
) {
3566 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3569 if (cat
->cnm_flags
& kCatNameNoCopyName
) {
3570 DBG_ASSERT((cat
->cnm_flags
& (kCatNameIsAllocated
|kCatNameIsConsumed
|kCatNameIsMangled
)) == 0);
3571 DBG_ASSERT(cat
->cnm_length
== 0);
3572 DBG_ASSERT(cat
->cnm_nameptr
== 0);
3573 DBG_ASSERT(strlen(cat
->cnm_namespace
) == 0);
3578 extern void hfs_vhash_dbg(struct hfsnode
*hp
);
3580 /* Checks the valicity of a hfs vnode */
3581 void debug_check_vnode(struct vnode
*vp
, int stage
) {
3587 if (VTOHFS(vp
)->hfs_mount_flags
& kHFSBootVolumeInconsistentMask
)
3588 DEBUG_BREAK_MSG(("Volume is damaged!"));
3592 DEBUG_BREAK_MSG(("Null vnode"));
3593 if (vp
->v_tag
!= VT_HFS
)
3594 DEBUG_BREAK_MSG(("Not a HFS vnode, it is a %d", vp
->v_tag
));
3595 if (vp
->v_data
==NULL
)
3596 DEBUG_BREAK_MSG(("v_data is NULL"));
3600 if (hp
->h_valid
!= HFS_VNODE_MAGIC
)
3601 DEBUG_BREAK_MSG(("Bad Formed HFS node"));
3602 if (hp
->h_vp
==NULL
|| hp
->h_vp
!=vp
)
3603 DEBUG_BREAK_MSG(("Bad hfsnode vnode pte"));
3604 if (hp
->h_meta
== NULL
)
3605 DEBUG_BREAK_MSG(("Bad hfsnode meta ptr"));
3606 switch (H_FORKTYPE(hp
)) {
3609 if ((hp
->h_meta
->h_siblinghead
.cqh_first
== NULL
) || (hp
->h_meta
->h_siblinghead
.cqh_last
== NULL
))
3610 DEBUG_BREAK_MSG(("Null sibling header"));
3611 if ((hp
->h_sibling
.cqe_next
==NULL
) || (hp
->h_sibling
.cqe_prev
==NULL
))
3612 DEBUG_BREAK_MSG(("Null sibling list"));
3613 if (hp
->h_meta
->h_usecount
<1 || hp
->h_meta
->h_usecount
>2)
3614 DEBUG_BREAK_MSG(("Bad sibling usecount"));
3618 if ((hp
->h_meta
->h_siblinghead
.cqh_first
!= NULL
) || (hp
->h_meta
->h_siblinghead
.cqh_last
!= NULL
))
3619 DEBUG_BREAK_MSG(("Non Null sibling header"));
3620 if ((hp
->h_sibling
.cqe_next
!=NULL
) || (hp
->h_sibling
.cqe_prev
!=NULL
))
3621 DEBUG_BREAK_MSG(("Null sibling list"));
3622 if (hp
->h_meta
->h_usecount
!=1)
3623 DEBUG_BREAK_MSG(("Bad usecount"));
3627 DEBUG_BREAK_MSG(("Bad hfsnode fork type"));
3631 if (hp
->h_meta
->h_devvp
== NULL
)
3632 DEBUG_BREAK_MSG(("Bad hfsnode dev vnode"));
3634 DEBUG_BREAK_MSG(("Bad dev id"));
3635 if (H_FILEID(hp
) == 0)
3636 DEBUG_BREAK_MSG(("Bad file id"));
3638 if (((hp
->h_meta
->h_metaflags
& IN_DATANODE
)==0) && (H_DIRID(hp
) == 0) && (H_FILEID(hp
) != 1))
3639 DEBUG_BREAK_MSG(("Bad dir id"));
3641 if (hp
->h_meta
->h_namePtr
== NULL
&& hp
->h_meta
->h_namelen
!=0)
3642 DEBUG_BREAK_MSG(("hfs meta h_namelen is not 0"));
3643 if (hp
->h_meta
->h_namePtr
!= NULL
&& strlen(hp
->h_meta
->h_namePtr
) != hp
->h_meta
->h_namelen
)
3644 DEBUG_BREAK_MSG(("Bad hfs meta h_namelen"));
3646 /* Check the hash */
3649 /* Check to see if we want to compare with the disk */
3652 hfsCatalogInfo catInfo
;
3654 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
3657 if (hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_SHARED
, current_proc()))
3660 if (hfs_getcatalog(VTOVCB(vp
), H_DIRID(hp
), hp
->h_meta
->h_namePtr
, hp
->h_meta
->h_namelen
, &catInfo
))
3661 DEBUG_BREAK_MSG(("Could not find hfsnode Catalog record"));
3663 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3665 if (H_FILEID(hp
) != catInfo
.nodeData
.cnd_nodeID
)
3666 DEBUG_BREAK_MSG(("hfsnode catalog node id mismatch"));
3667 if (H_DIRID(hp
) != catInfo
.nodeData
.cnm_parID
)
3668 DEBUG_BREAK_MSG(("hfsnode catalog dir id mismatch"));
3669 if (strcmp(hp
->h_meta
->h_namePtr
, catInfo
.nodeData
.cnm_nameptr
) != 0)
3670 DEBUG_BREAK_MSG(("hfsnode catalog name mismatch"));
3671 /* Check dates too??? */
3673 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3680 for(i
= 0, size
= 0; i
< kHFSPlusExtentDensity
; i
++)
3682 size
+= hp
->fcbExtents
[i
].blockCount
;
3685 if (hp
->fcbEOF
> hp
->fcbPLen
)
3686 DEBUG_BREAK_MSG(("fcbPLen is smaller than fcbEOF"));
3688 if (hp
->fcbExtents
[kHFSPlusExtentDensity
-1].blockCount
== 0) {
3689 if ((off_t
)size
* (off_t
)VTOVCB(vp
)->blockSize
!= hp
->fcbPLen
)
3690 DEBUG_BREAK_MSG(("fcbPLen does not match extents"));
3692 if ( hp
->fcbPLen
< (off_t
)size
* (off_t
)VTOVCB(vp
)->blockSize
)
3693 DEBUG_BREAK_MSG(("fcbPLen is smaller than extents"));
3695 for(i
= 0; i
< kHFSPlusExtentDensity
; i
++)
3697 if (hp
->fcbExtents
[i
].blockCount
== 0 || hp
->fcbExtents
[i
].startBlock
== 0)
3700 if ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) && i
> kHFSExtentDensity
)
3701 DEBUG_BREAK_MSG(("Illegal value in extents for ordinary HFS"));
3702 if (i
> kHFSPlusExtentDensity
) {
3703 for(; i
< kHFSPlusExtentDensity
; i
++)
3705 if (hp
->fcbExtents
[i
].blockCount
!= 0 || hp
->fcbExtents
[i
].startBlock
!= 0)
3706 DEBUG_BREAK_MSG(("Illegal value in extents"));
3713 if (0 && vp
->v_flag
& VSYSTEM
) {
3716 BTGetInformation(hp
, 0, &info
);
3717 if (hp
->fcbBTCBPtr
== NULL
)
3718 DEBUG_BREAK_MSG(("Null fcbBTCBPtr"));
3719 if (H_HINT(hp
) == 0)
3720 DEBUG_BREAK_MSG(("hint is 0"));
3721 if (H_HINT(hp
) > info
.numNodes
)
3722 DEBUG_BREAK_MSG(("hint > numNodes"));
3727 #endif /* HFS_DIAGNOSTIC */