void savedir_diag (char const *name) { if (ignore_failed_read_option) savedir_warn (name); else savedir_error (name); }
/* Return the filenames in directory NAME, relative to the chdir_fd. If the directory does not exist, report error if MUST_EXIST is true. Return NULL on errors. */ char * tar_savedir (const char *name, int must_exist) { char *ret = NULL; DIR *dir = NULL; int fd = openat (chdir_fd, name, open_read_flags | O_DIRECTORY); if (fd < 0) { if (!must_exist && errno == ENOENT) return NULL; open_error (name); } else if (! ((dir = fdopendir (fd)) && (ret = streamsavedir (dir)))) savedir_error (name); if (dir ? closedir (dir) != 0 : 0 <= fd && close (fd) != 0) savedir_error (name); return ret; }
/* 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; }
/* Recursively scan the given directory. */ static const char * scan_directory (char *dir, dev_t device) { char *dirp = savedir (dir); /* for scanning directory */ char *name_buffer; /* directory, `/', and directory member */ size_t name_buffer_size; /* allocated size of name_buffer, minus 2 */ size_t name_length; /* used length in name_buffer */ struct stat stat_data; struct directory *directory; if (! dirp) savedir_error (dir); name_buffer_size = strlen (dir) + NAME_FIELD_SIZE; name_buffer = xmalloc (name_buffer_size + 2); strcpy (name_buffer, dir); if (! ISSLASH (dir[strlen (dir) - 1])) strcat (name_buffer, "/"); name_length = strlen (name_buffer); if (deref_stat (dereference_option, name_buffer, &stat_data)) { stat_diag (name_buffer); /* FIXME: used to be children = CHANGED_CHILDREN; but changed to: */ free (name_buffer); free (dirp); return NULL; } directory = procdir (name_buffer, &stat_data, device, 0, NULL); if (dirp && directory->children != NO_CHILDREN) { char *entry; /* directory entry being scanned */ size_t entrylen; /* length of directory entry */ dumpdir_iter_t itr; makedumpdir (directory, dirp); for (entry = dumpdir_first (directory->dump, 1, &itr); entry; entry = dumpdir_next (itr)) { entrylen = strlen (entry); if (name_buffer_size <= entrylen - 1 + name_length) { do name_buffer_size += NAME_FIELD_SIZE; while (name_buffer_size <= entrylen - 1 + name_length); name_buffer = xrealloc (name_buffer, name_buffer_size + 2); } strcpy (name_buffer + name_length, entry + 1); if (*entry == 'I') /* Ignored entry */ *entry = 'N'; else if (excluded_name (name_buffer)) *entry = 'N'; else { if (deref_stat (dereference_option, name_buffer, &stat_data)) { stat_diag (name_buffer); *entry = 'N'; continue; } if (S_ISDIR (stat_data.st_mode)) { int pd_flag = (verbose_option ? PD_VERBOSE : 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 (name_buffer, &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); } free (name_buffer); if (dirp) free (dirp); return directory->dump ? directory->dump->contents : NULL; }