xref: /freebsd/bin/pax/tables.c (revision ffbef1cd72df344d28042741cc8bde3dceab4ad4)
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