Commit | Line | Data |
---|---|---|
1479465f GJ |
1 | /* |
2 | * libdpkg - Debian packaging suite library routines | |
3 | * t-tarextract.c - test tar extractor | |
4 | * | |
5 | * Copyright © 2014 Guillem Jover <guillem@debian.org> | |
6 | * | |
7 | * This is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License as | |
9 | * published by the Free Software Foundation; either version 2, | |
10 | * or (at your option) any later version. | |
11 | * | |
12 | * This is distributed in the hope that it will be useful, but | |
13 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License | |
18 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | |
19 | */ | |
20 | ||
21 | #include <config.h> | |
22 | #include <compat.h> | |
23 | ||
24 | #include <sys/types.h> | |
25 | #if HAVE_SYS_SYSMACROS_H | |
26 | #include <sys/sysmacros.h> /* Needed on AIX for major()/minor(). */ | |
27 | #endif | |
28 | ||
29 | #include <fcntl.h> | |
30 | #include <stdint.h> | |
31 | #include <stdio.h> | |
32 | #include <stdlib.h> | |
33 | #include <unistd.h> | |
34 | ||
35 | #include <dpkg/ehandle.h> | |
36 | #include <dpkg/fdio.h> | |
37 | #include <dpkg/buffer.h> | |
38 | #include <dpkg/tarfn.h> | |
39 | ||
40 | struct tar_context { | |
41 | int tar_fd; | |
42 | }; | |
43 | ||
44 | static int | |
45 | tar_read(void *ctx, char *buffer, int size) | |
46 | { | |
47 | struct tar_context *tc = ctx; | |
48 | ||
49 | return fd_read(tc->tar_fd, buffer, size); | |
50 | } | |
51 | ||
52 | static int | |
53 | tar_object_skip(struct tar_context *tc, struct tar_entry *te) | |
54 | { | |
55 | off_t size; | |
56 | ||
57 | size = (te->size + TARBLKSZ - 1) / TARBLKSZ * TARBLKSZ; | |
58 | if (size == 0) | |
59 | return 0; | |
60 | ||
61 | return fd_skip(tc->tar_fd, size, NULL); | |
62 | } | |
63 | ||
64 | static int | |
65 | tar_object(void *ctx, struct tar_entry *te) | |
66 | { | |
67 | printf("%s mode=%o time=%ld.%.9d uid=%d gid=%d", te->name, | |
68 | te->stat.mode, te->mtime, 0, te->stat.uid, te->stat.gid); | |
69 | if (te->stat.uname) | |
70 | printf(" uname=%s", te->stat.uname); | |
71 | if (te->stat.gname) | |
72 | printf(" gname=%s", te->stat.gname); | |
73 | ||
74 | switch (te->type) { | |
75 | case TAR_FILETYPE_FILE0: | |
76 | case TAR_FILETYPE_FILE: | |
77 | tar_object_skip(ctx, te); | |
78 | printf(" type=file size=%jd", (intmax_t)te->size); | |
79 | break; | |
80 | case TAR_FILETYPE_HARDLINK: | |
81 | printf(" type=hardlink linkto=%s size=%jd", | |
82 | te->linkname, (intmax_t)te->size); | |
83 | break; | |
84 | case TAR_FILETYPE_SYMLINK: | |
85 | printf(" type=symlink linkto=%s size=%jd", | |
86 | te->linkname, (intmax_t)te->size); | |
87 | break; | |
88 | case TAR_FILETYPE_DIR: | |
89 | printf(" type=dir"); | |
90 | break; | |
91 | case TAR_FILETYPE_CHARDEV: | |
92 | case TAR_FILETYPE_BLOCKDEV: | |
93 | printf(" type=device id=%d.%d", major(te->dev), minor(te->dev)); | |
94 | break; | |
95 | case TAR_FILETYPE_FIFO: | |
96 | printf(" type=fifo"); | |
97 | break; | |
98 | default: | |
99 | ohshit("unexpected tar entry type '%c'", te->type); | |
100 | } | |
101 | ||
102 | printf("\n"); | |
103 | ||
104 | return 0; | |
105 | } | |
106 | ||
107 | struct tar_operations tar_ops = { | |
108 | .read = tar_read, | |
109 | .extract_file = tar_object, | |
110 | .link = tar_object, | |
111 | .symlink = tar_object, | |
112 | .mkdir = tar_object, | |
113 | .mknod = tar_object, | |
114 | }; | |
115 | ||
116 | int | |
117 | main(int argc, char **argv) | |
118 | { | |
119 | struct tar_context ctx; | |
120 | const char *tar_name = argv[1]; | |
121 | ||
122 | setvbuf(stdout, NULL, _IOLBF, 0); | |
123 | ||
124 | push_error_context(); | |
125 | ||
126 | if (tar_name) { | |
127 | ctx.tar_fd = open(tar_name, O_RDONLY); | |
128 | if (ctx.tar_fd < 0) | |
129 | ohshite("cannot open file '%s'", tar_name); | |
130 | } else { | |
131 | ctx.tar_fd = STDIN_FILENO; | |
132 | } | |
133 | ||
134 | if (tar_extractor(&ctx, &tar_ops)) | |
135 | ohshite("extracting tar"); | |
136 | ||
137 | if (tar_name) | |
138 | close(ctx.tar_fd); | |
139 | ||
140 | pop_error_context(ehflag_normaltidy); | |
141 | ||
142 | return 0; | |
143 | } |