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