Skip to content

Commit

Permalink
fs: convert to u8 string for filesystem path
Browse files Browse the repository at this point in the history
PR-URL: nodejs#54653
Fixes: nodejs#54476
Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
jazelly authored and louwers committed Nov 2, 2024
1 parent efb6a48 commit ef0dafb
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 31 deletions.
77 changes: 46 additions & 31 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3130,22 +3130,24 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
ToNamespacedPath(env, &src);
THROW_IF_INSUFFICIENT_PERMISSIONS(
env, permission::PermissionScope::kFileSystemRead, src.ToStringView());
auto src_path = std::filesystem::path(src.ToStringView());

auto src_path = std::filesystem::path(src.ToU8StringView());

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 = std::filesystem::path(dest.ToStringView());

auto dest_path = std::filesystem::path(dest.ToU8StringView());
bool dereference = args[2]->IsTrue();
bool recursive = args[3]->IsTrue();

std::error_code error_code;
auto src_status = dereference
? std::filesystem::symlink_status(src_path, error_code)
: std::filesystem::status(src_path, error_code);

if (error_code) {
#ifdef _WIN32
int errorno = uv_translate_sys_error(error_code.value());
Expand All @@ -3169,34 +3171,41 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
if (!error_code) {
// Check if src and dest are identical.
if (std::filesystem::equivalent(src_path, dest_path)) {
std::string message =
"src and dest cannot be the same " + dest_path.string();
return THROW_ERR_FS_CP_EINVAL(env, message.c_str());
std::u8string message =
u8"src and dest cannot be the same " + dest_path.u8string();
return THROW_ERR_FS_CP_EINVAL(
env, reinterpret_cast<const char*>(message.c_str()));
}

const bool dest_is_dir =
dest_status.type() == std::filesystem::file_type::directory;

if (src_is_dir && !dest_is_dir) {
std::string message = "Cannot overwrite non-directory " +
src_path.string() + " with directory " +
dest_path.string();
return THROW_ERR_FS_CP_DIR_TO_NON_DIR(env, message.c_str());
std::u8string message = u8"Cannot overwrite non-directory " +
src_path.u8string() + u8" with directory " +
dest_path.u8string();
return THROW_ERR_FS_CP_DIR_TO_NON_DIR(
env, reinterpret_cast<const char*>(message.c_str()));
}

if (!src_is_dir && dest_is_dir) {
std::string message = "Cannot overwrite directory " + dest_path.string() +
" with non-directory " + src_path.string();
return THROW_ERR_FS_CP_NON_DIR_TO_DIR(env, message.c_str());
std::u8string message = u8"Cannot overwrite directory " +
dest_path.u8string() + u8" with non-directory " +
src_path.u8string();
return THROW_ERR_FS_CP_NON_DIR_TO_DIR(
env, reinterpret_cast<const char*>(message.c_str()));
}
}

std::string dest_path_str = dest_path.string();
std::u8string dest_path_str = dest_path.u8string();

// Check if dest_path is a subdirectory of src_path.
if (src_is_dir && dest_path_str.starts_with(src_path.string())) {
std::string message = "Cannot copy " + src_path.string() +
" to a subdirectory of self " + dest_path.string();
return THROW_ERR_FS_CP_EINVAL(env, message.c_str());
if (src_is_dir && dest_path_str.starts_with(src_path.u8string())) {
std::u8string message = u8"Cannot copy " + src_path.u8string() +
u8" to a subdirectory of self " +
dest_path.u8string();
return THROW_ERR_FS_CP_EINVAL(
env, reinterpret_cast<const char*>(message.c_str()));
}

auto dest_parent = dest_path.parent_path();
Expand All @@ -3207,9 +3216,11 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
dest_parent.parent_path() != dest_parent) {
if (std::filesystem::equivalent(
src_path, dest_path.parent_path(), error_code)) {
std::string message = "Cannot copy " + src_path.string() +
" to a subdirectory of self " + dest_path.string();
return THROW_ERR_FS_CP_EINVAL(env, message.c_str());
std::u8string message = u8"Cannot copy " + src_path.u8string() +
u8" to a subdirectory of self " +
dest_path.u8string();
return THROW_ERR_FS_CP_EINVAL(
env, reinterpret_cast<const char*>(message.c_str()));
}

// If equivalent fails, it's highly likely that dest_parent does not exist
Expand All @@ -3221,25 +3232,29 @@ static void CpSyncCheckPaths(const FunctionCallbackInfo<Value>& args) {
}

if (src_is_dir && !recursive) {
std::string message =
"Recursive option not enabled, cannot copy a directory: " +
src_path.string();
return THROW_ERR_FS_EISDIR(env, message.c_str());
std::u8string message =
u8"Recursive option not enabled, cannot copy a directory: " +
src_path.u8string();
return THROW_ERR_FS_EISDIR(env,
reinterpret_cast<const char*>(message.c_str()));
}

switch (src_status.type()) {
case std::filesystem::file_type::socket: {
std::string message = "Cannot copy a socket file: " + dest_path.string();
return THROW_ERR_FS_CP_SOCKET(env, message.c_str());
std::u8string message = u8"Cannot copy a socket file: " + dest_path_str;
return THROW_ERR_FS_CP_SOCKET(
env, reinterpret_cast<const char*>(message.c_str()));
}
case std::filesystem::file_type::fifo: {
std::string message = "Cannot copy a FIFO pipe: " + dest_path.string();
return THROW_ERR_FS_CP_FIFO_PIPE(env, message.c_str());
std::u8string message = u8"Cannot copy a FIFO pipe: " + dest_path_str;
return THROW_ERR_FS_CP_FIFO_PIPE(
env, reinterpret_cast<const char*>(message.c_str()));
}
case std::filesystem::file_type::unknown: {
std::string message =
"Cannot copy an unknown file type: " + dest_path.string();
return THROW_ERR_FS_CP_UNKNOWN(env, message.c_str());
std::u8string message =
u8"Cannot copy an unknown file type: " + dest_path_str;
return THROW_ERR_FS_CP_UNKNOWN(
env, reinterpret_cast<const char*>(message.c_str()));
}
default:
break;
Expand Down
4 changes: 4 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,10 @@ class BufferValue : public MaybeStackBuffer<char> {
inline std::string_view ToStringView() const {
return std::string_view(out(), length());
}
inline std::u8string_view ToU8StringView() const {
return std::u8string_view(reinterpret_cast<const char8_t*>(out()),
length());
}
};

#define SPREAD_BUFFER_ARG(val, name) \
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/copy/utf/新建文件夹/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
purpose: 'testing copy'
};
8 changes: 8 additions & 0 deletions test/parallel/test-fs-cp.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ function nextdir() {

// Synchronous implementation of copy.

// It copies a nested folder containing UTF characters.
{
const src = './test/fixtures/copy/utf/新建文件夹';
const dest = nextdir();
cpSync(src, dest, mustNotMutateObjectDeep({ recursive: true }));
assertDirEquivalent(src, dest);
}

// It copies a nested folder structure with files and folders.
{
const src = './test/fixtures/copy/kitchen-sink';
Expand Down

0 comments on commit ef0dafb

Please sign in to comment.