14b88c807SRodney W. Grimes /*- 24b88c807SRodney W. Grimes * Copyright (c) 1992 Keith Muller. 34b88c807SRodney W. Grimes * Copyright (c) 1992, 1993 44b88c807SRodney W. Grimes * The Regents of the University of California. All rights reserved. 54b88c807SRodney W. Grimes * 64b88c807SRodney W. Grimes * This code is derived from software contributed to Berkeley by 74b88c807SRodney W. Grimes * Keith Muller of the University of California, San Diego. 84b88c807SRodney W. Grimes * 94b88c807SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 104b88c807SRodney W. Grimes * modification, are permitted provided that the following conditions 114b88c807SRodney W. Grimes * are met: 124b88c807SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 134b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 144b88c807SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 154b88c807SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 164b88c807SRodney W. Grimes * documentation and/or other materials provided with the distribution. 174b88c807SRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 184b88c807SRodney W. Grimes * must display the following acknowledgement: 194b88c807SRodney W. Grimes * This product includes software developed by the University of 204b88c807SRodney W. Grimes * California, Berkeley and its contributors. 214b88c807SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 224b88c807SRodney W. Grimes * may be used to endorse or promote products derived from this software 234b88c807SRodney W. Grimes * without specific prior written permission. 244b88c807SRodney W. Grimes * 254b88c807SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 264b88c807SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 274b88c807SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 284b88c807SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 294b88c807SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 304b88c807SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 314b88c807SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 324b88c807SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 334b88c807SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 344b88c807SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 354b88c807SRodney W. Grimes * SUCH DAMAGE. 364b88c807SRodney W. Grimes */ 374b88c807SRodney W. Grimes 384b88c807SRodney W. Grimes #ifndef lint 39c9a8d1f4SPhilippe Charnier #if 0 40c9a8d1f4SPhilippe Charnier static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 5/31/93"; 41c9a8d1f4SPhilippe Charnier #endif 42c9a8d1f4SPhilippe Charnier static const char rcsid[] = 432a456239SPeter Wemm "$FreeBSD$"; 444b88c807SRodney W. Grimes #endif /* not lint */ 454b88c807SRodney W. Grimes 464b88c807SRodney W. Grimes #include <sys/types.h> 474b88c807SRodney W. Grimes #include <sys/time.h> 484b88c807SRodney W. Grimes #include <sys/stat.h> 494b88c807SRodney W. Grimes #include <sys/fcntl.h> 50007d3350SEivind Eklund #include <errno.h> 514b88c807SRodney W. Grimes #include <stdio.h> 52007d3350SEivind Eklund #include <stdlib.h> 534b88c807SRodney W. Grimes #include <string.h> 544b88c807SRodney W. Grimes #include <unistd.h> 554b88c807SRodney W. Grimes #include "pax.h" 564b88c807SRodney W. Grimes #include "tables.h" 574b88c807SRodney W. Grimes #include "extern.h" 584b88c807SRodney W. Grimes 594b88c807SRodney W. Grimes /* 604b88c807SRodney W. Grimes * Routines for controlling the contents of all the different databases pax 614b88c807SRodney W. Grimes * keeps. Tables are dynamically created only when they are needed. The 624b88c807SRodney W. Grimes * goal was speed and the ability to work with HUGE archives. The databases 634b88c807SRodney W. Grimes * were kept simple, but do have complex rules for when the contents change. 6446be34b9SKris Kennaway * As of this writing, the POSIX library functions were more complex than 654b88c807SRodney W. Grimes * needed for this application (pax databases have very short lifetimes and 664b88c807SRodney W. Grimes * do not survive after pax is finished). Pax is required to handle very 674b88c807SRodney W. Grimes * large archives. These database routines carefully combine memory usage and 684b88c807SRodney W. Grimes * temporary file storage in ways which will not significantly impact runtime 694b88c807SRodney W. Grimes * performance while allowing the largest possible archives to be handled. 7046be34b9SKris Kennaway * Trying to force the fit to the POSIX databases routines was not considered 714b88c807SRodney W. Grimes * time well spent. 724b88c807SRodney W. Grimes */ 734b88c807SRodney W. Grimes 744b88c807SRodney W. Grimes static HRDLNK **ltab = NULL; /* hard link table for detecting hard links */ 754b88c807SRodney W. Grimes static FTM **ftab = NULL; /* file time table for updating arch */ 764b88c807SRodney W. Grimes static NAMT **ntab = NULL; /* interactive rename storage table */ 774b88c807SRodney W. Grimes static DEVT **dtab = NULL; /* device/inode mapping tables */ 784b88c807SRodney W. Grimes static ATDIR **atab = NULL; /* file tree directory time reset table */ 794b88c807SRodney W. Grimes static int dirfd = -1; /* storage for setting created dir time/mode */ 804b88c807SRodney W. Grimes static u_long dircnt; /* entries in dir time/mode storage */ 814b88c807SRodney W. Grimes static int ffd = -1; /* tmp file for file time table name storage */ 824b88c807SRodney W. Grimes 834b88c807SRodney W. Grimes static DEVT *chk_dev __P((dev_t, int)); 844b88c807SRodney W. Grimes 854b88c807SRodney W. Grimes /* 864b88c807SRodney W. Grimes * hard link table routines 874b88c807SRodney W. Grimes * 884b88c807SRodney W. Grimes * The hard link table tries to detect hard links to files using the device and 894b88c807SRodney W. Grimes * inode values. We do this when writing an archive, so we can tell the format 904b88c807SRodney W. Grimes * write routine that this file is a hard link to another file. The format 914b88c807SRodney W. Grimes * write routine then can store this file in whatever way it wants (as a hard 924b88c807SRodney W. Grimes * link if the format supports that like tar, or ignore this info like cpio). 934b88c807SRodney W. Grimes * (Actually a field in the format driver table tells us if the format wants 944b88c807SRodney W. Grimes * hard link info. if not, we do not waste time looking for them). We also use 954b88c807SRodney W. Grimes * the same table when reading an archive. In that situation, this table is 964b88c807SRodney W. Grimes * used by the format read routine to detect hard links from stored dev and 974b88c807SRodney W. Grimes * inode numbers (like cpio). This will allow pax to create a link when one 984b88c807SRodney W. Grimes * can be detected by the archive format. 994b88c807SRodney W. Grimes */ 1004b88c807SRodney W. Grimes 1014b88c807SRodney W. Grimes /* 1024b88c807SRodney W. Grimes * lnk_start 1034b88c807SRodney W. Grimes * Creates the hard link table. 1044b88c807SRodney W. Grimes * Return: 1054b88c807SRodney W. Grimes * 0 if created, -1 if failure 1064b88c807SRodney W. Grimes */ 1074b88c807SRodney W. Grimes 1084b88c807SRodney W. Grimes #if __STDC__ 1094b88c807SRodney W. Grimes int 1104b88c807SRodney W. Grimes lnk_start(void) 1114b88c807SRodney W. Grimes #else 1124b88c807SRodney W. Grimes int 1134b88c807SRodney W. Grimes lnk_start() 1144b88c807SRodney W. Grimes #endif 1154b88c807SRodney W. Grimes { 1164b88c807SRodney W. Grimes if (ltab != NULL) 1174b88c807SRodney W. Grimes return(0); 1184b88c807SRodney W. Grimes if ((ltab = (HRDLNK **)calloc(L_TAB_SZ, sizeof(HRDLNK *))) == NULL) { 119a885d9dcSSøren Schmidt pax_warn(1, "Cannot allocate memory for hard link table"); 1204b88c807SRodney W. Grimes return(-1); 1214b88c807SRodney W. Grimes } 1224b88c807SRodney W. Grimes return(0); 1234b88c807SRodney W. Grimes } 1244b88c807SRodney W. Grimes 1254b88c807SRodney W. Grimes /* 1264b88c807SRodney W. Grimes * chk_lnk() 1274b88c807SRodney W. Grimes * Looks up entry in hard link hash table. If found, it copies the name 1284b88c807SRodney W. Grimes * of the file it is linked to (we already saw that file) into ln_name. 1294b88c807SRodney W. Grimes * lnkcnt is decremented and if goes to 1 the node is deleted from the 1304b88c807SRodney W. Grimes * database. (We have seen all the links to this file). If not found, 1314b88c807SRodney W. Grimes * we add the file to the database if it has the potential for having 1324b88c807SRodney W. Grimes * hard links to other files we may process (it has a link count > 1) 1334b88c807SRodney W. Grimes * Return: 1344b88c807SRodney W. Grimes * if found returns 1; if not found returns 0; -1 on error 1354b88c807SRodney W. Grimes */ 1364b88c807SRodney W. Grimes 1374b88c807SRodney W. Grimes #if __STDC__ 1384b88c807SRodney W. Grimes int 1394b88c807SRodney W. Grimes chk_lnk(register ARCHD *arcn) 1404b88c807SRodney W. Grimes #else 1414b88c807SRodney W. Grimes int 1424b88c807SRodney W. Grimes chk_lnk(arcn) 1434b88c807SRodney W. Grimes register ARCHD *arcn; 1444b88c807SRodney W. Grimes #endif 1454b88c807SRodney W. Grimes { 1464b88c807SRodney W. Grimes register HRDLNK *pt; 1474b88c807SRodney W. Grimes register HRDLNK **ppt; 1484b88c807SRodney W. Grimes register u_int indx; 1494b88c807SRodney W. Grimes 1504b88c807SRodney W. Grimes if (ltab == NULL) 1514b88c807SRodney W. Grimes return(-1); 1524b88c807SRodney W. Grimes /* 1534b88c807SRodney W. Grimes * ignore those nodes that cannot have hard links 1544b88c807SRodney W. Grimes */ 1554b88c807SRodney W. Grimes if ((arcn->type == PAX_DIR) || (arcn->sb.st_nlink <= 1)) 1564b88c807SRodney W. Grimes return(0); 1574b88c807SRodney W. Grimes 1584b88c807SRodney W. Grimes /* 1594b88c807SRodney W. Grimes * hash inode number and look for this file 1604b88c807SRodney W. Grimes */ 1614b88c807SRodney W. Grimes indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ; 1624b88c807SRodney W. Grimes if ((pt = ltab[indx]) != NULL) { 1634b88c807SRodney W. Grimes /* 1644b88c807SRodney W. Grimes * it's hash chain in not empty, walk down looking for it 1654b88c807SRodney W. Grimes */ 1664b88c807SRodney W. Grimes ppt = &(ltab[indx]); 1674b88c807SRodney W. Grimes while (pt != NULL) { 1684b88c807SRodney W. Grimes if ((pt->ino == arcn->sb.st_ino) && 1694b88c807SRodney W. Grimes (pt->dev == arcn->sb.st_dev)) 1704b88c807SRodney W. Grimes break; 1714b88c807SRodney W. Grimes ppt = &(pt->fow); 1724b88c807SRodney W. Grimes pt = pt->fow; 1734b88c807SRodney W. Grimes } 1744b88c807SRodney W. Grimes 1754b88c807SRodney W. Grimes if (pt != NULL) { 1764b88c807SRodney W. Grimes /* 1774b88c807SRodney W. Grimes * found a link. set the node type and copy in the 1784b88c807SRodney W. Grimes * name of the file it is to link to. we need to 1794b88c807SRodney W. Grimes * handle hardlinks to regular files differently than 1804b88c807SRodney W. Grimes * other links. 1814b88c807SRodney W. Grimes */ 1824b88c807SRodney W. Grimes arcn->ln_nlen = l_strncpy(arcn->ln_name, pt->name, 1834b88c807SRodney W. Grimes PAXPATHLEN+1); 184877155d0SPhilippe Charnier arcn->ln_name[PAXPATHLEN] = '\0'; 1854b88c807SRodney W. Grimes if (arcn->type == PAX_REG) 1864b88c807SRodney W. Grimes arcn->type = PAX_HRG; 1874b88c807SRodney W. Grimes else 1884b88c807SRodney W. Grimes arcn->type = PAX_HLK; 1894b88c807SRodney W. Grimes 1904b88c807SRodney W. Grimes /* 1914b88c807SRodney W. Grimes * if we have found all the links to this file, remove 1924b88c807SRodney W. Grimes * it from the database 1934b88c807SRodney W. Grimes */ 1944b88c807SRodney W. Grimes if (--pt->nlink <= 1) { 1954b88c807SRodney W. Grimes *ppt = pt->fow; 1964b88c807SRodney W. Grimes (void)free((char *)pt->name); 1974b88c807SRodney W. Grimes (void)free((char *)pt); 1984b88c807SRodney W. Grimes } 1994b88c807SRodney W. Grimes return(1); 2004b88c807SRodney W. Grimes } 2014b88c807SRodney W. Grimes } 2024b88c807SRodney W. Grimes 2034b88c807SRodney W. Grimes /* 2044b88c807SRodney W. Grimes * we never saw this file before. It has links so we add it to the 2054b88c807SRodney W. Grimes * front of this hash chain 2064b88c807SRodney W. Grimes */ 2074b88c807SRodney W. Grimes if ((pt = (HRDLNK *)malloc(sizeof(HRDLNK))) != NULL) { 2084b88c807SRodney W. Grimes if ((pt->name = strdup(arcn->name)) != NULL) { 2094b88c807SRodney W. Grimes pt->dev = arcn->sb.st_dev; 2104b88c807SRodney W. Grimes pt->ino = arcn->sb.st_ino; 2114b88c807SRodney W. Grimes pt->nlink = arcn->sb.st_nlink; 2124b88c807SRodney W. Grimes pt->fow = ltab[indx]; 2134b88c807SRodney W. Grimes ltab[indx] = pt; 2144b88c807SRodney W. Grimes return(0); 2154b88c807SRodney W. Grimes } 2164b88c807SRodney W. Grimes (void)free((char *)pt); 2174b88c807SRodney W. Grimes } 2184b88c807SRodney W. Grimes 219a885d9dcSSøren Schmidt pax_warn(1, "Hard link table out of memory"); 2204b88c807SRodney W. Grimes return(-1); 2214b88c807SRodney W. Grimes } 2224b88c807SRodney W. Grimes 2234b88c807SRodney W. Grimes /* 2244b88c807SRodney W. Grimes * purg_lnk 2254b88c807SRodney W. Grimes * remove reference for a file that we may have added to the data base as 2264b88c807SRodney W. Grimes * a potential source for hard links. We ended up not using the file, so 2274b88c807SRodney W. Grimes * we do not want to accidently point another file at it later on. 2284b88c807SRodney W. Grimes */ 2294b88c807SRodney W. Grimes 2304b88c807SRodney W. Grimes #if __STDC__ 2314b88c807SRodney W. Grimes void 2324b88c807SRodney W. Grimes purg_lnk(register ARCHD *arcn) 2334b88c807SRodney W. Grimes #else 2344b88c807SRodney W. Grimes void 2354b88c807SRodney W. Grimes purg_lnk(arcn) 2364b88c807SRodney W. Grimes register ARCHD *arcn; 2374b88c807SRodney W. Grimes #endif 2384b88c807SRodney W. Grimes { 2394b88c807SRodney W. Grimes register HRDLNK *pt; 2404b88c807SRodney W. Grimes register HRDLNK **ppt; 2414b88c807SRodney W. Grimes register u_int indx; 2424b88c807SRodney W. Grimes 2434b88c807SRodney W. Grimes if (ltab == NULL) 2444b88c807SRodney W. Grimes return; 2454b88c807SRodney W. Grimes /* 2464b88c807SRodney W. Grimes * do not bother to look if it could not be in the database 2474b88c807SRodney W. Grimes */ 2484b88c807SRodney W. Grimes if ((arcn->sb.st_nlink <= 1) || (arcn->type == PAX_DIR) || 2494b88c807SRodney W. Grimes (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) 2504b88c807SRodney W. Grimes return; 2514b88c807SRodney W. Grimes 2524b88c807SRodney W. Grimes /* 2534b88c807SRodney W. Grimes * find the hash chain for this inode value, if empty return 2544b88c807SRodney W. Grimes */ 2554b88c807SRodney W. Grimes indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ; 2564b88c807SRodney W. Grimes if ((pt = ltab[indx]) == NULL) 2574b88c807SRodney W. Grimes return; 2584b88c807SRodney W. Grimes 2594b88c807SRodney W. Grimes /* 2604b88c807SRodney W. Grimes * walk down the list looking for the inode/dev pair, unlink and 2614b88c807SRodney W. Grimes * free if found 2624b88c807SRodney W. Grimes */ 2634b88c807SRodney W. Grimes ppt = &(ltab[indx]); 2644b88c807SRodney W. Grimes while (pt != NULL) { 2654b88c807SRodney W. Grimes if ((pt->ino == arcn->sb.st_ino) && 2664b88c807SRodney W. Grimes (pt->dev == arcn->sb.st_dev)) 2674b88c807SRodney W. Grimes break; 2684b88c807SRodney W. Grimes ppt = &(pt->fow); 2694b88c807SRodney W. Grimes pt = pt->fow; 2704b88c807SRodney W. Grimes } 2714b88c807SRodney W. Grimes if (pt == NULL) 2724b88c807SRodney W. Grimes return; 2734b88c807SRodney W. Grimes 2744b88c807SRodney W. Grimes /* 2754b88c807SRodney W. Grimes * remove and free it 2764b88c807SRodney W. Grimes */ 2774b88c807SRodney W. Grimes *ppt = pt->fow; 2784b88c807SRodney W. Grimes (void)free((char *)pt->name); 2794b88c807SRodney W. Grimes (void)free((char *)pt); 2804b88c807SRodney W. Grimes } 2814b88c807SRodney W. Grimes 2824b88c807SRodney W. Grimes /* 2834b88c807SRodney W. Grimes * lnk_end() 2844b88c807SRodney W. Grimes * pull apart a existing link table so we can reuse it. We do this between 2854b88c807SRodney W. Grimes * read and write phases of append with update. (The format may have 2864b88c807SRodney W. Grimes * used the link table, and we need to start with a fresh table for the 2874b88c807SRodney W. Grimes * write phase 2884b88c807SRodney W. Grimes */ 2894b88c807SRodney W. Grimes 2904b88c807SRodney W. Grimes #if __STDC__ 2914b88c807SRodney W. Grimes void 2924b88c807SRodney W. Grimes lnk_end(void) 2934b88c807SRodney W. Grimes #else 2944b88c807SRodney W. Grimes void 2954b88c807SRodney W. Grimes lnk_end() 2964b88c807SRodney W. Grimes #endif 2974b88c807SRodney W. Grimes { 2984b88c807SRodney W. Grimes register int i; 2994b88c807SRodney W. Grimes register HRDLNK *pt; 3004b88c807SRodney W. Grimes register HRDLNK *ppt; 3014b88c807SRodney W. Grimes 3024b88c807SRodney W. Grimes if (ltab == NULL) 3034b88c807SRodney W. Grimes return; 3044b88c807SRodney W. Grimes 3054b88c807SRodney W. Grimes for (i = 0; i < L_TAB_SZ; ++i) { 3064b88c807SRodney W. Grimes if (ltab[i] == NULL) 3074b88c807SRodney W. Grimes continue; 3084b88c807SRodney W. Grimes pt = ltab[i]; 3094b88c807SRodney W. Grimes ltab[i] = NULL; 3104b88c807SRodney W. Grimes 3114b88c807SRodney W. Grimes /* 3124b88c807SRodney W. Grimes * free up each entry on this chain 3134b88c807SRodney W. Grimes */ 3144b88c807SRodney W. Grimes while (pt != NULL) { 3154b88c807SRodney W. Grimes ppt = pt; 3164b88c807SRodney W. Grimes pt = ppt->fow; 3174b88c807SRodney W. Grimes (void)free((char *)ppt->name); 3184b88c807SRodney W. Grimes (void)free((char *)ppt); 3194b88c807SRodney W. Grimes } 3204b88c807SRodney W. Grimes } 3214b88c807SRodney W. Grimes return; 3224b88c807SRodney W. Grimes } 3234b88c807SRodney W. Grimes 3244b88c807SRodney W. Grimes /* 3254b88c807SRodney W. Grimes * modification time table routines 3264b88c807SRodney W. Grimes * 3274b88c807SRodney W. Grimes * The modification time table keeps track of last modification times for all 3284b88c807SRodney W. Grimes * files stored in an archive during a write phase when -u is set. We only 3294b88c807SRodney W. Grimes * add a file to the archive if it is newer than a file with the same name 3304b88c807SRodney W. Grimes * already stored on the archive (if there is no other file with the same 3314b88c807SRodney W. Grimes * name on the archive it is added). This applies to writes and appends. 3324b88c807SRodney W. Grimes * An append with an -u must read the archive and store the modification time 3334b88c807SRodney W. Grimes * for every file on that archive before starting the write phase. It is clear 3344b88c807SRodney W. Grimes * that this is one HUGE database. To save memory space, the actual file names 3354b88c807SRodney W. Grimes * are stored in a scatch file and indexed by an in memory hash table. The 3364b88c807SRodney W. Grimes * hash table is indexed by hashing the file path. The nodes in the table store 3374b88c807SRodney W. Grimes * the length of the filename and the lseek offset within the scratch file 3384b88c807SRodney W. Grimes * where the actual name is stored. Since there are never any deletions to this 3394b88c807SRodney W. Grimes * table, fragmentation of the scratch file is never a issue. Lookups seem to 3404b88c807SRodney W. Grimes * not exhibit any locality at all (files in the database are rarely 3414b88c807SRodney W. Grimes * looked up more than once...). So caching is just a waste of memory. The 3424b88c807SRodney W. Grimes * only limitation is the amount of scatch file space available to store the 3434b88c807SRodney W. Grimes * path names. 3444b88c807SRodney W. Grimes */ 3454b88c807SRodney W. Grimes 3464b88c807SRodney W. Grimes /* 3474b88c807SRodney W. Grimes * ftime_start() 3484b88c807SRodney W. Grimes * create the file time hash table and open for read/write the scratch 3494b88c807SRodney W. Grimes * file. (after created it is unlinked, so when we exit we leave 3504b88c807SRodney W. Grimes * no witnesses). 3514b88c807SRodney W. Grimes * Return: 3524b88c807SRodney W. Grimes * 0 if the table and file was created ok, -1 otherwise 3534b88c807SRodney W. Grimes */ 3544b88c807SRodney W. Grimes 3554b88c807SRodney W. Grimes #if __STDC__ 3564b88c807SRodney W. Grimes int 3574b88c807SRodney W. Grimes ftime_start(void) 3584b88c807SRodney W. Grimes #else 3594b88c807SRodney W. Grimes int 3604b88c807SRodney W. Grimes ftime_start() 3614b88c807SRodney W. Grimes #endif 3624b88c807SRodney W. Grimes { 3634b88c807SRodney W. Grimes if (ftab != NULL) 3644b88c807SRodney W. Grimes return(0); 3654b88c807SRodney W. Grimes if ((ftab = (FTM **)calloc(F_TAB_SZ, sizeof(FTM *))) == NULL) { 366a885d9dcSSøren Schmidt pax_warn(1, "Cannot allocate memory for file time table"); 3674b88c807SRodney W. Grimes return(-1); 3684b88c807SRodney W. Grimes } 3694b88c807SRodney W. Grimes 3704b88c807SRodney W. Grimes /* 3714b88c807SRodney W. Grimes * get random name and create temporary scratch file, unlink name 3724b88c807SRodney W. Grimes * so it will get removed on exit 3734b88c807SRodney W. Grimes */ 374ffbef1cdSKris Kennaway memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE)); 375ffbef1cdSKris Kennaway if ((ffd = mkstemp(tempfile)) < 0) { 376ffbef1cdSKris Kennaway sys_warn(1, errno, "Unable to create temporary file: %s", 377ffbef1cdSKris Kennaway tempfile); 3784b88c807SRodney W. Grimes return(-1); 3794b88c807SRodney W. Grimes } 380ffbef1cdSKris Kennaway (void)unlink(tempfile); 3814b88c807SRodney W. Grimes 3824b88c807SRodney W. Grimes return(0); 3834b88c807SRodney W. Grimes } 3844b88c807SRodney W. Grimes 3854b88c807SRodney W. Grimes /* 3864b88c807SRodney W. Grimes * chk_ftime() 3874b88c807SRodney W. Grimes * looks up entry in file time hash table. If not found, the file is 3884b88c807SRodney W. Grimes * added to the hash table and the file named stored in the scratch file. 3894b88c807SRodney W. Grimes * If a file with the same name is found, the file times are compared and 3904b88c807SRodney W. Grimes * the most recent file time is retained. If the new file was younger (or 3914b88c807SRodney W. Grimes * was not in the database) the new file is selected for storage. 3924b88c807SRodney W. Grimes * Return: 3934b88c807SRodney W. Grimes * 0 if file should be added to the archive, 1 if it should be skipped, 3944b88c807SRodney W. Grimes * -1 on error 3954b88c807SRodney W. Grimes */ 3964b88c807SRodney W. Grimes 3974b88c807SRodney W. Grimes #if __STDC__ 3984b88c807SRodney W. Grimes int 3994b88c807SRodney W. Grimes chk_ftime(register ARCHD *arcn) 4004b88c807SRodney W. Grimes #else 4014b88c807SRodney W. Grimes int 4024b88c807SRodney W. Grimes chk_ftime(arcn) 4034b88c807SRodney W. Grimes register ARCHD *arcn; 4044b88c807SRodney W. Grimes #endif 4054b88c807SRodney W. Grimes { 4064b88c807SRodney W. Grimes register FTM *pt; 4074b88c807SRodney W. Grimes register int namelen; 4084b88c807SRodney W. Grimes register u_int indx; 4094b88c807SRodney W. Grimes char ckname[PAXPATHLEN+1]; 4104b88c807SRodney W. Grimes 4114b88c807SRodney W. Grimes /* 4124b88c807SRodney W. Grimes * no info, go ahead and add to archive 4134b88c807SRodney W. Grimes */ 4144b88c807SRodney W. Grimes if (ftab == NULL) 4154b88c807SRodney W. Grimes return(0); 4164b88c807SRodney W. Grimes 4174b88c807SRodney W. Grimes /* 4184b88c807SRodney W. Grimes * hash the pathname and look up in table 4194b88c807SRodney W. Grimes */ 4204b88c807SRodney W. Grimes namelen = arcn->nlen; 4214b88c807SRodney W. Grimes indx = st_hash(arcn->name, namelen, F_TAB_SZ); 4224b88c807SRodney W. Grimes if ((pt = ftab[indx]) != NULL) { 4234b88c807SRodney W. Grimes /* 4244b88c807SRodney W. Grimes * the hash chain is not empty, walk down looking for match 4254b88c807SRodney W. Grimes * only read up the path names if the lengths match, speeds 4264b88c807SRodney W. Grimes * up the search a lot 4274b88c807SRodney W. Grimes */ 4284b88c807SRodney W. Grimes while (pt != NULL) { 4294b88c807SRodney W. Grimes if (pt->namelen == namelen) { 4304b88c807SRodney W. Grimes /* 4314b88c807SRodney W. Grimes * potential match, have to read the name 4324b88c807SRodney W. Grimes * from the scratch file. 4334b88c807SRodney W. Grimes */ 4344b88c807SRodney W. Grimes if (lseek(ffd,pt->seek,SEEK_SET) != pt->seek) { 435a885d9dcSSøren Schmidt sys_warn(1, errno, 4364b88c807SRodney W. Grimes "Failed ftime table seek"); 4374b88c807SRodney W. Grimes return(-1); 4384b88c807SRodney W. Grimes } 4394b88c807SRodney W. Grimes if (read(ffd, ckname, namelen) != namelen) { 440a885d9dcSSøren Schmidt sys_warn(1, errno, 4414b88c807SRodney W. Grimes "Failed ftime table read"); 4424b88c807SRodney W. Grimes return(-1); 4434b88c807SRodney W. Grimes } 4444b88c807SRodney W. Grimes 4454b88c807SRodney W. Grimes /* 4464b88c807SRodney W. Grimes * if the names match, we are done 4474b88c807SRodney W. Grimes */ 4484b88c807SRodney W. Grimes if (!strncmp(ckname, arcn->name, namelen)) 4494b88c807SRodney W. Grimes break; 4504b88c807SRodney W. Grimes } 4514b88c807SRodney W. Grimes 4524b88c807SRodney W. Grimes /* 4534b88c807SRodney W. Grimes * try the next entry on the chain 4544b88c807SRodney W. Grimes */ 4554b88c807SRodney W. Grimes pt = pt->fow; 4564b88c807SRodney W. Grimes } 4574b88c807SRodney W. Grimes 4584b88c807SRodney W. Grimes if (pt != NULL) { 4594b88c807SRodney W. Grimes /* 4604b88c807SRodney W. Grimes * found the file, compare the times, save the newer 4614b88c807SRodney W. Grimes */ 4624b88c807SRodney W. Grimes if (arcn->sb.st_mtime > pt->mtime) { 4634b88c807SRodney W. Grimes /* 4644b88c807SRodney W. Grimes * file is newer 4654b88c807SRodney W. Grimes */ 4664b88c807SRodney W. Grimes pt->mtime = arcn->sb.st_mtime; 4674b88c807SRodney W. Grimes return(0); 4684b88c807SRodney W. Grimes } 4694b88c807SRodney W. Grimes /* 4704b88c807SRodney W. Grimes * file is older 4714b88c807SRodney W. Grimes */ 4724b88c807SRodney W. Grimes return(1); 4734b88c807SRodney W. Grimes } 4744b88c807SRodney W. Grimes } 4754b88c807SRodney W. Grimes 4764b88c807SRodney W. Grimes /* 4774b88c807SRodney W. Grimes * not in table, add it 4784b88c807SRodney W. Grimes */ 4794b88c807SRodney W. Grimes if ((pt = (FTM *)malloc(sizeof(FTM))) != NULL) { 4804b88c807SRodney W. Grimes /* 4814b88c807SRodney W. Grimes * add the name at the end of the scratch file, saving the 4824b88c807SRodney W. Grimes * offset. add the file to the head of the hash chain 4834b88c807SRodney W. Grimes */ 4844b88c807SRodney W. Grimes if ((pt->seek = lseek(ffd, (off_t)0, SEEK_END)) >= 0) { 4854b88c807SRodney W. Grimes if (write(ffd, arcn->name, namelen) == namelen) { 4864b88c807SRodney W. Grimes pt->mtime = arcn->sb.st_mtime; 4874b88c807SRodney W. Grimes pt->namelen = namelen; 4884b88c807SRodney W. Grimes pt->fow = ftab[indx]; 4894b88c807SRodney W. Grimes ftab[indx] = pt; 4904b88c807SRodney W. Grimes return(0); 4914b88c807SRodney W. Grimes } 492a885d9dcSSøren Schmidt sys_warn(1, errno, "Failed write to file time table"); 4934b88c807SRodney W. Grimes } else 494a885d9dcSSøren Schmidt sys_warn(1, errno, "Failed seek on file time table"); 4954b88c807SRodney W. Grimes } else 496a885d9dcSSøren Schmidt pax_warn(1, "File time table ran out of memory"); 4974b88c807SRodney W. Grimes 4984b88c807SRodney W. Grimes if (pt != NULL) 4994b88c807SRodney W. Grimes (void)free((char *)pt); 5004b88c807SRodney W. Grimes return(-1); 5014b88c807SRodney W. Grimes } 5024b88c807SRodney W. Grimes 5034b88c807SRodney W. Grimes /* 5044b88c807SRodney W. Grimes * Interactive rename table routines 5054b88c807SRodney W. Grimes * 5064b88c807SRodney W. Grimes * The interactive rename table keeps track of the new names that the user 50746be34b9SKris Kennaway * assigns to files from tty input. Since this map is unique for each file 5084b88c807SRodney W. Grimes * we must store it in case there is a reference to the file later in archive 5094b88c807SRodney W. Grimes * (a link). Otherwise we will be unable to find the file we know was 5104b88c807SRodney W. Grimes * extracted. The remapping of these files is stored in a memory based hash 5114b88c807SRodney W. Grimes * table (it is assumed since input must come from /dev/tty, it is unlikely to 5124b88c807SRodney W. Grimes * be a very large table). 5134b88c807SRodney W. Grimes */ 5144b88c807SRodney W. Grimes 5154b88c807SRodney W. Grimes /* 5164b88c807SRodney W. Grimes * name_start() 5174b88c807SRodney W. Grimes * create the interactive rename table 5184b88c807SRodney W. Grimes * Return: 5194b88c807SRodney W. Grimes * 0 if successful, -1 otherwise 5204b88c807SRodney W. Grimes */ 5214b88c807SRodney W. Grimes 5224b88c807SRodney W. Grimes #if __STDC__ 5234b88c807SRodney W. Grimes int 5244b88c807SRodney W. Grimes name_start(void) 5254b88c807SRodney W. Grimes #else 5264b88c807SRodney W. Grimes int 5274b88c807SRodney W. Grimes name_start() 5284b88c807SRodney W. Grimes #endif 5294b88c807SRodney W. Grimes { 5304b88c807SRodney W. Grimes if (ntab != NULL) 5314b88c807SRodney W. Grimes return(0); 5324b88c807SRodney W. Grimes if ((ntab = (NAMT **)calloc(N_TAB_SZ, sizeof(NAMT *))) == NULL) { 533a885d9dcSSøren Schmidt pax_warn(1, "Cannot allocate memory for interactive rename table"); 5344b88c807SRodney W. Grimes return(-1); 5354b88c807SRodney W. Grimes } 5364b88c807SRodney W. Grimes return(0); 5374b88c807SRodney W. Grimes } 5384b88c807SRodney W. Grimes 5394b88c807SRodney W. Grimes /* 5404b88c807SRodney W. Grimes * add_name() 5414b88c807SRodney W. Grimes * add the new name to old name mapping just created by the user. 5424b88c807SRodney W. Grimes * If an old name mapping is found (there may be duplicate names on an 5434b88c807SRodney W. Grimes * archive) only the most recent is kept. 5444b88c807SRodney W. Grimes * Return: 5454b88c807SRodney W. Grimes * 0 if added, -1 otherwise 5464b88c807SRodney W. Grimes */ 5474b88c807SRodney W. Grimes 5484b88c807SRodney W. Grimes #if __STDC__ 5494b88c807SRodney W. Grimes int 5504b88c807SRodney W. Grimes add_name(register char *oname, int onamelen, char *nname) 5514b88c807SRodney W. Grimes #else 5524b88c807SRodney W. Grimes int 5534b88c807SRodney W. Grimes add_name(oname, onamelen, nname) 5544b88c807SRodney W. Grimes register char *oname; 5554b88c807SRodney W. Grimes int onamelen; 5564b88c807SRodney W. Grimes char *nname; 5574b88c807SRodney W. Grimes #endif 5584b88c807SRodney W. Grimes { 5594b88c807SRodney W. Grimes register NAMT *pt; 5604b88c807SRodney W. Grimes register u_int indx; 5614b88c807SRodney W. Grimes 5624b88c807SRodney W. Grimes if (ntab == NULL) { 5634b88c807SRodney W. Grimes /* 5644b88c807SRodney W. Grimes * should never happen 5654b88c807SRodney W. Grimes */ 566a885d9dcSSøren Schmidt pax_warn(0, "No interactive rename table, links may fail\n"); 5674b88c807SRodney W. Grimes return(0); 5684b88c807SRodney W. Grimes } 5694b88c807SRodney W. Grimes 5704b88c807SRodney W. Grimes /* 5714b88c807SRodney W. Grimes * look to see if we have already mapped this file, if so we 5724b88c807SRodney W. Grimes * will update it 5734b88c807SRodney W. Grimes */ 5744b88c807SRodney W. Grimes indx = st_hash(oname, onamelen, N_TAB_SZ); 5754b88c807SRodney W. Grimes if ((pt = ntab[indx]) != NULL) { 5764b88c807SRodney W. Grimes /* 5774b88c807SRodney W. Grimes * look down the has chain for the file 5784b88c807SRodney W. Grimes */ 5794b88c807SRodney W. Grimes while ((pt != NULL) && (strcmp(oname, pt->oname) != 0)) 5804b88c807SRodney W. Grimes pt = pt->fow; 5814b88c807SRodney W. Grimes 5824b88c807SRodney W. Grimes if (pt != NULL) { 5834b88c807SRodney W. Grimes /* 5844b88c807SRodney W. Grimes * found an old mapping, replace it with the new one 5854b88c807SRodney W. Grimes * the user just input (if it is different) 5864b88c807SRodney W. Grimes */ 5874b88c807SRodney W. Grimes if (strcmp(nname, pt->nname) == 0) 5884b88c807SRodney W. Grimes return(0); 5894b88c807SRodney W. Grimes 5904b88c807SRodney W. Grimes (void)free((char *)pt->nname); 5914b88c807SRodney W. Grimes if ((pt->nname = strdup(nname)) == NULL) { 592a885d9dcSSøren Schmidt pax_warn(1, "Cannot update rename table"); 5934b88c807SRodney W. Grimes return(-1); 5944b88c807SRodney W. Grimes } 5954b88c807SRodney W. Grimes return(0); 5964b88c807SRodney W. Grimes } 5974b88c807SRodney W. Grimes } 5984b88c807SRodney W. Grimes 5994b88c807SRodney W. Grimes /* 6004b88c807SRodney W. Grimes * this is a new mapping, add it to the table 6014b88c807SRodney W. Grimes */ 6024b88c807SRodney W. Grimes if ((pt = (NAMT *)malloc(sizeof(NAMT))) != NULL) { 6034b88c807SRodney W. Grimes if ((pt->oname = strdup(oname)) != NULL) { 6044b88c807SRodney W. Grimes if ((pt->nname = strdup(nname)) != NULL) { 6054b88c807SRodney W. Grimes pt->fow = ntab[indx]; 6064b88c807SRodney W. Grimes ntab[indx] = pt; 6074b88c807SRodney W. Grimes return(0); 6084b88c807SRodney W. Grimes } 6094b88c807SRodney W. Grimes (void)free((char *)pt->oname); 6104b88c807SRodney W. Grimes } 6114b88c807SRodney W. Grimes (void)free((char *)pt); 6124b88c807SRodney W. Grimes } 613a885d9dcSSøren Schmidt pax_warn(1, "Interactive rename table out of memory"); 6144b88c807SRodney W. Grimes return(-1); 6154b88c807SRodney W. Grimes } 6164b88c807SRodney W. Grimes 6174b88c807SRodney W. Grimes /* 6184b88c807SRodney W. Grimes * sub_name() 6194b88c807SRodney W. Grimes * look up a link name to see if it points at a file that has been 6204b88c807SRodney W. Grimes * remapped by the user. If found, the link is adjusted to contain the 6214b88c807SRodney W. Grimes * new name (oname is the link to name) 6224b88c807SRodney W. Grimes */ 6234b88c807SRodney W. Grimes 6244b88c807SRodney W. Grimes #if __STDC__ 6254b88c807SRodney W. Grimes void 6264b88c807SRodney W. Grimes sub_name(register char *oname, int *onamelen) 6274b88c807SRodney W. Grimes #else 6284b88c807SRodney W. Grimes void 6294b88c807SRodney W. Grimes sub_name(oname, onamelen) 6304b88c807SRodney W. Grimes register char *oname; 6314b88c807SRodney W. Grimes int *onamelen; 6324b88c807SRodney W. Grimes #endif 6334b88c807SRodney W. Grimes { 6344b88c807SRodney W. Grimes register NAMT *pt; 6354b88c807SRodney W. Grimes register u_int indx; 6364b88c807SRodney W. Grimes 6374b88c807SRodney W. Grimes if (ntab == NULL) 6384b88c807SRodney W. Grimes return; 6394b88c807SRodney W. Grimes /* 6404b88c807SRodney W. Grimes * look the name up in the hash table 6414b88c807SRodney W. Grimes */ 6424b88c807SRodney W. Grimes indx = st_hash(oname, *onamelen, N_TAB_SZ); 6434b88c807SRodney W. Grimes if ((pt = ntab[indx]) == NULL) 6444b88c807SRodney W. Grimes return; 6454b88c807SRodney W. Grimes 6464b88c807SRodney W. Grimes while (pt != NULL) { 6474b88c807SRodney W. Grimes /* 6484b88c807SRodney W. Grimes * walk down the hash cahin looking for a match 6494b88c807SRodney W. Grimes */ 6504b88c807SRodney W. Grimes if (strcmp(oname, pt->oname) == 0) { 6514b88c807SRodney W. Grimes /* 6524b88c807SRodney W. Grimes * found it, replace it with the new name 6534b88c807SRodney W. Grimes * and return (we know that oname has enough space) 6544b88c807SRodney W. Grimes */ 6554b88c807SRodney W. Grimes *onamelen = l_strncpy(oname, pt->nname, PAXPATHLEN+1); 656877155d0SPhilippe Charnier oname[PAXPATHLEN] = '\0'; 6574b88c807SRodney W. Grimes return; 6584b88c807SRodney W. Grimes } 6594b88c807SRodney W. Grimes pt = pt->fow; 6604b88c807SRodney W. Grimes } 6614b88c807SRodney W. Grimes 6624b88c807SRodney W. Grimes /* 6634b88c807SRodney W. Grimes * no match, just return 6644b88c807SRodney W. Grimes */ 6654b88c807SRodney W. Grimes return; 6664b88c807SRodney W. Grimes } 6674b88c807SRodney W. Grimes 6684b88c807SRodney W. Grimes /* 6694b88c807SRodney W. Grimes * device/inode mapping table routines 6704b88c807SRodney W. Grimes * (used with formats that store device and inodes fields) 6714b88c807SRodney W. Grimes * 6724b88c807SRodney W. Grimes * device/inode mapping tables remap the device field in a archive header. The 6734b88c807SRodney W. Grimes * device/inode fields are used to determine when files are hard links to each 6744b88c807SRodney W. Grimes * other. However these values have very little meaning outside of that. This 6754b88c807SRodney W. Grimes * database is used to solve one of two different problems. 6764b88c807SRodney W. Grimes * 6774b88c807SRodney W. Grimes * 1) when files are appended to an archive, while the new files may have hard 6784b88c807SRodney W. Grimes * links to each other, you cannot determine if they have hard links to any 6794b88c807SRodney W. Grimes * file already stored on the archive from a prior run of pax. We must assume 6804b88c807SRodney W. Grimes * that these inode/device pairs are unique only within a SINGLE run of pax 6814b88c807SRodney W. Grimes * (which adds a set of files to an archive). So we have to make sure the 6824b88c807SRodney W. Grimes * inode/dev pairs we add each time are always unique. We do this by observing 6834b88c807SRodney W. Grimes * while the inode field is very dense, the use of the dev field is fairly 6844b88c807SRodney W. Grimes * sparse. Within each run of pax, we remap any device number of a new archive 6854b88c807SRodney W. Grimes * member that has a device number used in a prior run and already stored in a 6864b88c807SRodney W. Grimes * file on the archive. During the read phase of the append, we store the 6874b88c807SRodney W. Grimes * device numbers used and mark them to not be used by any file during the 6884b88c807SRodney W. Grimes * write phase. If during write we go to use one of those old device numbers, 6894b88c807SRodney W. Grimes * we remap it to a new value. 6904b88c807SRodney W. Grimes * 6914b88c807SRodney W. Grimes * 2) Often the fields in the archive header used to store these values are 6924b88c807SRodney W. Grimes * too small to store the entire value. The result is an inode or device value 6934b88c807SRodney W. Grimes * which can be truncated. This really can foul up an archive. With truncation 6944b88c807SRodney W. Grimes * we end up creating links between files that are really not links (after 6954b88c807SRodney W. Grimes * truncation the inodes are the same value). We address that by detecting 6964b88c807SRodney W. Grimes * truncation and forcing a remap of the device field to split truncated 6974b88c807SRodney W. Grimes * inodes away from each other. Each truncation creates a pattern of bits that 6984b88c807SRodney W. Grimes * are removed. We use this pattern of truncated bits to partition the inodes 6994b88c807SRodney W. Grimes * on a single device to many different devices (each one represented by the 7004b88c807SRodney W. Grimes * truncated bit pattern). All inodes on the same device that have the same 7014b88c807SRodney W. Grimes * truncation pattern are mapped to the same new device. Two inodes that 7024b88c807SRodney W. Grimes * truncate to the same value clearly will always have different truncation 7034b88c807SRodney W. Grimes * bit patterns, so they will be split from away each other. When we spot 7044b88c807SRodney W. Grimes * device truncation we remap the device number to a non truncated value. 7054b88c807SRodney W. Grimes * (for more info see table.h for the data structures involved). 7064b88c807SRodney W. Grimes */ 7074b88c807SRodney W. Grimes 7084b88c807SRodney W. Grimes /* 7094b88c807SRodney W. Grimes * dev_start() 7104b88c807SRodney W. Grimes * create the device mapping table 7114b88c807SRodney W. Grimes * Return: 7124b88c807SRodney W. Grimes * 0 if successful, -1 otherwise 7134b88c807SRodney W. Grimes */ 7144b88c807SRodney W. Grimes 7154b88c807SRodney W. Grimes #if __STDC__ 7164b88c807SRodney W. Grimes int 7174b88c807SRodney W. Grimes dev_start(void) 7184b88c807SRodney W. Grimes #else 7194b88c807SRodney W. Grimes int 7204b88c807SRodney W. Grimes dev_start() 7214b88c807SRodney W. Grimes #endif 7224b88c807SRodney W. Grimes { 7234b88c807SRodney W. Grimes if (dtab != NULL) 7244b88c807SRodney W. Grimes return(0); 7254b88c807SRodney W. Grimes if ((dtab = (DEVT **)calloc(D_TAB_SZ, sizeof(DEVT *))) == NULL) { 726a885d9dcSSøren Schmidt pax_warn(1, "Cannot allocate memory for device mapping table"); 7274b88c807SRodney W. Grimes return(-1); 7284b88c807SRodney W. Grimes } 7294b88c807SRodney W. Grimes return(0); 7304b88c807SRodney W. Grimes } 7314b88c807SRodney W. Grimes 7324b88c807SRodney W. Grimes /* 7334b88c807SRodney W. Grimes * add_dev() 7344b88c807SRodney W. Grimes * add a device number to the table. this will force the device to be 7354b88c807SRodney W. Grimes * remapped to a new value if it be used during a write phase. This 7364b88c807SRodney W. Grimes * function is called during the read phase of an append to prohibit the 7374b88c807SRodney W. Grimes * use of any device number already in the archive. 7384b88c807SRodney W. Grimes * Return: 7394b88c807SRodney W. Grimes * 0 if added ok, -1 otherwise 7404b88c807SRodney W. Grimes */ 7414b88c807SRodney W. Grimes 7424b88c807SRodney W. Grimes #if __STDC__ 7434b88c807SRodney W. Grimes int 7444b88c807SRodney W. Grimes add_dev(register ARCHD *arcn) 7454b88c807SRodney W. Grimes #else 7464b88c807SRodney W. Grimes int 7474b88c807SRodney W. Grimes add_dev(arcn) 7484b88c807SRodney W. Grimes register ARCHD *arcn; 7494b88c807SRodney W. Grimes #endif 7504b88c807SRodney W. Grimes { 7514b88c807SRodney W. Grimes if (chk_dev(arcn->sb.st_dev, 1) == NULL) 7524b88c807SRodney W. Grimes return(-1); 7534b88c807SRodney W. Grimes return(0); 7544b88c807SRodney W. Grimes } 7554b88c807SRodney W. Grimes 7564b88c807SRodney W. Grimes /* 7574b88c807SRodney W. Grimes * chk_dev() 7584b88c807SRodney W. Grimes * check for a device value in the device table. If not found and the add 7594b88c807SRodney W. Grimes * flag is set, it is added. This does NOT assign any mapping values, just 7604b88c807SRodney W. Grimes * adds the device number as one that need to be remapped. If this device 76146be34b9SKris Kennaway * is already mapped, just return with a pointer to that entry. 7624b88c807SRodney W. Grimes * Return: 7634b88c807SRodney W. Grimes * pointer to the entry for this device in the device map table. Null 7644b88c807SRodney W. Grimes * if the add flag is not set and the device is not in the table (it is 7654b88c807SRodney W. Grimes * not been seen yet). If add is set and the device cannot be added, null 7664b88c807SRodney W. Grimes * is returned (indicates an error). 7674b88c807SRodney W. Grimes */ 7684b88c807SRodney W. Grimes 7694b88c807SRodney W. Grimes #if __STDC__ 7704b88c807SRodney W. Grimes static DEVT * 7714b88c807SRodney W. Grimes chk_dev(dev_t dev, int add) 7724b88c807SRodney W. Grimes #else 7734b88c807SRodney W. Grimes static DEVT * 7744b88c807SRodney W. Grimes chk_dev(dev, add) 7754b88c807SRodney W. Grimes dev_t dev; 7764b88c807SRodney W. Grimes int add; 7774b88c807SRodney W. Grimes #endif 7784b88c807SRodney W. Grimes { 7794b88c807SRodney W. Grimes register DEVT *pt; 7804b88c807SRodney W. Grimes register u_int indx; 7814b88c807SRodney W. Grimes 7824b88c807SRodney W. Grimes if (dtab == NULL) 7834b88c807SRodney W. Grimes return(NULL); 7844b88c807SRodney W. Grimes /* 7854b88c807SRodney W. Grimes * look to see if this device is already in the table 7864b88c807SRodney W. Grimes */ 7874b88c807SRodney W. Grimes indx = ((unsigned)dev) % D_TAB_SZ; 7884b88c807SRodney W. Grimes if ((pt = dtab[indx]) != NULL) { 7894b88c807SRodney W. Grimes while ((pt != NULL) && (pt->dev != dev)) 7904b88c807SRodney W. Grimes pt = pt->fow; 7914b88c807SRodney W. Grimes 7924b88c807SRodney W. Grimes /* 7934b88c807SRodney W. Grimes * found it, return a pointer to it 7944b88c807SRodney W. Grimes */ 7954b88c807SRodney W. Grimes if (pt != NULL) 7964b88c807SRodney W. Grimes return(pt); 7974b88c807SRodney W. Grimes } 7984b88c807SRodney W. Grimes 7994b88c807SRodney W. Grimes /* 8004b88c807SRodney W. Grimes * not in table, we add it only if told to as this may just be a check 8014b88c807SRodney W. Grimes * to see if a device number is being used. 8024b88c807SRodney W. Grimes */ 8034b88c807SRodney W. Grimes if (add == 0) 8044b88c807SRodney W. Grimes return(NULL); 8054b88c807SRodney W. Grimes 8064b88c807SRodney W. Grimes /* 8074b88c807SRodney W. Grimes * allocate a node for this device and add it to the front of the hash 8084b88c807SRodney W. Grimes * chain. Note we do not assign remaps values here, so the pt->list 8094b88c807SRodney W. Grimes * list must be NULL. 8104b88c807SRodney W. Grimes */ 8114b88c807SRodney W. Grimes if ((pt = (DEVT *)malloc(sizeof(DEVT))) == NULL) { 812a885d9dcSSøren Schmidt pax_warn(1, "Device map table out of memory"); 8134b88c807SRodney W. Grimes return(NULL); 8144b88c807SRodney W. Grimes } 8154b88c807SRodney W. Grimes pt->dev = dev; 8164b88c807SRodney W. Grimes pt->list = NULL; 8174b88c807SRodney W. Grimes pt->fow = dtab[indx]; 8184b88c807SRodney W. Grimes dtab[indx] = pt; 8194b88c807SRodney W. Grimes return(pt); 8204b88c807SRodney W. Grimes } 8214b88c807SRodney W. Grimes /* 8224b88c807SRodney W. Grimes * map_dev() 8234b88c807SRodney W. Grimes * given an inode and device storage mask (the mask has a 1 for each bit 8244b88c807SRodney W. Grimes * the archive format is able to store in a header), we check for inode 8254b88c807SRodney W. Grimes * and device truncation and remap the device as required. Device mapping 8264b88c807SRodney W. Grimes * can also occur when during the read phase of append a device number was 8274b88c807SRodney W. Grimes * seen (and was marked as do not use during the write phase). WE ASSUME 8284b88c807SRodney W. Grimes * that unsigned longs are the same size or bigger than the fields used 8294b88c807SRodney W. Grimes * for ino_t and dev_t. If not the types will have to be changed. 8304b88c807SRodney W. Grimes * Return: 8314b88c807SRodney W. Grimes * 0 if all ok, -1 otherwise. 8324b88c807SRodney W. Grimes */ 8334b88c807SRodney W. Grimes 8344b88c807SRodney W. Grimes #if __STDC__ 8354b88c807SRodney W. Grimes int 8364b88c807SRodney W. Grimes map_dev(register ARCHD *arcn, u_long dev_mask, u_long ino_mask) 8374b88c807SRodney W. Grimes #else 8384b88c807SRodney W. Grimes int 8394b88c807SRodney W. Grimes map_dev(arcn, dev_mask, ino_mask) 8404b88c807SRodney W. Grimes register ARCHD *arcn; 8414b88c807SRodney W. Grimes u_long dev_mask; 8424b88c807SRodney W. Grimes u_long ino_mask; 8434b88c807SRodney W. Grimes #endif 8444b88c807SRodney W. Grimes { 8454b88c807SRodney W. Grimes register DEVT *pt; 8464b88c807SRodney W. Grimes register DLIST *dpt; 8474b88c807SRodney W. Grimes static dev_t lastdev = 0; /* next device number to try */ 8484b88c807SRodney W. Grimes int trc_ino = 0; 8494b88c807SRodney W. Grimes int trc_dev = 0; 8504b88c807SRodney W. Grimes ino_t trunc_bits = 0; 8514b88c807SRodney W. Grimes ino_t nino; 8524b88c807SRodney W. Grimes 8534b88c807SRodney W. Grimes if (dtab == NULL) 8544b88c807SRodney W. Grimes return(0); 8554b88c807SRodney W. Grimes /* 8564b88c807SRodney W. Grimes * check for device and inode truncation, and extract the truncated 8574b88c807SRodney W. Grimes * bit pattern. 8584b88c807SRodney W. Grimes */ 8594b88c807SRodney W. Grimes if ((arcn->sb.st_dev & (dev_t)dev_mask) != arcn->sb.st_dev) 8604b88c807SRodney W. Grimes ++trc_dev; 8614b88c807SRodney W. Grimes if ((nino = arcn->sb.st_ino & (ino_t)ino_mask) != arcn->sb.st_ino) { 8624b88c807SRodney W. Grimes ++trc_ino; 8634b88c807SRodney W. Grimes trunc_bits = arcn->sb.st_ino & (ino_t)(~ino_mask); 8644b88c807SRodney W. Grimes } 8654b88c807SRodney W. Grimes 8664b88c807SRodney W. Grimes /* 8674b88c807SRodney W. Grimes * see if this device is already being mapped, look up the device 8684b88c807SRodney W. Grimes * then find the truncation bit pattern which applies 8694b88c807SRodney W. Grimes */ 8704b88c807SRodney W. Grimes if ((pt = chk_dev(arcn->sb.st_dev, 0)) != NULL) { 8714b88c807SRodney W. Grimes /* 8724b88c807SRodney W. Grimes * this device is already marked to be remapped 8734b88c807SRodney W. Grimes */ 8744b88c807SRodney W. Grimes for (dpt = pt->list; dpt != NULL; dpt = dpt->fow) 8754b88c807SRodney W. Grimes if (dpt->trunc_bits == trunc_bits) 8764b88c807SRodney W. Grimes break; 8774b88c807SRodney W. Grimes 8784b88c807SRodney W. Grimes if (dpt != NULL) { 8794b88c807SRodney W. Grimes /* 8804b88c807SRodney W. Grimes * we are being remapped for this device and pattern 8814b88c807SRodney W. Grimes * change the device number to be stored and return 8824b88c807SRodney W. Grimes */ 8834b88c807SRodney W. Grimes arcn->sb.st_dev = dpt->dev; 8844b88c807SRodney W. Grimes arcn->sb.st_ino = nino; 8854b88c807SRodney W. Grimes return(0); 8864b88c807SRodney W. Grimes } 8874b88c807SRodney W. Grimes } else { 8884b88c807SRodney W. Grimes /* 8894b88c807SRodney W. Grimes * this device is not being remapped YET. if we do not have any 8904b88c807SRodney W. Grimes * form of truncation, we do not need a remap 8914b88c807SRodney W. Grimes */ 8924b88c807SRodney W. Grimes if (!trc_ino && !trc_dev) 8934b88c807SRodney W. Grimes return(0); 8944b88c807SRodney W. Grimes 8954b88c807SRodney W. Grimes /* 8964b88c807SRodney W. Grimes * we have truncation, have to add this as a device to remap 8974b88c807SRodney W. Grimes */ 8984b88c807SRodney W. Grimes if ((pt = chk_dev(arcn->sb.st_dev, 1)) == NULL) 8994b88c807SRodney W. Grimes goto bad; 9004b88c807SRodney W. Grimes 9014b88c807SRodney W. Grimes /* 9024b88c807SRodney W. Grimes * if we just have a truncated inode, we have to make sure that 9034b88c807SRodney W. Grimes * all future inodes that do not truncate (they have the 9044b88c807SRodney W. Grimes * truncation pattern of all 0's) continue to map to the same 9054b88c807SRodney W. Grimes * device number. We probably have already written inodes with 9064b88c807SRodney W. Grimes * this device number to the archive with the truncation 9074b88c807SRodney W. Grimes * pattern of all 0's. So we add the mapping for all 0's to the 9084b88c807SRodney W. Grimes * same device number. 9094b88c807SRodney W. Grimes */ 9104b88c807SRodney W. Grimes if (!trc_dev && (trunc_bits != 0)) { 9114b88c807SRodney W. Grimes if ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL) 9124b88c807SRodney W. Grimes goto bad; 9134b88c807SRodney W. Grimes dpt->trunc_bits = 0; 9144b88c807SRodney W. Grimes dpt->dev = arcn->sb.st_dev; 9154b88c807SRodney W. Grimes dpt->fow = pt->list; 9164b88c807SRodney W. Grimes pt->list = dpt; 9174b88c807SRodney W. Grimes } 9184b88c807SRodney W. Grimes } 9194b88c807SRodney W. Grimes 9204b88c807SRodney W. Grimes /* 9214b88c807SRodney W. Grimes * look for a device number not being used. We must watch for wrap 9224b88c807SRodney W. Grimes * around on lastdev (so we do not get stuck looking forever!) 9234b88c807SRodney W. Grimes */ 9244b88c807SRodney W. Grimes while (++lastdev > 0) { 9254b88c807SRodney W. Grimes if (chk_dev(lastdev, 0) != NULL) 9264b88c807SRodney W. Grimes continue; 9274b88c807SRodney W. Grimes /* 9284b88c807SRodney W. Grimes * found an unused value. If we have reached truncation point 9294b88c807SRodney W. Grimes * for this format we are hosed, so we give up. Otherwise we 9304b88c807SRodney W. Grimes * mark it as being used. 9314b88c807SRodney W. Grimes */ 9324b88c807SRodney W. Grimes if (((lastdev & ((dev_t)dev_mask)) != lastdev) || 9334b88c807SRodney W. Grimes (chk_dev(lastdev, 1) == NULL)) 9344b88c807SRodney W. Grimes goto bad; 9354b88c807SRodney W. Grimes break; 9364b88c807SRodney W. Grimes } 9374b88c807SRodney W. Grimes 9384b88c807SRodney W. Grimes if ((lastdev <= 0) || ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL)) 9394b88c807SRodney W. Grimes goto bad; 9404b88c807SRodney W. Grimes 9414b88c807SRodney W. Grimes /* 9424b88c807SRodney W. Grimes * got a new device number, store it under this truncation pattern. 9434b88c807SRodney W. Grimes * change the device number this file is being stored with. 9444b88c807SRodney W. Grimes */ 9454b88c807SRodney W. Grimes dpt->trunc_bits = trunc_bits; 9464b88c807SRodney W. Grimes dpt->dev = lastdev; 9474b88c807SRodney W. Grimes dpt->fow = pt->list; 9484b88c807SRodney W. Grimes pt->list = dpt; 9494b88c807SRodney W. Grimes arcn->sb.st_dev = lastdev; 9504b88c807SRodney W. Grimes arcn->sb.st_ino = nino; 9514b88c807SRodney W. Grimes return(0); 9524b88c807SRodney W. Grimes 9534b88c807SRodney W. Grimes bad: 954a885d9dcSSøren Schmidt pax_warn(1, "Unable to fix truncated inode/device field when storing %s", 9554b88c807SRodney W. Grimes arcn->name); 956a885d9dcSSøren Schmidt pax_warn(0, "Archive may create improper hard links when extracted"); 9574b88c807SRodney W. Grimes return(0); 9584b88c807SRodney W. Grimes } 9594b88c807SRodney W. Grimes 9604b88c807SRodney W. Grimes /* 9614b88c807SRodney W. Grimes * directory access/mod time reset table routines (for directories READ by pax) 9624b88c807SRodney W. Grimes * 9634b88c807SRodney W. Grimes * The pax -t flag requires that access times of archive files to be the same 9644b88c807SRodney W. Grimes * before being read by pax. For regular files, access time is restored after 9654b88c807SRodney W. Grimes * the file has been copied. This database provides the same functionality for 9664b88c807SRodney W. Grimes * directories read during file tree traversal. Restoring directory access time 9674b88c807SRodney W. Grimes * is more complex than files since directories may be read several times until 9684b88c807SRodney W. Grimes * all the descendants in their subtree are visited by fts. Directory access 9694b88c807SRodney W. Grimes * and modification times are stored during the fts pre-order visit (done 9704b88c807SRodney W. Grimes * before any descendants in the subtree is visited) and restored after the 9714b88c807SRodney W. Grimes * fts post-order visit (after all the descendants have been visited). In the 9724b88c807SRodney W. Grimes * case of premature exit from a subtree (like from the effects of -n), any 9734b88c807SRodney W. Grimes * directory entries left in this database are reset during final cleanup 9744b88c807SRodney W. Grimes * operations of pax. Entries are hashed by inode number for fast lookup. 9754b88c807SRodney W. Grimes */ 9764b88c807SRodney W. Grimes 9774b88c807SRodney W. Grimes /* 9784b88c807SRodney W. Grimes * atdir_start() 9794b88c807SRodney W. Grimes * create the directory access time database for directories READ by pax. 9804b88c807SRodney W. Grimes * Return: 9814b88c807SRodney W. Grimes * 0 is created ok, -1 otherwise. 9824b88c807SRodney W. Grimes */ 9834b88c807SRodney W. Grimes 9844b88c807SRodney W. Grimes #if __STDC__ 9854b88c807SRodney W. Grimes int 9864b88c807SRodney W. Grimes atdir_start(void) 9874b88c807SRodney W. Grimes #else 9884b88c807SRodney W. Grimes int 9894b88c807SRodney W. Grimes atdir_start() 9904b88c807SRodney W. Grimes #endif 9914b88c807SRodney W. Grimes { 9924b88c807SRodney W. Grimes if (atab != NULL) 9934b88c807SRodney W. Grimes return(0); 9944b88c807SRodney W. Grimes if ((atab = (ATDIR **)calloc(A_TAB_SZ, sizeof(ATDIR *))) == NULL) { 995a885d9dcSSøren Schmidt pax_warn(1,"Cannot allocate space for directory access time table"); 9964b88c807SRodney W. Grimes return(-1); 9974b88c807SRodney W. Grimes } 9984b88c807SRodney W. Grimes return(0); 9994b88c807SRodney W. Grimes } 10004b88c807SRodney W. Grimes 10014b88c807SRodney W. Grimes 10024b88c807SRodney W. Grimes /* 10034b88c807SRodney W. Grimes * atdir_end() 10044b88c807SRodney W. Grimes * walk through the directory access time table and reset the access time 10054b88c807SRodney W. Grimes * of any directory who still has an entry left in the database. These 10064b88c807SRodney W. Grimes * entries are for directories READ by pax 10074b88c807SRodney W. Grimes */ 10084b88c807SRodney W. Grimes 10094b88c807SRodney W. Grimes #if __STDC__ 10104b88c807SRodney W. Grimes void 10114b88c807SRodney W. Grimes atdir_end(void) 10124b88c807SRodney W. Grimes #else 10134b88c807SRodney W. Grimes void 10144b88c807SRodney W. Grimes atdir_end() 10154b88c807SRodney W. Grimes #endif 10164b88c807SRodney W. Grimes { 10174b88c807SRodney W. Grimes register ATDIR *pt; 10184b88c807SRodney W. Grimes register int i; 10194b88c807SRodney W. Grimes 10204b88c807SRodney W. Grimes if (atab == NULL) 10214b88c807SRodney W. Grimes return; 10224b88c807SRodney W. Grimes /* 10234b88c807SRodney W. Grimes * for each non-empty hash table entry reset all the directories 10244b88c807SRodney W. Grimes * chained there. 10254b88c807SRodney W. Grimes */ 10264b88c807SRodney W. Grimes for (i = 0; i < A_TAB_SZ; ++i) { 10274b88c807SRodney W. Grimes if ((pt = atab[i]) == NULL) 10284b88c807SRodney W. Grimes continue; 10294b88c807SRodney W. Grimes /* 10304b88c807SRodney W. Grimes * remember to force the times, set_ftime() looks at pmtime 10314b88c807SRodney W. Grimes * and patime, which only applies to things CREATED by pax, 10324b88c807SRodney W. Grimes * not read by pax. Read time reset is controlled by -t. 10334b88c807SRodney W. Grimes */ 10344b88c807SRodney W. Grimes for (; pt != NULL; pt = pt->fow) 10354b88c807SRodney W. Grimes set_ftime(pt->name, pt->mtime, pt->atime, 1); 10364b88c807SRodney W. Grimes } 10374b88c807SRodney W. Grimes } 10384b88c807SRodney W. Grimes 10394b88c807SRodney W. Grimes /* 10404b88c807SRodney W. Grimes * add_atdir() 10414b88c807SRodney W. Grimes * add a directory to the directory access time table. Table is hashed 10424b88c807SRodney W. Grimes * and chained by inode number. This is for directories READ by pax 10434b88c807SRodney W. Grimes */ 10444b88c807SRodney W. Grimes 10454b88c807SRodney W. Grimes #if __STDC__ 10464b88c807SRodney W. Grimes void 10474b88c807SRodney W. Grimes add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime) 10484b88c807SRodney W. Grimes #else 10494b88c807SRodney W. Grimes void 10504b88c807SRodney W. Grimes add_atdir(fname, dev, ino, mtime, atime) 10514b88c807SRodney W. Grimes char *fname; 10524b88c807SRodney W. Grimes dev_t dev; 10534b88c807SRodney W. Grimes ino_t ino; 10544b88c807SRodney W. Grimes time_t mtime; 10554b88c807SRodney W. Grimes time_t atime; 10564b88c807SRodney W. Grimes #endif 10574b88c807SRodney W. Grimes { 10584b88c807SRodney W. Grimes register ATDIR *pt; 10594b88c807SRodney W. Grimes register u_int indx; 10604b88c807SRodney W. Grimes 10614b88c807SRodney W. Grimes if (atab == NULL) 10624b88c807SRodney W. Grimes return; 10634b88c807SRodney W. Grimes 10644b88c807SRodney W. Grimes /* 10654b88c807SRodney W. Grimes * make sure this directory is not already in the table, if so just 10664b88c807SRodney W. Grimes * return (the older entry always has the correct time). The only 10674b88c807SRodney W. Grimes * way this will happen is when the same subtree can be traversed by 10684b88c807SRodney W. Grimes * different args to pax and the -n option is aborting fts out of a 10694b88c807SRodney W. Grimes * subtree before all the post-order visits have been made). 10704b88c807SRodney W. Grimes */ 10714b88c807SRodney W. Grimes indx = ((unsigned)ino) % A_TAB_SZ; 10724b88c807SRodney W. Grimes if ((pt = atab[indx]) != NULL) { 10734b88c807SRodney W. Grimes while (pt != NULL) { 10744b88c807SRodney W. Grimes if ((pt->ino == ino) && (pt->dev == dev)) 10754b88c807SRodney W. Grimes break; 10764b88c807SRodney W. Grimes pt = pt->fow; 10774b88c807SRodney W. Grimes } 10784b88c807SRodney W. Grimes 10794b88c807SRodney W. Grimes /* 10804b88c807SRodney W. Grimes * oops, already there. Leave it alone. 10814b88c807SRodney W. Grimes */ 10824b88c807SRodney W. Grimes if (pt != NULL) 10834b88c807SRodney W. Grimes return; 10844b88c807SRodney W. Grimes } 10854b88c807SRodney W. Grimes 10864b88c807SRodney W. Grimes /* 10874b88c807SRodney W. Grimes * add it to the front of the hash chain 10884b88c807SRodney W. Grimes */ 10894b88c807SRodney W. Grimes if ((pt = (ATDIR *)malloc(sizeof(ATDIR))) != NULL) { 10904b88c807SRodney W. Grimes if ((pt->name = strdup(fname)) != NULL) { 10914b88c807SRodney W. Grimes pt->dev = dev; 10924b88c807SRodney W. Grimes pt->ino = ino; 10934b88c807SRodney W. Grimes pt->mtime = mtime; 10944b88c807SRodney W. Grimes pt->atime = atime; 10954b88c807SRodney W. Grimes pt->fow = atab[indx]; 10964b88c807SRodney W. Grimes atab[indx] = pt; 10974b88c807SRodney W. Grimes return; 10984b88c807SRodney W. Grimes } 10994b88c807SRodney W. Grimes (void)free((char *)pt); 11004b88c807SRodney W. Grimes } 11014b88c807SRodney W. Grimes 1102a885d9dcSSøren Schmidt pax_warn(1, "Directory access time reset table ran out of memory"); 11034b88c807SRodney W. Grimes return; 11044b88c807SRodney W. Grimes } 11054b88c807SRodney W. Grimes 11064b88c807SRodney W. Grimes /* 11074b88c807SRodney W. Grimes * get_atdir() 11084b88c807SRodney W. Grimes * look up a directory by inode and device number to obtain the access 11094b88c807SRodney W. Grimes * and modification time you want to set to. If found, the modification 11104b88c807SRodney W. Grimes * and access time parameters are set and the entry is removed from the 11114b88c807SRodney W. Grimes * table (as it is no longer needed). These are for directories READ by 11124b88c807SRodney W. Grimes * pax 11134b88c807SRodney W. Grimes * Return: 11144b88c807SRodney W. Grimes * 0 if found, -1 if not found. 11154b88c807SRodney W. Grimes */ 11164b88c807SRodney W. Grimes 11174b88c807SRodney W. Grimes #if __STDC__ 11184b88c807SRodney W. Grimes int 11194b88c807SRodney W. Grimes get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) 11204b88c807SRodney W. Grimes #else 11214b88c807SRodney W. Grimes int 11224b88c807SRodney W. Grimes get_atdir(dev, ino, mtime, atime) 11234b88c807SRodney W. Grimes dev_t dev; 11244b88c807SRodney W. Grimes ino_t ino; 11254b88c807SRodney W. Grimes time_t *mtime; 11264b88c807SRodney W. Grimes time_t *atime; 11274b88c807SRodney W. Grimes #endif 11284b88c807SRodney W. Grimes { 11294b88c807SRodney W. Grimes register ATDIR *pt; 11304b88c807SRodney W. Grimes register ATDIR **ppt; 11314b88c807SRodney W. Grimes register u_int indx; 11324b88c807SRodney W. Grimes 11334b88c807SRodney W. Grimes if (atab == NULL) 11344b88c807SRodney W. Grimes return(-1); 11354b88c807SRodney W. Grimes /* 11364b88c807SRodney W. Grimes * hash by inode and search the chain for an inode and device match 11374b88c807SRodney W. Grimes */ 11384b88c807SRodney W. Grimes indx = ((unsigned)ino) % A_TAB_SZ; 11394b88c807SRodney W. Grimes if ((pt = atab[indx]) == NULL) 11404b88c807SRodney W. Grimes return(-1); 11414b88c807SRodney W. Grimes 11424b88c807SRodney W. Grimes ppt = &(atab[indx]); 11434b88c807SRodney W. Grimes while (pt != NULL) { 11444b88c807SRodney W. Grimes if ((pt->ino == ino) && (pt->dev == dev)) 11454b88c807SRodney W. Grimes break; 11464b88c807SRodney W. Grimes /* 11474b88c807SRodney W. Grimes * no match, go to next one 11484b88c807SRodney W. Grimes */ 11494b88c807SRodney W. Grimes ppt = &(pt->fow); 11504b88c807SRodney W. Grimes pt = pt->fow; 11514b88c807SRodney W. Grimes } 11524b88c807SRodney W. Grimes 11534b88c807SRodney W. Grimes /* 11544b88c807SRodney W. Grimes * return if we did not find it. 11554b88c807SRodney W. Grimes */ 11564b88c807SRodney W. Grimes if (pt == NULL) 11574b88c807SRodney W. Grimes return(-1); 11584b88c807SRodney W. Grimes 11594b88c807SRodney W. Grimes /* 11604b88c807SRodney W. Grimes * found it. return the times and remove the entry from the table. 11614b88c807SRodney W. Grimes */ 11624b88c807SRodney W. Grimes *ppt = pt->fow; 11634b88c807SRodney W. Grimes *mtime = pt->mtime; 11644b88c807SRodney W. Grimes *atime = pt->atime; 11654b88c807SRodney W. Grimes (void)free((char *)pt->name); 11664b88c807SRodney W. Grimes (void)free((char *)pt); 11674b88c807SRodney W. Grimes return(0); 11684b88c807SRodney W. Grimes } 11694b88c807SRodney W. Grimes 11704b88c807SRodney W. Grimes /* 11714b88c807SRodney W. Grimes * directory access mode and time storage routines (for directories CREATED 11724b88c807SRodney W. Grimes * by pax). 11734b88c807SRodney W. Grimes * 11744b88c807SRodney W. Grimes * Pax requires that extracted directories, by default, have their access/mod 11754b88c807SRodney W. Grimes * times and permissions set to the values specified in the archive. During the 11764b88c807SRodney W. Grimes * actions of extracting (and creating the destination subtree during -rw copy) 11774b88c807SRodney W. Grimes * directories extracted may be modified after being created. Even worse is 11784b88c807SRodney W. Grimes * that these directories may have been created with file permissions which 11794b88c807SRodney W. Grimes * prohibits any descendants of these directories from being extracted. When 11804b88c807SRodney W. Grimes * directories are created by pax, access rights may be added to permit the 11814b88c807SRodney W. Grimes * creation of files in their subtree. Every time pax creates a directory, the 11824b88c807SRodney W. Grimes * times and file permissions specified by the archive are stored. After all 11834b88c807SRodney W. Grimes * files have been extracted (or copied), these directories have their times 11844b88c807SRodney W. Grimes * and file modes reset to the stored values. The directory info is restored in 11854b88c807SRodney W. Grimes * reverse order as entries were added to the data file from root to leaf. To 11864b88c807SRodney W. Grimes * restore atime properly, we must go backwards. The data file consists of 11874b88c807SRodney W. Grimes * records with two parts, the file name followed by a DIRDATA trailer. The 11884b88c807SRodney W. Grimes * fixed sized trailer contains the size of the name plus the off_t location in 11894b88c807SRodney W. Grimes * the file. To restore we work backwards through the file reading the trailer 11904b88c807SRodney W. Grimes * then the file name. 11914b88c807SRodney W. Grimes */ 11924b88c807SRodney W. Grimes 11934b88c807SRodney W. Grimes /* 11944b88c807SRodney W. Grimes * dir_start() 11954b88c807SRodney W. Grimes * set up the directory time and file mode storage for directories CREATED 11964b88c807SRodney W. Grimes * by pax. 11974b88c807SRodney W. Grimes * Return: 11984b88c807SRodney W. Grimes * 0 if ok, -1 otherwise 11994b88c807SRodney W. Grimes */ 12004b88c807SRodney W. Grimes 12014b88c807SRodney W. Grimes #if __STDC__ 12024b88c807SRodney W. Grimes int 12034b88c807SRodney W. Grimes dir_start(void) 12044b88c807SRodney W. Grimes #else 12054b88c807SRodney W. Grimes int 12064b88c807SRodney W. Grimes dir_start() 12074b88c807SRodney W. Grimes #endif 12084b88c807SRodney W. Grimes { 12094b88c807SRodney W. Grimes if (dirfd != -1) 12104b88c807SRodney W. Grimes return(0); 12114b88c807SRodney W. Grimes 12124b88c807SRodney W. Grimes /* 12134b88c807SRodney W. Grimes * unlink the file so it goes away at termination by itself 12144b88c807SRodney W. Grimes */ 1215ffbef1cdSKris Kennaway memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE)); 1216ffbef1cdSKris Kennaway if ((dirfd = mkstemp(tempfile)) >= 0) { 1217ffbef1cdSKris Kennaway (void)unlink(tempfile); 12184b88c807SRodney W. Grimes return(0); 12194b88c807SRodney W. Grimes } 1220ffbef1cdSKris Kennaway pax_warn(1, "Unable to create temporary file for directory times: %s", 1221ffbef1cdSKris Kennaway tempfile); 12224b88c807SRodney W. Grimes return(-1); 12234b88c807SRodney W. Grimes } 12244b88c807SRodney W. Grimes 12254b88c807SRodney W. Grimes /* 12264b88c807SRodney W. Grimes * add_dir() 12274b88c807SRodney W. Grimes * add the mode and times for a newly CREATED directory 12284b88c807SRodney W. Grimes * name is name of the directory, psb the stat buffer with the data in it, 12294b88c807SRodney W. Grimes * frc_mode is a flag that says whether to force the setting of the mode 12304b88c807SRodney W. Grimes * (ignoring the user set values for preserving file mode). Frc_mode is 12314b88c807SRodney W. Grimes * for the case where we created a file and found that the resulting 12324b88c807SRodney W. Grimes * directory was not writeable and the user asked for file modes to NOT 12334b88c807SRodney W. Grimes * be preserved. (we have to preserve what was created by default, so we 12344b88c807SRodney W. Grimes * have to force the setting at the end. this is stated explicitly in the 12354b88c807SRodney W. Grimes * pax spec) 12364b88c807SRodney W. Grimes */ 12374b88c807SRodney W. Grimes 12384b88c807SRodney W. Grimes #if __STDC__ 12394b88c807SRodney W. Grimes void 12404b88c807SRodney W. Grimes add_dir(char *name, int nlen, struct stat *psb, int frc_mode) 12414b88c807SRodney W. Grimes #else 12424b88c807SRodney W. Grimes void 12434b88c807SRodney W. Grimes add_dir(name, nlen, psb, frc_mode) 12444b88c807SRodney W. Grimes char *name; 12454b88c807SRodney W. Grimes int nlen; 12464b88c807SRodney W. Grimes struct stat *psb; 12474b88c807SRodney W. Grimes int frc_mode; 12484b88c807SRodney W. Grimes #endif 12494b88c807SRodney W. Grimes { 12504b88c807SRodney W. Grimes DIRDATA dblk; 12514b88c807SRodney W. Grimes 12524b88c807SRodney W. Grimes if (dirfd < 0) 12534b88c807SRodney W. Grimes return; 12544b88c807SRodney W. Grimes 12554b88c807SRodney W. Grimes /* 12564b88c807SRodney W. Grimes * get current position (where file name will start) so we can store it 12574b88c807SRodney W. Grimes * in the trailer 12584b88c807SRodney W. Grimes */ 12594b88c807SRodney W. Grimes if ((dblk.npos = lseek(dirfd, 0L, SEEK_CUR)) < 0) { 1260a885d9dcSSøren Schmidt pax_warn(1,"Unable to store mode and times for directory: %s",name); 12614b88c807SRodney W. Grimes return; 12624b88c807SRodney W. Grimes } 12634b88c807SRodney W. Grimes 12644b88c807SRodney W. Grimes /* 12654b88c807SRodney W. Grimes * write the file name followed by the trailer 12664b88c807SRodney W. Grimes */ 12674b88c807SRodney W. Grimes dblk.nlen = nlen + 1; 12684b88c807SRodney W. Grimes dblk.mode = psb->st_mode & 0xffff; 12694b88c807SRodney W. Grimes dblk.mtime = psb->st_mtime; 12704b88c807SRodney W. Grimes dblk.atime = psb->st_atime; 12714b88c807SRodney W. Grimes dblk.frc_mode = frc_mode; 12724b88c807SRodney W. Grimes if ((write(dirfd, name, dblk.nlen) == dblk.nlen) && 12734b88c807SRodney W. Grimes (write(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) { 12744b88c807SRodney W. Grimes ++dircnt; 12754b88c807SRodney W. Grimes return; 12764b88c807SRodney W. Grimes } 12774b88c807SRodney W. Grimes 1278a885d9dcSSøren Schmidt pax_warn(1,"Unable to store mode and times for created directory: %s",name); 12794b88c807SRodney W. Grimes return; 12804b88c807SRodney W. Grimes } 12814b88c807SRodney W. Grimes 12824b88c807SRodney W. Grimes /* 12834b88c807SRodney W. Grimes * proc_dir() 12844b88c807SRodney W. Grimes * process all file modes and times stored for directories CREATED 12854b88c807SRodney W. Grimes * by pax 12864b88c807SRodney W. Grimes */ 12874b88c807SRodney W. Grimes 12884b88c807SRodney W. Grimes #if __STDC__ 12894b88c807SRodney W. Grimes void 12904b88c807SRodney W. Grimes proc_dir(void) 12914b88c807SRodney W. Grimes #else 12924b88c807SRodney W. Grimes void 12934b88c807SRodney W. Grimes proc_dir() 12944b88c807SRodney W. Grimes #endif 12954b88c807SRodney W. Grimes { 12964b88c807SRodney W. Grimes char name[PAXPATHLEN+1]; 12974b88c807SRodney W. Grimes DIRDATA dblk; 12984b88c807SRodney W. Grimes u_long cnt; 12994b88c807SRodney W. Grimes 13004b88c807SRodney W. Grimes if (dirfd < 0) 13014b88c807SRodney W. Grimes return; 13024b88c807SRodney W. Grimes /* 13034b88c807SRodney W. Grimes * read backwards through the file and process each directory 13044b88c807SRodney W. Grimes */ 13054b88c807SRodney W. Grimes for (cnt = 0; cnt < dircnt; ++cnt) { 13064b88c807SRodney W. Grimes /* 13074b88c807SRodney W. Grimes * read the trailer, then the file name, if this fails 13084b88c807SRodney W. Grimes * just give up. 13094b88c807SRodney W. Grimes */ 13104b88c807SRodney W. Grimes if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0) 13114b88c807SRodney W. Grimes break; 13124b88c807SRodney W. Grimes if (read(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk)) 13134b88c807SRodney W. Grimes break; 13144b88c807SRodney W. Grimes if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) 13154b88c807SRodney W. Grimes break; 13164b88c807SRodney W. Grimes if (read(dirfd, name, dblk.nlen) != dblk.nlen) 13174b88c807SRodney W. Grimes break; 13184b88c807SRodney W. Grimes if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) 13194b88c807SRodney W. Grimes break; 13204b88c807SRodney W. Grimes 13214b88c807SRodney W. Grimes /* 13224b88c807SRodney W. Grimes * frc_mode set, make sure we set the file modes even if 13234b88c807SRodney W. Grimes * the user didn't ask for it (see file_subs.c for more info) 13244b88c807SRodney W. Grimes */ 13254b88c807SRodney W. Grimes if (pmode || dblk.frc_mode) 13264b88c807SRodney W. Grimes set_pmode(name, dblk.mode); 13274b88c807SRodney W. Grimes if (patime || pmtime) 13284b88c807SRodney W. Grimes set_ftime(name, dblk.mtime, dblk.atime, 0); 13294b88c807SRodney W. Grimes } 13304b88c807SRodney W. Grimes 13314b88c807SRodney W. Grimes (void)close(dirfd); 13324b88c807SRodney W. Grimes dirfd = -1; 13334b88c807SRodney W. Grimes if (cnt != dircnt) 1334a885d9dcSSøren Schmidt pax_warn(1,"Unable to set mode and times for created directories"); 13354b88c807SRodney W. Grimes return; 13364b88c807SRodney W. Grimes } 13374b88c807SRodney W. Grimes 13384b88c807SRodney W. Grimes /* 13394b88c807SRodney W. Grimes * database independent routines 13404b88c807SRodney W. Grimes */ 13414b88c807SRodney W. Grimes 13424b88c807SRodney W. Grimes /* 13434b88c807SRodney W. Grimes * st_hash() 13444b88c807SRodney W. Grimes * hashes filenames to a u_int for hashing into a table. Looks at the tail 13454b88c807SRodney W. Grimes * end of file, as this provides far better distribution than any other 13464b88c807SRodney W. Grimes * part of the name. For performance reasons we only care about the last 13474b88c807SRodney W. Grimes * MAXKEYLEN chars (should be at LEAST large enough to pick off the file 13484b88c807SRodney W. Grimes * name). Was tested on 500,000 name file tree traversal from the root 13494b88c807SRodney W. Grimes * and gave almost a perfectly uniform distribution of keys when used with 13504b88c807SRodney W. Grimes * prime sized tables (MAXKEYLEN was 128 in test). Hashes (sizeof int) 13514b88c807SRodney W. Grimes * chars at a time and pads with 0 for last addition. 13524b88c807SRodney W. Grimes * Return: 13534b88c807SRodney W. Grimes * the hash value of the string MOD (%) the table size. 13544b88c807SRodney W. Grimes */ 13554b88c807SRodney W. Grimes 13564b88c807SRodney W. Grimes #if __STDC__ 13574b88c807SRodney W. Grimes u_int 13584b88c807SRodney W. Grimes st_hash(char *name, int len, int tabsz) 13594b88c807SRodney W. Grimes #else 13604b88c807SRodney W. Grimes u_int 13614b88c807SRodney W. Grimes st_hash(name, len, tabsz) 13624b88c807SRodney W. Grimes char *name; 13634b88c807SRodney W. Grimes int len; 13644b88c807SRodney W. Grimes int tabsz; 13654b88c807SRodney W. Grimes #endif 13664b88c807SRodney W. Grimes { 13674b88c807SRodney W. Grimes register char *pt; 13684b88c807SRodney W. Grimes register char *dest; 13694b88c807SRodney W. Grimes register char *end; 13704b88c807SRodney W. Grimes register int i; 13714b88c807SRodney W. Grimes register u_int key = 0; 13724b88c807SRodney W. Grimes register int steps; 13734b88c807SRodney W. Grimes register int res; 13744b88c807SRodney W. Grimes u_int val; 13754b88c807SRodney W. Grimes 13764b88c807SRodney W. Grimes /* 13774b88c807SRodney W. Grimes * only look at the tail up to MAXKEYLEN, we do not need to waste 13784b88c807SRodney W. Grimes * time here (remember these are pathnames, the tail is what will 13794b88c807SRodney W. Grimes * spread out the keys) 13804b88c807SRodney W. Grimes */ 13814b88c807SRodney W. Grimes if (len > MAXKEYLEN) { 13824b88c807SRodney W. Grimes pt = &(name[len - MAXKEYLEN]); 13834b88c807SRodney W. Grimes len = MAXKEYLEN; 13844b88c807SRodney W. Grimes } else 13854b88c807SRodney W. Grimes pt = name; 13864b88c807SRodney W. Grimes 13874b88c807SRodney W. Grimes /* 13884b88c807SRodney W. Grimes * calculate the number of u_int size steps in the string and if 13894b88c807SRodney W. Grimes * there is a runt to deal with 13904b88c807SRodney W. Grimes */ 13914b88c807SRodney W. Grimes steps = len/sizeof(u_int); 13924b88c807SRodney W. Grimes res = len % sizeof(u_int); 13934b88c807SRodney W. Grimes 13944b88c807SRodney W. Grimes /* 13954b88c807SRodney W. Grimes * add up the value of the string in unsigned integer sized pieces 13964b88c807SRodney W. Grimes * too bad we cannot have unsigned int aligned strings, then we 13974b88c807SRodney W. Grimes * could avoid the expensive copy. 13984b88c807SRodney W. Grimes */ 13994b88c807SRodney W. Grimes for (i = 0; i < steps; ++i) { 14004b88c807SRodney W. Grimes end = pt + sizeof(u_int); 14014b88c807SRodney W. Grimes dest = (char *)&val; 14024b88c807SRodney W. Grimes while (pt < end) 14034b88c807SRodney W. Grimes *dest++ = *pt++; 14044b88c807SRodney W. Grimes key += val; 14054b88c807SRodney W. Grimes } 14064b88c807SRodney W. Grimes 14074b88c807SRodney W. Grimes /* 14084b88c807SRodney W. Grimes * add in the runt padded with zero to the right 14094b88c807SRodney W. Grimes */ 14104b88c807SRodney W. Grimes if (res) { 14114b88c807SRodney W. Grimes val = 0; 14124b88c807SRodney W. Grimes end = pt + res; 14134b88c807SRodney W. Grimes dest = (char *)&val; 14144b88c807SRodney W. Grimes while (pt < end) 14154b88c807SRodney W. Grimes *dest++ = *pt++; 14164b88c807SRodney W. Grimes key += val; 14174b88c807SRodney W. Grimes } 14184b88c807SRodney W. Grimes 14194b88c807SRodney W. Grimes /* 14204b88c807SRodney W. Grimes * return the result mod the table size 14214b88c807SRodney W. Grimes */ 14224b88c807SRodney W. Grimes return(key % tabsz); 14234b88c807SRodney W. Grimes } 1424