1 1.46 rillig /* $NetBSD: ftree.c,v 1.46 2024/09/08 17:28:36 rillig Exp $ */ 2 1.4 cgd 3 1.1 jtc /*- 4 1.28 agc * Copyright (c) 1992 Keith Muller. 5 1.1 jtc * Copyright (c) 1992, 1993 6 1.1 jtc * The Regents of the University of California. All rights reserved. 7 1.1 jtc * 8 1.1 jtc * This code is derived from software contributed to Berkeley by 9 1.1 jtc * Keith Muller of the University of California, San Diego. 10 1.1 jtc * 11 1.1 jtc * Redistribution and use in source and binary forms, with or without 12 1.1 jtc * modification, are permitted provided that the following conditions 13 1.1 jtc * are met: 14 1.1 jtc * 1. Redistributions of source code must retain the above copyright 15 1.1 jtc * notice, this list of conditions and the following disclaimer. 16 1.1 jtc * 2. Redistributions in binary form must reproduce the above copyright 17 1.1 jtc * notice, this list of conditions and the following disclaimer in the 18 1.1 jtc * documentation and/or other materials provided with the distribution. 19 1.27 agc * 3. Neither the name of the University nor the names of its contributors 20 1.27 agc * may be used to endorse or promote products derived from this software 21 1.27 agc * without specific prior written permission. 22 1.27 agc * 23 1.27 agc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 1.27 agc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 1.27 agc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 1.27 agc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 1.27 agc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 1.27 agc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 1.27 agc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 1.27 agc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 1.27 agc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 1.27 agc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 1.27 agc * SUCH DAMAGE. 34 1.27 agc */ 35 1.27 agc 36 1.27 agc /*- 37 1.12 lukem * Copyright (c) 2001 The NetBSD Foundation, Inc. 38 1.12 lukem * All rights reserved. 39 1.12 lukem * 40 1.12 lukem * This code is derived from software contributed to The NetBSD Foundation 41 1.12 lukem * by Luke Mewburn of Wasabi Systems. 42 1.12 lukem * 43 1.12 lukem * Redistribution and use in source and binary forms, with or without 44 1.12 lukem * modification, are permitted provided that the following conditions 45 1.12 lukem * are met: 46 1.12 lukem * 1. Redistributions of source code must retain the above copyright 47 1.12 lukem * notice, this list of conditions and the following disclaimer. 48 1.12 lukem * 2. Redistributions in binary form must reproduce the above copyright 49 1.12 lukem * notice, this list of conditions and the following disclaimer in the 50 1.12 lukem * documentation and/or other materials provided with the distribution. 51 1.12 lukem * 52 1.12 lukem * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 53 1.12 lukem * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 54 1.12 lukem * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 55 1.12 lukem * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 56 1.12 lukem * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 57 1.12 lukem * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 58 1.12 lukem * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 59 1.12 lukem * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 60 1.12 lukem * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 61 1.12 lukem * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 62 1.12 lukem * POSSIBILITY OF SUCH DAMAGE. 63 1.12 lukem */ 64 1.12 lukem 65 1.29 lukem #if HAVE_NBTOOL_CONFIG_H 66 1.29 lukem #include "nbtool_config.h" 67 1.29 lukem #endif 68 1.29 lukem 69 1.6 christos #include <sys/cdefs.h> 70 1.29 lukem #if !defined(lint) 71 1.4 cgd #if 0 72 1.4 cgd static char sccsid[] = "@(#)ftree.c 8.2 (Berkeley) 4/18/94"; 73 1.4 cgd #else 74 1.46 rillig __RCSID("$NetBSD: ftree.c,v 1.46 2024/09/08 17:28:36 rillig Exp $"); 75 1.4 cgd #endif 76 1.1 jtc #endif /* not lint */ 77 1.1 jtc 78 1.1 jtc #include <sys/types.h> 79 1.1 jtc #include <sys/time.h> 80 1.1 jtc #include <sys/stat.h> 81 1.1 jtc #include <sys/param.h> 82 1.1 jtc #include <ctype.h> 83 1.1 jtc #include <errno.h> 84 1.17 tv #include <fts.h> 85 1.17 tv #include <stdio.h> 86 1.1 jtc #include <stdlib.h> 87 1.17 tv #include <string.h> 88 1.17 tv #include <unistd.h> 89 1.1 jtc #include "pax.h" 90 1.1 jtc #include "ftree.h" 91 1.1 jtc #include "extern.h" 92 1.22 christos #include "options.h" 93 1.18 lukem #ifndef SMALL 94 1.12 lukem #include "mtree.h" 95 1.18 lukem #endif /* SMALL */ 96 1.16 tv 97 1.1 jtc /* 98 1.1 jtc * routines to interface with the fts library function. 99 1.1 jtc * 100 1.1 jtc * file args supplied to pax are stored on a single linked list (of type FTREE) 101 1.1 jtc * and given to fts to be processed one at a time. pax "selects" files from 102 1.1 jtc * the expansion of each arg into the corresponding file tree (if the arg is a 103 1.1 jtc * directory, otherwise the node itself is just passed to pax). The selection 104 1.1 jtc * is modified by the -n and -u flags. The user is informed when a specific 105 1.1 jtc * file arg does not generate any selected files. -n keeps expanding the file 106 1.1 jtc * tree arg until one of its files is selected, then skips to the next file 107 1.1 jtc * arg. when the user does not supply the file trees as command line args to 108 1.1 jtc * pax, they are read from stdin 109 1.1 jtc */ 110 1.1 jtc 111 1.10 itohy static FTS *ftsp = NULL; /* current FTS handle */ 112 1.1 jtc static int ftsopts; /* options to be used on fts_open */ 113 1.1 jtc static char *farray[2]; /* array for passing each arg to fts */ 114 1.1 jtc static FTREE *fthead = NULL; /* head of linked list of file args */ 115 1.1 jtc static FTREE *fttail = NULL; /* tail of linked list of file args */ 116 1.1 jtc static FTREE *ftcur = NULL; /* current file arg being processed */ 117 1.1 jtc static FTSENT *ftent = NULL; /* current file tree entry */ 118 1.1 jtc static int ftree_skip; /* when set skip to next file arg */ 119 1.18 lukem #ifndef SMALL 120 1.12 lukem static NODE *ftnode = NULL; /* mtree(8) specfile; used by -M */ 121 1.18 lukem #endif /* SMALL */ 122 1.1 jtc 123 1.11 lukem static int ftree_arg(void); 124 1.11 lukem 125 1.11 lukem #define FTS_ERRNO(x) (x)->fts_errno 126 1.1 jtc 127 1.1 jtc /* 128 1.1 jtc * ftree_start() 129 1.1 jtc * initialize the options passed to fts_open() during this run of pax 130 1.1 jtc * options are based on the selection of pax options by the user 131 1.1 jtc * fts_start() also calls fts_arg() to open the first valid file arg. We 132 1.1 jtc * also attempt to reset directory access times when -t (tflag) is set. 133 1.1 jtc * Return: 134 1.1 jtc * 0 if there is at least one valid file arg to process, -1 otherwise 135 1.1 jtc */ 136 1.1 jtc 137 1.1 jtc int 138 1.41 matt ftree_start(void) 139 1.1 jtc { 140 1.12 lukem 141 1.18 lukem #ifndef SMALL 142 1.12 lukem /* 143 1.12 lukem * if -M is given, the list of filenames on stdin is actually 144 1.12 lukem * an mtree(8) specfile, so parse the specfile into a NODE * 145 1.12 lukem * tree at ftnode, for use by next_file() 146 1.12 lukem */ 147 1.12 lukem if (Mflag) { 148 1.12 lukem if (fthead != NULL) { 149 1.12 lukem tty_warn(1, 150 1.12 lukem "The -M flag is only supported when reading file list from stdin"); 151 1.34 dsl return -1; 152 1.12 lukem } 153 1.12 lukem ftnode = spec(stdin); 154 1.12 lukem if (ftnode != NULL && 155 1.12 lukem (ftnode->type != F_DIR || strcmp(ftnode->name, ".") != 0)) { 156 1.12 lukem tty_warn(1, 157 1.12 lukem "First node of specfile is not `.' directory"); 158 1.34 dsl return -1; 159 1.12 lukem } 160 1.34 dsl return 0; 161 1.12 lukem } 162 1.18 lukem #endif /* SMALL */ 163 1.12 lukem 164 1.1 jtc /* 165 1.1 jtc * set up the operation mode of fts, open the first file arg. We must 166 1.1 jtc * use FTS_NOCHDIR, as the user may have to open multiple archives and 167 1.1 jtc * if fts did a chdir off into the boondocks, we may create an archive 168 1.45 rillig * volume in a place where the user did not expect to. 169 1.1 jtc */ 170 1.1 jtc ftsopts = FTS_NOCHDIR; 171 1.1 jtc 172 1.1 jtc /* 173 1.46 rillig * optional user flags that affect file traversal 174 1.1 jtc * -H command line symlink follow only (half follow) 175 1.1 jtc * -L follow sylinks (logical) 176 1.1 jtc * -P do not follow sylinks (physical). This is the default. 177 1.1 jtc * -X do not cross over mount points 178 1.1 jtc * -t preserve access times on files read. 179 1.1 jtc * -n select only the first member of a file tree when a match is found 180 1.1 jtc * -d do not extract subtrees rooted at a directory arg. 181 1.1 jtc */ 182 1.1 jtc if (Lflag) 183 1.1 jtc ftsopts |= FTS_LOGICAL; 184 1.1 jtc else 185 1.1 jtc ftsopts |= FTS_PHYSICAL; 186 1.1 jtc if (Hflag) 187 1.1 jtc ftsopts |= FTS_COMFOLLOW; 188 1.1 jtc if (Xflag) 189 1.1 jtc ftsopts |= FTS_XDEV; 190 1.1 jtc 191 1.1 jtc if ((fthead == NULL) && ((farray[0] = malloc(PAXPATHLEN+2)) == NULL)) { 192 1.6 christos tty_warn(1, "Unable to allocate memory for file name buffer"); 193 1.34 dsl return -1; 194 1.1 jtc } 195 1.1 jtc 196 1.1 jtc if (ftree_arg() < 0) 197 1.43 lukem return 0; 198 1.1 jtc if (tflag && (atdir_start() < 0)) 199 1.34 dsl return -1; 200 1.34 dsl return 0; 201 1.1 jtc } 202 1.1 jtc 203 1.1 jtc /* 204 1.1 jtc * ftree_add() 205 1.1 jtc * add the arg to the linked list of files to process. Each will be 206 1.1 jtc * processed by fts one at a time 207 1.1 jtc * Return: 208 1.1 jtc * 0 if added to the linked list, -1 if failed 209 1.1 jtc */ 210 1.1 jtc 211 1.1 jtc int 212 1.9 is ftree_add(char *str, int isdir) 213 1.1 jtc { 214 1.5 tls FTREE *ft; 215 1.5 tls int len; 216 1.1 jtc 217 1.1 jtc /* 218 1.1 jtc * simple check for bad args 219 1.1 jtc */ 220 1.1 jtc if ((str == NULL) || (*str == '\0')) { 221 1.26 christos tty_warn(0, "Invalid file name argument"); 222 1.34 dsl return -1; 223 1.1 jtc } 224 1.1 jtc 225 1.1 jtc /* 226 1.1 jtc * allocate FTREE node and add to the end of the linked list (args are 227 1.1 jtc * processed in the same order they were passed to pax). Get rid of any 228 1.1 jtc * trailing / the user may pass us. (watch out for / by itself). 229 1.1 jtc */ 230 1.1 jtc if ((ft = (FTREE *)malloc(sizeof(FTREE))) == NULL) { 231 1.6 christos tty_warn(0, "Unable to allocate memory for filename"); 232 1.34 dsl return -1; 233 1.1 jtc } 234 1.1 jtc 235 1.1 jtc if (((len = strlen(str) - 1) > 0) && (str[len] == '/')) 236 1.1 jtc str[len] = '\0'; 237 1.1 jtc ft->fname = str; 238 1.9 is ft->refcnt = -isdir; 239 1.1 jtc ft->fow = NULL; 240 1.1 jtc if (fthead == NULL) { 241 1.1 jtc fttail = fthead = ft; 242 1.34 dsl return 0; 243 1.1 jtc } 244 1.1 jtc fttail->fow = ft; 245 1.1 jtc fttail = ft; 246 1.34 dsl return 0; 247 1.1 jtc } 248 1.1 jtc 249 1.1 jtc /* 250 1.1 jtc * ftree_sel() 251 1.1 jtc * this entry has been selected by pax. bump up reference count and handle 252 1.1 jtc * -n and -d processing. 253 1.1 jtc */ 254 1.1 jtc 255 1.1 jtc void 256 1.5 tls ftree_sel(ARCHD *arcn) 257 1.1 jtc { 258 1.1 jtc /* 259 1.1 jtc * set reference bit for this pattern. This linked list is only used 260 1.1 jtc * when file trees are supplied pax as args. The list is not used when 261 1.1 jtc * the trees are read from stdin. 262 1.1 jtc */ 263 1.10 itohy if (ftcur != NULL) 264 1.1 jtc ftcur->refcnt = 1; 265 1.1 jtc 266 1.1 jtc /* 267 1.1 jtc * if -n we are done with this arg, force a skip to the next arg when 268 1.1 jtc * pax asks for the next file in next_file(). 269 1.12 lukem * if -M we don't use fts(3), so the rest of this function is moot. 270 1.1 jtc * if -d we tell fts only to match the directory (if the arg is a dir) 271 1.1 jtc * and not the entire file tree rooted at that point. 272 1.1 jtc */ 273 1.1 jtc if (nflag) 274 1.1 jtc ftree_skip = 1; 275 1.1 jtc 276 1.12 lukem if (Mflag || !dflag || (arcn->type != PAX_DIR)) 277 1.1 jtc return; 278 1.1 jtc 279 1.1 jtc if (ftent != NULL) 280 1.1 jtc (void)fts_set(ftsp, ftent, FTS_SKIP); 281 1.1 jtc } 282 1.1 jtc 283 1.1 jtc /* 284 1.1 jtc * ftree_chk() 285 1.1 jtc * called at end on pax execution. Prints all those file args that did not 286 1.1 jtc * have a selected member (reference count still 0) 287 1.1 jtc */ 288 1.1 jtc 289 1.1 jtc void 290 1.1 jtc ftree_chk(void) 291 1.1 jtc { 292 1.5 tls FTREE *ft; 293 1.5 tls int wban = 0; 294 1.1 jtc 295 1.1 jtc /* 296 1.1 jtc * make sure all dir access times were reset. 297 1.1 jtc */ 298 1.1 jtc if (tflag) 299 1.1 jtc atdir_end(); 300 1.1 jtc 301 1.1 jtc /* 302 1.1 jtc * walk down list and check reference count. Print out those members 303 1.1 jtc * that never had a match 304 1.1 jtc */ 305 1.1 jtc for (ft = fthead; ft != NULL; ft = ft->fow) { 306 1.9 is if (ft->refcnt != 0) 307 1.1 jtc continue; 308 1.1 jtc if (wban == 0) { 309 1.6 christos tty_warn(1, 310 1.6 christos "WARNING! These file names were not selected:"); 311 1.1 jtc ++wban; 312 1.1 jtc } 313 1.1 jtc (void)fprintf(stderr, "%s\n", ft->fname); 314 1.1 jtc } 315 1.1 jtc } 316 1.1 jtc 317 1.1 jtc /* 318 1.1 jtc * ftree_arg() 319 1.1 jtc * Get the next file arg for fts to process. Can be from either the linked 320 1.1 jtc * list or read from stdin when the user did not them as args to pax. Each 321 1.1 jtc * arg is processed until the first successful fts_open(). 322 1.1 jtc * Return: 323 1.1 jtc * 0 when the next arg is ready to go, -1 if out of file args (or EOF on 324 1.1 jtc * stdin). 325 1.1 jtc */ 326 1.1 jtc 327 1.1 jtc static int 328 1.1 jtc ftree_arg(void) 329 1.1 jtc { 330 1.1 jtc /* 331 1.1 jtc * close off the current file tree 332 1.1 jtc */ 333 1.1 jtc if (ftsp != NULL) { 334 1.1 jtc (void)fts_close(ftsp); 335 1.1 jtc ftsp = NULL; 336 1.37 simonb ftent = NULL; 337 1.1 jtc } 338 1.1 jtc 339 1.1 jtc /* 340 1.1 jtc * keep looping until we get a valid file tree to process. Stop when we 341 1.1 jtc * reach the end of the list (or get an eof on stdin) 342 1.1 jtc */ 343 1.1 jtc for(;;) { 344 1.1 jtc if (fthead == NULL) { 345 1.30 christos int i, c = EOF; 346 1.1 jtc /* 347 1.1 jtc * the user didn't supply any args, get the file trees 348 1.10 itohy * to process from stdin; 349 1.1 jtc */ 350 1.42 christos for (i = 0; i < PAXPATHLEN + 2;) { 351 1.30 christos c = getchar(); 352 1.30 christos if (c == EOF) 353 1.30 christos break; 354 1.30 christos else if (c == sep) { 355 1.30 christos if (i != 0) 356 1.30 christos break; 357 1.30 christos } else 358 1.42 christos farray[0][i++] = c; 359 1.30 christos } 360 1.30 christos if (i == 0) 361 1.30 christos return -1; 362 1.30 christos farray[0][i] = '\0'; 363 1.1 jtc } else { 364 1.1 jtc /* 365 1.35 msaitoh * the user supplied the file args as arguments to pax 366 1.1 jtc */ 367 1.1 jtc if (ftcur == NULL) 368 1.1 jtc ftcur = fthead; 369 1.1 jtc else if ((ftcur = ftcur->fow) == NULL) 370 1.34 dsl return -1; 371 1.9 is 372 1.9 is if (ftcur->refcnt < 0) { 373 1.9 is /* 374 1.9 is * chdir entry. 375 1.9 is * Change directory and retry loop. 376 1.9 is */ 377 1.9 is if (ar_dochdir(ftcur->fname)) 378 1.9 is return (-1); 379 1.9 is continue; 380 1.9 is } 381 1.1 jtc farray[0] = ftcur->fname; 382 1.1 jtc } 383 1.1 jtc 384 1.1 jtc /* 385 1.1 jtc * watch it, fts wants the file arg stored in a array of char 386 1.1 jtc * ptrs, with the last one a null. we use a two element array 387 1.1 jtc * and set farray[0] to point at the buffer with the file name 388 1.10 itohy * in it. We cannot pass all the file args to fts at one shot 389 1.1 jtc * as we need to keep a handle on which file arg generates what 390 1.1 jtc * files (the -n and -d flags need this). If the open is 391 1.1 jtc * successful, return a 0. 392 1.1 jtc */ 393 1.1 jtc if ((ftsp = fts_open(farray, ftsopts, NULL)) != NULL) 394 1.1 jtc break; 395 1.1 jtc } 396 1.34 dsl return 0; 397 1.1 jtc } 398 1.1 jtc 399 1.1 jtc /* 400 1.1 jtc * next_file() 401 1.1 jtc * supplies the next file to process in the supplied archd structure. 402 1.1 jtc * Return: 403 1.1 jtc * 0 when contents of arcn have been set with the next file, -1 when done. 404 1.1 jtc */ 405 1.1 jtc 406 1.1 jtc int 407 1.5 tls next_file(ARCHD *arcn) 408 1.1 jtc { 409 1.18 lukem #ifndef SMALL 410 1.12 lukem static char curdir[PAXPATHLEN+2], curpath[PAXPATHLEN+2]; 411 1.12 lukem static int curdirlen; 412 1.12 lukem 413 1.12 lukem struct stat statbuf; 414 1.12 lukem FTSENT Mftent; 415 1.18 lukem #endif /* SMALL */ 416 1.12 lukem int cnt; 417 1.12 lukem time_t atime, mtime; 418 1.12 lukem char *curlink; 419 1.12 lukem #define MFTENT_DUMMY_DEV UINT_MAX 420 1.12 lukem 421 1.12 lukem curlink = NULL; 422 1.18 lukem #ifndef SMALL 423 1.12 lukem /* 424 1.12 lukem * if parsing an mtree(8) specfile, build up `dummy' ftsent 425 1.12 lukem * from specfile info, and jump below to complete setup of arcn. 426 1.12 lukem */ 427 1.12 lukem if (Mflag) { 428 1.20 lukem int skipoptional; 429 1.19 lukem 430 1.19 lukem next_ftnode: 431 1.20 lukem skipoptional = 0; 432 1.12 lukem if (ftnode == NULL) /* tree is empty */ 433 1.12 lukem return (-1); 434 1.12 lukem 435 1.12 lukem /* get current name */ 436 1.12 lukem if (snprintf(curpath, sizeof(curpath), "%s%s%s", 437 1.12 lukem curdir, curdirlen ? "/" : "", ftnode->name) 438 1.40 lukem >= (int)sizeof(curpath)) { 439 1.15 lukem tty_warn(1, "line %lu: %s: %s", (u_long)ftnode->lineno, 440 1.14 lukem curdir, strerror(ENAMETOOLONG)); 441 1.12 lukem return (-1); 442 1.12 lukem } 443 1.12 lukem ftnode->flags |= F_VISIT; /* mark node visited */ 444 1.12 lukem 445 1.12 lukem /* construct dummy FTSENT */ 446 1.12 lukem Mftent.fts_path = curpath; 447 1.12 lukem Mftent.fts_statp = &statbuf; 448 1.12 lukem Mftent.fts_pointer = ftnode; 449 1.12 lukem ftent = &Mftent; 450 1.18 lukem /* look for existing file */ 451 1.12 lukem if (lstat(Mftent.fts_path, &statbuf) == -1) { 452 1.19 lukem if (ftnode->flags & F_OPT) 453 1.20 lukem skipoptional = 1; 454 1.19 lukem 455 1.18 lukem /* missing: fake up stat info */ 456 1.12 lukem memset(&statbuf, 0, sizeof(statbuf)); 457 1.12 lukem statbuf.st_dev = MFTENT_DUMMY_DEV; 458 1.12 lukem statbuf.st_ino = ftnode->lineno; 459 1.12 lukem statbuf.st_size = 0; 460 1.12 lukem #define NODETEST(t, m) \ 461 1.12 lukem if (!(t)) { \ 462 1.15 lukem tty_warn(1, "line %lu: %s: %s not specified", \ 463 1.15 lukem (u_long)ftnode->lineno, \ 464 1.15 lukem ftent->fts_path, m); \ 465 1.34 dsl return -1; \ 466 1.12 lukem } 467 1.12 lukem statbuf.st_mode = nodetoino(ftnode->type); 468 1.12 lukem NODETEST(ftnode->flags & F_TYPE, "type"); 469 1.12 lukem NODETEST(ftnode->flags & F_MODE, "mode"); 470 1.12 lukem if (!(ftnode->flags & F_TIME)) 471 1.12 lukem statbuf.st_mtime = starttime; 472 1.13 lukem NODETEST(ftnode->flags & (F_GID | F_GNAME), "group"); 473 1.13 lukem NODETEST(ftnode->flags & (F_UID | F_UNAME), "user"); 474 1.12 lukem if (ftnode->type == F_BLOCK || ftnode->type == F_CHAR) 475 1.12 lukem NODETEST(ftnode->flags & F_DEV, 476 1.12 lukem "device number"); 477 1.12 lukem if (ftnode->type == F_LINK) 478 1.12 lukem NODETEST(ftnode->flags & F_SLINK, "symlink"); 479 1.12 lukem /* don't require F_FLAGS or F_SIZE */ 480 1.12 lukem #undef NODETEST 481 1.18 lukem } else { 482 1.18 lukem if (ftnode->flags & F_TYPE && nodetoino(ftnode->type) 483 1.18 lukem != (statbuf.st_mode & S_IFMT)) { 484 1.18 lukem tty_warn(1, 485 1.15 lukem "line %lu: %s: type mismatch: specfile %s, tree %s", 486 1.18 lukem (u_long)ftnode->lineno, ftent->fts_path, 487 1.18 lukem inotype(nodetoino(ftnode->type)), 488 1.18 lukem inotype(statbuf.st_mode)); 489 1.34 dsl return -1; 490 1.18 lukem } 491 1.20 lukem if (ftnode->type == F_DIR && (ftnode->flags & F_OPT)) 492 1.20 lukem skipoptional = 1; 493 1.12 lukem } 494 1.12 lukem /* 495 1.12 lukem * override settings with those from specfile 496 1.12 lukem */ 497 1.12 lukem if (ftnode->flags & F_MODE) { 498 1.44 riastrad statbuf.st_mode &= ~ALLPERMS; 499 1.12 lukem statbuf.st_mode |= (ftnode->st_mode & ALLPERMS); 500 1.12 lukem } 501 1.12 lukem if (ftnode->flags & (F_GID | F_GNAME)) 502 1.12 lukem statbuf.st_gid = ftnode->st_gid; 503 1.12 lukem if (ftnode->flags & (F_UID | F_UNAME)) 504 1.12 lukem statbuf.st_uid = ftnode->st_uid; 505 1.16 tv #if HAVE_STRUCT_STAT_ST_FLAGS 506 1.12 lukem if (ftnode->flags & F_FLAGS) 507 1.12 lukem statbuf.st_flags = ftnode->st_flags; 508 1.16 tv #endif 509 1.12 lukem if (ftnode->flags & F_TIME) 510 1.31 jmc #if BSD4_4 && !HAVE_NBTOOL_CONFIG_H 511 1.12 lukem statbuf.st_mtimespec = ftnode->st_mtimespec; 512 1.16 tv #else 513 1.16 tv statbuf.st_mtime = ftnode->st_mtimespec.tv_sec; 514 1.16 tv #endif 515 1.12 lukem if (ftnode->flags & F_DEV) 516 1.12 lukem statbuf.st_rdev = ftnode->st_rdev; 517 1.12 lukem if (ftnode->flags & F_SLINK) 518 1.12 lukem curlink = ftnode->slink; 519 1.12 lukem /* ignore F_SIZE */ 520 1.12 lukem 521 1.12 lukem /* 522 1.12 lukem * find next node 523 1.12 lukem */ 524 1.12 lukem if (ftnode->type == F_DIR && ftnode->child != NULL) { 525 1.12 lukem /* directory with unseen child */ 526 1.12 lukem ftnode = ftnode->child; 527 1.22 christos curdirlen = strlcpy(curdir, curpath, sizeof(curdir)); 528 1.12 lukem } else do { 529 1.12 lukem if (ftnode->next != NULL) { 530 1.12 lukem /* next node at current level */ 531 1.12 lukem ftnode = ftnode->next; 532 1.12 lukem } else { /* move back to parent */ 533 1.12 lukem /* reset time only on first cd.. */ 534 1.12 lukem if (Mftent.fts_pointer == ftnode && tflag && 535 1.12 lukem (get_atdir(MFTENT_DUMMY_DEV, ftnode->lineno, 536 1.12 lukem &mtime, &atime) == 0)) { 537 1.12 lukem set_ftime(ftent->fts_path, 538 1.36 tls mtime, atime, 1, 0); 539 1.12 lukem } 540 1.21 lukem ftnode = ftnode->parent; 541 1.12 lukem if (ftnode->parent == ftnode) 542 1.12 lukem ftnode = NULL; 543 1.21 lukem else { 544 1.12 lukem curdirlen -= strlen(ftnode->name) + 1; 545 1.12 lukem curdir[curdirlen] = '\0'; 546 1.12 lukem } 547 1.12 lukem } 548 1.12 lukem } while (ftnode != NULL && ftnode->flags & F_VISIT); 549 1.20 lukem if (skipoptional) /* skip optional entries */ 550 1.19 lukem goto next_ftnode; 551 1.12 lukem goto got_ftent; 552 1.12 lukem } 553 1.18 lukem #endif /* SMALL */ 554 1.1 jtc 555 1.1 jtc /* 556 1.1 jtc * ftree_sel() might have set the ftree_skip flag if the user has the 557 1.1 jtc * -n option and a file was selected from this file arg tree. (-n says 558 1.10 itohy * only one member is matched for each pattern) ftree_skip being 1 559 1.1 jtc * forces us to go to the next arg now. 560 1.1 jtc */ 561 1.1 jtc if (ftree_skip) { 562 1.1 jtc /* 563 1.1 jtc * clear and go to next arg 564 1.1 jtc */ 565 1.1 jtc ftree_skip = 0; 566 1.1 jtc if (ftree_arg() < 0) 567 1.34 dsl return -1; 568 1.1 jtc } 569 1.1 jtc 570 1.24 christos if (ftsp == NULL) 571 1.24 christos return -1; 572 1.1 jtc /* 573 1.1 jtc * loop until we get a valid file to process 574 1.1 jtc */ 575 1.1 jtc for(;;) { 576 1.1 jtc if ((ftent = fts_read(ftsp)) == NULL) { 577 1.1 jtc /* 578 1.1 jtc * out of files in this tree, go to next arg, if none 579 1.1 jtc * we are done 580 1.1 jtc */ 581 1.1 jtc if (ftree_arg() < 0) 582 1.34 dsl return -1; 583 1.1 jtc continue; 584 1.1 jtc } 585 1.1 jtc 586 1.1 jtc /* 587 1.1 jtc * handle each type of fts_read() flag 588 1.1 jtc */ 589 1.1 jtc switch(ftent->fts_info) { 590 1.1 jtc case FTS_D: 591 1.1 jtc case FTS_DEFAULT: 592 1.1 jtc case FTS_F: 593 1.1 jtc case FTS_SL: 594 1.1 jtc case FTS_SLNONE: 595 1.1 jtc /* 596 1.1 jtc * these are all ok 597 1.1 jtc */ 598 1.1 jtc break; 599 1.1 jtc case FTS_DP: 600 1.1 jtc /* 601 1.1 jtc * already saw this directory. If the user wants file 602 1.1 jtc * access times reset, we use this to restore the 603 1.1 jtc * access time for this directory since this is the 604 1.1 jtc * last time we will see it in this file subtree 605 1.1 jtc * remember to force the time (this is -t on a read 606 1.1 jtc * directory, not a created directory). 607 1.1 jtc */ 608 1.11 lukem if (!tflag || (get_atdir( 609 1.11 lukem ftent->fts_statp->st_dev, ftent->fts_statp->st_ino, 610 1.11 lukem &mtime, &atime) < 0)) 611 1.1 jtc continue; 612 1.36 tls set_ftime(ftent->fts_path, mtime, atime, 1, 0); 613 1.1 jtc continue; 614 1.1 jtc case FTS_DC: 615 1.1 jtc /* 616 1.1 jtc * fts claims a file system cycle 617 1.1 jtc */ 618 1.6 christos tty_warn(1,"File system cycle found at %s", 619 1.6 christos ftent->fts_path); 620 1.1 jtc continue; 621 1.1 jtc case FTS_DNR: 622 1.11 lukem syswarn(1, FTS_ERRNO(ftent), 623 1.1 jtc "Unable to read directory %s", ftent->fts_path); 624 1.1 jtc continue; 625 1.1 jtc case FTS_ERR: 626 1.11 lukem syswarn(1, FTS_ERRNO(ftent), 627 1.1 jtc "File system traversal error"); 628 1.1 jtc continue; 629 1.1 jtc case FTS_NS: 630 1.1 jtc case FTS_NSOK: 631 1.11 lukem syswarn(1, FTS_ERRNO(ftent), 632 1.1 jtc "Unable to access %s", ftent->fts_path); 633 1.1 jtc continue; 634 1.1 jtc } 635 1.1 jtc 636 1.18 lukem #ifndef SMALL 637 1.12 lukem got_ftent: 638 1.18 lukem #endif /* SMALL */ 639 1.1 jtc /* 640 1.1 jtc * ok got a file tree node to process. copy info into arcn 641 1.1 jtc * structure (initialize as required) 642 1.1 jtc */ 643 1.1 jtc arcn->skip = 0; 644 1.1 jtc arcn->pad = 0; 645 1.1 jtc arcn->ln_nlen = 0; 646 1.1 jtc arcn->ln_name[0] = '\0'; 647 1.1 jtc arcn->sb = *(ftent->fts_statp); 648 1.1 jtc 649 1.1 jtc /* 650 1.1 jtc * file type based set up and copy into the arcn struct 651 1.1 jtc * SIDE NOTE: 652 1.1 jtc * we try to reset the access time on all files and directories 653 1.1 jtc * we may read when the -t flag is specified. files are reset 654 1.1 jtc * when we close them after copying. we reset the directories 655 1.1 jtc * when we are done with their file tree (we also clean up at 656 1.1 jtc * end in case we cut short a file tree traversal). However 657 1.1 jtc * there is no way to reset access times on symlinks. 658 1.1 jtc */ 659 1.1 jtc switch(S_IFMT & arcn->sb.st_mode) { 660 1.1 jtc case S_IFDIR: 661 1.1 jtc arcn->type = PAX_DIR; 662 1.1 jtc if (!tflag) 663 1.1 jtc break; 664 1.1 jtc add_atdir(ftent->fts_path, arcn->sb.st_dev, 665 1.1 jtc arcn->sb.st_ino, arcn->sb.st_mtime, 666 1.1 jtc arcn->sb.st_atime); 667 1.1 jtc break; 668 1.1 jtc case S_IFCHR: 669 1.1 jtc arcn->type = PAX_CHR; 670 1.1 jtc break; 671 1.1 jtc case S_IFBLK: 672 1.1 jtc arcn->type = PAX_BLK; 673 1.1 jtc break; 674 1.1 jtc case S_IFREG: 675 1.1 jtc /* 676 1.1 jtc * only regular files with have data to store on the 677 1.1 jtc * archive. all others will store a zero length skip. 678 1.1 jtc * the skip field is used by pax for actual data it has 679 1.1 jtc * to read (or skip over). 680 1.1 jtc */ 681 1.1 jtc arcn->type = PAX_REG; 682 1.1 jtc arcn->skip = arcn->sb.st_size; 683 1.1 jtc break; 684 1.1 jtc case S_IFLNK: 685 1.1 jtc arcn->type = PAX_SLK; 686 1.12 lukem if (curlink != NULL) { 687 1.22 christos cnt = strlcpy(arcn->ln_name, curlink, 688 1.12 lukem sizeof(arcn->ln_name)); 689 1.1 jtc /* 690 1.1 jtc * have to read the symlink path from the file 691 1.1 jtc */ 692 1.12 lukem } else if ((cnt = 693 1.12 lukem readlink(ftent->fts_path, arcn->ln_name, 694 1.25 itojun sizeof(arcn->ln_name) - 1)) < 0) { 695 1.1 jtc syswarn(1, errno, "Unable to read symlink %s", 696 1.1 jtc ftent->fts_path); 697 1.1 jtc continue; 698 1.1 jtc } 699 1.1 jtc /* 700 1.1 jtc * set link name length, watch out readlink does not 701 1.35 msaitoh * always null terminate the link path 702 1.1 jtc */ 703 1.1 jtc arcn->ln_name[cnt] = '\0'; 704 1.1 jtc arcn->ln_nlen = cnt; 705 1.1 jtc break; 706 1.31 jmc #ifdef S_IFSOCK 707 1.1 jtc case S_IFSOCK: 708 1.1 jtc /* 709 1.1 jtc * under BSD storing a socket is senseless but we will 710 1.1 jtc * let the format specific write function make the 711 1.1 jtc * decision of what to do with it. 712 1.1 jtc */ 713 1.1 jtc arcn->type = PAX_SCK; 714 1.1 jtc break; 715 1.31 jmc #endif 716 1.1 jtc case S_IFIFO: 717 1.1 jtc arcn->type = PAX_FIF; 718 1.1 jtc break; 719 1.1 jtc } 720 1.1 jtc break; 721 1.1 jtc } 722 1.1 jtc 723 1.1 jtc /* 724 1.1 jtc * copy file name, set file name length 725 1.1 jtc */ 726 1.22 christos arcn->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name)); 727 1.33 dsl arcn->org_name = arcn->fts_name; 728 1.33 dsl strlcpy(arcn->fts_name, ftent->fts_path, sizeof arcn->fts_name); 729 1.24 christos if (strcmp(NM_CPIO, argv0) == 0) { 730 1.24 christos /* 731 1.24 christos * cpio does *not* descend directories listed in the 732 1.24 christos * arguments, unlike pax/tar, so needs special handling 733 1.24 christos * here. failure to do so results in massive amounts 734 1.24 christos * of duplicated files in the output. We kill fts after 735 1.24 christos * the first name is extracted, what a waste. 736 1.24 christos */ 737 1.24 christos ftcur->refcnt = 1; 738 1.24 christos (void)ftree_arg(); 739 1.24 christos } 740 1.34 dsl return 0; 741 1.1 jtc } 742