summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2019-04-04 15:06:44 -0700
committerGitHub <noreply@github.com>2019-04-04 15:06:44 -0700
commitaeea1c463941806a0176859c06c0e2e9716efcb0 (patch)
tree66b216a1967068230777a0d5867a46e4e510ddca /src
parent80db20430ec103cc8b3ca1734770e50c84c626ab (diff)
parentfb7614c0f3dfc95a0b78948c5878628e12750082 (diff)
downloadlibgit2-aeea1c463941806a0176859c06c0e2e9716efcb0.tar.gz
Merge pull request #4874 from tiennou/test/4615
Test that largefiles can be read through the tree API
Diffstat (limited to 'src')
-rw-r--r--src/posix.c38
-rw-r--r--src/posix.h1
-rw-r--r--src/win32/posix_w32.c52
3 files changed, 91 insertions, 0 deletions
diff --git a/src/posix.c b/src/posix.c
index bffe02e05..b5dfac56d 100644
--- a/src/posix.c
+++ b/src/posix.c
@@ -155,6 +155,44 @@ int p_rename(const char *from, const char *to)
return -1;
}
+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;
+ prealloc.fst_posmode = F_PEOFPOSMODE;
+ prealloc.fst_offset = offset;
+ prealloc.fst_length = len;
+
+ /*
+ * 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
+}
+
#endif /* GIT_WIN32 */
ssize_t p_read(git_file fd, void *buf, size_t cnt)
diff --git a/src/posix.h b/src/posix.h
index 2934f2479..0119b6bb7 100644
--- a/src/posix.h
+++ b/src/posix.h
@@ -115,6 +115,7 @@ extern int p_open(const char *path, int flags, ...);
extern int p_creat(const char *path, mode_t mode);
extern int p_getcwd(char *buffer_out, size_t size);
extern int p_rename(const char *from, const char *to);
+extern int p_fallocate(int fd, off_t offset, off_t len);
extern int git__page_size(size_t *page_size);
extern int git__mmap_alignment(size_t *page_size);
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index d8bbebb5d..fcaf77e89 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -516,6 +516,58 @@ int p_creat(const char *path, mode_t mode)
return p_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
}
+int p_fallocate(int fd, off_t offset, off_t len)
+{
+ HANDLE fh = (HANDLE)_get_osfhandle(fd);
+ LARGE_INTEGER zero, position, oldsize, newsize;
+ size_t size;
+
+ if (fh == INVALID_HANDLE_VALUE) {
+ errno = EBADF;
+ return -1;
+ }
+
+ if (offset < 0 || len <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (git__add_sizet_overflow(&size, offset, len)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ zero.u.LowPart = 0;
+ zero.u.HighPart = 0;
+
+ newsize.u.LowPart = (size & 0xffffffff);
+
+#if (SIZE_MAX > UINT32_MAX)
+ newsize.u.HighPart = size >> 32;
+#else
+ newsize.u.HighPart = 0;
+#endif
+
+ if (!GetFileSizeEx(fh, &oldsize)) {
+ set_errno();
+ return -1;
+ }
+
+ /* POSIX emulation: attempting to shrink the file is ignored */
+ if (oldsize.QuadPart >= newsize.QuadPart)
+ return 0;
+
+ if (!SetFilePointerEx(fh, zero, &position, FILE_CURRENT) ||
+ !SetFilePointerEx(fh, newsize, NULL, FILE_BEGIN) ||
+ !SetEndOfFile(fh) ||
+ !SetFilePointerEx(fh, position, 0, FILE_BEGIN)) {
+ set_errno();
+ return -1;
+ }
+
+ return 0;
+}
+
int p_utimes(const char *path, const struct p_timeval times[2])
{
git_win32_path wpath;