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
4 changes: 2 additions & 2 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
types: [published]
Copy link
Contributor Author

@dajimenezriv-internxt dajimenezriv-internxt Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was fixed since the last version but it was not merged.


jobs:
publish_npm:
publish:
runs-on: ubuntu-latest
timeout-minutes: 1

Expand All @@ -24,7 +24,7 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "@internxt:registry=https://npm.pkg.github.com/" > .npmrc
echo "//npm.pkg.github.com/:_authToken=$GITHUB_TOKEN >> .npmrc
echo "//npm.pkg.github.com/:_authToken=$GITHUB_TOKEN" >> .npmrc

- name: Publish package to github
run: npm publish --scope=@internxt --access public
Expand Down
Binary file modified dist/addon.node
Binary file not shown.
24 changes: 0 additions & 24 deletions include/placeholders_interface/Placeholders.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,13 @@
#include <string>
#include <PlaceholderInfo.h>

struct PlaceholderResult {
bool success;
std::wstring errorMessage;
};

class Placeholders
{
public:
static PlaceholderResult CreateOne(
const wchar_t *fileName,
const wchar_t *fileIdentity,
int64_t fileSize,
LARGE_INTEGER creationTime,
LARGE_INTEGER lastWriteTime,
LARGE_INTEGER lastAccessTime,
const wchar_t *destPath);

static void MaintainIdentity(std::wstring &fullPath, PCWSTR fileIdentity, bool isDirectory);

static PlaceholderResult CreateEntry(
const wchar_t *itemName,
const wchar_t *itemIdentity,
LARGE_INTEGER creationTime,
LARGE_INTEGER lastWriteTime,
LARGE_INTEGER lastAccessTime,
const wchar_t *destPath);

static void ForceShellRefresh(const std::wstring &path);
static void UpdateSyncStatus(const std::wstring &filePath, bool syncState, bool isDirectory);
static HRESULT UpdatePinState(const std::wstring &path, const PinState state);
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 FileState GetPlaceholderInfo(const std::wstring &directoryPath);
Expand Down
4 changes: 2 additions & 2 deletions include/virtual_drive/Wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

#include <node_api.h>

napi_value CreatePlaceholderFile(napi_env env, napi_callback_info args);
napi_value CreateFilePlaceholderWrapper(napi_env env, napi_callback_info args);
napi_value CreateFolderPlaceholderWrapper(napi_env env, napi_callback_info args);
napi_value UnregisterSyncRootWrapper(napi_env env, napi_callback_info args);
napi_value RegisterSyncRootWrapper(napi_env env, napi_callback_info args);
napi_value GetRegisteredSyncRootsWrapper(napi_env env, napi_callback_info args);
napi_value ConnectSyncRootWrapper(napi_env env, napi_callback_info args);
napi_value CreateEntryWrapper(napi_env env, napi_callback_info args);
napi_value DisconnectSyncRootWrapper(napi_env env, napi_callback_info args);
napi_value GetFileIdentityWrapper(napi_env env, napi_callback_info args);
napi_value addLoggerPathWrapper(napi_env env, napi_callback_info args);
Expand Down
3 changes: 2 additions & 1 deletion include/virtual_drive/convert_to_placeholder.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

#include <node_api.h>

napi_value convert_to_placeholder_impl(napi_env env, napi_callback_info args);
napi_value convert_to_placeholder_wrapper(napi_env env, napi_callback_info args);
void convert_to_placeholder(const std::wstring &path, const std::wstring &placeholderId);
16 changes: 8 additions & 8 deletions native-src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
napi_value init(napi_env env, napi_value exports)
{
napi_property_descriptor desc = {
"createPlaceholderFile",
"createFilePlaceholder",
nullptr,
CreatePlaceholderFile,
CreateFilePlaceholderWrapper,
nullptr,
nullptr,
nullptr,
Expand Down Expand Up @@ -88,20 +88,20 @@ napi_value init(napi_env env, napi_value exports)
return nullptr;
}

napi_property_descriptor createEntryDesc = {
"createEntry",
napi_property_descriptor createFolderPlaceholderDesc = {
"createFolderPlaceholder",
nullptr,
CreateEntryWrapper,
CreateFolderPlaceholderWrapper,
nullptr,
nullptr,
nullptr,
napi_default,
nullptr};

napi_status defineCreateEntryStatus = napi_define_properties(env, exports, 1, &createEntryDesc);
if (defineCreateEntryStatus != napi_ok)
napi_status defineCreateFolderPlaceholderStatus = napi_define_properties(env, exports, 1, &createFolderPlaceholderDesc);
if (defineCreateFolderPlaceholderStatus != napi_ok)
{
napi_throw_error(env, nullptr, "Failed to define createEntry function");
napi_throw_error(env, nullptr, "Failed to define createFolderPlaceholder function");
return nullptr;
}

Expand Down
205 changes: 2 additions & 203 deletions native-src/placeholders_interface/Planceholders.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,88 +15,14 @@
#include <cctype>
#include <windows.h>
#include <shlobj.h>
#include "convert_to_placeholder.h"

using namespace std;

namespace fs = std::filesystem;

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

bool DirectoryExists(const wchar_t *path)
{
DWORD attributes = GetFileAttributesW(path);
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY);
}

PlaceholderResult Placeholders::CreateOne(
const wchar_t *fileName,
const wchar_t *fileIdentity,
int64_t fileSize,
LARGE_INTEGER creationTime,
LARGE_INTEGER lastWriteTime,
LARGE_INTEGER lastAccessTime,
const wchar_t *destPath)
{
PlaceholderResult result = {false, L""};

try
{
CF_PLACEHOLDER_CREATE_INFO cloudEntry = {};

std::wstring fullDestPath = std::wstring(destPath) + L'\\';

wstring fullPath = std::wstring(destPath) + L'\\' + fileName;

if (std::filesystem::exists(fullPath))
{
Placeholders::ConvertToPlaceholder(fullPath, fileIdentity);
Placeholders::MaintainIdentity(fullPath, fileIdentity, false);
result.success = true;
return result;
}

std::wstring relativeName(fileIdentity);

cloudEntry.FileIdentity = relativeName.c_str();
cloudEntry.FileIdentityLength = static_cast<DWORD>((relativeName.size() + 1) * sizeof(WCHAR));

cloudEntry.RelativeFileName = fileName;
cloudEntry.Flags = CF_PLACEHOLDER_CREATE_FLAG_MARK_IN_SYNC;

cloudEntry.FsMetadata.FileSize.QuadPart = fileSize;
cloudEntry.FsMetadata.BasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
cloudEntry.FsMetadata.BasicInfo.CreationTime = creationTime;
cloudEntry.FsMetadata.BasicInfo.LastWriteTime = lastWriteTime;
cloudEntry.FsMetadata.BasicInfo.LastAccessTime = lastAccessTime;
cloudEntry.FsMetadata.BasicInfo.ChangeTime = lastWriteTime;

try
{
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;
prop.Id(1);
prop.Value(L"Value1");
prop.IconResource(L"shell32.dll,-44");

// UpdateSyncStatus(fullDestPath, true, false);
}
catch (...)
{
result.errorMessage = L"Failed to create or customize placeholder";
wprintf(L"[CreatePlaceholder] Failed to create or customize placeholder with %08x\n", static_cast<HRESULT>(winrt::to_hresult()));
}

return result;
}

std::string cleanString(const std::string &str)
{
std::string cleanedStr;
Expand Down Expand Up @@ -136,133 +62,6 @@ void Placeholders::MaintainIdentity(std::wstring &fullPath, PCWSTR itemIdentity,
}
}

PlaceholderResult Placeholders::CreateEntry(
const wchar_t *itemName,
const wchar_t *itemIdentity,
LARGE_INTEGER creationTime,
LARGE_INTEGER lastWriteTime,
LARGE_INTEGER lastAccessTime,
const wchar_t *destPath)
{
PlaceholderResult result = {false, L""};

std::wstring fullDestPath = std::wstring(destPath) + L"\\" + std::wstring(itemName);
CF_PLACEHOLDER_CREATE_INFO cloudEntry = {};
std::wstring relativeName(itemIdentity);
cloudEntry.FileIdentity = relativeName.c_str();
cloudEntry.FileIdentityLength = static_cast<DWORD>((relativeName.size() + 1) * sizeof(WCHAR));
cloudEntry.RelativeFileName = itemName;
cloudEntry.Flags = CF_PLACEHOLDER_CREATE_FLAG_DISABLE_ON_DEMAND_POPULATION; // -> desactive download on demand
cloudEntry.FsMetadata.BasicInfo.FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
cloudEntry.FsMetadata.BasicInfo.CreationTime = creationTime;
cloudEntry.FsMetadata.BasicInfo.LastWriteTime = lastWriteTime;
cloudEntry.FsMetadata.BasicInfo.LastAccessTime = lastAccessTime;

try
{
// TODO: si existe o es placeholder return
if (DirectoryExists(fullDestPath.c_str()))
{
Placeholders::ConvertToPlaceholder(fullDestPath, itemIdentity);
Placeholders::MaintainIdentity(fullDestPath, itemIdentity, true);
result.success = true;
return result;
}

// wprintf(L"Create directory, full destination path: %ls, fullDestPath.c_str()");
PathRemoveFileSpecW(&fullDestPath[0]);
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);
}

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", L"directory", error.message().c_str());
}
catch (...)
{
result.errorMessage = L"Unknown error occurred";
wprintf(L"[CreatePlaceholder] Unknown error occurred\n");
}

return result;
}

PlaceholderResult Placeholders::ConvertToPlaceholder(const std::wstring &fullPath, const std::wstring &serverIdentity)
{
PlaceholderResult result = {false, L""};

if (!std::filesystem::exists(fullPath))
{
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);

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)
{
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 = {};

LPCVOID idStrLPCVOID = static_cast<LPCVOID>(serverIdentity.c_str());
DWORD idStrByteLength = static_cast<DWORD>(serverIdentity.size() * sizeof(wchar_t));

HRESULT hr = CfConvertToPlaceholder(fileHandle, idStrLPCVOID, idStrByteLength, convertFlags, &convertUsn, &overlapped);

if (FAILED(hr))
{
CloseHandle(fileHandle);
if (hr != 0x8007017C) // Ignorar error específico de "ya es un placeholder"
{
result.errorMessage = L"Failed to convert to placeholder. HRESULT: 0x" + std::to_wstring(static_cast<unsigned int>(hr));
return result;
}
return result;
}

if (!isDirectory)
{
HRESULT hrPinState = CfSetPinState(fileHandle, CF_PIN_STATE_PINNED, CF_SET_PIN_FLAG_NONE, nullptr);
if (FAILED(hrPinState))
{
CloseHandle(fileHandle);
result.errorMessage = L"Failed to set pin state. HRESULT: 0x" + std::to_wstring(static_cast<unsigned int>(hrPinState));
return result;
}
}

CloseHandle(fileHandle);
wprintf(L"[ConvertToPlaceholder] Successfully converted to placeholder: %ls\n", fullPath.c_str());
result.success = true;
return result;
}

/**
* @brief Mark a file or directory as synchronized
* @param filePath path to the file or directory
Expand Down Expand Up @@ -315,7 +114,7 @@ void Placeholders::UpdateSyncStatus(const std::wstring &filePath,
break;

case ERROR_CLOUD_FILE_NOT_IN_SYNC:
ConvertToPlaceholder(filePath, L"temp_identity");
convert_to_placeholder(filePath, L"temp_identity");
hr = CfSetInSyncState(h, sync, CF_SET_IN_SYNC_FLAG_NONE, nullptr);
wprintf(L"[UpdateSyncStatus] Retry CfSetInSyncState\n");
break;
Expand Down
6 changes: 3 additions & 3 deletions native-src/virtual_drive/Wrappers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#include "update_sync_status_wrapper.h"
#include "NAPI_SAFE_WRAP.h"

napi_value CreatePlaceholderFile(napi_env env, napi_callback_info args) {
napi_value CreateFilePlaceholderWrapper(napi_env env, napi_callback_info args) {
return NAPI_SAFE_WRAP(env, args, create_file_placeholder_impl);
}

Expand All @@ -43,7 +43,7 @@ napi_value ConnectSyncRootWrapper(napi_env env, napi_callback_info args) {
return NAPI_SAFE_WRAP(env, args, connect_sync_root_impl);
}

napi_value CreateEntryWrapper(napi_env env, napi_callback_info args) {
napi_value CreateFolderPlaceholderWrapper(napi_env env, napi_callback_info args) {
return NAPI_SAFE_WRAP(env, args, create_folder_placeholder_impl);
}

Expand Down Expand Up @@ -104,7 +104,7 @@ napi_value GetPlaceholderStateWrapper(napi_env env, napi_callback_info args) {
}

napi_value ConvertToPlaceholderWrapper(napi_env env, napi_callback_info args) {
return NAPI_SAFE_WRAP(env, args, convert_to_placeholder_impl);
return NAPI_SAFE_WRAP(env, args, convert_to_placeholder_wrapper);
}

napi_value HydrateFileWrapper(napi_env env, napi_callback_info args) {
Expand Down
Loading