X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fshared%2Ffileio.c;h=f10126954b2d4d2b6a53c52cb0eb65e77f385a5c;hp=733b3203880b83bbd8b555de78f0a7c855bea323;hb=4de33e7f3238a6fe616e61139ab87e221572e5e5;hpb=7ff7394d9e4e9189c30fd018235e6b1728c6f2d0 diff --git a/src/shared/fileio.c b/src/shared/fileio.c index 733b32038..f10126954 100644 --- a/src/shared/fileio.c +++ b/src/shared/fileio.c @@ -20,6 +20,7 @@ ***/ #include +#include #include "fileio.h" #include "util.h" #include "strv.h" @@ -117,6 +118,77 @@ int read_one_line_file(const char *fn, char **line) { return 0; } +ssize_t sendfile_full(int out_fd, const char *fn) { + _cleanup_fclose_ FILE *f; + struct stat st; + int r; + ssize_t s; + + size_t n, l; + _cleanup_free_ char *buf = NULL; + + assert(out_fd > 0); + assert(fn); + + f = fopen(fn, "re"); + if (!f) + return -errno; + + r = fstat(fileno(f), &st); + if (r < 0) + return -errno; + + s = sendfile(out_fd, fileno(f), NULL, st.st_size); + if (s < 0) + if (errno == EINVAL || errno == ENOSYS) { + /* continue below */ + } else + return -errno; + else + return s; + + /* sendfile() failed, fall back to read/write */ + + /* Safety check */ + if (st.st_size > 4*1024*1024) + return -E2BIG; + + n = st.st_size > 0 ? st.st_size : LINE_MAX; + l = 0; + + while (true) { + char *t; + size_t k; + + t = realloc(buf, n); + if (!t) + return -ENOMEM; + + buf = t; + k = fread(buf + l, 1, n - l, f); + + if (k <= 0) { + if (ferror(f)) + return -errno; + + break; + } + + l += k; + n *= 2; + + /* Safety check */ + if (n > 4*1024*1024) + return -E2BIG; + } + + r = write(out_fd, buf, l); + if (r < 0) + return -errno; + + return (ssize_t) l; +} + int read_full_file(const char *fn, char **contents, size_t *size) { _cleanup_fclose_ FILE *f = NULL; size_t n, l; @@ -168,7 +240,7 @@ int read_full_file(const char *fn, char **contents, size_t *size) { buf[l] = 0; *contents = buf; - buf = NULL; + buf = NULL; /* do not free */ if (size) *size = l; @@ -462,35 +534,42 @@ fail: static int parse_env_file_push(const char *filename, unsigned line, const char *key, char *value, void *userdata) { - assert(utf8_is_valid(key)); - if (value && !utf8_is_valid(value)) - /* FIXME: filter UTF-8 */ - log_error("%s:%u: invalid UTF-8 for key %s: '%s', ignoring.", - filename, line, key, value); - else { - const char *k; - va_list* ap = (va_list*) userdata; - va_list aq; + const char *k; + va_list aq, *ap = userdata; + + if (!utf8_is_valid(key)) { + _cleanup_free_ char *p = utf8_escape_invalid(key); - va_copy(aq, *ap); + log_error("%s:%u: invalid UTF-8 in key '%s', ignoring.", + filename, line, p); + return -EINVAL; + } - while ((k = va_arg(aq, const char *))) { - char **v; + if (value && !utf8_is_valid(value)) { + _cleanup_free_ char *p = utf8_escape_invalid(value); - v = va_arg(aq, char **); + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", + filename, line, key, p); + return -EINVAL; + } - if (streq(key, k)) { - va_end(aq); - free(*v); - *v = value; - return 1; - } - } + va_copy(aq, *ap); + + while ((k = va_arg(aq, const char *))) { + char **v; - va_end(aq); + v = va_arg(aq, char **); + + if (streq(key, k)) { + va_end(aq); + free(*v); + *v = value; + return 1; + } } + va_end(aq); free(value); return 0; } @@ -514,28 +593,34 @@ int parse_env_file( static int load_env_file_push(const char *filename, unsigned line, const char *key, char *value, void *userdata) { - assert(utf8_is_valid(key)); + char ***m = userdata; + char *p; + int r; - if (value && !utf8_is_valid(value)) - /* FIXME: filter UTF-8 */ - log_error("%s:%u: invalid UTF-8 for key %s: '%s', ignoring.", - filename, line, key, value); - else { - char ***m = userdata; - char *p; - int r; + if (!utf8_is_valid(key)) { + _cleanup_free_ char *t = utf8_escape_invalid(key); - p = strjoin(key, "=", strempty(value), NULL); - if (!p) - return -ENOMEM; + log_error("%s:%u: invalid UTF-8 for key '%s', ignoring.", + filename, line, t); + return -EINVAL; + } - r = strv_push(m, p); - if (r < 0) { - free(p); - return r; - } + if (value && !utf8_is_valid(value)) { + _cleanup_free_ char *t = utf8_escape_invalid(value); + + log_error("%s:%u: invalid UTF-8 value for key %s: '%s', ignoring.", + filename, line, key, t); + return -EINVAL; } + p = strjoin(key, "=", strempty(value), NULL); + if (!p) + return -ENOMEM; + + r = strv_consume(m, p); + if (r < 0) + return r; + free(value); return 0; }