hard drives. writable frikkin hardrives. next up: limiting their capacity...

This commit is contained in:
Florian Nücke 2013-10-04 01:13:55 +02:00
parent 0927f076ce
commit e85afe8518
10 changed files with 149 additions and 69 deletions

View File

@ -1,5 +1,7 @@
driver.fs = {}
-------------------------------------------------------------------------------
local mtab = {children={}}
local function segments(path)
@ -31,30 +33,20 @@ end
local function findNode(path, create)
local parts = segments(path)
local node = mtab
for _, part in ipairs(parts) do
if not node.children[part] then
for i = 1, #parts do
if not node.children[parts[i]] then
if create then
node.children[part] = {children={}}
node.children[parts[i]] = {children={}, parent=node}
else
return nil
return node, table.concat(parts, "/", i)
end
end
node = node.children[part]
node = node.children[parts[i]]
end
return node
end
local function findFs(path)
local parts = segments(path)
local node = mtab
for i = 1, #parts do
if not node.children[parts[i]] then
return node.fs, table.concat(parts, "/", i), node
end
node = node.children[parts[i]]
end
return node.fs, "", node
end
-------------------------------------------------------------------------------
function driver.fs.mount(fs, path)
assert(type(fs) == "string",
@ -71,18 +63,29 @@ end
function driver.fs.umount(fsOrPath)
assert(type(fsOrPath) == "string",
"bad argument #1 (string expected, got " .. type(fsOrPath) .. ")")
if type(fsOrPath) == "string" then
local node = findNode(fsOrPath)
if node and node.fs then
node.fs = nil
return true
local function removeEmptyNodes(node)
while node and node.parent and not node.fs and not next(node.children) do
for k, c in pairs(node.parent.children) do
if c == node then
node.parent.children[k] = nil
break
end
end
node = node.parent
end
end
local node, rest = findNode(fsOrPath)
if not rest and node.fs then
node.fs = nil
removeEmptyNodes(node)
return true
else
local queue = {mtab}
repeat
local node = table.remove(queue)
if node.fs == fsOrPath then
node.fs = nil
removeEmptyNodes(node)
return true
end
for _, child in ipairs(node.children) do
@ -92,30 +95,63 @@ function driver.fs.umount(fsOrPath)
end
end
function driver.fs.listdir(path)
local fs, subpath, node = findFs(path)
local result = {}
for k, _ in pairs(node.children) do
table.insert(result, k .. "/")
-------------------------------------------------------------------------------
function driver.fs.exists(path)
local node, rest = findNode(path)
if not rest then -- virtual directory
return true
end
if fs then
local fsresult = {sendToNode(fs, "fs.list", subpath)}
for _, k in ipairs(fsresult) do
table.insert(result, k)
if node.fs then
return sendToNode(node.fs, "fs.exists", rest)
end
end
function driver.fs.size(path)
local node, rest = findNode(path)
if node.fs and rest then
return sendToNode(node.fs, "fs.size", rest)
end
return 0 -- no such file or directory or virtual directory
end
function driver.fs.listdir(path)
local node, rest = findNode(path)
local result
if node.fs then
result = {sendToNode(node.fs, "fs.list", rest or "")}
else
result = {}
end
if not rest then
for k, _ in pairs(node.children) do
table.insert(result, k .. "/")
end
end
table.sort(result)
return table.unpack(result)
end
-------------------------------------------------------------------------------
function driver.fs.remove(path)
local node, rest = findNode(path)
if node.fs and rest then
return sendToNode(node.fs, "fs.remove", rest)
end
end
function driver.fs.rename(oldPath, newPath)
--[[ TODO moving between file systems will require actual data copying...
local node, rest = findNode(path)
local newNode, newRest = findNode(newPath)
if node.fs and rest and newNode and newRest then
return sendToNode(node.fs, "fs.rename", rest)
end
]]
end
function driver.fs.tmpname()
end
-------------------------------------------------------------------------------
local file = {}
@ -306,35 +342,37 @@ function file.write(f, ...)
end
buffer = buffer .. arg
]]
sendToNode(f.fs, "fs.write", arg)
sendToNode(f.fs, "fs.write", f.handle, arg)
end
return f
end
-------------------------------------------------------------------------------
function driver.fs.open(path, mode)
assert(type(path) == "string",
"bad argument #1 (string expected, got " .. type(path) .. ")")
mode = mode or "r"
assert(({r=true, rb=true, w=true, wb=true, a=true, ab=true})[mode],
"bad argument #2 (r[b], w[b] or a[b] expected, got " .. tostring(mode) .. ")")
local fs, subpath = findFs(path)
if not fs then
local node, rest = findNode(path)
if not node.fs or not rest then -- files can only be in file systems
return nil, "file not found"
end
local handle, reason = sendToNode(fs, "fs.open", subpath, mode)
local handle, reason = sendToNode(node.fs, "fs.open", rest or "", mode)
if not handle then
return nil, reason
end
return setmetatable({
fs = fs,
fs = node.fs,
handle = handle,
bsize = 8 * 1024,
bmode = "no"
bmode = "full"
}, {
__index = file,
__gc = function(f)
-- File.close does a syscall, which yields, and that's not possible in
-- the __gc metamethod. So we start a timer to do the yield.
-- file.close does a syscall, which yields, and that's not possible in
-- the __gc metamethod. So we start a timer to do the yield/cleanup.
event.timer(0, function()
file.close(f)
end)
@ -353,19 +391,7 @@ function driver.fs.type(f)
end
end
-- Aliases for vanilla Lua.
os.remove = driver.fs.remove
os.rename = driver.fs.rename
os.tmpname = driver.fs.tmpname
io = {}
-- TODO io.flush = function() end
-- TODO io.lines = function(filename) end
io.open = driver.fs.open
-- TODO io.popen = function(prog, mode) end
io.read = driver.fs.read
-- TODO io.tmpfile = function() end
io.type = driver.fs.type
-------------------------------------------------------------------------------
function loadfile(file, env)
local f, reason = driver.fs.open(file)

View File

@ -152,8 +152,8 @@ end
local function main(args)
local function init()
sandbox.driver.fs.mount(os.romAddress(), "/rom")
local result, reason = sandbox.loadfile("/rom/init.lua")
sandbox.driver.fs.mount(os.romAddress(), "/boot")
local result, reason = sandbox.loadfile("/boot/init.lua")
if not result then
error(reason)
end

View File

@ -0,0 +1,31 @@
-- Aliases for vanilla Lua.
os.remove = driver.fs.remove
os.rename = driver.fs.rename
-- TODO os.tmpname = function() end
io = {}
-- TODO io.flush = function() end
-- TODO io.lines = function(filename) end
io.open = driver.fs.open
-- TODO io.popen = function(prog, mode) end
io.read = driver.fs.read
-- TODO io.tmpfile = function() end
io.type = driver.fs.type
-------------------------------------------------------------------------------
event.listen("component_added", function(_, address)
if component.type(address) == "filesystem" then
local name = address:sub(1, 3)
repeat
name = address:sub(1, name:len() + 1)
until not driver.fs.exists("/dev/" .. name)
driver.fs.mount(address, "/dev/" .. name)
end
end)
event.listen("component_removed", function(_, address)
if component.type(address) == "filesystem" then
driver.fs.umount(address)
end
end)

View File

@ -1,7 +1,10 @@
dofile("/rom/api/event.lua")
dofile("/rom/api/component.lua")
dofile("/rom/api/term.lua")
dofile("/rom/sh.lua")
dofile("/boot/api/event.lua")
dofile("/boot/api/component.lua")
dofile("/boot/api/filesystem.lua")
dofile("/boot/api/term.lua")
dofile("/boot/sh.lua")
driver.fs.umount("/boot")
event.fire(...)
while true do

View File

@ -6,22 +6,24 @@ object Items {
var multi: item.Delegator = null
var gpu: item.GraphicsCard = null
var hdd: item.Hdd = null
var rs: item.RedstoneCard = null
var ram32k: item.Memory = null
var ram64k: item.Memory = null
var ram128k: item.Memory = null
var hdd: item.Hdd = null
def init() {
multi = new item.Delegator(Config.itemId)
gpu = new item.GraphicsCard(multi)
hdd = new item.Hdd(multi)
rs = new item.RedstoneCard(multi)
ram32k = new item.Memory(multi, 32)
ram64k = new item.Memory(multi, 64)
ram128k = new item.Memory(multi, 128)
hdd = new item.Hdd(multi, 2 * 1024 * 1024)
}
}

View File

@ -100,7 +100,7 @@ class Delegator(id: Int) extends Block(id, Material.iron) {
// ----------------------------------------------------------------------- //
override def breakBlock(world: World, x: Int, y: Int, z: Int, blockId: Int, metadata: Int) = {
subBlock(world, x, y, z) match {
subBlock(metadata) match {
case None => // Invalid but avoid match error.
case Some(subBlock) => {
world.getBlockTileEntity(x, y, z) match {

View File

@ -1,5 +1,5 @@
package li.cil.oc.common.item
class Hdd(val parent: Delegator) extends Delegate {
class Hdd(val parent: Delegator, val capacity: Int) extends Delegate {
def unlocalizedName = "HardDiskDrive"
}

View File

@ -46,6 +46,7 @@ trait ComponentInventory extends IInventory with Node {
}
}
}
computer.recomputeMemory()
}
override def save(nbt: NBTTagCompound) = {

View File

@ -39,7 +39,7 @@ class FileSystem(val fileSystem: api.FileSystem) extends Node {
None
case Array(path: Array[Byte]) if message.name == "fs.exists" =>
Some(Array(fileSystem.exists(clean(path)).asInstanceOf[Any]))
case Array(path: Array[Byte]) if message.name == "fs.exists" =>
case Array(path: Array[Byte]) if message.name == "fs.size" =>
Some(Array(fileSystem.size(clean(path)).asInstanceOf[Any]))
case Array(path: Array[Byte]) if message.name == "fs.isDirectory" =>
Some(Array(fileSystem.isDirectory(clean(path)).asInstanceOf[Any]))

View File

@ -1,16 +1,33 @@
package li.cil.oc.server.driver
import li.cil.oc
import li.cil.oc.api.driver.{Item, Slot}
import li.cil.oc.{Config, Items}
import li.cil.oc.api.driver
import li.cil.oc.api.driver.Slot
import net.minecraft.item.ItemStack
object FileSystem extends driver.Item {
object FileSystem extends Item {
override def api = Option(getClass.getResourceAsStream(Config.driverPath + "fs.lua"))
override def worksWith(item: ItemStack) = WorksWith(Items.hdd)(item)
override def slot(item: ItemStack) = Slot.HDD
override def node(item: ItemStack) = None
override def node(item: ItemStack) = {
// We have a bit of a chicken-egg problem here, because we want to use the
// node's address as the folder name... so we generate the address here,
// if necessary. No one will know, right? Right!?
val tag = nbt(item)
val address =
if (tag.hasKey("address"))
tag.getString("address")
else
java.util.UUID.randomUUID().toString
oc.api.FileSystem.fromSaveDir(address).flatMap(oc.api.FileSystem.asNode) match {
case None => None
case Some(node) =>
node.address = Some(address)
node.load(tag)
Some(node)
}
}
}