]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfs_vfsutils.c
e69c2e046cd30e434f6877d4ce8c6eb8faeef7e8
[apple/xnu.git] / bsd / hfs / hfs_vfsutils.c
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* @(#)hfs_vfsutils.c 4.0
23 *
24 * (c) 1997-2000 Apple Computer, Inc. All Rights Reserved
25 *
26 * hfs_vfsutils.c -- Routines that go between the HFS layer and the VFS.
27 *
28 * Change History (most recent first):
29 *
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
97 * than 31 characters.
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()
108 *
109 */
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>
118 #include <sys/buf.h>
119 #include <sys/ubc.h>
120 #include <sys/unistd.h>
121
122 #include "hfs.h"
123 #include "hfs_dbg.h"
124 #include "hfs_mount.h"
125 #include "hfs_endian.h"
126
127 #include "hfscommon/headers/FileMgrInternal.h"
128 #include "hfscommon/headers/BTreesInternal.h"
129 #include "hfscommon/headers/HFSUnicodeWrappers.h"
130
131 #define SUPPORTS_MAC_ALIASES 0
132 #define kMaxSecsForFsync 5
133
134 #define BYPASSBLOCKINGOPTIMIZATION 0
135
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;
141
142 OSErr ValidMasterDirectoryBlock( HFSMasterDirectoryBlock *mdb );
143
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);
148
149 extern int hfs_vinit( struct mount *mntp, int (**specops)(void *), int (**fifoops)(), struct vnode **vpp);
150
151 extern OSErr GetVolumeNameFromCatalog(ExtendedVCB *vcb);
152
153 static int InitMetaFileVNode(struct vnode *vp, off_t eof, u_long clumpSize, const HFSPlusExtentRecord extents,
154 HFSCatalogNodeID fileID, void * keyCompareProc);
155
156 static void ReleaseMetaFileVNode(struct vnode *vp);
157
158 static void RemovedMetaDataDirectory(ExtendedVCB *vcb);
159
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);
164
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);
170
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 //*******************************************************************************
176
177 //*******************************************************************************
178 // Routine: hfs_MountHFSVolume
179 //
180 //
181 //*******************************************************************************
182
183 OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb,
184 struct proc *p)
185 {
186 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
187 struct vnode *tmpvnode;
188 OSErr err;
189 HFSPlusExtentRecord extents;
190 ByteCount utf8chars;
191 DBG_FUNC_NAME("hfs_MountHFSVolume");
192 DBG_PRINT_FUNC_NAME();
193
194 if (hfsmp == nil || mdb == nil) /* exit if bad paramater */
195 return (EINVAL);
196
197 err = ValidMasterDirectoryBlock( mdb ); /* make sure this is an HFS disk */
198 if (err)
199 return MacToVFSError(err);
200
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))
203 return (EINVAL);
204
205 /*
206 * The MDB seems OK: transfer info from it into VCB
207 * Note - the VCB starts out clear (all zeros)
208 *
209 */
210 vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev);
211
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 */
235 /*
236 * Copy the drVN field, which is a Pascal String to the vcb, which is a cstring
237 */
238
239 /* convert hfs encoded name into UTF-8 string */
240 err = hfs_to_utf8(vcb, mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN);
241 /*
242 * When an HFS name cannot be encoded with the current
243 * volume encoding we use MacRoman as a fallback.
244 */
245 if (err || (utf8chars == 0))
246 (void) mac_roman_to_utf8(mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN);
247
248 // Initialize our dirID/nodePtr cache associated with this volume.
249 err = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
250 ReturnIfError( err );
251
252 hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
253 vcb->vcbVBMIOSize = kHFSBlockSize;
254
255 // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
256 VCB_LOCK_INIT(vcb);
257
258 /*
259 * Set up Extents B-tree vnode...
260 */
261 err = GetInitializedVNode(hfsmp, &tmpvnode);
262 if (err) goto MtVolErr;
263 /* HFSToHFSPlusExtents(mdb->drXTExtRec, extents); */ /* ASDFADSFSD */
264 extents[0].startBlock = SWAP_BE16 (mdb->drXTExtRec[0].startBlock);
265 extents[0].blockCount = SWAP_BE16 (mdb->drXTExtRec[0].blockCount);
266 extents[1].startBlock = SWAP_BE16 (mdb->drXTExtRec[1].startBlock);
267 extents[1].blockCount = SWAP_BE16 (mdb->drXTExtRec[1].blockCount);
268 extents[2].startBlock = SWAP_BE16 (mdb->drXTExtRec[2].startBlock);
269 extents[2].blockCount = SWAP_BE16 (mdb->drXTExtRec[2].blockCount);
270
271 err = InitMetaFileVNode(tmpvnode, SWAP_BE32 (mdb->drXTFlSize), SWAP_BE32 (mdb->drXTClpSiz), extents,
272 kHFSExtentsFileID, CompareExtentKeys);
273 if (err) goto MtVolErr;
274
275 /*
276 * Set up Catalog B-tree vnode...
277 */
278 err = GetInitializedVNode(hfsmp, &tmpvnode);
279 if (err) goto MtVolErr;
280 /* HFSToHFSPlusExtents(mdb->drCTExtRec, extents); */
281 extents[0].startBlock = SWAP_BE16 (mdb->drCTExtRec[0].startBlock);
282 extents[0].blockCount = SWAP_BE16 (mdb->drCTExtRec[0].blockCount);
283 extents[1].startBlock = SWAP_BE16 (mdb->drCTExtRec[1].startBlock);
284 extents[1].blockCount = SWAP_BE16 (mdb->drCTExtRec[1].blockCount);
285 extents[2].startBlock = SWAP_BE16 (mdb->drCTExtRec[2].startBlock);
286 extents[2].blockCount = SWAP_BE16 (mdb->drCTExtRec[2].blockCount);
287
288 err = InitMetaFileVNode(tmpvnode, SWAP_BE32 (mdb->drCTFlSize), SWAP_BE32 (mdb->drCTClpSiz), extents,
289 kHFSCatalogFileID, CompareCatalogKeys);
290 if (err) goto MtVolErr;
291
292 /* mark the volume dirty (clear clean unmount bit) */
293 vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask;
294
295 /* Remove any MetaDataDirectory from hfs disks */
296 if (hfsmp->hfs_fs_ronly == 0)
297 RemovedMetaDataDirectory(vcb);
298
299 /*
300 * all done with b-trees so we can unlock now...
301 */
302 VOP_UNLOCK(vcb->catalogRefNum, 0, p);
303 VOP_UNLOCK(vcb->extentsRefNum, 0, p);
304
305 err = noErr;
306
307 if ( err == noErr )
308 {
309 if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected
310 {
311 MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
312 }
313 }
314 goto CmdDone;
315
316 //-- Release any resources allocated so far before exiting with an error:
317 MtVolErr:;
318 ReleaseMetaFileVNode(vcb->catalogRefNum);
319 ReleaseMetaFileVNode(vcb->extentsRefNum);
320
321 CmdDone:;
322 return( err );
323 }
324
325 //*******************************************************************************
326 // Routine: hfs_MountHFSPlusVolume
327 //
328 //
329 //*******************************************************************************
330
331 OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
332 off_t embeddedOffset, off_t disksize, struct proc *p)
333 {
334 register ExtendedVCB *vcb;
335 HFSPlusForkData *fdp;
336 struct vnode *tmpvnode;
337 OSErr retval;
338
339 if (hfsmp == nil || vhp == nil) /* exit if bad paramater */
340 return (EINVAL);
341
342 DBG_VFS(("hfs_MountHFSPlusVolume: signature=0x%x, version=%d, blockSize=%ld\n",
343 SWAP_BE16 (vhp->signature),
344 SWAP_BE16 (vhp->version),
345 SWAP_BE32 (vhp->blockSize)));
346
347 retval = ValidVolumeHeader(vhp); /* make sure this is an HFS Plus disk */
348 if (retval)
349 return MacToVFSError(retval);
350
351 /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */
352 if (hfsmp->hfs_fs_ronly == 0 && (SWAP_BE32 (vhp->attributes) & kHFSVolumeUnmountedMask) == 0)
353 return (EINVAL);
354
355 /* Make sure we can live with the physical block size. */
356 if ((disksize & (hfsmp->hfs_phys_block_size - 1)) ||
357 (embeddedOffset & (hfsmp->hfs_phys_block_size - 1)) ||
358 (SWAP_BE32(vhp->blockSize) < hfsmp->hfs_phys_block_size)) {
359 return (ENXIO);
360 }
361
362 /*
363 * The VolumeHeader seems OK: transfer info from it into VCB
364 * Note - the VCB starts out clear (all zeros)
365 */
366 vcb = HFSTOVCB(hfsmp);
367
368 //DBG_ASSERT((hfsmp->hfs_raw_dev & 0xFFFF0000) == 0);
369 vcb->vcbVRefNum = MAKE_VREFNUM(hfsmp->hfs_raw_dev);
370 vcb->vcbSigWord = SWAP_BE16 (vhp->signature);
371 vcb->vcbLsMod = SWAP_BE32 (vhp->modifyDate);
372 vcb->vcbAtrb = (UInt16) SWAP_BE32 (vhp->attributes); // VCB only uses lower 16 bits
373 vcb->vcbClpSiz = SWAP_BE32 (vhp->rsrcClumpSize);
374 vcb->vcbNxtCNID = SWAP_BE32 (vhp->nextCatalogID);
375 vcb->vcbVolBkUp = SWAP_BE32 (vhp->backupDate);
376 vcb->vcbWrCnt = SWAP_BE32 (vhp->writeCount);
377 vcb->vcbFilCnt = SWAP_BE32 (vhp->fileCount);
378 vcb->vcbDirCnt = SWAP_BE32 (vhp->folderCount);
379
380 /* copy 32 bytes of Finder info */
381 bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));
382
383 vcb->vcbAlBlSt = 0; /* hfs+ allocation blocks start at first block of volume */
384 vcb->vcbWrCnt++; /* compensate for write of Volume Header on last flush */
385
386 VCB_LOCK_INIT(vcb);
387
388 /* Now fill in the Extended VCB info */
389 vcb->nextAllocation = SWAP_BE32 (vhp->nextAllocation);
390 vcb->totalBlocks = SWAP_BE32 (vhp->totalBlocks);
391 vcb->freeBlocks = SWAP_BE32 (vhp->freeBlocks);
392 vcb->blockSize = SWAP_BE32 (vhp->blockSize);
393 vcb->checkedDate = SWAP_BE32 (vhp->checkedDate);
394 vcb->encodingsBitmap = SWAP_BE64 (vhp->encodingsBitmap);
395
396 vcb->hfsPlusIOPosOffset = embeddedOffset;
397
398 vcb->localCreateDate = SWAP_BE32 (vhp->createDate); /* in local time, not GMT! */
399
400 /* Update the logical block size in the mount struct (currently set up from the wrapper MDB)
401 using the new blocksize value: */
402 hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
403 vcb->vcbVBMIOSize = min(vcb->blockSize, MAXPHYSIO);
404
405 // XXX PPD: Should check here for hardware lock flag and set flags in VCB/MP appropriately
406 // vcb->vcbAtrb |= kVolumeHardwareLockMask; // XXX this line for debugging only!!!!
407
408 // Initialize our dirID/nodePtr cache associated with this volume.
409 retval = InitMRUCache( sizeof(UInt32), kDefaultNumMRUCacheBlocks, &(vcb->hintCachePtr) );
410 if (retval != noErr) goto ErrorExit;
411
412 /*
413 * Set up Extents B-tree vnode...
414 */
415 retval = GetInitializedVNode(hfsmp, &tmpvnode);
416 if (retval) goto ErrorExit;
417 fdp = &vhp->extentsFile;
418 SWAP_HFS_PLUS_FORK_DATA (fdp);
419 retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents,
420 kHFSExtentsFileID, CompareExtentKeysPlus);
421 SWAP_HFS_PLUS_FORK_DATA (fdp);
422 if (retval) goto ErrorExit;
423
424 /*
425 * Set up Catalog B-tree vnode...
426 */
427 retval = GetInitializedVNode(hfsmp, &tmpvnode);
428 if (retval) goto ErrorExit;
429 fdp = &vhp->catalogFile;
430 SWAP_HFS_PLUS_FORK_DATA (fdp);
431 retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents,
432 kHFSCatalogFileID, CompareExtendedCatalogKeys);
433 SWAP_HFS_PLUS_FORK_DATA (fdp);
434 if (retval) goto ErrorExit;
435
436 /*
437 * Set up Allocation file vnode...
438 */
439 retval = GetInitializedVNode(hfsmp, &tmpvnode);
440 if (retval) goto ErrorExit;
441 fdp = &vhp->allocationFile;
442 SWAP_HFS_PLUS_FORK_DATA (fdp);
443 retval = InitMetaFileVNode(tmpvnode, fdp->logicalSize, fdp->clumpSize, fdp->extents,
444 kHFSAllocationFileID, NULL);
445 SWAP_HFS_PLUS_FORK_DATA (fdp);
446 if (retval) goto ErrorExit;
447
448 /*
449 * Now that Catalog file is open get the volume name from the catalog
450 */
451 retval = MacToVFSError( GetVolumeNameFromCatalog(vcb) );
452 if (retval != noErr) goto ErrorExit;
453
454 /* mark the volume dirty (clear clean unmount bit) */
455 vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask;
456
457 /* setup private/hidden directory for unlinked files */
458 hfsmp->hfs_private_metadata_dir = FindMetaDataDirectory(vcb);
459
460 /*
461 * all done with metadata files so we can unlock now...
462 */
463 VOP_UNLOCK(vcb->allocationsRefNum, 0, p);
464 VOP_UNLOCK(vcb->catalogRefNum, 0, p);
465 VOP_UNLOCK(vcb->extentsRefNum, 0, p);
466
467 if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) ) // if the disk is not write protected
468 {
469 MarkVCBDirty( vcb ); // mark VCB dirty so it will be written
470 }
471
472 DBG_VFS(("hfs_MountHFSPlusVolume: returning (%d)\n", retval));
473
474 return (0);
475
476
477 ErrorExit:
478 /*
479 * A fatal error occured and the volume cannot be mounted
480 * release any resources that we aquired...
481 */
482
483 DBG_VFS(("hfs_MountHFSPlusVolume: fatal error (%d)\n", retval));
484
485 InvalidateCatalogCache(vcb);
486
487 ReleaseMetaFileVNode(vcb->allocationsRefNum);
488 ReleaseMetaFileVNode(vcb->catalogRefNum);
489 ReleaseMetaFileVNode(vcb->extentsRefNum);
490
491 return (retval);
492 }
493
494
495 /*
496 * ReleaseMetaFileVNode
497 *
498 * vp L - -
499 */
500 static void ReleaseMetaFileVNode(struct vnode *vp)
501 {
502 if (vp)
503 {
504 FCB *fcb = VTOFCB(vp);
505
506 if (fcb->fcbBTCBPtr != NULL)
507 (void) BTClosePath(fcb); /* ignore errors since there is only one path open */
508
509 /* release the node even if BTClosePath fails */
510 if (VOP_ISLOCKED(vp))
511 vput(vp);
512 else
513 vrele(vp);
514 }
515 }
516
517
518 /*
519 * InitMetaFileVNode
520 *
521 * vp U L L
522 */
523 static int InitMetaFileVNode(struct vnode *vp, off_t eof, u_long clumpSize, const HFSPlusExtentRecord extents,
524 HFSCatalogNodeID fileID, void * keyCompareProc)
525 {
526 FCB *fcb;
527 ExtendedVCB *vcb;
528 int result = 0;
529
530 DBG_ASSERT(vp != NULL);
531 DBG_ASSERT(vp->v_data != NULL);
532
533 vcb = VTOVCB(vp);
534 fcb = VTOFCB(vp);
535
536 switch (fileID)
537 {
538 case kHFSExtentsFileID:
539 vcb->extentsRefNum = vp;
540 break;
541
542 case kHFSCatalogFileID:
543 vcb->catalogRefNum = vp;
544 break;
545
546 case kHFSAllocationFileID:
547 vcb->allocationsRefNum = vp;
548 break;
549
550 default:
551 panic("InitMetaFileVNode: invalid fileID!");
552 }
553
554 fcb->fcbEOF = eof;
555 fcb->fcbPLen = eof;
556 fcb->fcbClmpSize = clumpSize;
557 H_FILEID(VTOH(vp)) = fileID;
558 H_DIRID(VTOH(vp)) = kHFSRootParentID;
559 H_FORKTYPE(VTOH(vp)) = kSysFile;
560
561 bcopy(extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
562
563 /*
564 * Lock the hfsnode and insert the hfsnode into the hash queue:
565 */
566 hfs_vhashins(H_DEV(VTOH(vp)), fileID, VTOH(vp));
567 vp->v_flag |= VSYSTEM; /* tag our metadata files (used by vflush call) */
568
569 /* As the vnode is a system vnode we don't need UBC */
570 if(UBCINFOEXISTS(vp)) {
571 /* So something is wrong if the it exists */
572 panic("ubc exists for system vnode");
573 }
574
575 if (keyCompareProc != NULL) {
576 result = BTOpenPath(fcb,
577 (KeyCompareProcPtr) keyCompareProc,
578 GetBTreeBlock,
579 ReleaseBTreeBlock,
580 ExtendBTreeFile,
581 SetBTreeBlockSize);
582 result = MacToVFSError(result);
583 }
584
585 return (result);
586 }
587
588
589 /*************************************************************
590 *
591 * Unmounts a hfs volume.
592 * At this point vflush() has been called (to dump all non-metadata files)
593 *
594 *************************************************************/
595
596 short hfsUnmount( register struct hfsmount *hfsmp, struct proc *p)
597 {
598 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
599 int retval = E_NONE;
600
601 (void) DisposeMRUCache(vcb->hintCachePtr);
602 InvalidateCatalogCache( vcb );
603 // XXX PPD: Should dispose of any allocated volume cache here: call DisposeVolumeCacheBlocks( vcb )?
604
605 (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
606 (void) hfs_metafilelocking(hfsmp, kHFSExtentsFileID, LK_EXCLUSIVE, p);
607
608 if (vcb->vcbSigWord == kHFSPlusSigWord)
609 ReleaseMetaFileVNode(vcb->allocationsRefNum);
610
611 ReleaseMetaFileVNode(vcb->catalogRefNum);
612 ReleaseMetaFileVNode(vcb->extentsRefNum);
613
614 return (retval);
615 }
616
617
618 /*
619 * hfs_resolvelink - auto resolve HFS+ hardlinks
620 *
621 * Used after calling GetCatalogNode or GetCatalogOffspring
622 */
623 void hfs_resolvelink(ExtendedVCB *vcb, CatalogNodeData *cndp)
624 {
625 struct FInfo *fip;
626 char iNodeName[32];
627 UInt32 hint;
628 UInt32 indlinkno;
629 UInt32 linkparid, linkcnid;
630 OSErr result;
631
632 fip = (struct FInfo *) &cndp->cnd_finderInfo;
633
634 /*
635 * if this is an indirect link (hardlink) then auto resolve it...
636 */
637 if ((vcb->vcbSigWord == kHFSPlusSigWord)
638 && (cndp->cnd_type == kCatalogFileNode)
639 && (fip->fdType == kHardLinkFileType)
640 && (fip->fdCreator == kHFSPlusCreator)
641 && ((cndp->cnd_createDate == vcb->vcbCrDate) ||
642 (cndp->cnd_createDate == VCBTOHFS(vcb)->hfs_metadata_createdate))) {
643
644 indlinkno = cndp->cnd_iNodeNum;
645 MAKE_INODE_NAME(iNodeName, indlinkno);
646 /*
647 * Get nodeData from the data node file.
648 * Flag the node data to NOT copy the name (ie preserve the original)
649 * Also preserve the parent directory ID.
650 */
651 linkparid = cndp->cnm_parID;
652 linkcnid = cndp->cnd_nodeID;
653 cndp->cnm_flags |= kCatNameNoCopyName;
654 result = GetCatalogNode(vcb, VCBTOHFS(vcb)->hfs_private_metadata_dir,
655 iNodeName, 0, 0, cndp, &hint);
656 cndp->cnm_flags &= ~kCatNameNoCopyName;
657
658 /* Make sure there's a reference */
659 if (result == 0) {
660 if (cndp->cnd_linkCount == 0) cndp->cnd_linkCount = 2;
661
662 /* Keep a copy of iNodeNum to put into h_indnodeno */
663 cndp->cnd_iNodeNumCopy = indlinkno;
664 cndp->cnm_parID = linkparid;
665 cndp->cnd_linkCNID = linkcnid;
666 }
667 }
668 }
669
670
671 /*
672 * Performs a lookup on the given dirID, name. Returns the catalog info
673 *
674 * If len is -1, then it is a null terminated string, pass it along to MacOS as kUndefinedStrLen
675 */
676
677 short hfs_getcatalog (ExtendedVCB *vcb, UInt32 parentDirID, char *name, short len, hfsCatalogInfo *catInfo)
678 {
679 OSErr result;
680 UInt32 length;
681
682 if (len == -1 ) { /* Convert it to MacOS terms */
683 if (name)
684 length = strlen(name);
685 else
686 length = kUndefinedStrLen;
687 }
688 else
689 length = len;
690
691 result = GetCatalogNode(vcb, parentDirID, name, length, catInfo->hint, &catInfo->nodeData, &catInfo->hint);
692
693 #if HFS_DIAGNOSTICS
694 if (catInfo->nodeData.cnm_nameptr) {
695 DBG_ASSERT(strlen(catInfo->nodeData.cnm_nameptr) == catInfo->nodeData.cnm_length);
696 }
697 #endif
698
699 if (result == 0)
700 hfs_resolvelink(vcb, &catInfo->nodeData);
701
702 return MacToVFSError(result);
703 }
704
705
706
707 short hfsDelete (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, short isfile, UInt32 catalogHint)
708 {
709 OSErr result = noErr;
710
711 /* XXX have all the file's blocks been flushed/trashed? */
712
713 /*
714 * DeleteFile will delete the catalog node and then
715 * free up any disk space used by the file.
716 */
717 if (isfile)
718 result = DeleteFile(vcb, parentDirID, name, catalogHint);
719 else /* is a directory */
720 result = DeleteCatalogNode(vcb, parentDirID, name, catalogHint);
721
722 if (result)
723 DBG_ERR(("on Delete, DeleteFile returned: %d: dirid: %ld name: %s\n", result, parentDirID, name));
724
725 return MacToVFSError(result);
726 }
727
728
729 short hfsMoveRename (ExtendedVCB *vcb, UInt32 oldDirID, char *oldName, UInt32 newDirID, char *newName, UInt32 *hint)
730 {
731 OSErr result = noErr;
732
733 result = MoveRenameCatalogNode(vcb, oldDirID,oldName, *hint, newDirID, newName, hint, 0);
734
735 if (result)
736 DBG_ERR(("on hfsMoveRename, MoveRenameCatalogNode returned: %d: newdirid: %ld newname: %s\n", result, newDirID, newName));
737
738
739 return MacToVFSError(result);
740 }
741
742 /* XXX SER pass back the hint so other people can use it */
743
744
745 short hfsCreate(ExtendedVCB *vcb, UInt32 dirID, char *name, int mode, UInt32 tehint)
746 {
747 OSErr result = noErr;
748 HFSCatalogNodeID catalogNodeID;
749 UInt32 catalogHint;
750 UInt32 type;
751
752 /* just test for directories, the default is to create a file (like symlinks) */
753 if ((mode & IFMT) == IFDIR)
754 type = kCatalogFolderNode;
755 else
756 type = kCatalogFileNode;
757
758 result = CreateCatalogNode (vcb, dirID, name, type, &catalogNodeID, &catalogHint, tehint);
759
760 return MacToVFSError(result);
761 }
762
763
764 short hfsCreateFileID (ExtendedVCB *vcb, UInt32 parentDirID, StringPtr name, UInt32 catalogHint, UInt32 *fileIDPtr)
765 {
766 return MacToVFSError(CreateFileIDRef(vcb, parentDirID, name, catalogHint, fileIDPtr));
767 }
768
769
770 /********************************************************************************/
771 /* */
772 /* hfs_vget_catinfo - Returns a vnode derived from a hfs catInfo struct */
773 /* */
774 /********************************************************************************/
775
776 int hfs_vget_catinfo(struct vnode *parent_vp, struct hfsCatalogInfo *catInfo, u_int32_t forkType, struct vnode **target_vp)
777 {
778 int retval = E_NONE;
779
780 if (forkType == kDefault) {
781 if (catInfo->nodeData.cnd_type == kCatalogFolderNode)
782 forkType = kDirectory;
783 else
784 forkType = kDataFork;
785 }
786
787 *target_vp = hfs_vhashget(H_DEV(VTOH(parent_vp)), catInfo->nodeData.cnd_nodeID, forkType);
788
789 if (*target_vp == NULL)
790 retval = hfs_vcreate( VTOVCB(parent_vp), catInfo, forkType, target_vp);
791
792 return (retval);
793 }
794
795
796
797 /************************************************************************/
798 /* hfs_vcreate - Returns a vnode derived from hfs */
799 /* */
800 /* When creating the vnode, care must be made to set the */
801 /* correct fields in the correct order. Calls to malloc() */
802 /* and other subroutines, can cause a context switch, */
803 /* and the fields must be ready for the possibility */
804 /* */
805 /* */
806 /************************************************************************/
807
808 short hfs_vcreate(ExtendedVCB *vcb, hfsCatalogInfo *catInfo, UInt8 forkType, struct vnode **vpp)
809 {
810 struct hfsnode *hp;
811 struct vnode *vp;
812 struct hfsmount *hfsmp;
813 struct hfsfilemeta *fm;
814 struct mount *mp;
815 struct vfsFCB *xfcb;
816 dev_t dev;
817 short retval;
818
819 hfsmp = VCBTOHFS(vcb);
820 mp = HFSTOVFS(hfsmp);
821 dev = hfsmp->hfs_raw_dev;
822
823 /* Check if unmount in progress */
824 if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
825 *vpp = NULL;
826 return (EPERM);
827 }
828
829 /*
830 * If this is a hard link then check if the
831 * data node already exists in our hash.
832 */
833 if ((forkType == kDataFork)
834 && (catInfo->nodeData.cnd_type == kCatalogFileNode)
835 && ((catInfo->nodeData.cnd_mode & IFMT) == IFREG)
836 && (catInfo->nodeData.cnd_linkCount > 0)) {
837 vp = hfs_vhashget(dev, catInfo->nodeData.cnd_nodeID, kDataFork);
838 if (vp != NULL) {
839 /* Use the name of the link and it's parent ID. */
840 hp = VTOH(vp);
841 H_DIRID(hp) = catInfo->nodeData.cnm_parID;
842 hfs_set_metaname(catInfo->nodeData.cnm_nameptr, hp->h_meta, hfsmp);
843 *vpp = vp;
844 return (0);
845 }
846 }
847
848 MALLOC_ZONE(hp, struct hfsnode *, sizeof(struct hfsnode), M_HFSNODE, M_WAITOK);
849 bzero((caddr_t)hp, sizeof(struct hfsnode));
850 hp->h_nodeflags |= IN_ALLOCATING;
851 lockinit(&hp->h_lock, PINOD, "hfsnode", 0, 0);
852 H_FORKTYPE(hp) = forkType;
853 rl_init(&hp->h_invalidranges);
854
855 /*
856 * There were several blocking points since we first
857 * checked the hash. Now that we're through blocking,
858 * check the hash again in case we're racing for the
859 * same hnode.
860 */
861 vp = hfs_vhashget(dev, catInfo->nodeData.cnd_nodeID, forkType);
862 if (vp != NULL) {
863 /* We lost the race, use the winner's vnode */
864 FREE_ZONE(hp, sizeof(struct hfsnode), M_HFSNODE);
865 *vpp = vp;
866 UBCINFOCHECK("hfs_vcreate", vp);
867 return (0);
868 }
869
870 /*
871 * Insert the hfsnode into the hash queue, also if meta exists
872 * add to sibling list and return the meta address
873 */
874 fm = NULL;
875 if (SIBLING_FORKTYPE(forkType))
876 hfs_vhashins_sibling(dev, catInfo->nodeData.cnd_nodeID, hp, &fm);
877 else
878 hfs_vhashins(dev, catInfo->nodeData.cnd_nodeID, hp);
879
880 /* Allocate a new vnode. If unsuccesful, leave after freeing memory */
881 if ((retval = getnewvnode(VT_HFS, mp, hfs_vnodeop_p, &vp))) {
882 hfs_vhashrem(hp);
883 if (hp->h_nodeflags & IN_WANT) {
884 hp->h_nodeflags &= ~IN_WANT;
885 wakeup(hp);
886 }
887 FREE_ZONE(hp, sizeof(struct hfsnode), M_HFSNODE);
888 *vpp = NULL;
889 return (retval);
890 }
891 hp->h_vp = vp;
892 vp->v_data = hp;
893
894 hp->h_nodeflags &= ~IN_ALLOCATING;
895 if (hp->h_nodeflags & IN_WANT) {
896 hp->h_nodeflags &= ~IN_WANT;
897 wakeup((caddr_t)hp);
898 }
899
900 /*
901 * If needed allocate and init the object meta data:
902 */
903 if (fm == NULL) {
904 /* Allocate it....remember we can do a context switch here */
905 MALLOC_ZONE(fm, struct hfsfilemeta *, sizeof(struct hfsfilemeta), M_HFSFMETA, M_WAITOK);
906 bzero(fm, sizeof(struct hfsfilemeta));
907
908 /* Fill it in */
909 /*
910 * NOTICE: XXX Even though we have added the vnode to the hash so it is alive on TWO
911 * accessable lists, we do not assign it until later,
912 * this helps to make sure we do not use a half initiated meta
913 */
914
915 /* Init the sibling list if needed */
916 if (SIBLING_FORKTYPE(forkType)) {
917 simple_lock_init(&fm->h_siblinglock);
918 CIRCLEQ_INIT(&fm->h_siblinghead);
919 CIRCLEQ_INSERT_HEAD(&fm->h_siblinghead, hp, h_sibling);
920 };
921
922 fm->h_dev = dev;
923 CopyCatalogToObjectMeta(catInfo, vp, fm);
924
925 /*
926 * the vnode is finally alive, with the exception of the FCB below,
927 * It is finally locked and ready for its debutante ball
928 */
929 hp->h_meta = fm;
930 };
931 fm->h_usecount++;
932
933 /*
934 * Init the File Control Block.
935 */
936 CopyCatalogToFCB(catInfo, vp);
937
938 /*
939 * Finish vnode initialization.
940 * Setting the v_type 'stamps' the vnode as 'complete', so should be done almost last.
941 *
942 * At this point the vnode should be locked and fully allocated. And ready to be used
943 * or accessed. (though having it locked prevents most of this, it
944 * can still be accessed through lists and hashs).
945 */
946 vp->v_type = IFTOVT(hp->h_meta->h_mode);
947 if ((vp->v_type == VREG)
948 && (UBCINFOMISSING(vp) || UBCINFORECLAIMED(vp))) {
949 ubc_info_init(vp);
950 }
951
952 /*
953 * Initialize the vnode from the inode, check for aliases, sets the VROOT flag.
954 * Note that the underlying vnode may have changed.
955 */
956 if ((retval = hfs_vinit(mp, hfs_specop_p, hfs_fifoop_p, &vp))) {
957 vput(vp);
958 *vpp = NULL;
959 return (retval);
960 }
961
962 /*
963 * Finish inode initialization now that aliasing has been resolved.
964 */
965 hp->h_meta->h_devvp = hfsmp->hfs_devvp;
966 VREF(hp->h_meta->h_devvp);
967
968 *vpp = vp;
969 return 0;
970 }
971
972 void CopyCatalogToObjectMeta(struct hfsCatalogInfo *catalogInfo, struct vnode *vp, struct hfsfilemeta *fm)
973 {
974 ExtendedVCB *vcb = VTOVCB(vp);
975 struct mount *mp = VTOVFS(vp);
976 Boolean isHFSPlus, isDirectory;
977 ushort finderFlags;
978 ushort filetype;
979
980 DBG_ASSERT (fm != NULL);
981 DBG_ASSERT (fm->h_namelen == 0);
982 DBG_ASSERT (fm->h_namePtr == 0);
983
984 DBG_UTILS(("\tCopying to file's meta data: name:%s, nodeid:%ld\n", catalogInfo->nodeData.cnm_nameptr, catalogInfo->nodeData.cnd_nodeID));
985
986 isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
987 isDirectory = (catalogInfo->nodeData.cnd_type == kCatalogFolderNode);
988 finderFlags = SWAP_BE16 (((struct FInfo *)(&catalogInfo->nodeData.cnd_finderInfo))->fdFlags);
989
990 /* Copy over the dirid, and hint */
991 fm->h_nodeID = catalogInfo->nodeData.cnd_nodeID;
992 fm->h_dirID = catalogInfo->nodeData.cnm_parID;
993 fm->h_hint = catalogInfo->hint;
994
995 /* Copy over the name */
996 hfs_name_CatToMeta(&catalogInfo->nodeData, fm);
997
998
999 /* get dates in BSD format */
1000 fm->h_mtime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
1001 fm->h_crtime = to_bsd_time(catalogInfo->nodeData.cnd_createDate);
1002 fm->h_butime = to_bsd_time(catalogInfo->nodeData.cnd_backupDate);
1003 if (isHFSPlus) {
1004 fm->h_atime = to_bsd_time(catalogInfo->nodeData.cnd_accessDate);
1005 fm->h_ctime = to_bsd_time(catalogInfo->nodeData.cnd_attributeModDate);
1006 }
1007 else {
1008 fm->h_atime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
1009 fm->h_ctime = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
1010 }
1011
1012 /* Now the rest */
1013 if (isHFSPlus && (catalogInfo->nodeData.cnd_mode & IFMT)) {
1014 fm->h_uid = catalogInfo->nodeData.cnd_ownerID;
1015 fm->h_gid = catalogInfo->nodeData.cnd_groupID;
1016 fm->h_pflags = catalogInfo->nodeData.cnd_ownerFlags |
1017 (catalogInfo->nodeData.cnd_adminFlags << 16);
1018 fm->h_mode = (mode_t)catalogInfo->nodeData.cnd_mode;
1019 #if 1
1020 if (fm->h_uid == 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1021 fm->h_uid = UNKNOWNUID;
1022 fm->h_metaflags |= IN_CHANGE;
1023 vcb->vcbFlags |= kHFS_DamagedVolume; /* Trigger fsck on next mount */
1024 };
1025 if (fm->h_gid == 0xFFFFFFFD) { /* 0xfffffffd = 4294967293, the old "unknown" */
1026 fm->h_gid = UNKNOWNGID;
1027 fm->h_metaflags |= IN_CHANGE;
1028 vcb->vcbFlags |= kHFS_DamagedVolume; /* Trigger fsck on next mount */
1029 };
1030 #endif
1031 filetype = fm->h_mode & IFMT;
1032 if (filetype == IFCHR || filetype == IFBLK)
1033 fm->h_rdev = catalogInfo->nodeData.cnd_rawDevice;
1034 else {
1035 fm->h_rdev = 0;
1036 #if HFS_HARDLINKS
1037 if (catalogInfo->nodeData.cnd_type == kCatalogFileNode &&
1038 catalogInfo->nodeData.cnd_linkCount > 0) {
1039 fm->h_nlink = catalogInfo->nodeData.cnd_linkCount;
1040 fm->h_indnodeno = catalogInfo->nodeData.cnd_iNodeNumCopy;
1041 fm->h_metaflags |= IN_DATANODE;
1042 }
1043 #endif
1044 }
1045
1046 if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
1047 /*
1048 * Override the permissions as determined by the mount auguments
1049 * in ALMOST the same way unset permissions are treated but keep
1050 * track of whether or not the file or folder is hfs locked
1051 * by leaving the h_pflags field unchanged from what was unpacked
1052 * out of the catalog.
1053 */
1054 fm->h_metaflags |= IN_UNSETACCESS;
1055 fm->h_uid = VTOHFS(vp)->hfs_uid;
1056 fm->h_gid = VTOHFS(vp)->hfs_gid;
1057 #if OVERRIDE_UNKNOWN_PERMISSIONS
1058 /* Default access is full read/write/execute: */
1059 /* XXX won't this smash IFCHR, IFBLK and IFLNK (for no-follow lookups)? */
1060 fm->h_mode = ACCESSPERMS; /* 0777: rwxrwxrwx */
1061 fm->h_rdev = 0;
1062
1063 /* ... but no more than that permitted by the mount point's: */
1064 if (isDirectory) {
1065 fm->h_mode &= VTOHFS(vp)->hfs_dir_mask;
1066 }
1067 else {
1068 fm->h_mode &= VTOHFS(vp)->hfs_file_mask;
1069 }
1070
1071 if(isDirectory)
1072 fm->h_mode |= IFDIR;
1073 else if (SUPPORTS_MAC_ALIASES && (finderFlags & kIsAlias)) /* aliases will be symlinks in the future */
1074 fm->h_mode |= IFLNK;
1075 else
1076 fm->h_mode |= IFREG;
1077 #endif
1078 };
1079 } else {
1080 /*
1081 * Set the permissions as determined by the mount auguments
1082 * but keep in account if the file or folder is hfs locked
1083 */
1084 fm->h_metaflags |= IN_UNSETACCESS;
1085 fm->h_uid = VTOHFS(vp)->hfs_uid;
1086 fm->h_gid = VTOHFS(vp)->hfs_gid;
1087 fm->h_pflags = 0; /* No valid pflags on disk (IMMUTABLE is synced from lock flag later) */
1088 fm->h_rdev = 0; /* No valid rdev on disk */
1089 /* Default access is full read/write/execute: */
1090 fm->h_mode = ACCESSPERMS; /* 0777: rwxrwxrwx */
1091
1092 /* ... but no more than that permitted by the mount point's: */
1093 if (isDirectory) {
1094 fm->h_mode &= VTOHFS(vp)->hfs_dir_mask;
1095 }
1096 else {
1097 fm->h_mode &= VTOHFS(vp)->hfs_file_mask;
1098 }
1099
1100 if(isDirectory)
1101 fm->h_mode |= IFDIR;
1102 else if (SUPPORTS_MAC_ALIASES && (finderFlags & kIsAlias)) /* aliases will be symlinks in the future */
1103 fm->h_mode |= IFLNK;
1104 else
1105 fm->h_mode |= IFREG;
1106 };
1107
1108 /* Make sure that there is no nodeType/mode mismatch */
1109 if (isDirectory && ((fm->h_mode & IFMT) != IFDIR)) {
1110 fm->h_mode &= ~IFMT; /* Clear the bad bits */
1111 fm->h_mode |= IFDIR; /* Set the proper one */
1112 };
1113
1114 /* Make sure the IMMUTABLE bits are in sync with the locked flag in the catalog: */
1115 if (!isDirectory) {
1116 if (catalogInfo->nodeData.cnd_flags & kHFSFileLockedMask) {
1117 /* The file's supposed to be locked:
1118 Make sure at least one of the IMMUTABLE bits is set: */
1119 if ((fm->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) == 0) {
1120 fm->h_pflags |= UF_IMMUTABLE; /* Set the user-changable IMMUTABLE bit */
1121 };
1122 } else {
1123 /* The file's supposed to be unlocked: */
1124 fm->h_pflags &= ~(SF_IMMUTABLE | UF_IMMUTABLE);
1125 };
1126 };
1127
1128 if (isDirectory) {
1129 fm->h_nlink = 2 + catalogInfo->nodeData.cnd_valence;
1130 fm->h_size = (2 * sizeof(hfsdotentry)) +
1131 (catalogInfo->nodeData.cnd_valence * AVERAGE_HFSDIRENTRY_SIZE);
1132 if (fm->h_size < MAX_HFSDIRENTRY_SIZE)
1133 fm->h_size = MAX_HFSDIRENTRY_SIZE;
1134 } else {
1135 fm->h_size = (off_t)vcb->blockSize *
1136 (off_t)(catalogInfo->nodeData.cnd_rsrcfork.totalBlocks +
1137 catalogInfo->nodeData.cnd_datafork.totalBlocks);
1138 }
1139 }
1140
1141
1142 void CopyCatalogToFCB(struct hfsCatalogInfo *catalogInfo, struct vnode *vp)
1143 {
1144 FCB *fcb = VTOFCB(vp);
1145 ExtendedVCB *vcb = VTOVCB(vp);
1146 Boolean isHFSPlus, isDirectory, isResource;
1147 HFSPlusExtentDescriptor *extents;
1148 UInt8 forkType;
1149
1150 DBG_ASSERT (vp != NULL);
1151 DBG_ASSERT (fcb != NULL);
1152 DBG_ASSERT (vcb != NULL);
1153 DBG_ASSERT (VTOH(vp) != NULL);
1154
1155 forkType = H_FORKTYPE(VTOH(vp));
1156 isResource = (forkType == kRsrcFork);
1157 isDirectory = (catalogInfo->nodeData.cnd_type == kCatalogFolderNode);
1158 isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
1159
1160 /* Init the fcb */
1161 fcb->fcbFlags = catalogInfo->nodeData.cnd_flags;
1162
1163 if (forkType != kDirectory) {
1164 fcb->fcbFlags &= kHFSFileLockedMask; /* Clear resource, dirty bits */
1165 if (fcb->fcbFlags != 0) /* if clear, its not locked, then.. */
1166 fcb->fcbFlags = fcbFileLockedMask; /* duplicate the bit for later use */
1167
1168 fcb->fcbClmpSize = vcb->vcbClpSiz; /*XXX why not use the one in catalogInfo? */
1169
1170 if (isResource)
1171 extents = catalogInfo->nodeData.cnd_rsrcfork.extents;
1172 else
1173 extents = catalogInfo->nodeData.cnd_datafork.extents;
1174
1175 /* Copy the extents to their correct location: */
1176 bcopy (extents, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
1177
1178 if (isResource) {
1179 fcb->fcbEOF = catalogInfo->nodeData.cnd_rsrcfork.logicalSize;
1180 fcb->fcbPLen = (off_t)((off_t)catalogInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
1181 fcb->fcbFlags |= fcbResourceMask;
1182 } else {
1183 fcb->fcbEOF = catalogInfo->nodeData.cnd_datafork.logicalSize;
1184 fcb->fcbPLen = (off_t)((off_t)catalogInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize);
1185 };
1186 };
1187
1188
1189 }
1190
1191 int hasOverflowExtents(struct hfsnode *hp)
1192 {
1193 ExtendedVCB *vcb = HTOVCB(hp);
1194 FCB *fcb = HTOFCB(hp);
1195 u_long blocks;
1196
1197 if (vcb->vcbSigWord == kHFSPlusSigWord)
1198 {
1199
1200 if (fcb->fcbExtents[7].blockCount == 0)
1201 return false;
1202
1203 blocks = fcb->fcbExtents[0].blockCount +
1204 fcb->fcbExtents[1].blockCount +
1205 fcb->fcbExtents[2].blockCount +
1206 fcb->fcbExtents[3].blockCount +
1207 fcb->fcbExtents[4].blockCount +
1208 fcb->fcbExtents[5].blockCount +
1209 fcb->fcbExtents[6].blockCount +
1210 fcb->fcbExtents[7].blockCount;
1211 }
1212 else
1213 {
1214 if (fcb->fcbExtents[2].blockCount == 0)
1215 return false;
1216
1217 blocks = fcb->fcbExtents[0].blockCount +
1218 fcb->fcbExtents[1].blockCount +
1219 fcb->fcbExtents[2].blockCount;
1220 }
1221
1222 return ((fcb->fcbPLen / vcb->blockSize) > blocks);
1223 }
1224
1225
1226 int hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p)
1227 {
1228 ExtendedVCB *vcb;
1229 struct vnode *vp = NULL;
1230 int numOfLockedBuffs;
1231 int retval = 0;
1232
1233 vcb = HFSTOVCB(hfsmp);
1234
1235 DBG_UTILS(("hfs_metafilelocking: vol: %d, file: %d %s%s%s\n", vcb->vcbVRefNum, fileID,
1236 ((flags & LK_TYPE_MASK) == LK_RELEASE ? "RELEASE" : ""),
1237 ((flags & LK_TYPE_MASK) == LK_EXCLUSIVE ? "EXCLUSIVE" : ""),
1238 ((flags & LK_TYPE_MASK) == LK_SHARED ? "SHARED" : "") ));
1239
1240
1241 switch (fileID)
1242 {
1243 case kHFSExtentsFileID:
1244 vp = vcb->extentsRefNum;
1245 break;
1246
1247 case kHFSCatalogFileID:
1248 vp = vcb->catalogRefNum;
1249 break;
1250
1251 case kHFSAllocationFileID:
1252 /* bitmap is covered by Extents B-tree locking */
1253 /* FALL THROUGH */
1254 default:
1255 panic("hfs_lockmetafile: invalid fileID");
1256 }
1257
1258 if (vp != NULL) {
1259
1260 /* Release, if necesary any locked buffer caches */
1261 if ((flags & LK_TYPE_MASK) == LK_RELEASE) {
1262 struct timeval tv = time;
1263 u_int32_t lastfsync = tv.tv_sec;
1264
1265 (void) BTGetLastSync(VTOFCB(vp), &lastfsync);
1266
1267 numOfLockedBuffs = count_lock_queue();
1268 if ((numOfLockedBuffs > kMaxLockedMetaBuffers) || ((numOfLockedBuffs>1) && ((tv.tv_sec - lastfsync) > kMaxSecsForFsync))) {
1269 DBG_UTILS(("Synching meta deta: %d... # locked buffers = %d, fsync gap = %ld\n", H_FILEID(VTOH(vp)),
1270 numOfLockedBuffs, (tv.tv_sec - lastfsync)));
1271 hfs_fsync_transaction(vp);
1272 };
1273 };
1274
1275 retval = lockmgr(&VTOH(vp)->h_lock, flags, &vp->v_interlock, p);
1276 };
1277
1278 return retval;
1279 }
1280
1281
1282 /*
1283 * There are three ways to qualify for ownership rights on an object:
1284 *
1285 * 1. (a) Your UID matches the UID of the vnode
1286 * (b) The object in question is owned by "unknown" and your UID matches the console user's UID
1287 * 2. (a) Permissions on the filesystem are being ignored and your UID matches the replacement UID
1288 * (b) Permissions on the filesystem are being ignored and the replacement UID is "unknown" and
1289 * your UID matches the console user UID
1290 * 3. You are root
1291 *
1292 */
1293 int hfs_owner_rights(struct vnode *vp, struct ucred *cred, struct proc *p, Boolean invokesuperuserstatus) {
1294 return ((cred->cr_uid == VTOH(vp)->h_meta->h_uid) || /* [1a] */
1295 ((VTOH(vp)->h_meta->h_uid == UNKNOWNUID) && (cred->cr_uid == console_user)) || /* [1b] */
1296 ((VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) && /* [2] */
1297 ((cred->cr_uid == VTOHFS(vp)->hfs_uid) || /* [2a] */
1298 ((VTOHFS(vp)->hfs_uid == UNKNOWNUID) && (cred->cr_uid == console_user)))) || /* [2b] */
1299 (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) ? 0 : EPERM;
1300 }
1301
1302
1303
1304 int hfs_catalogentry_owner_rights(uid_t obj_uid, struct mount *mp, struct ucred *cred, struct proc *p, Boolean invokesuperuserstatus) {
1305 return ((cred->cr_uid == obj_uid) || /* [1a] */
1306 ((obj_uid == UNKNOWNUID) && (cred->cr_uid == console_user)) || /* [1b] */
1307 ((mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) && /* [2] */
1308 ((cred->cr_uid == VFSTOHFS(mp)->hfs_uid) || /* [2a] */
1309 ((VFSTOHFS(mp)->hfs_uid == UNKNOWNUID) && (cred->cr_uid == console_user)))) || /* [2b] */
1310 (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) ? 0 : EPERM;
1311 }
1312
1313
1314
1315 void CopyVNodeToCatalogNode (struct vnode *vp, struct CatalogNodeData *nodeData)
1316 {
1317 ExtendedVCB *vcb;
1318 FCB *fcb;
1319 struct hfsnode *hp;
1320 Boolean isHFSPlus, isResource;
1321 HFSPlusExtentDescriptor *extents;
1322 off_t fileReadLimit;
1323
1324 hp = VTOH(vp);
1325 vcb = HTOVCB(hp);
1326 fcb = HTOFCB(hp);
1327 isResource = (H_FORKTYPE(hp) == kRsrcFork);
1328 isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
1329
1330 /* date and time of last fork modification */
1331 if (hp->h_meta->h_mtime != 0)
1332 nodeData->cnd_contentModDate = to_hfs_time(hp->h_meta->h_mtime);
1333
1334 if (isHFSPlus) {
1335 /* Make sure that there is no nodeType/mode mismatch */
1336 if ((nodeData->cnd_type == kCatalogFolderNode)
1337 && ((hp->h_meta->h_mode & IFMT) != IFDIR)) {
1338
1339 DBG_ASSERT((hp->h_meta->h_mode & IFMT) == IFDIR);
1340 hp->h_meta->h_mode &= ~IFMT; /* Clear the bad bits */
1341 hp->h_meta->h_mode |= IFDIR; /* Set the proper one */
1342 };
1343 /* date and time of last modification (any kind) */
1344 if (hp->h_meta->h_ctime != 0)
1345 nodeData->cnd_attributeModDate = to_hfs_time(hp->h_meta->h_ctime);
1346 /* date and time of last access (MacOS X only) */
1347 if (hp->h_meta->h_atime != 0)
1348 nodeData->cnd_accessDate = to_hfs_time(hp->h_meta->h_atime);
1349 /* hfs_setattr can change the create date */
1350 if (hp->h_meta->h_crtime != 0)
1351 nodeData->cnd_createDate = to_hfs_time(hp->h_meta->h_crtime);
1352 if (! (hp->h_meta->h_metaflags & IN_UNSETACCESS)) {
1353 nodeData->cnd_adminFlags = hp->h_meta->h_pflags >> 16;
1354 nodeData->cnd_ownerFlags = hp->h_meta->h_pflags & 0x000000FF;
1355 nodeData->cnd_mode = hp->h_meta->h_mode;
1356 nodeData->cnd_ownerID = hp->h_meta->h_uid;
1357 nodeData->cnd_groupID = hp->h_meta->h_gid;
1358 }
1359 };
1360
1361 /* the rest only applies to files */
1362 if (nodeData->cnd_type == kCatalogFileNode) {
1363 if (hp->h_meta->h_pflags & (SF_IMMUTABLE | UF_IMMUTABLE)) {
1364 /* The file is locked: set the locked bit in the catalog. */
1365 nodeData->cnd_flags |= kHFSFileLockedMask;
1366 } else {
1367 /* The file is unlocked: make sure the locked bit in the catalog is clear. */
1368 nodeData->cnd_flags &= ~kHFSFileLockedMask;
1369 };
1370 if (CIRCLEQ_EMPTY(&hp->h_invalidranges)) {
1371 fileReadLimit = fcb->fcbEOF;
1372 } else {
1373 fileReadLimit = CIRCLEQ_FIRST(&hp->h_invalidranges)->rl_start;
1374 };
1375 if (isResource) {
1376 extents = nodeData->cnd_rsrcfork.extents;
1377 nodeData->cnd_rsrcfork.logicalSize = fileReadLimit;
1378 nodeData->cnd_rsrcfork.totalBlocks = fcb->fcbPLen / vcb->blockSize;
1379 } else {
1380 extents = nodeData->cnd_datafork.extents;
1381 nodeData->cnd_datafork.logicalSize = fileReadLimit;
1382 nodeData->cnd_datafork.totalBlocks = fcb->fcbPLen / vcb->blockSize;
1383 };
1384
1385 bcopy ( fcb->fcbExtents, extents, sizeof(HFSPlusExtentRecord));
1386
1387 if ((vp->v_type == VBLK) || (vp->v_type == VCHR))
1388 nodeData->cnd_rawDevice = hp->h_meta->h_rdev;
1389 else if (hp->h_meta->h_metaflags & IN_DATANODE)
1390 nodeData->cnd_linkCount = hp->h_meta->h_nlink;
1391
1392 if (vp->v_type == VLNK) {
1393 ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdType = SWAP_BE32 (kSymLinkFileType);
1394 ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdCreator = SWAP_BE32 (kSymLinkCreator);
1395
1396 /* Set this up as an alias */
1397 #if SUPPORTS_MAC_ALIASES
1398 ((struct FInfo *)(&nodeData->cnd_finderInfo))->fdFlags |= SWAP_BE16 (kIsAlias);
1399 #endif
1400 }
1401 }
1402 }
1403
1404
1405 /*********************************************************************
1406
1407 Sets the name in the filemeta structure
1408
1409 XXX Does not preflight if changing from one size to another
1410 XXX Currently not protected from context switching
1411
1412 *********************************************************************/
1413
1414 void hfs_set_metaname(char *name, struct hfsfilemeta *fm, struct hfsmount *hfsmp)
1415 {
1416 int namelen = strlen(name);
1417 char *tname, *fname;
1418
1419 #if HFS_DIAGNOSTIC
1420 DBG_ASSERT(name != NULL);
1421 DBG_ASSERT(fm != NULL);
1422 if (fm->h_namePtr) {
1423 DBG_ASSERT(fm->h_namelen == strlen(fm->h_namePtr));
1424 if (strlen(fm->h_namePtr) > MAXHFSVNODELEN)
1425 DBG_ASSERT(fm->h_metaflags & IN_LONGNAME);
1426 };
1427 if (fm->h_metaflags & IN_LONGNAME) {
1428 DBG_ASSERT(fm->h_namePtr != (char *)fm->h_fileName);
1429 DBG_ASSERT(fm->h_namePtr != NULL);
1430 };
1431 #endif //HFS_DIAGNOSTIC
1432
1433 /*
1434 * Details that have to be dealt with:
1435 * 1. No name is allocated. fm->h_namePtr should be NULL
1436 * 2. A name is being changed and:
1437 * a. it was in static space and now cannot fit
1438 * b. It was malloc'd and now will fit in the static
1439 * c. It did and will fit in the static
1440 * This could be a little smarter:
1441 * - Dont re'malloc if the new name is smaller (but then wasting memory)
1442 * - If its a longname but the same size, we still free and malloc
1443 * -
1444 */
1445
1446
1447 /* Allocate the new memory */
1448 if (namelen > MAXHFSVNODELEN) {
1449 /*
1450 * Notice the we ALWAYS allocate, even if the new is less then the old,
1451 * or even if they are the SAME
1452 */
1453 MALLOC(tname, char *, namelen+1, M_TEMP, M_WAITOK);
1454 }
1455 else
1456 tname = fm->h_fileName;
1457
1458 simple_lock(&hfsmp->hfs_renamelock);
1459
1460 /* Check to see if there is something to free, if yes, remember it */
1461 if (fm->h_metaflags & IN_LONGNAME)
1462 fname = fm->h_namePtr;
1463 else
1464 fname = NULL;
1465
1466 /* Set the flag */
1467 if (namelen > MAXHFSVNODELEN) {
1468 fm->h_metaflags |= IN_LONGNAME;
1469 }
1470 else {
1471 fm->h_metaflags &= ~IN_LONGNAME;
1472 };
1473
1474 /* Now copy it over */
1475 bcopy(name, tname, namelen+1);
1476
1477 fm->h_namePtr = tname;
1478 fm->h_namelen = namelen;
1479
1480 simple_unlock(&hfsmp->hfs_renamelock);
1481
1482 /* Lastly, free the old, if set */
1483 if (fname != NULL)
1484 FREE(fname, M_TEMP);
1485
1486 }
1487
1488 void hfs_name_CatToMeta(CatalogNodeData *nodeData, struct hfsfilemeta *fm)
1489 {
1490 char *fname;
1491
1492 #if HFS_DIAGNOSTIC
1493 DBG_ASSERT(nodeData != NULL);
1494 DBG_ASSERT(fm != NULL);
1495 if (fm->h_namePtr) {
1496 DBG_ASSERT(fm->h_namelen == strlen(fm->h_namePtr));
1497 if (strlen(fm->h_namePtr) > MAXHFSVNODELEN)
1498 DBG_ASSERT(fm->h_metaflags & IN_LONGNAME);
1499 };
1500 if (fm->h_metaflags & IN_LONGNAME) {
1501 DBG_ASSERT(fm->h_namePtr != (char *)fm->h_fileName);
1502 DBG_ASSERT(fm->h_namePtr != NULL);
1503 };
1504
1505 DBG_ASSERT(nodeData->cnm_nameptr != NULL);
1506
1507 if (nodeData->cnm_length) {
1508 DBG_ASSERT(strlen(nodeData->cnm_nameptr) == nodeData->cnm_length);
1509 }
1510
1511 if (nodeData->cnm_length > MAXHFSVNODELEN)
1512 { DBG_ASSERT(nodeData->cnm_nameptr != nodeData->cnm_namespace); }
1513 else if (nodeData->cnm_nameptr)
1514 { DBG_ASSERT(nodeData->cnm_nameptr == nodeData->cnm_namespace); }
1515
1516 #endif //HFS_DIAGNOSTIC
1517
1518
1519 /* Check to see if there is something to free, if yes, remember it */
1520 if (fm->h_metaflags & IN_LONGNAME)
1521 fname = fm->h_namePtr;
1522 else
1523 fname = NULL;
1524
1525 /* Set the flag */
1526 if (nodeData->cnm_length > MAXHFSVNODELEN) {
1527 fm->h_metaflags |= IN_LONGNAME;
1528 } else {
1529 fm->h_metaflags &= ~IN_LONGNAME;
1530 };
1531
1532 /* Copy over the name */
1533 if (nodeData->cnm_nameptr == nodeData->cnm_namespace) {
1534 bcopy(nodeData->cnm_namespace, fm->h_fileName, nodeData->cnm_length+1);
1535 fm->h_namePtr = fm->h_fileName;
1536 }
1537 else {
1538 fm->h_namePtr = nodeData->cnm_nameptr;
1539 }
1540
1541 fm->h_namelen = nodeData->cnm_length;
1542
1543 nodeData->cnm_flags |= kCatNameIsConsumed;
1544 nodeData->cnm_flags &= ~kCatNameIsAllocated;
1545 nodeData->cnm_length = 0;
1546 nodeData->cnm_nameptr = (char *)0;
1547 nodeData->cnm_namespace[0] = 0;
1548
1549 /* Lastly, free the old, if set */
1550 if (fname != NULL)
1551 FREE(fname, M_TEMP);
1552 }
1553
1554
1555
1556 unsigned long DerivePermissionSummary(uid_t obj_uid, gid_t obj_gid, mode_t obj_mode, struct mount *mp, struct ucred *cred, struct proc *p) {
1557 register gid_t *gp;
1558 unsigned long permissions;
1559 int i;
1560
1561 /* User id 0 (root) always gets access. */
1562 if (cred->cr_uid == 0) {
1563 permissions = R_OK | W_OK | X_OK;
1564 goto Exit;
1565 };
1566
1567 /* Otherwise, check the owner. */
1568 if (hfs_catalogentry_owner_rights(obj_uid, mp, cred, p, false) == 0) {
1569 permissions = ((unsigned long)obj_mode & S_IRWXU) >> 6;
1570 goto Exit;
1571 }
1572
1573 /* Otherwise, check the groups. */
1574 if (! (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS)) {
1575 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) {
1576 if (obj_gid == *gp) {
1577 permissions = ((unsigned long)obj_mode & S_IRWXG) >> 3;
1578 goto Exit;
1579 }
1580 };
1581 };
1582
1583 /* Otherwise, settle for 'others' access. */
1584 permissions = (unsigned long)obj_mode & S_IRWXO;
1585
1586 Exit:
1587 return permissions;
1588 }
1589
1590
1591
1592 int AttributeBlockSize(struct attrlist *attrlist) {
1593 int size;
1594 attrgroup_t a;
1595
1596 #if ((ATTR_CMN_NAME | ATTR_CMN_DEVID | ATTR_CMN_FSID | ATTR_CMN_OBJTYPE | \
1597 ATTR_CMN_OBJTAG | ATTR_CMN_OBJID | ATTR_CMN_OBJPERMANENTID | ATTR_CMN_PAROBJID | \
1598 ATTR_CMN_SCRIPT | ATTR_CMN_CRTIME | ATTR_CMN_MODTIME | ATTR_CMN_CHGTIME | \
1599 ATTR_CMN_ACCTIME | ATTR_CMN_BKUPTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_OWNERID | \
1600 ATTR_CMN_GRPID | ATTR_CMN_ACCESSMASK | ATTR_CMN_NAMEDATTRCOUNT | ATTR_CMN_NAMEDATTRLIST| \
1601 ATTR_CMN_FLAGS | ATTR_CMN_USERACCESS) != ATTR_CMN_VALIDMASK)
1602 #error AttributeBlockSize: Missing bits in common mask computation!
1603 #endif
1604 DBG_ASSERT((attrlist->commonattr & ~ATTR_CMN_VALIDMASK) == 0);
1605
1606 #if ((ATTR_VOL_FSTYPE | ATTR_VOL_SIGNATURE | ATTR_VOL_SIZE | ATTR_VOL_SPACEFREE | \
1607 ATTR_VOL_SPACEAVAIL | ATTR_VOL_MINALLOCATION | ATTR_VOL_ALLOCATIONCLUMP | ATTR_VOL_IOBLOCKSIZE | \
1608 ATTR_VOL_OBJCOUNT | ATTR_VOL_FILECOUNT | ATTR_VOL_DIRCOUNT | ATTR_VOL_MAXOBJCOUNT | \
1609 ATTR_VOL_MOUNTPOINT | ATTR_VOL_NAME | ATTR_VOL_MOUNTFLAGS | ATTR_VOL_INFO | \
1610 ATTR_VOL_MOUNTEDDEVICE| ATTR_VOL_ENCODINGSUSED | ATTR_VOL_CAPABILITIES | ATTR_VOL_ATTRIBUTES) != ATTR_VOL_VALIDMASK)
1611 #error AttributeBlockSize: Missing bits in volume mask computation!
1612 #endif
1613 DBG_ASSERT((attrlist->volattr & ~ATTR_VOL_VALIDMASK) == 0);
1614
1615 #if ((ATTR_DIR_LINKCOUNT | ATTR_DIR_ENTRYCOUNT | ATTR_DIR_MOUNTSTATUS) != ATTR_DIR_VALIDMASK)
1616 #error AttributeBlockSize: Missing bits in directory mask computation!
1617 #endif
1618 DBG_ASSERT((attrlist->dirattr & ~ATTR_DIR_VALIDMASK) == 0);
1619 #if ((ATTR_FILE_LINKCOUNT | ATTR_FILE_TOTALSIZE | ATTR_FILE_ALLOCSIZE | ATTR_FILE_IOBLOCKSIZE | \
1620 ATTR_FILE_CLUMPSIZE | ATTR_FILE_DEVTYPE | ATTR_FILE_FILETYPE | ATTR_FILE_FORKCOUNT | \
1621 ATTR_FILE_FORKLIST | ATTR_FILE_DATALENGTH | ATTR_FILE_DATAALLOCSIZE | ATTR_FILE_DATAEXTENTS | \
1622 ATTR_FILE_RSRCLENGTH | ATTR_FILE_RSRCALLOCSIZE | ATTR_FILE_RSRCEXTENTS) != ATTR_FILE_VALIDMASK)
1623 #error AttributeBlockSize: Missing bits in file mask computation!
1624 #endif
1625 DBG_ASSERT((attrlist->fileattr & ~ATTR_FILE_VALIDMASK) == 0);
1626
1627 #if ((ATTR_FORK_TOTALSIZE | ATTR_FORK_ALLOCSIZE) != ATTR_FORK_VALIDMASK)
1628 #error AttributeBlockSize: Missing bits in fork mask computation!
1629 #endif
1630 DBG_ASSERT((attrlist->forkattr & ~ATTR_FORK_VALIDMASK) == 0);
1631
1632 size = 0;
1633
1634 if ((a = attrlist->commonattr) != 0) {
1635 if (a & ATTR_CMN_NAME) size += sizeof(struct attrreference);
1636 if (a & ATTR_CMN_DEVID) size += sizeof(dev_t);
1637 if (a & ATTR_CMN_FSID) size += sizeof(fsid_t);
1638 if (a & ATTR_CMN_OBJTYPE) size += sizeof(fsobj_type_t);
1639 if (a & ATTR_CMN_OBJTAG) size += sizeof(fsobj_tag_t);
1640 if (a & ATTR_CMN_OBJID) size += sizeof(fsobj_id_t);
1641 if (a & ATTR_CMN_OBJPERMANENTID) size += sizeof(fsobj_id_t);
1642 if (a & ATTR_CMN_PAROBJID) size += sizeof(fsobj_id_t);
1643 if (a & ATTR_CMN_SCRIPT) size += sizeof(text_encoding_t);
1644 if (a & ATTR_CMN_CRTIME) size += sizeof(struct timespec);
1645 if (a & ATTR_CMN_MODTIME) size += sizeof(struct timespec);
1646 if (a & ATTR_CMN_CHGTIME) size += sizeof(struct timespec);
1647 if (a & ATTR_CMN_ACCTIME) size += sizeof(struct timespec);
1648 if (a & ATTR_CMN_BKUPTIME) size += sizeof(struct timespec);
1649 if (a & ATTR_CMN_FNDRINFO) size += 32 * sizeof(UInt8);
1650 if (a & ATTR_CMN_OWNERID) size += sizeof(uid_t);
1651 if (a & ATTR_CMN_GRPID) size += sizeof(gid_t);
1652 if (a & ATTR_CMN_ACCESSMASK) size += sizeof(u_long);
1653 if (a & ATTR_CMN_NAMEDATTRCOUNT) size += sizeof(u_long);
1654 if (a & ATTR_CMN_NAMEDATTRLIST) size += sizeof(struct attrreference);
1655 if (a & ATTR_CMN_FLAGS) size += sizeof(u_long);
1656 if (a & ATTR_CMN_USERACCESS) size += sizeof(u_long);
1657 };
1658 if ((a = attrlist->volattr) != 0) {
1659 if (a & ATTR_VOL_FSTYPE) size += sizeof(u_long);
1660 if (a & ATTR_VOL_SIGNATURE) size += sizeof(u_long);
1661 if (a & ATTR_VOL_SIZE) size += sizeof(off_t);
1662 if (a & ATTR_VOL_SPACEFREE) size += sizeof(off_t);
1663 if (a & ATTR_VOL_SPACEAVAIL) size += sizeof(off_t);
1664 if (a & ATTR_VOL_MINALLOCATION) size += sizeof(off_t);
1665 if (a & ATTR_VOL_ALLOCATIONCLUMP) size += sizeof(off_t);
1666 if (a & ATTR_VOL_IOBLOCKSIZE) size += sizeof(u_long);
1667 if (a & ATTR_VOL_OBJCOUNT) size += sizeof(u_long);
1668 if (a & ATTR_VOL_FILECOUNT) size += sizeof(u_long);
1669 if (a & ATTR_VOL_DIRCOUNT) size += sizeof(u_long);
1670 if (a & ATTR_VOL_MAXOBJCOUNT) size += sizeof(u_long);
1671 if (a & ATTR_VOL_MOUNTPOINT) size += sizeof(struct attrreference);
1672 if (a & ATTR_VOL_NAME) size += sizeof(struct attrreference);
1673 if (a & ATTR_VOL_MOUNTFLAGS) size += sizeof(u_long);
1674 if (a & ATTR_VOL_MOUNTEDDEVICE) size += sizeof(struct attrreference);
1675 if (a & ATTR_VOL_ENCODINGSUSED) size += sizeof(unsigned long long);
1676 if (a & ATTR_VOL_CAPABILITIES) size += sizeof(vol_capabilities_attr_t);
1677 if (a & ATTR_VOL_ATTRIBUTES) size += sizeof(vol_attributes_attr_t);
1678 };
1679 if ((a = attrlist->dirattr) != 0) {
1680 if (a & ATTR_DIR_LINKCOUNT) size += sizeof(u_long);
1681 if (a & ATTR_DIR_ENTRYCOUNT) size += sizeof(u_long);
1682 if (a & ATTR_DIR_MOUNTSTATUS) size += sizeof(u_long);
1683 };
1684 if ((a = attrlist->fileattr) != 0) {
1685 if (a & ATTR_FILE_LINKCOUNT) size += sizeof(u_long);
1686 if (a & ATTR_FILE_TOTALSIZE) size += sizeof(off_t);
1687 if (a & ATTR_FILE_ALLOCSIZE) size += sizeof(off_t);
1688 if (a & ATTR_FILE_IOBLOCKSIZE) size += sizeof(size_t);
1689 if (a & ATTR_FILE_CLUMPSIZE) size += sizeof(off_t);
1690 if (a & ATTR_FILE_DEVTYPE) size += sizeof(u_long);
1691 if (a & ATTR_FILE_FILETYPE) size += sizeof(u_long);
1692 if (a & ATTR_FILE_FORKCOUNT) size += sizeof(u_long);
1693 if (a & ATTR_FILE_FORKLIST) size += sizeof(struct attrreference);
1694 if (a & ATTR_FILE_DATALENGTH) size += sizeof(off_t);
1695 if (a & ATTR_FILE_DATAALLOCSIZE) size += sizeof(off_t);
1696 if (a & ATTR_FILE_DATAEXTENTS) size += sizeof(extentrecord);
1697 if (a & ATTR_FILE_RSRCLENGTH) size += sizeof(off_t);
1698 if (a & ATTR_FILE_RSRCALLOCSIZE) size += sizeof(off_t);
1699 if (a & ATTR_FILE_RSRCEXTENTS) size += sizeof(extentrecord);
1700 };
1701 if ((a = attrlist->forkattr) != 0) {
1702 if (a & ATTR_FORK_TOTALSIZE) size += sizeof(off_t);
1703 if (a & ATTR_FORK_ALLOCSIZE) size += sizeof(off_t);
1704 };
1705
1706 return size;
1707 }
1708
1709
1710
1711 char* FindMountpointName(struct mount *mp) {
1712 size_t namelength = strlen(mp->mnt_stat.f_mntonname);
1713 int foundchars = 0;
1714 char *c;
1715
1716 if (namelength == 0) return NULL;
1717
1718 /* Look backwards through the name string, looking for the first slash
1719 encountered (which must precede the last part of the pathname)
1720 */
1721 for (c = mp->mnt_stat.f_mntonname + namelength - 1; namelength > 0; --c, --namelength) {
1722 if (*c != '/') {
1723 foundchars = 1;
1724 } else if (foundchars) {
1725 return (c + 1);
1726 };
1727 };
1728
1729 return mp->mnt_stat.f_mntonname;
1730 }
1731
1732
1733
1734 void PackObjectName(struct vnode *vp,
1735 char *name,
1736 size_t namelen,
1737 void **attrbufptrptr,
1738 void **varbufptrptr) {
1739 char *mpname;
1740 size_t mpnamelen;
1741 u_long attrlength;
1742
1743 /* The name of an object may be incorrect for the root of a mounted filesystem
1744 because it may be mounted on a different directory name than the name of the
1745 volume (such as "blah-1". For the root directory, it's best to return the
1746 last element of the location where the volume's mounted:
1747 */
1748 if ((vp->v_flag & VROOT) && (mpname = FindMountpointName(vp->v_mount))) {
1749 mpnamelen = strlen(mpname);
1750
1751 /* Trim off any trailing slashes: */
1752 while ((mpnamelen > 0) && (mpname[mpnamelen-1] == '/')) {
1753 --mpnamelen;
1754 };
1755
1756 /* If there's anything left, use it instead of the volume's name */
1757 if (mpnamelen > 0) {
1758 name = mpname;
1759 namelen = mpnamelen;
1760 };
1761 };
1762
1763 attrlength = namelen + 1;
1764 ((struct attrreference *)(*attrbufptrptr))->attr_dataoffset = (char *)(*varbufptrptr) - (char *)(*attrbufptrptr);
1765 ((struct attrreference *)(*attrbufptrptr))->attr_length = attrlength;
1766 (void) strncpy((unsigned char *)(*varbufptrptr), name, attrlength);
1767
1768 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1769 (char *)(*varbufptrptr) += attrlength + ((4 - (attrlength & 3)) & 3);
1770 ++((struct attrreference *)(*attrbufptrptr));
1771 }
1772
1773
1774
1775 void PackVolCommonAttributes(struct attrlist *alist,
1776 struct vnode *root_vp,
1777 struct hfsCatalogInfo *root_catInfo,
1778 void **attrbufptrptr,
1779 void **varbufptrptr) {
1780 void *attrbufptr;
1781 void *varbufptr;
1782 attrgroup_t a;
1783 struct hfsnode *root_hp = VTOH(root_vp);
1784 struct mount *mp = VTOVFS(root_vp);
1785 struct hfsmount *hfsmp = VTOHFS(root_vp);
1786 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1787 u_long attrlength;
1788
1789 attrbufptr = *attrbufptrptr;
1790 varbufptr = *varbufptrptr;
1791
1792 if ((a = alist->commonattr) != 0) {
1793 if (a & ATTR_CMN_NAME) {
1794 PackObjectName(root_vp, H_NAME(root_hp), root_hp->h_meta->h_namelen, &attrbufptr, &varbufptr);
1795 };
1796 if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = hfsmp->hfs_raw_dev;
1797 if (a & ATTR_CMN_FSID) {
1798 *((fsid_t *)attrbufptr) = mp->mnt_stat.f_fsid;
1799 ++((fsid_t *)attrbufptr);
1800 };
1801 if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = 0;
1802 if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = VT_HFS;
1803 if (a & ATTR_CMN_OBJID) {
1804 ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1805 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1806 ++((fsobj_id_t *)attrbufptr);
1807 };
1808 if (a & ATTR_CMN_OBJPERMANENTID) {
1809 ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1810 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1811 ++((fsobj_id_t *)attrbufptr);
1812 };
1813 if (a & ATTR_CMN_PAROBJID) {
1814 ((fsobj_id_t *)attrbufptr)->fid_objno = 0;
1815 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
1816 ++((fsobj_id_t *)attrbufptr);
1817 };
1818 VCB_LOCK(vcb);
1819 if (a & ATTR_CMN_SCRIPT) *((text_encoding_t *)attrbufptr)++ = vcb->volumeNameEncodingHint;
1820 /* NOTE: all VCB dates are in Mac OS time */
1821 if (a & ATTR_CMN_CRTIME) {
1822 ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbCrDate);
1823 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1824 ++((struct timespec *)attrbufptr);
1825 };
1826 if (a & ATTR_CMN_MODTIME) {
1827 ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod);
1828 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1829 ++((struct timespec *)attrbufptr);
1830 };
1831 if (a & ATTR_CMN_CHGTIME) {
1832 ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod);
1833 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1834 ++((struct timespec *)attrbufptr);
1835 };
1836 if (a & ATTR_CMN_ACCTIME) {
1837 ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbLsMod);
1838 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1839 ++((struct timespec *)attrbufptr);
1840 };
1841 if (a & ATTR_CMN_BKUPTIME) {
1842 ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(vcb->vcbVolBkUp);
1843 ((struct timespec *)attrbufptr)->tv_nsec = 0;
1844 ++((struct timespec *)attrbufptr);
1845 };
1846 if (a & ATTR_CMN_FNDRINFO) {
1847 bcopy (&vcb->vcbFndrInfo, attrbufptr, sizeof(vcb->vcbFndrInfo));
1848 (char *)attrbufptr += sizeof(vcb->vcbFndrInfo);
1849 };
1850 VCB_UNLOCK(vcb);
1851 if (a & ATTR_CMN_OWNERID) {
1852 if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
1853 *((uid_t *)attrbufptr)++ =
1854 (VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid;
1855 } else {
1856 *((uid_t *)attrbufptr)++ =
1857 (root_hp->h_meta->h_uid == UNKNOWNUID) ? console_user : root_hp->h_meta->h_uid;
1858 };
1859 };
1860 if (a & ATTR_CMN_GRPID) {
1861 if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
1862 *((gid_t *)attrbufptr)++ = VTOHFS(root_vp)->hfs_gid;
1863 } else {
1864 *((gid_t *)attrbufptr)++ = root_hp->h_meta->h_gid;
1865 };
1866 };
1867 if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)root_hp->h_meta->h_mode;
1868 if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */
1869 if (a & ATTR_CMN_NAMEDATTRLIST) {
1870 attrlength = 0;
1871 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
1872 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
1873
1874 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
1875 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
1876 ++((struct attrreference *)attrbufptr);
1877 };
1878 if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = root_hp->h_meta->h_pflags;
1879 if (a & ATTR_CMN_USERACCESS) {
1880 if (mp->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
1881 *((u_long *)attrbufptr)++ =
1882 DerivePermissionSummary((VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid,
1883 VTOHFS(root_vp)->hfs_gid,
1884 root_hp->h_meta->h_mode,
1885 VTOVFS(root_vp),
1886 current_proc()->p_ucred,
1887 current_proc());
1888 } else {
1889 *((u_long *)attrbufptr)++ =
1890 DerivePermissionSummary((root_hp->h_meta->h_uid == UNKNOWNUID) ? console_user : root_hp->h_meta->h_uid,
1891 root_hp->h_meta->h_gid,
1892 root_hp->h_meta->h_mode,
1893 VTOVFS(root_vp),
1894 current_proc()->p_ucred,
1895 current_proc());
1896 };
1897 };
1898 };
1899
1900 *attrbufptrptr = attrbufptr;
1901 *varbufptrptr = varbufptr;
1902 }
1903
1904
1905
1906 void PackVolAttributeBlock(struct attrlist *alist,
1907 struct vnode *root_vp,
1908 struct hfsCatalogInfo *root_catInfo,
1909 void **attrbufptrptr,
1910 void **varbufptrptr) {
1911 void *attrbufptr;
1912 void *varbufptr;
1913 attrgroup_t a;
1914 struct mount *mp = VTOVFS(root_vp);
1915 struct hfsmount *hfsmp = VTOHFS(root_vp);
1916 ExtendedVCB *vcb = HFSTOVCB(hfsmp);
1917 u_long attrlength;
1918
1919 attrbufptr = *attrbufptrptr;
1920 varbufptr = *varbufptrptr;
1921
1922 if ((a = alist->volattr) != 0) {
1923 VCB_LOCK(vcb);
1924 if (a & ATTR_VOL_FSTYPE) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_vfc->vfc_typenum;
1925 if (a & ATTR_VOL_SIGNATURE) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbSigWord;
1926 if (a & ATTR_VOL_SIZE) *((off_t *)attrbufptr)++ = (off_t)vcb->totalBlocks * (off_t)vcb->blockSize;
1927 if (a & ATTR_VOL_SPACEFREE) *((off_t *)attrbufptr)++ = (off_t)vcb->freeBlocks * (off_t)vcb->blockSize;
1928 if (a & ATTR_VOL_SPACEAVAIL) *((off_t *)attrbufptr)++ = (off_t)vcb->freeBlocks * (off_t)vcb->blockSize;
1929 if (a & ATTR_VOL_MINALLOCATION) *((off_t *)attrbufptr)++ = (off_t)vcb->blockSize;
1930 if (a & ATTR_VOL_ALLOCATIONCLUMP) *((off_t *)attrbufptr)++ = (off_t)(vcb->vcbClpSiz);
1931 if (a & ATTR_VOL_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = (u_long)hfsmp->hfs_logBlockSize;
1932 if (a & ATTR_VOL_OBJCOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt + (u_long)vcb->vcbDirCnt;
1933 if (a & ATTR_VOL_FILECOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbFilCnt;
1934 if (a & ATTR_VOL_DIRCOUNT) *((u_long *)attrbufptr)++ = (u_long)vcb->vcbDirCnt;
1935 if (a & ATTR_VOL_MAXOBJCOUNT) *((u_long *)attrbufptr)++ = 0xFFFFFFFF;
1936 if (a & ATTR_VOL_MOUNTPOINT) {
1937 ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
1938 ((struct attrreference *)attrbufptr)->attr_length = strlen(mp->mnt_stat.f_mntonname) + 1;
1939 attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1940 attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */
1941 (void) bcopy(mp->mnt_stat.f_mntonname, varbufptr, attrlength);
1942
1943 /* Advance beyond the space just allocated: */
1944 (char *)varbufptr += attrlength;
1945 ++((struct attrreference *)attrbufptr);
1946 };
1947 if (a & ATTR_VOL_NAME) {
1948 ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
1949 ((struct attrreference *)attrbufptr)->attr_length = VTOH(root_vp)->h_meta->h_namelen + 1;
1950 attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1951 attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */
1952 bcopy(H_NAME(VTOH(root_vp)), varbufptr, attrlength);
1953
1954 /* Advance beyond the space just allocated: */
1955 (char *)varbufptr += attrlength;
1956 ++((struct attrreference *)attrbufptr);
1957 };
1958 if (a & ATTR_VOL_MOUNTFLAGS) *((u_long *)attrbufptr)++ = (u_long)mp->mnt_flag;
1959 if (a & ATTR_VOL_MOUNTEDDEVICE) {
1960 ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
1961 ((struct attrreference *)attrbufptr)->attr_length = strlen(mp->mnt_stat.f_mntfromname) + 1;
1962 attrlength = ((struct attrreference *)attrbufptr)->attr_length;
1963 attrlength = attrlength + ((4 - (attrlength & 3)) & 3); /* round up to the next 4-byte boundary: */
1964 (void) bcopy(mp->mnt_stat.f_mntfromname, varbufptr, attrlength);
1965
1966 /* Advance beyond the space just allocated: */
1967 (char *)varbufptr += attrlength;
1968 ++((struct attrreference *)attrbufptr);
1969 };
1970 if (a & ATTR_VOL_ENCODINGSUSED) *((unsigned long long *)attrbufptr)++ = (unsigned long long)vcb->encodingsBitmap;
1971 if (a & ATTR_VOL_CAPABILITIES) {
1972 if (vcb->vcbSigWord == kHFSPlusSigWord) {
1973 ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_FORMAT] =
1974 VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_SYMBOLICLINKS | VOL_CAP_FMT_HARDLINKS;
1975 } else { /* Plain HFS */
1976 ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_FORMAT] =
1977 VOL_CAP_FMT_PERSISTENTOBJECTIDS;
1978 }
1979 ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_INTERFACES] =
1980 VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_NFSEXPORT | VOL_CAP_INT_READDIRATTR;
1981 ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_RESERVED1] = 0;
1982 ((vol_capabilities_attr_t *)attrbufptr)->capabilities[VOL_CAPABILITIES_RESERVED2] = 0;
1983
1984 ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_FORMAT] =
1985 VOL_CAP_FMT_PERSISTENTOBJECTIDS | VOL_CAP_FMT_SYMBOLICLINKS | VOL_CAP_FMT_HARDLINKS;
1986 ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_INTERFACES] =
1987 VOL_CAP_INT_SEARCHFS | VOL_CAP_INT_ATTRLIST | VOL_CAP_INT_NFSEXPORT | VOL_CAP_INT_READDIRATTR;
1988 ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_RESERVED1] = 0;
1989 ((vol_capabilities_attr_t *)attrbufptr)->valid[VOL_CAPABILITIES_RESERVED2] = 0;
1990
1991 ++((vol_capabilities_attr_t *)attrbufptr);
1992 };
1993 if (a & ATTR_VOL_ATTRIBUTES) {
1994 ((vol_attributes_attr_t *)attrbufptr)->validattr.commonattr = ATTR_CMN_VALIDMASK;
1995 ((vol_attributes_attr_t *)attrbufptr)->validattr.volattr = ATTR_VOL_VALIDMASK;
1996 ((vol_attributes_attr_t *)attrbufptr)->validattr.dirattr = ATTR_DIR_VALIDMASK;
1997 ((vol_attributes_attr_t *)attrbufptr)->validattr.fileattr = ATTR_FILE_VALIDMASK;
1998 ((vol_attributes_attr_t *)attrbufptr)->validattr.forkattr = ATTR_FORK_VALIDMASK;
1999
2000 ((vol_attributes_attr_t *)attrbufptr)->nativeattr.commonattr = ATTR_CMN_VALIDMASK;
2001 ((vol_attributes_attr_t *)attrbufptr)->nativeattr.volattr = ATTR_VOL_VALIDMASK;
2002 ((vol_attributes_attr_t *)attrbufptr)->nativeattr.dirattr = ATTR_DIR_VALIDMASK;
2003 ((vol_attributes_attr_t *)attrbufptr)->nativeattr.fileattr = ATTR_FILE_VALIDMASK;
2004 ((vol_attributes_attr_t *)attrbufptr)->nativeattr.forkattr = ATTR_FORK_VALIDMASK;
2005
2006 ++((vol_attributes_attr_t *)attrbufptr);
2007 };
2008 VCB_UNLOCK(vcb);
2009 };
2010
2011 *attrbufptrptr = attrbufptr;
2012 *varbufptrptr = varbufptr;
2013 }
2014
2015
2016
2017
2018 void PackVolumeInfo(struct attrlist *alist,
2019 struct vnode *root_vp,
2020 struct hfsCatalogInfo *root_catinfo,
2021 void **attrbufptrptr,
2022 void **varbufptrptr) {
2023
2024 PackVolCommonAttributes(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr);
2025 PackVolAttributeBlock(alist, root_vp, root_catinfo, attrbufptrptr, varbufptrptr);
2026 };
2027
2028 // Pack the common attribute contents of an objects hfsCatalogInfo
2029 void PackCommonCatalogInfoAttributeBlock(struct attrlist *alist,
2030 struct vnode *root_vp,
2031 struct hfsCatalogInfo *catalogInfo,
2032 void **attrbufptrptr,
2033 void **varbufptrptr )
2034 {
2035 struct hfsnode *hp;
2036 void *attrbufptr;
2037 void *varbufptr;
2038 attrgroup_t a;
2039 u_long attrlength;
2040 Boolean isHFSPlus;
2041
2042 hp = VTOH(root_vp);
2043 attrbufptr = *attrbufptrptr;
2044 varbufptr = *varbufptrptr;
2045 isHFSPlus = (VTOVCB(root_vp)->vcbSigWord == kHFSPlusSigWord);
2046
2047 if ((a = alist->commonattr) != 0)
2048 {
2049 if (a & ATTR_CMN_NAME)
2050 {
2051 attrlength = strlen(catalogInfo->nodeData.cnm_nameptr) + 1;
2052 ((struct attrreference *)attrbufptr)->attr_dataoffset = (char *)varbufptr - (char *)attrbufptr;
2053 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
2054 (void) strncpy((unsigned char *)varbufptr,
2055 catalogInfo->nodeData.cnm_nameptr, attrlength);
2056
2057 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2058 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
2059 ++((struct attrreference *)attrbufptr);
2060 };
2061 if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = H_DEV(hp);
2062 if (a & ATTR_CMN_FSID) {
2063 *((fsid_t *)attrbufptr) = VTOVFS(root_vp)->mnt_stat.f_fsid;
2064 ++((fsid_t *)attrbufptr);
2065 };
2066 if (a & ATTR_CMN_OBJTYPE)
2067 {
2068 switch (catalogInfo->nodeData.cnd_type) {
2069 case kCatalogFolderNode:
2070 *((fsobj_type_t *)attrbufptr)++ = VDIR;
2071 break;
2072
2073 case kCatalogFileNode:
2074 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2075 if ((HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) &&
2076 (catalogInfo->nodeData.cnd_mode & IFMT)) {
2077 *((fsobj_type_t *)attrbufptr)++ =
2078 IFTOVT((mode_t)catalogInfo->nodeData.cnd_mode);
2079 } else {
2080 *((fsobj_type_t *)attrbufptr)++ = VREG;
2081 };
2082 break;
2083
2084 default:
2085 *((fsobj_type_t *)attrbufptr)++ = VNON;
2086 break;
2087 };
2088 }
2089 if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = root_vp->v_tag;
2090 if (a & ATTR_CMN_OBJID) {
2091 u_int32_t cnid;
2092
2093 /* For hard links use the link's cnid */
2094 if (catalogInfo->nodeData.cnd_iNodeNumCopy != 0)
2095 cnid = catalogInfo->nodeData.cnd_linkCNID;
2096 else
2097 cnid = catalogInfo->nodeData.cnd_nodeID;
2098 ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
2099 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
2100 ++((fsobj_id_t *)attrbufptr);
2101 };
2102 if (a & ATTR_CMN_OBJPERMANENTID) {
2103 u_int32_t cnid;
2104
2105 /* For hard links use the link's cnid */
2106 if (catalogInfo->nodeData.cnd_iNodeNumCopy != 0)
2107 cnid = catalogInfo->nodeData.cnd_linkCNID;
2108 else
2109 cnid = catalogInfo->nodeData.cnd_nodeID;
2110 ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
2111 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
2112 ++((fsobj_id_t *)attrbufptr);
2113 };
2114 if (a & ATTR_CMN_PAROBJID)
2115 {
2116 ((fsobj_id_t *)attrbufptr)->fid_objno = catalogInfo->nodeData.cnm_parID;
2117 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
2118 ++((fsobj_id_t *)attrbufptr);
2119 };
2120 if (a & ATTR_CMN_SCRIPT)
2121 {
2122 if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) {
2123 *((text_encoding_t *)attrbufptr)++ = catalogInfo->nodeData.cnd_textEncoding;
2124 } else {
2125 *((text_encoding_t *)attrbufptr)++ = VTOHFS(root_vp)->hfs_encoding;
2126 }
2127 };
2128 if (a & ATTR_CMN_CRTIME)
2129 {
2130 ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_createDate);
2131 ((struct timespec *)attrbufptr)->tv_nsec = 0;
2132 ++((struct timespec *)attrbufptr);
2133 };
2134 if (a & ATTR_CMN_MODTIME)
2135 {
2136 ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_contentModDate);
2137 ((struct timespec *)attrbufptr)->tv_nsec = 0;
2138 ++((struct timespec *)attrbufptr);
2139 };
2140 if (a & ATTR_CMN_CHGTIME)
2141 {
2142 ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_attributeModDate);
2143 ((struct timespec *)attrbufptr)->tv_nsec = 0;
2144 ++((struct timespec *)attrbufptr);
2145 };
2146 if (a & ATTR_CMN_ACCTIME)
2147 {
2148 ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_accessDate);
2149 ((struct timespec *)attrbufptr)->tv_nsec = 0;
2150 ++((struct timespec *)attrbufptr);
2151 };
2152 if (a & ATTR_CMN_BKUPTIME)
2153 {
2154 ((struct timespec *)attrbufptr)->tv_sec = to_bsd_time(catalogInfo->nodeData.cnd_backupDate);
2155 ((struct timespec *)attrbufptr)->tv_nsec = 0;
2156 ++((struct timespec *)attrbufptr);
2157 };
2158 if (a & ATTR_CMN_FNDRINFO)
2159 {
2160 bcopy (&catalogInfo->nodeData.cnd_finderInfo, attrbufptr, sizeof(catalogInfo->nodeData.cnd_finderInfo));
2161 (char *)attrbufptr += sizeof(catalogInfo->nodeData.cnd_finderInfo);
2162 };
2163 if (a & ATTR_CMN_OWNERID) {
2164 if ((VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) ||
2165 ((catalogInfo->nodeData.cnd_mode & IFMT) == 0)) {
2166 *((uid_t *)attrbufptr)++ =
2167 (VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid;
2168 } else {
2169 *((uid_t *)attrbufptr)++ =
2170 (catalogInfo->nodeData.cnd_ownerID == UNKNOWNUID) ? console_user : catalogInfo->nodeData.cnd_ownerID;
2171 };
2172 }
2173 if (a & ATTR_CMN_GRPID) {
2174 if ((VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) ||
2175 ((catalogInfo->nodeData.cnd_mode & IFMT) == 0)) {
2176 *((gid_t *)attrbufptr)++ = VTOHFS(root_vp)->hfs_gid;
2177 } else {
2178 *((gid_t *)attrbufptr)++ = catalogInfo->nodeData.cnd_groupID;
2179 };
2180 }
2181 if (a & ATTR_CMN_ACCESSMASK) {
2182 if (((catalogInfo->nodeData.cnd_mode & IFMT) == 0)
2183 #if OVERRIDE_UNKNOWN_PERMISSIONS
2184 || (VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS)
2185 #endif
2186 ) {
2187 switch (catalogInfo->nodeData.cnd_type) {
2188 case kCatalogFileNode:
2189 /* Files in an HFS+ catalog can represent many things (regular files, symlinks, block/character devices, ...) */
2190 *((u_long *)attrbufptr)++ = (u_long)(IFREG | (ACCESSPERMS & (u_long)(VTOHFS(root_vp)->hfs_file_mask)));
2191 break;
2192
2193 case kCatalogFolderNode:
2194 *((u_long *)attrbufptr)++ = (u_long)(IFDIR | (ACCESSPERMS & (u_long)(VTOHFS(root_vp)->hfs_dir_mask)));
2195 break;
2196
2197 default:
2198 *((u_long *)attrbufptr)++ = (u_long)((catalogInfo->nodeData.cnd_mode & IFMT) |
2199 VTOHFS(root_vp)->hfs_dir_mask);
2200 };
2201 } else {
2202 *((u_long *)attrbufptr)++ =
2203 (u_long)catalogInfo->nodeData.cnd_mode;
2204 };
2205 }
2206 if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */
2207 if (a & ATTR_CMN_NAMEDATTRLIST)
2208 {
2209 attrlength = 0;
2210 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
2211 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
2212
2213 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2214 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
2215 ++((struct attrreference *)attrbufptr);
2216 };
2217 if (a & ATTR_CMN_FLAGS) {
2218 u_long flags;
2219
2220 if (catalogInfo->nodeData.cnd_mode & IFMT)
2221 flags = catalogInfo->nodeData.cnd_ownerFlags |
2222 catalogInfo->nodeData.cnd_adminFlags << 16;
2223 else
2224 flags = 0;
2225
2226 if (catalogInfo->nodeData.cnd_type == kCatalogFileNode) {
2227 if (catalogInfo->nodeData.cnd_flags & kHFSFileLockedMask)
2228 flags |= UF_IMMUTABLE;
2229 else
2230 flags &= ~UF_IMMUTABLE;
2231 };
2232 *((u_long *)attrbufptr)++ = flags;
2233 };
2234 if (a & ATTR_CMN_USERACCESS) {
2235 if ((VTOVFS(root_vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) ||
2236 ((catalogInfo->nodeData.cnd_mode & IFMT) == 0)) {
2237 *((u_long *)attrbufptr)++ =
2238 DerivePermissionSummary((VTOHFS(root_vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(root_vp)->hfs_uid,
2239 VTOHFS(root_vp)->hfs_gid,
2240 #if OVERRIDE_UNKNOWN_PERMISSIONS
2241 (catalogInfo->nodeData.cnd_type == kCatalogFileNode) ? VTOHFS(root_vp)->hfs_file_mask : VTOHFS(root_vp)->hfs_dir_mask,
2242 #else
2243 (catalogInfo->nodeData.cnd_mode & IFMT) ?
2244 (u_long)catalogInfo->nodeData.cnd_mode :
2245 ((catalogInfo->nodeData.cnd_type == kCatalogFileNode) ?
2246 VTOHFS(root_vp)->hfs_file_mask :
2247 VTOHFS(root_vp)->hfs_dir_mask),
2248 #endif
2249 VTOVFS(root_vp),
2250 current_proc()->p_ucred,
2251 current_proc());
2252 } else {
2253 *((u_long *)attrbufptr)++ =
2254 DerivePermissionSummary((catalogInfo->nodeData.cnd_ownerID == UNKNOWNUID) ? console_user : catalogInfo->nodeData.cnd_ownerID,
2255 catalogInfo->nodeData.cnd_groupID,
2256 (mode_t)catalogInfo->nodeData.cnd_mode,
2257 VTOVFS(root_vp),
2258 current_proc()->p_ucred,
2259 current_proc());
2260 };
2261 };
2262 };
2263
2264 *attrbufptrptr = attrbufptr;
2265 *varbufptrptr = varbufptr;
2266 }
2267
2268
2269 void PackCommonAttributeBlock(struct attrlist *alist,
2270 struct vnode *vp,
2271 struct hfsCatalogInfo *catInfo,
2272 void **attrbufptrptr,
2273 void **varbufptrptr) {
2274 struct hfsnode *hp;
2275 void *attrbufptr;
2276 void *varbufptr;
2277 attrgroup_t a;
2278 u_long attrlength;
2279
2280 hp = VTOH(vp);
2281
2282 attrbufptr = *attrbufptrptr;
2283 varbufptr = *varbufptrptr;
2284
2285 if ((a = alist->commonattr) != 0) {
2286 if (a & ATTR_CMN_NAME) {
2287 PackObjectName(vp, H_NAME(hp), hp->h_meta->h_namelen, &attrbufptr, &varbufptr);
2288 };
2289 if (a & ATTR_CMN_DEVID) *((dev_t *)attrbufptr)++ = H_DEV(hp);
2290 if (a & ATTR_CMN_FSID) {
2291 *((fsid_t *)attrbufptr) = VTOVFS(vp)->mnt_stat.f_fsid;
2292 ++((fsid_t *)attrbufptr);
2293 };
2294 if (a & ATTR_CMN_OBJTYPE) *((fsobj_type_t *)attrbufptr)++ = vp->v_type;
2295 if (a & ATTR_CMN_OBJTAG) *((fsobj_tag_t *)attrbufptr)++ = vp->v_tag;
2296 if (a & ATTR_CMN_OBJID) {
2297 u_int32_t cnid;
2298
2299 /* For hard links use the link's cnid */
2300 if (hp->h_meta->h_metaflags & IN_DATANODE)
2301 cnid = catInfo->nodeData.cnd_linkCNID;
2302 else
2303 cnid = H_FILEID(hp);
2304 ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
2305 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
2306 ++((fsobj_id_t *)attrbufptr);
2307 };
2308 if (a & ATTR_CMN_OBJPERMANENTID) {
2309 u_int32_t cnid;
2310
2311 /* For hard links use the link's cnid */
2312 if (hp->h_meta->h_metaflags & IN_DATANODE)
2313 cnid = catInfo->nodeData.cnd_linkCNID;
2314 else
2315 cnid = H_FILEID(hp);
2316 ((fsobj_id_t *)attrbufptr)->fid_objno = cnid;
2317 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
2318 ++((fsobj_id_t *)attrbufptr);
2319 };
2320 if (a & ATTR_CMN_PAROBJID) {
2321 ((fsobj_id_t *)attrbufptr)->fid_objno = H_DIRID(hp);
2322 ((fsobj_id_t *)attrbufptr)->fid_generation = 0;
2323 ++((fsobj_id_t *)attrbufptr);
2324 };
2325 if (a & ATTR_CMN_SCRIPT)
2326 {
2327 if (HTOVCB(hp)->vcbSigWord == kHFSPlusSigWord) {
2328 *((text_encoding_t *)attrbufptr)++ = catInfo->nodeData.cnd_textEncoding;
2329 } else {
2330 *((text_encoding_t *)attrbufptr)++ = VTOHFS(vp)->hfs_encoding;
2331 }
2332 };
2333 if (a & ATTR_CMN_CRTIME) {
2334 ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_crtime;
2335 ((struct timespec *)attrbufptr)->tv_nsec = 0;
2336 ++((struct timespec *)attrbufptr);
2337 };
2338 if (a & ATTR_CMN_MODTIME) {
2339 ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_mtime;
2340 ((struct timespec *)attrbufptr)->tv_nsec = 0;
2341 ++((struct timespec *)attrbufptr);
2342 };
2343 if (a & ATTR_CMN_CHGTIME) {
2344 ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_ctime;
2345 ((struct timespec *)attrbufptr)->tv_nsec = 0;
2346 ++((struct timespec *)attrbufptr);
2347 };
2348 if (a & ATTR_CMN_ACCTIME) {
2349 ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_atime;
2350 ((struct timespec *)attrbufptr)->tv_nsec = 0;
2351 ++((struct timespec *)attrbufptr);
2352 };
2353 if (a & ATTR_CMN_BKUPTIME) {
2354 ((struct timespec *)attrbufptr)->tv_sec = hp->h_meta->h_butime;
2355 ((struct timespec *)attrbufptr)->tv_nsec = 0;
2356 ++((struct timespec *)attrbufptr);
2357 };
2358 if (a & ATTR_CMN_FNDRINFO) {
2359 bcopy (&catInfo->nodeData.cnd_finderInfo, attrbufptr, sizeof(catInfo->nodeData.cnd_finderInfo));
2360 (char *)attrbufptr += sizeof(catInfo->nodeData.cnd_finderInfo);
2361 };
2362 if (a & ATTR_CMN_OWNERID) {
2363 if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
2364 *((uid_t *)attrbufptr)++ =
2365 (VTOHFS(vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(vp)->hfs_uid;
2366 } else {
2367 *((uid_t *)attrbufptr)++ =
2368 (hp->h_meta->h_uid == UNKNOWNUID) ? console_user : hp->h_meta->h_uid;
2369 }
2370 };
2371 if (a & ATTR_CMN_GRPID) {
2372 if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
2373 *((gid_t *)attrbufptr)++ = VTOHFS(vp)->hfs_gid;
2374 } else {
2375 *((gid_t *)attrbufptr)++ = hp->h_meta->h_gid;
2376 };
2377 };
2378 if (a & ATTR_CMN_ACCESSMASK) *((u_long *)attrbufptr)++ = (u_long)hp->h_meta->h_mode;
2379 if (a & ATTR_CMN_NAMEDATTRCOUNT) *((u_long *)attrbufptr)++ = 0; /* XXX PPD TBC */
2380 if (a & ATTR_CMN_NAMEDATTRLIST) {
2381 attrlength = 0;
2382 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
2383 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
2384
2385 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2386 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
2387 ++((struct attrreference *)attrbufptr);
2388 };
2389 if (a & ATTR_CMN_FLAGS) *((u_long *)attrbufptr)++ = hp->h_meta->h_pflags;
2390 if (a & ATTR_CMN_USERACCESS) {
2391 if (VTOVFS(vp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
2392 *((u_long *)attrbufptr)++ =
2393 DerivePermissionSummary((VTOHFS(vp)->hfs_uid == UNKNOWNUID) ? console_user : VTOHFS(vp)->hfs_uid,
2394 VTOHFS(vp)->hfs_gid,
2395 hp->h_meta->h_mode,
2396 VTOVFS(vp),
2397 current_proc()->p_ucred,
2398 current_proc());
2399 } else {
2400 *((u_long *)attrbufptr)++ =
2401 DerivePermissionSummary((hp->h_meta->h_uid == UNKNOWNUID) ? console_user : hp->h_meta->h_uid,
2402 hp->h_meta->h_gid,
2403 hp->h_meta->h_mode,
2404 VTOVFS(vp),
2405 current_proc()->p_ucred,
2406 current_proc());
2407 };
2408 };
2409 };
2410
2411 *attrbufptrptr = attrbufptr;
2412 *varbufptrptr = varbufptr;
2413 }
2414
2415
2416 // Pack the directory attributes given hfsCatalogInfo
2417 void PackCatalogInfoDirAttributeBlock( struct attrlist *alist, struct vnode *vp,
2418 struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr )
2419 {
2420 void *attrbufptr;
2421 attrgroup_t a;
2422 u_long valence;
2423
2424 attrbufptr = *attrbufptrptr;
2425 a = alist->dirattr;
2426
2427 if ( (catInfo->nodeData.cnd_type == kCatalogFolderNode) && (a != 0) ) {
2428 valence = catInfo->nodeData.cnd_valence;
2429 if ((catInfo->nodeData.cnm_parID == kRootParID) &&
2430 (VTOHFS(vp)->hfs_private_metadata_dir != 0)) {
2431 --valence; /* hide private dir */
2432 }
2433 /* The 'link count' is faked */
2434 if (a & ATTR_DIR_LINKCOUNT)
2435 *((u_long *)attrbufptr)++ = 2 + valence;
2436 if (a & ATTR_DIR_ENTRYCOUNT)
2437 *((u_long *)attrbufptr)++ = valence;
2438 if (a & ATTR_DIR_MOUNTSTATUS)
2439 *((u_long *)attrbufptr)++ = 0;
2440 };
2441
2442 *attrbufptrptr = attrbufptr;
2443 }
2444
2445
2446 void PackDirAttributeBlock(struct attrlist *alist,
2447 struct vnode *vp,
2448 struct hfsCatalogInfo *catInfo,
2449 void **attrbufptrptr,
2450 void **varbufptrptr) {
2451 void *attrbufptr;
2452 attrgroup_t a;
2453 u_long valence;
2454
2455 attrbufptr = *attrbufptrptr;
2456
2457 a = alist->dirattr;
2458 if ((vp->v_type == VDIR) && (a != 0)) {
2459 valence = catInfo->nodeData.cnd_valence;
2460 if ((catInfo->nodeData.cnm_parID == kRootParID) &&
2461 (VTOHFS(vp)->hfs_private_metadata_dir != 0)) {
2462 --valence; /* hide private dir */
2463 }
2464
2465 /* The 'link count' is faked */
2466 if (a & ATTR_DIR_LINKCOUNT)
2467 *((u_long *)attrbufptr)++ = 2 + valence;
2468 if (a & ATTR_DIR_ENTRYCOUNT)
2469 *((u_long *)attrbufptr)++ = valence;
2470 if (a & ATTR_DIR_MOUNTSTATUS) {
2471 if (vp->v_mountedhere) {
2472 *((u_long *)attrbufptr)++ = DIR_MNTSTATUS_MNTPOINT;
2473 } else {
2474 *((u_long *)attrbufptr)++ = 0;
2475 };
2476 };
2477 };
2478
2479 *attrbufptrptr = attrbufptr;
2480 }
2481
2482
2483
2484 // Pack the file attributes from the hfsCatalogInfo for the file.
2485 void PackCatalogInfoFileAttributeBlock( struct attrlist *alist, struct vnode *root_vp, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr )
2486 {
2487 void *attrbufptr;
2488 void *varbufptr;
2489 attrgroup_t a;
2490 u_long attrlength;
2491 ExtendedVCB *vcb = VTOVCB(root_vp);
2492
2493 attrbufptr = *attrbufptrptr;
2494 varbufptr = *varbufptrptr;
2495
2496 a = alist->fileattr;
2497 if ( (catInfo->nodeData.cnd_type == kCatalogFileNode) && (a != 0) )
2498 {
2499 #if HFS_HARDLINKS
2500 if (a & ATTR_FILE_LINKCOUNT) {
2501 u_long linkcnt = catInfo->nodeData.cnd_linkCount;
2502
2503 if (linkcnt < 1)
2504 linkcnt = 1;
2505 *((u_long *)attrbufptr)++ = linkcnt;
2506 }
2507 #else
2508 if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1;
2509 #endif
2510 if (a & ATTR_FILE_TOTALSIZE) {
2511 *((off_t *)attrbufptr)++ =
2512 (off_t)catInfo->nodeData.cnd_datafork.logicalSize +
2513 (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
2514 }
2515 if (a & ATTR_FILE_ALLOCSIZE) {
2516 *((off_t *)attrbufptr)++ =
2517 (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize) +
2518 (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
2519 }
2520 if (a & ATTR_FILE_IOBLOCKSIZE) {
2521 *((u_long *)attrbufptr)++ = (u_long)(VTOHFS(root_vp)->hfs_logBlockSize);
2522 }
2523 if (a & ATTR_FILE_CLUMPSIZE) {
2524 *((u_long *)attrbufptr)++ = vcb->vcbClpSiz;
2525 }
2526 if (a & ATTR_FILE_DEVTYPE) {
2527 u_long rawdev;
2528 u_short filetype;
2529
2530 filetype = (catInfo->nodeData.cnd_mode & IFMT);
2531 if (filetype == IFCHR || filetype == IFBLK)
2532 rawdev = (u_long)catInfo->nodeData.cnd_rawDevice;
2533 else
2534 rawdev = 0;
2535
2536 *((u_long *)attrbufptr)++ = rawdev;
2537 }
2538 if (a & ATTR_FILE_FILETYPE) {
2539 *((u_long *)attrbufptr)++ = 0; /* XXX PPD */
2540 }
2541 if (a & ATTR_FILE_FORKCOUNT) {
2542 *((u_long *)attrbufptr)++ = 2; /* XXX PPD */
2543 }
2544 if (a & ATTR_FILE_FORKLIST) {
2545 attrlength = 0;
2546 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
2547 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
2548
2549 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2550 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
2551 ++((struct attrreference *)attrbufptr);
2552 };
2553 if (a & ATTR_FILE_DATALENGTH) {
2554 *((off_t *)attrbufptr)++ =
2555 (off_t)catInfo->nodeData.cnd_datafork.logicalSize;
2556 }
2557 if (a & ATTR_FILE_DATAALLOCSIZE) {
2558 *((off_t *)attrbufptr)++ =
2559 (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize);
2560 }
2561 if (a & ATTR_FILE_DATAEXTENTS) {
2562 bcopy(&catInfo->nodeData.cnd_datafork.extents, attrbufptr, sizeof(extentrecord));
2563 (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2564 };
2565 if (a & ATTR_FILE_RSRCLENGTH) {
2566 *((off_t *)attrbufptr)++ =
2567 (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
2568 }
2569 if (a & ATTR_FILE_RSRCALLOCSIZE) {
2570 *((off_t *)attrbufptr)++ =
2571 (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
2572 }
2573 if (a & ATTR_FILE_RSRCEXTENTS) {
2574 bcopy(&catInfo->nodeData.cnd_rsrcfork.extents, attrbufptr, sizeof(extentrecord));
2575 (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2576 };
2577 };
2578
2579 *attrbufptrptr = attrbufptr;
2580 *varbufptrptr = varbufptr;
2581 }
2582
2583
2584 void PackFileAttributeBlock(struct attrlist *alist,
2585 struct vnode *vp,
2586 struct hfsCatalogInfo *catInfo,
2587 void **attrbufptrptr,
2588 void **varbufptrptr) {
2589 struct hfsnode *hp = VTOH(vp);
2590 FCB *fcb = HTOFCB(hp);
2591 ExtendedVCB *vcb = HTOVCB(hp);
2592 Boolean isHFSPlus = (vcb->vcbSigWord == kHFSPlusSigWord);
2593 void *attrbufptr = *attrbufptrptr;
2594 void *varbufptr = *varbufptrptr;
2595 attrgroup_t a = alist->fileattr;
2596 u_long attrlength;
2597
2598 if (a != 0) {
2599 #if HFS_HARDLINKS
2600 if (a & ATTR_FILE_LINKCOUNT) {
2601 u_long linkcnt = catInfo->nodeData.cnd_linkCount;
2602
2603 if (linkcnt < 1)
2604 linkcnt = 1;
2605 *((u_long *)attrbufptr)++ = linkcnt;
2606 }
2607 #else
2608 if (a & ATTR_FILE_LINKCOUNT) *((u_long *)attrbufptr)++ = 1;
2609 #endif
2610 if (a & ATTR_FILE_TOTALSIZE) {
2611 *((off_t *)attrbufptr)++ =
2612 (off_t)catInfo->nodeData.cnd_datafork.logicalSize +
2613 (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
2614 }
2615 if (a & ATTR_FILE_ALLOCSIZE) {
2616 switch (H_FORKTYPE(hp)) {
2617 case kDataFork:
2618 *((off_t *)attrbufptr)++ =
2619 (off_t)fcb->fcbPLen +
2620 (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
2621 break;
2622 case kRsrcFork:
2623 *((off_t *)attrbufptr)++ =
2624 (off_t)fcb->fcbPLen +
2625 (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize);
2626 break;
2627 default:
2628 *((off_t *)attrbufptr)++ =
2629 (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize) +
2630 (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
2631 };
2632 };
2633 if (a & ATTR_FILE_IOBLOCKSIZE) *((u_long *)attrbufptr)++ = GetLogicalBlockSize(vp);
2634 if (a & ATTR_FILE_CLUMPSIZE) *((u_long *)attrbufptr)++ = fcb->fcbClmpSize;
2635 if (a & ATTR_FILE_DEVTYPE) {
2636 u_long rawdev;
2637
2638 if ((vp->v_type == VBLK) || (vp->v_type == VCHR))
2639 rawdev = (u_long)catInfo->nodeData.cnd_rawDevice;
2640 else
2641 rawdev = 0;
2642 *((u_long *)attrbufptr)++ = rawdev;
2643 }
2644 if (a & ATTR_FILE_FILETYPE) *((u_long *)attrbufptr)++ = 0; /* XXX PPD */
2645 if (a & ATTR_FILE_FORKCOUNT) *((u_long *)attrbufptr)++ = 2; /* XXX PPD */
2646 if (a & ATTR_FILE_FORKLIST) {
2647 attrlength = 0;
2648 ((struct attrreference *)attrbufptr)->attr_dataoffset = 0;
2649 ((struct attrreference *)attrbufptr)->attr_length = attrlength;
2650
2651 /* Advance beyond the space just allocated and round up to the next 4-byte boundary: */
2652 (char *)varbufptr += attrlength + ((4 - (attrlength & 3)) & 3);
2653 ++((struct attrreference *)attrbufptr);
2654 };
2655 if (H_FORKTYPE(hp) == kDataFork) {
2656 if (a & ATTR_FILE_DATALENGTH)
2657 *((off_t *)attrbufptr)++ = fcb->fcbEOF;
2658 if (a & ATTR_FILE_DATAALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen;
2659 if (a & ATTR_FILE_DATAEXTENTS) {
2660 bcopy ( fcb->fcbExtents, attrbufptr, sizeof(extentrecord));
2661 (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2662 };
2663 } else {
2664 if (a & ATTR_FILE_DATALENGTH) {
2665 *((off_t *)attrbufptr)++ =
2666 (off_t)catInfo->nodeData.cnd_datafork.logicalSize;
2667 }
2668 if (a & ATTR_FILE_DATAALLOCSIZE) {
2669 *((off_t *)attrbufptr)++ =
2670 (off_t)((off_t)catInfo->nodeData.cnd_datafork.totalBlocks * (off_t)vcb->blockSize);
2671 }
2672 if (a & ATTR_FILE_DATAEXTENTS) {
2673 bcopy(&catInfo->nodeData.cnd_datafork.extents, attrbufptr, sizeof(extentrecord));
2674 (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2675 };
2676 };
2677 if (H_FORKTYPE(hp) == kRsrcFork) {
2678 if (a & ATTR_FILE_RSRCLENGTH)
2679 *((off_t *)attrbufptr)++ = fcb->fcbEOF;
2680 if (a & ATTR_FILE_RSRCALLOCSIZE) *((off_t *)attrbufptr)++ = fcb->fcbPLen;
2681 if (a & ATTR_FILE_RSRCEXTENTS) {
2682 bcopy ( fcb->fcbExtents, attrbufptr, sizeof(extentrecord));
2683 (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2684 };
2685 } else {
2686 if (a & ATTR_FILE_RSRCLENGTH) {
2687 *((off_t *)attrbufptr)++ =
2688 (off_t)catInfo->nodeData.cnd_rsrcfork.logicalSize;
2689 }
2690 if (a & ATTR_FILE_RSRCALLOCSIZE) {
2691 *((off_t *)attrbufptr)++ =
2692 (off_t)((off_t)catInfo->nodeData.cnd_rsrcfork.totalBlocks * (off_t)vcb->blockSize);
2693 }
2694 if (a & ATTR_FILE_RSRCEXTENTS) {
2695 bcopy(&catInfo->nodeData.cnd_rsrcfork.extents, attrbufptr, sizeof(extentrecord));
2696 (char *)attrbufptr += sizeof(extentrecord) + ((4 - (sizeof(extentrecord) & 3)) & 3);
2697 };
2698 };
2699 };
2700
2701 *attrbufptrptr = attrbufptr;
2702 *varbufptrptr = varbufptr;
2703 }
2704
2705 #if 0
2706 void PackForkAttributeBlock(struct attrlist *alist,
2707 struct vnode *vp,
2708 struct hfsCatalogInfo *catInfo,
2709 void **attrbufptrptr,
2710 void **varbufptrptr) {
2711 /* XXX PPD TBC */
2712 }
2713 #endif
2714
2715
2716 // This routine takes catInfo, and alist, as inputs and packs it into an attribute block.
2717 void PackCatalogInfoAttributeBlock ( struct attrlist *alist, struct vnode *root_vp, struct hfsCatalogInfo *catInfo, void **attrbufptrptr, void **varbufptrptr)
2718 {
2719 //XXX Preflight that alist only contains bits with fields in catInfo
2720
2721 PackCommonCatalogInfoAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr );
2722
2723 switch ( catInfo->nodeData.cnd_type )
2724 {
2725 case kCatalogFolderNode:
2726 PackCatalogInfoDirAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr );
2727 break;
2728
2729 case kCatalogFileNode:
2730 PackCatalogInfoFileAttributeBlock( alist, root_vp, catInfo, attrbufptrptr, varbufptrptr );
2731 break;
2732
2733 default: /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR not being handled... */
2734 /* XXX PPD - Panic? */
2735 break;
2736 }
2737 }
2738
2739
2740
2741 void PackAttributeBlock(struct attrlist *alist,
2742 struct vnode *vp,
2743 struct hfsCatalogInfo *catInfo,
2744 void **attrbufptrptr,
2745 void **varbufptrptr)
2746 {
2747 if (alist->volattr != 0) {
2748 DBG_ASSERT((vp->v_flag & VROOT) != 0);
2749 PackVolumeInfo(alist,vp, catInfo, attrbufptrptr, varbufptrptr);
2750 } else {
2751 PackCommonAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
2752
2753 switch (vp->v_type) {
2754 case VDIR:
2755 PackDirAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
2756 break;
2757
2758 case VREG:
2759 case VLNK:
2760 PackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
2761 break;
2762
2763 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
2764 not being handled...
2765 */
2766 default:
2767 /* XXX PPD - Panic? */
2768 break;
2769 };
2770 };
2771 };
2772
2773
2774
2775 void UnpackVolumeAttributeBlock(struct attrlist *alist,
2776 struct vnode *root_vp,
2777 ExtendedVCB *vcb,
2778 void **attrbufptrptr,
2779 void **varbufptrptr) {
2780 void *attrbufptr = *attrbufptrptr;
2781 attrgroup_t a;
2782
2783 if ((alist->commonattr == 0) && (alist->volattr == 0)) {
2784 return; /* Get out without dirtying the VCB */
2785 };
2786
2787 VCB_LOCK(vcb);
2788
2789 a = alist->commonattr;
2790
2791 if (a & ATTR_CMN_SCRIPT) {
2792 vcb->volumeNameEncodingHint = (u_int32_t)*(((text_encoding_t *)attrbufptr)++);
2793 #if HFS_DIAGNOSTIC
2794 a &= ~ATTR_CMN_SCRIPT;
2795 #endif
2796 };
2797 if (a & ATTR_CMN_CRTIME) {
2798 vcb->vcbCrDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2799 /* Need to update the local time also */
2800 vcb->localCreateDate = UTCToLocal(vcb->vcbCrDate);
2801 ++((struct timespec *)attrbufptr);
2802 #if HFS_DIAGNOSTIC
2803 a &= ~ATTR_CMN_CRTIME;
2804 #endif
2805 };
2806 if (a & ATTR_CMN_MODTIME) {
2807 vcb->vcbLsMod = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2808 ++((struct timespec *)attrbufptr);
2809 #if HFS_DIAGNOSTIC
2810 a &= ~ATTR_CMN_MODTIME;
2811 #endif
2812 };
2813 if (a & ATTR_CMN_BKUPTIME) {
2814 vcb->vcbVolBkUp = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2815 ++((struct timespec *)attrbufptr);
2816 #if HFS_DIAGNOSTIC
2817 a &= ~ATTR_CMN_BKUPTIME;
2818 #endif
2819 };
2820 if (a & ATTR_CMN_FNDRINFO) {
2821 bcopy (attrbufptr, &vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo));
2822 (char *)attrbufptr += sizeof(vcb->vcbFndrInfo);
2823 #if HFS_DIAGNOSTIC
2824 a &= ~ATTR_CMN_FNDRINFO;
2825 #endif
2826 };
2827
2828 DBG_ASSERT(a == 0); /* All common attributes for volumes must've been handled by now... */
2829
2830 a = alist->volattr & ~ATTR_VOL_INFO;
2831 if (a & ATTR_VOL_NAME) {
2832 copystr(((char *)attrbufptr) + *((u_long *)attrbufptr), vcb->vcbVN, sizeof(vcb->vcbVN), NULL);
2833 (char *)attrbufptr += sizeof(struct attrreference);
2834 #if HFS_DIAGNOSTIC
2835 a &= ~ATTR_VOL_NAME;
2836 #endif
2837 };
2838
2839 DBG_ASSERT(a == 0); /* All common attributes for volumes must've been handled by now... */
2840
2841 vcb->vcbFlags |= 0xFF00; // Mark the VCB dirty
2842
2843 VCB_UNLOCK(vcb);
2844 }
2845
2846
2847 void UnpackCommonAttributeBlock(struct attrlist *alist,
2848 struct vnode *vp,
2849 struct hfsCatalogInfo *catInfo,
2850 void **attrbufptrptr,
2851 void **varbufptrptr) {
2852 struct hfsnode *hp = VTOH(vp);
2853 void *attrbufptr;
2854 attrgroup_t a;
2855
2856 attrbufptr = *attrbufptrptr;
2857
2858 DBG_ASSERT(catInfo != NULL);
2859
2860 a = alist->commonattr;
2861 if (a & ATTR_CMN_SCRIPT) {
2862 catInfo->nodeData.cnd_textEncoding = (u_int32_t)*((text_encoding_t *)attrbufptr)++;
2863 UpdateVolumeEncodings(VTOVCB(vp), catInfo->nodeData.cnd_textEncoding); /* Update the volume encoding */
2864 #if HFS_DIAGNOSTIC
2865 a &= ~ATTR_CMN_SCRIPT;
2866 #endif
2867 };
2868 if (a & ATTR_CMN_CRTIME) {
2869 catInfo->nodeData.cnd_createDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2870 VTOH(vp)->h_meta->h_crtime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2871 ++((struct timespec *)attrbufptr);
2872 #if HFS_DIAGNOSTIC
2873 a &= ~ATTR_CMN_CRTIME;
2874 #endif
2875 };
2876 if (a & ATTR_CMN_MODTIME) {
2877 catInfo->nodeData.cnd_contentModDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2878 VTOH(vp)->h_meta->h_mtime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2879 ++((struct timespec *)attrbufptr);
2880 hp->h_nodeflags &= ~IN_UPDATE;
2881 #if HFS_DIAGNOSTIC
2882 a &= ~ATTR_CMN_MODTIME;
2883 #endif
2884 };
2885 if (a & ATTR_CMN_CHGTIME) {
2886 catInfo->nodeData.cnd_attributeModDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2887 VTOH(vp)->h_meta->h_ctime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2888 ++((struct timespec *)attrbufptr);
2889 hp->h_nodeflags &= ~IN_CHANGE;
2890 #if HFS_DIAGNOSTIC
2891 a &= ~ATTR_CMN_CHGTIME;
2892 #endif
2893 };
2894 if (a & ATTR_CMN_ACCTIME) {
2895 catInfo->nodeData.cnd_accessDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2896 VTOH(vp)->h_meta->h_atime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2897 ++((struct timespec *)attrbufptr);
2898 hp->h_nodeflags &= ~IN_ACCESS;
2899 #if HFS_DIAGNOSTIC
2900 a &= ~ATTR_CMN_ACCTIME;
2901 #endif
2902 };
2903 if (a & ATTR_CMN_BKUPTIME) {
2904 catInfo->nodeData.cnd_backupDate = to_hfs_time((UInt32)((struct timespec *)attrbufptr)->tv_sec);
2905 VTOH(vp)->h_meta->h_butime = (UInt32)((struct timespec *)attrbufptr)->tv_sec;
2906 ++((struct timespec *)attrbufptr);
2907 #if HFS_DIAGNOSTIC
2908 a &= ~ATTR_CMN_BKUPTIME;
2909 #endif
2910 };
2911 if (a & ATTR_CMN_FNDRINFO) {
2912 bcopy (attrbufptr, &catInfo->nodeData.cnd_finderInfo, sizeof(catInfo->nodeData.cnd_finderInfo));
2913 (char *)attrbufptr += sizeof(catInfo->nodeData.cnd_finderInfo);
2914 #if HFS_DIAGNOSTIC
2915 a &= ~ATTR_CMN_FNDRINFO;
2916 #endif
2917 };
2918 if (a & ATTR_CMN_OWNERID) {
2919 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
2920 u_int32_t uid = (u_int32_t)*((uid_t *)attrbufptr)++;
2921 if (uid != (uid_t)VNOVAL)
2922 hp->h_meta->h_uid = uid; /* catalog will get updated by hfs_chown() */
2923 }
2924 else {
2925 ((uid_t *)attrbufptr)++;
2926 }
2927 #if HFS_DIAGNOSTIC
2928 a &= ~ATTR_CMN_OWNERID;
2929 #endif
2930 };
2931 if (a & ATTR_CMN_GRPID) {
2932 u_int32_t gid = (u_int32_t)*((gid_t *)attrbufptr)++;
2933 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
2934 if (gid != (gid_t)VNOVAL)
2935 hp->h_meta->h_gid = gid; /* catalog will get updated by hfs_chown() */
2936 };
2937 #if HFS_DIAGNOSTIC
2938 a &= ~ATTR_CMN_GRPID;
2939 #endif
2940 };
2941 if (a & ATTR_CMN_ACCESSMASK) {
2942 u_int16_t mode = (u_int16_t)*((u_long *)attrbufptr)++;
2943 if (VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) {
2944 if (mode != (mode_t)VNOVAL) {
2945 hp->h_meta->h_mode &= ~ALLPERMS;
2946 hp->h_meta->h_mode |= (mode & ALLPERMS); /* catalog will get updated by hfs_chmod() */
2947 }
2948 };
2949 #if HFS_DIAGNOSTIC
2950 a &= ~ATTR_CMN_ACCESSMASK;
2951 #endif
2952 };
2953 if (a & ATTR_CMN_FLAGS) {
2954 u_long flags = *((u_long *)attrbufptr)++;
2955 /* Flags are settable only on HFS+ volumes. A special exception is made for the IMMUTABLE
2956 flags (SF_IMMUTABLE and UF_IMMUTABLE), which can be set on HFS volumes as well: */
2957 if ((VTOVCB(vp)->vcbSigWord == kHFSPlusSigWord) ||
2958 ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && ((flags & ~IMMUTABLE) == 0))) {
2959 if (flags != (u_long)VNOVAL) {
2960 hp->h_meta->h_pflags = flags; /* catalog will get updated by hfs_chflags */
2961 };
2962 };
2963 #if HFS_DIAGNOSTIC
2964 a &= ~ATTR_CMN_FLAGS;
2965 #endif
2966 };
2967
2968 #if HFS_DIAGNOSTIC
2969 if (a != 0) {
2970 DEBUG_BREAK_MSG(("UnpackCommonAttributes: unhandled bit: 0x%08X\n", a));
2971 };
2972 #endif
2973
2974 *attrbufptrptr = attrbufptr;
2975 // *varbufptrptr = varbufptr;
2976 }
2977
2978
2979
2980 #if 0
2981 void UnpackDirAttributeBlock(struct attrlist *alist,
2982 struct vnode *vp,
2983 struct hfsCatalogInfo *catInfo,
2984 void **attrbufptrptr,
2985 void **varbufptrptr) {
2986 void *attrbufptr;
2987 void *varbufptr;
2988 attrgroup_t a;
2989 u_long attrlength;
2990
2991 attrbufptr = *attrbufptrptr;
2992 varbufptr = *varbufptrptr;
2993
2994 /* XXX PPD TBC */
2995
2996 *attrbufptrptr = attrbufptr;
2997 *varbufptrptr = varbufptr;
2998 }
2999 #endif
3000
3001
3002
3003 #if 0
3004 void UnpackFileAttributeBlock(struct attrlist *alist,
3005 struct vnode *vp,
3006 struct hfsCatalogInfo *catInfo,
3007 void **attrbufptrptr,
3008 void **varbufptrptr) {
3009 void *attrbufptr;
3010 void *varbufptr;
3011 attrgroup_t a;
3012 u_long attrlength;
3013
3014 attrbufptr = *attrbufptrptr;
3015 varbufptr = *varbufptrptr;
3016
3017 /* XXX PPD TBC */
3018
3019 *attrbufptrptr = attrbufptr;
3020 *varbufptrptr = varbufptr;
3021 }
3022 #endif
3023
3024
3025
3026 #if 0
3027 void UnpackForkAttributeBlock(struct attrlist *alist,
3028 struct vnode *vp,
3029 struct hfsCatalogInfo *catInfo,
3030 void **attrbufptrptr,
3031 void **varbufptrptr) {
3032 void *attrbufptr;
3033 void *varbufptr;
3034 attrgroup_t a;
3035 u_long attrlength;
3036
3037 attrbufptr = *attrbufptrptr;
3038 varbufptr = *varbufptrptr;
3039
3040 /* XXX PPD TBC */
3041
3042 *attrbufptrptr = attrbufptr;
3043 *varbufptrptr = varbufptr;
3044 }
3045 #endif
3046
3047
3048
3049 void UnpackAttributeBlock(struct attrlist *alist,
3050 struct vnode *vp,
3051 struct hfsCatalogInfo *catInfo,
3052 void **attrbufptrptr,
3053 void **varbufptrptr) {
3054
3055
3056 if (alist->volattr != 0) {
3057 UnpackVolumeAttributeBlock(alist, vp, VTOVCB(vp), attrbufptrptr, varbufptrptr);
3058 return;
3059 };
3060
3061 /* We're dealing with a vnode object here: */
3062 UnpackCommonAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
3063
3064 #if 0
3065 switch (vp->v_type) {
3066 case VDIR:
3067 UnpackDirAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
3068 break;
3069
3070 case VREG:
3071 /* case VCPLX: */ /* XXX PPD TBC */
3072 UnpackFileAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
3073 break;
3074
3075 case VFORK:
3076 UnpackForkAttributeBlock(alist, vp, catInfo, attrbufptrptr, varbufptrptr);
3077 break;
3078
3079 /* Without this the compiler complains about VNON,VBLK,VCHR,VLNK,VSOCK,VFIFO,VBAD and VSTR
3080 not being handled...
3081 */
3082 default:
3083 /* XXX PPD - Panic? */
3084 break;
3085 };
3086 #endif
3087
3088 };
3089
3090
3091 unsigned long BestBlockSizeFit(unsigned long allocationBlockSize,
3092 unsigned long blockSizeLimit,
3093 unsigned long baseMultiple) {
3094 /*
3095 Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the
3096 specified limit but still an even multiple of the baseMultiple.
3097 */
3098 int baseBlockCount, blockCount;
3099 unsigned long trialBlockSize;
3100
3101 if (allocationBlockSize % baseMultiple != 0) {
3102 /*
3103 Whoops: the allocation blocks aren't even multiples of the specified base:
3104 no amount of dividing them into even parts will be a multiple, either then!
3105 */
3106 return 512; /* Hope for the best */
3107 };
3108
3109 /* Try the obvious winner first, to prevent 12K allocation blocks, for instance,
3110 from being handled as two 6K logical blocks instead of 3 4K logical blocks.
3111 Even though the former (the result of the loop below) is the larger allocation
3112 block size, the latter is more efficient: */
3113 if (allocationBlockSize % PAGE_SIZE == 0) return PAGE_SIZE;
3114
3115 /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */
3116 baseBlockCount = allocationBlockSize / baseMultiple; /* Now guaranteed to be an even multiple */
3117
3118 for (blockCount = baseBlockCount; blockCount > 0; --blockCount) {
3119 trialBlockSize = blockCount * baseMultiple;
3120 if (allocationBlockSize % trialBlockSize == 0) { /* An even multiple? */
3121 if ((trialBlockSize <= blockSizeLimit) &&
3122 (trialBlockSize % baseMultiple == 0)) {
3123 return trialBlockSize;
3124 };
3125 };
3126 };
3127
3128 /* Note: we should never get here, since blockCount = 1 should always work,
3129 but this is nice and safe and makes the compiler happy, too ... */
3130 return 512;
3131 }
3132
3133
3134 /*
3135 * To make the HFS Plus filesystem follow UFS unlink semantics, a remove
3136 * of an active vnode is translated to a move/rename so the file appears
3137 * deleted. The destination folder for these move/renames is setup here
3138 * and a reference to it is place in hfsmp->hfs_private_metadata_dir.
3139 */
3140 u_long
3141 FindMetaDataDirectory(ExtendedVCB *vcb)
3142 {
3143 char namep[32];
3144 hfsCatalogInfo catInfo;
3145 HFSCatalogNodeID dirID;
3146 u_int32_t metadata_createdate;
3147 int retval;
3148
3149 if (vcb->vcbSigWord != kHFSPlusSigWord)
3150 return (0);
3151
3152 dirID = 0;
3153 metadata_createdate = 0;
3154 strncpy(namep, HFSPLUS_PRIVATE_DIR, sizeof(namep));
3155 INIT_CATALOGDATA(&catInfo.nodeData, kCatNameNoCopyName);
3156 catInfo.hint = kNoHint;
3157
3158 /* lock catalog b-tree */
3159 retval = hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_SHARED, current_proc());
3160 if (retval) goto Err_Exit;
3161
3162 if (hfs_getcatalog(vcb, kRootDirID, namep, -1, &catInfo) == 0) {
3163 dirID = catInfo.nodeData.cnd_nodeID;
3164 metadata_createdate = catInfo.nodeData.cnd_createDate;
3165 } else if (VCBTOHFS(vcb)->hfs_fs_ronly == 0) {
3166 if (CreateCatalogNode(vcb, kRootDirID, namep, kCatalogFolderNode, &dirID, &catInfo.hint, 0) == 0) {
3167 catInfo.hint = kNoHint;
3168 if (hfs_getcatalog(vcb, kRootDirID, namep, -1, &catInfo) == 0) {
3169
3170 /* create date is later used for validation */
3171 catInfo.nodeData.cnd_createDate = vcb->vcbCrDate;
3172 metadata_createdate = catInfo.nodeData.cnd_createDate;
3173
3174 /* directory with no permissions owned by root */
3175 catInfo.nodeData.cnd_mode = IFDIR;
3176 catInfo.nodeData.cnd_adminFlags = (SF_IMMUTABLE >> 16);
3177
3178 /* hidden and off the desktop view */
3179 ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frLocation.v = SWAP_BE16 (22460);
3180 ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frLocation.h = SWAP_BE16 (22460);
3181 ((struct DInfo *)(&catInfo.nodeData.cnd_finderInfo))->frFlags |= SWAP_BE16 (kIsInvisible + kNameLocked);
3182
3183 (void) UpdateCatalogNode(vcb, kRootDirID, namep, catInfo.hint, &catInfo.nodeData);
3184 }
3185 }
3186 }
3187
3188 /* unlock catalog b-tree */
3189 (void) hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_RELEASE, current_proc());
3190
3191 VCBTOHFS(vcb)->hfs_metadata_createdate = metadata_createdate;
3192 Err_Exit:
3193 CLEAN_CATALOGDATA(&catInfo.nodeData);
3194
3195 return dirID;
3196 }
3197
3198
3199 static void
3200 RemovedMetaDataDirectory(ExtendedVCB *vcb)
3201 {
3202 char name[32];
3203 hfsCatalogInfo catInfo;
3204 int retval;
3205
3206 strncpy(name, HFSPLUS_PRIVATE_DIR, sizeof(name));
3207 INIT_CATALOGDATA(&catInfo.nodeData, kCatNameNoCopyName);
3208
3209 /* lock catalog b-tree */
3210 retval = hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_SHARED, current_proc());
3211 if (retval) goto Err_Exit;
3212
3213 /* If the HFSPLUSMETADATAFOLDER exists then delete it. */
3214 retval = GetCatalogNode(vcb, kRootDirID, name, strlen(name), kNoHint,
3215 &catInfo.nodeData, &catInfo.hint);
3216 if (retval == 0 && (catInfo.nodeData.cnd_type == kCatalogFolderNode)) {
3217 (void) DeleteCatalogNode(vcb, kRootDirID, name, catInfo.hint);
3218 printf("hfs_mount: removed \"%s\" from hfs volume \"%s\"\n", name, vcb->vcbVN);
3219 }
3220
3221 /* unlock catalog b-tree */
3222 (void) hfs_metafilelocking(VCBTOHFS(vcb), kHFSCatalogFileID, LK_RELEASE, current_proc());
3223
3224 Err_Exit:
3225 CLEAN_CATALOGDATA(&catInfo.nodeData);
3226 }
3227
3228 /*
3229 * This will return the correct logical block size for a given vnode.
3230 * For most files, it is the allocation block size, for meta data like
3231 * BTrees, this is kept as part of the BTree private nodeSize
3232 */
3233 u_int32_t
3234 GetLogicalBlockSize(struct vnode *vp)
3235 {
3236 u_int32_t logBlockSize;
3237
3238 DBG_ASSERT(vp != NULL);
3239
3240 /* start with default */
3241 logBlockSize = VTOHFS(vp)->hfs_logBlockSize;
3242
3243 if (vp->v_flag & VSYSTEM) {
3244 if (VTOH(vp)->fcbBTCBPtr != NULL) {
3245 BTreeInfoRec bTreeInfo;
3246
3247 /*
3248 * We do not lock the BTrees, because if we are getting block..then the tree
3249 * should be locked in the first place.
3250 * We just want the nodeSize wich will NEVER change..so even if the world
3251 * is changing..the nodeSize should remain the same. Which argues why lock
3252 * it in the first place??
3253 */
3254
3255 (void) BTGetInformation (VTOFCB(vp), kBTreeInfoVersion, &bTreeInfo);
3256
3257 logBlockSize = bTreeInfo.nodeSize;
3258
3259 } else if (H_FILEID(VTOH(vp)) == kHFSAllocationFileID) {
3260 logBlockSize = VTOVCB(vp)->vcbVBMIOSize;
3261 }
3262 }
3263
3264 DBG_ASSERT(logBlockSize > 0);
3265
3266 return logBlockSize;
3267 }
3268
3269 /*
3270 * Map HFS Common errors (negative) to BSD error codes (positive).
3271 * Positive errors (ie BSD errors) are passed through unchanged.
3272 */
3273 short MacToVFSError(OSErr err)
3274 {
3275 if (err >= 0) {
3276 if (err > 0) {
3277 DBG_ERR(("MacToVFSError: passing error #%d unchanged...\n", err));
3278 };
3279 return err;
3280 };
3281
3282 if (err != 0) {
3283 DBG_ERR(("MacToVFSError: mapping error code %d...\n", err));
3284 };
3285
3286 switch (err) {
3287 case dirFulErr: /* -33 */
3288 case dskFulErr: /* -34 */
3289 case btNoSpaceAvail: /* -32733 */
3290 case fxOvFlErr: /* -32750 */
3291 return ENOSPC; /* +28 */
3292
3293 case btBadNode: /* -32731 */
3294 case ioErr: /* -36 */
3295 return EIO; /* +5 */
3296
3297 case mFulErr: /* -41 */
3298 case memFullErr: /* -108 */
3299 return ENOMEM; /* +12 */
3300
3301 case tmfoErr: /* -42 */
3302 /* Consider EMFILE (Too many open files, 24)? */
3303 return ENFILE; /* +23 */
3304
3305 case nsvErr: /* -35 */
3306 case fnfErr: /* -43 */
3307 case dirNFErr: /* -120 */
3308 case fidNotFound: /* -1300 */
3309 return ENOENT; /* +2 */
3310
3311 case wPrErr: /* -44 */
3312 case vLckdErr: /* -46 */
3313 case fsDSIntErr: /* -127 */
3314 return EROFS; /* +30 */
3315
3316 case opWrErr: /* -49 */
3317 case fLckdErr: /* -45 */
3318 return EACCES; /* +13 */
3319
3320 case permErr: /* -54 */
3321 case wrPermErr: /* -61 */
3322 return EPERM; /* +1 */
3323
3324 case fBsyErr: /* -47 */
3325 return EBUSY; /* +16 */
3326
3327 case dupFNErr: /* -48 */
3328 case fidExists: /* -1301 */
3329 case cmExists: /* -32718 */
3330 case btExists: /* -32734 */
3331 return EEXIST; /* +17 */
3332
3333 case rfNumErr: /* -51 */
3334 return EBADF; /* +9 */
3335
3336 case notAFileErr: /* -1302 */
3337 return EISDIR; /* +21 */
3338
3339 case cmNotFound: /* -32719 */
3340 case btNotFound: /* -32735 */
3341 return ENOENT; /* 28 */
3342
3343 case cmNotEmpty: /* -32717 */
3344 return ENOTEMPTY; /* 66 */
3345
3346 case cmFThdDirErr: /* -32714 */
3347 return EISDIR; /* 21 */
3348
3349 case fxRangeErr: /* -32751 */
3350 return EIO; /* 5 */
3351
3352 case bdNamErr: /* -37 */
3353 return ENAMETOOLONG; /* 63 */
3354
3355 case fnOpnErr: /* -38 */
3356 case eofErr: /* -39 */
3357 case posErr: /* -40 */
3358 case paramErr: /* -50 */
3359 case badMDBErr: /* -60 */
3360 case badMovErr: /* -122 */
3361 case sameFileErr: /* -1306 */
3362 case badFidErr: /* -1307 */
3363 case fileBoundsErr: /* -1309 */
3364 return EINVAL; /* +22 */
3365
3366 case fsBTBadNodeSize:
3367 return ENXIO;
3368 default:
3369 DBG_UTILS(("Unmapped MacOS error: %d\n", err));
3370 return EIO; /* +5 */
3371 }
3372 }
3373
3374
3375 /*
3376 * All of our debugging functions
3377 */
3378
3379 #if HFS_DIAGNOSTIC
3380
3381 void debug_vn_status (char* introStr, struct vnode *vn)
3382 {
3383 DBG_VOP(("%s:\t",introStr));
3384 if (vn != NULL)
3385 {
3386 if (vn->v_tag != VT_HFS)
3387 {
3388 DBG_VOP(("NON-HFS VNODE Ox%08lX\n", (unsigned long)vn));
3389 }
3390 else if(vn->v_tag==VT_HFS && (vn->v_data==NULL || VTOH((vn))->h_valid != HFS_VNODE_MAGIC))
3391 {
3392 DBG_VOP(("BAD VNODE PRIVATE DATA!!!!\n"));
3393 }
3394 else
3395 {
3396 DBG_VOP(("r: %d & ", vn->v_usecount));
3397 if (lockstatus(&VTOH(vn)->h_lock))
3398 {
3399 DBG_VOP_CONT(("is L\n"));
3400 }
3401 else
3402 {
3403 DBG_VOP_CONT(("is U\n"));
3404 }
3405 }
3406 }
3407 else
3408 {
3409 DBG_VOP(("vnode is NULL\n"));
3410 };
3411 }
3412
3413 void debug_vn_print (char* introStr, struct vnode *vn)
3414 {
3415 // DBG_FUNC_NAME("DBG_VN_PRINT");
3416 DBG_ASSERT (vn != NULL);
3417 DBG_VFS(("%s: ",introStr));
3418 DBG_VFS_CONT(("vnode: 0x%x is a ", (uint)vn));
3419 switch (vn->v_tag)
3420 {
3421 case VT_UFS:
3422 DBG_VFS_CONT(("%s","UFS"));
3423 break;
3424 case VT_HFS:
3425 DBG_VFS_CONT(("%s","HFS"));
3426 break;
3427 default:
3428 DBG_VFS_CONT(("%s","UNKNOWN"));
3429 break;
3430 }
3431
3432 DBG_VFS_CONT((" vnode\n"));
3433 if (vn->v_tag==VT_HFS)
3434 {
3435 if (vn->v_data==NULL)
3436 {
3437 DBG_VFS(("BAD VNODE PRIVATE DATA!!!!\n"));
3438 }
3439 else
3440 {
3441 DBG_VFS((" Name: %s Id: %ld ",H_NAME(VTOH(vn)), H_FILEID(VTOH(vn))));
3442 }
3443 }
3444 else
3445 DBG_VFS((" "));
3446
3447 DBG_VFS_CONT(("Refcount: %d\n", vn->v_usecount));
3448 if (VOP_ISLOCKED(vn))
3449 {
3450 DBG_VFS((" The vnode is locked\n"));
3451 }
3452 else
3453 {
3454 DBG_VFS((" The vnode is not locked\n"));
3455 }
3456 }
3457
3458 void debug_rename_test_locks (char* introStr,
3459 struct vnode *fvp,
3460 struct vnode *fdvp,
3461 struct vnode *tvp,
3462 struct vnode *tdvp,
3463 int fstatus,
3464 int fdstatus,
3465 int tstatus,
3466 int tdstatus
3467 )
3468 {
3469 DBG_VOP(("\t%s: ", introStr));
3470 if (fvp) {if(lockstatus(&VTOH(fvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3471 if (fdvp) {if(lockstatus(&VTOH(fdvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3472 if (tvp) {if(lockstatus(&VTOH(tvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3473 if (tdvp) {if(lockstatus(&VTOH(tdvp)->h_lock)){DBG_VFS_CONT(("L"));} else {DBG_VFS_CONT(("U"));}} else { DBG_VFS_CONT(("X"));};
3474 DBG_VFS_CONT(("\n"));
3475
3476 if (fvp) {
3477 if (lockstatus(&VTOH(fvp)->h_lock)) {
3478 if (fstatus==VOPDBG_UNLOCKED) {
3479 DBG_VOP(("\tfvp should be NOT LOCKED and it is\n"));
3480 }
3481 } else if (fstatus == VOPDBG_LOCKED) {
3482 DBG_VOP(("\tfvp should be LOCKED and it isnt\n"));
3483 }
3484 }
3485
3486 if (fdvp) {
3487 if (lockstatus(&VTOH(fdvp)->h_lock)) {
3488 if (fdstatus==VOPDBG_UNLOCKED) {
3489 DBG_VOP(("\tfdvp should be NOT LOCKED and it is\n"));
3490 }
3491 } else if (fdstatus == VOPDBG_LOCKED) {
3492 DBG_VOP(("\tfdvp should be LOCKED and it isnt\n"));
3493 }
3494 }
3495
3496 if (tvp) {
3497 if (lockstatus(&VTOH(tvp)->h_lock)) {
3498 if (tstatus==VOPDBG_UNLOCKED) {
3499 DBG_VOP(("\ttvp should be NOT LOCKED and it is\n"));
3500 }
3501 } else if (tstatus == VOPDBG_LOCKED) {
3502 DBG_VOP(("\ttvp should be LOCKED and it isnt\n"));
3503 }
3504 }
3505
3506 if (tdvp) {
3507 if (lockstatus(&VTOH(tdvp)->h_lock)) {
3508 if (tdstatus==VOPDBG_UNLOCKED) {
3509 DBG_VOP(("\ttdvp should be NOT LOCKED and it is\n"));
3510 }
3511 } else if (tdstatus == VOPDBG_LOCKED) {
3512 DBG_VOP(("\ttdvp should be LOCKED and it isnt\n"));
3513
3514 }
3515 }
3516
3517 }
3518 #endif /* HFS_DIAGNOSTIC */
3519
3520
3521 #if HFS_DIAGNOSTIC
3522 void debug_check_buffersizes(struct vnode *vp, struct hfsnode *hp, struct buf *bp) {
3523 DBG_ASSERT(bp->b_validoff == 0);
3524 DBG_ASSERT(bp->b_dirtyoff == 0);
3525 DBG_ASSERT((bp->b_bcount == HTOHFS(hp)->hfs_logBlockSize) ||
3526 ((bp->b_bcount % 512 == 0) &&
3527 (bp->b_validend > 0) &&
3528 (bp->b_dirtyend > 0) &&
3529 (bp->b_bcount < HTOHFS(hp)->hfs_logBlockSize)));
3530
3531 if (bp->b_validend == 0) {
3532 DBG_ASSERT(bp->b_dirtyend == 0);
3533 } else {
3534 DBG_ASSERT(bp->b_validend == bp->b_bcount);
3535 DBG_ASSERT(bp->b_dirtyend <= bp->b_bcount);
3536 };
3537 }
3538
3539
3540 void debug_check_blocksizes(struct vnode *vp) {
3541 struct hfsnode *hp = VTOH(vp);
3542 struct buf *bp;
3543
3544 if (vp->v_flag & VSYSTEM) return;
3545
3546 for (bp = vp->v_cleanblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) {
3547 debug_check_buffersizes(vp, hp, bp);
3548 };
3549
3550 for (bp = vp->v_dirtyblkhd.lh_first; bp != NULL; bp = bp->b_vnbufs.le_next) {
3551 debug_check_buffersizes(vp, hp, bp);
3552 };
3553 }
3554
3555 void debug_check_catalogdata(struct CatalogNodeData *cat) {
3556
3557 if (cat->cnm_nameptr == NULL) {
3558 DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == 0);
3559 }
3560 else if (cat->cnm_nameptr == cat->cnm_namespace) {
3561 DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == 0);
3562 }
3563 else {
3564 DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == kCatNameIsAllocated);
3565 }
3566
3567 if (cat->cnm_nameptr) {
3568 DBG_ASSERT(strlen(cat->cnm_nameptr) == cat->cnm_length);
3569 }
3570
3571 if (cat->cnm_flags & kCatNameIsConsumed) {
3572 DBG_ASSERT((cat->cnm_flags & kCatNameIsAllocated) == 0);
3573 }
3574
3575 if (cat->cnm_flags & kCatNameNoCopyName) {
3576 DBG_ASSERT((cat->cnm_flags & (kCatNameIsAllocated|kCatNameIsConsumed|kCatNameIsMangled)) == 0);
3577 DBG_ASSERT(cat->cnm_length == 0);
3578 DBG_ASSERT(cat->cnm_nameptr == 0);
3579 DBG_ASSERT(strlen(cat->cnm_namespace) == 0);
3580 }
3581
3582 }
3583
3584 extern void hfs_vhash_dbg(struct hfsnode *hp);
3585
3586 /* Checks the valicity of a hfs vnode */
3587 void debug_check_vnode(struct vnode *vp, int stage) {
3588 struct hfsnode *hp;
3589 u_long size;
3590 int i;
3591
3592 /* vcb stuff */
3593 if (VTOHFS(vp)->hfs_mount_flags & kHFSBootVolumeInconsistentMask)
3594 DEBUG_BREAK_MSG(("Volume is damaged!"));
3595
3596 /* vnode stuff */
3597 if (vp==NULL)
3598 DEBUG_BREAK_MSG(("Null vnode"));
3599 if (vp->v_tag != VT_HFS)
3600 DEBUG_BREAK_MSG(("Not a HFS vnode, it is a %d", vp->v_tag));
3601 if (vp->v_data==NULL)
3602 DEBUG_BREAK_MSG(("v_data is NULL"));
3603
3604 /* hfsnode stuff */
3605 hp = VTOH(vp);
3606 if (hp->h_valid != HFS_VNODE_MAGIC)
3607 DEBUG_BREAK_MSG(("Bad Formed HFS node"));
3608 if (hp->h_vp==NULL || hp->h_vp!=vp)
3609 DEBUG_BREAK_MSG(("Bad hfsnode vnode pte"));
3610 if (hp->h_meta == NULL)
3611 DEBUG_BREAK_MSG(("Bad hfsnode meta ptr"));
3612 switch (H_FORKTYPE(hp)) {
3613 case kDataFork:
3614 case kRsrcFork:
3615 if ((hp->h_meta->h_siblinghead.cqh_first == NULL) || (hp->h_meta->h_siblinghead.cqh_last == NULL))
3616 DEBUG_BREAK_MSG(("Null sibling header"));
3617 if ((hp->h_sibling.cqe_next==NULL) || (hp->h_sibling.cqe_prev==NULL))
3618 DEBUG_BREAK_MSG(("Null sibling list"));
3619 if (hp->h_meta->h_usecount<1 || hp->h_meta->h_usecount>2)
3620 DEBUG_BREAK_MSG(("Bad sibling usecount"));
3621 break;
3622 case kDirectory:
3623 case kSysFile:
3624 if ((hp->h_meta->h_siblinghead.cqh_first != NULL) || (hp->h_meta->h_siblinghead.cqh_last != NULL))
3625 DEBUG_BREAK_MSG(("Non Null sibling header"));
3626 if ((hp->h_sibling.cqe_next!=NULL) || (hp->h_sibling.cqe_prev!=NULL))
3627 DEBUG_BREAK_MSG(("Null sibling list"));
3628 if (hp->h_meta->h_usecount!=1)
3629 DEBUG_BREAK_MSG(("Bad usecount"));
3630
3631 break;
3632 default:
3633 DEBUG_BREAK_MSG(("Bad hfsnode fork type"));
3634 }
3635
3636 /* hfsmeta stuff */
3637 if (hp->h_meta->h_devvp == NULL)
3638 DEBUG_BREAK_MSG(("Bad hfsnode dev vnode"));
3639 if (H_DEV(hp) == 0)
3640 DEBUG_BREAK_MSG(("Bad dev id"));
3641 if (H_FILEID(hp) == 0)
3642 DEBUG_BREAK_MSG(("Bad file id"));
3643
3644 if (((hp->h_meta->h_metaflags & IN_DATANODE)==0) && (H_DIRID(hp) == 0) && (H_FILEID(hp) != 1))
3645 DEBUG_BREAK_MSG(("Bad dir id"));
3646
3647 if (hp->h_meta->h_namePtr == NULL && hp->h_meta->h_namelen!=0)
3648 DEBUG_BREAK_MSG(("hfs meta h_namelen is not 0"));
3649 if (hp->h_meta->h_namePtr != NULL && strlen(hp->h_meta->h_namePtr) != hp->h_meta->h_namelen)
3650 DEBUG_BREAK_MSG(("Bad hfs meta h_namelen"));
3651
3652 /* Check the hash */
3653 hfs_vhash_dbg(hp);
3654
3655 /* Check to see if we want to compare with the disk */
3656 if (stage > 200) {
3657 int retval;
3658 hfsCatalogInfo catInfo;
3659
3660 INIT_CATALOGDATA(&catInfo.nodeData, 0);
3661 catInfo.hint = 0;
3662
3663 if (hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_SHARED, current_proc()))
3664 return;
3665
3666 if (hfs_getcatalog(VTOVCB(vp), H_DIRID(hp), hp->h_meta->h_namePtr, hp->h_meta->h_namelen, &catInfo))
3667 DEBUG_BREAK_MSG(("Could not find hfsnode Catalog record"));
3668
3669 (void) hfs_metafilelocking(VTOHFS(vp), kHFSCatalogFileID, LK_RELEASE, current_proc());
3670
3671 if (H_FILEID(hp) != catInfo.nodeData.cnd_nodeID)
3672 DEBUG_BREAK_MSG(("hfsnode catalog node id mismatch"));
3673 if (H_DIRID(hp) != catInfo.nodeData.cnm_parID)
3674 DEBUG_BREAK_MSG(("hfsnode catalog dir id mismatch"));
3675 if (strcmp(hp->h_meta->h_namePtr, catInfo.nodeData.cnm_nameptr) != 0)
3676 DEBUG_BREAK_MSG(("hfsnode catalog name mismatch"));
3677 /* Check dates too??? */
3678
3679 CLEAN_CATALOGDATA(&catInfo.nodeData);
3680
3681 }
3682
3683
3684 /* Check Extents */
3685 {
3686 for(i = 0, size = 0; i < kHFSPlusExtentDensity; i++)
3687 {
3688 size += hp->fcbExtents[i].blockCount;
3689 }
3690
3691 if (hp->fcbEOF > hp->fcbPLen)
3692 DEBUG_BREAK_MSG(("fcbPLen is smaller than fcbEOF"));
3693
3694 if (hp->fcbExtents[kHFSPlusExtentDensity-1].blockCount == 0) {
3695 if ((off_t)size * (off_t)VTOVCB(vp)->blockSize != hp->fcbPLen)
3696 DEBUG_BREAK_MSG(("fcbPLen does not match extents"));
3697 } else {
3698 if ( hp->fcbPLen < (off_t)size * (off_t)VTOVCB(vp)->blockSize)
3699 DEBUG_BREAK_MSG(("fcbPLen is smaller than extents"));
3700 }
3701 for(i = 0; i < kHFSPlusExtentDensity; i++)
3702 {
3703 if (hp->fcbExtents[i].blockCount == 0 || hp->fcbExtents[i].startBlock == 0)
3704 break;
3705 }
3706 if ((VTOVCB(vp)->vcbSigWord == kHFSSigWord) && i > kHFSExtentDensity)
3707 DEBUG_BREAK_MSG(("Illegal value in extents for ordinary HFS"));
3708 if (i > kHFSPlusExtentDensity) {
3709 for(; i < kHFSPlusExtentDensity; i++)
3710 {
3711 if (hp->fcbExtents[i].blockCount != 0 || hp->fcbExtents[i].startBlock != 0)
3712 DEBUG_BREAK_MSG(("Illegal value in extents"));
3713 }
3714 }
3715 }
3716
3717
3718 /* BTree stuff */
3719 if (0 && vp->v_flag & VSYSTEM) {
3720 BTreeInfoRec info;
3721
3722 BTGetInformation(hp, 0, &info);
3723 if (hp->fcbBTCBPtr == NULL)
3724 DEBUG_BREAK_MSG(("Null fcbBTCBPtr"));
3725 if (H_HINT(hp) == 0)
3726 DEBUG_BREAK_MSG(("hint is 0"));
3727 if (H_HINT(hp) > info.numNodes)
3728 DEBUG_BREAK_MSG(("hint > numNodes"));
3729 }
3730
3731 }
3732
3733 #endif /* HFS_DIAGNOSTIC */