Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
6 changes: 2 additions & 4 deletions src/compile_cache.cc
Original file line number Diff line number Diff line change
Expand Up @@ -232,10 +232,8 @@ static std::string GetRelativePath(std::string_view path,
// the paths to wide strings before using std::filesystem::path.
// On other platforms, std::filesystem::path can handle UTF-8 directly.
#ifdef _WIN32
std::filesystem::path module_path(
ConvertToWideString(std::string(path), CP_UTF8));
std::filesystem::path base_path(
ConvertToWideString(std::string(base), CP_UTF8));
std::filesystem::path module_path(ConvertUTF8ToWideString(std::string(path)));
std::filesystem::path base_path(ConvertUTF8ToWideString(std::string(base)));
#else
std::filesystem::path module_path(path);
std::filesystem::path base_path(base);
Expand Down
52 changes: 8 additions & 44 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3169,42 +3169,6 @@ static void GetFormatOfExtensionlessFile(
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT);
}

#ifdef _WIN32
#define BufferValueToPath(str) \
std::filesystem::path(ConvertToWideString(str.ToString(), CP_UTF8))

std::string ConvertWideToUTF8(const std::wstring& wstr) {
if (wstr.empty()) return std::string();

int size_needed = WideCharToMultiByte(CP_UTF8,
0,
&wstr[0],
static_cast<int>(wstr.size()),
nullptr,
0,
nullptr,
nullptr);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8,
0,
&wstr[0],
static_cast<int>(wstr.size()),
&strTo[0],
size_needed,
nullptr,
nullptr);
return strTo;
}

#define PathToString(path) ConvertWideToUTF8(path.wstring());

#else // _WIN32

#define BufferValueToPath(str) std::filesystem::path(str.ToStringView());
#define PathToString(path) path.native();

#endif // _WIN32

static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args);
Isolate* isolate = env->isolate();
Expand All @@ -3217,15 +3181,15 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, src.ToStringView());

auto src_path = BufferValueToPath(src);
auto src_path = src.ToPath();

BufferValue dest(isolate, args[1]);
CHECK_NOT_NULL(*dest);
ToNamespacedPath(env, &dest);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView());

auto dest_path = BufferValueToPath(dest);
auto dest_path = dest.ToPath();
bool dereference = args[2]->IsTrue();
bool recursive = args[3]->IsTrue();

Expand Down Expand Up @@ -3254,8 +3218,8 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
(src_status.type() == std::filesystem::file_type::directory) ||
(dereference && src_status.type() == std::filesystem::file_type::symlink);

auto src_path_str = PathToString(src_path);
auto dest_path_str = PathToString(dest_path);
auto src_path_str = ConvertPathToUTF8(src_path);
auto dest_path_str = ConvertPathToUTF8(dest_path);

