diff --git a/include/placeholders_interface/Placeholders.h b/include/placeholders_interface/Placeholders.h index b720bb10..b557a13c 100644 --- a/include/placeholders_interface/Placeholders.h +++ b/include/placeholders_interface/Placeholders.h @@ -10,10 +10,15 @@ enum class PlaceholderAttribute PINNED = 2, }; +struct PlaceholderResult { + bool success; + std::wstring errorMessage; +}; + class Placeholders { public: - static void CreateOne( + static PlaceholderResult CreateOne( _In_ PCWSTR fileName, _In_ PCWSTR fileIdentity, int64_t fileSize, @@ -26,7 +31,7 @@ class Placeholders static void MaintainIdentity(std::wstring &fullPath, PCWSTR fileIdentity, bool isDirectory); - static void CreateEntry( + static PlaceholderResult CreateEntry( _In_ PCWSTR itemName, _In_ PCWSTR itemIdentity, bool isDirectory, @@ -44,7 +49,7 @@ class Placeholders static CF_PLACEHOLDER_STATE GetPlaceholderState(const std::wstring &filePath); static std::vector GetPlaceholderWithStatePending(const std::wstring &filePath); static bool IsFileValidForSync(const std::wstring &filePath); - static bool ConvertToPlaceholder(const std::wstring &fullPath, const std::wstring &serverIdentity); + static PlaceholderResult ConvertToPlaceholder(const std::wstring &fullPath, const std::wstring &serverIdentity); static std::string GetFileIdentity(const std::wstring &filePath); static void UpdateFileIdentity(const std::wstring &filePath, const std::wstring &fileIdentity, bool isDirectory); static PlaceholderAttribute GetAttribute(const std::wstring &filePath); diff --git a/native-src/placeholders_interface/Planceholders.cpp b/native-src/placeholders_interface/Planceholders.cpp index 18a67c88..d4fd025b 100644 --- a/native-src/placeholders_interface/Planceholders.cpp +++ b/native-src/placeholders_interface/Planceholders.cpp @@ -13,6 +13,8 @@ #include #include #include +#include +#include using namespace std; @@ -26,7 +28,7 @@ bool DirectoryExists(const wchar_t *path) return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY); } -void Placeholders::CreateOne( +PlaceholderResult Placeholders::CreateOne( _In_ PCWSTR fileName, _In_ PCWSTR fileIdentity, int64_t fileSize, @@ -37,6 +39,8 @@ void Placeholders::CreateOne( FILETIME lastAccessTime, _In_ PCWSTR destPath) { + PlaceholderResult result = {false, L""}; + try { CF_PLACEHOLDER_CREATE_INFO cloudEntry = {}; @@ -49,7 +53,8 @@ void Placeholders::CreateOne( { Placeholders::ConvertToPlaceholder(fullPath, fileIdentity); Placeholders::MaintainIdentity(fullPath, fileIdentity, false); - return; + result.success = true; + return result; } std::wstring relativeName(fileIdentity); @@ -71,9 +76,11 @@ void Placeholders::CreateOne( { winrt::check_hresult(CfCreatePlaceholders(fullDestPath.c_str(), &cloudEntry, 1, CF_CREATE_FLAG_NONE, NULL)); Placeholders::UpdatePinState(fullPath, PinState::OnlineOnly); + result.success = true; } catch (const winrt::hresult_error &error) { + result.errorMessage = error.message().c_str(); wprintf(L"[CreatePlaceholder] error: %s", error.message().c_str()); } winrt::StorageProviderItemProperty prop; @@ -85,8 +92,11 @@ void Placeholders::CreateOne( } catch (...) { + result.errorMessage = L"Failed to create or customize placeholder"; wprintf(L"[CreatePlaceholder] Failed to create or customize placeholder with %08x\n", static_cast(winrt::to_hresult())); } + + return result; } std::string cleanString(const std::string &str) @@ -128,7 +138,7 @@ void Placeholders::MaintainIdentity(std::wstring &fullPath, PCWSTR itemIdentity, } } -void Placeholders::CreateEntry( +PlaceholderResult Placeholders::CreateEntry( _In_ PCWSTR itemName, _In_ PCWSTR itemIdentity, bool isDirectory, @@ -140,6 +150,7 @@ void Placeholders::CreateEntry( FILETIME lastAccessTime, _In_ PCWSTR destPath) { + PlaceholderResult result = {false, L""}; std::wstring fullDestPath = std::wstring(destPath) + L"\\" + std::wstring(itemName); CF_PLACEHOLDER_CREATE_INFO cloudEntry = {}; @@ -158,7 +169,8 @@ void Placeholders::CreateEntry( { Placeholders::ConvertToPlaceholder(fullDestPath, itemIdentity); Placeholders::MaintainIdentity(fullDestPath, itemIdentity, true); - return; // No hacer nada si ya existe + result.success = true; + return result; } if (isDirectory) // TODO: the function createEntry is used to create only folders (directories), so this if is always true @@ -168,6 +180,7 @@ void Placeholders::CreateEntry( HRESULT hr = CfCreatePlaceholders(fullDestPath.c_str(), &cloudEntry, 1, CF_CREATE_FLAG_NONE, NULL); if (FAILED(hr)) { + result.errorMessage = L"Failed to create placeholder directory"; wprintf(L"[CreatePlaceholder] Failed to create placeholder directory with HRESULT 0x%08x\n", hr); throw winrt::hresult_error(hr); } @@ -175,99 +188,86 @@ void Placeholders::CreateEntry( std::wstring finalPath = std::wstring(destPath) + L"\\" + std::wstring(itemName); Placeholders::UpdatePinState(finalPath, PinState::OnlineOnly); UpdateSyncStatus(finalPath, true, true); + result.success = true; } } catch (const winrt::hresult_error &error) { + result.errorMessage = error.message().c_str(); wprintf(L"[CreatePlaceholder] Error while creating %s: %s\n", isDirectory ? L"directory" : L"file", error.message().c_str()); } + catch (...) + { + result.errorMessage = L"Unknown error occurred"; + wprintf(L"[CreatePlaceholder] Unknown error occurred\n"); + } + + return result; } -bool Placeholders::ConvertToPlaceholder(const std::wstring &fullPath, const std::wstring &serverIdentity) +PlaceholderResult Placeholders::ConvertToPlaceholder(const std::wstring &fullPath, const std::wstring &serverIdentity) { - try + PlaceholderResult result = {false, L""}; + + if (!std::filesystem::exists(fullPath)) { - if (!std::filesystem::exists(fullPath)) - { - wprintf(L"[ConvertToPlaceholder] File does not exist\n"); - return false; - } + result.errorMessage = L"File does not exist"; + return result; + } - wprintf(L"[ConvertToPlaceholder] Full path: %ls\n", fullPath.c_str()); - bool isDirectory = fs::is_directory(fullPath); + wprintf(L"[ConvertToPlaceholder] Full path: %ls\n", fullPath.c_str()); + bool isDirectory = fs::is_directory(fullPath); - 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, - nullptr); + 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, + nullptr); - if (fileHandle == INVALID_HANDLE_VALUE) - { - // Manejar el error al abrir el archivo - return false; - } + if (fileHandle == INVALID_HANDLE_VALUE) + { + result.errorMessage = L"Failed to open file: " + std::to_wstring(GetLastError()); + return result; + } - CF_CONVERT_FLAGS convertFlags = CF_CONVERT_FLAG_MARK_IN_SYNC; - USN convertUsn; - OVERLAPPED overlapped = {}; + CF_CONVERT_FLAGS convertFlags = CF_CONVERT_FLAG_MARK_IN_SYNC; + USN convertUsn; + OVERLAPPED overlapped = {}; - LPCVOID idStrLPCVOID = static_cast(serverIdentity.c_str()); - DWORD idStrByteLength = static_cast(serverIdentity.size() * sizeof(wchar_t)); + LPCVOID idStrLPCVOID = static_cast(serverIdentity.c_str()); + DWORD idStrByteLength = static_cast(serverIdentity.size() * sizeof(wchar_t)); - HRESULT hr = CfConvertToPlaceholder(fileHandle, idStrLPCVOID, idStrByteLength, convertFlags, &convertUsn, &overlapped); + HRESULT hr = CfConvertToPlaceholder(fileHandle, idStrLPCVOID, idStrByteLength, convertFlags, &convertUsn, &overlapped); - if (FAILED(hr)) + if (FAILED(hr)) + { + CloseHandle(fileHandle); + if (hr != 0x8007017C) // Ignorar error específico de "ya es un placeholder" { - // Manejar el error al convertir a marcador de posición - if (hr != 0x8007017C) - { - wprintf(L"[ConvertToPlaceholder] Error converting to placeholder, ConvertToPlaceholder failed with HRESULT 0x%X\n", hr); - } - - // Puedes obtener información detallada sobre el error usando FormatMessage - LPVOID errorMsg; - FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - hr, - 0, // Default language - (LPWSTR)&errorMsg, - 0, - NULL); - - // Liberar el buffer de mensaje de error - LocalFree(errorMsg); - - CloseHandle(fileHandle); - return false; + result.errorMessage = L"Failed to convert to placeholder. HRESULT: 0x" + std::to_wstring(static_cast(hr)); + return result; } + return result; + } - if (!isDirectory) + if (!isDirectory) + { + HRESULT hrPinState = CfSetPinState(fileHandle, CF_PIN_STATE_PINNED, CF_SET_PIN_FLAG_NONE, nullptr); + if (FAILED(hrPinState)) { - 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); + result.errorMessage = L"Failed to set pin state. HRESULT: 0x" + std::to_wstring(static_cast(hrPinState)); + return result; } - - CloseHandle(fileHandle); - wprintf(L"[ConvertToPlaceholder] Successfully converted to placeholder: %ls\n", fullPath.c_str()); - return true; - } - catch (const winrt::hresult_error &error) - { - // Manejar excepciones desconocidas - wprintf(L"[ConvertToPlaceholder] Unknown exception occurred\n"); - return false; } + + CloseHandle(fileHandle); + wprintf(L"[ConvertToPlaceholder] Successfully converted to placeholder: %ls\n", fullPath.c_str()); + result.success = true; + return result; } std::wstring GetErrorMessageFromHRESULT(HRESULT hr) diff --git a/native-src/virtual_drive/Wrappers.cpp b/native-src/virtual_drive/Wrappers.cpp index 1c4906f7..ae426a86 100644 --- a/native-src/virtual_drive/Wrappers.cpp +++ b/native-src/virtual_drive/Wrappers.cpp @@ -92,7 +92,7 @@ napi_value CreatePlaceholderFile(napi_env env, napi_callback_info args) destPath = new WCHAR[destPathLength + 1]; napi_get_value_string_utf16(env, argv[7], reinterpret_cast(const_cast(destPath)), destPathLength + 1, nullptr); - Placeholders::CreateOne( + PlaceholderResult result = Placeholders::CreateOne( fileName, fileIdentity, fileSize, @@ -103,13 +103,28 @@ napi_value CreatePlaceholderFile(napi_env env, napi_callback_info args) lastAccessTime, destPath); + // Create result object + napi_value resultObj; + napi_create_object(env, &resultObj); + + // Add success property + napi_value successValue; + napi_get_boolean(env, result.success, &successValue); + napi_set_named_property(env, resultObj, "success", successValue); + + // Add errorMessage property if there is an error + if (!result.success && !result.errorMessage.empty()) + { + napi_value errorMessageValue; + napi_create_string_utf16(env, reinterpret_cast(result.errorMessage.c_str()), result.errorMessage.length(), &errorMessageValue); + napi_set_named_property(env, resultObj, "errorMessage", errorMessageValue); + } + delete[] fileName; delete[] fileIdentity; delete[] destPath; - napi_value result; - napi_get_boolean(env, true, &result); - return result; + return resultObj; } napi_value UnregisterSyncRootWrapper(napi_env env, napi_callback_info args) @@ -470,7 +485,7 @@ napi_value CreateEntryWrapper(napi_env env, napi_callback_info args) destPath = new WCHAR[destPathLength + 1]; napi_get_value_string_utf16(env, argv[8], reinterpret_cast(const_cast(destPath)), destPathLength + 1, nullptr); - Placeholders::CreateEntry( + PlaceholderResult result = Placeholders::CreateEntry( itemName, itemIdentity, isDirectory, @@ -482,13 +497,28 @@ napi_value CreateEntryWrapper(napi_env env, napi_callback_info args) lastAccessTime, destPath); + // Create result object + napi_value resultObj; + napi_create_object(env, &resultObj); + + // Add success property + napi_value successValue; + napi_get_boolean(env, result.success, &successValue); + napi_set_named_property(env, resultObj, "success", successValue); + + // Add errorMessage property if there is an error + if (!result.success && !result.errorMessage.empty()) + { + napi_value errorMessageValue; + napi_create_string_utf16(env, reinterpret_cast(result.errorMessage.c_str()), result.errorMessage.length(), &errorMessageValue); + napi_set_named_property(env, resultObj, "errorMessage", errorMessageValue); + } + delete[] itemName; delete[] itemIdentity; delete[] destPath; - napi_value result; - napi_get_boolean(env, true, &result); - return result; + return resultObj; } // disconection wrapper @@ -718,36 +748,42 @@ napi_value ConvertToPlaceholderWrapper(napi_env env, napi_callback_info args) { size_t argc = 2; napi_value argv[2]; - napi_get_cb_info(env, args, &argc, argv, nullptr, nullptr); if (argc < 2) { - napi_throw_error(env, nullptr, "Both full path and placeholder ID are required for ConvertToPlaceholder"); + napi_throw_type_error(env, nullptr, "Wrong number of arguments"); return nullptr; } - size_t pathLength; - napi_get_value_string_utf16(env, argv[0], nullptr, 0, &pathLength); + char path[1024]; + char serverIdentity[1024]; + size_t pathLen, serverIdentityLen; - std::unique_ptr widePath(new char16_t[pathLength + 1]); + napi_get_value_string_utf8(env, argv[0], path, sizeof(path), &pathLen); + napi_get_value_string_utf8(env, argv[1], serverIdentity, sizeof(serverIdentity), &serverIdentityLen); - napi_get_value_string_utf16(env, argv[0], widePath.get(), pathLength + 1, nullptr); + std::wstring wPath(path, path + pathLen); + std::wstring wServerIdentity(serverIdentity, serverIdentity + serverIdentityLen); - size_t placeholderIdLength; - napi_get_value_string_utf16(env, argv[1], nullptr, 0, &placeholderIdLength); + PlaceholderResult result = Placeholders::ConvertToPlaceholder(wPath, wServerIdentity); - std::unique_ptr widePlaceholderId(new char16_t[placeholderIdLength + 1]); + napi_value resultObj; + napi_create_object(env, &resultObj); - napi_get_value_string_utf16(env, argv[1], widePlaceholderId.get(), placeholderIdLength + 1, nullptr); + napi_value successValue; + napi_get_boolean(env, result.success, &successValue); + napi_set_named_property(env, resultObj, "success", successValue); - bool success = Placeholders::ConvertToPlaceholder( - reinterpret_cast(widePath.get()), - reinterpret_cast(widePlaceholderId.get())); + if (!result.success) + { + std::string errorMessage(result.errorMessage.begin(), result.errorMessage.end()); + napi_value errorValue; + napi_create_string_utf8(env, errorMessage.c_str(), errorMessage.length(), &errorValue); + napi_set_named_property(env, resultObj, "errorMessage", errorValue); + } - napi_value result; - napi_get_boolean(env, success, &result); - return result; + return resultObj; } napi_value UpdateFileIdentityWrapper(napi_env env, napi_callback_info args)