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
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
10 changes: 9 additions & 1 deletion src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,8 @@ class MaybeStackBuffer {
inline std::basic_string_view<T> ToStringView() const {
return {out(), length()};
}
// This can only be used if the buffer contains path data in UTF8
inline std::filesystem::path ToPath() const;

private:
size_t length_;
Expand Down Expand Up @@ -1038,9 +1040,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