From 1d45bb35abcac352f916180128bf40622ba0bc11 Mon Sep 17 00:00:00 2001 From: "B. Watson" Date: Sat, 15 Nov 2025 03:21:17 -0500 Subject: Improve & document filename & size sanity-checking. --- src/extract.c | 82 +++++++++++++++++++++++++++++++++++------------------------ src/unalf.1 | 15 ++++++++++- src/unalf.rst | 13 ++++++++++ 3 files changed, 76 insertions(+), 34 deletions(-) diff --git a/src/extract.c b/src/extract.c index dc6a4f1..af3efeb 100644 --- a/src/extract.c +++ b/src/extract.c @@ -19,41 +19,23 @@ u16 dpeek(int addr) { return mem[addr] | (mem[addr + 1] << 8); } -void fix_filename(void) { - char *p; - - if(!out_filename) return; - - if(strlen(out_filename) > 12) { - fprintf(stderr, "%s: filename in ALF header not null-terminated, fixing.\n", self); - out_filename[12] = '\0'; - } - - if(opts.lowercase) { - for(p = out_filename; *p; p++) - *p = tolower(*p); - } +static void bad_atari_filename(const char *msg) { + char fn[50] = ""; + char xbuf[5]; + int i; + u8 c; - if(!opts.keepdot) { - for(p = out_filename; *p; p++) - if(p[0] == '.' && !p[1]) - *p = '\0'; + for(i = 0; (c = (u8)out_filename[i]) && i < 12; i++) { + if(c < ' ' || c > '|') { + /* not printable, insert a hex escape */ + sprintf(xbuf, "$%02X", c); + strcat(fn, xbuf); + } else { + strncat(fn, (char *)&c, 1); + } } -} - -void make_backup(void) { - /* up to 12-char FILENAME.EXT, plus a ~, plus null terminator = 14 */ - char backup[14]; - strncpy(backup, out_filename, 13); - strncat(backup, "~", 13); - - /* silently ignore errors! */ - rename(out_filename, backup); -} - -static void bad_atari_filename(const char *msg) { - fprintf(stderr, "%s: bad Atari filename: %s\n", self, msg); + fprintf(stderr, "%s: bad Atari filename \"%s\": %s\n", self, fn, msg); } /* note to self: it's tempting to use isalpha(), isprint(), etc @@ -93,6 +75,41 @@ static void sanity_check_filename(void) { bad_atari_filename("invalid characters. corrupt ALF file?"); } +void fix_filename(void) { + char *p; + + if(!out_filename) return; + + if(strlen(out_filename) > 12) { + fprintf(stderr, "%s: filename in ALF header not null-terminated, fixing.\n", self); + out_filename[12] = '\0'; + } + + sanity_check_filename(); + + if(opts.lowercase) { + for(p = out_filename; *p; p++) + *p = tolower(*p); + } + + if(!opts.keepdot) { + for(p = out_filename; *p; p++) + if(p[0] == '.' && !p[1]) + *p = '\0'; + } +} + +void make_backup(void) { + /* up to 12-char FILENAME.EXT, plus a ~, plus null terminator = 14 */ + char backup[14]; + + strncpy(backup, out_filename, 13); + strncat(backup, "~", 13); + + /* silently ignore errors! */ + rename(out_filename, backup); +} + void extract_alf(void) { /* get ready to call fake 6502 stuff. set up memory like the Atari. */ dpoke(MEMTOP, 0xbc1f); @@ -100,7 +117,6 @@ void extract_alf(void) { while(read_alf_header()) { out_filename = (char *)(mem + alf_hdr_filename); - sanity_check_filename(); fix_filename(); if(!file_wanted(out_filename)) { diff --git a/src/unalf.1 b/src/unalf.1 index 9303f0b..b2f918f 100644 --- a/src/unalf.1 +++ b/src/unalf.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "UNALF" 1 "2025-11-14" "0.1.0" "Urchlay's Atari 8-bit Tools" +.TH "UNALF" 1 "2025-11-15" "0.1.0" "Urchlay's Atari 8-bit Tools" .SH NAME unalf \- extract Atari 8-bit ALF archives .\" RST source for unalf(1) man page. Convert with: @@ -266,6 +266,19 @@ If you have an ALF file that does this, try it with the Atari \fBUNALF14.COM\fP and see if it has the same problem. If it does, you\(aqve found a bug in \fBunalf\fP, please send me the \&.alf file via email (see \fBAUTHOR\fP, below). +.TP +.B \fBbad Atari filename\fP \fI\fP \fI\fP +The filename stored in the ALF header doesn\(aqt follow the rules for +Atari DOS filenames. \fI\fP will be something like "doesn\(aqt start +with A\-Z" or "invalid character". The filename will be printed with +any unprintable characters as hex values (e.g. \fB$01\fP). +.TP +.B \fBheader # (compressed|original) size is...\fP +Followed by "impossibly large", "suspiciously large", or "too large +to fit on a floppy disk". May indicate a corrupt archive, or someone +really might have created an ALF file with files this big... though +"impossibly large" means >16MB. \fBunalf\fP can\(aqt extract a file +that big. .UNINDENT .SH NOTES .sp diff --git a/src/unalf.rst b/src/unalf.rst index b829bf9..2e716a1 100644 --- a/src/unalf.rst +++ b/src/unalf.rst @@ -221,6 +221,19 @@ Besides the standard error messages such as "no such file or directory": If it does, you've found a bug in **unalf**, please send me the .alf file via email (see **AUTHOR**, below). +**bad Atari filename** ** ** + The filename stored in the ALF header doesn't follow the rules for + Atari DOS filenames. ** will be something like "doesn't start + with A-Z" or "invalid character". The filename will be printed with + any unprintable characters as hex values (e.g. **$01**). + +**header # (compressed|original) size is...** + Followed by "impossibly large", "suspiciously large", or "too large + to fit on a floppy disk". May indicate a corrupt archive, or someone + really might have created an ALF file with files this big... though + "impossibly large" means >=16MB. **unalf** can't extract a file + that big. + NOTES ===== -- cgit v1.2.3