forked from Hyperion/HyperionOS
rewrite
This commit is contained in:
217
Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/10_vfs.kmod
Executable file
217
Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/10_vfs.kmod
Executable file
@@ -0,0 +1,217 @@
|
||||
local args = {...}
|
||||
local kernel = args[1]
|
||||
local fs = {}
|
||||
local disks = {}
|
||||
local mounts = {["/"]="$"}
|
||||
|
||||
-- path normaliing
|
||||
local function normalizePath(path)
|
||||
if not path or path == "" then return "/" end
|
||||
if path:sub(1,1) ~= "/" then path = "/" .. path end
|
||||
local parts = {}
|
||||
for part in path:gmatch("[^/]+") do
|
||||
if part == ".." then
|
||||
if #parts > 0 then table.remove(parts) end
|
||||
elseif part ~= "." and part ~= "" then
|
||||
parts[#parts+1] = part
|
||||
end
|
||||
end
|
||||
return "/" .. table.concat(parts, "/")
|
||||
end
|
||||
|
||||
-- disk resolution
|
||||
local function resolvePath(path)
|
||||
local abs = normalizePath(path)
|
||||
local best = "/"
|
||||
for mount, diskAddr in pairs(mounts) do
|
||||
if abs:sub(1, #mount) == mount and #mount > #best then
|
||||
best = mount
|
||||
end
|
||||
end
|
||||
local newPath = abs:sub(#best + 1)
|
||||
if newPath == "" then newPath = "/" end
|
||||
return disks[mounts[best]], newPath
|
||||
end
|
||||
|
||||
-- Symlinks
|
||||
-- Format: #!@SYMLINK[target]
|
||||
local SYMLINK_PREFIX = "#!@SYMLINK["
|
||||
local SYMLINK_SUFFIX = "]"
|
||||
local SYMLINK_MAX_DEPTH = 64
|
||||
|
||||
local function isSymlink(disk, path)
|
||||
if not disk:fileExists(path) then return false end
|
||||
local text = disk:readAllText(path)
|
||||
if not text then return false end
|
||||
return text:sub(1, #SYMLINK_PREFIX) == SYMLINK_PREFIX
|
||||
end
|
||||
|
||||
local function readSymlink(disk, path)
|
||||
local text = disk:readAllText(path)
|
||||
if not text then return nil end
|
||||
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end
|
||||
local target = text:sub(#SYMLINK_PREFIX + 1)
|
||||
if target:sub(-1) == SYMLINK_SUFFIX then
|
||||
target = target:sub(1, -2)
|
||||
end
|
||||
return target
|
||||
end
|
||||
|
||||
|
||||
-- Path resolution
|
||||
local function splitPath(p)
|
||||
local parts = {}
|
||||
for part in p:gmatch("[^/]+") do parts[#parts+1] = part end
|
||||
return parts
|
||||
end
|
||||
|
||||
local function resolveSymlink(path)
|
||||
path = normalizePath(path)
|
||||
local symlinkDepth = 0
|
||||
local parts = splitPath(path)
|
||||
local resolved = {}
|
||||
local i = 1
|
||||
|
||||
while i <= #parts do
|
||||
local comp = parts[i]
|
||||
if comp == "." then
|
||||
elseif comp == ".." then
|
||||
if #resolved > 0 then table.remove(resolved) end
|
||||
else
|
||||
local currentPath = "/" .. table.concat(resolved, "/")
|
||||
local disk, p = resolvePath(currentPath .. "/" .. comp)
|
||||
if isSymlink(disk, p) then
|
||||
symlinkDepth = symlinkDepth + 1
|
||||
if symlinkDepth > SYMLINK_MAX_DEPTH then
|
||||
error("Too many levels of symbolic links: " .. path)
|
||||
end
|
||||
local target = readSymlink(disk, p)
|
||||
if not target then
|
||||
resolved[#resolved+1] = comp
|
||||
else
|
||||
if target:sub(1,1) == "/" then
|
||||
resolved = splitPath(normalizePath(target))
|
||||
else
|
||||
local base = resolved
|
||||
resolved = {}
|
||||
for _, seg in ipairs(base) do resolved[#resolved+1]=seg end
|
||||
for seg in target:gmatch("[^/]+") do
|
||||
if seg == ".." then
|
||||
if #resolved>0 then table.remove(resolved) end
|
||||
elseif seg ~= "." then
|
||||
resolved[#resolved+1]=seg
|
||||
end
|
||||
end
|
||||
end
|
||||
local remaining = {}
|
||||
for j=i+1,#parts do remaining[#remaining+1]=parts[j] end
|
||||
parts = remaining
|
||||
i = 0
|
||||
end
|
||||
else
|
||||
resolved[#resolved+1]=comp
|
||||
end
|
||||
end
|
||||
i=i+1
|
||||
end
|
||||
|
||||
local finalPath="/"..table.concat(resolved,"/")
|
||||
local disk,diskPath=resolvePath(finalPath)
|
||||
return disk,diskPath
|
||||
end
|
||||
|
||||
-- PUBLIC API: MOUNTING
|
||||
function fs.mount(disk, mountPoint)
|
||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||
mounts[mountPoint]=disk
|
||||
end
|
||||
function fs.unmount(mountPoint)
|
||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||
mounts[mountPoint]=nil
|
||||
end
|
||||
function fs.virtDisk(diskObj)
|
||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||
if disks[diskObj.address] then error("Disk exists") end
|
||||
disks[diskObj.address]=diskObj
|
||||
end
|
||||
function fs.eject(addr)
|
||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||
disks[addr]=nil
|
||||
end
|
||||
|
||||
-- SYMLINK API
|
||||
function fs.symlink(target, linkPath)
|
||||
local disk, p = resolvePath(linkPath)
|
||||
return disk:writeAllText(p, SYMLINK_PREFIX..target..SYMLINK_SUFFIX)
|
||||
end
|
||||
function fs.isLink(path)
|
||||
local disk, p = resolvePath(path)
|
||||
return isSymlink(disk,p)
|
||||
end
|
||||
function fs.readLink(path)
|
||||
local disk, p = resolvePath(path)
|
||||
return readSymlink(disk,p)
|
||||
end
|
||||
|
||||
-- FILE OPERATIONS
|
||||
function fs.exists(path)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:fileExists(p) or disk:directoryExists(p)
|
||||
end
|
||||
|
||||
function fs.isFile(path)
|
||||
local disk, p = resolveSymlink(path)
|
||||
if isSymlink(disk, p) then return false end
|
||||
return disk:fileExists(p)
|
||||
end
|
||||
|
||||
function fs.isDir(path)
|
||||
local disk, p = resolveSymlink(path)
|
||||
if isSymlink(disk, p) then return false end
|
||||
return disk:directoryExists(p)
|
||||
end
|
||||
|
||||
function fs.list(path)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:list(p)
|
||||
end
|
||||
|
||||
function fs.makeDir(path)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:makeDirectory(p)
|
||||
end
|
||||
|
||||
function fs.remove(path)
|
||||
local disk, p = resolvePath(path)
|
||||
if isSymlink(disk, p) then
|
||||
return disk:remove(p)
|
||||
end
|
||||
local d2, p2 = resolveSymlink(path)
|
||||
return d2:remove(p2)
|
||||
end
|
||||
|
||||
function fs.readAllText(path)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:readAllText(p)
|
||||
end
|
||||
|
||||
function fs.writeAllText(path, text)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:writeAllText(p, text)
|
||||
end
|
||||
|
||||
function fs.appendAllText(path, text)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:appendAllText(p, text)
|
||||
end
|
||||
|
||||
function fs.getSize(path)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:getSize(p)
|
||||
end
|
||||
|
||||
-- INIT
|
||||
for _,v in kernel.initdisks.list() do fs.virtDisk(v) end
|
||||
kernel.fs=fs
|
||||
kernel.chache.preload.fs=fs
|
||||
kernel.chache.preload.filesystem=fs
|
||||
Reference in New Issue
Block a user