Skip to content

Commit

Permalink
Fix synchronisation inclusion issues. Add support to compare hash and…
Browse files Browse the repository at this point in the history
… file size instead.
  • Loading branch information
dkocher committed Nov 30, 2010
1 parent a079f1c commit 6a4bdbc
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 36 deletions.
3 changes: 3 additions & 0 deletions source/ch/cyberduck/core/Preferences.java
Original file line number Diff line number Diff line change
Expand Up @@ -417,6 +417,9 @@ protected void setDefaults() {
defaults.put("queue.download.quarantine", String.valueOf(true));
defaults.put("queue.download.wherefrom", String.valueOf(true));

defaults.put("queue.sync.compare.hash", String.valueOf(true));
defaults.put("queue.sync.compare.size", String.valueOf(false));

defaults.put("queue.dock.badge", String.valueOf(false));

/**
Expand Down
137 changes: 104 additions & 33 deletions source/ch/cyberduck/core/SyncTransfer.java
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ public AttributedList<Path> children(final Path parent) {
children.addAll(_delegateUpload.children(parent));
}
for(Path child : children) {
this.setStatus(child);
if(child.getSession().isTimestampSupported()) {
if(child instanceof FTPPath) {
// Make sure we have a UTC timestamp
Expand All @@ -242,22 +241,34 @@ public AttributedList<Path> children(final Path parent) {
return new AttributedList<Path>(children);
}

private void setStatus(Path path) {
/**
* Set the skipped flag on the file attributes if no synchronisation is needed
* depending on the current action selection to mirror or only download or upload missing files.
*
* @param path
*/
@Override
public boolean isSkipped(Path path) {
boolean skipped = false;
final Comparison comparison = this.compare(path);
// Updating default skip settings for actual transfer
if(COMPARISON_EQUAL.equals(comparison)) {
skipped = true;
skipped = path.attributes().isFile();
}
else {
if(comparison.equals(COMPARISON_REMOTE_NEWER)) {
skipped = this.getAction().equals(ACTION_UPLOAD);
}
else if(comparison.equals(COMPARISON_LOCAL_NEWER)) {
skipped = this.getAction().equals(ACTION_DOWNLOAD);
if(path.attributes().isFile()) {
if(comparison.equals(COMPARISON_REMOTE_NEWER)) {
skipped = this.getAction().equals(ACTION_UPLOAD);
}
else if(comparison.equals(COMPARISON_LOCAL_NEWER)) {
skipped = this.getAction().equals(ACTION_DOWNLOAD);
}
}
}
path.status().setSkipped(skipped);
if(log.isDebugEnabled()) {
log.debug("isSkipped:" + skipped + "," + path);
}
return skipped;
}

/**
Expand Down Expand Up @@ -305,9 +316,6 @@ public Path lookup(PathReference reference) {
if(null == path) {
log.warn("Lookup failed for " + reference + " in cache");
}
else {
setStatus(path);
}
return path;
}
};
Expand Down Expand Up @@ -415,9 +423,31 @@ public String toString() {
* @return COMPARISON_REMOTE_NEWER, COMPARISON_LOCAL_NEWER or COMPARISON_EQUAL
*/
public Comparison compare(Path p) {
log.debug("compare:" + p);
if(log.isDebugEnabled()) {
log.debug("compare:" + p);
}
if(p.getLocal().exists() && p.exists()) {
return this.compareTimestamp(p);
if(Preferences.instance().getBoolean("queue.sync.compare.hash")) {
// MD5/ETag Checksum is supported
Comparison comparison = this.compareHash(p);
if(!COMPARISON_UNEQUAL.equals(comparison)) {
// Decision is available
return comparison;
}
}
if(Preferences.instance().getBoolean("queue.sync.compare.size")) {
Comparison comparison = this.compareSize(p);
if(!COMPARISON_UNEQUAL.equals(comparison)) {
// Decision is available
return comparison;
}
}
// Default comparison is using timestamp of file.
Comparison comparison = this.compareTimestamp(p);
if(!COMPARISON_UNEQUAL.equals(comparison)) {
// Decision is available
return comparison;
}
}
else if(p.exists()) {
// Only the remote file exists
Expand All @@ -435,39 +465,78 @@ else if(p.getLocal().exists()) {
* @return
*/
private Comparison compareSize(Path p) {
log.debug("compareSize:" + p);
if(p.attributes().getSize() == -1) {
p.readSize();
}
//fist make sure both files are larger than 0 bytes
if(p.attributes().getSize() == 0 && p.getLocal().attributes().getSize() == 0) {
return COMPARISON_EQUAL;
if(log.isDebugEnabled()) {
log.debug("compareSize:" + p);
}
if(p.attributes().getSize() == 0) {
return COMPARISON_LOCAL_NEWER;
}
if(p.getLocal().attributes().getSize() == 0) {
return COMPARISON_REMOTE_NEWER;
}
if(p.attributes().getSize() == p.getLocal().attributes().getSize()) {
return COMPARISON_EQUAL;
if(p.attributes().isFile()) {
if(p.attributes().getSize() == -1) {
p.readSize();
}
//fist make sure both files are larger than 0 bytes
if(p.attributes().getSize() == 0 && p.getLocal().attributes().getSize() == 0) {
return COMPARISON_EQUAL;
}
if(p.attributes().getSize() == 0) {
return COMPARISON_LOCAL_NEWER;
}
if(p.getLocal().attributes().getSize() == 0) {
return COMPARISON_REMOTE_NEWER;
}
if(p.attributes().getSize() == p.getLocal().attributes().getSize()) {
return COMPARISON_EQUAL;
}
}
//different file size - further comparison check
return COMPARISON_UNEQUAL;
}

/**
* Compare MD5 hash of files
*
* @param p
* @return
*/
private Comparison compareHash(Path p) {
if(log.isDebugEnabled()) {
log.debug("compareHash:" + p);
}
if(p.attributes().isFile()) {
if(null == p.attributes().getChecksum()) {
if(p.getSession().isChecksumSupported()) {
p.readChecksum();
}
}
if(null == p.attributes().getChecksum()) {
log.warn("No checksum available for comparison:" + p);
return COMPARISON_UNEQUAL;
}
//fist make sure both files are larger than 0 bytes
if(p.attributes().getChecksum().equals(p.getLocal().attributes().getChecksum())) {
return COMPARISON_EQUAL;
}
}
//different sum - further comparison check
return COMPARISON_UNEQUAL;
}

/**
* @param p
* @return
*/
private Comparison compareTimestamp(Path p) {
log.debug("compareTimestamp:" + p);
if(p.getSession().isTimestampSupported()) {
if(p.attributes().getModificationDate() == -1) {
if(log.isDebugEnabled()) {
log.debug("compareTimestamp:" + p);
}
if(-1 == p.attributes().getModificationDate()) {
if(p.getSession().isTimestampSupported()) {
// Make sure we have a UTC timestamp
p.readTimestamp();
}
}
if(-1 == p.attributes().getModificationDate()) {
log.warn("No modification date available for comparison:" + p);
return COMPARISON_UNEQUAL;
}
final Calendar remote = this.asCalendar(p.attributes().getModificationDate(), Calendar.SECOND);
final Calendar local = this.asCalendar(p.getLocal().attributes().getModificationDate(), Calendar.SECOND);
if(local.before(remote)) {
Expand All @@ -486,7 +555,9 @@ private Comparison compareTimestamp(Path p) {
* @return
*/
private Calendar asCalendar(final long timestamp, final int precision) {
log.debug("asCalendar:" + timestamp);
if(log.isDebugEnabled()) {
log.debug("asCalendar:" + timestamp);
}
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
c.setTimeInMillis(timestamp);
if(precision == Calendar.MILLISECOND) {
Expand Down
15 changes: 12 additions & 3 deletions source/ch/cyberduck/core/Transfer.java
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,16 @@ public Path lookup(PathReference r) {
* @return True if the path is not skipped when transferring
*/
public boolean isIncluded(Path item) {
return item.status().isSelected() && !item.status().isSkipped();
return item.status().isSelected() && !this.isSkipped(item);
}

/**
*
* @param item
* @return
*/
public boolean isSkipped(Path item) {
return false;
}

/**
Expand All @@ -401,7 +410,7 @@ public boolean isIncluded(Path item) {
* @return True if selectable
*/
public boolean isSelectable(Path item) {
return !item.status().isSkipped();
return !this.isSkipped(item);
}

/**
Expand Down Expand Up @@ -724,7 +733,7 @@ public int numberOfRoots() {
*/
public boolean isComplete() {
for(Path root : this.roots) {
if(root.status().isSkipped()) {
if(this.isSkipped(root)) {
continue;
}
if(!root.status().isComplete()) {
Expand Down

0 comments on commit 6a4bdbc

Please sign in to comment.