• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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