Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified dist/addon.node
Binary file not shown.
8 changes: 4 additions & 4 deletions include/placeholders_interface/Placeholders.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
class Placeholders
{
public:
static void MaintainIdentity(const std::wstring &fullPath, PCWSTR fileIdentity, bool isDirectory);
static void UpdateSyncStatus(const std::wstring &filePath, bool isDirectory);
static void UpdateFileIdentity(const std::wstring &filePath, const std::wstring &fileIdentity, bool isDirectory);
static FileState GetPlaceholderInfo(const std::wstring &directoryPath);
static winrt::file_handle OpenFileHandle(const std::wstring &path, DWORD accessRights, bool openAsPlaceholder);
static void UpdateSyncStatus(const std::wstring &path);
static void UpdateFileIdentity(const std::wstring &path, const std::wstring &placeholderId);
static FileState GetPlaceholderInfo(const std::wstring &path);
};
8 changes: 0 additions & 8 deletions include/sync_root_interface/SyncRoot.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,11 @@
#include <iostream>
#include <vector>

struct ItemInfo
{
std::wstring path;
std::wstring fileIdentity;
bool isPlaceholder;
};

class SyncRoot
{
public:
static HRESULT ConnectSyncRoot(const wchar_t *syncRootPath, InputSyncCallbacks syncCallbacks, napi_env env, CF_CONNECTION_KEY *connectionKey);
static HRESULT DisconnectSyncRoot(const wchar_t *syncRootPath);
static void HydrateFile(const wchar_t *filePath);

private:
CF_CONNECTION_KEY connectionKey;
Expand Down
24 changes: 5 additions & 19 deletions include/sync_root_interface/Utilities.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ class Utilities
{
public:
static void ApplyTransferStateToFile(_In_ LPCWSTR fullPath, _In_ CF_CALLBACK_INFO &callbackInfo, UINT64 total, UINT64 completed);
static std::wstring GetErrorMessageCloudFiles(HRESULT hr);

static winrt::com_array<wchar_t>
ConvertSidToStringSid(_In_ PSID sid)
Expand All @@ -20,16 +19,17 @@ class Utilities
}
};

inline static LARGE_INTEGER JsTimestampToLargeInteger(int64_t jsTimestamp) {
inline static LARGE_INTEGER JsTimestampToLargeInteger(int64_t jsTimestamp)
{
const int64_t EPOCH_DIFFERENCE = 11644473600000LL;
const int64_t MS_TO_100NS = 10000LL;

int64_t windowsTime = (jsTimestamp + EPOCH_DIFFERENCE) * MS_TO_100NS;

LARGE_INTEGER largeInteger;
largeInteger.LowPart = static_cast<DWORD>(windowsTime & 0xFFFFFFFF);
largeInteger.HighPart = static_cast<DWORD>((windowsTime >> 32) & 0xFFFFFFFF);

return largeInteger;
}

Expand All @@ -39,18 +39,4 @@ class Utilities
largeInteger.QuadPart = longlong;
return largeInteger;
}

static DWORD convertSizeToDWORD(size_t &convertVar)
{
if (convertVar > UINT_MAX)
{
convertVar = UINT_MAX;
}
return static_cast<DWORD>(convertVar);
}

static DWORD sizeToDWORD(size_t size)
{
return convertSizeToDWORD(size);
}
};
146 changes: 38 additions & 108 deletions native-src/placeholders_interface/Planceholders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,71 +17,41 @@
#include <shlobj.h>
#include "convert_to_placeholder.h"

using namespace std;

namespace fs = std::filesystem;

#pragma comment(lib, "shlwapi.lib")

std::string cleanString(const std::string &str)
winrt::file_handle Placeholders::OpenFileHandle(const std::wstring &path, DWORD dwDesiredAccess, bool openAsPlaceholder)
{
std::string cleanedStr;
for (char ch : str)
{
if (std::isprint(static_cast<unsigned char>(ch)))
{
cleanedStr.push_back(ch);
}
}
return cleanedStr;
}

