mirror of
https://git.savannah.gnu.org/git/tar.git
synced 2026-08-16 22:36:05 +00:00
--one-top-level clarifications
Bring back documentation for --one-top-level absolute file names, and clarify its behavior. Allow --one-top-level only with -x, -d, -t. * src/misc.c (chdir_do): Do not pass -1 to openat. Simplify now that open_searchdir_how no longer has RESOLVE_BENEATH when one_top_level_dir is absolute. Fix errno confusion in messages. * src/tar.c (decode_options): Allow --one-top-level only with -x, -d, and -t. Do not use RESOLVE_BENEATH if --one-top-level=/foo is used; this simplifies chdir_do.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
GNU tar NEWS - User visible changes. 2026-06-20
|
||||
GNU tar NEWS - User visible changes. 2026-07-22
|
||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||
|
||||
version 1.35.90 (git)
|
||||
@@ -35,8 +35,8 @@ empty string that file or member is skipped and a warning is printed.
|
||||
The warning can be suppressed using the --warning=empty-transform
|
||||
option.
|
||||
|
||||
** --one-top-level=DIR now requires DIR to be relative.
|
||||
Previously this restriction was alluded to in the manual but not enforced.
|
||||
** The --one-top-level option now requires either -x or -d mode.
|
||||
Previously the behavior was unspecified in other operation modes.
|
||||
|
||||
* Bug fixes
|
||||
|
||||
|
||||
+10
-7
@@ -3287,14 +3287,14 @@ directory.
|
||||
|
||||
@opsummary{one-top-level}
|
||||
@item --one-top-level[=@var{dir}]
|
||||
Tells @command{tar} to create a new directory beneath the extraction directory
|
||||
(or the one passed to @option{-C}) and use it to prevent @command{tar}
|
||||
from modifying files outside that directory.
|
||||
If @var{dir} is present, it must be a relative file name.
|
||||
If it is absent, the name of the new directory
|
||||
Tells @command{tar} to use a directory beneath the extraction directory
|
||||
(or the one passed to @option{-C}) to prevent @command{tar}
|
||||
from accessing files outside that directory.
|
||||
If @var{dir} is absent, the name of the directory
|
||||
is the base name of the archive minus any recognized archive suffix.
|
||||
If multiple @option{-C} options are present,
|
||||
each has its own subdirectory with the same name.
|
||||
If @var{dir} is an absolute file name, that is the only such directory;
|
||||
otherwise, the working directory and the directories specified by
|
||||
any @option{-C} options each have the named subdirectory.
|
||||
Any member names that do not begin
|
||||
with that directory name (after
|
||||
transformations from @option{--transform} and
|
||||
@@ -3302,6 +3302,9 @@ transformations from @option{--transform} and
|
||||
file name suffixes are @samp{.tar}, and any compression suffixes
|
||||
recognizable by @xref{--auto-compress}.
|
||||
|
||||
This option can be used only when extracting, comparing, or reading
|
||||
from the archive.
|
||||
|
||||
@opsummary{overwrite}
|
||||
@item --overwrite
|
||||
|
||||
|
||||
+32
-32
@@ -1079,7 +1079,8 @@ idx_t chdir_current;
|
||||
|
||||
/* Value suitable for use as the first argument to openat, and in
|
||||
similar locations for fstatat, etc. This is an open file
|
||||
descriptor, or AT_FDCWD if the working directory is current. It is
|
||||
descriptor, or AT_FDCWD if the working directory is current,
|
||||
or BADFD if the directory has not been opened yet. It is
|
||||
valid until the next invocation of chdir_do. */
|
||||
static int chdir_fd = AT_FDCWD;
|
||||
|
||||
@@ -1095,7 +1096,7 @@ chdir_do (idx_t i, bool create)
|
||||
int fd = curr->fd;
|
||||
bool one_top_level = !!one_top_level_dir;
|
||||
|
||||
/* Nothing to create unless we are at the one_top_level dir that has
|
||||
/* Nothing to create unless we are at a one_top_level dir that has
|
||||
not been created yet. */
|
||||
create &= i & one_top_level & (fd == BADFD || fd == 0);
|
||||
|
||||
@@ -1103,42 +1104,41 @@ chdir_do (idx_t i, bool create)
|
||||
{
|
||||
if (! fd || create)
|
||||
{
|
||||
if (! IS_ABSOLUTE_FILE_NAME (curr->name))
|
||||
chdir_do ((i - 1) & ~+one_top_level, false);
|
||||
int dfd;
|
||||
if (IS_ABSOLUTE_FILE_NAME (curr->name))
|
||||
dfd = AT_FDCWD;
|
||||
else
|
||||
{
|
||||
chdir_do ((i - 1) & ~+one_top_level, false);
|
||||
dfd = chdir_fd;
|
||||
}
|
||||
|
||||
fd = openat (chdir_fd, curr->name,
|
||||
fd = openat (dfd, curr->name,
|
||||
open_searchdir_how.flags & ~O_NOFOLLOW);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (create)
|
||||
if (errno == ENOENT)
|
||||
{
|
||||
struct open_how saved_open_searchdir_how = open_searchdir_how;
|
||||
/* Don't use O_BENEATH during creation of the
|
||||
directory. The one-top-level directory is
|
||||
allowed to be given as an absolute path. */
|
||||
open_searchdir_how.resolve = 0;
|
||||
if (create_dir (curr->name))
|
||||
/* Directory likely exists now; retry. */
|
||||
fd = openat (chdir_fd, curr->name,
|
||||
open_searchdir_how.flags & ~O_NOFOLLOW);
|
||||
open_searchdir_how = saved_open_searchdir_how;
|
||||
/* Either the creation or open failed */
|
||||
if (fd < 0)
|
||||
open_fatal (curr->name);
|
||||
}
|
||||
else if ((i & one_top_level) && errno == ENOENT)
|
||||
{
|
||||
/* We are requested to not create the directory now. Mark it
|
||||
as to be created later when called with create == true. */
|
||||
chdir_fd = curr->fd = BADFD;
|
||||
chdir_current = i;
|
||||
/* Do not add it to the cache */
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
open_fatal (curr->name);
|
||||
if (create)
|
||||
{
|
||||
if (!create_dir (curr->name))
|
||||
fatal_exit ();
|
||||
/* Directory likely exists now; retry. */
|
||||
fd = openat (dfd, curr->name,
|
||||
open_searchdir_how.flags & ~O_NOFOLLOW);
|
||||
}
|
||||
else if (i & one_top_level)
|
||||
{
|
||||
/* Mark it to be created later if called with CREATE. */
|
||||
chdir_fd = curr->fd = BADFD;
|
||||
chdir_current = i;
|
||||
/* Do not add it to the cache. */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (fd < 0)
|
||||
open_fatal (curr->name);
|
||||
}
|
||||
|
||||
curr->fd = fd;
|
||||
|
||||
@@ -2656,6 +2656,10 @@ decode_options (int argc, char **argv)
|
||||
|
||||
if (optloc_lookup (OC_ONE_TOP_LEVEL))
|
||||
{
|
||||
if (!is_subcommand_class (SUBCL_READ))
|
||||
option_conflict_error ("--one-top-level",
|
||||
subcommand_string (subcommand_option));
|
||||
|
||||
if (absolute_names_option)
|
||||
{
|
||||
struct option_locus *one_top_level_loc =
|
||||
@@ -2712,6 +2716,7 @@ decode_options (int argc, char **argv)
|
||||
open_searchdir_how.flags = (search_flags | nofollow_flag
|
||||
| O_BINARY | O_CLOEXEC | O_DIRECTORY);
|
||||
if (!absolute_names_option && !dereference_option
|
||||
&& ! (one_top_level_dir && IS_ABSOLUTE_FILE_NAME (one_top_level_dir))
|
||||
&& (subcommand_option == EXTRACT_SUBCOMMAND
|
||||
|| subcommand_option == DIFF_SUBCOMMAND))
|
||||
open_searchdir_how.resolve = RESOLVE_BENEATH;
|
||||
|
||||
Reference in New Issue
Block a user