Some new options, useful for restoring single files or subtrees from the

deltas.

Submitted by:	A JOSEPH KOSHY <koshy@fakir.india.hp.com>
This commit is contained in:
Poul-Henning Kamp 1996-08-30 10:21:00 +00:00
parent e7d24931fe
commit d09e8179fa
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=17946
9 changed files with 562 additions and 83 deletions

View File

@ -6,13 +6,13 @@
# this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
# ----------------------------------------------------------------------------
#
# $Id: Makefile,v 1.8 1995/03/25 18:14:22 joerg Exp $
# $Id: Makefile,v 1.9 1995/07/12 18:35:22 bde Exp $
#
PROG= ctm
NOTYET= ctm_ed.c
SRCS= ctm.c ctm_input.c ctm_pass1.c ctm_pass2.c ctm_pass3.c \
ctm_syntax.c ctm_ed.c
ctm_passb.c ctm_syntax.c ctm_ed.c
LDADD+= -lmd
DPADD+= ${LIBMD}
MAN1= ctm.1

View File

@ -10,7 +10,7 @@
.\"
.\" CTM and ctm(1) by <phk@login.dknet.dk>
.\"
.\" $Id: ctm.1,v 1.6 1996/05/27 22:46:21 wosch Exp $
.\" $Id: ctm.1,v 1.7 1996/07/24 21:36:48 phk Exp $
.\"
.Dd Mar 25, 1995
.Os
@ -20,11 +20,15 @@
.Nd source code mirror program
.Sh SYNOPSIS
.Nm ctm
.Op Fl cFpPquv
.Op Fl cFklquv
.Op Fl b Ar basedir
.Op Fl B Ar backup-file
.Op Fl e Ar include-regex
.Op Fl t Ar tar-command
.Op Fl T Ar tmpdir
.Op Fl V Ar level
.Ar file Op ...
.Op Fl x Ar exclude-regex
.Ar file...
.Sh DESCRIPTION
.Nm Ctm
was originally
@ -55,7 +59,7 @@ The
command runs in a number of passes. It will process the entire
input file in each pass, before commencing with the next pass.
Before working one a file
Before working on a file
.Ar name
.Nm ctm
first checks for the existence of the file
@ -64,17 +68,45 @@ If this file exists,
.Nm ctm
works on it instead.
Pass 1 will validate that the input file is OK. The syntax, the data
Pass 1 will verify that the input file is OK. 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.
If a
.Ar backup-file
had been specified using the
.Fl B
option, all files that would be modified by this
.Nm ctm
invocation are backed up
to this file using the archiver command specified by the
.Fl t
option. The default archiver command is
.Nm "tar -rf %s -T -" .
Pass 3 will actually apply the delta.
The list of files that would be modified by
.Nm ctm
is subject to filtering regular expressions specified
using the
.Fl e
and
.Fl x
options.
The
.Fl e
and
.Fl x
options are applied in order of appearance on the command line. The last
filter that matched a given file name determines whether the file would be
operated on or left alone by
.Nm ctm .
.Nm Ctm
will extract the file hierarchy below its working directory. Absolute
@ -91,23 +123,76 @@ are explicitly prohibited as a security measure.
.It Fl b Ar basedir
Prepend the path
.Ar basedir
on every filename.
to every filename.
.It Fl B Ar backup-file
Backup all files that would be modified by this CTM run to
.Ar backup-file .
If any filters are specified using the
.Fl e
and
.Fl x
options, then the final set of files backed up are those that would be
modified by CTM after the filters are applied.
.It Fl c
Check it out, don't do anything.
.It Fl e Ar regular_expression
Match each name in the CTM file against
.Ar regular_expression ,
and if it matches process the file, otherwise leave it alone. There may be
any number of these options. Use of this option disables the
.Pa .ctm_status
sequence number checks. For example, the expression
.Ic ^usr.sbin/ctm
for example, will select the
.Nm usr.sbin/ctm
source directory and all pathnames under it.
Pathnames can be disabled from being considered by CTM using the
.Fl x
option.
.It Fl F
Force.
.It Fl p
Less paranoid.
.It Fl k
Keep files and directories and don't remove them even if the CTM file
specifies they are to be removed. If the
.Fl B
option is specified, these files and directories will not be backed up.
.It Fl l
List files that would be modified by this invocation of CTM and the
actions that would be performed on them. Use of the
.Fl l
option disables the
.Pa .ctm_status
checks and integrity checks on the source tree being operated on. The
.Fl l
option can be combined with the
.Fl e
and
.Fl x
options to determine which files would be modified by the given set of
command line options.
.It Fl P
Paranoid.
.It Fl q
Tell us less.
.It Fl t Ar tar-command
Use
.Ar tar-command
instead of the default archiver
.Nm tar .
This option takes effect only if a backup file had been specified using the
.Fl B
option. A %s in the tar command will be replaced by the name of the backup
file.
.It Fl T Ar tmpdir
Put temporary files under
.Ar tmpdir .
@ -124,6 +209,18 @@ Tell us more.
.Ar Level
is the level of verbosity.
.It Fl x Ar regular_expression
Match each name in the CTM file against
.Ar regular_expression
and if it matches, leave the file alone. There may be any number of these
options. Use of this option disables the
.Pa .ctm_status
sequence number checks.
Pathnames can be selected for CTM's consideration using the
.Fl e
option.
.El
.Sh ENVIRONMENT
@ -144,6 +241,14 @@ contains the sequence number of the last CTM delta applied. Changing
or removing this file will greatly confuse
.Nm ctm .
Using the
.Fl e
and
.Fl x
options can update a partial subset of the source tree and causes sources
to be in an inconsistent state. It is assumed that you know what you are
doing when you use these options.
.Sh EXAMPLES
.Bd -literal
@ -153,14 +258,20 @@ cd ~cvs
.Ed
To extract and patch all sources under `lib'
.Bd -literal
cd ~/lib-srcs
/usr/sbin/ctm -e '^lib' ~ctm/src-cur*
.Ed
.Sh DIAGNOSTICS
Numerous messages, hopefully self-explaining. The
Numerous messages, hopefully self-explanatory. The
.Dq noise level
can be adjusted with the
.Fl q
and
.Fl q ,
.Fl v
and
.Fl V
options.
.Sh SEE ALSO
@ -169,7 +280,7 @@ options.
.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

View File

@ -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.12 1996/02/05 16:06:46 phk 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 <file> Backup to tar-file.
* -d <int> Debug TBD.
* -m <mail-addr> Email me instead.
* -r <name> Reconstruct file.
@ -22,16 +21,21 @@
*
* Options we have:
* -b <dir> Base-dir
* -B <file> Backup to tar-file.
* -t Tar command (default as in TARCMD).
* -c Check it out, don't do anything.
* -F Force
* -p Less paranoid.
* -P Paranoid.
* -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
* -k Keep files and directories that would have been removed.
* -l List actions.
*
* Options we don't actually use:
* -p Less paranoid.
* -P Paranoid.
*/
#define EXTERN /* */
@ -44,35 +48,82 @@ extern int Proc(char *, unsigned applied);
int
main(int argc, char **argv)
{
int stat=0;
int stat=0, err=0;
int c;
extern int optopt,optind;
extern char * optarg;
unsigned applied = 0;
FILE *statfile;
struct CTM_Filter *nfilter = NULL; /* new filter */
u_char * basedir;
basedir = NULL;
Verbose = 1;
Paranoid = 1;
SetTime = 0;
KeepIt = 0;
ListIt = 0;
BackupFile = NULL;
TarCmd = TARCMD;
LastFilter = FilterList = NULL;
setbuf(stderr,0);
setbuf(stdout,0);
while((c=getopt(argc,argv,"ab:B:cd:Fm:pPqr:R:T:uV:v")) != -1) {
while((c=getopt(argc,argv,"ab:B:cd:e:Fklm:pPqr:R:t:T:uV:vx:")) != -1) {
switch (c) {
case 'b': basedir = optarg; break; /* Base Directory */
case 'B': BackupFile = optarg; break;
case 'c': CheckIt++; break; /* Only check it */
case 'F': Force = 1; break;
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 't': TarCmd = optarg; break; /* archiver command */
case 'T': TmpDir = optarg; break; /* set temporary directory */
case 'u': SetTime++; break; /* Set timestamp on files */
case 'v': Verbose++; break; /* Verbose */
case 'V': sscanf(optarg,"%d", &c); /* Verbose */
Verbose += c;
break;
case 'e': /* filter expressions */
case 'x':
if (NULL == (nfilter = Malloc(sizeof(struct CTM_Filter)))) {
fprintf(stderr,
"Out of memory for expressions: \"%s\"\n",
optarg);
stat++;
break;
}
(void) memset(nfilter, 0, sizeof(struct CTM_Filter));
if (0 != (err =
regcomp(&nfilter->CompiledRegex, optarg, REG_NOSUB))) {
char errmsg[128];
regerror(err, &nfilter->CompiledRegex, errmsg,
sizeof(errmsg));
fprintf(stderr, "Regular expression: \"%s\"\n", errmsg);
stat++;
break;
}
/* note whether the filter enables or disables on match */
nfilter->Action =
(('e' == c) ? CTM_FILTER_ENABLE : CTM_FILTER_DISABLE);
/* link in the expression into the list */
nfilter->Next = NULL;
if (NULL == FilterList) {
LastFilter = FilterList = nfilter; /* init head and tail */
} else { /* place at tail */
LastFilter->Next = nfilter;
LastFilter = nfilter;
}
break;
case ':':
fprintf(stderr,"Option '%c' requires an argument.\n",optopt);
stat++;
@ -110,26 +161,37 @@ main(int argc, char **argv)
}
strcat(Buffer, CTM_STATUS);
if((statfile = fopen(Buffer, "r")) == NULL)
fprintf(stderr, "Warning: %s not found.\n", Buffer);
else {
fscanf(statfile, "%*s %u", &applied);
fclose(statfile);
}
if(ListIt)
applied = 0;
else
if((statfile = fopen(Buffer, "r")) == NULL) {
if (Verbose > 0)
fprintf(stderr, "Warning: %s not found.\n", Buffer);
} else {
fscanf(statfile, "%*s %u", &applied);
fclose(statfile);
}
if(!argc)
stat |= Proc("-", applied);
while(argc-- && stat == Exit_Done) {
stat |= Proc(*argv++, applied);
stat &= ~Exit_Version;
stat &= ~(Exit_Version | Exit_NoMatch);
}
if(stat == Exit_Done)
stat = Exit_OK;
if(Verbose)
if(Verbose > 0)
fprintf(stderr,"Exit(%d)\n",stat);
if (FilterList)
for (nfilter = FilterList; nfilter; ) {
struct CTM_Filter *tmp = nfilter->Next;
Free(nfilter);
nfilter = tmp;
}
return stat;
}
@ -176,7 +238,8 @@ Proc(char *filename, unsigned applied)
return Exit_Broke;
}
unlink(fn);
fprintf(stderr,"Writing tmp-file \"%s\"\n",fn);
if (Verbose > 0)
fprintf(stderr,"Writing tmp-file \"%s\"\n",fn);
while(EOF != (i=getc(f)))
if(EOF == putc(i,f2)) {
fclose(f2);
@ -192,6 +255,11 @@ Proc(char *filename, unsigned applied)
if((i=Pass1(f, applied)))
goto exit_and_close;
if(ListIt) {
i = Exit_Done;
goto exit_and_close;
}
if(!p) {
rewind(f);
} else {
@ -216,10 +284,25 @@ Proc(char *filename, unsigned applied)
}
if(CheckIt) {
fprintf(stderr,"All checks out ok.\n");
if (Verbose > 0)
fprintf(stderr,"All checks out ok.\n");
i = Exit_Done;
goto exit_and_close;
}
/* backup files if requested */
if(BackupFile) {
i = PassB(f);
if(!p) {
rewind(f);
} else {
pclose(f);
f = popen(p,"r");
if(!f) { perror(p); return Exit_Broke; }
}
}
i=Pass3(f);
@ -232,6 +315,8 @@ Proc(char *filename, unsigned applied)
if(i)
return i;
fprintf(stderr,"All done ok\n");
if (Verbose > 0)
fprintf(stderr,"All done ok\n");
return Exit_Done;
}

View File

@ -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.8 1996/02/05 16:06:47 phk Exp $
* $Id: ctm.h,v 1.9 1996/04/29 21:02:29 phk Exp $
*
*/
@ -22,12 +22,14 @@
#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"
#define TARCMD "tar -rf %s -T -"
/* The fields... */
#define CTM_F_MASK 0xff
@ -51,12 +53,21 @@
#define CTM_Q_MD5_Force 0x0800
struct CTM_Syntax {
char *Key;
int *List;
char *Key; /* CTM key for operation */
int *List; /* List of operations */
};
extern struct CTM_Syntax Syntax[];
struct CTM_Filter {
struct CTM_Filter *Next; /* next filter in the list */
int Action; /* enable or disable */
regex_t CompiledRegex; /* compiled regex */
};
#define CTM_FILTER_DISABLE 0
#define CTM_FILTER_ENABLE 1
#define Malloc malloc
#define Free free
#define Delete(foo) if (!foo) ; else {Free(foo); foo = 0; }
@ -74,6 +85,8 @@ EXTERN u_char *FileName;
EXTERN u_char *TmpDir;
EXTERN u_char *CatPtr;
EXTERN u_char *Buffer;
EXTERN u_char *BackupFile;
EXTERN u_char *TarCmd;
/*
* Paranoid -- Just in case they should be after us...
@ -106,8 +119,12 @@ EXTERN int Verbose;
EXTERN int Exit;
EXTERN int Force;
EXTERN int CheckIt;
EXTERN int KeepIt;
EXTERN int ListIt;
EXTERN int SetTime;
EXTERN struct timeval Times[2];
EXTERN struct CTM_Filter *FilterList;
EXTERN struct CTM_Filter *LastFilter;
#define Exit_OK 0
#define Exit_Garbage 1
@ -118,6 +135,7 @@ EXTERN struct timeval Times[2];
#define Exit_Mess 32
#define Exit_Done 64
#define Exit_Version 128
#define Exit_NoMatch 256
void Fatal_(int ln, char *fn, char *kind);
#define Fatal(foo) Fatal_(__LINE__,__FILE__,foo)
@ -139,6 +157,7 @@ u_char * Fdata(FILE *fd, int u_chars, MD5_CTX *ctx);
int Pass1(FILE *fd, unsigned applied);
int Pass2(FILE *fd);
int PassB(FILE *fd);
int Pass3(FILE *fd);
int ctm_edit(u_char *script, int length, char *filein, char *fileout);

View File

@ -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.11 1995/07/12 09:16:08 phk Exp $
* $Id: ctm_pass1.c,v 1.12 1996/02/05 16:06:50 phk Exp $
*
*/
@ -23,9 +23,9 @@ Pass1(FILE *fd, unsigned applied)
u_char *p,*q;
MD5_CTX ctx;
int i,j,sep,cnt;
u_char *md5=0,*trash=0;
u_char *md5=0,*name=0,*trash=0;
struct CTM_Syntax *sp;
int slashwarn=0;
int slashwarn=0, match=0, total_matches=0;
unsigned current;
char md5_1[33];
@ -55,8 +55,10 @@ Pass1(FILE *fd, unsigned applied)
GETFIELDCOPY(Prefix,'\n'); /* <Prefix> */
sscanf(Nbr, "%u", &current);
if (FilterList || ListIt)
current = 0; /* ignore if -l or if filters are present */
if(current && current <= applied) {
if(Verbose)
if(Verbose > 0)
fprintf(stderr,"Delta number %u is already applied; ignoring.\n",
current);
return Exit_Version;
@ -64,8 +66,14 @@ Pass1(FILE *fd, unsigned applied)
for(;;) {
Delete(md5);
Delete(name);
Delete(trash);
cnt = -1;
/* if a filter list is defined we assume that all pathnames require
an action opposite to that requested by the first filter in the
list.
If no filter is defined, all pathnames are assumed to match. */
match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
GETFIELD(p,' '); /* CTM_something */
@ -92,31 +100,61 @@ Pass1(FILE *fd, unsigned applied)
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++;
}
/* if we have been asked to `keep' files then skip
removes; i.e. we don't match these entries at
all. */
if (KeepIt &&
(!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR"))) {
match = CTM_FILTER_DISABLE;
break;
}
/* If filter expression have been defined, match the
path name against the expression list. */
if (FilterList) {
struct CTM_Filter *filter;
for (filter = FilterList; filter;
filter = filter->Next) {
if (0 == regexec(&filter->CompiledRegex, name,
0, 0, 0))
/* if the name matches, adopt the
action */
match = filter->Action;
}
}
/* Add up the total number of matches */
total_matches += match;
break;
case CTM_F_Uid:
GETFIELD(p,sep);
@ -170,22 +208,22 @@ Pass1(FILE *fd, unsigned applied)
p = MD5Data(trash,cnt,md5_1);
if(md5 && strcmp(md5,p)) {
Fatal("Internal MD5 failed.");
return 1;
return Exit_Garbage;
default:
fprintf(stderr,"List = 0x%x\n",j);
Fatal("List had garbage.");
return 1;
return Exit_Garbage;
}
}
}
}
if(Verbose > 5)
putc('\n',stderr);
continue;
if(ListIt && match)
printf("> %s %s\n", sp->Key, name);
}
Delete(md5);
Delete(name);
Delete(trash);
q = MD5End (&ctx,md5_1);
@ -198,7 +236,7 @@ Pass1(FILE *fd, unsigned applied)
Fatal("MD5 sum doesn't match.");
fprintf(stderr,"\tI have:<%s>\n",q);
fprintf(stderr,"\tShould have been:<%s>\n",p);
return 1;
return Exit_Garbage;
}
if (-1 != getc(fd)) {
if(!Force) {
@ -206,5 +244,7 @@ Pass1(FILE *fd, unsigned applied)
return 16;
}
}
return 0;
if ((Verbose > 1) && (0 == total_matches))
printf("No matches in \"%s\"\n", FileName);
return (total_matches ? Exit_OK : Exit_NoMatch);
}

