From 7f8f216682b8974d82ff2b16538c4b80d758eb0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Tue, 21 Jan 2014 01:40:28 +0100 Subject: [PATCH] added basic support for symbolic links, pretty untested as of yet, though. they're kind of like mounts in that they have to be re-created after a reboot. --- assets/opencomputers/lua/rom/bin/ln.lua | 22 ++++ assets/opencomputers/lua/rom/bin/ls.lua | 4 +- .../opencomputers/lua/rom/lib/filesystem.lua | 108 ++++++++++++++---- 3 files changed, 108 insertions(+), 26 deletions(-) create mode 100644 assets/opencomputers/lua/rom/bin/ln.lua diff --git a/assets/opencomputers/lua/rom/bin/ln.lua b/assets/opencomputers/lua/rom/bin/ln.lua new file mode 100644 index 000000000..e46908ad6 --- /dev/null +++ b/assets/opencomputers/lua/rom/bin/ln.lua @@ -0,0 +1,22 @@ +local component = require("component") +local fs = require("filesystem") +local shell = require("shell") + +local dirs = shell.parse(...) +if #dirs == 0 then + print("Usage: ln []") + return +end + +local target = shell.resolve(dirs[1]) +local linkpath +if #dirs > 1 then + linkpath = shell.resolve(dirs[2]) +else + linkpath = fs.concat(shell.getWorkingDirectory(), fs.name(target)) +end + +local result, reason = fs.link(target, linkpath) +if not result then + print(reason) +end \ No newline at end of file diff --git a/assets/opencomputers/lua/rom/bin/ls.lua b/assets/opencomputers/lua/rom/bin/ls.lua index 8b52c8b49..88b510ad1 100644 --- a/assets/opencomputers/lua/rom/bin/ls.lua +++ b/assets/opencomputers/lua/rom/bin/ls.lua @@ -43,7 +43,9 @@ for i = 1, #dirs do end end for _, f in ipairs(lsf) do - if f:sub(-4) == ".lua" then + if fs.isLink(fs.concat(path, f)) then + setColor(0xFFAA00) + elseif f:sub(-4) == ".lua" then setColor(0x00FF00) else setColor(0xFFFFFF) diff --git a/assets/opencomputers/lua/rom/lib/filesystem.lua b/assets/opencomputers/lua/rom/lib/filesystem.lua index fadddeb67..1a239f7b1 100644 --- a/assets/opencomputers/lua/rom/lib/filesystem.lua +++ b/assets/opencomputers/lua/rom/lib/filesystem.lua @@ -3,7 +3,7 @@ local unicode = require("unicode") local filesystem, fileStream = {}, {} local isAutorunEnabled = true -local mtab = {children={}} +local mtab = {children={}, links={}} local function segments(path) path = path:gsub("\\", "/") @@ -31,19 +31,29 @@ local function segments(path) return parts end -local function findNode(path, create) +local function findNode(path, create, depth) checkArg(1, path, "string") + depth = depth or 0 + if depth > 100 then + error("link cycle detected") + end local parts = segments(path) local node = mtab - for i = 1, #parts do - if not node.children[parts[i]] then - if create then - node.children[parts[i]] = {children={}, parent=node} + while #parts > 0 do + local part = parts[1] + if not node.children[part] then + if node.links[part] then + return findNode(filesystem.concat(node.links[part], table.concat(parts, "/", 2)), create, depth + 1) else - return node, table.concat(parts, "/", i) + if create then + node.children[part] = {children={}, links={}, parent=node} + else + return node, table.concat(parts, "/") + end end end - node = node.children[parts[i]] + node = node.children[part] + table.remove(parts, 1) end return node end @@ -111,6 +121,24 @@ function filesystem.get(path) return nil, "no such file system" end +function filesystem.isLink(path) + local node, rest = findNode(filesystem.path(path)) + return not rest and node.links[filesystem.name(path)] ~= nil +end + +function filesystem.link(target, linkpath) + checkArg(1, target, "string") + checkArg(2, linkpath, "string") + + if filesystem.exists(linkpath) then + return nil, "file already exists" + end + + local node = findNode(filesystem.path(linkpath), true) + node.links[filesystem.name(linkpath)] = target + return true +end + function filesystem.mount(fs, path) checkArg(1, fs, "string", "table") if type(fs) == "string" then @@ -119,6 +147,10 @@ function filesystem.mount(fs, path) assert(type(fs) == "table", "bad argument #1 (file system proxy or address expected)") checkArg(2, path, "string") + if path ~= "/" and filesystem.exists(path) then + return nil, "file already exists" + end + local node = findNode(path, true) if node.fs then return nil, "another filesystem is already mounted here" @@ -217,7 +249,7 @@ end function filesystem.exists(path) local node, rest = findNode(path) - if not rest then -- virtual directory + if not rest or node.links[rest] then -- virtual directory or symbolic link return true end if node.fs then @@ -266,9 +298,12 @@ function filesystem.list(path) result = {} end if not rest then - for k, _ in pairs(node.children) do + for k in pairs(node.children) do table.insert(result, k .. "/") end + for k in pairs(node.links) do + table.insert(result, k) + end end table.sort(result) local i = 0 @@ -279,6 +314,9 @@ function filesystem.list(path) end function filesystem.makeDirectory(path) + if filesystem.exists(path) then + return nil, "file or directory with that name already exists" + end local node, rest = findNode(path) if node.fs and rest then return node.fs.makeDirectory(rest) @@ -290,29 +328,49 @@ function filesystem.makeDirectory(path) end function filesystem.remove(path) - local node, rest = findNode(path) - if node.fs and rest then - return node.fs.remove(rest) + local node, rest = findNode(filesystem.path(path)) + local name = filesystem.name(path) + if node.children[name] then + node.children[name] = nil + return true + elseif node.links[name] then + node.links[name] = nil + return true + else + node, rest = findNode(path) + if node.fs and rest then + return node.fs.remove(rest) + end + return nil, "no such file or directory" end - return nil, "no such non-virtual directory" end function filesystem.rename(oldPath, newPath) - local oldNode, oldRest = findNode(oldPath) - local newNode, newRest = findNode(newPath) - if oldNode.fs and oldRest and newNode.fs and newRest then - if oldNode.fs.address == newNode.fs.address then - return oldNode.fs.rename(oldRest, newRest) - else - local result, reason = filesystem.copy(oldPath, newPath) - if result then - return filesystem.remove(oldPath) + if filesystem.isLink(oldPath) then + local node, rest = findNode(filesystem.path(oldPath)) + local target = node.links[filesystem.name(oldPath)] + local result, reason = filesystem.link(target, newPath) + if result then + filesystem.remove(oldPath) + end + return result, reason + else + local oldNode, oldRest = findNode(oldPath) + local newNode, newRest = findNode(newPath) + if oldNode.fs and oldRest and newNode.fs and newRest then + if oldNode.fs.address == newNode.fs.address then + return oldNode.fs.rename(oldRest, newRest) else - return nil, reason + local result, reason = filesystem.copy(oldPath, newPath) + if result then + return filesystem.remove(oldPath) + else + return nil, reason + end end end + return nil, "trying to read from or write to virtual directory" end - return nil, "trying to read from or write to virtual directory" end function filesystem.copy(fromPath, toPath)