[alt.sources.patches] compress 4.1 file deletion fixes

djm@eng.umd.edu (David J. MacKenzie) (06/27/91)

> This new version of compress seems to have the old problem with zcat
> somtimes deleting the compressed file when interrupted.  I thought
> this bug was fixed long ago.

To be precise, comp.sources.misc "v06i066: compress 4.0 bug fixes"
submitted by res@cbnews.ATT.COM (Robert E. Stampfli) contains that
fix.  It drops in to 4.1 with only a few small changes.  Below, I have
adapted Robert's fixes for compress 4.1.  I also fixed a problem with
declaring signal handlers in the wrong place, which prevented compress
from compiling with gcc.  And I fixed the problem that the error
messages that compress prints #ifdef SHORTNAMES when it can't tack on
a .Z only mentioned the last component of the pathname.  This happened
both in Robert's patch and in the stock code, when creating the output
file.


--- compress.c.dist	Tue Jun 25 17:36:59 1991
+++ compress.c	Thu Jun 27 02:19:55 1991
@@ -373,6 +373,7 @@
 #define	CLEAR	256	/* table clear output code */
 
 int force = 0;
+int valid = 0;		/* set when signal can remove ofname */
 char ofname [100];
 #ifdef DEBUG
 int verbose = 0;
@@ -429,18 +430,18 @@
 
 int overwrite = 0;	/* Do not overwrite unless given -f flag */
 int recursive = 0;  /* compress directories */
