Commit 79ca2edc by Ramsay Jones Committed by Shawn O. Pearce

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 <ramsay@ramsay1.demon.co.uk>
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
parent 7a6cf815
......@@ -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 = <openssl/sha.h>
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
......
......@@ -23,14 +23,15 @@
#ifdef GIT_WIN32
# include <io.h>
# include <winsock2.h>
# include <windows.h>
#define snprintf _snprintf
typedef int ssize_t;
#else
# include <unistd.h>
# include <sys/mman.h>
# include <arpa/inet.h>
#endif
......
......@@ -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 */
......
......@@ -10,6 +10,7 @@
#define _FILE_OFFSET_BITS 64
#include "common.h"
#include "map.h"
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
......@@ -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).
......
#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__ */
......@@ -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;
......
#include "map.h"
#include <sys/mman.h>
#include <errno.h>
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;
}
#include "map.h"
#include <errno.h>
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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment