ramfs.lua (5218B)
1 local ramdisk_packed =[[os/ 2 apps/ 3 os/test.lua osprint("test123! test123! test123!")\nosprint("\_-'-_/")\n]] 4 5 6 function string.trimr(str, char) 7 char = char or " " 8 9 local len, epos = string.len(str), 1 10 11 for i=1,len do 12 if str:sub(len - epos, len - epos) == char then 13 epos = epos + 1 14 end 15 end 16 17 return str:sub(1, len - epos) 18 end 19 20 function string.triml(str, char) 21 char = char or " " 22 23 local len, spos = string.len(str), 1 24 25 for i=1,len do 26 if str:sub(spos, spos) == char then 27 spos = spos + 1 28 end 29 end 30 return str:sub(spos, len) 31 end 32 33 function string.trim(str, char) 34 return string.triml(string.trimr(str, char), char) 35 end 36 37 function ramdisk_followPath(fs, path, curnode) 38 path = string.trim(path:triml("/"), "/") 39 40 curnode = curnode or fs 41 42 -- Empty path means we're at the target 43 if string.len(path) == 0 then 44 return curnode, "" 45 end 46 47 if path:match("^..") then 48 if curnode.parent == nil then 49 return curnode, path 50 else 51 curnode = curnode.parent 52 end 53 end 54 55 local name = path:match("([^/]+)") 56 local remaining = path:match("/(.*)$") or "" 57 58 print("DEBUG: path='"..path.."' name='"..name.."' remaining='"..remaining.."'") 59 60 if curnode.dirs[name] then 61 if string.len(remaining) > 0 then 62 return ramdisk_followPath(fs, remaining, curnode.dirs[name]) 63 else 64 return curnode.dirs[name], "" 65 end 66 end 67 68 if curnode.files then 69 if curnode.files[name] then 70 if string.len(remaining) > 0 then 71 return ramdisk_followPath(fs, remaining, curnode.files[name]) 72 else 73 return curnode.files[name] 74 end 75 end 76 end 77 78 return curnode, name 79 end 80 81 82 local FSInstance = { 83 new = function(filesystem, manifest) 84 if filesystem == nil or manifest == nil or manifest.allowedDirs == nil then 85 return nil 86 end 87 local allowedDirs = manifest.allowedDirs 88 local instance = { 89 root = filesystem; 90 allowedDirs = allowedDirs; 91 pathHashes = {}; 92 } 93 return setmetatable(instance, FSInstance) 94 end 95 } 96 FSInstance.__index = FSInstance 97 98 function FSInstance.read(path) 99 local node, path = ramdisk_followPath(self.root, path) 100 if node and node.type == "file" then 101 return node.content 102 end 103 end 104 105 106 function ramdisk_addDir(filesystem, path) 107 local node, name = ramdisk_followPath(filesystem, path) 108 109 local dir = { 110 name = name; 111 type = "directory"; 112 dirs = {}; 113 files = {}; 114 parent = node; 115 } 116 117 node.dirs[name] = dir 118 end 119 120 function ramdisk_addFile(filesystem, path, content) 121 local node, name = ramdisk_followPath(filesystem, path) 122 local file = { 123 name = name; 124 type = "file"; 125 content = content; 126 parent = node; 127 } 128 129 node.files[name] = file 130 end 131 132 function ramdisk_print(node, path) 133 if node == nil then return nil end 134 135 local path = path or "" 136 local fullpath = path..(node.name or "") 137 138 if node.type == "directory" then 139 fullpath = fullpath.."/" 140 end 141 142 print(fullpath) 143 144 if node.type == "directory" then 145 -- Sort keys to ensure consistent ordering 146 local dirKeys = {} 147 for k in pairs(node.dirs) do 148 table.insert(dirKeys, k) 149 end 150 table.sort(dirKeys) 151 152 -- Print directories depth-first 153 for _, k in ipairs(dirKeys) do 154 ramdisk_print(node.dirs[k], fullpath) 155 end 156 157 -- Then print files 158 local fileKeys = {} 159 for k in pairs(node.files) do 160 table.insert(fileKeys, k) 161 end 162 table.sort(fileKeys) 163 164 for _, k in ipairs(fileKeys) do 165 ramdisk_print(node.files[k], fullpath) 166 end 167 end 168 end 169 170 --ramdisk_addDir(filesystem, "/os/") 171 172 --ramdisk_addDir(filesystem, "/apps/") 173 174 175 176 177 178 function ramdisk_unpack(packed, allowedDirs) 179 local fs = { 180 type = "directory"; 181 dirs = {}; 182 files = {}; 183 allowedDirs = allowedDirs; 184 parent = nil; 185 } 186 187 while packed and string.len(packed) > 0 do 188 local line = packed:match("([^\n]*)\n?") 189 packed = packed:sub(string.len(line) + 2, string.len(packed)) 190 191 if string.len(line) <= 1 then 192 break 193 end 194 195 local path, content = line:match("([^\t]+)\t(.*)") 196 197 if path == nil and line:match("^.+/$") then 198 path = line 199 print("dir: "..path) 200 ramdisk_addDir(fs, path) 201 elseif path ~= nil then 202 print("file: "..path) 203 print("content: "..(content or "")) 204 ramdisk_addFile(fs, path, content) 205 end 206 207 end 208 209 return fs 210 end 211 212 local unpacked_fs = ramdisk_unpack(ramdisk_packed) 213 214 print("~~~~~~~~~~~~~~~~~~") 215 print("Manual filesystem:") 216 ramdisk_print(filesystem) 217 print("~~~~~~~~~~~~~~~~~~") 218 print("Unpacked filesystem:") 219 ramdisk_print(unpacked_fs) 220 print("~~~~~~~~~~~~~~~~~~") 221 local fs = FSInstance.new(unpacked_fs, { allowedDirs = "all" }) 222 print("test.lua:", fs:read("/os/test.lua")) 223 print("~~~~~~~~~~~~~~~~~~") 224 225