/** * @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 --- */