package com.wouterbreukink.onedrive.tasks; import com.google.api.client.util.Maps; import com.google.api.client.util.Preconditions; import com.wouterbreukink.onedrive.client.OneDriveItem; import com.wouterbreukink.onedrive.filesystem.FileSystemProvider; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.io.File; import java.io.IOException; import java.util.Map; import static com.wouterbreukink.onedrive.CommandLineOpts.getCommandLineOpts; public class CheckTask extends Task { private static final Logger log = LogManager.getLogger(UploadTask.class.getName()); private final OneDriveItem remoteFile; private final File localFile; public CheckTask(TaskOptions options, OneDriveItem remoteFile, File localFile) { super(options); this.remoteFile = Preconditions.checkNotNull(remoteFile); this.localFile = Preconditions.checkNotNull(localFile); } public int priority() { return 10; } @Override public String toString() { return String.format("Checking %s %s", remoteFile.isDirectory() ? "folder" : "file", remoteFile.getFullName()); } @Override protected void taskBody() throws IOException { if (localFile.isDirectory() && remoteFile.isDirectory()) { // If we are syncing folders // Verify the timestamps FileSystemProvider.FileMatch match = fileSystem.verifyMatch( localFile, remoteFile.getCreatedDateTime(), remoteFile.getLastModifiedDateTime()); if (match == FileSystemProvider.FileMatch.NO) { queue.add(new UpdatePropertiesTask(getTaskOptions(), remoteFile, localFile)); } OneDriveItem[] remoteFiles = api.getChildren(remoteFile); // Index the local files Map<String, File> localFileCache = Maps.newHashMap(); //noinspection ConstantConditions File[] files = localFile.listFiles(); if (files == null) { log.warn("Unable to recurse into local directory " + localFile.getPath()); reporter.skipped(); return; } for (File file : files) { localFileCache.put(file.getName(), file); } // Iterate over all the remote files for (OneDriveItem remoteFile : remoteFiles) { if (remoteFile.isDirectory() && !getCommandLineOpts().isRecursive()) { continue; } File localFile = localFileCache.remove(remoteFile.getName()); processChild(remoteFile, localFile); } // Iterate over any local files we've not matched yet for (File localFile : localFileCache.values()) { if (localFile.isDirectory() && !getCommandLineOpts().isRecursive()) { continue; } processChild(null, localFile); } return; } // Skip if the file size is too big or if the file is ignored switch (getCommandLineOpts().getDirection()) { case UP: if (isSizeInvalid(localFile) || isIgnored(localFile)) { reporter.skipped(); return; } break; case DOWN: if (isSizeInvalid(remoteFile) || isIgnored(remoteFile)) { reporter.skipped(); return; } break; } if (localFile.isFile() && !remoteFile.isDirectory()) { // If we are syncing files // Check if the remote file matches the local file FileSystemProvider.FileMatch match = fileSystem.verifyMatch( localFile, remoteFile.getCrc32(), remoteFile.getSize(), remoteFile.getCreatedDateTime(), remoteFile.getLastModifiedDateTime()); switch (match) { case NO: switch (getCommandLineOpts().getDirection()) { case UP: queue.add(new UploadTask(getTaskOptions(), remoteFile.getParent(), localFile, true)); break; case DOWN: queue.add(new DownloadTask(getTaskOptions(), localFile.getParentFile(), remoteFile, true)); break; default: throw new IllegalStateException("Unsupported direction " + getCommandLineOpts().getDirection()); } break; case CRC: queue.add(new UpdatePropertiesTask(getTaskOptions(), remoteFile, localFile)); break; case YES: reporter.same(); break; } } else { // Resolve cases where remote and local disagree over whether the item is a file or folder switch (getCommandLineOpts().getDirection()) { case UP: new DeleteTask(getTaskOptions(), remoteFile).taskBody(); // Execute immediately queue.add(new UploadTask(getTaskOptions(), remoteFile.getParent(), localFile, true)); break; case DOWN: new DeleteTask(getTaskOptions(), localFile).taskBody(); // Execute immediately queue.add(new DownloadTask(getTaskOptions(), localFile.getParentFile(), remoteFile, true)); break; default: throw new IllegalStateException("Unsupported direction " + getCommandLineOpts().getDirection()); } } } private void processChild(OneDriveItem remoteFile, File localFile) { if (remoteFile == null && localFile == null) { throw new IllegalArgumentException("Must specify at least one file"); } if (remoteFile != null && isIgnored(remoteFile) || localFile != null && isIgnored((localFile))) { reporter.skipped(); return; } boolean remoteOnly = localFile == null; boolean localOnly = remoteFile == null; // Case 1: We only have the file remotely if (remoteOnly) { switch (getCommandLineOpts().getDirection()) { case UP: queue.add(new DeleteTask(getTaskOptions(), remoteFile)); break; case DOWN: queue.add(new DownloadTask(getTaskOptions(), this.localFile, remoteFile, false)); break; default: throw new IllegalStateException("Unsupported direction " + getCommandLineOpts().getDirection()); } } // Case 2: We only have the file locally else if (localOnly) { switch (getCommandLineOpts().getDirection()) { case UP: queue.add(new UploadTask(getTaskOptions(), this.remoteFile, localFile, false)); break; case DOWN: queue.add(new DeleteTask(getTaskOptions(), localFile)); break; default: throw new IllegalStateException("Unsupported direction " + getCommandLineOpts().getDirection()); } } // Case 3: We have the file in both locations else { queue.add(new CheckTask(getTaskOptions(), remoteFile, localFile)); } } }