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#include "entry.h" 16 17#include <iostream> 18#include <fstream> 19#include <optional> 20 21namespace Hdc { 22 23constexpr size_t ENTRY_FILE_BUFSIZE = 4 * 1024; // 4KB 24constexpr uint64_t ENTRY_MAX_FILE_SIZE = static_cast<uint64_t>(4) * 1024 * 1024 * 1024; // 4GB 25std::optional<std::string> StripPrefix(const std::string& str, const std::string& prefix) 26{ 27 if (str.compare(0, prefix.length(), prefix) == 0) { 28 auto p_path = str.substr(prefix.length()); 29 return p_path; 30 } else { 31 return std::nullopt; 32 } 33} 34 35Entry::Entry(std::string prefix, std::string path) 36{ 37 this->prefix = prefix + Base::GetPathSep(); 38 uv_fs_t req; 39 int rc = uv_fs_lstat(nullptr, &req, path.c_str(), nullptr); 40 uv_fs_req_cleanup(&req); 41 if (rc == 0) { 42 if (req.statbuf.st_mode & S_IFDIR) { 43 header.UpdataFileType(TypeFlage::DIRECTORY); 44 header.UpdataSize(0); 45 } else if (req.statbuf.st_mode & S_IFREG) { 46 auto fileSize = req.statbuf.st_size; 47 if (fileSize < ENTRY_MAX_FILE_SIZE) { // max package size is 4GB 48 header.UpdataSize(fileSize); 49 needSize = fileSize; 50 header.UpdataFileType(TypeFlage::ORDINARYFILE); 51 } else { 52#ifdef HDC_HOST 53 Base::PrintMessage("[Warning]File: %s, size: %lldB, over the 4GB limit, ignored.", 54 path.c_str(), fileSize); 55#else 56 WRITE_LOG(LOG_WARN, "File: %s, size: %lldB, over the 4GB limit, ignored.", 57 path.c_str(), fileSize); 58#endif 59 } 60 } 61 } 62 UpdataName(path); 63} 64 65Entry::Entry(uint8_t data[512], int dataLen) 66{ 67 header = Header(data, dataLen); 68 needSize = header.Size(); 69} 70 71 72void Entry::AddData(uint8_t *data, size_t len) 73{ 74 if (this->needSize == 0) { 75 return; 76 } 77 if (this->needSize > len) { 78 for (size_t i = 0; i < len; i++) { 79 this->data.push_back(data[i]); 80 } 81 this->needSize -= len; 82 } else { 83 for (size_t i = 0; i < this->needSize; i++) { 84 this->data.push_back(data[i]); 85 } 86 this->needSize = 0; 87 } 88} 89 90std::string Entry::GetName() 91{ 92 auto name = this->prefix + this->header.Name(); 93 return name; 94} 95 96bool Entry::UpdataName(std::string name) 97{ 98 if (!this->prefix.empty()) { 99 auto p_path = Hdc::StripPrefix(name, this->prefix); 100 if (p_path.has_value()) { 101 return this->header.UpdataName(p_path.value()); 102 } 103 } 104 return this->header.UpdataName(name); 105} 106 107bool Entry::CopyPayload(std::string prefixPath, std::ifstream &inFile) 108{ 109 switch (this->header.FileType()) { 110 case TypeFlage::ORDINARYFILE: { 111 if (!PayloadToFile(prefixPath, inFile)) { 112 return false; 113 } 114 break; 115 } 116 case TypeFlage::DIRECTORY: { 117 if (!PayloadToDir(prefixPath, inFile)) { 118 return false; 119 } 120 break; 121 } 122 default: 123 return false; 124 } 125 return true; 126} 127 128bool Entry::PayloadToFile(std::string prefixPath, std::ifstream &inFile) 129{ 130 std::string saveFile = ""; 131 saveFile = prefixPath + GetName(); 132 std::ofstream outFile(saveFile, std::ios::app | std::ios::binary); 133 if (!outFile.is_open()) { 134 WRITE_LOG(LOG_FATAL, "PayloadToFile open %s fail", saveFile.c_str()); 135 return false; 136 } 137 bool ret = true; 138 uint8_t *buffAppend = new uint8_t[ENTRY_FILE_BUFSIZE]; 139 while (this->needSize >= ENTRY_FILE_BUFSIZE) { 140 ret = ReadAndWriteData(inFile, outFile, buffAppend, ENTRY_FILE_BUFSIZE, ENTRY_FILE_BUFSIZE); 141 if (!ret) { 142 break; 143 } 144 this->needSize -= ENTRY_FILE_BUFSIZE; 145 } 146 if (ret && this->needSize > 0) { 147 long int paddingSize = HEADER_LEN - (this->needSize % HEADER_LEN); 148 long int lastBufSize = (paddingSize == HEADER_LEN) ? this->needSize : 149 this->needSize + paddingSize; 150 ret = ReadAndWriteData(inFile, outFile, buffAppend, lastBufSize, this->needSize); 151 } 152 delete[] buffAppend; 153 buffAppend = nullptr; 154 outFile.close(); 155 this->needSize = 0; 156 return ret; 157} 158 159bool Entry::ReadAndWriteData(std::ifstream &inFile, std::ofstream &outFile, uint8_t *buffAppend, 160 int readSize, int writeSize) 161{ 162 if (buffAppend == nullptr) { 163 WRITE_LOG(LOG_FATAL, "ReadAndWriteData buffAppend is null"); 164 return false; 165 } 166 inFile.read(reinterpret_cast<char*>(buffAppend), readSize); 167 auto readcnt = inFile.gcount(); 168 if (inFile.fail() || readcnt != readSize) { 169 WRITE_LOG(LOG_FATAL, "ReadAndWriteData read file error"); 170 return false; 171 } 172 outFile.write(reinterpret_cast<const char*>(buffAppend), writeSize); 173 if (outFile.fail()) { 174 WRITE_LOG(LOG_FATAL, "ReadAndWriteData write file error"); 175 return false; 176 } 177 return true; 178} 179 180bool Entry::PayloadToDir(std::string prefixPath, std::ifstream &inFile) 181{ 182 std::string saveFile = ""; 183 auto dirPath = prefixPath.append(GetName()); 184 std::string estr; 185 bool b = Base::TryCreateDirectory(dirPath, estr); 186 if (!b) { 187 WRITE_LOG(LOG_FATAL, "PayloadToDir mkdir failed dirPath:%s estr:%s", dirPath.c_str(), estr.c_str()); 188 return false; 189 } 190 return true; 191} 192 193bool Entry::WriteToTar(std::ofstream &file) 194{ 195 switch (header.FileType()) { 196 case TypeFlage::ORDINARYFILE: { 197 char buff[HEADER_LEN] = {0}; 198 header.GetBytes(reinterpret_cast<uint8_t *>(buff), HEADER_LEN); 199 file.write(buff, HEADER_LEN); 200 if (header.Size() == 0) { 201 break; 202 } 203 std::string name = Base::UnicodeToUtf8(GetName().c_str(), true); 204 std::ifstream inFile(name, std::ios::binary); 205 if (!inFile) { 206 WRITE_LOG(LOG_FATAL, "open %s fail", name.c_str()); 207 } 208 file << inFile.rdbuf(); 209 auto pading = HEADER_LEN - (needSize % HEADER_LEN); 210 if (pading < HEADER_LEN) { 211 char pad[HEADER_LEN] = {0}; 212 file.write(pad, pading); 213 } 214 break; 215 } 216 case TypeFlage::DIRECTORY: { 217 char buff[HEADER_LEN] = {0}; 218 header.GetBytes(reinterpret_cast<uint8_t *>(buff), HEADER_LEN); 219 file.write(buff, HEADER_LEN); 220 break; 221 } 222 default: 223 return false; 224 } 225 return true; 226} 227} 228