fixed creating symlinks and mounts in real folders to "break" the file system (in that the virtual node overwrote the real one), virtual and real fs nodes/directories should now mix well.

This commit is contained in:
Florian Nücke 2014-01-29 19:16:22 +01:00
parent 9cc0a70643
commit ffa5a3c2d9

View File

@ -46,26 +46,33 @@ local function findNode(path, create, depth)
return findNode(filesystem.concat(node.links[part], table.concat(parts, "/", 2)), create, depth + 1) return findNode(filesystem.concat(node.links[part], table.concat(parts, "/", 2)), create, depth + 1)
else else
if create then if create then
node.children[part] = {children={}, links={}, parent=node} node.children[part] = {name=part, parent=node, children={}, links={}}
else else
return node, table.concat(parts, "/") local vnode, vrest = node, table.concat(parts, "/")
local rest = vrest
while node and not node.fs do
rest = filesystem.concat(node.name, rest)
node = node.parent
end
return node, rest, vnode, vrest
end end
end end
end end
node = node.children[part] node = node.children[part]
table.remove(parts, 1) table.remove(parts, 1)
end end
return node local vnode, vrest = node, nil
local rest = nil
while node and not node.fs do
rest = rest and filesystem.concat(node.name, rest) or node.name
node = node.parent
end
return node, rest, vnode, vrest
end end
local function removeEmptyNodes(node) local function removeEmptyNodes(node)
while node and node.parent and not node.fs and not next(node.children) do while node and node.parent and not node.fs and not next(node.children) and not next(node.links) do
for k, c in pairs(node.parent.children) do node.parent.children[node.name] = nil
if c == node then
node.parent.children[k] = nil
break
end
end
node = node.parent node = node.parent
end end
end end
@ -106,24 +113,23 @@ function filesystem.get(path)
local node, rest = findNode(path) local node, rest = findNode(path)
if node.fs then if node.fs then
local proxy = node.fs local proxy = node.fs
path = "/" path = ""
while node.parent do while node and node.parent do
for name, child in pairs(node.parent.children) do path = filesystem.concat(node.name, path)
if child == node then
path = "/" .. name .. path
break
end
end
node = node.parent node = node.parent
end end
return proxy, filesystem.canonical(path) path = filesystem.canonical(path)
if path ~= "/" then
path = "/" .. path
end
return proxy, path
end end
return nil, "no such file system" return nil, "no such file system"
end end
function filesystem.isLink(path) function filesystem.isLink(path)
local node, rest = findNode(filesystem.path(path)) local node, rest, vnode, vrest = findNode(filesystem.path(path))
return not rest and node.links[filesystem.name(path)] ~= nil return not vrest and vnode.links[filesystem.name(path)] ~= nil
end end
function filesystem.link(target, linkpath) function filesystem.link(target, linkpath)
@ -134,8 +140,8 @@ function filesystem.link(target, linkpath)
return nil, "file already exists" return nil, "file already exists"
end end
local node = findNode(filesystem.path(linkpath), true) local node, rest, vnode, vrest = findNode(filesystem.path(linkpath), true)
node.links[filesystem.name(linkpath)] = target vnode.links[filesystem.name(linkpath)] = target
return true return true
end end
@ -151,11 +157,11 @@ function filesystem.mount(fs, path)
return nil, "file already exists" return nil, "file already exists"
end end
local node = findNode(path, true) local node, rest, vnode, vrest = findNode(path, true)
if node.fs then if vnode.fs then
return nil, "another filesystem is already mounted here" return nil, "another filesystem is already mounted here"
end end
node.fs = fs vnode.fs = fs
return true return true
end end
@ -223,10 +229,10 @@ end
function filesystem.umount(fsOrPath) function filesystem.umount(fsOrPath)
checkArg(1, fsOrPath, "string", "table") checkArg(1, fsOrPath, "string", "table")
if type(fsOrPath) == "string" then if type(fsOrPath) == "string" then
local node, rest = findNode(fsOrPath) local node, rest, vnode, vrest = findNode(fsOrPath)
if not rest and node.fs then if not vrest and vnode.fs then
node.fs = nil vnode.fs = nil
removeEmptyNodes(node) removeEmptyNodes(vnode)
return true return true
end end
end end
@ -234,9 +240,9 @@ function filesystem.umount(fsOrPath)
local queue = {mtab} local queue = {mtab}
for proxy, path in filesystem.mounts() do for proxy, path in filesystem.mounts() do
if string.sub(proxy.address, 1, address:len()) == address then if string.sub(proxy.address, 1, address:len()) == address then
local node = findNode(path) local node, rest, vnode, vrest = findNode(path)
node.fs = nil vnode.fs = nil
removeEmptyNodes(node) removeEmptyNodes(vnode)
return true return true
end end
end end
@ -248,8 +254,8 @@ function filesystem.umount(fsOrPath)
end end
function filesystem.exists(path) function filesystem.exists(path)
local node, rest = findNode(path) local node, rest, vnode, vrest = findNode(path)
if not rest or node.links[rest] then -- virtual directory or symbolic link if not vrest or vnode.links[vrest] then -- virtual directory or symbolic link
return true return true
end end
if node.fs then if node.fs then
@ -259,53 +265,66 @@ function filesystem.exists(path)
end end
function filesystem.size(path) function filesystem.size(path)
local node, rest = findNode(path) local node, rest, vnode, vrest = findNode(path)
if not vnode.fs and (not vrest or vnode.links[vrest]) then
return 0 -- virtual directory or symlink
end
if node.fs and rest then if node.fs and rest then
return node.fs.size(rest) return node.fs.size(rest)
end end
return 0 -- no such file or directory or it's a virtual directory return 0 -- no such file or directory
end end
function filesystem.isDirectory(path) function filesystem.isDirectory(path)
local node, rest = findNode(path) local node, rest, vnode, vrest = findNode(path)
if node.fs and rest then if not vnode.fs and not vrest then
return node.fs.isDirectory(rest) return true -- virtual directory
else
return not rest or unicode.len(rest) == 0
end end
if node.fs then
return not rest or node.fs.isDirectory(rest)
end
return false
end end
function filesystem.lastModified(path) function filesystem.lastModified(path)
local node, rest = findNode(path) local node, rest, vnode, vrest = findNode(path)
if not vnode.fs and not vrest then
return 0 -- virtual directory
end
if node.fs and rest then if node.fs and rest then
return node.fs.lastModified(rest) return node.fs.lastModified(rest)
end end
return 0 -- no such file or directory or it's a virtual directory return 0 -- no such file or directory
end end
function filesystem.list(path) function filesystem.list(path)
local node, rest = findNode(path) local node, rest, vnode, vrest = findNode(path)
if not node.fs and rest then if not vnode.fs and vrest and not node.fs then
return nil, "no such file or directory" return nil, "no such file or directory"
end end
local result, reason local result, reason
if node.fs then if node.fs then
result, reason = node.fs.list(rest or "") result, reason = node.fs.list(rest or "")
if not result then
return nil, reason or "no such directory"
end
else
result = {}
end end
if not rest then result = result or {}
for k in pairs(node.children) do if not vrest then
for k in pairs(vnode.children) do
table.insert(result, k .. "/") table.insert(result, k .. "/")
end end
for k in pairs(node.links) do for k in pairs(vnode.links) do
table.insert(result, k) table.insert(result, k)
end end
end end
table.sort(result) table.sort(result)
local i, f = 1, nil
while i <= #result do
if result[i] == f then
table.remove(result, i)
else
f = result[i]
end
i = i + 1
end
local i = 0 local i = 0
return function() return function()
i = i + 1 i = i + 1
@ -328,13 +347,15 @@ function filesystem.makeDirectory(path)
end end
function filesystem.remove(path) function filesystem.remove(path)
local node, rest = findNode(filesystem.path(path)) local node, rest, vnode, vrest = findNode(filesystem.path(path))
local name = filesystem.name(path) local name = filesystem.name(path)
if node.children[name] then if vnode.children[name] then
node.children[name] = nil vnode.children[name] = nil
removeEmptyNodes(vnode)
return true return true
elseif node.links[name] then elseif vnode.links[name] then
node.links[name] = nil vnode.links[name] = nil
removeEmptyNodes(vnode)
return true return true
else else
node, rest = findNode(path) node, rest = findNode(path)
@ -347,8 +368,8 @@ end
function filesystem.rename(oldPath, newPath) function filesystem.rename(oldPath, newPath)
if filesystem.isLink(oldPath) then if filesystem.isLink(oldPath) then
local node, rest = findNode(filesystem.path(oldPath)) local node, rest, vnode, vrest = findNode(filesystem.path(oldPath))
local target = node.links[filesystem.name(oldPath)] local target = vnode.links[filesystem.name(oldPath)]
local result, reason = filesystem.link(target, newPath) local result, reason = filesystem.link(target, newPath)
if result then if result then
filesystem.remove(oldPath) filesystem.remove(oldPath)