xref: /haiku/src/tools/generate_attribute_stores.cpp (revision 508f54795f39c3e7552d87c95aae9dd8ec6f505b)
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