mirror of https://github.com/nextcloud/android
192 lines
7.4 KiB
Java
192 lines
7.4 KiB
Java
/*
|
|
* Nextcloud - Android Client
|
|
*
|
|
* SPDX-FileCopyrightText: 2020-2021 Tobias Kaminsky <tobias@kaminsky.me>
|
|
* SPDX-FileCopyrightText: 2018-2019 Andy Scherzinger <info@andy-scherzinger>
|
|
* SPDX-FileCopyrightText: 2015 ownCloud Inc.
|
|
* SPDX-FileCopyrightText: 2015 María Asensio Valverde <masensio@solidgear.es>
|
|
* SPDX-FileCopyrightText: 2012 David A. Velasco <dvelasco@solidgear.es>
|
|
* SPDX-License-Identifier: GPL-2.0-only AND AGPL-3.0-or-later
|
|
*/
|
|
package com.owncloud.android.operations;
|
|
|
|
import android.text.TextUtils;
|
|
|
|
import com.owncloud.android.datamodel.FileDataStorageManager;
|
|
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.common.utils.Log_OC;
|
|
import com.owncloud.android.lib.resources.files.RenameFileRemoteOperation;
|
|
import com.owncloud.android.operations.common.SyncOperation;
|
|
import com.owncloud.android.utils.FileStorageUtils;
|
|
import com.owncloud.android.utils.MimeTypeUtil;
|
|
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
|
|
/**
|
|
* Remote operation performing the rename of a remote file (or folder?) in the ownCloud server.
|
|
*/
|
|
public class RenameFileOperation extends SyncOperation {
|
|
|
|
private static final String TAG = RenameFileOperation.class.getSimpleName();
|
|
|
|
private OCFile file;
|
|
private String remotePath;
|
|
private String newName;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param remotePath RemotePath of the OCFile instance describing the remote file or folder to rename
|
|
* @param newName New name to set as the name of file.
|
|
*/
|
|
public RenameFileOperation(String remotePath, String newName, FileDataStorageManager storageManager) {
|
|
super(storageManager);
|
|
|
|
this.remotePath = remotePath;
|
|
this.newName = newName;
|
|
}
|
|
|
|
/**
|
|
* Performs the rename operation.
|
|
*
|
|
* @param client Client object to communicate with the remote ownCloud server.
|
|
*/
|
|
@Override
|
|
protected RemoteOperationResult run(OwnCloudClient client) {
|
|
RemoteOperationResult result = null;
|
|
String newRemotePath = null;
|
|
|
|
file = getStorageManager().getFileByPath(remotePath);
|
|
|
|
// check if the new name is valid in the local file system
|
|
try {
|
|
if (!isValidNewName()) {
|
|
return new RemoteOperationResult(ResultCode.INVALID_LOCAL_FILE_NAME);
|
|
}
|
|
String parent = new File(file.getRemotePath()).getParent();
|
|
parent = parent.endsWith(OCFile.PATH_SEPARATOR) ? parent : parent + OCFile.PATH_SEPARATOR;
|
|
newRemotePath = parent + newName;
|
|
if (file.isFolder()) {
|
|
newRemotePath += OCFile.PATH_SEPARATOR;
|
|
}
|
|
|
|
// check local overwrite
|
|
if (getStorageManager().getFileByPath(newRemotePath) != null) {
|
|
return new RemoteOperationResult(ResultCode.INVALID_OVERWRITE);
|
|
}
|
|
|
|
result = new RenameFileRemoteOperation(file.getFileName(),
|
|
file.getRemotePath(),
|
|
newName,
|
|
file.isFolder())
|
|
.execute(client);
|
|
|
|
if (result.isSuccess()) {
|
|
if (file.isFolder()) {
|
|
getStorageManager().moveLocalFile(file, newRemotePath, parent);
|
|
//saveLocalDirectory();
|
|
|
|
} else {
|
|
saveLocalFile(newRemotePath);
|
|
}
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
Log_OC.e(TAG, "Rename " + file.getRemotePath() + " to " + ((newRemotePath == null) ?
|
|
newName : newRemotePath) + ": " +
|
|
(result!= null ? result.getLogMessage() : ""), e);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private void saveLocalFile(String newRemotePath) {
|
|
file.setFileName(newName);
|
|
|
|
if (!file.isEncrypted()) {
|
|
file.setDecryptedRemotePath(newRemotePath);
|
|
}
|
|
|
|
// try to rename the local copy of the file
|
|
if (file.isDown()) {
|
|
String oldPath = file.getStoragePath();
|
|
File f = new File(oldPath);
|
|
String parentStoragePath = f.getParent();
|
|
if (!parentStoragePath.endsWith(File.separator)) {
|
|
parentStoragePath += File.separator;
|
|
}
|
|
if (f.renameTo(new File(parentStoragePath + newName))) {
|
|
String newPath = parentStoragePath + newName;
|
|
file.setStoragePath(newPath);
|
|
|
|
// notify MediaScanner about removed file
|
|
getStorageManager().deleteFileInMediaScan(oldPath);
|
|
// notify to scan about new file, if it is a media file
|
|
if (MimeTypeUtil.isMedia(file.getMimeType())) {
|
|
FileDataStorageManager.triggerMediaScan(newPath, file);
|
|
}
|
|
}
|
|
// 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(file);
|
|
}
|
|
|
|
/**
|
|
* 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 (TextUtils.isEmpty(newName) || newName.contains(File.separator)) {
|
|
return false;
|
|
}
|
|
// create a test file
|
|
String tmpFolderName = FileStorageUtils.getTemporalPath("");
|
|
File testFile = new File(tmpFolderName + newName);
|
|
File tmpFolder = testFile.getParentFile();
|
|
if (!tmpFolder.exists() && !tmpFolder.mkdirs()) {
|
|
Log_OC.e(TAG, "Unable to create parent folder " + tmpFolder.getAbsolutePath());
|
|
}
|
|
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 " + newName + " 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;
|
|
}
|
|
|
|
public OCFile getFile() {
|
|
return this.file;
|
|
}
|
|
}
|