/* * Syncany, www.syncany.org * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.syncany.operations.restore; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import org.syncany.config.Config; import org.syncany.database.FileContent.FileChecksum; import org.syncany.database.FileVersion; import org.syncany.database.FileVersion.FileType; import org.syncany.database.MultiChunkEntry.MultiChunkId; import org.syncany.database.PartialFileHistory.FileHistoryId; import org.syncany.database.SqlDatabase; import org.syncany.operations.AbstractTransferOperation; import org.syncany.operations.Assembler; import org.syncany.operations.Downloader; import org.syncany.operations.restore.RestoreOperationResult.RestoreResultCode; import org.syncany.plugins.transfer.StorageException; public class RestoreOperation extends AbstractTransferOperation { private static final Logger logger = Logger.getLogger(RestoreOperation.class.getSimpleName()); public static final String ACTION_ID = "restore"; private RestoreOperationOptions options; private SqlDatabase localDatabase; private Downloader downloader; private Assembler assembler; public RestoreOperation(Config config) { this(config, new RestoreOperationOptions()); } public RestoreOperation(Config config, RestoreOperationOptions options) { super(config, ACTION_ID); this.options = options; this.localDatabase = new SqlDatabase(config); this.downloader = new Downloader(config, transferManager); this.assembler = new Assembler(config, localDatabase, null); } @Override public RestoreOperationResult execute() throws Exception { logger.log(Level.INFO, ""); logger.log(Level.INFO, "Running 'Restore' at client " + config.getMachineName() + " ..."); logger.log(Level.INFO, "--------------------------------------------"); // Find file history FileHistoryId restoreFileHistoryId = findFileHistoryId(); if (restoreFileHistoryId == null) { return new RestoreOperationResult(RestoreResultCode.NACK_NO_FILE); } // Find file version FileVersion restoreFileVersion = findRestoreFileVersion(restoreFileHistoryId); if (restoreFileVersion == null) { return new RestoreOperationResult(RestoreResultCode.NACK_NO_FILE); } else if (restoreFileVersion.getType() == FileType.FOLDER) { return new RestoreOperationResult(RestoreResultCode.NACK_INVALID_FILE); } logger.log(Level.INFO, "Restore file identified: " + restoreFileVersion); // Download multichunks downloadMultiChunks(restoreFileVersion); // Restore file logger.log(Level.INFO, "- Restoring: " + restoreFileVersion); RestoreFileSystemAction restoreAction = new RestoreFileSystemAction(config, assembler, restoreFileVersion, options.getRelativeTargetPath()); RestoreFileSystemActionResult restoreResult = restoreAction.execute(); return new RestoreOperationResult(RestoreResultCode.ACK, restoreResult.getTargetFile()); } private FileHistoryId findFileHistoryId() { return localDatabase.expandFileHistoryId(options.getFileHistoryId()); } private FileVersion findRestoreFileVersion(FileHistoryId restoreFileHistoryId) { if (options.getFileVersion() != null) { return localDatabase.getFileVersion(restoreFileHistoryId, options.getFileVersion()); } else { List<FileVersion> fileHistory = localDatabase.getFileHistory(restoreFileHistoryId); if (fileHistory.size() >= 2) { // In this case, we automatically restore the "previous" version return fileHistory.get(fileHistory.size()-2); } else if (fileHistory.size() == 1){ // In this case, we restore the last version. This is likely a deleted version. return fileHistory.get(0); } else { return null; } } } private void downloadMultiChunks(FileVersion restoreFileVersion) throws StorageException, IOException { Set<MultiChunkId> multiChunksToDownload = new HashSet<MultiChunkId>(); FileChecksum restoreFileChecksum = restoreFileVersion.getChecksum(); if (restoreFileChecksum != null) { multiChunksToDownload.addAll(localDatabase.getMultiChunkIds(restoreFileChecksum)); logger.log(Level.INFO, "Downloading " + multiChunksToDownload.size() + " multichunk(s) to restore file ..."); downloader.downloadAndDecryptMultiChunks(multiChunksToDownload); } } }