コード例 #1
0
ファイル: vac.c プロジェクト: dancrossnyc/harvey
void
vacstdin(VacFile *fp, char *name)
{
	int64_t off;
	VacFile *f;
	static char buf[8192];
	int n;

	if((f = vacfilecreate(fp, name, 0666)) == nil){
		warn("vacfilecreate %s: %r", name);
		return;
	}

	off = 0;
	while((n = read(0, buf, sizeof buf)) > 0){
		if(vacfilewrite(f, buf, n, off) < 0){
			warn("venti write %s: %r", name);
			vacfiledecref(f);
			return;
		}
		off += n;
	}
	vacfileflush(f, 1);
	vacfiledecref(f);
}
コード例 #2
0
ファイル: vacfs.c プロジェクト: npe9/harvey
char *
rremove(Fid *f)
{
	VacFile *vf, *vfp;
	char errbuf[80];
	char *err = nil;

	if(!f->busy)
		return vtstrdup(Enotexist);
	vf = f->file;
	vfp = vacfilegetparent(vf);

	if(!permf(vfp, f->user, Pwrite)) {
		err = Eperm;
		goto Exit;
	}

	if(!vacfileremove(vf)) {
		rerrstr(errbuf, sizeof errbuf);
		err = errbuf;
	}

Exit:
	vacfiledecref(vfp);
	rclunk(f);
	return vtstrdup(err);
}
コード例 #3
0
ファイル: vacfs.c プロジェクト: npe9/harvey
char*
rcreate(Fid* fid)
{
	VacFile *vf;
	uint32_t mode;

	if(fid->open)
		return vtstrdup(Eisopen);
	if(!fid->busy)
		return vtstrdup(Enotexist);
	if(fs->mode & ModeSnapshot)
		return vtstrdup(Erdonly);
	vf = fid->file;
	if(!vacfileisdir(vf))
		return vtstrdup(Enotdir);
	if(!permf(vf, fid->user, Pwrite))
		return vtstrdup(Eperm);

	mode = rhdr.perm & 0777;

	if(rhdr.perm & DMDIR){
		if((rhdr.mode & OTRUNC) || (rhdr.perm & DMAPPEND))
			return vtstrdup(Emode);
		switch(rhdr.mode & OPERM){
		default:
			return vtstrdup(Emode);
		case OEXEC:
		case OREAD:
			break;
		case OWRITE:
		case ORDWR:
			return vtstrdup(Eperm);
		}
		mode |= ModeDir;
	}
	vf = vacfilecreate(vf, rhdr.name, mode);
	if(vf == nil) {
		char err[80];
		rerrstr(err, sizeof err);

		return vtstrdup(err);
	}

	vacfiledecref(fid->file);

	fid->file = vf;
	fid->qid.type = QTFILE;
	if(vacfileisdir(vf))
		fid->qid.type = QTDIR;
	fid->qid.vers = vacfilegetmcount(vf);
	fid->qid.path = vacfilegetid(vf);

	thdr.qid = fid->qid;
	thdr.iounit = messagesize - IOHDRSZ;

	return 0;
}
コード例 #4
0
ファイル: vacfs.c プロジェクト: npe9/harvey
char *
rclunk(Fid *f)
{
	f->busy = 0;
	f->open = 0;
	vtfree(f->user);
	f->user = nil;
	if(f->file)
		vacfiledecref(f->file);
	f->file = nil;
	vdeclose(f->vde);
	f->vde = nil;
	return 0;
}
コード例 #5
0
ファイル: vacfs.c プロジェクト: npe9/harvey
char *
rstat(Fid *f)
{
	VacDir dir;
	static uint8_t statbuf[1024];
	VacFile *parent;
	
	if(!f->busy)
		return vtstrdup(Enotexist);
	parent = vacfilegetparent(f->file);
	vacfilegetdir(f->file, &dir);
	thdr.stat = statbuf;
	thdr.nstat = vacstat(parent, &dir, thdr.stat, sizeof statbuf);
	vdcleanup(&dir);
	vacfiledecref(parent);
	return 0;
}
コード例 #6
0
ファイル: vac.c プロジェクト: dancrossnyc/harvey
int
vacmerge(VacFile *fp, char *name)
{
	VacFs *mfs;
	VacDir vd;
	VacDirEnum *de;
	VacFile *mp;
	uint64_t maxqid, offset;

	if(strlen(name) < 4 || strcmp(name+strlen(name)-4, ".vac") != 0)
		return -1;
	if((mfs = vacfsopen(z, name, VtOREAD, 100)) == nil)
		return -1;
	if(verbose)
		fprint(2, "merging %s\n", name);

	mp = vacfsgetroot(mfs);
	de = vdeopen(mp);
	if(de){
		offset = 0;
		if(vacfsgetmaxqid(mfs, &maxqid) >= 0){
			_vacfsnextqid(fs, &offset);
			vacfsjumpqid(fs, maxqid+1);
		}
		while(vderead(de, &vd) > 0){
			if(vd.qid > maxqid){
				warn("vacmerge %s: maxqid=%lld but %s has %lld",
					name, maxqid, vd.elem, vd.qid);
				vacfsjumpqid(fs, vd.qid - maxqid);
				maxqid = vd.qid;
			}
			vacmergefile(fp, mp, &vd, name,
				offset, maxqid);
			vdcleanup(&vd);
		}
		vdeclose(de);
	}
	vacfiledecref(mp);
	vacfsclose(mfs);
	return 0;
}
コード例 #7
0
ファイル: vac.c プロジェクト: dancrossnyc/harvey
/*
 * fp is the directory we're writing.
 * mp is the directory whose contents we're merging in.
 * d is the directory entry of the file from mp that we want to add to fp.
 * vacfile is the name of the .vac file, for error messages.
 * offset is the qid that qid==0 in mp should correspond to.
 * max is the maximum qid we expect to see (not really needed).
 */
