| File: | src/bin/pax/tables.c |
| Warning: | line 1767, column 7 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: tables.c,v 1.55 2023/11/26 16:04:17 espie Exp $ */ | |||
| 2 | /* $NetBSD: tables.c,v 1.4 1995/03/21 09:07:45 cgd Exp $ */ | |||
| 3 | ||||
| 4 | /*- | |||
| 5 | * Copyright (c) 1992 Keith Muller. | |||
| 6 | * Copyright (c) 1992, 1993 | |||
| 7 | * The Regents of the University of California. All rights reserved. | |||
| 8 | * | |||
| 9 | * This code is derived from software contributed to Berkeley by | |||
| 10 | * Keith Muller of the University of California, San Diego. | |||
| 11 | * | |||
| 12 | * Redistribution and use in source and binary forms, with or without | |||
| 13 | * modification, are permitted provided that the following conditions | |||
| 14 | * are met: | |||
| 15 | * 1. Redistributions of source code must retain the above copyright | |||
| 16 | * notice, this list of conditions and the following disclaimer. | |||
| 17 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 18 | * notice, this list of conditions and the following disclaimer in the | |||
| 19 | * documentation and/or other materials provided with the distribution. | |||
| 20 | * 3. Neither the name of the University nor the names of its contributors | |||
| 21 | * may be used to endorse or promote products derived from this software | |||
| 22 | * without specific prior written permission. | |||
| 23 | * | |||
| 24 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |||
| 25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |||
| 26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |||
| 27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |||
| 28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |||
| 29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |||
| 30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |||
| 31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |||
| 32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |||
| 33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |||
| 34 | * SUCH DAMAGE. | |||
| 35 | */ | |||
| 36 | ||||
| 37 | #include <sys/types.h> | |||
| 38 | #include <sys/stat.h> | |||
| 39 | #include <errno(*__errno()).h> | |||
| 40 | #include <fcntl.h> | |||
| 41 | #include <limits.h> | |||
| 42 | #include <signal.h> | |||
| 43 | #include <stdio.h> | |||
| 44 | #include <stdlib.h> | |||
| 45 | #include <string.h> | |||
| 46 | #include <unistd.h> | |||
| 47 | ||||
| 48 | #include "pax.h" | |||
| 49 | #include "extern.h" | |||
| 50 | static u_int st_hash(const char *, int, int); | |||
| 51 | ||||
| 52 | /* | |||
| 53 | * Routines for controlling the contents of all the different databases pax | |||
| 54 | * keeps. Tables are dynamically created only when they are needed. The | |||
| 55 | * goal was speed and the ability to work with HUGE archives. The databases | |||
| 56 | * were kept simple, but do have complex rules for when the contents change. | |||
| 57 | * As of this writing, the posix library functions were more complex than | |||
| 58 | * needed for this application (pax databases have very short lifetimes and | |||
| 59 | * do not survive after pax is finished). Pax is required to handle very | |||
| 60 | * large archives. These database routines carefully combine memory usage and | |||
| 61 | * temporary file storage in ways which will not significantly impact runtime | |||
| 62 | * performance while allowing the largest possible archives to be handled. | |||
| 63 | * Trying to force the fit to the posix database routines was not considered | |||
| 64 | * time well spent. | |||
| 65 | */ | |||
| 66 | ||||
| 67 | /* | |||
| 68 | * data structures and constants used by the different databases kept by pax | |||
| 69 | */ | |||
| 70 | ||||
| 71 | /* | |||
| 72 | * Hash Table Sizes MUST BE PRIME, if set too small performance suffers. | |||
| 73 | * Probably safe to expect 500000 inodes per tape. Assuming good key | |||
| 74 | * distribution (inodes) chains of under 50 long (worst case) is ok. | |||
| 75 | */ | |||
| 76 | #define L_TAB_SZ2503 2503 /* hard link hash table size */ | |||
| 77 | #define F_TAB_SZ50503 50503 /* file time hash table size */ | |||
| 78 | #define N_TAB_SZ541 541 /* interactive rename hash table */ | |||
| 79 | #define D_TAB_SZ317 317 /* unique device mapping table */ | |||
| 80 | #define A_TAB_SZ317 317 /* ftree dir access time reset table */ | |||
| 81 | #define SL_TAB_SZ317 317 /* escape symlink tables */ | |||
| 82 | #define MAXKEYLEN64 64 /* max number of chars for hash */ | |||
| 83 | #define DIRP_SIZE64 64 /* initial size of created dir table */ | |||
| 84 | ||||
| 85 | /* | |||
| 86 | * file hard link structure (hashed by dev/ino and chained) used to find the | |||
| 87 | * hard links in a file system or with some archive formats (cpio) | |||
| 88 | */ | |||
| 89 | typedef struct hrdlnk { | |||
| 90 | ino_t ino; /* files inode number */ | |||
| 91 | char *name; /* name of first file seen with this ino/dev */ | |||
| 92 | dev_t dev; /* files device number */ | |||
| 93 | u_long nlink; /* expected link count */ | |||
| 94 | struct hrdlnk *fow; | |||
| 95 | } HRDLNK; | |||
| 96 | ||||
| 97 | /* | |||
| 98 | * Archive write update file time table (the -u, -C flag), hashed by filename. | |||
| 99 | * Filenames are stored in a scratch file at seek offset into the file. The | |||
| 100 | * file time (mod time) and the file name length (for a quick check) are | |||
| 101 | * stored in a hash table node. We were forced to use a scratch file because | |||
| 102 | * with -u, the mtime for every node in the archive must always be available | |||
| 103 | * to compare against (and this data can get REALLY large with big archives). | |||
| 104 | * By being careful to read only when we have a good chance of a match, the | |||
| 105 | * performance loss is not measurable (and the size of the archive we can | |||
| 106 | * handle is greatly increased). | |||
| 107 | */ | |||
| 108 | typedef struct ftm { | |||
| 109 | off_t seek; /* location in scratch file */ | |||
| 110 | struct timespec mtim; /* files last modification time */ | |||
| 111 | struct ftm *fow; | |||
| 112 | int namelen; /* file name length */ | |||
| 113 | } FTM; | |||
| 114 | ||||
| 115 | /* | |||
| 116 | * Interactive rename table (-i flag), hashed by orig filename. | |||
| 117 | * We assume this will not be a large table as this mapping data can only be | |||
| 118 | * obtained through interactive input by the user. Nobody is going to type in | |||
| 119 | * changes for 500000 files? We use chaining to resolve collisions. | |||
| 120 | */ | |||
| 121 | ||||
| 122 | typedef struct namt { | |||
| 123 | char *oname; /* old name */ | |||
| 124 | char *nname; /* new name typed in by the user */ | |||
| 125 | struct namt *fow; | |||
| 126 | } NAMT; | |||
| 127 | ||||
| 128 | /* | |||
| 129 | * Unique device mapping tables. Some protocols (e.g. cpio) require that the | |||
| 130 | * <c_dev,c_ino> pair will uniquely identify a file in an archive unless they | |||
| 131 | * are links to the same file. Appending to archives can break this. For those | |||
| 132 | * protocols that have this requirement we map c_dev to a unique value not seen | |||
| 133 | * in the archive when we append. We also try to handle inode truncation with | |||
| 134 | * this table. (When the inode field in the archive header are too small, we | |||
| 135 | * remap the dev on writes to remove accidental collisions). | |||
| 136 | * | |||
| 137 | * The list is hashed by device number using chain collision resolution. Off of | |||
| 138 | * each DEVT are linked the various remaps for this device based on those bits | |||
| 139 | * in the inode which were truncated. For example if we are just remapping to | |||
| 140 | * avoid a device number during an update append, off the DEVT we would have | |||
| 141 | * only a single DLIST that has a truncation id of 0 (no inode bits were | |||
| 142 | * stripped for this device so far). When we spot inode truncation we create | |||
| 143 | * a new mapping based on the set of bits in the inode which were stripped off. | |||
| 144 | * so if the top four bits of the inode are stripped and they have a pattern of | |||
| 145 | * 0110...... (where . are those bits not truncated) we would have a mapping | |||
| 146 | * assigned for all inodes that has the same 0110.... pattern (with this dev | |||
| 147 | * number of course). This keeps the mapping sparse and should be able to store | |||
| 148 | * close to the limit of files which can be represented by the optimal | |||
| 149 | * combination of dev and inode bits, and without creating a fouled up archive. | |||
| 150 | * Note we also remap truncated devs in the same way (an exercise for the | |||
| 151 | * dedicated reader; always wanted to say that...:) | |||
| 152 | */ | |||
| 153 | ||||
| 154 | typedef struct devt { | |||
| 155 | dev_t dev; /* the orig device number we now have to map */ | |||
| 156 | struct devt *fow; /* new device map list */ | |||
| 157 | struct dlist *list; /* map list based on inode truncation bits */ | |||
| 158 | } DEVT; | |||
| 159 | ||||
| 160 | typedef struct dlist { | |||
| 161 | ino_t trunc_bits; /* truncation pattern for a specific map */ | |||
| 162 | dev_t dev; /* the new device id we use */ | |||
| 163 | struct dlist *fow; | |||
| 164 | } DLIST; | |||
| 165 | ||||
| 166 | /* | |||
| 167 | * ftree directory access time reset table. When we are done with a | |||
| 168 | * subtree we reset the access and mod time of the directory when the tflag is | |||
| 169 | * set. Not really explicitly specified in the pax spec, but easy and fast to | |||
| 170 | * do (and this may have even been intended in the spec, it is not clear). | |||
| 171 | * table is hashed by inode with chaining. | |||
| 172 | */ | |||
| 173 | ||||
| 174 | typedef struct atdir { | |||
| 175 | struct file_times ft; | |||
| 176 | struct atdir *fow; | |||
| 177 | } ATDIR; | |||
| 178 | ||||
| 179 | /* | |||
| 180 | * created directory time and mode storage entry. After pax is finished during | |||
| 181 | * extraction or copy, we must reset directory access modes and times that | |||
| 182 | * may have been modified after creation (they no longer have the specified | |||
| 183 | * times and/or modes). We must reset time in the reverse order of creation, | |||
| 184 | * because entries are added from the top of the file tree to the bottom. | |||
| 185 | * We MUST reset times from leaf to root (it will not work the other | |||
| 186 | * direction). | |||
| 187 | */ | |||
| 188 | ||||
| 189 | typedef struct dirdata { | |||
| 190 | struct file_times ft; | |||
| 191 | u_int16_t mode; /* file mode to restore */ | |||
| 192 | u_int16_t frc_mode; /* do we force mode settings? */ | |||
| 193 | } DIRDATA; | |||
| 194 | ||||
| 195 | static HRDLNK **ltab = NULL((void *)0); /* hard link table for detecting hard links */ | |||
| 196 | static FTM **ftab = NULL((void *)0); /* file time table for updating arch */ | |||
| 197 | static NAMT **ntab = NULL((void *)0); /* interactive rename storage table */ | |||
| 198 | #ifndef NOCPIO | |||
| 199 | static DEVT **dtab = NULL((void *)0); /* device/inode mapping tables */ | |||
| 200 | #endif | |||
| 201 | static ATDIR **atab = NULL((void *)0); /* file tree directory time reset table */ | |||
| 202 | static DIRDATA *dirp = NULL((void *)0); /* storage for setting created dir time/mode */ | |||
| 203 | static size_t dirsize; /* size of dirp table */ | |||
| 204 | static size_t dircnt = 0; /* entries in dir time/mode storage */ | |||
| 205 | static int ffd = -1; /* tmp file for file time table name storage */ | |||
| 206 | ||||
| 207 | /* | |||
| 208 | * hard link table routines | |||
| 209 | * | |||
| 210 | * The hard link table tries to detect hard links to files using the device and | |||
| 211 | * inode values. We do this when writing an archive, so we can tell the format | |||
| 212 | * write routine that this file is a hard link to another file. The format | |||
| 213 | * write routine then can store this file in whatever way it wants (as a hard | |||
| 214 | * link if the format supports that like tar, or ignore this info like cpio). | |||
| 215 | * (Actually a field in the format driver table tells us if the format wants | |||
| 216 | * hard link info. if not, we do not waste time looking for them). We also use | |||
| 217 | * the same table when reading an archive. In that situation, this table is | |||
| 218 | * used by the format read routine to detect hard links from stored dev and | |||
| 219 | * inode numbers (like cpio). This will allow pax to create a link when one | |||
| 220 | * can be detected by the archive format. | |||
| 221 | */ | |||
| 222 | ||||
| 223 | /* | |||
| 224 | * lnk_start | |||
| 225 | * Creates the hard link table. | |||
| 226 | * Return: | |||
| 227 | * 0 if created, -1 if failure | |||
| 228 | */ | |||
| 229 | ||||
| 230 | int | |||
| 231 | lnk_start(void) | |||
| 232 | { | |||
| 233 | if (ltab != NULL((void *)0)) | |||
| 234 | return(0); | |||
| 235 | if ((ltab = calloc(L_TAB_SZ2503, sizeof(HRDLNK *))) == NULL((void *)0)) { | |||
| 236 | paxwarn(1, "Cannot allocate memory for hard link table"); | |||
| 237 | return(-1); | |||
| 238 | } | |||
| 239 | return(0); | |||
| 240 | } | |||
| 241 | ||||
| 242 | /* | |||
| 243 | * chk_lnk() | |||
| 244 | * Looks up entry in hard link hash table. If found, it copies the name | |||
| 245 | * of the file it is linked to (we already saw that file) into ln_name. | |||
| 246 | * lnkcnt is decremented and if goes to 1 the node is deleted from the | |||
| 247 | * database. (We have seen all the links to this file). If not found, | |||
| 248 | * we add the file to the database if it has the potential for having | |||
| 249 | * hard links to other files we may process (it has a link count > 1) | |||
| 250 | * Return: | |||
| 251 | * if found returns 1; if not found returns 0; -1 on error | |||
| 252 | */ | |||
| 253 | ||||
| 254 | int | |||
| 255 | chk_lnk(ARCHD *arcn) | |||
| 256 | { | |||
| 257 | HRDLNK *pt; | |||
| 258 | HRDLNK **ppt; | |||
| 259 | u_int indx; | |||
| 260 | ||||
| 261 | if (ltab == NULL((void *)0)) | |||
| 262 | return(-1); | |||
| 263 | /* | |||
| 264 | * ignore those nodes that cannot have hard links | |||
| 265 | */ | |||
| 266 | if ((arcn->type == PAX_DIR1) || (arcn->sb.st_nlink <= 1)) | |||
| 267 | return(0); | |||
| 268 | ||||
| 269 | /* | |||
| 270 | * hash inode number and look for this file | |||
| 271 | */ | |||
| 272 | indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ2503; | |||
| 273 | if ((pt = ltab[indx]) != NULL((void *)0)) { | |||
| 274 | /* | |||
| 275 | * its hash chain in not empty, walk down looking for it | |||
| 276 | */ | |||
| 277 | ppt = &(ltab[indx]); | |||
| 278 | while (pt != NULL((void *)0)) { | |||
| 279 | if ((pt->ino == arcn->sb.st_ino) && | |||
| 280 | (pt->dev == arcn->sb.st_dev)) | |||
| 281 | break; | |||
| 282 | ppt = &(pt->fow); | |||
| 283 | pt = pt->fow; | |||
| 284 | } | |||
| 285 | ||||
| 286 | if (pt != NULL((void *)0)) { | |||
| 287 | /* | |||
| 288 | * found a link. set the node type and copy in the | |||
| 289 | * name of the file it is to link to. we need to | |||
| 290 | * handle hardlinks to regular files differently than | |||
| 291 | * other links. | |||
| 292 | */ | |||
| 293 | arcn->ln_nlen = strlcpy(arcn->ln_name, pt->name, | |||
| 294 | sizeof(arcn->ln_name)); | |||
| 295 | /* XXX truncate? */ | |||
| 296 | if ((size_t)arcn->nlen >= sizeof(arcn->name)) | |||
| 297 | arcn->nlen = sizeof(arcn->name) - 1; | |||
| 298 | if (arcn->type == PAX_REG4) | |||
| 299 | arcn->type = PAX_HRG9; | |||
| 300 | else | |||
| 301 | arcn->type = PAX_HLK8; | |||
| 302 | ||||
| 303 | /* | |||
| 304 | * if we have found all the links to this file, remove | |||
| 305 | * it from the database | |||
| 306 | */ | |||
| 307 | if (--pt->nlink <= 1) { | |||
| 308 | *ppt = pt->fow; | |||
| 309 | free(pt->name); | |||
| 310 | free(pt); | |||
| 311 | } | |||
| 312 | return(1); | |||
| 313 | } | |||
| 314 | } | |||
| 315 | ||||
| 316 | /* | |||
| 317 | * we never saw this file before. It has links so we add it to the | |||
| 318 | * front of this hash chain | |||
| 319 | */ | |||
| 320 | if ((pt = malloc(sizeof(HRDLNK))) != NULL((void *)0)) { | |||
| 321 | if ((pt->name = strdup(arcn->name)) != NULL((void *)0)) { | |||
| 322 | pt->dev = arcn->sb.st_dev; | |||
| 323 | pt->ino = arcn->sb.st_ino; | |||
| 324 | pt->nlink = arcn->sb.st_nlink; | |||
| 325 | pt->fow = ltab[indx]; | |||
| 326 | ltab[indx] = pt; | |||
| 327 | return(0); | |||
| 328 | } | |||
| 329 | free(pt); | |||
| 330 | } | |||
| 331 | ||||
| 332 | paxwarn(1, "Hard link table out of memory"); | |||
| 333 | return(-1); | |||
| 334 | } | |||
| 335 | ||||
| 336 | /* | |||
| 337 | * purg_lnk | |||
| 338 | * remove reference for a file that we may have added to the data base as | |||
| 339 | * a potential source for hard links. We ended up not using the file, so | |||
| 340 | * we do not want to accidently point another file at it later on. | |||
| 341 | */ | |||
| 342 | ||||
| 343 | void | |||
| 344 | purg_lnk(ARCHD *arcn) | |||
| 345 | { | |||
| 346 | HRDLNK *pt; | |||
| 347 | HRDLNK **ppt; | |||
| 348 | u_int indx; | |||
| 349 | ||||
| 350 | if (ltab == NULL((void *)0)) | |||
| 351 | return; | |||
| 352 | /* | |||
| 353 | * do not bother to look if it could not be in the database | |||
| 354 | */ | |||
| 355 | if ((arcn->sb.st_nlink <= 1) || (arcn->type == PAX_DIR1) || | |||
| 356 | PAX_IS_HARDLINK(arcn->type)((arcn->type) == 8 || (arcn->type) == 9)) | |||
| 357 | return; | |||
| 358 | ||||
| 359 | /* | |||
| 360 | * find the hash chain for this inode value, if empty return | |||
| 361 | */ | |||
| 362 | indx = ((unsigned)arcn->sb.st_ino) % L_TAB_SZ2503; | |||
| 363 | if ((pt = ltab[indx]) == NULL((void *)0)) | |||
| 364 | return; | |||
| 365 | ||||
| 366 | /* | |||
| 367 | * walk down the list looking for the inode/dev pair, unlink and | |||
| 368 | * free if found | |||
| 369 | */ | |||
| 370 | ppt = &(ltab[indx]); | |||
| 371 | while (pt != NULL((void *)0)) { | |||
| 372 | if ((pt->ino == arcn->sb.st_ino) && | |||
| 373 | (pt->dev == arcn->sb.st_dev)) | |||
| 374 | break; | |||
| 375 | ppt = &(pt->fow); | |||
| 376 | pt = pt->fow; | |||
| 377 | } | |||
| 378 | if (pt == NULL((void *)0)) | |||
| 379 | return; | |||
| 380 | ||||
| 381 | /* | |||
| 382 | * remove and free it | |||
| 383 | */ | |||
| 384 | *ppt = pt->fow; | |||
| 385 | free(pt->name); | |||
| 386 | free(pt); | |||
| 387 | } | |||
| 388 | ||||
| 389 | /* | |||
| 390 | * lnk_end() | |||
| 391 | * pull apart a existing link table so we can reuse it. We do this between | |||
| 392 | * read and write phases of append with update. (The format may have | |||
| 393 | * used the link table, and we need to start with a fresh table for the | |||
| 394 | * write phase | |||
| 395 | */ | |||
| 396 | ||||
| 397 | void | |||
| 398 | lnk_end(void) | |||
| 399 | { | |||
| 400 | int i; | |||
| 401 | HRDLNK *pt; | |||
| 402 | HRDLNK *ppt; | |||
| 403 | ||||
| 404 | if (ltab == NULL((void *)0)) | |||
| 405 | return; | |||
| 406 | ||||
| 407 | for (i = 0; i < L_TAB_SZ2503; ++i) { | |||
| 408 | if (ltab[i] == NULL((void *)0)) | |||
| 409 | continue; | |||
| 410 | pt = ltab[i]; | |||
| 411 | ltab[i] = NULL((void *)0); | |||
| 412 | ||||
| 413 | /* | |||
| 414 | * free up each entry on this chain | |||
| 415 | */ | |||
| 416 | while (pt != NULL((void *)0)) { | |||
| 417 | ppt = pt; | |||
| 418 | pt = ppt->fow; | |||
| 419 | free(ppt->name); | |||
| 420 | free(ppt); | |||
| 421 | } | |||
| 422 | } | |||
| 423 | } | |||
| 424 | ||||
| 425 | /* | |||
| 426 | * modification time table routines | |||
| 427 | * | |||
| 428 | * The modification time table keeps track of last modification times for all | |||
| 429 | * files stored in an archive during a write phase when -u is set. We only | |||
| 430 | * add a file to the archive if it is newer than a file with the same name | |||
| 431 | * already stored on the archive (if there is no other file with the same | |||
| 432 | * name on the archive it is added). This applies to writes and appends. | |||
| 433 | * An append with an -u must read the archive and store the modification time | |||
| 434 | * for every file on that archive before starting the write phase. It is clear | |||
| 435 | * that this is one HUGE database. To save memory space, the actual file names | |||
| 436 | * are stored in a scratch file and indexed by an in-memory hash table. The | |||
| 437 | * hash table is indexed by hashing the file path. The nodes in the table store | |||
| 438 | * the length of the filename and the lseek offset within the scratch file | |||
| 439 | * where the actual name is stored. Since there are never any deletions from | |||
| 440 | * this table, fragmentation of the scratch file is never a issue. Lookups | |||
| 441 | * seem to not exhibit any locality at all (files in the database are rarely | |||
| 442 | * looked up more than once...), so caching is just a waste of memory. The | |||
| 443 | * only limitation is the amount of scratch file space available to store the | |||
| 444 | * path names. | |||
| 445 | */ | |||
| 446 | ||||
| 447 | /* | |||
| 448 | * ftime_start() | |||
| 449 | * create the file time hash table and open for read/write the scratch | |||
| 450 | * file. (after created it is unlinked, so when we exit we leave | |||
| 451 | * no witnesses). | |||
| 452 | * Return: | |||
| 453 | * 0 if the table and file was created ok, -1 otherwise | |||
| 454 | */ | |||
| 455 | ||||
| 456 | int | |||
| 457 | ftime_start(void) | |||
| 458 | { | |||
| 459 | ||||
| 460 | if (ftab != NULL((void *)0)) | |||
| 461 | return(0); | |||
| 462 | if ((ftab = calloc(F_TAB_SZ50503, sizeof(FTM *))) == NULL((void *)0)) { | |||
| 463 | paxwarn(1, "Cannot allocate memory for file time table"); | |||
| 464 | return(-1); | |||
| 465 | } | |||
| 466 | ||||
| 467 | /* | |||
| 468 | * get random name and create temporary scratch file, unlink name | |||
| 469 | * so it will get removed on exit | |||
| 470 | */ | |||
| 471 | memcpy(tempbase, _TFILE_BASE"paxXXXXXXXXXX", sizeof(_TFILE_BASE"paxXXXXXXXXXX")); | |||
| 472 | if ((ffd = mkstemp(tempfile)) == -1) { | |||
| 473 | syswarn(1, errno(*__errno()), "Unable to create temporary file: %s", | |||
| 474 | tempfile); | |||
| 475 | return(-1); | |||
| 476 | } | |||
| 477 | (void)unlink(tempfile); | |||
| 478 | ||||
| 479 | return(0); | |||
| 480 | } | |||
| 481 | ||||
| 482 | /* | |||
| 483 | * chk_ftime() | |||
| 484 | * looks up entry in file time hash table. If not found, the file is | |||
| 485 | * added to the hash table and the file named stored in the scratch file. | |||
| 486 | * If a file with the same name is found, the file times are compared and | |||
| 487 | * the most recent file time is retained. If the new file was younger (or | |||
| 488 | * was not in the database) the new file is selected for storage. | |||
| 489 | * Return: | |||
| 490 | * 0 if file should be added to the archive, 1 if it should be skipped, | |||
| 491 | * -1 on error | |||
| 492 | */ | |||
| 493 | ||||
| 494 | int | |||
| 495 | chk_ftime(ARCHD *arcn) | |||
| 496 | { | |||
| 497 | FTM *pt; | |||
| 498 | int namelen; | |||
| 499 | u_int indx; | |||
| 500 | char ckname[PAXPATHLEN3072+1]; | |||
| 501 | ||||
| 502 | /* | |||
| 503 | * no info, go ahead and add to archive | |||
| 504 | */ | |||
| 505 | if (ftab == NULL((void *)0)) | |||
| 506 | return(0); | |||
| 507 | ||||
| 508 | /* | |||
| 509 | * hash the pathname and look up in table | |||
| 510 | */ | |||
| 511 | namelen = arcn->nlen; | |||
| 512 | indx = st_hash(arcn->name, namelen, F_TAB_SZ50503); | |||
| 513 | if ((pt = ftab[indx]) != NULL((void *)0)) { | |||
| 514 | /* | |||
| 515 | * the hash chain is not empty, walk down looking for match | |||
| 516 | * only read up the path names if the lengths match, speeds | |||
| 517 | * up the search a lot | |||
| 518 | */ | |||
| 519 | while (pt != NULL((void *)0)) { | |||
| 520 | if (pt->namelen == namelen) { | |||
| 521 | /* | |||
| 522 | * potential match, have to read the name | |||
| 523 | * from the scratch file. | |||
| 524 | */ | |||
| 525 | if (lseek(ffd,pt->seek,SEEK_SET0) != pt->seek) { | |||
| 526 | syswarn(1, errno(*__errno()), | |||
| 527 | "Failed ftime table seek"); | |||
| 528 | return(-1); | |||
| 529 | } | |||
| 530 | if (read(ffd, ckname, namelen) != namelen) { | |||
| 531 | syswarn(1, errno(*__errno()), | |||
| 532 | "Failed ftime table read"); | |||
| 533 | return(-1); | |||
| 534 | } | |||
| 535 | ||||
| 536 | /* | |||
| 537 | * if the names match, we are done | |||
| 538 | */ | |||
| 539 | if (!strncmp(ckname, arcn->name, namelen)) | |||
| 540 | break; | |||
| 541 | } | |||
| 542 | ||||
| 543 | /* | |||
| 544 | * try the next entry on the chain | |||
| 545 | */ | |||
| 546 | pt = pt->fow; | |||
| 547 | } | |||
| 548 | ||||
| 549 | if (pt != NULL((void *)0)) { | |||
| 550 | /* | |||
| 551 | * found the file, compare the times, save the newer | |||
| 552 | */ | |||
| 553 | if (timespeccmp(&arcn->sb.st_mtim, &pt->mtim, >)(((&arcn->sb.st_mtim)->tv_sec == (&pt->mtim) ->tv_sec) ? ((&arcn->sb.st_mtim)->tv_nsec > ( &pt->mtim)->tv_nsec) : ((&arcn->sb.st_mtim)-> tv_sec > (&pt->mtim)->tv_sec))) { | |||
| 554 | /* | |||
| 555 | * file is newer | |||
| 556 | */ | |||
| 557 | pt->mtim = arcn->sb.st_mtim; | |||
| 558 | return(0); | |||
| 559 | } | |||
| 560 | /* | |||
| 561 | * file is older | |||
| 562 | */ | |||
| 563 | return(1); | |||
| 564 | } | |||
| 565 | } | |||
| 566 | ||||
| 567 | /* | |||
| 568 | * not in table, add it | |||
| 569 | */ | |||
| 570 | if ((pt = malloc(sizeof(FTM))) != NULL((void *)0)) { | |||
| 571 | /* | |||
| 572 | * add the name at the end of the scratch file, saving the | |||
| 573 | * offset. add the file to the head of the hash chain | |||
| 574 | */ | |||
| 575 | if ((pt->seek = lseek(ffd, 0, SEEK_END2)) >= 0) { | |||
| 576 | if (write(ffd, arcn->name, namelen) == namelen) { | |||
| 577 | pt->mtim = arcn->sb.st_mtim; | |||
| 578 | pt->namelen = namelen; | |||
| 579 | pt->fow = ftab[indx]; | |||
| 580 | ftab[indx] = pt; | |||
| 581 | return(0); | |||
| 582 | } | |||
| 583 | syswarn(1, errno(*__errno()), "Failed write to file time table"); | |||
| 584 | } else | |||
| 585 | syswarn(1, errno(*__errno()), "Failed seek on file time table"); | |||
| 586 | } else | |||
| 587 | paxwarn(1, "File time table ran out of memory"); | |||
| 588 | ||||
| 589 | if (pt != NULL((void *)0)) | |||
| 590 | free(pt); | |||
| 591 | return(-1); | |||
| 592 | } | |||
| 593 | ||||
| 594 | /* | |||
| 595 | * escaping (absolute or w/"..") symlink table routines | |||
| 596 | * | |||
| 597 | * By default, an archive shouldn't be able extract to outside of the | |||
| 598 | * current directory. What should we do if the archive contains a symlink | |||
| 599 | * whose value is either absolute or contains ".." components? What we'll | |||
| 600 | * do is initially create the path as an empty file (to block attempts to | |||
| 601 | * reference _through_ it) and instead record its path and desired | |||
| 602 | * final value and mode. Then once all the other archive | |||
| 603 | * members are created (but before the pass to set timestamps on | |||
| 604 | * directories) we'll process those records, replacing the placeholder with | |||
| 605 | * the correct symlink and setting them to the correct mode, owner, group, | |||
| 606 | * and timestamps. | |||
| 607 | * | |||
| 608 | * Note: we also need to handle hardlinks to symlinks (barf) as well as | |||
| 609 | * hardlinks whose target is replaced by a later entry in the archive (barf^2). | |||
| 610 | * | |||
| 611 | * So we track things by dev+ino of the placeholder file, associating with | |||
| 612 | * that the value and mode of the final symlink and a list of paths that | |||
| 613 | * should all be hardlinks of that. We'll 'store' the symlink's desired | |||
| 614 | * timestamps, owner, and group by setting them on the placeholder file. | |||
| 615 | * | |||
| 616 | * The operations are: | |||
| 617 | * a) create an escaping symlink: create the placeholder file and add an entry | |||
| 618 | * for the new link | |||
| 619 | * b) create a hardlink: do the link. If the target turns out to be a | |||
| 620 | * zero-length file whose dev+ino are in the symlink table, then add this | |||
| 621 | * path to the list of names for that link | |||
| 622 | * c) perform deferred processing: for each entry, check each associated path: | |||
| 623 | * if it's a zero-length file with the correct dev+ino then recreate it as | |||
| 624 | * the specified symlink or hardlink to the first such | |||
| 625 | */ | |||
| 626 | ||||
| 627 | struct slpath { | |||
| 628 | char *sp_path; | |||
| 629 | struct slpath *sp_next; | |||
| 630 | }; | |||
| 631 | struct slinode { | |||
| 632 | ino_t sli_ino; | |||
| 633 | char *sli_value; | |||
| 634 | struct slpath sli_paths; | |||
| 635 | struct slinode *sli_fow; /* hash table chain */ | |||
| 636 | dev_t sli_dev; | |||
| 637 | mode_t sli_mode; | |||
| 638 | }; | |||
| 639 | ||||
| 640 | static struct slinode **slitab = NULL((void *)0); | |||
| 641 | ||||
| 642 | /* | |||
| 643 | * sltab_start() | |||
| 644 | * create the hash table | |||
| 645 | * Return: | |||
| 646 | * 0 if the table and file was created ok, -1 otherwise | |||
| 647 | */ | |||
| 648 | ||||
| 649 | int | |||
| 650 | sltab_start(void) | |||
| 651 | { | |||
| 652 | ||||
| 653 | if ((slitab = calloc(SL_TAB_SZ317, sizeof *slitab)) == NULL((void *)0)) { | |||
| 654 | syswarn(1, errno(*__errno()), "symlink table"); | |||
| 655 | return(-1); | |||
| 656 | } | |||
| 657 | ||||
| 658 | return(0); | |||
| 659 | } | |||
| 660 | ||||
| 661 | /* | |||
| 662 | * sltab_add_sym() | |||
| 663 | * Create the placeholder and tracking info for an escaping symlink. | |||
| 664 | * Return: | |||
| 665 | * 0 on success, -1 otherwise | |||
| 666 | */ | |||
| 667 | ||||
| 668 | int | |||
| 669 | sltab_add_sym(const char *path0, const char *value0, mode_t mode) | |||
| 670 | { | |||
| 671 | struct stat sb; | |||
| 672 | struct slinode *s; | |||
| 673 | struct slpath *p; | |||
| 674 | char *path, *value; | |||
| 675 | u_int indx; | |||
| 676 | int fd; | |||
| 677 | ||||
| 678 | /* create the placeholder */ | |||
| 679 | fd = open(path0, O_WRONLY0x0001 | O_CREAT0x0200 | O_EXCL0x0800 | O_CLOEXEC0x10000, 0600); | |||
| 680 | if (fd == -1) | |||
| 681 | return (-1); | |||
| 682 | if (fstat(fd, &sb) == -1) { | |||
| 683 | unlink(path0); | |||
| 684 | close(fd); | |||
| 685 | return (-1); | |||
| 686 | } | |||
| 687 | close(fd); | |||
| 688 | ||||
| 689 | if (havechd && *path0 != '/') { | |||
| 690 | if ((path = realpath(path0, NULL((void *)0))) == NULL((void *)0)) { | |||
| 691 | syswarn(1, errno(*__errno()), "Cannot canonicalize %s", path0); | |||
| 692 | unlink(path0); | |||
| 693 | return (-1); | |||
| 694 | } | |||
| 695 | } else if ((path = strdup(path0)) == NULL((void *)0)) { | |||
| 696 | syswarn(1, errno(*__errno()), "defered symlink path"); | |||
| 697 | unlink(path0); | |||
| 698 | return (-1); | |||
| 699 | } | |||
| 700 | if ((value = strdup(value0)) == NULL((void *)0)) { | |||
| 701 | syswarn(1, errno(*__errno()), "defered symlink value"); | |||
| 702 | unlink(path); | |||
| 703 | free(path); | |||
| 704 | return (-1); | |||
| 705 | } | |||
| 706 | ||||
| 707 | /* now check the hash table for conflicting entry */ | |||
| 708 | indx = (sb.st_ino ^ sb.st_dev) % SL_TAB_SZ317; | |||
| 709 | for (s = slitab[indx]; s != NULL((void *)0); s = s->sli_fow) { | |||
| 710 | if (s->sli_ino != sb.st_ino || s->sli_dev != sb.st_dev) | |||
| 711 | continue; | |||
| 712 | ||||
| 713 | /* | |||
| 714 | * One of our placeholders got removed behind our back and | |||
| 715 | * we've reused the inode. Weird, but clean up the mess. | |||
| 716 | */ | |||
| 717 | free(s->sli_value); | |||
| 718 | free(s->sli_paths.sp_path); | |||
| 719 | p = s->sli_paths.sp_next; | |||
| 720 | while (p != NULL((void *)0)) { | |||
| 721 | struct slpath *next_p = p->sp_next; | |||
| 722 | ||||
| 723 | free(p->sp_path); | |||
| 724 | free(p); | |||
| 725 | p = next_p; | |||
| 726 | } | |||
| 727 | goto set_value; | |||
| 728 | } | |||
| 729 | ||||
| 730 | /* Normal case: create a new node */ | |||
| 731 | if ((s = malloc(sizeof *s)) == NULL((void *)0)) { | |||
| 732 | syswarn(1, errno(*__errno()), "defered symlink"); | |||
| 733 | unlink(path); | |||
| 734 | free(path); | |||
| 735 | free(value); | |||
| 736 | return (-1); | |||
| 737 | } | |||
| 738 | s->sli_ino = sb.st_ino; | |||
| 739 | s->sli_dev = sb.st_dev; | |||
| 740 | s->sli_fow = slitab[indx]; | |||
| 741 | slitab[indx] = s; | |||
| 742 | ||||
| 743 | set_value: | |||
| 744 | s->sli_paths.sp_path = path; | |||
| 745 | s->sli_paths.sp_next = NULL((void *)0); | |||
| 746 | s->sli_value = value; | |||
| 747 | s->sli_mode = mode; | |||
| 748 | return (0); | |||
| 749 | } | |||
| 750 | ||||
| 751 | /* | |||
| 752 | * sltab_add_link() | |||
| 753 | * A hardlink was created; if it looks like a placeholder, handle the | |||
| 754 | * tracking. | |||
| 755 | * Return: | |||
| 756 | * 0 if things are ok, -1 if something went wrong | |||
| 757 | */ | |||
| 758 | ||||
| 759 | int | |||
| 760 | sltab_add_link(const char *path, const struct stat *sb) | |||
| 761 | { | |||
| 762 | struct slinode *s; | |||
| 763 | struct slpath *p; | |||
| 764 | u_int indx; | |||
| 765 | ||||
| 766 | if (!S_ISREG(sb->st_mode)((sb->st_mode & 0170000) == 0100000) || sb->st_size != 0) | |||
| 767 | return (1); | |||
| 768 | ||||
| 769 | /* find the hash table entry for this hardlink */ | |||
| 770 | indx = (sb->st_ino ^ sb->st_dev) % SL_TAB_SZ317; | |||
| 771 | for (s = slitab[indx]; s != NULL((void *)0); s = s->sli_fow) { | |||
| 772 | if (s->sli_ino != sb->st_ino || s->sli_dev != sb->st_dev) | |||
| 773 | continue; | |||
| 774 | ||||
| 775 | if ((p = malloc(sizeof *p)) == NULL((void *)0)) { | |||
| 776 | syswarn(1, errno(*__errno()), "deferred symlink hardlink"); | |||
| 777 | return (-1); | |||
| 778 | } | |||
| 779 | if (havechd && *path != '/') { | |||
| 780 | if ((p->sp_path = realpath(path, NULL((void *)0))) == NULL((void *)0)) { | |||
| 781 | syswarn(1, errno(*__errno()), "Cannot canonicalize %s", | |||
| 782 | path); | |||
| 783 | free(p); | |||
| 784 | return (-1); | |||
| 785 | } | |||
| 786 | } else if ((p->sp_path = strdup(path)) == NULL((void *)0)) { | |||
| 787 | syswarn(1, errno(*__errno()), "defered symlink hardlink path"); | |||
| 788 | free(p); | |||
| 789 | return (-1); | |||
| 790 | } | |||
| 791 | ||||
| 792 | /* link it in */ | |||
| 793 | p->sp_next = s->sli_paths.sp_next; | |||
| 794 | s->sli_paths.sp_next = p; | |||
| 795 | return (0); | |||
| 796 | } | |||
| 797 | ||||
| 798 | /* not found */ | |||
| 799 | return (1); | |||
| 800 | } | |||
| 801 | ||||
| 802 | ||||
| 803 | static int | |||
| 804 | sltab_process_one(struct slinode *s, struct slpath *p, const char *first, | |||
| 805 | int in_sig) | |||
| 806 | { | |||
| 807 | struct stat sb; | |||
| 808 | char *path = p->sp_path; | |||
| 809 | mode_t mode; | |||
| 810 | int err; | |||
| 811 | ||||
| 812 | /* | |||
| 813 | * is it the expected placeholder? This can fail legimately | |||
| 814 | * if the archive overwrote the link with another, later entry, | |||
| 815 | * so don't warn. | |||
| 816 | */ | |||
| 817 | if (stat(path, &sb) != 0 || !S_ISREG(sb.st_mode)((sb.st_mode & 0170000) == 0100000) || sb.st_size != 0 || | |||
| 818 | sb.st_ino != s->sli_ino || sb.st_dev != s->sli_dev) | |||
| 819 | return (0); | |||
| 820 | ||||
| 821 | if (unlink(path) && errno(*__errno()) != ENOENT2) { | |||
| 822 | if (!in_sig) | |||
| 823 | syswarn(1, errno(*__errno()), "deferred symlink removal"); | |||
| 824 | return (0); | |||
| 825 | } | |||
| 826 | ||||
| 827 | err = 0; | |||
| 828 | if (first != NULL((void *)0)) { | |||
| 829 | /* add another hardlink to the existing symlink */ | |||
| 830 | if (linkat(AT_FDCWD-100, first, AT_FDCWD-100, path, 0) == 0) | |||
| 831 | return (0); | |||
| 832 | ||||
| 833 | /* | |||
| 834 | * Couldn't hardlink the symlink for some reason, so we'll | |||
| 835 | * try creating it as its own symlink, but save the error | |||
| 836 | * for reporting if that fails. | |||
| 837 | */ | |||
| 838 | err = errno(*__errno()); | |||
| 839 | } | |||
| 840 | ||||
| 841 | if (symlink(s->sli_value, path)) { | |||
| 842 | if (!in_sig) { | |||
| 843 | const char *qualifier = ""; | |||
| 844 | if (err) | |||
| 845 | qualifier = " hardlink"; | |||
| 846 | else | |||
| 847 | err = errno(*__errno()); | |||
| 848 | ||||
| 849 | syswarn(1, err, "deferred symlink%s: %s", | |||
| 850 | qualifier, path); | |||
| 851 | } | |||
| 852 | return (0); | |||
| 853 | } | |||
| 854 | ||||
| 855 | /* success, so set the id, mode, and times */ | |||
| 856 | mode = s->sli_mode; | |||
| 857 | if (pids) { | |||
| 858 | /* if can't set the ids, force the set[ug]id bits off */ | |||
| 859 | if (set_ids(path, sb.st_uid, sb.st_gid)) | |||
| 860 | mode &= ~(SETBITS(0004000 | 0002000)); | |||
| 861 | } | |||
| 862 | ||||
| 863 | if (pmode) | |||
| 864 | set_pmode(path, mode); | |||
| 865 | ||||
| 866 | if (patime || pmtime) | |||
| 867 | set_ftime(path, &sb.st_mtim, &sb.st_atim, 0); | |||
| 868 | ||||
| 869 | /* | |||
| 870 | * If we tried to link to first but failed, then this new symlink | |||
| 871 | * might be a better one to try in the future. Guess from the errno. | |||
| 872 | */ | |||
| 873 | if (err == 0 || err == ENOENT2 || err == EMLINK31 || err == EOPNOTSUPP45) | |||
| 874 | return (1); | |||
| 875 | return (0); | |||
| 876 | } | |||
| 877 | ||||
| 878 | /* | |||
| 879 | * sltab_process() | |||
| 880 | * Do all the delayed process for escape symlinks | |||
| 881 | */ | |||
| 882 | ||||
| 883 | void | |||
| 884 | sltab_process(int in_sig) | |||
| 885 | { | |||
| 886 | struct slinode *s; | |||
| 887 | struct slpath *p; | |||
| 888 | char *first; | |||
| 889 | u_int indx; | |||
| 890 | ||||
| 891 | if (slitab == NULL((void *)0)) | |||
| 892 | return; | |||
| 893 | ||||
| 894 | /* walk across the entire hash table */ | |||
| 895 | for (indx = 0; indx < SL_TAB_SZ317; indx++) { | |||
| 896 | while ((s = slitab[indx]) != NULL((void *)0)) { | |||
| 897 | /* pop this entry */ | |||
| 898 | slitab[indx] = s->sli_fow; | |||
| 899 | ||||
| 900 | first = NULL((void *)0); | |||
| 901 | p = &s->sli_paths; | |||
| 902 | while (1) { | |||
| 903 | struct slpath *next_p; | |||
| 904 | ||||
| 905 | if (sltab_process_one(s, p, first, in_sig)) { | |||
| 906 | if (!in_sig) | |||
| 907 | free(first); | |||
| 908 | first = p->sp_path; | |||
| 909 | } else if (!in_sig) | |||
| 910 | free(p->sp_path); | |||
| 911 | ||||
| 912 | if ((next_p = p->sp_next) == NULL((void *)0)) | |||
| 913 | break; | |||
| 914 | *p = *next_p; | |||
| 915 | if (!in_sig) | |||
| 916 | free(next_p); | |||
| 917 | } | |||
| 918 | if (!in_sig) { | |||
| 919 | free(first); | |||
| 920 | free(s->sli_value); | |||
| 921 | free(s); | |||
| 922 | } | |||
| 923 | } | |||
| 924 | } | |||
| 925 | if (!in_sig) | |||
| 926 | free(slitab); | |||
| 927 | slitab = NULL((void *)0); | |||
| 928 | } | |||
| 929 | ||||
| 930 | ||||
| 931 | /* | |||
| 932 | * Interactive rename table routines | |||
| 933 | * | |||
| 934 | * The interactive rename table keeps track of the new names that the user | |||
| 935 | * assigns to files from tty input. Since this map is unique for each file | |||
| 936 | * we must store it in case there is a reference to the file later in archive | |||
| 937 | * (a link). Otherwise we will be unable to find the file we know was | |||
| 938 | * extracted. The remapping of these files is stored in a memory based hash | |||
| 939 | * table (it is assumed since input must come from /dev/tty, it is unlikely to | |||
| 940 | * be a very large table). | |||
| 941 | */ | |||
| 942 | ||||
| 943 | /* | |||
| 944 | * name_start() | |||
| 945 | * create the interactive rename table | |||
| 946 | * Return: | |||
| 947 | * 0 if successful, -1 otherwise | |||
| 948 | */ | |||
| 949 | ||||
| 950 | int | |||
| 951 | name_start(void) | |||
| 952 | { | |||
| 953 | if (ntab != NULL((void *)0)) | |||
| 954 | return(0); | |||
| 955 | if ((ntab = calloc(N_TAB_SZ541, sizeof(NAMT *))) == NULL((void *)0)) { | |||
| 956 | paxwarn(1, "Cannot allocate memory for interactive rename table"); | |||
| 957 | return(-1); | |||
| 958 | } | |||
| 959 | return(0); | |||
| 960 | } | |||
| 961 | ||||
| 962 | /* | |||
| 963 | * add_name() | |||
| 964 | * add the new name to old name mapping just created by the user. | |||
| 965 | * If an old name mapping is found (there may be duplicate names on an | |||
| 966 | * archive) only the most recent is kept. | |||
| 967 | * Return: | |||
| 968 | * 0 if added, -1 otherwise | |||
| 969 | */ | |||
| 970 | ||||
| 971 | int | |||
| 972 | add_name(char *oname, int onamelen, char *nname) | |||
| 973 | { | |||
| 974 | NAMT *pt; | |||
| 975 | u_int indx; | |||
| 976 | ||||
| 977 | if (ntab == NULL((void *)0)) { | |||
| 978 | /* | |||
| 979 | * should never happen | |||
| 980 | */ | |||
| 981 | paxwarn(0, "No interactive rename table, links may fail"); | |||
| 982 | return(0); | |||
| 983 | } | |||
| 984 | ||||
| 985 | /* | |||
| 986 | * look to see if we have already mapped this file, if so we | |||
| 987 | * will update it | |||
| 988 | */ | |||
| 989 | indx = st_hash(oname, onamelen, N_TAB_SZ541); | |||
| 990 | if ((pt = ntab[indx]) != NULL((void *)0)) { | |||
| 991 | /* | |||
| 992 | * look down the has chain for the file | |||
| 993 | */ | |||
| 994 | while ((pt != NULL((void *)0)) && (strcmp(oname, pt->oname) != 0)) | |||
| 995 | pt = pt->fow; | |||
| 996 | ||||
| 997 | if (pt != NULL((void *)0)) { | |||
| 998 | /* | |||
| 999 | * found an old mapping, replace it with the new one | |||
| 1000 | * the user just input (if it is different) | |||
| 1001 | */ | |||
| 1002 | if (strcmp(nname, pt->nname) == 0) | |||
| 1003 | return(0); | |||
| 1004 | ||||
| 1005 | free(pt->nname); | |||
| 1006 | if ((pt->nname = strdup(nname)) == NULL((void *)0)) { | |||
| 1007 | paxwarn(1, "Cannot update rename table"); | |||
| 1008 | return(-1); | |||
| 1009 | } | |||
| 1010 | return(0); | |||
| 1011 | } | |||
| 1012 | } | |||
| 1013 | ||||
| 1014 | /* | |||
| 1015 | * this is a new mapping, add it to the table | |||
| 1016 | */ | |||
| 1017 | if ((pt = malloc(sizeof(NAMT))) != NULL((void *)0)) { | |||
| 1018 | if ((pt->oname = strdup(oname)) != NULL((void *)0)) { | |||
| 1019 | if ((pt->nname = strdup(nname)) != NULL((void *)0)) { | |||
| 1020 | pt->fow = ntab[indx]; | |||
| 1021 | ntab[indx] = pt; | |||
| 1022 | return(0); | |||
| 1023 | } | |||
| 1024 | free(pt->oname); | |||
| 1025 | } | |||
| 1026 | free(pt); | |||
| 1027 | } | |||
| 1028 | paxwarn(1, "Interactive rename table out of memory"); | |||
| 1029 | return(-1); | |||
| 1030 | } | |||
| 1031 | ||||
| 1032 | /* | |||
| 1033 | * sub_name() | |||
| 1034 | * look up a link name to see if it points at a file that has been | |||
| 1035 | * remapped by the user. If found, the link is adjusted to contain the | |||
| 1036 | * new name (oname is the link to name) | |||
| 1037 | */ | |||
| 1038 | ||||
| 1039 | void | |||
| 1040 | sub_name(char *oname, int *onamelen, int onamesize) | |||
| 1041 | { | |||
| 1042 | NAMT *pt; | |||
| 1043 | u_int indx; | |||
| 1044 | ||||
| 1045 | if (ntab == NULL((void *)0)) | |||
| ||||
| 1046 | return; | |||
| 1047 | /* | |||
| 1048 | * look the name up in the hash table | |||
| 1049 | */ | |||
| 1050 | indx = st_hash(oname, *onamelen, N_TAB_SZ541); | |||
| 1051 | if ((pt = ntab[indx]) == NULL((void *)0)) | |||
| 1052 | return; | |||
| 1053 | ||||
| 1054 | while (pt != NULL((void *)0)) { | |||
| 1055 | /* | |||
| 1056 | * walk down the hash chain looking for a match | |||
| 1057 | */ | |||
| 1058 | if (strcmp(oname, pt->oname) == 0) { | |||
| 1059 | /* | |||
| 1060 | * found it, replace it with the new name | |||
| 1061 | * and return (we know that oname has enough space) | |||
| 1062 | */ | |||
| 1063 | *onamelen = strlcpy(oname, pt->nname, onamesize); | |||
| 1064 | if (*onamelen >= onamesize) | |||
| 1065 | *onamelen = onamesize - 1; /* XXX truncate? */ | |||
| 1066 | return; | |||
| 1067 | } | |||
| 1068 | pt = pt->fow; | |||
| 1069 | } | |||
| 1070 | ||||
| 1071 | /* | |||
| 1072 | * no match, just return | |||
| 1073 | */ | |||
| 1074 | } | |||
| 1075 | ||||
| 1076 | #ifndef NOCPIO | |||
| 1077 | /* | |||
| 1078 | * device/inode mapping table routines | |||
| 1079 | * (used with formats that store device and inodes fields) | |||
| 1080 | * | |||
| 1081 | * device/inode mapping tables remap the device field in a archive header. The | |||
| 1082 | * device/inode fields are used to determine when files are hard links to each | |||
| 1083 | * other. However these values have very little meaning outside of that. This | |||
| 1084 | * database is used to solve one of two different problems. | |||
| 1085 | * | |||
| 1086 | * 1) when files are appended to an archive, while the new files may have hard | |||
| 1087 | * links to each other, you cannot determine if they have hard links to any | |||
| 1088 | * file already stored on the archive from a prior run of pax. We must assume | |||
| 1089 | * that these inode/device pairs are unique only within a SINGLE run of pax | |||
| 1090 | * (which adds a set of files to an archive). So we have to make sure the | |||
| 1091 | * inode/dev pairs we add each time are always unique. We do this by observing | |||
| 1092 | * while the inode field is very dense, the use of the dev field is fairly | |||
| 1093 | * sparse. Within each run of pax, we remap any device number of a new archive | |||
| 1094 | * member that has a device number used in a prior run and already stored in a | |||
| 1095 | * file on the archive. During the read phase of the append, we store the | |||
| 1096 | * device numbers used and mark them to not be used by any file during the | |||
| 1097 | * write phase. If during write we go to use one of those old device numbers, | |||
| 1098 | * we remap it to a new value. | |||
| 1099 | * | |||
| 1100 | * 2) Often the fields in the archive header used to store these values are | |||
| 1101 | * too small to store the entire value. The result is an inode or device value | |||
| 1102 | * which can be truncated. This really can foul up an archive. With truncation | |||
| 1103 | * we end up creating links between files that are really not links (after | |||
| 1104 | * truncation the inodes are the same value). We address that by detecting | |||
| 1105 | * truncation and forcing a remap of the device field to split truncated | |||
| 1106 | * inodes away from each other. Each truncation creates a pattern of bits that | |||
| 1107 | * are removed. We use this pattern of truncated bits to partition the inodes | |||
| 1108 | * on a single device to many different devices (each one represented by the | |||
| 1109 | * truncated bit pattern). All inodes on the same device that have the same | |||
| 1110 | * truncation pattern are mapped to the same new device. Two inodes that | |||
| 1111 | * truncate to the same value clearly will always have different truncation | |||
| 1112 | * bit patterns, so they will be split from away each other. When we spot | |||
| 1113 | * device truncation we remap the device number to a non truncated value. | |||
| 1114 | * (for more info see table.h for the data structures involved). | |||
| 1115 | */ | |||
| 1116 | ||||
| 1117 | static DEVT *chk_dev(dev_t, int); | |||
| 1118 | ||||
| 1119 | /* | |||
| 1120 | * dev_start() | |||
| 1121 | * create the device mapping table | |||
| 1122 | * Return: | |||
| 1123 | * 0 if successful, -1 otherwise | |||
| 1124 | */ | |||
| 1125 | ||||
| 1126 | int | |||
| 1127 | dev_start(void) | |||
| 1128 | { | |||
| 1129 | if (dtab != NULL((void *)0)) | |||
| 1130 | return(0); | |||
| 1131 | if ((dtab = calloc(D_TAB_SZ317, sizeof(DEVT *))) == NULL((void *)0)) { | |||
| 1132 | paxwarn(1, "Cannot allocate memory for device mapping table"); | |||
| 1133 | return(-1); | |||
| 1134 | } | |||
| 1135 | return(0); | |||
| 1136 | } | |||
| 1137 | ||||
| 1138 | /* | |||
| 1139 | * add_dev() | |||
| 1140 | * add a device number to the table. this will force the device to be | |||
| 1141 | * remapped to a new value if it be used during a write phase. This | |||
| 1142 | * function is called during the read phase of an append to prohibit the | |||
| 1143 | * use of any device number already in the archive. | |||
| 1144 | * Return: | |||
| 1145 | * 0 if added ok, -1 otherwise | |||
| 1146 | */ | |||
| 1147 | ||||
| 1148 | int | |||
| 1149 | add_dev(ARCHD *arcn) | |||
| 1150 | { | |||
| 1151 | if (chk_dev(arcn->sb.st_dev, 1) == NULL((void *)0)) | |||
| 1152 | return(-1); | |||
| 1153 | return(0); | |||
| 1154 | } | |||
| 1155 | ||||
| 1156 | /* | |||
| 1157 | * chk_dev() | |||
| 1158 | * check for a device value in the device table. If not found and the add | |||
| 1159 | * flag is set, it is added. This does NOT assign any mapping values, just | |||
| 1160 | * adds the device number as one that need to be remapped. If this device | |||
| 1161 | * is already mapped, just return with a pointer to that entry. | |||
| 1162 | * Return: | |||
| 1163 | * pointer to the entry for this device in the device map table. Null | |||
| 1164 | * if the add flag is not set and the device is not in the table (it is | |||
| 1165 | * not been seen yet). If add is set and the device cannot be added, null | |||
| 1166 | * is returned (indicates an error). | |||
| 1167 | */ | |||
| 1168 | ||||
| 1169 | static DEVT * | |||
| 1170 | chk_dev(dev_t dev, int add) | |||
| 1171 | { | |||
| 1172 | DEVT *pt; | |||
| 1173 | u_int indx; | |||
| 1174 | ||||
| 1175 | if (dtab == NULL((void *)0)) | |||
| 1176 | return(NULL((void *)0)); | |||
| 1177 | /* | |||
| 1178 | * look to see if this device is already in the table | |||
| 1179 | */ | |||
| 1180 | indx = ((unsigned)dev) % D_TAB_SZ317; | |||
| 1181 | if ((pt = dtab[indx]) != NULL((void *)0)) { | |||
| 1182 | while ((pt != NULL((void *)0)) && (pt->dev != dev)) | |||
| 1183 | pt = pt->fow; | |||
| 1184 | ||||
| 1185 | /* | |||
| 1186 | * found it, return a pointer to it | |||
| 1187 | */ | |||
| 1188 | if (pt != NULL((void *)0)) | |||
| 1189 | return(pt); | |||
| 1190 | } | |||
| 1191 | ||||
| 1192 | /* | |||
| 1193 | * not in table, we add it only if told to as this may just be a check | |||
| 1194 | * to see if a device number is being used. | |||
| 1195 | */ | |||
| 1196 | if (add == 0) | |||
| 1197 | return(NULL((void *)0)); | |||
| 1198 | ||||
| 1199 | /* | |||
| 1200 | * allocate a node for this device and add it to the front of the hash | |||
| 1201 | * chain. Note we do not assign remaps values here, so the pt->list | |||
| 1202 | * list must be NULL. | |||
| 1203 | */ | |||
| 1204 | if ((pt = malloc(sizeof(DEVT))) == NULL((void *)0)) { | |||
| 1205 | paxwarn(1, "Device map table out of memory"); | |||
| 1206 | return(NULL((void *)0)); | |||
| 1207 | } | |||
| 1208 | pt->dev = dev; | |||
| 1209 | pt->list = NULL((void *)0); | |||
| 1210 | pt->fow = dtab[indx]; | |||
| 1211 | dtab[indx] = pt; | |||
| 1212 | return(pt); | |||
| 1213 | } | |||
| 1214 | /* | |||
| 1215 | * map_dev() | |||
| 1216 | * given an inode and device storage mask (the mask has a 1 for each bit | |||
| 1217 | * the archive format is able to store in a header), we check for inode | |||
| 1218 | * and device truncation and remap the device as required. Device mapping | |||
| 1219 | * can also occur when during the read phase of append a device number was | |||
| 1220 | * seen (and was marked as do not use during the write phase). WE ASSUME | |||
| 1221 | * that unsigned longs are the same size or bigger than the fields used | |||
| 1222 | * for ino_t and dev_t. If not the types will have to be changed. | |||
| 1223 | * Return: | |||
| 1224 | * 0 if all ok, -1 otherwise. | |||
| 1225 | */ | |||
| 1226 | ||||
| 1227 | int | |||
| 1228 | map_dev(ARCHD *arcn, u_long dev_mask, u_long ino_mask) | |||
| 1229 | { | |||
| 1230 | DEVT *pt; | |||
| 1231 | DLIST *dpt; | |||
| 1232 | static dev_t lastdev = 0; /* next device number to try */ | |||
| 1233 | int trc_ino = 0; | |||
| 1234 | int trc_dev = 0; | |||
| 1235 | ino_t trunc_bits = 0; | |||
| 1236 | ino_t nino; | |||
| 1237 | ||||
| 1238 | if (dtab == NULL((void *)0)) | |||
| 1239 | return(0); | |||
| 1240 | /* | |||
| 1241 | * check for device and inode truncation, and extract the truncated | |||
| 1242 | * bit pattern. | |||
| 1243 | */ | |||
| 1244 | if ((arcn->sb.st_dev & (dev_t)dev_mask) != arcn->sb.st_dev) | |||
| 1245 | ++trc_dev; | |||
| 1246 | if ((nino = arcn->sb.st_ino & (ino_t)ino_mask) != arcn->sb.st_ino) { | |||
| 1247 | ++trc_ino; | |||
| 1248 | trunc_bits = arcn->sb.st_ino & (ino_t)(~ino_mask); | |||
| 1249 | } | |||
| 1250 | ||||
| 1251 | /* | |||
| 1252 | * see if this device is already being mapped, look up the device | |||
| 1253 | * then find the truncation bit pattern which applies | |||
| 1254 | */ | |||
| 1255 | if ((pt = chk_dev(arcn->sb.st_dev, 0)) != NULL((void *)0)) { | |||
| 1256 | /* | |||
| 1257 | * this device is already marked to be remapped | |||
| 1258 | */ | |||
| 1259 | for (dpt = pt->list; dpt != NULL((void *)0); dpt = dpt->fow) | |||
| 1260 | if (dpt->trunc_bits == trunc_bits) | |||
| 1261 | break; | |||
| 1262 | ||||
| 1263 | if (dpt != NULL((void *)0)) { | |||
| 1264 | /* | |||
| 1265 | * we are being remapped for this device and pattern | |||
| 1266 | * change the device number to be stored and return | |||
| 1267 | */ | |||
| 1268 | arcn->sb.st_dev = dpt->dev; | |||
| 1269 | arcn->sb.st_ino = nino; | |||
| 1270 | return(0); | |||
| 1271 | } | |||
| 1272 | } else { | |||
| 1273 | /* | |||
| 1274 | * this device is not being remapped YET. if we do not have any | |||
| 1275 | * form of truncation, we do not need a remap | |||
| 1276 | */ | |||
| 1277 | if (!trc_ino && !trc_dev) | |||
| 1278 | return(0); | |||
| 1279 | ||||
| 1280 | /* | |||
| 1281 | * we have truncation, have to add this as a device to remap | |||
| 1282 | */ | |||
| 1283 | if ((pt = chk_dev(arcn->sb.st_dev, 1)) == NULL((void *)0)) | |||
| 1284 | goto bad; | |||
| 1285 | ||||
| 1286 | /* | |||
| 1287 | * if we just have a truncated inode, we have to make sure that | |||
| 1288 | * all future inodes that do not truncate (they have the | |||
| 1289 | * truncation pattern of all 0's) continue to map to the same | |||
| 1290 | * device number. We probably have already written inodes with | |||
| 1291 | * this device number to the archive with the truncation | |||
| 1292 | * pattern of all 0's. So we add the mapping for all 0's to the | |||
| 1293 | * same device number. | |||
| 1294 | */ | |||
| 1295 | if (!trc_dev && (trunc_bits != 0)) { | |||
| 1296 | if ((dpt = malloc(sizeof(DLIST))) == NULL((void *)0)) | |||
| 1297 | goto bad; | |||
| 1298 | dpt->trunc_bits = 0; | |||
| 1299 | dpt->dev = arcn->sb.st_dev; | |||
| 1300 | dpt->fow = pt->list; | |||
| 1301 | pt->list = dpt; | |||
| 1302 | } | |||
| 1303 | } | |||
| 1304 | ||||
| 1305 | /* | |||
| 1306 | * look for a device number not being used. We must watch for wrap | |||
| 1307 | * around on lastdev (so we do not get stuck looking forever!) | |||
| 1308 | */ | |||
| 1309 | while (++lastdev > 0) { | |||
| 1310 | if (chk_dev(lastdev, 0) != NULL((void *)0)) | |||
| 1311 | continue; | |||
| 1312 | /* | |||
| 1313 | * found an unused value. If we have reached truncation point | |||
| 1314 | * for this format we are hosed, so we give up. Otherwise we | |||
| 1315 | * mark it as being used. | |||
| 1316 | */ | |||
| 1317 | if (((lastdev & ((dev_t)dev_mask)) != lastdev) || | |||
| 1318 | (chk_dev(lastdev, 1) == NULL((void *)0))) | |||
| 1319 | goto bad; | |||
| 1320 | break; | |||
| 1321 | } | |||
| 1322 | ||||
| 1323 | if ((lastdev <= 0) || ((dpt = malloc(sizeof(DLIST))) == NULL((void *)0))) | |||
| 1324 | goto bad; | |||
| 1325 | ||||
| 1326 | /* | |||
| 1327 | * got a new device number, store it under this truncation pattern. | |||
| 1328 | * change the device number this file is being stored with. | |||
| 1329 | */ | |||
| 1330 | dpt->trunc_bits = trunc_bits; | |||
| 1331 | dpt->dev = lastdev; | |||
| 1332 | dpt->fow = pt->list; | |||
| 1333 | pt->list = dpt; | |||
| 1334 | arcn->sb.st_dev = lastdev; | |||
| 1335 | arcn->sb.st_ino = nino; | |||
| 1336 | return(0); | |||
| 1337 | ||||
| 1338 | bad: | |||
| 1339 | paxwarn(1, "Unable to fix truncated inode/device field when storing %s", | |||
| 1340 | arcn->name); | |||
| 1341 | paxwarn(0, "Archive may create improper hard links when extracted"); | |||
| 1342 | return(0); | |||
| 1343 | } | |||
| 1344 | #endif /* NOCPIO */ | |||
| 1345 | ||||
| 1346 | /* | |||
| 1347 | * directory access/mod time reset table routines (for directories READ by pax) | |||
| 1348 | * | |||
| 1349 | * The pax -t flag requires that access times of archive files be the same | |||
| 1350 | * before being read by pax. For regular files, access time is restored after | |||
| 1351 | * the file has been copied. This database provides the same functionality for | |||
| 1352 | * directories read during file tree traversal. Restoring directory access time | |||
| 1353 | * is more complex than files since directories may be read several times until | |||
| 1354 | * all the descendants in their subtree are visited by fts. Directory access | |||
| 1355 | * and modification times are stored during the fts pre-order visit (done | |||
| 1356 | * before any descendants in the subtree are visited) and restored after the | |||
| 1357 | * fts post-order visit (after all the descendants have been visited). In the | |||
| 1358 | * case of premature exit from a subtree (like from the effects of -n), any | |||
| 1359 | * directory entries left in this database are reset during final cleanup | |||
| 1360 | * operations of pax. Entries are hashed by inode number for fast lookup. | |||
| 1361 | */ | |||
| 1362 | ||||
| 1363 | /* | |||
| 1364 | * atdir_start() | |||
| 1365 | * create the directory access time database for directories READ by pax. | |||
| 1366 | * Return: | |||
| 1367 | * 0 is created ok, -1 otherwise. | |||
| 1368 | */ | |||
| 1369 | ||||
| 1370 | int | |||
| 1371 | atdir_start(void) | |||
| 1372 | { | |||
| 1373 | if (atab != NULL((void *)0)) | |||
| 1374 | return(0); | |||
| 1375 | if ((atab = calloc(A_TAB_SZ317, sizeof(ATDIR *))) == NULL((void *)0)) { | |||
| 1376 | paxwarn(1,"Cannot allocate space for directory access time table"); | |||
| 1377 | return(-1); | |||
| 1378 | } | |||
| 1379 | return(0); | |||
| 1380 | } | |||
| 1381 | ||||
| 1382 | ||||
| 1383 | /* | |||
| 1384 | * atdir_end() | |||
| 1385 | * walk through the directory access time table and reset the access time | |||
| 1386 | * of any directory who still has an entry left in the database. These | |||
| 1387 | * entries are for directories READ by pax | |||
| 1388 | */ | |||
| 1389 | ||||
| 1390 | void | |||
| 1391 | atdir_end(void) | |||
| 1392 | { | |||
| 1393 | ATDIR *pt; | |||
| 1394 | int i; | |||
| 1395 | ||||
| 1396 | if (atab == NULL((void *)0)) | |||
| 1397 | return; | |||
| 1398 | /* | |||
| 1399 | * for each non-empty hash table entry reset all the directories | |||
| 1400 | * chained there. | |||
| 1401 | */ | |||
| 1402 | for (i = 0; i < A_TAB_SZ317; ++i) { | |||
| 1403 | if ((pt = atab[i]) == NULL((void *)0)) | |||
| 1404 | continue; | |||
| 1405 | /* | |||
| 1406 | * remember to force the times, set_ftime() looks at pmtime | |||
| 1407 | * and patime, which only applies to things CREATED by pax, | |||
| 1408 | * not read by pax. Read time reset is controlled by -t. | |||
| 1409 | */ | |||
| 1410 | for (; pt != NULL((void *)0); pt = pt->fow) | |||
| 1411 | set_attr(&pt->ft, 1, 0, 0, 0); | |||
| 1412 | } | |||
| 1413 | } | |||
| 1414 | ||||
| 1415 | /* | |||
| 1416 | * add_atdir() | |||
| 1417 | * add a directory to the directory access time table. Table is hashed | |||
| 1418 | * and chained by inode number. This is for directories READ by pax | |||
| 1419 | */ | |||
| 1420 | ||||
| 1421 | void | |||
| 1422 | add_atdir(char *fname, dev_t dev, ino_t ino, const struct timespec *mtimp, | |||
| 1423 | const struct timespec *atimp) | |||
| 1424 | { | |||
| 1425 | ATDIR *pt; | |||
| 1426 | sigset_t allsigs, savedsigs; | |||
| 1427 | u_int indx; | |||
| 1428 | ||||
| 1429 | if (atab == NULL((void *)0)) | |||
| 1430 | return; | |||
| 1431 | ||||
| 1432 | /* | |||
| 1433 | * make sure this directory is not already in the table, if so just | |||
| 1434 | * return (the older entry always has the correct time). The only | |||
| 1435 | * way this will happen is when the same subtree can be traversed by | |||
| 1436 | * different args to pax and the -n option is aborting fts out of a | |||
| 1437 | * subtree before all the post-order visits have been made. | |||
| 1438 | */ | |||
| 1439 | indx = ((unsigned)ino) % A_TAB_SZ317; | |||
| 1440 | if ((pt = atab[indx]) != NULL((void *)0)) { | |||
| 1441 | while (pt != NULL((void *)0)) { | |||
| 1442 | if ((pt->ft.ft_ino == ino) && (pt->ft.ft_dev == dev)) | |||
| 1443 | break; | |||
| 1444 | pt = pt->fow; | |||
| 1445 | } | |||
| 1446 | ||||
| 1447 | /* | |||
| 1448 | * oops, already there. Leave it alone. | |||
| 1449 | */ | |||
| 1450 | if (pt != NULL((void *)0)) | |||
| 1451 | return; | |||
| 1452 | } | |||
| 1453 | ||||
| 1454 | /* | |||
| 1455 | * add it to the front of the hash chain | |||
| 1456 | */ | |||
| 1457 | sigfillset(&allsigs); | |||
| 1458 | sigprocmask(SIG_BLOCK1, &allsigs, &savedsigs); | |||
| 1459 | if ((pt = malloc(sizeof *pt)) != NULL((void *)0)) { | |||
| 1460 | if ((pt->ft.ft_name = strdup(fname)) != NULL((void *)0)) { | |||
| 1461 | pt->ft.ft_dev = dev; | |||
| 1462 | pt->ft.ft_ino = ino; | |||
| 1463 | pt->ft.ft_mtim = *mtimp; | |||
| 1464 | pt->ft.ft_atim = *atimp; | |||
| 1465 | pt->fow = atab[indx]; | |||
| 1466 | atab[indx] = pt; | |||
| 1467 | sigprocmask(SIG_SETMASK3, &savedsigs, NULL((void *)0)); | |||
| 1468 | return; | |||
| 1469 | } | |||
| 1470 | free(pt); | |||
| 1471 | } | |||
| 1472 | ||||
| 1473 | sigprocmask(SIG_SETMASK3, &savedsigs, NULL((void *)0)); | |||
| 1474 | paxwarn(1, "Directory access time reset table ran out of memory"); | |||
| 1475 | } | |||
| 1476 | ||||
| 1477 | /* | |||
| 1478 | * get_atdir() | |||
| 1479 | * look up a directory by inode and device number to obtain the access | |||
| 1480 | * and modification time you want to set to. If found, the modification | |||
| 1481 | * and access time parameters are set and the entry is removed from the | |||
| 1482 | * table (as it is no longer needed). These are for directories READ by | |||
| 1483 | * pax | |||
| 1484 | * Return: | |||
| 1485 | * 0 if found, -1 if not found. | |||
| 1486 | */ | |||
| 1487 | ||||
| 1488 | int | |||
| 1489 | do_atdir(const char *name, dev_t dev, ino_t ino) | |||
| 1490 | { | |||
| 1491 | ATDIR *pt; | |||
| 1492 | ATDIR **ppt; | |||
| 1493 | sigset_t allsigs, savedsigs; | |||
| 1494 | u_int indx; | |||
| 1495 | ||||
| 1496 | if (atab == NULL((void *)0)) | |||
| 1497 | return(-1); | |||
| 1498 | /* | |||
| 1499 | * hash by inode and search the chain for an inode and device match | |||
| 1500 | */ | |||
| 1501 | indx = ((unsigned)ino) % A_TAB_SZ317; | |||
| 1502 | if ((pt = atab[indx]) == NULL((void *)0)) | |||
| 1503 | return(-1); | |||
| 1504 | ||||
| 1505 | ppt = &(atab[indx]); | |||
| 1506 | while (pt != NULL((void *)0)) { | |||
| 1507 | if ((pt->ft.ft_ino == ino) && (pt->ft.ft_dev == dev)) | |||
| 1508 | break; | |||
| 1509 | /* | |||
| 1510 | * no match, go to next one | |||
| 1511 | */ | |||
| 1512 | ppt = &(pt->fow); | |||
| 1513 | pt = pt->fow; | |||
| 1514 | } | |||
| 1515 | ||||
| 1516 | /* | |||
| 1517 | * return if we did not find it. | |||
| 1518 | */ | |||
| 1519 | if (pt == NULL((void *)0) || pt->ft.ft_name == NULL((void *)0) || | |||
| 1520 | strcmp(name, pt->ft.ft_name) == 0) | |||
| 1521 | return(-1); | |||
| 1522 | ||||
| 1523 | /* | |||
| 1524 | * found it. set the times and remove the entry from the table. | |||
| 1525 | */ | |||
| 1526 | set_attr(&pt->ft, 1, 0, 0, 0); | |||
| 1527 | sigfillset(&allsigs); | |||
| 1528 | sigprocmask(SIG_BLOCK1, &allsigs, &savedsigs); | |||
| 1529 | *ppt = pt->fow; | |||
| 1530 | sigprocmask(SIG_SETMASK3, &savedsigs, NULL((void *)0)); | |||
| 1531 | free(pt->ft.ft_name); | |||
| 1532 | free(pt); | |||
| 1533 | return(0); | |||
| 1534 | } | |||
| 1535 | ||||
| 1536 | /* | |||
| 1537 | * directory access mode and time storage routines (for directories CREATED | |||
| 1538 | * by pax). | |||
| 1539 | * | |||
| 1540 | * Pax requires that extracted directories, by default, have their access/mod | |||
| 1541 | * times and permissions set to the values specified in the archive. During the | |||
| 1542 | * actions of extracting (and creating the destination subtree during -rw copy) | |||
| 1543 | * directories extracted may be modified after being created. Even worse is | |||
| 1544 | * that these directories may have been created with file permissions which | |||
| 1545 | * prohibits any descendants of these directories from being extracted. When | |||
| 1546 | * directories are created by pax, access rights may be added to permit the | |||
| 1547 | * creation of files in their subtree. Every time pax creates a directory, the | |||
| 1548 | * times and file permissions specified by the archive are stored. After all | |||
| 1549 | * files have been extracted (or copied), these directories have their times | |||
| 1550 | * and file modes reset to the stored values. The directory info is restored in | |||
| 1551 | * reverse order as entries were added from root to leaf: to restore atime | |||
| 1552 | * properly, we must go backwards. | |||
| 1553 | */ | |||
| 1554 | ||||
| 1555 | /* | |||
| 1556 | * dir_start() | |||
| 1557 | * set up the directory time and file mode storage for directories CREATED | |||
| 1558 | * by pax. | |||
| 1559 | * Return: | |||
| 1560 | * 0 if ok, -1 otherwise | |||
| 1561 | */ | |||
| 1562 | ||||
| 1563 | int | |||
| 1564 | dir_start(void) | |||
| 1565 | { | |||
| 1566 | if (dirp != NULL((void *)0)) | |||
| 1567 | return(0); | |||
| 1568 | ||||
| 1569 | dirsize = DIRP_SIZE64; | |||
| 1570 | if ((dirp = reallocarray(NULL((void *)0), dirsize, sizeof(DIRDATA))) == NULL((void *)0)) { | |||
| 1571 | paxwarn(1, "Unable to allocate memory for directory times"); | |||
| 1572 | return(-1); | |||
| 1573 | } | |||
| 1574 | return(0); | |||
| 1575 | } | |||
| 1576 | ||||
| 1577 | /* | |||
| 1578 | * add_dir() | |||
| 1579 | * add the mode and times for a newly CREATED directory | |||
| 1580 | * name is name of the directory, psb the stat buffer with the data in it, | |||
| 1581 | * frc_mode is a flag that says whether to force the setting of the mode | |||
| 1582 | * (ignoring the user set values for preserving file mode). Frc_mode is | |||
| 1583 | * for the case where we created a file and found that the resulting | |||
| 1584 | * directory was not writeable and the user asked for file modes to NOT | |||
| 1585 | * be preserved. (we have to preserve what was created by default, so we | |||
| 1586 | * have to force the setting at the end. this is stated explicitly in the | |||
| 1587 | * pax spec) | |||
| 1588 | */ | |||
| 1589 | ||||
| 1590 | void | |||
| 1591 | add_dir(char *name, struct stat *psb, int frc_mode) | |||
| 1592 | { | |||
| 1593 | DIRDATA *dblk; | |||
| 1594 | sigset_t allsigs, savedsigs; | |||
| 1595 | char realname[PATH_MAX1024], *rp; | |||
| 1596 | ||||
| 1597 | if (dirp == NULL((void *)0)) | |||
| 1598 | return; | |||
| 1599 | ||||
| 1600 | if (havechd && *name != '/') { | |||
| 1601 | if ((rp = realpath(name, realname)) == NULL((void *)0)) { | |||
| 1602 | paxwarn(1, "Cannot canonicalize %s", name); | |||
| 1603 | return; | |||
| 1604 | } | |||
| 1605 | name = rp; | |||
| 1606 | } | |||
| 1607 | if (dircnt == dirsize) { | |||
| 1608 | dblk = reallocarray(dirp, dirsize * 2, sizeof(DIRDATA)); | |||
| 1609 | if (dblk == NULL((void *)0)) { | |||
| 1610 | paxwarn(1, "Unable to store mode and times for created" | |||
| 1611 | " directory: %s", name); | |||
| 1612 | return; | |||
| 1613 | } | |||
| 1614 | sigprocmask(SIG_BLOCK1, &allsigs, &savedsigs); | |||
| 1615 | dirp = dblk; | |||
| 1616 | dirsize *= 2; | |||
| 1617 | sigprocmask(SIG_SETMASK3, &savedsigs, NULL((void *)0)); | |||
| 1618 | } | |||
| 1619 | dblk = &dirp[dircnt]; | |||
| 1620 | if ((dblk->ft.ft_name = strdup(name)) == NULL((void *)0)) { | |||
| 1621 | paxwarn(1, "Unable to store mode and times for created" | |||
| 1622 | " directory: %s", name); | |||
| 1623 | return; | |||
| 1624 | } | |||
| 1625 | dblk->ft.ft_mtim = psb->st_mtim; | |||
| 1626 | dblk->ft.ft_atim = psb->st_atim; | |||
| 1627 | dblk->ft.ft_ino = psb->st_ino; | |||
| 1628 | dblk->ft.ft_dev = psb->st_dev; | |||
| 1629 | dblk->mode = psb->st_mode & ABITS((0001000 | 0000700 | 0000070 | 0000007) | (0004000 | 0002000 )); | |||
| 1630 | dblk->frc_mode = frc_mode; | |||
| 1631 | sigprocmask(SIG_BLOCK1, &allsigs, &savedsigs); | |||
| 1632 | ++dircnt; | |||
| 1633 | sigprocmask(SIG_SETMASK3, &savedsigs, NULL((void *)0)); | |||
| 1634 | } | |||
| 1635 | ||||
| 1636 | /* | |||
| 1637 | * delete_dir() | |||
| 1638 | * When we rmdir a directory, we may want to make sure we don't | |||
| 1639 | * later warn about being unable to set its mode and times. | |||
| 1640 | */ | |||
| 1641 | ||||
| 1642 | void | |||
| 1643 | delete_dir(dev_t dev, ino_t ino) | |||
| 1644 | { | |||
| 1645 | DIRDATA *dblk; | |||
| 1646 | char *name; | |||
| 1647 | size_t i; | |||
| 1648 | ||||
| 1649 | if (dirp == NULL((void *)0)) | |||
| 1650 | return; | |||
| 1651 | for (i = 0; i < dircnt; i++) { | |||
| 1652 | dblk = &dirp[i]; | |||
| 1653 | ||||
| 1654 | if (dblk->ft.ft_name == NULL((void *)0)) | |||
| 1655 | continue; | |||
| 1656 | if (dblk->ft.ft_dev == dev && dblk->ft.ft_ino == ino) { | |||
| 1657 | name = dblk->ft.ft_name; | |||
| 1658 | dblk->ft.ft_name = NULL((void *)0); | |||
| 1659 | free(name); | |||
| 1660 | break; | |||
| 1661 | } | |||
| 1662 | } | |||
| 1663 | } | |||
| 1664 | ||||
| 1665 | /* | |||
| 1666 | * proc_dir(int in_sig) | |||
| 1667 | * process all file modes and times stored for directories CREATED | |||
| 1668 | * by pax. If in_sig is set, we're in a signal handler and can't | |||
| 1669 | * free stuff. | |||
| 1670 | */ | |||
| 1671 | ||||
| 1672 | void | |||
| 1673 | proc_dir(int in_sig) | |||
| 1674 | { | |||
| 1675 | DIRDATA *dblk; | |||
| 1676 | size_t cnt; | |||
| 1677 | ||||
| 1678 | if (dirp == NULL((void *)0)) | |||
| 1679 | return; | |||
| 1680 | /* | |||
| 1681 | * read backwards through the file and process each directory | |||
| 1682 | */ | |||
| 1683 | cnt = dircnt; | |||
| 1684 | while (cnt-- > 0) { | |||
| 1685 | dblk = &dirp[cnt]; | |||
| 1686 | /* | |||
| 1687 | * If we remove a directory we created, we replace the | |||
| 1688 | * ft_name with NULL. Ignore those. | |||
| 1689 | */ | |||
| 1690 | if (dblk->ft.ft_name == NULL((void *)0)) | |||
| 1691 | continue; | |||
| 1692 | ||||
| 1693 | /* | |||
| 1694 | * frc_mode set, make sure we set the file modes even if | |||
| 1695 | * the user didn't ask for it (see file_subs.c for more info) | |||
| 1696 | */ | |||
| 1697 | set_attr(&dblk->ft, 0, dblk->mode, pmode || dblk->frc_mode, | |||
| 1698 | in_sig); | |||
| 1699 | if (!in_sig) | |||
| 1700 | free(dblk->ft.ft_name); | |||
| 1701 | } | |||
| 1702 | ||||
| 1703 | if (!in_sig) | |||
| 1704 | free(dirp); | |||
| 1705 | dirp = NULL((void *)0); | |||
| 1706 | dircnt = 0; | |||
| 1707 | } | |||
| 1708 | ||||
| 1709 | /* | |||
| 1710 | * database independent routines | |||
| 1711 | */ | |||
| 1712 | ||||
| 1713 | /* | |||
| 1714 | * st_hash() | |||
| 1715 | * hashes filenames to a u_int for hashing into a table. Looks at the tail | |||
| 1716 | * end of file, as this provides far better distribution than any other | |||
| 1717 | * part of the name. For performance reasons we only care about the last | |||
| 1718 | * MAXKEYLEN chars (should be at LEAST large enough to pick off the file | |||
| 1719 | * name). Was tested on 500,000 name file tree traversal from the root | |||
| 1720 | * and gave almost a perfectly uniform distribution of keys when used with | |||
| 1721 | * prime sized tables (MAXKEYLEN was 128 in test). Hashes (sizeof int) | |||
| 1722 | * chars at a time and pads with 0 for last addition. | |||
| 1723 | * Return: | |||
| 1724 | * the hash value of the string MOD (%) the table size. | |||
| 1725 | */ | |||
| 1726 | ||||
| 1727 | static u_int | |||
| 1728 | st_hash(const char *name, int len, int tabsz) | |||
| 1729 | { | |||
| 1730 | const char *pt; | |||
| 1731 | char *dest; | |||
| 1732 | const char *end; | |||
| 1733 | int i; | |||
| 1734 | u_int key = 0; | |||
| 1735 | int steps; | |||
| 1736 | int res; | |||
| 1737 | u_int val; | |||
| 1738 | ||||
| 1739 | /* | |||
| 1740 | * only look at the tail up to MAXKEYLEN, we do not need to waste | |||
| 1741 | * time here (remember these are pathnames, the tail is what will | |||
| 1742 | * spread out the keys) | |||
| 1743 | */ | |||
| 1744 | if (len > MAXKEYLEN64) { | |||
| 1745 | pt = &(name[len - MAXKEYLEN64]); | |||
| 1746 | len = MAXKEYLEN64; | |||
| 1747 | } else | |||
| 1748 | pt = name; | |||
| 1749 | ||||
| 1750 | /* | |||
| 1751 | * calculate the number of u_int size steps in the string and if | |||
| 1752 | * there is a runt to deal with | |||
| 1753 | */ | |||
| 1754 | steps = len/sizeof(u_int); | |||
| 1755 | res = len % sizeof(u_int); | |||
| 1756 | ||||
| 1757 | /* | |||
| 1758 | * add up the value of the string in unsigned integer sized pieces | |||
| 1759 | * too bad we cannot have unsigned int aligned strings, then we | |||
| 1760 | * could avoid the expensive copy. | |||
| 1761 | */ | |||
| 1762 | for (i = 0; i < steps; ++i) { | |||
| 1763 | end = pt + sizeof(u_int); | |||
| 1764 | dest = (char *)&val; | |||
| 1765 | while (pt < end) | |||
| 1766 | *dest++ = *pt++; | |||
| 1767 | key += val; | |||
| ||||
| 1768 | } | |||
| 1769 | ||||
| 1770 | /* | |||
| 1771 | * add in the runt padded with zero to the right | |||
| 1772 | */ | |||
| 1773 | if (res) { | |||
| 1774 | val = 0; | |||
| 1775 | end = pt + res; | |||
| 1776 | dest = (char *)&val; | |||
| 1777 | while (pt < end) | |||
| 1778 | *dest++ = *pt++; | |||
| 1779 | key += val; | |||
| 1780 | } | |||
| 1781 | ||||
| 1782 | /* | |||
| 1783 | * return the result mod the table size | |||
| 1784 | */ | |||
| 1785 | return(key % tabsz); | |||
| 1786 | } |