2 * upgrade-apply-deltafs
4 * Copyright (c) 2017 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
25 #include <sys/statfs.h>
26 #include <sys/types.h>
30 #include "SS_PatchDelta.h"
31 #include "fota_common.h"
32 #include "SS_Engine_Errors.h"
33 #include "SS_Common.h"
34 #include "patch_helper.h"
36 extern void *SS_Malloc(unsigned int size);
39 unsigned char *buffer;
44 ssize_t ss_fileSink(unsigned char *data, ssize_t len, void *token)
46 int ss_fd = *(int *)token;
50 while (done < (ssize_t) len) {
51 wrote = write(ss_fd, data + done, len - done);
53 if (errno == EINTR || errno == EAGAIN)
54 continue; // try again
55 strerror_r(errno, buf, sizeof(buf));
56 LOGE("error writing %d bytes: %s\n", (int)(len - done), buf);
64 // Take a string 'str' of 40 hex digits and parse it into the 20
65 // byte array 'digest'. 'str' may contain only the digest or be of
66 // the form "<digest>:<anything>". Return 0 on success, -1 on any
68 int ParseSha1(const char *str, uint8_t * digest)
73 for (i = 0; i < SHA_DIGEST_SIZE * 2; ++i, ++ps) {
75 if (*ps >= '0' && *ps <= '9')
77 else if (*ps >= 'a' && *ps <= 'f')
78 digit = *ps - 'a' + 10;
79 else if (*ps >= 'A' && *ps <= 'F')
80 digit = *ps - 'A' + 10;
95 int SS_LoadFile(const char *filename, FileInfo * file)
100 //LOGL(LOG_SSENGINE,"SS_LoadFile --- [File name %s]\n",filename);
102 if (stat(filename, &file->st) != 0) {
103 strerror_r(errno, buf, sizeof(buf));
104 LOGE("failed to stat \"%s\": %s\n", filename, buf);
108 file->size = file->st.st_size;
109 file->data = SS_Malloc(file->size);
111 strerror_r(errno, buf, sizeof(buf));
112 LOGE("failed to allocate memory for \"%s\": %s\n", filename, buf);
116 FILE *f = fopen(filename, "rb");
118 strerror_r(errno, buf, sizeof(buf));
119 LOGE("failed to open \"%s\": %s\n", filename, buf);
125 ssize_t bytes_read = fread(file->data, 1, file->size, f);
126 if (bytes_read != file->size) {
127 LOGE("short read of \"%s\" (%ld bytes of %ld)\n", filename, (long)bytes_read, (long)file->size);
134 //LOGL(LOG_SSENGINE,"SS_LoadFile --- [bytes_read %d]\n",bytes_read);
135 SHA1(file->sha1, file->data, file->size);
139 extern int gvalid_session;
140 static void create_dir(char *pathname, int mode)
145 /* Strip trailing '/' */
146 if (pathname[strlen(pathname) - 1] == '/')
147 pathname[strlen(pathname) - 1] = '\0';
149 /* Try creating the directory. */
150 r = mkdir(pathname, mode);
153 /* On failure, try creating parent directory. */
154 p = strrchr(pathname, '/');
157 create_dir(pathname, 0755);
159 r = mkdir(pathname, mode);
163 if (r != EEXIST && r != -1)
164 LOG("Could not create directory [%s] Error[%d]\n", pathname, r);
169 *********************************************************************************
171 *********************************************************************************
174 * This is used to apply patch for a file during delta FS upgrade
179 * @return 0 - in case of success
180 * 1 - in case of error during patch application
182 *********************************************************************************
185 int SS_UpdateDeltaFS(const char *source_filename, const char *target_filename,
186 const char *source_sha1_str, const char *target_sha1_str, int patch_data_size, TAR* tar_file)
188 uint8_t target_sha1[SHA_DIGEST_SIZE] = { 0, };
192 char *outname = NULL;
196 if (ParseSha1(target_sha1_str, target_sha1) != 0) {
197 LOGE("failed to parse tgt-sha1 \"%s\"\n", target_sha1_str);
202 int enough_space = 0;
203 size_t free_space = 0;
206 SS_GetAvailableFreeSpace(source_filename, &free_space);
207 enough_space = (free_space > (256 << 10)) && // 256k (two-block) minimum
208 (free_space > (patch_data_size * 3 / 2)); // 50% margin of error
211 LOGL(LOG_SSENGINE, "For %s: free space %ld bytes; enough %d\n", source_filename, (long)free_space,
214 unlink(source_filename);
216 //LOGL(LOG_SSENGINE, "For %s: target %ld bytes; free space %ld bytes; enough %d\n",
217 // source_filename, (long)patch_data_size, (long)free_space, enough_space);
218 //LOGL(LOG_SSENGINE,"Generate Target Space availabitiy [%d]\n", enough_space);
224 // We write the decoded output to "<tgt-file>.patch".
225 //allocate some extra space to allow for concatinating ".patch" with the name
226 outname = (char *)SS_Malloc(strlen(target_filename) + 10);
227 if (outname == NULL) {
228 LOGE("SS_Malloc failed!!\n");
231 snprintf(outname, strlen(target_filename) + 10,
232 "%s.patch", target_filename);
234 output = open(outname, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
237 char *dir_path = strrchr(outname, '/');
239 // need to create directory as the target may be different from source
240 LOGL(LOG_SSENGINE, "need to create directory [%s]\n", outname);
241 create_dir(outname, 0755);
243 output = open(outname, O_WRONLY | O_CREAT | O_TRUNC, S_IRWXU);
245 strerror_r(errno, buf, sizeof(buf));
246 LOGE("failed to open output file %s: %s\n", outname, buf);
247 result = E_SS_FAILURE;
253 result = apply_patch_brotli((char *)source_filename, outname, tar_file, -1, &free_space);
259 if (result != S_SS_SUCCESS) {
261 LOGE("applying patch failed result : [%d]\n", result);
262 SS_SetUpgradeState(E_SS_FSUPDATEFAILED);
263 result = E_SS_FAILURE;
266 LOGE("applying patch failed; retrying\n");
267 SS_Free(outname);//wgid: 20739
270 // succeeded; no need to retry
273 } while (retry-- > 0);
275 unsigned char current_target_sha1[SHA_DIGEST_SIZE] = { 0, };
277 int fd = open(outname, O_RDONLY);
279 LOGE("cannot open %s to verify SHA1\n", outname);
280 result = E_SS_FAILURE;
283 unsigned char buff[4096];
285 int res = read(fd, buff, 4096);
287 LOGE("cannot read %s to verify SHA1\n", outname);
289 result = E_SS_FAILURE;
295 SHA1Update(&ctx1, buff, res);
299 SHA1Final(current_target_sha1, &ctx1);
300 if (memcmp(current_target_sha1, target_sha1, SHA_DIGEST_SIZE) != 0) {
301 LOGE("patch did not produce expected sha1\n");
302 SS_SetUpgradeState(E_SS_FSSHA_MISMATCH);
303 result = E_SS_FAILURE;
307 // Finally, rename the .patch file to replace the target file.
308 #ifdef ENHANCED_BSDIFF
309 if (SS_rename1(outname, target_filename) != 0) {
310 strerror_r(errno, buf, sizeof(buf));
311 LOGE("rename of .patch to \"%s\" failed: %s\n", target_filename, buf);
312 SS_SetUpgradeState(E_SS_FSUPDATEFAILED);
313 result = E_SS_FAILURE;
317 if (rename(outname, target_filename) != 0) {
318 strerror_r(errno, buf, sizeof(buf));
319 LOGE("rename of .patch to \"%s\" failed: %s\n", target_filename, buf);
320 SS_SetUpgradeState(E_SS_FSUPDATEFAILED);
321 result = E_SS_FAILURE;
324 //remove source file if target is not same
325 if (strcmp(source_filename, target_filename) != 0)
326 unlink(source_filename);