static BTKey* catalogDataRead(off_t offset, io_func* io) { int16_t recordType; HFSPlusCatalogRecord* record; uint16_t nameLength; if(!READ(io, offset, sizeof(int16_t), &recordType)) return NULL; FLIPENDIAN(recordType); fflush(stdout); switch(recordType) { case kHFSPlusFolderRecord: record = (HFSPlusCatalogRecord*) malloc(sizeof(HFSPlusCatalogFolder)); if(!READ(io, offset, sizeof(HFSPlusCatalogFolder), record)) return NULL; flipCatalogFolder((HFSPlusCatalogFolder*)record); break; case kHFSPlusFileRecord: record = (HFSPlusCatalogRecord*) malloc(sizeof(HFSPlusCatalogFile)); if(!READ(io, offset, sizeof(HFSPlusCatalogFile), record)) return NULL; flipCatalogFile((HFSPlusCatalogFile*)record); break; case kHFSPlusFolderThreadRecord: case kHFSPlusFileThreadRecord: record = (HFSPlusCatalogRecord*) malloc(sizeof(HFSPlusCatalogThread)); if(!READ(io, offset + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t), sizeof(uint16_t), &nameLength)) return NULL; FLIPENDIAN(nameLength); if(!READ(io, offset, sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint16_t) + (sizeof(uint16_t) * nameLength), record)) return NULL; flipCatalogThread((HFSPlusCatalogThread*)record, FALSE); break; } return (BTKey*)record; }
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; }
HFSCatalogNodeID newFile(const char* pathName, Volume* volume) { HFSPlusCatalogFolder* parentFolder; HFSPlusCatalogFile file; HFSPlusCatalogKey key; HFSPlusCatalogThread thread; uint32_t newFileID; int threadLength; char* path; char* name; char* curChar; char* lastSeparator; path = strdup(pathName); curChar = path; lastSeparator = NULL; while((*curChar) != '\0') { if((*curChar) == '/') lastSeparator = curChar; curChar++; } if(lastSeparator == NULL) { parentFolder = (HFSPlusCatalogFolder*) getRecordFromPath("/", volume, NULL, NULL); name = path; } else { name = lastSeparator + 1; *lastSeparator = '\0'; parentFolder = (HFSPlusCatalogFolder*) getRecordFromPath(path, volume, NULL, NULL); } if(parentFolder == NULL || parentFolder->recordType != kHFSPlusFolderRecord) { free(path); free(parentFolder); return FALSE; } newFileID = volume->volumeHeader->nextCatalogID++; volume->volumeHeader->fileCount++; file.recordType = kHFSPlusFileRecord; file.flags = kHFSThreadExistsMask; file.reserved1 = 0; file.fileID = newFileID; file.createDate = UNIX_TO_APPLE_TIME(time(NULL)); file.contentModDate = file.createDate; file.attributeModDate = file.createDate; file.accessDate = file.createDate; file.backupDate = file.createDate; file.permissions.ownerID = parentFolder->permissions.ownerID; file.permissions.groupID = parentFolder->permissions.groupID; file.permissions.adminFlags = 0; file.permissions.ownerFlags = 0; file.permissions.fileMode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; file.permissions.special.iNodeNum = 0; memset(&file.userInfo, 0, sizeof(file.userInfo)); memset(&file.finderInfo, 0, sizeof(file.finderInfo)); file.textEncoding = 0; file.reserved2 = 0; memset(&file.dataFork, 0, sizeof(file.dataFork)); memset(&file.resourceFork, 0, sizeof(file.resourceFork)); key.parentID = parentFolder->folderID; ASCIIToUnicode(name, &key.nodeName); key.keyLength = sizeof(key.parentID) + STR_SIZE(key.nodeName); thread.recordType = kHFSPlusFileThreadRecord; thread.reserved = 0; thread.parentID = parentFolder->folderID; ASCIIToUnicode(name, &thread.nodeName); threadLength = sizeof(thread.recordType) + sizeof(thread.reserved) + sizeof(thread.parentID) + STR_SIZE(thread.nodeName); flipCatalogThread(&thread, TRUE); flipCatalogFile(&file); ASSERT(addToBTree(volume->catalogTree, (BTKey*)(&key), sizeof(HFSPlusCatalogFile), (unsigned char *)(&file)), "addToBTree"); key.nodeName.length = 0; key.parentID = newFileID; key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length); ASSERT(addToBTree(volume->catalogTree, (BTKey*)(&key), threadLength, (unsigned char *)(&thread)), "addToBTree"); parentFolder->valence++; updateCatalog(volume, (HFSPlusCatalogRecord*) parentFolder); updateVolume(volume); free(parentFolder); free(path); return newFileID; }