Added logging system, fixed filesystem read handle buffering and added read handle seeking.

This commit is contained in:
2025-09-15 08:10:50 +03:00
parent d3d5f21ab1
commit 099fbee8c6
4 changed files with 667 additions and 483 deletions
+18 -4
View File
@@ -4,14 +4,18 @@ _G._OSVERSION = "HALYDE VERSION" -- TODO: Put this in a separate config file
_G._OSLOGO = "" _G._OSLOGO = ""
_G._PUBLIC = {} _G._PUBLIC = {}
_G._PUBLIC.unicode = assert(loadfile("/lib/unicode.lua")(loadfile)) _G._PUBLIC.unicode = assert(loadfile("/lib/unicode.lua")(loadfile))
local log = assert(loadfile("/lib/log.lua")(loadfile))
local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil
repeat repeat
tmpdata = handle:read(math.huge) tmpdata = handle:read(math.huge)
_OSLOGO = _OSLOGO .. (tmpdata or "") _OSLOGO = _OSLOGO .. (tmpdata or "")
until not tmpdata until not tmpdata
handle:close()
_G.package = {["preloaded"] = {}} log.kernel.info("Loaded OS logo")
_G.package = { ["preloaded"] = {} }
loadfile("/halyde/kernel/modules/datatools.lua")() loadfile("/halyde/kernel/modules/datatools.lua")()
@@ -26,7 +30,11 @@ function _G.reqgen(load)
modulepath = module modulepath = module
elseif filesystem.exists("/lib/" .. module .. ".lua") then elseif filesystem.exists("/lib/" .. module .. ".lua") then
modulepath = "/lib/" .. module .. ".lua" modulepath = "/lib/" .. module .. ".lua"
elseif shell and shell.workingDirectory and filesystem.exists(filesystem.concat(shell.workingDirectory, module .. ".lua")) then elseif
shell
and shell.workingDirectory
and filesystem.exists(filesystem.concat(shell.workingDirectory, module .. ".lua"))
then
modulepath = shell.workingDirectory .. module .. ".lua" modulepath = shell.workingDirectory .. module .. ".lua"
end end
assert(modulepath, "Module not found\nPossible locations:\n/lib/" .. module .. ".lua") assert(modulepath, "Module not found\nPossible locations:\n/lib/" .. module .. ".lua")
@@ -36,11 +44,12 @@ function _G.reqgen(load)
data = data .. (tmpdata or "") data = data .. (tmpdata or "")
until not tmpdata until not tmpdata
handle:close() handle:close()
return(assert(load(data, "="..modulepath))(table.unpack(args))) return (assert(load(data, "=" .. modulepath))(table.unpack(args)))
end end
end end
_G.require = reqgen(_G.load) _G.require = reqgen(_G.load)
log.kernel.info("Generated userland require function")
function _G.package.preload(module) function _G.package.preload(module)
local handle, data, tmpdata = assert(filesystem.open("/lib/" .. module .. ".lua", "r")), "", nil local handle, data, tmpdata = assert(filesystem.open("/lib/" .. module .. ".lua", "r")), "", nil
@@ -49,15 +58,18 @@ function _G.package.preload(module)
data = data .. (tmpdata or "") data = data .. (tmpdata or "")
until not tmpdata until not tmpdata
handle:close() handle:close()
package.preloaded[module] = assert(load(data, "="..module))() package.preloaded[module] = assert(load(data, "=" .. module))()
_G[module] = nil _G[module] = nil
end end
-- Datatools is imported twice??
require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modload gets run, modload requires filesystem which requires computer which requires datatools. TODO: When VFS is implemented, make the pre-VFS loading of filesystem load a more basic version. And remove this. require("/halyde/kernel/datatools.lua") -- If this is not imported BEFORE modload gets run, modload requires filesystem which requires computer which requires datatools. TODO: When VFS is implemented, make the pre-VFS loading of filesystem load a more basic version. And remove this.
log.kernel.info("Loading modules")
require("/halyde/kernel/modload.lua") require("/halyde/kernel/modload.lua")
package.preload("component") package.preload("component")
package.preload("computer") package.preload("computer")
log.kernel.info("Pre-loaded low-level packages")
local component = require("component") local component = require("component")
local gpu = component.gpu local gpu = component.gpu
@@ -65,6 +77,7 @@ local screenAddress = component.list("screen")()
gpu.bind(screenAddress) gpu.bind(screenAddress)
gpu.setResolution(gpu.maxResolution()) gpu.setResolution(gpu.maxResolution())
log.kernel.info("Bound GPU to screen " .. tostring(screenAddress))
if not filesystem.exists("/halyde/config/shell.json") then -- Auto-generate configs if not filesystem.exists("/halyde/config/shell.json") then -- Auto-generate configs
filesystem.copy("/halyde/config/generate/shell.json", "/halyde/config/shell.json") filesystem.copy("/halyde/config/generate/shell.json", "/halyde/config/shell.json")
@@ -73,4 +86,5 @@ if not filesystem.exists("/halyde/config/startupapps.json") then
filesystem.copy("/halyde/config/generate/startupapps.json", "/halyde/config/startupapps.json") filesystem.copy("/halyde/config/generate/startupapps.json", "/halyde/config/startupapps.json")
end end
log.kernel.info("Starting tsched")
require("/halyde/kernel/tsched.lua") require("/halyde/kernel/tsched.lua")
+6
View File
@@ -0,0 +1,6 @@
INFO [1.45] Loaded OS logo
INFO [1.5] Generated userland require function
INFO [1.5] Loading modules
INFO [2.2] Pre-loaded low-level packages
INFO [2.3] Bound GPU to screen d9443671-225d-4637-980f-fad46c9fb845
INFO [2.3] Starting tsched
+242 -119
View File
@@ -1,6 +1,8 @@
local loadfile = ... -- raw loadfile from boot.lua local loadfile = ... -- raw loadfile from boot.lua
local unicode, component, computer local unicode, component, computer
local bufferSize = math.huge or math.maxinteger
if loadfile then if loadfile then
unicode = loadfile("/lib/unicode.lua")(loadfile) unicode = loadfile("/lib/unicode.lua")(loadfile)
component = loadfile("/lib/component.lua")(loadfile) component = loadfile("/lib/component.lua")(loadfile)
@@ -50,7 +52,7 @@ function filesystem.absolutePath(path) -- returns the address and absolute path
address = computer.tmpAddress() address = computer.tmpAddress()
path = path:sub(5) path = path:sub(5)
elseif path:find("^/mnt/...") then elseif path:find("^/mnt/...") then
address = component.get(path:sub(6,8)) address = component.get(path:sub(6, 8))
if not address then if not address then
address = computer.getBootAddress() address = computer.getBootAddress()
else else
@@ -72,29 +74,31 @@ function filesystem.exists(path) -- check if path exists
return false return false
end end
if absPath:find("^/special/drive/...") then if absPath:find("^/special/drive/...") then
return not not (computer.getBootAddress() and component.get(absPath:sub(16,18))) return not not (computer.getBootAddress() and component.get(absPath:sub(16, 18)))
end end
if absPath:find("^/special/eeprom/") then if absPath:find("^/special/eeprom/") then
return table.find({"init.lua","data.bin","label.txt"},absPath:sub(17)) return table.find({ "init.lua", "data.bin", "label.txt" }, absPath:sub(17))
end end
return component.invoke(address, "exists", absPath) return component.invoke(address, "exists", absPath)
end end
local function readBytes(self,n) local function readBytes(self, n)
n = n or 1 n = n or 1
if n==1 then if n == 1 then
local byte = self:read(1) local byte = self:read(1)
if byte==nil then return nil end if byte == nil then
return nil
end
return string.byte(byte) return string.byte(byte)
end end
local bytes, res = {string.byte(self:read(n),1,n)}, 0 local bytes, res = { string.byte(self:read(n), 1, n) }, 0
if self.littleEndian then if self.littleEndian then
for i=#bytes,1,-1 do for i = #bytes, 1, -1 do
res = (res<<8)&0xFFFFFFFF | bytes[i] res = (res << 8) & 0xFFFFFFFF | bytes[i]
end end
else else
for i=1,#bytes do for i = 1, #bytes do
res = (res<<8)&0xFFFFFFFF | bytes[i] res = (res << 8) & 0xFFFFFFFF | bytes[i]
end end
end end
return res return res
@@ -108,8 +112,10 @@ end
local function iterateBytes(self) local function iterateBytes(self)
return function() return function()
local byte = readBytes(self,1) local byte = readBytes(self, 1)
if byte==nil then self:close() end if byte == nil then
self:close()
end
return byte return byte
end end
end end
@@ -120,20 +126,20 @@ end
function filesystem.makeReadStream(content) function filesystem.makeReadStream(content)
local properHandle = {} local properHandle = {}
local readcursor = 1 local readCursor = 1
function properHandle.read(self, amount) function properHandle.read(self, amount)
checkArg(2, amount, "number") checkArg(2, amount, "number")
local limit = string.len(content)+1 local limit = string.len(content) + 1
local out = nil local out = nil
if readcursor<limit then if readCursor < limit then
if amount==math.huge then if amount == math.huge then
out = string.sub(content,math.min(readcursor,limit)) out = string.sub(content, math.min(readCursor, limit))
else else
out = string.sub(content,math.min(readcursor,limit),math.min(readcursor+amount-1,limit)) out = string.sub(content, math.min(readCursor, limit), math.min(readCursor + amount - 1, limit))
end end
end end
readcursor=readcursor+amount readCursor = readCursor + amount
if out=="" then if out == "" then
return nil return nil
end end
return out return out
@@ -146,7 +152,7 @@ function filesystem.makeReadStream(content)
return nil return nil
end end
function properHandle.close() function properHandle.close()
content=nil content = nil
end end
return properHandle return properHandle
end end
@@ -168,14 +174,14 @@ function filesystem.open(path, mode, buffered) -- opens a file and returns its h
return nil, "/special does not allow creating files" return nil, "/special does not allow creating files"
end end
local address, absPath = filesystem.absolutePath(path) local address, absPath = filesystem.absolutePath(path)
local unmanagedDrive = address==computer.getBootAddress() and absPath:find("^/special/drive") local unmanagedDrive = address == computer.getBootAddress() and absPath:find("^/special/drive")
local unmanagedProxy, sectorSize, sectorCount, handle local unmanagedProxy, sectorSize, sectorCount, handle
if unmanagedDrive then if unmanagedDrive then
unmanagedProxy = component.proxy(component.get(absPath:sub(16,18))) unmanagedProxy = component.proxy(component.get(absPath:sub(16, 18)))
sectorSize = unmanagedProxy.getSectorSize() sectorSize = unmanagedProxy.getSectorSize()
sectorCount = math.ceil(unmanagedProxy.getCapacity()/sectorSize) sectorCount = math.ceil(unmanagedProxy.getCapacity() / sectorSize)
elseif not (address==computer.getBootAddress() and absPath:find("^/special/")) then elseif not (address == computer.getBootAddress() and absPath:find("^/special/")) then
local handleArgs = {component.invoke(address, "open", absPath, mode)} local handleArgs = { component.invoke(address, "open", absPath, mode) }
handle = handleArgs[1] handle = handleArgs[1]
if not handle then if not handle then
return table.unpack(handleArgs) return table.unpack(handleArgs)
@@ -186,41 +192,86 @@ function filesystem.open(path, mode, buffered) -- opens a file and returns its h
properHandle.handle = handle properHandle.handle = handle
properHandle.address = address properHandle.address = address
local content = nil local content = nil
local readcursor = 1 local bufferOffset = 0 -- Position in file where buffer starts
if buffered and mode:sub(1,1)=="r" then local readCursor = 1 -- Position within buffer (1-based)
content=""
repeat if buffered and mode == "r" then
tmpdata = component.invoke(address, "read", handle, math.huge or math.maxinteger) content = component.invoke(address, "read", handle, bufferSize) or ""
content = content .. (tmpdata or "") bufferOffset = 0
until not tmpdata readCursor = 1
component.invoke(address, "close", handle)
end end
function properHandle.read(self, amount) function properHandle.read(self, amount)
checkArg(2, amount, "number") checkArg(2, amount, "number")
if unmanagedDrive then if unmanagedDrive then
local sectorIdx = ((readcursor-1)//sectorSize)+1 -- TODO: Test if this still works
if sectorIdx>sectorCount then return nil end local sectorIdx = ((readCursor - 1) // sectorSize) + 1
if sectorIdx > sectorCount then
return nil
end
local sector = unmanagedProxy.readSector(sectorIdx) local sector = unmanagedProxy.readSector(sectorIdx)
local data = sector:sub(((readcursor-1)%sectorSize)+1,((readcursor+math.min(amount,sectorSize)-2)%sectorSize)+1) local data = sector:sub(
readcursor=readcursor+#data ((readCursor - 1) % sectorSize) + 1,
if data=="" then return nil end ((readCursor + math.min(amount, sectorSize) - 2) % sectorSize) + 1
)
readCursor = readCursor + #data
if data == "" then
return nil
end
return data return data
else else
if buffered then if buffered then
local limit = string.len(content)+1 if amount == math.huge or amount == math.maxinteger then
local out = nil -- Read everything remaining
if readcursor<limit then local result = ""
if amount==math.huge then
out = string.sub(content,math.min(readcursor,limit)) -- First, get what's left in current buffer
if content and readCursor <= #content then
result = content:sub(readCursor)
readCursor = #content + 1
end
-- Then read all remaining data from file
while true do
local newData = component.invoke(address, "read", handle, bufferSize)
if not newData or newData == "" then
break
end
result = result .. newData
end
-- Update buffer state
content = nil
bufferOffset = bufferOffset + #(content or "")
return result ~= "" and result or nil
else else
out = string.sub(content,math.min(readcursor,limit),math.min(readcursor+amount-1,limit)) local result = ""
local remaining = amount
while remaining > 0 do
-- If we need more data or buffer is empty
if not content or readCursor > #content then
content = component.invoke(address, "read", handle, bufferSize)
if not content or content == "" then
break
end end
bufferOffset = bufferOffset + (readCursor - 1)
readCursor = 1
end end
readcursor=readcursor+amount
if out=="" then -- Extract data from current buffer
return nil local available = #content - readCursor + 1
local toRead = math.min(remaining, available)
local chunk = content:sub(readCursor, readCursor + toRead - 1)
result = result .. chunk
readCursor = readCursor + toRead
remaining = remaining - toRead
end
return result ~= "" and result or nil
end end
return out
else else
return component.invoke(self.address, "read", self.handle, amount) return component.invoke(self.address, "read", self.handle, amount)
end end
@@ -233,16 +284,26 @@ function filesystem.open(path, mode, buffered) -- opens a file and returns its h
function properHandle.write(self, data) function properHandle.write(self, data)
checkArg(2, data, "string") checkArg(2, data, "string")
if unmanagedDrive then if unmanagedDrive then
local startSector = ((readcursor-1)//sectorSize)+1 local startSector = ((readCursor - 1) // sectorSize) + 1
if startSector>sectorCount then return nil, "not enough space" end if startSector > sectorCount then
local startSByte = ((readcursor-1)%sectorSize)+1 return nil, "not enough space"
local sect = unmanagedProxy.readSector(startSector)
unmanagedProxy.writeSector(startSector,sect:sub(1,startSByte-1)..data:sub(1,sectorSize-startSByte+1))
for i=2,(#data+startSByte)//sectorSize do
if startSector+i-1>sectorCount then return nil, "not enough space" end
unmanagedProxy.writeSector(startSector+i-1,data:sub(startSByte+sectorSize*(i-1),startSByte+sectorSize*i-1))
end end
readcursor=readcursor+#data local startSByte = ((readCursor - 1) % sectorSize) + 1
local sect = unmanagedProxy.readSector(startSector)
unmanagedProxy.writeSector(
startSector,
sect:sub(1, startSByte - 1) .. data:sub(1, sectorSize - startSByte + 1)
)
for i = 2, (#data + startSByte) // sectorSize do
if startSector + i - 1 > sectorCount then
return nil, "not enough space"
end
unmanagedProxy.writeSector(
startSector + i - 1,
data:sub(startSByte + sectorSize * (i - 1), startSByte + sectorSize * i - 1)
)
end
readCursor = readCursor + #data
return true return true
else else
return component.invoke(self.address, "write", self.handle, data) return component.invoke(self.address, "write", self.handle, data)
@@ -251,33 +312,32 @@ function filesystem.open(path, mode, buffered) -- opens a file and returns its h
function properHandle.close(self) function properHandle.close(self)
if buffered then if buffered then
content = nil content = nil
else end
return component.invoke(self.address, "close", self.handle) return component.invoke(self.address, "close", self.handle)
end end
end if address == computer.getBootAddress() then
if address==computer.getBootAddress() then
local eeprom local eeprom
pcall(function() pcall(function()
eeprom = component.eeprom eeprom = component.eeprom
end) end)
if eeprom then if eeprom then
local getFunc, setFunc local getFunc, setFunc
if absPath=="/special/eeprom/init.lua" then if absPath == "/special/eeprom/init.lua" then
getFunc,setFunc = "get","set" getFunc, setFunc = "get", "set"
elseif absPath=="/special/eeprom/data.bin" then elseif absPath == "/special/eeprom/data.bin" then
getFunc,setFunc = "getData","setData" getFunc, setFunc = "getData", "setData"
elseif absPath=="/special/eeprom/label.txt" then elseif absPath == "/special/eeprom/label.txt" then
getFunc,setFunc = "getLabel","setLabel" getFunc, setFunc = "getLabel", "setLabel"
end end
if mode:sub(1,1)=="r" and getFunc then if mode:sub(1, 1) == "r" and getFunc then
local stream = filesystem.makeReadStream(eeprom[getFunc]() or "") local stream = filesystem.makeReadStream(eeprom[getFunc]() or "")
properHandle.read = stream.read properHandle.read = stream.read
properHandle.close = stream.close properHandle.close = stream.close
elseif mode:sub(1,1)=="w" and setFunc then elseif mode:sub(1, 1) == "w" and setFunc then
local content = "" local content = ""
function properHandle.write(self, data) function properHandle.write(self, data)
checkArg(2, data, "string") checkArg(2, data, "string")
content=content..data content = content .. data
end end
function properHandle.close(self) function properHandle.close(self)
return eeprom[setFunc](content) return eeprom[setFunc](content)
@@ -285,6 +345,39 @@ function filesystem.open(path, mode, buffered) -- opens a file and returns its h
end end
end end
end end
function properHandle.seek(self, whence, offset)
checkArg(2, whence, "string", "number")
checkArg(3, offset, "number", "nil")
if not offset then
offset = 0
end
if type(whence) == "number" then
offset = whence
end
if not whence or type(whence) == "number" then
whence = "cur"
end
if buffered then
-- Calculate current absolute position in file
local currentAbsolutePos = bufferOffset + readCursor - 1
-- Seek the underlying file handle to the correct position
component.invoke(self.address, "seek", self.handle, "set", currentAbsolutePos)
-- Now perform the actual seek
local newPos = component.invoke(self.address, "seek", self.handle, whence, offset)
-- Invalidate the buffer and reset positions
content = nil
bufferOffset = newPos or 0
readCursor = 1
return newPos
else
return component.invoke(self.address, "seek", self.handle, whence, offset)
end
end
return properHandle return properHandle
end end
@@ -296,7 +389,7 @@ function filesystem.list(path)
local returnTable = {} local returnTable = {}
local tmpAddress = computer.tmpAddress() local tmpAddress = computer.tmpAddress()
for address, _ in component.list("filesystem") do for address, _ in component.list("filesystem") do
if address~=tmpAddress then if address ~= tmpAddress then
table.insert(returnTable, address:sub(1, 3) .. "/") table.insert(returnTable, address:sub(1, 3) .. "/")
end end
end end
@@ -305,13 +398,13 @@ function filesystem.list(path)
local returnTable = {} local returnTable = {}
local tmpAddress = computer.tmpAddress() local tmpAddress = computer.tmpAddress()
for address, type in component.list("drive") do for address, type in component.list("drive") do
if address~=tmpAddress and type=="drive" then if address ~= tmpAddress and type == "drive" then
table.insert(returnTable, address:sub(1, 3)) table.insert(returnTable, address:sub(1, 3))
end end
end end
return returnTable return returnTable
elseif path=="/special/eeprom" then elseif path == "/special/eeprom" then
return {"init.lua","data.bin","label.txt"} return { "init.lua", "data.bin", "label.txt" }
else else
local address, absPath = filesystem.absolutePath(path) local address, absPath = filesystem.absolutePath(path)
if not address then if not address then
@@ -327,11 +420,13 @@ function filesystem.size(path)
if not address then if not address then
return false return false
end end
if address==computer.getBootAddress() then if address == computer.getBootAddress() then
if absPath:find("^/special/drive") then if absPath:find("^/special/drive") then
local drive = component.get(absPath:sub(16,18)) local drive = component.get(absPath:sub(16, 18))
if not drive then return false end if not drive then
return component.invoke(drive,"getCapacity") return false
end
return component.invoke(drive, "getCapacity")
elseif absPath:find("^/special/eeprom") then elseif absPath:find("^/special/eeprom") then
local eeprom local eeprom
pcall(function() pcall(function()
@@ -339,11 +434,11 @@ function filesystem.size(path)
end) end)
if eeprom then if eeprom then
local getFunc local getFunc
if absPath=="/special/eeprom/init.lua" then if absPath == "/special/eeprom/init.lua" then
getFunc = "get" getFunc = "get"
elseif absPath=="/special/eeprom/data.bin" then elseif absPath == "/special/eeprom/data.bin" then
getFunc = "getData" getFunc = "getData"
elseif absPath=="/special/eeprom/label.txt" then elseif absPath == "/special/eeprom/label.txt" then
getFunc = "getLabel" getFunc = "getLabel"
end end
return #(eeprom[getFunc]()) return #(eeprom[getFunc]())
@@ -353,52 +448,66 @@ function filesystem.size(path)
return component.invoke(address, "size", absPath) return component.invoke(address, "size", absPath)
end end
local function getRecursiveList(address,absPath) local function getRecursiveList(address, absPath)
local list = component.invoke(address,"list",absPath) local list = component.invoke(address, "list", absPath)
local dirList = {} local dirList = {}
local listChanged = true local listChanged = true
while listChanged do while listChanged do
listChanged = false listChanged = false
for i=1,#list do for i = 1, #list do
if component.invoke(address, "isDirectory", absPath.."/"..list[i]) then if component.invoke(address, "isDirectory", absPath .. "/" .. list[i]) then
listChanged = true listChanged = true
local dir = list[i] local dir = list[i]
if dir:sub(-1)=="/" then dir=dir:sub(1,-2) end if dir:sub(-1) == "/" then
table.insert(dirList,dir) dir = dir:sub(1, -2)
table.remove(list,i) end
local subDir = component.invoke(address,"list",absPath.."/"..dir) table.insert(dirList, dir)
for j=1,#subDir do table.insert(list,dir.."/"..subDir[j]) end table.remove(list, i)
local subDir = component.invoke(address, "list", absPath .. "/" .. dir)
for j = 1, #subDir do
table.insert(list, dir .. "/" .. subDir[j])
end end
end end
end end
return list,dirList end
return list, dirList
end end
local function copyContent(fromHandle,toHandle) local function copyContent(fromHandle, toHandle)
if not (fromHandle and toHandle) then return end if not (fromHandle and toHandle) then
local memory = math.floor(computer.freeMemory()*0.8) return
end
local memory = math.floor(computer.freeMemory() * 0.8)
local tmpdata local tmpdata
while true do while true do
tmpdata = fromHandle:read(memory) tmpdata = fromHandle:read(memory)
if not tmpdata then break end if not tmpdata then
local status,reason = toHandle:write(tmpdata) break
if status~=true then break end end
local status, reason = toHandle:write(tmpdata)
if status ~= true then
break
end
end end
fromHandle:close() fromHandle:close()
toHandle:close() toHandle:close()
end end
local function copyRecursive(fromAddress,fromAbsPath,toAddress,toAbsPath) local function copyRecursive(fromAddress, fromAbsPath, toAddress, toAbsPath)
-- TODO: make this use copyContent -- TODO: make this use copyContent
if fromAbsPath:sub(-1)=="/" then fromAbsPath=fromAbsPath:sub(1,-2) end if fromAbsPath:sub(-1) == "/" then
if toAbsPath:sub(-1)=="/" then toAbsPath=toAbsPath:sub(1,-2) end fromAbsPath = fromAbsPath:sub(1, -2)
component.invoke(toAddress,"makeDirectory",toAbsPath)
local fileList,dirList = getRecursiveList(fromAddress,fromAbsPath)
for i=1,#dirList do
component.invoke(toAddress,"makeDirectory",toAbsPath.."/"..dirList[i])
end end
for i=1,#fileList do if toAbsPath:sub(-1) == "/" then
local fromFile, toFile = fromAbsPath.."/"..fileList[i], toAbsPath.."/"..fileList[i] toAbsPath = toAbsPath:sub(1, -2)
end
component.invoke(toAddress, "makeDirectory", toAbsPath)
local fileList, dirList = getRecursiveList(fromAddress, fromAbsPath)
for i = 1, #dirList do
component.invoke(toAddress, "makeDirectory", toAbsPath .. "/" .. dirList[i])
end
for i = 1, #fileList do
local fromFile, toFile = fromAbsPath .. "/" .. fileList[i], toAbsPath .. "/" .. fileList[i]
--[[ local handle = component.invoke(fromAddress, "open", fromFile, "r") --[[ local handle = component.invoke(fromAddress, "open", fromFile, "r")
local data, tmpdata = "", nil local data, tmpdata = "", nil
repeat repeat
@@ -412,11 +521,19 @@ local function copyRecursive(fromAddress,fromAbsPath,toAddress,toAbsPath)
local fromHandle = component.invoke(fromAddress, "open", fromFile, "r") local fromHandle = component.invoke(fromAddress, "open", fromFile, "r")
local toHandle = component.invoke(toAddress, "open", toFile, "w") local toHandle = component.invoke(toAddress, "open", toFile, "w")
copyContent({ copyContent({
["read"]=function(...) return component.invoke(fromAddress, "read", handle, ...) end, ["read"] = function(...)
["close"]=function(...) return component.invoke(fromAddress, "close", handle, ...) end return component.invoke(fromAddress, "read", handle, ...)
},{ end,
["write"]=function(...) return component.invoke(fromAddress, "write", handle, ...) end, ["close"] = function(...)
["close"]=function(...) return component.invoke(fromAddress, "close", handle, ...) end return component.invoke(fromAddress, "close", handle, ...)
end,
}, {
["write"] = function(...)
return component.invoke(fromAddress, "write", handle, ...)
end,
["close"] = function(...)
return component.invoke(fromAddress, "close", handle, ...)
end,
}) })
end end
end end
@@ -441,7 +558,7 @@ function filesystem.rename(fromPath, toPath)
if fromAddress == toAddress then if fromAddress == toAddress then
return component.invoke(fromAddress, "rename", fromAbsPath, toAbsPath) return component.invoke(fromAddress, "rename", fromAbsPath, toAbsPath)
elseif filesystem.isDirectory(fromPath) then -- component.invoke(fromAddress, "isDirectory", fromAbsPath) then elseif filesystem.isDirectory(fromPath) then -- component.invoke(fromAddress, "isDirectory", fromAbsPath) then
copyRecursive(fromAddress,fromAbsPath,toAddress,toAbsPath) copyRecursive(fromAddress, fromAbsPath, toAddress, toAbsPath)
filesystem.remove(fromPath) -- component.invoke(fromAddress,"remove", fromAbsPath) filesystem.remove(fromPath) -- component.invoke(fromAddress,"remove", fromAbsPath)
else else
local handle, data, tmpdata = filesystem.open(fromPath), "", nil -- component.invoke(fromAddress, "open", fromAbsPath, "r"), "", nil local handle, data, tmpdata = filesystem.open(fromPath), "", nil -- component.invoke(fromAddress, "open", fromAbsPath, "r"), "", nil
@@ -466,7 +583,7 @@ function filesystem.copy(fromPath, toPath)
return false return false
end end
if filesystem.isDirectory(fromPath) then -- component.invoke(fromAddress, "isDirectory", fromAbsPath) if filesystem.isDirectory(fromPath) then -- component.invoke(fromAddress, "isDirectory", fromAbsPath)
copyRecursive(fromAddress,fromAbsPath,toAddress,toAbsPath) copyRecursive(fromAddress, fromAbsPath, toAddress, toAbsPath)
else else
--[[ local handle = filesystem.open(fromPath,"r") --[[ local handle = filesystem.open(fromPath,"r")
local data, tmpdata = "", nil local data, tmpdata = "", nil
@@ -478,7 +595,7 @@ function filesystem.copy(fromPath, toPath)
local handle = filesystem.open(toPath,"w") local handle = filesystem.open(toPath,"w")
handle:write(data) handle:write(data)
handle:close() ]] handle:close() ]]
copyContent(filesystem.open(fromPath,"r"),filesystem.open(toPath,"w")) copyContent(filesystem.open(fromPath, "r"), filesystem.open(toPath, "w"))
end end
end end
@@ -488,9 +605,15 @@ function filesystem.remove(path)
if not address then if not address then
return false return false
end end
if absPath:find("^/special") then return false end if absPath:find("^/special") then
if absPath:find("^/tmp") then return false end return false
if absPath:find("^/mnt") then return false end end
if absPath:find("^/tmp") then
return false
end
if absPath:find("^/mnt") then
return false
end
return component.invoke(address, "remove", absPath) return component.invoke(address, "remove", absPath)
end end
@@ -503,4 +626,4 @@ function filesystem.makeDirectory(path)
return component.invoke(address, "makeDirectory", absPath) return component.invoke(address, "makeDirectory", absPath)
end end
return(filesystem) return filesystem
+66 -25
View File
@@ -1,30 +1,71 @@
local fs = require("filesystem") local fs, computer
local computer = require("computer") if require then
fs = require("filesystem")
computer = require("computer")
else
local loadfile = ...
fs = loadfile("/lib/filesystem.lua")(loadfile)
computer = _G.computer
end
logFileSizeLimit = 16384
local function writeToLog(path, text)
local handle
if fs.exists(path) then
handle = assert(fs.open(path, "a"))
else
handle = assert(fs.open(path, "w"))
end
handle:write(text .. "\n")
handle:close()
-- Log trimming if it gets too long
if fs.size(path) > logFileSizeLimit then
ocelot.log("Trimming log...")
local newlineCounter = 0
local sizeCounter = 0
local readHandle = fs.open(path, "r")
local chunkSize = 1024
readHandle:seek("end", -chunkSize)
repeat
local readText = readHandle:read(chunkSize)
readHandle:seek(-chunkSize * 2)
local _, newlineCount = readText:gsub("\n", "\n")
newlineCounter = newlineCounter + newlineCount
sizeCounter = sizeCounter + chunkSize
until sizeCounter >= logFileSizeLimit * 0.75
readHandle:seek(chunkSize)
local writeHandle = fs.open(path, "w")
while true do
local tmpdata = readHandle:read(math.huge or math.maxinteger)
if not tmpdata then
break
end
writeHandle:write(tmpdata)
end
readHandle:close()
writeHandle:close()
end
end
local log = {} local log = {}
function log.add(text, logType) setmetatable(log, {
checkArg(1, text, "string") ["__index"] = function(tab, index)
checkArg(2, logType, "string", "nil") return {
if logType ~= "debug" and logType ~= "info" and logType ~= "warning" and logType ~= "error" and logType then ["logpath"] = fs.concat("/halyde/logs/", index .. ".log"),
error("Log type must either be debug, info, warning or error.") ["info"] = function(text)
end writeToLog(fs.concat("/halyde/logs/", index .. ".log"), "INFO [" .. computer.uptime() .. "] " .. text)
if not logType then end,
logType = "debug" ["warn"] = function(text)
end writeToLog(fs.concat("/halyde/logs/", index .. ".log"), "WARN [" .. computer.uptime() .. "] " .. text)
local handle = fs.open("/halyde/system.log", "a") end,
local time = computer.uptime() ["error"] = function(text)
local logText = string.format("[%02d:%02d:%02d:%02d] " .. text, math.floor(time / 86400), math.floor(time / 3600 % 24), math.floor(time / 60 % 60), math.floor(time % 60)) .. "\n" writeToLog(fs.concat("/halyde/logs/", index .. ".log"), "ERROR [" .. computer.uptime() .. "] " .. text)
if logType == "debug" then end,
handle:write("\27[37m" .. logText) }
elseif logType == "info" then end,
handle:write("\27[97m" .. logText) })
elseif logType == "warning" then
handle:write("\27[93m" .. logText)
else
handle:write("\27[91m" .. logText)
end
handle:close()
end
return log return log