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 *ptr_read_all, struct timeval *ptr_dt, int progress) { char *full_fn; const char *filename; const int num_int64 = SECTOR_SIZE >> 3; uint64_t sector[num_int64]; FILE *f; int fd; size_t sectors_read; uint64_t expected_offset; int final_errno; struct timeval t1, t2; /* Progress time. */ struct timeval pt1 = { .tv_sec = -1000, .tv_usec = 0 }; *ptr_ok = *ptr_corrupted = *ptr_changed = *ptr_overwritten = 0; full_fn = full_fn_from_number(&filename, path, number); assert(full_fn); printf("Validating file %s ... %s", filename, progress ? BLANK : ""); fflush(stdout); #ifdef __CYGWIN__ /* We don't need write access, but some kernels require that * the file descriptor passed to fdatasync(2) to be writable. */ f = fopen(full_fn, "rb+"); #else f = fopen(full_fn, "rb"); #endif if (!f) err(errno, "Can't open file %s", full_fn); fd = fileno(f); assert(fd >= 0); /* If the kernel follows our advice, f3read won't ever read from cache * even when testing small memory cards without a remount, and * we should have a better reading-speed measurement. */ assert(!fdatasync(fd)); assert(!posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED)); /* Obtain initial time. */ assert(!gettimeofday(&t1, NULL)); /* Help the kernel to help us. */ assert(!posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL)); sectors_read = fread(sector, SECTOR_SIZE, 1, f); final_errno = errno; expected_offset = (uint64_t)number * GIGABYTES; while (sectors_read > 0) { uint64_t rn; int error_count, i; assert(sectors_read == 1); rn = sector[0]; error_count = 0; for (i = 1; error_count <= TOLERANCE && i < num_int64; i++) { rn = random_number(rn); if (rn != sector[i]) error_count++; } if (expected_offset == sector[0]) { if (error_count == 0) (*ptr_ok)++; else if (error_count <= TOLERANCE) (*ptr_changed)++; else (*ptr_corrupted)++; } else if (error_count <= TOLERANCE) (*ptr_overwritten)++; else (*ptr_corrupted)++; sectors_read = fread(sector, SECTOR_SIZE, 1, f); final_errno = errno; expected_offset += SECTOR_SIZE; if (progress) { struct timeval pt2; assert(!gettimeofday(&pt2, NULL)); /* Avoid often printouts. */ if (delay_ms(&pt1, &pt2) >= 200) { PRINT_STATUS(CLEAR); fflush(stdout); pt1 = pt2; } } } assert(!gettimeofday(&t2, NULL)); update_dt(ptr_dt, &t1, &t2); *ptr_read_all = feof(f); *ptr_size = ftell(f); PRINT_STATUS(progress ? CLEAR : ""); if (!*ptr_read_all) { assert(ferror(f)); printf(" - NOT fully read due to \"%s\"", strerror(final_errno)); } printf("\n"); fclose(f); free(full_fn); } static void report(const char *prefix, uint64_t i) { double f = (double) (i * SECTOR_SIZE); const char *unit = adjust_unit(&f); printf("%s %.2f %s (%" PRIu64 " sectors)\n", prefix, f, unit, i); }
int add_dt(void *handle, dt_rec_t *addp) { return (update_dt((dt_handle_t *)handle, NULL, addp)); }
int modify_dt(void *handle, const dt_rec_t *origp, dt_rec_t *newp) { return (update_dt((dt_handle_t *)handle, origp, newp)); }
int delete_dt(void *handle, const dt_rec_t *delp) { return (update_dt((dt_handle_t *)handle, delp, NULL)); }