2 * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* @(#)hfs_vfsutils.c 4.0
24 * (c) 1997-2000 Apple Computer, Inc. All Rights Reserved
26 * hfs_vfsutils.c -- Routines that go between the HFS layer and the VFS.
28 * Change History (most recent first):
30 * 22-Jan-2000 Don Brady Remove calls to MountCheck.
31 * 7-Sep-1999 Don Brady Add HFS Plus hard-link support.
32 * 25-Aug-1999 Don Brady Dont't use vcbAlBlSt for HFS plus volumes (2350009).
33 * 9-Aug-1999 Pat Dirks Added support for ATTR_VOL_ENCODINGSUSED [#2357367].
34 * 16-Jul-1999 Pat Dirks Fixed PackCommonCatalogInfoAttributeBlock to return full range of possible vnode types [#2317604]
35 * 15-Jun-1999 Pat Dirks Added support for return of mounted device in hfs_getattrlist [#2345297].
36 * 9-Jun-1999 Don Brady Cleanup vcb accesses in hfs_MountHFSVolume.
37 * 3-Jun-1999 Don Brady Remove references to unused/legacy vcb fields (eg vcbXTClpSiz).
38 * 21-May-1999 Don Brady Add call to hfs_vinit in hfsGet to support mknod.
39 * 6-Apr-1999 Don Brady Fixed de-reference of NULL dvp in hfsGet.
40 * 22-Mar-1999 Don Brady Add support for UFS delete semantics.
41 * 1-Mar-1999 Scott Roberts Dont double MALLOC on long names.
42 * 23-Feb-1999 Pat Dirks Change incrementing of meta refcount to be done BEFORE lock is acquired.
43 * 2-Feb-1999 Pat Dirks For volume ATTR_CMN_SCRIPT use vcb->volumeNameEncodingHint instead of 0.
44 * 10-Mar-1999 Don Brady Removing obsolete code.
45 * 2-Feb-1999 Don Brady For volume ATTR_CMN_SCRIPT use vcb->volumeNameEncodingHint instead of 0.
46 * 18-Jan-1999 Pat Dirks Changed CopyCatalogToHFSNode to start with ACCESSPERMS instead of adding
47 * write access only for unlocked files (now handled via IMMUTABLE setting)
48 * 7-Dec-1998 Pat Dirks Changed PackCatalogInfoFileAttributeBlock to return proper I/O block size.
49 * 7-Dec-1998 Don Brady Pack the real text encoding instead of zero.
50 * 16-Dec-1998 Don Brady Use the root's crtime intead of vcb create time for getattrlist.
51 * 16-Dec-1998 Don Brady Use the root's crtime intead of vcb create time for getattrlist.
52 * 2-Dec-1998 Scott Roberts Copy the mdbVN correctly into the vcb.
53 * 3-Dec-1998 Pat Dirks Added support for ATTR_VOL_MOUNTFLAGS.
54 * 20-Nov-1998 Don Brady Add support for UTF-8 names.
55 * 18-Nov-1998 Pat Dirks Changed UnpackCommonAttributeBlock to call wait for hfs_chflags to update catalog entry when changing flags
56 * 13-Nov-1998 Pat Dirks Changed BestBlockSizeFit to try PAGE_SIZE only and skip check for MAXBSIZE.
57 * 10-Nov-1998 Pat Dirks Changed CopyCatalogToHFSNode to ensure consistency between lock flag and IMMUTABLE bits.
58 * 10-Nov-1998 Pat Dirks Added MapFileOffset(), LogicalBlockSize() and UpdateBlockMappingTable() routines.
59 * 18-Nov-1998 Pat Dirks Changed PackVolAttributeBlock to return proper logical block size
60 * for ATTR_VOL_IOBLOCKSIZE attribute.
61 * 3-Nov-1998 Umesh Vaishampayan Changes to deal with "struct timespec"
62 * change in the kernel.
63 * 23-Sep-1998 Don Brady In UnpackCommonAttributeBlock simplified setting of gid, uid and mode.
64 * 10-Nov-1998 Pat Dirks Added MapFileOffset(), LogicalBlockSize() and UpdateBlockMappingTable() routines.
65 * 17-Sep-1998 Pat Dirks Changed BestBlockSizeFit to try MAXBSIZE and PAGE_SIZE first.
66 * 8-Sep-1998 Don Brady Fix CopyVNodeToCatalogNode to use h_mtime for contentModDate (instead of h_ctime).
67 * 4-Sep-1998 Pat Dirks Added BestBlockSizeFit routine.
68 * 18-Aug-1998 Don Brady Change DEBUG_BREAK_MSG to a DBG_UTILS in MacToVFSError (radar #2262802).
69 * 30-Jun-1998 Don Brady Add calls to MacToVFSError to hfs/hfsplus mount routines (for radar #2249539).
70 * 22-Jun-1998 Don Brady Add more error cases to MacToVFSError; all HFS Common errors are negative.
71 * Changed hfsDelete to call DeleteFile for files.
72 * 4-Jun-1998 Pat Dirks Changed incorrect references to 'vcbAlBlkSize' to 'blockSize';
73 * Added hfsCreateFileID.
74 * 4-Jun-1998 Don Brady Add hfsMoveRename to replace hfsMove and hfsRename. Use VPUT/VRELE macros
75 * instead of vput/vrele to catch bad ref counts.
76 * 28-May-1998 Pat Dirks Adjusted for change in definition of ATTR_CMN_NAME and removed ATTR_CMN_RAWDEVICE.
77 * 7-May-1998 Don Brady Added check for NULL vp to hfs_metafilelocking (radar #2233832).
78 * 24-Apr-1998 Pat Dirks Fixed AttributeBlockSize to return only length of variable attribute block.
79 * 4/21/1998 Don Brady Add SUPPORTS_MAC_ALIASES conditional (for radar #2225419).
80 * 4/21/1998 Don Brady Map cmNotEmpty errors to ENOTEMPTY (radar #2229259).
81 * 4/21/1998 Don Brady Fix up time/date conversions.
82 * 4/20/1998 Don Brady Remove course-grained hfs metadata locking.
83 * 4/18/1998 Don Brady Add VCB locking.
84 * 4/17/1998 Pat Dirks Fixed PackFileAttributeBlock to return more up-to-date EOF/PEOF info from vnode.
85 * 4/15/1998 Don Brady Add hasOverflowExtents and hfs_metafilelocking. Use ExtendBTreeFile instead
86 * of SetEndOfForkProc. Set forktype for system files.
87 * 4/14/1998 Deric Horn PackCatalogInfoAttributeBlock(), and related packing routines to
88 * pack attribute data given hfsCatalogInfo, without the objects vnode;
89 * 4/14/1998 Scott Roberts Add execute priviledges to all hfs objects.
90 * 4/9/1998 Don Brady Add MDB/VolumeHeader flushing to hfsUnmount;
91 * 4/8/1998 Don Brady Make sure vcbVRefNum field gets initialized (use MAKE_VREFNUM).
92 * 4/6/1998 Don Brady Removed calls to CreateVolumeCatalogCache (obsolete).
93 * 4/06/1998 Scott Roberts Added complex file support.
94 * 4/02/1998 Don Brady UpdateCatalogNode now takes parID and name as input.
95 * 3/31/1998 Don Brady Sync up with final HFSVolumes.h header file.
96 * 3/31/1998 Don Brady Check result from UFSToHFSStr to make sure hfs/hfs+ names are not greater
98 * 3/30/1998 Don Brady In InitMetaFileVNode set VSYSTEM bit in vnode's v_flag.
99 * 3/26/1998 Don Brady Cleaned up hfs_MountXXX routines. Removed CloseBtreeFile and OpenBTreeFile.
100 * Simplified hfsUnmount (removed MacOS specific code).
101 * 3/17/1998 Don Brady AttributeBlockSize calculation did not account for the size field (4bytes).
102 * PackVolCommonAttributes and PackCommonAttributeBlock for ATTR_CMN_NAME
103 * were not setting up the name correctly.
104 * 3/17/1998 Don Brady Changed CreateCatalogNode interface to take kCatalogFolderNode and
105 * kCatalogFileNode as type input. Also, force MountCheck to always run.
106 * 12-nov-1997 Scott Roberts Initially created file.
107 * 17-Mar-98 ser Broke out and created CopyCatalogToHFSNode()
110 #include <sys/param.h>
111 #include <sys/systm.h>
112 #include <sys/kernel.h>
113 #include <sys/malloc.h>
114 #include <sys/stat.h>
115 #include <sys/attr.h>
116 #include <sys/mount.h>
117 #include <sys/lock.h>
120 #include <sys/unistd.h>
124 #include "hfs_mount.h"
125 #include "hfs_endian.h"
127 #include "hfscommon/headers/FileMgrInternal.h"
128 #include "hfscommon/headers/BTreesInternal.h"
129 #include "hfscommon/headers/HFSUnicodeWrappers.h"
131 #define SUPPORTS_MAC_ALIASES 0
132 #define kMaxSecsForFsync 5
134 #define BYPASSBLOCKINGOPTIMIZATION 0
136 extern int (**hfs_vnodeop_p
)(void *);
137 extern int (**hfs_specop_p
)(void *);
138 extern int (**hfs_fifoop_p
)(void *);
139 extern int count_lock_queue
__P((void));
140 extern uid_t console_user
;
142 OSErr
ValidMasterDirectoryBlock( HFSMasterDirectoryBlock
*mdb
);
144 /* Externs from vhash */
145 extern void hfs_vhashins_sibling(dev_t dev
, UInt32 nodeID
, struct hfsnode
*hp
, struct hfsfilemeta
**fm
);
146 extern void hfs_vhashins(dev_t dev
, UInt32 nodeID
,struct hfsnode
*hp
);
147 extern struct vnode
*hfs_vhashget(dev_t dev
, UInt32 nodeID
, UInt8 forkType
);
149 extern int hfs_vinit( struct mount
*mntp
, int (**specops
)(void *), int (**fifoops
)(), struct vnode
**vpp
);
151 extern OSErr
GetVolumeNameFromCatalog(ExtendedVCB
*vcb
);
153 static int InitMetaFileVNode(struct vnode
*vp
, off_t eof
, u_long clumpSize
, const HFSPlusExtentRecord extents
,
154 HFSCatalogNodeID fileID
, void * keyCompareProc
);
156 static void ReleaseMetaFileVNode(struct vnode
*vp
);
158 static void RemovedMetaDataDirectory(ExtendedVCB
*vcb
);
160 void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
);
161 void CopyCatalogToFCB(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
);
162 void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
);
163 u_int32_t
GetLogicalBlockSize(struct vnode
*vp
);
165 /* BTree accessor routines */
166 extern OSStatus
GetBTreeBlock(FileReference vp
, UInt32 blockNum
, GetBlockOptions options
, BlockDescriptor
*block
);
167 extern OSStatus
SetBTreeBlockSize(FileReference vp
, ByteCount blockSize
, ItemCount minBlockCount
);
168 extern OSStatus
ExtendBTreeFile(FileReference vp
, FSSize minEOF
, FSSize maxEOF
);
169 extern OSStatus
ReleaseBTreeBlock(FileReference vp
, BlockDescPtr blockPtr
, ReleaseBlockOptions options
);
171 //*******************************************************************************
172 // Note: Finder information in the HFS/HFS+ metadata are considered opaque and
173 // hence are not in the right byte order on little endian machines. It is
174 // the responsibility of the finder and other clients to swap the data.
175 //*******************************************************************************
177 //*******************************************************************************
178 // Routine: hfs_MountHFSVolume
181 //*******************************************************************************
183 OSErr
hfs_MountHFSVolume(struct hfsmount
*hfsmp
, HFSMasterDirectoryBlock
*mdb
,
184 u_long sectors
, struct proc
*p
)
186 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
187 struct vnode
*tmpvnode
;
189 HFSPlusExtentRecord extents
;
191 DBG_FUNC_NAME("hfs_MountHFSVolume");
192 DBG_PRINT_FUNC_NAME();
194 if (hfsmp
== nil
|| mdb
== nil
) /* exit if bad paramater */
197 err
= ValidMasterDirectoryBlock( mdb
); /* make sure this is an HFS disk */
199 return MacToVFSError(err
);
201 /* don't mount a writeable volume if its dirty, it must be cleaned by fsck_hfs */
202 if ((hfsmp
->hfs_fs_ronly
== 0) && ((SWAP_BE16 (mdb
->drAtrb
) & kHFSVolumeUnmountedMask
) == 0))
206 * The MDB seems OK: transfer info from it into VCB
207 * Note - the VCB starts out clear (all zeros)
210 vcb
->vcbVRefNum
= MAKE_VREFNUM(hfsmp
->hfs_raw_dev
);
212 vcb
->vcbSigWord
= SWAP_BE16 (mdb
->drSigWord
);
213 vcb
->vcbCrDate
= LocalToUTC (SWAP_BE32 (mdb
->drCrDate
));
214 vcb
->localCreateDate
= SWAP_BE32 (mdb
->drCrDate
);
215 vcb
->vcbLsMod
= LocalToUTC (SWAP_BE32 (mdb
->drLsMod
));
216 vcb
->vcbAtrb
= SWAP_BE16 (mdb
->drAtrb
);
217 vcb
->vcbNmFls
= SWAP_BE16 (mdb
->drNmFls
);
218 vcb
->vcbVBMSt
= SWAP_BE16 (mdb
->drVBMSt
);
219 vcb
->nextAllocation
= SWAP_BE16 (mdb
->drAllocPtr
);
220 vcb
->totalBlocks
= SWAP_BE16 (mdb
->drNmAlBlks
);
221 vcb
->blockSize
= SWAP_BE32 (mdb
->drAlBlkSiz
);
222 vcb
->vcbClpSiz
= SWAP_BE32 (mdb
->drClpSiz
);
223 vcb
->vcbAlBlSt
= SWAP_BE16 (mdb
->drAlBlSt
);
224 vcb
->vcbNxtCNID
= SWAP_BE32 (mdb
->drNxtCNID
);
225 vcb
->freeBlocks
= SWAP_BE16 (mdb
->drFreeBks
);
226 vcb
->vcbVolBkUp
= LocalToUTC (SWAP_BE32 (mdb
->drVolBkUp
));
227 vcb
->vcbWrCnt
= SWAP_BE32 (mdb
->drWrCnt
);
228 vcb
->vcbNmRtDirs
= SWAP_BE16 (mdb
->drNmRtDirs
);
229 vcb
->vcbFilCnt
= SWAP_BE32 (mdb
->drFilCnt
);
230 vcb
->vcbDirCnt
= SWAP_BE32 (mdb
->drDirCnt
);
231 bcopy(mdb
->drFndrInfo
, vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
232 vcb
->nextAllocation
= SWAP_BE16 ( mdb
->drAllocPtr
); /* Duplicate?!?!?! */
233 vcb
->encodingsBitmap
= 0;
234 vcb
->vcbWrCnt
++; /* Compensate for write of MDB on last flush */
236 * Copy the drVN field, which is a Pascal String to the vcb, which is a cstring
239 /* convert hfs encoded name into UTF-8 string */
240 err
= hfs_to_utf8(vcb
, mdb
->drVN
, NAME_MAX
, &utf8chars
, vcb
->vcbVN
);
242 * When an HFS name cannot be encoded with the current
243 * volume encoding we use MacRoman as a fallback.
245 if (err
|| (utf8chars
== 0))
246 (void) mac_roman_to_utf8(mdb
->drVN
, NAME_MAX
, &utf8chars
, vcb
->vcbVN
);
248 vcb
->altIDSector
= sectors
- 2;
250 // Initialize our dirID/nodePtr cache associated with this volume.
251 err
= InitMRUCache( sizeof(UInt32
), kDefaultNumMRUCacheBlocks
, &(vcb
->hintCachePtr
) );
252 ReturnIfError( err
);
254 hfsmp
->hfs_logBlockSize
= BestBlockSizeFit(vcb
->blockSize
, MAXBSIZE
, hfsmp
->hfs_phys_block_size
);
255 vcb
->vcbVBMIOSize
= kHFSBlockSize
;
257 // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
261 * Set up Extents B-tree vnode...
263 err
= GetInitializedVNode(hfsmp
, &tmpvnode
);
264 if (err
) goto MtVolErr
;
265 /* HFSToHFSPlusExtents(mdb->drXTExtRec, extents); */ /* ASDFADSFSD */
266 extents
[0].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[0].startBlock
);
267 extents
[0].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[0].blockCount
);
268 extents
[1].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[1].startBlock
);
269 extents
[1].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[1].blockCount
);
270 extents
[2].startBlock
= SWAP_BE16 (mdb
->drXTExtRec
[2].startBlock
);
271 extents
[2].blockCount
= SWAP_BE16 (mdb
->drXTExtRec
[2].blockCount
);
273 err
= InitMetaFileVNode(tmpvnode
, SWAP_BE32 (mdb
->drXTFlSize
), SWAP_BE32 (mdb
->drXTClpSiz
), extents
,
274 kHFSExtentsFileID
, CompareExtentKeys
);
275 if (err
) goto MtVolErr
;
278 * Set up Catalog B-tree vnode...
280 err
= GetInitializedVNode(hfsmp
, &tmpvnode
);
281 if (err
) goto MtVolErr
;
282 /* HFSToHFSPlusExtents(mdb->drCTExtRec, extents); */
283 extents
[0].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[0].startBlock
);
284 extents
[0].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[0].blockCount
);
285 extents
[1].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[1].startBlock
);
286 extents
[1].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[1].blockCount
);
287 extents
[2].startBlock
= SWAP_BE16 (mdb
->drCTExtRec
[2].startBlock
);
288 extents
[2].blockCount
= SWAP_BE16 (mdb
->drCTExtRec
[2].blockCount
);
290 err
= InitMetaFileVNode(tmpvnode
, SWAP_BE32 (mdb
->drCTFlSize
), SWAP_BE32 (mdb
->drCTClpSiz
), extents
,
291 kHFSCatalogFileID
, CompareCatalogKeys
);
292 if (err
) goto MtVolErr
;
294 /* mark the volume dirty (clear clean unmount bit) */
295 vcb
->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
297 /* Remove any MetaDataDirectory from hfs disks */
298 if (hfsmp
->hfs_fs_ronly
== 0)
299 RemovedMetaDataDirectory(vcb
);
302 * all done with b-trees so we can unlock now...
304 VOP_UNLOCK(vcb
->catalogRefNum
, 0, p
);
305 VOP_UNLOCK(vcb
->extentsRefNum
, 0, p
);
311 if ( !(vcb
->vcbAtrb
& kHFSVolumeHardwareLockMask
) ) // if the disk is not write protected
313 MarkVCBDirty( vcb
); // mark VCB dirty so it will be written
318 //-- Release any resources allocated so far before exiting with an error:
320 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
321 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
327 //*******************************************************************************
328 // Routine: hfs_MountHFSPlusVolume
331 //*******************************************************************************
333 OSErr
hfs_MountHFSPlusVolume(struct hfsmount
*hfsmp
, HFSPlusVolumeHeader
*vhp
,
334 u_long embBlkOffset
, u_long sectors
, struct proc
*p
)
336 register ExtendedVCB
*vcb
;
337 HFSPlusForkData
*fdp
;
338 struct vnode
*tmpvnode
;
341 if (hfsmp
== nil
|| vhp
== nil
) /* exit if bad paramater */
344 DBG_VFS(("hfs_MountHFSPlusVolume: signature=0x%x, version=%d, blockSize=%ld\n",
345 SWAP_BE16 (vhp
->signature
),
346 SWAP_BE16 (vhp
->version
),
347 SWAP_BE32 (vhp
->blockSize
)));
349 retval
= ValidVolumeHeader(vhp
); /* make sure this is an HFS Plus disk */
351 return MacToVFSError(retval
);
353 /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */
354 if (hfsmp
->hfs_fs_ronly
== 0 && (SWAP_BE32 (vhp
->attributes
) & kHFSVolumeUnmountedMask
) == 0)
357 * The VolumeHeader seems OK: transfer info from it into VCB
358 * Note - the VCB starts out clear (all zeros)
360 vcb
= HFSTOVCB(hfsmp
);
362 //DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0);
363 vcb
->vcbVRefNum
= MAKE_VREFNUM(hfsmp
->hfs_raw_dev
);
364 vcb
->vcbSigWord
= SWAP_BE16 (vhp
->signature
);
365 vcb
->vcbLsMod
= SWAP_BE32 (vhp
->modifyDate
);
366 vcb
->vcbAtrb
= (UInt16
) SWAP_BE32 (vhp
->attributes
); // VCB only uses lower 16 bits
367 vcb
->vcbClpSiz
= SWAP_BE32 (vhp
->rsrcClumpSize
);
368 vcb
->vcbNxtCNID
= SWAP_BE32 (vhp
->nextCatalogID
);
369 vcb
->vcbVolBkUp
= SWAP_BE32 (vhp
->backupDate
);
370 vcb
->vcbWrCnt
= SWAP_BE32 (vhp
->writeCount
);
371 vcb
->vcbFilCnt
= SWAP_BE32 (vhp
->fileCount
);
372 vcb
->vcbDirCnt
= SWAP_BE32 (vhp
->folderCount
);
374 /* copy 32 bytes of Finder info */
375 bcopy(vhp
->finderInfo
, vcb
->vcbFndrInfo
, sizeof(vhp
->finderInfo
));
377 vcb
->vcbAlBlSt
= 0; /* hfs+ allocation blocks start at first block of volume */
378 vcb
->vcbWrCnt
++; /* compensate for write of Volume Header on last flush */
382 /* Now fill in the Extended VCB info */
383 vcb
->nextAllocation
= SWAP_BE32 (vhp
->nextAllocation
);
384 vcb
->totalBlocks
= SWAP_BE32 (vhp
->totalBlocks
);
385 vcb
->freeBlocks
= SWAP_BE32 (vhp
->freeBlocks
);
386 vcb
->blockSize
= SWAP_BE32 (vhp
->blockSize
);
387 vcb
->checkedDate
= SWAP_BE32 (vhp
->checkedDate
);
388 vcb
->encodingsBitmap
= SWAP_BE64 (vhp
->encodingsBitmap
);
390 vcb
->hfsPlusIOPosOffset
= embBlkOffset
* 512;
392 vcb
->altIDSector
= embBlkOffset
+ sectors
- 2;
394 vcb
->localCreateDate
= SWAP_BE32 (vhp
->createDate
); /* in local time, not GMT! */
396 /* Update the logical block size in the mount struct (currently set up from the wrapper MDB)
397 using the new blocksize value: */
398 hfsmp
->hfs_logBlockSize
= BestBlockSizeFit(vcb
->blockSize
, MAXBSIZE
, hfsmp
->hfs_phys_block_size
);
399 vcb
->vcbVBMIOSize
= min(vcb
->blockSize
, MAXPHYSIO
);
401 // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
402 // vcb->vcbAtrb |= kVolumeHardwareLockMask; // XXX this line for debugging only!!!!
404 // Initialize our dirID/nodePtr cache associated with this volume.
405 retval
= InitMRUCache( sizeof(UInt32
), kDefaultNumMRUCacheBlocks
, &(vcb
->hintCachePtr
) );
406 if (retval
!= noErr
) goto ErrorExit
;
409 * Set up Extents B-tree vnode...
411 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
);
412 if (retval
) goto ErrorExit
;
413 fdp
= &vhp
->extentsFile
;
414 SWAP_HFS_PLUS_FORK_DATA (fdp
);
415 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
416 kHFSExtentsFileID
, CompareExtentKeysPlus
);
417 SWAP_HFS_PLUS_FORK_DATA (fdp
);
418 if (retval
) goto ErrorExit
;
421 * Set up Catalog B-tree vnode...
423 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
);
424 if (retval
) goto ErrorExit
;
425 fdp
= &vhp
->catalogFile
;
426 SWAP_HFS_PLUS_FORK_DATA (fdp
);
427 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
428 kHFSCatalogFileID
, CompareExtendedCatalogKeys
);
429 SWAP_HFS_PLUS_FORK_DATA (fdp
);
430 if (retval
) goto ErrorExit
;
433 * Set up Allocation file vnode...
435 retval
= GetInitializedVNode(hfsmp
, &tmpvnode
);
436 if (retval
) goto ErrorExit
;
437 fdp
= &vhp
->allocationFile
;
438 SWAP_HFS_PLUS_FORK_DATA (fdp
);
439 retval
= InitMetaFileVNode(tmpvnode
, fdp
->logicalSize
, fdp
->clumpSize
, fdp
->extents
,
440 kHFSAllocationFileID
, NULL
);
441 SWAP_HFS_PLUS_FORK_DATA (fdp
);
442 if (retval
) goto ErrorExit
;
445 * Now that Catalog file is open get the volume name from the catalog
447 retval
= MacToVFSError( GetVolumeNameFromCatalog(vcb
) );
448 if (retval
!= noErr
) goto ErrorExit
;
450 /* mark the volume dirty (clear clean unmount bit) */
451 vcb
->vcbAtrb
&= ~kHFSVolumeUnmountedMask
;
453 /* setup private/hidden directory for unlinked files */
454 hfsmp
->hfs_private_metadata_dir
= FindMetaDataDirectory(vcb
);
457 * all done with metadata files so we can unlock now...
459 VOP_UNLOCK(vcb
->allocationsRefNum
, 0, p
);
460 VOP_UNLOCK(vcb
->catalogRefNum
, 0, p
);
461 VOP_UNLOCK(vcb
->extentsRefNum
, 0, p
);
463 if ( !(vcb
->vcbAtrb
& kHFSVolumeHardwareLockMask
) ) // if the disk is not write protected
465 MarkVCBDirty( vcb
); // mark VCB dirty so it will be written
468 DBG_VFS(("hfs_MountHFSPlusVolume: returning (%d)\n", retval
));
475 * A fatal error occured and the volume cannot be mounted
476 * release any resources that we aquired...
479 DBG_VFS(("hfs_MountHFSPlusVolume: fatal error (%d)\n", retval
));
481 InvalidateCatalogCache(vcb
);
483 ReleaseMetaFileVNode(vcb
->allocationsRefNum
);
484 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
485 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
492 * ReleaseMetaFileVNode
496 static void ReleaseMetaFileVNode(struct vnode
*vp
)
500 FCB
*fcb
= VTOFCB(vp
);
502 if (fcb
->fcbBTCBPtr
!= NULL
)
503 (void) BTClosePath(fcb
); /* ignore errors since there is only one path open */
505 /* release the node even if BTClosePath fails */
506 if (VOP_ISLOCKED(vp
))
519 static int InitMetaFileVNode(struct vnode
*vp
, off_t eof
, u_long clumpSize
, const HFSPlusExtentRecord extents
,
520 HFSCatalogNodeID fileID
, void * keyCompareProc
)
526 DBG_ASSERT(vp
!= NULL
);
527 DBG_ASSERT(vp
->v_data
!= NULL
);
534 case kHFSExtentsFileID
:
535 vcb
->extentsRefNum
= vp
;
538 case kHFSCatalogFileID
:
539 vcb
->catalogRefNum
= vp
;
542 case kHFSAllocationFileID
:
543 vcb
->allocationsRefNum
= vp
;
547 panic("InitMetaFileVNode: invalid fileID!");
552 fcb
->fcbClmpSize
= clumpSize
;
553 H_FILEID(VTOH(vp
)) = fileID
;
554 H_DIRID(VTOH(vp
)) = kHFSRootParentID
;
555 H_FORKTYPE(VTOH(vp
)) = kSysFile
;
557 bcopy(extents
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
560 * Lock the hfsnode and insert the hfsnode into the hash queue:
562 hfs_vhashins(H_DEV(VTOH(vp
)), fileID
, VTOH(vp
));
563 vp
->v_flag
|= VSYSTEM
; /* tag our metadata files (used by vflush call) */
565 /* As the vnode is a system vnode we don't need UBC */
566 if(UBCINFOEXISTS(vp
)) {
567 /* So something is wrong if the it exists */
568 panic("ubc exists for system vnode");
571 if (keyCompareProc
!= NULL
) {
572 result
= BTOpenPath(fcb
,
573 (KeyCompareProcPtr
) keyCompareProc
,
578 result
= MacToVFSError(result
);
585 /*************************************************************
587 * Unmounts a hfs volume.
588 * At this point vflush() has been called (to dump all non-metadata files)
590 *************************************************************/
592 short hfsUnmount( register struct hfsmount
*hfsmp
, struct proc
*p
)
594 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
597 (void) DisposeMRUCache(vcb
->hintCachePtr
);
598 InvalidateCatalogCache( vcb
);
599 // XXX PPD: Should dispose of any allocated volume cache here: call DisposeVolumeCacheBlocks( vcb )?
601 (void) hfs_metafilelocking(hfsmp
, kHFSCatalogFileID
, LK_EXCLUSIVE
, p
);
602 (void) hfs_metafilelocking(hfsmp
, kHFSExtentsFileID
, LK_EXCLUSIVE
, p
);
604 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
605 ReleaseMetaFileVNode(vcb
->allocationsRefNum
);
607 ReleaseMetaFileVNode(vcb
->catalogRefNum
);
608 ReleaseMetaFileVNode(vcb
->extentsRefNum
);
615 * hfs_resolvelink - auto resolve HFS+ hardlinks
617 * Used after calling GetCatalogNode or GetCatalogOffspring
619 void hfs_resolvelink(ExtendedVCB
*vcb
, CatalogNodeData
*cndp
)
625 UInt32 linkparid
, linkcnid
;
628 fip
= (struct FInfo
*) &cndp
->cnd_finderInfo
;
631 * if this is an indirect link (hardlink) then auto resolve it...
633 if ((vcb
->vcbSigWord
== kHFSPlusSigWord
)
634 && (cndp
->cnd_type
== kCatalogFileNode
)
635 && (fip
->fdType
== kHardLinkFileType
)
636 && (fip
->fdCreator
== kHFSPlusCreator
)
637 && ((cndp
->cnd_createDate
== vcb
->vcbCrDate
) ||
638 (cndp
->cnd_createDate
== VCBTOHFS(vcb
)->hfs_metadata_createdate
))) {
640 indlinkno
= cndp
->cnd_iNodeNum
;
641 MAKE_INODE_NAME(iNodeName
, indlinkno
);
643 * Get nodeData from the data node file.
644 * Flag the node data to NOT copy the name (ie preserve the original)
645 * Also preserve the parent directory ID.
647 linkparid
= cndp
->cnm_parID
;
648 linkcnid
= cndp
->cnd_nodeID
;
649 cndp
->cnm_flags
|= kCatNameNoCopyName
;
650 result
= GetCatalogNode(vcb
, VCBTOHFS(vcb
)->hfs_private_metadata_dir
,
651 iNodeName
, 0, 0, cndp
, &hint
);
652 cndp
->cnm_flags
&= ~kCatNameNoCopyName
;
654 /* Make sure there's a reference */
656 if (cndp
->cnd_linkCount
== 0) cndp
->cnd_linkCount
= 2;
658 /* Keep a copy of iNodeNum to put into h_indnodeno */
659 cndp
->cnd_iNodeNumCopy
= indlinkno
;
660 cndp
->cnm_parID
= linkparid
;
661 cndp
->cnd_linkCNID
= linkcnid
;
668 * Performs a lookup on the given dirID, name. Returns the catalog info
670 * If len is -1, then it is a null terminated string, pass it along to MacOS as kUndefinedStrLen
673 short hfs_getcatalog (ExtendedVCB
*vcb
, UInt32 parentDirID
, char *name
, short len
, hfsCatalogInfo
*catInfo
)
678 if (len
== -1 ) { /* Convert it to MacOS terms */
680 length
= strlen(name
);
682 length
= kUndefinedStrLen
;
687 result
= GetCatalogNode(vcb
, parentDirID
, name
, length
, catInfo
->hint
, &catInfo
->nodeData
, &catInfo
->hint
);
690 if (catInfo
->nodeData
.cnm_nameptr
) {
691 DBG_ASSERT(strlen(catInfo
->nodeData
.cnm_nameptr
) == catInfo
->nodeData
.cnm_length
);
696 hfs_resolvelink(vcb
, &catInfo
->nodeData
);
698 return MacToVFSError(result
);
703 short hfsDelete (ExtendedVCB
*vcb
, UInt32 parentDirID
, StringPtr name
, short isfile
, UInt32 catalogHint
)
705 OSErr result
= noErr
;
707 /* XXX have all the file's blocks been flushed/trashed? */
710 * DeleteFile will delete the catalog node and then
711 * free up any disk space used by the file.
714 result
= DeleteFile(vcb
, parentDirID
, name
, catalogHint
);
715 else /* is a directory */
716 result
= DeleteCatalogNode(vcb
, parentDirID
, name
, catalogHint
);
719 DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result
, parentDirID
, name
));
721 return MacToVFSError(result
);
725 short hfsMoveRename (ExtendedVCB
*vcb
, UInt32 oldDirID
, char *oldName
, UInt32 newDirID
, char *newName
, UInt32
*hint
)
727 OSErr result
= noErr
;
729 result
= MoveRenameCatalogNode(vcb
, oldDirID
,oldName
, *hint
, newDirID
, newName
, hint
, 0);
732 DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result
, newDirID
, newName
));
735 return MacToVFSError(result
);
738 /* XXX SER pass back the hint so other people can use it */
741 short hfsCreate(ExtendedVCB
*vcb
, UInt32 dirID
, char *name
, int mode
, UInt32 tehint
)
743 OSErr result
= noErr
;
744 HFSCatalogNodeID catalogNodeID
;
748 /* just test for directories, the default is to create a file (like symlinks) */
749 if ((mode
& IFMT
) == IFDIR
)
750 type
= kCatalogFolderNode
;
752 type
= kCatalogFileNode
;
754 result
= CreateCatalogNode (vcb
, dirID
, name
, type
, &catalogNodeID
, &catalogHint
, tehint
);
756 return MacToVFSError(result
);
760 short hfsCreateFileID (ExtendedVCB
*vcb
, UInt32 parentDirID
, StringPtr name
, UInt32 catalogHint
, UInt32
*fileIDPtr
)
762 return MacToVFSError(CreateFileIDRef(vcb
, parentDirID
, name
, catalogHint
, fileIDPtr
));
766 /********************************************************************************/
768 /* hfs_vget_catinfo - Returns a vnode derived from a hfs catInfo struct */
770 /********************************************************************************/
772 int hfs_vget_catinfo(struct vnode
*parent_vp
, struct hfsCatalogInfo
*catInfo
, u_int32_t forkType
, struct vnode
**target_vp
)
776 if (forkType
== kDefault
) {
777 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
)
778 forkType
= kDirectory
;
780 forkType
= kDataFork
;
783 *target_vp
= hfs_vhashget(H_DEV(VTOH(parent_vp
)), catInfo
->nodeData
.cnd_nodeID
, forkType
);
785 if (*target_vp
== NULL
)
786 retval
= hfs_vcreate( VTOVCB(parent_vp
), catInfo
, forkType
, target_vp
);
793 /************************************************************************/
794 /* hfs_vcreate - Returns a vnode derived from hfs */
796 /* When creating the vnode, care must be made to set the */
797 /* correct fields in the correct order. Calls to malloc() */
798 /* and other subroutines, can cause a context switch, */
799 /* and the fields must be ready for the possibility */
802 /************************************************************************/
804 short hfs_vcreate(ExtendedVCB
*vcb
, hfsCatalogInfo
*catInfo
, UInt8 forkType
, struct vnode
**vpp
)
808 struct hfsmount
*hfsmp
;
809 struct hfsfilemeta
*fm
;
816 DBG_ASSERT(vcb
!= NULL
);
817 DBG_ASSERT(catInfo
!= NULL
);
818 DBG_ASSERT(vpp
!= NULL
);
819 DBG_ASSERT((forkType
== kDirectory
) || (forkType
== kDataFork
) || (forkType
== kRsrcFork
));
820 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) {
821 DBG_ASSERT(forkType
== kDirectory
);
823 DBG_ASSERT(forkType
!= kDirectory
);
827 if ( ! ((forkType
== kDirectory
) || (forkType
== kDataFork
) || (forkType
== kRsrcFork
)))
828 panic("Bad fork type");
829 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) {
830 if (forkType
!= kDirectory
)
831 panic("non directory type");
833 if (forkType
!= kDataFork
&& forkType
!= kRsrcFork
)
834 panic("non fork type");
837 hfsmp
= VCBTOHFS(vcb
);
838 mp
= HFSTOVFS(hfsmp
);
839 dev
= hfsmp
->hfs_raw_dev
;
841 /* Check if unmount in progress */
842 if (mp
->mnt_kern_flag
& MNTK_UNMOUNT
) {
848 * If this is a hard link then check if the
849 * data node already exists in our hash.
851 if ((forkType
== kDataFork
)
852 && (catInfo
->nodeData
.cnd_type
== kCatalogFileNode
)
853 && ((catInfo
->nodeData
.cnd_mode
& IFMT
) == IFREG
)
854 && (catInfo
->nodeData
.cnd_linkCount
> 0)) {
855 vp
= hfs_vhashget(dev
, catInfo
->nodeData
.cnd_nodeID
, kDataFork
);
857 /* Use the name of the link and it's parent ID. */
859 H_DIRID(hp
) = catInfo
->nodeData
.cnm_parID
;
860 hfs_set_metaname(catInfo
->nodeData
.cnm_nameptr
, hp
->h_meta
, hfsmp
);
866 /* Must malloc() here, since getnewvnode() can sleep */
867 MALLOC_ZONE(hp
, struct hfsnode
*, sizeof(struct hfsnode
), M_HFSNODE
, M_WAITOK
);
868 bzero((caddr_t
)hp
, sizeof(struct hfsnode
));
871 * Set that this node is in the process of being allocated
872 * Set it as soon as possible, so context switches well always hit upon it.
873 * if this is set then wakeup() MUST be called on hp after the flag is cleared
874 * DO NOT exit without clearing and waking up !!!!
876 hp
->h_nodeflags
|= IN_ALLOCATING
; /* Mark this as being allocating */
877 lockinit(&hp
->h_lock
, PINOD
, "hfsnode", 0, 0);
880 /* getnewvnode() does a VREF() on the vnode */
881 /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
882 if ((retval
= getnewvnode(VT_HFS
, mp
, hfs_vnodeop_p
, &vp
))) {
883 wakeup(hp
); /* Shouldnt happen, but just to make sure */
884 FREE_ZONE(hp
, sizeof(struct hfsnode
), M_HFSNODE
);
890 * Set the essentials before locking it down
892 hp
->h_vp
= vp
; /* Make HFSTOV work */
893 vp
->v_data
= hp
; /* Make VTOH work */
894 H_FORKTYPE(hp
) = forkType
;
895 rl_init(&hp
->h_invalidranges
);
899 * Lock the hfsnode and insert the hfsnode into the hash queue, also if meta exists
900 * add to sibling list and return the meta address
902 if (SIBLING_FORKTYPE(forkType
))
903 hfs_vhashins_sibling(dev
, catInfo
->nodeData
.cnd_nodeID
, hp
, &fm
);
905 hfs_vhashins(dev
, catInfo
->nodeData
.cnd_nodeID
, hp
);
908 * If needed allocate and init the object meta data:
911 /* Allocate it....remember we can do a context switch here */
912 MALLOC_ZONE(fm
, struct hfsfilemeta
*, sizeof(struct hfsfilemeta
), M_HFSFMETA
, M_WAITOK
);
913 bzero(fm
, sizeof(struct hfsfilemeta
));
917 * NOTICE: XXX Even though we have added the vnode to the hash so it is alive on TWO
918 * accessable lists, we do not assign it until later,
919 * this helps to make sure we do not use a half initiated meta
922 /* Init the sibling list if needed */
923 if (SIBLING_FORKTYPE(forkType
)) {
924 simple_lock_init(&fm
->h_siblinglock
);
925 CIRCLEQ_INIT(&fm
->h_siblinghead
);
926 CIRCLEQ_INSERT_HEAD(&fm
->h_siblinghead
, hp
, h_sibling
);
930 CopyCatalogToObjectMeta(catInfo
, vp
, fm
);
933 * the vnode is finally alive, with the exception of the FCB below,
934 * It is finally locked and ready for its debutante ball
942 * Init the File Control Block.
944 CopyCatalogToFCB(catInfo
, vp
);
947 * Finish vnode initialization.
948 * Setting the v_type 'stamps' the vnode as 'complete', so should be done almost last.
950 * At this point the vnode should be locked and fully allocated. And ready to be used
951 * or accessed. (though having it locked prevents most of this, it
952 * can still be accessed through lists and hashs).
954 vp
->v_type
= IFTOVT(hp
->h_meta
->h_mode
);
955 if ((vp
->v_type
== VREG
)
956 && (UBCINFOMISSING(vp
) || UBCINFORECLAIMED(vp
))) {
961 * Initialize the vnode from the inode, check for aliases, sets the VROOT flag.
962 * Note that the underlying vnode may have changed.
964 if ((retval
= hfs_vinit(mp
, hfs_specop_p
, hfs_fifoop_p
, &vp
))) {
972 * Finish inode initialization now that aliasing has been resolved.
974 hp
->h_meta
->h_devvp
= hfsmp
->hfs_devvp
;
975 VREF(hp
->h_meta
->h_devvp
);
978 hp
->h_valid
= HFS_VNODE_MAGIC
;
980 hp
->h_nodeflags
&= ~IN_ALLOCATING
; /* vnode is completely initialized */
982 /* Wake up anybody waiting for us to finish..see hfs_vhash.c */
987 /* Lets do some testing here */
988 DBG_ASSERT(hp
->h_meta
);
989 DBG_ASSERT(VTOH(vp
)==hp
);
990 DBG_ASSERT(HTOV(hp
)==vp
);
991 DBG_ASSERT(hp
->h_meta
->h_usecount
>=1 && hp
->h_meta
->h_usecount
<=2);
992 if (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) {
993 DBG_ASSERT(vp
->v_type
== VDIR
);
994 DBG_ASSERT(H_FORKTYPE(VTOH(vp
)) == kDirectory
);
996 #endif // HFS_DIAGNOSTIC
1004 void CopyCatalogToObjectMeta(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
, struct hfsfilemeta
*fm
)
1006 ExtendedVCB
*vcb
= VTOVCB(vp
);
1007 struct mount
*mp
= VTOVFS(vp
);
1008 Boolean isHFSPlus
, isDirectory
;
1012 DBG_ASSERT (fm
!= NULL
);
1013 DBG_ASSERT (fm
->h_namelen
== 0);
1014 DBG_ASSERT (fm
->h_namePtr
== 0);
1016 DBG_UTILS(("\tCopying to file's meta data: name:%s, nodeid:%ld\n", catalogInfo
->nodeData
.cnm_nameptr
, catalogInfo
->nodeData
.cnd_nodeID
));
1018 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1019 isDirectory
= (catalogInfo
->nodeData
.cnd_type
== kCatalogFolderNode
);
1020 finderFlags
= SWAP_BE16 (((struct FInfo
*)(&catalogInfo
->nodeData
.cnd_finderInfo
))->fdFlags
);
1022 /* Copy over the dirid, and hint */
1023 fm
->h_nodeID
= catalogInfo
->nodeData
.cnd_nodeID
;
1024 fm
->h_dirID
= catalogInfo
->nodeData
.cnm_parID
;
1025 fm
->h_hint
= catalogInfo
->hint
;
1027 /* Copy over the name */
1028 hfs_name_CatToMeta(&catalogInfo
->nodeData
, fm
);
1031 /* get dates in BSD format */
1032 fm
->h_mtime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1033 fm
->h_crtime
= to_bsd_time(catalogInfo
->nodeData
.cnd_createDate
);
1034 fm
->h_butime
= to_bsd_time(catalogInfo
->nodeData
.cnd_backupDate
);
1036 fm
->h_atime
= to_bsd_time(catalogInfo
->nodeData
.cnd_accessDate
);
1037 fm
->h_ctime
= to_bsd_time(catalogInfo
->nodeData
.cnd_attributeModDate
);
1040 fm
->h_atime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1041 fm
->h_ctime
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
1045 if (isHFSPlus
&& (catalogInfo
->nodeData
.cnd_mode
& IFMT
)) {
1046 fm
->h_uid
= catalogInfo
->nodeData
.cnd_ownerID
;
1047 fm
->h_gid
= catalogInfo
->nodeData
.cnd_groupID
;
1048 fm
->h_pflags
= catalogInfo
->nodeData
.cnd_ownerFlags
|
1049 (catalogInfo
->nodeData
.cnd_adminFlags
<< 16);
1050 fm
->h_mode
= (mode_t
)catalogInfo
->nodeData
.cnd_mode
;
1052 if (fm
->h_uid
== 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1053 fm
->h_uid
= UNKNOWNUID
;
1054 fm
->h_metaflags
|= IN_CHANGE
;
1055 vcb
->vcbFlags
|= kHFS_DamagedVolume
; /* Trigger fsck on next mount */
1057 if (fm
->h_gid
== 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1058 fm
->h_gid
= UNKNOWNGID
;
1059 fm
->h_metaflags
|= IN_CHANGE
;
1060 vcb
->vcbFlags
|= kHFS_DamagedVolume
; /* Trigger fsck on next mount */
1063 filetype
= fm
->h_mode
& IFMT
;
1064 if (filetype
== IFCHR
|| filetype
== IFBLK
)
1065 fm
->h_rdev
= catalogInfo
->nodeData
.cnd_rawDevice
;
1069 if (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
&&
1070 catalogInfo
->nodeData
.cnd_linkCount
> 0) {
1071 fm
->h_nlink
= catalogInfo
->nodeData
.cnd_linkCount
;
1072 fm
->h_indnodeno
= catalogInfo
->nodeData
.cnd_iNodeNumCopy
;
1073 fm
->h_metaflags
|= IN_DATANODE
;
1078 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1080 * Override the permissions as determined by the mount auguments
1081 * in ALMOST the same way unset permissions are treated but keep
1082 * track of whether or not the file or folder is hfs locked
1083 * by leaving the h_pflags field unchanged from what was unpacked
1084 * out of the catalog.
1086 fm
->h_metaflags
|= IN_UNSETACCESS
;
1087 fm
->h_uid
= VTOHFS(vp
)->hfs_uid
;
1088 fm
->h_gid
= VTOHFS(vp
)->hfs_gid
;
1089 #if OVERRIDE_UNKNOWN_PERMISSIONS
1090 /* Default access is full read/write/execute: */
1091 /* XXX won't this smash IFCHR, IFBLK and IFLNK (for no-follow lookups)? */
1092 fm
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
1095 /* ... but no more than that permitted by the mount point's: */
1097 fm
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
1100 fm
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
1104 fm
->h_mode
|= IFDIR
;
1105 else if (SUPPORTS_MAC_ALIASES
&& (finderFlags
& kIsAlias
)) /* aliases will be symlinks in the future */
1106 fm
->h_mode
|= IFLNK
;
1108 fm
->h_mode
|= IFREG
;
1113 * Set the permissions as determined by the mount auguments
1114 * but keep in account if the file or folder is hfs locked
1116 fm
->h_metaflags
|= IN_UNSETACCESS
;
1117 fm
->h_uid
= VTOHFS(vp
)->hfs_uid
;
1118 fm
->h_gid
= VTOHFS(vp
)->hfs_gid
;
1119 fm
->h_pflags
= 0; /* No valid pflags on disk (IMMUTABLE is synced from lock flag later) */
1120 fm
->h_rdev
= 0; /* No valid rdev on disk */
1121 /* Default access is full read/write/execute: */
1122 fm
->h_mode
= ACCESSPERMS
; /* 0777: rwxrwxrwx */
1124 /* ... but no more than that permitted by the mount point's: */
1126 fm
->h_mode
&= VTOHFS(vp
)->hfs_dir_mask
;
1129 fm
->h_mode
&= VTOHFS(vp
)->hfs_file_mask
;
1133 fm
->h_mode
|= IFDIR
;
1134 else if (SUPPORTS_MAC_ALIASES
&& (finderFlags
& kIsAlias
)) /* aliases will be symlinks in the future */
1135 fm
->h_mode
|= IFLNK
;
1137 fm
->h_mode
|= IFREG
;
1140 /* Make sure that there is no nodeType/mode mismatch */
1141 if (isDirectory
&& ((fm
->h_mode
& IFMT
) != IFDIR
)) {
1142 fm
->h_mode
&= ~IFMT
; /* Clear the bad bits */
1143 fm
->h_mode
|= IFDIR
; /* Set the proper one */
1146 /* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */
1148 if (catalogInfo
->nodeData
.cnd_flags
& kHFSFileLockedMask
) {
1149 /* The file's supposed to be locked:
1150 Make sure at least one of the IMMUTABLE bits is set: */
1151 if ((fm
->h_pflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
)) == 0) {
1152 fm
->h_pflags
|= UF_IMMUTABLE
; /* Set the user-changable IMMUTABLE bit */
1155 /* The file's supposed to be unlocked: */
1156 fm
->h_pflags
&= ~(SF_IMMUTABLE
| UF_IMMUTABLE
);
1161 fm
->h_nlink
= 2 + catalogInfo
->nodeData
.cnd_valence
;
1162 fm
->h_size
= (2 * sizeof(hfsdotentry
)) +
1163 (catalogInfo
->nodeData
.cnd_valence
* AVERAGE_HFSDIRENTRY_SIZE
);
1164 if (fm
->h_size
< MAX_HFSDIRENTRY_SIZE
)
1165 fm
->h_size
= MAX_HFSDIRENTRY_SIZE
;
1167 fm
->h_size
= (off_t
)vcb
->blockSize
*
1168 (off_t
)(catalogInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
+
1169 catalogInfo
->nodeData
.cnd_datafork
.totalBlocks
);
1174 void CopyCatalogToFCB(struct hfsCatalogInfo
*catalogInfo
, struct vnode
*vp
)
1176 FCB
*fcb
= VTOFCB(vp
);
1177 ExtendedVCB
*vcb
= VTOVCB(vp
);
1178 Boolean isHFSPlus
, isDirectory
, isResource
;
1179 HFSPlusExtentDescriptor
*extents
;
1182 DBG_ASSERT (vp
!= NULL
);
1183 DBG_ASSERT (fcb
!= NULL
);
1184 DBG_ASSERT (vcb
!= NULL
);
1185 DBG_ASSERT (VTOH(vp
) != NULL
);
1187 forkType
= H_FORKTYPE(VTOH(vp
));
1188 isResource
= (forkType
== kRsrcFork
);
1189 isDirectory
= (catalogInfo
->nodeData
.cnd_type
== kCatalogFolderNode
);
1190 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1193 fcb
->fcbFlags
= catalogInfo
->nodeData
.cnd_flags
;
1195 if (forkType
!= kDirectory
) {
1196 fcb
->fcbFlags
&= kHFSFileLockedMask
; /* Clear resource, dirty bits */
1197 if (fcb
->fcbFlags
!= 0) /* if clear, its not locked, then.. */
1198 fcb
->fcbFlags
= fcbFileLockedMask
; /* duplicate the bit for later use */
1200 fcb
->fcbClmpSize
= vcb
->vcbClpSiz
; /*XXX why not use the one in catalogInfo? */
1203 extents
= catalogInfo
->nodeData
.cnd_rsrcfork
.extents
;
1205 extents
= catalogInfo
->nodeData
.cnd_datafork
.extents
;
1207 /* Copy the extents to their correct location: */
1208 bcopy (extents
, fcb
->fcbExtents
, sizeof(HFSPlusExtentRecord
));
1211 fcb
->fcbEOF
= catalogInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
1212 fcb
->fcbPLen
= (off_t
)((off_t
)catalogInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
1213 fcb
->fcbFlags
|= fcbResourceMask
;
1215 fcb
->fcbEOF
= catalogInfo
->nodeData
.cnd_datafork
.logicalSize
;
1216 fcb
->fcbPLen
= (off_t
)((off_t
)catalogInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
1223 int hasOverflowExtents(struct hfsnode
*hp
)
1225 ExtendedVCB
*vcb
= HTOVCB(hp
);
1226 FCB
*fcb
= HTOFCB(hp
);
1229 if (vcb
->vcbSigWord
== kHFSPlusSigWord
)
1232 if (fcb
->fcbExtents
[7].blockCount
== 0)
1235 blocks
= fcb
->fcbExtents
[0].blockCount
+
1236 fcb
->fcbExtents
[1].blockCount
+
1237 fcb
->fcbExtents
[2].blockCount
+
1238 fcb
->fcbExtents
[3].blockCount
+
1239 fcb
->fcbExtents
[4].blockCount
+
1240 fcb
->fcbExtents
[5].blockCount
+
1241 fcb
->fcbExtents
[6].blockCount
+
1242 fcb
->fcbExtents
[7].blockCount
;
1246 if (fcb
->fcbExtents
[2].blockCount
== 0)
1249 blocks
= fcb
->fcbExtents
[0].blockCount
+
1250 fcb
->fcbExtents
[1].blockCount
+
1251 fcb
->fcbExtents
[2].blockCount
;
1254 return ((fcb
->fcbPLen
/ vcb
->blockSize
) > blocks
);
1258 int hfs_metafilelocking(struct hfsmount
*hfsmp
, u_long fileID
, u_int flags
, struct proc
*p
)
1261 struct vnode
*vp
= NULL
;
1262 int numOfLockedBuffs
;
1265 vcb
= HFSTOVCB(hfsmp
);
1267 DBG_UTILS(("hfs_metafilelocking: vol: %d, file: %d %s%s%s\n", vcb
->vcbVRefNum
, fileID
,
1268 ((flags
& LK_TYPE_MASK
) == LK_RELEASE
? "RELEASE" : ""),
1269 ((flags
& LK_TYPE_MASK
) == LK_EXCLUSIVE
? "EXCLUSIVE" : ""),
1270 ((flags
& LK_TYPE_MASK
) == LK_SHARED
? "SHARED" : "") ));
1275 case kHFSExtentsFileID
:
1276 vp
= vcb
->extentsRefNum
;
1279 case kHFSCatalogFileID
:
1280 vp
= vcb
->catalogRefNum
;
1283 case kHFSAllocationFileID
:
1284 /* bitmap is covered by Extents B-tree locking */
1287 panic("hfs_lockmetafile: invalid fileID");
1292 /* Release, if necesary any locked buffer caches */
1293 if ((flags
& LK_TYPE_MASK
) == LK_RELEASE
) {
1294 struct timeval tv
= time
;
1295 u_int32_t lastfsync
= tv
.tv_sec
;
1297 (void) BTGetLastSync(VTOFCB(vp
), &lastfsync
);
1299 numOfLockedBuffs
= count_lock_queue();
1300 if ((numOfLockedBuffs
> kMaxLockedMetaBuffers
) || ((numOfLockedBuffs
>1) && ((tv
.tv_sec
- lastfsync
) > kMaxSecsForFsync
))) {
1301 DBG_UTILS(("Synching meta deta: %d... # locked buffers = %d, fsync gap = %ld\n", H_FILEID(VTOH(vp
)),
1302 numOfLockedBuffs
, (tv
.tv_sec
- lastfsync
)));
1303 hfs_fsync_transaction(vp
);
1307 retval
= lockmgr(&VTOH(vp
)->h_lock
, flags
, &vp
->v_interlock
, p
);
1315 * There are three ways to qualify for ownership rights on an object:
1317 * 1. (a) Your UID matches the UID of the vnode
1318 * (b) The object in question is owned by "unknown" and your UID matches the console user's UID
1319 * 2. (a) Permissions on the filesystem are being ignored and your UID matches the replacement UID
1320 * (b) Permissions on the filesystem are being ignored and the replacement UID is "unknown" and
1321 * your UID matches the console user UID
1325 int hfs_owner_rights(struct vnode
*vp
, struct ucred
*cred
, struct proc
*p
, Boolean invokesuperuserstatus
) {
1326 return ((cred
->cr_uid
== VTOH(vp
)->h_meta
->h_uid
) || /* [1a] */
1327 ((VTOH(vp
)->h_meta
->h_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)) || /* [1b] */
1328 ((VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) && /* [2] */
1329 ((cred
->cr_uid
== VTOHFS(vp
)->hfs_uid
) || /* [2a] */
1330 ((VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)))) || /* [2b] */
1331 (invokesuperuserstatus
&& (suser(cred
, &p
->p_acflag
) == 0))) ? 0 : EPERM
;
1336 int hfs_catalogentry_owner_rights(uid_t obj_uid
, struct mount
*mp
, struct ucred
*cred
, struct proc
*p
, Boolean invokesuperuserstatus
) {
1337 return ((cred
->cr_uid
== obj_uid
) || /* [1a] */
1338 ((obj_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)) || /* [1b] */
1339 ((mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) && /* [2] */
1340 ((cred
->cr_uid
== VFSTOHFS(mp
)->hfs_uid
) || /* [2a] */
1341 ((VFSTOHFS(mp
)->hfs_uid
== UNKNOWNUID
) && (cred
->cr_uid
== console_user
)))) || /* [2b] */
1342 (invokesuperuserstatus
&& (suser(cred
, &p
->p_acflag
) == 0))) ? 0 : EPERM
;
1347 void CopyVNodeToCatalogNode (struct vnode
*vp
, struct CatalogNodeData
*nodeData
)
1352 Boolean isHFSPlus
, isResource
;
1353 HFSPlusExtentDescriptor
*extents
;
1354 off_t fileReadLimit
;
1359 isResource
= (H_FORKTYPE(hp
) == kRsrcFork
);
1360 isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
1362 /* date and time of last fork modification */
1363 if (hp
->h_meta
->h_mtime
!= 0)
1364 nodeData
->cnd_contentModDate
= to_hfs_time(hp
->h_meta
->h_mtime
);
1367 /* Make sure that there is no nodeType/mode mismatch */
1368 if ((nodeData
->cnd_type
== kCatalogFolderNode
)
1369 && ((hp
->h_meta
->h_mode
& IFMT
) != IFDIR
)) {
1371 DBG_ASSERT((hp
->h_meta
->h_mode
& IFMT
) == IFDIR
);
1372 hp
->h_meta
->h_mode
&= ~IFMT
; /* Clear the bad bits */
1373 hp
->h_meta
->h_mode
|= IFDIR
; /* Set the proper one */
1375 /* date and time of last modification (any kind) */
1376 if (hp
->h_meta
->h_ctime
!= 0)
1377 nodeData
->cnd_attributeModDate
= to_hfs_time(hp
->h_meta
->h_ctime
);
1378 /* date and time of last access (MacOS X only) */
1379 if (hp
->h_meta
->h_atime
!= 0)
1380 nodeData
->cnd_accessDate
= to_hfs_time(hp
->h_meta
->h_atime
);
1381 /* hfs_setattr can change the create date */
1382 if (hp
->h_meta
->h_crtime
!= 0)
1383 nodeData
->cnd_createDate
= to_hfs_time(hp
->h_meta
->h_crtime
);
1384 if (! (hp
->h_meta
->h_metaflags
& IN_UNSETACCESS
)) {
1385 nodeData
->cnd_adminFlags
= hp
->h_meta
->h_pflags
>> 16;
1386 nodeData
->cnd_ownerFlags
= hp
->h_meta
->h_pflags
& 0x000000FF;
1387 nodeData
->cnd_mode
= hp
->h_meta
->h_mode
;
1388 nodeData
->cnd_ownerID
= hp
->h_meta
->h_uid
;
1389 nodeData
->cnd_groupID
= hp
->h_meta
->h_gid
;
1393 /* the rest only applies to files */
1394 if (nodeData
->cnd_type
== kCatalogFileNode
) {
1395 if (hp
->h_meta
->h_pflags
& (SF_IMMUTABLE
| UF_IMMUTABLE
)) {
1396 /* The file is locked: set the locked bit in the catalog. */
1397 nodeData
->cnd_flags
|= kHFSFileLockedMask
;
1399 /* The file is unlocked: make sure the locked bit in the catalog is clear. */
1400 nodeData
->cnd_flags
&= ~kHFSFileLockedMask
;
1402 if (CIRCLEQ_EMPTY(&hp
->h_invalidranges
)) {
1403 fileReadLimit
= fcb
->fcbEOF
;
1405 fileReadLimit
= CIRCLEQ_FIRST(&hp
->h_invalidranges
)->rl_start
;
1408 extents
= nodeData
->cnd_rsrcfork
.extents
;
1409 nodeData
->cnd_rsrcfork
.logicalSize
= fileReadLimit
;
1410 nodeData
->cnd_rsrcfork
.totalBlocks
= fcb
->fcbPLen
/ vcb
->blockSize
;
1412 extents
= nodeData
->cnd_datafork
.extents
;
1413 nodeData
->cnd_datafork
.logicalSize
= fileReadLimit
;
1414 nodeData
->cnd_datafork
.totalBlocks
= fcb
->fcbPLen
/ vcb
->blockSize
;
1417 bcopy ( fcb
->fcbExtents
, extents
, sizeof(HFSPlusExtentRecord
));
1419 if ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))
1420 nodeData
->cnd_rawDevice
= hp
->h_meta
->h_rdev
;
1421 else if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
1422 nodeData
->cnd_linkCount
= hp
->h_meta
->h_nlink
;
1424 if (vp
->v_type
== VLNK
) {
1425 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdType
= SWAP_BE32 (kSymLinkFileType
);
1426 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdCreator
= SWAP_BE32 (kSymLinkCreator
);
1428 /* Set this up as an alias */
1429 #if SUPPORTS_MAC_ALIASES
1430 ((struct FInfo
*)(&nodeData
->cnd_finderInfo
))->fdFlags
|= SWAP_BE16 (kIsAlias
);
1437 /*********************************************************************
1439 Sets the name in the filemeta structure
1441 XXX Does not preflight if changing from one size to another
1442 XXX Currently not protected from context switching
1444 *********************************************************************/
1446 void hfs_set_metaname(char *name
, struct hfsfilemeta
*fm
, struct hfsmount
*hfsmp
)
1448 int namelen
= strlen(name
);
1449 char *tname
, *fname
;
1452 DBG_ASSERT(name
!= NULL
);
1453 DBG_ASSERT(fm
!= NULL
);
1454 if (fm
->h_namePtr
) {
1455 DBG_ASSERT(fm
->h_namelen
== strlen(fm
->h_namePtr
));
1456 if (strlen(fm
->h_namePtr
) > MAXHFSVNODELEN
)
1457 DBG_ASSERT(fm
->h_metaflags
& IN_LONGNAME
);
1459 if (fm
->h_metaflags
& IN_LONGNAME
) {
1460 DBG_ASSERT(fm
->h_namePtr
!= (char *)fm
->h_fileName
);
1461 DBG_ASSERT(fm
->h_namePtr
!= NULL
);
1463 #endif //HFS_DIAGNOSTIC
1466 * Details that have to be dealt with:
1467 * 1. No name is allocated. fm->h_namePtr should be NULL
1468 * 2. A name is being changed and:
1469 * a. it was in static space and now cannot fit
1470 * b. It was malloc'd and now will fit in the static
1471 * c. It did and will fit in the static
1472 * This could be a little smarter:
1473 * - Dont re'malloc if the new name is smaller (but then wasting memory)
1474 * - If its a longname but the same size, we still free and malloc
1479 /* Allocate the new memory */
1480 if (namelen
> MAXHFSVNODELEN
) {
1482 * Notice the we ALWAYS allocate, even if the new is less then the old,
1483 * or even if they are the SAME
1485 MALLOC(tname
, char *, namelen
+1, M_TEMP
, M_WAITOK
);
1488 tname
= fm
->h_fileName
;
1490 simple_lock(&hfsmp
->hfs_renamelock
);
1492 /* Check to see if there is something to free, if yes, remember it */
1493 if (fm
->h_metaflags
& IN_LONGNAME
)
1494 fname
= fm
->h_namePtr
;
1499 if (namelen
> MAXHFSVNODELEN
) {
1500 fm
->h_metaflags
|= IN_LONGNAME
;
1503 fm
->h_metaflags
&= ~IN_LONGNAME
;
1506 /* Now copy it over */
1507 bcopy(name
, tname
, namelen
+1);
1509 fm
->h_namePtr
= tname
;
1510 fm
->h_namelen
= namelen
;
1512 simple_unlock(&hfsmp
->hfs_renamelock
);
1514 /* Lastly, free the old, if set */
1516 FREE(fname
, M_TEMP
);
1520 void hfs_name_CatToMeta(CatalogNodeData
*nodeData
, struct hfsfilemeta
*fm
)
1525 DBG_ASSERT(nodeData
!= NULL
);
1526 DBG_ASSERT(fm
!= NULL
);
1527 if (fm
->h_namePtr
) {
1528 DBG_ASSERT(fm
->h_namelen
== strlen(fm
->h_namePtr
));
1529 if (strlen(fm
->h_namePtr
) > MAXHFSVNODELEN
)
1530 DBG_ASSERT(fm
->h_metaflags
& IN_LONGNAME
);
1532 if (fm
->h_metaflags
& IN_LONGNAME
) {
1533 DBG_ASSERT(fm
->h_namePtr
!= (char *)fm
->h_fileName
);
1534 DBG_ASSERT(fm
->h_namePtr
!= NULL
);
1537 DBG_ASSERT(nodeData
->cnm_nameptr
!= NULL
);
1539 if (nodeData
->cnm_length
) {
1540 DBG_ASSERT(strlen(nodeData
->cnm_nameptr
) == nodeData
->cnm_length
);
1543 if (nodeData
->cnm_length
> MAXHFSVNODELEN
)
1544 { DBG_ASSERT(nodeData
->cnm_nameptr
!= nodeData
->cnm_namespace
); }
1545 else if (nodeData
->cnm_nameptr
)
1546 { DBG_ASSERT(nodeData
->cnm_nameptr
== nodeData
->cnm_namespace
); }
1548 #endif //HFS_DIAGNOSTIC
1551 /* Check to see if there is something to free, if yes, remember it */
1552 if (fm
->h_metaflags
& IN_LONGNAME
)
1553 fname
= fm
->h_namePtr
;
1558 if (nodeData
->cnm_length
> MAXHFSVNODELEN
) {
1559 fm
->h_metaflags
|= IN_LONGNAME
;
1561 fm
->h_metaflags
&= ~IN_LONGNAME
;
1564 /* Copy over the name */
1565 if (nodeData
->cnm_nameptr
== nodeData
->cnm_namespace
) {
1566 bcopy(nodeData
->cnm_namespace
, fm
->h_fileName
, nodeData
->cnm_length
+1);
1567 fm
->h_namePtr
= fm
->h_fileName
;
1570 fm
->h_namePtr
= nodeData
->cnm_nameptr
;
1573 fm
->h_namelen
= nodeData
->cnm_length
;
1575 nodeData
->cnm_flags
|= kCatNameIsConsumed
;
1576 nodeData
->cnm_flags
&= ~kCatNameIsAllocated
;
1577 nodeData
->cnm_length
= 0;
1578 nodeData
->cnm_nameptr
= (char *)0;
1579 nodeData
->cnm_namespace
[0] = 0;
1581 /* Lastly, free the old, if set */
1583 FREE(fname
, M_TEMP
);
1588 unsigned long DerivePermissionSummary(uid_t obj_uid
, gid_t obj_gid
, mode_t obj_mode
, struct mount
*mp
, struct ucred
*cred
, struct proc
*p
) {
1590 unsigned long permissions
;
1593 /* User id 0 (root) always gets access. */
1594 if (cred
->cr_uid
== 0) {
1595 permissions
= R_OK
| W_OK
| X_OK
;
1599 /* Otherwise, check the owner. */
1600 if (hfs_catalogentry_owner_rights(obj_uid
, mp
, cred
, p
, false) == 0) {
1601 permissions
= ((unsigned long)obj_mode
& S_IRWXU
) >> 6;
1605 /* Otherwise, check the groups. */
1606 if (! (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)) {
1607 for (i
= 0, gp
= cred
->cr_groups
; i
< cred
->cr_ngroups
; i
++, gp
++) {
1608 if (obj_gid
== *gp
) {
1609 permissions
= ((unsigned long)obj_mode
& S_IRWXG
) >> 3;
1615 /* Otherwise, settle for 'others' access. */
1616 permissions
= (unsigned long)obj_mode
& S_IRWXO
;
1624 int AttributeBlockSize(struct attrlist
*attrlist
) {
1628 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1629 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_PAROBJID | \
1630 ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
1631 ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1632 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST| \
1633 ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) != ATTR_CMN_VALIDMASK)
1634 #error AttributeBlockSize: Missing bits in common mask computation!
1636 DBG_ASSERT((attrlist
->commonattr
& ~ATTR_CMN_VALIDMASK
) == 0);
1638 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
1639 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1640 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | \
1641 ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | \
1642 ATTR_VOL_MOUNTEDDEVICE| ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) != ATTR_VOL_VALIDMASK)
1643 #error AttributeBlockSize: Missing bits in volume mask computation!
1645 DBG_ASSERT((attrlist
->volattr
& ~ATTR_VOL_VALIDMASK
) == 0);
1647 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) != ATTR_DIR_VALIDMASK)
1648 #error AttributeBlockSize: Missing bits in directory mask computation!
1650 DBG_ASSERT((attrlist
->dirattr
& ~ATTR_DIR_VALIDMASK
) == 0);
1651 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
1652 ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | \
1653 ATTR_FILE_FORKLIST | ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1654 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) != ATTR_FILE_VALIDMASK)
1655 #error AttributeBlockSize: Missing bits in file mask computation!
1657 DBG_ASSERT((attrlist
->fileattr
& ~ATTR_FILE_VALIDMASK
) == 0);
1659 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1660 #error AttributeBlockSize: Missing bits in fork mask computation!
1662 DBG_ASSERT((attrlist
->forkattr
& ~ATTR_FORK_VALIDMASK
) == 0);
1666 if ((a
= attrlist
->commonattr
) != 0) {
1667 if (a
& ATTR_CMN_NAME
) size
+= sizeof(struct attrreference
);
1668 if (a
& ATTR_CMN_DEVID
) size
+= sizeof(dev_t
);
1669 if (a
& ATTR_CMN_FSID
) size
+= sizeof(fsid_t
);
1670 if (a
& ATTR_CMN_OBJTYPE
) size
+= sizeof(fsobj_type_t
);
1671 if (a
& ATTR_CMN_OBJTAG
) size
+= sizeof(fsobj_tag_t
);
1672 if (a
& ATTR_CMN_OBJID
) size
+= sizeof(fsobj_id_t
);
1673 if (a
& ATTR_CMN_OBJPERMANENTID
) size
+= sizeof(fsobj_id_t
);
1674 if (a
& ATTR_CMN_PAROBJID
) size
+= sizeof(fsobj_id_t
);
1675 if (a
& ATTR_CMN_SCRIPT
) size
+= sizeof(text_encoding_t
);
1676 if (a
& ATTR_CMN_CRTIME
) size
+= sizeof(struct timespec
);
1677 if (a
& ATTR_CMN_MODTIME
) size
+= sizeof(struct timespec
);
1678 if (a
& ATTR_CMN_CHGTIME
) size
+= sizeof(struct timespec
);
1679 if (a
& ATTR_CMN_ACCTIME
) size
+= sizeof(struct timespec
);
1680 if (a
& ATTR_CMN_BKUPTIME
) size
+= sizeof(struct timespec
);
1681 if (a
& ATTR_CMN_FNDRINFO
) size
+= 32 * sizeof(UInt8
);
1682 if (a
& ATTR_CMN_OWNERID
) size
+= sizeof(uid_t
);
1683 if (a
& ATTR_CMN_GRPID
) size
+= sizeof(gid_t
);
1684 if (a
& ATTR_CMN_ACCESSMASK
) size
+= sizeof(u_long
);
1685 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) size
+= sizeof(u_long
);
1686 if (a
& ATTR_CMN_NAMEDATTRLIST
) size
+= sizeof(struct attrreference
);
1687 if (a
& ATTR_CMN_FLAGS
) size
+= sizeof(u_long
);
1688 if (a
& ATTR_CMN_USERACCESS
) size
+= sizeof(u_long
);
1690 if ((a
= attrlist
->volattr
) != 0) {
1691 if (a
& ATTR_VOL_FSTYPE
) size
+= sizeof(u_long
);
1692 if (a
& ATTR_VOL_SIGNATURE
) size
+= sizeof(u_long
);
1693 if (a
& ATTR_VOL_SIZE
) size
+= sizeof(off_t
);
1694 if (a
& ATTR_VOL_SPACEFREE
) size
+= sizeof(off_t
);
1695 if (a
& ATTR_VOL_SPACEAVAIL
) size
+= sizeof(off_t
);
1696 if (a
& ATTR_VOL_MINALLOCATION
) size
+= sizeof(off_t
);
1697 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) size
+= sizeof(off_t
);
1698 if (a
& ATTR_VOL_IOBLOCKSIZE
) size
+= sizeof(u_long
);
1699 if (a
& ATTR_VOL_OBJCOUNT
) size
+= sizeof(u_long
);
1700 if (a
& ATTR_VOL_FILECOUNT
) size
+= sizeof(u_long
);
1701 if (a
& ATTR_VOL_DIRCOUNT
) size
+= sizeof(u_long
);
1702 if (a
& ATTR_VOL_MAXOBJCOUNT
) size
+= sizeof(u_long
);
1703 if (a
& ATTR_VOL_MOUNTPOINT
) size
+= sizeof(struct attrreference
);
1704 if (a
& ATTR_VOL_NAME
) size
+= sizeof(struct attrreference
);
1705 if (a
& ATTR_VOL_MOUNTFLAGS
) size
+= sizeof(u_long
);
1706 if (a
& ATTR_VOL_MOUNTEDDEVICE
) size
+= sizeof(struct attrreference
);
1707 if (a
& ATTR_VOL_ENCODINGSUSED
) size
+= sizeof(unsigned long long);
1708 if (a
& ATTR_VOL_CAPABILITIES
) size
+= sizeof(vol_capabilities_attr_t
);
1709 if (a
& ATTR_VOL_ATTRIBUTES
) size
+= sizeof(vol_attributes_attr_t
);
1711 if ((a
= attrlist
->dirattr
) != 0) {
1712 if (a
& ATTR_DIR_LINKCOUNT
) size
+= sizeof(u_long
);
1713 if (a
& ATTR_DIR_ENTRYCOUNT
) size
+= sizeof(u_long
);
1714 if (a
& ATTR_DIR_MOUNTSTATUS
) size
+= sizeof(u_long
);
1716 if ((a
= attrlist
->fileattr
) != 0) {
1717 if (a
& ATTR_FILE_LINKCOUNT
) size
+= sizeof(u_long
);
1718 if (a
& ATTR_FILE_TOTALSIZE
) size
+= sizeof(off_t
);
1719 if (a
& ATTR_FILE_ALLOCSIZE
) size
+= sizeof(off_t
);
1720 if (a
& ATTR_FILE_IOBLOCKSIZE
) size
+= sizeof(size_t);
1721 if (a
& ATTR_FILE_CLUMPSIZE
) size
+= sizeof(off_t
);
1722 if (a
& ATTR_FILE_DEVTYPE
) size
+= sizeof(u_long
);
1723 if (a
& ATTR_FILE_FILETYPE
) size
+= sizeof(u_long
);
1724 if (a
& ATTR_FILE_FORKCOUNT
) size
+= sizeof(u_long
);
1725 if (a
& ATTR_FILE_FORKLIST
) size
+= sizeof(struct attrreference
);
1726 if (a
& ATTR_FILE_DATALENGTH
) size
+= sizeof(off_t
);
1727 if (a
& ATTR_FILE_DATAALLOCSIZE
) size
+= sizeof(off_t
);
1728 if (a
& ATTR_FILE_DATAEXTENTS
) size
+= sizeof(extentrecord
);
1729 if (a
& ATTR_FILE_RSRCLENGTH
) size
+= sizeof(off_t
);
1730 if (a
& ATTR_FILE_RSRCALLOCSIZE
) size
+= sizeof(off_t
);
1731 if (a
& ATTR_FILE_RSRCEXTENTS
) size
+= sizeof(extentrecord
);
1733 if ((a
= attrlist
->forkattr
) != 0) {
1734 if (a
& ATTR_FORK_TOTALSIZE
) size
+= sizeof(off_t
);
1735 if (a
& ATTR_FORK_ALLOCSIZE
) size
+= sizeof(off_t
);
1743 char* FindMountpointName(struct mount
*mp
) {
1744 size_t namelength
= strlen(mp
->mnt_stat
.f_mntonname
);
1748 if (namelength
== 0) return NULL
;
1750 /* Look backwards through the name string, looking for the first slash
1751 encountered (which must precede the last part of the pathname)
1753 for (c
= mp
->mnt_stat
.f_mntonname
+ namelength
- 1; namelength
> 0; --c
, --namelength
) {
1756 } else if (foundchars
) {
1761 return mp
->mnt_stat
.f_mntonname
;
1766 void PackObjectName(struct vnode
*vp
,
1769 void **attrbufptrptr
,
1770 void **varbufptrptr
) {
1775 /* The name of an object may be incorrect for the root of a mounted filesystem
1776 because it may be mounted on a different directory name than the name of the
1777 volume (such as "blah-1". For the root directory, it's best to return the
1778 last element of the location where the volume's mounted:
1780 if ((vp
->v_flag
& VROOT
) && (mpname
= FindMountpointName(vp
->v_mount
))) {
1781 mpnamelen
= strlen(mpname
);
1783 /* Trim off any trailing slashes: */
1784 while ((mpnamelen
> 0) && (mpname
[mpnamelen
-1] == '/')) {
1788 /* If there's anything left, use it instead of the volume's name */
1789 if (mpnamelen
> 0) {
1791 namelen
= mpnamelen
;
1795 attrlength
= namelen
+ 1;
1796 ((struct attrreference
*)(*attrbufptrptr
))->attr_dataoffset
= (char *)(*varbufptrptr
) - (char *)(*attrbufptrptr
);
1797 ((struct attrreference
*)(*attrbufptrptr
))->attr_length
= attrlength
;
1798 (void) strncpy((unsigned char *)(*varbufptrptr
), name
, attrlength
);
1800 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1801 (char *)(*varbufptrptr
) += attrlength
+ ((4 - (attrlength
& 3)) & 3);
1802 ++((struct attrreference
*)(*attrbufptrptr
));
1807 void PackVolCommonAttributes(struct attrlist
*alist
,
1808 struct vnode
*root_vp
,
1809 struct hfsCatalogInfo
*root_catInfo
,
1810 void **attrbufptrptr
,
1811 void **varbufptrptr
) {
1815 struct hfsnode
*root_hp
= VTOH(root_vp
);
1816 struct mount
*mp
= VTOVFS(root_vp
);
1817 struct hfsmount
*hfsmp
= VTOHFS(root_vp
);
1818 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1821 attrbufptr
= *attrbufptrptr
;
1822 varbufptr
= *varbufptrptr
;
1824 if ((a
= alist
->commonattr
) != 0) {
1825 if (a
& ATTR_CMN_NAME
) {
1826 PackObjectName(root_vp
, H_NAME(root_hp
), root_hp
->h_meta
->h_namelen
, &attrbufptr
, &varbufptr
);
1828 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = hfsmp
->hfs_raw_dev
;
1829 if (a
& ATTR_CMN_FSID
) {
1830 *((fsid_t
*)attrbufptr
) = mp
->mnt_stat
.f_fsid
;
1831 ++((fsid_t
*)attrbufptr
);
1833 if (a
& ATTR_CMN_OBJTYPE
) *((fsobj_type_t
*)attrbufptr
)++ = 0;
1834 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = VT_HFS
;
1835 if (a
& ATTR_CMN_OBJID
) {
1836 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1837 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1838 ++((fsobj_id_t
*)attrbufptr
);
1840 if (a
& ATTR_CMN_OBJPERMANENTID
) {
1841 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1842 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1843 ++((fsobj_id_t
*)attrbufptr
);
1845 if (a
& ATTR_CMN_PAROBJID
) {
1846 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= 0;
1847 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
1848 ++((fsobj_id_t
*)attrbufptr
);
1851 if (a
& ATTR_CMN_SCRIPT
) *((text_encoding_t
*)attrbufptr
)++ = vcb
->volumeNameEncodingHint
;
1852 /* NOTE: all VCB dates are in Mac OS time */
1853 if (a
& ATTR_CMN_CRTIME
) {
1854 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbCrDate
);
1855 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1856 ++((struct timespec
*)attrbufptr
);
1858 if (a
& ATTR_CMN_MODTIME
) {
1859 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1860 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1861 ++((struct timespec
*)attrbufptr
);
1863 if (a
& ATTR_CMN_CHGTIME
) {
1864 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1865 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1866 ++((struct timespec
*)attrbufptr
);
1868 if (a
& ATTR_CMN_ACCTIME
) {
1869 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbLsMod
);
1870 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1871 ++((struct timespec
*)attrbufptr
);
1873 if (a
& ATTR_CMN_BKUPTIME
) {
1874 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(vcb
->vcbVolBkUp
);
1875 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
1876 ++((struct timespec
*)attrbufptr
);
1878 if (a
& ATTR_CMN_FNDRINFO
) {
1879 bcopy (&vcb
->vcbFndrInfo
, attrbufptr
, sizeof(vcb
->vcbFndrInfo
));
1880 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
1883 if (a
& ATTR_CMN_OWNERID
) {
1884 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1885 *((uid_t
*)attrbufptr
)++ =
1886 (VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
;
1888 *((uid_t
*)attrbufptr
)++ =
1889 (root_hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: root_hp
->h_meta
->h_uid
;
1892 if (a
& ATTR_CMN_GRPID
) {
1893 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1894 *((gid_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_gid
;
1896 *((gid_t
*)attrbufptr
)++ = root_hp
->h_meta
->h_gid
;
1899 if (a
& ATTR_CMN_ACCESSMASK
) *((u_long
*)attrbufptr
)++ = (u_long
)root_hp
->h_meta
->h_mode
;
1900 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
1901 if (a
& ATTR_CMN_NAMEDATTRLIST
) {
1903 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
1904 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
1906 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1907 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
1908 ++((struct attrreference
*)attrbufptr
);
1910 if (a
& ATTR_CMN_FLAGS
) *((u_long
*)attrbufptr
)++ = root_hp
->h_meta
->h_pflags
;
1911 if (a
& ATTR_CMN_USERACCESS
) {
1912 if (mp
->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
1913 *((u_long
*)attrbufptr
)++ =
1914 DerivePermissionSummary((VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
,
1915 VTOHFS(root_vp
)->hfs_gid
,
1916 root_hp
->h_meta
->h_mode
,
1918 current_proc()->p_ucred
,
1921 *((u_long
*)attrbufptr
)++ =
1922 DerivePermissionSummary((root_hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: root_hp
->h_meta
->h_uid
,
1923 root_hp
->h_meta
->h_gid
,
1924 root_hp
->h_meta
->h_mode
,
1926 current_proc()->p_ucred
,
1932 *attrbufptrptr
= attrbufptr
;
1933 *varbufptrptr
= varbufptr
;
1938 void PackVolAttributeBlock(struct attrlist
*alist
,
1939 struct vnode
*root_vp
,
1940 struct hfsCatalogInfo
*root_catInfo
,
1941 void **attrbufptrptr
,
1942 void **varbufptrptr
) {
1946 struct mount
*mp
= VTOVFS(root_vp
);
1947 struct hfsmount
*hfsmp
= VTOHFS(root_vp
);
1948 ExtendedVCB
*vcb
= HFSTOVCB(hfsmp
);
1951 attrbufptr
= *attrbufptrptr
;
1952 varbufptr
= *varbufptrptr
;
1954 if ((a
= alist
->volattr
) != 0) {
1956 if (a
& ATTR_VOL_FSTYPE
) *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_vfc
->vfc_typenum
;
1957 if (a
& ATTR_VOL_SIGNATURE
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbSigWord
;
1958 if (a
& ATTR_VOL_SIZE
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->totalBlocks
* (off_t
)vcb
->blockSize
;
1959 if (a
& ATTR_VOL_SPACEFREE
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->freeBlocks
* (off_t
)vcb
->blockSize
;
1960 if (a
& ATTR_VOL_SPACEAVAIL
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->freeBlocks
* (off_t
)vcb
->blockSize
;
1961 if (a
& ATTR_VOL_MINALLOCATION
) *((off_t
*)attrbufptr
)++ = (off_t
)vcb
->blockSize
;
1962 if (a
& ATTR_VOL_ALLOCATIONCLUMP
) *((off_t
*)attrbufptr
)++ = (off_t
)(vcb
->vcbClpSiz
);
1963 if (a
& ATTR_VOL_IOBLOCKSIZE
) *((u_long
*)attrbufptr
)++ = (u_long
)hfsmp
->hfs_logBlockSize
;
1964 if (a
& ATTR_VOL_OBJCOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
+ (u_long
)vcb
->vcbDirCnt
;
1965 if (a
& ATTR_VOL_FILECOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbFilCnt
;
1966 if (a
& ATTR_VOL_DIRCOUNT
) *((u_long
*)attrbufptr
)++ = (u_long
)vcb
->vcbDirCnt
;
1967 if (a
& ATTR_VOL_MAXOBJCOUNT
) *((u_long
*)attrbufptr
)++ = 0xFFFFFFFF;
1968 if (a
& ATTR_VOL_MOUNTPOINT
) {
1969 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1970 ((struct attrreference
*)attrbufptr
)->attr_length
= strlen(mp
->mnt_stat
.f_mntonname
) + 1;
1971 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1972 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1973 (void) bcopy(mp
->mnt_stat
.f_mntonname
, varbufptr
, attrlength
);
1975 /* Advance beyond the space just allocated: */
1976 (char *)varbufptr
+= attrlength
;
1977 ++((struct attrreference
*)attrbufptr
);
1979 if (a
& ATTR_VOL_NAME
) {
1980 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1981 ((struct attrreference
*)attrbufptr
)->attr_length
= VTOH(root_vp
)->h_meta
->h_namelen
+ 1;
1982 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1983 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1984 bcopy(H_NAME(VTOH(root_vp
)), varbufptr
, attrlength
);
1986 /* Advance beyond the space just allocated: */
1987 (char *)varbufptr
+= attrlength
;
1988 ++((struct attrreference
*)attrbufptr
);
1990 if (a
& ATTR_VOL_MOUNTFLAGS
) *((u_long
*)attrbufptr
)++ = (u_long
)mp
->mnt_flag
;
1991 if (a
& ATTR_VOL_MOUNTEDDEVICE
) {
1992 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
1993 ((struct attrreference
*)attrbufptr
)->attr_length
= strlen(mp
->mnt_stat
.f_mntfromname
) + 1;
1994 attrlength
= ((struct attrreference
*)attrbufptr
)->attr_length
;
1995 attrlength
= attrlength
+ ((4 - (attrlength
& 3)) & 3); /* round up to the next 4-byte boundary: */
1996 (void) bcopy(mp
->mnt_stat
.f_mntfromname
, varbufptr
, attrlength
);
1998 /* Advance beyond the space just allocated: */
1999 (char *)varbufptr
+= attrlength
;
2000 ++((struct attrreference
*)attrbufptr
);
2002 if (a
& ATTR_VOL_ENCODINGSUSED
) *((unsigned long long *)attrbufptr
)++ = (unsigned long long)vcb
->encodingsBitmap
;
2003 if (a
& ATTR_VOL_CAPABILITIES
) {
2004 if (vcb
->vcbSigWord
== kHFSPlusSigWord
) {
2005 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_FORMAT
] =
2006 VOL_CAP_FMT_PERSISTENTOBJECTIDS
| VOL_CAP_FMT_SYMBOLICLINKS
| VOL_CAP_FMT_HARDLINKS
;
2007 } else { /* Plain HFS */
2008 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_FORMAT
] =
2009 VOL_CAP_FMT_PERSISTENTOBJECTIDS
;
2011 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_INTERFACES
] =
2012 VOL_CAP_INT_SEARCHFS
| VOL_CAP_INT_ATTRLIST
| VOL_CAP_INT_NFSEXPORT
| VOL_CAP_INT_READDIRATTR
;
2013 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_RESERVED1
] = 0;
2014 ((vol_capabilities_attr_t
*)attrbufptr
)->capabilities
[VOL_CAPABILITIES_RESERVED2
] = 0;
2016 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_FORMAT
] =
2017 VOL_CAP_FMT_PERSISTENTOBJECTIDS
| VOL_CAP_FMT_SYMBOLICLINKS
| VOL_CAP_FMT_HARDLINKS
;
2018 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_INTERFACES
] =
2019 VOL_CAP_INT_SEARCHFS
| VOL_CAP_INT_ATTRLIST
| VOL_CAP_INT_NFSEXPORT
| VOL_CAP_INT_READDIRATTR
;
2020 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_RESERVED1
] = 0;
2021 ((vol_capabilities_attr_t
*)attrbufptr
)->valid
[VOL_CAPABILITIES_RESERVED2
] = 0;
2023 ++((vol_capabilities_attr_t
*)attrbufptr
);
2025 if (a
& ATTR_VOL_ATTRIBUTES
) {
2026 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.commonattr
= ATTR_CMN_VALIDMASK
;
2027 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.volattr
= ATTR_VOL_VALIDMASK
;
2028 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.dirattr
= ATTR_DIR_VALIDMASK
;
2029 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.fileattr
= ATTR_FILE_VALIDMASK
;
2030 ((vol_attributes_attr_t
*)attrbufptr
)->validattr
.forkattr
= ATTR_FORK_VALIDMASK
;
2032 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.commonattr
= ATTR_CMN_VALIDMASK
;
2033 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.volattr
= ATTR_VOL_VALIDMASK
;
2034 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.dirattr
= ATTR_DIR_VALIDMASK
;
2035 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.fileattr
= ATTR_FILE_VALIDMASK
;
2036 ((vol_attributes_attr_t
*)attrbufptr
)->nativeattr
.forkattr
= ATTR_FORK_VALIDMASK
;
2038 ++((vol_attributes_attr_t
*)attrbufptr
);
2043 *attrbufptrptr
= attrbufptr
;
2044 *varbufptrptr
= varbufptr
;
2050 void PackVolumeInfo(struct attrlist
*alist
,
2051 struct vnode
*root_vp
,
2052 struct hfsCatalogInfo
*root_catinfo
,
2053 void **attrbufptrptr
,
2054 void **varbufptrptr
) {
2056 PackVolCommonAttributes(alist
, root_vp
, root_catinfo
, attrbufptrptr
, varbufptrptr
);
2057 PackVolAttributeBlock(alist
, root_vp
, root_catinfo
, attrbufptrptr
, varbufptrptr
);
2060 // Pack the common attribute contents of an objects hfsCatalogInfo
2061 void PackCommonCatalogInfoAttributeBlock(struct attrlist
*alist
,
2062 struct vnode
*root_vp
,
2063 struct hfsCatalogInfo
*catalogInfo
,
2064 void **attrbufptrptr
,
2065 void **varbufptrptr
)
2075 attrbufptr
= *attrbufptrptr
;
2076 varbufptr
= *varbufptrptr
;
2077 isHFSPlus
= (VTOVCB(root_vp
)->vcbSigWord
== kHFSPlusSigWord
);
2079 if ((a
= alist
->commonattr
) != 0)
2081 if (a
& ATTR_CMN_NAME
)
2083 attrlength
= strlen(catalogInfo
->nodeData
.cnm_nameptr
) + 1;
2084 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= (char *)varbufptr
- (char *)attrbufptr
;
2085 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2086 (void) strncpy((unsigned char *)varbufptr
,
2087 catalogInfo
->nodeData
.cnm_nameptr
, attrlength
);
2089 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2090 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2091 ++((struct attrreference
*)attrbufptr
);
2093 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = H_DEV(hp
);
2094 if (a
& ATTR_CMN_FSID
) {
2095 *((fsid_t
*)attrbufptr
) = VTOVFS(root_vp
)->mnt_stat
.f_fsid
;
2096 ++((fsid_t
*)attrbufptr
);
2098 if (a
& ATTR_CMN_OBJTYPE
)
2100 switch (catalogInfo
->nodeData
.cnd_type
) {
2101 case kCatalogFolderNode
:
2102 *((fsobj_type_t
*)attrbufptr
)++ = VDIR
;
2105 case kCatalogFileNode
:
2106 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2107 if ((HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) &&
2108 (catalogInfo
->nodeData
.cnd_mode
& IFMT
)) {
2109 *((fsobj_type_t
*)attrbufptr
)++ =
2110 IFTOVT((mode_t
)catalogInfo
->nodeData
.cnd_mode
);
2112 *((fsobj_type_t
*)attrbufptr
)++ = VREG
;
2117 *((fsobj_type_t
*)attrbufptr
)++ = VNON
;
2121 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = root_vp
->v_tag
;
2122 if (a
& ATTR_CMN_OBJID
) {
2125 /* For hard links use the link's cnid */
2126 if (catalogInfo
->nodeData
.cnd_iNodeNumCopy
!= 0)
2127 cnid
= catalogInfo
->nodeData
.cnd_linkCNID
;
2129 cnid
= catalogInfo
->nodeData
.cnd_nodeID
;
2130 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2131 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2132 ++((fsobj_id_t
*)attrbufptr
);
2134 if (a
& ATTR_CMN_OBJPERMANENTID
) {
2137 /* For hard links use the link's cnid */
2138 if (catalogInfo
->nodeData
.cnd_iNodeNumCopy
!= 0)
2139 cnid
= catalogInfo
->nodeData
.cnd_linkCNID
;
2141 cnid
= catalogInfo
->nodeData
.cnd_nodeID
;
2142 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2143 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2144 ++((fsobj_id_t
*)attrbufptr
);
2146 if (a
& ATTR_CMN_PAROBJID
)
2148 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= catalogInfo
->nodeData
.cnm_parID
;
2149 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2150 ++((fsobj_id_t
*)attrbufptr
);
2152 if (a
& ATTR_CMN_SCRIPT
)
2154 if (HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) {
2155 *((text_encoding_t
*)attrbufptr
)++ = catalogInfo
->nodeData
.cnd_textEncoding
;
2157 *((text_encoding_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_encoding
;
2160 if (a
& ATTR_CMN_CRTIME
)
2162 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_createDate
);
2163 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2164 ++((struct timespec
*)attrbufptr
);
2166 if (a
& ATTR_CMN_MODTIME
)
2168 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_contentModDate
);
2169 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2170 ++((struct timespec
*)attrbufptr
);
2172 if (a
& ATTR_CMN_CHGTIME
)
2174 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_attributeModDate
);
2175 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2176 ++((struct timespec
*)attrbufptr
);
2178 if (a
& ATTR_CMN_ACCTIME
)
2180 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_accessDate
);
2181 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2182 ++((struct timespec
*)attrbufptr
);
2184 if (a
& ATTR_CMN_BKUPTIME
)
2186 ((struct timespec
*)attrbufptr
)->tv_sec
= to_bsd_time(catalogInfo
->nodeData
.cnd_backupDate
);
2187 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2188 ++((struct timespec
*)attrbufptr
);
2190 if (a
& ATTR_CMN_FNDRINFO
)
2192 bcopy (&catalogInfo
->nodeData
.cnd_finderInfo
, attrbufptr
, sizeof(catalogInfo
->nodeData
.cnd_finderInfo
));
2193 (char *)attrbufptr
+= sizeof(catalogInfo
->nodeData
.cnd_finderInfo
);
2195 if (a
& ATTR_CMN_OWNERID
) {
2196 if ((VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) ||
2197 ((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)) {
2198 *((uid_t
*)attrbufptr
)++ =
2199 (VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
;
2201 *((uid_t
*)attrbufptr
)++ =
2202 (catalogInfo
->nodeData
.cnd_ownerID
== UNKNOWNUID
) ? console_user
: catalogInfo
->nodeData
.cnd_ownerID
;
2205 if (a
& ATTR_CMN_GRPID
) {
2206 if ((VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) ||
2207 ((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)) {
2208 *((gid_t
*)attrbufptr
)++ = VTOHFS(root_vp
)->hfs_gid
;
2210 *((gid_t
*)attrbufptr
)++ = catalogInfo
->nodeData
.cnd_groupID
;
2213 if (a
& ATTR_CMN_ACCESSMASK
) {
2214 if (((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)
2215 #if OVERRIDE_UNKNOWN_PERMISSIONS
2216 || (VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
)
2219 switch (catalogInfo
->nodeData
.cnd_type
) {
2220 case kCatalogFileNode
:
2221 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2222 *((u_long
*)attrbufptr
)++ = (u_long
)(IFREG
| (ACCESSPERMS
& (u_long
)(VTOHFS(root_vp
)->hfs_file_mask
)));
2225 case kCatalogFolderNode
:
2226 *((u_long
*)attrbufptr
)++ = (u_long
)(IFDIR
| (ACCESSPERMS
& (u_long
)(VTOHFS(root_vp
)->hfs_dir_mask
)));
2230 *((u_long
*)attrbufptr
)++ = (u_long
)((catalogInfo
->nodeData
.cnd_mode
& IFMT
) |
2231 VTOHFS(root_vp
)->hfs_dir_mask
);
2234 *((u_long
*)attrbufptr
)++ =
2235 (u_long
)catalogInfo
->nodeData
.cnd_mode
;
2238 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
2239 if (a
& ATTR_CMN_NAMEDATTRLIST
)
2242 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2243 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2245 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2246 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2247 ++((struct attrreference
*)attrbufptr
);
2249 if (a
& ATTR_CMN_FLAGS
) {
2252 if (catalogInfo
->nodeData
.cnd_mode
& IFMT
)
2253 flags
= catalogInfo
->nodeData
.cnd_ownerFlags
|
2254 catalogInfo
->nodeData
.cnd_adminFlags
<< 16;
2258 if (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) {
2259 if (catalogInfo
->nodeData
.cnd_flags
& kHFSFileLockedMask
)
2260 flags
|= UF_IMMUTABLE
;
2262 flags
&= ~UF_IMMUTABLE
;
2264 *((u_long
*)attrbufptr
)++ = flags
;
2266 if (a
& ATTR_CMN_USERACCESS
) {
2267 if ((VTOVFS(root_vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) ||
2268 ((catalogInfo
->nodeData
.cnd_mode
& IFMT
) == 0)) {
2269 *((u_long
*)attrbufptr
)++ =
2270 DerivePermissionSummary((VTOHFS(root_vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(root_vp
)->hfs_uid
,
2271 VTOHFS(root_vp
)->hfs_gid
,
2272 #if OVERRIDE_UNKNOWN_PERMISSIONS
2273 (catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) ? VTOHFS(root_vp
)->hfs_file_mask
: VTOHFS(root_vp
)->hfs_dir_mask
,
2275 (catalogInfo
->nodeData
.cnd_mode
& IFMT
) ?
2276 (u_long
)catalogInfo
->nodeData
.cnd_mode
:
2277 ((catalogInfo
->nodeData
.cnd_type
== kCatalogFileNode
) ?
2278 VTOHFS(root_vp
)->hfs_file_mask
:
2279 VTOHFS(root_vp
)->hfs_dir_mask
),
2282 current_proc()->p_ucred
,
2285 *((u_long
*)attrbufptr
)++ =
2286 DerivePermissionSummary((catalogInfo
->nodeData
.cnd_ownerID
== UNKNOWNUID
) ? console_user
: catalogInfo
->nodeData
.cnd_ownerID
,
2287 catalogInfo
->nodeData
.cnd_groupID
,
2288 (mode_t
)catalogInfo
->nodeData
.cnd_mode
,
2290 current_proc()->p_ucred
,
2296 *attrbufptrptr
= attrbufptr
;
2297 *varbufptrptr
= varbufptr
;
2301 void PackCommonAttributeBlock(struct attrlist
*alist
,
2303 struct hfsCatalogInfo
*catInfo
,
2304 void **attrbufptrptr
,
2305 void **varbufptrptr
) {
2314 attrbufptr
= *attrbufptrptr
;
2315 varbufptr
= *varbufptrptr
;
2317 if ((a
= alist
->commonattr
) != 0) {
2318 if (a
& ATTR_CMN_NAME
) {
2319 PackObjectName(vp
, H_NAME(hp
), hp
->h_meta
->h_namelen
, &attrbufptr
, &varbufptr
);
2321 if (a
& ATTR_CMN_DEVID
) *((dev_t
*)attrbufptr
)++ = H_DEV(hp
);
2322 if (a
& ATTR_CMN_FSID
) {
2323 *((fsid_t
*)attrbufptr
) = VTOVFS(vp
)->mnt_stat
.f_fsid
;
2324 ++((fsid_t
*)attrbufptr
);
2326 if (a
& ATTR_CMN_OBJTYPE
) *((fsobj_type_t
*)attrbufptr
)++ = vp
->v_type
;
2327 if (a
& ATTR_CMN_OBJTAG
) *((fsobj_tag_t
*)attrbufptr
)++ = vp
->v_tag
;
2328 if (a
& ATTR_CMN_OBJID
) {
2331 /* For hard links use the link's cnid */
2332 if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
2333 cnid
= catInfo
->nodeData
.cnd_linkCNID
;
2335 cnid
= H_FILEID(hp
);
2336 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2337 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2338 ++((fsobj_id_t
*)attrbufptr
);
2340 if (a
& ATTR_CMN_OBJPERMANENTID
) {
2343 /* For hard links use the link's cnid */
2344 if (hp
->h_meta
->h_metaflags
& IN_DATANODE
)
2345 cnid
= catInfo
->nodeData
.cnd_linkCNID
;
2347 cnid
= H_FILEID(hp
);
2348 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= cnid
;
2349 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2350 ++((fsobj_id_t
*)attrbufptr
);
2352 if (a
& ATTR_CMN_PAROBJID
) {
2353 ((fsobj_id_t
*)attrbufptr
)->fid_objno
= H_DIRID(hp
);
2354 ((fsobj_id_t
*)attrbufptr
)->fid_generation
= 0;
2355 ++((fsobj_id_t
*)attrbufptr
);
2357 if (a
& ATTR_CMN_SCRIPT
)
2359 if (HTOVCB(hp
)->vcbSigWord
== kHFSPlusSigWord
) {
2360 *((text_encoding_t
*)attrbufptr
)++ = catInfo
->nodeData
.cnd_textEncoding
;
2362 *((text_encoding_t
*)attrbufptr
)++ = VTOHFS(vp
)->hfs_encoding
;
2365 if (a
& ATTR_CMN_CRTIME
) {
2366 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_crtime
;
2367 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2368 ++((struct timespec
*)attrbufptr
);
2370 if (a
& ATTR_CMN_MODTIME
) {
2371 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_mtime
;
2372 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2373 ++((struct timespec
*)attrbufptr
);
2375 if (a
& ATTR_CMN_CHGTIME
) {
2376 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_ctime
;
2377 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2378 ++((struct timespec
*)attrbufptr
);
2380 if (a
& ATTR_CMN_ACCTIME
) {
2381 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_atime
;
2382 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2383 ++((struct timespec
*)attrbufptr
);
2385 if (a
& ATTR_CMN_BKUPTIME
) {
2386 ((struct timespec
*)attrbufptr
)->tv_sec
= hp
->h_meta
->h_butime
;
2387 ((struct timespec
*)attrbufptr
)->tv_nsec
= 0;
2388 ++((struct timespec
*)attrbufptr
);
2390 if (a
& ATTR_CMN_FNDRINFO
) {
2391 bcopy (&catInfo
->nodeData
.cnd_finderInfo
, attrbufptr
, sizeof(catInfo
->nodeData
.cnd_finderInfo
));
2392 (char *)attrbufptr
+= sizeof(catInfo
->nodeData
.cnd_finderInfo
);
2394 if (a
& ATTR_CMN_OWNERID
) {
2395 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2396 *((uid_t
*)attrbufptr
)++ =
2397 (VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(vp
)->hfs_uid
;
2399 *((uid_t
*)attrbufptr
)++ =
2400 (hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: hp
->h_meta
->h_uid
;
2403 if (a
& ATTR_CMN_GRPID
) {
2404 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2405 *((gid_t
*)attrbufptr
)++ = VTOHFS(vp
)->hfs_gid
;
2407 *((gid_t
*)attrbufptr
)++ = hp
->h_meta
->h_gid
;
2410 if (a
& ATTR_CMN_ACCESSMASK
) *((u_long
*)attrbufptr
)++ = (u_long
)hp
->h_meta
->h_mode
;
2411 if (a
& ATTR_CMN_NAMEDATTRCOUNT
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD TBC */
2412 if (a
& ATTR_CMN_NAMEDATTRLIST
) {
2414 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2415 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2417 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2418 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2419 ++((struct attrreference
*)attrbufptr
);
2421 if (a
& ATTR_CMN_FLAGS
) *((u_long
*)attrbufptr
)++ = hp
->h_meta
->h_pflags
;
2422 if (a
& ATTR_CMN_USERACCESS
) {
2423 if (VTOVFS(vp
)->mnt_flag
& MNT_UNKNOWNPERMISSIONS
) {
2424 *((u_long
*)attrbufptr
)++ =
2425 DerivePermissionSummary((VTOHFS(vp
)->hfs_uid
== UNKNOWNUID
) ? console_user
: VTOHFS(vp
)->hfs_uid
,
2426 VTOHFS(vp
)->hfs_gid
,
2429 current_proc()->p_ucred
,
2432 *((u_long
*)attrbufptr
)++ =
2433 DerivePermissionSummary((hp
->h_meta
->h_uid
== UNKNOWNUID
) ? console_user
: hp
->h_meta
->h_uid
,
2437 current_proc()->p_ucred
,
2443 *attrbufptrptr
= attrbufptr
;
2444 *varbufptrptr
= varbufptr
;
2448 // Pack the directory attributes given hfsCatalogInfo
2449 void PackCatalogInfoDirAttributeBlock( struct attrlist
*alist
, struct vnode
*vp
,
2450 struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2456 attrbufptr
= *attrbufptrptr
;
2459 if ( (catInfo
->nodeData
.cnd_type
== kCatalogFolderNode
) && (a
!= 0) ) {
2460 valence
= catInfo
->nodeData
.cnd_valence
;
2461 if ((catInfo
->nodeData
.cnm_parID
== kRootParID
) &&
2462 (VTOHFS(vp
)->hfs_private_metadata_dir
!= 0)) {
2463 --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 *((u_long
*)attrbufptr
)++ = 0;
2474 *attrbufptrptr
= attrbufptr
;
2478 void PackDirAttributeBlock(struct attrlist
*alist
,
2480 struct hfsCatalogInfo
*catInfo
,
2481 void **attrbufptrptr
,
2482 void **varbufptrptr
) {
2487 attrbufptr
= *attrbufptrptr
;
2490 if ((vp
->v_type
== VDIR
) && (a
!= 0)) {
2491 valence
= catInfo
->nodeData
.cnd_valence
;
2492 if ((catInfo
->nodeData
.cnm_parID
== kRootParID
) &&
2493 (VTOHFS(vp
)->hfs_private_metadata_dir
!= 0)) {
2494 --valence
; /* hide private dir */
2497 /* The 'link count' is faked */
2498 if (a
& ATTR_DIR_LINKCOUNT
)
2499 *((u_long
*)attrbufptr
)++ = 2 + valence
;
2500 if (a
& ATTR_DIR_ENTRYCOUNT
)
2501 *((u_long
*)attrbufptr
)++ = valence
;
2502 if (a
& ATTR_DIR_MOUNTSTATUS
) {
2503 if (vp
->v_mountedhere
) {
2504 *((u_long
*)attrbufptr
)++ = DIR_MNTSTATUS_MNTPOINT
;
2506 *((u_long
*)attrbufptr
)++ = 0;
2511 *attrbufptrptr
= attrbufptr
;
2516 // Pack the file attributes from the hfsCatalogInfo for the file.
2517 void PackCatalogInfoFileAttributeBlock( struct attrlist
*alist
, struct vnode
*root_vp
, struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2523 ExtendedVCB
*vcb
= VTOVCB(root_vp
);
2525 attrbufptr
= *attrbufptrptr
;
2526 varbufptr
= *varbufptrptr
;
2528 a
= alist
->fileattr
;
2529 if ( (catInfo
->nodeData
.cnd_type
== kCatalogFileNode
) && (a
!= 0) )
2532 if (a
& ATTR_FILE_LINKCOUNT
) {
2533 u_long linkcnt
= catInfo
->nodeData
.cnd_linkCount
;
2537 *((u_long
*)attrbufptr
)++ = linkcnt
;
2540 if (a
& ATTR_FILE_LINKCOUNT
) *((u_long
*)attrbufptr
)++ = 1;
2542 if (a
& ATTR_FILE_TOTALSIZE
) {
2543 *((off_t
*)attrbufptr
)++ =
2544 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
+
2545 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2547 if (a
& ATTR_FILE_ALLOCSIZE
) {
2548 *((off_t
*)attrbufptr
)++ =
2549 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
) +
2550 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2552 if (a
& ATTR_FILE_IOBLOCKSIZE
) {
2553 *((u_long
*)attrbufptr
)++ = (u_long
)(VTOHFS(root_vp
)->hfs_logBlockSize
);
2555 if (a
& ATTR_FILE_CLUMPSIZE
) {
2556 *((u_long
*)attrbufptr
)++ = vcb
->vcbClpSiz
;
2558 if (a
& ATTR_FILE_DEVTYPE
) {
2562 filetype
= (catInfo
->nodeData
.cnd_mode
& IFMT
);
2563 if (filetype
== IFCHR
|| filetype
== IFBLK
)
2564 rawdev
= (u_long
)catInfo
->nodeData
.cnd_rawDevice
;
2568 *((u_long
*)attrbufptr
)++ = rawdev
;
2570 if (a
& ATTR_FILE_FILETYPE
) {
2571 *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD */
2573 if (a
& ATTR_FILE_FORKCOUNT
) {
2574 *((u_long
*)attrbufptr
)++ = 2; /* XXX PPD */
2576 if (a
& ATTR_FILE_FORKLIST
) {
2578 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2579 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2581 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2582 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2583 ++((struct attrreference
*)attrbufptr
);
2585 if (a
& ATTR_FILE_DATALENGTH
) {
2586 *((off_t
*)attrbufptr
)++ =
2587 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
;
2589 if (a
& ATTR_FILE_DATAALLOCSIZE
) {
2590 *((off_t
*)attrbufptr
)++ =
2591 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2593 if (a
& ATTR_FILE_DATAEXTENTS
) {
2594 bcopy(&catInfo
->nodeData
.cnd_datafork
.extents
, attrbufptr
, sizeof(extentrecord
));
2595 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2597 if (a
& ATTR_FILE_RSRCLENGTH
) {
2598 *((off_t
*)attrbufptr
)++ =
2599 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2601 if (a
& ATTR_FILE_RSRCALLOCSIZE
) {
2602 *((off_t
*)attrbufptr
)++ =
2603 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2605 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2606 bcopy(&catInfo
->nodeData
.cnd_rsrcfork
.extents
, attrbufptr
, sizeof(extentrecord
));
2607 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2611 *attrbufptrptr
= attrbufptr
;
2612 *varbufptrptr
= varbufptr
;
2616 void PackFileAttributeBlock(struct attrlist
*alist
,
2618 struct hfsCatalogInfo
*catInfo
,
2619 void **attrbufptrptr
,
2620 void **varbufptrptr
) {
2621 struct hfsnode
*hp
= VTOH(vp
);
2622 FCB
*fcb
= HTOFCB(hp
);
2623 ExtendedVCB
*vcb
= HTOVCB(hp
);
2624 Boolean isHFSPlus
= (vcb
->vcbSigWord
== kHFSPlusSigWord
);
2625 void *attrbufptr
= *attrbufptrptr
;
2626 void *varbufptr
= *varbufptrptr
;
2627 attrgroup_t a
= alist
->fileattr
;
2632 if (a
& ATTR_FILE_LINKCOUNT
) {
2633 u_long linkcnt
= catInfo
->nodeData
.cnd_linkCount
;
2637 *((u_long
*)attrbufptr
)++ = linkcnt
;
2640 if (a
& ATTR_FILE_LINKCOUNT
) *((u_long
*)attrbufptr
)++ = 1;
2642 if (a
& ATTR_FILE_TOTALSIZE
) {
2643 *((off_t
*)attrbufptr
)++ =
2644 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
+
2645 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2647 if (a
& ATTR_FILE_ALLOCSIZE
) {
2648 switch (H_FORKTYPE(hp
)) {
2650 *((off_t
*)attrbufptr
)++ =
2651 (off_t
)fcb
->fcbPLen
+
2652 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2655 *((off_t
*)attrbufptr
)++ =
2656 (off_t
)fcb
->fcbPLen
+
2657 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2660 *((off_t
*)attrbufptr
)++ =
2661 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
) +
2662 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2665 if (a
& ATTR_FILE_IOBLOCKSIZE
) *((u_long
*)attrbufptr
)++ = GetLogicalBlockSize(vp
);
2666 if (a
& ATTR_FILE_CLUMPSIZE
) *((u_long
*)attrbufptr
)++ = fcb
->fcbClmpSize
;
2667 if (a
& ATTR_FILE_DEVTYPE
) {
2670 if ((vp
->v_type
== VBLK
) || (vp
->v_type
== VCHR
))
2671 rawdev
= (u_long
)catInfo
->nodeData
.cnd_rawDevice
;
2674 *((u_long
*)attrbufptr
)++ = rawdev
;
2676 if (a
& ATTR_FILE_FILETYPE
) *((u_long
*)attrbufptr
)++ = 0; /* XXX PPD */
2677 if (a
& ATTR_FILE_FORKCOUNT
) *((u_long
*)attrbufptr
)++ = 2; /* XXX PPD */
2678 if (a
& ATTR_FILE_FORKLIST
) {
2680 ((struct attrreference
*)attrbufptr
)->attr_dataoffset
= 0;
2681 ((struct attrreference
*)attrbufptr
)->attr_length
= attrlength
;
2683 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2684 (char *)varbufptr
+= attrlength
+ ((4 - (attrlength
& 3)) & 3);
2685 ++((struct attrreference
*)attrbufptr
);
2687 if (H_FORKTYPE(hp
) == kDataFork
) {
2688 if (a
& ATTR_FILE_DATALENGTH
)
2689 *((off_t
*)attrbufptr
)++ = fcb
->fcbEOF
;
2690 if (a
& ATTR_FILE_DATAALLOCSIZE
) *((off_t
*)attrbufptr
)++ = fcb
->fcbPLen
;
2691 if (a
& ATTR_FILE_DATAEXTENTS
) {
2692 bcopy ( fcb
->fcbExtents
, attrbufptr
, sizeof(extentrecord
));
2693 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2696 if (a
& ATTR_FILE_DATALENGTH
) {
2697 *((off_t
*)attrbufptr
)++ =
2698 (off_t
)catInfo
->nodeData
.cnd_datafork
.logicalSize
;
2700 if (a
& ATTR_FILE_DATAALLOCSIZE
) {
2701 *((off_t
*)attrbufptr
)++ =
2702 (off_t
)((off_t
)catInfo
->nodeData
.cnd_datafork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2704 if (a
& ATTR_FILE_DATAEXTENTS
) {
2705 bcopy(&catInfo
->nodeData
.cnd_datafork
.extents
, attrbufptr
, sizeof(extentrecord
));
2706 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2709 if (H_FORKTYPE(hp
) == kRsrcFork
) {
2710 if (a
& ATTR_FILE_RSRCLENGTH
)
2711 *((off_t
*)attrbufptr
)++ = fcb
->fcbEOF
;
2712 if (a
& ATTR_FILE_RSRCALLOCSIZE
) *((off_t
*)attrbufptr
)++ = fcb
->fcbPLen
;
2713 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2714 bcopy ( fcb
->fcbExtents
, attrbufptr
, sizeof(extentrecord
));
2715 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2718 if (a
& ATTR_FILE_RSRCLENGTH
) {
2719 *((off_t
*)attrbufptr
)++ =
2720 (off_t
)catInfo
->nodeData
.cnd_rsrcfork
.logicalSize
;
2722 if (a
& ATTR_FILE_RSRCALLOCSIZE
) {
2723 *((off_t
*)attrbufptr
)++ =
2724 (off_t
)((off_t
)catInfo
->nodeData
.cnd_rsrcfork
.totalBlocks
* (off_t
)vcb
->blockSize
);
2726 if (a
& ATTR_FILE_RSRCEXTENTS
) {
2727 bcopy(&catInfo
->nodeData
.cnd_rsrcfork
.extents
, attrbufptr
, sizeof(extentrecord
));
2728 (char *)attrbufptr
+= sizeof(extentrecord
) + ((4 - (sizeof(extentrecord
) & 3)) & 3);
2733 *attrbufptrptr
= attrbufptr
;
2734 *varbufptrptr
= varbufptr
;
2738 void PackForkAttributeBlock(struct attrlist
*alist
,
2740 struct hfsCatalogInfo
*catInfo
,
2741 void **attrbufptrptr
,
2742 void **varbufptrptr
) {
2748 // This routine takes catInfo, and alist, as inputs and packs it into an attribute block.
2749 void PackCatalogInfoAttributeBlock ( struct attrlist
*alist
, struct vnode
*root_vp
, struct hfsCatalogInfo
*catInfo
, void **attrbufptrptr
, void **varbufptrptr
)
2751 //XXX Preflight that alist only contains bits with fields in catInfo
2753 PackCommonCatalogInfoAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2755 switch ( catInfo
->nodeData
.cnd_type
)
2757 case kCatalogFolderNode
:
2758 PackCatalogInfoDirAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2761 case kCatalogFileNode
:
2762 PackCatalogInfoFileAttributeBlock( alist
, root_vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2765 default: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR not being handled... */
2766 /* XXX PPD - Panic? */
2773 void PackAttributeBlock(struct attrlist
*alist
,
2775 struct hfsCatalogInfo
*catInfo
,
2776 void **attrbufptrptr
,
2777 void **varbufptrptr
)
2779 if (alist
->volattr
!= 0) {
2780 DBG_ASSERT((vp
->v_flag
& VROOT
) != 0);
2781 PackVolumeInfo(alist
,vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2783 PackCommonAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2785 switch (vp
->v_type
) {
2787 PackDirAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2792 PackFileAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
2795 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
2796 not being handled...
2799 /* XXX PPD - Panic? */
2807 void UnpackVolumeAttributeBlock(struct attrlist
*alist
,
2808 struct vnode
*root_vp
,
2810 void **attrbufptrptr
,
2811 void **varbufptrptr
) {
2812 void *attrbufptr
= *attrbufptrptr
;
2815 if ((alist
->commonattr
== 0) && (alist
->volattr
== 0)) {
2816 return; /* Get out without dirtying the VCB */
2821 a
= alist
->commonattr
;
2823 if (a
& ATTR_CMN_SCRIPT
) {
2824 vcb
->volumeNameEncodingHint
= (u_int32_t
)*(((text_encoding_t
*)attrbufptr
)++);
2826 a
&= ~ATTR_CMN_SCRIPT
;
2829 if (a
& ATTR_CMN_CRTIME
) {
2830 vcb
->vcbCrDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2831 /* Need to update the local time also */
2832 vcb
->localCreateDate
= UTCToLocal(vcb
->vcbCrDate
);
2833 ++((struct timespec
*)attrbufptr
);
2835 a
&= ~ATTR_CMN_CRTIME
;
2838 if (a
& ATTR_CMN_MODTIME
) {
2839 vcb
->vcbLsMod
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2840 ++((struct timespec
*)attrbufptr
);
2842 a
&= ~ATTR_CMN_MODTIME
;
2845 if (a
& ATTR_CMN_BKUPTIME
) {
2846 vcb
->vcbVolBkUp
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2847 ++((struct timespec
*)attrbufptr
);
2849 a
&= ~ATTR_CMN_BKUPTIME
;
2852 if (a
& ATTR_CMN_FNDRINFO
) {
2853 bcopy (attrbufptr
, &vcb
->vcbFndrInfo
, sizeof(vcb
->vcbFndrInfo
));
2854 (char *)attrbufptr
+= sizeof(vcb
->vcbFndrInfo
);
2856 a
&= ~ATTR_CMN_FNDRINFO
;
2860 DBG_ASSERT(a
== 0); /* All common attributes for volumes must've been handled by now... */
2862 a
= alist
->volattr
& ~ATTR_VOL_INFO
;
2863 if (a
& ATTR_VOL_NAME
) {
2864 copystr(((char *)attrbufptr
) + *((u_long
*)attrbufptr
), vcb
->vcbVN
, sizeof(vcb
->vcbVN
), NULL
);
2865 (char *)attrbufptr
+= sizeof(struct attrreference
);
2867 a
&= ~ATTR_VOL_NAME
;
2871 DBG_ASSERT(a
== 0); /* All common attributes for volumes must've been handled by now... */
2873 vcb
->vcbFlags
|= 0xFF00; // Mark the VCB dirty
2879 void UnpackCommonAttributeBlock(struct attrlist
*alist
,
2881 struct hfsCatalogInfo
*catInfo
,
2882 void **attrbufptrptr
,
2883 void **varbufptrptr
) {
2884 struct hfsnode
*hp
= VTOH(vp
);
2888 attrbufptr
= *attrbufptrptr
;
2890 DBG_ASSERT(catInfo
!= NULL
);
2892 a
= alist
->commonattr
;
2893 if (a
& ATTR_CMN_SCRIPT
) {
2894 catInfo
->nodeData
.cnd_textEncoding
= (u_int32_t
)*((text_encoding_t
*)attrbufptr
)++;
2895 UpdateVolumeEncodings(VTOVCB(vp
), catInfo
->nodeData
.cnd_textEncoding
); /* Update the volume encoding */
2897 a
&= ~ATTR_CMN_SCRIPT
;
2900 if (a
& ATTR_CMN_CRTIME
) {
2901 catInfo
->nodeData
.cnd_createDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2902 VTOH(vp
)->h_meta
->h_crtime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2903 ++((struct timespec
*)attrbufptr
);
2905 a
&= ~ATTR_CMN_CRTIME
;
2908 if (a
& ATTR_CMN_MODTIME
) {
2909 catInfo
->nodeData
.cnd_contentModDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2910 VTOH(vp
)->h_meta
->h_mtime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2911 ++((struct timespec
*)attrbufptr
);
2912 hp
->h_nodeflags
&= ~IN_UPDATE
;
2914 a
&= ~ATTR_CMN_MODTIME
;
2917 if (a
& ATTR_CMN_CHGTIME
) {
2918 catInfo
->nodeData
.cnd_attributeModDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2919 VTOH(vp
)->h_meta
->h_ctime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2920 ++((struct timespec
*)attrbufptr
);
2921 hp
->h_nodeflags
&= ~IN_CHANGE
;
2923 a
&= ~ATTR_CMN_CHGTIME
;
2926 if (a
& ATTR_CMN_ACCTIME
) {
2927 catInfo
->nodeData
.cnd_accessDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2928 VTOH(vp
)->h_meta
->h_atime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2929 ++((struct timespec
*)attrbufptr
);
2930 hp
->h_nodeflags
&= ~IN_ACCESS
;
2932 a
&= ~ATTR_CMN_ACCTIME
;
2935 if (a
& ATTR_CMN_BKUPTIME
) {
2936 catInfo
->nodeData
.cnd_backupDate
= to_hfs_time((UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
);
2937 VTOH(vp
)->h_meta
->h_butime
= (UInt32
)((struct timespec
*)attrbufptr
)->tv_sec
;
2938 ++((struct timespec
*)attrbufptr
);
2940 a
&= ~ATTR_CMN_BKUPTIME
;
2943 if (a
& ATTR_CMN_FNDRINFO
) {
2944 bcopy (attrbufptr
, &catInfo
->nodeData
.cnd_finderInfo
, sizeof(catInfo
->nodeData
.cnd_finderInfo
));
2945 (char *)attrbufptr
+= sizeof(catInfo
->nodeData
.cnd_finderInfo
);
2947 a
&= ~ATTR_CMN_FNDRINFO
;
2950 if (a
& ATTR_CMN_OWNERID
) {
2951 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2952 u_int32_t uid
= (u_int32_t
)*((uid_t
*)attrbufptr
)++;
2953 if (uid
!= (uid_t
)VNOVAL
)
2954 hp
->h_meta
->h_uid
= uid
; /* catalog will get updated by hfs_chown() */
2957 ((uid_t
*)attrbufptr
)++;
2960 a
&= ~ATTR_CMN_OWNERID
;
2963 if (a
& ATTR_CMN_GRPID
) {
2964 u_int32_t gid
= (u_int32_t
)*((gid_t
*)attrbufptr
)++;
2965 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2966 if (gid
!= (gid_t
)VNOVAL
)
2967 hp
->h_meta
->h_gid
= gid
; /* catalog will get updated by hfs_chown() */
2970 a
&= ~ATTR_CMN_GRPID
;
2973 if (a
& ATTR_CMN_ACCESSMASK
) {
2974 u_int16_t mode
= (u_int16_t
)*((u_long
*)attrbufptr
)++;
2975 if (VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) {
2976 if (mode
!= (mode_t
)VNOVAL
) {
2977 hp
->h_meta
->h_mode
&= ~ALLPERMS
;
2978 hp
->h_meta
->h_mode
|= (mode
& ALLPERMS
); /* catalog will get updated by hfs_chmod() */
2982 a
&= ~ATTR_CMN_ACCESSMASK
;
2985 if (a
& ATTR_CMN_FLAGS
) {
2986 u_long flags
= *((u_long
*)attrbufptr
)++;
2987 /* Flags are settable only on HFS+ volumes. A special exception is made for the IMMUTABLE
2988 flags (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on HFS volumes as well: */
2989 if ((VTOVCB(vp
)->vcbSigWord
== kHFSPlusSigWord
) ||
2990 ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) && ((flags
& ~IMMUTABLE
) == 0))) {
2991 if (flags
!= (u_long
)VNOVAL
) {
2992 hp
->h_meta
->h_pflags
= flags
; /* catalog will get updated by hfs_chflags */
2996 a
&= ~ATTR_CMN_FLAGS
;
3002 DEBUG_BREAK_MSG(("UnpackCommonAttributes: unhandled bit: 0x%08X\n", a
));
3006 *attrbufptrptr
= attrbufptr
;
3007 // *varbufptrptr = varbufptr;
3013 void UnpackDirAttributeBlock(struct attrlist
*alist
,
3015 struct hfsCatalogInfo
*catInfo
,
3016 void **attrbufptrptr
,
3017 void **varbufptrptr
) {
3023 attrbufptr
= *attrbufptrptr
;
3024 varbufptr
= *varbufptrptr
;
3028 *attrbufptrptr
= attrbufptr
;
3029 *varbufptrptr
= varbufptr
;
3036 void UnpackFileAttributeBlock(struct attrlist
*alist
,
3038 struct hfsCatalogInfo
*catInfo
,
3039 void **attrbufptrptr
,
3040 void **varbufptrptr
) {
3046 attrbufptr
= *attrbufptrptr
;
3047 varbufptr
= *varbufptrptr
;
3051 *attrbufptrptr
= attrbufptr
;
3052 *varbufptrptr
= varbufptr
;
3059 void UnpackForkAttributeBlock(struct attrlist
*alist
,
3061 struct hfsCatalogInfo
*catInfo
,
3062 void **attrbufptrptr
,
3063 void **varbufptrptr
) {
3069 attrbufptr
= *attrbufptrptr
;
3070 varbufptr
= *varbufptrptr
;
3074 *attrbufptrptr
= attrbufptr
;
3075 *varbufptrptr
= varbufptr
;
3081 void UnpackAttributeBlock(struct attrlist
*alist
,
3083 struct hfsCatalogInfo
*catInfo
,
3084 void **attrbufptrptr
,
3085 void **varbufptrptr
) {
3088 if (alist
->volattr
!= 0) {
3089 UnpackVolumeAttributeBlock(alist
, vp
, VTOVCB(vp
), attrbufptrptr
, varbufptrptr
);
3093 /* We're dealing with a vnode object here: */
3094 UnpackCommonAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3097 switch (vp
->v_type
) {
3099 UnpackDirAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3103 /* case VCPLX: */ /* XXX PPD TBC */
3104 UnpackFileAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3108 UnpackForkAttributeBlock(alist
, vp
, catInfo
, attrbufptrptr
, varbufptrptr
);
3111 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
3112 not being handled...
3115 /* XXX PPD - Panic? */
3123 unsigned long BestBlockSizeFit(unsigned long allocationBlockSize
,
3124 unsigned long blockSizeLimit
,
3125 unsigned long baseMultiple
) {
3127 Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the
3128 specified limit but still an even multiple of the baseMultiple.
3130 int baseBlockCount
, blockCount
;
3131 unsigned long trialBlockSize
;
3133 if (allocationBlockSize
% baseMultiple
!= 0) {
3135 Whoops: the allocation blocks aren't even multiples of the specified base:
3136 no amount of dividing them into even parts will be a multiple, either then!
3138 return 512; /* Hope for the best */
3141 /* Try the obvious winner first, to prevent 12K allocation blocks, for instance,
3142 from being handled as two 6K logical blocks instead of 3 4K logical blocks.
3143 Even though the former (the result of the loop below) is the larger allocation
3144 block size, the latter is more efficient: */
3145 if (allocationBlockSize
% PAGE_SIZE
== 0) return PAGE_SIZE
;
3147 /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */
3148 baseBlockCount
= allocationBlockSize
/ baseMultiple
; /* Now guaranteed to be an even multiple */
3150 for (blockCount
= baseBlockCount
; blockCount
> 0; --blockCount
) {
3151 trialBlockSize
= blockCount
* baseMultiple
;
3152 if (allocationBlockSize
% trialBlockSize
== 0) { /* An even multiple? */
3153 if ((trialBlockSize
<= blockSizeLimit
) &&
3154 (trialBlockSize
% baseMultiple
== 0)) {
3155 return trialBlockSize
;
3160 /* Note: we should never get here, since blockCount = 1 should always work,
3161 but this is nice and safe and makes the compiler happy, too ... */
3167 * To make the HFS Plus filesystem follow UFS unlink semantics, a remove
3168 * of an active vnode is translated to a move/rename so the file appears
3169 * deleted. The destination folder for these move/renames is setup here
3170 * and a reference to it is place in hfsmp->hfs_private_metadata_dir.
3173 FindMetaDataDirectory(ExtendedVCB
*vcb
)
3176 hfsCatalogInfo catInfo
;
3177 HFSCatalogNodeID dirID
;
3178 u_int32_t metadata_createdate
;
3181 if (vcb
->vcbSigWord
!= kHFSPlusSigWord
)
3185 metadata_createdate
= 0;
3186 strncpy(namep
, HFSPLUS_PRIVATE_DIR
, sizeof(namep
));
3187 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
3188 catInfo
.hint
= kNoHint
;
3190 /* lock catalog b-tree */
3191 retval
= hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_SHARED
, current_proc());
3192 if (retval
) goto Err_Exit
;
3194 if (hfs_getcatalog(vcb
, kRootDirID
, namep
, -1, &catInfo
) == 0) {
3195 dirID
= catInfo
.nodeData
.cnd_nodeID
;
3196 metadata_createdate
= catInfo
.nodeData
.cnd_createDate
;
3197 } else if (VCBTOHFS(vcb
)->hfs_fs_ronly
== 0) {
3198 if (CreateCatalogNode(vcb
, kRootDirID
, namep
, kCatalogFolderNode
, &dirID
, &catInfo
.hint
, 0) == 0) {
3199 catInfo
.hint
= kNoHint
;
3200 if (hfs_getcatalog(vcb
, kRootDirID
, namep
, -1, &catInfo
) == 0) {
3202 /* create date is later used for validation */
3203 catInfo
.nodeData
.cnd_createDate
= vcb
->vcbCrDate
;
3204 metadata_createdate
= catInfo
.nodeData
.cnd_createDate
;
3206 /* directory with no permissions owned by root */
3207 catInfo
.nodeData
.cnd_mode
= IFDIR
;
3208 catInfo
.nodeData
.cnd_adminFlags
= (SF_IMMUTABLE
>> 16);
3210 /* hidden and off the desktop view */
3211 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frLocation
.v
= SWAP_BE16 (22460);
3212 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frLocation
.h
= SWAP_BE16 (22460);
3213 ((struct DInfo
*)(&catInfo
.nodeData
.cnd_finderInfo
))->frFlags
|= SWAP_BE16 (kIsInvisible
+ kNameLocked
);
3215 (void) UpdateCatalogNode(vcb
, kRootDirID
, namep
, catInfo
.hint
, &catInfo
.nodeData
);
3220 /* unlock catalog b-tree */
3221 (void) hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3223 VCBTOHFS(vcb
)->hfs_metadata_createdate
= metadata_createdate
;
3225 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3232 RemovedMetaDataDirectory(ExtendedVCB
*vcb
)
3235 hfsCatalogInfo catInfo
;
3238 strncpy(name
, HFSPLUS_PRIVATE_DIR
, sizeof(name
));
3239 INIT_CATALOGDATA(&catInfo
.nodeData
, kCatNameNoCopyName
);
3241 /* lock catalog b-tree */
3242 retval
= hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_SHARED
, current_proc());
3243 if (retval
) goto Err_Exit
;
3245 /* If the HFSPLUSMETADATAFOLDER exists then delete it. */
3246 retval
= GetCatalogNode(vcb
, kRootDirID
, name
, strlen(name
), kNoHint
,
3247 &catInfo
.nodeData
, &catInfo
.hint
);
3248 if (retval
== 0 && (catInfo
.nodeData
.cnd_type
== kCatalogFolderNode
)) {
3249 (void) DeleteCatalogNode(vcb
, kRootDirID
, name
, catInfo
.hint
);
3250 printf("hfs_mount: removed \"%s\" from hfs volume \"%s\"\n", name
, vcb
->vcbVN
);
3253 /* unlock catalog b-tree */
3254 (void) hfs_metafilelocking(VCBTOHFS(vcb
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3257 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3261 * This will return the correct logical block size for a given vnode.
3262 * For most files, it is the allocation block size, for meta data like
3263 * BTrees, this is kept as part of the BTree private nodeSize
3266 GetLogicalBlockSize(struct vnode
*vp
)
3268 u_int32_t logBlockSize
;
3270 DBG_ASSERT(vp
!= NULL
);
3272 /* start with default */
3273 logBlockSize
= VTOHFS(vp
)->hfs_logBlockSize
;
3275 if (vp
->v_flag
& VSYSTEM
) {
3276 if (VTOH(vp
)->fcbBTCBPtr
!= NULL
) {
3277 BTreeInfoRec bTreeInfo
;
3280 * We do not lock the BTrees, because if we are getting block..then the tree
3281 * should be locked in the first place.
3282 * We just want the nodeSize wich will NEVER change..so even if the world
3283 * is changing..the nodeSize should remain the same. Which argues why lock
3284 * it in the first place??
3287 (void) BTGetInformation (VTOFCB(vp
), kBTreeInfoVersion
, &bTreeInfo
);
3289 logBlockSize
= bTreeInfo
.nodeSize
;
3291 } else if (H_FILEID(VTOH(vp
)) == kHFSAllocationFileID
) {
3292 logBlockSize
= VTOVCB(vp
)->vcbVBMIOSize
;
3296 DBG_ASSERT(logBlockSize
> 0);
3298 return logBlockSize
;
3302 * Map HFS Common errors (negative) to BSD error codes (positive).
3303 * Positive errors (ie BSD errors) are passed through unchanged.
3305 short MacToVFSError(OSErr err
)
3309 DBG_ERR(("MacToVFSError: passing error #%d unchanged...\n", err
));
3315 DBG_ERR(("MacToVFSError: mapping error code %d...\n", err
));
3319 case dirFulErr
: /* -33 */
3320 case dskFulErr
: /* -34 */
3321 case btNoSpaceAvail
: /* -32733 */
3322 case fxOvFlErr
: /* -32750 */
3323 return ENOSPC
; /* +28 */
3325 case btBadNode
: /* -32731 */
3326 case ioErr
: /* -36 */
3327 return EIO
; /* +5 */
3329 case mFulErr
: /* -41 */
3330 case memFullErr
: /* -108 */
3331 return ENOMEM
; /* +12 */
3333 case tmfoErr
: /* -42 */
3334 /* Consider EMFILE (Too many open files, 24)? */
3335 return ENFILE
; /* +23 */
3337 case nsvErr
: /* -35 */
3338 case fnfErr
: /* -43 */
3339 case dirNFErr
: /* -120 */
3340 case fidNotFound
: /* -1300 */
3341 return ENOENT
; /* +2 */
3343 case wPrErr
: /* -44 */
3344 case vLckdErr
: /* -46 */
3345 case fsDSIntErr
: /* -127 */
3346 return EROFS
; /* +30 */
3348 case opWrErr
: /* -49 */
3349 case fLckdErr
: /* -45 */
3350 return EACCES
; /* +13 */
3352 case permErr
: /* -54 */
3353 case wrPermErr
: /* -61 */
3354 return EPERM
; /* +1 */
3356 case fBsyErr
: /* -47 */
3357 return EBUSY
; /* +16 */
3359 case dupFNErr
: /* -48 */
3360 case fidExists
: /* -1301 */
3361 case cmExists
: /* -32718 */
3362 case btExists
: /* -32734 */
3363 return EEXIST
; /* +17 */
3365 case rfNumErr
: /* -51 */
3366 return EBADF
; /* +9 */
3368 case notAFileErr
: /* -1302 */
3369 return EISDIR
; /* +21 */
3371 case cmNotFound
: /* -32719 */
3372 case btNotFound
: /* -32735 */
3373 return ENOENT
; /* 28 */
3375 case cmNotEmpty
: /* -32717 */
3376 return ENOTEMPTY
; /* 66 */
3378 case cmFThdDirErr
: /* -32714 */
3379 return EISDIR
; /* 21 */
3381 case fxRangeErr
: /* -32751 */
3384 case bdNamErr
: /* -37 */
3385 return ENAMETOOLONG
; /* 63 */
3387 case fnOpnErr
: /* -38 */
3388 case eofErr
: /* -39 */
3389 case posErr
: /* -40 */
3390 case paramErr
: /* -50 */
3391 case badMDBErr
: /* -60 */
3392 case badMovErr
: /* -122 */
3393 case sameFileErr
: /* -1306 */
3394 case badFidErr
: /* -1307 */
3395 case fileBoundsErr
: /* -1309 */
3396 return EINVAL
; /* +22 */
3399 DBG_UTILS(("Unmapped MacOS error: %d\n", err
));
3400 return EIO
; /* +5 */
3406 * All of our debugging functions
3411 void debug_vn_status (char* introStr
, struct vnode
*vn
)
3413 DBG_VOP(("%s:\t",introStr
));
3416 if (vn
->v_tag
!= VT_HFS
)
3418 DBG_VOP(("NON-HFS VNODE Ox%08lX\n", (unsigned long)vn
));
3420 else if(vn
->v_tag
==VT_HFS
&& (vn
->v_data
==NULL
|| VTOH((vn
))->h_valid
!= HFS_VNODE_MAGIC
))
3422 DBG_VOP(("BAD VNODE PRIVATE DATA!!!!\n"));
3426 DBG_VOP(("r: %d & ", vn
->v_usecount
));
3427 if (lockstatus(&VTOH(vn
)->h_lock
))
3429 DBG_VOP_CONT(("is L\n"));
3433 DBG_VOP_CONT(("is U\n"));
3439 DBG_VOP(("vnode is NULL\n"));
3443 void debug_vn_print (char* introStr
, struct vnode
*vn
)
3445 // DBG_FUNC_NAME("DBG_VN_PRINT");
3446 DBG_ASSERT (vn
!= NULL
);
3447 DBG_VFS(("%s: ",introStr
));
3448 DBG_VFS_CONT(("vnode: 0x%x is a ", (uint
)vn
));
3452 DBG_VFS_CONT(("%s","UFS"));
3455 DBG_VFS_CONT(("%s","HFS"));
3458 DBG_VFS_CONT(("%s","UNKNOWN"));
3462 DBG_VFS_CONT((" vnode\n"));
3463 if (vn
->v_tag
==VT_HFS
)
3465 if (vn
->v_data
==NULL
)
3467 DBG_VFS(("BAD VNODE PRIVATE DATA!!!!\n"));
3471 DBG_VFS((" Name: %s Id: %ld ",H_NAME(VTOH(vn
)), H_FILEID(VTOH(vn
))));
3477 DBG_VFS_CONT(("Refcount: %d\n", vn
->v_usecount
));
3478 if (VOP_ISLOCKED(vn
))
3480 DBG_VFS((" The vnode is locked\n"));
3484 DBG_VFS((" The vnode is not locked\n"));
3488 void debug_rename_test_locks (char* introStr
,
3499 DBG_VOP(("\t%s: ", introStr
));
3500 if (fvp
) {if(lockstatus(&VTOH(fvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3501 if (fdvp
) {if(lockstatus(&VTOH(fdvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3502 if (tvp
) {if(lockstatus(&VTOH(tvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3503 if (tdvp
) {if(lockstatus(&VTOH(tdvp
)->h_lock
)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3504 DBG_VFS_CONT(("\n"));
3507 if (lockstatus(&VTOH(fvp
)->h_lock
)) {
3508 if (fstatus
==VOPDBG_UNLOCKED
) {
3509 DBG_VOP(("\tfvp should be NOT LOCKED and it is\n"));
3511 } else if (fstatus
== VOPDBG_LOCKED
) {
3512 DBG_VOP(("\tfvp should be LOCKED and it isnt\n"));
3517 if (lockstatus(&VTOH(fdvp
)->h_lock
)) {
3518 if (fdstatus
==VOPDBG_UNLOCKED
) {
3519 DBG_VOP(("\tfdvp should be NOT LOCKED and it is\n"));
3521 } else if (fdstatus
== VOPDBG_LOCKED
) {
3522 DBG_VOP(("\tfdvp should be LOCKED and it isnt\n"));
3527 if (lockstatus(&VTOH(tvp
)->h_lock
)) {
3528 if (tstatus
==VOPDBG_UNLOCKED
) {
3529 DBG_VOP(("\ttvp should be NOT LOCKED and it is\n"));
3531 } else if (tstatus
== VOPDBG_LOCKED
) {
3532 DBG_VOP(("\ttvp should be LOCKED and it isnt\n"));
3537 if (lockstatus(&VTOH(tdvp
)->h_lock
)) {
3538 if (tdstatus
==VOPDBG_UNLOCKED
) {
3539 DBG_VOP(("\ttdvp should be NOT LOCKED and it is\n"));
3541 } else if (tdstatus
== VOPDBG_LOCKED
) {
3542 DBG_VOP(("\ttdvp should be LOCKED and it isnt\n"));
3548 #endif /* HFS_DIAGNOSTIC */
3552 void debug_check_buffersizes(struct vnode
*vp
, struct hfsnode
*hp
, struct buf
*bp
) {
3553 DBG_ASSERT(bp
->b_validoff
== 0);
3554 DBG_ASSERT(bp
->b_dirtyoff
== 0);
3555 DBG_ASSERT((bp
->b_bcount
== HTOHFS(hp
)->hfs_logBlockSize
) ||
3556 ((bp
->b_bcount
% 512 == 0) &&
3557 (bp
->b_validend
> 0) &&
3558 (bp
->b_dirtyend
> 0) &&
3559 (bp
->b_bcount
< HTOHFS(hp
)->hfs_logBlockSize
)));
3561 if (bp
->b_validend
== 0) {
3562 DBG_ASSERT(bp
->b_dirtyend
== 0);
3564 DBG_ASSERT(bp
->b_validend
== bp
->b_bcount
);
3565 DBG_ASSERT(bp
->b_dirtyend
<= bp
->b_bcount
);
3570 void debug_check_blocksizes(struct vnode
*vp
) {
3571 struct hfsnode
*hp
= VTOH(vp
);
3574 if (vp
->v_flag
& VSYSTEM
) return;
3576 for (bp
= vp
->v_cleanblkhd
.lh_first
; bp
!= NULL
; bp
= bp
->b_vnbufs
.le_next
) {
3577 debug_check_buffersizes(vp
, hp
, bp
);
3580 for (bp
= vp
->v_dirtyblkhd
.lh_first
; bp
!= NULL
; bp
= bp
->b_vnbufs
.le_next
) {
3581 debug_check_buffersizes(vp
, hp
, bp
);
3585 void debug_check_catalogdata(struct CatalogNodeData
*cat
) {
3587 if (cat
->cnm_nameptr
== NULL
) {
3588 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3590 else if (cat
->cnm_nameptr
== cat
->cnm_namespace
) {
3591 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3594 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == kCatNameIsAllocated
);
3597 if (cat
->cnm_nameptr
) {
3598 DBG_ASSERT(strlen(cat
->cnm_nameptr
) == cat
->cnm_length
);
3601 if (cat
->cnm_flags
& kCatNameIsConsumed
) {
3602 DBG_ASSERT((cat
->cnm_flags
& kCatNameIsAllocated
) == 0);
3605 if (cat
->cnm_flags
& kCatNameNoCopyName
) {
3606 DBG_ASSERT((cat
->cnm_flags
& (kCatNameIsAllocated
|kCatNameIsConsumed
|kCatNameIsMangled
)) == 0);
3607 DBG_ASSERT(cat
->cnm_length
== 0);
3608 DBG_ASSERT(cat
->cnm_nameptr
== 0);
3609 DBG_ASSERT(strlen(cat
->cnm_namespace
) == 0);
3614 extern void hfs_vhash_dbg(struct hfsnode
*hp
);
3616 /* Checks the valicity of a hfs vnode */
3617 void debug_check_vnode(struct vnode
*vp
, int stage
) {
3623 if (VTOHFS(vp
)->hfs_mount_flags
& kHFSBootVolumeInconsistentMask
)
3624 DEBUG_BREAK_MSG(("Volume is damaged!"));
3628 DEBUG_BREAK_MSG(("Null vnode"));
3629 if (vp
->v_tag
!= VT_HFS
)
3630 DEBUG_BREAK_MSG(("Not a HFS vnode, it is a %d", vp
->v_tag
));
3631 if (vp
->v_data
==NULL
)
3632 DEBUG_BREAK_MSG(("v_data is NULL"));
3636 if (hp
->h_valid
!= HFS_VNODE_MAGIC
)
3637 DEBUG_BREAK_MSG(("Bad Formed HFS node"));
3638 if (hp
->h_vp
==NULL
|| hp
->h_vp
!=vp
)
3639 DEBUG_BREAK_MSG(("Bad hfsnode vnode pte"));
3640 if (hp
->h_meta
== NULL
)
3641 DEBUG_BREAK_MSG(("Bad hfsnode meta ptr"));
3642 switch (H_FORKTYPE(hp
)) {
3645 if ((hp
->h_meta
->h_siblinghead
.cqh_first
== NULL
) || (hp
->h_meta
->h_siblinghead
.cqh_last
== NULL
))
3646 DEBUG_BREAK_MSG(("Null sibling header"));
3647 if ((hp
->h_sibling
.cqe_next
==NULL
) || (hp
->h_sibling
.cqe_prev
==NULL
))
3648 DEBUG_BREAK_MSG(("Null sibling list"));
3649 if (hp
->h_meta
->h_usecount
<1 || hp
->h_meta
->h_usecount
>2)
3650 DEBUG_BREAK_MSG(("Bad sibling usecount"));
3654 if ((hp
->h_meta
->h_siblinghead
.cqh_first
!= NULL
) || (hp
->h_meta
->h_siblinghead
.cqh_last
!= NULL
))
3655 DEBUG_BREAK_MSG(("Non Null sibling header"));
3656 if ((hp
->h_sibling
.cqe_next
!=NULL
) || (hp
->h_sibling
.cqe_prev
!=NULL
))
3657 DEBUG_BREAK_MSG(("Null sibling list"));
3658 if (hp
->h_meta
->h_usecount
!=1)
3659 DEBUG_BREAK_MSG(("Bad usecount"));
3663 DEBUG_BREAK_MSG(("Bad hfsnode fork type"));
3667 if (hp
->h_meta
->h_devvp
== NULL
)
3668 DEBUG_BREAK_MSG(("Bad hfsnode dev vnode"));
3670 DEBUG_BREAK_MSG(("Bad dev id"));
3671 if (H_FILEID(hp
) == 0)
3672 DEBUG_BREAK_MSG(("Bad file id"));
3674 if (((hp
->h_meta
->h_metaflags
& IN_DATANODE
)==0) && (H_DIRID(hp
) == 0) && (H_FILEID(hp
) != 1))
3675 DEBUG_BREAK_MSG(("Bad dir id"));
3677 if (hp
->h_meta
->h_namePtr
== NULL
&& hp
->h_meta
->h_namelen
!=0)
3678 DEBUG_BREAK_MSG(("hfs meta h_namelen is not 0"));
3679 if (hp
->h_meta
->h_namePtr
!= NULL
&& strlen(hp
->h_meta
->h_namePtr
) != hp
->h_meta
->h_namelen
)
3680 DEBUG_BREAK_MSG(("Bad hfs meta h_namelen"));
3682 /* Check the hash */
3685 /* Check to see if we want to compare with the disk */
3688 hfsCatalogInfo catInfo
;
3690 INIT_CATALOGDATA(&catInfo
.nodeData
, 0);
3693 if (hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_SHARED
, current_proc()))
3696 if (hfs_getcatalog(VTOVCB(vp
), H_DIRID(hp
), hp
->h_meta
->h_namePtr
, hp
->h_meta
->h_namelen
, &catInfo
))
3697 DEBUG_BREAK_MSG(("Could not find hfsnode Catalog record"));
3699 (void) hfs_metafilelocking(VTOHFS(vp
), kHFSCatalogFileID
, LK_RELEASE
, current_proc());
3701 if (H_FILEID(hp
) != catInfo
.nodeData
.cnd_nodeID
)
3702 DEBUG_BREAK_MSG(("hfsnode catalog node id mismatch"));
3703 if (H_DIRID(hp
) != catInfo
.nodeData
.cnm_parID
)
3704 DEBUG_BREAK_MSG(("hfsnode catalog dir id mismatch"));
3705 if (strcmp(hp
->h_meta
->h_namePtr
, catInfo
.nodeData
.cnm_nameptr
) != 0)
3706 DEBUG_BREAK_MSG(("hfsnode catalog name mismatch"));
3707 /* Check dates too??? */
3709 CLEAN_CATALOGDATA(&catInfo
.nodeData
);
3716 for(i
= 0, size
= 0; i
< kHFSPlusExtentDensity
; i
++)
3718 size
+= hp
->fcbExtents
[i
].blockCount
;
3721 if (hp
->fcbEOF
> hp
->fcbPLen
)
3722 DEBUG_BREAK_MSG(("fcbPLen is smaller than fcbEOF"));
3724 if (hp
->fcbExtents
[kHFSPlusExtentDensity
-1].blockCount
== 0) {
3725 if ((off_t
)size
* (off_t
)VTOVCB(vp
)->blockSize
!= hp
->fcbPLen
)
3726 DEBUG_BREAK_MSG(("fcbPLen does not match extents"));
3728 if ( hp
->fcbPLen
< (off_t
)size
* (off_t
)VTOVCB(vp
)->blockSize
)
3729 DEBUG_BREAK_MSG(("fcbPLen is smaller than extents"));
3731 for(i
= 0; i
< kHFSPlusExtentDensity
; i
++)
3733 if (hp
->fcbExtents
[i
].blockCount
== 0 || hp
->fcbExtents
[i
].startBlock
== 0)
3736 if ((VTOVCB(vp
)->vcbSigWord
== kHFSSigWord
) && i
> kHFSExtentDensity
)
3737 DEBUG_BREAK_MSG(("Illegal value in extents for ordinary HFS"));
3738 if (i
> kHFSPlusExtentDensity
) {
3739 for(; i
< kHFSPlusExtentDensity
; i
++)
3741 if (hp
->fcbExtents
[i
].blockCount
!= 0 || hp
->fcbExtents
[i
].startBlock
!= 0)
3742 DEBUG_BREAK_MSG(("Illegal value in extents"));
3749 if (0 && vp
->v_flag
& VSYSTEM
) {
3752 BTGetInformation(hp
, 0, &info
);
3753 if (hp
->fcbBTCBPtr
== NULL
)
3754 DEBUG_BREAK_MSG(("Null fcbBTCBPtr"));
3755 if (H_HINT(hp
) == 0)
3756 DEBUG_BREAK_MSG(("hint is 0"));
3757 if (H_HINT(hp
) > info
.numNodes
)
3758 DEBUG_BREAK_MSG(("hint > numNodes"));
3763 #endif /* HFS_DIAGNOSTIC */