diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..42b5a73167eca8dcf6782f61016dea3d1ee24f26 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mkdtemp_ani.h" + +#include + +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "mkdtemp_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +ani_string MkdtempAni::MkdtempSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string prefix) +{ + auto [succPath, prefixPath] = TypeConverter::ToUTF8String(env, prefix); + if (!succPath) { + HILOGE("Invalid path"); + ErrorHandler::Throw(env, EINVAL); + return nullptr; + } + + auto ret = MkdtempCore::DoMkdtemp(prefixPath); + if (!ret.IsSuccess()) { + HILOGE("Mkdtemp faild"); + const auto &err = ret.GetError(); + ErrorHandler::Throw(env, err); + return nullptr; + } + + const auto &res = ret.GetData().value(); + auto [succ, result] = TypeConverter::ToAniString(env, res); + if (!succ) { + HILOGE("Create ani_string error"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return nullptr; + } + return result; +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..cda9c8e12905bb44cf86f03a70dc57ce369deed4 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/mkdtemp_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_MKDTEMP_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_MKDTEMP_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class MkdtempAni final { +public: + static ani_string MkdtempSync(ani_env *env, [[maybe_unused]] ani_class clazz, ani_string prefix); +}; + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_MKDTEMP_ANI_H diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.cpp b/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e571ae53aeec1fc58b00de8fd16eec429fc7af89 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "movedir_ani.h" + +#include + +#include "ani_signature.h" +#include "error_handler.h" +#include "filemgmt_libhilog.h" +#include "movedir_core.h" +#include "type_converter.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { +using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature; + +static tuple ToConflictFiles(ani_env *env, const ErrFiles &files) +{ + auto classDesc = FS::ConflictFilesInner::classDesc.c_str(); + ani_class cls; + ani_status ret; + if ((ret = env->FindClass(classDesc, &cls)) != ANI_OK) { + HILOGE("Cannot find class %{public}s, err: %{public}d", classDesc, ret); + return { false, nullptr }; + } + + auto ctorDesc = FS::ConflictFilesInner::ctorDesc.c_str(); + auto ctorSig = FS::ConflictFilesInner::ctorSig.c_str(); + ani_method ctor; + if ((ret = env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) != ANI_OK) { + HILOGE("Cannot find class %{public}s constructor method, err: %{public}d", classDesc, ret); + return { false, nullptr }; + } + + auto [succSrc, src] = TypeConverter::ToAniString(env, files.srcFiles); + if (!succSrc) { + HILOGE("Convert ConflictFiles srcFiles to ani string failed!"); + return { false, nullptr }; + } + + auto [succDest, dest] = TypeConverter::ToAniString(env, files.destFiles); + if (!succSrc) { + HILOGE("Convert ConflictFiles destFiles to ani string failed!"); + return { false, nullptr }; + } + + ani_object obj; + if ((ret = env->Object_New(cls, ctor, &obj, src, dest)) != ANI_OK) { + HILOGE("Create ConflictFiles object failed!, err: %{public}d", ret); + return { false, nullptr }; + } + + return { true, obj }; +} + +static tuple> ToConflictFilesArray( + ani_env *env, const optional> &errFiles) +{ + if (!errFiles.has_value()) { + return { true, nullopt }; + } + auto classDesc = BuiltInTypes::Array::classDesc.c_str(); + ani_class cls = nullptr; + ani_status ret; + + if ((ret = env->FindClass(classDesc, &cls)) != ANI_OK) { + HILOGE("Cannot find class %{public}s, err: %{public}d", classDesc, ret); + return { false, nullopt }; + } + + auto ctorDesc = BuiltInTypes::Array::ctorDesc.c_str(); + auto ctorSig = BuiltInTypes::Array::ctorSig.c_str(); + ani_method ctor; + if ((ret = env->Class_FindMethod(cls, ctorDesc, ctorSig, &ctor)) != ANI_OK) { + HILOGE("Cannot find class %{public}s constructor method, err: %{public}d", classDesc, ret); + return { false, nullopt }; + } + + ani_object arr; + auto files = errFiles.value(); + if ((ret = env->Object_New(cls, ctor, &arr, files.size())) != ANI_OK) { + HILOGE("Create Array failed!, err: %{public}d", ret); + return { false, nullopt }; + } + + auto setterDesc = BuiltInTypes::Array::setterDesc.c_str(); + auto setterSig = BuiltInTypes::Array::objectSetterSig.c_str(); + ani_size index = 0; + for (const auto &errFile : files) { + auto [succ, fileObj] = ToConflictFiles(env, errFile); + if (!succ) { + return { false, nullopt }; + } + + if ((ret = env->Object_CallMethodByName_Void(arr, setterDesc, setterSig, index, fileObj)) != ANI_OK) { + HILOGE("Add element to Array failed, err: %{public}d", ret); + return { false, nullopt }; + } + index++; + } + + return { true, make_optional(move(arr)) }; +} + +void MoveDirAni::MoveDirSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string src, ani_string dest, ani_object mode) +{ + auto [succSrc, srcPath] = TypeConverter::ToUTF8String(env, src); + auto [succDest, destPath] = TypeConverter::ToUTF8String(env, dest); + if (!succSrc || !succDest) { + HILOGE("The first/second argument requires filepath"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto [succMode, optMode] = TypeConverter::ToOptionalInt32(env, mode); + if (!succMode) { + HILOGE("Invalid mode"); + ErrorHandler::Throw(env, EINVAL); + return; + } + + auto [fsResult, errFiles] = MoveDirCore::DoMoveDir(srcPath, destPath, optMode); + if (!fsResult.IsSuccess()) { + HILOGE("DoMoveDir failed!"); + auto [succ, errData] = ToConflictFilesArray(env, errFiles); + if (!succ) { + HILOGE("Convert conflict files array failed"); + ErrorHandler::Throw(env, UNKNOWN_ERR); + return; + } + const FsError &err = fsResult.GetError(); + ErrorHandler::Throw(env, err, errData); + return; + } +} + +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.h b/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.h new file mode 100644 index 0000000000000000000000000000000000000000..bd17504464739b6b56f293980792b1e72b05d858 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/ani/movedir_ani.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_MOVEDIR_ANI_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_MOVEDIR_ANI_H + +#include + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +namespace ANI { + +class MoveDirAni final { +public: + static void MoveDirSync( + ani_env *env, [[maybe_unused]] ani_class clazz, ani_string src, ani_string dest, ani_object mode); +}; +} // namespace ANI +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS + +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_ANI_MOVEDIR_ANI_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.cpp b/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..487f35c69e38f90b309425a64e7b16ae4b4ae33e --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mkdtemp_core.h" + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +FsResult MkdtempCore::DoMkdtemp(const string &path) +{ + unique_ptr mkdtempReq = { new uv_fs_t, FsUtils::FsReqCleanup }; + if (!mkdtempReq) { + HILOGE("Failed to request heap memory."); + return FsResult::Error(ENOMEM); + } + int ret = uv_fs_mkdtemp(nullptr, mkdtempReq.get(), const_cast(path.c_str()), nullptr); + if (ret < 0) { + HILOGE("Failed to create a temporary directory with path"); + return FsResult::Error(ret); + } + + return FsResult::Success(move(mkdtempReq->path)); +} + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS diff --git a/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.h b/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.h new file mode 100644 index 0000000000000000000000000000000000000000..df936597f265e739e766715b4792ab4c565a8688 --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/mkdtemp_core.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MKDTEMP_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MKDTEMP_CORE_H + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +class MkdtempCore final { +public: + static FsResult DoMkdtemp(const std::string &path); +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MKDTEMP_CORE_H \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/movedir_core.cpp b/interfaces/kits/js/src/mod_fs/properties/movedir_core.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2b7e49e8dc4eb762ac48d24d7cac535b6d6650fd --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/movedir_core.cpp @@ -0,0 +1,306 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "movedir_core.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "file_utils.h" +#include "filemgmt_libhilog.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { +using namespace std; + +static int RecurMoveDir(const string &srcPath, const string &destPath, const int mode, + deque &errfiles); + +static tuple JudgeExistAndEmpty(const string &path) +{ + std::error_code errCode; + filesystem::path pathName(path); + if (filesystem::exists(pathName, errCode)) { + if (filesystem::is_empty(pathName, errCode)) { + return { true, true }; + } + return { true, false }; + } + return { false, false }; +} + +static int RmDirectory(const string &path) +{ + filesystem::path pathName(path); + std::error_code errCode; + if (filesystem::exists(pathName, errCode)) { + std::error_code errCode; + (void)filesystem::remove_all(pathName, errCode); + if (errCode.value() != 0) { + HILOGE("Failed to remove directory, error code: %{public}d", errCode.value()); + return errCode.value(); + } + } else if (errCode.value() != ERRNO_NOERR) { + HILOGE("Fs exists fail, errcode is %{public}d", errCode.value()); + return errCode.value(); + } + return ERRNO_NOERR; +} + +static int RemovePath(const string& pathStr) +{ + filesystem::path pathTarget(pathStr); + std::error_code errCode; + if (!filesystem::remove(pathTarget, errCode)) { + HILOGE("Failed to remove file or directory, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return ERRNO_NOERR; +} + +static int CopyAndDeleteFile(const string &src, const string &dest) +{ + filesystem::path dstPath(dest); + std::error_code errCode; + if (filesystem::exists(dstPath, errCode)) { + int removeRes = RemovePath(dest); + if (removeRes != 0) { + HILOGE("Failed to remove dest file"); + return removeRes; + } + } + filesystem::path srcPath(src); + if (!filesystem::copy_file(srcPath, dstPath, filesystem::copy_options::overwrite_existing, errCode)) { + HILOGE("Failed to copy file, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return RemovePath(src); +} + +static int RenameFile(const string &src, const string &dest, const int mode, deque &errfiles) +{ + filesystem::path dstPath(dest); + std::error_code errCode; + if (filesystem::exists(dstPath, errCode)) { + if (filesystem::is_directory(dstPath, errCode)) { + errfiles.emplace_front(src, dest); + return ERRNO_NOERR; + } + if (mode == DIRMODE_FILE_THROW_ERR) { + errfiles.emplace_back(src, dest); + return ERRNO_NOERR; + } + } + if (errCode.value() != ERRNO_NOERR) { + HILOGE("Fs exists or is_directory fail, errcode is %{public}d", errCode.value()); + } + filesystem::path srcPath(src); + filesystem::rename(srcPath, dstPath, errCode); + if (errCode.value() == EXDEV) { + HILOGD("Failed to rename file due to EXDEV"); + return CopyAndDeleteFile(src, dest); + } + return errCode.value(); +} + +static int32_t FilterFunc(const struct dirent *filename) +{ + if (string_view(filename->d_name) == "." || string_view(filename->d_name) == "..") { + return FILE_DISMATCH; + } + return FILE_MATCH; +} + +static int RenameDir(const string &src, const string &dest, const int mode, deque &errfiles) +{ + filesystem::path destPath(dest); + std::error_code errCode; + if (filesystem::exists(destPath, errCode)) { + return RecurMoveDir(src, dest, mode, errfiles); + } else if (errCode.value() != ERRNO_NOERR) { + HILOGE("Fs exists fail, errcode is %{public}d", errCode.value()); + return errCode.value(); + } + filesystem::path srcPath(src); + filesystem::rename(srcPath, destPath, errCode); + if (errCode.value() == EXDEV) { + HILOGD("Failed to rename file due to EXDEV"); + if (!filesystem::create_directory(destPath, errCode)) { + HILOGE("Failed to create directory, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return RecurMoveDir(src, dest, mode, errfiles); + } + if (errCode.value() != 0) { + HILOGE("Failed to rename file, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return ERRNO_NOERR; +} + +struct NameListArg { + struct dirent** namelist; + int num; +}; + +static void Deleter(struct NameListArg *arg) +{ + for (int i = 0; i < arg->num; i++) { + free((arg->namelist)[i]); + (arg->namelist)[i] = nullptr; + } + free(arg->namelist); + arg->namelist = nullptr; + delete arg; + arg = nullptr; +} + +static int RecurMoveDir(const string &srcPath, const string &destPath, const int mode, + deque &errfiles) +{ + filesystem::path dpath(destPath); + std::error_code errCode; + if (!filesystem::is_directory(dpath, errCode)) { + errfiles.emplace_front(srcPath, destPath); + return ERRNO_NOERR; + } + + unique_ptr ptr = {new struct NameListArg, Deleter}; + if (!ptr) { + HILOGE("Failed to request heap memory."); + return ENOMEM; + } + int num = scandir(srcPath.c_str(), &(ptr->namelist), FilterFunc, alphasort); + ptr->num = num; + + for (int i = 0; i < num; i++) { + if ((ptr->namelist[i])->d_type == DT_DIR) { + string srcTemp = srcPath + '/' + string((ptr->namelist[i])->d_name); + string destTemp = destPath + '/' + string((ptr->namelist[i])->d_name); + size_t size = errfiles.size(); + int res = RenameDir(srcTemp, destTemp, mode, errfiles); + if (res != ERRNO_NOERR) { + return res; + } + if (size != errfiles.size()) { + continue; + } + res = RemovePath(srcTemp); + if (res) { + return res; + } + } else { + string src = srcPath + '/' + string((ptr->namelist[i])->d_name); + string dest = destPath + '/' + string((ptr->namelist[i])->d_name); + int res = RenameFile(src, dest, mode, errfiles); + if (res != ERRNO_NOERR) { + HILOGE("Failed to rename file for error %{public}d", res); + return res; + } + } + } + return ERRNO_NOERR; +} + +static int MoveDirFunc(const string &src, const string &dest, const int mode, deque &errfiles) +{ + size_t found = string(src).rfind('/'); + if (found == std::string::npos) { + return EINVAL; + } + if (access(src.c_str(), W_OK) != 0) { + HILOGE("Failed to move src directory due to doesn't exist or hasn't write permission"); + return errno; + } + string dirName = string(src).substr(found); + string destStr = dest + dirName; + auto [destStrExist, destStrEmpty] = JudgeExistAndEmpty(destStr); + if (destStrExist && !destStrEmpty) { + if (mode == DIRMODE_DIRECTORY_REPLACE) { + int removeRes = RmDirectory(destStr); + if (removeRes) { + HILOGE("Failed to remove dest directory in DIRMODE_DIRECTORY_REPLACE"); + return removeRes; + } + } + if (mode == DIRMODE_DIRECTORY_THROW_ERR) { + HILOGE("Failed to move directory in DIRMODE_DIRECTORY_THROW_ERR"); + return ENOTEMPTY; + } + } + int res = RenameDir(src, destStr, mode, errfiles); + if (res == ERRNO_NOERR) { + if (!errfiles.empty()) { + HILOGE("Failed to movedir with some conflicted files"); + return EEXIST; + } + int removeRes = RmDirectory(src); + if (removeRes) { + HILOGE("Failed to remove src directory"); + return removeRes; + } + } + return res; +} + +static tuple ValidMoveDirArg( + const string &src, const string &dest, optional mode) +{ + std::error_code errCode; + if (!filesystem::is_directory(filesystem::status(src.c_str(), errCode))) { + HILOGE("Invalid src, errCode = %{public}d", errCode.value()); + return { false, 0 }; + } + if (!filesystem::is_directory(filesystem::status(dest.c_str(), errCode))) { + HILOGE("Invalid dest,errCode = %{public}d", errCode.value()); + return { false, 0 }; + } + int modeType = 0; + if (mode.has_value()) { + modeType = mode.value(); + if (modeType < DIRMODE_MIN || modeType > DIRMODE_MAX) { + HILOGE("Invalid mode"); + return { false, 0 }; + } + } + return { true, modeType }; +} + +MoveDirResult MoveDirCore::DoMoveDir( + const string &src, const string &dest, optional modeType) +{ + auto [succ, mode] = ValidMoveDirArg(src, dest, modeType); + if (!succ) { + return { FsResult::Error(EINVAL), nullopt }; + } + deque errfiles = {}; + int ret = MoveDirFunc(src, dest, mode, errfiles); + if (ret == EEXIST) { + return { FsResult::Error(EEXIST), optional> { errfiles } }; + } else if (ret) { + return { FsResult::Error(ret), nullopt }; + } + return { FsResult::Success(), nullopt }; +} + +} // ModuleFileIO +} // FileManagement +} // OHOS \ No newline at end of file diff --git a/interfaces/kits/js/src/mod_fs/properties/movedir_core.h b/interfaces/kits/js/src/mod_fs/properties/movedir_core.h new file mode 100644 index 0000000000000000000000000000000000000000..f10eaa5321bce542448c6d5bce604c63e6060f7a --- /dev/null +++ b/interfaces/kits/js/src/mod_fs/properties/movedir_core.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MOVEDIR_CORE_H +#define INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MOVEDIR_CORE_H + +#include +#include + +#include "filemgmt_libfs.h" +#include "fs_utils.h" + +namespace OHOS { +namespace FileManagement { +namespace ModuleFileIO { + +constexpr int DIRMODE_MIN = 0; +constexpr int DIRMODE_MAX = 3; + +constexpr int FILE_DISMATCH = 0; +constexpr int FILE_MATCH = 1; +constexpr int MOVEDIR_DEFAULT_PERM = 0770; + +enum ModeOfMoveDir { + DIRMODE_DIRECTORY_THROW_ERR = 0, + DIRMODE_FILE_THROW_ERR, + DIRMODE_FILE_REPLACE, + DIRMODE_DIRECTORY_REPLACE +}; + +struct ErrFiles { + std::string srcFiles; + std::string destFiles; + ErrFiles(const std::string& src, const std::string& dest) : srcFiles(src), destFiles(dest) {} + ~ErrFiles() = default; +}; + +struct MoveDirResult { + FsResult fsResult; + optional> errFiles; +}; + +class MoveDirCore final { +public: + static MoveDirResult DoMoveDir( + const std::string &src, const std::string &dest, std::optional mode = std::nullopt); +}; + +} // namespace ModuleFileIO +} // namespace FileManagement +} // namespace OHOS +#endif // INTERFACES_KITS_JS_SRC_MOD_FS_PROPERTIES_MOVEDIR_CORE_H \ No newline at end of file diff --git a/interfaces/test/unittest/js/mod_fs/properties/mkdtemp_core_mock_test.cpp b/interfaces/test/unittest/js/mod_fs/properties/mkdtemp_core_mock_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..287f9d9adb3f27bfa98547360a05fc12ed812fcd --- /dev/null +++ b/interfaces/test/unittest/js/mod_fs/properties/mkdtemp_core_mock_test.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include + +#include "mkdtemp_core.h" +#include "uv_fs_mock.h" + +namespace OHOS::FileManagement::ModuleFileIO::Test { +using namespace testing; +using namespace testing::ext; +using namespace std; + +class MkdtempCoreMockTest : public testing::Test { +public: + static filesystem::path tempFilePath; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); + static inline shared_ptr uvMock = nullptr; +}; + +filesystem::path MkdtempCoreMockTest::tempFilePath; + +void MkdtempCoreMockTest::SetUpTestCase(void) +{ + GTEST_LOG_(INFO) << "SetUpTestCase"; + tempFilePath = filesystem::temp_directory_path() / "test"; + std::filesystem::create_directory(tempFilePath); + uvMock = std::make_shared(); + Uvfs::ins = uvMock; +} + +void MkdtempCoreMockTest::TearDownTestCase(void) +{ + GTEST_LOG_(INFO) << "TearDownTestCase"; + filesystem::remove_all(tempFilePath); + Uvfs::ins = nullptr; + uvMock = nullptr; +} + +void MkdtempCoreMockTest::SetUp(void) +{ + GTEST_LOG_(INFO) << "SetUp"; +} + +void MkdtempCoreMockTest::TearDown(void) +{ + GTEST_LOG_(INFO) << "TearDown"; +} + +/** + * @tc.name: MkdtempCoreMockTest_DoMkdtemp_0001 + * @tc.desc: Test function of DoMkdtemp() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MkdtempCoreMockTest, MkdtempCoreMockTest_DoMkdtemp_0001, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MkdtempCoreMockTest-begin MkdtempCoreMockTest_DoMkdtemp_0001"; + + uv_fs_t mock_req; + mock_req.path = const_cast("/data/local/tmp/test/XXXXXX"); + + EXPECT_CALL(*uvMock, uv_fs_mkdtemp(_, _, _, _)) + .WillOnce(Invoke([&](uv_loop_t*, uv_fs_t* req, const char*, uv_fs_cb) { + *req = mock_req; + return 0; + })); + + auto ret = MkdtempCore::DoMkdtemp("/data/local/tmp/test/XXXXXX"); + EXPECT_EQ(ret.IsSuccess(), true); + + GTEST_LOG_(INFO) << "MkdtempCoreMockTest-end MkdtempCoreMockTest_DoMkdtemp_0001"; +} + +/** + * @tc.name: MkdtempCoreMockTest_DoMkdtemp_0002 + * @tc.desc: Test function of DoMkdtemp() interface for FAILED. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MkdtempCoreMockTest, MkdtempCoreMockTest_DoMkdtemp_0002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MkdtempCoreMockTest-begin MkdtempCoreMockTest_DoMkdtemp_0002"; + + string path = tempFilePath.string() + "/XXXXXX"; + + EXPECT_CALL(*uvMock, uv_fs_mkdtemp(_, _, _, _)).WillOnce(Return(-1)); + auto ret = MkdtempCore::DoMkdtemp(path); + EXPECT_EQ(ret.IsSuccess(), false); + + GTEST_LOG_(INFO) << "MkdtempCoreMockTest-end MkdtempCoreMockTest_DoMkdtemp_0002"; +} + +} // namespace OHOS::FileManagement::ModuleFileIO::Test \ No newline at end of file diff --git a/interfaces/test/unittest/js/mod_fs/properties/movedir_core_test.cpp b/interfaces/test/unittest/js/mod_fs/properties/movedir_core_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3e578db2ea065306e7000bb34f8871f6e3c7ec46 --- /dev/null +++ b/interfaces/test/unittest/js/mod_fs/properties/movedir_core_test.cpp @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include "movedir_core.h" + +namespace OHOS::FileManagement::ModuleFileIO::Test { +using namespace testing; +using namespace testing::ext; +using namespace std; + +class MoveDirCoreTest : public testing::Test { +public: + static filesystem::path srcPath; + static filesystem::path destPath; + static void SetUpTestCase(void); + static void TearDownTestCase(void); + void SetUp(); + void TearDown(); +}; + +filesystem::path MoveDirCoreTest::srcPath; +filesystem::path MoveDirCoreTest::destPath; + +void MoveDirCoreTest::SetUpTestCase(void) +{ + srcPath = filesystem::temp_directory_path() / "src/"; + destPath = filesystem::temp_directory_path() / "dest/"; + std::filesystem::create_directory(srcPath); + std::filesystem::create_directory(destPath); + GTEST_LOG_(INFO) << "SetUpTestCase"; +} + +void MoveDirCoreTest::TearDownTestCase(void) +{ + GTEST_LOG_(INFO) << "TearDownTestCase"; + filesystem::remove_all(srcPath); + filesystem::remove_all(destPath); +} + +void MoveDirCoreTest::SetUp(void) +{ + GTEST_LOG_(INFO) << "SetUp"; +} + +void MoveDirCoreTest::TearDown(void) +{ + GTEST_LOG_(INFO) << "TearDown"; +} + +/** + * @tc.name: MoveDirCoreTest_DoMoveDir_0001 + * @tc.desc: Test function of DoMoveDir() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MoveDirCoreTest, MoveDirCoreTest_DoMoveDir_0001, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MoveDirCoreTest-begin MoveDirCoreTest_DoMoveDir_0001"; + + string src = srcPath.string() + "/test01"; + string dest = destPath.string(); + filesystem::create_directories(src); + + auto result = MoveDirCore::DoMoveDir(src, dest, optional()); + + EXPECT_TRUE(result.fsResult.IsSuccess()); + EXPECT_FALSE(result.errFiles.has_value()); + + GTEST_LOG_(INFO) << "MoveDirCoreTest-end MoveDirCoreTest_DoMoveDir_0001"; +} + +/** + * @tc.name: MoveDirCoreTest_DoMoveDir_0002 + * @tc.desc: Test function of DoMoveDir() interface for FAILED. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MoveDirCoreTest, MoveDirCoreTest_DoMoveDir_0002, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MoveDirCoreTest-begin MoveDirCoreTest_DoMoveDir_0002"; + + string src = srcPath.string() + "/test02"; + string dest = destPath.string(); + filesystem::create_directories(src); + + int invalidMode = DIRMODE_MAX + 1; + auto result = MoveDirCore::DoMoveDir(src, dest, optional(invalidMode)); + + EXPECT_FALSE(result.fsResult.IsSuccess()); + auto err = result.fsResult.GetError(); + EXPECT_EQ(err.GetErrNo(), 13900020); + EXPECT_FALSE(result.errFiles.has_value()); + + GTEST_LOG_(INFO) << "MoveDirCoreTest-end MoveDirCoreTest_DoMoveDir_0002"; +} + +/** + * @tc.name: MoveDirCoreTest_DoMoveDir_0003 + * @tc.desc: Test function of DoMoveDir() interface for FAILED. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MoveDirCoreTest, MoveDirCoreTest_DoMoveDir_0003, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MoveDirCoreTest-begin MoveDirCoreTest_DoMoveDir_0002"; + + string src = srcPath.string() + "/test03"; + string dest = destPath.string(); + + auto result = MoveDirCore::DoMoveDir(src, dest, optional(DIRMODE_DIRECTORY_REPLACE)); + + EXPECT_FALSE(result.fsResult.IsSuccess()); + auto err = result.fsResult.GetError(); + EXPECT_EQ(err.GetErrNo(), 13900020); + EXPECT_FALSE(result.errFiles.has_value()); + + GTEST_LOG_(INFO) << "MoveDirCoreTest-end MoveDirCoreTest_DoMoveDir_0003"; +} + +/** + * @tc.name: MoveDirCoreTest_DoMoveDir_0004 + * @tc.desc: Test function of DoMoveDir() interface for FAILED. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MoveDirCoreTest, MoveDirCoreTest_DoMoveDir_0004, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MoveDirCoreTest-begin MoveDirCoreTest_DoMoveDir_0002"; + + string src = srcPath.string(); + string dest = destPath.string() + "/test04"; + + auto result = MoveDirCore::DoMoveDir(src, dest, optional(DIRMODE_DIRECTORY_REPLACE)); + + EXPECT_FALSE(result.fsResult.IsSuccess()); + auto err = result.fsResult.GetError(); + EXPECT_EQ(err.GetErrNo(), 13900020); + EXPECT_FALSE(result.errFiles.has_value()); + + GTEST_LOG_(INFO) << "MoveDirCoreTest-end MoveDirCoreTest_DoMoveDir_0004"; +} + +/** + * @tc.name: MoveDirCoreTest_DoMoveDir_0005 + * @tc.desc: Test function of DoMoveDir() interface for FAILED. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MoveDirCoreTest, MoveDirCoreTest_DoMoveDir_0005, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MoveDirCoreTest-begin MoveDirCoreTest_DoMoveDir_0005"; + + string src = "/data/local/test05/src/src/src/test05"; + string dest = destPath.string() + "/src"; + filesystem::create_directories(src); + filesystem::create_directories(dest); + + auto result = MoveDirCore::DoMoveDir( + "/data/local/test05/", destPath.string(), optional(DIRMODE_DIRECTORY_THROW_ERR)); + + EXPECT_FALSE(result.fsResult.IsSuccess()); + auto err = result.fsResult.GetError(); + EXPECT_EQ(err.GetErrNo(), 13900032); + EXPECT_FALSE(result.errFiles.has_value()); + + filesystem::remove_all("/data/local/test05"); + + GTEST_LOG_(INFO) << "MoveDirCoreTest-end MoveDirCoreTest_DoMoveDir_0005"; +} + +/** + * @tc.name: MoveDirCoreTest_DoMoveDir_0006 + * @tc.desc: Test function of DoMoveDir() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MoveDirCoreTest, MoveDirCoreTest_DoMoveDir_0006, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MoveDirCoreTest-begin MoveDirCoreTest_DoMoveDir_0006"; + + string src = "/data/local/test06/src/src/src/test06"; + string dest = destPath.string() + "/src"; + filesystem::create_directories(src); + filesystem::create_directories(dest); + + auto result = MoveDirCore::DoMoveDir( + "/data/local/test06/src", destPath.string(), optional(DIRMODE_DIRECTORY_REPLACE)); + + EXPECT_TRUE(result.fsResult.IsSuccess()); + + filesystem::remove_all("/data/local/test06"); + + GTEST_LOG_(INFO) << "MoveDirCoreTest-end MoveDirCoreTest_DoMoveDir_0006"; +} + +/** + * @tc.name: MoveDirCoreTest_DoMoveDir_0007 + * @tc.desc: Test function of DoMoveDir() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MoveDirCoreTest, MoveDirCoreTest_DoMoveDir_0007, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MoveDirCoreTest-begin MoveDirCoreTest_DoMoveDir_0007"; + + filesystem::create_directories("/data/local/test07/src"); + filesystem::create_directories("/data/local/test07/dest"); + filesystem::path srcFile = "/data/local/test07/src/test_file.txt"; + ofstream(srcFile) << "Test content\n123\n456"; + filesystem::path destFile = "/data/local/test07/dest/test_file.txt"; + ofstream(destFile) << "Test content\ndest"; + + auto result = MoveDirCore::DoMoveDir( + "/data/local/test07/src/", "/data/local/test07/dest/", optional(DIRMODE_FILE_THROW_ERR)); + + EXPECT_FALSE(result.fsResult.IsSuccess()); + auto err = result.fsResult.GetError(); + EXPECT_EQ(err.GetErrNo(), 13900015); + EXPECT_TRUE(result.errFiles.has_value()); + + filesystem::remove_all("/data/local/test07"); + + GTEST_LOG_(INFO) << "MoveDirCoreTest-end MoveDirCoreTest_DoMoveDir_0007"; +} + +/** + * @tc.name: MoveDirCoreTest_DoMoveDir_0008 + * @tc.desc: Test function of DoMoveDir() interface for FAILED. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MoveDirCoreTest, MoveDirCoreTest_DoMoveDir_0008, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MoveDirCoreTest-begin MoveDirCoreTest_DoMoveDir_0008"; + + filesystem::create_directories("/data/local/test08/src"); + filesystem::create_directories("/data/local/test08/dest/test_file/test_file"); + filesystem::path srcFile = "/data/local/test08/src/test_file"; + ofstream(srcFile) << "Test content\n123\n456"; + + auto result = MoveDirCore::DoMoveDir( + "/data/local/test08/src/", "/data/local/test08/dest/test_file/", optional(DIRMODE_FILE_REPLACE)); + + EXPECT_FALSE(result.fsResult.IsSuccess()); + EXPECT_TRUE(result.errFiles.has_value()); + + filesystem::remove_all("/data/local/test08"); + + GTEST_LOG_(INFO) << "MoveDirCoreTest-end MoveDirCoreTest_DoMoveDir_0008"; +} + +/** + * @tc.name: MoveDirCoreTest_DoMoveDir_0009 + * @tc.desc: Test function of DoMoveDir() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MoveDirCoreTest, MoveDirCoreTest_DoMoveDir_0009, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MoveDirCoreTest-begin MoveDirCoreTest_DoMoveDir_0009"; + + filesystem::create_directories("/data/local/test09/src"); + filesystem::create_directories("/data/local/test09/dest"); + filesystem::path srcFile = "/data/local/test09/src/test_file.txt"; + ofstream(srcFile) << "Test content\n123\n456"; + filesystem::path destFile = "/data/local/test09/dest/test_file.txt"; + ofstream(destFile) << "Test content\ndest"; + + auto result = MoveDirCore::DoMoveDir( + "/data/local/test09/src/", "/data/local/test09/dest/", optional(DIRMODE_FILE_REPLACE)); + + EXPECT_TRUE(result.fsResult.IsSuccess()); + EXPECT_FALSE(result.errFiles.has_value()); + + filesystem::remove_all("/data/local/test09"); + + GTEST_LOG_(INFO) << "MoveDirCoreTest-end MoveDirCoreTest_DoMoveDir_0009"; +} + +/** + * @tc.name: MoveDirCoreTest_DoMoveDir_0010 + * @tc.desc: Test function of DoMoveDir() interface for SUCCESS. + * @tc.size: MEDIUM + * @tc.type: FUNC + * @tc.level Level 1 + */ +HWTEST_F(MoveDirCoreTest, MoveDirCoreTest_DoMoveDir_0010, testing::ext::TestSize.Level1) +{ + GTEST_LOG_(INFO) << "MoveDirCoreTest-begin MoveDirCoreTest_DoMoveDir_0010"; + + filesystem::create_directories("/data/local/test09/src/test_file.txt"); + filesystem::create_directories("/data/local/test09/dest"); + filesystem::path destFile = "/data/local/test09/dest/test_file.txt"; + ofstream(destFile) << "Test content\ndest"; + + auto result = MoveDirCore::DoMoveDir( + "/data/local/test09/src/", "/data/local/test09/dest/", optional(DIRMODE_FILE_REPLACE)); + + EXPECT_FALSE(result.fsResult.IsSuccess()); + EXPECT_TRUE(result.errFiles.has_value()); + + filesystem::remove_all("/data/local/test09"); + + GTEST_LOG_(INFO) << "MoveDirCoreTest-end MoveDirCoreTest_DoMoveDir_0010"; +} + +} // namespace OHOS::FileManagement::ModuleFileIO::Test \ No newline at end of file