diff --git a/interfaces/kits/cj/src/copy_dir.cpp b/interfaces/kits/cj/src/copy_dir.cpp new file mode 100644 index 0000000000000000000000000000000000000000..00dfa9a7e58c1a5415e1b1af057421671dde7446 --- /dev/null +++ b/interfaces/kits/cj/src/copy_dir.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2024 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 "file_fs_impl.h" +#include "n_error.h" +#include "securec.h" +#include "copy_dir.h" + +using namespace OHOS; +using namespace OHOS::FFI; +using namespace OHOS::FileManagement; +using namespace OHOS::CJSystemapi; +using namespace OHOS::FileManagement::LibN; + +namespace { + +static int RecurCopyDir(const std::string &srcPath, const std::string &destPath, const int mode, + std::vector &errfiles); + +static int MakeDir(const std::string &path) +{ + std::filesystem::path destDir(path); + std::error_code errCode; + if (!std::filesystem::create_directory(destDir, errCode)) { + LOGE("Failed to create directory, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return OHOS::FileManagement::LibN::ERRNO_NOERR; +} + +struct NameList { + struct dirent** namelist = { nullptr }; + int direntNum = 0; +}; + +static int RemoveFile(const std::string &destPath) +{ + std::filesystem::path destFile(destPath); + std::error_code errCode; + if (!std::filesystem::remove(destFile, errCode)) { + LOGE("Failed to remove file with path, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return OHOS::FileManagement::LibN::ERRNO_NOERR; +} + +static void Deleter(struct NameList *arg) +{ + for (int i = 0; i < arg->direntNum; i++) { + free((arg->namelist)[i]); + (arg->namelist)[i] = nullptr; + } + free(arg->namelist); +} + +static int CopyFile(const std::string &src, const std::string &dest, const int mode) +{ + std::filesystem::path dstPath(dest); + if (std::filesystem::exists(dstPath)) { + int ret = (mode == DIRMODE_FILE_COPY_THROW_ERR) ? EEXIST : RemoveFile(dest); + if (ret) { + LOGE("Failed to copy file due to existing destPath with throw err"); + return ret; + } + } + std::filesystem::path srcPath(src); + std::error_code errCode; + if (!std::filesystem::copy_file(srcPath, dstPath, std::filesystem::copy_options::overwrite_existing, errCode)) { + LOGE("Failed to copy file, error code: %{public}d", errCode.value()); + return errCode.value(); + } + return OHOS::FileManagement::LibN::ERRNO_NOERR; +} + +static int CopySubDir(const std::string &srcPath, const std::string &destPath, const int mode, + std::vector &errfiles) +{ + if (!std::filesystem::exists(destPath)) { + int res = MakeDir(destPath); + if (res != OHOS::FileManagement::LibN::ERRNO_NOERR) { + LOGE("Failed to mkdir"); + return res; + } + } + return RecurCopyDir(srcPath, destPath, mode, errfiles); +} + +static int FilterFunc(const struct dirent *filename) +{ + if (std::string_view(filename->d_name) == "." || std::string_view(filename->d_name) == "..") { + return DISMATCH; + } + return MATCH; +} + +static int RecurCopyDir(const std::string &srcPath, const std::string &destPath, const int mode, + std::vector &errfiles) +{ + std::unique_ptr pNameList = {new (std::nothrow) struct NameList, Deleter}; + if (pNameList == nullptr) { + LOGE("Failed to request heap memory."); + return ENOMEM; + } + int num = scandir(srcPath.c_str(), &(pNameList->namelist), FilterFunc, alphasort); + pNameList->direntNum = num; + + for (int i = 0; i < num; i++) { + if ((pNameList->namelist[i])->d_type == DT_DIR) { + std::string srcTemp = srcPath + '/' + std::string((pNameList->namelist[i])->d_name); + std::string destTemp = destPath + '/' + std::string((pNameList->namelist[i])->d_name); + LOGI("srcTemp %{public}s from", srcTemp.c_str()); + LOGI("destTemp %{public}s to", destTemp.c_str()); + int res = CopySubDir(srcTemp, destTemp, mode, errfiles); + if (res == OHOS::FileManagement::LibN::ERRNO_NOERR) { + continue; + } + return res; + } else { + LOGI("srcPath %{public}s from", srcPath.c_str()); + LOGI("destPath %{public}s to", destPath.c_str()); + std::string src = srcPath + '/' + std::string((pNameList->namelist[i])->d_name); + std::string dest = destPath + '/' + std::string((pNameList->namelist[i])->d_name); + LOGI("CopyFile %{public}s from", src.c_str()); + LOGI("CopyFile %{public}s to", dest.c_str()); + int res = CopyFile(src, dest, mode); + if (res == EEXIST) { + errfiles.emplace_back(src, dest); + continue; + } else if (res == OHOS::FileManagement::LibN::ERRNO_NOERR) { + continue; + } else { + LOGE("Failed to copy file for error %{public}d", res); + return res; + } + } + } + return OHOS::FileManagement::LibN::ERRNO_NOERR; +} + +static bool AllowToCopy(const std::string &src, const std::string &dest) +{ + if (dest.find(src) == 0 || std::filesystem::path(src).parent_path() == dest) { + return false; + } + return true; +} + +static int CopyDirFunc(const std::string &src, const std::string &dest, const int mode, + std::vector &errfiles) +{ + size_t found = std::string(src).rfind('/'); + if (found == std::string::npos) { + LOGE("CopyDirFunc EINVAL"); + return EINVAL; + } + std::string dirName = std::string(src).substr(found); + std::string destStr = dest + dirName; + LOGI("destStr: %{public}s", destStr.c_str()); + if (!std::filesystem::exists(destStr)) { + int res = MakeDir(destStr); + if (res != OHOS::FileManagement::LibN::ERRNO_NOERR) { + LOGE("Failed to mkdir"); + return res; + } + } + int res = RecurCopyDir(src, destStr, mode, errfiles); + if (!errfiles.empty() && res == OHOS::FileManagement::LibN::ERRNO_NOERR) { + LOGE("CopyDirFunc EEXIST"); + return EEXIST; + } + return res; +} + +static CConflictFiles* VectorToCConflict(std::vector &errfiles) +{ + CConflictFiles* result = new CConflictFiles[errfiles.size()]; + for (size_t i = 0; i < errfiles.size(); i++) { + size_t srcFilesLen = errfiles[i].srcFiles.length() + 1; + result[i].srcFiles = new char[srcFilesLen]; + if (strcpy_s(result[i].srcFiles, srcFilesLen, errfiles[i].srcFiles.c_str()) != 0) { + delete result[i].srcFiles; + for (size_t j = i - 1; j >= 0; j--) { + delete result[j].srcFiles; + delete result[j].destFiles; + } + delete[] result; + return nullptr; + } + size_t destFilesLen = errfiles[i].destFiles.length() + 1; + result[i].destFiles = new char[destFilesLen]; + if (strcpy_s(result[i].destFiles, destFilesLen, errfiles[i].destFiles.c_str()) != 0) { + for (size_t j = i; j >= 0; j--) { + delete result[j].srcFiles; + delete result[j].destFiles; + } + delete[] result; + return nullptr; + } + } + return result; +} + +} + +namespace OHOS { +namespace CJSystemapi { + +RetDataCArrConflictFiles CopyDirImpl::CopyDir(std::string src, std::string dest, int mode) +{ + LOGI("FS_TEST:: FileFsImpl::CopyDir start"); + RetDataCArrConflictFiles ret = { .code = EINVAL, .data = { .head = nullptr, .size = 0 } }; + if (!std::filesystem::is_directory(std::filesystem::status(dest))) { + LOGE("Invalid dest"); + return ret; + } + if (!AllowToCopy(src, dest)) { + LOGE("Failed to copy file"); + return ret; + } + if (mode < COPYMODE_MIN || mode > COPYMODE_MAX) { + LOGE("Invalid mode"); + return ret; + } + LOGI("FS_TEST:: FileFsImpl::Copy parameter check passed"); + std::vector errfiles = {}; + ret.code = CopyDirFunc(src, dest, mode, errfiles); + ret.data.size = (int64_t)errfiles.size(); + ret.data.head = VectorToCConflict(errfiles); + return ret; +} + +} +} // namespace OHOS::CJSystemapi \ No newline at end of file diff --git a/interfaces/kits/cj/src/copy_dir.h b/interfaces/kits/cj/src/copy_dir.h new file mode 100644 index 0000000000000000000000000000000000000000..5baa00960e939cb9baf37c4979790888642dac03 --- /dev/null +++ b/interfaces/kits/cj/src/copy_dir.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 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 OHOS_FILE_FS_COPY_DIR_H +#define OHOS_FILE_FS_COPY_DIR_H + +#include +#include "utils.h" + +namespace OHOS { +namespace CJSystemapi { + +constexpr int COPYMODE_MIN = 0; +constexpr int COPYMODE_MAX = 1; + +constexpr int DISMATCH = 0; +constexpr int MATCH = 1; + +enum ModeOfCopyDir { + DIRMODE_FILE_COPY_THROW_ERR = 0, + DIRMODE_FILE_COPY_REPLACE +}; + +class CopyDirImpl { +public: + static RetDataCArrConflictFiles CopyDir(std::string src, std::string dest, int mode); +}; + +} +} + +#endif // OHOS_FILE_FS_COPY_DIR_H \ No newline at end of file