+extern onintr(), oops();
 main( argc, argv )
 register int argc; char **argv;
 {
     char **filelist, **fileptr;
     char *cp, *rindex(), *malloc();
-    extern onintr(), oops();
 
 
     if ( (bgnd_flag = signal ( SIGINT, SIG_IGN )) != SIG_IGN ) {
 	signal ( SIGINT, onintr );
-	signal ( SIGSEGV, oops );
     }
+    signal ( SIGSEGV, oops );
 
 #ifdef COMPATIBLE
     nomagic = 1;	/* Original didn't have a magic number */
@@ -615,6 +616,14 @@
 	      ** directory, but it shouldn't do any harm.
 	      */
 	      if (strcmp(tempname + strlen(tempname) - 2, ".Z") != 0) {
+#ifdef SHORTNAMES
+		    if ((cp=rindex(tempname,'/')) != NULL)	cp++;
+		    else					cp = tempname;
+		    if (strlen(cp) > 12) {
+			fprintf(stderr,"%s.Z: No such file or directory\n",tempname);
+			return;
+		    }
+#endif  /* SHORTNAMES */
 		strcat(tempname,".Z");
 		errno = 0;
 #ifdef	BSD4
@@ -732,7 +741,7 @@
 		if ((cp=rindex(ofname,'/')) != NULL)	cp++;
 		else					cp = ofname;
 		if (strlen(cp) > 12) {
-		    fprintf(stderr,"%s: filename too long to tack on .Z\n",cp);
+		    fprintf(stderr,"%s: filename too long to tack on .Z\n",ofname);
 		    signal(SIGINT,onintr);
 		    return;
 		}
@@ -746,8 +755,7 @@
 		    response[0] = 'n';
 		    fprintf(stderr, "%s already exists;", ofname);
 		    if (foreground()) {
-			fprintf(stderr, " do you wish to overwrite %s (y or n)? ",
-			ofname);
+			fprintf(stderr, " OK to overwrite (y or n)? ");
 			fflush(stderr);
 			read(2, response, 2);
 			while (response[1] != '\n') {
@@ -765,6 +773,7 @@
 	    }
 	    signal(SIGINT,onintr);
 	    if(zcat_flg == 0) {		/* Open output file */
+	        valid = 1;
 		if (freopen(ofname, "w", stdout) == NULL) {
 		    perror(ofname);
 			return;
@@ -1400,7 +1409,8 @@
 writeerr()
 {
     perror ( ofname );
-    unlink ( ofname );
+    if (valid)
+	unlink ( ofname );
     exit ( 1 );
 }
 
@@ -1439,6 +1449,7 @@
 	timep[0] = statbuf.st_atime;
 	timep[1] = statbuf.st_mtime;
 	utime(ofname, timep);	/* Update last accessed and modified times */
+	valid = 0;		/* prevent latent ofname removal */
 	if (unlink(ifname))	/* Remove input file */
 	    perror(ifname);
 	if(!quiet)
@@ -1469,7 +1480,8 @@
 
 onintr ( )
 {
-    unlink ( ofname );
+    if (valid)
+	unlink ( ofname );
     exit ( 1 );
 }
 
@@ -1477,7 +1489,8 @@
 {
     if ( do_decomp == 1 ) 
     	fprintf ( stderr, "uncompress: corrupt input\n" );
-    unlink ( ofname );
+    if (valid)
+	unlink ( ofname );
     exit ( 1 );
 }
 
--
David J. MacKenzie <djm@eng.umd.edu> <djm@ai.mit.edu>

djm@eng.umd.edu (David J. MacKenzie) (06/29/91)

> Pardon the ignorance, but what kind of diff format is the one above?
> Larry Wall's patch doesn't seem to recognise it.

Sorry, I forgot to mention it.  It's a unified diff, produced by GNU
diff 1.15.  It's like context format except that it omits duplicate
context lines to save space.  If you can anonymous ftp,
prep.ai.mit.edu:pub/gnu/patch-2.0.12u4.tar.Z is a version of patch
that recognizes unified diffs.  If not, here is a short program called
unipatch that converts unified diffs to context diffs.  It came from
comp.sources.misc "v14i070: Unified context diff tools" plus a patch
in comp.sources.bugs.  You'll likely be seeing more unified diffs on
the net as time goes on, so it's worth while having programs that can
deal with them.


/*
A filter to turn a unidiff into a degenerate context diff (no '!'s)
for patch. Author: davison@dri.com (uunet!drivax!davison).
*/
#include <stdio.h>
#define ERR(a) {fputs(a,stderr);exit(1);}
struct Ln {
	struct Ln *lk;
	char t;
	char s[1];
} r,*h,*ln;
char *malloc();
main()
{
char bf[2048],*cp,ch;
long os,ol,ns,nl,ne,lncnt=0;
for(;;){
 for(;;){
	if(!fgets(bf,sizeof bf,stdin)) exit(0);
	lncnt++;
	if(!strncmp(bf,"@@ -",4)) break;
	if(!strncmp(bf,"+++ ",4)) printf("***%s",bf+3);
	else fputs(bf,stdout);
 }
 if(sscanf(bf+4,"%ld,%ld +%ld,%ld %c",&os,&ol,&ns,&nl,&ch)!=5||ch!='@')
	goto bad;
 r.lk=0, h= &r, ne=ns+nl-1;
 printf("***************\n*** %ld,%ld ****\n",os,os+ol-(os>0));
 while(ol||nl){
	if(!fgets(bf,sizeof bf,stdin)){
		if(nl>2) ERR("Unexpected end of file.\n");
		strcpy(bf," \n");
	}
	lncnt++;
	if(*bf=='\t'||*bf=='\n')
		ch=' ', cp=bf;
	else
		ch= *bf, cp=bf+1;
	switch(ch){
	case'-':if(!ol--) goto bad;
		printf("- %s",cp);
		break;
	case'=':ch=' ';
	case' ':if(!ol--) goto bad;
		printf("  %s",cp);
	case'+':if(!nl--) goto bad;
		ln = (struct Ln*)malloc(sizeof(*ln)+strlen(cp));
		if(!ln) ERR("Out of memory!\n");
		ln->lk=0, ln->t=ch, strcpy(ln->s,cp);
		h->lk=ln, h=ln;
		break;
	default:
	bad:	fprintf(stderr,"Malformed unidiff at line %ld: ",lncnt);
		ERR(bf);
	}
 }
 printf("--- %ld,%ld ----\n",ns,ne);
 for(ln=r.lk;ln;ln=h){
	printf("%c %s",ln->t,ln->s);
	h=ln->lk;
	free(ln);
 }
}
}
--
David J. MacKenzie <djm@eng.umd.edu> <djm@ai.mit.edu>