Skip to content

Commit

Permalink
Merge pull request #626 from Tarsnap/tf-null-output
Browse files Browse the repository at this point in the history
Add --null-output to -t and -x
  • Loading branch information
cperciva authored Feb 8, 2025
2 parents 9dfb039 + 33b1e5f commit d9c607c
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 51 deletions.
4 changes: 4 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
each archive name with a null character (like `find -print0`). If one or
more -v arguments are specified, multiple null characters are used to
separate fields; see the man page for details.
- tarsnap now accepts --null-output with -x and -t, which causes them to
separate each filename with a null character. If there are multiple fields
on a line, null characters are used instead of spaces; see the man page for
details.
- tarsnap now accepts --null-input as a synonym for --null. For compatibility
reasons, --null is still supported, and will not be deprecated.
- tarsnap now accepts --hashes, which causes --list-archives to print hashes
Expand Down
2 changes: 2 additions & 0 deletions misc/zsh_completion/_tarsnap
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,7 @@ _shtab_tarsnap_t_options=(
"--include[process only certain files or directories]:pattern:"
"--iso-dates[print dates as yyyy-mm-dd hh\:mm\:ss]"
"--newer[only add files and dirs newer than ARG]:date:"
"--null-output[output split by NULs instead of newlines]"
"-O[write files to stdout (-x) or stderr (-t)]"
"-P[preserve pathnames]"
"-q[stop after the first selected entry]"
Expand Down Expand Up @@ -782,6 +783,7 @@ _shtab_tarsnap_x_options=(
"--keep-newer-files[do not overwrite newer existing files]"
"-m[do not extract modification time]"
"--newer[only add files and dirs newer than ARG]:date:"
"--null-output[output split by NULs instead of newlines]"
"--numeric-owner[ignore symbolic ownership when restoring]"
"-O[write files to stdout (-x) or stderr (-t)]"
"-o[use the current uid and gid\; requires -p]"
Expand Down
2 changes: 1 addition & 1 deletion tar/bsdtar.c
Original file line number Diff line number Diff line change
Expand Up @@ -1054,7 +1054,7 @@ main(int argc, char **argv)
only_mode(bsdtar, "--null-input", "cxt");
if (bsdtar->option_null_output) {
if (bsdtar->mode != OPTION_LIST_ARCHIVES)
only_mode(bsdtar, "--null-output", "");
only_mode(bsdtar, "--null-output", "xt");
}

/* We should only have remaining args in -c, -t, and -x modes. */
Expand Down
1 change: 1 addition & 0 deletions tar/bsdtar.h
Original file line number Diff line number Diff line change
Expand Up @@ -332,5 +332,6 @@ int apply_substitution(struct bsdtar *, const char *, char **, int);
void cleanup_substitution(struct bsdtar *);
#endif

void print_sep(struct bsdtar *, FILE *, char, int);
void list_item_verbose(struct bsdtar *, FILE *,
struct archive_entry *);
18 changes: 10 additions & 8 deletions tar/read.c
Original file line number Diff line number Diff line change
Expand Up @@ -282,23 +282,23 @@ read_archive(struct bsdtar *bsdtar, char mode)
fflush(out);
r = archive_read_data_skip(a);
if (r == ARCHIVE_WARN) {
fprintf(out, "\n");
print_sep(bsdtar, out, '\n', 1);
bsdtar_warnc(bsdtar, 0, "%s",
archive_error_string(a));
}
if (r == ARCHIVE_RETRY) {
fprintf(out, "\n");
print_sep(bsdtar, out, '\n', 1);
bsdtar_warnc(bsdtar, 0, "%s",
archive_error_string(a));
}
if (r == ARCHIVE_FATAL) {
fprintf(out, "\n");
print_sep(bsdtar, out, '\n', 1);
bsdtar_warnc(bsdtar, 0, "%s",
archive_error_string(a));
bsdtar->return_value = 1;
break;
}
fprintf(out, "\n");
print_sep(bsdtar, out, '\n', 1);
} else {
/* Note: some rewrite failures prevent extraction. */
if (edit_pathname(bsdtar, entry))
Expand Down Expand Up @@ -363,11 +363,11 @@ read_archive(struct bsdtar *bsdtar, char mode)
safe_fprintf(stderr, ": %s",
archive_error_string(a));
if (!bsdtar->verbose)
fprintf(stderr, "\n");
print_sep(bsdtar, stderr, '\n', 1);
bsdtar->return_value = 1;
}
if (bsdtar->verbose)
fprintf(stderr, "\n");
print_sep(bsdtar, stderr, '\n', 1);
if (r == ARCHIVE_FATAL)
break;
}
Expand All @@ -386,9 +386,11 @@ read_archive(struct bsdtar *bsdtar, char mode)
if (r <= ARCHIVE_WARN)
bsdtar->return_value = 1;

