From 7e9b21aa2a13b97b54b0083eb8f40b7f428bc829 Mon Sep 17 00:00:00 2001 From: Jeff Hostetler Date: Fri, 27 Feb 2015 08:54:48 -0500 Subject: [PATCH] Fix p_ftruncate to handle big files for git_clone --- src/win32/posix.h | 2 +- src/win32/posix_w32.c | 24 ++++++++++++++++++--- tests/core/ftruncate.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 tests/core/ftruncate.c diff --git a/src/win32/posix.h b/src/win32/posix.h index 104966edc..9ac78430b 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -41,7 +41,7 @@ extern int p_chdir(const char* path); extern int p_chmod(const char* path, mode_t mode); extern int p_rmdir(const char* path); extern int p_access(const char* path, mode_t mode); -extern int p_ftruncate(int fd, long size); +extern int p_ftruncate(int fd, git_off_t size); /* p_lstat is almost but not quite POSIX correct. Specifically, the use of * ENOTDIR is wrong, in that it does not mean precisely that a non-directory diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 6e005c1cd..874cba9cc 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -42,12 +42,30 @@ /* GetFinalPathNameByHandleW signature */ typedef DWORD(WINAPI *PFGetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, DWORD); -int p_ftruncate(int fd, long size) +/** + * Truncate or extend file. + * + * We now take a "git_off_t" rather than "long" because + * files may be longer than 2Gb. + */ +int p_ftruncate(int fd, git_off_t size) { + if (size < 0) { + errno = EINVAL; + return -1; + } + #if defined(_MSC_VER) && _MSC_VER >= 1500 - return _chsize_s(fd, size); + return ((_chsize_s(fd, size) == 0) ? 0 : -1); #else - return _chsize(fd, size); + /* TODO Find a replacement for _chsize() that handles big files. + * This comment is probably __MINGW32__ specific. + */ + if (size > INT32_MAX) { + errno = EFBIG; + return -1; + } + return _chsize(fd, (long)size); #endif } diff --git a/tests/core/ftruncate.c b/tests/core/ftruncate.c new file mode 100644 index 000000000..21981d677 --- /dev/null +++ b/tests/core/ftruncate.c @@ -0,0 +1,48 @@ +/** + * Some tests for p_ftruncate() to ensure that + * properly handles large (2Gb+) files. + */ + +#include "clar_libgit2.h" + +static const char *filename = "core_ftruncate.txt"; +static int fd = -1; + +void test_core_ftruncate__initialize(void) +{ + if (!cl_getenv("GITTEST_INVASIVE_FS_SIZE")) + cl_skip(); + + cl_must_pass((fd = p_open(filename, O_CREAT | O_RDWR, 0644))); +} + +void test_core_ftruncate__cleanup(void) +{ + if (fd < 0) + return; + + p_close(fd); + fd = 0; + + p_unlink(filename); +} + +static void _extend(git_off_t i64len) +{ + struct stat st; + int error; + + cl_assert((error = p_ftruncate(fd, i64len)) == 0); + cl_assert((error = p_fstat(fd, &st)) == 0); + cl_assert(st.st_size == i64len); +} + +void test_core_ftruncate__2gb(void) +{ + _extend(0x80000001); +} + +void test_core_ftruncate__4gb(void) +{ + _extend(0x100000001); +}