Compress 4.1, Patch 1

Dave Mack csu at alembic.acs.com
Sat Jun 29 09:36:22 AEST 1991


Patch Priority: COSMIC

This patch brings compress 4.1 up to the level that was supposed
to be posted in comp.sources.misc. One or two more patches will
probably follow in the next week or so as I integrate improvements
that people have sent me.

PLEASE APPLY THIS PATCH. It fixes several very nasty bugs in the
posted version.

A couple of comments:

First, please don't blame Kent Landfield for this SNAFU, it's not
his fault. The posted version was the May 30 version. I mailed
Kent the final version on June 1 and never received an ACK from
him. I should have realized that that indicated that there was a
problem.

Second, several people have pointed out that there is another
compress variant called compress 4.3 floating around. It was
put together by (among others) Don Gloistein and Lyle Rains,
and they have done a beautiful job of making compress faster and
more portable. Because of this, and because of the confusion in
version numbering, I'll coordinate with them to put together a
compress version that is based on their version but incorporates
the modifications I made to compress 4.1. If there's any justice
in the world, this will be released this summer as compress 4.4 or
higher.

Finally, the next version of compress that I put out will be
sent to comp.sources.reviewed. This is not an indictment of
Kent's management of comp.sources.misc; it's just that the
ad hoc testing I was able to do (with considerable help from
Pat Myrto and Kent) was not adequate for software targetted for
Usenet.

Dave Mack

diff -rc compress.posted/compress.1 compress41/compress.1
*** compress.posted/compress.1	Fri Jun 28 19:07:12 1991
--- compress41/compress.1	Fri Jun 28 19:08:45 1991
***************
*** 51,65 ****
  while keeping the same ownership modes, access and modification times.
  If no files are specified, the standard input is compressed to the
  standard output.
! Compressed files can be restored to their original form using
! .I uncompress
! or
! .I zcat.
! .PP
! The
  .B \-f
! option will force compression of
! .I name.
  If
  .B \-f
  is not given and
--- 51,65 ----
  while keeping the same ownership modes, access and modification times.
  If no files are specified, the standard input is compressed to the
  standard output.
! .I Compress
! will only attempt to compress regular files.
! In particular, it will ignore symbolic links. If a file has multiple
! hard links,
! .I compress
! will refuse to compress it unless the
  .B \-f
! flag is given.
! .PP
  If
  .B \-f
  is not given and
***************
*** 67,82 ****
  is run in the foreground,
  the user is prompted as to whether an existing file should be overwritten.
  .PP
  The
  .B \-c
  option makes
  .I compress/uncompress
  write to the standard output; no files are changed.
! The nondestructive behavior of
  .I zcat
! is identical to that of
  .I uncompress
  .B \-c.
  .PP
  If the
  .B \-r
--- 67,105 ----
  is run in the foreground,
  the user is prompted as to whether an existing file should be overwritten.
  .PP
+ Compressed files can be restored to their original form using
+ .I uncompress
+ or
+ .I zcat.
+ .PP
+ .I uncompress
+ takes a list of files on its command line and replaces each
+ file whose name ends with
+ .B "\&.Z"
+ and which begins with the correct magic number with an uncompressed
+ file without the 
+ .B "\&.Z."
+ The uncompressed file will have the mode, ownership and
+ timestamps of the compressed file.
+ .PP
  The
  .B \-c
  option makes
  .I compress/uncompress
  write to the standard output; no files are changed.
! .PP
  .I zcat
! is identical to
  .I uncompress
  .B \-c.
+ .I zcat
+ uncompresses either a list of files on the command line or its
+ standard input and writes the uncompressed data on standard output.
+ .I zcat
+ will uncompress files that have the correct magic number whether
+ they have a
+ .B "\&.Z"
+ suffix or not.
  .PP
  If the
  .B \-r
***************
*** 87,92 ****
--- 110,121 ----
  .I compress
  will descend into the directory and compress all the files it finds there.
  .PP
