diff --git a/app/src/main/java/com/nextcloud/utils/extensions/FileDataStorageManagerExtensions.kt b/app/src/main/java/com/nextcloud/utils/extensions/FileDataStorageManagerExtensions.kt index fab3fe145c54..437b3c32eda7 100644 --- a/app/src/main/java/com/nextcloud/utils/extensions/FileDataStorageManagerExtensions.kt +++ b/app/src/main/java/com/nextcloud/utils/extensions/FileDataStorageManagerExtensions.kt @@ -17,6 +17,7 @@ import com.owncloud.android.lib.resources.files.model.RemoteFile import com.owncloud.android.lib.resources.shares.OCShare import com.owncloud.android.lib.resources.status.OCCapability import com.owncloud.android.utils.FileStorageUtils +import com.owncloud.android.utils.MimeType import com.owncloud.android.utils.MimeTypeUtil import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -185,6 +186,36 @@ fun FileDataStorageManager.moveFiles(ocFile: OCFile?, targetPath: String, target } } +fun FileDataStorageManager.createDirectoryTree(remotePath: String, createdRemoteFolder: RemoteFile?) { + if (getFileByEncryptedRemotePath(FileStorageUtils.getParentPath(remotePath)) == null) { + // When parent of remote path is not created + val subFolders = remotePath.split(OCFile.PATH_SEPARATOR.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() + var composedRemotePath = OCFile.ROOT_PATH + + // For each ancestor folders create them recursively + for (subFolder in subFolders) { + if (subFolder.isNotEmpty()) { + composedRemotePath = composedRemotePath + subFolder + OCFile.PATH_SEPARATOR + createDirectoryTree(composedRemotePath, createdRemoteFolder) + } + } + } else { + // Create directory on DB + with(OCFile(remotePath)) { + mimeType = MimeType.DIRECTORY + val parentId: Long = getFileByEncryptedRemotePath(FileStorageUtils.getParentPath(remotePath)).getFileId() + setParentId(parentId) + remoteId = createdRemoteFolder?.remoteId + modificationTimestamp = System.currentTimeMillis() + isEncrypted = FileStorageUtils.checkEncryptionStatus(this, this@createDirectoryTree) + permissions = createdRemoteFolder?.permissions + saveFile(this) + } + + Log_OC.d(FileDataStorageManager.TAG, "createDirectoryTree: created $remotePath in Database") + } +} + @Suppress("ReturnCount") private fun moveLocalFiles(accountName: String, ocFile: OCFile, defaultSavePath: String, targetPath: String): Boolean { val localFile = File(FileStorageUtils.getDefaultSavePathFor(accountName, ocFile)) diff --git a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java index 6c57e9965b23..d00963f31ba2 100644 --- a/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/CreateFolderOperation.java @@ -18,6 +18,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.utils.e2ee.E2ECounterHelper; import com.nextcloud.utils.e2ee.E2EVersionHelper; +import com.nextcloud.utils.extensions.FileDataStorageManagerExtensionsKt; import com.nextcloud.utils.extensions.OCFileExtensionsKt; import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; @@ -552,33 +553,7 @@ private void onCreateRemoteFolderOperationFinish(RemoteOperationResult result) { * Save new directory in local database. */ private void saveFolderInDB() { - if (getStorageManager().getFileByPath(FileStorageUtils.getParentPath(remotePath)) == null) { - // When parent of remote path is not created - String[] subFolders = remotePath.split(PATH_SEPARATOR); - String composedRemotePath = ROOT_PATH; - - // For each ancestor folders create them recursively - for (String subFolder : subFolders) { - if (!subFolder.isEmpty()) { - composedRemotePath = composedRemotePath + subFolder + PATH_SEPARATOR; - remotePath = composedRemotePath; - saveFolderInDB(); - } - } - } else { - // Create directory on DB - OCFile newDir = new OCFile(remotePath); - newDir.setMimeType(MimeType.DIRECTORY); - long parentId = getStorageManager().getFileByPath(FileStorageUtils.getParentPath(remotePath)).getFileId(); - newDir.setParentId(parentId); - newDir.setRemoteId(createdRemoteFolder.getRemoteId()); - newDir.setModificationTimestamp(System.currentTimeMillis()); - newDir.setEncrypted(FileStorageUtils.checkEncryptionStatus(newDir, getStorageManager())); - newDir.setPermissions(createdRemoteFolder.getPermissions()); - getStorageManager().saveFile(newDir); - - Log_OC.d(TAG, "Create directory " + remotePath + " in Database"); - } + FileDataStorageManagerExtensionsKt.createDirectoryTree(getStorageManager(), remotePath, createdRemoteFolder); } public String getRemotePath() { diff --git a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java index c71fe7d504a6..0fc9dc253044 100644 --- a/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java +++ b/app/src/main/java/com/owncloud/android/operations/UploadFileOperation.java @@ -27,6 +27,7 @@ import com.nextcloud.utils.autoRename.AutoRename; import com.nextcloud.utils.e2ee.E2ECounterHelper; import com.nextcloud.utils.e2ee.E2EVersionHelper; +import com.nextcloud.utils.extensions.FileDataStorageManagerExtensionsKt; import com.nextcloud.utils.extensions.RemoteOperationResultExtensionsKt; import com.owncloud.android.datamodel.ArbitraryDataProvider; import com.owncloud.android.datamodel.ArbitraryDataProviderImpl; @@ -55,6 +56,7 @@ import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation; import com.owncloud.android.lib.resources.files.UploadFileRemoteOperation; import com.owncloud.android.lib.resources.files.model.RemoteFile; +import com.owncloud.android.lib.resources.status.NextcloudVersion; import com.owncloud.android.lib.resources.status.OCCapability; import com.owncloud.android.operations.common.SyncOperation; import com.owncloud.android.operations.e2e.E2EClientData; @@ -474,45 +476,58 @@ protected RemoteOperationResult run(OwnCloudClient client) { Log_OC.d(TAG, "parent lookup for path: " + remoteParentPath + " → " + (parent == null ? "not found in DB" : "found, id=" + parent.getFileId())); - final boolean isResumingEncryptedUpload = (mFolderUnlockToken != null && !mFolderUnlockToken.isEmpty()); - if (!isResumingEncryptedUpload && (parent == null || mRemoteFolderToBeCreated)) { - Log_OC.d(TAG, "verifying remote parent folder exists: " + remoteParentPath); - final var result = grantFolderExistence(remoteParentPath, client); - if (!result.isSuccess()) { - Log_OC.e(TAG, "grantFolderExistence failed for: " + remoteParentPath + ", code: " + - result.getCode() + ", message: " + result.getMessage()); - return result; + // Create folders only for Nextcloud < 32; 32+ handles this automatically. + if (getCapabilities().getVersion().isOlderThan(NextcloudVersion.nextcloud_32)) { + final boolean isResumingEncryptedUpload = (mFolderUnlockToken != null && !mFolderUnlockToken.isEmpty()); + if (!isResumingEncryptedUpload && (parent == null || mRemoteFolderToBeCreated)) { + Log_OC.d(TAG, "verifying remote parent folder exists: " + remoteParentPath); + final var result = grantFolderExistence(remoteParentPath, client); + + if (!result.isSuccess()) { + Log_OC.e(TAG, "grantFolderExistence failed for: " + remoteParentPath + ", code: " + + result.getCode() + ", message: " + result.getMessage()); + return result; + } + + parent = getStorageManager().getFileByPath(remoteParentPath); + if (parent == null) { + Log_OC.e(TAG, "parent still null after grantFolderExistence: " + remoteParentPath); + return new RemoteOperationResult<>(ResultCode.UNKNOWN_ERROR); + } + + Log_OC.d(TAG, "remote parent folder confirmed: " + remoteParentPath + ", id=" + parent.getFileId()); } - parent = getStorageManager().getFileByPath(remoteParentPath); if (parent == null) { - Log_OC.e(TAG, "parent still null after grantFolderExistence: " + remoteParentPath); - return new RemoteOperationResult<>(ResultCode.UNKNOWN_ERROR); + Log_OC.e(TAG, "parent is null, cannot proceed: " + remoteParentPath + "," + " unlock token: " + mFolderUnlockToken); + return new RemoteOperationResult<>(false, "Parent folder not found", HttpStatus.SC_NOT_FOUND); } - - Log_OC.d(TAG, "remote parent folder confirmed: " + remoteParentPath + ", id=" + parent.getFileId()); } - if (parent == null) { - Log_OC.e(TAG, "parent is null, cannot proceed: " + remoteParentPath + "," + " unlock token: " + mFolderUnlockToken); - return new RemoteOperationResult<>(false, "Parent folder not found", HttpStatus.SC_NOT_FOUND); - } - - // - resume of encrypted upload, then parent file exists already as unlock is only for direct parent - mFile.setParentId(parent.getFileId()); - // check if any parent is encrypted encryptedAncestor = FileStorageUtils.checkEncryptionStatus(parent, getStorageManager()); mFile.setEncrypted(encryptedAncestor); + if (encryptedAncestor && parent != null) { + // - resume of encrypted upload, then parent file exists already as unlock is only for direct parent + mFile.setParentId(parent.getFileId()); + } + RemoteOperationResult result; if (encryptedAncestor) { Log_OC.d(TAG, "⬆️🔗" + "encrypted upload"); - return encryptedUpload(client, parent); + result = encryptedUpload(client, parent); } else { Log_OC.d(TAG, "⬆️" + "normal upload"); - return normalUpload(client); + result = normalUpload(client); } + + if (result.isSuccess() && getCapabilities().getVersion().isNewerOrEqual(NextcloudVersion.nextcloud_32)) { + // Add the folders that the server creates automatically (from Nextcloud 32) to local db + FileDataStorageManagerExtensionsKt.createDirectoryTree(getStorageManager(), remoteParentPath, null); + } + + return result; } // region E2E Upload