⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 applylog.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "all.h"#define	Nwork	16int localdirstat(char*, Dir*);int ismatch(char*);void conflict(char*, char*, ...);void error(char*, ...);int isdir(char*);void worker(int fdf, int fdt, char *from, char *to);vlong	nextoff(void);void	failure(void *, char *note);QLock	lk;vlong	off;int errors;int nconf;int donothing;char **conf;int verbose;char **match;int nmatch;int tempspool = 1;int safeinstall = 1;char *lroot;char *rroot;Db *clientdb;int skip;int douid;char *mkname(char*, int, char*, char*);char localbuf[10240];char remotebuf[10240];int copyfile(char*, char*, char*, Dir*, int, int*);ulong maxnow;int maxn;char *timefile;int timefd;Db *copyerr;typedef struct Res Res;struct Res{	char c;	char *name;};Res *res;int nres;void addresolve(int c, char *name){	if(name[0] == '/')		name++;	res = erealloc(res, (nres+1)*sizeof res[0]);	res[nres].c = c;	res[nres].name = name;	nres++;}intresolve(char *name){	int i, len;	for(i=0; i<nres; i++){		len = strlen(res[i].name);		if(len == 0)			return res[i].c;		if(strncmp(name, res[i].name, len) == 0 && (name[len]=='/' || name[len] == 0))			return res[i].c;	}	return '?';}voidreadtimefile(void){	int n;	char buf[24];	if((timefd = open(timefile, ORDWR)) < 0	&& (timefd = create(timefile, ORDWR|OEXCL, 0666)) < 0)		return;	n = readn(timefd, buf, sizeof buf);	if(n < sizeof buf)		return;	maxnow = atoi(buf);	maxn = atoi(buf+12);}voidwritetimefile(void){	char buf[24+1];	snprint(buf, sizeof buf, "%11lud %11d ", maxnow, maxn);	pwrite(timefd, buf, 24, 0);}static void membogus(char**);voidaddce(char *local){	char e[ERRMAX];	Dir d;	memset(&d, 0, sizeof d);	rerrstr(e, sizeof e);	d.name = atom(e);	d.uid = "";	d.gid = "";	insertdb(copyerr, atom(local), &d);}voiddelce(char *local){	removedb(copyerr, local);}voidchat(char *f, ...){	Fmt fmt;	char buf[256];	va_list arg;	if(!verbose)		return;	fmtfdinit(&fmt, 1, buf, sizeof buf);	va_start(arg, f);	fmtvprint(&fmt, f, arg);	va_end(arg);	fmtfdflush(&fmt);}voidusage(void){	fprint(2, "usage: replica/applylog [-cnSstuv] [-T timefile] clientdb clientroot serverroot [path ...]\n");	exits("usage");}intnotexists(char *path){	char buf[ERRMAX];	if(access(path, AEXIST) >= 0)		return 0;		rerrstr(buf, sizeof buf);	if(strstr(buf, "entry not found") || strstr(buf, "not exist"))		return 1;	/* some other error, like network hangup */	return 0;}voidmain(int argc, char **argv){ 	char *f[10], *local, *name, *remote, *s, *t, verb;	int fd, havedb, havelocal, i, k, n, nf, resolve1, skip;	int checkedmatch1, checkedmatch2, 		checkedmatch3, checkedmatch4;	ulong now;	Biobuf bin;	Dir dbd, ld, nd, rd;	Avlwalk *w;	Entry *e;	membogus(argv);	quotefmtinstall();	ARGBEGIN{	case 's':	case 'c':		i = ARGC();		addresolve(i, EARGF(usage()));		break;	case 'n':		donothing = 1;		verbose = 1;		break;	case 'S':		safeinstall = 0;		break;	case 'T':		timefile = EARGF(usage());		break;	case 't':		tempspool = 0;		break;	case 'u':		douid = 1;		break;	case 'v':		verbose++;		break;	default:		usage();	}ARGEND	if(argc < 3)		usage();	if(timefile)		readtimefile();	lroot = argv[1];	if(!isdir(lroot))		sysfatal("bad local root directory");	rroot = argv[2];	if(!isdir(rroot))		sysfatal("bad remote root directory");	match = argv+3;	nmatch = argc-3;	for(i=0; i<nmatch; i++)		if(match[i][0] == '/')			match[i]++;	if((clientdb = opendb(argv[0])) == nil)		sysfatal("opendb %q: %r", argv[2]);		copyerr = opendb(nil);	skip = 0;	Binit(&bin, 0, OREAD);	for(; s=Brdstr(&bin, '\n', 1); free(s)){		t = estrdup(s);		nf = tokenize(s, f, nelem(f));		if(nf != 10 || strlen(f[2]) != 1){			skip = 1;			fprint(2, "warning: skipping bad log entry <%s>\n", t);			free(t);			continue;		}		free(t);		now = strtoul(f[0], 0, 0);		n = atoi(f[1]);		verb = f[2][0];		name = f[3];		if(now < maxnow || (now==maxnow && n <= maxn))			continue;		local = mkname(localbuf, sizeof localbuf, lroot, name);		if(strcmp(f[4], "-") == 0)			f[4] = f[3];		remote = mkname(remotebuf, sizeof remotebuf, rroot, f[4]);		rd.name = f[4];		rd.mode = strtoul(f[5], 0, 8);		rd.uid = f[6];		rd.gid = f[7];		rd.mtime = strtoul(f[8], 0, 10);		rd.length = strtoll(f[9], 0, 10);		havedb = finddb(clientdb, name, &dbd)>=0;		havelocal = localdirstat(local, &ld)>=0;		resolve1 = resolve(name);		/*		 * if(!ismatch(name)){		 *	skip = 1;		 *	continue;		 * }		 * 		 * This check used to be right here, but we want		 * the time to be able to move forward past entries		 * that don't match and have already been applied.		 * So now every path below must checked !ismatch(name)		 * before making any changes to the local file		 * system.  The fake variable checkedmatch		 * tracks whether !ismatch(name) has been checked.		 * If the compiler doesn't produce any used/set		 * warnings, then all the paths should be okay.		 * Even so, we have the asserts to fall back on.		 */		switch(verb){		case 'd':	/* delete file */			delce(local);			if(!havelocal)	/* doesn't exist; who cares? */				break;			if(!ismatch(name)){				if(!skip)					fprint(2, "stopped updating log apply time because of %s\n", name);				skip = 1;				continue;			}			SET(checkedmatch1);			if(!havedb){				if(resolve1 == 's')					goto DoRemove;				else if(resolve1 == 'c')					goto DoRemoveDb;				conflict(name, "locally created; will not remove");				skip = 1;				continue;			}			assert(havelocal && havedb);			if(dbd.mtime > rd.mtime)		/* we have a newer file than what was deleted */				break;			if(!(dbd.mode&DMDIR) && (dbd.mtime != ld.mtime || dbd.length != ld.length)){	/* locally modified since we downloaded it */				if(resolve1 == 's')					goto DoRemove;				else if(resolve1 == 'c')					break;				conflict(name, "locally modified; will not remove");				skip = 1;				continue;			}		    DoRemove:			USED(checkedmatch1);			assert(ismatch(name));			chat("d %q\n", name);			if(donothing)				break;			if(remove(local) < 0){				error("removing %q", name);				skip = 1;				continue;			}		    DoRemoveDb:			USED(checkedmatch1);			assert(ismatch(name));			removedb(clientdb, name);			break;		case 'a':	/* add file */			if(!havedb){				if(!ismatch(name)){					if(!skip)						fprint(2, "stopped updating log apply time because of %s\n", name);					skip = 1;					continue;				}				SET(checkedmatch2);				if(!havelocal)					goto DoCreate;				if((ld.mode&DMDIR) && (rd.mode&DMDIR))					break;				if(resolve1 == 's')					goto DoCreate;				else if(resolve1 == 'c')					goto DoCreateDb;				conflict(name, "locally created; will not overwrite");				skip = 1;				continue;			}			assert(havedb);			if(dbd.mtime >= rd.mtime)	/* already created this file; ignore */				break;			if(havelocal){				if((ld.mode&DMDIR) && (rd.mode&DMDIR))					break;				if(!ismatch(name)){					if(!skip)						fprint(2, "stopped updating log apply time because of %s\n", name);					skip = 1;					continue;				}				SET(checkedmatch2);				if(dbd.mtime==ld.mtime && dbd.length==ld.length)					goto DoCreate;				if(resolve1=='s')					goto DoCreate;				else if(resolve1 == 'c')					break;				conflict(name, "locally modified; will not overwrite");				skip = 1;				continue;			}			if(!ismatch(name)){				if(!skip)					fprint(2, "stopped updating log apply time because of %s\n", name);				skip = 1;				continue;			}			SET(checkedmatch2);		    DoCreate:			USED(checkedmatch2);			assert(ismatch(name));			if(notexists(remote)){				addce(local);				/* no skip=1 */				break;;			}			chat("a %q %luo %q %q %lud\n", name, rd.mode, rd.uid, rd.gid, rd.mtime);			if(donothing)				break;			if(rd.mode&DMDIR){				if((fd = create(local, OREAD, DMDIR)) < 0){					error("mkdir %q: %r", name);					skip = 1;					continue;				}				nulldir(&nd);				nd.mode = rd.mode;				if(dirfwstat(fd, &nd) < 0)					fprint(2, "warning: cannot set mode on %q\n", local);				nulldir(&nd);				nd.gid = rd.gid;				if(dirfwstat(fd, &nd) < 0)					fprint(2, "warning: cannot set gid on %q\n", local);				if(douid){					nulldir(&nd);					nd.uid = rd.uid;					if(dirfwstat(fd, &nd) < 0)						fprint(2, "warning: cannot set uid on %q\n", local);				}				close(fd);				rd.mtime = now;			}else{				if(copyfile(local, remote, name, &rd, 1, &k) < 0){					if(k)						addce(local);					skip = 1;					continue;				}			}		    DoCreateDb:			USED(checkedmatch2);			assert(ismatch(name));			insertdb(clientdb, name, &rd);			break;					case 'c':	/* change contents */			if(!havedb){				if(notexists(remote)){					addce(local);					/* no skip=1 */					break;				}				if(!ismatch(name)){					if(!skip)						fprint(2, "stopped updating log apply time because of %s\n", name);					skip = 1;					continue;				}				SET(checkedmatch3);				if(resolve1 == 's')					goto DoCopy;				else if(resolve1=='c')					goto DoCopyDb;				if(havelocal)					conflict(name, "locally created; will not update");				else					conflict(name, "not replicated; will not update");				skip = 1;				continue;			}			if(dbd.mtime >= rd.mtime)		/* already have/had this version; ignore */				break;			if(!ismatch(name)){				if(!skip)					fprint(2, "stopped updating log apply time because of %s\n", name);				skip = 1;				continue;			}			SET(checkedmatch3);			if(!havelocal){				if(notexists(remote)){					addce(local);					/* no skip=1 */					break;				}				if(resolve1 == 's')					goto DoCopy;				else if(resolve1 == 'c')					break;				conflict(name, "locally removed; will not update");				skip = 1;				continue;			}			assert(havedb && havelocal);			if(dbd.mtime != ld.mtime || dbd.length != ld.length){				if(notexists(remote)){					addce(local);					/* no skip=1 */					break;				}				if(resolve1 == 's')					goto DoCopy;				else if(resolve1 == 'c')					break;				conflict(name, "locally modified; will not update");				skip = 1;				continue;			}		    DoCopy:			USED(checkedmatch3);			assert(ismatch(name));			if(notexists(remote)){				addce(local);				/* no skip=1 */				break;			}			chat("c %q\n", name);			if(donothing)				break;			if(copyfile(local, remote, name, &rd, 0, &k) < 0){				if(k)					addce(local);				skip = 1;				continue;			}		    DoCopyDb:			USED(checkedmatch3);			assert(ismatch(name));			if(!havedb){				if(havelocal)					dbd = ld;				else					dbd = rd;			}			dbd.mtime = rd.mtime;			dbd.length = rd.length;			insertdb(clientdb, name, &dbd);			break;					case 'm':	/* change metadata */			if(!havedb){				if(notexists(remote)){					addce(local);					/* no skip=1 */					break;				}				if(!ismatch(name)){					if(!skip)						fprint(2, "stopped updating log apply time because of %s\n", name);					skip = 1;					continue;				}				SET(checkedmatch4);				if(resolve1 == 's'){					USED(checkedmatch4);					SET(checkedmatch2);					goto DoCreate;				}				else if(resolve1 == 'c')					goto DoMetaDb;				if(havelocal)					conflict(name, "locally created; will not update metadata");				else					conflict(name, "not replicated; will not update metadata");				skip = 1;				continue;			}			if(!(dbd.mode&DMDIR) && dbd.mtime > rd.mtime)		/* have newer version; ignore */				break;			if((dbd.mode&DMDIR) && dbd.mtime > now)				break;			if(havelocal && (!douid || strcmp(ld.uid, rd.uid)==0) && strcmp(ld.gid, rd.gid)==0 && ld.mode==rd.mode)				break;			if(!havelocal){				if(notexists(remote)){					addce(local);					/* no skip=1 */					break;				}				if(!ismatch(name)){					if(!skip)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -