ctm_pass3.c revision 2948
1/*
2 * ----------------------------------------------------------------------------
3 * "THE BEER-WARE LICENSE" (Revision 42):
4 * <phk@login.dknet.dk> 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.   Poul-Henning Kamp
7 * ----------------------------------------------------------------------------
8 *
9 * $Id$
10 *
11 */
12
13#include "ctm.h"
14#define BADREAD 32
15
16/*---------------------------------------------------------------------------*/
17/* Pass3 -- Validate the incomming CTM-file.
18 */
19
20int
21Pass3(FILE *fd)
22{
23    u_char *p,*q,buf[BUFSIZ];
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 *ed=0;
29    struct stat st;
30
31    if(Verbose>3)
32	printf("Pass3 -- Applying the CTM-patch\n");
33    MD5Init (&ctx);
34
35    GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
36    GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
37    GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
38    GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
39    GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
40    GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
41
42    for(;;) {
43	if(md5)		{Free(md5), md5 = 0;}
44	if(uid)		{Free(uid), uid = 0;}
45	if(gid)		{Free(gid), gid = 0;}
46	if(mode)	{Free(mode), mode = 0;}
47	if(md5before)	{Free(md5before), md5before = 0;}
48	if(trash)	{Free(trash), trash = 0;}
49	if(name)	{Free(name), name = 0;}
50	cnt = -1;
51
52	GETFIELD(p,' ');
53
54	if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
55
56	if(!strcmp(p+3,"_END"))
57	    break;
58
59	for(sp=Syntax;sp->Key;sp++)
60	    if(!strcmp(p+3,sp->Key))
61		goto found;
62	WRONG
63    found:
64	for(i=0;(j = sp->List[i]);i++) {
65	    if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
66		sep = ' ';
67	    else
68		sep = '\n';
69
70	    switch (j & CTM_F_MASK) {
71		case CTM_F_Name: GETFIELDCOPY(name,sep); break;
72		case CTM_F_Uid:  GETFIELDCOPY(uid,sep); break;
73		case CTM_F_Gid:  GETFIELDCOPY(gid,sep); break;
74		case CTM_F_Mode: GETFIELDCOPY(mode,sep); break;
75		case CTM_F_MD5:
76		    if(j & CTM_Q_MD5_Before)
77			GETFIELDCOPY(md5before,sep);
78		    else
79			GETFIELDCOPY(md5,sep);
80		    break;
81		case CTM_F_Count: GETBYTECNT(cnt,sep); break;
82		case CTM_F_Bytes: GETDATA(trash,cnt); break;
83		default: WRONG
84		}
85	    }
86	/* XXX This should go away.  Disallow trailing '/' */
87	j = strlen(name)-1;
88	if(name[j] == '/') name[j] = '\0';
89
90	fprintf(stderr,"> %s %s\n",sp->Key,name);
91	if(!strcmp(sp->Key,"FM") || !strcmp(sp->Key, "FS")) {
92	    i = open(name,O_WRONLY|O_CREAT|O_TRUNC,0644);
93	    if(i < 0) {
94		perror(name);
95		WRONG
96	    }
97	    if(cnt != write(i,trash,cnt)) {
98		perror(name);
99		WRONG
100	    }
101	    close(i);
102	    if(strcmp(md5,MD5File(name))) {
103		fprintf(stderr,"  %s %s MD5 didn't come out right\n",
104		   sp->Key,name);
105		WRONG
106	    }
107	    continue;
108	}
109	if(!strcmp(sp->Key,"FE")) {
110	    ed = popen("ed -s","w");
111	    if(!ed) {
112		WRONG
113	    }
114	    if(cnt != fwrite(trash,1,cnt,ed)) {
115		perror(name);
116		pclose(ed);
117		WRONG
118	    }
119	    fprintf(ed,"w %s\n",name);
120	    if(pclose(ed)) {
121		perror("ed");
122		WRONG
123	    }
124	    if(strcmp(md5,MD5File(name))) {
125		fprintf(stderr,"  %s %s MD5 didn't come out right\n",
126		   sp->Key,name);
127		WRONG
128	    }
129	    continue;
130	}
131	if(!strcmp(sp->Key,"FN")) {
132	    strcpy(buf,name);
133	    strcat(buf,".ctm");
134	    i = ctm_edit(trash,cnt,name,buf);
135	    if(i) {
136		fprintf(stderr," %s %s Edit failed with code %d.\n",
137		    sp->Key,name,i);
138	        WRONG
139	    }
140	    rename(buf,name);
141	    if(strcmp(md5,MD5File(name))) {
142		fprintf(stderr," %s %s Edit failed MD5 check.\n",
143		    sp->Key,name);
144	        WRONG
145	    }
146	    continue;
147	}
148	if(!strcmp(sp->Key,"DM")) {
149	    if(0 > mkdir(name,0755)) {
150		sprintf(buf,"mkdir -p %s",name);
151		system(buf);
152	    }
153	    if(0 > stat(name,&st) || ((st.st_mode & S_IFMT) != S_IFDIR)) {
154		fprintf(stderr,"<%s> mkdir failed\n",name);
155		WRONG
156	    }
157	    continue;
158	}
159	if(!strcmp(sp->Key,"DR") || !strcmp(sp->Key,"FR")) {
160	    if(0 > unlink(name)) {
161		sprintf(buf,"rm -rf %s",name);
162		system(buf);
163	    }
164	    continue;
165	}
166	WRONG
167    }
168    q = MD5End (&ctx);
169    GETFIELD(p,'\n');
170    if(strcmp(q,p)) WRONG
171    if (-1 != getc(fd)) WRONG
172    return 0;
173}
174