More simply stream management.

This commit is contained in:
Andrea Mazzoleni 2011-06-26 11:10:51 +02:00
parent 2eec5eb675
commit b90e7fdacf
3 changed files with 319 additions and 164 deletions

160
state.c
View file

@ -53,7 +53,7 @@ void state_done(struct snapraid_state* state)
void state_config(struct snapraid_state* state, const char* path, int verbose, int gui, int force_zero, int force_empty, int expect_unrecoverable, int expect_recoverable)
{
FILE* f;
STREAM* f;
unsigned line;
unsigned content_count;
@ -70,7 +70,7 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
fflush(stderr);
}
f = fopen(path, "rt");
f = sopen(path);
if (!f) {
if (errno == ENOENT) {
fprintf(stderr, "No configuration file found at '%s'\n", path);
@ -91,20 +91,20 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
int c;
/* skip initial spaces */
strgetspace(f);
sgetspace(f);
/* read the command */
ret = strgettoken(f, tag, sizeof(tag));
ret = sgettok(f, tag, sizeof(tag));
if (ret != 0) {
fprintf(stderr, "Error reading the configuration file '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
/* skip spaces after the command */
strgetspace(f);
sgetspace(f);
if (strcmp(tag, "block_size") == 0) {
ret = strgetu32(f, &state->block_size);
ret = sgetu32(f, &state->block_size);
if (ret != 0) {
fprintf(stderr, "Invalid 'block_size' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -129,7 +129,7 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
exit(EXIT_FAILURE);
}
ret = strgettoken(f, buffer, sizeof(buffer));
ret = sgettok(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid 'parity' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -142,7 +142,7 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
exit(EXIT_FAILURE);
}
ret = strgettoken(f, buffer, sizeof(buffer));
ret = sgettok(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid 'q-parity' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -153,7 +153,7 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
} else if (strcmp(tag, "content") == 0) {
struct snapraid_content* content;
ret = strgettoken(f, buffer, sizeof(buffer));
ret = sgettok(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid 'content' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -166,15 +166,15 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
} else if (strcmp(tag, "disk") == 0) {
char dir[PATH_MAX];
ret = strgettoken(f, buffer, sizeof(buffer));
ret = sgettok(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid 'disk' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
strgetspace(f);
sgetspace(f);
ret = strgettoken(f, dir, sizeof(dir));
ret = sgettok(f, dir, sizeof(dir));
if (ret != 0) {
fprintf(stderr, "Invalid 'disk' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -184,7 +184,7 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
} else if (strcmp(tag, "exclude") == 0) {
struct snapraid_filter* filter;
ret = strgettoken(f, buffer, sizeof(buffer));
ret = sgettok(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid 'exclude' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -199,7 +199,7 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
} else if (strcmp(tag, "include") == 0) {
struct snapraid_filter* filter;
ret = strgettoken(f, buffer, sizeof(buffer));
ret = sgettok(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid 'include' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -214,37 +214,37 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
} else if (tag[0] == 0) {
/* allow empty lines */
} else if (tag[0] == '#') {
ret = strgetline(f, buffer, sizeof(buffer));
ret = sgetline(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid comment in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr, "Unknown tag '%s' in '%s' at line %u\n", tag, path, line);
fprintf(stderr, "Invalid command '%s' in '%s' at line %u\n", tag, path, line);
exit(EXIT_FAILURE);
}
/* skip final spaces */
strgetspace(f);
sgetspace(f);
/* next line */
c = strgetcnl(f);
c = sgeteol(f);
if (c == EOF) {
break;
}
if (c != '\n') {
fprintf(stderr, "Extra char '%c' after command specification in '%s' at line %u\n", (char)c, path, line);
fprintf(stderr, "Extra data in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
++line;
}
if (ferror(f)) {
if (serror(f)) {
fprintf(stderr, "Error reading the configuration file '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
fclose(f);
sclose(f);
if (state->parity[0] == 0) {
fprintf(stderr, "No 'parity' specification in '%s'\n", path);
@ -279,7 +279,7 @@ void state_config(struct snapraid_state* state, const char* path, int verbose, i
void state_read(struct snapraid_state* state)
{
FILE* f;
STREAM* f;
char path[PATH_MAX];
struct snapraid_disk* disk;
struct snapraid_file* file;
@ -305,7 +305,7 @@ void state_read(struct snapraid_state* state)
}
printf("Loading state from %s...\n", path);
f = fopen(path, "rt");
f = sopen(path);
if (f != 0) {
/* if openend stop the search */
break;
@ -342,56 +342,24 @@ void state_read(struct snapraid_state* state)
while (1) {
char buffer[PATH_MAX];
char tag[PATH_MAX];
int ret;
int cmd;
int c;
/* decode the command */
cmd = 0;
c = strgetc(f);
if (c == 'b') {
if (strgetc(f) == 'l' && strgetc(f) == 'k') {
c = strgetc(f);
if (c == ' ') {
cmd = 'b';
} else if (c == 's' && strgetc(f) == 'i' && strgetc(f) == 'z' && strgetc(f) == 'e' && strgetc(f) == ' ') {
cmd = 's';
}
}
} else if (c == 'i') {
if (strgetc(f) == 'n' && strgetc(f) == 'v' && strgetc(f) == ' ') {
cmd = 'i';
}
} else if (c == 'f') {
if (strgetc(f) == 'i' && strgetc(f) == 'l' && strgetc(f) == 'e' && strgetc(f) == ' ') {
cmd = 'f';
}
} else if (c == 'c') {
if (strgetc(f) == 'h' && strgetc(f) == 'e' && strgetc(f) == 'c' && strgetc(f) == 'k'
&& strgetc(f) == 's' && strgetc(f) == 'u' && strgetc(f) == 'm' && strgetc(f) == ' ') {
cmd = 'c';
}
} else if (c == '\n') {
} else if (c == '\r') {
c = strgetc(f);
if (c != '\n') {
fprintf(stderr, "Unexpected carrige return in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
} else if (c == '#') {
int ret = strgetline(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid comment in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
} else if (c == EOF) {
break;
} else {
fprintf(stderr, "Unknown char '%c' in '%s' at line %u\n", (char)c, path, line);
/* read the command */
ret = sgettok(f, tag, sizeof(tag));
if (ret != 0) {
fprintf(stderr, "Error reading the configuration file '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
if (cmd == 'b' || cmd == 'i') {
/* skip only one space if present */
c = sgetc(f);
if (c != ' ') {
sungetc(c, f);
}
if (strcmp(tag, "blk") == 0 || strcmp(tag, "inv") == 0) {
/* "blk"/"inv" command */
block_off_t v_pos;
struct snapraid_block* block;
@ -401,7 +369,7 @@ void state_read(struct snapraid_state* state)
exit(EXIT_FAILURE);
}
ret = strgetu32(f, &v_pos);
ret = sgetu32(f, &v_pos);
if (ret != 0) {
fprintf(stderr, "Invalid 'blk' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -422,10 +390,10 @@ void state_read(struct snapraid_state* state)
block->parity_pos = v_pos;
/* check if we are at the end of the line */
c = strgetcnl(f);
c = sgeteol(f);
if (c == '\n') {
/* no hash present */
ungetc(c, f);
sungetc(c, f);
} else {
if (c != ' ') {
fprintf(stderr, "Invalid 'blk' specification in '%s' at line %u\n", path, line);
@ -433,7 +401,7 @@ void state_read(struct snapraid_state* state)
}
/* set the hash only if present */
ret = strgethex(f, block->hash, HASH_SIZE);
ret = sgethex(f, block->hash, HASH_SIZE);
if (ret != 0) {
fprintf(stderr, "Invalid 'blk' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -443,7 +411,7 @@ void state_read(struct snapraid_state* state)
}
/* set the parity only if present */
if (cmd == 'b')
if (strcmp(tag, "blk") == 0)
block_flag_set(block, BLOCK_HAS_PARITY);
/* parity implies hash */
@ -465,7 +433,7 @@ void state_read(struct snapraid_state* state)
/* stat */
++count_block;
} else if (cmd == 'f') {
} else if (strcmp(tag, "file") == 0) {
/* file */
char buffer[PATH_MAX];
char sub[PATH_MAX];
@ -479,55 +447,55 @@ void state_read(struct snapraid_state* state)
exit(EXIT_FAILURE);
}
ret = strgettoken(f, buffer, sizeof(buffer));
ret = sgettok(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
c = strgetc(f);
c = sgetc(f);
if (c != ' ') {
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
ret = strgetu64(f, &v_size);
ret = sgetu64(f, &v_size);
if (ret != 0) {
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
c = strgetc(f);
c = sgetc(f);
if (c != ' ') {
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
ret = strgetu64(f, &v_mtime);
ret = sgetu64(f, &v_mtime);
if (ret != 0) {
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
c = strgetc(f);
c = sgetc(f);
if (c != ' ') {
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
ret = strgetu64(f, &v_inode);
ret = sgetu64(f, &v_inode);
if (ret != 0) {
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
c = strgetc(f);
c = sgetc(f);
if (c != ' ') {
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
ret = strgetline(f, sub, sizeof(sub));
ret = sgetline(f, sub, sizeof(sub));
if (ret != 0) {
fprintf(stderr, "Invalid 'file' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -567,8 +535,8 @@ void state_read(struct snapraid_state* state)
/* stat */
++count_file;
} else if (cmd == 'c') {
ret = strgettoken(f, buffer, sizeof(buffer));
} else if (strcmp(tag, "checksum") == 0) {
ret = sgettok(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid 'checksum' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -582,10 +550,10 @@ void state_read(struct snapraid_state* state)
fprintf(stderr, "Invalid 'checksum' specification '%s' in '%s' at line %u\n", buffer, path, line);
exit(EXIT_FAILURE);
}
} else if (cmd == 's') {
} else if (strcmp(tag, "blksize") == 0) {
block_off_t blksize;
ret = strgetu32(f, &blksize);
ret = sgetu32(f, &blksize);
if (ret != 0) {
fprintf(stderr, "Invalid 'blksize' specification in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
@ -596,21 +564,33 @@ void state_read(struct snapraid_state* state)
fprintf(stderr, "Please restore the 'block_size' value in the configuration file to '%u'\n", blksize / 1024);
exit(EXIT_FAILURE);
}
} else if (tag[0] == 0) {
/* allow empty lines */
sgetspace(f);
} else if (tag[0] == '#') {
ret = sgetline(f, buffer, sizeof(buffer));
if (ret != 0) {
fprintf(stderr, "Invalid comment in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
} else {
fprintf(stderr, "Invalid command '%s' in '%s' at line %u\n", tag, path, line);
exit(EXIT_FAILURE);
}
/* next line */
c = strgetcnl(f);
c = sgeteol(f);
if (c == EOF) {
break;
}
if (c != '\n') {
fprintf(stderr, "Extra char '%c' after command specification in '%s' at line %u\n", (char)c, path, line);
fprintf(stderr, "Extra data in '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
++line;
}
if (ferror(f)) {
if (serror(f)) {
fprintf(stderr, "Error reading the content file '%s' at line %u\n", path, line);
exit(EXIT_FAILURE);
}
@ -620,7 +600,7 @@ void state_read(struct snapraid_state* state)
exit(EXIT_FAILURE);
}
fclose(f);
sclose(f);
if (state->verbose) {
printf("\tfile %u\n", count_file);

208
util.c
View file

@ -84,28 +84,77 @@ char* strdechex(void* void_data, unsigned data_len, char* str)
}
/****************************************************************************/
/* get */
/* stream */
int strgettoken(FILE* f, char* s, unsigned size)
STREAM* sopen(const char* file)
{
char* i = s;
char* send = s + size;
STREAM* s = malloc_nofail(sizeof(STREAM));
s->f = open(file, O_RDONLY | O_BINARY | O_SEQUENTIAL);
if (s->f == -1) {
free(s);
return 0;
}
s->buffer = malloc_nofail(STREAM_SIZE);
s->pos = s->buffer;
s->end = s->buffer;
s->state = STREAM_OK;
return s;
}
void sclose(STREAM* s)
{
close(s->f);
free(s->buffer);
free(s);
}
int sflow(STREAM* s)
{
ssize_t ret;
if (s->state != STREAM_OK)
return EOF;
ret = read(s->f, s->buffer, STREAM_SIZE);
if (ret < 0) {
s->state = STREAM_ERROR;
return EOF;
}
if (ret == 0) {
s->state = STREAM_EOF;
return EOF;
}
s->pos = s->buffer;
s->end = s->buffer + ret;
return *s->pos++;
}
int sgettok(STREAM* f, char* str, int size)
{
char* i = str;
char* send = str + size;
int c;
while (1) {
c = strgetc(f);
c = sgetc(f);
if (c == EOF) {
break;
}
if (c == ' ' || c == '\t') {
ungetc(c, f);
sungetc(c, f);
break;
}
if (c == '\n') {
/* remove ending carrige return to support the Windows CR+LF format */
if (i != s && i[-1] == '\r')
if (i != str && i[-1] == '\r')
--i;
ungetc(c, f);
sungetc(c, f);
break;
}
@ -120,29 +169,52 @@ int strgettoken(FILE* f, char* s, unsigned size)
return 0;
}
int strgetline(FILE* f, char* s, unsigned size)
int sgetline(STREAM* f, char* str, int size)
{
char* i = s;
char* send = s + size;
char* i = str;
char* send = str + size;
int c;
while (1) {
c = strgetc(f);
if (c == EOF) {
break;
}
if (c == '\n') {
/* remove ending carrige return to support the Windows CR+LF format */
if (i != s && i[-1] == '\r')
--i;
ungetc(c, f);
break;
/* if there is enough data in memory */
if (sptrlookup(f, size)) {
unsigned char* pos = sptrget(f);
while (1) {
c = *pos++;
if (c == '\n') {
/* remove ending carrige return to support the Windows CR+LF format */
if (i != str && i[-1] == '\r')
--i;
--pos;
break;
}
*i++ = c;
if (i == send)
return -1;
}
*i++ = c;
sptrset(f, pos);
} else {
while (1) {
c = sgetc(f);
if (c == EOF) {
break;
}
if (c == '\n') {
/* remove ending carrige return to support the Windows CR+LF format */
if (i != str && i[-1] == '\r')
--i;
sungetc(c, f);
break;
}
if (i == send)
return -1;
*i++ = c;
if (i == send)
return -1;
}
}
*i = 0;
@ -150,26 +222,26 @@ int strgetline(FILE* f, char* s, unsigned size)
return 0;
}
int strgetu32(FILE* f, uint32_t* value)
int sgetu32(STREAM* f, uint32_t* value)
{
int c;
c = strgetc(f);
c = sgetc(f);
if (c>='0' && c<='9') {
uint32_t v;
v = c - '0';
c = strgetc(f);
c = sgetc(f);
while (c>='0' && c<='9') {
v *= 10;
v += c - '0';
c = strgetc(f);
c = sgetc(f);
}
*value = v;
ungetc(c, f);
sungetc(c, f);
return 0;
} else {
/* nothing read */
@ -177,26 +249,26 @@ int strgetu32(FILE* f, uint32_t* value)
}
}
int strgetu64(FILE* f, uint64_t* value)
int sgetu64(STREAM* f, uint64_t* value)
{
int c;
c = strgetc(f);
c = sgetc(f);
if (c>='0' && c<='9') {
uint64_t v;
v = c - '0';
c = strgetc(f);
c = sgetc(f);
while (c>='0' && c<='9') {
v *= 10;
v += c - '0';
c = strgetc(f);
c = sgetc(f);
}
*value = v;
ungetc(c, f);
sungetc(c, f);
return 0;
} else {
/* nothing read */
@ -204,33 +276,63 @@ int strgetu64(FILE* f, uint64_t* value)
}
}
int strgethex(FILE* f, void* void_data, unsigned data_len)
int sgethex(STREAM* f, void* void_data, int size)
{
unsigned char* data = void_data;
unsigned i;
for(i=0;i<data_len;++i) {
unsigned b0;
unsigned b1;
unsigned b;
int c;
/* if there is enough data in memory */
if (sptrlookup(f, size * 2)) {
/* optimized version with all the data in memory */
unsigned char* pos = sptrget(f);
unsigned x = 0;
c = strgetc(f);
if (c == EOF)
while (size--) {
unsigned b0;
unsigned b1;
unsigned b;
b0 = strdecset[pos[0]];
b1 = strdecset[pos[1]];
pos += 2;
b = (b0 << 4) | b1;
x |= b;
*data++ = b;
}
/* at the end check if a digit was wrong */
if (x > 0xFF) {
return -1;
b0 = strdecset[c];
}
c = strgetc(f);
if (c == EOF)
return -1;
b1 = strdecset[c];
sptrset(f, pos);
} else {
/* standard version using sgetc() */
while (size--) {
unsigned b0;
unsigned b1;
unsigned b;
int c;
b = (b0 << 4) | b1;
c = sgetc(f);
if (c == EOF)
return -1;
b0 = strdecset[c];
if (b > 0xFF)
return -1;
c = sgetc(f);
if (c == EOF)
return -1;
b1 = strdecset[c];
*data++ = b;
b = (b0 << 4) | b1;
if (b > 0xFF)
return -1;
*data++ = b;
}
}
return 0;

115
util.h
View file

@ -31,32 +31,105 @@ void strenchex(char* str, const void* void_data, unsigned data_len);
*/
char* strdechex(void* void_data, unsigned data_len, char* str);
/****************************************************************************/
/* get */
/* stream */
#define STREAM_SIZE (64*1024)
#define STREAM_OK 0
#define STREAM_ERROR -1
#define STREAM_EOF 1
struct stream {
unsigned char* buffer;
unsigned char* pos;
unsigned char* end;
int state;
int f;
};
/**
* Get a char from a stream.
* Opaque STREAM type. Like ::FILE.
*/
static inline int strgetc(FILE* f)
typedef struct stream STREAM;
/**
* Open a stream for reading. Like fopen().
*/
STREAM* sopen(const char* file);
/**
* Close a stream. Like fclose().
*/
void sclose(STREAM* s);
/**
* Fill the stream buffer and read a char.
*/
int sflow(STREAM* s);
/**
* Checks if the buffer has enough data loaded.
*/
static inline int sptrlookup(STREAM* s, int size)
{
#if HAVE_GETC_UNLOCKED
return getc_unlocked(f);
#else
return getc(f);
#endif
return s->pos + size <= s->end;
}
/**
* Gets the current stream ptr.
*/
unsigned char* sptrget(STREAM* s)
{
return s->pos;
}
/**
* Set the current stream ptr.
*/
void sptrset(STREAM* s, unsigned char* ptr)
{
s->pos = ptr;
}
/**
* Read a char. Like fgetc().
*/
static inline int sgetc(STREAM* s)
{
if (s->pos == s->end)
return sflow(s);
return *s->pos++;
}
/**
* Unread a char.
* Like ungetc() but you have to unget the same char read.
*/
static inline void sungetc(int c, STREAM* s)
{
if (c != EOF)
--s->pos;
}
/**
* Check the error status. Like ferror().
*/
static inline int serror(STREAM* s)
{
return s->state == STREAM_ERROR;
}
/**
* Get a char from a stream, ignoring one '\r'.
*/
static inline int strgetcnl(FILE* f)
static inline int sgeteol(STREAM* f)
{
int c;
c = strgetc(f);
c = sgetc(f);
if (c == '\r')
c = strgetc(f);
c = sgetc(f);
return c;
}
@ -65,18 +138,18 @@ static inline int strgetcnl(FILE* f)
* Read all the spaces and tabs.
* Returns the number of spaces and tabs read.
*/
static inline int strgetspace(FILE* f)
static inline int sgetspace(STREAM* f)
{
int count = 0;
int c;
c = strgetc(f);
c = sgetc(f);
while (c == ' ' || c == '\t') {
++count;
c = strgetc(f);
c = sgetc(f);
}
ungetc(c, f);
sungetc(c, f);
return count;
}
@ -85,34 +158,34 @@ static inline int strgetspace(FILE* f)
* Stops at the first ' ', '\t', '\n' or EOF.
* Returns error if the buffer is too small.
*/
int strgettoken(FILE* f, char* str, unsigned size);
int sgettok(STREAM* f, char* str, int size);
/**
* Read until the end of line.
* Stops at the first '\n' or EOF.
* Returns error if the buffer is too small.
*/
int strgetline(FILE* f, char* str, unsigned size);
int sgetline(STREAM* f, char* str, int size);
/**
* Read a 32 bit number.
* Stops at the first not digit char or EOF.
* Returns error if there isn't enough to read.
*/
int strgetu32(FILE* f, uint32_t* value);
int sgetu32(STREAM* f, uint32_t* value);
/**
* Read a 64 bit number.
* Stops at the first not digit char.
* Returns error if there isn't enough to read.
*/
int strgetu64(FILE* f, uint64_t* value);
int sgetu64(STREAM* f, uint64_t* value);
/**
* Read an hexadecimal string of fixed length.
* Returns error if there isn't enough to read.
*/
int strgethex(FILE* f, void* void_data, unsigned data_len);
int sgethex(STREAM* f, void* data, int size);
/****************************************************************************/
/* path */