fixes, bits and pieces, changes in ID referencing, terrain and wall takes damage, working test pickaxe, and a new issue

This commit is contained in:
Song Minjae
2017-04-17 02:18:52 +09:00
parent 6087072d3d
commit f2ae2d9449
40 changed files with 502 additions and 249 deletions

View File

@@ -94,7 +94,7 @@ internal class Filesystem(globals: Globals, computer: TerrarumComputer) {
path.dropMount()
return VDUtil.getFile(disk, path)?.file
return VDUtil.getFile(disk, path)
}
/**
@@ -201,7 +201,7 @@ internal class Filesystem(globals: Globals, computer: TerrarumComputer) {
if (file!!.contents is EntryFile)
return LuaValue.valueOf(file.contents.getSizePure().toInt())
else if (file.contents is EntryDirectory)
return LuaValue.valueOf(file.contents.entries.size)
return LuaValue.valueOf(file.contents.entryCount)
}
catch (e: KotlinNullPointerException) {
}
@@ -279,12 +279,12 @@ internal class Filesystem(globals: Globals, computer: TerrarumComputer) {
val file = VDUtil.getFile(disk1, pathFrom)!!
try {
VDUtil.addFile(disk2, pathTo.getParent(), file.file)
VDUtil.addFile(disk2, pathTo.getParent(), file)
}
catch (e: FileNotFoundException) {
// roll back delete on disk2
if (oldFile != null) {
VDUtil.addFile(disk2, oldFile.parent.entryID, oldFile.file)
VDUtil.addFile(disk2, oldFile.parentEntryID, oldFile)
throw FileNotFoundException("No such destination")
}
}

View File

@@ -41,7 +41,7 @@ object VDUtil {
unsanitisedHierarchy.removeAt(0)
// removes tail slash
if (unsanitisedHierarchy.size > 0 &&
unsanitisedHierarchy[unsanitisedHierarchy.lastIndex].isEmpty())
unsanitisedHierarchy[unsanitisedHierarchy.lastIndex].isEmpty())
unsanitisedHierarchy.removeAt(unsanitisedHierarchy.lastIndex)
unsanitisedHierarchy.forEach {
@@ -202,7 +202,7 @@ object VDUtil {
val calculatedCRC = diskEntry.hashCode()
val crcMsg = "CRC failed: expected ${entryCRC.toHex()}, got ${calculatedCRC.toHex()}\n" +
"at file \"${diskEntry.getFilenameString(charset)}\" (entry ID ${diskEntry.entryID})"
"at file \"${diskEntry.getFilenameString(charset)}\" (entry ID ${diskEntry.entryID})"
if (calculatedCRC != entryCRC) {
if (crcWarnLevel == Level.SEVERE)
@@ -243,7 +243,7 @@ object VDUtil {
throw IllegalArgumentException("The entry is not directory")
val entriesList = ArrayList<DiskEntry>()
dirToSearch.contents.entries.forEach {
dirToSearch.contents.forEach {
val entry = disk.entries[it]
if (entry != null) entriesList.add(entry)
}
@@ -267,7 +267,7 @@ object VDUtil {
* Search a entry using path
* @return Pair of <The file, Parent file>, or null if not found
*/
fun getFile(disk: VirtualDisk, path: VDPath): EntrySearchResult? {
fun getFile(disk: VirtualDisk, path: VDPath): DiskEntry? {
val searchHierarchy = ArrayList<DiskEntry>()
fun getCurrentEntry(): DiskEntry = searchHierarchy.last()
//var currentDirectory = disk.root
@@ -276,10 +276,7 @@ object VDUtil {
// path of root
if (path.hierarchy.size == 0) {
return EntrySearchResult(
disk.entries[0]!!,
disk.entries[0]!!
)
return disk.entries[0]!!
}
try {
@@ -310,10 +307,7 @@ object VDUtil {
}
// file found
return EntrySearchResult(
searchHierarchy[searchHierarchy.lastIndex],
searchHierarchy[searchHierarchy.lastIndex - 1]
)
return searchHierarchy[searchHierarchy.lastIndex]
}
/**
@@ -323,12 +317,12 @@ object VDUtil {
*/
private fun DiskEntry.getAsNormalFile(disk: VirtualDisk): EntryFile =
this.contents as? EntryFile ?:
if (this.contents is EntryDirectory)
throw RuntimeException("this is directory")
else if (this.contents is EntrySymlink)
disk.entries[this.contents.target]!!.getAsNormalFile(disk)
else
throw RuntimeException("Unknown entry type")
if (this.contents is EntryDirectory)
throw RuntimeException("this is directory")
else if (this.contents is EntrySymlink)
disk.entries[this.contents.target]!!.getAsNormalFile(disk)
else
throw RuntimeException("Unknown entry type")
/**
* SYNOPSIS disk.getFile("bin/msh.lua")!!.first.getAsNormalFile(disk)
*
@@ -336,18 +330,18 @@ object VDUtil {
*/
private fun DiskEntry.getAsDirectory(disk: VirtualDisk): EntryDirectory =
this.contents as? EntryDirectory ?:
if (this.contents is EntrySymlink)
disk.entries[this.contents.target]!!.getAsDirectory(disk)
else if (this.contents is EntryFile)
throw RuntimeException("this is not directory")
else
throw RuntimeException("Unknown entry type")
if (this.contents is EntrySymlink)
disk.entries[this.contents.target]!!.getAsDirectory(disk)
else if (this.contents is EntryFile)
throw RuntimeException("this is not directory")
else
throw RuntimeException("Unknown entry type")
/**
* Search for the file and returns a instance of normal file.
*/
fun getAsNormalFile(disk: VirtualDisk, path: VDPath) =
getFile(disk, path)!!.file.getAsNormalFile(disk)
getFile(disk, path)!!.getAsNormalFile(disk)
/**
* Fetch the file and returns a instance of normal file.
*/
@@ -357,7 +351,7 @@ object VDUtil {
* Search for the file and returns a instance of directory.
*/
fun getAsDirectory(disk: VirtualDisk, path: VDPath) =
getFile(disk, path)!!.file.getAsDirectory(disk)
getFile(disk, path)!!.getAsDirectory(disk)
/**
* Fetch the file and returns a instance of directory.
*/
@@ -367,11 +361,8 @@ object VDUtil {
* Deletes file on the disk safely.
*/
fun deleteFile(disk: VirtualDisk, path: VDPath) {
disk.checkReadOnly()
val fileSearchResult = getFile(disk, path)!!
return deleteFile(disk, fileSearchResult.file.entryID)
return deleteFile(disk, fileSearchResult.entryID)
}
/**
* Deletes file on the disk safely.
@@ -386,29 +377,25 @@ object VDUtil {
}
val parentID = file.parentEntryID
val parentDir = disk.entries[parentID]
val parentDir = getAsDirectory(disk, parentID)
fun rollback() {
if (!disk.entries.contains(targetID)) {
disk.entries[targetID] = file
}
if (!(parentDir!!.contents as EntryDirectory).entries.contains(targetID)) {
(parentDir.contents as EntryDirectory).entries.add(targetID)
if (!parentDir.contains(targetID)) {
parentDir.add(targetID)
}
}
if (parentDir == null || parentDir.contents !is EntryDirectory) {
throw FileNotFoundException("No such parent directory")
}
// check if directory "parentID" has "targetID" in the first place
else if (!directoryContains(disk, parentID, targetID)) {
if (!directoryContains(disk, parentID, targetID)) {
throw FileNotFoundException("No such file to delete")
}
else if (targetID == 0) {
throw IOException("Cannot delete root file system")
}
else if (file.contents is EntryDirectory && file.contents.entries.size > 0) {
//throw IOException("Cannot delete directory that contains something")
else if (file.contents is EntryDirectory && file.contents.entryCount > 0) {
deleteDirRecurse(disk, targetID)
}
else {
@@ -416,7 +403,7 @@ object VDUtil {
// delete file record
disk.entries.remove(targetID)
// unlist file from parent directly
(disk.entries[parentID]!!.contents as EntryDirectory).entries.remove(targetID)
parentDir.remove(targetID)
}
catch (e: Exception) {
rollback()
@@ -428,7 +415,7 @@ object VDUtil {
* Changes the name of the entry.
*/
fun renameFile(disk: VirtualDisk, path: VDPath, newName: String, charset: Charset) {
val file = getFile(disk, path)?.file
val file = getFile(disk, path)
if (file != null) {
file.filename = newName.sanitisePath().toEntryName(DiskEntry.NAME_LENGTH, charset)
@@ -451,23 +438,12 @@ object VDUtil {
}
}
/**
* Add file to the specified directory. ParentID of the file will be overwritten.
* Add file to the specified directory.
* The file will get new EntryID and its ParentID will be overwritten.
*/
fun addFile(disk: VirtualDisk, parentPath: VDPath, file: DiskEntry) {
disk.checkReadOnly()
disk.checkCapacity(file.serialisedSize)
try {
val parentID = getFile(disk, parentPath)!!.file.entryID
// add record to the directory
getAsDirectory(disk, parentPath).entries.add(file.entryID)
// add entry on the disk
disk.entries[file.entryID] = file
file.parentEntryID = parentID
}
catch (e: KotlinNullPointerException) {
throw FileNotFoundException("No such directory")
}
val targetDirID = getFile(disk, parentPath)!!.entryID
return addFile(disk, targetDirID, file)
}
/**
* Add file to the specified directory. ParentID of the file will be overwritten.
@@ -477,10 +453,13 @@ object VDUtil {
disk.checkCapacity(file.serialisedSize)
try {
// generate new ID for the file
file.entryID = disk.generateUniqueID()
// add record to the directory
getAsDirectory(disk, directoryID).entries.add(file.entryID)
getAsDirectory(disk, directoryID).add(file.entryID)
// add entry on the disk
disk.entries[file.entryID] = file
// make this boy recognise his new parent
file.parentEntryID = directoryID
}
catch (e: KotlinNullPointerException) {
@@ -491,28 +470,8 @@ object VDUtil {
* Add subdirectory to the specified directory.
*/
fun addDir(disk: VirtualDisk, parentPath: VDPath, name: ByteArray) {
disk.checkReadOnly()
disk.checkCapacity(EntryDirectory.NEW_ENTRY_SIZE)
val newID = disk.generateUniqueID()
try {
val parentID = getFile(disk, parentPath)!!.file.entryID
// add record to the directory
getAsDirectory(disk, parentPath).entries.add(newID)
// add entry on the disk
disk.entries[newID] = DiskEntry(
newID,
parentID,
name,
currentUnixtime,
currentUnixtime,
EntryDirectory()
)
}
catch (e: KotlinNullPointerException) {
throw FileNotFoundException("No such directory")
}
val parentID = getFile(disk, parentPath)!!.entryID
return addDir(disk, parentID, name)
}
/**
* Add file to the specified directory.
@@ -525,7 +484,7 @@ object VDUtil {
try {
// add record to the directory
getAsDirectory(disk, directoryID).entries.add(newID)
getAsDirectory(disk, directoryID).add(newID)
// add entry on the disk
disk.entries[newID] = DiskEntry(
newID,
@@ -553,7 +512,7 @@ object VDUtil {
}
// recurse
else {
entry.contents.entries.forEach {
entry.contents.forEach {
entriesToDelete.add(entry.entryID)
recurse1(disk.entries[it])
}
@@ -562,7 +521,7 @@ object VDUtil {
val entry = disk.entries[directoryID]
if (entry != null && entry.contents is EntryDirectory) {
entry.contents.entries.forEach {
entry.contents.forEach {
entriesToDelete.add(directoryID)
recurse1(disk.entries[it])
}
@@ -630,12 +589,10 @@ object VDUtil {
fun moveFile(disk1: VirtualDisk, fromPath: VDPath, disk2: VirtualDisk, toPath: VDPath) {
val file = getFile(disk1, fromPath)
if (file != null) {
if (file.file.contents is EntryDirectory) {
throw IOException("Cannot move directory")
}
// checking readOnly is redundant here
disk2.checkCapacity(file.file.contents.getSizeEntry())
if (file != null) {
disk2.checkCapacity(file.contents.getSizeEntry())
try {
deleteFile(disk2, toPath)
@@ -644,11 +601,11 @@ object VDUtil {
deleteFile(disk1, fromPath) // any uncaught no_from_file will be caught here
try {
addFile(disk2, toPath.getParent(), file.file)
addFile(disk2, toPath.getParent(), file)
}
catch (e: FileNotFoundException) {
// roll back delete on disk1
addFile(disk1, file.parent.entryID, file.file)
addFile(disk1, file.parentEntryID, file)
throw FileNotFoundException("No such destination")
}
}
@@ -740,7 +697,6 @@ object VDUtil {
val path1 = this.replace('\\', '/')
return path1
}
data class EntrySearchResult(val file: DiskEntry, val parent: DiskEntry)
fun resolveIfSymlink(disk: VirtualDisk, indexNumber: EntryID, recurse: Boolean = false): DiskEntry {
var entry: DiskEntry? = disk.entries[indexNumber]
@@ -769,7 +725,7 @@ object VDUtil {
throw FileNotFoundException("Not a directory")
}
else {
return dir.contents.entries.contains(targetID)
return dir.contents.contains(targetID)
}
}
@@ -784,11 +740,16 @@ object VDUtil {
return disk.entries.filter { disk.entries[it.value.parentEntryID] == null }.keys.toList()
}
/**
* Searches for null-pointing entries (phantoms) within every directory.
*
* @return List of search results, which is Pair(directory that contains null pointer, null pointer)
*/
fun gcSearchPhantomBaby(disk: VirtualDisk): List<Pair<EntryID, EntryID>> {
// Pair<DirectoryID, ID of phantom in the directory>
val phantoms = ArrayList<Pair<EntryID, EntryID>>()
disk.entries.filter { it.value.contents is EntryDirectory }.values.forEach { directory ->
(directory.contents as EntryDirectory).entries.forEach { dirEntryID ->
(directory.contents as EntryDirectory).forEach { dirEntryID ->
if (disk.entries[dirEntryID] == null) {
phantoms.add(Pair(directory.entryID, dirEntryID))
}
@@ -811,7 +772,7 @@ object VDUtil {
fun gcDumpAll(disk: VirtualDisk) {
try {
gcSearchPhantomBaby(disk).forEach {
getAsDirectory(disk, it.first).entries.remove(it.second)
getAsDirectory(disk, it.first).remove(it.second)
}
gcSearchOrphan(disk).forEach {
disk.entries.remove(it)

View File

@@ -1,5 +1,6 @@
package net.torvald.terrarum.virtualcomputer.tvd
import java.io.IOException
import java.nio.charset.Charset
import java.util.*
import java.util.function.Consumer
@@ -182,10 +183,30 @@ class EntryFile(var bytes: ByteArray64) : DiskEntryContent {
return buffer
}
}
class EntryDirectory(val entries: ArrayList<EntryID> = ArrayList<EntryID>()) : DiskEntryContent {
class EntryDirectory(private val entries: ArrayList<EntryID> = ArrayList<EntryID>()) : DiskEntryContent {
override fun getSizePure() = entries.size * 4L
override fun getSizeEntry() = getSizePure() + 2
private fun checkCapacity(toAdd: Int = 1) {
if (entries.size + toAdd > 65535)
throw IOException("Directory entries limit exceeded.")
}
fun add(entryID: EntryID) {
checkCapacity()
entries.add(entryID)
}
fun remove(entryID: EntryID) {
entries.removeAt(entryID)
}
fun contains(entryID: EntryID) = entries.contains(entryID)
fun forEach(consumer: (EntryID) -> Unit) = entries.forEach(consumer)
val entryCount: Int
get() = entries.size
override fun serialize(): AppendableByteBuffer {
val buffer = AppendableByteBuffer(getSizeEntry())