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_catalog.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 
   26 #include <sys/systm.h>
   27 #include <sys/kernel.h>
   28 #include <sys/malloc.h>
   29 #include <sys/stat.h>
   30 #include <sys/mount.h>
   31 #include <sys/vnode.h>
   32 #include <sys/namei.h>
   33 #include <sys/dirent.h>
   34 #include <vfs/vfs_support.h>
   35 #include <libkern/libkern.h>
   36 
   37 #include <sys/utfconv.h>
   38 
   39 #include "hfs.h"
   40 #include "hfs_catalog.h"
   41 #include "hfs_format.h"
   42 #include "hfs_endian.h"
   43 
   44 #include "hfscommon/headers/BTreesInternal.h"
   45 #include "hfscommon/headers/CatalogPrivate.h"
   46 #include "hfscommon/headers/HFSUnicodeWrappers.h"
   47 
   48 extern OSErr PositionIterator(CatalogIterator *cip, UInt32 offset, BTreeIterator *bip, UInt16 *op);
   49 
   50 /*
   51  * Initialization of an FSBufferDescriptor structure.
   52  */
   53 #define BDINIT(bd, addr) { \
   54         (bd).bufferAddress = (addr); \
   55         (bd).itemSize = sizeof(*(addr)); \
   56         (bd).itemCount = 1; \
   57 }
   58 
   59 
   60 struct btobj {
   61         BTreeIterator           iterator;
   62         HFSPlusCatalogKey       key;
   63         CatalogRecord           data;
   64 };
   65 
   66 struct update_state {
   67         struct cat_desc *       s_desc; 
   68         struct cat_attr *       s_attr;
   69         struct cat_fork *       s_datafork;
   70         struct cat_fork *       s_rsrcfork;
   71         struct hfsmount *       s_hfsmp;
   72 };
   73 
   74 
   75 static int cat_lookupbykey(struct hfsmount *hfsmp, CatalogKey *keyp, u_long hint, int wantrsrc,
   76                   struct cat_desc *descp, struct cat_attr *attrp, struct cat_fork *forkp);
   77 
   78 static int cat_lookupmangled(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc,
   79                   struct cat_desc *outdescp, struct cat_attr *attrp, struct cat_fork *forkp);
   80 
   81 extern int mac_roman_to_unicode(const Str31 hfs_str, UniChar *uni_str,
   82                                 UInt32 maxCharLen, UInt32 *unicodeChars);
   83 
   84 extern int unicode_to_hfs(ExtendedVCB *vcb, ByteCount srcLen,
   85                           const u_int16_t* srcStr, Str31 dstStr, int retry);
   86 
   87 
   88 /* Internal catalog support routines */
   89 
   90 int resolvelink(struct hfsmount *hfsmp, u_long linkref, struct HFSPlusCatalogFile *recp);
   91 
   92 static int resolvelinkid(struct hfsmount *hfsmp, u_long linkref, ino_t *ino);
   93 
   94 static int getkey(struct hfsmount *hfsmp, cnid_t cnid, CatalogKey * key);
   95 
   96 static int buildkey(struct hfsmount *hfsmp, struct cat_desc *descp,
   97                         HFSPlusCatalogKey *key, int retry);
   98 
   99 static void buildthreadkey(HFSCatalogNodeID parentID, int std_hfs, CatalogKey *key);
  100 
  101 static void buildrecord(struct cat_attr *attrp, cnid_t cnid, int std_hfs, u_int32_t encoding, CatalogRecord *crp, int *recordSize);
  102 
  103 static int catrec_update(const CatalogKey *ckp, CatalogRecord *crp, u_int16_t reclen, struct update_state *state);
  104 
  105 static int builddesc(const HFSPlusCatalogKey *key, cnid_t cnid, u_long hint, u_long encoding,
  106                         int isdir, struct cat_desc *descp);
  107 
  108 static void getbsdattr(struct hfsmount *hfsmp, const struct HFSPlusCatalogFile *crp, struct cat_attr * attrp);
  109 
  110 static void promotekey(struct hfsmount *hfsmp, const HFSCatalogKey *hfskey, HFSPlusCatalogKey *keyp, u_long *encoding);
  111 static void promotefork(struct hfsmount *hfsmp, const struct HFSCatalogFile *file, int resource, struct cat_fork * forkp);
  112 static void promoteattr(struct hfsmount *hfsmp, const CatalogRecord *dataPtr, struct HFSPlusCatalogFile *crp);
  113 
  114 static cnid_t getcnid(const CatalogRecord *crp);
  115 static u_long getencoding(const CatalogRecord *crp);
  116 static cnid_t getparentcnid(const CatalogRecord *recp);
  117 
  118 static int isadir(const CatalogRecord *crp);
  119 
  120 static int buildthread(void *keyp, void *recp, int std_hfs, int directory);
  121 
  122 
  123 __private_extern__
  124 int
  125 cat_preflight(struct hfsmount *hfsmp, catops_t ops, cat_cookie_t *cookie, struct proc *p)
  126 {
  127         FCB *fcb;
  128         int result;
  129 
  130         fcb = GetFileControlBlock(HFSTOVCB(hfsmp)->catalogRefNum);
  131 
  132         /* Lock catalog b-tree */
  133         result = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
  134         if (result)
  135                  return (result);
  136          
  137         result = BTReserveSpace(fcb, ops, (void*)cookie);
  138         
  139         /* Unlock catalog b-tree */
  140         (void) hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
  141 
  142         MacToVFSError(result);
  143 }
  144 
  145 __private_extern__
  146 void
  147 cat_postflight(struct hfsmount *hfsmp, cat_cookie_t *cookie, struct proc *p)
  148 {
  149         FCB *fcb;
  150         int error;
  151 
  152         fcb = GetFileControlBlock(HFSTOVCB(hfsmp)->catalogRefNum);
  153 
  154         error = hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_EXCLUSIVE, p);
  155         (void) BTReleaseReserve(fcb, (void*)cookie);
  156         if (error == 0) {
  157                 hfs_metafilelocking(hfsmp, kHFSCatalogFileID, LK_RELEASE, p);
  158         }
  159 }
  160 
  161  
  162 __private_extern__
  163 void
  164 cat_convertattr(
  165         struct hfsmount *hfsmp,
  166         CatalogRecord * recp,
  167         struct cat_attr *attrp,
  168         struct cat_fork *datafp,
  169         struct cat_fork *rsrcfp)
  170 {
  171         int std_hfs = HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord;
  172 
  173         if (std_hfs) {
  174                 struct HFSPlusCatalogFile cnoderec;
  175 
  176                 promoteattr(hfsmp, recp, &cnoderec);
  177                 getbsdattr(hfsmp, &cnoderec, attrp);
  178         } else {
  179                 getbsdattr(hfsmp, (struct HFSPlusCatalogFile *)recp, attrp);
  180         }
  181 
  182         if (isadir(recp))
  183                 bzero(datafp, sizeof(*datafp));
  184         else if (std_hfs) {
  185                 promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, 0, datafp);
  186                 promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, 1, rsrcfp);
  187         } else {
  188                 /* Convert the data fork. */
  189                 datafp->cf_size = recp->hfsPlusFile.dataFork.logicalSize;
  190                 datafp->cf_blocks = recp->hfsPlusFile.dataFork.totalBlocks;
  191                 if ((hfsmp->hfc_stage == HFC_RECORDING) &&
  192                     (attrp->ca_atime >= hfsmp->hfc_timebase)) {
  193                         datafp->cf_bytesread =
  194                                 recp->hfsPlusFile.dataFork.clumpSize *
  195                                 HFSTOVCB(hfsmp)->blockSize;
  196                 } else {
  197                         datafp->cf_bytesread = 0;
  198                 }
  199                 datafp->cf_vblocks = 0;
  200                 bcopy(&recp->hfsPlusFile.dataFork.extents[0],
  201                       &datafp->cf_extents[0], sizeof(HFSPlusExtentRecord));
  202 
  203                 /* Convert the resource fork. */
  204                 rsrcfp->cf_size = recp->hfsPlusFile.resourceFork.logicalSize;
  205                 rsrcfp->cf_blocks = recp->hfsPlusFile.resourceFork.totalBlocks;
  206                 if ((hfsmp->hfc_stage == HFC_RECORDING) &&
  207                     (attrp->ca_atime >= hfsmp->hfc_timebase)) {
  208                         datafp->cf_bytesread =
  209                                 recp->hfsPlusFile.resourceFork.clumpSize *
  210                                 HFSTOVCB(hfsmp)->blockSize;
  211                 } else {
  212                         datafp->cf_bytesread = 0;
  213                 }
  214                 rsrcfp->cf_vblocks = 0;
  215                 bcopy(&recp->hfsPlusFile.resourceFork.extents[0],
  216                       &rsrcfp->cf_extents[0], sizeof(HFSPlusExtentRecord));
  217         }
  218 }
  219 
  220 __private_extern__
  221 int
  222 cat_convertkey(
  223         struct hfsmount *hfsmp,
  224         CatalogKey *key,
  225         CatalogRecord * recp,
  226         struct cat_desc *descp)
  227 {
  228         int std_hfs = HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord;
  229         HFSPlusCatalogKey * pluskey = NULL;
  230         u_long encoding;
  231 
  232         if (std_hfs) {
  233                 MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
  234                 promotekey(hfsmp, (HFSCatalogKey *)key, pluskey, &encoding);
  235 
  236         } else {
  237                 pluskey = (HFSPlusCatalogKey *)key;
  238                 encoding = getencoding(recp);
  239         }
  240 
  241         builddesc(pluskey, getcnid(recp), 0, encoding, isadir(recp), descp);
  242         if (std_hfs) {
  243                 FREE(pluskey, M_TEMP);
  244         }
  245         return (0);
  246 }
  247 
  248 
  249 /*
  250  * cat_releasedesc
  251  */
  252 __private_extern__
  253 void
  254 cat_releasedesc(struct cat_desc *descp)
  255 {
  256         char * name;
  257 
  258         if (descp == NULL)
  259                 return;
  260 
  261         if ((descp->cd_flags & CD_HASBUF) &&
  262             (descp->cd_nameptr != NULL)) {
  263                 name = descp->cd_nameptr;
  264                 descp->cd_nameptr = NULL;
  265                 descp->cd_namelen = 0;
  266                 descp->cd_flags &= ~CD_HASBUF;
  267                 remove_name(name);
  268         }
  269         descp->cd_nameptr = NULL;
  270         descp->cd_namelen = 0;
  271 }
  272 
  273 /*
  274  * These Catalog functions allow access to the HFS Catalog (database).
  275  * The catalog b-tree lock must be aquired before calling any of these routines.
  276  */
  277 
  278 /*
  279  * cat_lookup - lookup a catalog node using a cnode decriptor
  280  */
  281 __private_extern__
  282 int
  283 cat_lookup(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc,
  284              struct cat_desc *outdescp, struct cat_attr *attrp,
  285              struct cat_fork *forkp)
  286 {
  287         CatalogKey * keyp;
  288         int std_hfs;
  289         int result;
  290 
  291         std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord);
  292 
  293         MALLOC(keyp, CatalogKey *, sizeof(CatalogKey), M_TEMP, M_WAITOK);
  294 
  295         result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)keyp, 1);
  296         if (result)
  297                 goto exit;
  298 
  299         result = cat_lookupbykey(hfsmp, keyp, descp->cd_hint, wantrsrc, outdescp, attrp, forkp);
  300         
  301         if (result == ENOENT) {
  302                 if (!std_hfs) {
  303                         result = cat_lookupmangled(hfsmp, descp, wantrsrc, outdescp, attrp, forkp);
  304                 } else if (hfsmp->hfs_encoding != kTextEncodingMacRoman) {
  305                 //      make MacRoman key from utf-8
  306                 //      result = cat_lookupbykey(hfsmp, keyp, descp->cd_hint, attrp, forkp);
  307                 //      update desc text encoding so that other catalog ops succeed
  308                 }
  309         }
  310 exit:   
  311         FREE(keyp, M_TEMP);
  312 
  313         return (result);
  314 }
  315 
  316 __private_extern__
  317 int
  318 cat_insertfilethread(struct hfsmount *hfsmp, struct cat_desc *descp)
  319 {
  320         struct BTreeIterator *iterator;
  321         struct FSBufferDescriptor file_data;
  322         struct HFSCatalogFile file_rec;
  323         UInt16 datasize;
  324         FCB *fcb;
  325         int result;
  326 
  327         if (HFSTOVCB(hfsmp)->vcbSigWord != kHFSSigWord)
  328                 return (EINVAL);
  329 
  330         fcb = GetFileControlBlock(HFSTOVCB(hfsmp)->catalogRefNum);
  331 
  332         MALLOC(iterator, BTreeIterator *, 2 * sizeof(*iterator), M_TEMP, M_WAITOK);
  333         bzero(&iterator[0], 2* sizeof(*iterator));
  334         result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)&iterator[0].key, 0);
  335         if (result)
  336                 goto exit;
  337 
  338         BDINIT(file_data, &file_rec);
  339         result = BTSearchRecord(fcb, &iterator[0], &file_data, &datasize, &iterator[0]);
  340         if (result) 
  341                 goto exit;
  342 
  343         if (file_rec.recordType != kHFSFileRecord) {
  344                 result = EISDIR;
  345                 goto exit;
  346         }
  347 
  348         if ((file_rec.flags & kHFSThreadExistsMask) == 0) {
  349                 struct FSBufferDescriptor thread_data;
  350                 struct HFSCatalogThread thread_rec;
  351 
  352                 file_rec.flags |= kHFSThreadExistsMask;
  353                 BDINIT(thread_data, &thread_rec);
  354                 thread_data.itemSize = buildthread(&iterator[0].key, &thread_rec, 1, 0);
  355                 buildthreadkey(file_rec.fileID, 1, (CatalogKey *)&iterator[1].key);
  356         
  357                 result = BTInsertRecord(fcb, &iterator[1], &thread_data, thread_data.itemSize);
  358                 if (result)
  359                         goto exit;
  360         
  361                 (void) BTReplaceRecord(fcb, &iterator[0], &file_data, datasize);
  362                 (void) BTFlushPath(fcb);
  363         }       
  364 exit:
  365         (void) BTFlushPath(fcb);
  366         FREE(iterator, M_TEMP);
  367 
  368         return MacToVFSError(result);
  369 }
  370 
  371 
  372 /*
  373  * cat_idlookup - lookup a catalog node using a cnode id
  374  */
  375 __private_extern__
  376 int
  377 cat_idlookup(struct hfsmount *hfsmp, cnid_t cnid, struct cat_desc *outdescp,
  378                  struct cat_attr *attrp, struct cat_fork *forkp)
  379 {
  380         struct BTreeIterator * iterator;
  381         FSBufferDescriptor btdata;
  382         UInt16  datasize;
  383         CatalogKey * keyp;
  384         CatalogRecord * recp;
  385         int result;
  386         int std_hfs;
  387 
  388         std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord);
  389 
  390         MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
  391         bzero(iterator, sizeof(*iterator));
  392         buildthreadkey(cnid, std_hfs, (CatalogKey *)&iterator->key);
  393 
  394         MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK);
  395         BDINIT(btdata, recp);
  396 
  397         result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator,
  398                                 &btdata, &datasize, iterator);
  399         if (result)
  400                 goto exit;
  401 
  402         /* Turn thread record into a cnode key (in place) */
  403         switch (recp->recordType) {
  404         case kHFSFileThreadRecord:
  405         case kHFSFolderThreadRecord:
  406                 keyp = (CatalogKey *)((char *)&recp->hfsThread.reserved + 6);
  407                 keyp->hfs.keyLength = kHFSCatalogKeyMinimumLength + keyp->hfs.nodeName[0];
  408                 break;
  409 
  410         case kHFSPlusFileThreadRecord:
  411         case kHFSPlusFolderThreadRecord:
  412                 keyp = (CatalogKey *)&recp->hfsPlusThread.reserved;
  413                 keyp->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength +
  414                                           (keyp->hfsPlus.nodeName.length * 2);
  415                 break;
  416 
  417         default:
  418                 result = ENOENT;
  419                 goto exit;
  420         }
  421 
  422         result = cat_lookupbykey(hfsmp, keyp, 0, 0, outdescp, attrp, forkp);
  423 exit:
  424         FREE(recp, M_TEMP);
  425         FREE(iterator, M_TEMP);
  426 
  427         return MacToVFSError(result);
  428 }
  429 
  430 
  431 /*
  432  * cat_lookupmangled - lookup a catalog node using a mangled name
  433  */
  434 static int
  435 cat_lookupmangled(struct hfsmount *hfsmp, struct cat_desc *descp, int wantrsrc,
  436                   struct cat_desc *outdescp, struct cat_attr *attrp, struct cat_fork *forkp)
  437 {
  438         cnid_t fileID;
  439         int prefixlen;
  440         int result;
  441         
  442         if (wantrsrc)
  443                 return (ENOENT);
  444 
  445         fileID = GetEmbeddedFileID(descp->cd_nameptr, descp->cd_namelen, &prefixlen);
  446         if (fileID < kHFSFirstUserCatalogNodeID)
  447                 return (ENOENT);
  448 
  449         result = cat_idlookup(hfsmp, fileID, outdescp, attrp, forkp);
  450         if (result)
  451                 return (ENOENT);
  452 
  453         /* It must be in the correct directory */
  454         if (descp->cd_parentcnid != outdescp->cd_parentcnid)
  455                 goto falsematch;
  456 
  457         if ((outdescp->cd_namelen < prefixlen) ||
  458             bcmp(outdescp->cd_nameptr, descp->cd_nameptr, prefixlen-6) != 0)
  459                 goto falsematch;
  460 
  461         return (0);
  462 
  463 falsematch:
  464         cat_releasedesc(outdescp);
  465         return (ENOENT);
  466 }
  467 
  468 
  469 /*
  470  * cat_lookupbykey - lookup a catalog node using a cnode key
  471  */
  472 static int
  473 cat_lookupbykey(struct hfsmount *hfsmp, CatalogKey *keyp, u_long hint, int wantrsrc,
  474                   struct cat_desc *descp, struct cat_attr *attrp, struct cat_fork *forkp)
  475 {
  476         struct BTreeIterator * iterator;
  477         FSBufferDescriptor btdata;
  478         CatalogRecord * recp;
  479         UInt16  datasize;
  480         int result;
  481         int std_hfs;
  482         u_long ilink = 0;
  483         cnid_t cnid = 0;
  484         u_long encoding = 0;
  485 
  486         std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord);
  487 
  488         MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK);
  489         BDINIT(btdata, recp);
  490         MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
  491         bzero(iterator, sizeof(*iterator));
  492         iterator->hint.nodeNum = hint;
  493         bcopy(keyp, &iterator->key, sizeof(CatalogKey));
  494 
  495         result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator,
  496                                 &btdata, &datasize, iterator);
  497         if (result) 
  498                 goto exit;
  499 
  500         /* Save the cnid now in case there's a hard link */
  501         cnid = getcnid(recp);
  502         encoding = getencoding(recp);
  503         hint = iterator->hint.nodeNum;
  504 
  505         /* Hide the journal files (if any) */
  506         if (hfsmp->jnl &&
  507                 ((cnid == hfsmp->hfs_jnlfileid) ||
  508                  (cnid == hfsmp->hfs_jnlinfoblkid))) {
  509 
  510                 result = ENOENT;
  511                 goto exit;
  512         }
  513 
  514         /*
  515          * When a hardlink link is encountered, auto resolve it
  516          */
  517         if (!std_hfs
  518             && (attrp || forkp) 
  519             && (recp->recordType == kHFSPlusFileRecord)
  520             && (SWAP_BE32(recp->hfsPlusFile.userInfo.fdType) == kHardLinkFileType)
  521             && (SWAP_BE32(recp->hfsPlusFile.userInfo.fdCreator) == kHFSPlusCreator)
  522             && ((to_bsd_time(recp->hfsPlusFile.createDate) == HFSTOVCB(hfsmp)->vcbCrDate) ||
  523                 (to_bsd_time(recp->hfsPlusFile.createDate) == hfsmp->hfs_metadata_createdate))) {
  524 
  525                 ilink = recp->hfsPlusFile.bsdInfo.special.iNodeNum;
  526 
  527                 (void) resolvelink(hfsmp, ilink, (struct HFSPlusCatalogFile *)recp);
  528         }
  529 
  530         if (attrp != NULL) {
  531                 if (std_hfs) {
  532                         struct HFSPlusCatalogFile cnoderec;
  533 
  534                         promoteattr(hfsmp, recp, &cnoderec);
  535                         getbsdattr(hfsmp, &cnoderec, attrp);
  536                 } else {
  537                         getbsdattr(hfsmp, (struct HFSPlusCatalogFile *)recp, attrp);
  538                         if (ilink)
  539                                 attrp->ca_rdev = ilink;
  540                 }
  541         }
  542         if (forkp != NULL) {
  543                 if (isadir(recp)) {
  544                         bzero(forkp, sizeof(*forkp));
  545                 } else if (std_hfs) {
  546                         promotefork(hfsmp, (HFSCatalogFile *)&recp->hfsFile, wantrsrc, forkp);
  547                 } else if (wantrsrc) {
  548                         /* Convert the resource fork. */
  549                         forkp->cf_size = recp->hfsPlusFile.resourceFork.logicalSize;
  550                         forkp->cf_blocks = recp->hfsPlusFile.resourceFork.totalBlocks;
  551                         if ((hfsmp->hfc_stage == HFC_RECORDING) &&
  552                             (to_bsd_time(recp->hfsPlusFile.accessDate) >= hfsmp->hfc_timebase)) {
  553                                 forkp->cf_bytesread =
  554                                         recp->hfsPlusFile.resourceFork.clumpSize *
  555                                         HFSTOVCB(hfsmp)->blockSize;
  556                         } else {
  557                                 forkp->cf_bytesread = 0;
  558                         }
  559                         forkp->cf_vblocks = 0;
  560                         bcopy(&recp->hfsPlusFile.resourceFork.extents[0],
  561                               &forkp->cf_extents[0], sizeof(HFSPlusExtentRecord));
  562                 } else {
  563                         /* Convert the data fork. */
  564                         forkp->cf_size = recp->hfsPlusFile.dataFork.logicalSize;
  565                         forkp->cf_blocks = recp->hfsPlusFile.dataFork.totalBlocks;
  566                         if ((hfsmp->hfc_stage == HFC_RECORDING) &&
  567                             (to_bsd_time(recp->hfsPlusFile.accessDate) >= hfsmp->hfc_timebase)) {
  568                                 forkp->cf_bytesread =
  569                                         recp->hfsPlusFile.dataFork.clumpSize *
  570                                         HFSTOVCB(hfsmp)->blockSize;
  571                         } else {
  572                                 forkp->cf_bytesread = 0;
  573                         }
  574                         forkp->cf_vblocks = 0;
  575                         bcopy(&recp->hfsPlusFile.dataFork.extents[0],
  576                               &forkp->cf_extents[0], sizeof(HFSPlusExtentRecord));
  577                 }
  578         }
  579         if (descp != NULL) {
  580                 HFSPlusCatalogKey * pluskey = NULL;
  581 
  582                 if (std_hfs) {
  583                         MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
  584                         promotekey(hfsmp, (HFSCatalogKey *)&iterator->key, pluskey, &encoding);
  585         
  586                 } else
  587                         pluskey = (HFSPlusCatalogKey *)&iterator->key;
  588 
  589                 builddesc(pluskey, cnid, hint, encoding, isadir(recp), descp);
  590                 if (std_hfs) {
  591                         FREE(pluskey, M_TEMP);
  592                 }
  593         }
  594 exit:
  595         FREE(iterator, M_TEMP);
  596         FREE(recp, M_TEMP);
  597 
  598         return MacToVFSError(result);
  599 }
  600 
  601 
  602 /*
  603  * cat_create - create a node in the catalog
  604  */
  605 __private_extern__
  606 int
  607 cat_create(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp,
  608         struct cat_desc *out_descp)
  609 {
  610         ExtendedVCB * vcb;
  611         FCB * fcb;
  612         struct btobj * bto;
  613         FSBufferDescriptor btdata;
  614         u_int32_t nextCNID;
  615         u_int32_t datalen;
  616         int std_hfs;
  617         int result;
  618         u_long encoding;
  619         int modeformat;
  620 
  621         modeformat = attrp->ca_mode & S_IFMT;
  622 
  623         vcb = HFSTOVCB(hfsmp);
  624         fcb = GetFileControlBlock(vcb->catalogRefNum);
  625         nextCNID = vcb->vcbNxtCNID;
  626         std_hfs = (vcb->vcbSigWord == kHFSSigWord);
  627 
  628         if (std_hfs && nextCNID == 0xFFFFFFFF)
  629                 return (ENOSPC);
  630 
  631         /* Get space for iterator, key and data */      
  632         MALLOC(bto, struct btobj *, sizeof(struct btobj), M_TEMP, M_WAITOK);
  633         bzero(bto, sizeof(struct btobj));
  634 
  635         result = buildkey(hfsmp, descp, &bto->key, 0);
  636         if (result)
  637                 goto exit;
  638 
  639         if (!std_hfs) {
  640                 encoding = hfs_pickencoding(bto->key.nodeName.unicode,
  641                         bto->key.nodeName.length);
  642                 hfs_setencodingbits(hfsmp, encoding);
  643         }
  644 
  645         /*
  646          * Insert the thread record first
  647          */
  648         if (!std_hfs || (modeformat == S_IFDIR)) {
  649                 datalen = buildthread((void*)&bto->key, &bto->data, std_hfs,
  650                                 S_ISDIR(attrp->ca_mode));
  651                 btdata.bufferAddress = &bto->data;
  652                 btdata.itemSize = datalen;
  653                 btdata.itemCount = 1;
  654                 
  655                 for (;;) {
  656                         buildthreadkey(nextCNID, std_hfs, (CatalogKey *) &bto->iterator.key);
  657 
  658                         result = BTInsertRecord(fcb, &bto->iterator, &btdata, datalen);
  659                         if (result == btExists && !std_hfs) {
  660                                 /*
  661                                  * Allow CNIDs on HFS Plus volumes to wrap around
  662                                  */
  663                                 ++nextCNID;
  664                                 if (nextCNID < kHFSFirstUserCatalogNodeID) {
  665                                         vcb->vcbAtrb |= kHFSCatalogNodeIDsReusedMask;
  666                                         vcb->vcbFlags |= 0xFF00;
  667                                         nextCNID = kHFSFirstUserCatalogNodeID;
  668                                 }
  669                                 continue;
  670                         }
  671                         break;
  672                 }
  673                 if (result) goto exit;
  674         }
  675 
  676         /*
  677          * Now insert the file/directory record
  678          */
  679         buildrecord(attrp, nextCNID, std_hfs, encoding, &bto->data, &datalen);
  680         btdata.bufferAddress = &bto->data;
  681         btdata.itemSize = datalen;
  682         btdata.itemCount = 1;
  683         
  684         bcopy(&bto->key, &bto->iterator.key, sizeof(bto->key));
  685 
  686         result = BTInsertRecord(fcb, &bto->iterator, &btdata, datalen);
  687         if (result) {
  688                 if (result == btExists)
  689                         result = EEXIST;
  690 
  691                 /* Back out the thread record */
  692                 if (!std_hfs || S_ISDIR(attrp->ca_mode)) {
  693                         buildthreadkey(nextCNID, std_hfs, (CatalogKey *)&bto->iterator.key);
  694                         (void) BTDeleteRecord(fcb, &bto->iterator);
  695                 }
  696                 goto exit;
  697         }
  698 
  699         /*
  700          * Insert was Successfull, update name, parent and volume
  701          */
  702 
  703 
  704         if (out_descp != NULL) {
  705                 HFSPlusCatalogKey * pluskey = NULL;
  706 
  707                 if (std_hfs) {
  708                         MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
  709                         promotekey(hfsmp, (HFSCatalogKey *)&bto->iterator.key, pluskey, &encoding);
  710         
  711                 } else
  712                         pluskey = (HFSPlusCatalogKey *)&bto->iterator.key;
  713 
  714                 builddesc(pluskey, nextCNID, bto->iterator.hint.nodeNum,
  715                         encoding, S_ISDIR(attrp->ca_mode), out_descp);
  716                 if (std_hfs) {
  717                         FREE(pluskey, M_TEMP);
  718                 }
  719         }
  720         attrp->ca_fileid = nextCNID;
  721 
  722         /* Update parent stats */
  723         TrashCatalogIterator(vcb, descp->cd_parentcnid);
  724         
  725         /* Update volume stats */
  726         if (++nextCNID < kHFSFirstUserCatalogNodeID) {
  727                 vcb->vcbAtrb |= kHFSCatalogNodeIDsReusedMask;
  728                 nextCNID = kHFSFirstUserCatalogNodeID;
  729         }
  730         vcb->vcbNxtCNID = nextCNID;
  731         vcb->vcbFlags |= 0xFF00;
  732 
  733 exit:
  734         (void) BTFlushPath(fcb);
  735         FREE(bto, M_TEMP);
  736 
  737         return MacToVFSError(result);
  738 }
  739 
  740 
  741 /*
  742  * cnode_rename - rename a catalog node
  743  *
  744  * Assumes that the target's directory exists.
  745  *
  746  * Order of B-tree operations:
  747  *      1. BTSearchRecord(from_cnode, &data);
  748  *      2. BTInsertRecord(to_cnode, &data);
  749  *      3. BTDeleteRecord(from_cnode);
  750  *      4. BTDeleteRecord(from_thread);
  751  *      5. BTInsertRecord(to_thread);
  752  */
  753 __private_extern__
  754 int 
  755 cat_rename (
  756         struct hfsmount * hfsmp,
  757         struct cat_desc * from_cdp,
  758         struct cat_desc * todir_cdp,
  759         struct cat_desc * to_cdp,
  760         struct cat_desc * out_cdp )
  761 {
  762         struct BTreeIterator * to_iterator = NULL;
  763         struct BTreeIterator * from_iterator = NULL;
  764         FSBufferDescriptor btdata;
  765         CatalogRecord * recp = NULL;
  766         HFSPlusCatalogKey * to_key;
  767         ExtendedVCB * vcb;
  768         FCB * fcb;
  769         UInt16  datasize;
  770         int result = 0;
  771         int sourcegone = 0;
  772         int skipthread = 0;
  773         int directory = from_cdp->cd_flags & CD_ISDIR;
  774         int std_hfs;
  775         u_long encoding = 0;
  776 
  777         vcb = HFSTOVCB(hfsmp);
  778         fcb = GetFileControlBlock(vcb->catalogRefNum);
  779         std_hfs = (vcb->vcbSigWord == kHFSSigWord);
  780 
  781         if (from_cdp->cd_namelen == 0 || to_cdp->cd_namelen == 0)
  782                 return (EINVAL);
  783 
  784         MALLOC(from_iterator, BTreeIterator *, sizeof(*from_iterator), M_TEMP, M_WAITOK);
  785         bzero(from_iterator, sizeof(*from_iterator));
  786         if ((result = buildkey(hfsmp, from_cdp, (HFSPlusCatalogKey *)&from_iterator->key, 0)))
  787                 goto exit;      
  788 
  789         MALLOC(to_iterator, BTreeIterator *, sizeof(*to_iterator), M_TEMP, M_WAITOK);
  790         bzero(to_iterator, sizeof(*to_iterator));
  791         if ((result = buildkey(hfsmp, to_cdp, (HFSPlusCatalogKey *)&to_iterator->key, 0)))
  792                 goto exit;      
  793 
  794         to_key = (HFSPlusCatalogKey *)&to_iterator->key;
  795         MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK);
  796         BDINIT(btdata, recp);
  797 
  798         /*
  799          * When moving a directory, make sure its a valid move.
  800          */
  801         if (directory && (from_cdp->cd_parentcnid != to_cdp->cd_parentcnid)) {
  802                 struct BTreeIterator iterator = {0};
  803                 cnid_t cnid = from_cdp->cd_cnid;
  804                 cnid_t pathcnid = todir_cdp->cd_parentcnid;
  805 
  806                 /* First check the obvious ones */
  807                 if (cnid == fsRtDirID  ||
  808                     cnid == to_cdp->cd_parentcnid  ||
  809                     cnid == pathcnid) {
  810                         result = EINVAL;
  811                         goto exit;
  812                 }
  813 
  814                 /*
  815                  * Traverese destination path all the way back to the root
  816                  * making sure that source directory is not encountered.
  817                  *
  818                  */
  819                 while (pathcnid > fsRtDirID) {
  820                         buildthreadkey(pathcnid, std_hfs,
  821                                         (CatalogKey *)&iterator.key);
  822                         result = BTSearchRecord(fcb, &iterator, &btdata,
  823                                         &datasize, NULL);
  824                         if (result) goto exit;
  825                         
  826                         pathcnid = getparentcnid(recp);
  827                         if (pathcnid == cnid) {
  828                                 result = EINVAL;
  829                                 goto exit;
  830                         }
  831                 }
  832         }
  833 
  834         /*
  835          * Step 1: Find cnode data at old location
  836          */
  837         result = BTSearchRecord(fcb, from_iterator, &btdata,
  838                                 &datasize, from_iterator);
  839         if (result)
  840                 goto exit;
  841 
  842         /* Update the text encoding (on disk and in descriptor) */
  843         if (!std_hfs) {
  844                 encoding = hfs_pickencoding(to_key->nodeName.unicode,
  845                                 to_key->nodeName.length);
  846                 hfs_setencodingbits(hfsmp, encoding);
  847                 recp->hfsPlusFile.textEncoding = encoding;
  848                 if (out_cdp)
  849                         out_cdp->cd_encoding = encoding;
  850         }
  851         
  852         if (std_hfs && !directory &&
  853             !(recp->hfsFile.flags & kHFSThreadExistsMask))
  854                 skipthread = 1;
  855 #if 0
  856         /*
  857          * If the keys are identical then there's nothing left to do!
  858          *
  859          * update the hint and exit
  860          *
  861          */
  862         if (std_hfs && hfskeycompare(to_key, iter->key) == 0)
  863                 goto exit;      
  864         if (!std_hfs && hfspluskeycompare(to_key, iter->key) == 0)
  865                 goto exit;      
  866 #endif
  867 
  868         /* Trash the iterator caches */
  869         TrashCatalogIterator(vcb, from_cdp->cd_parentcnid);
  870         if (from_cdp->cd_parentcnid != to_cdp->cd_parentcnid)
  871                 TrashCatalogIterator(vcb, to_cdp->cd_parentcnid);
  872 
  873         /* Step 2: Insert cnode at new location */
  874         result = BTInsertRecord(fcb, to_iterator, &btdata, datasize);
  875         if (result == btExists) {
  876                 int fromtype = recp->recordType;
  877 
  878                 if (from_cdp->cd_parentcnid != to_cdp->cd_parentcnid)
  879                         goto exit; /* EEXIST */
  880 
  881                 /* Find cnode data at new location */
  882                 result = BTSearchRecord(fcb, to_iterator, &btdata, &datasize, NULL);
  883                 
  884                 if ((fromtype != recp->recordType) ||
  885                     (from_cdp->cd_cnid != getcnid(recp)))
  886                         goto exit; /* EEXIST */
  887                 
  888                 /* The old name is a case variant and must be removed */
  889                 result = BTDeleteRecord(fcb, from_iterator);
  890                 if (result)
  891                         goto exit;
  892 
  893                 /* Insert cnode (now that case duplicate is gone) */
  894                 result = BTInsertRecord(fcb, to_iterator, &btdata, datasize);
  895                 if (result) {
  896                         /* Try and restore original before leaving */
  897                     // XXXdbg
  898                     #if 1
  899                        {
  900                         int err;
  901                         err = BTInsertRecord(fcb, from_iterator, &btdata, datasize);
  902                         if (err)
  903                                 panic("cat_create: could not undo (BTInsert = %d)", err);
  904                        }
  905                     #else
  906                         (void) BTInsertRecord(fcb, from_iterator, &btdata, datasize);
  907                     #endif
  908                         goto exit;
  909                 }
  910                 sourcegone = 1;
  911         }
  912         if (result)
  913                 goto exit;
  914 
  915         /* Step 3: Remove cnode from old location */
  916         if (!sourcegone) {
  917                 result = BTDeleteRecord(fcb, from_iterator);
  918                 if (result) {
  919                         /* Try and delete new record before leaving */
  920                   // XXXdbg
  921                   #if 1
  922                      {
  923                         int err;
  924                         err = BTDeleteRecord(fcb, to_iterator);
  925                         if (err)
  926                                 panic("cat_create: could not undo (BTDelete = %d)", err);
  927                      }                  
  928                   #else
  929                         (void) BTDeleteRecord(fcb, to_iterator);
  930                   #endif
  931                         goto exit;
  932                 }
  933         }
  934 
  935         /* #### POINT OF NO RETURN #### */
  936 
  937         /*
  938          * Step 4: Remove cnode's old thread record
  939          */
  940         buildthreadkey(from_cdp->cd_cnid, std_hfs, (CatalogKey *)&from_iterator->key);
  941         (void) BTDeleteRecord(fcb, from_iterator);
  942 
  943         /*
  944          * Step 5: Insert cnode's new thread record
  945          * (optional for HFS files)
  946          */
  947         if (!skipthread) {
  948                 datasize = buildthread(&to_iterator->key, recp, std_hfs, directory);
  949                 btdata.itemSize = datasize;
  950                 buildthreadkey(from_cdp->cd_cnid, std_hfs, (CatalogKey *)&from_iterator->key);
  951                 result = BTInsertRecord(fcb, from_iterator, &btdata, datasize);
  952         }
  953 
  954         if (out_cdp) {
  955                 HFSPlusCatalogKey * pluskey = NULL;
  956 
  957                 if (std_hfs) {
  958                         MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
  959                         promotekey(hfsmp, (HFSCatalogKey *)&to_iterator->key, pluskey, &encoding);
  960 
  961                         /* Save the real encoding hint in the Finder Info (field 4). */
  962                         if (directory && from_cdp->cd_cnid == kHFSRootFolderID) {
  963                                 u_long realhint;
  964 
  965                                 realhint = hfs_pickencoding(pluskey->nodeName.unicode, pluskey->nodeName.length);
  966                                 vcb->vcbFndrInfo[4] = SET_HFS_TEXT_ENCODING(realhint);
  967                         }
  968         
  969                 } else
  970                         pluskey = (HFSPlusCatalogKey *)&to_iterator->key;
  971 
  972                 builddesc(pluskey, from_cdp->cd_cnid, to_iterator->hint.nodeNum,
  973                         encoding, directory, out_cdp);
  974                 if (std_hfs) {
  975                         FREE(pluskey, M_TEMP);
  976                 }
  977         }
  978 exit:
  979         (void) BTFlushPath(fcb);
  980         if (from_iterator)
  981                 FREE(from_iterator, M_TEMP);
  982         if (to_iterator)
  983                 FREE(to_iterator, M_TEMP);
  984         if (recp)
  985                 FREE(recp, M_TEMP);
  986         return MacToVFSError(result);
  987 }
  988 
  989 
  990 /*
  991  * cat_delete - delete a node from the catalog
  992  *
  993  * Order of B-tree operations:
  994  *      1. BTDeleteRecord(cnode);
  995  *      2. BTDeleteRecord(thread);
  996  *      3. BTUpdateRecord(parent);
  997  */
  998 __private_extern__
  999 int
 1000 cat_delete(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp)
 1001 {
 1002         ExtendedVCB * vcb;
 1003         FCB * fcb;
 1004         BTreeIterator *iterator;
 1005         cnid_t cnid;
 1006         int std_hfs;
 1007         int result;
 1008 
 1009         vcb = HFSTOVCB(hfsmp);
 1010         fcb = GetFileControlBlock(vcb->catalogRefNum);
 1011         std_hfs = (vcb->vcbSigWord == kHFSSigWord);
 1012 
 1013         /* Preflight check:
 1014          *
 1015          * The root directory cannot be deleted
 1016          * A directory must be empty
 1017          * A file must be zero length (no blocks)
 1018          */
 1019         if (descp->cd_cnid < kHFSFirstUserCatalogNodeID ||
 1020             descp->cd_parentcnid == kRootParID)
 1021                 return (EINVAL);
 1022 
 1023         /* XXX Preflight Missing */
 1024         
 1025         /* Get space for iterator */    
 1026         MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
 1027         bzero(iterator, sizeof(*iterator));
 1028 
 1029         /*
 1030          * Derive a key from either the file ID (for a virtual inode)
 1031          * or the descriptor.
 1032          */
 1033         if (descp->cd_namelen == 0) {
 1034                 result = getkey(hfsmp, attrp->ca_fileid, (CatalogKey *)&iterator->key);
 1035                 cnid = attrp->ca_fileid;
 1036         } else {
 1037                 result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)&iterator->key, 0);
 1038                 cnid = descp->cd_cnid;
 1039         }
 1040         if (result)
 1041                 goto exit;
 1042 
 1043         /* Delete record */
 1044         result = BTDeleteRecord(fcb, iterator);
 1045         if (result)
 1046                 goto exit;
 1047 
 1048         /* Delete thread record, ignore errors */
 1049         buildthreadkey(cnid, std_hfs, (CatalogKey *)&iterator->key);
 1050         (void) BTDeleteRecord(fcb, iterator);
 1051 
 1052         TrashCatalogIterator(vcb, descp->cd_parentcnid);
 1053 
 1054 exit:
 1055         (void) BTFlushPath(fcb);
 1056         FREE(iterator, M_TEMP);
 1057 
 1058         return MacToVFSError(result);
 1059 }
 1060 
 1061 
 1062 /*
 1063  * cnode_update - update the catalog node described by descp
 1064  * using the data from attrp and forkp.
 1065  */
 1066 __private_extern__
 1067 int
 1068 cat_update(struct hfsmount *hfsmp, struct cat_desc *descp, struct cat_attr *attrp,
 1069         struct cat_fork *dataforkp, struct cat_fork *rsrcforkp)
 1070 {
 1071         ExtendedVCB * vcb;
 1072         FCB * fcb;
 1073         BTreeIterator * iterator;
 1074         struct update_state state;
 1075         int std_hfs;
 1076         int result;
 1077 
 1078         vcb = HFSTOVCB(hfsmp);
 1079         fcb = GetFileControlBlock(vcb->catalogRefNum);
 1080         std_hfs = (vcb->vcbSigWord == kHFSSigWord);
 1081 
 1082         state.s_desc = descp;
 1083         state.s_attr = attrp;
 1084         state.s_datafork = dataforkp;
 1085         state.s_rsrcfork = rsrcforkp;
 1086         state.s_hfsmp = hfsmp;
 1087 
 1088         /* Get space for iterator */    
 1089         MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
 1090         bzero(iterator, sizeof(*iterator));
 1091 
 1092         /*
 1093          * For open-deleted files we need to do a lookup by cnid
 1094          * (using thread rec).
 1095          *
 1096          * For hard links, the target of the update is the inode
 1097          * itself (not the link record) so a lookup by fileid
 1098          * (i.e. thread rec) is needed.
 1099          */
 1100         if ((descp->cd_cnid != attrp->ca_fileid) || (descp->cd_namelen == 0))
 1101                 result = getkey(hfsmp, attrp->ca_fileid, (CatalogKey *)&iterator->key);
 1102         else
 1103                 result = buildkey(hfsmp, descp, (HFSPlusCatalogKey *)&iterator->key, 0);
 1104         if (result)
 1105                 goto exit;
 1106 
 1107         /* Pass a node hint */
 1108         iterator->hint.nodeNum = descp->cd_hint;
 1109 
 1110         result = BTUpdateRecord(fcb, iterator,
 1111                                 (IterateCallBackProcPtr)catrec_update, &state);
 1112         if (result)
 1113                 goto exit;
 1114 
 1115         /* Update the node hint. */
 1116         descp->cd_hint = iterator->hint.nodeNum;
 1117 
 1118 exit:
 1119         (void) BTFlushPath(fcb);
 1120         FREE(iterator, M_TEMP);
 1121 
 1122         return MacToVFSError(result);
 1123 }
 1124 
 1125 /*
 1126  * catrec_update - Update the fields of a catalog record
 1127  * This is called from within BTUpdateRecord.
 1128  */
 1129 static int
 1130 catrec_update(const CatalogKey *ckp, CatalogRecord *crp, u_int16_t reclen,
 1131               struct update_state *state)
 1132 {
 1133         struct cat_desc *descp;
 1134         struct cat_attr *attrp;
 1135         struct cat_fork *forkp;
 1136         struct hfsmount *hfsmp;
 1137         long blksize;
 1138         int i;
 1139 
 1140         descp   = state->s_desc;
 1141         attrp   = state->s_attr;
 1142         hfsmp   = state->s_hfsmp;
 1143         blksize = HFSTOVCB(hfsmp)->blockSize;
 1144 
 1145         switch (crp->recordType) {
 1146         case kHFSFolderRecord: {
 1147                 HFSCatalogFolder *dir;
 1148                 
 1149                 dir = (struct HFSCatalogFolder *)crp;
 1150                 /* Do a quick sanity check */
 1151                 if ((ckp->hfs.parentID != descp->cd_parentcnid) ||
 1152                     (dir->folderID != descp->cd_cnid))
 1153                         return (btNotFound);
 1154                 dir->valence    = attrp->ca_entries;
 1155                 dir->createDate = UTCToLocal(to_hfs_time(attrp->ca_itime));
 1156                 dir->modifyDate = UTCToLocal(to_hfs_time(attrp->ca_mtime));
 1157                 dir->backupDate = UTCToLocal(to_hfs_time(attrp->ca_btime));
 1158                 bcopy(&attrp->ca_finderinfo[0], &dir->userInfo, 16);
 1159                 bcopy(&attrp->ca_finderinfo[16], &dir->finderInfo, 16);
 1160                 break;
 1161         }
 1162         case kHFSFileRecord: {
 1163                 HFSCatalogFile *file;
 1164                 
 1165                 file = (struct HFSCatalogFile *)crp;
 1166                 /* Do a quick sanity check */
 1167                 if ((ckp->hfs.parentID != descp->cd_parentcnid) ||
 1168                     (file->fileID != attrp->ca_fileid))
 1169                         return (btNotFound);
 1170                 file->createDate = UTCToLocal(to_hfs_time(attrp->ca_itime));
 1171                 file->modifyDate = UTCToLocal(to_hfs_time(attrp->ca_mtime));
 1172                 file->backupDate = UTCToLocal(to_hfs_time(attrp->ca_btime));
 1173                 bcopy(&attrp->ca_finderinfo[0], &file->userInfo, 16);
 1174                 bcopy(&attrp->ca_finderinfo[16], &file->finderInfo, 16);
 1175                 if (state->s_rsrcfork) {
 1176                         forkp = state->s_rsrcfork;
 1177                         file->rsrcLogicalSize  = forkp->cf_size;
 1178                         file->rsrcPhysicalSize = forkp->cf_blocks * blksize;
 1179                         for (i = 0; i < kHFSExtentDensity; ++i) {
 1180                                 file->rsrcExtents[i].startBlock =
 1181                                         (u_int16_t)forkp->cf_extents[i].startBlock;
 1182                                 file->rsrcExtents[i].blockCount =
 1183                                         (u_int16_t)forkp->cf_extents[i].blockCount;
 1184                         }
 1185                 }
 1186                 if (state->s_datafork) {
 1187                         forkp = state->s_datafork;
 1188                         file->dataLogicalSize  = forkp->cf_size;
 1189                         file->dataPhysicalSize = forkp->cf_blocks * blksize;
 1190                         for (i = 0; i < kHFSExtentDensity; ++i) {
 1191                                 file->dataExtents[i].startBlock =
 1192                                         (u_int16_t)forkp->cf_extents[i].startBlock;
 1193                                 file->dataExtents[i].blockCount =
 1194                                         (u_int16_t)forkp->cf_extents[i].blockCount;
 1195                         }
 1196                 }
 1197                 break;
 1198         }
 1199         case kHFSPlusFolderRecord: {
 1200                 HFSPlusCatalogFolder *dir;
 1201                 
 1202                 dir = (struct HFSPlusCatalogFolder *)crp;
 1203                 /* Do a quick sanity check */
 1204                 if ((ckp->hfsPlus.parentID != descp->cd_parentcnid) ||
 1205                         (dir->folderID != descp->cd_cnid))
 1206                         return (btNotFound);
 1207                 dir->valence          = attrp->ca_entries;
 1208                 dir->createDate       = to_hfs_time(attrp->ca_itime);
 1209                 dir->contentModDate   = to_hfs_time(attrp->ca_mtime);
 1210                 dir->backupDate       = to_hfs_time(attrp->ca_btime);
 1211                 dir->accessDate       = to_hfs_time(attrp->ca_atime);
 1212                 dir->attributeModDate = to_hfs_time(attrp->ca_ctime);
 1213                 dir->textEncoding     = descp->cd_encoding;
 1214                 bcopy(&attrp->ca_finderinfo[0], &dir->userInfo, 32);
 1215                 /*
 1216                  * Update the BSD Info if it was already initialized on
 1217                  * disk or if the runtime values have been modified.
 1218                  *
 1219                  * If the BSD info was already initialized, but
 1220                  * MNT_UNKNOWNPERMISSIONS is set, then the runtime IDs are
 1221                  * probably different than what was on disk.  We don't want
 1222                  * to overwrite the on-disk values (so if we turn off
 1223                  * MNT_UNKNOWNPERMISSIONS, the old IDs get used again).
 1224                  * This way, we can still change fields like the mode or
 1225                  * dates even when MNT_UNKNOWNPERMISSIONS is set.
 1226                  *
 1227                  * Note that if MNT_UNKNOWNPERMISSIONS is set, hfs_chown
 1228                  * won't change the uid or gid from their defaults.  So, if
 1229                  * the BSD info wasn't set, and the runtime values are not
 1230                  * default, then what changed was the mode or flags.  We
 1231                  * have to set the uid and gid to something, so use the
 1232                  * supplied values (which will be default), which has the
 1233                  * same effect as creating a new file while
 1234                  * MNT_UNKNOWNPERMISSIONS is set.
 1235                  */
 1236                 if ((dir->bsdInfo.fileMode != 0) ||
 1237                     (attrp->ca_flags != 0) ||
 1238                     (attrp->ca_uid != hfsmp->hfs_uid) ||
 1239                     (attrp->ca_gid != hfsmp->hfs_gid) ||
 1240                     ((attrp->ca_mode & ALLPERMS) !=
 1241                      (hfsmp->hfs_dir_mask & ACCESSPERMS))) {
 1242                         if ((dir->bsdInfo.fileMode == 0) ||
 1243                             (HFSTOVFS(hfsmp)->mnt_flag &
 1244                              MNT_UNKNOWNPERMISSIONS) == 0) {
 1245                                 dir->bsdInfo.ownerID = attrp->ca_uid;
 1246                                 dir->bsdInfo.groupID = attrp->ca_gid;
 1247                         }
 1248                         dir->bsdInfo.ownerFlags = attrp->ca_flags & 0x000000FF;
 1249                         dir->bsdInfo.adminFlags = attrp->ca_flags >> 16;
 1250                         dir->bsdInfo.fileMode   = attrp->ca_mode;
 1251                 }
 1252                 break;
 1253         }
 1254         case kHFSPlusFileRecord: {
 1255                 HFSPlusCatalogFile *file;
 1256                 
 1257                 file = (struct HFSPlusCatalogFile *)crp;
 1258                 /* Do a quick sanity check */
 1259                 if (file->fileID != attrp->ca_fileid)
 1260                         return (btNotFound);
 1261                 file->createDate       = to_hfs_time(attrp->ca_itime);
 1262                 file->contentModDate   = to_hfs_time(attrp->ca_mtime);
 1263                 file->backupDate       = to_hfs_time(attrp->ca_btime);
 1264                 file->accessDate       = to_hfs_time(attrp->ca_atime);
 1265                 file->attributeModDate = to_hfs_time(attrp->ca_ctime);
 1266                 file->textEncoding     = descp->cd_encoding;
 1267                 bcopy(&attrp->ca_finderinfo[0], &file->userInfo, 32);
 1268                 /*
 1269                  * Update the BSD Info if it was already initialized on
 1270                  * disk or if the runtime values have been modified.
 1271                  *
 1272                  * If the BSD info was already initialized, but
 1273                  * MNT_UNKNOWNPERMISSIONS is set, then the runtime IDs are
 1274                  * probably different than what was on disk.  We don't want
 1275                  * to overwrite the on-disk values (so if we turn off
 1276                  * MNT_UNKNOWNPERMISSIONS, the old IDs get used again).
 1277                  * This way, we can still change fields like the mode or
 1278                  * dates even when MNT_UNKNOWNPERMISSIONS is set.
 1279                  *
 1280                  * Note that if MNT_UNKNOWNPERMISSIONS is set, hfs_chown
 1281                  * won't change the uid or gid from their defaults.  So, if
 1282                  * the BSD info wasn't set, and the runtime values are not
 1283                  * default, then what changed was the mode or flags.  We
 1284                  * have to set the uid and gid to something, so use the
 1285                  * supplied values (which will be default), which has the
 1286                  * same effect as creating a new file while
 1287                  * MNT_UNKNOWNPERMISSIONS is set.
 1288                  */
 1289                 if ((file->bsdInfo.fileMode != 0) ||
 1290                     (attrp->ca_flags != 0) ||
 1291                     (attrp->ca_uid != hfsmp->hfs_uid) ||
 1292                     (attrp->ca_gid != hfsmp->hfs_gid) ||
 1293                     ((attrp->ca_mode & ALLPERMS) !=
 1294                      (hfsmp->hfs_file_mask & ACCESSPERMS))) {
 1295                         if ((file->bsdInfo.fileMode == 0) ||
 1296                             (HFSTOVFS(hfsmp)->mnt_flag &
 1297                              MNT_UNKNOWNPERMISSIONS) == 0) {
 1298                                 file->bsdInfo.ownerID = attrp->ca_uid;
 1299                                 file->bsdInfo.groupID = attrp->ca_gid;
 1300                         }
 1301                         file->bsdInfo.ownerFlags = attrp->ca_flags & 0x000000FF;
 1302                         file->bsdInfo.adminFlags = attrp->ca_flags >> 16;
 1303                         file->bsdInfo.fileMode   = attrp->ca_mode;
 1304                 }
 1305                 if (state->s_rsrcfork) {
 1306                         forkp = state->s_rsrcfork;
 1307                         file->resourceFork.logicalSize = forkp->cf_size;
 1308                         file->resourceFork.totalBlocks = forkp->cf_blocks;
 1309                         bcopy(&forkp->cf_extents[0], &file->resourceFork.extents,
 1310                                 sizeof(HFSPlusExtentRecord));
 1311                         /* Push blocks read to disk */
 1312                         file->resourceFork.clumpSize =
 1313                                         howmany(forkp->cf_bytesread, blksize);
 1314                 }
 1315                 if (state->s_datafork) {
 1316                         forkp = state->s_datafork;
 1317                         file->dataFork.logicalSize = forkp->cf_size;
 1318                         file->dataFork.totalBlocks = forkp->cf_blocks;
 1319                         bcopy(&forkp->cf_extents[0], &file->dataFork.extents,
 1320                                 sizeof(HFSPlusExtentRecord));
 1321                         /* Push blocks read to disk */
 1322                         file->resourceFork.clumpSize =
 1323                                         howmany(forkp->cf_bytesread, blksize);
 1324                 }
 1325 
 1326                 if ((file->resourceFork.extents[0].startBlock != 0) &&
 1327                     (file->resourceFork.extents[0].startBlock ==
 1328                      file->dataFork.extents[0].startBlock))
 1329                         panic("catrec_update: rsrc fork == data fork");
 1330 
 1331                 /* Synchronize the lock state */
 1332                 if (attrp->ca_flags & (SF_IMMUTABLE | UF_IMMUTABLE))
 1333                         file->flags |= kHFSFileLockedMask;
 1334                 else
 1335                         file->flags &= ~kHFSFileLockedMask;
 1336 
 1337                 /* Push out special field if necessary */
 1338                 if (S_ISBLK(attrp->ca_mode) || S_ISCHR(attrp->ca_mode))
 1339                         file->bsdInfo.special.rawDevice = attrp->ca_rdev;
 1340                 else if (descp->cd_cnid != attrp->ca_fileid
 1341                      ||  attrp->ca_nlink == 2)
 1342                         file->bsdInfo.special.linkCount = attrp->ca_nlink;
 1343                 break;
 1344         }
 1345         default:
 1346                 return (btNotFound);
 1347         }
 1348         return (0);
 1349 }
 1350 
 1351 /*
 1352  * catrec_readattr - 
 1353  * This is called from within BTIterateRecords.
 1354  */
 1355 struct readattr_state {
 1356         struct hfsmount *hfsmp;
 1357         struct cat_entrylist *list;
 1358         cnid_t  dir_cnid;
 1359         int stdhfs;
 1360         int error;
 1361 };
 1362 
 1363 static int
 1364 catrec_readattr(const CatalogKey *key, const CatalogRecord *rec,
 1365                 u_long node, struct readattr_state *state)
 1366 {
 1367         struct cat_entrylist *list = state->list;
 1368         struct hfsmount *hfsmp = state->hfsmp;
 1369         struct cat_entry *cep;
 1370         cnid_t parentcnid;
 1371 
 1372         if (list->realentries >= list->maxentries)
 1373                 return (0);  /* stop */
 1374         
 1375         parentcnid = state->stdhfs ? key->hfs.parentID : key->hfsPlus.parentID;
 1376 
 1377         switch(rec->recordType) {
 1378         case kHFSPlusFolderRecord:
 1379         case kHFSPlusFileRecord:
 1380         case kHFSFolderRecord:
 1381         case kHFSFileRecord:
 1382                 if (parentcnid != state->dir_cnid) {
 1383                         state->error = ENOENT;
 1384                         return (0);     /* stop */
 1385                 }
 1386                 break;
 1387         default:
 1388                 state->error = ENOENT;
 1389                 return (0);     /* stop */
 1390         }
 1391 
 1392         /* Hide the private meta data directory and journal files */
 1393         if (parentcnid == kRootDirID) {
 1394                 if ((rec->recordType == kHFSPlusFolderRecord) &&
 1395                     (rec->hfsPlusFolder.folderID == hfsmp->hfs_privdir_desc.cd_cnid)) {
 1396                         return (1);     /* continue */
 1397                 }
 1398                 if (hfsmp->jnl &&
 1399                     (rec->recordType == kHFSPlusFileRecord) &&
 1400                     ((rec->hfsPlusFile.fileID == hfsmp->hfs_jnlfileid) ||
 1401                      (rec->hfsPlusFile.fileID == hfsmp->hfs_jnlinfoblkid))) {
 1402 
 1403                         return (1);     /* continue */
 1404                 }
 1405         }
 1406 
 1407 
 1408         cep = &list->entry[list->realentries++];
 1409 
 1410         if (state->stdhfs) {
 1411                 struct HFSPlusCatalogFile cnoderec;
 1412                 HFSPlusCatalogKey * pluskey;
 1413                 long encoding;
 1414 
 1415                 promoteattr(hfsmp, rec, &cnoderec);
 1416                 getbsdattr(hfsmp, &cnoderec, &cep->ce_attr);
 1417 
 1418                 MALLOC(pluskey, HFSPlusCatalogKey *, sizeof(HFSPlusCatalogKey), M_TEMP, M_WAITOK);
 1419                 promotekey(hfsmp, (HFSCatalogKey *)key, pluskey, &encoding);
 1420                 builddesc(pluskey, getcnid(rec), node, encoding, isadir(rec), &cep->ce_desc);
 1421                 FREE(pluskey, M_TEMP);
 1422 
 1423                 if (rec->recordType == kHFSFileRecord) {
 1424                         int blksize = HFSTOVCB(hfsmp)->blockSize;
 1425 
 1426                         cep->ce_datasize = rec->hfsFile.dataLogicalSize;
 1427                         cep->ce_datablks = rec->hfsFile.dataPhysicalSize / blksize;
 1428                         cep->ce_rsrcsize = rec->hfsFile.rsrcLogicalSize;
 1429                         cep->ce_rsrcblks = rec->hfsFile.rsrcPhysicalSize / blksize;
 1430                 }
 1431         } else {
 1432                 getbsdattr(hfsmp, (struct HFSPlusCatalogFile *)rec, &cep->ce_attr);
 1433                 builddesc((HFSPlusCatalogKey *)key, getcnid(rec), node, getencoding(rec),
 1434                         isadir(rec), &cep->ce_desc);
 1435                 
 1436                 if (rec->recordType == kHFSPlusFileRecord) {
 1437                         cep->ce_datasize = rec->hfsPlusFile.dataFork.logicalSize;
 1438                         cep->ce_datablks = rec->hfsPlusFile.dataFork.totalBlocks;
 1439                         cep->ce_rsrcsize = rec->hfsPlusFile.resourceFork.logicalSize;
 1440                         cep->ce_rsrcblks = rec->hfsPlusFile.resourceFork.totalBlocks;
 1441                         
 1442                         /* Save link reference for later processing. */
 1443                         if ((SWAP_BE32(rec->hfsPlusFile.userInfo.fdType) == kHardLinkFileType)
 1444                         &&  (SWAP_BE32(rec->hfsPlusFile.userInfo.fdCreator) == kHFSPlusCreator))
 1445                                 cep->ce_attr.ca_rdev = rec->hfsPlusFile.bsdInfo.special.iNodeNum;
 1446                 }
 1447         }
 1448 
 1449         return (list->realentries < list->maxentries);
 1450 }
 1451 
 1452 /*
 1453  * Note: index is zero relative
 1454  */
 1455 __private_extern__
 1456 int
 1457 cat_getentriesattr(struct hfsmount *hfsmp, struct cat_desc *prevdesc, int index,
 1458                 struct cat_entrylist *ce_list)
 1459 {
 1460         FCB* fcb;
 1461         CatalogKey * key;
 1462         BTreeIterator * iterator;
 1463         struct readattr_state state;
 1464         cnid_t parentcnid;
 1465         int i;
 1466         int std_hfs;
 1467         int result = 0;
 1468 
 1469         ce_list->realentries = 0;
 1470 
 1471         fcb = GetFileControlBlock(HFSTOVCB(hfsmp)->catalogRefNum);
 1472         std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord);
 1473         parentcnid = prevdesc->cd_parentcnid;
 1474 
 1475         state.hfsmp = hfsmp;
 1476         state.list = ce_list;
 1477         state.dir_cnid = parentcnid;
 1478         state.stdhfs = std_hfs;
 1479         state.error = 0;
 1480 
 1481         MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
 1482         bzero(iterator, sizeof(*iterator));
 1483         key = (CatalogKey *)&iterator->key;
 1484         iterator->hint.nodeNum = prevdesc->cd_hint;
 1485 
 1486         /*
 1487          * If the last entry wasn't cached then establish the iterator
 1488          */
 1489         if ((index == 0) ||
 1490             (prevdesc->cd_namelen == 0) ||
 1491             (buildkey(hfsmp, prevdesc, (HFSPlusCatalogKey *)key, 0) != 0)) {
 1492                 int i;
 1493                 /*
 1494                  * Position the iterator at the directory thread.
 1495                  * (ie just before the first entry)
 1496                  */
 1497                 buildthreadkey(parentcnid, std_hfs, key);
 1498                 result = BTSearchRecord(fcb, iterator, NULL, NULL, iterator);
 1499                 if (result)
 1500                         goto exit;  /* bad news */
 1501                 /*
 1502                  * Iterate until we reach the entry just
 1503                  * before the one we want to start with.
 1504                  */
 1505                 for (i = 0; i < index; ++i) {
 1506                         result = BTIterateRecord(fcb, kBTreeNextRecord, iterator, NULL, NULL);
 1507                         if (result)
 1508                                 goto exit;  /* bad news */
 1509                 }
 1510         }
 1511 
 1512         /* Fill list with entries. */
 1513         result = BTIterateRecords(fcb, kBTreeNextRecord, iterator,
 1514                         (IterateCallBackProcPtr)catrec_readattr, &state);
 1515 
 1516         if (state.error)
 1517                 result = state.error;
 1518         else if (ce_list->realentries == 0)
 1519                 result = ENOENT;
 1520         else
 1521                 result = MacToVFSError(result);
 1522 
 1523         if (std_hfs)
 1524                 goto exit;
 1525 
 1526         /*
 1527          *  Resolve any hard links.
 1528          */
 1529         for (i = 0; i < ce_list->realentries; ++i) {
 1530                 struct FndrFileInfo *fip;
 1531                 struct cat_entry *cep;
 1532                 struct HFSPlusCatalogFile filerec;
 1533 
 1534                 cep = &ce_list->entry[i];
 1535                 if (!S_ISREG(cep->ce_attr.ca_mode))
 1536                         continue;
 1537         
 1538                 /* Note: Finder info is still in Big Endian */
 1539                 fip = (struct FndrFileInfo *)&cep->ce_attr.ca_finderinfo;
 1540 
 1541                 /* Check for hard link signature. */
 1542                 if ((cep->ce_attr.ca_rdev != 0)
 1543                 &&  (SWAP_BE32(fip->fdType) == kHardLinkFileType)
 1544                 &&  (SWAP_BE32(fip->fdCreator) == kHFSPlusCreator)
 1545                 &&  ((cep->ce_attr.ca_itime == HFSTOVCB(hfsmp)->vcbCrDate) ||
 1546                      (cep->ce_attr.ca_itime == hfsmp->hfs_metadata_createdate))) {
 1547 
 1548                         if (resolvelink(hfsmp, cep->ce_attr.ca_rdev, &filerec) != 0)
 1549                                 continue;
 1550                         /* Repack entry from inode record. */
 1551                         getbsdattr(hfsmp, &filerec, &cep->ce_attr);             
 1552                         cep->ce_datasize = filerec.dataFork.logicalSize;
 1553                         cep->ce_datablks = filerec.dataFork.totalBlocks;
 1554                         cep->ce_rsrcsize = filerec.resourceFork.logicalSize;
 1555                         cep->ce_rsrcblks = filerec.resourceFork.totalBlocks;
 1556                 }
 1557         }
 1558 exit:
 1559         FREE(iterator, M_TEMP);
 1560         
 1561         return MacToVFSError(result);
 1562 }
 1563 
 1564 struct linkinfo {
 1565         u_long  link_ref;
 1566         void *  dirent_addr;
 1567 };
 1568 
 1569 struct read_state {
 1570         u_int32_t       cbs_parentID;
 1571         u_int32_t       cbs_hiddenDirID;
 1572         u_int32_t       cbs_hiddenJournalID;
 1573         u_int32_t       cbs_hiddenInfoBlkID;
 1574         off_t           cbs_lastoffset;
 1575         struct uio *    cbs_uio;
 1576         ExtendedVCB *   cbs_vcb;
 1577         int8_t          cbs_hfsPlus;
 1578         int8_t          cbs_case_sensitive;
 1579         int16_t         cbs_result;
 1580         int32_t         cbs_numresults;
 1581         u_long         *cbs_cookies;
 1582         int32_t         cbs_ncookies;
 1583         int32_t         cbs_nlinks;
 1584         int32_t         cbs_maxlinks;
 1585         struct linkinfo *cbs_linkinfo;
 1586 };
 1587 
 1588 /* Map file mode type to directory entry types */
 1589 u_char modetodirtype[16] = {
 1590         DT_REG, DT_FIFO, DT_CHR, DT_UNKNOWN,
 1591         DT_DIR, DT_UNKNOWN, DT_BLK, DT_UNKNOWN,
 1592         DT_REG, DT_UNKNOWN, DT_LNK, DT_UNKNOWN,
 1593         DT_SOCK, DT_UNKNOWN, DT_WHT, DT_UNKNOWN
 1594 };
 1595 
 1596 #define MODE_TO_DT(mode)  (modetodirtype[((mode) & S_IFMT) >> 12])
 1597 
 1598 static int
 1599 catrec_read(const CatalogKey *ckp, const CatalogRecord *crp,
 1600                     u_int16_t recordLen, struct read_state *state)
 1601 {
 1602         struct hfsmount *hfsmp;
 1603         CatalogName *cnp;
 1604         size_t utf8chars;
 1605         u_int32_t curID;
 1606         OSErr result;
 1607         struct dirent catent;
 1608         time_t itime;
 1609         u_long ilinkref = 0;
 1610         void * uiobase;
 1611         
 1612         if (state->cbs_hfsPlus)
 1613                 curID = ckp->hfsPlus.parentID;
 1614         else
 1615                 curID = ckp->hfs.parentID;
 1616 
 1617         /* We're done when parent directory changes */
 1618         if (state->cbs_parentID != curID) {
 1619 lastitem:
 1620 /*
 1621  * The NSDirectoryList class chokes on empty records (it doesnt check d_reclen!)
 1622  * so remove padding for now...
 1623  */
 1624 #if 0
 1625                 /*
 1626                  * Pad the end of list with an empty record.
 1627                  * This eliminates an extra call by readdir(3c).
 1628                  */
 1629                 catent.d_fileno = 0;
 1630                 catent.d_reclen = 0;
 1631                 catent.d_type = 0;
 1632                 catent.d_namlen = 0;
 1633                 *(int32_t*)&catent.d_name[0] = 0;
 1634 
 1635                 state->cbs_lastoffset = state->cbs_uio->uio_offset;
 1636 
 1637                 state->cbs_result = uiomove((caddr_t) &catent, 12, state->cbs_uio);
 1638                 if (state->cbs_result == 0)
 1639                         state->cbs_result = ENOENT;
 1640 #else
 1641                 state->cbs_lastoffset = state->cbs_uio->uio_offset;
 1642                 state->cbs_result = ENOENT;
 1643 #endif
 1644                 return (0);     /* stop */
 1645         }
 1646 
 1647         if (state->cbs_hfsPlus) {
 1648                 switch(crp->recordType) {
 1649                 case kHFSPlusFolderRecord:
 1650                         catent.d_type = DT_DIR;
 1651                         catent.d_fileno = crp->hfsPlusFolder.folderID;
 1652                         break;
 1653                 case kHFSPlusFileRecord:
 1654                         itime = to_bsd_time(crp->hfsPlusFile.createDate);
 1655                         hfsmp = VCBTOHFS(state->cbs_vcb);
 1656                         /*
 1657                          * When a hardlink link is encountered save its link ref.
 1658                          */
 1659                         if ((SWAP_BE32(crp->hfsPlusFile.userInfo.fdType) == kHardLinkFileType) &&
 1660                             (SWAP_BE32(crp->hfsPlusFile.userInfo.fdCreator) == kHFSPlusCreator) &&
 1661                             ((itime == state->cbs_vcb->vcbCrDate) ||
 1662                              (itime == hfsmp->hfs_metadata_createdate))) {
 1663                                 ilinkref = crp->hfsPlusFile.bsdInfo.special.iNodeNum;
 1664                         }
 1665                         catent.d_type = MODE_TO_DT(crp->hfsPlusFile.bsdInfo.fileMode);
 1666                         catent.d_fileno = crp->hfsPlusFile.fileID;
 1667                         break;
 1668                 default:
 1669                         return (0);     /* stop */
 1670                 };
 1671 
 1672                 cnp = (CatalogName*) &ckp->hfsPlus.nodeName;
 1673                 result = utf8_encodestr(cnp->ustr.unicode, cnp->ustr.length * sizeof(UniChar),
 1674                                 catent.d_name, &utf8chars, kdirentMaxNameBytes + 1, ':', 0);
 1675                 if (result == ENAMETOOLONG) {
 1676                         result = ConvertUnicodeToUTF8Mangled(cnp->ustr.length * sizeof(UniChar),
 1677                                 cnp->ustr.unicode, kdirentMaxNameBytes + 1, (ByteCount*)&utf8chars, catent.d_name, catent.d_fileno);            
 1678                 }
 1679         } else { /* hfs */
 1680                 switch(crp->recordType) {
 1681                 case kHFSFolderRecord:
 1682                         catent.d_type = DT_DIR;
 1683                         catent.d_fileno = crp->hfsFolder.folderID;
 1684                         break;
 1685                 case kHFSFileRecord:
 1686                         catent.d_type = DT_REG;
 1687                         catent.d_fileno = crp->hfsFile.fileID;
 1688                         break;
 1689                 default:
 1690                         return (0);     /* stop */
 1691                 };
 1692 
 1693                 cnp = (CatalogName*) ckp->hfs.nodeName;
 1694                 result = hfs_to_utf8(state->cbs_vcb, cnp->pstr, kdirentMaxNameBytes + 1,
 1695                                     (ByteCount *)&utf8chars, catent.d_name);
 1696                 /*
 1697                  * When an HFS name cannot be encoded with the current
 1698                  * volume encoding we use MacRoman as a fallback.
 1699                  */
 1700                 if (result)
 1701                         result = mac_roman_to_utf8(cnp->pstr, kdirentMaxNameBytes + 1,
 1702                                     (ByteCount *)&utf8chars, catent.d_name);
 1703         }
 1704 
 1705         catent.d_namlen = utf8chars;
 1706         catent.d_reclen = DIRENTRY_SIZE(utf8chars);
 1707         
 1708         /* hide our private meta data directory */
 1709         if (curID == kRootDirID                         &&
 1710             catent.d_fileno == state->cbs_hiddenDirID   &&
 1711             catent.d_type == DT_DIR) {
 1712                 if (state->cbs_case_sensitive) {
 1713                         // This is how we skip over these entries.  The next
 1714                         // time we fill in a real item the uio_offset will
 1715                         // point to the correct place in the "virtual" directory
 1716                         // so that PositionIterator() will do the right thing
 1717                         // when scanning to get to a particular position in the
 1718                         // directory.
 1719                         state->cbs_uio->uio_offset += catent.d_reclen;
 1720                         state->cbs_lastoffset = state->cbs_uio->uio_offset;
 1721 
 1722                         return (1);     /* skip and continue */
 1723                 } else
 1724                         goto lastitem;
 1725         }
 1726         
 1727         /* Hide the journal files */
 1728         if ((curID == kRootDirID) &&
 1729             (catent.d_type == DT_REG) &&
 1730             ((catent.d_fileno == state->cbs_hiddenJournalID) ||
 1731              (catent.d_fileno == state->cbs_hiddenInfoBlkID))) {
 1732 
 1733                 // see comment up above for why this is here
 1734                 state->cbs_uio->uio_offset += catent.d_reclen;
 1735                 state->cbs_lastoffset = state->cbs_uio->uio_offset;
 1736 
 1737                 return (1);     /* skip and continue */
 1738         }
 1739 
 1740         state->cbs_lastoffset = state->cbs_uio->uio_offset;
 1741         uiobase = state->cbs_uio->uio_iov->iov_base;
 1742 
 1743         /* if this entry won't fit then we're done */
 1744         if (catent.d_reclen > state->cbs_uio->uio_resid ||
 1745             (ilinkref != 0 && state->cbs_nlinks == state->cbs_maxlinks) ||
 1746             (state->cbs_ncookies != 0 && state->cbs_numresults >= state->cbs_ncookies))
 1747                 return (0);     /* stop */
 1748 
 1749         state->cbs_result = uiomove((caddr_t) &catent, catent.d_reclen, state->cbs_uio);
 1750 
 1751         /*
 1752          * Record any hard links for post processing.
 1753          */
 1754         if ((ilinkref != 0) &&
 1755             (state->cbs_result == 0) &&
 1756             (state->cbs_nlinks < state->cbs_maxlinks)) {
 1757                 state->cbs_linkinfo[state->cbs_nlinks].dirent_addr = uiobase;
 1758                 state->cbs_linkinfo[state->cbs_nlinks].link_ref = ilinkref;
 1759                 state->cbs_nlinks++;
 1760         }
 1761 
 1762         if (state->cbs_cookies) {
 1763             state->cbs_cookies[state->cbs_numresults++] = state->cbs_uio->uio_offset;
 1764         } else {
 1765             state->cbs_numresults++;
 1766         }
 1767 
 1768         /* continue iteration if there's room */
 1769         return (state->cbs_result == 0  &&
 1770                 state->cbs_uio->uio_resid >= AVERAGE_HFSDIRENTRY_SIZE);
 1771 }
 1772 
 1773 #define SMALL_DIRENTRY_SIZE  (sizeof(struct dirent) - (MAXNAMLEN + 1) + 8)
 1774 /*
 1775  *
 1776  */
 1777 __private_extern__
 1778 int
 1779 cat_getdirentries(struct hfsmount *hfsmp, struct cat_desc *descp, int entrycnt,
 1780                 struct uio *uio, int *eofflag, u_long *cookies, int ncookies)
 1781 {
 1782         ExtendedVCB *vcb = HFSTOVCB(hfsmp);
 1783         BTreeIterator * iterator;
 1784         CatalogIterator *cip;
 1785         u_int32_t diroffset;
 1786         u_int16_t op;
 1787         struct read_state state;
 1788         u_int32_t dirID = descp->cd_cnid;
 1789         void * buffer;
 1790         int bufsize;
 1791         int maxdirentries;
 1792         int result;
 1793 
 1794         diroffset = uio->uio_offset;
 1795         *eofflag = 0;
 1796         maxdirentries = MIN(entrycnt, uio->uio_resid / SMALL_DIRENTRY_SIZE);
 1797 
 1798         /* Get a buffer for collecting link info and for a btree iterator */
 1799         bufsize = (maxdirentries * sizeof(struct linkinfo)) + sizeof(*iterator);
 1800         MALLOC(buffer, void *, bufsize, M_TEMP, M_WAITOK);
 1801         bzero(buffer, bufsize);
 1802 
 1803         state.cbs_nlinks = 0;
 1804         state.cbs_maxlinks = maxdirentries;
 1805         state.cbs_linkinfo = (struct linkinfo *) buffer;
 1806         iterator = (BTreeIterator *) ((char *)buffer + (maxdirentries * sizeof(struct linkinfo)));
 1807 
 1808         /* get an iterator and position it */
 1809         cip = GetCatalogIterator(vcb, dirID, diroffset);
 1810 
 1811         result = PositionIterator(cip, diroffset, iterator, &op);
 1812         if (result == cmNotFound) {
 1813                 *eofflag = 1;
 1814                 result = 0;
 1815                 AgeCatalogIterator(cip);
 1816                 goto cleanup;
 1817         } else if ((result = MacToVFSError(result)))
 1818                 goto cleanup;
 1819 
 1820         state.cbs_hiddenDirID = hfsmp->hfs_privdir_desc.cd_cnid;
 1821         if (hfsmp->jnl) {
 1822                 state.cbs_hiddenJournalID = hfsmp->hfs_jnlfileid;
 1823                 state.cbs_hiddenInfoBlkID = hfsmp->hfs_jnlinfoblkid;
 1824         }
 1825 
 1826         state.cbs_lastoffset = cip->currentOffset;
 1827         state.cbs_vcb = vcb;
 1828         state.cbs_uio = uio;
 1829         state.cbs_result = 0;
 1830         state.cbs_parentID = dirID;
 1831         if (diroffset <= 2*sizeof(struct hfsdotentry)) {
 1832             state.cbs_numresults = diroffset/sizeof(struct hfsdotentry);
 1833         } else {
 1834             state.cbs_numresults = 0;
 1835         }
 1836         state.cbs_cookies = cookies;
 1837         state.cbs_ncookies = ncookies;
 1838 
 1839         if (vcb->vcbSigWord == kHFSPlusSigWord)
 1840                 state.cbs_hfsPlus = 1;
 1841         else
 1842                 state.cbs_hfsPlus = 0;
 1843 
 1844         if (hfsmp->hfs_flags & HFS_CASE_SENSITIVE)
 1845                 state.cbs_case_sensitive = 1;
 1846         else
 1847                 state.cbs_case_sensitive = 0;
 1848 
 1849         /* process as many entries as possible... */
 1850         result = BTIterateRecords(GetFileControlBlock(vcb->catalogRefNum), op,
 1851                  iterator, (IterateCallBackProcPtr)catrec_read, &state);
 1852 
 1853         /*
 1854          * Post process any hard links to get the real file id.
 1855          */
 1856         if (state.cbs_nlinks > 0) {
 1857                 struct iovec aiov;
 1858                 struct uio auio;
 1859                 u_int32_t fileid;
 1860                 int i;
 1861                 u_int32_t tempid;
 1862 
 1863                 auio.uio_iov = &aiov;
 1864                 auio.uio_iovcnt = 1;
 1865                 auio.uio_segflg = uio->uio_segflg;
 1866                 auio.uio_rw = UIO_READ;  /* read kernel memory into user memory */
 1867                 auio.uio_procp = uio->uio_procp;
 1868 
 1869                 for (i = 0; i < state.cbs_nlinks; ++i) {
 1870                         fileid = 0;
 1871                         
 1872                         if (resolvelinkid(hfsmp, state.cbs_linkinfo[i].link_ref, &fileid) != 0)
 1873                                 continue;
 1874 
 1875                         /* Update the file id in the user's buffer */
 1876                         aiov.iov_base = (char *) state.cbs_linkinfo[i].dirent_addr;
 1877                         aiov.iov_len = sizeof(fileid);
 1878                         auio.uio_offset = 0;
 1879                         auio.uio_resid = aiov.iov_len;
 1880                         (void) uiomove((caddr_t)&fileid, sizeof(fileid), &auio);
 1881                 }
 1882         }
 1883         if (state.cbs_result)
 1884                 result = state.cbs_result;
 1885         else
 1886                 result = MacToVFSError(result);
 1887 
 1888         if (result == ENOENT) {
 1889                 *eofflag = 1;
 1890                 result = 0;
 1891         }
 1892 
 1893         if (result == 0) {
 1894                 cip->currentOffset = state.cbs_lastoffset;
 1895                 cip->nextOffset = uio->uio_offset;
 1896                 UpdateCatalogIterator(iterator, cip);
 1897         }
 1898 
 1899 cleanup:
 1900         if (result) {
 1901                 cip->volume = 0;
 1902                 cip->folderID = 0;
 1903                 AgeCatalogIterator(cip);
 1904         }
 1905 
 1906         (void) ReleaseCatalogIterator(cip);
 1907         FREE(buffer, M_TEMP);
 1908         
 1909         return (result);
 1910 }
 1911 
 1912 
 1913 /*
 1914  * cat_binarykeycompare - compare two HFS Plus catalog keys.
 1915 
 1916  * The name portion of the key is comapred using a 16-bit binary comparison. 
 1917  * This is called from the b-tree code.
 1918  */
 1919 __private_extern__
 1920 int
 1921 cat_binarykeycompare(HFSPlusCatalogKey *searchKey, HFSPlusCatalogKey *trialKey)
 1922 {
 1923         u_int32_t searchParentID, trialParentID;
 1924         int result;
 1925 
 1926         searchParentID = searchKey->parentID;
 1927         trialParentID = trialKey->parentID;
 1928         result = 0;
 1929         
 1930         if (searchParentID > trialParentID) {
 1931                 ++result;
 1932         } else if (searchParentID < trialParentID) {
 1933                 --result;
 1934         } else {
 1935                 u_int16_t * str1 = &searchKey->nodeName.unicode[0];
 1936                 u_int16_t * str2 = &trialKey->nodeName.unicode[0];
 1937                 int length1 = searchKey->nodeName.length;
 1938                 int length2 = trialKey->nodeName.length;
 1939                 u_int16_t c1, c2;
 1940                 int length;
 1941         
 1942                 if (length1 < length2) {
 1943                         length = length1;
 1944                         --result;
 1945                 } else if (length1 > length2) {
 1946                         length = length2;
 1947                         ++result;
 1948                 } else {
 1949                         length = length1;
 1950                 }
 1951         
 1952                 while (length--) {
 1953                         c1 = *(str1++);
 1954                         c2 = *(str2++);
 1955         
 1956                         if (c1 > c2) {
 1957                                 result = 1;
 1958                                 break;
 1959                         }
 1960                         if (c1 < c2) {
 1961                                 result = -1;
 1962                                 break;
 1963                         }
 1964                 }
 1965         }
 1966 
 1967         return result;
 1968 }
 1969 
 1970 
 1971 /*
 1972  * buildkey - build a Catalog b-tree key from a cnode descriptor
 1973  */
 1974 static int
 1975 buildkey(struct hfsmount *hfsmp, struct cat_desc *descp,
 1976         HFSPlusCatalogKey *key, int retry)
 1977 {
 1978         int utf8_flags = 0;
 1979         int result = 0;
 1980         size_t unicodeBytes = 0;
 1981 
 1982         if (descp->cd_namelen == 0 || descp->cd_nameptr[0] == '\0')
 1983                 return (EINVAL);  /* invalid name */
 1984 
 1985         key->parentID = descp->cd_parentcnid;
 1986         key->nodeName.length = 0;
 1987         /*
 1988          * Convert filename from UTF-8 into Unicode
 1989          */
 1990         
 1991         if ((descp->cd_flags & CD_DECOMPOSED) == 0)
 1992                 utf8_flags |= UTF_DECOMPOSED;
 1993         result = utf8_decodestr(descp->cd_nameptr, descp->cd_namelen,
 1994                 key->nodeName.unicode, &unicodeBytes,
 1995                 sizeof(key->nodeName.unicode), ':', utf8_flags);
 1996         key->nodeName.length = unicodeBytes / sizeof(UniChar);
 1997         key->keyLength = kHFSPlusCatalogKeyMinimumLength + unicodeBytes;
 1998         if (result) {
 1999                 if (result != ENAMETOOLONG)
 2000                         result = EINVAL;  /* name has invalid characters */
 2001                 return (result);
 2002         }
 2003 
 2004         /*
 2005          * For HFS volumes convert to an HFS compatible key
 2006          *
 2007          * XXX need to save the encoding that succeeded
 2008          */
 2009         if (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord) {
 2010                 HFSCatalogKey hfskey;
 2011 
 2012                 bzero(&hfskey, sizeof(hfskey));
 2013                 hfskey.keyLength = kHFSCatalogKeyMinimumLength;
 2014                 hfskey.parentID = key->parentID;
 2015                 hfskey.nodeName[0] = 0;
 2016                 if (key->nodeName.length > 0) {
 2017                         if (unicode_to_hfs(HFSTOVCB(hfsmp),
 2018                                 key->nodeName.length * 2,
 2019                                 key->nodeName.unicode,
 2020                                 &hfskey.nodeName[0], retry) != 0) {
 2021                                 return (EINVAL);
 2022                         }
 2023                         hfskey.keyLength += hfskey.nodeName[0];
 2024                 }
 2025                 bcopy(&hfskey, key, sizeof(hfskey));
 2026         }
 2027         return (0);
 2028  }
 2029 
 2030 
 2031 /*
 2032  * Resolve hard link reference to obtain the inode record.
 2033  */
 2034 __private_extern__
 2035 int
 2036 resolvelink(struct hfsmount *hfsmp, u_long linkref, struct HFSPlusCatalogFile *recp)
 2037 {
 2038         FSBufferDescriptor btdata;
 2039         struct BTreeIterator *iterator;
 2040         struct cat_desc idesc;
 2041         char inodename[32];
 2042         int result = 0;
 2043 
 2044         BDINIT(btdata, recp);
 2045         MAKE_INODE_NAME(inodename, linkref);
 2046 
 2047         /* Get space for iterator */    
 2048         MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
 2049         bzero(iterator, sizeof(*iterator));
 2050 
 2051         /* Build a descriptor for private dir. */       
 2052         idesc.cd_parentcnid = hfsmp->hfs_privdir_desc.cd_cnid;
 2053         idesc.cd_nameptr = inodename;
 2054         idesc.cd_namelen = strlen(inodename);
 2055         idesc.cd_flags = 0;
 2056         idesc.cd_hint = 0;
 2057         idesc.cd_encoding = 0;
 2058         (void) buildkey(hfsmp, &idesc, (HFSPlusCatalogKey *)&iterator->key, 0);
 2059 
 2060         result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator,
 2061                                 &btdata, NULL, NULL);
 2062 
 2063         if (result == 0) {
 2064                 /* Make sure there's a reference */
 2065                 if (recp->bsdInfo.special.linkCount == 0)
 2066                         recp->bsdInfo.special.linkCount = 2;
 2067         } else {
 2068                 printf("HFS resolvelink: can't find %s\n", inodename);
 2069         }
 2070 
 2071         FREE(iterator, M_TEMP);
 2072 
 2073         return (result ? ENOENT : 0);
 2074 }
 2075 
 2076 /*
 2077  * Resolve hard link reference to obtain the inode number.
 2078  */
 2079 static int
 2080 resolvelinkid(struct hfsmount *hfsmp, u_long linkref, ino_t *ino)
 2081 {
 2082         struct HFSPlusCatalogFile record;
 2083         int error;
 2084         
 2085         error = resolvelink(hfsmp, linkref, &record);
 2086         if (error == 0) {
 2087                 if (record.fileID == 0)
 2088                         error = ENOENT;
 2089                 else
 2090                         *ino = record.fileID;
 2091         }
 2092         return (error);
 2093 }
 2094 
 2095 /*
 2096  * getkey - get a key from id by doing a thread lookup
 2097  */
 2098 static int
 2099 getkey(struct hfsmount *hfsmp, cnid_t cnid, CatalogKey * key)
 2100 {
 2101         struct BTreeIterator * iterator;
 2102         FSBufferDescriptor btdata;
 2103         UInt16  datasize;
 2104         CatalogKey * keyp;
 2105         CatalogRecord * recp;
 2106         int result;
 2107         int std_hfs;
 2108 
 2109         std_hfs = (HFSTOVCB(hfsmp)->vcbSigWord == kHFSSigWord);
 2110 
 2111         MALLOC(iterator, BTreeIterator *, sizeof(*iterator), M_TEMP, M_WAITOK);
 2112         bzero(iterator, sizeof(*iterator));
 2113         buildthreadkey(cnid, std_hfs, (CatalogKey *)&iterator->key);
 2114 
 2115         MALLOC(recp, CatalogRecord *, sizeof(CatalogRecord), M_TEMP, M_WAITOK);
 2116         BDINIT(btdata, recp);
 2117 
 2118         result = BTSearchRecord(VTOF(HFSTOVCB(hfsmp)->catalogRefNum), iterator,
 2119                                 &btdata, &datasize, iterator);
 2120         if (result)
 2121                 goto exit;
 2122 
 2123         /* Turn thread record into a cnode key (in place) */
 2124         switch (recp->recordType) {
 2125         case kHFSFileThreadRecord:
 2126         case kHFSFolderThreadRecord:
 2127                 keyp = (CatalogKey *)((char *)&recp->hfsThread.reserved + 6);
 2128                 keyp->hfs.keyLength = kHFSCatalogKeyMinimumLength + keyp->hfs.nodeName[0];
 2129                 bcopy(keyp, key, keyp->hfs.keyLength + 1);
 2130                 break;
 2131 
 2132         case kHFSPlusFileThreadRecord:
 2133         case kHFSPlusFolderThreadRecord:
 2134                 keyp = (CatalogKey *)&recp->hfsPlusThread.reserved;
 2135                 keyp->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength +
 2136                                           (keyp->hfsPlus.nodeName.length * 2);
 2137                 bcopy(keyp, key, keyp->hfsPlus.keyLength + 2);
 2138                 break;
 2139 
 2140         default:
 2141                 result = ENOENT;
 2142                 break;
 2143         }
 2144 
 2145 exit:
 2146         FREE(iterator, M_TEMP);
 2147         FREE(recp, M_TEMP);
 2148 
 2149         return MacToVFSError(result);
 2150 }
 2151 
 2152 
 2153 /*
 2154  * buildrecord - build a default catalog directory or file record
 2155  */
 2156 static void
 2157 buildrecord(struct cat_attr *attrp, cnid_t cnid, int std_hfs, u_int32_t encoding,
 2158             CatalogRecord *crp, int *recordSize)
 2159 {
 2160         int type = attrp->ca_mode & S_IFMT;
 2161         u_int32_t createtime = to_hfs_time(attrp->ca_itime);
 2162 
 2163         if (std_hfs) {
 2164                 createtime = UTCToLocal(createtime);
 2165                 if (type == S_IFDIR) {
 2166                         bzero(crp, sizeof(HFSCatalogFolder));
 2167                         crp->recordType = kHFSFolderRecord;
 2168                         crp->hfsFolder.folderID = cnid;
 2169                         crp->hfsFolder.createDate = createtime;
 2170                         crp->hfsFolder.modifyDate = createtime;
 2171                         bcopy(attrp->ca_finderinfo, &crp->hfsFolder.userInfo, 32);
 2172                         *recordSize = sizeof(HFSCatalogFolder);
 2173                 } else {
 2174                         bzero(crp, sizeof(HFSCatalogFile));
 2175                         crp->recordType = kHFSFileRecord;
 2176                         crp->hfsFile.fileID = cnid;
 2177                         crp->hfsFile.createDate = createtime;
 2178                         crp->hfsFile.modifyDate = createtime;
 2179                         bcopy(attrp->ca_finderinfo, &crp->hfsFile.userInfo, 16);
 2180                         bcopy(&attrp->ca_finderinfo[16], &crp->hfsFile.finderInfo, 16);
 2181                         *recordSize = sizeof(HFSCatalogFile);
 2182                 }
 2183         } else {
 2184                 struct HFSPlusBSDInfo * bsdp = NULL;
 2185                 struct FndrFileInfo * fip = NULL;
 2186 
 2187                 if (type == S_IFDIR) {
 2188                         bzero(crp, sizeof(HFSPlusCatalogFolder));
 2189                         crp->recordType = kHFSPlusFolderRecord;
 2190                         crp->hfsPlusFolder.folderID = cnid;     
 2191                         crp->hfsPlusFolder.createDate = createtime;
 2192                         crp->hfsPlusFolder.contentModDate = createtime;
 2193                         crp->hfsPlusFolder.accessDate = createtime;
 2194                         crp->hfsPlusFolder.attributeModDate = createtime;
 2195                         crp->hfsPlusFolder.textEncoding = encoding;
 2196                         bcopy(attrp->ca_finderinfo, &crp->hfsPlusFolder.userInfo, 32);
 2197                         bsdp = &crp->hfsPlusFolder.bsdInfo;
 2198                         *recordSize = sizeof(HFSPlusCatalogFolder);
 2199                 } else {
 2200                         bzero(crp, sizeof(HFSPlusCatalogFile));
 2201                         crp->recordType = kHFSPlusFileRecord;
 2202                         crp->hfsPlusFile.fileID = cnid;
 2203                         crp->hfsPlusFile.createDate = createtime;
 2204                         crp->hfsPlusFile.contentModDate = createtime;
 2205                         crp->hfsPlusFile.accessDate = createtime;
 2206                         crp->hfsPlusFile.attributeModDate = createtime;
 2207                         crp->hfsPlusFile.flags |= kHFSThreadExistsMask;
 2208                         crp->hfsPlusFile.textEncoding = encoding;
 2209                         bsdp = &crp->hfsPlusFile.bsdInfo;
 2210                         switch(type) {
 2211                         case S_IFBLK:
 2212                         case S_IFCHR:
 2213                                 /* BLK/CHR need to save the device info */
 2214                                 bsdp->special.rawDevice = attrp->ca_rdev;
 2215                                 break;
 2216                         case S_IFREG:
 2217                                 /* Hardlink links need to save the linkref */
 2218                                 fip = (FndrFileInfo *)&attrp->ca_finderinfo;
 2219                                 if ((SWAP_BE32(fip->fdType) == kHardLinkFileType) &&
 2220                                     (SWAP_BE32(fip->fdCreator) == kHFSPlusCreator)) {
 2221                                         bsdp->special.iNodeNum = attrp->ca_rdev;
 2222                                 }
 2223                                 bcopy(attrp->ca_finderinfo, &crp->hfsPlusFile.userInfo, 32);
 2224                                 break;
 2225                         case S_IFLNK:
 2226                                 /* Symlinks also have a type and creator */
 2227                                 bcopy(attrp->ca_finderinfo, &crp->hfsPlusFile.userInfo, 32);
 2228                                 break;
 2229                         }
 2230                         *recordSize = sizeof(HFSPlusCatalogFile);
 2231                 }
 2232                 bsdp->ownerID    = attrp->ca_uid;
 2233                 bsdp->groupID    = attrp->ca_gid;
 2234                 bsdp->fileMode   = attrp->ca_mode;
 2235                 bsdp->adminFlags = attrp->ca_flags >> 16;
 2236                 bsdp->ownerFlags = attrp->ca_flags & 0x000000FF;
 2237         }
 2238 }
 2239 
 2240 
 2241 /*
 2242  * builddesc - build a cnode descriptor from an HFS+ key
 2243  */
 2244 static int
 2245 builddesc(const HFSPlusCatalogKey *key, cnid_t cnid, u_long hint, u_long encoding,
 2246         int isdir, struct cat_desc *descp)
 2247 {
 2248         int result = 0;
 2249         char * nameptr;
 2250         long bufsize;
 2251         size_t utf8len;
 2252         char tmpbuff[128];
 2253 
 2254         /* guess a size... */
 2255         bufsize = (3 * key->nodeName.length) + 1;
 2256         if (bufsize >= sizeof(tmpbuff)-1) {
 2257             MALLOC(nameptr, char *, bufsize, M_TEMP, M_WAITOK);
 2258         } else {
 2259             nameptr = &tmpbuff[0];
 2260         }
 2261 
 2262         result = utf8_encodestr(key->nodeName.unicode,
 2263                         key->nodeName.length * sizeof(UniChar),
 2264                         nameptr, (size_t *)&utf8len,
 2265                         bufsize, ':', 0);
 2266 
 2267         if (result == ENAMETOOLONG) {
 2268                 bufsize = 1 + utf8_encodelen(key->nodeName.unicode,
 2269                                              key->nodeName.length * sizeof(UniChar),
 2270                                              ':', 0);
 2271                 FREE(nameptr, M_TEMP);
 2272                 MALLOC(nameptr, char *, bufsize, M_TEMP, M_WAITOK);
 2273 
 2274                 result = utf8_encodestr(key->nodeName.unicode,
 2275                                         key->nodeName.length * sizeof(UniChar),
 2276                                         nameptr, (size_t *)&utf8len,
 2277                                         bufsize, ':', 0);
 2278         }
 2279         descp->cd_parentcnid = key->parentID;
 2280         descp->cd_nameptr = add_name(nameptr, utf8len, 0, 0);
 2281         descp->cd_namelen = utf8len;
 2282         descp->cd_cnid = cnid;
 2283         descp->cd_hint = hint;
 2284         descp->cd_flags = CD_DECOMPOSED | CD_HASBUF;
 2285         if (isdir)
 2286                 descp->cd_flags |= CD_ISDIR;    
 2287         descp->cd_encoding = encoding;
 2288         if (nameptr != &tmpbuff[0]) {
 2289             FREE(nameptr, M_TEMP);
 2290         }
 2291         return result;
 2292 }
 2293 
 2294 
 2295 /*
 2296  * getbsdattr - get attributes in bsd format
 2297  *
 2298  */
 2299 static void
 2300 getbsdattr(struct hfsmount *hfsmp, const struct HFSPlusCatalogFile *crp, struct cat_attr * attrp)
 2301 {
 2302         int isDirectory = (crp->recordType == kHFSPlusFolderRecord);
 2303         const struct HFSPlusBSDInfo *bsd = &crp->bsdInfo;
 2304 
 2305         attrp->ca_nlink = 1;
 2306         attrp->ca_atime = to_bsd_time(crp->accessDate);
 2307         attrp->ca_mtime = to_bsd_time(crp->contentModDate);
 2308         attrp->ca_mtime_nsec = 0;
 2309         attrp->ca_ctime = to_bsd_time(crp->attributeModDate);
 2310         attrp->ca_itime = to_bsd_time(crp->createDate);
 2311         attrp->ca_btime = to_bsd_time(crp->backupDate);
 2312 
 2313         if ((bsd->fileMode & S_IFMT) == 0) {
 2314                 attrp->ca_flags = 0;
 2315                 attrp->ca_uid = hfsmp->hfs_uid;
 2316                 attrp->ca_gid = hfsmp->hfs_gid;
 2317                 if (isDirectory)
 2318                         attrp->ca_mode = S_IFDIR | (hfsmp->hfs_dir_mask & ACCESSPERMS);
 2319                 else
 2320                         attrp->ca_mode = S_IFREG | (hfsmp->hfs_file_mask & ACCESSPERMS);
 2321                 attrp->ca_rdev = 0;
 2322         } else {
 2323                 attrp->ca_rdev = 0;
 2324                 attrp->ca_uid = bsd->ownerID;
 2325                 attrp->ca_gid = bsd->groupID;
 2326                 attrp->ca_flags = bsd->ownerFlags | (bsd->adminFlags << 16);
 2327                 attrp->ca_mode = (mode_t)bsd->fileMode;
 2328                 switch (attrp->ca_mode & S_IFMT) {
 2329                 case S_IFCHR: /* fall through */
 2330                 case S_IFBLK:
 2331                         attrp->ca_rdev = bsd->special.rawDevice;
 2332                         break;
 2333                 case S_IFREG:
 2334                         /* Pick up the hard link count */
 2335                         if (bsd->special.linkCount > 0)
 2336                                 attrp->ca_nlink = bsd->special.linkCount;
 2337                         break;
 2338                 }
 2339 
 2340                 if (HFSTOVFS(hfsmp)->mnt_flag & MNT_UNKNOWNPERMISSIONS) {
 2341                         /*
 2342                          *  Override the permissions as determined by the mount auguments
 2343                          *  in ALMOST the same way unset permissions are treated but keep
 2344                          *  track of whether or not the file or folder is hfs locked
 2345                          *  by leaving the h_pflags field unchanged from what was unpacked
 2346                          *  out of the catalog.
 2347                          */
 2348                         attrp->ca_uid = hfsmp->hfs_uid;
 2349                         attrp->ca_gid = hfsmp->hfs_gid;
 2350                 }
 2351         }
 2352 
 2353         if (isDirectory) {
 2354                 if (!S_ISDIR(attrp->ca_mode)) {
 2355                         attrp->ca_mode &= ~S_IFMT;
 2356                         attrp->ca_mode |= S_IFDIR;
 2357                 }
 2358                 attrp->ca_nlink = 2 + ((HFSPlusCatalogFolder *)crp)->valence;
 2359                 attrp->ca_entries = ((HFSPlusCatalogFolder *)crp)->valence;
 2360         } else {
 2361                 /* Keep IMMUTABLE bits in sync with HFS locked flag */
 2362                 if (crp->flags & kHFSFileLockedMask) {
 2363                         /* The file's supposed to be locked:
 2364                            Make sure at least one of the IMMUTABLE bits is set: */
 2365                         if ((attrp->ca_flags & (SF_IMMUTABLE | UF_IMMUTABLE)) == 0)
 2366                                 attrp->ca_flags |= UF_IMMUTABLE;
 2367                 } else {
 2368                         /* The file's supposed to be unlocked: */
 2369                         attrp->ca_flags &= ~(SF_IMMUTABLE | UF_IMMUTABLE);
 2370                 }
 2371                 /* get total blocks (both forks) */
 2372                 attrp->ca_blocks = crp->dataFork.totalBlocks + crp->resourceFork.totalBlocks;
 2373         }
 2374         
 2375         attrp->ca_fileid = crp->fileID;
 2376 
 2377         bcopy(&crp->userInfo, attrp->ca_finderinfo, 32);
 2378 }
 2379 
 2380 /*
 2381  * promotekey - promote hfs key to hfs plus key
 2382  *
 2383  */
 2384 static void
 2385 promotekey(struct hfsmount *hfsmp, const HFSCatalogKey *hfskey,
 2386            HFSPlusCatalogKey *keyp, u_long *encoding)
 2387 {
 2388         hfs_to_unicode_func_t hfs_get_unicode = hfsmp->hfs_get_unicode;
 2389         UInt32 uniCount;
 2390         int error;
 2391 
 2392         *encoding = hfsmp->hfs_encoding;
 2393 
 2394         error = hfs_get_unicode(hfskey->nodeName, keyp->nodeName.unicode,
 2395                                 kHFSPlusMaxFileNameChars, &uniCount);
 2396         /*
 2397          * When an HFS name cannot be encoded with the current
 2398          * encoding use MacRoman as a fallback.
 2399          */
 2400         if (error && hfsmp->hfs_encoding != kTextEncodingMacRoman) {
 2401                 *encoding = 0;
 2402                 (void) mac_roman_to_unicode(hfskey->nodeName,
 2403                                             keyp->nodeName.unicode,
 2404                                             kHFSPlusMaxFileNameChars,
 2405                                             &uniCount);
 2406         }
 2407 
 2408         keyp->nodeName.length = uniCount;
 2409         keyp->parentID = hfskey->parentID;
 2410 }
 2411 
 2412 /*
 2413  * promotefork - promote hfs fork info to hfs plus
 2414  *
 2415  */
 2416 static void
 2417 promotefork(struct hfsmount *hfsmp, const struct HFSCatalogFile *filep,
 2418             int resource, struct cat_fork * forkp)
 2419 {
 2420         struct HFSPlusExtentDescriptor *xp;
 2421         u_long blocksize = HFSTOVCB(hfsmp)->blockSize;
 2422 
 2423         bzero(forkp, sizeof(*forkp));
 2424         xp = &forkp->cf_extents[0];
 2425         if (resource) {
 2426                 forkp->cf_size = filep->rsrcLogicalSize;
 2427                 forkp->cf_blocks = filep->rsrcPhysicalSize / blocksize;
 2428                 forkp->cf_bytesread = 0;
 2429                 forkp->cf_vblocks = 0;
 2430                 xp[0].startBlock = (u_int32_t)filep->rsrcExtents[0].startBlock;
 2431                 xp[0].blockCount = (u_int32_t)filep->rsrcExtents[0].blockCount;
 2432                 xp[1].startBlock = (u_int32_t)filep->rsrcExtents[1].startBlock;
 2433                 xp[1].blockCount = (u_int32_t)filep->rsrcExtents[1].blockCount;
 2434                 xp[2].startBlock = (u_int32_t)filep->rsrcExtents[2].startBlock;
 2435                 xp[2].blockCount = (u_int32_t)filep->rsrcExtents[2].blockCount;
 2436         } else {
 2437                 forkp->cf_size = filep->dataLogicalSize;
 2438                 forkp->cf_blocks = filep->dataPhysicalSize / blocksize;
 2439                 forkp->cf_bytesread = 0;
 2440                 forkp->cf_vblocks = 0;
 2441                 xp[0].startBlock = (u_int32_t)filep->dataExtents[0].startBlock;
 2442                 xp[0].blockCount = (u_int32_t)filep->dataExtents[0].blockCount;
 2443                 xp[1].startBlock = (u_int32_t)filep->dataExtents[1].startBlock;
 2444                 xp[1].blockCount = (u_int32_t)filep->dataExtents[1].blockCount;
 2445                 xp[2].startBlock = (u_int32_t)filep->dataExtents[2].startBlock;
 2446                 xp[2].blockCount = (u_int32_t)filep->dataExtents[2].blockCount;
 2447         }
 2448 }
 2449 
 2450 /*
 2451  * promoteattr - promote hfs catalog attributes to hfs plus
 2452  *
 2453  */
 2454 static void
 2455 promoteattr(struct hfsmount *hfsmp, const CatalogRecord *dataPtr, struct HFSPlusCatalogFile *crp)
 2456 {
 2457         u_long blocksize = HFSTOVCB(hfsmp)->blockSize;
 2458 
 2459         if (dataPtr->recordType == kHFSFolderRecord) {
 2460                 struct HFSCatalogFolder * folder;
 2461 
 2462                 folder = (struct HFSCatalogFolder *) dataPtr;
 2463                 crp->recordType       = kHFSPlusFolderRecord;
 2464                 crp->flags            = folder->flags;
 2465                 crp->fileID           = folder->folderID;
 2466                 crp->createDate       = LocalToUTC(folder->createDate);
 2467                 crp->contentModDate   = LocalToUTC(folder->modifyDate);
 2468                 crp->backupDate       = LocalToUTC(folder->backupDate);
 2469                 crp->reserved1        = folder->valence;
 2470                 bcopy(&folder->userInfo, &crp->userInfo, 32);
 2471         } else /* file */ {
 2472                 struct HFSCatalogFile * file;
 2473 
 2474                 file = (struct HFSCatalogFile *) dataPtr;
 2475                 crp->recordType       = kHFSPlusFileRecord;
 2476                 crp->flags            = file->flags;
 2477                 crp->fileID           = file->fileID;
 2478                 crp->createDate       = LocalToUTC(file->createDate);
 2479                 crp->contentModDate   = LocalToUTC(file->modifyDate);
 2480                 crp->backupDate       = LocalToUTC(file->backupDate);
 2481                 crp->reserved1        = 0;
 2482                 bcopy(&file->userInfo, &crp->userInfo, 16);
 2483                 bcopy(&file->finderInfo, &crp->finderInfo, 16);
 2484                 crp->dataFork.totalBlocks = file->dataPhysicalSize / blocksize;
 2485                 crp->resourceFork.totalBlocks = file->rsrcPhysicalSize / blocksize;
 2486         }
 2487         crp->textEncoding = 0;
 2488         crp->attributeModDate = crp->contentModDate;
 2489         crp->accessDate = crp->contentModDate;
 2490         bzero(&crp->bsdInfo, sizeof(HFSPlusBSDInfo));
 2491         crp->reserved2 = 0;
 2492 }
 2493 
 2494 /*
 2495  * Build a catalog node thread record from a catalog key
 2496  * and return the size of the record.
 2497  */
 2498 static int
 2499 buildthread(void *keyp, void *recp, int std_hfs, int directory)
 2500 {
 2501         int size = 0;
 2502 
 2503         if (std_hfs) {
 2504                 HFSCatalogKey *key = (HFSCatalogKey *)keyp;
 2505                 HFSCatalogThread *rec = (HFSCatalogThread *)recp;
 2506 
 2507                 size = sizeof(HFSCatalogThread);
 2508                 bzero(rec, size);
 2509                 if (directory)
 2510                         rec->recordType = kHFSFolderThreadRecord;
 2511                 else
 2512                         rec->recordType = kHFSFileThreadRecord;
 2513                 rec->parentID = key->parentID;
 2514                 bcopy(key->nodeName, rec->nodeName, key->nodeName[0]+1);
 2515 
 2516         } else /* HFS+ */ {
 2517                 HFSPlusCatalogKey *key = (HFSPlusCatalogKey *)keyp;
 2518                 HFSPlusCatalogThread *rec = (HFSPlusCatalogThread *)recp;
 2519 
 2520                 size = sizeof(HFSPlusCatalogThread);
 2521                 if (directory)
 2522                         rec->recordType = kHFSPlusFolderThreadRecord;
 2523                 else
 2524                         rec->recordType = kHFSPlusFileThreadRecord;
 2525                 rec->reserved = 0;
 2526                 rec->parentID = key->parentID;                  
 2527                 bcopy(&key->nodeName, &rec->nodeName,
 2528                         sizeof(UniChar) * (key->nodeName.length + 1));
 2529 
 2530                 /* HFS Plus has varaible sized thread records */
 2531                 size -= (sizeof(rec->nodeName.unicode) -
 2532                           (rec->nodeName.length * sizeof(UniChar)));
 2533         }
 2534         
 2535         return (size);
 2536 }
 2537 
 2538 /*
 2539  * Build a catalog node thread key.
 2540  */
 2541 static void
 2542 buildthreadkey(HFSCatalogNodeID parentID, int std_hfs, CatalogKey *key)
 2543 {
 2544         if (std_hfs) {
 2545                 key->hfs.keyLength = kHFSCatalogKeyMinimumLength;
 2546                 key->hfs.reserved = 0;
 2547                 key->hfs.parentID = parentID;
 2548                 key->hfs.nodeName[0] = 0;
 2549         } else {
 2550                 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength;
 2551                 key->hfsPlus.parentID = parentID;
 2552                 key->hfsPlus.nodeName.length = 0;
 2553         }
 2554 }
 2555 
 2556 /*
 2557  * Extract the text encoding from a catalog node record.
 2558  */
 2559 static u_long 
 2560 getencoding(const CatalogRecord *crp)
 2561 {
 2562         u_long encoding;
 2563 
 2564         if (crp->recordType == kHFSPlusFolderRecord)
 2565                 encoding = crp->hfsPlusFolder.textEncoding;
 2566         else if (crp->recordType == kHFSPlusFileRecord)
 2567                 encoding = crp->hfsPlusFile.textEncoding;
 2568         else
 2569                 encoding = 0;
 2570 
 2571         return (encoding);
 2572 }
 2573 
 2574 /*
 2575  * Extract the CNID from a catalog node record.
 2576  */
 2577 static cnid_t 
 2578 getcnid(const CatalogRecord *crp)
 2579 {
 2580         cnid_t cnid = 0;
 2581 
 2582         switch (crp->recordType) {
 2583         case kHFSFolderRecord:
 2584                 cnid = crp->hfsFolder.folderID;
 2585                 break;
 2586         case kHFSFileRecord:
 2587                 cnid = crp->hfsFile.fileID;
 2588                 break;
 2589         case kHFSPlusFolderRecord:
 2590                 cnid = crp->hfsPlusFolder.folderID;
 2591                 break;
 2592         case kHFSPlusFileRecord:
 2593                 cnid = crp->hfsPlusFile.fileID;
 2594                 break;
 2595         default:
 2596                 panic("hfs: getcnid: unknown recordType (crp @ 0x%x)\n", crp);
 2597                 break;
 2598         }
 2599 
 2600         return (cnid);
 2601 }
 2602 
 2603 /*
 2604  * Extract the parent ID from a catalog node record.
 2605  */
 2606 static cnid_t 
 2607 getparentcnid(const CatalogRecord *recp)
 2608 {
 2609         cnid_t cnid = 0;
 2610 
 2611         switch (recp->recordType) {
 2612         case kHFSFileThreadRecord:
 2613         case kHFSFolderThreadRecord:
 2614                 cnid = recp->hfsThread.parentID;
 2615                 break;
 2616 
 2617         case kHFSPlusFileThreadRecord:
 2618         case kHFSPlusFolderThreadRecord:
 2619                 cnid = recp->hfsPlusThread.parentID;
 2620                 break;
 2621         default:
 2622                 panic("hfs: getparentcnid: unknown recordType (crp @ 0x%x)\n", recp);
 2623                 break;
 2624         }
 2625 
 2626         return (cnid);
 2627 }
 2628 
 2629 /*
 2630  * Determine if a catalog node record is a directory.
 2631  */
 2632 static int 
 2633 isadir(const CatalogRecord *crp)
 2634 {
 2635         return (crp->recordType == kHFSFolderRecord ||
 2636                 crp->recordType == kHFSPlusFolderRecord);
 2637 }
 2638 
 2639 

Cache object: c1556c61afc9bfca8c56993443f7cb90


[ 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.