From c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 7 Oct 2016 15:10:20 +0200 Subject: Update to FreeBSD head 2016-08-23 Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd. --- freebsd/sys/kern/subr_sbuf.c | 131 +++++++++++++++++++++++++++++-------------- 1 file changed, 88 insertions(+), 43 deletions(-) (limited to 'freebsd/sys/kern/subr_sbuf.c') diff --git a/freebsd/sys/kern/subr_sbuf.c b/freebsd/sys/kern/subr_sbuf.c index e61b0844..73a9b383 100644 --- a/freebsd/sys/kern/subr_sbuf.c +++ b/freebsd/sys/kern/subr_sbuf.c @@ -37,6 +37,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -44,6 +45,7 @@ __FBSDID("$FreeBSD$"); #else /* _KERNEL */ #include #include +#include #include #include #include @@ -54,11 +56,11 @@ __FBSDID("$FreeBSD$"); #ifdef _KERNEL static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); -#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK) +#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK|M_ZERO) #define SBFREE(buf) free(buf, M_SBUF) #else /* _KERNEL */ #define KASSERT(e, m) -#define SBMALLOC(size) malloc(size) +#define SBMALLOC(size) calloc(1, size) #define SBFREE(buf) free(buf) #endif /* _KERNEL */ @@ -72,6 +74,7 @@ static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); #define SBUF_FREESPACE(s) ((s)->s_size - ((s)->s_len + 1)) #define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND) #define SBUF_ISSECTION(s) ((s)->s_flags & SBUF_INSECTION) +#define SBUF_NULINCLUDED(s) ((s)->s_flags & SBUF_INCLUDENUL) /* * Set / clear flags @@ -79,6 +82,7 @@ static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers"); #define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0) #define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0) +#define SBUF_MINSIZE 2 /* Min is 1 byte + nulterm. */ #define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */ #ifdef PAGE_SIZE @@ -102,9 +106,15 @@ _assert_sbuf_integrity(const char *fun, struct sbuf *s) ("%s called with a NULL sbuf pointer", fun)); KASSERT(s->s_buf != NULL, ("%s called with uninitialized or corrupt sbuf", fun)); - KASSERT(s->s_len < s->s_size, - ("wrote past end of sbuf (%jd >= %jd)", - (intmax_t)s->s_len, (intmax_t)s->s_size)); + if (SBUF_ISFINISHED(s) && SBUF_NULINCLUDED(s)) { + KASSERT(s->s_len <= s->s_size, + ("wrote past end of sbuf (%jd >= %jd)", + (intmax_t)s->s_len, (intmax_t)s->s_size)); + } else { + KASSERT(s->s_len < s->s_size, + ("wrote past end of sbuf (%jd >= %jd)", + (intmax_t)s->s_len, (intmax_t)s->s_size)); + } } static void @@ -187,8 +197,9 @@ sbuf_newbuf(struct sbuf *s, char *buf, int length, int flags) s->s_buf = buf; if ((s->s_flags & SBUF_AUTOEXTEND) == 0) { - KASSERT(s->s_size >= 0, - ("attempt to create a too small sbuf")); + KASSERT(s->s_size >= SBUF_MINSIZE, + ("attempt to create an sbuf smaller than %d bytes", + SBUF_MINSIZE)); } if (s->s_buf != NULL) @@ -264,6 +275,28 @@ sbuf_uionew(struct sbuf *s, struct uio *uio, int *error) } #endif +int +sbuf_get_flags(struct sbuf *s) +{ + + return (s->s_flags & SBUF_USRFLAGMSK); +} + +void +sbuf_clear_flags(struct sbuf *s, int flags) +{ + + s->s_flags &= ~(flags & SBUF_USRFLAGMSK); +} + +void +sbuf_set_flags(struct sbuf *s, int flags) +{ + + + s->s_flags |= (flags & SBUF_USRFLAGMSK); +} + /* * Clear an sbuf and reset its position. */ @@ -354,34 +387,51 @@ sbuf_drain(struct sbuf *s) } /* - * Append a byte to an sbuf. This is the core function for appending + * Append bytes to an sbuf. This is the core function for appending * to an sbuf and is the main place that deals with extending the * buffer and marking overflow. */ static void -sbuf_put_byte(struct sbuf *s, int c) +sbuf_put_bytes(struct sbuf *s, const char *buf, size_t len) { + size_t n; assert_sbuf_integrity(s); assert_sbuf_state(s, 0); if (s->s_error != 0) return; - if (SBUF_FREESPACE(s) <= 0) { - /* - * If there is a drain, use it, otherwise extend the - * buffer. - */ - if (s->s_drain_func != NULL) - (void)sbuf_drain(s); - else if (sbuf_extend(s, 1) < 0) - s->s_error = ENOMEM; - if (s->s_error != 0) - return; + while (len > 0) { + if (SBUF_FREESPACE(s) <= 0) { + /* + * If there is a drain, use it, otherwise extend the + * buffer. + */ + if (s->s_drain_func != NULL) + (void)sbuf_drain(s); + else if (sbuf_extend(s, len > INT_MAX ? INT_MAX : len) + < 0) + s->s_error = ENOMEM; + if (s->s_error != 0) + return; + } + n = SBUF_FREESPACE(s); + if (len < n) + n = len; + memcpy(&s->s_buf[s->s_len], buf, n); + s->s_len += n; + if (SBUF_ISSECTION(s)) + s->s_sect_len += n; + len -= n; + buf += n; } - s->s_buf[s->s_len++] = c; - if (SBUF_ISSECTION(s)) - s->s_sect_len++; +} + +static void +sbuf_put_byte(struct sbuf *s, char c) +{ + + sbuf_put_bytes(s, &c, 1); } /* @@ -390,19 +440,10 @@ sbuf_put_byte(struct sbuf *s, int c) int sbuf_bcat(struct sbuf *s, const void *buf, size_t len) { - const char *str = buf; - const char *end = str + len; - - assert_sbuf_integrity(s); - assert_sbuf_state(s, 0); + sbuf_put_bytes(s, buf, len); if (s->s_error != 0) return (-1); - for (; str < end; str++) { - sbuf_put_byte(s, *str); - if (s->s_error != 0) - return (-1); - } return (0); } @@ -456,18 +497,12 @@ sbuf_bcpy(struct sbuf *s, const void *buf, size_t len) int sbuf_cat(struct sbuf *s, const char *str) { + size_t n; - assert_sbuf_integrity(s); - assert_sbuf_state(s, 0); - + n = strlen(str); + sbuf_put_bytes(s, str, n); if (s->s_error != 0) return (-1); - - while (*str != '\0') { - sbuf_put_byte(s, *str++); - if (s->s_error != 0) - return (-1); - } return (0); } @@ -590,6 +625,10 @@ sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap) va_copy(ap_copy, ap); len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1, fmt, ap_copy); + if (len < 0) { + s->s_error = errno; + return (-1); + } va_end(ap_copy); if (SBUF_FREESPACE(s) >= len) @@ -699,11 +738,13 @@ sbuf_finish(struct sbuf *s) assert_sbuf_integrity(s); assert_sbuf_state(s, 0); + s->s_buf[s->s_len] = '\0'; + if (SBUF_NULINCLUDED(s)) + s->s_len++; if (s->s_drain_func != NULL) { while (s->s_len > 0 && s->s_error == 0) s->s_error = sbuf_drain(s); } - s->s_buf[s->s_len] = '\0'; SBUF_SETFLAG(s, SBUF_FINISHED); #ifdef _KERNEL return (s->s_error); @@ -745,6 +786,10 @@ sbuf_len(struct sbuf *s) if (s->s_error != 0) return (-1); + + /* If finished, nulterm is already in len, else add one. */ + if (SBUF_NULINCLUDED(s) && !SBUF_ISFINISHED(s)) + return (s->s_len + 1); return (s->s_len); } -- cgit v1.2.3