diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/io.c | 48 | ||||
| -rw-r--r-- | src/opts.c | 3 | ||||
| -rw-r--r-- | src/unalf.1 | 33 | ||||
| -rw-r--r-- | src/unalf.h | 1 | ||||
| -rw-r--r-- | src/unalf.rst | 29 | ||||
| -rw-r--r-- | src/usage.c | 1 |
6 files changed, 94 insertions, 21 deletions
@@ -28,6 +28,7 @@ static void eof_junk(long pos) { static void check_hdr_size(const char *name, unsigned long size) { const char *desc; + int fatal = 0; /* fits on a double-density disk? */ if(size < 184320) @@ -35,22 +36,51 @@ static void check_hdr_size(const char *name, unsigned long size) { /* >= 16MB files are impossible because the decrunch algorithm ignores the high byte of the 4-byte length. */ - if(size >= 16777216L) + if(size >= 16777216L) { desc = "impossibly large (>=16MB)"; + fatal = !opts.listonly; /* listing the file isn't an error, extracting it is. */ /* >1MB files are possible (e.g. with a hard drive on SpartaDOS X) but exceedingly rare in the Atari world. */ - else if(size > 1048576L) + } else if(size > 1048576L) { desc = "suspiciously large (>1MB)"; - else + } else { desc = "too large for a floppy disk (>180KB)"; + } - fprintf(stderr, "%s: header #%d %s size is %s.\n", - self, headers_read, name, desc); + fprintf(stderr, "%s: %s: header #%d %s size is %s.\n", + self, (fatal ? "fatal" : "warning"), headers_read, name, desc); + if(fatal) exit(1); } -static void sanity_check_header(void) { - check_hdr_size("original", getquad(alf_hdr_origsize0)); - check_hdr_size("compressed", getquad(alf_hdr_compsize0)); +static void sanity_check_header(long pos) { + struct stat s; + unsigned long origsize, compsize; + int fatal; + + origsize = getquad(alf_hdr_origsize0); + compsize = getquad(alf_hdr_compsize0); + + check_hdr_size("original", origsize); + check_hdr_size("compressed", compsize); + + pos += 29; /* skip header */ + if(fstat(fileno(in_file), &s) < 0) { + fprintf(stderr, "%s: fatal: fstat on %s ", self, in_filename); + perror("failed"); + return; + } + + if(compsize > (s.st_size - pos)) { + fatal = !(opts.force || opts.listonly); + fprintf(stderr, "%s: %s: compressed size for header #%d is bigger than the rest of the file (truncated?), use -F to override.\n", fatal ? "fatal" : "warning", self, headers_read); + exit(1); + } + + if(compsize > origsize * 2) { + fatal = !(opts.force || opts.listonly); + fprintf(stderr, "%s: %s: compressed size for header #%d is over twice the uncompressed size (corrupt?), use -F to override.\n", fatal ? "fatal": "warning", self, headers_read); + exit(1); + } } /* return 1 if a header is read, 0 if not */ @@ -84,7 +114,7 @@ int read_alf_header(void) { if(h2 < 0x0f) die_arc(); if(h2 == 0x0f) { headers_read++; - sanity_check_header(); + sanity_check_header(read_pos); return 1; /* signature matches */ } } @@ -1,6 +1,6 @@ #include "unalf.h" -#define OPTIONS "aefklLopqtTvVd:x:" +#define OPTIONS "aefFklLopqtTvVd:x:" /* uncomment to test exclude/include glob lists */ // #define DEBUG_GLOBS @@ -38,6 +38,7 @@ void parse_opts(int argc, char * const *argv) { case 'e': opts.listonly = opts.testonly = 0; break; case 'k': opts.keepdot++; break; case 'f': opts.fixjunk++; opts.testonly = 1; opts.listonly = 0; opts.quiet = 1; break; + case 'F': opts.force++; break; case 'l': opts.listonly++; opts.testonly = 0; break; case 'L': opts.lowercase++; break; case 'o': opts.overwrite++; break; diff --git a/src/unalf.1 b/src/unalf.1 index f7d4ff3..2c8054f 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-12-02" "0.3.0" "Urchlay's Atari 8-bit Tools" +.TH "UNALF" 1 "2025-12-03" "0.3.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: @@ -111,6 +111,15 @@ backup is made. . .INDENT 0.0 .TP +.B \-F +Force \fBunalf\fP to continue after detecting an invalid compressed file +size in an \fIALF\fP header. This isn\(aqt the default because it can cause +\fBunalf\fP to get stuck in an infinite loop. +.UNINDENT +.\" force uncompressing in case of invalid compressed size. +. +.INDENT 0.0 +.TP .B \-h\fP,\fB \-\-help Show built\-in help message. .UNINDENT @@ -287,6 +296,20 @@ cause these errors. .TP .B \fBfatal: compressed data is truncated, EOF before end marker\fP Self\-explanatory. The ALF file ends before the compressed data does. +.TP +.B \fBheader #<n> (compressed|original) size is impossibly large (>16MB)\fP +\fBunalf\fP can\(aqt handle files of more than 16MB in size. This isn\(aqt a +bug, it\(aqs just the way it was designed (in 1988, remember). Neither +\fBLZ.COM\fP nor \fBalf\fP will create files like this, so you \fIprobably\fP +have a corrupt ALF archive. +.TP +.B \fBcompressed size for header #<n> is bigger than the rest of the file (truncated?)\fP +Normally this means a truncated \fIALF\fP file, or one with a corrupted header. +You can use the \fB\-F\fP option to turn this error into a non\-fatal warning. +.TP +.B \fBcompressed size for header #<n> is over twice the uncompressed size (corrupt?)\fP +This generally means you have a corrupted \fIALF\fP file. +You can use the \fB\-F\fP option to turn this error into a non\-fatal warning. .UNINDENT .SS Warnings .sp @@ -333,11 +356,9 @@ 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 #<n> (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. +Followed by "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. .TP .B \fBALF files don\(aqt normally contain other ALF files, are you trying to extract/list multiple ALF files at once?\fP You gave a \fIwildcard\fP argument that ends with \fI\&.alf\fP\&. This is OK if diff --git a/src/unalf.h b/src/unalf.h index 33a7760..4adaeb3 100644 --- a/src/unalf.h +++ b/src/unalf.h @@ -80,6 +80,7 @@ typedef struct { int verbose_list; int fixjunk; int ignore_datetime; + int force; } opts_t; #define MAX_EXCLUDES 256 diff --git a/src/unalf.rst b/src/unalf.rst index 146e056..069fad1 100644 --- a/src/unalf.rst +++ b/src/unalf.rst @@ -89,6 +89,13 @@ OPTIONS .. fix (remove) junk at EOF. +-F + Force **unalf** to continue after detecting an invalid compressed file + size in an *ALF* header. This isn't the default because it can cause + **unalf** to get stuck in an infinite loop. + +.. force uncompressing in case of invalid compressed size. + -h, --help Show built-in help message. @@ -242,6 +249,20 @@ Fatal errors **fatal: compressed data is truncated, EOF before end marker** Self-explanatory. The ALF file ends before the compressed data does. +**header #<n> (compressed|original) size is impossibly large (>16MB)** + **unalf** can't handle files of more than 16MB in size. This isn't a + bug, it's just the way it was designed (in 1988, remember). Neither + **LZ.COM** nor **alf** will create files like this, so you *probably* + have a corrupt ALF archive. + +**compressed size for header #<n> is bigger than the rest of the file (truncated?)** + Normally this means a truncated *ALF* file, or one with a corrupted header. + You can use the **-F** option to turn this error into a non-fatal warning. + +**compressed size for header #<n> is over twice the uncompressed size (corrupt?)** + This generally means you have a corrupted *ALF* file. + You can use the **-F** option to turn this error into a non-fatal warning. + Warnings -------- @@ -287,11 +308,9 @@ Warnings any unprintable characters as hex values (e.g. **$01**). **header #<n> (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. + Followed by "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. **ALF files don't normally contain other ALF files, are you trying to extract/list multiple ALF files at once?** You gave a *wildcard* argument that ends with *.alf*. This is OK if diff --git a/src/usage.c b/src/usage.c index 7615d2e..0f43fca 100644 --- a/src/usage.c +++ b/src/usage.c @@ -4,6 +4,7 @@ const char *usage_msg[] = { " -d: set output directory (created if needed).", " -e: extract files (redundant; this is the default action).", " -f: fix (remove) junk at EOF.", + " -F: force uncompressing in case of invalid compressed size.", " -h: show this help message.", " -k: keep trailing periods (dots) in filenames.", " -l: list files in archive (filenames only).", |
