1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "rmdirent.h"
17
18 #include <cstring>
19 #include <dirent.h>
20 #include <filesystem>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23 #include <tuple>
24 #include <unistd.h>
25
26 #include "common_func.h"
27 #include "filemgmt_libhilog.h"
28 #include "uv.h"
29
30 namespace OHOS {
31 namespace FileManagement {
32 namespace ModuleFileIO {
33 using namespace std;
34 using namespace OHOS::FileManagement::LibN;
35
36 #ifdef __MUSL__
RmDirent(const string & fpath)37 static NError RmDirent(const string &fpath)
38 {
39 std::filesystem::path strToPath(fpath);
40 std::error_code errCode;
41 std::uintmax_t num = std::filesystem::remove_all(strToPath, errCode);
42 if (errCode) {
43 HILOGE("Failed to remove directory, error code: %{public}d", errCode.value());
44 return NError(errCode.value());
45 }
46 if (!num || std::filesystem::exists(strToPath)) {
47 HILOGE("Failed to remove directory, dirPath does not exist");
48 return NError(ENOENT);
49 }
50 return NError(ERRNO_NOERR);
51 }
52
53 #else
RmDirent(const string & fpath)54 static NError RmDirent(const string &fpath)
55 {
56 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> scandir_req = {
57 new (std::nothrow) uv_fs_t, CommonFunc::fs_req_cleanup };
58 if (!scandir_req) {
59 HILOGE("Failed to request heap memory.");
60 return NError(ENOMEM);
61 }
62 int ret = 0;
63 ret = uv_fs_scandir(nullptr, scandir_req.get(), fpath.c_str(), 0, nullptr);
64 if (ret < 0) {
65 HILOGE("Failed to scandir, ret: %{public}d", ret);
66 return NError(ret);
67 }
68 uv_dirent_t dent;
69 while (uv_fs_scandir_next(scandir_req.get(), &dent) != UV_EOF) {
70 string filePath = fpath + "/" + string(dent.name);
71 if (dent.type == UV_DIRENT_FILE) {
72 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> unlink_req = {
73 new (std::nothrow) uv_fs_t, CommonFunc::fs_req_cleanup };
74 if (!unlink_req) {
75 HILOGE("Failed to request heap memory.");
76 return NError(ENOMEM);
77 }
78 ret = uv_fs_unlink(nullptr, unlink_req.get(), filePath.c_str(), nullptr);
79 if (ret < 0) {
80 HILOGE("Failed to unlink file, ret: %{public}d", ret);
81 return NError(ret);
82 }
83 } else if (dent.type == UV_DIRENT_DIR) {
84 auto rmDirentRes = RmDirent(filePath);
85 if (rmDirentRes) {
86 return rmDirentRes;
87 }
88 }
89 }
90 std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> rmdir_req = {
91 new (std::nothrow) uv_fs_t, CommonFunc::fs_req_cleanup };
92 if (!rmdir_req) {
93 HILOGE("Failed to request heap memory.");
94 return NError(ENOMEM);
95 }
96 ret = uv_fs_rmdir(nullptr, rmdir_req.get(), fpath.c_str(), nullptr);
97 if (ret < 0) {
98 HILOGE("Failed to rmdir empty dir, ret: %{public}d", ret);
99 return NError(ret);
100 }
101 return NError(ERRNO_NOERR);
102 }
103 #endif
104
Sync(napi_env env,napi_callback_info info)105 napi_value Rmdirent::Sync(napi_env env, napi_callback_info info)
106 {
107 NFuncArg funcArg(env, info);
108 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
109 HILOGE("Number of arguments unmatched");
110 NError(EINVAL).ThrowErr(env);
111 return nullptr;
112 }
113
114 auto [succ, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
115 if (!succ) {
116 HILOGE("Invalid path from JS first argument");
117 NError(EINVAL).ThrowErr(env);
118 return nullptr;
119 }
120
121 auto err = RmDirent(string(path.get()));
122 if (err) {
123 err.ThrowErr(env);
124 return nullptr;
125 }
126
127 return NVal::CreateUndefined(env).val_;
128 }
129
Async(napi_env env,napi_callback_info info)130 napi_value Rmdirent::Async(napi_env env, napi_callback_info info)
131 {
132 NFuncArg funcArg(env, info);
133 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
134 HILOGE("Number of arguments unmatched");
135 NError(EINVAL).ThrowErr(env);
136 return nullptr;
137 }
138
139 auto [succ, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
140 if (!succ) {
141 HILOGE("Invalid path from JS first argument");
142 NError(EINVAL).ThrowErr(env);
143 return nullptr;
144 }
145
146 auto cbExec = [tmpPath = string(path.get())]() -> NError {
147 return RmDirent(tmpPath);
148 };
149 auto cbCompl = [](napi_env env, NError err) -> NVal {
150 if (err) {
151 return { env, err.GetNapiErr(env) };
152 } else {
153 return NVal::CreateUndefined(env);
154 }
155 };
156
157 NVal thisVar(env, funcArg.GetThisVar());
158 size_t argc = funcArg.GetArgc();
159 if (argc == NARG_CNT::ONE) {
160 return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_RMDIRENT_NAME, cbExec, cbCompl).val_;
161 } else {
162 NVal cb(env, funcArg[NARG_POS::SECOND]);
163 return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_RMDIRENT_NAME, cbExec, cbCompl).val_;
164 }
165 }
166 } // namespace ModuleFileIO
167 } // namespace FileManagement
168 } // namespace OHOS