summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2019-02-22 20:10:52 +0000
committerEdward Thomson <ethomson@edwardthomson.com>2019-02-22 20:10:52 +0000
commitbd132046b04875f928e52d16363fb73f8e85dded (patch)
treeed89c4f13e9e7134906c52a3620cce2ef9e782d6
parent0345a380a090d28c8435f09f2f35085b435229d9 (diff)
downloadlibgit2-bd132046b04875f928e52d16363fb73f8e85dded.tar.gz
p_fallocate: compatibility fixes for macOS
On macOS, fcntl(..., F_PREALLOCATE, ...) will only succeed when followed by an ftruncate(), even when it reports success. However, that syscall will fail when the file already exists. Thus, we must ignore the error code and simply let ftruncate extend the size of the file itself (albeit slowly). By calling ftruncate, we also need to prevent against file shrinkage, for compatibility with posix_ftruncate, which will only extend files, never shrink them.
-rw-r--r--src/posix.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/src/posix.c b/src/posix.c
index 242fda8c6..b5dfac56d 100644
--- a/src/posix.c
+++ b/src/posix.c
@@ -159,6 +159,20 @@ int p_fallocate(int fd, off_t offset, off_t len)
{
#ifdef __APPLE__
fstore_t prealloc;
+ struct stat st;
+ size_t newsize;
+ int error;
+
+ if ((error = p_fstat(fd, &st)) < 0)
+ return error;
+
+ if (git__add_sizet_overflow(&newsize, offset, len)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (newsize < (unsigned long long)st.st_size)
+ return 0;
memset(&prealloc, 0, sizeof(prealloc));
prealloc.fst_flags = F_ALLOCATEALL;
@@ -166,7 +180,14 @@ int p_fallocate(int fd, off_t offset, off_t len)
prealloc.fst_offset = offset;
prealloc.fst_length = len;
- return fcntl(fd, F_PREALLOCATE, &prealloc);
+ /*
+ * fcntl will often error when the file already exists; ignore
+ * this error since ftruncate will also resize the file (although
+ * likely slower).
+ */
+ fcntl(fd, F_PREALLOCATE, &prealloc);
+
+ return ftruncate(fd, (offset + len));
#else
return posix_fallocate(fd, offset, len);
#endif