Subject: Re: bug#51857: cross-filesystem copying broken on macOS with coreutils >= 9.0

From: Paul Eggert <[email-masked]>
Date: Mon, 15 Nov 2021 23:31:12 -0800

On 11/15/21 19:14, Sudhip Nashi wrote:
> lseek(0x3, 0x0, 0x3)		 = -1 Err#6

Oh my, it appears lseek (fd, 0, SEEK_HOLE) is failing with errno == 
ENXIO when the file has no holes, even though the Darwin man page 
clearly states that lseek should return the file size in that case (see 
<https://github.com/apple/darwin-xnu/blob/main/bsd/man/man2/lseek.2>). 
So, not only does macOS lseek disagree with all other implementations, 
it even disagrees with the Darwin documentation.

To work around this macOS problem I installed the attached further patch 
into Gnulib and propagated it into coreutils. Please try the latest 
coreutils version on Savannah, or you can simply run configure+make from 
the tarball that is temporarily at:

https://web.cs.ucla.edu/~eggert/coreutils-9.0.28-6d0f0.tar.gz

From 1a268176fbb184e393c98575e61fe692264c7d91 Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Mon, 15 Nov 2021 22:17:44 -0800
Subject: [PATCH] lseek: port around macOS SEEK_HOLE glitch

Problem reported by Sudhip Nashi (Bug#51857#47).
* lib/lseek.c (rpl_lseek): Work around macOS lseek+SEEK_HOLE
returning -1 with ENXIO if there are no holes before EOF,
contrary to the macOS documentation.
---
 ChangeLog   | 6 ++++++
 lib/lseek.c | 6 ++++--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 71a226570..efc3a3887 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2021-11-15  Paul Eggert  <[email-masked]>
 
+	lseek: port around macOS SEEK_HOLE glitch
+	Problem reported by Sudhip Nashi (Bug#51857#47).
+	* lib/lseek.c (rpl_lseek): Work around macOS lseek+SEEK_HOLE
+	returning -1 with ENXIO if there are no holes before EOF,
+	contrary to the macOS documentation.
+
 	lseek: port around macOS SEEK_DATA glitch
 	Problem reported by Sudhip Nashi (Bug#51857).
 	* doc/posix-functions/lseek.texi (lseek): Mention macOS SEEK_DATA
diff --git a/lib/lseek.c b/lib/lseek.c
index 7dcd6c9da..e9a96ad20 100644
--- a/lib/lseek.c
+++ b/lib/lseek.c
@@ -61,10 +61,12 @@ rpl_lseek (int fd, off_t offset, int whence)
          data followed by a possibly-empty hole.  To work around this
          portability glitch, check whether OFFSET is within data by
          using lseek+SEEK_HOLE, and if so return to OFFSET by using
-         lseek+SEEK_SET.  */
+         lseek+SEEK_SET.  Also, contrary to the macOS documentation,
+         lseek+SEEK_HOLE can fail with ENXIO if there are no holes on
+         or after OFFSET.  What a mess!  */
       off_t next_hole = lseek (fd, offset, SEEK_HOLE);
       if (next_hole < 0)
-        return next_hole;
+        return errno == ENXIO ? offset : next_hole;
       if (next_hole != offset)
         whence = SEEK_SET;
     }
-- 
2.32.0