X-Git-Url: http://git.linex4red.de/pub/Android/ownCloud.git/blobdiff_plain/c301865c351da2c46c82cca268c0d7e32bc2fd83..c2abbaaedb69dba35866a48b745b68f3519cbca1:/src/com/owncloud/android/operations/SynchronizeFolderOperation.java diff --git a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java index 12e7f3f0..25f7ed35 100644 --- a/src/com/owncloud/android/operations/SynchronizeFolderOperation.java +++ b/src/com/owncloud/android/operations/SynchronizeFolderOperation.java @@ -1,10 +1,9 @@ /* ownCloud Android client application - * Copyright (C) 2012 Bartek Przybylski + * Copyright (C) 2012-2013 ownCloud Inc. * * 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. + * 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 @@ -18,22 +17,32 @@ package com.owncloud.android.operations; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Vector; import org.apache.http.HttpStatus; +import org.apache.jackrabbit.webdav.DavConstants; import org.apache.jackrabbit.webdav.MultiStatus; import org.apache.jackrabbit.webdav.client.methods.PropFindMethod; -import android.accounts.Account; -import android.content.Context; -import android.util.Log; - +import com.owncloud.android.Log_OC; import com.owncloud.android.datamodel.DataStorageManager; import com.owncloud.android.datamodel.OCFile; import com.owncloud.android.operations.RemoteOperationResult.ResultCode; import com.owncloud.android.utils.FileStorageUtils; +import android.accounts.Account; +import android.content.Context; + + import eu.alefzero.webdav.WebdavClient; import eu.alefzero.webdav.WebdavEntry; import eu.alefzero.webdav.WebdavUtils; @@ -72,6 +81,8 @@ public class SynchronizeFolderOperation extends RemoteOperation { private int mConflictsFound; private int mFailsInFavouritesFound; + + private Map mForgottenLocalFiles; public SynchronizeFolderOperation( String remotePath, @@ -86,6 +97,7 @@ public class SynchronizeFolderOperation extends RemoteOperation { mStorageManager = dataStorageManager; mAccount = account; mContext = context; + mForgottenLocalFiles = new HashMap(); } @@ -97,6 +109,10 @@ public class SynchronizeFolderOperation extends RemoteOperation { return mFailsInFavouritesFound; } + public Map getForgottenLocalFiles() { + return mForgottenLocalFiles; + } + /** * Returns the list of files and folders contained in the synchronized folder, if called after synchronization is complete. * @@ -112,14 +128,17 @@ public class SynchronizeFolderOperation extends RemoteOperation { RemoteOperationResult result = null; mFailsInFavouritesFound = 0; mConflictsFound = 0; + mForgottenLocalFiles.clear(); // code before in FileSyncAdapter.fetchData PropFindMethod query = null; try { - Log.d(TAG, "Synchronizing " + mAccount.name + ", fetching files in " + mRemotePath); + Log_OC.d(TAG, "Synchronizing " + mAccount.name + ", fetching files in " + mRemotePath); // remote request - query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath)); + query = new PropFindMethod(client.getBaseUri() + WebdavUtils.encodePath(mRemotePath), + DavConstants.PROPFIND_ALL_PROP, + DavConstants.DEPTH_1); int status = client.executeMethod(query); // check and process response - /// TODO take into account all the possible status per child-resource @@ -138,27 +157,42 @@ public class SynchronizeFolderOperation extends RemoteOperation { List updatedFiles = new Vector(resp.getResponses().length - 1); List filesToSyncContents = new Vector(); for (int i = 1; i < resp.getResponses().length; ++i) { + /// new OCFile instance with the data from the server WebdavEntry we = new WebdavEntry(resp.getResponses()[i], client.getBaseUri().getPath()); OCFile file = fillOCFile(we); + + /// set data about local state, keeping unchanged former data if existing + file.setLastSyncDateForProperties(mCurrentSyncTime); OCFile oldFile = mStorageManager.getFileByPath(file.getRemotePath()); if (oldFile != null) { file.setKeepInSync(oldFile.keepInSync()); file.setLastSyncDateForData(oldFile.getLastSyncDateForData()); - if (file.keepInSync()) { - //disableObservance(file); // first disable observer so we won't get file upload right after download - // // now, the FileDownloader service sends a broadcast before start a download; the FileObserverService is listening for it - //requestFileSynchronization(file, oldFile, client); - SynchronizeFileOperation operation = new SynchronizeFileOperation( oldFile, - file, - mStorageManager, - mAccount, - true, - false, - mContext - ); - filesToSyncContents.add(operation); + file.setModificationTimestampAtLastSyncForData(oldFile.getModificationTimestampAtLastSyncForData()); // must be kept unchanged when the file contents are not updated + checkAndFixForeignStoragePath(oldFile); + file.setStoragePath(oldFile.getStoragePath()); + } + + /// scan default location if local copy of file is not linked in OCFile instance + if (file.getStoragePath() == null && !file.isDirectory()) { + File f = new File(FileStorageUtils.getDefaultSavePathFor(mAccount.name, file)); + if (f.exists()) { + file.setStoragePath(f.getAbsolutePath()); + file.setLastSyncDateForData(f.lastModified()); } } + + /// prepare content synchronization for kept-in-sync files + if (file.keepInSync()) { + SynchronizeFileOperation operation = new SynchronizeFileOperation( oldFile, + file, + mStorageManager, + mAccount, + true, + false, + mContext + ); + filesToSyncContents.add(operation); + } updatedFiles.add(file); } @@ -178,9 +212,9 @@ public class SynchronizeFolderOperation extends RemoteOperation { } else { mFailsInFavouritesFound++; if (contentsResult.getException() != null) { - Log.d(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage(), contentsResult.getException()); + Log_OC.e(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage(), contentsResult.getException()); } else { - Log.d(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage()); + Log_OC.e(TAG, "Error while synchronizing favourites : " + contentsResult.getLogMessage()); } } } // won't let these fails break the synchronization process @@ -194,7 +228,7 @@ public class SynchronizeFolderOperation extends RemoteOperation { for (int i=0; i < mChildren.size(); ) { file = mChildren.get(i); if (file.getLastSyncDateForProperties() != mCurrentSyncTime) { - Log.d(TAG, "removing file: " + file); + Log_OC.d(TAG, "removing file: " + file); mStorageManager.removeFile(file, (file.isDown() && file.getStoragePath().startsWith(currentSavePath))); mChildren.remove(i); } else { @@ -212,21 +246,30 @@ public class SynchronizeFolderOperation extends RemoteOperation { result = new RemoteOperationResult(ResultCode.SYNC_CONFLICT); // should be different result, but will do the job } else { - result = new RemoteOperationResult(true, status); + result = new RemoteOperationResult(true, status, query.getResponseHeaders()); } } else { - result = new RemoteOperationResult(false, status); + result = new RemoteOperationResult(false, status, query.getResponseHeaders()); } - Log.i(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage()); + } catch (Exception e) { result = new RemoteOperationResult(e); - Log.e(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage(), result.getException()); + } finally { if (query != null) query.releaseConnection(); // let the connection available for other methods + if (result.isSuccess()) { + Log_OC.i(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage()); + } else { + if (result.isException()) { + Log_OC.e(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage(), result.getException()); + } else { + Log_OC.e(TAG, "Synchronizing " + mAccount.name + ", folder " + mRemotePath + ": " + result.getLogMessage()); + } + } } return result; @@ -249,11 +292,73 @@ public class SynchronizeFolderOperation extends RemoteOperation { file.setCreationTimestamp(we.createTimestamp()); file.setFileLength(we.contentLength()); file.setMimetype(we.contentType()); - file.setModificationTimestamp(we.modifiedTimesamp()); - file.setLastSyncDateForProperties(mCurrentSyncTime); + file.setModificationTimestamp(we.modifiedTimestamp()); file.setParentId(mParentId); return file; } + /** + * Checks the storage path of the OCFile received as parameter. If it's out of the local ownCloud folder, + * tries to copy the file inside it. + * + * If the copy fails, the link to the local file is nullified. The account of forgotten files is kept in + * {@link #mForgottenLocalFiles} + * + * @param file File to check and fix. + */ + private void checkAndFixForeignStoragePath(OCFile file) { + String storagePath = file.getStoragePath(); + String expectedPath = FileStorageUtils.getDefaultSavePathFor(mAccount.name, file); + if (storagePath != null && !storagePath.equals(expectedPath)) { + /// fix storagePaths out of the local ownCloud folder + File originalFile = new File(storagePath); + if (FileStorageUtils.getUsableSpace(mAccount.name) < originalFile.length()) { + mForgottenLocalFiles.put(file.getRemotePath(), storagePath); + file.setStoragePath(null); + + } else { + InputStream in = null; + OutputStream out = null; + try { + File expectedFile = new File(expectedPath); + File expectedParent = expectedFile.getParentFile(); + expectedParent.mkdirs(); + if (!expectedParent.isDirectory()) { + throw new IOException("Unexpected error: parent directory could not be created"); + } + expectedFile.createNewFile(); + if (!expectedFile.isFile()) { + throw new IOException("Unexpected error: target file could not be created"); + } + in = new FileInputStream(originalFile); + out = new FileOutputStream(expectedFile); + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0){ + out.write(buf, 0, len); + } + file.setStoragePath(expectedPath); + + } catch (Exception e) { + Log_OC.e(TAG, "Exception while copying foreign file " + expectedPath, e); + mForgottenLocalFiles.put(file.getRemotePath(), storagePath); + file.setStoragePath(null); + + } finally { + try { + if (in != null) in.close(); + } catch (Exception e) { + Log_OC.d(TAG, "Weird exception while closing input stream for " + storagePath + " (ignoring)", e); + } + try { + if (out != null) out.close(); + } catch (Exception e) { + Log_OC.d(TAG, "Weird exception while closing output stream for " + expectedPath + " (ignoring)", e); + } + } + } + } + } + }