diff --git a/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java b/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java index 2fc7577b..9fd1581b 100644 --- a/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java +++ b/src/main/java/org/qortal/arbitrary/ArbitraryDataReader.java @@ -167,7 +167,7 @@ public class ArbitraryDataReader { private void createUncompressedDirectory() { try { - Files.createDirectories(this.uncompressedPath); + Files.createDirectories(this.uncompressedPath.getParent()); } catch (IOException e) { throw new IllegalStateException("Unable to create temp directory"); } @@ -366,9 +366,24 @@ public class ArbitraryDataReader { throw new IllegalStateException(String.format("Unable to unzip file: %s", e.getMessage())); } + // If unzipped data was a file not a directory, move it into a data/ directory so that the .qortal + // metadata folder is able to be created there too + if (this.uncompressedPath.toFile().isFile()) { + // Rename to temporary filename + Path tempDest = Paths.get(this.uncompressedPath.getParent().toString(), "data2"); + this.uncompressedPath.toFile().renameTo(tempDest.toFile()); + // Create a "data" directory + Files.createDirectories(this.uncompressedPath); + // Move the original file into the newly created directory + Path finalPath = Paths.get(this.uncompressedPath.toString(), "data"); + tempDest.toFile().renameTo(finalPath.toFile()); + } + // Replace filePath pointer with the uncompressed file path if (FilesystemUtils.pathInsideDataOrTempPath(this.filePath)) { - Files.delete(this.filePath); + if (Files.exists(this.filePath)) { + Files.delete(this.filePath); + } } this.filePath = this.uncompressedPath; } diff --git a/src/test/java/org/qortal/test/arbitrary/ArbitraryDataTests.java b/src/test/java/org/qortal/test/arbitrary/ArbitraryDataTests.java index bd6a5373..c1bc07b4 100644 --- a/src/test/java/org/qortal/test/arbitrary/ArbitraryDataTests.java +++ b/src/test/java/org/qortal/test/arbitrary/ArbitraryDataTests.java @@ -9,6 +9,7 @@ import org.qortal.arbitrary.ArbitraryDataReader; import org.qortal.arbitrary.ArbitraryDataTransactionBuilder; import org.qortal.arbitrary.exception.MissingDataException; import org.qortal.arbitrary.metadata.ArbitraryDataMetadataPatch; +import org.qortal.crypto.Crypto; import org.qortal.data.transaction.ArbitraryTransactionData; import org.qortal.data.transaction.ArbitraryTransactionData.*; import org.qortal.data.transaction.RegisterNameTransactionData; @@ -27,6 +28,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; +import java.util.Objects; import static org.junit.Assert.*; @@ -325,6 +327,43 @@ public class ArbitraryDataTests extends Common { } } + @Test + public void testSingleFile() throws DataException, IOException, MissingDataException { + try (final Repository repository = RepositoryManager.getRepository()) { + PrivateKeyAccount alice = Common.getTestAccount(repository, "alice"); + String publicKey58 = Base58.encode(alice.getPublicKey()); + String name = "TEST"; // Can be anything for this test + String identifier = "test1"; // Blank, not null + Service service = Service.DOCUMENT; // Can be anything for this test + + // Register the name to Alice + RegisterNameTransactionData transactionData = new RegisterNameTransactionData(TestTransaction.generateBase(alice), name, ""); + TransactionUtils.signAndMint(repository, transactionData, alice); + + // Create PUT transaction + Path path1 = Paths.get("src/test/resources/arbitrary/demo1/lorem1.txt"); + byte[] path1FileDigest = Crypto.digest(path1.toFile()); + ArbitraryDataDigest path1DirectoryDigest = new ArbitraryDataDigest(path1.getParent()); + path1DirectoryDigest.compute(); + this.createAndMintTxn(repository, publicKey58, path1, name, identifier, Method.PUT, service, alice); + + // Now build the latest data state for this name + ArbitraryDataReader arbitraryDataReader1 = new ArbitraryDataReader(name, ResourceIdType.NAME, service, identifier); + arbitraryDataReader1.loadSynchronously(true); + Path builtFilePath = Paths.get(arbitraryDataReader1.getFilePath().toString(), "data"); + byte[] builtFileDigest = Crypto.digest(builtFilePath.toFile()); + + // Compare it against the hash of the original file + assertArrayEquals(builtFileDigest, path1FileDigest); + + // The directory digest won't match because the file is renamed to "data" + // We may need to find a way to retain the filename + ArbitraryDataDigest builtDirectoryDigest = new ArbitraryDataDigest(arbitraryDataReader1.getFilePath()); + builtDirectoryDigest.compute(); + assertFalse(Objects.equals(path1DirectoryDigest.getHash58(), builtDirectoryDigest.getHash58())); + } + } + private void createAndMintTxn(Repository repository, String publicKey58, Path path, String name, String identifier, Method method, Service service, PrivateKeyAccount account) throws DataException {