+ The
+ .B \-V
+ flag tells each of these programs to print its version and patchlevel,
+ along with any preprocessor flags specified during compilation, on
+ stderr before doing any compression or uncompression.
+ .PP
  .I Compress
  uses the modified Lempel-Ziv algorithm popularized in
  "A Technique for High Performance Data Compression",
***************
*** 147,157 ****
  a message is printed yielding the percentage of
  reduction for each file compressed.
  .PP
- If the
- .B \-V
- option is specified, the current version and compile options are printed on
- stderr.
- .PP
  Exit status is normally 0;
  if the last file is larger after (attempted) compression, the status is 2;
  if an error occurs, exit status is 1.
--- 176,181 ----
***************
*** 158,164 ****
  .SH "SEE ALSO"
  pack(1), compact(1)
  .SH "DIAGNOSTICS"
! Usage: compress [\-dfvcV] [\-b maxbits] [file ...]
  .in +8
  Invalid options were specified on the command line.
  .in -8
--- 182,188 ----
  .SH "SEE ALSO"
  pack(1), compact(1)
  .SH "DIAGNOSTICS"
! Usage: compress [\-dfvcVr] [\-b maxbits] [file ...]
  .in +8
  Invalid options were specified on the command line.
  .in -8
***************
*** 220,229 ****
  (Relevant only for
  .BR \-v \.)
  .in -8
! -- not a regular file: unchanged
  .in +8
! When the input file is not a regular file,
! (e.g. a directory), it is
  left unaltered.
  .in -8
  -- has 
--- 244,253 ----
  (Relevant only for
  .BR \-v \.)
  .in -8
! -- not a regular file or directory: ignored
  .in +8
! When the input file is not a regular file or directory,
! (e.g. a symbolic link, socket, FIFO, device file), it is
  left unaltered.
  .in -8
  -- has 
***************
*** 232,238 ****
  .in +8
  The input file has links; it is left unchanged.  See
  .IR ln "(1)"
! for more information.
  .in -8
  -- file unchanged
  .in +8
--- 256,264 ----
  .in +8
  The input file has links; it is left unchanged.  See
  .IR ln "(1)"
! for more information. Use the
! .B \-f
! flag to force compression of multiply-linked files.
  .in -8
  -- file unchanged
  .in +8
***************
*** 245,247 ****
--- 271,284 ----
  should be used for file transfer to architectures with 
  a small process data space (64KB or less, as exhibited by the DEC PDP
  series, the Intel 80286, etc.)
+ .PP
+ Invoking compress with a \-r
+ flag will occasionally cause it to produce spurious error warnings of the form
+ .PP
+ .in 8
+ "<filename>.Z already has .Z suffix - ignored"
+ .in -8
+ .PP
+ These warnings can be ignored. See the comments in compress.c:compdir()
+ for an explanation.
+ 
diff -rc compress.posted/compress.c compress41/compress.c
*** compress.posted/compress.c	Fri Jun 28 19:07:09 1991
--- compress41/compress.c	Fri Jun 28 19:08:41 1991
***************
*** 3,8 ****
--- 3,11 ----
   */
  #define	min(a,b)	((a>b) ? b : a)
  
+ /* MAXPATHLEN - maximum length of a pathname we allow */
+ #define MAXPATHLEN 1024
+ 
  /*
   * machine variants which require cc -Dmachine:  pdp11, z8000, pcxt
   */
***************
*** 373,379 ****
  #define	CLEAR	256	/* table clear output code */
  
  int force = 0;
! char ofname [100];
  #ifdef DEBUG
  int verbose = 0;
  #endif /* DEBUG */
--- 376,382 ----
  #define	CLEAR	256	/* table clear output code */
  
  int force = 0;
! char ofname[MAXPATHLEN];
  #ifdef DEBUG
  int verbose = 0;
  #endif /* DEBUG */
***************
*** 386,391 ****
--- 389,395 ----
  
  
  int do_decomp = 0;
