@@ -761,7 +761,7 @@ void FolderMan::saveFolder(Folder *folder)
761761 saveFolder (folder, settings);
762762}
763763
764- Folder *FolderMan::folderForPath (const QString &path, QString *relativePath)
764+ Folder *FolderMan::folderForPath (const QString &path, QString *relativePath) const
765765{
766766 QString absolutePath = QDir::cleanPath (path) + QLatin1Char (' /' );
767767
@@ -912,29 +912,40 @@ static QString canonicalPath(const QString &path)
912912
913913static QString checkPathForSyncRootMarkingRecursive (const QString &path, FolderMan::NewFolderType folderType, const QUuid &accountUuid)
914914{
915+ // First do basic checks if this path is usable
916+ const QFileInfo selectedPathInfo (path);
917+ if (!selectedPathInfo.isDir ()) {
918+ return FolderMan::tr (" The selected path is not a folder." );
919+ }
920+
921+ if (numberOfSyncJournals (selectedPathInfo.filePath ()) != 0 ) {
922+ return FolderMan::tr (" The folder %1 is used in a folder sync connection." ).arg (QDir::toNativeSeparators (selectedPathInfo.filePath ()));
923+ }
924+
925+ // Check for sync root markings in this folder
915926 std::pair<QString, QUuid> existingTags = Utility::getDirectorySyncRootMarkings (path);
916927 if (!existingTags.first .isEmpty ()) {
917928 if (existingTags.first != Theme::instance ()->orgDomainName ()) {
918929 // another application uses this as spaces root folder
919- return FolderMan::tr (" Folder '%1' is already in use by application %2! " ).arg (path, existingTags.first );
930+ return FolderMan::tr (" Folder '%1' is already in use by application %2. " ).arg (path, existingTags.first );
920931 }
921932
922933 // Looks good, it's our app, let's check the account tag:
923934 switch (folderType) {
924935 case FolderMan::NewFolderType::SpacesFolder:
925936 if (existingTags.second == accountUuid) {
926- // Nice, that's what we like, the sync root for our account in our app. No error.
937+ // Nice, that's what we like, the sync root for our account in our app. No error, and we don't need to check the parent folders .
927938 return {};
928939 }
929940 [[fallthrough]];
930- case FolderMan::NewFolderType::OC10SyncRoot:
931- [[fallthrough]];
932941 case FolderMan::NewFolderType::SpacesSyncRoot:
933942 // It's our application but we don't want to create a spaces folder, so it must be another space root
934943 return FolderMan::tr (" Folder '%1' is already in use by another account." ).arg (path);
935944 }
936945 }
937946
947+ // This folder is ok, but check the parent folders if they are used
948+
938949 QString parent = QFileInfo (path).path ();
939950 if (parent == path) { // root dir, stop recursing
940951 return {};
@@ -943,51 +954,7 @@ static QString checkPathForSyncRootMarkingRecursive(const QString &path, FolderM
943954 return checkPathForSyncRootMarkingRecursive (parent, folderType, accountUuid);
944955}
945956
946- QString FolderMan::checkPathValidityRecursive (const QString &path, FolderMan::NewFolderType folderType, const QUuid &accountUuid)
947- {
948- if (path.isEmpty ()) {
949- return FolderMan::tr (" No valid folder selected!" );
950- }
951-
952- #ifdef Q_OS_WIN
953- Utility::NtfsPermissionLookupRAII ntfs_perm;
954- #endif
955-
956- auto pathLengthCheck = Folder::checkPathLength (path);
957- if (!pathLengthCheck) {
958- return pathLengthCheck.error ();
959- }
960-
961- const QFileInfo selectedPathInfo (path);
962- if (!selectedPathInfo.exists ()) {
963- const QString parentPath = selectedPathInfo.path ();
964- if (parentPath != path) {
965- return checkPathValidityRecursive (parentPath, folderType, accountUuid);
966- }
967- return FolderMan::tr (" The selected path does not exist!" );
968- }
969-
970- if (numberOfSyncJournals (selectedPathInfo.filePath ()) != 0 ) {
971- return FolderMan::tr (" The folder %1 is used in a folder sync connection!" ).arg (QDir::toNativeSeparators (selectedPathInfo.filePath ()));
972- }
973-
974- // At this point we know there is no syncdb in the parent hierarchy, check for spaces sync root.
975-
976- if (!selectedPathInfo.isDir ()) {
977- return FolderMan::tr (" The selected path is not a folder!" );
978- }
979-
980- if (!selectedPathInfo.isWritable ()) {
981- return FolderMan::tr (" You have no permission to write to the selected folder!" );
982- }
983-
984- return checkPathForSyncRootMarkingRecursive (path, folderType, accountUuid);
985- }
986-
987957/*
988- * OC10 folder:
989- * - sync root not in syncdb folder
990- * - sync root not in spaces root
991958 * with spaces:
992959 * - spaces sync root not in syncdb folder
993960 * - spaces sync root not in another spaces sync root
@@ -996,41 +963,71 @@ QString FolderMan::checkPathValidityRecursive(const QString &path, FolderMan::Ne
996963 * - space *can* be in sync root
997964 * - space not in spaces sync root of other account (check with account uuid)
998965 */
999- QString FolderMan::checkPathValidityForNewFolder (const QString &path, NewFolderType folderType, const QUuid &accountUuid) const
966+ QString FolderMan::checkPathValidity (const QString &path, NewFolderType folderType, const QUuid &accountUuid) const
1000967{
1001- // check if the local directory isn't used yet in another ownCloud sync
968+ // Do checks against existing folders. This catches cases where:
969+ // - the user deleted a folder from the filesystem, but there is still a folder sync connection in the configuration
970+ // - check if this folder contains other folders for spaces
971+ // If so, error out.
1002972 const auto cs = Utility::fsCaseSensitivity ();
1003-
1004973 const QString userDir = QDir::cleanPath (canonicalPath (path)) + QLatin1Char (' /' );
1005974 for (auto f : folders ()) {
1006975 const QString folderDir = QDir::cleanPath (canonicalPath (f->path ())) + QLatin1Char (' /' );
1007-
1008976 if (QString::compare (folderDir, userDir, cs) == 0 ) {
1009- return tr (" There is already a sync from the server to this local folder. "
1010- " Please pick another local folder!" );
977+ return tr (" There is already a sync from the server to this local folder." );
1011978 }
1012979 if (FileSystem::isChildPathOf (folderDir, userDir)) {
1013- return tr (" The local folder %1 already contains a folder used in a folder sync connection. "
1014- " Please pick another local folder!" )
980+ return tr (" The local folder %1 already contains a folder used in a folder sync connection." )
1015981 .arg (QDir::toNativeSeparators (path));
1016982 }
1017983
1018984 if (FileSystem::isChildPathOf (userDir, folderDir)) {
1019- return tr (" The local folder %1 is already contained in a folder used in a folder sync connection. "
1020- " Please pick another local folder!" )
985+ return tr (" The local folder %1 is already contained in a folder used in a folder sync connection." )
1021986 .arg (QDir::toNativeSeparators (path));
1022987 }
1023988 }
1024989
1025- const auto result = checkPathValidityRecursive (path, folderType, accountUuid);
1026- if (!result.isEmpty ()) {
1027- return tr (" %1 Please pick another local folder!" ).arg (result);
990+ // Now run filesystem based checks
991+ return findExistingFolderAndCheckValidity (path, folderType, accountUuid);
992+ }
993+
994+ QString FolderMan::findExistingFolderAndCheckValidity (const QString &path, NewFolderType folderType, const QUuid &accountUuid)
995+ {
996+ if (path.isEmpty ()) {
997+ return tr (" No valid folder selected." );
1028998 }
1029- return {};
999+
1000+ #ifdef Q_OS_WIN
1001+ Utility::NtfsPermissionLookupRAII ntfs_perm;
1002+ #endif
1003+
1004+ auto pathLengthCheck = Folder::checkPathLength (path);
1005+ if (!pathLengthCheck) {
1006+ return pathLengthCheck.error ();
1007+ }
1008+
1009+ // If this is a new folder, recurse up to the first parent that exists, to see if we can use that to create a new folder
1010+ const QFileInfo selectedPathInfo (path);
1011+ if (!selectedPathInfo.exists ()) {
1012+ const QString parentPath = selectedPathInfo.path ();
1013+ if (parentPath != path) {
1014+ return findExistingFolderAndCheckValidity (parentPath, folderType, accountUuid);
1015+ }
1016+ return tr (" The selected path does not exist." );
1017+ }
1018+
1019+ // At this point we have an existing folder, so check if we can create files/folders here.
1020+ // Note: we don't need to write to any parent, so we don't need to check writablility when traversing the parents.
1021+ if (!selectedPathInfo.isWritable ()) {
1022+ return tr (" You have no permission to write to the selected folder." );
1023+ }
1024+
1025+ // Now check if none of the parents is already used.
1026+ return checkPathForSyncRootMarkingRecursive (canonicalPath (path), folderType, accountUuid);
10301027}
10311028
10321029QString FolderMan::findGoodPathForNewSyncFolder (
1033- const QString &basePath, const QString &newFolder, FolderMan::NewFolderType folderType, const QUuid &accountUuid)
1030+ const QString &basePath, const QString &newFolder, FolderMan::NewFolderType folderType, const QUuid &accountUuid) const
10341031{
10351032 OC_ASSERT (!accountUuid.isNull () || folderType == FolderMan::NewFolderType::SpacesSyncRoot);
10361033
@@ -1041,7 +1038,7 @@ QString FolderMan::findGoodPathForNewSyncFolder(
10411038 // possibly find a valid sync folder inside it.
10421039 // Example: Someone syncs their home directory. Then ~/foobar is not
10431040 // going to be an acceptable sync folder path for any value of foobar.
1044- if (FolderMan::instance ()-> folderForPath (QFileInfo (normalisedPath).canonicalPath ())) {
1041+ if (folderForPath (QFileInfo (normalisedPath).canonicalPath ())) {
10451042 // Any path with that parent is going to be unacceptable,
10461043 // so just keep it as-is.
10471044 return canonicalPath (normalisedPath);
@@ -1050,7 +1047,7 @@ QString FolderMan::findGoodPathForNewSyncFolder(
10501047 {
10511048 QString folder = normalisedPath;
10521049 for (int attempt = 2 ; attempt <= 100 ; ++attempt) {
1053- if (!QFileInfo::exists (folder) && FolderMan::instance ()-> checkPathValidityForNewFolder (folder, folderType, accountUuid).isEmpty ()) {
1050+ if (!QFileInfo::exists (folder) && checkPathValidity (folder, folderType, accountUuid).isEmpty ()) {
10541051 return canonicalPath (folder);
10551052 }
10561053 folder = normalisedPath + QStringLiteral (" (%1)" ).arg (attempt);
0 commit comments