diff --git a/interfaces/kits/js/src/mod_fs/common_func.cpp b/interfaces/kits/js/src/mod_fs/common_func.cpp index 4118a6f1f230215193607b8cdf5fd10c448df88e..676c278a6d4f04651df8c046b9e7e62cc44ad99b 100644 --- a/interfaces/kits/js/src/mod_fs/common_func.cpp +++ b/interfaces/kits/js/src/mod_fs/common_func.cpp @@ -40,6 +40,7 @@ namespace FileManagement { namespace ModuleFileIO { using namespace std; using namespace OHOS::FileManagement::LibN; +using UvRequest = std::unique_ptr; namespace { const std::vector PUBLIC_DIR_PATHS = { @@ -253,6 +254,38 @@ void CommonFunc::fs_req_cleanup(uv_fs_t* req) } } +tuple CommonFunc::GetRealPath(const string &path) +{ + UvRequest realpath_req = { new (std::nothrow) uv_fs_t, CommonFunc::fs_req_cleanup }; + if (!realpath_req) { + HILOGE("Failed to request heap memory."); + return { ENOMEM, move(realpath_req) }; + } + int ret = uv_fs_realpath(nullptr, realpath_req.get(), path.c_str(), nullptr); + if (ret < 0) { + HILOGE("Failed to get realpath."); + return { ret, move(realpath_req) }; + } + return { ERRNO_NOERR, move(realpath_req) }; +} + +bool CommonFunc::IsValidDirectory(const string &path) +{ + UvRequest req(new (std::nothrow) uv_fs_t, CommonFunc::fs_req_cleanup); + if (!req) { + HILOGE("Failed to allocate memory for uv_fs_t"); + return false; + } + + auto ret = uv_fs_stat(nullptr, req.get(), path.c_str(), nullptr); + if (ret) { + HILOGE("Failed to stat directory, error code: %{public}d", ret); + return false; + } + + return (req->statbuf.st_mode & S_IFDIR); +} + string CommonFunc::GetModeFromFlags(unsigned int flags) { const string readMode = "r"; diff --git a/interfaces/kits/js/src/mod_fs/common_func.h b/interfaces/kits/js/src/mod_fs/common_func.h index e9afb302bba91d6028ddd62a6f61d4e8235a30b7..c4c8719e8c35ab123186e845f766ee796903b2f0 100644 --- a/interfaces/kits/js/src/mod_fs/common_func.h +++ b/interfaces/kits/js/src/mod_fs/common_func.h @@ -81,6 +81,9 @@ struct CommonFunc { napi_value srcPath, napi_value dstPath); static void fs_req_cleanup(uv_fs_t* req); + static std::tuple> + GetRealPath(const std::string &path); + static bool IsValidDirectory(const std::string &path); static std::string GetModeFromFlags(unsigned int flags); static bool CheckPublicDirPath(const std::string &sandboxPath); static std::string Decode(const std::string &uri); diff --git a/interfaces/kits/js/src/mod_fs/properties/copydir.cpp b/interfaces/kits/js/src/mod_fs/properties/copydir.cpp index 3dcaea202ad133ae3aa84fe0904d08299b62cc6e..635685bd620fcb3808f53ca27b109e6c51e59a23 100644 --- a/interfaces/kits/js/src/mod_fs/properties/copydir.cpp +++ b/interfaces/kits/js/src/mod_fs/properties/copydir.cpp @@ -31,6 +31,7 @@ namespace FileManagement { namespace ModuleFileIO { using namespace std; using namespace OHOS::FileManagement::LibN; +using UvRequest = std::unique_ptr; static int RecurCopyDir(const string &srcPath, const string &destPath, const int mode, vector &errfiles); @@ -44,32 +45,60 @@ static bool AllowToCopy(const string &src, const string &dest) return true; } -static tuple, unique_ptr, int> ParseAndCheckJsOperand(napi_env env, - const NFuncArg &funcArg) +static tuple ParseAndCheckJsOperand(napi_env env, const NFuncArg &funcArg) { auto [resGetFirstArg, src, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); - if (!resGetFirstArg || !filesystem::is_directory(filesystem::status(src.get()))) { + if (!resGetFirstArg) { + HILOGE("Failed to convert src to a UTF-8 string"); + return { EINVAL, UvRequest{ nullptr, CommonFunc::fs_req_cleanup }, + UvRequest{ nullptr, CommonFunc::fs_req_cleanup }, 0 }; + } + + auto [resSrcPath, realpathSrc] = CommonFunc::GetRealPath(string(src.get())); + if (resSrcPath != ERRNO_NOERR) { + HILOGE("Failed to get real path of source, ret: %{public}d", resSrcPath); + return { resSrcPath, move(realpathSrc), UvRequest{ nullptr, CommonFunc::fs_req_cleanup }, 0 }; + } + + bool ret = CommonFunc::IsValidDirectory(static_cast(realpathSrc->ptr)); + if (!ret) { HILOGE("Invalid src"); - return { false, nullptr, nullptr, 0 }; + return { ENOTDIR, move(realpathSrc), UvRequest{ nullptr, CommonFunc::fs_req_cleanup }, 0 }; } + auto [resGetSecondArg, dest, unused] = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8String(); - if (!resGetSecondArg || !filesystem::is_directory(filesystem::status(dest.get()))) { + if (!resGetSecondArg) { + HILOGE("Failed to convert dest to a UTF-8 string"); + return { EINVAL, move(realpathSrc), UvRequest{ nullptr, CommonFunc::fs_req_cleanup }, 0 }; + } + + auto [resDestPath, realpathDest] = CommonFunc::GetRealPath(string(dest.get())); + if (resDestPath != ERRNO_NOERR) { + HILOGE("Failed to get real path of destination, ret: %{public}d", resDestPath); + return { resDestPath, move(realpathSrc), move(realpathDest), 0 }; + } + + ret = CommonFunc::IsValidDirectory(static_cast(realpathDest->ptr)); + if (!ret) { HILOGE("Invalid dest"); - return { false, nullptr, nullptr, 0 }; + return { ENOTDIR, move(realpathSrc), move(realpathDest), 0 }; } - if (!AllowToCopy(src.get(), dest.get())) { - return { false, nullptr, nullptr, 0 }; + + if (!AllowToCopy(static_cast(realpathSrc->ptr), + static_cast(realpathDest->ptr))) { + return { EINVAL, move(realpathSrc), move(realpathDest), 0 }; } + int mode = 0; if (funcArg.GetArgc() >= NARG_CNT::THREE) { bool resGetThirdArg = false; tie(resGetThirdArg, mode) = NVal(env, funcArg[NARG_POS::THIRD]).ToInt32(mode); if (!resGetThirdArg || (mode < COPYMODE_MIN || mode > COPYMODE_MAX)) { HILOGE("Invalid mode"); - return { false, nullptr, nullptr, 0 }; + return { EINVAL, move(realpathSrc), move(realpathDest), 0 }; } } - return { true, move(src), move(dest), mode }; + return { ERRNO_NOERR, move(realpathSrc), move(realpathDest), mode }; } static int MakeDir(const string &path) @@ -237,14 +266,16 @@ napi_value CopyDir::Sync(napi_env env, napi_callback_info info) NError(EINVAL).ThrowErr(env); return nullptr; } - auto [succ, src, dest, mode] = ParseAndCheckJsOperand(env, funcArg); - if (!succ) { + auto [succ, srcReq, destReq, mode] = ParseAndCheckJsOperand(env, funcArg); + if (succ) { NError(EINVAL).ThrowErr(env); return nullptr; } vector errfiles = {}; - int ret = CopyDirFunc(src.get(), dest.get(), mode, errfiles); + string src(static_cast(srcReq->ptr)); + string dest(static_cast(destReq->ptr)); + int ret = CopyDirFunc(src, dest, mode, errfiles); if (ret == EEXIST && mode == DIRMODE_FILE_COPY_THROW_ERR) { NError(ret).ThrowErrAddData(env, EEXIST, PushErrFilesInData(env, errfiles)); return nullptr; @@ -268,8 +299,8 @@ napi_value CopyDir::Async(napi_env env, napi_callback_info info) NError(EINVAL).ThrowErr(env); return nullptr; } - auto [succ, src, dest, mode] = ParseAndCheckJsOperand(env, funcArg); - if (!succ) { + auto [succ, srcReq, destReq, mode] = ParseAndCheckJsOperand(env, funcArg); + if (succ) { NError(EINVAL).ThrowErr(env); return nullptr; } @@ -280,7 +311,8 @@ napi_value CopyDir::Async(napi_env env, napi_callback_info info) NError(ENOMEM).ThrowErr(env); return nullptr; } - auto cbExec = [srcPath = string(src.get()), destPath = string(dest.get()), mode = mode, arg]() -> NError { + auto cbExec = [srcPath = static_cast(srcReq->ptr), + destPath = static_cast(destReq->ptr), mode = mode, arg]() -> NError { arg->errNo = CopyDirFunc(srcPath, destPath, mode, arg->errfiles); if (arg->errNo) { return NError(arg->errNo); diff --git a/interfaces/kits/js/src/mod_fs/properties/listfile.cpp b/interfaces/kits/js/src/mod_fs/properties/listfile.cpp index e046e174517d0d2fb836b0c6b712efc23adc7655..2bacb53fd5e12a420db6159316630c5961f09f33 100755 --- a/interfaces/kits/js/src/mod_fs/properties/listfile.cpp +++ b/interfaces/kits/js/src/mod_fs/properties/listfile.cpp @@ -23,6 +23,7 @@ #include #include +#include "common_func.h" #include "file_utils.h" #include "filemgmt_libhilog.h" @@ -100,14 +101,14 @@ static bool GetFileFilterParam(const NVal &argv, FileFilter *filter) return true; } -static bool GetOptionParam(const NVal &argv, OptionArgs *optionArgs) +static int GetOptionParam(const NVal &argv, OptionArgs *optionArgs) { bool succ = false; if (argv.HasProp("listNum")) { tie(succ, optionArgs->listNum) = argv.GetProp("listNum").ToInt64(0); if (!succ || optionArgs->listNum < 0) { HILOGE("Failed to get listNum prop"); - return false; + return EINVAL; } } @@ -115,7 +116,7 @@ static bool GetOptionParam(const NVal &argv, OptionArgs *optionArgs) tie(succ, optionArgs->recursion) = argv.GetProp("recursion").ToBool(false); if (!succ) { HILOGE("Failed to get recursion prop."); - return false; + return EINVAL; } } @@ -125,28 +126,33 @@ static bool GetOptionParam(const NVal &argv, OptionArgs *optionArgs) auto ret = GetFileFilterParam(filterProp, &optionArgs->filter); if (!ret) { HILOGE("Failed to get filter prop."); - return false; + return EINVAL; } } } - return true; + return ERRNO_NOERR; } -static bool GetOptionArg(napi_env env, const NFuncArg &funcArg, OptionArgs &optionArgs, const string &path) +static int GetOptionArg(napi_env env, const NFuncArg &funcArg, OptionArgs &optionArgs, const string &path) { - optionArgs.path = path; + auto [ret, realpathSrc] = CommonFunc::GetRealPath(path); + if (ret) { + HILOGE("Failed to get absolute path"); + return ret; + } + optionArgs.path = std::string(static_cast(realpathSrc->ptr)); if (funcArg.GetArgc() == NARG_CNT::ONE) { - return true; + return ERRNO_NOERR; } if (funcArg.GetArgc() >= NARG_CNT::TWO) { auto options = NVal(env, funcArg[NARG_POS::SECOND]); if (options.TypeIs(napi_object)) { return GetOptionParam(options, &optionArgs); } else if (options.TypeIs(napi_undefined) || options.TypeIs(napi_function)) { - return true; + return ERRNO_NOERR; } } - return false; + return EINVAL; } static bool FilterSuffix(const vector &suffixs, const struct dirent &filename) @@ -331,13 +337,13 @@ napi_value ListFile::Sync(napi_env env, napi_callback_info info) NError(EINVAL).ThrowErr(env); return nullptr; } - if (!GetOptionArg(env, funcArg, g_optionArgs, string(path.get()))) { + int ret = GetOptionArg(env, funcArg, g_optionArgs, string(path.get())); + if (ret) { HILOGE("Invalid options"); NError(EINVAL).ThrowErr(env); return nullptr; } vector direntsRes; - int ret = 0; ret = g_optionArgs.recursion ? RecursiveFunc(path.get(), direntsRes) : FilterFileRes(path.get(), direntsRes); if (ret) { NError(ret).ThrowErr(env); @@ -365,8 +371,9 @@ napi_value ListFile::Async(napi_env env, napi_callback_info info) } OptionArgs optionArgsTmp = {}; - if (!GetOptionArg(env, funcArg, optionArgsTmp, string(path.get()))) { - HILOGE("Invalid options"); + int ret = GetOptionArg(env, funcArg, optionArgsTmp, string(path.get())); + if (ret) { + HILOGE("Failed to get arguments"); NError(EINVAL).ThrowErr(env); return nullptr; } diff --git a/interfaces/kits/js/src/mod_fs/properties/movedir.cpp b/interfaces/kits/js/src/mod_fs/properties/movedir.cpp index 57ffb70fe1e8c3d252a435e7bbcefc058e4e0931..36c0a7884881ccb8b2f437b729d210a41fb3f8df 100644 --- a/interfaces/kits/js/src/mod_fs/properties/movedir.cpp +++ b/interfaces/kits/js/src/mod_fs/properties/movedir.cpp @@ -32,6 +32,7 @@ namespace FileManagement { namespace ModuleFileIO { using namespace std; using namespace OHOS::FileManagement::LibN; +using UvRequest = std::unique_ptr; static int RecurMoveDir(const string &srcPath, const string &destPath, const int mode, deque &errfiles); @@ -73,28 +74,55 @@ static int RemovePath(const string& pathStr) return ERRNO_NOERR; } -static tuple, unique_ptr, int> ParseJsOperand(napi_env env, const NFuncArg& funcArg) +static tuple ParseJsOperand(napi_env env, const NFuncArg& funcArg) { auto [resGetFirstArg, src, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String(); - if (!resGetFirstArg || !filesystem::is_directory(filesystem::status(src.get()))) { + if (!resGetFirstArg) { + HILOGE("Failed to convert src to a UTF-8 string"); + return { EINVAL, UvRequest{ nullptr, CommonFunc::fs_req_cleanup }, + UvRequest{ nullptr, CommonFunc::fs_req_cleanup }, 0 }; + } + + auto [resSrcPath, realpathSrc] = CommonFunc::GetRealPath(string(src.get())); + if (resSrcPath != ERRNO_NOERR) { + HILOGE("Failed to get real path of source, ret: %{public}d", resSrcPath); + return { resSrcPath, move(realpathSrc), UvRequest{ nullptr, CommonFunc::fs_req_cleanup }, 0 }; + } + + bool ret = CommonFunc::IsValidDirectory(static_cast(realpathSrc->ptr)); + if (!ret) { HILOGE("Invalid src"); - return { false, nullptr, nullptr, 0 }; + return { ENOTDIR, move(realpathSrc), UvRequest{ nullptr, CommonFunc::fs_req_cleanup }, 0 }; } + auto [resGetSecondArg, dest, unused] = NVal(env, funcArg[NARG_POS::SECOND]).ToUTF8String(); - if (!resGetSecondArg || !filesystem::is_directory(filesystem::status(dest.get()))) { + if (!resGetSecondArg) { + HILOGE("Failed to convert dest to a UTF-8 string"); + return { EINVAL, move(realpathSrc), UvRequest{ nullptr, CommonFunc::fs_req_cleanup }, 0 }; + } + + auto [resDestPath, realpathDest] = CommonFunc::GetRealPath(string(dest.get())); + if (resDestPath != ERRNO_NOERR) { + HILOGE("Failed to get real path of destination, ret: %{public}d", resDestPath); + return { resDestPath, move(realpathSrc), move(realpathDest), 0 }; + } + + ret = CommonFunc::IsValidDirectory(static_cast(realpathDest->ptr)); + if (!ret) { HILOGE("Invalid dest"); - return { false, nullptr, nullptr, 0 }; + return { ENOTDIR, move(realpathSrc), move(realpathDest), 0 }; } + int mode = 0; if (funcArg.GetArgc() >= NARG_CNT::THREE) { bool resGetThirdArg = false; tie(resGetThirdArg, mode) = NVal(env, funcArg[NARG_POS::THIRD]).ToInt32(mode); if (!resGetThirdArg || (mode < DIRMODE_MIN || mode > DIRMODE_MAX)) { HILOGE("Invalid mode"); - return { false, nullptr, nullptr, 0 }; + return { EINVAL, move(realpathSrc), move(realpathDest), 0 }; } } - return { true, move(src), move(dest), mode }; + return { ERRNO_NOERR, move(realpathSrc), move(realpathDest), mode }; } static int RestoreTime(const string &srcPath, const string &destPath) @@ -343,14 +371,16 @@ napi_value MoveDir::Sync(napi_env env, napi_callback_info info) NError(EINVAL).ThrowErr(env); return nullptr; } - auto [succ, src, dest, mode] = ParseJsOperand(env, funcArg); - if (!succ) { + auto [succ, srcReq, destReq, mode] = ParseJsOperand(env, funcArg); + if (succ) { NError(EINVAL).ThrowErr(env); return nullptr; } + string src(static_cast(srcReq->ptr)); + string dest(static_cast(destReq->ptr)); deque errfiles = {}; - int ret = MoveDirFunc(src.get(), dest.get(), mode, errfiles); + int ret = MoveDirFunc(src, dest, mode, errfiles); if (ret == EEXIST) { NError(ret).ThrowErrAddData(env, EEXIST, GetErrData(env, errfiles)); return nullptr; @@ -375,8 +405,8 @@ napi_value MoveDir::Async(napi_env env, napi_callback_info info) NError(EINVAL).ThrowErr(env); return nullptr; } - auto [succ, src, dest, mode] = ParseJsOperand(env, funcArg); - if (!succ) { + auto [succ, srcReq, destReq, mode] = ParseJsOperand(env, funcArg); + if (succ) { NError(EINVAL).ThrowErr(env); return nullptr; } @@ -386,7 +416,8 @@ napi_value MoveDir::Async(napi_env env, napi_callback_info info) NError(ENOMEM).ThrowErr(env); return nullptr; } - auto cbExec = [srcPath = string(src.get()), destPath = string(dest.get()), mode = mode, arg]() -> NError { + auto cbExec = [srcPath = static_cast(srcReq->ptr), + destPath = static_cast(destReq->ptr), mode = mode, arg]() -> NError { arg->errNo = MoveDirFunc(srcPath, destPath, mode, arg->errfiles); if (arg->errNo) { return NError(arg->errNo);