mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-14 01:39:36 -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 = {}
|
driver.fs = {}
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
local mtab = {children={}}
|
local mtab = {children={}}
|
||||||
|
|
||||||
local function segments(path)
|
local function segments(path)
|
||||||
@ -31,30 +33,20 @@ end
|
|||||||
local function findNode(path, create)
|
local function findNode(path, create)
|
||||||
local parts = segments(path)
|
local parts = segments(path)
|
||||||
local node = mtab
|
local node = mtab
|
||||||
for _, part in ipairs(parts) do
|
for i = 1, #parts do
|
||||||
if not node.children[part] then
|
if not node.children[parts[i]] then
|
||||||
if create then
|
if create then
|
||||||
node.children[part] = {children={}}
|
node.children[parts[i]] = {children={}, parent=node}
|
||||||
else
|
else
|
||||||
return nil
|
return node, table.concat(parts, "/", i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
node = node.children[part]
|
node = node.children[parts[i]]
|
||||||
end
|
end
|
||||||
return node
|
return node
|
||||||
end
|
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)
|
function driver.fs.mount(fs, path)
|
||||||
assert(type(fs) == "string",
|
assert(type(fs) == "string",
|
||||||
@ -71,18 +63,29 @@ end
|
|||||||
function driver.fs.umount(fsOrPath)
|
function driver.fs.umount(fsOrPath)
|
||||||
assert(type(fsOrPath) == "string",
|
assert(type(fsOrPath) == "string",
|
||||||
"bad argument #1 (string expected, got " .. type(fsOrPath) .. ")")
|
"bad argument #1 (string expected, got " .. type(fsOrPath) .. ")")
|
||||||
if type(fsOrPath) == "string" then
|
local function removeEmptyNodes(node)
|
||||||
local node = findNode(fsOrPath)
|
while node and node.parent and not node.fs and not next(node.children) do
|
||||||
if node and node.fs then
|
for k, c in pairs(node.parent.children) do
|
||||||
node.fs = nil
|
if c == node then
|
||||||
return true
|
node.parent.children[k] = nil
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
node = node.parent
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
local node, rest = findNode(fsOrPath)
|
||||||
|
if not rest and node.fs then
|
||||||
|
node.fs = nil
|
||||||
|
removeEmptyNodes(node)
|
||||||
|
return true
|
||||||
else
|
else
|
||||||
local queue = {mtab}
|
local queue = {mtab}
|
||||||
repeat
|
repeat
|
||||||
local node = table.remove(queue)
|
local node = table.remove(queue)
|
||||||
if node.fs == fsOrPath then
|
if node.fs == fsOrPath then
|
||||||
node.fs = nil
|
node.fs = nil
|
||||||
|
removeEmptyNodes(node)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
for _, child in ipairs(node.children) do
|
for _, child in ipairs(node.children) do
|
||||||
@ -92,30 +95,63 @@ function driver.fs.umount(fsOrPath)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function driver.fs.listdir(path)
|
-------------------------------------------------------------------------------
|
||||||
local fs, subpath, node = findFs(path)
|
|
||||||
local result = {}
|
function driver.fs.exists(path)
|
||||||
for k, _ in pairs(node.children) do
|
local node, rest = findNode(path)
|
||||||
table.insert(result, k .. "/")
|
if not rest then -- virtual directory
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
if fs then
|
if node.fs then
|
||||||
local fsresult = {sendToNode(fs, "fs.list", subpath)}
|
return sendToNode(node.fs, "fs.exists", rest)
|
||||||
for _, k in ipairs(fsresult) do
|
end
|
||||||
table.insert(result, k)
|
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
|
||||||
end
|
end
|
||||||
table.sort(result)
|
table.sort(result)
|
||||||
return table.unpack(result)
|
return table.unpack(result)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
function driver.fs.remove(path)
|
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
|
end
|
||||||
|
|
||||||
function driver.fs.rename(oldPath, newPath)
|
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
|
end
|
||||||
|
|
||||||
function driver.fs.tmpname()
|
-------------------------------------------------------------------------------
|
||||||
end
|
|
||||||
|
|
||||||
local file = {}
|
local file = {}
|
||||||
|
|
||||||
@ -306,35 +342,37 @@ function file.write(f, ...)
|
|||||||
end
|
end
|
||||||
buffer = buffer .. arg
|
buffer = buffer .. arg
|
||||||
]]
|
]]
|
||||||
sendToNode(f.fs, "fs.write", arg)
|
sendToNode(f.fs, "fs.write", f.handle, arg)
|
||||||
end
|
end
|
||||||
return f
|
return f
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
|
||||||
function driver.fs.open(path, mode)
|
function driver.fs.open(path, mode)
|
||||||
assert(type(path) == "string",
|
assert(type(path) == "string",
|
||||||
"bad argument #1 (string expected, got " .. type(path) .. ")")
|
"bad argument #1 (string expected, got " .. type(path) .. ")")
|
||||||
mode = mode or "r"
|
mode = mode or "r"
|
||||||
assert(({r=true, rb=true, w=true, wb=true, a=true, ab=true})[mode],
|
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) .. ")")
|
"bad argument #2 (r[b], w[b] or a[b] expected, got " .. tostring(mode) .. ")")
|
||||||
local fs, subpath = findFs(path)
|
local node, rest = findNode(path)
|
||||||
if not fs then
|
if not node.fs or not rest then -- files can only be in file systems
|
||||||
return nil, "file not found"
|
return nil, "file not found"
|
||||||
end
|
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
|
if not handle then
|
||||||
return nil, reason
|
return nil, reason
|
||||||
end
|
end
|
||||||
return setmetatable({
|
return setmetatable({
|
||||||
fs = fs,
|
fs = node.fs,
|
||||||
handle = handle,
|
handle = handle,
|
||||||
bsize = 8 * 1024,
|
bsize = 8 * 1024,
|
||||||
bmode = "no"
|
bmode = "full"
|
||||||
}, {
|
}, {
|
||||||
__index = file,
|
__index = file,
|
||||||
__gc = function(f)
|
__gc = function(f)
|
||||||
-- File.close does a syscall, which yields, and that's not possible in
|
-- 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.
|
-- the __gc metamethod. So we start a timer to do the yield/cleanup.
|
||||||
event.timer(0, function()
|
event.timer(0, function()
|
||||||
file.close(f)
|
file.close(f)
|
||||||
end)
|
end)
|
||||||
@ -353,19 +391,7 @@ function driver.fs.type(f)
|
|||||||
end
|
end
|
||||||
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)
|
function loadfile(file, env)
|
||||||
local f, reason = driver.fs.open(file)
|
local f, reason = driver.fs.open(file)
|
||||||
@ -387,4 +413,4 @@ function dofile(file)
|
|||||||
return nil, reason
|
return nil, reason
|
||||||
end
|
end
|
||||||
return f()
|
return f()
|
||||||
end
|
end
|
||||||
|
@ -152,8 +152,8 @@ end
|
|||||||
|
|
||||||
local function main(args)
|
local function main(args)
|
||||||
local function init()
|
local function init()
|
||||||
sandbox.driver.fs.mount(os.romAddress(), "/rom")
|
sandbox.driver.fs.mount(os.romAddress(), "/boot")
|
||||||
local result, reason = sandbox.loadfile("/rom/init.lua")
|
local result, reason = sandbox.loadfile("/boot/init.lua")
|
||||||
if not result then
|
if not result then
|
||||||
error(reason)
|
error(reason)
|
||||||
end
|
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("/boot/api/event.lua")
|
||||||
dofile("/rom/api/component.lua")
|
dofile("/boot/api/component.lua")
|
||||||
dofile("/rom/api/term.lua")
|
dofile("/boot/api/filesystem.lua")
|
||||||
dofile("/rom/sh.lua")
|
dofile("/boot/api/term.lua")
|
||||||
|
dofile("/boot/sh.lua")
|
||||||
|
|
||||||
|
driver.fs.umount("/boot")
|
||||||
|
|
||||||
event.fire(...)
|
event.fire(...)
|
||||||
while true do
|
while true do
|
||||||
|
@ -6,22 +6,24 @@ object Items {
|
|||||||
var multi: item.Delegator = null
|
var multi: item.Delegator = null
|
||||||
|
|
||||||
var gpu: item.GraphicsCard = null
|
var gpu: item.GraphicsCard = null
|
||||||
var hdd: item.Hdd = null
|
|
||||||
var rs: item.RedstoneCard = null
|
var rs: item.RedstoneCard = null
|
||||||
|
|
||||||
var ram32k: item.Memory = null
|
var ram32k: item.Memory = null
|
||||||
var ram64k: item.Memory = null
|
var ram64k: item.Memory = null
|
||||||
var ram128k: item.Memory = null
|
var ram128k: item.Memory = null
|
||||||
|
|
||||||
|
var hdd: item.Hdd = null
|
||||||
|
|
||||||
def init() {
|
def init() {
|
||||||
multi = new item.Delegator(Config.itemId)
|
multi = new item.Delegator(Config.itemId)
|
||||||
|
|
||||||
gpu = new item.GraphicsCard(multi)
|
gpu = new item.GraphicsCard(multi)
|
||||||
hdd = new item.Hdd(multi)
|
|
||||||
rs = new item.RedstoneCard(multi)
|
rs = new item.RedstoneCard(multi)
|
||||||
|
|
||||||
ram32k = new item.Memory(multi, 32)
|
ram32k = new item.Memory(multi, 32)
|
||||||
ram64k = new item.Memory(multi, 64)
|
ram64k = new item.Memory(multi, 64)
|
||||||
ram128k = new item.Memory(multi, 128)
|
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) = {
|
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 None => // Invalid but avoid match error.
|
||||||
case Some(subBlock) => {
|
case Some(subBlock) => {
|
||||||
world.getBlockTileEntity(x, y, z) match {
|
world.getBlockTileEntity(x, y, z) match {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
package li.cil.oc.common.item
|
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"
|
def unlocalizedName = "HardDiskDrive"
|
||||||
}
|
}
|
@ -46,6 +46,7 @@ trait ComponentInventory extends IInventory with Node {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
computer.recomputeMemory()
|
||||||
}
|
}
|
||||||
|
|
||||||
override def save(nbt: NBTTagCompound) = {
|
override def save(nbt: NBTTagCompound) = {
|
||||||
|
@ -39,7 +39,7 @@ class FileSystem(val fileSystem: api.FileSystem) extends Node {
|
|||||||
None
|
None
|
||||||
case Array(path: Array[Byte]) if message.name == "fs.exists" =>
|
case Array(path: Array[Byte]) if message.name == "fs.exists" =>
|
||||||
Some(Array(fileSystem.exists(clean(path)).asInstanceOf[Any]))
|
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]))
|
Some(Array(fileSystem.size(clean(path)).asInstanceOf[Any]))
|
||||||
case Array(path: Array[Byte]) if message.name == "fs.isDirectory" =>
|
case Array(path: Array[Byte]) if message.name == "fs.isDirectory" =>
|
||||||
Some(Array(fileSystem.isDirectory(clean(path)).asInstanceOf[Any]))
|
Some(Array(fileSystem.isDirectory(clean(path)).asInstanceOf[Any]))
|
||||||
|
@ -1,16 +1,33 @@
|
|||||||
package li.cil.oc.server.driver
|
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.{Config, Items}
|
||||||
import li.cil.oc.api.driver
|
|
||||||
import li.cil.oc.api.driver.Slot
|
|
||||||
import net.minecraft.item.ItemStack
|
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 api = Option(getClass.getResourceAsStream(Config.driverPath + "fs.lua"))
|
||||||
|
|
||||||
override def worksWith(item: ItemStack) = WorksWith(Items.hdd)(item)
|
override def worksWith(item: ItemStack) = WorksWith(Items.hdd)(item)
|
||||||
|
|
||||||
override def slot(item: ItemStack) = Slot.HDD
|
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