diff --git a/cache/src/main/kotlin/org/openrs2/cache/DiskStore.kt b/cache/src/main/kotlin/org/openrs2/cache/DiskStore.kt index 3c43f709..e34028a4 100644 --- a/cache/src/main/kotlin/org/openrs2/cache/DiskStore.kt +++ b/cache/src/main/kotlin/org/openrs2/cache/DiskStore.kt @@ -30,10 +30,13 @@ public class DiskStore private constructor( private val data: BufferedFileChannel, private val musicData: BufferedFileChannel?, private val indexes: Array, - private val alloc: ByteBufAllocator + private val alloc: ByteBufAllocator, + legacyData: Boolean ) : Store { private data class IndexEntry(val size: Int, val block: Int) + private val archiveOffset = if (legacyData) 1 else 0 + init { require(indexes.size == Store.MAX_ARCHIVE + 1) } @@ -194,7 +197,7 @@ public class DiskStore private constructor( } val actualNum = tempBuf.readUnsignedShort() val nextBlock = tempBuf.readUnsignedMedium() - val actualArchive = tempBuf.readUnsignedByte().toInt() + val actualArchive = (tempBuf.readUnsignedByte().toInt() - archiveOffset) and 0xFF // verify header when { @@ -317,7 +320,7 @@ public class DiskStore private constructor( } val actualNum = tempBuf.readUnsignedShort() nextBlock = tempBuf.readUnsignedMedium() - val actualArchive = tempBuf.readUnsignedByte().toInt() + val actualArchive = (tempBuf.readUnsignedByte().toInt() - archiveOffset) and 0xFF if (actualGroup != group || actualNum != num || actualArchive != archive) { block = 0 @@ -371,7 +374,7 @@ public class DiskStore private constructor( } val actualNum = tempBuf.readUnsignedShort() nextNextBlock = tempBuf.readUnsignedMedium() - val actualArchive = tempBuf.readUnsignedByte().toInt() + val actualArchive = (tempBuf.readUnsignedByte().toInt() - archiveOffset) and 0xFF if (actualGroup != group || actualNum != nextNum || actualArchive != archive) { nextBlock = 0 @@ -403,7 +406,7 @@ public class DiskStore private constructor( } tempBuf.writeShort(num) tempBuf.writeMedium(nextBlock) - tempBuf.writeByte(archive) + tempBuf.writeByte(archive + archiveOffset) data.write(blockPos, tempBuf, headerSize) @@ -501,10 +504,13 @@ public class DiskStore private constructor( val js5DataPath = dataPath(root) val legacyDataPath = legacyDataPath(root) - val dataPath = if (Files.exists(js5DataPath)) { - js5DataPath - } else { + // We check for js5DataPath first as it takes precedence. + val legacyDataFile = !Files.exists(js5DataPath) + + val dataPath = if (legacyDataFile) { legacyDataPath + } else { + js5DataPath } val data = BufferedFileChannel( FileChannel.open(dataPath, READ, WRITE), @@ -539,17 +545,17 @@ public class DiskStore private constructor( } } - return DiskStore(root, data, musicData, archives, alloc) + return DiskStore(root, data, musicData, archives, alloc, legacyDataFile) } public fun create( root: Path, alloc: ByteBufAllocator = ByteBufAllocator.DEFAULT, - legacyDataPath: Boolean = false + legacyDataFile: Boolean = false ): Store { Files.createDirectories(root) - val dataPath = if (legacyDataPath) { + val dataPath = if (legacyDataFile) { legacyDataPath(root) } else { dataPath(root) @@ -563,7 +569,7 @@ public class DiskStore private constructor( val archives = Array(Store.MAX_ARCHIVE + 1) { null } - return DiskStore(root, data, null, archives, alloc) + return DiskStore(root, data, null, archives, alloc, legacyDataFile) } } } diff --git a/cache/src/test/kotlin/org/openrs2/cache/DiskStoreTest.kt b/cache/src/test/kotlin/org/openrs2/cache/DiskStoreTest.kt index 208d0dcc..d2bf6b9d 100644 --- a/cache/src/test/kotlin/org/openrs2/cache/DiskStoreTest.kt +++ b/cache/src/test/kotlin/org/openrs2/cache/DiskStoreTest.kt @@ -507,6 +507,12 @@ class DiskStoreTest { } } + readTest("corrupt-first-invalid-archive-legacy") { store -> + assertFailsWith { + store.read(0, 1).release() + } + } + readTest("corrupt-first-invalid-block-number") { store -> assertFailsWith { store.read(255, 1).release() @@ -537,6 +543,12 @@ class DiskStoreTest { } } + readTest("corrupt-second-invalid-archive-legacy") { store -> + assertFailsWith { + store.read(0, 1).release() + } + } + readTest("corrupt-second-invalid-block-number") { store -> assertFailsWith { store.read(255, 1).release() @@ -587,6 +599,15 @@ class DiskStoreTest { } } + overwriteTest( + "corrupt-first-invalid-archive-legacy", + "corrupt-first-invalid-archive-overwritten-legacy" + ) { store -> + copiedBuffer("Hello".repeat(300)).use { buf -> + store.write(0, 1, buf) + } + } + overwriteTest("corrupt-first-invalid-block-number", "corrupt-first-invalid-block-number-overwritten") { store -> copiedBuffer("Hello".repeat(300)).use { buf -> store.write(255, 1, buf) @@ -617,6 +638,15 @@ class DiskStoreTest { } } + overwriteTest( + "corrupt-second-invalid-archive-legacy", + "corrupt-second-invalid-archive-overwritten-legacy" + ) { store -> + copiedBuffer("Hello".repeat(300)).use { buf -> + store.write(0, 1, buf) + } + } + overwriteTest( "corrupt-second-invalid-block-number", "corrupt-second-invalid-block-number-overwritten" @@ -665,6 +695,14 @@ class DiskStoreTest { } } + readTest("corrupt-first-invalid-archive-overwritten-legacy") { store -> + store.read(0, 1).use { actual -> + copiedBuffer("Hello".repeat(300)).use { expected -> + assertEquals(expected, actual) + } + } + } + readTest("corrupt-first-invalid-block-number-overwritten") { store -> store.read(255, 1).use { actual -> copiedBuffer("Hello".repeat(300)).use { expected -> @@ -705,6 +743,14 @@ class DiskStoreTest { } } + readTest("corrupt-second-invalid-archive-overwritten-legacy") { store -> + store.read(0, 1).use { actual -> + copiedBuffer("Hello".repeat(300)).use { expected -> + assertEquals(expected, actual) + } + } + } + readTest("corrupt-second-invalid-block-number-overwritten") { store -> store.read(255, 1).use { actual -> copiedBuffer("Hello".repeat(300)).use { expected -> @@ -762,9 +808,9 @@ class DiskStoreTest { @Test fun testCreateLegacyDataFile() { - writeTest("single-block-legacy", legacyDataPath = true) { store -> + writeTest("single-block-legacy", legacyDataFile = true) { store -> copiedBuffer("OpenRS2").use { buf -> - store.write(255, 1, buf) + store.write(0, 1, buf) } } } @@ -773,7 +819,7 @@ class DiskStoreTest { fun testOpenLegacyDataFile() { readTest("single-block-legacy") { store -> copiedBuffer("OpenRS2").use { expected -> - store.read(255, 1).use { actual -> + store.read(0, 1).use { actual -> assertEquals(expected, actual) } } @@ -786,10 +832,10 @@ class DiskStoreTest { } } - private fun writeTest(name: String, legacyDataPath: Boolean = false, f: (Store) -> Unit) { + private fun writeTest(name: String, legacyDataFile: Boolean = false, f: (Store) -> Unit) { Jimfs.newFileSystem(Configuration.forCurrentPlatform()).use { fs -> val actual = fs.rootDirectories.first().resolve("cache") - DiskStore.create(actual, legacyDataPath = legacyDataPath).use { store -> + DiskStore.create(actual, legacyDataFile = legacyDataFile).use { store -> f(store) } diff --git a/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-legacy/main_file_cache.dat b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-legacy/main_file_cache.dat new file mode 100644 index 00000000..7220e157 Binary files /dev/null and b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-legacy/main_file_cache.dat differ diff --git a/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-legacy/main_file_cache.idx0 b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-legacy/main_file_cache.idx0 new file mode 100644 index 00000000..fba8761c Binary files /dev/null and b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-legacy/main_file_cache.idx0 differ diff --git a/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-overwritten-legacy/main_file_cache.dat b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-overwritten-legacy/main_file_cache.dat new file mode 100644 index 00000000..653f74e4 Binary files /dev/null and b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-overwritten-legacy/main_file_cache.dat differ diff --git a/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-overwritten-legacy/main_file_cache.idx0 b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-overwritten-legacy/main_file_cache.idx0 new file mode 100644 index 00000000..f7c437d5 Binary files /dev/null and b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-overwritten-legacy/main_file_cache.idx0 differ diff --git a/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-legacy/main_file_cache.dat b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-legacy/main_file_cache.dat new file mode 100644 index 00000000..9745254c Binary files /dev/null and b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-legacy/main_file_cache.dat differ diff --git a/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-legacy/main_file_cache.idx0 b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-legacy/main_file_cache.idx0 new file mode 100644 index 00000000..fba8761c Binary files /dev/null and b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-legacy/main_file_cache.idx0 differ diff --git a/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-overwritten-legacy/main_file_cache.dat b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-overwritten-legacy/main_file_cache.dat new file mode 100644 index 00000000..93ca1146 Binary files /dev/null and b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-overwritten-legacy/main_file_cache.dat differ diff --git a/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-overwritten-legacy/main_file_cache.idx0 b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-overwritten-legacy/main_file_cache.idx0 new file mode 100644 index 00000000..6c97b5aa Binary files /dev/null and b/cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-overwritten-legacy/main_file_cache.idx0 differ diff --git a/cache/src/test/resources/org/openrs2/cache/disk-store/single-block-legacy/main_file_cache.dat b/cache/src/test/resources/org/openrs2/cache/disk-store/single-block-legacy/main_file_cache.dat index 98a426d1..c7bc0906 100644 Binary files a/cache/src/test/resources/org/openrs2/cache/disk-store/single-block-legacy/main_file_cache.dat and b/cache/src/test/resources/org/openrs2/cache/disk-store/single-block-legacy/main_file_cache.dat differ diff --git a/cache/src/test/resources/org/openrs2/cache/disk-store/single-block-legacy/main_file_cache.idx255 b/cache/src/test/resources/org/openrs2/cache/disk-store/single-block-legacy/main_file_cache.idx0 similarity index 100% rename from cache/src/test/resources/org/openrs2/cache/disk-store/single-block-legacy/main_file_cache.idx255 rename to cache/src/test/resources/org/openrs2/cache/disk-store/single-block-legacy/main_file_cache.idx0