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 #include "create_randomaccessfile_core.h"
16
17 #include <securec.h>
18
19 #include "file_entity.h"
20 #include "file_utils.h"
21 #include "filemgmt_libhilog.h"
22 #include "fs_randomaccessfile.h"
23 #include "fs_utils.h"
24 #include "randomaccessfile_entity.h"
25
26 namespace OHOS {
27 namespace FileManagement {
28 namespace ModuleFileIO {
29 using namespace std;
30
ParseStringToFileInfo(const string & path)31 static tuple<bool, FileInfo, int> ParseStringToFileInfo(const string &path)
32 {
33 OHOS::DistributedFS::FDGuard sfd;
34 auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(sfd, false);
35 if (fdg == nullptr) {
36 HILOGE("Failed to request heap memory.");
37 return { false, FileInfo { false, nullptr, nullptr }, ENOMEM};
38 }
39 size_t length = path.length() + 1;
40 auto chars = std::make_unique<char[]>(length);
41 auto ret = strncpy_s(chars.get(), length, path.c_str(), length - 1);
42 if (ret != EOK) {
43 HILOGE("Copy file path failed!");
44 return { false, FileInfo { false, nullptr, nullptr }, ENOMEM};
45 }
46 return { true, FileInfo { true, move(chars), move(fdg) }, ERRNO_NOERR};
47 }
48
ParseFdToFileInfo(const int32_t & fd)49 static tuple<bool, FileInfo, int> ParseFdToFileInfo(const int32_t &fd)
50 {
51 if (fd < 0) {
52 HILOGE("Invalid fd");
53 return { false, FileInfo { false, nullptr, nullptr }, EINVAL};
54 }
55 auto dupFd = dup(fd);
56 if (dupFd < 0) {
57 HILOGE("Failed to get valid fd, fail reason: %{public}s, fd: %{public}d", strerror(errno), fd);
58 return { false, FileInfo { false, nullptr, nullptr }, EINVAL};
59 }
60 auto fdg = CreateUniquePtr<DistributedFS::FDGuard>(dupFd, false);
61 if (fdg == nullptr) {
62 HILOGE("Failed to request heap memory.");
63 close(dupFd);
64 return { false, FileInfo { false, nullptr, nullptr }, ENOMEM};
65 }
66 return { true, FileInfo { false, nullptr, move(fdg) }, ERRNO_NOERR};
67 }
68
ValidRafOptions(const optional<RandomAccessFileOptions> & options)69 static tuple<bool, int64_t, int64_t> ValidRafOptions(const optional<RandomAccessFileOptions> &options)
70 {
71 RandomAccessFileOptions op = options.value();
72 int64_t opStart = INVALID_POS;
73 int64_t opEnd = INVALID_POS;
74
75 optional<int64_t> startOp = op.start;
76 optional<int64_t> endOp = op.end;
77
78 if (startOp.has_value()) {
79 int64_t start = 0;
80 start = startOp.value();
81 if (start < 0) {
82 HILOGE("Invalid option.start, positive integer is desired");
83 return {false, opStart, opEnd};
84 }
85 opStart = start;
86 }
87 if (endOp.has_value()) {
88 int64_t end = 0;
89 end = endOp.value();
90 if (end < 0) {
91 HILOGE("Invalid option.end, positive integer is desired");
92 return {false, opStart, opEnd};
93 }
94 opEnd = end;
95 }
96 return {true, opStart, opEnd};
97 }
98
ValidAndConvertFlags(const optional<int32_t> & mode,const optional<RandomAccessFileOptions> & options,FileInfo & fileInfo)99 static tuple<bool, uint32_t, int64_t, int64_t> ValidAndConvertFlags(const optional<int32_t> &mode,
100 const optional<RandomAccessFileOptions> &options, FileInfo &fileInfo)
101 {
102 uint32_t flags = O_RDONLY;
103 int64_t start = INVALID_POS;
104 int64_t end = INVALID_POS;
105 if (fileInfo.isPath && mode.has_value()) {
106 auto modeValue = mode.value();
107 if (modeValue < 0) {
108 HILOGE("Invalid flags");
109 return {false, flags, start, end};
110 }
111 flags = FsUtils::ConvertFlags(static_cast<uint32_t>(modeValue));
112 }
113
114 if (options.has_value()) {
115 auto [succOpt, start, end] = ValidRafOptions(options);
116 if (!succOpt) {
117 HILOGE("Invalid RandomAccessFile options");
118 return {false, flags, start, end};
119 }
120 }
121
122 return {true, flags, start, end};
123 }
124
InstantiateRandomAccessFile(unique_ptr<DistributedFS::FDGuard> fdg,int64_t fp,int64_t start=INVALID_POS,int64_t end=INVALID_POS)125 static FsResult<FsRandomAccessFile *> InstantiateRandomAccessFile(unique_ptr<DistributedFS::FDGuard> fdg,
126 int64_t fp,
127 int64_t start = INVALID_POS,
128 int64_t end = INVALID_POS)
129 {
130 FsResult<FsRandomAccessFile *> result = FsRandomAccessFile::Constructor();
131 if (!result.IsSuccess()) {
132 HILOGE("Failed to instantiate class");
133 return FsResult<FsRandomAccessFile *>::Error(EIO);
134 }
135
136 const FsRandomAccessFile *objRAF = result.GetData().value();
137 if (!objRAF) {
138 HILOGE("Cannot instantiate randomaccessfile");
139 return FsResult<FsRandomAccessFile *>::Error(EIO);
140 }
141
142 auto *rafEntity = objRAF->GetRAFEntity();
143 if (!rafEntity) {
144 HILOGE("Cannot instantiate randomaccessfile because of void entity");
145 return FsResult<FsRandomAccessFile *>::Error(EIO);
146 }
147 rafEntity->fd.swap(fdg);
148 rafEntity->filePointer = fp;
149 rafEntity->start = start;
150 rafEntity->end = end;
151 return result;
152 }
153
DoCreateRandomAccessFile(const string & path,const optional<int32_t> & mode,const optional<RandomAccessFileOptions> & options)154 FsResult<FsRandomAccessFile *> CreateRandomAccessFileCore::DoCreateRandomAccessFile(
155 const string &path, const optional<int32_t> &mode, const optional<RandomAccessFileOptions> &options)
156 {
157 auto [succ, fileInfo, err] = ParseStringToFileInfo(path);
158 if (!succ) {
159 return FsResult<FsRandomAccessFile *>::Error(err);
160 }
161
162 auto [succFlags, flags, ignoreStart, ignoreEnd] = ValidAndConvertFlags(mode, options, fileInfo);
163 if (!succFlags) {
164 return FsResult<FsRandomAccessFile *>::Error(EINVAL);
165 }
166
167 unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup)*> openReq = { new uv_fs_t, FsUtils::FsReqCleanup };
168 if (!openReq) {
169 HILOGE("Failed to request heap memory.");
170 return FsResult<FsRandomAccessFile *>::Error(ENOMEM);
171 }
172
173 int ret = uv_fs_open(nullptr, openReq.get(), fileInfo.path.get(), flags, S_IRUSR |
174 S_IWUSR | S_IRGRP | S_IWGRP, NULL);
175 if (ret < 0) {
176 return FsResult<FsRandomAccessFile *>::Error(ret);
177 }
178
179 fileInfo.fdg->SetFD(openReq.get()->result, false);
180
181 if (options.has_value()) {
182 auto [succ, start, end] = ValidRafOptions(options);
183 if (succ) {
184 return InstantiateRandomAccessFile(move(fileInfo.fdg), 0, start, end);
185 }
186 }
187 return InstantiateRandomAccessFile(move(fileInfo.fdg), 0);
188 }
189
DoCreateRandomAccessFile(const int32_t & fd,const optional<RandomAccessFileOptions> & options)190 FsResult<FsRandomAccessFile *> CreateRandomAccessFileCore::DoCreateRandomAccessFile(
191 const int32_t &fd, const optional<RandomAccessFileOptions> &options)
192 {
193 auto [succ, fileInfo, err] = ParseFdToFileInfo(fd);
194 if (!succ) {
195 return FsResult<FsRandomAccessFile *>::Error(err);
196 }
197 if (options.has_value()) {
198 auto [succ, start, end] = ValidRafOptions(options);
199 if (succ) {
200 return InstantiateRandomAccessFile(move(fileInfo.fdg), 0, start, end);
201 }
202 }
203 return InstantiateRandomAccessFile(move(fileInfo.fdg), 0);
204 }
205
206 } // namespace ModuleFileIO
207 } // namespace FileManagement
208 } // namespace OHOS