15bebb993Sopenharmony_ci/* 25bebb993Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 35bebb993Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 45bebb993Sopenharmony_ci * you may not use this file except in compliance with the License. 55bebb993Sopenharmony_ci * You may obtain a copy of the License at 65bebb993Sopenharmony_ci * 75bebb993Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 85bebb993Sopenharmony_ci * 95bebb993Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 105bebb993Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 115bebb993Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 125bebb993Sopenharmony_ci * See the License for the specific language governing permissions and 135bebb993Sopenharmony_ci * limitations under the License. 145bebb993Sopenharmony_ci */ 155bebb993Sopenharmony_ci 165bebb993Sopenharmony_ci#include "move_file.h" 175bebb993Sopenharmony_ci#include "macro.h" 185bebb993Sopenharmony_ci#include "stat_impl.h" 195bebb993Sopenharmony_ci 205bebb993Sopenharmony_ci#include <cstring> 215bebb993Sopenharmony_ci#include <fcntl.h> 225bebb993Sopenharmony_ci 235bebb993Sopenharmony_ci#ifdef __MUSL__ 245bebb993Sopenharmony_ci#include <filesystem> 255bebb993Sopenharmony_ci#else 265bebb993Sopenharmony_ci#include <sys/stat.h> 275bebb993Sopenharmony_ci#endif 285bebb993Sopenharmony_ci 295bebb993Sopenharmony_ci#include "uv.h" 305bebb993Sopenharmony_ci#include <tuple> 315bebb993Sopenharmony_ci#include <unistd.h> 325bebb993Sopenharmony_ci 335bebb993Sopenharmony_cinamespace OHOS { 345bebb993Sopenharmony_cinamespace CJSystemapi { 355bebb993Sopenharmony_ciusing namespace std; 365bebb993Sopenharmony_ciusing namespace OHOS::FileManagement::LibN; 375bebb993Sopenharmony_ci 385bebb993Sopenharmony_ci#ifdef __MUSL__ 395bebb993Sopenharmony_cistatic bool CheckDir(const string &path) 405bebb993Sopenharmony_ci{ 415bebb993Sopenharmony_ci if (!filesystem::is_directory(filesystem::status(path))) { 425bebb993Sopenharmony_ci return false; 435bebb993Sopenharmony_ci } 445bebb993Sopenharmony_ci return true; 455bebb993Sopenharmony_ci} 465bebb993Sopenharmony_ci#else 475bebb993Sopenharmony_cistatic bool CheckDir(const string &path) 485bebb993Sopenharmony_ci{ 495bebb993Sopenharmony_ci struct stat fileInformation; 505bebb993Sopenharmony_ci if (stat(path.c_str(), &fileInformation) == 0) { 515bebb993Sopenharmony_ci if (fileInformation.st_mode & S_IFDIR) { 525bebb993Sopenharmony_ci return true; 535bebb993Sopenharmony_ci } 545bebb993Sopenharmony_ci } else { 555bebb993Sopenharmony_ci LOGE("Failed to stat file"); 565bebb993Sopenharmony_ci } 575bebb993Sopenharmony_ci return false; 585bebb993Sopenharmony_ci} 595bebb993Sopenharmony_ci#endif 605bebb993Sopenharmony_ci 615bebb993Sopenharmony_cistatic int ChangeTime(const string &path, uv_fs_t *statReq) 625bebb993Sopenharmony_ci{ 635bebb993Sopenharmony_ci std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> utime_req = { 645bebb993Sopenharmony_ci new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup }; 655bebb993Sopenharmony_ci if (!utime_req) { 665bebb993Sopenharmony_ci LOGE("Failed to request heap memory."); 675bebb993Sopenharmony_ci return ENOMEM; 685bebb993Sopenharmony_ci } 695bebb993Sopenharmony_ci double atime = static_cast<double>(statReq->statbuf.st_atim.tv_sec) + 705bebb993Sopenharmony_ci static_cast<double>(statReq->statbuf.st_atim.tv_nsec) / NS; 715bebb993Sopenharmony_ci double mtime = static_cast<double>(statReq->statbuf.st_mtim.tv_sec) + 725bebb993Sopenharmony_ci static_cast<double>(statReq->statbuf.st_mtim.tv_nsec) / NS; 735bebb993Sopenharmony_ci int ret = uv_fs_utime(nullptr, utime_req.get(), path.c_str(), atime, mtime, nullptr); 745bebb993Sopenharmony_ci if (ret < 0) { 755bebb993Sopenharmony_ci LOGE("Failed to utime dstPath"); 765bebb993Sopenharmony_ci } 775bebb993Sopenharmony_ci return ret; 785bebb993Sopenharmony_ci} 795bebb993Sopenharmony_cistatic int CopyAndDeleteFile(const string &src, const string &dest) 805bebb993Sopenharmony_ci{ 815bebb993Sopenharmony_ci std::unique_ptr<uv_fs_t, decltype(CommonFunc::FsReqCleanup)*> stat_req = { 825bebb993Sopenharmony_ci new (std::nothrow) uv_fs_t, CommonFunc::FsReqCleanup }; 835bebb993Sopenharmony_ci if (!stat_req) { 845bebb993Sopenharmony_ci LOGE("Failed to request heap memory."); 855bebb993Sopenharmony_ci return ENOMEM; 865bebb993Sopenharmony_ci } 875bebb993Sopenharmony_ci int ret = uv_fs_stat(nullptr, stat_req.get(), src.c_str(), nullptr); 885bebb993Sopenharmony_ci if (ret < 0) { 895bebb993Sopenharmony_ci LOGE("Failed to stat srcPath"); 905bebb993Sopenharmony_ci return ret; 915bebb993Sopenharmony_ci } 925bebb993Sopenharmony_ci#if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM) 935bebb993Sopenharmony_ci filesystem::path dstPath(dest); 945bebb993Sopenharmony_ci std::error_code errCode; 955bebb993Sopenharmony_ci if (filesystem::exists(dstPath)) { 965bebb993Sopenharmony_ci if (!filesystem::remove(dstPath, errCode)) { 975bebb993Sopenharmony_ci LOGE("Failed to remove dest file, error code: %{public}d", errCode.value()); 985bebb993Sopenharmony_ci return errCode.value(); 995bebb993Sopenharmony_ci } 1005bebb993Sopenharmony_ci } 1015bebb993Sopenharmony_ci filesystem::path srcPath(src); 1025bebb993Sopenharmony_ci if (!filesystem::copy_file(srcPath, dstPath, filesystem::copy_options::overwrite_existing, errCode)) { 1035bebb993Sopenharmony_ci LOGE("Failed to copy file, error code: %{public}d", errCode.value()); 1045bebb993Sopenharmony_ci return errCode.value(); 1055bebb993Sopenharmony_ci } 1065bebb993Sopenharmony_ci#else 1075bebb993Sopenharmony_ci uv_fs_t copyfile_req; 1085bebb993Sopenharmony_ci ret = uv_fs_copyfile(nullptr, ©file_req, src.c_str(), dest.c_str(), MODE_FORCE_MOVE, nullptr); 1095bebb993Sopenharmony_ci uv_fs_req_cleanup(©file_req); 1105bebb993Sopenharmony_ci if (ret < 0) { 1115bebb993Sopenharmony_ci LOGE("Failed to move file using copyfile interface."); 1125bebb993Sopenharmony_ci return ret; 1135bebb993Sopenharmony_ci } 1145bebb993Sopenharmony_ci#endif 1155bebb993Sopenharmony_ci uv_fs_t unlinkReq; 1165bebb993Sopenharmony_ci ret = uv_fs_unlink(nullptr, &unlinkReq, src.c_str(), nullptr); 1175bebb993Sopenharmony_ci if (ret < 0) { 1185bebb993Sopenharmony_ci LOGE("Failed to unlink src file"); 1195bebb993Sopenharmony_ci int result = uv_fs_unlink(nullptr, &unlinkReq, dest.c_str(), nullptr); 1205bebb993Sopenharmony_ci if (result < 0) { 1215bebb993Sopenharmony_ci LOGE("Failed to unlink dest file"); 1225bebb993Sopenharmony_ci return result; 1235bebb993Sopenharmony_ci } 1245bebb993Sopenharmony_ci uv_fs_req_cleanup(&unlinkReq); 1255bebb993Sopenharmony_ci return ret; 1265bebb993Sopenharmony_ci } 1275bebb993Sopenharmony_ci uv_fs_req_cleanup(&unlinkReq); 1285bebb993Sopenharmony_ci return ChangeTime(dest, stat_req.get()); 1295bebb993Sopenharmony_ci} 1305bebb993Sopenharmony_ci 1315bebb993Sopenharmony_cistatic int RenameFile(const string &src, const string &dest) 1325bebb993Sopenharmony_ci{ 1335bebb993Sopenharmony_ci int ret = 0; 1345bebb993Sopenharmony_ci uv_fs_t renameReq; 1355bebb993Sopenharmony_ci ret = uv_fs_rename(nullptr, &renameReq, src.c_str(), dest.c_str(), nullptr); 1365bebb993Sopenharmony_ci if (ret < 0 && (string_view(uv_err_name(ret)) == "EXDEV")) { 1375bebb993Sopenharmony_ci return CopyAndDeleteFile(src, dest); 1385bebb993Sopenharmony_ci } 1395bebb993Sopenharmony_ci if (ret < 0) { 1405bebb993Sopenharmony_ci LOGE("Failed to move file using rename syscall."); 1415bebb993Sopenharmony_ci return ret; 1425bebb993Sopenharmony_ci } 1435bebb993Sopenharmony_ci return OHOS::FileManagement::LibN::ERRNO_NOERR; 1445bebb993Sopenharmony_ci} 1455bebb993Sopenharmony_ci 1465bebb993Sopenharmony_ciint MoveFileImpl::MoveFile(const std::string& src, const std::string& dest, int mode) 1475bebb993Sopenharmony_ci{ 1485bebb993Sopenharmony_ci LOGI("FS_TEST:: MoveFileImpl::MoveFile start"); 1495bebb993Sopenharmony_ci if (CheckDir(src)) { 1505bebb993Sopenharmony_ci LOGE("Invalid src"); 1515bebb993Sopenharmony_ci return EINVAL; 1525bebb993Sopenharmony_ci } 1535bebb993Sopenharmony_ci if (CheckDir(dest)) { 1545bebb993Sopenharmony_ci LOGE("Invalid dest"); 1555bebb993Sopenharmony_ci return EINVAL; 1565bebb993Sopenharmony_ci } 1575bebb993Sopenharmony_ci uv_fs_t accessReq; 1585bebb993Sopenharmony_ci int ret = uv_fs_access(nullptr, &accessReq, src.c_str(), W_OK, nullptr); 1595bebb993Sopenharmony_ci if (ret < 0) { 1605bebb993Sopenharmony_ci LOGE("Failed to move src file due to doesn't exist or hasn't write permission"); 1615bebb993Sopenharmony_ci uv_fs_req_cleanup(&accessReq); 1625bebb993Sopenharmony_ci return ret; 1635bebb993Sopenharmony_ci } 1645bebb993Sopenharmony_ci if (mode == MODE_THROW_ERR) { 1655bebb993Sopenharmony_ci ret = uv_fs_access(nullptr, &accessReq, dest.c_str(), 0, nullptr); 1665bebb993Sopenharmony_ci uv_fs_req_cleanup(&accessReq); 1675bebb993Sopenharmony_ci if (ret == 0) { 1685bebb993Sopenharmony_ci LOGE("Failed to move file due to existing destPath with MODE_THROW_ERR."); 1695bebb993Sopenharmony_ci return EEXIST; 1705bebb993Sopenharmony_ci } 1715bebb993Sopenharmony_ci if (ret < 0 && (string_view(uv_err_name(ret)) != "ENOENT")) { 1725bebb993Sopenharmony_ci LOGE("Failed to access destPath with MODE_THROW_ERR."); 1735bebb993Sopenharmony_ci return ret; 1745bebb993Sopenharmony_ci } 1755bebb993Sopenharmony_ci } else { 1765bebb993Sopenharmony_ci uv_fs_req_cleanup(&accessReq); 1775bebb993Sopenharmony_ci } 1785bebb993Sopenharmony_ci return RenameFile(src, dest); 1795bebb993Sopenharmony_ci} 1805bebb993Sopenharmony_ci 1815bebb993Sopenharmony_ci} 1825bebb993Sopenharmony_ci}