#include "cpio_platform.h"
-__FBSDID("$FreeBSD: src/usr.bin/cpio/cpio.c,v 1.13 2008/09/04 05:20:46 kientzle Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/cpio/cpio.c,v 1.14 2008/11/29 20:22:02 kientzle Exp $");
#include <sys/types.h>
#include <archive.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
#ifdef HAVE_STDARG_H
#include <stdarg.h>
#endif
#include "cpio.h"
#include "matching.h"
+/* Fixed size of uname/gname caches. */
+#define name_cache_size 101
+
+struct name_cache {
+ int probes;
+ int hits;
+ size_t size;
+ struct {
+ id_t id;
+ char *name;
+ } cache[name_cache_size];
+};
+
static int copy_data(struct archive *, struct archive *);
static const char *cpio_rename(const char *name);
static int entry_to_archive(struct cpio *, struct archive_entry *);
static int file_to_archive(struct cpio *, const char *);
+static void free_cache(struct name_cache *cache);
+static void list_item_verbose(struct cpio *, struct archive_entry *);
static void long_help(void);
+static const char *lookup_gname(struct cpio *, gid_t gid);
+static int lookup_gname_helper(struct cpio *,
+ const char **name, id_t gid);
+static const char *lookup_uname(struct cpio *, uid_t uid);
+static int lookup_uname_helper(struct cpio *,
+ const char **name, id_t uid);
static void mode_in(struct cpio *);
static void mode_list(struct cpio *);
static void mode_out(struct cpio *);
"Must specify at least one of -i, -o, or -p");
}
+ free_cache(cpio->gname_cache);
+ free_cache(cpio->uname_cache);
return (0);
}
}
if (excluded(cpio, archive_entry_pathname(entry)))
continue;
- if (cpio->verbose) {
- /* TODO: uname/gname lookups */
- /* TODO: Clean this up. */
- fprintf(stdout,
- "%s%3d %8s%8s " CPIO_FILESIZE_PRINTF " %s\n",
- archive_entry_strmode(entry),
- archive_entry_nlink(entry),
- archive_entry_uname(entry),
- archive_entry_gname(entry),
- (CPIO_FILESIZE_TYPE)archive_entry_size(entry),
- archive_entry_pathname(entry));
- } else
+ if (cpio->verbose)
+ list_item_verbose(cpio, entry);
+ else
fprintf(stdout, "%s\n", archive_entry_pathname(entry));
}
r = archive_read_close(a);
exit(0);
}
+/*
+ * Display information about the current file.
+ *
+ * The format here roughly duplicates the output of 'ls -l'.
+ * This is based on SUSv2, where 'tar tv' is documented as
+ * listing additional information in an "unspecified format,"
+ * and 'pax -l' is documented as using the same format as 'ls -l'.
+ */
+static void
+list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
+{
+ char size[32];
+ char date[32];
+ const char *uname, *gname;
+ FILE *out = stdout;
+ const struct stat *st;
+ const char *fmt;
+ time_t tim;
+ static time_t now;
+
+ st = archive_entry_stat(entry);
+
+ if (!now)
+ time(&now);
+
+ /* Use uname if it's present, else uid. */
+ uname = archive_entry_uname(entry);
+ if (uname == NULL)
+ uname = lookup_uname(cpio, archive_entry_uid(entry));
+
+ /* Use gname if it's present, else gid. */
+ gname = archive_entry_gname(entry);
+ if (gname == NULL)
+ gname = lookup_gname(cpio, archive_entry_gid(entry));
+
+ /* Print device number or file size. */
+ if (S_ISCHR(st->st_mode) || S_ISBLK(st->st_mode)) {
+ snprintf(size, sizeof(size), "%lu,%lu",
+ (unsigned long)major(st->st_rdev),
+ (unsigned long)minor(st->st_rdev)); /* ls(1) also casts here. */
+ } else {
+ snprintf(size, sizeof(size), CPIO_FILESIZE_PRINTF,
+ (CPIO_FILESIZE_TYPE)st->st_size);
+ }
+
+ /* Format the time using 'ls -l' conventions. */
+ tim = (time_t)st->st_mtime;
+ if (abs(tim - now) > (365/2)*86400)
+ fmt = cpio->day_first ? "%e %b %Y" : "%b %e %Y";
+ else
+ fmt = cpio->day_first ? "%e %b %H:%M" : "%b %e %H:%M";
+ strftime(date, sizeof(date), fmt, localtime(&tim));
+
+ fprintf(out, "%s%3d %-8s %-8s %8s %12s %s",
+ archive_entry_strmode(entry),
+ archive_entry_nlink(entry),
+ uname, gname, size, date,
+ archive_entry_pathname(entry));
+
+ /* Extra information for links. */
+ if (archive_entry_hardlink(entry)) /* Hard link */
+ fprintf(out, " link to %s", archive_entry_hardlink(entry));
+ else if (archive_entry_symlink(entry)) /* Symbolic link */
+ fprintf(out, " -> %s", archive_entry_symlink(entry));
+ fprintf(out, "\n");
+}
+
static void
mode_pass(struct cpio *cpio, const char *destdir)
{
free(lr->pathname);
free(lr);
}
+
+static void
+free_cache(struct name_cache *cache)
+{
+ size_t i;
+
+ if (cache != NULL) {
+ for (i = 0; i < cache->size; i++)
+ free(cache->cache[i].name);
+ free(cache);
+ }
+}
+
+/*
+ * Lookup uname/gname from uid/gid, return NULL if no match.
+ */
+static const char *
+lookup_name(struct cpio *cpio, struct name_cache **name_cache_variable,
+ int (*lookup_fn)(struct cpio *, const char **, id_t), id_t id)
+{
+ char asnum[16];
+ struct name_cache *cache;
+ const char *name;
+ int slot;
+
+
+ if (*name_cache_variable == NULL) {
+ *name_cache_variable = malloc(sizeof(struct name_cache));
+ if (*name_cache_variable == NULL)
+ cpio_errc(1, ENOMEM, "No more memory");
+ memset(*name_cache_variable, 0, sizeof(struct name_cache));
+ (*name_cache_variable)->size = name_cache_size;
+ }
+
+ cache = *name_cache_variable;
+ cache->probes++;
+
+ slot = id % cache->size;
+ if (cache->cache[slot].name != NULL) {
+ if (cache->cache[slot].id == id) {
+ cache->hits++;
+ return (cache->cache[slot].name);
+ }
+ free(cache->cache[slot].name);
+ cache->cache[slot].name = NULL;
+ }
+
+ if (lookup_fn(cpio, &name, id) == 0) {
+ if (name == NULL || name[0] == '\0') {
+ /* If lookup failed, format it as a number. */
+ snprintf(asnum, sizeof(asnum), "%u", (unsigned)id);
+ name = asnum;
+ }
+ cache->cache[slot].name = strdup(name);
+ if (cache->cache[slot].name != NULL) {
+ cache->cache[slot].id = id;
+ return (cache->cache[slot].name);
+ }
+ /*
+ * Conveniently, NULL marks an empty slot, so
+ * if the strdup() fails, we've just failed to
+ * cache it. No recovery necessary.
+ */
+ }
+ return (NULL);
+}
+
+static const char *
+lookup_uname(struct cpio *cpio, uid_t uid)
+{
+ return (lookup_name(cpio, &cpio->uname_cache,
+ &lookup_uname_helper, (id_t)uid));
+}
+
+static int
+lookup_uname_helper(struct cpio *cpio, const char **name, id_t id)
+{
+ struct passwd *pwent;
+
+ (void)cpio; /* UNUSED */
+
+ errno = 0;
+ pwent = getpwuid((uid_t)id);
+ if (pwent == NULL) {
+ *name = NULL;
+ if (errno != 0)
+ cpio_warnc(errno, "getpwuid(%d) failed", id);
+ return (errno);
+ }
+
+ *name = pwent->pw_name;
+ return (0);
+}
+
+static const char *
+lookup_gname(struct cpio *cpio, gid_t gid)
+{
+ return (lookup_name(cpio, &cpio->gname_cache,
+ &lookup_gname_helper, (id_t)gid));
+}
+
+static int
+lookup_gname_helper(struct cpio *cpio, const char **name, id_t id)
+{
+ struct group *grent;
+
+ (void)cpio; /* UNUSED */
+
+ errno = 0;
+ grent = getgrgid((gid_t)id);
+ if (grent == NULL) {
+ *name = NULL;
+ if (errno != 0)
+ cpio_warnc(errno, "getgrgid(%d) failed", id);
+ return (errno);
+ }
+
+ *name = grent->gr_name;
+ return (0);
+}
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/usr.bin/cpio/cpio.h,v 1.4 2008/08/04 01:25:48 cperciva Exp $
+ * $FreeBSD: src/usr.bin/cpio/cpio.h,v 1.5 2008/11/29 20:22:02 kientzle Exp $
*/
#ifndef CPIO_H_INCLUDED
char *pass_destpath;
int uid_override;
int gid_override;
+ int day_first; /* true if locale prefers day/mon */
/* If >= 0, then close this when done. */
int fd;
int return_value; /* Value returned by main() */
struct archive_entry_linkresolver *linkresolver;
+ struct name_cache *uname_cache;
+ struct name_cache *gname_cache;
+
/* Work data. */
struct matching *matching;
char *buff;
-$FreeBSD$
+$FreeBSD: src/usr.bin/cpio/test/test_option_tv.stdout.uu,v 1.2 2008/11/29 20:22:02 kientzle Exp $
begin 644 test_option_tv.stdout
-G+7)W+7(M+7(M+2`@(#$@("`H;G5L;"D@("AN=6QL*2`P(&9I;&4*
+M+7)W+7(M+7(M+2`@(#$@=&EM("`@("`@=&EM("`@("`@("`@("`@(#`@1&5C
+/(#,Q("`Q.38Y(&9I;&4*
`
end
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/usr.bin/tar/config_freebsd.h,v 1.7 2008/11/08 04:43:24 kientzle Exp $
+ * $FreeBSD: src/usr.bin/tar/config_freebsd.h,v 1.8 2008/11/29 20:06:53 kientzle Exp $
*/
/* A default configuration for FreeBSD, used if there is no config.h. */
#define HAVE_UNISTD_H 1
#define HAVE_UNSIGNED_LONG_LONG
#define HAVE_VPRINTF 1
+#define HAVE_WCTYPE_H 1
#define HAVE_ZLIB_H 1
#undef MAJOR_IN_MKDEV
#define STDC_HEADERS 1
* regular dir or via fchdir(2) for a symlink).
*/
#include "bsdtar_platform.h"
-__FBSDID("$FreeBSD: src/usr.bin/tar/tree.c,v 1.8 2007/03/11 10:36:42 kientzle Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/tar/tree.c,v 1.9 2008/11/27 05:49:52 kientzle Exp $");
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
/*
* We've finished a directory; ascend back to the parent.
*/
-static void
+static int
tree_ascend(struct tree *t)
{
struct tree_entry *te;
+ int r = 0;
te = t->stack;
t->depth--;
if (te->flags & isDirLink) {
- fchdir(te->fd);
+ if (fchdir(te->fd) != 0) {
+ t->tree_errno = errno;
+ r = TREE_ERROR_FATAL;
+ }
close(te->fd);
t->openCount--;
} else {
- chdir("..");
+ if (chdir("..") != 0) {
+ t->tree_errno = errno;
+ r = TREE_ERROR_FATAL;
+ }
}
+ return (r);
}
/*
tree_next(struct tree *t)
{
struct dirent *de = NULL;
+ int r;
+
+ /* If we're called again after a fatal error, that's an API
+ * violation. Just crash now. */
+ if (t->visit_type == TREE_ERROR_FATAL) {
+ const char *msg = "Unable to continue traversing"
+ " directory heirarchy after a fatal error.";
+ write(2, msg, strlen(msg));
+ *(int *)0 = 1; /* Deliberate SEGV; NULL pointer dereference. */
+ exit(1); /* In case the SEGV didn't work. */
+ }
/* Handle the startup case by returning the initial entry. */
if (t->flags & needsReturn) {
t->depth++;
t->d = opendir(".");
if (t->d == NULL) {
- tree_ascend(t); /* Undo "chdir" */
+ r = tree_ascend(t); /* Undo "chdir" */
tree_pop(t);
t->tree_errno = errno;
- return (t->visit_type = TREE_ERROR_DIR);
+ t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
+ return (t->visit_type);
}
t->flags &= ~hasLstat;
t->flags &= ~hasStat;
/* We've done everything necessary for the top stack entry. */
if (t->stack->flags & needsPostVisit) {
- tree_ascend(t);
+ r = tree_ascend(t);
tree_pop(t);
t->flags &= ~hasLstat;
t->flags &= ~hasStat;
- return (t->visit_type = TREE_POSTASCENT);
+ t->visit_type = r != 0 ? r : TREE_POSTASCENT;
+ return (t->visit_type);
}
}
return (t->visit_type = 0);
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
- * $FreeBSD: src/usr.bin/tar/tree.h,v 1.3 2007/01/09 08:12:17 kientzle Exp $
+ * $FreeBSD: src/usr.bin/tar/tree.h,v 1.4 2008/11/27 05:49:52 kientzle Exp $
*/
/*-
* * Supports very deep logical traversals. The fts package
* uses "non-chdir" approach for logical traversals. This
* package does use a chdir approach for logical traversals
- * and can therefore handle pathnames much longer than
- * PATH_MAX.
+ * and can therefore handle pathnames much longer than PATH_MAX.
* * Supports deep physical traversals "out of the box."
* Due to the memory optimizations above, there's no need to
* limit dir names to 32k.
void tree_close(struct tree *);
/*
- * tree_next() returns Zero if there is no next entry, non-zero if there is.
- * Note that directories are potentially visited three times. The first
- * time as "regular" file. If tree_descend() is invoked at that time,
- * the directory is added to a work list and will be visited two more
- * times: once just after descending into the directory and again
- * just after ascending back to the parent.
+ * tree_next() returns Zero if there is no next entry, non-zero if
+ * there is. Note that directories are potentially visited three
+ * times. Directories are always visited first as part of enumerating
+ * their parent. If tree_descend() is invoked at that time, the
+ * directory is added to a work list and will subsequently be visited
+ * two more times: once just after descending into the directory and
+ * again just after ascending back to the parent.
*
- * TREE_ERROR is returned if the descent failed (because the
+ * TREE_ERROR_DIR is returned if the descent failed (because the
* directory couldn't be opened, for instance). This is returned
- * instead of TREE_PREVISIT/TREE_POSTVISIT.
+ * instead of TREE_PREVISIT/TREE_POSTVISIT. TREE_ERROR_DIR is not a
+ * fatal error, but it does imply that the relevant subtree won't be
+ * visited. TREE_ERROR_FATAL is returned for an error that left the
+ * traversal completely hosed. Right now, this is only returned for
+ * chdir() failures during ascent.
*/
#define TREE_REGULAR 1
#define TREE_POSTDESCENT 2
#define TREE_POSTASCENT 3
#define TREE_ERROR_DIR -1
+#define TREE_ERROR_FATAL -2
+
int tree_next(struct tree *);
+/* Errno value associated with the last traversal error. */
int tree_errno(struct tree *);
/*
* Return information about the current entry.
*/
+/* Current depth in the traversal. */
int tree_current_depth(struct tree *);
+
/*
* The current full pathname, length of the full pathname,
* and a name that can be used to access the file.
const char *tree_current_path(struct tree *);
size_t tree_current_pathlen(struct tree *);
const char *tree_current_access_path(struct tree *);
+
/*
* Request the lstat() or stat() data for the current path. Since the
* tree package needs to do some of this anyway, and caches the
*/
const struct stat *tree_current_stat(struct tree *);
const struct stat *tree_current_lstat(struct tree *);
-/* The following tests may use mechanisms much faster than stat()/lstat(). */
+
+/* The following functions use tricks to avoid a certain number of
+ * stat()/lstat() calls. */
/* "is_physical_dir" is equivalent to S_ISDIR(tree_current_lstat()->st_mode) */
int tree_current_is_physical_dir(struct tree *);
/* "is_physical_link" is equivalent to S_ISLNK(tree_current_lstat()->st_mode) */
*/
#include "bsdtar_platform.h"
-__FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.21 2008/11/10 05:04:55 kientzle Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/tar/util.c,v 1.22 2008/11/29 20:06:53 kientzle Exp $");
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
+#ifdef HAVE_WCTYPE_H
+#include <wctype.h>
+#else
+/* If we don't have wctype, we need to hack up some version of iswprint(). */
+#define iswprint isprint
+#endif
#include "bsdtar.h"
static void bsdtar_vwarnc(struct bsdtar *, int code,
const char *fmt, va_list ap);
+static size_t bsdtar_expand_char(char *, size_t, char);
static const char *strip_components(const char *path, int elements);
+/* TODO: Hack up a version of mbtowc for platforms with no wide
+ * character support at all. I think the following might suffice,
+ * but it needs careful testing.
+ * #if !HAVE_MBTOWC
+ * #define mbtowc(wcp, p, n) ((*wcp = *p), 1)
+ * #endif
+ */
+
/*
* Print a string, taking care with any non-printable characters.
+ *
+ * Note that we use a stack-allocated buffer to receive the formatted
+ * string if we can. This is partly performance (avoiding a call to
+ * malloc()), partly out of expedience (we have to call vsnprintf()
+ * before malloc() anyway to find out how big a buffer we need; we may
+ * as well point that first call at a small local buffer in case it
+ * works), but mostly for safety (so we can use this to print messages
+ * about out-of-memory conditions).
*/
void
safe_fprintf(FILE *f, const char *fmt, ...)
{
- char *buff;
- char *buff_heap;
- int buff_length;
+ char fmtbuff_stack[256]; /* Place to format the printf() string. */
+ char outbuff[256]; /* Buffer for outgoing characters. */
+ char *fmtbuff_heap; /* If fmtbuff_stack is too small, we use malloc */
+ char *fmtbuff; /* Pointer to fmtbuff_stack or fmtbuff_heap. */
+ int fmtbuff_length;
int length;
va_list ap;
- char *p;
+ const char *p;
unsigned i;
- char buff_stack[256];
- char copy_buff[256];
+ wchar_t wc;
+ char try_wc;
/* Use a stack-allocated buffer if we can, for speed and safety. */
- buff_heap = NULL;
- buff_length = sizeof(buff_stack);
- buff = buff_stack;
+ fmtbuff_heap = NULL;
+ fmtbuff_length = sizeof(fmtbuff_stack);
+ fmtbuff = fmtbuff_stack;
+ /* Try formatting into the stack buffer. */
va_start(ap, fmt);
- length = vsnprintf(buff, buff_length, fmt, ap);
+ length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
va_end(ap);
- /* If the result is too large, allocate a buffer on the heap. */
- if (length >= buff_length) {
- buff_length = length+1;
- buff_heap = malloc(buff_length);
- /* Failsafe: use the truncated string if malloc fails. */
- if (buff_heap != NULL) {
- buff = buff_heap;
+
+ /* If the result was too large, allocate a buffer on the heap. */
+ if (length >= fmtbuff_length) {
+ fmtbuff_length = length+1;
+ fmtbuff_heap = malloc(fmtbuff_length);
+
+ /* Reformat the result into the heap buffer if we can. */
+ if (fmtbuff_heap != NULL) {
+ fmtbuff = fmtbuff_heap;
va_start(ap, fmt);
- length = vsnprintf(buff, buff_length, fmt, ap);
+ length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
va_end(ap);
+ } else {
+ /* Leave fmtbuff pointing to the truncated
+ * string in fmtbuff_stack. */
+ length = sizeof(fmtbuff_stack) - 1;
}
}
+ /* Note: mbrtowc() has a cleaner API, but mbtowc() seems a bit
+ * more portable, so we use that here instead. */
+ mbtowc(NULL, NULL, 0); /* Reset the shift state. */
+
/* Write data, expanding unprintable characters. */
- p = buff;
+ p = fmtbuff;
i = 0;
+ try_wc = 1;
while (*p != '\0') {
- unsigned char c = *p++;
-
- if (isprint(c) && c != '\\')
- copy_buff[i++] = c;
- else {
- copy_buff[i++] = '\\';
- switch (c) {
- case '\a': copy_buff[i++] = 'a'; break;
- case '\b': copy_buff[i++] = 'b'; break;
- case '\f': copy_buff[i++] = 'f'; break;
- case '\n': copy_buff[i++] = 'n'; break;
-#if '\r' != '\n'
- /* On some platforms, \n and \r are the same. */
- case '\r': copy_buff[i++] = 'r'; break;
-#endif
- case '\t': copy_buff[i++] = 't'; break;
- case '\v': copy_buff[i++] = 'v'; break;
- case '\\': copy_buff[i++] = '\\'; break;
- default:
- sprintf(copy_buff + i, "%03o", c);
- i += 3;
+ int n;
+
+ /* Convert to wide char, test if the wide
+ * char is printable in the current locale. */
+ if (try_wc && (n = mbtowc(&wc, p, length)) != -1) {
+ length -= n;
+ if (iswprint(wc) && wc != L'\\') {
+ /* Printable, copy the bytes through. */
+ while (n-- > 0)
+ outbuff[i++] = *p++;
+ } else {
+ /* Not printable, format the bytes. */
+ while (n-- > 0)
+ i += bsdtar_expand_char(
+ outbuff, i, *p++);
}
+ } else {
+ /* After any conversion failure, don't bother
+ * trying to convert the rest. */
+ i += bsdtar_expand_char(outbuff, i, *p++);
+ try_wc = 0;
}
- /* If our temp buffer is full, dump it and keep going. */
- if (i > (sizeof(copy_buff) - 8)) {
- copy_buff[i++] = '\0';
- fprintf(f, "%s", copy_buff);
+ /* If our output buffer is full, dump it and keep going. */
+ if (i > (sizeof(outbuff) - 20)) {
+ outbuff[i++] = '\0';
+ fprintf(f, "%s", outbuff);
i = 0;
}
}
- copy_buff[i++] = '\0';
- fprintf(f, "%s", copy_buff);
+ outbuff[i++] = '\0';
+ fprintf(f, "%s", outbuff);
+
+ /* If we allocated a heap-based formatting buffer, free it now. */
+ if (fmtbuff_heap != NULL)
+ free(fmtbuff_heap);
+}
+
+/*
+ * Render an arbitrary sequence of bytes into printable ASCII characters.
+ */
+static size_t
+bsdtar_expand_char(char *buff, size_t offset, char c)
+{
+ size_t i = offset;
+
+ if (isprint(c) && c != '\\')
+ buff[i++] = c;
+ else {
+ buff[i++] = '\\';
+ switch (c) {
+ case '\a': buff[i++] = 'a'; break;
+ case '\b': buff[i++] = 'b'; break;
+ case '\f': buff[i++] = 'f'; break;
+ case '\n': buff[i++] = 'n'; break;
+#if '\r' != '\n'
+ /* On some platforms, \n and \r are the same. */
+ case '\r': buff[i++] = 'r'; break;
+#endif
+ case '\t': buff[i++] = 't'; break;
+ case '\v': buff[i++] = 'v'; break;
+ case '\\': buff[i++] = '\\'; break;
+ default:
+ sprintf(buff + i, "%03o", 0xFF & (int)c);
+ i += 3;
+ }
+ }
- /* If we allocated a heap-based buffer, free it now. */
- if (buff_heap != NULL)
- free(buff_heap);
+ return (i - offset);
}
static void
*/
#include "bsdtar_platform.h"
-__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.77 2008/09/14 03:49:00 kientzle Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.79 2008/11/27 05:49:52 kientzle Exp $");
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
const struct stat *st = NULL, *lst = NULL;
int descend;
- if (tree_ret == TREE_ERROR_DIR)
- bsdtar_warnc(bsdtar, errno, "%s: Couldn't visit directory", name);
+ 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;
lst = tree_current_lstat(tree);