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#ifndef DIFF_PATCH_H
17#define DIFF_PATCH_H
18
19#ifdef __WIN32
20#include "pkg_utils.h"
21#else
22#include <sys/mman.h>
23#endif
24#include <cstdlib>
25#include <unistd.h>
26#include <vector>
27#include "log/log.h"
28#include "patch/update_patch.h"
29
30namespace UpdatePatch {
31#ifdef __WIN32
32#undef ERROR
33#endif
34
35#define PATCH_LOGE(format, ...) Logger(Updater::ERROR, (UPDATER_LOG_FILE_NAME), (__LINE__), format, ##__VA_ARGS__)
36#define PATCH_DEBUG(format, ...) Logger(Updater::DEBUG, (UPDATER_LOG_FILE_NAME), (__LINE__), format, ##__VA_ARGS__)
37#define PATCH_LOGI(format, ...) Logger(Updater::INFO, (UPDATER_LOG_FILE_NAME), (__LINE__), format, ##__VA_ARGS__)
38#define PATCH_LOGW(format, ...) Logger(Updater::WARNING, (UPDATER_LOG_FILE_NAME), (__LINE__), format, ##__VA_ARGS__)
39
40enum {
41    PATCH_SUCCESS = 0,
42	PATCH_INVALID_PARAM,
43    PATCH_NEW_FILE,
44    PATCH_EXCEED_LIMIT,
45    PATCH_INVALID_PATCH,
46};
47
48/*
49 * The pkgdiff patch header looks like this:
50 *
51 *    "pkgdiff0"                  (8)   [magic number and version]
52 *    block count                 (4)
53 *    for each block:
54 *        block type              (4)   [BLOCK_{NORMAL, DEFLATE, RAW, Lz4}]
55 *        if block type == BLOCK_NORMAL:
56 *           source start         (8)
57 *           source len           (8)
58 *           bsdiff patch offset  (8)   [from start of patch file]
59 *        if block type == BLOCK_DEFLATE:
60 *           source start         (8)
61 *           source len           (8)
62 *           bsdiff patch offset  (8)   [from start of patch file]
63 *           source expanded len  (8)   [size of uncompressed source]
64 *           target expected len  (8)   [size of uncompressed target]
65 *           zip level            (4)
66 *                method          (4)
67 *                windowBits      (4)
68 *                memLevel        (4)
69 *                strategy        (4)
70 *        if block type == BLOCK_LZ4:
71 *           source start         (8)
72 *           source len           (8)
73 *           bsdiff patch offset  (8)   [from start of patch file]
74 *           source expanded len  (8)   [size of uncompressed source]
75 *           target expected len  (8)   [size of uncompressed target]
76 *           lz4 level            (4)
77 *                method          (4)
78 *                blockIndependence     (4)
79 *                contentChecksumFlag   (4)
80 *                blockSizeID     (4)
81 *                autoFlush       (4)
82 *        if block type == RAW:
83 *           target len           (4)
84 *           data                 (target len)
85 *
86 */
87
88/* Header is
89    0	8	 "BSDIFF40"
90    8	8	length of bzip2ed ctrl block
91    16	8	length of bzip2ed diff block
92    24	8	length of new file
93*/
94/* File is
95    0	32	Header
96    32	40	Bzip2ed ctrl block
97    40	48	Bzip2ed diff block
98    48	56	Bzip2ed extra block
99*/
100
101// patch block types
102#define BLOCK_NORMAL 0
103#define BLOCK_GZIP 1
104#define BLOCK_DEFLATE 2
105#define BLOCK_RAW 3
106#define BLOCK_LZ4 4
107
108static constexpr size_t GZIP_HEADER_LEN = 10;
109static constexpr size_t VERSION = 2;
110static constexpr unsigned short HEADER_CRC = 0x02; /* bit 1 set: CRC16 for the gzip header */
111static constexpr unsigned short EXTRA_FIELD = 0x04; /* bit 2 set: extra field present */
112static constexpr unsigned short ORIG_NAME = 0x08; /* bit 3 set: original file name present */
113static constexpr unsigned short COMMENT = 0x10; /* bit 4 set: file comment present */
114static constexpr unsigned short ENCRYPTED = 0x20; /* bit 5 set: file is encrypted */
115static constexpr uint8_t SHIFT_RIGHT_FOUR_BITS = 4;
116
117// The gzip footer size really is fixed.
118static constexpr size_t GZIP_FOOTER_LEN = 8;
119static constexpr size_t LZ4_HEADER_LEN = 4;
120static constexpr size_t IGMDIFF_LIMIT_UNIT = 10240;
121
122static constexpr int LZ4S_MAGIC = 0x184D2204;
123static constexpr int LZ4B_MAGIC = 0x184C2102;
124static constexpr int GZIP_MAGIC = 0x00088b1f;
125
126static constexpr int PATCH_NORMAL_MIN_HEADER_LEN = 24;
127static constexpr int PATCH_DEFLATE_MIN_HEADER_LEN = 60;
128static constexpr int PATCH_LZ4_MIN_HEADER_LEN = 64;
129
130constexpr const char *BSDIFF_MAGIC = "BSDIFF40";
131constexpr const char *PKGDIFF_MAGIC = "PKGDIFF0";
132
133struct PatchHeader {
134    size_t srcStart = 0;
135    size_t srcLength = 0;
136    size_t patchOffset = 0;
137    size_t expandedLen = 0;
138    size_t targetSize = 0;
139};
140
141struct ControlData {
142    int64_t diffLength;
143    int64_t extraLength;
144    int64_t offsetIncrement;
145    uint8_t *diffNewStart;
146    uint8_t *diffOldStart;
147    uint8_t *extraNewStart;
148};
149
150struct MemMapInfo {
151    uint8_t *memory {};
152    size_t length {};
153    int fd {-1};
154    ~MemMapInfo()
155    {
156        if (memory != nullptr) {
157            munmap(memory, length);
158        }
159        memory = nullptr;
160        if (fd != -1) {
161            close(fd);
162            fd = -1;
163        }
164    }
165};
166
167int32_t WriteDataToFile(const std::string &fileName, const std::vector<uint8_t> &data, size_t dataSize);
168int32_t PatchMapFile(const std::string &fileName, MemMapInfo &info);
169std::string GeneraterBufferHash(const BlockBuffer &buffer);
170std::string ConvertSha256Hex(const BlockBuffer &buffer);
171} // namespace UpdatePatch
172#endif // DIFF_PATCH_H