int
vacmergefile(VacFile *fp, VacFile *mp, VacDir *d, char *vacfile,
	int64_t offset, int64_t max)
{
	VtEntry ed, em;
	VacFile *mf;
	VacFile *f;

	mf = vacfilewalk(mp, d->elem);
	if(mf == nil){
		warn("could not walk %s in %s", d->elem, vacfile);
		return -1;
	}
	if(vacfilegetentries(mf, &ed, &em) < 0){
		warn("could not get entries for %s in %s", d->elem, vacfile);
		vacfiledecref(mf);
		return -1;
	}

	if((f = vacfilecreate(fp, d->elem, d->mode)) == nil){
		warn("vacfilecreate %s: %r", d->elem);
		vacfiledecref(mf);
		return -1;
	}
	if(d->qidspace){
		d->qidoffset += offset;
		d->qidmax += offset;
	}else{
		d->qidspace = 1;
		d->qidoffset = offset;
		d->qidmax = max;
	}
	if(vacfilesetdir(f, d) < 0
	|| vacfilesetentries(f, &ed, &em) < 0
	|| vacfilesetqidspace(f, d->qidoffset, d->qidmax) < 0){
		warn("vacmergefile %s: %r", d->elem);
		vacfiledecref(mf);
		vacfiledecref(f);
		return -1;
	}

	vacfiledecref(mf);
	vacfiledecref(f);
	return 0;
}
コード例 #8
0
ファイル: vac.c プロジェクト: dancrossnyc/harvey
void
threadmain(int argc, char **argv)
{
	int i, j, fd, n, printstats;
	Dir *d;
	char *s;
	uint64_t u;
	VacFile *f, *fdiff;
	VacFs *fsdiff;
	int blocksize;
	int outfd;
	char *stdinname;
	char *diffvac;
	uint64_t qid;


	fmtinstall('F', vtfcallfmt);
	fmtinstall('H', encodefmt);
	fmtinstall('V', vtscorefmt);

	blocksize = BlockSize;
	stdinname = nil;
	printstats = 0;
	fsdiff = nil;
	diffvac = nil;

	ARGBEGIN{
	case 'V':
		chattyventi++;
		break;
	case 'a':
		archivefile = EARGF(usage());
		break;
	case 'b':
		u = unittoull(EARGF(usage()));
		if(u < 512)
			u = 512;
		if(u > VtMaxLumpSize)
			u = VtMaxLumpSize;
		blocksize = u;
		break;
	case 'd':
		diffvac = EARGF(usage());
		break;
	case 'e':
		excludepattern(EARGF(usage()));
		break;
	case 'f':
		vacfile = EARGF(usage());
		break;
	case 'h':
		host = EARGF(usage());
		break;
	case 'i':
		stdinname = EARGF(usage());
		break;
	case 'm':
		merge++;
		break;
	case 'q':
		qdiff++;
		break;
	case 's':
		printstats++;
		break;
	case 'v':
		verbose++;
		break;
	case 'x':
		loadexcludefile(EARGF(usage()));
		break;
	default:
		usage();
	}ARGEND

	if(argc == 0 && !stdinname)
		usage();

	if(archivefile && (vacfile || diffvac)){
		fprint(2, "cannot use -a with -f, -d\n");
		usage();
	}

	z = vtdial(host);
	if(z == nil)
		sysfatal("could not connect to server: %r");
	if(vtconnect(z) < 0)
		sysfatal("vtconnect: %r");

	// Setup:
	//	fs is the output vac file system
	//	f is directory in output vac to write new files
	//	fdiff is corresponding directory in existing vac
	if(archivefile){
		VacFile *fp;
		char yyyy[5];
		char mmdd[10];
		char oldpath[40];
		Tm tm;

		fdiff = nil;
		if((outfd = open(archivefile, ORDWR)) < 0){
			if(access(archivefile, 0) >= 0)
				sysfatal("open %s: %r", archivefile);
			if((outfd = create(archivefile, OWRITE, 0666)) < 0)
				sysfatal("create %s: %r", archivefile);
			atexit(removevacfile);	// because it is new
			if((fs = vacfscreate(z, blocksize, 512)) == nil)
				sysfatal("vacfscreate: %r");
		}else{
			if((fs = vacfsopen(z, archivefile, VtORDWR, 512)) == nil)
				sysfatal("vacfsopen %s: %r", archivefile);
			if((fdiff = recentarchive(fs, oldpath)) != nil){
				if(verbose)
					fprint(2, "diff %s\n", oldpath);
			}else
				if(verbose)
					fprint(2, "no recent archive to diff against\n");
		}

		// Create yyyy/mmdd.
		tm = *localtime(time(0));
		snprint(yyyy, sizeof yyyy, "%04d", tm.year+1900);
		fp = vacfsgetroot(fs);
		if((f = vacfilewalk(fp, yyyy)) == nil
		&& (f = vacfilecreate(fp, yyyy, ModeDir|0555)) == nil)
			sysfatal("vacfscreate %s: %r", yyyy);
		vacfiledecref(fp);
		fp = f;

		snprint(mmdd, sizeof mmdd, "%02d%02d", tm.mon+1, tm.mday);
		n = 0;
		while((f = vacfilewalk(fp, mmdd)) != nil){
			vacfiledecref(f);
			n++;
			snprint(mmdd+4, sizeof mmdd-4, ".%d", n);
		}
		f = vacfilecreate(fp, mmdd, ModeDir|0555);
		if(f == nil)
			sysfatal("vacfscreate %s/%s: %r", yyyy, mmdd);
		vacfiledecref(fp);

		if(verbose)
			fprint(2, "archive %s/%s\n", yyyy, mmdd);
	}else{
		if(vacfile == nil)
			outfd = 1;
		else if((outfd = create(vacfile, OWRITE, 0666)) < 0)
			sysfatal("create %s: %r", vacfile);
		atexit(removevacfile);
		if((fs = vacfscreate(z, blocksize, 512)) == nil)
			sysfatal("vacfscreate: %r");
		f = vacfsgetroot(fs);

		fdiff = nil;
		if(diffvac){
			if((fsdiff = vacfsopen(z, diffvac, VtOREAD, 128)) == nil)
				warn("vacfsopen %s: %r", diffvac);
			else
				fdiff = vacfsgetroot(fsdiff);
		}
	}

	if(stdinname)
		vacstdin(f, stdinname);
	for(i=0; i<argc; i++){
		// We can't use / and . and .. and ../.. as valid archive
		// names, so expand to the list of files in the directory.
		if(argv[i][0] == 0){
			warn("empty string given as command-line argument");
			continue;
		}
		cleanname(argv[i]);
		if(strcmp(argv[i], "/") == 0
		|| strcmp(argv[i], ".") == 0
		|| strcmp(argv[i], "..") == 0
		|| (strlen(argv[i]) > 3 && strcmp(argv[i]+strlen(argv[i])-3, "/..") == 0)){
			if((fd = open(argv[i], OREAD)) < 0){
				warn("open %s: %r", argv[i]);
				continue;
			}
			while((n = dirread(fd, &d)) > 0){
				for(j=0; j<n; j++){
					s = vtmalloc(strlen(argv[i])+1+strlen(d[j].name)+1);
					strcpy(s, argv[i]);
					strcat(s, "/");
					strcat(s, d[j].name);
					cleanname(s);
					vac(f, fdiff, s, &d[j]);
				}
				free(d);
			}
			close(fd);
			continue;
		}
		if((d = dirstat(argv[i])) == nil){
			warn("stat %s: %r", argv[i]);
			continue;
		}
		vac(f, fdiff, argv[i], d);
		free(d);
	}
	if(fdiff)
		vacfiledecref(fdiff);

	/*
	 * Record the maximum qid so that vacs can be merged
	 * without introducing overlapping qids.  Older versions
	 * of vac arranged that the root would have the largest
	 * qid in the file system, but we can't do that anymore
	 * (the root gets created first!).
	 */
	if(_vacfsnextqid(fs, &qid) >= 0)
		vacfilesetqidspace(f, 0, qid);
	vacfiledecref(f);

	/*
	 * Copy fsdiff's root block score into fs's slot for that,
	 * so that vacfssync will copy it into root.prev for us.
	 * Just nice documentation, no effect.
	 */
	if(fsdiff)
		memmove(fs->score, fsdiff->score, VtScoreSize);
	if(vacfssync(fs) < 0)
		fprint(2, "vacfssync: %r\n");

	fprint(outfd, "vac:%V\n", fs->score);
	atexitdont(removevacfile);
	vacfsclose(fs);
	vthangup(z);

	if(printstats){
		fprint(2,
			"%d files, %d files skipped, %d directories\n"
			"%lld data bytes written, %lld data bytes skipped\n",
			stats.nfile, stats.skipfiles, stats.ndir, stats.data, stats.skipdata);
		dup(2, 1);
		packetstats();
	}
	threadexitsall(0);
}
コード例 #9
0
ファイル: vac.c プロジェクト: dancrossnyc/harvey
/*
 * Archive the file named name, which has stat info d,
 * into the vac directory fp (p = parent).
 *
 * If we're doing a vac -d against another archive, the
 * equivalent directory to fp in that archive is diffp.
 */
