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

📄 mkpaqfs.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include <u.h>#include <libc.h>#include <bio.h>#include <flate.h>#include <mp.h>#include <libsec.h>#include "paqfs.h"enum {	OffsetSize = 4,	/* size of block offset */};void paqfs(char *root, char *label);PaqDir *paqFile(char *name, Dir *dir);PaqDir *paqDir(char *name, Dir *dir);PaqDir *paqDirAlloc(Dir *d, ulong offset);void paqDirFree(PaqDir *pd);void writeHeader(char *label);void writeTrailer(ulong root);ulong writeBlock(uchar *buf, int type);void usage(void);void outWrite(void *buf, int n);int paqDirSize(PaqDir *dir);void putDir(uchar *p, PaqDir *dir);void putHeader(uchar *p, PaqHeader *h);void putBlock(uchar *p, PaqBlock *h);void putTrailer(uchar *p, PaqTrailer *t);void putl(uchar *p, ulong v);void puts(uchar *p, int x);uchar *putstr(uchar *p, char *s);void *emallocz(int size);void warn(char *fmt, ...);int uflag=0;			/* uncompressed */long blocksize = 4*1024;Biobuf *out;DigestState *outdg;voidmain(int argc, char *argv[]){	char *s, *ss;	char *outfile = nil;	char *label = nil;	char *file;	ARGBEGIN {	case 'u':		uflag=1;		break;	case 'o':		outfile = ARGF();		break;	case 'l':		label = ARGF();		if(label == nil)			usage();		break;	case 'b':		s = ARGF();		if(s) {			blocksize = strtoul(s, &ss, 0);			if(s == ss)				usage();			if(*ss == 'k')				blocksize *= 1024;		}		if(blocksize < MinBlockSize)			sysfatal("blocksize too small: must be at lease %d", MinBlockSize);		if(blocksize > MaxBlockSize)			sysfatal("blocksize too large: must be no greater than %d", MaxBlockSize);		break;	} ARGEND	if(outfile == nil) {		out = emallocz(sizeof(Biobuf));		Binit(out, 1, OWRITE);	} else {		out = Bopen(outfile, OWRITE|OTRUNC);		if(out == nil)			sysfatal("could not create file: %s: %r", outfile);	}	deflateinit();	file = argv[0];	if(file == nil)		file = ".";	if(label == nil) {		if(strrchr(file, '/'))			label = strrchr(file, '/') + 1;		else			label = file;	}	paqfs(file, label);	Bterm(out);	exits(0);}voidusage(void){	fprint(2, "usage: %s [-u] [-b blocksize] -o output [root]\n", argv0);	exits("usage");}voidpaqfs(char *root, char *label){	Dir *dir;	PaqDir *pd;	ulong offset;	uchar *buf;	dir = dirstat(root);	if(dir == nil)		sysfatal("could not stat root: %s: %r", root);	writeHeader(label);	if(dir->mode & DMDIR)		pd = paqDir(root, dir);	else		pd = paqFile(root, dir);	buf = emallocz(blocksize);	putDir(buf, pd);	offset = writeBlock(buf, DirBlock);	writeTrailer(offset);	paqDirFree(pd);	free(dir);}PaqDir *paqFile(char *name, Dir *dir){	int fd, n, nn, nb;	vlong tot;	uchar *block, *pointer;	ulong offset;	fd = open(name, OREAD);	if(fd < 0) {		warn("could not open file: %s: %r", name);		return nil;	}	block = emallocz(blocksize);	pointer = emallocz(blocksize);	nb = 0;	n = 0;	tot = 0;	for(;;) {		nn = read(fd, block+n, blocksize-n);		if(nn < 0) {			warn("read failed: %s: %r", name);			goto Err;		}		tot += nn;		if(nn == 0) {				if(n == 0)				break;				/* pad out last block */			memset(block+n, 0, blocksize-n);			nn = blocksize - n;		}		n += nn;		if(n < blocksize)			continue;		if(nb >= blocksize/OffsetSize) {			warn("file too big for blocksize: %s", name);			goto Err;		}		offset = writeBlock(block, DataBlock);		putl(pointer+nb*OffsetSize, offset);		nb++;		n = 0;	}	offset = writeBlock(pointer, PointerBlock);	close(fd);	free(pointer);	free(block);	dir->length = tot;	return paqDirAlloc(dir, offset);Err:	close(fd);	free(pointer);	free(block);	return nil;}PaqDir *paqDir(char *name, Dir *dir){	Dir *dirs, *p;	PaqDir *pd;	int i, n, nb, fd, ndir;	uchar *block, *pointer;	char *nname;	ulong offset;	fd = open(name, OREAD);	if(fd < 0) {		warn("could not open directory: %s: %r", name);		return nil;	}	ndir = dirreadall(fd, &dirs);	close(fd);	if(ndir < 0) {		warn("could not read directory: %s: %r", name);		return nil;	}	block = emallocz(blocksize);	pointer = emallocz(blocksize);	nb = 0;	n = 0;	nname = nil;	pd = nil;	for(i=0; i<ndir; i++) {		p = dirs + i;		free(nname);		nname = emallocz(strlen(name) + strlen(p->name) + 2);		sprint(nname, "%s/%s", name, p->name);		if(p->mode & DMDIR)			pd = paqDir(nname, p);		else			pd = paqFile(nname, p);		if(pd == nil)			continue;		if(n+paqDirSize(pd) >= blocksize) {			/* zero fill the block */			memset(block+n, 0, blocksize-n);			offset = writeBlock(block, DirBlock);			n = 0;			if(nb >= blocksize/OffsetSize) {				warn("directory too big for blocksize: %s", nname);				goto Err;			}			putl(pointer+nb*OffsetSize, offset);			nb++;		}		if(n+paqDirSize(pd) >= blocksize) {			warn("directory entry does not fit in a block: %s", nname);			paqDirFree(pd);			continue;		}		putDir(block+n, pd);		n += paqDirSize(pd);		paqDirFree(pd);		pd = nil;	}	if(n > 0) {		/* zero fill the block */		memset(block+n, 0, blocksize-n);		offset = writeBlock(block, DirBlock);		if(nb >= blocksize/OffsetSize) {			warn("directory too big for blocksize: %s", nname);			goto Err;		}		putl(pointer+nb*OffsetSize, offset);	}	offset = writeBlock(pointer, PointerBlock);	free(nname);	free(dirs);	paqDirFree(pd);	free(block);	free(pointer);	return paqDirAlloc(dir, offset);Err:		free(nname);	free(dirs);	paqDirFree(pd);	free(block);	free(pointer);	return nil;}PaqDir *paqDirAlloc(Dir *dir, ulong offset){	PaqDir *pd;	static ulong qid = 1;	pd = emallocz(sizeof(PaqDir));		pd->name = strdup(dir->name);	pd->qid = qid++;	pd->mode = dir->mode & (DMDIR|DMAPPEND|0777);	pd->mtime = dir->mtime;	pd->length = dir->length;	pd->uid = strdup(dir->uid);	pd->gid = strdup(dir->gid);	pd->offset = offset;	return pd;}voidpaqDirFree(PaqDir *pd){	if(pd == nil)		return;	free(pd->name);	free(pd->uid);	free(pd->gid);	free(pd);}voidwriteHeader(char *label){	PaqHeader hdr;	uchar buf[HeaderSize];	memset(&hdr, 0, sizeof(hdr));	hdr.magic = HeaderMagic;	hdr.version = Version;	hdr.blocksize = blocksize;	hdr.time = time(nil);	strncpy(hdr.label, label, sizeof(hdr.label));	hdr.label[sizeof(hdr.label)-1] = 0;	putHeader(buf, &hdr);	outWrite(buf, sizeof(buf));}voidwriteTrailer(ulong root){	PaqTrailer tlr;	uchar buf[TrailerSize];	memset(&tlr, 0, sizeof(tlr));	tlr.magic = TrailerMagic;	tlr.root = root;	putTrailer(buf, &tlr);	outWrite(buf, sizeof(buf));}ulongwriteBlock(uchar *b, int type){	uchar *cb, *ob;	int n;	PaqBlock bh;	uchar buf[BlockSize];	ulong offset;	offset = Boffset(out);	bh.magic = BlockMagic;	bh.size = blocksize;		bh.type = type;	bh.encoding = NoEnc;	bh.adler32 = adler32(0, b, blocksize);	ob = b;	if(!uflag) {		cb = emallocz(blocksize);		n = deflateblock(cb, blocksize, b, blocksize, 6, 0);		if(n > 0 && n < blocksize) {			bh.encoding = DeflateEnc;			bh.size = n;			ob = cb;		}		}	putBlock(buf, &bh);	outWrite(buf, sizeof(buf));	outWrite(ob, bh.size);		if(ob != b)		free(ob);	return offset;}voidoutWrite(void *buf, int n){	if(Bwrite(out, buf, n) < n)		sysfatal("write failed: %r");	outdg = sha1((uchar*)buf, n, nil, outdg);}intpaqDirSize(PaqDir *d){	return MinDirSize + strlen(d->name) + strlen(d->uid) + strlen(d->gid);}voidputHeader(uchar *p, PaqHeader *h){	if(h->blocksize < 65536){		putl(p, h->magic);		puts(p+4, h->version);		puts(p+6, h->blocksize);	}else{		assert(h->magic == HeaderMagic);		puts(p, BigHeaderMagic);		puts(p+2, h->version);		putl(p+4, h->blocksize);	}	putl(p+8, h->time);	memmove(p+12, h->label, sizeof(h->label));}voidputTrailer(uchar *p, PaqTrailer *h){	putl(p, h->magic);	putl(p+4, h->root);	outdg = sha1(p, 8, p+8, outdg);}voidputBlock(uchar *p, PaqBlock *b){	if(b->size < 65536){		putl(p, b->magic);		puts(p+4, b->size);	}else{		assert(b->magic == BlockMagic);		puts(p, BigBlockMagic);		putl(p+2, b->size);	}	p[6] = b->type;	p[7] = b->encoding;	putl(p+8, b->adler32);}voidputDir(uchar *p, PaqDir *d){	uchar *q;	puts(p, paqDirSize(d));	putl(p+2, d->qid);		putl(p+6, d->mode);	putl(p+10, d->mtime);	putl(p+14, d->length);	putl(p+18, d->offset);	q = putstr(p+22, d->name);	q = putstr(q, d->uid);	q = putstr(q, d->gid);	assert(q-p == paqDirSize(d));}voidputl(uchar *p, ulong v){	p[0] = v>>24;	p[1] = v>>16;	p[2] = v>>8;	p[3] = v;}voidputs(uchar *p, int v){	assert(v < (1<<16));	p[0] = v>>8;	p[1] = v;}uchar *putstr(uchar *p, char *s){	int n = strlen(s);	puts(p, n+2);	memmove(p+2, s, n);	return p+2+n;}void *emallocz(int size){	void *p;	p = malloc(size);	if(p == nil)		sysfatal("malloc failed");	memset(p, 0, size);	return p;}voidwarn(char *fmt, ...){	char buf[1024];	va_list arg;	va_start(arg, fmt);	vseprint(buf, buf+sizeof(buf), fmt, arg);	va_end(arg);	fprint(2, "%s: %s\n", argv0, buf);}

⌨️ 快捷键说明

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