1 /*
2 * Copyright (c) 2021 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 "open.h"
17 #include <cstring>
18 #include <fcntl.h>
19 #include <tuple>
20 #include <unistd.h>
21 #include "remote_uri.h"
22
23 #include "../../common/napi/n_async/n_async_work_callback.h"
24 #include "../../common/napi/n_async/n_async_work_promise.h"
25 #include "../../common/napi/n_func_arg.h"
26
27 namespace OHOS {
28 namespace DistributedFS {
29 namespace ModuleFileIO {
30 using namespace std;
31
AdaptToAbi(int & flags)32 int AdaptToAbi(int &flags)
33 {
34 static constexpr int USR_O_RDONLY = 00;
35 static constexpr int USR_O_WRONLY = 01;
36 static constexpr int USR_O_RDWR = 02;
37 static constexpr int USR_O_CREAT = 0100;
38 static constexpr int USR_O_EXCL = 0200;
39 static constexpr int USR_O_TRUNC = 01000;
40 static constexpr int USR_O_APPEND = 02000;
41 static constexpr int USR_O_NONBLOCK = 04000;
42 static constexpr int USR_O_DIRECTORY = 0200000;
43 static constexpr int USR_O_NOFOLLOW = 0400000;
44 static constexpr int USR_O_SYNC = 04010000;
45
46 int flagsABI = 0;
47 flagsABI |= ((flags & USR_O_RDONLY) == USR_O_RDONLY) ? O_RDONLY : 0;
48 flagsABI |= ((flags & USR_O_WRONLY) == USR_O_WRONLY) ? O_WRONLY : 0;
49 flagsABI |= ((flags & USR_O_RDWR) == USR_O_RDWR) ? O_RDWR : 0;
50 flagsABI |= ((flags & USR_O_CREAT) == USR_O_CREAT) ? O_CREAT : 0;
51 flagsABI |= ((flags & USR_O_EXCL) == USR_O_EXCL) ? O_EXCL : 0;
52 flagsABI |= ((flags & USR_O_TRUNC) == USR_O_TRUNC) ? O_TRUNC : 0;
53 flagsABI |= ((flags & USR_O_APPEND) == USR_O_APPEND) ? O_APPEND : 0;
54 flagsABI |= ((flags & USR_O_NONBLOCK) == USR_O_NONBLOCK) ? O_NONBLOCK : 0;
55 flagsABI |= ((flags & USR_O_DIRECTORY) == USR_O_DIRECTORY) ? O_DIRECTORY : 0;
56 flagsABI |= ((flags & USR_O_NOFOLLOW) == USR_O_NOFOLLOW) ? O_NOFOLLOW : 0;
57 flagsABI |= ((flags & USR_O_SYNC) == USR_O_SYNC) ? O_SYNC : 0;
58 flags = flagsABI;
59 return flagsABI;
60 }
61
Sync(napi_env env,napi_callback_info info)62 napi_value Open::Sync(napi_env env, napi_callback_info info)
63 {
64 NFuncArg funcArg(env, info);
65 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::THREE)) {
66 UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
67 return nullptr;
68 }
69
70 bool succ = false;
71 unique_ptr<char[]> path;
72 tie(succ, path, ignore) = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
73 if (!succ) {
74 UniError(EINVAL).ThrowErr(env, "Invalid path");
75 return nullptr;
76 }
77
78 int flags = O_RDONLY;
79 if (funcArg.GetArgc() >= NARG_CNT::TWO) {
80 tie(succ, flags) = NVal(env, funcArg[NARG_POS::SECOND]).ToInt32();
81 if (!succ) {
82 UniError(EINVAL).ThrowErr(env, "Invalid flags");
83 return nullptr;
84 }
85 }
86 (void)AdaptToAbi(flags);
87 int fd = -1;
88 if (ModuleRemoteUri::RemoteUri::IsRemoteUri(path.get(), fd, flags)) {
89 return NVal::CreateInt64(env, fd).val_;
90 }
91
92 size_t argc = funcArg.GetArgc();
93 if (argc != NARG_CNT::THREE) {
94 size_t flagsFirst { flags };
95 if ((flagsFirst & O_CREAT) || (flagsFirst & O_TMPFILE)) {
96 UniError(EINVAL).ThrowErr(env, "called with O_CREAT/O_TMPFILE but no mode");
97 return nullptr;
98 }
99 fd = open(path.get(), flags);
100 } else {
101 int mode;
102 tie(succ, mode) = NVal(env, funcArg.GetArg(NARG_POS::THIRD)).ToInt32();
103 if (!succ) {
104 UniError(EINVAL).ThrowErr(env, "Invalid mode");
105 return nullptr;
106 }
107 fd = open(path.get(), flags, mode);
108 }
109
110 if (fd == -1) {
111 if (errno == ENAMETOOLONG) {
112 UniError(errno).ThrowErr(env, "Filename too long");
113 return nullptr;
114 }
115 UniError(errno).ThrowErr(env);
116 return nullptr;
117 }
118
119 return NVal::CreateInt64(env, fd).val_;
120 }
121
DoOpenExec(const std::string & path,const int flags,const int mode,shared_ptr<int32_t> arg)122 static UniError DoOpenExec(const std::string& path, const int flags, const int mode, shared_ptr<int32_t> arg)
123 {
124 int fd = -1;
125 if (!ModuleRemoteUri::RemoteUri::IsRemoteUri(path, fd, flags)) {
126 fd = open(path.c_str(), flags, mode);
127 }
128 *arg = fd;
129 if (fd == -1) {
130 return UniError(errno);
131 } else {
132 return UniError(ERRNO_NOERR);
133 }
134 }
135
Async(napi_env env,napi_callback_info info)136 napi_value Open::Async(napi_env env, napi_callback_info info)
137 {
138 NFuncArg funcArg(env, info);
139 if (!funcArg.InitArgs(NARG_CNT::ONE, NARG_CNT::FOUR)) {
140 UniError(EINVAL).ThrowErr(env, "Number of arguments unmatched");
141 return nullptr;
142 }
143
144 auto [succ, path, unuse] = NVal(env, funcArg[NARG_POS::FIRST]).ToUTF8String();
145 if (!succ) {
146 UniError(EINVAL).ThrowErr(env, "Invalid path");
147 return nullptr;
148 }
149
150 int flags = O_RDONLY;
151 if (funcArg.GetArgc() >= NARG_CNT::TWO && !NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_function)) {
152 tie(succ, flags) = NVal(env, funcArg[NARG_POS::SECOND]).ToInt32();
153 if (!succ) {
154 UniError(EINVAL).ThrowErr(env, "Invalid flags");
155 return nullptr;
156 }
157 (void)AdaptToAbi(flags);
158 }
159
160 int mode = 0;
161 size_t argc = funcArg.GetArgc();
162 if (argc == NARG_CNT::FOUR ||
163 (argc == NARG_CNT::THREE && NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_number))) {
164 tie(succ, mode) = NVal(env, funcArg[NARG_POS::THIRD]).ToInt32();
165 if (!succ) {
166 UniError(EINVAL).ThrowErr(env, "Invalid mode");
167 return nullptr;
168 }
169 }
170
171 auto arg = make_shared<int32_t>();
172 auto cbExec = [path = string(path.get()), flags, mode, arg](napi_env env) -> UniError {
173 return DoOpenExec(path, flags, mode, arg);
174 };
175
176 auto cbComplCallback = [arg](napi_env env, UniError err) -> NVal {
177 if (err) {
178 if (err.GetErrno(ERR_CODE_SYSTEM_POSIX) == ENAMETOOLONG) {
179 return {env, err.GetNapiErr(env, "Filename too long")};
180 }
181 return { env, err.GetNapiErr(env) };
182 }
183 return { NVal::CreateInt64(env, *arg) };
184 };
185
186 NVal thisVar(env, funcArg.GetThisVar());
187 if (argc == NARG_CNT::ONE || (argc == NARG_CNT::TWO && NVal(env, funcArg[NARG_POS::SECOND]).TypeIs(napi_number)) ||
188 (argc == NARG_CNT::THREE && (NVal(env, funcArg[NARG_POS::THIRD]).TypeIs(napi_number)))) {
189 return NAsyncWorkPromise(env, thisVar).Schedule("FileIOOpen", cbExec, cbComplCallback).val_;
190 } else {
191 NVal cb(env, funcArg[argc - 1]);
192 return NAsyncWorkCallback(env, thisVar, cb).Schedule("FileIOOpen", cbExec, cbComplCallback).val_;
193 }
194 }
195 } // namespace ModuleFileIO
196 } // namespace DistributedFS
197 } // namespace OHOS