[manual index][section index]

NAME

vac - read/write venti archives

SYNOPSIS

include "vac.m";
vac := load Vac Vac->PATH;
Direntry: import vac;
Source, Vacdir, Vacfile: import vac;
File, Sink, MSink: import vac;

init:		fn();

Direntry: adt {
	new:	fn(): ref Direntry;
	mk:	fn(d: Sys->Dir): ref Direntry;
	mkdir:	fn(de: self ref Direntry): ref Sys->Dir;
	pack:	fn(de: self ref Direntry): array of byte;
	unpack:	fn(d: array of byte): ref Direntry;
};

Source: adt {
	new:	fn(s: ref Venti->Session, e: ref Venti->Entry): ref Source;
	get:	fn(s: self ref Source, i: big, d: array of byte): int;
	oget:	fn(s: self ref Source, offset: big): array of byte;
};

Vacfile: adt {
	mk:	fn(s: ref Source): ref Vacfile;
	new:	fn(session: ref Venti->Session, e: ref Venti->Entry): ref Vacfile;
	read:	fn(v: self ref Vacfile, d: array of byte, n: int): int;
	seek:	fn(v: self ref Vacfile, offset: big): big;
	pread:	fn(v: self ref Vacfile, d: array of byte, n: int, offset: big): int;
};

Vacdir: adt {
	mk:	fn(vf: ref Vacfile, ms: ref Source): ref Vacdir;
	new:	fn(session: ref Venti->Session, e, me: ref Venti->Entry): ref Vacdir;
	walk:	fn(v: self ref Vacdir, elem: string): ref Direntry;
	open:	fn(v: self ref Vacdir, de: ref Direntry):
			(ref Venti->Entry, ref Venti->Entry);
	readdir:	fn(v: self ref Vacdir):
				(int, ref Direntry);
	rewind:	fn(v: self ref Vacdir);
};

File: adt {
	new:	fn(s: ref Venti->Session, dtype, dsize, varblocks: int): ref File;
	write:	fn(f: self ref File, d: array of byte): int;
	finish:	fn(f: self ref File): ref Venti->Entry;
	mkstate:	fn(session: ref Venti->Session, e: ref Venti->Entry, varblocks: int): ref File;
};

Sink: adt {
	new:	fn(s: ref Venti->Session, dsize: int): ref Sink;
	add:	fn(m: self ref Sink, e: ref Venti->Entry): int;
	finish:	fn(m: self ref Sink): ref Venti->Entry;
};

MSink: adt {
	new:	fn(s: ref Venti->Session, dsize: int): ref MSink;
	add:	fn(m: self ref MSink, de: ref Direntry): int;
	finish:	fn(m: self ref MSink): ref Venti->Entry;
};

blocksread, blockswritten, bytesread, byteswritten: big;

openroot:
	fn(session: ref Venti->Session, score: Venti->Score):
		(ref Vacdir, ref Direntry, string);
readscore:
	fn(path: string):
		(string, ref Venti->Score, string);

DESCRIPTION

Vac is a module for reading and writing venti archives. Init initialises the module and must be called before any other function. Adt's Source, Vacfile and Vacdir provide functions for reading venti archives, along with openroot and readscore. Adt's File, Sink and MSink facilitate writing archives.

A Direntry is used for both writing and reading and is the vac equivalent of a Sys->Dir.


Direntry.new()
Returns a new, empty Direntry.
Direntry.mk(dir)
Returns the Direntry equivalent of dir.
d.mkdir()
Returns the Dir equivalent of d.
d.pack()
Packs d into Direntrysize bytes.
Direntry.unpack(data)
Unpacks data into a Direntry.

Source holds a Venti->Entry from which whole blocks of data from the hash tree are read from. The difference with a plain entry is that it has a Venti->Session associated with it.


