HFSPlusCatalogRecord* getLinkTarget(HFSPlusCatalogRecord* record, HFSCatalogNodeID parentID, HFSPlusCatalogKey *key, Volume* volume) { io_func* io; char pathBuffer[1024]; HFSPlusCatalogRecord* toReturn; HFSPlusCatalogKey nkey; int exact; if(record->recordType == kHFSPlusFileRecord && (((HFSPlusCatalogFile*)record)->permissions.fileMode & S_IFLNK) == S_IFLNK) { io = openRawFile(((HFSPlusCatalogFile*)record)->fileID, &(((HFSPlusCatalogFile*)record)->dataFork), record, volume); READ(io, 0, (((HFSPlusCatalogFile*)record)->dataFork).logicalSize, pathBuffer); CLOSE(io); pathBuffer[(((HFSPlusCatalogFile*)record)->dataFork).logicalSize] = '\0'; toReturn = getRecordFromPath3(pathBuffer, volume, NULL, key, TRUE, TRUE, parentID); free(record); return toReturn; } else if(record->recordType == kHFSPlusFileRecord && (((HFSPlusCatalogFile*)record)->userInfo.fileType) == kHardLinkFileType) { sprintf(pathBuffer, "iNode%d", ((HFSPlusCatalogFile*)record)->permissions.special.iNodeNum); nkey.parentID = volume->metadataDir; ASCIIToUnicode(pathBuffer, &nkey.nodeName); nkey.keyLength = sizeof(nkey.parentID) + sizeof(nkey.nodeName.length) + (sizeof(uint16_t) * nkey.nodeName.length); toReturn = (HFSPlusCatalogRecord*) search(volume->catalogTree, (BTKey*)(&nkey), &exact, NULL, NULL); free(record); return toReturn; } else { return record; } }
int makeSymlink(const char* pathName, const char* target, Volume* volume) { io_func* io; HFSPlusCatalogFile* record; record = (HFSPlusCatalogFile*) getRecordFromPath3(pathName, volume, NULL, NULL, TRUE, FALSE, kHFSRootFolderID); if(!record) { newFile(pathName, volume); record = (HFSPlusCatalogFile*) getRecordFromPath(pathName, volume, NULL, NULL); if(!record) { return FALSE; } record->permissions.fileMode |= S_IFLNK; record->userInfo.fileType = kSymLinkFileType; record->userInfo.fileCreator = kSymLinkCreator; updateCatalog(volume, (HFSPlusCatalogRecord*) record); } else { if(record->recordType != kHFSPlusFileRecord || (((HFSPlusCatalogFile*)record)->permissions.fileMode & S_IFLNK) != S_IFLNK) { free(record); return FALSE; } } io = openRawFile(record->fileID, &record->dataFork, (HFSPlusCatalogRecord*) record, volume); WRITE(io, 0, strlen(target), (void*) target); CLOSE(io); free(record); return TRUE; }
HFSPlusCatalogRecord* getLinkTarget(HFSPlusCatalogRecord* record, HFSCatalogNodeID parentID, HFSPlusCatalogKey *key, Volume* volume) { io_func* io; char pathBuffer[1024]; HFSPlusCatalogRecord* toReturn; if(record->recordType == kHFSPlusFileRecord && (((HFSPlusCatalogFile*)record)->permissions.fileMode & S_IFLNK) == S_IFLNK) { io = openRawFile(((HFSPlusCatalogFile*)record)->fileID, &(((HFSPlusCatalogFile*)record)->dataFork), record, volume); READ(io, 0, (((HFSPlusCatalogFile*)record)->dataFork).logicalSize, pathBuffer); CLOSE(io); pathBuffer[(((HFSPlusCatalogFile*)record)->dataFork).logicalSize] = '\0'; toReturn = getRecordFromPath3(pathBuffer, volume, NULL, key, TRUE, TRUE, parentID); free(record); return toReturn; } else { return record; } }
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; }
HFSPlusCatalogRecord* getRecordFromPath2(const char* path, Volume* volume, char **name, HFSPlusCatalogKey* retKey, char traverse) { return getRecordFromPath3(path, volume, name, retKey, TRUE, TRUE, kHFSRootFolderID); }
void hfs_untar(Volume* volume, AbstractFile* tarFile) { size_t tarSize = tarFile->getLength(tarFile); size_t curRecord = 0; char block[512]; while(curRecord < tarSize) { tarFile->seek(tarFile, curRecord); tarFile->read(tarFile, block, 512); uint32_t mode = 0; char* fileName = NULL; const char* target = NULL; uint32_t type = 0; uint32_t size; uint32_t uid; uint32_t gid; sscanf(&block[100], "%o", &mode); fileName = &block[0]; sscanf(&block[156], "%o", &type); target = &block[157]; sscanf(&block[124], "%o", &size); sscanf(&block[108], "%o", &uid); sscanf(&block[116], "%o", &gid); if(fileName[0] == '\0') break; if(fileName[0] == '.' && fileName[1] == '/') { fileName += 2; } if(fileName[0] == '\0') goto loop; if(fileName[strlen(fileName) - 1] == '/') fileName[strlen(fileName) - 1] = '\0'; HFSPlusCatalogRecord* record = getRecordFromPath3(fileName, volume, NULL, NULL, TRUE, FALSE, kHFSRootFolderID); if(record) { if(record->recordType == kHFSPlusFolderRecord || type == 5) { if(!silence) printf("ignoring %s, type = %d\n", fileName, type); free(record); goto loop; } else { printf("replacing %s\n", fileName); free(record); removeFile(fileName, volume); } } if(type == 0) { if(!silence) printf("file: %s (%04o), size = %d\n", fileName, mode, size); void* buffer = malloc(size); tarFile->seek(tarFile, curRecord + 512); tarFile->read(tarFile, buffer, size); AbstractFile* inFile = createAbstractFileFromMemory(&buffer, size); add_hfs(volume, inFile, fileName); free(buffer); } else if(type == 5) { if(!silence) printf("directory: %s (%04o)\n", fileName, mode); newFolder(fileName, volume); } else if(type == 2) { if(!silence) printf("symlink: %s (%04o) -> %s\n", fileName, mode, target); makeSymlink(fileName, target, volume); } chmodFile(fileName, mode, volume); chownFile(fileName, uid, gid, volume); loop: curRecord = (curRecord + 512) + ((size + 511) / 512 * 512); } }