summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorc-blake <c-blake@users.noreply.github.com>2023-02-22 13:54:04 -0500
committerGitHub <noreply@github.com>2023-02-22 13:54:04 -0500
commitfdd75202576634f1fb8c7948d6031e34af9ea67e (patch)
tree394d1f75eef99428b10d47b422f7d253cd0c7463
parentab1d4a5d58af8452b26f57f244bcd0d39b409c5e (diff)
downloadNim-fdd75202576634f1fb8c7948d6031e34af9ea67e.tar.gz
Fix the TODO portion of recently added `posix_fallocate` on OS X. (#21387)
-rw-r--r--lib/posix/posix.nim19
1 files changed, 17 insertions, 2 deletions
diff --git a/lib/posix/posix.nim b/lib/posix/posix.nim
index aee9308a6..07652c64d 100644
--- a/lib/posix/posix.nim
+++ b/lib/posix/posix.nim
@@ -198,9 +198,24 @@ proc posix_fadvise*(a1: cint, a2, a3: Off, a4: cint): cint {.
 
 proc ftruncate*(a1: cint, a2: Off): cint {.importc, header: "<unistd.h>".}
 when defined(osx):              # 2001 POSIX evidently does not concern Apple
+  type FStore {.importc: "fstore_t", header: "<fcntl.h>", bycopy.} = object
+    fst_flags: uint32           ## IN: flags word
+    fst_posmode: cint           ## IN: indicates offset field
+    fst_offset,                 ## IN: start of the region
+      fst_length,               ## IN: size of the region
+      fst_bytesalloc: Off       ## OUT: number of bytes allocated
+  var F_PEOFPOSMODE {.importc, header: "<fcntl.h>".}: cint
+  var F_ALLOCATEALL {.importc, header: "<fcntl.h>".}: uint32
+  var F_PREALLOCATE {.importc, header: "<fcntl.h>".}: cint
   proc posix_fallocate*(a1: cint, a2, a3: Off): cint =
-    ftruncate(a1, a2 + a3)      # Set size to off + len, max offset
-else:                           # TODO: Use fcntl(fd, F_PREALLOCATE, ..) above
+    var fst = FStore(fst_flags: F_ALLOCATEALL, fst_posmode: F_PEOFPOSMODE,
+                     fst_offset: a2, fst_length: a3)
+    # Must also call ftruncate to match what POSIX does. Unlike posix_fallocate,
+    # this can shrink files.  Could guard w/getFileSize, but caller likely knows
+    # present size & has no good reason to call this unless it is growing.
+    if fcntl(a1, F_PREALLOCATE, fst.addr) != cint(-1): ftruncate(a1, a2 + a3)
+    else: cint(-1)
+else:
   proc posix_fallocate*(a1: cint, a2, a3: Off): cint {.
     importc, header: "<fcntl.h>".}