Fix legacy DiskStore support

The archive IDs are offset by one in a legacy main_file_cache.dat cache.

Signed-off-by: Graham <gpe@openrs2.org>
Graham 3 years ago
parent b1c3cbc7e3
commit 02f35fd014
  1. 30
      cache/src/main/kotlin/org/openrs2/cache/DiskStore.kt
  2. 56
      cache/src/test/kotlin/org/openrs2/cache/DiskStoreTest.kt
  3. BIN
      cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-legacy/main_file_cache.dat
  4. BIN
      cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-legacy/main_file_cache.idx0
  5. BIN
      cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-overwritten-legacy/main_file_cache.dat
  6. BIN
      cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-first-invalid-archive-overwritten-legacy/main_file_cache.idx0
  7. BIN
      cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-legacy/main_file_cache.dat
  8. BIN
      cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-legacy/main_file_cache.idx0
  9. BIN
      cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-overwritten-legacy/main_file_cache.dat
  10. BIN
      cache/src/test/resources/org/openrs2/cache/disk-store/corrupt-second-invalid-archive-overwritten-legacy/main_file_cache.idx0
  11. BIN
      cache/src/test/resources/org/openrs2/cache/disk-store/single-block-legacy/main_file_cache.dat
  12. 0
      cache/src/test/resources/org/openrs2/cache/disk-store/single-block-legacy/main_file_cache.idx0

