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