// Check files on server against local client files.
Iterator<Map.Entry<String, StorageObject>> objectsMapIter = objectsMap.entrySet().iterator();
while (objectsMapIter.hasNext()) {
Map.Entry<String, StorageObject> entry = objectsMapIter.next();
String keyPath = entry.getKey();
StorageObject storageObject = entry.getValue();
String[] splitPathComponents = splitFilePathIntoDirPaths(
keyPath, storageObject.isDirectoryPlaceholder());
int componentCount = 0;
for (String localPath: splitPathComponents) {
componentCount += 1;
String filepath = objectKeyToFilepathMap.get(localPath);
// Check whether local file is already on server
if (filepath != null) {
// File has been backed up in the past, is it still up-to-date?
File file = new File(filepath);
// We don't care about directory date changes, as long as it's present.
if (file.isDirectory()) {
// Only flag key path as already synced if the current localPath
// is also equivalent to the *full* path of the object in the storage
// service, not just an object's parent directory. (Issue #69)
if (componentCount == splitPathComponents.length) {
alreadySynchronisedKeys.add(keyPath);
alreadySynchronisedLocalPaths.add(localPath);
boolean wasRemoved = onlyOnClientKeys.remove(keyPath);
// Backwards-compatibility with JetS3t directory place-holders
// without trailing slash (/) suffixes
if (!wasRemoved && !keyPath.endsWith("/")
&& storageObject.isDirectoryPlaceholder())
{
onlyOnClientKeys.remove(keyPath + "/");
}
}
}
// If upload is forced, don't bother comparing object MD5 hashes
else if (isForceUpload) {
// Treat file as if it's already synchronized with the service, whether
// it is or not doesn't really matter since we're uploading it regardless
alreadySynchronisedKeys.add(keyPath);
alreadySynchronisedLocalPaths.add(localPath);
onlyOnClientKeys.remove(keyPath);
}
// Compare file hashes.
else {
String fileHashAsBase64 = ServiceUtils.toBase64(
generateFileMD5Hash(file, storageObject.getKey(), progressWatcher));
// Get the service object's Base64 hash.
String objectHash = null;
if (storageObject.containsMetadata(StorageObject.METADATA_HEADER_ORIGINAL_HASH_MD5)) {
// Use the object's *original* hash, as it is an encoded version of a local file.
objectHash = (String) storageObject.getMetadata(
StorageObject.METADATA_HEADER_ORIGINAL_HASH_MD5);
if (log.isDebugEnabled()) {
log.debug("Object in service is encoded, using the object's original hash value for: "
+ storageObject.getKey());
}
} else {
// The object wasn't altered when uploaded, so use its current hash.
objectHash = storageObject.getMd5HashAsBase64();
}
if (fileHashAsBase64.equals(objectHash)) {
// Hashes match so file is already synchronised.
alreadySynchronisedKeys.add(keyPath);
alreadySynchronisedLocalPaths.add(localPath);
onlyOnClientKeys.remove(keyPath);
} else {
// File is out-of-synch. Check which version has the latest date.
Date objectLastModified = null;
String metadataLocalFileDate = (String) storageObject.getMetadata(
Constants.METADATA_JETS3T_LOCAL_FILE_DATE);
if (metadataLocalFileDate == null) {
// This is risky as local file times and service times don't match!
if (!isAssumeLocalLatestInMismatch() && log.isWarnEnabled()) {
log.warn("Using service last modified date as file date. This is not reliable "
+ "as the time according to service can differ from your local system time. "
+ "Please use the metadata item "
+ Constants.METADATA_JETS3T_LOCAL_FILE_DATE);
}
objectLastModified = storageObject.getLastModifiedDate();
} else {
objectLastModified = ServiceUtils
.parseIso8601Date(metadataLocalFileDate);
}
if (objectLastModified.getTime() > file.lastModified()) {
updatedOnServerKeys.add(keyPath);
onlyOnClientKeys.remove(keyPath);
} else if (objectLastModified.getTime() < file.lastModified()) {
updatedOnClientKeys.add(keyPath);
onlyOnClientKeys.remove(keyPath);
} else {
// Local file date and service object date values match exactly, yet the
// local file has a different hash. This shouldn't ever happen, but
// sometimes does with Excel files.
if (isAssumeLocalLatestInMismatch()) {
if (log.isWarnEnabled()) {
log.warn("Backed-up object \"" + storageObject.getKey()
+ "\" and local file \"" + file.getName()
+ "\" have the same date but different hash values. "
+ "Assuming local file is the latest version.");
}
updatedOnClientKeys.add(keyPath);
onlyOnClientKeys.remove(keyPath);
} else {
throw new IOException("Backed-up object \"" + storageObject.getKey()
+ "\" and local file \"" + file.getName()
+ "\" have the same date but different hash values. "
+ "This shouldn't happen!");
}