12926Sphk/* 22926Sphk * ---------------------------------------------------------------------------- 32926Sphk * "THE BEER-WARE LICENSE" (Revision 42): 493150Sphk * <phk@FreeBSD.org> wrote this file. As long as you retain this notice you 52926Sphk * can do whatever you want with this stuff. If we meet some day, and you think 62926Sphk * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp 72926Sphk * ---------------------------------------------------------------------------- 82926Sphk * 950479Speter * $FreeBSD$ 102926Sphk * 112926Sphk */ 122926Sphk 132886Sphk#include "ctm.h" 142926Sphk#define BADREAD 32 152886Sphk 162886Sphk/*---------------------------------------------------------------------------*/ 174816Sphk/* Pass3 -- Validate the incoming CTM-file. 182886Sphk */ 192886Sphk 202886Sphkint 2115456Sphksettime(const char *name, const struct timeval *times) 2215456Sphk{ 2315456Sphk if (SetTime) 2415456Sphk if (utimes(name,times)) { 2529526Scharnier warn("utimes(): %s", name); 2615456Sphk return -1; 2715456Sphk } 2815456Sphk return 0; 2915456Sphk} 3015456Sphk 3115456Sphkint 322886SphkPass3(FILE *fd) 332886Sphk{ 342886Sphk u_char *p,*q,buf[BUFSIZ]; 352886Sphk MD5_CTX ctx; 362886Sphk int i,j,sep,cnt; 372886Sphk u_char *md5=0,*md5before=0,*trash=0,*name=0,*uid=0,*gid=0,*mode=0; 382886Sphk struct CTM_Syntax *sp; 392886Sphk FILE *ed=0; 402886Sphk struct stat st; 419491Sphk char md5_1[33]; 4217946Sphk int match=0; 4315456Sphk struct timeval times[2]; 4417946Sphk struct CTM_Filter *filter = NULL; 458857Srgrimes if(Verbose>3) 462886Sphk printf("Pass3 -- Applying the CTM-patch\n"); 472886Sphk MD5Init (&ctx); 482886Sphk 492886Sphk GETFIELD(p,' '); if(strcmp("CTM_BEGIN",p)) WRONG 502886Sphk GETFIELD(p,' '); if(strcmp(Version,p)) WRONG 512886Sphk GETFIELD(p,' '); if(strcmp(Name,p)) WRONG 522886Sphk GETFIELD(p,' '); if(strcmp(Nbr,p)) WRONG 532886Sphk GETFIELD(p,' '); if(strcmp(TimeStamp,p)) WRONG 542886Sphk GETFIELD(p,'\n'); if(strcmp(Prefix,p)) WRONG 552886Sphk 5615456Sphk /* 5715456Sphk * This would be cleaner if mktime() worked in UTC rather than 5815456Sphk * local time. 5915456Sphk */ 6015456Sphk if (SetTime) { 6115456Sphk struct tm tm; 6215456Sphk char *tz; 6315456Sphk char buf[5]; 6415456Sphk int i; 6515456Sphk 6615456Sphk#define SUBSTR(off,len) strncpy(buf, &TimeStamp[off], len), buf[len] = '\0' 6715456Sphk#define WRONGDATE { fprintf(stderr, " %s failed date validation\n",\ 6815456Sphk TimeStamp); WRONG} 6915456Sphk 7015456Sphk if (strlen(TimeStamp) != 15 || TimeStamp[14] != 'Z') WRONGDATE 7115456Sphk for (i = 0; i < 14; i++) 7215456Sphk if (!isdigit(TimeStamp[i])) WRONGDATE 7315456Sphk 7415456Sphk tz = getenv("TZ"); 7515456Sphk if (setenv("TZ", "UTC", 1) < 0) WRONG 7615456Sphk tzset(); 7715456Sphk 7815456Sphk tm.tm_isdst = tm.tm_gmtoff = 0; 7915456Sphk 8015456Sphk SUBSTR(0, 4); 8115456Sphk tm.tm_year = atoi(buf) - 1900; 8215456Sphk SUBSTR(4, 2); 8315456Sphk tm.tm_mon = atoi(buf) - 1; 8415456Sphk if (tm.tm_mon < 0 || tm.tm_mon > 11) WRONGDATE 8515456Sphk SUBSTR(6, 2); 8615456Sphk tm.tm_mday = atoi(buf); 8715456Sphk if (tm.tm_mday < 1 || tm.tm_mday > 31) WRONG; 8815456Sphk SUBSTR(8, 2); 8915456Sphk tm.tm_hour = atoi(buf); 9015456Sphk if (tm.tm_hour > 24) WRONGDATE 9115456Sphk SUBSTR(10, 2); 9215456Sphk tm.tm_min = atoi(buf); 9315456Sphk if (tm.tm_min > 59) WRONGDATE 9415456Sphk SUBSTR(12, 2); 9515456Sphk tm.tm_sec = atoi(buf); 9615456Sphk if (tm.tm_min > 62) WRONGDATE /* allow leap seconds */ 9715456Sphk 9815456Sphk times[0].tv_sec = times[1].tv_sec = mktime(&tm); 9915456Sphk if (times[0].tv_sec == -1) WRONGDATE 10015456Sphk times[0].tv_usec = times[1].tv_usec = 0; 10115456Sphk 10215456Sphk if (tz) { 10315456Sphk if (setenv("TZ", tz, 1) < 0) WRONGDATE 10415456Sphk } else { 10515456Sphk unsetenv("TZ"); 10615456Sphk } 10715456Sphk } 10815456Sphk 1092886Sphk for(;;) { 11013917Sphk Delete(md5); 11113917Sphk Delete(uid); 11213917Sphk Delete(gid); 11313917Sphk Delete(mode); 11413917Sphk Delete(md5before); 11513917Sphk Delete(trash); 11613917Sphk Delete(name); 1172886Sphk cnt = -1; 1182886Sphk 1192886Sphk GETFIELD(p,' '); 1202886Sphk 1212886Sphk if (p[0] != 'C' || p[1] != 'T' || p[2] != 'M') WRONG 1222886Sphk 1232886Sphk if(!strcmp(p+3,"_END")) 1242886Sphk break; 1252886Sphk 1262886Sphk for(sp=Syntax;sp->Key;sp++) 1272886Sphk if(!strcmp(p+3,sp->Key)) 1282886Sphk goto found; 1292886Sphk WRONG 1302886Sphk found: 1312886Sphk for(i=0;(j = sp->List[i]);i++) { 1322886Sphk if (sp->List[i+1] && (sp->List[i+1] & CTM_F_MASK) != CTM_F_Bytes) 1332886Sphk sep = ' '; 1342886Sphk else 1352886Sphk sep = '\n'; 1362886Sphk 1372886Sphk switch (j & CTM_F_MASK) { 13813917Sphk case CTM_F_Name: GETNAMECOPY(name,sep,j, Verbose); break; 1392886Sphk case CTM_F_Uid: GETFIELDCOPY(uid,sep); break; 1402886Sphk case CTM_F_Gid: GETFIELDCOPY(gid,sep); break; 1412886Sphk case CTM_F_Mode: GETFIELDCOPY(mode,sep); break; 1422886Sphk case CTM_F_MD5: 1432886Sphk if(j & CTM_Q_MD5_Before) 1448857Srgrimes GETFIELDCOPY(md5before,sep); 1452886Sphk else 1468857Srgrimes GETFIELDCOPY(md5,sep); 1472886Sphk break; 1482886Sphk case CTM_F_Count: GETBYTECNT(cnt,sep); break; 1492886Sphk case CTM_F_Bytes: GETDATA(trash,cnt); break; 1502886Sphk default: WRONG 1512886Sphk } 1522886Sphk } 1532948Sphk /* XXX This should go away. Disallow trailing '/' */ 1542886Sphk j = strlen(name)-1; 1552886Sphk if(name[j] == '/') name[j] = '\0'; 1562948Sphk 15717946Sphk /* 15817946Sphk * If a filter list is specified, run thru the filter list and 15917946Sphk * match `name' against filters. If the name matches, set the 16017946Sphk * required action to that specified in the filter. 16117946Sphk * The default action if no filterlist is given is to match 16217946Sphk * everything. 16317946Sphk */ 16417946Sphk 16517946Sphk match = (FilterList ? !(FilterList->Action) : CTM_FILTER_ENABLE); 16617946Sphk for (filter = FilterList; filter; filter = filter->Next) { 16717946Sphk if (0 == regexec(&filter->CompiledRegex, name, 16817946Sphk 0, 0, 0)) { 16917946Sphk match = filter->Action; 17017946Sphk } 17117946Sphk } 17217946Sphk 17317946Sphk if (CTM_FILTER_DISABLE == match) /* skip file if disabled */ 17417946Sphk continue; 17517946Sphk 17617946Sphk if (Verbose > 0) 17717946Sphk fprintf(stderr,"> %s %s\n",sp->Key,name); 1782886Sphk if(!strcmp(sp->Key,"FM") || !strcmp(sp->Key, "FS")) { 1797372Sjoerg i = open(name,O_WRONLY|O_CREAT|O_TRUNC,0666); 1802886Sphk if(i < 0) { 18129526Scharnier warn("%s", name); 1822948Sphk WRONG 1832886Sphk } 1842886Sphk if(cnt != write(i,trash,cnt)) { 18529526Scharnier warn("%s", name); 1862948Sphk WRONG 1872886Sphk } 1882886Sphk close(i); 1899491Sphk if(strcmp(md5,MD5File(name,md5_1))) { 1902886Sphk fprintf(stderr," %s %s MD5 didn't come out right\n", 1912886Sphk sp->Key,name); 1922948Sphk WRONG 1932886Sphk } 19415456Sphk if (settime(name,times)) WRONG 1952886Sphk continue; 1968857Srgrimes } 1972886Sphk if(!strcmp(sp->Key,"FE")) { 1982971Sphk ed = popen("ed","w"); 1992886Sphk if(!ed) { 2002886Sphk WRONG 2012886Sphk } 2022971Sphk fprintf(ed,"e %s\n",name); 2032886Sphk if(cnt != fwrite(trash,1,cnt,ed)) { 20429526Scharnier warn("%s", name); 2052886Sphk pclose(ed); 2062948Sphk WRONG 2072886Sphk } 2082886Sphk fprintf(ed,"w %s\n",name); 2092886Sphk if(pclose(ed)) { 21029526Scharnier warn("ed"); 2112948Sphk WRONG 2122886Sphk } 2139491Sphk if(strcmp(md5,MD5File(name,md5_1))) { 2142886Sphk fprintf(stderr," %s %s MD5 didn't come out right\n", 2152886Sphk sp->Key,name); 2162948Sphk WRONG 2172886Sphk } 21815456Sphk if (settime(name,times)) WRONG 2192886Sphk continue; 2202886Sphk } 2212926Sphk if(!strcmp(sp->Key,"FN")) { 2222926Sphk strcpy(buf,name); 22313917Sphk strcat(buf,TMPSUFF); 2242926Sphk i = ctm_edit(trash,cnt,name,buf); 2252926Sphk if(i) { 2262948Sphk fprintf(stderr," %s %s Edit failed with code %d.\n", 2272948Sphk sp->Key,name,i); 2282948Sphk WRONG 2292926Sphk } 23020971Sphk if(strcmp(md5,MD5File(buf,md5_1))) { 2312948Sphk fprintf(stderr," %s %s Edit failed MD5 check.\n", 2322948Sphk sp->Key,name); 2332948Sphk WRONG 2342948Sphk } 23520971Sphk if (rename(buf,name) == -1) 23620971Sphk WRONG 23715456Sphk if (settime(name,times)) WRONG 2382948Sphk continue; 2392926Sphk } 2402886Sphk if(!strcmp(sp->Key,"DM")) { 2417372Sjoerg if(0 > mkdir(name,0777)) { 2422886Sphk sprintf(buf,"mkdir -p %s",name); 2432886Sphk system(buf); 2442886Sphk } 2452886Sphk if(0 > stat(name,&st) || ((st.st_mode & S_IFMT) != S_IFDIR)) { 2462886Sphk fprintf(stderr,"<%s> mkdir failed\n",name); 2472948Sphk WRONG 2482886Sphk } 24915456Sphk if (settime(name,times)) WRONG 2502886Sphk continue; 2518857Srgrimes } 2524816Sphk if(!strcmp(sp->Key,"FR")) { 25317946Sphk if (KeepIt) { 25417946Sphk if (Verbose > 1) 25517946Sphk printf("<%s> not removed\n", name); 25617946Sphk } 25717946Sphk else if (0 != unlink(name)) { 2584947Sphk fprintf(stderr,"<%s> unlink failed\n",name); 2596181Sphk if (!Force) 2606181Sphk WRONG 2614947Sphk } 2624947Sphk continue; 2638857Srgrimes } 2648857Srgrimes if(!strcmp(sp->Key,"DR")) { 2654947Sphk /* 2664947Sphk * We cannot use rmdir() because we do not get the directories 2674947Sphk * in '-depth' order (cvs-cur.0018.gz for examples) 2684947Sphk */ 26917946Sphk if (KeepIt) { 27017946Sphk if (Verbose > 1) { 27117946Sphk printf("<%s> not removed\n", name); 27217946Sphk } 27317946Sphk } else { 27417946Sphk sprintf(buf,"rm -rf %s",name); 27517946Sphk system(buf); 27617946Sphk } 2772886Sphk continue; 2788857Srgrimes } 2792886Sphk WRONG 2802886Sphk } 28113917Sphk 28213917Sphk Delete(md5); 28313917Sphk Delete(uid); 28413917Sphk Delete(gid); 28513917Sphk Delete(mode); 28613917Sphk Delete(md5before); 28713917Sphk Delete(trash); 28813917Sphk Delete(name); 28913917Sphk 2909491Sphk q = MD5End (&ctx,md5_1); 2912886Sphk GETFIELD(p,'\n'); 2922886Sphk if(strcmp(q,p)) WRONG 2932886Sphk if (-1 != getc(fd)) WRONG 2942886Sphk return 0; 2952886Sphk} 296