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