• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 "randomaccessfile_ani.h"
17 
18 #include "ani_helper.h"
19 #include "ani_signature.h"
20 #include "error_handler.h"
21 #include "filemgmt_libhilog.h"
22 #include "fs_randomaccessfile.h"
23 #include "type_converter.h"
24 
25 namespace OHOS {
26 namespace FileManagement {
27 namespace ModuleFileIO {
28 namespace ANI {
29 using namespace std;
30 using namespace OHOS::FileManagement::ModuleFileIO;
31 using namespace OHOS::FileManagement::ModuleFileIO::ANI::AniSignature;
32 
33 const int BUF_SIZE = 1024;
34 const string READ_STREAM_CLASS = "ReadStream";
35 const string WRITE_STREAM_CLASS = "WriteStream";
36 const string OFFSET = "offset";
37 const string LENGTH = "length";
38 
Unwrap(ani_env * env,ani_object object)39 static FsRandomAccessFile *Unwrap(ani_env *env, ani_object object)
40 {
41     ani_long nativePtr;
42     auto ret = env->Object_GetFieldByName_Long(object, "nativePtr", &nativePtr);
43     if (ret != ANI_OK) {
44         HILOGE("Unwrap FsRandomAccessFile err: %{public}d", ret);
45         return nullptr;
46     }
47     uintptr_t ptrValue = static_cast<uintptr_t>(nativePtr);
48     FsRandomAccessFile *rafFile = reinterpret_cast<FsRandomAccessFile *>(ptrValue);
49     return rafFile;
50 }
51 
ToReadOptions(ani_env * env,ani_object obj)52 static tuple<bool, optional<ReadOptions>> ToReadOptions(ani_env *env, ani_object obj)
53 {
54     ReadOptions options;
55     ani_boolean isUndefined;
56     env->Reference_IsUndefined(obj, &isUndefined);
57     if (isUndefined) {
58         return { true, nullopt };
59     }
60 
61     auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, OFFSET);
62     if (!succOffset) {
63         HILOGE("Illegal option.offset parameter");
64         return { false, nullopt };
65     }
66     options.offset = offset;
67 
68     auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, LENGTH);
69     if (!succLength) {
70         HILOGE("Illegal option.length parameter");
71         return { false, nullopt };
72     }
73     options.length = length;
74     return { true, make_optional<ReadOptions>(move(options)) };
75 }
76 
ToWriteOptions(ani_env * env,ani_object obj)77 static tuple<bool, optional<WriteOptions>> ToWriteOptions(ani_env *env, ani_object obj)
78 {
79     WriteOptions options;
80     ani_boolean isUndefined;
81     env->Reference_IsUndefined(obj, &isUndefined);
82     if (isUndefined) {
83         return { true, nullopt };
84     }
85 
86     auto [succOffset, offset] = AniHelper::ParseInt64Option(env, obj, OFFSET);
87     if (!succOffset) {
88         HILOGE("Illegal option.offset parameter");
89         return { false, nullopt };
90     }
91     options.offset = offset;
92 
93     auto [succLength, length] = AniHelper::ParseInt64Option(env, obj, LENGTH);
94     if (!succLength) {
95         HILOGE("Illegal option.length parameter");
96         return { false, nullopt };
97     }
98     options.length = length;
99 
100     auto [succEncoding, encoding] = AniHelper::ParseEncoding(env, obj);
101     if (!succEncoding) {
102         HILOGE("Illegal option.encoding parameter");
103         return { false, nullopt };
104     }
105     options.encoding = encoding;
106     return { true, make_optional<WriteOptions>(move(options)) };
107 }
108 
ParseStringBuffer(ani_env * env,const ani_object & buf)109 static tuple<bool, ani_string> ParseStringBuffer(ani_env *env, const ani_object &buf)
110 {
111     ani_class cls;
112     auto classDesc = BuiltInTypes::String::classDesc.c_str();
113     env->FindClass(classDesc, &cls);
114 
115     ani_boolean isString;
116     env->Object_InstanceOf(buf, cls, &isString);
117     if (!isString) {
118         return { false, {} };
119     }
120     auto result = static_cast<ani_string>(buf);
121     return { true, move(result) };
122 }
123 
ParseArrayBuffer(ani_env * env,const ani_object & buf)124 static tuple<bool, ani_arraybuffer> ParseArrayBuffer(ani_env *env, const ani_object &buf)
125 {
126     ani_class cls;
127     auto classDesc = BuiltInTypes::ArrayBuffer::classDesc.c_str();
128     env->FindClass(classDesc, &cls);
129 
130     ani_boolean isArrayBuffer;
131     env->Object_InstanceOf(buf, cls, &isArrayBuffer);
132     if (!isArrayBuffer) {
133         return { false, {} };
134     }
135     auto result = static_cast<ani_arraybuffer>(buf);
136     return { true, move(result) };
137 }
138 
SetFilePointer(ani_env * env,ani_object object,ani_double fp)139 void RandomAccessFileAni::SetFilePointer(ani_env *env, [[maybe_unused]] ani_object object, ani_double fp)
140 {
141     auto rafFile = Unwrap(env, object);
142     if (rafFile == nullptr) {
143         HILOGE("Cannot unwrap rafFile!");
144         ErrorHandler::Throw(env, UNKNOWN_ERR);
145         return;
146     }
147     auto ret = rafFile->SetFilePointerSync(static_cast<int64_t>(fp));
148     if (!ret.IsSuccess()) {
149         HILOGE("SetFilePointerSync failed!");
150         const auto &err = ret.GetError();
151         ErrorHandler::Throw(env, err);
152         return;
153     }
154 }
155 
Close(ani_env * env,ani_object object)156 void RandomAccessFileAni::Close(ani_env *env, [[maybe_unused]] ani_object object)
157 {
158     auto rafFile = Unwrap(env, object);
159     if (rafFile == nullptr) {
160         HILOGE("Cannot unwrap rafFile!");
161         ErrorHandler::Throw(env, UNKNOWN_ERR);
162         return;
163     }
164     auto ret = rafFile->CloseSync();
165     if (!ret.IsSuccess()) {
166         HILOGE("close rafFile failed!");
167         const auto &err = ret.GetError();
168         ErrorHandler::Throw(env, err);
169         return;
170     }
171 }
172 
WriteSync(ani_env * env,ani_object object,ani_object buf,ani_object options)173 ani_double RandomAccessFileAni::WriteSync(
174     ani_env *env, [[maybe_unused]] ani_object object, ani_object buf, ani_object options)
175 {
176     auto rafFile = Unwrap(env, object);
177     if (rafFile == nullptr) {
178         HILOGE("Cannot unwrap rafFile!");
179         ErrorHandler::Throw(env, UNKNOWN_ERR);
180         return -1;
181     }
182 
183     auto [succOp, op] = ToWriteOptions(env, options);
184     if (!succOp) {
185         HILOGE("Failed to resolve options!");
186         ErrorHandler::Throw(env, EINVAL);
187         return -1;
188     }
189 
190     auto [isString, stringBuffer] = ParseStringBuffer(env, buf);
191     if (isString) {
192         auto [succBuf, buffer] = TypeConverter::ToUTF8String(env, stringBuffer);
193         if (!succBuf) {
194             HILOGE("Failed to resolve stringBuffer!");
195             ErrorHandler::Throw(env, EINVAL);
196             return -1;
197         }
198         auto ret = rafFile->WriteSync(buffer, op);
199         if (!ret.IsSuccess()) {
200             HILOGE("write buffer failed!");
201             ErrorHandler::Throw(env, ret.GetError());
202             return -1;
203         }
204         return static_cast<double>(ret.GetData().value());
205     }
206 
207     auto [isArrayBuffer, arrayBuffer] = ParseArrayBuffer(env, buf);
208     if (isArrayBuffer) {
209         auto [succBuf, buffer] = TypeConverter::ToArrayBuffer(env, arrayBuffer);
210         if (!succBuf) {
211             HILOGE("Failed to resolve arrayBuffer!");
212             ErrorHandler::Throw(env, EINVAL);
213             return -1;
214         }
215         auto ret = rafFile->WriteSync(buffer, op);
216         if (!ret.IsSuccess()) {
217             HILOGE("write buffer failed!");
218             ErrorHandler::Throw(env, ret.GetError());
219             return -1;
220         }
221         return static_cast<double>(ret.GetData().value());
222     }
223     HILOGE("Unsupported buffer type!");
224     ErrorHandler::Throw(env, EINVAL);
225     return -1;
226 }
227 
ReadSync(ani_env * env,ani_object object,ani_arraybuffer buf,ani_object options)228 ani_double RandomAccessFileAni::ReadSync(
229     ani_env *env, [[maybe_unused]] ani_object object, ani_arraybuffer buf, ani_object options)
230 {
231     auto rafFile = Unwrap(env, object);
232     if (rafFile == nullptr) {
233         HILOGE("Cannot unwrap rafFile!");
234         ErrorHandler::Throw(env, UNKNOWN_ERR);
235         return -1;
236     }
237 
238     auto [succBuf, arrayBuffer] = TypeConverter::ToArrayBuffer(env, buf);
239     if (!succBuf) {
240         HILOGE("Failed to resolve arrayBuffer!");
241         ErrorHandler::Throw(env, EINVAL);
242         return -1;
243     }
244 
245     auto [succOp, op] = ToReadOptions(env, options);
246     if (!succOp) {
247         HILOGE("Failed to resolve options!");
248         ErrorHandler::Throw(env, EINVAL);
249         return -1;
250     }
251 
252     auto ret = rafFile->ReadSync(arrayBuffer, op);
253     if (!ret.IsSuccess()) {
254         HILOGE("Read file content failed!");
255         const auto &err = ret.GetError();
256         ErrorHandler::Throw(env, err);
257         return -1;
258     }
259     return static_cast<double>(ret.GetData().value());
260 }
261 
GetFilePath(ani_env * env,const int fd)262 static ani_string GetFilePath(ani_env *env, const int fd)
263 {
264     auto dstFd = dup(fd);
265     if (dstFd < 0) {
266         HILOGE("Failed to get valid fd, fail reason: %{public}s, fd: %{public}d", strerror(errno), fd);
267         return nullptr;
268     }
269 
270     string path = "/proc/self/fd/" + to_string(dstFd);
271     auto buf = CreateUniquePtr<char[]>(BUF_SIZE);
272     int readLinkRes = readlink(path.c_str(), buf.get(), BUF_SIZE);
273     if (readLinkRes < 0) {
274         close(dstFd);
275         return nullptr;
276     }
277 
278     close(dstFd);
279     auto [succ, filePath] = TypeConverter::ToAniString(env, string(buf.get()));
280     if (!succ) {
281         return nullptr;
282     }
283     return move(filePath);
284 }
285 
CreateReadStreamOptions(ani_env * env,int64_t start,int64_t end)286 static ani_object CreateReadStreamOptions(ani_env *env, int64_t start, int64_t end)
287 {
288     static const char *className = FS::ReadStreamOptionsInner::classDesc.c_str();
289     ani_class cls;
290     if (ANI_OK != env->FindClass(className, &cls)) {
291         HILOGE("Cannot find class %{public}s", className);
292         return nullptr;
293     }
294     ani_method ctor;
295     if (ANI_OK != env->Class_FindMethod(cls, FS::ReadStreamOptionsInner::ctorDesc.c_str(),
296         FS::ReadStreamOptionsInner::ctorSig.c_str(), &ctor)) {
297         HILOGE("Cannot find constructor method for class %{public}s", className);
298         return nullptr;
299     }
300     ani_object obj;
301     if (ANI_OK != env->Object_New(cls, ctor, &obj)) {
302         HILOGE("New %{public}s obj Failed", className);
303         return nullptr;
304     }
305 
306     ani_field startField = nullptr;
307     ani_field endField = nullptr;
308     if (ANI_OK != env->Class_FindField(cls, "start", &startField)) {
309         HILOGE("Cannot find start in class %{public}s", className);
310         return nullptr;
311     }
312     if (ANI_OK != env->Class_FindField(cls, "end", &endField)) {
313         HILOGE("Cannot find end in class %{public}s", className);
314         return nullptr;
315     }
316 
317     if (start >= 0) {
318         env->Object_SetField_Int(obj, startField, start);
319     }
320     if (end >= 0) {
321         env->Object_SetField_Int(obj, endField, end);
322     }
323     if (obj == nullptr) {
324         HILOGE("CreateReadStreamOptions is nullptr");
325     }
326 
327     return move(obj);
328 }
329 
CreateWriteStreamOptions(ani_env * env,int64_t start,int flags)330 static ani_object CreateWriteStreamOptions(ani_env *env, int64_t start, int flags)
331 {
332     static const char *className = FS::WriteStreamOptionsInner::classDesc.c_str();
333     ani_class cls;
334     if (ANI_OK != env->FindClass(className, &cls)) {
335         HILOGE("Cannot find class %{public}s", className);
336         return nullptr;
337     }
338     ani_method ctor;
339     if (ANI_OK != env->Class_FindMethod(cls, FS::WriteStreamOptionsInner::ctorDesc.c_str(),
340         FS::WriteStreamOptionsInner::ctorSig.c_str(), &ctor)) {
341         HILOGE("Cannot find constructor method for class %{public}s", className);
342         return nullptr;
343     }
344     ani_object obj;
345     if (ANI_OK != env->Object_New(cls, ctor, &obj)) {
346         HILOGE("New %{public}s obj Failed", className);
347         return nullptr;
348     }
349 
350     ani_field modeField = nullptr;
351     ani_field startField = nullptr;
352     if (ANI_OK != env->Class_FindField(cls, "mode", &modeField)) {
353         HILOGE("Cannot find mode in class %{public}s", className);
354         return nullptr;
355     }
356     if (ANI_OK != env->Class_FindField(cls, "start", &startField)) {
357         HILOGE("Cannot find start in class %{public}s", className);
358         return nullptr;
359     }
360 
361     env->Object_SetField_Int(obj, modeField, flags);
362     if (start >= 0) {
363         env->Object_SetField_Int(obj, startField, start);
364     }
365 
366     return move(obj);
367 }
368 
CreateReadStream(ani_env * env,ani_string filePath,ani_object options)369 static ani_object CreateReadStream(ani_env *env, ani_string filePath, ani_object options)
370 {
371     static const char *className = "L@ohos/file/fs/fileIo/ReadStream;";
372     ani_class cls;
373     if (ANI_OK != env->FindClass(className, &cls)) {
374         HILOGE("Cannot find class %{public}s", className);
375         return nullptr;
376     }
377     ani_method ctor;
378     if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", "Lstd/core/String;L@ohos/file/fs/ReadStreamOptions;:V", &ctor)) {
379         HILOGE("Cannot find constructor method for class %{public}s", className);
380         return nullptr;
381     }
382     ani_object obj;
383     if (ANI_OK != env->Object_New(cls, ctor, &obj, filePath, options)) {
384         HILOGE("New %{public}s obj Failed", className);
385         return nullptr;
386     }
387 
388     return move(obj);
389 }
390 
CreateWriteStream(ani_env * env,ani_string filePath,ani_object options)391 static ani_object CreateWriteStream(ani_env *env, ani_string filePath, ani_object options)
392 {
393     static const char *className = "L@ohos/file/fs/fileIo/WriteStream;";
394     ani_class cls;
395     if (ANI_OK != env->FindClass(className, &cls)) {
396         HILOGE("Cannot find class %{public}s", className);
397         return nullptr;
398     }
399     ani_method ctor;
400     if (ANI_OK !=
401         env->Class_FindMethod(cls, "<ctor>", "Lstd/core/String;L@ohos/file/fs/WriteStreamOptions;:V", &ctor)) {
402         HILOGE("Cannot find constructor method for class %{public}s", className);
403         return nullptr;
404     }
405     ani_object obj;
406     if (ANI_OK != env->Object_New(cls, ctor, &obj, filePath, options)) {
407         HILOGE("New %{public}s obj Failed", className);
408         return nullptr;
409     }
410 
411     return move(obj);
412 }
413 
CreateStream(ani_env * env,const string & streamName,RandomAccessFileEntity * rafEntity,int flags)414 static ani_object CreateStream(ani_env *env, const string &streamName, RandomAccessFileEntity *rafEntity, int flags)
415 {
416     ani_string filePath = GetFilePath(env, rafEntity->fd.get()->GetFD());
417     if (!filePath) {
418         HILOGE("Get file path failed, errno=%{public}d", errno);
419         ErrorHandler::Throw(env, errno);
420         return nullptr;
421     }
422 
423     if (streamName == READ_STREAM_CLASS) {
424         ani_object obj = CreateReadStreamOptions(env, rafEntity->start, rafEntity->end);
425         return CreateReadStream(env, filePath, obj);
426     }
427     if (streamName == WRITE_STREAM_CLASS) {
428         ani_object obj = CreateWriteStreamOptions(env, rafEntity->start, flags);
429         return CreateWriteStream(env, filePath, obj);
430     }
431 
432     return nullptr;
433 }
434 
GetReadStream(ani_env * env,ani_object object)435 ani_object RandomAccessFileAni::GetReadStream(ani_env *env, [[maybe_unused]] ani_object object)
436 {
437     auto rafFile = Unwrap(env, object);
438     if (rafFile == nullptr) {
439         HILOGE("Cannot unwrap rafFile!");
440         ErrorHandler::Throw(env, UNKNOWN_ERR);
441         return nullptr;
442     }
443 
444     auto entity = rafFile->GetRAFEntity();
445     if (!entity) {
446         HILOGE("Get RandomAccessFileEntity failed!");
447         ErrorHandler::Throw(env, EIO);
448         return nullptr;
449     }
450 
451     int flags = fcntl(entity->fd.get()->GetFD(), F_GETFL);
452     unsigned int uflags = static_cast<unsigned int>(flags);
453     if (((uflags & O_ACCMODE) != O_RDONLY) && ((uflags & O_ACCMODE) != O_RDWR)) {
454         HILOGE("Failed to check Permission");
455         ErrorHandler::Throw(env, EACCES);
456         return nullptr;
457     }
458 
459     return CreateStream(env, READ_STREAM_CLASS, entity, flags);
460 }
461 
GetWriteStream(ani_env * env,ani_object object)462 ani_object RandomAccessFileAni::GetWriteStream(ani_env *env, [[maybe_unused]] ani_object object)
463 {
464     auto rafFile = Unwrap(env, object);
465     if (rafFile == nullptr) {
466         HILOGE("Cannot unwrap rafFile!");
467         ErrorHandler::Throw(env, UNKNOWN_ERR);
468         return nullptr;
469     }
470 
471     auto entity = rafFile->GetRAFEntity();
472     if (!entity) {
473         HILOGE("Get RandomAccessFileEntity failed!");
474         ErrorHandler::Throw(env, EIO);
475         return nullptr;
476     }
477 
478     int flags = fcntl(entity->fd.get()->GetFD(), F_GETFL);
479     unsigned int uflags = static_cast<unsigned int>(flags);
480     if (((uflags & O_ACCMODE) != O_WRONLY) && ((uflags & O_ACCMODE) != O_RDWR)) {
481         HILOGE("Failed to check Permission");
482         ErrorHandler::Throw(env, EACCES);
483         return nullptr;
484     }
485 
486     return CreateStream(env, WRITE_STREAM_CLASS, entity, flags);
487 }
488 
489 } // namespace ANI
490 } // namespace ModuleFileIO
491 } // namespace FileManagement
492 } // namespace OHOS