1 /*
2 * Copyright 2003-2012 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2
4 *
5 * Copyright 2005-2012 Ned Ludd - <solar@gentoo.org>
6 * Copyright 2005-2012 Mike Frysinger - <vapier@gentoo.org>
7 */
8
9 /* stick common symbols here that are needed by paxinc.h */
10
11 #define IN_paxinc
12 #include "paxinc.h"
13
14 char do_reverse_endian;
15
16 /* some of this ar code was taken from busybox */
17
18 #define AR_MAGIC "!<arch>"
19 #define AR_MAGIC_SIZE (sizeof(AR_MAGIC)-1) /* dont count null byte */
ar_open_fd(const char * filename,int fd,bool verbose)20 archive_handle *ar_open_fd(const char *filename, int fd, bool verbose)
21 {
22 static archive_handle ret;
23 char buf[AR_MAGIC_SIZE];
24
25 ret.filename = filename;
26 ret.fd = fd;
27 ret.skip = 0;
28 ret.extfn = NULL;
29 ret.verbose = verbose;
30
31 if (read(ret.fd, buf, AR_MAGIC_SIZE) != AR_MAGIC_SIZE)
32 return NULL;
33 if (strncmp(buf, AR_MAGIC, AR_MAGIC_SIZE))
34 return NULL;
35
36 return &ret;
37 }
ar_open(const char * filename,bool verbose)38 archive_handle *ar_open(const char *filename, bool verbose)
39 {
40 int fd;
41 archive_handle *ret;
42
43 if ((fd=open(filename, O_RDONLY)) == -1)
44 errp("%s: could not open", filename);
45
46 ret = ar_open_fd(filename, fd, verbose);
47 if (ret == NULL)
48 close(fd);
49
50 return ret;
51 }
52
ar_next(archive_handle * ar)53 archive_member *ar_next(archive_handle *ar)
54 {
55 char *s;
56 ssize_t len = 0;
57 static archive_member ret;
58
59 if (ar->skip && lseek(ar->fd, ar->skip, SEEK_CUR) == -1) {
60 close_and_ret:
61 free(ar->extfn);
62 close(ar->fd);
63 ar->extfn = NULL;
64 ar->fd = -1;
65 return NULL;
66 }
67
68 if (read(ar->fd, ret.buf.raw, sizeof(ret.buf.raw)) != sizeof(ret.buf.raw))
69 goto close_and_ret;
70
71 /* ar header starts on an even byte (2 byte aligned)
72 * '\n' is used for padding */
73 if (ret.buf.raw[0] == '\n') {
74 memmove(ret.buf.raw, ret.buf.raw+1, 59);
75 if (read(ar->fd, ret.buf.raw+59, 1) != 1)
76 goto close_and_ret;
77 }
78
79 if ((ret.buf.formatted.magic[0] != '`') || (ret.buf.formatted.magic[1] != '\n')) {
80 /* When dealing with corrupt or random embedded cross-compilers, they might
81 * be abusing the archive format; only complain when in verbose mode. */
82 if (ar->verbose)
83 warn("%s: invalid ar entry", ar->filename);
84 goto close_and_ret;
85 }
86
87 if (ret.buf.formatted.name[0] == '/' && ret.buf.formatted.name[1] == '/') {
88 if (ar->extfn != NULL) {
89 warn("%s: Duplicate GNU extended filename section", ar->filename);
90 goto close_and_ret;
91 }
92 len = atoi(ret.buf.formatted.size);
93 ar->extfn = xmalloc(sizeof(char) * (len + 1));
94 if (read(ar->fd, ar->extfn, len) != len)
95 goto close_and_ret;
96 ar->extfn[len--] = '\0';
97 for (; len > 0; len--)
98 if (ar->extfn[len] == '\n')
99 ar->extfn[len] = '\0';
100 ar->skip = 0;
101 return ar_next(ar);
102 }
103
104 s = ret.buf.formatted.name;
105 if (s[0] == '#' && s[1] == '1' && s[2] == '/') {
106 /* BSD extended filename, always in use on Darwin */
107 len = atoi(s + 3);
108 if (len <= (ssize_t)sizeof(ret.buf.formatted.name)) {
109 if (read(ar->fd, ret.buf.formatted.name, len) != len)
110 goto close_and_ret;
111 } else {
112 s = alloca(sizeof(char) * len + 1);
113 if (read(ar->fd, s, len) != len)
114 goto close_and_ret;
115 s[len] = '\0';
116 }
117 } else if (s[0] == '/' && s[1] >= '0' && s[1] <= '9') {
118 /* GNU extended filename */
119 if (ar->extfn == NULL) {
120 warn("%s: GNU extended filename without special data section", ar->filename);
121 goto close_and_ret;
122 }
123 s = ar->extfn + atoi(s + 1);
124 }
125
126 snprintf(ret.name, sizeof(ret.name), "%s:%s", ar->filename, s);
127 ret.name[sizeof(ret.name) - 1] = '\0';
128 if ((s=strchr(ret.name+strlen(ar->filename), '/')) != NULL)
129 *s = '\0';
130 ret.date = atoi(ret.buf.formatted.date);
131 ret.uid = atoi(ret.buf.formatted.uid);
132 ret.gid = atoi(ret.buf.formatted.gid);
133 ret.mode = strtol(ret.buf.formatted.mode, NULL, 8);
134 ret.size = atoi(ret.buf.formatted.size);
135 ar->skip = ret.size - len;
136
137 return &ret;
138 }
139
140 /* Convert file perms into octal string */
strfileperms(const char * fname)141 const char *strfileperms(const char *fname)
142 {
143 struct stat st;
144 static char buf[8];
145
146 if (stat(fname, &st) == -1)
147 return "";
148
149 snprintf(buf, sizeof(buf), "%o", st.st_mode);
150
151 return buf + 2;
152 }
153
154 /* Color helpers */
155 #define COLOR(c,b) "\e[" c ";" b "m"
156 const char *NORM = COLOR("00", "00");
157 const char *RED = COLOR("31", "01");
158 const char *YELLOW = COLOR("33", "01");
159
color_init(bool disable)160 void color_init(bool disable)
161 {
162 if (!disable) {
163 const char *nocolor = getenv("NOCOLOR");
164 if (nocolor)
165 disable = !strcmp(nocolor, "yes") || !strcmp(nocolor, "true");
166 }
167 if (disable)
168 NORM = RED = YELLOW = "";
169 }
170
171 /* File system helpers. */
172 int root_fd = AT_FDCWD;
173
fopenat_r(int dir_fd,const char * path)174 FILE *fopenat_r(int dir_fd, const char *path)
175 {
176 int fd = openat(dir_fd, path, O_RDONLY|O_CLOEXEC);
177 if (fd == -1)
178 return NULL;
179 return fdopen(fd, "re");
180 }
181
root_rel_path(const char * path)182 const char *root_rel_path(const char *path)
183 {
184 /*
185 * openat() will ignore the dirfd if path starts with
186 * a /, so consume all of that noise
187 *
188 * XXX: we don't handle relative paths like ../ that
189 * break out of the --root option, but for now, just
190 * don't do that :P.
191 */
192 if (root_fd != AT_FDCWD) {
193 while (*path == '/')
194 ++path;
195 if (*path == '\0')
196 path = ".";
197 }
198
199 return path;
200 }
201