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