1/*
2 * Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
3 * This file may be used under the terms of the MIT License.
4 */
5
6
7#include <dirent.h>
8#include <unistd.h>
9#include <stdio.h>
10#include <string.h>
11
12#include <Entry.h>
13#include <File.h>
14#include <fs_attr.h>
15#include <TypeConstants.h>
16
17
18const char* kTempFile = "/tmp/bfs_attribute_iterator_test";
19
20bool gVerbose;
21
22
23bool
24is_marker(const char* name)
25{
26	return strstr(name, ":marker") != NULL;
27}
28
29
30int32
31attribute_index(const char* name)
32{
33	int32 number;
34	if (sscanf(name, "test:%ld", &number) == 1)
35		return number;
36
37	return 0;
38}
39
40
41void
42add_attributes(BFile& file, int32 start, int32 count)
43{
44	for (int32 index = start; index < start + count; index++) {
45		char name[B_ATTR_NAME_LENGTH];
46		snprintf(name, sizeof(name), "test:%ld", index);
47		file.WriteAttr(name, B_INT32_TYPE, 0, &index, sizeof(int32));
48	}
49}
50
51
52void
53remove_attributes(BFile& file, int32 start, int32 count)
54{
55	for (int32 index = start; index < start + count; index++) {
56		char name[B_ATTR_NAME_LENGTH];
57		snprintf(name, sizeof(name), "test:%ld", index);
58		file.RemoveAttr(name);
59	}
60}
61
62
63void
64add_marker_attribute(BFile& file, int32 index)
65{
66	char name[B_ATTR_NAME_LENGTH];
67	snprintf(name, sizeof(name), "test:%ld:marker", index);
68	file.WriteAttr(name, B_INT32_TYPE, 0, &index, sizeof(int32));
69}
70
71
72void
73remove_marker_attribute(BFile& file, int32 index)
74{
75	char name[B_ATTR_NAME_LENGTH];
76	snprintf(name, sizeof(name), "test:%ld:marker", index);
77	file.RemoveAttr(name);
78}
79
80
81void
82test_remove_attributes(BFile& file, int32 start, int32 count, int32 removeAt,
83	int32 removeIndex1, int32 removeIndex2)
84{
85	int fd = file.Dup();
86	if (fd < 0)
87		return;
88
89	int32 index = 0;
90	bool seen[4096] = {0};
91
92	if (gVerbose)
93		printf("test removeAt %ld\n", removeAt);
94
95	DIR* dir = fs_fopen_attr_dir(fd);
96	while (struct dirent* entry = fs_read_attr_dir(dir)) {
97		if (gVerbose)
98			printf("  %ld. %s\n", index, entry->d_name);
99		if (index == removeAt) {
100			if (removeIndex1 > 0)
101				remove_marker_attribute(file, removeIndex1);
102			if (removeIndex2 > 0)
103				remove_marker_attribute(file, removeIndex2);
104		}
105		index++;
106
107		if (is_marker(entry->d_name))
108			continue;
109
110		int32 attributeIndex = attribute_index(entry->d_name);
111		if (attributeIndex > 0) {
112			if (seen[attributeIndex]) {
113				printf("attribute index %ld already listed!\n", attributeIndex);
114				exit(1);
115			} else
116				seen[attributeIndex] = true;
117		}
118	}
119
120	fs_close_attr_dir(dir);
121	close(fd);
122
123	for (int32 i = start; i < start + count; i++) {
124		if (!seen[i]) {
125			printf("attribute index %ld not listed, saw only %ld/%ld!\n", i,
126				index, count);
127			exit(1);
128		}
129	}
130}
131
132
133void
134test_add_attributes(BFile& file, int32 start, int32 count, int32 addAt,
135	int32 addIndex1, int32 addIndex2)
136{
137	int fd = file.Dup();
138	if (fd < 0)
139		return;
140
141	int32 index = 0;
142	bool seen[4096] = {0};
143
144	if (gVerbose)
145		printf("test addAt %ld\n", addAt);
146
147	DIR* dir = fs_fopen_attr_dir(fd);
148	while (struct dirent* entry = fs_read_attr_dir(dir)) {
149		if (gVerbose)
150			printf("  %ld. %s\n", index, entry->d_name);
151		if (index == addAt) {
152			if (addIndex1 > 0)
153				add_marker_attribute(file, addIndex1);
154			if (addIndex2 > 0)
155				add_marker_attribute(file, addIndex2);
156		}
157		index++;
158
159		if (is_marker(entry->d_name))
160			continue;
161
162		int32 attributeIndex = attribute_index(entry->d_name);
163		if (attributeIndex > 0) {
164			if (seen[attributeIndex]) {
165				printf("attribute index %ld already listed!\n", attributeIndex);
166				exit(1);
167			} else
168				seen[attributeIndex] = true;
169		}
170	}
171
172	fs_close_attr_dir(dir);
173	close(fd);
174
175	for (int32 i = start; i < start + count; i++) {
176		if (!seen[i]) {
177			printf("attribute index %ld not listed, saw only %ld/%ld!\n", i,
178				index, count);
179			exit(1);
180		}
181	}
182}
183
184
185int
186main(int argc, char** argv)
187{
188	if (argc > 1 && !strcmp(argv[1], "-v"))
189		gVerbose = true;
190
191	BFile file;
192	status_t status = file.SetTo(kTempFile, B_CREATE_FILE | B_READ_WRITE);
193	if (status != B_OK) {
194		fprintf(stderr, "Could not create temporary file: %s\n",
195			strerror(status));
196		return 1;
197	}
198
199	puts("--------- Remove Tests ----------");
200
201	// remove test, many attributes
202
203	puts("Test 1...");
204
205	for (int32 count = 5; count <= 100; count += 5) {
206		add_attributes(file, 1, count);
207		add_marker_attribute(file, count);
208		add_attributes(file, count + 1, count);
209
210		test_remove_attributes(file, 1, count,
211			count & 1 ? count - 1 : count + 1, count, -1);
212
213		remove_attributes(file, 1, count * 2);
214	}
215
216	// remove test, all positions
217
218	puts("Test 2...");
219
220	for (int32 i = 1; i < 100; i++) {
221		add_attributes(file, 1, 50);
222		add_marker_attribute(file, 51);
223		add_attributes(file, 51, 50);
224
225		test_remove_attributes(file, 1, 100, i, 51, -1);
226
227		remove_attributes(file, 1, 100);
228	}
229
230	// remove test, all positions, remove many
231
232	puts("Test 3...");
233
234	for (int32 i = 1; i < 100; i++) {
235		add_attributes(file, 1, 33);
236		add_marker_attribute(file, 33);
237		add_attributes(file, 34, 34);
238		add_marker_attribute(file, 67);
239		add_attributes(file, 68, 33);
240
241		test_remove_attributes(file, 1, 100, i, 33, 67);
242
243		remove_attributes(file, 1, 100);
244	}
245
246	puts("--------- Add Tests ----------");
247
248	// add test, many attributes
249
250	puts("Test 4...");
251
252	for (int32 count = 10; count <= 200; count += 10) {
253		add_attributes(file, 1, count);
254
255		int32 half = count / 2;
256
257		test_add_attributes(file, 1, count,
258			half & 1 ? half - 1 : half + 1, half - 2, half + 2);
259
260		remove_attributes(file, 1, count);
261	}
262
263	// add test, all iterator positions
264
265	puts("Test 5...");
266
267	for (int32 i = 1; i < 100; i++) {
268		add_attributes(file, 1, 100);
269
270		test_add_attributes(file, 1, 100, i, 50, -1);
271
272		remove_attributes(file, 1, 100);
273	}
274
275	// add test, all attribute positions
276
277	puts("Test 6...");
278
279	for (int32 i = 1; i < 100; i++) {
280		add_attributes(file, 1, 100);
281
282		test_add_attributes(file, 1, 100, 50, i, -1);
283
284		remove_attributes(file, 1, 100);
285	}
286
287	// add test, many attributes
288
289	puts("Test 7...");
290
291	for (int32 i = 1; i < 100; i++) {
292		add_attributes(file, 1, 100);
293
294		test_add_attributes(file, 1, 100, i, 33, 67);
295
296		remove_attributes(file, 1, 100);
297	}
298
299	// add test, many attributes
300
301	puts("Test 8...");
302
303	for (int32 i = 1; i < 100; i++) {
304		add_attributes(file, 1, 100);
305
306		test_add_attributes(file, 1, 100, 50, i - 1, i + 1);
307
308		remove_attributes(file, 1, 100);
309	}
310
311	BEntry entry;
312	if (entry.SetTo(kTempFile) == B_OK)
313		entry.Remove();
314
315	return 0;
316}
317