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

📄 mkfs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#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;}char *strdup(char *s){	char *t;	t = emalloc(strlen(s) + 1);	return strcpy(t, s);}voidsetnames(File *f){	sprint(newfile, "%s%s", newroot, f->new);	if(f->old){		if(f->old[0] == '/')			sprint(oldfile, "%s%s", oldroot, f->old);		else			strcpy(oldfile, f->old);	}else		sprint(oldfile, "%s%s", oldroot, f->new);	if(strlen(newfile) >= sizeof newfile 	|| strlen(oldfile) >= sizeof oldfile)		error("name overfile");}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 */voidskipdir(void){	char *p, c;	int level;	if(indent < 0 || b == nil)	/* b is nil when copying adm/users */		return;	level = indent;	for(;;){		indent = 0;		p = Brdline(b, '\n');		lineno++;		if(!p){			indent = -1;			return;		}		while((c = *p++) != '\n')			if(c == ' ')				indent++;			else if(c == '\t')				indent += 8;			else				break;		if(indent <= level){			Bseek(b, -Blinelen(b), 1);			lineno--;			return;		}	}}File*getfile(File *old){	File *f;	char *elem;	char *p;	int c;	if(indent < 0)		return 0;loop:	indent = 0;	p = Brdline(b, '\n');	lineno++;	if(!p){		indent = -1;		return 0;	}	while((c = *p++) != '\n')		if(c == ' ')			indent++;		else if(c == '\t')			indent += 8;		else			break;	if(c == '\n' || c == '#')		goto loop;	p--;	f = emalloc(sizeof *f);	p = getname(p, &elem);	if(debug)		fprint(2, "getfile: %q root %q\n", elem, old->new);	f->new = mkpath(old->new, elem);	f->elem = utfrrune(f->new, L'/') + 1;	p = getmode(p, &f->mode);	p = getname(p, &f->uid);	if(!*f->uid)		f->uid = "-";	p = getname(p, &f->gid);	if(!*f->gid)		f->gid = "-";	f->old = getpath(p);	if(f->old && strcmp(f->old, "-") == 0){		free(f->old);		f->old = 0;	}	setnames(f);	if(debug)		printfile(f);	return f;}char*getpath(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(n + 1);	memcpy(new, p, n);	new[n] = 0;	return new;}char*getname(char *p, char **buf){	char *s, *start;	int c;	while((c = *p) == ' ' || c == '\t')		p++;	start = p;	while((c = *p) != '\n' && c != ' ' && c != '\t' && c != '\0')		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("can't read environment variable %q", *buf+1);			skipdir();			free(*buf);			return nil;		}		free(*buf);		*buf = s;	}	return p;}char*getmode(char *p, ulong *xmode){	char *buf, *s;	ulong m;	*xmode = ~0;	p = getname(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("bad mode specification %q", buf);		free(buf);		return p;	}	*xmode = m | strtoul(s, 0, 8);	free(buf);	return p;}voidsetusers(void){	File file;	int m;	if(fskind != Kfs)		return;	m = modes;	modes = 1;	file.uid = "adm";	file.gid = "adm";	file.mode = DMDIR|0775;	file.new = "/adm";	file.elem = "adm";	file.old = 0;	setnames(&file);	strcpy(oldfile, file.new);	/* Don't use root for /adm */	mkfile(&file);	file.new = "/adm/users";	file.old = users;	file.elem = "users";	file.mode = 0664;	setnames(&file);	if (file.old)		strcpy(oldfile, file.old);	/* Don't use root for /adm/users */	mkfile(&file);	kfscmd("user");	mkfile(&file);	file.mode = DMDIR|0775;	file.new = "/adm";	file.old = "/adm";	file.elem = "adm";	setnames(&file);	strcpy(oldfile, file.old);	/* Don't use root for /adm */	mkfile(&file);	modes = m;}voidmountkfs(char *name){	char kname[64];	if(fskind != Kfs)		return;	if(name[0])		snprint(kname, sizeof kname, "/srv/kfs.%s", name);	else		strcpy(kname, "/srv/kfs");	sfd = open(kname, ORDWR);	if(sfd < 0){		fprint(2, "can't open %q\n", kname);		exits("open /srv/kfs");	}	if(mount(sfd, -1, "/n/kfs", MREPL|MCREATE, "") < 0){		fprint(2, "can't mount kfs on /n/kfs\n");		exits("mount kfs");	}	close(sfd);	strcat(kname, ".cmd");	sfd = open(kname, ORDWR);	if(sfd < 0){		fprint(2, "can't open %q\n", kname);		exits("open /srv/kfs");	}}voidkfscmd(char *cmd){	char buf[4*1024];	int n;	if(fskind != Kfs)		return;	if(write(sfd, cmd, strlen(cmd)) != strlen(cmd)){		fprint(2, "%q: error writing %q: %r", prog, cmd);		return;	}	for(;;){		n = read(sfd, buf, sizeof buf - 1);		if(n <= 0)			return;		buf[n] = '\0';		if(strcmp(buf, "done") == 0 || strcmp(buf, "success") == 0)			return;		if(strcmp(buf, "unknown command") == 0){			fprint(2, "%q: command %q not recognized\n", prog, cmd);			return;		}	}}void *emalloc(ulong n){	void *p;	if((p = malloc(n)) == 0)		error("out of memory");	return p;}voiderror(char *fmt, ...){	char buf[1024];	va_list arg;	sprint(buf, "%q: %q:%d: ", prog, proto, lineno);	va_start(arg, fmt);	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);	va_end(arg);	fprint(2, "%s\n", buf);	kfscmd("disallow");	kfscmd("sync");	exits(0);}voidwarn(char *fmt, ...){	char buf[1024];	va_list arg;	sprint(buf, "%q: %q:%d: ", prog, proto, lineno);	va_start(arg, fmt);	vseprint(buf+strlen(buf), buf+sizeof(buf), fmt, arg);	va_end(arg);	fprint(2, "%s\n", buf);}voidprintfile(File *f){	if(f->old)		fprint(2, "%q from %q %q %q %lo\n", f->new, f->old, f->uid, f->gid, f->mode);	else		fprint(2, "%q %q %q %lo\n", f->new, f->uid, f->gid, f->mode);}voidusage(void){	fprint(2, "usage: %q [-aprvx] [-d root] [-n name] [-s source] [-u users] [-z n] proto ...\n", prog);	exits("usage");}

⌨️ 快捷键说明

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