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