Skip to content

Commit aeea1c4

Browse files
authored
Merge pull request libgit2#4874 from tiennou/test/4615
Test that largefiles can be read through the tree API
2 parents 80db204 + fb7614c commit aeea1c4

File tree

5 files changed

+181
-0
lines changed

5 files changed

+181
-0
lines changed

src/posix.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,44 @@ int p_rename(const char *from, const char *to)
155155
return -1;
156156
}
157157

158+
int p_fallocate(int fd, off_t offset, off_t len)
159+
{
160+
#ifdef __APPLE__
161+
fstore_t prealloc;
162+
struct stat st;
163+
size_t newsize;
164+
int error;
165+
166+
if ((error = p_fstat(fd, &st)) < 0)
167+
return error;
168+
169+
if (git__add_sizet_overflow(&newsize, offset, len)) {
170+
errno = EINVAL;
171+
return -1;
172+
}
173+
174+
if (newsize < (unsigned long long)st.st_size)
175+
return 0;
176+
177+
memset(&prealloc, 0, sizeof(prealloc));
178+
prealloc.fst_flags = F_ALLOCATEALL;
179+
prealloc.fst_posmode = F_PEOFPOSMODE;
180+
prealloc.fst_offset = offset;
181+
prealloc.fst_length = len;
182+
183+
/*
184+
* fcntl will often error when the file already exists; ignore
185+
* this error since ftruncate will also resize the file (although
186+
* likely slower).
187+
*/
188+
fcntl(fd, F_PREALLOCATE, &prealloc);
189+
190+
return ftruncate(fd, (offset + len));
191+
#else
192+
return posix_fallocate(fd, offset, len);
193+
#endif
194+
}
195+
158196
#endif /* GIT_WIN32 */
159197

160198
ssize_t p_read(git_file fd, void *buf, size_t cnt)

src/posix.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ extern int p_open(const char *path, int flags, ...);
115115
extern int p_creat(const char *path, mode_t mode);
116116
extern int p_getcwd(char *buffer_out, size_t size);
117117
extern int p_rename(const char *from, const char *to);
118+
extern int p_fallocate(int fd, off_t offset, off_t len);
118119

119120
extern int git__page_size(size_t *page_size);
120121
extern int git__mmap_alignment(size_t *page_size);

src/win32/posix_w32.c

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,58 @@ int p_creat(const char *path, mode_t mode)
516516
return p_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
517517
}
518518

519+
int p_fallocate(int fd, off_t offset, off_t len)
520+
{
521+
HANDLE fh = (HANDLE)_get_osfhandle(fd);
522+
LARGE_INTEGER zero, position, oldsize, newsize;
523+
size_t size;
524+
525+
if (fh == INVALID_HANDLE_VALUE) {
526+
errno = EBADF;
527+
return -1;
528+
}
529+
530+
if (offset < 0 || len <= 0) {
531+
errno = EINVAL;
532+
return -1;
533+
}
534+
535+
if (git__add_sizet_overflow(&size, offset, len)) {
536+
errno = EINVAL;
537+
return -1;
538+
}
539+
540+
zero.u.LowPart = 0;
541+
zero.u.HighPart = 0;
542+
543+
newsize.u.LowPart = (size & 0xffffffff);
544+
545+
#if (SIZE_MAX > UINT32_MAX)
546+
newsize.u.HighPart = size >> 32;
547+
#else
548+
newsize.u.HighPart = 0;
549+
#endif
550+
551+
if (!GetFileSizeEx(fh, &oldsize)) {
552+
set_errno();
553+
return -1;
554+
}
555+
556+
/* POSIX emulation: attempting to shrink the file is ignored */
557+
if (oldsize.QuadPart >= newsize.QuadPart)
558+
return 0;
559+
560+
if (!SetFilePointerEx(fh, zero, &position, FILE_CURRENT) ||
561+
!SetFilePointerEx(fh, newsize, NULL, FILE_BEGIN) ||
562+
!SetEndOfFile(fh) ||
563+
!SetFilePointerEx(fh, position, 0, FILE_BEGIN)) {
564+
set_errno();
565+
return -1;
566+
}
567+
568+
return 0;
569+
}
570+
519571
int p_utimes(const char *path, const struct p_timeval times[2])
520572
{
521573
git_win32_path wpath;

tests/core/posix.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ void test_core_posix__initialize(void)
2727
#endif
2828
}
2929

