From: David A. Velasco Date: Tue, 26 Aug 2014 08:57:25 +0000 (+0200) Subject: Added MoveFileOperation to move OCFiles X-Git-Tag: oc-android-1.7.0_signed~197^2~20 X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/commitdiff_plain/e050da100938046e3d914ccbec7d9b955a27c748?ds=inline;hp=--cc Added MoveFileOperation to move OCFiles --- e050da100938046e3d914ccbec7d9b955a27c748 diff --git a/owncloud-android-library b/owncloud-android-library index e43e43f5..9d286636 160000 --- a/owncloud-android-library +++ b/owncloud-android-library @@ -1 +1 @@ -Subproject commit e43e43f51a895c591b72aaef8f36ef5595d18dba +Subproject commit 9d286636d5674f348a456cb697962f1c78fa306a diff --git a/src/com/owncloud/android/operations/MoveFileOperation.java b/src/com/owncloud/android/operations/MoveFileOperation.java new file mode 100644 index 00000000..f1a3f9f1 --- /dev/null +++ b/src/com/owncloud/android/operations/MoveFileOperation.java @@ -0,0 +1,195 @@ +/* ownCloud Android client application + * Copyright (C) 2012-2014 ownCloud Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, + * as published by the Free Software Foundation. + * + * 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 . + * + */ + +package com.owncloud.android.operations; + +import java.io.File; +import java.io.IOException; + +import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.lib.common.OwnCloudClient; +import com.owncloud.android.lib.common.operations.RemoteOperationResult; +import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode; +import com.owncloud.android.lib.resources.files.RenameRemoteFileOperation; +import com.owncloud.android.operations.common.SyncOperation; +import com.owncloud.android.utils.FileStorageUtils; +import com.owncloud.android.utils.Log_OC; + +import android.accounts.Account; + + +/** + * Operation mmoving an {@link OCFile} to a different folder. + * + * @author David A. Velasco + */ +public class MoveFileOperation extends SyncOperation { + + private static final String TAG = MoveFileOperation.class.getSimpleName(); + + private String mPath; + private Account mAccount; + private String mNewParentPath; + private OCFile mFile; + + + + /** + * Constructor + * + * @param path Remote path of the {@link OCFile} to move. + * @param newParentPath Path to the folder where the file will be moved into. + * @param account OwnCloud account containing both the file and the target folder + */ + public MoveFileOperation(String path, String newParentPath, Account account) { + mPath = path; + mNewParentPath = newParentPath; + mAccount = account; + mFile = null; + } + + public OCFile getFile() { + return mFile; + } + + + /** + * Performs the operation. + * + * @param client Client object to communicate with the remote ownCloud server. + */ + @Override + protected RemoteOperationResult run(OwnCloudClient client) { + RemoteOperationResult result = null; + + mFile = getStorageManager().getFileByPath(mPath); + + // check if the new name is valid in the local file system + try { + String parentPath = (new File(mFile.getRemotePath())).getParent(); + parentPath = (parentPath.endsWith(OCFile.PATH_SEPARATOR)) + ? parentPath + : parentPath + OCFile.PATH_SEPARATOR; + + String mNewPath = mNewParentPath + mFile.getFileName(); + if (mFile.isFolder() && !mNewPath.endsWith(OCFile.PATH_SEPARATOR)) { + mNewPath += OCFile.PATH_SEPARATOR; + } + + // check local overwrite + if (getStorageManager().getFileByPath(mPath) != null) { + return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE); + } + + MoveRemoteFileOperation operation = new MoveRemoteFileOperation( + mFile.getRemotePath(), + mNewPath, + mFile.isFolder() + ); + result = operation.execute(client); + + if (result.isSuccess()) { + if (mFile.isFolder()) { + saveLocalDirectory(); + + } else { + saveLocalFile(); + } + } + + } catch (IOException e) { + Log_OC.e(TAG, "Move " + mFile.getRemotePath() + " to " + + (mNewParentPath==null) + ": " + + ((result!= null) ? result.getLogMessage() : ""), e); + } + + return result; + } + + + private void saveLocalDirectory() { + getStorageManager().moveFolder(mFile, mNewParentPath); + String localPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile); + File localDir = new File(localPath); + if (localDir.exists()) { + localDir.renameTo(new File(FileStorageUtils.getSavePath(mAccount.name) + mNewParentPath)); + // TODO - if renameTo fails, children files that are already down will result unlinked + } + } + + private void saveLocalFile() { + mFile.setFileName(mNewName); + + // try to rename the local copy of the file + if (mFile.isDown()) { + File f = new File(mFile.getStoragePath()); + String parentStoragePath = f.getParent(); + if (!parentStoragePath.endsWith(File.separator)) + parentStoragePath += File.separator; + if (f.renameTo(new File(parentStoragePath + mNewName))) { + mFile.setStoragePath(parentStoragePath + mNewName); + } + // else - NOTHING: the link to the local file is kept although the local name can't be updated + // TODO - study conditions when this could be a problem + } + + getStorageManager().saveFile(mFile); + } + + /** + * Checks if the new name to set is valid in the file system + * + * The only way to be sure is trying to create a file with that name. It's made in the temporal directory + * for downloads, out of any account, and then removed. + * + * IMPORTANT: The test must be made in the same file system where files are download. The internal storage + * could be formatted with a different file system. + * + * TODO move this method, and maybe FileDownload.get***Path(), to a class with utilities specific for the interactions with the file system + * + * @return 'True' if a temporal file named with the name to set could be created in the file system where + * local files are stored. + * @throws IOException When the temporal folder can not be created. + */ + private boolean isValidNewName() throws IOException { + // check tricky names + if (mNewName == null || mNewName.length() <= 0 || mNewName.contains(File.separator) || mNewName.contains("%")) { + return false; + } + // create a test file + String tmpFolderName = FileStorageUtils.getTemporalPath(""); + File testFile = new File(tmpFolderName + mNewName); + File tmpFolder = testFile.getParentFile(); + tmpFolder.mkdirs(); + if (!tmpFolder.isDirectory()) { + throw new IOException("Unexpected error: temporal directory could not be created"); + } + try { + testFile.createNewFile(); // return value is ignored; it could be 'false' because the file already existed, that doesn't invalidate the name + } catch (IOException e) { + Log_OC.i(TAG, "Test for validity of name " + mNewName + " in the file system failed"); + return false; + } + boolean result = (testFile.exists() && testFile.isFile()); + + // cleaning ; result is ignored, since there is not much we could do in case of failure, but repeat and repeat... + testFile.delete(); + + return result; + } + +}