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 "fs_randomaccessfile.h"
17
18 #include <fcntl.h>
19
20 #include "file_uri.h"
21 #include "file_utils.h"
22 #include "filemgmt_libfs.h"
23 #include "filemgmt_libhilog.h"
24 #include "fs_utils.h"
25
26 namespace OHOS {
27 namespace FileManagement {
28 namespace ModuleFileIO {
29 using namespace std;
30
DoReadRAF(void * buf,size_t len,int fd,int64_t offset)31 static int DoReadRAF(void* buf, size_t len, int fd, int64_t offset)
32 {
33 unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup)*> readReq = {
34 new (nothrow) uv_fs_t, FsUtils::FsReqCleanup };
35 if (readReq == nullptr) {
36 HILOGE("Failed to request heap memory.");
37 return ENOMEM;
38 }
39 uv_buf_t iov = uv_buf_init(static_cast<char *>(buf), len);
40 int ret = uv_fs_read(nullptr, readReq.get(), fd, &iov, 1, offset, nullptr);
41 return ret;
42 }
43
DoWriteRAF(void * buf,size_t len,int fd,int64_t offset)44 static int DoWriteRAF(void* buf, size_t len, int fd, int64_t offset)
45 {
46 unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup)*> writeReq = {
47 new (nothrow) uv_fs_t, FsUtils::FsReqCleanup };
48 if (writeReq == nullptr) {
49 HILOGE("Failed to request heap memory.");
50 return ENOMEM;
51 }
52 uv_buf_t iov = uv_buf_init(static_cast<char *>(buf), len);
53 int ret = uv_fs_write(nullptr, writeReq.get(), fd, &iov, 1, offset, nullptr);
54 return ret;
55 }
56
GetFD() const57 FsResult<int32_t> FsRandomAccessFile::GetFD() const
58 {
59 if (!rafEntity) {
60 HILOGE("Failed to get entity of RandomAccessFile");
61 return FsResult<int32_t>::Error(EIO);
62 }
63 return FsResult<int32_t>::Success(rafEntity->fd.get()->GetFD());
64 }
65
GetFPointer() const66 FsResult<int64_t> FsRandomAccessFile::GetFPointer() const
67 {
68 if (!rafEntity) {
69 HILOGE("Failed to get entity of RandomAccessFile");
70 return FsResult<int64_t>::Error(EIO);
71 }
72 return FsResult<int64_t>::Success(rafEntity->filePointer);
73 }
74
SetFilePointerSync(const int64_t & fp) const75 FsResult<void> FsRandomAccessFile::SetFilePointerSync(const int64_t &fp) const
76 {
77 if (!rafEntity) {
78 HILOGE("Failed to get entity of RandomAccessFile");
79 return FsResult<void>::Error(EIO);
80 }
81 rafEntity->filePointer = fp;
82 return FsResult<void>::Success();
83 }
84
CalculateOffset(int64_t offset,int64_t fPointer)85 static int64_t CalculateOffset(int64_t offset, int64_t fPointer)
86 {
87 if (offset < 0) {
88 HILOGD("No specified offset provided");
89 offset = fPointer;
90 } else {
91 offset += fPointer;
92 }
93 return offset;
94 }
95
ValidReadArg(ArrayBuffer & buffer,const optional<ReadOptions> & options)96 tuple<bool, void *, size_t, int64_t> ValidReadArg(ArrayBuffer &buffer, const optional<ReadOptions> &options)
97 {
98 size_t retLen = 0;
99 int64_t offset = -1;
100 bool succ = false;
101 void *buf = buffer.buf;
102 size_t bufLen = buffer.length;
103
104 if (bufLen > UINT_MAX) {
105 HILOGE("Invalid arraybuffer");
106 return { false, nullptr, retLen, offset };
107 }
108 optional<size_t> lengthOp = nullopt;
109 optional<int64_t> offsetOp = nullopt;
110 if (options.has_value()) {
111 ReadOptions op = options.value();
112 lengthOp = op.length;
113 offsetOp = op.offset;
114 }
115 tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp);
116 if (!succ) {
117 HILOGE("Failed to get actual length");
118 return { false, nullptr, retLen, offset };
119 }
120 if (offsetOp.has_value()) {
121 offset = offsetOp.value();
122 if (offset < 0) {
123 HILOGE("option.offset shall be positive number");
124 return { false, nullptr, retLen, offset };
125 }
126 }
127 return { true, buf, retLen, offset };
128 }
129
ReadSync(ArrayBuffer & buffer,const optional<ReadOptions> & options) const130 FsResult<int64_t> FsRandomAccessFile::ReadSync(ArrayBuffer &buffer, const optional<ReadOptions> &options) const
131 {
132 if (!rafEntity) {
133 HILOGE("Failed to get entity of RandomAccessFile");
134 return FsResult<int64_t>::Error(EIO);
135 }
136 auto [succ, buf, len, offset] = ValidReadArg(buffer, options);
137 if (!succ) {
138 HILOGE("Invalid buffer/options");
139 return FsResult<int64_t>::Error(EINVAL);
140 }
141 offset = CalculateOffset(offset, rafEntity->filePointer);
142 int actLen = DoReadRAF(buf, len, rafEntity->fd.get()->GetFD(), offset);
143 if (actLen < 0) {
144 HILOGE("Failed to read file for %{private}d", actLen);
145 return FsResult<int64_t>::Error(actLen);
146 }
147 rafEntity->filePointer = offset + actLen;
148 return FsResult<int64_t>::Success(static_cast<int64_t>(actLen));
149 }
150
ValidWriteArg(void * buffer,const size_t bufLen,const optional<WriteOptions> & options)151 tuple<bool, void *, size_t, int64_t> ValidWriteArg(
152 void *buffer, const size_t bufLen, const optional<WriteOptions> &options)
153 {
154 size_t retLen = 0;
155 int64_t offset = -1;
156 bool succ = false;
157
158 if (bufLen > UINT_MAX) {
159 HILOGE("The Size of buffer is too large");
160 return { false, nullptr, 0, offset };
161 }
162
163 optional<size_t> lengthOp = nullopt;
164 optional<int64_t> offsetOp = nullopt;
165 if (options.has_value()) {
166 WriteOptions op = options.value();
167 lengthOp = op.length;
168 offsetOp = op.offset;
169 }
170
171 tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp);
172 if (!succ) {
173 HILOGE("Failed to get actual length");
174 return { false, nullptr, 0, offset };
175 }
176
177 if (offsetOp.has_value()) {
178 offset = offsetOp.value();
179 if (offset < 0) {
180 HILOGE("option.offset shall be positive number");
181 return { false, nullptr, 0, offset };
182 }
183 }
184 return { true, buffer, retLen, offset };
185 }
186
WriteSync(const string & buffer,const optional<WriteOptions> & options) const187 FsResult<int64_t> FsRandomAccessFile::WriteSync(const string &buffer, const optional<WriteOptions> &options) const
188 {
189 if (!rafEntity) {
190 HILOGE("Failed to get entity of RandomAccessFile");
191 return FsResult<int64_t>::Error(EIO);
192 }
193
194 bool succ = false;
195 size_t len = 0;
196 int64_t offset = -1;
197 void *buf = nullptr;
198 size_t bufLen = static_cast<size_t>(buffer.length());
199
200 tie(succ, buf, len, offset) = ValidWriteArg(const_cast<void *>(static_cast<const void *>(buffer.c_str())),
201 bufLen, options);
202 if (!succ) {
203 HILOGE("Invalid buffer/options");
204 return FsResult<int64_t>::Error(EINVAL);
205 }
206 offset = CalculateOffset(offset, rafEntity->filePointer);
207 int writeLen = DoWriteRAF(buf, len, rafEntity->fd.get()->GetFD(), offset);
208 if (writeLen < 0) {
209 return FsResult<int64_t>::Error(writeLen);
210 }
211 rafEntity->filePointer = offset + writeLen;
212 return FsResult<int64_t>::Success(static_cast<int64_t>(writeLen));
213 }
214
WriteSync(const ArrayBuffer & buffer,const optional<WriteOptions> & options) const215 FsResult<int64_t> FsRandomAccessFile::WriteSync(const ArrayBuffer &buffer, const optional<WriteOptions> &options) const
216 {
217 if (!rafEntity) {
218 HILOGE("Failed to get entity of RandomAccessFile");
219 return FsResult<int64_t>::Error(EIO);
220 }
221
222 bool succ = false;
223 size_t len = 0;
224 int64_t offset = -1;
225 void *buf = nullptr;
226
227 tie(succ, buf, len, offset) = ValidWriteArg(buffer.buf, buffer.length, options);
228 if (!succ) {
229 HILOGE("Invalid buffer/options");
230 return FsResult<int64_t>::Error(EINVAL);
231 }
232 offset = CalculateOffset(offset, rafEntity->filePointer);
233 int writeLen = DoWriteRAF(buf, len, rafEntity->fd.get()->GetFD(), offset);
234 if (writeLen < 0) {
235 return FsResult<int64_t>::Error(writeLen);
236 }
237 rafEntity->filePointer = offset + writeLen;
238 return FsResult<int64_t>::Success(static_cast<int64_t>(writeLen));
239 }
240
CloseFd(int fd)241 static int CloseFd(int fd)
242 {
243 unique_ptr<uv_fs_t, decltype(FsUtils::FsReqCleanup)*> closeReq = { new uv_fs_t, FsUtils::FsReqCleanup };
244 if (!closeReq) {
245 HILOGE("Failed to request heap memory.");
246 return ENOMEM;
247 }
248 int ret = uv_fs_close(nullptr, closeReq.get(), fd, nullptr);
249 if (ret < 0) {
250 HILOGE("Failed to close file with ret: %{private}d", ret);
251 return ret;
252 }
253 return ERRNO_NOERR;
254 }
255
CloseSync() const256 FsResult<void> FsRandomAccessFile::CloseSync() const
257 {
258 if (!rafEntity) {
259 HILOGE("Failed to get entity of RandomAccessFile");
260 return FsResult<void>::Error(EIO);
261 }
262 auto err = CloseFd(rafEntity->fd.get()->GetFD());
263 if (err) {
264 return FsResult<void>::Error(err);
265 }
266 return FsResult<void>::Success();
267 }
268
Constructor()269 FsResult<FsRandomAccessFile *> FsRandomAccessFile::Constructor()
270 {
271 auto rafEntity = CreateUniquePtr<RandomAccessFileEntity>();
272 if (rafEntity == nullptr) {
273 HILOGE("Failed to request heap memory.");
274 return FsResult<FsRandomAccessFile *>::Error(ENOMEM);
275 }
276
277 FsRandomAccessFile *randomAccessFilePtr = new FsRandomAccessFile(move(rafEntity));
278 if (randomAccessFilePtr == nullptr) {
279 HILOGE("INNER BUG. Failed to wrap entity for obj RandomAccessFile");
280 return FsResult<FsRandomAccessFile *>::Error(EIO);
281 }
282 return FsResult<FsRandomAccessFile *>::Success(move(randomAccessFilePtr));
283 }
284
285 } // namespace ModuleFileIO
286 } // namespace FileManagement
287 } // namespace OHOS