blob: d29c8068b82852d33b743f9f7321161cd54080c3 [file] [log] [blame] [raw]
package li.cil.oc.server.fs
import java.io
import li.cil.oc.Settings
import li.cil.oc.api.fs.Mode
import net.minecraft.nbt.NBTTagCompound
trait Capacity extends OutputStreamFileSystem {
private var used = computeSize("/")
// Used when loading data from disk to virtual file systems, to allow
// exceeding the actual capacity of a file system.
private var ignoreCapacity = false
protected def capacity: Long
// ----------------------------------------------------------------------- //
override def spaceTotal = capacity
override def spaceUsed = used
// ----------------------------------------------------------------------- //
override def delete(path: String) = {
val freed = Settings.get.fileCost + size(path)
if (super.delete(path)) {
used -= freed
true
}
else false
}
override def makeDirectory(path: String) = {
if (capacity - used < Settings.get.fileCost && !ignoreCapacity) {
throw new io.IOException("not enough space")
}
if (super.makeDirectory(path)) {
used += Settings.get.fileCost
true
}
else false
}
// ----------------------------------------------------------------------- //
override def load(nbt: NBTTagCompound) {
try {
ignoreCapacity = true
super.load(nbt)
} finally {
ignoreCapacity = false
}
}
override def save(nbt: NBTTagCompound) {
super.save(nbt)
// For the tooltip.
nbt.setLong("capacity.used", used)
}
// ----------------------------------------------------------------------- //
override abstract protected def openOutputHandle(id: Int, path: String, mode: Mode): Option[OutputHandle] = {
val delta =
if (exists(path))
if (mode == Mode.Write)
-size(path) // Overwrite, file gets cleared.
else
0 // Append, no immediate changes.
else
Settings.get.fileCost // File creation.
if (capacity - used < delta && !ignoreCapacity) {
throw new io.IOException("not enough space")
}
super.openOutputHandle(id, path, mode) match {
case None => None
case Some(stream) =>
used += delta
if (mode == Mode.Append) {
stream.seek(stream.length())
}
Some(new CountingOutputHandle(this, stream))
}
}
// ----------------------------------------------------------------------- //
private def computeSize(path: String): Long =
Settings.get.fileCost +
size(path) +
(if (isDirectory(path))
list(path).foldLeft(0L)((acc, child) => acc + computeSize(path + child))
else 0)
protected class CountingOutputHandle(override val owner: Capacity, val inner: OutputHandle) extends OutputHandle(inner.owner, inner.handle, inner.path) {
override def isClosed = inner.isClosed
override def length = inner.length
override def position = inner.position
override def close() = inner.close()
override def seek(to: Long) = inner.seek(to)
override def write(b: Array[Byte]) {
if (owner.capacity - owner.used < b.length && !ignoreCapacity)
throw new io.IOException("not enough space")
inner.write(b)
owner.used = owner.used + b.length
}
}
}