if (!error_code) {
// Check if src and dest are identical.
Expand Down Expand Up @@ -3350,7 +3314,7 @@ static bool CopyUtimes(const std::filesystem::path& src,
uv_fs_t req;
auto cleanup = OnScopeLeave([&req]() { uv_fs_req_cleanup(&req); });

auto src_path_str = PathToString(src);
auto src_path_str = ConvertPathToUTF8(src);
int result = uv_fs_stat(nullptr, &req, src_path_str.c_str(), nullptr);
if (is_uv_error(result)) {
env->ThrowUVException(result, "stat", nullptr, src_path_str.c_str());
Expand All @@ -3361,7 +3325,7 @@ static bool CopyUtimes(const std::filesystem::path& src,
const double source_atime = s->st_atim.tv_sec + s->st_atim.tv_nsec / 1e9;
const double source_mtime = s->st_mtim.tv_sec + s->st_mtim.tv_nsec / 1e9;

auto dest_file_path_str = PathToString(dest);
auto dest_file_path_str = ConvertPathToUTF8(dest);
int utime_result = uv_fs_utime(nullptr,
&req,
dest_file_path_str.c_str(),
Expand Down Expand Up @@ -3496,7 +3460,7 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
std::error_code error;
for (auto dir_entry : std::filesystem::directory_iterator(src)) {
auto dest_file_path = dest / dir_entry.path().filename();
auto dest_str = PathToString(dest);
auto dest_str = ConvertPathToUTF8(dest);

if (dir_entry.is_symlink()) {
if (verbatim_symlinks) {
Expand Down Expand Up @@ -3559,7 +3523,7 @@ static void CpSyncCopyDir(const FunctionCallbackInfo<Value>& args) {
}
} else if (std::filesystem::is_regular_file(dest_file_path)) {
if (!dereference || (!force && error_on_exist)) {
auto dest_file_path_str = PathToString(dest_file_path);
auto dest_file_path_str = ConvertPathToUTF8(dest_file_path);
env->ThrowStdErrException(
std::make_error_code(std::errc::file_exists),
"cp",
Expand Down
32 changes: 13 additions & 19 deletions src/node_modules.cc
Original file line number Diff line number Diff line change
Expand Up @@ -296,22 +296,24 @@ const BindingData::PackageConfig* BindingData::TraverseParent(

// Stop the search when the process doesn't have permissions
// to walk upwards
if (is_permissions_enabled &&
!env->permission()->is_granted(
env,
permission::PermissionScope::kFileSystemRead,
current_path.generic_string())) [[unlikely]] {
return nullptr;
if (is_permissions_enabled) {
if (!env->permission()->is_granted(
env,
permission::PermissionScope::kFileSystemRead,
ConvertGenericPathToUTF8(current_path))) [[unlikely]] {
return nullptr;
}
}

// Check if the path ends with `/node_modules`
if (current_path.generic_string().ends_with("/node_modules")) {
if (current_path.filename() == "node_modules") {
return nullptr;
}

auto package_json_path = current_path / "package.json";

auto package_json =
GetPackageJSON(realm, package_json_path.string(), nullptr);
GetPackageJSON(realm, ConvertPathToUTF8(package_json_path), nullptr);
if (package_json != nullptr) {
return package_json;
}
Expand All @@ -333,20 +335,12 @@ void BindingData::GetNearestParentPackageJSONType(

ToNamespacedPath(realm->env(), &path_value);

std::string path_value_str = path_value.ToString();
auto path = path_value.ToPath();

if (slashCheck) {
path_value_str.push_back(kPathSeparator);
path /= "";
}

std::filesystem::path path;

#ifdef _WIN32
std::wstring wide_path = ConvertToWideString(path_value_str, GetACP());
path = std::filesystem::path(wide_path);
#else
path = std::filesystem::path(path_value_str);
#endif

auto package_json = TraverseParent(realm, path);

if (package_json == nullptr) {
Expand Down
60 changes: 56 additions & 4 deletions src/util-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -718,19 +718,71 @@ inline bool IsWindowsBatchFile(const char* filename) {
return !extension.empty() && (extension == "cmd" || extension == "bat");
}

inline std::wstring ConvertToWideString(const std::string& str,
UINT code_page) {
inline std::wstring ConvertUTF8ToWideString(const std::string& str) {
int size_needed = MultiByteToWideChar(
code_page, 0, &str[0], static_cast<int>(str.size()), nullptr, 0);
CP_UTF8, 0, &str[0], static_cast<int>(str.size()), nullptr, 0);
std::wstring wstrTo(size_needed, 0);
MultiByteToWideChar(code_page,
MultiByteToWideChar(CP_UTF8,
0,
&str[0],
static_cast<int>(str.size()),
&wstrTo[0],
size_needed);
return wstrTo;
}

std::string ConvertWideStringToUTF8(const std::wstring& wstr) {
if (wstr.empty()) return std::string();

int size_needed = WideCharToMultiByte(CP_UTF8,
0,
&wstr[0],
static_cast<int>(wstr.size()),
nullptr,
0,
nullptr,
nullptr);
std::string strTo(size_needed, 0);
WideCharToMultiByte(CP_UTF8,
0,
&wstr[0],
static_cast<int>(wstr.size()),
&strTo[0],
size_needed,
nullptr,
nullptr);
return strTo;
}

template <typename T, size_t kStackStorageSize>
std::filesystem::path MaybeStackBuffer<T, kStackStorageSize>::ToPath() const {
std::wstring wide_path = ConvertUTF8ToWideString(ToString());
return std::filesystem::path(wide_path);
}

std::string ConvertPathToUTF8(const std::filesystem::path& path) {
return ConvertWideStringToUTF8(path.wstring());
}

std::string ConvertGenericPathToUTF8(const std::filesystem::path& path) {
return ConvertWideStringToUTF8(path.generic_wstring());
}

#else // _WIN32

template <typename T, size_t kStackStorageSize>
std::filesystem::path MaybeStackBuffer<T, kStackStorageSize>::ToPath() const {
return std::filesystem::path(ToStringView());
}

std::string ConvertPathToUTF8(const std::filesystem::path& path) {
return path.native();
}

std::string ConvertGenericPathToUTF8(const std::filesystem::path& path) {
return path.generic_string();
}

#endif // _WIN32

inline v8::MaybeLocal<v8::Object> NewDictionaryInstance(
Expand Down
9 changes: 8 additions & 1 deletion src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ class MaybeStackBuffer {
inline std::basic_string_view<T> ToStringView() const {
return {out(), length()};
}
inline std::filesystem::path ToPath() const;

private:
size_t length_;
Expand Down Expand Up @@ -1038,9 +1039,15 @@ class JSONOutputStream final : public v8::OutputStream {
// Returns true if OS==Windows and filename ends in .bat or .cmd,
// case insensitive.
inline bool IsWindowsBatchFile(const char* filename);
inline std::wstring ConvertToWideString(const std::string& str, UINT code_page);
inline std::wstring ConvertUTF8ToWideString(const std::string& str);
inline std::string ConvertWideStringToUTF8(const std::wstring& wstr);

#endif // _WIN32

inline std::filesystem::path ConvertUTF8ToPath(const std::string& str);
inline std::string ConvertPathToUTF8(const std::filesystem::path& path);
inline std::string ConvertGenericPathToUTF8(const std::filesystem::path& path);

// A helper to create a new instance of the dictionary template.
// Unlike v8::DictionaryTemplate::NewInstance, this method will
// check that all properties have been set (are not empty MaybeLocals)
Expand Down
Loading