diff --git a/f3read.c b/f3read.c index 4d31f82..f3d1abe 100644 --- a/f3read.c +++ b/f3read.c @@ -13,20 +13,6 @@ #include "utils.h" -static uint64_t offset_from_filename(const char *filename) -{ - char str[5]; - uint64_t number; - - /* Obtain number. */ - assert(is_my_file(filename)); - strncpy(str, filename, 4); - str[4] = '\0'; - number = (uint64_t) strtol(str, NULL, 10) - 1; - - return number * GIGABYTES; -} - static inline void update_dt(struct timeval *dt, const struct timeval *t1, const struct timeval *t2) { @@ -48,11 +34,13 @@ static inline void update_dt(struct timeval *dt, const struct timeval *t1, #define CLEAR ("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b" \ "\b\b\b\b\b\b\b\b\b\b\b\b\b") -static void validate_file(const char *path, const char *filename, +static void validate_file(const char *path, int number, uint64_t *ptr_ok, uint64_t *ptr_corrupted, uint64_t *ptr_changed, uint64_t *ptr_overwritten, uint64_t *ptr_size, int *read_all, struct timeval *ptr_dt, int progress) { + char full_fn[PATH_MAX]; + const char *filename; uint8_t sector[SECTOR_SIZE], *p, *ptr_end; FILE *f; int fd; @@ -61,7 +49,6 @@ static void validate_file(const char *path, const char *filename, uint64_t offset, expected_offset; struct drand48_data state; long int rand_int; - char full_fn[PATH_MAX]; char *tail_msg = ""; struct timeval t1, t2; /* Progress time. */ @@ -69,9 +56,9 @@ static void validate_file(const char *path, const char *filename, *ptr_ok = *ptr_corrupted = *ptr_changed = *ptr_overwritten = 0; + full_fn_from_number(full_fn, &filename, path, number); printf("Validating file %s ... %s", filename, progress ? BLANK : ""); fflush(stdout); - get_full_fn(full_fn, sizeof(full_fn), path, filename); f = fopen(full_fn, "rb"); if (!f) err(errno, "Can't open file %s", full_fn); @@ -92,7 +79,7 @@ static void validate_file(const char *path, const char *filename, ptr_end = sector + SECTOR_SIZE; sectors_read = fread(sector, SECTOR_SIZE, 1, f); - expected_offset = offset_from_filename(filename); + expected_offset = (uint64_t)number * GIGABYTES; while (sectors_read > 0) { assert(sectors_read == 1); offset = *((uint64_t *) sector); @@ -162,44 +149,45 @@ static inline double dt_to_s(struct timeval *dt) return ret > 0 ? ret : 1; } -static int iterate_path(const char *path, int progress) +static void iterate_files(const char *path, const int *files, int progress) { - DIR *ptr_dir; - struct dirent *entry; - const char *filename, *unit; uint64_t tot_ok, tot_corrupted, tot_changed, tot_overwritten, tot_size; struct timeval tot_dt = { .tv_sec = 0, .tv_usec = 0 }; double read_speed; - int and_read_all; + const char *unit; + int and_read_all = 1; + int or_missing_file = 0; + int number = 0; - ptr_dir = opendir(path); - if (!ptr_dir) - err(errno, "Can't open path %s", path); - - entry = readdir(ptr_dir); tot_ok = tot_corrupted = tot_changed = tot_overwritten = tot_size = 0; - and_read_all = 1; printf(" SECTORS " " ok/corrupted/changed/overwritten\n"); - while (entry) { - filename = entry->d_name; - if (is_my_file(filename)) { - uint64_t sec_ok, sec_corrupted, sec_changed, - sec_overwritten, file_size; - int read_all; - validate_file(path, filename, &sec_ok, &sec_corrupted, - &sec_changed, &sec_overwritten, - &file_size, &read_all, &tot_dt, progress); - tot_ok += sec_ok; - tot_corrupted += sec_corrupted; - tot_changed += sec_changed; - tot_overwritten += sec_overwritten; - tot_size += file_size; - and_read_all = and_read_all && read_all; + + while (*files >= 0) { + uint64_t sec_ok, sec_corrupted, sec_changed, + sec_overwritten, file_size; + int read_all; + + or_missing_file = or_missing_file || (*files != number); + for (; number < *files; number++) { + char full_fn[PATH_MAX]; + const char *filename; + full_fn_from_number(full_fn, &filename, "", number); + printf("Missing file %s\n", filename); } - entry = readdir(ptr_dir); + number++; + + validate_file(path, *files, &sec_ok, &sec_corrupted, + &sec_changed, &sec_overwritten, + &file_size, &read_all, &tot_dt, progress); + tot_ok += sec_ok; + tot_corrupted += sec_corrupted; + tot_changed += sec_changed; + tot_overwritten += sec_overwritten; + tot_size += file_size; + and_read_all = and_read_all && read_all; + files++; } - closedir(ptr_dir); assert(tot_size / SECTOR_SIZE == (tot_ok + tot_corrupted + tot_changed + tot_overwritten)); @@ -208,6 +196,8 @@ static int iterate_path(const char *path, int progress) report("\t Corrupted:", tot_corrupted); report("\tSlightly changed:", tot_changed); report("\t Overwritten:", tot_overwritten); + if (or_missing_file) + printf("WARNING: Not all F3 files are available\n"); if (!and_read_all) printf("WARNING: Not all data was read due to I/O error(s)\n"); @@ -215,14 +205,79 @@ static int iterate_path(const char *path, int progress) read_speed = (double)tot_size / dt_to_s(&tot_dt); unit = adjust_unit(&read_speed); printf("Average reading speed: %.2f %s/s\n", read_speed, unit); - return 0; +} + +static int number_from_filename(const char *filename) +{ + char str[FILENAME_NUM_DIGITS + 1]; + assert(is_my_file(filename)); + strncpy(str, filename, FILENAME_NUM_DIGITS); + str[FILENAME_NUM_DIGITS] = '\0'; + return strtol(str, NULL, 10) - 1; +} + +/* Don't call this function directly, use ls_my_files instead. */ +static int *__ls_my_files(DIR *dir, int *pcount, int *pindex) +{ + struct dirent *entry; + const char *filename; + + entry = readdir(dir); + if (!entry) { + int *ret = malloc(sizeof(const int) * (*pcount + 1)); + *pindex = *pcount - 1; + ret[*pcount] = -1; + closedir(dir); + return ret; + } + + filename = entry->d_name; + if (is_my_file(filename)) { + int my_index; + int *ret; + (*pcount)++; + ret = __ls_my_files(dir, pcount, &my_index); + ret[my_index] = number_from_filename(filename); + *pindex = my_index - 1; + return ret; + } + + return __ls_my_files(dir, pcount, pindex); +} + +/* To be used with qsort(3). */ +static int cmpintp(const void *p1, const void *p2) +{ + return *(const int *)p1 - *(const int *)p2; +} + +static const int *ls_my_files(const char *path) +{ + DIR *dir = opendir(path); + int my_count; + int my_index; + int *ret; + + if (!dir) + err(errno, "Can't open path %s", path); + + my_count = 0; + ret = __ls_my_files(dir, &my_count, &my_index); + assert(my_index == -1); + qsort(ret, my_count, sizeof(*ret), cmpintp); + return ret; } int main(int argc, char *argv[]) { if (argc == 2) { + const char *path = argv[1]; + const int *files = ls_my_files(path); /* If stdout isn't a terminal, supress progress. */ - return iterate_path(argv[1], isatty(STDOUT_FILENO)); + int progress = isatty(STDOUT_FILENO); + iterate_files(path, files, progress); + free((void *)files); + return 0; } fprintf(stderr, "Usage: f3read \n"); diff --git a/f3write.c b/f3write.c index 2a8faae..308a28b 100644 --- a/f3write.c +++ b/f3write.c @@ -269,7 +269,8 @@ static inline void end_measurement(int fd, struct flow *fw) static int create_and_fill_file(const char *path, int number, size_t size, struct flow *fw) { - char filename[PATH_MAX]; + char full_fn[PATH_MAX]; + const char *filename; int fd, fine; void *buf; size_t remaining; @@ -280,17 +281,17 @@ static int create_and_fill_file(const char *path, int number, size_t size, assert(size % fw->block_size == 0); /* Create the file. */ - assert(snprintf(filename, sizeof(filename), "%s/%04i.fff", - path, number + 1) < sizeof(filename)); - printf("Creating file %04i.fff ... ", number + 1); + + full_fn_from_number(full_fn, &filename, path, number); + printf("Creating file %s ... ", filename); fflush(stdout); - fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); + fd = open(full_fn, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR); if (fd < 0) { if (errno == ENOSPC) { printf("No space left.\n"); return 0; } - err(errno, "Can't create file %s", filename); + err(errno, "Can't create file %s", full_fn); } assert(fd >= 0); @@ -311,7 +312,7 @@ static int create_and_fill_file(const char *path, int number, size_t size, fine = 0; break; } else - err(errno, "Write to file %s failed", filename); + err(errno, "Write to file %s failed", full_fn); } assert(written == fw->block_size); remaining -= written; @@ -397,7 +398,8 @@ static void unlink_old_files(const char *path) filename = entry->d_name; if (is_my_file(filename)) { char full_fn[PATH_MAX]; - get_full_fn(full_fn, sizeof(full_fn), path, filename); + assert(snprintf(full_fn, sizeof(full_fn), "%s/%s", + path, filename) < sizeof(full_fn)); printf("Removing old file %s ...\n", filename); if (unlink(full_fn)) err(errno, "Can't remove file %s", full_fn); diff --git a/utils.c b/utils.c index ff2f8d7..a4adeae 100644 --- a/utils.c +++ b/utils.c @@ -14,6 +14,19 @@ const char *adjust_unit(double *ptr_bytes) return units[i]; } +void full_fn_from_number(char *full_fn, const char **filename, + const char *path, int num) +{ + static char format[32] = ""; + if (!format[0]) { + assert(FILENAME_NUM_DIGITS > 0); + assert(FILENAME_NUM_DIGITS < 10); + sprintf(format, "%%s/%%%02ii.fff", FILENAME_NUM_DIGITS); + } + assert(snprintf(full_fn, PATH_MAX, format, path, num + 1) < PATH_MAX); + *filename = full_fn + strlen(path) + 1; +} + #ifdef APPLE_MAC #include diff --git a/utils.h b/utils.h index 5ec247c..90601fe 100644 --- a/utils.h +++ b/utils.h @@ -8,6 +8,9 @@ #include #include +#define FILENAME_NUM_DIGITS 4 +#define FILENAME_SIZE (FILENAME_NUM_DIGITS + 4) + #define SECTOR_SIZE (512) #define GIGABYTES (1024 * 1024 * 1024) @@ -15,18 +18,16 @@ const char *adjust_unit(double *ptr_bytes); static inline int is_my_file(const char *filename) { - return (strlen(filename) == 8) && isdigit(filename[0]) && - isdigit(filename[1]) && isdigit(filename[2]) && - isdigit(filename[3]) && (filename[4] == '.') && - (filename[5] == 'f') && (filename[6] == 'f') && - (filename[7] == 'f'); + return (strlen(filename) == FILENAME_SIZE) && + isdigit(filename[0]) && isdigit(filename[1]) && + isdigit(filename[2]) && isdigit(filename[3]) && + (filename[4] == '.') && (filename[5] == 'f') && + (filename[6] == 'f') && (filename[7] == 'f'); } -static inline void get_full_fn(char *full_fn, int len, - const char *path, const char *filename) -{ - assert(snprintf(full_fn, len, "%s/%s", path, filename) < len); -} +/* @filename should be PATH_MAX long. */ +void full_fn_from_number(char *full_fn, const char **filename, + const char *path, int num); static inline long delay_ms(const struct timeval *t1, const struct timeval *t2) {