/* * Test whether current entry is a dir or link to a dir. */ int tree_current_is_dir(struct tree *t) { const struct stat *st; /* * If we already have lstat() info, then try some * cheap tests to determine if this is a dir. */ if (t->flags & hasLstat) { /* If lstat() says it's a dir, it must be a dir. */ if (S_ISDIR(tree_current_lstat(t)->st_mode)) return 1; /* Not a dir; might be a link to a dir. */ /* If it's not a link, then it's not a link to a dir. */ if (!S_ISLNK(tree_current_lstat(t)->st_mode)) return 0; /* * It's a link, but we don't know what it's a link to, * so we'll have to use stat(). */ } st = tree_current_stat(t); /* If we can't stat it, it's not a dir. */ if (st == NULL) return 0; /* Use the definitive test. Hopefully this is cached. */ return (S_ISDIR(st->st_mode)); }
/* * Test whether current entry is a physical directory. Usually, we * already have at least one of stat() or lstat() in memory, so we * use tricks to try to avoid an extra trip to the disk. */ int tree_current_is_physical_dir(struct tree *t) { const struct stat *st; /* * If stat() says it isn't a dir, then it's not a dir. * If stat() data is cached, this check is free, so do it first. */ if ((t->flags & hasStat) && (!S_ISDIR(tree_current_stat(t)->st_mode))) return 0; /* * Either stat() said it was a dir (in which case, we have * to determine whether it's really a link to a dir) or * stat() info wasn't available. So we use lstat(), which * hopefully is already cached. */ st = tree_current_lstat(t); /* If we can't stat it, it's not a dir. */ if (st == NULL) return 0; /* Use the definitive test. Hopefully this is cached. */ return (S_ISDIR(st->st_mode)); }
int main(int argc, char **argv) { size_t max_path_len = 0; int max_depth = 0; system("pwd"); while (*++argv) { struct tree *t = tree_open(*argv); while (tree_next(t)) { size_t path_len = tree_current_pathlen(t); int depth = tree_current_depth(t); if (path_len > max_path_len) max_path_len = path_len; if (depth > max_depth) max_depth = depth; printf("%s\n", tree_current_path(t)); if (S_ISDIR(tree_current_lstat(t)->st_mode)) tree_descend(t); /* Descend into every dir. */ } tree_close(t); printf("Max path length: %d\n", max_path_len); printf("Max depth: %d\n", max_depth); printf("Final open count: %d\n", t->openCount); printf("Max open count: %d\n", t->maxOpenCount); fflush(stdout); system("pwd"); } return (0); }
/* * Test whether current entry is a symbolic link. */ int tree_current_is_physical_link(struct tree *t) { const struct stat *st = tree_current_lstat(t); if (st == NULL) return 0; return (S_ISLNK(st->st_mode)); }
/* * Write tree to the archive. If pathname is a symbolic link it will be * followed. Other symbolic links are stored as such to the archive. */ static int shar_write_tree(struct archive *a, const char *pathname) { struct tree *t; const struct stat *lst, *st; int error = 0; int tree_ret; int first; assert(a != NULL); assert(pathname != NULL); t = tree_open(pathname); for (first = 1; (tree_ret = tree_next(t)); first = 0) { if (tree_ret == TREE_ERROR_DIR) { warnx("%s: %s", tree_current_path(t), strerror(tree_errno(t))); error = 1; continue; } else if (tree_ret != TREE_REGULAR) continue; if ((lst = tree_current_lstat(t)) == NULL) { warn("%s", tree_current_path(t)); error = 1; continue; } /* * If the symlink was given on command line then * follow it rather than write it as symlink. */ if (first && S_ISLNK(lst->st_mode)) { if ((st = tree_current_stat(t)) == NULL) { warn("%s", tree_current_path(t)); error = 1; continue; } } else st = lst; if (shar_write_entry(a, tree_current_path(t), tree_current_access_path(t), st) != ARCHIVE_OK) error = 1; tree_descend(t); } tree_close(t); return ((error != 0) ? ARCHIVE_WARN : ARCHIVE_OK); }
/* * Called by the client to mark the directory just returned from * tree_next() as needing to be visited. */ void tree_descend(struct tree *t) { const struct stat *s = tree_current_lstat(t); if (S_ISDIR(s->st_mode)) { tree_add(t, t->basename); t->stack->flags |= isDir; } if (S_ISLNK(s->st_mode) && S_ISDIR(tree_current_stat(t)->st_mode)) { tree_add(t, t->basename); t->stack->flags |= isDirLink; } }
/* * Add the file or dir hierarchy named by 'path' to the archive */ static void write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) { struct archive_entry *entry = NULL, *spare_entry = NULL; struct tree *tree; char symlink_mode = bsdtar->symlink_mode; dev_t first_dev = 0; int dev_recorded = 0; int tree_ret; tree = tree_open(path); if (!tree) { lafe_warnc(errno, "%s: Cannot open", path); bsdtar->return_value = 1; return; } while ((tree_ret = tree_next(tree)) != 0) { int r; const char *name = tree_current_path(tree); const struct stat *st = NULL; /* info to use for this entry */ const struct stat *lst = NULL; /* lstat() information */ int descend; if (tree_ret == TREE_ERROR_FATAL) lafe_errc(1, tree_errno(tree), "%s: Unable to continue traversing directory tree", name); if (tree_ret == TREE_ERROR_DIR) { lafe_warnc(errno, "%s: Couldn't visit directory", name); bsdtar->return_value = 1; } if (tree_ret != TREE_REGULAR) continue; /* * If this file/dir is excluded by a filename * pattern, skip it. */ if (lafe_excluded(bsdtar->matching, name)) continue; /* * Get lstat() info from the tree library. */ lst = tree_current_lstat(tree); if (lst == NULL) { /* Couldn't lstat(); must not exist. */ lafe_warnc(errno, "%s: Cannot stat", name); /* Return error if files disappear during traverse. */ bsdtar->return_value = 1; continue; } /* * Distinguish 'L'/'P'/'H' symlink following. */ switch(symlink_mode) { case 'H': /* 'H': After the first item, rest like 'P'. */ symlink_mode = 'P'; /* 'H': First item (from command line) like 'L'. */ /* FALLTHROUGH */ case 'L': /* 'L': Do descend through a symlink to dir. */ descend = tree_current_is_dir(tree); /* 'L': Follow symlinks to files. */ archive_read_disk_set_symlink_logical(bsdtar->diskreader); /* 'L': Archive symlinks as targets, if we can. */ st = tree_current_stat(tree); if (st != NULL) break; /* If stat fails, we have a broken symlink; * in that case, don't follow the link. */ /* FALLTHROUGH */ default: /* 'P': Don't descend through a symlink to dir. */ descend = tree_current_is_physical_dir(tree); /* 'P': Don't follow symlinks to files. */ archive_read_disk_set_symlink_physical(bsdtar->diskreader); /* 'P': Archive symlinks as symlinks. */ st = lst; break; } if (bsdtar->option_no_subdirs) descend = 0; /* * Are we about to cross to a new filesystem? */ if (!dev_recorded) { /* This is the initial file system. */ first_dev = lst->st_dev; dev_recorded = 1; } else if (lst->st_dev == first_dev) { /* The starting file system is always acceptable. */ } else if (descend == 0) { /* We're not descending, so no need to check. */ } else if (bsdtar->option_dont_traverse_mounts) { descend = 0; } else { /* We're prepared to cross a mount point. */ /* XXX TODO: check whether this filesystem is * synthetic and/or local. Add a new * --local-only option to skip non-local * filesystems. Skip synthetic filesystems * regardless. * * The results should be cached, since * tree.c doesn't usually visit a directory * and the directory contents together. A simple * move-to-front list should perform quite well. * * This is going to be heavily OS dependent: * FreeBSD's statfs() in conjunction with getvfsbyname() * provides all of this; NetBSD's statvfs() does * most of it; other systems will vary. */ } /* * In -u mode, check that the file is newer than what's * already in the archive; in all modes, obey --newerXXX flags. */ if (!new_enough(bsdtar, name, st)) { if (!descend) continue; if (bsdtar->option_interactive && !yes("add '%s'", name)) continue; tree_descend(tree); continue; } archive_entry_free(entry); entry = archive_entry_new(); archive_entry_set_pathname(entry, name); archive_entry_copy_sourcepath(entry, tree_current_access_path(tree)); /* Populate the archive_entry with metadata from the disk. */ /* XXX TODO: Arrange to open a regular file before * calling this so we can pass in an fd and shorten * the race to query metadata. The linkify dance * makes this more complex than it might sound. */ #if defined(_WIN32) && !defined(__CYGWIN__) /* TODO: tree.c uses stat(), which is badly broken * on Windows. To fix this, we should * deprecate tree_current_stat() and provide a new * call tree_populate_entry(t, entry). This call * would use stat() internally on POSIX and * GetInfoByFileHandle() internally on Windows. * This would be another step towards a tree-walker * that can be integrated deep into libarchive. * For now, just set st to NULL on Windows; * archive_read_disk_entry_from_file() should * be smart enough to use platform-appropriate * ways to probe file information. */ st = NULL; #endif r = archive_read_disk_entry_from_file(bsdtar->diskreader, entry, -1, st); if (bsdtar->uid >= 0) { archive_entry_set_uid(entry, bsdtar->uid); if (!bsdtar->uname) archive_entry_set_uname(entry, archive_read_disk_uname(bsdtar->diskreader, bsdtar->uid)); } if (bsdtar->gid >= 0) { archive_entry_set_gid(entry, bsdtar->gid); if (!bsdtar->gname) archive_entry_set_gname(entry, archive_read_disk_gname(bsdtar->diskreader, bsdtar->gid)); } if (bsdtar->uname) archive_entry_set_uname(entry, bsdtar->uname); if (bsdtar->gname) archive_entry_set_gname(entry, bsdtar->gname); if (r != ARCHIVE_OK) lafe_warnc(archive_errno(bsdtar->diskreader), "%s", archive_error_string(bsdtar->diskreader)); if (r < ARCHIVE_WARN) continue; /* XXX TODO: Just use flag data from entry; avoid the * duplicate check here. */ /* * If this file/dir is flagged "nodump" and we're * honoring such flags, skip this file/dir. */ #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) /* BSD systems store flags in struct stat */ if (bsdtar->option_honor_nodump && (lst->st_flags & UF_NODUMP)) continue; #endif #if defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) /* Linux uses ioctl to read flags. */ if (bsdtar->option_honor_nodump) { int fd = open(name, O_RDONLY | O_NONBLOCK | O_BINARY); if (fd >= 0) { unsigned long fflags; int r = ioctl(fd, EXT2_IOC_GETFLAGS, &fflags); close(fd); if (r >= 0 && (fflags & EXT2_NODUMP_FL)) continue; } } #endif #ifdef __APPLE__ if (bsdtar->enable_copyfile) { /* If we're using copyfile(), ignore "._XXX" files. */ const char *bname = strrchr(name, '/'); if (bname == NULL) bname = name; else ++bname; if (bname[0] == '.' && bname[1] == '_') continue; } else { /* If not, drop the copyfile() data. */ archive_entry_copy_mac_metadata(entry, NULL, 0); } #endif /* * If the user vetoes this file/directory, skip it. * We want this to be fairly late; if some other * check would veto this file, we shouldn't bother * the user with it. */ if (bsdtar->option_interactive && !yes("add '%s'", name)) continue; if (descend) tree_descend(tree); /* * Rewrite the pathname to be archived. If rewrite * fails, skip the entry. */ if (edit_pathname(bsdtar, entry)) continue; /* Display entry as we process it. * This format is required by SUSv2. */ if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(entry)); /* Non-regular files get archived with zero size. */ if (archive_entry_filetype(entry) != AE_IFREG) archive_entry_set_size(entry, 0); archive_entry_linkify(bsdtar->resolver, &entry, &spare_entry); while (entry != NULL) { write_file(bsdtar, a, entry); archive_entry_free(entry); entry = spare_entry; spare_entry = NULL; } if (bsdtar->verbose) fprintf(stderr, "\n"); } archive_entry_free(entry); tree_close(tree); }
/* * Add the file or dir hierarchy named by 'path' to the archive */ static void write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) { struct archive_entry *entry = NULL, *spare_entry = NULL; struct tree *tree; char symlink_mode = bsdtar->symlink_mode; dev_t first_dev = 0; int dev_recorded = 0; int tree_ret; dev_t last_dev = 0; char * fstype; tree = tree_open(path); if (!tree) { bsdtar_warnc(bsdtar, errno, "%s: Cannot open", path); bsdtar->return_value = 1; return; } while ((tree_ret = tree_next(tree))) { int r; const char *name = tree_current_path(tree); const struct stat *st = NULL; /* info to use for this entry */ const struct stat *lst = NULL; /* lstat() information */ int descend; if (truncate_archive(bsdtar)) break; if (checkpoint_archive(bsdtar, 0)) exit(1); disk_pause(bsdtar); if (network_select(0)) exit(1); if (tree_ret == TREE_ERROR_FATAL) bsdtar_errc(bsdtar, 1, tree_errno(tree), "%s: Unable to continue traversing directory tree", name); if (tree_ret == TREE_ERROR_DIR) { bsdtar_warnc(bsdtar, errno, "%s: Couldn't visit directory", name); bsdtar->return_value = 1; } if (tree_ret != TREE_REGULAR) continue; /* * If this file/dir is excluded by a filename * pattern, skip it. */ if (excluded(bsdtar, name)) continue; /* * Get lstat() info from the tree library. */ lst = tree_current_lstat(tree); if (lst == NULL) { /* Couldn't lstat(); must not exist. */ bsdtar_warnc(bsdtar, errno, "%s: Cannot stat", name); /* Return error if files disappear during traverse. */ bsdtar->return_value = 1; continue; } /* * Distinguish 'L'/'P'/'H' symlink following. */ switch(symlink_mode) { case 'H': /* 'H': After the first item, rest like 'P'. */ symlink_mode = 'P'; /* 'H': First item (from command line) like 'L'. */ /* FALLTHROUGH */ case 'L': /* 'L': Do descend through a symlink to dir. */ descend = tree_current_is_dir(tree); /* 'L': Follow symlinks to files. */ archive_read_disk_set_symlink_logical(bsdtar->diskreader); /* 'L': Archive symlinks as targets, if we can. */ st = tree_current_stat(tree); if (st != NULL) break; /* If stat fails, we have a broken symlink; * in that case, don't follow the link. */ /* FALLTHROUGH */ default: /* 'P': Don't descend through a symlink to dir. */ descend = tree_current_is_physical_dir(tree); /* 'P': Don't follow symlinks to files. */ archive_read_disk_set_symlink_physical(bsdtar->diskreader); /* 'P': Archive symlinks as symlinks. */ st = lst; break; } if (bsdtar->option_no_subdirs) descend = 0; /* * If user has asked us not to cross mount points, * then don't descend into a dir on a different * device. */ if (!dev_recorded) { last_dev = first_dev = lst->st_dev; dev_recorded = 1; } if (bsdtar->option_dont_traverse_mounts) { if (lst->st_dev != first_dev) descend = 0; } /* * If the user did not specify --insane-filesystems, do not * cross into a new filesystem which is known to be synthetic. * Note that we will archive synthetic filesystems if we are * explicitly told to do so. */ if ((bsdtar->option_insane_filesystems == 0) && (descend != 0) && (lst->st_dev != last_dev)) { fstype = getfstype(tree_current_access_path(tree)); if (fstype == NULL) bsdtar_errc(bsdtar, 1, errno, "%s: Error getting filesystem type", name); if (getfstype_issynthetic(fstype)) { if (!bsdtar->option_quiet) bsdtar_warnc(bsdtar, 0, "Not descending into filesystem of type %s: %s", fstype, name); descend = 0; } else { /* This device is ok to archive. */ last_dev = lst->st_dev; } free(fstype); } /* * In -u mode, check that the file is newer than what's * already in the archive; in all modes, obey --newerXXX flags. */ if (!new_enough(bsdtar, name, st)) { if (!descend) continue; if (bsdtar->option_interactive && !yes("add '%s'", name)) continue; tree_descend(tree); continue; } archive_entry_free(entry); entry = archive_entry_new(); archive_entry_set_pathname(entry, name); archive_entry_copy_sourcepath(entry, tree_current_access_path(tree)); /* Populate the archive_entry with metadata from the disk. */ /* XXX TODO: Arrange to open a regular file before * calling this so we can pass in an fd and shorten * the race to query metadata. The linkify dance * makes this more complex than it might sound. */ r = archive_read_disk_entry_from_file(bsdtar->diskreader, entry, -1, st); if (r != ARCHIVE_OK) bsdtar_warnc(bsdtar, archive_errno(bsdtar->diskreader), "%s", archive_error_string(bsdtar->diskreader)); if (r < ARCHIVE_WARN) continue; /* XXX TODO: Just use flag data from entry; avoid the * duplicate check here. */ /* * If this file/dir is flagged "nodump" and we're * honoring such flags, skip this file/dir. */ #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP) /* BSD systems store flags in struct stat */ if (bsdtar->option_honor_nodump && (lst->st_flags & UF_NODUMP)) continue; #endif #if defined(EXT2_NODUMP_FL) /* Linux uses ioctl to read flags. */ if (bsdtar->option_honor_nodump) { unsigned long fflags, dummy; archive_entry_fflags(entry, &fflags, &dummy); if (fflags & EXT2_NODUMP_FL) continue; } #endif /* * Don't back up the cache directory or any files inside it. */ if ((lst->st_ino == bsdtar->cachedir_ino) && (lst->st_dev == bsdtar->cachedir_dev)) { if (!bsdtar->option_quiet) bsdtar_warnc(bsdtar, 0, "Not adding cache directory to archive: %s", name); continue; } /* * If the user vetoes this file/directory, skip it. * We want this to be fairly late; if some other * check would veto this file, we shouldn't bother * the user with it. */ if (bsdtar->option_interactive && !yes("add '%s'", name)) continue; /* Note: if user vetoes, we won't descend. */ if (descend) tree_descend(tree); /* * Rewrite the pathname to be archived. If rewrite * fails, skip the entry. */ if (edit_pathname(bsdtar, entry)) continue; /* * If this is a socket, skip the entry: POSIX requires that * pax(1) emit a "diagnostic message" (i.e., warning) that * sockets cannot be archived, but this can make backups of * running systems very noisy. */ if (S_ISSOCK(st->st_mode)) continue; /* Display entry as we process it. * This format is required by SUSv2. */ if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(entry)); /* * If the user hasn't specifically asked to have the access * time stored, zero it. At the moment this usually only * matters for files which have flags set, since the "posix * restricted" format doesn't store access times for most * other files. */ if (bsdtar->option_store_atime == 0) archive_entry_set_atime(entry, 0, 0); /* Non-regular files get archived with zero size. */ if (!S_ISREG(st->st_mode)) archive_entry_set_size(entry, 0); /* Record what we're doing, for SIGINFO / SIGUSR1. */ siginfo_setinfo(bsdtar, "adding", archive_entry_pathname(entry), archive_entry_size(entry)); archive_entry_linkify(bsdtar->resolver, &entry, &spare_entry); /* Handle SIGINFO / SIGUSR1 request if one was made. */ siginfo_printinfo(bsdtar, 0); while (entry != NULL) { write_entry_backend(bsdtar, a, entry, st, tree_current_realpath(tree)); archive_entry_free(entry); entry = spare_entry; spare_entry = NULL; } if (bsdtar->verbose) fprintf(stderr, "\n"); } archive_entry_free(entry); if (tree_close(tree)) bsdtar_errc(bsdtar, 1, 0, "Error traversing directory tree"); }
/* * Add the file or dir hierarchy named by 'path' to the archive */ static void write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) { struct archive_entry *entry = NULL, *spare_entry = NULL; struct tree *tree; char symlink_mode = bsdtar->symlink_mode; dev_t first_dev = 0; int dev_recorded = 0; int tree_ret; tree = tree_open(path); if (!tree) { bsdtar_warnc(bsdtar, errno, "%s: Cannot open", path); bsdtar->return_value = 1; return; } while ((tree_ret = tree_next(tree))) { int r; const char *name = tree_current_path(tree); const struct stat *st = NULL; /* info to use for this entry */ const struct stat *lst = NULL; /* lstat() information */ int descend; if (tree_ret == TREE_ERROR_FATAL) bsdtar_errc(bsdtar, 1, tree_errno(tree), "%s: Unable to continue traversing directory tree", name); if (tree_ret == TREE_ERROR_DIR) { bsdtar_warnc(bsdtar, errno, "%s: Couldn't visit directory", name); bsdtar->return_value = 1; } if (tree_ret != TREE_REGULAR) continue; /* * If this file/dir is excluded by a filename * pattern, skip it. */ if (excluded(bsdtar, name)) continue; /* * Get lstat() info from the tree library. */ lst = tree_current_lstat(tree); if (lst == NULL) { /* Couldn't lstat(); must not exist. */ bsdtar_warnc(bsdtar, errno, "%s: Cannot stat", name); /* Return error if files disappear during traverse. */ bsdtar->return_value = 1; continue; } /* * Distinguish 'L'/'P'/'H' symlink following. */ switch(symlink_mode) { case 'H': /* 'H': After the first item, rest like 'P'. */ symlink_mode = 'P'; /* 'H': First item (from command line) like 'L'. */ /* FALLTHROUGH */ case 'L': /* 'L': Do descend through a symlink to dir. */ descend = tree_current_is_dir(tree); /* 'L': Follow symlinks to files. */ archive_read_disk_set_symlink_logical(bsdtar->diskreader); /* 'L': Archive symlinks as targets, if we can. */ st = tree_current_stat(tree); if (st != NULL) break; /* If stat fails, we have a broken symlink; * in that case, don't follow the link. */ /* FALLTHROUGH */ default: /* 'P': Don't descend through a symlink to dir. */ descend = tree_current_is_physical_dir(tree); /* 'P': Don't follow symlinks to files. */ archive_read_disk_set_symlink_physical(bsdtar->diskreader); /* 'P': Archive symlinks as symlinks. */ st = lst; break; } /* * If user has asked us not to cross mount points, * then don't descend into into a dir on a different * device. */ if (!dev_recorded) { first_dev = lst->st_dev; dev_recorded = 1; } if (bsdtar->option_dont_traverse_mounts) { if (lst->st_dev != first_dev) descend = 0; } /* * In -u mode, check that the file is newer than what's * already in the archive; in all modes, obey --newerXXX flags. */ if (!new_enough(bsdtar, name, st)) continue; archive_entry_free(entry); entry = archive_entry_new(); archive_entry_set_pathname(entry, name); archive_entry_copy_sourcepath(entry, tree_current_access_path(tree)); /* Populate the archive_entry with metadata from the disk. */ /* XXX TODO: Arrange to open a regular file before * calling this so we can pass in an fd and shorten * the race to query metadata. The linkify dance * makes this more complex than it might sound. */ r = archive_read_disk_entry_from_file(bsdtar->diskreader, entry, -1, st); if (r != ARCHIVE_OK) bsdtar_warnc(bsdtar, archive_errno(bsdtar->diskreader), archive_error_string(bsdtar->diskreader)); if (r < ARCHIVE_WARN) continue; /* XXX TODO: Just use flag data from entry; avoid the * duplicate check here. */ /* * If this file/dir is flagged "nodump" and we're * honoring such flags, skip this file/dir. */ #ifdef HAVE_STRUCT_STAT_ST_FLAGS /* BSD systems store flags in struct stat */ if (bsdtar->option_honor_nodump && (lst->st_flags & UF_NODUMP)) continue; #endif #if defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) /* Linux uses ioctl to read flags. */ if (bsdtar->option_honor_nodump) { int fd = open(name, O_RDONLY | O_NONBLOCK); if (fd >= 0) { unsigned long fflags; int r = ioctl(fd, EXT2_IOC_GETFLAGS, &fflags); close(fd); if (r >= 0 && (fflags & EXT2_NODUMP_FL)) continue; } } #endif /* * If the user vetoes this file/directory, skip it. * We want this to be fairly late; if some other * check would veto this file, we shouldn't bother * the user with it. */ if (bsdtar->option_interactive && !yes("add '%s'", name)) continue; /* Note: if user vetoes, we won't descend. */ if (descend && !bsdtar->option_no_subdirs) tree_descend(tree); /* * Rewrite the pathname to be archived. If rewrite * fails, skip the entry. */ if (edit_pathname(bsdtar, entry)) continue; /* Display entry as we process it. * This format is required by SUSv2. */ if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(entry)); /* Non-regular files get archived with zero size. */ if (!S_ISREG(st->st_mode)) archive_entry_set_size(entry, 0); /* Record what we're doing, for SIGINFO / SIGUSR1. */ siginfo_setinfo(bsdtar, "adding", archive_entry_pathname(entry), archive_entry_size(entry)); archive_entry_linkify(bsdtar->resolver, &entry, &spare_entry); /* Handle SIGINFO / SIGUSR1 request if one was made. */ siginfo_printinfo(bsdtar, 0); while (entry != NULL) { write_entry_backend(bsdtar, a, entry); archive_entry_free(entry); entry = spare_entry; spare_entry = NULL; } if (bsdtar->verbose) fprintf(stderr, "\n"); } archive_entry_free(entry); tree_close(tree); }