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 <memory>
18 #include <tuple>
19 #include "securec.h"
20 #include "utils.h"
21
22 using namespace std;
23
24 namespace OHOS {
25 namespace CJSystemapi {
26 namespace FileFs {
27
GetActualLen(size_t bufLen,size_t bufOff,int64_t offset,int64_t length)28 std::tuple<int, size_t> GetActualLen(size_t bufLen, size_t bufOff, int64_t offset, int64_t length)
29 {
30 size_t retLen = bufLen - bufOff;
31
32 if (length == 0) {
33 return { SUCCESS_CODE, retLen };
34 }
35
36 if (length < 0 || static_cast<size_t>(length) > retLen) {
37 LOGE("Invalid option length, length: %{public}" PRId64 ", retLen: %{public}zu", length, retLen);
38 return { EINVAL, 0 };
39 }
40 retLen = static_cast<size_t>(length);
41 return { SUCCESS_CODE, retLen };
42 }
43
GetReadArg(size_t bufLen,int64_t length,int64_t offset)44 tuple<int, std::unique_ptr<char[]>, size_t, int64_t> GetReadArg(size_t bufLen, int64_t length, int64_t offset)
45 {
46 std::unique_ptr<char[]> buf = std::make_unique<char[]>(bufLen);
47
48 auto [state, retLen] = GetActualLen(bufLen, 0, offset, length);
49 if (state != SUCCESS_CODE) {
50 LOGE("Failed to get actual length");
51 return { EINVAL, nullptr, 0, 0 };
52 }
53
54 if (offset < 0) {
55 LOGE("option.offset shall be positive number");
56 return { EINVAL, nullptr, 0, 0 };
57 }
58
59 return { SUCCESS_CODE, move(buf), retLen, offset };
60 }
61
Close()62 int StreamImpl::Close()
63 {
64 if (!fp_) {
65 LOGE("close false, fp is null");
66 return GetErrorCode(EIO);
67 }
68 fp_.reset();
69 return SUCCESS_CODE;
70 }
71
Flush()72 int StreamImpl::Flush()
73 {
74 if (!fp_) {
75 LOGE("flush false, fp is null");
76 return GetErrorCode(EIO);
77 }
78 int ret = fflush(fp_.get());
79 if (ret < 0) {
80 LOGE("Failed to fflush file in the stream, ret: %{public}d", ret);
81 return GetErrorCode(errno);
82 }
83 return SUCCESS_CODE;
84 }
85
ReadImpl(std::unique_ptr<char[]> & buf,size_t len,FILE * filp,uint8_t * buffer)86 tuple<int, int64_t> ReadImpl(std::unique_ptr<char[]> &buf, size_t len, FILE* filp, uint8_t* buffer)
87 {
88 size_t actLen = fread(buf.get(), sizeof(char), len, filp);
89 if ((actLen != static_cast<size_t>(len) && !feof(filp)) || ferror(filp)) {
90 LOGE("Invalid buffer size and pointer, actlen: %{public}zu", actLen);
91 return {GetErrorCode(EIO), 0};
92 }
93 if (actLen != 0) {
94 int ret = memcpy_s(buffer, actLen, buf.get(), actLen);
95 if (ret != 0) {
96 return {GetErrorCode(EIO), 0};
97 }
98 }
99 return {SUCCESS_CODE, static_cast<int64_t>(actLen)};
100 }
101
ReadCur(uint8_t * buffer,size_t buLen,int64_t length)102 tuple<int, int64_t> StreamImpl::ReadCur(uint8_t* buffer, size_t buLen, int64_t length)
103 {
104 if (!fp_) {
105 LOGE("Stream may have been closed");
106 return {GetErrorCode(EIO), 0};
107 }
108
109 FILE *filp = nullptr;
110 filp = fp_.get();
111
112 auto [state, buf, len, offsetResult] = GetReadArg(static_cast<size_t>(buLen), length, 0.0);
113 if (state != SUCCESS_CODE) {
114 LOGE("Failed to resolve buf and options");
115 return {GetErrorCode(state), 0};
116 }
117
118 return ReadImpl(buf, len, filp, buffer);
119 }
120
Read(uint8_t * buffer,size_t buLen,int64_t length,int64_t offset)121 tuple<int, int64_t> StreamImpl::Read(uint8_t* buffer, size_t buLen, int64_t length, int64_t offset)
122 {
123 if (!fp_) {
124 LOGE("Stream may have been closed");
125 return {GetErrorCode(EIO), 0};
126 }
127
128 FILE *filp = nullptr;
129 filp = fp_.get();
130
131 auto [state, buf, len, offsetResult] = GetReadArg(static_cast<size_t>(buLen), length, offset);
132 if (state != SUCCESS_CODE) {
133 LOGE("Failed to resolve buf and options");
134 return {GetErrorCode(state), 0};
135 }
136
137 if (offsetResult >= 0) {
138 int result = fseek(filp, static_cast<long>(offsetResult), SEEK_SET);
139 if (result < 0) {
140 LOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", result);
141 return {GetErrorCode(errno), 0};
142 }
143 }
144 return ReadImpl(buf, len, filp, buffer);
145 }
146
WriteCur(void * buffer,int64_t length,const std::string & encode)147 tuple<int, int64_t> StreamImpl::WriteCur(void* buffer, int64_t length, const std::string& encode)
148 {
149 FILE *filp = nullptr;
150 filp = fp_.get();
151
152 auto [state, buf, len, offsetResult] =
153 CommonFunc::GetWriteArg(buffer, length, 0, encode);
154 if (state != SUCCESS_CODE) {
155 LOGE("Failed to resolve buf and options");
156 return {GetErrorCode(state), 0};
157 }
158
159 size_t writeLen = fwrite(buf, 1, len, filp);
160 if ((writeLen == 0) && (writeLen != len)) {
161 LOGE("Failed to fwrite stream");
162 return {GetErrorCode(EIO), 0};
163 }
164 return {SUCCESS_CODE, static_cast<int64_t>(writeLen)};
165 }
166
Write(void * buffer,int64_t length,int64_t offset,const std::string & encode)167 tuple<int, int64_t> StreamImpl::Write(void* buffer, int64_t length, int64_t offset, const std::string& encode)
168 {
169 FILE *filp = nullptr;
170 filp = fp_.get();
171
172 auto [state, buf, len, offsetResult] =
173 CommonFunc::GetWriteArg(buffer, length, offset, encode);
174 if (state != SUCCESS_CODE) {
175 LOGE("Failed to resolve buf and options");
176 return {GetErrorCode(state), 0};
177 }
178
179 if (offsetResult >= 0) {
180 int ret = fseek(filp, static_cast<long>(offsetResult), SEEK_SET);
181 if (ret < 0) {
182 LOGE("Failed to set the offset location of the file stream pointer, ret: %{public}d", ret);
183 return {GetErrorCode(errno), 0};
184 }
185 }
186
187 size_t writeLen = fwrite(buf, 1, len, filp);
188 if ((writeLen == 0) && (writeLen != len)) {
189 LOGE("Failed to fwrite stream");
190 return {GetErrorCode(EIO), 0};
191 }
192 return {SUCCESS_CODE, static_cast<int64_t>(writeLen)};
193 }
194
195 }
196 }
197 }