/* Output incremental data for the directory ENTRY to the file DATA. Return nonzero if successful, preserving errno on write failure. */ static bool write_directory_file_entry (void *entry, void *data) { struct directory const *directory = entry; FILE *fp = data; if (DIR_IS_FOUND (directory)) { char buf[SYSINT_BUFSIZE]; char const *s; s = DIR_IS_NFS (directory) ? "1" : "0"; fwrite (s, 2, 1, fp); s = sysinttostr (directory->mtime.tv_sec, TYPE_MINIMUM (time_t), TYPE_MAXIMUM (time_t), buf); fwrite (s, strlen (s) + 1, 1, fp); s = imaxtostr (directory->mtime.tv_nsec, buf); fwrite (s, strlen (s) + 1, 1, fp); s = sysinttostr (directory->device_number, TYPE_MINIMUM (dev_t), TYPE_MAXIMUM (dev_t), buf); fwrite (s, strlen (s) + 1, 1, fp); s = sysinttostr (directory->inode_number, TYPE_MINIMUM (ino_t), TYPE_MAXIMUM (ino_t), buf); fwrite (s, strlen (s) + 1, 1, fp); fwrite (directory->name, strlen (directory->name) + 1, 1, fp); if (directory->dump) { const char *p; struct dumpdir_iter *itr; for (p = dumpdir_first (directory->dump, 0, &itr); p; p = dumpdir_next (itr)) fwrite (p, strlen (p) + 1, 1, fp); free (itr); } fwrite ("\0\0", 2, 1, fp); } return ! ferror (fp); }
/* Output incremental data for the directory ENTRY to the file DATA. Return nonzero if successful, preserving errno on write failure. */ static bool write_directory_file_entry (void *entry, void *data) { struct directory const *directory = entry; FILE *fp = data; if (DIR_IS_FOUND (directory)) { char buf[UINTMAX_STRSIZE_BOUND]; char *s; s = DIR_IS_NFS (directory) ? "1" : "0"; fwrite (s, 2, 1, fp); s = (TYPE_SIGNED (time_t) ? imaxtostr (directory->mtime.tv_sec, buf) : umaxtostr (directory->mtime.tv_sec, buf)); fwrite (s, strlen (s) + 1, 1, fp); s = umaxtostr (directory->mtime.tv_nsec, buf); fwrite (s, strlen (s) + 1, 1, fp); s = umaxtostr (directory->device_number, buf); fwrite (s, strlen (s) + 1, 1, fp); s = umaxtostr (directory->inode_number, buf); fwrite (s, strlen (s) + 1, 1, fp); fwrite (directory->name, strlen (directory->name) + 1, 1, fp); if (directory->dump) { const char *p; dumpdir_iter_t itr; for (p = dumpdir_first (directory->dump, 0, &itr); p; p = dumpdir_next (itr)) fwrite (p, strlen (p) + 1, 1, fp); free (itr); } fwrite ("\0\0", 2, 1, fp); } return ! ferror (fp); }
/* 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; }