From ae76545a0094114ef29dba52df97e69ab28b3dbc Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw@gnome.org>
Date: Sun, 3 Mar 2013 09:50:44 +0100
Subject: Abstract mmap() into a compat API

The Win32 for mmap() is very different from Unix, so abstract
this into our own p11_mmap_xxx() functions.
---
 common/compat.c          | 158 +++++++++++++++++++++++++++++++++++++----------
 common/compat.h          |  16 +++++
 common/tests/frob-cert.c |  35 ++++-------
 tools/tests/test.c       |   2 +
 trust/parser.c           |  28 +++------
 5 files changed, 160 insertions(+), 79 deletions(-)

diff --git a/common/compat.c b/common/compat.c
index 33e608f..af28e1d 100644
--- a/common/compat.c
+++ b/common/compat.c
@@ -175,6 +175,10 @@ basename (const char *name)
 #endif /* HAVE_BASENAME */
 
 #ifdef OS_UNIX
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 void
 p11_mutex_init (p11_mutex_t *mutex)
@@ -196,6 +200,57 @@ p11_dl_error (void)
 	return msg ? strdup (msg) : NULL;
 }
 
+struct _p11_mmap {
+	int fd;
+	void *data;
+	size_t size;
+};
+
+p11_mmap *
+p11_mmap_open (const char *path,
+               void **data,
+               size_t *size)
+{
+	struct stat sb;
+	p11_mmap *map;
+
+	map = calloc (1, sizeof (p11_mmap));
+	if (map == NULL)
+		return NULL;
+
+	map->fd = open (path, O_RDONLY);
+	if (map->fd == -1) {
+		free (map);
+		return NULL;
+	}
+
+	if (fstat (map->fd, &sb) < 0) {
+		close (map->fd);
+		free (map);
+		return NULL;
+	}
+
+	map->size = sb.st_size;
+	map->data = mmap (NULL, map->size, PROT_READ, MAP_PRIVATE, map->fd, 0);
+	if (data == NULL) {
+		close (map->fd);
+		free (map);
+		return NULL;
+	}
+
+	*data = map->data;
+	*size = map->size;
+	return map;
+}
+
+void
+p11_mmap_close (p11_mmap *map)
+{
+	munmap (map->data, map->size);
+	close (map->fd);
+	free (map);
+}
+
 #endif /* OS_UNIX */
 
 #ifdef OS_WIN32
@@ -246,43 +301,78 @@ p11_thread_join (p11_thread_t thread)
 	return 0;
 }
 
-#endif /* OS_WIN32 */
+struct _p11_mmap {
+	HANDLE file;
+	HANDLE mapping;
+	void *data;
+};
 
