1 /* tar.c - create/extract archives
2 *
3 * Copyright 2014 Ashwini Kumar <ak.ashwini81@gmail.com>
4 *
5 * USTAR interchange format is of interest in
6 * See http://http://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html
7 * For writing to external program
8 * http://www.gnu.org/software/tar/manual/html_node/Writing-to-an-External-Program.html
9
10 USE_TAR(NEWTOY(tar, "&(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)j(bzip2)z(gzip)O(to-stdout)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):[!txc][!jz]", TOYFLAG_USR|TOYFLAG_BIN))
11
12 config TAR
13 bool "tar"
14 default n
15 help
16 usage: tar -[cxtjzhmvO] [-X FILE] [-T FILE] [-f TARFILE] [-C DIR]
17
18 Create, extract, or list files from a tar file
19
20 Operation:
21 c Create
22 f Name of TARFILE ('-' for stdin/out)
23 h Follow symlinks
24 j (De)compress using bzip2
25 m Don't restore mtime
26 t List
27 v Verbose
28 x Extract
29 z (De)compress using gzip
30 C Change to DIR before operation
31 O Extract to stdout
32 exclude=FILE File to exclude
33 X File with names to exclude
34 T File with names to include
35 */
36
37 #define FOR_tar
38 #include "toys.h"
39
40 GLOBALS(
41 char *fname;
42 char *dir;
43 struct arg_list *inc_file;
44 struct arg_list *exc_file;
45 char *tocmd;
46 struct arg_list *exc;
47
48 struct arg_list *inc, *pass;
49 void *inodes, *handle;
50 )
51
52 struct tar_hdr {
53 char name[100], mode[8], uid[8], gid[8],size[12], mtime[12], chksum[8],
54 type, link[100], magic[8], uname[32], gname[32], major[8], minor[8],
55 prefix[155], padd[12];
56 };
57
58 struct file_header {
59 char *name, *link_target, *uname, *gname;
60 off_t size;
61 uid_t uid;
62 gid_t gid;
63 mode_t mode;
64 time_t mtime;
65 dev_t device;
66 };
67
68 struct archive_handler {
69 int src_fd;
70 struct file_header file_hdr;
71 off_t offset;
72 void (*extract_handler)(struct archive_handler*);
73 };
74
75 struct inode_list {
76 struct inode_list *next;
77 char *arg;
78 ino_t ino;
79 dev_t dev;
80 };
81
copy_in_out(int src,int dst,off_t size)82 static void copy_in_out(int src, int dst, off_t size)
83 {
84 int i, rd, rem = size%512, cnt;
85
86 cnt = size/512 + (rem?1:0);
87
88 for (i = 0; i < cnt; i++) {
89 rd = (i == cnt-1 && rem) ? rem : 512;
90 xreadall(src, toybuf, rd);
91 writeall(dst, toybuf, rd);
92 }
93 }
94
95 //convert to octal
itoo(char * str,int len,off_t val)96 static void itoo(char *str, int len, off_t val)
97 {
98 char *t, tmp[sizeof(off_t)*3+1];
99 int cnt = sprintf(tmp, "%0*llo", len, (unsigned long long)val);
100
101 t = tmp + cnt - len;
102 if (*t == '0') t++;
103 memcpy(str, t, len);
104 }
105
seen_inode(void ** list,struct stat * st,char * name)106 static struct inode_list *seen_inode(void **list, struct stat *st, char *name)
107 {
108 if (!st) llist_traverse(*list, llist_free_arg);
109 else if (!S_ISDIR(st->st_mode) && st->st_nlink > 1) {
110 struct inode_list *new;
111
112 for (new = *list; new; new = new->next)
113 if(new->ino == st->st_ino && new->dev == st->st_dev)
114 return new;
115
116 new = xzalloc(sizeof(*new));
117 new->ino = st->st_ino;
118 new->dev = st->st_dev;
119 new->arg = xstrdup(name);
120 new->next = *list;
121 *list = new;
122 }
123 return 0;
124 }
125
write_longname(struct archive_handler * tar,char * name,char type)126 static void write_longname(struct archive_handler *tar, char *name, char type)
127 {
128 struct tar_hdr tmp;
129 unsigned int sum = 0;
130 int i, sz = strlen(name) +1;
131 char buf[512] = {0,};
132
133 memset(&tmp, 0, sizeof(tmp));
134 strcpy(tmp.name, "././@LongLink");
135 sprintf(tmp.mode, "%0*d", (int)sizeof(tmp.mode)-1, 0);
136 sprintf(tmp.uid, "%0*d", (int)sizeof(tmp.uid)-1, 0);
137 sprintf(tmp.gid, "%0*d", (int)sizeof(tmp.gid)-1, 0);
138 sprintf(tmp.size, "%0*d", (int)sizeof(tmp.size)-1, 0);
139 sprintf(tmp.mtime, "%0*d", (int)sizeof(tmp.mtime)-1, 0);
140 itoo(tmp.size, sizeof(tmp.size), sz);
141 tmp.type = type;
142 memset(tmp.chksum, ' ', 8);
143 strcpy(tmp.magic, "ustar ");
144 for (i= 0; i < 512; i++) sum += (unsigned int)((char*)&tmp)[i];
145 itoo(tmp.chksum, sizeof(tmp.chksum)-1, sum);
146
147 writeall(tar->src_fd, (void*) &tmp, sizeof(tmp));
148 //write name to archive
149 writeall(tar->src_fd, name, sz);
150 if (sz%512) writeall(tar->src_fd, buf, (512-(sz%512)));
151 }
152
filter(struct arg_list * lst,char * name)153 static int filter(struct arg_list *lst, char *name)
154 {
155 struct arg_list *cur;
156
157 for (cur = lst; cur; cur = cur->next)
158 if (!fnmatch(cur->arg, name, 1<<3)) return 1;
159 return 0;
160 }
161
add_file(struct archive_handler * tar,char ** nam,struct stat * st)162 static void add_file(struct archive_handler *tar, char **nam, struct stat *st)
163 {
164 struct tar_hdr hdr;
165 struct passwd *pw;
166 struct group *gr;
167 struct inode_list *node;
168 int i, fd =-1;
169 char *c, *p, *name = *nam, *lnk, *hname, buf[512] = {0,};
170 unsigned int sum = 0;
171 static int warn = 1;
172
173 for (p = name; *p; p++)
174 if ((p == name || p[-1] == '/') && *p != '/'
175 && filter(TT.exc, p)) return;
176
177 if (S_ISDIR(st->st_mode) && name[strlen(name)-1] != '/') {
178 lnk = xmprintf("%s/",name);
179 free(name);
180 *nam = name = lnk;
181 }
182 hname = name;
183 //remove leading '/' or relative path '../' component
184 if (*hname == '/') hname++;
185 if (!*hname) return;
186 while ((c = strstr(hname, "../"))) hname = c + 3;
187 if (warn && hname != name) {
188 fprintf(stderr, "removing leading '%.*s' "
189 "from member names\n", (int)(hname-name), name);
190 warn = 0;
191 }
192
193 memset(&hdr, 0, sizeof(hdr));
194 strncpy(hdr.name, hname, sizeof(hdr.name));
195 itoo(hdr.mode, sizeof(hdr.mode), st->st_mode &07777);
196 itoo(hdr.uid, sizeof(hdr.uid), st->st_uid);
197 itoo(hdr.gid, sizeof(hdr.gid), st->st_gid);
198 itoo(hdr.size, sizeof(hdr.size), 0); //set size later
199 itoo(hdr.mtime, sizeof(hdr.mtime), st->st_mtime);
200 for (i=0; i<sizeof(hdr.chksum); i++) hdr.chksum[i] = ' ';
201
202 if ((node = seen_inode(&TT.inodes, st, hname))) {
203 //this is a hard link
204 hdr.type = '1';
205 if (strlen(node->arg) > sizeof(hdr.link))
206 write_longname(tar, hname, 'K'); //write longname LINK
207 xstrncpy(hdr.link, node->arg, sizeof(hdr.link));
208 } else if (S_ISREG(st->st_mode)) {
209 hdr.type = '0';
210 if (st->st_size <= (off_t)0777777777777LL)
211 itoo(hdr.size, sizeof(hdr.size), st->st_size);
212 else {
213 error_msg("can't store file '%s' of size '%lld'\n",
214 hname, (unsigned long long)st->st_size);
215 return;
216 }
217 } else if (S_ISLNK(st->st_mode)) {
218 hdr.type = '2'; //'K' long link
219 if (!(lnk = xreadlink(name))) {
220 perror_msg("readlink");
221 return;
222 }
223 if (strlen(lnk) > sizeof(hdr.link))
224 write_longname(tar, hname, 'K'); //write longname LINK
225 xstrncpy(hdr.link, lnk, sizeof(hdr.link));
226 free(lnk);
227 }
228 else if (S_ISDIR(st->st_mode)) hdr.type = '5';
229 else if (S_ISFIFO(st->st_mode)) hdr.type = '6';
230 else if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
231 hdr.type = (S_ISCHR(st->st_mode))?'3':'4';
232 itoo(hdr.major, sizeof(hdr.major), dev_major(st->st_rdev));
233 itoo(hdr.minor, sizeof(hdr.minor), dev_minor(st->st_rdev));
234 } else {
235 error_msg("unknown file type '%o'", st->st_mode & S_IFMT);
236 return;
237 }
238 if (strlen(hname) > sizeof(hdr.name))
239 write_longname(tar, hname, 'L'); //write longname NAME
240 strcpy(hdr.magic, "ustar ");
241 if ((pw = getpwuid(st->st_uid)))
242 snprintf(hdr.uname, sizeof(hdr.uname), "%s", pw->pw_name);
243 else snprintf(hdr.uname, sizeof(hdr.uname), "%d", st->st_uid);
244
245 if ((gr = getgrgid(st->st_gid)))
246 snprintf(hdr.gname, sizeof(hdr.gname), "%s", gr->gr_name);
247 else snprintf(hdr.gname, sizeof(hdr.gname), "%d", st->st_gid);
248
249 //calculate chksum.
250 for (i= 0; i < 512; i++) sum += (unsigned int)((char*)&hdr)[i];
251 itoo(hdr.chksum, sizeof(hdr.chksum)-1, sum);
252 if (toys.optflags & FLAG_v) printf("%s\n",hname);
253 writeall(tar->src_fd, (void*)&hdr, 512);
254
255 //write actual data to archive
256 if (hdr.type != '0') return; //nothing to write
257 if ((fd = open(name, O_RDONLY)) < 0) {
258 perror_msg("can't open '%s'", name);
259 return;
260 }
261 copy_in_out(fd, tar->src_fd, st->st_size);
262 if (st->st_size%512) writeall(tar->src_fd, buf, (512-(st->st_size%512)));
263 close(fd);
264 }
265
add_to_tar(struct dirtree * node)266 static int add_to_tar(struct dirtree *node)
267 {
268 struct stat st;
269 char *path;
270 struct archive_handler *hdl = (struct archive_handler*)TT.handle;
271
272 if (!fstat(hdl->src_fd, &st) && st.st_dev == node->st.st_dev
273 && st.st_ino == node->st.st_ino) {
274 error_msg("'%s' file is the archive; not dumped", TT.fname);
275 return ((DIRTREE_RECURSE | ((toys.optflags & FLAG_h)?DIRTREE_SYMFOLLOW:0)));
276 }
277
278 if (!dirtree_notdotdot(node)) return 0;
279 path = dirtree_path(node, 0);
280 add_file(hdl, &path, &(node->st)); //path may be modified
281 free(path);
282 if (toys.optflags & FLAG_no_recursion) return 0;
283 return ((DIRTREE_RECURSE | ((toys.optflags & FLAG_h)?DIRTREE_SYMFOLLOW:0)));
284 }
285
compress_stream(struct archive_handler * tar_hdl)286 static void compress_stream(struct archive_handler *tar_hdl)
287 {
288 int pipefd[2];
289 pid_t cpid;
290
291 xpipe(pipefd);
292
293 signal(SIGPIPE, SIG_IGN);
294 cpid = fork();
295 if (cpid == -1) perror_exit("fork");
296
297 if (!cpid) { /* Child reads from pipe */
298 char *argv[] = {(toys.optflags&FLAG_z)?"gzip":"bzip2", "-f", NULL};
299 xclose(pipefd[1]); /* Close unused write*/
300 dup2(pipefd[0], 0);
301 dup2(tar_hdl->src_fd, 1); //write to tar fd
302 xexec(argv);
303 } else {
304 xclose(pipefd[0]); /* Close unused read end */
305 dup2(pipefd[1], tar_hdl->src_fd); //write to pipe
306 }
307 }
308
extract_to_stdout(struct archive_handler * tar)309 static void extract_to_stdout(struct archive_handler *tar)
310 {
311 struct file_header *file_hdr = &tar->file_hdr;
312
313 copy_in_out(tar->src_fd, 0, file_hdr->size);
314 tar->offset += file_hdr->size;
315 }
316
extract_to_command(struct archive_handler * tar)317 static void extract_to_command(struct archive_handler *tar)
318 {
319 int pipefd[2], status = 0;
320 pid_t cpid;
321 struct file_header *file_hdr = &tar->file_hdr;
322
323 xpipe(pipefd);
324 if (!S_ISREG(file_hdr->mode)) return; //only regular files are supported.
325
326 cpid = fork();
327 if (cpid == -1) perror_exit("fork");
328
329 if (!cpid) { // Child reads from pipe
330 char buf[64], *argv[4] = {"sh", "-c", TT.tocmd, NULL};
331
332 setenv("TAR_FILETYPE", "f", 1);
333 sprintf(buf, "%0o", file_hdr->mode);
334 setenv("TAR_MODE", buf, 1);
335 sprintf(buf, "%ld", (long)file_hdr->size);
336 setenv("TAR_SIZE", buf, 1);
337 setenv("TAR_FILENAME", file_hdr->name, 1);
338 setenv("TAR_UNAME", file_hdr->uname, 1);
339 setenv("TAR_GNAME", file_hdr->gname, 1);
340 sprintf(buf, "%0o", (int)file_hdr->mtime);
341 setenv("TAR_MTIME", buf, 1);
342 sprintf(buf, "%0o", file_hdr->uid);
343 setenv("TAR_UID", buf, 1);
344 sprintf(buf, "%0o", file_hdr->gid);
345 setenv("TAR_GID", buf, 1);
346
347 xclose(pipefd[1]); // Close unused write
348 dup2(pipefd[0], 0);
349 signal(SIGPIPE, SIG_DFL);
350 xexec(argv);
351 } else {
352 xclose(pipefd[0]); // Close unused read end
353 copy_in_out(tar->src_fd, pipefd[1], file_hdr->size);
354 tar->offset += file_hdr->size;
355 xclose(pipefd[1]);
356 waitpid(cpid, &status, 0);
357 if (WIFSIGNALED(status))
358 xprintf("tar : %d: child returned %d\n", cpid, WTERMSIG(status));
359 }
360 }
361
extract_to_disk(struct archive_handler * tar)362 static void extract_to_disk(struct archive_handler *tar)
363 {
364 int flags, dst_fd = -1;
365 char *s;
366 struct stat ex;
367 struct file_header *file_hdr = &tar->file_hdr;
368
369 flags = strlen(file_hdr->name);
370 if (flags>2) {
371 if (strstr(file_hdr->name, "/../") || !strcmp(file_hdr->name, "../") ||
372 !strcmp(file_hdr->name+flags-3, "/.."))
373 {
374 error_msg("drop %s", file_hdr->name);
375 }
376 }
377
378 if (file_hdr->name[flags-1] == '/') file_hdr->name[flags-1] = 0;
379 //Regular file with preceding path
380 if ((s = strrchr(file_hdr->name, '/'))) {
381 if (mkpath(file_hdr->name) && errno !=EEXIST) {
382 error_msg(":%s: not created", file_hdr->name);
383 return;
384 }
385 }
386
387 //remove old file, if exists
388 if (!(toys.optflags & FLAG_k) && !S_ISDIR(file_hdr->mode)
389 && !lstat( file_hdr->name, &ex)) {
390 if (unlink(file_hdr->name)) {
391 perror_msg("can't remove: %s",file_hdr->name);
392 }
393 }
394
395 //hard link
396 if (S_ISREG(file_hdr->mode) && file_hdr->link_target) {
397 if (link(file_hdr->link_target, file_hdr->name))
398 perror_msg("can't link '%s' -> '%s'",file_hdr->name, file_hdr->link_target);
399 goto COPY;
400 }
401
402 switch (file_hdr->mode & S_IFMT) {
403 case S_IFREG:
404 flags = O_WRONLY|O_CREAT|O_EXCL;
405 if (toys.optflags & FLAG_overwrite) flags = O_WRONLY|O_CREAT|O_TRUNC;
406 dst_fd = open(file_hdr->name, flags, file_hdr->mode & 07777);
407 if (dst_fd == -1) perror_msg("%s: can't open", file_hdr->name);
408 break;
409 case S_IFDIR:
410 if ((mkdir(file_hdr->name, file_hdr->mode) == -1) && errno != EEXIST)
411 perror_msg("%s: can't create", file_hdr->name);
412 break;
413 case S_IFLNK:
414 if (symlink(file_hdr->link_target, file_hdr->name))
415 perror_msg("can't link '%s' -> '%s'",file_hdr->name, file_hdr->link_target);
416 break;
417 case S_IFBLK:
418 case S_IFCHR:
419 case S_IFIFO:
420 if (mknod(file_hdr->name, file_hdr->mode, file_hdr->device))
421 perror_msg("can't create '%s'", file_hdr->name);
422 break;
423 default:
424 printf("type not yet supported\n");
425 break;
426 }
427
428 //copy file....
429 COPY:
430 copy_in_out(tar->src_fd, dst_fd, file_hdr->size);
431 tar->offset += file_hdr->size;
432 close(dst_fd);
433
434 if (S_ISLNK(file_hdr->mode)) return;
435 if (!(toys.optflags & FLAG_o)) {
436 //set ownership..., --no-same-owner, --numeric-owner
437 uid_t u = file_hdr->uid;
438 gid_t g = file_hdr->gid;
439
440 if (!(toys.optflags & FLAG_numeric_owner)) {
441 struct group *gr = getgrnam(file_hdr->gname);
442 struct passwd *pw = getpwnam(file_hdr->uname);
443 if (pw) u = pw->pw_uid;
444 if (gr) g = gr->gr_gid;
445 }
446 if (chown(file_hdr->name, u, g))
447 perror_msg("chown %d:%d '%s'", u, g, file_hdr->name);;
448 }
449
450 if (toys.optflags & FLAG_p) // || !(toys.optflags & FLAG_no_same_permissions))
451 chmod(file_hdr->name, file_hdr->mode);
452
453 //apply mtime
454 if (!(toys.optflags & FLAG_m)) {
455 struct timeval times[2] = {{file_hdr->mtime, 0},{file_hdr->mtime, 0}};
456 utimes(file_hdr->name, times);
457 }
458 }
459
add_to_list(struct arg_list ** llist,char * name)460 static void add_to_list(struct arg_list **llist, char *name)
461 {
462 struct arg_list **list = llist;
463
464 while (*list) list=&((*list)->next);
465 *list = xzalloc(sizeof(struct arg_list));
466 (*list)->arg = name;
467 if ((name[strlen(name)-1] == '/') && strlen(name) != 1)
468 name[strlen(name)-1] = '\0';
469 }
470
add_from_file(struct arg_list ** llist,struct arg_list * flist)471 static void add_from_file(struct arg_list **llist, struct arg_list *flist)
472 {
473 char *line = NULL;
474
475 while (flist) {
476 int fd = 0;
477
478 if (strcmp((char *)flist->arg, "-"))
479 fd = xopen((char *)flist->arg, O_RDONLY);
480
481 while ((line = get_line(fd))) {
482 add_to_list(llist, line);
483 }
484 if (fd) close(fd);
485 flist = flist->next;
486 }
487 }
488
init_handler()489 static struct archive_handler *init_handler()
490 {
491 struct archive_handler *tar_hdl = xzalloc(sizeof(struct archive_handler));
492 tar_hdl->extract_handler = extract_to_disk;
493 return tar_hdl;
494 }
495
496 //convert octal to int
otoi(char * str,int len)497 static int otoi(char *str, int len)
498 {
499 long val;
500 char *endp, inp[len+1]; //1 for NUL termination
501
502 memcpy(inp, str, len);
503 inp[len] = '\0'; //nul-termination made sure
504 val = strtol(inp, &endp, 8);
505 if (*endp && *endp != ' ') error_exit("invalid param");
506 return (int)val;
507 }
508
extract_stream(struct archive_handler * tar_hdl)509 static void extract_stream(struct archive_handler *tar_hdl)
510 {
511 int pipefd[2];
512 pid_t cpid;
513
514 xpipe(pipefd);
515
516 cpid = fork();
517 if (cpid == -1) perror_exit("fork");
518
519 if (!cpid) { /* Child reads from pipe */
520 char *argv[] =
521 {(toys.optflags&FLAG_z)?"gunzip":"bunzip2", "-cf", "-", NULL};
522 xclose(pipefd[0]); /* Close unused read*/
523 dup2(tar_hdl->src_fd, 0);
524 dup2(pipefd[1], 1); //write to pipe
525 xexec(argv);
526 } else {
527 xclose(pipefd[1]); /* Close unused read end */
528 dup2(pipefd[0], tar_hdl->src_fd); //read from pipe
529 }
530 }
531
process_extended_hdr(struct archive_handler * tar,int size)532 static char *process_extended_hdr(struct archive_handler *tar, int size)
533 {
534 char *value = NULL, *p, *buf = xzalloc(size+1);
535
536 if (readall(tar->src_fd, buf, size) != size) error_exit("short read");
537 buf[size] = 0;
538 tar->offset += size;
539 p = buf;
540
541 while (size) {
542 char *key;
543 int len, n;
544
545 // extended records are of the format: "LEN NAME=VALUE\n"
546 sscanf(p, "%d %n", &len, &n);
547 key = p + n;
548 p += len;
549 size -= len;
550 p[-1] = 0;
551 if (size < 0) {
552 error_msg("corrupted extended header");
553 break;
554 }
555
556 len = strlen("path=");
557 if (!strncmp(key, "path=", len)) {
558 value = key + strlen("path=");
559 break;
560 }
561 }
562 if (value) value = xstrdup(value);
563 free(buf);
564 return value;
565 }
566
tar_skip(struct archive_handler * tar,int sz)567 static void tar_skip(struct archive_handler *tar, int sz)
568 {
569 int x;
570
571 while ((x = lskip(tar->src_fd, sz))) {
572 tar->offset += sz - x;
573 sz = x;
574 }
575 tar->offset += sz;
576 }
577
unpack_tar(struct archive_handler * tar_hdl)578 static void unpack_tar(struct archive_handler *tar_hdl)
579 {
580 struct tar_hdr tar;
581 struct file_header *file_hdr;
582 int i, j, maj, min, sz, e = 0;
583 unsigned int cksum;
584 char *longname = NULL, *longlink = NULL;
585
586 while (1) {
587 cksum = 0;
588 if (tar_hdl->offset % 512) {
589 sz = 512 - tar_hdl->offset % 512;
590 tar_skip(tar_hdl, sz);
591 }
592 i = readall(tar_hdl->src_fd, &tar, 512);
593 tar_hdl->offset += i;
594 if (i != 512) {
595 if (i >= 2) goto CHECK_MAGIC; //may be a small (<512 byte)zipped file
596 error_exit("read error");
597 }
598
599 if (!tar.name[0]) {
600 if (e) return; //end of tar 2 empty blocks
601 e = 1;//empty jump to next block
602 continue;
603 }
604 if (strncmp(tar.magic, "ustar", 5)) {
605 // Try detecting .gz or .bz2 by looking for their magic.
606 CHECK_MAGIC:
607 if ((!strncmp(tar.name, "\x1f\x8b", 2) || !strncmp(tar.name, "BZh", 3))
608 && !lseek(tar_hdl->src_fd, -i, SEEK_CUR)) {
609 toys.optflags |= (*tar.name == 'B') ? FLAG_j : FLAG_z;
610 tar_hdl->offset -= i;
611 extract_stream(tar_hdl);
612 continue;
613 }
614 error_exit("invalid tar format");
615 }
616
617 for (j = 0; j<148; j++) cksum += (unsigned int)((char*)&tar)[j];
618 for (j = 156; j<500; j++) cksum += (unsigned int)((char*)&tar)[j];
619 //cksum field itself treated as ' '
620 for ( j= 0; j<8; j++) cksum += (unsigned int)' ';
621
622 if (cksum != otoi(tar.chksum, sizeof(tar.chksum))) error_exit("wrong cksum");
623
624 file_hdr = &tar_hdl->file_hdr;
625 memset(file_hdr, 0, sizeof(struct file_header));
626 file_hdr->mode = otoi(tar.mode, sizeof(tar.mode));
627 file_hdr->uid = otoi(tar.uid, sizeof(tar.uid));
628 file_hdr->gid = otoi(tar.gid, sizeof(tar.gid));
629 file_hdr->size = otoi(tar.size, sizeof(tar.size));
630 file_hdr->mtime = otoi(tar.mtime, sizeof(tar.mtime));
631 file_hdr->uname = xstrdup(tar.uname);
632 file_hdr->gname = xstrdup(tar.gname);
633 maj = otoi(tar.major, sizeof(tar.major));
634 min = otoi(tar.minor, sizeof(tar.minor));
635 file_hdr->device = dev_makedev(maj, min);
636
637 if (tar.type <= '7') {
638 if (tar.link[0]) {
639 sz = sizeof(tar.link);
640 file_hdr->link_target = xmalloc(sz + 1);
641 memcpy(file_hdr->link_target, tar.link, sz);
642 file_hdr->link_target[sz] = '\0';
643 }
644
645 file_hdr->name = xzalloc(256);// pathname supported size
646 if (tar.prefix[0]) {
647 memcpy(file_hdr->name, tar.prefix, sizeof(tar.prefix));
648 sz = strlen(file_hdr->name);
649 if (file_hdr->name[sz-1] != '/') file_hdr->name[sz] = '/';
650 }
651 sz = strlen(file_hdr->name);
652 memcpy(file_hdr->name + sz, tar.name, sizeof(tar.name));
653 if (file_hdr->name[255]) error_exit("filename too long");
654 }
655
656 switch (tar.type) {
657 // case '\0':
658 case '0':
659 case '7':
660 case '1': //Hard Link
661 file_hdr->mode |= S_IFREG;
662 break;
663 case '2':
664 file_hdr->mode |= S_IFLNK;
665 break;
666 case '3':
667 file_hdr->mode |= S_IFCHR;
668 break;
669 case '4':
670 file_hdr->mode |= S_IFBLK;
671 break;
672 case '5':
673 file_hdr->mode |= S_IFDIR;
674 break;
675 case '6':
676 file_hdr->mode |= S_IFIFO;
677 break;
678 case 'K':
679 longlink = xzalloc(file_hdr->size +1);
680 xread(tar_hdl->src_fd, longlink, file_hdr->size);
681 tar_hdl->offset += file_hdr->size;
682 continue;
683 case 'L':
684 free(longname);
685 longname = xzalloc(file_hdr->size +1);
686 xread(tar_hdl->src_fd, longname, file_hdr->size);
687 tar_hdl->offset += file_hdr->size;
688 continue;
689 case 'D':
690 case 'M':
691 case 'N':
692 case 'S':
693 case 'V':
694 case 'g': // pax global header
695 tar_skip(tar_hdl, file_hdr->size);
696 continue;
697 case 'x': // pax extended header
698 free(longname);
699 longname = process_extended_hdr(tar_hdl, file_hdr->size);
700 continue;
701 default: break;
702 }
703
704 if (longname) {
705 free(file_hdr->name);
706 file_hdr->name = longname;
707 longname = NULL;
708 }
709 if (longlink) {
710 free(file_hdr->link_target);
711 file_hdr->link_target = longlink;
712 longlink = NULL;
713 }
714
715 if ((file_hdr->mode & S_IFREG) &&
716 file_hdr->name[strlen(file_hdr->name)-1] == '/') {
717 file_hdr->name[strlen(file_hdr->name)-1] = '\0';
718 file_hdr->mode &= ~S_IFREG;
719 file_hdr->mode |= S_IFDIR;
720 }
721
722 if ((file_hdr->link_target && *(file_hdr->link_target))
723 || S_ISLNK(file_hdr->mode) || S_ISDIR(file_hdr->mode))
724 file_hdr->size = 0;
725
726 if (filter(TT.exc, file_hdr->name) ||
727 (TT.inc && !filter(TT.inc, file_hdr->name))) goto SKIP;
728 add_to_list(&TT.pass, xstrdup(file_hdr->name));
729
730 if (toys.optflags & FLAG_t) {
731 if (toys.optflags & FLAG_v) {
732 char perm[11];
733 struct tm *lc = localtime((const time_t*)&(file_hdr->mtime));
734
735 mode_to_string(file_hdr->mode, perm);
736 printf("%s %s/%s %9ld %d-%02d-%02d %02d:%02d:%02d ",perm,file_hdr->uname,
737 file_hdr->gname, (long)file_hdr->size, 1900+lc->tm_year,
738 1+lc->tm_mon, lc->tm_mday, lc->tm_hour, lc->tm_min, lc->tm_sec);
739 }
740 printf("%s",file_hdr->name);
741 if (file_hdr->link_target) printf(" -> %s",file_hdr->link_target);
742 xputc('\n');
743 SKIP:
744 tar_skip(tar_hdl, file_hdr->size);
745 } else {
746 if (toys.optflags & FLAG_v) printf("%s\n",file_hdr->name);
747 tar_hdl->extract_handler(tar_hdl);
748 }
749 free(file_hdr->name);
750 free(file_hdr->link_target);
751 free(file_hdr->uname);
752 free(file_hdr->gname);
753 }
754 }
755
tar_main(void)756 void tar_main(void)
757 {
758 struct archive_handler *tar_hdl;
759 int fd = 0;
760 struct arg_list *tmp;
761 char **args = toys.optargs;
762
763 if (!geteuid()) toys.optflags |= FLAG_p;
764
765 for (tmp = TT.exc; tmp; tmp = tmp->next)
766 tmp->arg = xstrdup(tmp->arg); //freeing at the end fails otherwise
767
768 while(*args) add_to_list(&TT.inc, xstrdup(*args++));
769 if (toys.optflags & FLAG_X) add_from_file(&TT.exc, TT.exc_file);
770 if (toys.optflags & FLAG_T) add_from_file(&TT.inc, TT.inc_file);
771
772 if (toys.optflags & FLAG_c) {
773 if (!TT.inc) error_exit("empty archive");
774 fd = 1;
775 }
776 if ((toys.optflags & FLAG_f) && strcmp(TT.fname, "-"))
777 fd = xcreate(TT.fname, fd*(O_WRONLY|O_CREAT|O_TRUNC), 0666);
778 if (toys.optflags & FLAG_C) xchdir(TT.dir);
779
780 tar_hdl = init_handler();
781 tar_hdl->src_fd = fd;
782
783 if ((toys.optflags & FLAG_x) || (toys.optflags & FLAG_t)) {
784 if (toys.optflags & FLAG_O) tar_hdl->extract_handler = extract_to_stdout;
785 if (toys.optflags & FLAG_to_command) {
786 signal(SIGPIPE, SIG_IGN); //will be using pipe between child & parent
787 tar_hdl->extract_handler = extract_to_command;
788 }
789 if (toys.optflags & FLAG_z) extract_stream(tar_hdl);
790 unpack_tar(tar_hdl);
791 for (tmp = TT.inc; tmp; tmp = tmp->next)
792 if (!filter(TT.exc, tmp->arg) && !filter(TT.pass, tmp->arg))
793 error_msg("'%s' not in archive", tmp->arg);
794 } else if (toys.optflags & FLAG_c) {
795 //create the tar here.
796 if (toys.optflags & (FLAG_j|FLAG_z)) compress_stream(tar_hdl);
797 for (tmp = TT.inc; tmp; tmp = tmp->next) {
798 TT.handle = tar_hdl;
799 //recurse thru dir and add files to archive
800 dirtree_flagread(tmp->arg, DIRTREE_SYMFOLLOW*!!(toys.optflags&FLAG_h),
801 add_to_tar);
802 }
803 memset(toybuf, 0, 1024);
804 writeall(tar_hdl->src_fd, toybuf, 1024);
805 seen_inode(&TT.inodes, 0, 0);
806 }
807
808 if (CFG_TOYBOX_FREE) {
809 close(tar_hdl->src_fd);
810 free(tar_hdl);
811 llist_traverse(TT.exc, llist_free_arg);
812 llist_traverse(TT.inc, llist_free_arg);
813 llist_traverse(TT.pass, llist_free_arg);
814 }
815 }
816