diff options
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/fsutil.c | 55 | ||||
-rw-r--r-- | src/shared/include/camellia/fsutil.h | 13 |
2 files changed, 68 insertions, 0 deletions
diff --git a/src/shared/fsutil.c b/src/shared/fsutil.c new file mode 100644 index 0000000..a1dabfd --- /dev/null +++ b/src/shared/fsutil.c @@ -0,0 +1,55 @@ +#include <camellia/fsutil.h> +#include <limits.h> + +// TODO shared assert +#define assert(...) {} + +void fs_normslice(long *restrict offset, size_t *restrict length, size_t max, bool expand) +{ + assert(max <= (size_t)LONG_MAX); + + if (*offset < 0) { + /* Negative offsets are relative to EOF + 1. + * Thus: + * write(-1) writes right after the file ends; atomic append + * write(-n) writes, overriding the last (n-1) bytes + * read(-n) reads the last (n-1) bytes + */ + *offset += max + 1; + if (*offset < 0) { + /* cursor went before the file, EOF */ + *length = *offset = 0; + goto end; + } + } + + if (expand) { + /* This is a write() to a file with a dynamic size. + * We don't care if it goes past the current size, because the + * driver can handle expanding it. */ + } else { + /* This operation can't extend the file, it's either: + * - any read() + * - a write() to a file with a static size (e.g. a framebuffer) + * *offset and *length describe a slice of a buffer with length max, + * so their sum must not overflow it. */ + if ((size_t)*offset <= max) { + size_t maxlen = max - (size_t)*offset; + if (true || *length > maxlen) + *length = maxlen; + } else { + /* regular EOF */ + *length = *offset = 0; + goto end; + } + } + +end: + if (*length > 0) { + assert(0 <= *offset); + if (!expand) + assert(*offset + *length <= max); + } else { + /* EOF, *offset is undefined. */ + } +} diff --git a/src/shared/include/camellia/fsutil.h b/src/shared/include/camellia/fsutil.h new file mode 100644 index 0000000..eb2b23e --- /dev/null +++ b/src/shared/include/camellia/fsutil.h @@ -0,0 +1,13 @@ +#pragma once +#include <stdbool.h> +#include <stddef.h> + +/** Normalizes the offset and length passed to a fs into safe values. + * If returns *length == 0, *offset is meaningless. + * + * @param expand Can this operation expand the target file? + * true if writing to a file with an adjustable size + * false if reading any sort of file + * or writing to a file with static size + */ +void fs_normslice(long *restrict offset, size_t *restrict length, size_t max, bool expand); |