Mail Archives: djgpp-workers/1997/12/10/03:31:34
On Mon, 8 Dec 1997, Eli Zaretskii wrote:
> The following changes correct several problems in DJTAR. They should
> be applied on top of Esa Peuha's patches that add .zip file support.
I didn't post my patches to djgpp-workers list, so they are attached here.
> Note that the seemingly large change in the `get_new_name' function is
> just a reindentation, since the code indentation was left intact after
> it was copied from an inner block, which made the program structure
> hard to read.
So the -b switch to diff was a bad idea...
> The latter change was necessary because the original code would treat
> filenames like `foo/bar.zip/baz.tgz' as a .zip archive. The new test
> only does that for files whose name ends with a ".zip", and the test
> is now case-insensitive, so e.g. ".ZIP" and ".Zip" are also okay.
Apparently I didn't think about this too carefully :-)
> Btw, I suggest to modify the code so that it would detect the .zip
> format automatically based on the file contents.
This is not trivial. The main function must read four bytes from the
beginning of the file, but those four bytes must also be available to the
untar/unzip code. The input file might not be seekable (if it is raw
disk), and it might not be possible to open the file, read the bytes and
close it to be opened again (if it is stdin). But if anyone can think of a
solution, then please implement this.
> This is more
> consistent with the previous DJTAR operation whereby it always guessed
> the format without asking the user and without relying on file name
> features.
I think that's a false analogy. Previously, every file had to be untarred
after decompressing, so there was no point to ask what to do with the
file, but now a zipped .tar file can be reasonably considered either as a
.zip file or a compressed .tar file, so the user might want to choose the
format.
diff -b -C 2 -N -r djgpp/src/utils/djtar/djtar.c newdjgpp/src/utils/djtar/djtar.c
*** djgpp/src/utils/djtar/djtar.c Sun Sep 1 16:44:26 1996
--- newdjgpp/src/utils/djtar/djtar.c Mon Nov 17 19:32:10 1997
***************
*** 1,15 ****
/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
- #include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
- #include <string.h>
- #include <errno.h>
- #include <dos.h>
- #include <time.h>
#include <io.h>
- #include <crt0.h>
#define NO_LFN (!_use_lfn("."))
--- 1,9 ----
***************
*** 134,138 ****
}
! static int
change(char *fname, const char *problem, int isadir)
{
--- 128,132 ----
}
! int
change(char *fname, const char *problem, int isadir)
{
***************
*** 198,202 ****
/*------------------------------------------------------------------------*/
! static int
isadir(char *n)
{
--- 192,196 ----
/*------------------------------------------------------------------------*/
! int
isadir(char *n)
{
***************
*** 216,220 ****
}
! static void
do_directories(char *n)
{
--- 210,214 ----
}
! void
do_directories(char *n)
{
***************
*** 244,251 ****
/*------------------------------------------------------------------------*/
- typedef enum { DOS_BINARY, DOS_TEXT, UNIX_TEXT } File_type;
-
/* Guess DOS file type by looking at its contents. */
! static File_type
guess_file_type(char *buf, register size_t buflen)
{
--- 238,243 ----
/*------------------------------------------------------------------------*/
/* Guess DOS file type by looking at its contents. */
! File_type
guess_file_type(char *buf, register size_t buflen)
{
***************
*** 275,381 ****
/*------------------------------------------------------------------------*/
! typedef struct {
! char name[100];
! char operm[8];
! char ouid[8];
! char ogid[8];
! char osize[12];
! char otime[12];
! char ocsum[8];
! char flags[1];
! char filler[355];
! } TARREC;
!
! static TARREC header;
! 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;
! static long posn = 0;
! static time_t ftime;
! static struct ftime ftimes;
! static struct tm *tm;
! static int r;
! static int skipping;
! static char new[2048]; /* got to think about LFN's! */
!
! int
! tarread(char *buf, long buf_size)
{
! int should_be_written;
!
! while (buf_size)
! {
! char *info;
! int write_errno = 0;
! int dsize = 512, wsize;
!
! if (skipping)
! {
! if (skipping <= buf_size)
! {
! bytes_out += skipping;
! buf += skipping;
! buf_size -= skipping;
! skipping = 0;
! looking_for_header = 1;
! if (buf_size < sizeof header)
! return 0;
! }
! else
! {
! bytes_out += buf_size;
! skipping -= buf_size;
! return 0;
! }
! }
!
! if (looking_for_header)
! {
! int head_csum = 0;
! int i;
!
! memcpy(&header, buf, sizeof header);
! if (header.name[0] == 0)
! {
! bytes_out += buf_size; /* assume everything left should be counted */
! return EOF;
! }
! buf += sizeof header;
! buf_size -= sizeof header;
! bytes_out += sizeof header;
! first_block = 1;
! file_type = DOS_BINARY;
! looking_for_header = 0;
/* ONLY_DIR says to extract only files which are siblings
of that directory. */
! should_be_written = list_only == 0;
! if (should_be_written &&
! only_dir && strncmp(only_dir, header.name, strlen(only_dir)))
! should_be_written = 0;
! sscanf(header.operm, " %lo", &perm);
! sscanf(header.ouid, " %lo", &uid);
! sscanf(header.ogid, " %lo", &gid);
! sscanf(header.osize, " %lo", &size);
! sscanf(header.otime, " %o", &ftime);
! sscanf(header.ocsum, " %o", &head_csum);
! for (i = 0; i < sizeof header; i++)
! {
! /* Checksum on header, but with the checksum field blanked out. */
! int j = (i > 147 && i < 156) ? ' ' : *((unsigned char *)&header + i);
!
! 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_entry(header.name);
if (should_be_written && !to_stdout && NO_LFN)
{
--- 267,284 ----
/*------------------------------------------------------------------------*/
! char *
! get_new_name(char *name_to_change, int *should_be_written)
{
! char *changed_name, *info;
! char new[2048]; /* got to think about LFN's! */
/* ONLY_DIR says to extract only files which are siblings
of that directory. */
! *should_be_written = list_only == 0;
! if (*should_be_written &&
! only_dir && strncmp(only_dir, name_to_change, strlen(only_dir)))
! *should_be_written = 0;
! changed_name = get_entry(name_to_change);
if (should_be_written && !to_stdout && NO_LFN)
{
***************
*** 482,710 ****
}
}
!
! if (v_switch)
! fprintf(log_out, "%08lx %6lo ", posn, perm);
! else
! fprintf(log_out, "%c%c%c%c ",
! S_ISDIR(perm) ? 'd' : '-',
! perm & S_IRUSR ? 'r' : '-',
! perm & S_IWUSR ? 'w' : '-',
! perm & S_IXUSR ? 'x' : '-');
! fprintf(log_out, "%.20s %9ld %s", ctime(&ftime)+4, size, changed_name);
! #if 0
! fprintf(log_out, "(out: %ld)", bytes_out);
! #endif
! if (header.flags[1] == 0x32)
! fprintf(log_out, " -> %s", header.filler);
! fprintf(log_out, "%s\n",
! !should_be_written && !list_only ? "\t[ skipped ]" : "");
! posn += 512 + ((size+511) & ~511);
! #if 0
! fprintf(log_out, "%6lo %02x %12ld %s\n",perm,header.flags[0],size,changed_name);
! #endif
! if (should_be_written == 0)
! {
! skipping = (size+511) & ~511;
! continue;
! }
! else if (changed_name[strlen(changed_name)-1] == '/' && !to_stdout)
! {
! changed_name[strlen(changed_name)-1] = 0;
! do {
! if (strcmp(changed_name, ".") == 0)
! r = 0; /* current dir always exists */
! else if (strcmp(changed_name, "..") == 0)
! r = !isadir(changed_name); /* root has no parent */
! else
! r = mkdir(changed_name
! #ifdef __GO32__
! ,0
! #endif
! );
! if (r && (errno==EACCES))
! {
! change(changed_name, "Duplicate directory name", 2);
! continue;
! }
! if (r)
! r = change(changed_name, "Unable to create directory", 1);
! else
! fprintf(log_out, "Making directory %s\n", changed_name);
! } while (r);
! looking_for_header = 1;
! continue;
! }
! else
! {
! open_file:
! if (!to_stdout)
! {
! do_directories(changed_name);
! r = open(changed_name,
! O_WRONLY | O_BINARY | O_CREAT | O_EXCL, S_IWRITE | S_IREAD);
! if (r < 0)
! if (change(changed_name, "Cannot exclusively open file", 0))
! goto open_file;
! else
! {
! skipping = (size+511) & ~511;
! continue;
! }
! }
! else
! {
! r = fileno(stdout);
! if (!to_tty)
! setmode(r, O_BINARY);
! }
! }
! }
!
! while (size)
! {
! char tbuf[512];
! char *wbuf = buf;
!
! if (buf_size <= 0) /* this buffer exhausted */
! return 0;
! if (size < 512)
! dsize = size;
! else if (buf_size < 512)
! dsize = buf_size;
! else
! dsize = 512;
! if (first_block && (text_dos || text_unix || to_tty))
! {
! file_type = guess_file_type(buf, dsize);
! first_block = 0;
! if (file_type == UNIX_TEXT && text_dos)
! setmode(r, O_TEXT); /* will add CR chars to each line */
! }
! if ((text_unix || to_tty) && file_type == DOS_TEXT)
! {
! /* If they asked for text files to be written Unix style, or
! we are writing to console, remove the CR and ^Z characters
! from DOS text files.
! Note that we don't alter the original uncompressed data so
! as not to screw up the CRC computations. */
! char *s=buf, *d=tbuf;
! while (s-buf < dsize)
! {
! if (*s != '\r' && *s != 26)
! *d++ = *s;
! s++;
! }
! wsize = d - tbuf;
! wbuf = tbuf;
! }
! else
! {
! wbuf = buf;
! wsize = dsize;
! }
! errno = 0;
! if (write(r, wbuf, wsize) < wsize)
! {
! if (errno == 0)
! errno = ENOSPC;
! fprintf(log_out, "%s: %s\n", changed_name, strerror(errno));
! write_errno = errno;
! break;
! }
! size -= dsize;
! buf_size -= dsize;
! buf += dsize;
! bytes_out += dsize;
! }
!
! if (!to_stdout)
! {
! close(r);
! r = open(changed_name, O_RDONLY);
! tm = localtime(&ftime);
! ftimes.ft_tsec = tm->tm_sec / 2;
! ftimes.ft_min = tm->tm_min;
! ftimes.ft_hour = tm->tm_hour;
! ftimes.ft_day = tm->tm_mday;
! ftimes.ft_month = tm->tm_mon+1;
! ftimes.ft_year = tm->tm_year - 80;
! setftime(r, &ftimes);
! close(r);
! chmod(changed_name, perm);
! }
! looking_for_header = 1;
! if (write_errno == ENOSPC) /* target disk full: quit early */
! {
! bytes_out += buf_size;
! return EOF;
! }
! else if (write_errno) /* other error: skip this file, try next */
! skipping = (size - dsize + 511) & ~511;
! else /* skip the slack garbage to the next 512-byte boundary */
! skipping = 512 - dsize;
! }
! return 0;
! }
!
! /*------------------------------------------------------------------------*/
!
! int part_nb;
! static const char *zip_description[] = {
! "uncompressed",
! "COMPRESS'ed",
! "PACK'ed",
! "LZH'ed",
! "compressed by unknown method (4)",
! "compressed by unknown method (5)",
! "compressed by unknown method (6)",
! "compressed by unknown method (7)",
! "deflated by "
! };
!
! static void
! tar_gz_read(char *fname)
! {
! void *f;
!
! errno = 0;
! f = oread_open(fname);
! if (errno)
! {
! fprintf(log_out, "%s: %s\n", fname, strerror(errno));
! return;
! }
! ifname = fname;
! header_bytes = 0;
! clear_bufs(); /* clear input and output buffers */
! part_nb = 0; /* FIXME!! handle multi-part gzip's */
! method = get_method(f);
! if (method < 0)
! {
! oread_close(f);
! return; /* error message already emitted */
! }
! if (v_switch)
! fprintf(log_out, "-- `%s\' is %s%s --\n\n",
! fname,
! method > MAX_METHODS ? "corrupted (?)" : zip_description[method],
! method == DEFLATED ? (pkzip ? "PKZip" : "GZip") : "");
!
! bytes_out = 0;
! looking_for_header = 1;
! posn = 0;
!
! if ((*decompressor)(f) != OK)
! {
! fprintf(log_out,
! "\n%s: corrupted file; I might have written garbage\n", fname);
! fflush(log_out);
! }
! oread_close(f);
! method = -1;
}
/*------------------------------------------------------------------------*/
! FILE * log_out = stdout;
static char djtarx[] = "djtarx.exe";
static char djtart[] = "djtart.exe";
--- 385,394 ----
}
}
! return changed_name;
}
/*------------------------------------------------------------------------*/
! FILE *log_out = stdout;
static char djtarx[] = "djtarx.exe";
static char djtart[] = "djtart.exe";
***************
*** 738,743 ****
{
case 'n':
! DoNameChanges(argv[i+1]);
! i++;
break;
case 'v':
--- 422,426 ----
{
case 'n':
! DoNameChanges(argv[++i]);
break;
case 'v':
***************
*** 785,788 ****
--- 468,474 ----
for (; i < argc; i++)
+ if(strstr(argv[i], ".zip"))
+ epunzip_read(argv[i]);
+ else
tar_gz_read(argv[i]);
diff -b -C 2 -N -r djgpp/src/utils/djtar/epunzip.c newdjgpp/src/utils/djtar/epunzip.c
*** djgpp/src/utils/djtar/epunzip.c Thu Jan 1 00:00:00 1970
--- newdjgpp/src/utils/djtar/epunzip.c Sun Nov 16 21:55:32 1997
***************
*** 0 ****
--- 1,296 ----
+ #include <dos.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <io.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <sys/stat.h>
+ #include <unistd.h>
+
+ extern int errno;
+
+ #include "oread.h"
+ #include "zread.h"
+
+ /*
+ extern int text_unix;
+ extern int text_dos;
+ extern int ignore_csum;
+ */
+
+ extern int to_stdout;
+ extern int to_tty;
+ extern int list_only;
+ extern FILE *log_out;
+
+ #define CRYFLG 1
+ #define EXTFLG 8
+
+ static int epoutfile = 0;
+ static char *changed_name = NULL;
+
+ int epcopy(char *, long);
+
+ void
+ epunzip_read(char *zipfilename)
+ {
+ errno = 0;
+ ifd = oread_open(zipfilename);
+ if(errno)
+ {
+ fprintf(log_out, "%s: %s\n", zipfilename, strerror(errno));
+ return;
+ }
+
+ while(1)
+ {
+ int buffer, ext_header, timedate, crc, size, length, name_length,
+ extra_length, should_be_written, count, real_file = 0;
+ char filename[2048];
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+
+ if(*(short *)&buffer != *(short *)"PK")
+ {
+ fprintf(log_out, "%s: invalid zip file structure\n", zipfilename);
+ break;
+ }
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+
+ if(*(short *)&buffer != *(short *)"\3\4")
+ {
+ /* not a local header - all done */
+ break;
+ }
+
+ /* version info - ignore it */
+ get_byte();
+ get_byte();
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+
+ if(*(short *)&buffer & CRYFLG)
+ {
+ fprintf(log_out, "%s has encrypted file(s) - use unzip\n", zipfilename);
+ break;
+ }
+ ext_header = *(short *)&buffer & EXTFLG ? 1 : 0;
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+
+ method = *(short *)&buffer;
+ if(method != 8 && method != 0)
+ {
+ fprintf(log_out, "%s has file(s) compressed with unsupported method - use unzip\n", zipfilename);
+ break;
+ }
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+ ((char *)&buffer)[2] = (char)get_byte();
+ ((char *)&buffer)[3] = (char)get_byte();
+ timedate = buffer;
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+ ((char *)&buffer)[2] = (char)get_byte();
+ ((char *)&buffer)[3] = (char)get_byte();
+ crc = buffer;
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+ ((char *)&buffer)[2] = (char)get_byte();
+ ((char *)&buffer)[3] = (char)get_byte();
+ size = buffer;
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+ ((char *)&buffer)[2] = (char)get_byte();
+ ((char *)&buffer)[3] = (char)get_byte();
+ length = buffer;
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+ name_length = *(short *)&buffer;
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+ extra_length = *(short *)&buffer;
+
+ for(count = 0; count < name_length; count++)
+ {
+ filename[count] = (char)get_byte();
+ }
+ filename[name_length] = 0;
+
+ for(count = 0; count < extra_length; count++)
+ {
+ get_byte();
+ }
+
+ changed_name = get_new_name(filename, &should_be_written);
+
+ fprintf(log_out, "%s%s\n", changed_name,
+ !should_be_written && !list_only ? "\t[ skipped ]" : "");
+
+ if(!should_be_written)
+ epoutfile = open("/dev/null",
+ O_WRONLY | O_BINARY | O_CREAT | O_EXCL,
+ S_IWRITE | S_IREAD);
+ else if(changed_name[strlen(changed_name) - 1] == '/' && !to_stdout)
+ {
+ changed_name[strlen(changed_name) - 1] = 0;
+ do
+ {
+ if(strcmp(changed_name, ".") == 0)
+ epoutfile = 0; /* current dir always exists */
+ else if(strcmp(changed_name, "..") == 0)
+ epoutfile = !isadir(changed_name); /* root has no parent */
+ else
+ epoutfile = mkdir(changed_name, 0);
+ if(epoutfile && (errno == EACCES))
+ {
+ change(changed_name, "Duplicate directory name", 2);
+ continue;
+ }
+ if(epoutfile)
+ epoutfile = change(changed_name, "Unable to create directory", 1);
+ else
+ fprintf(log_out, "Making directory %s\n", changed_name);
+ }
+ while(epoutfile);
+ continue;
+ }
+ else
+ {
+ open_file:
+ if(!to_stdout)
+ {
+ do_directories(changed_name);
+ epoutfile = open(changed_name,
+ O_WRONLY | O_BINARY | O_CREAT | O_EXCL,
+ S_IWRITE | S_IREAD);
+ if(epoutfile < 0)
+ if(change(changed_name, "Cannot exclusively open file", 0))
+ goto open_file;
+ else
+ epoutfile = open("/dev/null",
+ O_WRONLY | O_BINARY | O_CREAT | O_EXCL,
+ S_IWRITE | S_IREAD);
+ real_file = 1;
+ }
+ else
+ {
+ epoutfile = fileno(stdout);
+ if(!to_tty)
+ setmode(epoutfile, O_BINARY);
+ }
+ }
+
+ updcrc(NULL, 0);
+
+ if(method == 0) /* stored */
+ {
+
+ if(ext_header)
+ {
+ fprintf(log_out, "%s has stored file with extended local header\
+ \n\aKill the program that produced it!!!\n", zipfilename);
+ break;
+ }
+
+ if(size != length)
+ {
+ fprintf(log_out, "%s has stored file with different lengths\n",
+ zipfilename);
+ break;
+ }
+
+ for(count = length; count; count--)
+ {
+ char c = (char)get_byte();
+ put_ubyte(c, epcopy);
+ }
+ flush_window(epcopy);
+
+ }
+ else /* deflated */
+ {
+ if(inflate(epcopy))
+ {
+ fprintf(log_out, "inflation failed on %s\n", zipfilename);
+ break;
+ }
+
+ if(ext_header)
+ {
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+ ((char *)&buffer)[2] = (char)get_byte();
+ ((char *)&buffer)[3] = (char)get_byte();
+ if(buffer != *(int *)"PK\7\x8")
+ {
+ fprintf(log_out, "%s: invalid zip file structure\n",
+ zipfilename);
+ break;
+ }
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+ ((char *)&buffer)[2] = (char)get_byte();
+ ((char *)&buffer)[3] = (char)get_byte();
+ crc = buffer;
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+ ((char *)&buffer)[2] = (char)get_byte();
+ ((char *)&buffer)[3] = (char)get_byte();
+ size = buffer;
+
+ ((char *)&buffer)[0] = (char)get_byte();
+ ((char *)&buffer)[1] = (char)get_byte();
+ ((char *)&buffer)[2] = (char)get_byte();
+ ((char *)&buffer)[3] = (char)get_byte();
+ length = buffer;
+ }
+
+ }
+
+ if((unsigned)crc != updcrc(outbuf, 0))
+ {
+ fprintf(log_out, "invalid crc on %s\n", zipfilename);
+ break;
+ }
+
+ if(epoutfile != fileno(stdout))
+ close(epoutfile);
+
+ if(real_file)
+ {
+ epoutfile = open(changed_name, O_RDONLY);
+ setftime(epoutfile, (struct ftime *)&timedate);
+ close(epoutfile);
+ real_file = 0;
+ }
+ }
+
+ oread_close(ifd);
+ }
+
+ int
+ epcopy(char *buffer, long size)
+ {
+ errno = 0;
+ if(write(epoutfile, buffer, size) < size)
+ {
+ if (errno == 0)
+ errno = ENOSPC;
+ fprintf(log_out, "%s: %s\n", changed_name, strerror(errno));
+ }
+ return 0;
+ }
diff -b -C 2 -N -r djgpp/src/utils/djtar/inflate.c newdjgpp/src/utils/djtar/inflate.c
*** djgpp/src/utils/djtar/inflate.c Thu Nov 16 20:01:20 1995
--- newdjgpp/src/utils/djtar/inflate.c Tue Nov 11 17:46:22 1997
***************
*** 142,146 ****
int inflate_dynamic (void);
int inflate_block (int *);
! int inflate (void);
--- 142,146 ----
int inflate_dynamic (void);
int inflate_block (int *);
! int inflate (int (*)(char *, long));
***************
*** 155,159 ****
/* unsigned wp; current position in slide */
#define wp outcnt
! #define flush_output(w) (wp=(w),flush_window())
/* Tables for deflate from PKZIP's appnote.txt. */
--- 155,159 ----
/* unsigned wp; current position in slide */
#define wp outcnt
! #define flush_output(w) (wp=(w),flush_window(func))
/* Tables for deflate from PKZIP's appnote.txt. */
***************
*** 211,214 ****
--- 211,216 ----
unsigned bk; /* bits in bit buffer */
+ int (*func)(char *, long);
+
ush mask_bits[] = {
0x0000,
***************
*** 915,919 ****
! int inflate()
/* decompress an inflated entry */
{
--- 917,921 ----
! int inflate(int (*fp)(char *, long))
/* decompress an inflated entry */
{
***************
*** 922,925 ****
--- 924,928 ----
unsigned h; /* maximum struct huft's malloc'ed */
+ func = fp;
/* initialize window, bit buffer */
diff -b -C 2 -N -r djgpp/src/utils/djtar/makefile newdjgpp/src/utils/djtar/makefile
*** djgpp/src/utils/djtar/makefile Thu Nov 16 20:10:28 1995
--- newdjgpp/src/utils/djtar/makefile Sun Nov 16 21:56:48 1997
***************
*** 11,15 ****
$(BIN)/djtar.exe : oread.o unzip.o unlzw.o unlzh.o unpack.o inflate.o \
! crypt.o util.o zmethod.o
$(BIN)/djtarx.exe : $(BIN)/stubify.exe
--- 11,15 ----
$(BIN)/djtar.exe : oread.o unzip.o unlzw.o unlzh.o unpack.o inflate.o \
! crypt.o util.o zmethod.o untar.o epunzip.o
$(BIN)/djtarx.exe : $(BIN)/stubify.exe
diff -b -C 2 -N -r djgpp/src/utils/djtar/unpack.c newdjgpp/src/utils/djtar/unpack.c
*** djgpp/src/utils/djtar/unpack.c Thu Nov 16 20:01:20 1995
--- newdjgpp/src/utils/djtar/unpack.c Mon Nov 17 18:54:50 1997
***************
*** 226,230 ****
/* At this point, peek is the next complete code, of len bits */
if (peek == eob && len == max_len) break; /* end of file? */
! put_ubyte(literal[peek+lit_base[len]]);
Tracev((stderr,"%02d %04x %c\n", len, peek,
literal[peek+lit_base[len]]));
--- 226,230 ----
/* At this point, peek is the next complete code, of len bits */
if (peek == eob && len == max_len) break; /* end of file? */
! put_ubyte(literal[peek+lit_base[len]], tarread);
Tracev((stderr,"%02d %04x %c\n", len, peek,
literal[peek+lit_base[len]]));
***************
*** 232,236 ****
} /* for (;;) */
! flush_window();
Trace((stderr, "bytes_out %ld\n", bytes_out));
if (orig_len != (ulg)bytes_out) {
--- 232,236 ----
} /* for (;;) */
! flush_window(tarread);
Trace((stderr, "bytes_out %ld\n", bytes_out));
if (orig_len != (ulg)bytes_out) {
diff -b -C 2 -N -r djgpp/src/utils/djtar/untar.c newdjgpp/src/utils/djtar/untar.c
*** djgpp/src/utils/djtar/untar.c Thu Jan 1 00:00:00 1970
--- newdjgpp/src/utils/djtar/untar.c Mon Nov 17 19:29:30 1997
***************
*** 0 ****
--- 1,348 ----
+ /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
+ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
+ #include <dos.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <io.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <sys/stat.h>
+ #include <time.h>
+ #include <unistd.h>
+
+ extern int errno;
+
+ /*------------------------------------------------------------------------*/
+
+ #include "oread.h"
+ #include "zread.h"
+
+ extern int text_unix;
+ extern int text_dos;
+ extern int to_stdout;
+ extern int to_tty;
+ extern int ignore_csum;
+ extern int list_only;
+
+ extern FILE *log_out;
+
+ /*------------------------------------------------------------------------*/
+
+ typedef struct {
+ char name[100];
+ char operm[8];
+ char ouid[8];
+ char ogid[8];
+ char osize[12];
+ char otime[12];
+ char ocsum[8];
+ char flags[1];
+ char filler[355];
+ } TARREC;
+
+ static TARREC header;
+ 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;
+ static long posn = 0;
+ static time_t ftime;
+ static struct ftime ftimes;
+ static struct tm *tm;
+ static int r;
+ static int skipping;
+
+ int
+ tarread(char *buf, long buf_size)
+ {
+ int should_be_written;
+
+ while (buf_size)
+ {
+ int write_errno = 0;
+ int dsize = 512, wsize;
+
+ if (skipping)
+ {
+ if (skipping <= buf_size)
+ {
+ bytes_out += skipping;
+ buf += skipping;
+ buf_size -= skipping;
+ skipping = 0;
+ looking_for_header = 1;
+ if (buf_size < sizeof header)
+ return 0;
+ }
+ else
+ {
+ bytes_out += buf_size;
+ skipping -= buf_size;
+ return 0;
+ }
+ }
+
+ if (looking_for_header)
+ {
+ int head_csum = 0;
+ int i;
+
+ memcpy(&header, buf, sizeof header);
+ if (header.name[0] == 0)
+ {
+ bytes_out += buf_size; /* assume everything left should be counted */
+ return EOF;
+ }
+ buf += sizeof header;
+ buf_size -= sizeof header;
+ bytes_out += sizeof header;
+ first_block = 1;
+ file_type = DOS_BINARY;
+ looking_for_header = 0;
+
+ sscanf(header.operm, " %lo", &perm);
+ sscanf(header.ouid, " %lo", &uid);
+ sscanf(header.ogid, " %lo", &gid);
+ sscanf(header.osize, " %lo", &size);
+ sscanf(header.otime, " %o", &ftime);
+ sscanf(header.ocsum, " %o", &head_csum);
+ for (i = 0; i < sizeof header; i++)
+ {
+ /* Checksum on header, but with the checksum field blanked out. */
+ int j = (i > 147 && i < 156) ? ' ' : *((unsigned char *)&header + i);
+
+ 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);
+
+ if (v_switch)
+ fprintf(log_out, "%08lx %6lo ", posn, perm);
+ else
+ fprintf(log_out, "%c%c%c%c ",
+ S_ISDIR(perm) ? 'd' : '-',
+ perm & S_IRUSR ? 'r' : '-',
+ perm & S_IWUSR ? 'w' : '-',
+ perm & S_IXUSR ? 'x' : '-');
+ fprintf(log_out, "%.20s %9ld %s", ctime(&ftime)+4, size, changed_name);
+ #if 0
+ fprintf(log_out, "(out: %ld)", bytes_out);
+ #endif
+ if (header.flags[1] == 0x32)
+ fprintf(log_out, " -> %s", header.filler);
+ fprintf(log_out, "%s\n",
+ !should_be_written && !list_only ? "\t[ skipped ]" : "");
+ posn += 512 + ((size+511) & ~511);
+ #if 0
+ fprintf(log_out, "%6lo %02x %12ld %s\n",perm,header.flags[0],size,changed_name);
+ #endif
+
+ if (should_be_written == 0)
+ {
+ skipping = (size+511) & ~511;
+ continue;
+ }
+ else if (changed_name[strlen(changed_name)-1] == '/' && !to_stdout)
+ {
+ changed_name[strlen(changed_name)-1] = 0;
+ do {
+ if (strcmp(changed_name, ".") == 0)
+ r = 0; /* current dir always exists */
+ else if (strcmp(changed_name, "..") == 0)
+ r = !isadir(changed_name); /* root has no parent */
+ else
+ r = mkdir(changed_name
+ #ifdef __GO32__
+ ,0
+ #endif
+ );
+ if (r && (errno==EACCES))
+ {
+ change(changed_name, "Duplicate directory name", 2);
+ continue;
+ }
+ if (r)
+ r = change(changed_name, "Unable to create directory", 1);
+ else
+ fprintf(log_out, "Making directory %s\n", changed_name);
+ } while (r);
+ looking_for_header = 1;
+ continue;
+ }
+ else
+ {
+ open_file:
+ if (!to_stdout)
+ {
+ do_directories(changed_name);
+ r = open(changed_name,
+ O_WRONLY | O_BINARY | O_CREAT | O_EXCL, S_IWRITE | S_IREAD);
+ if (r < 0)
+ if (change(changed_name, "Cannot exclusively open file", 0))
+ goto open_file;
+ else
+ {
+ skipping = (size+511) & ~511;
+ continue;
+ }
+ }
+ else
+ {
+ r = fileno(stdout);
+ if (!to_tty)
+ setmode(r, O_BINARY);
+ }
+ }
+
+ }
+
+ while (size)
+ {
+ char tbuf[512];
+ char *wbuf = buf;
+
+ if (buf_size <= 0) /* this buffer exhausted */
+ return 0;
+ if (size < 512)
+ dsize = size;
+ else if (buf_size < 512)
+ dsize = buf_size;
+ else
+ dsize = 512;
+ if (first_block && (text_dos || text_unix || to_tty))
+ {
+ file_type = guess_file_type(buf, dsize);
+ first_block = 0;
+ if (file_type == UNIX_TEXT && text_dos)
+ setmode(r, O_TEXT); /* will add CR chars to each line */
+ }
+ if ((text_unix || to_tty) && file_type == DOS_TEXT)
+ {
+ /* If they asked for text files to be written Unix style, or
+ we are writing to console, remove the CR and ^Z characters
+ from DOS text files.
+ Note that we don't alter the original uncompressed data so
+ as not to screw up the CRC computations. */
+ char *s=buf, *d=tbuf;
+ while (s-buf < dsize)
+ {
+ if (*s != '\r' && *s != 26)
+ *d++ = *s;
+ s++;
+ }
+ wsize = d - tbuf;
+ wbuf = tbuf;
+ }
+ else
+ {
+ wbuf = buf;
+ wsize = dsize;
+ }
+ errno = 0;
+ if (write(r, wbuf, wsize) < wsize)
+ {
+ if (errno == 0)
+ errno = ENOSPC;
+ fprintf(log_out, "%s: %s\n", changed_name, strerror(errno));
+ write_errno = errno;
+ break;
+ }
+ size -= dsize;
+ buf_size -= dsize;
+ buf += dsize;
+ bytes_out += dsize;
+ }
+
+ if (!to_stdout)
+ {
+ close(r);
+ r = open(changed_name, O_RDONLY);
+ tm = localtime(&ftime);
+ ftimes.ft_tsec = tm->tm_sec / 2;
+ ftimes.ft_min = tm->tm_min;
+ ftimes.ft_hour = tm->tm_hour;
+ ftimes.ft_day = tm->tm_mday;
+ ftimes.ft_month = tm->tm_mon+1;
+ ftimes.ft_year = tm->tm_year - 80;
+ setftime(r, &ftimes);
+ close(r);
+ chmod(changed_name, perm);
+ }
+ looking_for_header = 1;
+ if (write_errno == ENOSPC) /* target disk full: quit early */
+ {
+ bytes_out += buf_size;
+ return EOF;
+ }
+ else if (write_errno) /* other error: skip this file, try next */
+ skipping = (size - dsize + 511) & ~511;
+ else /* skip the slack garbage to the next 512-byte boundary */
+ skipping = 512 - dsize;
+ }
+ return 0;
+ }
+
+ /*------------------------------------------------------------------------*/
+
+ int part_nb;
+ static const char *zip_description[] = {
+ "uncompressed",
+ "COMPRESS'ed",
+ "PACK'ed",
+ "LZH'ed",
+ "compressed by unknown method (4)",
+ "compressed by unknown method (5)",
+ "compressed by unknown method (6)",
+ "compressed by unknown method (7)",
+ "deflated by "
+ };
+
+ void
+ tar_gz_read(char *fname)
+ {
+ void *f;
+
+ errno = 0;
+ f = oread_open(fname);
+ if (errno)
+ {
+ fprintf(log_out, "%s: %s\n", fname, strerror(errno));
+ return;
+ }
+ ifname = fname;
+ header_bytes = 0;
+ clear_bufs(); /* clear input and output buffers */
+ part_nb = 0; /* FIXME!! handle multi-part gzip's */
+ method = get_method(f);
+ if (method < 0)
+ {
+ oread_close(f);
+ return; /* error message already emitted */
+ }
+ if (v_switch)
+ fprintf(log_out, "-- `%s\' is %s%s --\n\n",
+ fname,
+ method > MAX_METHODS ? "corrupted (?)" : zip_description[method],
+ method == DEFLATED ? (pkzip ? "PKZip" : "GZip") : "");
+
+ bytes_out = 0;
+ looking_for_header = 1;
+ posn = 0;
+
+ if ((*decompressor)(f) != OK)
+ {
+ fprintf(log_out,
+ "\n%s: corrupted file; I might have written garbage\n", fname);
+ fflush(log_out);
+ }
+ oread_close(f);
+ method = -1;
+ }
diff -b -C 2 -N -r djgpp/src/utils/djtar/unzip.c newdjgpp/src/utils/djtar/unzip.c
*** djgpp/src/utils/djtar/unzip.c Thu Nov 16 20:04:06 1995
--- newdjgpp/src/utils/djtar/unzip.c Fri Nov 14 18:30:18 1997
***************
*** 118,122 ****
if (method == DEFLATED) {
! int res = inflate();
if (res == 3) {
--- 118,122 ----
if (method == DEFLATED) {
! int res = inflate(tarread);
if (res == 3) {
***************
*** 140,146 ****
if (decrypt) zdecode(c);
#endif
! put_ubyte(c);
}
! flush_window();
} else {
error("internal error, invalid method");
--- 140,146 ----
if (decrypt) zdecode(c);
#endif
! put_ubyte(c, tarread);
}
! flush_window(tarread);
} else {
error("internal error, invalid method");
diff -b -C 2 -N -r djgpp/src/utils/djtar/util.c newdjgpp/src/utils/djtar/util.c
*** djgpp/src/utils/djtar/util.c Thu Nov 16 20:05:18 1995
--- newdjgpp/src/utils/djtar/util.c Mon Nov 17 18:55:46 1997
***************
*** 32,36 ****
/* ===========================================================================
* Copy input to output unchanged.
! * For DJTAR this means we call tarrread() directly.
* IN assertion: insize bytes have already been read in inbuf.
*/
--- 32,36 ----
/* ===========================================================================
* Copy input to output unchanged.
! * For DJTAR this means we call tarread() directly.
* IN assertion: insize bytes have already been read in inbuf.
*/
***************
*** 111,115 ****
* files on-the-fly.)
*/
! void flush_window(void)
{
if (outcnt == 0) return;
--- 111,115 ----
* files on-the-fly.)
*/
! void flush_window(int (*func)(char *, long))
{
if (outcnt == 0) return;
***************
*** 117,121 ****
if (!test) {
! tarread((char *)window, outcnt);
}
else
--- 117,121 ----
if (!test) {
! func((char *)window, outcnt);
}
else
diff -b -C 2 -N -r djgpp/src/utils/djtar/zread.h newdjgpp/src/utils/djtar/zread.h
*** djgpp/src/utils/djtar/zread.h Thu Nov 16 20:03:20 1995
--- newdjgpp/src/utils/djtar/zread.h Mon Nov 17 19:33:40 1997
***************
*** 9,14 ****
#include <stdio.h>
- #include <stddef.h>
#include <string.h>
#define memzero(s, n) memset ((void *)(s), 0, (n))
--- 9,14 ----
#include <stdio.h>
#include <string.h>
+
#define memzero(s, n) memset ((void *)(s), 0, (n))
***************
*** 128,133 ****
#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
! #define put_ubyte(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
! flush_window();}
/* Macros for getting two-byte and four-byte header values */
--- 128,133 ----
#define try_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf(1))
! #define put_ubyte(c,f) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\
! flush_window(f);}
/* Macros for getting two-byte and four-byte header values */
***************
*** 157,162 ****
int (*decompressor)(void *);
! /* in djtarx.c */
extern int tarread (char *, long);
/* in zmethod.c */
--- 157,172 ----
int (*decompressor)(void *);
! typedef enum { DOS_BINARY, DOS_TEXT, UNIX_TEXT } File_type;
!
! /* in djtar.c */
! extern int change (char *, const char *, int);
! extern int isadir (char *);
! extern void do_directories(char *);
! extern File_type guess_file_type(char *, register size_t);
! extern char* get_new_name(char *, int *);
!
! /* in untar.c */
extern int tarread (char *, long);
+ extern void tar_gz_read (char *);
/* in zmethod.c */
***************
*** 173,189 ****
extern int unlzh (void *);
- /* in trees.c */
- void ct_init (ush *_attr, int *_method);
- int ct_tally (int _dist, int _lc);
- ulg flush_block (char *_buf, ulg _stored_len, int _eof);
-
- /* in bits.c */
- void bi_init (void);
- void send_bits (int value, int length);
- unsigned bi_reverse (unsigned value, int length);
- void bi_windup (void);
- void copy_block (char *buf, unsigned len, int header);
- extern int (*read_buf) (char *buf, unsigned size);
-
/* in util.c: */
extern int copy (void *);
--- 183,186 ----
***************
*** 192,196 ****
extern int fill_inbuf (int eof_ok);
extern void flush_outbuf (void);
! extern void flush_window (void);
extern char *basename (char *fname);
extern void error (const char *m);
--- 189,193 ----
extern int fill_inbuf (int eof_ok);
extern void flush_outbuf (void);
! extern void flush_window (int (*)(char *, long));
extern char *basename (char *fname);
extern void error (const char *m);
***************
*** 200,204 ****
/* in inflate.c */
! extern int inflate (void);
#endif /* __zread_h_ */
--- 197,204 ----
/* in inflate.c */
! extern int inflate (int (*)(char *, long));
!
! /* in epunzip.c */
! extern void epunzip_read(char *);
#endif /* __zread_h_ */
diff -b -C 2 -N -r djgpp/src/utils/redir.c newdjgpp/src/utils/redir.c
*** djgpp/src/utils/redir.c Wed Jul 12 04:06:50 1995
--- newdjgpp/src/utils/redir.c Mon Nov 10 18:06:10 1997
***************
*** 86,94 ****
while (argc > 1 && argv[1][0] == '-')
{
if (strcmp(argv[1], "-i")==0 && argc > 2)
{
! close(0);
! if (open(argv[2], O_RDONLY, 0666) != 0)
fatal("redir: attempt to redirect stdin from %s failed", argv[2]);
argc--;
argv++;
--- 86,95 ----
while (argc > 1 && argv[1][0] == '-')
{
+ int temp;
if (strcmp(argv[1], "-i")==0 && argc > 2)
{
! if ((temp = open(argv[2], O_RDONLY, 0666)) < 0 || dup2(temp, 0) == -1)
fatal("redir: attempt to redirect stdin from %s failed", argv[2]);
+ close(temp);
argc--;
argv++;
***************
*** 96,102 ****
else if (strcmp(argv[1], "-o")==0 && argc > 2)
{
! close(1);
! if (open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666) != 1)
fatal("redir: attempt to redirect stdout to %s failed", argv[2]);
argc--;
argv++;
--- 97,104 ----
else if (strcmp(argv[1], "-o")==0 && argc > 2)
{
! if ((temp = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0
! || dup2(temp, 1) == -1)
fatal("redir: attempt to redirect stdout to %s failed", argv[2]);
+ close(temp);
argc--;
argv++;
***************
*** 104,110 ****
else if (strcmp(argv[1], "-oa")==0 && argc > 2)
{
! close(1);
! if (open(argv[2], O_WRONLY|O_APPEND|O_CREAT, 0666) != 1)
fatal("redir: attempt to append stdout to %s failed", argv[2]);
argc--;
argv++;
--- 106,113 ----
else if (strcmp(argv[1], "-oa")==0 && argc > 2)
{
! if ((temp = open(argv[2], O_WRONLY|O_APPEND|O_CREAT, 0666)) < 0
! || dup2(temp, 1) == -1)
fatal("redir: attempt to append stdout to %s failed", argv[2]);
+ close(temp);
argc--;
argv++;
***************
*** 112,118 ****
else if (strcmp(argv[1], "-e")==0 && argc > 2)
{
! close(2);
! if (open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666) != 2)
fatal("redir: attempt to redirect stderr to %s failed", argv[2]);
argc--;
argv++;
--- 115,122 ----
else if (strcmp(argv[1], "-e")==0 && argc > 2)
{
! if ((temp = open(argv[2], O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0
! || dup2(temp, 2) == -1)
fatal("redir: attempt to redirect stderr to %s failed", argv[2]);
+ close(temp);
argc--;
argv++;
***************
*** 120,126 ****
else if (strcmp(argv[1], "-ea")==0 && argc > 2)
{
! close(2);
! if (open(argv[2], O_WRONLY|O_APPEND|O_CREAT, 0666) != 2)
fatal("redir: attempt to append stderr to %s failed", argv[2]);
argc--;
argv++;
--- 124,131 ----
else if (strcmp(argv[1], "-ea")==0 && argc > 2)
{
! if ((temp = open(argv[2], O_WRONLY|O_APPEND|O_CREAT, 0666)) < 0
! || dup2(temp, 2) == -1)
fatal("redir: attempt to append stderr to %s failed", argv[2]);
+ close(temp);
argc--;
argv++;
***************
*** 128,132 ****
else if (strcmp(argv[1], "-eo")==0)
{
- close(2);
if (dup2(1,2) == -1)
fatal("redir: attempt to redirect stderr to stdout failed", 0);
--- 133,136 ----
***************
*** 134,138 ****
else if (strcmp(argv[1], "-oe")==0)
{
- close(1);
if (dup2(2,1) == -1)
fatal("redir: attempt to redirect stdout to stderr failed", 0);
--- 138,141 ----
diff -b -C 2 -N -r djgpp/src/utils/utils.tex newdjgpp/src/utils/utils.tex
*** djgpp/src/utils/utils.tex Tue Jan 23 22:19:30 1996
--- newdjgpp/src/utils/utils.tex Mon Nov 17 20:13:12 1997
***************
*** 60,64 ****
@code{bin2h} allows a developer to embed a binary file into a source
! file, bu converting the binary data to an array of integer values.
Usage: @code{bin2h} @file{datafile} @var{symbol} @file{headerfile}
--- 60,64 ----
@code{bin2h} allows a developer to embed a binary file into a source
! file, by converting the binary data to an array of integer values.
Usage: @code{bin2h} @file{datafile} @var{symbol} @file{headerfile}
***************
*** 93,107 ****
space, because DOS implements pipes as temporary disk files.)
@code{djtar} knows about all the compression methods supported by
! @code{gzip}, namely, deflation (aka LZ77, either by @code{gzip}, by
! @code{zip}, or by @code{pkzip}), LZW compression (by @code{compress}), LZH
! compression (as with @code{compress -H} available with some versions of
! @code{compress}), or Huffman compression (by @code{pack}). Tar files
! compressed with @code{zip} or @code{pkzip} can be decompressed by
! @code{djtar} only if the @file{.zip} file contains a single tar file
compressed with either the @code{deflation} or @code{stored} (i.e.,
! uncompressed, like with @samp{pkzip -e0}) methods; if more than a single
! tar file was put into a compressed zip file, files beyond the first one
! will be ignored by @code{djtar} (a message to this effect will be printed
! under @code{-v} option).
@code{djtar} can also read tar archives (compressed or otherwise) written
--- 93,105 ----
space, because DOS implements pipes as temporary disk files.)
@code{djtar} knows about all the compression methods supported by
! @code{gzip}, namely, deflation (by @code{gzip}), LZW compression
! (by @code{compress}), LZH compression (as with @code{compress -H}
! available with some versions of @code{compress}), or Huffman compression
! (by @code{pack}).
!
! @code{djtar} can also decompress files compressed with @code{zip} or
! @code{pkzip}, but only if the @file{.zip} file contains only files
compressed with either the @code{deflation} or @code{stored} (i.e.,
! uncompressed, like with @samp{pkzip -e0}) methods.
@code{djtar} can also read tar archives (compressed or otherwise) written
***************
*** 175,179 ****
This option modifies the output format slightly to aid in debugging tar
file problems. It also causes @code{djtar} to emit more verbose warning
! messages and print the compression method for compressed archices.
@item -.
--- 173,177 ----
This option modifies the output format slightly to aid in debugging tar
file problems. It also causes @code{djtar} to emit more verbose warning
! messages and print the compression method for compressed archives.
@item -.
***************
*** 442,446 ****
smaller files. @code{merge} puts them back together again.
! Usage: @code{split} @var{inputbase} @var{outputfile}
Each input file is made from appending a sequence number to
--- 440,444 ----
smaller files. @code{merge} puts them back together again.
! Usage: @code{merge} @var{inputbase} @var{outputfile}
Each input file is made from appending a sequence number to
--- cut here ---
Esa Peuha
student of mathematics at the University of Helsinki
http://www.helsinki.fi/~peuha/
- Raw text -