1 /*
2 * Copyright (c) 2024 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 "stream_impl.h"
17 #include "securec.h"
18
19 #include <memory>
20 #include <tuple>
21
22 using namespace std;
23
24 namespace OHOS {
25 namespace CJSystemapi {
26 namespace FileFs {
27
DecodeString(const std::string & buffer,const std::string & encode)28 std::tuple<int, std::unique_ptr<char[]>, size_t> DecodeString(const std::string& buffer, const std::string& encode)
29 {
30 std::unique_ptr<char[]> buf = std::make_unique<char[]>(buffer.length() + 1);
31 if (!buf) {
32 return { ENOMEM, nullptr, 0};
33 }
34
35 for (size_t i = 0; i < buffer.length(); i++) {
36 buf[i] = buffer[i];
37 }
38
39 if (encode == "utf-8") {
40 return make_tuple(SUCCESS_CODE, move(buf), buffer.length());
41 } else {
42 return { EINVAL, nullptr, 0};
43 }
44 }
45
GetActualLen(size_t bufLen,size_t bufOff,int64_t offset,int64_t length)46 std::tuple<int, size_t> GetActualLen(size_t bufLen, size_t bufOff, int64_t offset, int64_t length)
47 {
48 size_t retLen = bufLen - bufOff;
49
50 if (length == 0) {
51 return { SUCCESS_CODE, retLen };
52 }
53
54 if (length < 0 || static_cast<size_t>(length) > retLen) {
55 LOGE("Invalid option length, length: %{public}" PRId64 ", retLen: %{public}zu", length, retLen);
56 return { EINVAL, 0 };
57 }
58 retLen = static_cast<size_t>(length);
59 return { SUCCESS_CODE, retLen };
60 }
61
GetWriteArg(const std::string & buffer,int64_t length,int64_t offset,const std::string & encode)62 tuple<int, unique_ptr<char[]>, void *, size_t, int64_t> GetWriteArg(const std::string& buffer, int64_t length,
63 int64_t offset, const std::string& encode)
64 {
65 void *buf = nullptr;
66
67 auto [decodeState, bufferGuard, bufLen] = DecodeString(buffer, encode);
68 if (decodeState != SUCCESS_CODE) {
69 LOGE("Illegal write buffer or encoding");
70 return { decodeState, nullptr, nullptr, 0, 0 };
71 } else {
72 buf = bufferGuard.get();
73 }
74 if (bufLen > UINT_MAX) {
75 LOGE("The Size of buffer is too large");
76 return { false, nullptr, nullptr, 0, 0 };
77 }
78
79 auto [lenState, retLen] = GetActualLen(bufLen, 0, offset, length);
80 if (lenState != SUCCESS_CODE) {
81 LOGE("Failed to get actual length");
82 return { lenState, nullptr, nullptr, 0, 0 };
83 }
84
85 if (offset < 0) {
86 LOGE("option.offset shall be positive number");
87 return { EINVAL, nullptr, nullptr, 0, 0 };
88 }
89
90 return { SUCCESS_CODE, move(bufferGuard), buf, retLen, offset };
91 }
92
GetReadArg(size_t bufLen,int64_t length,int64_t offset)93 tuple<int, std::unique_ptr<char[]>, size_t, int64_t> GetReadArg(size_t bufLen, int64_t length, int64_t offset)
94 {
95 std::unique_ptr<char[]> buf = std::make_unique<char[]>(bufLen);
96
97 auto [state, retLen] = GetActualLen(bufLen, 0, offset, length);
98 if (state != SUCCESS_CODE) {
99 LOGE("Failed to get actual length");
100 return { EINVAL, nullptr, 0, 0 };
101 }
102
103 if (offset < 0) {
104 LOGE("option.offset shall be positive number");
105 return { EINVAL, nullptr, 0, 0 };
106 }
107
108 return { SUCCESS_CODE, move(buf), retLen, offset };
109 }
110
Close()111 int StreamImpl::Close()
112 {
113 if (!fp_) {
114 LOGE("close false, fp is null");
115 return GetErrorCode(EIO);
116 }
117 fp_.reset();
118 return SUCCESS_CODE;
119 }
120
Flush()121 int StreamImpl::Flush()
122 {
123 if (!fp_) {
124 LOGE("flush false, fp is null");
125 return GetErrorCode(EIO);
126 }
127 int ret = fflush(fp_.get());
128 if (ret < 0) {
129 LOGE("Failed to fflush file in the stream, ret: %{public}d", ret);
130 return GetErrorCode(errno);
131 }
132 return SUCCESS_CODE;
133 }
134
ReadImpl(std::unique_ptr<char[]> & buf,size_t len,FILE * filp,uint8_t * buffer)135 tuple<int, int64_t> ReadImpl(std::unique_ptr<char[]> &buf, size_t len, FILE* filp, uint8_t* buffer)
136 {
137 size_t actLen = fread(buf.get(), sizeof(char), len, filp);
138 if ((actLen != static_cast<size_t>(len) && !feof(filp)) || ferror(filp)) {
139 LOGE("Invalid buffer size and pointer, actlen: %{public}zu", actLen);
140 return {GetErrorCode(EIO), 0};
141 }
142 if (actLen != 0) {
143 int ret = memcpy_s(buffer, actLen, buf.get(), actLen);
144 if (ret != 0) {
145 return {GetErrorCode(EIO), 0};
146 }
147 }
148 return {SUCCESS_CODE, static_cast<int64_t>(actLen)};
149 }
150
ReadCur(uint8_t * buffer,size_t buLen,int64_t length)151 tuple<int, int64_t> StreamImpl::ReadCur(uint8_t* buffer, size_t buLen, int64_t length)
152 {
153 if (!fp_) {
154 LOGE("Stream may have been closed");
155 return {GetErrorCode(EIO), 0};
156 }
157
158 FILE *filp = nullptr;
159 filp = fp_.get();
160
161 auto [state, buf, len, offsetResult] = GetReadArg(static_cast<size_t>(buLen), length, 0.0);
162 if (state != SUCCESS_CODE) {
163 LOGE("Failed to resolve buf and options");
164 return {GetErrorCode(state), 0};
165 }
166
167 return ReadImpl(buf, len, filp, buffer);
168 }
169
Read(uint8_t * buffer,size_t buLen,int64_t length,int64_t offset)170 tuple<int, int64_t> StreamImpl::Read(uint8_t* buffer, size_t buLen, int64_t length, int64_t offset)
171 {
172 if (!fp_) {
173 LOGE("Stream may have been closed");
174 return {GetErrorCode(EIO), 0};
175 }
176
177 FILE *filp = nullptr;
178 filp = fp_.get();
179
180 auto [state, buf, len, offsetResult] = GetReadArg(static_cast<size_t>(buLen), length, offset);
181 if (state != SUCCESS_CODE) {
182 LOGE("Failed to resolve buf and options");
183 return {GetErrorCode(state), 0};
184 }
185
186 if (offsetResult >= 0) {
187 int result = fseek(filp, static_cast<long>(offsetResult), SEEK_SET);
188 if (result < 0) {
189 LOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", result);
190 return {GetErrorCode(errno), 0};
191 }
192 }
193 return ReadImpl(buf, len, filp, buffer);
194 }
195
WriteCur(const std::string & buffer,int64_t length,const std::string & encode)196 tuple<int, int64_t> StreamImpl::WriteCur(const std::string& buffer, int64_t length, const std::string& encode)
197 {
198 FILE *filp = nullptr;
199 filp = fp_.get();
200
201 auto [state, bufGuard, buf, len, offsetResult] =
202 GetWriteArg(buffer, length, 0.0, encode);
203 if (state != SUCCESS_CODE) {
204 LOGE("Failed to resolve buf and options");
205 return {GetErrorCode(state), 0};
206 }
207
208 size_t writeLen = fwrite(buf, 1, len, filp);
209 if ((writeLen == 0) && (writeLen != len)) {
210 LOGE("Failed to fwrite stream");
211 return {GetErrorCode(EIO), 0};
212 }
213 return {SUCCESS_CODE, static_cast<int64_t>(writeLen)};
214 }
215
Write(const std::string & buffer,int64_t length,int64_t offset,const std::string & encode)216 tuple<int, int64_t> StreamImpl::Write(const std::string& buffer, int64_t length, int64_t offset,
217 const std::string& encode)
218 {
219 FILE *filp = nullptr;
220 filp = fp_.get();
221
222 auto [state, bufGuard, buf, len, offsetResult] =
223 GetWriteArg(buffer, length, offset, encode);
224 if (state != SUCCESS_CODE) {
225 LOGE("Failed to resolve buf and options");
226 return {GetErrorCode(state), 0};
227 }
228
229 if (offsetResult >= 0) {
230 int ret = fseek(filp, static_cast<long>(offsetResult), SEEK_SET);
231 if (ret < 0) {
232 LOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
233 return {GetErrorCode(errno), 0};
234 }
235 }
236
237 size_t writeLen = fwrite(buf, 1, len, filp);
238 if ((writeLen == 0) && (writeLen != len)) {
239 LOGE("Failed to fwrite stream");
240 return {GetErrorCode(EIO), 0};
241 }
242 return {SUCCESS_CODE, static_cast<int64_t>(writeLen)};
243 }
244
245 }
246 }
247 }