diff --git a/include/util.hpp b/include/util.hpp index 61232bd6..1ec2c49d 100644 --- a/include/util.hpp +++ b/include/util.hpp @@ -26,6 +26,9 @@ enum NumberBase { int xfclose(FILE *file); int xclose(int fd); +// Measure file size with `fseek` and `ftell` idiom +long seekSize(FILE *file); + // Locale-independent character class functions bool isNewline(int c); bool isBlankSpace(int c); diff --git a/src/asm/actions.cpp b/src/asm/actions.cpp index a3e22308..de1ba1ce 100644 --- a/src/asm/actions.cpp +++ b/src/asm/actions.cpp @@ -18,7 +18,7 @@ #include "extern/utf8decoder.hpp" #include "helpers.hpp" #include "linkdefs.hpp" -#include "util.hpp" // xfclose +#include "util.hpp" // xfclose, seekSize #include "asm/charmap.hpp" #include "asm/format.hpp" @@ -151,13 +151,12 @@ std::optional act_ReadFile(std::string const &name, uint32_t maxLen Defer closeFile{[&] { xfclose(file); }}; size_t readSize = maxLen; - if (fseek(file, 0, SEEK_END) == 0) { + if (long fileSize = seekSize(file); fileSize != -1) { // If the file is seekable and shorter than the max length, // just read as many bytes as there are - if (long fileSize = ftell(file); static_cast(fileSize) < readSize) { + if (static_cast(fileSize) < readSize) { readSize = fileSize; } - fseek(file, 0, SEEK_SET); // LCOV_EXCL_START } else if (errno != ESPIPE) { error( diff --git a/src/asm/section.cpp b/src/asm/section.cpp index 63d38f22..165b5fb8 100644 --- a/src/asm/section.cpp +++ b/src/asm/section.cpp @@ -21,7 +21,7 @@ #include "helpers.hpp" #include "itertools.hpp" // InsertionOrderedMap #include "linkdefs.hpp" -#include "util.hpp" // xfclose +#include "util.hpp" // xfclose, seekSize #include "asm/fstack.hpp" #include "asm/lexer.hpp" @@ -977,14 +977,13 @@ bool sect_BinaryFile(std::string const &name, uint32_t startPos) { } Defer closeFile{[&] { xfclose(file); }}; - if (fseek(file, 0, SEEK_END) == 0) { - if (unsigned long fsize = ftell(file); - startPos > fsize) { // `ftell` cannot fail here, since `fseek` succeeded. + if (long fileSize = seekSize(file); fileSize != -1) { + if (startPos > static_cast(fileSize)) { error( - "Specified start position (%" PRIu32 ") is greater than length of \"%s\" (%lu)", + "Specified start position (%" PRIu32 ") is greater than length of \"%s\" (%ld)", startPos, name.c_str(), - fsize + fileSize ); return false; } @@ -1038,24 +1037,23 @@ bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t l } Defer closeFile{[&] { xfclose(file); }}; - if (fseek(file, 0, SEEK_END) == 0) { - if (unsigned long fsize = ftell(file); - startPos > fsize) { // `ftell` cannot fail here, since `fseek` succeeded. + if (long fileSize = seekSize(file); fileSize != -1) { + if (startPos > static_cast(fileSize)) { error( - "Specified start position (%" PRIu32 ") is greater than length of \"%s\" (%lu)", + "Specified start position (%" PRIu32 ") is greater than length of \"%s\" (%ld)", startPos, name.c_str(), - fsize + fileSize ); return false; - } else if (startPos + length > fsize) { + } else if (startPos + length > static_cast(fileSize)) { error( "Specified range in `INCBIN` file \"%s\" is out of bounds (%" PRIu32 " + %" PRIu32 " > %ld)", name.c_str(), startPos, length, - fsize + fileSize ); return false; } diff --git a/src/link/output.cpp b/src/link/output.cpp index 587b2b48..6e273367 100644 --- a/src/link/output.cpp +++ b/src/link/output.cpp @@ -112,16 +112,13 @@ static uint32_t checkOverlaySize() { return 0; } - if (fseek(overlayFile, 0, SEEK_END) != 0) { + long overlaySize = seekSize(overlayFile); + + if (overlaySize == -1) { warnx("Overlay file is not seekable, cannot check if properly formed"); return 0; } - long overlaySize = ftell(overlayFile); - - // Reset back to beginning - fseek(overlayFile, 0, SEEK_SET); - if (overlaySize % BANK_SIZE) { warnx("Overlay file does not have a size multiple of 0x4000"); } else if (options.is32kMode && overlaySize != 0x8000) { diff --git a/src/util.cpp b/src/util.cpp index 0b97cc18..27bd3490 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -25,6 +25,20 @@ int xclose(int fd) { return close(fd); } +long seekSize(FILE *file) { + if (fseek(file, 0, SEEK_END) != 0) { + return -1; + } + long size = ftell(file); + if (size < 0) { + return -1; + } + if (fseek(file, 0, SEEK_SET) != 0) { + return -1; + } + return size; +} + bool isNewline(int c) { return c == '\r' || c == '\n'; }