• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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