GCC Code Coverage Report | |||||||||||||||||||||
|
|||||||||||||||||||||
Line | Branch | Exec | Source |
1 |
/* $OpenBSD: ar_subs.c,v 1.45 2015/03/19 05:14:24 guenther Exp $ */ |
||
2 |
/* $NetBSD: ar_subs.c,v 1.5 1995/03/21 09:07:06 cgd Exp $ */ |
||
3 |
|||
4 |
/*- |
||
5 |
* Copyright (c) 1992 Keith Muller. |
||
6 |
* Copyright (c) 1992, 1993 |
||
7 |
* The Regents of the University of California. All rights reserved. |
||
8 |
* |
||
9 |
* This code is derived from software contributed to Berkeley by |
||
10 |
* Keith Muller of the University of California, San Diego. |
||
11 |
* |
||
12 |
* Redistribution and use in source and binary forms, with or without |
||
13 |
* modification, are permitted provided that the following conditions |
||
14 |
* are met: |
||
15 |
* 1. Redistributions of source code must retain the above copyright |
||
16 |
* notice, this list of conditions and the following disclaimer. |
||
17 |
* 2. Redistributions in binary form must reproduce the above copyright |
||
18 |
* notice, this list of conditions and the following disclaimer in the |
||
19 |
* documentation and/or other materials provided with the distribution. |
||
20 |
* 3. Neither the name of the University nor the names of its contributors |
||
21 |
* may be used to endorse or promote products derived from this software |
||
22 |
* without specific prior written permission. |
||
23 |
* |
||
24 |
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
||
25 |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||
26 |
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
||
27 |
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
||
28 |
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||
29 |
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
||
30 |
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
||
31 |
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
||
32 |
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
||
33 |
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
||
34 |
* SUCH DAMAGE. |
||
35 |
*/ |
||
36 |
|||
37 |
#include <sys/types.h> |
||
38 |
#include <sys/time.h> |
||
39 |
#include <sys/stat.h> |
||
40 |
#include <signal.h> |
||
41 |
#include <string.h> |
||
42 |
#include <stdio.h> |
||
43 |
#include <fcntl.h> |
||
44 |
#include <errno.h> |
||
45 |
#include <unistd.h> |
||
46 |
#include <stdlib.h> |
||
47 |
#include "pax.h" |
||
48 |
#include "extern.h" |
||
49 |
|||
50 |
static void wr_archive(ARCHD *, int is_app); |
||
51 |
static int get_arc(void); |
||
52 |
static int next_head(ARCHD *); |
||
53 |
extern sigset_t s_mask; |
||
54 |
|||
55 |
/* |
||
56 |
* Routines which control the overall operation modes of pax as specified by |
||
57 |
* the user: list, append, read ... |
||
58 |
*/ |
||
59 |
|||
60 |
static char hdbuf[BLKMULT]; /* space for archive header on read */ |
||
61 |
u_long flcnt; /* number of files processed */ |
||
62 |
|||
63 |
/* |
||
64 |
* list() |
||
65 |
* list the contents of an archive which match user supplied pattern(s) |
||
66 |
* (no pattern matches all). |
||
67 |
*/ |
||
68 |
|||
69 |
void |
||
70 |
list(void) |
||
71 |
18 |
{ |
|
72 |
ARCHD *arcn; |
||
73 |
int res; |
||
74 |
ARCHD archd; |
||
75 |
time_t now; |
||
76 |
|||
77 |
18 |
arcn = &archd; |
|
78 |
/* |
||
79 |
* figure out archive type; pass any format specific options to the |
||
80 |
* archive option processing routine; call the format init routine. We |
||
81 |
* also save current time for ls_list() so we do not make a system |
||
82 |
* call for each file we need to print. If verbose (vflag) start up |
||
83 |
* the name and group caches. |
||
84 |
*/ |
||
85 |
✓✗✓✗ ✓✗ |
18 |
if ((get_arc() < 0) || ((*frmt->options)() < 0) || |
86 |
((*frmt->st_rd)() < 0)) |
||
87 |
return; |
||
88 |
|||
89 |
✗✓✗✗ ✗✗ |
18 |
if (vflag && ((uidtb_start() < 0) || (gidtb_start() < 0))) |
90 |
return; |
||
91 |
|||
92 |
18 |
now = time(NULL); |
|
93 |
|||
94 |
/* |
||
95 |
* step through the archive until the format says it is done |
||
96 |
*/ |
||
97 |
✓✓ | 136 |
while (next_head(arcn) == 0) { |
98 |
✗✓ | 100 |
if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) { |
99 |
/* |
||
100 |
* we need to read, to get the real filename |
||
101 |
*/ |
||
102 |
off_t cnt; |
||
103 |
if (!rd_wrfile(arcn, arcn->type == PAX_GLF |
||
104 |
? -1 : -2, &cnt)) |
||
105 |
(void)rd_skip(cnt + arcn->pad); |
||
106 |
continue; |
||
107 |
} |
||
108 |
|||
109 |
/* |
||
110 |
* check for pattern, and user specified options match. |
||
111 |
* When all patterns are matched we are done. |
||
112 |
*/ |
||
113 |
✗✓ | 100 |
if ((res = pat_match(arcn)) < 0) |
114 |
break; |
||
115 |
|||
116 |
✓✗✓✗ |
100 |
if ((res == 0) && (sel_chk(arcn) == 0)) { |
117 |
/* |
||
118 |
* pattern resulted in a selected file |
||
119 |
*/ |
||
120 |
✗✓ | 100 |
if (pat_sel(arcn) < 0) |
121 |
break; |
||
122 |
|||
123 |
/* |
||
124 |
* modify the name as requested by the user if name |
||
125 |
* survives modification, do a listing of the file |
||
126 |
*/ |
||
127 |
✗✓ | 100 |
if ((res = mod_name(arcn)) < 0) |
128 |
break; |
||
129 |
✓✗ | 100 |
if (res == 0) |
130 |
100 |
ls_list(arcn, now, stdout); |
|
131 |
} |
||
132 |
|||
133 |
/* |
||
134 |
* skip to next archive format header using values calculated |
||
135 |
* by the format header read routine |
||
136 |
*/ |
||
137 |
✗✓ | 100 |
if (rd_skip(arcn->skip + arcn->pad) == 1) |
138 |
break; |
||
139 |
} |
||
140 |
|||
141 |
/* |
||
142 |
* all done, let format have a chance to cleanup, and make sure that |
||
143 |
* the patterns supplied by the user were all matched |
||
144 |
*/ |
||
145 |
18 |
(void)(*frmt->end_rd)(); |
|
146 |
18 |
(void)sigprocmask(SIG_BLOCK, &s_mask, NULL); |
|
147 |
18 |
ar_close(0); |
|
148 |
18 |
pat_chk(); |
|
149 |
} |
||
150 |
|||
151 |
static int |
||
152 |
cmp_file_times(int mtime_flag, int ctime_flag, ARCHD *arcn, struct stat *sbp) |
||
153 |
{ |
||
154 |
struct stat sb; |
||
155 |
|||
156 |
if (sbp == NULL) { |
||
157 |
if (lstat(arcn->name, &sb) != 0) |
||
158 |
return (0); |
||
159 |
sbp = &sb; |
||
160 |
} |
||
161 |
|||
162 |
if (ctime_flag && mtime_flag) |
||
163 |
return (timespeccmp(&arcn->sb.st_mtim, &sbp->st_mtim, <=) && |
||
164 |
timespeccmp(&arcn->sb.st_ctim, &sbp->st_ctim, <=)); |
||
165 |
else if (ctime_flag) |
||
166 |
return (timespeccmp(&arcn->sb.st_ctim, &sbp->st_ctim, <=)); |
||
167 |
else |
||
168 |
return (timespeccmp(&arcn->sb.st_mtim, &sbp->st_mtim, <=)); |
||
169 |
} |
||
170 |
|||
171 |
/* |
||
172 |
* extract() |
||
173 |
* extract the member(s) of an archive as specified by user supplied |
||
174 |
* pattern(s) (no patterns extracts all members) |
||
175 |
*/ |
||
176 |
|||
177 |
void |
||
178 |
extract(void) |
||
179 |
2 |
{ |
|
180 |
ARCHD *arcn; |
||
181 |
int res; |
||
182 |
off_t cnt; |
||
183 |
ARCHD archd; |
||
184 |
int fd; |
||
185 |
time_t now; |
||
186 |
|||
187 |
2 |
sltab_start(); |
|
188 |
|||
189 |
2 |
arcn = &archd; |
|
190 |
/* |
||
191 |
* figure out archive type; pass any format specific options to the |
||
192 |
* archive option processing routine; call the format init routine; |
||
193 |
* start up the directory modification time and access mode database |
||
194 |
*/ |
||
195 |
✓✗✓✗ ✓✗✓✗ |
2 |
if ((get_arc() < 0) || ((*frmt->options)() < 0) || |
196 |
((*frmt->st_rd)() < 0) || (dir_start() < 0)) |
||
197 |
return; |
||
198 |
|||
199 |
/* |
||
200 |
* When we are doing interactive rename, we store the mapping of names |
||
201 |
* so we can fix up hard links files later in the archive. |
||
202 |
*/ |
||
203 |
✗✓✗✗ |
2 |
if (iflag && (name_start() < 0)) |
204 |
return; |
||
205 |
|||
206 |
2 |
now = time(NULL); |
|
207 |
|||
208 |
/* |
||
209 |
* step through each entry on the archive until the format read routine |
||
210 |
* says it is done |
||
211 |
*/ |
||
212 |
✓✓ | 18 |
while (next_head(arcn) == 0) { |
213 |
✗✓ | 14 |
if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) { |
214 |
/* |
||
215 |
* we need to read, to get the real filename |
||
216 |
*/ |
||
217 |
if (!rd_wrfile(arcn, arcn->type == PAX_GLF |
||
218 |
? -1 : -2, &cnt)) |
||
219 |
(void)rd_skip(cnt + arcn->pad); |
||
220 |
continue; |
||
221 |
} |
||
222 |
|||
223 |
/* |
||
224 |
* check for pattern, and user specified options match. When |
||
225 |
* all the patterns are matched we are done |
||
226 |
*/ |
||
227 |
✗✓ | 14 |
if ((res = pat_match(arcn)) < 0) |
228 |
break; |
||
229 |
|||
230 |
✓✗✗✓ |
14 |
if ((res > 0) || (sel_chk(arcn) != 0)) { |
231 |
/* |
||
232 |
* file is not selected. skip past any file data and |
||
233 |
* padding and go back for the next archive member |
||
234 |
*/ |
||
235 |
(void)rd_skip(arcn->skip + arcn->pad); |
||
236 |
continue; |
||
237 |
} |
||
238 |
|||
239 |
/* |
||
240 |
* with -u or -D only extract when the archive member is newer |
||
241 |
* than the file with the same name in the file system (no |
||
242 |
* test of being the same type is required). |
||
243 |
* NOTE: this test is done BEFORE name modifications as |
||
244 |
* specified by pax. this operation can be confusing to the |
||
245 |
* user who might expect the test to be done on an existing |
||
246 |
* file AFTER the name mod. In honesty the pax spec is probably |
||
247 |
* flawed in this respect. |
||
248 |
*/ |
||
249 |
✓✗✗✓ ✗✗ |
14 |
if ((uflag || Dflag) && |
250 |
cmp_file_times(uflag, Dflag, arcn, NULL)) { |
||
251 |
(void)rd_skip(arcn->skip + arcn->pad); |
||
252 |
continue; |
||
253 |
} |
||
254 |
|||
255 |
/* |
||
256 |
* this archive member is now been selected. modify the name. |
||
257 |
*/ |
||
258 |
✓✗✓✗ |
14 |
if ((pat_sel(arcn) < 0) || ((res = mod_name(arcn)) < 0)) |
259 |
break; |
||
260 |
✗✓ | 14 |
if (res > 0) { |
261 |
/* |
||
262 |
* a bad name mod, skip and purge name from link table |
||
263 |
*/ |
||
264 |
purg_lnk(arcn); |
||
265 |
(void)rd_skip(arcn->skip + arcn->pad); |
||
266 |
continue; |
||
267 |
} |
||
268 |
|||
269 |
/* |
||
270 |
* Non standard -Y and -Z flag. When the existing file is |
||
271 |
* same age or newer skip |
||
272 |
*/ |
||
273 |
✓✗✗✓ ✗✗ |
14 |
if ((Yflag || Zflag) && |
274 |
cmp_file_times(Yflag, Zflag, arcn, NULL)) { |
||
275 |
(void)rd_skip(arcn->skip + arcn->pad); |
||
276 |
continue; |
||
277 |
} |
||
278 |
|||
279 |
✗✓ | 14 |
if (vflag) { |
280 |
if (vflag > 1) |
||
281 |
ls_list(arcn, now, listf); |
||
282 |
else { |
||
283 |
(void)safe_print(arcn->name, listf); |
||
284 |
vfpart = 1; |
||
285 |
} |
||
286 |
} |
||
287 |
|||
288 |
/* |
||
289 |
* if required, chdir around. |
||
290 |
*/ |
||
291 |
✗✓✗✗ |
14 |
if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL)) |
292 |
if (chdir(arcn->pat->chdname) != 0) |
||
293 |
syswarn(1, errno, "Cannot chdir to %s", |
||
294 |
arcn->pat->chdname); |
||
295 |
|||
296 |
/* |
||
297 |
* all ok, extract this member based on type |
||
298 |
*/ |
||
299 |
✓✓ | 14 |
if (!PAX_IS_REG(arcn->type)) { |
300 |
/* |
||
301 |
* process archive members that are not regular files. |
||
302 |
* throw out padding and any data that might follow the |
||
303 |
* header (as determined by the format). |
||
304 |
*/ |
||
305 |
✓✓ | 8 |
if (PAX_IS_HARDLINK(arcn->type)) |
306 |
4 |
res = lnk_creat(arcn); |
|
307 |
else |
||
308 |
4 |
res = node_creat(arcn); |
|
309 |
|||
310 |
8 |
(void)rd_skip(arcn->skip + arcn->pad); |
|
311 |
✗✓ | 8 |
if (res < 0) |
312 |
purg_lnk(arcn); |
||
313 |
|||
314 |
✗✓✗✗ |
8 |
if (vflag && vfpart) { |
315 |
(void)putc('\n', listf); |
||
316 |
vfpart = 0; |
||
317 |
} |
||
318 |
goto popd; |
||
319 |
} |
||
320 |
/* |
||
321 |
* we have a file with data here. If we can not create it, skip |
||
322 |
* over the data and purge the name from hard link table |
||
323 |
*/ |
||
324 |
✗✓ | 6 |
if ((fd = file_creat(arcn)) < 0) { |
325 |
(void)rd_skip(arcn->skip + arcn->pad); |
||
326 |
purg_lnk(arcn); |
||
327 |
goto popd; |
||
328 |
} |
||
329 |
/* |
||
330 |
* extract the file from the archive and skip over padding and |
||
331 |
* any unprocessed data |
||
332 |
*/ |
||
333 |
6 |
res = rd_wrfile(arcn, fd, &cnt); |
|
334 |
6 |
file_close(arcn, fd); |
|
335 |
✗✓✗✗ |
6 |
if (vflag && vfpart) { |
336 |
(void)putc('\n', listf); |
||
337 |
vfpart = 0; |
||
338 |
} |
||
339 |
✓✗ | 6 |
if (!res) |
340 |
6 |
(void)rd_skip(cnt + arcn->pad); |
|
341 |
|||
342 |
14 |
popd: |
|
343 |
/* |
||
344 |
* if required, chdir around. |
||
345 |
*/ |
||
346 |
✗✓✗✗ |
14 |
if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL)) |
347 |
if (fchdir(cwdfd) != 0) |
||
348 |
syswarn(1, errno, |
||
349 |
"Can't fchdir to starting directory"); |
||
350 |
} |
||
351 |
|||
352 |
/* |
||
353 |
* all done, restore directory modes and times as required; make sure |
||
354 |
* all patterns supplied by the user were matched; block off signals |
||
355 |
* to avoid chance for multiple entry into the cleanup code. |
||
356 |
*/ |
||
357 |
2 |
(void)(*frmt->end_rd)(); |
|
358 |
2 |
(void)sigprocmask(SIG_BLOCK, &s_mask, NULL); |
|
359 |
2 |
ar_close(0); |
|
360 |
2 |
sltab_process(0); |
|
361 |
2 |
proc_dir(0); |
|
362 |
2 |
pat_chk(); |
|
363 |
} |
||
364 |
|||
365 |
/* |
||
366 |
* wr_archive() |
||
367 |
* Write an archive. used in both creating a new archive and appends on |
||
368 |
* previously written archive. |
||
369 |
*/ |
||
370 |
|||
371 |
static void |
||
372 |
wr_archive(ARCHD *arcn, int is_app) |
||
373 |
12 |
{ |
|
374 |
int res; |
||
375 |
int hlk; |
||
376 |
int wr_one; |
||
377 |
off_t cnt; |
||
378 |
int (*wrf)(ARCHD *); |
||
379 |
12 |
int fd = -1; |
|
380 |
time_t now; |
||
381 |
|||
382 |
/* |
||
383 |
* if this format supports hard link storage, start up the database |
||
384 |
* that detects them. |
||
385 |
*/ |
||
386 |
✓✓✗✓ |
12 |
if (((hlk = frmt->hlk) == 1) && (lnk_start() < 0)) |
387 |
return; |
||
388 |
|||
389 |
/* |
||
390 |
* if this is not append, and there are no files, we do not write a |
||
391 |
* trailer |
||
392 |
*/ |
||
393 |
12 |
wr_one = is_app; |
|
394 |
|||
395 |
/* |
||
396 |
* start up the file traversal code and format specific write |
||
397 |
*/ |
||
398 |
✓✓ | 12 |
if (ftree_start() < 0) { |
399 |
✓✓ | 4 |
if (is_app) |
400 |
2 |
goto trailer; |
|
401 |
return; |
||
402 |
✗✓ | 8 |
} else if (((*frmt->st_wr)() < 0)) |
403 |
return; |
||
404 |
|||
405 |
8 |
wrf = frmt->wr; |
|
406 |
|||
407 |
/* |
||
408 |
* When we are doing interactive rename, we store the mapping of names |
||
409 |
* so we can fix up hard links files later in the archive. |
||
410 |
*/ |
||
411 |
✗✓✗✗ |
8 |
if (iflag && (name_start() < 0)) |
412 |
return; |
||
413 |
|||
414 |
8 |
now = time(NULL); |
|
415 |
|||
416 |
/* |
||
417 |
* while there are files to archive, process them one at at time |
||
418 |
*/ |
||
419 |
✓✓ | 34 |
while (next_file(arcn) == 0) { |
420 |
/* |
||
421 |
* check if this file meets user specified options match. |
||
422 |
*/ |
||
423 |
✗✓ | 18 |
if (sel_chk(arcn) != 0) |
424 |
continue; |
||
425 |
18 |
fd = -1; |
|
426 |
✗✓ | 18 |
if (uflag) { |
427 |
/* |
||
428 |
* only archive if this file is newer than a file with |
||
429 |
* the same name that is already stored on the archive |
||
430 |
*/ |
||
431 |
if ((res = chk_ftime(arcn)) < 0) |
||
432 |
break; |
||
433 |
if (res > 0) { |
||
434 |
ftree_skipped_newer(arcn); |
||
435 |
continue; |
||
436 |
} |
||
437 |
} |
||
438 |
|||
439 |
/* |
||
440 |
* this file is considered selected now. see if this is a hard |
||
441 |
* link to a file already stored |
||
442 |
*/ |
||
443 |
18 |
ftree_sel(arcn); |
|
444 |
✓✗✗✓ |
18 |
if (hlk && (chk_lnk(arcn) < 0)) |
445 |
break; |
||
446 |
|||
447 |
✓✓✓✓ |
18 |
if (PAX_IS_REG(arcn->type) || (arcn->type == PAX_HRG)) { |
448 |
/* |
||
449 |
* we will have to read this file. by opening it now we |
||
450 |
* can avoid writing a header to the archive for a file |
||
451 |
* we were later unable to read (we also purge it from |
||
452 |
* the link table). |
||
453 |
*/ |
||
454 |
✗✓ | 14 |
if ((fd = open(arcn->org_name, O_RDONLY, 0)) < 0) { |
455 |
syswarn(1,errno, "Unable to open %s to read", |
||
456 |
arcn->org_name); |
||
457 |
purg_lnk(arcn); |
||
458 |
continue; |
||
459 |
} |
||
460 |
} |
||
461 |
|||
462 |
/* |
||
463 |
* Now modify the name as requested by the user |
||
464 |
*/ |
||
465 |
✗✓ | 18 |
if ((res = mod_name(arcn)) < 0) { |
466 |
/* |
||
467 |
* name modification says to skip this file, close the |
||
468 |
* file and purge link table entry |
||
469 |
*/ |
||
470 |
rdfile_close(arcn, &fd); |
||
471 |
purg_lnk(arcn); |
||
472 |
break; |
||
473 |
} |
||
474 |
|||
475 |
✓✗✗✓ ✗✗ |
18 |
if ((res > 0) || (docrc && (set_crc(arcn, fd) < 0))) { |
476 |
/* |
||
477 |
* unable to obtain the crc we need, close the file, |
||
478 |
* purge link table entry |
||
479 |
*/ |
||
480 |
rdfile_close(arcn, &fd); |
||
481 |
purg_lnk(arcn); |
||
482 |
continue; |
||
483 |
} |
||
484 |
|||
485 |
✗✓ | 18 |
if (vflag) { |
486 |
if (vflag > 1) |
||
487 |
ls_list(arcn, now, listf); |
||
488 |
else { |
||
489 |
(void)safe_print(arcn->name, listf); |
||
490 |
vfpart = 1; |
||
491 |
} |
||
492 |
} |
||
493 |
18 |
++flcnt; |
|
494 |
|||
495 |
/* |
||
496 |
* looks safe to store the file, have the format specific |
||
497 |
* routine write routine store the file header on the archive |
||
498 |
*/ |
||
499 |
✗✓ | 18 |
if ((res = (*wrf)(arcn)) < 0) { |
500 |
rdfile_close(arcn, &fd); |
||
501 |
break; |
||
502 |
} |
||
503 |
18 |
wr_one = 1; |
|
504 |
✓✓ | 18 |
if (res > 0) { |
505 |
/* |
||
506 |
* format write says no file data needs to be stored |
||
507 |
* so we are done messing with this file |
||
508 |
*/ |
||
509 |
✗✓✗✗ |
8 |
if (vflag && vfpart) { |
510 |
(void)putc('\n', listf); |
||
511 |
vfpart = 0; |
||
512 |
} |
||
513 |
8 |
rdfile_close(arcn, &fd); |
|
514 |
8 |
continue; |
|
515 |
} |
||
516 |
|||
517 |
/* |
||
518 |
* Add file data to the archive, quit on write error. if we |
||
519 |
* cannot write the entire file contents to the archive we |
||
520 |
* must pad the archive to replace the missing file data |
||
521 |
* (otherwise during an extract the file header for the file |
||
522 |
* which FOLLOWS this one will not be where we expect it to |
||
523 |
* be). |
||
524 |
*/ |
||
525 |
10 |
res = wr_rdfile(arcn, fd, &cnt); |
|
526 |
10 |
rdfile_close(arcn, &fd); |
|
527 |
✗✓✗✗ |
10 |
if (vflag && vfpart) { |
528 |
(void)putc('\n', listf); |
||
529 |
vfpart = 0; |
||
530 |
} |
||
531 |
✗✓ | 10 |
if (res < 0) |
532 |
break; |
||
533 |
|||
534 |
/* |
||
535 |
* pad as required, cnt is number of bytes not written |
||
536 |
*/ |
||
537 |
✗✓✗✗ ✓✓✓✗ |
10 |
if (((cnt > 0) && (wr_skip(cnt) < 0)) || |
538 |
((arcn->pad > 0) && (wr_skip(arcn->pad) < 0))) |
||
539 |
break; |
||
540 |
} |
||
541 |
|||
542 |
10 |
trailer: |
|
543 |
/* |
||
544 |
* tell format to write trailer; pad to block boundary; reset directory |
||
545 |
* mode/access times, and check if all patterns supplied by the user |
||
546 |
* were matched. block off signals to avoid chance for multiple entry |
||
547 |
* into the cleanup code |
||
548 |
*/ |
||
549 |
✓✗ | 10 |
if (wr_one) { |
550 |
10 |
(*frmt->end_wr)(); |
|
551 |
10 |
wr_fin(); |
|
552 |
} |
||
553 |
10 |
(void)sigprocmask(SIG_BLOCK, &s_mask, NULL); |
|
554 |
10 |
ar_close(0); |
|
555 |
✗✓ | 10 |
if (tflag) |
556 |
proc_dir(0); |
||
557 |
10 |
ftree_chk(); |
|
558 |
} |
||
559 |
|||
560 |
/* |
||
561 |
* append() |
||
562 |
* Add file to previously written archive. Archive format specified by the |
||
563 |
* user must agree with archive. The archive is read first to collect |
||
564 |
* modification times (if -u) and locate the archive trailer. The archive |
||
565 |
* is positioned in front of the record with the trailer and wr_archive() |
||
566 |
* is called to add the new members. |
||
567 |
* PAX IMPLEMENTATION DETAIL NOTE: |
||
568 |
* -u is implemented by adding the new members to the end of the archive. |
||
569 |
* Care is taken so that these do not end up as links to the older |
||
570 |
* version of the same file already stored in the archive. It is expected |
||
571 |
* when extraction occurs these newer versions will over-write the older |
||
572 |
* ones stored "earlier" in the archive (this may be a bad assumption as |
||
573 |
* it depends on the implementation of the program doing the extraction). |
||
574 |
* It is really difficult to splice in members without either re-writing |
||
575 |
* the entire archive (from the point were the old version was), or having |
||
576 |
* assistance of the format specification in terms of a special update |
||
577 |
* header that invalidates a previous archive record. The posix spec left |
||
578 |
* the method used to implement -u unspecified. This pax is able to |
||
579 |
* over write existing files that it creates. |
||
580 |
*/ |
||
581 |
|||
582 |
void |
||
583 |
append(void) |
||
584 |
6 |
{ |
|
585 |
ARCHD *arcn; |
||
586 |
int res; |
||
587 |
ARCHD archd; |
||
588 |
FSUB *orgfrmt; |
||
589 |
int udev; |
||
590 |
off_t tlen; |
||
591 |
|||
592 |
6 |
arcn = &archd; |
|
593 |
6 |
orgfrmt = frmt; |
|
594 |
|||
595 |
/* |
||
596 |
* Do not allow an append operation if the actual archive is of a |
||
597 |
* different format than the user specified format. |
||
598 |
*/ |
||
599 |
✗✓ | 6 |
if (get_arc() < 0) |
600 |
return; |
||
601 |
✗✓✗✗ |
6 |
if ((orgfrmt != NULL) && (orgfrmt != frmt)) { |
602 |
paxwarn(1, "Cannot mix current archive format %s with %s", |
||
603 |
frmt->name, orgfrmt->name); |
||
604 |
return; |
||
605 |
} |
||
606 |
|||
607 |
/* |
||
608 |
* pass the format any options and start up format |
||
609 |
*/ |
||
610 |
✓✗✓✗ |
6 |
if (((*frmt->options)() < 0) || ((*frmt->st_rd)() < 0)) |
611 |
return; |
||
612 |
|||
613 |
/* |
||
614 |
* if we only are adding members that are newer, we need to save the |
||
615 |
* mod times for all files we see. |
||
616 |
*/ |
||
617 |
✗✓✗✗ |
6 |
if (uflag && (ftime_start() < 0)) |
618 |
return; |
||
619 |
|||
620 |
/* |
||
621 |
* some archive formats encode hard links by recording the device and |
||
622 |
* file serial number (inode) but copy the file anyway (multiple times) |
||
623 |
* to the archive. When we append, we run the risk that newly added |
||
624 |
* files may have the same device and inode numbers as those recorded |
||
625 |
* on the archive but during a previous run. If this happens, when the |
||
626 |
* archive is extracted we get INCORRECT hard links. We avoid this by |
||
627 |
* remapping the device numbers so that newly added files will never |
||
628 |
* use the same device number as one found on the archive. remapping |
||
629 |
* allows new members to safely have links among themselves. remapping |
||
630 |
* also avoids problems with file inode (serial number) truncations |
||
631 |
* when the inode number is larger than storage space in the archive |
||
632 |
* header. See the remap routines for more details. |
||
633 |
*/ |
||
634 |
✗✓✗✗ |
6 |
if ((udev = frmt->udev) && (dev_start() < 0)) |
635 |
return; |
||
636 |
|||
637 |
/* |
||
638 |
* reading the archive may take a long time. If verbose tell the user |
||
639 |
*/ |
||
640 |
✗✓ | 6 |
if (vflag) { |
641 |
(void)fprintf(listf, |
||
642 |
"%s: Reading archive to position at the end...", argv0); |
||
643 |
vfpart = 1; |
||
644 |
} |
||
645 |
|||
646 |
/* |
||
647 |
* step through the archive until the format says it is done |
||
648 |
*/ |
||
649 |
✓✓ | 12 |
while (next_head(arcn) == 0) { |
650 |
/* |
||
651 |
* check if this file meets user specified options. |
||
652 |
*/ |
||
653 |
✗✓ | 6 |
if (sel_chk(arcn) != 0) { |
654 |
if (rd_skip(arcn->skip + arcn->pad) == 1) |
||
655 |
break; |
||
656 |
continue; |
||
657 |
} |
||
658 |
|||
659 |
✗✓ | 6 |
if (uflag) { |
660 |
/* |
||
661 |
* see if this is the newest version of this file has |
||
662 |
* already been seen, if so skip. |
||
663 |
*/ |
||
664 |
if ((res = chk_ftime(arcn)) < 0) |
||
665 |
break; |
||
666 |
if (res > 0) { |
||
667 |
if (rd_skip(arcn->skip + arcn->pad) == 1) |
||
668 |
break; |
||
669 |
continue; |
||
670 |
} |
||
671 |
} |
||
672 |
|||
673 |
/* |
||
674 |
* Store this device number. Device numbers seen during the |
||
675 |
* read phase of append will cause newly appended files with a |
||
676 |
* device number seen in the old part of the archive to be |
||
677 |
* remapped to an unused device number. |
||
678 |
*/ |
||
679 |
✗✓✗✗ ✓✗ |
6 |
if ((udev && (add_dev(arcn) < 0)) || |
680 |
(rd_skip(arcn->skip + arcn->pad) == 1)) |
||
681 |
break; |
||
682 |
} |
||
683 |
|||
684 |
/* |
||
685 |
* done, finish up read and get the number of bytes to back up so we |
||
686 |
* can add new members. The format might have used the hard link table, |
||
687 |
* purge it. |
||
688 |
*/ |
||
689 |
6 |
tlen = (*frmt->end_rd)(); |
|
690 |
6 |
lnk_end(); |
|
691 |
|||
692 |
/* |
||
693 |
* try to position for write, if this fails quit. if any error occurs, |
||
694 |
* we will refuse to write |
||
695 |
*/ |
||
696 |
✗✓ | 6 |
if (appnd_start(tlen) < 0) |
697 |
return; |
||
698 |
|||
699 |
/* |
||
700 |
* tell the user we are done reading. |
||
701 |
*/ |
||
702 |
✗✓✗✗ |
6 |
if (vflag && vfpart) { |
703 |
(void)fputs("done.\n", listf); |
||
704 |
vfpart = 0; |
||
705 |
} |
||
706 |
|||
707 |
/* |
||
708 |
* go to the writing phase to add the new members |
||
709 |
*/ |
||
710 |
6 |
wr_archive(arcn, 1); |
|
711 |
} |
||
712 |
|||
713 |
/* |
||
714 |
* archive() |
||
715 |
* write a new archive |
||
716 |
*/ |
||
717 |
|||
718 |
void |
||
719 |
archive(void) |
||
720 |
6 |
{ |
|
721 |
ARCHD archd; |
||
722 |
|||
723 |
/* |
||
724 |
* if we only are adding members that are newer, we need to save the |
||
725 |
* mod times for all files; set up for writing; pass the format any |
||
726 |
* options write the archive |
||
727 |
*/ |
||
728 |
✗✓✗✗ ✓✗ |
6 |
if ((uflag && (ftime_start() < 0)) || (wr_start() < 0)) |
729 |
return; |
||
730 |
✗✓ | 6 |
if ((*frmt->options)() < 0) |
731 |
return; |
||
732 |
|||
733 |
6 |
wr_archive(&archd, 0); |
|
734 |
} |
||
735 |
|||
736 |
/* |
||
737 |
* copy() |
||
738 |
* copy files from one part of the file system to another. this does not |
||
739 |
* use any archive storage. The EFFECT OF THE COPY IS THE SAME as if an |
||
740 |
* archive was written and then extracted in the destination directory |
||
741 |
* (except the files are forced to be under the destination directory). |
||
742 |
*/ |
||
743 |
|||
744 |
void |
||
745 |
copy(void) |
||
746 |
{ |
||
747 |
ARCHD *arcn; |
||
748 |
int res; |
||
749 |
int fddest; |
||
750 |
char *dest_pt; |
||
751 |
size_t dlen; |
||
752 |
size_t drem; |
||
753 |
int fdsrc = -1; |
||
754 |
struct stat sb; |
||
755 |
ARCHD archd; |
||
756 |
char dirbuf[PAXPATHLEN+1]; |
||
757 |
|||
758 |
sltab_start(); |
||
759 |
|||
760 |
arcn = &archd; |
||
761 |
/* |
||
762 |
* set up the destination dir path and make sure it is a directory. We |
||
763 |
* make sure we have a trailing / on the destination |
||
764 |
*/ |
||
765 |
dlen = strlcpy(dirbuf, dirptr, sizeof(dirbuf)); |
||
766 |
if (dlen >= sizeof(dirbuf) || |
||
767 |
(dlen == sizeof(dirbuf) - 1 && dirbuf[dlen - 1] != '/')) { |
||
768 |
paxwarn(1, "directory name is too long %s", dirptr); |
||
769 |
return; |
||
770 |
} |
||
771 |
dest_pt = dirbuf + dlen; |
||
772 |
if (*(dest_pt-1) != '/') { |
||
773 |
*dest_pt++ = '/'; |
||
774 |
*dest_pt = '\0'; |
||
775 |
++dlen; |
||
776 |
} |
||
777 |
drem = PAXPATHLEN - dlen; |
||
778 |
|||
779 |
if (stat(dirptr, &sb) < 0) { |
||
780 |
syswarn(1, errno, "Cannot access destination directory %s", |
||
781 |
dirptr); |
||
782 |
return; |
||
783 |
} |
||
784 |
if (!S_ISDIR(sb.st_mode)) { |
||
785 |
paxwarn(1, "Destination is not a directory %s", dirptr); |
||
786 |
return; |
||
787 |
} |
||
788 |
|||
789 |
/* |
||
790 |
* start up the hard link table; file traversal routines and the |
||
791 |
* modification time and access mode database |
||
792 |
*/ |
||
793 |
if ((lnk_start() < 0) || (ftree_start() < 0) || (dir_start() < 0)) |
||
794 |
return; |
||
795 |
|||
796 |
/* |
||
797 |
* When we are doing interactive rename, we store the mapping of names |
||
798 |
* so we can fix up hard links files later in the archive. |
||
799 |
*/ |
||
800 |
if (iflag && (name_start() < 0)) |
||
801 |
return; |
||
802 |
|||
803 |
/* |
||
804 |
* set up to cp file trees |
||
805 |
*/ |
||
806 |
cp_start(); |
||
807 |
|||
808 |
/* |
||
809 |
* while there are files to archive, process them |
||
810 |
*/ |
||
811 |
while (next_file(arcn) == 0) { |
||
812 |
fdsrc = -1; |
||
813 |
|||
814 |
/* |
||
815 |
* check if this file meets user specified options |
||
816 |
*/ |
||
817 |
if (sel_chk(arcn) != 0) |
||
818 |
continue; |
||
819 |
|||
820 |
/* |
||
821 |
* if there is already a file in the destination directory with |
||
822 |
* the same name and it is newer, skip the one stored on the |
||
823 |
* archive. |
||
824 |
* NOTE: this test is done BEFORE name modifications as |
||
825 |
* specified by pax. this can be confusing to the user who |
||
826 |
* might expect the test to be done on an existing file AFTER |
||
827 |
* the name mod. In honesty the pax spec is probably flawed in |
||
828 |
* this respect |
||
829 |
*/ |
||
830 |
if (uflag || Dflag) { |
||
831 |
/* |
||
832 |
* create the destination name |
||
833 |
*/ |
||
834 |
if (strlcpy(dest_pt, arcn->name + (*arcn->name == '/'), |
||
835 |
drem + 1) > drem) { |
||
836 |
paxwarn(1, "Destination pathname too long %s", |
||
837 |
arcn->name); |
||
838 |
continue; |
||
839 |
} |
||
840 |
|||
841 |
/* |
||
842 |
* if existing file is same age or newer skip |
||
843 |
*/ |
||
844 |
res = lstat(dirbuf, &sb); |
||
845 |
*dest_pt = '\0'; |
||
846 |
|||
847 |
if (res == 0) { |
||
848 |
ftree_skipped_newer(arcn); |
||
849 |
if (cmp_file_times(uflag, Dflag, arcn, &sb)) |
||
850 |
continue; |
||
851 |
} |
||
852 |
} |
||
853 |
|||
854 |
/* |
||
855 |
* this file is considered selected. See if this is a hard link |
||
856 |
* to a previous file; modify the name as requested by the |
||
857 |
* user; set the final destination. |
||
858 |
*/ |
||
859 |
ftree_sel(arcn); |
||
860 |
if ((chk_lnk(arcn) < 0) || ((res = mod_name(arcn)) < 0)) |
||
861 |
break; |
||
862 |
if ((res > 0) || (set_dest(arcn, dirbuf, dlen) < 0)) { |
||
863 |
/* |
||
864 |
* skip file, purge from link table |
||
865 |
*/ |
||
866 |
purg_lnk(arcn); |
||
867 |
continue; |
||
868 |
} |
||
869 |
|||
870 |
/* |
||
871 |
* Non standard -Y and -Z flag. When the existing file is |
||
872 |
* same age or newer skip |
||
873 |
*/ |
||
874 |
if ((Yflag || Zflag) && |
||
875 |
cmp_file_times(Yflag, Zflag, arcn, NULL)) |
||
876 |
continue; |
||
877 |
|||
878 |
if (vflag) { |
||
879 |
(void)safe_print(arcn->name, listf); |
||
880 |
vfpart = 1; |
||
881 |
} |
||
882 |
++flcnt; |
||
883 |
|||
884 |
/* |
||
885 |
* try to create a hard link to the src file if requested |
||
886 |
* but make sure we are not trying to overwrite ourselves. |
||
887 |
*/ |
||
888 |
if (lflag) |
||
889 |
res = cross_lnk(arcn); |
||
890 |
else |
||
891 |
res = chk_same(arcn); |
||
892 |
if (res <= 0) { |
||
893 |
if (vflag && vfpart) { |
||
894 |
(void)putc('\n', listf); |
||
895 |
vfpart = 0; |
||
896 |
} |
||
897 |
continue; |
||
898 |
} |
||
899 |
|||
900 |
/* |
||
901 |
* have to create a new file |
||
902 |
*/ |
||
903 |
if (!PAX_IS_REG(arcn->type)) { |
||
904 |
/* |
||
905 |
* create a link or special file |
||
906 |
*/ |
||
907 |
if (PAX_IS_HARDLINK(arcn->type)) |
||
908 |
res = lnk_creat(arcn); |
||
909 |
else |
||
910 |
res = node_creat(arcn); |
||
911 |
if (res < 0) |
||
912 |
purg_lnk(arcn); |
||
913 |
if (vflag && vfpart) { |
||
914 |
(void)putc('\n', listf); |
||
915 |
vfpart = 0; |
||
916 |
} |
||
917 |
continue; |
||
918 |
} |
||
919 |
|||
920 |
/* |
||
921 |
* have to copy a regular file to the destination directory. |
||
922 |
* first open source file and then create the destination file |
||
923 |
*/ |
||
924 |
if ((fdsrc = open(arcn->org_name, O_RDONLY, 0)) < 0) { |
||
925 |
syswarn(1, errno, "Unable to open %s to read", |
||
926 |
arcn->org_name); |
||
927 |
purg_lnk(arcn); |
||
928 |
continue; |
||
929 |
} |
||
930 |
if ((fddest = file_creat(arcn)) < 0) { |
||
931 |
rdfile_close(arcn, &fdsrc); |
||
932 |
purg_lnk(arcn); |
||
933 |
continue; |
||
934 |
} |
||
935 |
|||
936 |
/* |
||
937 |
* copy source file data to the destination file |
||
938 |
*/ |
||
939 |
cp_file(arcn, fdsrc, fddest); |
||
940 |
file_close(arcn, fddest); |
||
941 |
rdfile_close(arcn, &fdsrc); |
||
942 |
|||
943 |
if (vflag && vfpart) { |
||
944 |
(void)putc('\n', listf); |
||
945 |
vfpart = 0; |
||
946 |
} |
||
947 |
} |
||
948 |
|||
949 |
/* |
||
950 |
* restore directory modes and times as required; make sure all |
||
951 |
* patterns were selected block off signals to avoid chance for |
||
952 |
* multiple entry into the cleanup code. |
||
953 |
*/ |
||
954 |
(void)sigprocmask(SIG_BLOCK, &s_mask, NULL); |
||
955 |
ar_close(0); |
||
956 |
sltab_process(0); |
||
957 |
proc_dir(0); |
||
958 |
ftree_chk(); |
||
959 |
} |
||
960 |
|||
961 |
/* |
||
962 |
* next_head() |
||
963 |
* try to find a valid header in the archive. Uses format specific |
||
964 |
* routines to extract the header and id the trailer. Trailers may be |
||
965 |
* located within a valid header or in an invalid header (the location |
||
966 |
* is format specific. The inhead field from the option table tells us |
||
967 |
* where to look for the trailer). |
||
968 |
* We keep reading (and resyncing) until we get enough contiguous data |
||
969 |
* to check for a header. If we cannot find one, we shift by a byte |
||
970 |
* add a new byte from the archive to the end of the buffer and try again. |
||
971 |
* If we get a read error, we throw out what we have (as we must have |
||
972 |
* contiguous data) and start over again. |
||
973 |
* ASSUMED: headers fit within a BLKMULT header. |
||
974 |
* Return: |
||
975 |
* 0 if we got a header, -1 if we are unable to ever find another one |
||
976 |
* (we reached the end of input, or we reached the limit on retries. see |
||
977 |
* the specs for rd_wrbuf() for more details) |
||
978 |
*/ |
||
979 |
|||
980 |
static int |
||
981 |
next_head(ARCHD *arcn) |
||
982 |
146 |
{ |
|
983 |
int ret; |
||
984 |
char *hdend; |
||
985 |
int res; |
||
986 |
int shftsz; |
||
987 |
int hsz; |
||
988 |
146 |
int in_resync = 0; /* set when we are in resync mode */ |
|
989 |
146 |
int cnt = 0; /* counter for trailer function */ |
|
990 |
146 |
int first = 1; /* on 1st read, EOF isn't premature. */ |
|
991 |
|||
992 |
/* |
||
993 |
* set up initial conditions, we want a whole frmt->hsz block as we |
||
994 |
* have no data yet. |
||
995 |
*/ |
||
996 |
146 |
res = hsz = frmt->hsz; |
|
997 |
146 |
hdend = hdbuf; |
|
998 |
146 |
shftsz = hsz - 1; |
|
999 |
for (;;) { |
||
1000 |
/* |
||
1001 |
* keep looping until we get a contiguous FULL buffer |
||
1002 |
* (frmt->hsz is the proper size) |
||
1003 |
*/ |
||
1004 |
for (;;) { |
||
1005 |
✓✓ | 170 |
if ((ret = rd_wrbuf(hdend, res)) == res) |
1006 |
168 |
break; |
|
1007 |
|||
1008 |
/* |
||
1009 |
* If we read 0 bytes (EOF) from an archive when we |
||
1010 |
* expect to find a header, we have stepped upon |
||
1011 |
* an archive without the customary block of zeroes |
||
1012 |
* end marker. It's just stupid to error out on |
||
1013 |
* them, so exit gracefully. |
||
1014 |
*/ |
||
1015 |
✓✗ | 2 |
if (first && ret == 0) |
1016 |
2 |
return(-1); |
|
1017 |
first = 0; |
||
1018 |
|||
1019 |
/* |
||
1020 |
* some kind of archive read problem, try to resync the |
||
1021 |
* storage device, better give the user the bad news. |
||
1022 |
*/ |
||
1023 |
if ((ret == 0) || (rd_sync() < 0)) { |
||
1024 |
paxwarn(1,"Premature end of file on archive read"); |
||
1025 |
return(-1); |
||
1026 |
} |
||
1027 |
if (!in_resync) { |
||
1028 |
if (act == APPND) { |
||
1029 |
paxwarn(1, |
||
1030 |
"Archive I/O error, cannot continue"); |
||
1031 |
return(-1); |
||
1032 |
} |
||
1033 |
paxwarn(1,"Archive I/O error. Trying to recover."); |
||
1034 |
++in_resync; |
||
1035 |
} |
||
1036 |
|||
1037 |
/* |
||
1038 |
* oh well, throw it all out and start over |
||
1039 |
*/ |
||
1040 |
res = hsz; |
||
1041 |
hdend = hdbuf; |
||
1042 |
} |
||
1043 |
|||
1044 |
/* |
||
1045 |
* ok we have a contiguous buffer of the right size. Call the |
||
1046 |
* format read routine. If this was not a valid header and this |
||
1047 |
* format stores trailers outside of the header, call the |
||
1048 |
* format specific trailer routine to check for a trailer. We |
||
1049 |
* have to watch out that we do not mis-identify file data or |
||
1050 |
* block padding as a header or trailer. Format specific |
||
1051 |
* trailer functions must NOT check for the trailer while we |
||
1052 |
* are running in resync mode. Some trailer functions may tell |
||
1053 |
* us that this block cannot contain a valid header either, so |
||
1054 |
* we then throw out the entire block and start over. |
||
1055 |
*/ |
||
1056 |
✓✓ | 168 |
if ((*frmt->rd)(arcn, hdbuf) == 0) |
1057 |
120 |
break; |
|
1058 |
|||
1059 |
✓✗ | 48 |
if (!frmt->inhead) { |
1060 |
/* |
||
1061 |
* this format has trailers outside of valid headers |
||
1062 |
*/ |
||
1063 |
✓✓ | 48 |
if ((ret = (*frmt->trail)(arcn,hdbuf,in_resync,&cnt)) == 0){ |
1064 |
/* |
||
1065 |
* valid trailer found, drain input as required |
||
1066 |
*/ |
||
1067 |
24 |
ar_drain(); |
|
1068 |
24 |
return(-1); |
|
1069 |
} |
||
1070 |
|||
1071 |
✓✗ | 24 |
if (ret == 1) { |
1072 |
/* |
||
1073 |
* we are in resync and we were told to throw |
||
1074 |
* the whole block out because none of the |
||
1075 |
* bytes in this block can be used to form a |
||
1076 |
* valid header |
||
1077 |
*/ |
||
1078 |
24 |
res = hsz; |
|
1079 |
24 |
hdend = hdbuf; |
|
1080 |
24 |
continue; |
|
1081 |
} |
||
1082 |
} |
||
1083 |
|||
1084 |
/* |
||
1085 |
* Brute force section. |
||
1086 |
* not a valid header. We may be able to find a header yet. So |
||
1087 |
* we shift over by one byte, and set up to read one byte at a |
||
1088 |
* time from the archive and place it at the end of the buffer. |
||
1089 |
* We will keep moving byte at a time until we find a header or |
||
1090 |
* get a read error and have to start over. |
||
1091 |
*/ |
||
1092 |
if (!in_resync) { |
||
1093 |
if (act == APPND) { |
||
1094 |
paxwarn(1,"Unable to append, archive header flaw"); |
||
1095 |
return(-1); |
||
1096 |
} |
||
1097 |
paxwarn(1,"Invalid header, starting valid header search."); |
||
1098 |
++in_resync; |
||
1099 |
} |
||
1100 |
memmove(hdbuf, hdbuf+1, shftsz); |
||
1101 |
res = 1; |
||
1102 |
hdend = hdbuf + shftsz; |
||
1103 |
} |
||
1104 |
|||
1105 |
/* |
||
1106 |
* ok got a valid header, check for trailer if format encodes it in the |
||
1107 |
* the header. NOTE: the parameters are different than trailer routines |
||
1108 |
* which encode trailers outside of the header! |
||
1109 |
*/ |
||
1110 |
✗✓✗✗ |
120 |
if (frmt->inhead && ((*frmt->trail)(arcn,NULL,0,NULL) == 0)) { |
1111 |
/* |
||
1112 |
* valid trailer found, drain input as required |
||
1113 |
*/ |
||
1114 |
ar_drain(); |
||
1115 |
return(-1); |
||
1116 |
} |
||
1117 |
|||
1118 |
120 |
++flcnt; |
|
1119 |
120 |
return(0); |
|
1120 |
} |
||
1121 |
|||
1122 |
/* |
||
1123 |
* get_arc() |
||
1124 |
* Figure out what format an archive is. Handles archive with flaws by |
||
1125 |
* brute force searches for a legal header in any supported format. The |
||
1126 |
* format id routines have to be careful to NOT mis-identify a format. |
||
1127 |
* ASSUMED: headers fit within a BLKMULT header. |
||
1128 |
* Return: |
||
1129 |
* 0 if archive found -1 otherwise |
||
1130 |
*/ |
||
1131 |
|||
1132 |
static int |
||
1133 |
get_arc(void) |
||
1134 |
26 |
{ |
|
1135 |
int i; |
||
1136 |
26 |
int hdsz = 0; |
|
1137 |
int res; |
||
1138 |
26 |
int minhd = BLKMULT; |
|
1139 |
char *hdend; |
||
1140 |
26 |
int notice = 0; |
|
1141 |
|||
1142 |
/* |
||
1143 |
* find the smallest header size in all archive formats and then set up |
||
1144 |
* to read the archive. |
||
1145 |
*/ |
||
1146 |
✓✓ | 286 |
for (i = 0; ford[i] >= 0; ++i) { |
1147 |
✓✓✓✓ |
260 |
if (fsub[ford[i]].name != NULL && fsub[ford[i]].hsz < minhd) |
1148 |
78 |
minhd = fsub[ford[i]].hsz; |
|
1149 |
} |
||
1150 |
✗✓ | 26 |
if (rd_start() < 0) |
1151 |
return(-1); |
||
1152 |
26 |
res = BLKMULT; |
|
1153 |
26 |
hdsz = 0; |
|
1154 |
26 |
hdend = hdbuf; |
|
1155 |
for (;;) { |
||
1156 |
for (;;) { |
||
1157 |
/* |
||
1158 |
* fill the buffer with at least the smallest header |
||
1159 |
*/ |
||
1160 |
26 |
i = rd_wrbuf(hdend, res); |
|
1161 |
✓✗ | 26 |
if (i > 0) |
1162 |
26 |
hdsz += i; |
|
1163 |
✗✓ | 26 |
if (hdsz >= minhd) |
1164 |
26 |
break; |
|
1165 |
|||
1166 |
/* |
||
1167 |
* if we cannot recover from a read error quit |
||
1168 |
*/ |
||
1169 |
if ((i == 0) || (rd_sync() < 0)) |
||
1170 |
goto out; |
||
1171 |
|||
1172 |
/* |
||
1173 |
* when we get an error none of the data we already |
||
1174 |
* have can be used to create a legal header (we just |
||
1175 |
* got an error in the middle), so we throw it all out |
||
1176 |
* and refill the buffer with fresh data. |
||
1177 |
*/ |
||
1178 |
res = BLKMULT; |
||
1179 |
hdsz = 0; |
||
1180 |
hdend = hdbuf; |
||
1181 |
if (!notice) { |
||
1182 |
if (act == APPND) |
||
1183 |
return(-1); |
||
1184 |
paxwarn(1,"Cannot identify format. Searching..."); |
||
1185 |
++notice; |
||
1186 |
} |
||
1187 |
} |
||
1188 |
|||
1189 |
/* |
||
1190 |
* we have at least the size of the smallest header in any |
||
1191 |
* archive format. Look to see if we have a match. The array |
||
1192 |
* ford[] is used to specify the header id order to reduce the |
||
1193 |
* chance of incorrectly id'ing a valid header (some formats |
||
1194 |
* may be subsets of each other and the order would then be |
||
1195 |
* important). |
||
1196 |
*/ |
||
1197 |
✓✗ | 30 |
for (i = 0; ford[i] >= 0; ++i) { |
1198 |
✓✗✓✓ |
30 |
if (fsub[ford[i]].id == NULL || |
1199 |
(*fsub[ford[i]].id)(hdbuf, hdsz) < 0) |
||
1200 |
continue; |
||
1201 |
26 |
frmt = &(fsub[ford[i]]); |
|
1202 |
/* |
||
1203 |
* yuck, to avoid slow special case code in the extract |
||
1204 |
* routines, just push this header back as if it was |
||
1205 |
* not seen. We have left extra space at start of the |
||
1206 |
* buffer for this purpose. This is a bit ugly, but |
||
1207 |
* adding all the special case code is far worse. |
||
1208 |
*/ |
||
1209 |
26 |
pback(hdbuf, hdsz); |
|
1210 |
26 |
return(0); |
|
1211 |
} |
||
1212 |
|||
1213 |
/* |
||
1214 |
* We have a flawed archive, no match. we start searching, but |
||
1215 |
* we never allow additions to flawed archives |
||
1216 |
*/ |
||
1217 |
if (!notice) { |
||
1218 |
if (act == APPND) |
||
1219 |
return(-1); |
||
1220 |
paxwarn(1, "Cannot identify format. Searching..."); |
||
1221 |
++notice; |
||
1222 |
} |
||
1223 |
|||
1224 |
/* |
||
1225 |
* brute force search for a header that we can id. |
||
1226 |
* we shift through byte at a time. this is slow, but we cannot |
||
1227 |
* determine the nature of the flaw in the archive in a |
||
1228 |
* portable manner |
||
1229 |
*/ |
||
1230 |
if (--hdsz > 0) { |
||
1231 |
memmove(hdbuf, hdbuf+1, hdsz); |
||
1232 |
res = BLKMULT - hdsz; |
||
1233 |
hdend = hdbuf + hdsz; |
||
1234 |
} else { |
||
1235 |
res = BLKMULT; |
||
1236 |
hdend = hdbuf; |
||
1237 |
hdsz = 0; |
||
1238 |
} |
||
1239 |
} |
||
1240 |
|||
1241 |
out: |
||
1242 |
/* |
||
1243 |
* we cannot find a header, bow, apologize and quit |
||
1244 |
*/ |
||
1245 |
paxwarn(1, "Sorry, unable to determine archive format."); |
||
1246 |
return(-1); |
||
1247 |
} |
Generated by: GCOVR (Version 3.3) |