wchar_t * StrToUnicode( const char *buf ) { wchar_t unibuf[1024]; ASCIIToUnicode( buf, unibuf, sizeof(unibuf) ); return _wcsdup( unibuf ); }
int setAttribute(Volume* volume, uint32_t fileID, const char* name, uint8_t* data, size_t size) { HFSPlusAttrKey key; HFSPlusAttrData* record; int ret, exact; 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); record = (HFSPlusAttrData*) malloc(sizeof(HFSPlusAttrData) + size); memset(record, 0, sizeof(HFSPlusAttrData)); record->recordType = kHFSPlusAttrInlineData; record->size = size; memcpy(record->data, data, size); ret = updateAttributes(volume, &key, (HFSPlusAttrRecord*) record); free(record); return ret; }
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 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)); }
size_t getAttribute(Volume* volume, uint32_t fileID, const char* name, uint8_t** data) { HFSPlusAttrKey key; HFSPlusAttrRecord* record; size_t size; int exact; 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); *data = NULL; record = (HFSPlusAttrRecord*) search(volume->attrTree, (BTKey*)(&key), &exact, NULL, NULL); if(exact == FALSE) { if(record) free(record); return 0; } switch(record->recordType) { case kHFSPlusAttrInlineData: size = record->attrData.size; *data = (uint8_t*) malloc(size); memcpy(*data, record->attrData.data, size); free(record); return size; default: fprintf(stderr, "unsupported attribute node format\n"); return 0; } }
HFSCatalogNodeID newFolder(const char* pathName, Volume* volume) { HFSPlusCatalogFolder* parentFolder; HFSPlusCatalogFolder folder; HFSPlusCatalogKey key; HFSPlusCatalogThread thread; uint32_t newFolderID; 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; } newFolderID = volume->volumeHeader->nextCatalogID++; volume->volumeHeader->folderCount++; folder.recordType = kHFSPlusFolderRecord; folder.flags = kHFSHasFolderCountMask; folder.valence = 0; folder.folderID = newFolderID; folder.createDate = UNIX_TO_APPLE_TIME(time(NULL)); folder.contentModDate = folder.createDate; folder.attributeModDate = folder.createDate; folder.accessDate = folder.createDate; folder.backupDate = folder.createDate; folder.permissions.ownerID = parentFolder->permissions.ownerID; folder.permissions.groupID = parentFolder->permissions.groupID; folder.permissions.adminFlags = 0; folder.permissions.ownerFlags = 0; folder.permissions.fileMode = S_IFDIR | S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; folder.permissions.special.iNodeNum = 0; memset(&folder.userInfo, 0, sizeof(folder.userInfo)); memset(&folder.finderInfo, 0, sizeof(folder.finderInfo)); folder.textEncoding = 0; folder.folderCount = 0; key.parentID = parentFolder->folderID; ASCIIToUnicode(name, &key.nodeName); key.keyLength = sizeof(key.parentID) + STR_SIZE(key.nodeName); thread.recordType = kHFSPlusFolderThreadRecord; 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); flipCatalogFolder(&folder); ASSERT(addToBTree(volume->catalogTree, (BTKey*)(&key), sizeof(HFSPlusCatalogFolder), (unsigned char *)(&folder)), "addToBTree"); key.nodeName.length = 0; key.parentID = newFolderID; key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length); ASSERT(addToBTree(volume->catalogTree, (BTKey*)(&key), threadLength, (unsigned char *)(&thread)), "addToBTree"); parentFolder->folderCount++; parentFolder->valence++; updateCatalog(volume, (HFSPlusCatalogRecord*) parentFolder); updateVolume(volume); free(parentFolder); free(path); return newFolderID; }
HFSPlusCatalogRecord* getRecordFromPath3(const char* path, Volume* volume, char **name, HFSPlusCatalogKey* retKey, char traverse, char returnLink, HFSCatalogNodeID parentID) { HFSPlusCatalogKey key; HFSPlusCatalogRecord* record; char* origPath; char* myPath; char* word; char* pathLimit; uint32_t realParent; int exact; if(path[0] == '\0' || (path[0] == '/' && path[1] == '\0')) { if(name != NULL) *name = (char*)path; key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length); key.parentID = kHFSRootFolderID; key.nodeName.length = 0; record = (HFSPlusCatalogRecord*) search(volume->catalogTree, (BTKey*)(&key), &exact, NULL, NULL); key.parentID = ((HFSPlusCatalogThread*)record)->parentID; key.nodeName = ((HFSPlusCatalogThread*)record)->nodeName; free(record); record = (HFSPlusCatalogRecord*) search(volume->catalogTree, (BTKey*)(&key), &exact, NULL, NULL); return record; } myPath = strdup(path); origPath = myPath; record = NULL; if(path[0] == '/') { key.parentID = kHFSRootFolderID; } else { key.parentID = parentID; } pathLimit = myPath + strlen(myPath); for(word = (char*)strtok(myPath, "/"); word && (word < pathLimit); word = ((word + strlen(word) + 1) < pathLimit) ? (char*)strtok(word + strlen(word) + 1, "/") : NULL) { if(name != NULL) *name = (char*)(path + (word - origPath)); if(record != NULL) { free(record); record = NULL; } if(word[0] == '\0') { continue; } ASCIIToUnicode(word, &key.nodeName); key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length) + (sizeof(uint16_t) * key.nodeName.length); record = (HFSPlusCatalogRecord*) search(volume->catalogTree, (BTKey*)(&key), &exact, NULL, NULL); if(record == NULL || exact == FALSE) { free(origPath); if(record != NULL) { free(record); } return NULL; } if(traverse) { if(((word + strlen(word) + 1) < pathLimit) || returnLink) { record = getLinkTarget(record, key.parentID, &key, volume); if(record == NULL || exact == FALSE) { free(origPath); return NULL; } } } if(record->recordType == kHFSPlusFileRecord) { if((word + strlen(word) + 1) >= pathLimit) { free(origPath); if(retKey != NULL) { memcpy(retKey, &key, sizeof(HFSPlusCatalogKey)); } return record; } else { free(origPath); free(record); return NULL; } } if(record->recordType != kHFSPlusFolderRecord) hfs_panic("inconsistent catalog tree!"); realParent = key.parentID; key.parentID = ((HFSPlusCatalogFolder*)record)->folderID; } if(retKey != NULL) { memcpy(retKey, &key, sizeof(HFSPlusCatalogKey)); retKey->parentID = realParent; } free(origPath); return record; }
CatalogRecordList* getFolderContents(HFSCatalogNodeID CNID, Volume* volume) { BTree* tree; HFSPlusCatalogThread* record; HFSPlusCatalogKey key; uint32_t nodeNumber; int recordNumber; BTNodeDescriptor* descriptor; off_t recordOffset; off_t recordDataOffset; HFSPlusCatalogKey* currentKey; CatalogRecordList* list; CatalogRecordList* lastItem; CatalogRecordList* item; char pathBuffer[1024]; HFSPlusCatalogRecord* toReturn; HFSPlusCatalogKey nkey; int exact; tree = volume->catalogTree; key.keyLength = sizeof(key.parentID) + sizeof(key.nodeName.length); key.parentID = CNID; key.nodeName.length = 0; list = NULL; record = (HFSPlusCatalogThread*) search(tree, (BTKey*)(&key), NULL, &nodeNumber, &recordNumber); if(record == NULL) return NULL; free(record); ++recordNumber; while(nodeNumber != 0) { descriptor = readBTNodeDescriptor(nodeNumber, tree); while(recordNumber < descriptor->numRecords) { recordOffset = getRecordOffset(recordNumber, nodeNumber, tree); currentKey = (HFSPlusCatalogKey*) READ_KEY(tree, recordOffset, tree->io); recordDataOffset = recordOffset + currentKey->keyLength + sizeof(currentKey->keyLength); if(currentKey->parentID == CNID) { item = (CatalogRecordList*) malloc(sizeof(CatalogRecordList)); item->name = currentKey->nodeName; item->record = (HFSPlusCatalogRecord*) READ_DATA(tree, recordDataOffset, tree->io); if(item->record->recordType == kHFSPlusFileRecord && (((HFSPlusCatalogFile*)item->record)->userInfo.fileType) == kHardLinkFileType) { sprintf(pathBuffer, "iNode%d", ((HFSPlusCatalogFile*)item->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(item->record); item->record = toReturn; } item->next = NULL; if(list == NULL) { list = item; } else { lastItem->next = item; } lastItem = item; free(currentKey); } else { free(currentKey); free(descriptor); return list; } recordNumber++; } nodeNumber = descriptor->fLink; recordNumber = 0; free(descriptor); } return list; }