• 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 #include "open.h"
16 
17 #include <cstdio>
18 #include <cstdlib>
19 #include <cstring>
20 #include <memory>
21 
22 #include "ability.h"
23 #include "bundle_mgr_proxy.h"
24 #include "class_file/file_entity.h"
25 #include "class_file/file_n_exporter.h"
26 #include "common_func.h"
27 #include "datashare_helper.h"
28 #include "filemgmt_libhilog.h"
29 #include "ipc_skeleton.h"
30 #include "iservice_registry.h"
31 #include "remote_uri.h"
32 #include "status_receiver_host.h"
33 #include "system_ability_definition.h"
34 
35 namespace OHOS {
36 namespace FileManagement {
37 namespace ModuleFileIO {
38 using namespace std;
39 using namespace OHOS::FileManagement::LibN;
40 using namespace OHOS::DistributedFS::ModuleRemoteUri;
41 using namespace OHOS::AppExecFwk;
42 
GetJsFlags(napi_env env,const NFuncArg & funcArg)43 static tuple<bool, unsigned int> GetJsFlags(napi_env env, const NFuncArg &funcArg)
44 {
45     unsigned int mode = O_RDONLY;
46     bool succ = false;
47     if (funcArg.GetArgc() >= NARG_CNT::TWO && NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_number)) {
48         tie(succ, mode) = NVal(env, funcArg[NARG_POS::SECOND]).ToInt32();
49         unsigned int invalidMode = (O_WRONLY | O_RDWR);
50         if (!succ || ((mode & invalidMode) == invalidMode)) {
51             HILOGE("Invalid mode");
52             NError(EINVAL).ThrowErr(env);
53             return { false, mode };
54         }
55         (void)CommonFunc::ConvertJsFlags(mode);
56     }
57     return { true, mode };
58 }
59 
InstantiateFile(napi_env env,int fd,string pathOrUri,bool isUri)60 static NVal InstantiateFile(napi_env env, int fd, string pathOrUri, bool isUri)
61 {
62     napi_value objFile = NClass::InstantiateClass(env, FileNExporter::className_, {});
63     if (!objFile) {
64         HILOGE("Failed to instantiate class");
65         NError(EIO).ThrowErr(env);
66         int ret = close(fd);
67         if (ret < 0) {
68             HILOGE("Failed to close fd");
69         }
70         return NVal();
71     }
72 
73     auto fileEntity = NClass::GetEntityOf<FileEntity>(env, objFile);
74     if (!fileEntity) {
75         HILOGE("Failed to get fileEntity");
76         NError(EIO).ThrowErr(env);
77         int ret = close(fd);
78         if (ret < 0) {
79             HILOGE("Failed to close fd");
80         }
81         return NVal();
82     }
83     auto fdg = make_unique<DistributedFS::FDGuard>(fd, true);
84     fileEntity->fd_.swap(fdg);
85     if (isUri) {
86         fileEntity->path_ = "";
87         fileEntity->uri_ = pathOrUri;
88     } else {
89         fileEntity->path_ = pathOrUri;
90         fileEntity->uri_ = "";
91     }
92     return { env, objFile };
93 }
94 
OpenFileByDatashare(string path,unsigned int flags)95 static int OpenFileByDatashare(string path, unsigned int flags)
96 {
97     std::shared_ptr<DataShare::DataShareHelper> dataShareHelper = nullptr;
98     int fd = -1;
99     sptr<FileIoToken> remote = new (std::nothrow) IRemoteStub<FileIoToken>();
100     if (!remote) {
101         HILOGE("Failed to get remote object");
102         return -ENOMEM;
103     }
104 
105     dataShareHelper = DataShare::DataShareHelper::Creator(remote->AsObject(), MEDIALIBRARY_DATA_URI);
106     if (!dataShareHelper) {
107         HILOGE("Failed to connect to datashare");
108         return -E_PERMISSION;
109     }
110     Uri uri(path);
111     fd = dataShareHelper->OpenFile(uri, CommonFunc::GetModeFromFlags(flags));
112     return fd;
113 }
114 
GetBundleMgrProxy()115 static sptr<BundleMgrProxy> GetBundleMgrProxy()
116 {
117     sptr<ISystemAbilityManager> systemAbilityManager =
118         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
119     if (!systemAbilityManager) {
120         HILOGE("Failed to get system ability mgr.");
121         return nullptr;
122     }
123 
124     sptr<IRemoteObject> remoteObject = systemAbilityManager->GetSystemAbility(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID);
125     if (!remoteObject) {
126         HILOGE("Failed to get bundle manager proxy.");
127         return nullptr;
128     }
129     return iface_cast<BundleMgrProxy>(remoteObject);
130 }
131 
GetBundleNameSelf()132 static string GetBundleNameSelf()
133 {
134     int uid = -1;
135     uid = IPCSkeleton::GetCallingUid();
136 
137     sptr<BundleMgrProxy> bundleMgrProxy = GetBundleMgrProxy();
138     if (!bundleMgrProxy) {
139         HILOGE("Bundle mgr proxy is null ptr.");
140         return nullptr;
141     }
142     string bundleName;
143     if (!bundleMgrProxy->GetBundleNameForUid(uid, bundleName)) {
144         HILOGE("Failed to get bundleNameSelf. uid is %{public}d", uid);
145         return nullptr;
146     }
147     return bundleName;
148 }
149 
GetPathFromFileUri(string path,string bundleName,unsigned int mode)150 static string GetPathFromFileUri(string path, string bundleName, unsigned int mode)
151 {
152     if (bundleName != GetBundleNameSelf()) {
153         if ((mode & O_WRONLY) == O_WRONLY || (mode & O_RDWR) == O_RDWR) {
154             path = PATH_SHARE + MODE_RW + bundleName + path;
155         } else {
156             path = PATH_SHARE + MODE_R + bundleName + path;
157         }
158     }
159     return path;
160 }
161 
Sync(napi_env env,napi_callback_info info)162 napi_value Open::Sync(napi_env env, napi_callback_info info)
163 {
164     NFuncArg funcArg(env, info);
165     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::TWO)) {
166         HILOGE("Number of arguments unmatched");
167         NError(EINVAL).ThrowErr(env);
168         return nullptr;
169     }
170     auto [succPath, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
171     if (!succPath) {
172         HILOGE("Invalid path");
173         NError(EINVAL).ThrowErr(env);
174         return nullptr;
175     }
176     auto [succMode, mode] = GetJsFlags(env, funcArg);
177     if (!succMode) {
178         HILOGE("Invalid mode");
179         return nullptr;
180     }
181     int fd = -1;
182     string pathStr = string(path.get());
183     if (RemoteUri::IsMediaUri(pathStr)) {
184         int ret = OpenFileByDatashare(pathStr, mode);
185         if (ret >= 0) {
186             auto file = InstantiateFile(env, ret, pathStr, true).val_;
187             return file;
188         }
189         HILOGE("Failed to open file by Datashare");
190         NError(-ret).ThrowErr(env);
191         return nullptr;
192     } else if (RemoteUri::IsFileUri(pathStr)) {
193         RemoteUri remoteUri = RemoteUri(pathStr);
194         pathStr = GetPathFromFileUri(remoteUri.GetPath(), remoteUri.GetAuthority(), mode);
195     } else if (RemoteUri::IsRemoteUri(pathStr, fd, mode)) {
196         if (fd >= 0) {
197             auto file = InstantiateFile(env, fd, pathStr, true).val_;
198             return file;
199         }
200         HILOGE("Failed to open file by RemoteUri");
201         NError(E_INVAL).ThrowErr(env);
202         return nullptr;
203     }
204     std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> open_req = {
205         new uv_fs_t, CommonFunc::fs_req_cleanup };
206     if (!open_req) {
207         HILOGE("Failed to request heap memory.");
208         NError(ENOMEM).ThrowErr(env);
209         return nullptr;
210     }
211     int ret = uv_fs_open(nullptr, open_req.get(), pathStr.c_str(), mode, S_IRUSR |
212         S_IWUSR | S_IRGRP | S_IWGRP, nullptr);
213     if (ret < 0) {
214         HILOGE("Failed to open file for libuv error %{public}d", ret);
215         NError(errno).ThrowErr(env);
216         return nullptr;
217     }
218     auto file = InstantiateFile(env, ret, pathStr, false).val_;
219     return file;
220 }
221 
222 struct AsyncOpenFileArg {
223     int fd;
224     string path;
225     string uri;
226 };
227 
Async(napi_env env,napi_callback_info info)228 napi_value Open::Async(napi_env env, napi_callback_info info)
229 {
230     NFuncArg funcArg(env, info);
231     if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
232         HILOGE("Number of arguments unmatched");
233         NError(EINVAL).ThrowErr(env);
234         return nullptr;
235     }
236     auto [succPath, path, ignore] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
237     if (!succPath) {
238         HILOGE("Invalid path");
239         NError(EINVAL).ThrowErr(env);
240         return nullptr;
241     }
242     auto [succMode, mode] = GetJsFlags(env, funcArg);
243     if (!succMode) {
244         HILOGE("Invalid mode");
245         return nullptr;
246     }
247     auto arg = make_shared<AsyncOpenFileArg>();
248     auto argv = funcArg[NARG_POS::FIRST];
249     auto cbExec = [arg, argv, path = string(path.get()), mode = mode, env = env]() -> NError {
250         string pathStr = path;
251         int fd = -1;
252         if (RemoteUri::IsMediaUri(path)) {
253             int ret = OpenFileByDatashare(path, mode);
254             if (ret >= 0) {
255                 arg->fd = ret;
256                 arg->path = "";
257                 arg->uri = path;
258                 return NError(ERRNO_NOERR);
259             }
260             HILOGE("Failed to open file by Datashare");
261             return NError(-ret);
262         } else if (RemoteUri::IsFileUri(path)) {
263             RemoteUri remoteUri = RemoteUri(path);
264             pathStr = GetPathFromFileUri(remoteUri.GetPath(), remoteUri.GetAuthority(), mode);
265         } else if (RemoteUri::IsRemoteUri(path, fd, mode)) {
266             if (fd >= 0) {
267                 arg->fd = fd;
268                 arg->path = "";
269                 arg->uri = path;
270                 return NError(ERRNO_NOERR);
271             }
272             HILOGE("Failed to open file by RemoteUri");
273             return NError(E_INVAL);
274         }
275         std::unique_ptr<uv_fs_t, decltype(CommonFunc::fs_req_cleanup)*> open_req = {
276             new uv_fs_t, CommonFunc::fs_req_cleanup };
277         if (!open_req) {
278             HILOGE("Failed to request heap memory.");
279             return NError(ERRNO_NOERR);
280         }
281         int ret = uv_fs_open(nullptr, open_req.get(), pathStr.c_str(), mode, S_IRUSR |
282             S_IWUSR | S_IRGRP | S_IWGRP, nullptr);
283         if (ret < 0) {
284             HILOGE("Failed to open file for libuv error %{public}d", ret);
285             return NError(errno);
286         }
287         arg->fd = ret;
288         arg->path = pathStr;
289         arg->uri = "";
290         return NError(ERRNO_NOERR);
291     };
292     auto cbCompl = [arg](napi_env env, NError err) -> NVal {
293         if (err) {
294             return { env, err.GetNapiErr(env) };
295         }
296         bool isUri = false;
297         if (arg->path.empty() && arg->uri.size()) {
298             isUri = true;
299             return InstantiateFile(env, arg->fd, arg->uri, isUri);
300         }
301         return InstantiateFile(env, arg->fd, arg->path, isUri);
302     };
303     NVal thisVar(env, funcArg.GetThisVar());
304     if (funcArg.GetArgc() == NARG_CNT::ONE || (funcArg.GetArgc() == NARG_CNT::TWO &&
305         NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_number))) {
306         return NAsyncWorkPromise(env, thisVar).Schedule(PROCEDURE_OPEN_NAME, cbExec, cbCompl).val_;
307     } else {
308         int cbIdx = ((funcArg.GetArgc() == NARG_CNT::THREE) ? NARG_POS::THIRD : NARG_POS::SECOND);
309         NVal cb(env, funcArg[cbIdx]);
310         return NAsyncWorkCallback(env, thisVar, cb).Schedule(PROCEDURE_OPEN_NAME, cbExec, cbCompl).val_;
311     }
312 }
313 } // namespace ModuleFileIO
314 } // namespace FileManagement
315 } // namespace OHOS