/* * Copyright 2009, Haiku Inc. All rights reserved. * Distributed under the terms of the MIT License. * * Authors: * Michael Lotz */ #include #include #include #include #include #include #include #include #define ATTRIBUTE_FILE_MAGIC 'attr' #define ATTRIBUTE_DIR_NAME "_HAIKU" #define COPY_BUFFER_SIZE 128 * 1024 struct attribute_file { uint32 magic; // 'attr' uint32 entry_count; uint8 entries[1]; } _PACKED; struct attribute_entry { type_code type; uint32 size; uint8 name_length; // including 0 byte char name[1]; // 0 terminated, followed by data } _PACKED; void recurse_directory(BDirectory &directory, uint8 *copyBuffer) { BNode node; entry_ref ref; BDirectory attributeDir; bool attributeDirCreated = false; char nameBuffer[B_FILE_NAME_LENGTH]; directory.Rewind(); while (directory.GetNextRef(&ref) == B_OK) { if (strcmp(ref.name, ATTRIBUTE_DIR_NAME) == 0) continue; if (node.SetTo(&ref) != B_OK) { printf("failed to set node to ref \"%s\"\n", ref.name); continue; } node.RewindAttrs(); BFile attributeFile; uint32 attributeCount = 0; while (node.GetNextAttrName(nameBuffer) == B_OK) { attr_info info; if (node.GetAttrInfo(nameBuffer, &info) != B_OK) { printf("failed to get attr info of \"%s\" on file \"%s\"\n", nameBuffer, ref.name); continue; } if (attributeCount == 0) { if (!attributeDirCreated) { directory.CreateDirectory(ATTRIBUTE_DIR_NAME, NULL); if (!directory.Contains(ATTRIBUTE_DIR_NAME, B_DIRECTORY_NODE)) { printf("attribute store directory not available\n"); return; } attributeDir.SetTo(&directory, ATTRIBUTE_DIR_NAME); attributeDirCreated = true; } attributeDir.CreateFile(ref.name, NULL); if (attributeFile.SetTo(&attributeDir, ref.name, B_WRITE_ONLY | B_ERASE_FILE) != B_OK) { printf("cannot open attribute file for writing\n"); break; } attributeFile.Seek(sizeof(attribute_file) - 1, SEEK_SET); } attribute_entry entry; entry.type = info.type; entry.size = info.size; entry.name_length = strlen(nameBuffer) + 1; attributeFile.Write(&entry, sizeof(attribute_entry) - 1); attributeFile.Write(nameBuffer, entry.name_length); off_t offset = 0; while (info.size > 0) { size_t copySize = min_c(info.size, COPY_BUFFER_SIZE); if (node.ReadAttr(nameBuffer, info.type, offset, copyBuffer, copySize) < B_OK) { printf("error reading attribute \"%s\" of file \"%s\"\n", nameBuffer, ref.name); return; } attributeFile.Write(copyBuffer, copySize); info.size -= COPY_BUFFER_SIZE; offset += COPY_BUFFER_SIZE; } attributeCount++; } if (attributeCount > 0) { attribute_file file; file.magic = ATTRIBUTE_FILE_MAGIC; file.entry_count = attributeCount; attributeFile.WriteAt(0, &file, sizeof(attribute_file) - 1); } if (node.IsDirectory()) { BDirectory subDirectory(&ref); recurse_directory(subDirectory, copyBuffer); } } } int main(int argc, char *argv[]) { if (argc < 2) { printf("usage: %s \n", argv[0]); return 1; } uint8 *copyBuffer = (uint8 *)malloc(COPY_BUFFER_SIZE); if (copyBuffer == NULL) { printf("cannot allocate copy buffer\n"); return 2; } BDirectory root(argv[1]); recurse_directory(root, copyBuffer); free(copyBuffer); return 0; }