157111Smuller /*- 257111Smuller * Copyright (c) 1992 Keith Muller. 3*60676Sbostic * Copyright (c) 1992, 1993 4*60676Sbostic * The Regents of the University of California. All rights reserved. 557111Smuller * 657111Smuller * This code is derived from software contributed to Berkeley by 757111Smuller * Keith Muller of the University of California, San Diego. 857111Smuller * 957111Smuller * %sccs.include.redist.c% 1057111Smuller */ 1157111Smuller 1257111Smuller #ifndef lint 13*60676Sbostic static char sccsid[] = "@(#)ftree.c 8.1 (Berkeley) 05/31/93"; 1457111Smuller #endif /* not lint */ 1557111Smuller 1657111Smuller #include <sys/types.h> 1757111Smuller #include <sys/time.h> 1857111Smuller #include <sys/stat.h> 1957111Smuller #include <sys/param.h> 2057111Smuller #include <unistd.h> 2157111Smuller #include <string.h> 2257111Smuller #include <stdio.h> 2357111Smuller #include <ctype.h> 2457111Smuller #include <errno.h> 2557111Smuller #include <stdlib.h> 2657111Smuller #include <fts.h> 2757111Smuller #include "pax.h" 2857111Smuller #include "ftree.h" 2957111Smuller #include "extern.h" 3057111Smuller 3157111Smuller /* 3257111Smuller * routines to interface with the fts library function. 3357111Smuller * 3457111Smuller * file args supplied to pax are stored on a single linked list (of type FTREE) 3557111Smuller * and given to fts to be processed one at a time. pax "selects" files from 3657111Smuller * the expansion of each arg into the corresponding file tree (if the arg is a 3757111Smuller * directory, otherwise the node itself is just passed to pax). The selection 3857111Smuller * is modified by the -n and -u flags. The user is informed when a specific 3957111Smuller * file arg does not generate any selected files. -n keeps expanding the file 4057111Smuller * tree arg until one of its files is selected, then skips to the next file 4157111Smuller * arg. when the user does not supply the file trees as command line args to 4257111Smuller * pax, they are read from stdin 4357111Smuller */ 4457111Smuller 4557111Smuller static FTS *ftsp = NULL; /* curent FTS handle */ 4657111Smuller static int ftsopts; /* options to be used on fts_open */ 4757111Smuller static char *farray[2]; /* array for passing each arg to fts */ 4857111Smuller static FTREE *fthead = NULL; /* head of linked list of file args */ 4957111Smuller static FTREE *fttail = NULL; /* tail of linked list of file args */ 5057111Smuller static FTREE *ftcur = NULL; /* current file arg being processed */ 5157111Smuller static FTSENT *ftent = NULL; /* current file tree entry */ 5257111Smuller static int ftree_skip; /* when set skip to next file arg */ 5357111Smuller 5457111Smuller static int ftree_arg __P((void)); 5557111Smuller 5657111Smuller /* 5757111Smuller * ftree_start() 5857111Smuller * initialize the options passed to fts_open() during this run of pax 5957111Smuller * options are based on the selection of pax options by the user 6057111Smuller * fts_start() also calls fts_arg() to open the first valid file arg. We 6157111Smuller * also attempt to reset directory access times when -t (tflag) is set. 6257111Smuller * Return: 6357111Smuller * 0 if there is at least one valid file arg to process, -1 otherwise 6457111Smuller */ 6557111Smuller 6657111Smuller #if __STDC__ 6757111Smuller int 6857111Smuller ftree_start(void) 6957111Smuller #else 7057111Smuller int 7157111Smuller ftree_start() 7257111Smuller #endif 7357111Smuller { 7457111Smuller /* 7557111Smuller * set up the operation mode of fts, open the first file arg. We must 7657111Smuller * use FTS_NOCHDIR, as the user may have to open multiple archives and 7757111Smuller * if fts did a chdir off into the boondocks, we may create an archive 7857111Smuller * volume in an place where the user did not expect to. 7957111Smuller */ 8057111Smuller ftsopts = FTS_NOCHDIR; 8157111Smuller 8257111Smuller /* 8357111Smuller * optional user flags that effect file traversal 8457111Smuller * -H command line symlink follow only 8557111Smuller * -L follow sylinks 8657111Smuller * -X do not cross over mount points 8757111Smuller * -t preserve access times on files read. 8857111Smuller * -n select only the first member of a file tree when a match is found 8957111Smuller * -d do not extract subtrees rooted at a directory arg. 9057111Smuller */ 9157111Smuller if (Lflag) 9257111Smuller ftsopts |= FTS_LOGICAL; 9357111Smuller else 9457111Smuller ftsopts |= FTS_PHYSICAL; 9557111Smuller if (Hflag) 9657111Smuller # ifdef NET2_FTS 9757111Smuller warn(0, "The -H flag is not supported on this version"); 9857111Smuller # else 9957111Smuller ftsopts |= FTS_COMFOLLOW; 10057111Smuller # endif 10157111Smuller if (Xflag) 10257111Smuller ftsopts |= FTS_XDEV; 10357111Smuller 10457111Smuller if ((fthead == NULL) && ((farray[0] = malloc(PAXPATHLEN+2)) == NULL)) { 10557111Smuller warn(1, "Unable to allocate memory for file name buffer"); 10657111Smuller return(-1); 10757111Smuller } 10857111Smuller 10957111Smuller if (ftree_arg() < 0) 11057111Smuller return(-1); 11157111Smuller if (tflag && (atdir_start() < 0)) 11257111Smuller return(-1); 11357111Smuller return(0); 11457111Smuller } 11557111Smuller 11657111Smuller /* 11757111Smuller * ftree_add() 11857111Smuller * add the arg to the linked list of files to process. Each will be 11957111Smuller * processed by fts one at a time 12057111Smuller * Return: 12157111Smuller * 0 if added to the linked list, -1 if failed 12257111Smuller */ 12357111Smuller 12457111Smuller #if __STDC__ 12557111Smuller int 12657111Smuller ftree_add(register char *str) 12757111Smuller #else 12857111Smuller int 12957111Smuller ftree_add(str) 13057111Smuller register char *str; 13157111Smuller #endif 13257111Smuller { 13357111Smuller register FTREE *ft; 13457111Smuller register int len; 13557111Smuller 13657111Smuller /* 13757111Smuller * simple check for bad args 13857111Smuller */ 13957111Smuller if ((str == NULL) || (*str == '\0')) { 14057111Smuller warn(0, "Invalid file name arguement"); 14157111Smuller return(-1); 14257111Smuller } 14357111Smuller 14457111Smuller /* 14557111Smuller * allocate FTREE node and add to the end of the linked list (args are 14657111Smuller * processed in the same order they were passed to pax). Get rid of any 14757111Smuller * trailing / the user may pass us. (watch out for / by itself). 14857111Smuller */ 14957111Smuller if ((ft = (FTREE *)malloc(sizeof(FTREE))) == NULL) { 15057111Smuller warn(0, "Unable to allocate memory for filename"); 15157111Smuller return(-1); 15257111Smuller } 15357111Smuller 15457111Smuller if (((len = strlen(str) - 1) > 0) && (str[len] == '/')) 15557111Smuller str[len] = '\0'; 15657111Smuller ft->fname = str; 15757111Smuller ft->refcnt = 0; 15857111Smuller ft->fow = NULL; 15957111Smuller if (fthead == NULL) { 16057111Smuller fttail = fthead = ft; 16157111Smuller return(0); 16257111Smuller } 16357111Smuller fttail->fow = ft; 16457111Smuller fttail = ft; 16557111Smuller return(0); 16657111Smuller } 16757111Smuller 16857111Smuller /* 16957111Smuller * ftree_sel() 17057111Smuller * this entry has been selected by pax. bump up reference count and handle 17157111Smuller * -n and -d processing. 17257111Smuller */ 17357111Smuller 17457111Smuller #if __STDC__ 17557111Smuller void 17657111Smuller ftree_sel(register ARCHD *arcn) 17757111Smuller #else 17857111Smuller void 17957111Smuller ftree_sel(arcn) 18057111Smuller register ARCHD *arcn; 18157111Smuller #endif 18257111Smuller { 18357111Smuller /* 18457111Smuller * set reference bit for this pattern. This linked list is only used 18557582Smuller * when file trees are supplied pax as args. The list is not used when 18657582Smuller * the trees are read from stdin. 18757111Smuller */ 18857581Smuller if (ftcur != NULL) 18957111Smuller ftcur->refcnt = 1; 19057111Smuller 19157111Smuller /* 19257111Smuller * if -n we are done with this arg, force a skip to the next arg when 19357111Smuller * pax asks for the next file in next_file(). 19457111Smuller * if -d we tell fts only to match the directory (if the arg is a dir) 19557111Smuller * and not the entire file tree rooted at that point. 19657111Smuller */ 19757111Smuller if (nflag) 19857111Smuller ftree_skip = 1; 19957111Smuller 20057111Smuller if (!dflag || (arcn->type != PAX_DIR)) 20157111Smuller return; 20257582Smuller 20357111Smuller if (ftent != NULL) 20457111Smuller (void)fts_set(ftsp, ftent, FTS_SKIP); 20557111Smuller } 20657111Smuller 20757111Smuller /* 20857111Smuller * ftree_chk() 20957111Smuller * called at end on pax execution. Prints all those file args that did not 21057111Smuller * have a selected member (reference count still 0) 21157111Smuller */ 21257111Smuller 21357111Smuller #if __STDC__ 21457111Smuller void 21557111Smuller ftree_chk(void) 21657111Smuller #else 21757111Smuller void 21857111Smuller ftree_chk() 21957111Smuller #endif 22057111Smuller { 22157111Smuller register FTREE *ft; 22257111Smuller register int wban = 0; 22357111Smuller 22457111Smuller /* 22557111Smuller * make sure all dir access times were reset. 22657111Smuller */ 22757111Smuller if (tflag) 22857111Smuller atdir_end(); 22957111Smuller 23057111Smuller /* 23157111Smuller * walk down list and check reference count. Print out those members 23257111Smuller * that never had a match 23357111Smuller */ 23457111Smuller for (ft = fthead; ft != NULL; ft = ft->fow) { 23557111Smuller if (ft->refcnt > 0) 23657111Smuller continue; 23757111Smuller if (wban == 0) { 23857111Smuller warn(1,"WARNING! These file names were not selected:"); 23957111Smuller ++wban; 24057111Smuller } 24157111Smuller (void)fprintf(stderr, "%s\n", ft->fname); 24257111Smuller } 24357111Smuller } 24457111Smuller 24557111Smuller /* 24657111Smuller * ftree_arg() 24757111Smuller * Get the next file arg for fts to process. Can be from either the linked 24857111Smuller * list or read from stdin when the user did not them as args to pax. Each 24957111Smuller * arg is processed until the first successful fts_open(). 25057111Smuller * Return: 25157111Smuller * 0 when the next arg is ready to go, -1 if out of file args (or EOF on 25257111Smuller * stdin). 25357111Smuller */ 25457111Smuller 25557111Smuller #if __STDC__ 25657111Smuller static int 25757111Smuller ftree_arg(void) 25857111Smuller #else 25957111Smuller static int 26057111Smuller ftree_arg() 26157111Smuller #endif 26257111Smuller { 26357111Smuller register char *pt; 26457111Smuller 26557111Smuller /* 26657111Smuller * close off the current file tree 26757111Smuller */ 26857111Smuller if (ftsp != NULL) { 26957111Smuller (void)fts_close(ftsp); 27057111Smuller ftsp = NULL; 27157111Smuller } 27257582Smuller 27357111Smuller /* 27457111Smuller * keep looping until we get a valid file tree to process. Stop when we 27557111Smuller * reach the end of the list (or get an eof on stdin) 27657111Smuller */ 27757111Smuller for(;;) { 27857111Smuller if (fthead == NULL) { 27957111Smuller /* 28057111Smuller * the user didn't supply any args, get the file trees 28157581Smuller * to process from stdin; 28257111Smuller */ 28357111Smuller if (fgets(farray[0], PAXPATHLEN+1, stdin) == NULL) 28457111Smuller return(-1); 28557111Smuller if ((pt = strchr(farray[0], '\n')) != NULL) 28657111Smuller *pt = '\0'; 28757111Smuller } else { 28857111Smuller /* 28957111Smuller * the user supplied the file args as arguements to pax 29057111Smuller */ 29157581Smuller if (ftcur == NULL) 29257111Smuller ftcur = fthead; 29357582Smuller else if ((ftcur = ftcur->fow) == NULL) 29457581Smuller return(-1); 29557111Smuller farray[0] = ftcur->fname; 29657111Smuller } 29757111Smuller 29857111Smuller /* 29957111Smuller * watch it, fts wants the file arg stored in a array of char 30057111Smuller * ptrs, with the last one a null. we use a two element array 30157111Smuller * and set farray[0] to point at the buffer with the file name 30257111Smuller * in it. We cannnot pass all the file args to fts at one shot 30357111Smuller * as we need to keep a handle on which file arg generates what 30457111Smuller * files (the -n and -d flags need this). If the open is 30557111Smuller * successful, return a 0. 30657111Smuller */ 30757111Smuller if ((ftsp = fts_open(farray, ftsopts, NULL)) != NULL) 30857111Smuller break; 30957111Smuller } 31057111Smuller return(0); 31157111Smuller } 31257111Smuller 31357111Smuller /* 31457111Smuller * next_file() 31557111Smuller * supplies the next file to process in the supplied archd structure. 31657111Smuller * Return: 31757111Smuller * 0 when contents of arcn have been set with the next file, -1 when done. 31857111Smuller */ 31957111Smuller 32057111Smuller #if __STDC__ 32157111Smuller int 32257111Smuller next_file(register ARCHD *arcn) 32357111Smuller #else 32457111Smuller int 32557111Smuller next_file(arcn) 32657111Smuller register ARCHD *arcn; 32757111Smuller #endif 32857111Smuller { 32957111Smuller register int cnt; 33057111Smuller time_t atime; 33157111Smuller time_t mtime; 33257111Smuller 33357111Smuller /* 33457111Smuller * ftree_sel() might have set the ftree_skip flag if the user has the 33557111Smuller * -n option and a file was selected from this file arg tree. (-n says 33657111Smuller * only one member is matched for each pattern) ftree_skip being 1 33757582Smuller * forces us to go to the next arg now. 33857111Smuller */ 33957111Smuller if (ftree_skip) { 34057111Smuller /* 34157111Smuller * clear and go to next arg 34257111Smuller */ 34357111Smuller ftree_skip = 0; 34457111Smuller if (ftree_arg() < 0) 34557111Smuller return(-1); 34657111Smuller } 34757111Smuller 34857111Smuller /* 34957111Smuller * loop until we get a valid file to process 35057111Smuller */ 35157111Smuller for(;;) { 35257111Smuller if ((ftent = fts_read(ftsp)) == NULL) { 35357111Smuller /* 35457111Smuller * out of files in this tree, go to next arg, if none 35557111Smuller * we are done 35657111Smuller */ 35757111Smuller if (ftree_arg() < 0) 35857111Smuller return(-1); 35957111Smuller continue; 36057111Smuller } 36157111Smuller 36257111Smuller /* 36357111Smuller * handle each type of fts_read() flag 36457111Smuller */ 36557111Smuller switch(ftent->fts_info) { 36657111Smuller case FTS_D: 36757111Smuller case FTS_DEFAULT: 36857111Smuller case FTS_F: 36957111Smuller case FTS_SL: 37057111Smuller case FTS_SLNONE: 37157111Smuller /* 37257111Smuller * these are all ok 37357111Smuller */ 37457111Smuller break; 37557111Smuller case FTS_DP: 37657111Smuller /* 37757111Smuller * already saw this directory. If the user wants file 37857111Smuller * access times reset, we use this to restore the 37957111Smuller * access time for this directory since this is the 38057111Smuller * last time we will see it in this file subtree 38157111Smuller * remember to force the time (this is -t on a read 38257111Smuller * directory, not a created directory). 38357111Smuller */ 38457111Smuller # ifdef NET2_FTS 38557111Smuller if (!tflag || (get_atdir(ftent->fts_statb.st_dev, 38657111Smuller ftent->fts_statb.st_ino, &mtime, &atime) < 0)) 38757111Smuller # else 38857111Smuller if (!tflag || (get_atdir(ftent->fts_statp->st_dev, 38957111Smuller ftent->fts_statp->st_ino, &mtime, &atime) < 0)) 39057111Smuller # endif 39157111Smuller continue; 39257111Smuller set_ftime(ftent->fts_path, mtime, atime, 1); 39357111Smuller continue; 39457111Smuller case FTS_DC: 39557111Smuller /* 39657111Smuller * fts claims a file system cycle 39757111Smuller */ 39857111Smuller warn(1,"File system cycle found at %s",ftent->fts_path); 39957111Smuller continue; 40057111Smuller case FTS_DNR: 40157111Smuller # ifdef NET2_FTS 40257111Smuller syswarn(1, errno, 40357111Smuller # else 40457111Smuller syswarn(1, ftent->fts_errno, 40557111Smuller # endif 40657111Smuller "Unable to read directory %s", ftent->fts_path); 40757111Smuller continue; 40857111Smuller case FTS_ERR: 40957111Smuller # ifdef NET2_FTS 41057111Smuller syswarn(1, errno, 41157111Smuller # else 41257111Smuller syswarn(1, ftent->fts_errno, 41357111Smuller # endif 41457111Smuller "File system traversal error"); 41557111Smuller continue; 41657111Smuller case FTS_NS: 41757111Smuller case FTS_NSOK: 41857111Smuller # ifdef NET2_FTS 41957111Smuller syswarn(1, errno, 42057111Smuller # else 42157111Smuller syswarn(1, ftent->fts_errno, 42257111Smuller # endif 42357111Smuller "Unable to access %s", ftent->fts_path); 42457111Smuller continue; 42557111Smuller } 42657111Smuller 42757111Smuller /* 42857111Smuller * ok got a file tree node to process. copy info into arcn 42957111Smuller * structure (initialize as required) 43057111Smuller */ 43157111Smuller arcn->skip = 0; 43257111Smuller arcn->pad = 0; 43357111Smuller arcn->ln_nlen = 0; 43457111Smuller arcn->ln_name[0] = '\0'; 43557111Smuller # ifdef NET2_FTS 43657111Smuller arcn->sb = ftent->fts_statb; 43757111Smuller # else 43857111Smuller arcn->sb = *(ftent->fts_statp); 43957111Smuller # endif 44057111Smuller 44157111Smuller /* 44257111Smuller * file type based set up and copy into the arcn struct 44357111Smuller * SIDE NOTE: 44457111Smuller * we try to reset the access time on all files and directories 44557111Smuller * we may read when the -t flag is specified. files are reset 44657111Smuller * when we close them after copying. we reset the directories 44757111Smuller * when we are done with their file tree (we also clean up at 44857111Smuller * end in case we cut short a file tree traversal). However 44957111Smuller * there is no way to reset access times on symlinks. 45057111Smuller */ 45157111Smuller switch(S_IFMT & arcn->sb.st_mode) { 45257111Smuller case S_IFDIR: 45357111Smuller arcn->type = PAX_DIR; 45457111Smuller if (!tflag) 45557111Smuller break; 45657111Smuller add_atdir(ftent->fts_path, arcn->sb.st_dev, 45757111Smuller arcn->sb.st_ino, arcn->sb.st_mtime, 45857111Smuller arcn->sb.st_atime); 45957111Smuller break; 46057111Smuller case S_IFCHR: 46157111Smuller arcn->type = PAX_CHR; 46257111Smuller break; 46357111Smuller case S_IFBLK: 46457111Smuller arcn->type = PAX_BLK; 46557111Smuller break; 46657111Smuller case S_IFREG: 46757111Smuller /* 46857111Smuller * only regular files with have data to store on the 46957111Smuller * archive. all others will store a zero length skip. 47057111Smuller * the skip field is used by pax for actual data it has 47157111Smuller * to read (or skip over). 47257111Smuller */ 47357111Smuller arcn->type = PAX_REG; 47457111Smuller arcn->skip = arcn->sb.st_size; 47557111Smuller break; 47657111Smuller case S_IFLNK: 47757111Smuller arcn->type = PAX_SLK; 47857111Smuller /* 47957111Smuller * have to read the symlink path from the file 48057111Smuller */ 48157111Smuller if ((cnt = readlink(ftent->fts_path, arcn->ln_name, 48257111Smuller PAXPATHLEN)) < 0) { 48357111Smuller syswarn(1, errno, "Unable to read symlink %s", 48457111Smuller ftent->fts_path); 48557111Smuller continue; 48657111Smuller } 48757111Smuller /* 48857111Smuller * set link name length, watch out readlink does not 48957111Smuller * allways null terminate the link path 49057111Smuller */ 49157111Smuller arcn->ln_name[cnt] = '\0'; 49257111Smuller arcn->ln_nlen = cnt; 49357111Smuller break; 49457111Smuller case S_IFSOCK: 49557111Smuller /* 49657111Smuller * under BSD storing a socket is senseless but we will 49757111Smuller * let the format specific write function make the 49857111Smuller * decision of what to do with it. 49957111Smuller */ 50057111Smuller arcn->type = PAX_SCK; 50157111Smuller break; 50257111Smuller case S_IFIFO: 50357111Smuller arcn->type = PAX_FIF; 50457111Smuller break; 50557111Smuller } 50657111Smuller break; 50757111Smuller } 50857111Smuller 50957111Smuller /* 51057111Smuller * copy file name, set file name length 51157111Smuller */ 51257111Smuller arcn->nlen = l_strncpy(arcn->name, ftent->fts_path, PAXPATHLEN+1); 51357582Smuller arcn->name[arcn->nlen] = '\0'; 51457111Smuller arcn->org_name = ftent->fts_path; 51557111Smuller return(0); 51657111Smuller } 517