mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-13 01:10:19 -04:00
hard drives. writable frikkin hardrives. next up: limiting their capacity...
This commit is contained in:
parent
0927f076ce
commit
e85afe8518
@ -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.exists(path)
|
||||
local node, rest = findNode(path)
|
||||
if not rest then -- virtual directory
|
||||
return true
|
||||
end
|
||||
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 fs, subpath, node = findFs(path)
|
||||
local result = {}
|
||||
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
|
||||
if fs then
|
||||
local fsresult = {sendToNode(fs, "fs.list", subpath)}
|
||||
for _, k in ipairs(fsresult) 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)
|
||||
|
@ -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
|
||||
|
31
assets/opencomputers/lua/rom/api/filesystem.lua
Normal file
31
assets/opencomputers/lua/rom/api/filesystem.lua
Normal 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)
|
@ -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
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
@ -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 {
|
||||
|
@ -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"
|
||||
}
|
@ -46,6 +46,7 @@ trait ComponentInventory extends IInventory with Node {
|
||||
}
|
||||
}
|
||||
}
|
||||
computer.recomputeMemory()
|
||||
}
|
||||
|
||||
override def save(nbt: NBTTagCompound) = {
|
||||
|
@ -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]))
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user