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
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)

View File

@ -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)