/* DIR is the operand of a -C option; add it to vector of chdir targets, and return the index of its location. */ int chdir_arg(char const *dir) { char *absdir; if (wd_count == wd_alloc) { if (wd_alloc == 0) wd_alloc = 2; wd = x2nrealloc (wd, &wd_alloc, sizeof *wd); if (! wd_count) { char path[PATH_MAX+1]; memset(path, 0, sizeof(path)); getcwd(path, sizeof(path) - 1); wd[wd_count].name = "."; wd[wd_count].abspath = strdup(path); wd[wd_count].fd = AT_FDCWD; wd_count++; } } /* Optimize the common special case of the working directory, or the working directory as a prefix. */ if (dir[0]) { while (dir[0] == '.' && ISSLASH (dir[1])) for (dir += 2; ISSLASH (*dir); dir++) continue; if (! dir[dir[0] == '.']) return wd_count - 1; } /* If the given name is absolute, use it to represent this directory; otherwise, construct a name based on the previous -C option. */ if (IS_ABSOLUTE_FILE_NAME (dir)) absdir = xstrdup (dir); else if (wd[wd_count - 1].abspath) { namebuf_t nbuf = namebuf_create (wd[wd_count - 1].abspath); namebuf_add_dir (nbuf, dir); absdir = namebuf_finish (nbuf); } else absdir = 0; wd[wd_count].name = dir; wd[wd_count].abspath = absdir; wd[wd_count].fd = 0; return wd_count++; }
/* Recursively scan the given directory DIR. DEVICE is the device number where DIR resides (for --one-file-system). If CMDLINE is true, the directory name was explicitly listed in the command line. Unless *PDIR is NULL, store there a pointer to the struct directory describing DIR. */ struct directory * scan_directory (char *dir, dev_t device, bool cmdline) { char *dirp = savedir (dir); /* for scanning directory */ namebuf_t nbuf; char *tmp; struct stat stat_data; struct directory *directory; char ch; if (! dirp) savedir_error (dir); tmp = xstrdup (dir); zap_slashes (tmp); if (deref_stat (dereference_option, tmp, &stat_data)) { dir_removed_diag (tmp, cmdline, stat_diag); free (tmp); free (dirp); return NULL; } directory = procdir (tmp, &stat_data, device, (cmdline ? PD_FORCE_INIT : 0), &ch); free (tmp); nbuf = namebuf_create (dir); if (dirp && directory->children != NO_CHILDREN) { char *entry; /* directory entry being scanned */ dumpdir_iter_t itr; makedumpdir (directory, dirp); for (entry = dumpdir_first (directory->dump, 1, &itr); entry; entry = dumpdir_next (itr)) { char *full_name = namebuf_name (nbuf, entry + 1); if (*entry == 'I') /* Ignored entry */ *entry = 'N'; else if (excluded_name (full_name)) *entry = 'N'; else { if (deref_stat (dereference_option, full_name, &stat_data)) { file_removed_diag (full_name, false, stat_diag); *entry = 'N'; continue; } if (S_ISDIR (stat_data.st_mode)) { int pd_flag = 0; if (!recursion_option) pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN; else if (directory->children == ALL_CHILDREN) pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN; *entry = 'D'; procdir (full_name, &stat_data, device, pd_flag, entry); } else if (one_file_system_option && device != stat_data.st_dev) *entry = 'N'; else if (*entry == 'Y') /* New entry, skip further checks */; /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */ else if (OLDER_STAT_TIME (stat_data, m) && (!after_date_option || OLDER_STAT_TIME (stat_data, c))) *entry = 'N'; else *entry = 'Y'; } } free (itr); } namebuf_free (nbuf); if (dirp) free (dirp); return directory; }
/* Recursively scan the directory identified by ST. */ struct directory * scan_directory (struct tar_stat_info *st) { char const *dir = st->orig_file_name; char *dirp = get_directory_entries (st); dev_t device = st->stat.st_dev; bool cmdline = ! st->parent; namebuf_t nbuf; char *tmp; struct directory *directory; char ch; if (! dirp) savedir_error (dir); info_attach_exclist (st); tmp = xstrdup (dir); zap_slashes (tmp); directory = procdir (tmp, st, (cmdline ? PD_FORCE_INIT : 0), &ch); free (tmp); nbuf = namebuf_create (dir); if (dirp) { if (directory->children != NO_CHILDREN) { char *entry; /* directory entry being scanned */ struct dumpdir_iter *itr; makedumpdir (directory, dirp); for (entry = dumpdir_first (directory->dump, 1, &itr); entry; entry = dumpdir_next (itr)) { char *full_name = namebuf_name (nbuf, entry + 1); if (*entry == 'I') /* Ignored entry */ *entry = 'N'; else if (excluded_name (full_name, st)) *entry = 'N'; else { int fd = st->fd; void (*diag) (char const *) = 0; struct tar_stat_info stsub; tar_stat_init (&stsub); if (fd < 0) { errno = - fd; diag = open_diag; } else if (fstatat (fd, entry + 1, &stsub.stat, fstatat_flags) != 0) diag = stat_diag; else if (S_ISDIR (stsub.stat.st_mode)) { int subfd = subfile_open (st, entry + 1, open_read_flags); if (subfd < 0) diag = open_diag; else { stsub.fd = subfd; if (fstat (subfd, &stsub.stat) != 0) diag = stat_diag; } } if (diag) { file_removed_diag (full_name, false, diag); *entry = 'N'; } else if (S_ISDIR (stsub.stat.st_mode)) { int pd_flag = 0; if (!recursion_option) pd_flag |= PD_FORCE_CHILDREN | NO_CHILDREN; else if (directory->children == ALL_CHILDREN) pd_flag |= PD_FORCE_CHILDREN | ALL_CHILDREN; *entry = 'D'; stsub.parent = st; procdir (full_name, &stsub, pd_flag, entry); restore_parent_fd (&stsub); } else if (one_file_system_option && device != stsub.stat.st_dev) *entry = 'N'; else if (*entry == 'Y') /* New entry, skip further checks */; /* FIXME: if (S_ISHIDDEN (stat_data.st_mode))?? */ else if (OLDER_STAT_TIME (stsub.stat, m) && (!after_date_option || OLDER_STAT_TIME (stsub.stat, c))) *entry = 'N'; else *entry = 'Y'; tar_stat_destroy (&stsub); } } free (itr); } else if (directory->tagfile) maketagdumpdir (directory); } namebuf_free (nbuf); free (dirp); return directory; }