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