• 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 
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