1d31093e8SAxel Dörfler/*
2d31093e8SAxel Dörfler * Copyright 2009, Axel D��rfler, axeld@pinc-software.de.
3d31093e8SAxel Dörfler * Distributed under the terms of the MIT License.
4d31093e8SAxel Dörfler */
5d31093e8SAxel Dörfler
6d31093e8SAxel Dörfler
7d31093e8SAxel Dörfler#include <new>
8d31093e8SAxel Dörfler#include <string>
9d31093e8SAxel Dörfler#include <vector>
10d31093e8SAxel Dörfler
113b9dec1cSAxel Dörfler#include <dirent.h>
12d31093e8SAxel Dörfler#include <errno.h>
13d31093e8SAxel Dörfler#include <fcntl.h>
14d31093e8SAxel Dörfler#include <getopt.h>
15d31093e8SAxel Dörfler#include <stdio.h>
16d31093e8SAxel Dörfler#include <stdlib.h>
17d31093e8SAxel Dörfler#include <string.h>
18d31093e8SAxel Dörfler#include <sys/stat.h>
19d31093e8SAxel Dörfler#include <unistd.h>
20d31093e8SAxel Dörfler
21636ccbf3SAxel Dörfler#include <fs_attr.h>
22782bdb40SAxel Dörfler#include <fs_volume.h>
2397f89e03SAxel Dörfler#include <OS.h>
24636ccbf3SAxel Dörfler#include <TypeConstants.h>
25d31093e8SAxel Dörfler
26d31093e8SAxel Dörfler
27d31093e8SAxel Dörflerenum file_action {
28d31093e8SAxel Dörfler	kCreateFile,
29d31093e8SAxel Dörfler	kCreateDir,
30d31093e8SAxel Dörfler	kRenameFile,
31d31093e8SAxel Dörfler	kRemoveFile,
32d31093e8SAxel Dörfler	kRemoveDir,
33d31093e8SAxel Dörfler	kAppendFile,
34d31093e8SAxel Dörfler	kReplaceFile,
35d31093e8SAxel Dörfler	kTruncateFile,
36d31093e8SAxel Dörfler
37d31093e8SAxel Dörfler	kNumActions
38d31093e8SAxel Dörfler};
39d31093e8SAxel Dörfler
4097f89e03SAxel Dörflerstruct block_identifier {
4197f89e03SAxel Dörfler	off_t		offset;
4297f89e03SAxel Dörfler	uint32		identifier;
4397f89e03SAxel Dörfler	uint16		data[0];
4497f89e03SAxel Dörfler};
4597f89e03SAxel Dörfler
4697f89e03SAxel Dörflerstruct entry {
4797f89e03SAxel Dörfler	std::string	name;
4897f89e03SAxel Dörfler	uint32		identifier;
4997f89e03SAxel Dörfler	off_t		size;
5097f89e03SAxel Dörfler};
5197f89e03SAxel Dörfler
5297f89e03SAxel Dörflertypedef std::vector<entry> EntryVector;
53d31093e8SAxel Dörfler
54d31093e8SAxel Dörfler
553b9dec1cSAxel Dörflerconst char* kDefaultBaseDir = "./random_file_temp";
56636ccbf3SAxel Dörflerconst char* kIdentifierAttribute = "rfa:identifier";
573b9dec1cSAxel Dörfler
58d31093e8SAxel Dörflerconst uint32 kDefaultDirCount = 1;
59d31093e8SAxel Dörflerconst uint32 kDefaultFileCount = 10;
60d31093e8SAxel Dörflerconst uint32 kDefaultRunCount = 100;
61d31093e8SAxel Dörflerconst off_t kDefaultMaxFileSize = 32768;
62d31093e8SAxel Dörfler
63d31093e8SAxel Dörflerconst uint32 kMaxFileCount = 1000000;
64d31093e8SAxel Dörflerconst uint32 kMaxDirCount = 100000;
65d31093e8SAxel Dörfler
66d31093e8SAxel Dörflerconst uint32 kBlockSize = 256;
67d31093e8SAxel Dörfler
68d31093e8SAxel Dörfler
69d31093e8SAxel Dörflerextern const char *__progname;
70d31093e8SAxel Dörflerstatic const char *kProgramName = __progname;
71d31093e8SAxel Dörfler
72d31093e8SAxel Dörflerstatic bool sDisableFileCache = false;
73d31093e8SAxel Dörflerstatic bool sVerbose = false;
743ea61f1fSAxel Dörflerstatic bool sCheckBeforeRemove = false;
75d31093e8SAxel Dörflerstatic off_t sMaxFileSize = kDefaultMaxFileSize;
76d31093e8SAxel Dörflerstatic uint32 sCount = 0;
77d31093e8SAxel Dörfler
7897f89e03SAxel Dörflerstatic off_t sWriteTotal = 0;
7997f89e03SAxel Dörflerstatic off_t sReadTotal = 0;
8097f89e03SAxel Dörflerstatic bigtime_t sWriteTime = 0;
8197f89e03SAxel Dörflerstatic bigtime_t sReadTime = 0;
823b9dec1cSAxel Dörflerstatic uint32 sRun = 0;
8397f89e03SAxel Dörfler
84d31093e8SAxel Dörfler
85d31093e8SAxel Dörflerstatic off_t
8697f89e03SAxel Dörflerstring_to_size(const char* valueWithUnit)
87d31093e8SAxel Dörfler{
88d31093e8SAxel Dörfler	char* unit;
89d31093e8SAxel Dörfler	off_t size = strtoull(valueWithUnit, &unit, 10);
90d31093e8SAxel Dörfler
91d31093e8SAxel Dörfler	if (strchr(unit, 'G') || strchr(unit, 'g'))
92d31093e8SAxel Dörfler		size *= 1024 * 1024 * 1024;
93d31093e8SAxel Dörfler	else if (strchr(unit, 'M') || strchr(unit, 'm'))
94d31093e8SAxel Dörfler		size *= 1024 * 1024;
95d31093e8SAxel Dörfler	else if (strchr(unit, 'K') || strchr(unit, 'k'))
96d31093e8SAxel Dörfler		size *= 1024;
97d31093e8SAxel Dörfler
98d31093e8SAxel Dörfler	return size;
99d31093e8SAxel Dörfler}
100d31093e8SAxel Dörfler
101d31093e8SAxel Dörfler
10297f89e03SAxel Dörflerstatic std::string
10397f89e03SAxel Dörflersize_to_string(off_t size)
10497f89e03SAxel Dörfler{
10597f89e03SAxel Dörfler	char buffer[256];
10697f89e03SAxel Dörfler
107782bdb40SAxel Dörfler	if (size > 10LL * 1024 * 1024 * 1024) {
108782bdb40SAxel Dörfler		snprintf(buffer, sizeof(buffer), "%g GB",
109782bdb40SAxel Dörfler			size / (1024.0 * 1024 * 1024));
110782bdb40SAxel Dörfler	} else if (size > 10 * 1024 * 1024)
11197f89e03SAxel Dörfler		snprintf(buffer, sizeof(buffer), "%g MB", size / (1024.0 * 1024));
11297f89e03SAxel Dörfler	else if (size > 10 * 1024)
11397f89e03SAxel Dörfler		snprintf(buffer, sizeof(buffer), "%g KB", size / (1024.0));
11497f89e03SAxel Dörfler	else
11597f89e03SAxel Dörfler		snprintf(buffer, sizeof(buffer), "%lld B", size);
11697f89e03SAxel Dörfler
11797f89e03SAxel Dörfler	return buffer;
11897f89e03SAxel Dörfler}
11997f89e03SAxel Dörfler
12097f89e03SAxel Dörfler
12197f89e03SAxel Dörflerstatic std::string
12297f89e03SAxel Dörflertime_to_string(bigtime_t usecs)
12397f89e03SAxel Dörfler{
12497f89e03SAxel Dörfler	static const bigtime_t kSecond = 1000000ULL;
12597f89e03SAxel Dörfler	static const bigtime_t kHour = 3600 * kSecond;
12697f89e03SAxel Dörfler	static const bigtime_t kMinute = 60 * kSecond;
12797f89e03SAxel Dörfler
12897f89e03SAxel Dörfler	uint32 hours = usecs / kHour;
12997f89e03SAxel Dörfler	uint32 minutes = usecs / kMinute;
13097f89e03SAxel Dörfler	uint32 seconds = usecs / kSecond;
13197f89e03SAxel Dörfler
13297f89e03SAxel Dörfler	char buffer[256];
13397f89e03SAxel Dörfler	if (usecs >= kHour) {
13497f89e03SAxel Dörfler		minutes %= 60;
13597f89e03SAxel Dörfler		seconds %= 60;
13697f89e03SAxel Dörfler		snprintf(buffer, sizeof(buffer), "%luh %02lum %02lus", hours, minutes,
13797f89e03SAxel Dörfler			seconds);
13897f89e03SAxel Dörfler	} else if (usecs > 100 * kSecond) {
13997f89e03SAxel Dörfler		seconds %= 60;
14097f89e03SAxel Dörfler		snprintf(buffer, sizeof(buffer), "%lum %02lus", minutes, seconds);
14197f89e03SAxel Dörfler	} else
14297f89e03SAxel Dörfler		snprintf(buffer, sizeof(buffer), "%gs", 1.0 * usecs / kSecond);
14397f89e03SAxel Dörfler
14497f89e03SAxel Dörfler	return buffer;
14597f89e03SAxel Dörfler}
14697f89e03SAxel Dörfler
14797f89e03SAxel Dörfler
148d31093e8SAxel Dörflerstatic void
149d31093e8SAxel Dörflerusage(int status)
150d31093e8SAxel Dörfler{
151d31093e8SAxel Dörfler	fprintf(stderr,
152d31093e8SAxel Dörfler		"Usage: %s [options]\n"
15397f89e03SAxel Dörfler		"Performs some random file actions for file system testing.\n"
154d31093e8SAxel Dörfler		"\n"
15597f89e03SAxel Dörfler		"  -r, --runs=<count>\t\tThe number of actions to perform.\n"
15697f89e03SAxel Dörfler		"\t\t\t\tDefaults to %lu.\n"
15797f89e03SAxel Dörfler		"  -s, --seed=<seed>\t\tThe base seed to use for the random numbers.\n"
158d31093e8SAxel Dörfler		"  -f, --file-count=<count>\tThe maximal number of files to create.\n"
15997f89e03SAxel Dörfler		"\t\t\t\tDefaults to %lu.\n"
160d31093e8SAxel Dörfler		"  -d, --dir-count=<count>\tThe maximal number of directories to create.\n"
16197f89e03SAxel Dörfler		"\t\t\t\tDefaults to %lu.\n"
162d31093e8SAxel Dörfler		"  -m, --max-file-size=<size>\tThe maximal file size of the files.\n"
16397f89e03SAxel Dörfler		"\t\t\t\tDefaults to %lld.\n"
1643b9dec1cSAxel Dörfler		"  -b, --base-dir=<path>\t\tThe base directory for the actions. "
1653b9dec1cSAxel Dörfler			"Defaults\n"
1663b9dec1cSAxel Dörfler		"\t\t\t\tto %s.\n"
16797f89e03SAxel Dörfler		"  -c, --check-interval=<count>\tCheck after every <count> runs. "
16897f89e03SAxel Dörfler			"Defaults to 0,\n"
16997f89e03SAxel Dörfler		"\t\t\t\tmeaning only check once at the end.\n"
17097f89e03SAxel Dörfler		"  -n, --no-cache\t\tDisables the file cache when doing I/O on\n"
17197f89e03SAxel Dörfler		"\t\t\t\ta file.\n"
1725734ece8SAxel Dörfler		"  -a, --always-check\t\tAlways check contents before removing data.\n"
17397f89e03SAxel Dörfler		"  -k, --keep-dirty\t\tDo not remove the working files on quit.\n"
174782bdb40SAxel Dörfler		"  -i, --mount-image=<image>\tMounts an image for the actions, and "
175782bdb40SAxel Dörfler			"remounts\n"
176782bdb40SAxel Dörfler		"\t\t\t\tit before checking (each time).\n"
17797f89e03SAxel Dörfler		"  -v, --verbose\t\t\tShow the actions as being performed\n",
17897f89e03SAxel Dörfler		kProgramName, kDefaultRunCount, kDefaultFileCount, kDefaultDirCount,
1793b9dec1cSAxel Dörfler		kDefaultMaxFileSize, kDefaultBaseDir);
180d31093e8SAxel Dörfler
181d31093e8SAxel Dörfler	exit(status);
182d31093e8SAxel Dörfler}
183d31093e8SAxel Dörfler
184d31093e8SAxel Dörfler
18597f89e03SAxel Dörflerstatic void
18697f89e03SAxel Dörflererror(const char* format, ...)
18797f89e03SAxel Dörfler{
18897f89e03SAxel Dörfler	va_list args;
18997f89e03SAxel Dörfler	va_start(args, format);
19097f89e03SAxel Dörfler
19197f89e03SAxel Dörfler	fprintf(stderr, "%s: ", kProgramName);
19297f89e03SAxel Dörfler	vfprintf(stderr, format, args);
19397f89e03SAxel Dörfler	fputc('\n', stderr);
19497f89e03SAxel Dörfler
19597f89e03SAxel Dörfler	va_end(args);
19697f89e03SAxel Dörfler	fflush(stderr);
19797f89e03SAxel Dörfler
19897f89e03SAxel Dörfler	exit(1);
19997f89e03SAxel Dörfler}
20097f89e03SAxel Dörfler
20197f89e03SAxel Dörfler
20297f89e03SAxel Dörflerstatic void
20397f89e03SAxel Dörflerwarning(const char* format, ...)
20497f89e03SAxel Dörfler{
20597f89e03SAxel Dörfler	va_list args;
20697f89e03SAxel Dörfler	va_start(args, format);
20797f89e03SAxel Dörfler
20897f89e03SAxel Dörfler	fprintf(stderr, "%s: ", kProgramName);
20997f89e03SAxel Dörfler	vfprintf(stderr, format, args);
21097f89e03SAxel Dörfler	fputc('\n', stderr);
21197f89e03SAxel Dörfler
21297f89e03SAxel Dörfler	va_end(args);
21397f89e03SAxel Dörfler	fflush(stderr);
21497f89e03SAxel Dörfler}
21597f89e03SAxel Dörfler
21697f89e03SAxel Dörfler
217d31093e8SAxel Dörflerstatic void
218d31093e8SAxel Dörflerverbose(const char* format, ...)
219d31093e8SAxel Dörfler{
220d31093e8SAxel Dörfler	if (!sVerbose)
221d31093e8SAxel Dörfler		return;
222d31093e8SAxel Dörfler
223d31093e8SAxel Dörfler	va_list args;
224d31093e8SAxel Dörfler	va_start(args, format);
225d31093e8SAxel Dörfler
226d31093e8SAxel Dörfler	vprintf(format, args);
227d31093e8SAxel Dörfler	putchar('\n');
228d31093e8SAxel Dörfler
229d31093e8SAxel Dörfler	va_end(args);
23097f89e03SAxel Dörfler	fflush(stdout);
231d31093e8SAxel Dörfler}
232d31093e8SAxel Dörfler
233d31093e8SAxel Dörfler
2343b9dec1cSAxel Dörflerstatic void
2353b9dec1cSAxel Dörfleraction(const char* format, ...)
2363b9dec1cSAxel Dörfler{
2373b9dec1cSAxel Dörfler	if (!sVerbose)
2383b9dec1cSAxel Dörfler		return;
2393b9dec1cSAxel Dörfler
2403b9dec1cSAxel Dörfler	va_list args;
2413b9dec1cSAxel Dörfler	va_start(args, format);
2423b9dec1cSAxel Dörfler
2433b9dec1cSAxel Dörfler	printf("%7lu  ", sRun + 1);
2443b9dec1cSAxel Dörfler	vprintf(format, args);
2453b9dec1cSAxel Dörfler	putchar('\n');
2463b9dec1cSAxel Dörfler
2473b9dec1cSAxel Dörfler	va_end(args);
2483b9dec1cSAxel Dörfler	fflush(stdout);
2493b9dec1cSAxel Dörfler}
2503b9dec1cSAxel Dörfler
2513b9dec1cSAxel Dörfler
252d31093e8SAxel Dörflerstatic file_action
253d31093e8SAxel Dörflerchoose_action()
254d31093e8SAxel Dörfler{
255d31093e8SAxel Dörfler	return (file_action)(rand() % kNumActions);
256d31093e8SAxel Dörfler}
257d31093e8SAxel Dörfler
258d31093e8SAxel Dörfler
259d31093e8SAxel Dörflerstatic inline int
260d31093e8SAxel Dörflerchoose_index(const EntryVector& entries)
261d31093e8SAxel Dörfler{
262d31093e8SAxel Dörfler	return rand() % entries.size();
263d31093e8SAxel Dörfler}
264d31093e8SAxel Dörfler
265d31093e8SAxel Dörfler
266d31093e8SAxel Dörflerstatic inline const std::string&
267d31093e8SAxel Dörflerchoose_parent(const EntryVector& entries)
268d31093e8SAxel Dörfler{
26997f89e03SAxel Dörfler	return entries[choose_index(entries)].name;
270d31093e8SAxel Dörfler}
271d31093e8SAxel Dörfler
272d31093e8SAxel Dörfler
273d31093e8SAxel Dörflerstatic std::string
274d31093e8SAxel Dörflercreate_name(const std::string& parent, const char* prefix)
275d31093e8SAxel Dörfler{
276d31093e8SAxel Dörfler	char buffer[1024];
277d31093e8SAxel Dörfler	snprintf(buffer, sizeof(buffer), "%s/%s-%lu", parent.c_str(), prefix,
278d31093e8SAxel Dörfler		sCount++);
279d31093e8SAxel Dörfler
280d31093e8SAxel Dörfler	std::string name = buffer;
281d31093e8SAxel Dörfler	return name;
282d31093e8SAxel Dörfler}
283d31093e8SAxel Dörfler
284d31093e8SAxel Dörfler
285d31093e8SAxel Dörflerstatic int
286d31093e8SAxel Dörfleropen_file(const std::string& name, int mode)
287d31093e8SAxel Dörfler{
28897f89e03SAxel Dörfler	return open(name.c_str(), mode | (sDisableFileCache ? O_DIRECT : 0), 0666);
289d31093e8SAxel Dörfler}
290d31093e8SAxel Dörfler
291d31093e8SAxel Dörfler
292d31093e8SAxel Dörflerstatic void
29397f89e03SAxel Dörflergenerate_block(char* buffer, const struct entry& entry, off_t offset)
294d31093e8SAxel Dörfler{
29597f89e03SAxel Dörfler	block_identifier* block = (block_identifier*)buffer;
29697f89e03SAxel Dörfler	block->offset = offset;
29797f89e03SAxel Dörfler	block->identifier = entry.identifier;
29897f89e03SAxel Dörfler
29997f89e03SAxel Dörfler	uint32 count = (kBlockSize - offsetof(block_identifier, data))  / 2;
30097f89e03SAxel Dörfler	offset += offsetof(block_identifier, data);
30197f89e03SAxel Dörfler
30297f89e03SAxel Dörfler	for (uint32 i = 0; i < count; i++) {
30397f89e03SAxel Dörfler		block->data[i] = offset + i * 2;
30497f89e03SAxel Dörfler	}
305d31093e8SAxel Dörfler}
306d31093e8SAxel Dörfler
307d31093e8SAxel Dörfler
308d31093e8SAxel Dörflerstatic void
30997f89e03SAxel Dörflerwrite_blocks(int fd, struct entry& entry, bool append = false)
310d31093e8SAxel Dörfler{
311d31093e8SAxel Dörfler	off_t size = min_c(rand() % sMaxFileSize, sMaxFileSize);
312d31093e8SAxel Dörfler	off_t offset = 0;
313d31093e8SAxel Dörfler
314d31093e8SAxel Dörfler	if (append) {
315d31093e8SAxel Dörfler		// in the append case, we need to check the file size
316d31093e8SAxel Dörfler		struct stat stat;
31797f89e03SAxel Dörfler		if (fstat(fd, &stat) != 0)
31897f89e03SAxel Dörfler			error("stat file failed: %s\n", strerror(errno));
319d31093e8SAxel Dörfler
320d31093e8SAxel Dörfler		if (size + stat.st_size > sMaxFileSize)
321d31093e8SAxel Dörfler			size = sMaxFileSize - stat.st_size;
322d31093e8SAxel Dörfler
323d31093e8SAxel Dörfler		offset = stat.st_size;
324d31093e8SAxel Dörfler	}
325d31093e8SAxel Dörfler
3263b9dec1cSAxel Dörfler	verbose("\t\twrite %lu bytes", size);
327d31093e8SAxel Dörfler
32897f89e03SAxel Dörfler	entry.size += size;
32997f89e03SAxel Dörfler	uint32 blockOffset = offset % kBlockSize;
33097f89e03SAxel Dörfler	sWriteTotal += size;
33197f89e03SAxel Dörfler
33297f89e03SAxel Dörfler	bigtime_t start = system_time();
33397f89e03SAxel Dörfler
334d31093e8SAxel Dörfler	while (size > 0) {
335d31093e8SAxel Dörfler		char block[kBlockSize];
33697f89e03SAxel Dörfler		generate_block(block, entry, offset - blockOffset);
337d31093e8SAxel Dörfler
33897f89e03SAxel Dörfler		ssize_t toWrite = min_c(size, kBlockSize - blockOffset);
33997f89e03SAxel Dörfler		ssize_t bytesWritten = write(fd, block + blockOffset, toWrite);
34097f89e03SAxel Dörfler		if (bytesWritten != toWrite)
34197f89e03SAxel Dörfler			error("writing failed: %s", strerror(errno));
342d31093e8SAxel Dörfler
343d31093e8SAxel Dörfler		offset += toWrite;
344d31093e8SAxel Dörfler		size -= toWrite;
34597f89e03SAxel Dörfler		blockOffset = 0;
34697f89e03SAxel Dörfler	}
34797f89e03SAxel Dörfler
34897f89e03SAxel Dörfler	sWriteTime += system_time() - start;
34997f89e03SAxel Dörfler}
35097f89e03SAxel Dörfler
35197f89e03SAxel Dörfler
35297f89e03SAxel Dörflerstatic void
35397f89e03SAxel Dörflerdump_block(const char* buffer, int size, const char* prefix)
35497f89e03SAxel Dörfler{
35597f89e03SAxel Dörfler	const int DUMPED_BLOCK_SIZE = 16;
35697f89e03SAxel Dörfler	int i;
35797f89e03SAxel Dörfler
35897f89e03SAxel Dörfler	for (i = 0; i < size;) {
35997f89e03SAxel Dörfler		int start = i;
36097f89e03SAxel Dörfler
36197f89e03SAxel Dörfler		printf("%s%04x ", prefix, i);
36297f89e03SAxel Dörfler		for (; i < start + DUMPED_BLOCK_SIZE; i++) {
36397f89e03SAxel Dörfler			if (!(i % 4))
36497f89e03SAxel Dörfler				printf(" ");
36597f89e03SAxel Dörfler
36697f89e03SAxel Dörfler			if (i >= size)
36797f89e03SAxel Dörfler				printf("  ");
36897f89e03SAxel Dörfler			else
36997f89e03SAxel Dörfler				printf("%02x", *(unsigned char*)(buffer + i));
37097f89e03SAxel Dörfler		}
37197f89e03SAxel Dörfler		printf("  ");
37297f89e03SAxel Dörfler
37397f89e03SAxel Dörfler		for (i = start; i < start + DUMPED_BLOCK_SIZE; i++) {
37497f89e03SAxel Dörfler			if (i < size) {
37597f89e03SAxel Dörfler				char c = buffer[i];
37697f89e03SAxel Dörfler
37797f89e03SAxel Dörfler				if (c < 30)
37897f89e03SAxel Dörfler					printf(".");
37997f89e03SAxel Dörfler				else
38097f89e03SAxel Dörfler					printf("%c", c);
38197f89e03SAxel Dörfler			} else
38297f89e03SAxel Dörfler				break;
38397f89e03SAxel Dörfler		}
38497f89e03SAxel Dörfler		printf("\n");
38597f89e03SAxel Dörfler	}
38697f89e03SAxel Dörfler}
38797f89e03SAxel Dörfler
38897f89e03SAxel Dörfler
38997f89e03SAxel Dörflerstatic void
3903ea61f1fSAxel Dörflercheck_file(const struct entry& file)
39197f89e03SAxel Dörfler{
3923ea61f1fSAxel Dörfler	int fd = open_file(file.name, O_RDONLY);
3933ea61f1fSAxel Dörfler	if (fd < 0) {
3943ea61f1fSAxel Dörfler		error("opening file \"%s\" failed: %s", file.name.c_str(),
3953ea61f1fSAxel Dörfler			strerror(errno));
3963ea61f1fSAxel Dörfler	}
39797f89e03SAxel Dörfler
3983ea61f1fSAxel Dörfler	// first check if size matches
39997f89e03SAxel Dörfler
4003ea61f1fSAxel Dörfler	struct stat stat;
4013ea61f1fSAxel Dörfler	if (fstat(fd, &stat) != 0)
4023ea61f1fSAxel Dörfler		error("stat file \"%s\" failed: %s", file.name.c_str(), strerror(errno));
4033ea61f1fSAxel Dörfler
4043ea61f1fSAxel Dörfler	if (file.size != stat.st_size) {
4053ea61f1fSAxel Dörfler		warning("size does not match for \"%s\"! Expected %lld reported %lld",
4063ea61f1fSAxel Dörfler			file.name.c_str(), file.size, stat.st_size);
4073ea61f1fSAxel Dörfler		close(fd);
4083ea61f1fSAxel Dörfler		return;
4093ea61f1fSAxel Dörfler	}
41097f89e03SAxel Dörfler
4113ea61f1fSAxel Dörfler	// check contents
41297f89e03SAxel Dörfler
4133ea61f1fSAxel Dörfler	off_t size = file.size;
4143ea61f1fSAxel Dörfler	off_t offset = 0;
4153ea61f1fSAxel Dörfler	sReadTotal += size;
4163ea61f1fSAxel Dörfler
4173ea61f1fSAxel Dörfler	bigtime_t start = system_time();
4183ea61f1fSAxel Dörfler
4193ea61f1fSAxel Dörfler	while (size > 0) {
4203ea61f1fSAxel Dörfler		// read block
4213ea61f1fSAxel Dörfler		char block[kBlockSize];
4223ea61f1fSAxel Dörfler		ssize_t toRead = min_c(size, kBlockSize);
4233ea61f1fSAxel Dörfler		ssize_t bytesRead = read(fd, block, toRead);
4243ea61f1fSAxel Dörfler		if (bytesRead != toRead) {
4253ea61f1fSAxel Dörfler			error("reading \"%s\" failed: %s", file.name.c_str(),
42697f89e03SAxel Dörfler				strerror(errno));
42797f89e03SAxel Dörfler		}
42897f89e03SAxel Dörfler
4293ea61f1fSAxel Dörfler		// compare with generated block
4303ea61f1fSAxel Dörfler		char generatedBlock[kBlockSize];
4313ea61f1fSAxel Dörfler		generate_block(generatedBlock, file, offset);
43297f89e03SAxel Dörfler
4333ea61f1fSAxel Dörfler		if (memcmp(generatedBlock, block, bytesRead) != 0) {
4343ea61f1fSAxel Dörfler			dump_block(generatedBlock, bytesRead, "generated: ");
4353ea61f1fSAxel Dörfler			dump_block(block, bytesRead, "read:      ");
4363ea61f1fSAxel Dörfler			error("block at %lld differ in \"%s\"!", offset, file.name.c_str());
43797f89e03SAxel Dörfler		}
43897f89e03SAxel Dörfler
4393ea61f1fSAxel Dörfler		offset += toRead;
4403ea61f1fSAxel Dörfler		size -= toRead;
4413ea61f1fSAxel Dörfler	}
44297f89e03SAxel Dörfler
4433ea61f1fSAxel Dörfler	sReadTime += system_time() - start;
4443ea61f1fSAxel Dörfler
4453ea61f1fSAxel Dörfler	close(fd);
4463ea61f1fSAxel Dörfler}
4473ea61f1fSAxel Dörfler
4483ea61f1fSAxel Dörfler
4493ea61f1fSAxel Dörflerstatic void
4503ea61f1fSAxel Dörflercheck_files(EntryVector& files)
4513ea61f1fSAxel Dörfler{
4523ea61f1fSAxel Dörfler	verbose("check all files...");
4533ea61f1fSAxel Dörfler
4543ea61f1fSAxel Dörfler	for (EntryVector::iterator i = files.begin(); i != files.end(); i++) {
4553ea61f1fSAxel Dörfler		const struct entry& file = *i;
4563ea61f1fSAxel Dörfler
4573ea61f1fSAxel Dörfler		check_file(file);
458d31093e8SAxel Dörfler	}
459d31093e8SAxel Dörfler}
460d31093e8SAxel Dörfler
461d31093e8SAxel Dörfler
4623b9dec1cSAxel Dörflerstatic void
4633b9dec1cSAxel Dörflerremove_dirs(const std::string& path)
4643b9dec1cSAxel Dörfler{
4653b9dec1cSAxel Dörfler	DIR* dir = opendir(path.c_str());
4663b9dec1cSAxel Dörfler	if (dir == NULL) {
4673b9dec1cSAxel Dörfler		warning("Could not open directory \"%s\": %s", path.c_str(),
4683b9dec1cSAxel Dörfler			strerror(errno));
4693b9dec1cSAxel Dörfler		return;
4703b9dec1cSAxel Dörfler	}
4713b9dec1cSAxel Dörfler
4723b9dec1cSAxel Dörfler	while (struct dirent* entry = readdir(dir)) {
4733b9dec1cSAxel Dörfler		if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
4743b9dec1cSAxel Dörfler			continue;
4753b9dec1cSAxel Dörfler
4763b9dec1cSAxel Dörfler		std::string subPath = path + "/" + entry->d_name;
4773b9dec1cSAxel Dörfler		remove_dirs(subPath);
4783b9dec1cSAxel Dörfler	}
4793b9dec1cSAxel Dörfler
4803b9dec1cSAxel Dörfler	closedir(dir);
4813b9dec1cSAxel Dörfler	rmdir(path.c_str());
4823b9dec1cSAxel Dörfler}
4833b9dec1cSAxel Dörfler
4843b9dec1cSAxel Dörfler
485782bdb40SAxel Dörflerstatic void
486782bdb40SAxel Dörflermount_image(const char* image, const char* mountPoint)
487782bdb40SAxel Dörfler{
488782bdb40SAxel Dörfler	dev_t volume = fs_mount_volume(mountPoint, image, NULL, 0, NULL);
489782bdb40SAxel Dörfler	if (volume < 0)
490782bdb40SAxel Dörfler		error("mounting failed: %s", strerror(volume));
491782bdb40SAxel Dörfler}
492782bdb40SAxel Dörfler
493782bdb40SAxel Dörfler
494782bdb40SAxel Dörflerstatic void
495782bdb40SAxel Dörflerunmount_image(const char* mountPoint)
496782bdb40SAxel Dörfler{
497782bdb40SAxel Dörfler	status_t status = fs_unmount_volume(mountPoint, 0);
498782bdb40SAxel Dörfler	if (status != B_OK)
499782bdb40SAxel Dörfler		error("unmounting failed: %s", strerror(status));
500782bdb40SAxel Dörfler}
501782bdb40SAxel Dörfler
502782bdb40SAxel Dörfler
503d31093e8SAxel Dörfler//	#pragma mark - Actions
504d31093e8SAxel Dörfler
505d31093e8SAxel Dörfler
506d31093e8SAxel Dörflerstatic void
507d31093e8SAxel Dörflercreate_dir(EntryVector& dirs)
508d31093e8SAxel Dörfler{
509d31093e8SAxel Dörfler	std::string parent = choose_parent(dirs);
510d31093e8SAxel Dörfler	std::string name = create_name(parent, "dir");
511d31093e8SAxel Dörfler
5125734ece8SAxel Dörfler	action("create dir %s (identifier %lu)", name.c_str(), sCount);
513d31093e8SAxel Dörfler
51497f89e03SAxel Dörfler	if (mkdir(name.c_str(), 0777) != 0)
51597f89e03SAxel Dörfler		error("creating dir \"%s\" failed: %s", name.c_str(), strerror(errno));
51697f89e03SAxel Dörfler
51797f89e03SAxel Dörfler	struct entry dir;
51897f89e03SAxel Dörfler	dir.name = name;
51997f89e03SAxel Dörfler	dir.identifier = sCount;
52097f89e03SAxel Dörfler	dir.size = 0;
521d31093e8SAxel Dörfler
52297f89e03SAxel Dörfler	dirs.push_back(dir);
523d31093e8SAxel Dörfler}
524d31093e8SAxel Dörfler
525d31093e8SAxel Dörfler
526d31093e8SAxel Dörflerstatic void
527d31093e8SAxel Dörflerremove_dir(EntryVector& dirs)
528d31093e8SAxel Dörfler{
529d31093e8SAxel Dörfler	if (dirs.empty())
530d31093e8SAxel Dörfler		return;
531d31093e8SAxel Dörfler
532d31093e8SAxel Dörfler	int index = choose_index(dirs);
5333b9dec1cSAxel Dörfler	if (index == 0)
5343b9dec1cSAxel Dörfler		return;
5353b9dec1cSAxel Dörfler
53697f89e03SAxel Dörfler	const std::string& name = dirs[index].name;
537d31093e8SAxel Dörfler
53897f89e03SAxel Dörfler	if (rmdir(name.c_str()) != 0) {
539d31093e8SAxel Dörfler		if (errno == ENOTEMPTY || errno == EEXIST) {
540d31093e8SAxel Dörfler			// TODO: in rare cases, we could remove all files
541d31093e8SAxel Dörfler			return;
542d31093e8SAxel Dörfler		}
543d31093e8SAxel Dörfler
54497f89e03SAxel Dörfler		error("removing dir \"%s\" failed: %s", name.c_str(), strerror(errno));
545d31093e8SAxel Dörfler	}
546d31093e8SAxel Dörfler
5473b9dec1cSAxel Dörfler	action("removed dir %s", name.c_str());
548d31093e8SAxel Dörfler
549d31093e8SAxel Dörfler	EntryVector::iterator iterator = dirs.begin();
550d31093e8SAxel Dörfler	dirs.erase(iterator + index);
551d31093e8SAxel Dörfler}
552d31093e8SAxel Dörfler
553d31093e8SAxel Dörfler
554d31093e8SAxel Dörflerstatic void
555d31093e8SAxel Dörflercreate_file(const EntryVector& dirs, EntryVector& files)
556d31093e8SAxel Dörfler{
557d31093e8SAxel Dörfler	std::string parent = choose_parent(dirs);
558d31093e8SAxel Dörfler	std::string name = create_name(parent, "file");
559d31093e8SAxel Dörfler
5605734ece8SAxel Dörfler	action("create file %s (identifier %lu)", name.c_str(), sCount);
561d31093e8SAxel Dörfler
562d31093e8SAxel Dörfler	int fd = open_file(name, O_RDWR | O_CREAT | O_TRUNC);
56397f89e03SAxel Dörfler	if (fd < 0)
56497f89e03SAxel Dörfler		error("creating file \"%s\" failed: %s", name.c_str(), strerror(errno));
56597f89e03SAxel Dörfler
56697f89e03SAxel Dörfler	struct entry file;
56797f89e03SAxel Dörfler	file.name = name;
56897f89e03SAxel Dörfler	file.identifier = sCount;
56997f89e03SAxel Dörfler	file.size = 0;
57097f89e03SAxel Dörfler	write_blocks(fd, file);
57197f89e03SAxel Dörfler
57297f89e03SAxel Dörfler	files.push_back(file);
573d31093e8SAxel Dörfler
574636ccbf3SAxel Dörfler	fs_write_attr(fd, kIdentifierAttribute, B_UINT32_TYPE, 0, &file.identifier,
575636ccbf3SAxel Dörfler		sizeof(uint32));
576636ccbf3SAxel Dörfler
577d31093e8SAxel Dörfler	close(fd);
578d31093e8SAxel Dörfler}
579d31093e8SAxel Dörfler
580d31093e8SAxel Dörfler
581d31093e8SAxel Dörflerstatic void
582d31093e8SAxel Dörflerremove_file(EntryVector& files)
583d31093e8SAxel Dörfler{
584d31093e8SAxel Dörfler	if (files.empty())
585d31093e8SAxel Dörfler		return;
586d31093e8SAxel Dörfler
587d31093e8SAxel Dörfler	int index = choose_index(files);
58897f89e03SAxel Dörfler	const std::string& name = files[index].name;
589d31093e8SAxel Dörfler
5903ea61f1fSAxel Dörfler	if (sCheckBeforeRemove)
5913ea61f1fSAxel Dörfler		check_file(files[index]);
5923ea61f1fSAxel Dörfler
59397f89e03SAxel Dörfler	if (remove(name.c_str()) != 0)
59497f89e03SAxel Dörfler		error("removing file \"%s\" failed: %s", name.c_str(), strerror(errno));
595d31093e8SAxel Dörfler
5963b9dec1cSAxel Dörfler	action("removed file %s", name.c_str());
597d31093e8SAxel Dörfler
598d31093e8SAxel Dörfler	EntryVector::iterator iterator = files.begin();
599d31093e8SAxel Dörfler	files.erase(iterator + index);
600d31093e8SAxel Dörfler}
601d31093e8SAxel Dörfler
602d31093e8SAxel Dörfler
603d31093e8SAxel Dörflerstatic void
604d31093e8SAxel Dörflerrename_file(const EntryVector& dirs, EntryVector& files)
605d31093e8SAxel Dörfler{
606d31093e8SAxel Dörfler	if (files.empty())
607d31093e8SAxel Dörfler		return;
608d31093e8SAxel Dörfler
609d31093e8SAxel Dörfler	std::string parent = choose_parent(dirs);
61097f89e03SAxel Dörfler	std::string newName = create_name(parent, "renamed-file");
611d31093e8SAxel Dörfler
612d31093e8SAxel Dörfler	int index = choose_index(files);
61397f89e03SAxel Dörfler	const std::string& oldName = files[index].name;
614d31093e8SAxel Dörfler
6153b9dec1cSAxel Dörfler	action("rename file \"%s\" to \"%s\"", oldName.c_str(), newName.c_str());
616d31093e8SAxel Dörfler
61797f89e03SAxel Dörfler	if (rename(oldName.c_str(), newName.c_str()) != 0) {
61897f89e03SAxel Dörfler		error("renaming file \"%s\" to \"%s\" failed: %s", oldName.c_str(),
61997f89e03SAxel Dörfler			newName.c_str(), strerror(errno));
620d31093e8SAxel Dörfler	}
621d31093e8SAxel Dörfler
62297f89e03SAxel Dörfler	files[index].name = newName;
623d31093e8SAxel Dörfler}
624d31093e8SAxel Dörfler
625d31093e8SAxel Dörfler
626d31093e8SAxel Dörflerstatic void
62797f89e03SAxel Dörflerappend_file(EntryVector& files)
628d31093e8SAxel Dörfler{
629d31093e8SAxel Dörfler	if (files.empty())
630d31093e8SAxel Dörfler		return;
631d31093e8SAxel Dörfler
63297f89e03SAxel Dörfler	struct entry& file = files[choose_index(files)];
633d31093e8SAxel Dörfler
6343b9dec1cSAxel Dörfler	action("append to \"%s\"", file.name.c_str());
635d31093e8SAxel Dörfler
63697f89e03SAxel Dörfler	int fd = open_file(file.name, O_WRONLY | O_APPEND);
637d31093e8SAxel Dörfler	if (fd < 0) {
63897f89e03SAxel Dörfler		error("appending to file \"%s\" failed: %s", file.name.c_str(),
63997f89e03SAxel Dörfler			strerror(errno));
640d31093e8SAxel Dörfler	}
641d31093e8SAxel Dörfler
64297f89e03SAxel Dörfler	write_blocks(fd, file, true);
643d31093e8SAxel Dörfler	close(fd);
644d31093e8SAxel Dörfler}
645d31093e8SAxel Dörfler
646d31093e8SAxel Dörfler
647d31093e8SAxel Dörflerstatic void
64897f89e03SAxel Dörflerreplace_file(EntryVector& files)
649d31093e8SAxel Dörfler{
650d31093e8SAxel Dörfler	if (files.empty())
651d31093e8SAxel Dörfler		return;
652d31093e8SAxel Dörfler
65397f89e03SAxel Dörfler	struct entry& file = files[choose_index(files)];
654d31093e8SAxel Dörfler
6553b9dec1cSAxel Dörfler	action("replace \"%s\" contents", file.name.c_str());
656d31093e8SAxel Dörfler
6573ea61f1fSAxel Dörfler	if (sCheckBeforeRemove)
6583ea61f1fSAxel Dörfler		check_file(file);
6593ea61f1fSAxel Dörfler
66097f89e03SAxel Dörfler	int fd = open_file(file.name, O_CREAT | O_WRONLY | O_TRUNC);
661d31093e8SAxel Dörfler	if (fd < 0) {
66297f89e03SAxel Dörfler		error("replacing file \"%s\" failed: %s", file.name.c_str(),
66397f89e03SAxel Dörfler			strerror(errno));
664d31093e8SAxel Dörfler	}
665d31093e8SAxel Dörfler
66697f89e03SAxel Dörfler	file.size = 0;
66797f89e03SAxel Dörfler	write_blocks(fd, file);
66897f89e03SAxel Dörfler
669d31093e8SAxel Dörfler	close(fd);
670d31093e8SAxel Dörfler}
671d31093e8SAxel Dörfler
672d31093e8SAxel Dörfler
673d31093e8SAxel Dörflerstatic void
67497f89e03SAxel Dörflertruncate_file(EntryVector& files)
675d31093e8SAxel Dörfler{
676d31093e8SAxel Dörfler	if (files.empty())
677d31093e8SAxel Dörfler		return;
678d31093e8SAxel Dörfler
67997f89e03SAxel Dörfler	struct entry& file = files[choose_index(files)];
680d31093e8SAxel Dörfler
6813b9dec1cSAxel Dörfler	action("truncate \"%s\"", file.name.c_str());
682d31093e8SAxel Dörfler
6833ea61f1fSAxel Dörfler	if (sCheckBeforeRemove)
6843ea61f1fSAxel Dörfler		check_file(file);
6853ea61f1fSAxel Dörfler
68697f89e03SAxel Dörfler	int fd = open_file(file.name, O_WRONLY | O_TRUNC);
687d31093e8SAxel Dörfler	if (fd < 0) {
68897f89e03SAxel Dörfler		error("truncating file \"%s\" failed: %s", file.name.c_str(),
68997f89e03SAxel Dörfler			strerror(errno));
690d31093e8SAxel Dörfler	}
691d31093e8SAxel Dörfler
69297f89e03SAxel Dörfler	file.size = 0;
69397f89e03SAxel Dörfler
694d31093e8SAxel Dörfler	close(fd);
695d31093e8SAxel Dörfler}
696d31093e8SAxel Dörfler
697d31093e8SAxel Dörfler
698d31093e8SAxel Dörfler//	#pragma mark -
699d31093e8SAxel Dörfler
700d31093e8SAxel Dörfler
701d31093e8SAxel Dörflerint
702d31093e8SAxel Dörflermain(int argc, char** argv)
703d31093e8SAxel Dörfler{
704d31093e8SAxel Dörfler	// parse arguments
705d31093e8SAxel Dörfler
706d31093e8SAxel Dörfler	const static struct option kOptions[] = {
707d31093e8SAxel Dörfler		{"runs", required_argument, 0, 'r'},
708d31093e8SAxel Dörfler		{"seed", required_argument, 0, 's'},
709d31093e8SAxel Dörfler		{"file-count", required_argument, 0, 'f'},
710d31093e8SAxel Dörfler		{"dir-count", required_argument, 0, 'd'},
71197f89e03SAxel Dörfler		{"check-interval", required_argument, 0, 'c'},
712d31093e8SAxel Dörfler		{"max-file-size", required_argument, 0, 'm'},
7133b9dec1cSAxel Dörfler		{"base-dir", required_argument, 0, 'b'},
714d31093e8SAxel Dörfler		{"no-cache", no_argument, 0, 'n'},
7153ea61f1fSAxel Dörfler		{"always-check", no_argument, 0, 'a'},
71697f89e03SAxel Dörfler		{"keep-dirty", no_argument, 0, 'k'},
717782bdb40SAxel Dörfler		{"mount-image", required_argument, 0, 'i'},
718d31093e8SAxel Dörfler		{"verbose", no_argument, 0, 'v'},
719d31093e8SAxel Dörfler		{"help", no_argument, 0, 'h'},
720d31093e8SAxel Dörfler		{NULL}
721d31093e8SAxel Dörfler	};
722d31093e8SAxel Dörfler
723d31093e8SAxel Dörfler	uint32 maxFileCount = kDefaultFileCount;
724d31093e8SAxel Dörfler	uint32 maxDirCount = kDefaultDirCount;
725d31093e8SAxel Dörfler	uint32 runs = kDefaultRunCount;
72697f89e03SAxel Dörfler	uint32 checkInterval = 0;
7273ea61f1fSAxel Dörfler	uint32 seed = 0;
72897f89e03SAxel Dörfler	bool keepDirty = false;
729782bdb40SAxel Dörfler	const char* mountImage = NULL;
730d31093e8SAxel Dörfler
7313b9dec1cSAxel Dörfler	struct entry base;
7323b9dec1cSAxel Dörfler	base.name = kDefaultBaseDir;
7333b9dec1cSAxel Dörfler	base.identifier = 0;
7343b9dec1cSAxel Dörfler	base.size = 0;
7353b9dec1cSAxel Dörfler
736d31093e8SAxel Dörfler	int c;
737782bdb40SAxel Dörfler	while ((c = getopt_long(argc, argv, "r:s:f:d:c:m:b:naki:vh", kOptions,
738d31093e8SAxel Dörfler			NULL)) != -1) {
739d31093e8SAxel Dörfler		switch (c) {
740d31093e8SAxel Dörfler			case 0:
741d31093e8SAxel Dörfler				break;
742d31093e8SAxel Dörfler			case 'r':
743d31093e8SAxel Dörfler				runs = strtoul(optarg, NULL, 0);
744d31093e8SAxel Dörfler				if (runs < 1)
745d31093e8SAxel Dörfler					runs = 1;
746d31093e8SAxel Dörfler				break;
747d31093e8SAxel Dörfler			case 's':
748d31093e8SAxel Dörfler				// seed
7493ea61f1fSAxel Dörfler				seed = strtoul(optarg, NULL, 0);
750d31093e8SAxel Dörfler				break;
751d31093e8SAxel Dörfler			case 'f':
752d31093e8SAxel Dörfler				// file count
753d31093e8SAxel Dörfler				maxFileCount = strtoul(optarg, NULL, 0);
754d31093e8SAxel Dörfler				if (maxFileCount < 5)
755d31093e8SAxel Dörfler					maxFileCount = 5;
756d31093e8SAxel Dörfler				else if (maxFileCount > kMaxFileCount)
757d31093e8SAxel Dörfler					maxFileCount = kMaxFileCount;
758d31093e8SAxel Dörfler				break;
759d31093e8SAxel Dörfler			case 'd':
760d31093e8SAxel Dörfler				// directory count
761d31093e8SAxel Dörfler				maxDirCount = strtoul(optarg, NULL, 0);
762d31093e8SAxel Dörfler				if (maxDirCount < 1)
763d31093e8SAxel Dörfler					maxDirCount = 1;
764d31093e8SAxel Dörfler				else if (maxDirCount > kMaxDirCount)
765d31093e8SAxel Dörfler					maxDirCount = kMaxDirCount;
766d31093e8SAxel Dörfler				break;
76797f89e03SAxel Dörfler			case 'c':
76897f89e03SAxel Dörfler				// check interval
76997f89e03SAxel Dörfler				checkInterval = strtoul(optarg, NULL, 0);
77097f89e03SAxel Dörfler				if (checkInterval < 0)
77197f89e03SAxel Dörfler					checkInterval = 0;
77297f89e03SAxel Dörfler				break;
773d31093e8SAxel Dörfler			case 'm':
774d31093e8SAxel Dörfler				// max file size
77597f89e03SAxel Dörfler				sMaxFileSize = string_to_size(optarg);
776d31093e8SAxel Dörfler				break;
7773b9dec1cSAxel Dörfler			case 'b':
7783b9dec1cSAxel Dörfler				base.name = optarg;
7793b9dec1cSAxel Dörfler				break;
780d31093e8SAxel Dörfler			case 'n':
781d31093e8SAxel Dörfler				sDisableFileCache = true;
782d31093e8SAxel Dörfler				break;
7833ea61f1fSAxel Dörfler			case 'a':
7843ea61f1fSAxel Dörfler				sCheckBeforeRemove = true;
7853ea61f1fSAxel Dörfler				break;
78697f89e03SAxel Dörfler			case 'k':
78797f89e03SAxel Dörfler				keepDirty = true;
78897f89e03SAxel Dörfler				break;
789782bdb40SAxel Dörfler			case 'i':
790782bdb40SAxel Dörfler				mountImage = optarg;
791782bdb40SAxel Dörfler				break;
792d31093e8SAxel Dörfler			case 'v':
793d31093e8SAxel Dörfler				sVerbose = true;
794d31093e8SAxel Dörfler				break;
795d31093e8SAxel Dörfler			case 'h':
796d31093e8SAxel Dörfler				usage(0);
797d31093e8SAxel Dörfler				break;
798d31093e8SAxel Dörfler			default:
799d31093e8SAxel Dörfler				usage(1);
800d31093e8SAxel Dörfler				break;
801d31093e8SAxel Dörfler		}
802d31093e8SAxel Dörfler	}
803d31093e8SAxel Dörfler
80497f89e03SAxel Dörfler	if (mkdir(base.name.c_str(), 0777) != 0 && errno != EEXIST) {
805d31093e8SAxel Dörfler		fprintf(stderr, "%s: cannot create base directory: %s\n",
806d31093e8SAxel Dörfler			kProgramName, strerror(errno));
807d31093e8SAxel Dörfler		return 1;
808d31093e8SAxel Dörfler	}
809782bdb40SAxel Dörfler	if (mountImage != NULL)
810782bdb40SAxel Dörfler		mount_image(mountImage, base.name.c_str());
811782bdb40SAxel Dörfler
812782bdb40SAxel Dörfler	EntryVector dirs;
813782bdb40SAxel Dörfler	EntryVector files;
814d31093e8SAxel Dörfler
81597f89e03SAxel Dörfler	dirs.push_back(base);
81697f89e03SAxel Dörfler
8173ea61f1fSAxel Dörfler	srand(seed);
8183ea61f1fSAxel Dörfler
8193ea61f1fSAxel Dörfler	verbose("%lu runs, %lu files (up to %s in size), %lu dirs, seed %lu\n", runs,
8203ea61f1fSAxel Dörfler		maxFileCount, size_to_string(sMaxFileSize).c_str(), maxDirCount, seed);
8213ea61f1fSAxel Dörfler
8223b9dec1cSAxel Dörfler	for (sRun = 0; sRun < runs; sRun++) {
823d31093e8SAxel Dörfler		file_action action = choose_action();
82497f89e03SAxel Dörfler
825d31093e8SAxel Dörfler		switch (action) {
826d31093e8SAxel Dörfler			case kCreateFile:
827d31093e8SAxel Dörfler				if (files.size() > maxFileCount / 2) {
828d31093e8SAxel Dörfler					// create a single file
829d31093e8SAxel Dörfler					if (files.size() < maxFileCount)
830d31093e8SAxel Dörfler						create_file(dirs, files);
831d31093e8SAxel Dörfler				} else {
832bf9f6085SAxel Dörfler					// create some more files to fill up the list (ie. 10%)
833bf9f6085SAxel Dörfler					uint32 count
834bf9f6085SAxel Dörfler						= min_c(maxFileCount, files.size() + maxFileCount / 10);
835bf9f6085SAxel Dörfler					for (uint32 i = files.size(); i < count; i++) {
836d31093e8SAxel Dörfler						create_file(dirs, files);
837d31093e8SAxel Dörfler					}
838d31093e8SAxel Dörfler				}
839d31093e8SAxel Dörfler				break;
840d31093e8SAxel Dörfler			case kCreateDir:
841d31093e8SAxel Dörfler				if (dirs.size() > maxDirCount / 2) {
842d31093e8SAxel Dörfler					// create a single directory
843d31093e8SAxel Dörfler					if (dirs.size() < maxDirCount)
844d31093e8SAxel Dörfler						create_dir(dirs);
845d31093e8SAxel Dörfler				} else {
846bf9f6085SAxel Dörfler					// create some more directories to fill up the list (ie. 10%)
847bf9f6085SAxel Dörfler					uint32 count
848bf9f6085SAxel Dörfler						= min_c(maxDirCount, dirs.size() + maxDirCount / 10);
849bf9f6085SAxel Dörfler					for (uint32 i = dirs.size(); i < count; i++) {
850d31093e8SAxel Dörfler						create_dir(dirs);
851d31093e8SAxel Dörfler					}
852d31093e8SAxel Dörfler				}
853d31093e8SAxel Dörfler				break;
854d31093e8SAxel Dörfler			case kRenameFile:
855d31093e8SAxel Dörfler				rename_file(dirs, files);
856d31093e8SAxel Dörfler				break;
857d31093e8SAxel Dörfler			case kRemoveFile:
858d31093e8SAxel Dörfler				remove_file(files);
859d31093e8SAxel Dörfler				break;
860d31093e8SAxel Dörfler			case kRemoveDir:
861d31093e8SAxel Dörfler				remove_dir(dirs);
862d31093e8SAxel Dörfler				break;
863d31093e8SAxel Dörfler			case kAppendFile:
864d31093e8SAxel Dörfler				append_file(files);
865d31093e8SAxel Dörfler				break;
866d31093e8SAxel Dörfler			case kReplaceFile:
867d31093e8SAxel Dörfler				replace_file(files);
868d31093e8SAxel Dörfler				break;
869d31093e8SAxel Dörfler			case kTruncateFile:
870d31093e8SAxel Dörfler				truncate_file(files);
871d31093e8SAxel Dörfler				break;
872d31093e8SAxel Dörfler
873d31093e8SAxel Dörfler			default:
874d31093e8SAxel Dörfler				break;
875d31093e8SAxel Dörfler		}
876d31093e8SAxel Dörfler
8773b9dec1cSAxel Dörfler		if (checkInterval != 0 && sRun > 0 && (sRun % checkInterval) == 0
878782bdb40SAxel Dörfler			&& sRun + 1 < runs) {
879782bdb40SAxel Dörfler			if (mountImage != NULL) {
880782bdb40SAxel Dörfler				// Always remount image before checking its contents
881782bdb40SAxel Dörfler				unmount_image(base.name.c_str());
882782bdb40SAxel Dörfler				mount_image(mountImage, base.name.c_str());
883782bdb40SAxel Dörfler			}
88497f89e03SAxel Dörfler			check_files(files);
885782bdb40SAxel Dörfler		}
886782bdb40SAxel Dörfler	}
887782bdb40SAxel Dörfler
888782bdb40SAxel Dörfler	if (mountImage != NULL) {
889782bdb40SAxel Dörfler		unmount_image(base.name.c_str());
890782bdb40SAxel Dörfler		mount_image(mountImage, base.name.c_str());
891d31093e8SAxel Dörfler	}
89297f89e03SAxel Dörfler
89397f89e03SAxel Dörfler	check_files(files);
89497f89e03SAxel Dörfler
89597f89e03SAxel Dörfler	if (!keepDirty) {
89697f89e03SAxel Dörfler		for (int i = files.size(); i-- > 0;) {
89797f89e03SAxel Dörfler			remove_file(files);
89897f89e03SAxel Dörfler		}
8993b9dec1cSAxel Dörfler		remove_dirs(base.name);
900d31093e8SAxel Dörfler	}
901d31093e8SAxel Dörfler
902782bdb40SAxel Dörfler	if (mountImage != NULL) {
903782bdb40SAxel Dörfler		unmount_image(base.name.c_str());
904782bdb40SAxel Dörfler		if (!keepDirty)
905782bdb40SAxel Dörfler			remove_dirs(base.name);
906782bdb40SAxel Dörfler	}
907782bdb40SAxel Dörfler
90897f89e03SAxel Dörfler	printf("%s written in %s, %s/s\n", size_to_string(sWriteTotal).c_str(),
90997f89e03SAxel Dörfler		time_to_string(sWriteTime).c_str(),
91097f89e03SAxel Dörfler		size_to_string(int64(0.5 + sWriteTotal
91197f89e03SAxel Dörfler			/ (sWriteTime / 1000000.0))).c_str());
91297f89e03SAxel Dörfler	printf("%s read in %s, %s/s\n", size_to_string(sReadTotal).c_str(),
91397f89e03SAxel Dörfler		time_to_string(sReadTime).c_str(),
91497f89e03SAxel Dörfler		size_to_string(int64(0.5 + sReadTotal
91597f89e03SAxel Dörfler			/ (sReadTime / 1000000.0))).c_str());
91697f89e03SAxel Dörfler
917d31093e8SAxel Dörfler	return 0;
918d31093e8SAxel Dörfler}
919