From 79ca2edcd4e7a801400fa33c2c705b8f03a5d7f5 Mon Sep 17 00:00:00 2001 From: Ramsay Jones Date: Fri, 20 Mar 2009 19:51:48 +0000 Subject: [PATCH] win32: Add routines to abstract memory-mapped file functions In particular, the git__mmap() and git__munmap() routines provide the interface to platform specific memory-mapped file facilities. We provide implementations for unix and win32, which can be found in their own sub-directories. Signed-off-by: Ramsay Jones Signed-off-by: Shawn O. Pearce --- Makefile | 12 +++-- src/common.h | 5 +- src/fileops.c | 10 ++-- src/fileops.h | 10 ++-- src/map.h | 31 ++++++++++++ src/odb.c | 2 +- src/unix/map.c | 61 +++++++++++++++++++++++ src/win32/map.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 236 insertions(+), 20 deletions(-) create mode 100644 src/map.h create mode 100644 src/unix/map.c create mode 100644 src/win32/map.c diff --git a/Makefile b/Makefile index ca88eb622..6d681ba63 100644 --- a/Makefile +++ b/Makefile @@ -11,6 +11,7 @@ all:: DOXYGEN = doxygen INSTALL = install RANLIB = ranlib +AR = ar cr prefix=/usr/local libdir=$(prefix)/lib @@ -21,6 +22,8 @@ CFLAGS = -g -O2 -Wall LIBS = -L. -lgit2 -lz OS = unix +CRYPTO_LIB = -lcrypto + EXTRA_LIBS = EXTRA_SRC = EXTRA_OBJ = @@ -32,6 +35,8 @@ ifneq (,$(findstring CYGWIN,$(uname_S))) endif SRC_C = $(wildcard src/*.c) +OS_SRC = $(wildcard src/$(OS)/*.c) +SRC_C += $(OS_SRC) OBJS = $(patsubst %.c,%.o,$(SRC_C)) HDRS = $(wildcard src/*.h) PUBLIC_HEADERS = $(wildcard src/git/*.h) @@ -46,7 +51,7 @@ TEST_RUN = $(patsubst %.exe,%.run,$(TEST_EXE)) ifndef NO_OPENSSL SHA1_HEADER = - EXTRA_LIBS += -lcrypto + EXTRA_LIBS += $(CRYPTO_LIB) else SHA1_HEADER = "sha1/sha1.h" EXTRA_SRC += src/sha1/sha1.c @@ -68,8 +73,7 @@ all:: $(GIT_LIB) clean: rm -f $(GIT_LIB) rm -f libgit2.pc - rm -f src/*.o - rm -f src/sha1/*.o + rm -f src/*.o src/sha1/*.o src/unix/*.o rm -f tests/*.o tests/*.exe tests/*.toc rm -rf trash-*.exe rm -rf apidocs @@ -111,7 +115,7 @@ uninstall: $(OBJS): $(HDRS) $(GIT_LIB): $(OBJS) rm -f $(GIT_LIB) - $(AR) cr $(GIT_LIB) $(OBJS) + $(AR) $(GIT_LIB) $(OBJS) $(RANLIB) $(GIT_LIB) T_HDR = tests/test_lib.h tests/test_helpers.h diff --git a/src/common.h b/src/common.h index 14dc301e7..221c73c75 100644 --- a/src/common.h +++ b/src/common.h @@ -23,14 +23,15 @@ #ifdef GIT_WIN32 # include -# include +# include + +#define snprintf _snprintf typedef int ssize_t; #else # include -# include # include #endif diff --git a/src/fileops.c b/src/fileops.c index e2ec61507..09e1e1219 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -106,18 +106,16 @@ void gitfo_free_buf(gitfo_buf *obj) obj->data = NULL; } -int gitfo_map_ro(gitfo_map *out, git_file fd, off_t begin, size_t len) +int gitfo_map_ro(git_map *out, git_file fd, off_t begin, size_t len) { - out->data = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, begin); - if (out->data == (void*)-1) + if (git__mmap(out, len, GIT_PROT_READ, GIT_MAP_SHARED, fd, begin) < 0) return git_os_error(); - out->len = len; return GIT_SUCCESS; } -void gitfo_free_map(gitfo_map *out) +void gitfo_free_map(git_map *out) { - munmap(out->data, out->len); + git__munmap(out); } /* cached diskio */ diff --git a/src/fileops.h b/src/fileops.h index 3cc1e1683..39e01811c 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -10,6 +10,7 @@ #define _FILE_OFFSET_BITS 64 #include "common.h" +#include "map.h" #include #include #include @@ -29,11 +30,6 @@ typedef struct { /* file io buffer */ size_t len; /* data length */ } gitfo_buf; -typedef struct { /* memory mapped buffer */ - void *data; /* data bytes */ - size_t len; /* data length */ -} gitfo_map; - extern int gitfo_exists(const char *path); extern int gitfo_open(const char *path, int flags); extern int gitfo_creat(const char *path, int mode); @@ -66,7 +62,7 @@ extern void gitfo_free_buf(gitfo_buf *obj); * - GIT_EOSERR on an unspecified OS related error. */ extern int gitfo_map_ro( - gitfo_map *out, + git_map *out, git_file fd, off_t begin, size_t len); @@ -75,7 +71,7 @@ extern int gitfo_map_ro( * Release the memory associated with a previous memory mapping. * @param map the mapping description previously configured. */ -extern void gitfo_free_map(gitfo_map *map); +extern void gitfo_free_map(git_map *map); /** * Walk each directory entry, except '.' and '..', calling fn(state). diff --git a/src/map.h b/src/map.h new file mode 100644 index 000000000..3188ffdbb --- /dev/null +++ b/src/map.h @@ -0,0 +1,31 @@ +#ifndef INCLUDE_map_h__ +#define INCLUDE_map_h__ + +#include "common.h" + + +/* git__mmap() prot values */ +#define GIT_PROT_NONE 0x0 +#define GIT_PROT_READ 0x1 +#define GIT_PROT_WRITE 0x2 +#define GIT_PROT_EXEC 0x4 + +/* git__mmmap() flags values */ +#define GIT_MAP_FILE 0 +#define GIT_MAP_SHARED 1 +#define GIT_MAP_PRIVATE 2 +#define GIT_MAP_TYPE 0xf +#define GIT_MAP_FIXED 0x10 + +typedef struct { /* memory mapped buffer */ + void *data; /* data bytes */ + size_t len; /* data length */ +#ifdef GIT_WIN32 + HANDLE fmh; /* file mapping handle */ +#endif +} git_map; + +extern int git__mmap(git_map *out, size_t len, int prot, int flags, int fd, off_t offset); +extern int git__munmap(git_map *map); + +#endif /* INCLUDE_map_h__ */ diff --git a/src/odb.c b/src/odb.c index 11fd982b0..bd65f4709 100644 --- a/src/odb.c +++ b/src/odb.c @@ -43,7 +43,7 @@ struct git_pack { /** The .idx file, mapped into memory. */ git_file idx_fd; - gitfo_map idx_map; + git_map idx_map; uint32_t *im_fanout; unsigned char *im_oid; uint32_t *im_crc; diff --git a/src/unix/map.c b/src/unix/map.c new file mode 100644 index 000000000..a41bae0b8 --- /dev/null +++ b/src/unix/map.c @@ -0,0 +1,61 @@ + +#include "map.h" +#include +#include + + +int git__mmap(git_map *out, size_t len, int prot, int flags, int fd, off_t offset) +{ + int mprot = 0; + int mflag = 0; + + assert((out != NULL) && (len > 0)); + + if ((out == NULL) || (len == 0)) { + errno = EINVAL; + return GIT_ERROR; + } + + out->data = NULL; + out->len = 0; + + if (prot & GIT_PROT_WRITE) + mprot = PROT_WRITE; + else if (prot & GIT_PROT_READ) + mprot = PROT_READ; + else { + errno = EINVAL; + return GIT_ERROR; + } + + if ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED) + mflag = MAP_SHARED; + else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE) + mflag = MAP_PRIVATE; + + if (flags & GIT_MAP_FIXED) { + errno = EINVAL; + return GIT_ERROR; + } + + out->data = mmap(NULL, len, mprot, mflag, fd, offset); + if (!out->data || out->data == MAP_FAILED) + return git_os_error(); + out->len = len; + + return GIT_SUCCESS; +} + +int git__munmap(git_map *map) +{ + assert(map != NULL); + + if (!map) + return GIT_ERROR; + + munmap(map->data, map->len); + + return GIT_SUCCESS; +} + + diff --git a/src/win32/map.c b/src/win32/map.c new file mode 100644 index 000000000..7d685c722 --- /dev/null +++ b/src/win32/map.c @@ -0,0 +1,125 @@ + +#include "map.h" +#include + + +static DWORD get_page_size(void) +{ + static DWORD page_size; + SYSTEM_INFO sys; + + if (!page_size) { + GetSystemInfo(&sys); + page_size = sys.dwAllocationGranularity; + } + + return page_size; +} + +int git__mmap(git_map *out, size_t len, int prot, int flags, int fd, off_t offset) +{ + HANDLE fh = (HANDLE)_get_osfhandle(fd); + DWORD page_size = get_page_size(); + DWORD fmap_prot = 0; + DWORD view_prot = 0; + DWORD off_low = 0; + DWORD off_hi = 0; + off_t page_start; + off_t page_offset; + + assert((out != NULL) && (len > 0)); + + if ((out == NULL) || (len == 0)) { + errno = EINVAL; + return GIT_ERROR; + } + + out->data = NULL; + out->len = 0; + out->fmh = NULL; + + if (fh == INVALID_HANDLE_VALUE) { + errno = EBADF; + return GIT_ERROR; + } + + if (prot & GIT_PROT_WRITE) + fmap_prot |= PAGE_READWRITE; + else if (prot & GIT_PROT_READ) + fmap_prot |= PAGE_READONLY; + else { + errno = EINVAL; + return GIT_ERROR; + } + + if (prot & GIT_PROT_WRITE) + view_prot |= FILE_MAP_WRITE; + if (prot & GIT_PROT_READ) + view_prot |= FILE_MAP_READ; + + if (flags & GIT_MAP_FIXED) { + errno = EINVAL; + return GIT_ERROR; + } + + page_start = (offset / page_size) * page_size; + page_offset = offset - page_start; + + if (page_offset != 0) { /* offset must be multiple of page size */ + errno = EINVAL; + return GIT_ERROR; + } + + out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL); + if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) { + /* errno = ? */ + out->fmh = NULL; + return GIT_ERROR; + } + + off_low = (DWORD)(page_start); + if (sizeof(off_t) > 4) + off_hi = (DWORD)(page_start >> 32); + out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len); + if (!out->data) { + /* errno = ? */ + CloseHandle(out->fmh); + out->fmh = NULL; + return GIT_ERROR; + } + out->len = len; + + return GIT_SUCCESS; +} + +int git__munmap(git_map *map) +{ + assert(map != NULL); + + if (!map) + return GIT_ERROR; + + if (map->data) { + if (!UnmapViewOfFile(map->data)) { + /* errno = ? */ + CloseHandle(map->fmh); + map->data = NULL; + map->fmh = NULL; + return GIT_ERROR; + } + map->data = NULL; + } + + if (map->fmh) { + if (!CloseHandle(map->fmh)) { + /* errno = ? */ + map->fmh = NULL; + return GIT_ERROR; + } + map->fmh = NULL; + } + + return GIT_SUCCESS; +} + +