void
vac(VacFile *fp, VacFile *diffp, char *name, Dir *d)
{
	char *elem, *s;
	static char buf[65536];
	int fd, i, n, bsize;
	int64_t off;
	Dir *dk;	// kids
	VacDir vd, vddiff;
	VacFile *f, *fdiff;
	VtEntry e;

	if(!includefile(name)){
		warn("excluding %s%s", name, (d->mode&DMDIR) ? "/" : "");
		return;
	}

	if(d->mode&DMDIR)
		stats.ndir++;
	else
		stats.nfile++;

	if(merge && vacmerge(fp, name) >= 0)
		return;

	if(verbose)
		fprint(2, "%s%s\n", name, (d->mode&DMDIR) ? "/" : "");

	if((fd = open(name, OREAD)) < 0){
		warn("open %s: %r", name);
		return;
	}

	elem = strrchr(name, '/');
	if(elem)
		elem++;
	else
		elem = name;

	plan9tovacdir(&vd, d);
	if((f = vacfilecreate(fp, elem, vd.mode)) == nil){
		warn("vacfilecreate %s: %r", name);
		return;
	}
	if(diffp)
		fdiff = vacfilewalk(diffp, elem);
	else
		fdiff = nil;

	if(vacfilesetdir(f, &vd) < 0)
		warn("vacfilesetdir %s: %r", name);

	if(d->mode&DMDIR){
		while((n = dirread(fd, &dk)) > 0){
			for(i=0; i<n; i++){
				s = vtmalloc(strlen(name)+1+strlen(dk[i].name)+1);
				strcpy(s, name);
				strcat(s, "/");
				strcat(s, dk[i].name);
				vac(f, fdiff, s, &dk[i]);
				free(s);
			}
			free(dk);
		}
	}else{
		off = 0;
		bsize = fs->bsize;
		if(fdiff){
			/*
			 * Copy fdiff's contents into f by moving the score.
			 * We'll diff and update below.
			 */
			if(vacfilegetentries(fdiff, &e, nil) >= 0)
			if(vacfilesetentries(f, &e, nil) >= 0){
				bsize = e.dsize;

				/*
				 * Or if -q is set, and the metadata looks the same,
				 * don't even bother reading the file.
				 */
				if(qdiff && vacfilegetdir(fdiff, &vddiff) >= 0){
					if(vddiff.mtime == vd.mtime)
					if(vddiff.size == vd.size)
					if(!vddiff.plan9 || (/* vddiff.p9path == vd.p9path && */ vddiff.p9version == vd.p9version)){
						stats.skipfiles++;
						stats.nfile--;
						vdcleanup(&vddiff);
						goto Out;
					}

					/*
					 * Skip over presumably-unchanged prefix
					 * of an append-only file.
					 */
					if(vd.mode&ModeAppend)
					if(vddiff.size < vd.size)
					if(vddiff.plan9 && vd.plan9)
					if(vddiff.p9path == vd.p9path){
						off = vd.size/bsize*bsize;
						if(seek(fd, off, 0) >= 0)
							stats.skipdata += off;
						else{
							seek(fd, 0, 0);	// paranoia
							off = 0;
						}
					}

					vdcleanup(&vddiff);
					// XXX different verbose chatty prints for kaminsky?
				}
			}
		}
		if(qdiff && verbose)
			fprint(2, "+%s\n", name);
		while((n = readn(fd, buf, bsize)) > 0){
			if(fdiff && sha1matches(f, off/bsize, (uint8_t*)buf, n)){
				off += n;
				stats.skipdata += n;
				continue;
			}
			if(vacfilewrite(f, buf, n, off) < 0){
				warn("venti write %s: %r", name);
				goto Out;
			}
			stats.data += n;
			off += n;
		}
		/*
		 * Since we started with fdiff's contents,
		 * set the size in case fdiff was bigger.
		 */
		if(fdiff && vacfilesetsize(f, off) < 0)
			warn("vtfilesetsize %s: %r", name);
	}

Out:
	vacfileflush(f, 1);
	vacfiledecref(f);
	if(fdiff)
		vacfiledecref(fdiff);
	close(fd);
}
コード例 #10
0
ファイル: vac.c プロジェクト: dancrossnyc/harvey
VacFile*
recentarchive(VacFs *fs, char *path)
{
	VacFile *fp, *f;
	VacDirEnum *de;
	VacDir vd;
	char buf[10];
	int year, mmdd, nn, n, n1;
	char *p;

	fp = vacfsgetroot(fs);
	de = vdeopen(fp);
	year = 0;
	if(de){
		for(; vderead(de, &vd) > 0; vdcleanup(&vd)){
			if(strlen(vd.elem) != 4)
				continue;
			if((n = strtol(vd.elem, &p, 10)) < 1900 || *p != 0)
				continue;
			if(year < n)
				year = n;
		}
	}
	vdeclose(de);
	if(year == 0){
		vacfiledecref(fp);
		return nil;
	}
	snprint(buf, sizeof buf, "%04d", year);
	if((f = vacfilewalk(fp, buf)) == nil){
		fprint(2, "warning: dirread %s but cannot walk", buf);
		vacfiledecref(fp);
		return nil;
	}
	fp = f;

	de = vdeopen(fp);
	mmdd = 0;
	nn = 0;
	if(de){
		for(; vderead(de, &vd) > 0; vdcleanup(&vd)){
			if(strlen(vd.elem) < 4)
				continue;
			if((n = strtol(vd.elem, &p, 10)) < 100 || n > 1231 || p != vd.elem+4)
				continue;
			if(*p == '.'){
				if(p[1] == '0' || (n1 = strtol(p+1, &p, 10)) == 0 || *p != 0)
					continue;
			}else{
				if(*p != 0)
					continue;
				n1 = 0;
			}
			if(n < mmdd || (n == mmdd && n1 < nn))
				continue;
			mmdd = n;
			nn = n1;
		}
	}
	vdeclose(de);
	if(mmdd == 0){
		vacfiledecref(fp);
		return nil;
	}
	if(nn == 0)
		snprint(buf, sizeof buf, "%04d", mmdd);
	else
		snprint(buf, sizeof buf, "%04d.%d", mmdd, nn);
	if((f = vacfilewalk(fp, buf)) == nil){
		fprint(2, "warning: dirread %s but cannot walk", buf);
		vacfiledecref(fp);
		return nil;
	}
	vacfiledecref(fp);

	sprint(path, "%04d/%s", year, buf);
	return f;
}
コード例 #11
0
ファイル: vacfs.c プロジェクト: npe9/harvey
char*
rwalk(Fid *f)
{
	VacFile *file, *nfile;
	Fid *nf;
	int nqid, nwname;
	Qid qid;
	char *err = nil;

	if(f->busy == 0)
		return Enotexist;
	nf = nil;
	if(rhdr.fid != rhdr.newfid){
		if(f->open)
			return vtstrdup(Eisopen);
		if(f->busy == 0)
			return vtstrdup(Enotexist);
		nf = newfid(rhdr.newfid);
		if(nf->busy)
			return vtstrdup(Eisopen);
		nf->busy = 1;
		nf->open = 0;
		nf->qid = f->qid;
		nf->file = vacfileincref(f->file);
		nf->user = vtstrdup(f->user);
		f = nf;
	}

	nwname = rhdr.nwname;

	/* easy case */
	if(nwname == 0) {
		thdr.nwqid = 0;
		return 0;
	}

	file = f->file;
	vacfileincref(file);
	qid = f->qid;

	for(nqid = 0; nqid < nwname; nqid++){
		if((qid.type & QTDIR) == 0){
			err = Enotdir;
			break;
		}
		if(!permf(file, f->user, Pexec)) {
			err = Eperm;
			break;
		}
		nfile = vacfilewalk(file, rhdr.wname[nqid]);
		if(nfile == nil)
			break;
		vacfiledecref(file);
		file = nfile;
		qid.type = QTFILE;
		if(vacfileisdir(file))
			qid.type = QTDIR;
		qid.vers = vacfilegetmcount(file);
		qid.path = vacfilegetid(file);
		thdr.wqid[nqid] = qid;
	}

	thdr.nwqid = nqid;

	if(nqid == nwname){
		/* success */
		f->qid = thdr.wqid[nqid-1];
		vacfiledecref(f->file);
		f->file = file;
		return 0;
	}

	vacfiledecref(file);
	if(nf != nil)
		rclunk(nf);

	/* only error on the first element */
	if(nqid == 0)
		return vtstrdup(err);

	return 0;
}
コード例 #12
0
ファイル: unvac.c プロジェクト: AustenConrad/plan-9
void
unvac(VacFile *f, char *name, VacDir *vdir)
{
	static char buf[65536];
	int fd, n, m,  bsize;
	ulong mode, mode9;
	char *newname;
	char *what;
	vlong off;
	Dir d, *dp;
	VacDirEnum *vde;
	VacDir newvdir;
	VacFile *newf;

	if(vdir)
		mode = vdir->mode;
	else
		mode = vacfilegetmode(f);

	if(vdir){
		if(table){
			if(chatty){
				mode9 = vdir->mode&0777;
				if(mode&ModeDir)
					mode9 |= DMDIR;
				if(mode&ModeAppend)
					mode9 |= DMAPPEND;
				if(mode&ModeExclusive)
					mode9 |= DMEXCL;
				print("%M %-10s %-10s %11lld %t %s\n",
					mode9, vdir->uid, vdir->gid, vdir->size,
					vdir->mtime, name);
			}else
				print("%s%s\n", name, (mode&ModeDir) ? "/" : "");
		}
		else if(chatty)
			fprint(2, "%s%s\n", name, (mode&ModeDir) ? "/" : "");
	}

	if(mode&(ModeDevice|ModeLink|ModeNamedPipe|ModeExclusive)){
		if(table)
			return;
		if(mode&ModeDevice)
			what = "device";
		else if(mode&ModeLink)
			what = "link";
		else if(mode&ModeNamedPipe)
			what = "named pipe";
		else if(mode&ModeExclusive)
			what = "lock";
		else
			what = "unknown type of file";
		fprint(2, "warning: ignoring %s %s\n", what, name);
		return;
	}
	
	if(mode&ModeDir){
		if((vde = vdeopen(f)) == nil){
			fprint(2, "vdeopen %s: %r", name);
			errors++;
			return;
		}
		if(!table && !tostdout && vdir){
			// create directory
			if((dp = dirstat(name)) == nil){
				if((fd = create(name, OREAD, DMDIR|(mode&0777))) < 0){
					fprint(2, "mkdir %s: %r\n", name);
					vdeclose(vde);
				}
				close(fd);
			}else{
				if(!(dp->mode&DMDIR)){
					fprint(2, "%s already exists and is not a directory\n", name);
					errors++;
					free(dp);
					vdeclose(vde);
					return;
				}
				free(dp);
			}
		}
		while(vderead(vde, &newvdir) > 0){
			if(name == nil)
				newname = newvdir.elem;
			else
				newname = smprint("%s/%s", name, newvdir.elem);
			if(wantfile(newname)){
				if((newf = vacfilewalk(f, newvdir.elem)) == nil){
					fprint(2, "walk %s: %r\n", name);
					errors++;
				}else if(newf == f){
					fprint(2, "walk loop: %s\n", newname);
					vacfiledecref(newf);
				}else{
					unvac(newf, newname, &newvdir);
					vacfiledecref(newf);
				}
			}
			if(newname != newvdir.elem)
				free(newname);
			vdcleanup(&newvdir);
		}
		vdeclose(vde);
	}else{
		if(!table){
			off = 0;
			if(tostdout)
				fd = dup(1, -1);
			else if(diff && (fd = open(name, ORDWR)) >= 0){
				bsize = vacfiledsize(f);
				while((n = readn(fd, buf, bsize)) > 0){
					if(sha1matches(f, off/bsize, (uchar*)buf, n)){
						off += n;
						stats.skipdata += n;
						continue;
					}
					seek(fd, off, 0);
					if((m = vacfileread(f, buf, n, off)) < 0)
						break;
					if(writen(fd, buf, m) != m){
						fprint(2, "write %s: %r\n", name);
						goto Err;
					}
					off += m;
					stats.data += m;
					if(m < n){
						nulldir(&d);
						d.length = off;
						if(dirfwstat(fd, &d) < 0){
							fprint(2, "dirfwstat %s: %r\n", name);
							goto Err;
						}
						break;
					}
				}
			}
			else if((fd = create(name, OWRITE, mode&0777)) < 0){
				fprint(2, "create %s: %r\n", name);
				errors++;
				return;
			}
			while((n = vacfileread(f, buf, sizeof buf, off)) > 0){
				if(writen(fd, buf, n) != n){
					fprint(2, "write %s: %r\n", name);
				Err:
					errors++;
					close(fd);
					remove(name);
					return;
				}
				off += n;
				stats.data += n;
			}
			close(fd);
		}
	}
	if(vdir && settimes && !tostdout){
		nulldir(&d);
		d.mtime = vdir->mtime;
		if(dirwstat(name, &d) < 0)
			fprint(2, "warning: setting mtime on %s: %r", name);
	}
}
コード例 #13
0
ファイル: vacfs.c プロジェクト: 00001/plan9port
int
vacstat(VacFile *parent, VacDir *vd, uchar *p, int np)
{
	int ret;
	Dir dir;
#ifdef PLAN9PORT
	int n;
	VacFile *vf;
	uvlong size;
	char *ext = nil;
#endif

	memset(&dir, 0, sizeof(dir));

	dir.qid.path = vd->qid + vacfilegetqidoffset(parent);
	if(vd->qidspace)
		dir.qid.path += vd->qidoffset;
	dir.qid.vers = vd->mcount;
	dir.mode = vd->mode & 0777;
	if(vd->mode & ModeAppend){
		dir.qid.type |= QTAPPEND;
		dir.mode |= DMAPPEND;
	}
	if(vd->mode & ModeExclusive){
		dir.qid.type |= QTEXCL;
		dir.mode |= DMEXCL;
	}
	if(vd->mode & ModeDir){
		dir.qid.type |= QTDIR;
		dir.mode |= DMDIR;
	}
	
#ifdef PLAN9PORT
	if(vd->mode & (ModeLink|ModeDevice|ModeNamedPipe)){
		vf = vacfilewalk(parent, vd->elem);
		if(vf == nil)
			return 0;
		vacfilegetsize(vf, &size);
		ext = malloc(size+1);
		if(ext == nil)
			return 0;
		n = vacfileread(vf, ext, size, 0);
		USED(n);
		ext[size] = 0;
		vacfiledecref(vf);
		if(vd->mode & ModeLink){
			dir.qid.type |= QTSYMLINK;
			dir.mode |= DMSYMLINK;
		}
		if(vd->mode & ModeDevice)
			dir.mode |= DMDEVICE;
		if(vd->mode & ModeNamedPipe)
			dir.mode |= DMNAMEDPIPE;
	}
#endif
	
	dir.atime = vd->atime;
	dir.mtime = vd->mtime;
	dir.length = vd->size;

	dir.name = vd->elem;
	dir.uid = vd->uid;
	dir.gid = vd->gid;
	dir.muid = vd->mid;

	ret = convD2M(&dir, p, np);
#ifdef PLAN9PORT
	free(ext);
#endif
	return ret;
}