diff options
Diffstat (limited to 'src/openvpn/buffer.c')
-rw-r--r-- | src/openvpn/buffer.c | 129 |
1 files changed, 112 insertions, 17 deletions
diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c index f9c76b1..b32bc8b 100644 --- a/src/openvpn/buffer.c +++ b/src/openvpn/buffer.c @@ -37,6 +37,8 @@ #include "memdbg.h" +#include <wchar.h> + size_t array_mult_safe(const size_t m1, const size_t m2, const size_t extra) { @@ -44,7 +46,7 @@ array_mult_safe(const size_t m1, const size_t m2, const size_t extra) unsigned long long res = (unsigned long long)m1 * (unsigned long long)m2 + (unsigned long long)extra; if (unlikely(m1 > limit) || unlikely(m2 > limit) || unlikely(extra > limit) || unlikely(res > (unsigned long long)limit)) { - msg(M_FATAL, "attemped allocation of excessively large array"); + msg(M_FATAL, "attempted allocation of excessively large array"); } return (size_t) res; } @@ -179,14 +181,6 @@ buf_assign(struct buffer *dest, const struct buffer *src) return buf_write(dest, BPTR(src), BLEN(src)); } -struct buffer -clear_buf(void) -{ - struct buffer buf; - CLEAR(buf); - return buf; -} - void free_buf(struct buffer *buf) { @@ -197,6 +191,34 @@ free_buf(struct buffer *buf) CLEAR(*buf); } +static void +free_buf_gc(struct buffer *buf, struct gc_arena *gc) +{ + if (gc) + { + struct gc_entry **e = &gc->list; + + while (*e) + { + /* check if this object is the one we want to delete */ + if ((uint8_t *)(*e + 1) == buf->data) + { + struct gc_entry *to_delete = *e; + + /* remove element from linked list and free it */ + *e = (*e)->next; + free(to_delete); + + break; + } + + e = &(*e)->next; + } + } + + CLEAR(*buf); +} + /* * Return a buffer for write that is a subset of another buffer */ @@ -289,6 +311,29 @@ openvpn_snprintf(char *str, size_t size, const char *format, ...) } /* + * openvpn_swprintf() is currently only used by Windows code paths + * and when enabled for all platforms it will currently break older + * OpenBSD versions lacking vswprintf(3) support in their libc. + */ + +#ifdef _WIN32 +bool +openvpn_swprintf(wchar_t *const str, const size_t size, const wchar_t *const format, ...) +{ + va_list arglist; + int len = -1; + if (size > 0) + { + va_start(arglist, format); + len = vswprintf(str, size, format, arglist); + va_end(arglist); + str[size - 1] = L'\0'; + } + return (len >= 0 && len < size); +} +#endif + +/* * write a string to the end of a buffer that was * truncated by buf_printf */ @@ -323,16 +368,33 @@ convert_to_one_line(struct buffer *buf) } } -/* NOTE: requires that string be null terminated */ -void -buf_write_string_file(const struct buffer *buf, const char *filename, int fd) +bool +buffer_write_file(const char *filename, const struct buffer *buf) { - const int len = strlen((char *) BPTR(buf)); - const int size = write(fd, BPTR(buf), len); - if (size != len) + bool ret = false; + int fd = platform_open(filename, O_CREAT | O_TRUNC | O_WRONLY, + S_IRUSR | S_IWUSR); + if (fd == -1) { - msg(M_ERR, "Write error on file '%s'", filename); + msg(M_ERRNO, "Cannot open file '%s' for write", filename); + return false; } + + const int size = write(fd, BPTR(buf), BLEN(buf)); + if (size != BLEN(buf)) + { + msg(M_ERRNO, "Write error on file '%s'", filename); + goto cleanup; + } + + ret = true; +cleanup: + if (close(fd) < 0) + { + msg(M_ERRNO, "Close error on file %s", filename); + ret = false; + } + return ret; } /* @@ -412,7 +474,7 @@ x_gc_freespecial(struct gc_arena *a) } void -gc_addspecial(void *addr, void(free_function)(void *), struct gc_arena *a) +gc_addspecial(void *addr, void (*free_function)(void *), struct gc_arena *a) { ASSERT(a); struct gc_entry_special *e; @@ -1335,3 +1397,36 @@ buffer_list_file(const char *fn, int max_line_len) } return bl; } + +struct buffer +buffer_read_from_file(const char *filename, struct gc_arena *gc) +{ + struct buffer ret = { 0 }; + + platform_stat_t file_stat = {0}; + if (platform_stat(filename, &file_stat) < 0) + { + return ret; + } + + FILE *fp = platform_fopen(filename, "r"); + if (!fp) + { + return ret; + } + + const size_t size = file_stat.st_size; + ret = alloc_buf_gc(size + 1, gc); /* space for trailing \0 */ + ssize_t read_size = fread(BPTR(&ret), 1, size, fp); + if (read_size < 0) + { + free_buf_gc(&ret, gc); + goto cleanup; + } + ASSERT(buf_inc_len(&ret, read_size)); + buf_null_terminate(&ret); + +cleanup: + fclose(fp); + return ret; +} |