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 22using namespace std; 23 24namespace OHOS { 25namespace CJSystemapi { 26namespace FileFs { 27 28std::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 46std::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 62tuple<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 93tuple<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 111int 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 121int 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 135tuple<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 151tuple<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 170tuple<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 196tuple<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 216tuple<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}