mirror of
https://git.savannah.gnu.org/git/tar.git
synced 2026-10-22 00:22:34 +00:00
tar: don’t dereference -hxg removals
When using ‘tar -h -x -g/dev/null’, do not dereference when removing the destination. Problem reported by Peng Gao in: https://lists.gnu.org/r/bug-tar/2026-09/msg00014.html * src/misc.c (FDBASE_NOFOLLOW): New flag. (remove_any_file, tar_savedir): Use it. (open_subdir): Support it.
This commit is contained in:
@@ -411,6 +411,7 @@ Paul Siddall pauls@postman.essex.ac.uk
|
||||
Pavel Raiskup praiskup@redhat.com
|
||||
Peder Chr. Norgaard pcn@tbit.dk
|
||||
Pekka Janhunen Pekka.Janhunen@fmi.fi
|
||||
Peng Gao gaopengsha@gmail.com
|
||||
Per Bojsen pb@delta.dk
|
||||
Per Foreby perf@efd.lth.se
|
||||
Pete Geenhuizen peteg@beno.css.gov
|
||||
|
||||
+16
-8
@@ -46,6 +46,10 @@ enum
|
||||
|
||||
/* Follow symlinks, regardless of open_searchdir_how. */
|
||||
FDBASE_FOLLOW = 1 << 3,
|
||||
|
||||
/* Do not follow symlinks, regardless of open_searchdir_how.
|
||||
This option overrides FDBASE_FOLLOW. */
|
||||
FDBASE_NOFOLLOW = 1 << 4,
|
||||
};
|
||||
|
||||
static void namebuf_add_dir (namebuf_t, char const *);
|
||||
@@ -716,7 +720,7 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
non-directory. */
|
||||
bool try_unlink_first = cannot_unlink_dir ();
|
||||
|
||||
struct fdbase f = fdbase (file_name);
|
||||
struct fdbase f = fdbase_opendir (file_name, FDBASE_NOFOLLOW);
|
||||
|
||||
if (try_unlink_first)
|
||||
{
|
||||
@@ -783,7 +787,8 @@ remove_any_file (const char *file_name, enum remove_option option)
|
||||
}
|
||||
|
||||
free (directory);
|
||||
return safer_rmdir (file_name, fdbase (file_name)) == 0;
|
||||
struct fdbase f1 = fdbase_opendir (file_name, FDBASE_NOFOLLOW);
|
||||
return safer_rmdir (file_name, f1) == 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1294,8 +1299,9 @@ open_subdir (int fd, char const *subdir, int fflags)
|
||||
{
|
||||
struct open_how how =
|
||||
{
|
||||
.flags = (open_searchdir_how.flags
|
||||
& ~(fflags & FDBASE_FOLLOW ? O_NOFOLLOW : 0)),
|
||||
.flags = ((open_searchdir_how.flags
|
||||
& ~(fflags & FDBASE_FOLLOW ? O_NOFOLLOW : 0))
|
||||
| (fflags & FDBASE_NOFOLLOW ? O_NOFOLLOW : 0)),
|
||||
.resolve = fflags & FDBASE_ESCAPE ? 0 : open_searchdir_how.resolve
|
||||
};
|
||||
return openat2 (fd, subdir, &how, sizeof how);
|
||||
@@ -1729,8 +1735,8 @@ namebuf_finish (namebuf_t buf)
|
||||
}
|
||||
|
||||
/* Return the filenames in directory NAME, relative to the chdir_fd.
|
||||
If the directory does not exist, report error if MUST_EXIST is
|
||||
true.
|
||||
If MUST_EXIST, report an error if the directory does not exist;
|
||||
if !MUST_EXIST, do not follow symlinks regardless of -h.
|
||||
|
||||
Return NULL on errors.
|
||||
*/
|
||||
@@ -1739,9 +1745,11 @@ tar_savedir (const char *name, bool must_exist)
|
||||
{
|
||||
char *ret = NULL;
|
||||
DIR *dir = NULL;
|
||||
struct fdbase f = fdbase (name);
|
||||
struct fdbase f = fdbase_opendir (name, must_exist ? 0 : FDBASE_NOFOLLOW);
|
||||
int fd = (f.fd == BADFD ? -1
|
||||
: openat (f.fd, f.base, open_read_flags | O_DIRECTORY));
|
||||
: openat (f.fd, f.base,
|
||||
(open_read_flags | O_DIRECTORY
|
||||
| (must_exist ? 0 : O_NOFOLLOW))));
|
||||
if (fd < 0)
|
||||
{
|
||||
if (!must_exist && errno == ENOENT)
|
||||
|
||||
Reference in New Issue
Block a user