diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2015-03-04 14:55:56 +0100 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2015-03-04 14:55:56 +0100 |
commit | bdf0e734506b5b18234d48a0e7c6995aeda30b9d (patch) | |
tree | 540c17e5719bf72acc6a0b19ecf54398934de33f | |
parent | 107958d7173ab84566c9d89b1cafa08379c849fb (diff) | |
parent | d8be5087771db34b191b13f22a2846888a477c36 (diff) | |
download | libgit2-bdf0e734506b5b18234d48a0e7c6995aeda30b9d.tar.gz |
Merge pull request #2932 from jeffhostetler/jeffhostetler/big_clone_crash
Fix crash in git_clone on extremely large repos
-rw-r--r-- | src/win32/posix.h | 2 | ||||
-rw-r--r-- | src/win32/posix_w32.c | 24 | ||||
-rw-r--r-- | tests/core/ftruncate.c | 48 |
3 files changed, 69 insertions, 5 deletions
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..b8b4f43f8 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -42,12 +42,28 @@ /* 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 defined(_MSC_VER) && _MSC_VER >= 1500 - return _chsize_s(fd, size); + if (size < 0) { + errno = EINVAL; + return -1; + } + +#if !defined(__MINGW32__) + return ((_chsize_s(fd, size) == 0) ? 0 : -1); #else - return _chsize(fd, size); + /* TODO MINGW32 Find a replacement for _chsize() that handles big files. */ + 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); +} |