diff options
| author | hachem <im@hachem.wtf> | 2026-10-11 02:16:56 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-10-11 02:16:56 +0200 |
| commit | 59794d0b999e544a94230d9562bf2b99d2ed74c7 (patch) | |
| tree | a001db5b5ebb9453d6a0e96f56b36e6ec3ccdd51 | |
| parent | 88750ed7132c08bcfb24e878c893ef7185c3c0b0 (diff) | |
feat: actual real vfs, not a faked one lmao
| -rw-r--r-- | bridge/bridge.zig | 2 | ||||
| -rw-r--r-- | bridge/hosts.zig | 30 | ||||
| -rw-r--r-- | build.zig | 5 | ||||
| -rw-r--r-- | etc/lung | 79 | ||||
| -rw-r--r-- | etc/motd | 1 | ||||
| -rw-r--r-- | etc/profile | 8 | ||||
| -rw-r--r-- | gils/cat.rv | 3 | ||||
| -rw-r--r-- | gils/cp.rv | 6 | ||||
| -rw-r--r-- | gils/ed.rv | 8 | ||||
| -rw-r--r-- | gils/head.rv | 4 | ||||
| -rw-r--r-- | gils/ls.rv | 11 | ||||
| -rw-r--r-- | gils/mkdir.rv | 2 | ||||
| -rw-r--r-- | gils/mv.rv | 8 | ||||
| -rw-r--r-- | gils/rm.rv | 2 | ||||
| -rw-r--r-- | gils/tail.rv | 4 | ||||
| -rw-r--r-- | gils/touch.rv | 6 | ||||
| -rw-r--r-- | gils/tree.rv | 12 | ||||
| -rw-r--r-- | gils/wc.rv | 4 | ||||
| -rw-r--r-- | kernel/io.rv | 12 | ||||
| -rw-r--r-- | kernel/seed.rv | 13 | ||||
| -rw-r--r-- | kernel/shell.rv | 4 | ||||
| -rw-r--r-- | kernel/vfs.rv | 345 |
22 files changed, 473 insertions, 96 deletions
diff --git a/bridge/bridge.zig b/bridge/bridge.zig index 0b56525..a7e0e58 100644 --- a/bridge/bridge.zig +++ b/bridge/bridge.zig @@ -21,8 +21,8 @@ const init_program = blk: { @embedFile("k_console") ++ "\n" ++ @embedFile("k_vmm") ++ "\n" ++ @embedFile("k_fs") ++ "\n" ++ - @embedFile("k_io") ++ "\n" ++ @embedFile("k_vfs") ++ "\n" ++ + @embedFile("k_io") ++ "\n" ++ @embedFile("k_seed") ++ "\n"; // gils shit diff --git a/bridge/hosts.zig b/bridge/hosts.zig index 7ce5650..caf8b0d 100644 --- a/bridge/hosts.zig +++ b/bridge/hosts.zig @@ -24,6 +24,14 @@ const scripts = [_]Script{ .{ .name = "tail", .src = @embedFile("k_gils_tail") }, }; +// /etc/ shit +const EtcFile = struct { name: []const u8, src: []const u8 }; +const etc_files = [_]EtcFile{ + .{ .name = "motd", .src = @embedFile("k_etc_motd") }, + .{ .name = "profile", .src = @embedFile("k_etc_profile") }, + .{ .name = "lung", .src = @embedFile("k_etc_lung") }, +}; + // the actual framebuffer, the data layout feels pretty self explanatory pub const Fb = struct { ptr: [*]u8, @@ -425,6 +433,25 @@ fn hostScriptSrc(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult { } // pass shit to revo +fn hostEtcCount(_: []const revo.Value, _: *revo.VM) anyerror!HostResult { + return HostResult.data(Data.new.num(etc_files.len)); +} + +// pass shit to revo +fn hostEtcName(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult { + const i = argInt(usize, args, 0) orelse return HostResult.other("etc_name: bad index"); + if (i >= etc_files.len) return HostResult.other("etc_name: out of range"); + return HostResult.data(try vm.ownValueString(etc_files[i].name)); +} + +// pass shit to revo +fn hostEtcSrc(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult { + const i = argInt(usize, args, 0) orelse return HostResult.other("etc_src: bad index"); + if (i >= etc_files.len) return HostResult.other("etc_src: out of range"); + return HostResult.data(try vm.ownValueString(etc_files[i].src)); +} + +// pass shit to revo fn hostEvalScript(args: []const revo.Value, vm: *revo.VM) anyerror!HostResult { const sid = args[0].asString() orelse return HostResult.other("eval_script: not a string"); const src = vm.stringValue(sid); @@ -487,6 +514,9 @@ pub fn passShitToRevo(vm: *revo.VM) !void { try vm.registerGlobal("script_count", try vm.installHost("script_count", define(&[_]T{}, hostScriptCount))); try vm.registerGlobal("script_name", try vm.installHost("script_name", define(&[_]T{.number}, hostScriptName))); try vm.registerGlobal("script_src", try vm.installHost("script_src", define(&[_]T{.number}, hostScriptSrc))); + try vm.registerGlobal("etc_count", try vm.installHost("etc_count", define(&[_]T{}, hostEtcCount))); + try vm.registerGlobal("etc_name", try vm.installHost("etc_name", define(&[_]T{.number}, hostEtcName))); + try vm.registerGlobal("etc_src", try vm.installHost("etc_src", define(&[_]T{.number}, hostEtcSrc))); try vm.registerGlobal("alloc_contig", try vm.installHost("alloc_contig", define(&[_]T{.number}, hostAllocContig))); try vm.registerGlobal("blit_str", try vm.installHost("blit_str", define(&[_]T{ .number, .string }, hostBlitStr))); try vm.registerGlobal("phys_to_str", try vm.installHost("phys_to_str", define(&[_]T{ .number, .number }, hostPhysToStr))); @@ -89,6 +89,11 @@ pub fn build(b: *std.Build) void { bridge_mod.addAnonymousImport("k_gils_" ++ g, .{ .root_source_file = b.path("gils/" ++ g ++ ".rv") }); } + // /etc/ bullshit + inline for (.{ "motd", "profile", "lung" }) |name| { + bridge_mod.addAnonymousImport("k_etc_" ++ name, .{ .root_source_file = b.path("etc/" ++ name) }); + } + kernel.root_module.addImport("bridge", bridge_mod); inline for (.{ diff --git a/etc/lung b/etc/lung new file mode 100644 index 0000000..54c10ab --- /dev/null +++ b/etc/lung @@ -0,0 +1,79 @@ +(((())))11111{{{}}}}}}[[[]]]]]]]-------_______)juvvvvvvvvvvvvvvvvvvvvvuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvccccccvvvvvvccccccccccccccccccccccccccvvvvvvuuuuuuuuuuuuuuuunnnnnnnnnnnxxxxxxxxxxxxxxxrrrrrrrrrrrrrrrrrrrrrrrrjjjjjjjjjffjf)][}} +||(((()))11111{{{{}}}}}[[[]]]]]]????----______-{tuuuuuuvvvvvvvvvvvvvvuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvccccccvvvvvvcccccccccccccccccccccccvvvvvvvvvuuuuuuuuuuuuunnnnnnnnnnnxxxxxxxxxxxxxxrrrrrrrrrrrrrrrrrrrjjjjjjjjjjjjjjjjjjff/{-_-][ +|||||(((()))111111{{}}}[[[[[[]]]]]??----________[fnuuuuuuuuuuuuuvvvvvvuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvcccccccccccccccccccccccccvvvccccccvvvvvvvvvuuuuuuuuuunnnnnnnnnnnnnnxxxxxxrrrrrrrrrrrrrrjjjjjjjjjrjjjjjjjjjjjjjjjjjjjjffft)~+[{{1 +\\\|||((())))1111111{{{}}[[[[[]]]]??----_________]|xuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvvcccccccccccccccccccccccccvvvvvvvvvuuuuuuuuuuuuuuuunnnnnnnnnnnnnxxxxxxxxrrrrrrrrrrrrrrrjjjjjjjjjjjjjjjjjjjjjjjjjjjjjffftf\}<+{))) +\\\\\||||(()))1111111{{{}}}}[[[[]]??----________+_?(ruuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvvvvvvcccccccccccccccccccccvvvvvuuunnnnnnuuuuuuuuuuuuunnnnnnnnnnnnnnnxxxxxxrrrrrrrrrrrrrjjjjjjjjjjjjjjjjjfffffffffffjjjffffft/{~I~{||( +/\\\\\\||((())))111111{{{}}}[[[[]]??-----_____+++++_1fnnnuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvuvvvvvvvvvvvvvcvvvvvvvvvvuuuuvvvvvuuuuunnnnnnnnnnnnnnnnnnnnnnnnnnnnnnxxxxxxxxxxxxrrrrrjjjjjjjjjjjjjjjjjjjjjjjjffffffffffffffffffftt\(]+<?)//\ +//\\\\\\\|||(((()))11111{{{}[[[[[]]]?------__++++++++{txnunnnnnuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuvvvvvvvvvvvvvvvuuuuuunnnnnnnuuunnnnnnnnnnnnnnnnnnnnnnxxxxxxxxxxxnxxxxxxxrrrrrrrrjjjjjjjjjjjjjjjjjfffffffffffffffffffffffftttt//|}?]-])//( +/t////\\\\\||((((()))1111{{{}}}[[]]]?------__+++++++~+]\xnnnnnnnnnnnnnnnnnnnnnnnnnnuuuuuuuuuuuuuuuvuuuuuuuuuuuuuuuuuvuuunnnxxrrjjjjjrrrrjjjjrjjjrrrrrrrrrrjjjjrrxrxrrrxxxxxxxxxxrrrrrrrrjjjjjjjjjjjjfffffffffffffftttttttttttttttttftt\{?_-?_](//1 +tttt////\\\|||(((()))11111{{}}}[[[[]]?-----__+++++++~~~?(rxxnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnuuuuuuuuuuuuuuuuuuuunnnnxxrrjfffttt///\\/tttttttttfffffffffft/\\///tttfjjrrrrrrrrrrrrrrrrjjjjjjjjjjjjjjfffffffffffffftttttttttttttttt////(_l><~+?[[}} +ttttt//////\\|||((()))))111{}}}}}[[]]]?----__+++_++++~~~-(fxxxxnnnnnnnnnnnnnnnnnnnnnxxxnnnnunnnnnuuuuuuuuuuuuuunxjjjjjfjjft/\|||(()))(\//\\\|\||\\///\|(1}[[[}{1)((((|/tfjjjjjjjjjjjjjjjjjjjjjjjjjjffffffffffffffftttt|(1}[]][1\//////)-<___[1{{{{ +fttttttt///\\\\|||((())))111{{{}}[[[]]?---___+++_++~~~<<>~{frxxxxxxxxxxxxxnnnnnnnnnnxxxxnnnnnnnnnnunnnnnxxxxrjjft/\\\\||(1{}}}}}}}}}}?__]}}}}111{{1)1[-~>iii!!ii~_?}{1(|\\ttfjjjjjjjjjjjfffffffffffffffffffffftfftt|}-+<>!I;,^`:>_?[1{?__+_]))((() +jffffttt//////\\\|||(((())11{{{}}}[[]]?---___+++_+~~~<<>ii<]/rrxrrxxxxxxxxxxxxxxxxxxnnnnnnnnnnnnnnnnnxxrrjjffttt//\(1}?~iI:,,,"""""""^`''^,,I<_--_++>I,`. .'`^``^,l+[(\/tttffffjjjjjffffffffttttftttttfffftttt\[~><<<il;,` '",:!<<_}1((((( +jjjfffttttt////\\\\|||((()))111{}}[[[]]]?---_+++++~~~<<>iiii-|jrjrrrrrrrrrxxxxxxxxxxxxxxxxnnnxnnnnnnxrrjjtt/\\|(1{]_!,' .''.'. ..'`:<[(/tttttffffffffttttttttttttttttttttttt(_>!!lI:` .''''"I<_[{)((((( +rrjjjjffttttt////\\\||||(())111{{}}[[]]]?---___++~~~<<<>i!!!!+(tjjjrrrrrrrrrrrrrxxxxxxxxxxxxxxxxxrrrrjft/\||(1}]_i" .`:-)\///ttftfftttttttttttttttt/////////(-l``^^`. '",",:l<?}{1)))))) +rrrrrjjfffttttt///\\||||(((())11{}}[[[]]???--__+~~~~<>>ii!!!!!>{tjjjjrrrrrrrrrrrrrxrrrrrrrrrrrjjjfftt/\|))1{[-i;' . .,-(\\//tttttttttttt////////\\\\\\\\\(?: .. "i>i!!i+?}{{1111111 +xxrrrrrjjjffttt////\\\||||(())11{{}}[[]]]??--__++~~<<>>i!!!!lll<[tjfffffffffffffffffjjjjjjjjjfftt/||())1}[?+l` ...'l?(\\//tttt/////////\\\\\\\\|||||\()?i:````^:!+?[]<ii><-]{{{1111111 +xxxxrrrjjjfffttttt//\\|||||(())11{{}[[[]]]?--___+~<<>>i!!!lllIII!](ttttttttttttttttffffffffftt//\|)))1{[-~l" '. '~1\\\////\\\\\\\||||||||(((((((((((()111111111}+ll<~+?]]][[}}}}}} +xxxxrrrrjjjjffttttt//\\\\||||()111{}}}[]]]?--__+++~<>ii!!!llII;;::-)///////tttttttttttttt////\|(()11}?<!;". l[)|||\\\\\\\|||||||||(((()))))))((()))1111{}-<;I<-][[[[[]?----- +xxxxxxrrrjjjfttttttt///\\||||(()11{{}}[[]]??-__+++~<>ii!!!lIII;:,,,>}|\\\\\\\\//////////\\|||(()){]_i:"' .l-1)(|||((((|||||||(((((()))))))))))1111{[<l!>I,:<[[[}}{}[]---- +nnxxxxxxrrrjjfffftttt///\\\||(()111{{}[[]]]??--_++~>>ii!!!llI;;:,"",i[(|||||\\\\\\\\///\\|((((1}?<I^. :~[1))(((((((((((()))))11111111111{{{{{{?illI`^I-[}{{{{{}[]]]] +nnxnxxxxxrrrjjjjjfttttt//\\\||(())1{{}}[[]]??--_+~~<ii!!!!ll;;;:,"^^^l-1(((||||||||||||||()11[_>I"' .l-}11))))))))))))))111111{{{{{{{{{{{}?>llI, ,-[}}}}}}}}}}[[[ +unnnxxxxxrrrrjjjjjfttttt//\\||||()1{{{}}[]]]?--_+~~<ii!lllII;;;:,,"^`':+})))))(||||((((()1{]+>I"' ;+[{1111111111111111{{{{{{{{{{}}}}?>!!i!!!!~[}}}}}}}}}}}[[[ +unnnnxxxxxrrrrrrjjfttttt//\\\|||()11{{{}[]]]?--_+~~<ii!lllII;;;:,,"^`''"<[11)))(())))()1{]+iI,` :<?}{{{{{{{{{{{{{{{{{}}}}}}}}}]_>l!>_-?--?][}[[[[}}}}}}[[[ +uununxxxxxxrrrrrjjfftttt///\\\||()11{{{}[]]]?--__+~<ii!lllII;;::,,"^`'. `!?{{{{{1111{1{[-~!,' .......'```^^`. "<?[[[}}}}{{{{}}{{}}}}}[}}}]>;,I!<_-?][[[[[[[[[[[[[[[[[[[ +uuuuunxxxxxxxrrrrjjffffttt//\\\|(()1{{{}}[[]??--_+~<ii!lllII;:::,,"^`'.. .:~[}}}{{{}}[-~>l". .`",:;IIIIlll!!!!lI;,,,,,,::;IIII:"` `>-][}}}}}}}[[[[[[[[[[[]->:^;>_-____--???]]]]]]]]]]]]]]] +vuuuuunnnxxxxrrrrrjjfffttt//\\\||()11{{}}[[]]??-_+~<ii!lllII;:::,,"^`'.. "i-]]][[[?_<l:"^`^ '":Ilii><<~~~~++++~<>i>>>>><<<>>>>il;" `!-]][[[[[[[]]]?_+++~iII!!;l~]]]?-_______----??]]]]]]]] +vvvvuuunnxxxxxxrrrjjffftttt/\\\\|(()111{}}[[]]?-_+~~>i!!lII;::,,,"""^'.... `!_---?-<l:,:;;"' `,;!i><~~+++_---?????????--_++~~<<>i!I:. .I~???]]]][]]_>;":l>~+--+!l>-?]?????--_++___---??????? +vvvvuuunnnnnnxxxrrjjffftttt/\\\\||())11{}}[[]]?-_+~~>i!!lI;;:,,,""""^`'... 'I+--_>lIIl!I,`. .. `,;!>><~~~+_-?]]]]]]]]]]]]?--_+++~<<>!l;` ,<+___~<i!ll!<+----???-~!;I~?]]]]]??--____-----????? +ccvvvvuuunnxxxxxrrrjjjjffttt/\\\\|(())1{}}[[]]?-_+~<>i!!lI;;:,,"^^^^^^``'.. .:<+~!!!!!l;"^`' .`' .`,;l><~+++__-][[[[[[[[[[]]]]]???-_+~~<i!I" .,li><<<+_-???????????_>I;l<-???????--------------- +zcccvvvuunnnxxxxrrrjjjjfftttt///\\|(()1{}}[[[]?-_+~<>i!!lI;:,,,"^^^^^^^^^````^:>~<!!!!I;::,"^. '^` .`,;li<~+__--??]][[[[[[[[[[[[[[]]??-_+~<>il,' "l<~_-----??????????-_+-------------------------- +zzccvvvuuunnxxxxxxrrjjjfftttt///\\\|()11}}}[[]]?_+~<ii!!lI;:,,,"^^^^^^^"""",:I!><ill!!llllI,^' .``. '^,;Ili<~++++__-??]]]][[[[[[[[[[]]]?-__+~<i!;^ ^I!<~+___--------------------------------------- +zzcccvvvuuunnnnxxxrrjjjfftttt///\\\|()11{}}[[[]?-+~<>i!llI;::,,"""^^^^^",:;Il>~<ilI!iiii!lI::"^' .`` '^:Il!><+____--??][]]]][[[[}}[[[[[]?--_+~<iil,' ."I>~+++_____________________------------------ +zXzzcvvvvuuunnnnnxrrrjjjftttt///\\\|()11{}}[[[]?-+~<>i!lI;;::,,""^"^^^",::;l~__<!II!<<>>>i!I;:"^ .. .`,I!><~+-??][[[[[}}[[[[[[[[}}}}[[[[]]?-__~>i!;^ ."l<++++_________________________----------_-- +zzzzzccvvuuunnnxxxrrrrrjffffttt/\\\|()11{}}[[]]--+++~>i!lI;::,,,,,,,:;l!lli-]?+iI::!~-??-+>lI,"` .^:I!>~+_?][[[}}{{{{{{{{{}}}}{{{{{{{{}[[]]?_+<il,' "!<~~~++++++++++++++++++_____________----__- +Xzzzzccvvuuunnnxxxrrrrrjffffttt///\|()11{}}[[]?-_+++~<>ii!llI;,,::Il!iii!i_??_>I,":>-[[[?+>lI,' '";l>~-??]}}}{{1)))(()))111111))))))11{{{}[]-_~>l" `I<~~~++++++++++++++++++++++______________- +YXXXzccccvuunnnxxxrrrrrjjfffttt///\\()11{}}[[]?_+~~~~~<>ii!!!I:,:;!iiii>+--_+>I;:;i-}1{{]_<l"' .`,;!<+_-][}{1111)((||||||((|||||||(((()))1}[?_~i;' ^I<~~~~~~~~~~~~~~~~~++++++++++++______---- +YXXXXzzccvvuunnnxxrrrrrjjfffttt///\\()11{}}[[]-_+~<<>>>iii!l!!IIl><<<<+_?]?-_>l;;l+{)(1[->I:,"^' .'`",l>~-?[{)(||\\\\\\\\\|||((())111{[?_+<i;` ^l<~~<~~~~~~~~~~~~~~~~~+++++++++_____---- +YYXXXzzcccvuunnnxxxrrrrjjfffftt///\\|(11{}}[[]?_~<<>>ii!!lllllll!i<_??]]]-+~>I;!i>-)(}_ili<>l,' .''' '^^^`'. ^l~?{(||||||((((){[-~~<<<>!lI;;::"`. ^l<<~~~~~~~~~~~~~~~~~~~++++++____------- +YYXXXXzcccvuuunnxxxrrrrjjffffttt//\\|()1{}[[]]-_+~<>iiiii!I;;Ill!!>+-?]]_~iI;",l><~--<<+_~i;"`'''`";;,' '^,:;;;Il!!lI:^`^"l<-]{1)((()){}]_<;^. `I><<<<<<<<<<<<<~~~~~~~+++++__--------- +YYXXXXzzccvuuuunxxxrrrrjjffffftt//\\|()1{}[]??-_+~~~<<<><>!IIIl!>+_?]?-~>illI,"Ili<-[[]]_!;,:;I;,"";;:' .`"IllIl<+?[{1))11{}[?_>I"^^""^^^""",:;;;:,". ^li><<<<<<<<<<<<~<~~~~~++++___-------- +UUYYXXzzzcvuuuunxxxrrrrjjffffftt//\\|()1{}[]]?-_+++~++~<<i!lll!!lI!>~>!llllll;:I>_})){?<ll!><<~>;,,II:` ",. +{]+i!l!<-[{1))11}]_>;:Il!l:' .`. :!i>>>>>>>>>>>><<<<<~~~~++___-------? +JJUYXXzzzcvuuuunxxxrrrrjjffffftt//\\|()1{}[[]?--____+~~+~~<>i!!l;:;:,"",;lIII:,;>?}}-~~?{1{]___+iI:ll:` '`^""^'.^I+?<i!lI;I>_[}{11}?<;,;><i>+?; :i; "I!iiiiiiiiiiiiii>>><<~~~++__------?? +JJUYYXXzzzcvuuunxxxrrrrjjffffftt//\\|()1{}[[]?----???-+~~~~~<>>!I;III:",;I;:;:::Ii~+]1\fff\11{}?+!Iiil" '^:Ili>><+---_+~<<il:;l<-][{[_i;,I><>!!>>il:,,:I;,`.. . "I!i!i!!!!!!!!!!!!!i><<<~++_----???? +JJUUUXXXzzcvuuunxxxrrrrjjffffftt//\\|()1{}[[]?------??---_+<>>>ilIl!!lI;;;;;;:,,"I-{\jxxrj/())1}-<!><i:. '^:l><~+_--??-_+~>!I;::I>-]][_<l:,:li>><~+_--?--+~>!l;:"` .`' ^;!!!!!!llII;;;;;;;;Illi><+_--???]]] +JJJUUYXXzzcvuuunxxxrrrrjjffffftt//\\|(11{}[[?--__++~~~~~++~>!!lllIIlI;,"^^^"""^``:+1/jnnxjf\()11}-<~<i;`. '^,li~+-?][[[[]?_~ilII;;I>_]]]_<!;::;Ii>++_?][[]]?-+<i!l;^ '^",,` '^:Il!!!!lI;:,"^^````'```"I>_--?????] +CJJJUYXXzzcvuuunxxxrrrrjjffffftt//\\()11}[[]?-_++~<>ii!!!!!lI;:,,"^^``'....'``'''"<1/rnnnxf/|(()1[??+iI,^. .`,Ii<_-?[}}}}]??_~>lllII!+][[[-<iI;IIli<+-]}{111{}[?_~>il" '````.'.`,"'..':!>~>I,",^ 'i+-?????? +CCJJUYXXzzcvuuunxxxrrrrjjffffftt//\\()1{}[[]?-__+~<i!lIII;;::,^^`'''. .. .">?)rnnnxf/\\\()1{}?+>I:. .'":li<+-?[[[[[]??_~>!!ll!>-[}}[-~!I;Ili~_-][{111111{[?_~>l" ."l, .l?]_I . I<_-?---- +CCJUUYYXXzzvuuunxxxxrrjjjfffftt///\|(11{}[[]?___+~>i!lI;;::,""^``'... ^ll>1jxxxt)(tt/|()){?_>:. '`":Ii<+_???]]][[]?_<ii!l!<?[}}}?~iIIli<_][}}{{{{{{}}[?_~il" .`. "!il" ',IIIl!i> +CCCJUYYXXzzvuuunxxxxrrjjjfffftt///\|(11{}[[]?___+~>i!lI;;:,,"^^``'''....... .`^.^~)fff(-?\t///\(){?>:'..'^",I!>~~+_-][}{{{}]+>!l!>_[}{{}?+iI;I>~?[{1{}}}}}[]]?_+<!;` '"^ ';I;" "III!i>> +LCJJUYYXXzzvuuunxxxxrrjjjfffftttt/\|()1{}[[]?_+~~>i!lI;:::,""^`''''.....''. .'' l[(||)--)\///\||)]<:'..'`^";l!ii<+-]}{{1)1[+iI!<_?[{{{{[-<!::l~]}11{{{{}[[]?_+<iI". '`' 'I!l;. :!!i><~~ +LCJJUYYXXzzvuuunxxxxrrjjjfffftt//\||)1{}}[]?-++<<i!llI;:::,""^`''''....''' .' "!+_--__])//t//\|[<;`''``^,;I!ii>~_][{{1)1]<li+-]][{}}}[]_>l,,>?{111{{}[]?-+~<iI,' .'''. ,+??-I 'i?]????? +LCJJJYYXXzzvuuunxxxxrrrjjjffftt//\|()1{}[]]?_+~<>i!lII;:::,"^`'''.....''`' ^,;>-]+<~?1/tt//|]>;"^`^^,:li>~~++-][{11){_~+]}{}}{1111{}]+>I:!_{11){{}]?-+~<iI:` ``' '>[{{1-: `:-11{{{{{ +QLCJJYYXXzzvuuunxxxxrrrjjjtttt///\|(){{[[]??_+~<>i!lII:::,""^`'''....'```' .``',>?]+>~-1/ft/\1+l:,"^",;l!><<~+_-?[}{{{}???[}}{1(\/|){}]_<il~]{)1){}[?-_~<iI:^. .`' :_1)1)[+: ^i?)|\\\\\ +QLCJJYYYXzzvuuunxxrrrjjjjfttt///\\|(1{}[[]??_+~<>i!lI;:::,"^^`'''....`""^' `:,`.':<?[+<+[)\\|\)?>:,,"",:l!i<~~~++_?][}}}}[?____-[{(){[-~<<<><-[{)11{}]-_+<iI,^. `' :+)(((1?i". ^l?)|\\\\\ +LLCJUUYYXzzvuuunxxrrrjjfftttt///\|()1{}[]]?-+~<>>!!lI;:,,,"^^`''.....^"^' 'l>I,`'"i?]_ii-{(||()}+l"`^''^,I!!>~~+++_-?][[[[[?_+++-?][[]?+~<<<~-][}}}{}}]-+~>l:^' '^. ,+(\\/\{<:' `l-1|\\\\\ +LLCJUYYXXzzvuuuxxrrrrjjffttt////\()11{}[]?-_+~<>>!!lI;:,""^^``''.....'^.. ,i~<l:^`:+11?~<?1(((){->I^. `:l!>~~++_--?]]][[[]??][}{{{{}}}}]??]][[[}}}}}]-+~iI,` .`` ^<)|///1<;` .;~}(\|||| +LLJJUYXXzzcuuunxxxrrjjffffttt//\|()1{}[]]?-_~~<>i!lI;;:,""^```''..... 'l>i+-<;^^l}/|?_-?{))(1?>l;^ `Ii>~++++_-??][[[[[}}{1)))(((()1{}}[[[[[}}}}}]-+~iI". .. ^<{(\\\1<;` ^i-1||||| +LLJJUYXXzcvuuunxxxrjjjfffttt//\\|)1{{}[]]?_+~<>i!llI;:,,"^^```'.. ':~~!-[+!I;l+{){{1}{11{[>l;,' ^!>~+++___--?]][[[}}{11))1)))1{{{}}[[[][][]]]-+~!:^ '!}(\\\1~I` 'I+}((((( +CCJUUYXXzcvuunxxxrrjjffttttt/\\\|)1{}[[]?-_+~<>i!llI;,"""^```''. ,i~>l]}_>i!ll_)\\|1}?__~l;,". `I>++__________+_-?][[[[[}}}[]????-????]??]]?+<l:` .'l])|||1_!". .,>[))))) +CCJUUYXXzcvunxxrrrjjjffttt//\\\|()1{}[]??-+~<>i!lII;:,"^^^``'''. 'I~~>!]}_<~_+~{/t|{[_~<iI,^`' ,!~++__+~>;"^''`^,;li<~~~<<>i!I:,,,,;!<+--_~i;". 'I?1())1?i"' ^!?{11{1 +CCJUUYXXzcvunxxrrrjjjffttt//\\\|(1{{}]]??-+~<ii!lI;::,""^^``''.. ',l+]?+<><~<<>i<1\|[_~>l,",,` "!~+___+~>l:^. .";Illl:^. ^:!iii!I"' "-{11{]i"' ';~]{11{ +CCJUYXXzcvuunxrrrjjfffttt//\\\|(){{}[]?--_+<>i!llI;,""^^^^`'''.. `>__-?+i:";><l,l~?-_<i!l,.. "l<+__+~~~>l:""^````''....''```":l><~~~>l,' I-1{]i". ,>?}{{} +JJUYYXzzvuunxxrrrjjfftttt//\\|()1{}[[]?-_+~>i!!lI;:,""^^^``'.... ,i+_~!ll;^ '":;:I!!!!I,^. ;<++++++~<iI;:;IllllI;;;::::;!>~~++++~>I" '<[]>^. "i]{111 +JJUYXzzcvuuxxrrjjfftttt///\\\|()1}}[[?-_++<i!lIII;:,""^````'......^!__~!,' .'`^",:,"",,` ,<++____+~<i!lllIIIIIIIIII!i<~+~~~~~<!:' :_<" ^!?)||| +JJUYXzcvuunxrrjjffftttt//\\\|()1{}[[]-__~~>i!lIII:,,"^^````'...':~[?!' .'`^^``^` ^i++___--?--__++~~<<<<~~__-_++~~~~<i:' '` 'I_)\\\ +UUYXXzcvunxxrrjjfftttt//\\\||(1{}[[]?-_+~<>i!lII;:,"^^^````'.."<-_: ..'``` `l<+_--?]]]]?????------?---_+~<<<!:`. ;+1|\\ +UUYXzccvunxxrjffffttt///\\||(){{}[[]?__~<<>i!lI;;::"^^^````'^!_!. .`^` 'Ii<_--?????]]]]]]?????-___+<>iI,`.. . ,~}|// +UYXzcvvunxxrjfffttt///\\\\|()1{}[[]]-_+~<>i!lI;;::,"^^^```^!-_I ";` .. ";l>+_-_????????]????-___+~i;"`'''. ^<](// +YYXzvvunnxrjjfftttt//\/\|||()1{[[]?--_+<>>i!II;::,,"^^^^,!~+I. "I. .. ^,;I!i<~~~~++++++++++~~<>!I:^''''`. 'l-)// +XXzcvunxxrjjfftt////\\\||())1{}[]]?-_+~<>>!lII;:,,,"^";!il' .' .^",:::;IIIIl!iiiii!!!lIII;:"^`''' .I-(jn +Xzcuunxxrrjfftt////\\|||()1{}[[]]?--_+<<>i!lI;::,,,":!>: `^"",,,,;Ili><~__-_+++~<il:,^``'' ,_\vJ +zcvunxxrrjffftt////\\||((1{{}[]]?-__+<<>!!lII;:::::I;' '^,,,"",:Il!><+-?]]??_+>l;,^``'. `~(nY +zcunxxrjjfftt///\\\\|||()1{}[[]?--_+~<>i!lllI;::;l;` `","""",;I;;;l!<_--+i;:,"^```'. ;]tv +vuunxrrjjfft//\\\\|||())1{}[[]]?-_+~~<ii!lllIII><i, ^"""""",:;;:,,;!i!I,""""^^``' `+|x +unxxrjjfftt/\\\\||||())1{}}[]]??-_+~<>iii!lIIIl+-; '``^^`^",:;:,""""^"",,^`''. . ,_( +nxxrjjffttt/\\|||||()11{}[]]]]?-__+~~<>ii~?]-~~+!` .``^^^^",::::::::;:,"'. 'i} +xxrjffttt//\\||||())1{}}[]]]???-_+~~~~+[/fjf\}!. '`^^^`'``^"""""`. l] +xrjjff///\\\||(|(()11{}[]]]]?--_+~~~~]/xxf\[i' .'``'. ,_ +jffftt/\\\|||((())1{{}]]??--__++~<<<]tnuj1<. .''. ^< diff --git a/etc/motd b/etc/motd new file mode 100644 index 0000000..f252b8e --- /dev/null +++ b/etc/motd @@ -0,0 +1 @@ +why the hell are you using this os? diff --git a/etc/profile b/etc/profile new file mode 100644 index 0000000..7cd7a19 --- /dev/null +++ b/etc/profile @@ -0,0 +1,8 @@ +# acts like .bash_profile or .zsh_profile + +const motd_size = fs:size("/etc/motd") +if motd_size > 0 do + puts("\n") + puts(fs:read_bytes("/etc/motd", 0, motd_size)) + puts("\n") +end diff --git a/gils/cat.rv b/gils/cat.rv index 0666304..cb0df34 100644 --- a/gils/cat.rv +++ b/gils/cat.rv @@ -5,6 +5,5 @@ const parsed = arg_name(context.rest, 0) if parsed.name:len() == 0 do fail("usage: cat <path>\n") end else do const path = expand_path(parsed.name) - if vfs_owns(path) do vfs_cat(path) end - else do fs:cat(path) end + vfs:cat(path) end @@ -8,13 +8,13 @@ if context.argv:len() < 3 do end else do const source = expand_path(context.argv[1]) const destination = expand_path(context.argv[2]) - const size = fs:size(source) + const size = vfs:size(source) if size < 0 do fail("cp: #{source}: no such file\n") end else do - const contents = if (size > 0) fs:read_bytes(source, 0, size) else "" - if (fs:store(destination, contents) == 1) + const contents = if (size > 0) vfs:read_bytes(source, 0, size) else "" + if (vfs:store(destination, contents) == 1) puts("#{source} -> #{destination}\n") end end @@ -211,7 +211,7 @@ fn ed_write(state, command) do const contents = ed_join(state.lines) - fs:store(path, contents) + vfs:store(path, contents) state.path = path state.dirty = :false puts("#{contents:len()}\n") @@ -267,7 +267,7 @@ fn ed_run_file(state, line, parsed) do const path = expand_path(rest:split(" ")[0]) - if fs:size(path) < 0 do + if vfs:size(path) < 0 do puts("?\n") return :nil end @@ -337,10 +337,10 @@ fn gils_ed(context) -> :hold do else "" if ed_state.path:len() > 0 do - const size = fs:size(ed_state.path) + const size = vfs:size(ed_state.path) if size > 0 do - const contents = fs:read_bytes(ed_state.path, 0, size) + const contents = vfs:read_bytes(ed_state.path, 0, size) const raw_lines = contents:split("\n") for index in 0..raw_lines:len() do diff --git a/gils/head.rv b/gils/head.rv index eb50087..c124ed3 100644 --- a/gils/head.rv +++ b/gils/head.rv @@ -1,11 +1,11 @@ # gimme some head lung fn file_lines(path) -> table | :nil do - const size = fs:size(path) + const size = vfs:size(path) if (size < 0) return :nil - const contents = if (size > 0) fs:read_bytes(path, 0, size) else "" + const contents = if (size > 0) vfs:read_bytes(path, 0, size) else "" const raw_lines = contents:split("\n") let result = {} for index in 0..raw_lines:len() do @@ -3,13 +3,4 @@ const context = env.ctx const target = if (context.argv:len() > 1) expand_path(context.argv[1]) else wd.path -if vfs_owns(target) do - vfs_ls(target) -end else do - const count = fs:ls(target) - if target == "/" do - puts(" proc/\n") - end else if count == 0 do - puts(" (empty)\n") - end -end +vfs:ls(target) diff --git a/gils/mkdir.rv b/gils/mkdir.rv index 9da7689..f701ac9 100644 --- a/gils/mkdir.rv +++ b/gils/mkdir.rv @@ -5,5 +5,5 @@ const context = env.ctx if context.argv:len() < 2 do fail("usage: mkdir <path>\n") end else do - fs:mkdir(expand_path(context.argv[1])) + vfs:mkdir(expand_path(context.argv[1])) end @@ -6,14 +6,14 @@ if context.argv:len() < 3 do end else do const source = expand_path(context.argv[1]) const destination = expand_path(context.argv[2]) - const size = fs:size(source) + const size = vfs:size(source) if size < 0 do fail("mv: #{source}: no such file\n") end else do - const contents = if (size > 0) fs:read_bytes(source, 0, size) else "" - if fs:store(destination, contents) == 1 do - fs:unlink(source) + const contents = if (size > 0) vfs:read_bytes(source, 0, size) else "" + if vfs:store(destination, contents) == 1 do + vfs:unlink(source) puts("#{source} -> #{destination}\n") end end @@ -6,5 +6,5 @@ const parsed = arg_name(context.rest, 0) if parsed.name:len() == 0 do fail("usage: rm <path>\n") end else do - fs:rm(expand_path(parsed.name)) + vfs:rm(expand_path(parsed.name)) end diff --git a/gils/tail.rv b/gils/tail.rv index c0ce1df..b5513a6 100644 --- a/gils/tail.rv +++ b/gils/tail.rv @@ -2,11 +2,11 @@ # and its between my legs fn file_lines(path) -> table | :nil do - const size = fs:size(path) + const size = vfs:size(path) if (size < 0) return :nil - const contents = if (size > 0) fs:read_bytes(path, 0, size) else "" + const contents = if (size > 0) vfs:read_bytes(path, 0, size) else "" const raw_lines = contents:split("\n") let result = {} diff --git a/gils/touch.rv b/gils/touch.rv index 3032e96..5e27309 100644 --- a/gils/touch.rv +++ b/gils/touch.rv @@ -5,9 +5,9 @@ if context.argv:len() < 2 do fail("usage: touch <path>\n") end else do const path = expand_path(context.argv[1]) - if fs:is_dir(path) do + if vfs:is_dir(path) do fail("touch: #{path}: is a directory\n") - end else if fs:size(path) < 0 do - fs:store(path, "") + end else if vfs:size(path) < 0 do + vfs:store(path, "") end end diff --git a/gils/tree.rv b/gils/tree.rv index d146403..4aad0df 100644 --- a/gils/tree.rv +++ b/gils/tree.rv @@ -1,7 +1,7 @@ # recursive directory listing fn tree_walk(path, prefix) do - const items = fs:entries(path) + const items = vfs:entries(path) if (items == :nil) return :nil @@ -29,17 +29,9 @@ end const context = env.ctx const target = if (context.argv:len() > 1) expand_path(context.argv[1]) else wd.path -if vfs_owns(target) and target != "/" do - fail("tree: #{target}: virtual dir\n") -end else if target != "/" and fs:is_dir(target) == :false do +if vfs:is_dir(target) == :false do fail("tree: #{target}: not a directory\n") end else do puts("#{target}\n") tree_walk(target, "") - # /proc is the one thing not on disk so tack it on at root - if target == "/" do - puts("`-- proc/\n") - puts(" |-- uptime\n") - puts(" `-- meminfo\n") - end end @@ -5,12 +5,12 @@ if context.argv:len() < 2 do fail("usage: wc <path>\n") end else do const path = expand_path(context.argv[1]) - const size = fs:size(path) + const size = vfs:size(path) if size < 0 do fail("wc: #{path}: no such file\n") end else do - const contents = if (size > 0) fs:read_bytes(path, 0, size) else "" + const contents = if (size > 0) vfs:read_bytes(path, 0, size) else "" let line_count = 0 let word_count = 0 let in_word = :false diff --git a/kernel/io.rv b/kernel/io.rv index af28403..43d43a9 100644 --- a/kernel/io.rv +++ b/kernel/io.rv @@ -3,12 +3,12 @@ global io = { fn open(self, path, mode) -> { path: string, offset: num } do if mode == "w" do - fs:store(path, "") + vfs:store(path, "") end let offset = 0 if mode == "a" do - const size = fs:size(path) + const size = vfs:size(path) if (size > 0) offset = size end @@ -17,23 +17,23 @@ global io = { end, fn read(self, handle, count) -> string do - const data = fs:read_bytes(handle.path, handle.offset, count) + const data = vfs:read_bytes(handle.path, handle.offset, count) handle.offset += data:len() return data end, fn read_all(self, handle) -> string do - const size = fs:size(handle.path) + const size = vfs:size(handle.path) if (size <= handle.offset) return "" - const data = fs:read_bytes(handle.path, handle.offset, size - handle.offset) + const data = vfs:read_bytes(handle.path, handle.offset, size - handle.offset) handle.offset += data:len() return data end, fn write(self, handle, data) -> num do - fs:write_at(handle.path, handle.offset, data) + vfs:write_at(handle.path, handle.offset, data) handle.offset += data:len() return data:len() end, diff --git a/kernel/seed.rv b/kernel/seed.rv index 9dc2dc5..95ed632 100644 --- a/kernel/seed.rv +++ b/kernel/seed.rv @@ -23,16 +23,9 @@ fn seed_fs() do fs:mkdir("/etc") fs:mkdir("/home") - fs:store("/etc/motd", "welcome to revel") - fs:store("/etc/profile", """ - # /etc/profile runs once at shell startup, keep it quick - - const motd_size = fs:size("/etc/motd") - if motd_size > 0 do - puts(fs:read_bytes("/etc/motd", 0, motd_size)) - puts("\n") - end - """) + for index in 0..etc_count() do + fs:store("/etc/#{etc_name(index)}", etc_src(index)) + end fs:store("/home/balls.txt", "its lowk insane how big my balls are lol jk\n\t- hachem") fs:store("/home/i have big balls.txt", "dude my balls are actually massive lol jk\n\t- hachem") diff --git a/kernel/shell.rv b/kernel/shell.rv index e016d18..e5f4caf 100644 --- a/kernel/shell.rv +++ b/kernel/shell.rv @@ -128,9 +128,7 @@ fn cmd_cd(context) do const target = if (arg == "..") parent_of(wd.path) else expand_path(arg) - if target == "/proc" - or target == "/bin" - or fs:is_dir(target) do + if vfs:is_dir(target) do wd.path = target end else do fail("cd: #{arg}: not a directory\n") diff --git a/kernel/vfs.rv b/kernel/vfs.rv index 6df71cc..6547595 100644 --- a/kernel/vfs.rv +++ b/kernel/vfs.rv @@ -1,12 +1,25 @@ -# shitty vfs implementation -# proc and /bin arent on disk, theyre completely virtual +# vfs mount table +# +# tools only ever touch vfs not fs now since they never know or care whether a path is a real +# file on disk or something, so they can read/write to shit like /dev/null for example -const TASK_STATES = { "free", "ready", "dead", "blocked" } +const T_FILE = 1 +const T_DIR = 2 +const T_CHAR = 3 # stream + +fn parent_dir(path) -> string do + const parts = path:split("/") + let out = "" + for index in 0..(parts:len() - 1) do + if (parts[index] != "") + out = out ~ "/" ~ parts[index] + end + return if (out == "") "/" else out +end -global vfs_owns = fn(path) -> bool do - if (path == "/proc" or path:starts_with?("/proc/")) - return :true - return :false +fn leaf(path) -> string do + const parts = path:split("/") + return parts[parts:len() - 1] end global parse_pid = fn(text) -> num do @@ -24,39 +37,307 @@ global parse_pid = fn(text) -> num do return number end -global vfs_ls = fn(path) do - if path == "/proc" do - puts(" uptime\n meminfo\n") +const TASK_STATES = { "free", "ready", "dead", "blocked" } + +const procfs = { + writable = :false, + + fn body(self, path) -> string | :nil do + if (path == "/proc/uptime") + return "#{math.floor(uptime() / 100)}s\n" + if (path == "/proc/meminfo") + return "#{(mem_free() shr 20)} MiB free / #{(mem_total() shr 20)} MiB total\n" + + if path:starts_with?("/proc/") do + const pid = parse_pid(path[6..]) + if (pid >= 0 and pid < task_max() and task_state(pid) != 0) + return "pid #{pid}: #{TASK_STATES[task_state(pid)]}\n" + end + + return :nil + end, + + fn entries(self, path) -> table | :nil do + if (path != "/proc") + return :nil + + let out = { + { name = "uptime", type = T_FILE, size = self:size("/proc/uptime") }, + { name = "meminfo", type = T_FILE, size = self:size("/proc/meminfo") }, + } for pid in 0..task_max() do if (task_state(pid) != 0) - puts(" #{pid}\n") + out:push({ name = "#{pid}", type = T_FILE, size = self:size("/proc/#{pid}") }) end - end else do - puts("ls: #{path}: no such directory\n") - end + + return out + end, + + fn is_dir(self, path) -> bool do + return path == "/proc" + end, + + fn size(self, path) -> num do + const b = self:body(path) + if (b == :nil) + return -1 + return b:len() + end, + + fn read_bytes(self, path, offset, length) -> string do + const b = self:body(path) + if (b == :nil) + return "" + + let stop = offset + length + if (stop > b:len()) + stop = b:len() + if (offset >= stop) + return "" + + return b[offset..stop] + end, +} + +const DEV_SAMPLE = 64 + +fn dev_size(name) -> num do + if (name == "zero" or name == "random") + return DEV_SAMPLE + if (name == "null" or name == "full") + return 0 + return -1 end -global vfs_cat = fn(path) do - if path == "/proc/uptime" do - puts("#{math.floor(uptime() / 100)}s\n") - return :nil - end +global devfs = { + writable = :true, + rng = 0, - if path == "/proc/meminfo" do - puts("#{(mem_free() shr 20)} MiB free / #{(mem_total() shr 20)} MiB total\n") - return :nil - end + # random bs go + fn next_byte(self) -> num do + if (self.rng == 0) + self.rng = (uptime() band 0xffffffff) bor 1 + + let x = self.rng + x = x bxor ((x shl 13) band 0xffffffff) + x = x bxor (x shr 17) + x = x bxor ((x shl 5) band 0xffffffff) + self.rng = x band 0xffffffff - if path:starts_with?("/proc/") do - const pid = parse_pid(path[6..]) - if pid >= 0 and pid < task_max() and task_state(pid) != 0 do - puts("pid #{pid}: #{TASK_STATES[task_state(pid)]}\n") + return self.rng band 0xff + end, + + fn entries(self, path) -> table | :nil do + if (path != "/dev") return :nil + + const names = { "null", "zero", "random", "full" } + let out = {} + for index in 0..names:len() do + const name = names[index] + out:push({ name = name, type = T_CHAR, size = dev_size(name) }) end - puts("cat: #{path}: no such file\n") - return :nil - end + return out + end, - puts("cat: #{path}: no such file\n") -end + fn is_dir(self, path) -> bool do + return path == "/dev" + end, + + fn size(self, path) -> num do + return dev_size(leaf(path)) + end, + + fn read_bytes(self, path, offset, length) -> string do + const name = leaf(path) + + if name == "zero" do + let out = "" + for index in 0..length do out = out ~ string.of_ascii(0) end + return out + end + + if name == "random" do + let out = "" + # 33..126 is the printable ascii range + for index in 0..length do out = out ~ string.of_ascii(33 + (self:next_byte() band 0x3f)) end + return out + end + + return "" # null and full read as empty + end, + + fn store(self, path, text) -> num do + const name = leaf(path) + if (name == "null") + return 1 + if name == "full" do + fail("#{path}: no space left on device\n") + return 0 + end + + fail("#{path}: read-only device\n") + return 0 + end, + + fn write_at(self, path, offset, text) do + self:store(path, text) + end, +} + +global vfs = { + mounts = { + { at = "/proc", fs = procfs }, + { at = "/dev", fs = devfs }, + }, + + fn mount(self, at, backend) do + self.mounts:push({ at = at, fs = backend }) + end, + + fn backend(self, path) do + let best = :nil + for index in 0..self.mounts:len() do + const m = self.mounts[index] + if (path == m.at or path:starts_with?(m.at ~ "/")) do + if (best == :nil or m.at:len() > best.at:len()) + best = m + end + end + return if (best == :nil) fs else best.fs + end, + + fn children_of(self, dir) -> table do + let out = {} + for index in 0..self.mounts:len() do + const at = self.mounts[index].at + if (parent_dir(at) == dir) + out:push(leaf(at)) + end + return out + end, + + fn entries(self, path) -> table | :nil do + let out = self:backend(path):entries(path) + + const kids = self:children_of(path) + if kids:len() > 0 do + if (out == :nil) + out = {} + for index in 0..kids:len() do + out:push({ name = kids[index], type = T_DIR, size = 0 }) + end + end + + return out + end, + + fn is_dir(self, path) -> bool do + for index in 0..self.mounts:len() do + if (self.mounts[index].at == path) + return :true + end + return self:backend(path):is_dir(path) + end, + + fn size(self, path) -> num do + return self:backend(path):size(path) + end, + + fn read_bytes(self, path, offset, length) -> string do + return self:backend(path):read_bytes(path, offset, length) + end, + + fn store(self, path, text) -> num do + const b = self:backend(path) + if (b == fs) + return fs:store(path, text) + if b.writable == :false do + fail("#{path}: read-only filesystem\n") + return 0 + end + return b:store(path, text) + end, + + fn write_at(self, path, offset, text) do + const b = self:backend(path) + if b == fs do + fs:write_at(path, offset, text) + return :nil + end + if b.writable == :false do + fail("#{path}: read-only filesystem\n") + return :nil + end + b:write_at(path, offset, text) + end, + + fn mkdir(self, path) do + if self:backend(path) != fs do + fail("#{path}: read-only filesystem\n") + return :nil + end + fs:mkdir(path) + end, + + fn unlink(self, path) do + if self:backend(path) != fs do + fail("#{path}: read-only filesystem\n") + return :nil + end + fs:unlink(path) + end, + + fn rm(self, path) do + if self:backend(path) != fs do + fail("rm: #{path}: read-only filesystem\n") + return :nil + end + fs:rm(path) + end, + + fn cat(self, path) do + const b = self:backend(path) + if b == fs do + fs:cat(path) + return :nil + end + + const sz = b:size(path) + if sz < 0 do + fail("cat: #{path}: no such file\n") + return :nil + end + + puts(b:read_bytes(path, 0, sz)) + end, + + fn ls(self, path) do + const items = self:entries(path) + + if items == :nil do + const sz = self:size(path) + if (sz >= 0) + puts(" #{leaf(path)} #{sz} bytes\n") + else + fail("ls: #{path}: no such directory\n") + return :nil + end + + if items:len() == 0 do + puts(" (empty)\n") + return :nil + end + + for index in 0..items:len() do + const entry = items[index] + if (entry.type == T_DIR) + puts(" #{entry.name}/\n") + else if (entry.type == T_CHAR) + puts(" #{entry.name}\n") + else + puts(" #{entry.name} #{entry.size} bytes\n") + end + end, +} |
