1*84d9c625SLionel Sambuc /* $NetBSD: tables.c,v 1.31 2013/10/18 19:53:34 christos Exp $ */
285fee539SLionel Sambuc
385fee539SLionel Sambuc /*-
485fee539SLionel Sambuc * Copyright (c) 1992 Keith Muller.
585fee539SLionel Sambuc * Copyright (c) 1992, 1993
685fee539SLionel Sambuc * The Regents of the University of California. All rights reserved.
785fee539SLionel Sambuc *
885fee539SLionel Sambuc * This code is derived from software contributed to Berkeley by
985fee539SLionel Sambuc * Keith Muller of the University of California, San Diego.
1085fee539SLionel Sambuc *
1185fee539SLionel Sambuc * Redistribution and use in source and binary forms, with or without
1285fee539SLionel Sambuc * modification, are permitted provided that the following conditions
1385fee539SLionel Sambuc * are met:
1485fee539SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
1585fee539SLionel Sambuc * notice, this list of conditions and the following disclaimer.
1685fee539SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
1785fee539SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
1885fee539SLionel Sambuc * documentation and/or other materials provided with the distribution.
1985fee539SLionel Sambuc * 3. Neither the name of the University nor the names of its contributors
2085fee539SLionel Sambuc * may be used to endorse or promote products derived from this software
2185fee539SLionel Sambuc * without specific prior written permission.
2285fee539SLionel Sambuc *
2385fee539SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2485fee539SLionel Sambuc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2585fee539SLionel Sambuc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2685fee539SLionel Sambuc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2785fee539SLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2885fee539SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2985fee539SLionel Sambuc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3085fee539SLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3185fee539SLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3285fee539SLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3385fee539SLionel Sambuc * SUCH DAMAGE.
3485fee539SLionel Sambuc */
3585fee539SLionel Sambuc
3685fee539SLionel Sambuc #if HAVE_NBTOOL_CONFIG_H
3785fee539SLionel Sambuc #include "nbtool_config.h"
3885fee539SLionel Sambuc #endif
3985fee539SLionel Sambuc
4085fee539SLionel Sambuc #include <sys/cdefs.h>
4185fee539SLionel Sambuc #if !defined(lint)
4285fee539SLionel Sambuc #if 0
4385fee539SLionel Sambuc static char sccsid[] = "@(#)tables.c 8.1 (Berkeley) 5/31/93";
4485fee539SLionel Sambuc #else
45*84d9c625SLionel Sambuc __RCSID("$NetBSD: tables.c,v 1.31 2013/10/18 19:53:34 christos Exp $");
4685fee539SLionel Sambuc #endif
4785fee539SLionel Sambuc #endif /* not lint */
4885fee539SLionel Sambuc
4985fee539SLionel Sambuc #include <sys/types.h>
5085fee539SLionel Sambuc #include <sys/time.h>
5185fee539SLionel Sambuc #include <sys/stat.h>
5285fee539SLionel Sambuc #include <sys/param.h>
5385fee539SLionel Sambuc #include <stdio.h>
5485fee539SLionel Sambuc #include <ctype.h>
5585fee539SLionel Sambuc #include <fcntl.h>
5685fee539SLionel Sambuc #include <paths.h>
5785fee539SLionel Sambuc #include <string.h>
5885fee539SLionel Sambuc #include <unistd.h>
5985fee539SLionel Sambuc #include <errno.h>
6085fee539SLionel Sambuc #include <stdlib.h>
6185fee539SLionel Sambuc #include "pax.h"
6285fee539SLionel Sambuc #include "tables.h"
6385fee539SLionel Sambuc #include "extern.h"
6485fee539SLionel Sambuc
6585fee539SLionel Sambuc /*
6685fee539SLionel Sambuc * Routines for controlling the contents of all the different databases pax
6785fee539SLionel Sambuc * keeps. Tables are dynamically created only when they are needed. The
6885fee539SLionel Sambuc * goal was speed and the ability to work with HUGE archives. The databases
6985fee539SLionel Sambuc * were kept simple, but do have complex rules for when the contents change.
7085fee539SLionel Sambuc * As of this writing, the POSIX library functions were more complex than
7185fee539SLionel Sambuc * needed for this application (pax databases have very short lifetimes and
7285fee539SLionel Sambuc * do not survive after pax is finished). Pax is required to handle very
7385fee539SLionel Sambuc * large archives. These database routines carefully combine memory usage and
7485fee539SLionel Sambuc * temporary file storage in ways which will not significantly impact runtime
7585fee539SLionel Sambuc * performance while allowing the largest possible archives to be handled.
7685fee539SLionel Sambuc * Trying to force the fit to the POSIX database routines was not considered
7785fee539SLionel Sambuc * time well spent.
7885fee539SLionel Sambuc */
7985fee539SLionel Sambuc
8085fee539SLionel Sambuc static HRDLNK **ltab = NULL; /* hard link table for detecting hard links */
8185fee539SLionel Sambuc static FTM **ftab = NULL; /* file time table for updating arch */
8285fee539SLionel Sambuc static NAMT **ntab = NULL; /* interactive rename storage table */
8385fee539SLionel Sambuc static DEVT **dtab = NULL; /* device/inode mapping tables */
8485fee539SLionel Sambuc static ATDIR **atab = NULL; /* file tree directory time reset table */
8585fee539SLionel Sambuc #ifdef DIRS_USE_FILE
8685fee539SLionel Sambuc static int dirfd = -1; /* storage for setting created dir time/mode */
8785fee539SLionel Sambuc static u_long dircnt; /* entries in dir time/mode storage */
8885fee539SLionel Sambuc #endif
8985fee539SLionel Sambuc static int ffd = -1; /* tmp file for file time table name storage */
9085fee539SLionel Sambuc
9185fee539SLionel Sambuc static DEVT *chk_dev(dev_t, int);
9285fee539SLionel Sambuc
9385fee539SLionel Sambuc /*
9485fee539SLionel Sambuc * hard link table routines
9585fee539SLionel Sambuc *
9685fee539SLionel Sambuc * The hard link table tries to detect hard links to files using the device and
9785fee539SLionel Sambuc * inode values. We do this when writing an archive, so we can tell the format
9885fee539SLionel Sambuc * write routine that this file is a hard link to another file. The format
9985fee539SLionel Sambuc * write routine then can store this file in whatever way it wants (as a hard
10085fee539SLionel Sambuc * link if the format supports that like tar, or ignore this info like cpio).
10185fee539SLionel Sambuc * (Actually a field in the format driver table tells us if the format wants
10285fee539SLionel Sambuc * hard link info. if not, we do not waste time looking for them). We also use
10385fee539SLionel Sambuc * the same table when reading an archive. In that situation, this table is
10485fee539SLionel Sambuc * used by the format read routine to detect hard links from stored dev and
10585fee539SLionel Sambuc * inode numbers (like cpio). This will allow pax to create a link when one
10685fee539SLionel Sambuc * can be detected by the archive format.
10785fee539SLionel Sambuc */
10885fee539SLionel Sambuc
10985fee539SLionel Sambuc /*
11085fee539SLionel Sambuc * lnk_start
11185fee539SLionel Sambuc * Creates the hard link table.
11285fee539SLionel Sambuc * Return:
11385fee539SLionel Sambuc * 0 if created, -1 if failure
11485fee539SLionel Sambuc */
11585fee539SLionel Sambuc
11685fee539SLionel Sambuc int
lnk_start(void)11785fee539SLionel Sambuc lnk_start(void)
11885fee539SLionel Sambuc {
11985fee539SLionel Sambuc if (ltab != NULL)
12085fee539SLionel Sambuc return 0;
12185fee539SLionel Sambuc if ((ltab = (HRDLNK **)calloc(L_TAB_SZ, sizeof(HRDLNK *))) == NULL) {
12285fee539SLionel Sambuc tty_warn(1, "Cannot allocate memory for hard link table");
12385fee539SLionel Sambuc return -1;
12485fee539SLionel Sambuc }
12585fee539SLionel Sambuc return 0;
12685fee539SLionel Sambuc }
12785fee539SLionel Sambuc
12885fee539SLionel Sambuc /*
12985fee539SLionel Sambuc * chk_lnk()
13085fee539SLionel Sambuc * Looks up entry in hard link hash table. If found, it copies the name
13185fee539SLionel Sambuc * of the file it is linked to (we already saw that file) into ln_name.
13285fee539SLionel Sambuc * lnkcnt is decremented and if goes to 1 the node is deleted from the
13385fee539SLionel Sambuc * database. (We have seen all the links to this file). If not found,
13485fee539SLionel Sambuc * we add the file to the database if it has the potential for having
13585fee539SLionel Sambuc * hard links to other files we may process (it has a link count > 1)
13685fee539SLionel Sambuc * Return:
13785fee539SLionel Sambuc * if found returns 1; if not found returns 0; -1 on error
13885fee539SLionel Sambuc */
13985fee539SLionel Sambuc
14085fee539SLionel Sambuc int
chk_lnk(ARCHD * arcn)14185fee539SLionel Sambuc chk_lnk(ARCHD *arcn)
14285fee539SLionel Sambuc {
14385fee539SLionel Sambuc HRDLNK *pt;
14485fee539SLionel Sambuc HRDLNK **ppt;
14585fee539SLionel Sambuc u_int indx;
14685fee539SLionel Sambuc
14785fee539SLionel Sambuc if (ltab == NULL)
14885fee539SLionel Sambuc return -1;
14985fee539SLionel Sambuc /*
15085fee539SLionel Sambuc * ignore those nodes that cannot have hard links
15185fee539SLionel Sambuc */
15285fee539SLionel Sambuc if ((arcn->type == PAX_DIR) || (arcn->sb.st_nlink <= 1))
15385fee539SLionel Sambuc return 0;
15485fee539SLionel Sambuc
15585fee539SLionel Sambuc /*
15685fee539SLionel Sambuc * hash inode number and look for this file
15785fee539SLionel Sambuc */
15885fee539SLionel Sambuc indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ;
15985fee539SLionel Sambuc if ((pt = ltab[indx]) != NULL) {
16085fee539SLionel Sambuc /*
16185fee539SLionel Sambuc * its hash chain is not empty, walk down looking for it
16285fee539SLionel Sambuc */
16385fee539SLionel Sambuc ppt = &(ltab[indx]);
16485fee539SLionel Sambuc while (pt != NULL) {
16585fee539SLionel Sambuc if ((pt->ino == arcn->sb.st_ino) &&
16685fee539SLionel Sambuc (pt->dev == arcn->sb.st_dev))
16785fee539SLionel Sambuc break;
16885fee539SLionel Sambuc ppt = &(pt->fow);
16985fee539SLionel Sambuc pt = pt->fow;
17085fee539SLionel Sambuc }
17185fee539SLionel Sambuc
17285fee539SLionel Sambuc if (pt != NULL) {
17385fee539SLionel Sambuc /*
17485fee539SLionel Sambuc * found a link. set the node type and copy in the
17585fee539SLionel Sambuc * name of the file it is to link to. we need to
17685fee539SLionel Sambuc * handle hardlinks to regular files differently than
17785fee539SLionel Sambuc * other links.
17885fee539SLionel Sambuc */
17985fee539SLionel Sambuc arcn->ln_nlen = strlcpy(arcn->ln_name, pt->name,
18085fee539SLionel Sambuc sizeof(arcn->ln_name));
18185fee539SLionel Sambuc if (arcn->type == PAX_REG)
18285fee539SLionel Sambuc arcn->type = PAX_HRG;
18385fee539SLionel Sambuc else
18485fee539SLionel Sambuc arcn->type = PAX_HLK;
18585fee539SLionel Sambuc
18685fee539SLionel Sambuc /*
18785fee539SLionel Sambuc * if we have found all the links to this file, remove
18885fee539SLionel Sambuc * it from the database
18985fee539SLionel Sambuc */
19085fee539SLionel Sambuc if (--pt->nlink <= 1) {
19185fee539SLionel Sambuc *ppt = pt->fow;
19285fee539SLionel Sambuc (void)free((char *)pt->name);
19385fee539SLionel Sambuc (void)free((char *)pt);
19485fee539SLionel Sambuc }
19585fee539SLionel Sambuc return 1;
19685fee539SLionel Sambuc }
19785fee539SLionel Sambuc }
19885fee539SLionel Sambuc
19985fee539SLionel Sambuc /*
20085fee539SLionel Sambuc * we never saw this file before. It has links so we add it to the
20185fee539SLionel Sambuc * front of this hash chain
20285fee539SLionel Sambuc */
20385fee539SLionel Sambuc if ((pt = (HRDLNK *)malloc(sizeof(HRDLNK))) != NULL) {
20485fee539SLionel Sambuc if ((pt->name = strdup(arcn->name)) != NULL) {
20585fee539SLionel Sambuc pt->dev = arcn->sb.st_dev;
20685fee539SLionel Sambuc pt->ino = arcn->sb.st_ino;
20785fee539SLionel Sambuc pt->nlink = arcn->sb.st_nlink;
20885fee539SLionel Sambuc pt->fow = ltab[indx];
20985fee539SLionel Sambuc ltab[indx] = pt;
21085fee539SLionel Sambuc return 0;
21185fee539SLionel Sambuc }
21285fee539SLionel Sambuc (void)free((char *)pt);
21385fee539SLionel Sambuc }
21485fee539SLionel Sambuc
21585fee539SLionel Sambuc tty_warn(1, "Hard link table out of memory");
21685fee539SLionel Sambuc return -1;
21785fee539SLionel Sambuc }
21885fee539SLionel Sambuc
21985fee539SLionel Sambuc /*
22085fee539SLionel Sambuc * purg_lnk
22185fee539SLionel Sambuc * remove reference for a file that we may have added to the data base as
22285fee539SLionel Sambuc * a potential source for hard links. We ended up not using the file, so
22385fee539SLionel Sambuc * we do not want to accidentally point another file at it later on.
22485fee539SLionel Sambuc */
22585fee539SLionel Sambuc
22685fee539SLionel Sambuc void
purg_lnk(ARCHD * arcn)22785fee539SLionel Sambuc purg_lnk(ARCHD *arcn)
22885fee539SLionel Sambuc {
22985fee539SLionel Sambuc HRDLNK *pt;
23085fee539SLionel Sambuc HRDLNK **ppt;
23185fee539SLionel Sambuc u_int indx;
23285fee539SLionel Sambuc
23385fee539SLionel Sambuc if (ltab == NULL)
23485fee539SLionel Sambuc return;
23585fee539SLionel Sambuc /*
23685fee539SLionel Sambuc * do not bother to look if it could not be in the database
23785fee539SLionel Sambuc */
23885fee539SLionel Sambuc if ((arcn->sb.st_nlink <= 1) || (arcn->type == PAX_DIR) ||
23985fee539SLionel Sambuc (arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
24085fee539SLionel Sambuc return;
24185fee539SLionel Sambuc
24285fee539SLionel Sambuc /*
24385fee539SLionel Sambuc * find the hash chain for this inode value, if empty return
24485fee539SLionel Sambuc */
24585fee539SLionel Sambuc indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ;
24685fee539SLionel Sambuc if ((pt = ltab[indx]) == NULL)
24785fee539SLionel Sambuc return;
24885fee539SLionel Sambuc
24985fee539SLionel Sambuc /*
25085fee539SLionel Sambuc * walk down the list looking for the inode/dev pair, unlink and
25185fee539SLionel Sambuc * free if found
25285fee539SLionel Sambuc */
25385fee539SLionel Sambuc ppt = &(ltab[indx]);
25485fee539SLionel Sambuc while (pt != NULL) {
25585fee539SLionel Sambuc if ((pt->ino == arcn->sb.st_ino) &&
25685fee539SLionel Sambuc (pt->dev == arcn->sb.st_dev))
25785fee539SLionel Sambuc break;
25885fee539SLionel Sambuc ppt = &(pt->fow);
25985fee539SLionel Sambuc pt = pt->fow;
26085fee539SLionel Sambuc }
26185fee539SLionel Sambuc if (pt == NULL)
26285fee539SLionel Sambuc return;
26385fee539SLionel Sambuc
26485fee539SLionel Sambuc /*
26585fee539SLionel Sambuc * remove and free it
26685fee539SLionel Sambuc */
26785fee539SLionel Sambuc *ppt = pt->fow;
26885fee539SLionel Sambuc (void)free((char *)pt->name);
26985fee539SLionel Sambuc (void)free((char *)pt);
27085fee539SLionel Sambuc }
27185fee539SLionel Sambuc
27285fee539SLionel Sambuc /*
27385fee539SLionel Sambuc * lnk_end()
27485fee539SLionel Sambuc * pull apart a existing link table so we can reuse it. We do this between
27585fee539SLionel Sambuc * read and write phases of append with update. (The format may have
27685fee539SLionel Sambuc * used the link table, and we need to start with a fresh table for the
27785fee539SLionel Sambuc * write phase
27885fee539SLionel Sambuc */
27985fee539SLionel Sambuc
28085fee539SLionel Sambuc void
lnk_end(void)28185fee539SLionel Sambuc lnk_end(void)
28285fee539SLionel Sambuc {
28385fee539SLionel Sambuc int i;
28485fee539SLionel Sambuc HRDLNK *pt;
28585fee539SLionel Sambuc HRDLNK *ppt;
28685fee539SLionel Sambuc
28785fee539SLionel Sambuc if (ltab == NULL)
28885fee539SLionel Sambuc return;
28985fee539SLionel Sambuc
29085fee539SLionel Sambuc for (i = 0; i < L_TAB_SZ; ++i) {
29185fee539SLionel Sambuc if (ltab[i] == NULL)
29285fee539SLionel Sambuc continue;
29385fee539SLionel Sambuc pt = ltab[i];
29485fee539SLionel Sambuc ltab[i] = NULL;
29585fee539SLionel Sambuc
29685fee539SLionel Sambuc /*
29785fee539SLionel Sambuc * free up each entry on this chain
29885fee539SLionel Sambuc */
29985fee539SLionel Sambuc while (pt != NULL) {
30085fee539SLionel Sambuc ppt = pt;
30185fee539SLionel Sambuc pt = ppt->fow;
30285fee539SLionel Sambuc (void)free((char *)ppt->name);
30385fee539SLionel Sambuc (void)free((char *)ppt);
30485fee539SLionel Sambuc }
30585fee539SLionel Sambuc }
30685fee539SLionel Sambuc return;
30785fee539SLionel Sambuc }
30885fee539SLionel Sambuc
30985fee539SLionel Sambuc /*
31085fee539SLionel Sambuc * modification time table routines
31185fee539SLionel Sambuc *
31285fee539SLionel Sambuc * The modification time table keeps track of last modification times for all
31385fee539SLionel Sambuc * files stored in an archive during a write phase when -u is set. We only
31485fee539SLionel Sambuc * add a file to the archive if it is newer than a file with the same name
31585fee539SLionel Sambuc * already stored on the archive (if there is no other file with the same
31685fee539SLionel Sambuc * name on the archive it is added). This applies to writes and appends.
31785fee539SLionel Sambuc * An append with an -u must read the archive and store the modification time
31885fee539SLionel Sambuc * for every file on that archive before starting the write phase. It is clear
31985fee539SLionel Sambuc * that this is one HUGE database. To save memory space, the actual file names
32085fee539SLionel Sambuc * are stored in a scratch file and indexed by an in-memory hash table. The
32185fee539SLionel Sambuc * hash table is indexed by hashing the file path. The nodes in the table store
32285fee539SLionel Sambuc * the length of the filename and the lseek offset within the scratch file
32385fee539SLionel Sambuc * where the actual name is stored. Since there are never any deletions from this
32485fee539SLionel Sambuc * table, fragmentation of the scratch file is never a issue. Lookups seem to
32585fee539SLionel Sambuc * not exhibit any locality at all (files in the database are rarely
32685fee539SLionel Sambuc * looked up more than once...), so caching is just a waste of memory. The
32785fee539SLionel Sambuc * only limitation is the amount of scratch file space available to store the
32885fee539SLionel Sambuc * path names.
32985fee539SLionel Sambuc */
33085fee539SLionel Sambuc
33185fee539SLionel Sambuc /*
33285fee539SLionel Sambuc * ftime_start()
33385fee539SLionel Sambuc * create the file time hash table and open for read/write the scratch
33485fee539SLionel Sambuc * file. (after created it is unlinked, so when we exit we leave
33585fee539SLionel Sambuc * no witnesses).
33685fee539SLionel Sambuc * Return:
33785fee539SLionel Sambuc * 0 if the table and file was created ok, -1 otherwise
33885fee539SLionel Sambuc */
33985fee539SLionel Sambuc
34085fee539SLionel Sambuc int
ftime_start(void)34185fee539SLionel Sambuc ftime_start(void)
34285fee539SLionel Sambuc {
34385fee539SLionel Sambuc if (ftab != NULL)
34485fee539SLionel Sambuc return 0;
34585fee539SLionel Sambuc if ((ftab = (FTM **)calloc(F_TAB_SZ, sizeof(FTM *))) == NULL) {
34685fee539SLionel Sambuc tty_warn(1, "Cannot allocate memory for file time table");
34785fee539SLionel Sambuc return -1;
34885fee539SLionel Sambuc }
34985fee539SLionel Sambuc
35085fee539SLionel Sambuc /*
35185fee539SLionel Sambuc * get random name and create temporary scratch file, unlink name
35285fee539SLionel Sambuc * so it will get removed on exit
35385fee539SLionel Sambuc */
35485fee539SLionel Sambuc memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE));
35585fee539SLionel Sambuc if ((ffd = mkstemp(tempfile)) == -1) {
35685fee539SLionel Sambuc syswarn(1, errno, "Unable to create temporary file: %s",
35785fee539SLionel Sambuc tempfile);
35885fee539SLionel Sambuc return -1;
35985fee539SLionel Sambuc }
36085fee539SLionel Sambuc
36185fee539SLionel Sambuc (void)unlink(tempfile);
36285fee539SLionel Sambuc return 0;
36385fee539SLionel Sambuc }
36485fee539SLionel Sambuc
36585fee539SLionel Sambuc /*
36685fee539SLionel Sambuc * chk_ftime()
36785fee539SLionel Sambuc * looks up entry in file time hash table. If not found, the file is
36885fee539SLionel Sambuc * added to the hash table and the file named stored in the scratch file.
36985fee539SLionel Sambuc * If a file with the same name is found, the file times are compared and
37085fee539SLionel Sambuc * the most recent file time is retained. If the new file was younger (or
37185fee539SLionel Sambuc * was not in the database) the new file is selected for storage.
37285fee539SLionel Sambuc * Return:
37385fee539SLionel Sambuc * 0 if file should be added to the archive, 1 if it should be skipped,
37485fee539SLionel Sambuc * -1 on error
37585fee539SLionel Sambuc */
37685fee539SLionel Sambuc
37785fee539SLionel Sambuc int
chk_ftime(ARCHD * arcn)37885fee539SLionel Sambuc chk_ftime(ARCHD *arcn)
37985fee539SLionel Sambuc {
38085fee539SLionel Sambuc FTM *pt;
38185fee539SLionel Sambuc int namelen;
38285fee539SLionel Sambuc u_int indx;
38385fee539SLionel Sambuc char ckname[PAXPATHLEN+1];
38485fee539SLionel Sambuc
38585fee539SLionel Sambuc /*
38685fee539SLionel Sambuc * no info, go ahead and add to archive
38785fee539SLionel Sambuc */
38885fee539SLionel Sambuc if (ftab == NULL)
38985fee539SLionel Sambuc return 0;
39085fee539SLionel Sambuc
39185fee539SLionel Sambuc /*
39285fee539SLionel Sambuc * hash the pathname and look up in table
39385fee539SLionel Sambuc */
39485fee539SLionel Sambuc namelen = arcn->nlen;
39585fee539SLionel Sambuc indx = st_hash(arcn->name, namelen, F_TAB_SZ);
39685fee539SLionel Sambuc if ((pt = ftab[indx]) != NULL) {
39785fee539SLionel Sambuc /*
39885fee539SLionel Sambuc * the hash chain is not empty, walk down looking for match
39985fee539SLionel Sambuc * only read up the path names if the lengths match, speeds
40085fee539SLionel Sambuc * up the search a lot
40185fee539SLionel Sambuc */
40285fee539SLionel Sambuc while (pt != NULL) {
40385fee539SLionel Sambuc if (pt->namelen == namelen) {
40485fee539SLionel Sambuc /*
40585fee539SLionel Sambuc * potential match, have to read the name
40685fee539SLionel Sambuc * from the scratch file.
40785fee539SLionel Sambuc */
40885fee539SLionel Sambuc if (lseek(ffd,pt->seek,SEEK_SET) != pt->seek) {
40985fee539SLionel Sambuc syswarn(1, errno,
41085fee539SLionel Sambuc "Failed ftime table seek");
41185fee539SLionel Sambuc return -1;
41285fee539SLionel Sambuc }
41385fee539SLionel Sambuc if (xread(ffd, ckname, namelen) != namelen) {
41485fee539SLionel Sambuc syswarn(1, errno,
41585fee539SLionel Sambuc "Failed ftime table read");
41685fee539SLionel Sambuc return -1;
41785fee539SLionel Sambuc }
41885fee539SLionel Sambuc
41985fee539SLionel Sambuc /*
42085fee539SLionel Sambuc * if the names match, we are done
42185fee539SLionel Sambuc */
42285fee539SLionel Sambuc if (!strncmp(ckname, arcn->name, namelen))
42385fee539SLionel Sambuc break;
42485fee539SLionel Sambuc }
42585fee539SLionel Sambuc
42685fee539SLionel Sambuc /*
42785fee539SLionel Sambuc * try the next entry on the chain
42885fee539SLionel Sambuc */
42985fee539SLionel Sambuc pt = pt->fow;
43085fee539SLionel Sambuc }
43185fee539SLionel Sambuc
43285fee539SLionel Sambuc if (pt != NULL) {
43385fee539SLionel Sambuc /*
43485fee539SLionel Sambuc * found the file, compare the times, save the newer
43585fee539SLionel Sambuc */
43685fee539SLionel Sambuc if (arcn->sb.st_mtime > pt->mtime) {
43785fee539SLionel Sambuc /*
43885fee539SLionel Sambuc * file is newer
43985fee539SLionel Sambuc */
44085fee539SLionel Sambuc pt->mtime = arcn->sb.st_mtime;
44185fee539SLionel Sambuc return 0;
44285fee539SLionel Sambuc }
44385fee539SLionel Sambuc /*
44485fee539SLionel Sambuc * file is older
44585fee539SLionel Sambuc */
44685fee539SLionel Sambuc return 1;
44785fee539SLionel Sambuc }
44885fee539SLionel Sambuc }
44985fee539SLionel Sambuc
45085fee539SLionel Sambuc /*
45185fee539SLionel Sambuc * not in table, add it
45285fee539SLionel Sambuc */
45385fee539SLionel Sambuc if ((pt = (FTM *)malloc(sizeof(FTM))) != NULL) {
45485fee539SLionel Sambuc /*
45585fee539SLionel Sambuc * add the name at the end of the scratch file, saving the
45685fee539SLionel Sambuc * offset. add the file to the head of the hash chain
45785fee539SLionel Sambuc */
45885fee539SLionel Sambuc if ((pt->seek = lseek(ffd, (off_t)0, SEEK_END)) >= 0) {
45985fee539SLionel Sambuc if (xwrite(ffd, arcn->name, namelen) == namelen) {
46085fee539SLionel Sambuc pt->mtime = arcn->sb.st_mtime;
46185fee539SLionel Sambuc pt->namelen = namelen;
46285fee539SLionel Sambuc pt->fow = ftab[indx];
46385fee539SLionel Sambuc ftab[indx] = pt;
46485fee539SLionel Sambuc return 0;
46585fee539SLionel Sambuc }
46685fee539SLionel Sambuc syswarn(1, errno, "Failed write to file time table");
46785fee539SLionel Sambuc } else
46885fee539SLionel Sambuc syswarn(1, errno, "Failed seek on file time table");
46985fee539SLionel Sambuc } else
47085fee539SLionel Sambuc tty_warn(1, "File time table ran out of memory");
47185fee539SLionel Sambuc
47285fee539SLionel Sambuc if (pt != NULL)
47385fee539SLionel Sambuc (void)free((char *)pt);
47485fee539SLionel Sambuc return -1;
47585fee539SLionel Sambuc }
47685fee539SLionel Sambuc
47785fee539SLionel Sambuc /*
47885fee539SLionel Sambuc * Interactive rename table routines
47985fee539SLionel Sambuc *
48085fee539SLionel Sambuc * The interactive rename table keeps track of the new names that the user
48185fee539SLionel Sambuc * assigns to files from tty input. Since this map is unique for each file
48285fee539SLionel Sambuc * we must store it in case there is a reference to the file later in archive
48385fee539SLionel Sambuc * (a link). Otherwise we will be unable to find the file we know was
48485fee539SLionel Sambuc * extracted. The remapping of these files is stored in a memory based hash
48585fee539SLionel Sambuc * table (it is assumed since input must come from /dev/tty, it is unlikely to
48685fee539SLionel Sambuc * be a very large table).
48785fee539SLionel Sambuc */
48885fee539SLionel Sambuc
48985fee539SLionel Sambuc /*
49085fee539SLionel Sambuc * name_start()
49185fee539SLionel Sambuc * create the interactive rename table
49285fee539SLionel Sambuc * Return:
49385fee539SLionel Sambuc * 0 if successful, -1 otherwise
49485fee539SLionel Sambuc */
49585fee539SLionel Sambuc
49685fee539SLionel Sambuc int
name_start(void)49785fee539SLionel Sambuc name_start(void)
49885fee539SLionel Sambuc {
49985fee539SLionel Sambuc if (ntab != NULL)
50085fee539SLionel Sambuc return 0;
50185fee539SLionel Sambuc if ((ntab = (NAMT **)calloc(N_TAB_SZ, sizeof(NAMT *))) == NULL) {
50285fee539SLionel Sambuc tty_warn(1,
50385fee539SLionel Sambuc "Cannot allocate memory for interactive rename table");
50485fee539SLionel Sambuc return -1;
50585fee539SLionel Sambuc }
50685fee539SLionel Sambuc return 0;
50785fee539SLionel Sambuc }
50885fee539SLionel Sambuc
50985fee539SLionel Sambuc /*
51085fee539SLionel Sambuc * add_name()
51185fee539SLionel Sambuc * add the new name to old name mapping just created by the user.
51285fee539SLionel Sambuc * If an old name mapping is found (there may be duplicate names on an
51385fee539SLionel Sambuc * archive) only the most recent is kept.
51485fee539SLionel Sambuc * Return:
51585fee539SLionel Sambuc * 0 if added, -1 otherwise
51685fee539SLionel Sambuc */
51785fee539SLionel Sambuc
51885fee539SLionel Sambuc int
add_name(char * oname,int onamelen,char * nname)51985fee539SLionel Sambuc add_name(char *oname, int onamelen, char *nname)
52085fee539SLionel Sambuc {
52185fee539SLionel Sambuc NAMT *pt;
52285fee539SLionel Sambuc u_int indx;
52385fee539SLionel Sambuc
52485fee539SLionel Sambuc if (ntab == NULL) {
52585fee539SLionel Sambuc /*
52685fee539SLionel Sambuc * should never happen
52785fee539SLionel Sambuc */
52885fee539SLionel Sambuc tty_warn(0, "No interactive rename table, links may fail\n");
52985fee539SLionel Sambuc return 0;
53085fee539SLionel Sambuc }
53185fee539SLionel Sambuc
53285fee539SLionel Sambuc /*
53385fee539SLionel Sambuc * look to see if we have already mapped this file, if so we
53485fee539SLionel Sambuc * will update it
53585fee539SLionel Sambuc */
53685fee539SLionel Sambuc indx = st_hash(oname, onamelen, N_TAB_SZ);
53785fee539SLionel Sambuc if ((pt = ntab[indx]) != NULL) {
53885fee539SLionel Sambuc /*
53985fee539SLionel Sambuc * look down the has chain for the file
54085fee539SLionel Sambuc */
54185fee539SLionel Sambuc while ((pt != NULL) && (strcmp(oname, pt->oname) != 0))
54285fee539SLionel Sambuc pt = pt->fow;
54385fee539SLionel Sambuc
54485fee539SLionel Sambuc if (pt != NULL) {
54585fee539SLionel Sambuc /*
54685fee539SLionel Sambuc * found an old mapping, replace it with the new one
54785fee539SLionel Sambuc * the user just input (if it is different)
54885fee539SLionel Sambuc */
54985fee539SLionel Sambuc if (strcmp(nname, pt->nname) == 0)
55085fee539SLionel Sambuc return 0;
55185fee539SLionel Sambuc
55285fee539SLionel Sambuc (void)free((char *)pt->nname);
55385fee539SLionel Sambuc if ((pt->nname = strdup(nname)) == NULL) {
55485fee539SLionel Sambuc tty_warn(1, "Cannot update rename table");
55585fee539SLionel Sambuc return -1;
55685fee539SLionel Sambuc }
55785fee539SLionel Sambuc return 0;
55885fee539SLionel Sambuc }
55985fee539SLionel Sambuc }
56085fee539SLionel Sambuc
56185fee539SLionel Sambuc /*
56285fee539SLionel Sambuc * this is a new mapping, add it to the table
56385fee539SLionel Sambuc */
56485fee539SLionel Sambuc if ((pt = (NAMT *)malloc(sizeof(NAMT))) != NULL) {
56585fee539SLionel Sambuc if ((pt->oname = strdup(oname)) != NULL) {
56685fee539SLionel Sambuc if ((pt->nname = strdup(nname)) != NULL) {
56785fee539SLionel Sambuc pt->fow = ntab[indx];
56885fee539SLionel Sambuc ntab[indx] = pt;
56985fee539SLionel Sambuc return 0;
57085fee539SLionel Sambuc }
57185fee539SLionel Sambuc (void)free((char *)pt->oname);
57285fee539SLionel Sambuc }
57385fee539SLionel Sambuc (void)free((char *)pt);
57485fee539SLionel Sambuc }
57585fee539SLionel Sambuc tty_warn(1, "Interactive rename table out of memory");
57685fee539SLionel Sambuc return -1;
57785fee539SLionel Sambuc }
57885fee539SLionel Sambuc
57985fee539SLionel Sambuc /*
58085fee539SLionel Sambuc * sub_name()
58185fee539SLionel Sambuc * look up a link name to see if it points at a file that has been
58285fee539SLionel Sambuc * remapped by the user. If found, the link is adjusted to contain the
58385fee539SLionel Sambuc * new name (oname is the link to name)
58485fee539SLionel Sambuc */
58585fee539SLionel Sambuc
58685fee539SLionel Sambuc void
sub_name(char * oname,int * onamelen,size_t onamesize)58785fee539SLionel Sambuc sub_name(char *oname, int *onamelen, size_t onamesize)
58885fee539SLionel Sambuc {
58985fee539SLionel Sambuc NAMT *pt;
59085fee539SLionel Sambuc u_int indx;
59185fee539SLionel Sambuc
59285fee539SLionel Sambuc if (ntab == NULL)
59385fee539SLionel Sambuc return;
59485fee539SLionel Sambuc /*
59585fee539SLionel Sambuc * look the name up in the hash table
59685fee539SLionel Sambuc */
59785fee539SLionel Sambuc indx = st_hash(oname, *onamelen, N_TAB_SZ);
59885fee539SLionel Sambuc if ((pt = ntab[indx]) == NULL)
59985fee539SLionel Sambuc return;
60085fee539SLionel Sambuc
60185fee539SLionel Sambuc while (pt != NULL) {
60285fee539SLionel Sambuc /*
60385fee539SLionel Sambuc * walk down the hash chain looking for a match
60485fee539SLionel Sambuc */
60585fee539SLionel Sambuc if (strcmp(oname, pt->oname) == 0) {
60685fee539SLionel Sambuc /*
60785fee539SLionel Sambuc * found it, replace it with the new name
60885fee539SLionel Sambuc * and return (we know that oname has enough space)
60985fee539SLionel Sambuc */
61085fee539SLionel Sambuc *onamelen = strlcpy(oname, pt->nname, onamesize);
61185fee539SLionel Sambuc return;
61285fee539SLionel Sambuc }
61385fee539SLionel Sambuc pt = pt->fow;
61485fee539SLionel Sambuc }
61585fee539SLionel Sambuc
61685fee539SLionel Sambuc /*
61785fee539SLionel Sambuc * no match, just return
61885fee539SLionel Sambuc */
61985fee539SLionel Sambuc return;
62085fee539SLionel Sambuc }
62185fee539SLionel Sambuc
62285fee539SLionel Sambuc /*
62385fee539SLionel Sambuc * device/inode mapping table routines
62485fee539SLionel Sambuc * (used with formats that store device and inodes fields)
62585fee539SLionel Sambuc *
62685fee539SLionel Sambuc * device/inode mapping tables remap the device field in an archive header. The
62785fee539SLionel Sambuc * device/inode fields are used to determine when files are hard links to each
62885fee539SLionel Sambuc * other. However these values have very little meaning outside of that. This
62985fee539SLionel Sambuc * database is used to solve one of two different problems.
63085fee539SLionel Sambuc *
63185fee539SLionel Sambuc * 1) when files are appended to an archive, while the new files may have hard
63285fee539SLionel Sambuc * links to each other, you cannot determine if they have hard links to any
63385fee539SLionel Sambuc * file already stored on the archive from a prior run of pax. We must assume
63485fee539SLionel Sambuc * that these inode/device pairs are unique only within a SINGLE run of pax
63585fee539SLionel Sambuc * (which adds a set of files to an archive). So we have to make sure the
63685fee539SLionel Sambuc * inode/dev pairs we add each time are always unique. We do this by observing
63785fee539SLionel Sambuc * while the inode field is very dense, the use of the dev field is fairly
63885fee539SLionel Sambuc * sparse. Within each run of pax, we remap any device number of a new archive
63985fee539SLionel Sambuc * member that has a device number used in a prior run and already stored in a
64085fee539SLionel Sambuc * file on the archive. During the read phase of the append, we store the
64185fee539SLionel Sambuc * device numbers used and mark them to not be used by any file during the
64285fee539SLionel Sambuc * write phase. If during write we go to use one of those old device numbers,
64385fee539SLionel Sambuc * we remap it to a new value.
64485fee539SLionel Sambuc *
64585fee539SLionel Sambuc * 2) Often the fields in the archive header used to store these values are
64685fee539SLionel Sambuc * too small to store the entire value. The result is an inode or device value
64785fee539SLionel Sambuc * which can be truncated. This really can foul up an archive. With truncation
64885fee539SLionel Sambuc * we end up creating links between files that are really not links (after
64985fee539SLionel Sambuc * truncation the inodes are the same value). We address that by detecting
65085fee539SLionel Sambuc * truncation and forcing a remap of the device field to split truncated
65185fee539SLionel Sambuc * inodes away from each other. Each truncation creates a pattern of bits that
65285fee539SLionel Sambuc * are removed. We use this pattern of truncated bits to partition the inodes
65385fee539SLionel Sambuc * on a single device to many different devices (each one represented by the
65485fee539SLionel Sambuc * truncated bit pattern). All inodes on the same device that have the same
65585fee539SLionel Sambuc * truncation pattern are mapped to the same new device. Two inodes that
65685fee539SLionel Sambuc * truncate to the same value clearly will always have different truncation
65785fee539SLionel Sambuc * bit patterns, so they will be split from away each other. When we spot
65885fee539SLionel Sambuc * device truncation we remap the device number to a non truncated value.
65985fee539SLionel Sambuc * (for more info see table.h for the data structures involved).
66085fee539SLionel Sambuc */
66185fee539SLionel Sambuc
66285fee539SLionel Sambuc /*
66385fee539SLionel Sambuc * dev_start()
66485fee539SLionel Sambuc * create the device mapping table
66585fee539SLionel Sambuc * Return:
66685fee539SLionel Sambuc * 0 if successful, -1 otherwise
66785fee539SLionel Sambuc */
66885fee539SLionel Sambuc
66985fee539SLionel Sambuc int
dev_start(void)67085fee539SLionel Sambuc dev_start(void)
67185fee539SLionel Sambuc {
67285fee539SLionel Sambuc if (dtab != NULL)
67385fee539SLionel Sambuc return 0;
67485fee539SLionel Sambuc if ((dtab = (DEVT **)calloc(D_TAB_SZ, sizeof(DEVT *))) == NULL) {
67585fee539SLionel Sambuc tty_warn(1, "Cannot allocate memory for device mapping table");
67685fee539SLionel Sambuc return -1;
67785fee539SLionel Sambuc }
67885fee539SLionel Sambuc return 0;
67985fee539SLionel Sambuc }
68085fee539SLionel Sambuc
68185fee539SLionel Sambuc /*
68285fee539SLionel Sambuc * add_dev()
68385fee539SLionel Sambuc * add a device number to the table. this will force the device to be
68485fee539SLionel Sambuc * remapped to a new value if it be used during a write phase. This
68585fee539SLionel Sambuc * function is called during the read phase of an append to prohibit the
68685fee539SLionel Sambuc * use of any device number already in the archive.
68785fee539SLionel Sambuc * Return:
68885fee539SLionel Sambuc * 0 if added ok, -1 otherwise
68985fee539SLionel Sambuc */
69085fee539SLionel Sambuc
69185fee539SLionel Sambuc int
add_dev(ARCHD * arcn)69285fee539SLionel Sambuc add_dev(ARCHD *arcn)
69385fee539SLionel Sambuc {
69485fee539SLionel Sambuc if (chk_dev(arcn->sb.st_dev, 1) == NULL)
69585fee539SLionel Sambuc return -1;
69685fee539SLionel Sambuc return 0;
69785fee539SLionel Sambuc }
69885fee539SLionel Sambuc
69985fee539SLionel Sambuc /*
70085fee539SLionel Sambuc * chk_dev()
70185fee539SLionel Sambuc * check for a device value in the device table. If not found and the add
70285fee539SLionel Sambuc * flag is set, it is added. This does NOT assign any mapping values, just
70385fee539SLionel Sambuc * adds the device number as one that need to be remapped. If this device
70485fee539SLionel Sambuc * is already mapped, just return with a pointer to that entry.
70585fee539SLionel Sambuc * Return:
70685fee539SLionel Sambuc * pointer to the entry for this device in the device map table. Null
70785fee539SLionel Sambuc * if the add flag is not set and the device is not in the table (it is
70885fee539SLionel Sambuc * not been seen yet). If add is set and the device cannot be added, null
70985fee539SLionel Sambuc * is returned (indicates an error).
71085fee539SLionel Sambuc */
71185fee539SLionel Sambuc
71285fee539SLionel Sambuc static DEVT *
chk_dev(dev_t dev,int add)71385fee539SLionel Sambuc chk_dev(dev_t dev, int add)
71485fee539SLionel Sambuc {
71585fee539SLionel Sambuc DEVT *pt;
71685fee539SLionel Sambuc u_int indx;
71785fee539SLionel Sambuc
71885fee539SLionel Sambuc if (dtab == NULL)
71985fee539SLionel Sambuc return NULL;
72085fee539SLionel Sambuc /*
72185fee539SLionel Sambuc * look to see if this device is already in the table
72285fee539SLionel Sambuc */
72385fee539SLionel Sambuc indx = ((unsigned)dev) % D_TAB_SZ;
72485fee539SLionel Sambuc if ((pt = dtab[indx]) != NULL) {
72585fee539SLionel Sambuc while ((pt != NULL) && (pt->dev != dev))
72685fee539SLionel Sambuc pt = pt->fow;
72785fee539SLionel Sambuc
72885fee539SLionel Sambuc /*
72985fee539SLionel Sambuc * found it, return a pointer to it
73085fee539SLionel Sambuc */
73185fee539SLionel Sambuc if (pt != NULL)
73285fee539SLionel Sambuc return pt;
73385fee539SLionel Sambuc }
73485fee539SLionel Sambuc
73585fee539SLionel Sambuc /*
73685fee539SLionel Sambuc * not in table, we add it only if told to as this may just be a check
73785fee539SLionel Sambuc * to see if a device number is being used.
73885fee539SLionel Sambuc */
73985fee539SLionel Sambuc if (add == 0)
74085fee539SLionel Sambuc return NULL;
74185fee539SLionel Sambuc
74285fee539SLionel Sambuc /*
74385fee539SLionel Sambuc * allocate a node for this device and add it to the front of the hash
74485fee539SLionel Sambuc * chain. Note we do not assign remaps values here, so the pt->list
74585fee539SLionel Sambuc * list must be NULL.
74685fee539SLionel Sambuc */
74785fee539SLionel Sambuc if ((pt = (DEVT *)malloc(sizeof(DEVT))) == NULL) {
74885fee539SLionel Sambuc tty_warn(1, "Device map table out of memory");
74985fee539SLionel Sambuc return NULL;
75085fee539SLionel Sambuc }
75185fee539SLionel Sambuc pt->dev = dev;
75285fee539SLionel Sambuc pt->list = NULL;
75385fee539SLionel Sambuc pt->fow = dtab[indx];
75485fee539SLionel Sambuc dtab[indx] = pt;
75585fee539SLionel Sambuc return pt;
75685fee539SLionel Sambuc }
75785fee539SLionel Sambuc /*
75885fee539SLionel Sambuc * map_dev()
75985fee539SLionel Sambuc * given an inode and device storage mask (the mask has a 1 for each bit
76085fee539SLionel Sambuc * the archive format is able to store in a header), we check for inode
76185fee539SLionel Sambuc * and device truncation and remap the device as required. Device mapping
76285fee539SLionel Sambuc * can also occur when during the read phase of append a device number was
76385fee539SLionel Sambuc * seen (and was marked as do not use during the write phase). WE ASSUME
76485fee539SLionel Sambuc * that unsigned longs are the same size or bigger than the fields used
76585fee539SLionel Sambuc * for ino_t and dev_t. If not the types will have to be changed.
76685fee539SLionel Sambuc * Return:
76785fee539SLionel Sambuc * 0 if all ok, -1 otherwise.
76885fee539SLionel Sambuc */
76985fee539SLionel Sambuc
77085fee539SLionel Sambuc int
map_dev(ARCHD * arcn,u_long dev_mask,u_long ino_mask)77185fee539SLionel Sambuc map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask)
77285fee539SLionel Sambuc {
77385fee539SLionel Sambuc DEVT *pt;
77485fee539SLionel Sambuc DLIST *dpt;
77585fee539SLionel Sambuc static dev_t lastdev = 0; /* next device number to try */
77685fee539SLionel Sambuc int trc_ino = 0;
77785fee539SLionel Sambuc int trc_dev = 0;
77885fee539SLionel Sambuc ino_t trunc_bits = 0;
77985fee539SLionel Sambuc ino_t nino;
78085fee539SLionel Sambuc
78185fee539SLionel Sambuc if (dtab == NULL)
78285fee539SLionel Sambuc return 0;
78385fee539SLionel Sambuc /*
78485fee539SLionel Sambuc * check for device and inode truncation, and extract the truncated
78585fee539SLionel Sambuc * bit pattern.
78685fee539SLionel Sambuc */
78785fee539SLionel Sambuc if ((arcn->sb.st_dev & (dev_t)dev_mask) != arcn->sb.st_dev)
78885fee539SLionel Sambuc ++trc_dev;
78985fee539SLionel Sambuc if ((nino = arcn->sb.st_ino & (ino_t)ino_mask) != arcn->sb.st_ino) {
79085fee539SLionel Sambuc ++trc_ino;
79185fee539SLionel Sambuc trunc_bits = arcn->sb.st_ino & (ino_t)(~ino_mask);
79285fee539SLionel Sambuc }
79385fee539SLionel Sambuc
79485fee539SLionel Sambuc /*
79585fee539SLionel Sambuc * see if this device is already being mapped, look up the device
79685fee539SLionel Sambuc * then find the truncation bit pattern which applies
79785fee539SLionel Sambuc */
79885fee539SLionel Sambuc if ((pt = chk_dev(arcn->sb.st_dev, 0)) != NULL) {
79985fee539SLionel Sambuc /*
80085fee539SLionel Sambuc * this device is already marked to be remapped
80185fee539SLionel Sambuc */
80285fee539SLionel Sambuc for (dpt = pt->list; dpt != NULL; dpt = dpt->fow)
80385fee539SLionel Sambuc if (dpt->trunc_bits == trunc_bits)
80485fee539SLionel Sambuc break;
80585fee539SLionel Sambuc
80685fee539SLionel Sambuc if (dpt != NULL) {
80785fee539SLionel Sambuc /*
80885fee539SLionel Sambuc * we are being remapped for this device and pattern
80985fee539SLionel Sambuc * change the device number to be stored and return
81085fee539SLionel Sambuc */
81185fee539SLionel Sambuc arcn->sb.st_dev = dpt->dev;
81285fee539SLionel Sambuc arcn->sb.st_ino = nino;
81385fee539SLionel Sambuc return 0;
81485fee539SLionel Sambuc }
81585fee539SLionel Sambuc } else {
81685fee539SLionel Sambuc /*
81785fee539SLionel Sambuc * this device is not being remapped YET. if we do not have any
81885fee539SLionel Sambuc * form of truncation, we do not need a remap
81985fee539SLionel Sambuc */
82085fee539SLionel Sambuc if (!trc_ino && !trc_dev)
82185fee539SLionel Sambuc return 0;
82285fee539SLionel Sambuc
82385fee539SLionel Sambuc /*
82485fee539SLionel Sambuc * we have truncation, have to add this as a device to remap
82585fee539SLionel Sambuc */
82685fee539SLionel Sambuc if ((pt = chk_dev(arcn->sb.st_dev, 1)) == NULL)
82785fee539SLionel Sambuc goto bad;
82885fee539SLionel Sambuc
82985fee539SLionel Sambuc /*
83085fee539SLionel Sambuc * if we just have a truncated inode, we have to make sure that
83185fee539SLionel Sambuc * all future inodes that do not truncate (they have the
83285fee539SLionel Sambuc * truncation pattern of all 0's) continue to map to the same
83385fee539SLionel Sambuc * device number. We probably have already written inodes with
83485fee539SLionel Sambuc * this device number to the archive with the truncation
83585fee539SLionel Sambuc * pattern of all 0's. So we add the mapping for all 0's to the
83685fee539SLionel Sambuc * same device number.
83785fee539SLionel Sambuc */
83885fee539SLionel Sambuc if (!trc_dev && (trunc_bits != 0)) {
83985fee539SLionel Sambuc if ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL)
84085fee539SLionel Sambuc goto bad;
84185fee539SLionel Sambuc dpt->trunc_bits = 0;
84285fee539SLionel Sambuc dpt->dev = arcn->sb.st_dev;
84385fee539SLionel Sambuc dpt->fow = pt->list;
84485fee539SLionel Sambuc pt->list = dpt;
84585fee539SLionel Sambuc }
84685fee539SLionel Sambuc }
84785fee539SLionel Sambuc
84885fee539SLionel Sambuc /*
84985fee539SLionel Sambuc * look for a device number not being used. We must watch for wrap
85085fee539SLionel Sambuc * around on lastdev (so we do not get stuck looking forever!)
85185fee539SLionel Sambuc */
85285fee539SLionel Sambuc while (++lastdev > 0) {
85385fee539SLionel Sambuc if (chk_dev(lastdev, 0) != NULL)
85485fee539SLionel Sambuc continue;
85585fee539SLionel Sambuc /*
85685fee539SLionel Sambuc * found an unused value. If we have reached truncation point
85785fee539SLionel Sambuc * for this format we are hosed, so we give up. Otherwise we
85885fee539SLionel Sambuc * mark it as being used.
85985fee539SLionel Sambuc */
86085fee539SLionel Sambuc if (((lastdev & ((dev_t)dev_mask)) != lastdev) ||
86185fee539SLionel Sambuc (chk_dev(lastdev, 1) == NULL))
86285fee539SLionel Sambuc goto bad;
86385fee539SLionel Sambuc break;
86485fee539SLionel Sambuc }
86585fee539SLionel Sambuc
86685fee539SLionel Sambuc if ((lastdev <= 0) || ((dpt = (DLIST *)malloc(sizeof(DLIST))) == NULL))
86785fee539SLionel Sambuc goto bad;
86885fee539SLionel Sambuc
86985fee539SLionel Sambuc /*
87085fee539SLionel Sambuc * got a new device number, store it under this truncation pattern.
87185fee539SLionel Sambuc * change the device number this file is being stored with.
87285fee539SLionel Sambuc */
87385fee539SLionel Sambuc dpt->trunc_bits = trunc_bits;
87485fee539SLionel Sambuc dpt->dev = lastdev;
87585fee539SLionel Sambuc dpt->fow = pt->list;
87685fee539SLionel Sambuc pt->list = dpt;
87785fee539SLionel Sambuc arcn->sb.st_dev = lastdev;
87885fee539SLionel Sambuc arcn->sb.st_ino = nino;
87985fee539SLionel Sambuc return 0;
88085fee539SLionel Sambuc
88185fee539SLionel Sambuc bad:
88285fee539SLionel Sambuc tty_warn(1,
88385fee539SLionel Sambuc "Unable to fix truncated inode/device field when storing %s",
88485fee539SLionel Sambuc arcn->name);
88585fee539SLionel Sambuc tty_warn(0, "Archive may create improper hard links when extracted");
88685fee539SLionel Sambuc return 0;
88785fee539SLionel Sambuc }
88885fee539SLionel Sambuc
88985fee539SLionel Sambuc /*
89085fee539SLionel Sambuc * directory access/mod time reset table routines (for directories READ by pax)
89185fee539SLionel Sambuc *
89285fee539SLionel Sambuc * The pax -t flag requires that access times of archive files to be the same
89385fee539SLionel Sambuc * as before being read by pax. For regular files, access time is restored after
89485fee539SLionel Sambuc * the file has been copied. This database provides the same functionality for
89585fee539SLionel Sambuc * directories read during file tree traversal. Restoring directory access time
89685fee539SLionel Sambuc * is more complex than files since directories may be read several times until
89785fee539SLionel Sambuc * all the descendants in their subtree are visited by fts. Directory access
89885fee539SLionel Sambuc * and modification times are stored during the fts pre-order visit (done
89985fee539SLionel Sambuc * before any descendants in the subtree is visited) and restored after the
90085fee539SLionel Sambuc * fts post-order visit (after all the descendants have been visited). In the
90185fee539SLionel Sambuc * case of premature exit from a subtree (like from the effects of -n), any
90285fee539SLionel Sambuc * directory entries left in this database are reset during final cleanup
90385fee539SLionel Sambuc * operations of pax. Entries are hashed by inode number for fast lookup.
90485fee539SLionel Sambuc */
90585fee539SLionel Sambuc
90685fee539SLionel Sambuc /*
90785fee539SLionel Sambuc * atdir_start()
90885fee539SLionel Sambuc * create the directory access time database for directories READ by pax.
90985fee539SLionel Sambuc * Return:
91085fee539SLionel Sambuc * 0 is created ok, -1 otherwise.
91185fee539SLionel Sambuc */
91285fee539SLionel Sambuc
91385fee539SLionel Sambuc int
atdir_start(void)91485fee539SLionel Sambuc atdir_start(void)
91585fee539SLionel Sambuc {
91685fee539SLionel Sambuc if (atab != NULL)
91785fee539SLionel Sambuc return 0;
91885fee539SLionel Sambuc if ((atab = (ATDIR **)calloc(A_TAB_SZ, sizeof(ATDIR *))) == NULL) {
91985fee539SLionel Sambuc tty_warn(1,
92085fee539SLionel Sambuc "Cannot allocate space for directory access time table");
92185fee539SLionel Sambuc return -1;
92285fee539SLionel Sambuc }
92385fee539SLionel Sambuc return 0;
92485fee539SLionel Sambuc }
92585fee539SLionel Sambuc
92685fee539SLionel Sambuc
92785fee539SLionel Sambuc /*
92885fee539SLionel Sambuc * atdir_end()
92985fee539SLionel Sambuc * walk through the directory access time table and reset the access time
93085fee539SLionel Sambuc * of any directory who still has an entry left in the database. These
93185fee539SLionel Sambuc * entries are for directories READ by pax
93285fee539SLionel Sambuc */
93385fee539SLionel Sambuc
93485fee539SLionel Sambuc void
atdir_end(void)93585fee539SLionel Sambuc atdir_end(void)
93685fee539SLionel Sambuc {
93785fee539SLionel Sambuc ATDIR *pt;
93885fee539SLionel Sambuc int i;
93985fee539SLionel Sambuc
94085fee539SLionel Sambuc if (atab == NULL)
94185fee539SLionel Sambuc return;
94285fee539SLionel Sambuc /*
94385fee539SLionel Sambuc * for each non-empty hash table entry reset all the directories
94485fee539SLionel Sambuc * chained there.
94585fee539SLionel Sambuc */
94685fee539SLionel Sambuc for (i = 0; i < A_TAB_SZ; ++i) {
94785fee539SLionel Sambuc if ((pt = atab[i]) == NULL)
94885fee539SLionel Sambuc continue;
94985fee539SLionel Sambuc /*
95085fee539SLionel Sambuc * remember to force the times, set_ftime() looks at pmtime
95185fee539SLionel Sambuc * and patime, which only applies to things CREATED by pax,
95285fee539SLionel Sambuc * not read by pax. Read time reset is controlled by -t.
95385fee539SLionel Sambuc */
95485fee539SLionel Sambuc for (; pt != NULL; pt = pt->fow)
95585fee539SLionel Sambuc set_ftime(pt->name, pt->mtime, pt->atime, 1, 0);
95685fee539SLionel Sambuc }
95785fee539SLionel Sambuc }
95885fee539SLionel Sambuc
95985fee539SLionel Sambuc /*
96085fee539SLionel Sambuc * add_atdir()
96185fee539SLionel Sambuc * add a directory to the directory access time table. Table is hashed
96285fee539SLionel Sambuc * and chained by inode number. This is for directories READ by pax
96385fee539SLionel Sambuc */
96485fee539SLionel Sambuc
96585fee539SLionel Sambuc void
add_atdir(char * fname,dev_t dev,ino_t ino,time_t mtime,time_t atime)96685fee539SLionel Sambuc add_atdir(char *fname, dev_t dev, ino_t ino, time_t mtime, time_t atime)
96785fee539SLionel Sambuc {
96885fee539SLionel Sambuc ATDIR *pt;
96985fee539SLionel Sambuc u_int indx;
97085fee539SLionel Sambuc
97185fee539SLionel Sambuc if (atab == NULL)
97285fee539SLionel Sambuc return;
97385fee539SLionel Sambuc
97485fee539SLionel Sambuc /*
97585fee539SLionel Sambuc * make sure this directory is not already in the table, if so just
97685fee539SLionel Sambuc * return (the older entry always has the correct time). The only
97785fee539SLionel Sambuc * way this will happen is when the same subtree can be traversed by
97885fee539SLionel Sambuc * different args to pax and the -n option is aborting fts out of a
97985fee539SLionel Sambuc * subtree before all the post-order visits have been made.
98085fee539SLionel Sambuc */
98185fee539SLionel Sambuc indx = ((unsigned)ino) % A_TAB_SZ;
98285fee539SLionel Sambuc if ((pt = atab[indx]) != NULL) {
98385fee539SLionel Sambuc while (pt != NULL) {
98485fee539SLionel Sambuc if ((pt->ino == ino) && (pt->dev == dev))
98585fee539SLionel Sambuc break;
98685fee539SLionel Sambuc pt = pt->fow;
98785fee539SLionel Sambuc }
98885fee539SLionel Sambuc
98985fee539SLionel Sambuc /*
99085fee539SLionel Sambuc * oops, already there. Leave it alone.
99185fee539SLionel Sambuc */
99285fee539SLionel Sambuc if (pt != NULL)
99385fee539SLionel Sambuc return;
99485fee539SLionel Sambuc }
99585fee539SLionel Sambuc
99685fee539SLionel Sambuc /*
99785fee539SLionel Sambuc * add it to the front of the hash chain
99885fee539SLionel Sambuc */
99985fee539SLionel Sambuc if ((pt = (ATDIR *)malloc(sizeof(ATDIR))) != NULL) {
100085fee539SLionel Sambuc if ((pt->name = strdup(fname)) != NULL) {
100185fee539SLionel Sambuc pt->dev = dev;
100285fee539SLionel Sambuc pt->ino = ino;
100385fee539SLionel Sambuc pt->mtime = mtime;
100485fee539SLionel Sambuc pt->atime = atime;
100585fee539SLionel Sambuc pt->fow = atab[indx];
100685fee539SLionel Sambuc atab[indx] = pt;
100785fee539SLionel Sambuc return;
100885fee539SLionel Sambuc }
100985fee539SLionel Sambuc (void)free((char *)pt);
101085fee539SLionel Sambuc }
101185fee539SLionel Sambuc
101285fee539SLionel Sambuc tty_warn(1, "Directory access time reset table ran out of memory");
101385fee539SLionel Sambuc return;
101485fee539SLionel Sambuc }
101585fee539SLionel Sambuc
101685fee539SLionel Sambuc /*
101785fee539SLionel Sambuc * get_atdir()
101885fee539SLionel Sambuc * look up a directory by inode and device number to obtain the access
101985fee539SLionel Sambuc * and modification time you want to set to. If found, the modification
102085fee539SLionel Sambuc * and access time parameters are set and the entry is removed from the
102185fee539SLionel Sambuc * table (as it is no longer needed). These are for directories READ by
102285fee539SLionel Sambuc * pax
102385fee539SLionel Sambuc * Return:
102485fee539SLionel Sambuc * 0 if found, -1 if not found.
102585fee539SLionel Sambuc */
102685fee539SLionel Sambuc
102785fee539SLionel Sambuc int
get_atdir(dev_t dev,ino_t ino,time_t * mtime,time_t * atime)102885fee539SLionel Sambuc get_atdir(dev_t dev, ino_t ino, time_t *mtime, time_t *atime)
102985fee539SLionel Sambuc {
103085fee539SLionel Sambuc ATDIR *pt;
103185fee539SLionel Sambuc ATDIR **ppt;
103285fee539SLionel Sambuc u_int indx;
103385fee539SLionel Sambuc
103485fee539SLionel Sambuc if (atab == NULL)
103585fee539SLionel Sambuc return -1;
103685fee539SLionel Sambuc /*
103785fee539SLionel Sambuc * hash by inode and search the chain for an inode and device match
103885fee539SLionel Sambuc */
103985fee539SLionel Sambuc indx = ((unsigned)ino) % A_TAB_SZ;
104085fee539SLionel Sambuc if ((pt = atab[indx]) == NULL)
104185fee539SLionel Sambuc return -1;
104285fee539SLionel Sambuc
104385fee539SLionel Sambuc ppt = &(atab[indx]);
104485fee539SLionel Sambuc while (pt != NULL) {
104585fee539SLionel Sambuc if ((pt->ino == ino) && (pt->dev == dev))
104685fee539SLionel Sambuc break;
104785fee539SLionel Sambuc /*
104885fee539SLionel Sambuc * no match, go to next one
104985fee539SLionel Sambuc */
105085fee539SLionel Sambuc ppt = &(pt->fow);
105185fee539SLionel Sambuc pt = pt->fow;
105285fee539SLionel Sambuc }
105385fee539SLionel Sambuc
105485fee539SLionel Sambuc /*
105585fee539SLionel Sambuc * return if we did not find it.
105685fee539SLionel Sambuc */
105785fee539SLionel Sambuc if (pt == NULL)
105885fee539SLionel Sambuc return -1;
105985fee539SLionel Sambuc
106085fee539SLionel Sambuc /*
106185fee539SLionel Sambuc * found it. return the times and remove the entry from the table.
106285fee539SLionel Sambuc */
106385fee539SLionel Sambuc *ppt = pt->fow;
106485fee539SLionel Sambuc *mtime = pt->mtime;
106585fee539SLionel Sambuc *atime = pt->atime;
106685fee539SLionel Sambuc (void)free((char *)pt->name);
106785fee539SLionel Sambuc (void)free((char *)pt);
106885fee539SLionel Sambuc return 0;
106985fee539SLionel Sambuc }
107085fee539SLionel Sambuc
107185fee539SLionel Sambuc /*
107285fee539SLionel Sambuc * directory access mode and time storage routines (for directories CREATED
107385fee539SLionel Sambuc * by pax).
107485fee539SLionel Sambuc *
107585fee539SLionel Sambuc * Pax requires that extracted directories, by default, have their access/mod
107685fee539SLionel Sambuc * times and permissions set to the values specified in the archive. During the
107785fee539SLionel Sambuc * actions of extracting (and creating the destination subtree during -rw copy)
107885fee539SLionel Sambuc * directories extracted may be modified after being created. Even worse is
107985fee539SLionel Sambuc * that these directories may have been created with file permissions which
108085fee539SLionel Sambuc * prohibits any descendants of these directories from being extracted. When
108185fee539SLionel Sambuc * directories are created by pax, access rights may be added to permit the
108285fee539SLionel Sambuc * creation of files in their subtree. Every time pax creates a directory, the
108385fee539SLionel Sambuc * times and file permissions specified by the archive are stored. After all
108485fee539SLionel Sambuc * files have been extracted (or copied), these directories have their times
108585fee539SLionel Sambuc * and file modes reset to the stored values. The directory info is restored in
108685fee539SLionel Sambuc * reverse order as entries were added to the data file from root to leaf. To
108785fee539SLionel Sambuc * restore atime properly, we must go backwards. The data file consists of
108885fee539SLionel Sambuc * records with two parts, the file name followed by a DIRDATA trailer. The
108985fee539SLionel Sambuc * fixed sized trailer contains the size of the name plus the off_t location in
109085fee539SLionel Sambuc * the file. To restore we work backwards through the file reading the trailer
109185fee539SLionel Sambuc * then the file name.
109285fee539SLionel Sambuc */
109385fee539SLionel Sambuc
109485fee539SLionel Sambuc #ifndef DIRS_USE_FILE
109585fee539SLionel Sambuc static DIRDATA *dirdata_head;
109685fee539SLionel Sambuc #endif
109785fee539SLionel Sambuc
109885fee539SLionel Sambuc /*
109985fee539SLionel Sambuc * dir_start()
110085fee539SLionel Sambuc * set up the directory time and file mode storage for directories CREATED
110185fee539SLionel Sambuc * by pax.
110285fee539SLionel Sambuc * Return:
110385fee539SLionel Sambuc * 0 if ok, -1 otherwise
110485fee539SLionel Sambuc */
110585fee539SLionel Sambuc
110685fee539SLionel Sambuc int
dir_start(void)110785fee539SLionel Sambuc dir_start(void)
110885fee539SLionel Sambuc {
110985fee539SLionel Sambuc #ifdef DIRS_USE_FILE
111085fee539SLionel Sambuc if (dirfd != -1)
111185fee539SLionel Sambuc return 0;
111285fee539SLionel Sambuc
111385fee539SLionel Sambuc /*
111485fee539SLionel Sambuc * unlink the file so it goes away at termination by itself
111585fee539SLionel Sambuc */
111685fee539SLionel Sambuc memcpy(tempbase, _TFILE_BASE, sizeof(_TFILE_BASE));
111785fee539SLionel Sambuc if ((dirfd = mkstemp(tempfile)) >= 0) {
111885fee539SLionel Sambuc (void)unlink(tempfile);
111985fee539SLionel Sambuc return 0;
112085fee539SLionel Sambuc }
112185fee539SLionel Sambuc tty_warn(1, "Unable to create temporary file for directory times: %s",
112285fee539SLionel Sambuc tempfile);
112385fee539SLionel Sambuc return -1;
112485fee539SLionel Sambuc #else
112585fee539SLionel Sambuc return (0);
112685fee539SLionel Sambuc #endif /* DIRS_USE_FILE */
112785fee539SLionel Sambuc }
112885fee539SLionel Sambuc
112985fee539SLionel Sambuc /*
113085fee539SLionel Sambuc * add_dir()
113185fee539SLionel Sambuc * add the mode and times for a newly CREATED directory
113285fee539SLionel Sambuc * name is name of the directory, psb the stat buffer with the data in it,
113385fee539SLionel Sambuc * frc_mode is a flag that says whether to force the setting of the mode
113485fee539SLionel Sambuc * (ignoring the user set values for preserving file mode). Frc_mode is
113585fee539SLionel Sambuc * for the case where we created a file and found that the resulting
113685fee539SLionel Sambuc * directory was not writable and the user asked for file modes to NOT
113785fee539SLionel Sambuc * be preserved. (we have to preserve what was created by default, so we
113885fee539SLionel Sambuc * have to force the setting at the end. this is stated explicitly in the
113985fee539SLionel Sambuc * pax spec)
114085fee539SLionel Sambuc */
114185fee539SLionel Sambuc
114285fee539SLionel Sambuc void
add_dir(char * name,int nlen,struct stat * psb,int frc_mode)114385fee539SLionel Sambuc add_dir(char *name, int nlen, struct stat *psb, int frc_mode)
114485fee539SLionel Sambuc {
114585fee539SLionel Sambuc #ifdef DIRS_USE_FILE
114685fee539SLionel Sambuc DIRDATA dblk;
114785fee539SLionel Sambuc #else
114885fee539SLionel Sambuc DIRDATA *dblk;
114985fee539SLionel Sambuc #endif
115085fee539SLionel Sambuc char realname[MAXPATHLEN], *rp;
115185fee539SLionel Sambuc
115285fee539SLionel Sambuc if (havechd && *name != '/') {
115385fee539SLionel Sambuc if ((rp = realpath(name, realname)) == NULL) {
115485fee539SLionel Sambuc tty_warn(1, "Cannot canonicalize %s", name);
115585fee539SLionel Sambuc return;
115685fee539SLionel Sambuc }
115785fee539SLionel Sambuc name = rp;
1158*84d9c625SLionel Sambuc #ifdef DIRS_USE_FILE
115985fee539SLionel Sambuc nlen = strlen(name);
1160*84d9c625SLionel Sambuc #endif
116185fee539SLionel Sambuc }
116285fee539SLionel Sambuc
116385fee539SLionel Sambuc #ifdef DIRS_USE_FILE
116485fee539SLionel Sambuc if (dirfd < 0)
116585fee539SLionel Sambuc return;
116685fee539SLionel Sambuc
116785fee539SLionel Sambuc /*
116885fee539SLionel Sambuc * get current position (where file name will start) so we can store it
116985fee539SLionel Sambuc * in the trailer
117085fee539SLionel Sambuc */
117185fee539SLionel Sambuc if ((dblk.npos = lseek(dirfd, 0L, SEEK_CUR)) < 0) {
117285fee539SLionel Sambuc tty_warn(1,
117385fee539SLionel Sambuc "Unable to store mode and times for directory: %s",name);
117485fee539SLionel Sambuc return;
117585fee539SLionel Sambuc }
117685fee539SLionel Sambuc
117785fee539SLionel Sambuc /*
117885fee539SLionel Sambuc * write the file name followed by the trailer
117985fee539SLionel Sambuc */
118085fee539SLionel Sambuc dblk.nlen = nlen + 1;
118185fee539SLionel Sambuc dblk.mode = psb->st_mode & 0xffff;
118285fee539SLionel Sambuc dblk.mtime = psb->st_mtime;
118385fee539SLionel Sambuc dblk.atime = psb->st_atime;
118485fee539SLionel Sambuc #if HAVE_STRUCT_STAT_ST_FLAGS
118585fee539SLionel Sambuc dblk.fflags = psb->st_flags;
118685fee539SLionel Sambuc #else
118785fee539SLionel Sambuc dblk.fflags = 0;
118885fee539SLionel Sambuc #endif
118985fee539SLionel Sambuc dblk.frc_mode = frc_mode;
119085fee539SLionel Sambuc if ((xwrite(dirfd, name, dblk.nlen) == dblk.nlen) &&
119185fee539SLionel Sambuc (xwrite(dirfd, (char *)&dblk, sizeof(dblk)) == sizeof(dblk))) {
119285fee539SLionel Sambuc ++dircnt;
119385fee539SLionel Sambuc return;
119485fee539SLionel Sambuc }
119585fee539SLionel Sambuc
119685fee539SLionel Sambuc tty_warn(1,
119785fee539SLionel Sambuc "Unable to store mode and times for created directory: %s",name);
119885fee539SLionel Sambuc return;
119985fee539SLionel Sambuc #else
120085fee539SLionel Sambuc
120185fee539SLionel Sambuc if ((dblk = malloc(sizeof(*dblk))) == NULL ||
120285fee539SLionel Sambuc (dblk->name = strdup(name)) == NULL) {
120385fee539SLionel Sambuc tty_warn(1,
120485fee539SLionel Sambuc "Unable to store mode and times for directory: %s",name);
120585fee539SLionel Sambuc if (dblk != NULL)
120685fee539SLionel Sambuc free(dblk);
120785fee539SLionel Sambuc return;
120885fee539SLionel Sambuc }
120985fee539SLionel Sambuc
121085fee539SLionel Sambuc dblk->mode = psb->st_mode & 0xffff;
121185fee539SLionel Sambuc dblk->mtime = psb->st_mtime;
121285fee539SLionel Sambuc dblk->atime = psb->st_atime;
121385fee539SLionel Sambuc #if HAVE_STRUCT_STAT_ST_FLAGS
121485fee539SLionel Sambuc dblk->fflags = psb->st_flags;
121585fee539SLionel Sambuc #else
121685fee539SLionel Sambuc dblk->fflags = 0;
121785fee539SLionel Sambuc #endif
121885fee539SLionel Sambuc dblk->frc_mode = frc_mode;
121985fee539SLionel Sambuc
122085fee539SLionel Sambuc dblk->next = dirdata_head;
122185fee539SLionel Sambuc dirdata_head = dblk;
122285fee539SLionel Sambuc return;
122385fee539SLionel Sambuc #endif /* DIRS_USE_FILE */
122485fee539SLionel Sambuc }
122585fee539SLionel Sambuc
122685fee539SLionel Sambuc /*
122785fee539SLionel Sambuc * proc_dir()
122885fee539SLionel Sambuc * process all file modes and times stored for directories CREATED
122985fee539SLionel Sambuc * by pax
123085fee539SLionel Sambuc */
123185fee539SLionel Sambuc
123285fee539SLionel Sambuc void
proc_dir(void)123385fee539SLionel Sambuc proc_dir(void)
123485fee539SLionel Sambuc {
123585fee539SLionel Sambuc #ifdef DIRS_USE_FILE
123685fee539SLionel Sambuc char name[PAXPATHLEN+1];
123785fee539SLionel Sambuc DIRDATA dblk;
123885fee539SLionel Sambuc u_long cnt;
123985fee539SLionel Sambuc
124085fee539SLionel Sambuc if (dirfd < 0)
124185fee539SLionel Sambuc return;
124285fee539SLionel Sambuc /*
124385fee539SLionel Sambuc * read backwards through the file and process each directory
124485fee539SLionel Sambuc */
124585fee539SLionel Sambuc for (cnt = 0; cnt < dircnt; ++cnt) {
124685fee539SLionel Sambuc /*
124785fee539SLionel Sambuc * read the trailer, then the file name, if this fails
124885fee539SLionel Sambuc * just give up.
124985fee539SLionel Sambuc */
125085fee539SLionel Sambuc if (lseek(dirfd, -((off_t)sizeof(dblk)), SEEK_CUR) < 0)
125185fee539SLionel Sambuc break;
125285fee539SLionel Sambuc if (xread(dirfd,(char *)&dblk, sizeof(dblk)) != sizeof(dblk))
125385fee539SLionel Sambuc break;
125485fee539SLionel Sambuc if (lseek(dirfd, dblk.npos, SEEK_SET) < 0)
125585fee539SLionel Sambuc break;
125685fee539SLionel Sambuc if (xread(dirfd, name, dblk.nlen) != dblk.nlen)
125785fee539SLionel Sambuc break;
125885fee539SLionel Sambuc if (lseek(dirfd, dblk.npos, SEEK_SET) < 0)
125985fee539SLionel Sambuc break;
126085fee539SLionel Sambuc
126185fee539SLionel Sambuc /*
126285fee539SLionel Sambuc * frc_mode set, make sure we set the file modes even if
126385fee539SLionel Sambuc * the user didn't ask for it (see file_subs.c for more info)
126485fee539SLionel Sambuc */
126585fee539SLionel Sambuc if (pmode || dblk.frc_mode)
126685fee539SLionel Sambuc set_pmode(name, dblk.mode);
126785fee539SLionel Sambuc if (patime || pmtime)
126885fee539SLionel Sambuc set_ftime(name, dblk.mtime, dblk.atime, 0, 0);
126985fee539SLionel Sambuc if (pfflags)
127085fee539SLionel Sambuc set_chflags(name, dblk.fflags);
127185fee539SLionel Sambuc }
127285fee539SLionel Sambuc
127385fee539SLionel Sambuc (void)close(dirfd);
127485fee539SLionel Sambuc dirfd = -1;
127585fee539SLionel Sambuc if (cnt != dircnt)
127685fee539SLionel Sambuc tty_warn(1,
127785fee539SLionel Sambuc "Unable to set mode and times for created directories");
127885fee539SLionel Sambuc return;
127985fee539SLionel Sambuc #else
128085fee539SLionel Sambuc DIRDATA *dblk;
128185fee539SLionel Sambuc
128285fee539SLionel Sambuc for (dblk = dirdata_head; dblk != NULL; dblk = dirdata_head) {
128385fee539SLionel Sambuc dirdata_head = dblk->next;
128485fee539SLionel Sambuc
128585fee539SLionel Sambuc /*
128685fee539SLionel Sambuc * frc_mode set, make sure we set the file modes even if
128785fee539SLionel Sambuc * the user didn't ask for it (see file_subs.c for more info)
128885fee539SLionel Sambuc */
128985fee539SLionel Sambuc if (pmode || dblk->frc_mode)
129085fee539SLionel Sambuc set_pmode(dblk->name, dblk->mode);
129185fee539SLionel Sambuc if (patime || pmtime)
129285fee539SLionel Sambuc set_ftime(dblk->name, dblk->mtime, dblk->atime, 0, 0);
129385fee539SLionel Sambuc if (pfflags)
129485fee539SLionel Sambuc set_chflags(dblk->name, dblk->fflags);
129585fee539SLionel Sambuc
129685fee539SLionel Sambuc free(dblk->name);
129785fee539SLionel Sambuc free(dblk);
129885fee539SLionel Sambuc }
129985fee539SLionel Sambuc #endif /* DIRS_USE_FILE */
130085fee539SLionel Sambuc }
130185fee539SLionel Sambuc
130285fee539SLionel Sambuc /*
130385fee539SLionel Sambuc * database independent routines
130485fee539SLionel Sambuc */
130585fee539SLionel Sambuc
130685fee539SLionel Sambuc /*
130785fee539SLionel Sambuc * st_hash()
130885fee539SLionel Sambuc * hashes filenames to a u_int for hashing into a table. Looks at the tail
130985fee539SLionel Sambuc * end of file, as this provides far better distribution than any other
131085fee539SLionel Sambuc * part of the name. For performance reasons we only care about the last
131185fee539SLionel Sambuc * MAXKEYLEN chars (should be at LEAST large enough to pick off the file
131285fee539SLionel Sambuc * name). Was tested on 500,000 name file tree traversal from the root
131385fee539SLionel Sambuc * and gave almost a perfectly uniform distribution of keys when used with
131485fee539SLionel Sambuc * prime sized tables (MAXKEYLEN was 128 in test). Hashes (sizeof int)
131585fee539SLionel Sambuc * chars at a time and pads with 0 for last addition.
131685fee539SLionel Sambuc * Return:
131785fee539SLionel Sambuc * the hash value of the string MOD (%) the table size.
131885fee539SLionel Sambuc */
131985fee539SLionel Sambuc
132085fee539SLionel Sambuc u_int
st_hash(char * name,int len,int tabsz)132185fee539SLionel Sambuc st_hash(char *name, int len, int tabsz)
132285fee539SLionel Sambuc {
132385fee539SLionel Sambuc char *pt;
132485fee539SLionel Sambuc char *dest;
132585fee539SLionel Sambuc char *end;
132685fee539SLionel Sambuc int i;
132785fee539SLionel Sambuc u_int key = 0;
132885fee539SLionel Sambuc int steps;
132985fee539SLionel Sambuc int res;
133085fee539SLionel Sambuc u_int val;
133185fee539SLionel Sambuc
133285fee539SLionel Sambuc /*
133385fee539SLionel Sambuc * only look at the tail up to MAXKEYLEN, we do not need to waste
133485fee539SLionel Sambuc * time here (remember these are pathnames, the tail is what will
133585fee539SLionel Sambuc * spread out the keys)
133685fee539SLionel Sambuc */
133785fee539SLionel Sambuc if (len > MAXKEYLEN) {
133885fee539SLionel Sambuc pt = &(name[len - MAXKEYLEN]);
133985fee539SLionel Sambuc len = MAXKEYLEN;
134085fee539SLionel Sambuc } else
134185fee539SLionel Sambuc pt = name;
134285fee539SLionel Sambuc
134385fee539SLionel Sambuc /*
134485fee539SLionel Sambuc * calculate the number of u_int size steps in the string and if
134585fee539SLionel Sambuc * there is a runt to deal with
134685fee539SLionel Sambuc */
134785fee539SLionel Sambuc steps = len/sizeof(u_int);
134885fee539SLionel Sambuc res = len % sizeof(u_int);
134985fee539SLionel Sambuc
135085fee539SLionel Sambuc /*
135185fee539SLionel Sambuc * add up the value of the string in unsigned integer sized pieces
135285fee539SLionel Sambuc * too bad we cannot have unsigned int aligned strings, then we
135385fee539SLionel Sambuc * could avoid the expensive copy.
135485fee539SLionel Sambuc */
135585fee539SLionel Sambuc for (i = 0; i < steps; ++i) {
135685fee539SLionel Sambuc end = pt + sizeof(u_int);
135785fee539SLionel Sambuc dest = (char *)&val;
135885fee539SLionel Sambuc while (pt < end)
135985fee539SLionel Sambuc *dest++ = *pt++;
136085fee539SLionel Sambuc key += val;
136185fee539SLionel Sambuc }
136285fee539SLionel Sambuc
136385fee539SLionel Sambuc /*
136485fee539SLionel Sambuc * add in the runt padded with zero to the right
136585fee539SLionel Sambuc */
136685fee539SLionel Sambuc if (res) {
136785fee539SLionel Sambuc val = 0;
136885fee539SLionel Sambuc end = pt + res;
136985fee539SLionel Sambuc dest = (char *)&val;
137085fee539SLionel Sambuc while (pt < end)
137185fee539SLionel Sambuc *dest++ = *pt++;
137285fee539SLionel Sambuc key += val;
137385fee539SLionel Sambuc }
137485fee539SLionel Sambuc
137585fee539SLionel Sambuc /*
137685fee539SLionel Sambuc * return the result mod the table size
137785fee539SLionel Sambuc */
137885fee539SLionel Sambuc return key % tabsz;
137985fee539SLionel Sambuc }
1380