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