VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/bsd/kern/subr_sbuf.c

Last change on this file was 69046, checked in by vboxsync, 8 years ago

Global: replace fall-through comments with RT_FALL_THRU().
bugref:8192: gcc warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
1/*-
2 * Copyright (c) 2000 Poul-Henning Kamp and Dag-Erling Coïdan Smørgrav
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef VBOX
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: src/sys/kern/subr_sbuf.c,v 1.30.8.1 2009/04/15 03:14:26 kensmith Exp $");
32
33#include <sys/param.h>
34
35#ifdef _KERNEL
36#include <sys/ctype.h>
37#include <sys/kernel.h>
38#include <sys/malloc.h>
39#include <sys/systm.h>
40#include <sys/uio.h>
41#include <machine/stdarg.h>
42#else /* _KERNEL */
43#include <ctype.h>
44#include <stdarg.h>
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#endif /* _KERNEL */
49
50#include <sys/sbuf.h>
51
52#ifdef _KERNEL
53static MALLOC_DEFINE(M_SBUF, "sbuf", "string buffers");
54#define SBMALLOC(size) malloc(size, M_SBUF, M_WAITOK)
55#define SBFREE(buf) free(buf, M_SBUF)
56#else /* _KERNEL */
57#define KASSERT(e, m)
58#define SBMALLOC(size) malloc(size)
59#define SBFREE(buf) free(buf)
60#define min(x,y) MIN(x,y)
61#endif /* _KERNEL */
62#else /* VBOX */
63# include <iprt/param.h>
64# include <iprt/ctype.h>
65# include <slirp.h>
66# define SBMALLOC(size) RTMemAlloc((size))
67# define SBFREE(buf) RTMemFree((buf))
68#endif
69
70/*
71 * Predicates
72 */
73#define SBUF_ISDYNAMIC(s) ((s)->s_flags & SBUF_DYNAMIC)
74#define SBUF_ISDYNSTRUCT(s) ((s)->s_flags & SBUF_DYNSTRUCT)
75#define SBUF_ISFINISHED(s) ((s)->s_flags & SBUF_FINISHED)
76#define SBUF_HASOVERFLOWED(s) ((s)->s_flags & SBUF_OVERFLOWED)
77#define SBUF_HASROOM(s) ((s)->s_len < (s)->s_size - 1)
78#define SBUF_FREESPACE(s) ((s)->s_size - (s)->s_len - 1)
79#define SBUF_CANEXTEND(s) ((s)->s_flags & SBUF_AUTOEXTEND)
80
81/*
82 * Set / clear flags
83 */
84#define SBUF_SETFLAG(s, f) do { (s)->s_flags |= (f); } while (0)
85#define SBUF_CLEARFLAG(s, f) do { (s)->s_flags &= ~(f); } while (0)
86
87#define SBUF_MINEXTENDSIZE 16 /* Should be power of 2. */
88#define SBUF_MAXEXTENDSIZE PAGE_SIZE
89#define SBUF_MAXEXTENDINCR PAGE_SIZE
90
91/*
92 * Debugging support
93 */
94#if defined(_KERNEL) && defined(INVARIANTS)
95static void
96_assert_sbuf_integrity(const char *fun, struct sbuf *s)
97{
98 KASSERT(s != NULL,
99 ("%s called with a NULL sbuf pointer", fun));
100 KASSERT(s->s_buf != NULL,
101 ("%s called with uninitialized or corrupt sbuf", fun));
102 KASSERT(s->s_len < s->s_size,
103 ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
104}
105
106static void
107_assert_sbuf_state(const char *fun, struct sbuf *s, int state)
108{
109 KASSERT((s->s_flags & SBUF_FINISHED) == state,
110 ("%s called with %sfinished or corrupt sbuf", fun,
111 (state ? "un" : "")));
112}
113#define assert_sbuf_integrity(s) _assert_sbuf_integrity(__func__, (s))
114#define assert_sbuf_state(s, i) _assert_sbuf_state(__func__, (s), (i))
115#else /* _KERNEL && INVARIANTS */
116#define assert_sbuf_integrity(s) do { } while (0)
117#define assert_sbuf_state(s, i) do { } while (0)
118#endif /* _KERNEL && INVARIANTS */
119
120static int
121sbuf_extendsize(int size)
122{
123 int newsize;
124
125 newsize = SBUF_MINEXTENDSIZE;
126 while (newsize < size) {
127 if (newsize < (int)SBUF_MAXEXTENDSIZE)
128 newsize *= 2;
129 else
130 newsize += SBUF_MAXEXTENDINCR;
131 }
132
133 return (newsize);
134}
135
136
137/*
138 * Extend an sbuf.
139 */
140static int
141sbuf_extend(struct sbuf *s, int addlen)
142{
143 char *newbuf;
144 int newsize;
145
146 if (!SBUF_CANEXTEND(s))
147 return (-1);
148
149 newsize = sbuf_extendsize(s->s_size + addlen);
150 newbuf = (char *)SBMALLOC(newsize);
151 if (newbuf == NULL)
152 return (-1);
153 bcopy(s->s_buf, newbuf, s->s_size);
154 if (SBUF_ISDYNAMIC(s))
155 SBFREE(s->s_buf);
156 else
157 SBUF_SETFLAG(s, SBUF_DYNAMIC);
158 s->s_buf = newbuf;
159 s->s_size = newsize;
160 return (0);
161}
162
163/*
164 * Initialize an sbuf.
165 * If buf is non-NULL, it points to a static or already-allocated string
166 * big enough to hold at least length characters.
167 */
168struct sbuf *
169sbuf_new(struct sbuf *s, char *buf, int length, int flags)
170{
171 KASSERT(length >= 0,
172 ("attempt to create an sbuf of negative length (%d)", length));
173 KASSERT((flags & ~SBUF_USRFLAGMSK) == 0,
174 ("%s called with invalid flags", __func__));
175
176 flags &= SBUF_USRFLAGMSK;
177 if (s == NULL) {
178 s = (struct sbuf *)SBMALLOC(sizeof *s);
179 if (s == NULL)
180 return (NULL);
181 bzero(s, sizeof *s);
182 s->s_flags = flags;
183 SBUF_SETFLAG(s, SBUF_DYNSTRUCT);
184 } else {
185 bzero(s, sizeof *s);
186 s->s_flags = flags;
187 }
188 s->s_size = length;
189 if (buf) {
190 s->s_buf = buf;
191 return (s);
192 }
193 if (flags & SBUF_AUTOEXTEND)
194 s->s_size = sbuf_extendsize(s->s_size);
195 s->s_buf = (char *)SBMALLOC(s->s_size);
196 if (s->s_buf == NULL) {
197 if (SBUF_ISDYNSTRUCT(s))
198 SBFREE(s);
199 return (NULL);
200 }
201 SBUF_SETFLAG(s, SBUF_DYNAMIC);
202 return (s);
203}
204
205#ifdef _KERNEL
206/*
207 * Create an sbuf with uio data
208 */
209struct sbuf *
210sbuf_uionew(struct sbuf *s, struct uio *uio, int *error)
211{
212 KASSERT(uio != NULL,
213 ("%s called with NULL uio pointer", __func__));
214 KASSERT(error != NULL,
215 ("%s called with NULL error pointer", __func__));
216
217 s = sbuf_new(s, NULL, uio->uio_resid + 1, 0);
218 if (s == NULL) {
219 *error = ENOMEM;
220 return (NULL);
221 }
222 *error = uiomove(s->s_buf, uio->uio_resid, uio);
223 if (*error != 0) {
224 sbuf_delete(s);
225 return (NULL);
226 }
227 s->s_len = s->s_size - 1;
228 *error = 0;
229 return (s);
230}
231#endif
232
233/*
234 * Clear an sbuf and reset its position.
235 */
236void
237sbuf_clear(struct sbuf *s)
238{
239 assert_sbuf_integrity(s);
240 /* don't care if it's finished or not */
241
242 SBUF_CLEARFLAG(s, SBUF_FINISHED);
243 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
244 s->s_len = 0;
245}
246
247/*
248 * Set the sbuf's end position to an arbitrary value.
249 * Effectively truncates the sbuf at the new position.
250 */
251int
252sbuf_setpos(struct sbuf *s, int pos)
253{
254 assert_sbuf_integrity(s);
255 assert_sbuf_state(s, 0);
256
257 KASSERT(pos >= 0,
258 ("attempt to seek to a negative position (%d)", pos));
259 KASSERT(pos < s->s_size,
260 ("attempt to seek past end of sbuf (%d >= %d)", pos, s->s_size));
261
262 if (pos < 0 || pos > s->s_len)
263 return (-1);
264 s->s_len = pos;
265 return (0);
266}
267
268/*
269 * Append a byte string to an sbuf.
270 */
271int
272sbuf_bcat(struct sbuf *s, const void *buf, size_t len)
273{
274 const char *str = buf;
275
276 assert_sbuf_integrity(s);
277 assert_sbuf_state(s, 0);
278
279 if (SBUF_HASOVERFLOWED(s))
280 return (-1);
281
282 for (; len; len--) {
283 if (!SBUF_HASROOM(s) && sbuf_extend(s, len) < 0)
284 break;
285 s->s_buf[s->s_len++] = *str++;
286 }
287 if (len) {
288 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
289 return (-1);
290 }
291 return (0);
292}
293
294#ifdef _KERNEL
295/*
296 * Copy a byte string from userland into an sbuf.
297 */
298int
299sbuf_bcopyin(struct sbuf *s, const void *uaddr, size_t len)
300{
301 assert_sbuf_integrity(s);
302 assert_sbuf_state(s, 0);
303
304 if (SBUF_HASOVERFLOWED(s))
305 return (-1);
306
307 if (len == 0)
308 return (0);
309 if (len > SBUF_FREESPACE(s)) {
310 sbuf_extend(s, len - SBUF_FREESPACE(s));
311 len = min(len, SBUF_FREESPACE(s));
312 }
313 if (copyin(uaddr, s->s_buf + s->s_len, len) != 0)
314 return (-1);
315 s->s_len += len;
316
317 return (0);
318}
319#endif
320
321/*
322 * Copy a byte string into an sbuf.
323 */
324int
325sbuf_bcpy(struct sbuf *s, const void *buf, size_t len)
326{
327 assert_sbuf_integrity(s);
328 assert_sbuf_state(s, 0);
329
330 sbuf_clear(s);
331 return (sbuf_bcat(s, buf, len));
332}
333
334/*
335 * Append a string to an sbuf.
336 */
337int
338sbuf_cat(struct sbuf *s, const char *str)
339{
340 assert_sbuf_integrity(s);
341 assert_sbuf_state(s, 0);
342
343 if (SBUF_HASOVERFLOWED(s))
344 return (-1);
345
346 while (*str) {
347 if (!SBUF_HASROOM(s) && sbuf_extend(s, strlen(str)) < 0)
348 break;
349 s->s_buf[s->s_len++] = *str++;
350 }
351 if (*str) {
352 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
353 return (-1);
354 }
355 return (0);
356}
357
358#ifdef _KERNEL
359/*
360 * Append a string from userland to an sbuf.
361 */
362int
363sbuf_copyin(struct sbuf *s, const void *uaddr, size_t len)
364{
365 size_t done;
366
367 assert_sbuf_integrity(s);
368 assert_sbuf_state(s, 0);
369
370 if (SBUF_HASOVERFLOWED(s))
371 return (-1);
372
373 if (len == 0)
374 len = SBUF_FREESPACE(s); /* XXX return 0? */
375 if (len > SBUF_FREESPACE(s)) {
376 sbuf_extend(s, len);
377 len = min(len, SBUF_FREESPACE(s));
378 }
379 switch (copyinstr(uaddr, s->s_buf + s->s_len, len + 1, &done)) {
380 case ENAMETOOLONG:
381 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
382 RT_FALL_THRU();
383 case 0:
384 s->s_len += done - 1;
385 break;
386 default:
387 return (-1); /* XXX */
388 }
389
390 return (done);
391}
392#endif
393
394/*
395 * Copy a string into an sbuf.
396 */
397int
398sbuf_cpy(struct sbuf *s, const char *str)
399{
400 assert_sbuf_integrity(s);
401 assert_sbuf_state(s, 0);
402
403 sbuf_clear(s);
404 return (sbuf_cat(s, str));
405}
406
407/*
408 * Format the given argument list and append the resulting string to an sbuf.
409 */
410int
411sbuf_vprintf(struct sbuf *s, const char *fmt, va_list ap)
412{
413 va_list ap_copy;
414 int len;
415
416 assert_sbuf_integrity(s);
417 assert_sbuf_state(s, 0);
418
419 KASSERT(fmt != NULL,
420 ("%s called with a NULL format string", __func__));
421
422 if (SBUF_HASOVERFLOWED(s))
423 return (-1);
424
425 do {
426 va_copy(ap_copy, ap);
427#ifndef VBOX
428 len = vsnprintf(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
429 fmt, ap_copy);
430#else
431 len = RTStrPrintfV(&s->s_buf[s->s_len], SBUF_FREESPACE(s) + 1,
432 fmt, ap_copy);
433#endif
434 va_end(ap_copy);
435 } while (len > SBUF_FREESPACE(s) &&
436 sbuf_extend(s, len - SBUF_FREESPACE(s)) == 0);
437
438 /*
439 * s->s_len is the length of the string, without the terminating nul.
440 * When updating s->s_len, we must subtract 1 from the length that
441 * we passed into vsnprintf() because that length includes the
442 * terminating nul.
443 *
444 * vsnprintf() returns the amount that would have been copied,
445 * given sufficient space, hence the min() calculation below.
446 */
447 s->s_len += min(len, SBUF_FREESPACE(s));
448 if (!SBUF_HASROOM(s) && !SBUF_CANEXTEND(s))
449 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
450
451 KASSERT(s->s_len < s->s_size,
452 ("wrote past end of sbuf (%d >= %d)", s->s_len, s->s_size));
453
454 if (SBUF_HASOVERFLOWED(s))
455 return (-1);
456 return (0);
457}
458
459/*
460 * Format the given arguments and append the resulting string to an sbuf.
461 */
462int
463sbuf_printf(struct sbuf *s, const char *fmt, ...)
464{
465 va_list ap;
466 int result;
467
468 va_start(ap, fmt);
469 result = sbuf_vprintf(s, fmt, ap);
470 va_end(ap);
471 return(result);
472}
473
474/*
475 * Append a character to an sbuf.
476 */
477int
478sbuf_putc(struct sbuf *s, int c)
479{
480 assert_sbuf_integrity(s);
481 assert_sbuf_state(s, 0);
482
483 if (SBUF_HASOVERFLOWED(s))
484 return (-1);
485
486 if (!SBUF_HASROOM(s) && sbuf_extend(s, 1) < 0) {
487 SBUF_SETFLAG(s, SBUF_OVERFLOWED);
488 return (-1);
489 }
490 if (c != '\0')
491 s->s_buf[s->s_len++] = c;
492 return (0);
493}
494
495/*
496 * Trim whitespace characters from end of an sbuf.
497 */
498int
499sbuf_trim(struct sbuf *s)
500{
501 assert_sbuf_integrity(s);
502 assert_sbuf_state(s, 0);
503
504 if (SBUF_HASOVERFLOWED(s))
505 return (-1);
506
507#ifndef VBOX
508 while (s->s_len && isspace(s->s_buf[s->s_len-1]))
509 --s->s_len;
510#else
511 while (s->s_len && RT_C_IS_SPACE(s->s_buf[s->s_len-1]))
512 --s->s_len;
513#endif
514
515 return (0);
516}
517
518/*
519 * Check if an sbuf overflowed
520 */
521int
522sbuf_overflowed(struct sbuf *s)
523{
524 return SBUF_HASOVERFLOWED(s);
525}
526
527/*
528 * Finish off an sbuf.
529 */
530void
531sbuf_finish(struct sbuf *s)
532{
533 assert_sbuf_integrity(s);
534 assert_sbuf_state(s, 0);
535
536 s->s_buf[s->s_len] = '\0';
537 SBUF_CLEARFLAG(s, SBUF_OVERFLOWED);
538 SBUF_SETFLAG(s, SBUF_FINISHED);
539}
540
541/*
542 * Return a pointer to the sbuf data.
543 */
544char *
545sbuf_data(struct sbuf *s)
546{
547 assert_sbuf_integrity(s);
548 assert_sbuf_state(s, SBUF_FINISHED);
549
550 return s->s_buf;
551}
552
553/*
554 * Return the length of the sbuf data.
555 */
556int
557sbuf_len(struct sbuf *s)
558{
559 assert_sbuf_integrity(s);
560 /* don't care if it's finished or not */
561
562 if (SBUF_HASOVERFLOWED(s))
563 return (-1);
564 return s->s_len;
565}
566
567/*
568 * Clear an sbuf, free its buffer if necessary.
569 */
570void
571sbuf_delete(struct sbuf *s)
572{
573 int isdyn;
574
575 assert_sbuf_integrity(s);
576 /* don't care if it's finished or not */
577
578 if (SBUF_ISDYNAMIC(s))
579 SBFREE(s->s_buf);
580 isdyn = SBUF_ISDYNSTRUCT(s);
581 bzero(s, sizeof *s);
582 if (isdyn)
583 SBFREE(s);
584}
585
586/*
587 * Check if an sbuf has been finished.
588 */
589int
590sbuf_done(struct sbuf *s)
591{
592
593 return(SBUF_ISFINISHED(s));
594}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette