From 2f4c0e9ae5c4c9452e0f71f15da840b192b6796b Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Mon, 11 Jul 2016 15:18:40 +0100 Subject: [PATCH 1/2] Remove TODO as the usage of CheckpointStorage is only through ServiceHubInternal into the StateMachineManager. We don't restrict access to internal for now as this causes too much other change. --- .../kotlin/com/r3corda/node/services/api/CheckpointStorage.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/node/src/main/kotlin/com/r3corda/node/services/api/CheckpointStorage.kt b/node/src/main/kotlin/com/r3corda/node/services/api/CheckpointStorage.kt index 4268d7ffc6..f80d0dcdfe 100644 --- a/node/src/main/kotlin/com/r3corda/node/services/api/CheckpointStorage.kt +++ b/node/src/main/kotlin/com/r3corda/node/services/api/CheckpointStorage.kt @@ -5,8 +5,6 @@ import com.r3corda.node.services.statemachine.ProtocolStateMachineImpl /** * Thread-safe storage of fiber checkpoints. - * - * TODO: Make internal to node again once split [ServiceHub] into a public (to contracts etc) and private (to node) view */ interface CheckpointStorage { From 63f40fd8d42dc4d69b59183aed4cac3f1d1353b4 Mon Sep 17 00:00:00 2001 From: Matthew Nesbit Date: Tue, 12 Jul 2016 11:52:56 +0100 Subject: [PATCH 2/2] Remove TODO associated with the fact that the ZIP filesystem does not specify the Path Separator character. Add a test to check access through forward or backward slashes is consistent. --- .../com/r3corda/core/contracts/Structures.kt | 5 ++-- .../core/node/AttachmentsClassLoader.kt | 6 ++-- .../core/node/AttachmentClassLoaderTests.kt | 30 +++++++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt index 543e6c8b6e..9bef3bcd89 100644 --- a/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt +++ b/core/src/main/kotlin/com/r3corda/core/contracts/Structures.kt @@ -381,12 +381,11 @@ interface Attachment : NamedByHash { * @throws FileNotFoundException if the given path doesn't exist in the attachment. */ fun extractFile(path: String, outputTo: OutputStream) { - val p = path.toLowerCase() + val p = path.toLowerCase().split('\\','/') openAsJAR().use { jar -> while (true) { val e = jar.nextJarEntry ?: break - // TODO: Normalise path separators here for more platform independence, as zip doesn't mandate a type. - if (e.name.toLowerCase() == p) { + if (e.name.toLowerCase().split('\\','/') == p) { jar.copyTo(outputTo) return } diff --git a/core/src/main/kotlin/com/r3corda/core/node/AttachmentsClassLoader.kt b/core/src/main/kotlin/com/r3corda/core/node/AttachmentsClassLoader.kt index 1023be43b7..879cc1800d 100644 --- a/core/src/main/kotlin/com/r3corda/core/node/AttachmentsClassLoader.kt +++ b/core/src/main/kotlin/com/r3corda/core/node/AttachmentsClassLoader.kt @@ -37,11 +37,11 @@ class AttachmentsClassLoader(attachments: List, parent: ClassLoader // We already verified that paths are not strange/game playing when we inserted the attachment // into the storage service. So we don't need to repeat it here. // - // We forbid files that differ only in case to avoid issues for Windows/Mac developers where the + // We forbid files that differ only in case, or path separator to avoid issues for Windows/Mac developers where the // filesystem tries to be case insensitive. This may break developers who attempt to use ProGuard. // - // TODO: Do we need extra overlap checks? - val path = entry.name.toLowerCase() + // Also convert to Unix path separators as all resource/class lookups will expect this. + val path = entry.name.toLowerCase().replace('\\', '/') if (path in pathsToAttachments) throw OverlappingAttachments(path) pathsToAttachments[path] = attachment diff --git a/core/src/test/kotlin/com/r3corda/core/node/AttachmentClassLoaderTests.kt b/core/src/test/kotlin/com/r3corda/core/node/AttachmentClassLoaderTests.kt index 8bbfe83ebe..ec8999854c 100644 --- a/core/src/test/kotlin/com/r3corda/core/node/AttachmentClassLoaderTests.kt +++ b/core/src/test/kotlin/com/r3corda/core/node/AttachmentClassLoaderTests.kt @@ -9,6 +9,7 @@ import com.r3corda.core.serialization.* import com.r3corda.core.testing.DUMMY_NOTARY import com.r3corda.core.testing.MEGA_CORP import org.apache.commons.io.IOUtils +import org.junit.Assert import org.junit.Test import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream @@ -93,6 +94,14 @@ class AttachmentClassLoaderTests { return bs.toByteArray() } + fun readAttachment(attachment: Attachment, filepath: String) : ByteArray { + ByteArrayOutputStream().use { + attachment.extractFile(filepath, it) + return it.toByteArray() + } + + } + @Test fun `test MockAttachmentStorage open as jar`() { val storage = MockAttachmentStorage() @@ -130,6 +139,27 @@ class AttachmentClassLoaderTests { assertEquals("some data", txt) } + @Test + fun `Check platform independent path handling in attachment jars`() { + val storage = MockAttachmentStorage() + + val att1 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("/folder1/foldera/file1.txt", "some data"))) + val att2 = storage.importAttachment(ByteArrayInputStream(fakeAttachment("\\folder1\\folderb\\file2.txt", "some other data"))) + + val data1a = readAttachment(storage.openAttachment(att1)!!, "/folder1/foldera/file1.txt") + Assert.assertArrayEquals("some data".toByteArray(), data1a) + + val data1b = readAttachment(storage.openAttachment(att1)!!, "\\folder1\\foldera\\file1.txt") + Assert.assertArrayEquals("some data".toByteArray(), data1b) + + val data2a = readAttachment(storage.openAttachment(att2)!!, "\\folder1\\folderb\\file2.txt") + Assert.assertArrayEquals("some other data".toByteArray(), data2a) + + val data2b = readAttachment(storage.openAttachment(att2)!!, "/folder1/folderb/file2.txt") + Assert.assertArrayEquals("some other data".toByteArray(), data2b) + + } + @Test fun `loading class AnotherDummyContract`() { val storage = MockAttachmentStorage()