diff --git a/include/sync_root_interface/Utilities.h b/include/sync_root_interface/Utilities.h index f36df097..8164fdf2 100644 --- a/include/sync_root_interface/Utilities.h +++ b/include/sync_root_interface/Utilities.h @@ -11,6 +11,7 @@ class Utilities static std::wstring ProcessErrorNameToWString(_In_ ProcessErrorName error); static std::wstring FileOperationErrorToWString(_In_ FileOperationError error); static bool IsTemporaryFile(const std::wstring &fullPath); + static std::wstring GetErrorMessageCloudFiles(HRESULT hr); static winrt::com_array ConvertSidToStringSid(_In_ PSID sid) diff --git a/native-src/placeholders_interface/Planceholders.cpp b/native-src/placeholders_interface/Planceholders.cpp index c8de198f..6b52bf30 100644 --- a/native-src/placeholders_interface/Planceholders.cpp +++ b/native-src/placeholders_interface/Planceholders.cpp @@ -49,7 +49,7 @@ void Placeholders::CreateOne( { Placeholders::ConvertToPlaceholder(fullPath, fileIdentity); Placeholders::MaintainIdentity(fullPath, fileIdentity, false); - return; // No hacer nada si ya existe + return; } std::wstring relativeName(fileIdentity); @@ -189,22 +189,20 @@ bool Placeholders::ConvertToPlaceholder(const std::wstring &fullPath, const std: { if (!std::filesystem::exists(fullPath)) { - // El archivo no existe wprintf(L"[ConvertToPlaceholder] File does not exist\n"); return false; } - // Obtener un handle al archivo + wprintf(L"[ConvertToPlaceholder] Full path: %ls\n", fullPath.c_str()); bool isDirectory = fs::is_directory(fullPath); - // Obtener un handle al archivo o carpeta HANDLE fileHandle = CreateFileW( fullPath.c_str(), FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, - isDirectory ? FILE_FLAG_BACKUP_SEMANTICS : 0, // Agregar FILE_FLAG_BACKUP_SEMANTICS si es una carpeta + isDirectory ? FILE_FLAG_BACKUP_SEMANTICS : 0, nullptr); if (fileHandle == INVALID_HANDLE_VALUE) @@ -217,7 +215,6 @@ bool Placeholders::ConvertToPlaceholder(const std::wstring &fullPath, const std: USN convertUsn; OVERLAPPED overlapped = {}; - // Convierte la cadena de la identidad del servidor a LPCVOID LPCVOID idStrLPCVOID = static_cast(serverIdentity.c_str()); DWORD idStrByteLength = static_cast(serverIdentity.size() * sizeof(wchar_t)); @@ -246,13 +243,19 @@ bool Placeholders::ConvertToPlaceholder(const std::wstring &fullPath, const std: LocalFree(errorMsg); CloseHandle(fileHandle); - return false; } if (!isDirectory) { - CfSetPinState(fileHandle, CF_PIN_STATE_PINNED, CF_SET_PIN_FLAG_NONE, nullptr); + HRESULT hrPinState = CfSetPinState(fileHandle, CF_PIN_STATE_PINNED, CF_SET_PIN_FLAG_NONE, nullptr); + if (FAILED(hrPinState)) + { + std::wstring errorMessage = Utilities::GetErrorMessageCloudFiles(hrPinState); + wprintf(L"[ConvertToPlaceholder] Error setting pin state, HRESULT: 0x%X\nDetails: %s\n", hrPinState, errorMessage.c_str()); + CloseHandle(fileHandle); + return false; + } } CloseHandle(fileHandle); @@ -267,43 +270,102 @@ bool Placeholders::ConvertToPlaceholder(const std::wstring &fullPath, const std: } } +std::wstring GetErrorMessageFromHRESULT(HRESULT hr) +{ + LPWSTR errorMessage = nullptr; + DWORD result = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + hr, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + reinterpret_cast(&errorMessage), + 0, + nullptr); + + std::wstring message; + if (result > 0 && errorMessage) + { + message = errorMessage; + LocalFree(errorMessage); + } + else + { + message = L"Error desconocido"; + } + + return message; +} + /** * @brief Mark a file or directory as synchronized * @param filePath path to the file or directory * @param isDirectory true if the path is a directory, false if it is a file * @return void */ -void Placeholders::UpdateSyncStatus(const std::wstring &filePath, bool inputSyncState, bool isDirectory = false) +void Placeholders::UpdateSyncStatus(const std::wstring &filePath, + bool inputSyncState, + bool isDirectory /* = false */) { wprintf(L"[UpdateSyncStatus] Path: %ls\n", filePath.c_str()); - HANDLE fileHandle = CreateFileW( - filePath.c_str(), - FILE_WRITE_ATTRIBUTES, // permisson needed to change the state - FILE_SHARE_READ | FILE_SHARE_WRITE, - nullptr, - OPEN_EXISTING, - isDirectory ? FILE_FLAG_BACKUP_SEMANTICS : FILE_ATTRIBUTE_NORMAL, - nullptr); - if (fileHandle == INVALID_HANDLE_VALUE) + DWORD flags = FILE_FLAG_OPEN_REPARSE_POINT; + if (isDirectory) + flags |= FILE_FLAG_BACKUP_SEMANTICS; + + HANDLE h = CreateFileW(filePath.c_str(), + FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, + OPEN_EXISTING, + flags, + nullptr); + + if (h == INVALID_HANDLE_VALUE) { - wprintf(L"[UpdateSyncStatus] Error al abrir el archivo: %d\n", GetLastError()); + wprintf(L"[UpdateSyncStatus] CreateFileW falló: %lu\n", GetLastError()); CloseHandle(fileHandle); return; } - // https://learn.microsoft.com/en-us/windows/win32/api/cfapi/nf-cfapi-cfsetinsyncstate - // https://learn.microsoft.com/en-us/windows/win32/api/cfapi/ne-cfapi-cf_in_sync_state - CF_IN_SYNC_STATE syncState = inputSyncState ? CF_IN_SYNC_STATE_IN_SYNC : CF_IN_SYNC_STATE_NOT_IN_SYNC; - // wprintf(L"Marking item as %s: %ls\n", inputSyncState ? L"IN_SYNC" : L"NOT_IN_SYNC", filePath.c_str()); - HRESULT hr = CfSetInSyncState(fileHandle, syncState, CF_SET_IN_SYNC_FLAG_NONE, nullptr); - // imprimir hresult + CF_IN_SYNC_STATE sync = inputSyncState ? CF_IN_SYNC_STATE_IN_SYNC + : CF_IN_SYNC_STATE_NOT_IN_SYNC; + + HRESULT hr = CfSetInSyncState(h, sync, CF_SET_IN_SYNC_FLAG_NONE, nullptr); + if (FAILED(hr)) { - wprintf(L"[UpdateSyncStatus] Error al establecer el estado de sincronización: %ld\n", hr); + switch (HRESULT_CODE(hr)) + { + case ERROR_RETRY: + Sleep(50); + hr = CfSetInSyncState(h, sync, CF_SET_IN_SYNC_FLAG_NONE, nullptr); + wprintf(L"[UpdateSyncStatus] Retry CfSetInSyncState\n"); + break; + + case ERROR_CLOUD_FILE_PROVIDER_NOT_RUNNING: // 0x1A94 + SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, filePath.c_str(), nullptr); + wprintf(L"[UpdateSyncStatus] Retry CfSetInSyncState\n"); + break; + + case ERROR_CLOUD_FILE_NOT_IN_SYNC: + ConvertToPlaceholder(filePath, L"temp_identity"); + hr = CfSetInSyncState(h, sync, CF_SET_IN_SYNC_FLAG_NONE, nullptr); + wprintf(L"[UpdateSyncStatus] Retry CfSetInSyncState\n"); + break; + + default: + wprintf(L"[UpdateSyncStatus] CfSetInSyncState 0x%08X\n", hr); + break; + } + } + else + { + wprintf(L"[UpdateSyncStatus] Estado actualizado\n"); } - CloseHandle(fileHandle); + CloseHandle(h); + + SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, filePath.c_str(), nullptr); } void Placeholders::UpdateFileIdentity(const std::wstring &filePath, const std::wstring &fileIdentity, bool isDirectory) @@ -351,46 +413,13 @@ void Placeholders::UpdateFileIdentity(const std::wstring &filePath, const std::w if (FAILED(hr)) { - wprintf(L"[UpdateFileIdentity] Error updating fileIdentity: 0x%08X\n", hr); - LPWSTR errorMessage = nullptr; - FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - nullptr, - HRESULT_CODE(hr), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - reinterpret_cast(&errorMessage), - 0, - nullptr); - if (errorMessage) - { - wprintf(L"[UpdateFileIdentity] Error: %ls\n", errorMessage); - LocalFree(errorMessage); - } - } - - CloseHandle(fileHandle); -} - -CF_PLACEHOLDER_STATE Placeholders::GetPlaceholderState(const std::wstring &filePath) -{ - HANDLE fileHandle = CreateFileW(filePath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); - if (fileHandle == INVALID_HANDLE_VALUE) - { - // Error al abrir el archivo - return CF_PLACEHOLDER_STATE_INVALID; - } - - FILE_BASIC_INFO fileBasicInfo; - if (!GetFileInformationByHandleEx(fileHandle, FileBasicInfo, &fileBasicInfo, sizeof(fileBasicInfo))) - { - // Error al obtener la información básica del archivo + std::wstring errorMessage = Utilities::GetErrorMessageCloudFiles(hr); + wprintf(L"[UpdateFileIdentity] Error updating fileIdentity: %ls\n", errorMessage.c_str()); CloseHandle(fileHandle); - return CF_PLACEHOLDER_STATE_INVALID; + return; } - CF_PLACEHOLDER_STATE placeholderState = CfGetPlaceholderStateFromFileInfo(&fileBasicInfo, FileBasicInfo); CloseHandle(fileHandle); - - return placeholderState; } std::string Placeholders::GetFileIdentity(const std::wstring &filePath) @@ -415,22 +444,6 @@ std::string Placeholders::GetFileIdentity(const std::wstring &filePath) } } -CF_PLACEHOLDER_STATE GetPlaceholderStateMock(const std::wstring &filePath) -{ - static std::random_device rd; - static std::mt19937 gen(rd()); - static std::uniform_int_distribution dis(0, 1); - - if (dis(gen) == 0) - { - return CF_PLACEHOLDER_STATE_IN_SYNC; - } - else - { - return CF_PLACEHOLDER_STATE_SYNC_ROOT; - } -} - FileState Placeholders::GetPlaceholderInfo(const std::wstring &directoryPath) { diff --git a/native-src/sync_root_interface/Utilities.cpp b/native-src/sync_root_interface/Utilities.cpp index fa664e3b..1f1e9ada 100644 --- a/native-src/sync_root_interface/Utilities.cpp +++ b/native-src/sync_root_interface/Utilities.cpp @@ -160,6 +160,26 @@ void Utilities::ApplyTransferStateToFile(_In_ PCWSTR fullPath, _In_ CF_CALLBACK_ } } +std::wstring Utilities::GetErrorMessageCloudFiles(HRESULT hr) { + LPWSTR errorMsg = nullptr; + DWORD size = FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + nullptr, + hr, + 0, + (LPWSTR)&errorMsg, + 0, + nullptr + ); + + std::wstring message; + if (size > 0 && errorMsg != nullptr) { + message.assign(errorMsg, size); + } + LocalFree(errorMsg); + return message; +} + bool Utilities::IsTemporaryFile(const std::wstring &fullPath) { diff --git a/package.json b/package.json index de1c7c72..eaf05714 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@internxt/node-win", - "version": "1.0.9", + "version": "1.0.10", "description": "Drive desktop node addon", "main": "dist/index.ts", "types": "dist/index.d.ts",