11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1992 Keith Muller. 31556Srgrimes * Copyright (c) 1992, 1993 41556Srgrimes * The Regents of the University of California. All rights reserved. 51556Srgrimes * 61556Srgrimes * This code is derived from software contributed to Berkeley by 71556Srgrimes * Keith Muller of the University of California, San Diego. 81556Srgrimes * 91556Srgrimes * Redistribution and use in source and binary forms, with or without 101556Srgrimes * modification, are permitted provided that the following conditions 111556Srgrimes * are met: 121556Srgrimes * 1. Redistributions of source code must retain the above copyright 131556Srgrimes * notice, this list of conditions and the following disclaimer. 141556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 151556Srgrimes * notice, this list of conditions and the following disclaimer in the 161556Srgrimes * documentation and/or other materials provided with the distribution. 171556Srgrimes * 4. Neither the name of the University nor the names of its contributors 181556Srgrimes * may be used to endorse or promote products derived from this software 191556Srgrimes * without specific prior written permission. 201556Srgrimes * 211556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311556Srgrimes * SUCH DAMAGE. 321556Srgrimes */ 331556Srgrimes 341556Srgrimes#ifndef lint 3536049Scharnier#if 0 3636049Scharnierstatic char sccsid[] = "@(#)ar_subs.c 8.2 (Berkeley) 4/18/94"; 3736049Scharnier#endif 381556Srgrimes#endif /* not lint */ 3999110Sobrien#include <sys/cdefs.h> 4099110Sobrien__FBSDID("$FreeBSD$"); 411556Srgrimes 421556Srgrimes#include <sys/types.h> 431556Srgrimes#include <sys/time.h> 441556Srgrimes#include <sys/stat.h> 451556Srgrimes#include <signal.h> 461556Srgrimes#include <string.h> 471556Srgrimes#include <stdio.h> 481556Srgrimes#include <fcntl.h> 491556Srgrimes#include <errno.h> 501556Srgrimes#include <unistd.h> 511556Srgrimes#include <stdlib.h> 521556Srgrimes#include "pax.h" 531556Srgrimes#include "extern.h" 541556Srgrimes 5590113Simpstatic void wr_archive(ARCHD *, int is_app); 5690110Simpstatic int get_arc(void); 5790113Simpstatic int next_head(ARCHD *); 581556Srgrimes 591556Srgrimes/* 601556Srgrimes * Routines which control the overall operation modes of pax as specified by 611556Srgrimes * the user: list, append, read ... 621556Srgrimes */ 631556Srgrimes 6476019Skrisstatic char hdbuf[BLKMULT]; /* space for archive header on read */ 651556Srgrimesu_long flcnt; /* number of files processed */ 661556Srgrimes 671556Srgrimes/* 681556Srgrimes * list() 691556Srgrimes * list the contents of an archive which match user supplied pattern(s) 701556Srgrimes * (no pattern matches all). 711556Srgrimes */ 721556Srgrimes 731556Srgrimesvoid 741556Srgrimeslist(void) 751556Srgrimes{ 7690113Simp ARCHD *arcn; 7790113Simp int res; 781556Srgrimes ARCHD archd; 791556Srgrimes time_t now; 801556Srgrimes 811556Srgrimes arcn = &archd; 821556Srgrimes /* 831556Srgrimes * figure out archive type; pass any format specific options to the 841556Srgrimes * archive option processing routine; call the format init routine. We 851556Srgrimes * also save current time for ls_list() so we do not make a system 861556Srgrimes * call for each file we need to print. If verbose (vflag) start up 871556Srgrimes * the name and group caches. 881556Srgrimes */ 891556Srgrimes if ((get_arc() < 0) || ((*frmt->options)() < 0) || 901556Srgrimes ((*frmt->st_rd)() < 0)) 911556Srgrimes return; 921556Srgrimes 931556Srgrimes if (vflag && ((uidtb_start() < 0) || (gidtb_start() < 0))) 941556Srgrimes return; 951556Srgrimes 9676017Skris now = time(NULL); 971556Srgrimes 981556Srgrimes /* 991556Srgrimes * step through the archive until the format says it is done 1001556Srgrimes */ 1011556Srgrimes while (next_head(arcn) == 0) { 1021556Srgrimes /* 1031556Srgrimes * check for pattern, and user specified options match. 1041556Srgrimes * When all patterns are matched we are done. 1051556Srgrimes */ 1061556Srgrimes if ((res = pat_match(arcn)) < 0) 1071556Srgrimes break; 1081556Srgrimes 1091556Srgrimes if ((res == 0) && (sel_chk(arcn) == 0)) { 1101556Srgrimes /* 1111556Srgrimes * pattern resulted in a selected file 1121556Srgrimes */ 1131556Srgrimes if (pat_sel(arcn) < 0) 1141556Srgrimes break; 1151556Srgrimes 1161556Srgrimes /* 1171556Srgrimes * modify the name as requested by the user if name 1181556Srgrimes * survives modification, do a listing of the file 1191556Srgrimes */ 1201556Srgrimes if ((res = mod_name(arcn)) < 0) 1211556Srgrimes break; 1221556Srgrimes if (res == 0) 12376351Skris ls_list(arcn, now, stdout); 1241556Srgrimes } 1251556Srgrimes 1261556Srgrimes /* 1271556Srgrimes * skip to next archive format header using values calculated 1281556Srgrimes * by the format header read routine 1291556Srgrimes */ 1301556Srgrimes if (rd_skip(arcn->skip + arcn->pad) == 1) 1311556Srgrimes break; 1321556Srgrimes } 1331556Srgrimes 1341556Srgrimes /* 1351556Srgrimes * all done, let format have a chance to cleanup, and make sure that 1361556Srgrimes * the patterns supplied by the user were all matched 1371556Srgrimes */ 1381556Srgrimes (void)(*frmt->end_rd)(); 13976017Skris (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); 1401556Srgrimes ar_close(); 1411556Srgrimes pat_chk(); 1421556Srgrimes} 1431556Srgrimes 1441556Srgrimes/* 1451556Srgrimes * extract() 1461556Srgrimes * extract the member(s) of an archive as specified by user supplied 1471556Srgrimes * pattern(s) (no patterns extracts all members) 1481556Srgrimes */ 1491556Srgrimes 1501556Srgrimesvoid 1511556Srgrimesextract(void) 1521556Srgrimes{ 15390113Simp ARCHD *arcn; 15490113Simp int res; 1551556Srgrimes off_t cnt; 1561556Srgrimes ARCHD archd; 1571556Srgrimes struct stat sb; 1581556Srgrimes int fd; 15976351Skris time_t now; 1601556Srgrimes 1611556Srgrimes arcn = &archd; 1621556Srgrimes /* 1631556Srgrimes * figure out archive type; pass any format specific options to the 1641556Srgrimes * archive option processing routine; call the format init routine; 1651556Srgrimes * start up the directory modification time and access mode database 1661556Srgrimes */ 1671556Srgrimes if ((get_arc() < 0) || ((*frmt->options)() < 0) || 1681556Srgrimes ((*frmt->st_rd)() < 0) || (dir_start() < 0)) 1691556Srgrimes return; 1701556Srgrimes 1711556Srgrimes /* 1721556Srgrimes * When we are doing interactive rename, we store the mapping of names 1731556Srgrimes * so we can fix up hard links files later in the archive. 1741556Srgrimes */ 1751556Srgrimes if (iflag && (name_start() < 0)) 1761556Srgrimes return; 1771556Srgrimes 17876351Skris now = time(NULL); 17976351Skris 1801556Srgrimes /* 1811556Srgrimes * step through each entry on the archive until the format read routine 1821556Srgrimes * says it is done 1831556Srgrimes */ 1841556Srgrimes while (next_head(arcn) == 0) { 1851556Srgrimes 1861556Srgrimes /* 1871556Srgrimes * check for pattern, and user specified options match. When 1881556Srgrimes * all the patterns are matched we are done 1891556Srgrimes */ 1901556Srgrimes if ((res = pat_match(arcn)) < 0) 1911556Srgrimes break; 1921556Srgrimes 1931556Srgrimes if ((res > 0) || (sel_chk(arcn) != 0)) { 1941556Srgrimes /* 1951556Srgrimes * file is not selected. skip past any file data and 1961556Srgrimes * padding and go back for the next archive member 1971556Srgrimes */ 1981556Srgrimes (void)rd_skip(arcn->skip + arcn->pad); 1991556Srgrimes continue; 2001556Srgrimes } 2011556Srgrimes 2021556Srgrimes /* 2031556Srgrimes * with -u or -D only extract when the archive member is newer 204102230Strhodes * than the file with the same name in the file system (nos 2051556Srgrimes * test of being the same type is required). 2061556Srgrimes * NOTE: this test is done BEFORE name modifications as 2071556Srgrimes * specified by pax. this operation can be confusing to the 2081556Srgrimes * user who might expect the test to be done on an existing 2091556Srgrimes * file AFTER the name mod. In honesty the pax spec is probably 2101556Srgrimes * flawed in this respect. 2111556Srgrimes */ 2121556Srgrimes if ((uflag || Dflag) && ((lstat(arcn->name, &sb) == 0))) { 2131556Srgrimes if (uflag && Dflag) { 2141556Srgrimes if ((arcn->sb.st_mtime <= sb.st_mtime) && 2151556Srgrimes (arcn->sb.st_ctime <= sb.st_ctime)) { 2161556Srgrimes (void)rd_skip(arcn->skip + arcn->pad); 2171556Srgrimes continue; 2181556Srgrimes } 2191556Srgrimes } else if (Dflag) { 2201556Srgrimes if (arcn->sb.st_ctime <= sb.st_ctime) { 2211556Srgrimes (void)rd_skip(arcn->skip + arcn->pad); 2221556Srgrimes continue; 2231556Srgrimes } 2241556Srgrimes } else if (arcn->sb.st_mtime <= sb.st_mtime) { 2251556Srgrimes (void)rd_skip(arcn->skip + arcn->pad); 2261556Srgrimes continue; 2271556Srgrimes } 2281556Srgrimes } 2291556Srgrimes 2301556Srgrimes /* 2311556Srgrimes * this archive member is now been selected. modify the name. 2321556Srgrimes */ 2331556Srgrimes if ((pat_sel(arcn) < 0) || ((res = mod_name(arcn)) < 0)) 2341556Srgrimes break; 2351556Srgrimes if (res > 0) { 2361556Srgrimes /* 2371556Srgrimes * a bad name mod, skip and purge name from link table 2381556Srgrimes */ 2391556Srgrimes purg_lnk(arcn); 2401556Srgrimes (void)rd_skip(arcn->skip + arcn->pad); 2411556Srgrimes continue; 2421556Srgrimes } 2431556Srgrimes 2441556Srgrimes /* 24546684Skris * Non standard -Y and -Z flag. When the existing file is 2461556Srgrimes * same age or newer skip 2471556Srgrimes */ 2481556Srgrimes if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) { 2491556Srgrimes if (Yflag && Zflag) { 2501556Srgrimes if ((arcn->sb.st_mtime <= sb.st_mtime) && 2511556Srgrimes (arcn->sb.st_ctime <= sb.st_ctime)) { 2521556Srgrimes (void)rd_skip(arcn->skip + arcn->pad); 2531556Srgrimes continue; 2541556Srgrimes } 2551556Srgrimes } else if (Yflag) { 2561556Srgrimes if (arcn->sb.st_ctime <= sb.st_ctime) { 2571556Srgrimes (void)rd_skip(arcn->skip + arcn->pad); 2581556Srgrimes continue; 2591556Srgrimes } 2601556Srgrimes } else if (arcn->sb.st_mtime <= sb.st_mtime) { 2611556Srgrimes (void)rd_skip(arcn->skip + arcn->pad); 2621556Srgrimes continue; 2631556Srgrimes } 2641556Srgrimes } 2651556Srgrimes 2661556Srgrimes if (vflag) { 26776351Skris if (vflag > 1) 26876351Skris ls_list(arcn, now, listf); 26976351Skris else { 27076351Skris (void)fputs(arcn->name, listf); 27176351Skris vfpart = 1; 27276351Skris } 2731556Srgrimes } 2741556Srgrimes 2751556Srgrimes /* 27676351Skris * if required, chdir around. 27776351Skris */ 27876351Skris if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL)) 27976351Skris if (chdir(arcn->pat->chdname) != 0) 28076351Skris syswarn(1, errno, "Cannot chdir to %s", 28176351Skris arcn->pat->chdname); 28276351Skris 28376351Skris /* 2841556Srgrimes * all ok, extract this member based on type 2851556Srgrimes */ 2861556Srgrimes if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) { 2871556Srgrimes /* 2881556Srgrimes * process archive members that are not regular files. 2891556Srgrimes * throw out padding and any data that might follow the 2901556Srgrimes * header (as determined by the format). 2911556Srgrimes */ 2921556Srgrimes if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) 2931556Srgrimes res = lnk_creat(arcn); 2941556Srgrimes else 2951556Srgrimes res = node_creat(arcn); 2961556Srgrimes 2971556Srgrimes (void)rd_skip(arcn->skip + arcn->pad); 2981556Srgrimes if (res < 0) 2991556Srgrimes purg_lnk(arcn); 3001556Srgrimes 3011556Srgrimes if (vflag && vfpart) { 30276351Skris (void)putc('\n', listf); 3031556Srgrimes vfpart = 0; 3041556Srgrimes } 3051556Srgrimes continue; 3061556Srgrimes } 3071556Srgrimes /* 3081556Srgrimes * we have a file with data here. If we can not create it, skip 3091556Srgrimes * over the data and purge the name from hard link table 3101556Srgrimes */ 3111556Srgrimes if ((fd = file_creat(arcn)) < 0) { 3121556Srgrimes (void)rd_skip(arcn->skip + arcn->pad); 3131556Srgrimes purg_lnk(arcn); 3141556Srgrimes continue; 3151556Srgrimes } 3161556Srgrimes /* 3171556Srgrimes * extract the file from the archive and skip over padding and 3181556Srgrimes * any unprocessed data 3191556Srgrimes */ 3201556Srgrimes res = (*frmt->rd_data)(arcn, fd, &cnt); 3211556Srgrimes file_close(arcn, fd); 3221556Srgrimes if (vflag && vfpart) { 32376351Skris (void)putc('\n', listf); 3241556Srgrimes vfpart = 0; 3251556Srgrimes } 3261556Srgrimes if (!res) 3271556Srgrimes (void)rd_skip(cnt + arcn->pad); 32876351Skris 32976351Skris /* 33076351Skris * if required, chdir around. 33176351Skris */ 33276351Skris if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL)) 33376351Skris if (fchdir(cwdfd) != 0) 33476351Skris syswarn(1, errno, 33576351Skris "Can't fchdir to starting directory"); 3361556Srgrimes } 3371556Srgrimes 3381556Srgrimes /* 3391556Srgrimes * all done, restore directory modes and times as required; make sure 3401556Srgrimes * all patterns supplied by the user were matched; block off signals 3411556Srgrimes * to avoid chance for multiple entry into the cleanup code. 3421556Srgrimes */ 3431556Srgrimes (void)(*frmt->end_rd)(); 34476017Skris (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); 3451556Srgrimes ar_close(); 3461556Srgrimes proc_dir(); 3471556Srgrimes pat_chk(); 3481556Srgrimes} 3491556Srgrimes 3501556Srgrimes/* 3511556Srgrimes * wr_archive() 3521556Srgrimes * Write an archive. used in both creating a new archive and appends on 3531556Srgrimes * previously written archive. 3541556Srgrimes */ 3551556Srgrimes 3561556Srgrimesstatic void 35790113Simpwr_archive(ARCHD *arcn, int is_app) 3581556Srgrimes{ 35990113Simp int res; 36090113Simp int hlk; 36190113Simp int wr_one; 3621556Srgrimes off_t cnt; 363114583Smarkm int (*wrf)(ARCHD *); 3641556Srgrimes int fd = -1; 36576351Skris time_t now; 3661556Srgrimes 3671556Srgrimes /* 3681556Srgrimes * if this format supports hard link storage, start up the database 3691556Srgrimes * that detects them. 3701556Srgrimes */ 3711556Srgrimes if (((hlk = frmt->hlk) == 1) && (lnk_start() < 0)) 3721556Srgrimes return; 3731556Srgrimes 3741556Srgrimes /* 3751556Srgrimes * start up the file traversal code and format specific write 3761556Srgrimes */ 3771556Srgrimes if ((ftree_start() < 0) || ((*frmt->st_wr)() < 0)) 3781556Srgrimes return; 3791556Srgrimes wrf = frmt->wr; 3801556Srgrimes 3811556Srgrimes /* 3821556Srgrimes * When we are doing interactive rename, we store the mapping of names 3831556Srgrimes * so we can fix up hard links files later in the archive. 3841556Srgrimes */ 3851556Srgrimes if (iflag && (name_start() < 0)) 3861556Srgrimes return; 3871556Srgrimes 3881556Srgrimes /* 3891556Srgrimes * if this not append, and there are no files, we do no write a trailer 3901556Srgrimes */ 3911556Srgrimes wr_one = is_app; 3921556Srgrimes 39376351Skris now = time(NULL); 39476351Skris 3951556Srgrimes /* 3961556Srgrimes * while there are files to archive, process them one at at time 3971556Srgrimes */ 3981556Srgrimes while (next_file(arcn) == 0) { 3991556Srgrimes /* 4001556Srgrimes * check if this file meets user specified options match. 4011556Srgrimes */ 402140097Sbrian if (sel_chk(arcn) != 0) { 403140097Sbrian ftree_notsel(); 4041556Srgrimes continue; 405140097Sbrian } 4061556Srgrimes fd = -1; 4071556Srgrimes if (uflag) { 4081556Srgrimes /* 4091556Srgrimes * only archive if this file is newer than a file with 4101556Srgrimes * the same name that is already stored on the archive 4111556Srgrimes */ 4121556Srgrimes if ((res = chk_ftime(arcn)) < 0) 4131556Srgrimes break; 4141556Srgrimes if (res > 0) 4151556Srgrimes continue; 4161556Srgrimes } 4171556Srgrimes 4181556Srgrimes /* 4191556Srgrimes * this file is considered selected now. see if this is a hard 4201556Srgrimes * link to a file already stored 4211556Srgrimes */ 4221556Srgrimes ftree_sel(arcn); 4231556Srgrimes if (hlk && (chk_lnk(arcn) < 0)) 4241556Srgrimes break; 4251556Srgrimes 4261556Srgrimes if ((arcn->type == PAX_REG) || (arcn->type == PAX_HRG) || 4271556Srgrimes (arcn->type == PAX_CTG)) { 4281556Srgrimes /* 4291556Srgrimes * we will have to read this file. by opening it now we 4301556Srgrimes * can avoid writing a header to the archive for a file 4311556Srgrimes * we were later unable to read (we also purge it from 4321556Srgrimes * the link table). 4331556Srgrimes */ 4341556Srgrimes if ((fd = open(arcn->org_name, O_RDONLY, 0)) < 0) { 43576017Skris syswarn(1,errno, "Unable to open %s to read", 4361556Srgrimes arcn->org_name); 4371556Srgrimes purg_lnk(arcn); 4381556Srgrimes continue; 4391556Srgrimes } 4401556Srgrimes } 4411556Srgrimes 4421556Srgrimes /* 4431556Srgrimes * Now modify the name as requested by the user 4441556Srgrimes */ 4451556Srgrimes if ((res = mod_name(arcn)) < 0) { 4461556Srgrimes /* 4471556Srgrimes * name modification says to skip this file, close the 4481556Srgrimes * file and purge link table entry 4491556Srgrimes */ 4501556Srgrimes rdfile_close(arcn, &fd); 4511556Srgrimes purg_lnk(arcn); 4521556Srgrimes break; 4531556Srgrimes } 4541556Srgrimes 4551556Srgrimes if ((res > 0) || (docrc && (set_crc(arcn, fd) < 0))) { 4561556Srgrimes /* 4571556Srgrimes * unable to obtain the crc we need, close the file, 4588855Srgrimes * purge link table entry 4591556Srgrimes */ 4601556Srgrimes rdfile_close(arcn, &fd); 4611556Srgrimes purg_lnk(arcn); 4621556Srgrimes continue; 4631556Srgrimes } 4641556Srgrimes 4651556Srgrimes if (vflag) { 46676351Skris if (vflag > 1) 46776351Skris ls_list(arcn, now, listf); 46876351Skris else { 46976351Skris (void)fputs(arcn->name, listf); 47076351Skris vfpart = 1; 47176351Skris } 4721556Srgrimes } 4731556Srgrimes ++flcnt; 4741556Srgrimes 4751556Srgrimes /* 4761556Srgrimes * looks safe to store the file, have the format specific 4771556Srgrimes * routine write routine store the file header on the archive 4781556Srgrimes */ 4791556Srgrimes if ((res = (*wrf)(arcn)) < 0) { 4801556Srgrimes rdfile_close(arcn, &fd); 4811556Srgrimes break; 4821556Srgrimes } 4831556Srgrimes wr_one = 1; 4841556Srgrimes if (res > 0) { 4858855Srgrimes /* 4861556Srgrimes * format write says no file data needs to be stored 4871556Srgrimes * so we are done messing with this file 4881556Srgrimes */ 4891556Srgrimes if (vflag && vfpart) { 49076351Skris (void)putc('\n', listf); 4911556Srgrimes vfpart = 0; 4921556Srgrimes } 4931556Srgrimes rdfile_close(arcn, &fd); 4941556Srgrimes continue; 4951556Srgrimes } 4961556Srgrimes 4971556Srgrimes /* 4981556Srgrimes * Add file data to the archive, quit on write error. if we 4991556Srgrimes * cannot write the entire file contents to the archive we 5001556Srgrimes * must pad the archive to replace the missing file data 5011556Srgrimes * (otherwise during an extract the file header for the file 5021556Srgrimes * which FOLLOWS this one will not be where we expect it to 5031556Srgrimes * be). 5041556Srgrimes */ 5051556Srgrimes res = (*frmt->wr_data)(arcn, fd, &cnt); 5061556Srgrimes rdfile_close(arcn, &fd); 5071556Srgrimes if (vflag && vfpart) { 50876351Skris (void)putc('\n', listf); 5091556Srgrimes vfpart = 0; 5101556Srgrimes } 5111556Srgrimes if (res < 0) 5121556Srgrimes break; 5131556Srgrimes 5141556Srgrimes /* 5151556Srgrimes * pad as required, cnt is number of bytes not written 5161556Srgrimes */ 5171556Srgrimes if (((cnt > 0) && (wr_skip(cnt) < 0)) || 5181556Srgrimes ((arcn->pad > 0) && (wr_skip(arcn->pad) < 0))) 5191556Srgrimes break; 5201556Srgrimes } 5211556Srgrimes 5221556Srgrimes /* 52346684Skris * tell format to write trailer; pad to block boundary; reset directory 5241556Srgrimes * mode/access times, and check if all patterns supplied by the user 5251556Srgrimes * were matched. block off signals to avoid chance for multiple entry 5261556Srgrimes * into the cleanup code 5271556Srgrimes */ 5281556Srgrimes if (wr_one) { 5291556Srgrimes (*frmt->end_wr)(); 5301556Srgrimes wr_fin(); 5311556Srgrimes } 53276017Skris (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); 5331556Srgrimes ar_close(); 5341556Srgrimes if (tflag) 5351556Srgrimes proc_dir(); 5361556Srgrimes ftree_chk(); 5371556Srgrimes} 5381556Srgrimes 5391556Srgrimes/* 5401556Srgrimes * append() 5411556Srgrimes * Add file to previously written archive. Archive format specified by the 5421556Srgrimes * user must agree with archive. The archive is read first to collect 5431556Srgrimes * modification times (if -u) and locate the archive trailer. The archive 5441556Srgrimes * is positioned in front of the record with the trailer and wr_archive() 5451556Srgrimes * is called to add the new members. 5461556Srgrimes * PAX IMPLEMENTATION DETAIL NOTE: 5471556Srgrimes * -u is implemented by adding the new members to the end of the archive. 5488855Srgrimes * Care is taken so that these do not end up as links to the older 5491556Srgrimes * version of the same file already stored in the archive. It is expected 5501556Srgrimes * when extraction occurs these newer versions will over-write the older 5511556Srgrimes * ones stored "earlier" in the archive (this may be a bad assumption as 5521556Srgrimes * it depends on the implementation of the program doing the extraction). 5531556Srgrimes * It is really difficult to splice in members without either re-writing 5541556Srgrimes * the entire archive (from the point were the old version was), or having 5551556Srgrimes * assistance of the format specification in terms of a special update 55646684Skris * header that invalidates a previous archive record. The POSIX spec left 5571556Srgrimes * the method used to implement -u unspecified. This pax is able to 5581556Srgrimes * over write existing files that it creates. 5591556Srgrimes */ 5601556Srgrimes 5611556Srgrimesvoid 5621556Srgrimesappend(void) 5631556Srgrimes{ 56490113Simp ARCHD *arcn; 56590113Simp int res; 5661556Srgrimes ARCHD archd; 5671556Srgrimes FSUB *orgfrmt; 5681556Srgrimes int udev; 5691556Srgrimes off_t tlen; 5701556Srgrimes 5711556Srgrimes arcn = &archd; 5721556Srgrimes orgfrmt = frmt; 5731556Srgrimes 5741556Srgrimes /* 5751556Srgrimes * Do not allow an append operation if the actual archive is of a 57646684Skris * different format than the user specified format. 5771556Srgrimes */ 5781556Srgrimes if (get_arc() < 0) 5791556Srgrimes return; 5801556Srgrimes if ((orgfrmt != NULL) && (orgfrmt != frmt)) { 58176017Skris paxwarn(1, "Cannot mix current archive format %s with %s", 5821556Srgrimes frmt->name, orgfrmt->name); 5831556Srgrimes return; 5841556Srgrimes } 5851556Srgrimes 5861556Srgrimes /* 5871556Srgrimes * pass the format any options and start up format 5881556Srgrimes */ 5891556Srgrimes if (((*frmt->options)() < 0) || ((*frmt->st_rd)() < 0)) 5901556Srgrimes return; 5911556Srgrimes 5921556Srgrimes /* 5931556Srgrimes * if we only are adding members that are newer, we need to save the 5941556Srgrimes * mod times for all files we see. 5951556Srgrimes */ 5961556Srgrimes if (uflag && (ftime_start() < 0)) 5971556Srgrimes return; 5981556Srgrimes 5991556Srgrimes /* 6001556Srgrimes * some archive formats encode hard links by recording the device and 6011556Srgrimes * file serial number (inode) but copy the file anyway (multiple times) 6021556Srgrimes * to the archive. When we append, we run the risk that newly added 6031556Srgrimes * files may have the same device and inode numbers as those recorded 6041556Srgrimes * on the archive but during a previous run. If this happens, when the 6051556Srgrimes * archive is extracted we get INCORRECT hard links. We avoid this by 6061556Srgrimes * remapping the device numbers so that newly added files will never 6071556Srgrimes * use the same device number as one found on the archive. remapping 6081556Srgrimes * allows new members to safely have links among themselves. remapping 6091556Srgrimes * also avoids problems with file inode (serial number) truncations 6101556Srgrimes * when the inode number is larger than storage space in the archive 6111556Srgrimes * header. See the remap routines for more details. 6121556Srgrimes */ 6131556Srgrimes if ((udev = frmt->udev) && (dev_start() < 0)) 6141556Srgrimes return; 6151556Srgrimes 6161556Srgrimes /* 6171556Srgrimes * reading the archive may take a long time. If verbose tell the user 6181556Srgrimes */ 6191556Srgrimes if (vflag) { 62076351Skris (void)fprintf(listf, 6211556Srgrimes "%s: Reading archive to position at the end...", argv0); 6221556Srgrimes vfpart = 1; 6231556Srgrimes } 6241556Srgrimes 6251556Srgrimes /* 6261556Srgrimes * step through the archive until the format says it is done 6271556Srgrimes */ 6281556Srgrimes while (next_head(arcn) == 0) { 6291556Srgrimes /* 6301556Srgrimes * check if this file meets user specified options. 6311556Srgrimes */ 6321556Srgrimes if (sel_chk(arcn) != 0) { 6331556Srgrimes if (rd_skip(arcn->skip + arcn->pad) == 1) 6341556Srgrimes break; 6351556Srgrimes continue; 6361556Srgrimes } 6371556Srgrimes 6381556Srgrimes if (uflag) { 6391556Srgrimes /* 6401556Srgrimes * see if this is the newest version of this file has 6411556Srgrimes * already been seen, if so skip. 6421556Srgrimes */ 6431556Srgrimes if ((res = chk_ftime(arcn)) < 0) 6441556Srgrimes break; 6451556Srgrimes if (res > 0) { 6461556Srgrimes if (rd_skip(arcn->skip + arcn->pad) == 1) 6471556Srgrimes break; 6481556Srgrimes continue; 6491556Srgrimes } 6501556Srgrimes } 6511556Srgrimes 6521556Srgrimes /* 6531556Srgrimes * Store this device number. Device numbers seen during the 6541556Srgrimes * read phase of append will cause newly appended files with a 6551556Srgrimes * device number seen in the old part of the archive to be 6561556Srgrimes * remapped to an unused device number. 6571556Srgrimes */ 6581556Srgrimes if ((udev && (add_dev(arcn) < 0)) || 6591556Srgrimes (rd_skip(arcn->skip + arcn->pad) == 1)) 6601556Srgrimes break; 6611556Srgrimes } 6621556Srgrimes 6631556Srgrimes /* 6641556Srgrimes * done, finish up read and get the number of bytes to back up so we 6651556Srgrimes * can add new members. The format might have used the hard link table, 6661556Srgrimes * purge it. 6671556Srgrimes */ 6681556Srgrimes tlen = (*frmt->end_rd)(); 6691556Srgrimes lnk_end(); 6701556Srgrimes 6711556Srgrimes /* 67246684Skris * try to position for write, if this fails quit. if any error occurs, 6731556Srgrimes * we will refuse to write 6741556Srgrimes */ 6751556Srgrimes if (appnd_start(tlen) < 0) 6761556Srgrimes return; 6771556Srgrimes 6781556Srgrimes /* 6791556Srgrimes * tell the user we are done reading. 6801556Srgrimes */ 6811556Srgrimes if (vflag && vfpart) { 68276351Skris (void)fputs("done.\n", listf); 6831556Srgrimes vfpart = 0; 6841556Srgrimes } 6858855Srgrimes 6861556Srgrimes /* 6871556Srgrimes * go to the writing phase to add the new members 6881556Srgrimes */ 6891556Srgrimes wr_archive(arcn, 1); 6901556Srgrimes} 6911556Srgrimes 6921556Srgrimes/* 6931556Srgrimes * archive() 6941556Srgrimes * write a new archive 6951556Srgrimes */ 6961556Srgrimes 6971556Srgrimesvoid 6981556Srgrimesarchive(void) 6991556Srgrimes{ 7001556Srgrimes ARCHD archd; 7011556Srgrimes 7021556Srgrimes /* 7031556Srgrimes * if we only are adding members that are newer, we need to save the 7041556Srgrimes * mod times for all files; set up for writing; pass the format any 7051556Srgrimes * options write the archive 7061556Srgrimes */ 7071556Srgrimes if ((uflag && (ftime_start() < 0)) || (wr_start() < 0)) 7081556Srgrimes return; 7091556Srgrimes if ((*frmt->options)() < 0) 7101556Srgrimes return; 7111556Srgrimes 7121556Srgrimes wr_archive(&archd, 0); 7131556Srgrimes} 7141556Srgrimes 7151556Srgrimes/* 7161556Srgrimes * copy() 717102230Strhodes * copy files from one part of the file system to another. this does not 7181556Srgrimes * use any archive storage. The EFFECT OF THE COPY IS THE SAME as if an 7191556Srgrimes * archive was written and then extracted in the destination directory 7201556Srgrimes * (except the files are forced to be under the destination directory). 7211556Srgrimes */ 7221556Srgrimes 7231556Srgrimesvoid 7241556Srgrimescopy(void) 7251556Srgrimes{ 72690113Simp ARCHD *arcn; 72790113Simp int res; 72890113Simp int fddest; 72990113Simp char *dest_pt; 73090113Simp int dlen; 73190113Simp int drem; 7321556Srgrimes int fdsrc = -1; 7331556Srgrimes struct stat sb; 7341556Srgrimes ARCHD archd; 7351556Srgrimes char dirbuf[PAXPATHLEN+1]; 7361556Srgrimes 7371556Srgrimes arcn = &archd; 7381556Srgrimes /* 7391556Srgrimes * set up the destination dir path and make sure it is a directory. We 7401556Srgrimes * make sure we have a trailing / on the destination 7411556Srgrimes */ 74231688Seivind dlen = l_strncpy(dirbuf, dirptr, sizeof(dirbuf) - 1); 7431556Srgrimes dest_pt = dirbuf + dlen; 7441556Srgrimes if (*(dest_pt-1) != '/') { 7451556Srgrimes *dest_pt++ = '/'; 7461556Srgrimes ++dlen; 7471556Srgrimes } 7481556Srgrimes *dest_pt = '\0'; 7491556Srgrimes drem = PAXPATHLEN - dlen; 7501556Srgrimes 7511556Srgrimes if (stat(dirptr, &sb) < 0) { 75276017Skris syswarn(1, errno, "Cannot access destination directory %s", 7531556Srgrimes dirptr); 7541556Srgrimes return; 7551556Srgrimes } 7561556Srgrimes if (!S_ISDIR(sb.st_mode)) { 75776017Skris paxwarn(1, "Destination is not a directory %s", dirptr); 7581556Srgrimes return; 7591556Srgrimes } 7601556Srgrimes 7611556Srgrimes /* 7621556Srgrimes * start up the hard link table; file traversal routines and the 7638855Srgrimes * modification time and access mode database 7641556Srgrimes */ 7651556Srgrimes if ((lnk_start() < 0) || (ftree_start() < 0) || (dir_start() < 0)) 7661556Srgrimes return; 7671556Srgrimes 7681556Srgrimes /* 7691556Srgrimes * When we are doing interactive rename, we store the mapping of names 7701556Srgrimes * so we can fix up hard links files later in the archive. 7711556Srgrimes */ 7721556Srgrimes if (iflag && (name_start() < 0)) 7731556Srgrimes return; 7741556Srgrimes 7751556Srgrimes /* 7761556Srgrimes * set up to cp file trees 7771556Srgrimes */ 7781556Srgrimes cp_start(); 7791556Srgrimes 7801556Srgrimes /* 7811556Srgrimes * while there are files to archive, process them 7821556Srgrimes */ 7831556Srgrimes while (next_file(arcn) == 0) { 7841556Srgrimes fdsrc = -1; 7851556Srgrimes 7861556Srgrimes /* 7871556Srgrimes * check if this file meets user specified options 7881556Srgrimes */ 789140097Sbrian if (sel_chk(arcn) != 0) { 790140097Sbrian ftree_notsel(); 7911556Srgrimes continue; 792140097Sbrian } 7931556Srgrimes 7941556Srgrimes /* 7951556Srgrimes * if there is already a file in the destination directory with 7961556Srgrimes * the same name and it is newer, skip the one stored on the 7971556Srgrimes * archive. 7981556Srgrimes * NOTE: this test is done BEFORE name modifications as 7991556Srgrimes * specified by pax. this can be confusing to the user who 8001556Srgrimes * might expect the test to be done on an existing file AFTER 8011556Srgrimes * the name mod. In honesty the pax spec is probably flawed in 8021556Srgrimes * this respect 8031556Srgrimes */ 8041556Srgrimes if (uflag || Dflag) { 8051556Srgrimes /* 8061556Srgrimes * create the destination name 8071556Srgrimes */ 8081556Srgrimes if (*(arcn->name) == '/') 8091556Srgrimes res = 1; 8101556Srgrimes else 8111556Srgrimes res = 0; 8121556Srgrimes if ((arcn->nlen - res) > drem) { 81376017Skris paxwarn(1, "Destination pathname too long %s", 8141556Srgrimes arcn->name); 8151556Srgrimes continue; 8161556Srgrimes } 8171556Srgrimes (void)strncpy(dest_pt, arcn->name + res, drem); 8181556Srgrimes dirbuf[PAXPATHLEN] = '\0'; 8191556Srgrimes 8201556Srgrimes /* 8211556Srgrimes * if existing file is same age or newer skip 8221556Srgrimes */ 8231556Srgrimes res = lstat(dirbuf, &sb); 8241556Srgrimes *dest_pt = '\0'; 8251556Srgrimes 8261556Srgrimes if (res == 0) { 8271556Srgrimes if (uflag && Dflag) { 8281556Srgrimes if ((arcn->sb.st_mtime<=sb.st_mtime) && 8291556Srgrimes (arcn->sb.st_ctime<=sb.st_ctime)) 8301556Srgrimes continue; 8311556Srgrimes } else if (Dflag) { 8321556Srgrimes if (arcn->sb.st_ctime <= sb.st_ctime) 8331556Srgrimes continue; 8341556Srgrimes } else if (arcn->sb.st_mtime <= sb.st_mtime) 8351556Srgrimes continue; 8361556Srgrimes } 8371556Srgrimes } 8381556Srgrimes 8391556Srgrimes /* 8401556Srgrimes * this file is considered selected. See if this is a hard link 8411556Srgrimes * to a previous file; modify the name as requested by the 8421556Srgrimes * user; set the final destination. 8431556Srgrimes */ 8441556Srgrimes ftree_sel(arcn); 8451556Srgrimes if ((chk_lnk(arcn) < 0) || ((res = mod_name(arcn)) < 0)) 8461556Srgrimes break; 8471556Srgrimes if ((res > 0) || (set_dest(arcn, dirbuf, dlen) < 0)) { 8481556Srgrimes /* 8491556Srgrimes * skip file, purge from link table 8501556Srgrimes */ 8511556Srgrimes purg_lnk(arcn); 8521556Srgrimes continue; 8531556Srgrimes } 8541556Srgrimes 8551556Srgrimes /* 856222177Suqs * Non standard -Y and -Z flag. When the existing file is 8571556Srgrimes * same age or newer skip 8581556Srgrimes */ 8591556Srgrimes if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) { 8601556Srgrimes if (Yflag && Zflag) { 8611556Srgrimes if ((arcn->sb.st_mtime <= sb.st_mtime) && 8621556Srgrimes (arcn->sb.st_ctime <= sb.st_ctime)) 8631556Srgrimes continue; 8641556Srgrimes } else if (Yflag) { 8651556Srgrimes if (arcn->sb.st_ctime <= sb.st_ctime) 8661556Srgrimes continue; 8671556Srgrimes } else if (arcn->sb.st_mtime <= sb.st_mtime) 8681556Srgrimes continue; 8691556Srgrimes } 8701556Srgrimes 8711556Srgrimes if (vflag) { 87276351Skris (void)fputs(arcn->name, listf); 8731556Srgrimes vfpart = 1; 8741556Srgrimes } 8751556Srgrimes ++flcnt; 8761556Srgrimes 8771556Srgrimes /* 8781556Srgrimes * try to create a hard link to the src file if requested 8791556Srgrimes * but make sure we are not trying to overwrite ourselves. 8801556Srgrimes */ 8818855Srgrimes if (lflag) 8821556Srgrimes res = cross_lnk(arcn); 8831556Srgrimes else 8841556Srgrimes res = chk_same(arcn); 8851556Srgrimes if (res <= 0) { 8861556Srgrimes if (vflag && vfpart) { 88776351Skris (void)putc('\n', listf); 8881556Srgrimes vfpart = 0; 8891556Srgrimes } 8901556Srgrimes continue; 8911556Srgrimes } 8921556Srgrimes 8931556Srgrimes /* 8941556Srgrimes * have to create a new file 8951556Srgrimes */ 8961556Srgrimes if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) { 8971556Srgrimes /* 8981556Srgrimes * create a link or special file 8991556Srgrimes */ 9001556Srgrimes if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) 9011556Srgrimes res = lnk_creat(arcn); 9021556Srgrimes else 9031556Srgrimes res = node_creat(arcn); 9041556Srgrimes if (res < 0) 9051556Srgrimes purg_lnk(arcn); 9061556Srgrimes if (vflag && vfpart) { 90776351Skris (void)putc('\n', listf); 9081556Srgrimes vfpart = 0; 9091556Srgrimes } 9101556Srgrimes continue; 9111556Srgrimes } 9121556Srgrimes 9131556Srgrimes /* 9141556Srgrimes * have to copy a regular file to the destination directory. 9151556Srgrimes * first open source file and then create the destination file 9161556Srgrimes */ 9171556Srgrimes if ((fdsrc = open(arcn->org_name, O_RDONLY, 0)) < 0) { 91876017Skris syswarn(1, errno, "Unable to open %s to read", 9191556Srgrimes arcn->org_name); 9201556Srgrimes purg_lnk(arcn); 9211556Srgrimes continue; 9221556Srgrimes } 9231556Srgrimes if ((fddest = file_creat(arcn)) < 0) { 9241556Srgrimes rdfile_close(arcn, &fdsrc); 9251556Srgrimes purg_lnk(arcn); 9261556Srgrimes continue; 9271556Srgrimes } 9281556Srgrimes 9291556Srgrimes /* 9301556Srgrimes * copy source file data to the destination file 9311556Srgrimes */ 9321556Srgrimes cp_file(arcn, fdsrc, fddest); 9331556Srgrimes file_close(arcn, fddest); 9341556Srgrimes rdfile_close(arcn, &fdsrc); 9351556Srgrimes 9361556Srgrimes if (vflag && vfpart) { 93776351Skris (void)putc('\n', listf); 9381556Srgrimes vfpart = 0; 9391556Srgrimes } 9401556Srgrimes } 9411556Srgrimes 9421556Srgrimes /* 9431556Srgrimes * restore directory modes and times as required; make sure all 9441556Srgrimes * patterns were selected block off signals to avoid chance for 9451556Srgrimes * multiple entry into the cleanup code. 9461556Srgrimes */ 94776017Skris (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); 9481556Srgrimes ar_close(); 9491556Srgrimes proc_dir(); 9501556Srgrimes ftree_chk(); 9511556Srgrimes} 9521556Srgrimes 9531556Srgrimes/* 9541556Srgrimes * next_head() 9551556Srgrimes * try to find a valid header in the archive. Uses format specific 9561556Srgrimes * routines to extract the header and id the trailer. Trailers may be 9571556Srgrimes * located within a valid header or in an invalid header (the location 9581556Srgrimes * is format specific. The inhead field from the option table tells us 9591556Srgrimes * where to look for the trailer). 9601556Srgrimes * We keep reading (and resyncing) until we get enough contiguous data 9611556Srgrimes * to check for a header. If we cannot find one, we shift by a byte 9621556Srgrimes * add a new byte from the archive to the end of the buffer and try again. 9631556Srgrimes * If we get a read error, we throw out what we have (as we must have 9641556Srgrimes * contiguous data) and start over again. 9651556Srgrimes * ASSUMED: headers fit within a BLKMULT header. 9661556Srgrimes * Return: 9671556Srgrimes * 0 if we got a header, -1 if we are unable to ever find another one 9681556Srgrimes * (we reached the end of input, or we reached the limit on retries. see 9691556Srgrimes * the specs for rd_wrbuf() for more details) 9701556Srgrimes */ 9711556Srgrimes 9721556Srgrimesstatic int 97390113Simpnext_head(ARCHD *arcn) 9741556Srgrimes{ 97590113Simp int ret; 97690113Simp char *hdend; 97790113Simp int res; 97890113Simp int shftsz; 97990113Simp int hsz; 98090113Simp int in_resync = 0; /* set when we are in resync mode */ 9811556Srgrimes int cnt = 0; /* counter for trailer function */ 98276351Skris int first = 1; /* on 1st read, EOF isn't premature. */ 9838855Srgrimes 9841556Srgrimes /* 9851556Srgrimes * set up initial conditions, we want a whole frmt->hsz block as we 9861556Srgrimes * have no data yet. 9871556Srgrimes */ 9881556Srgrimes res = hsz = frmt->hsz; 9891556Srgrimes hdend = hdbuf; 9901556Srgrimes shftsz = hsz - 1; 9911556Srgrimes for(;;) { 9921556Srgrimes /* 9931556Srgrimes * keep looping until we get a contiguous FULL buffer 9941556Srgrimes * (frmt->hsz is the proper size) 9951556Srgrimes */ 9961556Srgrimes for (;;) { 9971556Srgrimes if ((ret = rd_wrbuf(hdend, res)) == res) 9981556Srgrimes break; 9991556Srgrimes 10001556Srgrimes /* 100176351Skris * If we read 0 bytes (EOF) from an archive when we 100276351Skris * expect to find a header, we have stepped upon 100376351Skris * an archive without the customary block of zeroes 100476351Skris * end marker. It's just stupid to error out on 100576351Skris * them, so exit gracefully. 100676351Skris */ 100776351Skris if (first && ret == 0) 100876351Skris return(-1); 100976351Skris first = 0; 101076351Skris 101176351Skris /* 10121556Srgrimes * some kind of archive read problem, try to resync the 10131556Srgrimes * storage device, better give the user the bad news. 10141556Srgrimes */ 10151556Srgrimes if ((ret == 0) || (rd_sync() < 0)) { 101676017Skris paxwarn(1,"Premature end of file on archive read"); 10171556Srgrimes return(-1); 10181556Srgrimes } 10191556Srgrimes if (!in_resync) { 10201556Srgrimes if (act == APPND) { 102176017Skris paxwarn(1, 102276019Skris "Archive I/O error, cannot continue"); 10231556Srgrimes return(-1); 10241556Srgrimes } 102576017Skris paxwarn(1,"Archive I/O error. Trying to recover."); 10261556Srgrimes ++in_resync; 10271556Srgrimes } 10281556Srgrimes 10291556Srgrimes /* 10301556Srgrimes * oh well, throw it all out and start over 10311556Srgrimes */ 10321556Srgrimes res = hsz; 10331556Srgrimes hdend = hdbuf; 10341556Srgrimes } 10351556Srgrimes 10361556Srgrimes /* 10371556Srgrimes * ok we have a contiguous buffer of the right size. Call the 10381556Srgrimes * format read routine. If this was not a valid header and this 10391556Srgrimes * format stores trailers outside of the header, call the 10401556Srgrimes * format specific trailer routine to check for a trailer. We 10411556Srgrimes * have to watch out that we do not mis-identify file data or 10421556Srgrimes * block padding as a header or trailer. Format specific 10431556Srgrimes * trailer functions must NOT check for the trailer while we 10441556Srgrimes * are running in resync mode. Some trailer functions may tell 10451556Srgrimes * us that this block cannot contain a valid header either, so 10461556Srgrimes * we then throw out the entire block and start over. 10471556Srgrimes */ 10481556Srgrimes if ((*frmt->rd)(arcn, hdbuf) == 0) 10491556Srgrimes break; 10501556Srgrimes 10511556Srgrimes if (!frmt->inhead) { 10521556Srgrimes /* 10531556Srgrimes * this format has trailers outside of valid headers 10541556Srgrimes */ 1055114583Smarkm if ((ret = (*frmt->trail_tar)(hdbuf,in_resync,&cnt)) == 0){ 10561556Srgrimes /* 10571556Srgrimes * valid trailer found, drain input as required 10581556Srgrimes */ 10591556Srgrimes ar_drain(); 10601556Srgrimes return(-1); 10611556Srgrimes } 10621556Srgrimes 10631556Srgrimes if (ret == 1) { 10641556Srgrimes /* 10651556Srgrimes * we are in resync and we were told to throw 10661556Srgrimes * the whole block out because none of the 10671556Srgrimes * bytes in this block can be used to form a 10681556Srgrimes * valid header 10691556Srgrimes */ 10701556Srgrimes res = hsz; 10711556Srgrimes hdend = hdbuf; 10721556Srgrimes continue; 10731556Srgrimes } 10741556Srgrimes } 10751556Srgrimes 10761556Srgrimes /* 10771556Srgrimes * Brute force section. 10781556Srgrimes * not a valid header. We may be able to find a header yet. So 10791556Srgrimes * we shift over by one byte, and set up to read one byte at a 10801556Srgrimes * time from the archive and place it at the end of the buffer. 10811556Srgrimes * We will keep moving byte at a time until we find a header or 10821556Srgrimes * get a read error and have to start over. 10831556Srgrimes */ 10841556Srgrimes if (!in_resync) { 10851556Srgrimes if (act == APPND) { 108676017Skris paxwarn(1,"Unable to append, archive header flaw"); 10871556Srgrimes return(-1); 10881556Srgrimes } 108976017Skris paxwarn(1,"Invalid header, starting valid header search."); 10901556Srgrimes ++in_resync; 10911556Srgrimes } 109276017Skris memmove(hdbuf, hdbuf+1, shftsz); 10931556Srgrimes res = 1; 10941556Srgrimes hdend = hdbuf + shftsz; 10951556Srgrimes } 10961556Srgrimes 10971556Srgrimes /* 1098222177Suqs * ok got a valid header, check for trailer if format encodes it in 1099114583Smarkm * the header. 11001556Srgrimes */ 1101114583Smarkm if (frmt->inhead && ((*frmt->trail_cpio)(arcn) == 0)) { 11021556Srgrimes /* 11031556Srgrimes * valid trailer found, drain input as required 11041556Srgrimes */ 11051556Srgrimes ar_drain(); 11061556Srgrimes return(-1); 11071556Srgrimes } 11081556Srgrimes 11091556Srgrimes ++flcnt; 11101556Srgrimes return(0); 11111556Srgrimes} 11121556Srgrimes 11131556Srgrimes/* 11141556Srgrimes * get_arc() 11151556Srgrimes * Figure out what format an archive is. Handles archive with flaws by 11161556Srgrimes * brute force searches for a legal header in any supported format. The 11171556Srgrimes * format id routines have to be careful to NOT mis-identify a format. 11181556Srgrimes * ASSUMED: headers fit within a BLKMULT header. 11191556Srgrimes * Return: 11201556Srgrimes * 0 if archive found -1 otherwise 11211556Srgrimes */ 11221556Srgrimes 11231556Srgrimesstatic int 11241556Srgrimesget_arc(void) 11251556Srgrimes{ 112690113Simp int i; 112790113Simp int hdsz = 0; 112890113Simp int res; 112990113Simp int minhd = BLKMULT; 11301556Srgrimes char *hdend; 11311556Srgrimes int notice = 0; 11328855Srgrimes 11331556Srgrimes /* 11341556Srgrimes * find the smallest header size in all archive formats and then set up 11351556Srgrimes * to read the archive. 11361556Srgrimes */ 11371556Srgrimes for (i = 0; ford[i] >= 0; ++i) { 11381556Srgrimes if (fsub[ford[i]].hsz < minhd) 11391556Srgrimes minhd = fsub[ford[i]].hsz; 11401556Srgrimes } 11411556Srgrimes if (rd_start() < 0) 11421556Srgrimes return(-1); 11431556Srgrimes res = BLKMULT; 11441556Srgrimes hdsz = 0; 11451556Srgrimes hdend = hdbuf; 11461556Srgrimes for(;;) { 11471556Srgrimes for (;;) { 11481556Srgrimes /* 11491556Srgrimes * fill the buffer with at least the smallest header 11501556Srgrimes */ 11511556Srgrimes i = rd_wrbuf(hdend, res); 11521556Srgrimes if (i > 0) 11531556Srgrimes hdsz += i; 11541556Srgrimes if (hdsz >= minhd) 11551556Srgrimes break; 11561556Srgrimes 11571556Srgrimes /* 11581556Srgrimes * if we cannot recover from a read error quit 11591556Srgrimes */ 11601556Srgrimes if ((i == 0) || (rd_sync() < 0)) 11611556Srgrimes goto out; 11621556Srgrimes 11631556Srgrimes /* 11641556Srgrimes * when we get an error none of the data we already 11651556Srgrimes * have can be used to create a legal header (we just 11661556Srgrimes * got an error in the middle), so we throw it all out 11671556Srgrimes * and refill the buffer with fresh data. 11681556Srgrimes */ 11691556Srgrimes res = BLKMULT; 11701556Srgrimes hdsz = 0; 11711556Srgrimes hdend = hdbuf; 11721556Srgrimes if (!notice) { 11731556Srgrimes if (act == APPND) 11741556Srgrimes return(-1); 117576017Skris paxwarn(1,"Cannot identify format. Searching..."); 11761556Srgrimes ++notice; 11771556Srgrimes } 11781556Srgrimes } 11791556Srgrimes 11801556Srgrimes /* 11811556Srgrimes * we have at least the size of the smallest header in any 11821556Srgrimes * archive format. Look to see if we have a match. The array 11831556Srgrimes * ford[] is used to specify the header id order to reduce the 11841556Srgrimes * chance of incorrectly id'ing a valid header (some formats 11851556Srgrimes * may be subsets of each other and the order would then be 11861556Srgrimes * important). 11871556Srgrimes */ 11881556Srgrimes for (i = 0; ford[i] >= 0; ++i) { 11891556Srgrimes if ((*fsub[ford[i]].id)(hdbuf, hdsz) < 0) 11901556Srgrimes continue; 11911556Srgrimes frmt = &(fsub[ford[i]]); 11928855Srgrimes /* 11931556Srgrimes * yuck, to avoid slow special case code in the extract 11941556Srgrimes * routines, just push this header back as if it was 11951556Srgrimes * not seen. We have left extra space at start of the 11961556Srgrimes * buffer for this purpose. This is a bit ugly, but 11971556Srgrimes * adding all the special case code is far worse. 11981556Srgrimes */ 11991556Srgrimes pback(hdbuf, hdsz); 12001556Srgrimes return(0); 12011556Srgrimes } 12021556Srgrimes 12031556Srgrimes /* 12041556Srgrimes * We have a flawed archive, no match. we start searching, but 12051556Srgrimes * we never allow additions to flawed archives 12061556Srgrimes */ 12071556Srgrimes if (!notice) { 12081556Srgrimes if (act == APPND) 12091556Srgrimes return(-1); 121076017Skris paxwarn(1, "Cannot identify format. Searching..."); 12111556Srgrimes ++notice; 12121556Srgrimes } 12131556Srgrimes 12141556Srgrimes /* 12151556Srgrimes * brute force search for a header that we can id. 12161556Srgrimes * we shift through byte at a time. this is slow, but we cannot 12171556Srgrimes * determine the nature of the flaw in the archive in a 12181556Srgrimes * portable manner 12191556Srgrimes */ 12201556Srgrimes if (--hdsz > 0) { 122176017Skris memmove(hdbuf, hdbuf+1, hdsz); 12221556Srgrimes res = BLKMULT - hdsz; 12231556Srgrimes hdend = hdbuf + hdsz; 12241556Srgrimes } else { 12251556Srgrimes res = BLKMULT; 12261556Srgrimes hdend = hdbuf; 12271556Srgrimes hdsz = 0; 12281556Srgrimes } 12291556Srgrimes } 12301556Srgrimes 12311556Srgrimes out: 12321556Srgrimes /* 12331556Srgrimes * we cannot find a header, bow, apologize and quit 12341556Srgrimes */ 123576017Skris paxwarn(1, "Sorry, unable to determine archive format."); 12361556Srgrimes return(-1); 12371556Srgrimes} 1238