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 "ufs_ptable.h"
17 
18 #include <algorithm>
19 #include <fcntl.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 
23 #include "log/log.h"
24 #include "securec.h"
25 #include "updater/updater_const.h"
26 
27 namespace Updater {
GetDeviceLunNum()28 uint32_t UfsPtable::GetDeviceLunNum()
29 {
30     return deviceLunNum_;
31 }
32 
GetDeviceLunCapacity(const uint32_t lunIndex)33 uint64_t UfsPtable::GetDeviceLunCapacity(const uint32_t lunIndex)
34 {
35     char lunIndexName = 'a' + lunIndex;
36     std::string capacityPath = std::string(PREFIX_SYS_CLASS_BLOCK) + lunIndexName + "/size";
37     uint64_t capacity = 0;
38     GetCapacity(capacityPath, capacity);
39     return capacity;
40 }
41 
GetPtableExtraOffset(void)42 uint32_t UfsPtable::GetPtableExtraOffset(void)
43 {
44     return 0;
45 }
46 
47 // avoid u disk being recognized as a valid gpt lun device
CheckDeviceLunRemoveable(const uint32_t lunIndex)48 bool UfsPtable::CheckDeviceLunRemoveable(const uint32_t lunIndex)
49 {
50     constexpr uint32_t minRemoveableStartIdx = 3;
51     if (lunIndex <= minRemoveableStartIdx) {
52         return false;
53     }
54     char lunIndexName = 'a' + lunIndex;
55     std::string removableNode = std::string(PREFIX_SYS_CLASS_BLOCK) + lunIndexName + "/removable";
56     std::string removableResult {};
57     std::ifstream fin(removableNode, std::ios::in);
58     if (!fin.is_open()) {
59         LOG(ERROR) << "open " << removableNode << " failed";
60         return false;
61     }
62     fin >> removableResult;
63     LOG(INFO) << "lun " << lunIndex << " removable result is : " << removableResult;
64     return removableResult == "1";
65 }
66 
GetDeviceBlockSize(void)67 uint32_t UfsPtable::GetDeviceBlockSize(void)
68 {
69     return ptableData_.blockSize;
70 }
71 
GetDeviceLunNodePath(const uint32_t lun)72 std::string UfsPtable::GetDeviceLunNodePath(const uint32_t lun)
73 {
74     char lunIndexName = 'a' + lun;
75     return std::string(PREFIX_UFS_NODE) + lunIndexName;
76 }
77 
SetDeviceLunNum()78 void UfsPtable::SetDeviceLunNum()
79 {
80     if (deviceLunNum_ > 0) {
81         return;
82     }
83     uint32_t lunIndex;
84     for (lunIndex = 0; lunIndex < MAX_LUN_NUMBERS; lunIndex++) {
85         std::string ufsNode = GetDeviceLunNodePath(lunIndex);
86         if (!CheckFileExist(ufsNode)) {
87             LOG(ERROR) << "file " << ufsNode << " is not exist";
88             break;
89         }
90 #ifndef UPDATER_UT
91         if (CheckDeviceLunRemoveable(lunIndex)) {
92             LOG(ERROR) << "device " << ufsNode << " is removable, may be a u disk";
93             break;
94         }
95 #endif
96     }
97     deviceLunNum_ = lunIndex;
98     LOG(INFO) << "device lun num is " << deviceLunNum_;
99     return;
100 }
101 
ParseGptHeaderByUfsLun(const uint8_t * gptImage,const uint32_t len,const uint32_t lun,const uint32_t blockSize)102 bool UfsPtable::ParseGptHeaderByUfsLun(const uint8_t *gptImage, const uint32_t len,
103     const uint32_t lun, const uint32_t blockSize)
104 {
105     GPTHeaderInfo gptHeaderInfo;
106     (void)memset_s(&gptHeaderInfo, sizeof(GPTHeaderInfo), 0, sizeof(GPTHeaderInfo));
107     if (!GetPartitionGptHeaderInfo(gptImage + blockSize, blockSize, gptHeaderInfo)) {
108         LOG(ERROR) << "GetPartitionGptHeaderInfo fail";
109         return false;
110     }
111     uint32_t deviceBlockSize = GetDeviceBlockSize();
112     if (deviceBlockSize == 0) {
113         LOG(ERROR) << "block device size invalid " << deviceBlockSize;
114         return false;
115     }
116     uint64_t lunDeviceSize = GetDeviceLunCapacity(lun);
117     uint32_t lunLbaNum = lunDeviceSize / deviceBlockSize;
118     return PartitionCheckGptHeader(gptImage, len, lunLbaNum, blockSize, gptHeaderInfo);
119 }
120 
UfsReadGpt(const uint8_t * gptImage,const uint32_t len,const uint32_t lun,const uint32_t blockSize)121 bool UfsPtable::UfsReadGpt(const uint8_t *gptImage, const uint32_t len,
122     const uint32_t lun, const uint32_t blockSize)
123 {
124     if (gptImage == nullptr || len < ptableData_.writeDeviceLunSize || lun >= MAX_LUN_NUMBERS || blockSize == 0) {
125         LOG(ERROR) << "invaild input";
126         return false;
127     }
128     if (!ParseGptHeaderByUfsLun(gptImage, len, lun, blockSize)) {
129         LOG(ERROR) << "Primary signature invalid";
130         return false;
131     }
132     auto startIter = partitionInfo_.end();
133     for (auto it = partitionInfo_.begin(); it != partitionInfo_.end();) {
134         if ((*it).lun == lun) {
135             it = partitionInfo_.erase(it);
136             startIter = it;
137             continue;
138         }
139         it++;
140     }
141 
142     uint32_t partEntryCnt = blockSize / PARTITION_ENTRY_SIZE;
143     uint32_t partition0 = GET_LLWORD_FROM_BYTE(gptImage + blockSize + PARTITION_ENTRIES_OFFSET);
144 
145     uint32_t count = 0;
146     const uint8_t *data = nullptr;
147     for (uint32_t i = 0; i < (MAX_PARTITION_NUM / partEntryCnt) && count < MAX_PARTITION_NUM; i++) {
148         data = gptImage + (partition0 + i) * blockSize;
149         for (uint32_t j = 0; j < partEntryCnt; j++) {
150             uint8_t typeGuid[GPT_PARTITION_TYPE_GUID_LEN] = {0};
151             if (memcpy_s(typeGuid, sizeof(typeGuid), &data[(j * PARTITION_ENTRY_SIZE)], sizeof(typeGuid)) != EOK) {
152                 LOG(ERROR) << "memcpy guid fail";
153             }
154             if (typeGuid[0] == 0x00 && typeGuid[1] == 0x00) { // 0x00 means no partition
155                 i = MAX_PARTITION_NUM / partEntryCnt;
156                 break;
157             }
158             uint64_t firstLba = GET_LLWORD_FROM_BYTE(&data[(j * PARTITION_ENTRY_SIZE) + FIRST_LBA_OFFSET]);
159             uint64_t lastLba = GET_LLWORD_FROM_BYTE(&data[(j * PARTITION_ENTRY_SIZE) + LAST_LBA_OFFSET]);
160             // add a new partition info into partitionInfo_ vector
161             PtnInfo newPtnInfo = {};
162             newPtnInfo.startAddr = firstLba * static_cast<uint64_t>(GetDeviceBlockSize());
163             newPtnInfo.writePath = GetDeviceLunNodePath(lun);
164             // General algorithm : calculate partition size by lba
165             newPtnInfo.partitionSize = (lastLba - firstLba + 1) * static_cast<uint64_t>(GetDeviceBlockSize());
166             const uint8_t *nameOffset = data + (j * PARTITION_ENTRY_SIZE + GPT_PARTITION_NAME_OFFSET);
167             // 2 bytes for 1 charactor of partition name
168             ParsePartitionName(nameOffset, MAX_GPT_NAME_SIZE, newPtnInfo.dispName, MAX_GPT_NAME_SIZE / 2);
169             (void)memcpy_s(newPtnInfo.partitionTypeGuid, sizeof(newPtnInfo.partitionTypeGuid),
170                 typeGuid, sizeof(typeGuid));
171             newPtnInfo.lun = lun;
172             startIter = ++(partitionInfo_.insert(startIter, newPtnInfo));
173             count++;
174         }
175     }
176     return true;
177 }
178 
179 
UfsPatchGptHeader(UfsPartitionDataInfo & ptnDataInfo,const uint32_t blockSize)180 void UfsPtable::UfsPatchGptHeader(UfsPartitionDataInfo &ptnDataInfo, const uint32_t blockSize)
181 {
182     uint32_t deviceBlockSize = GetDeviceBlockSize();
183     // mbr len + gptHeader len = 2 blockSize
184     if (blockSize == 0 || ptnDataInfo.writeDataLen < 2 * blockSize || ptnDataInfo.lunSize == 0 ||
185         deviceBlockSize == 0) {
186         LOG(ERROR) << "invaild argument";
187         return;
188     }
189     uint64_t cardSizeSector = ptnDataInfo.lunSize / deviceBlockSize;
190     if (cardSizeSector == 0) {
191         cardSizeSector = DEFAULT_SECTOR_NUM;
192     }
193     // Patching primary header
194     uint8_t *primaryGptHeader = ptnDataInfo.data + blockSize;
195     uint64_t lastUsableSector = cardSizeSector - 1 - (hasBackupPtable_ ? GPT_PTABLE_BACKUP_SIZE : 0);
196     if (reservedSize_ != 0 && lastUsableSector > reservedSize_) {
197         LOG(INFO) << "reserve " << reservedSize_ << "block for " << GetDeviceLunNodePath(ptnDataInfo.lunIndex);
198         lastUsableSector -= reservedSize_;
199     }
200     LOG(INFO) << "cardSizeSector " << cardSizeSector << ", lastUsableSector " << lastUsableSector;
201     PUT_LONG_LONG(primaryGptHeader + BACKUP_HEADER_OFFSET, (cardSizeSector - 1));
202     PUT_LONG_LONG(primaryGptHeader + LAST_USABLE_LBA_OFFSET, lastUsableSector);
203     // Find last partition
204     uint32_t totalPart = 0;
205     while (((TMP_DATA_SIZE - blockSize - blockSize) > totalPart * PARTITION_ENTRY_SIZE) &&
206         (*(primaryGptHeader + blockSize + totalPart * PARTITION_ENTRY_SIZE) != 0)) {
207         totalPart++;
208     }
209     if (totalPart == 0) {
210         LOG(ERROR) << "no partition exist";
211         return;
212     }
213     // Patching last partition
214     uint8_t *lastPartOffset = primaryGptHeader + blockSize + (totalPart - 1) * PARTITION_ENTRY_SIZE;
215     uint64_t lastLba = GET_LLWORD_FROM_BYTE(lastPartOffset + PARTITION_ENTRY_LAST_LBA);
216     uint64_t firstLba = GET_LLWORD_FROM_BYTE(lastPartOffset + FIRST_LBA_OFFSET);
217     // General algorithm : calculate partition size by lba
218     uint64_t partitionSize = (lastLba - firstLba + 1) * deviceBlockSize;
219     std::string partitionName;
220     uint8_t *nameOffset = lastPartOffset + GPT_PARTITION_NAME_OFFSET;
221     // 2 bytes for 1 charactor of partition name
222     ParsePartitionName(nameOffset, MAX_GPT_NAME_SIZE, partitionName, MAX_GPT_NAME_SIZE / 2);
223     if (partitionName == USERDATA_PARTITION || (totalPart == 1 && partitionSize == 0)) {
224         // patch userdata or only one partition
225         PUT_LONG_LONG(lastPartOffset + PARTITION_ENTRY_LAST_LBA, lastUsableSector);
226         LOG(INFO) << "partitionSize=" << partitionSize << ", partition_name:" << partitionName;
227     }
228 
229     // Updating CRC of the Partition entry array in both headers
230     uint32_t partCount = GET_LWORD_FROM_BYTE(primaryGptHeader + PARTITION_COUNT_OFFSET);
231     uint32_t entrySize = GET_LWORD_FROM_BYTE(primaryGptHeader + PENTRY_SIZE_OFFSET);
232     // mbr len + gptHeader len = 2 blockSize
233     uint32_t crcValue = CalculateCrc32(ptnDataInfo.data + (blockSize * 2), partCount * entrySize);
234     PUT_LONG(primaryGptHeader + PARTITION_CRC_OFFSET, crcValue);
235     // Clearing CRC fields to calculate
236     PUT_LONG(primaryGptHeader + HEADER_CRC_OFFSET, 0);
237     crcValue = CalculateCrc32(primaryGptHeader, GPT_CRC_LEN);
238     PUT_LONG(primaryGptHeader + HEADER_CRC_OFFSET, crcValue);
239     return;
240 }
241 
242 // blocksize is 4096, lbaLen is 512. Because in ptable.img block is 512 while in device block is 4096
ParsePartitionFromBuffer(uint8_t * ptbImgBuffer,const uint32_t imgBufSize)243 bool UfsPtable::ParsePartitionFromBuffer(uint8_t *ptbImgBuffer, const uint32_t imgBufSize)
244 {
245     if (ptbImgBuffer == nullptr) {
246         LOG(ERROR) << "input param invalid";
247         return false;
248     }
249 
250     uint32_t imgBlockSize = ptableData_.lbaLen; // 512
251     uint32_t deviceBlockSize = GetDeviceBlockSize();
252     if (imgBufSize < ptableData_.emmcGptDataLen + ptableData_.imgLuSize + GetPtableExtraOffset()) {
253         LOG(ERROR) << "input param invalid imgBufSize";
254         return false;
255     }
256 
257     SetDeviceLunNum();
258     LOG(INFO) << "lun number of ptable:" << deviceLunNum_;
259 
260     for (uint32_t i = 0; i < deviceLunNum_; i++) {
261         UfsPartitionDataInfo newLunPtnDataInfo;
262         (void)memset_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, 0, TMP_DATA_SIZE);
263         uint8_t *lunStart = GetPtableImageUfsLunPmbrStart(ptbImgBuffer, i);
264         uint8_t *gptHeaderStart = GetPtableImageUfsLunGptHeaderStart(ptbImgBuffer, i);
265         // first block is mbr, second block is gptHeader
266         if (!CheckProtectiveMbr(lunStart, imgBlockSize) || !CheckIfValidGpt(gptHeaderStart, imgBlockSize)) {
267             newLunPtnDataInfo.isGptVaild = false;
268             ufsPtnDataInfo_.push_back(newLunPtnDataInfo);
269             continue;
270         }
271         // for hisi: change ptable.img(512 bytes/block) into format of device(4096 bytes/block)
272         if (memcpy_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, lunStart, imgBlockSize) != EOK) {
273             LOG(WARNING) << "memcpy_s pmbr fail";
274         }
275         if (memcpy_s(newLunPtnDataInfo.data + deviceBlockSize, TMP_DATA_SIZE - deviceBlockSize,
276             gptHeaderStart, imgBlockSize) != EOK) {
277             LOG(WARNING) << "memcpy_s gpt header fail";
278         }
279         // skip 2 lba length to set gpt entry
280         if (memcpy_s(newLunPtnDataInfo.data + 2 * deviceBlockSize, TMP_DATA_SIZE - 2 * deviceBlockSize,
281             GetPtableImageUfsLunEntryStart(ptbImgBuffer, i), GPT_ENTRYS_SIZE) != EOK) {
282             LOG(WARNING) << "memcpy_s gpt data fail";
283         }
284         newLunPtnDataInfo.writeDataLen = ptableData_.writeDeviceLunSize;
285         newLunPtnDataInfo.lunIndex = i + ptableData_.startLunNumber;
286         newLunPtnDataInfo.lunSize = GetDeviceLunCapacity(newLunPtnDataInfo.lunIndex);
287         UfsPatchGptHeader(newLunPtnDataInfo, deviceBlockSize);
288         newLunPtnDataInfo.isGptVaild = true;
289         ufsPtnDataInfo_.push_back(newLunPtnDataInfo);
290         if (!UfsReadGpt(newLunPtnDataInfo.data, newLunPtnDataInfo.writeDataLen,
291             newLunPtnDataInfo.lunIndex, deviceBlockSize)) {
292             LOG(ERROR) << "parse ufs gpt fail";
293             return false;
294         }
295     }
296     return true;
297 }
298 
ReadAndCheckMbr(const uint32_t lunIndex,const uint32_t blockSize)299 bool UfsPtable::ReadAndCheckMbr(const uint32_t lunIndex, const uint32_t blockSize)
300 {
301     if (blockSize <= 0 || lunIndex < 0 || lunIndex > deviceLunNum_) {
302         LOG(ERROR) << "blockSize <= 0";
303         return false;
304     }
305 
306     uint8_t *buffer = new(std::nothrow) uint8_t[blockSize]();
307     if (buffer == nullptr) {
308         LOG(ERROR) << "new buffer failed!";
309         return false;
310     }
311     std::string ufsNode = GetDeviceLunNodePath(lunIndex);
312     if (!MemReadWithOffset(ufsNode, 0, buffer, blockSize)) {
313         LOG(ERROR) << "read " << blockSize << " bytes from ufsNode " << ufsNode << " failed!";
314         delete [] buffer;
315         return false;
316     }
317 
318     bool result = CheckProtectiveMbr(buffer, blockSize);
319 
320     delete [] buffer;
321     return result;
322 }
323 
GetLunNumFromNode(const std::string & ufsNode)324 int32_t UfsPtable::GetLunNumFromNode(const std::string &ufsNode)
325 {
326     if (std::char_traits<char>::length(PREFIX_UFS_NODE) + 1 != ufsNode.length()) {
327         LOG(ERROR) << "ufsNode length is " << ufsNode.length() << ", \
328             not equal to PREFIX_UFS_NODE(" << std::char_traits<char>::length(PREFIX_UFS_NODE) << ") + 1";
329         return -1;
330     }
331     char ufsLunIndex = ufsNode.back();
332     // such as : 'a' - 'a'
333     return (ufsLunIndex - 'a');
334 }
335 
LoadPartitionInfoFromLun(const uint32_t lunIndex,const uint32_t imgLen)336 bool UfsPtable::LoadPartitionInfoFromLun(const uint32_t lunIndex, const uint32_t imgLen)
337 {
338     if (imgLen == 0 || lunIndex < 0 || lunIndex > deviceLunNum_) {
339         LOG(ERROR) << "imgLen or lunIndex is invaild " << imgLen << " " << lunIndex;
340         return false;
341     }
342     std::string ufsNode = GetDeviceLunNodePath(lunIndex);
343 
344     uint8_t *buffer = new(std::nothrow) uint8_t[imgLen]();
345     if (buffer == nullptr) {
346         LOG(ERROR) << "new buffer failed!";
347         return false;
348     }
349     if (!MemReadWithOffset(ufsNode, 0, buffer, imgLen)) {
350         LOG(ERROR) << "read " << imgLen << " bytes from ufsNode " << ufsNode << " failed!";
351         delete [] buffer;
352         return false;
353     }
354     UfsPartitionDataInfo newLunPtnDataInfo;
355     newLunPtnDataInfo.isGptVaild = true;
356     newLunPtnDataInfo.lunIndex = lunIndex;
357     newLunPtnDataInfo.lunSize = imgLen;
358     newLunPtnDataInfo.writeDataLen = imgLen;
359     (void)memset_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, 0, TMP_DATA_SIZE);
360     if (memcpy_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, buffer, imgLen) != EOK) {
361         LOG(WARNING) << "memcpy_s mbr fail";
362     }
363 
364     ufsPtnDataInfo_.push_back(newLunPtnDataInfo);
365     int32_t result = UfsReadGpt(buffer, imgLen, lunIndex, GetDeviceBlockSize());
366     delete [] buffer;
367     return result;
368 }
369 
LoadAllLunPartitions()370 uint32_t UfsPtable::LoadAllLunPartitions()
371 {
372     uint32_t lunIndex;
373     for (lunIndex = 0; lunIndex < deviceLunNum_; lunIndex++) {
374         if (ReadAndCheckMbr(lunIndex, GetDeviceBlockSize())) {
375             LoadPartitionInfoFromLun(lunIndex, ptableData_.writeDeviceLunSize);
376         }
377     }
378     return lunIndex;
379 }
380 
LoadPtableFromDevice()381 bool UfsPtable::LoadPtableFromDevice()
382 {
383     if (!partitionInfo_.empty()) {
384         LOG(INFO) << "ptable is already loaded to ram";
385         return true;
386     }
387     SetDeviceLunNum();
388     if (LoadAllLunPartitions() == 0) {
389         LOG(ERROR) << "init ptable to ram fail";
390         return false;
391     }
392     LOG(INFO) << "init ptable to ram ok";
393     return true;
394 }
395 
WritePartitionTable()396 bool UfsPtable::WritePartitionTable()
397 {
398     if (ufsPtnDataInfo_.empty()) {
399         LOG(ERROR) << "ufsPtnDataInfo_ is empty, write failed!";
400         return false;
401     }
402     for (uint32_t i = 0; i < ufsPtnDataInfo_.size(); i++) {
403         uint64_t writeDataLen = ufsPtnDataInfo_[i].writeDataLen;
404         std::string ufsNode = GetDeviceLunNodePath(ufsPtnDataInfo_[i].lunIndex);
405         LOG(INFO) << "ufs node name:" << ufsNode << ", writeDataLen = " << writeDataLen;
406 
407         if (!ufsPtnDataInfo_[i].isGptVaild) {
408             LOG(WARNING) <<  "invaild ptable, no need to update";
409             continue;
410         }
411         if (!WriteBufferToPath(ufsNode, 0, ufsPtnDataInfo_[i].data, writeDataLen)) {
412             LOG(ERROR) << "write first gpt fail";
413             return false;
414         }
415 #ifndef UPDATER_UT
416         if (hasBackupPtable_) {
417             LOG(INFO) << "should write back up ptable to device";
418             uint64_t lunSize = GetDeviceLunCapacity(ufsPtnDataInfo_[i].lunIndex);
419             WriteBackupPartitionTable(ufsPtnDataInfo_[i].lunIndex, lunSize);
420         }
421 #endif
422     }
423     return true;
424 }
425 
WriteBackupPartitionTable(uint32_t lunIdx,uint64_t lunSize)426 bool UfsPtable::WriteBackupPartitionTable(uint32_t lunIdx, uint64_t lunSize)
427 {
428     if (lunIdx >= ufsPtnDataInfo_.size()) {
429         LOG(ERROR) << "lunIdx invalid , lunIdx = " << lunIdx << ", ufsPtnDataInfo size = " << ufsPtnDataInfo_.size();
430         return false;
431     }
432 
433     std::string ufsNode = GetDeviceLunNodePath(lunIdx);
434     uint32_t deviceBlockSize = GetDeviceBlockSize();
435     if (lunSize == 0 || lunSize <= GPT_PTABLE_BACKUP_SIZE * deviceBlockSize) {
436         LOG(ERROR) << "lun size invalid, lun size = " << lunSize;
437         return false;
438     }
439     if (deviceBlockSize == 0) {
440         LOG(ERROR) << "deviceBlockSize is invalid";
441         return false;
442     }
443     uint64_t deviceBackGptEntryOffset = lunSize - GPT_PTABLE_BACKUP_SIZE * deviceBlockSize;
444     uint64_t deviceBackGptHeaderOffset = lunSize - deviceBlockSize;
445     std::unique_ptr<uint8_t[]> backUpHeader = std::make_unique<uint8_t[]>(deviceBlockSize);
446     if (memcpy_s(backUpHeader.get(), deviceBlockSize, ufsPtnDataInfo_[lunIdx].data +
447         deviceBlockSize, deviceBlockSize) != EOK) {
448         LOG(ERROR) << "memcpy error, deviceBlockSize:" << deviceBlockSize;
449         return false;
450     }
451     PatchBackUpGptHeader(backUpHeader.get(), deviceBlockSize, deviceBackGptEntryOffset / deviceBlockSize);
452     if (!WriteBufferToPath(ufsNode, deviceBackGptHeaderOffset, backUpHeader.get(), deviceBlockSize)) {
453         LOG(ERROR) << "write back up gpt header failed, deviceBackGptHeaderOffset = " << deviceBackGptHeaderOffset
454             << ", deviceBlockSize = " << deviceBlockSize;
455         return false;
456     }
457 
458     if (!WriteBufferToPath(ufsNode, deviceBackGptEntryOffset, ufsPtnDataInfo_[lunIdx].data +
459         deviceBlockSize * 2, (GPT_PTABLE_BACKUP_SIZE - 1) * deviceBlockSize)) { // 2 : pmbr(1) + gpt header(1)
460         LOG(ERROR) << "write back up gpt entries failed, deviceBackGptEntryOffset = " << deviceBackGptEntryOffset
461             << ", deviceBlockSize = " << deviceBlockSize;
462         return false;
463     }
464     LOG(INFO) << "write backup partition table successful";
465     return true;
466 }
467 
GetPtableImageUfsLunPmbrStart(uint8_t * imageBuf,const uint32_t lunIndex)468 uint8_t *UfsPtable::GetPtableImageUfsLunPmbrStart(uint8_t *imageBuf, const uint32_t lunIndex)
469 {
470     uint32_t pmbrStart = ptableData_.emmcGptDataLen + GetPtableExtraOffset() + lunIndex * ptableData_.imgLuSize;
471     LOG(INFO) << "GetPtableImageUfsLunPmbrStart : " << std::hex << pmbrStart << std::dec;
472     return imageBuf + pmbrStart;
473 }
474 
GetPtableImageUfsLunGptHeaderStart(uint8_t * imageBuf,const uint32_t lunIndex)475 uint8_t *UfsPtable::GetPtableImageUfsLunGptHeaderStart(uint8_t *imageBuf, const uint32_t lunIndex)
476 {
477     uint32_t gptHeaderStart = ptableData_.emmcGptDataLen + GetPtableExtraOffset() + lunIndex * ptableData_.imgLuSize +
478         ptableData_.lbaLen;
479     LOG(INFO) << "GetPtableImageUfsLunGptHeaderStart : " << std::hex << gptHeaderStart << std::dec;
480     return imageBuf + gptHeaderStart;
481 }
482 
GetPtableImageUfsLunEntryStart(uint8_t * imageBuf,const uint32_t lunIndex)483 uint8_t *UfsPtable::GetPtableImageUfsLunEntryStart(uint8_t *imageBuf, const uint32_t lunIndex)
484 {
485     uint32_t entryStart = ptableData_.emmcGptDataLen + GetPtableExtraOffset() + lunIndex * ptableData_.imgLuSize +
486         ptableData_.lbaLen + ptableData_.gptHeaderLen;
487     LOG(INFO) << "GetPtableImageUfsLunEntryStart : " << std::hex << entryStart << std::dec;
488     return imageBuf + entryStart;
489 }
490 
EditPartitionBuf(uint8_t * imageBuf,uint64_t imgBufSize,std::vector<PtnInfo> & modifyList)491 bool UfsPtable::EditPartitionBuf(uint8_t *imageBuf, uint64_t imgBufSize, std::vector<PtnInfo> &modifyList)
492 {
493     if (imageBuf == nullptr || imgBufSize == 0 || modifyList.empty() || ptableData_.blockSize == 0) {
494         LOG(ERROR) << "input invalid";
495         return false;
496     }
497     if (imgBufSize < ptableData_.emmcGptDataLen || deviceLunNum_ == 0) {
498         LOG(ERROR) << "can not get offset, imgBufsize =" << imgBufSize << ",emmcGptDataLen ="
499             << ptableData_.emmcGptDataLen << ", deviceLunNum = " << deviceLunNum_;
500         return false;
501     }
502 
503     uint32_t gptSize = ptableData_.imgLuSize;
504     uint32_t imgBlockSize = ptableData_.lbaLen; // 512
505     uint32_t deviceBlockSize = GetDeviceBlockSize(); // 4096 or 512
506     uint32_t startLu = ptableData_.startLunNumber;
507     for (uint32_t i = 0; i < deviceLunNum_; ++i) {
508         UfsPartitionDataInfo newLunPtnDataInfo;
509         (void)memset_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, 0, TMP_DATA_SIZE);
510         std::string ufsNode = GetDeviceLunNodePath(i + startLu);
511         newLunPtnDataInfo.lunSize = GetDeviceLunCapacity(i + startLu);
512         if (newLunPtnDataInfo.lunSize == 0) {
513             LOG(ERROR) << "get devDenisity failed in " << ufsNode;
514             return false;
515         }
516         uint8_t *curGptBuf = GetPtableImageUfsLunPmbrStart(imageBuf, i + startLu);
517         if (!ufsPtnDataInfo_[i].isGptVaild) {
518             continue;
519         }
520         struct GptParseInfo gptInfo(imgBlockSize, deviceBlockSize, newLunPtnDataInfo.lunSize -
521             (hasBackupPtable_ ? (GPT_PTABLE_BACKUP_SIZE * deviceBlockSize) : 0));
522         for (auto &t : modifyList) {
523             if (static_cast<uint32_t>(t.lun) == i + startLu && !ChangeGpt(curGptBuf, gptSize, gptInfo, t)) {
524                 LOG(ERROR) << "ChangeGpt failed";
525                 return false;
526             }
527         }
528         /* mbr block = 1 block */
529         if (memcpy_s(newLunPtnDataInfo.data, TMP_DATA_SIZE, curGptBuf, imgBlockSize) != EOK) {
530             LOG(WARNING) << "memcpy_s fail";
531         }
532         newLunPtnDataInfo.writeDataLen = ptableData_.writeDeviceLunSize;
533         UfsPatchGptHeader(newLunPtnDataInfo, imgBlockSize);
534     }
535     return true;
536 }
537 
GetPtableImageBuffer(uint8_t * imageBuf,const uint32_t imgBufSize)538 bool UfsPtable::GetPtableImageBuffer(uint8_t *imageBuf, const uint32_t imgBufSize)
539 {
540     uint32_t imgBlockSize = ptableData_.lbaLen; // 512
541     uint32_t deviceBlockSize = GetDeviceBlockSize();
542     SetDeviceLunNum();
543     if (imageBuf == nullptr || imgBufSize == 0 ||
544         imgBufSize < ptableData_.emmcGptDataLen + GetPtableExtraOffset() + ptableData_.imgLuSize * deviceLunNum_) {
545         LOG(ERROR) << "input param invalid";
546         return false;
547     }
548     for (uint32_t i = 0; i < deviceLunNum_; ++i) {
549         uint32_t curImgOffset = 0;
550         uint32_t curDevOffset = 0;
551         uint32_t imgOffset = ptableData_.emmcGptDataLen + GetPtableExtraOffset() + ptableData_.imgLuSize * i;
552         /* get ufs node name */
553         std::string ufsNode = GetDeviceLunNodePath(i + ptableData_.startLunNumber);
554         if (!CheckFileExist(ufsNode)) {
555             LOG(ERROR) << "file " << ufsNode << " is not exist";
556             return false;
557         }
558         /* get mbr head */
559         if (!MemReadWithOffset(ufsNode, curDevOffset, imageBuf + curImgOffset + imgOffset, imgBlockSize)) {
560             LOG(ERROR) << "MemReadWithOffset " << ufsNode << " error";
561             return false;
562         }
563         bool isGptExist = CheckProtectiveMbr(imageBuf + curImgOffset + imgOffset, imgBlockSize);
564         curImgOffset += imgBlockSize;
565         curDevOffset += deviceBlockSize;
566         if (!isGptExist) {
567             continue;
568         }
569         /* get gpt head */
570         if (!MemReadWithOffset(ufsNode, curDevOffset, imageBuf + curImgOffset + imgOffset, imgBlockSize)) {
571             LOG(ERROR) << "MemReadWithOffset " << ufsNode << " error";
572             return false;
573         }
574         uint32_t maxPartCount = GET_LWORD_FROM_BYTE(&imageBuf[imgOffset + curImgOffset + PARTITION_COUNT_OFFSET]);
575         uint32_t entrySize = GET_LWORD_FROM_BYTE(&imageBuf[imgOffset + curImgOffset + PENTRY_SIZE_OFFSET]);
576         curImgOffset += imgBlockSize;
577         curDevOffset += deviceBlockSize;
578         /* get gpt buf */
579         uint32_t gptInfoLen = maxPartCount * entrySize;
580         if (!MemReadWithOffset(ufsNode, curDevOffset, imageBuf + curImgOffset + imgOffset, gptInfoLen)) {
581             LOG(ERROR) << "MemReadWithOffset " << ufsNode << " error" << gptInfoLen;
582             return false;
583         }
584     }
585     return true;
586 }
587 } // namespace Updater
588