void Placeholders::MaintainIdentity(const std::wstring &fullPath, PCWSTR itemIdentity, bool isDirectory)
{
std::string identity = Placeholders::GetPlaceholderInfo(fullPath).placeholderId;
if (!identity.empty())
{
int len = WideCharToMultiByte(CP_UTF8, 0, itemIdentity, -1, NULL, 0, NULL, NULL);
if (len > 0)
{
std::string itemIdentityStr(len, 0);
WideCharToMultiByte(CP_UTF8, 0, itemIdentity, -1, &itemIdentityStr[0], len, NULL, NULL);
std::string cleanIdentity = cleanString(identity);
std::string cleanItemIdentity = cleanString(itemIdentityStr);
if (cleanIdentity != cleanItemIdentity)
{
wprintf(L"[MaintainIdentity] Identity is incorrect, updating...\n");
std::wstring itemIdentityStrW(itemIdentity);
Placeholders::UpdateFileIdentity(fullPath, itemIdentityStrW, isDirectory);
}
}
else
{
// Handle error as needed
}
}
}
bool isDirectory = std::filesystem::is_directory(path);

void Placeholders::UpdateSyncStatus(const std::wstring &path, bool isDirectory)
{
DWORD flags = FILE_FLAG_OPEN_REPARSE_POINT;
DWORD dwFlagsAndAttributes = 0;
if (openAsPlaceholder)
dwFlagsAndAttributes |= FILE_FLAG_OPEN_REPARSE_POINT;
if (isDirectory)
flags |= FILE_FLAG_BACKUP_SEMANTICS;
dwFlagsAndAttributes |= FILE_FLAG_BACKUP_SEMANTICS;

DWORD dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;

winrt::file_handle fileHandle{CreateFileW(
path.c_str(),
FILE_WRITE_ATTRIBUTES,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
dwDesiredAccess,
dwShareMode,
nullptr,
OPEN_EXISTING,
flags,
dwFlagsAndAttributes,
nullptr)};

if (!fileHandle)
{
throw std::runtime_error("Failed to open item: " + std::to_string(GetLastError()));
throw std::runtime_error("Failed to open file handle: " + std::to_string(GetLastError()));
}

return fileHandle;
}

void Placeholders::UpdateSyncStatus(const std::wstring &path)
{
auto fileHandle = Placeholders::OpenFileHandle(path, FILE_WRITE_ATTRIBUTES, true);

winrt::check_hresult(CfSetInSyncState(
fileHandle.get(),
CF_IN_SYNC_STATE_IN_SYNC,
Expand All @@ -91,82 +61,42 @@ void Placeholders::UpdateSyncStatus(const std::wstring &path, bool isDirectory)
SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, path.c_str(), nullptr);
}

void Placeholders::UpdateFileIdentity(const std::wstring &filePath, const std::wstring &fileIdentity, bool isDirectory)
void Placeholders::UpdateFileIdentity(const std::wstring &path, const std::wstring &placeholderId)
{
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);
auto fileHandle = OpenFileHandle(path, FILE_WRITE_ATTRIBUTES, true);

if (fileHandle == INVALID_HANDLE_VALUE)
{
DWORD errorCode = GetLastError();
wprintf(L"[UpdateFileIdentity] Error opening file: %d\n", errorCode);
LPWSTR errorMessage = nullptr;
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
nullptr,
errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&errorMessage),
0,
nullptr);
if (errorMessage)
{
wprintf(L"[UpdateFileIdentity] Error: %ls\n", errorMessage);
LocalFree(errorMessage);
}
return;
}

HRESULT hr = CfUpdatePlaceholder(
fileHandle, // Handle del archivo.
nullptr, // CF_FS_METADATA opcional.
fileIdentity.c_str(), // Identidad del archivo.
static_cast<DWORD>(fileIdentity.size() * sizeof(wchar_t)), // Longitud de la identidad del archivo.
nullptr, // Rango a deshidratar, opcional.
0, // Conteo de rangos a deshidratar, debe ser 0 si no se usa.
CF_UPDATE_FLAG_NONE, // Flags de actualización.
nullptr, // USN opcional.
nullptr // OVERLAPPED opcional.
);

if (FAILED(hr))
{
std::wstring errorMessage = Utilities::GetErrorMessageCloudFiles(hr);
wprintf(L"[UpdateFileIdentity] Error updating fileIdentity: %ls\n", errorMessage.c_str());
CloseHandle(fileHandle);
return;
}

CloseHandle(fileHandle);
winrt::check_hresult(CfUpdatePlaceholder(
fileHandle.get(),
nullptr,
placeholderId.c_str(),
static_cast<DWORD>(placeholderId.size() * sizeof(wchar_t)),
nullptr,
0,
CF_UPDATE_FLAG_NONE,
nullptr,
nullptr));
}

