Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Jun 1996 08:35:35 -0700
From:      Poul-Henning Kamp <phk@freebsd.org>
To:        ctm-announce@freebsd.org
Subject:   CTM: You may want to look at this...
Message-ID:  <1974.834420935@critter.tfs.com>

next in thread | raw e-mail | index | archive | help

Danny Zerkel has too much time on his hands, I'm sure you guys will
appreciate that he spends it on CTM.  I certainly do :-)

Much appreciated Danny!

Comments to Danny and me please

Poul-Henning

------- Forwarded Message

Return-Path: dzerkel@cas.org
Received: from tfs.com (tfs.com [140.145.250.1])
          by freefall.freebsd.org (8.7.5/8.7.3) with SMTP id FAA29899
          for <phk@freebsd.org>; Mon, 10 Jun 1996 05:50:42 -0700 (PDT)
Received: from srv01s4 by tfs.com (smail3.1.28.1) with SMTP
	id m0uT6Qa-0003vuC; Mon, 10 Jun 96 05:50 PDT
Date: Mon, 10 Jun 1996 08:50:36 -0400
From: dzerkel@cas.org (Danny Zerkel - D26)
Message-Id: <9606101250.AA25788@cas.org>
To: phk@critter.tfs.com
Subject: CTM changes
Content-Type: X-sun-attachment

- ----------
X-Sun-Data-Type: text
X-Sun-Data-Description: text
X-Sun-Data-Name: text
X-Sun-Charset: us-ascii
X-Sun-Content-Lines: 23

Poul-Henning,

Life has kept me busy, lately.  I have finally gotten back to CTM, however.
Here is my new version.  It includes the -e reg_expr option, plus -x reg_expr,
- -l, and -k.  The -x adds a regular expression which, if found, will remove
the file from the list.  All -e's are processed before the -x's.  The -l
option causes CTM to list the actions and filenames in the input files only.
(This is a good way to verify -e's and -x's.)  The -k option prohibits removes
of files or directories.

Danny J. Zerkel
- ----------
X-Sun-Data-Type: default-app
X-Sun-Data-Description: default
X-Sun-Data-Name: ctm.diff
X-Sun-Charset: us-ascii
X-Sun-Content-Lines: 1054

- --- ctm.1.ctm	Sun May  5 20:02:11 1996
+++ ctm.1	Sun Jun  9 23:21:33 1996
@@ -10,7 +10,7 @@
 .\"
 .\" CTM and ctm(1) by <phk@login.dknet.dk>
 .\"
- -.\" $Id: ctm.1,v 1.2.4.1 1996/01/31 02:01:56 nate Exp $
+.\" $Id: ctm.1,v 1.5 1996/04/29 21:02:26 phk Exp $
 .\"
 .Dd Mar 25, 1995
 .Os
@@ -20,8 +20,12 @@
 .Nd source code mirror program
 .Sh SYNOPSIS
 .Nm ctm
- -.Op Fl cFpPqv
+.Op Fl cklFquv
+.Op Fl b Ar basedir
+.Op Fl e Ar reg_expr . . .
+.Op Fl x Ar reg_expr . . .
 .Op Fl T Ar tmpdir
+.Op Fl V Ar level
 .Ar file Op ...
 .Sh DESCRIPTION
 .Nm Ctm
@@ -53,15 +57,23 @@
 command runs in a number of passes.  It will process the entire
 input file in each pass, before commencing with the next pass.
 
- -Pass 1 will validate that the input file is OK.  The syntax, the data
+Before working on a file
+.Ar name
+.Nm ctm
+first checks for the existence of the file
+.Ar name.ctm .
+If this file exists,
+.Nm ctm
+works on it instead.
+
+Pass 1 will verify that the input file is okay.  The syntax, the data
 and the global MD5 checksum will be checked.  If any of these fail,
 .Nm ctm
- -will never be able to do anything with the file, so it will simply
- -reject it.
+will simply reject the input file.
 
 Pass 2 will validate that the directory tree is in the state expected by
 the CTM delta.  This is done by looking for files and directories which
- -should/should not exists and by checking the MD5 checksums of files.  
+should/should not exist and by checking the MD5 checksums of files.  
 
 Pass 3 will actually apply the delta.
 
@@ -74,20 +86,49 @@
 are explicitly prohibited as a security measure.
 
 .Ss Options
- -
 .Bl -tag -width indent -compact
 
+.It Fl b Ar basedir
+Prepend the path
+.Ar basedir
+to every filename.
+
 .It Fl c
 Check it out, don't do anything.
 
