1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402 |
- /*
- * ownCloud Android client application
- *
- * @author David A. Velasco
- * Copyright (C) 2016 ownCloud GmbH.
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
- package com.owncloud.android.operations;
- import android.accounts.Account;
- import android.content.Context;
- import android.net.Uri;
- import android.os.Build;
- import android.support.annotation.RequiresApi;
- import com.evernote.android.job.JobRequest;
- import com.evernote.android.job.util.Device;
- import com.google.gson.reflect.TypeToken;
- import com.owncloud.android.datamodel.ArbitraryDataProvider;
- import com.owncloud.android.datamodel.DecryptedFolderMetadata;
- import com.owncloud.android.datamodel.EncryptedFolderMetadata;
- import com.owncloud.android.datamodel.FileDataStorageManager;
- import com.owncloud.android.datamodel.OCFile;
- import com.owncloud.android.datamodel.ThumbnailsCacheManager;
- import com.owncloud.android.datamodel.UploadsStorageManager;
- import com.owncloud.android.db.OCUpload;
- import com.owncloud.android.files.services.FileUploader;
- import com.owncloud.android.lib.common.OwnCloudClient;
- import com.owncloud.android.lib.common.network.OnDatatransferProgressListener;
- import com.owncloud.android.lib.common.network.ProgressiveDataTransferer;
- import com.owncloud.android.lib.common.operations.OperationCancelledException;
- import com.owncloud.android.lib.common.operations.RemoteOperation;
- 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.ChunkedUploadRemoteFileOperation;
- import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
- import com.owncloud.android.lib.resources.files.GetMetadataOperation;
- import com.owncloud.android.lib.resources.files.LockFileOperation;
- import com.owncloud.android.lib.resources.files.ReadRemoteFileOperation;
- import com.owncloud.android.lib.resources.files.RemoteFile;
- import com.owncloud.android.lib.resources.files.StoreMetadataOperation;
- import com.owncloud.android.lib.resources.files.UnlockFileOperation;
- import com.owncloud.android.lib.resources.files.UpdateMetadataOperation;
- import com.owncloud.android.lib.resources.files.UploadRemoteFileOperation;
- import com.owncloud.android.operations.common.SyncOperation;
- import com.owncloud.android.utils.ConnectivityUtils;
- import com.owncloud.android.utils.EncryptionUtils;
- import com.owncloud.android.utils.FileStorageUtils;
- import com.owncloud.android.utils.MimeType;
- import com.owncloud.android.utils.MimeTypeUtil;
- import com.owncloud.android.utils.PowerUtils;
- import com.owncloud.android.utils.UriUtils;
- import org.apache.commons.httpclient.HttpStatus;
- import org.apache.commons.httpclient.methods.RequestEntity;
- import org.lukhnos.nnio.file.Files;
- import org.lukhnos.nnio.file.Paths;
- import java.io.File;
- import java.io.FileInputStream;
- import java.io.FileNotFoundException;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.io.RandomAccessFile;
- import java.nio.channels.FileChannel;
- import java.nio.channels.FileLock;
- import java.nio.channels.OverlappingFileLockException;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Iterator;
- import java.util.Set;
- import java.util.UUID;
- import java.util.concurrent.atomic.AtomicBoolean;
- import static com.owncloud.android.utils.EncryptionUtils.encodeStringToBase64Bytes;
- /**
- * Operation performing the update in the ownCloud server
- * of a file that was modified locally.
- */
- public class UploadFileOperation extends SyncOperation {
- private static final String TAG = UploadFileOperation.class.getSimpleName();
- public static final int CREATED_BY_USER = 0;
- public static final int CREATED_AS_INSTANT_PICTURE = 1;
- public static final int CREATED_AS_INSTANT_VIDEO = 2;
- /**
- * OCFile which is to be uploaded.
- */
- private OCFile mFile;
- /**
- * Original OCFile which is to be uploaded in case file had to be renamed
- * (if forceOverwrite==false and remote file already exists).
- */
- private OCFile mOldFile;
- private String mRemotePath = null;
- private String mFolderUnlockToken;
- private boolean mChunked = false;
- private boolean mRemoteFolderToBeCreated = false;
- private boolean mForceOverwrite = false;
- private int mLocalBehaviour = FileUploader.LOCAL_BEHAVIOUR_COPY;
- private int mCreatedBy = CREATED_BY_USER;
- private boolean mOnWifiOnly = false;
- private boolean mWhileChargingOnly = false;
- private boolean mIgnoringPowerSaveMode = false;
- private boolean mWasRenamed = false;
- private long mOCUploadId = -1;
- /**
- * Local path to file which is to be uploaded (before any possible renaming or moving).
- */
- private String mOriginalStoragePath = null;
- private Set<OnDatatransferProgressListener> mDataTransferListeners = new HashSet<>();
- private OnRenameListener mRenameUploadListener;
- private final AtomicBoolean mCancellationRequested = new AtomicBoolean(false);
- private final AtomicBoolean mUploadStarted = new AtomicBoolean(false);
- private Context mContext;
- private UploadRemoteFileOperation mUploadOperation;
- protected RequestEntity mEntity = null;
- private Account mAccount;
- private OCUpload mUpload;
- private UploadsStorageManager uploadsStorageManager;
- public static OCFile obtainNewOCFileToUpload(String remotePath, String localPath, String mimeType) {
- // MIME type
- if (mimeType == null || mimeType.length() <= 0) {
- mimeType = MimeTypeUtil.getBestMimeTypeByFilename(localPath);
- }
- OCFile newFile = new OCFile(remotePath);
- newFile.setStoragePath(localPath);
- newFile.setLastSyncDateForProperties(0);
- newFile.setLastSyncDateForData(0);
- // size
- if (localPath != null && localPath.length() > 0) {
- File localFile = new File(localPath);
- newFile.setFileLength(localFile.length());
- newFile.setLastSyncDateForData(localFile.lastModified());
- } // don't worry about not assigning size, the problems with localPath
- // are checked when the UploadFileOperation instance is created
- newFile.setMimetype(mimeType);
- return newFile;
- }
- public UploadFileOperation(Account account,
- OCFile file,
- OCUpload upload,
- boolean chunked,
- boolean forceOverwrite,
- int localBehaviour,
- Context context,
- boolean onWifiOnly,
- boolean whileChargingOnly
- ) {
- if (account == null) {
- throw new IllegalArgumentException("Illegal NULL account in UploadFileOperation " + "creation");
- }
- if (upload == null) {
- throw new IllegalArgumentException("Illegal NULL file in UploadFileOperation creation");
- }
- if (upload.getLocalPath() == null || upload.getLocalPath().length() <= 0) {
- throw new IllegalArgumentException(
- "Illegal file in UploadFileOperation; storage path invalid: "
- + upload.getLocalPath());
- }
- mAccount = account;
- mUpload = upload;
- if (file == null) {
- mFile = obtainNewOCFileToUpload(
- upload.getRemotePath(),
- upload.getLocalPath(),
- upload.getMimeType()
- );
- } else {
- mFile = file;
- }
- mOnWifiOnly = onWifiOnly;
- mWhileChargingOnly = whileChargingOnly;
- mRemotePath = upload.getRemotePath();
- mChunked = chunked;
- mForceOverwrite = forceOverwrite;
- mLocalBehaviour = localBehaviour;
- mOriginalStoragePath = mFile.getStoragePath();
- mContext = context;
- mOCUploadId = upload.getUploadId();
- mCreatedBy = upload.getCreadtedBy();
- mRemoteFolderToBeCreated = upload.isCreateRemoteFolder();
- // Ignore power save mode only if user explicitly created this upload
- mIgnoringPowerSaveMode = (mCreatedBy == CREATED_BY_USER);
- mFolderUnlockToken = upload.getFolderUnlockToken();
- }
- public boolean getIsWifiRequired() {
- return mOnWifiOnly;
- }
- public boolean getIsChargingRequired() {
- return mWhileChargingOnly;
- }
- public boolean getIsIgnoringPowerSaveMode() { return mIgnoringPowerSaveMode; }
- public Account getAccount() {
- return mAccount;
- }
- public String getFileName() {
- return (mFile != null) ? mFile.getFileName() : null;
- }
- public OCFile getFile() {
- return mFile;
- }
- /**
- * If remote file was renamed, return original OCFile which was uploaded. Is
- * null is file was not renamed.
- */
- public OCFile getOldFile() {
- return mOldFile;
- }
- public String getOriginalStoragePath() {
- return mOriginalStoragePath;
- }
- public String getStoragePath() {
- return mFile.getStoragePath();
- }
- public String getRemotePath() {
- return mFile.getRemotePath();
- }
- public String getDecryptedRemotePath() {
- return mFile.getDecryptedRemotePath();
- }
- public String getMimeType() {
- return mFile.getMimetype();
- }
- public int getLocalBehaviour() {
- return mLocalBehaviour;
- }
- public void setRemoteFolderToBeCreated() {
- mRemoteFolderToBeCreated = true;
- }
- public boolean wasRenamed() {
- return mWasRenamed;
- }
- public void setCreatedBy(int createdBy) {
- mCreatedBy = createdBy;
- if (createdBy < CREATED_BY_USER || CREATED_AS_INSTANT_VIDEO < createdBy) {
- mCreatedBy = CREATED_BY_USER;
- }
- }
- public int getCreatedBy() {
- return mCreatedBy;
- }
- public boolean isInstantPicture() {
- return mCreatedBy == CREATED_AS_INSTANT_PICTURE;
- }
- public boolean isInstantVideo() {
- return mCreatedBy == CREATED_AS_INSTANT_VIDEO;
- }
- public void setOCUploadId(long id) {
- mOCUploadId = id;
- }
- public long getOCUploadId() {
- return mOCUploadId;
- }
- public Set<OnDatatransferProgressListener> getDataTransferListeners() {
- return mDataTransferListeners;
- }
- public void addDataTransferProgressListener(OnDatatransferProgressListener listener) {
- synchronized (mDataTransferListeners) {
- mDataTransferListeners.add(listener);
- }
- if (mEntity != null) {
- ((ProgressiveDataTransferer) mEntity).addDatatransferProgressListener(listener);
- }
- if (mUploadOperation != null) {
- mUploadOperation.addDatatransferProgressListener(listener);
- }
- }
- public void removeDataTransferProgressListener(OnDatatransferProgressListener listener) {
- synchronized (mDataTransferListeners) {
- mDataTransferListeners.remove(listener);
- }
- if (mEntity != null) {
- ((ProgressiveDataTransferer) mEntity).removeDatatransferProgressListener(listener);
- }
- if (mUploadOperation != null) {
- mUploadOperation.removeDatatransferProgressListener(listener);
- }
- }
- public void addRenameUploadListener(OnRenameListener listener) {
- mRenameUploadListener = listener;
- }
- public boolean isChunkedUploadSupported() {
- return mChunked;
- }
- public Context getContext() {
- return mContext;
- }
- @Override
- @SuppressWarnings("PMD.AvoidDuplicateLiterals")
- protected RemoteOperationResult run(OwnCloudClient client) {
- mCancellationRequested.set(false);
- mUploadStarted.set(true);
- uploadsStorageManager = new UploadsStorageManager(mContext.getContentResolver(),
- mContext);
- for (OCUpload ocUpload : uploadsStorageManager.getAllStoredUploads()) {
- if (ocUpload.getUploadId() == getOCUploadId()) {
- ocUpload.setFileSize(0);
- uploadsStorageManager.updateUpload(ocUpload);
- break;
- }
- }
- // check the existence of the parent folder for the file to upload
- String remoteParentPath = new File(getRemotePath()).getParent();
- remoteParentPath = remoteParentPath.endsWith(OCFile.PATH_SEPARATOR) ?
- remoteParentPath : remoteParentPath + OCFile.PATH_SEPARATOR;
- OCFile parent = getStorageManager().getFileByPath(remoteParentPath);
- mFile.setParentId(parent.getFileId());
- if (parent.isEncrypted()) {
- UnlockFileOperation unlockFileOperation = new UnlockFileOperation(parent.getLocalId(), mFolderUnlockToken);
- RemoteOperationResult unlockFileOperationResult = unlockFileOperation.execute(client);
- if (!unlockFileOperationResult.isSuccess()) {
- return unlockFileOperationResult;
- }
- }
- RemoteOperationResult result = grantFolderExistence(remoteParentPath, client);
- if (!result.isSuccess()) {
- return result;
- }
- if (parent.isEncrypted()) {
- Log_OC.d(TAG, "encrypted upload");
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
- return encryptedUpload(client, parent);
- } else {
- Log_OC.e(TAG, "Encrypted upload on old Android API");
- return new RemoteOperationResult(ResultCode.OLD_ANDROID_API);
- }
- } else {
- Log_OC.d(TAG, "normal upload");
- return normalUpload(client);
- }
- }
- @RequiresApi(api = Build.VERSION_CODES.KITKAT)
- private RemoteOperationResult encryptedUpload(OwnCloudClient client, OCFile parentFile) {
- RemoteOperationResult result = null;
- File temporalFile = null;
- File originalFile = new File(mOriginalStoragePath);
- File expectedFile = null;
- FileLock fileLock = null;
- long size;
- boolean metadataExists = false;
- String token = null;
- ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProvider(getContext().getContentResolver());
- String privateKey = arbitraryDataProvider.getValue(getAccount().name, EncryptionUtils.PRIVATE_KEY);
- String publicKey = arbitraryDataProvider.getValue(getAccount().name, EncryptionUtils.PUBLIC_KEY);
- try {
- // check conditions
- result = checkConditions(originalFile);
- /***** E2E *****/
- // Lock folder
- LockFileOperation lockFileOperation = new LockFileOperation(parentFile.getLocalId());
- RemoteOperationResult lockFileOperationResult = lockFileOperation.execute(client);
- if (lockFileOperationResult.isSuccess()) {
- token = (String) lockFileOperationResult.getData().get(0);
- } else if (lockFileOperationResult.getHttpCode() == HttpStatus.SC_FORBIDDEN) {
- throw new Exception("Forbidden! Please try again later.)");
- } else {
- throw new Exception("Unknown error!");
- }
- // Update metadata
- GetMetadataOperation getMetadataOperation = new GetMetadataOperation(parentFile.getLocalId());
- RemoteOperationResult getMetadataOperationResult = getMetadataOperation.execute(client);
- DecryptedFolderMetadata metadata;
- if (getMetadataOperationResult.isSuccess()) {
- metadataExists = true;
- // decrypt metadata
- String serializedEncryptedMetadata = (String) getMetadataOperationResult.getData().get(0);
- EncryptedFolderMetadata encryptedFolderMetadata = EncryptionUtils.deserializeJSON(
- serializedEncryptedMetadata, new TypeToken<EncryptedFolderMetadata>() {
- });
- metadata = EncryptionUtils.decryptFolderMetaData(encryptedFolderMetadata, privateKey);
- } else if (getMetadataOperationResult.getHttpCode() == HttpStatus.SC_NOT_FOUND) {
- // new metadata
- metadata = new DecryptedFolderMetadata();
- metadata.metadata = new DecryptedFolderMetadata.Metadata();
- metadata.metadata.metadataKeys = new HashMap<>();
- String metadataKey = EncryptionUtils.encodeBytesToBase64String(EncryptionUtils.generateKey());
- String encryptedMetadataKey = EncryptionUtils.encryptStringAsymmetric(metadataKey, publicKey);
- metadata.metadata.metadataKeys.put(0, encryptedMetadataKey);
- } else {
- // TODO error
- throw new Exception("something wrong");
- }
- /***** E2E *****/
- // check name collision
- checkNameCollision(client);
- String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
- expectedFile = new File(expectedPath);
- result = copyFile(originalFile, expectedPath);
- if (result != null) {
- return result;
- }
- // Get the last modification date of the file from the file system
- Long timeStampLong = originalFile.lastModified() / 1000;
- String timeStamp = timeStampLong.toString();
- /***** E2E *****/
- // Key
- byte[] key = null;
- try {
- // TODO change key if file has changed, e.g. when file is updated
- key = encodeStringToBase64Bytes(metadata.files.get(mFile.getFileName()).encrypted.key);
- } catch (Exception e) {
- // no key found
- }
- if (key == null || key.length == 0) {
- key = EncryptionUtils.generateKey();
- }
- // IV
- byte[] iv = null;
- try {
- iv = encodeStringToBase64Bytes(metadata.files.get(mFile.getFileName()).initializationVector);
- } catch (Exception e) {
- // no iv found
- }
- if (iv == null || iv.length == 0) {
- iv = EncryptionUtils.generateIV();
- }
- EncryptionUtils.EncryptedFile encryptedFile = EncryptionUtils.encryptFile(mFile, key, iv);
- // new random file name, check if it exists in metadata
- String encryptedFileName = UUID.randomUUID().toString().replaceAll("-", "");
- while (metadata.files.get(encryptedFileName) != null) {
- encryptedFileName = UUID.randomUUID().toString().replaceAll("-", "");
- }
- mFile.setEncryptedFileName(encryptedFileName);
- File encryptedTempFile = File.createTempFile("encFile", encryptedFileName);
- FileOutputStream fileOutputStream = new FileOutputStream(encryptedTempFile);
- fileOutputStream.write(encryptedFile.encryptedBytes);
- fileOutputStream.close();
- /***** E2E *****/
- FileChannel channel = null;
- try {
- channel = new RandomAccessFile(mFile.getStoragePath(), "rw").getChannel();
- fileLock = channel.tryLock();
- } catch (FileNotFoundException e) {
- // this basically means that the file is on SD card
- // try to copy file to temporary dir if it doesn't exist
- String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
- mFile.setStoragePath(temporalPath);
- temporalFile = new File(temporalPath);
- Files.deleteIfExists(Paths.get(temporalPath));
- result = copy(originalFile, temporalFile);
- if (result == null) {
- if (temporalFile.length() == originalFile.length()) {
- channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel();
- fileLock = channel.tryLock();
- } else {
- result = new RemoteOperationResult(ResultCode.LOCK_FAILED);
- }
- }
- }
- try {
- size = channel.size();
- } catch (IOException e1) {
- size = new File(mFile.getStoragePath()).length();
- }
- for (OCUpload ocUpload : uploadsStorageManager.getAllStoredUploads()) {
- if (ocUpload.getUploadId() == getOCUploadId()) {
- ocUpload.setFileSize(size);
- uploadsStorageManager.updateUpload(ocUpload);
- break;
- }
- }
- /// perform the upload
- if (mChunked && (size > ChunkedUploadRemoteFileOperation.CHUNK_SIZE)) {
- mUploadOperation = new ChunkedUploadRemoteFileOperation(mContext, encryptedTempFile.getAbsolutePath(),
- mFile.getParentRemotePath() + encryptedFileName, mFile.getMimetype(),
- mFile.getEtagInConflict(), timeStamp);
- } else {
- mUploadOperation = new UploadRemoteFileOperation(encryptedTempFile.getAbsolutePath(),
- mFile.getParentRemotePath() + encryptedFileName, mFile.getMimetype(),
- mFile.getEtagInConflict(), timeStamp);
- }
- Iterator<OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
- while (listener.hasNext()) {
- mUploadOperation.addDatatransferProgressListener(listener.next());
- }
- if (mCancellationRequested.get()) {
- throw new OperationCancelledException();
- }
- // FileChannel channel = null;
- // try {
- // channel = new RandomAccessFile(ocFile.getStoragePath(), "rw").getChannel();
- // fileLock = channel.tryLock();
- // } catch (FileNotFoundException e) {
- // if (temporalFile == null) {
- // String temporalPath = FileStorageUtils.getTemporalPath(account.name) + ocFile.getRemotePath();
- // ocFile.setStoragePath(temporalPath);
- // temporalFile = new File(temporalPath);
- //
- // result = copy(originalFile, temporalFile);
- //
- // if (result != null) {
- // return result;
- // } else {
- // if (temporalFile.length() == originalFile.length()) {
- // channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel();
- // fileLock = channel.tryLock();
- // } else {
- // while (temporalFile.length() != originalFile.length()) {
- // Files.deleteIfExists(Paths.get(temporalPath));
- // result = copy(originalFile, temporalFile);
- //
- // if (result != null) {
- // return result;
- // } else {
- // channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").
- // getChannel();
- // fileLock = channel.tryLock();
- // }
- // }
- // }
- // }
- // } else {
- // channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel();
- // fileLock = channel.tryLock();
- // }
- // }
- // boolean test = true;
- // if (test) {
- // throw new Exception("test");
- // }
-
- result = mUploadOperation.execute(client);
- // if (result == null || result.isSuccess() && mUploadOperation != null) {
- // result = mUploadOperation.execute(client);
- /// move local temporal file or original file to its corresponding
- // location in the Nextcloud local folder
- if (!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED) {
- result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
- }
- // }
- if (result.isSuccess()) {
- // upload metadata
- DecryptedFolderMetadata.DecryptedFile decryptedFile = new DecryptedFolderMetadata.DecryptedFile();
- DecryptedFolderMetadata.Data data = new DecryptedFolderMetadata.Data();
- data.filename = mFile.getFileName();
- data.mimetype = mFile.getMimetype();
- data.key = EncryptionUtils.encodeBytesToBase64String(key);
- decryptedFile.encrypted = data;
- decryptedFile.initializationVector = EncryptionUtils.encodeBytesToBase64String(iv);
- decryptedFile.authenticationTag = encryptedFile.authenticationTag;
- metadata.files.put(encryptedFileName, decryptedFile);
- EncryptedFolderMetadata encryptedFolderMetadata = EncryptionUtils.encryptFolderMetadata(metadata,
- privateKey);
- String serializedFolderMetadata = EncryptionUtils.serializeJSON(encryptedFolderMetadata);
- // upload metadata
- RemoteOperationResult uploadMetadataOperationResult;
- if (metadataExists) {
- // update metadata
- UpdateMetadataOperation storeMetadataOperation = new UpdateMetadataOperation(parentFile.getLocalId(),
- serializedFolderMetadata, token);
- uploadMetadataOperationResult = storeMetadataOperation.execute(client);
- } else {
- // store metadata
- StoreMetadataOperation storeMetadataOperation = new StoreMetadataOperation(parentFile.getLocalId(),
- serializedFolderMetadata);
- uploadMetadataOperationResult = storeMetadataOperation.execute(client);
- }
- if (!uploadMetadataOperationResult.isSuccess()) {
- throw new Exception();
- }
- }
- } catch (FileNotFoundException e) {
- Log_OC.d(TAG, mFile.getStoragePath() + " not exists anymore");
- result = new RemoteOperationResult(ResultCode.LOCAL_FILE_NOT_FOUND);
- } catch (OverlappingFileLockException e) {
- Log_OC.d(TAG, "Overlapping file lock exception");
- result = new RemoteOperationResult(ResultCode.LOCK_FAILED);
- } catch (Exception e) {
- result = new RemoteOperationResult(e);
- } finally {
- mUploadStarted.set(false);
- // if something fails, store token and retry again
- mUpload.setFolderUnlockToken(token);
- uploadsStorageManager.updateUpload(mUpload);
- if (fileLock != null) {
- try {
- fileLock.release();
- } catch (IOException e) {
- Log_OC.e(TAG, "Failed to unlock file with path " + mFile.getStoragePath());
- }
- }
- if (temporalFile != null && !originalFile.equals(temporalFile)) {
- temporalFile.delete();
- }
- if (result == null) {
- result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR);
- }
- if (result.isSuccess()) {
- Log_OC.i(TAG, "Upload of " + mFile.getStoragePath() + " to " + mFile.getRemotePath() + ": " +
- result.getLogMessage());
- } else {
- if (result.getException() != null) {
- if (result.isCancelled()) {
- Log_OC.w(TAG, "Upload of " + mFile.getStoragePath() + " to " + mFile.getRemotePath() +
- ": " + result.getLogMessage());
- } else {
- Log_OC.e(TAG, "Upload of " + mFile.getStoragePath() + " to " + mFile.getRemotePath() +
- ": " + result.getLogMessage(), result.getException());
- }
- } else {
- Log_OC.e(TAG, "Upload of " + mFile.getStoragePath() + " to " + mFile.getRemotePath() +
- ": " + result.getLogMessage());
- }
- }
- }
- // TODO on failure store token
- if (result.isSuccess()) {
- handleSuccessfulUpload(temporalFile, expectedFile, originalFile, client);
- unlockFolder(parentFile, client, token);
- } else if (result.getCode() == ResultCode.SYNC_CONFLICT) {
- getStorageManager().saveConflict(mFile, mFile.getEtagInConflict());
- }
- return result;
- }
- private void unlockFolder(OCFile parentFolder, OwnCloudClient client, String token) {
- if (token != null) {
- UnlockFileOperation unlockFileOperation = new UnlockFileOperation(parentFolder.getLocalId(), token);
- RemoteOperationResult unlockFileOperationResult = unlockFileOperation.execute(client);
- if (!unlockFileOperationResult.isSuccess()) {
- Log_OC.e(TAG, "Failed to unlock " + parentFolder.getLocalId());
- }
- }
- }
- private RemoteOperationResult checkConditions(File originalFile) {
- if (Device.getNetworkType(mContext).equals(JobRequest.NetworkType.ANY) ||
- ConnectivityUtils.isInternetWalled(mContext)) {
- return new RemoteOperationResult(ResultCode.NO_NETWORK_CONNECTION);
- }
-
- /// Check that connectivity conditions are met and delays the upload otherwise
- // TODO verify if this can be deleted
- if (mOnWifiOnly && !Device.getNetworkType(mContext).equals(JobRequest.NetworkType.UNMETERED)) {
- Log_OC.d(TAG, "Upload delayed until WiFi is available: " + getRemotePath());
- return new RemoteOperationResult(ResultCode.DELAYED_FOR_WIFI);
- }
- // TODO verify if this can be deleted
- // Check if charging conditions are met and delays the upload otherwise
- if (mWhileChargingOnly && !Device.isCharging(mContext)) {
- Log_OC.d(TAG, "Upload delayed until the device is charging: " + getRemotePath());
- return new RemoteOperationResult(ResultCode.DELAYED_FOR_CHARGING);
- }
- // Check that device is not in power save mode
- if (!mIgnoringPowerSaveMode && UploadUtils.isPowerSaveMode(mContext)) {
- Log_OC.d(TAG, "Upload delayed because device is in power save mode: " + getRemotePath());
- return new RemoteOperationResult(ResultCode.DELAYED_IN_POWER_SAVE_MODE);
- }
- /// check if the file continues existing before schedule the operation
- if (!originalFile.exists()) {
- Log_OC.d(TAG, mOriginalStoragePath + " not exists anymore");
- return new RemoteOperationResult(ResultCode.LOCAL_FILE_NOT_FOUND);
- }
- return null;
- }
- private RemoteOperationResult normalUpload(OwnCloudClient client) {
- RemoteOperationResult result = null;
- File temporalFile = null;
- File originalFile = new File(mOriginalStoragePath);
- File expectedFile = null;
- FileLock fileLock = null;
- long size = 0;
- try {
- // check conditions
- result = checkConditions(originalFile);
- // check name collision
- checkNameCollision(client);
- String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
- expectedFile = new File(expectedPath);
- result = copyFile(originalFile, expectedPath);
- if (result != null) {
- return result;
- }
- // Get the last modification date of the file from the file system
- Long timeStampLong = originalFile.lastModified() / 1000;
- String timeStamp = timeStampLong.toString();
- FileChannel channel = null;
- try {
- channel = new RandomAccessFile(mFile.getStoragePath(), "rw").getChannel();
- fileLock = channel.tryLock();
- } catch (FileNotFoundException e) {
- // this basically means that the file is on SD card
- // try to copy file to temporary dir if it doesn't exist
- String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
- mFile.setStoragePath(temporalPath);
- temporalFile = new File(temporalPath);
- Files.deleteIfExists(Paths.get(temporalPath));
- result = copy(originalFile, temporalFile);
- if (result == null) {
- if (temporalFile.length() == originalFile.length()) {
- channel = new RandomAccessFile(temporalFile.getAbsolutePath(), "rw").getChannel();
- fileLock = channel.tryLock();
- } else {
- result = new RemoteOperationResult(ResultCode.LOCK_FAILED);
- }
- }
- }
- try {
- size = channel.size();
- } catch (IOException e1) {
- size = new File(mFile.getStoragePath()).length();
- }
- for (OCUpload ocUpload : uploadsStorageManager.getAllStoredUploads()) {
- if (ocUpload.getUploadId() == getOCUploadId()) {
- ocUpload.setFileSize(size);
- uploadsStorageManager.updateUpload(ocUpload);
- break;
- }
- }
- // perform the upload
- if (mChunked && (size > ChunkedUploadRemoteFileOperation.CHUNK_SIZE)) {
- mUploadOperation = new ChunkedUploadRemoteFileOperation(mContext, mFile.getStoragePath(),
- mFile.getRemotePath(), mFile.getMimetype(), mFile.getEtagInConflict(), timeStamp);
- } else {
- mUploadOperation = new UploadRemoteFileOperation(mFile.getStoragePath(),
- mFile.getRemotePath(), mFile.getMimetype(), mFile.getEtagInConflict(), timeStamp);
- }
- Iterator<OnDatatransferProgressListener> listener = mDataTransferListeners.iterator();
- while (listener.hasNext()) {
- mUploadOperation.addDatatransferProgressListener(listener.next());
- }
- if (mCancellationRequested.get()) {
- throw new OperationCancelledException();
- }
- if (result == null || result.isSuccess() && mUploadOperation != null) {
- result = mUploadOperation.execute(client);
- /// move local temporal file or original file to its corresponding
- // location in the Nextcloud local folder
- if (!result.isSuccess() && result.getHttpCode() == HttpStatus.SC_PRECONDITION_FAILED) {
- result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT);
- }
- }
- } catch (FileNotFoundException e) {
- Log_OC.d(TAG, mOriginalStoragePath + " not exists anymore");
- result = new RemoteOperationResult(ResultCode.LOCAL_FILE_NOT_FOUND);
- } catch (OverlappingFileLockException e) {
- Log_OC.d(TAG, "Overlapping file lock exception");
- result = new RemoteOperationResult(ResultCode.LOCK_FAILED);
- } catch (Exception e) {
- result = new RemoteOperationResult(e);
- } finally {
- mUploadStarted.set(false);
- if (fileLock != null) {
- try {
- fileLock.release();
- } catch (IOException e) {
- Log_OC.e(TAG, "Failed to unlock file with path " + mOriginalStoragePath);
- }
- }
- if (temporalFile != null && !originalFile.equals(temporalFile)) {
- temporalFile.delete();
- }
- if (result == null) {
- result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR);
- }
- if (result.isSuccess()) {
- Log_OC.i(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath + ": " +
- result.getLogMessage());
- } else {
- if (result.getException() != null) {
- if (result.isCancelled()) {
- Log_OC.w(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
- ": " + result.getLogMessage());
- } else {
- Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
- ": " + result.getLogMessage(), result.getException());
- }
- } else {
- Log_OC.e(TAG, "Upload of " + mOriginalStoragePath + " to " + mRemotePath +
- ": " + result.getLogMessage());
- }
- }
- }
- if (result.isSuccess()) {
- handleSuccessfulUpload(temporalFile, expectedFile, originalFile, client);
- } else if (result.getCode() == ResultCode.SYNC_CONFLICT) {
- getStorageManager().saveConflict(mFile, mFile.getEtagInConflict());
- }
- return result;
- }
- private RemoteOperationResult copyFile(File originalFile, String expectedPath) throws OperationCancelledException,
- IOException {
- RemoteOperationResult result = null;
- if (mLocalBehaviour == FileUploader.LOCAL_BEHAVIOUR_COPY && !mOriginalStoragePath.equals(expectedPath)) {
- String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
- mFile.setStoragePath(temporalPath);
- File temporalFile = new File(temporalPath);
- result = copy(originalFile, temporalFile);
- }
- if (mCancellationRequested.get()) {
- throw new OperationCancelledException();
- }
- return result;
- }
- private void checkNameCollision(OwnCloudClient client) throws OperationCancelledException {
- /// automatic rename of file to upload in case of name collision in server
- Log_OC.d(TAG, "Checking name collision in server");
- if (!mForceOverwrite) {
- // TODO encrypted always false?
- String remotePath = getAvailableRemotePath(client, mRemotePath, null, false);
- mWasRenamed = !remotePath.equals(mRemotePath);
- if (mWasRenamed) {
- createNewOCFile(remotePath);
- Log_OC.d(TAG, "File renamed as " + remotePath);
- }
- mRemotePath = remotePath;
- mRenameUploadListener.onRenameUpload();
- }
- if (mCancellationRequested.get()) {
- throw new OperationCancelledException();
- }
- }
- private void handleSuccessfulUpload(File temporalFile, File expectedFile, File originalFile,
- OwnCloudClient client) {
- switch (mLocalBehaviour) {
- case FileUploader.LOCAL_BEHAVIOUR_FORGET:
- default:
- String temporalPath = FileStorageUtils.getTemporalPath(mAccount.name) + mFile.getRemotePath();
- if (mOriginalStoragePath.equals(temporalPath)) {
- // delete local file is was pre-copied in temporary folder (see .ui.helpers.UriUploader)
- temporalFile = new File(temporalPath);
- temporalFile.delete();
- }
- mFile.setStoragePath("");
- saveUploadedFile(client);
- break;
- case FileUploader.LOCAL_BEHAVIOUR_DELETE:
- Log_OC.d(TAG, "Delete source file");
- originalFile.delete();
- getStorageManager().deleteFileInMediaScan(originalFile.getAbsolutePath());
- saveUploadedFile(client);
- break;
- case FileUploader.LOCAL_BEHAVIOUR_COPY:
- if (temporalFile != null) {
- try {
- move(temporalFile, expectedFile);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- mFile.setStoragePath(expectedFile.getAbsolutePath());
- saveUploadedFile(client);
- FileDataStorageManager.triggerMediaScan(expectedFile.getAbsolutePath());
- break;
- case FileUploader.LOCAL_BEHAVIOUR_MOVE:
- String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, mFile);
- expectedFile = new File(expectedPath);
- try {
- move(originalFile, expectedFile);
- } catch (IOException e) {
- e.printStackTrace();
- }
- getStorageManager().deleteFileInMediaScan(originalFile.getAbsolutePath());
- mFile.setStoragePath(expectedFile.getAbsolutePath());
- saveUploadedFile(client);
- FileDataStorageManager.triggerMediaScan(expectedFile.getAbsolutePath());
- break;
- }
- }
- /**
- * Checks the existence of the folder where the current file will be uploaded both
- * in the remote server and in the local database.
- * <p/>
- * If the upload is set to enforce the creation of the folder, the method tries to
- * create it both remote and locally.
- *
- * @param pathToGrant Full remote path whose existence will be granted.
- * @return An {@link OCFile} instance corresponding to the folder where the file
- * will be uploaded.
- */
- private RemoteOperationResult grantFolderExistence(String pathToGrant, OwnCloudClient client) {
- RemoteOperation operation = new ExistenceCheckRemoteOperation(pathToGrant, mContext, false);
- RemoteOperationResult result = operation.execute(client);
- if (!result.isSuccess() && result.getCode() == ResultCode.FILE_NOT_FOUND && mRemoteFolderToBeCreated) {
- SyncOperation syncOp = new CreateFolderOperation(pathToGrant, true);
- result = syncOp.execute(client, getStorageManager());
- }
- if (result.isSuccess()) {
- OCFile parentDir = getStorageManager().getFileByPath(pathToGrant);
- if (parentDir == null) {
- parentDir = createLocalFolder(pathToGrant);
- }
- if (parentDir != null) {
- result = new RemoteOperationResult(ResultCode.OK);
- } else {
- result = new RemoteOperationResult(ResultCode.UNKNOWN_ERROR);
- }
- }
- return result;
- }
- private OCFile createLocalFolder(String remotePath) {
- String parentPath = new File(remotePath).getParent();
- parentPath = parentPath.endsWith(OCFile.PATH_SEPARATOR) ?
- parentPath : parentPath + OCFile.PATH_SEPARATOR;
- OCFile parent = getStorageManager().getFileByPath(parentPath);
- if (parent == null) {
- parent = createLocalFolder(parentPath);
- }
- if (parent != null) {
- OCFile createdFolder = new OCFile(remotePath);
- createdFolder.setMimetype(MimeType.DIRECTORY);
- createdFolder.setParentId(parent.getFileId());
- getStorageManager().saveFile(createdFolder);
- return createdFolder;
- }
- return null;
- }
- /**
- * Create a new OCFile mFile with new remote path. This is required if forceOverwrite==false.
- * New file is stored as mFile, original as mOldFile.
- *
- * @param newRemotePath new remote path
- */
- private void createNewOCFile(String newRemotePath) {
- // a new OCFile instance must be created for a new remote path
- OCFile newFile = new OCFile(newRemotePath);
- newFile.setCreationTimestamp(mFile.getCreationTimestamp());
- newFile.setFileLength(mFile.getFileLength());
- newFile.setMimetype(mFile.getMimetype());
- newFile.setModificationTimestamp(mFile.getModificationTimestamp());
- newFile.setModificationTimestampAtLastSyncForData(
- mFile.getModificationTimestampAtLastSyncForData()
- );
- newFile.setEtag(mFile.getEtag());
- newFile.setAvailableOffline(mFile.isAvailableOffline());
- newFile.setLastSyncDateForProperties(mFile.getLastSyncDateForProperties());
- newFile.setLastSyncDateForData(mFile.getLastSyncDateForData());
- newFile.setStoragePath(mFile.getStoragePath());
- newFile.setParentId(mFile.getParentId());
- mOldFile = mFile;
- mFile = newFile;
- }
- /**
- * Checks if remotePath does not exist in the server and returns it, or adds
- * a suffix to it in order to avoid the server file is overwritten.
- *
- * @param client OwnCloud client
- * @param remotePath remote path of the file
- * @param metadata metadata of encrypted folder
- * @return new remote path
- */
- private String getAvailableRemotePath(OwnCloudClient client, String remotePath, DecryptedFolderMetadata metadata,
- boolean encrypted) {
- boolean check = existsFile(client, remotePath, metadata, encrypted);
- if (!check) {
- return remotePath;
- }
- int pos = remotePath.lastIndexOf('.');
- String suffix;
- String extension = "";
- String remotePathWithoutExtension = "";
- if (pos >= 0) {
- extension = remotePath.substring(pos + 1);
- remotePathWithoutExtension = remotePath.substring(0, pos);
- }
- int count = 2;
- do {
- suffix = " (" + count + ")";
- if (pos >= 0) {
- check = existsFile(client, remotePathWithoutExtension + suffix + "." + extension, metadata, encrypted);
- } else {
- check = existsFile(client, remotePath + suffix, metadata, encrypted);
- }
- count++;
- } while (check);
- if (pos >= 0) {
- return remotePathWithoutExtension + suffix + "." + extension;
- } else {
- return remotePath + suffix;
- }
- }
- private boolean existsFile(OwnCloudClient client, String remotePath, DecryptedFolderMetadata metadata,
- boolean encrypted) {
- if (encrypted) {
- String fileName = new File(remotePath).getName();
- for (DecryptedFolderMetadata.DecryptedFile file : metadata.files.values()) {
- if (file.encrypted.filename.equalsIgnoreCase(fileName)) {
- return true;
- }
- }
- return false;
- } else {
- ExistenceCheckRemoteOperation existsOperation = new ExistenceCheckRemoteOperation(remotePath, mContext,
- false);
- RemoteOperationResult result = existsOperation.execute(client);
- return result.isSuccess();
- }
- }
- /**
- * Allows to cancel the actual upload operation. If actual upload operating
- * is in progress it is cancelled, if upload preparation is being performed
- * upload will not take place.
- */
- public void cancel() {
- if (mUploadOperation == null) {
- if (mUploadStarted.get()) {
- Log_OC.d(TAG, "Cancelling upload during upload preparations.");
- mCancellationRequested.set(true);
- } else {
- Log_OC.e(TAG, "No upload in progress. This should not happen.");
- }
- } else {
- Log_OC.d(TAG, "Cancelling upload during actual upload operation.");
- mUploadOperation.cancel();
- }
- }
- /**
- * As soon as this method return true, upload can be cancel via cancel().
- */
- public boolean isUploadInProgress() {
- return mUploadStarted.get();
- }
- /**
- * TODO rewrite with homogeneous fail handling, remove dependency on {@link RemoteOperationResult},
- * TODO use Exceptions instead
- *
- * @param sourceFile Source file to copy.
- * @param targetFile Target location to copy the file.
- * @return {@link RemoteOperationResult}
- * @throws IOException exception if file cannot be accessed
- */
- private RemoteOperationResult copy(File sourceFile, File targetFile) throws IOException {
- Log_OC.d(TAG, "Copying local file");
- RemoteOperationResult result = null;
- if (FileStorageUtils.getUsableSpace(mAccount.name) < sourceFile.length()) {
- result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_FULL);
- return result; // error condition when the file should be copied
- } else {
- Log_OC.d(TAG, "Creating temporal folder");
- File temporalParent = targetFile.getParentFile();
- temporalParent.mkdirs();
- if (!temporalParent.isDirectory()) {
- throw new IOException(
- "Unexpected error: parent directory could not be created");
- }
- Log_OC.d(TAG, "Creating temporal file");
- targetFile.createNewFile();
- if (!targetFile.isFile()) {
- throw new IOException(
- "Unexpected error: target file could not be created");
- }
- Log_OC.d(TAG, "Copying file contents");
- InputStream in = null;
- OutputStream out = null;
- try {
- if (!mOriginalStoragePath.equals(targetFile.getAbsolutePath())) {
- // In case document provider schema as 'content://'
- if (mOriginalStoragePath.startsWith(UriUtils.URI_CONTENT_SCHEME)) {
- Uri uri = Uri.parse(mOriginalStoragePath);
- in = mContext.getContentResolver().openInputStream(uri);
- } else {
- in = new FileInputStream(sourceFile);
- }
- out = new FileOutputStream(targetFile);
- int nRead;
- byte[] buf = new byte[4096];
- while (!mCancellationRequested.get() &&
- (nRead = in.read(buf)) > -1) {
- out.write(buf, 0, nRead);
- }
- out.flush();
- } // else: weird but possible situation, nothing to copy
- if (mCancellationRequested.get()) {
- result = new RemoteOperationResult(new OperationCancelledException());
- return result;
- }
- } catch (Exception e) {
- result = new RemoteOperationResult(ResultCode.LOCAL_STORAGE_NOT_COPIED);
- return result;
- } finally {
- try {
- if (in != null) {
- in.close();
- }
- } catch (Exception e) {
- Log_OC.d(TAG, "Weird exception while closing input stream for " +
- mOriginalStoragePath + " (ignoring)", e);
- }
- try {
- if (out != null) {
- out.close();
- }
- } catch (Exception e) {
- Log_OC.d(TAG, "Weird exception while closing output stream for " +
- targetFile.getAbsolutePath() + " (ignoring)", e);
- }
- }
- }
- return result;
- }
- /**
- * TODO rewrite with homogeneous fail handling, remove dependency on {@link RemoteOperationResult},
- * TODO use Exceptions instead
- * <p>
- * TODO refactor both this and 'copy' in a single method
- *
- * @param sourceFile Source file to move.
- * @param targetFile Target location to move the file.
- * @return {@link RemoteOperationResult} result from remote operation
- * @throws IOException exception if file cannot be read/wrote
- */
- private void move(File sourceFile, File targetFile) throws IOException {
- if (!targetFile.equals(sourceFile)) {
- File expectedFolder = targetFile.getParentFile();
- expectedFolder.mkdirs();
- if (expectedFolder.isDirectory()) {
- if (!sourceFile.renameTo(targetFile)) {
- // try to copy and then delete
- targetFile.createNewFile();
- FileChannel inChannel = new FileInputStream(sourceFile).getChannel();
- FileChannel outChannel = new FileOutputStream(targetFile).getChannel();
- try {
- inChannel.transferTo(0, inChannel.size(), outChannel);
- sourceFile.delete();
- } catch (Exception e) {
- mFile.setStoragePath(""); // forget the local file
- // by now, treat this as a success; the file was uploaded
- // the best option could be show a warning message
- } finally {
- if (inChannel != null) {
- inChannel.close();
- }
- if (outChannel != null) {
- outChannel.close();
- }
- }
- }
- } else {
- mFile.setStoragePath("");
- }
- }
- }
- /**
- * Saves a OC File after a successful upload.
- * <p>
- * A PROPFIND is necessary to keep the props in the local database
- * synchronized with the server, specially the modification time and Etag
- * (where available)
- */
- private void saveUploadedFile(OwnCloudClient client) {
- OCFile file = mFile;
- if (file.fileExists()) {
- file = getStorageManager().getFileById(file.getFileId());
- }
- long syncDate = System.currentTimeMillis();
- file.setLastSyncDateForData(syncDate);
- // new PROPFIND to keep data consistent with server
- // in theory, should return the same we already have
- // TODO from the appropriate OC server version, get data from last PUT response headers, instead
- // TODO of a new PROPFIND; the latter may fail, specially for chunked uploads
- ReadRemoteFileOperation operation = new ReadRemoteFileOperation(getRemotePath());
- RemoteOperationResult result = operation.execute(client);
- if (result.isSuccess()) {
- updateOCFile(file, (RemoteFile) result.getData().get(0));
- file.setLastSyncDateForProperties(syncDate);
- } else {
- Log_OC.e(TAG, "Error reading properties of file after successful upload; this is gonna hurt...");
- }
- if (mWasRenamed) {
- OCFile oldFile = getStorageManager().getFileByPath(mOldFile.getRemotePath());
- if (oldFile != null) {
- oldFile.setStoragePath(null);
- getStorageManager().saveFile(oldFile);
- getStorageManager().saveConflict(oldFile, null);
- }
- // else: it was just an automatic renaming due to a name
- // coincidence; nothing else is needed, the storagePath is right
- // in the instance returned by mCurrentUpload.getFile()
- }
- file.setNeedsUpdateThumbnail(true);
- getStorageManager().saveFile(file);
- getStorageManager().saveConflict(file, null);
- FileDataStorageManager.triggerMediaScan(file.getStoragePath());
- // generate new Thumbnail
- final ThumbnailsCacheManager.ThumbnailGenerationTask task =
- new ThumbnailsCacheManager.ThumbnailGenerationTask(getStorageManager(), mAccount);
- task.execute(new ThumbnailsCacheManager.ThumbnailGenerationTaskObject(file, file.getRemoteId()));
- }
- private void updateOCFile(OCFile file, RemoteFile remoteFile) {
- file.setCreationTimestamp(remoteFile.getCreationTimestamp());
- file.setFileLength(remoteFile.getLength());
- file.setMimetype(remoteFile.getMimeType());
- file.setModificationTimestamp(remoteFile.getModifiedTimestamp());
- file.setModificationTimestampAtLastSyncForData(remoteFile.getModifiedTimestamp());
- file.setEtag(remoteFile.getEtag());
- file.setRemoteId(remoteFile.getRemoteId());
- }
- public interface OnRenameListener {
- void onRenameUpload();
- }
- }
|