summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorStef Walter <stef@thewalter.net>2013-08-26 14:48:59 +0200
committerStef Walter <stef@thewalter.net>2013-08-28 10:59:10 +0200
commitcdad5bceee79afbf8b3440b39c72890d2e67448d (patch)
treef07a8a45fd549a70277e4df9ae783fb996198c7d /common
parente1042e93488f2b38abeea58b65440111df69afdc (diff)
Avoid multiple stat() calls for same file
As a side effect we can also not use the dirent.d_type field https://bugs.freedesktop.org/show_bug.cgi?id=68525
Diffstat (limited to 'common')
-rw-r--r--common/compat.c39
-rw-r--r--common/compat.h3
-rw-r--r--common/test.c2
3 files changed, 32 insertions, 12 deletions
diff --git a/common/compat.c b/common/compat.c
index d813236..9aa556a 100644
--- a/common/compat.c
+++ b/common/compat.c
@@ -182,10 +182,11 @@ struct _p11_mmap {
p11_mmap *
p11_mmap_open (const char *path,
+ struct stat *sb,
void **data,
size_t *size)
{
- struct stat sb;
+ struct stat stb;
p11_mmap *map;
map = calloc (1, sizeof (p11_mmap));
@@ -198,13 +199,24 @@ p11_mmap_open (const char *path,
return NULL;
}
- if (fstat (map->fd, &sb) < 0) {
+ 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;
}
- map->size = sb.st_size;
+ map->size = sb->st_size;
map->data = mmap (NULL, map->size, PROT_READ, MAP_PRIVATE, map->fd, 0);
if (map->data == NULL) {
close (map->fd);
@@ -289,6 +301,7 @@ struct _p11_mmap {
p11_mmap *
p11_mmap_open (const char *path,
+ struct stat *sb,
void **data,
size_t *size)
{
@@ -315,14 +328,18 @@ p11_mmap_open (const char *path,
return NULL;
}
- if (!GetFileSizeEx (map->file, &large)) {
- errn = GetLastError ();
- CloseHandle (map->file);
- free (map);
- SetLastError (errn);
- if (errn == ERROR_ACCESS_DENIED)
- errno = EPERM;
- return NULL;
+ if (sb == NULL) {
+ if (!GetFileSizeEx (map->file, &large)) {
+ errn = GetLastError ();
+ CloseHandle (map->file);
+ free (map);
+ SetLastError (errn);
+ if (errn == ERROR_ACCESS_DENIED)
+ errno = EPERM;
+ return NULL;
+ }
+ } else {
+ large.QuadPart = sb->st_size;
}
mapping = CreateFileMapping (map->file, NULL, PAGE_READONLY, 0, 0, NULL);
diff --git a/common/compat.h b/common/compat.h
index b593cf6..d7fe414 100644
--- a/common/compat.h
+++ b/common/compat.h
@@ -38,6 +38,7 @@
#include "config.h"
#include <sys/types.h>
+#include <sys/stat.h>
#ifdef _GNU_SOURCE
#error Make the crap stop. _GNU_SOURCE is completely unportable and breaks all sorts of behavior
@@ -158,6 +159,7 @@ void p11_dl_close (void * dl);
typedef struct _p11_mmap p11_mmap;
p11_mmap * p11_mmap_open (const char *path,
+ struct stat *sb,
void **data,
size_t *size);
@@ -220,6 +222,7 @@ char * p11_dl_error (void);
typedef struct _p11_mmap p11_mmap;
p11_mmap * p11_mmap_open (const char *path,
+ struct stat *sb,
void **data,
size_t *size);
diff --git a/common/test.c b/common/test.c
index daee663..83e9644 100644
--- a/common/test.c
+++ b/common/test.c
@@ -350,7 +350,7 @@ copy_file (const char *input,
ssize_t written;
size_t size;
- mmap = p11_mmap_open (input, (void **)&data, &size);
+ mmap = p11_mmap_open (input, NULL, (void **)&data, &size);
assert (mmap != NULL);
while (size > 0) {