Change size to unsinged long long, so if -1 is passed it will read as much as possible.
[oweals/busybox.git] / libbb / untar.c
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; either version 2 of the License, or
5  *  (at your option) any later version.
6  *
7  *  This program is distributed in the hope that it will be useful,
8  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *  GNU Library General Public License for more details.
11  *
12  *  You should have received a copy of the GNU General Public License
13  *  along with this program; if not, write to the Free Software
14  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
15  *
16  * NOTE: This is used by deb_extract to avoid calling the whole tar applet.
17  * Its functionality should be merged with tar to avoid duplication
18  */
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include "libbb.h"
24
25 extern int untar(FILE *src_tar_file, int untar_function, char *base_path)
26 {
27         typedef struct raw_tar_header {
28         char name[100];               /*   0-99 */
29         char mode[8];                 /* 100-107 */
30         char uid[8];                  /* 108-115 */
31         char gid[8];                  /* 116-123 */
32         char size[12];                /* 124-135 */
33         char mtime[12];               /* 136-147 */
34         char chksum[8];               /* 148-155 */
35         char typeflag;                /* 156-156 */
36         char linkname[100];           /* 157-256 */
37         char magic[6];                /* 257-262 */
38         char version[2];              /* 263-264 */
39         char uname[32];               /* 265-296 */
40         char gname[32];               /* 297-328 */
41         char devmajor[8];             /* 329-336 */
42         char devminor[8];             /* 337-344 */
43         char prefix[155];             /* 345-499 */
44         char padding[12];             /* 500-512 */
45         } raw_tar_header_t;
46
47         raw_tar_header_t raw_tar_header;
48         unsigned char *temp = (unsigned char *) &raw_tar_header;
49         long i;
50         long next_header_offset = 0;
51         long uncompressed_count = 0;
52         size_t size;
53         mode_t mode;
54
55         while (fread((char *) &raw_tar_header, 1, 512, src_tar_file) == 512) {
56                 long sum = 0;
57                 char *dir = NULL;
58
59                 uncompressed_count += 512;
60
61                 /* Check header has valid magic */
62                 if (strncmp(raw_tar_header.magic, "ustar", 5) != 0) {
63                         /* Put this pack after TODO (check child still alive) is done */
64                         error_msg("Invalid tar magic");
65                         break;
66                 }
67
68                 /* Do checksum on headers */
69         for (i =  0; i < 148 ; i++) {
70                         sum += temp[i];
71                 }
72         sum += ' ' * 8;
73                 for (i =  156; i < 512 ; i++) {
74                         sum += temp[i];
75                 }
76         if (sum != strtol(raw_tar_header.chksum, NULL, 8)) {
77                         error_msg("Invalid tar header checksum");
78                         break;
79                 }
80
81                 /* convert to type'ed variables */
82         size = strtol(raw_tar_header.size, NULL, 8);
83                 parse_mode(raw_tar_header.mode, &mode);
84
85                 /* start of next header is at */
86                 next_header_offset = uncompressed_count + size;
87                 if (size % 512 != 0) {
88                         next_header_offset += (512 - size % 512);
89                 }
90
91                 /*
92                  * seek to start of control file, return length
93                  *
94                 if (dpkg_untar_function & dpkg_untar_seek_control) {
95                         if ((raw_tar_header.typeflag == '0') || (raw_tar_header.typeflag == '\0')) {
96                                 char *tar_filename;
97
98                                 tar_filename = strrchr(raw_tar_header.name, '/');
99                                 if (tar_filename == NULL) {
100                                         tar_filename = strdup(raw_tar_header.name);
101                                 } else {
102                                         tar_filename++;
103                                 }
104
105                                 if (strcmp(tar_filename, "control") == 0) {
106                                         return(size);
107                                 }
108                         }
109
110                 }
111 */
112                 if (untar_function & (extract_verbose_extract | extract_contents)) {
113                         printf("%s\n", raw_tar_header.name);
114                 }
115
116                 /* extract files */
117                 if (base_path != NULL) {
118                         dir = xmalloc(strlen(raw_tar_header.name) + strlen(base_path) + 2);
119                         sprintf(dir, "%s/%s", base_path, raw_tar_header.name);
120                         create_path(dir, 0777);
121                 }
122                 switch (raw_tar_header.typeflag ) {
123                         case '0':
124                         case '\0':
125                                 /* If the name ends in a '/' then assume it is
126                                  * supposed to be a directory, and fall through
127                                  */
128                                 if (raw_tar_header.name[strlen(raw_tar_header.name)-1] != '/') {
129                                         switch (untar_function) {
130                                                 case (extract_extract): {
131                                                                 FILE *dst_file = wfopen(dir, "w");
132                                                                 copy_file_chunk(src_tar_file, dst_file, size);
133                                                                 fclose(dst_file);
134                                                         }
135                                                         break;
136                                                 default: {
137                                                                 int remaining = size;
138                                                                 while (remaining-- > 0) {
139                                                                         fgetc(src_tar_file);
140                                                                 }
141                                                         }
142                                         }
143                                         uncompressed_count += size;
144                                         break;
145                                 }
146                         case '5':
147                                 if (untar_function & (extract_extract | extract_verbose_extract)) {
148                                         if (create_path(dir, mode) != TRUE) {
149                                                 free(dir);
150                                                 perror_msg("%s: Cannot mkdir", raw_tar_header.name); 
151                                                 return(EXIT_FAILURE);
152                                         }
153                                 }
154                                 break;
155                         case '1':
156                                 if (untar_function & extract_extract) {
157                                         if (link(raw_tar_header.linkname, raw_tar_header.name) < 0) {
158                                                 free(dir);
159                                                 perror_msg("%s: Cannot create hard link to '%s'", raw_tar_header.name, raw_tar_header.linkname); 
160                                                 return(EXIT_FAILURE);
161                                         }
162                                 }
163                                 break;
164                         case '2':
165                                 if (untar_function & extract_extract) {
166                                         if (symlink(raw_tar_header.linkname, raw_tar_header.name) < 0) {
167                                                 free(dir);
168                                                 perror_msg("%s: Cannot create symlink to '%s'", raw_tar_header.name, raw_tar_header.linkname); 
169                                                 return(EXIT_FAILURE);
170                                         }
171                                 }
172                                 break;
173                         case '3':
174                         case '4':
175                         case '6':
176 //                              if (tarExtractSpecial( &header, extractFlag, tostdoutFlag)==FALSE)
177 //                                      errorFlag=TRUE;
178 //                              break;
179                         default:
180                                 error_msg("Unknown file type '%c' in tar file", raw_tar_header.typeflag);
181                                 free(dir);
182                                 return(EXIT_FAILURE);
183                 }
184 //              free(dir);
185         }
186         return(EXIT_SUCCESS);
187 }