From a8a44245682728ff44ea8205007778eef5231a37 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:11:22 +0100 Subject: [PATCH 1/7] handle metadata worker edge cases Signed-off-by: alperozturk --- .../nextcloud/client/database/dao/FileDao.kt | 2 +- .../client/jobs/metadata/MetadataWorker.kt | 72 +++++++++++++++---- 2 files changed, 58 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt b/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt index 06a94aaafdff..86d02064c7a3 100644 --- a/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt +++ b/app/src/main/java/com/nextcloud/client/database/dao/FileDao.kt @@ -79,7 +79,7 @@ interface FileDao { AND file_owner = :accountName AND is_encrypted = 0 AND (content_type = :dirType OR content_type = :webdavType) - ORDER BY ${ProviderTableMeta.FILE_DEFAULT_SORT_ORDER} + ORDER BY ${ProviderTableMeta._ID} ASC """ ) fun getNonEncryptedSubfolders( diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index b6e19b318846..2ba5ee016be8 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -29,34 +29,64 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri @Suppress("DEPRECATION", "ReturnCount") override suspend fun doWork(): Result { - val storageManager = FileDataStorageManager(user, context.contentResolver) val filePath = inputData.getString(FILE_PATH) if (filePath == null) { Log_OC.e(TAG, "❌ Invalid folder path. Aborting metadata sync. $filePath") return Result.failure() } + + val storageManager = FileDataStorageManager(user, context.contentResolver) val currentDir = storageManager.getFileByDecryptedRemotePath(filePath) if (currentDir == null) { Log_OC.e(TAG, "❌ Current directory is null. Aborting metadata sync. $filePath") return Result.failure() } - Log_OC.d(TAG, "🕒 Starting metadata sync for folder: $filePath") + if (currentDir.fileId <= 0) { + Log_OC.e(TAG, "❌ Current directory has invalid ID: ${currentDir.fileId}. Path: $filePath") + return Result.failure() + } + + Log_OC.d(TAG, "🕒 Starting metadata sync for folder: $filePath, id: ${currentDir.fileId}") + + // First check current dir + val currentRefreshResult = refreshFolder(currentDir, storageManager) + if (!currentRefreshResult) { + Log_OC.e(TAG, "❌ Failed to refresh current directory: $filePath") + return Result.failure() + } - // first check current dir - refreshFolder(currentDir, storageManager) + // Re-fetch the folder after refresh to get updated data + val refreshedDir = storageManager.getFileByPath(filePath) + if (refreshedDir == null || refreshedDir.fileId <= 0) { + Log_OC.e(TAG, "❌ Directory invalid after refresh. Path: $filePath") + return Result.failure() + } // then get up-to-date subfolders - val subfolders = storageManager.getNonEncryptedSubfolders(currentDir.fileId, user.accountName) + val subfolders = storageManager.getNonEncryptedSubfolders(refreshedDir.fileId, user.accountName) + Log_OC.d(TAG, "Found ${subfolders.size} subfolders to sync") + + var failedCount = 0 subfolders.forEach { subFolder -> - refreshFolder(subFolder, storageManager) + if (subFolder.fileId <= 0) { + Log_OC.e(TAG, "⚠️ Skipping subfolder with invalid ID: ${subFolder.remotePath}") + failedCount++ + return@forEach + } + + val success = refreshFolder(subFolder, storageManager) + if (!success) { + failedCount++ + } } - Log_OC.d(TAG, "🏁 Metadata sync completed for folder: $filePath") + Log_OC.d(TAG, "🏁 Metadata sync completed for folder: $filePath. Failed: $failedCount/${subfolders.size}") + return Result.success() } @Suppress("DEPRECATION") - private suspend fun refreshFolder(folder: OCFile, storageManager: FileDataStorageManager) = + private suspend fun refreshFolder(folder: OCFile, storageManager: FileDataStorageManager): Boolean = withContext(Dispatchers.IO) { Log_OC.d( TAG, @@ -65,19 +95,31 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri " eTag: " + folder.etag + "\n" + " eTagOnServer: " + folder.etagOnServer ) + if (folder.fileId <= 0) { + Log_OC.e(TAG, "❌ Folder has invalid ID: ${folder.remotePath}") + return@withContext false + } + if (!folder.isEtagChanged) { Log_OC.d(TAG, "Skipping ${folder.remotePath}, eTag didn't change") - return@withContext + return@withContext false } - Log_OC.d(TAG, "⏳ Fetching metadata for: ${folder.remotePath}") + Log_OC.d(TAG, "⏳ Fetching metadata for: ${folder.remotePath}, id: ${folder.fileId}") val operation = RefreshFolderOperation(folder, storageManager, user, context) - val result = operation.execute(user, context) - if (result.isSuccess) { - Log_OC.d(TAG, "✅ Successfully fetched metadata for: ${folder.remotePath}") - } else { - Log_OC.e(TAG, "❌ Failed to fetch metadata for: ${folder.remotePath}") + return@withContext try { + val result = operation.execute(user, context) + if (result.isSuccess) { + Log_OC.d(TAG, "✅ Successfully fetched metadata for: ${folder.remotePath}") + true + } else { + Log_OC.e(TAG, "❌ Failed to fetch metadata for: ${folder.remotePath}") + false + } + } catch (e: Exception) { + Log_OC.e(TAG, "❌ Exception refreshing folder ${folder.remotePath}: ${e.message}", e) + false } } } From 307960e5ff49954f495d94e0760ee13b3e4924ce Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:12:15 +0100 Subject: [PATCH 2/7] handle metadata worker edge cases Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index 2ba5ee016be8..c5110e71e852 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -19,6 +19,7 @@ import com.owncloud.android.operations.RefreshFolderOperation import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +@Suppress("DEPRECATION", "ReturnCount", "TooGenericExceptionCaught") class MetadataWorker(private val context: Context, params: WorkerParameters, private val user: User) : CoroutineWorker(context, params) { @@ -27,7 +28,6 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri const val FILE_PATH = "file_path" } - @Suppress("DEPRECATION", "ReturnCount") override suspend fun doWork(): Result { val filePath = inputData.getString(FILE_PATH) if (filePath == null) { From 6c0d88f38a0b735a19976c4eb295a701c86a9dea Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:25:26 +0100 Subject: [PATCH 3/7] handle metadata worker edge cases Signed-off-by: alperozturk --- .../com/nextcloud/client/jobs/metadata/MetadataWorker.kt | 8 ++++---- .../main/java/com/owncloud/android/datamodel/OCFile.java | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index c5110e71e852..134c93ab98c1 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -41,7 +41,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri Log_OC.e(TAG, "❌ Current directory is null. Aborting metadata sync. $filePath") return Result.failure() } - if (currentDir.fileId <= 0) { + if (currentDir.hasValidParentId()) { Log_OC.e(TAG, "❌ Current directory has invalid ID: ${currentDir.fileId}. Path: $filePath") return Result.failure() } @@ -57,7 +57,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri // Re-fetch the folder after refresh to get updated data val refreshedDir = storageManager.getFileByPath(filePath) - if (refreshedDir == null || refreshedDir.fileId <= 0) { + if (refreshedDir == null || refreshedDir.hasValidParentId()) { Log_OC.e(TAG, "❌ Directory invalid after refresh. Path: $filePath") return Result.failure() } @@ -68,7 +68,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri var failedCount = 0 subfolders.forEach { subFolder -> - if (subFolder.fileId <= 0) { + if (subFolder.hasValidParentId()) { Log_OC.e(TAG, "⚠️ Skipping subfolder with invalid ID: ${subFolder.remotePath}") failedCount++ return@forEach @@ -95,7 +95,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri " eTag: " + folder.etag + "\n" + " eTagOnServer: " + folder.etagOnServer ) - if (folder.fileId <= 0) { + if (folder.hasValidParentId()) { Log_OC.e(TAG, "❌ Folder has invalid ID: ${folder.remotePath}") return@withContext false } diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index 11455a2707d2..79638369f84f 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -1166,4 +1166,9 @@ public void setIsRecommendedFile(boolean value) { public boolean isRecommendedFile() { return recommendedFile; } + + // only root directories parent id can be 0 + public boolean hasValidParentId() { + return !isRootDirectory() && getParentId() != 0; + } } From 5b17836c5f6fd12e45ae55de3488ddc9621417a2 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:26:17 +0100 Subject: [PATCH 4/7] handle metadata worker edge cases Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index 134c93ab98c1..1d94fbe014c8 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -69,7 +69,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri var failedCount = 0 subfolders.forEach { subFolder -> if (subFolder.hasValidParentId()) { - Log_OC.e(TAG, "⚠️ Skipping subfolder with invalid ID: ${subFolder.remotePath}") + Log_OC.e(TAG, "❌ Skipping subfolder with invalid ID: ${subFolder.remotePath}") failedCount++ return@forEach } From 71391fe52245166bba9bfff2b2a4d19fe8123135 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:28:54 +0100 Subject: [PATCH 5/7] handle metadata worker edge cases Signed-off-by: alperozturk --- .../com/nextcloud/client/jobs/metadata/MetadataWorker.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index 1d94fbe014c8..30bedb87e978 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -41,7 +41,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri Log_OC.e(TAG, "❌ Current directory is null. Aborting metadata sync. $filePath") return Result.failure() } - if (currentDir.hasValidParentId()) { + if (!currentDir.hasValidParentId()) { Log_OC.e(TAG, "❌ Current directory has invalid ID: ${currentDir.fileId}. Path: $filePath") return Result.failure() } @@ -57,7 +57,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri // Re-fetch the folder after refresh to get updated data val refreshedDir = storageManager.getFileByPath(filePath) - if (refreshedDir == null || refreshedDir.hasValidParentId()) { + if (refreshedDir == null || !refreshedDir.hasValidParentId()) { Log_OC.e(TAG, "❌ Directory invalid after refresh. Path: $filePath") return Result.failure() } @@ -68,7 +68,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri var failedCount = 0 subfolders.forEach { subFolder -> - if (subFolder.hasValidParentId()) { + if (!subFolder.hasValidParentId()) { Log_OC.e(TAG, "❌ Skipping subfolder with invalid ID: ${subFolder.remotePath}") failedCount++ return@forEach @@ -95,7 +95,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri " eTag: " + folder.etag + "\n" + " eTagOnServer: " + folder.etagOnServer ) - if (folder.hasValidParentId()) { + if (!folder.hasValidParentId()) { Log_OC.e(TAG, "❌ Folder has invalid ID: ${folder.remotePath}") return@withContext false } From 050828f627f7e8cc2f30321736860022652cf1c6 Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:31:28 +0100 Subject: [PATCH 6/7] handle metadata worker edge cases Signed-off-by: alperozturk --- .../main/java/com/owncloud/android/datamodel/OCFile.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index 79638369f84f..a2e905cb2329 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -1169,6 +1169,10 @@ public boolean isRecommendedFile() { // only root directories parent id can be 0 public boolean hasValidParentId() { - return !isRootDirectory() && getParentId() != 0; + if (isRootDirectory()) { + return getParentId() == 0; + } else { + return getParentId() != 0; + } } } From dd0e339e21e4b496070c269dc8a9c87431bb060d Mon Sep 17 00:00:00 2001 From: alperozturk Date: Mon, 15 Dec 2025 15:33:34 +0100 Subject: [PATCH 7/7] handle metadata worker edge cases Signed-off-by: alperozturk --- .../java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt index 30bedb87e978..057268c7287f 100644 --- a/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt +++ b/app/src/main/java/com/nextcloud/client/jobs/metadata/MetadataWorker.kt @@ -102,7 +102,7 @@ class MetadataWorker(private val context: Context, params: WorkerParameters, pri if (!folder.isEtagChanged) { Log_OC.d(TAG, "Skipping ${folder.remotePath}, eTag didn't change") - return@withContext false + return@withContext true } Log_OC.d(TAG, "⏳ Fetching metadata for: ${folder.remotePath}, id: ${folder.fileId}")