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());
}
}