File 1672-erts-Fix-large-read-writes-on-macOS.patch of Package erlang

From 434c97f4596bb9df4d132f7f3bf51aac6376de6d Mon Sep 17 00:00:00 2001
From: Lukas Larsson <lukas@erlang.org>
Date: Fri, 26 Aug 2022 09:37:43 +0200
Subject: [PATCH 1/2] erts: Fix large read/writes on macOS

On macOS there is an (as far as I can tell) undocumented limitation
for read and write that the size is not allowed to be greater than
2GB. So if we get an EINVAL from read/write and the size is > 2GB
we try again with a smaller size.

Closes #6242
---
 erts/emulator/nifs/unix/unix_prim_file.c | 12 ++++++++++++
 lib/kernel/test/file_SUITE.erl           | 15 +++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/erts/emulator/nifs/unix/unix_prim_file.c b/erts/emulator/nifs/unix/unix_prim_file.c
index d110ead1e5..ff47d08ec4 100644
--- a/erts/emulator/nifs/unix/unix_prim_file.c
+++ b/erts/emulator/nifs/unix/unix_prim_file.c
@@ -42,6 +42,8 @@
 
 #include <utime.h>
 
+#define FALLBACK_RW_LENGTH ((1ull << 31) - 1)
+
 /* Macros for testing file types. */
 #ifdef NO_UMASK
 #define FILE_MODE 0644
@@ -284,6 +286,11 @@ Sint64 efile_readv(efile_data_t *d, SysIOVec *iov, int iovlen) {
 
         if(use_fallback) {
             result = read(u->fd, iov->iov_base, iov->iov_len);
+
+            /* Some OSs (e.g. macOS) does not allow reads greater than 2 GB,
+               so if we get EINVAL in the fallback, we try with a smaller length */
+            if (result < 0 && errno == EINVAL && iov->iov_len > FALLBACK_RW_LENGTH)
+                result = read(u->fd, iov->iov_base, FALLBACK_RW_LENGTH);
         }
 
         if(result > 0) {
@@ -329,6 +336,11 @@ Sint64 efile_writev(efile_data_t *d, SysIOVec *iov, int iovlen) {
 
         if(use_fallback) {
             result = write(u->fd, iov->iov_base, iov->iov_len);
+
+            /* Some OSs (e.g. macOS) does not allow writes greater than 2 GB,
+               so if we get EINVAL in the fallback, we try with a smaller length */
+            if (result < 0 && errno == EINVAL && iov->iov_len > FALLBACK_RW_LENGTH)
+                result = write(u->fd, iov->iov_base, FALLBACK_RW_LENGTH);
         }
 
         if(result > 0) {
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 52ef711008..dc9d0ebb2c 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -4088,6 +4088,21 @@ do_large_file(Name) ->
     {ok,R}   = ?FILE_MODULE:read(F1, L+1),
     ok       = ?FILE_MODULE:close(F1),
 
+    %% Reopen the file try to read all of it; used to fail on macOS
+    %% We open with binary in order to not get a memory explosion.
+    {ok, F2} = ?FILE_MODULE:open(Name, [raw,read,binary]),
+    IsWindows = element(1,os:type()) =:= win32,
+    case {?FILE_MODULE:read(F2, P), erlang:system_info(wordsize)} of
+        {{ok, B}, 8} ->
+            P = byte_size(B);
+        {eof, 8} when IsWindows ->
+            ok;
+        {eof, 4} ->
+            %% Cannot read such large files on 32-bit
+            ok
+    end,
+    ok = ?FILE_MODULE:close(F2),
+
     ok.
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-- 
2.35.3

openSUSE Build Service is sponsored by