From c0c68f3b0117c77dd834fde1a7bf7bcd93aba22f Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 11 Dec 2025 20:07:55 -0500 Subject: [PATCH] fix(vfs/cfapi): Preserve FILE_ATTRIBUTE_SYSTEM to prevent custom folder icons from being reset --- src/libsync/vfs/cfapi/cfapiwrapper.cpp | 27 ++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/libsync/vfs/cfapi/cfapiwrapper.cpp b/src/libsync/vfs/cfapi/cfapiwrapper.cpp index 2e878506825a8..b7836f5c0656f 100644 --- a/src/libsync/vfs/cfapi/cfapiwrapper.cpp +++ b/src/libsync/vfs/cfapi/cfapiwrapper.cpp @@ -417,6 +417,12 @@ OCC::Result updatePlaceholderStat OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &metadata.BasicInfo.LastAccessTime); OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &metadata.BasicInfo.ChangeTime); + // Preserve existing file attributes (especially FILE_ATTRIBUTE_SYSTEM for custom folder icons) + const auto currentAttributes = GetFileAttributesW(reinterpret_cast(path.utf16())); + if (currentAttributes != INVALID_FILE_ATTRIBUTES) { + metadata.BasicInfo.FileAttributes = currentAttributes; + } + qCInfo(lcCfApiWrapper) << "updatePlaceholderState" << path << modtime; const auto updateFlags = item.isDirectory() ? CF_UPDATE_FLAG_MARK_IN_SYNC | CF_UPDATE_FLAG_ENABLE_ON_DEMAND_POPULATION : CF_UPDATE_FLAG_MARK_IN_SYNC; @@ -1062,15 +1068,21 @@ OCC::Result OCC::CfApiWrapper::createPlaceholderInfo(const QStrin cloudEntry.RelativeFileName = relativePath.data(); cloudEntry.Flags = CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC; cloudEntry.FsMetadata.FileSize.QuadPart = size; - cloudEntry.FsMetadata.BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &cloudEntry.FsMetadata.BasicInfo.CreationTime); OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &cloudEntry.FsMetadata.BasicInfo.LastWriteTime); OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &cloudEntry.FsMetadata.BasicInfo.LastAccessTime); OCC::Utility::UnixTimeToLargeIntegerFiletime(modtime, &cloudEntry.FsMetadata.BasicInfo.ChangeTime); + // Preserve existing file attributes (especially FILE_ATTRIBUTE_SYSTEM for custom folder icons) + const auto currentAttributes = GetFileAttributesW(reinterpret_cast(path.utf16())); + if (currentAttributes != INVALID_FILE_ATTRIBUTES) { + cloudEntry.FsMetadata.BasicInfo.FileAttributes = currentAttributes; + } else { + cloudEntry.FsMetadata.BasicInfo.FileAttributes = fileInfo.isDir() ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; + } + if (fileInfo.isDir()) { cloudEntry.Flags |= CF_PLACEHOLDER_CREATE_FLAG_DISABLE_ON_DEMAND_POPULATION; - cloudEntry.FsMetadata.BasicInfo.FileAttributes = FILE_ATTRIBUTE_DIRECTORY; cloudEntry.FsMetadata.FileSize.QuadPart = 0; } @@ -1116,15 +1128,22 @@ OCC::Result OCC::CfApiWrapper::createPlaceholdersInfo(const QStri cloudEntry[itemIndice].RelativeFileName = placeholderInfo.platformNativeRelativePath.data(); cloudEntry[itemIndice].Flags = CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC; cloudEntry[itemIndice].FsMetadata.FileSize.QuadPart = placeholderInfo.size; - cloudEntry[itemIndice].FsMetadata.BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL; OCC::Utility::UnixTimeToLargeIntegerFiletime(placeholderInfo.modtime, &cloudEntry[itemIndice].FsMetadata.BasicInfo.CreationTime); OCC::Utility::UnixTimeToLargeIntegerFiletime(placeholderInfo.modtime, &cloudEntry[itemIndice].FsMetadata.BasicInfo.LastWriteTime); OCC::Utility::UnixTimeToLargeIntegerFiletime(placeholderInfo.modtime, &cloudEntry[itemIndice].FsMetadata.BasicInfo.LastAccessTime); OCC::Utility::UnixTimeToLargeIntegerFiletime(placeholderInfo.modtime, &cloudEntry[itemIndice].FsMetadata.BasicInfo.ChangeTime); + // Preserve existing file attributes (especially FILE_ATTRIBUTE_SYSTEM for custom folder icons) + const auto fullPath = localBasePath + QDir::separator() + placeholderInfo.relativePath; + const auto currentAttributes = GetFileAttributesW(reinterpret_cast(fullPath.utf16())); + if (currentAttributes != INVALID_FILE_ATTRIBUTES) { + cloudEntry[itemIndice].FsMetadata.BasicInfo.FileAttributes = currentAttributes; + } else { + cloudEntry[itemIndice].FsMetadata.BasicInfo.FileAttributes = placeholderInfo.fileInfo.isDir() ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL; + } + if (placeholderInfo.fileInfo.isDir()) { cloudEntry[itemIndice].Flags |= CF_PLACEHOLDER_CREATE_FLAG_DISABLE_ON_DEMAND_POPULATION; - cloudEntry[itemIndice].FsMetadata.BasicInfo.FileAttributes = FILE_ATTRIBUTE_DIRECTORY; cloudEntry[itemIndice].FsMetadata.FileSize.QuadPart = 0; } }