From 998e4660cf0e65706d1c4235c3cc5ea0fb8322d9 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Oct 30 2018 04:57:24 +0000 Subject: import coreutils-8.22-23.el7 --- diff --git a/SOURCES/coreutils-8.22-df-filtermountlistupdate.patch b/SOURCES/coreutils-8.22-df-filtermountlistupdate.patch index 208437c..b50fb56 100644 --- a/SOURCES/coreutils-8.22-df-filtermountlistupdate.patch +++ b/SOURCES/coreutils-8.22-df-filtermountlistupdate.patch @@ -1,7 +1,8 @@ -diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c ---- coreutils-8.22-orig/src/df.c 2015-07-06 15:51:56.218101224 +0200 -+++ coreutils-8.22/src/df.c 2015-07-06 16:07:14.429941697 +0200 -@@ -47,12 +47,12 @@ struct devlist +diff --git a/src/df.c b/src/df.c +index e28a656..fe222d9 100644 +--- a/src/df.c ++++ b/src/df.c +@@ -45,12 +45,12 @@ /* Filled with device numbers of examined file systems to avoid duplicities in output. */ @@ -16,7 +17,7 @@ diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c /* If true, show even file systems with zero size or uninteresting types. */ -@@ -617,7 +617,7 @@ excluded_fstype (const char *fstype) +@@ -609,13 +609,10 @@ excluded_fstype (const char *fstype) me_mountdir wins. */ static void @@ -25,17 +26,13 @@ diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c { struct mount_entry *me; -@@ -621,9 +621,6 @@ filter_mount_list (void) - { - struct mount_entry *me; - - /* Store of already-processed device numbers. */ - struct devlist *devlist_head = NULL; - /* Sort all 'wanted' entries into the list devlist_head. */ for (me = mount_list; me;) { -@@ -631,41 +628,66 @@ filter_mount_list (void) +@@ -623,41 +620,66 @@ filter_mount_list (void) struct devlist *devlist; struct mount_entry *discard_me = NULL; @@ -122,7 +119,7 @@ diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c } else { -@@ -673,28 +695,49 @@ filter_mount_list (void) +@@ -665,28 +687,49 @@ filter_mount_list (void) devlist = xmalloc (sizeof *devlist); devlist->me = me; devlist->dev_num = buf.st_dev; @@ -138,16 +135,6 @@ diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c /* Finally rebuild the mount_list from the devlist. */ - mount_list = NULL; - while (devlist_head) -- { -- /* Add the mount entry. */ -- me = devlist_head->me; -- me->me_next = mount_list; -- mount_list = me; -- /* Free devlist entry and advance. */ -- struct devlist *devlist = devlist_head->next; -- free (devlist_head); -- devlist_head = devlist; -- } + if (! devices_only) { + mount_list = NULL; + while (device_list) @@ -162,8 +149,8 @@ diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c + device_list = devlist; + } + } - } - ++} ++ +/* Search a mount entry list for device id DEV. + Return the corresponding mount entry if found or NULL if not. */ + @@ -173,20 +160,28 @@ diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c + struct devlist *dl = device_list; + + while (dl) -+ { + { +- /* Add the mount entry. */ +- me = devlist_head->me; +- me->me_next = mount_list; +- mount_list = me; +- /* Free devlist entry and advance. */ +- struct devlist *devlist = devlist_head->next; +- free (devlist_head); +- devlist_head = devlist; + if (dl->dev_num == dev) + return dl->me; + dl = dl->next; -+ } + } + + return NULL; -+} -+ + } + + /* Return true if N is a known integer value. On many file systems, UINTMAX_MAX represents an unknown value; on AIX, UINTMAX_MAX - 1 represents unknown. Use a rule that works on AIX file systems, and -@@ -887,6 +887,11 @@ get_dev (char const *disk, char const *m +@@ -856,6 +899,11 @@ get_dev (char const *disk, char const *mount_point, char const* file, if (!selected_fstype (fstype) || excluded_fstype (fstype)) return; @@ -198,7 +193,7 @@ diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c /* If MOUNT_POINT is NULL, then the file system is not mounted, and this program reports on the file system that the special file is on. It would be better to report on the unmounted file system, -@@ -900,9 +924,43 @@ get_dev (char const *disk, char const *m +@@ -868,9 +916,43 @@ get_dev (char const *disk, char const *mount_point, char const* file, fsu = *force_fsu; else if (get_fs_usage (stat_file, disk, &fsu)) { @@ -245,7 +240,7 @@ diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c } if (fsu.fsu_blocks == 0 && !show_all_fs && !show_listed_fs) -@@ -1320,8 +1325,7 @@ get_all_entries (void) +@@ -1275,8 +1357,7 @@ get_all_entries (void) { struct mount_entry *me; @@ -255,10 +250,20 @@ diff -urNp coreutils-8.22-orig/src/df.c coreutils-8.22/src/df.c for (me = mount_list; me; me = me->me_next) get_dev (me->me_devname, me->me_mountdir, NULL, NULL, me->me_type, -diff -urNp coreutils-8.22-orig/doc/coreutils.texi coreutils-8.22/doc/coreutils.texi ---- coreutils-8.22-orig/doc/coreutils.texi 2015-07-06 17:44:13.266328267 +0200 -+++ coreutils-8.22/doc/coreutils.texi 2015-07-06 17:48:41.612327379 +0200 -@@ -11149,11 +11149,15 @@ The program accepts the following option +@@ -1325,7 +1406,7 @@ or all file systems by default.\n\ + emit_mandatory_arg_note (); + + fputs (_("\ +- -a, --all include dummy file systems\n\ ++ -a, --all include pseudo, duplicate, inaccessible file systems\n\ + -B, --block-size=SIZE scale sizes by SIZE before printing them; e.g.,\n\ + '-BM' prints sizes in units of 1,048,576 bytes;\n\ + see SIZE format below\n\ +diff --git a/doc/coreutils.texi b/doc/coreutils.texi +index 942d9a1..1df1eac 100644 +--- a/doc/coreutils.texi ++++ b/doc/coreutils.texi +@@ -11123,11 +11123,15 @@ The program accepts the following options. Also see @ref{Common options}. @itemx --all @opindex -a @opindex --all @@ -278,9 +283,10 @@ diff -urNp coreutils-8.22-orig/doc/coreutils.texi coreutils-8.22/doc/coreutils.t @item -B @var{size} @itemx --block-size=@var{size} -diff -urNp coreutils-8.22-orig/tests/df/skip-duplicates.sh coreutils-8.22/tests/df/skip-duplicates.sh ---- coreutils-8.22-orig/tests/df/skip-duplicates.sh 2013-12-04 15:48:30.000000000 +0100 -+++ coreutils-8.22/tests/df/skip-duplicates.sh 2015-07-06 17:45:47.176027871 +0200 +diff --git a/tests/df/skip-duplicates.sh b/tests/df/skip-duplicates.sh +index 1e94dc0..4069604 100755 +--- a/tests/df/skip-duplicates.sh ++++ b/tests/df/skip-duplicates.sh @@ -2,7 +2,7 @@ # Test df's behavior when the mount list contains duplicate entries. # This test is skipped on systems that lack LD_PRELOAD support; that's fine. @@ -295,14 +301,13 @@ diff -urNp coreutils-8.22-orig/tests/df/skip-duplicates.sh coreutils-8.22/tests/ require_gcc_shared_ -df || skip_ "df fails" -- --# Simulate an mtab file with two entries of the same device number. --# Also add entries with unstatable mount dirs to ensure that's handled. --cat > k.c <<'EOF' || framework_failure_ +# We use --local here so as to not activate +# potentially very many remote mounts. +df --local || skip_ 'df fails' -+ + +-# Simulate an mtab file with two entries of the same device number. +-# Also add entries with unstatable mount dirs to ensure that's handled. +-cat > k.c <<'EOF' || framework_failure_ +export CU_NONROOT_FS=$(df --local --output=target 2>&1 | grep /. | head -n1) +export CU_REMOTE_FS=$(df --local --output=target 2>&1 | grep /. | + tail -n+2 | head -n1) @@ -442,14 +447,13 @@ diff -urNp coreutils-8.22-orig/tests/df/skip-duplicates.sh coreutils-8.22/tests/ -# consist of a header and one entry. -LD_PRELOAD=./k.so df >out || fail=1 -test $(wc -l out && fail=1 --test $(wc -l out || fail=1 +test $(wc -l out && fail=1 +-test $(wc -l out || fail=1 +test "$CU_REMOTE_FS" && elide_remote=1 || elide_remote=0 @@ -484,9 +488,10 @@ diff -urNp coreutils-8.22-orig/tests/df/skip-duplicates.sh coreutils-8.22/tests/ # Ensure that filtering duplicates does not affect # argument processing (now without the fake getmntent()). -diff -urNp coreutils-8.22-orig/init.cfg coreutils-8.22/init.cfg ---- coreutils-8.22-orig/init.cfg 2015-07-06 18:04:08.930235675 +0200 -+++ coreutils-8.22/init.cfg 2015-07-06 18:04:41.939481587 +0200 +diff --git a/init.cfg b/init.cfg +index 360d4da..16f9813 100644 +--- a/init.cfg ++++ b/init.cfg @@ -472,6 +472,18 @@ require_sparse_support_() fi } diff --git a/SOURCES/coreutils-8.22-mv-n-noreplace.patch b/SOURCES/coreutils-8.22-mv-n-noreplace.patch new file mode 100644 index 0000000..574ad19 --- /dev/null +++ b/SOURCES/coreutils-8.22-mv-n-noreplace.patch @@ -0,0 +1,1017 @@ +From 76df06ff8fa39ae0cb0d167b7f622139778dc7d7 Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Thu, 4 Jan 2018 09:42:10 +0100 +Subject: [PATCH] mv -n: do not overwrite the destination + +... if it is created by another process after mv has checked its +non-existence. + +* src/copy.c (copy_internal): Use renameat2 (..., RENAME_NOREPLACE) +if called by mv -n. If it fails with EEXIST in that case, pretend +successful rename as if the existing destination file was detected +by the preceding lstat call. + +Fixes https://bugs.gnu.org/29961 +--- + aclocal.m4 | 1 + + bootstrap.conf | 2 + + gnulib-tests/gnulib.mk | 18 ++++ + gnulib-tests/test-renameat.c | 206 ++++++++++++++++++++++++++++++++++++++ + gnulib-tests/test-renameat2.c | 209 ++++++++++++++++++++++++++++++++++++++ + lib/gnulib.mk | 21 +++- + lib/renameat.c | 25 +++++ + lib/renameat2.c | 227 ++++++++++++++++++++++++++++++++++++++++++ + lib/renameat2.h | 30 ++++++ + m4/gnulib-comp.m4 | 22 ++++ + m4/renameat.m4 | 25 +++++ + src/copy.c | 27 ++++- + 12 files changed, 808 insertions(+), 5 deletions(-) + create mode 100644 gnulib-tests/test-renameat.c + create mode 100644 gnulib-tests/test-renameat2.c + create mode 100644 lib/renameat.c + create mode 100644 lib/renameat2.c + create mode 100644 lib/renameat2.h + create mode 100644 m4/renameat.m4 + +diff --git a/aclocal.m4 b/aclocal.m4 +index 9c5a2b0..c678967 100644 +--- a/aclocal.m4 ++++ b/aclocal.m4 +@@ -1332,6 +1332,7 @@ m4_include([m4/realloc.m4]) + m4_include([m4/regex.m4]) + m4_include([m4/remove.m4]) + m4_include([m4/rename.m4]) ++m4_include([m4/renameat.m4]) + m4_include([m4/rewinddir.m4]) + m4_include([m4/rmdir.m4]) + m4_include([m4/rpmatch.m4]) +diff --git a/bootstrap.conf b/bootstrap.conf +index 7def1f9..9b7c913 100644 +--- a/bootstrap.conf ++++ b/bootstrap.conf +@@ -199,6 +199,8 @@ gnulib_modules=" + regex + remove + rename ++ renameat ++ renameat2 + rmdir + root-dev-ino + rpmatch +diff --git a/gnulib-tests/gnulib.mk b/gnulib-tests/gnulib.mk +index b2da030..38d439c 100644 +--- a/gnulib-tests/gnulib.mk ++++ b/gnulib-tests/gnulib.mk +@@ -1676,6 +1676,24 @@ EXTRA_DIST += test-rename.h test-rename.c signature.h macros.h + + ## end gnulib module rename-tests + ++## begin gnulib module renameat-tests ++ ++TESTS += test-renameat ++check_PROGRAMS += test-renameat ++test_renameat_LDADD = $(LDADD) @LIBINTL@ ++EXTRA_DIST += test-rename.h test-renameat.c signature.h macros.h ++ ++## end gnulib module renameat-tests ++ ++## begin gnulib module renameat2-tests ++ ++TESTS += test-renameat2 ++check_PROGRAMS += test-renameat2 ++test_renameat2_LDADD = $(LDADD) @LIBINTL@ ++EXTRA_DIST += test-rename.h test-renameat2.c signature.h macros.h ++ ++## end gnulib module renameat2-tests ++ + ## begin gnulib module rmdir-tests + + TESTS += test-rmdir +diff --git a/gnulib-tests/test-renameat.c b/gnulib-tests/test-renameat.c +new file mode 100644 +index 0000000..ac96d88 +--- /dev/null ++++ b/gnulib-tests/test-renameat.c +@@ -0,0 +1,206 @@ ++/* Tests of renameat. ++ Copyright (C) 2009-2017 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 of the License, 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 . */ ++ ++/* Written by Eric Blake , 2009. */ ++ ++#include ++ ++#include ++ ++#include "signature.h" ++SIGNATURE_CHECK (renameat, int, (int, char const *, int, char const *)); ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "filenamecat.h" ++#include "ignore-value.h" ++#include "macros.h" ++ ++#define BASE "test-renameat.t" ++ ++#include "test-rename.h" ++ ++static int dfd1 = AT_FDCWD; ++static int dfd2 = AT_FDCWD; ++ ++/* Wrapper to test renameat like rename. */ ++static int ++do_rename (char const *name1, char const *name2) ++{ ++ return renameat (dfd1, name1, dfd2, name2); ++} ++ ++int ++main (void) ++{ ++ int i; ++ int dfd; ++ char *cwd; ++ int result; ++ ++ /* Clean up any trash from prior testsuite runs. */ ++ ignore_value (system ("rm -rf " BASE "*")); ++ ++ /* Test behaviour for invalid file descriptors. */ ++ { ++ errno = 0; ++ ASSERT (renameat (-1, "foo", AT_FDCWD, "bar") == -1); ++ ASSERT (errno == EBADF); ++ } ++ { ++ close (99); ++ errno = 0; ++ ASSERT (renameat (99, "foo", AT_FDCWD, "bar") == -1); ++ ASSERT (errno == EBADF); ++ } ++ ASSERT (close (creat (BASE "oo", 0600)) == 0); ++ { ++ errno = 0; ++ ASSERT (renameat (AT_FDCWD, BASE "oo", -1, "bar") == -1); ++ ASSERT (errno == EBADF); ++ } ++ { ++ errno = 0; ++ ASSERT (renameat (AT_FDCWD, BASE "oo", 99, "bar") == -1); ++ ASSERT (errno == EBADF); ++ } ++ ASSERT (unlink (BASE "oo") == 0); ++ ++ /* Test basic rename functionality, using current directory. */ ++ result = test_rename (do_rename, false); ++ dfd1 = open (".", O_RDONLY); ++ ASSERT (0 <= dfd1); ++ ASSERT (test_rename (do_rename, false) == result); ++ dfd2 = dfd1; ++ ASSERT (test_rename (do_rename, false) == result); ++ dfd1 = AT_FDCWD; ++ ASSERT (test_rename (do_rename, false) == result); ++ ASSERT (close (dfd2) == 0); ++ ++ /* Create locations to manipulate. */ ++ ASSERT (mkdir (BASE "sub1", 0700) == 0); ++ ASSERT (mkdir (BASE "sub2", 0700) == 0); ++ dfd = creat (BASE "00", 0600); ++ ASSERT (0 <= dfd); ++ ASSERT (close (dfd) == 0); ++ cwd = getcwd (NULL, 0); ++ ASSERT (cwd); ++ ++ dfd = open (BASE "sub1", O_RDONLY); ++ ASSERT (0 <= dfd); ++ ASSERT (chdir (BASE "sub2") == 0); ++ ++ /* There are 16 possible scenarios, based on whether an fd is ++ AT_FDCWD or real, and whether a file is absolute or relative. ++ ++ To ensure that we test all of the code paths (rather than ++ triggering early normalization optimizations), we use a loop to ++ repeatedly rename a file in the parent directory, use an fd open ++ on subdirectory 1, all while executing in subdirectory 2; all ++ relative names are thus given with a leading "../". Finally, the ++ last scenario (two relative paths given, neither one AT_FDCWD) ++ has two paths, based on whether the two fds are equivalent, so we ++ do the other variant after the loop. */ ++ for (i = 0; i < 16; i++) ++ { ++ int fd1 = (i & 8) ? dfd : AT_FDCWD; ++ char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL); ++ int fd2 = (i & 2) ? dfd : AT_FDCWD; ++ char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL); ++ ++ ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2); ++ ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2); ++ ASSERT (renameat (fd1, file1, fd2, file2) == 0); ++ free (file1); ++ free (file2); ++ } ++ dfd2 = open ("..", O_RDONLY); ++ ASSERT (0 <= dfd2); ++ ASSERT (renameat (dfd, "../" BASE "16", dfd2, BASE "17") == 0); ++ ASSERT (close (dfd2) == 0); ++ ++ /* Now we change back to the parent directory, and set dfd to "."; ++ using dfd in remaining tests will expose any bugs if emulation ++ via /proc/self/fd doesn't check for empty names. */ ++ ASSERT (chdir ("..") == 0); ++ ASSERT (close (dfd) == 0); ++ dfd = open (".", O_RDONLY); ++ ASSERT (0 <= dfd); ++ ++ ASSERT (close (creat (BASE "sub2/file", 0600)) == 0); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "sub1", dfd, BASE "sub2") == -1); ++ ASSERT (errno == EEXIST || errno == ENOTEMPTY); ++ ASSERT (unlink (BASE "sub2/file") == 0); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "sub1/.") == -1); ++ ASSERT (errno == EINVAL || errno == EISDIR || errno == EBUSY ++ || errno == ENOTEMPTY || errno == EEXIST); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "sub2/.", dfd, BASE "sub1") == -1); ++ ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "17", dfd, BASE "sub1") == -1); ++ ASSERT (errno == EISDIR); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "nosuch", dfd, BASE "18") == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat (dfd, "", dfd, BASE "17") == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "17", dfd, "") == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "17") == -1); ++ ASSERT (errno == ENOTDIR); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "17/", dfd, BASE "18") == -1); ++ ASSERT (errno == ENOTDIR); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "17", dfd, BASE "18/") == -1); ++ ASSERT (errno == ENOTDIR || errno == ENOENT); ++ ++ /* Finally, make sure we can overwrite existing files. */ ++ ASSERT (close (creat (BASE "sub2/file", 0600)) == 0); ++ errno = 0; ++ ASSERT (renameat (dfd, BASE "sub2", dfd, BASE "sub1") == 0); ++ ASSERT (renameat (dfd, BASE "sub1/file", dfd, BASE "17") == 0); ++ ++ /* Cleanup. */ ++ ASSERT (close (dfd) == 0); ++ errno = 0; ++ ASSERT (unlink (BASE "sub1/file") == -1); ++ ASSERT (errno == ENOENT); ++ ASSERT (unlink (BASE "17") == 0); ++ ASSERT (rmdir (BASE "sub1") == 0); ++ errno = 0; ++ ASSERT (rmdir (BASE "sub2") == -1); ++ ASSERT (errno == ENOENT); ++ free (cwd); ++ ++ if (result) ++ fputs ("skipping test: symlinks not supported on this file system\n", ++ stderr); ++ return result; ++} +diff --git a/gnulib-tests/test-renameat2.c b/gnulib-tests/test-renameat2.c +new file mode 100644 +index 0000000..7c250ea +--- /dev/null ++++ b/gnulib-tests/test-renameat2.c +@@ -0,0 +1,209 @@ ++/* Test renameat2. ++ Copyright (C) 2009-2017 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 of the License, 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 . */ ++ ++/* Written by Eric Blake , 2009. */ ++ ++#include ++ ++#include ++ ++#include ++ ++#include "signature.h" ++SIGNATURE_CHECK (renameat2, int, ++ (int, char const *, int, char const *, unsigned int)); ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "filenamecat.h" ++#include "ignore-value.h" ++#include "macros.h" ++ ++#define BASE "test-renameat2.t" ++ ++#include "test-rename.h" ++ ++static int dfd1 = AT_FDCWD; ++static int dfd2 = AT_FDCWD; ++ ++/* Wrapper to test renameat2 like rename. */ ++static int ++do_rename (char const *name1, char const *name2) ++{ ++ return renameat2 (dfd1, name1, dfd2, name2, 0); ++} ++ ++int ++main (void) ++{ ++ int i; ++ int dfd; ++ char *cwd; ++ int result; ++ ++ /* Clean up any trash from prior testsuite runs. */ ++ ignore_value (system ("rm -rf " BASE "*")); ++ ++ /* Test behaviour for invalid file descriptors. */ ++ { ++ errno = 0; ++ ASSERT (renameat2 (-1, "foo", AT_FDCWD, "bar", 0) == -1); ++ ASSERT (errno == EBADF); ++ } ++ { ++ close (99); ++ errno = 0; ++ ASSERT (renameat2 (99, "foo", AT_FDCWD, "bar", 0) == -1); ++ ASSERT (errno == EBADF); ++ } ++ ASSERT (close (creat (BASE "oo", 0600)) == 0); ++ { ++ errno = 0; ++ ASSERT (renameat2 (AT_FDCWD, BASE "oo", -1, "bar", 0) == -1); ++ ASSERT (errno == EBADF); ++ } ++ { ++ errno = 0; ++ ASSERT (renameat2 (AT_FDCWD, BASE "oo", 99, "bar", 0) == -1); ++ ASSERT (errno == EBADF); ++ } ++ ASSERT (unlink (BASE "oo") == 0); ++ ++ /* Test basic rename functionality, using current directory. */ ++ result = test_rename (do_rename, false); ++ dfd1 = open (".", O_RDONLY); ++ ASSERT (0 <= dfd1); ++ ASSERT (test_rename (do_rename, false) == result); ++ dfd2 = dfd1; ++ ASSERT (test_rename (do_rename, false) == result); ++ dfd1 = AT_FDCWD; ++ ASSERT (test_rename (do_rename, false) == result); ++ ASSERT (close (dfd2) == 0); ++ ++ /* Create locations to manipulate. */ ++ ASSERT (mkdir (BASE "sub1", 0700) == 0); ++ ASSERT (mkdir (BASE "sub2", 0700) == 0); ++ dfd = creat (BASE "00", 0600); ++ ASSERT (0 <= dfd); ++ ASSERT (close (dfd) == 0); ++ cwd = getcwd (NULL, 0); ++ ASSERT (cwd); ++ ++ dfd = open (BASE "sub1", O_RDONLY); ++ ASSERT (0 <= dfd); ++ ASSERT (chdir (BASE "sub2") == 0); ++ ++ /* There are 16 possible scenarios, based on whether an fd is ++ AT_FDCWD or real, and whether a file is absolute or relative. ++ ++ To ensure that we test all of the code paths (rather than ++ triggering early normalization optimizations), we use a loop to ++ repeatedly rename a file in the parent directory, use an fd open ++ on subdirectory 1, all while executing in subdirectory 2; all ++ relative names are thus given with a leading "../". Finally, the ++ last scenario (two relative paths given, neither one AT_FDCWD) ++ has two paths, based on whether the two fds are equivalent, so we ++ do the other variant after the loop. */ ++ for (i = 0; i < 16; i++) ++ { ++ int fd1 = (i & 8) ? dfd : AT_FDCWD; ++ char *file1 = file_name_concat ((i & 4) ? ".." : cwd, BASE "xx", NULL); ++ int fd2 = (i & 2) ? dfd : AT_FDCWD; ++ char *file2 = file_name_concat ((i & 1) ? ".." : cwd, BASE "xx", NULL); ++ ++ ASSERT (sprintf (strchr (file1, '\0') - 2, "%02d", i) == 2); ++ ASSERT (sprintf (strchr (file2, '\0') - 2, "%02d", i + 1) == 2); ++ ASSERT (renameat2 (fd1, file1, fd2, file2, 0) == 0); ++ free (file1); ++ free (file2); ++ } ++ dfd2 = open ("..", O_RDONLY); ++ ASSERT (0 <= dfd2); ++ ASSERT (renameat2 (dfd, "../" BASE "16", dfd2, BASE "17", 0) == 0); ++ ASSERT (close (dfd2) == 0); ++ ++ /* Now we change back to the parent directory, and set dfd to "."; ++ using dfd in remaining tests will expose any bugs if emulation ++ via /proc/self/fd doesn't check for empty names. */ ++ ASSERT (chdir ("..") == 0); ++ ASSERT (close (dfd) == 0); ++ dfd = open (".", O_RDONLY); ++ ASSERT (0 <= dfd); ++ ++ ASSERT (close (creat (BASE "sub2/file", 0600)) == 0); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "sub1", dfd, BASE "sub2", 0) == -1); ++ ASSERT (errno == EEXIST || errno == ENOTEMPTY); ++ ASSERT (unlink (BASE "sub2/file") == 0); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "sub2", dfd, BASE "sub1/.", 0) == -1); ++ ASSERT (errno == EINVAL || errno == EISDIR || errno == EBUSY ++ || errno == ENOTEMPTY || errno == EEXIST); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "sub2/.", dfd, BASE "sub1", 0) == -1); ++ ASSERT (errno == EINVAL || errno == EBUSY || errno == EEXIST); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "17", dfd, BASE "sub1", 0) == -1); ++ ASSERT (errno == EISDIR); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "nosuch", dfd, BASE "18", 0) == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat2 (dfd, "", dfd, BASE "17", 0) == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "17", dfd, "", 0) == -1); ++ ASSERT (errno == ENOENT); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "sub2", dfd, BASE "17", 0) == -1); ++ ASSERT (errno == ENOTDIR); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "17/", dfd, BASE "18", 0) == -1); ++ ASSERT (errno == ENOTDIR); ++ errno = 0; ++ ASSERT (renameat2 (dfd, BASE "17", dfd, BASE "18/", 0) == -1); ++ ASSERT (errno == ENOTDIR || errno == ENOENT); ++ ++ /* Finally, make sure we cannot overwrite existing files. */ ++ ASSERT (close (creat (BASE "sub2/file", 0600)) == 0); ++ errno = 0; ++ ASSERT ((renameat2 (dfd, BASE "sub2", dfd, BASE "sub1", RENAME_NOREPLACE) ++ == -1) ++ && errno == EEXIST); ++ ASSERT ((renameat2 (dfd, BASE "sub2/file", dfd, BASE "17", RENAME_NOREPLACE) ++ == -1) ++ && errno == EEXIST); ++ ++ /* Cleanup. */ ++ ASSERT (close (dfd) == 0); ++ ASSERT (unlink (BASE "sub2/file") == 0); ++ ASSERT (unlink (BASE "17") == 0); ++ ASSERT (rmdir (BASE "sub1") == 0); ++ ASSERT (rmdir (BASE "sub2") == 0); ++ free (cwd); ++ ++ if (result) ++ fputs ("skipping test: symlinks not supported on this file system\n", ++ stderr); ++ return result; ++} +diff --git a/lib/gnulib.mk b/lib/gnulib.mk +index 844791b..76729b0 100644 +--- a/lib/gnulib.mk ++++ b/lib/gnulib.mk +@@ -21,7 +21,7 @@ + # the same distribution terms as the rest of that program. + # + # Generated by gnulib-tool. +-# Reproduce by: gnulib-tool --import --dir=. --local-dir=gl --lib=libcoreutils --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=gnulib-tests --aux-dir=build-aux --with-tests --avoid=canonicalize-lgpl --avoid=dummy --makefile-name=gnulib.mk --no-conditional-dependencies --no-libtool --macro-prefix=gl acl alignof alloca announce-gen areadlink-with-size argmatch argv-iter assert autobuild backupfile base64 buffer-lcm c-strcase c-strtod c-strtold calloc-gnu canon-host canonicalize chown cloexec closein closeout config-h configmake crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 cycle-check d-ino d-type di-set diacrit dirfd dirname do-release-commit-and-tag dtoastr dup2 environ error euidaccess exclude exitfail faccessat fadvise fchdir fchmodat fchownat fclose fcntl fcntl-safer fd-reopen fdatasync fdl fdopen fdutimensat file-type fileblocks filemode filenamecat filevercmp fnmatch-gnu fopen-safer fprintftime freopen freopen-safer fseeko fstatat fsusage fsync ftello ftoastr ftruncate fts full-read full-write getgroups gethrxtime getline getloadavg getlogin getndelim2 getopt-gnu getpagesize getpass-gnu gettext-h gettime gettimeofday getugroups getusershell git-version-gen gitlog-to-changelog gnu-make gnu-web-doc-update gnumakefile gnupload group-member hard-locale hash hash-pjw heap host-os human idcache ignore-value inttostr inttypes isapipe isatty isblank largefile lchmod lchown ldtoastr lib-ignore linebuffer link link-follow linkat long-options lstat maintainer-makefile malloc-gnu manywarnings mbrlen mbrtowc mbsalign mbswidth memcasecmp memchr memcmp2 mempcpy memrchr mgetgroups mkancesdirs mkdir mkdir-p mkfifo mknod mkstemp mktime modechange mountlist mpsort netinet_in non-recursive-gnulib-prefix-hack nproc obstack parse-datetime pathmax perl physmem pipe posix-shell posixtm posixver priv-set progname propername pthread putenv quote quotearg randint randperm read-file readlink readtokens readtokens0 readutmp realloc-gnu regex remove rename rmdir root-dev-ino rpmatch safe-read same save-cwd savedir savewd selinux-at settime sig2str sigaction smack ssize_t stat-macros stat-size stat-time statat stdbool stdlib-safer stpcpy stpncpy strdup-posix strftime strncat strnumcmp strpbrk strsignal strtod strtoimax strtoumax symlink sys_ioctl sys_resource sys_stat sys_wait termios timer-time timespec tzset uname unicodeio unistd-safer unlink-busy unlinkat unlocked-io unsetenv update-copyright uptime useless-if-before-free userspec utimecmp utimens vasprintf-posix vc-list-files verify verror version-etc-fsf wcswidth wcwidth winsz-ioctl winsz-termios write-any-file xalloc xfreopen xfts xgetcwd xgetgroups xgethostname xmemcoll xnanosleep xprintf xprintf-posix xreadlink xstrtod xstrtoimax xstrtol xstrtold xstrtoumax yesno ++# Reproduce by: gnulib-tool --import --dir=. --local-dir=gl --lib=libcoreutils --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=gnulib-tests --aux-dir=build-aux --with-tests --avoid=canonicalize-lgpl --avoid=dummy --makefile-name=gnulib.mk --no-conditional-dependencies --no-libtool --macro-prefix=gl acl alignof alloca announce-gen areadlink-with-size argmatch argv-iter assert autobuild backupfile base64 buffer-lcm c-strcase c-strtod c-strtold calloc-gnu canon-host canonicalize chown cloexec closein closeout config-h configmake crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 cycle-check d-ino d-type di-set diacrit dirfd dirname do-release-commit-and-tag dtoastr dup2 environ error euidaccess exclude exitfail faccessat fadvise fchdir fchmodat fchownat fclose fcntl fcntl-safer fd-reopen fdatasync fdl fdopen fdutimensat file-type fileblocks filemode filenamecat filevercmp fnmatch-gnu fopen-safer fprintftime freopen freopen-safer fseeko fstatat fsusage fsync ftello ftoastr ftruncate fts full-read full-write getgroups gethrxtime getline getloadavg getlogin getndelim2 getopt-gnu getpagesize getpass-gnu gettext-h gettime gettimeofday getugroups getusershell git-version-gen gitlog-to-changelog gnu-make gnu-web-doc-update gnumakefile gnupload group-member hard-locale hash hash-pjw heap host-os human idcache ignore-value inttostr inttypes isapipe isatty isblank largefile lchmod lchown ldtoastr lib-ignore linebuffer link link-follow linkat long-options lstat maintainer-makefile malloc-gnu manywarnings mbrlen mbrtowc mbsalign mbswidth memcasecmp memchr memcmp2 mempcpy memrchr mgetgroups mkancesdirs mkdir mkdir-p mkfifo mknod mkstemp mktime modechange mountlist mpsort netinet_in non-recursive-gnulib-prefix-hack nproc obstack parse-datetime pathmax perl physmem pipe posix-shell posixtm posixver priv-set progname propername pthread putenv quote quotearg randint randperm read-file readlink readtokens readtokens0 readutmp realloc-gnu regex remove rename renameat renameat2 rmdir root-dev-ino rpmatch safe-read same save-cwd savedir savewd selinux-at settime sig2str sigaction smack ssize_t stat-macros stat-size stat-time statat stdbool stdlib-safer stpcpy stpncpy strdup-posix strftime strncat strnumcmp strpbrk strsignal strtod strtoimax strtoumax symlink sys_ioctl sys_resource sys_stat sys_wait termios timer-time timespec tzset uname unicodeio unistd-safer unlink-busy unlinkat unlocked-io unsetenv update-copyright uptime useless-if-before-free userspec utimecmp utimens vasprintf-posix vc-list-files verify verror version-etc-fsf wcswidth wcwidth winsz-ioctl winsz-termios write-any-file xalloc xfreopen xfts xgetcwd xgetgroups xgethostname xmemcoll xnanosleep xprintf xprintf-posix xreadlink xstrtod xstrtoimax xstrtol xstrtold xstrtoumax yesno + + + MOSTLYCLEANFILES += lib/core lib/*.stackdump +@@ -3202,6 +3202,25 @@ EXTRA_lib_libcoreutils_a_SOURCES += lib/rename.c + + ## end gnulib module rename + ++## begin gnulib module renameat ++ ++ ++EXTRA_DIST += lib/renameat.c ++ ++EXTRA_lib_libcoreutils_a_SOURCES += lib/renameat.c ++ ++## end gnulib module renameat ++ ++## begin gnulib module renameat2 ++ ++lib_libcoreutils_a_SOURCES += lib/renameat2.c ++ ++EXTRA_DIST += lib/at-func2.c lib/renameat2.h ++ ++EXTRA_lib_libcoreutils_a_SOURCES += lib/at-func2.c ++ ++## end gnulib module renameat2 ++ + ## begin gnulib module rewinddir + + +diff --git a/lib/renameat.c b/lib/renameat.c +new file mode 100644 +index 0000000..48cee4b +--- /dev/null ++++ b/lib/renameat.c +@@ -0,0 +1,25 @@ ++/* Rename a file relative to open directories. ++ Copyright 2017 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 of the License, 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 . */ ++ ++#include ++#include ++#include "renameat2.h" ++ ++int ++renameat (int fd1, char const *src, int fd2, char const *dst) ++{ ++ return renameat2 (fd1, src, fd2, dst, 0); ++} +diff --git a/lib/renameat2.c b/lib/renameat2.c +new file mode 100644 +index 0000000..26cde86 +--- /dev/null ++++ b/lib/renameat2.c +@@ -0,0 +1,227 @@ ++/* Rename a file relative to open directories. ++ Copyright (C) 2009-2017 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 of the License, 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 . */ ++ ++/* written by Eric Blake and Paul Eggert */ ++ ++#include ++ ++#include "renameat2.h" ++ ++#include ++#include ++#include ++#include ++ ++#ifdef __linux__ ++# include ++#endif ++ ++static int ++errno_fail (int e) ++{ ++ errno = e; ++ return -1; ++} ++ ++#if HAVE_RENAMEAT ++ ++# include ++# include ++# include ++ ++# include "dirname.h" ++# include "openat.h" ++ ++#else ++# include "openat-priv.h" ++ ++static int ++rename_noreplace (char const *src, char const *dst) ++{ ++ /* This has a race between the call to lstat and the call to rename. */ ++ struct stat st; ++ return (lstat (dst, &st) == 0 || errno == EOVERFLOW ? errno_fail (EEXIST) ++ : errno == ENOENT ? rename (src, dst) ++ : -1); ++} ++#endif ++ ++#undef renameat ++ ++/* Rename FILE1, in the directory open on descriptor FD1, to FILE2, in ++ the directory open on descriptor FD2. If possible, do it without ++ changing the working directory. Otherwise, resort to using ++ save_cwd/fchdir, then rename/restore_cwd. If either the save_cwd or ++ the restore_cwd fails, then give a diagnostic and exit nonzero. ++ ++ Obey FLAGS when doing the renaming. If FLAGS is zero, this ++ function is equivalent to renameat (FD1, SRC, FD2, DST). */ ++ ++int ++renameat2 (int fd1, char const *src, int fd2, char const *dst, ++ unsigned int flags) ++{ ++ int ret_val = -1; ++ int err = EINVAL; ++ ++#ifdef SYS_renameat2 ++ ret_val = syscall (SYS_renameat2, fd1, src, fd2, dst, flags); ++ err = errno; ++#elif defined RENAME_EXCL ++ if (! (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))) ++ { ++ ret_val = renameatx_np (fd1, src, fd2, dst, ++ ((flags & RENAME_EXCHANGE ? RENAME_SWAP : 0) ++ | (flags & RENAME_NOREPLACE ? RENAME_EXCL : 0))); ++ err = errno; ++ } ++#endif ++ ++ if (! (ret_val < 0 && (err == EINVAL || err == ENOSYS || err == ENOTSUP))) ++ return ret_val; ++ ++#if HAVE_RENAMEAT ++ { ++ size_t src_len; ++ size_t dst_len; ++ char *src_temp = (char *) src; ++ char *dst_temp = (char *) dst; ++ bool src_slash; ++ bool dst_slash; ++ int rename_errno = ENOTDIR; ++ struct stat src_st; ++ struct stat dst_st; ++ bool dst_found_nonexistent = false; ++ ++ if (flags != 0) ++ { ++ /* RENAME_NOREPLACE is the only flag currently supported. */ ++ if (flags & ~RENAME_NOREPLACE) ++ return errno_fail (ENOTSUP); ++ else ++ { ++ /* This has a race between the call to lstatat and the calls to ++ renameat below. */ ++ if (lstatat (fd2, dst, &dst_st) == 0 || errno == EOVERFLOW) ++ return errno_fail (EEXIST); ++ if (errno != ENOENT) ++ return -1; ++ dst_found_nonexistent = true; ++ } ++ } ++ ++ /* Let strace see any ENOENT failure. */ ++ src_len = strlen (src); ++ dst_len = strlen (dst); ++ if (!src_len || !dst_len) ++ return renameat (fd1, src, fd2, dst); ++ ++ src_slash = src[src_len - 1] == '/'; ++ dst_slash = dst[dst_len - 1] == '/'; ++ if (!src_slash && !dst_slash) ++ return renameat (fd1, src, fd2, dst); ++ ++ /* Presence of a trailing slash requires directory semantics. If ++ the source does not exist, or if the destination cannot be turned ++ into a directory, give up now. Otherwise, strip trailing slashes ++ before calling rename. */ ++ if (lstatat (fd1, src, &src_st)) ++ return -1; ++ if (dst_found_nonexistent) ++ { ++ if (!S_ISDIR (src_st.st_mode)) ++ return errno_fail (ENOENT); ++ } ++ else if (lstatat (fd2, dst, &dst_st)) ++ { ++ if (errno != ENOENT || !S_ISDIR (src_st.st_mode)) ++ return -1; ++ } ++ else if (!S_ISDIR (dst_st.st_mode)) ++ return errno_fail (ENOTDIR); ++ else if (!S_ISDIR (src_st.st_mode)) ++ return errno_fail (EISDIR); ++ ++# if RENAME_TRAILING_SLASH_SOURCE_BUG ++ /* See the lengthy comment in rename.c why Solaris 9 is forced to ++ GNU behavior, while Solaris 10 is left with POSIX behavior, ++ regarding symlinks with trailing slash. */ ++ ret_val = -1; ++ if (src_slash) ++ { ++ src_temp = strdup (src); ++ if (!src_temp) ++ { ++ /* Rather than rely on strdup-posix, we set errno ourselves. */ ++ rename_errno = ENOMEM; ++ goto out; ++ } ++ strip_trailing_slashes (src_temp); ++ if (lstatat (fd1, src_temp, &src_st)) ++ { ++ rename_errno = errno; ++ goto out; ++ } ++ if (S_ISLNK (src_st.st_mode)) ++ goto out; ++ } ++ if (dst_slash) ++ { ++ dst_temp = strdup (dst); ++ if (!dst_temp) ++ { ++ rename_errno = ENOMEM; ++ goto out; ++ } ++ strip_trailing_slashes (dst_temp); ++ if (lstatat (fd2, dst_temp, &dst_st)) ++ { ++ if (errno != ENOENT) ++ { ++ rename_errno = errno; ++ goto out; ++ } ++ } ++ else if (S_ISLNK (dst_st.st_mode)) ++ goto out; ++ } ++# endif /* RENAME_TRAILING_SLASH_SOURCE_BUG */ ++ ++ /* renameat does not honor trailing / on Solaris 10. Solve it in a ++ similar manner to rename. No need to worry about bugs not present ++ on Solaris, since all other systems either lack renameat or honor ++ trailing slash correctly. */ ++ ++ ret_val = renameat (fd1, src_temp, fd2, dst_temp); ++ rename_errno = errno; ++ goto out; ++ out: ++ if (src_temp != src) ++ free (src_temp); ++ if (dst_temp != dst) ++ free (dst_temp); ++ errno = rename_errno; ++ return ret_val; ++ } ++#else /* !HAVE_RENAMEAT */ ++ ++ /* RENAME_NOREPLACE is the only flag currently supported. */ ++ if (flags & ~RENAME_NOREPLACE) ++ return errno_fail (ENOTSUP); ++ return at_func2 (fd1, src, fd2, dst, flags ? rename_noreplace : rename); ++ ++#endif /* !HAVE_RENAMEAT */ ++} +diff --git a/lib/renameat2.h b/lib/renameat2.h +new file mode 100644 +index 0000000..179210f +--- /dev/null ++++ b/lib/renameat2.h +@@ -0,0 +1,30 @@ ++/* Rename a file relative to open directories. ++ Copyright 2017 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 of the License, 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 . */ ++ ++/* written by Paul Eggert */ ++ ++/* Get RENAME_* macros from linux/fs.h if present, otherwise supply ++ the traditional Linux values. */ ++#if HAVE_LINUX_FS_H ++# include ++#endif ++#ifndef RENAME_NOREPLACE ++# define RENAME_NOREPLACE (1 << 0) ++# define RENAME_EXCHANGE (1 << 1) ++# define RENAME_WHITEOUT (1 << 2) ++#endif ++ ++extern int renameat2 (int, char const *, int, char const *, unsigned int); +diff --git a/m4/gnulib-comp.m4 b/m4/gnulib-comp.m4 +index 4ef3c43..309e308 100644 +--- a/m4/gnulib-comp.m4 ++++ b/m4/gnulib-comp.m4 +@@ -547,6 +547,10 @@ AC_DEFUN([gl_EARLY], + # Code from module remove-tests: + # Code from module rename: + # Code from module rename-tests: ++ # Code from module renameat: ++ # Code from module renameat-tests: ++ # Code from module renameat2: ++ # Code from module renameat2-tests: + # Code from module rewinddir: + # Code from module rmdir: + # Code from module rmdir-tests: +@@ -1696,6 +1700,18 @@ AC_DEFUN([gl_INIT], + AC_LIBOBJ([rename]) + fi + gl_STDIO_MODULE_INDICATOR([rename]) ++ gl_FUNC_RENAMEAT ++ if test $HAVE_RENAMEAT = 0 || test $REPLACE_RENAMEAT = 1; then ++ AC_LIBOBJ([renameat]) ++ fi ++ if test $HAVE_RENAMEAT = 0; then ++ AC_LIBOBJ([at-func2]) ++ fi ++ gl_STDIO_MODULE_INDICATOR([renameat]) ++ gl_FUNC_RENAMEAT ++ if test $HAVE_RENAMEAT = 0; then ++ AC_LIBOBJ([at-func2]) ++ fi + gl_FUNC_REWINDDIR + if test $HAVE_REWINDDIR = 0; then + AC_LIBOBJ([rewinddir]) +@@ -2868,6 +2884,9 @@ AC_DEFUN([gl_FILE_LIST], [ + lib/regexec.c + lib/remove.c + lib/rename.c ++ lib/renameat.c ++ lib/renameat2.c ++ lib/renameat2.h + lib/rewinddir.c + lib/rmdir.c + lib/root-dev-ino.c +@@ -3372,6 +3391,7 @@ AC_DEFUN([gl_FILE_LIST], [ + m4/regex.m4 + m4/remove.m4 + m4/rename.m4 ++ m4/renameat.m4 + m4/rewinddir.m4 + m4/rmdir.m4 + m4/rpmatch.m4 +@@ -3794,6 +3814,8 @@ AC_DEFUN([gl_FILE_LIST], [ + tests/test-remove.c + tests/test-rename.c + tests/test-rename.h ++ tests/test-renameat.c ++ tests/test-renameat2.c + tests/test-rmdir.c + tests/test-rmdir.h + tests/test-sameacls.c +diff --git a/m4/renameat.m4 b/m4/renameat.m4 +new file mode 100644 +index 0000000..1b97774 +--- /dev/null ++++ b/m4/renameat.m4 +@@ -0,0 +1,25 @@ ++# serial 3 ++# See if we need to provide renameat replacement. ++ ++dnl Copyright (C) 2009-2017 Free Software Foundation, Inc. ++dnl This file is free software; the Free Software Foundation ++dnl gives unlimited permission to copy and/or distribute it, ++dnl with or without modifications, as long as this notice is preserved. ++ ++# Written by Eric Blake. ++ ++AC_DEFUN([gl_FUNC_RENAMEAT], ++[ ++ AC_REQUIRE([gl_FUNC_OPENAT]) ++ AC_REQUIRE([gl_FUNC_RENAME]) ++ AC_REQUIRE([gl_STDIO_H_DEFAULTS]) ++ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) ++ AC_CHECK_HEADERS([linux/fs.h]) ++ AC_CHECK_FUNCS_ONCE([renameat]) ++ if test $ac_cv_func_renameat = no; then ++ HAVE_RENAMEAT=0 ++ elif test $REPLACE_RENAME = 1; then ++ dnl Solaris 9 and 10 have the same bugs in renameat as in rename. ++ REPLACE_RENAMEAT=1 ++ fi ++]) +diff --git a/src/copy.c b/src/copy.c +index 2a804945e..be4e357a8 100644 +--- a/src/copy.c ++++ b/src/copy.c +@@ -51,6 +51,7 @@ + #include "ignore-value.h" + #include "ioblksize.h" + #include "quote.h" ++#include "renameat2.h" + #include "root-uid.h" + #include "same.h" + #include "savedir.h" +@@ -2093,8 +2094,9 @@ copy_internal (char const *src_name, char const *dst_name, + + /* If the source is a directory, we don't always create the destination + directory. So --verbose should not announce anything until we're +- sure we'll create a directory. */ +- if (x->verbose && !S_ISDIR (src_mode)) ++ sure we'll create a directory. In move mode we delay the diagnostic ++ message until we know whether renameat2() has actually succeeded. */ ++ if (x->verbose && !S_ISDIR (src_mode) && !x->move_mode) + emit_verbose (src_name, dst_name, backup_succeeded ? dst_backup : NULL); + + /* Associate the destination file name with the source device and inode +@@ -2196,9 +2198,14 @@ copy_internal (char const *src_name, char const *dst_name, + + if (x->move_mode) + { +- if (rename (src_name, dst_name) == 0) ++ int flags = 0; ++ if (x->interactive == I_ALWAYS_NO) ++ /* do not replace DST_NAME if it was created since our last check */ ++ flags = RENAME_NOREPLACE; ++ ++ if (renameat2 (AT_FDCWD, src_name, AT_FDCWD, dst_name, flags) == 0) + { +- if (x->verbose && S_ISDIR (src_mode)) ++ if (x->verbose) + emit_verbose (src_name, dst_name, + backup_succeeded ? dst_backup : NULL); + +@@ -2226,6 +2233,15 @@ copy_internal (char const *src_name, char const *dst_name, + return true; + } + ++ if ((flags & RENAME_NOREPLACE) && (errno == EEXIST)) ++ { ++ /* Pretend the rename succeeded, so the caller (mv) ++ doesn't end up removing the source file. */ ++ if (rename_succeeded) ++ *rename_succeeded = true; ++ return true; ++ } ++ + /* FIXME: someday, consider what to do when moving a directory into + itself but when source and destination are on different devices. */ + +@@ -2301,6 +2317,9 @@ copy_internal (char const *src_name, char const *dst_name, + return false; + } + ++ if (x->verbose && !S_ISDIR (src_mode)) ++ emit_verbose (src_name, dst_name, backup_succeeded ? dst_backup : NULL); ++ + new_dst = true; + } + +-- +2.13.6 + diff --git a/SOURCES/coreutils-i18n-sort-memleak.patch b/SOURCES/coreutils-i18n-sort-memleak.patch new file mode 100644 index 0000000..2819b77 --- /dev/null +++ b/SOURCES/coreutils-i18n-sort-memleak.patch @@ -0,0 +1,103 @@ +From e16ae8b0f8a16f05d5881ad282bd58b31645a34f Mon Sep 17 00:00:00 2001 +From: Kamil Dudka +Date: Fri, 15 Jun 2018 12:47:38 +0200 +Subject: [PATCH] Resolves: #1259942 - fix memory leak in sort/I18N +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Patches written by Pádraig. + +Note that the corresponding i18n/sort-month test was not included +because it breaks unless sort is compiled -Dlint and we do not want +to decrease performance of the resulting RPMs (and valgrind is not +installed in production buildroots anyway). +--- + src/sort.c | 37 ++++++++++++++++++++++--------------- + 1 file changed, 22 insertions(+), 15 deletions(-) + +diff --git a/src/sort.c b/src/sort.c +index e47b039..c04b513 100644 +--- a/src/sort.c ++++ b/src/sort.c +@@ -2861,8 +2861,8 @@ getmonth_mb (const char *s, size_t len, char **ea) + register int lo = 0, hi = MONTHS_PER_YEAR, result; + char *tmp; + size_t wclength, mblength; +- const char **pp; +- const wchar_t **wpp; ++ const char *pp; ++ const wchar_t *wpp; + wchar_t *month_wcs; + mbstate_t state; + +@@ -2875,17 +2875,19 @@ getmonth_mb (const char *s, size_t len, char **ea) + if (len == 0) + return 0; + +- month = (char *) xmalloc (len + 1); ++ if (SIZE_MAX - len < 1) ++ xalloc_die (); ++ ++ month = (char *) xnmalloc (len + 1, MB_CUR_MAX); + +- tmp = (char *) xmalloc (len + 1); ++ pp = tmp = (char *) xnmalloc (len + 1, MB_CUR_MAX); + memcpy (tmp, s, len); + tmp[len] = '\0'; +- pp = (const char **)&tmp; +- month_wcs = (wchar_t *) xmalloc ((len + 1) * sizeof (wchar_t)); +- memset (&state, '\0', sizeof(mbstate_t)); ++ wpp = month_wcs = (wchar_t *) xnmalloc (len + 1, sizeof (wchar_t)); ++ memset (&state, '\0', sizeof (mbstate_t)); + +- wclength = mbsrtowcs (month_wcs, pp, len + 1, &state); +- if (wclength == (size_t)-1 || *pp != NULL) ++ wclength = mbsrtowcs (month_wcs, &pp, len + 1, &state); ++ if (wclength == (size_t)-1 || pp != NULL) + error (SORT_FAILURE, 0, _("Invalid multibyte input %s."), quote(s)); + + for (i = 0; i < wclength; i++) +@@ -2898,10 +2900,8 @@ getmonth_mb (const char *s, size_t len, char **ea) + } + } + +- wpp = (const wchar_t **)&month_wcs; +- +- mblength = wcsrtombs (month, wpp, len + 1, &state); +- assert (mblength != (-1) && *wpp == NULL); ++ mblength = wcsrtombs (month, &wpp, (len + 1) * MB_CUR_MAX, &state); ++ assert (mblength != (-1) && wpp == NULL); + + do + { +@@ -5363,10 +5363,10 @@ main (int argc, char **argv) + + if (nfiles == 0) + { +- static char *minus = (char *) "-"; + nfiles = 1; + free (files); +- files = − ++ files = xmalloc (sizeof *files); ++ *files = (char *) "-"; + } + + /* Need to re-check that we meet the minimum requirement for memory +@@ -5424,6 +5424,13 @@ main (int argc, char **argv) + sort (files, nfiles, outfile, nthreads); + } + ++#ifdef lint ++ if (files_from) ++ readtokens0_free (&tok); ++ else ++ free (files); ++#endif ++ + if (have_read_stdin && fclose (stdin) == EOF) + die (_("close failed"), "-"); + +-- +2.14.4 + diff --git a/SPECS/coreutils.spec b/SPECS/coreutils.spec index ffcebd5..5e9534d 100644 --- a/SPECS/coreutils.spec +++ b/SPECS/coreutils.spec @@ -1,7 +1,7 @@ Summary: A set of basic GNU tools commonly used in shell scripts Name: coreutils Version: 8.22 -Release: 21%{?dist} +Release: 23%{?dist} License: GPLv3+ Group: System Environment/Base Url: http://www.gnu.org/software/coreutils/ @@ -48,6 +48,10 @@ Patch15: coreutils-8.22-ls-interruption.patch # df: do not stat file systems that do not satisfy the -t/-x args (#1511947) Patch17: coreutils-8.22-df-stat.patch +# mv -n: do not overwrite the destination (#1526265) +# http://git.savannah.gnu.org/cgit/coreutils.git/commit/?id=v8.29-9-g29baf25aa +Patch18: coreutils-8.22-mv-n-noreplace.patch + # Our patches #general patch to workaround koji build system issues Patch100: coreutils-6.10-configuration.patch @@ -81,6 +85,9 @@ Patch800: coreutils-i18n.patch # fold: preserve new-lines in mutlibyte text (#1418505) Patch801: coreutils-i18n-fold-newline.patch +# sort -M: fix memory leak when using multibyte locale (#1540059) +Patch802: coreutils-i18n-sort-memleak.patch + #getgrouplist() patch from Ulrich Drepper. Patch908: coreutils-getgrouplist.patch #Prevent buffer overflow in who(1) (bug #158405). @@ -129,9 +136,10 @@ Provides: /bin/touch Provides: /bin/true Provides: /bin/uname +BuildRequires: bison +BuildRequires: gettext-devel BuildRequires: libselinux-devel BuildRequires: libacl-devel -BuildRequires: gettext bison BuildRequires: texinfo BuildRequires: autoconf BuildRequires: automake @@ -221,6 +229,10 @@ the old GNU fileutils, sh-utils, and textutils packages. %patch15 -p1 %patch17 -p1 +# patches added in RHEL-7.6 +%patch18 -p1 +%patch802 -p1 + chmod a+x tests/misc/sort-mb-tests.sh tests/df/direct.sh tests/cp/no-ctx.sh tests/dd/stats.sh || : #fix typos/mistakes in localized documentation(#439410, #440056) @@ -231,11 +243,10 @@ find ./po/ -name "*.p*" | xargs \ %build export CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing -fpic" %{expand:%%global optflags %{optflags} -D_GNU_SOURCE=1} -#autoreconf -i -v -touch aclocal.m4 configure config.hin Makefile.in */Makefile.in -aclocal -I m4 -autoconf --force -automake --copy --add-missing + +# needed to properly include the renameat2 gnulib module +autoreconf -fiv + %configure --enable-largefile \ --with-openssl=optional ac_cv_lib_crypto_MD5=no \ --enable-install-program=hostname,arch \ @@ -444,6 +455,13 @@ fi %{_sbindir}/chroot %changelog +* Fri Jun 15 2018 Kamil Dudka - 8.22-23 +- update description of the -a/--all option in df.1 man page (#1553212) +- sort -M: fix memory leak when using multibyte locale (#1540059) + +* Wed Jan 24 2018 Kamil Dudka - 8.22-22 +- mv -n: do not overwrite the destination (#1526265) + * Mon Dec 04 2017 Kamil Dudka - 8.22-21 - timeout: revert the last fix for a possible race (#1439465)