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 }