int removeExtents(RawFile* rawFile) { uint32_t blocksLeft; HFSPlusForkData* forkData; uint32_t currentBlock; uint32_t startBlock; uint32_t blockCount; HFSPlusExtentDescriptor* descriptor; int currentExtent; HFSPlusExtentKey extentKey; int exact; extentKey.keyLength = sizeof(HFSPlusExtentKey) - sizeof(extentKey.keyLength); extentKey.forkType = 0; extentKey.fileID = rawFile->id; forkData = rawFile->forkData; blocksLeft = forkData->totalBlocks; currentExtent = 0; currentBlock = 0; descriptor = (HFSPlusExtentDescriptor*) forkData->extents; while(blocksLeft > 0) { if(currentExtent == 8) { if(rawFile->volume->extentsTree == NULL) { hfs_panic("no extents overflow file loaded yet!"); return FALSE; } if(descriptor != ((HFSPlusExtentDescriptor*) forkData->extents)) { free(descriptor); } extentKey.startBlock = currentBlock; descriptor = (HFSPlusExtentDescriptor*) search(rawFile->volume->extentsTree, (BTKey*)(&extentKey), &exact, NULL, NULL); if(descriptor == NULL || exact == FALSE) { hfs_panic("inconsistent extents information!"); return FALSE; } else { removeFromBTree(rawFile->volume->extentsTree, (BTKey*)(&extentKey)); currentExtent = 0; continue; } } startBlock = descriptor[currentExtent].startBlock; blockCount = descriptor[currentExtent].blockCount; currentBlock += blockCount; blocksLeft -= blockCount; currentExtent++; } if(descriptor != ((HFSPlusExtentDescriptor*) forkData->extents)) { free(descriptor); } return TRUE; }
int unsetAttribute(Volume* volume, uint32_t fileID, const char* name) { HFSPlusAttrKey key; if(!volume->attrTree) return FALSE; memset(&key, 0 , sizeof(HFSPlusAttrKey)); key.fileID = fileID; key.startBlock = 0; ASCIIToUnicode(name, &key.name); key.keyLength = sizeof(HFSPlusAttrKey) - sizeof(HFSUniStr255) + sizeof(key.name.length) + (sizeof(uint16_t) * key.name.length); return removeFromBTree(volume->attrTree, (BTKey*)(&key)); }
static int updateAttributes(Volume* volume, HFSPlusAttrKey* skey, HFSPlusAttrRecord* srecord) { HFSPlusAttrKey key; HFSPlusAttrRecord* record; int ret, len; memcpy(&key, skey, skey->keyLength); switch(srecord->recordType) { case kHFSPlusAttrInlineData: len = srecord->attrData.size + sizeof(HFSPlusAttrData); record = (HFSPlusAttrRecord*) malloc(len); memcpy(record, srecord, len); flipAttrData((HFSPlusAttrData*) record); removeFromBTree(volume->attrTree, (BTKey*)(&key)); ret = addToBTree(volume->attrTree, (BTKey*)(&key), len, (unsigned char *)record); free(record); break; case kHFSPlusAttrForkData: record = (HFSPlusAttrRecord*) malloc(sizeof(HFSPlusAttrForkData)); memcpy(record, srecord, sizeof(HFSPlusAttrForkData)); flipAttrForkData((HFSPlusAttrForkData*) record); removeFromBTree(volume->attrTree, (BTKey*)(&key)); ret = addToBTree(volume->attrTree, (BTKey*)(&key), sizeof(HFSPlusAttrForkData), (unsigned char *)record); free(record); break; case kHFSPlusAttrExtents: record = (HFSPlusAttrRecord*) malloc(sizeof(HFSPlusAttrExtents)); memcpy(record, srecord, sizeof(HFSPlusAttrExtents)); flipAttrExtents((HFSPlusAttrExtents*) record); removeFromBTree(volume->attrTree, (BTKey*)(&key)); ret = addToBTree(volume->attrTree, (BTKey*)(&key), sizeof(HFSPlusAttrExtents), (unsigned char *)record); free(record); break; } return ret; }
int updateCatalog(Volume* volume, HFSPlusCatalogRecord* catalogRecord) { HFSPlusCatalogKey key; HFSPlusCatalogRecord* record; HFSPlusCatalogFile file; HFSPlusCatalogFolder folder; int exact; key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length); if(catalogRecord->recordType == kHFSPlusFolderRecord) { key.parentID = ((HFSPlusCatalogFolder*)catalogRecord)->folderID; } else if(catalogRecord->recordType == kHFSPlusFileRecord) { key.parentID = ((HFSPlusCatalogFile*)catalogRecord)->fileID; } else { /* unexpected */ return FALSE; } key.nodeName.length = 0; record = (HFSPlusCatalogRecord*) search(volume->catalogTree, (BTKey*)(&key), &exact, NULL, NULL); key.parentID = ((HFSPlusCatalogThread*)record)->parentID; key.nodeName = ((HFSPlusCatalogThread*)record)->nodeName; key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length) + (sizeof(uint16_t) * key.nodeName.length); free(record); record = (HFSPlusCatalogRecord*) search(volume->catalogTree, (BTKey*)(&key), &exact, NULL, NULL); removeFromBTree(volume->catalogTree, (BTKey*)(&key)); switch(record->recordType) { case kHFSPlusFolderRecord: memcpy(&folder, catalogRecord, sizeof(HFSPlusCatalogFolder)); flipCatalogFolder(&folder); free(record); return addToBTree(volume->catalogTree, (BTKey*)(&key), sizeof(HFSPlusCatalogFolder), (unsigned char *)(&folder)); break; case kHFSPlusFileRecord: memcpy(&file, catalogRecord, sizeof(HFSPlusCatalogFile)); flipCatalogFile(&file); free(record); return addToBTree(volume->catalogTree, (BTKey*)(&key), sizeof(HFSPlusCatalogFile), (unsigned char *)(&file)); break; } return TRUE; }
int removeFile(const char* fileName, Volume* volume) { HFSPlusCatalogRecord* record; HFSPlusCatalogKey key; io_func* io; HFSPlusCatalogFolder* parentFolder = NULL; record = getRecordFromPath3(fileName, volume, NULL, &key, TRUE, FALSE, kHFSRootFolderID); if(record != NULL) { parentFolder = (HFSPlusCatalogFolder*) getRecordByCNID(key.parentID, volume); if(parentFolder != NULL) { if(parentFolder->recordType != kHFSPlusFolderRecord) { ASSERT(FALSE, "parent not folder"); free(parentFolder); return FALSE; } } else { ASSERT(FALSE, "can't find parent"); return FALSE; } if(record->recordType == kHFSPlusFileRecord) { XAttrList* next, *attrs; io = openRawFile(((HFSPlusCatalogFile*)record)->fileID, &((HFSPlusCatalogFile*)record)->dataFork, record, volume); allocate((RawFile*)io->data, 0); CLOSE(io); removeFromBTree(volume->catalogTree, (BTKey*)(&key)); attrs = getAllExtendedAttributes(((HFSPlusCatalogFile*)record)->fileID, volume); if(attrs != NULL) { while(attrs != NULL) { next = attrs->next; unsetAttribute(volume, ((HFSPlusCatalogFile*)record)->fileID, attrs->name); free(attrs->name); free(attrs); attrs = next; } } key.nodeName.length = 0; key.parentID = ((HFSPlusCatalogFile*)record)->fileID; key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length); removeFromBTree(volume->catalogTree, (BTKey*)(&key)); volume->volumeHeader->fileCount--; } else { if(((HFSPlusCatalogFolder*)record)->valence > 0) { free(record); free(parentFolder); ASSERT(FALSE, "folder not empty"); return FALSE; } else { XAttrList *next, *attrs; removeFromBTree(volume->catalogTree, (BTKey*)(&key)); attrs = getAllExtendedAttributes(((HFSPlusCatalogFolder*)record)->folderID, volume); if(attrs != NULL) { while(attrs != NULL) { next = attrs->next; unsetAttribute(volume, ((HFSPlusCatalogFolder*)record)->folderID, attrs->name); free(attrs->name); free(attrs); attrs = next; } } key.nodeName.length = 0; key.parentID = ((HFSPlusCatalogFolder*)record)->folderID; key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length); removeFromBTree(volume->catalogTree, (BTKey*)(&key)); } parentFolder->folderCount--; volume->volumeHeader->folderCount--; } parentFolder->valence--; updateCatalog(volume, (HFSPlusCatalogRecord*) parentFolder); updateVolume(volume); free(record); free(parentFolder); return TRUE; } else { if(parentFolder) free(parentFolder); ASSERT(FALSE, "cannot find record"); return FALSE; } }
int move(const char* source, const char* dest, Volume* volume) { HFSPlusCatalogRecord* srcRec; HFSPlusCatalogFolder* srcFolderRec; HFSPlusCatalogFolder* destRec; char* destPath; char* destName; char* curChar; char* lastSeparator; int i; int threadLength; HFSPlusCatalogKey srcKey; HFSPlusCatalogKey destKey; HFSPlusCatalogThread* thread; srcRec = getRecordFromPath3(source, volume, NULL, &srcKey, TRUE, FALSE, kHFSRootFolderID); if(srcRec == NULL) { free(srcRec); return FALSE; } srcFolderRec = (HFSPlusCatalogFolder*) getRecordByCNID(srcKey.parentID, volume); if(srcFolderRec == NULL || srcFolderRec->recordType != kHFSPlusFolderRecord) { free(srcRec); free(srcFolderRec); return FALSE; } destPath = strdup(dest); curChar = destPath; lastSeparator = NULL; while((*curChar) != '\0') { if((*curChar) == '/') lastSeparator = curChar; curChar++; } if(lastSeparator == NULL) { destRec = (HFSPlusCatalogFolder*) getRecordFromPath("/", volume, NULL, NULL); destName = destPath; } else { destName = lastSeparator + 1; *lastSeparator = '\0'; destRec = (HFSPlusCatalogFolder*) getRecordFromPath(destPath, volume, NULL, NULL); if(destRec == NULL || destRec->recordType != kHFSPlusFolderRecord) { free(destPath); free(srcRec); free(destRec); free(srcFolderRec); return FALSE; } } removeFromBTree(volume->catalogTree, (BTKey*)(&srcKey)); srcKey.nodeName.length = 0; if(srcRec->recordType == kHFSPlusFolderRecord) { srcKey.parentID = ((HFSPlusCatalogFolder*)srcRec)->folderID; } else if(srcRec->recordType == kHFSPlusFileRecord) { srcKey.parentID = ((HFSPlusCatalogFile*)srcRec)->fileID; } else { /* unexpected */ return FALSE; } srcKey.keyLength = sizeof(srcKey.parentID) + sizeof(srcKey.nodeName.length); removeFromBTree(volume->catalogTree, (BTKey*)(&srcKey)); destKey.nodeName.length = strlen(destName); threadLength = sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint16_t) + (sizeof(uint16_t) * destKey.nodeName.length); thread = (HFSPlusCatalogThread*) malloc(threadLength); thread->reserved = 0; destKey.parentID = destRec->folderID; thread->parentID = destKey.parentID; thread->nodeName.length = destKey.nodeName.length; for(i = 0; i < destKey.nodeName.length; i++) { destKey.nodeName.unicode[i] = destName[i]; thread->nodeName.unicode[i] = destName[i]; } destKey.keyLength = sizeof(uint32_t) + sizeof(uint16_t) + (sizeof(uint16_t) * destKey.nodeName.length); switch(srcRec->recordType) { case kHFSPlusFolderRecord: thread->recordType = kHFSPlusFolderThreadRecord; flipCatalogFolder((HFSPlusCatalogFolder*)srcRec); addToBTree(volume->catalogTree, (BTKey*)(&destKey), sizeof(HFSPlusCatalogFolder), (unsigned char *)(srcRec)); break; case kHFSPlusFileRecord: thread->recordType = kHFSPlusFileThreadRecord; flipCatalogFile((HFSPlusCatalogFile*)srcRec); addToBTree(volume->catalogTree, (BTKey*)(&destKey), sizeof(HFSPlusCatalogFile), (unsigned char *)(srcRec)); break; } destKey.nodeName.length = 0; destKey.parentID = srcKey.parentID; destKey.keyLength = sizeof(destKey.parentID) + sizeof(destKey.nodeName.length); flipCatalogThread(thread, TRUE); addToBTree(volume->catalogTree, (BTKey*)(&destKey), threadLength, (unsigned char *)(thread)); /* adjust valence */ srcFolderRec->valence--; updateCatalog(volume, (HFSPlusCatalogRecord*) srcFolderRec); destRec->valence++; updateCatalog(volume, (HFSPlusCatalogRecord*) destRec); free(thread); free(destPath); free(srcRec); free(destRec); free(srcFolderRec); return TRUE; }