Adopt h2testw's file format

Now F3 and h2testw share the same file format.
Guenter Knauf has suggested this feature and
got the random-number generator used in h2testw from
Harald Bogeholz, the author of h2testw.

This change also addresses the issue that
the original random-number generator only fills
the first 32 bits of the 64 bits of the random numbers on
64-bit machines.
Besides the lower entropy on 64-bit machines, this issue was
making files generated on 32-bit and 64-bit machines incompatible.
Anselm Distelrath was the first to report this issue.
This commit is contained in:
Michel Machado 2014-05-14 11:44:13 -04:00
parent 1c50c85a4d
commit be1f587142
5 changed files with 25 additions and 121 deletions

View File

@ -18,7 +18,7 @@ card and then checks if can read it. It will assure you haven't been
sold a card with a smaller capacity than stated. sold a card with a smaller capacity than stated.
.PP .PP
When writing to flash drive, \fBf3write\fP fills the filesystem with 1GB When writing to flash drive, \fBf3write\fP fills the filesystem with 1GB
files named N.fff, where N is a number (i.e. /[0-9]+/). files named N.h2w, where N is a number (i.e. /[0-9]+/).
.PP .PP
WARNING: all data on the tested disk might be lost! WARNING: all data on the tested disk might be lost!
.SH OPTIONS .SH OPTIONS

View File

@ -44,8 +44,6 @@ static void validate_file(const char *path, int number,
int offset_match, error_count; int offset_match, error_count;
size_t sectors_read; size_t sectors_read;
uint64_t offset, expected_offset; uint64_t offset, expected_offset;
struct drand48_data state;
long int rand_int;
int final_errno; int final_errno;
struct timeval t1, t2; struct timeval t1, t2;
/* Progress time. */ /* Progress time. */
@ -79,17 +77,19 @@ static void validate_file(const char *path, int number,
final_errno = errno; final_errno = errno;
expected_offset = (uint64_t)number * GIGABYTES; expected_offset = (uint64_t)number * GIGABYTES;
while (sectors_read > 0) { while (sectors_read > 0) {
uint64_t rn;
assert(sectors_read == 1); assert(sectors_read == 1);
offset = *((uint64_t *) sector); offset = *((uint64_t *) sector);
offset_match = offset == expected_offset; offset_match = offset == expected_offset;
srand48_r(offset, &state); rn = offset;
p = sector + sizeof(offset); p = sector + sizeof(offset);
error_count = 0; error_count = 0;
for (; error_count <= TOLERANCE && p < ptr_end; for (; error_count <= TOLERANCE && p < ptr_end;
p += sizeof(long int)) { p += sizeof(rn)) {
lrand48_r(&state, &rand_int); rn = random_number(rn);
if (rand_int != *((long int *) p)) if (rn != *((typeof(rn) *) p))
error_count++; error_count++;
} }

View File

@ -18,20 +18,24 @@
static uint64_t fill_buffer(void *buf, size_t size, uint64_t offset) static uint64_t fill_buffer(void *buf, size_t size, uint64_t offset)
{ {
uint8_t *p, *ptr_next_sector, *ptr_end; uint8_t *p, *ptr_next_sector, *ptr_end;
struct drand48_data state; uint64_t rn;
assert(size > 0); assert(size > 0);
assert(size % SECTOR_SIZE == 0); assert(size % SECTOR_SIZE == 0);
assert(SECTOR_SIZE >= sizeof(offset) + sizeof(rn));
assert((SECTOR_SIZE - sizeof(offset)) % sizeof(rn) == 0);
p = buf; p = buf;
ptr_end = p + size; ptr_end = p + size;
while (p < ptr_end) { while (p < ptr_end) {
rn = offset;
memmove(p, &offset, sizeof(offset)); memmove(p, &offset, sizeof(offset));
srand48_r(offset, &state);
ptr_next_sector = p + SECTOR_SIZE; ptr_next_sector = p + SECTOR_SIZE;
p += sizeof(offset); p += sizeof(offset);
for (; p < ptr_next_sector; p += sizeof(long int)) for (; p < ptr_next_sector; p += sizeof(rn)) {
lrand48_r(&state, (long int *)p); rn = random_number(rn);
memmove(p, &rn, sizeof(rn));
}
assert(p == ptr_next_sector); assert(p == ptr_next_sector);
offset += SECTOR_SIZE; offset += SECTOR_SIZE;
} }

83
utils.c
View File

@ -33,14 +33,14 @@ int is_my_file(const char *filename)
p++; p++;
} while (isdigit(*p)); } while (isdigit(*p));
return (p[0] == '.') && (p[1] == 'f') && (p[2] == 'f') && return (p[0] == '.') && (p[1] == 'h') && (p[2] == '2') &&
(p[3] == 'f') && (p[4] == '\0'); (p[3] == 'w') && (p[4] == '\0');
} }
void full_fn_from_number(char *full_fn, const char **filename, void full_fn_from_number(char *full_fn, const char **filename,
const char *path, int num) const char *path, int num)
{ {
assert(snprintf(full_fn, PATH_MAX, "%s/%i.fff", path, num + 1) < assert(snprintf(full_fn, PATH_MAX, "%s/%i.h2w", path, num + 1) <
PATH_MAX); PATH_MAX);
*filename = full_fn + strlen(path) + 1; *filename = full_fn + strlen(path) + 1;
} }
@ -140,80 +140,3 @@ void print_header(FILE *f, char *name)
"This is free software; see the source for copying conditions.\n" "This is free software; see the source for copying conditions.\n"
"\n", name); "\n", name);
} }
#if defined(APPLE_MAC) || defined (CYGWIN)
#include <stdio.h>
#include <stdint.h>
int srand48_r(long int seedval, struct drand48_data *buffer)
{
/* The standards say we only have 32 bits. */
if (sizeof(long int) > 4)
seedval &= 0xffffffffl;
buffer->__x[2] = seedval >> 16;
buffer->__x[1] = seedval & 0xffffl;
buffer->__x[0] = 0x330e;
buffer->__a = 0x5deece66dull;
buffer->__c = 0xb;
buffer->__init = 1;
return 0;
}
static int __drand48_iterate(unsigned short int xsubi[3],
struct drand48_data *buffer)
{
uint64_t X;
uint64_t result;
/* Initialize buffer, if not yet done. */
if (__builtin_expect(!buffer->__init, 0)) {
buffer->__a = 0x5deece66dull;
buffer->__c = 0xb;
buffer->__init = 1;
}
/* Do the real work. We choose a data type which contains at least
48 bits. Because we compute the modulus it does not care how
many bits really are computed. */
X = (uint64_t) xsubi[2] << 32 | (uint32_t) xsubi[1] << 16 | xsubi[0];
result = X * buffer->__a + buffer->__c;
xsubi[0] = result & 0xffff;
xsubi[1] = (result >> 16) & 0xffff;
xsubi[2] = (result >> 32) & 0xffff;
return 0;
}
static int __nrand48_r(unsigned short int xsubi[3],
struct drand48_data *buffer, long int *result)
{
/* Compute next state. */
if (__drand48_iterate(xsubi, buffer) < 0)
return -1;
/* Store the result. */
if (sizeof(unsigned short int) == 2)
*result = xsubi[2] << 15 | xsubi[1] >> 1;
else
*result = xsubi[2] >> 1;
return 0;
}
int lrand48_r(struct drand48_data *buffer, long int *result)
{
/* Be generous for the arguments, detect some errors. */
if (buffer == NULL)
return -1;
return __nrand48_r(buffer->__x, buffer, result);
}
#endif /* APPLE_MAC or CYGWIN */

