1*2b9c0f9fSriastradh /* $NetBSD: ar_subs.c,v 1.59 2024/08/05 13:37:26 riastradh Exp $ */ 2b5b29542Sagc 3b5b29542Sagc /*- 4ed6ed8e6Sagc * Copyright (c) 1992 Keith Muller. 5b5b29542Sagc * Copyright (c) 1992, 1993 6b5b29542Sagc * The Regents of the University of California. All rights reserved. 7b5b29542Sagc * 8b5b29542Sagc * This code is derived from software contributed to Berkeley by 9b5b29542Sagc * Keith Muller of the University of California, San Diego. 10b5b29542Sagc * 11b5b29542Sagc * Redistribution and use in source and binary forms, with or without 12b5b29542Sagc * modification, are permitted provided that the following conditions 13b5b29542Sagc * are met: 14b5b29542Sagc * 1. Redistributions of source code must retain the above copyright 15b5b29542Sagc * notice, this list of conditions and the following disclaimer. 16b5b29542Sagc * 2. Redistributions in binary form must reproduce the above copyright 17b5b29542Sagc * notice, this list of conditions and the following disclaimer in the 18b5b29542Sagc * documentation and/or other materials provided with the distribution. 19b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors 20b5b29542Sagc * may be used to endorse or promote products derived from this software 21b5b29542Sagc * without specific prior written permission. 22b5b29542Sagc * 23b5b29542Sagc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24b5b29542Sagc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25b5b29542Sagc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26b5b29542Sagc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27b5b29542Sagc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28b5b29542Sagc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29b5b29542Sagc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30b5b29542Sagc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31b5b29542Sagc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32b5b29542Sagc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33b5b29542Sagc * SUCH DAMAGE. 34b5b29542Sagc */ 3549f0ad86Scgd 36171d6532Slukem #if HAVE_NBTOOL_CONFIG_H 37171d6532Slukem #include "nbtool_config.h" 38171d6532Slukem #endif 39171d6532Slukem 40f3cd6022Schristos #include <sys/cdefs.h> 41171d6532Slukem #if !defined(lint) 4249f0ad86Scgd #if 0 4349f0ad86Scgd static char sccsid[] = "@(#)ar_subs.c 8.2 (Berkeley) 4/18/94"; 4449f0ad86Scgd #else 45*2b9c0f9fSriastradh __RCSID("$NetBSD: ar_subs.c,v 1.59 2024/08/05 13:37:26 riastradh Exp $"); 4649f0ad86Scgd #endif 478b35abe2Sjtc #endif /* not lint */ 488b35abe2Sjtc 498b35abe2Sjtc #include <sys/types.h> 508b35abe2Sjtc #include <sys/time.h> 518b35abe2Sjtc #include <sys/stat.h> 528b35abe2Sjtc #include <sys/param.h> 538b35abe2Sjtc #include <signal.h> 548b35abe2Sjtc #include <string.h> 558b35abe2Sjtc #include <stdio.h> 568b35abe2Sjtc #include <ctype.h> 578b35abe2Sjtc #include <fcntl.h> 588b35abe2Sjtc #include <errno.h> 593a5b0ca8Skleink #include <time.h> 608b35abe2Sjtc #include <unistd.h> 618b35abe2Sjtc #include <stdlib.h> 628b35abe2Sjtc #include "pax.h" 63206f4182Schristos #include "pat_rep.h" 648b35abe2Sjtc #include "extern.h" 658b35abe2Sjtc 6614f615efSchristos static int path_check(ARCHD *, int); 67b419a254Sdsl static int wr_archive(ARCHD *, int is_app); 68c1bd745cSlukem static int get_arc(void); 69c1bd745cSlukem static int next_head(ARCHD *); 704e0ae89bSchristos #if !HAVE_NBTOOL_CONFIG_H 710a6f2d38Schristos static int fdochroot(int); 724e0ae89bSchristos #endif 738b35abe2Sjtc extern sigset_t s_mask; 748b35abe2Sjtc 758b35abe2Sjtc /* 768b35abe2Sjtc * Routines which control the overall operation modes of pax as specified by 778b35abe2Sjtc * the user: list, append, read ... 788b35abe2Sjtc */ 798b35abe2Sjtc 808b35abe2Sjtc static char hdbuf[BLKMULT]; /* space for archive header on read */ 818b35abe2Sjtc u_long flcnt; /* number of files processed */ 82789b7159Schristos ARCHD archd; 838b35abe2Sjtc 8415ea30ebSchristos static char cwdpath[MAXPATHLEN]; /* current working directory path */ 8515ea30ebSchristos static size_t cwdpathlen; /* current working directory path len */ 8615ea30ebSchristos 8715ea30ebSchristos int 8815ea30ebSchristos updatepath(void) 8915ea30ebSchristos { 9015ea30ebSchristos if (getcwd(cwdpath, sizeof(cwdpath)) == NULL) { 9115ea30ebSchristos syswarn(1, errno, "Cannot get working directory"); 9215ea30ebSchristos return -1; 9315ea30ebSchristos } 9415ea30ebSchristos cwdpathlen = strlen(cwdpath); 9515ea30ebSchristos return 0; 9615ea30ebSchristos } 9715ea30ebSchristos 9815ea30ebSchristos int 990a6f2d38Schristos fdochdir(int fcwd) 10015ea30ebSchristos { 1010a6f2d38Schristos if (fchdir(fcwd) == -1) { 10215ea30ebSchristos syswarn(1, errno, "Cannot chdir to `.'"); 10315ea30ebSchristos return -1; 10415ea30ebSchristos } 10515ea30ebSchristos return updatepath(); 10615ea30ebSchristos } 10715ea30ebSchristos 10815ea30ebSchristos int 10915ea30ebSchristos dochdir(const char *name) 11015ea30ebSchristos { 11115ea30ebSchristos if (chdir(name) == -1) 11215ea30ebSchristos syswarn(1, errno, "Cannot chdir to `%s'", name); 11315ea30ebSchristos return updatepath(); 11415ea30ebSchristos } 11515ea30ebSchristos 1166ae4f781Sjmc #if !HAVE_NBTOOL_CONFIG_H 11715ea30ebSchristos static int 1180a6f2d38Schristos fdochroot(int fcwd) 1190a6f2d38Schristos { 1200a6f2d38Schristos if (fchroot(fcwd) != 0) { 1210a6f2d38Schristos syswarn(1, errno, "Can't fchroot to \".\""); 1220a6f2d38Schristos return -1; 1230a6f2d38Schristos } 1240a6f2d38Schristos return updatepath(); 1250a6f2d38Schristos } 1266ae4f781Sjmc #endif 1270a6f2d38Schristos 128b60b306eSchristos /* 129b60b306eSchristos * mkdir(), but if we failed, check if someone else made it for us 130b60b306eSchristos * already and don't error out. 131b60b306eSchristos */ 132b60b306eSchristos int 133b60b306eSchristos domkdir(const char *fname, mode_t mode) 134b60b306eSchristos { 135b60b306eSchristos int error; 136b60b306eSchristos struct stat sb; 137b60b306eSchristos 138b39d90deSchristos if ((error = mkdir(fname, mode)) != -1) 139b60b306eSchristos return error; 140b60b306eSchristos 141b39d90deSchristos switch (errno) { 142b39d90deSchristos case EISDIR: 143b60b306eSchristos return 0; 144b39d90deSchristos case EEXIST: 145d0d28f16Schristos case EACCES: 146ef3fea85Schristos case ENOSYS: /* Grr Solaris */ 147bbe06531Srillig case EROFS: 148b39d90deSchristos error = errno; 149b39d90deSchristos if (stat(fname, &sb) != -1 && S_ISDIR(sb.st_mode)) 150b39d90deSchristos return 0; 151b60b306eSchristos errno = error; 152b39d90deSchristos /*FALLTHROUGH*/ 153b39d90deSchristos default: 154b60b306eSchristos return -1; 155b60b306eSchristos } 156b39d90deSchristos } 157b60b306eSchristos 1580a6f2d38Schristos static int 15914f615efSchristos path_check(ARCHD *arcn, int level) 16015ea30ebSchristos { 16115ea30ebSchristos char buf[MAXPATHLEN]; 162398a0816Schristos char *p; 163398a0816Schristos 164398a0816Schristos if ((p = strrchr(arcn->name, '/')) == NULL) 165398a0816Schristos return 0; 166398a0816Schristos *p = '\0'; 16715ea30ebSchristos 16815ea30ebSchristos if (realpath(arcn->name, buf) == NULL) { 16914f615efSchristos int error; 17014f615efSchristos error = path_check(arcn, level + 1); 17114f615efSchristos *p = '/'; 17214f615efSchristos if (error == 0) 17314f615efSchristos return 0; 17414f615efSchristos if (level == 0) 17515ea30ebSchristos syswarn(1, 0, "Cannot resolve `%s'", arcn->name); 17615ea30ebSchristos return -1; 17715ea30ebSchristos } 17815ea30ebSchristos if (strncmp(buf, cwdpath, cwdpathlen) != 0) { 179398a0816Schristos *p = '/'; 180398a0816Schristos syswarn(1, 0, "Attempt to write file `%s' that resolves into " 181398a0816Schristos "`%s/%s' outside current working directory `%s' ignored", 182398a0816Schristos arcn->name, buf, p + 1, cwdpath); 18315ea30ebSchristos return -1; 18415ea30ebSchristos } 185398a0816Schristos *p = '/'; 18615ea30ebSchristos return 0; 18715ea30ebSchristos } 18815ea30ebSchristos 1898b35abe2Sjtc /* 1908b35abe2Sjtc * list() 1918b35abe2Sjtc * list the contents of an archive which match user supplied pattern(s) 1923ac7ce18Swiz * (if no pattern is supplied, list entire contents). 1938b35abe2Sjtc */ 1948b35abe2Sjtc 195b419a254Sdsl int 1968b35abe2Sjtc list(void) 1978b35abe2Sjtc { 19848250187Stls ARCHD *arcn; 19948250187Stls int res; 2008b35abe2Sjtc time_t now; 2018b35abe2Sjtc 2028b35abe2Sjtc arcn = &archd; 2038b35abe2Sjtc /* 2048b35abe2Sjtc * figure out archive type; pass any format specific options to the 2058b35abe2Sjtc * archive option processing routine; call the format init routine. We 2068b35abe2Sjtc * also save current time for ls_list() so we do not make a system 2078b35abe2Sjtc * call for each file we need to print. If verbose (vflag) start up 2088b35abe2Sjtc * the name and group caches. 2098b35abe2Sjtc */ 2108b35abe2Sjtc if ((get_arc() < 0) || ((*frmt->options)() < 0) || 2118b35abe2Sjtc ((*frmt->st_rd)() < 0)) 212b419a254Sdsl return 1; 2138b35abe2Sjtc 2149f61b804Splunky now = time(NULL); 2158b35abe2Sjtc 2168b35abe2Sjtc /* 2178b35abe2Sjtc * step through the archive until the format says it is done 2188b35abe2Sjtc */ 2198b35abe2Sjtc while (next_head(arcn) == 0) { 220f70dfaafSchristos if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) { 221f70dfaafSchristos /* 222f70dfaafSchristos * we need to read, to get the real filename 223f70dfaafSchristos */ 224f70dfaafSchristos off_t cnt; 22506a1f6e7Schristos if (!(*frmt->rd_data)(arcn, -arcn->type, &cnt)) 226f70dfaafSchristos (void)rd_skip(cnt + arcn->pad); 227f70dfaafSchristos continue; 228f70dfaafSchristos } 229f70dfaafSchristos 2308b35abe2Sjtc /* 2318b35abe2Sjtc * check for pattern, and user specified options match. 2328b35abe2Sjtc * When all patterns are matched we are done. 2338b35abe2Sjtc */ 2348b35abe2Sjtc if ((res = pat_match(arcn)) < 0) 2358b35abe2Sjtc break; 2368b35abe2Sjtc 2378b35abe2Sjtc if ((res == 0) && (sel_chk(arcn) == 0)) { 2388b35abe2Sjtc /* 2398b35abe2Sjtc * pattern resulted in a selected file 2408b35abe2Sjtc */ 2418b35abe2Sjtc if (pat_sel(arcn) < 0) 2428b35abe2Sjtc break; 2438b35abe2Sjtc 2448b35abe2Sjtc /* 2458b35abe2Sjtc * modify the name as requested by the user if name 2468b35abe2Sjtc * survives modification, do a listing of the file 2478b35abe2Sjtc */ 248206f4182Schristos if ((res = mod_name(arcn, RENM)) < 0) 2498b35abe2Sjtc break; 25094eaa317Sjmc if (res == 0) { 25194eaa317Sjmc if (arcn->name[0] == '/' && !check_Aflag()) { 25294eaa317Sjmc memmove(arcn->name, arcn->name + 1, 25394eaa317Sjmc strlen(arcn->name)); 25494eaa317Sjmc } 2550c612021Schristos ls_list(arcn, now, stdout); 25694eaa317Sjmc } 2571faaf9a7Schristos /* 2581faaf9a7Schristos * if there's an error writing to stdout then we must 2591faaf9a7Schristos * stop now -- we're probably writing to a pipe that 2601faaf9a7Schristos * has been closed by the reader. 2611faaf9a7Schristos */ 2621faaf9a7Schristos if (ferror(stdout)) { 2631faaf9a7Schristos syswarn(1, errno, "Listing incomplete."); 2641faaf9a7Schristos break; 2651faaf9a7Schristos } 2668b35abe2Sjtc } 2678b35abe2Sjtc /* 2688b35abe2Sjtc * skip to next archive format header using values calculated 2698b35abe2Sjtc * by the format header read routine 2708b35abe2Sjtc */ 2718b35abe2Sjtc if (rd_skip(arcn->skip + arcn->pad) == 1) 2728b35abe2Sjtc break; 2738b35abe2Sjtc } 2748b35abe2Sjtc 2758b35abe2Sjtc /* 2768b35abe2Sjtc * all done, let format have a chance to cleanup, and make sure that 2778b35abe2Sjtc * the patterns supplied by the user were all matched 2788b35abe2Sjtc */ 2798b35abe2Sjtc (void)(*frmt->end_rd)(); 2809f61b804Splunky (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); 2818b35abe2Sjtc ar_close(); 2828b35abe2Sjtc pat_chk(); 283b419a254Sdsl 284b419a254Sdsl return 0; 2858b35abe2Sjtc } 2868b35abe2Sjtc 2878b35abe2Sjtc /* 2888b35abe2Sjtc * extract() 2898b35abe2Sjtc * extract the member(s) of an archive as specified by user supplied 2908b35abe2Sjtc * pattern(s) (no patterns extracts all members) 2918b35abe2Sjtc */ 2928b35abe2Sjtc 293b419a254Sdsl int 2948b35abe2Sjtc extract(void) 2958b35abe2Sjtc { 29648250187Stls ARCHD *arcn; 29748250187Stls int res; 2988b35abe2Sjtc off_t cnt; 2998b35abe2Sjtc struct stat sb; 3008b35abe2Sjtc int fd; 3010c612021Schristos time_t now; 3028b35abe2Sjtc 3038b35abe2Sjtc arcn = &archd; 3048b35abe2Sjtc /* 3058b35abe2Sjtc * figure out archive type; pass any format specific options to the 3068b35abe2Sjtc * archive option processing routine; call the format init routine; 3078b35abe2Sjtc * start up the directory modification time and access mode database 3088b35abe2Sjtc */ 3098b35abe2Sjtc if ((get_arc() < 0) || ((*frmt->options)() < 0) || 3108b35abe2Sjtc ((*frmt->st_rd)() < 0) || (dir_start() < 0)) 311b419a254Sdsl return 1; 3128b35abe2Sjtc 3139f61b804Splunky now = time(NULL); 31479308267Sjmc #if !HAVE_NBTOOL_CONFIG_H 3150a6f2d38Schristos if (do_chroot) 3160a6f2d38Schristos (void)fdochroot(cwdfd); 31779308267Sjmc #endif 3180c612021Schristos 3198b35abe2Sjtc /* 3208b35abe2Sjtc * When we are doing interactive rename, we store the mapping of names 3218b35abe2Sjtc * so we can fix up hard links files later in the archive. 3228b35abe2Sjtc */ 3238b35abe2Sjtc if (iflag && (name_start() < 0)) 324b419a254Sdsl return 1; 3258b35abe2Sjtc 3268b35abe2Sjtc /* 3278b35abe2Sjtc * step through each entry on the archive until the format read routine 3288b35abe2Sjtc * says it is done 3298b35abe2Sjtc */ 3308b35abe2Sjtc while (next_head(arcn) == 0) { 331ed868bc7Stron int write_to_hard_link = 0; 332ed868bc7Stron 333f70dfaafSchristos if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) { 334f70dfaafSchristos /* 335f70dfaafSchristos * we need to read, to get the real filename 336f70dfaafSchristos */ 33706a1f6e7Schristos if (!(*frmt->rd_data)(arcn, -arcn->type, &cnt)) 338f70dfaafSchristos (void)rd_skip(cnt + arcn->pad); 339f70dfaafSchristos continue; 340f70dfaafSchristos } 3418b35abe2Sjtc 3428b35abe2Sjtc /* 3438b35abe2Sjtc * check for pattern, and user specified options match. When 3448b35abe2Sjtc * all the patterns are matched we are done 3458b35abe2Sjtc */ 3468b35abe2Sjtc if ((res = pat_match(arcn)) < 0) 3478b35abe2Sjtc break; 3488b35abe2Sjtc 3498b35abe2Sjtc if ((res > 0) || (sel_chk(arcn) != 0)) { 3508b35abe2Sjtc /* 35178e294d1Smrg * file is not selected. skip past any file 35278e294d1Smrg * data and padding and go back for the next 35378e294d1Smrg * archive member 3548b35abe2Sjtc */ 3558b35abe2Sjtc (void)rd_skip(arcn->skip + arcn->pad); 3568b35abe2Sjtc continue; 3578b35abe2Sjtc } 3588b35abe2Sjtc 359c952ef6bSchristos if (kflag && (lstat(arcn->name, &sb) == 0)) { 360c952ef6bSchristos (void)rd_skip(arcn->skip + arcn->pad); 361c952ef6bSchristos continue; 362c952ef6bSchristos } 363c952ef6bSchristos 3648b35abe2Sjtc /* 3658b35abe2Sjtc * with -u or -D only extract when the archive member is newer 3663ac7ce18Swiz * than the file with the same name in the file system (no 3678b35abe2Sjtc * test of being the same type is required). 3688b35abe2Sjtc * NOTE: this test is done BEFORE name modifications as 3698b35abe2Sjtc * specified by pax. this operation can be confusing to the 3708b35abe2Sjtc * user who might expect the test to be done on an existing 3718b35abe2Sjtc * file AFTER the name mod. In honesty the pax spec is probably 37278e294d1Smrg * flawed in this respect. ignore this for GNU long links. 3738b35abe2Sjtc */ 374f70dfaafSchristos if ((uflag || Dflag) && ((lstat(arcn->name, &sb) == 0))) { 3758b35abe2Sjtc if (uflag && Dflag) { 3768b35abe2Sjtc if ((arcn->sb.st_mtime <= sb.st_mtime) && 3778b35abe2Sjtc (arcn->sb.st_ctime <= sb.st_ctime)) { 3788b35abe2Sjtc (void)rd_skip(arcn->skip + arcn->pad); 3798b35abe2Sjtc continue; 3808b35abe2Sjtc } 3818b35abe2Sjtc } else if (Dflag) { 3828b35abe2Sjtc if (arcn->sb.st_ctime <= sb.st_ctime) { 3838b35abe2Sjtc (void)rd_skip(arcn->skip + arcn->pad); 3848b35abe2Sjtc continue; 3858b35abe2Sjtc } 3868b35abe2Sjtc } else if (arcn->sb.st_mtime <= sb.st_mtime) { 3878b35abe2Sjtc (void)rd_skip(arcn->skip + arcn->pad); 3888b35abe2Sjtc continue; 3898b35abe2Sjtc } 3908b35abe2Sjtc } 3918b35abe2Sjtc 3928b35abe2Sjtc /* 3938b35abe2Sjtc * this archive member is now been selected. modify the name. 3948b35abe2Sjtc */ 395206f4182Schristos if ((pat_sel(arcn) < 0) || ((res = mod_name(arcn, RENM)) < 0)) 3968b35abe2Sjtc break; 3978b35abe2Sjtc if (res > 0) { 3988b35abe2Sjtc /* 3998b35abe2Sjtc * a bad name mod, skip and purge name from link table 4008b35abe2Sjtc */ 4018b35abe2Sjtc purg_lnk(arcn); 4028b35abe2Sjtc (void)rd_skip(arcn->skip + arcn->pad); 4038b35abe2Sjtc continue; 4048b35abe2Sjtc } 4058b35abe2Sjtc 40694eaa317Sjmc if (arcn->name[0] == '/' && !check_Aflag()) { 40794eaa317Sjmc memmove(arcn->name, arcn->name + 1, strlen(arcn->name)); 40894eaa317Sjmc } 4098b35abe2Sjtc /* 410f8adf56dSitohy * Non standard -Y and -Z flag. When the existing file is 41178e294d1Smrg * same age or newer skip; ignore this for GNU long links. 4128b35abe2Sjtc */ 413f70dfaafSchristos if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) { 4148b35abe2Sjtc if (Yflag && Zflag) { 4158b35abe2Sjtc if ((arcn->sb.st_mtime <= sb.st_mtime) && 4168b35abe2Sjtc (arcn->sb.st_ctime <= sb.st_ctime)) { 4178b35abe2Sjtc (void)rd_skip(arcn->skip + arcn->pad); 4188b35abe2Sjtc continue; 4198b35abe2Sjtc } 4208b35abe2Sjtc } else if (Yflag) { 4218b35abe2Sjtc if (arcn->sb.st_ctime <= sb.st_ctime) { 4228b35abe2Sjtc (void)rd_skip(arcn->skip + arcn->pad); 4238b35abe2Sjtc continue; 4248b35abe2Sjtc } 4258b35abe2Sjtc } else if (arcn->sb.st_mtime <= sb.st_mtime) { 4268b35abe2Sjtc (void)rd_skip(arcn->skip + arcn->pad); 4278b35abe2Sjtc continue; 4288b35abe2Sjtc } 4298b35abe2Sjtc } 4308b35abe2Sjtc 4318b35abe2Sjtc if (vflag) { 4320c612021Schristos if (vflag > 1) 4330c612021Schristos ls_list(arcn, now, listf); 4340c612021Schristos else { 4350c612021Schristos (void)safe_print(arcn->name, listf); 4368b35abe2Sjtc vfpart = 1; 4378b35abe2Sjtc } 4380c612021Schristos } 4398b35abe2Sjtc 4408b35abe2Sjtc /* 4410c612021Schristos * if required, chdir around. 4420c612021Schristos */ 4431301238aSsimonb if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL) && 4441301238aSsimonb !to_stdout) 44515ea30ebSchristos dochdir(arcn->pat->chdname); 44615ea30ebSchristos 44714f615efSchristos if (secure && path_check(arcn, 0) != 0) { 44815ea30ebSchristos (void)rd_skip(arcn->skip + arcn->pad); 44915ea30ebSchristos continue; 45015ea30ebSchristos } 45115ea30ebSchristos 4520c612021Schristos /* 4538b35abe2Sjtc * all ok, extract this member based on type 4548b35abe2Sjtc */ 455f70dfaafSchristos if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) { 4568b35abe2Sjtc /* 4578b35abe2Sjtc * process archive members that are not regular files. 4588b35abe2Sjtc * throw out padding and any data that might follow the 4598b35abe2Sjtc * header (as determined by the format). 4608b35abe2Sjtc */ 461ed868bc7Stron if ((arcn->type == PAX_HLK) || 462ed868bc7Stron (arcn->type == PAX_HRG)) 463ed868bc7Stron res = lnk_creat(arcn, &write_to_hard_link); 4648b35abe2Sjtc else 4658b35abe2Sjtc res = node_creat(arcn); 4668b35abe2Sjtc 467ed868bc7Stron if (!write_to_hard_link) { 4688b35abe2Sjtc (void)rd_skip(arcn->skip + arcn->pad); 4698b35abe2Sjtc if (res < 0) 4708b35abe2Sjtc purg_lnk(arcn); 4718b35abe2Sjtc 4728b35abe2Sjtc if (vflag && vfpart) { 4730c612021Schristos (void)putc('\n', listf); 4748b35abe2Sjtc vfpart = 0; 4758b35abe2Sjtc } 4768b35abe2Sjtc continue; 4778b35abe2Sjtc } 478ed868bc7Stron } 4791301238aSsimonb if (to_stdout) 4801301238aSsimonb fd = STDOUT_FILENO; 4811301238aSsimonb else { 4828b35abe2Sjtc /* 4831301238aSsimonb * We have a file with data here. If we cannot create 4841301238aSsimonb * it, skip over the data and purge the name from hard 4851301238aSsimonb * link table. 4868b35abe2Sjtc */ 487ed868bc7Stron if ((fd = file_creat(arcn, write_to_hard_link)) < 0) { 488d1391f9fSgrant (void)fflush(listf); 4898b35abe2Sjtc (void)rd_skip(arcn->skip + arcn->pad); 4908b35abe2Sjtc purg_lnk(arcn); 4918b35abe2Sjtc continue; 4928b35abe2Sjtc } 4931301238aSsimonb } 4948b35abe2Sjtc /* 4958b35abe2Sjtc * extract the file from the archive and skip over padding and 4968b35abe2Sjtc * any unprocessed data 4978b35abe2Sjtc */ 4988b35abe2Sjtc res = (*frmt->rd_data)(arcn, fd, &cnt); 4991301238aSsimonb if (!to_stdout) 5008b35abe2Sjtc file_close(arcn, fd); 5018b35abe2Sjtc if (vflag && vfpart) { 5020c612021Schristos (void)putc('\n', listf); 5038b35abe2Sjtc vfpart = 0; 5048b35abe2Sjtc } 5058b35abe2Sjtc if (!res) 5068b35abe2Sjtc (void)rd_skip(cnt + arcn->pad); 5070c612021Schristos 5080c612021Schristos /* 5090c612021Schristos * if required, chdir around. 5100c612021Schristos */ 5110c612021Schristos if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL)) 51215ea30ebSchristos fdochdir(cwdfd); 5138b35abe2Sjtc } 5148b35abe2Sjtc 5158b35abe2Sjtc /* 5168b35abe2Sjtc * all done, restore directory modes and times as required; make sure 5178b35abe2Sjtc * all patterns supplied by the user were matched; block off signals 5188b35abe2Sjtc * to avoid chance for multiple entry into the cleanup code. 5198b35abe2Sjtc */ 5208b35abe2Sjtc (void)(*frmt->end_rd)(); 5219f61b804Splunky (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); 5228b35abe2Sjtc ar_close(); 5238b35abe2Sjtc proc_dir(); 5248b35abe2Sjtc pat_chk(); 525b419a254Sdsl 526b419a254Sdsl return 0; 5278b35abe2Sjtc } 5288b35abe2Sjtc 5298b35abe2Sjtc /* 5308b35abe2Sjtc * wr_archive() 5318b35abe2Sjtc * Write an archive. used in both creating a new archive and appends on 5328b35abe2Sjtc * previously written archive. 5338b35abe2Sjtc */ 5348b35abe2Sjtc 535b419a254Sdsl static int 53648250187Stls wr_archive(ARCHD *arcn, int is_app) 5378b35abe2Sjtc { 53848250187Stls int res; 53948250187Stls int hlk; 54048250187Stls int wr_one; 5418b35abe2Sjtc off_t cnt; 542c1bd745cSlukem int (*wrf)(ARCHD *); 5438b35abe2Sjtc int fd = -1; 5440c612021Schristos time_t now; 5458b35abe2Sjtc 5468b35abe2Sjtc /* 5478b35abe2Sjtc * if this format supports hard link storage, start up the database 5488b35abe2Sjtc * that detects them. 5498b35abe2Sjtc */ 5508b35abe2Sjtc if (((hlk = frmt->hlk) == 1) && (lnk_start() < 0)) 551b419a254Sdsl return 1; 5528b35abe2Sjtc 5538b35abe2Sjtc /* 5548b35abe2Sjtc * start up the file traversal code and format specific write 5558b35abe2Sjtc */ 5568b35abe2Sjtc if ((ftree_start() < 0) || ((*frmt->st_wr)() < 0)) 557b419a254Sdsl return 1; 5588b35abe2Sjtc wrf = frmt->wr; 5598b35abe2Sjtc 5609f61b804Splunky now = time(NULL); 5610c612021Schristos 5628b35abe2Sjtc /* 5638b35abe2Sjtc * When we are doing interactive rename, we store the mapping of names 5648b35abe2Sjtc * so we can fix up hard links files later in the archive. 5658b35abe2Sjtc */ 5668b35abe2Sjtc if (iflag && (name_start() < 0)) 567b419a254Sdsl return 1; 5688b35abe2Sjtc 5698b35abe2Sjtc /* 5703ac7ce18Swiz * if this is not append, and there are no files, we do no write a trailer 5718b35abe2Sjtc */ 5728b35abe2Sjtc wr_one = is_app; 5738b35abe2Sjtc 5748b35abe2Sjtc /* 5758b35abe2Sjtc * while there are files to archive, process them one at at time 5768b35abe2Sjtc */ 5778b35abe2Sjtc while (next_file(arcn) == 0) { 5788b35abe2Sjtc /* 5798b35abe2Sjtc * check if this file meets user specified options match. 5808b35abe2Sjtc */ 5818b35abe2Sjtc if (sel_chk(arcn) != 0) 5828b35abe2Sjtc continue; 583206f4182Schristos /* 584206f4182Schristos * Here we handle the exclusion -X gnu style patterns which 585206f4182Schristos * are implemented like a pattern list. We don't modify the 586206f4182Schristos * name as this will be done below again, and we don't want 587206f4182Schristos * to double modify it. 588206f4182Schristos */ 589206f4182Schristos if ((res = mod_name(arcn, 0)) < 0) 590d9cd7080Schristos break; 591d9cd7080Schristos if (res == 1) 592d9cd7080Schristos continue; 5938b35abe2Sjtc fd = -1; 5948b35abe2Sjtc if (uflag) { 5958b35abe2Sjtc /* 5968b35abe2Sjtc * only archive if this file is newer than a file with 5978b35abe2Sjtc * the same name that is already stored on the archive 5988b35abe2Sjtc */ 5998b35abe2Sjtc if ((res = chk_ftime(arcn)) < 0) 6008b35abe2Sjtc break; 6018b35abe2Sjtc if (res > 0) 6028b35abe2Sjtc continue; 6038b35abe2Sjtc } 6048b35abe2Sjtc 6058b35abe2Sjtc /* 6068b35abe2Sjtc * this file is considered selected now. see if this is a hard 6078b35abe2Sjtc * link to a file already stored 6088b35abe2Sjtc */ 6098b35abe2Sjtc ftree_sel(arcn); 6108b35abe2Sjtc if (hlk && (chk_lnk(arcn) < 0)) 6118b35abe2Sjtc break; 6128b35abe2Sjtc 6138b35abe2Sjtc if ((arcn->type == PAX_REG) || (arcn->type == PAX_HRG) || 6148b35abe2Sjtc (arcn->type == PAX_CTG)) { 6158b35abe2Sjtc /* 6168b35abe2Sjtc * we will have to read this file. by opening it now we 6178b35abe2Sjtc * can avoid writing a header to the archive for a file 6188b35abe2Sjtc * we were later unable to read (we also purge it from 6198b35abe2Sjtc * the link table). 6208b35abe2Sjtc */ 6218b35abe2Sjtc if ((fd = open(arcn->org_name, O_RDONLY, 0)) < 0) { 6228b35abe2Sjtc syswarn(1, errno, "Unable to open %s to read", 6238b35abe2Sjtc arcn->org_name); 6248b35abe2Sjtc purg_lnk(arcn); 6258b35abe2Sjtc continue; 6268b35abe2Sjtc } 6278b35abe2Sjtc } 6288b35abe2Sjtc 6298b35abe2Sjtc /* 6308b35abe2Sjtc * Now modify the name as requested by the user 6318b35abe2Sjtc */ 632206f4182Schristos if ((res = mod_name(arcn, RENM)) < 0) { 6338b35abe2Sjtc /* 6348b35abe2Sjtc * name modification says to skip this file, close the 6358b35abe2Sjtc * file and purge link table entry 6368b35abe2Sjtc */ 6378b35abe2Sjtc rdfile_close(arcn, &fd); 6388b35abe2Sjtc purg_lnk(arcn); 6398b35abe2Sjtc break; 6408b35abe2Sjtc } 6418b35abe2Sjtc 64294eaa317Sjmc if (arcn->name[0] == '/' && !check_Aflag()) { 64394eaa317Sjmc memmove(arcn->name, arcn->name + 1, strlen(arcn->name)); 64494eaa317Sjmc } 64594eaa317Sjmc 6468b35abe2Sjtc if ((res > 0) || (docrc && (set_crc(arcn, fd) < 0))) { 6478b35abe2Sjtc /* 6488b35abe2Sjtc * unable to obtain the crc we need, close the file, 6498b35abe2Sjtc * purge link table entry 6508b35abe2Sjtc */ 6518b35abe2Sjtc rdfile_close(arcn, &fd); 6528b35abe2Sjtc purg_lnk(arcn); 6538b35abe2Sjtc continue; 6548b35abe2Sjtc } 6558b35abe2Sjtc 6568b35abe2Sjtc if (vflag) { 6570c612021Schristos if (vflag > 1) 6580c612021Schristos ls_list(arcn, now, listf); 6590c612021Schristos else { 6600c612021Schristos (void)safe_print(arcn->name, listf); 6618b35abe2Sjtc vfpart = 1; 6628b35abe2Sjtc } 6630c612021Schristos } 6648b35abe2Sjtc ++flcnt; 6658b35abe2Sjtc 6668b35abe2Sjtc /* 6678b35abe2Sjtc * looks safe to store the file, have the format specific 6688b35abe2Sjtc * routine write routine store the file header on the archive 6698b35abe2Sjtc */ 6708b35abe2Sjtc if ((res = (*wrf)(arcn)) < 0) { 6718b35abe2Sjtc rdfile_close(arcn, &fd); 6728b35abe2Sjtc break; 6738b35abe2Sjtc } 6748b35abe2Sjtc wr_one = 1; 6758b35abe2Sjtc if (res > 0) { 6768b35abe2Sjtc /* 6778b35abe2Sjtc * format write says no file data needs to be stored 6788b35abe2Sjtc * so we are done messing with this file 6798b35abe2Sjtc */ 6808b35abe2Sjtc if (vflag && vfpart) { 6810c612021Schristos (void)putc('\n', listf); 6828b35abe2Sjtc vfpart = 0; 6838b35abe2Sjtc } 6848b35abe2Sjtc rdfile_close(arcn, &fd); 6858b35abe2Sjtc continue; 6868b35abe2Sjtc } 6878b35abe2Sjtc 6888b35abe2Sjtc /* 6898b35abe2Sjtc * Add file data to the archive, quit on write error. if we 6908b35abe2Sjtc * cannot write the entire file contents to the archive we 6918b35abe2Sjtc * must pad the archive to replace the missing file data 6928b35abe2Sjtc * (otherwise during an extract the file header for the file 6938b35abe2Sjtc * which FOLLOWS this one will not be where we expect it to 6948b35abe2Sjtc * be). 6958b35abe2Sjtc */ 6968b35abe2Sjtc res = (*frmt->wr_data)(arcn, fd, &cnt); 6978b35abe2Sjtc rdfile_close(arcn, &fd); 6988b35abe2Sjtc if (vflag && vfpart) { 6990c612021Schristos (void)putc('\n', listf); 7008b35abe2Sjtc vfpart = 0; 7018b35abe2Sjtc } 7028b35abe2Sjtc if (res < 0) 7038b35abe2Sjtc break; 7048b35abe2Sjtc 7058b35abe2Sjtc /* 7068b35abe2Sjtc * pad as required, cnt is number of bytes not written 7078b35abe2Sjtc */ 7088b35abe2Sjtc if (((cnt > 0) && (wr_skip(cnt) < 0)) || 7098b35abe2Sjtc ((arcn->pad > 0) && (wr_skip(arcn->pad) < 0))) 7108b35abe2Sjtc break; 7118b35abe2Sjtc } 7128b35abe2Sjtc 7138b35abe2Sjtc /* 714f8adf56dSitohy * tell format to write trailer; pad to block boundary; reset directory 7158b35abe2Sjtc * mode/access times, and check if all patterns supplied by the user 7168b35abe2Sjtc * were matched. block off signals to avoid chance for multiple entry 7178b35abe2Sjtc * into the cleanup code 7188b35abe2Sjtc */ 7198b35abe2Sjtc if (wr_one) { 7208b35abe2Sjtc (*frmt->end_wr)(); 7218b35abe2Sjtc wr_fin(); 7228b35abe2Sjtc } 7239f61b804Splunky (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); 7248b35abe2Sjtc ar_close(); 7258b35abe2Sjtc if (tflag) 7268b35abe2Sjtc proc_dir(); 7278b35abe2Sjtc ftree_chk(); 728b419a254Sdsl 729b419a254Sdsl return 0; 7308b35abe2Sjtc } 7318b35abe2Sjtc 7328b35abe2Sjtc /* 7338b35abe2Sjtc * append() 7348b35abe2Sjtc * Add file to previously written archive. Archive format specified by the 7358b35abe2Sjtc * user must agree with archive. The archive is read first to collect 7368b35abe2Sjtc * modification times (if -u) and locate the archive trailer. The archive 7378b35abe2Sjtc * is positioned in front of the record with the trailer and wr_archive() 7388b35abe2Sjtc * is called to add the new members. 7398b35abe2Sjtc * PAX IMPLEMENTATION DETAIL NOTE: 7408b35abe2Sjtc * -u is implemented by adding the new members to the end of the archive. 7418b35abe2Sjtc * Care is taken so that these do not end up as links to the older 7428b35abe2Sjtc * version of the same file already stored in the archive. It is expected 7438b35abe2Sjtc * when extraction occurs these newer versions will over-write the older 7448b35abe2Sjtc * ones stored "earlier" in the archive (this may be a bad assumption as 7458b35abe2Sjtc * it depends on the implementation of the program doing the extraction). 7468b35abe2Sjtc * It is really difficult to splice in members without either re-writing 7478b35abe2Sjtc * the entire archive (from the point were the old version was), or having 7488b35abe2Sjtc * assistance of the format specification in terms of a special update 7498b35abe2Sjtc * header that invalidates a previous archive record. The posix spec left 7508b35abe2Sjtc * the method used to implement -u unspecified. This pax is able to 7518b35abe2Sjtc * over write existing files that it creates. 7528b35abe2Sjtc */ 7538b35abe2Sjtc 754b419a254Sdsl int 7558b35abe2Sjtc append(void) 7568b35abe2Sjtc { 75748250187Stls ARCHD *arcn; 75848250187Stls int res; 7598b35abe2Sjtc FSUB *orgfrmt; 7608b35abe2Sjtc int udev; 7618b35abe2Sjtc off_t tlen; 7628b35abe2Sjtc 7638b35abe2Sjtc arcn = &archd; 7648b35abe2Sjtc orgfrmt = frmt; 7658b35abe2Sjtc 7668b35abe2Sjtc /* 7678b35abe2Sjtc * Do not allow an append operation if the actual archive is of a 768f8adf56dSitohy * different format than the user specified format. 7698b35abe2Sjtc */ 7708b35abe2Sjtc if (get_arc() < 0) 771b419a254Sdsl return 1; 7728b35abe2Sjtc if ((orgfrmt != NULL) && (orgfrmt != frmt)) { 773f3cd6022Schristos tty_warn(1, "Cannot mix current archive format %s with %s", 7748b35abe2Sjtc frmt->name, orgfrmt->name); 775b419a254Sdsl return 1; 7768b35abe2Sjtc } 7778b35abe2Sjtc 7788b35abe2Sjtc /* 7798b35abe2Sjtc * pass the format any options and start up format 7808b35abe2Sjtc */ 7818b35abe2Sjtc if (((*frmt->options)() < 0) || ((*frmt->st_rd)() < 0)) 782b419a254Sdsl return 1; 7838b35abe2Sjtc 7848b35abe2Sjtc /* 7858b35abe2Sjtc * if we only are adding members that are newer, we need to save the 7868b35abe2Sjtc * mod times for all files we see. 7878b35abe2Sjtc */ 7888b35abe2Sjtc if (uflag && (ftime_start() < 0)) 789b419a254Sdsl return 1; 7908b35abe2Sjtc 7918b35abe2Sjtc /* 7928b35abe2Sjtc * some archive formats encode hard links by recording the device and 7938b35abe2Sjtc * file serial number (inode) but copy the file anyway (multiple times) 7948b35abe2Sjtc * to the archive. When we append, we run the risk that newly added 7958b35abe2Sjtc * files may have the same device and inode numbers as those recorded 7968b35abe2Sjtc * on the archive but during a previous run. If this happens, when the 7978b35abe2Sjtc * archive is extracted we get INCORRECT hard links. We avoid this by 7988b35abe2Sjtc * remapping the device numbers so that newly added files will never 7998b35abe2Sjtc * use the same device number as one found on the archive. remapping 8008b35abe2Sjtc * allows new members to safely have links among themselves. remapping 8018b35abe2Sjtc * also avoids problems with file inode (serial number) truncations 8028b35abe2Sjtc * when the inode number is larger than storage space in the archive 8038b35abe2Sjtc * header. See the remap routines for more details. 8048b35abe2Sjtc */ 8058b35abe2Sjtc if ((udev = frmt->udev) && (dev_start() < 0)) 806b419a254Sdsl return 1; 8078b35abe2Sjtc 8088b35abe2Sjtc /* 8098b35abe2Sjtc * reading the archive may take a long time. If verbose tell the user 8108b35abe2Sjtc */ 811702d1ca5Schristos if (vflag || Vflag) { 8120c612021Schristos (void)fprintf(listf, 8138b35abe2Sjtc "%s: Reading archive to position at the end...", argv0); 8148b35abe2Sjtc vfpart = 1; 8158b35abe2Sjtc } 8168b35abe2Sjtc 8178b35abe2Sjtc /* 8188b35abe2Sjtc * step through the archive until the format says it is done 8198b35abe2Sjtc */ 8208b35abe2Sjtc while (next_head(arcn) == 0) { 8218b35abe2Sjtc /* 8228b35abe2Sjtc * check if this file meets user specified options. 8238b35abe2Sjtc */ 8248b35abe2Sjtc if (sel_chk(arcn) != 0) { 8258b35abe2Sjtc if (rd_skip(arcn->skip + arcn->pad) == 1) 8268b35abe2Sjtc break; 8278b35abe2Sjtc continue; 8288b35abe2Sjtc } 8298b35abe2Sjtc 8308b35abe2Sjtc if (uflag) { 8318b35abe2Sjtc /* 8328b35abe2Sjtc * see if this is the newest version of this file has 8338b35abe2Sjtc * already been seen, if so skip. 8348b35abe2Sjtc */ 8358b35abe2Sjtc if ((res = chk_ftime(arcn)) < 0) 8368b35abe2Sjtc break; 8378b35abe2Sjtc if (res > 0) { 8388b35abe2Sjtc if (rd_skip(arcn->skip + arcn->pad) == 1) 8398b35abe2Sjtc break; 8408b35abe2Sjtc continue; 8418b35abe2Sjtc } 8428b35abe2Sjtc } 8438b35abe2Sjtc 8448b35abe2Sjtc /* 8458b35abe2Sjtc * Store this device number. Device numbers seen during the 8468b35abe2Sjtc * read phase of append will cause newly appended files with a 8478b35abe2Sjtc * device number seen in the old part of the archive to be 8488b35abe2Sjtc * remapped to an unused device number. 8498b35abe2Sjtc */ 8508b35abe2Sjtc if ((udev && (add_dev(arcn) < 0)) || 8518b35abe2Sjtc (rd_skip(arcn->skip + arcn->pad) == 1)) 8528b35abe2Sjtc break; 8538b35abe2Sjtc } 8548b35abe2Sjtc 8558b35abe2Sjtc /* 8568b35abe2Sjtc * done, finish up read and get the number of bytes to back up so we 8578b35abe2Sjtc * can add new members. The format might have used the hard link table, 8588b35abe2Sjtc * purge it. 8598b35abe2Sjtc */ 8608b35abe2Sjtc tlen = (*frmt->end_rd)(); 8618b35abe2Sjtc lnk_end(); 8628b35abe2Sjtc 8638b35abe2Sjtc /* 864f8adf56dSitohy * try to position for write, if this fails quit. if any error occurs, 8658b35abe2Sjtc * we will refuse to write 8668b35abe2Sjtc */ 8678b35abe2Sjtc if (appnd_start(tlen) < 0) 868b419a254Sdsl return 1; 8698b35abe2Sjtc 8708b35abe2Sjtc /* 8718b35abe2Sjtc * tell the user we are done reading. 8728b35abe2Sjtc */ 873702d1ca5Schristos if ((vflag || Vflag) && vfpart) { 8740c612021Schristos (void)safe_print("done.\n", listf); 8758b35abe2Sjtc vfpart = 0; 8768b35abe2Sjtc } 8778b35abe2Sjtc 8788b35abe2Sjtc /* 8798b35abe2Sjtc * go to the writing phase to add the new members 8808b35abe2Sjtc */ 881ed23b39fSelad res = wr_archive(arcn, 1); 882ed23b39fSelad if (res == 1) { 883ed23b39fSelad /* 884ed23b39fSelad * wr_archive failed in some way, but before any files were 885ed23b39fSelad * added. These are the only steps needed to cleanup (and 886ed23b39fSelad * not truncate the archive). 887ed23b39fSelad */ 888ed23b39fSelad wr_fin(); 8899f61b804Splunky (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); 890ed23b39fSelad ar_close(); 891ed23b39fSelad } 892ed23b39fSelad return res; 8938b35abe2Sjtc } 8948b35abe2Sjtc 8958b35abe2Sjtc /* 8968b35abe2Sjtc * archive() 8978b35abe2Sjtc * write a new archive 8988b35abe2Sjtc */ 8998b35abe2Sjtc 900b419a254Sdsl int 9018b35abe2Sjtc archive(void) 9028b35abe2Sjtc { 9038b35abe2Sjtc 9048b35abe2Sjtc /* 9058b35abe2Sjtc * if we only are adding members that are newer, we need to save the 9068b35abe2Sjtc * mod times for all files; set up for writing; pass the format any 9078b35abe2Sjtc * options write the archive 9088b35abe2Sjtc */ 9098b35abe2Sjtc if ((uflag && (ftime_start() < 0)) || (wr_start() < 0)) 910b419a254Sdsl return 1; 9118b35abe2Sjtc if ((*frmt->options)() < 0) 912b419a254Sdsl return 1; 9138b35abe2Sjtc 914b419a254Sdsl return wr_archive(&archd, 0); 9158b35abe2Sjtc } 9168b35abe2Sjtc 9178b35abe2Sjtc /* 9188b35abe2Sjtc * copy() 9198b35abe2Sjtc * copy files from one part of the file system to another. this does not 9208b35abe2Sjtc * use any archive storage. The EFFECT OF THE COPY IS THE SAME as if an 9218b35abe2Sjtc * archive was written and then extracted in the destination directory 9228b35abe2Sjtc * (except the files are forced to be under the destination directory). 9238b35abe2Sjtc */ 9248b35abe2Sjtc 925b419a254Sdsl int 9268b35abe2Sjtc copy(void) 9278b35abe2Sjtc { 92848250187Stls ARCHD *arcn; 92948250187Stls int res; 93048250187Stls int fddest; 93148250187Stls char *dest_pt; 932990d25a9Slukem size_t dlen; 933990d25a9Slukem size_t drem; 9348b35abe2Sjtc int fdsrc = -1; 9358b35abe2Sjtc struct stat sb; 9368b35abe2Sjtc char dirbuf[PAXPATHLEN+1]; 9378b35abe2Sjtc 9388b35abe2Sjtc arcn = &archd; 9398b35abe2Sjtc /* 9408b35abe2Sjtc * set up the destination dir path and make sure it is a directory. We 9418b35abe2Sjtc * make sure we have a trailing / on the destination 9428b35abe2Sjtc */ 9430c612021Schristos dlen = strlcpy(dirbuf, dirptr, sizeof(dirbuf)); 9440c612021Schristos if (dlen >= sizeof(dirbuf) || 9450c612021Schristos (dlen == sizeof(dirbuf) - 1 && dirbuf[dlen - 1] != '/')) { 9460c612021Schristos tty_warn(1, "directory name is too long %s", dirptr); 947b419a254Sdsl return 1; 9480c612021Schristos } 9498b35abe2Sjtc dest_pt = dirbuf + dlen; 9508b35abe2Sjtc if (*(dest_pt-1) != '/') { 9518b35abe2Sjtc *dest_pt++ = '/'; 9528b35abe2Sjtc ++dlen; 9538b35abe2Sjtc } 9548b35abe2Sjtc *dest_pt = '\0'; 9558b35abe2Sjtc drem = PAXPATHLEN - dlen; 9568b35abe2Sjtc 9578b35abe2Sjtc if (stat(dirptr, &sb) < 0) { 9588b35abe2Sjtc syswarn(1, errno, "Cannot access destination directory %s", 9598b35abe2Sjtc dirptr); 960b419a254Sdsl return 1; 9618b35abe2Sjtc } 9628b35abe2Sjtc if (!S_ISDIR(sb.st_mode)) { 963f3cd6022Schristos tty_warn(1, "Destination is not a directory %s", dirptr); 964b419a254Sdsl return 1; 9658b35abe2Sjtc } 9668b35abe2Sjtc 9678b35abe2Sjtc /* 9688b35abe2Sjtc * start up the hard link table; file traversal routines and the 9698b35abe2Sjtc * modification time and access mode database 9708b35abe2Sjtc */ 9718b35abe2Sjtc if ((lnk_start() < 0) || (ftree_start() < 0) || (dir_start() < 0)) 972b419a254Sdsl return 1; 9738b35abe2Sjtc 9748b35abe2Sjtc /* 9758b35abe2Sjtc * When we are doing interactive rename, we store the mapping of names 9768b35abe2Sjtc * so we can fix up hard links files later in the archive. 9778b35abe2Sjtc */ 9788b35abe2Sjtc if (iflag && (name_start() < 0)) 979b419a254Sdsl return 1; 9808b35abe2Sjtc 9818b35abe2Sjtc /* 9828b35abe2Sjtc * set up to cp file trees 9838b35abe2Sjtc */ 9848b35abe2Sjtc cp_start(); 9858b35abe2Sjtc 9868b35abe2Sjtc /* 9878b35abe2Sjtc * while there are files to archive, process them 9888b35abe2Sjtc */ 9898b35abe2Sjtc while (next_file(arcn) == 0) { 9908b35abe2Sjtc fdsrc = -1; 9918b35abe2Sjtc 9928b35abe2Sjtc /* 9938b35abe2Sjtc * check if this file meets user specified options 9948b35abe2Sjtc */ 9958b35abe2Sjtc if (sel_chk(arcn) != 0) 9968b35abe2Sjtc continue; 9978b35abe2Sjtc 9988b35abe2Sjtc /* 9998b35abe2Sjtc * if there is already a file in the destination directory with 10008b35abe2Sjtc * the same name and it is newer, skip the one stored on the 10018b35abe2Sjtc * archive. 10028b35abe2Sjtc * NOTE: this test is done BEFORE name modifications as 10038b35abe2Sjtc * specified by pax. this can be confusing to the user who 10048b35abe2Sjtc * might expect the test to be done on an existing file AFTER 10058b35abe2Sjtc * the name mod. In honesty the pax spec is probably flawed in 10068b35abe2Sjtc * this respect 10078b35abe2Sjtc */ 10088b35abe2Sjtc if (uflag || Dflag) { 10098b35abe2Sjtc /* 10108b35abe2Sjtc * create the destination name 10118b35abe2Sjtc */ 10120c612021Schristos if (strlcpy(dest_pt, arcn->name + (*arcn->name == '/'), 10130c612021Schristos drem + 1) > drem) { 1014f3cd6022Schristos tty_warn(1, "Destination pathname too long %s", 10158b35abe2Sjtc arcn->name); 10168b35abe2Sjtc continue; 10178b35abe2Sjtc } 10188b35abe2Sjtc 10198b35abe2Sjtc /* 10208b35abe2Sjtc * if existing file is same age or newer skip 10218b35abe2Sjtc */ 10228b35abe2Sjtc res = lstat(dirbuf, &sb); 10238b35abe2Sjtc *dest_pt = '\0'; 10248b35abe2Sjtc 10258b35abe2Sjtc if (res == 0) { 10268b35abe2Sjtc if (uflag && Dflag) { 10278b35abe2Sjtc if ((arcn->sb.st_mtime<=sb.st_mtime) && 10288b35abe2Sjtc (arcn->sb.st_ctime<=sb.st_ctime)) 10298b35abe2Sjtc continue; 10308b35abe2Sjtc } else if (Dflag) { 10318b35abe2Sjtc if (arcn->sb.st_ctime <= sb.st_ctime) 10328b35abe2Sjtc continue; 10338b35abe2Sjtc } else if (arcn->sb.st_mtime <= sb.st_mtime) 10348b35abe2Sjtc continue; 10358b35abe2Sjtc } 10368b35abe2Sjtc } 10378b35abe2Sjtc 10388b35abe2Sjtc /* 10398b35abe2Sjtc * this file is considered selected. See if this is a hard link 10408b35abe2Sjtc * to a previous file; modify the name as requested by the 10418b35abe2Sjtc * user; set the final destination. 10428b35abe2Sjtc */ 10438b35abe2Sjtc ftree_sel(arcn); 1044206f4182Schristos if ((chk_lnk(arcn) < 0) || ((res = mod_name(arcn, RENM)) < 0)) 10458b35abe2Sjtc break; 10468b35abe2Sjtc if ((res > 0) || (set_dest(arcn, dirbuf, dlen) < 0)) { 10478b35abe2Sjtc /* 10488b35abe2Sjtc * skip file, purge from link table 10498b35abe2Sjtc */ 10508b35abe2Sjtc purg_lnk(arcn); 10518b35abe2Sjtc continue; 10528b35abe2Sjtc } 10538b35abe2Sjtc 10548b35abe2Sjtc /* 1055344f0d1eSmsaitoh * Non standard -Y and -Z flag. When the existing file is 10568b35abe2Sjtc * same age or newer skip 10578b35abe2Sjtc */ 10588b35abe2Sjtc if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) { 10598b35abe2Sjtc if (Yflag && Zflag) { 10608b35abe2Sjtc if ((arcn->sb.st_mtime <= sb.st_mtime) && 10618b35abe2Sjtc (arcn->sb.st_ctime <= sb.st_ctime)) 10628b35abe2Sjtc continue; 10638b35abe2Sjtc } else if (Yflag) { 10648b35abe2Sjtc if (arcn->sb.st_ctime <= sb.st_ctime) 10658b35abe2Sjtc continue; 10668b35abe2Sjtc } else if (arcn->sb.st_mtime <= sb.st_mtime) 10678b35abe2Sjtc continue; 10688b35abe2Sjtc } 10698b35abe2Sjtc 10708b35abe2Sjtc if (vflag) { 10710c612021Schristos (void)safe_print(arcn->name, listf); 10728b35abe2Sjtc vfpart = 1; 10738b35abe2Sjtc } 10748b35abe2Sjtc ++flcnt; 10758b35abe2Sjtc 10768b35abe2Sjtc /* 10778b35abe2Sjtc * try to create a hard link to the src file if requested 10788b35abe2Sjtc * but make sure we are not trying to overwrite ourselves. 10798b35abe2Sjtc */ 10808b35abe2Sjtc if (lflag) 10818b35abe2Sjtc res = cross_lnk(arcn); 10828b35abe2Sjtc else 10838b35abe2Sjtc res = chk_same(arcn); 10848b35abe2Sjtc if (res <= 0) { 10858b35abe2Sjtc if (vflag && vfpart) { 10860c612021Schristos (void)putc('\n', listf); 10878b35abe2Sjtc vfpart = 0; 10888b35abe2Sjtc } 10898b35abe2Sjtc continue; 10908b35abe2Sjtc } 10918b35abe2Sjtc 10928b35abe2Sjtc /* 10938b35abe2Sjtc * have to create a new file 10948b35abe2Sjtc */ 10958b35abe2Sjtc if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) { 10968b35abe2Sjtc /* 10978b35abe2Sjtc * create a link or special file 10988b35abe2Sjtc */ 1099ed868bc7Stron if ((arcn->type == PAX_HLK) || 1100ed868bc7Stron (arcn->type == PAX_HRG)) { 1101ed868bc7Stron int payload; 1102ed868bc7Stron 1103ed868bc7Stron res = lnk_creat(arcn, &payload); 1104ed868bc7Stron } else { 11058b35abe2Sjtc res = node_creat(arcn); 1106ed868bc7Stron } 11078b35abe2Sjtc if (res < 0) 11088b35abe2Sjtc purg_lnk(arcn); 11098b35abe2Sjtc if (vflag && vfpart) { 11100c612021Schristos (void)putc('\n', listf); 11118b35abe2Sjtc vfpart = 0; 11128b35abe2Sjtc } 11138b35abe2Sjtc continue; 11148b35abe2Sjtc } 11158b35abe2Sjtc 11168b35abe2Sjtc /* 11178b35abe2Sjtc * have to copy a regular file to the destination directory. 11188b35abe2Sjtc * first open source file and then create the destination file 11198b35abe2Sjtc */ 11208b35abe2Sjtc if ((fdsrc = open(arcn->org_name, O_RDONLY, 0)) < 0) { 11218b35abe2Sjtc syswarn(1, errno, "Unable to open %s to read", 11228b35abe2Sjtc arcn->org_name); 11238b35abe2Sjtc purg_lnk(arcn); 11248b35abe2Sjtc continue; 11258b35abe2Sjtc } 1126ed868bc7Stron if ((fddest = file_creat(arcn, 0)) < 0) { 11278b35abe2Sjtc rdfile_close(arcn, &fdsrc); 11288b35abe2Sjtc purg_lnk(arcn); 11298b35abe2Sjtc continue; 11308b35abe2Sjtc } 11318b35abe2Sjtc 11328b35abe2Sjtc /* 1133d2813c52Slukem * copy source file data to the destination file. 1134d2813c52Slukem * if there was a failure, remove the temporary file 1135d2813c52Slukem * and leave any existing destination file unmodified. 11368b35abe2Sjtc */ 1137d2813c52Slukem if (cp_file(arcn, fdsrc, fddest) < 0) 1138d2813c52Slukem file_cleanup(arcn, fddest); 1139d2813c52Slukem else 11408b35abe2Sjtc file_close(arcn, fddest); 11418b35abe2Sjtc rdfile_close(arcn, &fdsrc); 11428b35abe2Sjtc 11438b35abe2Sjtc if (vflag && vfpart) { 11440c612021Schristos (void)putc('\n', listf); 11458b35abe2Sjtc vfpart = 0; 11468b35abe2Sjtc } 11478b35abe2Sjtc } 11488b35abe2Sjtc 11498b35abe2Sjtc /* 11508b35abe2Sjtc * restore directory modes and times as required; make sure all 11518b35abe2Sjtc * patterns were selected block off signals to avoid chance for 11528b35abe2Sjtc * multiple entry into the cleanup code. 11538b35abe2Sjtc */ 11549f61b804Splunky (void)sigprocmask(SIG_BLOCK, &s_mask, NULL); 11558b35abe2Sjtc ar_close(); 11568b35abe2Sjtc proc_dir(); 11578b35abe2Sjtc ftree_chk(); 1158b419a254Sdsl 1159b419a254Sdsl return 0; 11608b35abe2Sjtc } 11618b35abe2Sjtc 11628b35abe2Sjtc /* 11638b35abe2Sjtc * next_head() 11648b35abe2Sjtc * try to find a valid header in the archive. Uses format specific 11658b35abe2Sjtc * routines to extract the header and id the trailer. Trailers may be 11668b35abe2Sjtc * located within a valid header or in an invalid header (the location 11678b35abe2Sjtc * is format specific. The inhead field from the option table tells us 11688b35abe2Sjtc * where to look for the trailer). 11698b35abe2Sjtc * We keep reading (and resyncing) until we get enough contiguous data 11708b35abe2Sjtc * to check for a header. If we cannot find one, we shift by a byte 11718b35abe2Sjtc * add a new byte from the archive to the end of the buffer and try again. 11728b35abe2Sjtc * If we get a read error, we throw out what we have (as we must have 11738b35abe2Sjtc * contiguous data) and start over again. 11748b35abe2Sjtc * ASSUMED: headers fit within a BLKMULT header. 11758b35abe2Sjtc * Return: 11768b35abe2Sjtc * 0 if we got a header, -1 if we are unable to ever find another one 11778b35abe2Sjtc * (we reached the end of input, or we reached the limit on retries. see 11788b35abe2Sjtc * the specs for rd_wrbuf() for more details) 11798b35abe2Sjtc */ 11808b35abe2Sjtc 11818b35abe2Sjtc static int 118248250187Stls next_head(ARCHD *arcn) 11838b35abe2Sjtc { 118448250187Stls int ret; 118548250187Stls char *hdend; 118648250187Stls int res; 118748250187Stls int shftsz; 118848250187Stls int hsz; 118948250187Stls int in_resync = 0; /* set when we are in resync mode */ 11908b35abe2Sjtc int cnt = 0; /* counter for trailer function */ 11910c612021Schristos int first = 1; /* on 1st read, EOF isn't premature. */ 11928b35abe2Sjtc 11938b35abe2Sjtc /* 11948b35abe2Sjtc * set up initial conditions, we want a whole frmt->hsz block as we 11958b35abe2Sjtc * have no data yet. 11968b35abe2Sjtc */ 11978b35abe2Sjtc res = hsz = frmt->hsz; 11988b35abe2Sjtc hdend = hdbuf; 11998b35abe2Sjtc shftsz = hsz - 1; 12008b35abe2Sjtc for(;;) { 12018b35abe2Sjtc /* 12028b35abe2Sjtc * keep looping until we get a contiguous FULL buffer 12038b35abe2Sjtc * (frmt->hsz is the proper size) 12048b35abe2Sjtc */ 12058b35abe2Sjtc for (;;) { 12068b35abe2Sjtc if ((ret = rd_wrbuf(hdend, res)) == res) 12078b35abe2Sjtc break; 12088b35abe2Sjtc 12098b35abe2Sjtc /* 12100c612021Schristos * If we read 0 bytes (EOF) from an archive when we 12110c612021Schristos * expect to find a header, we have stepped upon 12120c612021Schristos * an archive without the customary block of zeroes 12130c612021Schristos * end marker. It's just stupid to error out on 12140c612021Schristos * them, so exit gracefully. 12150c612021Schristos */ 12160c612021Schristos if (first && ret == 0) 1217cdec4ac1Sdsl return -1; 12180c612021Schristos first = 0; 12190c612021Schristos 12200c612021Schristos /* 12218b35abe2Sjtc * some kind of archive read problem, try to resync the 12228b35abe2Sjtc * storage device, better give the user the bad news. 12238b35abe2Sjtc */ 12248b35abe2Sjtc if ((ret == 0) || (rd_sync() < 0)) { 1225f3cd6022Schristos tty_warn(1, 1226f3cd6022Schristos "Premature end of file on archive read"); 1227cdec4ac1Sdsl return -1; 12288b35abe2Sjtc } 12298b35abe2Sjtc if (!in_resync) { 12308b35abe2Sjtc if (act == APPND) { 1231f3cd6022Schristos tty_warn(1, 12328b35abe2Sjtc "Archive I/O error, cannot continue"); 1233cdec4ac1Sdsl return -1; 12348b35abe2Sjtc } 1235f3cd6022Schristos tty_warn(1, 1236f3cd6022Schristos "Archive I/O error. Trying to recover."); 12378b35abe2Sjtc ++in_resync; 12388b35abe2Sjtc } 12398b35abe2Sjtc 12408b35abe2Sjtc /* 12418b35abe2Sjtc * oh well, throw it all out and start over 12428b35abe2Sjtc */ 12438b35abe2Sjtc res = hsz; 12448b35abe2Sjtc hdend = hdbuf; 12458b35abe2Sjtc } 12468b35abe2Sjtc 12478b35abe2Sjtc /* 12488b35abe2Sjtc * ok we have a contiguous buffer of the right size. Call the 12498b35abe2Sjtc * format read routine. If this was not a valid header and this 12508b35abe2Sjtc * format stores trailers outside of the header, call the 12518b35abe2Sjtc * format specific trailer routine to check for a trailer. We 12528b35abe2Sjtc * have to watch out that we do not mis-identify file data or 12538b35abe2Sjtc * block padding as a header or trailer. Format specific 12548b35abe2Sjtc * trailer functions must NOT check for the trailer while we 12558b35abe2Sjtc * are running in resync mode. Some trailer functions may tell 12568b35abe2Sjtc * us that this block cannot contain a valid header either, so 12578b35abe2Sjtc * we then throw out the entire block and start over. 12588b35abe2Sjtc */ 12598b35abe2Sjtc if ((*frmt->rd)(arcn, hdbuf) == 0) 12608b35abe2Sjtc break; 12618b35abe2Sjtc 12628b35abe2Sjtc if (!frmt->inhead) { 12638b35abe2Sjtc /* 12648b35abe2Sjtc * this format has trailers outside of valid headers 12658b35abe2Sjtc */ 12668b35abe2Sjtc if ((ret = (*frmt->trail)(hdbuf,in_resync,&cnt)) == 0){ 12678b35abe2Sjtc /* 12688b35abe2Sjtc * valid trailer found, drain input as required 12698b35abe2Sjtc */ 12708b35abe2Sjtc ar_drain(); 1271cdec4ac1Sdsl return -1; 12728b35abe2Sjtc } 12738b35abe2Sjtc 12748b35abe2Sjtc if (ret == 1) { 12758b35abe2Sjtc /* 12768b35abe2Sjtc * we are in resync and we were told to throw 12778b35abe2Sjtc * the whole block out because none of the 12788b35abe2Sjtc * bytes in this block can be used to form a 12798b35abe2Sjtc * valid header 12808b35abe2Sjtc */ 12818b35abe2Sjtc res = hsz; 12828b35abe2Sjtc hdend = hdbuf; 12838b35abe2Sjtc continue; 12848b35abe2Sjtc } 12858b35abe2Sjtc } 12868b35abe2Sjtc 12878b35abe2Sjtc /* 12888b35abe2Sjtc * Brute force section. 12898b35abe2Sjtc * not a valid header. We may be able to find a header yet. So 12908b35abe2Sjtc * we shift over by one byte, and set up to read one byte at a 12918b35abe2Sjtc * time from the archive and place it at the end of the buffer. 12928b35abe2Sjtc * We will keep moving byte at a time until we find a header or 12938b35abe2Sjtc * get a read error and have to start over. 12948b35abe2Sjtc */ 12958b35abe2Sjtc if (!in_resync) { 12968b35abe2Sjtc if (act == APPND) { 1297f3cd6022Schristos tty_warn(1, 1298f3cd6022Schristos "Unable to append, archive header flaw"); 1299cdec4ac1Sdsl return -1; 13008b35abe2Sjtc } 1301f3cd6022Schristos tty_warn(1, 1302f3cd6022Schristos "Invalid header, starting valid header search."); 13038b35abe2Sjtc ++in_resync; 13048b35abe2Sjtc } 130506f53b68Smycroft memmove(hdbuf, hdbuf+1, shftsz); 13068b35abe2Sjtc res = 1; 13078b35abe2Sjtc hdend = hdbuf + shftsz; 13088b35abe2Sjtc } 13098b35abe2Sjtc 13108b35abe2Sjtc /* 13118b35abe2Sjtc * ok got a valid header, check for trailer if format encodes it in the 13128b35abe2Sjtc * the header. NOTE: the parameters are different than trailer routines 13138b35abe2Sjtc * which encode trailers outside of the header! 13148b35abe2Sjtc */ 1315f3cd6022Schristos if (frmt->inhead && ((*frmt->subtrail)(arcn) == 0)) { 13168b35abe2Sjtc /* 13178b35abe2Sjtc * valid trailer found, drain input as required 13188b35abe2Sjtc */ 13198b35abe2Sjtc ar_drain(); 1320cdec4ac1Sdsl return -1; 13218b35abe2Sjtc } 13228b35abe2Sjtc 13238b35abe2Sjtc ++flcnt; 1324cdec4ac1Sdsl return 0; 13258b35abe2Sjtc } 13268b35abe2Sjtc 13278b35abe2Sjtc /* 13288b35abe2Sjtc * get_arc() 13298b35abe2Sjtc * Figure out what format an archive is. Handles archive with flaws by 13308b35abe2Sjtc * brute force searches for a legal header in any supported format. The 13318b35abe2Sjtc * format id routines have to be careful to NOT mis-identify a format. 13328b35abe2Sjtc * ASSUMED: headers fit within a BLKMULT header. 13338b35abe2Sjtc * Return: 13348b35abe2Sjtc * 0 if archive found -1 otherwise 13358b35abe2Sjtc */ 13368b35abe2Sjtc 13378b35abe2Sjtc static int 13388b35abe2Sjtc get_arc(void) 13398b35abe2Sjtc { 134048250187Stls int i; 134148250187Stls int hdsz = 0; 134248250187Stls int res; 134348250187Stls int minhd = BLKMULT; 13448b35abe2Sjtc char *hdend; 13458b35abe2Sjtc int notice = 0; 13468b35abe2Sjtc 13478b35abe2Sjtc /* 13488b35abe2Sjtc * find the smallest header size in all archive formats and then set up 13498b35abe2Sjtc * to read the archive. 13508b35abe2Sjtc */ 13518b35abe2Sjtc for (i = 0; ford[i] >= 0; ++i) { 13528b35abe2Sjtc if (fsub[ford[i]].hsz < minhd) 13538b35abe2Sjtc minhd = fsub[ford[i]].hsz; 13548b35abe2Sjtc } 13558b35abe2Sjtc if (rd_start() < 0) 1356cdec4ac1Sdsl return -1; 13578b35abe2Sjtc res = BLKMULT; 13588b35abe2Sjtc hdsz = 0; 13598b35abe2Sjtc hdend = hdbuf; 13608b35abe2Sjtc for(;;) { 13618b35abe2Sjtc for (;;) { 13628b35abe2Sjtc /* 13638b35abe2Sjtc * fill the buffer with at least the smallest header 13648b35abe2Sjtc */ 13658b35abe2Sjtc i = rd_wrbuf(hdend, res); 13668b35abe2Sjtc if (i > 0) 13678b35abe2Sjtc hdsz += i; 13688b35abe2Sjtc if (hdsz >= minhd) 13698b35abe2Sjtc break; 13708b35abe2Sjtc 13718b35abe2Sjtc /* 13728b35abe2Sjtc * if we cannot recover from a read error quit 13738b35abe2Sjtc */ 13748b35abe2Sjtc if ((i == 0) || (rd_sync() < 0)) 13758b35abe2Sjtc goto out; 13768b35abe2Sjtc 13778b35abe2Sjtc /* 13788b35abe2Sjtc * when we get an error none of the data we already 13798b35abe2Sjtc * have can be used to create a legal header (we just 13808b35abe2Sjtc * got an error in the middle), so we throw it all out 13818b35abe2Sjtc * and refill the buffer with fresh data. 13828b35abe2Sjtc */ 13838b35abe2Sjtc res = BLKMULT; 13848b35abe2Sjtc hdsz = 0; 13858b35abe2Sjtc hdend = hdbuf; 13868b35abe2Sjtc if (!notice) { 13878b35abe2Sjtc if (act == APPND) 1388cdec4ac1Sdsl return -1; 1389f3cd6022Schristos tty_warn(1, 1390f3cd6022Schristos "Cannot identify format. Searching..."); 13918b35abe2Sjtc ++notice; 13928b35abe2Sjtc } 13938b35abe2Sjtc } 13948b35abe2Sjtc 13958b35abe2Sjtc /* 13968b35abe2Sjtc * we have at least the size of the smallest header in any 13978b35abe2Sjtc * archive format. Look to see if we have a match. The array 13988b35abe2Sjtc * ford[] is used to specify the header id order to reduce the 13998b35abe2Sjtc * chance of incorrectly id'ing a valid header (some formats 14008b35abe2Sjtc * may be subsets of each other and the order would then be 14018b35abe2Sjtc * important). 14028b35abe2Sjtc */ 14038b35abe2Sjtc for (i = 0; ford[i] >= 0; ++i) { 14048b35abe2Sjtc if ((*fsub[ford[i]].id)(hdbuf, hdsz) < 0) 14058b35abe2Sjtc continue; 14068b35abe2Sjtc frmt = &(fsub[ford[i]]); 14078b35abe2Sjtc /* 14088b35abe2Sjtc * yuck, to avoid slow special case code in the extract 14098b35abe2Sjtc * routines, just push this header back as if it was 14108b35abe2Sjtc * not seen. We have left extra space at start of the 14118b35abe2Sjtc * buffer for this purpose. This is a bit ugly, but 14128b35abe2Sjtc * adding all the special case code is far worse. 14138b35abe2Sjtc */ 14148b35abe2Sjtc pback(hdbuf, hdsz); 1415cdec4ac1Sdsl return 0; 14168b35abe2Sjtc } 14178b35abe2Sjtc 14188b35abe2Sjtc /* 14198b35abe2Sjtc * We have a flawed archive, no match. we start searching, but 14208b35abe2Sjtc * we never allow additions to flawed archives 14218b35abe2Sjtc */ 14228b35abe2Sjtc if (!notice) { 14238b35abe2Sjtc if (act == APPND) 1424cdec4ac1Sdsl return -1; 1425f3cd6022Schristos tty_warn(1, "Cannot identify format. Searching..."); 14268b35abe2Sjtc ++notice; 14278b35abe2Sjtc } 14288b35abe2Sjtc 14298b35abe2Sjtc /* 14308b35abe2Sjtc * brute force search for a header that we can id. 14318b35abe2Sjtc * we shift through byte at a time. this is slow, but we cannot 14328b35abe2Sjtc * determine the nature of the flaw in the archive in a 14338b35abe2Sjtc * portable manner 14348b35abe2Sjtc */ 14358b35abe2Sjtc if (--hdsz > 0) { 143606f53b68Smycroft memmove(hdbuf, hdbuf+1, hdsz); 14378b35abe2Sjtc res = BLKMULT - hdsz; 14388b35abe2Sjtc hdend = hdbuf + hdsz; 14398b35abe2Sjtc } else { 14408b35abe2Sjtc res = BLKMULT; 14418b35abe2Sjtc hdend = hdbuf; 14428b35abe2Sjtc hdsz = 0; 14438b35abe2Sjtc } 14448b35abe2Sjtc } 14458b35abe2Sjtc 14468b35abe2Sjtc out: 14478b35abe2Sjtc /* 14488b35abe2Sjtc * we cannot find a header, bow, apologize and quit 14498b35abe2Sjtc */ 14508461b5b8Schristos tty_warn(1, "Sorry, unable to determine archive format."); 1451cdec4ac1Sdsl return -1; 14528b35abe2Sjtc } 1453