Subject: bug#62404: --reflink=auto not falling back appropriately on older kernels

From: Pádraig Brady <[email-masked]>
Date: Thu, 23 Mar 2023 13:39:01 +0000

On 23/03/2023 13:03, Pádraig Brady wrote:
> Details at
> https://github.com/termux/termux-packages/issues/15706#issuecomment-1481144831
> 
> But in summary, the new --reflink errno checking in coreutils 9.2
> is not working appropriately on android 4.9 kernels at least.

Proposed patch attached.
It may be better to key on kernel version rather than __ANDROID__
(along the lines of https://github.com/coreutils/coreutils/commit/ba5e6885d),
but that needs more investigation.

cheers,
Pádraig
From abc695b6650722ac591f1b66b7d6971bab1acbc0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email-masked]>
Date: Thu, 23 Mar 2023 13:19:04 +0000
Subject: [PATCH] copy: fix --reflink=auto fallback on android

* src/copy.c (is_transient_failure): A new function refactored
from handle_clone_fail().
(is_CLONENOTSUP): Reverse the sense of the errno check on android,
so that we assume the clone is not supported unless we
get a transient error like EIO etc.
* NEWS: Mention the bug fix.
Addresses https://bugs.gnu.org/62404
---
 NEWS       |  7 +++++++
 src/copy.c | 22 ++++++++++++++++++++--
 2 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/NEWS b/NEWS
index 030f0e543..7bd10e411 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,13 @@ GNU coreutils NEWS                                    -*- outline -*-
 
 * Noteworthy changes in release ?.? (????-??-??) [?]
 
+** Bug fixes
+
+  cp --relink=auto (the default), mv, and install have improved
+  fall back to a standard copy on Android systems.  Previously default
+  copy operations could fail with "Permission denied" errors etc.
+  [issue introduced in coreutils-9.2]
+
 
 * Noteworthy changes in release 9.2 (2023-03-20) [stable]
 
diff --git a/src/copy.c b/src/copy.c
index 39197872c..1be28149a 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -278,15 +278,34 @@ create_hole (int fd, char const *name, bool punch_holes, off_t size)
 }

+/* Whether the errno from FICLONE, or copy_file_range
+   indicates operation is a transient failure.
+   I.e., a failure that would indicate the operation is supported,
+   but has failed in a terminal way.  */
+
+static bool
+is_transient_failure (int err)
+{
+  return err == EIO || err == ENOMEM
+         || err == ENOSPC || err == EDQUOT;
+}
+
+
 /* Whether the errno from FICLONE, or copy_file_range
    indicates operation is not supported for this file or file system.  */
 
 static bool
 is_CLONENOTSUP (int err)
 {
+#ifdef __ANDROID__
+  /* On kernel 4.9 at least various errors were reported,
+     so we reverse the sense of the errno check here.  */
+  return ! is_transient_failure (err);
+#else
   return err == ENOSYS || is_ENOTSUP (err)
          || err == EINVAL || err == EBADF
          || err == EXDEV || err == ETXTBSY;
+#endif
 }

@@ -1177,8 +1196,7 @@ handle_clone_fail (int dst_dirfd, char const* dst_relname,
      and instead only cater for specific transient errors.  */
   bool transient_failure;
   if (dest_desc < 0) /* currently for fclonefileat().  */
-    transient_failure = errno == EIO || errno == ENOMEM
-                        || errno == ENOSPC || errno == EDQUOT;
+    transient_failure = is_transient_failure (errno);
   else /* currently for FICLONE.  */
     transient_failure = ! is_CLONENOTSUP (errno);
 
-- 
2.26.2