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.
20 #include <sys/types.h>
27 #include "SS_Engine_Errors.h"
28 #include "SS_FSUpdate.h"
29 #include "fota_common.h"
33 /* tar Header Block, from POSIX 1003.1-1990. for reference */
37 struct posix_header { /* byte offset */
38 char name[100]; /* 0 */
39 char mode[8]; /* 100 */
40 char uid[8]; /* 108 */
41 char gid[8]; /* 116 */
42 char size[12]; /* 124 */
43 char mtime[12]; /* 136 */
44 char chksum[8]; /* 148 */
45 char typeflag; /* 156 */
46 char linkname[100]; /* 157 */
47 char magic[6]; /* 257 */
48 char version[2]; /* 263 */
49 char uname[32]; /* 265 */
50 char gname[32]; /* 297 */
51 char devmajor[8]; /* 329 */
52 char devminor[8]; /* 337 */
53 char prefix[155]; /* 345 */
58 #define MAX_ITEM_SIZE 0x7FFFFFFF
59 #define TAR_ITEM_SIZE_POSITION 124
60 #define TAR_SIZE_OF_ITEM_SIZE 8
61 #define TAR_SIZE_OF_HEADER 12
62 #define TAR_BLOCK_SIZE 512
63 #define TAR_ITEM_NAME_SIZE 100
64 #define TAR_LONG_NAME_SIZE 256
65 #define TAR_ITEM_TYPE_FLAG_POS 156
66 /*** The byte that indicates whether the prefix is present or not */
67 #define PREFIX_INDICATOR_BYTE 345
68 #define PREFIX_LEN 155
70 /** the rest heavily based on (ie mostly) untgz.c from zlib **/
72 /* Values used in typeflag field. */
74 #define REGTYPE '0' /* regular file */
75 #define AREGTYPE '\0' /* regular file */
76 #define LNKTYPE '1' /* link */
77 #define SYMTYPE '2' /* reserved */
78 #define CHRTYPE '3' /* character special */
79 #define BLKTYPE '4' /* block special */
80 #define DIRTYPE '5' /* directory */
81 #define FIFOTYPE '6' /* FIFO special */
82 #define CONTTYPE '7' /* reserved, for compatibility with gnu tar,
83 treat as regular file, where it represents
84 a regular file, but saved contiguously on disk */
86 /* GNU tar extensions */
88 #define GNUTYPE_DUMPDIR 'D' /* file names from dumped directory */
89 #define GNUTYPE_LONGLINK 'K' /* long link name */
90 #define GNUTYPE_LONGNAME 'L' /* long file name */
91 #define GNUTYPE_MULTIVOL 'M' /* continuation of file from another volume */
92 #define GNUTYPE_NAMES 'N' /* file name that does not fit into main hdr */
93 #define GNUTYPE_SPARSE 'S' /* sparse file */
94 #define GNUTYPE_VOLHDR 'V' /* tape/volume header */
96 extern void *SS_Malloc(SS_UINT32 size);
98 int gTarFd = -1; // Currenlty this logic supports only one tar file
100 void create_dir(char *pathname, int mode)
105 /* Strip trailing '/' */
106 if (pathname[strlen(pathname) - 1] == '/')
107 pathname[strlen(pathname) - 1] = '\0';
109 /* Try creating the directory. */
110 r = mkdir(pathname, mode);
113 /* On failure, try creating parent directory. */
114 p = strrchr(pathname, '/');
117 create_dir(pathname, 0755);
119 r = mkdir(pathname, mode);
123 if (r != EEXIST && r != -1)
124 LOG("Could not create directory [%s] Error[%d]\n", pathname, r);
128 /*-----------------------------------------------------------------------------
130 ----------------------------------------------------------------------------*/
131 int tar_get_item_offset(char *tar, char *item)
135 char header[TAR_BLOCK_SIZE] = { 0, };
136 char uExtendedName[MAX_FILE_PATH + 1] = { 0, };
137 char size_oct[TAR_SIZE_OF_HEADER] = { 0, };
138 unsigned long size_dec = 0;
145 LOG("Invalid params\n");
148 //check if gTarFd was opened by tar_open during SS_FSUpdateFile then use it
152 fd = open(tar, O_RDONLY);
154 LOGE("can't open file(%s).\n", tar);
159 tar_len = lseek(fd, 0, SEEK_END);
161 LOGL(LOG_SSENGINE, "can't read tar_len (%s).\n", tar);
164 pos = lseek(fd, 0, SEEK_SET);
166 LOGL(LOG_SSENGINE, "can't read pos (%s).\n", tar);
169 while (pos < tar_len) {
170 /* read file header */
171 rdcnt = read(fd, header, sizeof(header));
173 LOG("read failed. (rdcnt=%d)\n", rdcnt);
177 /* get file name and file size */
178 if (header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGNAME || header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGLINK) {
179 //rdcnt = read(fd, header, sizeof(header));
180 memset(uExtendedName, 0, sizeof(uExtendedName));
181 rdcnt = read(fd, uExtendedName, sizeof(uExtendedName) - 1);
183 LOG("read failed. (rdcnt=%d)\n", rdcnt);
186 rdcnt = read(fd, header, sizeof(header));
188 LOG("read failed. (rdcnt=%d)\n", rdcnt);
192 memset(uExtendedName, 0, sizeof(uExtendedName));
193 memcpy(uExtendedName, header, TAR_ITEM_NAME_SIZE);
195 memcpy(size_oct, header + TAR_ITEM_SIZE_POSITION, sizeof(size_oct));
196 size_dec = strtoul(size_oct, NULL, TAR_SIZE_OF_ITEM_SIZE);
197 if (size_dec > MAX_ITEM_SIZE) {
198 LOG("ITEM : [%s]\n", item);
199 LOG("size too big. (size_dec=0x%08X)\n", size_dec);
203 /* check if the file is what we are looking for */
204 if (strncmp(uExtendedName, item, sizeof(uExtendedName) - 1) == 0) {
205 ret = (int)lseek(fd, 0, SEEK_CUR);
209 /* move file pointer to next file header */
210 blknum = size_dec / TAR_BLOCK_SIZE;
211 if (size_dec % TAR_BLOCK_SIZE)
214 pos = lseek(fd, (off_t) (blknum * TAR_BLOCK_SIZE), SEEK_CUR);
216 LOGE("can't read next block (%s).\n", tar);
229 /*-----------------------------------------------------------------------------
231 ----------------------------------------------------------------------------*/
232 int tar_get_item_size(char *tar, char *item)
236 char header[TAR_BLOCK_SIZE] = { 0, };
237 char uExtendedName[MAX_FILE_PATH + 1] = { 0, };
238 char size_oct[TAR_SIZE_OF_HEADER] = { 0, };
239 unsigned long size_dec = 0;
246 LOG("Invalid params\n");
249 LOGL(LOG_SSENGINE, "Tar file Looking for (%s)\n", item);
250 fd = open(tar, O_RDONLY);
252 LOG("can't open file(%s).\n", tar);
256 tar_len = lseek(fd, 0, SEEK_END);
258 LOGL(LOG_SSENGINE, "can't read tar_len (%s).\n", tar);
261 pos = lseek(fd, 0, SEEK_SET);
263 LOGL(LOG_SSENGINE, "can't read pos (%s).\n", tar);
267 while (pos < tar_len) {
268 /* read file header */
269 rdcnt = read(fd, header, sizeof(header));
271 LOG("read failed. (rdcnt=%d)\n", rdcnt);
275 /* get file name and file size */
276 if (header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGNAME || header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGLINK) {
277 //rdcnt = read(fd, header, sizeof(header));
278 memset(uExtendedName, 0, sizeof(uExtendedName));
279 rdcnt = read(fd, uExtendedName, sizeof(uExtendedName) - 1);
281 LOG("read failed. (rdcnt=%d)\n", rdcnt);
284 rdcnt = read(fd, header, sizeof(header));
286 LOG("read failed. (rdcnt=%d)\n", rdcnt);
290 memset(uExtendedName, 0, sizeof(uExtendedName));
291 memcpy(uExtendedName, header, TAR_ITEM_NAME_SIZE);
293 memcpy(size_oct, header + TAR_ITEM_SIZE_POSITION, sizeof(size_oct));
294 size_dec = strtoul(size_oct, NULL, TAR_SIZE_OF_ITEM_SIZE);
295 if (size_dec > MAX_ITEM_SIZE) {
296 LOG("ITEM : [%s]\n", item);
297 LOG("size too big. (size_dec=0x%08X)\n", (unsigned int)size_dec);
301 /* check if the file is what we are looking for */
302 if (strncmp(uExtendedName, item, sizeof(uExtendedName) - 1) == 0) {
304 if ((ret == 0) && (header[TAR_ITEM_TYPE_FLAG_POS] == DIRTYPE))
305 ret = tar_get_folder_size(tar, item);
308 /* move file pointer to next file header */
309 //LOGL(LOG_SSENGINE,"Item in Tar (%s)\n", uExtendedName);
310 blknum = size_dec / TAR_BLOCK_SIZE;
311 if (size_dec % TAR_BLOCK_SIZE)
314 pos = lseek(fd, (off_t) (blknum * TAR_BLOCK_SIZE), SEEK_CUR);
316 LOGL(LOG_SSENGINE, "can't read next block (%s).\n", tar);
328 /*-----------------------------------------------------------------------------
330 ----------------------------------------------------------------------------*/
331 int tar_get_cfg_data(char *tar, char *item, char *buf, int buflen)
335 int data_offset = -1;
340 LOG("Invalid params\n");
343 data_size = tar_get_item_size(tar, item);
347 if (data_size > buflen)
350 data_offset = tar_get_item_offset(tar, item);
354 fd = open(tar, O_RDONLY);
356 LOG("can't open file(%s).\n", tar);
360 pos = lseek(fd, data_offset, SEEK_SET);
362 LOG("lseek fail (%s offset %d).\n", tar, data_offset);
367 rdcnt = read(fd, buf, data_size);
368 if (rdcnt != (ssize_t) data_size) {
369 LOG("read fail(%s from %s).\n", item, tar);
379 tar_Data_t *tar_build_cfg_table(char *tar)
384 char header[TAR_BLOCK_SIZE] = { 0, };
385 char uExtendedName[MAX_FILE_PATH + 1] = { 0, };
386 char size_oct[TAR_SIZE_OF_HEADER] = { 0, };
387 unsigned long size_dec = 0;
395 tar_Data_t *headparam = NULL, *tailparam = NULL, *newnode = NULL;
396 tar_Data_t *local_temp = NULL;
397 tar_Data_t *local_next = NULL;
399 LOGE("Bad param tar\n");
402 //check if gTarFd was opened by tar_open during SS_FSUpdateFile then use it
406 fd = open(tar, O_RDONLY);
408 LOG("can't open file(%s).\n", tar);
413 tar_len = lseek(fd, 0, SEEK_END);
415 LOGL(LOG_SSENGINE, "can't read tar_len (%s).\n", tar);
418 pos = lseek(fd, 0, SEEK_SET);
420 LOGL(LOG_SSENGINE, "can't read pos (%s).\n", tar);
423 while (pos < tar_len) {
424 /* read file header */
425 rdcnt = read(fd, header, sizeof(header));
427 LOG("read failed. (rdcnt=%d)\n", rdcnt);
431 /* get file name and file size */
432 if (header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGNAME || header[TAR_ITEM_TYPE_FLAG_POS] == GNUTYPE_LONGLINK) {
433 //rdcnt = read(fd, header, sizeof(header));
434 memset(uExtendedName, 0, sizeof(uExtendedName));
435 rdcnt = read(fd, uExtendedName, sizeof(uExtendedName) - 1);
437 LOG("read failed. (rdcnt=%d)\n", rdcnt);
441 rdcnt = read(fd, header, sizeof(header));
443 LOG("read failed. (rdcnt=%d)\n", rdcnt);
448 memset(uExtendedName, 0, sizeof(uExtendedName));
449 memcpy(uExtendedName, header, TAR_ITEM_NAME_SIZE);
451 memcpy(size_oct, header + TAR_ITEM_SIZE_POSITION, sizeof(size_oct));
452 size_dec = strtoul(size_oct, NULL, TAR_SIZE_OF_ITEM_SIZE);
453 if (size_dec > MAX_ITEM_SIZE) {
454 LOG("uExtendedName is : [%s]\n", uExtendedName);
455 LOG("size too big. (size_dec=0x%08X)\n", (unsigned int)size_dec);
459 //fix WGID : 51254 , size_dec comparison is not required
460 if ((strstr(uExtendedName, "/diff") != NULL)) { //add only delta files from rootfs and csc, hardcoding shd b removed..
462 /* check if the file is what we are looking for */
463 //strncpy(itemName, name,100);
464 itemSize = (int)size_dec;
465 itemOffset = (int)lseek(fd, 0, SEEK_CUR);
466 newnode = (tar_Data_t *) SS_Malloc(sizeof(tar_Data_t));
471 memset(newnode->itemName, 0, sizeof(newnode->itemName));
472 strncpy((char *)newnode->itemName, uExtendedName, sizeof(newnode->itemName) - 1);
473 newnode->itemOffset = itemOffset;
474 newnode->itemSize = itemSize;
475 newnode->nextnode = NULL;
476 if (headparam == NULL) {
480 (tailparam)->nextnode = newnode;
481 (tailparam) = (tailparam)->nextnode;
485 /* move file pointer to next file header */
486 blknum = size_dec / TAR_BLOCK_SIZE;
487 if (size_dec % TAR_BLOCK_SIZE)
490 pos = lseek(fd, (off_t) (blknum * TAR_BLOCK_SIZE), SEEK_CUR);
492 LOGL(LOG_SSENGINE, "can't read next block (%s).\n", tar);
498 //if gTarFd was opened by tar_open during SS_FSUpdateFile we do not close it
504 if (headparam != newnode && newnode)
507 local_temp = headparam;
509 local_next = local_temp->nextnode;
511 local_temp = local_next;
518 void tar_free_cfg_table(tar_Data_t ** delta_tar)
520 tar_Data_t *local_temp = NULL;
521 tar_Data_t *local_next = NULL;
522 LOGL(LOG_SSENGINE, "Free TAR CFG TABLE\n");
524 local_temp = *delta_tar;
526 local_next = local_temp->nextnode;
527 //LOGL(LOG_SSENGINE,"freeing [%s]\n",local_temp->itemName);
529 local_temp = local_next;
534 void deleteNode(tar_Data_t * head, tar_Data_t * n)
536 tar_Data_t *prev = head;
538 if (head->nextnode == NULL) {
539 LOG("There is only one node. The list can't be made empty\n");
542 strncpy((char *)head->itemName, (const char *)head->nextnode->itemName, TAR_ITEM_NAME_SIZE); //head->itemName = head->nextnode->itemName;
543 head->itemSize = head->nextnode->itemSize;
544 head->itemOffset = head->nextnode->itemOffset;
546 head->nextnode = head->nextnode->nextnode;
550 while (prev->nextnode != NULL && prev->nextnode != n)
551 prev = prev->nextnode;
552 if (prev->nextnode == NULL) {
553 LOG("Given node is not present in Linked List\n");
556 prev->nextnode = prev->nextnode->nextnode;
561 int tar_get_item_size_from_struct(tar_Data_t ** delta_tar, const char *patchname, int *data_size, int *data_offset)
563 tar_Data_t *head = *delta_tar;
564 tar_Data_t *base = *delta_tar;
568 //LOG("fast_tar_get_item_size- looking for [%s] [%s]\n",patchname,head->itemName);
570 if (strstr((const char *)head->itemName, patchname) != 0) {
571 //LOG("fast_tar_get_item_size found [%s] in [%s]\n",patchname, head->itemName);
572 *data_size = head->itemSize;
573 *data_offset = head->itemOffset;
574 deleteNode(base, head);
577 } else if (head->nextnode != NULL) {
578 head = head->nextnode;
579 //LOG("fast_tar_get_item_size current node [%s] \n",head->itemName);
581 LOGE("fast_tar_get_item_size FAILED TO GET [%s] in [%s]\n", patchname, (char *)head->itemName);
589 int tar_open(char *tar)
593 gTarFd = open(tar, O_RDONLY);
595 LOG("can't open TAR file(%s).\n", tar);
609 int tar_get_folder_size(char *tar, char *item)
613 char header[TAR_BLOCK_SIZE] = { 0, };
614 char name[TAR_LONG_NAME_SIZE + 1] = { 0, };
615 char *lastfolder = NULL;
616 int folderpathlen = 0;
617 char size_oct[TAR_SIZE_OF_HEADER] = { 0, };
618 unsigned long size_dec = 0;
625 LOG("Invalid params\n");
628 LOG("Tar folder Looking for (%s)\n", item);
629 fd = open(tar, O_RDONLY);
631 LOG("can't open file(%s).\n", tar);
635 tar_len = lseek(fd, 0, SEEK_END);
637 LOGL(LOG_SSENGINE, "can't read tar_len (%s).\n", tar);
640 pos = lseek(fd, 0, SEEK_SET);
642 LOGL(LOG_SSENGINE, "can't read pos (%s).\n", tar);
646 while (pos < tar_len) {
647 /* read file header */
648 rdcnt = read(fd, header, sizeof(header));
650 LOG("read failed. (rdcnt=%d)\n", rdcnt);
655 /* get file name and file size */
656 memcpy(name, header, sizeof(name) - 1);
657 memcpy(size_oct, header + TAR_ITEM_SIZE_POSITION, sizeof(size_oct));
659 size_dec = strtoul(size_oct, NULL, TAR_SIZE_OF_ITEM_SIZE);
661 LOG("strtoul failed. (errno=%d)\n", errno);
664 } else if (size_dec > MAX_ITEM_SIZE) {
665 LOG("size too big. (size_dec=0x%08X)\n", (unsigned int)size_dec);
670 /* check if the file is what we are looking for */
671 //Get until folder name
673 lastfolder = strrchr(name, '/');
675 folderpathlen = strlen(name) - strlen(lastfolder);
677 if (strncmp(name, item, folderpathlen) == 0) {
678 ret += (int)size_dec;
679 //LOG("Tar Files under folder [%s]\n", name);
683 /* move file pointer to next file header */
684 blknum = size_dec / TAR_BLOCK_SIZE;
685 if (size_dec % TAR_BLOCK_SIZE)
688 pos = lseek(fd, (off_t) (blknum * TAR_BLOCK_SIZE), SEEK_CUR);
690 LOGL(LOG_SSENGINE, "can't read next block (%s).\n", tar);
698 LOG("ret=%d\n", ret);
700 return ret; //Should return +1?? or Ignore??
703 int fast_tar_extract_file(char *tar, char *item, char *pathname, int size, int offset)
706 int data_size = size;
707 int data_offset = offset;
710 ssize_t writeCount = 0;
715 if (!item || !tar || !pathname){
716 LOG("Invalid params\n");
722 fd = open(tar, O_RDONLY);
724 LOG("can't open file(%s).\n", tar);
729 pos = lseek(fd, data_offset, SEEK_SET);
731 LOG("lseek fail (%s offset %d).\n", tar, data_offset);
735 buf = SS_Malloc(data_size + 1);
738 LOGE("Failed to Allocate Memory\n");
741 rdcnt = read(fd, buf, data_size);
742 if (rdcnt != (ssize_t) data_size) {
743 LOG(" rdcnt read fail(%s from %s).\n", item, tar);
748 fd2 = open(pathname, O_CREAT | O_WRONLY, S_IRWXU); // Directory where file is required should be created already.
750 LOG("can't open file(%s).\n", pathname);
755 writeCount = write(fd2, buf, rdcnt);
756 if (writeCount != rdcnt) {
757 LOG("writeCount write fail(%s from %s).\n", item, tar);
758 strerror_r(errno, err_buf, sizeof(err_buf));
759 LOG("Oh dear, something went wrong with read()! %s\n", err_buf);
770 return rdcnt; // or jus return success?
773 int tar_extract_file(char *tar, char *item, char *pathname)
777 int data_offset = -1;
780 ssize_t writeCount = 0;
785 if (!item || !tar || !pathname){
786 LOG("Invalid params\n");
789 data_size = tar_get_item_size(tar, item);
790 data_offset = tar_get_item_offset(tar, item);
792 if (data_size <= 0 || data_offset < 0) {
793 LOGE("Error Not a file , size is [%d], offset [%d] for item [%s]\n", data_size, data_offset, item);
796 LOGL(LOG_SSENGINE, "extracting file [%s] size [%d]\n", item, data_size);
797 fd = open(tar, O_RDONLY);
799 LOG("can't open file(%s).\n", tar);
802 pos = lseek(fd, data_offset, SEEK_SET);
804 LOG("lseek fail (%s offset %d).\n", tar, data_offset);
808 buf = SS_Malloc(data_size + 1);
811 LOGE("Failed to Allocate Memory\n");
814 rdcnt = read(fd, buf, data_size);
815 if (rdcnt != (ssize_t) data_size) {
816 LOG(" rdcnt read fail(%s from %s).\n", item, tar);
821 fd2 = open(pathname, O_CREAT | O_WRONLY, S_IRWXU); // Directory where file is required should be created already.
823 LOG("can't open file(%s).\n", pathname);
828 writeCount = write(fd2, buf, rdcnt);
829 if (writeCount != rdcnt) {
830 LOG("writeCount write fail(%s from %s).\n", item, tar);
831 strerror_r(errno, err_buf, sizeof(err_buf));
832 LOG("Oh dear, something went wrong with read()! %s\n", err_buf);
842 return rdcnt; // or jus return success?