View File

@ -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.11 1996/02/05 16:06:52 phk Exp $
* $Id: ctm_pass2.c,v 1.12 1996/04/29 21:02:30 phk Exp $
*
*/
@ -27,7 +27,10 @@ Pass2(FILE *fd)
struct CTM_Syntax *sp;
struct stat st;
int ret = 0;
int match = 0;
char md5_1[33];
struct CTM_Filter *filter;
FILE *ed = NULL;
if(Verbose>3)
printf("Pass2 -- Checking if CTM-patch will apply\n");
@ -49,6 +52,12 @@ Pass2(FILE *fd)
Delete(md5);
cnt = -1;
/* if a filter list was specified, check file name against
the filters specified
if no filter was given operate on all files. */
match = (FilterList ?
!(FilterList->Action) : CTM_FILTER_ENABLE);
GETFIELD(p,' ');
if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
@ -70,6 +79,22 @@ Pass2(FILE *fd)
switch (j & CTM_F_MASK) {
case CTM_F_Name:
GETNAMECOPY(name,sep,j,0);
/* If `keep' was specified, we won't remove any files,
so don't check if the file exists */
if (KeepIt &&
(!strcmp(sp->Key,"FR") || !strcmp(sp->Key,"DR"))) {
match = CTM_FILTER_DISABLE;
break;
}
for (filter = FilterList; filter; filter = filter->Next) if (0 == regexec(&filter->CompiledRegex, name,
0, 0, 0)) {
match = filter->Action;
}
if (CTM_FILTER_DISABLE == match)
break; /* should ignore this file */
/* XXX Check DR DM rec's for parent-dir */
if(j & CTM_Q_Name_New) {
/* XXX Check DR FR rec's for item */
@ -124,7 +149,7 @@ Pass2(FILE *fd)
if(j & CTM_Q_MD5_Before) {
char *tmp;
GETFIELD(p,sep);
if((st.st_mode & S_IFMT) == S_IFREG &&
if(match && (st.st_mode & S_IFMT) == S_IFREG &&
(tmp = MD5File(name,md5_1)) != NULL &&
strcmp(tmp,p)) {
fprintf(stderr," %s: %s md5 mismatch.\n",
@ -154,6 +179,8 @@ Pass2(FILE *fd)
case CTM_F_Bytes:
if(cnt < 0) WRONG
GETDATA(trash,cnt);
if (!match)
break;
if(!strcmp(sp->Key,"FN")) {
p = tempnam(TmpDir,"CTMclient");
j = ctm_edit(trash,cnt,name,p);
@ -174,6 +201,30 @@ Pass2(FILE *fd)
}
unlink(p);
Free(p);
} else if (!strcmp(sp->Key,"FE")) {
p = tempnam(TmpDir,"CTMclient");
ed = popen("ed","w");
if (!ed) {
WRONG
}
fprintf(ed,"e %s\n", name);
if (cnt != fwrite(trash,1,cnt,ed)) {
perror(name);
pclose(ed);
WRONG
}
fprintf(ed,"w %s\n",p);
if (pclose(ed)) {
perror(p);
WRONG
}
if(strcmp(md5,MD5File(p,md5_1))) {
fprintf(stderr,"%s %s MD5 didn't come out right\n",
sp->Key, name);
WRONG
}
unlink(p);
Free(p);
}
break;

View File

@ -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.12 1996/02/05 16:06:53 phk Exp $
* $Id: ctm_pass3.c,v 1.13 1996/04/29 21:02:32 phk Exp $
*
*/
@ -39,8 +39,9 @@ Pass3(FILE *fd)
FILE *ed=0;
struct stat st;
char md5_1[33];
int match=0;
struct timeval times[2];
struct CTM_Filter *filter = NULL;
if(Verbose>3)
printf("Pass3 -- Applying the CTM-patch\n");
MD5Init (&ctx);
@ -153,7 +154,27 @@ Pass3(FILE *fd)
j = strlen(name)-1;
if(name[j] == '/') name[j] = '\0';
fprintf(stderr,"> %s %s\n",sp->Key,name);
/*
* If a filter list is specified, run thru the filter list and
* match `name' against filters. If the name matches, set the
* required action to that specified in the filter.
* The default action if no filterlist is given is to match
* everything.
*/
match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
for (filter = FilterList; filter; filter = filter->Next) {
if (0 == regexec(&filter->CompiledRegex, name,
0, 0, 0)) {
match = filter->Action;
}
}
if (CTM_FILTER_DISABLE == match) /* skip file if disabled */
continue;
if (Verbose > 0)
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);
if(i < 0) {
@ -228,7 +249,11 @@ Pass3(FILE *fd)
continue;
}
if(!strcmp(sp->Key,"FR")) {
if (0 != unlink(name)) {
if (KeepIt) {
if (Verbose > 1)
printf("<%s> not removed\n", name);
}
else if (0 != unlink(name)) {
fprintf(stderr,"<%s> unlink failed\n",name);
if (!Force)
WRONG
@ -240,8 +265,14 @@ Pass3(FILE *fd)
* 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) {
printf("<%s> not removed\n", name);
}
} else {
sprintf(buf,"rm -rf %s",name);
system(buf);
}
continue;
}
WRONG

View File

@ -0,0 +1,142 @@
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <koshy@india.hp.com> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Joseph Koshy
* ----------------------------------------------------------------------------
*
* $Id$
*
*/
#include "ctm.h"
#define BADREAD 32
/*---------------------------------------------------------------------------*/
/* PassB -- Backup modified files.
*/
int
PassB(FILE *fd)
{
u_char *p,*q;
MD5_CTX ctx;
int i,j,sep,cnt;
u_char *md5=0,*md5before=0,*trash=0,*name=0,*uid=0,*gid=0,*mode=0;
struct CTM_Syntax *sp;
FILE *b = 0; /* backup command */
u_char buf[BUFSIZ];
char md5_1[33];
int ret = 0;
int match = 0;
struct CTM_Filter *filter = NULL;
if(Verbose>3)
printf("PassB -- Backing up files which would be changed.\n");
MD5Init (&ctx);
sprintf(buf, TarCmd, BackupFile);
b=popen(buf, "w");
if(!b) { perror(buf); return Exit_Garbage; }
GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
for(;;) {
Delete(md5);
Delete(uid);
Delete(gid);
Delete(mode);
Delete(md5before);
Delete(trash);
Delete(name);
cnt = -1;
GETFIELD(p,' ');
if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
if(!strcmp(p+3,"_END"))
break;
for(sp=Syntax;sp->Key;sp++)
if(!strcmp(p+3,sp->Key))
goto found;
WRONG
found:
for(i=0;(j = sp->List[i]);i++) {
if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
sep = ' ';
else
sep = '\n';
switch (j & CTM_F_MASK) {
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;
case CTM_F_MD5:
if(j & CTM_Q_MD5_Before)
GETFIELDCOPY(md5before,sep);
else
GETFIELDCOPY(md5,sep);
break;
case CTM_F_Count: GETBYTECNT(cnt,sep); break;
case CTM_F_Bytes: GETDATA(trash,cnt); break;
default: WRONG
}
}
/* XXX This should go away. Disallow trailing '/' */
j = strlen(name)-1;
if(name[j] == '/') name[j] = '\0';
if (KeepIt &&
(!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR")))
continue;
/* match the name against the elements of the filter list. The
action associated with the last matched filter determines whether
this file should be ignored or backed up. */
match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
for (filter = FilterList; filter; filter = filter->Next) {
if (0 == regexec(&filter->CompiledRegex, name, 0, 0, 0))
match = filter->Action;
}
if (CTM_FILTER_DISABLE == match)
continue;
if (!strcmp(sp->Key,"FS") || !strcmp(sp->Key,"FN") ||
!strcmp(sp->Key,"AS") || !strcmp(sp->Key,"DR") ||
!strcmp(sp->Key,"FR")) {
/* send name to the archiver for a backup */
cnt = strlen(name);
if (cnt != fwrite(name,1,cnt,b) || EOF == fputc('\n',b)) {
perror(name);
pclose(b);
WRONG;
}
}
}
ret = pclose(b);
Delete(md5);
Delete(uid);
Delete(gid);
Delete(mode);
Delete(md5before);
Delete(trash);
Delete(name);
q = MD5End (&ctx,md5_1);
GETFIELD(p,'\n'); /* <MD5> */
if(strcmp(q,p)) WRONG
if (-1 != getc(fd)) WRONG
return ret;
}

View File

@ -6,7 +6,7 @@
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*
* $Id: ctm_syntax.c,v 1.5 1995/05/30 03:47:28 rgrimes Exp $
* $Id: ctm_syntax.c,v 1.6 1996/02/05 16:06:55 phk Exp $
*
*/
@ -56,12 +56,12 @@ static int ctmDR[] = /* Directory Remove */
{ Name|Dir, 0 };
struct CTM_Syntax Syntax[] = {
{ "FM", ctmFM },
{ "FS", ctmFS },
{ "FE", ctmFE },
{ "FN", ctmFE },
{ "FR", ctmFR },
{ "AS", ctmAS },
{ "DM", ctmDM },
{ "DR", ctmDR },
{ 0, 0} };
{ "FM", ctmFM },
{ "FS", ctmFS },
{ "FE", ctmFE },
{ "FN", ctmFE },
{ "FR", ctmFR },
{ "AS", ctmAS },
{ "DM", ctmDM },
{ "DR", ctmDR },
{ 0, 0} };