if (bsdtar->verbose > 2)
fprintf(stdout, "Archive Format: %s, Compression: %s\n",
if (bsdtar->verbose > 2) {
fprintf(stdout, "Archive Format: %s, Compression: %s",
archive_format_name(a), archive_compression_name(a));
print_sep(bsdtar, stdout, '\n', 1);
}

/* Always print a final message for --progress-bytes. */
if ((mode == 'x') && (bsdtar->option_progress_bytes != 0))
Expand Down
23 changes: 8 additions & 15 deletions tar/tarsnap.1-man.in
Original file line number Diff line number Diff line change
Expand Up @@ -110,19 +110,6 @@ flag is specified two or more times, the command
line with which
\fB\%tarsnap\fP
was invoked to create each archive is also printed.
.PP
If the
\fB\--null-output\fP
argument is also specified, each archive name will be separated by a single
null character.
If the
\fB\-v\fP
flag is also specified, then the creation time will be separated by two null
characters.
If the
\fB\-v\fP
flag is specified two times, then the arguments in the command line will be
separated by three null characters.
.TP
\fB\--print-stats\fP
Print global statistics concerning the archives stored, and optionally
Expand Down Expand Up @@ -752,8 +739,14 @@ option to
\fBfind\fP(1).
.TP
\fB\--null-output\fP
(list-archives mode only)
Archive names in output are separated by null characters, not by newlines.
(x, t, and list-archives modes only)
Archive names and filenames in output are separated by null characters, not by
newlines.
.PP
If there are multiple fields on a line, they will be separated by two null
characters.
If a command line is printed within one of those fields, each argument will be
separated by three null characters.
.TP
\fB\--numeric-owner\fP
(x mode only)
Expand Down
23 changes: 8 additions & 15 deletions tar/tarsnap.1-mdoc.in
Original file line number Diff line number Diff line change
Expand Up @@ -121,19 +121,6 @@ flag is specified two or more times, the command
line with which
.Nm
was invoked to create each archive is also printed.
.Pp
If the
.Fl -null-output
argument is also specified, each archive name will be separated by a single
null character.
If the
.Fl v
flag is also specified, then the creation time will be separated by two null
characters.
If the
.Fl v
flag is specified two times, then the arguments in the command line will be
separated by three null characters.
.It Fl -print-stats
Print global statistics concerning the archives stored, and optionally
information about individual archive(s).
Expand Down Expand Up @@ -680,8 +667,14 @@ This is often used to read filenames output by the
option to
.Xr find 1 .
.It Fl -null-output
(list-archives mode only)
Archive names in output are separated by null characters, not by newlines.
(x, t, and list-archives modes only)
Archive names and filenames in output are separated by null characters, not by
newlines.
.Pp
If there are multiple fields on a line, they will be separated by two null
characters.
If a command line is printed within one of those fields, each argument will be
separated by three null characters.
.It Fl -numeric-owner
(x mode only)
Ignore symbolic user and group names when restoring archives to disk,
Expand Down
57 changes: 45 additions & 12 deletions tar/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -686,6 +686,22 @@ pathcmp(const char *a, const char *b)
return (*(const unsigned char *)a - *(const unsigned char *)b);
}

