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