1 /*
2  * Copyright (C) the libgit2 contributors. All rights reserved.
3  *
4  * This file is part of libgit2, distributed under the GNU GPL v2 with
5  * a Linking Exception. For full terms see the included COPYING file.
6  */
7 
8 #include "common.h"
9 
10 #include "map.h"
11 #include <errno.h>
12 
13 #ifndef NO_MMAP
14 
get_page_size(void)15 static DWORD get_page_size(void)
16 {
17 	static DWORD page_size;
18 	SYSTEM_INFO sys;
19 
20 	if (!page_size) {
21 		GetSystemInfo(&sys);
22 		page_size = sys.dwPageSize;
23 	}
24 
25 	return page_size;
26 }
27 
get_allocation_granularity(void)28 static DWORD get_allocation_granularity(void)
29 {
30 	static DWORD granularity;
31 	SYSTEM_INFO sys;
32 
33 	if (!granularity) {
34 		GetSystemInfo(&sys);
35 		granularity = sys.dwAllocationGranularity;
36 	}
37 
38 	return granularity;
39 }
40 
git__page_size(size_t * page_size)41 int git__page_size(size_t *page_size)
42 {
43 	*page_size = get_page_size();
44 	return 0;
45 }
46 
git__mmap_alignment(size_t * page_size)47 int git__mmap_alignment(size_t *page_size)
48 {
49 	*page_size = get_allocation_granularity();
50 	return 0;
51 }
52 
p_mmap(git_map * out,size_t len,int prot,int flags,int fd,off64_t offset)53 int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, off64_t offset)
54 {
55 	HANDLE fh = (HANDLE)_get_osfhandle(fd);
56 	DWORD alignment = get_allocation_granularity();
57 	DWORD fmap_prot = 0;
58 	DWORD view_prot = 0;
59 	DWORD off_low = 0;
60 	DWORD off_hi = 0;
61 	off64_t page_start;
62 	off64_t page_offset;
63 
64 	GIT_MMAP_VALIDATE(out, len, prot, flags);
65 
66 	out->data = NULL;
67 	out->len = 0;
68 	out->fmh = NULL;
69 
70 	if (fh == INVALID_HANDLE_VALUE) {
71 		errno = EBADF;
72 		git_error_set(GIT_ERROR_OS, "failed to mmap. Invalid handle value");
73 		return -1;
74 	}
75 
76 	if (prot & GIT_PROT_WRITE)
77 		fmap_prot |= PAGE_READWRITE;
78 	else if (prot & GIT_PROT_READ)
79 		fmap_prot |= PAGE_READONLY;
80 
81 	if (prot & GIT_PROT_WRITE)
82 		view_prot |= FILE_MAP_WRITE;
83 	if (prot & GIT_PROT_READ)
84 		view_prot |= FILE_MAP_READ;
85 
86 	page_start = (offset / alignment) * alignment;
87 	page_offset = offset - page_start;
88 
89 	if (page_offset != 0) { /* offset must be multiple of the allocation granularity */
90 		errno = EINVAL;
91 		git_error_set(GIT_ERROR_OS, "failed to mmap. Offset must be multiple of allocation granularity");
92 		return -1;
93 	}
94 
95 	out->fmh = CreateFileMapping(fh, NULL, fmap_prot, 0, 0, NULL);
96 	if (!out->fmh || out->fmh == INVALID_HANDLE_VALUE) {
97 		git_error_set(GIT_ERROR_OS, "failed to mmap. Invalid handle value");
98 		out->fmh = NULL;
99 		return -1;
100 	}
101 
102 	off_low = (DWORD)(page_start);
103 	off_hi = (DWORD)(page_start >> 32);
104 	out->data = MapViewOfFile(out->fmh, view_prot, off_hi, off_low, len);
105 	if (!out->data) {
106 		git_error_set(GIT_ERROR_OS, "failed to mmap. No data written");
107 		CloseHandle(out->fmh);
108 		out->fmh = NULL;
109 		return -1;
110 	}
111 	out->len = len;
112 
113 	return 0;
114 }
115 
p_munmap(git_map * map)116 int p_munmap(git_map *map)
117 {
118 	int error = 0;
119 
120 	GIT_ASSERT_ARG(map);
121 
122 	if (map->data) {
123 		if (!UnmapViewOfFile(map->data)) {
124 			git_error_set(GIT_ERROR_OS, "failed to munmap. Could not unmap view of file");
125 			error = -1;
126 		}
127 		map->data = NULL;
128 	}
129 
130 	if (map->fmh) {
131 		if (!CloseHandle(map->fmh)) {
132 			git_error_set(GIT_ERROR_OS, "failed to munmap. Could not close handle");
133 			error = -1;
134 		}
135 		map->fmh = NULL;
136 	}
137 
138 	return error;
139 }
140 
141 #endif
142