summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDhruva Krishnamurthy <dhruvakm@gmail.com>2020-06-17 14:31:11 -0700
committerDhruva Krishnamurthy <dhruvakm@gmail.com>2020-12-30 06:55:40 -0800
commit4ce8e01a7ada3c75f7407dc9fafd25b4ac38d037 (patch)
tree526cd9e3bf31ffd6e9fce4993b649ce2875713c4
parenta9f57a8919f264fa184320d1f5c3ed7a35b7576a (diff)
downloadlibgit2-4ce8e01a7ada3c75f7407dc9fafd25b4ac38d037.tar.gz
Support build with NO_MMAP to disable use of system mmap
* Use pread/pwrite to avoid updating position in file descriptor * Emulate missing pread/pwrite on win32 using overlapped file IO
-rw-r--r--src/indexer.c18
-rw-r--r--src/posix.c32
-rw-r--r--src/posix.h9
-rw-r--r--src/unix/posix.h3
-rw-r--r--src/win32/posix_w32.c70
5 files changed, 127 insertions, 5 deletions
diff --git a/src/indexer.c b/src/indexer.c
index 453bb3df7..ba82d716d 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -603,6 +603,23 @@ static void hash_partially(git_indexer *idx, const uint8_t *data, size_t size)
static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t size)
{
+#ifdef NO_MMAP
+ size_t remaining_size = size;
+ const char *ptr = (const char *)data;
+
+ /* Handle data size larger that ssize_t */
+ while (remaining_size > 0) {
+ ssize_t nb;
+ HANDLE_EINTR(nb, p_pwrite(idx->pack->mwf.fd, (void *)ptr,
+ remaining_size, offset));
+ if (nb <= 0)
+ return -1;
+
+ ptr += nb;
+ offset += nb;
+ remaining_size -= nb;
+ }
+#else
git_file fd = idx->pack->mwf.fd;
size_t mmap_alignment;
size_t page_offset;
@@ -627,6 +644,7 @@ static int write_at(git_indexer *idx, const void *data, off64_t offset, size_t s
map_data = (unsigned char *)map.data;
memcpy(map_data + page_offset, data, size);
p_munmap(&map);
+#endif
return 0;
}
diff --git a/src/posix.c b/src/posix.c
index debd8d2c8..bf764ae6b 100644
--- a/src/posix.c
+++ b/src/posix.c
@@ -238,6 +238,9 @@ int git__mmap_alignment(size_t *alignment)
int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset)
{
+ const char *ptr;
+ size_t remaining_len;
+
GIT_MMAP_VALIDATE(out, len, prot, flags);
/* writes cannot be emulated without handling pagefaults since write happens by
@@ -248,15 +251,30 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset
return -1;
}
+ if (!git__is_ssizet(len)) {
+ errno = EINVAL;
+ return -1;
+ }
+
out->len = 0;
out->data = git__malloc(len);
GIT_ERROR_CHECK_ALLOC(out->data);
- if (!git__is_ssizet(len) ||
- (p_lseek(fd, offset, SEEK_SET) < 0) ||
- (p_read(fd, out->data, len) != (ssize_t)len)) {
- git_error_set(GIT_ERROR_OS, "mmap emulation failed");
- return -1;
+ remaining_len = len;
+ ptr = (const char *)out->data;
+ while (remaining_len > 0) {
+ ssize_t nb;
+ HANDLE_EINTR(nb, p_pread(fd, (void *)ptr, remaining_len, offset));
+ if (nb <= 0) {
+ git_error_set(GIT_ERROR_OS, "mmap emulation failed");
+ git__free(out->data);
+ out->data = NULL;
+ return -1;
+ }
+
+ ptr += nb;
+ offset += nb;
+ remaining_len -= nb;
}
out->len = len;
@@ -268,6 +286,10 @@ int p_munmap(git_map *map)
GIT_ASSERT_ARG(map);
git__free(map->data);
+ /* Initializing will help debug use-after-free */
+ map->len = 0;
+ map->data = NULL;
+
return 0;
}
diff --git a/src/posix.h b/src/posix.h
index eef667762..d98bc82ca 100644
--- a/src/posix.h
+++ b/src/posix.h
@@ -89,6 +89,12 @@
#define EAFNOSUPPORT (INT_MAX-1)
#endif
+/* Compiler independent macro to handle signal interrpted system calls */
+#define HANDLE_EINTR(result, x) do { \
+ result = (x); \
+ } while (result == -1 && errno == EINTR);
+
+
/* Provide a 64-bit size for offsets. */
#if defined(_MSC_VER)
@@ -119,6 +125,9 @@ typedef int git_file;
extern ssize_t p_read(git_file fd, void *buf, size_t cnt);
extern int p_write(git_file fd, const void *buf, size_t cnt);
+extern ssize_t p_pread(int fd, void *data, size_t size, off64_t offset);
+extern ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset);
+
#define p_close(fd) close(fd)
#define p_umask(m) umask(m)
diff --git a/src/unix/posix.h b/src/unix/posix.h
index b5527a4a8..7b3325e78 100644
--- a/src/unix/posix.h
+++ b/src/unix/posix.h
@@ -101,4 +101,7 @@ GIT_INLINE(int) p_futimes(int f, const struct p_timeval t[2])
# define p_futimes futimes
#endif
+#define p_pread(f, d, s, o) pread(f, d, s, o)
+#define p_pwrite(f, d, s, o) pwrite(f, d, s, o)
+
#endif
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 5a5e92158..0a8f2bee0 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -981,3 +981,73 @@ int p_inet_pton(int af, const char *src, void *dst)
errno = EINVAL;
return -1;
}
+
+ssize_t p_pread(int fd, void *data, size_t size, off64_t offset)
+{
+ HANDLE fh;
+ DWORD rsize = 0;
+ OVERLAPPED ov = {0};
+ LARGE_INTEGER pos = {0};
+ off64_t final_offset = 0;
+
+ /* Fail if the final offset would have overflowed to match POSIX semantics. */
+ if (!git__is_ssizet(size) || git__add_int64_overflow(&final_offset, offset, (int64_t)size)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Truncate large writes to the maximum allowable size: the caller
+ * needs to always call this in a loop anyways.
+ */
+ if (size > INT32_MAX) {
+ size = INT32_MAX;
+ }
+
+ pos.QuadPart = offset;
+ ov.Offset = pos.LowPart;
+ ov.OffsetHigh = pos.HighPart;
+ fh = (HANDLE)_get_osfhandle(fd);
+
+ if (ReadFile(fh, data, (DWORD)size, &rsize, &ov)) {
+ return (ssize_t)rsize;
+ }
+
+ set_errno();
+ return -1;
+}
+
+ssize_t p_pwrite(int fd, const void *data, size_t size, off64_t offset)
+{
+ HANDLE fh;
+ DWORD wsize = 0;
+ OVERLAPPED ov = {0};
+ LARGE_INTEGER pos = {0};
+ off64_t final_offset = 0;
+
+ /* Fail if the final offset would have overflowed to match POSIX semantics. */
+ if (!git__is_ssizet(size) || git__add_int64_overflow(&final_offset, offset, (int64_t)size)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ /*
+ * Truncate large writes to the maximum allowable size: the caller
+ * needs to always call this in a loop anyways.
+ */
+ if (size > INT32_MAX) {
+ size = INT32_MAX;
+ }
+
+ pos.QuadPart = offset;
+ ov.Offset = pos.LowPart;
+ ov.OffsetHigh = pos.HighPart;
+ fh = (HANDLE)_get_osfhandle(fd);
+
+ if (WriteFile(fh, data, (DWORD)size, &wsize, &ov)) {
+ return (ssize_t)wsize;
+ }
+
+ set_errno();
+ return -1;
+}