Add delta.ua - a binary to apply an upgrade of DELTA_FS type.
[platform/core/system/upgrade.git] / src / upgrade-apply-deltafs / engine / ss_bspatch_common.c
1 /*-
2  * Copyright 2003-2005 Colin Percival
3  * Copyright 2012 Matthew Endsley
4  * All rights reserved
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted providing that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *      notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *      notice, this list of conditions and the following disclaimer in the
13  *      documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  *
27  * Modifications are made in reimplementing suffix sort array generation
28  * and how the data is read and written to.Iterative part replaced the
29  * recursive implementation to avoid buffer overflow problems
30  */
31 //#define ZLIB_MOD                                                                        //not stable yet.
32 //#define MAX_MATCH_SIZE                   // define ( MAX_MATCH_SIZE or CONST_MEMORY_USAGE ) or ( none of them )
33 #define CONST_MEMORY_USAGE (64*1024)    //tests show smallest time when using 64 kb
34 #define PATCH_FILE_FORMAT_MOD
35 #define BSDIFF_HEADER "BSDIFF40"
36 #define SSDIFF_HEADER "SSDIFF40"
37 //#define MULTI_THREADING
38 #include <stdbool.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45
46 #include <Alloc.h>
47 #include <7zFile.h>
48 #include <7zVersion.h>
49 #include <LzmaDec.h>
50 #include <LzmaEnc.h>
51
52 static void *SzAlloc(void *p, size_t size)
53 {
54         p = p;
55         return MyAlloc(size);
56 }
57
58 static void SzFree(void *p, void *address)
59 {
60         p = p;
61         MyFree(address);
62 }
63 ISzAlloc g_Alloc = { SzAlloc, SzFree };
64
65 static off_t offtin(u_char *buf)
66 {
67         off_t y;
68
69         y = buf[7] & 0x7F;
70         y = y * 256;
71         y += buf[6];
72         y = y * 256;
73         y += buf[5];
74         y = y * 256;
75         y += buf[4];
76         y = y * 256;
77         y += buf[3];
78         y = y * 256;
79         y += buf[2];
80         y = y * 256;
81         y += buf[1];
82         y = y * 256;
83         y += buf[0];
84
85         if (buf[7] & 0x80)
86                 y = -y;
87
88         return y;
89 }
90
91 #define IN_BUF_SIZE (1 << 16)
92 #define OUT_BUF_SIZE (1 << 16)
93
94 SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream,
95                 UInt64 *unpackSize, unsigned char *dec_data)
96 {
97         int thereIsSize = (*unpackSize != (UInt64)(Int64) - 1);
98         UInt64 offset = 0;
99         Byte inBuf[IN_BUF_SIZE];
100         Byte outBuf[OUT_BUF_SIZE];
101         size_t inPos = 0, inSize = 0, outPos = 0;
102
103         LzmaDec_Init(state);
104
105         offset = 0;
106
107         for (;;) {
108                 if (inPos == inSize) {
109                         inSize = IN_BUF_SIZE;
110                         RINOK(inStream->Read(inStream, inBuf, &inSize));
111                         inPos = 0;
112                 }
113
114                 SRes res;
115                 SizeT inProcessed = inSize - inPos;
116                 SizeT outProcessed = OUT_BUF_SIZE - outPos;
117                 ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
118                 ELzmaStatus status;
119
120                 if (thereIsSize && outProcessed > *unpackSize) {
121                         outProcessed = (SizeT) * unpackSize;
122                         finishMode = LZMA_FINISH_END;
123                 }
124
125                 res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed,
126                                 inBuf + inPos, &inProcessed, finishMode, &status);
127                 inPos += inProcessed;
128                 outPos += outProcessed;
129                 *unpackSize -= outProcessed;
130                 memcpy(dec_data + offset, outBuf, outProcessed);
131                 offset += outProcessed;
132
133                 outPos = 0;
134
135                 if ((res != SZ_OK) || (thereIsSize && *unpackSize == 0))
136                         return res;
137
138                 if (inProcessed == 0 && outProcessed == 0) {
139                         if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
140                                 return SZ_ERROR_DATA;
141                         return res;
142                 }
143         }
144 }
145
146 int apply_patch(const char *oldfile, unsigned char *patch_buffer, unsigned char **dest_buf, ssize_t *dest_size)
147 {
148         int fd = -1, result = 0;
149         off_t oldsize, newsize;
150         u_char header[16], buf[8];
151         u_char *old = NULL;
152         off_t oldpos, newpos;
153         off_t ctrl[4];          /////////////////////////////////////THREAD
154         off_t total_write;      /////////////////////////////////////////THREAD
155         off_t j;
156         off_t memory_usage = CONST_MEMORY_USAGE;
157         off_t match_size;
158         off_t patch_buffer_offset = 0;
159         bool flag;
160
161         /*
162            File format:
163            0    8          "BSDIFF40"
164            8    8          X
165            16   8          Y
166            24   8          sizeof(newfile)
167            32   X          bzip2(control block)
168            32+X Y          bzip2(diff block)
169            32+X+Y          ???   bzip2(extra block)
170            with control block a set of triples (x,y,z) meaning "add x bytes
171            from oldfile to x bytes from the diff block; copy y bytes from the
172            extra block; seek forwards in oldfile by z bytes".
173          */
174         // Read header
175         if (patch_buffer)
176                 memcpy(header, patch_buffer, 16);
177         else {
178                 printf("%s().%d Corrupt decoded patch buffer\n", __FUNCTION__, __LINE__);
179                 return 1;
180         }
181
182         /* Check for appropriate magic */
183         if (memcmp(header, BSDIFF_HEADER, 8) != 0 && memcmp(header, SSDIFF_HEADER, 8) != 0) {
184                 printf("%s().%d Patch buffer header corrupt\n", __FUNCTION__, __LINE__);
185                 return 1;
186         }
187
188         /* Read lengths from header */
189         newsize = offtin(header + 8);
190
191         if ((newsize < 0)) {
192                 printf("%s().%d Patch buffer corrupt\n", __FUNCTION__, __LINE__);
193                 return 1;
194         }
195
196         /* Cset patch_buffer_offset at the right place */
197         patch_buffer_offset += 16;
198
199         if (((fd = open(oldfile, O_RDONLY, 0)) < 0) ||
200                         ((oldsize = lseek(fd, 0, SEEK_END)) == -1) ||
201                         ((old = malloc(memory_usage + 1)) == NULL) ||
202                         (lseek(fd, 0, SEEK_SET) != 0)) {
203                 printf("Corruption in old file %s\n", oldfile);
204                 result = 1;
205                 goto Cleanup;
206         }
207
208         if ((*dest_buf = malloc(newsize + 1)) == NULL) {
209                 printf("Corruption in old file %s\n", oldfile);
210                 result = 1;
211                 goto Cleanup;
212         }
213         oldpos = 0;
214         newpos = 0;
215
216         total_write = 0;
217
218         while (total_write != newsize) {
219                 /* Read control data */
220                 for (j = 0; j <= 3; j++) {
221                         memcpy(buf, patch_buffer + patch_buffer_offset, 8);
222                         patch_buffer_offset += 8;
223                         ctrl[j] = offtin(buf);
224                 };
225
226                 total_write += (ctrl[0] + ctrl[1]);
227                 newpos = ctrl[3];
228                 oldpos = ctrl[2];
229
230                 //////////////////////////////////////////////////////////////////////////////////
231                 flag = true;
232                 match_size = ctrl[0];
233                 while (flag == true) {
234                         if (match_size <= memory_usage) {
235                                 if (pread(fd, old, match_size, oldpos) != match_size) {
236                                         printf("Corruption in old file %s\n", oldfile);
237                                         result = 1;
238                                         goto Cleanup;
239                                 }
240                                 if (newpos + match_size > newsize) {
241                                         printf("%s().%d Corrupt patch\n", __FUNCTION__, __LINE__);
242                                         result = 1;
243                                         goto Cleanup;
244                                 }
245                                 memcpy((*dest_buf) + newpos, patch_buffer + patch_buffer_offset, match_size);
246                                 patch_buffer_offset += match_size;
247                                 for (j = 0; j < match_size; j++)
248                                         (*dest_buf)[newpos + j] += old[j];
249                                 newpos += match_size;
250                                 flag = false;
251                         } else {
252                                 if (pread(fd, old, memory_usage, oldpos) != memory_usage) {
253                                         printf("%s().%d Corruption in old file %s\n", __FUNCTION__, __LINE__ , oldfile);
254                                         result = 1;
255                                         goto Cleanup;
256                                 }
257                                 if (newpos + memory_usage > newsize) {
258                                         printf("%s().%d Corrupt patch\n", __FUNCTION__, __LINE__);
259                                         result = 1;
260                                         goto Cleanup;
261                                 }
262                                 memcpy((*dest_buf) + newpos, patch_buffer + patch_buffer_offset, memory_usage);
263                                 patch_buffer_offset += memory_usage;
264                                 for (j = 0; j < memory_usage; j++)
265                                         (*dest_buf)[newpos + j] += old[j];
266                                 match_size -= memory_usage;
267                                 oldpos += memory_usage;
268                                 newpos += memory_usage;
269                         }
270                 }
271
272                 ////////////////////////////////////////////////////////////////////////////////////////
273                 /* Sanity-check */
274                 if (newpos + ctrl[1] > newsize) {
275                         printf("%s().%d Corrupt patch\n", __FUNCTION__, __LINE__);
276                         result = 1;
277                         goto Cleanup;
278                 }
279                 /* Read extra string */
280                 memcpy((*dest_buf) + newpos, patch_buffer + patch_buffer_offset, ctrl[1]);
281                 patch_buffer_offset += ctrl[1];
282         };
283         *dest_size = newsize;
284 Cleanup:
285         //close old file
286         if (fd >= 0)
287                 close(fd);
288         if (old)
289                 free(old);
290         return result;
291 }