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
27namespace Updater {
28uint32_t UfsPtable::GetDeviceLunNum()
29{
30    return deviceLunNum_;
31}
32
33uint64_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
42uint32_t UfsPtable::GetPtableExtraOffset(void)
43{
44    return 0;
45}
46
47// avoid u disk being recognized as a valid gpt lun device
48bool 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
67uint32_t UfsPtable::GetDeviceBlockSize(void)
68{
69    return ptableData_.blockSize;
70}
71
72std::string UfsPtable::GetDeviceLunNodePath(const uint32_t lun)
73{
74    char lunIndexName = 'a' + lun;
75    return std::string(PREFIX_UFS_NODE) + lunIndexName;
76}
77
78void 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
102bool 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
121bool 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
180void 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
243bool 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
299bool 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
324int32_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
336bool 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
370uint32_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
381bool 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
396bool 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
426bool 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
468uint8_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
475uint8_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
483uint8_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
491bool 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
538bool 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