Encapsulate fseek+ftell idiom in seekSize

This allows a single check for the return value of `seekSize`
to verify all three `fseek`+`ftell`+`fseek` calls.
This commit is contained in:
Rangi
2026-07-14 01:32:18 -04:00
parent e7855ea1b8
commit 7e2a3491a5
5 changed files with 34 additions and 23 deletions
+3
View File
@@ -26,6 +26,9 @@ enum NumberBase {
int xfclose(FILE *file); int xfclose(FILE *file);
int xclose(int fd); int xclose(int fd);
// Measure file size with `fseek` and `ftell` idiom
long seekSize(FILE *file);
// Locale-independent character class functions // Locale-independent character class functions
bool isNewline(int c); bool isNewline(int c);
bool isBlankSpace(int c); bool isBlankSpace(int c);
+3 -4
View File
@@ -18,7 +18,7 @@
#include "extern/utf8decoder.hpp" #include "extern/utf8decoder.hpp"
#include "helpers.hpp" #include "helpers.hpp"
#include "linkdefs.hpp" #include "linkdefs.hpp"
#include "util.hpp" // xfclose #include "util.hpp" // xfclose, seekSize
#include "asm/charmap.hpp" #include "asm/charmap.hpp"
#include "asm/format.hpp" #include "asm/format.hpp"
@@ -151,13 +151,12 @@ std::optional<std::string> act_ReadFile(std::string const &name, uint32_t maxLen
Defer closeFile{[&] { xfclose(file); }}; Defer closeFile{[&] { xfclose(file); }};
size_t readSize = maxLen; 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, // If the file is seekable and shorter than the max length,
// just read as many bytes as there are // just read as many bytes as there are
if (long fileSize = ftell(file); static_cast<size_t>(fileSize) < readSize) { if (static_cast<size_t>(fileSize) < readSize) {
readSize = fileSize; readSize = fileSize;
} }
fseek(file, 0, SEEK_SET);
// LCOV_EXCL_START // LCOV_EXCL_START
} else if (errno != ESPIPE) { } else if (errno != ESPIPE) {
error( error(
+11 -13
View File
@@ -21,7 +21,7 @@
#include "helpers.hpp" #include "helpers.hpp"
#include "itertools.hpp" // InsertionOrderedMap #include "itertools.hpp" // InsertionOrderedMap
#include "linkdefs.hpp" #include "linkdefs.hpp"
#include "util.hpp" // xfclose #include "util.hpp" // xfclose, seekSize
#include "asm/fstack.hpp" #include "asm/fstack.hpp"
#include "asm/lexer.hpp" #include "asm/lexer.hpp"
@@ -977,14 +977,13 @@ bool sect_BinaryFile(std::string const &name, uint32_t startPos) {
} }
Defer closeFile{[&] { xfclose(file); }}; Defer closeFile{[&] { xfclose(file); }};
if (fseek(file, 0, SEEK_END) == 0) { if (long fileSize = seekSize(file); fileSize != -1) {
if (unsigned long fsize = ftell(file); if (startPos > static_cast<size_t>(fileSize)) {
startPos > fsize) { // `ftell` cannot fail here, since `fseek` succeeded.
error( error(
"Specified start position (%" PRIu32 ") is greater than length of \"%s\" (%lu)", "Specified start position (%" PRIu32 ") is greater than length of \"%s\" (%ld)",
startPos, startPos,
name.c_str(), name.c_str(),
fsize fileSize
); );
return false; return false;
} }
@@ -1038,24 +1037,23 @@ bool sect_BinaryFileSlice(std::string const &name, uint32_t startPos, uint32_t l
} }
Defer closeFile{[&] { xfclose(file); }}; Defer closeFile{[&] { xfclose(file); }};
if (fseek(file, 0, SEEK_END) == 0) { if (long fileSize = seekSize(file); fileSize != -1) {
if (unsigned long fsize = ftell(file); if (startPos > static_cast<size_t>(fileSize)) {
startPos > fsize) { // `ftell` cannot fail here, since `fseek` succeeded.
error( error(
"Specified start position (%" PRIu32 ") is greater than length of \"%s\" (%lu)", "Specified start position (%" PRIu32 ") is greater than length of \"%s\" (%ld)",
startPos, startPos,
name.c_str(), name.c_str(),
fsize fileSize
); );
return false; return false;
} else if (startPos + length > fsize) { } else if (startPos + length > static_cast<size_t>(fileSize)) {
error( error(
"Specified range in `INCBIN` file \"%s\" is out of bounds (%" PRIu32 " + %" PRIu32 "Specified range in `INCBIN` file \"%s\" is out of bounds (%" PRIu32 " + %" PRIu32
" > %ld)", " > %ld)",
name.c_str(), name.c_str(),
startPos, startPos,
length, length,
fsize fileSize
); );
return false; return false;
} }
+3 -6
View File
@@ -112,16 +112,13 @@ static uint32_t checkOverlaySize() {
return 0; 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"); warnx("Overlay file is not seekable, cannot check if properly formed");
return 0; return 0;
} }
long overlaySize = ftell(overlayFile);
// Reset back to beginning
fseek(overlayFile, 0, SEEK_SET);
if (overlaySize % BANK_SIZE) { if (overlaySize % BANK_SIZE) {
warnx("Overlay file does not have a size multiple of 0x4000"); warnx("Overlay file does not have a size multiple of 0x4000");
} else if (options.is32kMode && overlaySize != 0x8000) { } else if (options.is32kMode && overlaySize != 0x8000) {
+14
View File
@@ -25,6 +25,20 @@ int xclose(int fd) {
return close(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) { bool isNewline(int c) {
return c == '\r' || c == '\n'; return c == '\r' || c == '\n';
} }