867 lines · 14.8 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 <auth.h>#include <bio.h> enum{	LEN	= 8*1024,	HUNKS	= 128, 	/*	 * types of destination file sytems	 */	Kfs = 0,	Fs,	Archive,}; typedef struct File	File; struct File{	char	*new;	char	*elem;	char	*old;	char	*uid;	char	*gid;	ulong	mode;}; void	arch(Dir*);void	copy(Dir*);int	copyfile(File*, Dir*, int);void*	emalloc(ulong);void	error(char *, ...);void	freefile(File*);File*	getfile(File*);char*	getmode(char*, ulong*);char*	getname(char*, char**);char*	getpath(char*);void	kfscmd(char *);void	mkdir(Dir*);int	mkfile(File*);void	mkfs(File*, int);char*	mkpath(char*, char*);void	mktree(File*, int);void	mountkfs(char*);void	printfile(File*);void	setnames(File*);void	setusers(void);void	skipdir(void);char*	strdup(char*);int	uptodate(Dir*, char*);void	usage(void);void	warn(char *, ...); Biobuf	*b;Biobufhdr bout;			/* stdout when writing archive */uchar	boutbuf[2*LEN];char	newfile[LEN];char	oldfile[LEN];char	*proto;char	*cputype;char	*users;char	*oldroot;char	*newroot;char	*prog = "mkfs";int	lineno;char	*buf;char	*zbuf;int	buflen = 1024-8;int	indent;int	verb;int	modes;int	ream;int	debug;int	xflag;int	sfd;int	fskind;			/* Kfs, Fs, Archive */int	setuid;			/* on Fs: set uid and gid? */char	*user; voidmain(int argc, char **argv){	File file;	char *name;	int i, errs; 	quotefmtinstall();	user = getuser();	name = "";	memset(&file, 0, sizeof file);	file.new = "";	file.old = 0;	oldroot = "";	newroot = "/n/kfs";	users = 0;	fskind = Kfs;	ARGBEGIN{	case 'a':		if(fskind != Kfs) {			fprint(2, "cannot use -a with -d\n");			usage();		}		fskind = Archive;		newroot = "";		Binits(&bout, 1, OWRITE, boutbuf, sizeof boutbuf);		break;	case 'd':		if(fskind != Kfs) {			fprint(2, "cannot use -d with -a\n");			usage();		}		fskind = Fs;		newroot = ARGF();		break;	case 'D':		debug = 1;		break;	case 'n':		name = EARGF(usage());		break;	case 'p':		modes = 1;		break;	case 'r':		ream = 1;		break;	case 's':		oldroot = ARGF();		break;	case 'u':		users = ARGF();		break;	case 'U':		setuid = 1;		break;	case 'v':		verb = 1;		break;	case 'x':		xflag = 1;		break;	case 'z':		buflen = atoi(ARGF())-8;		break;	default:		usage();	}ARGEND 	if(!argc)			usage(); 	buf = emalloc(buflen);	zbuf = emalloc(buflen);	memset(zbuf, 0, buflen); 	mountkfs(name);	kfscmd("allow");	proto = "users";	setusers();	cputype = getenv("cputype");	if(cputype == 0)		cputype = "68020"; 	errs = 0;	for(i = 0; i < argc; i++){		proto = argv[i];		fprint(2, "processing %q\n", proto); 		b = Bopen(proto, OREAD);		if(!b){			fprint(2, "%q: can't open %q: skipping\n", prog, proto);			errs++;			continue;		} 		lineno = 0;		indent = 0;		mkfs(&file, -1);		Bterm(b);	}	fprint(2, "file system made\n");	kfscmd("disallow");	kfscmd("sync");	if(errs)		exits("skipped protos");	if(fskind == Archive){		Bprint(&bout, "end of archive\n");		Bterm(&bout);	}	exits(0);} voidmkfs(File *me, int level){	File *child;	int rec; 	child = getfile(me);	if(!child)		return;	if((child->elem[0] == '+' || child->elem[0] == '*') && child->elem[1] == '\0'){		rec = child->elem[0] == '+';		free(child->new);		child->new = strdup(me->new);		setnames(child);		mktree(child, rec);		freefile(child);		child = getfile(me);	}	while(child && indent > level){		if(mkfile(child))			mkfs(child, indent);		freefile(child);		child = getfile(me);	}	if(child){		freefile(child);		Bseek(b, -Blinelen(b), 1);		lineno--;	}} voidmktree(File *me, int rec){	File child;	Dir *d;	int i, n, fd; 	fd = open(oldfile, OREAD);	if(fd < 0){		warn("can't open %q: %r", oldfile);		return;	} 	child = *me;	while((n = dirread(fd, &d)) > 0){		for(i = 0; i < n; i++){			child.new = mkpath(me->new, d[i].name);			if(me->old)				child.old = mkpath(me->old, d[i].name);			child.elem = d[i].name;			setnames(&child);			if(copyfile(&child, &d[i], 1) && rec)				mktree(&child, rec);			free(child.new);			if(child.old)				free(child.old);		}	}	close(fd);} intmkfile(File *f){	Dir *dir; 	if((dir = dirstat(oldfile)) == nil){		warn("can't stat file %q: %r", oldfile);		skipdir();		return 0;	}	return copyfile(f, dir, 0);} intcopyfile(File *f, Dir *d, int permonly){	ulong mode;	Dir nd; 	if(xflag){		Bprint(&bout, "%q\t%ld\t%lld\n", f->new, d->mtime, d->length);		return (d->mode & DMDIR) != 0;	}	if(verb && (fskind == Archive || ream))		fprint(2, "%q\n", f->new);	d->name = f->elem;	if(d->type != 'M'){		d->uid = "sys";		d->gid = "sys";		mode = (d->mode >> 6) & 7;		d->mode |= mode | (mode << 3);	}	if(strcmp(f->uid, "-") != 0)		d->uid = f->uid;	if(strcmp(f->gid, "-") != 0)		d->gid = f->gid;	if(fskind == Fs && !setuid){		d->uid = "";		d->gid = "";	}	if(f->mode != ~0){		if(permonly)			d->mode = (d->mode & ~0666) | (f->mode & 0666);		else if((d->mode&DMDIR) != (f->mode&DMDIR))			warn("inconsistent mode for %q", f->new);		else			d->mode = f->mode;	}	if(!uptodate(d, newfile)){		if(verb && (fskind != Archive && ream == 0))			fprint(2, "%q\n", f->new);		if(d->mode & DMDIR)			mkdir(d);		else			copy(d);	}else if(modes){		nulldir(&nd);		nd.mode = d->mode;		nd.gid = d->gid;		nd.mtime = d->mtime;		if(verb && (fskind != Archive && ream == 0))			fprint(2, "%q\n", f->new);		if(dirwstat(newfile, &nd) < 0)			warn("can't set modes for %q: %r", f->new);		nulldir(&nd);		nd.uid = d->uid;		dirwstat(newfile, &nd);	}	return (d->mode & DMDIR) != 0;} /* * check if file to is up to date with * respect to the file represented by df */intuptodate(Dir *df, char *to){	int ret;	Dir *dt; 	if(fskind == Archive || ream || (dt = dirstat(to)) == nil)		return 0;	ret = dt->mtime >= df->mtime;	free(dt);	return ret;} voidcopy(Dir *d){	char cptmp[LEN], *p;	int f, t, n, needwrite, nowarnyet = 1;	vlong tot, len;	Dir nd; 	f = open(oldfile, OREAD);	if(f < 0){		warn("can't open %q: %r", oldfile);		return;	}	t = -1;	if(fskind == Archive)		arch(d);	else{		strcpy(cptmp, newfile);		p = utfrrune(cptmp, L'/');		if(!p)			error("internal temporary file error");		strcpy(p+1, "__mkfstmp");		t = create(cptmp, OWRITE, 0666);		if(t < 0){			warn("can't create %q: %r", newfile);			close(f);			return;		}	} 	needwrite = 0;	for(tot = 0; tot < d->length; tot += n){		len = d->length - tot;		/* don't read beyond d->length */		if (len > buflen)			len = buflen;		n = read(f, buf, len);		if(n <= 0) {			if(n < 0 && nowarnyet) {				warn("can't read %q: %r", oldfile);				nowarnyet = 0;			}			/*			 * don't quit: pad to d->length (in pieces) to agree			 * with the length in the header, already emitted.			 */			memset(buf, 0, len);			n = len;		}		if(fskind == Archive){			if(Bwrite(&bout, buf, n) != n)				error("write error: %r");		}else if(memcmp(buf, zbuf, n) == 0){			if(seek(t, n, 1) < 0)				error("can't write zeros to %q: %r", newfile);			needwrite = 1;		}else{			if(write(t, buf, n) < n)				error("can't write %q: %r", newfile);			needwrite = 0;		}	}	close(f);	if(needwrite){		if(seek(t, -1, 1) < 0 || write(t, zbuf, 1) != 1)			error("can't write zero at end of %q: %r", newfile);	}	if(tot != d->length){		/* this should no longer happen */		warn("wrong number of bytes written to %q (was %lld should be %lld)\n",			newfile, tot, d->length);		if(fskind == Archive){			warn("seeking to proper position\n");			/* does no good if stdout is a pipe */			Bseek(&bout, d->length - tot, 1);		}	}	if(fskind == Archive)		return;	remove(newfile);	nulldir(&nd);	nd.mode = d->mode;	nd.gid = d->gid;	nd.mtime = d->mtime;	nd.name = d->name;	if(dirfwstat(t, &nd) < 0)		error("can't move tmp file to %q: %r", newfile);	nulldir(&nd);	nd.uid = d->uid;	dirfwstat(t, &nd);	close(t);} voidmkdir(Dir *d){	Dir *d1;	Dir nd;	int fd; 	if(fskind == Archive){		arch(d);		return;	}	fd = create(newfile, OREAD, d->mode);	nulldir(&nd);	nd.mode = d->mode;	nd.gid = d->gid;	nd.mtime = d->mtime;	if(fd < 0){		if((d1 = dirstat(newfile)) == nil || !(d1->mode & DMDIR)){			free(d1);			error("can't create %q", newfile);		}		free(d1);		if(dirwstat(newfile, &nd) < 0)			warn("can't set modes for %q: %r", newfile);		nulldir(&nd);		nd.uid = d->uid;		dirwstat(newfile, &nd);		return;	}	if(dirfwstat(fd, &nd) < 0)		warn("can't set modes for %q: %r", newfile);	nulldir(&nd);	nd.uid = d->uid;	dirfwstat(fd, &nd);	close(fd);} voidarch(Dir *d){	Bprint(&bout, "%q %luo %q %q %lud %lld\n",		newfile, d->mode, d->uid, d->gid, d->mtime, d->length);} char *mkpath(char *prefix, char *elem){	char *p;	int n; 	n = strlen(prefix) + strlen(elem) + 2;	p = emalloc(n);	sprint(p, "%s/%s", prefix, elem);	return p;}

Lines 1–500 of 867.