diff --git a/coreutils-9.1-copy-relative-dir.patch b/coreutils-9.1-copy-relative-dir.patch new file mode 100644 index 0000000..a75d162 --- /dev/null +++ b/coreutils-9.1-copy-relative-dir.patch @@ -0,0 +1,254 @@ +diff -Naur coreutils-9.1.orig/src/copy.c coreutils-9.1/src/copy.c +--- coreutils-9.1.orig/src/copy.c 2022-04-15 13:53:28.000000000 +0000 ++++ coreutils-9.1/src/copy.c 2023-05-04 21:09:46.290253081 +0000 +@@ -1954,6 +1954,7 @@ + bool restore_dst_mode = false; + char *earlier_file = NULL; + char *dst_backup = NULL; ++ char const *drelname = *dst_relname ? dst_relname : "."; + bool delayed_ok; + bool copied_as_regular = false; + bool dest_is_symlink = false; +@@ -1971,7 +1972,7 @@ + if (x->move_mode) + { + if (rename_errno < 0) +- rename_errno = (renameatu (AT_FDCWD, src_name, dst_dirfd, dst_relname, ++ rename_errno = (renameatu (AT_FDCWD, src_name, dst_dirfd, drelname, + RENAME_NOREPLACE) + ? errno : 0); + nonexistent_dst = *rename_succeeded = new_dst = rename_errno == 0; +@@ -1983,7 +1984,7 @@ + { + char const *name = rename_errno == 0 ? dst_name : src_name; + int dirfd = rename_errno == 0 ? dst_dirfd : AT_FDCWD; +- char const *relname = rename_errno == 0 ? dst_relname : src_name; ++ char const *relname = rename_errno == 0 ? drelname : src_name; + int fstatat_flags + = x->dereference == DEREF_NEVER ? AT_SYMLINK_NOFOLLOW : 0; + if (follow_fstatat (dirfd, relname, &src_sb, fstatat_flags) != 0) +@@ -2051,8 +2052,7 @@ + int fstatat_flags = use_lstat ? AT_SYMLINK_NOFOLLOW : 0; + if (!use_lstat && nonexistent_dst < 0) + new_dst = true; +- else if (follow_fstatat (dst_dirfd, dst_relname, &dst_sb, +- fstatat_flags) ++ else if (follow_fstatat (dst_dirfd, drelname, &dst_sb, fstatat_flags) + == 0) + { + have_dst_lstat = use_lstat; +@@ -2077,7 +2077,7 @@ + bool return_now = false; + + if (x->interactive != I_ALWAYS_NO +- && ! same_file_ok (src_name, &src_sb, dst_dirfd, dst_relname, ++ && ! same_file_ok (src_name, &src_sb, dst_dirfd, drelname, + &dst_sb, x, &return_now)) + { + error (0, 0, _("%s and %s are the same file"), +@@ -2140,7 +2140,7 @@ + cp and mv treat -i and -f differently. */ + if (x->move_mode) + { +- if (abandon_move (x, dst_name, dst_dirfd, dst_relname, &dst_sb)) ++ if (abandon_move (x, dst_name, dst_dirfd, drelname, &dst_sb)) + { + /* Pretend the rename succeeded, so the caller (mv) + doesn't end up removing the source file. */ +@@ -2321,14 +2321,11 @@ + Otherwise, use AT_SYMLINK_NOFOLLOW, in case dst_name is a symlink. */ + if (have_dst_lstat) + dst_lstat_sb = &dst_sb; ++ else if (fstatat (dst_dirfd, drelname, &tmp_buf, AT_SYMLINK_NOFOLLOW) ++ == 0) ++ dst_lstat_sb = &tmp_buf; + else +- { +- if (fstatat (dst_dirfd, dst_relname, &tmp_buf, +- AT_SYMLINK_NOFOLLOW) == 0) +- dst_lstat_sb = &tmp_buf; +- else +- lstat_ok = false; +- } ++ lstat_ok = false; + + /* Never copy through a symlink we've just created. */ + if (lstat_ok +@@ -2475,8 +2472,7 @@ + if (x->move_mode) + { + if (rename_errno == EEXIST) +- rename_errno = ((renameat (AT_FDCWD, src_name, dst_dirfd, dst_relname) +- == 0) ++ rename_errno = (renameat (AT_FDCWD, src_name, dst_dirfd, drelname) == 0 + ? 0 : errno); + + if (rename_errno == 0) +@@ -2576,7 +2572,7 @@ + or not, and this is enforced above. Therefore we check the src_mode + and operate on dst_name here as a tighter constraint and also because + src_mode is readily available here. */ +- if ((unlinkat (dst_dirfd, dst_relname, ++ if ((unlinkat (dst_dirfd, drelname, + S_ISDIR (src_mode) ? AT_REMOVEDIR : 0) + != 0) + && errno != ENOENT) +@@ -2646,7 +2642,7 @@ + to ask mkdir to copy all the CHMOD_MODE_BITS, letting mkdir + decide what to do with S_ISUID | S_ISGID | S_ISVTX. */ + mode_t mode = dst_mode_bits & ~omitted_permissions; +- if (mkdirat (dst_dirfd, dst_relname, mode) != 0) ++ if (mkdirat (dst_dirfd, drelname, mode) != 0) + { + error (0, errno, _("cannot create directory %s"), + quoteaf (dst_name)); +@@ -2657,8 +2653,7 @@ + for writing the directory's contents. Check if these + permissions are there. */ + +- if (fstatat (dst_dirfd, dst_relname, &dst_sb, +- AT_SYMLINK_NOFOLLOW) != 0) ++ if (fstatat (dst_dirfd, drelname, &dst_sb, AT_SYMLINK_NOFOLLOW) != 0) + { + error (0, errno, _("cannot stat %s"), quoteaf (dst_name)); + goto un_backup; +@@ -2670,7 +2665,7 @@ + dst_mode = dst_sb.st_mode; + restore_dst_mode = true; + +- if (lchmodat (dst_dirfd, dst_relname, dst_mode | S_IRWXU) != 0) ++ if (lchmodat (dst_dirfd, drelname, dst_mode | S_IRWXU) != 0) + { + error (0, errno, _("setting permissions for %s"), + quoteaf (dst_name)); +@@ -2924,7 +2919,7 @@ + /* Now that the destination file is very likely to exist, + add its info to the set. */ + struct stat sb; +- if (fstatat (dst_dirfd, dst_relname, &sb, AT_SYMLINK_NOFOLLOW) == 0) ++ if (fstatat (dst_dirfd, drelname, &sb, AT_SYMLINK_NOFOLLOW) == 0) + record_file (x->dest_info, dst_relname, &sb); + } + +@@ -2957,7 +2952,7 @@ + timespec[1] = get_stat_mtime (&src_sb); + + int utimensat_flags = dest_is_symlink ? AT_SYMLINK_NOFOLLOW : 0; +- if (utimensat (dst_dirfd, dst_relname, timespec, utimensat_flags) != 0) ++ if (utimensat (dst_dirfd, drelname, timespec, utimensat_flags) != 0) + { + error (0, errno, _("preserving times for %s"), quoteaf (dst_name)); + if (x->require_preserve) +@@ -2969,7 +2964,7 @@ + if (!dest_is_symlink && x->preserve_ownership + && (new_dst || !SAME_OWNER_AND_GROUP (src_sb, dst_sb))) + { +- switch (set_owner (x, dst_name, dst_dirfd, dst_relname, -1, ++ switch (set_owner (x, dst_name, dst_dirfd, drelname, -1, + &src_sb, new_dst, &dst_sb)) + { + case -1: +@@ -3024,8 +3019,9 @@ + the lstat, but deducing the current destination mode + is tricky in the presence of implementation-defined + rules for special mode bits. */ +- if (new_dst && fstatat (dst_dirfd, dst_relname, &dst_sb, +- AT_SYMLINK_NOFOLLOW) != 0) ++ if (new_dst && (fstatat (dst_dirfd, drelname, &dst_sb, ++ AT_SYMLINK_NOFOLLOW) ++ != 0)) + { + error (0, errno, _("cannot stat %s"), quoteaf (dst_name)); + return false; +@@ -3038,7 +3034,7 @@ + + if (restore_dst_mode) + { +- if (lchmodat (dst_dirfd, dst_relname, dst_mode | omitted_permissions) ++ if (lchmodat (dst_dirfd, drelname, dst_mode | omitted_permissions) + != 0) + { + error (0, errno, _("preserving permissions for %s"), +@@ -3068,7 +3064,7 @@ + if (dst_backup) + { + char const *dst_relbackup = &dst_backup[dst_relname - dst_name]; +- if (renameat (dst_dirfd, dst_relbackup, dst_dirfd, dst_relname) != 0) ++ if (renameat (dst_dirfd, dst_relbackup, dst_dirfd, drelname) != 0) + error (0, errno, _("cannot un-backup %s"), quoteaf (dst_name)); + else + { +diff -Naur coreutils-9.1.orig/src/cp.c coreutils-9.1/src/cp.c +--- coreutils-9.1.orig/src/cp.c 2023-05-04 21:08:46.747627135 +0000 ++++ coreutils-9.1/src/cp.c 2023-05-04 21:09:50.067286480 +0000 +@@ -273,15 +273,19 @@ + when done. */ + + static bool +-re_protect (char const *const_dst_name, int dst_dirfd, char const *dst_relname, ++re_protect (char const *const_dst_name, int dst_dirfd, char const *dst_fullname, + struct dir_attr *attr_list, const struct cp_options *x) + { + struct dir_attr *p; + char *dst_name; /* A copy of CONST_DST_NAME we can change. */ +- char *src_name; /* The source name in 'dst_name'. */ ++ char *src_name; /* The relative source name in 'dst_name'. */ ++ char *full_src_name; /* The full source name in 'dst_name'. */ + + ASSIGN_STRDUPA (dst_name, const_dst_name); +- src_name = dst_name + (dst_relname - const_dst_name); ++ full_src_name = dst_name + (dst_fullname - const_dst_name); ++ src_name = full_src_name; ++ while (*src_name == '/') ++ src_name++; + + for (p = attr_list; p; p = p->next) + { +@@ -324,7 +328,7 @@ + + if (x->preserve_mode) + { +- if (copy_acl (src_name, -1, dst_name, -1, p->st.st_mode) != 0) ++ if (copy_acl (full_src_name, -1, dst_name, -1, p->st.st_mode) != 0) + return false; + } + else if (p->restore_mode) +@@ -664,6 +668,7 @@ + bool parent_exists = true; /* True if dir_name (dst_name) exists. */ + struct dir_attr *attr_list; + char *arg_in_concat = NULL; ++ char *full_arg_in_concat = NULL; + char *arg = file[i]; + + /* Trailing slashes are meaningful (i.e., maybe worth preserving) +@@ -696,6 +701,7 @@ + (x->verbose ? "%s -> %s\n" : NULL), + &attr_list, &new_dst, x)); + ++ full_arg_in_concat = arg_in_concat; + while (*arg_in_concat == '/') + arg_in_concat++; + } +@@ -724,7 +730,7 @@ + new_dst, x, ©_into_self, NULL); + + if (parents_option) +- ok &= re_protect (dst_name, target_dirfd, arg_in_concat, ++ ok &= re_protect (dst_name, target_dirfd, full_arg_in_concat, + attr_list, x); + } + +diff -Naur coreutils-9.1.orig/tests/cp/cp-parents.sh coreutils-9.1/tests/cp/cp-parents.sh +--- coreutils-9.1.orig/tests/cp/cp-parents.sh 2022-04-08 11:22:18.000000000 +0000 ++++ coreutils-9.1/tests/cp/cp-parents.sh 2023-05-04 21:09:50.067286480 +0000 +@@ -66,4 +66,10 @@ + cp --parents --no-preserve=mode np/b/file np_dest/ || fail=1 + p=$(ls -ld np_dest/np|cut -b-10); case $p in drwxr-xr-x);; *) fail=1;; esac + ++# coreutils 9.1-9.3 inclusive would fail to copy acls for absolute dirs ++mkdir dest || framework_failure_ ++if test -f /bin/ls; then ++ cp -t dest --parents -p /bin/ls || fail=1 ++fi ++ + Exit $fail diff --git a/coreutils.spec b/coreutils.spec index 8c4a6b1..85f43c7 100644 --- a/coreutils.spec +++ b/coreutils.spec @@ -1,7 +1,7 @@ Summary: A set of basic GNU tools commonly used in shell scripts Name: coreutils Version: 9.1 -Release: 11%{?dist} +Release: 12%{?dist} License: GPLv3+ Url: https://www.gnu.org/software/coreutils/ Source0: https://ftp.gnu.org/gnu/%{name}/%{name}-%{version}.tar.xz @@ -23,6 +23,9 @@ Patch1: gnulib-simple-backup-fix.patch # basic support for checking NFSv4 ACLs (#2137866) Patch2: coreutils-nfsv4-acls.patch +# Fix directory-relative syscalls in copy code; broken in 9.1 +Patch3: coreutils-9.1-copy-relative-dir.patch + # disable the test-lock gnulib test prone to deadlock Patch100: coreutils-8.26-test-lock.patch @@ -261,6 +264,10 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir %license COPYING %changelog +* Thu May 04 2023 Pádraig Brady
- 9.1-12
+- further fixes to backups; broken in 9.1
+- fix some directory-relative syscalls; broken in 9.1
+
* Thu Jan 19 2023 Fedora Release Engineering