Compare commits
10 Commits
release_1_
...
release_1_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bf28f95b3a | ||
|
|
beeb19f927 | ||
|
|
553210d5ad | ||
|
|
ee2ec5ff19 | ||
|
|
d9d4435692 | ||
|
|
2251317e3f | ||
|
|
972bebf07e | ||
|
|
8e2898ab11 | ||
|
|
0b43ea2906 | ||
|
|
e4d1edadef |
18
NEWS
18
NEWS
@@ -1,6 +1,22 @@
|
|||||||
GNU tar NEWS - User visible changes. 2021-01-07
|
GNU tar NEWS - User visible changes. 2021-02-13
|
||||||
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
Please send GNU tar bug reports to <bug-tar@gnu.org>
|
||||||
|
|
||||||
|
version 1.34 - Sergey Poznyakoff, 2021-02-13
|
||||||
|
|
||||||
|
* Fix extraction over pipe (savannah bug #60002)
|
||||||
|
|
||||||
|
* Fix memory leak in read_header (savannah bug #59897)
|
||||||
|
|
||||||
|
* Fix extraction when . and .. are unreadable
|
||||||
|
|
||||||
|
See https://lists.gnu.org/archive/html/bug-tar/2021-01/msg00012.html
|
||||||
|
|
||||||
|
* Gracefully handle duplicate symlinks when extracting
|
||||||
|
|
||||||
|
See https://lists.gnu.org/archive/html/bug-tar/2021-01/msg00026.html
|
||||||
|
|
||||||
|
* Re-initialize supplementary groups when switching to user privileges
|
||||||
|
|
||||||
version 1.33 - Sergey Poznyakoff, 2021-01-07
|
version 1.33 - Sergey Poznyakoff, 2021-01-07
|
||||||
|
|
||||||
* POSIX extended format headers do not include PID by default
|
* POSIX extended format headers do not include PID by default
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
AC_INIT([GNU tar], [1.33], [bug-tar@gnu.org])
|
AC_INIT([GNU tar], [1.34], [bug-tar@gnu.org])
|
||||||
AC_CONFIG_SRCDIR([src/tar.c])
|
AC_CONFIG_SRCDIR([src/tar.c])
|
||||||
AC_CONFIG_AUX_DIR([build-aux])
|
AC_CONFIG_AUX_DIR([build-aux])
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
|
|||||||
@@ -83,6 +83,7 @@ stat-time
|
|||||||
stdbool
|
stdbool
|
||||||
stdint
|
stdint
|
||||||
stpcpy
|
stpcpy
|
||||||
|
stdopen
|
||||||
strdup-posix
|
strdup-posix
|
||||||
strerror
|
strerror
|
||||||
strnlen
|
strnlen
|
||||||
|
|||||||
@@ -32,7 +32,6 @@ AM_CFLAGS = $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
|
|||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
paxlib.h\
|
paxlib.h\
|
||||||
rmt.h\
|
rmt.h\
|
||||||
stdopen.h\
|
|
||||||
system.h\
|
system.h\
|
||||||
system-ioctl.h\
|
system-ioctl.h\
|
||||||
wordsplit.h\
|
wordsplit.h\
|
||||||
@@ -42,7 +41,6 @@ libtar_a_SOURCES = \
|
|||||||
paxerror.c paxexit-status.c paxlib.h paxnames.c \
|
paxerror.c paxexit-status.c paxlib.h paxnames.c \
|
||||||
rtapelib.c \
|
rtapelib.c \
|
||||||
rmt.h \
|
rmt.h \
|
||||||
stdopen.c stdopen.h \
|
|
||||||
system.h system-ioctl.h \
|
system.h system-ioctl.h \
|
||||||
wordsplit.c\
|
wordsplit.c\
|
||||||
xattr-at.c
|
xattr-at.c
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
/* stdopen.c - ensure that the three standard file descriptors are in use
|
|
||||||
|
|
||||||
Copyright 2005-2021 Free Software Foundation, Inc.
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 3, or (at your option)
|
|
||||||
any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
||||||
|
|
||||||
/* Written by Paul Eggert and Jim Meyering. */
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "stdopen.h"
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
/* Try to ensure that all of the standard file numbers (0, 1, 2)
|
|
||||||
are in use. Without this, each application would have to guard
|
|
||||||
every call to open, dup, fopen, etc. with tests to ensure they
|
|
||||||
don't use one of the special file numbers when opening a file.
|
|
||||||
Return false if at least one of the file descriptors is initially
|
|
||||||
closed and an attempt to reopen it fails. Otherwise, return true. */
|
|
||||||
bool
|
|
||||||
stdopen (void)
|
|
||||||
{
|
|
||||||
int fd;
|
|
||||||
bool ok = true;
|
|
||||||
|
|
||||||
for (fd = 0; fd <= 2; fd++)
|
|
||||||
{
|
|
||||||
if (fcntl (fd, F_GETFD) < 0)
|
|
||||||
{
|
|
||||||
if (errno != EBADF)
|
|
||||||
ok = false;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
static const int contrary_mode[]
|
|
||||||
= { O_WRONLY, O_RDONLY, O_RDONLY };
|
|
||||||
int mode = contrary_mode[fd];
|
|
||||||
int new_fd;
|
|
||||||
/* Open /dev/null with the contrary mode so that the typical
|
|
||||||
read (stdin) or write (stdout, stderr) operation will fail.
|
|
||||||
With descriptor 0, we can do even better on systems that
|
|
||||||
have /dev/full, by opening that write-only instead of
|
|
||||||
/dev/null. The only drawback is that a write-provoked
|
|
||||||
failure comes with a misleading errno value, ENOSPC. */
|
|
||||||
if (mode == O_RDONLY
|
|
||||||
|| (new_fd = open ("/dev/full", mode) != fd))
|
|
||||||
new_fd = open ("/dev/null", mode);
|
|
||||||
if (new_fd != fd)
|
|
||||||
{
|
|
||||||
if (0 <= new_fd)
|
|
||||||
close (new_fd);
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#ifndef STDOPEN_H
|
|
||||||
# define STDOPEN_H 1
|
|
||||||
|
|
||||||
# include <stdbool.h>
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
# endif
|
|
||||||
|
|
||||||
bool stdopen (void);
|
|
||||||
|
|
||||||
# ifdef __cplusplus
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
2
paxutils
2
paxutils
Submodule paxutils updated: 56939847bf...b7da0d659e
1
po/.gitignore
vendored
1
po/.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
/Makefile.in.in
|
||||||
/Makevars.template~
|
/Makevars.template~
|
||||||
/Makefile.in.in~
|
/Makefile.in.in~
|
||||||
*.gmo
|
*.gmo
|
||||||
|
|||||||
99
src/delete.c
99
src/delete.c
@@ -147,6 +147,23 @@ write_recent_bytes (char *data, size_t bytes)
|
|||||||
write_record (1);
|
write_record (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
flush_file (void)
|
||||||
|
{
|
||||||
|
off_t blocks_to_skip;
|
||||||
|
|
||||||
|
set_next_block_after (current_header);
|
||||||
|
blocks_to_skip = (current_stat_info.stat.st_size
|
||||||
|
+ BLOCKSIZE - 1) / BLOCKSIZE;
|
||||||
|
|
||||||
|
while (record_end - current_block <= blocks_to_skip)
|
||||||
|
{
|
||||||
|
blocks_to_skip -= (record_end - current_block);
|
||||||
|
flush_archive ();
|
||||||
|
}
|
||||||
|
current_block += blocks_to_skip;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
delete_archive_members (void)
|
delete_archive_members (void)
|
||||||
{
|
{
|
||||||
@@ -155,7 +172,6 @@ delete_archive_members (void)
|
|||||||
|
|
||||||
/* FIXME: Should clean the routine before cleaning these variables :-( */
|
/* FIXME: Should clean the routine before cleaning these variables :-( */
|
||||||
struct name *name;
|
struct name *name;
|
||||||
off_t blocks_to_skip = 0;
|
|
||||||
off_t blocks_to_keep = 0;
|
off_t blocks_to_keep = 0;
|
||||||
int kept_blocks_in_record;
|
int kept_blocks_in_record;
|
||||||
|
|
||||||
@@ -163,6 +179,7 @@ delete_archive_members (void)
|
|||||||
open_archive (ACCESS_UPDATE);
|
open_archive (ACCESS_UPDATE);
|
||||||
acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
|
acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
|
||||||
|
|
||||||
|
/* Skip to the first member that matches the name list. */
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
enum read_header status = read_header (¤t_header,
|
enum read_header status = read_header (¤t_header,
|
||||||
@@ -243,15 +260,12 @@ delete_archive_members (void)
|
|||||||
|
|
||||||
if (logical_status == HEADER_SUCCESS)
|
if (logical_status == HEADER_SUCCESS)
|
||||||
{
|
{
|
||||||
/* FIXME: Pheew! This is crufty code! */
|
|
||||||
logical_status = HEADER_STILL_UNREAD;
|
logical_status = HEADER_STILL_UNREAD;
|
||||||
goto flush_file;
|
flush_file ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: Solaris 2.4 Sun cc (the ANSI one, not the old K&R) says:
|
/* Skip matching members and move the rest up the archive. */
|
||||||
"delete.c", line 223: warning: loop not entered at top
|
while (logical_status != HEADER_END_OF_FILE)
|
||||||
Reported by Bruno Haible. */
|
|
||||||
while (1)
|
|
||||||
{
|
{
|
||||||
enum read_header status;
|
enum read_header status;
|
||||||
|
|
||||||
@@ -259,49 +273,27 @@ delete_archive_members (void)
|
|||||||
|
|
||||||
if (current_block == record_end)
|
if (current_block == record_end)
|
||||||
flush_archive ();
|
flush_archive ();
|
||||||
|
|
||||||
status = read_header (¤t_header, ¤t_stat_info,
|
status = read_header (¤t_header, ¤t_stat_info,
|
||||||
read_header_auto);
|
read_header_auto);
|
||||||
|
|
||||||
xheader_decode (¤t_stat_info);
|
switch (status)
|
||||||
|
|
||||||
if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
|
|
||||||
{
|
{
|
||||||
set_next_block_after (current_header);
|
case HEADER_STILL_UNREAD:
|
||||||
continue;
|
case HEADER_SUCCESS_EXTENDED:
|
||||||
}
|
abort ();
|
||||||
if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
|
|
||||||
{
|
|
||||||
logical_status = HEADER_END_OF_FILE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == HEADER_FAILURE)
|
|
||||||
{
|
|
||||||
ERROR ((0, 0, _("Deleting non-header from archive")));
|
|
||||||
set_next_block_after (current_header);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
case HEADER_SUCCESS:
|
||||||
/* Found another header. */
|
/* Found another header. */
|
||||||
|
xheader_decode (¤t_stat_info);
|
||||||
|
|
||||||
if ((name = name_scan (current_stat_info.file_name)) != NULL)
|
if ((name = name_scan (current_stat_info.file_name)) != NULL)
|
||||||
{
|
{
|
||||||
name->found_count++;
|
name->found_count++;
|
||||||
if (ISFOUND (name))
|
if (ISFOUND (name))
|
||||||
{
|
{
|
||||||
flush_file:
|
flush_file ();
|
||||||
set_next_block_after (current_header);
|
break;
|
||||||
blocks_to_skip = (current_stat_info.stat.st_size
|
|
||||||
+ BLOCKSIZE - 1) / BLOCKSIZE;
|
|
||||||
|
|
||||||
while (record_end - current_block <= blocks_to_skip)
|
|
||||||
{
|
|
||||||
blocks_to_skip -= (record_end - current_block);
|
|
||||||
flush_archive ();
|
|
||||||
}
|
|
||||||
current_block += blocks_to_skip;
|
|
||||||
blocks_to_skip = 0;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Copy header. */
|
/* Copy header. */
|
||||||
@@ -313,8 +305,10 @@ delete_archive_members (void)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
write_recent_blocks (recent_long_name, recent_long_name_blocks);
|
write_recent_blocks (recent_long_name,
|
||||||
write_recent_blocks (recent_long_link, recent_long_link_blocks);
|
recent_long_name_blocks);
|
||||||
|
write_recent_blocks (recent_long_link,
|
||||||
|
recent_long_link_blocks);
|
||||||
}
|
}
|
||||||
new_record[new_blocks] = *current_header;
|
new_record[new_blocks] = *current_header;
|
||||||
new_blocks++;
|
new_blocks++;
|
||||||
@@ -349,7 +343,8 @@ delete_archive_members (void)
|
|||||||
if (! count)
|
if (! count)
|
||||||
abort ();
|
abort ();
|
||||||
|
|
||||||
memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
|
memcpy (new_record + new_blocks, current_block,
|
||||||
|
count * BLOCKSIZE);
|
||||||
new_blocks += count;
|
new_blocks += count;
|
||||||
current_block += count;
|
current_block += count;
|
||||||
blocks_to_keep -= count;
|
blocks_to_keep -= count;
|
||||||
@@ -358,6 +353,28 @@ delete_archive_members (void)
|
|||||||
if (new_blocks == blocking_factor)
|
if (new_blocks == blocking_factor)
|
||||||
write_record (1);
|
write_record (1);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HEADER_ZERO_BLOCK:
|
||||||
|
if (ignore_zeros_option)
|
||||||
|
set_next_block_after (current_header);
|
||||||
|
else
|
||||||
|
logical_status = HEADER_END_OF_FILE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HEADER_END_OF_FILE:
|
||||||
|
logical_status = HEADER_END_OF_FILE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case HEADER_FAILURE:
|
||||||
|
ERROR ((0, 0, _("Deleting non-header from archive")));
|
||||||
|
set_next_block_after (current_header);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
abort ();
|
||||||
|
}
|
||||||
|
tar_stat_destroy (¤t_stat_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logical_status == HEADER_END_OF_FILE)
|
if (logical_status == HEADER_END_OF_FILE)
|
||||||
|
|||||||
@@ -1323,6 +1323,41 @@ extract_file (char *file_name, int typeflag)
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Find a delayed_link structure corresponding to the source NAME.
|
||||||
|
Such a structure exists in the delayed link list only if the link
|
||||||
|
placeholder file has been created. Therefore, try to stat the NAME
|
||||||
|
first. If it doesn't exist, there is no matching entry in the list.
|
||||||
|
Otherwise, look for the entry in list which has the matching dev
|
||||||
|
and ino numbers.
|
||||||
|
|
||||||
|
This approach avoids scanning the singly-linked list in obvious cases
|
||||||
|
and does not rely on comparing file names, which may differ for
|
||||||
|
various reasons (e.g. relative vs. absolute file names).
|
||||||
|
*/
|
||||||
|
static struct delayed_link *
|
||||||
|
find_delayed_link_source (char const *name)
|
||||||
|
{
|
||||||
|
struct delayed_link *dl;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (!delayed_link_head)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (fstatat (chdir_fd, name, &st, AT_SYMLINK_NOFOLLOW))
|
||||||
|
{
|
||||||
|
if (errno != ENOENT)
|
||||||
|
stat_error (name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (dl = delayed_link_head; dl; dl = dl->next)
|
||||||
|
{
|
||||||
|
if (dl->dev == st.st_dev && dl->ino == st.st_ino)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return dl;
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a placeholder file with name FILE_NAME, which will be
|
/* Create a placeholder file with name FILE_NAME, which will be
|
||||||
replaced after other extraction is done by a symbolic link if
|
replaced after other extraction is done by a symbolic link if
|
||||||
IS_SYMLINK is true, and by a hard link otherwise. Set
|
IS_SYMLINK is true, and by a hard link otherwise. Set
|
||||||
@@ -1342,6 +1377,15 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made,
|
|||||||
|
|
||||||
while ((fd = openat (chdir_fd, file_name, O_WRONLY | O_CREAT | O_EXCL, 0)) < 0)
|
while ((fd = openat (chdir_fd, file_name, O_WRONLY | O_CREAT | O_EXCL, 0)) < 0)
|
||||||
{
|
{
|
||||||
|
if (errno == EEXIST && find_delayed_link_source (file_name))
|
||||||
|
{
|
||||||
|
/* The placeholder file has already been created. This means
|
||||||
|
that the link being extracted is a duplicate of an already
|
||||||
|
processed one. Skip it.
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
switch (maybe_recoverable (file_name, false, interdir_made))
|
switch (maybe_recoverable (file_name, false, interdir_made))
|
||||||
{
|
{
|
||||||
case RECOVER_OK:
|
case RECOVER_OK:
|
||||||
@@ -1416,41 +1460,6 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find a delayed_link structure corresponding to the source NAME.
|
|
||||||
Such a structure exists in the delayed link list only if the link
|
|
||||||
placeholder file has been created. Therefore, try to stat the NAME
|
|
||||||
first. If it doesn't exist, there is no matching entry in the list.
|
|
||||||
Otherwise, look for the entry in list which has the matching dev
|
|
||||||
and ino numbers.
|
|
||||||
|
|
||||||
This approach avoids scanning the singly-linked list in obvious cases
|
|
||||||
and does not rely on comparing file names, which may differ for
|
|
||||||
various reasons (e.g. relative vs. absolute file names).
|
|
||||||
*/
|
|
||||||
static struct delayed_link *
|
|
||||||
find_delayed_link_source (char const *name)
|
|
||||||
{
|
|
||||||
struct delayed_link *dl;
|
|
||||||
struct stat st;
|
|
||||||
|
|
||||||
if (!delayed_link_head)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (fstatat (chdir_fd, name, &st, AT_SYMLINK_NOFOLLOW))
|
|
||||||
{
|
|
||||||
if (errno != ENOENT)
|
|
||||||
stat_error (name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (dl = delayed_link_head; dl; dl = dl->next)
|
|
||||||
{
|
|
||||||
if (dl->dev == st.st_dev && dl->ino == st.st_ino)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return dl;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
extract_link (char *file_name, int typeflag)
|
extract_link (char *file_name, int typeflag)
|
||||||
{
|
{
|
||||||
@@ -1708,7 +1717,12 @@ prepare_to_extract (char const *file_name, int typeflag, tar_extractor_t *fun)
|
|||||||
extractor = extract_file;
|
extractor = extract_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!EXTRACT_OVER_PIPE)
|
if (EXTRACT_OVER_PIPE)
|
||||||
|
{
|
||||||
|
if (extractor != extract_file)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
switch (old_files_option)
|
switch (old_files_option)
|
||||||
{
|
{
|
||||||
|
|||||||
38
src/list.c
38
src/list.c
@@ -408,26 +408,27 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
|||||||
enum read_header_mode mode)
|
enum read_header_mode mode)
|
||||||
{
|
{
|
||||||
union block *header;
|
union block *header;
|
||||||
union block *header_copy;
|
|
||||||
char *bp;
|
char *bp;
|
||||||
union block *data_block;
|
union block *data_block;
|
||||||
size_t size, written;
|
size_t size, written;
|
||||||
union block *next_long_name = 0;
|
union block *next_long_name = NULL;
|
||||||
union block *next_long_link = 0;
|
union block *next_long_link = NULL;
|
||||||
size_t next_long_name_blocks = 0;
|
size_t next_long_name_blocks = 0;
|
||||||
size_t next_long_link_blocks = 0;
|
size_t next_long_link_blocks = 0;
|
||||||
|
enum read_header status = HEADER_SUCCESS;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
enum read_header status;
|
|
||||||
|
|
||||||
header = find_next_block ();
|
header = find_next_block ();
|
||||||
*return_block = header;
|
*return_block = header;
|
||||||
if (!header)
|
if (!header)
|
||||||
return HEADER_END_OF_FILE;
|
{
|
||||||
|
status = HEADER_END_OF_FILE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if ((status = tar_checksum (header, false)) != HEADER_SUCCESS)
|
if ((status = tar_checksum (header, false)) != HEADER_SUCCESS)
|
||||||
return status;
|
break;
|
||||||
|
|
||||||
/* Good block. Decode file size and return. */
|
/* Good block. Decode file size and return. */
|
||||||
|
|
||||||
@@ -437,7 +438,10 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
|||||||
{
|
{
|
||||||
info->stat.st_size = OFF_FROM_HEADER (header->header.size);
|
info->stat.st_size = OFF_FROM_HEADER (header->header.size);
|
||||||
if (info->stat.st_size < 0)
|
if (info->stat.st_size < 0)
|
||||||
return HEADER_FAILURE;
|
{
|
||||||
|
status = HEADER_FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (header->header.typeflag == GNUTYPE_LONGNAME
|
if (header->header.typeflag == GNUTYPE_LONGNAME
|
||||||
@@ -447,10 +451,14 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
|||||||
|| header->header.typeflag == SOLARIS_XHDTYPE)
|
|| header->header.typeflag == SOLARIS_XHDTYPE)
|
||||||
{
|
{
|
||||||
if (mode == read_header_x_raw)
|
if (mode == read_header_x_raw)
|
||||||
return HEADER_SUCCESS_EXTENDED;
|
{
|
||||||
|
status = HEADER_SUCCESS_EXTENDED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
else if (header->header.typeflag == GNUTYPE_LONGNAME
|
else if (header->header.typeflag == GNUTYPE_LONGNAME
|
||||||
|| header->header.typeflag == GNUTYPE_LONGLINK)
|
|| header->header.typeflag == GNUTYPE_LONGLINK)
|
||||||
{
|
{
|
||||||
|
union block *header_copy;
|
||||||
size_t name_size = info->stat.st_size;
|
size_t name_size = info->stat.st_size;
|
||||||
size_t n = name_size % BLOCKSIZE;
|
size_t n = name_size % BLOCKSIZE;
|
||||||
size = name_size + BLOCKSIZE;
|
size = name_size + BLOCKSIZE;
|
||||||
@@ -517,7 +525,10 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
|||||||
xheader_decode_global (&xhdr);
|
xheader_decode_global (&xhdr);
|
||||||
xheader_destroy (&xhdr);
|
xheader_destroy (&xhdr);
|
||||||
if (mode == read_header_x_global)
|
if (mode == read_header_x_global)
|
||||||
return HEADER_SUCCESS_EXTENDED;
|
{
|
||||||
|
status = HEADER_SUCCESS_EXTENDED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Loop! */
|
/* Loop! */
|
||||||
@@ -536,6 +547,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
|||||||
name = next_long_name->buffer + BLOCKSIZE;
|
name = next_long_name->buffer + BLOCKSIZE;
|
||||||
recent_long_name = next_long_name;
|
recent_long_name = next_long_name;
|
||||||
recent_long_name_blocks = next_long_name_blocks;
|
recent_long_name_blocks = next_long_name_blocks;
|
||||||
|
next_long_name = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -567,6 +579,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
|||||||
name = next_long_link->buffer + BLOCKSIZE;
|
name = next_long_link->buffer + BLOCKSIZE;
|
||||||
recent_long_link = next_long_link;
|
recent_long_link = next_long_link;
|
||||||
recent_long_link_blocks = next_long_link_blocks;
|
recent_long_link_blocks = next_long_link_blocks;
|
||||||
|
next_long_link = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -578,9 +591,12 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
|||||||
}
|
}
|
||||||
assign_string (&info->link_name, name);
|
assign_string (&info->link_name, name);
|
||||||
|
|
||||||
return HEADER_SUCCESS;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free (next_long_name);
|
||||||
|
free (next_long_link);
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define ISOCTAL(c) ((c)>='0'&&(c)<='7')
|
#define ISOCTAL(c) ((c)>='0'&&(c)<='7')
|
||||||
|
|||||||
56
src/misc.c
56
src/misc.c
@@ -908,8 +908,6 @@ chdir_count (void)
|
|||||||
int
|
int
|
||||||
chdir_arg (char const *dir)
|
chdir_arg (char const *dir)
|
||||||
{
|
{
|
||||||
char *absdir;
|
|
||||||
|
|
||||||
if (wd_count == wd_alloc)
|
if (wd_count == wd_alloc)
|
||||||
{
|
{
|
||||||
if (wd_alloc == 0)
|
if (wd_alloc == 0)
|
||||||
@@ -919,9 +917,7 @@ chdir_arg (char const *dir)
|
|||||||
if (! wd_count)
|
if (! wd_count)
|
||||||
{
|
{
|
||||||
wd[wd_count].name = ".";
|
wd[wd_count].name = ".";
|
||||||
wd[wd_count].abspath = xgetcwd ();
|
wd[wd_count].abspath = NULL;
|
||||||
if (!wd[wd_count].abspath)
|
|
||||||
call_arg_fatal ("getcwd", ".");
|
|
||||||
wd[wd_count].fd = AT_FDCWD;
|
wd[wd_count].fd = AT_FDCWD;
|
||||||
wd_count++;
|
wd_count++;
|
||||||
}
|
}
|
||||||
@@ -938,22 +934,8 @@ chdir_arg (char const *dir)
|
|||||||
return wd_count - 1;
|
return wd_count - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* If the given name is absolute, use it to represent this directory;
|
|
||||||
otherwise, construct a name based on the previous -C option. */
|
|
||||||
if (IS_ABSOLUTE_FILE_NAME (dir))
|
|
||||||
absdir = xstrdup (dir);
|
|
||||||
else if (wd[wd_count - 1].abspath)
|
|
||||||
{
|
|
||||||
namebuf_t nbuf = namebuf_create (wd[wd_count - 1].abspath);
|
|
||||||
namebuf_add_dir (nbuf, dir);
|
|
||||||
absdir = namebuf_finish (nbuf);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
absdir = 0;
|
|
||||||
|
|
||||||
wd[wd_count].name = dir;
|
wd[wd_count].name = dir;
|
||||||
wd[wd_count].abspath = absdir;
|
wd[wd_count].abspath = NULL;
|
||||||
wd[wd_count].fd = 0;
|
wd[wd_count].fd = 0;
|
||||||
return wd_count++;
|
return wd_count++;
|
||||||
}
|
}
|
||||||
@@ -1054,6 +1036,40 @@ tar_getcdpath (int idx)
|
|||||||
}
|
}
|
||||||
return cwd;
|
return cwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!wd[idx].abspath)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int save_cwdi = chdir_current;
|
||||||
|
|
||||||
|
for (i = idx; i >= 0; i--)
|
||||||
|
if (wd[i].abspath)
|
||||||
|
break;
|
||||||
|
|
||||||
|
while (++i <= idx)
|
||||||
|
{
|
||||||
|
chdir_do (i);
|
||||||
|
if (i == 0)
|
||||||
|
{
|
||||||
|
if ((wd[i].abspath = xgetcwd ()) == NULL)
|
||||||
|
call_arg_fatal ("getcwd", ".");
|
||||||
|
}
|
||||||
|
else if (IS_ABSOLUTE_FILE_NAME (wd[i].name))
|
||||||
|
/* If the given name is absolute, use it to represent this
|
||||||
|
directory; otherwise, construct a name based on the
|
||||||
|
previous -C option. */
|
||||||
|
wd[i].abspath = xstrdup (wd[i].name);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
namebuf_t nbuf = namebuf_create (wd[i - 1].abspath);
|
||||||
|
namebuf_add_dir (nbuf, wd[i].name);
|
||||||
|
wd[i].abspath = namebuf_finish (nbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
chdir_do (save_cwdi);
|
||||||
|
}
|
||||||
|
|
||||||
return wd[idx].abspath;
|
return wd[idx].abspath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2248,7 +2248,7 @@ parse_default_options (struct tar_args *args)
|
|||||||
if (argp_parse (&argp,
|
if (argp_parse (&argp,
|
||||||
ws.ws_offs + ws.ws_wordc,
|
ws.ws_offs + ws.ws_wordc,
|
||||||
ws.ws_wordv,
|
ws.ws_wordv,
|
||||||
ARGP_IN_ORDER|ARGP_NO_EXIT, &idx, &args))
|
ARGP_IN_ORDER|ARGP_NO_EXIT, &idx, args))
|
||||||
abort (); /* shouldn't happen */
|
abort (); /* shouldn't happen */
|
||||||
args->loc = save_loc_ptr;
|
args->loc = save_loc_ptr;
|
||||||
if (name_more_files ())
|
if (name_more_files ())
|
||||||
@@ -2751,8 +2751,11 @@ main (int argc, char **argv)
|
|||||||
|
|
||||||
set_quoting_style (0, DEFAULT_QUOTING_STYLE);
|
set_quoting_style (0, DEFAULT_QUOTING_STYLE);
|
||||||
|
|
||||||
|
close_stdout_set_file_name (_("stdout"));
|
||||||
/* Make sure we have first three descriptors available */
|
/* Make sure we have first three descriptors available */
|
||||||
stdopen ();
|
if (stdopen ())
|
||||||
|
FATAL_ERROR ((0, 0, "%s",
|
||||||
|
_("failed to assert availability of the standard file descriptors")));
|
||||||
|
|
||||||
/* Pre-allocate a few structures. */
|
/* Pre-allocate a few structures. */
|
||||||
|
|
||||||
|
|||||||
@@ -122,6 +122,7 @@ TESTSUITE_AT = \
|
|||||||
extrac21.at\
|
extrac21.at\
|
||||||
extrac22.at\
|
extrac22.at\
|
||||||
extrac23.at\
|
extrac23.at\
|
||||||
|
extrac24.at\
|
||||||
filerem01.at\
|
filerem01.at\
|
||||||
filerem02.at\
|
filerem02.at\
|
||||||
dirrem01.at\
|
dirrem01.at\
|
||||||
|
|||||||
@@ -44,10 +44,11 @@ rm -rf dir
|
|||||||
# restore _all_ xattrs (not just the user.* domain)
|
# restore _all_ xattrs (not just the user.* domain)
|
||||||
tar --xattrs --xattrs-include='*' -xf archive.tar
|
tar --xattrs --xattrs-include='*' -xf archive.tar
|
||||||
|
|
||||||
getcap dir/file
|
# Newer systems print = instead of + here
|
||||||
|
getcap dir/file | sed 's/+/=/'
|
||||||
],
|
],
|
||||||
[0],
|
[0],
|
||||||
[dir/file = cap_chown+ei
|
[dir/file = cap_chown=ei
|
||||||
])
|
])
|
||||||
|
|
||||||
AT_CLEANUP
|
AT_CLEANUP
|
||||||
|
|||||||
41
tests/extrac24.at
Normal file
41
tests/extrac24.at
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Test suite for GNU tar. -*- autotest -*-
|
||||||
|
# Copyright 2021 Free Software Foundation, Inc.
|
||||||
|
#
|
||||||
|
# This file is part of GNU tar.
|
||||||
|
#
|
||||||
|
# GNU tar is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# GNU tar is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
AT_SETUP([--to-stdout])
|
||||||
|
AT_KEYWORDS([extract extrac24 to-stdout])
|
||||||
|
|
||||||
|
# Description: When extracting over pipe, only regular files should be
|
||||||
|
# extracted. In tar 1.33 this was broken, so that members of other types
|
||||||
|
# (in particular, directories) were extracted as usual. This test ensures
|
||||||
|
# that this is no longer the case.
|
||||||
|
#
|
||||||
|
# References: https://bugs.archlinux.org/task/69373,
|
||||||
|
# https://savannah.gnu.org/bugs/?60002
|
||||||
|
|
||||||
|
AT_TAR_CHECK([
|
||||||
|
mkdir dir/
|
||||||
|
echo TEXT > dir/file
|
||||||
|
tar cf a.tar dir
|
||||||
|
rm -r dir
|
||||||
|
tar --extract --to-stdout --file a.tar
|
||||||
|
test -d dir
|
||||||
|
],
|
||||||
|
[1],
|
||||||
|
[TEXT
|
||||||
|
])
|
||||||
|
|
||||||
|
AT_CLEANUP
|
||||||
@@ -344,6 +344,7 @@ m4_include([extrac20.at])
|
|||||||
m4_include([extrac21.at])
|
m4_include([extrac21.at])
|
||||||
m4_include([extrac22.at])
|
m4_include([extrac22.at])
|
||||||
m4_include([extrac23.at])
|
m4_include([extrac23.at])
|
||||||
|
m4_include([extrac24.at])
|
||||||
|
|
||||||
m4_include([backup01.at])
|
m4_include([backup01.at])
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user