void info_attach_exclist (struct tar_stat_info *dir) { struct excfile *file; struct exclist *head = NULL, *tail = NULL, *ent; struct vcs_ignore_file *vcsfile; if (dir->exclude_list) return; for (file = excfile_head; file; file = file->next) { if (faccessat (dir ? dir->fd : chdir_fd, file->name, F_OK, 0) == 0) { FILE *fp; struct exclude *ex = NULL; int fd = subfile_open (dir, file->name, O_RDONLY); if (fd == -1) { open_error (file->name); continue; } fp = fdopen (fd, "r"); if (!fp) { ERROR ((0, errno, _("%s: fdopen failed"), file->name)); close (fd); continue; } if (!ex) ex = new_exclude (); vcsfile = get_vcs_ignore_file (file->name); if (vcsfile->initfn) vcsfile->data = vcsfile->initfn (vcsfile->data); if (add_exclude_fp (vcsfile->addfn, ex, fp, EXCLUDE_WILDCARDS|EXCLUDE_ANCHORED, '\n', vcsfile->data)) { int e = errno; FATAL_ERROR ((0, e, "%s", quotearg_colon (file->name))); } fclose (fp); ent = xmalloc (sizeof (*ent)); ent->excluded = ex; ent->flags = file->flags == EXCL_DEFAULT ? file->flags : vcsfile->flags; ent->prev = tail; ent->next = NULL; if (tail) tail->next = ent; else head = ent; tail = ent; } } dir->exclude_list = head; }
/* 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; }