diff options
Diffstat (limited to 'include/bin.h')
| -rwxr-xr-x | include/bin.h | 315 |
1 files changed, 242 insertions, 73 deletions
diff --git a/include/bin.h b/include/bin.h index d764f09..d06b074 100755 --- a/include/bin.h +++ b/include/bin.h @@ -1,47 +1,77 @@ // bin.h - flat file, fixed block size, time series database +// +// Thread safety: Not thread-safe. External synchronization required. +// Behavior: No input validation — out-of-order data persists as-is. +// Unbuffered I/O by default (use _buffered variants for performance). +// _ok variants return 1 on success, 0 on any error (invalid args, I/O fail, +// overflow). Non-_ok variants remain for backward compatibility. #ifndef BIN_H #define BIN_H +/* USER-DEFINED (define before including): + * typedef <numerical_type> bin_key_t; + */ + #include <stddef.h> #include <stdint.h> #include <stdio.h> +#include <string.h> #include "type.h" typedef struct { - uint_t length; - uint_t block_size; + u64 length; + u64 block_size; } bin_meta_t; -FILE *bin_init(char const *, uint_t); +FILE *bin_init(char const *, u64); +FILE *bin_init_buffered(char const *, u64); FILE *bin_open(char const *path); -void bin_close(FILE *); -void bin_read(FILE *, int_t, void *, uint_t); -void bin_write(FILE *, int_t, void *, uint_t); -void bin_insert(FILE *, int_t, void *, uint_t); -void bin_append(FILE *, void *, uint_t); +FILE *bin_open_buffered(char const *path); +int bin_read(FILE *, i64, void *, u64); +void bin_write(FILE *, i64, void *, u64); +int bin_write_ok(FILE *, i64, void *, u64); +void bin_insert(FILE *, i64, void *, u64); +int bin_insert_ok(FILE *, i64, void *, u64); +void bin_append(FILE *, void *, u64); +int bin_append_ok(FILE *, void *, u64); +int bin_close(FILE *); -uint_t bin_length(FILE *); -uint_t bin_block_size(FILE *); +u64 bin_length(FILE *); +u64 bin_block_size(FILE *); -int_t bin_search(FILE *, bin_key_t); -uint_t bin_fuzzy_index(int_t); +i64 bin_search(FILE *, bin_key_t); +u64 bin_fuzzy_index(i64); #endif // BIN_H #ifdef BIN_IMPLEMENTATION // IMPLEMENTATION -#include <assert.h> #include <stdlib.h> -static void bin_write_length(FILE *, uint_t); -static void bin_write_block_size(FILE *, uint_t); +static void bin_write_length(FILE *, u64); +static void bin_write_block_size(FILE *, u64); -#define index_bytes(i, bs) ((i * bs) + sizeof(bin_meta_t)) +static inline i64 index_bytes_safe(i64 i, u64 bs, u64 *out) { + if (bs == 0 || i < 0 || (u64)i > (UINT64_MAX - sizeof(bin_meta_t)) / bs) + return -1; + *out = (u64)i * bs + sizeof(bin_meta_t); + return 0; +} #define member_sizeof(type, member) (sizeof(((type *)0)->member)) +static inline int fseek_safe(FILE *f, u64 offset) { +#ifdef _WIN32 + return _fseeki64(f, (long long)offset, SEEK_SET); +#else + if ((u64)(long)offset != offset) + return -1; + return fseek(f, (long)offset, SEEK_SET); +#endif +} + // bin_init() // // Creates the desired binary file @@ -50,7 +80,9 @@ static void bin_write_block_size(FILE *, uint_t); // // return - The newly created file -FILE *bin_init(char const *path, uint_t block_size) { +FILE *bin_init(char const *path, u64 block_size) { + if (!path) + return NULL; FILE *f = fopen(path, "wb+"); if (!f) @@ -64,6 +96,20 @@ FILE *bin_init(char const *path, uint_t block_size) { return f; } +FILE *bin_init_buffered(char const *path, u64 block_size) { + if (!path) + return NULL; + FILE *f = fopen(path, "wb+"); + + if (!f) + return NULL; + + bin_write_length(f, 0); + bin_write_block_size(f, block_size); + + return f; +} + // bin_open() // // Opens the desired binary file @@ -73,6 +119,8 @@ FILE *bin_init(char const *path, uint_t block_size) { // return - The newly opened file FILE *bin_open(char const *path) { + if (!path) + return NULL; FILE *f = fopen(path, "rb+"); if (!f) @@ -83,13 +131,23 @@ FILE *bin_open(char const *path) { return f; } +FILE *bin_open_buffered(char const *path) { + if (!path) + return NULL; + return fopen(path, "rb+"); +} + // bin_close() // // Closes the desired binary file // // f - The file descriptor to be closed -void bin_close(FILE *f) { fclose(f); } +int bin_close(FILE *f) { + if (!f) return 0; + int r = fclose(f); + return r == 0; +} // bin_read() // @@ -100,13 +158,33 @@ void bin_close(FILE *f) { fclose(f); } // data - The block_t buffer to be read into // n - The number of elements to read into the buffer -void bin_read(FILE *f, int_t i, void *data, uint_t n) { - uint_t bs = bin_block_size(f); +int bin_read(FILE *f, i64 i, void *data, u64 n) { + if (!f || !data || n == 0) + return 0; + u64 bs = bin_block_size(f); + if (bs == 0) + return 0; - assert(0 <= i && (i + n) <= bin_length(f)); + if (i < 0) + return 0; + u64 len = bin_length(f); + if ((u64)i + n > len) + return 0; - fseek(f, index_bytes(i, bs), SEEK_SET); - fread(data, bs, n, f); + u64 offset = 0; + if (index_bytes_safe(i, bs, &offset) != 0) + return 0; + if (bs > SIZE_MAX / n) + return 0; + fseek_safe(f, offset); + size_t read_n = fread(data, (size_t)bs, (size_t)n, f); + if (read_n != n) { + if ((n - read_n) > SIZE_MAX / bs) + return (int)read_n; + memset((char *)data + read_n * bs, 0, (n - read_n) * bs); + return (int)read_n; + } + return (int)n; } // bin_write() @@ -118,20 +196,30 @@ void bin_read(FILE *f, int_t i, void *data, uint_t n) { // data - The block_t buffer to write from // n - The number of elements to write from the buffer -void bin_write(FILE *f, int_t i, void *data, uint_t n) { - uint_t l = bin_length(f); - uint_t bs = bin_block_size(f); +void bin_write(FILE *f, i64 i, void *data, u64 n) { + (void)bin_write_ok(f, i, data, n); +} - assert(0 <= i && i <= l); +int bin_write_ok(FILE *f, i64 i, void *data, u64 n) { + if (!f || !data || n == 0) + return 0; + u64 l = bin_length(f); + u64 bs = bin_block_size(f); + if (bs == 0) + return 0; - fseek(f, index_bytes(i, bs), SEEK_SET); - fwrite(data, bs, n, f); + if (i < 0) + return 0; + if ((u64)i + n > l) + return 0; - if ((i + n) >= l) { - l += (i + n - l); - } - - bin_write_length(f, l); + u64 offset = 0; + if (index_bytes_safe(i, bs, &offset) != 0) + return 0; + if (fseek_safe(f, offset) != 0) + return 0; + size_t written = fwrite(data, bs, n, f); + return written == (size_t)n; } // bin_append() @@ -142,14 +230,31 @@ void bin_write(FILE *f, int_t i, void *data, uint_t n) { // data - The blocks to append to the file // n - The number of block to be appended -void bin_append(FILE *f, void *data, uint_t n) { - uint_t l = bin_length(f); - uint_t bs = bin_block_size(f); +void bin_append(FILE *f, void *data, u64 n) { + (void)bin_append_ok(f, data, n); +} - fseek(f, index_bytes(l, bs), SEEK_SET); - fwrite(data, bs, n, f); +int bin_append_ok(FILE *f, void *data, u64 n) { + if (!f || !data || n == 0) + return 0; + u64 l = bin_length(f); + u64 bs = bin_block_size(f); + if (bs == 0) + return 0; + if (l > UINT64_MAX - n) + return 0; + + u64 offset = 0; + if (index_bytes_safe((i64)l, bs, &offset) != 0) + return 0; + if (fseek_safe(f, offset) != 0) + return 0; + size_t written = fwrite(data, bs, n, f); + if (written != (size_t)n) + return 0; bin_write_length(f, l + n); + return 1; } // bin_insert() @@ -161,24 +266,59 @@ void bin_append(FILE *f, void *data, uint_t n) { // data - The blocks to insert into the file // n - The number of blocks to be inserted -void bin_insert(FILE *f, int_t i, void *data, uint_t n) { - uint_t l = bin_length(f); - uint_t bs = bin_block_size(f); +void bin_insert(FILE *f, i64 i, void *data, u64 n) { + (void)bin_insert_ok(f, i, data, n); +} + +int bin_insert_ok(FILE *f, i64 i, void *data, u64 n) { + if (!f || !data || n == 0) + return 0; + u64 l = bin_length(f); + u64 bs = bin_block_size(f); + if (bs == 0) + return 0; - assert(0 <= i && i <= l); + if (i < 0 || (u64)i > l) + return 0; - uint_t tmp_n = (l - i) * bs; + u64 blocks_to_move = l - (u64)i; + if (blocks_to_move > UINT64_MAX / bs) + return 0; - uint8_t tmp[tmp_n]; + if (l > UINT64_MAX - n) + return 0; - fseek(f, index_bytes(i, bs), SEEK_SET); - fread(tmp, bs, l - i, f); + u64 offset = 0; + if (index_bytes_safe(i, bs, &offset) != 0) + return 0; + if (fseek_safe(f, offset) != 0) + return 0; - fseek(f, index_bytes(i, bs), SEEK_SET); - fwrite(data, bs, n, f); - fwrite(tmp, 1, tmp_n, f); + if (blocks_to_move > 0) { + u64 tmp_n = blocks_to_move * bs; + if (tmp_n > SIZE_MAX) + return 0; + u8 *tmp = malloc((size_t)tmp_n); + if (tmp == NULL) + return 0; + size_t rn = fread(tmp, (size_t)bs, (size_t)blocks_to_move, f); + if (rn != (size_t)blocks_to_move) { + memset((char *)tmp + rn * (size_t)bs, 0, ((size_t)blocks_to_move - rn) * (size_t)bs); + } + + if (fseek_safe(f, offset) != 0) { free(tmp); return 0; } + size_t written = fwrite(data, bs, n, f); + if (written != (size_t)n) { free(tmp); return 0; } + fwrite(tmp, 1, (size_t)tmp_n, f); + free(tmp); + } else { + size_t written = fwrite(data, bs, n, f); + if (written != (size_t)n) + return 0; + } bin_write_length(f, l + n); + return 1; } // bin_length() @@ -189,11 +329,13 @@ void bin_insert(FILE *f, int_t i, void *data, uint_t n) { // // return - The length / number of entries in the file -uint_t bin_length(FILE *f) { - uint_t n = 0; +u64 bin_length(FILE *f) { + if (!f) return 0; + u64 n = 0; fseek(f, offsetof(bin_meta_t, length), SEEK_SET); - fread(&n, member_sizeof(bin_meta_t, length), 1, f); + size_t rn = fread(&n, member_sizeof(bin_meta_t, length), 1, f); + if (rn != 1) return 0; return n; } @@ -206,11 +348,13 @@ uint_t bin_length(FILE *f) { // // return - The block size for the entries in the file -uint_t bin_block_size(FILE *f) { - uint_t n = 0; +u64 bin_block_size(FILE *f) { + if (!f) return 0; + u64 n = 0; fseek(f, offsetof(bin_meta_t, block_size), SEEK_SET); - fread(&n, member_sizeof(bin_meta_t, block_size), 1, f); + size_t rn = fread(&n, member_sizeof(bin_meta_t, block_size), 1, f); + if (rn != 1) return 0; return n; } @@ -226,21 +370,38 @@ uint_t bin_block_size(FILE *f) { // The returned value is -( index + 1 ) where index is that of the // first element greater than k or bin_length(). -int_t bin_search(FILE *f, bin_key_t k) { - uint_t origin = ftell(f); +i64 bin_search(FILE *f, bin_key_t k) { + if (!f) return -1; + fpos_t origin; + fgetpos(f, &origin); - int_t l = 0; - int_t r = bin_length(f) - 1; - int_t m; + u64 len = bin_length(f); + if (len == 0) { + fsetpos(f, &origin); + return -1; + } + + i64 l = 0; + i64 r = (i64)len - 1; + i64 m; - uint_t bs = bin_block_size(f); + u64 bs = bin_block_size(f); - bin_key_t key; + bin_key_t key = 0; + int found = 0; while (l <= r) { - m = (l + r) / 2; - fseek(f, index_bytes(m, bs), SEEK_SET); - fread(&key, sizeof(k), 1, f); + m = l + (r - l) / 2; + u64 offset = 0; + if (index_bytes_safe(m, bs, &offset) != 0) { + fsetpos(f, &origin); + return -(l + 1); + } + fseek_safe(f, offset); + if (fread(&key, sizeof(k), 1, f) != 1) { + fsetpos(f, &origin); + return -(l + 1); + } if (key < k) l = m + 1; @@ -248,13 +409,15 @@ int_t bin_search(FILE *f, bin_key_t k) { else if (key > k) r = m - 1; - else + else { + found = 1; break; + } } - fseek(f, origin, SEEK_SET); + fsetpos(f, &origin); - if (key != k) + if (!found) return -(l + 1); return m; @@ -270,7 +433,11 @@ int_t bin_search(FILE *f, bin_key_t k) { // return - The index remapped the binary file. If the index is already // positive, then no operation occurrs. -uint_t bin_fuzzy_index(int_t i) { return (i < 0) ? -(i + 1) : i; } +u64 bin_fuzzy_index(i64 i) { + if (i < 0) + return (u64)(-(i + 1)); + return (u64)i; +} // bin_write_length() // @@ -279,9 +446,11 @@ uint_t bin_fuzzy_index(int_t i) { return (i < 0) ? -(i + 1) : i; } // f - The file to be written to // count - The length to be written to the file -static void bin_write_length(FILE *f, uint_t length) { +static void bin_write_length(FILE *f, u64 length) { fseek(f, offsetof(bin_meta_t, length), SEEK_SET); - fwrite(&length, member_sizeof(bin_meta_t, length), 1, f); + if (fwrite(&length, member_sizeof(bin_meta_t, length), 1, f) != 1) { + clearerr(f); + } } // bin_write_block_size() @@ -291,7 +460,7 @@ static void bin_write_length(FILE *f, uint_t length) { // f - The file to be written to // count - The block size to be written to the file -static void bin_write_block_size(FILE *f, uint_t block_size) { +static void bin_write_block_size(FILE *f, u64 block_size) { fseek(f, offsetof(bin_meta_t, block_size), SEEK_SET); fwrite(&block_size, member_sizeof(bin_meta_t, block_size), 1, f); } |