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

📄 revproto.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <auth.h>#include <fcall.h>#include <disk.h>enum {	LEN	= 8*1024,	HUNKS	= 128,};typedef struct File File;struct File{	char	*new;	char	*elem;	char	*old;	char	*uid;	char	*gid;	ulong	mode;};typedef void Mkfserr(char*, void*);typedef void Mkfsenum(char*, char*, Dir*, void*);typedef struct Name Name;struct Name {	int n;	char *s;};typedef struct Mkaux Mkaux;struct Mkaux {	Mkfserr *warn;	Mkfsenum *mkenum;	char *root;	char *xroot;	char *proto;	jmp_buf jmp;	Biobuf *b;	Name oldfile;	Name fullname;	int	lineno;	int	indent;	void *a;};static void domkfs(Mkaux *mkaux, File *me, int level);static int	copyfile(Mkaux*, File*, Dir*, int);static void	freefile(File*);static File*	getfile(Mkaux*, File*);static char*	getmode(Mkaux*, char*, ulong*);static char*	getname(Mkaux*, char*, char**);static char*	getpath(Mkaux*, char*);static int	mkfile(Mkaux*, File*);static char*	mkpath(Mkaux*, char*, char*);static void	mktree(Mkaux*, File*, int);static void	setnames(Mkaux*, File*);static void	skipdir(Mkaux*);static void	warn(Mkaux*, char *, ...);//static void//mprint(char *new, char *old, Dir *d, void*)//{//	print("%s %s %D\n", new, old, d);//}intrevrdproto(char *proto, char *root, char *xroot, Mkfsenum *mkenum, Mkfserr *mkerr, void *a){	Mkaux mx, *m;	File file;	int rv;	m = &mx;	memset(&mx, 0, sizeof mx);	if(root == nil)		root = "/";	m->root = root;	m->xroot = xroot;	m->warn = mkerr;	m->mkenum = mkenum;	m->a = a;	m->proto = proto;	m->lineno = 0;	m->indent = 0;	if((m->b = Bopen(proto, OREAD)) == nil) {		werrstr("open '%s': %r", proto);		return -1;	}	memset(&file, 0, sizeof file);	file.new = "";	file.old = nil;	rv = 0;	if(setjmp(m->jmp) == 0)		domkfs(m, &file, -1);	else		rv = -1;	free(m->oldfile.s);	free(m->fullname.s);	return rv;}static void*emalloc(Mkaux *mkaux, ulong n){	void *v;	v = malloc(n);	if(v == nil)		longjmp(mkaux->jmp, 1);	/* memory leak */	memset(v, 0, n);	return v;}static char*estrdup(Mkaux *mkaux, char *s){	s = strdup(s);	if(s == nil)		longjmp(mkaux->jmp, 1);	/* memory leak */	return s;}static voiddomkfs(Mkaux *mkaux, File *me, int level){	File *child;	int rec;	child = getfile(mkaux, me);	if(!child)		return;	if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){		rec = child->elem[0] == '+';		free(child->new);		child->new = estrdup(mkaux, me->new);		setnames(mkaux, child);		mktree(mkaux, child, rec);		freefile(child);		child = getfile(mkaux, me);	}	while(child && mkaux->indent > level){		if(mkfile(mkaux, child))			domkfs(mkaux, child, mkaux->indent);		freefile(child);		child = getfile(mkaux, me);	}	if(child){		freefile(child);		Bseek(mkaux->b, -Blinelen(mkaux->b), 1);		mkaux->lineno--;	}}enum {	SLOP = 30};static voidsetname(Mkaux *mkaux, Name *name, char *s1, char *s2){	int l;	l = strlen(s1)+strlen(s2)+1;	if(name->n < l) {		free(name->s);		name->s = emalloc(mkaux, l+SLOP);		name->n = l+SLOP;	}	snprint(name->s, name->n, "%s%s%s", s1, s2[0] && s2[0]!='/' ? "/" : "", s2);}static voidmktree(Mkaux *mkaux, File *me, int rec){	File child;	Dir *d;	int i, n, fd;	setname(mkaux, &mkaux->fullname, mkaux->root, me->new);	fd = open(mkaux->fullname.s, OREAD);	if(fd < 0){		warn(mkaux, "can't open %s: %r", mkaux->fullname.s);		return;	}	child = *me;	while((n = dirread(fd, &d)) > 0){		for(i = 0; i < n; i++){			child.new = mkpath(mkaux, me->new, d[i].name);			if(me->old)				child.old = mkpath(mkaux, me->old, d[i].name);			child.elem = d[i].name;			setnames(mkaux, &child);			if(copyfile(mkaux, &child, &d[i], 1) && rec)				mktree(mkaux, &child, rec);			free(child.new);			if(child.old)				free(child.old);		}	}	close(fd);}static intmkfile(Mkaux *mkaux, File *f){	Dir *d;	setname(mkaux, &mkaux->fullname, mkaux->root, f->new);	if((d = dirstat(mkaux->fullname.s)) == nil){		warn(mkaux, "can't stat file %s: %r", mkaux->fullname.s);		skipdir(mkaux);		return 0;	}	return copyfile(mkaux, f, d, 0);}static intcopyfile(Mkaux *mkaux, File *f, Dir *d, int permonly){	Dir *nd;	ulong xmode;	char *p;	/*	 * Extra stat here is inefficient but accounts for binds.	 */	setname(mkaux, &mkaux->fullname, mkaux->root, f->new);	if((nd = dirstat(mkaux->fullname.s)) != nil)		d = nd;	setname(mkaux, &mkaux->fullname, mkaux->xroot, f->old ? f->old : f->new);	d->name = f->elem;	if(d->type != 'M'){		d->uid = "sys";		d->gid = "sys";		xmode = (d->mode >> 6) & 7;		d->mode |= xmode | (xmode << 3);	}	if(strcmp(f->uid, "-") != 0)		d->uid = f->uid;	if(strcmp(f->gid, "-") != 0)		d->gid = f->gid;	if(f->mode != ~0){		if(permonly)			d->mode = (d->mode & ~0666) | (f->mode & 0666);		else if((d->mode&DMDIR) != (f->mode&DMDIR))			warn(mkaux, "inconsistent mode for %s", f->new);		else			d->mode = f->mode;	}	if(p = strrchr(f->new, '/'))		d->name = p+1;	else		d->name = f->new;	mkaux->mkenum(f->new, mkaux->fullname.s, d, mkaux->a);	xmode = d->mode;	free(nd);	return (xmode&DMDIR) != 0;}static char *mkpath(Mkaux *mkaux, char *prefix, char *elem){	char *p;	int n;	n = strlen(prefix) + strlen(elem) + 2;	p = emalloc(mkaux, n);	strcpy(p, prefix);	strcat(p, "/");	strcat(p, elem);	return p;}static voidsetnames(Mkaux *mkaux, File *f){		if(f->old){		if(f->old[0] == '/')			setname(mkaux, &mkaux->oldfile, f->old, "");		else			setname(mkaux, &mkaux->oldfile, mkaux->xroot, f->old);	} else		setname(mkaux, &mkaux->oldfile, mkaux->xroot, f->new);}static voidfreefile(File *f){	if(f->old)		free(f->old);	if(f->new)		free(f->new);	free(f);}/* * skip all files in the proto that * could be in the current dir */static voidskipdir(Mkaux *mkaux){	char *p, c;	int level;	if(mkaux->indent < 0)		return;	level = mkaux->indent;	for(;;){		mkaux->indent = 0;		p = Brdline(mkaux->b, '\n');		mkaux->lineno++;		if(!p){			mkaux->indent = -1;			return;		}		while((c = *p++) != '\n')			if(c == ' ')				mkaux->indent++;			else if(c == '\t')				mkaux->indent += 8;			else				break;		if(mkaux->indent <= level){			Bseek(mkaux->b, -Blinelen(mkaux->b), 1);			mkaux->lineno--;			return;		}	}}static File*getfile(Mkaux *mkaux, File *old){	File *f;	char *elem;	char *p;	int c;	if(mkaux->indent < 0)		return 0;loop:	mkaux->indent = 0;	p = Brdline(mkaux->b, '\n');	mkaux->lineno++;	if(!p){		mkaux->indent = -1;		return 0;	}	while((c = *p++) != '\n')		if(c == ' ')			mkaux->indent++;		else if(c == '\t')			mkaux->indent += 8;		else			break;	if(c == '\n' || c == '#')		goto loop;	p--;	f = emalloc(mkaux, sizeof *f);	p = getname(mkaux, p, &elem);	if(p == nil)		return nil;	f->new = mkpath(mkaux, old->new, elem);	free(elem);	f->elem = utfrrune(f->new, L'/') + 1;	p = getmode(mkaux, p, &f->mode);	p = getname(mkaux, p, &f->uid);	/* LEAK */	if(p == nil)		return nil;	if(!*f->uid)		f->uid = "-";		/* LEAK */	p = getname(mkaux, p, &f->gid);	/* LEAK */	if(p == nil)		return nil;	if(!*f->gid)		f->gid = "-";		/* LEAK */	f->old = getpath(mkaux, p);	if(f->old && strcmp(f->old, "-") == 0){		free(f->old);		f->old = 0;	}	setnames(mkaux, f);	return f;}static char*getpath(Mkaux *mkaux, char *p){	char *q, *new;	int c, n;	while((c = *p) == ' ' || c == '\t')		p++;	q = p;	while((c = *q) != '\n' && c != ' ' && c != '\t')		q++;	if(q == p)		return 0;	n = q - p;	new = emalloc(mkaux, n + 1);	memcpy(new, p, n);	new[n] = 0;	return new;}static char*getname(Mkaux *mkaux, char *p, char **buf){	char *s, *start;	int c;	while((c = *p) == ' ' || c == '\t')		p++;	start = p;	while((c = *p) != '\n' && c != ' ' && c != '\t')		p++;	*buf = malloc(p+1-start);	if(*buf == nil)		return nil;	memmove(*buf, start, p-start);	(*buf)[p-start] = '\0';	if(**buf == '$'){		s = getenv(*buf+1);		if(s == 0){			warn(mkaux, "can't read environment variable %s", *buf+1);			skipdir(mkaux);			free(*buf);			return nil;		}		free(*buf);		*buf = s;	}	return p;}static char*getmode(Mkaux *mkaux, char *p, ulong *xmode){	char *buf, *s;	ulong m;	*xmode = ~0;	p = getname(mkaux, p, &buf);	if(p == nil)		return nil;	s = buf;	if(!*s || strcmp(s, "-") == 0)		return p;	m = 0;	if(*s == 'd'){		m |= DMDIR;		s++;	}	if(*s == 'a'){		m |= DMAPPEND;		s++;	}	if(*s == 'l'){		m |= DMEXCL;		s++;	}	if(s[0] < '0' || s[0] > '7'	|| s[1] < '0' || s[1] > '7'	|| s[2] < '0' || s[2] > '7'	|| s[3]){		warn(mkaux, "bad mode specification %s", buf);		free(buf);		return p;	}	*xmode = m | strtoul(s, 0, 8);	free(buf);	return p;}static voidwarn(Mkaux *mkaux, char *fmt, ...){	char buf[256];	va_list va;	va_start(va, fmt);	vseprint(buf, buf+sizeof(buf), fmt, va);	va_end(va);	if(mkaux->warn)		mkaux->warn(buf, mkaux->a);	else		fprint(2, "warning: %s\n", buf);}

⌨️ 快捷键说明

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