-#ifndef HAVE_STRNSTR
+p11_mmap *
+p11_mmap_open (const char *path,
+               void **data,
+               size_t *size)
+{
+	HANDLE mapping;
+	LARGE_INTEGER large;
+	DWORD errn;
+	p11_mmap *map;
 
-/*-
- * Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
- * Copyright (c) 1990, 1993
- *      The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Chris Torek.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 4. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
+	map = calloc (1, sizeof (p11_mmap));
+	if (map == NULL)
+		return NULL;
+
+	map->file  = CreateFile (path, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
+	if (map->file == INVALID_HANDLE_VALUE) {
+		errn = GetLastError ();
+		free (map);
+		SetLastError (errn);
+		return NULL;
+	}
 
+	if (!GetFileSizeEx (map->file, &large)) {
+		errn = GetLastError ();
+		CloseHandle (map->file);
+		free (map);
+		SetLastError (errn);
+		return NULL;
+	}
+
+	mapping = CreateFileMapping (map->file, NULL, PAGE_READONLY, 0, 0, NULL);
+	if (!mapping) {
+		errn = GetLastError ();
+		CloseHandle (map->file);
+		free (map);
+		SetLastError (errn);
+		return NULL;
+	}
+
+	map->data = MapViewOfFile (mapping, FILE_MAP_READ, 0, 0, large.QuadPart);
+	CloseHandle (mapping);
+
+	if (map->data == NULL) {
+		errn = GetLastError ();
+		CloseHandle (map->file);
+		free (map);
+		SetLastError (errn);
+		return NULL;
+	}
+
+	*data = map->data;
+	*size = large.QuadPart;
+	return map;
+}
+
+void
+p11_mmap_close (p11_mmap *map)
+{
+	UnmapViewOfFile (map->data);
+	CloseHandle (map->file);
+	free (map);
+}
+
+#endif /* OS_WIN32 */
+
+#ifndef HAVE_STRNSTR
 #include <string.h>
 
 /*
diff --git a/common/compat.h b/common/compat.h
index 1b74a35..ad80ca5 100644
--- a/common/compat.h
+++ b/common/compat.h
@@ -133,6 +133,14 @@ char *    p11_dl_error       (void);
 #define p11_sleep_ms(ms) \
 	(Sleep (ms))
 
+typedef struct _p11_mmap p11_mmap;
+
+p11_mmap *  p11_mmap_open   (const char *path,
+                             void **data,
+                             size_t *size);
+
+void        p11_mmap_close  (p11_mmap *map);
+
 #endif /* OS_WIN32 */
 
 /* ----------------------------------------------------------------------------
@@ -186,6 +194,14 @@ char * p11_dl_error (void);
 	nanosleep (&_ts, NULL); \
 	} while(0)
 
+typedef struct _p11_mmap p11_mmap;
+
+p11_mmap *  p11_mmap_open   (const char *path,
+                             void **data,
+                             size_t *size);
+
+void        p11_mmap_close  (p11_mmap *map);
+
 #endif /* OS_UNIX */
 
 #ifdef	HAVE_ERRNO_H
diff --git a/common/tests/frob-cert.c b/common/tests/frob-cert.c
index f8ad392..71018bd 100644
--- a/common/tests/frob-cert.c
+++ b/common/tests/frob-cert.c
@@ -37,7 +37,6 @@
 
 #include <libtasn1.h>
 
-#include <sys/mman.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
@@ -86,12 +85,12 @@ main (int argc,
 	char message[ASN1_MAX_ERROR_DESCRIPTION_SIZE] = { 0, };
 	node_asn *definitions = NULL;
 	node_asn *cert = NULL;
-	unsigned char *data;
-	struct stat sb;
+	p11_mmap *map;
+	void *data;
+	size_t size;
 	int start, end;
 	ssize_t len;
 	int ret;
-	int fd;
 
 	if (argc != 4) {
 		fprintf (stderr, "usage: frob-cert struct field filename\n");
@@ -107,38 +106,26 @@ main (int argc,
 	ret = asn1_create_element (definitions, argv[1], &cert);
 	err_if_fail (ret, "Certificate");
 
-	fd = open (argv[3], O_RDONLY);
-	if (fd == -1) {
+	map = p11_mmap_open (argv[3], &data, &size);
+	if (map == NULL) {
 		fprintf (stderr, "couldn't open file: %s\n", argv[3]);
 		return 1;
 	}
 
-	if (fstat (fd, &sb) < 0) {
-		fprintf (stderr, "couldn't stat file: %s\n", argv[3]);
-		return 1;
-	}
-
-	data = mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-	if (data == NULL) {
-		fprintf (stderr, "couldn't map file: %s\n", argv[3]);
-		return 1;
-	}
-
-	ret = asn1_der_decoding (&cert, data, sb.st_size, message);
+	ret = asn1_der_decoding (&cert, data, size, message);
 	err_if_fail (ret, message);
 
-	ret = asn1_der_decoding_startEnd (cert, data, sb.st_size, argv[2], &start, &end);
+	ret = asn1_der_decoding_startEnd (cert, data, size, argv[2], &start, &end);
 	err_if_fail (ret, "asn1_der_decoding_startEnd");
 
-	len = tlv_length (data + start, sb.st_size - start);
+	len = tlv_length ((unsigned char *)data + start, size - start);
 	assert (len >= 0);
 
-	fprintf (stderr, "%lu %d %d %ld\n", sb.st_size, start, end, len);
-	fwrite (data + start, 1, len, stdout);
+	fprintf (stderr, "%lu %d %d %ld\n", (unsigned long)size, start, end, (long)len);
+	fwrite ((unsigned char *)data + start, 1, len, stdout);
 	fflush (stdout);
 
-	munmap (data, sb.st_size);
-	close (fd);
+	p11_mmap_close (map);
 
 	asn1_delete_structure (&cert);
 	asn1_delete_structure (&definitions);
diff --git a/tools/tests/test.c b/tools/tests/test.c
index ecc0410..c445099 100644
--- a/tools/tests/test.c
+++ b/tools/tests/test.c
@@ -38,6 +38,8 @@
 #include "debug.h"
 #include "test.h"
 
+#include <sys/stat.h>
+
 #include <assert.h>
 #include <dirent.h>
 #include <fcntl.h>
diff --git a/trust/parser.c b/trust/parser.c
index 6229d09..3448f40 100644
--- a/trust/parser.c
+++ b/trust/parser.c
@@ -52,7 +52,6 @@
 
 #include <libtasn1.h>
 
-#include <sys/mman.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
@@ -1043,33 +1042,20 @@ p11_parse_file (p11_parser *parser,
                 p11_parser_sink sink,
                 void *sink_data)
 {
+	p11_mmap *map;
 	void *data;
-	struct stat sb;
-	int fd;
+	size_t size;
 	int ret;
 
-	fd = open (filename, O_RDONLY);
-	if (fd == -1) {
-		p11_message ("couldn't open file: %s: %s", filename, strerror (errno));
+	map = p11_mmap_open (filename, &data, &size);
+	if (map == NULL) {
+		p11_message ("couldn't open and map file: %s: %s", filename, strerror (errno));
 		return P11_PARSE_FAILURE;
 	}
 
-	if (fstat (fd, &sb) < 0) {
-		p11_message ("couldn't stat file: %s: %s", filename, strerror (errno));
-		return P11_PARSE_FAILURE;
-	}
-
-	data = mmap (NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-	if (data == NULL) {
-		p11_message ("couldn't map file: %s: %s", filename, strerror (errno));
-		return P11_PARSE_FAILURE;
-	}
-
-	ret = p11_parse_memory (parser, filename, flags, data, sb.st_size, sink, sink_data);
-
-	munmap (data, sb.st_size);
-	close (fd);
+	ret = p11_parse_memory (parser, filename, flags, data, size, sink, sink_data);
 
+	p11_mmap_close (map);
 	return ret;
 }
 
-- 
cgit v1.1