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 * ----------------------------------------------------------------------------
9 * $FreeBSD: src/usr.sbin/ctm/ctm/ctm_pass3.c,v 1.19 1999/08/28 01:16:00 peter Exp $
10 * $DragonFly: src/usr.sbin/ctm/ctm/Attic/ctm_pass3.c,v 1.2 2003/06/17 04:29:53 dillon Exp $
17 /*---------------------------------------------------------------------------*/
18 /* Pass3 -- Validate the incoming CTM-file.
22 settime(const char *name, const struct timeval *times)
25 if (utimes(name,times)) {
26 warn("utimes(): %s", name);
35 u_char *p,*q,buf[BUFSIZ];
38 u_char *md5=0,*md5before=0,*trash=0,*name=0,*uid=0,*gid=0,*mode=0;
39 struct CTM_Syntax *sp;
44 struct timeval times[2];
45 struct CTM_Filter *filter = NULL;
47 printf("Pass3 -- Applying the CTM-patch\n");
50 GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG
51 GETFIELD(p,' '); if(strcmp(Version,p)) WRONG
52 GETFIELD(p,' '); if(strcmp(Name,p)) WRONG
53 GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG
54 GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG
55 GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG
58 * This would be cleaner if mktime() worked in UTC rather than
67 #define SUBSTR(off,len) strncpy(buf, &TimeStamp[off], len), buf[len] = '\0'
68 #define WRONGDATE { fprintf(stderr, " %s failed date validation\n",\
71 if (strlen(TimeStamp) != 15 || TimeStamp[14] != 'Z') WRONGDATE
72 for (i = 0; i < 14; i++)
73 if (!isdigit(TimeStamp[i])) WRONGDATE
76 if (setenv("TZ", "UTC", 1) < 0) WRONG
79 tm.tm_isdst = tm.tm_gmtoff = 0;
82 tm.tm_year = atoi(buf) - 1900;
84 tm.tm_mon = atoi(buf) - 1;
85 if (tm.tm_mon < 0 || tm.tm_mon > 11) WRONGDATE
87 tm.tm_mday = atoi(buf);
88 if (tm.tm_mday < 1 || tm.tm_mday > 31) WRONG;
90 tm.tm_hour = atoi(buf);
91 if (tm.tm_hour > 24) WRONGDATE
93 tm.tm_min = atoi(buf);
94 if (tm.tm_min > 59) WRONGDATE
96 tm.tm_sec = atoi(buf);
97 if (tm.tm_min > 62) WRONGDATE /* allow leap seconds */
99 times[0].tv_sec = times[1].tv_sec = mktime(&tm);
100 if (times[0].tv_sec == -1) WRONGDATE
101 times[0].tv_usec = times[1].tv_usec = 0;
104 if (setenv("TZ", tz, 1) < 0) WRONGDATE
122 if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG
124 if(!strcmp(p+3,"_END"))
127 for(sp=Syntax;sp->Key;sp++)
128 if(!strcmp(p+3,sp->Key))
132 for(i=0;(j = sp->List[i]);i++) {
133 if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes)
138 switch (j & CTM_F_MASK) {
139 case CTM_F_Name: GETNAMECOPY(name,sep,j, Verbose); break;
140 case CTM_F_Uid: GETFIELDCOPY(uid,sep); break;
141 case CTM_F_Gid: GETFIELDCOPY(gid,sep); break;
142 case CTM_F_Mode: GETFIELDCOPY(mode,sep); break;
144 if(j & CTM_Q_MD5_Before)
145 GETFIELDCOPY(md5before,sep);
147 GETFIELDCOPY(md5,sep);
149 case CTM_F_Count: GETBYTECNT(cnt,sep); break;
150 case CTM_F_Bytes: GETDATA(trash,cnt); break;
154 /* XXX This should go away. Disallow trailing '/' */
156 if(name[j] == '/') name[j] = '\0';
159 * If a filter list is specified, run thru the filter list and
160 * match `name' against filters. If the name matches, set the
161 * required action to that specified in the filter.
162 * The default action if no filterlist is given is to match
166 match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE);
167 for (filter = FilterList; filter; filter = filter->Next) {
168 if (0 == regexec(&filter->CompiledRegex, name,
170 match = filter->Action;
174 if (CTM_FILTER_DISABLE == match) /* skip file if disabled */
178 fprintf(stderr,"> %s %s\n",sp->Key,name);
179 if(!strcmp(sp->Key,"FM") || !strcmp(sp->Key, "FS")) {
180 i = open(name,O_WRONLY|O_CREAT|O_TRUNC,0666);
185 if(cnt != write(i,trash,cnt)) {
190 if(strcmp(md5,MD5File(name,md5_1))) {
191 fprintf(stderr," %s %s MD5 didn't come out right\n",
195 if (settime(name,times)) WRONG
198 if(!strcmp(sp->Key,"FE")) {
199 ed = popen("ed","w");
203 fprintf(ed,"e %s\n",name);
204 if(cnt != fwrite(trash,1,cnt,ed)) {
209 fprintf(ed,"w %s\n",name);
214 if(strcmp(md5,MD5File(name,md5_1))) {
215 fprintf(stderr," %s %s MD5 didn't come out right\n",
219 if (settime(name,times)) WRONG
222 if(!strcmp(sp->Key,"FN")) {
225 i = ctm_edit(trash,cnt,name,buf);
227 fprintf(stderr," %s %s Edit failed with code %d.\n",
231 if(strcmp(md5,MD5File(buf,md5_1))) {
232 fprintf(stderr," %s %s Edit failed MD5 check.\n",
236 if (rename(buf,name) == -1)
238 if (settime(name,times)) WRONG
241 if(!strcmp(sp->Key,"DM")) {
242 if(0 > mkdir(name,0777)) {
243 sprintf(buf,"mkdir -p %s",name);
246 if(0 > stat(name,&st) || ((st.st_mode & S_IFMT) != S_IFDIR)) {
247 fprintf(stderr,"<%s> mkdir failed\n",name);
250 if (settime(name,times)) WRONG
253 if(!strcmp(sp->Key,"FR")) {
256 printf("<%s> not removed\n", name);
258 else if (0 != unlink(name)) {
259 fprintf(stderr,"<%s> unlink failed\n",name);
265 if(!strcmp(sp->Key,"DR")) {
267 * We cannot use rmdir() because we do not get the directories
268 * in '-depth' order (cvs-cur.0018.gz for examples)
272 printf("<%s> not removed\n", name);
275 sprintf(buf,"rm -rf %s",name);
291 q = MD5End (&ctx,md5_1);
293 if(strcmp(q,p)) WRONG
294 if (-1 != getc(fd)) WRONG