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
,
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 // Initialize our dirID/nodePtr cache associated with this volume.
249 err
= InitMRUCache( sizeof(UInt32
), kDefaultNumMRUCacheBlocks
, &(vcb
->hintCachePtr
) );
250 ReturnIfError( err
);
252 hfsmp
->hfs_logBlockSize
= BestBlockSizeFit(vcb
->blockSize
, MAXBSIZE
, hfsmp
->hfs_phys_block_size
);
253 vcb
->vcbVBMIOSize
= kHFSBlockSize
;
255 // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
259 * Set up Extents B-tree vnode...
261 err
= GetInitializedVNode(hfsmp
, &tmpvnode
);
262 if (err
) goto MtVolErr
;
263 /* HFSToHFSPlusExtents(mdb->drXTExtRec, extents); */ /* ASDFADSFSD */
264 extents
[0].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[0].startBlock
);
265 extents
[0].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[0].blockCount
);
266 extents
[1].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[1].startBlock
);
267 extents
[1].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[1].blockCount
);
268 extents
[2].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[2].startBlock
);
269 extents
[2].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[2].blockCount
);
271 err
= InitMetaFileVNode(tmpvnode
, SWAP_BE32 (mdb
->drXTFlSize
), SWAP_BE32 (mdb
->drXTClpSiz
), extents
,
272 kHFSExtentsFileID
, CompareExtentKeys
);
273 if (err
) goto MtVolErr
;
276 * Set up Catalog B-tree vnode...
278 err
= GetInitializedVNode(hfsmp
, &tmpvnode
);
279 if (err
) goto MtVolErr
;
280 /* HFSToHFSPlusExtents(mdb->drCTExtRec, extents); */
281 extents
[0].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[0].startBlock
);
282 extents
[0].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[0].blockCount
);
283 extents
[1].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[1].startBlock
);
284 extents
[1].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[1].blockCount
);
285 extents
[2].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[2].startBlock
);
286 extents
[2].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[2].blockCount
);
288 err
= InitMetaFileVNode(tmpvnode
, SWAP_BE32 (mdb
->drCTFlSize
), SWAP_BE32 (mdb
->drCTClpSiz
), extents
,
289 kHFSCatalogFileID
, CompareCatalogKeys
);
290 if (err
) goto MtVolErr
;
292 /* mark the volume dirty (clear clean unmount bit) */
293 vcb
->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
295 /* Remove any MetaDataDirectory from hfs disks */
296 if (hfsmp
->hfs_fs_ronly
== 0)
297 RemovedMetaDataDirectory(vcb
);
300 * all done with b-trees so we can unlock now...
302 VOP_UNLOCK(vcb
->catalogRefNum
, 0, p
);
303 VOP_UNLOCK(vcb
->extentsRefNum
, 0, p
);
309 if ( !(vcb
->vcbAtrb
& kHFSVolumeHardwareLockMask
) ) // if the disk is not write protected
311 MarkVCBDirty( vcb
); // mark VCB dirty so it will be written
316 //-- Release any resources allocated so far before exiting with an error:
318 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
319 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
325 //*******************************************************************************
326 // Routine: hfs_MountHFSPlusVolume
329 //*******************************************************************************
331 OSErr
hfs_MountHFSPlusVolume(struct hfsmount
*hfsmp
, HFSPlusVolumeHeader
*vhp
,
332 off_t embeddedOffset
, off_t disksize
, struct proc
*p
)
334 register ExtendedVCB
*vcb
;
335 HFSPlusForkData
*fdp
;
336 struct vnode
*tmpvnode
;
339 if (hfsmp
== nil
|| vhp
== nil
) /* exit if bad paramater */
342 DBG_VFS(("hfs_MountHFSPlusVolume: signature=0x%x, version=%d, blockSize=%ld\n",
343 SWAP_BE16 (vhp
->signature
),
344 SWAP_BE16 (vhp
->version
),
345 SWAP_BE32 (vhp
->blockSize
)));
347 retval
= ValidVolumeHeader(vhp
); /* make sure this is an HFS Plus disk */
349 return MacToVFSError(retval
);
351 /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */
352 if (hfsmp
->hfs_fs_ronly
== 0 && (SWAP_BE32 (vhp
->attributes
) & kHFSVolumeUnmountedMask
) == 0)
355 /* Make sure we can live with the physical block size. */
356 if ((disksize
& (hfsmp
->hfs_phys_block_size
- 1)) ||
357 (embeddedOffset
& (hfsmp
->hfs_phys_block_size
- 1)) ||
358 (SWAP_BE32(vhp
->blockSize
) < hfsmp
->hfs_phys_block_size
)) {
363 * The VolumeHeader seems OK: transfer info from it into VCB
364 * Note - the VCB starts out clear (all zeros)
366 vcb
= HFSTOVCB(hfsmp
);
368 //DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0);
369 vcb
->vcbVRefNum
= MAKE_VREFNUM(hfsmp
->hfs_raw_dev
);
370 vcb
->vcbSigWord
= SWAP_BE16 (vhp
->signature
);
371 vcb
->vcbLsMod
= SWAP_BE32 (vhp
->modifyDate
);
372 vcb
->vcbAtrb
= (UInt16
) SWAP_BE32 (vhp
->attributes
); // VCB only uses lower 16 bits
373 vcb
->vcbClpSiz
= SWAP_BE32 (vhp
->rsrcClumpSize
);
374 vcb
->vcbNxtCNID
= SWAP_BE32 (vhp
->nextCatalogID
);
375 vcb
->vcbVolBkUp
= SWAP_BE32 (vhp
->backupDate
);
376 vcb
->vcbWrCnt
= SWAP_BE32 (vhp
->writeCount
);
377 vcb
->vcbFilCnt
= SWAP_BE32 (vhp
->fileCount
);
378 vcb
->vcbDirCnt
= SWAP_BE32 (vhp
->folderCount
);
380 /* copy 32 bytes of Finder info */
381 bcopy(vhp
->finderInfo
, vcb
->vcbFndrInfo
, sizeof(vhp
->finderInfo
));
383 vcb
->vcbAlBlSt
= 0; /* hfs+ allocation blocks start at first block of volume */
384 vcb
->vcbWrCnt
++; /* compensate for write of Volume Header on last flush */
388 /* Now fill in the Extended VCB info */
389 vcb
->nextAllocation
= SWAP_BE32 (vhp
->nextAllocation
);
390 vcb
->totalBlocks
= SWAP_BE32 (vhp
->totalBlocks
);
391 vcb
->freeBlocks
= SWAP_BE32 (vhp
->freeBlocks
);
392 vcb
->blockSize
= SWAP_BE32 (vhp
->blockSize
);
393 vcb
->checkedDate
= SWAP_BE32 (vhp
->checkedDate
);
394 vcb
->encodingsBitmap
= SWAP_BE64 (vhp
->encodingsBitmap
);
396 vcb
->hfsPlusIOPosOffset
= embeddedOffset
;
398 vcb
->localCreateDate
= SWAP_BE32 (vhp
->createDate
); /* in local time, not GMT! */
400 /* Update the logical block size in the mount struct (currently set up from the wrapper MDB)
401 using the new blocksize value: */
402 hfsmp
->hfs_logBlockSize
= BestBlockSizeFit(vcb
->blockSize
, MAXBSIZE
, hfsmp
->hfs_phys_block_size
);
403 vcb
->vcbVBMIOSize
= min(vcb
->blockSize
, MAXPHYSIO
);
405 // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
406 // vcb->vcbAtrb |= kVolumeHardwareLockMask; // XXX this line for debugging only!!!!
408 // Initialize our dirID/nodePtr cache associated with this volume.
409 retval
= InitMRUCache( sizeof(UInt32
), kDefaultNumMRUCacheBlocks
, &(vcb
->hintCachePtr
) );
410 if (retval
!= noErr
) goto ErrorExit
;
413 * Set up Extents B-tree vnode...
415 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
);
416 if (retval
) goto ErrorExit
;
417 fdp
= &vhp
->extentsFile
;
418 SWAP_HFS_PLUS_FORK_DATA (fdp
);
419 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
420 kHFSExtentsFileID
, CompareExtentKeysPlus
);
421 SWAP_HFS_PLUS_FORK_DATA (fdp
);
422 if (retval
) goto ErrorExit
;
425 * Set up Catalog B-tree vnode...
427 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
);
428 if (retval
) goto ErrorExit
;
429 fdp
= &vhp
->catalogFile
;
430 SWAP_HFS_PLUS_FORK_DATA (fdp
);
431 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
432 kHFSCatalogFileID
, CompareExtendedCatalogKeys
);
433 SWAP_HFS_PLUS_FORK_DATA (fdp
);
434 if (retval
) goto ErrorExit
;
437 * Set up Allocation file vnode...
439 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
);
440 if (retval
) goto ErrorExit
;
441 fdp
= &vhp
->allocationFile
;
442 SWAP_HFS_PLUS_FORK_DATA (fdp
);
443 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
444 kHFSAllocationFileID
, NULL
);
445 SWAP_HFS_PLUS_FORK_DATA (fdp
);
446 if (retval
) goto ErrorExit
;
449 * Now that Catalog file is open get the volume name from the catalog
451 retval
= MacToVFSError( GetVolumeNameFromCatalog(vcb
) );
452 if (retval
!= noErr
) goto ErrorExit
;
454 /* mark the volume dirty (clear clean unmount bit) */
455 vcb
->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
457 /* setup private/hidden directory for unlinked files */
458 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(vcb
);
461 * all done with metadata files so we can unlock now...
463 VOP_UNLOCK(vcb
->allocationsRefNum
, 0, p
);
464 VOP_UNLOCK(vcb
->catalogRefNum
, 0, p
);
465 VOP_UNLOCK(vcb
->extentsRefNum
, 0, p
);
467 if ( !(vcb
->vcbAtrb
& kHFSVolumeHardwareLockMask
) ) // if the disk is not write protected
469 MarkVCBDirty( vcb
); // mark VCB dirty so it will be written
472 DBG_VFS(("hfs_MountHFSPlusVolume: returning (%d)\n", retval
));
479 * A fatal error occured and the volume cannot be mounted
480 * release any resources that we aquired...
483 DBG_VFS(("hfs_MountHFSPlusVolume: fatal error (%d)\n", retval
));
485 InvalidateCatalogCache(vcb
);
487 ReleaseMetaFileVNode(vcb
->allocationsRefNum
);
488 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
489 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
496 * ReleaseMetaFileVNode
500 static void ReleaseMetaFileVNode(struct vnode
*vp
)
504 FCB
*fcb
= VTOFCB(vp
);
506 if (fcb
->fcbBTCBPtr
!= NULL
)
507 (void) BTClosePath(fcb
); /* ignore errors since there is only one path open */
509 /* release the node even if BTClosePath fails */
510 if (VOP_ISLOCKED(vp
))
523 static int InitMetaFileVNode(struct vnode
*vp
, off_t eof
, u_long clumpSize
, const HFSPlusExtentRecord extents
,
524 HFSCatalogNodeID fileID
, void * keyCompareProc
)
530 DBG_ASSERT(vp
!= NULL
);
531 DBG_ASSERT(vp
->v_data
!= NULL
);
538 case kHFSExtentsFileID
:
539 vcb
->extentsRefNum
= vp
;
542 case kHFSCatalogFileID
:
543 vcb
->catalogRefNum
= vp
;
546 case kHFSAllocationFileID
:
547 vcb
->allocationsRefNum
= vp
;
551 panic("InitMetaFileVNode: invalid fileID!");
556 fcb
->fcbClmpSize
= clumpSize
;
557 H_FILEID(VTOH(vp
)) = fileID
;
558 H_DIRID(VTOH(vp
)) = kHFSRootParentID
;
559 H_FORKTYPE(VTOH(vp
)) = kSysFile
;
561 bcopy(extents
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
564 * Lock the hfsnode and insert the hfsnode into the hash queue:
566 hfs_vhashins(H_DEV(VTOH(vp
)), fileID
, VTOH(vp
));
567 vp
->v_flag
|= VSYSTEM
; /* tag our metadata files (used by vflush call) */
569 /* As the vnode is a system vnode we don't need UBC */
570 if(UBCINFOEXISTS(vp
)) {
571 /* So something is wrong if the it exists */
572 panic("ubc exists for system vnode");
575 if (keyCompareProc
!= NULL
) {
576 result
= BTOpenPath(fcb
,
577 (KeyCompareProcPtr
) keyCompareProc
,
582 result
= MacToVFSError(result
);
589 /*************************************************************
591 * Unmounts a hfs volume.
592 * At this point vflush() has been called (to dump all non-metadata files)
594 *************************************************************/
596 short hfsUnmount( register struct hfsmount
*hfsmp
, struct proc
*p
)
598 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
601 (void) DisposeMRUCache(vcb
->hintCachePtr
);
602 InvalidateCatalogCache( vcb
);
603 // XXX PPD: Should dispose of any allocated volume cache here: call DisposeVolumeCacheBlocks( vcb )?
605 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_EXCLUSIVE
, p
);
606 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
, p
);
608 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
609 ReleaseMetaFileVNode(vcb
->allocationsRefNum
);
611 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
612 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
619 * hfs_resolvelink - auto resolve HFS+ hardlinks
621 * Used after calling GetCatalogNode or GetCatalogOffspring
623 void hfs_resolvelink(ExtendedVCB
*vcb
, CatalogNodeData
*cndp
)
629 UInt32 linkparid
, linkcnid
;
632 fip
= (struct FInfo
*) &cndp
->cnd_finderInfo
;
635 * if this is an indirect link (hardlink) then auto resolve it...
637 if ((vcb
->vcbSigWord
== kHFSPlusSigWord
)
638 && (cndp
->cnd_type
== kCatalogFileNode
)
639 && (fip
->fdType
== kHardLinkFileType
)
640 && (fip
->fdCreator
== kHFSPlusCreator
)
641 && ((cndp
->cnd_createDate
== vcb
->vcbCrDate
) ||
642 (cndp
->cnd_createDate
== VCBTOHFS(vcb
)->hfs_metadata_createdate
))) {
644 indlinkno
= cndp
->cnd_iNodeNum
;
645 MAKE_INODE_NAME(iNodeName
, indlinkno
);
647 * Get nodeData from the data node file.
648 * Flag the node data to NOT copy the name (ie preserve the original)
649 * Also preserve the parent directory ID.
651 linkparid
= cndp
->cnm_parID
;
652 linkcnid
= cndp
->cnd_nodeID
;
653 cndp
->cnm_flags
|= kCatNameNoCopyName
;
654 result
= GetCatalogNode(vcb
, VCBTOHFS(vcb
)->hfs_private_metadata_dir
,
655 iNodeName
, 0, 0, cndp
, &hint
);
656 cndp
->cnm_flags
&= ~kCatNameNoCopyName
;
658 /* Make sure there's a reference */
660 if (cndp
->cnd_linkCount
== 0) cndp
->cnd_linkCount
= 2;
662 /* Keep a copy of iNodeNum to put into h_indnodeno */
663 cndp
->cnd_iNodeNumCopy
= indlinkno
;
664 cndp
->cnm_parID
= linkparid
;
665 cndp
->cnd_linkCNID
= linkcnid
;
672 * Performs a lookup on the given dirID, name. Returns the catalog info
674 * If len is -1, then it is a null terminated string, pass it along to MacOS as kUndefinedStrLen
677 short hfs_getcatalog (ExtendedVCB
*vcb
, UInt32 parentDirID
, char *name
, short len
, hfsCatalogInfo
*catInfo
)
682 if (len
== -1 ) { /* Convert it to MacOS terms */
684 length
= strlen(name
);
686 length
= kUndefinedStrLen
;
691 result
= GetCatalogNode(vcb
, parentDirID
, name
, length
, catInfo
->hint
, &catInfo
->nodeData
, &catInfo
->hint
);
694 if (catInfo
->nodeData
.cnm_nameptr
) {
695 DBG_ASSERT(strlen(catInfo
->nodeData
.cnm_nameptr
) == catInfo
->nodeData
.cnm_length
);
700 hfs_resolvelink(vcb
, &catInfo
->nodeData
);
702 return MacToVFSError(result
);
707 short hfsDelete (ExtendedVCB
*vcb
, UInt32 parentDirID
, StringPtr name
, short isfile
, UInt32 catalogHint
)
709 OSErr result
= noErr
;
711 /* XXX have all the file's blocks been flushed/trashed? */
714 * DeleteFile will delete the catalog node and then
715 * free up any disk space used by the file.
718 result
= DeleteFile(vcb
, parentDirID
, name
, catalogHint
);
719 else /* is a directory */
720 result
= DeleteCatalogNode(vcb
, parentDirID
, name
, catalogHint
);
723 DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result
, parentDirID
, name
));
725 return MacToVFSError(result
);
729 short hfsMoveRename (ExtendedVCB
*vcb
, UInt32 oldDirID
, char *oldName
, UInt32 newDirID
, char *newName
, UInt32
*hint
)
731 OSErr result
= noErr
;
733 result
= MoveRenameCatalogNode(vcb
, oldDirID
,oldName
, *hint
, newDirID
, newName
, hint
, 0);
736 DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result
, newDirID
, newName
));
739 return MacToVFSError(result
);
742 /* XXX SER pass back the hint so other people can use it */
745 short hfsCreate(ExtendedVCB
*vcb
, UInt32 dirID
, char *name
, int mode
, UInt32 tehint
)
747 OSErr result
= noErr
;
748 HFSCatalogNodeID catalogNodeID
;
752 /* just test for directories, the default is to create a file (like symlinks) */
753 if ((mode
& IFMT
) == IFDIR
)
754 type
= kCatalogFolderNode
;
756 type
= kCatalogFileNode
;
758 result
= CreateCatalogNode (vcb
, dirID
, name
, type
, &catalogNodeID
, &catalogHint
, tehint
);
760 return MacToVFSError(result
);
764 short hfsCreateFileID (ExtendedVCB
*vcb
, UInt32 parentDirID
, StringPtr name
, UInt32 catalogHint
, UInt32
*fileIDPtr
)
766 return MacToVFSError(CreateFileIDRef(vcb
, parentDirID
, name
, catalogHint
, fileIDPtr
));
770 /********************************************************************************/
772 /* hfs_vget_catinfo - Returns a vnode derived from a hfs catInfo struct */
774 /********************************************************************************/
776 int hfs_vget_catinfo(struct vnode
*parent_vp
, struct hfsCatalogInfo
*catInfo
, u_int32_t forkType
, struct vnode
**target_vp
)
780 if (forkType
== kDefault
) {
781 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
)
782 forkType
= kDirectory
;
784 forkType
= kDataFork
;
787 *target_vp
= hfs_vhashget(H_DEV(VTOH(parent_vp
)), catInfo
->nodeData
.cnd_nodeID
, forkType
);
789 if (*target_vp
== NULL
)
790 retval
= hfs_vcreate( VTOVCB(parent_vp
), catInfo
, forkType
, target_vp
);
797 /************************************************************************/
798 /* hfs_vcreate - Returns a vnode derived from hfs */
800 /* When creating the vnode, care must be made to set the */
801 /* correct fields in the correct order. Calls to malloc() */
802 /* and other subroutines, can cause a context switch, */
803 /* and the fields must be ready for the possibility */
806 /************************************************************************/
808 short hfs_vcreate(ExtendedVCB
*vcb
, hfsCatalogInfo
*catInfo
, UInt8 forkType
, struct vnode
**vpp
)
812 struct hfsmount
*hfsmp
;
813 struct hfsfilemeta
*fm
;
819 hfsmp
= VCBTOHFS(vcb
);
820 mp
= HFSTOVFS(hfsmp
);
821 dev
= hfsmp
->hfs_raw_dev
;
823 /* Check if unmount in progress */
824 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
830 * If this is a hard link then check if the
831 * data node already exists in our hash.
833 if ((forkType
== kDataFork
)
834 && (catInfo
->nodeData
.cnd_type
== kCatalogFileNode
)
835 && ((catInfo
->nodeData
.cnd_mode
& IFMT
) == IFREG
)
836 && (catInfo
->nodeData
.cnd_linkCount
> 0)) {
837 vp
= hfs_vhashget(dev
, catInfo
->nodeData
.cnd_nodeID
, kDataFork
);
839 /* Use the name of the link and it's parent ID. */
841 H_DIRID(hp
) = catInfo
->nodeData
.cnm_parID
;
842 hfs_set_metaname(catInfo
->nodeData
.cnm_nameptr
, hp
->h_meta
, hfsmp
);
848 MALLOC_ZONE(hp
, struct hfsnode
*, sizeof(struct hfsnode
), M_HFSNODE
, M_WAITOK
);
849 bzero((caddr_t
)hp
, sizeof(struct hfsnode
));
850 hp
->h_nodeflags
|= IN_ALLOCATING
;
851 lockinit(&hp
->h_lock
, PINOD
, "hfsnode", 0, 0);
852 H_FORKTYPE(hp
) = forkType
;
853 rl_init(&hp
->h_invalidranges
);
856 * There were several blocking points since we first
857 * checked the hash. Now that we're through blocking,
858 * check the hash again in case we're racing for the
861 vp
= hfs_vhashget(dev
, catInfo
->nodeData
.cnd_nodeID
, forkType
);
863 /* We lost the race, use the winner's vnode */
864 FREE_ZONE(hp
, sizeof(struct hfsnode
), M_HFSNODE
);
866 UBCINFOCHECK("hfs_vcreate", vp
);
871 * Insert the hfsnode into the hash queue, also if meta exists
872 * add to sibling list and return the meta address
875 if (SIBLING_FORKTYPE(forkType
))
876 hfs_vhashins_sibling(dev
, catInfo
->nodeData
.cnd_nodeID
, hp
, &fm
);
878 hfs_vhashins(dev
, catInfo
->nodeData
.cnd_nodeID
, hp
);
880 /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
881 if ((retval
= getnewvnode(VT_HFS
, mp
, hfs_vnodeop_p
, &vp
))) {
883 if (hp
->h_nodeflags
& IN_WANT
) {
884 hp
->h_nodeflags
&= ~IN_WANT
;
887 FREE_ZONE(hp
, sizeof(struct hfsnode
), M_HFSNODE
);
894 hp
->h_nodeflags
&= ~IN_ALLOCATING
;
895 if (hp
->h_nodeflags
& IN_WANT
) {
896 hp
->h_nodeflags
&= ~IN_WANT
;
901 * If needed allocate and init the object meta data:
904 /* Allocate it....remember we can do a context switch here */
905 MALLOC_ZONE(fm
, struct hfsfilemeta
*, sizeof(struct hfsfilemeta
), M_HFSFMETA
, M_WAITOK
);
906 bzero(fm
, sizeof(struct hfsfilemeta
));
910 * NOTICE: XXX Even though we have added the vnode to the hash so it is alive on TWO
911 * accessable lists, we do not assign it until later,
912 * this helps to make sure we do not use a half initiated meta
915 /* Init the sibling list if needed */
916 if (SIBLING_FORKTYPE(forkType
)) {
917 simple_lock_init(&fm
->h_siblinglock
);
918 CIRCLEQ_INIT(&fm
->h_siblinghead
);
919 CIRCLEQ_INSERT_HEAD(&fm
->h_siblinghead
, hp
, h_sibling
);
923 CopyCatalogToObjectMeta(catInfo
, vp
, fm
);
926 * the vnode is finally alive, with the exception of the FCB below,
927 * It is finally locked and ready for its debutante ball
934 * Init the File Control Block.
936 CopyCatalogToFCB(catInfo
, vp
);
939 * Finish vnode initialization.
940 * Setting the v_type 'stamps' the vnode as 'complete', so should be done almost last.
942 * At this point the vnode should be locked and fully allocated. And ready to be used
943 * or accessed. (though having it locked prevents most of this, it
944 * can still be accessed through lists and hashs).
946 vp
->v_type
= IFTOVT(hp
->h_meta
->h_mode
);
947 if ((vp
->v_type
== VREG
)
948 && (UBCINFOMISSING(vp
) || UBCINFORECLAIMED(vp
))) {
953 * Initialize the vnode from the inode, check for aliases, sets the VROOT flag.
954 * Note that the underlying vnode may have changed.
956 if ((retval
= hfs_vinit(mp
, hfs_specop_p
, hfs_fifoop_p
, &vp
))) {
963 * Finish inode initialization now that aliasing has been resolved.
965 hp
->h_meta
->h_devvp
= hfsmp
->hfs_devvp
;
966 VREF(hp
->h_meta
->h_devvp
);
972 void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
)
974 ExtendedVCB
*vcb
= VTOVCB(vp
);
975 struct mount
*mp
= VTOVFS(vp
);
976 Boolean isHFSPlus
, isDirectory
;
980 DBG_ASSERT (fm
!= NULL
);
981 DBG_ASSERT (fm
->h_namelen
== 0);
982 DBG_ASSERT (fm
->h_namePtr
== 0);
984 DBG_UTILS(("\tCopying to file's meta data: name:%s, nodeid:%ld\n", catalogInfo
->nodeData
.cnm_nameptr
, catalogInfo
->nodeData
.cnd_nodeID
));
986 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
987 isDirectory
= (catalogInfo
->nodeData
.cnd_type
== kCatalogFolderNode
);
988 finderFlags
= SWAP_BE16 (((struct FInfo
*)(&catalogInfo
->nodeData
.cnd_finderInfo
))->fdFlags
);
990 /* Copy over the dirid, and hint */
991 fm
->h_nodeID
= catalogInfo
->nodeData
.cnd_nodeID
;
992 fm
->h_dirID
= catalogInfo
->nodeData
.cnm_parID
;
993 fm
->h_hint
= catalogInfo
->hint
;
995 /* Copy over the name */
996 hfs_name_CatToMeta(&catalogInfo
->nodeData
, fm
);
999 /* get dates in BSD format */
1000 fm
->h_mtime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1001 fm
->h_crtime
= to_bsd_time(catalogInfo
->nodeData
.cnd_createDate
);
1002 fm
->h_butime
= to_bsd_time(catalogInfo
->nodeData
.cnd_backupDate
);
1004 fm
->h_atime
= to_bsd_time(catalogInfo
->nodeData
.cnd_accessDate
);
1005 fm
->h_ctime
= to_bsd_time(catalogInfo
->nodeData
.cnd_attributeModDate
);
1008 fm
->h_atime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1009 fm
->h_ctime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1013 if (isHFSPlus
&& (catalogInfo
->nodeData
.cnd_mode
& IFMT
)) {
1014 fm
->h_uid
= catalogInfo
->nodeData
.cnd_ownerID
;
1015 fm
->h_gid
= catalogInfo
->nodeData
.cnd_groupID
;
1016 fm
->h_pflags
= catalogInfo
->nodeData
.cnd_ownerFlags
|
1017 (catalogInfo
->nodeData
.cnd_adminFlags
<< 16);
1018 fm
->h_mode
= (mode_t
)catalogInfo
->nodeData
.cnd_mode
;
1020 if (fm
->h_uid
== 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1021 fm
->h_uid
= UNKNOWNUID
;
1022 fm
->h_metaflags
|= IN_CHANGE
;
1023 vcb
->vcbFlags
|= kHFS_DamagedVolume
; /* Trigger fsck on next mount */
1025 if (fm
->h_gid
== 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1026 fm
->h_gid
= UNKNOWNGID
;
1027 fm
->h_metaflags
|= IN_CHANGE
;
1028 vcb
->vcbFlags
|= kHFS_DamagedVolume
; /* Trigger fsck on next mount */
1031 filetype
= fm
->h_mode
& IFMT
;
1032 if (filetype
== IFCHR
|| filetype
== IFBLK
)
1033 fm
->h_rdev
= catalogInfo
->nodeData
.cnd_rawDevice
;
1037 if (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
&&
1038 catalogInfo
->nodeData
.cnd_linkCount
> 0) {
1039 fm
->h_nlink
= catalogInfo
->nodeData
.cnd_linkCount
;
1040 fm
->h_indnodeno
= catalogInfo
->nodeData
.cnd_iNodeNumCopy
;
1041 fm
->h_metaflags
|= IN_DATANODE
;
1046 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1048 * Override the permissions as determined by the mount auguments
1049 * in ALMOST the same way unset permissions are treated but keep
1050 * track of whether or not the file or folder is hfs locked
1051 * by leaving the h_pflags field unchanged from what was unpacked
1052 * out of the catalog.
1054 fm
->h_metaflags
|= IN_UNSETACCESS
;
1055 fm
->h_uid
= VTOHFS(vp
)->hfs_uid
;
1056 fm
->h_gid
= VTOHFS(vp
)->hfs_gid
;
1057 #if OVERRIDE_UNKNOWN_PERMISSIONS
1058 /* Default access is full read/write/execute: */
1059 /* XXX won't this smash IFCHR, IFBLK and IFLNK (for no-follow lookups)? */
1060 fm
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
1063 /* ... but no more than that permitted by the mount point's: */
1065 fm
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
1068 fm
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
1072 fm
->h_mode
|= IFDIR
;
1073 else if (SUPPORTS_MAC_ALIASES
&& (finderFlags
& kIsAlias
)) /* aliases will be symlinks in the future */
1074 fm
->h_mode
|= IFLNK
;
1076 fm
->h_mode
|= IFREG
;
1081 * Set the permissions as determined by the mount auguments
1082 * but keep in account if the file or folder is hfs locked
1084 fm
->h_metaflags
|= IN_UNSETACCESS
;
1085 fm
->h_uid
= VTOHFS(vp
)->hfs_uid
;
1086 fm
->h_gid
= VTOHFS(vp
)->hfs_gid
;
1087 fm
->h_pflags
= 0; /* No valid pflags on disk (IMMUTABLE is synced from lock flag later) */
1088 fm
->h_rdev
= 0; /* No valid rdev on disk */
1089 /* Default access is full read/write/execute: */
1090 fm
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
1092 /* ... but no more than that permitted by the mount point's: */
1094 fm
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
1097 fm
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
1101 fm
->h_mode
|= IFDIR
;
1102 else if (SUPPORTS_MAC_ALIASES
&& (finderFlags
& kIsAlias
)) /* aliases will be symlinks in the future */
1103 fm
->h_mode
|= IFLNK
;
1105 fm
->h_mode
|= IFREG
;
1108 /* Make sure that there is no nodeType/mode mismatch */
1109 if (isDirectory
&& ((fm
->h_mode
& IFMT
) != IFDIR
)) {
1110 fm
->h_mode
&= ~IFMT
; /* Clear the bad bits */
1111 fm
->h_mode
|= IFDIR
; /* Set the proper one */
1114 /* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */
1116 if (catalogInfo
->nodeData
.cnd_flags
& kHFSFileLockedMask
) {
1117 /* The file's supposed to be locked:
1118 Make sure at least one of the IMMUTABLE bits is set: */
1119 if ((fm
->h_pflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
)) == 0) {
1120 fm
->h_pflags
|= UF_IMMUTABLE
; /* Set the user-changable IMMUTABLE bit */
1123 /* The file's supposed to be unlocked: */
1124 fm
->h_pflags
&= ~(SF_IMMUTABLE
| UF_IMMUTABLE
);
1129 fm
->h_nlink
= 2 + catalogInfo
->nodeData
.cnd_valence
;
1130 fm
->h_size
= (2 * sizeof(hfsdotentry
)) +
1131 (catalogInfo
->nodeData
.cnd_valence
* AVERAGE_HFSDIRENTRY_SIZE
);
1132 if (fm
->h_size
< MAX_HFSDIRENTRY_SIZE
)
1133 fm
->h_size
= MAX_HFSDIRENTRY_SIZE
;
1135 fm
->h_size
= (off_t
)vcb
->blockSize
*
1136 (off_t
)(catalogInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
+
1137 catalogInfo
->nodeData
.cnd_datafork
.totalBlocks
);
1142 void CopyCatalogToFCB(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
)
1144 FCB
*fcb
= VTOFCB(vp
);
1145 ExtendedVCB
*vcb
= VTOVCB(vp
);
1146 Boolean isHFSPlus
, isDirectory
, isResource
;
1147 HFSPlusExtentDescriptor
*extents
;
1150 DBG_ASSERT (vp
!= NULL
);
1151 DBG_ASSERT (fcb
!= NULL
);
1152 DBG_ASSERT (vcb
!= NULL
);
1153 DBG_ASSERT (VTOH(vp
) != NULL
);
1155 forkType
= H_FORKTYPE(VTOH(vp
));
1156 isResource
= (forkType
== kRsrcFork
);
1157 isDirectory
= (catalogInfo
->nodeData
.cnd_type
== kCatalogFolderNode
);
1158 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1161 fcb
->fcbFlags
= catalogInfo
->nodeData
.cnd_flags
;
1163 if (forkType
!= kDirectory
) {
1164 fcb
->fcbFlags
&= kHFSFileLockedMask
; /* Clear resource, dirty bits */
1165 if (fcb
->fcbFlags
!= 0) /* if clear, its not locked, then.. */
1166 fcb
->fcbFlags
= fcbFileLockedMask
; /* duplicate the bit for later use */
1168 fcb
->fcbClmpSize
= vcb
->vcbClpSiz
; /*XXX why not use the one in catalogInfo? */
1171 extents
= catalogInfo
->nodeData
.cnd_rsrcfork
.extents
;
1173 extents
= catalogInfo
->nodeData
.cnd_datafork
.extents
;
1175 /* Copy the extents to their correct location: */
1176 bcopy (extents
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
1179 fcb
->fcbEOF
= catalogInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
1180 fcb
->fcbPLen
= (off_t
)((off_t
)catalogInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
1181 fcb
->fcbFlags
|= fcbResourceMask
;
1183 fcb
->fcbEOF
= catalogInfo
->nodeData
.cnd_datafork
.logicalSize
;
1184 fcb
->fcbPLen
= (off_t
)((off_t
)catalogInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
1191 int hasOverflowExtents(struct hfsnode
*hp
)
1193 ExtendedVCB
*vcb
= HTOVCB(hp
);
1194 FCB
*fcb
= HTOFCB(hp
);
1197 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1200 if (fcb
->fcbExtents
[7].blockCount
== 0)
1203 blocks
= fcb
->fcbExtents
[0].blockCount
+
1204 fcb
->fcbExtents
[1].blockCount
+
1205 fcb
->fcbExtents
[2].blockCount
+
1206 fcb
->fcbExtents
[3].blockCount
+
1207 fcb
->fcbExtents
[4].blockCount
+
1208 fcb
->fcbExtents
[5].blockCount
+
1209 fcb
->fcbExtents
[6].blockCount
+
1210 fcb
->fcbExtents
[7].blockCount
;
1214 if (fcb
->fcbExtents
[2].blockCount
== 0)
1217 blocks
= fcb
->fcbExtents
[0].blockCount
+
1218 fcb
->fcbExtents
[1].blockCount
+
1219 fcb
->fcbExtents
[2].blockCount
;
1222 return ((fcb
->fcbPLen
/ vcb
->blockSize
) > blocks
);
1226 int hfs_metafilelocking(struct hfsmount
*hfsmp
, u_long fileID
, u_int flags
, struct proc
*p
)
1229 struct vnode
*vp
= NULL
;
1230 int numOfLockedBuffs
;
1233 vcb
= HFSTOVCB(hfsmp
);
1235 DBG_UTILS(("hfs_metafilelocking: vol: %d, file: %d %s%s%s\n", vcb
->vcbVRefNum
, fileID
,
1236 ((flags
& LK_TYPE_MASK
) == LK_RELEASE
? "RELEASE" : ""),
1237 ((flags
& LK_TYPE_MASK
) == LK_EXCLUSIVE
? "EXCLUSIVE" : ""),
1238 ((flags
& LK_TYPE_MASK
) == LK_SHARED
? "SHARED" : "") ));
1243 case kHFSExtentsFileID
:
1244 vp
= vcb
->extentsRefNum
;
1247 case kHFSCatalogFileID
:
1248 vp
= vcb
->catalogRefNum
;
1251 case kHFSAllocationFileID
:
1252 /* bitmap is covered by Extents B-tree locking */
1255 panic("hfs_lockmetafile: invalid fileID");
1260 /* Release, if necesary any locked buffer caches */
1261 if ((flags
& LK_TYPE_MASK
) == LK_RELEASE
) {
1262 struct timeval tv
= time
;
1263 u_int32_t lastfsync
= tv
.tv_sec
;
1265 (void) BTGetLastSync(VTOFCB(vp
), &lastfsync
);
1267 numOfLockedBuffs
= count_lock_queue();
1268 if ((numOfLockedBuffs
> kMaxLockedMetaBuffers
) || ((numOfLockedBuffs
>1) && ((tv
.tv_sec
- lastfsync
) > kMaxSecsForFsync
))) {
1269 DBG_UTILS(("Synching meta deta: %d... # locked buffers = %d, fsync gap = %ld\n", H_FILEID(VTOH(vp
)),
1270 numOfLockedBuffs
, (tv
.tv_sec
- lastfsync
)));
1271 hfs_fsync_transaction(vp
);
1275 retval
= lockmgr(&VTOH(vp
)->h_lock
, flags
, &vp
->v_interlock
, p
);
1283 * There are three ways to qualify for ownership rights on an object:
1285 * 1. (a) Your UID matches the UID of the vnode
1286 * (b) The object in question is owned by "unknown" and your UID matches the console user's UID
1287 * 2. (a) Permissions on the filesystem are being ignored and your UID matches the replacement UID
1288 * (b) Permissions on the filesystem are being ignored and the replacement UID is "unknown" and
1289 * your UID matches the console user UID
1293 int hfs_owner_rights(struct vnode
*vp
, struct ucred
*cred
, struct proc
*p
, Boolean invokesuperuserstatus
) {
1294 return ((cred
->cr_uid
== VTOH(vp
)->h_meta
->h_uid
) || /* [1a] */
1295 ((VTOH(vp
)->h_meta
->h_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)) || /* [1b] */
1296 ((VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) && /* [2] */
1297 ((cred
->cr_uid
== VTOHFS(vp
)->hfs_uid
) || /* [2a] */
1298 ((VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)))) || /* [2b] */
1299 (invokesuperuserstatus
&& (suser(cred
, &p
->p_acflag
) == 0))) ? 0 : EPERM
;
1304 int hfs_catalogentry_owner_rights(uid_t obj_uid
, struct mount
*mp
, struct ucred
*cred
, struct proc
*p
, Boolean invokesuperuserstatus
) {
1305 return ((cred
->cr_uid
== obj_uid
) || /* [1a] */
1306 ((obj_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)) || /* [1b] */
1307 ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) && /* [2] */
1308 ((cred
->cr_uid
== VFSTOHFS(mp
)->hfs_uid
) || /* [2a] */
1309 ((VFSTOHFS(mp
)->hfs_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)))) || /* [2b] */
1310 (invokesuperuserstatus
&& (suser(cred
, &p
->p_acflag
) == 0))) ? 0 : EPERM
;
1315 void CopyVNodeToCatalogNode (struct vnode
*vp
, struct CatalogNodeData
*nodeData
)
1320 Boolean isHFSPlus
, isResource
;
1321 HFSPlusExtentDescriptor
*extents
;
1322 off_t fileReadLimit
;
1327 isResource
= (H_FORKTYPE(hp
) == kRsrcFork
);
1328 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1330 /* date and time of last fork modification */
1331 if (hp
->h_meta
->h_mtime
!= 0)
1332 nodeData
->cnd_contentModDate
= to_hfs_time(hp
->h_meta
->h_mtime
);
1335 /* Make sure that there is no nodeType/mode mismatch */
1336 if ((nodeData
->cnd_type
== kCatalogFolderNode
)
1337 && ((hp
->h_meta
->h_mode
& IFMT
) != IFDIR
)) {
1339 DBG_ASSERT((hp
->h_meta
->h_mode
& IFMT
) == IFDIR
);
1340 hp
->h_meta
->h_mode
&= ~IFMT
; /* Clear the bad bits */
1341 hp
->h_meta
->h_mode
|= IFDIR
; /* Set the proper one */
1343 /* date and time of last modification (any kind) */
1344 if (hp
->h_meta
->h_ctime
!= 0)
1345 nodeData
->cnd_attributeModDate
= to_hfs_time(hp
->h_meta
->h_ctime
);
1346 /* date and time of last access (MacOS X only) */
1347 if (hp
->h_meta
->h_atime
!= 0)
1348 nodeData
->cnd_accessDate
= to_hfs_time(hp
->h_meta
->h_atime
);
1349 /* hfs_setattr can change the create date */
1350 if (hp
->h_meta
->h_crtime
!= 0)
1351 nodeData
->cnd_createDate
= to_hfs_time(hp
->h_meta
->h_crtime
);
1352 if (! (hp
->h_meta
->h_metaflags
& IN_UNSETACCESS
)) {
1353 nodeData
->cnd_adminFlags
= hp
->h_meta
->h_pflags
>> 16;
1354 nodeData
->cnd_ownerFlags
= hp
->h_meta
->h_pflags
& 0x000000FF;
1355 nodeData
->cnd_mode
= hp
->h_meta
->h_mode
;
1356 nodeData
->cnd_ownerID
= hp
->h_meta
->h_uid
;
1357 nodeData
->cnd_groupID
= hp
->h_meta
->h_gid
;
1361 /* the rest only applies to files */
1362 if (nodeData
->cnd_type
== kCatalogFileNode
) {
1363 if (hp
->h_meta
->h_pflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
)) {
1364 /* The file is locked: set the locked bit in the catalog. */
1365 nodeData
->cnd_flags
|= kHFSFileLockedMask
;
1367 /* The file is unlocked: make sure the locked bit in the catalog is clear. */
1368 nodeData
->cnd_flags
&= ~kHFSFileLockedMask
;
1370 if (CIRCLEQ_EMPTY(&hp
->h_invalidranges
)) {
1371 fileReadLimit
= fcb
->fcbEOF
;
1373 fileReadLimit
= CIRCLEQ_FIRST(&hp
->h_invalidranges
)->rl_start
;
1376 extents
= nodeData
->cnd_rsrcfork
.extents
;
1377 nodeData
->cnd_rsrcfork
.logicalSize
= fileReadLimit
;
1378 nodeData
->cnd_rsrcfork
.totalBlocks
= fcb
->fcbPLen
/ vcb
->blockSize
;
1380 extents
= nodeData
->cnd_datafork
.extents
;
1381 nodeData
->cnd_datafork
.logicalSize
= fileReadLimit
;
1382 nodeData
->cnd_datafork
.totalBlocks
= fcb
->fcbPLen
/ vcb
->blockSize
;
1385 bcopy ( fcb
->fcbExtents
, extents
, sizeof(HFSPlusExtentRecord
));
1387 if ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))
1388 nodeData
->cnd_rawDevice
= hp
->h_meta
->h_rdev
;
1389 else if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
1390 nodeData
->cnd_linkCount
= hp
->h_meta
->h_nlink
;
1392 if (vp
->v_type
== VLNK
) {
1393 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdType
= SWAP_BE32 (kSymLinkFileType
);
1394 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdCreator
= SWAP_BE32 (kSymLinkCreator
);
1396 /* Set this up as an alias */
1397 #if SUPPORTS_MAC_ALIASES
1398 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdFlags
|= SWAP_BE16 (kIsAlias
);
1405 /*********************************************************************
1407 Sets the name in the filemeta structure
1409 XXX Does not preflight if changing from one size to another
1410 XXX Currently not protected from context switching
1412 *********************************************************************/
1414 void hfs_set_metaname(char *name
, struct hfsfilemeta
*fm
, struct hfsmount
*hfsmp
)
1416 int namelen
= strlen(name
);
1417 char *tname
, *fname
;
1420 DBG_ASSERT(name
!= NULL
);
1421 DBG_ASSERT(fm
!= NULL
);
1422 if (fm
->h_namePtr
) {
1423 DBG_ASSERT(fm
->h_namelen
== strlen(fm
->h_namePtr
));
1424 if (strlen(fm
->h_namePtr
) > MAXHFSVNODELEN
)
1425 DBG_ASSERT(fm
->h_metaflags
& IN_LONGNAME
);
1427 if (fm
->h_metaflags
& IN_LONGNAME
) {
1428 DBG_ASSERT(fm
->h_namePtr
!= (char *)fm
->h_fileName
);
1429 DBG_ASSERT(fm
->h_namePtr
!= NULL
);
1431 #endif //HFS_DIAGNOSTIC
1434 * Details that have to be dealt with:
1435 * 1. No name is allocated. fm->h_namePtr should be NULL
1436 * 2. A name is being changed and:
1437 * a. it was in static space and now cannot fit
1438 * b. It was malloc'd and now will fit in the static
1439 * c. It did and will fit in the static
1440 * This could be a little smarter:
1441 * - Dont re'malloc if the new name is smaller (but then wasting memory)
1442 * - If its a longname but the same size, we still free and malloc
1447 /* Allocate the new memory */
1448 if (namelen
> MAXHFSVNODELEN
) {
1450 * Notice the we ALWAYS allocate, even if the new is less then the old,
1451 * or even if they are the SAME
1453 MALLOC(tname
, char *, namelen
+1, M_TEMP
, M_WAITOK
);
1456 tname
= fm
->h_fileName
;
1458 simple_lock(&hfsmp
->hfs_renamelock
);
1460 /* Check to see if there is something to free, if yes, remember it */
1461 if (fm
->h_metaflags
& IN_LONGNAME
)
1462 fname
= fm
->h_namePtr
;
1467 if (namelen
> MAXHFSVNODELEN
) {
1468 fm
->h_metaflags
|= IN_LONGNAME
;
1471 fm
->h_metaflags
&= ~IN_LONGNAME
;
1474 /* Now copy it over */
1475 bcopy(name
, tname
, namelen
+1);
1477 fm
->h_namePtr
= tname
;
1478 fm
->h_namelen
= namelen
;
1480 simple_unlock(&hfsmp
->hfs_renamelock
);
1482 /* Lastly, free the old, if set */
1484 FREE(fname
, M_TEMP
);
1488 void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
)
1493 DBG_ASSERT(nodeData
!= NULL
);
1494 DBG_ASSERT(fm
!= NULL
);
1495 if (fm
->h_namePtr
) {
1496 DBG_ASSERT(fm
->h_namelen
== strlen(fm
->h_namePtr
));
1497 if (strlen(fm
->h_namePtr
) > MAXHFSVNODELEN
)
1498 DBG_ASSERT(fm
->h_metaflags
& IN_LONGNAME
);
1500 if (fm
->h_metaflags
& IN_LONGNAME
) {
1501 DBG_ASSERT(fm
->h_namePtr
!= (char *)fm
->h_fileName
);
1502 DBG_ASSERT(fm
->h_namePtr
!= NULL
);
1505 DBG_ASSERT(nodeData
->cnm_nameptr
!= NULL
);
1507 if (nodeData
->cnm_length
) {
1508 DBG_ASSERT(strlen(nodeData
->cnm_nameptr
) == nodeData
->cnm_length
);
1511 if (nodeData
->cnm_length
> MAXHFSVNODELEN
)
1512 { DBG_ASSERT(nodeData
->cnm_nameptr
!= nodeData
->cnm_namespace
); }
1513 else if (nodeData
->cnm_nameptr
)
1514 { DBG_ASSERT(nodeData
->cnm_nameptr
== nodeData
->cnm_namespace
); }
1516 #endif //HFS_DIAGNOSTIC
1519 /* Check to see if there is something to free, if yes, remember it */
1520 if (fm
->h_metaflags
& IN_LONGNAME
)
1521 fname
= fm
->h_namePtr
;
1526 if (nodeData
->cnm_length
> MAXHFSVNODELEN
) {
1527 fm
->h_metaflags
|= IN_LONGNAME
;
1529 fm
->h_metaflags
&= ~IN_LONGNAME
;
1532 /* Copy over the name */
1533 if (nodeData
->cnm_nameptr
== nodeData
->cnm_namespace
) {
1534 bcopy(nodeData
->cnm_namespace
, fm
->h_fileName
, nodeData
->cnm_length
+1);
1535 fm
->h_namePtr
= fm
->h_fileName
;
1538 fm
->h_namePtr
= nodeData
->cnm_nameptr
;
1541 fm
->h_namelen
= nodeData
->cnm_length
;
1543 nodeData
->cnm_flags
|= kCatNameIsConsumed
;
1544 nodeData
->cnm_flags
&= ~kCatNameIsAllocated
;
1545 nodeData
->cnm_length
= 0;
1546 nodeData
->cnm_nameptr
= (char *)0;
1547 nodeData
->cnm_namespace
[0] = 0;
1549 /* Lastly, free the old, if set */
1551 FREE(fname
, M_TEMP
);
1556 unsigned long DerivePermissionSummary(uid_t obj_uid
, gid_t obj_gid
, mode_t obj_mode
, struct mount
*mp
, struct ucred
*cred
, struct proc
*p
) {
1558 unsigned long permissions
;
1561 /* User id 0 (root) always gets access. */
1562 if (cred
->cr_uid
== 0) {
1563 permissions
= R_OK
| W_OK
| X_OK
;
1567 /* Otherwise, check the owner. */
1568 if (hfs_catalogentry_owner_rights(obj_uid
, mp
, cred
, p
, false) == 0) {
1569 permissions
= ((unsigned long)obj_mode
& S_IRWXU
) >> 6;
1573 /* Otherwise, check the groups. */
1574 if (! (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
1575 for (i
= 0, gp
= cred
->cr_groups
; i
< cred
->cr_ngroups
; i
++, gp
++) {
1576 if (obj_gid
== *gp
) {
1577 permissions
= ((unsigned long)obj_mode
& S_IRWXG
) >> 3;
1583 /* Otherwise, settle for 'others' access. */
1584 permissions
= (unsigned long)obj_mode
& S_IRWXO
;
1592 int AttributeBlockSize(struct attrlist
*attrlist
) {
1596 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1597 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_PAROBJID | \
1598 ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
1599 ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1600 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST| \
1601 ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) != ATTR_CMN_VALIDMASK)
1602 #error AttributeBlockSize: Missing bits in common mask computation!
1604 DBG_ASSERT((attrlist
->commonattr
& ~ATTR_CMN_VALIDMASK
) == 0);
1606 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
1607 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1608 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | \
1609 ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | \
1610 ATTR_VOL_MOUNTEDDEVICE| ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) != ATTR_VOL_VALIDMASK)
1611 #error AttributeBlockSize: Missing bits in volume mask computation!
1613 DBG_ASSERT((attrlist
->volattr
& ~ATTR_VOL_VALIDMASK
) == 0);
1615 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) != ATTR_DIR_VALIDMASK)
1616 #error AttributeBlockSize: Missing bits in directory mask computation!
1618 DBG_ASSERT((attrlist
->dirattr
& ~ATTR_DIR_VALIDMASK
) == 0);
1619 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
1620 ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | \
1621 ATTR_FILE_FORKLIST | ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1622 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) != ATTR_FILE_VALIDMASK)
1623 #error AttributeBlockSize: Missing bits in file mask computation!
1625 DBG_ASSERT((attrlist
->fileattr
& ~ATTR_FILE_VALIDMASK
) == 0);
1627 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1628 #error AttributeBlockSize: Missing bits in fork mask computation!
1630 DBG_ASSERT((attrlist
->forkattr
& ~ATTR_FORK_VALIDMASK
) == 0);
1634 if ((a
= attrlist
->commonattr
) != 0) {
1635 if (a
& ATTR_CMN_NAME
) size
+= sizeof(struct attrreference
);
1636 if (a
& ATTR_CMN_DEVID
) size
+= sizeof(dev_t
);
1637 if (a
& ATTR_CMN_FSID
) size
+= sizeof(fsid_t
);
1638 if (a
& ATTR_CMN_OBJTYPE
) size
+= sizeof(fsobj_type_t
);
1639 if (a
& ATTR_CMN_OBJTAG
) size
+= sizeof(fsobj_tag_t
);
1640 if (a
& ATTR_CMN_OBJID
) size
+= sizeof(fsobj_id_t
);
1641 if (a
& ATTR_CMN_OBJPERMANENTID
) size
+= sizeof(fsobj_id_t
);
1642 if (a
& ATTR_CMN_PAROBJID
) size
+= sizeof(fsobj_id_t
);
1643 if (a
& ATTR_CMN_SCRIPT
) size
+= sizeof(text_encoding_t
);
1644 if (a
& ATTR_CMN_CRTIME
) size
+= sizeof(struct timespec
);
1645 if (a
& ATTR_CMN_MODTIME
) size
+= sizeof(struct timespec
);
1646 if (a
& ATTR_CMN_CHGTIME
) size
+= sizeof(struct timespec
);
1647 if (a
& ATTR_CMN_ACCTIME
) size
+= sizeof(struct timespec
);
1648 if (a
& ATTR_CMN_BKUPTIME
) size
+= sizeof(struct timespec
);
1649 if (a
& ATTR_CMN_FNDRINFO
) size
+= 32 * sizeof(UInt8
);
1650 if (a
& ATTR_CMN_OWNERID
) size
+= sizeof(uid_t
);
1651 if (a
& ATTR_CMN_GRPID
) size
+= sizeof(gid_t
);
1652 if (a
& ATTR_CMN_ACCESSMASK
) size
+= sizeof(u_long
);
1653 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) size
+= sizeof(u_long
);
1654 if (a
& ATTR_CMN_NAMEDATTRLIST
) size
+= sizeof(struct attrreference
);
1655 if (a
& ATTR_CMN_FLAGS
) size
+= sizeof(u_long
);
1656 if (a
& ATTR_CMN_USERACCESS
) size
+= sizeof(u_long
);
1658 if ((a
= attrlist
->volattr
) != 0) {
1659 if (a
& ATTR_VOL_FSTYPE
) size
+= sizeof(u_long
);
1660 if (a
& ATTR_VOL_SIGNATURE
) size
+= sizeof(u_long
);
1661 if (a
& ATTR_VOL_SIZE
) size
+= sizeof(off_t
);
1662 if (a
& ATTR_VOL_SPACEFREE
) size
+= sizeof(off_t
);
1663 if (a
& ATTR_VOL_SPACEAVAIL
) size
+= sizeof(off_t
);
1664 if (a
& ATTR_VOL_MINALLOCATION
) size
+= sizeof(off_t
);
1665 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) size
+= sizeof(off_t
);
1666 if (a
& ATTR_VOL_IOBLOCKSIZE
) size
+= sizeof(u_long
);
1667 if (a
& ATTR_VOL_OBJCOUNT
) size
+= sizeof(u_long
);
1668 if (a
& ATTR_VOL_FILECOUNT
) size
+= sizeof(u_long
);
1669 if (a
& ATTR_VOL_DIRCOUNT
) size
+= sizeof(u_long
);
1670 if (a
& ATTR_VOL_MAXOBJCOUNT
) size
+= sizeof(u_long
);
1671 if (a
& ATTR_VOL_MOUNTPOINT
) size
+= sizeof(struct attrreference
);
1672 if (a
& ATTR_VOL_NAME
) size
+= sizeof(struct attrreference
);
1673 if (a
& ATTR_VOL_MOUNTFLAGS
) size
+= sizeof(u_long
);
1674 if (a
& ATTR_VOL_MOUNTEDDEVICE
) size
+= sizeof(struct attrreference
);
1675 if (a
& ATTR_VOL_ENCODINGSUSED
) size
+= sizeof(unsigned long long);
1676 if (a
& ATTR_VOL_CAPABILITIES
) size
+= sizeof(vol_capabilities_attr_t
);
1677 if (a
& ATTR_VOL_ATTRIBUTES
) size
+= sizeof(vol_attributes_attr_t
);
1679 if ((a
= attrlist
->dirattr
) != 0) {
1680 if (a
& ATTR_DIR_LINKCOUNT
) size
+= sizeof(u_long
);
1681 if (a
& ATTR_DIR_ENTRYCOUNT
) size
+= sizeof(u_long
);
1682 if (a
& ATTR_DIR_MOUNTSTATUS
) size
+= sizeof(u_long
);
1684 if ((a
= attrlist
->fileattr
) != 0) {
1685 if (a
& ATTR_FILE_LINKCOUNT
) size
+= sizeof(u_long
);
1686 if (a
& ATTR_FILE_TOTALSIZE
) size
+= sizeof(off_t
);
1687 if (a
& ATTR_FILE_ALLOCSIZE
) size
+= sizeof(off_t
);
1688 if (a
& ATTR_FILE_IOBLOCKSIZE
) size
+= sizeof(size_t);
1689 if (a
& ATTR_FILE_CLUMPSIZE
) size
+= sizeof(off_t
);
1690 if (a
& ATTR_FILE_DEVTYPE
) size
+= sizeof(u_long
);
1691 if (a
& ATTR_FILE_FILETYPE
) size
+= sizeof(u_long
);
1692 if (a
& ATTR_FILE_FORKCOUNT
) size
+= sizeof(u_long
);
1693 if (a
& ATTR_FILE_FORKLIST
) size
+= sizeof(struct attrreference
);
1694 if (a
& ATTR_FILE_DATALENGTH
) size
+= sizeof(off_t
);
1695 if (a
& ATTR_FILE_DATAALLOCSIZE
) size
+= sizeof(off_t
);
1696 if (a
& ATTR_FILE_DATAEXTENTS
) size
+= sizeof(extentrecord
);
1697 if (a
& ATTR_FILE_RSRCLENGTH
) size
+= sizeof(off_t
);
1698 if (a
& ATTR_FILE_RSRCALLOCSIZE
) size
+= sizeof(off_t
);
1699 if (a
& ATTR_FILE_RSRCEXTENTS
) size
+= sizeof(extentrecord
);
1701 if ((a
= attrlist
->forkattr
) != 0) {
1702 if (a
& ATTR_FORK_TOTALSIZE
) size
+= sizeof(off_t
);
1703 if (a
& ATTR_FORK_ALLOCSIZE
) size
+= sizeof(off_t
);
1711 char* FindMountpointName(struct mount
*mp
) {
1712 size_t namelength
= strlen(mp
->mnt_stat
.f_mntonname
);
1716 if (namelength
== 0) return NULL
;
1718 /* Look backwards through the name string, looking for the first slash
1719 encountered (which must precede the last part of the pathname)
1721 for (c
= mp
->mnt_stat
.f_mntonname
+ namelength
- 1; namelength
> 0; --c
, --namelength
) {
1724 } else if (foundchars
) {
1729 return mp
->mnt_stat
.f_mntonname
;
1734 void PackObjectName(struct vnode
*vp
,
1737 void **attrbufptrptr
,
1738 void **varbufptrptr
) {
1743 /* The name of an object may be incorrect for the root of a mounted filesystem
1744 because it may be mounted on a different directory name than the name of the
1745 volume (such as "blah-1". For the root directory, it's best to return the
1746 last element of the location where the volume's mounted:
1748 if ((vp
->v_flag
& VROOT
) && (mpname
= FindMountpointName(vp
->v_mount
))) {
1749 mpnamelen
= strlen(mpname
);
1751 /* Trim off any trailing slashes: */
1752 while ((mpnamelen
> 0) && (mpname
[mpnamelen
-1] == '/')) {
1756 /* If there's anything left, use it instead of the volume's name */
1757 if (mpnamelen
> 0) {
1759 namelen
= mpnamelen
;
1763 attrlength
= namelen
+ 1;
1764 ((struct attrreference
*)(*attrbufptrptr
))->attr_dataoffset
= (char *)(*varbufptrptr
) - (char *)(*attrbufptrptr
);
1765 ((struct attrreference
*)(*attrbufptrptr
))->attr_length
= attrlength
;
1766 (void) strncpy((unsigned char *)(*varbufptrptr
), name
, attrlength
);
1768 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1769 (char *)(*varbufptrptr
) += attrlength
+ ((4 - (attrlength
& 3)) & 3);
1770 ++((struct attrreference
*)(*attrbufptrptr
));
1775 void PackVolCommonAttributes(struct attrlist
*alist
,
1776 struct vnode
*root_vp
,
1777 struct hfsCatalogInfo
*root_catInfo
,
1778 void **attrbufptrptr
,
1779 void **varbufptrptr
) {
1783 struct hfsnode
*root_hp
= VTOH(root_vp
);
1784 struct mount
*mp
= VTOVFS(root_vp
);
1785 struct hfsmount
*hfsmp
= VTOHFS(root_vp
);
1786 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1789 attrbufptr
= *attrbufptrptr
;
1790 varbufptr
= *varbufptrptr
;
1792 if ((a
= alist
->commonattr
) != 0) {
1793 if (a
& ATTR_CMN_NAME
) {
1794 PackObjectName(root_vp
, H_NAME(root_hp
), root_hp
->h_meta
->h_namelen
, &attrbufptr
, &varbufptr
);
1796 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1797 if (a
& ATTR_CMN_FSID
) {
1798 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1799 ++((fsid_t
*)attrbufptr
);
1801 if (a
& ATTR_CMN_OBJTYPE
) *((fsobj_type_t
*)attrbufptr
)++ = 0;
1802 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1803 if (a
& ATTR_CMN_OBJID
) {
1804 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1805 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1806 ++((fsobj_id_t
*)attrbufptr
);
1808 if (a
& ATTR_CMN_OBJPERMANENTID
) {
1809 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1810 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1811 ++((fsobj_id_t
*)attrbufptr
);
1813 if (a
& ATTR_CMN_PAROBJID
) {
1814 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1815 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1816 ++((fsobj_id_t
*)attrbufptr
);
1819 if (a
& ATTR_CMN_SCRIPT
) *((text_encoding_t
*)attrbufptr
)++ = vcb
->volumeNameEncodingHint
;
1820 /* NOTE: all VCB dates are in Mac OS time */
1821 if (a
& ATTR_CMN_CRTIME
) {
1822 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbCrDate
);
1823 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1824 ++((struct timespec
*)attrbufptr
);
1826 if (a
& ATTR_CMN_MODTIME
) {
1827 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1828 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1829 ++((struct timespec
*)attrbufptr
);
1831 if (a
& ATTR_CMN_CHGTIME
) {
1832 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1833 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1834 ++((struct timespec
*)attrbufptr
);
1836 if (a
& ATTR_CMN_ACCTIME
) {
1837 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1838 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1839 ++((struct timespec
*)attrbufptr
);
1841 if (a
& ATTR_CMN_BKUPTIME
) {
1842 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbVolBkUp
);
1843 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1844 ++((struct timespec
*)attrbufptr
);
1846 if (a
& ATTR_CMN_FNDRINFO
) {
1847 bcopy (&vcb
->vcbFndrInfo
, attrbufptr
, sizeof(vcb
->vcbFndrInfo
));
1848 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1851 if (a
& ATTR_CMN_OWNERID
) {
1852 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1853 *((uid_t
*)attrbufptr
)++ =
1854 (VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
;
1856 *((uid_t
*)attrbufptr
)++ =
1857 (root_hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: root_hp
->h_meta
->h_uid
;
1860 if (a
& ATTR_CMN_GRPID
) {
1861 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1862 *((gid_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_gid
;
1864 *((gid_t
*)attrbufptr
)++ = root_hp
->h_meta
->h_gid
;
1867 if (a
& ATTR_CMN_ACCESSMASK
) *((u_long
*)attrbufptr
)++ = (u_long
)root_hp
->h_meta
->h_mode
;
1868 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
1869 if (a
& ATTR_CMN_NAMEDATTRLIST
) {
1871 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1872 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1874 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1875 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1876 ++((struct attrreference
*)attrbufptr
);
1878 if (a
& ATTR_CMN_FLAGS
) *((u_long
*)attrbufptr
)++ = root_hp
->h_meta
->h_pflags
;
1879 if (a
& ATTR_CMN_USERACCESS
) {
1880 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1881 *((u_long
*)attrbufptr
)++ =
1882 DerivePermissionSummary((VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
,
1883 VTOHFS(root_vp
)->hfs_gid
,
1884 root_hp
->h_meta
->h_mode
,
1886 current_proc()->p_ucred
,
1889 *((u_long
*)attrbufptr
)++ =
1890 DerivePermissionSummary((root_hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: root_hp
->h_meta
->h_uid
,
1891 root_hp
->h_meta
->h_gid
,
1892 root_hp
->h_meta
->h_mode
,
1894 current_proc()->p_ucred
,
1900 *attrbufptrptr
= attrbufptr
;
1901 *varbufptrptr
= varbufptr
;
1906 void PackVolAttributeBlock(struct attrlist
*alist
,
1907 struct vnode
*root_vp
,
1908 struct hfsCatalogInfo
*root_catInfo
,
1909 void **attrbufptrptr
,
1910 void **varbufptrptr
) {
1914 struct mount
*mp
= VTOVFS(root_vp
);
1915 struct hfsmount
*hfsmp
= VTOHFS(root_vp
);
1916 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1919 attrbufptr
= *attrbufptrptr
;
1920 varbufptr
= *varbufptrptr
;
1922 if ((a
= alist
->volattr
) != 0) {
1924 if (a
& ATTR_VOL_FSTYPE
) *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_vfc
->vfc_typenum
;
1925 if (a
& ATTR_VOL_SIGNATURE
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbSigWord
;
1926 if (a
& ATTR_VOL_SIZE
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->totalBlocks
* (off_t
)vcb
->blockSize
;
1927 if (a
& ATTR_VOL_SPACEFREE
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->freeBlocks
* (off_t
)vcb
->blockSize
;
1928 if (a
& ATTR_VOL_SPACEAVAIL
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->freeBlocks
* (off_t
)vcb
->blockSize
;
1929 if (a
& ATTR_VOL_MINALLOCATION
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->blockSize
;
1930 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) *((off_t
*)attrbufptr
)++ = (off_t
)(vcb
->vcbClpSiz
);
1931 if (a
& ATTR_VOL_IOBLOCKSIZE
) *((u_long
*)attrbufptr
)++ = (u_long
)hfsmp
->hfs_logBlockSize
;
1932 if (a
& ATTR_VOL_OBJCOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
+ (u_long
)vcb
->vcbDirCnt
;
1933 if (a
& ATTR_VOL_FILECOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
;
1934 if (a
& ATTR_VOL_DIRCOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbDirCnt
;
1935 if (a
& ATTR_VOL_MAXOBJCOUNT
) *((u_long
*)attrbufptr
)++ = 0xFFFFFFFF;
1936 if (a
& ATTR_VOL_MOUNTPOINT
) {
1937 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1938 ((struct attrreference
*)attrbufptr
)->attr_length
= strlen(mp
->mnt_stat
.f_mntonname
) + 1;
1939 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1940 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1941 (void) bcopy(mp
->mnt_stat
.f_mntonname
, varbufptr
, attrlength
);
1943 /* Advance beyond the space just allocated: */
1944 (char *)varbufptr
+= attrlength
;
1945 ++((struct attrreference
*)attrbufptr
);
1947 if (a
& ATTR_VOL_NAME
) {
1948 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1949 ((struct attrreference
*)attrbufptr
)->attr_length
= VTOH(root_vp
)->h_meta
->h_namelen
+ 1;
1950 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1951 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1952 bcopy(H_NAME(VTOH(root_vp
)), varbufptr
, attrlength
);
1954 /* Advance beyond the space just allocated: */
1955 (char *)varbufptr
+= attrlength
;
1956 ++((struct attrreference
*)attrbufptr
);
1958 if (a
& ATTR_VOL_MOUNTFLAGS
) *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_flag
;
1959 if (a
& ATTR_VOL_MOUNTEDDEVICE
) {
1960 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1961 ((struct attrreference
*)attrbufptr
)->attr_length
= strlen(mp
->mnt_stat
.f_mntfromname
) + 1;
1962 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1963 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1964 (void) bcopy(mp
->mnt_stat
.f_mntfromname
, varbufptr
, attrlength
);
1966 /* Advance beyond the space just allocated: */
1967 (char *)varbufptr
+= attrlength
;
1968 ++((struct attrreference
*)attrbufptr
);
1970 if (a
& ATTR_VOL_ENCODINGSUSED
) *((unsigned long long *)attrbufptr
)++ = (unsigned long long)vcb
->encodingsBitmap
;
1971 if (a
& ATTR_VOL_CAPABILITIES
) {
1972 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
1973 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1974 VOL_CAP_FMT_PERSISTENTOBJECTIDS
| VOL_CAP_FMT_SYMBOLICLINKS
| VOL_CAP_FMT_HARDLINKS
;
1975 } else { /* Plain HFS */
1976 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_FORMAT
] =
1977 VOL_CAP_FMT_PERSISTENTOBJECTIDS
;
1979 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_INTERFACES
] =
1980 VOL_CAP_INT_SEARCHFS
| VOL_CAP_INT_ATTRLIST
| VOL_CAP_INT_NFSEXPORT
| VOL_CAP_INT_READDIRATTR
;
1981 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
1982 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
1984 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_FORMAT
] =
1985 VOL_CAP_FMT_PERSISTENTOBJECTIDS
| VOL_CAP_FMT_SYMBOLICLINKS
| VOL_CAP_FMT_HARDLINKS
;
1986 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_INTERFACES
] =
1987 VOL_CAP_INT_SEARCHFS
| VOL_CAP_INT_ATTRLIST
| VOL_CAP_INT_NFSEXPORT
| VOL_CAP_INT_READDIRATTR
;
1988 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
1989 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
1991 ++((vol_capabilities_attr_t
*)attrbufptr
);
1993 if (a
& ATTR_VOL_ATTRIBUTES
) {
1994 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.commonattr
= ATTR_CMN_VALIDMASK
;
1995 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.volattr
= ATTR_VOL_VALIDMASK
;
1996 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.dirattr
= ATTR_DIR_VALIDMASK
;
1997 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.fileattr
= ATTR_FILE_VALIDMASK
;
1998 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.forkattr
= ATTR_FORK_VALIDMASK
;
2000 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.commonattr
= ATTR_CMN_VALIDMASK
;
2001 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.volattr
= ATTR_VOL_VALIDMASK
;
2002 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.dirattr
= ATTR_DIR_VALIDMASK
;
2003 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.fileattr
= ATTR_FILE_VALIDMASK
;
2004 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.forkattr
= ATTR_FORK_VALIDMASK
;
2006 ++((vol_attributes_attr_t
*)attrbufptr
);
2011 *attrbufptrptr
= attrbufptr
;
2012 *varbufptrptr
= varbufptr
;
2018 void PackVolumeInfo(struct attrlist
*alist
,
2019 struct vnode
*root_vp
,
2020 struct hfsCatalogInfo
*root_catinfo
,
2021 void **attrbufptrptr
,
2022 void **varbufptrptr
) {
2024 PackVolCommonAttributes(alist
, root_vp
, root_catinfo
, attrbufptrptr
, varbufptrptr
);
2025 PackVolAttributeBlock(alist
, root_vp
, root_catinfo
, attrbufptrptr
, varbufptrptr
);
2028 // Pack the common attribute contents of an objects hfsCatalogInfo
2029 void PackCommonCatalogInfoAttributeBlock(struct attrlist
*alist
,
2030 struct vnode
*root_vp
,
2031 struct hfsCatalogInfo
*catalogInfo
,
2032 void **attrbufptrptr
,
2033 void **varbufptrptr
)
2043 attrbufptr
= *attrbufptrptr
;
2044 varbufptr
= *varbufptrptr
;
2045 isHFSPlus
= (VTOVCB(root_vp
)->vcbSigWord
== kHFSPlusSigWord
);
2047 if ((a
= alist
->commonattr
) != 0)
2049 if (a
& ATTR_CMN_NAME
)
2051 attrlength
= strlen(catalogInfo
->nodeData
.cnm_nameptr
) + 1;
2052 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
2053 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2054 (void) strncpy((unsigned char *)varbufptr
,
2055 catalogInfo
->nodeData
.cnm_nameptr
, attrlength
);
2057 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2058 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2059 ++((struct attrreference
*)attrbufptr
);
2061 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = H_DEV(hp
);
2062 if (a
& ATTR_CMN_FSID
) {
2063 *((fsid_t
*)attrbufptr
) = VTOVFS(root_vp
)->mnt_stat
.f_fsid
;
2064 ++((fsid_t
*)attrbufptr
);
2066 if (a
& ATTR_CMN_OBJTYPE
)
2068 switch (catalogInfo
->nodeData
.cnd_type
) {
2069 case kCatalogFolderNode
:
2070 *((fsobj_type_t
*)attrbufptr
)++ = VDIR
;
2073 case kCatalogFileNode
:
2074 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2075 if ((HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) &&
2076 (catalogInfo
->nodeData
.cnd_mode
& IFMT
)) {
2077 *((fsobj_type_t
*)attrbufptr
)++ =
2078 IFTOVT((mode_t
)catalogInfo
->nodeData
.cnd_mode
);
2080 *((fsobj_type_t
*)attrbufptr
)++ = VREG
;
2085 *((fsobj_type_t
*)attrbufptr
)++ = VNON
;
2089 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = root_vp
->v_tag
;
2090 if (a
& ATTR_CMN_OBJID
) {
2093 /* For hard links use the link's cnid */
2094 if (catalogInfo
->nodeData
.cnd_iNodeNumCopy
!= 0)
2095 cnid
= catalogInfo
->nodeData
.cnd_linkCNID
;
2097 cnid
= catalogInfo
->nodeData
.cnd_nodeID
;
2098 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2099 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2100 ++((fsobj_id_t
*)attrbufptr
);
2102 if (a
& ATTR_CMN_OBJPERMANENTID
) {
2105 /* For hard links use the link's cnid */
2106 if (catalogInfo
->nodeData
.cnd_iNodeNumCopy
!= 0)
2107 cnid
= catalogInfo
->nodeData
.cnd_linkCNID
;
2109 cnid
= catalogInfo
->nodeData
.cnd_nodeID
;
2110 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2111 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2112 ++((fsobj_id_t
*)attrbufptr
);
2114 if (a
& ATTR_CMN_PAROBJID
)
2116 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= catalogInfo
->nodeData
.cnm_parID
;
2117 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2118 ++((fsobj_id_t
*)attrbufptr
);
2120 if (a
& ATTR_CMN_SCRIPT
)
2122 if (HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) {
2123 *((text_encoding_t
*)attrbufptr
)++ = catalogInfo
->nodeData
.cnd_textEncoding
;
2125 *((text_encoding_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_encoding
;
2128 if (a
& ATTR_CMN_CRTIME
)
2130 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_createDate
);
2131 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2132 ++((struct timespec
*)attrbufptr
);
2134 if (a
& ATTR_CMN_MODTIME
)
2136 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
2137 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2138 ++((struct timespec
*)attrbufptr
);
2140 if (a
& ATTR_CMN_CHGTIME
)
2142 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_attributeModDate
);
2143 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2144 ++((struct timespec
*)attrbufptr
);
2146 if (a
& ATTR_CMN_ACCTIME
)
2148 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_accessDate
);
2149 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2150 ++((struct timespec
*)attrbufptr
);
2152 if (a
& ATTR_CMN_BKUPTIME
)
2154 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_backupDate
);
2155 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2156 ++((struct timespec
*)attrbufptr
);
2158 if (a
& ATTR_CMN_FNDRINFO
)
2160 bcopy (&catalogInfo
->nodeData
.cnd_finderInfo
, attrbufptr
, sizeof(catalogInfo
->nodeData
.cnd_finderInfo
));
2161 (char *)attrbufptr
+= sizeof(catalogInfo
->nodeData
.cnd_finderInfo
);
2163 if (a
& ATTR_CMN_OWNERID
) {
2164 if ((VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) ||
2165 ((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)) {
2166 *((uid_t
*)attrbufptr
)++ =
2167 (VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
;
2169 *((uid_t
*)attrbufptr
)++ =
2170 (catalogInfo
->nodeData
.cnd_ownerID
== UNKNOWNUID
) ? console_user
: catalogInfo
->nodeData
.cnd_ownerID
;
2173 if (a
& ATTR_CMN_GRPID
) {
2174 if ((VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) ||
2175 ((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)) {
2176 *((gid_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_gid
;
2178 *((gid_t
*)attrbufptr
)++ = catalogInfo
->nodeData
.cnd_groupID
;
2181 if (a
& ATTR_CMN_ACCESSMASK
) {
2182 if (((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)
2183 #if OVERRIDE_UNKNOWN_PERMISSIONS
2184 || (VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)
2187 switch (catalogInfo
->nodeData
.cnd_type
) {
2188 case kCatalogFileNode
:
2189 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2190 *((u_long
*)attrbufptr
)++ = (u_long
)(IFREG
| (ACCESSPERMS
& (u_long
)(VTOHFS(root_vp
)->hfs_file_mask
)));
2193 case kCatalogFolderNode
:
2194 *((u_long
*)attrbufptr
)++ = (u_long
)(IFDIR
| (ACCESSPERMS
& (u_long
)(VTOHFS(root_vp
)->hfs_dir_mask
)));
2198 *((u_long
*)attrbufptr
)++ = (u_long
)((catalogInfo
->nodeData
.cnd_mode
& IFMT
) |
2199 VTOHFS(root_vp
)->hfs_dir_mask
);
2202 *((u_long
*)attrbufptr
)++ =
2203 (u_long
)catalogInfo
->nodeData
.cnd_mode
;
2206 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
2207 if (a
& ATTR_CMN_NAMEDATTRLIST
)
2210 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2211 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2213 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2214 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2215 ++((struct attrreference
*)attrbufptr
);
2217 if (a
& ATTR_CMN_FLAGS
) {
2220 if (catalogInfo
->nodeData
.cnd_mode
& IFMT
)
2221 flags
= catalogInfo
->nodeData
.cnd_ownerFlags
|
2222 catalogInfo
->nodeData
.cnd_adminFlags
<< 16;
2226 if (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) {
2227 if (catalogInfo
->nodeData
.cnd_flags
& kHFSFileLockedMask
)
2228 flags
|= UF_IMMUTABLE
;
2230 flags
&= ~UF_IMMUTABLE
;
2232 *((u_long
*)attrbufptr
)++ = flags
;
2234 if (a
& ATTR_CMN_USERACCESS
) {
2235 if ((VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) ||
2236 ((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)) {
2237 *((u_long
*)attrbufptr
)++ =
2238 DerivePermissionSummary((VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
,
2239 VTOHFS(root_vp
)->hfs_gid
,
2240 #if OVERRIDE_UNKNOWN_PERMISSIONS
2241 (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) ? VTOHFS(root_vp
)->hfs_file_mask
: VTOHFS(root_vp
)->hfs_dir_mask
,
2243 (catalogInfo
->nodeData
.cnd_mode
& IFMT
) ?
2244 (u_long
)catalogInfo
->nodeData
.cnd_mode
:
2245 ((catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) ?
2246 VTOHFS(root_vp
)->hfs_file_mask
:
2247 VTOHFS(root_vp
)->hfs_dir_mask
),
2250 current_proc()->p_ucred
,
2253 *((u_long
*)attrbufptr
)++ =
2254 DerivePermissionSummary((catalogInfo
->nodeData
.cnd_ownerID
== UNKNOWNUID
) ? console_user
: catalogInfo
->nodeData
.cnd_ownerID
,
2255 catalogInfo
->nodeData
.cnd_groupID
,
2256 (mode_t
)catalogInfo
->nodeData
.cnd_mode
,
2258 current_proc()->p_ucred
,
2264 *attrbufptrptr
= attrbufptr
;
2265 *varbufptrptr
= varbufptr
;
2269 void PackCommonAttributeBlock(struct attrlist
*alist
,
2271 struct hfsCatalogInfo
*catInfo
,
2272 void **attrbufptrptr
,
2273 void **varbufptrptr
) {
2282 attrbufptr
= *attrbufptrptr
;
2283 varbufptr
= *varbufptrptr
;
2285 if ((a
= alist
->commonattr
) != 0) {
2286 if (a
& ATTR_CMN_NAME
) {
2287 PackObjectName(vp
, H_NAME(hp
), hp
->h_meta
->h_namelen
, &attrbufptr
, &varbufptr
);
2289 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = H_DEV(hp
);
2290 if (a
& ATTR_CMN_FSID
) {
2291 *((fsid_t
*)attrbufptr
) = VTOVFS(vp
)->mnt_stat
.f_fsid
;
2292 ++((fsid_t
*)attrbufptr
);
2294 if (a
& ATTR_CMN_OBJTYPE
) *((fsobj_type_t
*)attrbufptr
)++ = vp
->v_type
;
2295 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = vp
->v_tag
;
2296 if (a
& ATTR_CMN_OBJID
) {
2299 /* For hard links use the link's cnid */
2300 if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
2301 cnid
= catInfo
->nodeData
.cnd_linkCNID
;
2303 cnid
= H_FILEID(hp
);
2304 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2305 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2306 ++((fsobj_id_t
*)attrbufptr
);
2308 if (a
& ATTR_CMN_OBJPERMANENTID
) {
2311 /* For hard links use the link's cnid */
2312 if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
2313 cnid
= catInfo
->nodeData
.cnd_linkCNID
;
2315 cnid
= H_FILEID(hp
);
2316 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2317 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2318 ++((fsobj_id_t
*)attrbufptr
);
2320 if (a
& ATTR_CMN_PAROBJID
) {
2321 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= H_DIRID(hp
);
2322 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2323 ++((fsobj_id_t
*)attrbufptr
);
2325 if (a
& ATTR_CMN_SCRIPT
)
2327 if (HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) {
2328 *((text_encoding_t
*)attrbufptr
)++ = catInfo
->nodeData
.cnd_textEncoding
;
2330 *((text_encoding_t
*)attrbufptr
)++ = VTOHFS(vp
)->hfs_encoding
;
2333 if (a
& ATTR_CMN_CRTIME
) {
2334 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_crtime
;
2335 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2336 ++((struct timespec
*)attrbufptr
);
2338 if (a
& ATTR_CMN_MODTIME
) {
2339 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_mtime
;
2340 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2341 ++((struct timespec
*)attrbufptr
);
2343 if (a
& ATTR_CMN_CHGTIME
) {
2344 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_ctime
;
2345 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2346 ++((struct timespec
*)attrbufptr
);
2348 if (a
& ATTR_CMN_ACCTIME
) {
2349 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_atime
;
2350 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2351 ++((struct timespec
*)attrbufptr
);
2353 if (a
& ATTR_CMN_BKUPTIME
) {
2354 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_butime
;
2355 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2356 ++((struct timespec
*)attrbufptr
);
2358 if (a
& ATTR_CMN_FNDRINFO
) {
2359 bcopy (&catInfo
->nodeData
.cnd_finderInfo
, attrbufptr
, sizeof(catInfo
->nodeData
.cnd_finderInfo
));
2360 (char *)attrbufptr
+= sizeof(catInfo
->nodeData
.cnd_finderInfo
);
2362 if (a
& ATTR_CMN_OWNERID
) {
2363 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2364 *((uid_t
*)attrbufptr
)++ =
2365 (VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(vp
)->hfs_uid
;
2367 *((uid_t
*)attrbufptr
)++ =
2368 (hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: hp
->h_meta
->h_uid
;
2371 if (a
& ATTR_CMN_GRPID
) {
2372 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2373 *((gid_t
*)attrbufptr
)++ = VTOHFS(vp
)->hfs_gid
;
2375 *((gid_t
*)attrbufptr
)++ = hp
->h_meta
->h_gid
;
2378 if (a
& ATTR_CMN_ACCESSMASK
) *((u_long
*)attrbufptr
)++ = (u_long
)hp
->h_meta
->h_mode
;
2379 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
2380 if (a
& ATTR_CMN_NAMEDATTRLIST
) {
2382 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2383 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2385 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2386 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2387 ++((struct attrreference
*)attrbufptr
);
2389 if (a
& ATTR_CMN_FLAGS
) *((u_long
*)attrbufptr
)++ = hp
->h_meta
->h_pflags
;
2390 if (a
& ATTR_CMN_USERACCESS
) {
2391 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2392 *((u_long
*)attrbufptr
)++ =
2393 DerivePermissionSummary((VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(vp
)->hfs_uid
,
2394 VTOHFS(vp
)->hfs_gid
,
2397 current_proc()->p_ucred
,
2400 *((u_long
*)attrbufptr
)++ =
2401 DerivePermissionSummary((hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: hp
->h_meta
->h_uid
,
2405 current_proc()->p_ucred
,
2411 *attrbufptrptr
= attrbufptr
;
2412 *varbufptrptr
= varbufptr
;
2416 // Pack the directory attributes given hfsCatalogInfo
2417 void PackCatalogInfoDirAttributeBlock( struct attrlist
*alist
, struct vnode
*vp
,
2418 struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2424 attrbufptr
= *attrbufptrptr
;
2427 if ( (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) && (a
!= 0) ) {
2428 valence
= catInfo
->nodeData
.cnd_valence
;
2429 if ((catInfo
->nodeData
.cnm_parID
== kRootParID
) &&
2430 (VTOHFS(vp
)->hfs_private_metadata_dir
!= 0)) {
2431 --valence
; /* hide private dir */
2433 /* The 'link count' is faked */
2434 if (a
& ATTR_DIR_LINKCOUNT
)
2435 *((u_long
*)attrbufptr
)++ = 2 + valence
;
2436 if (a
& ATTR_DIR_ENTRYCOUNT
)
2437 *((u_long
*)attrbufptr
)++ = valence
;
2438 if (a
& ATTR_DIR_MOUNTSTATUS
)
2439 *((u_long
*)attrbufptr
)++ = 0;
2442 *attrbufptrptr
= attrbufptr
;
2446 void PackDirAttributeBlock(struct attrlist
*alist
,
2448 struct hfsCatalogInfo
*catInfo
,
2449 void **attrbufptrptr
,
2450 void **varbufptrptr
) {
2455 attrbufptr
= *attrbufptrptr
;
2458 if ((vp
->v_type
== VDIR
) && (a
!= 0)) {
2459 valence
= catInfo
->nodeData
.cnd_valence
;
2460 if ((catInfo
->nodeData
.cnm_parID
== kRootParID
) &&
2461 (VTOHFS(vp
)->hfs_private_metadata_dir
!= 0)) {
2462 --valence
; /* hide private dir */
2465 /* The 'link count' is faked */
2466 if (a
& ATTR_DIR_LINKCOUNT
)
2467 *((u_long
*)attrbufptr
)++ = 2 + valence
;
2468 if (a
& ATTR_DIR_ENTRYCOUNT
)
2469 *((u_long
*)attrbufptr
)++ = valence
;
2470 if (a
& ATTR_DIR_MOUNTSTATUS
) {
2471 if (vp
->v_mountedhere
) {
2472 *((u_long
*)attrbufptr
)++ = DIR_MNTSTATUS_MNTPOINT
;
2474 *((u_long
*)attrbufptr
)++ = 0;
2479 *attrbufptrptr
= attrbufptr
;
2484 // Pack the file attributes from the hfsCatalogInfo for the file.
2485 void PackCatalogInfoFileAttributeBlock( struct attrlist
*alist
, struct vnode
*root_vp
, struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2491 ExtendedVCB
*vcb
= VTOVCB(root_vp
);
2493 attrbufptr
= *attrbufptrptr
;
2494 varbufptr
= *varbufptrptr
;
2496 a
= alist
->fileattr
;
2497 if ( (catInfo
->nodeData
.cnd_type
== kCatalogFileNode
) && (a
!= 0) )
2500 if (a
& ATTR_FILE_LINKCOUNT
) {
2501 u_long linkcnt
= catInfo
->nodeData
.cnd_linkCount
;
2505 *((u_long
*)attrbufptr
)++ = linkcnt
;
2508 if (a
& ATTR_FILE_LINKCOUNT
) *((u_long
*)attrbufptr
)++ = 1;
2510 if (a
& ATTR_FILE_TOTALSIZE
) {
2511 *((off_t
*)attrbufptr
)++ =
2512 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
+
2513 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2515 if (a
& ATTR_FILE_ALLOCSIZE
) {
2516 *((off_t
*)attrbufptr
)++ =
2517 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
) +
2518 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2520 if (a
& ATTR_FILE_IOBLOCKSIZE
) {
2521 *((u_long
*)attrbufptr
)++ = (u_long
)(VTOHFS(root_vp
)->hfs_logBlockSize
);
2523 if (a
& ATTR_FILE_CLUMPSIZE
) {
2524 *((u_long
*)attrbufptr
)++ = vcb
->vcbClpSiz
;
2526 if (a
& ATTR_FILE_DEVTYPE
) {
2530 filetype
= (catInfo
->nodeData
.cnd_mode
& IFMT
);
2531 if (filetype
== IFCHR
|| filetype
== IFBLK
)
2532 rawdev
= (u_long
)catInfo
->nodeData
.cnd_rawDevice
;
2536 *((u_long
*)attrbufptr
)++ = rawdev
;
2538 if (a
& ATTR_FILE_FILETYPE
) {
2539 *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD */
2541 if (a
& ATTR_FILE_FORKCOUNT
) {
2542 *((u_long
*)attrbufptr
)++ = 2; /* XXX PPD */
2544 if (a
& ATTR_FILE_FORKLIST
) {
2546 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2547 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2549 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2550 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2551 ++((struct attrreference
*)attrbufptr
);
2553 if (a
& ATTR_FILE_DATALENGTH
) {
2554 *((off_t
*)attrbufptr
)++ =
2555 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
;
2557 if (a
& ATTR_FILE_DATAALLOCSIZE
) {
2558 *((off_t
*)attrbufptr
)++ =
2559 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2561 if (a
& ATTR_FILE_DATAEXTENTS
) {
2562 bcopy(&catInfo
->nodeData
.cnd_datafork
.extents
, attrbufptr
, sizeof(extentrecord
));
2563 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2565 if (a
& ATTR_FILE_RSRCLENGTH
) {
2566 *((off_t
*)attrbufptr
)++ =
2567 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2569 if (a
& ATTR_FILE_RSRCALLOCSIZE
) {
2570 *((off_t
*)attrbufptr
)++ =
2571 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2573 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2574 bcopy(&catInfo
->nodeData
.cnd_rsrcfork
.extents
, attrbufptr
, sizeof(extentrecord
));
2575 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2579 *attrbufptrptr
= attrbufptr
;
2580 *varbufptrptr
= varbufptr
;
2584 void PackFileAttributeBlock(struct attrlist
*alist
,
2586 struct hfsCatalogInfo
*catInfo
,
2587 void **attrbufptrptr
,
2588 void **varbufptrptr
) {
2589 struct hfsnode
*hp
= VTOH(vp
);
2590 FCB
*fcb
= HTOFCB(hp
);
2591 ExtendedVCB
*vcb
= HTOVCB(hp
);
2592 Boolean isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
2593 void *attrbufptr
= *attrbufptrptr
;
2594 void *varbufptr
= *varbufptrptr
;
2595 attrgroup_t a
= alist
->fileattr
;
2600 if (a
& ATTR_FILE_LINKCOUNT
) {
2601 u_long linkcnt
= catInfo
->nodeData
.cnd_linkCount
;
2605 *((u_long
*)attrbufptr
)++ = linkcnt
;
2608 if (a
& ATTR_FILE_LINKCOUNT
) *((u_long
*)attrbufptr
)++ = 1;
2610 if (a
& ATTR_FILE_TOTALSIZE
) {
2611 *((off_t
*)attrbufptr
)++ =
2612 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
+
2613 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2615 if (a
& ATTR_FILE_ALLOCSIZE
) {
2616 switch (H_FORKTYPE(hp
)) {
2618 *((off_t
*)attrbufptr
)++ =
2619 (off_t
)fcb
->fcbPLen
+
2620 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2623 *((off_t
*)attrbufptr
)++ =
2624 (off_t
)fcb
->fcbPLen
+
2625 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2628 *((off_t
*)attrbufptr
)++ =
2629 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
) +
2630 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2633 if (a
& ATTR_FILE_IOBLOCKSIZE
) *((u_long
*)attrbufptr
)++ = GetLogicalBlockSize(vp
);
2634 if (a
& ATTR_FILE_CLUMPSIZE
) *((u_long
*)attrbufptr
)++ = fcb
->fcbClmpSize
;
2635 if (a
& ATTR_FILE_DEVTYPE
) {
2638 if ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))
2639 rawdev
= (u_long
)catInfo
->nodeData
.cnd_rawDevice
;
2642 *((u_long
*)attrbufptr
)++ = rawdev
;
2644 if (a
& ATTR_FILE_FILETYPE
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD */
2645 if (a
& ATTR_FILE_FORKCOUNT
) *((u_long
*)attrbufptr
)++ = 2; /* XXX PPD */
2646 if (a
& ATTR_FILE_FORKLIST
) {
2648 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2649 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2651 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2652 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2653 ++((struct attrreference
*)attrbufptr
);
2655 if (H_FORKTYPE(hp
) == kDataFork
) {
2656 if (a
& ATTR_FILE_DATALENGTH
)
2657 *((off_t
*)attrbufptr
)++ = fcb
->fcbEOF
;
2658 if (a
& ATTR_FILE_DATAALLOCSIZE
) *((off_t
*)attrbufptr
)++ = fcb
->fcbPLen
;
2659 if (a
& ATTR_FILE_DATAEXTENTS
) {
2660 bcopy ( fcb
->fcbExtents
, attrbufptr
, sizeof(extentrecord
));
2661 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2664 if (a
& ATTR_FILE_DATALENGTH
) {
2665 *((off_t
*)attrbufptr
)++ =
2666 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
;
2668 if (a
& ATTR_FILE_DATAALLOCSIZE
) {
2669 *((off_t
*)attrbufptr
)++ =
2670 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2672 if (a
& ATTR_FILE_DATAEXTENTS
) {
2673 bcopy(&catInfo
->nodeData
.cnd_datafork
.extents
, attrbufptr
, sizeof(extentrecord
));
2674 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2677 if (H_FORKTYPE(hp
) == kRsrcFork
) {
2678 if (a
& ATTR_FILE_RSRCLENGTH
)
2679 *((off_t
*)attrbufptr
)++ = fcb
->fcbEOF
;
2680 if (a
& ATTR_FILE_RSRCALLOCSIZE
) *((off_t
*)attrbufptr
)++ = fcb
->fcbPLen
;
2681 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2682 bcopy ( fcb
->fcbExtents
, attrbufptr
, sizeof(extentrecord
));
2683 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2686 if (a
& ATTR_FILE_RSRCLENGTH
) {
2687 *((off_t
*)attrbufptr
)++ =
2688 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2690 if (a
& ATTR_FILE_RSRCALLOCSIZE
) {
2691 *((off_t
*)attrbufptr
)++ =
2692 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2694 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2695 bcopy(&catInfo
->nodeData
.cnd_rsrcfork
.extents
, attrbufptr
, sizeof(extentrecord
));
2696 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2701 *attrbufptrptr
= attrbufptr
;
2702 *varbufptrptr
= varbufptr
;
2706 void PackForkAttributeBlock(struct attrlist
*alist
,
2708 struct hfsCatalogInfo
*catInfo
,
2709 void **attrbufptrptr
,
2710 void **varbufptrptr
) {
2716 // This routine takes catInfo, and alist, as inputs and packs it into an attribute block.
2717 void PackCatalogInfoAttributeBlock ( struct attrlist
*alist
, struct vnode
*root_vp
, struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2719 //XXX Preflight that alist only contains bits with fields in catInfo
2721 PackCommonCatalogInfoAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2723 switch ( catInfo
->nodeData
.cnd_type
)
2725 case kCatalogFolderNode
:
2726 PackCatalogInfoDirAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2729 case kCatalogFileNode
:
2730 PackCatalogInfoFileAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2733 default: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR not being handled... */
2734 /* XXX PPD - Panic? */
2741 void PackAttributeBlock(struct attrlist
*alist
,
2743 struct hfsCatalogInfo
*catInfo
,
2744 void **attrbufptrptr
,
2745 void **varbufptrptr
)
2747 if (alist
->volattr
!= 0) {
2748 DBG_ASSERT((vp
->v_flag
& VROOT
) != 0);
2749 PackVolumeInfo(alist
,vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2751 PackCommonAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2753 switch (vp
->v_type
) {
2755 PackDirAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2760 PackFileAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2763 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
2764 not being handled...
2767 /* XXX PPD - Panic? */
2775 void UnpackVolumeAttributeBlock(struct attrlist
*alist
,
2776 struct vnode
*root_vp
,
2778 void **attrbufptrptr
,
2779 void **varbufptrptr
) {
2780 void *attrbufptr
= *attrbufptrptr
;
2783 if ((alist
->commonattr
== 0) && (alist
->volattr
== 0)) {
2784 return; /* Get out without dirtying the VCB */
2789 a
= alist
->commonattr
;
2791 if (a
& ATTR_CMN_SCRIPT
) {
2792 vcb
->volumeNameEncodingHint
= (u_int32_t
)*(((text_encoding_t
*)attrbufptr
)++);
2794 a
&= ~ATTR_CMN_SCRIPT
;
2797 if (a
& ATTR_CMN_CRTIME
) {
2798 vcb
->vcbCrDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2799 /* Need to update the local time also */
2800 vcb
->localCreateDate
= UTCToLocal(vcb
->vcbCrDate
);
2801 ++((struct timespec
*)attrbufptr
);
2803 a
&= ~ATTR_CMN_CRTIME
;
2806 if (a
& ATTR_CMN_MODTIME
) {
2807 vcb
->vcbLsMod
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2808 ++((struct timespec
*)attrbufptr
);
2810 a
&= ~ATTR_CMN_MODTIME
;
2813 if (a
& ATTR_CMN_BKUPTIME
) {
2814 vcb
->vcbVolBkUp
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2815 ++((struct timespec
*)attrbufptr
);
2817 a
&= ~ATTR_CMN_BKUPTIME
;
2820 if (a
& ATTR_CMN_FNDRINFO
) {
2821 bcopy (attrbufptr
, &vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
2822 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
2824 a
&= ~ATTR_CMN_FNDRINFO
;
2828 DBG_ASSERT(a
== 0); /* All common attributes for volumes must've been handled by now... */
2830 a
= alist
->volattr
& ~ATTR_VOL_INFO
;
2831 if (a
& ATTR_VOL_NAME
) {
2832 copystr(((char *)attrbufptr
) + *((u_long
*)attrbufptr
), vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
2833 (char *)attrbufptr
+= sizeof(struct attrreference
);
2835 a
&= ~ATTR_VOL_NAME
;
2839 DBG_ASSERT(a
== 0); /* All common attributes for volumes must've been handled by now... */
2841 vcb
->vcbFlags
|= 0xFF00; // Mark the VCB dirty
2847 void UnpackCommonAttributeBlock(struct attrlist
*alist
,
2849 struct hfsCatalogInfo
*catInfo
,
2850 void **attrbufptrptr
,
2851 void **varbufptrptr
) {
2852 struct hfsnode
*hp
= VTOH(vp
);
2856 attrbufptr
= *attrbufptrptr
;
2858 DBG_ASSERT(catInfo
!= NULL
);
2860 a
= alist
->commonattr
;
2861 if (a
& ATTR_CMN_SCRIPT
) {
2862 catInfo
->nodeData
.cnd_textEncoding
= (u_int32_t
)*((text_encoding_t
*)attrbufptr
)++;
2863 UpdateVolumeEncodings(VTOVCB(vp
), catInfo
->nodeData
.cnd_textEncoding
); /* Update the volume encoding */
2865 a
&= ~ATTR_CMN_SCRIPT
;
2868 if (a
& ATTR_CMN_CRTIME
) {
2869 catInfo
->nodeData
.cnd_createDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2870 VTOH(vp
)->h_meta
->h_crtime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2871 ++((struct timespec
*)attrbufptr
);
2873 a
&= ~ATTR_CMN_CRTIME
;
2876 if (a
& ATTR_CMN_MODTIME
) {
2877 catInfo
->nodeData
.cnd_contentModDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2878 VTOH(vp
)->h_meta
->h_mtime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2879 ++((struct timespec
*)attrbufptr
);
2880 hp
->h_nodeflags
&= ~IN_UPDATE
;
2882 a
&= ~ATTR_CMN_MODTIME
;
2885 if (a
& ATTR_CMN_CHGTIME
) {
2886 catInfo
->nodeData
.cnd_attributeModDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2887 VTOH(vp
)->h_meta
->h_ctime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2888 ++((struct timespec
*)attrbufptr
);
2889 hp
->h_nodeflags
&= ~IN_CHANGE
;
2891 a
&= ~ATTR_CMN_CHGTIME
;
2894 if (a
& ATTR_CMN_ACCTIME
) {
2895 catInfo
->nodeData
.cnd_accessDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2896 VTOH(vp
)->h_meta
->h_atime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2897 ++((struct timespec
*)attrbufptr
);
2898 hp
->h_nodeflags
&= ~IN_ACCESS
;
2900 a
&= ~ATTR_CMN_ACCTIME
;
2903 if (a
& ATTR_CMN_BKUPTIME
) {
2904 catInfo
->nodeData
.cnd_backupDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2905 VTOH(vp
)->h_meta
->h_butime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2906 ++((struct timespec
*)attrbufptr
);
2908 a
&= ~ATTR_CMN_BKUPTIME
;
2911 if (a
& ATTR_CMN_FNDRINFO
) {
2912 bcopy (attrbufptr
, &catInfo
->nodeData
.cnd_finderInfo
, sizeof(catInfo
->nodeData
.cnd_finderInfo
));
2913 (char *)attrbufptr
+= sizeof(catInfo
->nodeData
.cnd_finderInfo
);
2915 a
&= ~ATTR_CMN_FNDRINFO
;
2918 if (a
& ATTR_CMN_OWNERID
) {
2919 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2920 u_int32_t uid
= (u_int32_t
)*((uid_t
*)attrbufptr
)++;
2921 if (uid
!= (uid_t
)VNOVAL
)
2922 hp
->h_meta
->h_uid
= uid
; /* catalog will get updated by hfs_chown() */
2925 ((uid_t
*)attrbufptr
)++;
2928 a
&= ~ATTR_CMN_OWNERID
;
2931 if (a
& ATTR_CMN_GRPID
) {
2932 u_int32_t gid
= (u_int32_t
)*((gid_t
*)attrbufptr
)++;
2933 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2934 if (gid
!= (gid_t
)VNOVAL
)
2935 hp
->h_meta
->h_gid
= gid
; /* catalog will get updated by hfs_chown() */
2938 a
&= ~ATTR_CMN_GRPID
;
2941 if (a
& ATTR_CMN_ACCESSMASK
) {
2942 u_int16_t mode
= (u_int16_t
)*((u_long
*)attrbufptr
)++;
2943 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2944 if (mode
!= (mode_t
)VNOVAL
) {
2945 hp
->h_meta
->h_mode
&= ~ALLPERMS
;
2946 hp
->h_meta
->h_mode
|= (mode
& ALLPERMS
); /* catalog will get updated by hfs_chmod() */
2950 a
&= ~ATTR_CMN_ACCESSMASK
;
2953 if (a
& ATTR_CMN_FLAGS
) {
2954 u_long flags
= *((u_long
*)attrbufptr
)++;
2955 /* Flags are settable only on HFS+ volumes. A special exception is made for the IMMUTABLE
2956 flags (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on HFS volumes as well: */
2957 if ((VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) ||
2958 ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) && ((flags
& ~IMMUTABLE
) == 0))) {
2959 if (flags
!= (u_long
)VNOVAL
) {
2960 hp
->h_meta
->h_pflags
= flags
; /* catalog will get updated by hfs_chflags */
2964 a
&= ~ATTR_CMN_FLAGS
;
2970 DEBUG_BREAK_MSG(("UnpackCommonAttributes: unhandled bit: 0x%08X\n", a
));
2974 *attrbufptrptr
= attrbufptr
;
2975 // *varbufptrptr = varbufptr;
2981 void UnpackDirAttributeBlock(struct attrlist
*alist
,
2983 struct hfsCatalogInfo
*catInfo
,
2984 void **attrbufptrptr
,
2985 void **varbufptrptr
) {
2991 attrbufptr
= *attrbufptrptr
;
2992 varbufptr
= *varbufptrptr
;
2996 *attrbufptrptr
= attrbufptr
;
2997 *varbufptrptr
= varbufptr
;
3004 void UnpackFileAttributeBlock(struct attrlist
*alist
,
3006 struct hfsCatalogInfo
*catInfo
,
3007 void **attrbufptrptr
,
3008 void **varbufptrptr
) {
3014 attrbufptr
= *attrbufptrptr
;
3015 varbufptr
= *varbufptrptr
;
3019 *attrbufptrptr
= attrbufptr
;
3020 *varbufptrptr
= varbufptr
;
3027 void UnpackForkAttributeBlock(struct attrlist
*alist
,
3029 struct hfsCatalogInfo
*catInfo
,
3030 void **attrbufptrptr
,
3031 void **varbufptrptr
) {
3037 attrbufptr
= *attrbufptrptr
;
3038 varbufptr
= *varbufptrptr
;
3042 *attrbufptrptr
= attrbufptr
;
3043 *varbufptrptr
= varbufptr
;
3049 void UnpackAttributeBlock(struct attrlist
*alist
,
3051 struct hfsCatalogInfo
*catInfo
,
3052 void **attrbufptrptr
,
3053 void **varbufptrptr
) {
3056 if (alist
->volattr
!= 0) {
3057 UnpackVolumeAttributeBlock(alist
, vp
, VTOVCB(vp
), attrbufptrptr
, varbufptrptr
);
3061 /* We're dealing with a vnode object here: */
3062 UnpackCommonAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3065 switch (vp
->v_type
) {
3067 UnpackDirAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3071 /* case VCPLX: */ /* XXX PPD TBC */
3072 UnpackFileAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3076 UnpackForkAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3079 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
3080 not being handled...
3083 /* XXX PPD - Panic? */
3091 unsigned long BestBlockSizeFit(unsigned long allocationBlockSize
,
3092 unsigned long blockSizeLimit
,
3093 unsigned long baseMultiple
) {
3095 Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the
3096 specified limit but still an even multiple of the baseMultiple.
3098 int baseBlockCount
, blockCount
;
3099 unsigned long trialBlockSize
;
3101 if (allocationBlockSize
% baseMultiple
!= 0) {
3103 Whoops: the allocation blocks aren't even multiples of the specified base:
3104 no amount of dividing them into even parts will be a multiple, either then!
3106 return 512; /* Hope for the best */
3109 /* Try the obvious winner first, to prevent 12K allocation blocks, for instance,
3110 from being handled as two 6K logical blocks instead of 3 4K logical blocks.
3111 Even though the former (the result of the loop below) is the larger allocation
3112 block size, the latter is more efficient: */
3113 if (allocationBlockSize
% PAGE_SIZE
== 0) return PAGE_SIZE
;
3115 /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */
3116 baseBlockCount
= allocationBlockSize
/ baseMultiple
; /* Now guaranteed to be an even multiple */
3118 for (blockCount
= baseBlockCount
; blockCount
> 0; --blockCount
) {
3119 trialBlockSize
= blockCount
* baseMultiple
;
3120 if (allocationBlockSize
% trialBlockSize
== 0) { /* An even multiple? */
3121 if ((trialBlockSize
<= blockSizeLimit
) &&
3122 (trialBlockSize
% baseMultiple
== 0)) {
3123 return trialBlockSize
;
3128 /* Note: we should never get here, since blockCount = 1 should always work,
3129 but this is nice and safe and makes the compiler happy, too ... */
3135 * To make the HFS Plus filesystem follow UFS unlink semantics, a remove
3136 * of an active vnode is translated to a move/rename so the file appears
3137 * deleted. The destination folder for these move/renames is setup here
3138 * and a reference to it is place in hfsmp->hfs_private_metadata_dir.
3141 FindMetaDataDirectory(ExtendedVCB
*vcb
)
3144 hfsCatalogInfo catInfo
;
3145 HFSCatalogNodeID dirID
;
3146 u_int32_t metadata_createdate
;
3149 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
3153 metadata_createdate
= 0;
3154 strncpy(namep
, HFSPLUS_PRIVATE_DIR
, sizeof(namep
));
3155 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
3156 catInfo
.hint
= kNoHint
;
3158 /* lock catalog b-tree */
3159 retval
= hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_SHARED
, current_proc());
3160 if (retval
) goto Err_Exit
;
3162 if (hfs_getcatalog(vcb
, kRootDirID
, namep
, -1, &catInfo
) == 0) {
3163 dirID
= catInfo
.nodeData
.cnd_nodeID
;
3164 metadata_createdate
= catInfo
.nodeData
.cnd_createDate
;
3165 } else if (VCBTOHFS(vcb
)->hfs_fs_ronly
== 0) {
3166 if (CreateCatalogNode(vcb
, kRootDirID
, namep
, kCatalogFolderNode
, &dirID
, &catInfo
.hint
, 0) == 0) {
3167 catInfo
.hint
= kNoHint
;
3168 if (hfs_getcatalog(vcb
, kRootDirID
, namep
, -1, &catInfo
) == 0) {
3170 /* create date is later used for validation */
3171 catInfo
.nodeData
.cnd_createDate
= vcb
->vcbCrDate
;
3172 metadata_createdate
= catInfo
.nodeData
.cnd_createDate
;
3174 /* directory with no permissions owned by root */
3175 catInfo
.nodeData
.cnd_mode
= IFDIR
;
3176 catInfo
.nodeData
.cnd_adminFlags
= (SF_IMMUTABLE
>> 16);
3178 /* hidden and off the desktop view */
3179 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frLocation
.v
= SWAP_BE16 (22460);
3180 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frLocation
.h
= SWAP_BE16 (22460);
3181 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frFlags
|= SWAP_BE16 (kIsInvisible
+ kNameLocked
);
3183 (void) UpdateCatalogNode(vcb
, kRootDirID
, namep
, catInfo
.hint
, &catInfo
.nodeData
);
3188 /* unlock catalog b-tree */
3189 (void) hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3191 VCBTOHFS(vcb
)->hfs_metadata_createdate
= metadata_createdate
;
3193 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3200 RemovedMetaDataDirectory(ExtendedVCB
*vcb
)
3203 hfsCatalogInfo catInfo
;
3206 strncpy(name
, HFSPLUS_PRIVATE_DIR
, sizeof(name
));
3207 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
3209 /* lock catalog b-tree */
3210 retval
= hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_SHARED
, current_proc());
3211 if (retval
) goto Err_Exit
;
3213 /* If the HFSPLUSMETADATAFOLDER exists then delete it. */
3214 retval
= GetCatalogNode(vcb
, kRootDirID
, name
, strlen(name
), kNoHint
,
3215 &catInfo
.nodeData
, &catInfo
.hint
);
3216 if (retval
== 0 && (catInfo
.nodeData
.cnd_type
== kCatalogFolderNode
)) {
3217 (void) DeleteCatalogNode(vcb
, kRootDirID
, name
, catInfo
.hint
);
3218 printf("hfs_mount: removed \"%s\" from hfs volume \"%s\"\n", name
, vcb
->vcbVN
);
3221 /* unlock catalog b-tree */
3222 (void) hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3225 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3229 * This will return the correct logical block size for a given vnode.
3230 * For most files, it is the allocation block size, for meta data like
3231 * BTrees, this is kept as part of the BTree private nodeSize
3234 GetLogicalBlockSize(struct vnode
*vp
)
3236 u_int32_t logBlockSize
;
3238 DBG_ASSERT(vp
!= NULL
);
3240 /* start with default */
3241 logBlockSize
= VTOHFS(vp
)->hfs_logBlockSize
;
3243 if (vp
->v_flag
& VSYSTEM
) {
3244 if (VTOH(vp
)->fcbBTCBPtr
!= NULL
) {
3245 BTreeInfoRec bTreeInfo
;
3248 * We do not lock the BTrees, because if we are getting block..then the tree
3249 * should be locked in the first place.
3250 * We just want the nodeSize wich will NEVER change..so even if the world
3251 * is changing..the nodeSize should remain the same. Which argues why lock
3252 * it in the first place??
3255 (void) BTGetInformation (VTOFCB(vp
), kBTreeInfoVersion
, &bTreeInfo
);
3257 logBlockSize
= bTreeInfo
.nodeSize
;
3259 } else if (H_FILEID(VTOH(vp
)) == kHFSAllocationFileID
) {
3260 logBlockSize
= VTOVCB(vp
)->vcbVBMIOSize
;
3264 DBG_ASSERT(logBlockSize
> 0);
3266 return logBlockSize
;
3270 * Map HFS Common errors (negative) to BSD error codes (positive).
3271 * Positive errors (ie BSD errors) are passed through unchanged.
3273 short MacToVFSError(OSErr err
)
3277 DBG_ERR(("MacToVFSError: passing error #%d unchanged...\n", err
));
3283 DBG_ERR(("MacToVFSError: mapping error code %d...\n", err
));
3287 case dirFulErr
: /* -33 */
3288 case dskFulErr
: /* -34 */
3289 case btNoSpaceAvail
: /* -32733 */
3290 case fxOvFlErr
: /* -32750 */
3291 return ENOSPC
; /* +28 */
3293 case btBadNode
: /* -32731 */
3294 case ioErr
: /* -36 */
3295 return EIO
; /* +5 */
3297 case mFulErr
: /* -41 */
3298 case memFullErr
: /* -108 */
3299 return ENOMEM
; /* +12 */
3301 case tmfoErr
: /* -42 */
3302 /* Consider EMFILE (Too many open files, 24)? */
3303 return ENFILE
; /* +23 */
3305 case nsvErr
: /* -35 */
3306 case fnfErr
: /* -43 */
3307 case dirNFErr
: /* -120 */
3308 case fidNotFound
: /* -1300 */
3309 return ENOENT
; /* +2 */
3311 case wPrErr
: /* -44 */
3312 case vLckdErr
: /* -46 */
3313 case fsDSIntErr
: /* -127 */
3314 return EROFS
; /* +30 */
3316 case opWrErr
: /* -49 */
3317 case fLckdErr
: /* -45 */
3318 return EACCES
; /* +13 */
3320 case permErr
: /* -54 */
3321 case wrPermErr
: /* -61 */
3322 return EPERM
; /* +1 */
3324 case fBsyErr
: /* -47 */
3325 return EBUSY
; /* +16 */
3327 case dupFNErr
: /* -48 */
3328 case fidExists
: /* -1301 */
3329 case cmExists
: /* -32718 */
3330 case btExists
: /* -32734 */
3331 return EEXIST
; /* +17 */
3333 case rfNumErr
: /* -51 */
3334 return EBADF
; /* +9 */
3336 case notAFileErr
: /* -1302 */
3337 return EISDIR
; /* +21 */
3339 case cmNotFound
: /* -32719 */
3340 case btNotFound
: /* -32735 */
3341 return ENOENT
; /* 28 */
3343 case cmNotEmpty
: /* -32717 */
3344 return ENOTEMPTY
; /* 66 */
3346 case cmFThdDirErr
: /* -32714 */
3347 return EISDIR
; /* 21 */
3349 case fxRangeErr
: /* -32751 */
3352 case bdNamErr
: /* -37 */
3353 return ENAMETOOLONG
; /* 63 */
3355 case fnOpnErr
: /* -38 */
3356 case eofErr
: /* -39 */
3357 case posErr
: /* -40 */
3358 case paramErr
: /* -50 */
3359 case badMDBErr
: /* -60 */
3360 case badMovErr
: /* -122 */
3361 case sameFileErr
: /* -1306 */
3362 case badFidErr
: /* -1307 */
3363 case fileBoundsErr
: /* -1309 */
3364 return EINVAL
; /* +22 */
3366 case fsBTBadNodeSize
:
3369 DBG_UTILS(("Unmapped MacOS error: %d\n", err
));
3370 return EIO
; /* +5 */
3376 * All of our debugging functions
3381 void debug_vn_status (char* introStr
, struct vnode
*vn
)
3383 DBG_VOP(("%s:\t",introStr
));
3386 if (vn
->v_tag
!= VT_HFS
)
3388 DBG_VOP(("NON-HFS VNODE Ox%08lX\n", (unsigned long)vn
));
3390 else if(vn
->v_tag
==VT_HFS
&& (vn
->v_data
==NULL
|| VTOH((vn
))->h_valid
!= HFS_VNODE_MAGIC
))
3392 DBG_VOP(("BAD VNODE PRIVATE DATA!!!!\n"));
3396 DBG_VOP(("r: %d & ", vn
->v_usecount
));
3397 if (lockstatus(&VTOH(vn
)->h_lock
))
3399 DBG_VOP_CONT(("is L\n"));
3403 DBG_VOP_CONT(("is U\n"));
3409 DBG_VOP(("vnode is NULL\n"));
3413 void debug_vn_print (char* introStr
, struct vnode
*vn
)
3415 // DBG_FUNC_NAME("DBG_VN_PRINT");
3416 DBG_ASSERT (vn
!= NULL
);
3417 DBG_VFS(("%s: ",introStr
));
3418 DBG_VFS_CONT(("vnode: 0x%x is a ", (uint
)vn
));
3422 DBG_VFS_CONT(("%s","UFS"));
3425 DBG_VFS_CONT(("%s","HFS"));
3428 DBG_VFS_CONT(("%s","UNKNOWN"));
3432 DBG_VFS_CONT((" vnode\n"));
3433 if (vn
->v_tag
==VT_HFS
)
3435 if (vn
->v_data
==NULL
)
3437 DBG_VFS(("BAD VNODE PRIVATE DATA!!!!\n"));
3441 DBG_VFS((" Name: %s Id: %ld ",H_NAME(VTOH(vn
)), H_FILEID(VTOH(vn
))));
3447 DBG_VFS_CONT(("Refcount: %d\n", vn
->v_usecount
));
3448 if (VOP_ISLOCKED(vn
))
3450 DBG_VFS((" The vnode is locked\n"));
3454 DBG_VFS((" The vnode is not locked\n"));
3458 void debug_rename_test_locks (char* introStr
,
3469 DBG_VOP(("\t%s: ", introStr
));
3470 if (fvp
) {if(lockstatus(&VTOH(fvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3471 if (fdvp
) {if(lockstatus(&VTOH(fdvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3472 if (tvp
) {if(lockstatus(&VTOH(tvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3473 if (tdvp
) {if(lockstatus(&VTOH(tdvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3474 DBG_VFS_CONT(("\n"));
3477 if (lockstatus(&VTOH(fvp
)->h_lock
)) {
3478 if (fstatus
==VOPDBG_UNLOCKED
) {
3479 DBG_VOP(("\tfvp should be NOT LOCKED and it is\n"));
3481 } else if (fstatus
== VOPDBG_LOCKED
) {
3482 DBG_VOP(("\tfvp should be LOCKED and it isnt\n"));
3487 if (lockstatus(&VTOH(fdvp
)->h_lock
)) {
3488 if (fdstatus
==VOPDBG_UNLOCKED
) {
3489 DBG_VOP(("\tfdvp should be NOT LOCKED and it is\n"));
3491 } else if (fdstatus
== VOPDBG_LOCKED
) {
3492 DBG_VOP(("\tfdvp should be LOCKED and it isnt\n"));
3497 if (lockstatus(&VTOH(tvp
)->h_lock
)) {
3498 if (tstatus
==VOPDBG_UNLOCKED
) {
3499 DBG_VOP(("\ttvp should be NOT LOCKED and it is\n"));
3501 } else if (tstatus
== VOPDBG_LOCKED
) {
3502 DBG_VOP(("\ttvp should be LOCKED and it isnt\n"));
3507 if (lockstatus(&VTOH(tdvp
)->h_lock
)) {
3508 if (tdstatus
==VOPDBG_UNLOCKED
) {
3509 DBG_VOP(("\ttdvp should be NOT LOCKED and it is\n"));
3511 } else if (tdstatus
== VOPDBG_LOCKED
) {
3512 DBG_VOP(("\ttdvp should be LOCKED and it isnt\n"));
3518 #endif /* HFS_DIAGNOSTIC */
3522 void debug_check_buffersizes(struct vnode
*vp
, struct hfsnode
*hp
, struct buf
*bp
) {
3523 DBG_ASSERT(bp
->b_validoff
== 0);
3524 DBG_ASSERT(bp
->b_dirtyoff
== 0);
3525 DBG_ASSERT((bp
->b_bcount
== HTOHFS(hp
)->hfs_logBlockSize
) ||
3526 ((bp
->b_bcount
% 512 == 0) &&
3527 (bp
->b_validend
> 0) &&
3528 (bp
->b_dirtyend
> 0) &&
3529 (bp
->b_bcount
< HTOHFS(hp
)->hfs_logBlockSize
)));
3531 if (bp
->b_validend
== 0) {
3532 DBG_ASSERT(bp
->b_dirtyend
== 0);
3534 DBG_ASSERT(bp
->b_validend
== bp
->b_bcount
);
3535 DBG_ASSERT(bp
->b_dirtyend
<= bp
->b_bcount
);
3540 void debug_check_blocksizes(struct vnode
*vp
) {
3541 struct hfsnode
*hp
= VTOH(vp
);
3544 if (vp
->v_flag
& VSYSTEM
) return;
3546 for (bp
= vp
->v_cleanblkhd
.lh_first
; bp
!= NULL
; bp
= bp
->b_vnbufs
.le_next
) {
3547 debug_check_buffersizes(vp
, hp
, bp
);
3550 for (bp
= vp
->v_dirtyblkhd
.lh_first
; bp
!= NULL
; bp
= bp
->b_vnbufs
.le_next
) {
3551 debug_check_buffersizes(vp
, hp
, bp
);
3555 void debug_check_catalogdata(struct CatalogNodeData
*cat
) {
3557 if (cat
->cnm_nameptr
== NULL
) {
3558 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3560 else if (cat
->cnm_nameptr
== cat
->cnm_namespace
) {
3561 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3564 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == kCatNameIsAllocated
);
3567 if (cat
->cnm_nameptr
) {
3568 DBG_ASSERT(strlen(cat
->cnm_nameptr
) == cat
->cnm_length
);
3571 if (cat
->cnm_flags
& kCatNameIsConsumed
) {
3572 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3575 if (cat
->cnm_flags
& kCatNameNoCopyName
) {
3576 DBG_ASSERT((cat
->cnm_flags
& (kCatNameIsAllocated
|kCatNameIsConsumed
|kCatNameIsMangled
)) == 0);
3577 DBG_ASSERT(cat
->cnm_length
== 0);
3578 DBG_ASSERT(cat
->cnm_nameptr
== 0);
3579 DBG_ASSERT(strlen(cat
->cnm_namespace
) == 0);
3584 extern void hfs_vhash_dbg(struct hfsnode
*hp
);
3586 /* Checks the valicity of a hfs vnode */
3587 void debug_check_vnode(struct vnode
*vp
, int stage
) {
3593 if (VTOHFS(vp
)->hfs_mount_flags
& kHFSBootVolumeInconsistentMask
)
3594 DEBUG_BREAK_MSG(("Volume is damaged!"));
3598 DEBUG_BREAK_MSG(("Null vnode"));
3599 if (vp
->v_tag
!= VT_HFS
)
3600 DEBUG_BREAK_MSG(("Not a HFS vnode, it is a %d", vp
->v_tag
));
3601 if (vp
->v_data
==NULL
)
3602 DEBUG_BREAK_MSG(("v_data is NULL"));
3606 if (hp
->h_valid
!= HFS_VNODE_MAGIC
)
3607 DEBUG_BREAK_MSG(("Bad Formed HFS node"));
3608 if (hp
->h_vp
==NULL
|| hp
->h_vp
!=vp
)
3609 DEBUG_BREAK_MSG(("Bad hfsnode vnode pte"));
3610 if (hp
->h_meta
== NULL
)
3611 DEBUG_BREAK_MSG(("Bad hfsnode meta ptr"));
3612 switch (H_FORKTYPE(hp
)) {
3615 if ((hp
->h_meta
->h_siblinghead
.cqh_first
== NULL
) || (hp
->h_meta
->h_siblinghead
.cqh_last
== NULL
))
3616 DEBUG_BREAK_MSG(("Null sibling header"));
3617 if ((hp
->h_sibling
.cqe_next
==NULL
) || (hp
->h_sibling
.cqe_prev
==NULL
))
3618 DEBUG_BREAK_MSG(("Null sibling list"));
3619 if (hp
->h_meta
->h_usecount
<1 || hp
->h_meta
->h_usecount
>2)
3620 DEBUG_BREAK_MSG(("Bad sibling usecount"));
3624 if ((hp
->h_meta
->h_siblinghead
.cqh_first
!= NULL
) || (hp
->h_meta
->h_siblinghead
.cqh_last
!= NULL
))
3625 DEBUG_BREAK_MSG(("Non Null sibling header"));
3626 if ((hp
->h_sibling
.cqe_next
!=NULL
) || (hp
->h_sibling
.cqe_prev
!=NULL
))
3627 DEBUG_BREAK_MSG(("Null sibling list"));
3628 if (hp
->h_meta
->h_usecount
!=1)
3629 DEBUG_BREAK_MSG(("Bad usecount"));
3633 DEBUG_BREAK_MSG(("Bad hfsnode fork type"));
3637 if (hp
->h_meta
->h_devvp
== NULL
)
3638 DEBUG_BREAK_MSG(("Bad hfsnode dev vnode"));
3640 DEBUG_BREAK_MSG(("Bad dev id"));
3641 if (H_FILEID(hp
) == 0)
3642 DEBUG_BREAK_MSG(("Bad file id"));
3644 if (((hp
->h_meta
->h_metaflags
& IN_DATANODE
)==0) && (H_DIRID(hp
) == 0) && (H_FILEID(hp
) != 1))
3645 DEBUG_BREAK_MSG(("Bad dir id"));
3647 if (hp
->h_meta
->h_namePtr
== NULL
&& hp
->h_meta
->h_namelen
!=0)
3648 DEBUG_BREAK_MSG(("hfs meta h_namelen is not 0"));
3649 if (hp
->h_meta
->h_namePtr
!= NULL
&& strlen(hp
->h_meta
->h_namePtr
) != hp
->h_meta
->h_namelen
)
3650 DEBUG_BREAK_MSG(("Bad hfs meta h_namelen"));
3652 /* Check the hash */
3655 /* Check to see if we want to compare with the disk */
3658 hfsCatalogInfo catInfo
;
3660 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
3663 if (hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_SHARED
, current_proc()))
3666 if (hfs_getcatalog(VTOVCB(vp
), H_DIRID(hp
), hp
->h_meta
->h_namePtr
, hp
->h_meta
->h_namelen
, &catInfo
))
3667 DEBUG_BREAK_MSG(("Could not find hfsnode Catalog record"));
3669 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3671 if (H_FILEID(hp
) != catInfo
.nodeData
.cnd_nodeID
)
3672 DEBUG_BREAK_MSG(("hfsnode catalog node id mismatch"));
3673 if (H_DIRID(hp
) != catInfo
.nodeData
.cnm_parID
)
3674 DEBUG_BREAK_MSG(("hfsnode catalog dir id mismatch"));
3675 if (strcmp(hp
->h_meta
->h_namePtr
, catInfo
.nodeData
.cnm_nameptr
) != 0)
3676 DEBUG_BREAK_MSG(("hfsnode catalog name mismatch"));
3677 /* Check dates too??? */
3679 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3686 for(i
= 0, size
= 0; i
< kHFSPlusExtentDensity
; i
++)
3688 size
+= hp
->fcbExtents
[i
].blockCount
;
3691 if (hp
->fcbEOF
> hp
->fcbPLen
)
3692 DEBUG_BREAK_MSG(("fcbPLen is smaller than fcbEOF"));
3694 if (hp
->fcbExtents
[kHFSPlusExtentDensity
-1].blockCount
== 0) {
3695 if ((off_t
)size
* (off_t
)VTOVCB(vp
)->blockSize
!= hp
->fcbPLen
)
3696 DEBUG_BREAK_MSG(("fcbPLen does not match extents"));
3698 if ( hp
->fcbPLen
< (off_t
)size
* (off_t
)VTOVCB(vp
)->blockSize
)
3699 DEBUG_BREAK_MSG(("fcbPLen is smaller than extents"));
3701 for(i
= 0; i
< kHFSPlusExtentDensity
; i
++)
3703 if (hp
->fcbExtents
[i
].blockCount
== 0 || hp
->fcbExtents
[i
].startBlock
== 0)
3706 if ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) && i
> kHFSExtentDensity
)
3707 DEBUG_BREAK_MSG(("Illegal value in extents for ordinary HFS"));
3708 if (i
> kHFSPlusExtentDensity
) {
3709 for(; i
< kHFSPlusExtentDensity
; i
++)
3711 if (hp
->fcbExtents
[i
].blockCount
!= 0 || hp
->fcbExtents
[i
].startBlock
!= 0)
3712 DEBUG_BREAK_MSG(("Illegal value in extents"));
3719 if (0 && vp
->v_flag
& VSYSTEM
) {
3722 BTGetInformation(hp
, 0, &info
);
3723 if (hp
->fcbBTCBPtr
== NULL
)
3724 DEBUG_BREAK_MSG(("Null fcbBTCBPtr"));
3725 if (H_HINT(hp
) == 0)
3726 DEBUG_BREAK_MSG(("hint is 0"));
3727 if (H_HINT(hp
) > info
.numNodes
)
3728 DEBUG_BREAK_MSG(("hint > numNodes"));
3733 #endif /* HFS_DIAGNOSTIC */