1 /*
2 * Copyright (c) 2022-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 "stat_entity.h"
17 #include "stat_n_exporter.h"
18
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <memory>
23 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
24 #include <sys/xattr.h>
25 #endif
26
27 #include "file_utils.h"
28 #include "filemgmt_libhilog.h"
29
30 namespace OHOS::FileManagement::ModuleFileIO {
31 using namespace std;
32 using namespace OHOS::FileManagement::LibN;
33
CheckStatMode(napi_env env,napi_callback_info info,mode_t mode)34 static napi_value CheckStatMode(napi_env env, napi_callback_info info, mode_t mode)
35 {
36 NFuncArg funcArg(env, info);
37 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
38 HILOGE("Number of arguments unmatched");
39 NError(EINVAL).ThrowErr(env);
40 return nullptr;
41 }
42
43 auto statEntity = NClass::GetEntityOf<StatEntity>(env, funcArg.GetThisVar());
44 if (!statEntity) {
45 HILOGE("Failed to get stat entity");
46 return nullptr;
47 }
48
49 bool check = (statEntity->stat_.st_mode & S_IFMT) == mode;
50 return NVal::CreateBool(env, check).val_;
51 }
52
IsBlockDevice(napi_env env,napi_callback_info info)53 napi_value StatNExporter::IsBlockDevice(napi_env env, napi_callback_info info)
54 {
55 return CheckStatMode(env, info, S_IFBLK);
56 }
57
IsCharacterDevice(napi_env env,napi_callback_info info)58 napi_value StatNExporter::IsCharacterDevice(napi_env env, napi_callback_info info)
59 {
60 return CheckStatMode(env, info, S_IFCHR);
61 }
62
IsDirectory(napi_env env,napi_callback_info info)63 napi_value StatNExporter::IsDirectory(napi_env env, napi_callback_info info)
64 {
65 return CheckStatMode(env, info, S_IFDIR);
66 }
67
IsFIFO(napi_env env,napi_callback_info info)68 napi_value StatNExporter::IsFIFO(napi_env env, napi_callback_info info)
69 {
70 return CheckStatMode(env, info, S_IFIFO);
71 }
72
IsFile(napi_env env,napi_callback_info info)73 napi_value StatNExporter::IsFile(napi_env env, napi_callback_info info)
74 {
75 return CheckStatMode(env, info, S_IFREG);
76 }
77
IsSocket(napi_env env,napi_callback_info info)78 napi_value StatNExporter::IsSocket(napi_env env, napi_callback_info info)
79 {
80 return CheckStatMode(env, info, S_IFSOCK);
81 }
82
IsSymbolicLink(napi_env env,napi_callback_info info)83 napi_value StatNExporter::IsSymbolicLink(napi_env env, napi_callback_info info)
84 {
85 return CheckStatMode(env, info, S_IFLNK);
86 }
87
GetIno(napi_env env,napi_callback_info info)88 napi_value StatNExporter::GetIno(napi_env env, napi_callback_info info)
89 {
90 NFuncArg funcArg(env, info);
91 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
92 HILOGE("Number of arguments unmatched");
93 NError(EINVAL).ThrowErr(env);
94 return nullptr;
95 }
96
97 auto statEntity = NClass::GetEntityOf<StatEntity>(env, funcArg.GetThisVar());
98 if (!statEntity) {
99 HILOGE("Failed to get stat entity");
100 return nullptr;
101 }
102
103 return NVal::CreateBigInt64(env, statEntity->stat_.st_ino).val_;
104 }
105
GetMode(napi_env env,napi_callback_info info)106 napi_value StatNExporter::GetMode(napi_env env, napi_callback_info info)
107 {
108 NFuncArg funcArg(env, info);
109 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
110 HILOGE("Number of arguments unmatched");
111 NError(EINVAL).ThrowErr(env);
112 return nullptr;
113 }
114
115 auto statEntity = NClass::GetEntityOf<StatEntity>(env, funcArg.GetThisVar());
116 if (!statEntity) {
117 HILOGE("Failed to get stat entity");
118 return nullptr;
119 }
120
121 return NVal::CreateInt64(env, statEntity->stat_.st_mode & S_PERMISSION).val_;
122 }
123
GetUid(napi_env env,napi_callback_info info)124 napi_value StatNExporter::GetUid(napi_env env, napi_callback_info info)
125 {
126 NFuncArg funcArg(env, info);
127 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
128 HILOGE("Number of arguments unmatched");
129 NError(EINVAL).ThrowErr(env);
130 return nullptr;
131 }
132
133 auto statEntity = NClass::GetEntityOf<StatEntity>(env, funcArg.GetThisVar());
134 if (!statEntity) {
135 HILOGE("Failed to get stat entity");
136 return nullptr;
137 }
138
139 return NVal::CreateInt64(env, statEntity->stat_.st_uid).val_;
140 }
141
GetGid(napi_env env,napi_callback_info info)142 napi_value StatNExporter::GetGid(napi_env env, napi_callback_info info)
143 {
144 NFuncArg funcArg(env, info);
145 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
146 HILOGE("Number of arguments unmatched");
147 NError(EINVAL).ThrowErr(env);
148 return nullptr;
149 }
150
151 auto statEntity = NClass::GetEntityOf<StatEntity>(env, funcArg.GetThisVar());
152 if (!statEntity) {
153 HILOGE("Failed to get stat entity");
154 return nullptr;
155 }
156
157 return NVal::CreateInt64(env, statEntity->stat_.st_gid).val_;
158 }
159
GetSize(napi_env env,napi_callback_info info)160 napi_value StatNExporter::GetSize(napi_env env, napi_callback_info info)
161 {
162 NFuncArg funcArg(env, info);
163 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
164 HILOGE("Number of arguments unmatched");
165 NError(EINVAL).ThrowErr(env);
166 return nullptr;
167 }
168
169 auto statEntity = NClass::GetEntityOf<StatEntity>(env, funcArg.GetThisVar());
170 if (!statEntity) {
171 HILOGE("Failed to get stat entity");
172 return nullptr;
173 }
174
175 return NVal::CreateInt64(env, statEntity->stat_.st_size).val_;
176 }
177
GetAtime(napi_env env,napi_callback_info info)178 napi_value StatNExporter::GetAtime(napi_env env, napi_callback_info info)
179 {
180 NFuncArg funcArg(env, info);
181 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
182 HILOGE("Number of arguments unmatched");
183 NError(EINVAL).ThrowErr(env);
184 return nullptr;
185 }
186
187 auto statEntity = NClass::GetEntityOf<StatEntity>(env, funcArg.GetThisVar());
188 if (!statEntity) {
189 HILOGE("Failed to get stat entity");
190 return nullptr;
191 }
192
193 return NVal::CreateInt64(env, static_cast<int64_t>(statEntity->stat_.st_atim.tv_sec)).val_;
194 }
195
GetMtime(napi_env env,napi_callback_info info)196 napi_value StatNExporter::GetMtime(napi_env env, napi_callback_info info)
197 {
198 NFuncArg funcArg(env, info);
199 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
200 HILOGE("Number of arguments unmatched");
201 NError(EINVAL).ThrowErr(env);
202 return nullptr;
203 }
204
205 auto statEntity = NClass::GetEntityOf<StatEntity>(env, funcArg.GetThisVar());
206 if (!statEntity) {
207 HILOGE("Failed to get stat entity");
208 return nullptr;
209 }
210
211 return NVal::CreateInt64(env, static_cast<int64_t>(statEntity->stat_.st_mtim.tv_sec)).val_;
212 }
213
GetCtime(napi_env env,napi_callback_info info)214 napi_value StatNExporter::GetCtime(napi_env env, napi_callback_info info)
215 {
216 NFuncArg funcArg(env, info);
217 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
218 HILOGE("Number of arguments unmatched");
219 NError(EINVAL).ThrowErr(env);
220 return nullptr;
221 }
222
223 auto statEntity = NClass::GetEntityOf<StatEntity>(env, funcArg.GetThisVar());
224 if (!statEntity) {
225 HILOGE("Failed to get stat entity");
226 return nullptr;
227 }
228
229 return NVal::CreateInt64(env, static_cast<int64_t>(statEntity->stat_.st_ctim.tv_sec)).val_;
230 }
231
232 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
GetLocation(napi_env env,napi_callback_info info)233 napi_value StatNExporter::GetLocation(napi_env env, napi_callback_info info)
234 {
235 NFuncArg funcArg(env, info);
236 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
237 HILOGE("Number of arguments unmatched");
238 NError(EINVAL).ThrowErr(env);
239 return nullptr;
240 }
241
242 auto statEntity = NClass::GetEntityOf<StatEntity>(env, funcArg.GetThisVar());
243 if (!statEntity) {
244 HILOGE("Failed to get stat entity");
245 return nullptr;
246 }
247 std::unique_ptr<char[]> value = CreateUniquePtr<char[]>(MAX_ATTR_NAME);
248 if (value == nullptr) {
249 HILOGE("Getxattr memory out, errno is %{public}d", errno);
250 NError(ENOMEM).ThrowErr(env);
251 return nullptr;
252 }
253
254 ssize_t size = 0;
255 if (statEntity->fileInfo_->isPath) {
256 size = getxattr(statEntity->fileInfo_->path.get(), CLOUD_LOCATION_ATTR.c_str(), value.get(), MAX_ATTR_NAME);
257 } else {
258 size = fgetxattr(statEntity->fileInfo_->fdg->GetFD(), CLOUD_LOCATION_ATTR.c_str(), value.get(), MAX_ATTR_NAME);
259 }
260 Location defaultLocation = LOCAL;
261 if (size <= 0) {
262 if (errno != ENODATA && errno != EOPNOTSUPP) {
263 HILOGE("Getxattr value failed, errno is %{public}d", errno);
264 }
265 return NVal::CreateInt32(env, static_cast<int32_t>(defaultLocation)).val_;
266 }
267 std::string location = string(value.get(), static_cast<size_t>(size));
268 if (!std::all_of(location.begin(), location.end(), ::isdigit)) {
269 HILOGE("Getxattr location is not all digit!");
270 return NVal::CreateInt32(env, static_cast<int32_t>(defaultLocation)).val_;
271 }
272 defaultLocation = static_cast<Location>(atoi(location.c_str()));
273 return NVal::CreateInt32(env, static_cast<int32_t>(defaultLocation)).val_;
274 }
275 #endif
276
Constructor(napi_env env,napi_callback_info info)277 napi_value StatNExporter::Constructor(napi_env env, napi_callback_info info)
278 {
279 NFuncArg funcArg(env, info);
280 if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
281 HILOGE("Number of arguments unmatched");
282 NError(EINVAL).ThrowErr(env);
283 return nullptr;
284 }
285
286 auto statEntity = CreateUniquePtr<StatEntity>();
287 if (statEntity == nullptr) {
288 HILOGE("Failed to request heap memory.");
289 NError(ENOMEM).ThrowErr(env);
290 return nullptr;
291 }
292 if (!NClass::SetEntityFor<StatEntity>(env, funcArg.GetThisVar(), move(statEntity))) {
293 HILOGE("Failed to set stat entity");
294 NError(EINVAL).ThrowErr(env);
295 return nullptr;
296 }
297 return funcArg.GetThisVar();
298 }
299
Export()300 bool StatNExporter::Export()
301 {
302 vector<napi_property_descriptor> props = {
303 NVal::DeclareNapiFunction("isBlockDevice", IsBlockDevice),
304 NVal::DeclareNapiFunction("isCharacterDevice", IsCharacterDevice),
305 NVal::DeclareNapiFunction("isDirectory", IsDirectory),
306 NVal::DeclareNapiFunction("isFIFO", IsFIFO),
307 NVal::DeclareNapiFunction("isFile", IsFile),
308 NVal::DeclareNapiFunction("isSocket", IsSocket),
309 NVal::DeclareNapiFunction("isSymbolicLink", IsSymbolicLink),
310
311 NVal::DeclareNapiGetter("ino", GetIno),
312 NVal::DeclareNapiGetter("mode", GetMode),
313 NVal::DeclareNapiGetter("uid", GetUid),
314 NVal::DeclareNapiGetter("gid", GetGid),
315 NVal::DeclareNapiGetter("size", GetSize),
316 NVal::DeclareNapiGetter("atime", GetAtime),
317 NVal::DeclareNapiGetter("mtime", GetMtime),
318 NVal::DeclareNapiGetter("ctime", GetCtime),
319 #if !defined(WIN_PLATFORM) && !defined(IOS_PLATFORM)
320 NVal::DeclareNapiGetter("location", GetLocation),
321 #endif
322 };
323
324 #ifdef WIN_PLATFORM
325 string className = GetNExporterName();
326 #else
327 string className = GetClassName();
328 #endif
329 bool succ = false;
330 napi_value classValue = nullptr;
331 tie(succ, classValue) = NClass::DefineClass(exports_.env_, className, StatNExporter::Constructor,
332 std::move(props));
333 if (!succ) {
334 HILOGE("Failed to define class");
335 NError(EIO).ThrowErr(exports_.env_);
336 return false;
337 }
338 succ = NClass::SaveClass(exports_.env_, className, classValue);
339 if (!succ) {
340 HILOGE("Failed to save class");
341 NError(EIO).ThrowErr(exports_.env_);
342 return false;
343 }
344
345 return exports_.AddProp(className, classValue);
346 }
347
348 #ifdef WIN_PLATFORM
GetNExporterName()349 string StatNExporter::GetNExporterName()
350 #else
351 string StatNExporter::GetClassName()
352 #endif
353 {
354 return StatNExporter::className_;
355 }
356
StatNExporter(napi_env env,napi_value exports)357 StatNExporter::StatNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
358
~StatNExporter()359 StatNExporter::~StatNExporter() {}
360 } // namespace OHOS::FileManagement::ModuleFileIO