From: "Juan Manuel Guerrero" Organization: Darmstadt University of Technology To: djgpp-workers AT delorie DOT com Date: Mon, 11 Dec 2000 07:50:08 +0200 MIME-Version: 1.0 Content-type: text/plain; charset=US-ASCII Content-transfer-encoding: 7BIT Subject: A bugfix for djtar X-mailer: Pegasus Mail for Windows (v2.54DE) Message-ID: <116197B1031@HRZ1.hrz.tu-darmstadt.de> Reply-To: djgpp-workers AT delorie DOT com if djtar is invoked as: djtar -x foo.gz djtar will exit with an error message like: --- !!Directory checksum error!! --- This is the way it should be. Please note, that foo.gz is a **pure** gzip file and **not** a gzip compressed tar file. It does *not* contain a tar archive and this should be recognized by djtar. Unfortunately, if the **unziped** file size exceeds 32kB djtar will crash with the following traceback: Abort! Exiting due to signal SIGABRT Raised at eip=0000f1b6 eax=000ee484 ebx=00000120 ecx=00000000 edx=00012990 esi=00004000 edi=00000001 ebp=000ee530 esp=000ee480 program=J:\DJTAR.EXE cs: sel=00af base=8115a000 limit=000fffff ds: sel=00b7 base=8115a000 limit=000fffff es: sel=00b7 base=8115a000 limit=000fffff fs: sel=0087 base=00012990 limit=0000ffff gs: sel=00c7 base=00000000 limit=0010ffff ss: sel=00b7 base=8115a000 limit=000fffff App stack: [000eef54..0006ef54] Exceptn stack: [0006eea8..0006cf68] Call frame traceback EIPs: 0x0000f0d4 ___djgpp_traceback_exit+48 0x0000f1b6 _raise+94 0x0000e5fb _abort+27 0x0001439b __put_path2+55 0x00014342 __put_path+14 0x000160eb __chmod+59 0x00016535 ___file_exists+21 0x00012ea7 ___open+247 0x00006f7d _tarread+1817, line 277 of untar.c 0x00007ced _flush_window+61, line 121 of util.c 0x000042f0 _inflate_codes+1004, line 588 of inflate.c 0x00004d01 _inflate_dynamic+1625, line 862 of inflate.c 0x00004e21 _inflate_block+221, line 907 of inflate.c 0x00004e96 _inflate+70, line 939 of inflate.c 0x000077b9 _unzip+185, line 123 of unzip.c 0x00007374 _tar_gz_read+272, line 350 of untar.c 0x0000265c _main+1056, line 552 of djtar.c 0x00009b42 ___crt1_startup+178 32kB is the size of the transfer array used to move the unziped data to tarread(). The reason for this program abort is that the global variable: looking_for_header is not reset to the appropiate value every time that tarread() is called. Before tarread() is called for the first time, looking_for_header has been set to 1. This implies that tarread() checks the complete buf[] contents for tar headers. If it finds one it will extract all the info needed to create the file form it. If it does not find a header or the checksum is wrong it will set looking_for_header=0 and return with EOF. Neither the gzip nor the bzip decompression machinery can evaluate (for different reasons) this return value. Unfortunately tarread() returns EOF if there is an error condition **and** if there is really EOF. If tarread() is called a second time with new buf[] contents it will not check for a tar header at all, and will directely call open() with wrong parameters and producing the above abort. The patch below will fix this for bzip/gzip compressed files and for all other functions that may call tarread(). Please note that the goal of the patch is to fix the bug and not to allow the user to use djtar to unzip plain .gz or .bz2 files. regards, Guerrero, Juan Manuel diff -acprNC5 djgpp.orig/src/utils/djtar/untar.c djgpp/src/utils/djtar/untar.c *** djgpp.orig/src/utils/djtar/untar.c Tue Nov 28 21:20:44 2000 --- djgpp/src/utils/djtar/untar.c Sun Dec 10 18:37:16 2000 *************** typedef struct { *** 42,51 **** --- 42,52 ---- char flags[1]; char filler[355]; } TARREC; static TARREC header; + static int error_message_not_printed; static int looking_for_header; static char *changed_name; static int first_block = 1; static File_type file_type = DOS_BINARY; static long perm, uid, gid, size; *************** tarread(char *buf, long buf_size) *** 121,131 **** head_csum -= j; } if (head_csum && !ignore_csum) { /* Probably corrupted archive. Bail out. */ ! fprintf(log_out, "--- !!Directory checksum error!! ---\n"); bytes_out += buf_size; return EOF; } changed_name = get_new_name(header.name, &should_be_written); --- 122,140 ---- head_csum -= j; } if (head_csum && !ignore_csum) { /* Probably corrupted archive. Bail out. */ ! if (error_message_not_printed) ! { ! error_message_not_printed = 0; /* Yes, we have printed it. */ ! fprintf(log_out, "--- !!Directory checksum error!! ---\n"); ! } ! /* We have still not found a header in this buf[], ! so we MUST continue looking for a header next time ! that tarread() is called with a new buf[]. */ ! looking_for_header = 1; bytes_out += buf_size; return EOF; } changed_name = get_new_name(header.name, &should_be_written); *************** tar_gz_read(char *fname) *** 342,351 **** --- 351,361 ---- fname, method > MAX_METHODS ? "corrupted (?)" : zip_description[method], method == DEFLATED ? (pkzip ? "PKZip" : "GZip") : ""); bytes_out = 0; + error_message_not_printed = 1; looking_for_header = 1; posn = 0; if ((*decompressor)(f) != OK) {