summaryrefslogtreecommitdiff
path: root/src/openvpn/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/openvpn/buffer.c')
-rw-r--r--src/openvpn/buffer.c129
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;
+}