37
utils.h
View File

@ -6,13 +6,14 @@
#include <assert.h> #include <assert.h>
#include <sys/time.h> #include <sys/time.h>
#include <limits.h> #include <limits.h>
#include <stdint.h>
#define SECTOR_SIZE (512) #define SECTOR_SIZE (512)
#define GIGABYTES (1024 * 1024 * 1024) #define GIGABYTES (1024 * 1024 * 1024)
const char *adjust_unit(double *ptr_bytes); const char *adjust_unit(double *ptr_bytes);
/* Return true if @filename matches the regex /^[0-9]+\.fff$/ */ /* Return true if @filename matches the regex /^[0-9]+\.h2w$/ */
int is_my_file(const char *filename); int is_my_file(const char *filename);
/* @filename should be PATH_MAX long. */ /* @filename should be PATH_MAX long. */
@ -35,6 +36,11 @@ const int *ls_my_files(const char *path, int start_at);
void print_header(FILE *f, char *name); void print_header(FILE *f, char *name);
static inline uint64_t random_number(uint64_t prv_number)
{
return prv_number * 4294967311ULL + 17;
}
#ifdef APPLE_MAC #ifdef APPLE_MAC
/* For function fcntl. */ /* For function fcntl. */
@ -66,33 +72,4 @@ static inline int posix_fadvise(int fd, off_t offset, off_t len, int advice)
#endif /* APPLE_MAC */ #endif /* APPLE_MAC */
#if defined(APPLE_MAC) || defined(CYGWIN)
/*
* The following functions were copied from GNU Library C to make F3
* more portable.
*/
/* Data structure for communication with thread safe versions. This
* type is to be regarded as opaque. It's only exported because users
* have to allocate objects of this type.
*/
struct drand48_data {
unsigned short int __x[3]; /* Current state. */
unsigned short int __old_x[3]; /* Old state. */
unsigned short int __c; /* Additive const. in congruential formula. */
unsigned short int __init; /* Flag for initializing. */
unsigned long long int __a; /* Factor in congruential formula. */
};
/* Seed random number generator. */
extern int srand48_r(long int __seedval, struct drand48_data *__buffer)
__attribute__ ((nonnull(2)));
/* Return non-negative, long integer in [0,2^31). */
extern int lrand48_r(struct drand48_data *__restrict __buffer,
long int *__restrict __result) __attribute__ ((nonnull(1, 2)));
#endif /* APPLE_MAC or CYGWIN */
#endif /* HEADER_UTILS_H */ #endif /* HEADER_UTILS_H */