]> git.saurik.com Git - apple/hfs.git/blobdiff - core/CatalogUtilities.c
hfs-522.100.5.tar.gz
[apple/hfs.git] / core / CatalogUtilities.c
diff --git a/core/CatalogUtilities.c b/core/CatalogUtilities.c
new file mode 100644 (file)
index 0000000..e56473d
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2000-2002, 2004-2015 Apple Inc. All rights reserved.
+ *
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
+ */
+#include <sys/param.h>
+#include <sys/utfconv.h>
+#include <sys/stat.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <libkern/libkern.h>
+
+#include "FileMgrInternal.h"
+#include "BTreesInternal.h"
+#include "CatalogPrivate.h"
+#include "HFSUnicodeWrappers.h"
+#include "BTreesPrivate.h"
+#include <string.h>
+
+//
+//     Routine:        LocateCatalogNodeByKey
+//
+// Function:   Locates the catalog record for an existing folder or file
+//                             CNode and returns the key and data records.
+//
+
+OSErr
+LocateCatalogNodeByKey(const ExtendedVCB *volume, u_int32_t hint, CatalogKey *keyPtr,
+                                               CatalogRecord *dataPtr, u_int32_t *newHint)
+{
+       OSErr                           result;
+       CatalogName             *nodeName = NULL;
+       HFSCatalogNodeID        threadParentID;
+       u_int16_t tempSize;
+       FSBufferDescriptor       btRecord;
+       struct BTreeIterator *searchIterator;
+       FCB                     *fcb;
+
+       searchIterator = hfs_mallocz(sizeof(struct BTreeIterator));
+
+       fcb = GetFileControlBlock(volume->catalogRefNum);
+
+       btRecord.bufferAddress = dataPtr;
+       btRecord.itemCount = 1;
+       btRecord.itemSize = sizeof(CatalogRecord);
+
+       searchIterator->hint.nodeNum = hint;
+
+       bcopy(keyPtr, &searchIterator->key, sizeof(CatalogKey));
+       
+       result = BTSearchRecord( fcb, searchIterator, &btRecord, &tempSize, searchIterator );
+
+       if (result == noErr)
+       {
+               *newHint = searchIterator->hint.nodeNum;
+
+               BlockMoveData(&searchIterator->key, keyPtr, sizeof(CatalogKey));
+       }
+
+       if (result == btNotFound) {
+               result = cmNotFound;
+       }       
+
+       if (result) {
+               hfs_free(searchIterator, sizeof(*searchIterator));
+               return result;
+       }
+       
+       // if we got a thread record, then go look up real record
+       switch ( dataPtr->recordType )
+       {
+
+#if CONFIG_HFS_STD
+               case kHFSFileThreadRecord:
+               case kHFSFolderThreadRecord:
+                       threadParentID = dataPtr->hfsThread.parentID;
+                       nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
+                       break;
+#endif
+
+               case kHFSPlusFileThreadRecord:
+               case kHFSPlusFolderThreadRecord:
+                       threadParentID = dataPtr->hfsPlusThread.parentID;
+                       nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;    
+                       break;
+
+               default:
+                       threadParentID = 0;
+                       break;
+       }
+       
+       if ( threadParentID )           // found a thread
+               result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
+       
+       hfs_free(searchIterator, sizeof(*searchIterator));
+       return result;
+}
+
+
+
+//*******************************************************************************
+//     Routine:        LocateCatalogRecord
+//
+// Function:   Locates the catalog record associated with folderID and name
+//
+//*******************************************************************************
+
+OSErr
+LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
+                                       __unused u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint)
+{
+       OSErr result;
+       uint16_t tempSize;
+       FSBufferDescriptor btRecord;
+       struct BTreeIterator *searchIterator = NULL;
+       FCB *fcb;
+       BTreeControlBlock *btcb;
+
+       searchIterator = hfs_mallocz(sizeof(struct BTreeIterator));
+
+       fcb = GetFileControlBlock(volume->catalogRefNum);
+       btcb = (BTreeControlBlock *)fcb->fcbBTCBPtr;
+       
+       btRecord.bufferAddress = dataPtr;
+       btRecord.itemCount = 1;
+       btRecord.itemSize = sizeof(CatalogRecord);
+
+       BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), (CatalogKey *)&searchIterator->key);
+
+       result = BTSearchRecord(fcb, searchIterator, &btRecord, &tempSize, searchIterator);
+       if (result == noErr) {
+               *newHint = searchIterator->hint.nodeNum;
+               BlockMoveData(&searchIterator->key, keyPtr, CalcKeySize(btcb, &searchIterator->key));
+       }
+
+       hfs_free(searchIterator, sizeof(*searchIterator));
+       return (result == btNotFound ? cmNotFound : result);
+}
+
+
+
+/*
+ *     Routine:        BuildCatalogKey
+ *
+ *     Function:       Constructs a catalog key record (ckr) given the parent
+ *                             folder ID and CName.  Works for both classic and extended
+ *                             HFS volumes.
+ *
+ */
+
+void
+BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
+{
+       if ( isHFSPlus )
+       {
+               key->hfsPlus.keyLength                  = kHFSPlusCatalogKeyMinimumLength;      // initial key length (4 + 2)
+               key->hfsPlus.parentID                   = parentID;             // set parent ID
+               key->hfsPlus.nodeName.length    = 0;                    // null CName length
+               if ( cName != NULL )
+               {
+                       CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
+                       key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length
+               }
+       }
+#if CONFIG_HFS_STD
+       else
+       {
+               key->hfs.keyLength              = kHFSCatalogKeyMinimumLength;  // initial key length (1 + 4 + 1)
+               key->hfs.reserved               = 0;                            // clear unused byte
+               key->hfs.parentID               = parentID;                     // set parent ID
+               key->hfs.nodeName[0]    = 0;                            // null CName length
+               if ( cName != NULL )
+               {
+                       UpdateCatalogName(cName->pstr, key->hfs.nodeName);
+                       key->hfs.keyLength += key->hfs.nodeName[0];             // add CName size to key length
+               }
+       }
+#endif
+
+}
+
+OSErr
+BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const unsigned char *name, u_int32_t nameLength,
+                   CatalogKey *key)
+{
+       OSErr err = 0;
+
+    if ( name == NULL)
+        nameLength = 0;
+    else if (nameLength == kUndefinedStrLen)
+        nameLength = strlen((const char *)name);
+
+       if ( volume->vcbSigWord == kHFSPlusSigWord ) {
+               size_t unicodeBytes = 0;
+
+               key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength;       // initial key length (4 + 2)
+               key->hfsPlus.parentID = parentID;                       // set parent ID
+               key->hfsPlus.nodeName.length = 0;                       // null CName length
+               if ( nameLength > 0 ) {
+                       err = utf8_decodestr(name, nameLength, key->hfsPlus.nodeName.unicode,
+                               &unicodeBytes, sizeof(key->hfsPlus.nodeName.unicode), ':', UTF_DECOMPOSED);
+                       key->hfsPlus.nodeName.length = unicodeBytes / sizeof(UniChar);
+                       key->hfsPlus.keyLength += unicodeBytes;
+               }
+       }
+#if CONFIG_HFS_STD
+       else {
+               key->hfs.keyLength              = kHFSCatalogKeyMinimumLength;  // initial key length (1 + 4 + 1)
+               key->hfs.reserved               = 0;                            // clear unused byte
+               key->hfs.parentID               = parentID;                     // set parent ID
+               key->hfs.nodeName[0]    = 0;                            // null CName length
+               if ( nameLength > 0 ) {
+                       err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]);
+                       /*
+                        * Retry with MacRoman in case that's how it was exported.
+                        * When textEncoding != NULL we know that this is a create
+                        * or rename call and can skip the retry (ugly but it works).
+                        */
+                       if (err)
+                               err = utf8_to_mac_roman(nameLength, name, &key->hfs.nodeName[0]);
+                       key->hfs.keyLength += key->hfs.nodeName[0];             // add CName size to key length
+               }
+       }
+#endif
+
+       if (err) {
+               if (err == ENAMETOOLONG)
+                       err = bdNamErr; /* name is too long */
+               else
+                       err = paramErr; /* name has invalid characters */
+       }
+
+       return err;
+}
+
+
+//*******************************************************************************
+//     Routine:        FlushCatalog
+//
+// Function:   Flushes the catalog for a specified volume.
+//
+//*******************************************************************************
+
+OSErr
+FlushCatalog(ExtendedVCB *volume)
+{
+       FCB *   fcb;
+       OSErr   result;
+       struct hfsmount *hfsmp = VCBTOHFS (volume);
+       
+       fcb = GetFileControlBlock(volume->catalogRefNum);
+       result = BTFlushPath(fcb);
+
+       if (result == noErr)
+       {
+               //--- check if catalog's fcb is dirty...
+               
+               if ( (0) /*fcb->fcbFlags & fcbModifiedMask*/ )
+               {
+                       hfs_lock_mount (hfsmp);
+                       MarkVCBDirty(volume);   // Mark the VCB dirty
+                       volume->vcbLsMod = GetTimeUTC();        // update last modified date
+                       hfs_unlock_mount (hfsmp);
+
+               //      result = FlushVolumeControlBlock(volume);
+               }
+       }
+       
+       return result;
+}
+
+
+//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
+//     Routine:        UpdateCatalogName
+//
+//     Function:       Updates a CName.
+//
+//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
+
+void
+UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
+{
+       Size length = srcName[0];
+       
+       if (length > CMMaxCName)
+               length = CMMaxCName;                            // truncate to max
+
+       destName[0] = length;                                   // set length byte
+       
+       BlockMoveData(&srcName[1], &destName[1], length);
+}
+
+//_______________________________________________________________________
+
+void
+CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPlus)
+{
+       u_int32_t       length = 0;
+       
+       if ( srcName == NULL )
+       {
+               if ( dstName != NULL )
+                       dstName->ustr.length = 0;       // set length byte to zero (works for both unicode and pascal)          
+               return;
+       }
+       
+       if (isHFSPlus) {
+               length = sizeof(UniChar) * (srcName->ustr.length + 1);
+       }
+#if CONFIG_HFS_STD
+       else {
+               length = sizeof(u_int8_t) + srcName->pstr[0];
+       }
+#endif
+
+       if ( length > 1 )
+               BlockMoveData(srcName, dstName, length);
+       else
+               dstName->ustr.length = 0;       // set length byte to zero (works for both unicode and pascal)          
+}
+