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