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 "common_func.h"
17
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #include "../common/log.h"
25 #include "../common/napi/n_class.h"
26 #include "../common/napi/n_func_arg.h"
27 #include "../common/napi/n_val.h"
28 #include "../common/uni_error.h"
29
30 namespace OHOS {
31 namespace DistributedFS {
32 namespace ModuleFileIO {
33 using namespace std;
34
GetActualBuf(napi_env env,void * rawBuf,int64_t bufLen,NVal op)35 static tuple<bool, void *, int> GetActualBuf(napi_env env, void *rawBuf, int64_t bufLen, NVal op)
36 {
37 bool succ = false;
38 void *realBuf = nullptr;
39 int64_t opOffset = 0;
40 if (op.HasProp("offset")) {
41 tie(succ, opOffset) = op.GetProp("offset").ToInt64();
42 if (!succ || opOffset < 0) {
43 UniError(EINVAL).ThrowErr(env, "Invalid option.offset, positive integer is desired");
44 return { false, nullptr, opOffset };
45 } else if (opOffset > bufLen) {
46 UniError(EINVAL).ThrowErr(env, "Invalid option.offset, buffer limit exceeded");
47 return { false, nullptr, opOffset };
48 } else {
49 realBuf = static_cast<uint8_t *>(rawBuf) + opOffset;
50 }
51 } else {
52 realBuf = rawBuf;
53 }
54
55 return { true, realBuf, opOffset };
56 }
57
GetActualLen(napi_env env,int64_t bufLen,int64_t bufOff,NVal op)58 static tuple<bool, size_t> GetActualLen(napi_env env, int64_t bufLen, int64_t bufOff, NVal op)
59 {
60 bool succ = false;
61 int64_t retLen;
62
63 if (op.HasProp("length")) {
64 int64_t opLength;
65 tie(succ, opLength) = op.GetProp("length").ToInt64();
66 if (!succ) {
67 UniError(EINVAL).ThrowErr(env, "Invalid option.length, expect integer");
68 return { false, 0 };
69 }
70 if (opLength < 0) {
71 retLen = bufLen - bufOff;
72 } else if (opLength + bufOff > bufLen) {
73 UniError(EINVAL).ThrowErr(env, "Invalid option.length, buffer limit exceeded");
74 return { false, 0 };
75 } else {
76 retLen = opLength;
77 }
78 } else {
79 retLen = bufLen - bufOff;
80 }
81
82 return { true, retLen };
83 }
84
ConvertJsFlags(int & flags)85 int CommonFunc::ConvertJsFlags(int &flags)
86 {
87 static constexpr int USR_O_RDONLY = 00;
88 static constexpr int USR_O_WRONLY = 01;
89 static constexpr int USR_O_RDWR = 02;
90 static constexpr int USR_O_CREAT = 0100;
91 static constexpr int USR_O_EXCL = 0200;
92 static constexpr int USR_O_TRUNC = 01000;
93 static constexpr int USR_O_APPEND = 02000;
94 static constexpr int USR_O_NONBLOCK = 04000;
95 static constexpr int USR_O_DIRECTORY = 0200000;
96 static constexpr int USR_O_NOFOLLOW = 0400000;
97 static constexpr int USR_O_SYNC = 04010000;
98
99 int flagsABI = 0;
100 flagsABI |= ((flags & USR_O_RDONLY) == USR_O_RDONLY) ? O_RDONLY : 0;
101 flagsABI |= ((flags & USR_O_WRONLY) == USR_O_WRONLY) ? O_WRONLY : 0;
102 flagsABI |= ((flags & USR_O_RDWR) == USR_O_RDWR) ? O_RDWR : 0;
103 flagsABI |= ((flags & USR_O_CREAT) == USR_O_CREAT) ? O_CREAT : 0;
104 flagsABI |= ((flags & USR_O_EXCL) == USR_O_EXCL) ? O_EXCL : 0;
105 flagsABI |= ((flags & USR_O_TRUNC) == USR_O_TRUNC) ? O_TRUNC : 0;
106 flagsABI |= ((flags & USR_O_APPEND) == USR_O_APPEND) ? O_APPEND : 0;
107 flagsABI |= ((flags & USR_O_NONBLOCK) == USR_O_NONBLOCK) ? O_NONBLOCK : 0;
108 flagsABI |= ((flags & USR_O_DIRECTORY) == USR_O_DIRECTORY) ? O_DIRECTORY : 0;
109 flagsABI |= ((flags & USR_O_NOFOLLOW) == USR_O_NOFOLLOW) ? O_NOFOLLOW : 0;
110 flagsABI |= ((flags & USR_O_SYNC) == USR_O_SYNC) ? O_SYNC : 0;
111 flags = flagsABI;
112 return flagsABI;
113 }
114
GetCopyPathArg(napi_env env,napi_value srcPath,napi_value dstPath)115 tuple<bool, unique_ptr<char[]>, unique_ptr<char[]>> CommonFunc::GetCopyPathArg(napi_env env,
116 napi_value srcPath,
117 napi_value dstPath)
118 {
119 bool succ = false;
120 unique_ptr<char[]> src;
121 tie(succ, src, ignore) = NVal(env, srcPath).ToUTF8String();
122 if (!succ) {
123 return { false, nullptr, nullptr };
124 }
125
126 unique_ptr<char[]> dest;
127 tie(succ, dest, ignore) = NVal(env, dstPath).ToUTF8String();
128 if (!succ) {
129 return { false, nullptr, nullptr };
130 }
131 return make_tuple(succ, move(src), move(dest));
132 }
133
GetReadArg(napi_env env,napi_value readBuf,napi_value option)134 tuple<bool, void *, int64_t, bool, int64_t, int> CommonFunc::GetReadArg(napi_env env,
135 napi_value readBuf,
136 napi_value option)
137 {
138 bool succ = false;
139 void *retBuf = nullptr;
140 int64_t retLen;
141 bool posAssigned = false;
142 int64_t position;
143
144 NVal txt(env, readBuf);
145 void *buf = nullptr;
146 int64_t bufLen;
147 int offset = 0;
148 tie(succ, buf, bufLen) = txt.ToArraybuffer();
149 if (!succ) {
150 UniError(EINVAL).ThrowErr(env, "Invalid read buffer, expect arraybuffer");
151 return { false, nullptr, 0, posAssigned, position, offset };
152 }
153
154 NVal op = NVal(env, option);
155 tie(succ, retBuf, offset) = GetActualBuf(env, buf, bufLen, op);
156 if (!succ) {
157 return { false, nullptr, 0, posAssigned, position, offset };
158 }
159
160 int64_t bufOff = static_cast<uint8_t *>(retBuf) - static_cast<uint8_t *>(buf);
161 tie(succ, retLen) = GetActualLen(env, bufLen, bufOff, op);
162 if (!succ) {
163 return { false, nullptr, 0, posAssigned, position, offset };
164 }
165
166 if (op.HasProp("position")) {
167 tie(succ, position) = op.GetProp("position").ToInt64();
168 if (succ && position >= 0) {
169 posAssigned = true;
170 } else {
171 UniError(EINVAL).ThrowErr(env, "option.position shall be positive number");
172 return { false, nullptr, 0, posAssigned, position, offset };
173 }
174 }
175
176 return { true, retBuf, retLen, posAssigned, position, offset };
177 }
178
DecodeString(napi_env env,NVal jsStr,NVal encoding)179 static tuple<bool, unique_ptr<char[]>, int64_t> DecodeString(napi_env env, NVal jsStr, NVal encoding)
180 {
181 unique_ptr<char[]> buf;
182 if (!jsStr.TypeIs(napi_string)) {
183 return { false, nullptr, 0 };
184 }
185
186 bool succ = false;
187 if (!encoding) {
188 return jsStr.ToUTF8String();
189 }
190
191 unique_ptr<char[]> encodingBuf;
192 tie(succ, encodingBuf, ignore) = encoding.ToUTF8String();
193 if (!succ) {
194 return { false, nullptr, 0 };
195 }
196 string encodingStr(encodingBuf.release());
197 if (encodingStr == "utf-8") {
198 return jsStr.ToUTF8String();
199 } else if (encodingStr == "utf-16") {
200 return jsStr.ToUTF16String();
201 } else {
202 return { false, nullptr, 0 };
203 }
204 }
205
206 // Is everything ok? Do we need to free memory? What's the three args required by fwrite? Where to start writing?
GetWriteArg(napi_env env,napi_value argWBuf,napi_value argOption)207 tuple<bool, unique_ptr<char[]>, void *, int64_t, bool, int64_t> CommonFunc::GetWriteArg(napi_env env,
208 napi_value argWBuf,
209 napi_value argOption)
210 {
211 void *retBuf = nullptr;
212 int64_t retLen;
213 bool hasPos = false;
214 int64_t retPos;
215
216 /* To get write buffer */
217 bool succ = false;
218 void *buf = nullptr;
219 int64_t bufLen;
220 NVal op(env, argOption);
221 NVal jsBuffer(env, argWBuf);
222 unique_ptr<char[]> bufferGuard;
223 tie(succ, bufferGuard, bufLen) = DecodeString(env, jsBuffer, op.GetProp("encoding"));
224 if (!succ) {
225 tie(succ, buf, bufLen) = NVal(env, argWBuf).ToArraybuffer();
226 if (!succ) {
227 UniError(EINVAL).ThrowErr(env, "Illegal write buffer or encoding");
228 return { false, nullptr, nullptr, 0, hasPos, retPos };
229 }
230 } else {
231 buf = bufferGuard.get();
232 }
233
234 tie(succ, retBuf, ignore) = GetActualBuf(env, buf, bufLen, op);
235 if (!succ) {
236 return { false, nullptr, nullptr, 0, hasPos, retPos };
237 }
238
239 int64_t bufOff = static_cast<uint8_t *>(retBuf) - static_cast<uint8_t *>(buf);
240 tie(succ, retLen) = GetActualLen(env, bufLen, bufOff, op);
241 if (!succ) {
242 return { false, nullptr, nullptr, 0, hasPos, retPos };
243 }
244
245 /* To parse options - Where to begin writing */
246 if (op.HasProp("position")) {
247 int32_t position = 0;
248 tie(succ, position) = op.GetProp("position").ToInt32();
249 if (!succ || position < 0) {
250 UniError(EINVAL).ThrowErr(env, "option.position shall be positive number");
251 return { false, nullptr, nullptr, 0, hasPos, retPos };
252 }
253 hasPos = true;
254 retPos = position;
255 } else {
256 retPos = INVALID_POSITION;
257 }
258 return { true, move(bufferGuard), retBuf, retLen, hasPos, retPos };
259 }
260 } // namespace ModuleFileIO
261 } // namespace DistributedFS
262 } // namespace OHOS
263