+ struct stat statbuf, insbuf;
  
  /*****************************************************************
   * TAG( main )
***************
*** 596,603 ****
  comprexx(fileptr)
  char **fileptr;
  {
! 	struct stat statbuf,insbuf;
! 	char tempname[1024], *cp;
  
  	strcpy(tempname,*fileptr);
  	errno = 0;
--- 600,606 ----
  comprexx(fileptr)
  char **fileptr;
  {
! 	char tempname[MAXPATHLEN], *cp;
  
  	strcpy(tempname,*fileptr);
  	errno = 0;
***************
*** 647,652 ****
--- 650,658 ----
  	case S_IFDIR:	/* directory */
  	  if (recursive)
  	    compdir(tempname);
+ 	  else if ( ! quiet )
+ 	    fprintf(stderr,"%s is a directory -- ignored\n",
+ 		    tempname);
  	  break;
  
  	case S_IFREG:	/* regular file */
***************
*** 697,706 ****
  	    else {
  	/* COMPRESSION */
  		if (strcmp(tempname + strlen(tempname) - 2, ".Z") == 0) {
! 		    	fprintf(stderr, "%s: already has .Z suffix -- no change\n",
! 			    tempname);
! 		    return;
  		}
  		/* Open input file */
  		if ((freopen(tempname, "r", stdin)) == NULL) {
  		    perror(tempname); return;
--- 703,717 ----
  	    else {
  	/* COMPRESSION */
  		if (strcmp(tempname + strlen(tempname) - 2, ".Z") == 0) {
! 		  fprintf(stderr, "%s: already has .Z suffix -- no change\n",
! 			  tempname);
! 		  return;
  		}
+ 		if (insbuf.st_nlink > 1 && (! force) ) {
+ 		  fprintf(stderr, "%s has %d other links: unchanged\n",
+ 			  tempname,insbuf.st_nlink - 1);
+ 		  return;
+ 		}
  		/* Open input file */
  		if ((freopen(tempname, "r", stdin)) == NULL) {
  		    perror(tempname); return;
***************
*** 787,794 ****
  		if((exit_stat == 1) || (!quiet))
  			putc('\n', stderr);
  	    }
  	default:
! 		break;
  	} /* end switch */
  	return;
  } /* end comprexx */
--- 798,808 ----
  		if((exit_stat == 1) || (!quiet))
  			putc('\n', stderr);
  	    }
+ 	  break;
  	default:
! 	  fprintf(stderr,"%s is not a directory or a regular file - ignored\n",
! 		  tempname);
! 	  break;
  	} /* end switch */
  	return;
  } /* end comprexx */
***************
*** 802,808 ****
  #else
  	register struct dirent *dp;
  #endif
! 	char nbuf[1024];
  	char *nptr = nbuf;
  	dirp = opendir(dir);
  	if (dirp == NULL) {
--- 816,822 ----
  #else
  	register struct dirent *dp;
  #endif
! 	char nbuf[MAXPATHLEN];
  	char *nptr = nbuf;
  	dirp = opendir(dir);
  	if (dirp == NULL) {
***************
*** 809,823 ****
  		printf("%s unreadable\n", dir);		/* not stderr! */
  		return ;
  	}
  	while (dp = readdir(dirp)) {
  		if (dp->d_ino == 0)
  			continue;
! 		if (strcmp(dp->d_name,".") == 0 || strcmp(dp->d_name,"..") == 0)
  			continue;
! 		strcpy(nbuf,dir);
! 		strcat(nbuf,"/");
! 		strcat(nbuf,dp->d_name);
! 		comprexx(&nptr);
    	}
  	closedir(dirp);
  	return;
--- 823,856 ----
  		printf("%s unreadable\n", dir);		/* not stderr! */
  		return ;
  	}
