xref: /inferno-os/appl/cmd/ramfile.b (revision a3d4017d8d3be485b256b15d2344afac09112204)
1implement Ramfile;
2include "sys.m";
3	sys: Sys;
4include "draw.m";
5
6# synthesise a file that can be treated just like any other
7# file. limitations of file2chan mean that it's not possible
8# to know when an open should have truncated the file, so
9# we do the only possible thing, and truncate it when we get
10# a write at offset 0. thus it can be edited with an editor,
11# but can't be used to store seekable, writable data records
12# (unless the first record is never written)
13
14# there should be some way to determine when the file should
15# go away - file2chan sends a nil channel whenever the file
16# is closed by anyone, which is not good enough.
17
18stderr: ref Sys->FD;
19
20Ramfile: module {
21	init: fn(nil: ref Draw->Context, argv: list of string);
22};
23
24init(nil: ref Draw->Context, argv: list of string)
25{
26	sys = load Sys Sys->PATH;
27	stderr = sys->fildes(2);
28	if (len argv < 2 || len argv > 3) {
29		sys->fprint(stderr, "usage: ramfile path [data]\n");
30		return;
31	}
32	path := hd tl argv;
33	(dir, f) := pathsplit(path);
34
35	if (sys->bind("#s", dir, Sys->MBEFORE) == -1) {
36		sys->fprint(stderr, "ramfile: %r\n");
37		return;
38	}
39	fio := sys->file2chan(dir, f);
40	if (fio == nil) {
41		sys->fprint(stderr, "ramfile: file2chan failed: %r\n");
42		return;
43	}
44	data := array[0] of byte;
45	if (tl tl argv != nil)
46		data = array of byte hd tl tl argv;
47
48	spawn server(fio, data);
49	data = nil;
50}
51
52server(fio: ref Sys->FileIO, data: array of byte)
53{
54	for (;;) alt {
55	(offset, count, nil, rc) := <-fio.read =>
56		if (rc != nil) {
57			if (offset > len data)
58				rc <-= (nil, nil);
59			else {
60				end := offset + count;
61				if (end > len data)
62					end = len data;
63				rc <-= (data[offset:end], nil);
64			}
65		}
66	(offset, d, nil, wc) := <-fio.write =>
67		if (wc != nil) {
68			if (offset == 0)
69				data = array[0] of byte;
70			end := offset + len d;
71			if (end > len data) {
72				ndata := array[end] of byte;
73				ndata[0:] = data;
74				data = ndata;
75				ndata = nil;
76			}
77			data[offset:] = d;
78			wc <-= (len d, nil);
79		}
80	}
81}
82
83pathsplit(p: string): (string, string)
84{
85	for (i := len p - 1; i >= 0; i--)
86		if (p[i] != '/')
87			break;
88	if (i < 0)
89		return (p, nil);
90	p = p[0:i+1];
91	for (i = len p - 1; i >=0; i--)
92		if (p[i] == '/')
93			break;
94	if (i < 0)
95		return (".", p);
96	return (p[0:i+1], p[i+1:]);
97}
98