mirror of
https://github.com/nodejs/node.git
synced 2024-11-21 10:59:27 +00:00
fs: use wstring
on Windows paths
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com> PR-URL: https://github.com/nodejs/node/pull/55171 Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com>
This commit is contained in:
parent
d7a0b56b2c
commit
56e5bd8d2a
115
src/node_file.cc
115
src/node_file.cc
@ -3127,6 +3127,55 @@ static void GetFormatOfExtensionlessFile(
|
|||||||
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT);
|
return args.GetReturnValue().Set(EXTENSIONLESS_FORMAT_JAVASCRIPT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::wstring ConvertToWideString(const std::string& str) {
|
||||||
|
int size_needed = MultiByteToWideChar(
|
||||||
|
CP_UTF8, 0, &str[0], static_cast<int>(str.size()), nullptr, 0);
|
||||||
|
std::wstring wstrTo(size_needed, 0);
|
||||||
|
MultiByteToWideChar(CP_UTF8,
|
||||||
|
0,
|
||||||
|
&str[0],
|
||||||
|
static_cast<int>(str.size()),
|
||||||
|
&wstrTo[0],
|
||||||
|
size_needed);
|
||||||
|
return wstrTo;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BufferValueToPath(str) \
|
||||||
|
std::filesystem::path(ConvertToWideString(str.ToString()))
|
||||||
|
|
||||||
|
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) {
|
static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
|
||||||
Environment* env = Environment::GetCurrent(args);
|
Environment* env = Environment::GetCurrent(args);
|
||||||
Isolate* isolate = env->isolate();
|
Isolate* isolate = env->isolate();
|
||||||
@ -3139,7 +3188,7 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
|
|||||||
THROW_IF_INSUFFICIENT_PERMISSIONS(
|
THROW_IF_INSUFFICIENT_PERMISSIONS(
|
||||||
env, permission::PermissionScope::kFileSystemRead, src.ToStringView());
|
env, permission::PermissionScope::kFileSystemRead, src.ToStringView());
|
||||||
|
|
||||||
auto src_path = std::filesystem::path(src.ToU8StringView());
|
auto src_path = BufferValueToPath(src);
|
||||||
|
|
||||||
BufferValue dest(isolate, args[1]);
|
BufferValue dest(isolate, args[1]);
|
||||||
CHECK_NOT_NULL(*dest);
|
CHECK_NOT_NULL(*dest);
|
||||||
@ -3147,7 +3196,7 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
|
|||||||
THROW_IF_INSUFFICIENT_PERMISSIONS(
|
THROW_IF_INSUFFICIENT_PERMISSIONS(
|
||||||
env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView());
|
env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView());
|
||||||
|
|
||||||
auto dest_path = std::filesystem::path(dest.ToU8StringView());
|
auto dest_path = BufferValueToPath(dest);
|
||||||
bool dereference = args[2]->IsTrue();
|
bool dereference = args[2]->IsTrue();
|
||||||
bool recursive = args[3]->IsTrue();
|
bool recursive = args[3]->IsTrue();
|
||||||
|
|
||||||
@ -3176,47 +3225,41 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
|
|||||||
(src_status.type() == std::filesystem::file_type::directory) ||
|
(src_status.type() == std::filesystem::file_type::directory) ||
|
||||||
(dereference && src_status.type() == std::filesystem::file_type::symlink);
|
(dereference && src_status.type() == std::filesystem::file_type::symlink);
|
||||||
|
|
||||||
|
auto src_path_str = PathToString(src_path);
|
||||||
|
auto dest_path_str = PathToString(dest_path);
|
||||||
|
|
||||||
if (!error_code) {
|
if (!error_code) {
|
||||||
// Check if src and dest are identical.
|
// Check if src and dest are identical.
|
||||||
if (std::filesystem::equivalent(src_path, dest_path)) {
|
if (std::filesystem::equivalent(src_path, dest_path)) {
|
||||||
std::u8string message =
|
std::string message = "src and dest cannot be the same %s";
|
||||||
u8"src and dest cannot be the same " + dest_path.u8string();
|
return THROW_ERR_FS_CP_EINVAL(env, message.c_str(), dest_path_str);
|
||||||
return THROW_ERR_FS_CP_EINVAL(
|
|
||||||
env, reinterpret_cast<const char*>(message.c_str()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool dest_is_dir =
|
const bool dest_is_dir =
|
||||||
dest_status.type() == std::filesystem::file_type::directory;
|
dest_status.type() == std::filesystem::file_type::directory;
|
||||||
|
|
||||||
if (src_is_dir && !dest_is_dir) {
|
if (src_is_dir && !dest_is_dir) {
|
||||||
std::u8string message = u8"Cannot overwrite non-directory " +
|
std::string message =
|
||||||
src_path.u8string() + u8" with directory " +
|
"Cannot overwrite non-directory %s with directory %s";
|
||||||
dest_path.u8string();
|
|
||||||
return THROW_ERR_FS_CP_DIR_TO_NON_DIR(
|
return THROW_ERR_FS_CP_DIR_TO_NON_DIR(
|
||||||
env, reinterpret_cast<const char*>(message.c_str()));
|
env, message.c_str(), src_path_str, dest_path_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!src_is_dir && dest_is_dir) {
|
if (!src_is_dir && dest_is_dir) {
|
||||||
std::u8string message = u8"Cannot overwrite directory " +
|
std::string message =
|
||||||
dest_path.u8string() + u8" with non-directory " +
|
"Cannot overwrite directory %s with non-directory %s";
|
||||||
src_path.u8string();
|
|
||||||
return THROW_ERR_FS_CP_NON_DIR_TO_DIR(
|
return THROW_ERR_FS_CP_NON_DIR_TO_DIR(
|
||||||
env, reinterpret_cast<const char*>(message.c_str()));
|
env, message.c_str(), dest_path_str, src_path_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::u8string dest_path_str = dest_path.u8string();
|
|
||||||
std::u8string src_path_str = src_path.u8string();
|
|
||||||
if (!src_path_str.ends_with(std::filesystem::path::preferred_separator)) {
|
if (!src_path_str.ends_with(std::filesystem::path::preferred_separator)) {
|
||||||
src_path_str += std::filesystem::path::preferred_separator;
|
src_path_str += std::filesystem::path::preferred_separator;
|
||||||
}
|
}
|
||||||
// Check if dest_path is a subdirectory of src_path.
|
// Check if dest_path is a subdirectory of src_path.
|
||||||
if (src_is_dir && dest_path_str.starts_with(src_path_str)) {
|
if (src_is_dir && dest_path_str.starts_with(src_path_str)) {
|
||||||
std::u8string message = u8"Cannot copy " + src_path.u8string() +
|
std::string message = "Cannot copy %s to a subdirectory of self %s";
|
||||||
u8" to a subdirectory of self " +
|
|
||||||
dest_path.u8string();
|
|
||||||
return THROW_ERR_FS_CP_EINVAL(
|
return THROW_ERR_FS_CP_EINVAL(
|
||||||
env, reinterpret_cast<const char*>(message.c_str()));
|
env, message.c_str(), src_path_str, dest_path_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dest_parent = dest_path.parent_path();
|
auto dest_parent = dest_path.parent_path();
|
||||||
@ -3227,11 +3270,9 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
|
|||||||
dest_parent.parent_path() != dest_parent) {
|
dest_parent.parent_path() != dest_parent) {
|
||||||
if (std::filesystem::equivalent(
|
if (std::filesystem::equivalent(
|
||||||
src_path, dest_path.parent_path(), error_code)) {
|
src_path, dest_path.parent_path(), error_code)) {
|
||||||
std::u8string message = u8"Cannot copy " + src_path.u8string() +
|
std::string message = "Cannot copy %s to a subdirectory of self %s";
|
||||||
u8" to a subdirectory of self " +
|
|
||||||
dest_path.u8string();
|
|
||||||
return THROW_ERR_FS_CP_EINVAL(
|
return THROW_ERR_FS_CP_EINVAL(
|
||||||
env, reinterpret_cast<const char*>(message.c_str()));
|
env, message.c_str(), src_path_str, dest_path_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If equivalent fails, it's highly likely that dest_parent does not exist
|
// If equivalent fails, it's highly likely that dest_parent does not exist
|
||||||
@ -3243,29 +3284,23 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (src_is_dir && !recursive) {
|
if (src_is_dir && !recursive) {
|
||||||
std::u8string message =
|
std::string message =
|
||||||
u8"Recursive option not enabled, cannot copy a directory: " +
|
"Recursive option not enabled, cannot copy a directory: %s";
|
||||||
src_path.u8string();
|
return THROW_ERR_FS_EISDIR(env, message.c_str(), src_path_str);
|
||||||
return THROW_ERR_FS_EISDIR(env,
|
|
||||||
reinterpret_cast<const char*>(message.c_str()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (src_status.type()) {
|
switch (src_status.type()) {
|
||||||
case std::filesystem::file_type::socket: {
|
case std::filesystem::file_type::socket: {
|
||||||
std::u8string message = u8"Cannot copy a socket file: " + dest_path_str;
|
std::string message = "Cannot copy a socket file: %s";
|
||||||
return THROW_ERR_FS_CP_SOCKET(
|
return THROW_ERR_FS_CP_SOCKET(env, message.c_str(), dest_path_str);
|
||||||
env, reinterpret_cast<const char*>(message.c_str()));
|
|
||||||
}
|
}
|
||||||
case std::filesystem::file_type::fifo: {
|
case std::filesystem::file_type::fifo: {
|
||||||
std::u8string message = u8"Cannot copy a FIFO pipe: " + dest_path_str;
|
std::string message = "Cannot copy a FIFO pipe: %s";
|
||||||
return THROW_ERR_FS_CP_FIFO_PIPE(
|
return THROW_ERR_FS_CP_FIFO_PIPE(env, message.c_str(), dest_path_str);
|
||||||
env, reinterpret_cast<const char*>(message.c_str()));
|
|
||||||
}
|
}
|
||||||
case std::filesystem::file_type::unknown: {
|
case std::filesystem::file_type::unknown: {
|
||||||
std::u8string message =
|
std::string message = "Cannot copy an unknown file type: %s";
|
||||||
u8"Cannot copy an unknown file type: " + dest_path_str;
|
return THROW_ERR_FS_CP_UNKNOWN(env, message.c_str(), dest_path_str);
|
||||||
return THROW_ERR_FS_CP_UNKNOWN(
|
|
||||||
env, reinterpret_cast<const char*>(message.c_str()));
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -25,7 +25,7 @@ tmpdir.refresh();
|
|||||||
|
|
||||||
let dirc = 0;
|
let dirc = 0;
|
||||||
function nextdir(dirname) {
|
function nextdir(dirname) {
|
||||||
return tmpdir.resolve(dirname || `copy_${++dirc}`);
|
return tmpdir.resolve(dirname || `copy_%${++dirc}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Synchronous implementation of copy.
|
// Synchronous implementation of copy.
|
||||||
|
Loading…
Reference in New Issue
Block a user