From: Martin Willi Date: Thu, 21 Nov 2013 10:29:46 +0000 (+0100) Subject: chunk: Add functions to map file contents to a chunk X-Git-Tag: 5.1.2rc1~42^2~10 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=595b6d9a828538072dcf65c276b848a02698fdfe;p=thirdparty%2Fstrongswan.git chunk: Add functions to map file contents to a chunk --- diff --git a/src/libstrongswan/tests/suites/test_chunk.c b/src/libstrongswan/tests/suites/test_chunk.c index 1c0bac10e7..7971f5ca80 100644 --- a/src/libstrongswan/tests/suites/test_chunk.c +++ b/src/libstrongswan/tests/suites/test_chunk.c @@ -14,9 +14,10 @@ * for more details. */ - #include "test_suite.h" +#include + #include /******************************************************************************* @@ -774,6 +775,43 @@ START_TEST(test_chunk_hash_static) } 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 */ @@ -891,6 +929,10 @@ Suite *chunk_suite_create() 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)); diff --git a/src/libstrongswan/utils/chunk.c b/src/libstrongswan/utils/chunk.c index 644b8060fe..5c00c5b322 100644 --- a/src/libstrongswan/utils/chunk.c +++ b/src/libstrongswan/utils/chunk.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -275,6 +276,85 @@ chunk_t chunk_from_fd(int fd) 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"; diff --git a/src/libstrongswan/utils/chunk.h b/src/libstrongswan/utils/chunk.h index 80b6237ec5..92a96ffbaa 100644 --- a/src/libstrongswan/utils/chunk.h +++ b/src/libstrongswan/utils/chunk.h @@ -107,6 +107,32 @@ bool chunk_write(chunk_t chunk, char *path, char *label, mode_t mask, bool force */ 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. *