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