1fb299fa2Sopenharmony_ci/*
2fb299fa2Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd.
3fb299fa2Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4fb299fa2Sopenharmony_ci * you may not use this file except in compliance with the License.
5fb299fa2Sopenharmony_ci * You may obtain a copy of the License at
6fb299fa2Sopenharmony_ci *
7fb299fa2Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8fb299fa2Sopenharmony_ci *
9fb299fa2Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10fb299fa2Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11fb299fa2Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12fb299fa2Sopenharmony_ci * See the License for the specific language governing permissions and
13fb299fa2Sopenharmony_ci * limitations under the License.
14fb299fa2Sopenharmony_ci */
15fb299fa2Sopenharmony_ci
16fb299fa2Sopenharmony_ci#include "blocks_patch.h"
17fb299fa2Sopenharmony_ci#include <cstdio>
18fb299fa2Sopenharmony_ci#include <iostream>
19fb299fa2Sopenharmony_ci#include <vector>
20fb299fa2Sopenharmony_ci#include "diffpatch.h"
21fb299fa2Sopenharmony_ci
22fb299fa2Sopenharmony_ciusing namespace Hpackage;
23fb299fa2Sopenharmony_ciusing namespace std;
24fb299fa2Sopenharmony_ci
25fb299fa2Sopenharmony_cinamespace UpdatePatch {
26fb299fa2Sopenharmony_ci#define PATCH_MIN std::char_traits<char>::length(BSDIFF_MAGIC) + sizeof(int64_t) * 3
27fb299fa2Sopenharmony_ci#define GET_BYTE_FROM_BUFFER(v, index, buffer)  ((v) * 256 + (buffer)[index])
28fb299fa2Sopenharmony_ciconstexpr uint8_t BUFFER_MASK = 0x80;
29fb299fa2Sopenharmony_ci
30fb299fa2Sopenharmony_cistatic int64_t ReadLE64(const uint8_t *buffer)
31fb299fa2Sopenharmony_ci{
32fb299fa2Sopenharmony_ci    if (buffer == nullptr) {
33fb299fa2Sopenharmony_ci        return 0;
34fb299fa2Sopenharmony_ci    }
35fb299fa2Sopenharmony_ci    int64_t y = 0;
36fb299fa2Sopenharmony_ci    int32_t index = static_cast<int32_t>(sizeof(int64_t)) - 1;
37fb299fa2Sopenharmony_ci    y = buffer[index] & static_cast<uint8_t>(~BUFFER_MASK);
38fb299fa2Sopenharmony_ci    index--;
39fb299fa2Sopenharmony_ci    y = GET_BYTE_FROM_BUFFER(y, index, buffer);
40fb299fa2Sopenharmony_ci    index--;
41fb299fa2Sopenharmony_ci    y = GET_BYTE_FROM_BUFFER(y, index, buffer);
42fb299fa2Sopenharmony_ci    index--;
43fb299fa2Sopenharmony_ci    y = GET_BYTE_FROM_BUFFER(y, index, buffer);
44fb299fa2Sopenharmony_ci    index--;
45fb299fa2Sopenharmony_ci    y = GET_BYTE_FROM_BUFFER(y, index, buffer);
46fb299fa2Sopenharmony_ci    index--;
47fb299fa2Sopenharmony_ci    y = GET_BYTE_FROM_BUFFER(y, index, buffer);
48fb299fa2Sopenharmony_ci    index--;
49fb299fa2Sopenharmony_ci    y = GET_BYTE_FROM_BUFFER(y, index, buffer);
50fb299fa2Sopenharmony_ci    index--;
51fb299fa2Sopenharmony_ci    y = GET_BYTE_FROM_BUFFER(y, index, buffer);
52fb299fa2Sopenharmony_ci
53fb299fa2Sopenharmony_ci    index = static_cast<int32_t>(sizeof(int64_t));
54fb299fa2Sopenharmony_ci    if (buffer[index - 1] & BUFFER_MASK) {
55fb299fa2Sopenharmony_ci        y = -y;
56fb299fa2Sopenharmony_ci    }
57fb299fa2Sopenharmony_ci    return y;
58fb299fa2Sopenharmony_ci}
59fb299fa2Sopenharmony_ci
60fb299fa2Sopenharmony_ciint32_t BlocksPatch::ApplyPatch()
61fb299fa2Sopenharmony_ci{
62fb299fa2Sopenharmony_ci    int64_t controlDataSize = 0;
63fb299fa2Sopenharmony_ci    int64_t diffDataSize = 0;
64fb299fa2Sopenharmony_ci    int32_t ret = ReadHeader(controlDataSize, diffDataSize, newSize_);
65fb299fa2Sopenharmony_ci    if (ret != 0) {
66fb299fa2Sopenharmony_ci        PATCH_LOGE("Failed to read header ");
67fb299fa2Sopenharmony_ci        return -1;
68fb299fa2Sopenharmony_ci    }
69fb299fa2Sopenharmony_ci
70fb299fa2Sopenharmony_ci    while (newOffset_ < newSize_) {
71fb299fa2Sopenharmony_ci        ControlData ctrlData {};
72fb299fa2Sopenharmony_ci        ret = ReadControlData(ctrlData);
73fb299fa2Sopenharmony_ci        if (ret != 0) {
74fb299fa2Sopenharmony_ci            PATCH_LOGE("Failed to read control data");
75fb299fa2Sopenharmony_ci            return ret;
76fb299fa2Sopenharmony_ci        }
77fb299fa2Sopenharmony_ci        if (newOffset_ + ctrlData.diffLength > newSize_) {
78fb299fa2Sopenharmony_ci            PATCH_LOGE("Failed to check new offset %ld %zu", ctrlData.diffLength, newOffset_);
79fb299fa2Sopenharmony_ci            return PATCH_INVALID_PATCH;
80fb299fa2Sopenharmony_ci        }
81fb299fa2Sopenharmony_ci
82fb299fa2Sopenharmony_ci        ret = RestoreDiffData(ctrlData);
83fb299fa2Sopenharmony_ci        if (ret != 0) {
84fb299fa2Sopenharmony_ci            PATCH_LOGE("Failed to read diff data");
85fb299fa2Sopenharmony_ci            return ret;
86fb299fa2Sopenharmony_ci        }
87fb299fa2Sopenharmony_ci        oldOffset_ += ctrlData.diffLength;
88fb299fa2Sopenharmony_ci        newOffset_ += ctrlData.diffLength;
89fb299fa2Sopenharmony_ci        if (newOffset_ + ctrlData.extraLength > newSize_) {
90fb299fa2Sopenharmony_ci            PATCH_LOGE("Failed to check new offset %ld %zu", ctrlData.diffLength, newOffset_);
91fb299fa2Sopenharmony_ci            return PATCH_INVALID_PATCH;
92fb299fa2Sopenharmony_ci        }
93fb299fa2Sopenharmony_ci
94fb299fa2Sopenharmony_ci        ret = RestoreExtraData(ctrlData);
95fb299fa2Sopenharmony_ci        if (ret != 0) {
96fb299fa2Sopenharmony_ci            PATCH_LOGE("Failed to read extra data");
97fb299fa2Sopenharmony_ci            return ret;
98fb299fa2Sopenharmony_ci        }
99fb299fa2Sopenharmony_ci
100fb299fa2Sopenharmony_ci        newOffset_ += ctrlData.extraLength;
101fb299fa2Sopenharmony_ci        oldOffset_ += ctrlData.offsetIncrement;
102fb299fa2Sopenharmony_ci    }
103fb299fa2Sopenharmony_ci    controlDataReader_->Close();
104fb299fa2Sopenharmony_ci    diffDataReader_->Close();
105fb299fa2Sopenharmony_ci    extraDataReader_->Close();
106fb299fa2Sopenharmony_ci    return 0;
107fb299fa2Sopenharmony_ci}
108fb299fa2Sopenharmony_ci
109fb299fa2Sopenharmony_ciint32_t BlocksPatch::ReadHeader(int64_t &controlDataSize, int64_t &diffDataSize, int64_t &newSize)
110fb299fa2Sopenharmony_ci{
111fb299fa2Sopenharmony_ci    if (patchInfo_.buffer == nullptr || patchInfo_.length < patchInfo_.start ||
112fb299fa2Sopenharmony_ci        patchInfo_.length - patchInfo_.start <= PATCH_MIN) {
113fb299fa2Sopenharmony_ci        PATCH_LOGE("Invalid parm");
114fb299fa2Sopenharmony_ci        return -1;
115fb299fa2Sopenharmony_ci    }
116fb299fa2Sopenharmony_ci    BlockBuffer patchData = {patchInfo_.buffer + patchInfo_.start, patchInfo_.length - patchInfo_.start};
117fb299fa2Sopenharmony_ci    PATCH_DEBUG("Restore patch hash %zu %zu %s",
118fb299fa2Sopenharmony_ci        patchInfo_.length, patchInfo_.start, GeneraterBufferHash(patchData).c_str());
119fb299fa2Sopenharmony_ci    uint8_t *header = patchInfo_.buffer + patchInfo_.start;
120fb299fa2Sopenharmony_ci    if (memcmp(header, BSDIFF_MAGIC, std::char_traits<char>::length(BSDIFF_MAGIC)) != 0) {
121fb299fa2Sopenharmony_ci        PATCH_LOGE("Corrupt patch, patch head != BSDIFF40");
122fb299fa2Sopenharmony_ci        return -1;
123fb299fa2Sopenharmony_ci    }
124fb299fa2Sopenharmony_ci    /* Read lengths from header */
125fb299fa2Sopenharmony_ci    size_t offset = std::char_traits<char>::length(BSDIFF_MAGIC);
126fb299fa2Sopenharmony_ci    controlDataSize = ReadLE64(header + offset);
127fb299fa2Sopenharmony_ci    offset += sizeof(int64_t);
128fb299fa2Sopenharmony_ci    diffDataSize = ReadLE64(header + offset);
129fb299fa2Sopenharmony_ci    offset += sizeof(int64_t);
130fb299fa2Sopenharmony_ci    newSize = ReadLE64(header + offset);
131fb299fa2Sopenharmony_ci    offset += sizeof(int64_t);
132fb299fa2Sopenharmony_ci    if (controlDataSize < 0) {
133fb299fa2Sopenharmony_ci        PATCH_LOGE("Invalid control data size");
134fb299fa2Sopenharmony_ci        return -1;
135fb299fa2Sopenharmony_ci    }
136fb299fa2Sopenharmony_ci    if (newSize < 0) {
137fb299fa2Sopenharmony_ci        PATCH_LOGE("Invalid new data size");
138fb299fa2Sopenharmony_ci        return -1;
139fb299fa2Sopenharmony_ci    }
140fb299fa2Sopenharmony_ci    if (diffDataSize < 0 || (diffDataSize + controlDataSize) > static_cast<int64_t>(patchInfo_.length)) {
141fb299fa2Sopenharmony_ci        PATCH_LOGE("Invalid patch data size");
142fb299fa2Sopenharmony_ci        return -1;
143fb299fa2Sopenharmony_ci    }
144fb299fa2Sopenharmony_ci    BlockBuffer patchBuffer = {header, patchInfo_.length - patchInfo_.start};
145fb299fa2Sopenharmony_ci    controlDataReader_.reset(new BZip2BufferReadAdapter(offset, static_cast<size_t>(controlDataSize), patchBuffer));
146fb299fa2Sopenharmony_ci    offset += static_cast<size_t>(controlDataSize);
147fb299fa2Sopenharmony_ci    diffDataReader_.reset(new BZip2BufferReadAdapter(offset, static_cast<size_t>(diffDataSize), patchBuffer));
148fb299fa2Sopenharmony_ci    offset += static_cast<size_t>(diffDataSize);
149fb299fa2Sopenharmony_ci    extraDataReader_.reset(new BZip2BufferReadAdapter(offset,
150fb299fa2Sopenharmony_ci        patchInfo_.length - patchInfo_.start - offset, patchBuffer));
151fb299fa2Sopenharmony_ci    if (controlDataReader_ == nullptr || diffDataReader_ == nullptr || extraDataReader_ == nullptr) {
152fb299fa2Sopenharmony_ci        PATCH_LOGE("Failed to create reader");
153fb299fa2Sopenharmony_ci        return -1;
154fb299fa2Sopenharmony_ci    }
155fb299fa2Sopenharmony_ci    controlDataReader_->Open();
156fb299fa2Sopenharmony_ci    diffDataReader_->Open();
157fb299fa2Sopenharmony_ci    extraDataReader_->Open();
158fb299fa2Sopenharmony_ci    return 0;
159fb299fa2Sopenharmony_ci}
160fb299fa2Sopenharmony_ci
161fb299fa2Sopenharmony_ciint32_t BlocksPatch::ReadControlData(ControlData &ctrlData)
162fb299fa2Sopenharmony_ci{
163fb299fa2Sopenharmony_ci    std::vector<uint8_t> data(sizeof(int64_t), 0);
164fb299fa2Sopenharmony_ci    BlockBuffer info = {data.data(), sizeof(int64_t)};
165fb299fa2Sopenharmony_ci    int32_t ret = controlDataReader_->ReadData(info);
166fb299fa2Sopenharmony_ci    if (ret != 0) {
167fb299fa2Sopenharmony_ci        PATCH_LOGE("Failed to read diffLength");
168fb299fa2Sopenharmony_ci        return ret;
169fb299fa2Sopenharmony_ci    }
170fb299fa2Sopenharmony_ci    ctrlData.diffLength = ReadLE64(info.buffer);
171fb299fa2Sopenharmony_ci    ret = controlDataReader_->ReadData(info);
172fb299fa2Sopenharmony_ci    if (ret != 0) {
173fb299fa2Sopenharmony_ci        PATCH_LOGE("Failed to read extraLength");
174fb299fa2Sopenharmony_ci        return ret;
175fb299fa2Sopenharmony_ci    }
176fb299fa2Sopenharmony_ci    ctrlData.extraLength = ReadLE64(info.buffer);
177fb299fa2Sopenharmony_ci    ret = controlDataReader_->ReadData(info);
178fb299fa2Sopenharmony_ci    if (ret != 0) {
179fb299fa2Sopenharmony_ci        PATCH_LOGE("Failed to read offsetIncrement");
180fb299fa2Sopenharmony_ci        return ret;
181fb299fa2Sopenharmony_ci    }
182fb299fa2Sopenharmony_ci    ctrlData.offsetIncrement = ReadLE64(info.buffer);
183fb299fa2Sopenharmony_ci    return 0;
184fb299fa2Sopenharmony_ci}
185fb299fa2Sopenharmony_ci
186fb299fa2Sopenharmony_ciint32_t BlocksBufferPatch::ReadHeader(int64_t &controlDataSize, int64_t &diffDataSize, int64_t &newSize)
187fb299fa2Sopenharmony_ci{
188fb299fa2Sopenharmony_ci    int32_t ret = BlocksPatch::ReadHeader(controlDataSize, diffDataSize, newSize);
189fb299fa2Sopenharmony_ci    if (ret != 0) {
190fb299fa2Sopenharmony_ci        PATCH_LOGE("Failed to read header");
191fb299fa2Sopenharmony_ci        return -1;
192fb299fa2Sopenharmony_ci    }
193fb299fa2Sopenharmony_ci    PATCH_LOGI("ReadHeader controlDataSize: %ld %ld %ld", controlDataSize, diffDataSize, newSize);
194fb299fa2Sopenharmony_ci    newData_.resize(newSize);
195fb299fa2Sopenharmony_ci    return 0;
196fb299fa2Sopenharmony_ci}
197fb299fa2Sopenharmony_ci
198fb299fa2Sopenharmony_ciint32_t BlocksBufferPatch::RestoreDiffData(const ControlData &ctrlData)
199fb299fa2Sopenharmony_ci{
200fb299fa2Sopenharmony_ci    if (ctrlData.diffLength <= 0) {
201fb299fa2Sopenharmony_ci        return 0;
202fb299fa2Sopenharmony_ci    }
203fb299fa2Sopenharmony_ci    BlockBuffer diffData = {newData_.data() + newOffset_, static_cast<size_t>(ctrlData.diffLength)};
204fb299fa2Sopenharmony_ci    int32_t ret = diffDataReader_->ReadData(diffData);
205fb299fa2Sopenharmony_ci    if (ret != 0) {
206fb299fa2Sopenharmony_ci        PATCH_LOGE("Failed to read diff data");
207fb299fa2Sopenharmony_ci        return ret;
208fb299fa2Sopenharmony_ci    }
209fb299fa2Sopenharmony_ci
210fb299fa2Sopenharmony_ci    for (int64_t i = 0; i < ctrlData.diffLength; i++) {
211fb299fa2Sopenharmony_ci        if (((oldOffset_ + i) >= 0) && (static_cast<size_t>(oldOffset_ + i) < oldInfo_.length)) {
212fb299fa2Sopenharmony_ci            newData_[newOffset_ + i] += oldInfo_.buffer[oldOffset_ + i];
213fb299fa2Sopenharmony_ci        }
214fb299fa2Sopenharmony_ci    }
215fb299fa2Sopenharmony_ci    return 0;
216fb299fa2Sopenharmony_ci}
217fb299fa2Sopenharmony_ci
218fb299fa2Sopenharmony_ciint32_t BlocksBufferPatch::RestoreExtraData(const ControlData &ctrlData)
219fb299fa2Sopenharmony_ci{
220fb299fa2Sopenharmony_ci    if (ctrlData.extraLength <= 0) {
221fb299fa2Sopenharmony_ci        return 0;
222fb299fa2Sopenharmony_ci    }
223fb299fa2Sopenharmony_ci    BlockBuffer extraData = {newData_.data() + newOffset_, static_cast<size_t>(ctrlData.extraLength)};
224fb299fa2Sopenharmony_ci    int32_t ret = extraDataReader_->ReadData(extraData);
225fb299fa2Sopenharmony_ci    if (ret != 0) {
226fb299fa2Sopenharmony_ci        PATCH_LOGE("Failed to read extra data");
227fb299fa2Sopenharmony_ci        return ret;
228fb299fa2Sopenharmony_ci    }
229fb299fa2Sopenharmony_ci    return 0;
230fb299fa2Sopenharmony_ci}
231fb299fa2Sopenharmony_ci
232fb299fa2Sopenharmony_ciint32_t BlocksStreamPatch::RestoreDiffData(const ControlData &ctrlData)
233fb299fa2Sopenharmony_ci{
234fb299fa2Sopenharmony_ci    if (ctrlData.diffLength <= 0) {
235fb299fa2Sopenharmony_ci        return 0;
236fb299fa2Sopenharmony_ci    }
237fb299fa2Sopenharmony_ci    std::vector<uint8_t> diffData(ctrlData.diffLength);
238fb299fa2Sopenharmony_ci    BlockBuffer diffBuffer = {diffData.data(), diffData.size()};
239fb299fa2Sopenharmony_ci    int32_t ret = diffDataReader_->ReadData(diffBuffer);
240fb299fa2Sopenharmony_ci    if (ret != 0) {
241fb299fa2Sopenharmony_ci        PATCH_LOGE("Failed to read diff data");
242fb299fa2Sopenharmony_ci        return ret;
243fb299fa2Sopenharmony_ci    }
244fb299fa2Sopenharmony_ci
245fb299fa2Sopenharmony_ci    size_t oldOffset = static_cast<size_t>(oldOffset_);
246fb299fa2Sopenharmony_ci    size_t oldLength = stream_->GetFileLength();
247fb299fa2Sopenharmony_ci    PkgBuffer buffer {};
248fb299fa2Sopenharmony_ci    if (stream_->GetStreamType() == PkgStream::PkgStreamType_MemoryMap ||
249fb299fa2Sopenharmony_ci        stream_->GetStreamType() == PkgStream::PkgStreamType_Buffer) {
250fb299fa2Sopenharmony_ci        ret = stream_->GetBuffer(buffer);
251fb299fa2Sopenharmony_ci        if (ret != 0) {
252fb299fa2Sopenharmony_ci            PATCH_LOGE("Failed to get old buffer");
253fb299fa2Sopenharmony_ci            return ret;
254fb299fa2Sopenharmony_ci        }
255fb299fa2Sopenharmony_ci    } else {
256fb299fa2Sopenharmony_ci        std::vector<uint8_t> oldData(ctrlData.diffLength);
257fb299fa2Sopenharmony_ci        size_t readLen = 0;
258fb299fa2Sopenharmony_ci        ret = stream_->Read(buffer, oldOffset_, ctrlData.diffLength, readLen);
259fb299fa2Sopenharmony_ci        if (ret != 0 || readLen != static_cast<size_t>(ctrlData.diffLength)) {
260fb299fa2Sopenharmony_ci            PATCH_LOGE("Failed to get old buffer");
261fb299fa2Sopenharmony_ci            return ret;
262fb299fa2Sopenharmony_ci        }
263fb299fa2Sopenharmony_ci        oldOffset = 0;
264fb299fa2Sopenharmony_ci    }
265fb299fa2Sopenharmony_ci    for (int64_t i = 0; i < ctrlData.diffLength; i++) {
266fb299fa2Sopenharmony_ci        if ((oldOffset_ + i >= 0) && (static_cast<size_t>(oldOffset_ + i) < oldLength)) {
267fb299fa2Sopenharmony_ci            diffData[i] += buffer.buffer[static_cast<int64_t>(oldOffset) + i];
268fb299fa2Sopenharmony_ci        }
269fb299fa2Sopenharmony_ci    }
270fb299fa2Sopenharmony_ci    // write
271fb299fa2Sopenharmony_ci    return writer_->Write(newOffset_, diffBuffer, static_cast<size_t>(ctrlData.diffLength));
272fb299fa2Sopenharmony_ci}
273fb299fa2Sopenharmony_ci
274fb299fa2Sopenharmony_ciint32_t BlocksStreamPatch::RestoreExtraData(const ControlData &ctrlData)
275fb299fa2Sopenharmony_ci{
276fb299fa2Sopenharmony_ci    if (ctrlData.extraLength <= 0) {
277fb299fa2Sopenharmony_ci        return 0;
278fb299fa2Sopenharmony_ci    }
279fb299fa2Sopenharmony_ci    std::vector<uint8_t> extraData(ctrlData.extraLength);
280fb299fa2Sopenharmony_ci    BlockBuffer extraBuffer = {extraData.data(), static_cast<size_t>(ctrlData.extraLength)};
281fb299fa2Sopenharmony_ci    int32_t ret = extraDataReader_->ReadData(extraBuffer);
282fb299fa2Sopenharmony_ci    if (ret != 0) {
283fb299fa2Sopenharmony_ci        PATCH_LOGE("Failed to read extra data");
284fb299fa2Sopenharmony_ci        return ret;
285fb299fa2Sopenharmony_ci    }
286fb299fa2Sopenharmony_ci    // write
287fb299fa2Sopenharmony_ci    return writer_->Write(newOffset_, extraBuffer, static_cast<size_t>(ctrlData.extraLength));
288fb299fa2Sopenharmony_ci}
289fb299fa2Sopenharmony_ci} // namespace UpdatePatch
290