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