/* Print ${sep} if appropriate; otherwise, print ${num} NULs. */
void
print_sep(struct bsdtar *bsdtar, FILE * out, char sep, int num)
{
int i;

if (bsdtar->option_null_output) {
/* Print the specified number of NULs. */
for (i = 0; i < num; i++)
fprintf(out, "%c", '\0');
} else {
/* Print the normal separator. */
fprintf(out, "%c", sep);
}
}

/*
* Display information about the current file.
*
Expand Down Expand Up @@ -720,20 +736,25 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
}
if (!now)
time(&now);
fprintf(out, "%s %d ",
archive_entry_strmode(entry),
(int)(st->st_nlink));
fprintf(out, "%s", archive_entry_strmode(entry));
print_sep(bsdtar, out, ' ', 2);
fprintf(out, "%d", (int)(st->st_nlink));
print_sep(bsdtar, out, ' ', 2);

/* Use uname if it's present, else uid. */
p = archive_entry_uname(entry);
if ((p == NULL) || (*p == '\0')) {
sprintf(tmp, "%lu ", (unsigned long)st->st_uid);
sprintf(tmp, "%lu", (unsigned long)st->st_uid);
p = tmp;
}
w = strlen(p);
if (w > bsdtar->u_width)
bsdtar->u_width = w;
fprintf(out, "%-*s ", (int)bsdtar->u_width, p);
if (bsdtar->option_null_output)
fprintf(out, "%s", p);
else
fprintf(out, "%-*s", (int)bsdtar->u_width, p);
print_sep(bsdtar, out, ' ', 2);

/* Use gname if it's present, else gid. */
p = archive_entry_gname(entry);
Expand Down Expand Up @@ -766,7 +787,10 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
}
if (w + strlen(tmp) >= bsdtar->gs_width)
bsdtar->gs_width = w+strlen(tmp)+1;
fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp);
if (bsdtar->option_null_output)
fprintf(out, "%s", tmp);
else
fprintf(out, "%*s", (int)(bsdtar->gs_width - w), tmp);

/* Format the time. */
tim = (time_t)st->st_mtime;
Expand All @@ -788,13 +812,22 @@ list_item_verbose(struct bsdtar *bsdtar, FILE *out, struct archive_entry *entry)
#endif
}
strftime(tmp, sizeof(tmp), fmt, localtime(&tim));
fprintf(out, " %s ", tmp);
print_sep(bsdtar, out, ' ', 2);
fprintf(out, "%s", tmp);
print_sep(bsdtar, out, ' ', 2);
safe_fprintf(out, "%s", archive_entry_pathname(entry));

/* Extra information for links. */
if (archive_entry_hardlink(entry)) /* Hard link */
safe_fprintf(out, " link to %s",
archive_entry_hardlink(entry));
else if (S_ISLNK(st->st_mode)) /* Symbolic link */
safe_fprintf(out, " -> %s", archive_entry_symlink(entry));
if (archive_entry_hardlink(entry)) { /* Hard link */
print_sep(bsdtar, out, ' ', 2);
fprintf(out, "link to");
print_sep(bsdtar, out, ' ', 2);
safe_fprintf(out, "%s", archive_entry_hardlink(entry));
} else if (S_ISLNK(st->st_mode)) { /* Symbolic link */
print_sep(bsdtar, out, ' ', 2);
fprintf(out, "->");
print_sep(bsdtar, out, ' ', 2);
safe_fprintf(out, "%s", archive_entry_symlink(entry));
print_sep(bsdtar, out, ' ', 2);
}
}

0 comments on commit d9c607c

Please sign in to comment.