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>
|
||||
|
||||
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
|
||||
|
||||
* 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
|
||||
# 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_AUX_DIR([build-aux])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
|
||||
@@ -83,6 +83,7 @@ stat-time
|
||||
stdbool
|
||||
stdint
|
||||
stpcpy
|
||||
stdopen
|
||||
strdup-posix
|
||||
strerror
|
||||
strnlen
|
||||
|
||||
@@ -32,7 +32,6 @@ AM_CFLAGS = $(GNULIB_WARN_CFLAGS) $(WERROR_CFLAGS)
|
||||
noinst_HEADERS = \
|
||||
paxlib.h\
|
||||
rmt.h\
|
||||
stdopen.h\
|
||||
system.h\
|
||||
system-ioctl.h\
|
||||
wordsplit.h\
|
||||
@@ -42,7 +41,6 @@ libtar_a_SOURCES = \
|
||||
paxerror.c paxexit-status.c paxlib.h paxnames.c \
|
||||
rtapelib.c \
|
||||
rmt.h \
|
||||
stdopen.c stdopen.h \
|
||||
system.h system-ioctl.h \
|
||||
wordsplit.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~
|
||||
/Makefile.in.in~
|
||||
*.gmo
|
||||
|
||||
205
src/delete.c
205
src/delete.c
@@ -147,6 +147,23 @@ write_recent_bytes (char *data, size_t bytes)
|
||||
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
|
||||
delete_archive_members (void)
|
||||
{
|
||||
@@ -155,7 +172,6 @@ delete_archive_members (void)
|
||||
|
||||
/* FIXME: Should clean the routine before cleaning these variables :-( */
|
||||
struct name *name;
|
||||
off_t blocks_to_skip = 0;
|
||||
off_t blocks_to_keep = 0;
|
||||
int kept_blocks_in_record;
|
||||
|
||||
@@ -163,11 +179,12 @@ delete_archive_members (void)
|
||||
open_archive (ACCESS_UPDATE);
|
||||
acting_as_filter = strcmp (archive_name_array[0], "-") == 0;
|
||||
|
||||
/* Skip to the first member that matches the name list. */
|
||||
do
|
||||
{
|
||||
enum read_header status = read_header (¤t_header,
|
||||
¤t_stat_info,
|
||||
read_header_x_raw);
|
||||
¤t_stat_info,
|
||||
read_header_x_raw);
|
||||
|
||||
switch (status)
|
||||
{
|
||||
@@ -181,7 +198,7 @@ delete_archive_members (void)
|
||||
break;
|
||||
}
|
||||
name->found_count++;
|
||||
if (!ISFOUND(name))
|
||||
if (!ISFOUND (name))
|
||||
{
|
||||
skip_member ();
|
||||
break;
|
||||
@@ -243,15 +260,12 @@ delete_archive_members (void)
|
||||
|
||||
if (logical_status == HEADER_SUCCESS)
|
||||
{
|
||||
/* FIXME: Pheew! This is crufty code! */
|
||||
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:
|
||||
"delete.c", line 223: warning: loop not entered at top
|
||||
Reported by Bruno Haible. */
|
||||
while (1)
|
||||
/* Skip matching members and move the rest up the archive. */
|
||||
while (logical_status != HEADER_END_OF_FILE)
|
||||
{
|
||||
enum read_header status;
|
||||
|
||||
@@ -259,105 +273,108 @@ delete_archive_members (void)
|
||||
|
||||
if (current_block == record_end)
|
||||
flush_archive ();
|
||||
|
||||
status = read_header (¤t_header, ¤t_stat_info,
|
||||
read_header_auto);
|
||||
read_header_auto);
|
||||
|
||||
xheader_decode (¤t_stat_info);
|
||||
|
||||
if (status == HEADER_ZERO_BLOCK && ignore_zeros_option)
|
||||
switch (status)
|
||||
{
|
||||
set_next_block_after (current_header);
|
||||
continue;
|
||||
}
|
||||
if (status == HEADER_END_OF_FILE || status == HEADER_ZERO_BLOCK)
|
||||
{
|
||||
logical_status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
}
|
||||
case HEADER_STILL_UNREAD:
|
||||
case HEADER_SUCCESS_EXTENDED:
|
||||
abort ();
|
||||
|
||||
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. */
|
||||
xheader_decode (¤t_stat_info);
|
||||
|
||||
/* Found another header. */
|
||||
|
||||
if ((name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
{
|
||||
name->found_count++;
|
||||
if (ISFOUND(name))
|
||||
if ((name = name_scan (current_stat_info.file_name)) != NULL)
|
||||
{
|
||||
flush_file:
|
||||
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)
|
||||
name->found_count++;
|
||||
if (ISFOUND (name))
|
||||
{
|
||||
blocks_to_skip -= (record_end - current_block);
|
||||
flush_archive ();
|
||||
flush_file ();
|
||||
break;
|
||||
}
|
||||
current_block += blocks_to_skip;
|
||||
blocks_to_skip = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Copy header. */
|
||||
/* Copy header. */
|
||||
|
||||
if (current_stat_info.xhdr.size)
|
||||
{
|
||||
write_recent_bytes (current_stat_info.xhdr.buffer,
|
||||
current_stat_info.xhdr.size);
|
||||
}
|
||||
else
|
||||
{
|
||||
write_recent_blocks (recent_long_name, recent_long_name_blocks);
|
||||
write_recent_blocks (recent_long_link, recent_long_link_blocks);
|
||||
}
|
||||
new_record[new_blocks] = *current_header;
|
||||
new_blocks++;
|
||||
blocks_to_keep
|
||||
= (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
set_next_block_after (current_header);
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
|
||||
/* Copy data. */
|
||||
|
||||
kept_blocks_in_record = record_end - current_block;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
|
||||
while (blocks_to_keep)
|
||||
{
|
||||
int count;
|
||||
|
||||
if (current_block == record_end)
|
||||
if (current_stat_info.xhdr.size)
|
||||
{
|
||||
flush_read ();
|
||||
current_block = record_start;
|
||||
kept_blocks_in_record = blocking_factor;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
write_recent_bytes (current_stat_info.xhdr.buffer,
|
||||
current_stat_info.xhdr.size);
|
||||
}
|
||||
count = kept_blocks_in_record;
|
||||
if (blocking_factor - new_blocks < count)
|
||||
count = blocking_factor - new_blocks;
|
||||
|
||||
if (! count)
|
||||
abort ();
|
||||
|
||||
memcpy (new_record + new_blocks, current_block, count * BLOCKSIZE);
|
||||
new_blocks += count;
|
||||
current_block += count;
|
||||
blocks_to_keep -= count;
|
||||
kept_blocks_in_record -= count;
|
||||
|
||||
else
|
||||
{
|
||||
write_recent_blocks (recent_long_name,
|
||||
recent_long_name_blocks);
|
||||
write_recent_blocks (recent_long_link,
|
||||
recent_long_link_blocks);
|
||||
}
|
||||
new_record[new_blocks] = *current_header;
|
||||
new_blocks++;
|
||||
blocks_to_keep
|
||||
= (current_stat_info.stat.st_size + BLOCKSIZE - 1) / BLOCKSIZE;
|
||||
set_next_block_after (current_header);
|
||||
if (new_blocks == blocking_factor)
|
||||
write_record (1);
|
||||
|
||||
/* Copy data. */
|
||||
|
||||
kept_blocks_in_record = record_end - current_block;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
|
||||
while (blocks_to_keep)
|
||||
{
|
||||
int count;
|
||||
|
||||
if (current_block == record_end)
|
||||
{
|
||||
flush_read ();
|
||||
current_block = record_start;
|
||||
kept_blocks_in_record = blocking_factor;
|
||||
if (kept_blocks_in_record > blocks_to_keep)
|
||||
kept_blocks_in_record = blocks_to_keep;
|
||||
}
|
||||
count = kept_blocks_in_record;
|
||||
if (blocking_factor - new_blocks < count)
|
||||
count = blocking_factor - new_blocks;
|
||||
|
||||
if (! count)
|
||||
abort ();
|
||||
|
||||
memcpy (new_record + new_blocks, current_block,
|
||||
count * BLOCKSIZE);
|
||||
new_blocks += count;
|
||||
current_block += count;
|
||||
blocks_to_keep -= count;
|
||||
kept_blocks_in_record -= count;
|
||||
|
||||
if (new_blocks == blocking_factor)
|
||||
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)
|
||||
|
||||
@@ -1323,6 +1323,41 @@ extract_file (char *file_name, int typeflag)
|
||||
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
|
||||
replaced after other extraction is done by a symbolic link if
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
case RECOVER_OK:
|
||||
@@ -1416,41 +1460,6 @@ create_placeholder_file (char *file_name, bool is_symlink, bool *interdir_made,
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
if (!EXTRACT_OVER_PIPE)
|
||||
if (EXTRACT_OVER_PIPE)
|
||||
{
|
||||
if (extractor != extract_file)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (old_files_option)
|
||||
{
|
||||
|
||||
40
src/list.c
40
src/list.c
@@ -408,26 +408,27 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
enum read_header_mode mode)
|
||||
{
|
||||
union block *header;
|
||||
union block *header_copy;
|
||||
char *bp;
|
||||
union block *data_block;
|
||||
size_t size, written;
|
||||
union block *next_long_name = 0;
|
||||
union block *next_long_link = 0;
|
||||
union block *next_long_name = NULL;
|
||||
union block *next_long_link = NULL;
|
||||
size_t next_long_name_blocks = 0;
|
||||
size_t next_long_link_blocks = 0;
|
||||
|
||||
enum read_header status = HEADER_SUCCESS;
|
||||
|
||||
while (1)
|
||||
{
|
||||
enum read_header status;
|
||||
|
||||
header = find_next_block ();
|
||||
*return_block = header;
|
||||
if (!header)
|
||||
return HEADER_END_OF_FILE;
|
||||
{
|
||||
status = HEADER_END_OF_FILE;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((status = tar_checksum (header, false)) != HEADER_SUCCESS)
|
||||
return status;
|
||||
break;
|
||||
|
||||
/* 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);
|
||||
if (info->stat.st_size < 0)
|
||||
return HEADER_FAILURE;
|
||||
{
|
||||
status = HEADER_FAILURE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (mode == read_header_x_raw)
|
||||
return HEADER_SUCCESS_EXTENDED;
|
||||
{
|
||||
status = HEADER_SUCCESS_EXTENDED;
|
||||
break;
|
||||
}
|
||||
else if (header->header.typeflag == GNUTYPE_LONGNAME
|
||||
|| header->header.typeflag == GNUTYPE_LONGLINK)
|
||||
{
|
||||
union block *header_copy;
|
||||
size_t name_size = info->stat.st_size;
|
||||
size_t n = 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_destroy (&xhdr);
|
||||
if (mode == read_header_x_global)
|
||||
return HEADER_SUCCESS_EXTENDED;
|
||||
{
|
||||
status = HEADER_SUCCESS_EXTENDED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Loop! */
|
||||
@@ -536,6 +547,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
name = next_long_name->buffer + BLOCKSIZE;
|
||||
recent_long_name = next_long_name;
|
||||
recent_long_name_blocks = next_long_name_blocks;
|
||||
next_long_name = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -567,6 +579,7 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
name = next_long_link->buffer + BLOCKSIZE;
|
||||
recent_long_link = next_long_link;
|
||||
recent_long_link_blocks = next_long_link_blocks;
|
||||
next_long_link = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -578,9 +591,12 @@ read_header (union block **return_block, struct tar_stat_info *info,
|
||||
}
|
||||
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')
|
||||
|
||||
56
src/misc.c
56
src/misc.c
@@ -908,8 +908,6 @@ chdir_count (void)
|
||||
int
|
||||
chdir_arg (char const *dir)
|
||||
{
|
||||
char *absdir;
|
||||
|
||||
if (wd_count == wd_alloc)
|
||||
{
|
||||
if (wd_alloc == 0)
|
||||
@@ -919,9 +917,7 @@ chdir_arg (char const *dir)
|
||||
if (! wd_count)
|
||||
{
|
||||
wd[wd_count].name = ".";
|
||||
wd[wd_count].abspath = xgetcwd ();
|
||||
if (!wd[wd_count].abspath)
|
||||
call_arg_fatal ("getcwd", ".");
|
||||
wd[wd_count].abspath = NULL;
|
||||
wd[wd_count].fd = AT_FDCWD;
|
||||
wd_count++;
|
||||
}
|
||||
@@ -938,22 +934,8 @@ chdir_arg (char const *dir)
|
||||
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].abspath = absdir;
|
||||
wd[wd_count].abspath = NULL;
|
||||
wd[wd_count].fd = 0;
|
||||
return wd_count++;
|
||||
}
|
||||
@@ -1054,6 +1036,40 @@ tar_getcdpath (int idx)
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -2248,7 +2248,7 @@ parse_default_options (struct tar_args *args)
|
||||
if (argp_parse (&argp,
|
||||
ws.ws_offs + ws.ws_wordc,
|
||||
ws.ws_wordv,
|
||||
ARGP_IN_ORDER|ARGP_NO_EXIT, &idx, &args))
|
||||
ARGP_IN_ORDER|ARGP_NO_EXIT, &idx, args))
|
||||
abort (); /* shouldn't happen */
|
||||
args->loc = save_loc_ptr;
|
||||
if (name_more_files ())
|
||||
@@ -2751,8 +2751,11 @@ main (int argc, char **argv)
|
||||
|
||||
set_quoting_style (0, DEFAULT_QUOTING_STYLE);
|
||||
|
||||
close_stdout_set_file_name (_("stdout"));
|
||||
/* 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. */
|
||||
|
||||
|
||||
@@ -122,6 +122,7 @@ TESTSUITE_AT = \
|
||||
extrac21.at\
|
||||
extrac22.at\
|
||||
extrac23.at\
|
||||
extrac24.at\
|
||||
filerem01.at\
|
||||
filerem02.at\
|
||||
dirrem01.at\
|
||||
|
||||
@@ -44,10 +44,11 @@ rm -rf dir
|
||||
# restore _all_ xattrs (not just the user.* domain)
|
||||
tar --xattrs --xattrs-include='*' -xf archive.tar
|
||||
|
||||
getcap dir/file
|
||||
# Newer systems print = instead of + here
|
||||
getcap dir/file | sed 's/+/=/'
|
||||
],
|
||||
[0],
|
||||
[dir/file = cap_chown+ei
|
||||
[dir/file = cap_chown=ei
|
||||
])
|
||||
|
||||
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([extrac22.at])
|
||||
m4_include([extrac23.at])
|
||||
m4_include([extrac24.at])
|
||||
|
||||
m4_include([backup01.at])
|
||||
|
||||
|
||||
Reference in New Issue
Block a user