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