516 lines · 9.0 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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 *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);//} intrdproto(char *proto, char *root, 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->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--;	}} static voidmktree(Mkaux *mkaux, File *me, int rec){	File child;	Dir *d;	int i, n, fd; 	fd = open(mkaux->oldfile.s, OREAD);	if(fd < 0){		warn(mkaux, "can't open %s: %r", mkaux->oldfile.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((!(d[i].mode&DMDIR) || rec) && 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; 	if((d = dirstat(mkaux->oldfile.s)) == nil){		warn(mkaux, "can't stat file %s: %r", mkaux->oldfile.s);		skipdir(mkaux);		return 0;	}	return copyfile(mkaux, f, d, 0);} 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+SLOP/2) {		free(name->s);		name->s = emalloc(mkaux, l+SLOP);		name->n = l+SLOP;	}	snprint(name->s, name->n, "%s%s%s", s1, s1[0]==0 || s1[strlen(s1)-1]!='/' ? "/" : "", s2);} static intcopyfile(Mkaux *mkaux, File *f, Dir *d, int permonly){	Dir *nd;	ulong xmode;	char *p; 	setname(mkaux, &mkaux->fullname, mkaux->root, f->old ? f->old : f->new);	/*	 * Extra stat here is inefficient but accounts for binds.	 */	if((nd = dirstat(mkaux->fullname.s)) != nil)		d = nd; 	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->root, f->old);	} else		setname(mkaux, &mkaux->oldfile, mkaux->root, 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)		strcpy(f->uid, "-");	p = getname(mkaux, p, &f->gid);	/* LEAK */	if(p == nil)		return nil; 	if(!*f->gid)		strcpy(f->gid, "-");	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+2-start);	/* +2: need at least 2 bytes; might strcpy "-" into buf */	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;}

Lines 1–500 of 516.