* for more details.
*/
-
#include "test_suite.h"
+#include <unistd.h>
+
#include <utils/chunk.h>
/*******************************************************************************
END_TEST
/*******************************************************************************
+ * test for chunk_map and friends
+ */
+
+START_TEST(test_chunk_map)
+{
+ chunk_t *map, contents = chunk_from_chars(0x01,0x02,0x03,0x04,0x05);
+ char *path = "/tmp/strongswan-chunk-map-test";
+
+ ck_assert(chunk_write(contents, path, "chunk_map", 022, TRUE));
+
+ /* read */
+ map = chunk_map(path, FALSE);
+ ck_assert(map != NULL);
+ ck_assert_msg(chunk_equals(*map, contents), "%B", map);
+ /* altering mapped chunk should not hurt */
+ *map = chunk_empty;
+ ck_assert(chunk_unmap(map));
+
+ /* write */
+ map = chunk_map(path, TRUE);
+ ck_assert(map != NULL);
+ ck_assert_msg(chunk_equals(*map, contents), "%B", map);
+ map->ptr[0] = 0x06;
+ ck_assert(chunk_unmap(map));
+
+ /* verify write */
+ contents.ptr[0] = 0x06;
+ map = chunk_map(path, FALSE);
+ ck_assert(map != NULL);
+ ck_assert_msg(chunk_equals(*map, contents), "%B", map);
+ ck_assert(chunk_unmap(map));
+
+ unlink(path);
+}
+END_TEST
+
+/*******************************************************************************
* printf_hook tests
*/
tcase_add_test(tc, test_chunk_hash_static);
suite_add_tcase(s, tc);
+ tc = tcase_create("chunk_map");
+ tcase_add_test(tc, test_chunk_map);
+ suite_add_tcase(s, tc);
+
tc = tcase_create("printf_hook");
tcase_add_loop_test(tc, test_printf_hook_hash, 0, countof(printf_hook_data));
tcase_add_loop_test(tc, test_printf_hook_plus, 0, countof(printf_hook_data));
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
return chunk_clone(chunk_create(buf, total));
}
+/**
+ * Implementation for mmap()ed chunks
+ */
+typedef struct {
+ /* public chunk interface */
+ chunk_t public;
+ /* FD of open file */
+ int fd;
+ /* mmap() address */
+ void *map;
+ /* size of map */
+ size_t len;
+} mmaped_chunk_t;
+
+/**
+ * See header.
+ */
+chunk_t *chunk_map(char *path, bool wr)
+{
+ mmaped_chunk_t *chunk;
+ struct stat sb;
+ int tmp;
+
+ INIT(chunk,
+ .fd = open(path, wr ? O_RDWR : O_RDONLY),
+ );
+
+ if (chunk->fd == -1)
+ {
+ free(chunk);
+ return NULL;
+ }
+ if (fstat(chunk->fd, &sb) == -1)
+ {
+ tmp = errno;
+ chunk_unmap(&chunk->public);
+ errno = tmp;
+ return NULL;
+ }
+ chunk->len = sb.st_size;
+ /* map non-empty files only, as mmap() complains otherwise */
+ if (chunk->len)
+ {
+ /* in read-only mode, we allow writes, but don't sync to disk */
+ chunk->map = mmap(NULL, chunk->len, PROT_READ | PROT_WRITE,
+ wr ? MAP_SHARED : MAP_PRIVATE, chunk->fd, 0);
+ if (chunk->map == MAP_FAILED)
+ {
+ tmp = errno;
+ chunk_unmap(&chunk->public);
+ errno = tmp;
+ return NULL;
+ }
+ }
+ chunk->public = chunk_create(chunk->map, chunk->len);
+ return &chunk->public;
+}
+
+/**
+ * See header.
+ */
+bool chunk_unmap(chunk_t *public)
+{
+ mmaped_chunk_t *chunk;
+ bool ret = FALSE;
+ int tmp = 0;
+
+ chunk = (mmaped_chunk_t*)public;
+ if (chunk->map && chunk->map != MAP_FAILED)
+ {
+ ret = munmap(chunk->map, chunk->len) == 0;
+ tmp = errno;
+ }
+ close(chunk->fd);
+ free(chunk);
+ errno = tmp;
+
+ return ret;
+}
/** hex conversion digits */
static char hexdig_upper[] = "0123456789ABCDEF";
chunk_t chunk_from_fd(int fd);
/**
+ * mmap() a file to a chunk
+ *
+ * The returned chunk structure is allocated from heap, but it must be freed
+ * through chunk_unmap(). A user may alter the chunk ptr or len, but must pass
+ * the chunk pointer returned from chunk_map() to chunk_unmap() after use.
+ *
+ * On error, errno is set appropriately.
+ *
+ * @param path path of file to map
+ * @param wr TRUE to sync writes to disk
+ * @return mapped chunk, NULL on error
+ */
+chunk_t *chunk_map(char *path, bool wr);
+
+/**
+ * munmap() a chunk previously mapped with chunk_map()
+ *
+ * When unmapping a writeable map, the return value should be checked to
+ * ensure changes landed on disk.
+ *
+ * @param chunk pointer returned from chunk_map()
+ * @return TRUE of changes written back to file
+ */
+bool chunk_unmap(chunk_t *chunk);
+
+/**
* Convert a chunk of data to hex encoding.
*
* The resulting string is '\\0' terminated, but the chunk does not include