1 /*
2 * Copyright (c) 2022 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 "ptable.h"
17
18 #include <algorithm>
19 #include <map>
20 #include <sys/stat.h>
21
22 #include "applypatch/data_writer.h"
23 #include "log/log.h"
24 #include "securec.h"
25 #include "utils.h"
26 #include "fs_manager.h"
27
28 namespace Updater {
29 constexpr const char *PTABLE_CONFIG_PATH = "/etc/ptable_data.json";
30 constexpr const char *PTABLE_DATA_LABEL = "ptableData";
31 constexpr const char *EMMC_GPT_DATA_LEN_LABEL = "emmcGptDataLen";
32 constexpr const char *LBA_LEN_LABEL = "lbaLen";
33 constexpr const char *GPT_HEADER_LEN_LABEL = "gptHeaderLen";
34 constexpr const char *BLOCK_SIZE_LABEL = "blockSize";
35 constexpr const char *IMG_LUN_SIZE_LABEL = "imgLuSize";
36 constexpr const char *START_LUN_NUM_LABEL = "startLunNumber";
37 constexpr const char *WRITE_DEVICE_LUN_SIZE_LABEL = "writeDeviceLunSize";
38 constexpr const char *DEFAULT_LUN_NUM_LABEL = "defaultLunNum";
39
GetPtablePartitionInfo() const40 std::vector<Ptable::PtnInfo> Ptable::GetPtablePartitionInfo() const
41 {
42 return partitionInfo_;
43 }
44
CorrectBufByPtnList(uint8_t * imageBuf,uint64_t imgBufSize,const std::vector<PtnInfo> & srcInfo,const std::vector<PtnInfo> & dstInfo)45 bool Ptable::CorrectBufByPtnList(uint8_t *imageBuf, uint64_t imgBufSize, const std::vector<PtnInfo> &srcInfo,
46 const std::vector<PtnInfo> &dstInfo)
47 {
48 return false;
49 }
50
GetPtablePartitionNum() const51 uint32_t Ptable::GetPtablePartitionNum() const
52 {
53 return partitionInfo_.size();
54 }
55
LoadPtnInfo(const std::vector<PtnInfo> & ptnInfo)56 bool Ptable::LoadPtnInfo(const std::vector<PtnInfo> &ptnInfo)
57 {
58 if (ptnInfo.empty()) {
59 LOG(ERROR) << "ptnInfo is empty";
60 return false;
61 }
62 partitionInfo_ = ptnInfo;
63 return true;
64 }
65
SetReservedSize(uint64_t reservedSize)66 void Ptable::SetReservedSize(uint64_t reservedSize)
67 {
68 reservedSize_ = reservedSize;
69 }
70
GetPtablePartitionInfoInstance()71 std::vector<Ptable::PtnInfo>& Ptable::GetPtablePartitionInfoInstance()
72 {
73 return partitionInfo_;
74 }
75
InitPtable()76 bool Ptable::InitPtable()
77 {
78 if (!partitionInfo_.empty()) {
79 std::vector<PtnInfo>().swap(partitionInfo_);
80 }
81 if (!ParsePtableData()) {
82 LOG(ERROR) << "parse PtableData from json file error";
83 return false;
84 }
85 return true;
86 }
87
ParsePtableDataNode(const JsonNode & ptableDataNode)88 bool Ptable::ParsePtableDataNode(const JsonNode &ptableDataNode)
89 {
90 std::map<std::string, uint32_t*> ptableDataVars = {
91 {EMMC_GPT_DATA_LEN_LABEL, &ptableData_.emmcGptDataLen},
92 {LBA_LEN_LABEL, &ptableData_.lbaLen},
93 {GPT_HEADER_LEN_LABEL, &ptableData_.gptHeaderLen},
94 {BLOCK_SIZE_LABEL, &ptableData_.blockSize},
95 {IMG_LUN_SIZE_LABEL, &ptableData_.imgLuSize},
96 {START_LUN_NUM_LABEL, &ptableData_.startLunNumber},
97 {WRITE_DEVICE_LUN_SIZE_LABEL, &ptableData_.writeDeviceLunSize},
98 {DEFAULT_LUN_NUM_LABEL, &ptableData_.defaultLunNum},
99 };
100
101 for (auto dataVar : ptableDataVars) {
102 auto dataValue = ptableDataNode[dataVar.first.c_str()].As<uint32_t>();
103 if (!dataValue) {
104 LOG(ERROR) << "parse json failed! " << dataVar.first << " is nullptr!";
105 return false;
106 }
107 *(dataVar.second) = *dataValue;
108 LOG(INFO) << "set " << dataVar.first << " : " << *dataValue;
109 }
110 return true;
111 }
112
ParsePtableData()113 bool Ptable::ParsePtableData()
114 {
115 (void)memset_s(&ptableData_, sizeof(ptableData_), 0, sizeof(ptableData_));
116 std::ifstream ifs(std::string {PTABLE_CONFIG_PATH});
117 if (!ifs.is_open()) {
118 LOG(ERROR) << PTABLE_CONFIG_PATH << " not exist";
119 return false;
120 }
121
122 // get root node
123 std::string content {std::istreambuf_iterator<char> {ifs}, {}};
124 cJSONPtr root(cJSON_Parse(content.c_str()), cJSON_Delete);
125 if (root == nullptr) {
126 LOG(ERROR) << PTABLE_CONFIG_PATH << " contained json invalid";
127 return false;
128 }
129
130 JsonNode node(root.get(), false);
131 const JsonNode &ptableDataNode = node[PTABLE_DATA_LABEL];
132 bool ret = ParsePtableDataNode(ptableDataNode);
133 ptableData_.dataValid = ret;
134 return ret;
135 }
136
GetDefaultImageSize() const137 uint32_t Ptable::GetDefaultImageSize() const
138 {
139 return ptableData_.emmcGptDataLen + ptableData_.defaultLunNum * ptableData_.imgLuSize;
140 }
141
CheckFileExist(const std::string & fileName)142 bool Ptable::CheckFileExist(const std::string &fileName)
143 {
144 struct stat buffers;
145 if (memset_s(&buffers, sizeof(buffers), 0, sizeof(buffers)) != EOK) {
146 LOG(WARNING) << "memset_s fail";
147 }
148 if (stat(fileName.c_str(), &buffers) == 0) {
149 LOG(INFO) << fileName << " is exist";
150 return true;
151 }
152 LOG(INFO) << fileName << " is not exist";
153 return false;
154 }
155
MemReadWithOffset(const std::string & filePath,const uint64_t offset,uint8_t * outData,const uint32_t dataSize)156 bool Ptable::MemReadWithOffset(const std::string &filePath, const uint64_t offset,
157 uint8_t *outData, const uint32_t dataSize)
158 {
159 if (filePath.length() == 0 || outData == nullptr || dataSize == 0) {
160 LOG(ERROR) << "invaild input";
161 return false;
162 }
163
164 std::ifstream fin(filePath, std::ios::in);
165 if (fin.fail()) {
166 LOG(ERROR) << "open " << filePath << " fail";
167 return false;
168 }
169
170 fin.seekg(offset, std::ios::beg);
171 if (fin.tellg() != static_cast<long long>(offset)) {
172 LOG(ERROR) << "seekp 0x" << std::hex << offset << " bytes in " << filePath <<
173 " failed. Now is in 0x" << std::hex << fin.tellg() << std::dec;
174 fin.close();
175 return false;
176 }
177
178 if (!fin.read(reinterpret_cast<char *>(outData), dataSize)) {
179 LOG(ERROR) << "read 0x" << std::hex << dataSize << " bytes in " << filePath <<
180 " failed. only read 0x" << std::hex << fin.gcount() << std::dec;
181 fin.close();
182 return false;
183 }
184 fin.close();
185 return true;
186 }
187
Reflect(uint32_t data,const uint32_t len)188 uint32_t Ptable::Reflect(uint32_t data, const uint32_t len)
189 {
190 uint32_t ref = 0;
191 for (uint32_t i = 0; i < len; i++) {
192 if (data & 0x1) {
193 ref |= (1 << ((len - 1) - i));
194 }
195 data = (data >> 1);
196 }
197 return ref;
198 }
199
CalculateCrc32(const uint8_t * buffer,const uint32_t len)200 uint32_t Ptable::CalculateCrc32(const uint8_t *buffer, const uint32_t len)
201 {
202 if (buffer == nullptr || len == 0) {
203 LOG(INFO) << "invaild input";
204 return 0;
205 }
206 const uint32_t byteLen = 8; // 8:length of unit (i.e. byte)
207 uint32_t msb;
208 const uint64_t polynomial = 0x104C11DB7LL; // IEEE 32bit polynomial
209 uint32_t regs = 0xFFFFFFFF; // init to all ones
210 const uint32_t regsMask = 0xFFFFFFFF; // ensure only 32 bit answer
211 uint32_t regsMsb;
212 for (uint32_t i = 0; i < len; i++) {
213 uint32_t dataByte = buffer[i];
214 dataByte = Reflect(dataByte, 8); // 8:length of unit (i.e. byte)
215 for (uint32_t j = 0; j < byteLen; j++) {
216 msb = dataByte >> (byteLen - 1); // get MSB
217 msb &= 1; // ensure just 1 bit
218 regsMsb = (regs >> 31) & 1; // 31:32-1, MSB of regs
219 regs = regs << 1; // shift regs for CRC-CCITT
220 if (regsMsb ^ msb) { // MSB is a 1
221 regs = regs ^ polynomial; // XOR with generator poly
222 }
223 regs = regs & regsMask; // Mask off excess upper bits
224 dataByte <<= 1; // get to next bit
225 }
226 }
227 regs = regs & regsMask;
228 uint32_t ret = Reflect(regs, 32) ^ 0xFFFFFFFF; // 32:32bit
229 return ret;
230 }
231
VerifyMbrMagicNum(const uint8_t * buffer,const uint32_t size)232 bool Ptable::VerifyMbrMagicNum(const uint8_t *buffer, const uint32_t size)
233 {
234 // avoid checking past end of buffer
235 if (size < (MBR_MAGIC_NUM_POS + 1)) {
236 LOG(ERROR) << "size < (TABLE_SIGNATURE + 1)";
237 return false;
238 }
239 // check to see if magic number(0x55AA) exists at pos 0x1FE
240 if ((buffer[MBR_MAGIC_NUM_POS] != MBR_MAGIC_NUM_0) ||
241 (buffer[MBR_MAGIC_NUM_POS + 1] != MBR_MAGIC_NUM_1)) {
242 LOG(ERROR) << "MBR magic number does not match, magic buffer is " << unsigned(*(buffer + MBR_MAGIC_NUM_POS));
243 return false;
244 }
245 return true;
246 }
247
CheckProtectiveMbr(const uint8_t * gptImage,const uint32_t imgLen)248 bool Ptable::CheckProtectiveMbr(const uint8_t *gptImage, const uint32_t imgLen)
249 {
250 if (!VerifyMbrMagicNum(gptImage, imgLen)) {
251 LOG(ERROR) << "MBR magic number verify failed!";
252 return false;
253 }
254
255 // process each of the four partitions in the MBR, find a Protective MBR(0xEE)
256 uint32_t type;
257 for (uint32_t i = 0; i < MBR_GPT_MAX_NUM; i++) {
258 // type 0xEE indicates the protective MBR and GPT partitions exist
259 if (MBR_GPT_ENTRY + i * MBR_GPT_ENTRY_SIZE + GPT_TYPE_SIGN_OFFSET >= imgLen) {
260 LOG(INFO) << "not find Protective MBR(type: 0xEE) in this partition";
261 return false;
262 }
263 type = gptImage[MBR_GPT_ENTRY + i * MBR_GPT_ENTRY_SIZE + GPT_TYPE_SIGN_OFFSET];
264 if (type == MBR_PROTECTIVE_GPT_TYPE) {
265 LOG(INFO) << "type is MBR_PROTECTIVE_GPT_TYPE(0xEE), GPT partitions exist";
266 return true;
267 }
268 LOG(INFO) << "the " << i << " main GPT's type=0x" << std::hex << type << std::dec;
269 }
270 LOG(INFO) << "not find Protective MBR(type: 0xEE) in this partition";
271 return false;
272 }
273
CheckIfValidGpt(const uint8_t * gptImage,const uint32_t gptImageLen)274 bool Ptable::CheckIfValidGpt(const uint8_t *gptImage, const uint32_t gptImageLen)
275 {
276 // 8 is the length of EFI_MAGIC_NUMBER
277 if (gptImageLen < 8) {
278 LOG(ERROR) << "gptImageLen is less than 8.";
279 return false;
280 }
281 // get magic number
282 uint64_t gptMagic = GET_LLWORD_FROM_BYTE(gptImage);
283 if (gptMagic != EFI_MAGIC_NUMBER) {
284 LOG(ERROR) << "invaild partiton with gptMagic:0x" << std::hex << gptMagic << std::dec;
285 return false;
286 }
287 return true;
288 }
289
GetCapacity(const std::string & filePath,uint64_t & lunCapacity)290 bool Ptable::GetCapacity(const std::string &filePath, uint64_t &lunCapacity)
291 {
292 if (filePath.empty()) {
293 LOG(ERROR) << "filePath is empty or lunCapacity is nullptr";
294 return false;
295 }
296 std::ifstream fin(filePath, std::ios::in);
297 if (!fin.is_open()) {
298 LOG(ERROR) << "open " << filePath << " fail";
299 return false;
300 }
301
302 uint64_t sector = 0;
303 fin >> sector;
304 if (sector == 0) {
305 LOG(ERROR) << "read data from " << filePath << " fail";
306 fin.close();
307 return false;
308 }
309
310 uint64_t capacity = sector * SECTOR_SIZE;
311 LOG(INFO) << "lun capacity = 0x" << std::hex << capacity << std::dec;
312 lunCapacity = capacity;
313 fin.close();
314 return true;
315 }
316
GetPartitionGptHeaderInfo(const uint8_t * buffer,const uint32_t bufferLen,GPTHeaderInfo & gptHeaderInfo)317 bool Ptable::GetPartitionGptHeaderInfo(const uint8_t *buffer, const uint32_t bufferLen, GPTHeaderInfo& gptHeaderInfo)
318 {
319 if (buffer == nullptr || bufferLen < LBA_LENGTH) {
320 LOG(ERROR) << "input invalid";
321 return false;
322 }
323
324 // Check GPT Signature
325 if (!CheckIfValidGpt(buffer, bufferLen)) {
326 LOG(ERROR) << "invaild partiton with gptMagic";
327 return false;
328 }
329 gptHeaderInfo.headerSize = GET_LWORD_FROM_BYTE(buffer + HEADER_SIZE_OFFSET);
330 gptHeaderInfo.firstUsableLba = GET_LLWORD_FROM_BYTE(buffer + FIRST_USABLE_LBA_OFFSET);
331 gptHeaderInfo.maxPartitionCount = GET_LWORD_FROM_BYTE(buffer + PARTITION_COUNT_OFFSET);
332 gptHeaderInfo.partitionEntrySize = GET_LWORD_FROM_BYTE(buffer + PENTRY_SIZE_OFFSET);
333 if (gptHeaderInfo.maxPartitionCount == 0 || gptHeaderInfo.partitionEntrySize == 0) {
334 LOG(ERROR) << "invalid gpt header info";
335 return false;
336 }
337 return true;
338 }
339
PatchBackUpGptHeader(uint8_t * gptHeader,const uint32_t len,uint64_t backGptEntryStart)340 void Ptable::PatchBackUpGptHeader(uint8_t *gptHeader, const uint32_t len, uint64_t backGptEntryStart)
341 {
342 if (std::max({GPT_HEADER_OFFSET, BACKUP_HEADER_OFFSET, PARTITION_ENTRY_OFFSET}) + sizeof(uint64_t) > len ||
343 HEADER_CRC_OFFSET + sizeof(uint32_t) > len) {
344 LOG(ERROR) << "input param invalid";
345 return;
346 }
347 uint64_t gptHeaderOffset = GET_LLWORD_FROM_BYTE(gptHeader + GPT_HEADER_OFFSET);
348 uint64_t backHeaderOffset = GET_LLWORD_FROM_BYTE(gptHeader + BACKUP_HEADER_OFFSET);
349 PUT_LONG_LONG(gptHeader + GPT_HEADER_OFFSET, backHeaderOffset);
350 PUT_LONG_LONG(gptHeader + BACKUP_HEADER_OFFSET, gptHeaderOffset);
351 PUT_LONG_LONG(gptHeader + PARTITION_ENTRY_OFFSET, backGptEntryStart);
352 PUT_LONG(gptHeader + HEADER_CRC_OFFSET, 0);
353 uint32_t crcValue = CalculateCrc32(gptHeader, GPT_CRC_LEN);
354 PUT_LONG(gptHeader + HEADER_CRC_OFFSET, crcValue);
355 LOG(INFO) << "gpt header offset " << gptHeaderOffset << ", back header offset " << backHeaderOffset <<
356 ", crc value " << crcValue;
357 }
358
CheckGptHeader(uint8_t * buffer,const uint32_t bufferLen,const uint64_t lbaNum,const GPTHeaderInfo & gptHeaderInfo)359 bool Ptable::CheckGptHeader(uint8_t *buffer, const uint32_t bufferLen, const uint64_t lbaNum,
360 const GPTHeaderInfo& gptHeaderInfo)
361 {
362 if (bufferLen < LBA_LENGTH || lbaNum == 0) {
363 LOG(ERROR) << "bufferLen < LBA_LENGTH || lbaNum == 0";
364 return false;
365 }
366
367 if (gptHeaderInfo.headerSize < GPT_HEADER_SIZE || gptHeaderInfo.headerSize > bufferLen) {
368 LOG(ERROR) << "GPT Header size is invaild";
369 return false;
370 }
371 uint32_t orgCrcVal = GET_LWORD_FROM_BYTE(buffer + HEADER_CRC_OFFSET);
372 // Write CRC field to 0 before calculating the crc of the whole rest of GPT header
373 PUT_LONG(buffer + HEADER_CRC_OFFSET, 0);
374 uint32_t crcVal = CalculateCrc32(buffer, gptHeaderInfo.headerSize);
375 if (crcVal != orgCrcVal) {
376 LOG(ERROR) << "Header crc mismatch crcVal = " << std::hex << crcVal << " with orgCrcVal = " <<
377 orgCrcVal << std::dec;
378 return false;
379 }
380 PUT_LONG(buffer + HEADER_CRC_OFFSET, crcVal);
381
382 uint32_t currentLba = GET_LLWORD_FROM_BYTE(buffer + PRIMARY_HEADER_OFFSET);
383 uint32_t lastUsableLba = GET_LLWORD_FROM_BYTE(buffer + LAST_USABLE_LBA_OFFSET);
384 uint32_t partition0 = GET_LLWORD_FROM_BYTE(buffer + PARTITION_ENTRIES_OFFSET);
385
386 // check for first and last lba range
387 if (gptHeaderInfo.firstUsableLba > lbaNum || lastUsableLba > lbaNum) {
388 LOG(ERROR) << "invalid usable lba " << gptHeaderInfo.firstUsableLba << ", last is " << lastUsableLba <<
389 " lbaNum is " << lbaNum;
390 return false;
391 }
392 // check for partition entry size
393 if (gptHeaderInfo.partitionEntrySize != PARTITION_ENTRY_SIZE ||
394 gptHeaderInfo.maxPartitionCount > (MIN_PARTITION_ARRAY_SIZE / PARTITION_ENTRY_SIZE)) {
395 LOG(ERROR) << "invalid parition entry size or max count";
396 return false;
397 }
398 // GPT header should always be the 0x1 LBA, partition entry should always the 0x2 LBA
399 if (currentLba != 0x1 || partition0 != 0x2) {
400 LOG(ERROR) << "starting LBA mismatch";
401 return false;
402 }
403 LOG(INFO) << "gpt header check ok";
404 return true;
405 }
406
PartitionCheckGptHeader(const uint8_t * gptImage,const uint32_t len,const uint64_t lbaNum,const uint32_t blockSize,GPTHeaderInfo & gptHeaderInfo)407 bool Ptable::PartitionCheckGptHeader(const uint8_t *gptImage, const uint32_t len, const uint64_t lbaNum,
408 const uint32_t blockSize, GPTHeaderInfo& gptHeaderInfo)
409 {
410 if (len < ptableData_.writeDeviceLunSize || lbaNum == 0) {
411 LOG(ERROR) << "len" << len << "ptableData_.writeDeviceLunSize" << ptableData_.writeDeviceLunSize
412 << "lbaNum" << lbaNum;
413 return false;
414 }
415
416 uint8_t *buffer = new(std::nothrow) uint8_t[blockSize]();
417 if (buffer == nullptr) {
418 LOG(ERROR) << "new buffer failed!";
419 return false;
420 }
421 if (memcpy_s(buffer, blockSize, gptImage + blockSize, blockSize) != EOK) {
422 LOG(ERROR) << "copy gpt header fail";
423 delete [] buffer;
424 return false;
425 }
426
427 if (!CheckGptHeader(buffer, blockSize, lbaNum, gptHeaderInfo)) {
428 LOG(ERROR) << "CheckGptHeader fail";
429 delete [] buffer;
430 return false;
431 }
432
433 uint32_t partition0 = GET_LLWORD_FROM_BYTE(&buffer[PARTITION_ENTRIES_OFFSET]);
434 uint32_t orgCrcVal = GET_LWORD_FROM_BYTE(&buffer[PARTITION_CRC_OFFSET]);
435 delete [] buffer;
436
437 uint32_t crcVal = CalculateCrc32(gptImage + partition0 * blockSize,
438 gptHeaderInfo.maxPartitionCount * gptHeaderInfo.partitionEntrySize);
439 if (crcVal != orgCrcVal) {
440 LOG(ERROR) << "partition entires crc mismatch crcVal =" << std::hex << crcVal << " with orgCrcVal =" <<
441 orgCrcVal << std::dec;
442 return false;
443 }
444 LOG(INFO) << "PartitionCheckGptHeader ok";
445 return true;
446 }
447
PrintPtableInfo() const448 void Ptable::PrintPtableInfo() const
449 {
450 if (partitionInfo_.empty()) {
451 LOG(ERROR) << "ptable vector is empty!";
452 return;
453 }
454
455 LOG(INFO) << "ptnInfo : ===========================================";
456 LOG(INFO) << "partition count = " << std::dec << partitionInfo_.size();
457 for (size_t i = 0; i < partitionInfo_.size(); i++) {
458 LOG(INFO) << "ptable.entry[" << i << "].name=" << partitionInfo_[i].dispName.c_str() <<
459 ", startAddr=0x" << std::hex << partitionInfo_[i].startAddr << ", size=0x" <<
460 partitionInfo_[i].partitionSize << ", lun=" << std::dec << partitionInfo_[i].lun
461 << ", partType=" << partitionInfo_[i].partType;
462 }
463 LOG(INFO) << "ptnInfo : ===========================================";
464 }
465
PrintPtableInfo(const std::vector<PtnInfo> & ptnInfo) const466 void Ptable::PrintPtableInfo(const std::vector<PtnInfo> &ptnInfo) const
467 {
468 if (ptnInfo.empty()) {
469 LOG(ERROR) << "ptable vector is empty!";
470 return;
471 }
472
473 LOG(INFO) << "ptnInfo : ===========================================";
474 LOG(INFO) << "partition count = " << std::dec << ptnInfo.size();
475 for (size_t i = 0; i < ptnInfo.size(); i++) {
476 LOG(INFO) << "ptable.entry[" << i << "].name=" << ptnInfo[i].dispName.c_str() << ", startAddr=0x" <<
477 std::hex << ptnInfo[i].startAddr << ", size=0x" << ptnInfo[i].partitionSize << ", lun=" <<
478 std::dec << ptnInfo[i].lun << ", partType=" << ptnInfo[i].partType;
479 }
480 LOG(INFO) << "ptnInfo : ===========================================";
481 }
482
SetPartitionType(const std::string & partName,PtnInfo & ptnInfo)483 void Ptable::SetPartitionType(const std::string &partName, PtnInfo &ptnInfo)
484 {
485 if (PARTITION_AB_SUFFIX_SIZE > partName.size()) {
486 ptnInfo.partType = PARTITION_NORMAL_TYPE;
487 return;
488 }
489 std::string partSuffix = partName.substr(partName.size() - PARTITION_AB_SUFFIX_SIZE,
490 PARTITION_AB_SUFFIX_SIZE);
491 if (strcasecmp(partSuffix.c_str(), PARTITION_A_SUFFIX) == 0 ||
492 strcasecmp(partSuffix.c_str(), PARTITION_B_SUFFIX) == 0) {
493 ptnInfo.partType = PARTITION_AB_TYPE;
494 return;
495 }
496 ptnInfo.partType = PARTITION_NORMAL_TYPE;
497 }
498
ParsePartitionName(const uint8_t * data,const uint32_t dataLen,std::string & name,const uint32_t nameLen)499 void Ptable::ParsePartitionName(const uint8_t *data, const uint32_t dataLen,
500 std::string &name, const uint32_t nameLen)
501 {
502 if (data == nullptr || dataLen == 0 || nameLen == 0) {
503 LOG(ERROR) << "dataLen == 0 || nameLen == 0";
504 return;
505 }
506 char utf16Name[MAX_GPT_NAME_SIZE] = {0};
507 if (memcpy_s(utf16Name, sizeof(utf16Name), data, dataLen) != EOK) {
508 LOG(ERROR) << "memcpy name fail";
509 return;
510 }
511
512 std::string outName;
513 // convert utf8 to utf16, 2 bytes for 1 charactor of partition name
514 for (uint32_t n = 0; n < nameLen && n < (MAX_GPT_NAME_SIZE / 2) && utf16Name[n * 2] != '\0'; n++) {
515 outName = outName + utf16Name[n * 2];
516 }
517 for (uint32_t i = 0; i < outName.size(); i++) {
518 outName[i] = static_cast<char>(toupper(outName[i]));
519 }
520 name = outName;
521 return;
522 }
523
WriteBufferToPath(const std::string & path,const uint64_t offset,const uint8_t * buffer,const uint32_t size)524 bool Ptable::WriteBufferToPath(const std::string &path, const uint64_t offset,
525 const uint8_t *buffer, const uint32_t size)
526 {
527 std::unique_ptr<DataWriter> writer = DataWriter::CreateDataWriter(WRITE_RAW, path, offset);
528 if (writer == nullptr) {
529 LOG(ERROR) << "create writer class failed!";
530 return false;
531 }
532 bool ret = writer->Write(buffer, size, nullptr);
533 if (!ret) {
534 LOG(ERROR) << "writer to " << path << " with offset " << offset << " failed ";
535 DataWriter::ReleaseDataWriter(writer);
536 return false;
537 }
538 DataWriter::ReleaseDataWriter(writer);
539 return true;
540 }
541
GetPartionInfoByName(const std::string & partitionName,PtnInfo & ptnInfo,int32_t & index)542 bool Ptable::GetPartionInfoByName(const std::string &partitionName, PtnInfo &ptnInfo, int32_t &index)
543 {
544 if (partitionInfo_.empty()) {
545 LOG(ERROR) << "get partition failed! partitionInfo_ is empty";
546 return false;
547 }
548 auto findPart = [&ptnInfo, &index, this] (const std::string &partitionName) {
549 for (int32_t i = 0; i < static_cast<int32_t>(partitionInfo_.size()); i++) {
550 if (partitionInfo_[i].dispName.size() == partitionName.size() &&
551 strcasecmp(partitionInfo_[i].dispName.c_str(), partitionName.c_str()) == 0) {
552 index = i;
553 ptnInfo = partitionInfo_[i];
554 return true;
555 }
556 }
557 return false;
558 };
559 if (findPart(partitionName)) {
560 LOG(INFO) << "find partition name " << partitionName;
561 return true;
562 }
563 std::string partitionNameAB = partitionName;
564 if (Utils::IsUpdaterMode()) {
565 partitionNameAB += (GetCurrentSlot() == 1 ? PARTITION_A_SUFFIX : PARTITION_B_SUFFIX);
566 } else {
567 partitionNameAB += (GetCurrentSlot() == 1 ? PARTITION_B_SUFFIX : PARTITION_A_SUFFIX);
568 }
569 if (findPart(partitionNameAB)) {
570 LOG(INFO) << "find partitionAB name " << partitionNameAB;
571 return true;
572 }
573 LOG(ERROR) << "get partition info failed! Not found partition:" << partitionName;
574 return false;
575 }
576
AdjustGpt(uint8_t * ptnInfoBuf,uint64_t bufSize,const std::string & ptnName,uint64_t preLastLBA,uint64_t lastPtnLastLBA)577 bool Ptable::AdjustGpt(uint8_t *ptnInfoBuf, uint64_t bufSize, const std::string &ptnName, uint64_t preLastLBA,
578 uint64_t lastPtnLastLBA)
579 {
580 if (ptnInfoBuf == nullptr || bufSize == 0 || ptnName.empty()) {
581 LOG(ERROR) << "invalid input";
582 return false;
583 }
584 if (ptnName != LAST_PATITION_NAME) {
585 uint64_t firstLBA = GET_LLWORD_FROM_BYTE(&ptnInfoBuf[FIRST_LBA_OFFSET]);
586 uint64_t lastLBA = GET_LLWORD_FROM_BYTE(&ptnInfoBuf[LAST_LBA_OFFSET]);
587 lastLBA = lastLBA - firstLBA + preLastLBA + 1;
588 firstLBA = preLastLBA + 1;
589 PUT_LONG_LONG(ptnInfoBuf + FIRST_LBA_OFFSET, firstLBA);
590 PUT_LONG_LONG(ptnInfoBuf + LAST_LBA_OFFSET, lastLBA);
591 } else { /* this is USERDATA partition */
592 uint64_t firstLBA = preLastLBA + 1;
593 if (lastPtnLastLBA < firstLBA) {
594 LOG(ERROR) << "patch last partition fail";
595 return false;
596 }
597 PUT_LONG_LONG(ptnInfoBuf + FIRST_LBA_OFFSET, firstLBA);
598 /* resize last partition by device density */
599 PUT_LONG_LONG(ptnInfoBuf + LAST_LBA_OFFSET, lastPtnLastLBA);
600 }
601 return true;
602 }
603
ChangeGpt(uint8_t * gptBuf,uint64_t gptSize,GptParseInfo gptInfo,PtnInfo & modifyInfo)604 bool Ptable::ChangeGpt(uint8_t *gptBuf, uint64_t gptSize, GptParseInfo gptInfo, PtnInfo &modifyInfo)
605 {
606 if (gptBuf == nullptr || gptSize == 0 || gptSize <= gptInfo.imgBlockSize || gptInfo.devBlockSize == 0) {
607 LOG(ERROR) << "input param invalid";
608 return false;
609 }
610 bool modifyDectect = false;
611 uint8_t *gptHead = gptBuf + gptInfo.imgBlockSize; // skip pmbr
612 uint32_t ptnEntrySize = GET_LLWORD_FROM_BYTE(&gptHead[PENTRY_SIZE_OFFSET]);
613 uint64_t ptnStart = GET_LLWORD_FROM_BYTE(&gptHead[PARTITION_ENTRIES_OFFSET]);
614 uint64_t readSize = ptnStart * gptInfo.imgBlockSize;
615 uint8_t *ptnInfoBuf = gptBuf + readSize;
616 uint64_t preLastLBA = 0;
617 uint64_t lastPtnLastLBA = gptInfo.devDensity / gptInfo.devBlockSize - 1;
618
619 while (readSize < gptSize) {
620 std::string dispName;
621 // convert utf8 to utf16, 2 bytes for 1 charactor of partition name
622 ParsePartitionName(&ptnInfoBuf[GPT_PARTITION_NAME_OFFSET], MAX_GPT_NAME_SIZE, dispName, MAX_GPT_NAME_SIZE / 2);
623 if (dispName.empty()) {
624 break;
625 }
626 if (modifyDectect) {
627 /* partition after modify part */
628 if (!AdjustGpt(ptnInfoBuf, gptSize - readSize, dispName, preLastLBA, lastPtnLastLBA)) {
629 return false;
630 }
631 preLastLBA = GET_LLWORD_FROM_BYTE(&ptnInfoBuf[LAST_LBA_OFFSET]);
632 ptnInfoBuf += ptnEntrySize;
633 readSize += static_cast<uint64_t>(ptnEntrySize);
634 continue;
635 }
636 if (dispName == modifyInfo.dispName) {
637 LOG(INFO) << "modify part dectected!! dispName = " << dispName;
638 uint64_t firstLBA = modifyInfo.startAddr / gptInfo.devBlockSize;
639 uint64_t lastLBA = firstLBA + modifyInfo.partitionSize / gptInfo.devBlockSize - 1;
640 if ((dispName == LAST_PATITION_NAME) && (lastLBA != lastPtnLastLBA)) {
641 return false;
642 }
643 PUT_LONG_LONG(ptnInfoBuf + FIRST_LBA_OFFSET, firstLBA);
644 PUT_LONG_LONG(ptnInfoBuf + LAST_LBA_OFFSET, lastLBA);
645 modifyDectect = true;
646 preLastLBA = lastLBA;
647 }
648 ptnInfoBuf += ptnEntrySize;
649 readSize += static_cast<uint64_t>(ptnEntrySize);
650 }
651 return true;
652 }
653
WritePartitionBufToFile(uint8_t * ptbImgBuffer,const uint32_t imgBufSize)654 bool Ptable::WritePartitionBufToFile(uint8_t *ptbImgBuffer, const uint32_t imgBufSize)
655 {
656 if (ptbImgBuffer == nullptr || imgBufSize == 0) {
657 LOG(ERROR) << "Invalid param ";
658 return false;
659 }
660 std::ofstream ptbFile(PTABLE_TEMP_PATH, std::ios::ate | std::ios::binary);
661 if (ptbFile.fail()) {
662 LOG(ERROR) << "Failed to open " << PTABLE_TEMP_PATH << strerror(errno);
663 return false;
664 }
665 ptbFile.write(reinterpret_cast<const char*>(ptbImgBuffer), imgBufSize);
666 if (ptbFile.bad()) {
667 LOG(ERROR) << "Failed to write ptable tmp file " << imgBufSize << strerror(errno);
668 return false;
669 }
670 ptbFile.flush();
671 sync();
672 return true;
673 }
674
ReadPartitionFileToBuffer(uint8_t * ptbImgBuffer,uint32_t & imgBufSize)675 bool Ptable::ReadPartitionFileToBuffer(uint8_t *ptbImgBuffer, uint32_t &imgBufSize)
676 {
677 if (ptbImgBuffer == nullptr || imgBufSize == 0) {
678 LOG(ERROR) << "Invalid param ";
679 return false;
680 }
681
682 std::ifstream ptbFile(PTABLE_TEMP_PATH, std::ios::in | std::ios::binary);
683 if (!ptbFile.is_open()) {
684 LOG(ERROR) << "open " << PTABLE_TEMP_PATH << " failed " << strerror(errno);
685 return false;
686 }
687
688 ptbFile.seekg(0, std::ios::end);
689 uint32_t fileSize = static_cast<uint32_t>(ptbFile.tellg());
690 if (ptbFile.tellg() <= 0 || fileSize > imgBufSize) {
691 LOG(ERROR) << "ptbFile is error";
692 return false;
693 }
694
695 ptbFile.seekg(0, std::ios::beg);
696 if (!ptbFile.read(reinterpret_cast<char*>(ptbImgBuffer), fileSize)) {
697 LOG(ERROR) << "read ptable file to buffer failed " << fileSize << strerror(errno);
698 return false;
699 }
700 imgBufSize = fileSize;
701 return true;
702 }
703
DeletePartitionTmpFile()704 void Ptable::DeletePartitionTmpFile()
705 {
706 if (Utils::DeleteFile(PTABLE_TEMP_PATH) != 0) {
707 LOG(ERROR) << "delete ptable tmp file fail " << PTABLE_TEMP_PATH << strerror(errno);
708 return;
709 }
710 LOG(INFO) << "delete ptable tmp file success " << PTABLE_TEMP_PATH;
711 }
712 } // namespace Updater