xref: /netbsd-src/bin/pax/tables.c (revision 3dd8ce9f5e4237772b956ca51a2cee4f4d850572)
1*3dd8ce9fSchristos /*	$NetBSD: tables.c,v 1.31 2013/10/18 19:53:34 christos Exp $	*/
2b5b29542Sagc 
3b5b29542Sagc /*-
4ed6ed8e6Sagc  * Copyright (c) 1992 Keith Muller.
5b5b29542Sagc  * Copyright (c) 1992, 1993
6b5b29542Sagc  *	The Regents of the University of California.  All rights reserved.
7b5b29542Sagc  *
8b5b29542Sagc  * This code is derived from software contributed to Berkeley by
9b5b29542Sagc  * Keith Muller of the University of California, San Diego.
10b5b29542Sagc  *
11b5b29542Sagc  * Redistribution and use in source and binary forms, with or without
12b5b29542Sagc  * modification, are permitted provided that the following conditions
13b5b29542Sagc  * are met:
14b5b29542Sagc  * 1. Redistributions of source code must retain the above copyright
15b5b29542Sagc  *    notice, this list of conditions and the following disclaimer.
16b5b29542Sagc  * 2. Redistributions in binary form must reproduce the above copyright
17b5b29542Sagc  *    notice, this list of conditions and the following disclaimer in the
18b5b29542Sagc  *    documentation and/or other materials provided with the distribution.
19b5b29542Sagc  * 3. Neither the name of the University nor the names of its contributors
20b5b29542Sagc  *    may be used to endorse or promote products derived from this software
21b5b29542Sagc  *    without specific prior written permission.
22b5b29542Sagc  *
23b5b29542Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24b5b29542Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25b5b29542Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26b5b29542Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27b5b29542Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28b5b29542Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29b5b29542Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30b5b29542Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31b5b29542Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32b5b29542Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33b5b29542Sagc  * SUCH DAMAGE.
34b5b29542Sagc  */
3549f0ad86Scgd 
36171d6532Slukem #if HAVE_NBTOOL_CONFIG_H
37171d6532Slukem #include "nbtool_config.h"
38171d6532Slukem #endif
39171d6532Slukem 
40f3cd6022Schristos #include <sys/cdefs.h>
41171d6532Slukem #if !defined(lint)
4249f0ad86Scgd #if 0
4349f0ad86Scgd static char sccsid[] = "@(#)tables.c	8.1 (Berkeley) 5/31/93";
4449f0ad86Scgd #else
45*3dd8ce9fSchristos __RCSID("$NetBSD: tables.c,v 1.31 2013/10/18 19:53:34 christos Exp $");
4649f0ad86Scgd #endif
478b35abe2Sjtc #endif /* not lint */
488b35abe2Sjtc 
498b35abe2Sjtc #include <sys/types.h>
508b35abe2Sjtc #include <sys/time.h>
518b35abe2Sjtc #include <sys/stat.h>
528b35abe2Sjtc #include <sys/param.h>
538b35abe2Sjtc #include <stdio.h>
548b35abe2Sjtc #include <ctype.h>
55b75d6830Skleink #include <fcntl.h>
56e97454c2Skleink #include <paths.h>
578b35abe2Sjtc #include <string.h>
588b35abe2Sjtc #include <unistd.h>
598b35abe2Sjtc #include <errno.h>
608b35abe2Sjtc #include <stdlib.h>
618b35abe2Sjtc #include "pax.h"
628b35abe2Sjtc #include "tables.h"
638b35abe2Sjtc #include "extern.h"
648b35abe2Sjtc 
658b35abe2Sjtc /*
668b35abe2Sjtc  * Routines for controlling the contents of all the different databases pax
678b35abe2Sjtc  * keeps. Tables are dynamically created only when they are needed. The
688b35abe2Sjtc  * goal was speed and the ability to work with HUGE archives. The databases
698b35abe2Sjtc  * were kept simple, but do have complex rules for when the contents change.
705b367875Schristos  * As of this writing, the POSIX library functions were more complex than
718b35abe2Sjtc  * needed for this application (pax databases have very short lifetimes and
728b35abe2Sjtc  * do not survive after pax is finished). Pax is required to handle very
738b35abe2Sjtc  * large archives. These database routines carefully combine memory usage and
748b35abe2Sjtc  * temporary file storage in ways which will not significantly impact runtime
758b35abe2Sjtc  * performance while allowing the largest possible archives to be handled.
765b367875Schristos  * Trying to force the fit to the POSIX database routines was not considered
778b35abe2Sjtc  * time well spent.
788b35abe2Sjtc  */
798b35abe2Sjtc 
808b35abe2Sjtc static HRDLNK **ltab = NULL;	/* hard link table for detecting hard links */
818b35abe2Sjtc static FTM **ftab = NULL;	/* file time table for updating arch */
828b35abe2Sjtc static NAMT **ntab = NULL;	/* interactive rename storage table */
838b35abe2Sjtc static DEVT **dtab = NULL;	/* device/inode mapping tables */
848b35abe2Sjtc static ATDIR **atab = NULL;	/* file tree directory time reset table */
850317a206Sthorpej #ifdef DIRS_USE_FILE
868b35abe2Sjtc static int dirfd = -1;		/* storage for setting created dir time/mode */
878b35abe2Sjtc static u_long dircnt;		/* entries in dir time/mode storage */
880317a206Sthorpej #endif
898b35abe2Sjtc static int ffd = -1;		/* tmp file for file time table name storage */
908b35abe2Sjtc 
91c1bd745cSlukem static DEVT *chk_dev(dev_t, int);
928b35abe2Sjtc 
938b35abe2Sjtc /*
948b35abe2Sjtc  * hard link table routines
958b35abe2Sjtc  *
968b35abe2Sjtc  * The hard link table tries to detect hard links to files using the device and
978b35abe2Sjtc  * inode values. We do this when writing an archive, so we can tell the format
988b35abe2Sjtc  * write routine that this file is a hard link to another file. The format
998b35abe2Sjtc  * write routine then can store this file in whatever way it wants (as a hard
1008b35abe2Sjtc  * link if the format supports that like tar, or ignore this info like cpio).
1018b35abe2Sjtc  * (Actually a field in the format driver table tells us if the format wants
1028b35abe2Sjtc  * hard link info. if not, we do not waste time looking for them). We also use
1038b35abe2Sjtc  * the same table when reading an archive. In that situation, this table is
1048b35abe2Sjtc  * used by the format read routine to detect hard links from stored dev and
1058b35abe2Sjtc  * inode numbers (like cpio). This will allow pax to create a link when one
1068b35abe2Sjtc  * can be detected by the archive format.
1078b35abe2Sjtc  */
1088b35abe2Sjtc 
1098b35abe2Sjtc /*
1108b35abe2Sjtc  * lnk_start
1118b35abe2Sjtc  *	Creates the hard link table.
1128b35abe2Sjtc  * Return:
1138b35abe2Sjtc  *	0 if created, -1 if failure
1148b35abe2Sjtc  */
1158b35abe2Sjtc 
1168b35abe2Sjtc int
lnk_start(void)1178b35abe2Sjtc lnk_start(void)
1188b35abe2Sjtc {
1198b35abe2Sjtc 	if (ltab != NULL)
120cdec4ac1Sdsl 		return 0;
1218b35abe2Sjtc 	if ((ltab = (HRDLNK **)calloc(L_TAB_SZ, sizeof(HRDLNK *))) == NULL) {
122f3cd6022Schristos 		tty_warn(1, "Cannot allocate memory for hard link table");
123cdec4ac1Sdsl 		return -1;
1248b35abe2Sjtc 	}
125cdec4ac1Sdsl 	return 0;
1268b35abe2Sjtc }
1278b35abe2Sjtc 
1288b35abe2Sjtc /*
1298b35abe2Sjtc  * chk_lnk()
1308b35abe2Sjtc  *	Looks up entry in hard link hash table. If found, it copies the name
1318b35abe2Sjtc  *	of the file it is linked to (we already saw that file) into ln_name.
1328b35abe2Sjtc  *	lnkcnt is decremented and if goes to 1 the node is deleted from the
1338b35abe2Sjtc  *	database. (We have seen all the links to this file). If not found,
1348b35abe2Sjtc  *	we add the file to the database if it has the potential for having
1358b35abe2Sjtc  *	hard links to other files we may process (it has a link count > 1)
1368b35abe2Sjtc  * Return:
1378b35abe2Sjtc  *	if found returns 1; if not found returns 0; -1 on error
1388b35abe2Sjtc  */
1398b35abe2Sjtc 
1408b35abe2Sjtc int
chk_lnk(ARCHD * arcn)14148250187Stls chk_lnk(ARCHD *arcn)
1428b35abe2Sjtc {
14348250187Stls 	HRDLNK *pt;
14448250187Stls 	HRDLNK **ppt;
14548250187Stls 	u_int indx;
1468b35abe2Sjtc 
1478b35abe2Sjtc 	if (ltab == NULL)
148cdec4ac1Sdsl 		return -1;
1498b35abe2Sjtc 	/*
1508b35abe2Sjtc 	 * ignore those nodes that cannot have hard links
1518b35abe2Sjtc 	 */
1528b35abe2Sjtc 	if ((arcn->type == PAX_DIR) || (arcn->sb.st_nlink <= 1))
153cdec4ac1Sdsl 		return 0;
1548b35abe2Sjtc 
1558b35abe2Sjtc 	/*
1568b35abe2Sjtc 	 * hash inode number and look for this file
1578b35abe2Sjtc 	 */
1588b35abe2Sjtc 	indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ;
1598b35abe2Sjtc 	if ((pt = ltab[indx]) != NULL) {
1608b35abe2Sjtc 		/*
161a640fe8cSsnj 		 * its hash chain is not empty, walk down looking for it
1628b35abe2Sjtc 		 */
1638b35abe2Sjtc 		ppt = &(ltab[indx]);
1648b35abe2Sjtc 		while (pt != NULL) {
1658b35abe2Sjtc 			if ((pt->ino == arcn->sb.st_ino) &&
1668b35abe2Sjtc 			    (pt->dev == arcn->sb.st_dev))
1678b35abe2Sjtc 				break;
1688b35abe2Sjtc 			ppt = &(pt->fow);
1698b35abe2Sjtc 			pt = pt->fow;
1708b35abe2Sjtc 		}
1718b35abe2Sjtc 
1728b35abe2Sjtc 		if (pt != NULL) {
1738b35abe2Sjtc 			/*
1748b35abe2Sjtc 			 * found a link. set the node type and copy in the
1758b35abe2Sjtc 			 * name of the file it is to link to. we need to
1768b35abe2Sjtc 			 * handle hardlinks to regular files differently than
1778b35abe2Sjtc 			 * other links.
1788b35abe2Sjtc 			 */
1790c612021Schristos 			arcn->ln_nlen = strlcpy(arcn->ln_name, pt->name,
1800c612021Schristos 				sizeof(arcn->ln_name));
1818b35abe2Sjtc 			if (arcn->type == PAX_REG)
1828b35abe2Sjtc 				arcn->type = PAX_HRG;
1838b35abe2Sjtc 			else
1848b35abe2Sjtc 				arcn->type = PAX_HLK;
1858b35abe2Sjtc 
1868b35abe2Sjtc 			/*
1878b35abe2Sjtc 			 * if we have found all the links to this file, remove
1888b35abe2Sjtc 			 * it from the database
1898b35abe2Sjtc 			 */
1908b35abe2Sjtc 			if (--pt->nlink <= 1) {
1918b35abe2Sjtc 				*ppt = pt->fow;
1928b35abe2Sjtc 				(void)free((char *)pt->name);
1938b35abe2Sjtc 				(void)free((char *)pt);
1948b35abe2Sjtc 			}
195cdec4ac1Sdsl 			return 1;
1968b35abe2Sjtc 		}
1978b35abe2Sjtc 	}
1988b35abe2Sjtc 
1998b35abe2Sjtc 	/*
2008b35abe2Sjtc 	 * we never saw this file before. It has links so we add it to the
2018b35abe2Sjtc 	 * front of this hash chain
2028b35abe2Sjtc 	 */
2038b35abe2Sjtc 	if ((pt = (HRDLNK *)malloc(sizeof(HRDLNK))) != NULL) {
2048b35abe2Sjtc 		if ((pt->name = strdup(arcn->name)) != NULL) {
2058b35abe2Sjtc 			pt->dev = arcn->sb.st_dev;
2068b35abe2Sjtc 			pt->ino = arcn->sb.st_ino;
2078b35abe2Sjtc 			pt->nlink = arcn->sb.st_nlink;
2088b35abe2Sjtc 			pt->fow = ltab[indx];
2098b35abe2Sjtc 			ltab[indx] = pt;
210cdec4ac1Sdsl 			return 0;
2118b35abe2Sjtc 		}
2128b35abe2Sjtc 		(void)free((char *)pt);
2138b35abe2Sjtc 	}
2148b35abe2Sjtc 
215f3cd6022Schristos 	tty_warn(1, "Hard link table out of memory");
216cdec4ac1Sdsl 	return -1;
2178b35abe2Sjtc }
2188b35abe2Sjtc 
2198b35abe2Sjtc /*
2208b35abe2Sjtc  * purg_lnk
2218b35abe2Sjtc  *	remove reference for a file that we may have added to the data base as
2228b35abe2Sjtc  *	a potential source for hard links. We ended up not using the file, so
2233d98aa3fSchristos  *	we do not want to accidentally point another file at it later on.
2248b35abe2Sjtc  */
2258b35abe2Sjtc 
2268b35abe2Sjtc void
purg_lnk(ARCHD * arcn)22748250187Stls purg_lnk(ARCHD *arcn)
2288b35abe2Sjtc {
22948250187Stls 	HRDLNK *pt;
23048250187Stls 	HRDLNK **ppt;
23148250187Stls 	u_int indx;
2328b35abe2Sjtc 
2338b35abe2Sjtc 	if (ltab == NULL)
2348b35abe2Sjtc 		return;
2358b35abe2Sjtc 	/*
2368b35abe2Sjtc 	 * do not bother to look if it could not be in the database
2378b35abe2Sjtc 	 */
2388b35abe2Sjtc 	if ((arcn->sb.st_nlink <= 1) || (arcn->type == PAX_DIR) ||
2398b35abe2Sjtc 	    (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
2408b35abe2Sjtc 		return;
2418b35abe2Sjtc 
2428b35abe2Sjtc 	/*
2438b35abe2Sjtc 	 * find the hash chain for this inode value, if empty return
2448b35abe2Sjtc 	 */
2458b35abe2Sjtc 	indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ;
2468b35abe2Sjtc 	if ((pt = ltab[indx]) == NULL)
2478b35abe2Sjtc 		return;
2488b35abe2Sjtc 
2498b35abe2Sjtc 	/*
2508b35abe2Sjtc 	 * walk down the list looking for the inode/dev pair, unlink and
2518b35abe2Sjtc 	 * free if found
2528b35abe2Sjtc 	 */
2538b35abe2Sjtc 	ppt = &(ltab[indx]);
2548b35abe2Sjtc 	while (pt != NULL) {
2558b35abe2Sjtc 		if ((pt->ino == arcn->sb.st_ino) &&
2568b35abe2Sjtc 		    (pt->dev == arcn->sb.st_dev))
2578b35abe2Sjtc 			break;
2588b35abe2Sjtc 		ppt = &(pt->fow);
2598b35abe2Sjtc 		pt = pt->fow;
2608b35abe2Sjtc 	}
2618b35abe2Sjtc 	if (pt == NULL)
2628b35abe2Sjtc 		return;
2638b35abe2Sjtc 
2648b35abe2Sjtc 	/*
2658b35abe2Sjtc 	 * remove and free it
2668b35abe2Sjtc 	 */
2678b35abe2Sjtc 	*ppt = pt->fow;
2688b35abe2Sjtc 	(void)free((char *)pt->name);
2698b35abe2Sjtc 	(void)free((char *)pt);
2708b35abe2Sjtc }
2718b35abe2Sjtc 
2728b35abe2Sjtc /*
2738b35abe2Sjtc  * lnk_end()
2748b35abe2Sjtc  *	pull apart a existing link table so we can reuse it. We do this between
2758b35abe2Sjtc  *	read and write phases of append with update. (The format may have
2768b35abe2Sjtc  *	used the link table, and we need to start with a fresh table for the
2778b35abe2Sjtc  *	write phase
2788b35abe2Sjtc  */
2798b35abe2Sjtc 
2808b35abe2Sjtc void
lnk_end(void)2818b35abe2Sjtc lnk_end(void)
2828b35abe2Sjtc {
28348250187Stls 	int i;
28448250187Stls 	HRDLNK *pt;
28548250187Stls 	HRDLNK *ppt;
2868b35abe2Sjtc 
2878b35abe2Sjtc 	if (ltab == NULL)
2888b35abe2Sjtc 		return;
2898b35abe2Sjtc 
2908b35abe2Sjtc 	for (i = 0; i < L_TAB_SZ; ++i) {
2918b35abe2Sjtc 		if (ltab[i] == NULL)
2928b35abe2Sjtc 			continue;
2938b35abe2Sjtc 		pt = ltab[i];
2948b35abe2Sjtc 		ltab[i] = NULL;
2958b35abe2Sjtc 
2968b35abe2Sjtc 		/*
2978b35abe2Sjtc 		 * free up each entry on this chain
2988b35abe2Sjtc 		 */
2998b35abe2Sjtc 		while (pt != NULL) {
3008b35abe2Sjtc 			ppt = pt;
3018b35abe2Sjtc 			pt = ppt->fow;
3028b35abe2Sjtc 			(void)free((char *)ppt->name);
3038b35abe2Sjtc 			(void)free((char *)ppt);
3048b35abe2Sjtc 		}
3058b35abe2Sjtc 	}
3068b35abe2Sjtc 	return;
3078b35abe2Sjtc }
3088b35abe2Sjtc 
3098b35abe2Sjtc /*
3108b35abe2Sjtc  * modification time table routines
3118b35abe2Sjtc  *
3128b35abe2Sjtc  * The modification time table keeps track of last modification times for all
3138b35abe2Sjtc  * files stored in an archive during a write phase when -u is set. We only
3148b35abe2Sjtc  * add a file to the archive if it is newer than a file with the same name
3158b35abe2Sjtc  * already stored on the archive (if there is no other file with the same
3168b35abe2Sjtc  * name on the archive it is added). This applies to writes and appends.
3178b35abe2Sjtc  * An append with an -u must read the archive and store the modification time
3188b35abe2Sjtc  * for every file on that archive before starting the write phase. It is clear
3198b35abe2Sjtc  * that this is one HUGE database. To save memory space, the actual file names
3203ac7ce18Swiz  * are stored in a scratch file and indexed by an in-memory hash table. The
3218b35abe2Sjtc  * hash table is indexed by hashing the file path. The nodes in the table store
3228b35abe2Sjtc  * the length of the filename and the lseek offset within the scratch file
3233ac7ce18Swiz  * where the actual name is stored. Since there are never any deletions from this
3248b35abe2Sjtc  * table, fragmentation of the scratch file is never a issue. Lookups seem to
3258b35abe2Sjtc  * not exhibit any locality at all (files in the database are rarely
3263ac7ce18Swiz  * looked up more than once...), so caching is just a waste of memory. The
3273ac7ce18Swiz  * only limitation is the amount of scratch file space available to store the
3288b35abe2Sjtc  * path names.
3298b35abe2Sjtc  */
3308b35abe2Sjtc 
3318b35abe2Sjtc /*
3328b35abe2Sjtc  * ftime_start()
3338b35abe2Sjtc  *	create the file time hash table and open for read/write the scratch
3348b35abe2Sjtc  *	file. (after created it is unlinked, so when we exit we leave
3358b35abe2Sjtc  *	no witnesses).
3368b35abe2Sjtc  * Return:
3378b35abe2Sjtc  *	0 if the table and file was created ok, -1 otherwise
3388b35abe2Sjtc  */
3398b35abe2Sjtc 
3408b35abe2Sjtc int
ftime_start(void)3418b35abe2Sjtc ftime_start(void)
3428b35abe2Sjtc {
3438b35abe2Sjtc 	if (ftab != NULL)
344cdec4ac1Sdsl 		return 0;
3458b35abe2Sjtc 	if ((ftab = (FTM **)calloc(F_TAB_SZ, sizeof(FTM *))) == NULL) {
346f3cd6022Schristos 		tty_warn(1, "Cannot allocate memory for file time table");
347cdec4ac1Sdsl 		return -1;
3488b35abe2Sjtc 	}
3498b35abe2Sjtc 
3508b35abe2Sjtc 	/*
3518b35abe2Sjtc 	 * get random name and create temporary scratch file, unlink name
3528b35abe2Sjtc 	 * so it will get removed on exit
3538b35abe2Sjtc 	 */
3540c612021Schristos 	memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE));
3550c612021Schristos 	if ((ffd = mkstemp(tempfile)) == -1) {
356e97454c2Skleink 		syswarn(1, errno, "Unable to create temporary file: %s",
3570c612021Schristos 		    tempfile);
358cdec4ac1Sdsl 		return -1;
3598b35abe2Sjtc 	}
3608b35abe2Sjtc 
3610c612021Schristos 	(void)unlink(tempfile);
362cdec4ac1Sdsl 	return 0;
3638b35abe2Sjtc }
3648b35abe2Sjtc 
3658b35abe2Sjtc /*
3668b35abe2Sjtc  * chk_ftime()
3678b35abe2Sjtc  *	looks up entry in file time hash table. If not found, the file is
3688b35abe2Sjtc  *	added to the hash table and the file named stored in the scratch file.
3698b35abe2Sjtc  *	If a file with the same name is found, the file times are compared and
3708b35abe2Sjtc  *	the most recent file time is retained. If the new file was younger (or
3718b35abe2Sjtc  *	was not in the database) the new file is selected for storage.
3728b35abe2Sjtc  * Return:
3738b35abe2Sjtc  *	0 if file should be added to the archive, 1 if it should be skipped,
3748b35abe2Sjtc  *	-1 on error
3758b35abe2Sjtc  */
3768b35abe2Sjtc 
3778b35abe2Sjtc int
chk_ftime(ARCHD * arcn)37848250187Stls chk_ftime(ARCHD *arcn)
3798b35abe2Sjtc {
38048250187Stls 	FTM *pt;
38148250187Stls 	int namelen;
38248250187Stls 	u_int indx;
3838b35abe2Sjtc 	char ckname[PAXPATHLEN+1];
3848b35abe2Sjtc 
3858b35abe2Sjtc 	/*
3868b35abe2Sjtc 	 * no info, go ahead and add to archive
3878b35abe2Sjtc 	 */
3888b35abe2Sjtc 	if (ftab == NULL)
389cdec4ac1Sdsl 		return 0;
3908b35abe2Sjtc 
3918b35abe2Sjtc 	/*
3928b35abe2Sjtc 	 * hash the pathname and look up in table
3938b35abe2Sjtc 	 */
3948b35abe2Sjtc 	namelen = arcn->nlen;
3958b35abe2Sjtc 	indx = st_hash(arcn->name, namelen, F_TAB_SZ);
3968b35abe2Sjtc 	if ((pt = ftab[indx]) != NULL) {
3978b35abe2Sjtc 		/*
3988b35abe2Sjtc 		 * the hash chain is not empty, walk down looking for match
3998b35abe2Sjtc 		 * only read up the path names if the lengths match, speeds
4008b35abe2Sjtc 		 * up the search a lot
4018b35abe2Sjtc 		 */
4028b35abe2Sjtc 		while (pt != NULL) {
4038b35abe2Sjtc 			if (pt->namelen == namelen) {
4048b35abe2Sjtc 				/*
4058b35abe2Sjtc 				 * potential match, have to read the name
4068b35abe2Sjtc 				 * from the scratch file.
4078b35abe2Sjtc 				 */
4088b35abe2Sjtc 				if (lseek(ffd,pt->seek,SEEK_SET) != pt->seek) {
4098b35abe2Sjtc 					syswarn(1, errno,
4108b35abe2Sjtc 					    "Failed ftime table seek");
411cdec4ac1Sdsl 					return -1;
4128b35abe2Sjtc 				}
413ba0ae447Sitohy 				if (xread(ffd, ckname, namelen) != namelen) {
4148b35abe2Sjtc 					syswarn(1, errno,
4158b35abe2Sjtc 					    "Failed ftime table read");
416cdec4ac1Sdsl 					return -1;
4178b35abe2Sjtc 				}
4188b35abe2Sjtc 
4198b35abe2Sjtc 				/*
4208b35abe2Sjtc 				 * if the names match, we are done
4218b35abe2Sjtc 				 */
4228b35abe2Sjtc 				if (!strncmp(ckname, arcn->name, namelen))
4238b35abe2Sjtc 					break;
4248b35abe2Sjtc 			}
4258b35abe2Sjtc 
4268b35abe2Sjtc 			/*
4278b35abe2Sjtc 			 * try the next entry on the chain
4288b35abe2Sjtc 			 */
4298b35abe2Sjtc 			pt = pt->fow;
4308b35abe2Sjtc 		}
4318b35abe2Sjtc 
4328b35abe2Sjtc 		if (pt != NULL) {
4338b35abe2Sjtc 			/*
4348b35abe2Sjtc 			 * found the file, compare the times, save the newer
4358b35abe2Sjtc 			 */
4368b35abe2Sjtc 			if (arcn->sb.st_mtime > pt->mtime) {
4378b35abe2Sjtc 				/*
4388b35abe2Sjtc 				 * file is newer
4398b35abe2Sjtc 				 */
4408b35abe2Sjtc 				pt->mtime = arcn->sb.st_mtime;
441cdec4ac1Sdsl 				return 0;
4428b35abe2Sjtc 			}
4438b35abe2Sjtc 			/*
4448b35abe2Sjtc 			 * file is older
4458b35abe2Sjtc 			 */
446cdec4ac1Sdsl 			return 1;
4478b35abe2Sjtc 		}
4488b35abe2Sjtc 	}
4498b35abe2Sjtc 
4508b35abe2Sjtc 	/*
4518b35abe2Sjtc 	 * not in table, add it
4528b35abe2Sjtc 	 */
4538b35abe2Sjtc 	if ((pt = (FTM *)malloc(sizeof(FTM))) != NULL) {
4548b35abe2Sjtc 		/*
4558b35abe2Sjtc 		 * add the name at the end of the scratch file, saving the
4568b35abe2Sjtc 		 * offset. add the file to the head of the hash chain
4578b35abe2Sjtc 		 */
4588b35abe2Sjtc 		if ((pt->seek = lseek(ffd, (off_t)0, SEEK_END)) >= 0) {
459ba0ae447Sitohy 			if (xwrite(ffd, arcn->name, namelen) == namelen) {
4608b35abe2Sjtc 				pt->mtime = arcn->sb.st_mtime;
4618b35abe2Sjtc 				pt->namelen = namelen;
4628b35abe2Sjtc 				pt->fow = ftab[indx];
4638b35abe2Sjtc 				ftab[indx] = pt;
464cdec4ac1Sdsl 				return 0;
4658b35abe2Sjtc 			}
4668b35abe2Sjtc 			syswarn(1, errno, "Failed write to file time table");
4678b35abe2Sjtc 		} else
4688b35abe2Sjtc 			syswarn(1, errno, "Failed seek on file time table");
4698b35abe2Sjtc 	} else
470f3cd6022Schristos 		tty_warn(1, "File time table ran out of memory");
4718b35abe2Sjtc 
4728b35abe2Sjtc 	if (pt != NULL)
4738b35abe2Sjtc 		(void)free((char *)pt);
474cdec4ac1Sdsl 	return -1;
4758b35abe2Sjtc }
4768b35abe2Sjtc 
4778b35abe2Sjtc /*
4788b35abe2Sjtc  * Interactive rename table routines
4798b35abe2Sjtc  *
4808b35abe2Sjtc  * The interactive rename table keeps track of the new names that the user
481f8adf56dSitohy  * assigns to files from tty input. Since this map is unique for each file
4828b35abe2Sjtc  * we must store it in case there is a reference to the file later in archive
4838b35abe2Sjtc  * (a link). Otherwise we will be unable to find the file we know was
4848b35abe2Sjtc  * extracted. The remapping of these files is stored in a memory based hash
4858b35abe2Sjtc  * table (it is assumed since input must come from /dev/tty, it is unlikely to
4868b35abe2Sjtc  * be a very large table).
4878b35abe2Sjtc  */
4888b35abe2Sjtc 
4898b35abe2Sjtc /*
4908b35abe2Sjtc  * name_start()
4918b35abe2Sjtc  *	create the interactive rename table
4928b35abe2Sjtc  * Return:
4938b35abe2Sjtc  *	0 if successful, -1 otherwise
4948b35abe2Sjtc  */
4958b35abe2Sjtc 
4968b35abe2Sjtc int
name_start(void)4978b35abe2Sjtc name_start(void)
4988b35abe2Sjtc {
4998b35abe2Sjtc 	if (ntab != NULL)
500cdec4ac1Sdsl 		return 0;
5018b35abe2Sjtc 	if ((ntab = (NAMT **)calloc(N_TAB_SZ, sizeof(NAMT *))) == NULL) {
502f3cd6022Schristos 		tty_warn(1,
503f3cd6022Schristos 		    "Cannot allocate memory for interactive rename table");
504cdec4ac1Sdsl 		return -1;
5058b35abe2Sjtc 	}
506cdec4ac1Sdsl 	return 0;
5078b35abe2Sjtc }
5088b35abe2Sjtc 
5098b35abe2Sjtc /*
5108b35abe2Sjtc  * add_name()
5118b35abe2Sjtc  *	add the new name to old name mapping just created by the user.
5128b35abe2Sjtc  *	If an old name mapping is found (there may be duplicate names on an
5138b35abe2Sjtc  *	archive) only the most recent is kept.
5148b35abe2Sjtc  * Return:
5158b35abe2Sjtc  *	0 if added, -1 otherwise
5168b35abe2Sjtc  */
5178b35abe2Sjtc 
5188b35abe2Sjtc int
add_name(char * oname,int onamelen,char * nname)51948250187Stls add_name(char *oname, int onamelen, char *nname)
5208b35abe2Sjtc {
52148250187Stls 	NAMT *pt;
52248250187Stls 	u_int indx;
5238b35abe2Sjtc 
5248b35abe2Sjtc 	if (ntab == NULL) {
5258b35abe2Sjtc 		/*
5268b35abe2Sjtc 		 * should never happen
5278b35abe2Sjtc 		 */
528f3cd6022Schristos 		tty_warn(0, "No interactive rename table, links may fail\n");
529cdec4ac1Sdsl 		return 0;
5308b35abe2Sjtc 	}
5318b35abe2Sjtc 
5328b35abe2Sjtc 	/*
5338b35abe2Sjtc 	 * look to see if we have already mapped this file, if so we
5348b35abe2Sjtc 	 * will update it
5358b35abe2Sjtc 	 */
5368b35abe2Sjtc 	indx = st_hash(oname, onamelen, N_TAB_SZ);
5378b35abe2Sjtc 	if ((pt = ntab[indx]) != NULL) {
5388b35abe2Sjtc 		/*
5398b35abe2Sjtc 		 * look down the has chain for the file
5408b35abe2Sjtc 		 */
5418b35abe2Sjtc 		while ((pt != NULL) && (strcmp(oname, pt->oname) != 0))
5428b35abe2Sjtc 			pt = pt->fow;
5438b35abe2Sjtc 
5448b35abe2Sjtc 		if (pt != NULL) {
5458b35abe2Sjtc 			/*
5468b35abe2Sjtc 			 * found an old mapping, replace it with the new one
5478b35abe2Sjtc 			 * the user just input (if it is different)
5488b35abe2Sjtc 			 */
5498b35abe2Sjtc 			if (strcmp(nname, pt->nname) == 0)
550cdec4ac1Sdsl 				return 0;
5518b35abe2Sjtc 
5528b35abe2Sjtc 			(void)free((char *)pt->nname);
5538b35abe2Sjtc 			if ((pt->nname = strdup(nname)) == NULL) {
554f3cd6022Schristos 				tty_warn(1, "Cannot update rename table");
555cdec4ac1Sdsl 				return -1;
5568b35abe2Sjtc 			}
557cdec4ac1Sdsl 			return 0;
5588b35abe2Sjtc 		}
5598b35abe2Sjtc 	}
5608b35abe2Sjtc 
5618b35abe2Sjtc 	/*
5628b35abe2Sjtc 	 * this is a new mapping, add it to the table
5638b35abe2Sjtc 	 */
5648b35abe2Sjtc 	if ((pt = (NAMT *)malloc(sizeof(NAMT))) != NULL) {
5658b35abe2Sjtc 		if ((pt->oname = strdup(oname)) != NULL) {
5668b35abe2Sjtc 			if ((pt->nname = strdup(nname)) != NULL) {
5678b35abe2Sjtc 				pt->fow = ntab[indx];
5688b35abe2Sjtc 				ntab[indx] = pt;
569cdec4ac1Sdsl 				return 0;
5708b35abe2Sjtc 			}
5718b35abe2Sjtc 			(void)free((char *)pt->oname);
5728b35abe2Sjtc 		}
5738b35abe2Sjtc 		(void)free((char *)pt);
5748b35abe2Sjtc 	}
575f3cd6022Schristos 	tty_warn(1, "Interactive rename table out of memory");
576cdec4ac1Sdsl 	return -1;
5778b35abe2Sjtc }
5788b35abe2Sjtc 
5798b35abe2Sjtc /*
5808b35abe2Sjtc  * sub_name()
5818b35abe2Sjtc  *	look up a link name to see if it points at a file that has been
5828b35abe2Sjtc  *	remapped by the user. If found, the link is adjusted to contain the
5838b35abe2Sjtc  *	new name (oname is the link to name)
5848b35abe2Sjtc  */
5858b35abe2Sjtc 
5868b35abe2Sjtc void
sub_name(char * oname,int * onamelen,size_t onamesize)5870c612021Schristos sub_name(char *oname, int *onamelen, size_t onamesize)
5888b35abe2Sjtc {
58948250187Stls 	NAMT *pt;
59048250187Stls 	u_int indx;
5918b35abe2Sjtc 
5928b35abe2Sjtc 	if (ntab == NULL)
5938b35abe2Sjtc 		return;
5948b35abe2Sjtc 	/*
5958b35abe2Sjtc 	 * look the name up in the hash table
5968b35abe2Sjtc 	 */
5978b35abe2Sjtc 	indx = st_hash(oname, *onamelen, N_TAB_SZ);
5988b35abe2Sjtc 	if ((pt = ntab[indx]) == NULL)
5998b35abe2Sjtc 		return;
6008b35abe2Sjtc 
6018b35abe2Sjtc 	while (pt != NULL) {
6028b35abe2Sjtc 		/*
603655fadf6Slukem 		 * walk down the hash chain looking for a match
6048b35abe2Sjtc 		 */
6058b35abe2Sjtc 		if (strcmp(oname, pt->oname) == 0) {
6068b35abe2Sjtc 			/*
6078b35abe2Sjtc 			 * found it, replace it with the new name
6088b35abe2Sjtc 			 * and return (we know that oname has enough space)
6098b35abe2Sjtc 			 */
6100c612021Schristos 			*onamelen = strlcpy(oname, pt->nname, onamesize);
6118b35abe2Sjtc 			return;
6128b35abe2Sjtc 		}
6138b35abe2Sjtc 		pt = pt->fow;
6148b35abe2Sjtc 	}
6158b35abe2Sjtc 
6168b35abe2Sjtc 	/*
6178b35abe2Sjtc 	 * no match, just return
6188b35abe2Sjtc 	 */
6198b35abe2Sjtc 	return;
6208b35abe2Sjtc }
6218b35abe2Sjtc 
6228b35abe2Sjtc /*
6238b35abe2Sjtc  * device/inode mapping table routines
6248b35abe2Sjtc  * (used with formats that store device and inodes fields)
6258b35abe2Sjtc  *
6268ce1f4ffSmsaitoh  * device/inode mapping tables remap the device field in an archive header. The
6278b35abe2Sjtc  * device/inode fields are used to determine when files are hard links to each
6288b35abe2Sjtc  * other. However these values have very little meaning outside of that. This
6298b35abe2Sjtc  * database is used to solve one of two different problems.
6308b35abe2Sjtc  *
6318b35abe2Sjtc  * 1) when files are appended to an archive, while the new files may have hard
6328b35abe2Sjtc  * links to each other, you cannot determine if they have hard links to any
6338b35abe2Sjtc  * file already stored on the archive from a prior run of pax. We must assume
6348b35abe2Sjtc  * that these inode/device pairs are unique only within a SINGLE run of pax
6358b35abe2Sjtc  * (which adds a set of files to an archive). So we have to make sure the
6368b35abe2Sjtc  * inode/dev pairs we add each time are always unique. We do this by observing
6378b35abe2Sjtc  * while the inode field is very dense, the use of the dev field is fairly
6388b35abe2Sjtc  * sparse. Within each run of pax, we remap any device number of a new archive
6398b35abe2Sjtc  * member that has a device number used in a prior run and already stored in a
6408b35abe2Sjtc  * file on the archive. During the read phase of the append, we store the
6418b35abe2Sjtc  * device numbers used and mark them to not be used by any file during the
6428b35abe2Sjtc  * write phase. If during write we go to use one of those old device numbers,
6438b35abe2Sjtc  * we remap it to a new value.
6448b35abe2Sjtc  *
6458b35abe2Sjtc  * 2) Often the fields in the archive header used to store these values are
6468b35abe2Sjtc  * too small to store the entire value. The result is an inode or device value
6478b35abe2Sjtc  * which can be truncated. This really can foul up an archive. With truncation
6488b35abe2Sjtc  * we end up creating links between files that are really not links (after
6498b35abe2Sjtc  * truncation the inodes are the same value). We address that by detecting
6508b35abe2Sjtc  * truncation and forcing a remap of the device field to split truncated
6518b35abe2Sjtc  * inodes away from each other. Each truncation creates a pattern of bits that
6528b35abe2Sjtc  * are removed. We use this pattern of truncated bits to partition the inodes
6538b35abe2Sjtc  * on a single device to many different devices (each one represented by the
6548b35abe2Sjtc  * truncated bit pattern). All inodes on the same device that have the same
6558b35abe2Sjtc  * truncation pattern are mapped to the same new device. Two inodes that
6568b35abe2Sjtc  * truncate to the same value clearly will always have different truncation
6578b35abe2Sjtc  * bit patterns, so they will be split from away each other. When we spot
6588b35abe2Sjtc  * device truncation we remap the device number to a non truncated value.
6598b35abe2Sjtc  * (for more info see table.h for the data structures involved).
6608b35abe2Sjtc  */
6618b35abe2Sjtc 
6628b35abe2Sjtc /*
6638b35abe2Sjtc  * dev_start()
6648b35abe2Sjtc  *	create the device mapping table
6658b35abe2Sjtc  * Return:
6668b35abe2Sjtc  *	0 if successful, -1 otherwise
6678b35abe2Sjtc  */
6688b35abe2Sjtc 
6698b35abe2Sjtc int
dev_start(void)6708b35abe2Sjtc dev_start(void)
6718b35abe2Sjtc {
6728b35abe2Sjtc 	if (dtab != NULL)
673cdec4ac1Sdsl 		return 0;
6748b35abe2Sjtc 	if ((dtab = (DEVT **)calloc(D_TAB_SZ, sizeof(DEVT *))) == NULL) {
675f3cd6022Schristos 		tty_warn(1, "Cannot allocate memory for device mapping table");
676cdec4ac1Sdsl 		return -1;
6778b35abe2Sjtc 	}
678cdec4ac1Sdsl 	return 0;
6798b35abe2Sjtc }
6808b35abe2Sjtc 
6818b35abe2Sjtc /*
6828b35abe2Sjtc  * add_dev()
6838b35abe2Sjtc  *	add a device number to the table. this will force the device to be
6848b35abe2Sjtc  *	remapped to a new value if it be used during a write phase. This
6858b35abe2Sjtc  *	function is called during the read phase of an append to prohibit the
6868b35abe2Sjtc  *	use of any device number already in the archive.
6878b35abe2Sjtc  * Return:
6888b35abe2Sjtc  *	0 if added ok, -1 otherwise
6898b35abe2Sjtc  */
6908b35abe2Sjtc 
6918b35abe2Sjtc int
add_dev(ARCHD * arcn)69248250187Stls add_dev(ARCHD *arcn)
6938b35abe2Sjtc {
6948b35abe2Sjtc 	if (chk_dev(arcn->sb.st_dev, 1) == NULL)
695cdec4ac1Sdsl 		return -1;
696cdec4ac1Sdsl 	return 0;
6978b35abe2Sjtc }
6988b35abe2Sjtc 
6998b35abe2Sjtc /*
7008b35abe2Sjtc  * chk_dev()
7018b35abe2Sjtc  *	check for a device value in the device table. If not found and the add
7028b35abe2Sjtc  *	flag is set, it is added. This does NOT assign any mapping values, just
7038b35abe2Sjtc  *	adds the device number as one that need to be remapped. If this device
704f8adf56dSitohy  *	is already mapped, just return with a pointer to that entry.
7058b35abe2Sjtc  * Return:
7068b35abe2Sjtc  *	pointer to the entry for this device in the device map table. Null
7078b35abe2Sjtc  *	if the add flag is not set and the device is not in the table (it is
7088b35abe2Sjtc  *	not been seen yet). If add is set and the device cannot be added, null
7098b35abe2Sjtc  *	is returned (indicates an error).
7108b35abe2Sjtc  */
7118b35abe2Sjtc 
7128b35abe2Sjtc static DEVT *
chk_dev(dev_t dev,int add)7138b35abe2Sjtc chk_dev(dev_t dev, int add)
7148b35abe2Sjtc {
71548250187Stls 	DEVT *pt;
71648250187Stls 	u_int indx;
7178b35abe2Sjtc 
7188b35abe2Sjtc 	if (dtab == NULL)
719cdec4ac1Sdsl 		return NULL;
7208b35abe2Sjtc 	/*
7218b35abe2Sjtc 	 * look to see if this device is already in the table
7228b35abe2Sjtc 	 */
7238b35abe2Sjtc 	indx = ((unsigned)dev) % D_TAB_SZ;
7248b35abe2Sjtc 	if ((pt = dtab[indx]) != NULL) {
7258b35abe2Sjtc 		while ((pt != NULL) && (pt->dev != dev))
7268b35abe2Sjtc 			pt = pt->fow;
7278b35abe2Sjtc 
7288b35abe2Sjtc 		/*
7298b35abe2Sjtc 		 * found it, return a pointer to it
7308b35abe2Sjtc 		 */
7318b35abe2Sjtc 		if (pt != NULL)
732cdec4ac1Sdsl 			return pt;
7338b35abe2Sjtc 	}
7348b35abe2Sjtc 
7358b35abe2Sjtc 	/*
7368b35abe2Sjtc 	 * not in table, we add it only if told to as this may just be a check
7378b35abe2Sjtc 	 * to see if a device number is being used.
7388b35abe2Sjtc 	 */
7398b35abe2Sjtc 	if (add == 0)
740cdec4ac1Sdsl 		return NULL;
7418b35abe2Sjtc 
7428b35abe2Sjtc 	/*
7438b35abe2Sjtc 	 * allocate a node for this device and add it to the front of the hash
7448b35abe2Sjtc 	 * chain. Note we do not assign remaps values here, so the pt->list
7458b35abe2Sjtc 	 * list must be NULL.
7468b35abe2Sjtc 	 */
7478b35abe2Sjtc 	if ((pt = (DEVT *)malloc(sizeof(DEVT))) == NULL) {
748f3cd6022Schristos 		tty_warn(1, "Device map table out of memory");
749cdec4ac1Sdsl 		return NULL;
7508b35abe2Sjtc 	}
7518b35abe2Sjtc 	pt->dev = dev;
7528b35abe2Sjtc 	pt->list = NULL;
7538b35abe2Sjtc 	pt->fow = dtab[indx];
7548b35abe2Sjtc 	dtab[indx] = pt;
755cdec4ac1Sdsl 	return pt;
7568b35abe2Sjtc }
7578b35abe2Sjtc /*
7588b35abe2Sjtc  * map_dev()
7598b35abe2Sjtc  *	given an inode and device storage mask (the mask has a 1 for each bit
7608b35abe2Sjtc  *	the archive format is able to store in a header), we check for inode
7618b35abe2Sjtc  *	and device truncation and remap the device as required. Device mapping
7628b35abe2Sjtc  *	can also occur when during the read phase of append a device number was
7638b35abe2Sjtc  *	seen (and was marked as do not use during the write phase). WE ASSUME
7648b35abe2Sjtc  *	that unsigned longs are the same size or bigger than the fields used
7658b35abe2Sjtc  *	for ino_t and dev_t. If not the types will have to be changed.
7668b35abe2Sjtc  * Return:
7678b35abe2Sjtc  *	0 if all ok, -1 otherwise.
7688b35abe2Sjtc  */
7698b35abe2Sjtc 
7708b35abe2Sjtc int
map_dev(ARCHD * arcn,u_long dev_mask,u_long ino_mask)77148250187Stls map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask)
7728b35abe2Sjtc {
77348250187Stls 	DEVT *pt;
77448250187Stls 	DLIST *dpt;
7758b35abe2Sjtc 	static dev_t lastdev = 0;	/* next device number to try */
7768b35abe2Sjtc 	int trc_ino = 0;
7778b35abe2Sjtc 	int trc_dev = 0;
7788b35abe2Sjtc 	ino_t trunc_bits = 0;
7798b35abe2Sjtc 	ino_t nino;
7808b35abe2Sjtc 
7818b35abe2Sjtc 	if (dtab == NULL)
782cdec4ac1Sdsl 		return 0;
7838b35abe2Sjtc 	/*
7848b35abe2Sjtc 	 * check for device and inode truncation, and extract the truncated
7858b35abe2Sjtc 	 * bit pattern.
7868b35abe2Sjtc 	 */
7878b35abe2Sjtc 	if ((arcn->sb.st_dev & (dev_t)dev_mask) != arcn->sb.st_dev)
7888b35abe2Sjtc 		++trc_dev;
7898b35abe2Sjtc 	if ((nino = arcn->sb.st_ino & (ino_t)ino_mask) != arcn->sb.st_ino) {
7908b35abe2Sjtc 		++trc_ino;
7918b35abe2Sjtc 		trunc_bits = arcn->sb.st_ino & (ino_t)(~ino_mask);
7928b35abe2Sjtc 	}
7938b35abe2Sjtc 
7948b35abe2Sjtc 	/*
7958b35abe2Sjtc 	 * see if this device is already being mapped, look up the device
7968b35abe2Sjtc 	 * then find the truncation bit pattern which applies
7978b35abe2Sjtc 	 */
7988b35abe2Sjtc 	if ((pt = chk_dev(arcn->sb.st_dev, 0)) != NULL) {
7998b35abe2Sjtc 		/*
8008b35abe2Sjtc 		 * this device is already marked to be remapped
8018b35abe2Sjtc 		 */
8028b35abe2Sjtc 		for (dpt = pt->list; dpt != NULL; dpt = dpt->fow)
8038b35abe2Sjtc 			if (dpt->trunc_bits == trunc_bits)
8048b35abe2Sjtc 				break;
8058b35abe2Sjtc 
8068b35abe2Sjtc 		if (dpt != NULL) {
8078b35abe2Sjtc 			/*
8088b35abe2Sjtc 			 * we are being remapped for this device and pattern
8098b35abe2Sjtc 			 * change the device number to be stored and return
8108b35abe2Sjtc 			 */
8118b35abe2Sjtc 			arcn->sb.st_dev = dpt->dev;
8128b35abe2Sjtc 			arcn->sb.st_ino = nino;
813cdec4ac1Sdsl 			return 0;
8148b35abe2Sjtc 		}
8158b35abe2Sjtc 	} else {
8168b35abe2Sjtc 		/*
8178b35abe2Sjtc 		 * this device is not being remapped YET. if we do not have any
8188b35abe2Sjtc 		 * form of truncation, we do not need a remap
8198b35abe2Sjtc 		 */
8208b35abe2Sjtc 		if (!trc_ino && !trc_dev)
821cdec4ac1Sdsl 			return 0;
8228b35abe2Sjtc 
8238b35abe2Sjtc 		/*
8248b35abe2Sjtc 		 * we have truncation, have to add this as a device to remap
8258b35abe2Sjtc 		 */
8268b35abe2Sjtc 		if ((pt = chk_dev(arcn->sb.st_dev, 1)) == NULL)
8278b35abe2Sjtc 			goto bad;
8288b35abe2Sjtc 
8298b35abe2Sjtc 		/*
8308b35abe2Sjtc 		 * if we just have a truncated inode, we have to make sure that
8318b35abe2Sjtc 		 * all future inodes that do not truncate (they have the
8328b35abe2Sjtc 		 * truncation pattern of all 0's) continue to map to the same
8338b35abe2Sjtc 		 * device number. We probably have already written inodes with
8348b35abe2Sjtc 		 * this device number to the archive with the truncation
8358b35abe2Sjtc 		 * pattern of all 0's. So we add the mapping for all 0's to the
8368b35abe2Sjtc 		 * same device number.
8378b35abe2Sjtc 		 */
8388b35abe2Sjtc 		if (!trc_dev && (trunc_bits != 0)) {
8398b35abe2Sjtc 			if ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL)
8408b35abe2Sjtc 				goto bad;
8418b35abe2Sjtc 			dpt->trunc_bits = 0;
8428b35abe2Sjtc 			dpt->dev = arcn->sb.st_dev;
8438b35abe2Sjtc 			dpt->fow = pt->list;
8448b35abe2Sjtc 			pt->list = dpt;
8458b35abe2Sjtc 		}
8468b35abe2Sjtc 	}
8478b35abe2Sjtc 
8488b35abe2Sjtc 	/*
8498b35abe2Sjtc 	 * look for a device number not being used. We must watch for wrap
8508b35abe2Sjtc 	 * around on lastdev (so we do not get stuck looking forever!)
8518b35abe2Sjtc 	 */
8528b35abe2Sjtc 	while (++lastdev > 0) {
8538b35abe2Sjtc 		if (chk_dev(lastdev, 0) != NULL)
8548b35abe2Sjtc 			continue;
8558b35abe2Sjtc 		/*
8568b35abe2Sjtc 		 * found an unused value. If we have reached truncation point
8578b35abe2Sjtc 		 * for this format we are hosed, so we give up. Otherwise we
8588b35abe2Sjtc 		 * mark it as being used.
8598b35abe2Sjtc 		 */
8608b35abe2Sjtc 		if (((lastdev & ((dev_t)dev_mask)) != lastdev) ||
8618b35abe2Sjtc 		    (chk_dev(lastdev, 1) == NULL))
8628b35abe2Sjtc 			goto bad;
8638b35abe2Sjtc 		break;
8648b35abe2Sjtc 	}
8658b35abe2Sjtc 
8668b35abe2Sjtc 	if ((lastdev <= 0) || ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL))
8678b35abe2Sjtc 		goto bad;
8688b35abe2Sjtc 
8698b35abe2Sjtc 	/*
8708b35abe2Sjtc 	 * got a new device number, store it under this truncation pattern.
8718b35abe2Sjtc 	 * change the device number this file is being stored with.
8728b35abe2Sjtc 	 */
8738b35abe2Sjtc 	dpt->trunc_bits = trunc_bits;
8748b35abe2Sjtc 	dpt->dev = lastdev;
8758b35abe2Sjtc 	dpt->fow = pt->list;
8768b35abe2Sjtc 	pt->list = dpt;
8778b35abe2Sjtc 	arcn->sb.st_dev = lastdev;
8788b35abe2Sjtc 	arcn->sb.st_ino = nino;
879cdec4ac1Sdsl 	return 0;
8808b35abe2Sjtc 
8818b35abe2Sjtc     bad:
882f3cd6022Schristos 	tty_warn(1,
883f3cd6022Schristos 	    "Unable to fix truncated inode/device field when storing %s",
8848b35abe2Sjtc 	    arcn->name);
885f3cd6022Schristos 	tty_warn(0, "Archive may create improper hard links when extracted");
886cdec4ac1Sdsl 	return 0;
8878b35abe2Sjtc }
8888b35abe2Sjtc 
8898b35abe2Sjtc /*
8908b35abe2Sjtc  * directory access/mod time reset table routines (for directories READ by pax)
8918b35abe2Sjtc  *
8928b35abe2Sjtc  * The pax -t flag requires that access times of archive files to be the same
8933ac7ce18Swiz  * as before being read by pax. For regular files, access time is restored after
8948b35abe2Sjtc  * the file has been copied. This database provides the same functionality for
8958b35abe2Sjtc  * directories read during file tree traversal. Restoring directory access time
8968b35abe2Sjtc  * is more complex than files since directories may be read several times until
8978b35abe2Sjtc  * all the descendants in their subtree are visited by fts. Directory access
8988b35abe2Sjtc  * and modification times are stored during the fts pre-order visit (done
8998b35abe2Sjtc  * before any descendants in the subtree is visited) and restored after the
9008b35abe2Sjtc  * fts post-order visit (after all the descendants have been visited). In the
9018b35abe2Sjtc  * case of premature exit from a subtree (like from the effects of -n), any
9028b35abe2Sjtc  * directory entries left in this database are reset during final cleanup
9038b35abe2Sjtc  * operations of pax. Entries are hashed by inode number for fast lookup.
9048b35abe2Sjtc  */
9058b35abe2Sjtc 
9068b35abe2Sjtc /*
9078b35abe2Sjtc  * atdir_start()
9088b35abe2Sjtc  *	create the directory access time database for directories READ by pax.
9098b35abe2Sjtc  * Return:
9108b35abe2Sjtc  *	0 is created ok, -1 otherwise.
9118b35abe2Sjtc  */
9128b35abe2Sjtc 
9138b35abe2Sjtc int
atdir_start(void)9148b35abe2Sjtc atdir_start(void)
9158b35abe2Sjtc {
9168b35abe2Sjtc 	if (atab != NULL)
917cdec4ac1Sdsl 		return 0;
9188b35abe2Sjtc 	if ((atab = (ATDIR **)calloc(A_TAB_SZ, sizeof(ATDIR *))) == NULL) {
919f3cd6022Schristos 		tty_warn(1,
920f3cd6022Schristos 		    "Cannot allocate space for directory access time table");
921cdec4ac1Sdsl 		return -1;
9228b35abe2Sjtc 	}
923cdec4ac1Sdsl 	return 0;
9248b35abe2Sjtc }
9258b35abe2Sjtc 
9268b35abe2Sjtc 
9278b35abe2Sjtc /*
9288b35abe2Sjtc  * atdir_end()
9298b35abe2Sjtc  *	walk through the directory access time table and reset the access time
9308b35abe2Sjtc  *	of any directory who still has an entry left in the database. These
9318b35abe2Sjtc  *	entries are for directories READ by pax
9328b35abe2Sjtc  */
9338b35abe2Sjtc 
9348b35abe2Sjtc void
atdir_end(void)9358b35abe2Sjtc atdir_end(void)
9368b35abe2Sjtc {
93748250187Stls 	ATDIR *pt;
93848250187Stls 	int i;
9398b35abe2Sjtc 
9408b35abe2Sjtc 	if (atab == NULL)
9418b35abe2Sjtc 		return;
9428b35abe2Sjtc 	/*
9438b35abe2Sjtc 	 * for each non-empty hash table entry reset all the directories
9448b35abe2Sjtc 	 * chained there.
9458b35abe2Sjtc 	 */
9468b35abe2Sjtc 	for (i = 0; i < A_TAB_SZ; ++i) {
9478b35abe2Sjtc 		if ((pt = atab[i]) == NULL)
9488b35abe2Sjtc 			continue;
9498b35abe2Sjtc 		/*
9508b35abe2Sjtc 		 * remember to force the times, set_ftime() looks at pmtime
9518b35abe2Sjtc 		 * and patime, which only applies to things CREATED by pax,
9528b35abe2Sjtc 		 * not read by pax. Read time reset is controlled by -t.
9538b35abe2Sjtc 		 */
9548b35abe2Sjtc 		for (; pt != NULL; pt = pt->fow)
955cfdef6ecStls 			set_ftime(pt->name, pt->mtime, pt->atime, 1, 0);
9568b35abe2Sjtc 	}
9578b35abe2Sjtc }
9588b35abe2Sjtc 
9598b35abe2Sjtc /*
9608b35abe2Sjtc  * add_atdir()
9618b35abe2Sjtc  *	add a directory to the directory access time table. Table is hashed
9628b35abe2Sjtc  *	and chained by inode number. This is for directories READ by pax
9638b35abe2Sjtc  */
9648b35abe2Sjtc 
9658b35abe2Sjtc void
add_atdir(char * fname,dev_t dev,ino_t ino,time_t mtime,time_t atime)9668b35abe2Sjtc add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime)
9678b35abe2Sjtc {
96848250187Stls 	ATDIR *pt;
96948250187Stls 	u_int indx;
9708b35abe2Sjtc 
9718b35abe2Sjtc 	if (atab == NULL)
9728b35abe2Sjtc 		return;
9738b35abe2Sjtc 
9748b35abe2Sjtc 	/*
9758b35abe2Sjtc 	 * make sure this directory is not already in the table, if so just
9768b35abe2Sjtc 	 * return (the older entry always has the correct time). The only
9778b35abe2Sjtc 	 * way this will happen is when the same subtree can be traversed by
9788b35abe2Sjtc 	 * different args to pax and the -n option is aborting fts out of a
9793ac7ce18Swiz 	 * subtree before all the post-order visits have been made.
9808b35abe2Sjtc 	 */
9818b35abe2Sjtc 	indx = ((unsigned)ino) % A_TAB_SZ;
9828b35abe2Sjtc 	if ((pt = atab[indx]) != NULL) {
9838b35abe2Sjtc 		while (pt != NULL) {
9848b35abe2Sjtc 			if ((pt->ino == ino) && (pt->dev == dev))
9858b35abe2Sjtc 				break;
9868b35abe2Sjtc 			pt = pt->fow;
9878b35abe2Sjtc 		}
9888b35abe2Sjtc 
9898b35abe2Sjtc 		/*
9908b35abe2Sjtc 		 * oops, already there. Leave it alone.
9918b35abe2Sjtc 		 */
9928b35abe2Sjtc 		if (pt != NULL)
9938b35abe2Sjtc 			return;
9948b35abe2Sjtc 	}
9958b35abe2Sjtc 
9968b35abe2Sjtc 	/*
9978b35abe2Sjtc 	 * add it to the front of the hash chain
9988b35abe2Sjtc 	 */
9998b35abe2Sjtc 	if ((pt = (ATDIR *)malloc(sizeof(ATDIR))) != NULL) {
10008b35abe2Sjtc 		if ((pt->name = strdup(fname)) != NULL) {
10018b35abe2Sjtc 			pt->dev = dev;
10028b35abe2Sjtc 			pt->ino = ino;
10038b35abe2Sjtc 			pt->mtime = mtime;
10048b35abe2Sjtc 			pt->atime = atime;
10058b35abe2Sjtc 			pt->fow = atab[indx];
10068b35abe2Sjtc 			atab[indx] = pt;
10078b35abe2Sjtc 			return;
10088b35abe2Sjtc 		}
10098b35abe2Sjtc 		(void)free((char *)pt);
10108b35abe2Sjtc 	}
10118b35abe2Sjtc 
1012f3cd6022Schristos 	tty_warn(1, "Directory access time reset table ran out of memory");
10138b35abe2Sjtc 	return;
10148b35abe2Sjtc }
10158b35abe2Sjtc 
10168b35abe2Sjtc /*
10178b35abe2Sjtc  * get_atdir()
10188b35abe2Sjtc  *	look up a directory by inode and device number to obtain the access
10198b35abe2Sjtc  *	and modification time you want to set to. If found, the modification
10208b35abe2Sjtc  *	and access time parameters are set and the entry is removed from the
10218b35abe2Sjtc  *	table (as it is no longer needed). These are for directories READ by
10228b35abe2Sjtc  *	pax
10238b35abe2Sjtc  * Return:
10248b35abe2Sjtc  *	0 if found, -1 if not found.
10258b35abe2Sjtc  */
10268b35abe2Sjtc 
10278b35abe2Sjtc int
get_atdir(dev_t dev,ino_t ino,time_t * mtime,time_t * atime)10288b35abe2Sjtc get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime)
10298b35abe2Sjtc {
103048250187Stls 	ATDIR *pt;
103148250187Stls 	ATDIR **ppt;
103248250187Stls 	u_int indx;
10338b35abe2Sjtc 
10348b35abe2Sjtc 	if (atab == NULL)
1035cdec4ac1Sdsl 		return -1;
10368b35abe2Sjtc 	/*
10378b35abe2Sjtc 	 * hash by inode and search the chain for an inode and device match
10388b35abe2Sjtc 	 */
10398b35abe2Sjtc 	indx = ((unsigned)ino) % A_TAB_SZ;
10408b35abe2Sjtc 	if ((pt = atab[indx]) == NULL)
1041cdec4ac1Sdsl 		return -1;
10428b35abe2Sjtc 
10438b35abe2Sjtc 	ppt = &(atab[indx]);
10448b35abe2Sjtc 	while (pt != NULL) {
10458b35abe2Sjtc 		if ((pt->ino == ino) && (pt->dev == dev))
10468b35abe2Sjtc 			break;
10478b35abe2Sjtc 		/*
10488b35abe2Sjtc 		 * no match, go to next one
10498b35abe2Sjtc 		 */
10508b35abe2Sjtc 		ppt = &(pt->fow);
10518b35abe2Sjtc 		pt = pt->fow;
10528b35abe2Sjtc 	}
10538b35abe2Sjtc 
10548b35abe2Sjtc 	/*
10558b35abe2Sjtc 	 * return if we did not find it.
10568b35abe2Sjtc 	 */
10578b35abe2Sjtc 	if (pt == NULL)
1058cdec4ac1Sdsl 		return -1;
10598b35abe2Sjtc 
10608b35abe2Sjtc 	/*
10618b35abe2Sjtc 	 * found it. return the times and remove the entry from the table.
10628b35abe2Sjtc 	 */
10638b35abe2Sjtc 	*ppt = pt->fow;
10648b35abe2Sjtc 	*mtime = pt->mtime;
10658b35abe2Sjtc 	*atime = pt->atime;
10668b35abe2Sjtc 	(void)free((char *)pt->name);
10678b35abe2Sjtc 	(void)free((char *)pt);
1068cdec4ac1Sdsl 	return 0;
10698b35abe2Sjtc }
10708b35abe2Sjtc 
10718b35abe2Sjtc /*
10728b35abe2Sjtc  * directory access mode and time storage routines (for directories CREATED
10738b35abe2Sjtc  * by pax).
10748b35abe2Sjtc  *
10758b35abe2Sjtc  * Pax requires that extracted directories, by default, have their access/mod
10768b35abe2Sjtc  * times and permissions set to the values specified in the archive. During the
10778b35abe2Sjtc  * actions of extracting (and creating the destination subtree during -rw copy)
10788b35abe2Sjtc  * directories extracted may be modified after being created. Even worse is
10798b35abe2Sjtc  * that these directories may have been created with file permissions which
10808b35abe2Sjtc  * prohibits any descendants of these directories from being extracted. When
10818b35abe2Sjtc  * directories are created by pax, access rights may be added to permit the
10828b35abe2Sjtc  * creation of files in their subtree. Every time pax creates a directory, the
10838b35abe2Sjtc  * times and file permissions specified by the archive are stored. After all
10848b35abe2Sjtc  * files have been extracted (or copied), these directories have their times
10858b35abe2Sjtc  * and file modes reset to the stored values. The directory info is restored in
10868b35abe2Sjtc  * reverse order as entries were added to the data file from root to leaf. To
10878b35abe2Sjtc  * restore atime properly, we must go backwards. The data file consists of
10888b35abe2Sjtc  * records with two parts, the file name followed by a DIRDATA trailer. The
10898b35abe2Sjtc  * fixed sized trailer contains the size of the name plus the off_t location in
10908b35abe2Sjtc  * the file. To restore we work backwards through the file reading the trailer
10918b35abe2Sjtc  * then the file name.
10928b35abe2Sjtc  */
10938b35abe2Sjtc 
10940317a206Sthorpej #ifndef DIRS_USE_FILE
10950317a206Sthorpej static DIRDATA *dirdata_head;
10960317a206Sthorpej #endif
10970317a206Sthorpej 
10988b35abe2Sjtc /*
10998b35abe2Sjtc  * dir_start()
11008b35abe2Sjtc  *	set up the directory time and file mode storage for directories CREATED
11018b35abe2Sjtc  *	by pax.
11028b35abe2Sjtc  * Return:
11038b35abe2Sjtc  *	0 if ok, -1 otherwise
11048b35abe2Sjtc  */
11058b35abe2Sjtc 
11068b35abe2Sjtc int
dir_start(void)11078b35abe2Sjtc dir_start(void)
11088b35abe2Sjtc {
11090317a206Sthorpej #ifdef DIRS_USE_FILE
11108b35abe2Sjtc 	if (dirfd != -1)
1111cdec4ac1Sdsl 		return 0;
11128b35abe2Sjtc 
11138b35abe2Sjtc 	/*
11148b35abe2Sjtc 	 * unlink the file so it goes away at termination by itself
11158b35abe2Sjtc 	 */
11160c612021Schristos 	memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE));
11170c612021Schristos 	if ((dirfd = mkstemp(tempfile)) >= 0) {
11180c612021Schristos 		(void)unlink(tempfile);
1119cdec4ac1Sdsl 		return 0;
11208b35abe2Sjtc 	}
1121f3cd6022Schristos 	tty_warn(1, "Unable to create temporary file for directory times: %s",
11220c612021Schristos 	    tempfile);
1123cdec4ac1Sdsl 	return -1;
11240317a206Sthorpej #else
11250317a206Sthorpej 	return (0);
11260317a206Sthorpej #endif /* DIRS_USE_FILE */
11278b35abe2Sjtc }
11288b35abe2Sjtc 
11298b35abe2Sjtc /*
11308b35abe2Sjtc  * add_dir()
11318b35abe2Sjtc  *	add the mode and times for a newly CREATED directory
11328b35abe2Sjtc  *	name is name of the directory, psb the stat buffer with the data in it,
11338b35abe2Sjtc  *	frc_mode is a flag that says whether to force the setting of the mode
11348b35abe2Sjtc  *	(ignoring the user set values for preserving file mode). Frc_mode is
11358b35abe2Sjtc  *	for the case where we created a file and found that the resulting
11361035faffSwiz  *	directory was not writable and the user asked for file modes to NOT
11378b35abe2Sjtc  *	be preserved. (we have to preserve what was created by default, so we
11388b35abe2Sjtc  *	have to force the setting at the end. this is stated explicitly in the
11398b35abe2Sjtc  *	pax spec)
11408b35abe2Sjtc  */
11418b35abe2Sjtc 
11428b35abe2Sjtc void
add_dir(char * name,int nlen,struct stat * psb,int frc_mode)11438b35abe2Sjtc add_dir(char *name, int nlen, struct stat *psb, int frc_mode)
11448b35abe2Sjtc {
11450317a206Sthorpej #ifdef DIRS_USE_FILE
11468b35abe2Sjtc 	DIRDATA dblk;
1147c5d25686Schristos #else
1148c5d25686Schristos 	DIRDATA *dblk;
1149c5d25686Schristos #endif
1150c5d25686Schristos 	char realname[MAXPATHLEN], *rp;
11518b35abe2Sjtc 
1152c5d25686Schristos 	if (havechd && *name != '/') {
1153c5d25686Schristos 		if ((rp = realpath(name, realname)) == NULL) {
1154c5d25686Schristos 			tty_warn(1, "Cannot canonicalize %s", name);
1155c5d25686Schristos 			return;
1156c5d25686Schristos 		}
1157c5d25686Schristos 		name = rp;
1158*3dd8ce9fSchristos #ifdef DIRS_USE_FILE
1159c5d25686Schristos 		nlen = strlen(name);
1160*3dd8ce9fSchristos #endif
1161c5d25686Schristos 	}
1162c5d25686Schristos 
1163c5d25686Schristos #ifdef DIRS_USE_FILE
11648b35abe2Sjtc 	if (dirfd < 0)
11658b35abe2Sjtc 		return;
11668b35abe2Sjtc 
11678b35abe2Sjtc 	/*
11688b35abe2Sjtc 	 * get current position (where file name will start) so we can store it
11698b35abe2Sjtc 	 * in the trailer
11708b35abe2Sjtc 	 */
11718b35abe2Sjtc 	if ((dblk.npos = lseek(dirfd, 0L, SEEK_CUR)) < 0) {
1172f3cd6022Schristos 		tty_warn(1,
1173f3cd6022Schristos 		    "Unable to store mode and times for directory: %s",name);
11748b35abe2Sjtc 		return;
11758b35abe2Sjtc 	}
11768b35abe2Sjtc 
11778b35abe2Sjtc 	/*
11788b35abe2Sjtc 	 * write the file name followed by the trailer
11798b35abe2Sjtc 	 */
11808b35abe2Sjtc 	dblk.nlen = nlen + 1;
11818b35abe2Sjtc 	dblk.mode = psb->st_mode & 0xffff;
11828b35abe2Sjtc 	dblk.mtime = psb->st_mtime;
11838b35abe2Sjtc 	dblk.atime = psb->st_atime;
1184a328e341Stv #if HAVE_STRUCT_STAT_ST_FLAGS
1185b60cafe2Smrg 	dblk.fflags = psb->st_flags;
1186a328e341Stv #else
1187a328e341Stv 	dblk.fflags = 0;
1188a328e341Stv #endif
11898b35abe2Sjtc 	dblk.frc_mode = frc_mode;
1190ba0ae447Sitohy 	if ((xwrite(dirfd, name, dblk.nlen) == dblk.nlen) &&
1191ba0ae447Sitohy 	    (xwrite(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) {
11928b35abe2Sjtc 		++dircnt;
11938b35abe2Sjtc 		return;
11948b35abe2Sjtc 	}
11958b35abe2Sjtc 
1196f3cd6022Schristos 	tty_warn(1,
1197f3cd6022Schristos 	    "Unable to store mode and times for created directory: %s",name);
11988b35abe2Sjtc 	return;
11990317a206Sthorpej #else
12000317a206Sthorpej 
12010317a206Sthorpej 	if ((dblk = malloc(sizeof(*dblk))) == NULL ||
12020317a206Sthorpej 	    (dblk->name = strdup(name)) == NULL) {
12030317a206Sthorpej 		tty_warn(1,
12040317a206Sthorpej 		    "Unable to store mode and times for directory: %s",name);
12050317a206Sthorpej 		if (dblk != NULL)
12060317a206Sthorpej 			free(dblk);
12070317a206Sthorpej 		return;
12080317a206Sthorpej 	}
12090317a206Sthorpej 
12100317a206Sthorpej 	dblk->mode = psb->st_mode & 0xffff;
12110317a206Sthorpej 	dblk->mtime = psb->st_mtime;
12120317a206Sthorpej 	dblk->atime = psb->st_atime;
1213a328e341Stv #if HAVE_STRUCT_STAT_ST_FLAGS
12140317a206Sthorpej 	dblk->fflags = psb->st_flags;
1215a328e341Stv #else
1216a328e341Stv 	dblk->fflags = 0;
1217a328e341Stv #endif
12180317a206Sthorpej 	dblk->frc_mode = frc_mode;
12190317a206Sthorpej 
12200317a206Sthorpej 	dblk->next = dirdata_head;
12210317a206Sthorpej 	dirdata_head = dblk;
12220317a206Sthorpej 	return;
12230317a206Sthorpej #endif /* DIRS_USE_FILE */
12248b35abe2Sjtc }
12258b35abe2Sjtc 
12268b35abe2Sjtc /*
12278b35abe2Sjtc  * proc_dir()
12288b35abe2Sjtc  *	process all file modes and times stored for directories CREATED
12298b35abe2Sjtc  *	by pax
12308b35abe2Sjtc  */
12318b35abe2Sjtc 
12328b35abe2Sjtc void
proc_dir(void)12338b35abe2Sjtc proc_dir(void)
12348b35abe2Sjtc {
12350317a206Sthorpej #ifdef DIRS_USE_FILE
12368b35abe2Sjtc 	char name[PAXPATHLEN+1];
12378b35abe2Sjtc 	DIRDATA dblk;
12388b35abe2Sjtc 	u_long cnt;
12398b35abe2Sjtc 
12408b35abe2Sjtc 	if (dirfd < 0)
12418b35abe2Sjtc 		return;
12428b35abe2Sjtc 	/*
12438b35abe2Sjtc 	 * read backwards through the file and process each directory
12448b35abe2Sjtc 	 */
12458b35abe2Sjtc 	for (cnt = 0; cnt < dircnt; ++cnt) {
12468b35abe2Sjtc 		/*
12478b35abe2Sjtc 		 * read the trailer, then the file name, if this fails
12488b35abe2Sjtc 		 * just give up.
12498b35abe2Sjtc 		 */
12508b35abe2Sjtc 		if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0)
12518b35abe2Sjtc 			break;
1252ba0ae447Sitohy 		if (xread(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk))
12538b35abe2Sjtc 			break;
12548b35abe2Sjtc 		if (lseek(dirfd, dblk.npos, SEEK_SET) < 0)
12558b35abe2Sjtc 			break;
1256ba0ae447Sitohy 		if (xread(dirfd, name, dblk.nlen) != dblk.nlen)
12578b35abe2Sjtc 			break;
12588b35abe2Sjtc 		if (lseek(dirfd, dblk.npos, SEEK_SET) < 0)
12598b35abe2Sjtc 			break;
12608b35abe2Sjtc 
12618b35abe2Sjtc 		/*
12628b35abe2Sjtc 		 * frc_mode set, make sure we set the file modes even if
12638b35abe2Sjtc 		 * the user didn't ask for it (see file_subs.c for more info)
12648b35abe2Sjtc 		 */
12658b35abe2Sjtc 		if (pmode || dblk.frc_mode)
12668b35abe2Sjtc 			set_pmode(name, dblk.mode);
12678b35abe2Sjtc 		if (patime || pmtime)
1268cfdef6ecStls 			set_ftime(name, dblk.mtime, dblk.atime, 0, 0);
1269b60cafe2Smrg 		if (pfflags)
1270b60cafe2Smrg 			set_chflags(name, dblk.fflags);
12718b35abe2Sjtc 	}
12728b35abe2Sjtc 
12738b35abe2Sjtc 	(void)close(dirfd);
12748b35abe2Sjtc 	dirfd = -1;
12758b35abe2Sjtc 	if (cnt != dircnt)
1276f3cd6022Schristos 		tty_warn(1,
1277f3cd6022Schristos 		    "Unable to set mode and times for created directories");
12788b35abe2Sjtc 	return;
12790317a206Sthorpej #else
12800317a206Sthorpej 	DIRDATA *dblk;
12810317a206Sthorpej 
12820317a206Sthorpej 	for (dblk = dirdata_head; dblk != NULL; dblk = dirdata_head) {
12830317a206Sthorpej 		dirdata_head = dblk->next;
12840317a206Sthorpej 
12850317a206Sthorpej 		/*
12860317a206Sthorpej 		 * frc_mode set, make sure we set the file modes even if
12870317a206Sthorpej 		 * the user didn't ask for it (see file_subs.c for more info)
12880317a206Sthorpej 		 */
12890317a206Sthorpej 		if (pmode || dblk->frc_mode)
12900317a206Sthorpej 			set_pmode(dblk->name, dblk->mode);
12910317a206Sthorpej 		if (patime || pmtime)
1292cfdef6ecStls 			set_ftime(dblk->name, dblk->mtime, dblk->atime, 0, 0);
12930317a206Sthorpej 		if (pfflags)
12940317a206Sthorpej 			set_chflags(dblk->name, dblk->fflags);
12950317a206Sthorpej 
12960317a206Sthorpej 		free(dblk->name);
12970317a206Sthorpej 		free(dblk);
12980317a206Sthorpej 	}
12990317a206Sthorpej #endif /* DIRS_USE_FILE */
13008b35abe2Sjtc }
13018b35abe2Sjtc 
13028b35abe2Sjtc /*
13038b35abe2Sjtc  * database independent routines
13048b35abe2Sjtc  */
13058b35abe2Sjtc 
13068b35abe2Sjtc /*
13078b35abe2Sjtc  * st_hash()
13088b35abe2Sjtc  *	hashes filenames to a u_int for hashing into a table. Looks at the tail
13098b35abe2Sjtc  *	end of file, as this provides far better distribution than any other
13108b35abe2Sjtc  *	part of the name. For performance reasons we only care about the last
13118b35abe2Sjtc  *	MAXKEYLEN chars (should be at LEAST large enough to pick off the file
13128b35abe2Sjtc  *	name). Was tested on 500,000 name file tree traversal from the root
13138b35abe2Sjtc  *	and gave almost a perfectly uniform distribution of keys when used with
13148b35abe2Sjtc  *	prime sized tables (MAXKEYLEN was 128 in test). Hashes (sizeof int)
13158b35abe2Sjtc  *	chars at a time and pads with 0 for last addition.
13168b35abe2Sjtc  * Return:
13178b35abe2Sjtc  *	the hash value of the string MOD (%) the table size.
13188b35abe2Sjtc  */
13198b35abe2Sjtc 
13208b35abe2Sjtc u_int
st_hash(char * name,int len,int tabsz)13218b35abe2Sjtc st_hash(char *name, int len, int tabsz)
13228b35abe2Sjtc {
132348250187Stls 	char *pt;
132448250187Stls 	char *dest;
132548250187Stls 	char *end;
132648250187Stls 	int i;
132748250187Stls 	u_int key = 0;
132848250187Stls 	int steps;
132948250187Stls 	int res;
13308b35abe2Sjtc 	u_int val;
13318b35abe2Sjtc 
13328b35abe2Sjtc 	/*
13338b35abe2Sjtc 	 * only look at the tail up to MAXKEYLEN, we do not need to waste
13348b35abe2Sjtc 	 * time here (remember these are pathnames, the tail is what will
13358b35abe2Sjtc 	 * spread out the keys)
13368b35abe2Sjtc 	 */
13378b35abe2Sjtc 	if (len > MAXKEYLEN) {
13388b35abe2Sjtc 		pt = &(name[len - MAXKEYLEN]);
13398b35abe2Sjtc 		len = MAXKEYLEN;
13408b35abe2Sjtc 	} else
13418b35abe2Sjtc 		pt = name;
13428b35abe2Sjtc 
13438b35abe2Sjtc 	/*
13448b35abe2Sjtc 	 * calculate the number of u_int size steps in the string and if
13458b35abe2Sjtc 	 * there is a runt to deal with
13468b35abe2Sjtc 	 */
13478b35abe2Sjtc 	steps = len/sizeof(u_int);
13488b35abe2Sjtc 	res = len % sizeof(u_int);
13498b35abe2Sjtc 
13508b35abe2Sjtc 	/*
13518b35abe2Sjtc 	 * add up the value of the string in unsigned integer sized pieces
13528b35abe2Sjtc 	 * too bad we cannot have unsigned int aligned strings, then we
13538b35abe2Sjtc 	 * could avoid the expensive copy.
13548b35abe2Sjtc 	 */
13558b35abe2Sjtc 	for (i = 0; i < steps; ++i) {
13568b35abe2Sjtc 		end = pt + sizeof(u_int);
13578b35abe2Sjtc 		dest = (char *)&val;
13588b35abe2Sjtc 		while (pt < end)
13598b35abe2Sjtc 			*dest++ = *pt++;
13608b35abe2Sjtc 		key += val;
13618b35abe2Sjtc 	}
13628b35abe2Sjtc 
13638b35abe2Sjtc 	/*
13648b35abe2Sjtc 	 * add in the runt padded with zero to the right
13658b35abe2Sjtc 	 */
13668b35abe2Sjtc 	if (res) {
13678b35abe2Sjtc 		val = 0;
13688b35abe2Sjtc 		end = pt + res;
13698b35abe2Sjtc 		dest = (char *)&val;
13708b35abe2Sjtc 		while (pt < end)
13718b35abe2Sjtc 			*dest++ = *pt++;
13728b35abe2Sjtc 		key += val;
13738b35abe2Sjtc 	}
13748b35abe2Sjtc 
13758b35abe2Sjtc 	/*
13768b35abe2Sjtc 	 * return the result mod the table size
13778b35abe2Sjtc 	 */
1378cdec4ac1Sdsl 	return key % tabsz;
13798b35abe2Sjtc }
1380