local loadfile = ... -- raw loadfile from boot.lua local component, computer if loadfile then unicode = loadfile("/halyde/lib/unicode.lua")(loadfile) component = loadfile("/halyde/lib/component.lua")(loadfile) computer = _G.computer elseif import then unicode = import("unicode") component = import("component") computer = import("computer") end local filesystem = {} function filesystem.canonical(path) checkArg(1, path, "string") local segList = {} if path:sub(1, 1) ~= "/" then path = "/" .. path end path = path:gsub("/+", "/") for segment in path:gmatch("[^/]+") do if segment == ".." and segList[1] then table.remove(segList, #segList) elseif segment ~= "." then table.insert(segList, segment) end end return "/" .. table.concat(segList, "/") end function filesystem.concat(path1, path2) checkArg(1, path1, "string") checkArg(2, path2, "string") if path1:sub(-1, -1) == "/" then path1 = path1:sub(1, -2) end if path2:sub(1, 1) ~= "/" then path2 = "/" .. path2 end return path1 .. path2 end function filesystem.absolutePath(path) -- returns the address and absolute path of an object checkArg(1, path, "string") path = filesystem.canonical(path) local address = nil if path:find("^/tmp") then address = computer.tmpAddress() path = path:sub(5) elseif path:find("^/mnt/...") then address = component.get(path:sub(6,8)) if not address then address = computer.getBootAddress() else path = path:sub(9) end else address = computer.getBootAddress() end if not address then return nil, "no such component" end return address, path end function filesystem.exists(path) -- check if path exists checkArg(1, path, "string") local address, absPath = filesystem.absolutePath(path) if not address then return false end return component.invoke(address, "exists", absPath) end local function readBytes(self,n) n = n or 1 if n==1 then local byte = self:read(1) if byte==nil then return nil end return string.byte(byte) end local bytes, res = {string.byte(self:read(n),1,n)}, 0 for i=1,#bytes do res = (res<<8)&0xFFFFFFFF | bytes[i] end return res end local function readUnicodeChar(self) return unicode.readChar(function() return self:readBytes(1) end) end local function iterateBytes(self) return function() local byte = readBytes(self,1) if byte==nil then self:close() end return byte end end local function iterateUnicodeChars(self) return unicode.iterate(iterateBytes(self)) end function filesystem.open(path, mode, buffered) -- opens a file and returns its handle checkArg(1, path, "string") checkArg(2, mode, "string", "nil") checkArg(3, buffered, "boolean", "nil") if not mode then mode = "r" end if not buffered then buffered = true end if not (mode == "r" or mode == "w" or mode == "rb" or mode == "wb" or mode == "a" or mode == "ab") then return nil, "invalid handle type" end local address, absPath = filesystem.absolutePath(path) local handleArgs = {component.invoke(address, "open", absPath, mode)} local handle = handleArgs[1] if not handle then return table.unpack(handleArgs) end handleArgs = nil local properHandle = {} properHandle.handle = handle properHandle.address = address local content = nil local readcursor = 1 if buffered and mode:sub(1,1)=="r" then content="" repeat tmpdata = component.invoke(address, "read", handle, math.huge or math.maxinteger) content = content .. (tmpdata or "") until not tmpdata component.invoke(address, "close", handle) end function properHandle.read(self, amount) checkArg(2, amount, "number") if buffered then local limit = string.len(content)+1 local out = nil if readcursor