CatalogUtilities.c [plain text]
#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>
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;
}
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 ) result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
hfs_free(searchIterator, sizeof(*searchIterator));
return result;
}
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);
}
void
BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
{
if ( isHFSPlus )
{
key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; key->hfsPlus.parentID = parentID; key->hfsPlus.nodeName.length = 0; if ( cName != NULL )
{
CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; }
}
#if CONFIG_HFS_STD
else
{
key->hfs.keyLength = kHFSCatalogKeyMinimumLength; key->hfs.reserved = 0; key->hfs.parentID = parentID; key->hfs.nodeName[0] = 0; if ( cName != NULL )
{
UpdateCatalogName(cName->pstr, key->hfs.nodeName);
key->hfs.keyLength += key->hfs.nodeName[0]; }
}
#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; key->hfsPlus.parentID = parentID; key->hfsPlus.nodeName.length = 0; 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; key->hfs.reserved = 0; key->hfs.parentID = parentID; key->hfs.nodeName[0] = 0; if ( nameLength > 0 ) {
err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]);
if (err)
err = utf8_to_mac_roman(nameLength, name, &key->hfs.nodeName[0]);
key->hfs.keyLength += key->hfs.nodeName[0]; }
}
#endif
if (err) {
if (err == ENAMETOOLONG)
err = bdNamErr;
else
err = paramErr;
}
return err;
}
OSErr
FlushCatalog(ExtendedVCB *volume)
{
FCB * fcb;
OSErr result;
struct hfsmount *hfsmp = VCBTOHFS (volume);
fcb = GetFileControlBlock(volume->catalogRefNum);
result = BTFlushPath(fcb);
if (result == noErr)
{
if ( (0) )
{
hfs_lock_mount (hfsmp);
MarkVCBDirty(volume); volume->vcbLsMod = GetTimeUTC(); hfs_unlock_mount (hfsmp);
}
}
return result;
}
void
UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
{
Size length = srcName[0];
if (length > CMMaxCName)
length = CMMaxCName;
destName[0] = length;
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; 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; }