• 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 "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