From 57b364aaa090d1a4a48a13b2e9bdbe2c2bb4400b Mon Sep 17 00:00:00 2001 From: "Aidan C. Mullen" Date: Sat, 8 Mar 2025 09:26:26 -0500 Subject: [PATCH] Re-add filesize utility --- .gitignore | 4 +- src/filesize/filesize.c | 286 ++++++++++++++++++++++++++++++++++++++++ src/filesize/filesize.h | 15 +++ 3 files changed, 303 insertions(+), 2 deletions(-) create mode 100755 src/filesize/filesize.c create mode 100755 src/filesize/filesize.h diff --git a/.gitignore b/.gitignore index b4d5e8b..a9a4891 100644 --- a/.gitignore +++ b/.gitignore @@ -104,8 +104,8 @@ !/src/filesize /src/filesize/* -!/src/filesize/size.c -!/src/filesize/ +!/src/filesize/filesize.c +!/src/filesize/filesize.h # /src/logging !/src/logging diff --git a/src/filesize/filesize.c b/src/filesize/filesize.c new file mode 100755 index 0000000..11a7054 --- /dev/null +++ b/src/filesize/filesize.c @@ -0,0 +1,286 @@ +/** + * @author : Aidan Mullen (git@acm.contact) + * @file : filesize + * @created : Wednesday Jun 19, 2024 21:10:14 EDT + */ + +#include +#include + +#include "filesize.h" + +/* Test FILENAME_MAX on different platforms. */ + +char filename[FILENAME_MAX]; +char name[FILENAME_MAX]; + +/* + * =========== + * Buffer Size + * =========== + * + * Buffer size is chosen at compilation; it limits the block-size chosen by the + * user. When the block size is greater than the buffer, overflow occurs. + * + * The buffer size is defined in bytes. + * + * Larger buffer sizes are less accurate, which may be possible to fix if a + * position is set at the end of the read block, then the remaining area is + * read using a smaller buffer size. + */ + + /* This buffer size selection should be relegated to the options.ini file. */ + +#define BUFFER 1073741824 + +#if !defined(BUFFER) || BUFFER == 1 + +char buf[1]; /* 1B */ + +#elif BUFFER == 2 + +char buf[2]; /* 2B */ + +#elif BUFFER == 4 + +char buf[4]; /* 4B */ + +#elif BUFFER == 8 + +char buf[8]; /* 8B */ + +#elif BUFFER == 16 + +char buf[16]; /* 16B */ + +#elif BUFFER == 32 + +char buf[32]; /* 32B */ + +#elif BUFFER == 64 + +char buf[64]; /* 64B */ + +#elif BUFFER == 128 + +char buf[128]; /* 128B */ + +#elif BUFFER == 256 + +char buf[256]; /* 256B */ + +#elif BUFFER == 512 + +char buf[512]; /* 512B */ + +#elif BUFFER == 1024 + +char buf[1024]; /* 1KB */ + +#elif BUFFER == 2048 + +char buf[2048]; /* 2KB */ + +#elif BUFFER == 4096 + +char buf[4096]; /* 4KB */ + +#elif BUFFER == 8192 + +char buf[8192]; /* 8KB */ + +#elif BUFFER == 1048576 + +char buf[1048576]; /* 1MB */ + +#elif BUFFER == 536870912 + +char buf[536870912]; /* 512MB */ + +#elif BUFFER == 1073741824 + +char buf[1073741824]; /* 1GB */ + +#else + +char buf[BUFFER]; + +#endif + +unsigned long int bsize = BUFFER; + +fpos_t pos; +fpos_t end; + +/* + * =============== + * Fallback Reader + * =============== + * + * The reader counts each record in the file, then adds the value of the records + * (in bytes) in order to return the filesize. + * + * Fallback function in-case a platform solution is not present. + * Note that, depending on the buffer size, this method may be somewhat + * inaccurate, as a higher buffer size will only measure in records equivalent + * to its value, and may stop before reaching the end of the file; it may be + * possible to account for this by restarting the file-read at the endpoint + * found by fread with a lower buffer size, but this would require that fseek + * and ftell are not used, since these often use signed 32-bit integers that + * limit the maximum size they can read to ~2GB. + */ + +int get_size_fallback(void) +{ + /* + unsigned long int size = 0; + unsigned long int record = 0; + */ + unsigned long size = 0; + unsigned long record = 0; + + FILE * file; + + /* If mode is CLI */ + printf("Enter a filename: "); + + fgets(filename, sizeof(filename), stdin); + + /* Compare filename with \r\n and remove them. */ + filename[strcspn(filename, "\r\n")] = 0; + + strcpy(name, filename); + printf("Reading file \"%s\"...\n", name); + + file = fopen(filename, "rb"); + + printf("Warning: Using fallback reader; process may be slow.\n"); + printf("Initial buffer size: %lu\n", bsize); + + if (file) + { + fgetpos(file, &pos); + + printf("Attempting to read file...\n"); + + for + ( + size = 0; + (fread(buf, sizeof * buf, bsize, file) == bsize); + (record = size) + ) + { + (size = size + bsize); + fgetpos(file, &end); + printf("Read: [ %luB ]\n", size); + + if (record == size) + { + printf("No appropriately sized blocks remaining.\n"); + break; + } + } + + /* + * ============== + * Small File Fix + * ============== + * + * If result is 0, try again with lower block size, as small + * files cannot be read when the selected size is larger than them. + */ + + record = 0; + + if (size == 0) + { + while (bsize > 1) + { + printf("Attempting to read with lower buffer size...\n"); + + bsize = (bsize/2); + /* bsize = 1; */ + fsetpos(file, &pos); + printf("Buffer size lowered to %luB\n", bsize); + + while (fread(buf, sizeof * buf, bsize, file) == bsize) + { + size = size + bsize; + fgetpos(file, &pos); + printf("Read: [ %luB ]\n", size); + + if (record == size) + { + printf("No appropriately sized blocks remaining.\n"); + break; + } + + record = size; + } + } + } + + /* + * ============== + * Large File Fix + * ============== + * + * Using a large buffer to read large files quickly resulted in an + * inaccurate filesize. + * + * This block lowers the block size at the end of the reading, and + * attempts to read data after the current position in the file. It + * repeats this until the buffer size is one byte. + * + * The accuracy should be around plus-or-minus one byte when reading. + */ + + while (size > 0) + { + printf("Checking for remaining data...\n"); + + bsize = (bsize/2); + + fsetpos(file, &end); + + while (fread(buf, sizeof * buf, bsize, file) == bsize) + { + size = size + bsize; + fgetpos(file, &end); + printf("Read: [ %luB ]\n", size); + + if (record == size) + { + printf("No appropriately sized blocks remaining.\n"); + break; + } + + record = size; + } + if (bsize > 1) + { + continue; + } + else + { + printf("Buffer at minimum size; stopping.\n"); + break; + } + } + + printf("No further data to read; stopping.\n"); + + fclose(file); + + printf("Final buffer size: %luB\n", bsize); + printf("\nFilesize: %luB\n", size); + } + else + { + printf("Error: file not found.\n"); + } + + return(size); +} + +/* --- end of SIZE_C --- */ diff --git a/src/filesize/filesize.h b/src/filesize/filesize.h new file mode 100755 index 0000000..92e299f --- /dev/null +++ b/src/filesize/filesize.h @@ -0,0 +1,15 @@ +/** + * @author : Aidan Mullen (git@acm.contact) + * @file : sfileize + * @created : Wednesday Jun 19, 2024 21:13:29 EDT + */ + +#ifndef FILESIZE_H + +#define FILESIZE_H + +#endif /* end of include guard SIZE_H */ + +int get_size_fallback(void); + +/* --- end of SIZE_H --- */