@ -30,10 +30,13 @@ public class DiskStore private constructor(
private val data: BufferedFileChannel, private val data: BufferedFileChannel,
private val musicData: BufferedFileChannel?, private val musicData: BufferedFileChannel?,
private val indexes: Array<BufferedFileChannel?>, private val indexes: Array<BufferedFileChannel?>,
private val alloc: ByteBufAllocator private val alloc: ByteBufAllocator,
legacyData: Boolean
) : Store { ) : Store {
private data class IndexEntry(val size: Int, val block: Int) private data class IndexEntry(val size: Int, val block: Int)
private val archiveOffset = if (legacyData) 1 else 0
init { init {
require(indexes.size == Store.MAX_ARCHIVE + 1) require(indexes.size == Store.MAX_ARCHIVE + 1)
} }
@ -194,7 +197,7 @@ public class DiskStore private constructor(
} }
val actualNum = tempBuf.readUnsignedShort() val actualNum = tempBuf.readUnsignedShort()
val nextBlock = tempBuf.readUnsignedMedium() val nextBlock = tempBuf.readUnsignedMedium()
val actualArchive = tempBuf.readUnsignedByte().toInt() val actualArchive = (tempBuf.readUnsignedByte().toInt() - archiveOffset) and 0xFF
// verify header // verify header
when { when {
@ -317,7 +320,7 @@ public class DiskStore private constructor(
} }
val actualNum = tempBuf.readUnsignedShort() val actualNum = tempBuf.readUnsignedShort()
nextBlock = tempBuf.readUnsignedMedium() nextBlock = tempBuf.readUnsignedMedium()
val actualArchive = tempBuf.readUnsignedByte().toInt() val actualArchive = (tempBuf.readUnsignedByte().toInt() - archiveOffset) and 0xFF
if (actualGroup != group || actualNum != num || actualArchive != archive) { if (actualGroup != group || actualNum != num || actualArchive != archive) {
block = 0 block = 0
@ -371,7 +374,7 @@ public class DiskStore private constructor(
} }
val actualNum = tempBuf.readUnsignedShort() val actualNum = tempBuf.readUnsignedShort()
nextNextBlock = tempBuf.readUnsignedMedium() nextNextBlock = tempBuf.readUnsignedMedium()
val actualArchive = tempBuf.readUnsignedByte().toInt() val actualArchive = (tempBuf.readUnsignedByte().toInt() - archiveOffset) and 0xFF
if (actualGroup != group || actualNum != nextNum || actualArchive != archive) { if (actualGroup != group || actualNum != nextNum || actualArchive != archive) {
nextBlock = 0 nextBlock = 0
@ -403,7 +406,7 @@ public class DiskStore private constructor(
} }
tempBuf.writeShort(num) tempBuf.writeShort(num)
tempBuf.writeMedium(nextBlock) tempBuf.writeMedium(nextBlock)
tempBuf.writeByte(archive) tempBuf.writeByte(archive + archiveOffset)
data.write(blockPos, tempBuf, headerSize) data.write(blockPos, tempBuf, headerSize)
@ -501,10 +504,13 @@ public class DiskStore private constructor(
val js5DataPath = dataPath(root) val js5DataPath = dataPath(root)
val legacyDataPath = legacyDataPath(root) val legacyDataPath = legacyDataPath(root)
val dataPath = if (Files.exists(js5DataPath)) { // We check for js5DataPath first as it takes precedence.
js5DataPath val legacyDataFile = !Files.exists(js5DataPath)
} else {
val dataPath = if (legacyDataFile) {
legacyDataPath legacyDataPath
} else {
js5DataPath
} }
val data = BufferedFileChannel( val data = BufferedFileChannel(
FileChannel.open(dataPath, READ, WRITE), 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( public fun create(
root: Path, root: Path,
alloc: ByteBufAllocator = ByteBufAllocator.DEFAULT, alloc: ByteBufAllocator = ByteBufAllocator.DEFAULT,
legacyDataPath: Boolean = false legacyDataFile: Boolean = false
): Store { ): Store {
Files.createDirectories(root) Files.createDirectories(root)
val dataPath = if (legacyDataPath) { val dataPath = if (legacyDataFile) {
legacyDataPath(root) legacyDataPath(root)
} else { } else {
dataPath(root) dataPath(root)
@ -563,7 +569,7 @@ public class DiskStore private constructor(
val archives = Array<BufferedFileChannel?>(Store.MAX_ARCHIVE + 1) { null } val archives = Array<BufferedFileChannel?>(Store.MAX_ARCHIVE + 1) { null }
return DiskStore(root, data, null, archives, alloc) return DiskStore(root, data, null, archives, alloc, legacyDataFile)
} }
} }
} }

@ -507,6 +507,12 @@ class DiskStoreTest {
} }
} }
readTest("corrupt-first-invalid-archive-legacy") { store ->
assertFailsWith<StoreCorruptException> {
store.read(0, 1).release()
}
}
readTest("corrupt-first-invalid-block-number") { store -> readTest("corrupt-first-invalid-block-number") { store ->
assertFailsWith<StoreCorruptException> { assertFailsWith<StoreCorruptException> {
store.read(255, 1).release() store.read(255, 1).release()
@ -537,6 +543,12 @@ class DiskStoreTest {
} }
} }
readTest("corrupt-second-invalid-archive-legacy") { store ->
assertFailsWith<StoreCorruptException> {
store.read(0, 1).release()
}
}
readTest("corrupt-second-invalid-block-number") { store -> readTest("corrupt-second-invalid-block-number") { store ->
assertFailsWith<StoreCorruptException> { assertFailsWith<StoreCorruptException> {
store.read(255, 1).release() 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 -> overwriteTest("corrupt-first-invalid-block-number", "corrupt-first-invalid-block-number-overwritten") { store ->
copiedBuffer("Hello".repeat(300)).use { buf -> copiedBuffer("Hello".repeat(300)).use { buf ->
store.write(255, 1, 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( overwriteTest(
"corrupt-second-invalid-block-number", "corrupt-second-invalid-block-number",
"corrupt-second-invalid-block-number-overwritten" "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 -> readTest("corrupt-first-invalid-block-number-overwritten") { store ->
store.read(255, 1).use { actual -> store.read(255, 1).use { actual ->
copiedBuffer("Hello".repeat(300)).use { expected -> 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 -> readTest("corrupt-second-invalid-block-number-overwritten") { store ->
store.read(255, 1).use { actual -> store.read(255, 1).use { actual ->
copiedBuffer("Hello".repeat(300)).use { expected -> copiedBuffer("Hello".repeat(300)).use { expected ->
@ -762,9 +808,9 @@ class DiskStoreTest {
@Test @Test
fun testCreateLegacyDataFile() { fun testCreateLegacyDataFile() {
writeTest("single-block-legacy", legacyDataPath = true) { store -> writeTest("single-block-legacy", legacyDataFile = true) { store ->
copiedBuffer("OpenRS2").use { buf -> copiedBuffer("OpenRS2").use { buf ->
store.write(255, 1, buf) store.write(0, 1, buf)
} }
} }
} }
@ -773,7 +819,7 @@ class DiskStoreTest {
fun testOpenLegacyDataFile() { fun testOpenLegacyDataFile() {
readTest("single-block-legacy") { store -> readTest("single-block-legacy") { store ->
copiedBuffer("OpenRS2").use { expected -> copiedBuffer("OpenRS2").use { expected ->
store.read(255, 1).use { actual -> store.read(0, 1).use { actual ->
assertEquals(expected, 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 -> Jimfs.newFileSystem(Configuration.forCurrentPlatform()).use { fs ->
val actual = fs.rootDirectories.first().resolve("cache") val actual = fs.rootDirectories.first().resolve("cache")
DiskStore.create(actual, legacyDataPath = legacyDataPath).use { store -> DiskStore.create(actual, legacyDataFile = legacyDataFile).use { store ->
f(store) f(store)
} }

Loading…
Cancel
Save