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