s.new(session,entry)
Create a new Source from the session and the Entry. Always succeeds.
s.get(index,data)
Read a block from the hash tree into buffer data. Index denotes which data block to read, considering only data blocks (not pointer blocks). The first data block is 0. This function performs zero-extension and only works on entries that do not have the Entryvarblocks bit set.
s.oget(offset)
Read a block from the hash tree starting at offset . The data returned has been zero-extended. This functions also works on Entries with the Entryvarblocks bit set.

Vacfile is a Source with with an offset associated with it. It provides the standard functions read, pread and seek. A Vacfile can be created by Vacfile.mk(source) and Vacfile.new(session,entry). These functions always succeed.

Vacdir represents a directory stored in a venti archive. A venti directory is stored in Venti as two hash trees: one containing Entries representing the (data) contents of files and one containing all meta-information (direntries) for those files. A file in a directory is represented as a Direntry.


vd.mk(vacfile,metasource)
Open a venti directory. Vacfile should contain Entries, metasource should contain Direntries.
vd.new(session,entry,metaentry)
Open a venti directory from a entry and metaentry, such as those as returned by Vacdir.open.
vd.walk(elem)
Return the Direntry representing the file elem. Nil is returned when the file does not exist and the system error string set.
vd.open(direntry)
`Open' the file represented by direntry, by returning its entry and metaentry. The metaentry (second element of the tuple) is nil for files and non-nil for directories.
vd.readdir()
Read files in a directory. The number of direntries returned depends on the block size of the underlying archive. The first element of the tuple has the number of direntries returned and is < 0 for errors, and 0 when all files have been returned.
vd.rewind()
Rewind the directory offset to 0. Subsequent reads again return files.

A File is used for writing files to Venti as hash trees, eventually resulting in an Entry.


f.new(session,dtype,dsize,varblocks)
Start a new, empty file. Dtype is the type of the data being written, typically Venti->Datatype for a regular file. Dsize is the data and pointer block size. Constant Dsize is currently defined to 8192. Varblocks denotes whether the hash tree should be considered to have a variable block size. If it is non-zero, dsize has no meaning for the data block size and is only used for the pointer block size.
f.write(data)
Write data to the hash tree. The data is flushed to venti immediately and considered to be a single data block in the hash tree. Zero-truncation is performed on it. On failure -1 is returned, on success 0 is returned. Pointer blocks that have filled up by this write are flushed as well.
f.finish()
Flush all remaining pointer blocks and the top-level Entry to Venti and return the entry.
f.mkstate(session,entry,varblocks)
Initialise a File from an existing Entry. This can be used to append data to an already existing file.

A Sink is used to write venti directories. It consists of a File to which Entries can be added. Note that Direntries are written using an MSink. Data is only written to the File when a data block has been filled with entries.


s.new(session,dsize)
Make a new, empty directory. The size of the blocks in which entries are stored is dsize.
s.add(entry)
Add an entry to the directory. If a block is filled, it is flushed to Venti.
s.finish()
Flush the underlying file and return the Entry representing the directory.

An MSink is used to write the Direntries of a venti directory. It behaves identical to a Sink, with the difference that function add writes a Direntry by extracting the Entry from it, and another Entry for the meta-information if the Direntry represents a directory.

The variables blocksread, blockswritten, bytesread and byteswritten are kept up to date during module use. They contain the total number of blocks and bytes read from and written to the venti server. Venti protocol overhead is ignored, only the message payloads are accounted for.

Readscore parses a score from the file represented by path. The returned tuple contains the type of the score (e.g. vac if the score references a Root block), the second element is the parsed score itself. The third element describes an error if it is not nil.

Openroot opens the top-level directory of a vac archive by the score of its Root block. The tuple returned contains the Vacdir, and the Direntry containing information about the root directory. The third element describes an error if it is not nil.

SOURCE

/appl/lib/vac.b

SEE ALSO

venti(2)

DIAGNOSTICS

The functions unpacking data structures return nil for badly formed data, and set the system error string.

VAC(2) Rev:  Sat May 03 22:49:09 GMT 2008