FileState Placeholders::GetPlaceholderInfo(const std::wstring &path)
{
auto fileHandle = OpenFileHandle(path, FILE_READ_ATTRIBUTES, true);

constexpr DWORD fileIdMaxLength = 400;
constexpr DWORD infoSize = sizeof(CF_PLACEHOLDER_BASIC_INFO) + fileIdMaxLength;

std::vector<char> buffer(infoSize);
auto *info = reinterpret_cast<CF_PLACEHOLDER_BASIC_INFO *>(buffer.data());

auto fileHandle = handleForPath(path);
if (!fileHandle)
{
throw std::runtime_error("Failed to get file handle: " + std::to_string(GetLastError()));
}

winrt::check_hresult(CfGetPlaceholderInfo(
fileHandle.get(),
CF_PLACEHOLDER_INFO_BASIC,
info,
infoSize,
nullptr));

return FileState{
std::string(reinterpret_cast<const char *>(info->FileIdentity), info->FileIdentityLength),
info->PinState};
std::string placeholderId(reinterpret_cast<const char *>(info->FileIdentity), info->FileIdentityLength);

placeholderId.erase(std::remove(placeholderId.begin(), placeholderId.end(), '\0'), placeholderId.end());

return FileState{placeholderId, info->PinState};
}
58 changes: 6 additions & 52 deletions native-src/sync_root_interface/SyncRoot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,51 +8,6 @@

std::map<std::wstring, CF_CONNECTION_KEY> connectionMap;

void SyncRoot::HydrateFile(const wchar_t *filePath)
{
wprintf(L"Hydration file started %ls\n", filePath);
DWORD attrib = GetFileAttributesW(filePath);
if (!(attrib & FILE_ATTRIBUTE_DIRECTORY))
{
winrt::handle placeholder(CreateFileW(filePath, 0, FILE_READ_DATA, nullptr, OPEN_EXISTING, 0, nullptr));

LARGE_INTEGER offset;
offset.QuadPart = 0;
LARGE_INTEGER length;
GetFileSizeEx(placeholder.get(), &length);

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();

HRESULT hr = CfHydratePlaceholder(placeholder.get(), offset, length, CF_HYDRATE_FLAG_NONE, NULL);

if (FAILED(hr))
{
Logger::getInstance().log("Error hydrating file " + Logger::fromWStringToString(filePath), LogLevel::ERROR);
}
else
{
auto end = std::chrono::steady_clock::now();
auto elapsedMilliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

if (elapsedMilliseconds < 200)
{
wprintf(L"Already Hydrated: %d ms\n", elapsedMilliseconds);
}
else
{
wprintf(L"Hydration finished %ls\n", filePath);
}
}
}
}
}

HRESULT SyncRoot::ConnectSyncRoot(const wchar_t *syncRootPath, InputSyncCallbacks syncCallbacks, napi_env env, CF_CONNECTION_KEY *connectionKey)
{
register_threadsafe_fetch_data_callback("FetchDataThreadSafe", env, syncCallbacks);
Expand All @@ -61,23 +16,22 @@ HRESULT SyncRoot::ConnectSyncRoot(const wchar_t *syncRootPath, InputSyncCallback
CF_CALLBACK_REGISTRATION callbackTable[] = {
{CF_CALLBACK_TYPE_FETCH_DATA, fetch_data_callback_wrapper},
{CF_CALLBACK_TYPE_CANCEL_FETCH_DATA, cancel_fetch_data_callback_wrapper},
CF_CALLBACK_REGISTRATION_END
};
CF_CALLBACK_REGISTRATION_END};

HRESULT hr = CfConnectSyncRoot(
syncRootPath,
callbackTable,
nullptr,
CF_CONNECT_FLAG_REQUIRE_PROCESS_INFO | CF_CONNECT_FLAG_REQUIRE_FULL_FILE_PATH,
connectionKey
);
connectionKey);

wprintf(L"Connection key: %llu\n", connectionKey->Internal);

if (SUCCEEDED(hr)) {

if (SUCCEEDED(hr))
{
connectionMap[syncRootPath] = *connectionKey;
}

return hr;
}

Expand Down
Loading