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.
.PP
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
WARNING: all data on the tested disk might be lost!
.SH OPTIONS

View File

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

View File

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

83
utils.c
View File

@ -33,14 +33,14 @@ int is_my_file(const char *filename)
p++;
} while (isdigit(*p));
return (p[0] == '.') && (p[1] == 'f') && (p[2] == 'f') &&
(p[3] == 'f') && (p[4] == '\0');
return (p[0] == '.') && (p[1] == 'h') && (p[2] == '2') &&
(p[3] == 'w') && (p[4] == '\0');
}
void full_fn_from_number(char *full_fn, const char **filename,
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);
*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"
"\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 <sys/time.h>
#include <limits.h>
#include <stdint.h>
#define SECTOR_SIZE (512)
#define GIGABYTES (1024 * 1024 * 1024)
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);
/* @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);
static inline uint64_t random_number(uint64_t prv_number)
{
return prv_number * 4294967311ULL + 17;
}
#ifdef APPLE_MAC
/* 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 */
#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 */