+.It Fl e Ar reg_expr
+Match each name in the CTM file against
+.Ar reg_expr ,
+if it matches,
+process the file, otherwise skip it.  There many be any number of these
+expressions, included as seperate arguments.  Use of this option
+disables the
+.Pa .ctm_status
+sequence number checks.  The expression '^usr.sbin/ctm', for example,
+will select the 
+.Nm ctm
+source directory and all files and directories under it.
+
+.It Fl x Ar reg_expr
+Not match each name in the input file against
+.Ar reg_expr ,
+if it doesn't match,
+process the file, otherwise skip it.  Like
+.Fl e ,
+there may be many of these.  Note that all matches (
+.Fl e )
+are tested then all the not matches (
+.Fl x ) .
+
 .It Fl F
 Force.
 
- -.It Fl p
- -Less paranoid.
+.It Fl k
+Keep files and directories.  Ignore removes for files and directories.
 
- -.It Fl P
- -Paranoid.
+.It Fl l
+Just list the actions and filenames.  Especially useful for checking that
+matches are working correctly, before actually using them.
 
 .It Fl q
 Tell us less.
@@ -96,8 +137,17 @@
 Put temporary files under
 .Ar tmpdir .
 
+.It Fl u
+Set modification time of created and modified files to the CTM delta
+creation time.
+
 .It Fl v
+Tell us more.  Multiple use increases verbosity.
+
+.It Fl V Ar level
 Tell us more.
+.Ar Level
+is the level of verbosity.
 
 .El
 
@@ -120,9 +170,10 @@
 
 .Sh DIAGNOSTICS
 
- -Numerous messages, hopefully self-explaining.  The
+Numerous messages, hopefully self-explanatory.  The
 .Dq noise level
 can be adjusted with the
+.Fl V ,
 .Fl q
 and
 .Fl v
@@ -131,10 +182,11 @@
 .Sh SEE ALSO
 
 .Xr ctm 5
+.Xr re_format 7
 
 .Sh HISTORY
 
- -Initial trials ran during the FreeBSD 1.1.5, and many bugs and 
+Initial trials were run during the work on FreeBSD 1.1.5, and many bugs and 
 methods were hashed out.
 
 The
- --- ctm.5.ctm	Sun May  5 23:10:45 1996
+++ ctm.5	Mon May  6 22:15:44 1996
@@ -123,6 +123,18 @@
 .Xr diff 1
 -n script which should be applied to the file in question.
 
+.It \&FE Ar name uid gid mode md5before md5after count
+
+.Em OBSOLETE
+.Pp
+Edit the file
+.Ar name
+using
+.Xr ed 1 .
+The arguments are as above, but the data sections contains an
+.Xr diff 1
+-e script which should be applied to the file in question.
+
 .It \&FR Ar name md5
 
 Remove the file
- --- ctm.c.ctm	Sun May  5 19:17:28 1996
+++ ctm.c	Sun Jun  9 22:23:29 1996
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  *
- - * $Id: ctm.c,v 1.11 1995/05/30 03:47:19 rgrimes Exp $
+ * $Id: ctm.c,v 1.13 1996/04/29 21:02:28 phk Exp $
  *
  * This is the client program of 'CTM'.  It will apply a CTM-patch to a
  * collection of files.
@@ -14,7 +14,6 @@
  * Options we'd like to see:
  *
  * -a 			Attempt best effort.
- - * -b <dir>		Base-dir
  * -B <file>		Backup to tar-file.
  * -d <int>		Debug TBD.
  * -m <mail-addr>	Email me instead.
@@ -22,13 +21,22 @@
  * -R <file>		Read list of files to reconstruct.
  *
  * Options we have:
+ * -b <dir>		Base-dir for update.
  * -c			Check it out, don't do anything.
+ * -e <reg_expr>	Regular expression match on file names.
+ * -x <reg_expr>	Regular expression unmatch on file names.
  * -F      		Force
- - * -p			Less paranoid.
- - * -P			Paranoid.
+ * -k			Keep files and directories that would have been removed.
+ * -l			List actions and filenames only.
  * -q 			Tell us less.
  * -T <tmpdir>.		Temporary files.
+ * -u			Set all file modification times to the timestamp.
  * -v 			Tell us more.
+ * -V <level>		Tell us more level = number of -v.
+ *
+ * Options we don't actually use:
+ * -p			Less paranoid.
+ * -P			Paranoid.
  *
  */
 
@@ -46,23 +54,74 @@
     int c;
     extern int optopt,optind;
     extern char * optarg;
- -    FILE *statfile;
     unsigned applied = 0;
+    FILE *statfile;
+    u_char * basedir;
+    struct CTM_expr *last_expr = 0;
+    struct CTM_expr *last_nexpr = 0;
+    struct CTM_expr *new_expr = 0;
+    int err;
 
+    basedir = NULL;
     Verbose = 1;
     Paranoid = 1;
+    SetTime = 0;
+    ListIt = 0;
+    KeepIt = 0;
     setbuf(stderr,0);
     setbuf(stdout,0);
 
