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 8346251ddeSWarner Losh static DEVT *chk_dev(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 int 1094b88c807SRodney W. Grimes lnk_start(void) 1104b88c807SRodney W. Grimes { 1114b88c807SRodney W. Grimes if (ltab != NULL) 1124b88c807SRodney W. Grimes return(0); 1134b88c807SRodney W. Grimes if ((ltab = (HRDLNK **)calloc(L_TAB_SZ, sizeof(HRDLNK *))) == NULL) { 114778766feSKris Kennaway paxwarn(1, "Cannot allocate memory for hard link table"); 1154b88c807SRodney W. Grimes return(-1); 1164b88c807SRodney W. Grimes } 1174b88c807SRodney W. Grimes return(0); 1184b88c807SRodney W. Grimes } 1194b88c807SRodney W. Grimes 1204b88c807SRodney W. Grimes /* 1214b88c807SRodney W. Grimes * chk_lnk() 1224b88c807SRodney W. Grimes * Looks up entry in hard link hash table. If found, it copies the name 1234b88c807SRodney W. Grimes * of the file it is linked to (we already saw that file) into ln_name. 1244b88c807SRodney W. Grimes * lnkcnt is decremented and if goes to 1 the node is deleted from the 1254b88c807SRodney W. Grimes * database. (We have seen all the links to this file). If not found, 1264b88c807SRodney W. Grimes * we add the file to the database if it has the potential for having 1274b88c807SRodney W. Grimes * hard links to other files we may process (it has a link count > 1) 1284b88c807SRodney W. Grimes * Return: 1294b88c807SRodney W. Grimes * if found returns 1; if not found returns 0; -1 on error 1304b88c807SRodney W. Grimes */ 1314b88c807SRodney W. Grimes 1324b88c807SRodney W. Grimes int 133f789b261SWarner Losh chk_lnk(ARCHD *arcn) 1344b88c807SRodney W. Grimes { 135f789b261SWarner Losh HRDLNK *pt; 136f789b261SWarner Losh HRDLNK **ppt; 137f789b261SWarner Losh u_int indx; 1384b88c807SRodney W. Grimes 1394b88c807SRodney W. Grimes if (ltab == NULL) 1404b88c807SRodney W. Grimes return(-1); 1414b88c807SRodney W. Grimes /* 1424b88c807SRodney W. Grimes * ignore those nodes that cannot have hard links 1434b88c807SRodney W. Grimes */ 1444b88c807SRodney W. Grimes if ((arcn->type == PAX_DIR) || (arcn->sb.st_nlink <= 1)) 1454b88c807SRodney W. Grimes return(0); 1464b88c807SRodney W. Grimes 1474b88c807SRodney W. Grimes /* 1484b88c807SRodney W. Grimes * hash inode number and look for this file 1494b88c807SRodney W. Grimes */ 1504b88c807SRodney W. Grimes indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ; 1514b88c807SRodney W. Grimes if ((pt = ltab[indx]) != NULL) { 1524b88c807SRodney W. Grimes /* 1534b88c807SRodney W. Grimes * it's hash chain in not empty, walk down looking for it 1544b88c807SRodney W. Grimes */ 1554b88c807SRodney W. Grimes ppt = &(ltab[indx]); 1564b88c807SRodney W. Grimes while (pt != NULL) { 1574b88c807SRodney W. Grimes if ((pt->ino == arcn->sb.st_ino) && 1584b88c807SRodney W. Grimes (pt->dev == arcn->sb.st_dev)) 1594b88c807SRodney W. Grimes break; 1604b88c807SRodney W. Grimes ppt = &(pt->fow); 1614b88c807SRodney W. Grimes pt = pt->fow; 1624b88c807SRodney W. Grimes } 1634b88c807SRodney W. Grimes 1644b88c807SRodney W. Grimes if (pt != NULL) { 1654b88c807SRodney W. Grimes /* 1664b88c807SRodney W. Grimes * found a link. set the node type and copy in the 1674b88c807SRodney W. Grimes * name of the file it is to link to. we need to 1684b88c807SRodney W. Grimes * handle hardlinks to regular files differently than 1694b88c807SRodney W. Grimes * other links. 1704b88c807SRodney W. Grimes */ 1714b88c807SRodney W. Grimes arcn->ln_nlen = l_strncpy(arcn->ln_name, pt->name, 172b1787decSKris Kennaway sizeof(arcn->ln_name) - 1); 173b1787decSKris Kennaway arcn->ln_name[arcn->ln_nlen] = '\0'; 1744b88c807SRodney W. Grimes if (arcn->type == PAX_REG) 1754b88c807SRodney W. Grimes arcn->type = PAX_HRG; 1764b88c807SRodney W. Grimes else 1774b88c807SRodney W. Grimes arcn->type = PAX_HLK; 1784b88c807SRodney W. Grimes 1794b88c807SRodney W. Grimes /* 1804b88c807SRodney W. Grimes * if we have found all the links to this file, remove 1814b88c807SRodney W. Grimes * it from the database 1824b88c807SRodney W. Grimes */ 1834b88c807SRodney W. Grimes if (--pt->nlink <= 1) { 1844b88c807SRodney W. Grimes *ppt = pt->fow; 1854b88c807SRodney W. Grimes (void)free((char *)pt->name); 1864b88c807SRodney W. Grimes (void)free((char *)pt); 1874b88c807SRodney W. Grimes } 1884b88c807SRodney W. Grimes return(1); 1894b88c807SRodney W. Grimes } 1904b88c807SRodney W. Grimes } 1914b88c807SRodney W. Grimes 1924b88c807SRodney W. Grimes /* 1934b88c807SRodney W. Grimes * we never saw this file before. It has links so we add it to the 1944b88c807SRodney W. Grimes * front of this hash chain 1954b88c807SRodney W. Grimes */ 1964b88c807SRodney W. Grimes if ((pt = (HRDLNK *)malloc(sizeof(HRDLNK))) != NULL) { 1974b88c807SRodney W. Grimes if ((pt->name = strdup(arcn->name)) != NULL) { 1984b88c807SRodney W. Grimes pt->dev = arcn->sb.st_dev; 1994b88c807SRodney W. Grimes pt->ino = arcn->sb.st_ino; 2004b88c807SRodney W. Grimes pt->nlink = arcn->sb.st_nlink; 2014b88c807SRodney W. Grimes pt->fow = ltab[indx]; 2024b88c807SRodney W. Grimes ltab[indx] = pt; 2034b88c807SRodney W. Grimes return(0); 2044b88c807SRodney W. Grimes } 2054b88c807SRodney W. Grimes (void)free((char *)pt); 2064b88c807SRodney W. Grimes } 2074b88c807SRodney W. Grimes 208778766feSKris Kennaway paxwarn(1, "Hard link table out of memory"); 2094b88c807SRodney W. Grimes return(-1); 2104b88c807SRodney W. Grimes } 2114b88c807SRodney W. Grimes 2124b88c807SRodney W. Grimes /* 2134b88c807SRodney W. Grimes * purg_lnk 2144b88c807SRodney W. Grimes * remove reference for a file that we may have added to the data base as 2154b88c807SRodney W. Grimes * a potential source for hard links. We ended up not using the file, so 2164b88c807SRodney W. Grimes * we do not want to accidently point another file at it later on. 2174b88c807SRodney W. Grimes */ 2184b88c807SRodney W. Grimes 2194b88c807SRodney W. Grimes void 220f789b261SWarner Losh purg_lnk(ARCHD *arcn) 2214b88c807SRodney W. Grimes { 222f789b261SWarner Losh HRDLNK *pt; 223f789b261SWarner Losh HRDLNK **ppt; 224f789b261SWarner Losh u_int indx; 2254b88c807SRodney W. Grimes 2264b88c807SRodney W. Grimes if (ltab == NULL) 2274b88c807SRodney W. Grimes return; 2284b88c807SRodney W. Grimes /* 2294b88c807SRodney W. Grimes * do not bother to look if it could not be in the database 2304b88c807SRodney W. Grimes */ 2314b88c807SRodney W. Grimes if ((arcn->sb.st_nlink <= 1) || (arcn->type == PAX_DIR) || 2324b88c807SRodney W. Grimes (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG)) 2334b88c807SRodney W. Grimes return; 2344b88c807SRodney W. Grimes 2354b88c807SRodney W. Grimes /* 2364b88c807SRodney W. Grimes * find the hash chain for this inode value, if empty return 2374b88c807SRodney W. Grimes */ 2384b88c807SRodney W. Grimes indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ; 2394b88c807SRodney W. Grimes if ((pt = ltab[indx]) == NULL) 2404b88c807SRodney W. Grimes return; 2414b88c807SRodney W. Grimes 2424b88c807SRodney W. Grimes /* 2434b88c807SRodney W. Grimes * walk down the list looking for the inode/dev pair, unlink and 2444b88c807SRodney W. Grimes * free if found 2454b88c807SRodney W. Grimes */ 2464b88c807SRodney W. Grimes ppt = &(ltab[indx]); 2474b88c807SRodney W. Grimes while (pt != NULL) { 2484b88c807SRodney W. Grimes if ((pt->ino == arcn->sb.st_ino) && 2494b88c807SRodney W. Grimes (pt->dev == arcn->sb.st_dev)) 2504b88c807SRodney W. Grimes break; 2514b88c807SRodney W. Grimes ppt = &(pt->fow); 2524b88c807SRodney W. Grimes pt = pt->fow; 2534b88c807SRodney W. Grimes } 2544b88c807SRodney W. Grimes if (pt == NULL) 2554b88c807SRodney W. Grimes return; 2564b88c807SRodney W. Grimes 2574b88c807SRodney W. Grimes /* 2584b88c807SRodney W. Grimes * remove and free it 2594b88c807SRodney W. Grimes */ 2604b88c807SRodney W. Grimes *ppt = pt->fow; 2614b88c807SRodney W. Grimes (void)free((char *)pt->name); 2624b88c807SRodney W. Grimes (void)free((char *)pt); 2634b88c807SRodney W. Grimes } 2644b88c807SRodney W. Grimes 2654b88c807SRodney W. Grimes /* 2664b88c807SRodney W. Grimes * lnk_end() 2674b88c807SRodney W. Grimes * pull apart a existing link table so we can reuse it. We do this between 2684b88c807SRodney W. Grimes * read and write phases of append with update. (The format may have 2694b88c807SRodney W. Grimes * used the link table, and we need to start with a fresh table for the 2704b88c807SRodney W. Grimes * write phase 2714b88c807SRodney W. Grimes */ 2724b88c807SRodney W. Grimes 2734b88c807SRodney W. Grimes void 2744b88c807SRodney W. Grimes lnk_end(void) 2754b88c807SRodney W. Grimes { 276f789b261SWarner Losh int i; 277f789b261SWarner Losh HRDLNK *pt; 278f789b261SWarner Losh HRDLNK *ppt; 2794b88c807SRodney W. Grimes 2804b88c807SRodney W. Grimes if (ltab == NULL) 2814b88c807SRodney W. Grimes return; 2824b88c807SRodney W. Grimes 2834b88c807SRodney W. Grimes for (i = 0; i < L_TAB_SZ; ++i) { 2844b88c807SRodney W. Grimes if (ltab[i] == NULL) 2854b88c807SRodney W. Grimes continue; 2864b88c807SRodney W. Grimes pt = ltab[i]; 2874b88c807SRodney W. Grimes ltab[i] = NULL; 2884b88c807SRodney W. Grimes 2894b88c807SRodney W. Grimes /* 2904b88c807SRodney W. Grimes * free up each entry on this chain 2914b88c807SRodney W. Grimes */ 2924b88c807SRodney W. Grimes while (pt != NULL) { 2934b88c807SRodney W. Grimes ppt = pt; 2944b88c807SRodney W. Grimes pt = ppt->fow; 2954b88c807SRodney W. Grimes (void)free((char *)ppt->name); 2964b88c807SRodney W. Grimes (void)free((char *)ppt); 2974b88c807SRodney W. Grimes } 2984b88c807SRodney W. Grimes } 2994b88c807SRodney W. Grimes return; 3004b88c807SRodney W. Grimes } 3014b88c807SRodney W. Grimes 3024b88c807SRodney W. Grimes /* 3034b88c807SRodney W. Grimes * modification time table routines 3044b88c807SRodney W. Grimes * 3054b88c807SRodney W. Grimes * The modification time table keeps track of last modification times for all 3064b88c807SRodney W. Grimes * files stored in an archive during a write phase when -u is set. We only 3074b88c807SRodney W. Grimes * add a file to the archive if it is newer than a file with the same name 3084b88c807SRodney W. Grimes * already stored on the archive (if there is no other file with the same 3094b88c807SRodney W. Grimes * name on the archive it is added). This applies to writes and appends. 3104b88c807SRodney W. Grimes * An append with an -u must read the archive and store the modification time 3114b88c807SRodney W. Grimes * for every file on that archive before starting the write phase. It is clear 3124b88c807SRodney W. Grimes * that this is one HUGE database. To save memory space, the actual file names 3134b88c807SRodney W. Grimes * are stored in a scatch file and indexed by an in memory hash table. The 3144b88c807SRodney W. Grimes * hash table is indexed by hashing the file path. The nodes in the table store 3154b88c807SRodney W. Grimes * the length of the filename and the lseek offset within the scratch file 3164b88c807SRodney W. Grimes * where the actual name is stored. Since there are never any deletions to this 3174b88c807SRodney W. Grimes * table, fragmentation of the scratch file is never a issue. Lookups seem to 3184b88c807SRodney W. Grimes * not exhibit any locality at all (files in the database are rarely 3194b88c807SRodney W. Grimes * looked up more than once...). So caching is just a waste of memory. The 3204b88c807SRodney W. Grimes * only limitation is the amount of scatch file space available to store the 3214b88c807SRodney W. Grimes * path names. 3224b88c807SRodney W. Grimes */ 3234b88c807SRodney W. Grimes 3244b88c807SRodney W. Grimes /* 3254b88c807SRodney W. Grimes * ftime_start() 3264b88c807SRodney W. Grimes * create the file time hash table and open for read/write the scratch 3274b88c807SRodney W. Grimes * file. (after created it is unlinked, so when we exit we leave 3284b88c807SRodney W. Grimes * no witnesses). 3294b88c807SRodney W. Grimes * Return: 3304b88c807SRodney W. Grimes * 0 if the table and file was created ok, -1 otherwise 3314b88c807SRodney W. Grimes */ 3324b88c807SRodney W. Grimes 3334b88c807SRodney W. Grimes int 3344b88c807SRodney W. Grimes ftime_start(void) 3354b88c807SRodney W. Grimes { 336d12dd1a1SKris Kennaway 3374b88c807SRodney W. Grimes if (ftab != NULL) 3384b88c807SRodney W. Grimes return(0); 3394b88c807SRodney W. Grimes if ((ftab = (FTM **)calloc(F_TAB_SZ, sizeof(FTM *))) == NULL) { 340778766feSKris Kennaway paxwarn(1, "Cannot allocate memory for file time table"); 3414b88c807SRodney W. Grimes return(-1); 3424b88c807SRodney W. Grimes } 3434b88c807SRodney W. Grimes 3444b88c807SRodney W. Grimes /* 3454b88c807SRodney W. Grimes * get random name and create temporary scratch file, unlink name 3464b88c807SRodney W. Grimes * so it will get removed on exit 3474b88c807SRodney W. Grimes */ 348ffbef1cdSKris Kennaway memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE)); 349ffbef1cdSKris Kennaway if ((ffd = mkstemp(tempfile)) < 0) { 350778766feSKris Kennaway syswarn(1, errno, "Unable to create temporary file: %s", 351ffbef1cdSKris Kennaway tempfile); 3524b88c807SRodney W. Grimes return(-1); 3534b88c807SRodney W. Grimes } 354ffbef1cdSKris Kennaway (void)unlink(tempfile); 3554b88c807SRodney W. Grimes 3564b88c807SRodney W. Grimes return(0); 3574b88c807SRodney W. Grimes } 3584b88c807SRodney W. Grimes 3594b88c807SRodney W. Grimes /* 3604b88c807SRodney W. Grimes * chk_ftime() 3614b88c807SRodney W. Grimes * looks up entry in file time hash table. If not found, the file is 3624b88c807SRodney W. Grimes * added to the hash table and the file named stored in the scratch file. 3634b88c807SRodney W. Grimes * If a file with the same name is found, the file times are compared and 3644b88c807SRodney W. Grimes * the most recent file time is retained. If the new file was younger (or 3654b88c807SRodney W. Grimes * was not in the database) the new file is selected for storage. 3664b88c807SRodney W. Grimes * Return: 3674b88c807SRodney W. Grimes * 0 if file should be added to the archive, 1 if it should be skipped, 3684b88c807SRodney W. Grimes * -1 on error 3694b88c807SRodney W. Grimes */ 3704b88c807SRodney W. Grimes 3714b88c807SRodney W. Grimes int 372f789b261SWarner Losh chk_ftime(ARCHD *arcn) 3734b88c807SRodney W. Grimes { 374f789b261SWarner Losh FTM *pt; 375f789b261SWarner Losh int namelen; 376f789b261SWarner Losh u_int indx; 3774b88c807SRodney W. Grimes char ckname[PAXPATHLEN+1]; 3784b88c807SRodney W. Grimes 3794b88c807SRodney W. Grimes /* 3804b88c807SRodney W. Grimes * no info, go ahead and add to archive 3814b88c807SRodney W. Grimes */ 3824b88c807SRodney W. Grimes if (ftab == NULL) 3834b88c807SRodney W. Grimes return(0); 3844b88c807SRodney W. Grimes 3854b88c807SRodney W. Grimes /* 3864b88c807SRodney W. Grimes * hash the pathname and look up in table 3874b88c807SRodney W. Grimes */ 3884b88c807SRodney W. Grimes namelen = arcn->nlen; 3894b88c807SRodney W. Grimes indx = st_hash(arcn->name, namelen, F_TAB_SZ); 3904b88c807SRodney W. Grimes if ((pt = ftab[indx]) != NULL) { 3914b88c807SRodney W. Grimes /* 3924b88c807SRodney W. Grimes * the hash chain is not empty, walk down looking for match 3934b88c807SRodney W. Grimes * only read up the path names if the lengths match, speeds 3944b88c807SRodney W. Grimes * up the search a lot 3954b88c807SRodney W. Grimes */ 3964b88c807SRodney W. Grimes while (pt != NULL) { 3974b88c807SRodney W. Grimes if (pt->namelen == namelen) { 3984b88c807SRodney W. Grimes /* 3994b88c807SRodney W. Grimes * potential match, have to read the name 4004b88c807SRodney W. Grimes * from the scratch file. 4014b88c807SRodney W. Grimes */ 4024b88c807SRodney W. Grimes if (lseek(ffd,pt->seek,SEEK_SET) != pt->seek) { 403778766feSKris Kennaway syswarn(1, errno, 4044b88c807SRodney W. Grimes "Failed ftime table seek"); 4054b88c807SRodney W. Grimes return(-1); 4064b88c807SRodney W. Grimes } 4074b88c807SRodney W. Grimes if (read(ffd, ckname, namelen) != namelen) { 408778766feSKris Kennaway syswarn(1, errno, 4094b88c807SRodney W. Grimes "Failed ftime table read"); 4104b88c807SRodney W. Grimes return(-1); 4114b88c807SRodney W. Grimes } 4124b88c807SRodney W. Grimes 4134b88c807SRodney W. Grimes /* 4144b88c807SRodney W. Grimes * if the names match, we are done 4154b88c807SRodney W. Grimes */ 4164b88c807SRodney W. Grimes if (!strncmp(ckname, arcn->name, namelen)) 4174b88c807SRodney W. Grimes break; 4184b88c807SRodney W. Grimes } 4194b88c807SRodney W. Grimes 4204b88c807SRodney W. Grimes /* 4214b88c807SRodney W. Grimes * try the next entry on the chain 4224b88c807SRodney W. Grimes */ 4234b88c807SRodney W. Grimes pt = pt->fow; 4244b88c807SRodney W. Grimes } 4254b88c807SRodney W. Grimes 4264b88c807SRodney W. Grimes if (pt != NULL) { 4274b88c807SRodney W. Grimes /* 4284b88c807SRodney W. Grimes * found the file, compare the times, save the newer 4294b88c807SRodney W. Grimes */ 4304b88c807SRodney W. Grimes if (arcn->sb.st_mtime > pt->mtime) { 4314b88c807SRodney W. Grimes /* 4324b88c807SRodney W. Grimes * file is newer 4334b88c807SRodney W. Grimes */ 4344b88c807SRodney W. Grimes pt->mtime = arcn->sb.st_mtime; 4354b88c807SRodney W. Grimes return(0); 4364b88c807SRodney W. Grimes } 4374b88c807SRodney W. Grimes /* 4384b88c807SRodney W. Grimes * file is older 4394b88c807SRodney W. Grimes */ 4404b88c807SRodney W. Grimes return(1); 4414b88c807SRodney W. Grimes } 4424b88c807SRodney W. Grimes } 4434b88c807SRodney W. Grimes 4444b88c807SRodney W. Grimes /* 4454b88c807SRodney W. Grimes * not in table, add it 4464b88c807SRodney W. Grimes */ 4474b88c807SRodney W. Grimes if ((pt = (FTM *)malloc(sizeof(FTM))) != NULL) { 4484b88c807SRodney W. Grimes /* 4494b88c807SRodney W. Grimes * add the name at the end of the scratch file, saving the 4504b88c807SRodney W. Grimes * offset. add the file to the head of the hash chain 4514b88c807SRodney W. Grimes */ 4524b88c807SRodney W. Grimes if ((pt->seek = lseek(ffd, (off_t)0, SEEK_END)) >= 0) { 4534b88c807SRodney W. Grimes if (write(ffd, arcn->name, namelen) == namelen) { 4544b88c807SRodney W. Grimes pt->mtime = arcn->sb.st_mtime; 4554b88c807SRodney W. Grimes pt->namelen = namelen; 4564b88c807SRodney W. Grimes pt->fow = ftab[indx]; 4574b88c807SRodney W. Grimes ftab[indx] = pt; 4584b88c807SRodney W. Grimes return(0); 4594b88c807SRodney W. Grimes } 460778766feSKris Kennaway syswarn(1, errno, "Failed write to file time table"); 4614b88c807SRodney W. Grimes } else 462778766feSKris Kennaway syswarn(1, errno, "Failed seek on file time table"); 4634b88c807SRodney W. Grimes } else 464778766feSKris Kennaway paxwarn(1, "File time table ran out of memory"); 4654b88c807SRodney W. Grimes 4664b88c807SRodney W. Grimes if (pt != NULL) 4674b88c807SRodney W. Grimes (void)free((char *)pt); 4684b88c807SRodney W. Grimes return(-1); 4694b88c807SRodney W. Grimes } 4704b88c807SRodney W. Grimes 4714b88c807SRodney W. Grimes /* 4724b88c807SRodney W. Grimes * Interactive rename table routines 4734b88c807SRodney W. Grimes * 4744b88c807SRodney W. Grimes * The interactive rename table keeps track of the new names that the user 47546be34b9SKris Kennaway * assigns to files from tty input. Since this map is unique for each file 4764b88c807SRodney W. Grimes * we must store it in case there is a reference to the file later in archive 4774b88c807SRodney W. Grimes * (a link). Otherwise we will be unable to find the file we know was 4784b88c807SRodney W. Grimes * extracted. The remapping of these files is stored in a memory based hash 4794b88c807SRodney W. Grimes * table (it is assumed since input must come from /dev/tty, it is unlikely to 4804b88c807SRodney W. Grimes * be a very large table). 4814b88c807SRodney W. Grimes */ 4824b88c807SRodney W. Grimes 4834b88c807SRodney W. Grimes /* 4844b88c807SRodney W. Grimes * name_start() 4854b88c807SRodney W. Grimes * create the interactive rename table 4864b88c807SRodney W. Grimes * Return: 4874b88c807SRodney W. Grimes * 0 if successful, -1 otherwise 4884b88c807SRodney W. Grimes */ 4894b88c807SRodney W. Grimes 4904b88c807SRodney W. Grimes int 4914b88c807SRodney W. Grimes name_start(void) 4924b88c807SRodney W. Grimes { 4934b88c807SRodney W. Grimes if (ntab != NULL) 4944b88c807SRodney W. Grimes return(0); 4954b88c807SRodney W. Grimes if ((ntab = (NAMT **)calloc(N_TAB_SZ, sizeof(NAMT *))) == NULL) { 496778766feSKris Kennaway paxwarn(1, "Cannot allocate memory for interactive rename table"); 4974b88c807SRodney W. Grimes return(-1); 4984b88c807SRodney W. Grimes } 4994b88c807SRodney W. Grimes return(0); 5004b88c807SRodney W. Grimes } 5014b88c807SRodney W. Grimes 5024b88c807SRodney W. Grimes /* 5034b88c807SRodney W. Grimes * add_name() 5044b88c807SRodney W. Grimes * add the new name to old name mapping just created by the user. 5054b88c807SRodney W. Grimes * If an old name mapping is found (there may be duplicate names on an 5064b88c807SRodney W. Grimes * archive) only the most recent is kept. 5074b88c807SRodney W. Grimes * Return: 5084b88c807SRodney W. Grimes * 0 if added, -1 otherwise 5094b88c807SRodney W. Grimes */ 5104b88c807SRodney W. Grimes 5114b88c807SRodney W. Grimes int 512f789b261SWarner Losh add_name(char *oname, int onamelen, char *nname) 5134b88c807SRodney W. Grimes { 514f789b261SWarner Losh NAMT *pt; 515f789b261SWarner Losh u_int indx; 5164b88c807SRodney W. Grimes 5174b88c807SRodney W. Grimes if (ntab == NULL) { 5184b88c807SRodney W. Grimes /* 5194b88c807SRodney W. Grimes * should never happen 5204b88c807SRodney W. Grimes */ 521778766feSKris Kennaway paxwarn(0, "No interactive rename table, links may fail\n"); 5224b88c807SRodney W. Grimes return(0); 5234b88c807SRodney W. Grimes } 5244b88c807SRodney W. Grimes 5254b88c807SRodney W. Grimes /* 5264b88c807SRodney W. Grimes * look to see if we have already mapped this file, if so we 5274b88c807SRodney W. Grimes * will update it 5284b88c807SRodney W. Grimes */ 5294b88c807SRodney W. Grimes indx = st_hash(oname, onamelen, N_TAB_SZ); 5304b88c807SRodney W. Grimes if ((pt = ntab[indx]) != NULL) { 5314b88c807SRodney W. Grimes /* 5324b88c807SRodney W. Grimes * look down the has chain for the file 5334b88c807SRodney W. Grimes */ 5344b88c807SRodney W. Grimes while ((pt != NULL) && (strcmp(oname, pt->oname) != 0)) 5354b88c807SRodney W. Grimes pt = pt->fow; 5364b88c807SRodney W. Grimes 5374b88c807SRodney W. Grimes if (pt != NULL) { 5384b88c807SRodney W. Grimes /* 5394b88c807SRodney W. Grimes * found an old mapping, replace it with the new one 5404b88c807SRodney W. Grimes * the user just input (if it is different) 5414b88c807SRodney W. Grimes */ 5424b88c807SRodney W. Grimes if (strcmp(nname, pt->nname) == 0) 5434b88c807SRodney W. Grimes return(0); 5444b88c807SRodney W. Grimes 5454b88c807SRodney W. Grimes (void)free((char *)pt->nname); 5464b88c807SRodney W. Grimes if ((pt->nname = strdup(nname)) == NULL) { 547778766feSKris Kennaway paxwarn(1, "Cannot update rename table"); 5484b88c807SRodney W. Grimes return(-1); 5494b88c807SRodney W. Grimes } 5504b88c807SRodney W. Grimes return(0); 5514b88c807SRodney W. Grimes } 5524b88c807SRodney W. Grimes } 5534b88c807SRodney W. Grimes 5544b88c807SRodney W. Grimes /* 5554b88c807SRodney W. Grimes * this is a new mapping, add it to the table 5564b88c807SRodney W. Grimes */ 5574b88c807SRodney W. Grimes if ((pt = (NAMT *)malloc(sizeof(NAMT))) != NULL) { 5584b88c807SRodney W. Grimes if ((pt->oname = strdup(oname)) != NULL) { 5594b88c807SRodney W. Grimes if ((pt->nname = strdup(nname)) != NULL) { 5604b88c807SRodney W. Grimes pt->fow = ntab[indx]; 5614b88c807SRodney W. Grimes ntab[indx] = pt; 5624b88c807SRodney W. Grimes return(0); 5634b88c807SRodney W. Grimes } 5644b88c807SRodney W. Grimes (void)free((char *)pt->oname); 5654b88c807SRodney W. Grimes } 5664b88c807SRodney W. Grimes (void)free((char *)pt); 5674b88c807SRodney W. Grimes } 568778766feSKris Kennaway paxwarn(1, "Interactive rename table out of memory"); 5694b88c807SRodney W. Grimes return(-1); 5704b88c807SRodney W. Grimes } 5714b88c807SRodney W. Grimes 5724b88c807SRodney W. Grimes /* 5734b88c807SRodney W. Grimes * sub_name() 5744b88c807SRodney W. Grimes * look up a link name to see if it points at a file that has been 5754b88c807SRodney W. Grimes * remapped by the user. If found, the link is adjusted to contain the 5764b88c807SRodney W. Grimes * new name (oname is the link to name) 5774b88c807SRodney W. Grimes */ 5784b88c807SRodney W. Grimes 5794b88c807SRodney W. Grimes void 580f789b261SWarner Losh sub_name(char *oname, int *onamelen, size_t onamesize) 5814b88c807SRodney W. Grimes { 582f789b261SWarner Losh NAMT *pt; 583f789b261SWarner Losh u_int indx; 5844b88c807SRodney W. Grimes 5854b88c807SRodney W. Grimes if (ntab == NULL) 5864b88c807SRodney W. Grimes return; 5874b88c807SRodney W. Grimes /* 5884b88c807SRodney W. Grimes * look the name up in the hash table 5894b88c807SRodney W. Grimes */ 5904b88c807SRodney W. Grimes indx = st_hash(oname, *onamelen, N_TAB_SZ); 5914b88c807SRodney W. Grimes if ((pt = ntab[indx]) == NULL) 5924b88c807SRodney W. Grimes return; 5934b88c807SRodney W. Grimes 5944b88c807SRodney W. Grimes while (pt != NULL) { 5954b88c807SRodney W. Grimes /* 596778766feSKris Kennaway * walk down the hash chain looking for a match 5974b88c807SRodney W. Grimes */ 5984b88c807SRodney W. Grimes if (strcmp(oname, pt->oname) == 0) { 5994b88c807SRodney W. Grimes /* 6004b88c807SRodney W. Grimes * found it, replace it with the new name 6014b88c807SRodney W. Grimes * and return (we know that oname has enough space) 6024b88c807SRodney W. Grimes */ 603b1787decSKris Kennaway *onamelen = l_strncpy(oname, pt->nname, onamesize - 1); 604b1787decSKris Kennaway oname[*onamelen] = '\0'; 6054b88c807SRodney W. Grimes return; 6064b88c807SRodney W. Grimes } 6074b88c807SRodney W. Grimes pt = pt->fow; 6084b88c807SRodney W. Grimes } 6094b88c807SRodney W. Grimes 6104b88c807SRodney W. Grimes /* 6114b88c807SRodney W. Grimes * no match, just return 6124b88c807SRodney W. Grimes */ 6134b88c807SRodney W. Grimes return; 6144b88c807SRodney W. Grimes } 6154b88c807SRodney W. Grimes 6164b88c807SRodney W. Grimes /* 6174b88c807SRodney W. Grimes * device/inode mapping table routines 6184b88c807SRodney W. Grimes * (used with formats that store device and inodes fields) 6194b88c807SRodney W. Grimes * 6204b88c807SRodney W. Grimes * device/inode mapping tables remap the device field in a archive header. The 6214b88c807SRodney W. Grimes * device/inode fields are used to determine when files are hard links to each 6224b88c807SRodney W. Grimes * other. However these values have very little meaning outside of that. This 6234b88c807SRodney W. Grimes * database is used to solve one of two different problems. 6244b88c807SRodney W. Grimes * 6254b88c807SRodney W. Grimes * 1) when files are appended to an archive, while the new files may have hard 6264b88c807SRodney W. Grimes * links to each other, you cannot determine if they have hard links to any 6274b88c807SRodney W. Grimes * file already stored on the archive from a prior run of pax. We must assume 6284b88c807SRodney W. Grimes * that these inode/device pairs are unique only within a SINGLE run of pax 6294b88c807SRodney W. Grimes * (which adds a set of files to an archive). So we have to make sure the 6304b88c807SRodney W. Grimes * inode/dev pairs we add each time are always unique. We do this by observing 6314b88c807SRodney W. Grimes * while the inode field is very dense, the use of the dev field is fairly 6324b88c807SRodney W. Grimes * sparse. Within each run of pax, we remap any device number of a new archive 6334b88c807SRodney W. Grimes * member that has a device number used in a prior run and already stored in a 6344b88c807SRodney W. Grimes * file on the archive. During the read phase of the append, we store the 6354b88c807SRodney W. Grimes * device numbers used and mark them to not be used by any file during the 6364b88c807SRodney W. Grimes * write phase. If during write we go to use one of those old device numbers, 6374b88c807SRodney W. Grimes * we remap it to a new value. 6384b88c807SRodney W. Grimes * 6394b88c807SRodney W. Grimes * 2) Often the fields in the archive header used to store these values are 6404b88c807SRodney W. Grimes * too small to store the entire value. The result is an inode or device value 6414b88c807SRodney W. Grimes * which can be truncated. This really can foul up an archive. With truncation 6424b88c807SRodney W. Grimes * we end up creating links between files that are really not links (after 6434b88c807SRodney W. Grimes * truncation the inodes are the same value). We address that by detecting 6444b88c807SRodney W. Grimes * truncation and forcing a remap of the device field to split truncated 6454b88c807SRodney W. Grimes * inodes away from each other. Each truncation creates a pattern of bits that 6464b88c807SRodney W. Grimes * are removed. We use this pattern of truncated bits to partition the inodes 6474b88c807SRodney W. Grimes * on a single device to many different devices (each one represented by the 6484b88c807SRodney W. Grimes * truncated bit pattern). All inodes on the same device that have the same 6494b88c807SRodney W. Grimes * truncation pattern are mapped to the same new device. Two inodes that 6504b88c807SRodney W. Grimes * truncate to the same value clearly will always have different truncation 6514b88c807SRodney W. Grimes * bit patterns, so they will be split from away each other. When we spot 6524b88c807SRodney W. Grimes * device truncation we remap the device number to a non truncated value. 6534b88c807SRodney W. Grimes * (for more info see table.h for the data structures involved). 6544b88c807SRodney W. Grimes */ 6554b88c807SRodney W. Grimes 6564b88c807SRodney W. Grimes /* 6574b88c807SRodney W. Grimes * dev_start() 6584b88c807SRodney W. Grimes * create the device mapping table 6594b88c807SRodney W. Grimes * Return: 6604b88c807SRodney W. Grimes * 0 if successful, -1 otherwise 6614b88c807SRodney W. Grimes */ 6624b88c807SRodney W. Grimes 6634b88c807SRodney W. Grimes int 6644b88c807SRodney W. Grimes dev_start(void) 6654b88c807SRodney W. Grimes { 6664b88c807SRodney W. Grimes if (dtab != NULL) 6674b88c807SRodney W. Grimes return(0); 6684b88c807SRodney W. Grimes if ((dtab = (DEVT **)calloc(D_TAB_SZ, sizeof(DEVT *))) == NULL) { 669778766feSKris Kennaway paxwarn(1, "Cannot allocate memory for device mapping table"); 6704b88c807SRodney W. Grimes return(-1); 6714b88c807SRodney W. Grimes } 6724b88c807SRodney W. Grimes return(0); 6734b88c807SRodney W. Grimes } 6744b88c807SRodney W. Grimes 6754b88c807SRodney W. Grimes /* 6764b88c807SRodney W. Grimes * add_dev() 6774b88c807SRodney W. Grimes * add a device number to the table. this will force the device to be 6784b88c807SRodney W. Grimes * remapped to a new value if it be used during a write phase. This 6794b88c807SRodney W. Grimes * function is called during the read phase of an append to prohibit the 6804b88c807SRodney W. Grimes * use of any device number already in the archive. 6814b88c807SRodney W. Grimes * Return: 6824b88c807SRodney W. Grimes * 0 if added ok, -1 otherwise 6834b88c807SRodney W. Grimes */ 6844b88c807SRodney W. Grimes 6854b88c807SRodney W. Grimes int 686f789b261SWarner Losh add_dev(ARCHD *arcn) 6874b88c807SRodney W. Grimes { 6884b88c807SRodney W. Grimes if (chk_dev(arcn->sb.st_dev, 1) == NULL) 6894b88c807SRodney W. Grimes return(-1); 6904b88c807SRodney W. Grimes return(0); 6914b88c807SRodney W. Grimes } 6924b88c807SRodney W. Grimes 6934b88c807SRodney W. Grimes /* 6944b88c807SRodney W. Grimes * chk_dev() 6954b88c807SRodney W. Grimes * check for a device value in the device table. If not found and the add 6964b88c807SRodney W. Grimes * flag is set, it is added. This does NOT assign any mapping values, just 6974b88c807SRodney W. Grimes * adds the device number as one that need to be remapped. If this device 69846be34b9SKris Kennaway * is already mapped, just return with a pointer to that entry. 6994b88c807SRodney W. Grimes * Return: 7004b88c807SRodney W. Grimes * pointer to the entry for this device in the device map table. Null 7014b88c807SRodney W. Grimes * if the add flag is not set and the device is not in the table (it is 7024b88c807SRodney W. Grimes * not been seen yet). If add is set and the device cannot be added, null 7034b88c807SRodney W. Grimes * is returned (indicates an error). 7044b88c807SRodney W. Grimes */ 7054b88c807SRodney W. Grimes 7064b88c807SRodney W. Grimes static DEVT * 7074b88c807SRodney W. Grimes chk_dev(dev_t dev, int add) 7084b88c807SRodney W. Grimes { 709f789b261SWarner Losh DEVT *pt; 710f789b261SWarner Losh u_int indx; 7114b88c807SRodney W. Grimes 7124b88c807SRodney W. Grimes if (dtab == NULL) 7134b88c807SRodney W. Grimes return(NULL); 7144b88c807SRodney W. Grimes /* 7154b88c807SRodney W. Grimes * look to see if this device is already in the table 7164b88c807SRodney W. Grimes */ 7174b88c807SRodney W. Grimes indx = ((unsigned)dev) % D_TAB_SZ; 7184b88c807SRodney W. Grimes if ((pt = dtab[indx]) != NULL) { 7194b88c807SRodney W. Grimes while ((pt != NULL) && (pt->dev != dev)) 7204b88c807SRodney W. Grimes pt = pt->fow; 7214b88c807SRodney W. Grimes 7224b88c807SRodney W. Grimes /* 7234b88c807SRodney W. Grimes * found it, return a pointer to it 7244b88c807SRodney W. Grimes */ 7254b88c807SRodney W. Grimes if (pt != NULL) 7264b88c807SRodney W. Grimes return(pt); 7274b88c807SRodney W. Grimes } 7284b88c807SRodney W. Grimes 7294b88c807SRodney W. Grimes /* 7304b88c807SRodney W. Grimes * not in table, we add it only if told to as this may just be a check 7314b88c807SRodney W. Grimes * to see if a device number is being used. 7324b88c807SRodney W. Grimes */ 7334b88c807SRodney W. Grimes if (add == 0) 7344b88c807SRodney W. Grimes return(NULL); 7354b88c807SRodney W. Grimes 7364b88c807SRodney W. Grimes /* 7374b88c807SRodney W. Grimes * allocate a node for this device and add it to the front of the hash 7384b88c807SRodney W. Grimes * chain. Note we do not assign remaps values here, so the pt->list 7394b88c807SRodney W. Grimes * list must be NULL. 7404b88c807SRodney W. Grimes */ 7414b88c807SRodney W. Grimes if ((pt = (DEVT *)malloc(sizeof(DEVT))) == NULL) { 742778766feSKris Kennaway paxwarn(1, "Device map table out of memory"); 7434b88c807SRodney W. Grimes return(NULL); 7444b88c807SRodney W. Grimes } 7454b88c807SRodney W. Grimes pt->dev = dev; 7464b88c807SRodney W. Grimes pt->list = NULL; 7474b88c807SRodney W. Grimes pt->fow = dtab[indx]; 7484b88c807SRodney W. Grimes dtab[indx] = pt; 7494b88c807SRodney W. Grimes return(pt); 7504b88c807SRodney W. Grimes } 7514b88c807SRodney W. Grimes /* 7524b88c807SRodney W. Grimes * map_dev() 7534b88c807SRodney W. Grimes * given an inode and device storage mask (the mask has a 1 for each bit 7544b88c807SRodney W. Grimes * the archive format is able to store in a header), we check for inode 7554b88c807SRodney W. Grimes * and device truncation and remap the device as required. Device mapping 7564b88c807SRodney W. Grimes * can also occur when during the read phase of append a device number was 7574b88c807SRodney W. Grimes * seen (and was marked as do not use during the write phase). WE ASSUME 7584b88c807SRodney W. Grimes * that unsigned longs are the same size or bigger than the fields used 7594b88c807SRodney W. Grimes * for ino_t and dev_t. If not the types will have to be changed. 7604b88c807SRodney W. Grimes * Return: 7614b88c807SRodney W. Grimes * 0 if all ok, -1 otherwise. 7624b88c807SRodney W. Grimes */ 7634b88c807SRodney W. Grimes 7644b88c807SRodney W. Grimes int 765f789b261SWarner Losh map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask) 7664b88c807SRodney W. Grimes { 767f789b261SWarner Losh DEVT *pt; 768f789b261SWarner Losh DLIST *dpt; 7694b88c807SRodney W. Grimes static dev_t lastdev = 0; /* next device number to try */ 7704b88c807SRodney W. Grimes int trc_ino = 0; 7714b88c807SRodney W. Grimes int trc_dev = 0; 7724b88c807SRodney W. Grimes ino_t trunc_bits = 0; 7734b88c807SRodney W. Grimes ino_t nino; 7744b88c807SRodney W. Grimes 7754b88c807SRodney W. Grimes if (dtab == NULL) 7764b88c807SRodney W. Grimes return(0); 7774b88c807SRodney W. Grimes /* 7784b88c807SRodney W. Grimes * check for device and inode truncation, and extract the truncated 7794b88c807SRodney W. Grimes * bit pattern. 7804b88c807SRodney W. Grimes */ 7814b88c807SRodney W. Grimes if ((arcn->sb.st_dev & (dev_t)dev_mask) != arcn->sb.st_dev) 7824b88c807SRodney W. Grimes ++trc_dev; 7834b88c807SRodney W. Grimes if ((nino = arcn->sb.st_ino & (ino_t)ino_mask) != arcn->sb.st_ino) { 7844b88c807SRodney W. Grimes ++trc_ino; 7854b88c807SRodney W. Grimes trunc_bits = arcn->sb.st_ino & (ino_t)(~ino_mask); 7864b88c807SRodney W. Grimes } 7874b88c807SRodney W. Grimes 7884b88c807SRodney W. Grimes /* 7894b88c807SRodney W. Grimes * see if this device is already being mapped, look up the device 7904b88c807SRodney W. Grimes * then find the truncation bit pattern which applies 7914b88c807SRodney W. Grimes */ 7924b88c807SRodney W. Grimes if ((pt = chk_dev(arcn->sb.st_dev, 0)) != NULL) { 7934b88c807SRodney W. Grimes /* 7944b88c807SRodney W. Grimes * this device is already marked to be remapped 7954b88c807SRodney W. Grimes */ 7964b88c807SRodney W. Grimes for (dpt = pt->list; dpt != NULL; dpt = dpt->fow) 7974b88c807SRodney W. Grimes if (dpt->trunc_bits == trunc_bits) 7984b88c807SRodney W. Grimes break; 7994b88c807SRodney W. Grimes 8004b88c807SRodney W. Grimes if (dpt != NULL) { 8014b88c807SRodney W. Grimes /* 8024b88c807SRodney W. Grimes * we are being remapped for this device and pattern 8034b88c807SRodney W. Grimes * change the device number to be stored and return 8044b88c807SRodney W. Grimes */ 8054b88c807SRodney W. Grimes arcn->sb.st_dev = dpt->dev; 8064b88c807SRodney W. Grimes arcn->sb.st_ino = nino; 8074b88c807SRodney W. Grimes return(0); 8084b88c807SRodney W. Grimes } 8094b88c807SRodney W. Grimes } else { 8104b88c807SRodney W. Grimes /* 8114b88c807SRodney W. Grimes * this device is not being remapped YET. if we do not have any 8124b88c807SRodney W. Grimes * form of truncation, we do not need a remap 8134b88c807SRodney W. Grimes */ 8144b88c807SRodney W. Grimes if (!trc_ino && !trc_dev) 8154b88c807SRodney W. Grimes return(0); 8164b88c807SRodney W. Grimes 8174b88c807SRodney W. Grimes /* 8184b88c807SRodney W. Grimes * we have truncation, have to add this as a device to remap 8194b88c807SRodney W. Grimes */ 8204b88c807SRodney W. Grimes if ((pt = chk_dev(arcn->sb.st_dev, 1)) == NULL) 8214b88c807SRodney W. Grimes goto bad; 8224b88c807SRodney W. Grimes 8234b88c807SRodney W. Grimes /* 8244b88c807SRodney W. Grimes * if we just have a truncated inode, we have to make sure that 8254b88c807SRodney W. Grimes * all future inodes that do not truncate (they have the 8264b88c807SRodney W. Grimes * truncation pattern of all 0's) continue to map to the same 8274b88c807SRodney W. Grimes * device number. We probably have already written inodes with 8284b88c807SRodney W. Grimes * this device number to the archive with the truncation 8294b88c807SRodney W. Grimes * pattern of all 0's. So we add the mapping for all 0's to the 8304b88c807SRodney W. Grimes * same device number. 8314b88c807SRodney W. Grimes */ 8324b88c807SRodney W. Grimes if (!trc_dev && (trunc_bits != 0)) { 8334b88c807SRodney W. Grimes if ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL) 8344b88c807SRodney W. Grimes goto bad; 8354b88c807SRodney W. Grimes dpt->trunc_bits = 0; 8364b88c807SRodney W. Grimes dpt->dev = arcn->sb.st_dev; 8374b88c807SRodney W. Grimes dpt->fow = pt->list; 8384b88c807SRodney W. Grimes pt->list = dpt; 8394b88c807SRodney W. Grimes } 8404b88c807SRodney W. Grimes } 8414b88c807SRodney W. Grimes 8424b88c807SRodney W. Grimes /* 8434b88c807SRodney W. Grimes * look for a device number not being used. We must watch for wrap 8444b88c807SRodney W. Grimes * around on lastdev (so we do not get stuck looking forever!) 8454b88c807SRodney W. Grimes */ 8464b88c807SRodney W. Grimes while (++lastdev > 0) { 8474b88c807SRodney W. Grimes if (chk_dev(lastdev, 0) != NULL) 8484b88c807SRodney W. Grimes continue; 8494b88c807SRodney W. Grimes /* 8504b88c807SRodney W. Grimes * found an unused value. If we have reached truncation point 8514b88c807SRodney W. Grimes * for this format we are hosed, so we give up. Otherwise we 8524b88c807SRodney W. Grimes * mark it as being used. 8534b88c807SRodney W. Grimes */ 8544b88c807SRodney W. Grimes if (((lastdev & ((dev_t)dev_mask)) != lastdev) || 8554b88c807SRodney W. Grimes (chk_dev(lastdev, 1) == NULL)) 8564b88c807SRodney W. Grimes goto bad; 8574b88c807SRodney W. Grimes break; 8584b88c807SRodney W. Grimes } 8594b88c807SRodney W. Grimes 8604b88c807SRodney W. Grimes if ((lastdev <= 0) || ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL)) 8614b88c807SRodney W. Grimes goto bad; 8624b88c807SRodney W. Grimes 8634b88c807SRodney W. Grimes /* 8644b88c807SRodney W. Grimes * got a new device number, store it under this truncation pattern. 8654b88c807SRodney W. Grimes * change the device number this file is being stored with. 8664b88c807SRodney W. Grimes */ 8674b88c807SRodney W. Grimes dpt->trunc_bits = trunc_bits; 8684b88c807SRodney W. Grimes dpt->dev = lastdev; 8694b88c807SRodney W. Grimes dpt->fow = pt->list; 8704b88c807SRodney W. Grimes pt->list = dpt; 8714b88c807SRodney W. Grimes arcn->sb.st_dev = lastdev; 8724b88c807SRodney W. Grimes arcn->sb.st_ino = nino; 8734b88c807SRodney W. Grimes return(0); 8744b88c807SRodney W. Grimes 8754b88c807SRodney W. Grimes bad: 876778766feSKris Kennaway paxwarn(1, "Unable to fix truncated inode/device field when storing %s", 8774b88c807SRodney W. Grimes arcn->name); 878778766feSKris Kennaway paxwarn(0, "Archive may create improper hard links when extracted"); 8794b88c807SRodney W. Grimes return(0); 8804b88c807SRodney W. Grimes } 8814b88c807SRodney W. Grimes 8824b88c807SRodney W. Grimes /* 8834b88c807SRodney W. Grimes * directory access/mod time reset table routines (for directories READ by pax) 8844b88c807SRodney W. Grimes * 8854b88c807SRodney W. Grimes * The pax -t flag requires that access times of archive files to be the same 8864b88c807SRodney W. Grimes * before being read by pax. For regular files, access time is restored after 8874b88c807SRodney W. Grimes * the file has been copied. This database provides the same functionality for 8884b88c807SRodney W. Grimes * directories read during file tree traversal. Restoring directory access time 8894b88c807SRodney W. Grimes * is more complex than files since directories may be read several times until 8904b88c807SRodney W. Grimes * all the descendants in their subtree are visited by fts. Directory access 8914b88c807SRodney W. Grimes * and modification times are stored during the fts pre-order visit (done 8924b88c807SRodney W. Grimes * before any descendants in the subtree is visited) and restored after the 8934b88c807SRodney W. Grimes * fts post-order visit (after all the descendants have been visited). In the 8944b88c807SRodney W. Grimes * case of premature exit from a subtree (like from the effects of -n), any 8954b88c807SRodney W. Grimes * directory entries left in this database are reset during final cleanup 8964b88c807SRodney W. Grimes * operations of pax. Entries are hashed by inode number for fast lookup. 8974b88c807SRodney W. Grimes */ 8984b88c807SRodney W. Grimes 8994b88c807SRodney W. Grimes /* 9004b88c807SRodney W. Grimes * atdir_start() 9014b88c807SRodney W. Grimes * create the directory access time database for directories READ by pax. 9024b88c807SRodney W. Grimes * Return: 9034b88c807SRodney W. Grimes * 0 is created ok, -1 otherwise. 9044b88c807SRodney W. Grimes */ 9054b88c807SRodney W. Grimes 9064b88c807SRodney W. Grimes int 9074b88c807SRodney W. Grimes atdir_start(void) 9084b88c807SRodney W. Grimes { 9094b88c807SRodney W. Grimes if (atab != NULL) 9104b88c807SRodney W. Grimes return(0); 9114b88c807SRodney W. Grimes if ((atab = (ATDIR **)calloc(A_TAB_SZ, sizeof(ATDIR *))) == NULL) { 912778766feSKris Kennaway paxwarn(1,"Cannot allocate space for directory access time table"); 9134b88c807SRodney W. Grimes return(-1); 9144b88c807SRodney W. Grimes } 9154b88c807SRodney W. Grimes return(0); 9164b88c807SRodney W. Grimes } 9174b88c807SRodney W. Grimes 9184b88c807SRodney W. Grimes 9194b88c807SRodney W. Grimes /* 9204b88c807SRodney W. Grimes * atdir_end() 9214b88c807SRodney W. Grimes * walk through the directory access time table and reset the access time 9224b88c807SRodney W. Grimes * of any directory who still has an entry left in the database. These 9234b88c807SRodney W. Grimes * entries are for directories READ by pax 9244b88c807SRodney W. Grimes */ 9254b88c807SRodney W. Grimes 9264b88c807SRodney W. Grimes void 9274b88c807SRodney W. Grimes atdir_end(void) 9284b88c807SRodney W. Grimes { 929f789b261SWarner Losh ATDIR *pt; 930f789b261SWarner Losh int i; 9314b88c807SRodney W. Grimes 9324b88c807SRodney W. Grimes if (atab == NULL) 9334b88c807SRodney W. Grimes return; 9344b88c807SRodney W. Grimes /* 9354b88c807SRodney W. Grimes * for each non-empty hash table entry reset all the directories 9364b88c807SRodney W. Grimes * chained there. 9374b88c807SRodney W. Grimes */ 9384b88c807SRodney W. Grimes for (i = 0; i < A_TAB_SZ; ++i) { 9394b88c807SRodney W. Grimes if ((pt = atab[i]) == NULL) 9404b88c807SRodney W. Grimes continue; 9414b88c807SRodney W. Grimes /* 9424b88c807SRodney W. Grimes * remember to force the times, set_ftime() looks at pmtime 9434b88c807SRodney W. Grimes * and patime, which only applies to things CREATED by pax, 9444b88c807SRodney W. Grimes * not read by pax. Read time reset is controlled by -t. 9454b88c807SRodney W. Grimes */ 9464b88c807SRodney W. Grimes for (; pt != NULL; pt = pt->fow) 9474b88c807SRodney W. Grimes set_ftime(pt->name, pt->mtime, pt->atime, 1); 9484b88c807SRodney W. Grimes } 9494b88c807SRodney W. Grimes } 9504b88c807SRodney W. Grimes 9514b88c807SRodney W. Grimes /* 9524b88c807SRodney W. Grimes * add_atdir() 9534b88c807SRodney W. Grimes * add a directory to the directory access time table. Table is hashed 9544b88c807SRodney W. Grimes * and chained by inode number. This is for directories READ by pax 9554b88c807SRodney W. Grimes */ 9564b88c807SRodney W. Grimes 9574b88c807SRodney W. Grimes void 9584b88c807SRodney W. Grimes add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime) 9594b88c807SRodney W. Grimes { 960f789b261SWarner Losh ATDIR *pt; 961f789b261SWarner Losh u_int indx; 9624b88c807SRodney W. Grimes 9634b88c807SRodney W. Grimes if (atab == NULL) 9644b88c807SRodney W. Grimes return; 9654b88c807SRodney W. Grimes 9664b88c807SRodney W. Grimes /* 9674b88c807SRodney W. Grimes * make sure this directory is not already in the table, if so just 9684b88c807SRodney W. Grimes * return (the older entry always has the correct time). The only 9694b88c807SRodney W. Grimes * way this will happen is when the same subtree can be traversed by 9704b88c807SRodney W. Grimes * different args to pax and the -n option is aborting fts out of a 9714b88c807SRodney W. Grimes * subtree before all the post-order visits have been made). 9724b88c807SRodney W. Grimes */ 9734b88c807SRodney W. Grimes indx = ((unsigned)ino) % A_TAB_SZ; 9744b88c807SRodney W. Grimes if ((pt = atab[indx]) != NULL) { 9754b88c807SRodney W. Grimes while (pt != NULL) { 9764b88c807SRodney W. Grimes if ((pt->ino == ino) && (pt->dev == dev)) 9774b88c807SRodney W. Grimes break; 9784b88c807SRodney W. Grimes pt = pt->fow; 9794b88c807SRodney W. Grimes } 9804b88c807SRodney W. Grimes 9814b88c807SRodney W. Grimes /* 9824b88c807SRodney W. Grimes * oops, already there. Leave it alone. 9834b88c807SRodney W. Grimes */ 9844b88c807SRodney W. Grimes if (pt != NULL) 9854b88c807SRodney W. Grimes return; 9864b88c807SRodney W. Grimes } 9874b88c807SRodney W. Grimes 9884b88c807SRodney W. Grimes /* 9894b88c807SRodney W. Grimes * add it to the front of the hash chain 9904b88c807SRodney W. Grimes */ 9914b88c807SRodney W. Grimes if ((pt = (ATDIR *)malloc(sizeof(ATDIR))) != NULL) { 9924b88c807SRodney W. Grimes if ((pt->name = strdup(fname)) != NULL) { 9934b88c807SRodney W. Grimes pt->dev = dev; 9944b88c807SRodney W. Grimes pt->ino = ino; 9954b88c807SRodney W. Grimes pt->mtime = mtime; 9964b88c807SRodney W. Grimes pt->atime = atime; 9974b88c807SRodney W. Grimes pt->fow = atab[indx]; 9984b88c807SRodney W. Grimes atab[indx] = pt; 9994b88c807SRodney W. Grimes return; 10004b88c807SRodney W. Grimes } 10014b88c807SRodney W. Grimes (void)free((char *)pt); 10024b88c807SRodney W. Grimes } 10034b88c807SRodney W. Grimes 1004778766feSKris Kennaway paxwarn(1, "Directory access time reset table ran out of memory"); 10054b88c807SRodney W. Grimes return; 10064b88c807SRodney W. Grimes } 10074b88c807SRodney W. Grimes 10084b88c807SRodney W. Grimes /* 10094b88c807SRodney W. Grimes * get_atdir() 10104b88c807SRodney W. Grimes * look up a directory by inode and device number to obtain the access 10114b88c807SRodney W. Grimes * and modification time you want to set to. If found, the modification 10124b88c807SRodney W. Grimes * and access time parameters are set and the entry is removed from the 10134b88c807SRodney W. Grimes * table (as it is no longer needed). These are for directories READ by 10144b88c807SRodney W. Grimes * pax 10154b88c807SRodney W. Grimes * Return: 10164b88c807SRodney W. Grimes * 0 if found, -1 if not found. 10174b88c807SRodney W. Grimes */ 10184b88c807SRodney W. Grimes 10194b88c807SRodney W. Grimes int 10204b88c807SRodney W. Grimes get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime) 10214b88c807SRodney W. Grimes { 1022f789b261SWarner Losh ATDIR *pt; 1023f789b261SWarner Losh ATDIR **ppt; 1024f789b261SWarner Losh u_int indx; 10254b88c807SRodney W. Grimes 10264b88c807SRodney W. Grimes if (atab == NULL) 10274b88c807SRodney W. Grimes return(-1); 10284b88c807SRodney W. Grimes /* 10294b88c807SRodney W. Grimes * hash by inode and search the chain for an inode and device match 10304b88c807SRodney W. Grimes */ 10314b88c807SRodney W. Grimes indx = ((unsigned)ino) % A_TAB_SZ; 10324b88c807SRodney W. Grimes if ((pt = atab[indx]) == NULL) 10334b88c807SRodney W. Grimes return(-1); 10344b88c807SRodney W. Grimes 10354b88c807SRodney W. Grimes ppt = &(atab[indx]); 10364b88c807SRodney W. Grimes while (pt != NULL) { 10374b88c807SRodney W. Grimes if ((pt->ino == ino) && (pt->dev == dev)) 10384b88c807SRodney W. Grimes break; 10394b88c807SRodney W. Grimes /* 10404b88c807SRodney W. Grimes * no match, go to next one 10414b88c807SRodney W. Grimes */ 10424b88c807SRodney W. Grimes ppt = &(pt->fow); 10434b88c807SRodney W. Grimes pt = pt->fow; 10444b88c807SRodney W. Grimes } 10454b88c807SRodney W. Grimes 10464b88c807SRodney W. Grimes /* 10474b88c807SRodney W. Grimes * return if we did not find it. 10484b88c807SRodney W. Grimes */ 10494b88c807SRodney W. Grimes if (pt == NULL) 10504b88c807SRodney W. Grimes return(-1); 10514b88c807SRodney W. Grimes 10524b88c807SRodney W. Grimes /* 10534b88c807SRodney W. Grimes * found it. return the times and remove the entry from the table. 10544b88c807SRodney W. Grimes */ 10554b88c807SRodney W. Grimes *ppt = pt->fow; 10564b88c807SRodney W. Grimes *mtime = pt->mtime; 10574b88c807SRodney W. Grimes *atime = pt->atime; 10584b88c807SRodney W. Grimes (void)free((char *)pt->name); 10594b88c807SRodney W. Grimes (void)free((char *)pt); 10604b88c807SRodney W. Grimes return(0); 10614b88c807SRodney W. Grimes } 10624b88c807SRodney W. Grimes 10634b88c807SRodney W. Grimes /* 10644b88c807SRodney W. Grimes * directory access mode and time storage routines (for directories CREATED 10654b88c807SRodney W. Grimes * by pax). 10664b88c807SRodney W. Grimes * 10674b88c807SRodney W. Grimes * Pax requires that extracted directories, by default, have their access/mod 10684b88c807SRodney W. Grimes * times and permissions set to the values specified in the archive. During the 10694b88c807SRodney W. Grimes * actions of extracting (and creating the destination subtree during -rw copy) 10704b88c807SRodney W. Grimes * directories extracted may be modified after being created. Even worse is 10714b88c807SRodney W. Grimes * that these directories may have been created with file permissions which 10724b88c807SRodney W. Grimes * prohibits any descendants of these directories from being extracted. When 10734b88c807SRodney W. Grimes * directories are created by pax, access rights may be added to permit the 10744b88c807SRodney W. Grimes * creation of files in their subtree. Every time pax creates a directory, the 10754b88c807SRodney W. Grimes * times and file permissions specified by the archive are stored. After all 10764b88c807SRodney W. Grimes * files have been extracted (or copied), these directories have their times 10774b88c807SRodney W. Grimes * and file modes reset to the stored values. The directory info is restored in 10784b88c807SRodney W. Grimes * reverse order as entries were added to the data file from root to leaf. To 10794b88c807SRodney W. Grimes * restore atime properly, we must go backwards. The data file consists of 10804b88c807SRodney W. Grimes * records with two parts, the file name followed by a DIRDATA trailer. The 10814b88c807SRodney W. Grimes * fixed sized trailer contains the size of the name plus the off_t location in 10824b88c807SRodney W. Grimes * the file. To restore we work backwards through the file reading the trailer 10834b88c807SRodney W. Grimes * then the file name. 10844b88c807SRodney W. Grimes */ 10854b88c807SRodney W. Grimes 10864b88c807SRodney W. Grimes /* 10874b88c807SRodney W. Grimes * dir_start() 10884b88c807SRodney W. Grimes * set up the directory time and file mode storage for directories CREATED 10894b88c807SRodney W. Grimes * by pax. 10904b88c807SRodney W. Grimes * Return: 10914b88c807SRodney W. Grimes * 0 if ok, -1 otherwise 10924b88c807SRodney W. Grimes */ 10934b88c807SRodney W. Grimes 10944b88c807SRodney W. Grimes int 10954b88c807SRodney W. Grimes dir_start(void) 10964b88c807SRodney W. Grimes { 1097d12dd1a1SKris Kennaway 10984b88c807SRodney W. Grimes if (dirfd != -1) 10994b88c807SRodney W. Grimes return(0); 11004b88c807SRodney W. Grimes 11014b88c807SRodney W. Grimes /* 11024b88c807SRodney W. Grimes * unlink the file so it goes away at termination by itself 11034b88c807SRodney W. Grimes */ 1104ffbef1cdSKris Kennaway memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE)); 1105ffbef1cdSKris Kennaway if ((dirfd = mkstemp(tempfile)) >= 0) { 1106ffbef1cdSKris Kennaway (void)unlink(tempfile); 11074b88c807SRodney W. Grimes return(0); 11084b88c807SRodney W. Grimes } 1109778766feSKris Kennaway paxwarn(1, "Unable to create temporary file for directory times: %s", 1110ffbef1cdSKris Kennaway tempfile); 11114b88c807SRodney W. Grimes return(-1); 11124b88c807SRodney W. Grimes } 11134b88c807SRodney W. Grimes 11144b88c807SRodney W. Grimes /* 11154b88c807SRodney W. Grimes * add_dir() 11164b88c807SRodney W. Grimes * add the mode and times for a newly CREATED directory 11174b88c807SRodney W. Grimes * name is name of the directory, psb the stat buffer with the data in it, 11184b88c807SRodney W. Grimes * frc_mode is a flag that says whether to force the setting of the mode 11194b88c807SRodney W. Grimes * (ignoring the user set values for preserving file mode). Frc_mode is 11204b88c807SRodney W. Grimes * for the case where we created a file and found that the resulting 11214b88c807SRodney W. Grimes * directory was not writeable and the user asked for file modes to NOT 11224b88c807SRodney W. Grimes * be preserved. (we have to preserve what was created by default, so we 11234b88c807SRodney W. Grimes * have to force the setting at the end. this is stated explicitly in the 11244b88c807SRodney W. Grimes * pax spec) 11254b88c807SRodney W. Grimes */ 11264b88c807SRodney W. Grimes 11274b88c807SRodney W. Grimes void 11284b88c807SRodney W. Grimes add_dir(char *name, int nlen, struct stat *psb, int frc_mode) 11294b88c807SRodney W. Grimes { 11304b88c807SRodney W. Grimes DIRDATA dblk; 11314b88c807SRodney W. Grimes 11324b88c807SRodney W. Grimes if (dirfd < 0) 11334b88c807SRodney W. Grimes return; 11344b88c807SRodney W. Grimes 11354b88c807SRodney W. Grimes /* 11364b88c807SRodney W. Grimes * get current position (where file name will start) so we can store it 11374b88c807SRodney W. Grimes * in the trailer 11384b88c807SRodney W. Grimes */ 11394b88c807SRodney W. Grimes if ((dblk.npos = lseek(dirfd, 0L, SEEK_CUR)) < 0) { 1140778766feSKris Kennaway paxwarn(1,"Unable to store mode and times for directory: %s",name); 11414b88c807SRodney W. Grimes return; 11424b88c807SRodney W. Grimes } 11434b88c807SRodney W. Grimes 11444b88c807SRodney W. Grimes /* 11454b88c807SRodney W. Grimes * write the file name followed by the trailer 11464b88c807SRodney W. Grimes */ 11474b88c807SRodney W. Grimes dblk.nlen = nlen + 1; 11484b88c807SRodney W. Grimes dblk.mode = psb->st_mode & 0xffff; 11494b88c807SRodney W. Grimes dblk.mtime = psb->st_mtime; 11504b88c807SRodney W. Grimes dblk.atime = psb->st_atime; 11514b88c807SRodney W. Grimes dblk.frc_mode = frc_mode; 11524b88c807SRodney W. Grimes if ((write(dirfd, name, dblk.nlen) == dblk.nlen) && 11534b88c807SRodney W. Grimes (write(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) { 11544b88c807SRodney W. Grimes ++dircnt; 11554b88c807SRodney W. Grimes return; 11564b88c807SRodney W. Grimes } 11574b88c807SRodney W. Grimes 1158778766feSKris Kennaway paxwarn(1,"Unable to store mode and times for created directory: %s",name); 11594b88c807SRodney W. Grimes return; 11604b88c807SRodney W. Grimes } 11614b88c807SRodney W. Grimes 11624b88c807SRodney W. Grimes /* 11634b88c807SRodney W. Grimes * proc_dir() 11644b88c807SRodney W. Grimes * process all file modes and times stored for directories CREATED 11654b88c807SRodney W. Grimes * by pax 11664b88c807SRodney W. Grimes */ 11674b88c807SRodney W. Grimes 11684b88c807SRodney W. Grimes void 11694b88c807SRodney W. Grimes proc_dir(void) 11704b88c807SRodney W. Grimes { 11714b88c807SRodney W. Grimes char name[PAXPATHLEN+1]; 11724b88c807SRodney W. Grimes DIRDATA dblk; 11734b88c807SRodney W. Grimes u_long cnt; 11744b88c807SRodney W. Grimes 11754b88c807SRodney W. Grimes if (dirfd < 0) 11764b88c807SRodney W. Grimes return; 11774b88c807SRodney W. Grimes /* 11784b88c807SRodney W. Grimes * read backwards through the file and process each directory 11794b88c807SRodney W. Grimes */ 11804b88c807SRodney W. Grimes for (cnt = 0; cnt < dircnt; ++cnt) { 11814b88c807SRodney W. Grimes /* 11824b88c807SRodney W. Grimes * read the trailer, then the file name, if this fails 11834b88c807SRodney W. Grimes * just give up. 11844b88c807SRodney W. Grimes */ 11854b88c807SRodney W. Grimes if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0) 11864b88c807SRodney W. Grimes break; 11874b88c807SRodney W. Grimes if (read(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk)) 11884b88c807SRodney W. Grimes break; 11894b88c807SRodney W. Grimes if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) 11904b88c807SRodney W. Grimes break; 11914b88c807SRodney W. Grimes if (read(dirfd, name, dblk.nlen) != dblk.nlen) 11924b88c807SRodney W. Grimes break; 11934b88c807SRodney W. Grimes if (lseek(dirfd, dblk.npos, SEEK_SET) < 0) 11944b88c807SRodney W. Grimes break; 11954b88c807SRodney W. Grimes 11964b88c807SRodney W. Grimes /* 11974b88c807SRodney W. Grimes * frc_mode set, make sure we set the file modes even if 11984b88c807SRodney W. Grimes * the user didn't ask for it (see file_subs.c for more info) 11994b88c807SRodney W. Grimes */ 12004b88c807SRodney W. Grimes if (pmode || dblk.frc_mode) 12014b88c807SRodney W. Grimes set_pmode(name, dblk.mode); 12024b88c807SRodney W. Grimes if (patime || pmtime) 12034b88c807SRodney W. Grimes set_ftime(name, dblk.mtime, dblk.atime, 0); 12044b88c807SRodney W. Grimes } 12054b88c807SRodney W. Grimes 12064b88c807SRodney W. Grimes (void)close(dirfd); 12074b88c807SRodney W. Grimes dirfd = -1; 12084b88c807SRodney W. Grimes if (cnt != dircnt) 1209778766feSKris Kennaway paxwarn(1,"Unable to set mode and times for created directories"); 12104b88c807SRodney W. Grimes return; 12114b88c807SRodney W. Grimes } 12124b88c807SRodney W. Grimes 12134b88c807SRodney W. Grimes /* 12144b88c807SRodney W. Grimes * database independent routines 12154b88c807SRodney W. Grimes */ 12164b88c807SRodney W. Grimes 12174b88c807SRodney W. Grimes /* 12184b88c807SRodney W. Grimes * st_hash() 12194b88c807SRodney W. Grimes * hashes filenames to a u_int for hashing into a table. Looks at the tail 12204b88c807SRodney W. Grimes * end of file, as this provides far better distribution than any other 12214b88c807SRodney W. Grimes * part of the name. For performance reasons we only care about the last 12224b88c807SRodney W. Grimes * MAXKEYLEN chars (should be at LEAST large enough to pick off the file 12234b88c807SRodney W. Grimes * name). Was tested on 500,000 name file tree traversal from the root 12244b88c807SRodney W. Grimes * and gave almost a perfectly uniform distribution of keys when used with 12254b88c807SRodney W. Grimes * prime sized tables (MAXKEYLEN was 128 in test). Hashes (sizeof int) 12264b88c807SRodney W. Grimes * chars at a time and pads with 0 for last addition. 12274b88c807SRodney W. Grimes * Return: 12284b88c807SRodney W. Grimes * the hash value of the string MOD (%) the table size. 12294b88c807SRodney W. Grimes */ 12304b88c807SRodney W. Grimes 12314b88c807SRodney W. Grimes u_int 12324b88c807SRodney W. Grimes st_hash(char *name, int len, int tabsz) 12334b88c807SRodney W. Grimes { 1234f789b261SWarner Losh char *pt; 1235f789b261SWarner Losh char *dest; 1236f789b261SWarner Losh char *end; 1237f789b261SWarner Losh int i; 1238f789b261SWarner Losh u_int key = 0; 1239f789b261SWarner Losh int steps; 1240f789b261SWarner Losh int res; 12414b88c807SRodney W. Grimes u_int val; 12424b88c807SRodney W. Grimes 12434b88c807SRodney W. Grimes /* 12444b88c807SRodney W. Grimes * only look at the tail up to MAXKEYLEN, we do not need to waste 12454b88c807SRodney W. Grimes * time here (remember these are pathnames, the tail is what will 12464b88c807SRodney W. Grimes * spread out the keys) 12474b88c807SRodney W. Grimes */ 12484b88c807SRodney W. Grimes if (len > MAXKEYLEN) { 12494b88c807SRodney W. Grimes pt = &(name[len - MAXKEYLEN]); 12504b88c807SRodney W. Grimes len = MAXKEYLEN; 12514b88c807SRodney W. Grimes } else 12524b88c807SRodney W. Grimes pt = name; 12534b88c807SRodney W. Grimes 12544b88c807SRodney W. Grimes /* 12554b88c807SRodney W. Grimes * calculate the number of u_int size steps in the string and if 12564b88c807SRodney W. Grimes * there is a runt to deal with 12574b88c807SRodney W. Grimes */ 12584b88c807SRodney W. Grimes steps = len/sizeof(u_int); 12594b88c807SRodney W. Grimes res = len % sizeof(u_int); 12604b88c807SRodney W. Grimes 12614b88c807SRodney W. Grimes /* 12624b88c807SRodney W. Grimes * add up the value of the string in unsigned integer sized pieces 12634b88c807SRodney W. Grimes * too bad we cannot have unsigned int aligned strings, then we 12644b88c807SRodney W. Grimes * could avoid the expensive copy. 12654b88c807SRodney W. Grimes */ 12664b88c807SRodney W. Grimes for (i = 0; i < steps; ++i) { 12674b88c807SRodney W. Grimes end = pt + sizeof(u_int); 12684b88c807SRodney W. Grimes dest = (char *)&val; 12694b88c807SRodney W. Grimes while (pt < end) 12704b88c807SRodney W. Grimes *dest++ = *pt++; 12714b88c807SRodney W. Grimes key += val; 12724b88c807SRodney W. Grimes } 12734b88c807SRodney W. Grimes 12744b88c807SRodney W. Grimes /* 12754b88c807SRodney W. Grimes * add in the runt padded with zero to the right 12764b88c807SRodney W. Grimes */ 12774b88c807SRodney W. Grimes if (res) { 12784b88c807SRodney W. Grimes val = 0; 12794b88c807SRodney W. Grimes end = pt + res; 12804b88c807SRodney W. Grimes dest = (char *)&val; 12814b88c807SRodney W. Grimes while (pt < end) 12824b88c807SRodney W. Grimes *dest++ = *pt++; 12834b88c807SRodney W. Grimes key += val; 12844b88c807SRodney W. Grimes } 12854b88c807SRodney W. Grimes 12864b88c807SRodney W. Grimes /* 12874b88c807SRodney W. Grimes * return the result mod the table size 12884b88c807SRodney W. Grimes */ 12894b88c807SRodney W. Grimes return(key % tabsz); 12904b88c807SRodney W. Grimes } 1291