* Add option -a to always check before contents are removed.
* Print the settings on start in verbose mode. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@30360 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
8eb51285d3
commit
3ea61f1f22
@ -70,6 +70,7 @@ static const char *kProgramName = __progname;
|
||||
|
||||
static bool sDisableFileCache = false;
|
||||
static bool sVerbose = false;
|
||||
static bool sCheckBeforeRemove = false;
|
||||
static off_t sMaxFileSize = kDefaultMaxFileSize;
|
||||
static uint32 sCount = 0;
|
||||
|
||||
@ -166,6 +167,7 @@ usage(int status)
|
||||
"\t\t\t\tmeaning only check once at the end.\n"
|
||||
" -n, --no-cache\t\tDisables the file cache when doing I/O on\n"
|
||||
"\t\t\t\ta file.\n"
|
||||
" -a, --always-check\tAlways check contents before removing data.\n"
|
||||
" -k, --keep-dirty\t\tDo not remove the working files on quit.\n"
|
||||
" -v, --verbose\t\t\tShow the actions as being performed\n",
|
||||
kProgramName, kDefaultRunCount, kDefaultFileCount, kDefaultDirCount,
|
||||
@ -379,6 +381,66 @@ dump_block(const char* buffer, int size, const char* prefix)
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
check_file(const struct entry& file)
|
||||
{
|
||||
int fd = open_file(file.name, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
error("opening file \"%s\" failed: %s", file.name.c_str(),
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
// first check if size matches
|
||||
|
||||
struct stat stat;
|
||||
if (fstat(fd, &stat) != 0)
|
||||
error("stat file \"%s\" failed: %s", file.name.c_str(), strerror(errno));
|
||||
|
||||
if (file.size != stat.st_size) {
|
||||
warning("size does not match for \"%s\"! Expected %lld reported %lld",
|
||||
file.name.c_str(), file.size, stat.st_size);
|
||||
close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
// check contents
|
||||
|
||||
off_t size = file.size;
|
||||
off_t offset = 0;
|
||||
sReadTotal += size;
|
||||
|
||||
bigtime_t start = system_time();
|
||||
|
||||
while (size > 0) {
|
||||
// read block
|
||||
char block[kBlockSize];
|
||||
ssize_t toRead = min_c(size, kBlockSize);
|
||||
ssize_t bytesRead = read(fd, block, toRead);
|
||||
if (bytesRead != toRead) {
|
||||
error("reading \"%s\" failed: %s", file.name.c_str(),
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
// compare with generated block
|
||||
char generatedBlock[kBlockSize];
|
||||
generate_block(generatedBlock, file, offset);
|
||||
|
||||
if (memcmp(generatedBlock, block, bytesRead) != 0) {
|
||||
dump_block(generatedBlock, bytesRead, "generated: ");
|
||||
dump_block(block, bytesRead, "read: ");
|
||||
error("block at %lld differ in \"%s\"!", offset, file.name.c_str());
|
||||
}
|
||||
|
||||
offset += toRead;
|
||||
size -= toRead;
|
||||
}
|
||||
|
||||
sReadTime += system_time() - start;
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
check_files(EntryVector& files)
|
||||
{
|
||||
@ -387,63 +449,7 @@ check_files(EntryVector& files)
|
||||
for (EntryVector::iterator i = files.begin(); i != files.end(); i++) {
|
||||
const struct entry& file = *i;
|
||||
|
||||
int fd = open_file(file.name, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
error("opening file \"%s\" failed: %s", file.name.c_str(),
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
// first check if size matches
|
||||
|
||||
struct stat stat;
|
||||
if (fstat(fd, &stat) != 0) {
|
||||
error("stat file \"%s\" failed: %s", file.name.c_str(),
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
if (file.size != stat.st_size) {
|
||||
warning("size does not match for \"%s\"! Expected %lld "
|
||||
"reported %lld", file.name.c_str(), file.size, stat.st_size);
|
||||
close(fd);
|
||||
continue;
|
||||
}
|
||||
|
||||
// check contents
|
||||
|
||||
off_t size = file.size;
|
||||
off_t offset = 0;
|
||||
sReadTotal += size;
|
||||
|
||||
bigtime_t start = system_time();
|
||||
|
||||
while (size > 0) {
|
||||
// read block
|
||||
char block[kBlockSize];
|
||||
ssize_t toRead = min_c(size, kBlockSize);
|
||||
ssize_t bytesRead = read(fd, block, toRead);
|
||||
if (bytesRead != toRead) {
|
||||
error("reading \"%s\" failed: %s", file.name.c_str(),
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
// compare with generated block
|
||||
char generatedBlock[kBlockSize];
|
||||
generate_block(generatedBlock, file, offset);
|
||||
|
||||
if (memcmp(generatedBlock, block, bytesRead) != 0) {
|
||||
dump_block(generatedBlock, bytesRead, "generated: ");
|
||||
dump_block(block, bytesRead, "read: ");
|
||||
error("block at %lld differ in \"%s\"!", offset,
|
||||
file.name.c_str());
|
||||
}
|
||||
|
||||
offset += toRead;
|
||||
size -= toRead;
|
||||
}
|
||||
|
||||
sReadTime += system_time() - start;
|
||||
|
||||
close(fd);
|
||||
check_file(file);
|
||||
}
|
||||
}
|
||||
|
||||
@ -558,6 +564,9 @@ remove_file(EntryVector& files)
|
||||
int index = choose_index(files);
|
||||
const std::string& name = files[index].name;
|
||||
|
||||
if (sCheckBeforeRemove)
|
||||
check_file(files[index]);
|
||||
|
||||
if (remove(name.c_str()) != 0)
|
||||
error("removing file \"%s\" failed: %s", name.c_str(), strerror(errno));
|
||||
|
||||
@ -622,6 +631,9 @@ replace_file(EntryVector& files)
|
||||
|
||||
action("replace \"%s\" contents", file.name.c_str());
|
||||
|
||||
if (sCheckBeforeRemove)
|
||||
check_file(file);
|
||||
|
||||
int fd = open_file(file.name, O_CREAT | O_WRONLY | O_TRUNC);
|
||||
if (fd < 0) {
|
||||
error("replacing file \"%s\" failed: %s", file.name.c_str(),
|
||||
@ -645,6 +657,9 @@ truncate_file(EntryVector& files)
|
||||
|
||||
action("truncate \"%s\"", file.name.c_str());
|
||||
|
||||
if (sCheckBeforeRemove)
|
||||
check_file(file);
|
||||
|
||||
int fd = open_file(file.name, O_WRONLY | O_TRUNC);
|
||||
if (fd < 0) {
|
||||
error("truncating file \"%s\" failed: %s", file.name.c_str(),
|
||||
@ -674,6 +689,7 @@ main(int argc, char** argv)
|
||||
{"max-file-size", required_argument, 0, 'm'},
|
||||
{"base-dir", required_argument, 0, 'b'},
|
||||
{"no-cache", no_argument, 0, 'n'},
|
||||
{"always-check", no_argument, 0, 'a'},
|
||||
{"keep-dirty", no_argument, 0, 'k'},
|
||||
{"verbose", no_argument, 0, 'v'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
@ -684,6 +700,7 @@ main(int argc, char** argv)
|
||||
uint32 maxDirCount = kDefaultDirCount;
|
||||
uint32 runs = kDefaultRunCount;
|
||||
uint32 checkInterval = 0;
|
||||
uint32 seed = 0;
|
||||
bool keepDirty = false;
|
||||
|
||||
struct entry base;
|
||||
@ -692,7 +709,7 @@ main(int argc, char** argv)
|
||||
base.size = 0;
|
||||
|
||||
int c;
|
||||
while ((c = getopt_long(argc, argv, "r:s:f:d:c:m:b:nkvh", kOptions,
|
||||
while ((c = getopt_long(argc, argv, "r:s:f:d:c:m:b:nakvh", kOptions,
|
||||
NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 0:
|
||||
@ -704,7 +721,7 @@ main(int argc, char** argv)
|
||||
break;
|
||||
case 's':
|
||||
// seed
|
||||
srand(strtoul(optarg, NULL, 0));
|
||||
seed = strtoul(optarg, NULL, 0);
|
||||
break;
|
||||
case 'f':
|
||||
// file count
|
||||
@ -738,6 +755,9 @@ main(int argc, char** argv)
|
||||
case 'n':
|
||||
sDisableFileCache = true;
|
||||
break;
|
||||
case 'a':
|
||||
sCheckBeforeRemove = true;
|
||||
break;
|
||||
case 'k':
|
||||
keepDirty = true;
|
||||
break;
|
||||
@ -764,6 +784,11 @@ main(int argc, char** argv)
|
||||
|
||||
dirs.push_back(base);
|
||||
|
||||
srand(seed);
|
||||
|
||||
verbose("%lu runs, %lu files (up to %s in size), %lu dirs, seed %lu\n", runs,
|
||||
maxFileCount, size_to_string(sMaxFileSize).c_str(), maxDirCount, seed);
|
||||
|
||||
for (sRun = 0; sRun < runs; sRun++) {
|
||||
file_action action = choose_action();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user