30+
void test_core_posix__cleanup(void)
31+
{
32+
p_unlink("fallocate_test");
33+
}
34+
3035
static bool supports_ipv6(void)
3136
{
3237
#ifdef GIT_WIN32
@@ -190,3 +195,39 @@ void test_core_posix__p_regcomp_compile_userdiff_regexps(void)
190195
cl_must_pass(error);
191196
}
192197
}
198+
199+
void test_core_posix__fallocate(void)
200+
{
201+
int fd;
202+
struct stat st;
203+
204+
/* fallocate a new file succeeds */
205+
cl_must_pass(fd = p_open("fallocate_test", O_RDWR|O_CREAT, 0666));
206+
cl_must_pass(p_fallocate(fd, 0, 42));
207+
cl_must_pass(p_fstat(fd, &st));
208+
cl_assert_equal_i(42, st.st_size);
209+
p_close(fd);
210+
211+
/* fallocate an existing file succeeds */
212+
cl_must_pass(fd = p_open("fallocate_test", O_RDWR, 0666));
213+
cl_must_pass(p_fallocate(fd, 90, 9));
214+
cl_must_pass(p_fstat(fd, &st));
215+
cl_assert_equal_i(99, st.st_size);
216+
p_close(fd);
217+
218+
/* fallocate doesn't shrink */
219+
cl_must_pass(fd = p_open("fallocate_test", O_RDWR, 0666));
220+
cl_must_pass(p_fallocate(fd, 0, 14));
221+
cl_must_pass(p_fstat(fd, &st));
222+
cl_assert_equal_i(99, st.st_size);
223+
p_close(fd);
224+
225+
/* fallocate doesn't move the cursor */
226+
cl_must_pass(fd = p_open("fallocate_test", O_RDWR, 0666));
227+
cl_must_pass(p_fallocate(fd, 0, 100));
228+
cl_assert_equal_i(0, p_lseek(fd, 0, SEEK_CUR));
229+
cl_must_pass(p_lseek(fd, 42, SEEK_SET));
230+
cl_must_pass(p_fallocate(fd, 0, 200));
231+
cl_assert_equal_i(42, p_lseek(fd, 0, SEEK_CUR));
232+
p_close(fd);
233+
}

tests/object/tree/read.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,52 @@ void test_object_tree_read__two(void)
7373
git_object_free(obj);
7474
git_tree_free(tree);
7575
}
76+
77+
#define BIGFILE "bigfile"
78+
#define BIGFILE_SIZE (off_t)4 * 1024 * 1024 * 1024 /* 4 GiB */
79+
80+
void test_object_tree_read__largefile(void)
81+
{
82+
git_reference *ref;
83+
git_commit *commit;
84+
git_tree *tree;
85+
git_oid oid;
86+
const git_tree_entry *entry;
87+
git_object *object;
88+
git_buf file = GIT_BUF_INIT;
89+
int fd;
90+
git_index *idx;
91+
92+
if (!cl_is_env_set("GITTEST_INVASIVE_FS_SIZE"))
93+
cl_skip();
94+
95+
cl_git_pass(git_reference_lookup(&ref, g_repo, "refs/heads/master"));
96+
cl_git_pass(git_repository_index(&idx, g_repo));
97+
98+
cl_git_pass(git_buf_puts(&file, git_repository_workdir(g_repo)));
99+
cl_git_pass(git_buf_joinpath(&file, file.ptr, BIGFILE));
100+
101+
fd = p_open(git_buf_cstr(&file), O_CREAT|O_RDWR, 0644);
102+
cl_assert_(fd >= 0, "invalid file descriptor");
103+
104+
cl_must_pass(p_fallocate(fd, 0, BIGFILE_SIZE));
105+
cl_must_pass(p_close(fd));
106+
107+
cl_git_pass(git_index_add_bypath(idx, BIGFILE));
108+
cl_repo_commit_from_index(&oid, g_repo, NULL, 0, "bigfile");
109+
110+
cl_git_pass(git_commit_lookup(&commit, g_repo, &oid));
111+
cl_git_pass(git_commit_tree(&tree, commit));
112+
113+
entry = git_tree_entry_byname(tree, BIGFILE);
114+
cl_assert_(entry, "entry was NULL");
115+
116+
cl_git_pass(git_tree_entry_to_object(&object, g_repo, entry));
117+
118+
git_buf_dispose(&file);
119+
git_object_free(object);
120+
git_tree_free(tree);
121+
git_index_free(idx);
122+
git_commit_free(commit);
123+
git_reference_free(ref);
124+
}

0 commit comments

Comments
 (0)