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