aboutsummaryrefslogtreecommitdiff
path: root/sys/kern/subr_sbuf.c
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2001-06-11 17:05:52 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2001-06-11 17:05:52 +0000
commitb0def2b54805e62cfd2d4bf71236fdb91d7618b9 (patch)
treecc2047d7b2d1136314711a47d5c6025ee1784d50 /sys/kern/subr_sbuf.c
parent21ceb6efa2572847dfcb49302f2d2e2c1fb005a6 (diff)
downloadsrc-b0def2b54805e62cfd2d4bf71236fdb91d7618b9.tar.gz
src-b0def2b54805e62cfd2d4bf71236fdb91d7618b9.zip
Add sbuf_copyin(). Also add 'b' variants of sbuf_{cat,copyin,cpy}() which
ignore NUL bytes in the source string.
Notes
Notes: svn path=/head/; revision=78077
Diffstat (limited to 'sys/kern/subr_sbuf.c')
-rw-r--r--sys/kern/subr_sbuf.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/sys/kern/subr_sbuf.c b/sys/kern/subr_sbuf.c
index 6de352da4003..0493aefb6e6b 100644
--- a/sys/kern/subr_sbuf.c
+++ b/sys/kern/subr_sbuf.c
@@ -167,6 +167,72 @@ sbuf_setpos(struct sbuf *s, int pos)
}
/*
+ * Append a byte string to an sbuf.
+ */
+int
+sbuf_bcat(struct sbuf *s, const char *str, size_t len)
+{
+ assert_sbuf_integrity(s);
+ assert_sbuf_state(s, 0);
+
+ if (SBUF_HASOVERFLOWED(s))
+ return (-1);
+
+ while (len-- && SBUF_HASROOM(s))
+ s->s_buf[s->s_len++] = *str++;
+ if (len) {
+ SBUF_SETFLAG(s, SBUF_OVERFLOWED);
+ return (-1);
+ }
+ return (0);
+}
+
+#ifdef _KERNEL
+/*
+ * Copy a byte string from userland into an sbuf.
+ */
+int
+sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
+{
+ assert_sbuf_integrity(s);
+ assert_sbuf_state(s, 0);
+
+ if (SBUF_HASOVERFLOWED(s))
+ return (-1);
+
+ if (len == 0)
+ return (0);
+ if (len > (s->s_size - s->s_len - 1))
+ len = s->s_size - s->s_len - 1;
+ switch (copyin(uaddr, s->s_buf + s->s_len, len)) {
+ case ENAMETOOLONG:
+ SBUF_SETFLAG(s, SBUF_OVERFLOWED);
+ /* fall through */
+ case 0:
+ s->s_len += len;
+ break;
+ default:
+ return (-1); /* XXX */
+ }
+
+ return (0);
+}
+#endif
+
+/*
+ * Copy a byte string into an sbuf.
+ */
+int
+sbuf_bcpy(struct sbuf *s, const char *str, size_t len)
+{
+ assert_sbuf_integrity(s);
+ assert_sbuf_state(s, 0);
+
+ sbuf_clear(s);
+ return (sbuf_bcat(s, str, len));
+}
+
+/*
* Append a string to an sbuf.
*/
int
@@ -187,6 +253,38 @@ sbuf_cat(struct sbuf *s, const char *str)
return (0);
}
+#ifdef _KERNEL
+/*
+ * Copy a string from userland into an sbuf.
+ */
+int
+sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
+{
+ size_t done;
+
+ assert_sbuf_integrity(s);
+ assert_sbuf_state(s, 0);
+
+ if (SBUF_HASOVERFLOWED(s))
+ return (-1);
+
+ if (len == 0 || len > (s->s_size - s->s_len - 1))
+ len = s->s_size - s->s_len - 1;
+ switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
+ case ENAMETOOLONG:
+ SBUF_SETFLAG(s, SBUF_OVERFLOWED);
+ /* fall through */
+ case 0:
+ s->s_len += done - 1;
+ break;
+ default:
+ return (-1); /* XXX */
+ }
+
+ return (0);
+}
+#endif
+
/*
* Copy a string into an sbuf.
*/