• 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_stream.h"
17 
18 #include <cstring>
19 #include <tuple>
20 
21 #include "file_utils.h"
22 #include "filemgmt_libhilog.h"
23 
24 namespace OHOS {
25 namespace FileManagement {
26 namespace ModuleFileIO {
27 using namespace std;
28 const string UTF_8 = "utf-8";
29 
GetFilePtr()30 std::shared_ptr<FILE> FsStream::GetFilePtr()
31 {
32     std::lock_guard<std::mutex> lock(mtx);
33     if (!streamEntity) {
34         return nullptr;
35     }
36     return streamEntity->fp;
37 }
38 
ValidWriteArg(const size_t bufLen,const optional<WriteOptions> & options)39 static tuple<bool, size_t, int64_t> ValidWriteArg(const size_t bufLen, const optional<WriteOptions> &options)
40 {
41     size_t retLen = 0;
42     int64_t offset = -1;
43     bool succ = false;
44 
45     if (bufLen > UINT_MAX) {
46         HILOGE("The Size of buffer is too large");
47         return { false, 0, offset };
48     }
49 
50     optional<int64_t> lengthOp = nullopt;
51     optional<int64_t> offsetOp = nullopt;
52     optional<string> encodingOp = nullopt;
53     if (options.has_value()) {
54         WriteOptions op = options.value();
55         lengthOp = op.length;
56         offsetOp = op.offset;
57         encodingOp = op.encoding;
58     }
59 
60     tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp);
61     if (!succ) {
62         HILOGE("Failed to get actual length");
63         return { false, 0, offset };
64     }
65 
66     if (offsetOp.has_value()) {
67         offset = offsetOp.value();
68         if (offset < 0) {
69             HILOGE("option.offset shall be positive number");
70             return { false, 0, offset };
71         }
72     }
73 
74     if (encodingOp.has_value()) {
75         if (encodingOp.value() != UTF_8) {
76             HILOGE("option.encoding shall be utf-8");
77             return { false, 0, offset };
78         }
79     }
80     return { true, retLen, offset };
81 }
82 
ValidReadArg(const size_t bufLen,const optional<ReadOptions> & options)83 static tuple<bool, size_t, int64_t> ValidReadArg(const size_t bufLen, const optional<ReadOptions> &options)
84 {
85     size_t retLen = 0;
86     int64_t offset = -1;
87     bool succ = false;
88 
89     if (bufLen > UINT_MAX) {
90         HILOGE("The Size of buffer is too large");
91         return { false, 0, offset };
92     }
93 
94     optional<int64_t> lengthOp = nullopt;
95     optional<int64_t> offsetOp = nullopt;
96     if (options.has_value()) {
97         ReadOptions op = options.value();
98         lengthOp = op.length;
99         offsetOp = op.offset;
100     }
101 
102     tie(succ, retLen) = FsUtils::GetActualLen(bufLen, 0, lengthOp);
103     if (!succ) {
104         HILOGE("Failed to get actual length");
105         return { false, 0, offset };
106     }
107 
108     if (offsetOp.has_value()) {
109         offset = offsetOp.value();
110         if (offset < 0) {
111             HILOGE("option.offset shall be positive number");
112             return { false, 0, offset };
113         }
114     }
115     return { true, retLen, offset };
116 }
117 
Write(const ArrayBuffer & buf,const optional<WriteOptions> & options)118 FsResult<size_t> FsStream::Write(const ArrayBuffer &buf, const optional<WriteOptions> &options)
119 {
120     auto fp = GetFilePtr();
121     if (!fp) {
122         HILOGE("Failed to get file ptr");
123         return FsResult<size_t>::Error(EIO);
124     }
125 
126     auto [succ, retLen, offset] = ValidWriteArg(buf.length, options);
127     if (!succ) {
128         HILOGE("Invalid options");
129         return FsResult<size_t>::Error(EINVAL);
130     }
131 
132     if (offset >= 0) {
133         int ret = fseek(fp.get(), static_cast<long>(offset), SEEK_SET);
134         if (ret < 0) {
135             HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
136             return FsResult<size_t>::Error(errno);
137         }
138     }
139 
140     size_t writeLen = fwrite(buf.buf, 1, retLen, fp.get());
141     if ((writeLen == 0) && (writeLen != retLen)) {
142         HILOGE("Failed to fwrite stream");
143         return FsResult<size_t>::Error(EIO);
144     }
145     return FsResult<size_t>::Success(writeLen);
146 }
147 
Write(const string & buf,const optional<WriteOptions> & options)148 FsResult<size_t> FsStream::Write(const string &buf, const optional<WriteOptions> &options)
149 {
150     auto fp = GetFilePtr();
151     if (!fp) {
152         HILOGE("Failed to get file ptr");
153         return FsResult<size_t>::Error(EIO);
154     }
155 
156     size_t bufLen = static_cast<size_t>(buf.length());
157 
158     auto [succ, retLen, offset] = ValidWriteArg(bufLen, options);
159     if (!succ) {
160         HILOGE("Invalid options");
161         return FsResult<size_t>::Error(EINVAL);
162     }
163 
164     if (offset >= 0) {
165         int ret = fseek(fp.get(), static_cast<long>(offset), SEEK_SET);
166         if (ret < 0) {
167             HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
168             return FsResult<size_t>::Error(errno);
169         }
170     }
171 
172     size_t writeLen = fwrite(buf.c_str(), 1, retLen, fp.get());
173     if ((writeLen == 0) && (writeLen != retLen)) {
174         HILOGE("Failed to fwrite stream");
175         return FsResult<size_t>::Error(EIO);
176     }
177     return FsResult<size_t>::Success(writeLen);
178 }
179 
Read(ArrayBuffer & buf,const optional<ReadOptions> & options)180 FsResult<size_t> FsStream::Read(ArrayBuffer &buf, const optional<ReadOptions> &options)
181 {
182     auto fp = GetFilePtr();
183     if (!fp) {
184         HILOGE("Failed to get file ptr");
185         return FsResult<size_t>::Error(EIO);
186     }
187 
188     auto [succ, retLen, offset] = ValidReadArg(buf.length, options);
189     if (!succ) {
190         HILOGE("Invalid options");
191         return FsResult<size_t>::Error(EINVAL);
192     }
193 
194     if (offset >= 0) {
195         int ret = fseek(fp.get(), static_cast<long>(offset), SEEK_SET);
196         if (ret < 0) {
197             HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
198             return FsResult<size_t>::Error(errno);
199         }
200     }
201 
202     size_t actLen = fread(buf.buf, 1, retLen, fp.get());
203     if ((actLen != static_cast<size_t>(retLen) && !feof(fp.get())) || ferror(fp.get())) {
204         HILOGE("Invalid buffer size or pointer, actlen: %{public}zu", actLen);
205         return FsResult<size_t>::Error(EIO);
206     }
207 
208     return FsResult<size_t>::Success(actLen);
209 }
210 
Flush()211 FsResult<void> FsStream::Flush()
212 {
213     auto fp = GetFilePtr();
214     if (fp == nullptr) {
215         HILOGE("Failed to get entity of Stream");
216         return FsResult<void>::Error(EIO);
217     }
218 
219     int ret = fflush(fp.get());
220     if (ret < 0) {
221         HILOGE("Failed to fflush file in the stream, ret: %{public}d", ret);
222         return FsResult<void>::Error(errno);
223     }
224 
225     return FsResult<void>::Success();
226 }
227 
Close()228 FsResult<void> FsStream::Close()
229 {
230     if (!streamEntity) {
231         HILOGE("Failed to get entity of Stream, may closed twice");
232         return FsResult<void>::Error(EIO);
233     }
234     streamEntity = nullptr;
235     return FsResult<void>::Success();
236 }
237 
Seek(const int64_t & offset,const optional<int32_t> & typeOpt)238 FsResult<int64_t> FsStream::Seek(const int64_t &offset, const optional<int32_t> &typeOpt)
239 {
240     int whence = SEEK_SET;
241 
242     auto fp = GetFilePtr();
243     if (fp == nullptr) {
244         HILOGE("Failed to get file ptr");
245         return FsResult<int64_t>::Error(ENOENT);
246     }
247 
248     if (typeOpt.has_value()) {
249         int pos = typeOpt.value();
250         if (pos < SEEK_SET || pos > SEEK_END) {
251             HILOGE("Invalid whence");
252             return FsResult<int64_t>::Error(EINVAL);
253         }
254         whence = pos;
255     }
256 
257     if (offset >= 0) {
258         int ret = fseek(fp.get(), static_cast<long>(offset), whence);
259         if (ret < 0) {
260             HILOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
261             return FsResult<int64_t>::Error(errno);
262         }
263     }
264 
265     int64_t res = ftell(fp.get());
266     if (res < 0) {
267         HILOGE("Failed to tell, error:%{public}d", errno);
268         return FsResult<int64_t>::Error(errno);
269     }
270 
271     return FsResult<int64_t>::Success(res);
272 }
273 
Constructor()274 FsResult<FsStream *> FsStream::Constructor()
275 {
276     auto rafEntity = CreateUniquePtr<StreamEntity>();
277     if (rafEntity == nullptr) {
278         HILOGE("Failed to request heap memory.");
279         return FsResult<FsStream *>::Error(ENOMEM);
280     }
281     FsStream *fsStreamPtr = new FsStream(move(rafEntity));
282 
283     if (fsStreamPtr == nullptr) {
284         HILOGE("Failed to create FsStream object on heap.");
285         return FsResult<FsStream *>::Error(ENOMEM);
286     }
287 
288     return FsResult<FsStream *>::Success(move(fsStreamPtr));
289 }
290 
291 } // namespace ModuleFileIO
292 } // namespace FileManagement
293 } // namespace OHOS
294