• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "file_entity.h"
17 #include "file_n_exporter.h"
18 
19 #include <cstdio>
20 #include <cstdlib>
21 #include <cstring>
22 #include <memory>
23 #include <sys/file.h>
24 #include <tuple>
25 
26 #include "file_utils.h"
27 #include "filemgmt_libhilog.h"
28 #include "filemgmt_libn.h"
29 #include "../common_func.h"
30 
31 namespace OHOS {
32 namespace FileManagement {
33 namespace ModuleFileIO {
34 using namespace std;
35 using namespace OHOS::FileManagement::LibN;
36 
GetFileEntity(napi_env env,napi_value raf_entity)37 static FileEntity *GetFileEntity(napi_env env, napi_value raf_entity)
38 {
39     auto rafEntity = NClass::GetEntityOf<FileEntity>(env, raf_entity);
40     if (!rafEntity) {
41         HILOGE("Failed to get file entity");
42         NError(EINVAL).ThrowErr(env);
43         return nullptr;
44     }
45     if (!rafEntity->fd_) {
46         HILOGE("rafEntity fd is not exist");
47         NError(EINVAL).ThrowErr(env);
48         return nullptr;
49     }
50     return rafEntity;
51 }
52 
GetFD(napi_env env,napi_callback_info info)53 napi_value FileNExporter::GetFD(napi_env env, napi_callback_info info)
54 {
55     NFuncArg funcArg(env, info);
56     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
57         HILOGE("Number of arguments unmatched");
58         NError(EINVAL).ThrowErr(env);
59         return nullptr;
60     }
61     auto rafEntity = GetFileEntity(env, funcArg.GetThisVar());
62     if (!rafEntity) {
63         HILOGE("Failed to get file entity");
64         return nullptr;
65     }
66     return NVal::CreateInt32(env, rafEntity->fd_.get()->GetFD()).val_;
67 }
68 
69 #ifndef WIN_PLATFORM
RealPathCore(const string & srcPath)70 static tuple<int, unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*>> RealPathCore(const string &srcPath)
71 {
72     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> realpath_req = {
73         new (std::nothrow) uv_fs_t, CommonFunc::fs_req_cleanup };
74     if (!realpath_req) {
75         HILOGE("Failed to request heap memory.");
76         return { ENOMEM, move(realpath_req)};
77     }
78     int ret = uv_fs_realpath(nullptr, realpath_req.get(), srcPath.c_str(), nullptr);
79     if (ret < 0) {
80         HILOGE("Failed to realpath, ret: %{public}d, path: %{public}s", ret, srcPath.c_str());
81         return { ret, move(realpath_req)};
82     }
83     return { ERRNO_NOERR, move(realpath_req) };
84 }
85 
GetExclusive(napi_env env,NFuncArg & funcArg,bool & exclusive)86 static bool GetExclusive(napi_env env, NFuncArg &funcArg, bool &exclusive)
87 {
88     if (funcArg.GetArgc() >= NARG_CNT::ONE) {
89         bool succ = false;
90         tie(succ, exclusive) = NVal(env, funcArg[NARG_POS::FIRST]).ToBool(exclusive);
91         if (!succ) {
92             HILOGE("Invalid exclusive");
93             NError(EINVAL).ThrowErr(env);
94             return false;
95         }
96     }
97     return true;
98 }
99 
GetPath(napi_env env,napi_callback_info info)100 napi_value FileNExporter::GetPath(napi_env env, napi_callback_info info)
101 {
102     NFuncArg funcArg(env, info);
103     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
104         HILOGE("Number of arguments unmatched");
105         NError(EINVAL).ThrowErr(env);
106         return nullptr;
107     }
108     auto fileEntity = GetFileEntity(env, funcArg.GetThisVar());
109     if (!fileEntity) {
110         HILOGE("Failed to get file entity");
111         return nullptr;
112     }
113     auto [realPathRes, realPath] = RealPathCore(fileEntity->path_);
114     if (realPathRes != ERRNO_NOERR) {
115         NError(realPathRes).ThrowErr(env);
116         return nullptr;
117     }
118     return NVal::CreateUTF8String(env, string(static_cast<const char *>(realPath->ptr))).val_;
119 }
120 
GetName(napi_env env,napi_callback_info info)121 napi_value FileNExporter::GetName(napi_env env, napi_callback_info info)
122 {
123     NFuncArg funcArg(env, info);
124     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
125         HILOGE("Number of arguments unmatched");
126         NError(EINVAL).ThrowErr(env);
127         return nullptr;
128     }
129     auto fileEntity = GetFileEntity(env, funcArg.GetThisVar());
130     if (!fileEntity) {
131         HILOGE("Failed to get file entity");
132         return nullptr;
133     }
134     auto [realPathRes, realPath] = RealPathCore(fileEntity->path_);
135     if (realPathRes != ERRNO_NOERR) {
136         NError(realPathRes).ThrowErr(env);
137         return nullptr;
138     }
139     string path = string(static_cast<const char *>(realPath->ptr));
140     auto pos = path.find_last_of('/');
141     if (pos == string::npos) {
142         HILOGE("Failed to split filename from path, path: %{public}s", path.c_str());
143         NError(ENOENT).ThrowErr(env);
144         return nullptr;
145     }
146     return NVal::CreateUTF8String(env, path.substr(pos + 1)).val_;
147 }
148 
Lock(napi_env env,napi_callback_info info)149 napi_value FileNExporter::Lock(napi_env env, napi_callback_info info)
150 {
151     NFuncArg funcArg(env, info);
152     if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::TWO)) {
153         HILOGE("Number of arguments unmatched");
154         NError(EINVAL).ThrowErr(env);
155         return nullptr;
156     }
157 
158     auto fileEntity = GetFileEntity(env, funcArg.GetThisVar());
159     if (!fileEntity) {
160         HILOGE("Failed to get file entity");
161         NError(EINVAL).ThrowErr(env);
162         return nullptr;
163     }
164 
165     bool exclusive = false;
166     if (!GetExclusive(env, funcArg, exclusive)) {
167         return nullptr;
168     }
169     auto cbExec = [exclusive, fileEntity]() -> NError {
170         if (!fileEntity || !fileEntity->fd_.get()) {
171             HILOGE("File has been closed in Lock cbExec possibly");
172             return NError(EIO);
173         }
174         int ret = 0;
175         auto mode = exclusive ? LOCK_EX : LOCK_SH;
176         ret = flock(fileEntity->fd_.get()->GetFD(), mode);
177         if (ret < 0) {
178             HILOGE("Failed to lock file");
179             return NError(errno);
180         } else {
181             return NError(ERRNO_NOERR);
182         }
183     };
184 
185     auto cbCompl = [](napi_env env, NError err) -> NVal {
186         if (err) {
187             return { env, err.GetNapiErr(env) };
188         }
189         return NVal::CreateUndefined(env);
190     };
191 
192     NVal thisVar(env, funcArg.GetThisVar());
193     if (funcArg.GetArgc() == NARG_CNT::ZERO || (funcArg.GetArgc() == NARG_CNT::ONE &&
194         !NVal(env, funcArg[NARG_POS::FIRST]).TypeIs(napi_function))) {
195         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_LOCK_NAME, cbExec, cbCompl).val_;
196     } else {
197         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::TWO) ? NARG_POS::SECOND : NARG_POS::FIRST);
198         NVal cb(env, funcArg[cbIdx]);
199         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_LOCK_NAME, cbExec, cbCompl).val_;
200     }
201 }
202 
TryLock(napi_env env,napi_callback_info info)203 napi_value FileNExporter::TryLock(napi_env env, napi_callback_info info)
204 {
205     NFuncArg funcArg(env, info);
206     if (!funcArg.InitArgs(NARG_CNT::ZERO, NARG_CNT::ONE)) {
207         HILOGE("Number of arguments unmatched");
208         NError(EINVAL).ThrowErr(env);
209         return nullptr;
210     }
211 
212     auto fileEntity = GetFileEntity(env, funcArg.GetThisVar());
213     if (!fileEntity) {
214         HILOGE("Failed to get file entity");
215         NError(EINVAL).ThrowErr(env);
216         return nullptr;
217     }
218 
219     bool exclusive = false;
220     if (!GetExclusive(env, funcArg, exclusive)) {
221         return nullptr;
222     }
223 
224     int ret = 0;
225     auto mode = exclusive ? LOCK_EX : LOCK_SH;
226     ret = flock(fileEntity->fd_.get()->GetFD(), mode | LOCK_NB);
227     if (ret < 0) {
228         HILOGE("Failed to try to lock file");
229         NError(errno).ThrowErr(env);
230     }
231 
232     return NVal::CreateUndefined(env).val_;
233 }
234 
UnLock(napi_env env,napi_callback_info info)235 napi_value FileNExporter::UnLock(napi_env env, napi_callback_info info)
236 {
237     NFuncArg funcArg(env, info);
238     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
239         HILOGE("Number of arguments unmatched");
240         NError(EINVAL).ThrowErr(env);
241         return nullptr;
242     }
243 
244     auto fileEntity = GetFileEntity(env, funcArg.GetThisVar());
245     if (!fileEntity) {
246         HILOGE("Failed to get file entity");
247         NError(EINVAL).ThrowErr(env);
248         return nullptr;
249     }
250 
251     int ret = 0;
252     ret = flock(fileEntity->fd_.get()->GetFD(), LOCK_UN);
253     if (ret < 0) {
254         HILOGE("Failed to unlock file");
255         NError(errno).ThrowErr(env);
256         return nullptr;
257     }
258     return NVal::CreateUndefined(env).val_;
259 }
260 #endif
261 
Constructor(napi_env env,napi_callback_info info)262 napi_value FileNExporter::Constructor(napi_env env, napi_callback_info info)
263 {
264     NFuncArg funcArg(env, info);
265     if (!funcArg.InitArgs(NARG_CNT::ZERO)) {
266         HILOGE("Number of arguments unmatched");
267         NError(EINVAL).ThrowErr(env);
268         return nullptr;
269     }
270 
271     auto rafEntity = CreateUniquePtr<FileEntity>();
272     if (rafEntity == nullptr) {
273         HILOGE("Failed to request heap memory.");
274         NError(ENOMEM).ThrowErr(env);
275         return nullptr;
276     }
277     if (!NClass::SetEntityFor<FileEntity>(env, funcArg.GetThisVar(), move(rafEntity))) {
278         HILOGE("Failed to set file entity");
279         NError(EIO).ThrowErr(env);
280         return nullptr;
281     }
282     return funcArg.GetThisVar();
283 }
284 
Export()285 bool FileNExporter::Export()
286 {
287     vector<napi_property_descriptor> props = {
288         NVal::DeclareNapiGetter("fd", GetFD),
289 #ifndef WIN_PLATFORM
290         NVal::DeclareNapiGetter("path", GetPath),
291         NVal::DeclareNapiGetter("name", GetName),
292         NVal::DeclareNapiFunction("lock", Lock),
293         NVal::DeclareNapiFunction("tryLock", TryLock),
294         NVal::DeclareNapiFunction("unlock", UnLock),
295 #endif
296     };
297 
298 #ifdef WIN_PLATFORM
299     string className = GetNExporterName();
300 #else
301     string className = GetClassName();
302 #endif
303     bool succ = false;
304     napi_value classValue = nullptr;
305     tie(succ, classValue) = NClass::DefineClass(exports_.env_, className,
306         FileNExporter::Constructor, move(props));
307     if (!succ) {
308         HILOGE("Define class exceptions");
309         NError(EIO).ThrowErr(exports_.env_);
310         return false;
311     }
312     succ = NClass::SaveClass(exports_.env_, className, classValue);
313     if (!succ) {
314         HILOGE("Save class exceptions");
315         NError(EIO).ThrowErr(exports_.env_);
316         return false;
317     }
318 
319     return exports_.AddProp(className, classValue);
320 }
321 
322 #ifdef WIN_PLATFORM
GetNExporterName()323 string FileNExporter::GetNExporterName()
324 #else
325 string FileNExporter::GetClassName()
326 #endif
327 {
328     return FileNExporter::className_;
329 }
330 
FileNExporter(napi_env env,napi_value exports)331 FileNExporter::FileNExporter(napi_env env, napi_value exports) : NExporter(env, exports) {}
~FileNExporter()332 FileNExporter::~FileNExporter() {}
333 } // namespace ModuleFileIO
334 } // namespace FileManagement
335 } // namespace OHOS