From ea464339e9341eb260491f0c6740e7dc0e0aa81e Mon Sep 17 00:00:00 2001 From: Ponali Date: Mon, 14 Jul 2025 14:32:29 +0200 Subject: [PATCH] v2.4.0 - Added a /special/ folder with files for interacting with unmanaged drives and EEPROMs. --- argentum.cfg | 4 +- halyde/core/boot.lua | 3 +- halyde/core/termlib.lua | 2 +- halyde/lib/filesystem.lua | 583 +++++++++++++++++++++++--------------- init.lua | 17 +- 5 files changed, 374 insertions(+), 235 deletions(-) diff --git a/argentum.cfg b/argentum.cfg index 0ef212b..5dc4dcf 100644 --- a/argentum.cfg +++ b/argentum.cfg @@ -1,7 +1,7 @@ local agcfg = { ["halyde"] = { ["maindir"] = "", - ["version"] = "2.3.0", + ["version"] = "2.4.0", ["description"] = "A universal, customizable and feature-packed operating system for OpenComputers.", ["directories"] = { "halyde/apps", @@ -10,7 +10,7 @@ local agcfg = { "halyde/core", "halyde/drivers", "halyde/lib", - "halyde" + "halyde", "home", "mnt" }, diff --git a/halyde/core/boot.lua b/halyde/core/boot.lua index c2650dc..6518c98 100644 --- a/halyde/core/boot.lua +++ b/halyde/core/boot.lua @@ -1,7 +1,7 @@ local loadfile = ... local filesystem = loadfile("/halyde/lib/filesystem.lua")(loadfile) -_G._OSVERSION = "Halyde 2.3.0" +_G._OSVERSION = "Halyde 2.4.0" _G._OSLOGO = "" local handle, tmpdata = filesystem.open("/halyde/config/oslogo.ans", "r"), nil repeat @@ -32,6 +32,7 @@ function _G.import(module, ...) tmpdata = handle:read(math.huge or math.maxinteger) data = data .. (tmpdata or "") until not tmpdata + handle:close() return(assert(load(data, "="..modulepath))(table.unpack(args))) end diff --git a/halyde/core/termlib.lua b/halyde/core/termlib.lua index a0a61c8..21ad921 100644 --- a/halyde/core/termlib.lua +++ b/halyde/core/termlib.lua @@ -91,7 +91,7 @@ local function findCodeEnd(text,i) return v>=min and v<=max end i=i+2 - while not inRange(text:byte(i),0x40,0x7F) do i=i+1 end + while i<=#text and not inRange(text:byte(i),0x40,0x7F) do i=i+1 end return i end diff --git a/halyde/lib/filesystem.lua b/halyde/lib/filesystem.lua index 2691b8a..522d99f 100644 --- a/halyde/lib/filesystem.lua +++ b/halyde/lib/filesystem.lua @@ -71,6 +71,12 @@ function filesystem.exists(path) -- check if path exists if not address then return false end + if absPath:find("^/special/drive/...") then + return not not (computer.getBootAddress() and component.get(absPath:sub(16,18))) + end + if absPath:find("^/special/eeprom/") then + return table.find({"init.lua","data.bin","label.txt"},absPath:sub(17)) + end return component.invoke(address, "exists", absPath) end @@ -106,231 +112,6 @@ 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 readcursorsectorCount then return nil end + local sector = unmanagedProxy.readSector(sectorIdx) + local data = sector:sub(((readcursor-1)%sectorSize)+1,((readcursor+math.min(amount,sectorSize)-2)%sectorSize)+1) + readcursor=readcursor+#data + if data=="" then return nil end + return data + else + if buffered then + local limit = string.len(content)+1 + local out = nil + if readcursorsectorCount then return nil, "not enough space" end + 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 + else + return component.invoke(self.address, "write", self.handle, data) + end + end + function properHandle.close(self) + if buffered then + content = nil + else + return component.invoke(self.address, "close", self.handle) + end + end + if address==computer.getBootAddress() then + local eeprom + pcall(function() + eeprom = component.eeprom + end) + if eeprom then + local getFunc, setFunc + if absPath=="/special/eeprom/init.lua" then + getFunc,setFunc = "get","set" + elseif absPath=="/special/eeprom/data.bin" then + getFunc,setFunc = "getData","setData" + elseif absPath=="/special/eeprom/label.txt" then + getFunc,setFunc = "getLabel","setLabel" + end + if mode:sub(1,1)=="r" and getFunc then + local stream = filesystem.makeReadStream(eeprom[getFunc]() or "") + properHandle.read = stream.read + properHandle.close = stream.close + elseif mode:sub(1,1)=="w" and setFunc then + local content = "" + function properHandle.write(self, data) + checkArg(2, data, "string") + content=content..data + end + function properHandle.close(self) + return eeprom[setFunc](content) + end + end + end + end + return properHandle +end + +function filesystem.list(path) + checkArg(1, path, "string") + path = filesystem.canonical(path) + if path == "/mnt" then + -- list drives + local returnTable = {} + local tmpAddress = computer.tmpAddress() + for address, _ in component.list("filesystem") do + if address~=tmpAddress then + table.insert(returnTable, address:sub(1, 3) .. "/") + end + end + return returnTable + elseif path == "/special/drive" then + local returnTable = {} + local tmpAddress = computer.tmpAddress() + for address, _ in component.list("drive") do + if address~=tmpAddress then + table.insert(returnTable, address:sub(1, 3)) + end + end + return returnTable + elseif path=="/special/eeprom" then + return {"init.lua","data.bin","label.txt"} + else + local address, absPath = filesystem.absolutePath(path) + if not address then + return false + end + return component.invoke(address, "list", absPath) + end +end + +function filesystem.size(path) + checkArg(1, path, "string") + local address, absPath = filesystem.absolutePath(path) + if not address then + return false + end + if address==computer.getBootAddress() then + if absPath:find("^/special/drive") then + local drive = component.get(absPath:sub(16,18)) + if not drive then return false end + return component.invoke(drive,"getCapacity") + elseif absPath:find("^/special/eeprom") then + local eeprom + pcall(function() + eeprom = component.eeprom + end) + if eeprom then + local getFunc + if absPath=="/special/eeprom/init.lua" then + getFunc = "get" + elseif absPath=="/special/eeprom/data.bin" then + getFunc = "getData" + elseif absPath=="/special/eeprom/label.txt" then + getFunc = "getLabel" + end + return #(eeprom[getFunc]()) + end + end + end + return component.invoke(address, "size", absPath) +end + +local function getRecursiveList(address,absPath) + local list = component.invoke(address,"list",absPath) + local dirList = {} + local listChanged = true + while listChanged do + listChanged = false + for i=1,#list do + if component.invoke(address, "isDirectory", absPath.."/"..list[i]) then + listChanged = true + local dir = list[i] + if dir:sub(-1)=="/" then dir=dir:sub(1,-2) end + table.insert(dirList,dir) + 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 + return list,dirList +end + +local function copyContent(fromHandle,toHandle) + if not (fromHandle and toHandle) then return end + local memory = math.floor(computer.freeMemory()*0.8) + local tmpdata + while true do + tmpdata = fromHandle:read(memory) + if not tmpdata then break end + local status,reason = toHandle:write(tmpdata) + if status~=true then break end + end + fromHandle:close() + toHandle:close() +end + +local function copyRecursive(fromAddress,fromAbsPath,toAddress,toAbsPath) + -- TODO: make this use copyContent + if fromAbsPath:sub(-1)=="/" then fromAbsPath=fromAbsPath:sub(1,-2) end + if toAbsPath:sub(-1)=="/" then 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 data, tmpdata = "", nil + repeat + tmpdata = component.invoke(fromAddress, "read", handle, math.huge or math.maxinteger) + data = data .. (tmpdata or "") + until not tmpdata + tmpdata = component.invoke(fromAddress, "close", handle) + local handle = component.invoke(toAddress, "open", toFile, "w") + component.invoke(toAddress, "write", handle, data) + component.invoke(toAddress, "close", handle) ]] + local fromHandle = component.invoke(fromAddress, "open", fromFile, "r") + local toHandle = component.invoke(toAddress, "open", toFile, "w") + copyContent({ + ["read"]=function(...) return component.invoke(fromAddress, "read", handle, ...) end, + ["close"]=function(...) 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 + +function filesystem.isDirectory(path) + checkArg(1, path, "string") + local address, absPath = filesystem.absolutePath(path) + if not address then + return false + end + return component.invoke(address, "isDirectory", absPath) +end + +function filesystem.rename(fromPath, toPath) + checkArg(1, fromPath, "string") + checkArg(2, toPath, "string") + local fromAddress, fromAbsPath = filesystem.absolutePath(fromPath) + local toAddress, toAbsPath = filesystem.absolutePath(toPath) + if not fromAddress or not toAddress then + return false + end + if fromAddress == toAddress then + return component.invoke(fromAddress, "rename", fromAbsPath, toAbsPath) + elseif filesystem.isDirectory(fromPath) then -- component.invoke(fromAddress, "isDirectory", fromAbsPath) then + copyRecursive(fromAddress,fromAbsPath,toAddress,toAbsPath) + filesystem.remove(fromPath) -- component.invoke(fromAddress,"remove", fromAbsPath) + else + local handle, data, tmpdata = filesystem.open(fromPath), "", nil -- component.invoke(fromAddress, "open", fromAbsPath, "r"), "", nil + repeat + tmpdata = handle:read(math.huge or math.maxinteger) -- component.invoke(fromAddress, "read", handle, math.huge or math.maxinteger) + data = data .. (tmpdata or "") + until not tmpdata + tmpdata = handle:close() -- component.invoke(fromAddress, "close", handle) + local handle = filesystem.open(toPath) -- component.invoke(toAddress, "open", toAbsPath, "w") + handle:write(data) -- component.invoke(toAddress, "write", handle, data) + handle:close() -- component.invoke(toAddress, "close", handle) + filesystem.remove(fromPath) -- component.invoke(fromAddress, "remove", fromAbsPath) + end +end + +function filesystem.copy(fromPath, toPath) + checkArg(1, fromPath, "string") + checkArg(2, toPath, "string") + local fromAddress, fromAbsPath = filesystem.absolutePath(fromPath) + local toAddress, toAbsPath = filesystem.absolutePath(toPath) + if not fromAddress or not toAddress then + return false + end + if filesystem.isDirectory(fromPath) then -- component.invoke(fromAddress, "isDirectory", fromAbsPath) + copyRecursive(fromAddress,fromAbsPath,toAddress,toAbsPath) + else + --[[ local handle = filesystem.open(fromPath,"r") + local data, tmpdata = "", nil + repeat + tmpdata = handle:read(math.huge or math.maxinteger) + data = data .. (tmpdata or "") + until not tmpdata + tmpdata = handle:close() + local handle = filesystem.open(toPath,"w") + handle:write(data) + handle:close() ]] + copyContent(filesystem.open(fromPath,"r"),filesystem.open(toPath,"w")) + end +end + +function filesystem.remove(path) + checkArg(1, path, "string") + local address, absPath = filesystem.absolutePath(path) + if not address then + return false + end + if absPath:find("^/special") then return false end + if absPath:find("^/tmp") then return false end + if absPath:find("^/mnt") then return false end + return component.invoke(address, "remove", absPath) +end + +function filesystem.makeDirectory(path) + checkArg(1, path, "string") + local address, absPath = filesystem.absolutePath(path) + if not address then + return false + end + return component.invoke(address, "makeDirectory", absPath) +end + return(filesystem) diff --git a/init.lua b/init.lua index 93e15e1..56c7dcd 100644 --- a/init.lua +++ b/init.lua @@ -39,10 +39,15 @@ if not result then gpu.set(2,i,line) i = i + 1 end - gpu.set(2,i+1, "Press any key to restart.") - local evname - repeat - evname = computer.pullSignal() - until evname == "key_down" - computer.shutdown(true) + if computer~=nil then + gpu.set(2,i+1, "Press any key to restart.") + local evname + repeat + evname = computer.pullSignal() + until evname == "key_down" + computer.shutdown(true) + end + while true do + coroutine.yield() + end end