1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <koshy@india.hp.com> wrote this file.  As long as you retain this notice you
5 * can do whatever you want with this stuff. If we meet some day, and you think
6 * this stuff is worth it, you can buy me a beer in return.   Joseph Koshy
7 * ----------------------------------------------------------------------------
8 *
9 * $FreeBSD$
10 *
11 */
12
13#include "ctm.h"
14#define BADREAD 32
15
16/*---------------------------------------------------------------------------*/
17/* PassB -- Backup modified files.
18 */
19
20int
21PassB(FILE *fd)
22{
23    u_char *p,*q;
24    MD5_CTX ctx;
25    int i,j,sep,cnt;
26    u_char *md5=0,*md5before=0,*trash=0,*name=0,*uid=0,*gid=0,*mode=0;
27    struct CTM_Syntax *sp;
28    FILE *b = 0;	/* backup command */
29    u_char buf[BUFSIZ];
30    char md5_1[33];
31    int ret = 0;
32    int match = 0;
33    struct CTM_Filter *filter = NULL;
34
35    if(Verbose>3)
36	printf("PassB -- Backing up files which would be changed.\n");
37
38    MD5Init (&ctx);
39    snprintf(buf, sizeof(buf), fmtcheck(TarCmd, TARCMD), BackupFile);
40    b=popen(buf, "w");
41    if(!b) { warn("%s", buf); return Exit_Garbage; }
42
43    GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
44    GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
45    GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
46    GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
47    GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
48    GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
49
50    for(;;) {
51	Delete(md5);
52	Delete(uid);
53	Delete(gid);
54	Delete(mode);
55	Delete(md5before);
56	Delete(trash);
57	Delete(name);
58	cnt = -1;
59
60	GETFIELD(p,' ');
61
62	if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
63
64	if(!strcmp(p+3,"_END"))
65	    break;
66
67	for(sp=Syntax;sp->Key;sp++)
68	    if(!strcmp(p+3,sp->Key))
69		goto found;
70	WRONG
71    found:
72	for(i=0;(j = sp->List[i]);i++) {
73	    if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
74		sep = ' ';
75	    else
76		sep = '\n';
77
78	    switch (j & CTM_F_MASK) {
79		case CTM_F_Name: GETNAMECOPY(name,sep,j, Verbose); break;
80		case CTM_F_Uid:  GETFIELDCOPY(uid,sep); break;
81		case CTM_F_Gid:  GETFIELDCOPY(gid,sep); break;
82		case CTM_F_Mode: GETFIELDCOPY(mode,sep); break;
83		case CTM_F_MD5:
84		    if(j & CTM_Q_MD5_Before)
85			GETFIELDCOPY(md5before,sep);
86		    else
87			GETFIELDCOPY(md5,sep);
88		    break;
89		case CTM_F_Count: GETBYTECNT(cnt,sep); break;
90		case CTM_F_Bytes: GETDATA(trash,cnt); break;
91		default: WRONG
92		}
93	    }
94	/* XXX This should go away.  Disallow trailing '/' */
95	j = strlen(name)-1;
96	if(name[j] == '/') name[j] = '\0';
97
98	if (KeepIt &&
99	    (!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR")))
100	    continue;
101
102	/* match the name against the elements of the filter list.  The
103	   action associated with the last matched filter determines whether
104	   this file should be ignored or backed up. */
105	match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
106	for (filter = FilterList; filter; filter = filter->Next) {
107	    if (0 == regexec(&filter->CompiledRegex, name, 0, 0, 0))
108		match = filter->Action;
109	}
110
111	if (CTM_FILTER_DISABLE == match)
112		continue;
113
114	if (!strcmp(sp->Key,"FS") || !strcmp(sp->Key,"FN") ||
115	    !strcmp(sp->Key,"AS") || !strcmp(sp->Key,"DR") ||
116	    !strcmp(sp->Key,"FR")) {
117	    /* send name to the archiver for a backup */
118	    cnt = strlen(name);
119	    if (cnt != fwrite(name,1,cnt,b) || EOF == fputc('\n',b)) {
120		warn("%s", name);
121		pclose(b);
122		WRONG;
123	    }
124	}
125    }
126
127    ret = pclose(b);
128
129    Delete(md5);
130    Delete(uid);
131    Delete(gid);
132    Delete(mode);
133    Delete(md5before);
134    Delete(trash);
135    Delete(name);
136
137    q = MD5End (&ctx,md5_1);
138    GETFIELD(p,'\n');			/* <MD5> */
139    if(strcmp(q,p)) WRONG
140    if (-1 != getc(fd)) WRONG
141    return ret;
142}
143