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