From e85afe8518992ef396f7ea1563a47bfb22bc25d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 4 Oct 2013 01:13:55 +0200 Subject: [PATCH] hard drives. writable frikkin hardrives. next up: limiting their capacity... --- assets/opencomputers/lua/drivers/fs.lua | 134 +++++++++++------- assets/opencomputers/lua/kernel.lua | 4 +- .../opencomputers/lua/rom/api/filesystem.lua | 31 ++++ assets/opencomputers/lua/rom/init.lua | 11 +- li/cil/oc/Items.scala | 6 +- li/cil/oc/common/block/Delegator.scala | 2 +- li/cil/oc/common/item/Hdd.scala | 2 +- .../tileentity/ComponentInventory.scala | 1 + li/cil/oc/server/component/Filesystem.scala | 2 +- li/cil/oc/server/driver/FileSystem.scala | 25 +++- 10 files changed, 149 insertions(+), 69 deletions(-) create mode 100644 assets/opencomputers/lua/rom/api/filesystem.lua diff --git a/assets/opencomputers/lua/drivers/fs.lua b/assets/opencomputers/lua/drivers/fs.lua index 6c90f3e7d..0b5330cef 100644 --- a/assets/opencomputers/lua/drivers/fs.lua +++ b/assets/opencomputers/lua/drivers/fs.lua @@ -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) @@ -387,4 +413,4 @@ function dofile(file) return nil, reason end return f() -end \ No newline at end of file +end diff --git a/assets/opencomputers/lua/kernel.lua b/assets/opencomputers/lua/kernel.lua index 97f3b1dcf..e76b5e8d4 100644 --- a/assets/opencomputers/lua/kernel.lua +++ b/assets/opencomputers/lua/kernel.lua @@ -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 diff --git a/assets/opencomputers/lua/rom/api/filesystem.lua b/assets/opencomputers/lua/rom/api/filesystem.lua new file mode 100644 index 000000000..a784b42b0 --- /dev/null +++ b/assets/opencomputers/lua/rom/api/filesystem.lua @@ -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) diff --git a/assets/opencomputers/lua/rom/init.lua b/assets/opencomputers/lua/rom/init.lua index ed14a9033..342b925c6 100644 --- a/assets/opencomputers/lua/rom/init.lua +++ b/assets/opencomputers/lua/rom/init.lua @@ -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 diff --git a/li/cil/oc/Items.scala b/li/cil/oc/Items.scala index 3863ef0d3..07ffe0ae3 100644 --- a/li/cil/oc/Items.scala +++ b/li/cil/oc/Items.scala @@ -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) } } \ No newline at end of file diff --git a/li/cil/oc/common/block/Delegator.scala b/li/cil/oc/common/block/Delegator.scala index a71f38045..32b951e88 100644 --- a/li/cil/oc/common/block/Delegator.scala +++ b/li/cil/oc/common/block/Delegator.scala @@ -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 { diff --git a/li/cil/oc/common/item/Hdd.scala b/li/cil/oc/common/item/Hdd.scala index 0af49477a..b730dd8cb 100644 --- a/li/cil/oc/common/item/Hdd.scala +++ b/li/cil/oc/common/item/Hdd.scala @@ -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" } \ No newline at end of file diff --git a/li/cil/oc/common/tileentity/ComponentInventory.scala b/li/cil/oc/common/tileentity/ComponentInventory.scala index 477de6d50..20bd11c5b 100644 --- a/li/cil/oc/common/tileentity/ComponentInventory.scala +++ b/li/cil/oc/common/tileentity/ComponentInventory.scala @@ -46,6 +46,7 @@ trait ComponentInventory extends IInventory with Node { } } } + computer.recomputeMemory() } override def save(nbt: NBTTagCompound) = { diff --git a/li/cil/oc/server/component/Filesystem.scala b/li/cil/oc/server/component/Filesystem.scala index 32cb0988c..a4371f84b 100644 --- a/li/cil/oc/server/component/Filesystem.scala +++ b/li/cil/oc/server/component/Filesystem.scala @@ -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])) diff --git a/li/cil/oc/server/driver/FileSystem.scala b/li/cil/oc/server/driver/FileSystem.scala index ff213b789..5940bbbcd 100644 --- a/li/cil/oc/server/driver/FileSystem.scala +++ b/li/cil/oc/server/driver/FileSystem.scala @@ -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) + } + } } \ No newline at end of file