Ejemplo n.º 1
0
int
vtfileflush(VtFile *f)
{
	int ret;
	VtBlock *b;
	VtEntry e;

	assert(ISLOCKED(f));
	b = fileload(f, &e);
	if(!(e.flags&VtEntryLocal)){
		vtblockput(b);
		return 0;
	}

	ret = flushblock(f->c, nil, e.score, e.psize/VtScoreSize, e.dsize/VtEntrySize,
		e.type);
	if(ret < 0){
		vtblockput(b);
		return -1;
	}

	vtentrypack(&e, b->data, f->offset % f->epb);
	vtblockput(b);
	return 0;
}
Ejemplo n.º 2
0
VtBlock *
vtfileblock(VtFile *r, u32int bn, int mode)
{
	VtBlock *b, *bb;
	int index[VtPointerDepth+1];
	VtEntry e;
	int i;
	int m;

	assert(ISLOCKED(r));
	assert(bn != NilBlock);

	b = fileload(r, &e);
	if(b == nil)
		return nil;

	i = mkindices(&e, bn, index);
	if(i < 0)
		goto Err;
	if(i > DEPTH(e.type)){
		if(mode == VtOREAD){
			werrstr("bad address 0x%lux", (ulong)bn);
			goto Err;
		}
		index[i] = 0;
		if(growdepth(r, b, &e, i) < 0)
			goto Err;
	}

assert(b->type == VtDirType);

	index[DEPTH(e.type)] = r->offset % r->epb;

	/* mode for intermediate block */
	m = mode;
	/* why is this here? *
	if(m == VtOWRITE)
		m = VtORDWR;
	* well we disable it */

	for(i=DEPTH(e.type); i>=0; i--){
		bb = blockwalk(b, index[i], r->c, i==0 ? mode : m, &e);
		if(bb == nil)
			goto Err;
		vtblockput(b);
		b = bb;
	}
	b->pc = getcallerpc(&r);
	return b;
Err:
	vtblockput(b);
	return nil;
}
Ejemplo n.º 3
0
int
vtfileblockscore(VtFile *r, u32int bn, uchar score[VtScoreSize])
{
	VtBlock *b, *bb;
	int index[VtPointerDepth+1];
	VtEntry e;
	int i;

	assert(ISLOCKED(r));
	assert(bn != NilBlock);

	b = fileload(r, &e);
	if(b == nil)
		return -1;

	if(DEPTH(e.type) == 0){
		memmove(score, e.score, VtScoreSize);
		vtblockput(b);
		return 0;
	}

	i = mkindices(&e, bn, index);
	if(i < 0){
		vtblockput(b);
		return -1;
	}
	if(i > DEPTH(e.type)){
		memmove(score, vtzeroscore, VtScoreSize);
		vtblockput(b);
		return 0;
	}

	index[DEPTH(e.type)] = r->offset % r->epb;

	for(i=DEPTH(e.type); i>=1; i--){
		bb = blockwalk(b, index[i], r->c, VtOREAD, &e);
		if(bb == nil)
			goto Err;
		vtblockput(b);
		b = bb;
		if(memcmp(b->score, vtzeroscore, VtScoreSize) == 0)
			break;
	}

	memmove(score, b->data+index[0]*VtScoreSize, VtScoreSize);
	vtblockput(b);
	return 0;

Err:
	vtblockput(b);
	return -1;
}
Ejemplo n.º 4
0
int
vtfilegetentry(VtFile *r, VtEntry *e)
{
	VtBlock *b;

	assert(ISLOCKED(r));
	b = fileload(r, e);
	if(b == nil)
		return -1;
	vtblockput(b);

	return 0;
}
Ejemplo n.º 5
0
int
vtfilesetentry(VtFile *r, VtEntry *e)
{
	VtBlock *b;
	VtEntry ee;

	assert(ISLOCKED(r));
	b = fileload(r, &ee);
	if(b == nil)
		return -1;
	vtentrypack(e, b->data, r->offset % r->epb);
	vtblockput(b);
	return 0;
}
Ejemplo n.º 6
0
uvlong
vtfilegetsize(VtFile *r)
{
	VtEntry e;
	VtBlock *b;

	assert(ISLOCKED(r));
	b = fileload(r, &e);
	if(b == nil)
		return ~(uvlong)0;
	vtblockput(b);

	return e.size;
}
Ejemplo n.º 7
0
int
vtfilesetsize(VtFile *r, u64int size)
{
	int depth, edepth;
	VtEntry e;
	VtBlock *b;

	assert(ISLOCKED(r));
	if(size == 0)
		return vtfiletruncate(r);

	if(size > VtMaxFileSize || size > ((uvlong)MaxBlock)*r->dsize){
		werrstr(ETooBig);
		return -1;
	}

	b = fileload(r, &e);
	if(b == nil)
		return -1;

	/* quick out */
	if(e.size == size){
		vtblockput(b);
		return 0;
	}

	depth = sizetodepth(size, e.psize, e.dsize);
	edepth = DEPTH(e.type);
	if(depth < edepth){
		if(shrinkdepth(r, b, &e, depth) < 0){
			vtblockput(b);
			return -1;
		}
	}else if(depth > edepth){
		if(growdepth(r, b, &e, depth) < 0){
			vtblockput(b);
			return -1;
		}
	}

	if(size < e.size)
		shrinksize(r, &e, size);

	e.size = size;
	vtentrypack(&e, b->data, r->offset % r->epb);
	vtblockput(b);

	return 0;
}
Ejemplo n.º 8
0
static int
vtfilekill(VtFile *r, int doremove)
{
	VtEntry e;
	VtBlock *b;

	assert(ISLOCKED(r));
	b = fileload(r, &e);
	if(b == nil)
		return -1;

	if(doremove==0 && e.size == 0){
		/* already truncated */
		vtblockput(b);
		return 0;
	}

	if(doremove){
		if(e.gen != ~0)
			e.gen++;
		e.dsize = 0;
		e.psize = 0;
		e.flags = 0;
	}else
		e.flags &= ~VtEntryLocal;
	e.type = 0;
	e.size = 0;
	memmove(e.score, vtzeroscore, VtScoreSize);
	vtentrypack(&e, b->data, r->offset % r->epb);
	vtblockput(b);

	if(doremove){
		vtfileunlock(r);
		vtfileclose(r);
	}

	return 0;
}
Ejemplo n.º 9
0
uint
textload(Text *t, uint q0, char *file, int setqid)
{
	Rune *rp;
	Dirlist *dl, **dlp;
	int fd, i, j, n, ndl, nulls;
	uint q, q1;
	Dir *d, *dbuf;
	char *tmp;
	Text *u;

	if(t->ncache!=0 || t->file->nc || t->w==nil || t!=&t->w->body)
		error("text.load");
	if(t->w->isdir && t->file->nname==0){
		warning(nil, "empty directory name\n");
		return 0;
	}
	fd = open(file, OREAD);
	if(fd < 0){
		warning(nil, "can't open %s: %r\n", file);
		return 0;
	}
	d = dirfstat(fd);
	if(d == nil){
		warning(nil, "can't fstat %s: %r\n", file);
		goto Rescue;
	}
	nulls = FALSE;
	if(d->qid.type & QTDIR){
		/* this is checked in get() but it's possible the file changed underfoot */
		if(t->file->ntext > 1){
			warning(nil, "%s is a directory; can't read with multiple windows on it\n", file);
			goto Rescue;
		}
		t->w->isdir = TRUE;
		t->w->filemenu = FALSE;
		if(t->file->name[t->file->nname-1] != '/'){
			rp = runemalloc(t->file->nname+1);
			runemove(rp, t->file->name, t->file->nname);
			rp[t->file->nname] = '/';
			winsetname(t->w, rp, t->file->nname+1);
			free(rp);
		}
		dlp = nil;
		ndl = 0;
		dbuf = nil;
		while((n=dirread(fd, &dbuf)) > 0){
			for(i=0; i<n; i++){
				dl = emalloc(sizeof(Dirlist));
				j = strlen(dbuf[i].name);
				tmp = emalloc(j+1+1);
				memmove(tmp, dbuf[i].name, j);
				if(dbuf[i].qid.type & QTDIR)
					tmp[j++] = '/';
				tmp[j] = '\0';
				dl->r = bytetorune(tmp, &dl->nr);
				dl->wid = stringwidth(t->font, tmp);
				free(tmp);
				ndl++;
				dlp = realloc(dlp, ndl*sizeof(Dirlist*));
				dlp[ndl-1] = dl;
			}
			free(dbuf);
		}
		qsort(dlp, ndl, sizeof(Dirlist*), dircmp);
		t->w->dlp = dlp;
		t->w->ndl = ndl;
		textcolumnate(t, dlp, ndl);
		q1 = t->file->nc;
	}else{
		t->w->isdir = FALSE;
		t->w->filemenu = TRUE;
		q1 = q0 + fileload(t->file, q0, fd, &nulls);
	}
	if(setqid){
		t->file->dev = d->dev;
		t->file->mtime = d->mtime;
		t->file->qidpath = d->qid.path;
	}
	close(fd);
	rp = fbufalloc();
	for(q=q0; q<q1; q+=n){
		n = q1-q;
		if(n > RBUFSIZE)
			n = RBUFSIZE;
		bufread(t->file, q, rp, n);
		if(q < t->org)
			t->org += n;
		else if(q <= t->org+t->nchars)
			frinsert(t, rp, rp+n, q-t->org);
		if(t->lastlinefull)
			break;
	}
	fbuffree(rp);
	for(i=0; i<t->file->ntext; i++){
		u = t->file->text[i];
		if(u != t){
			if(u->org > u->file->nc)	/* will be 0 because of reset(), but safety first */
				u->org = 0;
			textresize(u, u->all);
			textbacknl(u, u->org, 0);	/* go to beginning of line */
		}
		textsetselect(u, q0, q0);
	}
	if(nulls)
		warning(nil, "%s: NUL bytes elided\n", file);
	free(d);
	return q1-q0;

    Rescue:
	close(fd);
	return 0;
}
Ejemplo n.º 10
0
int
vtfileflushbefore(VtFile *r, u64int offset)
{
	VtBlock *b, *bb;
	VtEntry e;
	int i, base, depth, ppb, epb, doflush;
	int index[VtPointerDepth+1], j, ret;
	VtBlock *bi[VtPointerDepth+2];
	uchar *score;

	assert(ISLOCKED(r));
	if(offset == 0)
		return 0;

	b = fileload(r, &e);
	if(b == nil)
		return -1;

	/*
	 * compute path through tree for the last written byte and the next one.
	 */
	ret = -1;
	memset(bi, 0, sizeof bi);
	depth = DEPTH(e.type);
	bi[depth+1] = b;
	i = mkindices(&e, (offset-1)/e.dsize, index);
	if(i < 0)
		goto Err;
	if(i > depth)
		goto Err;
	ppb = e.psize / VtScoreSize;
	epb = e.dsize / VtEntrySize;

	/*
	 * load the blocks along the last written byte
	 */
	index[depth] = r->offset % r->epb;
	for(i=depth; i>=0; i--){
		bb = blockwalk(b, index[i], r->c, VtORDWR, &e);
		if(bb == nil)
			goto Err;
		bi[i] = bb;
		b = bb;
	}
	ret = 0;

	/*
	 * walk up the path from leaf to root, flushing anything that
	 * has been finished.
	 */
	base = e.type&~VtTypeDepthMask;
	for(i=0; i<=depth; i++){
		doflush = 0;
		if(i == 0){
			/* leaf: data or dir block */
			if(offset%e.dsize == 0)
				doflush = 1;
		}else{
			/*
			 * interior node: pointer blocks.
			 * specifically, b = bi[i] is a block whose index[i-1]'th entry 
			 * points at bi[i-1].  
			 */
			b = bi[i];

			/*
			 * the index entries up to but not including index[i-1] point at 
			 * finished blocks, so flush them for sure.
			 */
			for(j=0; j<index[i-1]; j++)
				if(flushblock(r->c, nil, b->data+j*VtScoreSize, ppb, epb, base+i-1) < 0)
					goto Err;

			/*
			 * if index[i-1] is the last entry in the block and is global
			 * (i.e. the kid is flushed), then we can flush this block.
			 */
			if(j==ppb-1 && vtglobaltolocal(b->data+j*VtScoreSize)==NilBlock)
				doflush = 1;
		}
		if(doflush){
			if(i == depth)
				score = e.score;
			else
				score = bi[i+1]->data+index[i]*VtScoreSize;
			if(flushblock(r->c, bi[i], score, ppb, epb, base+i) < 0)
				goto Err;
		}
	}

Err:
	/* top: entry.  do this always so that the score is up-to-date */
	vtentrypack(&e, bi[depth+1]->data, index[depth]);
	for(i=0; i<nelem(bi); i++)
		if(bi[i])
			vtblockput(bi[i]);
	return ret;
}