diff --git a/box/src/main/java/ch/cyberduck/core/box/BoxAttributesFinderFeature.java b/box/src/main/java/ch/cyberduck/core/box/BoxAttributesFinderFeature.java index 0176931f922..a011911031f 100644 --- a/box/src/main/java/ch/cyberduck/core/box/BoxAttributesFinderFeature.java +++ b/box/src/main/java/ch/cyberduck/core/box/BoxAttributesFinderFeature.java @@ -24,6 +24,7 @@ import ch.cyberduck.core.box.io.swagger.client.model.File; import ch.cyberduck.core.box.io.swagger.client.model.Folder; import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.features.AttributesAdapter; import ch.cyberduck.core.features.AttributesFinder; import ch.cyberduck.core.io.Checksum; @@ -75,7 +76,12 @@ public PathAttributes toAttributes(final File f) { attrs.setSize(f.getSize()); } attrs.setFileId(f.getId()); - attrs.setChecksum(new Checksum(HashAlgorithm.sha1, f.getSha1())); + try { + attrs.setChecksum(new Checksum(HashAlgorithm.sha1, f.getSha1())); + } + catch(UnsupportedException e) { + attrs.setChecksum(Checksum.NONE); + } attrs.setETag(f.getEtag()); return attrs; } diff --git a/core/src/main/java/ch/cyberduck/core/io/CRC32ChecksumCompute.java b/core/src/main/java/ch/cyberduck/core/io/CRC32ChecksumCompute.java index 3f68cab2d9b..4b914378630 100644 --- a/core/src/main/java/ch/cyberduck/core/io/CRC32ChecksumCompute.java +++ b/core/src/main/java/ch/cyberduck/core/io/CRC32ChecksumCompute.java @@ -17,6 +17,7 @@ import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.ChecksumException; +import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.transfer.TransferStatus; import org.apache.commons.io.IOUtils; @@ -35,6 +36,7 @@ public Checksum compute(final InputStream in, final TransferStatus status) throw byte[] buffer = new byte[16384]; int bytesRead; while((bytesRead = normalized.read(buffer, 0, buffer.length)) != -1) { + status.validate(); crc32.update(buffer, 0, bytesRead); } } @@ -44,6 +46,11 @@ public Checksum compute(final InputStream in, final TransferStatus status) throw finally { IOUtils.closeQuietly(normalized); } - return new Checksum(HashAlgorithm.crc32, String.format("%08x", crc32.getValue())); + try { + return new Checksum(HashAlgorithm.crc32, String.format("%08x", crc32.getValue())); + } + catch(UnsupportedException e) { + return Checksum.NONE; + } } } diff --git a/core/src/main/java/ch/cyberduck/core/io/Checksum.java b/core/src/main/java/ch/cyberduck/core/io/Checksum.java index fb53d418242..528630cef4f 100644 --- a/core/src/main/java/ch/cyberduck/core/io/Checksum.java +++ b/core/src/main/java/ch/cyberduck/core/io/Checksum.java @@ -18,6 +18,9 @@ * feedback@cyberduck.io */ +import ch.cyberduck.core.exception.UnsupportedException; + +import org.apache.commons.codec.DecoderException; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.binary.Hex; import org.apache.commons.lang3.StringUtils; @@ -42,11 +45,16 @@ public Checksum(final HashAlgorithm algorithm, final byte[] digest) { this.base64 = Base64.encodeBase64String(digest); } - public Checksum(final HashAlgorithm algorithm, final String hexString) { + public Checksum(final HashAlgorithm algorithm, final String hexString) throws UnsupportedException { this.algorithm = algorithm; this.hash = hexString; this.hex = hexString; - this.base64 = null; + try { + this.base64 = Base64.encodeBase64String(Hex.decodeHex(hexString)); + } + catch(DecoderException e) { + throw new UnsupportedException(e); + } } public Checksum(final HashAlgorithm algorithm, final String hexString, final String base64String) { @@ -65,41 +73,58 @@ public Checksum(final Checksum other) { @Override public String toString() { - return hash; + return hex; } public static Checksum parse(final String hash) { if(StringUtils.isBlank(hash)) { return Checksum.NONE; } - switch(hash.length()) { - case 8: - if(hash.matches("[a-fA-F0-9]{8}")) { - return new Checksum(HashAlgorithm.crc32, hash); - } - break; - case 32: - if(hash.matches("[a-fA-F0-9]{32}")) { - return new Checksum(HashAlgorithm.md5, hash); - } - break; - case 40: - if(hash.matches("[a-fA-F0-9]{40}")) { - return new Checksum(HashAlgorithm.sha1, hash); - } - break; - case 64: - if(hash.matches("[A-Fa-f0-9]{64}")) { - return new Checksum(HashAlgorithm.sha256, hash); - } - break; - case 128: - if(hash.matches("[A-Fa-f0-9]{128}")) { - return new Checksum(HashAlgorithm.sha512, hash); - } - break; - default: - log.warn("Failure to detect algorithm for checksum {}", hash); + // Check for Base64 with proper padding + if(hash.matches("^[A-Za-z0-9+/]+={0,2}$") && hash.length() % 4 == 0) { + final Checksum result = parseHex(Hex.encodeHexString(Base64.decodeBase64(hash))); + if(result != Checksum.NONE) { + return new Checksum(result.algorithm, result.hex, hash); + } + } + // Parse as hex string + return parseHex(hash); + } + + private static Checksum parseHex(final String hexString) { + try { + switch(hexString.length()) { + case 8: + if(hexString.matches("[a-fA-F0-9]{8}")) { + return new Checksum(HashAlgorithm.crc32, hexString); + } + break; + case 32: + if(hexString.matches("[a-fA-F0-9]{32}")) { + return new Checksum(HashAlgorithm.md5, hexString); + } + break; + case 40: + if(hexString.matches("[a-fA-F0-9]{40}")) { + return new Checksum(HashAlgorithm.sha1, hexString); + } + break; + case 64: + if(hexString.matches("[A-Fa-f0-9]{64}")) { + return new Checksum(HashAlgorithm.sha256, hexString); + } + break; + case 128: + if(hexString.matches("[A-Fa-f0-9]{128}")) { + return new Checksum(HashAlgorithm.sha512, hexString); + } + break; + default: + log.warn("Failure to detect algorithm for checksum {}", hexString); + } + } + catch(UnsupportedException e) { + return Checksum.NONE; } return Checksum.NONE; } @@ -116,7 +141,7 @@ public boolean equals(final Object o) { if(algorithm != checksum.algorithm) { return false; } - if(!StringUtils.equalsIgnoreCase(hash, checksum.hash)) { + if(!StringUtils.equalsIgnoreCase(hex, checksum.hex)) { return false; } return true; @@ -125,7 +150,7 @@ public boolean equals(final Object o) { @Override public int hashCode() { int result = algorithm != null ? algorithm.hashCode() : 0; - result = 31 * result + (hash != null ? hash.hashCode() : 0); + result = 31 * result + (hex != null ? hex.hashCode() : 0); return result; } diff --git a/core/src/main/java/ch/cyberduck/core/io/MD5FastChecksumCompute.java b/core/src/main/java/ch/cyberduck/core/io/MD5FastChecksumCompute.java index b6ad041a28f..d6026606a64 100644 --- a/core/src/main/java/ch/cyberduck/core/io/MD5FastChecksumCompute.java +++ b/core/src/main/java/ch/cyberduck/core/io/MD5FastChecksumCompute.java @@ -18,6 +18,7 @@ import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.ChecksumCanceledException; import ch.cyberduck.core.exception.ChecksumException; +import ch.cyberduck.core.exception.ConnectionCanceledException; import ch.cyberduck.core.transfer.TransferStatus; import org.apache.commons.io.IOUtils; @@ -41,12 +42,13 @@ public Checksum compute(final InputStream in, final TransferStatus status) throw this.normalize(in, status), status)); } - protected byte[] digest(final String algorithm, final InputStream in, final StreamCancelation cancelation) throws ChecksumException, ChecksumCanceledException { + protected byte[] digest(final String algorithm, final InputStream in, final StreamCancelation cancelation) throws ChecksumException, ConnectionCanceledException { final MD5 md = new MD5(); try { byte[] buffer = new byte[16384]; int bytesRead; while((bytesRead = in.read(buffer, 0, buffer.length)) != -1) { + cancelation.validate(); md.Update(buffer, 0, bytesRead); } } diff --git a/core/src/test/java/ch/cyberduck/core/PathAttributesTest.java b/core/src/test/java/ch/cyberduck/core/PathAttributesTest.java index d6c8215cada..d095aa004e7 100644 --- a/core/src/test/java/ch/cyberduck/core/PathAttributesTest.java +++ b/core/src/test/java/ch/cyberduck/core/PathAttributesTest.java @@ -77,7 +77,7 @@ public void testSerialize() { acl.addAll(new Acl.CanonicalUser("user1"), new Acl.Role(Acl.Role.READ), new Acl.Role(Acl.Role.WRITE)); acl.addAll(new Acl.CanonicalUser("user2"), new Acl.Role(Acl.Role.FULL)); attributes.setAcl(acl); - attributes.setChecksum(new Checksum(HashAlgorithm.crc32, "abcdefab")); + attributes.setChecksum(new Checksum(HashAlgorithm.crc32, "abcdefab", null)); attributes.setVersionId("v-1"); attributes.setFileId("f-1"); attributes.setDisplayname("d-1"); diff --git a/core/src/test/java/ch/cyberduck/core/io/ChecksumTest.java b/core/src/test/java/ch/cyberduck/core/io/ChecksumTest.java index 05dc16f3943..ff87f696303 100644 --- a/core/src/test/java/ch/cyberduck/core/io/ChecksumTest.java +++ b/core/src/test/java/ch/cyberduck/core/io/ChecksumTest.java @@ -25,7 +25,7 @@ public class ChecksumTest { @Test - public void testParse() { + public void testParse() throws Exception { assertEquals(new Checksum(HashAlgorithm.md5, "d41d8cd98f00b204e9800998ecf8427e"), Checksum.parse("d41d8cd98f00b204e9800998ecf8427e")); assertEquals(new Checksum(HashAlgorithm.sha1, "da39a3ee5e6b4b0d3255bfef95601890afd80709"), diff --git a/core/src/test/java/ch/cyberduck/core/synchronization/ChecksumComparisonServiceTest.java b/core/src/test/java/ch/cyberduck/core/synchronization/ChecksumComparisonServiceTest.java index b5b2749c6c1..78ca2e14201 100644 --- a/core/src/test/java/ch/cyberduck/core/synchronization/ChecksumComparisonServiceTest.java +++ b/core/src/test/java/ch/cyberduck/core/synchronization/ChecksumComparisonServiceTest.java @@ -12,22 +12,22 @@ public class ChecksumComparisonServiceTest { @Test - public void testCompare() { + public void testCompare() throws Exception { ComparisonService s = new ChecksumComparisonService(); assertEquals(Comparison.equal, s.compare(Path.Type.file, new PathAttributes() { @Override public Checksum getChecksum() { - return new Checksum(HashAlgorithm.md5, "a"); + return new Checksum(HashAlgorithm.md5, "a", null); } - }, new PathAttributes().setChecksum(new Checksum(HashAlgorithm.md5, "a")) + }, new PathAttributes().setChecksum(new Checksum(HashAlgorithm.md5, "a", null)) )); assertEquals(Comparison.notequal, s.compare(Path.Type.file, new PathAttributes() { @Override public Checksum getChecksum() { - return new Checksum(HashAlgorithm.md5, "b"); + return new Checksum(HashAlgorithm.md5, "b", null); } - }, new PathAttributes().setChecksum(new Checksum(HashAlgorithm.md5, "a")))); + }, new PathAttributes().setChecksum(new Checksum(HashAlgorithm.md5, "a", null)))); } @Test diff --git a/core/src/test/java/ch/cyberduck/core/synchronization/DefaultComparePathFilterTest.java b/core/src/test/java/ch/cyberduck/core/synchronization/DefaultComparePathFilterTest.java index 5edaaaedd56..5fa9a12e91c 100644 --- a/core/src/test/java/ch/cyberduck/core/synchronization/DefaultComparePathFilterTest.java +++ b/core/src/test/java/ch/cyberduck/core/synchronization/DefaultComparePathFilterTest.java @@ -39,7 +39,7 @@ public PathAttributes find(final Path file, final ListProgressListener listener) return new PathAttributes() { @Override public Checksum getChecksum() { - return new Checksum(HashAlgorithm.md5, "a"); + return new Checksum(HashAlgorithm.md5, "a", null); } }; } @@ -54,7 +54,7 @@ public boolean find(final Path file, final ListProgressListener listener) { ComparePathFilter s = new DefaultComparePathFilter(new NullSession(new Host(new TestProtocol())), find, attributes) { @Override protected Checksum checksum(final HashAlgorithm algorithm, final Local local) { - return new Checksum(HashAlgorithm.md5, "a"); + return new Checksum(HashAlgorithm.md5, "a", null); } }; final String path = new AlphanumericRandomStringService().random(); @@ -166,7 +166,7 @@ public PathAttributes find(final Path file, final ListProgressListener listener) return new PathAttributes() { @Override public Checksum getChecksum() { - return new Checksum(HashAlgorithm.md5, "b"); + return new Checksum(HashAlgorithm.md5, "b", null); } @Override @@ -189,7 +189,7 @@ public long getModificationDate() { ComparePathFilter s = new DefaultComparePathFilter(new NullSession(new Host(new TestProtocol())), find, attributes) { @Override protected Checksum checksum(final HashAlgorithm algorithm, final Local local) { - return new Checksum(HashAlgorithm.md5, "a"); + return new Checksum(HashAlgorithm.md5, "a", null); } }; assertEquals(Comparison.local, s.compare(new Path("t", EnumSet.of(Path.Type.file)), new NullLocal("t") { diff --git a/dropbox/src/main/java/ch/cyberduck/core/dropbox/DropboxAttributesFinderFeature.java b/dropbox/src/main/java/ch/cyberduck/core/dropbox/DropboxAttributesFinderFeature.java index 7eb465883a1..d0a0b375c64 100644 --- a/dropbox/src/main/java/ch/cyberduck/core/dropbox/DropboxAttributesFinderFeature.java +++ b/dropbox/src/main/java/ch/cyberduck/core/dropbox/DropboxAttributesFinderFeature.java @@ -21,6 +21,7 @@ import ch.cyberduck.core.PathContainerService; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.NotfoundException; +import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.features.AttributesAdapter; import ch.cyberduck.core.features.AttributesFinder; import ch.cyberduck.core.io.Checksum; @@ -86,7 +87,12 @@ public PathAttributes toAttributes(final Metadata metadata) { if(file.getFileLockInfo() != null) { attributes.setLockId(String.valueOf(file.getFileLockInfo().getIsLockholder())); } - attributes.setChecksum(new Checksum(HashAlgorithm.dropbox_content_hash, file.getContentHash())); + try { + attributes.setChecksum(new Checksum(HashAlgorithm.dropbox_content_hash, file.getContentHash())); + } + catch(UnsupportedException e) { + attributes.setChecksum(Checksum.NONE); + } attributes.setVersionId(file.getRev()); } if(metadata instanceof FolderMetadata) { diff --git a/eue/src/main/java/ch/cyberduck/core/eue/ChunkListSHA256ChecksumCompute.java b/eue/src/main/java/ch/cyberduck/core/eue/ChunkListSHA256ChecksumCompute.java index 09b247538ec..37f845fe610 100644 --- a/eue/src/main/java/ch/cyberduck/core/eue/ChunkListSHA256ChecksumCompute.java +++ b/eue/src/main/java/ch/cyberduck/core/eue/ChunkListSHA256ChecksumCompute.java @@ -20,6 +20,7 @@ import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.ChecksumException; +import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.io.AbstractChecksumCompute; import ch.cyberduck.core.io.Checksum; import ch.cyberduck.core.io.HashAlgorithm; @@ -59,6 +60,11 @@ public Checksum compute(final Number length, final byte[] contentDigest) throws } digest.update(contentDigest); digest.update(intToBytes(length.intValue())); - return new Checksum(HashAlgorithm.cdash64, Base64.encodeBase64URLSafeString(digest.digest())); + try { + return new Checksum(HashAlgorithm.cdash64, Base64.encodeBase64URLSafeString(digest.digest())); + } + catch(UnsupportedException e) { + return Checksum.NONE; + } } } diff --git a/importer/src/main/java/ch/cyberduck/core/importer/ThirdpartyBookmarkCollection.java b/importer/src/main/java/ch/cyberduck/core/importer/ThirdpartyBookmarkCollection.java index dc11c453c6a..d8400e2be71 100644 --- a/importer/src/main/java/ch/cyberduck/core/importer/ThirdpartyBookmarkCollection.java +++ b/importer/src/main/java/ch/cyberduck/core/importer/ThirdpartyBookmarkCollection.java @@ -30,6 +30,7 @@ import ch.cyberduck.core.exception.AccessDeniedException; import ch.cyberduck.core.exception.BackgroundException; import ch.cyberduck.core.exception.LocalAccessDeniedException; +import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.io.Checksum; import ch.cyberduck.core.io.ChecksumComputeFactory; import ch.cyberduck.core.io.HashAlgorithm; @@ -75,10 +76,10 @@ public void load() throws AccessDeniedException { } if(preferences.getBoolean(this.getConfiguration())) { // Previously imported - final Checksum previous = new Checksum(HashAlgorithm.md5, - preferences.getProperty(String.format("%s.checksum", this.getConfiguration()))); - log.debug("Saved previous checksum {} for bookmark {}", previous, file); - if(StringUtils.isNotBlank(previous.hash)) { + try { + final Checksum previous = new Checksum(HashAlgorithm.md5, + preferences.getProperty(String.format("%s.checksum", this.getConfiguration()))); + log.debug("Saved previous checksum {} for bookmark {}", previous, file); if(previous.equals(current)) { log.info("Skip importing bookmarks from {} with previously saved checksum {}", file, previous); } @@ -87,8 +88,7 @@ public void load() throws AccessDeniedException { // Should filter existing bookmarks. Skip import } } - else { - // Skip flagged + catch(UnsupportedException e) { log.debug("Skip importing bookmarks from {}", file); } } @@ -155,7 +155,7 @@ public boolean add(final Host bookmark) { if(credentials.isPublicKeyAuthentication()) { try { keychain.addPassword(bookmark.getHostname(), credentials.getIdentity().getAbbreviatedPath(), - credentials.getPassword()); + credentials.getPassword()); } catch(LocalAccessDeniedException e) { log.error("Failure {} saving credentials for {} in password store", e, bookmark); @@ -164,7 +164,7 @@ public boolean add(final Host bookmark) { else if(!credentials.isAnonymousLogin()) { try { keychain.addPassword(bookmark.getProtocol().getScheme(), bookmark.getPort(), - bookmark.getHostname(), credentials.getUsername(), credentials.getPassword()); + bookmark.getHostname(), credentials.getUsername(), credentials.getPassword()); } catch(LocalAccessDeniedException e) { log.error("Failure {} saving credentials for {} in password store", e, bookmark); diff --git a/nextcloud/src/main/java/ch/cyberduck/core/nextcloud/NextcloudAttributesFinderFeature.java b/nextcloud/src/main/java/ch/cyberduck/core/nextcloud/NextcloudAttributesFinderFeature.java index f5161d7602c..517392fc22f 100644 --- a/nextcloud/src/main/java/ch/cyberduck/core/nextcloud/NextcloudAttributesFinderFeature.java +++ b/nextcloud/src/main/java/ch/cyberduck/core/nextcloud/NextcloudAttributesFinderFeature.java @@ -23,6 +23,7 @@ import ch.cyberduck.core.dav.DAVSession; import ch.cyberduck.core.dav.DAVTimestampFeature; import ch.cyberduck.core.exception.BackgroundException; +import ch.cyberduck.core.exception.UnsupportedException; import ch.cyberduck.core.io.Checksum; import ch.cyberduck.core.io.HashAlgorithm; @@ -129,7 +130,7 @@ public PathAttributes toAttributes(final DavResource resource) { attributes.setChecksum(new Checksum(HashAlgorithm.valueOf(StringUtils.lowerCase(StringUtils.split(v, ":")[0])), StringUtils.lowerCase(StringUtils.split(v, ":")[1]))); } - catch(IllegalArgumentException e) { + catch(IllegalArgumentException | UnsupportedException e) { log.warn("Unsupported checksum {}", v); } } diff --git a/onedrive/pom.xml b/onedrive/pom.xml index 4051c543c54..dd08b4d3f1c 100644 --- a/onedrive/pom.xml +++ b/onedrive/pom.xml @@ -23,7 +23,7 @@ onedrive - 3.2.3 + 3.2.4 diff --git a/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphItemListService.java b/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphItemListService.java index 469a2242668..998b8d3ace7 100644 --- a/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphItemListService.java +++ b/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphItemListService.java @@ -44,6 +44,6 @@ protected Iterator getIterator(final Path directory) throws log.debug("Return files for folder {}", folder); // getQuery(null): return new ODataQuery with default set of parameters // require listing Publication/VersionId - return Files.getFiles(folder, session.getQuery(null).top(HostPreferencesFactory.get(session.getHost()).getInteger("onedrive.listing.chunksize"))); + return Files.getFiles(folder, session.select(null).top(HostPreferencesFactory.get(session.getHost()).getInteger("onedrive.listing.chunksize"))); } } diff --git a/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphProtocol.java b/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphProtocol.java index fe281f6fbd6..179389ea051 100644 --- a/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphProtocol.java +++ b/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphProtocol.java @@ -18,8 +18,14 @@ import ch.cyberduck.core.AbstractProtocol; import ch.cyberduck.core.LocaleFactory; import ch.cyberduck.core.Scheme; +import ch.cyberduck.core.synchronization.ChainedComparisonService; +import ch.cyberduck.core.synchronization.ChecksumComparisonService; +import ch.cyberduck.core.synchronization.Comparison; import ch.cyberduck.core.synchronization.ComparisonService; import ch.cyberduck.core.synchronization.DefaultComparisonService; +import ch.cyberduck.core.synchronization.TimestampComparisonService; + +import java.util.EnumSet; public abstract class GraphProtocol extends AbstractProtocol { @Override @@ -72,7 +78,10 @@ public VersioningMode getVersioningMode() { @SuppressWarnings("unchecked") public T getFeature(final Class type) { if(type == ComparisonService.class) { - return (T) new DefaultComparisonService(DefaultComparisonService.forFiles(this), ComparisonService.disabled); + return (T) new DefaultComparisonService(new ChainedComparisonService(EnumSet.of(Comparison.unknown, Comparison.notequal), + new ChecksumComparisonService(), + new TimestampComparisonService() + ), ComparisonService.disabled); } return super.getFeature(type); } diff --git a/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphSession.java b/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphSession.java index 88597b3435e..d884c5173e1 100644 --- a/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphSession.java +++ b/onedrive/src/main/java/ch/cyberduck/core/onedrive/GraphSession.java @@ -80,7 +80,7 @@ protected GraphSession(final Host host, final X509TrustManager trust, final X509 public abstract String getFileId(final DriveItem.Metadata metadata); - public ODataQuery getQuery(ODataQuery query) { + public ODataQuery select(ODataQuery query) { if(query == null) { query = new ODataQuery(); } @@ -110,8 +110,8 @@ public DriveItem getItem(final Path currentPath) throws BackgroundException { return this.getItem(currentPath, true); } - public DriveItem.Metadata getMetadata(final DriveItem item, ODataQuery query) throws IOException { - return item.getMetadata(getQuery(query)); + public DriveItem.Metadata getMetadata(final DriveItem item, final ODataQuery query) throws IOException { + return item.getMetadata(this.select(query)); } public abstract DriveItem getItem(final Path file, final boolean resolveLastItem) throws BackgroundException; diff --git a/onedrive/src/main/java/ch/cyberduck/core/onedrive/features/GraphAttributesFinderFeature.java b/onedrive/src/main/java/ch/cyberduck/core/onedrive/features/GraphAttributesFinderFeature.java index d3737e37896..856b3f949e8 100644 --- a/onedrive/src/main/java/ch/cyberduck/core/onedrive/features/GraphAttributesFinderFeature.java +++ b/onedrive/src/main/java/ch/cyberduck/core/onedrive/features/GraphAttributesFinderFeature.java @@ -24,6 +24,7 @@ import ch.cyberduck.core.exception.NotfoundException; import ch.cyberduck.core.features.AttributesAdapter; import ch.cyberduck.core.features.AttributesFinder; +import ch.cyberduck.core.io.Checksum; import ch.cyberduck.core.onedrive.GraphExceptionMappingService; import ch.cyberduck.core.onedrive.GraphSession; import ch.cyberduck.core.webloc.UrlFileWriterFactory; @@ -32,7 +33,9 @@ import org.nuxeo.onedrive.client.OneDriveAPIException; import org.nuxeo.onedrive.client.types.DriveItem; import org.nuxeo.onedrive.client.types.DriveItemVersion; +import org.nuxeo.onedrive.client.types.File; import org.nuxeo.onedrive.client.types.FileSystemInfo; +import org.nuxeo.onedrive.client.types.Hashes; import org.nuxeo.onedrive.client.types.Publication; import java.io.IOException; @@ -89,6 +92,13 @@ private DriveItem.Metadata toMetadata(final Path file, final DriveItem item) thr public PathAttributes toAttributes(final DriveItem.Metadata metadata) { final PathAttributes attributes = new PathAttributes(); attributes.setETag(metadata.getETag()); + final File file = metadata.getFile(); + if(file != null) { + final Hashes hashes = file.getHashes(); + if(hashes != null) { + attributes.setChecksum(Checksum.parse(hashes.getQuickXorHash())); + } + } Optional webUrl = getWebUrl(metadata); if(metadata.isPackage()) { webUrl.ifPresent(url -> attributes.setSize(UrlFileWriterFactory.get().write(url).getBytes(Charset.defaultCharset()).length)); diff --git a/onedrive/src/test/java/ch/cyberduck/core/onedrive/GraphAttributesFinderFeatureTest.java b/onedrive/src/test/java/ch/cyberduck/core/onedrive/GraphAttributesFinderFeatureTest.java index bbbd4887f3d..8a7018a3699 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/onedrive/GraphAttributesFinderFeatureTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/onedrive/GraphAttributesFinderFeatureTest.java @@ -22,6 +22,7 @@ import ch.cyberduck.core.exception.NotfoundException; import ch.cyberduck.core.features.Delete; import ch.cyberduck.core.features.Home; +import ch.cyberduck.core.io.Checksum; import ch.cyberduck.core.onedrive.features.GraphAttributesFinderFeature; import ch.cyberduck.core.onedrive.features.GraphDeleteFeature; import ch.cyberduck.core.onedrive.features.GraphDirectoryFeature; @@ -63,6 +64,7 @@ public void testFindFile() throws Exception { assertNotEquals(-1L, attributes.getCreationDate()); assertNotEquals(-1L, attributes.getModificationDate()); assertNotNull(attributes.getETag()); + assertNotEquals(Checksum.NONE, attributes.getChecksum()); assertNull(attributes.getVersionId()); assertNotNull(attributes.getLink()); assertNotNull(attributes.getFileId()); @@ -79,6 +81,8 @@ public void testFindDirectory() throws Exception { assertNotEquals(-1L, attributes.getCreationDate()); assertNotEquals(-1L, attributes.getModificationDate()); assertNotNull(attributes.getETag()); + assertNotNull(attributes.getChecksum()); + assertEquals(Checksum.NONE, attributes.getChecksum()); assertNull(attributes.getVersionId()); assertNotNull(attributes.getLink()); assertNotNull(attributes.getFileId()); diff --git a/onedrive/src/test/java/ch/cyberduck/core/onedrive/GraphMoveFeatureTest.java b/onedrive/src/test/java/ch/cyberduck/core/onedrive/GraphMoveFeatureTest.java index a5646f39d33..bcde51b38f0 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/onedrive/GraphMoveFeatureTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/onedrive/GraphMoveFeatureTest.java @@ -84,6 +84,7 @@ public void testRename() throws BackgroundException { assertEquals(attributes, target.attributes()); assertEquals(attributes.getFileId(), target.attributes().getFileId()); assertNotEquals(attributes.getETag(), attributesFinder.find(rename).getETag()); + assertEquals(attributes.getChecksum(), attributesFinder.find(rename).getChecksum()); assertEquals(target.attributes().getETag(), attributesFinder.find(rename).getETag()); delete.delete(Collections.singletonList(rename), new DisabledLoginCallback(), new Delete.DisabledCallback()); } @@ -103,14 +104,17 @@ public void testMove() throws BackgroundException { Path touchedFile = new Path(drive, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); touch.touch(touchedFile, new TransferStatus().setMime("x-application/cyberduck")); final PathAttributes attributes = attributesFinder.find(touchedFile); - + assertEquals("AAAAAAAAAAAAAAAAAAAAAAAAAAA=", attributes.getChecksum().base64); + assertEquals("0000000000000000000000000000000000000000", attributes.getChecksum().hex); Path rename = new Path(targetDirectory, touchedFile.getName(), EnumSet.of(Path.Type.file)); assertTrue(move.isSupported(touchedFile, Optional.of(rename))); final Path target = move.move(touchedFile, rename, new TransferStatus(), new Delete.DisabledCallback(), new DisabledConnectionCallback()); final PathAttributes renamedAttributes = attributesFinder.find(rename); assertNotNull(renamedAttributes); assertEquals(attributes, renamedAttributes); + assertEquals(attributes.getFileId(), renamedAttributes.getFileId()); assertNotEquals(attributes.getETag(), renamedAttributes.getETag()); + assertEquals(attributes.getChecksum(), attributesFinder.find(rename).getChecksum()); assertEquals(target.attributes().getETag(), renamedAttributes.getETag()); delete.delete(Collections.singletonList(targetDirectory), new DisabledLoginCallback(), new Delete.DisabledCallback()); diff --git a/onedrive/src/test/java/ch/cyberduck/core/onedrive/OneDriveWriteFeatureTest.java b/onedrive/src/test/java/ch/cyberduck/core/onedrive/OneDriveWriteFeatureTest.java index 61cc5f6c15d..576b2ace045 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/onedrive/OneDriveWriteFeatureTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/onedrive/OneDriveWriteFeatureTest.java @@ -62,13 +62,13 @@ public void testWrite() throws Exception { final PathAttributes folderAttributes = new GraphAttributesFinderFeature(session, fileid).find(folder); final String folderEtag = folderAttributes.getETag(); final long folderTimestamp = folderAttributes.getModificationDate(); - final byte[] content = RandomUtils.nextBytes(5 * 1024 * 1024); + final byte[] sourceContent = RandomUtils.nextBytes(5 * 1024 * 1024); final TransferStatus status = new TransferStatus(); - status.setLength(content.length); + status.setLength(sourceContent.length); final Path file = new Path(folder, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file)); final String id = new GraphTouchFeature(session, fileid).touch(file, new TransferStatus()).attributes().getFileId(); final StatusOutputStream out = feature.write(file, status, new DisabledConnectionCallback()); - new StreamCopier(status, status).transfer(new ByteArrayInputStream(content), out); + new StreamCopier(status, status).transfer(new ByteArrayInputStream(sourceContent), out); assertNotNull(out.getStatus()); assertTrue(status.isComplete()); assertNotSame(PathAttributes.EMPTY, status.getResponse()); @@ -76,20 +76,27 @@ public void testWrite() throws Exception { assertEquals(folderEtag, new GraphAttributesFinderFeature(session, fileid).find(folder).getETag()); assertEquals(folderTimestamp, new GraphAttributesFinderFeature(session, fileid).find(folder).getModificationDate()); assertTrue(new DefaultFindFeature(session).find(file)); - final byte[] compare = new byte[content.length]; - final InputStream stream = new GraphReadFeature(session, fileid).read(file, new TransferStatus().setLength(content.length), new DisabledConnectionCallback()); + final byte[] compare = new byte[sourceContent.length]; + final InputStream stream = new GraphReadFeature(session, fileid).read(file, new TransferStatus().setLength(sourceContent.length), new DisabledConnectionCallback()); IOUtils.readFully(stream, compare); stream.close(); - assertArrayEquals(content, compare); + assertArrayEquals(sourceContent, compare); final Path copy = new Path(file); copy.attributes().setCustom(Collections.emptyMap()); assertEquals(id, fileid.getFileId(copy)); // Overwrite final StatusOutputStream overwrite = feature.write(file, status.setExists(true), new DisabledConnectionCallback()); assertNotNull(overwrite); - assertEquals(content.length, IOUtils.copyLarge(new ByteArrayInputStream(content), overwrite)); + final byte[] overwriteContent = RandomUtils.nextBytes(5 * 1024 * 1024); + assertEquals(overwriteContent.length, IOUtils.copyLarge(new ByteArrayInputStream(overwriteContent), overwrite)); overwrite.close(); - assertEquals(new GraphAttributesFinderFeature(session, fileid).toAttributes(overwrite.getStatus()), new GraphAttributesFinderFeature(session, fileid).find(file)); + final PathAttributes overwriteAttr = new GraphAttributesFinderFeature(session, fileid).toAttributes(overwrite.getStatus()); + assertEquals(overwriteAttr, new GraphAttributesFinderFeature(session, fileid).find(file)); + final PathAttributes sourceAttr = new GraphAttributesFinderFeature(session, fileid).toAttributes(out.getStatus()); + assertNotEquals(sourceAttr, overwriteAttr); + assertEquals(sourceAttr.getFileId(), overwriteAttr.getFileId()); + assertNotEquals(sourceAttr.getETag(), overwriteAttr.getETag()); + assertNotEquals(sourceAttr.getChecksum(), overwriteAttr.getChecksum()); new GraphDeleteFeature(session, fileid).delete(Collections.singletonList(file), new DisabledLoginCallback(), new Delete.DisabledCallback()); } diff --git a/onedrive/src/test/java/ch/cyberduck/core/onedrive/SharepointWriteFeatureTest.java b/onedrive/src/test/java/ch/cyberduck/core/onedrive/SharepointWriteFeatureTest.java index 429f61a3f6c..6d3473866e4 100644 --- a/onedrive/src/test/java/ch/cyberduck/core/onedrive/SharepointWriteFeatureTest.java +++ b/onedrive/src/test/java/ch/cyberduck/core/onedrive/SharepointWriteFeatureTest.java @@ -92,6 +92,9 @@ public void testWrite() throws Exception { assertEquals(content.length, IOUtils.copyLarge(new ByteArrayInputStream(content), overwrite)); overwrite.close(); assertEquals(new GraphAttributesFinderFeature(session, fileid).toAttributes(overwrite.getStatus()), new GraphAttributesFinderFeature(session, fileid).find(file)); + assertNotEquals(new GraphAttributesFinderFeature(session, fileid).toAttributes(out.getStatus()), new GraphAttributesFinderFeature(session, fileid).toAttributes(overwrite.getStatus())); + assertEquals(new GraphAttributesFinderFeature(session, fileid).toAttributes(out.getStatus()).getFileId(), new GraphAttributesFinderFeature(session, fileid).toAttributes(overwrite.getStatus()).getFileId()); + assertNotEquals(new GraphAttributesFinderFeature(session, fileid).toAttributes(out.getStatus()).getETag(), new GraphAttributesFinderFeature(session, fileid).toAttributes(overwrite.getStatus()).getETag()); new GraphDeleteFeature(session, fileid).delete(Collections.singletonList(file), new DisabledLoginCallback(), new Delete.DisabledCallback()); } }