From ed22ccaae650070c62f9b6f3e31daee8e5a86f69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonz=C3=A1lez?= Date: Mon, 28 Apr 2025 11:36:02 +0200 Subject: [PATCH 1/5] fix: progress bar --- include/sync_root_interface/Utilities.h | 1 + native-src/sync_root_interface/SyncRoot.cpp | 78 ++++++++++++------- native-src/sync_root_interface/Utilities.cpp | 81 ++++++++++++++------ 3 files changed, 110 insertions(+), 50 deletions(-) diff --git a/include/sync_root_interface/Utilities.h b/include/sync_root_interface/Utilities.h index 8164fdf2..3effcb19 100644 --- a/include/sync_root_interface/Utilities.h +++ b/include/sync_root_interface/Utilities.h @@ -12,6 +12,7 @@ class Utilities static std::wstring FileOperationErrorToWString(_In_ FileOperationError error); static bool IsTemporaryFile(const std::wstring &fullPath); static std::wstring GetErrorMessageCloudFiles(HRESULT hr); + static void ClearTransferProperties(_In_ LPCWSTR fullPath); static winrt::com_array ConvertSidToStringSid(_In_ PSID sid) diff --git a/native-src/sync_root_interface/SyncRoot.cpp b/native-src/sync_root_interface/SyncRoot.cpp index e362c68d..58483cb0 100644 --- a/native-src/sync_root_interface/SyncRoot.cpp +++ b/native-src/sync_root_interface/SyncRoot.cpp @@ -78,40 +78,66 @@ void SyncRoot::HydrateFile(const wchar_t *filePath) } } -void SyncRoot::DehydrateFile(const wchar_t *filePath) +void SyncRoot::DehydrateFile(const wchar_t* filePath) { - // Logger::getInstance().log("Dehydration file init", LogLevel::INFO); - wprintf(L"Dehydration file init %ls\n", filePath); - DWORD attrib = GetFileAttributesW(filePath); - if (!(attrib & FILE_ATTRIBUTE_DIRECTORY)) + wprintf(L"[DehydrateFile] init %ls\n", filePath); + + DWORD attr = GetFileAttributesW(filePath); + if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY)) + return; + + DWORD flags = FILE_FLAG_OPEN_REPARSE_POINT; + winrt::handle h(CreateFileW(filePath, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | + FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + flags, + nullptr)); + if (!h) { - winrt::handle placeholder(CreateFileW(filePath, 0, FILE_READ_DATA, nullptr, OPEN_EXISTING, 0, nullptr)); + wprintf(L"[DehydrateFile] CreateFileW falló: %lu\n", GetLastError()); + return; + } - LARGE_INTEGER offset; - offset.QuadPart = 0; - LARGE_INTEGER length; - GetFileSizeEx(placeholder.get(), &length); + if (!(attr & FILE_ATTRIBUTE_UNPINNED)) + { + CfSetPinState(h.get(), CF_PIN_STATE_UNPINNED, + CF_SET_PIN_FLAG_NONE, nullptr); + } - if (attrib & FILE_ATTRIBUTE_UNPINNED) - { - // Logger::getInstance().log("Dehydrating file " + Logger::fromWStringToString(filePath), LogLevel::INFO); - wprintf(L"Dehydrating file starteeed %ls\n", filePath); - HRESULT hr = CfDehydratePlaceholder(placeholder.get(), offset, length, CF_DEHYDRATE_FLAG_NONE, NULL); + LARGE_INTEGER len; GetFileSizeEx(h.get(), &len); - if (FAILED(hr)) - { - wprintf(L"Error dehydrating file %ls\n", filePath); - // Logger::getInstance().log("Error dehydrating file " + Logger::fromWStringToString(filePath), LogLevel::ERROR); - } - else - { - wprintf(L"Dehydration finished %ls\n", filePath); - // Logger::getInstance().log("Dehydration finished " + Logger::fromWStringToString(filePath), LogLevel::INFO); - } - } + HRESULT hr = CfDehydratePlaceholder(h.get(), + /*offset*/{}, len, + CF_DEHYDRATE_FLAG_NONE, nullptr); + + if (hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION)) + { + wprintf(L"[DehydrateFile] sharing-violation; reintentaré luego\n"); + return; + } + + if (FAILED(hr)) + { + wprintf(L"[DehydrateFile] CfDehydratePlaceholder 0x%08X\n", hr); + return; } + + CfSetInSyncState(h.get(), CF_IN_SYNC_STATE_NOT_IN_SYNC, + CF_SET_IN_SYNC_FLAG_NONE, nullptr); + + + Utilities::ClearTransferProperties(filePath); + + + SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, filePath, nullptr); + + wprintf(L"[DehydrateFile] OK %ls\n", filePath); } + HRESULT SyncRoot::RegisterSyncRoot(const wchar_t *syncRootPath, const wchar_t *providerName, const wchar_t *providerVersion, const GUID &providerId, const wchar_t *logoPath) { try diff --git a/native-src/sync_root_interface/Utilities.cpp b/native-src/sync_root_interface/Utilities.cpp index 1f1e9ada..88be4226 100644 --- a/native-src/sync_root_interface/Utilities.cpp +++ b/native-src/sync_root_interface/Utilities.cpp @@ -88,6 +88,26 @@ void Utilities::AddFolderToSearchIndexer(_In_ PCWSTR folder) } } +void Utilities::ClearTransferProperties(PCWSTR fullPath) +{ + winrt::com_ptr item; + winrt::com_ptrstore; + + if (FAILED(SHCreateItemFromParsingName(fullPath, nullptr, + __uuidof(item), item.put_void()))) + return; + + if (FAILED(item->GetPropertyStore(GPS_READWRITE | GPS_VOLATILEPROPERTIESONLY, + __uuidof(store), store.put_void()))) + return; + + PROPVARIANT empty; PropVariantInit(&empty); + store->SetValue(PKEY_StorageProviderTransferProgress, empty); + store->SetValue(PKEY_SyncTransferStatus, empty); + store->Commit(); +} + + void Utilities::ApplyTransferStateToFile(_In_ PCWSTR fullPath, _In_ CF_CALLBACK_INFO &callbackInfo, UINT64 total, UINT64 completed) { Logger::getInstance().log("ApplyTransferStateToFile", LogLevel::INFO); @@ -116,10 +136,10 @@ void Utilities::ApplyTransferStateToFile(_In_ PCWSTR fullPath, _In_ CF_CALLBACK_ { // First, get the Volatile property store for the file. That's where the properties are maintained. winrt::com_ptr shellItem; + winrt::com_ptrpropStoreVolatile; + winrt::check_hresult(SHCreateItemFromParsingName(fullPath, nullptr, __uuidof(shellItem), shellItem.put_void())); - // wprintf(L"transfer-> fullPath \"%s\"\n", fullPath); - // wprintf(L"transfer-> shellItem \"%s\"\n", shellItem); - winrt::com_ptr propStoreVolatile; + // wprintf(L"transfer-> propStoreVolatile \"%s\"\n", propStoreVolatile); winrt::check_hresult( shellItem->GetPropertyStore( @@ -130,27 +150,40 @@ void Utilities::ApplyTransferStateToFile(_In_ PCWSTR fullPath, _In_ CF_CALLBACK_ // The PKEY_StorageProviderTransferProgress property works with a UINT64 array that is two elements, with // element 0 being the amount of data transferred, and element 1 being the total amount // that will be transferred. - PROPVARIANT transferProgress; - UINT64 values[]{completed, total}; - winrt::check_hresult(InitPropVariantFromUInt64Vector(values, ARRAYSIZE(values), &transferProgress)); // TODO: should work, but doesn't the library doesn't have this function implemented - winrt::check_hresult(propStoreVolatile->SetValue(PKEY_StorageProviderTransferProgress, transferProgress)); - // wprintf(L"transfer-> transferProgress \"%s\"\n", transferProgress); - // Set the sync transfer status accordingly - - PROPVARIANT transferStatus; - winrt::check_hresult( - InitPropVariantFromUInt32( - (completed < total) ? SYNC_TRANSFER_STATUS::STS_TRANSFERRING : SYNC_TRANSFER_STATUS::STS_NONE, - &transferStatus)); - winrt::check_hresult(propStoreVolatile->SetValue(PKEY_SyncTransferStatus, transferStatus)); - // wprintf(L"transfer-> transferStatus \"%s\"\n", transferStatus); - // Without this, all your hard work is wasted. - winrt::check_hresult(propStoreVolatile->Commit()); - // wprintf(L"transfer-> propStoreVolatile \"%s\"\n", propStoreVolatile); - // Broadcast a notification that something about the file has changed, so that apps - // who subscribe (such as File Explorer) can update their UI to reflect the new progress - SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, static_cast(fullPath), nullptr); - wprintf(L"Succesfully Set Transfer Progress on \"%s\" to %llu/%llu\n", fullPath, completed, total); + if (completed < total) // ===== PROGRESO ACTIVO ===== + { + PROPVARIANT pvProgress, pvStatus; + UINT64 values[] { completed, total }; + InitPropVariantFromUInt64Vector(values, ARRAYSIZE(values), &pvProgress); + InitPropVariantFromUInt32(SYNC_TRANSFER_STATUS::STS_TRANSFERRING, &pvStatus); + + propStoreVolatile->SetValue(PKEY_StorageProviderTransferProgress, pvProgress); + propStoreVolatile->SetValue(PKEY_SyncTransferStatus, pvStatus); + propStoreVolatile->Commit(); + + PropVariantClear(&pvProgress); // buena higiene + } + else // ===== TRANSFERENCIA FINALIZADA ===== + { + PROPVARIANT empty; PropVariantInit(&empty); // --- NUEVO + propStoreVolatile->SetValue(PKEY_StorageProviderTransferProgress, empty); // --- NUEVO + propStoreVolatile->SetValue(PKEY_SyncTransferStatus, empty); // --- NUEVO + propStoreVolatile->Commit(); // --- NUEVO + + // (opcional pero recomendable) marcar el archivo como IN_SYNC // --- NUEVO + HANDLE h = CreateFileW(fullPath, + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT, + nullptr); + if (h != INVALID_HANDLE_VALUE) { + CfSetInSyncState(h, CF_IN_SYNC_STATE_IN_SYNC, + CF_SET_IN_SYNC_FLAG_NONE, nullptr); + CloseHandle(h); + } + } } catch (...) { From 1cdf82c8685ff7bfe7c620e6dde22e21cdbd9589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonz=C3=A1lez?= Date: Tue, 29 Apr 2025 11:00:42 +0200 Subject: [PATCH 2/5] chore: clean up --- native-src/sync_root_interface/SyncRoot.cpp | 10 ---------- native-src/sync_root_interface/Utilities.cpp | 17 ++++++++--------- 2 files changed, 8 insertions(+), 19 deletions(-) diff --git a/native-src/sync_root_interface/SyncRoot.cpp b/native-src/sync_root_interface/SyncRoot.cpp index 58483cb0..b4861109 100644 --- a/native-src/sync_root_interface/SyncRoot.cpp +++ b/native-src/sync_root_interface/SyncRoot.cpp @@ -42,8 +42,6 @@ void SyncRoot::HydrateFile(const wchar_t *filePath) if (attrib & FILE_ATTRIBUTE_PINNED) { - // if (!(attrib & FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS)) - // { Logger::getInstance().log("Hydration file init", LogLevel::INFO); auto start = std::chrono::steady_clock::now(); @@ -68,20 +66,12 @@ void SyncRoot::HydrateFile(const wchar_t *filePath) wprintf(L"Hydration finished %ls\n", filePath); } } - // } - // else - // { - // wprintf(L"File is already hydrated: %ls\n", filePath); - // Logger::getInstance().log("File is already hydrated " + Logger::fromWStringToString(filePath), LogLevel::INFO); - // } } } } void SyncRoot::DehydrateFile(const wchar_t* filePath) { - wprintf(L"[DehydrateFile] init %ls\n", filePath); - DWORD attr = GetFileAttributesW(filePath); if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY)) return; diff --git a/native-src/sync_root_interface/Utilities.cpp b/native-src/sync_root_interface/Utilities.cpp index 88be4226..35b824bd 100644 --- a/native-src/sync_root_interface/Utilities.cpp +++ b/native-src/sync_root_interface/Utilities.cpp @@ -150,7 +150,7 @@ void Utilities::ApplyTransferStateToFile(_In_ PCWSTR fullPath, _In_ CF_CALLBACK_ // The PKEY_StorageProviderTransferProgress property works with a UINT64 array that is two elements, with // element 0 being the amount of data transferred, and element 1 being the total amount // that will be transferred. - if (completed < total) // ===== PROGRESO ACTIVO ===== + if (completed < total) { PROPVARIANT pvProgress, pvStatus; UINT64 values[] { completed, total }; @@ -158,19 +158,18 @@ void Utilities::ApplyTransferStateToFile(_In_ PCWSTR fullPath, _In_ CF_CALLBACK_ InitPropVariantFromUInt32(SYNC_TRANSFER_STATUS::STS_TRANSFERRING, &pvStatus); propStoreVolatile->SetValue(PKEY_StorageProviderTransferProgress, pvProgress); - propStoreVolatile->SetValue(PKEY_SyncTransferStatus, pvStatus); + propStoreVolatile->SetValue(PKEY_SyncTransferStatus, pvStatus); propStoreVolatile->Commit(); - PropVariantClear(&pvProgress); // buena higiene + PropVariantClear(&pvProgress); } - else // ===== TRANSFERENCIA FINALIZADA ===== + else { - PROPVARIANT empty; PropVariantInit(&empty); // --- NUEVO - propStoreVolatile->SetValue(PKEY_StorageProviderTransferProgress, empty); // --- NUEVO - propStoreVolatile->SetValue(PKEY_SyncTransferStatus, empty); // --- NUEVO - propStoreVolatile->Commit(); // --- NUEVO + PROPVARIANT empty; PropVariantInit(&empty); + propStoreVolatile->SetValue(PKEY_StorageProviderTransferProgress, empty); + propStoreVolatile->SetValue(PKEY_SyncTransferStatus, empty); + propStoreVolatile->Commit(); - // (opcional pero recomendable) marcar el archivo como IN_SYNC // --- NUEVO HANDLE h = CreateFileW(fullPath, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, From 7e89119d5955ae2fcf5f767161dfdddb3048ac6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonz=C3=A1lez?= Date: Tue, 29 Apr 2025 11:02:10 +0200 Subject: [PATCH 3/5] chore: clean up --- native-src/sync_root_interface/SyncRoot.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/native-src/sync_root_interface/SyncRoot.cpp b/native-src/sync_root_interface/SyncRoot.cpp index b4861109..f9e1b2bf 100644 --- a/native-src/sync_root_interface/SyncRoot.cpp +++ b/native-src/sync_root_interface/SyncRoot.cpp @@ -99,9 +99,7 @@ void SyncRoot::DehydrateFile(const wchar_t* filePath) LARGE_INTEGER len; GetFileSizeEx(h.get(), &len); - HRESULT hr = CfDehydratePlaceholder(h.get(), - /*offset*/{}, len, - CF_DEHYDRATE_FLAG_NONE, nullptr); + HRESULT hr = CfDehydratePlaceholder(h.get(), {}, len, CF_DEHYDRATE_FLAG_NONE, nullptr); if (hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION)) { From aea1d4a099d361aecf9b04ed92b5e7591398e863 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonz=C3=A1lez?= Date: Tue, 29 Apr 2025 11:28:54 +0200 Subject: [PATCH 4/5] chore: revert sync root changes --- native-src/sync_root_interface/SyncRoot.cpp | 82 +++++++++------------ 1 file changed, 34 insertions(+), 48 deletions(-) diff --git a/native-src/sync_root_interface/SyncRoot.cpp b/native-src/sync_root_interface/SyncRoot.cpp index f9e1b2bf..e362c68d 100644 --- a/native-src/sync_root_interface/SyncRoot.cpp +++ b/native-src/sync_root_interface/SyncRoot.cpp @@ -42,6 +42,8 @@ void SyncRoot::HydrateFile(const wchar_t *filePath) if (attrib & FILE_ATTRIBUTE_PINNED) { + // if (!(attrib & FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS)) + // { Logger::getInstance().log("Hydration file init", LogLevel::INFO); auto start = std::chrono::steady_clock::now(); @@ -66,66 +68,50 @@ void SyncRoot::HydrateFile(const wchar_t *filePath) wprintf(L"Hydration finished %ls\n", filePath); } } + // } + // else + // { + // wprintf(L"File is already hydrated: %ls\n", filePath); + // Logger::getInstance().log("File is already hydrated " + Logger::fromWStringToString(filePath), LogLevel::INFO); + // } } } } -void SyncRoot::DehydrateFile(const wchar_t* filePath) +void SyncRoot::DehydrateFile(const wchar_t *filePath) { - DWORD attr = GetFileAttributesW(filePath); - if (attr == INVALID_FILE_ATTRIBUTES || (attr & FILE_ATTRIBUTE_DIRECTORY)) - return; - - DWORD flags = FILE_FLAG_OPEN_REPARSE_POINT; - winrt::handle h(CreateFileW(filePath, - FILE_WRITE_ATTRIBUTES, - FILE_SHARE_READ | FILE_SHARE_WRITE | - FILE_SHARE_DELETE, - nullptr, - OPEN_EXISTING, - flags, - nullptr)); - if (!h) - { - wprintf(L"[DehydrateFile] CreateFileW falló: %lu\n", GetLastError()); - return; - } - - if (!(attr & FILE_ATTRIBUTE_UNPINNED)) + // Logger::getInstance().log("Dehydration file init", LogLevel::INFO); + wprintf(L"Dehydration file init %ls\n", filePath); + DWORD attrib = GetFileAttributesW(filePath); + if (!(attrib & FILE_ATTRIBUTE_DIRECTORY)) { - CfSetPinState(h.get(), CF_PIN_STATE_UNPINNED, - CF_SET_PIN_FLAG_NONE, nullptr); - } - - LARGE_INTEGER len; GetFileSizeEx(h.get(), &len); + winrt::handle placeholder(CreateFileW(filePath, 0, FILE_READ_DATA, nullptr, OPEN_EXISTING, 0, nullptr)); - HRESULT hr = CfDehydratePlaceholder(h.get(), {}, len, CF_DEHYDRATE_FLAG_NONE, nullptr); + LARGE_INTEGER offset; + offset.QuadPart = 0; + LARGE_INTEGER length; + GetFileSizeEx(placeholder.get(), &length); - if (hr == HRESULT_FROM_WIN32(ERROR_SHARING_VIOLATION)) - { - wprintf(L"[DehydrateFile] sharing-violation; reintentaré luego\n"); - return; - } + if (attrib & FILE_ATTRIBUTE_UNPINNED) + { + // Logger::getInstance().log("Dehydrating file " + Logger::fromWStringToString(filePath), LogLevel::INFO); + wprintf(L"Dehydrating file starteeed %ls\n", filePath); + HRESULT hr = CfDehydratePlaceholder(placeholder.get(), offset, length, CF_DEHYDRATE_FLAG_NONE, NULL); - if (FAILED(hr)) - { - wprintf(L"[DehydrateFile] CfDehydratePlaceholder 0x%08X\n", hr); - return; + if (FAILED(hr)) + { + wprintf(L"Error dehydrating file %ls\n", filePath); + // Logger::getInstance().log("Error dehydrating file " + Logger::fromWStringToString(filePath), LogLevel::ERROR); + } + else + { + wprintf(L"Dehydration finished %ls\n", filePath); + // Logger::getInstance().log("Dehydration finished " + Logger::fromWStringToString(filePath), LogLevel::INFO); + } + } } - - CfSetInSyncState(h.get(), CF_IN_SYNC_STATE_NOT_IN_SYNC, - CF_SET_IN_SYNC_FLAG_NONE, nullptr); - - - Utilities::ClearTransferProperties(filePath); - - - SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, filePath, nullptr); - - wprintf(L"[DehydrateFile] OK %ls\n", filePath); } - HRESULT SyncRoot::RegisterSyncRoot(const wchar_t *syncRootPath, const wchar_t *providerName, const wchar_t *providerVersion, const GUID &providerId, const wchar_t *logoPath) { try From 0262b0b8284c27859a61b2496c2483a29d9bf9f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Gonz=C3=A1lez?= Date: Tue, 29 Apr 2025 12:08:08 +0200 Subject: [PATCH 5/5] chore: upgrade version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eaf05714..a13024fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@internxt/node-win", - "version": "1.0.10", + "version": "1.0.11", "description": "Drive desktop node addon", "main": "dist/index.ts", "types": "dist/index.d.ts",