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