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.

This commit is contained in:
Florian Nücke 2014-01-21 01:40:28 +01:00
parent 9d5f44919b
commit 7f8f216682
3 changed files with 108 additions and 26 deletions

View File

@ -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 <target> [<name>]")
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

View File

@ -43,7 +43,9 @@ for i = 1, #dirs do
end end
end end
for _, f in ipairs(lsf) do 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) setColor(0x00FF00)
else else
setColor(0xFFFFFF) setColor(0xFFFFFF)

View File

@ -3,7 +3,7 @@ local unicode = require("unicode")
local filesystem, fileStream = {}, {} local filesystem, fileStream = {}, {}
local isAutorunEnabled = true local isAutorunEnabled = true
local mtab = {children={}} local mtab = {children={}, links={}}
local function segments(path) local function segments(path)
path = path:gsub("\\", "/") path = path:gsub("\\", "/")
@ -31,19 +31,29 @@ local function segments(path)
return parts return parts
end end
local function findNode(path, create) local function findNode(path, create, depth)
checkArg(1, path, "string") checkArg(1, path, "string")
depth = depth or 0
if depth > 100 then
error("link cycle detected")
end
local parts = segments(path) local parts = segments(path)
local node = mtab local node = mtab
for i = 1, #parts do while #parts > 0 do
if not node.children[parts[i]] then local part = parts[1]
if create then if not node.children[part] then
node.children[parts[i]] = {children={}, parent=node} if node.links[part] then
return findNode(filesystem.concat(node.links[part], table.concat(parts, "/", 2)), create, depth + 1)
else 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
end end
node = node.children[parts[i]] node = node.children[part]
table.remove(parts, 1)
end end
return node return node
end end
@ -111,6 +121,24 @@ function filesystem.get(path)
return nil, "no such file system" return nil, "no such file system"
end 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) function filesystem.mount(fs, path)
checkArg(1, fs, "string", "table") checkArg(1, fs, "string", "table")
if type(fs) == "string" then 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)") assert(type(fs) == "table", "bad argument #1 (file system proxy or address expected)")
checkArg(2, path, "string") checkArg(2, path, "string")
if path ~= "/" and filesystem.exists(path) then
return nil, "file already exists"
end
local node = findNode(path, true) local node = findNode(path, true)
if node.fs then if node.fs then
return nil, "another filesystem is already mounted here" return nil, "another filesystem is already mounted here"
@ -217,7 +249,7 @@ end
function filesystem.exists(path) function filesystem.exists(path)
local node, rest = findNode(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 return true
end end
if node.fs then if node.fs then
@ -266,9 +298,12 @@ function filesystem.list(path)
result = {} result = {}
end end
if not rest then if not rest then
for k, _ in pairs(node.children) do for k in pairs(node.children) do
table.insert(result, k .. "/") table.insert(result, k .. "/")
end end
for k in pairs(node.links) do
table.insert(result, k)
end
end end
table.sort(result) table.sort(result)
local i = 0 local i = 0
@ -279,6 +314,9 @@ function filesystem.list(path)
end end
function filesystem.makeDirectory(path) 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) local node, rest = findNode(path)
if node.fs and rest then if node.fs and rest then
return node.fs.makeDirectory(rest) return node.fs.makeDirectory(rest)
@ -290,29 +328,49 @@ function filesystem.makeDirectory(path)
end end
function filesystem.remove(path) function filesystem.remove(path)
local node, rest = findNode(path) local node, rest = findNode(filesystem.path(path))
if node.fs and rest then local name = filesystem.name(path)
return node.fs.remove(rest) 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 end
return nil, "no such non-virtual directory"
end end
function filesystem.rename(oldPath, newPath) function filesystem.rename(oldPath, newPath)
local oldNode, oldRest = findNode(oldPath) if filesystem.isLink(oldPath) then
local newNode, newRest = findNode(newPath) local node, rest = findNode(filesystem.path(oldPath))
if oldNode.fs and oldRest and newNode.fs and newRest then local target = node.links[filesystem.name(oldPath)]
if oldNode.fs.address == newNode.fs.address then local result, reason = filesystem.link(target, newPath)
return oldNode.fs.rename(oldRest, newRest) if result then
else filesystem.remove(oldPath)
local result, reason = filesystem.copy(oldPath, newPath) end
if result then return result, reason
return filesystem.remove(oldPath) 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 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
end end
return nil, "trying to read from or write to virtual directory"
end end
return nil, "trying to read from or write to virtual directory"
end end
function filesystem.copy(fromPath, toPath) function filesystem.copy(fromPath, toPath)