The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/bsd/hfs/hfs_vfsutils.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*      @(#)hfs_vfsutils.c      4.0
   26 *
   27 *       (c) 1997-2002 Apple Computer, Inc.  All Rights Reserved
   28 *
   29 *       hfs_vfsutils.c -- Routines that go between the HFS layer and the VFS.
   30 *
   31 */
   32 #include <sys/param.h>
   33 #include <sys/systm.h>
   34 #include <sys/kernel.h>
   35 #include <sys/malloc.h>
   36 #include <sys/stat.h>
   37 #include <sys/mount.h>
   38 #include <sys/namei.h>
   39 #include <sys/lock.h>
   40 #include <sys/buf.h>
   41 #include <sys/ubc.h>
   42 #include <sys/unistd.h>
   43 
   44 #include "hfs.h"
   45 #include "hfs_catalog.h"
   46 #include "hfs_dbg.h"
   47 #include "hfs_mount.h"
   48 #include "hfs_endian.h"
   49 #include "hfs_cnode.h"
   50 
   51 #include "hfscommon/headers/FileMgrInternal.h"
   52 #include "hfscommon/headers/BTreesInternal.h"
   53 #include "hfscommon/headers/HFSUnicodeWrappers.h"
   54 
   55 
   56 extern int count_lock_queue __P((void));
   57 
   58 
   59 static void ReleaseMetaFileVNode(struct vnode *vp);
   60 static int  hfs_late_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, void *_args);
   61 
   62 static void hfs_metadatazone_init(struct hfsmount *);
   63 static u_int32_t hfs_hotfile_freeblocks(struct hfsmount *);
   64 
   65 
   66 
   67 u_int32_t GetLogicalBlockSize(struct vnode *vp);
   68 
   69 /* BTree accessor routines */
   70 extern OSStatus GetBTreeBlock(FileReference vp, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block);
   71 extern OSStatus SetBTreeBlockSize(FileReference vp, ByteCount blockSize, ItemCount minBlockCount);
   72 extern OSStatus ExtendBTreeFile(FileReference vp, FSSize minEOF, FSSize maxEOF);
   73 extern OSStatus ReleaseBTreeBlock(FileReference vp, BlockDescPtr blockPtr, ReleaseBlockOptions options);
   74 
   75 //*******************************************************************************
   76 // Note: Finder information in the HFS/HFS+ metadata are considered opaque and
   77 //       hence are not in the right byte order on little endian machines. It is
   78 //       the responsibility of the finder and other clients to swap the data.
   79 //*******************************************************************************
   80 
   81 //*******************************************************************************
   82 //      Routine:        hfs_MountHFSVolume
   83 //
   84 //
   85 //*******************************************************************************
   86 char hfs_catname[] = "Catalog B-tree";
   87 char hfs_extname[] = "Extents B-tree";
   88 char hfs_vbmname[] = "Volume Bitmap";
   89 
   90 char hfs_privdirname[] =
   91         "\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80\xE2\x90\x80HFS+ Private Data";
   92 
   93 __private_extern__
   94 OSErr hfs_MountHFSVolume(struct hfsmount *hfsmp, HFSMasterDirectoryBlock *mdb,
   95                 struct proc *p)
   96 {
   97         ExtendedVCB *vcb = HFSTOVCB(hfsmp);
   98         int error;
   99         ByteCount utf8chars;
  100         struct cat_desc cndesc;
  101         struct cat_attr cnattr;
  102         struct cat_fork fork;
  103 
  104         /* Block size must be a multiple of 512 */
  105         if (SWAP_BE32(mdb->drAlBlkSiz) == 0 ||
  106             (SWAP_BE32(mdb->drAlBlkSiz) & 0x01FF) != 0)
  107                 return (EINVAL);
  108 
  109         /* don't mount a writeable volume if its dirty, it must be cleaned by fsck_hfs */
  110         if (((hfsmp->hfs_flags & HFS_READ_ONLY) == 0) &&
  111             ((SWAP_BE16(mdb->drAtrb) & kHFSVolumeUnmountedMask) == 0)) {
  112                 return (EINVAL);
  113         }
  114         hfsmp->hfs_flags |= HFS_STANDARD;
  115         /*
  116          * The MDB seems OK: transfer info from it into VCB
  117          * Note - the VCB starts out clear (all zeros)
  118          *
  119          */
  120         vcb->vcbSigWord         = SWAP_BE16 (mdb->drSigWord);
  121         vcb->vcbCrDate          = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drCrDate)));
  122         vcb->localCreateDate    = SWAP_BE32 (mdb->drCrDate);
  123         vcb->vcbLsMod           = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drLsMod)));
  124         vcb->vcbAtrb            = SWAP_BE16 (mdb->drAtrb);
  125         vcb->vcbNmFls           = SWAP_BE16 (mdb->drNmFls);
  126         vcb->vcbVBMSt           = SWAP_BE16 (mdb->drVBMSt);
  127         vcb->nextAllocation     = SWAP_BE16 (mdb->drAllocPtr);
  128         vcb->totalBlocks        = SWAP_BE16 (mdb->drNmAlBlks);
  129         vcb->blockSize          = SWAP_BE32 (mdb->drAlBlkSiz);
  130         vcb->vcbClpSiz          = SWAP_BE32 (mdb->drClpSiz);
  131         vcb->vcbAlBlSt          = SWAP_BE16 (mdb->drAlBlSt);
  132         vcb->vcbNxtCNID         = SWAP_BE32 (mdb->drNxtCNID);
  133         vcb->freeBlocks         = SWAP_BE16 (mdb->drFreeBks);
  134         vcb->vcbVolBkUp         = to_bsd_time(LocalToUTC(SWAP_BE32(mdb->drVolBkUp)));
  135         vcb->vcbWrCnt           = SWAP_BE32 (mdb->drWrCnt);
  136         vcb->vcbNmRtDirs        = SWAP_BE16 (mdb->drNmRtDirs);
  137         vcb->vcbFilCnt          = SWAP_BE32 (mdb->drFilCnt);
  138         vcb->vcbDirCnt          = SWAP_BE32 (mdb->drDirCnt);
  139         bcopy(mdb->drFndrInfo, vcb->vcbFndrInfo, sizeof(vcb->vcbFndrInfo));
  140         if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0)
  141                 vcb->vcbWrCnt++;        /* Compensate for write of MDB on last flush */
  142 
  143         /* convert hfs encoded name into UTF-8 string */
  144         error = hfs_to_utf8(vcb, mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN);
  145         /*
  146          * When an HFS name cannot be encoded with the current
  147          * volume encoding we use MacRoman as a fallback.
  148          */
  149         if (error || (utf8chars == 0))
  150                 (void) mac_roman_to_utf8(mdb->drVN, NAME_MAX, &utf8chars, vcb->vcbVN);
  151 
  152         hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
  153         vcb->vcbVBMIOSize = kHFSBlockSize;
  154 
  155         VCB_LOCK_INIT(vcb);
  156 
  157         bzero(&cndesc, sizeof(cndesc));
  158         cndesc.cd_parentcnid = kRootParID;
  159         cndesc.cd_flags |= CD_ISMETA;
  160         bzero(&cnattr, sizeof(cnattr));
  161         cnattr.ca_nlink = 1;
  162         cnattr.ca_mode = S_IFREG;
  163         bzero(&fork, sizeof(fork));
  164 
  165         /*
  166          * Set up Extents B-tree vnode
  167          */
  168         cndesc.cd_nameptr = hfs_extname;
  169         cndesc.cd_namelen = strlen(hfs_extname);
  170         cndesc.cd_cnid = cnattr.ca_fileid = kHFSExtentsFileID;
  171         fork.cf_size = SWAP_BE32(mdb->drXTFlSize);
  172         fork.cf_blocks = fork.cf_size / vcb->blockSize;
  173         fork.cf_clump = SWAP_BE32(mdb->drXTClpSiz);
  174         fork.cf_vblocks = 0;
  175         fork.cf_extents[0].startBlock = SWAP_BE16(mdb->drXTExtRec[0].startBlock);
  176         fork.cf_extents[0].blockCount = SWAP_BE16(mdb->drXTExtRec[0].blockCount);
  177         fork.cf_extents[1].startBlock = SWAP_BE16(mdb->drXTExtRec[1].startBlock);
  178         fork.cf_extents[1].blockCount = SWAP_BE16(mdb->drXTExtRec[1].blockCount);
  179         fork.cf_extents[2].startBlock = SWAP_BE16(mdb->drXTExtRec[2].startBlock);
  180         fork.cf_extents[2].blockCount = SWAP_BE16(mdb->drXTExtRec[2].blockCount);
  181         cnattr.ca_blocks = fork.cf_blocks;
  182 
  183         error = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &fork,
  184                                 &vcb->extentsRefNum);
  185         if (error) goto MtVolErr;
  186         error = MacToVFSError(BTOpenPath(VTOF(vcb->extentsRefNum),
  187                                          (KeyCompareProcPtr)CompareExtentKeys));
  188         if (error) {
  189                 VOP_UNLOCK(vcb->extentsRefNum, 0, p);
  190                 goto MtVolErr;
  191         }
  192 
  193         /*
  194          * Set up Catalog B-tree vnode...
  195          */ 
  196         cndesc.cd_nameptr = hfs_catname;
  197         cndesc.cd_namelen = strlen(hfs_catname);
  198         cndesc.cd_cnid = cnattr.ca_fileid = kHFSCatalogFileID;
  199         fork.cf_size = SWAP_BE32(mdb->drCTFlSize);
  200         fork.cf_blocks = fork.cf_size / vcb->blockSize;
  201         fork.cf_clump = SWAP_BE32(mdb->drCTClpSiz);
  202         fork.cf_vblocks = 0;
  203         fork.cf_extents[0].startBlock = SWAP_BE16(mdb->drCTExtRec[0].startBlock);
  204         fork.cf_extents[0].blockCount = SWAP_BE16(mdb->drCTExtRec[0].blockCount);
  205         fork.cf_extents[1].startBlock = SWAP_BE16(mdb->drCTExtRec[1].startBlock);
  206         fork.cf_extents[1].blockCount = SWAP_BE16(mdb->drCTExtRec[1].blockCount);
  207         fork.cf_extents[2].startBlock = SWAP_BE16(mdb->drCTExtRec[2].startBlock);
  208         fork.cf_extents[2].blockCount = SWAP_BE16(mdb->drCTExtRec[2].blockCount);
  209         cnattr.ca_blocks = fork.cf_blocks;
  210 
  211         error = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &fork,
  212                                 &vcb->catalogRefNum);
  213         if (error) {
  214                 VOP_UNLOCK(vcb->extentsRefNum, 0, p);
  215                 goto MtVolErr;
  216         }
  217         error = MacToVFSError(BTOpenPath(VTOF(vcb->catalogRefNum),
  218                                          (KeyCompareProcPtr)CompareCatalogKeys));
  219         if (error) {
  220                 VOP_UNLOCK(vcb->catalogRefNum, 0, p);
  221                 VOP_UNLOCK(vcb->extentsRefNum, 0, p);
  222                 goto MtVolErr;
  223         }
  224 
  225         /* mark the volume dirty (clear clean unmount bit) */
  226         vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask;
  227 
  228         /*
  229          * all done with b-trees so we can unlock now...
  230          */
  231         VOP_UNLOCK(vcb->catalogRefNum, 0, p);
  232         VOP_UNLOCK(vcb->extentsRefNum, 0, p);
  233 
  234     if ( error == noErr )
  235       {
  236         if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) )             //      if the disk is not write protected
  237           {
  238             MarkVCBDirty( vcb );                                                                //      mark VCB dirty so it will be written
  239           }
  240       }
  241     goto        CmdDone;
  242 
  243     //--        Release any resources allocated so far before exiting with an error:
  244 MtVolErr:
  245         ReleaseMetaFileVNode(vcb->catalogRefNum);
  246         ReleaseMetaFileVNode(vcb->extentsRefNum);
  247 
  248 CmdDone:
  249     return (error);
  250 }
  251 
  252 //*******************************************************************************
  253 //      Routine:        hfs_MountHFSPlusVolume
  254 //
  255 //
  256 //*******************************************************************************
  257 
  258 __private_extern__
  259 OSErr hfs_MountHFSPlusVolume(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
  260         off_t embeddedOffset, u_int64_t disksize, struct proc *p, void *args)
  261 {
  262         register ExtendedVCB *vcb;
  263         struct cat_desc cndesc;
  264         struct cat_attr cnattr;
  265         struct cat_fork cfork;
  266         UInt32 blockSize;
  267         u_int64_t volumesize;
  268         struct BTreeInfoRec btinfo;
  269         u_int16_t  signature;
  270         u_int16_t  version;
  271         int  i;
  272         OSErr retval;
  273 
  274         signature = SWAP_BE16(vhp->signature);
  275         version = SWAP_BE16(vhp->version);
  276 
  277         if (signature == kHFSPlusSigWord) {
  278                 if (version != kHFSPlusVersion) {
  279                         printf("hfs_mount: invalid HFS+ version: %d\n", version);
  280                         return (EINVAL);
  281                 }
  282         } else if (signature == kHFSXSigWord) {
  283                 if (version != kHFSXVersion) {
  284                         printf("hfs_mount: invalid HFSX version: %d\n", version);
  285                         return (EINVAL);
  286                 }
  287                 /* The in-memory signature is always 'H+'. */
  288                 signature = kHFSPlusSigWord;
  289                 hfsmp->hfs_flags |= HFS_X;
  290         } else {
  291                 printf("hfs_mount: invalid HFS+ sig 0x%04x\n", signature);
  292                 return (EINVAL);
  293         }
  294 
  295         /* Block size must be at least 512 and a power of 2 */
  296         blockSize = SWAP_BE32(vhp->blockSize);
  297         if (blockSize < 512 || !powerof2(blockSize))
  298                 return (EINVAL);
  299    
  300         /* don't mount a writable volume if its dirty, it must be cleaned by fsck_hfs */
  301         if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0 && hfsmp->jnl == NULL &&
  302             (SWAP_BE32(vhp->attributes) & kHFSVolumeUnmountedMask) == 0)
  303                 return (EINVAL);
  304 
  305         /* Make sure we can live with the physical block size. */
  306         if ((disksize & (hfsmp->hfs_phys_block_size - 1)) ||
  307             (embeddedOffset & (hfsmp->hfs_phys_block_size - 1)) ||
  308             (blockSize < hfsmp->hfs_phys_block_size)) {
  309                 return (ENXIO);
  310         }
  311         /*
  312          * The VolumeHeader seems OK: transfer info from it into VCB
  313          * Note - the VCB starts out clear (all zeros)
  314          */
  315         vcb = HFSTOVCB(hfsmp);
  316 
  317         vcb->vcbSigWord = signature;
  318         vcb->vcbJinfoBlock = SWAP_BE32(vhp->journalInfoBlock);
  319         vcb->vcbLsMod   = to_bsd_time(SWAP_BE32(vhp->modifyDate));
  320         vcb->vcbAtrb    = (UInt16)SWAP_BE32(vhp->attributes);
  321         vcb->vcbClpSiz  = SWAP_BE32(vhp->rsrcClumpSize);
  322         vcb->vcbNxtCNID = SWAP_BE32(vhp->nextCatalogID);
  323         vcb->vcbVolBkUp = to_bsd_time(SWAP_BE32(vhp->backupDate));
  324         vcb->vcbWrCnt   = SWAP_BE32(vhp->writeCount);
  325         vcb->vcbFilCnt  = SWAP_BE32(vhp->fileCount);
  326         vcb->vcbDirCnt  = SWAP_BE32(vhp->folderCount);
  327         
  328         /* copy 32 bytes of Finder info */
  329         bcopy(vhp->finderInfo, vcb->vcbFndrInfo, sizeof(vhp->finderInfo));    
  330 
  331         vcb->vcbAlBlSt = 0;             /* hfs+ allocation blocks start at first block of volume */
  332         if ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0)
  333                 vcb->vcbWrCnt++;        /* compensate for write of Volume Header on last flush */
  334 
  335         VCB_LOCK_INIT(vcb);
  336 
  337         /* Now fill in the Extended VCB info */
  338         vcb->nextAllocation     = SWAP_BE32(vhp->nextAllocation);
  339         vcb->totalBlocks        = SWAP_BE32(vhp->totalBlocks);
  340         vcb->freeBlocks         = SWAP_BE32(vhp->freeBlocks);
  341         vcb->blockSize          = blockSize;
  342         vcb->encodingsBitmap    = SWAP_BE64(vhp->encodingsBitmap);
  343         vcb->localCreateDate    = SWAP_BE32(vhp->createDate);
  344         
  345         vcb->hfsPlusIOPosOffset = embeddedOffset;
  346 
  347         /* Default to no free block reserve */
  348         vcb->reserveBlocks = 0;
  349 
  350         /*
  351          * Update the logical block size in the mount struct
  352          * (currently set up from the wrapper MDB) using the
  353          * new blocksize value:
  354          */
  355         hfsmp->hfs_logBlockSize = BestBlockSizeFit(vcb->blockSize, MAXBSIZE, hfsmp->hfs_phys_block_size);
  356         vcb->vcbVBMIOSize = min(vcb->blockSize, MAXPHYSIO);
  357 
  358         bzero(&cndesc, sizeof(cndesc));
  359         cndesc.cd_parentcnid = kRootParID;
  360         cndesc.cd_flags |= CD_ISMETA;
  361         bzero(&cnattr, sizeof(cnattr));
  362         cnattr.ca_nlink = 1;
  363         cnattr.ca_mode = S_IFREG;
  364 
  365         /*
  366          * Set up Extents B-tree vnode
  367          */
  368         cndesc.cd_nameptr = hfs_extname;
  369         cndesc.cd_namelen = strlen(hfs_extname);
  370         cndesc.cd_cnid = cnattr.ca_fileid = kHFSExtentsFileID;
  371 
  372         cfork.cf_size    = SWAP_BE64 (vhp->extentsFile.logicalSize);
  373         cfork.cf_clump   = SWAP_BE32 (vhp->extentsFile.clumpSize);
  374         cfork.cf_blocks  = SWAP_BE32 (vhp->extentsFile.totalBlocks);
  375         cfork.cf_vblocks = 0;
  376         cnattr.ca_blocks = cfork.cf_blocks;
  377         for (i = 0; i < kHFSPlusExtentDensity; i++) {
  378                 cfork.cf_extents[i].startBlock =
  379                                 SWAP_BE32 (vhp->extentsFile.extents[i].startBlock);
  380                 cfork.cf_extents[i].blockCount =
  381                                 SWAP_BE32 (vhp->extentsFile.extents[i].blockCount);
  382         }
  383         retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &cfork,
  384                                  &vcb->extentsRefNum);
  385 
  386         if (retval) goto ErrorExit;
  387         retval = MacToVFSError(BTOpenPath(VTOF(vcb->extentsRefNum),
  388                                           (KeyCompareProcPtr) CompareExtentKeysPlus));
  389         if (retval) {
  390                 VOP_UNLOCK(vcb->extentsRefNum, 0, p);
  391                 goto ErrorExit;
  392         }
  393 
  394         /*
  395          * Set up Catalog B-tree vnode
  396          */ 
  397         cndesc.cd_nameptr = hfs_catname;
  398         cndesc.cd_namelen = strlen(hfs_catname);
  399         cndesc.cd_cnid = cnattr.ca_fileid = kHFSCatalogFileID;
  400 
  401         cfork.cf_size    = SWAP_BE64 (vhp->catalogFile.logicalSize);
  402         cfork.cf_clump   = SWAP_BE32 (vhp->catalogFile.clumpSize);
  403         cfork.cf_blocks  = SWAP_BE32 (vhp->catalogFile.totalBlocks);
  404         cfork.cf_vblocks = 0;
  405         cnattr.ca_blocks = cfork.cf_blocks;
  406         for (i = 0; i < kHFSPlusExtentDensity; i++) {
  407                 cfork.cf_extents[i].startBlock =
  408                                 SWAP_BE32 (vhp->catalogFile.extents[i].startBlock);
  409                 cfork.cf_extents[i].blockCount =
  410                                 SWAP_BE32 (vhp->catalogFile.extents[i].blockCount);
  411         }
  412         retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &cfork,
  413                                  &vcb->catalogRefNum);
  414         if (retval) {
  415                 VOP_UNLOCK(vcb->extentsRefNum, 0, p);
  416                 goto ErrorExit;
  417         }
  418         retval = MacToVFSError(BTOpenPath(VTOF(vcb->catalogRefNum),
  419                                           (KeyCompareProcPtr) CompareExtendedCatalogKeys));
  420         if (retval) {
  421                 VOP_UNLOCK(vcb->catalogRefNum, 0, p);
  422                 VOP_UNLOCK(vcb->extentsRefNum, 0, p);
  423                 goto ErrorExit;
  424         }
  425         if ((hfsmp->hfs_flags & HFS_X) &&
  426             BTGetInformation(VTOF(vcb->catalogRefNum), 0, &btinfo) == 0) {
  427                 if (btinfo.keyCompareType == kHFSBinaryCompare) {
  428                         hfsmp->hfs_flags |= HFS_CASE_SENSITIVE;
  429                         /* Install a case-sensitive key compare */
  430                         (void) BTOpenPath(VTOF(vcb->catalogRefNum),
  431                                           (KeyCompareProcPtr)cat_binarykeycompare);
  432                 }
  433         }
  434 
  435         /*
  436          * Set up Allocation file vnode
  437          */  
  438         cndesc.cd_nameptr = hfs_vbmname;
  439         cndesc.cd_namelen = strlen(hfs_vbmname);
  440         cndesc.cd_cnid = cnattr.ca_fileid = kHFSAllocationFileID;
  441 
  442         cfork.cf_size    = SWAP_BE64 (vhp->allocationFile.logicalSize);
  443         cfork.cf_clump   = SWAP_BE32 (vhp->allocationFile.clumpSize);
  444         cfork.cf_blocks  = SWAP_BE32 (vhp->allocationFile.totalBlocks);
  445         cfork.cf_vblocks = 0;
  446         cnattr.ca_blocks = cfork.cf_blocks;
  447         for (i = 0; i < kHFSPlusExtentDensity; i++) {
  448                 cfork.cf_extents[i].startBlock =
  449                                 SWAP_BE32 (vhp->allocationFile.extents[i].startBlock);
  450                 cfork.cf_extents[i].blockCount =
  451                                 SWAP_BE32 (vhp->allocationFile.extents[i].blockCount);
  452         }
  453         retval = hfs_getnewvnode(hfsmp, NULL, &cndesc, 0, &cnattr, &cfork,
  454                                  &vcb->allocationsRefNum);
  455         if (retval) {
  456                 VOP_UNLOCK(vcb->catalogRefNum, 0, p);
  457                 VOP_UNLOCK(vcb->extentsRefNum, 0, p);
  458                 goto ErrorExit;
  459         }
  460 
  461         /* Pick up volume name and create date */
  462         retval = cat_idlookup(hfsmp, kHFSRootFolderID, &cndesc, &cnattr, NULL);
  463         if (retval) {
  464                 VOP_UNLOCK(vcb->allocationsRefNum, 0, p);
  465                 VOP_UNLOCK(vcb->catalogRefNum, 0, p);
  466                 VOP_UNLOCK(vcb->extentsRefNum, 0, p);
  467                 goto ErrorExit;
  468         }
  469         vcb->vcbCrDate = cnattr.ca_itime;
  470         vcb->volumeNameEncodingHint = cndesc.cd_encoding;
  471         bcopy(cndesc.cd_nameptr, vcb->vcbVN, min(255, cndesc.cd_namelen));
  472         cat_releasedesc(&cndesc);
  473 
  474         /* mark the volume dirty (clear clean unmount bit) */
  475         vcb->vcbAtrb &= ~kHFSVolumeUnmountedMask;
  476         if (hfsmp->jnl && (hfsmp->hfs_flags & HFS_READ_ONLY) == 0) {
  477                 hfs_flushvolumeheader(hfsmp, TRUE, TRUE);
  478         }
  479 
  480         /*
  481          * all done with metadata files so we can unlock now...
  482          */
  483         VOP_UNLOCK(vcb->allocationsRefNum, 0, p);
  484         VOP_UNLOCK(vcb->catalogRefNum, 0, p);
  485         VOP_UNLOCK(vcb->extentsRefNum, 0, p);
  486 
  487         //
  488         // Check if we need to do late journal initialization.  This only
  489         // happens if a previous version of MacOS X (or 9) touched the disk.
  490         // In that case hfs_late_journal_init() will go re-locate the journal 
  491         // and journal_info_block files and validate that they're still kosher.
  492         //
  493         if (   (vcb->vcbAtrb & kHFSVolumeJournaledMask)
  494                 && (SWAP_BE32(vhp->lastMountedVersion) != kHFSJMountVersion)
  495                 && (hfsmp->jnl == NULL)) {
  496 
  497                 retval = hfs_late_journal_init(hfsmp, vhp, args);
  498                 if (retval != 0) {
  499                         hfsmp->jnl = NULL;
  500                         goto ErrorExit;
  501                 } else if (hfsmp->jnl) {
  502                         hfsmp->hfs_mp->mnt_flag |= MNT_JOURNALED;
  503                 }
  504         } else if (hfsmp->jnl) {
  505                 struct cat_attr jinfo_attr, jnl_attr;
  506                 
  507                 // if we're here we need to fill in the fileid's for the
  508                 // journal and journal_info_block.
  509                 hfsmp->hfs_jnlinfoblkid = GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jinfo_attr, NULL);
  510                 hfsmp->hfs_jnlfileid    = GetFileInfo(vcb, kRootDirID, ".journal", &jnl_attr, NULL);
  511                 if (hfsmp->hfs_jnlinfoblkid == 0 || hfsmp->hfs_jnlfileid == 0) {
  512                         printf("hfs: danger! couldn't find the file-id's for the journal or journal_info_block\n");
  513                         printf("hfs: jnlfileid %d, jnlinfoblkid %d\n", hfsmp->hfs_jnlfileid, hfsmp->hfs_jnlinfoblkid);
  514                 }
  515         }
  516 
  517         /*
  518          * Establish a metadata allocation zone.
  519          */
  520         hfs_metadatazone_init(hfsmp);
  521 
  522         /*
  523          * Make any metadata zone adjustments.
  524          */
  525         if (hfsmp->hfs_flags & HFS_METADATA_ZONE) {
  526                 /* Keep the roving allocator out of the metadata zone. */
  527                 if (vcb->nextAllocation >= hfsmp->hfs_metazone_start &&
  528                     vcb->nextAllocation <= hfsmp->hfs_metazone_end) {       
  529                         vcb->nextAllocation = hfsmp->hfs_metazone_end + 1;
  530                 }
  531         }
  532 
  533         /* setup private/hidden directory for unlinked files */
  534         FindMetaDataDirectory(vcb);
  535         if (hfsmp->jnl && ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0))
  536                 hfs_remove_orphans(hfsmp);
  537 
  538         if ( !(vcb->vcbAtrb & kHFSVolumeHardwareLockMask) )     // if the disk is not write protected
  539         {
  540                 MarkVCBDirty( vcb );    // mark VCB dirty so it will be written
  541         }
  542 
  543 
  544         /*
  545          * Allow hot file clustering if conditions allow.
  546          */
  547         if ((hfsmp->hfs_flags & HFS_METADATA_ZONE)  &&
  548             ((hfsmp->hfs_flags & HFS_READ_ONLY) == 0)) {
  549                 (void) hfs_recording_init(hfsmp, p);
  550         }
  551 
  552         return (0);
  553 
  554 ErrorExit:
  555         /*
  556          * A fatal error occured and the volume cannot be mounted
  557          * release any resources that we aquired...
  558          */
  559 
  560         InvalidateCatalogCache(vcb);   
  561         ReleaseMetaFileVNode(vcb->allocationsRefNum);
  562         ReleaseMetaFileVNode(vcb->catalogRefNum);
  563         ReleaseMetaFileVNode(vcb->extentsRefNum);
  564 
  565         return (retval);
  566 }
  567 
  568 
  569 /*
  570  * ReleaseMetaFileVNode
  571  *
  572  * vp   L - -
  573  */
  574 static void ReleaseMetaFileVNode(struct vnode *vp)
  575 {
  576         struct filefork *fp;
  577 
  578         if (vp && (fp = VTOF(vp))) {
  579                 if (fp->fcbBTCBPtr != NULL)
  580                         (void) BTClosePath(fp);
  581 
  582                 /* release the node even if BTClosePath fails */
  583                 vrele(vp);
  584                 vgone(vp);
  585         }
  586 }
  587 
  588 
  589 /*************************************************************
  590 *
  591 * Unmounts a hfs volume.
  592 *       At this point vflush() has been called (to dump all non-metadata files)
  593 *
  594 *************************************************************/
  595 
  596 __private_extern__
  597 int
  598 hfsUnmount( register struct hfsmount *hfsmp, struct proc *p)
  599 {
  600         ExtendedVCB *vcb = HFSTOVCB(hfsmp);
  601         int retval = E_NONE;
  602 
  603         InvalidateCatalogCache( vcb );
  604 
  605         if (hfsmp->hfc_filevp) {
  606                 ReleaseMetaFileVNode(hfsmp->hfc_filevp);
  607                 hfsmp->hfc_filevp = NULL;
  608         }
  609                 
  610         if (vcb->vcbSigWord == kHFSPlusSigWord)
  611                 ReleaseMetaFileVNode(vcb->allocationsRefNum);
  612 
  613         ReleaseMetaFileVNode(vcb->catalogRefNum);
  614         ReleaseMetaFileVNode(vcb->extentsRefNum);
  615 
  616         return (retval);
  617 }
  618 
  619 
  620 /*
  621  * Test is fork has overflow extents.
  622  */
  623 __private_extern__
  624 int
  625 overflow_extents(struct filefork *fp)
  626 {
  627         u_long blocks;
  628 
  629         if (VTOVCB(FTOV(fp))->vcbSigWord == kHFSPlusSigWord) {
  630                 if (fp->ff_extents[7].blockCount == 0)
  631                         return (0);
  632 
  633                 blocks = fp->ff_extents[0].blockCount +
  634                          fp->ff_extents[1].blockCount +
  635                          fp->ff_extents[2].blockCount +
  636                          fp->ff_extents[3].blockCount +
  637                          fp->ff_extents[4].blockCount +
  638                          fp->ff_extents[5].blockCount +
  639                          fp->ff_extents[6].blockCount +
  640                          fp->ff_extents[7].blockCount;  
  641         } else {
  642                 if (fp->ff_extents[2].blockCount == 0)
  643                         return false;
  644                 
  645                 blocks = fp->ff_extents[0].blockCount +
  646                          fp->ff_extents[1].blockCount +
  647                          fp->ff_extents[2].blockCount;  
  648           }
  649 
  650         return (fp->ff_blocks > blocks);
  651 }
  652 
  653 
  654 /*
  655  * Lock/Unlock a metadata file.
  656  */
  657 __private_extern__
  658 int
  659 hfs_metafilelocking(struct hfsmount *hfsmp, u_long fileID, u_int flags, struct proc *p)
  660 {
  661         ExtendedVCB             *vcb;
  662         struct vnode    *vp = NULL;
  663         int                             numOfLockedBuffs;
  664         int     retval = 0;
  665 
  666         vcb = HFSTOVCB(hfsmp);
  667 
  668         switch (fileID) {
  669         case kHFSExtentsFileID:
  670                 vp = vcb->extentsRefNum;
  671                 break;
  672 
  673         case kHFSCatalogFileID:
  674                 vp = vcb->catalogRefNum;
  675                 break;
  676 
  677         case kHFSAllocationFileID:
  678                 /* bitmap is covered by Extents B-tree locking */
  679                 /* FALL THROUGH */
  680         default:
  681                 panic("hfs_lockmetafile: invalid fileID");
  682         }
  683 
  684         if ((flags & LK_TYPE_MASK) != LK_RELEASE) {
  685                 flags |= LK_RETRY;
  686         } else if (hfsmp->jnl == NULL) {
  687                 struct timeval tv = time;
  688                 u_int32_t               lastfsync = tv.tv_sec; 
  689                 
  690                 (void) BTGetLastSync((FCB*)VTOF(vp), &lastfsync);
  691                 
  692                 numOfLockedBuffs = count_lock_queue();
  693                 if ((numOfLockedBuffs > kMaxLockedMetaBuffers) ||
  694                     ((numOfLockedBuffs > 1) && ((tv.tv_sec - lastfsync) > kMaxSecsForFsync))) {
  695                         hfs_btsync(vp, HFS_SYNCTRANS);
  696                 }
  697         }
  698         
  699         retval = lockmgr(&VTOC(vp)->c_lock, flags, &vp->v_interlock, p);
  700 
  701         return (retval);
  702 }
  703 
  704 /*
  705  * RequireFileLock
  706  *
  707  * Check to see if a vnode is locked in the current context
  708  * This is to be used for debugging purposes only!!
  709  */
  710 #if HFS_DIAGNOSTIC
  711 void RequireFileLock(FileReference vp, int shareable)
  712 {
  713         struct lock__bsd__ *lkp;
  714         int locked = false;
  715         pid_t pid;
  716         void * self;
  717 
  718         pid = current_proc()->p_pid;
  719         self = (void *) current_act();
  720         lkp = &VTOC(vp)->c_lock;
  721 
  722         simple_lock(&lkp->lk_interlock);
  723         
  724         if (shareable && (lkp->lk_sharecount > 0) && (lkp->lk_lockholder == LK_NOPROC))
  725                 locked = true;
  726         else if ((lkp->lk_exclusivecount > 0) && (lkp->lk_lockholder == pid) && (lkp->lk_lockthread == self))
  727                 locked = true;
  728 
  729         simple_unlock(&lkp->lk_interlock);
  730         
  731         if (!locked) {
  732                 switch (VTOC(vp)->c_fileid) {
  733                         case 3:
  734                                 DEBUG_BREAK_MSG((" #\n # RequireFileLock: extent btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp));
  735                                 break;
  736 
  737                         case 4:
  738                                 DEBUG_BREAK_MSG((" #\n # RequireFileLock: catalog btree vnode not locked! v: 0x%08X\n #\n", (u_int)vp));
  739                                 break;
  740 
  741                         default:
  742                                 DEBUG_BREAK_MSG((" #\n # RequireFileLock: file (%d) not locked! v: 0x%08X\n #\n", VTOC(vp)->c_fileid, (u_int)vp));
  743                                 break;
  744                 }
  745         }
  746 }
  747 #endif
  748 
  749 
  750 /*
  751  * There are three ways to qualify for ownership rights on an object:
  752  *
  753  * 1. (a) Your UID matches the cnode's UID.
  754  *    (b) The object in question is owned by "unknown"
  755  * 2. (a) Permissions on the filesystem are being ignored and
  756  *        your UID matches the replacement UID.
  757  *    (b) Permissions on the filesystem are being ignored and
  758  *        the replacement UID is "unknown".
  759  * 3. You are root.
  760  *
  761  */
  762 int
  763 hfs_owner_rights(struct hfsmount *hfsmp, uid_t cnode_uid, struct ucred *cred,
  764                 struct proc *p, int invokesuperuserstatus)
  765 {
  766         if ((cred->cr_uid == cnode_uid) ||                                    /* [1a] */
  767             (cnode_uid == UNKNOWNUID) ||                                                                          /* [1b] */
  768             ((HFSTOVFS(hfsmp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) &&          /* [2] */
  769               ((cred->cr_uid == hfsmp->hfs_uid) ||                            /* [2a] */
  770                 (hfsmp->hfs_uid == UNKNOWNUID))) ||                           /* [2b] */
  771             (invokesuperuserstatus && (suser(cred, &p->p_acflag) == 0))) {    /* [3] */
  772                 return (0);
  773         } else {        
  774                 return (EPERM);
  775         }
  776 }
  777 
  778 
  779 unsigned long BestBlockSizeFit(unsigned long allocationBlockSize,
  780                                unsigned long blockSizeLimit,
  781                                unsigned long baseMultiple) {
  782     /*
  783        Compute the optimal (largest) block size (no larger than allocationBlockSize) that is less than the
  784        specified limit but still an even multiple of the baseMultiple.
  785      */
  786     int baseBlockCount, blockCount;
  787     unsigned long trialBlockSize;
  788 
  789     if (allocationBlockSize % baseMultiple != 0) {
  790         /*
  791            Whoops: the allocation blocks aren't even multiples of the specified base:
  792            no amount of dividing them into even parts will be a multiple, either then!
  793         */
  794         return 512;             /* Hope for the best */
  795     };
  796 
  797     /* Try the obvious winner first, to prevent 12K allocation blocks, for instance,
  798        from being handled as two 6K logical blocks instead of 3 4K logical blocks.
  799        Even though the former (the result of the loop below) is the larger allocation
  800        block size, the latter is more efficient: */
  801     if (allocationBlockSize % PAGE_SIZE == 0) return PAGE_SIZE;
  802 
  803     /* No clear winner exists: pick the largest even fraction <= MAXBSIZE: */
  804     baseBlockCount = allocationBlockSize / baseMultiple;                                /* Now guaranteed to be an even multiple */
  805 
  806     for (blockCount = baseBlockCount; blockCount > 0; --blockCount) {
  807         trialBlockSize = blockCount * baseMultiple;
  808         if (allocationBlockSize % trialBlockSize == 0) {                                /* An even multiple? */
  809             if ((trialBlockSize <= blockSizeLimit) &&
  810                 (trialBlockSize % baseMultiple == 0)) {
  811                 return trialBlockSize;
  812             };
  813         };
  814     };
  815 
  816     /* Note: we should never get here, since blockCount = 1 should always work,
  817        but this is nice and safe and makes the compiler happy, too ... */
  818     return 512;
  819 }
  820 
  821 
  822 /*
  823  * To make the HFS Plus filesystem follow UFS unlink semantics, a remove
  824  * of an active vnode is translated to a move/rename so the file appears
  825  * deleted. The destination folder for these move/renames is setup here
  826  * and a reference to it is place in hfsmp->hfs_privdir_desc.
  827  */
  828 __private_extern__
  829 u_long
  830 FindMetaDataDirectory(ExtendedVCB *vcb)
  831 {
  832         struct hfsmount * hfsmp;
  833         struct vnode * dvp = NULL;
  834         struct cnode * dcp = NULL;
  835         struct FndrDirInfo * fndrinfo;
  836         struct cat_desc out_desc = {0};
  837         struct proc *p = current_proc();
  838         struct timeval tv;
  839         cat_cookie_t cookie;
  840         int error;
  841         
  842         if (vcb->vcbSigWord != kHFSPlusSigWord)
  843                 return (0);
  844 
  845         hfsmp = VCBTOHFS(vcb);
  846 
  847         if (hfsmp->hfs_privdir_desc.cd_parentcnid == 0) {
  848                 hfsmp->hfs_privdir_desc.cd_parentcnid = kRootDirID;
  849                 hfsmp->hfs_privdir_desc.cd_nameptr = hfs_privdirname;
  850                 hfsmp->hfs_privdir_desc.cd_namelen = strlen(hfs_privdirname);
  851                 hfsmp->hfs_privdir_desc.cd_flags = CD_ISDIR;
  852         }
  853 
  854         /* Lock catalog b-tree */
  855         if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p) != 0)
  856                 return (0);
  857 
  858         error = cat_lookup(hfsmp, &hfsmp->hfs_privdir_desc, 0, NULL,
  859                         &hfsmp->hfs_privdir_attr, NULL);
  860 
  861         /* Unlock catalog b-tree */
  862         (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
  863 
  864         if (error == 0) {
  865                 hfsmp->hfs_metadata_createdate = hfsmp->hfs_privdir_attr.ca_itime;
  866                 hfsmp->hfs_privdir_desc.cd_cnid = hfsmp->hfs_privdir_attr.ca_fileid;
  867                 /*
  868                  * Clear the system immutable flag if set...
  869                  */
  870                 if ((hfsmp->hfs_privdir_attr.ca_flags & SF_IMMUTABLE) &&
  871                     (hfsmp->hfs_flags & HFS_READ_ONLY) == 0) {
  872                         hfsmp->hfs_privdir_attr.ca_flags &= ~SF_IMMUTABLE;
  873 
  874                         hfs_global_shared_lock_acquire(hfsmp);
  875                         if (hfsmp->jnl) {
  876                                 if ((error = journal_start_transaction(hfsmp->jnl)) != 0) {
  877                                         hfs_global_shared_lock_release(hfsmp);
  878                                         return (hfsmp->hfs_privdir_attr.ca_fileid);
  879                                 }
  880                         }
  881                         if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_SHARED, p) == 0) {
  882                                 (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc,
  883                                              &hfsmp->hfs_privdir_attr, NULL, NULL);
  884                                 (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
  885                         }
  886                         if (hfsmp->jnl) {
  887                                 journal_end_transaction(hfsmp->jnl);
  888                         }
  889                         hfs_global_shared_lock_release(hfsmp);
  890                 }
  891                 return (hfsmp->hfs_privdir_attr.ca_fileid);
  892 
  893         } else if (hfsmp->hfs_flags & HFS_READ_ONLY) {
  894 
  895                 return (0);
  896         }
  897     
  898         /* Setup the default attributes */
  899         bzero(&hfsmp->hfs_privdir_attr, sizeof(struct cat_attr));
  900         hfsmp->hfs_privdir_attr.ca_mode = S_IFDIR;
  901         hfsmp->hfs_privdir_attr.ca_nlink = 2;
  902         hfsmp->hfs_privdir_attr.ca_itime = vcb->vcbCrDate;
  903         hfsmp->hfs_privdir_attr.ca_mtime = time.tv_sec;
  904 
  905         /* hidden and off the desktop view */
  906         fndrinfo = (struct FndrDirInfo *)&hfsmp->hfs_privdir_attr.ca_finderinfo;
  907         fndrinfo->frLocation.v = SWAP_BE16 (22460);
  908         fndrinfo->frLocation.h = SWAP_BE16 (22460);
  909         fndrinfo->frFlags |= SWAP_BE16 (kIsInvisible + kNameLocked);            
  910 
  911         // XXXdbg
  912         hfs_global_shared_lock_acquire(hfsmp);
  913         if (hfsmp->jnl) {
  914             if ((error = journal_start_transaction(hfsmp->jnl)) != 0) {
  915                         hfs_global_shared_lock_release(hfsmp);
  916                         return (0);
  917             }
  918         }
  919         /* Reserve some space in the Catalog file. */
  920         if (cat_preflight(hfsmp, CAT_CREATE, &cookie, p) != 0) {
  921                 if (hfsmp->jnl) {
  922                         journal_end_transaction(hfsmp->jnl);
  923                 }
  924                 hfs_global_shared_lock_release(hfsmp);
  925                 return (0);
  926         }
  927 
  928         if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p) == 0) {
  929                 error = cat_create(hfsmp, &hfsmp->hfs_privdir_desc,
  930                                 &hfsmp->hfs_privdir_attr, &out_desc);
  931 
  932                 (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
  933         }
  934 
  935         cat_postflight(hfsmp, &cookie, p);
  936         
  937         if (error) {
  938             if (hfsmp->jnl) {
  939                         journal_end_transaction(hfsmp->jnl);
  940             }
  941                 hfs_global_shared_lock_release(hfsmp);
  942 
  943             return (0);
  944         }
  945 
  946         hfsmp->hfs_privdir_desc.cd_hint = out_desc.cd_hint;
  947         hfsmp->hfs_privdir_desc.cd_cnid = out_desc.cd_cnid;
  948         hfsmp->hfs_privdir_attr.ca_fileid = out_desc.cd_cnid;
  949         hfsmp->hfs_metadata_createdate = vcb->vcbCrDate;
  950         
  951         if (VFS_ROOT(HFSTOVFS(hfsmp), &dvp) == 0) {
  952                 dcp = VTOC(dvp);
  953                 dcp->c_childhint = out_desc.cd_hint;
  954                 dcp->c_nlink++;
  955                 dcp->c_entries++;
  956                 dcp->c_flag |= C_CHANGE | C_UPDATE;
  957                 tv = time;
  958                 (void) VOP_UPDATE(dvp, &tv, &tv, 0);
  959                 vput(dvp);
  960         }
  961         hfs_volupdate(hfsmp, VOL_MKDIR, 1);
  962         if (hfsmp->jnl) {
  963             journal_end_transaction(hfsmp->jnl);
  964         } 
  965         hfs_global_shared_lock_release(hfsmp);
  966 
  967         cat_releasedesc(&out_desc);
  968 
  969         return (out_desc.cd_cnid);
  970 }
  971 
  972 __private_extern__
  973 u_long
  974 GetFileInfo(ExtendedVCB *vcb, u_int32_t dirid, char *name,
  975                         struct cat_attr *fattr, struct cat_fork *forkinfo)
  976 {
  977         struct hfsmount * hfsmp;
  978         struct vnode * dvp = NULL;
  979         struct cnode * dcp = NULL;
  980         struct FndrDirInfo * fndrinfo;
  981         struct cat_desc jdesc;
  982         struct timeval tv;
  983         int error;
  984         
  985         if (vcb->vcbSigWord != kHFSPlusSigWord)
  986                 return (0);
  987 
  988         hfsmp = VCBTOHFS(vcb);
  989 
  990         memset(&jdesc, 0, sizeof(struct cat_desc));
  991         jdesc.cd_parentcnid = kRootDirID;
  992         jdesc.cd_nameptr = name;
  993         jdesc.cd_namelen = strlen(name);
  994 
  995         /* Lock catalog b-tree */
  996         error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, current_proc());    
  997         if (error)
  998                 return (0);
  999 
 1000         error = cat_lookup(hfsmp, &jdesc, 0, NULL, fattr, forkinfo);
 1001 
 1002         (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, current_proc());
 1003 
 1004         if (error == 0) {
 1005                 return (fattr->ca_fileid);
 1006         } else if (hfsmp->hfs_flags & HFS_READ_ONLY) {
 1007                 return (0);
 1008         }
 1009 }
 1010 
 1011 
 1012 /*
 1013  * On Journaled HFS, there can be orphaned files.  These
 1014  * are files that were unlinked while busy. If the volume
 1015  * was not cleanly unmounted then some of these files may
 1016  * have persisted and need to be removed.
 1017  */
 1018 __private_extern__
 1019 void
 1020 hfs_remove_orphans(struct hfsmount * hfsmp)
 1021 {
 1022         struct BTreeIterator * iterator = NULL;
 1023         struct FSBufferDescriptor btdata;
 1024         struct HFSPlusCatalogFile filerec;
 1025         struct HFSPlusCatalogKey * keyp;
 1026         struct proc *p = current_proc();
 1027         FCB *fcb;
 1028         ExtendedVCB *vcb;
 1029         char filename[32];
 1030         char tempname[32];
 1031         size_t namelen;
 1032         cat_cookie_t cookie = {0};
 1033         int catlock = 0;
 1034         int catreserve = 0;
 1035         int started_tr = 0;
 1036         int shared_lock = 0;
 1037         int result;
 1038         
 1039         if (hfsmp->hfs_flags & HFS_CLEANED_ORPHANS)
 1040                 return;
 1041 
 1042         vcb = HFSTOVCB(hfsmp);
 1043         fcb = VTOF(vcb->catalogRefNum);
 1044 
 1045         btdata.bufferAddress = &filerec;
 1046         btdata.itemSize = sizeof(filerec);
 1047         btdata.itemCount = 1;
 1048 
 1049         MALLOC(iterator, struct BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
 1050         bzero(iterator, sizeof(*iterator));
 1051         keyp = (HFSPlusCatalogKey*)&iterator->key;
 1052         keyp->parentID = hfsmp->hfs_privdir_desc.cd_cnid;
 1053 
 1054         result = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);        
 1055         if (result)
 1056                 goto exit;
 1057         /*
 1058          * Position the iterator at the folder thread record.
 1059          * (i.e. one record before first child)
 1060          */
 1061         result = BTSearchRecord(fcb, iterator, NULL, NULL, iterator);
 1062 
 1063         (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
 1064         if (result)
 1065                 goto exit;
 1066 
 1067         /* Visit all the children in the HFS+ private directory. */
 1068         for (;;) {
 1069                 result = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);        
 1070                 if (result)
 1071                         goto exit;
 1072 
 1073                 result = BTIterateRecord(fcb, kBTreeNextRecord, iterator, &btdata, NULL);
 1074 
 1075                 (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
 1076                 if (result)
 1077                         break;
 1078 
 1079                 if (keyp->parentID != hfsmp->hfs_privdir_desc.cd_cnid)
 1080                         break;
 1081                 if (filerec.recordType != kHFSPlusFileRecord)
 1082                         continue;
 1083                 
 1084                 (void) utf8_encodestr(keyp->nodeName.unicode, keyp->nodeName.length * 2,
 1085                                       filename, &namelen, sizeof(filename), 0, 0);
 1086                 
 1087                 (void) sprintf(tempname, "%s%d", HFS_DELETE_PREFIX, filerec.fileID);
 1088                 
 1089                 /*
 1090                  * Delete all files named "tempxxx", where
 1091                  * xxx is the file's cnid in decimal.
 1092                  *
 1093                  */
 1094                 if (bcmp(tempname, filename, namelen) == 0) {
 1095                         struct filefork dfork = {0};
 1096                         struct filefork rfork = {0};
 1097                         struct cnode cnode = {0};
 1098 
 1099                         // XXXdbg
 1100                         hfs_global_shared_lock_acquire(hfsmp);
 1101                         shared_lock = 1;
 1102                         if (hfsmp->jnl) {
 1103                                 if (journal_start_transaction(hfsmp->jnl) != 0) {
 1104                                         goto exit;
 1105                                 }
 1106                                 started_tr = 1;
 1107                         }
 1108                 
 1109                         /*
 1110                          * Reserve some space in the Catalog file.
 1111                          */
 1112                         if (cat_preflight(hfsmp, CAT_DELETE, &cookie, p) != 0) {
 1113                                 goto exit;
 1114                         }
 1115                         catreserve = 1;
 1116 
 1117                         /* Lock catalog b-tree */
 1118                         if (hfs_metafilelocking(hfsmp, kHFSCatalogFileID,
 1119                                                 LK_EXCLUSIVE, p) != 0) {
 1120                                 goto exit;
 1121                         }
 1122                         catlock = 1;
 1123 
 1124                         /* Build a fake cnode */
 1125                         cat_convertattr(hfsmp, (CatalogRecord *)&filerec, &cnode.c_attr,
 1126                                         &dfork.ff_data, &rfork.ff_data);
 1127                         cnode.c_desc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid;
 1128                         cnode.c_desc.cd_nameptr = filename;
 1129                         cnode.c_desc.cd_namelen = namelen;
 1130                         cnode.c_desc.cd_cnid = cnode.c_attr.ca_fileid;
 1131                         cnode.c_blocks = dfork.ff_blocks + rfork.ff_blocks;
 1132 
 1133                         /* Position iterator at previous entry */
 1134                         if (BTIterateRecord(fcb, kBTreePrevRecord, iterator,
 1135                             NULL, NULL) != 0) {
 1136                                 break;
 1137                         }
 1138 
 1139                         /* Truncate the file to zero (both forks) */
 1140                         if (dfork.ff_blocks > 0) {
 1141                                 u_int64_t fsize;
 1142                                 
 1143                                 dfork.ff_cp = &cnode;
 1144                                 cnode.c_datafork = &dfork;
 1145                                 cnode.c_rsrcfork = NULL;
 1146                                 fsize = (u_int64_t)dfork.ff_blocks * (u_int64_t)HFSTOVCB(hfsmp)->blockSize;
 1147                                 while (fsize > 0) {
 1148                                         if (fsize > HFS_BIGFILE_SIZE) {
 1149                                                 fsize -= HFS_BIGFILE_SIZE;
 1150                                         } else {
 1151                                                 fsize = 0;
 1152                                         }
 1153 
 1154                                         if (TruncateFileC(vcb, (FCB*)&dfork, fsize, false) != 0) {
 1155                                                 printf("error truncting data fork!\n");
 1156                                                 break;
 1157                                         }
 1158 
 1159                                         //
 1160                                         // if we're iteratively truncating this file down,
 1161                                         // then end the transaction and start a new one so
 1162                                         // that no one transaction gets too big.
 1163                                         //
 1164                                         if (fsize > 0 && started_tr) {
 1165                                                 journal_end_transaction(hfsmp->jnl);
 1166                                                 if (journal_start_transaction(hfsmp->jnl) != 0) {
 1167                                                         started_tr = 0;
 1168                                                         break;
 1169                                                 }
 1170                                         }
 1171                                 }
 1172                         }
 1173 
 1174                         if (rfork.ff_blocks > 0) {
 1175                                 rfork.ff_cp = &cnode;
 1176                                 cnode.c_datafork = NULL;
 1177                                 cnode.c_rsrcfork = &rfork;
 1178                                 if (TruncateFileC(vcb, (FCB*)&rfork, 0, false) != 0) {
 1179                                         printf("error truncting rsrc fork!\n");
 1180                                         break;
 1181                                 }
 1182                         }
 1183 
 1184                         /* Remove the file record from the Catalog */   
 1185                         if (cat_delete(hfsmp, &cnode.c_desc, &cnode.c_attr) != 0) {
 1186                                 printf("error deleting cat rec!\n");
 1187                                 break;
 1188                         }
 1189                         
 1190                         /* Update parent and volume counts */   
 1191                         hfsmp->hfs_privdir_attr.ca_entries--;
 1192                         (void)cat_update(hfsmp, &hfsmp->hfs_privdir_desc,
 1193                                          &hfsmp->hfs_privdir_attr, NULL, NULL);
 1194                         hfs_volupdate(hfsmp, VOL_RMFILE, 0);
 1195 
 1196                         /* Drop locks and end the transaction */
 1197                         (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
 1198                         cat_postflight(hfsmp, &cookie, p);
 1199                         catlock = catreserve = 0;
 1200                         if (started_tr) {
 1201                                 journal_end_transaction(hfsmp->jnl);
 1202                                 started_tr = 0;
 1203                         }
 1204                         hfs_global_shared_lock_release(hfsmp);
 1205                         shared_lock = 0;
 1206 
 1207                 } /* end if */
 1208         } /* end for */
 1209         
 1210 exit:
 1211         if (catlock) {
 1212                 (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
 1213         }
 1214         if (catreserve) {
 1215                 cat_postflight(hfsmp, &cookie, p);
 1216         }
 1217         if (started_tr) {
 1218                 journal_end_transaction(hfsmp->jnl);
 1219         }
 1220         if (shared_lock) {
 1221                 hfs_global_shared_lock_release(hfsmp);
 1222         }
 1223 
 1224         FREE(iterator, M_TEMP);
 1225         hfsmp->hfs_flags |= HFS_CLEANED_ORPHANS;
 1226 }
 1227 
 1228 
 1229 /*
 1230  * This will return the correct logical block size for a given vnode.
 1231  * For most files, it is the allocation block size, for meta data like
 1232  * BTrees, this is kept as part of the BTree private nodeSize
 1233  */
 1234 u_int32_t
 1235 GetLogicalBlockSize(struct vnode *vp)
 1236 {
 1237 u_int32_t logBlockSize;
 1238         
 1239         DBG_ASSERT(vp != NULL);
 1240 
 1241         /* start with default */
 1242         logBlockSize = VTOHFS(vp)->hfs_logBlockSize;
 1243 
 1244         if (vp->v_flag & VSYSTEM) {
 1245                 if (VTOF(vp)->fcbBTCBPtr != NULL) {
 1246                         BTreeInfoRec                    bTreeInfo;
 1247         
 1248                         /*
 1249                          * We do not lock the BTrees, because if we are getting block..then the tree
 1250                          * should be locked in the first place.
 1251                          * We just want the nodeSize wich will NEVER change..so even if the world
 1252                          * is changing..the nodeSize should remain the same. Which argues why lock
 1253                          * it in the first place??
 1254                          */
 1255                         
 1256                         (void) BTGetInformation (VTOF(vp), kBTreeInfoVersion, &bTreeInfo);
 1257                                         
 1258                         logBlockSize = bTreeInfo.nodeSize;
 1259 
 1260                 } else if (VTOC(vp)->c_fileid == kHFSAllocationFileID) {
 1261                                 logBlockSize = VTOVCB(vp)->vcbVBMIOSize;
 1262                 }
 1263         }
 1264 
 1265         DBG_ASSERT(logBlockSize > 0);
 1266         
 1267         return logBlockSize;    
 1268 }
 1269 
 1270 __private_extern__
 1271 u_int32_t
 1272 hfs_freeblks(struct hfsmount * hfsmp, int wantreserve)
 1273 {
 1274         struct vcb_t *vcb = HFSTOVCB(hfsmp);
 1275         u_int32_t freeblks;
 1276 
 1277         freeblks = vcb->freeBlocks;
 1278         if (wantreserve) {
 1279                 if (freeblks > vcb->reserveBlocks)
 1280                         freeblks -= vcb->reserveBlocks;
 1281                 else
 1282                         freeblks = 0;
 1283         }
 1284         if (freeblks > vcb->loanedBlocks)
 1285                 freeblks -= vcb->loanedBlocks;
 1286         else
 1287                 freeblks = 0;
 1288 
 1289 #ifdef HFS_SPARSE_DEV
 1290         /* 
 1291          * When the underlying device is sparse, check the
 1292          * available space on the backing store volume.
 1293          */
 1294         if ((hfsmp->hfs_flags & HFS_HAS_SPARSE_DEVICE) && hfsmp->hfs_backingfs_rootvp) {
 1295                 struct statfs statbuf;  /* 272 bytes */
 1296                 u_int32_t vfreeblks;
 1297                 u_int32_t loanedblks;
 1298                 struct mount * backingfs_mp;
 1299 
 1300                 backingfs_mp = hfsmp->hfs_backingfs_rootvp->v_mount;
 1301 
 1302                 if (VFS_STATFS(backingfs_mp, &statbuf, current_proc()) == 0) {
 1303                         vfreeblks = statbuf.f_bavail;
 1304                         /* Normalize block count if needed. */
 1305                         if (statbuf.f_bsize != vcb->blockSize) {
 1306                                 vfreeblks = ((u_int64_t)vfreeblks * (u_int64_t)statbuf.f_bsize) / vcb->blockSize;
 1307                         }
 1308                         if (vfreeblks > hfsmp->hfs_sparsebandblks)
 1309                                 vfreeblks -= hfsmp->hfs_sparsebandblks;
 1310                         else
 1311                                 vfreeblks = 0;
 1312                         
 1313                         /* Take into account any delayed allocations. */
 1314                         loanedblks = 2 * vcb->loanedBlocks;
 1315                         if (vfreeblks > loanedblks)
 1316                                 vfreeblks -= loanedblks;
 1317                         else
 1318                                 vfreeblks = 0;
 1319 
 1320                         freeblks = MIN(vfreeblks, freeblks);
 1321                 }
 1322         }
 1323 #endif /* HFS_SPARSE_DEV */
 1324 
 1325         return (freeblks);
 1326 }
 1327 
 1328 /*
 1329  * Map HFS Common errors (negative) to BSD error codes (positive).
 1330  * Positive errors (ie BSD errors) are passed through unchanged.
 1331  */
 1332 short MacToVFSError(OSErr err)
 1333 {
 1334         if (err >= 0)
 1335                 return err;
 1336 
 1337         switch (err) {
 1338         case dskFulErr:                 /*    -34 */
 1339         case btNoSpaceAvail:            /* -32733 */
 1340                 return ENOSPC;
 1341         case fxOvFlErr:                 /* -32750 */
 1342                 return EOVERFLOW;
 1343         
 1344         case btBadNode:                 /* -32731 */
 1345                 return EBADF;
 1346         
 1347         case memFullErr:                /*  -108 */
 1348                 return ENOMEM;          /*   +12 */
 1349         
 1350         case cmExists:                  /* -32718 */
 1351         case btExists:                  /* -32734 */
 1352                 return EEXIST;          /*    +17 */
 1353         
 1354         case cmNotFound:                /* -32719 */
 1355         case btNotFound:                /* -32735 */    
 1356                 return ENOENT;          /*     28 */
 1357         
 1358         case cmNotEmpty:                /* -32717 */
 1359                 return ENOTEMPTY;       /*     66 */
 1360         
 1361         case cmFThdDirErr:              /* -32714 */
 1362                 return EISDIR;          /*     21 */
 1363         
 1364         case fxRangeErr:                /* -32751 */
 1365                 return ERANGE;
 1366         
 1367         case bdNamErr:                  /*   -37 */
 1368                 return ENAMETOOLONG;    /*    63 */
 1369         
 1370         case paramErr:                  /*   -50 */
 1371         case fileBoundsErr:             /* -1309 */
 1372                 return EINVAL;          /*   +22 */
 1373         
 1374         case fsBTBadNodeSize:
 1375                 return ENXIO;
 1376 
 1377         default:
 1378                 return EIO;             /*   +5 */
 1379         }
 1380 }
 1381 
 1382 
 1383 /*
 1384  * Get the directory entry name hint for a given index.
 1385  * The directory cnode (dcp) must be locked.
 1386  */
 1387 __private_extern__
 1388 char *
 1389 hfs_getnamehint(struct cnode *dcp, int index)
 1390 {
 1391         struct hfs_index *entry;
 1392         void *self;
 1393 
 1394         if (index > 0) {
 1395                 self = current_act();
 1396                 SLIST_FOREACH(entry, &dcp->c_indexlist, hi_link) {
 1397                         if ((entry->hi_index == index)
 1398                         &&  (entry->hi_thread == self))
 1399                                 return (entry->hi_name);
 1400                 }
 1401         }
 1402 
 1403         return (NULL);
 1404 }
 1405 
 1406 /*
 1407  * Save a directory entry name hint for a given index.
 1408  * The directory cnode (dcp) must be locked.
 1409  */
 1410 __private_extern__
 1411 void
 1412 hfs_savenamehint(struct cnode *dcp, int index, const char * namehint)
 1413 {
 1414         struct hfs_index *entry;
 1415         int len;
 1416 
 1417         if (index > 0) {
 1418                 len = strlen(namehint);
 1419                 MALLOC(entry, struct hfs_index *, len + sizeof(struct hfs_index),
 1420                         M_TEMP, M_WAITOK);
 1421                 entry->hi_index = index;
 1422                 entry->hi_thread = current_act();
 1423                 bcopy(namehint, entry->hi_name, len + 1);
 1424                 SLIST_INSERT_HEAD(&dcp->c_indexlist, entry, hi_link);
 1425         }
 1426 }
 1427 
 1428 /*
 1429  * Release the directory entry name hint for a given index.
 1430  * The directory cnode (dcp) must be locked.
 1431  */
 1432 __private_extern__
 1433 void
 1434 hfs_relnamehint(struct cnode *dcp, int index)
 1435 {
 1436         struct hfs_index *entry;
 1437         void *self;
 1438 
 1439         if (index > 0) {
 1440                 self = current_act();
 1441                 SLIST_FOREACH(entry, &dcp->c_indexlist, hi_link) {
 1442                         if ((entry->hi_index == index)
 1443                         &&  (entry->hi_thread == self)) {
 1444                                 SLIST_REMOVE(&dcp->c_indexlist, entry, hfs_index,
 1445                                         hi_link);
 1446                                 FREE(entry, M_TEMP);
 1447                                 break;
 1448                         }
 1449                 }
 1450         }
 1451 }
 1452 
 1453 /*
 1454  * Release all directory entry name hints.
 1455  */
 1456 __private_extern__
 1457 void
 1458 hfs_relnamehints(struct cnode *dcp)
 1459 {
 1460         struct hfs_index *entry;
 1461         struct hfs_index *next;
 1462 
 1463         if (!SLIST_EMPTY(&dcp->c_indexlist)) {
 1464                 for(entry = SLIST_FIRST(&dcp->c_indexlist);
 1465                     entry != NULL;
 1466                     entry = next) {
 1467                         next = SLIST_NEXT(entry, hi_link);
 1468                         SLIST_REMOVE(&dcp->c_indexlist, entry, hfs_index, hi_link);
 1469                         FREE(entry, M_TEMP);
 1470                 }
 1471         }
 1472 }
 1473 
 1474 
 1475 /*
 1476  * Perform a case-insensitive compare of two UTF-8 filenames.
 1477  *
 1478  * Returns 0 if the strings match.
 1479  */
 1480 __private_extern__
 1481 int
 1482 hfs_namecmp(const char *str1, size_t len1, const char *str2, size_t len2)
 1483 {
 1484         u_int16_t *ustr1, *ustr2;
 1485         size_t ulen1, ulen2;
 1486         size_t maxbytes;
 1487         int cmp = -1;
 1488 
 1489         if (len1 != len2)
 1490                 return (cmp);
 1491 
 1492         maxbytes = kHFSPlusMaxFileNameChars << 1;
 1493         MALLOC(ustr1, u_int16_t *, maxbytes << 1, M_TEMP, M_WAITOK);
 1494         ustr2 = ustr1 + (maxbytes >> 1);
 1495 
 1496         if (utf8_decodestr(str1, len1, ustr1, &ulen1, maxbytes, ':', 0) != 0)
 1497                 goto out;
 1498         if (utf8_decodestr(str2, len2, ustr2, &ulen2, maxbytes, ':', 0) != 0)
 1499                 goto out;
 1500         
 1501         cmp = FastUnicodeCompare(ustr1, ulen1>>1, ustr2, ulen2>>1);
 1502 out:
 1503         FREE(ustr1, M_TEMP);
 1504         return (cmp);
 1505 }
 1506 
 1507 
 1508 __private_extern__
 1509 int
 1510 hfs_early_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp,
 1511                                            void *_args, int embeddedOffset, int mdb_offset,
 1512                                            HFSMasterDirectoryBlock *mdbp, struct ucred *cred)
 1513 {
 1514         JournalInfoBlock *jibp;
 1515         struct buf       *jinfo_bp, *bp;
 1516         int               sectors_per_fsblock, arg_flags=0, arg_tbufsz=0;
 1517         int               retval, blksize = hfsmp->hfs_phys_block_size;
 1518         struct vnode     *devvp;
 1519         struct hfs_mount_args *args = _args;
 1520 
 1521         devvp = hfsmp->hfs_devvp;
 1522 
 1523         if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS)) {
 1524                 arg_flags  = args->journal_flags;
 1525                 arg_tbufsz = args->journal_tbuffer_size;
 1526         }
 1527 
 1528         sectors_per_fsblock = SWAP_BE32(vhp->blockSize) / blksize;
 1529                                 
 1530         retval = meta_bread(devvp,
 1531                                                 embeddedOffset/blksize + 
 1532                                                 (SWAP_BE32(vhp->journalInfoBlock)*sectors_per_fsblock),
 1533                                                 SWAP_BE32(vhp->blockSize), cred, &jinfo_bp);
 1534         if (retval)
 1535                 return retval;
 1536 
 1537         jibp = (JournalInfoBlock *)jinfo_bp->b_data;
 1538         jibp->flags  = SWAP_BE32(jibp->flags);
 1539         jibp->offset = SWAP_BE64(jibp->offset);
 1540         jibp->size   = SWAP_BE64(jibp->size);
 1541 
 1542         if (jibp->flags & kJIJournalInFSMask) {
 1543                 hfsmp->jvp = hfsmp->hfs_devvp;
 1544         } else {
 1545                 printf("hfs: journal not stored in fs! don't know what to do.\n");
 1546                 brelse(jinfo_bp);
 1547                 return EINVAL;
 1548         }
 1549 
 1550         // save this off for the hack-y check in hfs_remove()
 1551         hfsmp->jnl_start = jibp->offset / SWAP_BE32(vhp->blockSize);
 1552         hfsmp->jnl_size  = jibp->size;
 1553 
 1554         if (jibp->flags & kJIJournalNeedInitMask) {
 1555                 printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
 1556                            jibp->offset + (off_t)embeddedOffset, jibp->size);
 1557                 hfsmp->jnl = journal_create(hfsmp->jvp,
 1558                                                                         jibp->offset + (off_t)embeddedOffset,
 1559                                                                         jibp->size,
 1560                                                                         devvp,
 1561                                                                         blksize,
 1562                                                                         arg_flags,
 1563                                                                         arg_tbufsz,
 1564                                                                         hfs_sync_metadata, hfsmp->hfs_mp);
 1565 
 1566                 // no need to start a transaction here... if this were to fail
 1567                 // we'd just re-init it on the next mount.
 1568                 jibp->flags &= ~kJIJournalNeedInitMask;
 1569                 jibp->flags  = SWAP_BE32(jibp->flags);
 1570                 jibp->offset = SWAP_BE64(jibp->offset);
 1571                 jibp->size   = SWAP_BE64(jibp->size);
 1572                 bwrite(jinfo_bp);
 1573                 jinfo_bp = NULL;
 1574                 jibp     = NULL;
 1575         } else { 
 1576                 //printf("hfs: Opening the journal (joffset 0x%llx sz 0x%llx vhp_blksize %d)...\n",
 1577                 //         jibp->offset + (off_t)embeddedOffset,
 1578                 //         jibp->size, SWAP_BE32(vhp->blockSize));
 1579                                 
 1580                 hfsmp->jnl = journal_open(hfsmp->jvp,
 1581                                                                   jibp->offset + (off_t)embeddedOffset,
 1582                                                                   jibp->size,
 1583                                                                   devvp,
 1584                                                                   blksize,
 1585                                                                   arg_flags,
 1586                                                                   arg_tbufsz,
 1587                                                                   hfs_sync_metadata, hfsmp->hfs_mp);
 1588 
 1589                 brelse(jinfo_bp);
 1590                 jinfo_bp = NULL;
 1591                 jibp     = NULL;
 1592 
 1593                 if (hfsmp->jnl && mdbp) {
 1594                         // reload the mdb because it could have changed
 1595                         // if the journal had to be replayed.
 1596                         if (mdb_offset == 0) {
 1597                                 mdb_offset = (embeddedOffset / blksize) + HFS_PRI_SECTOR(blksize);
 1598                         }
 1599                         retval = meta_bread(devvp, mdb_offset, blksize, cred, &bp);
 1600                         if (retval) {
 1601                                 brelse(bp);
 1602                                 printf("hfs: failed to reload the mdb after opening the journal (retval %d)!\n",
 1603                                            retval);
 1604                                 return retval;
 1605                         }
 1606                         bcopy(bp->b_data + HFS_PRI_OFFSET(blksize), mdbp, 512);
 1607                         brelse(bp);
 1608                         bp = NULL;
 1609                 }
 1610         }
 1611 
 1612 
 1613         //printf("journal @ 0x%x\n", hfsmp->jnl);
 1614         
 1615         // if we expected the journal to be there and we couldn't
 1616         // create it or open it then we have to bail out.
 1617         if (hfsmp->jnl == NULL) {
 1618                 printf("hfs: early jnl init: failed to open/create the journal (retval %d).\n", retval);
 1619                 return EINVAL;
 1620         }
 1621 
 1622         return 0;
 1623 }
 1624 
 1625 
 1626 //
 1627 // This function will go and re-locate the .journal_info_block and
 1628 // the .journal files in case they moved (which can happen if you
 1629 // run Norton SpeedDisk).  If we fail to find either file we just
 1630 // disable journaling for this volume and return.  We turn off the
 1631 // journaling bit in the vcb and assume it will get written to disk
 1632 // later (if it doesn't on the next mount we'd do the same thing
 1633 // again which is harmless).  If we disable journaling we don't
 1634 // return an error so that the volume is still mountable.
 1635 //
 1636 // If the info we find for the .journal_info_block and .journal files
 1637 // isn't what we had stored, we re-set our cached info and proceed
 1638 // with opening the journal normally.
 1639 //
 1640 static int
 1641 hfs_late_journal_init(struct hfsmount *hfsmp, HFSPlusVolumeHeader *vhp, void *_args)
 1642 {
 1643         JournalInfoBlock *jibp;
 1644         struct buf       *jinfo_bp, *bp;
 1645         int               sectors_per_fsblock, arg_flags=0, arg_tbufsz=0;
 1646         int               retval, need_flush = 0, write_jibp = 0;
 1647         struct vnode     *devvp;
 1648         struct cat_attr   jib_attr, jattr;
 1649         struct cat_fork   jib_fork, jfork;
 1650         ExtendedVCB      *vcb;
 1651         u_long            fid;
 1652         struct hfs_mount_args *args = _args;
 1653         
 1654         devvp = hfsmp->hfs_devvp;
 1655         vcb = HFSTOVCB(hfsmp);
 1656         
 1657         if (args != NULL && (args->flags & HFSFSMNT_EXTENDED_ARGS)) {
 1658                 if (args->journal_disable) {
 1659                         return 0;
 1660                 }
 1661 
 1662                 arg_flags  = args->journal_flags;
 1663                 arg_tbufsz = args->journal_tbuffer_size;
 1664         }
 1665 
 1666         fid = GetFileInfo(vcb, kRootDirID, ".journal_info_block", &jib_attr, &jib_fork);
 1667         if (fid == 0 || jib_fork.cf_extents[0].startBlock == 0 || jib_fork.cf_size == 0) {
 1668                 printf("hfs: can't find the .journal_info_block! disabling journaling (start: %d).\n",
 1669                            jib_fork.cf_extents[0].startBlock);
 1670                 vcb->vcbAtrb &= ~kHFSVolumeJournaledMask;
 1671                 return 0;
 1672         }
 1673         hfsmp->hfs_jnlinfoblkid = fid;
 1674 
 1675         // make sure the journal_info_block begins where we think it should.
 1676         if (SWAP_BE32(vhp->journalInfoBlock) != jib_fork.cf_extents[0].startBlock) {
 1677                 printf("hfs: The journal_info_block moved (was: %d; is: %d).  Fixing up\n",
 1678                            SWAP_BE32(vhp->journalInfoBlock), jib_fork.cf_extents[0].startBlock);
 1679 
 1680                 vcb->vcbJinfoBlock    = jib_fork.cf_extents[0].startBlock;
 1681                 vhp->journalInfoBlock = SWAP_BE32(jib_fork.cf_extents[0].startBlock);
 1682         }
 1683 
 1684 
 1685         sectors_per_fsblock = SWAP_BE32(vhp->blockSize) / hfsmp->hfs_phys_block_size;
 1686         retval = meta_bread(devvp,
 1687                                                 vcb->hfsPlusIOPosOffset / hfsmp->hfs_phys_block_size + 
 1688                                                 (SWAP_BE32(vhp->journalInfoBlock)*sectors_per_fsblock),
 1689                                                 SWAP_BE32(vhp->blockSize), NOCRED, &jinfo_bp);
 1690         if (retval) {
 1691                 printf("hfs: can't read journal info block. disabling journaling.\n");
 1692                 vcb->vcbAtrb &= ~kHFSVolumeJournaledMask;
 1693                 return 0;
 1694         }
 1695 
 1696         jibp = (JournalInfoBlock *)jinfo_bp->b_data;
 1697         jibp->flags  = SWAP_BE32(jibp->flags);
 1698         jibp->offset = SWAP_BE64(jibp->offset);
 1699         jibp->size   = SWAP_BE64(jibp->size);
 1700 
 1701         fid = GetFileInfo(vcb, kRootDirID, ".journal", &jattr, &jfork);
 1702         if (fid == 0 || jfork.cf_extents[0].startBlock == 0 || jfork.cf_size == 0) {
 1703                 printf("hfs: can't find the journal file! disabling journaling (start: %d)\n",
 1704                            jfork.cf_extents[0].startBlock);
 1705                 brelse(jinfo_bp);
 1706                 vcb->vcbAtrb &= ~kHFSVolumeJournaledMask;
 1707                 return 0;
 1708         }
 1709         hfsmp->hfs_jnlfileid = fid;
 1710 
 1711         // make sure the journal file begins where we think it should.
 1712         if ((jibp->offset / (u_int64_t)vcb->blockSize) != jfork.cf_extents[0].startBlock) {
 1713                 printf("hfs: The journal file moved (was: %lld; is: %d).  Fixing up\n",
 1714                            (jibp->offset / (u_int64_t)vcb->blockSize), jfork.cf_extents[0].startBlock);
 1715 
 1716                 jibp->offset = (u_int64_t)jfork.cf_extents[0].startBlock * (u_int64_t)vcb->blockSize;
 1717                 write_jibp   = 1;
 1718         }
 1719 
 1720         // check the size of the journal file.
 1721         if (jibp->size != (u_int64_t)jfork.cf_extents[0].blockCount*vcb->blockSize) {
 1722                 printf("hfs: The journal file changed size! (was %lld; is %lld).  Fixing up.\n",
 1723                            jibp->size, (u_int64_t)jfork.cf_extents[0].blockCount*vcb->blockSize);
 1724                 
 1725                 jibp->size = (u_int64_t)jfork.cf_extents[0].blockCount * vcb->blockSize;
 1726                 write_jibp = 1;
 1727         }
 1728         
 1729         if (jibp->flags & kJIJournalInFSMask) {
 1730                 hfsmp->jvp = hfsmp->hfs_devvp;
 1731         } else {
 1732                 printf("hfs: journal not stored in fs! don't know what to do.\n");
 1733                 brelse(jinfo_bp);
 1734                 return EINVAL;
 1735         }
 1736 
 1737         // save this off for the hack-y check in hfs_remove()
 1738         hfsmp->jnl_start = jibp->offset / SWAP_BE32(vhp->blockSize);
 1739         hfsmp->jnl_size  = jibp->size;
 1740 
 1741         if (jibp->flags & kJIJournalNeedInitMask) {
 1742                 printf("hfs: Initializing the journal (joffset 0x%llx sz 0x%llx)...\n",
 1743                            jibp->offset + (off_t)vcb->hfsPlusIOPosOffset, jibp->size);
 1744                 hfsmp->jnl = journal_create(hfsmp->jvp,
 1745                                                                         jibp->offset + (off_t)vcb->hfsPlusIOPosOffset,
 1746                                                                         jibp->size,
 1747                                                                         devvp,
 1748                                                                         hfsmp->hfs_phys_block_size,
 1749                                                                         arg_flags,
 1750                                                                         arg_tbufsz,
 1751                                                                         hfs_sync_metadata, hfsmp->hfs_mp);
 1752 
 1753                 // no need to start a transaction here... if this were to fail
 1754                 // we'd just re-init it on the next mount.
 1755                 jibp->flags &= ~kJIJournalNeedInitMask;
 1756                 write_jibp   = 1;
 1757 
 1758         } else { 
 1759                 //
 1760                 // if we weren't the last person to mount this volume
 1761                 // then we need to throw away the journal because it
 1762                 // is likely that someone else mucked with the disk.
 1763                 // if the journal is empty this is no big deal.  if the
 1764                 // disk is dirty this prevents us from replaying the
 1765                 // journal over top of changes that someone else made.
 1766                 //
 1767                 arg_flags |= JOURNAL_RESET;
 1768                 
 1769                 //printf("hfs: Opening the journal (joffset 0x%llx sz 0x%llx vhp_blksize %d)...\n",
 1770                 //         jibp->offset + (off_t)vcb->hfsPlusIOPosOffset,
 1771                 //         jibp->size, SWAP_BE32(vhp->blockSize));
 1772                                 
 1773                 hfsmp->jnl = journal_open(hfsmp->jvp,
 1774                                                                   jibp->offset + (off_t)vcb->hfsPlusIOPosOffset,
 1775                                                                   jibp->size,
 1776                                                                   devvp,
 1777                                                                   hfsmp->hfs_phys_block_size,
 1778                                                                   arg_flags,
 1779                                                                   arg_tbufsz,
 1780                                                                   hfs_sync_metadata, hfsmp->hfs_mp);
 1781         }
 1782                         
 1783 
 1784         if (write_jibp) {
 1785                 jibp->flags  = SWAP_BE32(jibp->flags);
 1786                 jibp->offset = SWAP_BE64(jibp->offset);
 1787                 jibp->size   = SWAP_BE64(jibp->size);
 1788 
 1789                 bwrite(jinfo_bp);
 1790         } else {
 1791                 brelse(jinfo_bp);
 1792         } 
 1793         jinfo_bp = NULL;
 1794         jibp     = NULL;
 1795 
 1796         //printf("journal @ 0x%x\n", hfsmp->jnl);
 1797         
 1798         // if we expected the journal to be there and we couldn't
 1799         // create it or open it then we have to bail out.
 1800         if (hfsmp->jnl == NULL) {
 1801                 printf("hfs: late jnl init: failed to open/create the journal (retval %d).\n", retval);
 1802                 return EINVAL;
 1803         }
 1804 
 1805         return 0;
 1806 }
 1807 
 1808 /*
 1809  * Calculate the allocation zone for metadata.
 1810  *
 1811  * This zone includes the following:
 1812  *      Allocation Bitmap file
 1813  *      Overflow Extents file
 1814  *      Journal file
 1815  *      Quota files
 1816  *      Clustered Hot files
 1817  *      Catalog file
 1818  *
 1819  *                          METADATA ALLOCATION ZONE
 1820  * ____________________________________________________________________________
 1821  * |    |    |     |               |                              |           |
 1822  * | BM | JF | OEF |    CATALOG    |--->                          | HOT FILES |
 1823  * |____|____|_____|_______________|______________________________|___________|
 1824  *
 1825  * <------------------------------- N * 128 MB ------------------------------->
 1826  *
 1827  */
 1828 #define GIGABYTE  (u_int64_t)(1024*1024*1024)
 1829 
 1830 #define OVERFLOW_DEFAULT_SIZE (4*1024*1024)
 1831 #define OVERFLOW_MAXIMUM_SIZE (128*1024*1024)
 1832 #define JOURNAL_DEFAULT_SIZE  (8*1024*1024)
 1833 #define JOURNAL_MAXIMUM_SIZE  (512*1024*1024)
 1834 #define HOTBAND_MINIMUM_SIZE  (10*1024*1024)
 1835 #define HOTBAND_MAXIMUM_SIZE  (512*1024*1024)
 1836 
 1837 static void
 1838 hfs_metadatazone_init(struct hfsmount *hfsmp)
 1839 {
 1840         ExtendedVCB  *vcb;
 1841         struct BTreeInfoRec btinfo;
 1842         u_int64_t  fs_size;
 1843         u_int64_t  zonesize;
 1844         u_int64_t  temp;
 1845         u_int64_t  filesize;
 1846         u_int32_t  blk;
 1847         int  items;
 1848 
 1849         vcb = HFSTOVCB(hfsmp);
 1850         fs_size = (u_int64_t)vcb->blockSize * (u_int64_t)vcb->totalBlocks;
 1851 
 1852         /*
 1853          * For volumes less than 10 GB, don't bother.
 1854          */
 1855         if (fs_size < ((u_int64_t)10 * GIGABYTE))
 1856                 return;
 1857         /*
 1858          * Skip non-journaled volumes as well.
 1859          */
 1860         if (hfsmp->jnl == NULL)
 1861                 return;
 1862 
 1863         /*
 1864          * Start with allocation bitmap (a fixed size).
 1865          */
 1866         zonesize = roundup(vcb->totalBlocks / 8, vcb->vcbVBMIOSize);
 1867 
 1868         /*
 1869          * Overflow Extents file gets 4 MB per 100 GB.
 1870          */
 1871         items = fs_size / ((u_int64_t)100 * GIGABYTE);
 1872         filesize = (u_int64_t)(items + 1) * OVERFLOW_DEFAULT_SIZE;
 1873         if (filesize > OVERFLOW_MAXIMUM_SIZE)
 1874                 filesize = OVERFLOW_MAXIMUM_SIZE;
 1875         zonesize += filesize;
 1876         hfsmp->hfs_overflow_maxblks = filesize / vcb->blockSize;
 1877 
 1878         /*
 1879          * Plan for at least 8 MB of journal for each
 1880          * 100 GB of disk space (up to a 512 MB).
 1881          */
 1882         items = fs_size / ((u_int64_t)100 * GIGABYTE);
 1883         filesize = (u_int64_t)(items + 1) * JOURNAL_DEFAULT_SIZE;
 1884         if (filesize > JOURNAL_MAXIMUM_SIZE)
 1885                 filesize = JOURNAL_MAXIMUM_SIZE;
 1886         zonesize += filesize;
 1887 
 1888         /*
 1889          * Catalog file gets 10 MB per 1 GB.
 1890          *
 1891          * How about considering the current catalog size (used nodes * node size)
 1892          * and the current file data size to help estimate the required
 1893          * catalog size.
 1894          */
 1895         filesize = MIN((fs_size / 1024) * 10, GIGABYTE);
 1896         hfsmp->hfs_catalog_maxblks = filesize / vcb->blockSize;
 1897         zonesize += filesize;
 1898 
 1899         /*
 1900          * Add space for hot file region.
 1901          *
 1902          * ...for now, use 5 MB per 1 GB (0.5 %)
 1903          */
 1904         filesize = (fs_size / 1024) * 5;
 1905         if (filesize > HOTBAND_MAXIMUM_SIZE)
 1906                 filesize = HOTBAND_MAXIMUM_SIZE;
 1907         else if (filesize < HOTBAND_MINIMUM_SIZE)
 1908                 filesize = HOTBAND_MINIMUM_SIZE;
 1909         /*
 1910          * Calculate user quota file requirements.
 1911          */
 1912         items = QF_USERS_PER_GB * (fs_size / GIGABYTE);
 1913         if (items < QF_MIN_USERS)
 1914                 items = QF_MIN_USERS;
 1915         else if (items > QF_MAX_USERS)
 1916                 items = QF_MAX_USERS;
 1917         if (!powerof2(items)) {
 1918                 int x = items;
 1919                 items = 4;
 1920                 while (x>>1 != 1) {
 1921                         x = x >> 1;
 1922                         items = items << 1;
 1923                 }
 1924         }
 1925         filesize += (items + 1) * sizeof(struct dqblk);
 1926         /*
 1927          * Calculate group quota file requirements.
 1928          *
 1929          */
 1930         items = QF_GROUPS_PER_GB * (fs_size / GIGABYTE);
 1931         if (items < QF_MIN_GROUPS)
 1932                 items = QF_MIN_GROUPS;
 1933         else if (items > QF_MAX_GROUPS)
 1934                 items = QF_MAX_GROUPS;
 1935         if (!powerof2(items)) {
 1936                 int x = items;
 1937                 items = 4;
 1938                 while (x>>1 != 1) {
 1939                         x = x >> 1;
 1940                         items = items << 1;
 1941                 }
 1942         }
 1943         filesize += (items + 1) * sizeof(struct dqblk);
 1944         hfsmp->hfs_hotfile_maxblks = filesize / vcb->blockSize;
 1945         zonesize += filesize;
 1946 
 1947         /*
 1948          * Round up entire zone to a bitmap block's worth.
 1949          * The extra space goes to the catalog file and hot file area.
 1950          */
 1951         temp = zonesize;
 1952         zonesize = roundup(zonesize, vcb->vcbVBMIOSize * 8 * vcb->blockSize);
 1953         temp = zonesize - temp;  /* temp has extra space */
 1954         filesize += temp / 3;
 1955         hfsmp->hfs_catalog_maxblks += (temp - (temp / 3)) / vcb->blockSize;
 1956 
 1957         /* Convert to allocation blocks. */
 1958         blk = zonesize / vcb->blockSize;
 1959 
 1960         /* The default metadata zone location is at the start of volume. */
 1961         hfsmp->hfs_metazone_start = 1;
 1962         hfsmp->hfs_metazone_end = blk - 1;
 1963         
 1964         /* The default hotfile area is at the end of the zone. */
 1965         hfsmp->hfs_hotfile_start = blk - (filesize / vcb->blockSize);
 1966         hfsmp->hfs_hotfile_end = hfsmp->hfs_metazone_end;
 1967         hfsmp->hfs_hotfile_freeblks = hfs_hotfile_freeblocks(hfsmp);
 1968 #if 0
 1969         printf("HFS: metadata zone is %d to %d\n", hfsmp->hfs_metazone_start, hfsmp->hfs_metazone_end);
 1970         printf("HFS: hot file band is %d to %d\n", hfsmp->hfs_hotfile_start, hfsmp->hfs_hotfile_end);
 1971         printf("HFS: hot file band free blocks = %d\n", hfsmp->hfs_hotfile_freeblks);
 1972 #endif
 1973         hfsmp->hfs_flags |= HFS_METADATA_ZONE;
 1974 }
 1975 
 1976 
 1977 static u_int32_t
 1978 hfs_hotfile_freeblocks(struct hfsmount *hfsmp)
 1979 {
 1980         ExtendedVCB  *vcb = HFSTOVCB(hfsmp);
 1981         int  freeblocks;
 1982 
 1983         freeblocks = MetaZoneFreeBlocks(vcb);
 1984         /* Minus Extents overflow file reserve. */
 1985         freeblocks -=
 1986                 hfsmp->hfs_overflow_maxblks - VTOF(vcb->extentsRefNum)->ff_blocks;
 1987         /* Minus catalog file reserve. */
 1988         freeblocks -=
 1989                 hfsmp->hfs_catalog_maxblks - VTOF(vcb->catalogRefNum)->ff_blocks;
 1990         if (freeblocks < 0)
 1991                 freeblocks = 0;
 1992 
 1993         return MIN(freeblocks, hfsmp->hfs_hotfile_maxblks);
 1994 }
 1995 
 1996 /*
 1997  * Determine if a file is a "virtual" metadata file.
 1998  * This includes journal and quota files.
 1999  */
 2000 __private_extern__
 2001 int
 2002 hfs_virtualmetafile(struct cnode *cp)
 2003 {
 2004         char * filename;
 2005 
 2006 
 2007         if (cp->c_parentcnid != kHFSRootFolderID)
 2008                 return (0);
 2009 
 2010         filename = cp->c_desc.cd_nameptr;
 2011         if (filename == NULL)
 2012                 return (0);
 2013 
 2014         if ((strcmp(filename, ".journal") == 0) ||
 2015             (strcmp(filename, ".journal_info_block") == 0) ||
 2016             (strcmp(filename, ".quota.user") == 0) ||
 2017             (strcmp(filename, ".quota.group") == 0) ||
 2018             (strcmp(filename, ".hotfiles.btree") == 0))
 2019                 return (1);
 2020 
 2021         return (0);
 2022 }
 2023 

Cache object: 57cc0f28896a5e3f5ad790e0f6b85cac


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.