return !!SBUF_ISFINISHED(s);
}
-/*!
- * @function sbuf_uionew
- *
- * @brief
- * Create a new sbuf and initialize its buffer with data from the given uio.
- *
- * @param s
- * An optional existing sbuf to initialize, or NULL to allocate a new one.
- *
- * @param uio
- * The uio describing the data to populate the sbuf with.
- *
- * @param error
- * An output parameter to report any error to.
- *
- * @returns
- * The new and/or initialized sbuf, or NULL on error. The error code is
- * reported back via @a error.
- */
-struct sbuf *
-sbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
-{
- int size;
-
- if ((user_size_t)uio_resid(uio) > INT_MAX - 1) {
- *error = EINVAL;
- return NULL;
- }
-
- size = (int)uio_resid(uio);
- s = sbuf_new(s, NULL, size + 1, 0);
- if (s == NULL) {
- *error = ENOMEM;
- return NULL;
- }
-
- *error = uiomove(s->s_buf, size, uio);
- if (*error != 0) {
- sbuf_delete(s);
- return NULL;
- }
-
- s->s_len = size;
- *error = 0;
-
- return s;
-}
-
-/*!
- * @function sbuf_bcopyin
- *
- * @brief
- * Append userland data to an sbuf.
- *
- * @param s
- * The sbuf.
- *
- * @param uaddr
- * The userland address of data to append to the sbuf.
- *
- * @param len
- * The length of the data to copy from userland.
- *
- * @returns
- * 0 on success or -1 on error. Always returns -1 if the sbuf is marked as
- * overflowed.
- */
-int
-sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
-{
- if (SBUF_HASOVERFLOWED(s)) {
- return -1;
- }
-
- if (len == 0) {
- return 0;
- }
-
- if (-1 == sbuf_ensure_capacity(s, len)) {
- SBUF_SETFLAG(s, SBUF_OVERFLOWED);
- return -1;
- }
-
- if (copyin(CAST_USER_ADDR_T(uaddr), &s->s_buf[s->s_len], len) != 0) {
- return -1;
- }
-
- s->s_len += (int)len;
- return 0;
-}
-
-/*!
- * @function sbuf_copyin
- *
- * @brief
- * Append a userland string to an sbuf.
- *
- * @param s
- * The sbuf.
- *
- * @param uaddr
- * The userland address of the string to append to the sbuf.
- *
- * @param len
- * The maximum length of the string to copy. If zero, the current capacity of
- * the sbuf is used.
- *
- * @returns
- * The number of bytes copied or -1 if an error occurred. Always returns -1 if
- * the sbuf is marked as overflowed.
- */
-int
-sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
-{
- size_t done;
-
- if (SBUF_HASOVERFLOWED(s)) {
- return -1;
- }
-
- if (len == 0) {
- len = sbuf_capacity(s);
- } else if (-1 == sbuf_ensure_capacity(s, len)) {
- return -1;
- }
-
- switch (copyinstr(CAST_USER_ADDR_T(uaddr), &s->s_buf[s->s_len], len + 1, &done)) {
- case ENAMETOOLONG:
- SBUF_SETFLAG(s, SBUF_OVERFLOWED);
- s->s_len += done;
- return -1;
- case 0:
- s->s_len += done - 1;
- break;
- default:
- return -1;
- }
-
- return (int)done;
-}
-
#if DEBUG || DEVELOPMENT
/*
}
}
- SBUF_TESTING("sbuf_uionew")
- {
- SBUF_SHOULD("reject residuals that are too large")
- {
- struct sbuf *s = NULL;
- uio_t auio = NULL;
- char buf[4];
- int error = 0;
-
- buf[0] = 'A';
- buf[1] = 'B';
- buf[2] = 'C';
- buf[3] = 'D';
-
- auio = uio_create(1, 0, UIO_SYSSPACE, UIO_READ);
- uio_addiov(auio, (user_addr_t)buf, INT_MAX);
-
- s = sbuf_uionew(NULL, auio, &error);
- SBUF_ASSERT_EQ(NULL, s);
- SBUF_ASSERT_EQ(EINVAL, error);
-
- uio_free(auio);
- }
-
- SBUF_SHOULD("initialize using data described by the uio")
- {
- struct sbuf *s = NULL;
- uio_t auio = NULL;
- char buf[4];
- int error = 0;
-
- buf[0] = 'A';
- buf[1] = 'B';
- buf[2] = 'C';
- buf[3] = 'D';
-
- auio = uio_create(1, 0, UIO_SYSSPACE, UIO_WRITE);
- uio_addiov(auio, (user_addr_t)buf, sizeof(buf));
-
- s = sbuf_uionew(NULL, auio, &error);
- SBUF_ASSERT_NE(NULL, s);
- SBUF_ASSERT_EQ(0, error);
- SBUF_ASSERT_EQ(4, s->s_len);
- SBUF_ASSERT_EQ('A', s->s_buf[0]);
- SBUF_ASSERT_EQ('B', s->s_buf[1]);
- SBUF_ASSERT_EQ('C', s->s_buf[2]);
- SBUF_ASSERT_EQ('D', s->s_buf[3]);
-
- sbuf_delete(s);
- uio_free(auio);
- }
-
- SBUF_SHOULD("fail gracefully for bad addresses")
- {
- struct sbuf *s = NULL;
- uio_t auio = NULL;
- int error = 0;
-
- auio = uio_create(1, 0, UIO_USERSPACE, UIO_WRITE);
- uio_addiov(auio, (user_addr_t)0xdeadUL, 123);
-
- s = sbuf_uionew(NULL, auio, &error);
- SBUF_ASSERT_EQ(NULL, s);
- SBUF_ASSERT_NE(0, error);
-
- uio_free(auio);
- }
- }
-
- SBUF_TESTING("sbuf_bcopyin")
- {
- SBUF_SHOULD("succeed when len is zero")
- {
- struct sbuf *s = NULL;
- const void *uptr = (const void *)req->newptr;
-
- s = sbuf_new(NULL, NULL, 16, 0);
- SBUF_ASSERT_EQ(0, sbuf_bcopyin(s, uptr, 0));
- SBUF_ASSERT_EQ(0, s->s_len);
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("succeed in the simple case")
- {
- struct sbuf *s = NULL;
- const void *uptr = (const void *)req->newptr;
- size_t ulen = req->newlen;
-
- s = sbuf_new(NULL, NULL, 16, 0);
- SBUF_ASSERT_EQ(0, sbuf_bcopyin(s, uptr, ulen));
- SBUF_ASSERT_EQ(ulen, (size_t)s->s_len);
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("fail for invalid userland addresses")
- {
- struct sbuf *s = NULL;
- const void *uptr = (const void *)0xdeadUL;
- size_t ulen = req->newlen;
-
- s = sbuf_new(NULL, NULL, 16, 0);
- SBUF_ASSERT_EQ(-1, sbuf_bcopyin(s, uptr, ulen));
- SBUF_ASSERT_EQ(0, s->s_len);
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("fail for kernel addresses")
- {
- struct sbuf *s = NULL;
- const void *uptr = "abcd";
- size_t ulen = 4;
-
- s = sbuf_new(NULL, NULL, 16, 0);
- SBUF_ASSERT_EQ(-1, sbuf_bcopyin(s, uptr, ulen));
- SBUF_ASSERT_EQ(0, s->s_len);
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("fail if we don't have capacity for a fixed-len sbuf")
- {
- struct sbuf *s = NULL;
- const void *uptr = (const void *)req->newptr;
- size_t ulen = req->newlen;
- int len_before;
-
- s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
- SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcde"));
- len_before = s->s_len;
- SBUF_ASSERT_EQ(-1, sbuf_bcopyin(s, uptr, ulen));
- SBUF_ASSERT_EQ(len_before, s->s_len);
- SBUF_ASSERT(SBUF_ISSET(s, SBUF_OVERFLOWED));
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("auto-extend if we don't have capacity for an auto-extend sbuf")
- {
- struct sbuf *s = NULL;
- const void *uptr = (const void *)req->newptr;
- size_t ulen = req->newlen;
- int len_before;
-
- s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
- SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcde"));
- len_before = s->s_len;
- SBUF_ASSERT_EQ(0, sbuf_bcopyin(s, uptr, ulen));
- SBUF_ASSERT_EQ(len_before + (int)ulen, s->s_len);
- SBUF_ASSERT_NOT(SBUF_ISSET(s, SBUF_OVERFLOWED));
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("fail if overflowed")
- {
- struct sbuf *s = NULL;
- const void *uptr = (const void *)req->newptr;
- size_t ulen = req->newlen;
-
- s = sbuf_new(NULL, NULL, 16, 0);
- SBUF_SETFLAG(s, SBUF_OVERFLOWED);
- SBUF_ASSERT_EQ(-1, sbuf_bcopyin(s, uptr, ulen));
-
- sbuf_delete(s);
- }
- }
-
- SBUF_TESTING("sbuf_copyin")
- {
- SBUF_SHOULD("succeed in the simple case")
- {
- struct sbuf *s = NULL;
-
- s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
- SBUF_ASSERT_EQ(req->newlen + 1, sbuf_copyin(s, (const void *)req->newptr, req->newlen));
- SBUF_ASSERT_EQ(req->newlen, s->s_len);
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("use the sbuf capacity if len is zero")
- {
- struct sbuf *s = NULL;
-
- s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
- SBUF_ASSERT_EQ(req->newlen + 1, sbuf_copyin(s, (const void *)req->newptr, 0));
- SBUF_ASSERT_EQ(req->newlen, s->s_len);
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("fail if we can't extend the sbuf to accommodate")
- {
- struct sbuf *s = NULL;
-
- s = sbuf_new(NULL, NULL, 16, SBUF_FIXEDLEN);
- SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcde"));
- SBUF_ASSERT_EQ(-1, sbuf_copyin(s, (const void *)req->newptr, req->newlen));
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("auto-extend the buffer if necessary")
- {
- struct sbuf *s = NULL;
- int len_before;
-
- s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
- SBUF_ASSERT_EQ(0, sbuf_cpy(s, "0123456789abcde"));
- len_before = s->s_len;
- SBUF_ASSERT_NE(-1, sbuf_copyin(s, (const void *)req->newptr, req->newlen));
- SBUF_ASSERT_GT(len_before, s->s_len);
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("fail if the sbuf is overflowed")
- {
- struct sbuf *s = NULL;
-
- s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
- SBUF_SETFLAG(s, SBUF_OVERFLOWED);
- SBUF_ASSERT_EQ(-1, sbuf_copyin(s, (const void *)req->newptr, req->newlen));
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("fail gracefully for an invalid address")
- {
- struct sbuf *s = NULL;
-
- s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
- SBUF_ASSERT_EQ(-1, sbuf_copyin(s, (void *)0xdeadUL, req->newlen));
-
- sbuf_delete(s);
- }
-
- SBUF_SHOULD("fail gracefully for a kernel address")
- {
- struct sbuf *s = NULL;
- const char *ptr = "abcd";
-
- s = sbuf_new(NULL, NULL, 16, SBUF_AUTOEXTEND);
- SBUF_ASSERT_EQ(-1, sbuf_copyin(s, ptr, strlen(ptr)));
-
- sbuf_delete(s);
- }
- }
-
SBUF_TEST_END;
}