1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39#define FOR_cpio
40#include "toys.h"
41
42GLOBALS(
43 char *F, *p, *H;
44)
45
46
47
48
49static char *strpad(int fd, unsigned len, unsigned align)
50{
51 char *str;
52
53 align = (align + len) & 3;
54 if (align) len += (4-align);
55 xreadall(fd, str = xmalloc(len+1), len);
56 str[len]=0;
57
58 return str;
59}
60
61
62static unsigned x8u(char *hex)
63{
64 unsigned val, inpos = 8, outpos;
65 char pattern[6];
66
67 while (*hex == '0') {
68 hex++;
69 if (!--inpos) return 0;
70 }
71
72 sprintf(pattern, "%%%dX%%n", inpos);
73 sscanf(hex, pattern, &val, &outpos);
74 if (inpos != outpos) error_exit("bad header");
75
76 return val;
77}
78
79void cpio_main(void)
80{
81
82 int pipe, afd = FLAG(o);
83 pid_t pid = 0;
84
85
86
87 if (TT.p) {
88 if (toys.stacktop) {
89
90
91 pid = xpopen(0, &pipe, 0);
92 afd = pipe;
93 } else {
94
95 toys.optflags |= FLAG_i;
96 xchdir(TT.p);
97 }
98 }
99
100 if (TT.F) {
101 int perm = FLAG(o) ? O_CREAT|O_WRONLY|O_TRUNC : O_RDONLY;
102
103 afd = xcreate(TT.F, perm, 0644);
104 }
105
106
107
108 if (FLAG(i) || FLAG(t)) for (;;) {
109 char *name, *tofree, *data;
110 unsigned size, mode, uid, gid, timestamp;
111 int test = FLAG(t), err = 0;
112
113
114 if (!(size =readall(afd, toybuf, 110))) break;
115 if (size != 110 || memcmp(toybuf, "070701", 6)) error_exit("bad header");
116 tofree = name = strpad(afd, x8u(toybuf+94), 110);
117 if (!strcmp("TRAILER!!!", name)) {
118 if (CFG_TOYBOX_FREE) free(tofree);
119 break;
120 }
121
122
123 while (*name == '/') name++;
124
125
126 size = x8u(toybuf+54);
127 mode = x8u(toybuf+14);
128 uid = x8u(toybuf+22);
129 gid = x8u(toybuf+30);
130 timestamp = x8u(toybuf+46);
131
132 if (FLAG(t) || FLAG(v)) puts(name);
133
134 if (!test && strrchr(name, '/') && mkpath(name)) {
135 perror_msg("mkpath '%s'", name);
136 test++;
137 }
138
139
140
141
142 if (S_ISDIR(mode)) {
143 if (!test) err = mkdir(name, mode);
144 } else if (S_ISLNK(mode)) {
145 data = strpad(afd, size, 0);
146 if (!test) err = symlink(data, name);
147 free(data);
148
149 if (!err && !geteuid() && !FLAG(no_preserve_owner))
150 err = lchown(name, uid, gid);
151 } else if (S_ISREG(mode)) {
152 int fd = test ? 0 : open(name, O_CREAT|O_WRONLY|O_TRUNC|O_NOFOLLOW, mode);
153
154
155
156 if (fd < 0) {
157 perror_msg("create %s", name);
158 test++;
159 }
160
161 data = toybuf;
162 while (size) {
163 if (size < sizeof(toybuf)) data = strpad(afd, size, 0);
164 else xreadall(afd, toybuf, sizeof(toybuf));
165 if (!test) xwrite(fd, data, data == toybuf ? sizeof(toybuf) : size);
166 if (data != toybuf) {
167 free(data);
168 break;
169 }
170 size -= sizeof(toybuf);
171 }
172
173 if (!test) {
174
175 if (!geteuid() && !FLAG(no_preserve_owner)) {
176 err = fchown(fd, uid, gid);
177 if (!err) err = fchmod(fd, mode);
178 }
179 close(fd);
180 }
181 } else if (!test)
182 err = mknod(name, mode, dev_makedev(x8u(toybuf+78), x8u(toybuf+86)));
183
184
185 if (!test && !err) {
186
187
188
189
190 if (!S_ISREG(mode) && !S_ISLNK(mode) && !geteuid()
191 && !FLAG(no_preserve_owner))
192 {
193 int fd = open(name, O_RDONLY|O_NOFOLLOW);
194 struct stat st;
195
196 if (fd != -1 && !fstat(fd, &st) && (st.st_mode&S_IFMT) == (mode&S_IFMT))
197 err = fchown(fd, uid, gid);
198 else err = 1;
199
200 close(fd);
201 }
202
203
204 if (!err) {
205 struct timespec times[2];
206
207 memset(times, 0, sizeof(struct timespec)*2);
208 times[0].tv_sec = times[1].tv_sec = timestamp;
209 err = utimensat(AT_FDCWD, name, times, AT_SYMLINK_NOFOLLOW);
210 }
211 }
212
213 if (err) perror_msg_raw(name);
214 free(tofree);
215
216
217
218 } else {
219 char *name = 0;
220 size_t size = 0;
221
222 for (;;) {
223 struct stat st;
224 unsigned nlen, error = 0, zero = 0;
225 int len, fd = -1;
226 ssize_t llen;
227
228 len = getline(&name, &size, stdin);
229 if (len<1) break;
230 if (name[len-1] == '\n') name[--len] = 0;
231 nlen = len+1;
232 if (lstat(name, &st) || (S_ISREG(st.st_mode)
233 && st.st_size && (fd = open(name, O_RDONLY))<0))
234 {
235 perror_msg_raw(name);
236 continue;
237 }
238
239 if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) st.st_size = 0;
240 if (st.st_size >> 32) perror_msg("skipping >2G file '%s'", name);
241 else {
242 llen = sprintf(toybuf,
243 "070701%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X%08X",
244 (int)st.st_ino, st.st_mode, st.st_uid, st.st_gid, (int)st.st_nlink,
245 (int)st.st_mtime, (int)st.st_size, dev_major(st.st_dev),
246 dev_minor(st.st_dev), dev_major(st.st_rdev), dev_minor(st.st_rdev),
247 nlen, 0);
248 xwrite(afd, toybuf, llen);
249 xwrite(afd, name, nlen);
250
251
252 llen = (llen + nlen) & 3;
253 if (llen) xwrite(afd, &zero, 4-llen);
254
255
256 llen = st.st_size;
257 if (S_ISLNK(st.st_mode)) {
258 if (readlink(name, toybuf, sizeof(toybuf)-1) == llen)
259 xwrite(afd, toybuf, llen);
260 else perror_msg("readlink '%s'", name);
261 } else while (llen) {
262 nlen = llen > sizeof(toybuf) ? sizeof(toybuf) : llen;
263 llen -= nlen;
264
265 if (nlen != readall(fd, toybuf, nlen))
266 if (!error++) perror_msg("bad read from file '%s'", name);
267 xwrite(afd, toybuf, nlen);
268 }
269 llen = st.st_size & 3;
270 if (llen) xwrite(afd, &zero, 4-llen);
271 }
272 close(fd);
273 }
274 free(name);
275
276 memset(toybuf, 0, sizeof(toybuf));
277 xwrite(afd, toybuf,
278 sprintf(toybuf, "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0)+4);
279 }
280 if (TT.F) xclose(afd);
281
282 if (TT.p) toys.exitval |= xpclose(pid, pipe);
283}
284