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