1 /* 2 * Copyright 2009, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 12 #include <fs_attr.h> 13 14 #include <Directory.h> 15 #include <Entry.h> 16 #include <File.h> 17 #include <Node.h> 18 19 20 #define ATTRIBUTE_FILE_MAGIC 'attr' 21 #define ATTRIBUTE_DIR_NAME "_HAIKU" 22 #define COPY_BUFFER_SIZE 128 * 1024 23 24 25 struct attribute_file { 26 uint32 magic; // 'attr' 27 uint32 entry_count; 28 uint8 entries[1]; 29 } _PACKED; 30 31 32 struct attribute_entry { 33 type_code type; 34 uint32 size; 35 uint8 name_length; // including 0 byte 36 char name[1]; // 0 terminated, followed by data 37 } _PACKED; 38 39 40 void 41 recurse_directory(BDirectory &directory, uint8 *copyBuffer) 42 { 43 BNode node; 44 entry_ref ref; 45 BDirectory attributeDir; 46 bool attributeDirCreated = false; 47 char nameBuffer[B_FILE_NAME_LENGTH]; 48 directory.Rewind(); 49 50 while (directory.GetNextRef(&ref) == B_OK) { 51 if (strcmp(ref.name, ATTRIBUTE_DIR_NAME) == 0) 52 continue; 53 54 if (node.SetTo(&ref) != B_OK) { 55 printf("failed to set node to ref \"%s\"\n", ref.name); 56 continue; 57 } 58 59 node.RewindAttrs(); 60 BFile attributeFile; 61 uint32 attributeCount = 0; 62 while (node.GetNextAttrName(nameBuffer) == B_OK) { 63 attr_info info; 64 if (node.GetAttrInfo(nameBuffer, &info) != B_OK) { 65 printf("failed to get attr info of \"%s\" on file \"%s\"\n", 66 nameBuffer, ref.name); 67 continue; 68 } 69 70 if (attributeCount == 0) { 71 if (!attributeDirCreated) { 72 directory.CreateDirectory(ATTRIBUTE_DIR_NAME, NULL); 73 if (!directory.Contains(ATTRIBUTE_DIR_NAME, 74 B_DIRECTORY_NODE)) { 75 printf("attribute store directory not available\n"); 76 return; 77 } 78 79 attributeDir.SetTo(&directory, ATTRIBUTE_DIR_NAME); 80 attributeDirCreated = true; 81 } 82 83 attributeDir.CreateFile(ref.name, NULL); 84 if (attributeFile.SetTo(&attributeDir, ref.name, 85 B_WRITE_ONLY | B_ERASE_FILE) != B_OK) { 86 printf("cannot open attribute file for writing\n"); 87 break; 88 } 89 90 attributeFile.Seek(sizeof(attribute_file) - 1, SEEK_SET); 91 } 92 93 attribute_entry entry; 94 entry.type = info.type; 95 entry.size = info.size; 96 entry.name_length = strlen(nameBuffer) + 1; 97 attributeFile.Write(&entry, sizeof(attribute_entry) - 1); 98 attributeFile.Write(nameBuffer, entry.name_length); 99 100 off_t offset = 0; 101 while (info.size > 0) { 102 size_t copySize = min_c(info.size, COPY_BUFFER_SIZE); 103 if (node.ReadAttr(nameBuffer, info.type, offset, copyBuffer, 104 copySize) < B_OK) { 105 printf("error reading attribute \"%s\" of file \"%s\"\n", 106 nameBuffer, ref.name); 107 return; 108 } 109 110 attributeFile.Write(copyBuffer, copySize); 111 info.size -= COPY_BUFFER_SIZE; 112 offset += COPY_BUFFER_SIZE; 113 } 114 115 attributeCount++; 116 } 117 118 if (attributeCount > 0) { 119 attribute_file file; 120 file.magic = ATTRIBUTE_FILE_MAGIC; 121 file.entry_count = attributeCount; 122 attributeFile.WriteAt(0, &file, sizeof(attribute_file) - 1); 123 } 124 125 if (node.IsDirectory()) { 126 BDirectory subDirectory(&ref); 127 recurse_directory(subDirectory, copyBuffer); 128 } 129 } 130 } 131 132 133 int 134 main(int argc, char *argv[]) 135 { 136 if (argc < 2) { 137 printf("usage: %s <root directory>\n", argv[0]); 138 return 1; 139 } 140 141 uint8 *copyBuffer = (uint8 *)malloc(COPY_BUFFER_SIZE); 142 if (copyBuffer == NULL) { 143 printf("cannot allocate copy buffer\n"); 144 return 2; 145 } 146 147 BDirectory root(argv[1]); 148 recurse_directory(root, copyBuffer); 149 150 free(copyBuffer); 151 return 0; 152 } 153