From: Claudio Cambra Date: Sat, 18 Mar 2023 03:41:47 +0000 (+0100) Subject: Fix renaming directories remotely fixing local sync state in file provider X-Git-Tag: archive/raspbian/3.16.7-1_deb13u1+rpi1~1^2~12^2~10^2~55^2~49 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=05260795044bcfa9dda44443a34ea47119e94928;p=nextcloud-desktop.git Fix renaming directories remotely fixing local sync state in file provider Signed-off-by: Claudio Cambra --- diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager.swift index 438abe002..edf402dd2 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/Database/NextcloudFilesDatabaseManager.swift @@ -114,12 +114,9 @@ class NextcloudFilesDatabaseManager : NSObject { return itemMetadataFromOcId(ocId) } - private func processItemMetadatasToDelete(databaseToWriteTo: Realm, - existingMetadatas: Results, + private func processItemMetadatasToDelete(existingMetadatas: Results, updatedMetadatas: [NextcloudItemMetadataTable]) -> [NextcloudItemMetadataTable] { - assert(databaseToWriteTo.isInWriteTransaction) - var deletedMetadatas: [NextcloudItemMetadataTable] = [] for existingMetadata in existingMetadatas { @@ -129,23 +126,18 @@ class NextcloudFilesDatabaseManager : NSObject { deletedMetadatas.append(metadataToDelete) Logger.ncFilesDatabase.debug("Deleting item metadata during update. ocID: \(existingMetadata.ocId, privacy: .public), etag: \(existingMetadata.etag, privacy: .public), fileName: \(existingMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))") - - // Can't pass copies, we need the originals from the database - databaseToWriteTo.delete(ncDatabase().objects(NextcloudItemMetadataTable.self).filter("ocId == %@", metadataToDelete.ocId)) } return deletedMetadatas } - private func processItemMetadatasToUpdate(databaseToWriteTo: Realm, - existingMetadatas: Results, + private func processItemMetadatasToUpdate(existingMetadatas: Results, updatedMetadatas: [NextcloudItemMetadataTable], - updateDirectoryEtags: Bool) -> (newMetadatas: [NextcloudItemMetadataTable], updatedMetadatas: [NextcloudItemMetadataTable]) { - - assert(databaseToWriteTo.isInWriteTransaction) + updateDirectoryEtags: Bool) -> (newMetadatas: [NextcloudItemMetadataTable], updatedMetadatas: [NextcloudItemMetadataTable], directoriesNeedingRename: [NextcloudItemMetadataTable]) { var returningNewMetadatas: [NextcloudItemMetadataTable] = [] var returningUpdatedMetadatas: [NextcloudItemMetadataTable] = [] + var directoriesNeedingRename: [NextcloudItemMetadataTable] = [] for updatedMetadata in updatedMetadatas { if let existingMetadata = existingMetadatas.first(where: { $0.ocId == updatedMetadata.ocId }) { @@ -153,12 +145,20 @@ class NextcloudFilesDatabaseManager : NSObject { if existingMetadata.status == NextcloudItemMetadataTable.Status.normal.rawValue && !existingMetadata.isInSameDatabaseStoreableRemoteState(updatedMetadata) { - if !updateDirectoryEtags { - updatedMetadata.etag = existingMetadata.etag + if updatedMetadata.directory { + + if updatedMetadata.serverUrl != existingMetadata.serverUrl || updatedMetadata.fileName != existingMetadata.fileName { + + directoriesNeedingRename.append(NextcloudItemMetadataTable(value: updatedMetadata)) + updatedMetadata.etag = "" // Renaming doesn't change the etag so reset manually + + } else if !updateDirectoryEtags { + updatedMetadata.etag = existingMetadata.etag + } } - returningUpdatedMetadatas.append(NextcloudItemMetadataTable(value: updatedMetadata)) - databaseToWriteTo.add(updatedMetadata, update: .all) + returningUpdatedMetadatas.append(updatedMetadata) + Logger.ncFilesDatabase.debug("Updated existing item metadata. ocID: \(updatedMetadata.ocId, privacy: .public), etag: \(updatedMetadata.etag, privacy: .public), fileName: \(updatedMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))") } else { @@ -166,34 +166,54 @@ class NextcloudFilesDatabaseManager : NSObject { } } else { // This is a new metadata - returningNewMetadatas.append(NextcloudItemMetadataTable(value: updatedMetadata)) - databaseToWriteTo.add(updatedMetadata, update: .all) + returningNewMetadatas.append(updatedMetadata) Logger.ncFilesDatabase.debug("Created new item metadata during update. ocID: \(updatedMetadata.ocId, privacy: .public), etag: \(updatedMetadata.etag, privacy: .public), fileName: \(updatedMetadata.fileName, privacy: OSLogPrivacy.auto(mask: .hash))") } } - return (returningNewMetadatas, returningUpdatedMetadatas) + return (returningNewMetadatas, returningUpdatedMetadatas, directoriesNeedingRename) } func updateItemMetadatas(account: String, serverUrl: String, updatedMetadatas: [NextcloudItemMetadataTable], updateDirectoryEtags: Bool, completionHandler: @escaping(_ newMetadatas: [NextcloudItemMetadataTable]?, _ updatedMetadatas: [NextcloudItemMetadataTable]?, _ deletedMetadatas: [NextcloudItemMetadataTable]?) -> Void) { let database = ncDatabase() do { + let existingMetadatas = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl == %@ AND status == %@", account, serverUrl, NextcloudItemMetadataTable.Status.normal.rawValue) + + let metadatasToDelete = processItemMetadatasToDelete(existingMetadatas: existingMetadatas, + updatedMetadatas: updatedMetadatas) + + let metadatasToChange = processItemMetadatasToUpdate(existingMetadatas: existingMetadatas, + updatedMetadatas: updatedMetadatas, + updateDirectoryEtags: updateDirectoryEtags) + + var metadatasToUpdate = metadatasToChange.updatedMetadatas + let metadatasToCreate = metadatasToChange.newMetadatas + let directoriesNeedingRename = metadatasToChange.directoriesNeedingRename + + let metadatasToAdd = Array(metadatasToUpdate.map { NextcloudItemMetadataTable(value: $0) }) + + Array(metadatasToCreate.map { NextcloudItemMetadataTable(value: $0) }) + try database.write { - let existingMetadatas = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl == %@ AND status == %@", account, serverUrl, NextcloudItemMetadataTable.Status.normal.rawValue) + for metadata in metadatasToDelete { + // Can't pass copies, we need the originals from the database + database.delete(ncDatabase().objects(NextcloudItemMetadataTable.self).filter("ocId == %@", metadata.ocId)) + } - let deletedMetadatas = processItemMetadatasToDelete(databaseToWriteTo: database, - existingMetadatas: existingMetadatas, - updatedMetadatas: updatedMetadatas) + for metadata in metadatasToAdd { + database.add(metadata, update: .all) + } - let metadatasFromUpdate = processItemMetadatasToUpdate(databaseToWriteTo: database, - existingMetadatas: existingMetadatas, - updatedMetadatas: updatedMetadatas, - updateDirectoryEtags: updateDirectoryEtags) + } - completionHandler(metadatasFromUpdate.newMetadatas, metadatasFromUpdate.updatedMetadatas, deletedMetadatas) + for metadata in directoriesNeedingRename { + if let updatedDirectoryChildren = renameDirectoryAndPropagateToChildren(ocId: metadata.ocId, newServerUrl: metadata.serverUrl, newFileName: metadata.fileName) { + metadatasToUpdate += updatedDirectoryChildren + } } + + completionHandler(metadatasToCreate, metadatasToUpdate, metadatasToDelete) } catch let error { Logger.ncFilesDatabase.error("Could not update any item metadatas, received error: \(error.localizedDescription, privacy: .public)") completionHandler(nil, nil, nil) @@ -366,23 +386,22 @@ class NextcloudFilesDatabaseManager : NSObject { } } - func renameDirectoryAndPropagateToChildren(ocId: String, newServerUrl: String, newFileName: String) { + func renameDirectoryAndPropagateToChildren(ocId: String, newServerUrl: String, newFileName: String) -> [NextcloudItemMetadataTable]? { let database = ncDatabase() - do { - guard let directoryMetadata = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@ AND directory == true", ocId).first else { - Logger.ncFilesDatabase.error("Could not find a directory with ocID \(ocId, privacy: .public), cannot proceed with recursive renaming") - return - } - - let oldServerUrl = directoryMetadata.serverUrl + "/" + directoryMetadata.fileName + guard let directoryMetadata = database.objects(NextcloudItemMetadataTable.self).filter("ocId == %@ AND directory == true", ocId).first else { + Logger.ncFilesDatabase.error("Could not find a directory with ocID \(ocId, privacy: .public), cannot proceed with recursive renaming") + return nil + } - let childItemResults = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryMetadata.account, oldServerUrl) + let oldServerUrl = directoryMetadata.serverUrl + "/" + directoryMetadata.fileName + let childItemResults = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryMetadata.account, oldServerUrl) - renameItemMetadata(ocId: ocId, newServerUrl: newServerUrl, newFileName: newFileName) - Logger.ncFilesDatabase.debug("Renamed root renaming directory") + renameItemMetadata(ocId: ocId, newServerUrl: newServerUrl, newFileName: newFileName) + Logger.ncFilesDatabase.debug("Renamed root renaming directory") + do { try database.write { for childItem in childItemResults { let oldServerUrl = childItem.serverUrl @@ -394,7 +413,12 @@ class NextcloudFilesDatabaseManager : NSObject { } } catch let error { Logger.ncFilesDatabase.error("Could not rename directory metadata with ocId: \(ocId, privacy: .public) to new serverUrl: \(newServerUrl), received error: \(error.localizedDescription, privacy: .public)") + + return nil } + + let updatedChildItemResults = database.objects(NextcloudItemMetadataTable.self).filter("account == %@ AND serverUrl BEGINSWITH %@", directoryMetadata.account, newServerUrl) + return sortedItemMetadatas(updatedChildItemResults) } func localFileMetadataFromOcId(_ ocId: String) -> NextcloudLocalFileMetadataTable? { diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift index 952c37307..711255dcb 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderEnumerator.swift @@ -520,12 +520,7 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { var updatedDirectories: [NextcloudItemMetadataTable] = [] for updatedMetadata in allUpdatedMetadatas { if updatedMetadata.directory { - guard let directoryMetadata = dbManager.directoryMetadata(ocId: updatedMetadata.ocId) else { - Logger.enumeration.error("Could not find matching directory metadata for updated item metadata, cannot scan for updates") - continue - } - - updatedDirectories.append(directoryMetadata) + updatedDirectories.append(updatedMetadata) } } @@ -610,6 +605,11 @@ class FileProviderEnumerator: NSObject, NSFileProviderEnumerator { dbManager.addItemMetadata(directoryMetadata) } + // Don't update the etags for folders as we haven't checked their contents. + // When we do a recursive check, if we update the etags now, we will think + // that our local copies are up to date -- instead, leave them as the old. + // They will get updated when they are the subject of a readServerUrl call. + // (See above) dbManager.updateItemMetadatas(account: ncKitAccount, serverUrl: serverUrl, updatedMetadatas: metadatas, updateDirectoryEtags: false) { newMetadatas, updatedMetadatas, deletedMetadatas in completionHandler(metadatas, newMetadatas, updatedMetadatas, deletedMetadatas, nil) }