p11_mmap_open (const char *path,
               struct stat *sb,
               void **data,
               size_t *size)
{
	struct stat stb;
	p11_mmap *map;

	map = calloc (1, sizeof (p11_mmap));
	if (map == NULL)
		return NULL;

	map->fd = open (path, O_RDONLY | O_CLOEXEC);
	if (map->fd == -1) {
		free (map);
		return NULL;
	}

	if (sb == NULL) {
		sb = &stb;
		if (fstat (map->fd, &stb) < 0) {
			close (map->fd);
			free (map);
			return NULL;
		}
	}

	/* Workaround for broken ZFS on Linux */
	if (S_ISDIR (sb->st_mode)) {
		errno = EISDIR;
		close (map->fd);
		free (map);
		return NULL;
	}

	if (sb->st_size == 0) {
		*data = "";
		*size = 0;
		return map;
	}

	map->size = sb->st_size;
	map->data = mmap (NULL, map->size, PROT_READ, MAP_PRIVATE, map->fd, 0);
	if (map->data == MAP_FAILED) {
		close (map->fd);
		free (map);
		return NULL;
	}

	*data = map->data;
	*size = map->size;
	return map;
}
p11_mmap_open (const char *path,
               struct stat *sb,
               void **data,
               size_t *size)
{
	struct stat stb;
	p11_mmap *map;

	map = calloc (1, sizeof (p11_mmap));
	if (map == NULL)
		return NULL;

	map->fd = open (path, O_RDONLY | O_CLOEXEC);
	if (map->fd == -1) {
		free (map);
		return NULL;
	}

	if (sb == NULL) {
		sb = &stb;
		if (fstat (map->fd, &stb) < 0) {
			close (map->fd);
			free (map);
			return NULL;
		}
	}

	 
	if (S_ISDIR (sb->st_mode)) {
		errno = EISDIR;
		close (map->fd);
		free (map);
		return NULL;
	}

	if (sb->st_size == 0) {
		*data = "";
		*size = 0;
		return map;
	}

	map->size = sb->st_size;
	map->data = mmap (NULL, map->size, PROT_READ, MAP_PRIVATE, map->fd, 0);
	if (map->data == MAP_FAILED) {
		close (map->fd);
		free (map);
		return NULL;
	}

	*data = map->data;
	*size = map->size;
	return map;
}