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 "filemgmt_libhilog.h"
27
28 namespace OHOS {
29 namespace FileManagement {
30 namespace ModuleFileIO {
31 using namespace std;
32 using namespace OHOS::FileManagement::LibN;
33
34 #ifdef __MUSL__
RmDirent(const string & fpath)35 static NError RmDirent(const string &fpath)
36 {
37 std::filesystem::path strToPath(fpath);
38 std::uintmax_t num = std::filesystem::remove_all(strToPath);
39 if (!num || std::filesystem::exists(strToPath)) {
40 HILOGE("Failed to remove file or directory by path");
41 return NError(errno);
42 }
43
44 return NError(ERRNO_NOERR);
45 }
46
47 #else
RmDirent(const string & fpath)48 static NError RmDirent(const string &fpath)
49 {
50 if (rmdir(fpath.c_str()) == 0) {
51 return NError(ERRNO_NOERR);
52 }
53 auto dir = opendir(fpath.c_str());
54 if (!dir) {
55 return NError(errno);
56 }
57 struct dirent* entry = readdir(dir);
58 while (entry) {
59 if (strncmp(entry->d_name, ".", strlen(".")) == 0 ||
60 strncmp(entry->d_name, "..", strlen("..")) == 0) {
61 entry = readdir(dir);
62 continue;
63 }
64 struct stat fileInformation;
65 string filePath = fpath + '/';
66 filePath.insert(filePath.length(), entry->d_name);
67 if (stat(filePath.c_str(), &fileInformation) != 0) {
68 closedir(dir);
69 HILOGE("Failed to close directory");
70 return NError(errno);
71 }
72 if ((fileInformation.st_mode & S_IFMT) == S_IFDIR) {
73 auto err = RmDirent(filePath);
74 if (err) {
75 closedir(dir);
76 return err;
77 }
78 } else {
79 if (unlink(filePath.c_str()) != 0) {
80 closedir(dir);
81 return NError(errno);
82 }
83 }
84 entry = readdir(dir);
85 }
86 closedir(dir);
87 if (rmdir(fpath.c_str()) != 0) {
88 return NError(errno);
89 }
90 return NError(ERRNO_NOERR);
91 }
92 #endif
93
Sync(napi_env env,napi_callback_info info)94 napi_value Rmdirent::Sync(napi_env env, napi_callback_info info)
95 {
96 NFuncArg funcArg(env, info);
97 if (!funcArg.InitArgs(NARG_CNT::ONE)) {
98 HILOGE("Number of arguments unmatched");
99 NError(EINVAL).ThrowErr(env);
100 return nullptr;
101 }
102
103 auto [succ, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
104 if (!succ) {
105 HILOGE("Invalid path from JS first argument");
106 NError(EINVAL).ThrowErr(env);
107 return nullptr;
108 }
109
110 auto err = RmDirent(string(path.get()));
111 if (err) {
112 err.ThrowErr(env);
113 return nullptr;
114 }
115
116 return NVal::CreateUndefined(env).val_;
117 }
118
Async(napi_env env,napi_callback_info info)119 napi_value Rmdirent::Async(napi_env env, napi_callback_info info)
120 {
121 NFuncArg funcArg(env, info);
122 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
123 HILOGE("Number of arguments unmatched");
124 NError(EINVAL).ThrowErr(env);
125 return nullptr;
126 }
127
128 auto [succ, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
129 if (!succ) {
130 HILOGE("Invalid path from JS first argument");
131 NError(EINVAL).ThrowErr(env);
132 return nullptr;
133 }
134
135 auto cbExec = [tmpPath = string(path.get())]() -> NError {
136 return RmDirent(tmpPath);
137 };
138 auto cbCompl = [](napi_env env, NError err) -> NVal {
139 if (err) {
140 return { env, err.GetNapiErr(env) };
141 } else {
142 return NVal::CreateUndefined(env);
143 }
144 };
145
146 NVal thisVar(env, funcArg.GetThisVar());
147 size_t argc = funcArg.GetArgc();
148 if (argc == NARG_CNT::ONE) {
149 return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_RMDIRENT_NAME, cbExec, cbCompl).val_;
150 } else {
151 NVal cb(env, funcArg[NARG_POS::SECOND]);
152 return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_RMDIRENT_NAME, cbExec, cbCompl).val_;
153 }
154 }
155 } // namespace ModuleFileIO
156 } // namespace FileManagement
157 } // namespace OHOS