- -    while((c=getopt(argc,argv,"ab:B:cd:Fm:pPqr:R:T:Vv")) != -1) {
+    while((c=getopt(argc,argv,"ab:B:cd:e:Fklm:pPqr:R:T:uV:vx:")) != -1) {
 	switch (c) {
+	    case 'b': basedir = optarg;	break; /* Base Directory */
 	    case 'c': CheckIt++;	break; /* Only check it */
+	    case 'k': KeepIt++;		break; /* Don't do removes */
+	    case 'l': ListIt++;		break; /* Only list actions and files*/
 	    case 'p': Paranoid--;	break; /* Less Paranoid */
 	    case 'P': Paranoid++;	break; /* More Paranoid */
 	    case 'q': Verbose--;	break; /* Quiet */
 	    case 'v': Verbose++;	break; /* Verbose */
 	    case 'T': TmpDir = optarg;	break;
 	    case 'F': Force = 1;	break;
+	    case 'u': SetTime++;	break; /* Set timestamp on files */
+	    case 'e':
+	    case 'x':
+		new_expr = (struct CTM_expr*) Malloc(sizeof(struct CTM_expr));
+		if (new_expr == 0) {
+		    fprintf(stderr,"Out of memory for expressions: %s\n",
+		      optarg);
+		    stat++;
+		    break;
+		}
+		(void) memset(new_expr, 0, sizeof(struct CTM_expr));
+		err = regcomp(&new_expr->cmp_ex, optarg, REG_NOSUB);
+		if (err != 0) {
+		    char errmsg[128];
+
+		    regerror(err, &new_expr->cmp_ex, errmsg, sizeof(errmsg));
+		    fprintf(stderr, "Regular expression: %s\n", errmsg);
+		    stat++;
+		    break;
+		}
+		if (c == 'e') {
+		    if (last_expr == 0) {
+			expr_list = new_expr;
+		    } else {
+			last_expr->next = new_expr;
+		    }
+		    last_expr = new_expr;
+		} else {
+		    if (last_nexpr == 0) {
+			nexpr_list = new_expr;
+		    } else {
+			last_nexpr->next = new_expr;
+		    }
+		    last_nexpr = new_expr;
+		}
+		break;
+	    case 'V': sscanf(optarg,"%d", &c); /* Verbose */
+		      Verbose += c;
+		      break;
 	    case ':':
 		fprintf(stderr,"Option '%c' requires an argument.\n",optopt);
 		stat++;
@@ -85,11 +144,30 @@
     argc -= optind;
     argv += optind;
 
- -    if((statfile = fopen(CTM_STATUS, "r")) == NULL)
- -	fprintf(stderr, "Warning: " CTM_STATUS " not found.\n");
- -    else {
- -	fscanf(statfile, "%*s %u", &applied);
- -	fclose(statfile);
+    if (basedir == NULL) {
+	Buffer = (u_char *)Malloc(BUFSIZ + strlen(SUBSUFF) +1);
+	CatPtr = Buffer;
+	*Buffer  = '\0';
+    } else {
+	Buffer = (u_char *)Malloc(strlen(basedir)+ BUFSIZ + strlen(SUBSUFF) +1);
+	strcpy(Buffer, basedir);
+	CatPtr = Buffer + strlen(basedir);
+	if (CatPtr[-1] != '/') {
+		strcat(Buffer, "/");
+		CatPtr++;
+	}
+    }
+    strcat(Buffer, CTM_STATUS);
+
+    if (expr_list || ListIt) {
+	applied = 0;
+    } else {
+	if((statfile = fopen(Buffer, "r")) == NULL)
+	    fprintf(stderr, "Warning: %s not found.\n", Buffer);
+	else {
+	    fscanf(statfile, "%*s %u", &applied);
+	    fclose(statfile);
+	}
     }
 
     if(!argc)
@@ -103,7 +181,7 @@
     if(stat == Exit_Done)
 	stat = Exit_OK;
 
- -    if(Verbose)
+    if(Verbose && !(Verbose == 1 && ListIt))
 	fprintf(stderr,"Exit(%d)\n",stat);
     return stat;
 }
@@ -119,7 +197,7 @@
 	p = 0;
 	f = stdin;
     } else if(p && (!strcmp(p,".gz") || !strcmp(p,".Z"))) {
- -	p = Malloc(100);
+	p = alloca(20 + strlen(filename));
 	strcpy(p,"gunzip < ");
 	strcat(p,filename);
 	f = popen(p,"r");
@@ -136,7 +214,7 @@
     if(Verbose > 1)
 	fprintf(stderr,"Working on <%s>\n",filename);
 
- -    if(FileName) Free(FileName);
+    Delete(FileName);
     FileName = String(filename);
 
     /* If we cannot seek, we're doomed, so copy to a tmp-file in that case */
@@ -167,6 +245,19 @@
     if((i=Pass1(f, applied)))
 	goto exit_and_close;
 
+    if (!Pass1Match) {
+	if (Verbose > 1) {
+	    fprintf(stderr, "No matches in <%s>.\n", filename);
+	}
+	i = Exit_Done;
+	goto exit_and_close;
+    }
+
+    if (ListIt) {
+	i = Exit_Done;
+	goto exit_and_close;
+    }
+
     if(!p) {
         rewind(f);
     } else {
@@ -199,12 +290,11 @@
     i=Pass3(f);
 
 exit_and_close:
- -    if(!p) {
+    if(!p)
         fclose(f);
- -    } else {
+    else
 	pclose(f);
- -	Free(p);
- -    }
+
     if(i)
 	return i;
 
- --- ctm.h.ctm	Sun May  5 19:08:42 1996
+++ ctm.h	Sun Jun  9 22:23:57 1996
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  *
- - * $Id: ctm.h,v 1.7 1995/05/30 03:47:21 rgrimes Exp $
+ * $Id: ctm.h,v 1.9 1996/04/29 21:02:29 phk Exp $
  *
  */
 
@@ -17,13 +17,19 @@
 #include <ctype.h>
 #include <string.h>
 #include <errno.h>
+#include <time.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/file.h>
+#include <sys/time.h>
+#include <regex.h>
 
 #define VERSION "2.0"
 #define MAXSIZE (1024*1024*10)
 
+#define SUBSUFF ".ctm"
+#define TMPSUFF ".ctmtmp"
+
 /* The fields... */
 #define CTM_F_MASK		0xff
 #define CTM_F_Name		0x01
@@ -39,6 +45,7 @@
 #define CTM_Q_Name_File		0x0100
 #define CTM_Q_Name_Dir		0x0200
 #define CTM_Q_Name_New		0x0400
+#define CTM_Q_Name_Subst	0x0800
 #define CTM_Q_MD5_After		0x0100
 #define CTM_Q_MD5_Before	0x0200
 #define CTM_Q_MD5_Chunk		0x0400
@@ -46,13 +53,21 @@
 
 struct CTM_Syntax {
     char	*Key;
+    char	*Name;
     int		*List;
     };
 
 extern struct CTM_Syntax Syntax[];
 
+struct CTM_expr {
+    struct CTM_expr*	next;
+    regex_t		cmp_ex;
+};
+
 #define Malloc malloc
 #define Free free
+#define Delete(foo) if (!foo) ; else {Free(foo); foo = 0; }
+#define String(foo) strdup(foo)
 
 #ifndef EXTERN
 #  define EXTERN extern
@@ -63,8 +78,12 @@
 EXTERN u_char *TimeStamp;
 EXTERN u_char *Prefix;
 EXTERN u_char *FileName;
- -EXTERN u_char *BaseDir;
 EXTERN u_char *TmpDir;
+EXTERN u_char *CatPtr;
+EXTERN u_char *Buffer;
+
+EXTERN struct CTM_expr*	expr_list;
+EXTERN struct CTM_expr*	nexpr_list;
 
 /*
  * Paranoid -- Just in case they should be after us...
@@ -97,6 +116,11 @@
 EXTERN int Exit;
 EXTERN int Force;
 EXTERN int CheckIt;
+EXTERN int KeepIt;
+EXTERN int ListIt;
+EXTERN int SetTime;
+EXTERN int Pass1Match;
+EXTERN struct timeval Times[2];
 
 #define Exit_OK		0
 #define Exit_Garbage	1
@@ -108,13 +132,13 @@
 #define Exit_Done	64
 #define Exit_Version	128
 
- -char * String(char *s);
 void Fatal_(int ln, char *fn, char *kind);
 #define Fatal(foo) Fatal_(__LINE__,__FILE__,foo)
 #define Assert() Fatal_(__LINE__,__FILE__,"Assert failed.")
 #define WRONG {Assert(); return Exit_Mess;}
 
 u_char * Ffield(FILE *fd, MD5_CTX *ctx,u_char term);
+u_char * Fname(FILE *fd, MD5_CTX *ctx,u_char term,int qual, int verbose);
 
 int Fbytecnt(FILE *fd, MD5_CTX *ctx, u_char term);
 
@@ -124,6 +148,7 @@
 #define GETFIELDCOPY(p,q) if(!((p)=Ffield(fd,&ctx,(q)))) return BADREAD; else p=String(p)
 #define GETBYTECNT(p,q) if(0 >((p)= Fbytecnt(fd,&ctx,(q)))) return BADREAD
 #define GETDATA(p,q) if(!((p) = Fdata(fd,(q),&ctx))) return BADREAD
+#define GETNAMECOPY(p,q,r,v) if(!((p)=Fname(fd,&ctx,(q),(r),(v)))) return BADREAD; else p=String(p)
 
 int Pass1(FILE *fd, unsigned applied);
 int Pass2(FILE *fd);
- --- ctm_pass1.c.ctm	Sun May  5 22:27:10 1996
+++ ctm_pass1.c	Sun Jun  9 22:33:03 1996
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  *
- - * $Id: ctm_pass1.c,v 1.10.4.1 1995/09/06 14:20:20 davidg Exp $
+ * $Id: ctm_pass1.c,v 1.12 1996/02/05 16:06:50 phk Exp $
  *
  */
 
@@ -24,8 +24,10 @@
     MD5_CTX ctx;
     int i,j,sep,cnt;
     u_char *md5=0,*trash=0;
+    u_char *name = 0;
     struct CTM_Syntax *sp;
     int slashwarn=0;
+    int nomatch=0;
     unsigned current;
     char md5_1[33];
 
@@ -33,6 +35,10 @@
 	printf("Pass1 -- Checking integrity of incoming CTM-patch\n");
     MD5Init (&ctx);
 
+    /* Count number of CTM entries matched.  If no matches, ctm skips */
+    /* pass 2 & 3 for this ctm_file. */
+    Pass1Match = 0;
+
     GETFIELD(p,' ');				/* CTM_BEGIN */
     if(strcmp(p,"CTM_BEGIN")) {
 	Fatal("Probably not a CTM-patch at all.");
@@ -55,6 +61,9 @@
     GETFIELDCOPY(Prefix,'\n');				/* <Prefix> */
 
     sscanf(Nbr, "%u", &current);
+    if (expr_list || nexpr_list) {
+	current = 0;	/* Ignore status when we have regular expressions */
+    }
     if(current && current <= applied) {
 	if(Verbose)
 	    fprintf(stderr,"Delta number %u is already applied; ignoring.\n",
@@ -63,9 +72,11 @@
     }
 
     for(;;) {
- -	if(md5)		{Free(md5), md5 = 0;}
- -	if(trash)	{Free(trash), trash = 0;}
+	Delete(md5);
+	Delete(name);
+	Delete(trash);
 	cnt = -1;
+	nomatch = 0;
 
 	GETFIELD(p,' ');			/* CTM_something */
 
@@ -92,31 +103,66 @@
 		sep = ' ';
 	    else
 		sep = '\n';
- -	if(Verbose > 5)
- -	    fprintf(stderr," %x(%d)",sp->List[i],sep);
+	    if(Verbose > 5)
+		fprintf(stderr," %x(%d)",sp->List[i],sep);
 
 	    switch (j & CTM_F_MASK) {
 		case CTM_F_Name: /* XXX check for garbage and .. */
- -		    GETFIELD(p,sep);
- -		    j = strlen(p);
- -		    if(p[j-1] == '/' && !slashwarn)  {
+		    GETFIELDCOPY(name,sep);
+		    j = strlen(name);
+		    if(name[j-1] == '/' && !slashwarn)  {
 			fprintf(stderr,"Warning: contains trailing slash\n");
 			slashwarn++;
 		    }
- -		    if (p[0] == '/') {
+		    if (name[0] == '/') {
 			Fatal("Absolute paths are illegal.");
 			return Exit_Mess;
 		    }
+		    q = name;
 		    for (;;) {
- -			if (p[0] == '.' && p[1] == '.')
- -			    if (p[2] == '/' || p[2] == '\0') {
+			if (q[0] == '.' && q[1] == '.')
+			    if (q[2] == '/' || q[2] == '\0') {
 				Fatal("Paths containing '..' are illegal.");
 				return Exit_Mess;
 			    }
- -			if ((p = strchr(p, '/')) == NULL)
+			if ((q = strchr(q, '/')) == NULL)
 			    break;
- -			p++;
+			q++;
+		    }
+
+		    /* Skip removes... */
+		    if (KeepIt &&
+		      (!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR"))) {
+			nomatch = 1;
+			break;
+		    }
+
+		    /* Only need to check things that match regular expr's */
+
+		    if (expr_list || nexpr_list) {
+			struct CTM_expr *expr;
+
+			for (expr = expr_list; expr; expr = expr->next) {
+			    if (regexec(&expr->cmp_ex, name, 0, 0, 0) == 0) {
+				break;
+			    }
+			}
+			if (expr_list && expr == 0) {
+			    nomatch = 1;
+			    break;
+			}
+			for (expr = nexpr_list; expr; expr = expr->next) {
+			    if (regexec(&expr->cmp_ex, name, 0, 0, 0) != 0) {
+				break;
+			    }
+			}
+			if (nexpr_list && expr == 0) {
+			    nomatch = 1;
+			    break;
+			}
 		    }
+
+		    Pass1Match++;
 		    break;
 		case CTM_F_Uid:
 		    GETFIELD(p,sep);
@@ -182,8 +228,18 @@
 	    }
 	if(Verbose > 5)
 	    putc('\n',stderr);
- -	continue;
+	if (ListIt && !nomatch) {
+	    if (Pass1Match == 1 && strcmp(FileName, "-")) {
+		printf("%s\n", FileName);
+	    }
+	    printf("%s: %s\n", sp->Name, name);
+	}
     }
+
+    Delete(md5);
+    Delete(name);
+    Delete(trash);
+
     q = MD5End (&ctx,md5_1);
     if(Verbose > 2)
 	printf("Expecting Global MD5 <%s>\n",q);
- --- ctm_pass2.c.ctm	Sun May  5 21:52:21 1996
+++ ctm_pass2.c	Sun Jun  9 22:43:58 1996
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  *
- - * $Id: ctm_pass2.c,v 1.8.4.1 1995/09/06 14:20:21 davidg Exp $
+ * $Id: ctm_pass2.c,v 1.12 1996/04/29 21:02:30 phk Exp $
  *
  */
 
@@ -27,6 +27,7 @@
     struct CTM_Syntax *sp;
     struct stat st;
     int ret = 0;
+    int matches = 0;
     char md5_1[33];
 
     if(Verbose>3)
@@ -44,10 +45,11 @@
     /* XXX drop or use ? */
 
     for(;;) {
- -	if(trash)	{Free(trash), trash = 0;}
- -	if(name)	{Free(name), name = 0;}
- -	if(md5)		{Free(md5), md5 = 0;}
+	Delete(trash);
+	Delete(name);
+	Delete(md5);
 	cnt = -1;
+	matches = 1;
 
 	GETFIELD(p,' ');
 
@@ -69,7 +71,39 @@
 
 	    switch (j & CTM_F_MASK) {
 		case CTM_F_Name:
- -		    GETFIELDCOPY(name,sep);
+		    GETNAMECOPY(name,sep,j,0);
+
+		    /* Skip removes... */
+		    if (KeepIt &&
+		      (!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR"))) {
+			matches = 0;
+			break;
+		    }
+
+		    /* Only need to check things that match regular expr's */
+		    if (expr_list || nexpr_list) {
+			struct CTM_expr *expr;
+
+			for (expr = expr_list; expr; expr = expr->next) {
+			    if (regexec(&expr->cmp_ex, name, 0, 0, 0) == 0) {
+				break;
+			    }
+			}
+			if (expr_list && expr == 0) {
+			    matches = 0;
+			    break;
+			}
+			for (expr = nexpr_list; expr; expr = expr->next) {
+			    if (regexec(&expr->cmp_ex, name, 0, 0, 0) != 0) {
+				break;
+			    }
+			}
+			if (nexpr_list && expr == 0) {
+			    matches = 0;
+			    break;
+			}
+		    }
+
 		    /* XXX Check DR DM rec's for parent-dir */
 		    if(j & CTM_Q_Name_New) {
 			/* XXX Check DR FR rec's for item */
@@ -89,6 +123,12 @@
 			    ret |= Exit_NotOK;
 			break;
 		    }
+		    if (SetTime && getuid() && (getuid() != st.st_uid)) {
+			    fprintf(stderr,
+				"  %s: %s not mine, cannot set time.\n",
+				sp->Key,name);
+			    ret |= Exit_NotOK;
+		    }
 		    if (j & CTM_Q_Name_Dir) {
 			if((st.st_mode & S_IFMT) != S_IFDIR) {
 			    fprintf(stderr,
@@ -116,9 +156,11 @@
 		case CTM_F_MD5:
 		    if(!name) WRONG
 		    if(j & CTM_Q_MD5_Before) {
+		        char *tmp;
 			GETFIELD(p,sep);
- -			if((st.st_mode & S_IFMT) == S_IFREG &&
- -			  strcmp(MD5File(name,md5_1),p)) {
+			if(matches && (st.st_mode & S_IFMT) == S_IFREG &&
+			  (tmp = MD5File(name,md5_1)) != NULL &&
+			  strcmp(tmp,p)) {
 			    fprintf(stderr,"  %s: %s md5 mismatch.\n",
 				sp->Key,name);
 			    if(j & CTM_Q_MD5_Force) {
@@ -146,22 +188,26 @@
 		case CTM_F_Bytes:
 		    if(cnt < 0) WRONG
 		    GETDATA(trash,cnt);
- -		    if(!strcmp(sp->Key,"FN")) {
+		    if(matches && !strcmp(sp->Key,"FN")) {
 			p = tempnam(TmpDir,"CTMclient");
 			j = ctm_edit(trash,cnt,name,p);
 			if(j) {
 			    fprintf(stderr,"  %s: %s edit returned %d.\n",
 				sp->Key,name,j);
 			    ret |= j;
+			    unlink(p);
+			    Free(p);
 			    return ret;
 			} else if(strcmp(md5,MD5File(p,md5_1))) {
 			    fprintf(stderr,"  %s: %s edit fails.\n",
 				sp->Key,name);
 			    ret |= Exit_Mess;
+			    unlink(p);
+			    Free(p);
 			    return ret;
 			}
- -			unlink(p);
- -			free(p);
+		        unlink(p);
+			Free(p);
 		    }
 
 		    break;
@@ -169,6 +215,11 @@
 	    }
         }
     }
+
+    Delete(trash);
+    Delete(name);
+    Delete(md5);
+
     q = MD5End (&ctx,md5_1);
     GETFIELD(p,'\n');			/* <MD5> */
     if(strcmp(q,p)) WRONG
- --- ctm_pass3.c.ctm	Sun May  5 20:02:58 1996
+++ ctm_pass3.c	Sun Jun  9 22:26:15 1996
@@ -6,7 +6,7 @@
  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
  * ----------------------------------------------------------------------------
  *
- - * $Id: ctm_pass3.c,v 1.10.4.1 1995/09/06 14:20:22 davidg Exp $
+ * $Id: ctm_pass3.c,v 1.13 1996/04/29 21:02:32 phk Exp $
  *
  */
 
@@ -18,6 +18,17 @@
  */
 
 int
+settime(const char *name, const struct timeval *times)
+{
+	if (SetTime)
+	    if (utimes(name,times)) {
+		fprintf(stderr, "  utimes(): %s: %s\n", name, strerror(errno));
+		return -1;
+	    }
+	return 0;
+}
+
+int
 Pass3(FILE *fd)
 {
     u_char *p,*q,buf[BUFSIZ];
@@ -28,6 +39,7 @@
     FILE *ed=0;
     struct stat st;
     char md5_1[33];
+    struct timeval times[2];
 
     if(Verbose>3)
 	printf("Pass3 -- Applying the CTM-patch\n");
@@ -40,14 +52,67 @@
     GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
     GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
 
+    /*
+     * This would be cleaner if mktime() worked in UTC rather than
+     * local time.
+     */
+    if (SetTime) {
+        struct tm tm;
+        char *tz;
+        char buf[5];
+        int i;
+
+#define SUBSTR(off,len)	strncpy(buf, &TimeStamp[off], len), buf[len] = '\0'
+#define WRONGDATE { fprintf(stderr, " %s failed date validation\n",\
+	TimeStamp); WRONG}
+
+        if (strlen(TimeStamp) != 15 || TimeStamp[14] != 'Z') WRONGDATE
+	for (i = 0; i < 14; i++)
+	    if (!isdigit(TimeStamp[i])) WRONGDATE
+
+        tz = getenv("TZ");
+	if (setenv("TZ", "UTC", 1) < 0) WRONG
+	tzset();
+
+	tm.tm_isdst = tm.tm_gmtoff = 0;
+
+        SUBSTR(0, 4);
+        tm.tm_year = atoi(buf) - 1900;
+        SUBSTR(4, 2);
+        tm.tm_mon = atoi(buf) - 1;
+        if (tm.tm_mon < 0 || tm.tm_mon > 11) WRONGDATE
+        SUBSTR(6, 2);
+        tm.tm_mday = atoi(buf);
+        if (tm.tm_mday < 1 || tm.tm_mday > 31) WRONG;
+        SUBSTR(8, 2);
+        tm.tm_hour = atoi(buf);
+        if (tm.tm_hour > 24) WRONGDATE
+        SUBSTR(10, 2);
+        tm.tm_min = atoi(buf);
+        if (tm.tm_min > 59) WRONGDATE
+        SUBSTR(12, 2);
+        tm.tm_sec = atoi(buf);
+        if (tm.tm_min > 62) WRONGDATE	/* allow leap seconds */
+    
+        times[0].tv_sec = times[1].tv_sec = mktime(&tm);
+        if (times[0].tv_sec == -1) WRONGDATE
+	times[0].tv_usec = times[1].tv_usec = 0;
+
+        if (tz) {
+            if (setenv("TZ", tz, 1) < 0) WRONGDATE
+         } else {
+            unsetenv("TZ");
+        }
+    }
+
     for(;;) {
- -	if(md5)		{Free(md5), md5 = 0;}
- -	if(uid)		{Free(uid), uid = 0;}
- -	if(gid)		{Free(gid), gid = 0;}
- -	if(mode)	{Free(mode), mode = 0;}
- -	if(md5before)	{Free(md5before), md5before = 0;}
- -	if(trash)	{Free(trash), trash = 0;}
- -	if(name)	{Free(name), name = 0;}
+	Delete(md5);
+	Delete(uid);
+	Delete(gid);
+	Delete(mode);
+	Delete(md5before);
+	Delete(trash);
+	Delete(name);
 	cnt = -1;
 
 	GETFIELD(p,' ');
@@ -69,7 +134,7 @@
 		sep = '\n';
 
 	    switch (j & CTM_F_MASK) {
- -		case CTM_F_Name: GETFIELDCOPY(name,sep); break;
+		case CTM_F_Name: GETNAMECOPY(name,sep,j, Verbose); break;
 		case CTM_F_Uid:  GETFIELDCOPY(uid,sep); break;
 		case CTM_F_Gid:  GETFIELDCOPY(gid,sep); break;
 		case CTM_F_Mode: GETFIELDCOPY(mode,sep); break;
@@ -88,6 +153,32 @@
 	j = strlen(name)-1;
 	if(name[j] == '/') name[j] = '\0';
 
+	if (expr_list || nexpr_list) {
+	    struct CTM_expr *expr;
+
+	    for (expr = expr_list; expr; expr = expr->next) {
+		if (regexec(&expr->cmp_ex, name, 0, 0, 0) == 0) {
+		    break;
+		}
+	    }
+	    if (expr_list && expr == 0) {
+		if (Verbose>3)
+		    fprintf(stderr, "skipped %s %s (matched)\n", sp->Key, name);
+		continue;
+	    }
+	    for (expr = nexpr_list; expr; expr = expr->next) {
+		if (regexec(&expr->cmp_ex, name, 0, 0, 0) != 0) {
+		    break;
+		}
+	    }
+	    if (nexpr_list && expr == 0) {
+		if (Verbose>3)
+		    fprintf(stderr, "skipped %s %s (not matched)\n", sp->Key,
+		      name);
+		continue;
+	    }
+	}
+
 	fprintf(stderr,"> %s %s\n",sp->Key,name);
 	if(!strcmp(sp->Key,"FM") || !strcmp(sp->Key, "FS")) {
 	    i = open(name,O_WRONLY|O_CREAT|O_TRUNC,0666);
@@ -105,6 +196,7 @@
 		   sp->Key,name);
 		WRONG
 	    }
+	    if (settime(name,times)) WRONG
 	    continue;
 	}
 	if(!strcmp(sp->Key,"FE")) {
@@ -128,11 +220,12 @@
 		   sp->Key,name);
 		WRONG
 	    }
+	    if (settime(name,times)) WRONG
 	    continue;
 	}
 	if(!strcmp(sp->Key,"FN")) {
 	    strcpy(buf,name);
- -	    strcat(buf,".ctm");
+	    strcat(buf,TMPSUFF);
 	    i = ctm_edit(trash,cnt,name,buf);
 	    if(i) {
 		fprintf(stderr," %s %s Edit failed with code %d.\n",
@@ -145,6 +238,7 @@
 		    sp->Key,name);
 	        WRONG
 	    }
+	    if (settime(name,times)) WRONG
 	    continue;
 	}
 	if(!strcmp(sp->Key,"DM")) {
@@ -156,10 +250,15 @@
 		fprintf(stderr,"<%s> mkdir failed\n",name);
 		WRONG
 	    }
+	    if (settime(name,times)) WRONG
 	    continue;
 	}
 	if(!strcmp(sp->Key,"FR")) {
- -	    if (0 != unlink(name)) {
+	    if (KeepIt) {
+		if (Verbose > 1) {
+		    fprintf(stderr, "<%s> kept\n", name);
+		}
+	    } else if (0 != unlink(name)) {
 		fprintf(stderr,"<%s> unlink failed\n",name);
 		if (!Force)
 		    WRONG
@@ -171,12 +270,27 @@
 	     * We cannot use rmdir() because we do not get the directories
 	     * in '-depth' order (cvs-cur.0018.gz for examples)
 	     */
- -	    sprintf(buf,"rm -rf %s",name);
- -	    system(buf);
+	    if (KeepIt) {
+		if (Verbose > 1) {
+		    fprintf(stderr, "<%s> kept\n", name);
+		}
+	    } else {
+		sprintf(buf,"rm -rf %s",name);
+		system(buf);
+	    }
 	    continue;
 	}
 	WRONG
     }
+
+    Delete(md5);
+    Delete(uid);
+    Delete(gid);
+    Delete(mode);
+    Delete(md5before);
+    Delete(trash);
+    Delete(name);
+
     q = MD5End (&ctx,md5_1);
     GETFIELD(p,'\n');
     if(strcmp(q,p)) WRONG
- --- ctm_syntax.c.ctm	Sun Jun  9 17:11:42 1996
+++ ctm_syntax.c	Sun Jun  9 17:14:22 1996
@@ -56,12 +56,12 @@
     { Name|Dir, 0 };
 
 struct CTM_Syntax Syntax[] = {
- -    { "FM", ctmFM },
- -    { "FS", ctmFS },
- -    { "FE", ctmFE },
- -    { "FN", ctmFE },
- -    { "FR", ctmFR },
- -    { "AS", ctmAS },
- -    { "DM", ctmDM },
- -    { "DR", ctmDR },
+    { "FM", "create", ctmFM },
+    { "FS", "replace", ctmFS },
+    { "FE", "edit", ctmFE },
+    { "FN", "modify", ctmFE },
+    { "FR", "remove", ctmFR },
+    { "AS", "change", ctmAS },
+    { "DM", "mkdir", ctmDM },
+    { "DR", "rmdir", ctmDR },
     { 0, 0} };

------- End of Forwarded Message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1974.834420935>