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