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