xref: /inferno-os/appl/cmd/ramfile.b (revision a3d4017d8d3be485b256b15d2344afac09112204)
137da2899SCharles.Forsythimplement Ramfile;
237da2899SCharles.Forsythinclude "sys.m";
337da2899SCharles.Forsyth	sys: Sys;
437da2899SCharles.Forsythinclude "draw.m";
537da2899SCharles.Forsyth
637da2899SCharles.Forsyth# synthesise a file that can be treated just like any other
737da2899SCharles.Forsyth# file. limitations of file2chan mean that it's not possible
837da2899SCharles.Forsyth# to know when an open should have truncated the file, so
937da2899SCharles.Forsyth# we do the only possible thing, and truncate it when we get
1037da2899SCharles.Forsyth# a write at offset 0. thus it can be edited with an editor,
1137da2899SCharles.Forsyth# but can't be used to store seekable, writable data records
1237da2899SCharles.Forsyth# (unless the first record is never written)
1337da2899SCharles.Forsyth
1437da2899SCharles.Forsyth# there should be some way to determine when the file should
1537da2899SCharles.Forsyth# go away - file2chan sends a nil channel whenever the file
1637da2899SCharles.Forsyth# is closed by anyone, which is not good enough.
1737da2899SCharles.Forsyth
1837da2899SCharles.Forsythstderr: ref Sys->FD;
1937da2899SCharles.Forsyth
2037da2899SCharles.ForsythRamfile: module {
2137da2899SCharles.Forsyth	init: fn(nil: ref Draw->Context, argv: list of string);
2237da2899SCharles.Forsyth};
2337da2899SCharles.Forsyth
2437da2899SCharles.Forsythinit(nil: ref Draw->Context, argv: list of string)
2537da2899SCharles.Forsyth{
2637da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
2737da2899SCharles.Forsyth	stderr = sys->fildes(2);
2837da2899SCharles.Forsyth	if (len argv < 2 || len argv > 3) {
2937da2899SCharles.Forsyth		sys->fprint(stderr, "usage: ramfile path [data]\n");
3037da2899SCharles.Forsyth		return;
3137da2899SCharles.Forsyth	}
3237da2899SCharles.Forsyth	path := hd tl argv;
3337da2899SCharles.Forsyth	(dir, f) := pathsplit(path);
3437da2899SCharles.Forsyth
35*a3d4017dSCharles.Forsyth	if (sys->bind("#s", dir, Sys->MBEFORE) == -1) {
3637da2899SCharles.Forsyth		sys->fprint(stderr, "ramfile: %r\n");
3737da2899SCharles.Forsyth		return;
3837da2899SCharles.Forsyth	}
3937da2899SCharles.Forsyth	fio := sys->file2chan(dir, f);
4037da2899SCharles.Forsyth	if (fio == nil) {
4137da2899SCharles.Forsyth		sys->fprint(stderr, "ramfile: file2chan failed: %r\n");
4237da2899SCharles.Forsyth		return;
4337da2899SCharles.Forsyth	}
4437da2899SCharles.Forsyth	data := array[0] of byte;
4537da2899SCharles.Forsyth	if (tl tl argv != nil)
4637da2899SCharles.Forsyth		data = array of byte hd tl tl argv;
4737da2899SCharles.Forsyth
4837da2899SCharles.Forsyth	spawn server(fio, data);
4937da2899SCharles.Forsyth	data = nil;
5037da2899SCharles.Forsyth}
5137da2899SCharles.Forsyth
5237da2899SCharles.Forsythserver(fio: ref Sys->FileIO, data: array of byte)
5337da2899SCharles.Forsyth{
5437da2899SCharles.Forsyth	for (;;) alt {
553f1f06c5SCharles.Forsyth	(offset, count, nil, rc) := <-fio.read =>
5637da2899SCharles.Forsyth		if (rc != nil) {
5737da2899SCharles.Forsyth			if (offset > len data)
5837da2899SCharles.Forsyth				rc <-= (nil, nil);
5937da2899SCharles.Forsyth			else {
6037da2899SCharles.Forsyth				end := offset + count;
6137da2899SCharles.Forsyth				if (end > len data)
6237da2899SCharles.Forsyth					end = len data;
6337da2899SCharles.Forsyth				rc <-= (data[offset:end], nil);
6437da2899SCharles.Forsyth			}
6537da2899SCharles.Forsyth		}
663f1f06c5SCharles.Forsyth	(offset, d, nil, wc) := <-fio.write =>
6737da2899SCharles.Forsyth		if (wc != nil) {
6837da2899SCharles.Forsyth			if (offset == 0)
6937da2899SCharles.Forsyth				data = array[0] of byte;
7037da2899SCharles.Forsyth			end := offset + len d;
7137da2899SCharles.Forsyth			if (end > len data) {
7237da2899SCharles.Forsyth				ndata := array[end] of byte;
7337da2899SCharles.Forsyth				ndata[0:] = data;
7437da2899SCharles.Forsyth				data = ndata;
7537da2899SCharles.Forsyth				ndata = nil;
7637da2899SCharles.Forsyth			}
7737da2899SCharles.Forsyth			data[offset:] = d;
7837da2899SCharles.Forsyth			wc <-= (len d, nil);
7937da2899SCharles.Forsyth		}
8037da2899SCharles.Forsyth	}
8137da2899SCharles.Forsyth}
8237da2899SCharles.Forsyth
8337da2899SCharles.Forsythpathsplit(p: string): (string, string)
8437da2899SCharles.Forsyth{
8537da2899SCharles.Forsyth	for (i := len p - 1; i >= 0; i--)
8637da2899SCharles.Forsyth		if (p[i] != '/')
8737da2899SCharles.Forsyth			break;
8837da2899SCharles.Forsyth	if (i < 0)
8937da2899SCharles.Forsyth		return (p, nil);
9037da2899SCharles.Forsyth	p = p[0:i+1];
9137da2899SCharles.Forsyth	for (i = len p - 1; i >=0; i--)
9237da2899SCharles.Forsyth		if (p[i] == '/')
9337da2899SCharles.Forsyth			break;
9437da2899SCharles.Forsyth	if (i < 0)
9537da2899SCharles.Forsyth		return (".", p);
9637da2899SCharles.Forsyth	return (p[0:i+1], p[i+1:]);
9737da2899SCharles.Forsyth}
98