+ 	/*
+ 	** WARNING: the following algorithm will occasionally cause
+ 	** compress to produce error warnings of the form "<filename>.Z
+ 	** already has .Z suffix - ignored". This occurs when the
+ 	** .Z output file is inserted into the directory below
+ 	** readdir's current pointer.
+ 	** These warnings are harmless but annoying. The alternative
+ 	** to allowing this would be to store the entire directory
+ 	** list in memory, then compress the entries in the stored
+ 	** list. Given the depth-first recursive algorithm used here,
+ 	** this could use up a tremendous amount of memory. I don't
+ 	** think it's worth it. -- Dave Mack
+ 	*/
  	while (dp = readdir(dirp)) {
  		if (dp->d_ino == 0)
  			continue;
! 		if (strcmp(dp->d_name,".") == 0 ||
! 		    strcmp(dp->d_name,"..") == 0)
  			continue;
! 		if ( (strlen(dir)+strlen(dp->d_name)+1) < (MAXPATHLEN - 1)){
! 		  strcpy(nbuf,dir);
! 		  strcat(nbuf,"/");
! 		  strcat(nbuf,dp->d_name);
! 		  comprexx(&nptr);
! 		}
! 		else {
! 		  fprintf(stderr,"Pathname too long: %s/%s\n",dir,dp->d_name);
! 		}
    	}
  	closedir(dirp);
  	return;
***************
*** 1407,1448 ****
  copystat(ifname, ofname)
  char *ifname, *ofname;
  {
-     struct stat statbuf;
      int mode;
      time_t timep[2];
  
      fclose(stdout);
!     if (stat(ifname, &statbuf)) {		/* Get stat on input file */
! 	perror(ifname);
! 	return;
!     }
!     if ((statbuf.st_mode & S_IFMT/*0170000*/) != S_IFREG/*0100000*/) {
! 	if(quiet)
! 	    	fprintf(stderr, "%s: ", ifname);
! 	fprintf(stderr, " -- not a regular file: unchanged");
! 	exit_stat = 1;
!     } else if (statbuf.st_nlink > 1 && (! force) ) {
! 	if(quiet)
! 	    	fprintf(stderr, "%s: ", ifname);
! 	fprintf(stderr, " -- has %d other links: unchanged",
! 		statbuf.st_nlink - 1);
! 	exit_stat = 1;
!     } else if (exit_stat == 2 && (!force)) { /* No compression: remove file.Z */
  	if(!quiet)
! 		fprintf(stderr, " -- file unchanged");
      } else {			/* ***** Successful Compression ***** */
  	exit_stat = 0;
! 	mode = statbuf.st_mode & 07777;
  	if (chmod(ofname, mode))		/* Copy modes */
  	    perror(ofname);
! 	chown(ofname, statbuf.st_uid, statbuf.st_gid);	/* Copy ownership */
! 	timep[0] = statbuf.st_atime;
! 	timep[1] = statbuf.st_mtime;
  	utime(ofname, timep);	/* Update last accessed and modified times */
  	if (unlink(ifname))	/* Remove input file */
  	    perror(ifname);
  	if(!quiet)
! 		fprintf(stderr, " -- replaced with %s", ofname);
  	return;		/* Successful return */
      }
  
--- 1440,1466 ----
  copystat(ifname, ofname)
  char *ifname, *ofname;
  {
      int mode;
      time_t timep[2];
  
      fclose(stdout);
!     if (exit_stat == 2 && (!force)) { /* No compression: remove file.Z */
  	if(!quiet)
! 		fprintf(stderr, "No compression -- %s unchanged",
! 			ifname);
      } else {			/* ***** Successful Compression ***** */
  	exit_stat = 0;
! 	mode = insbuf.st_mode & 07777;
  	if (chmod(ofname, mode))		/* Copy modes */
  	    perror(ofname);
! 	chown(ofname, insbuf.st_uid, insbuf.st_gid);	/* Copy ownership */
! 	timep[0] = insbuf.st_atime;
! 	timep[1] = insbuf.st_mtime;
  	utime(ofname, timep);	/* Update last accessed and modified times */
  	if (unlink(ifname))	/* Remove input file */
  	    perror(ifname);
  	if(!quiet)
! 		fprintf(stderr, " -- replaced with %s",ofname);
  	return;		/* Successful return */
      }
  
diff -rc compress.posted/patchlevel.h compress41/patchlevel.h
*** compress.posted/patchlevel.h	Fri Jun 28 19:07:16 1991
--- compress41/patchlevel.h	Fri Jun 28 19:12:42 1991
***************
*** 1 ****
! #define PATCHLEVEL 0
--- 1 ----
! #define PATCHLEVEL 1



More information about the Comp.sources.bugs mailing list