1 : #define VSTR_ADD_C
2 : /*
3 : * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 James Antill
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 : *
19 : * email: james@and.org
20 : */
21 : /* function to add data to a vstr */
22 : #include "main.h"
23 :
24 : static void vstr__cache_iovec_add_end(Vstr_base *base, Vstr_node *node,
25 : unsigned int len)
26 459626 : {
27 459626 : char *tmp = NULL;
28 459626 : unsigned int num = 0;
29 :
30 459626 : tmp = vstr_export__node_ptr(node);
31 459626 : ASSERT((node != base->beg) || !base->used);
32 :
33 459626 : num = VSTR__CACHE(base)->vec->off + base->num - 1;
34 :
35 459626 : ASSERT(num < VSTR__CACHE(base)->vec->sz);
36 :
37 459626 : VSTR__CACHE(base)->vec->v[num].iov_len = len;
38 459626 : VSTR__CACHE(base)->vec->v[num].iov_base = tmp;
39 459626 : VSTR__CACHE(base)->vec->t[num] = node->type;
40 : }
41 :
42 : static void vstr__cache_iovec_add_beg(Vstr_base *base, Vstr_node *node,
43 : unsigned int len)
44 45 : {
45 45 : char *tmp = NULL;
46 45 : unsigned int num = 0;
47 :
48 45 : tmp = vstr_export__node_ptr(node);
49 :
50 45 : ASSERT(VSTR__CACHE(base)->vec->off);
51 45 : num = --VSTR__CACHE(base)->vec->off;
52 :
53 45 : VSTR__CACHE(base)->vec->v[num].iov_len = len;
54 45 : VSTR__CACHE(base)->vec->v[num].iov_base = tmp;
55 45 : VSTR__CACHE(base)->vec->t[num] = node->type;
56 : }
57 :
58 : void vstr__cache_iovec_add_node_end(Vstr_base *base, unsigned int num,
59 : unsigned int len)
60 751413 : { /* done by hand in vstr-inline.h -- for add_buf and add_rep_chr */
61 751413 : if (!base->iovec_upto_date)
62 312152 : return;
63 :
64 439261 : num += VSTR__CACHE(base)->vec->off;
65 439261 : VSTR__CACHE(base)->vec->v[num - 1].iov_len += len;
66 : }
67 :
68 : static void vstr__cache_iovec_maybe_add(Vstr_base *base, Vstr_node *node,
69 : int at_end, unsigned int len)
70 1288943 : {
71 1288943 : if (!base->iovec_upto_date)
72 787623 : return;
73 :
74 501320 : if (at_end &&
75 : (base->num <= (VSTR__CACHE(base)->vec->sz - VSTR__CACHE(base)->vec->off)))
76 459626 : vstr__cache_iovec_add_end(base, node, len);
77 41694 : else if (!at_end && VSTR__CACHE(base)->vec->off)
78 45 : vstr__cache_iovec_add_beg(base, node, len);
79 : else
80 41649 : base->iovec_upto_date = FALSE;
81 : }
82 :
83 : Vstr_node *vstr__add_setup_pos(Vstr_base *base, size_t *pos, unsigned int *num,
84 : size_t *orig_scan_len)
85 1413535 : {
86 1413535 : Vstr_node *scan = NULL;
87 :
88 1413535 : assert(base && pos && num && *pos);
89 :
90 1413535 : scan = vstr_base__pos(base, pos, num, TRUE);;
91 :
92 1413535 : if (orig_scan_len)
93 267151 : *orig_scan_len = scan->len;
94 :
95 1413535 : if ((*pos != scan->len) && !(scan = vstr__base_split_node(base, scan, *pos)))
96 25 : return (NULL);
97 1413510 : assert(*pos == scan->len);
98 :
99 1413510 : return (scan);
100 : }
101 :
102 : /* add 2: one for setup_pos -> split_node ; one for rouding error in divide */
103 : #define VSTR__ADD_BEG(max, int_type, o_p_s_l) do { \
104 : assert(vstr__check_spare_nodes(base->conf)); \
105 : assert(vstr__check_real_nodes(base)); \
106 : \
107 : if (pos && base->len) \
108 : { \
109 : scan = vstr__add_setup_pos(base, &pos, &num, o_p_s_l); \
110 : if (!scan) \
111 : return (FALSE); \
112 : } \
113 : \
114 : if (((VSTR_TYPE_NODE_ ## int_type) != VSTR_TYPE_NODE_BUF) || !scan || \
115 : (scan->type != VSTR_TYPE_NODE_BUF) || (pos != scan->len) || \
116 : (len > (base->conf->buf_sz - scan->len))) \
117 : { \
118 : unsigned int alloc_num = (len / max) + !!(len % max); \
119 : \
120 : if (!vstr_cntl_conf(base->conf, \
121 : VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_ ## int_type, \
122 : alloc_num, UINT_MAX)) \
123 : return (FALSE); \
124 : } \
125 : \
126 : if (pos && base->len) \
127 : { \
128 : pos_scan = scan; \
129 : pos_scan_next = scan->next \
130 :
131 : #define VSTR__ADD_MID(max, node_type) \
132 : if (scan != base->end) \
133 : base->iovec_upto_date = FALSE; \
134 : } \
135 : else if (base->len) \
136 : { \
137 : pos_scan_next = base->beg; \
138 : assert(!pos); \
139 : vstr__base_zero_used(base); \
140 : } else if (!pos && !base->len) pos = 1; \
141 : \
142 : scan = (Vstr_node *)base->conf-> spare_ ## node_type ## _beg; \
143 : if (pos_scan) \
144 : { \
145 : assert(base->len); \
146 : pos_scan->next = scan; \
147 : } \
148 : else \
149 : base->beg = scan; \
150 : \
151 : num = 0; \
152 : base->len += len; \
153 : \
154 : while (len > 0) \
155 : { \
156 : size_t tmp = (max); \
157 : \
158 : if (tmp > len) \
159 : tmp = len; \
160 : \
161 : base-> node_ ## node_type ## _used = TRUE; \
162 : ++num; \
163 : ++base->num; \
164 :
165 : #define VSTR__ADD_END(node_type, int_type, o_p_s_l) \
166 : scan->len = tmp; \
167 : \
168 : vstr__cache_iovec_maybe_add(base, scan, pos, tmp); \
169 : \
170 : len -= tmp; \
171 : \
172 : if (!len) \
173 : break; \
174 : \
175 : scan = scan->next; \
176 : } \
177 : \
178 : base->conf-> spare_ ## node_type ## _beg = \
179 : (Vstr_node_ ## node_type *)scan->next; \
180 : base->conf-> spare_ ## node_type ## _num -= num; \
181 : \
182 : assert(!scan || (scan->type == (VSTR_TYPE_NODE_ ## int_type))); \
183 : \
184 : if (!(scan->next = pos_scan_next)) \
185 : base->end = scan; \
186 : \
187 : vstr__cache_add(base, orig_pos, orig_len); \
188 : \
189 : ASSERT(vstr__check_spare_nodes(base->conf)); \
190 : ASSERT(vstr__check_real_nodes(base)); \
191 : } while (FALSE)
192 :
193 : int vstr_extern_inline_add_buf(Vstr_base *base, size_t pos,
194 : const void *buffer, size_t len)
195 309703 : {
196 309703 : unsigned int num = 0;
197 309703 : size_t orig_pos = pos;
198 309703 : size_t orig_len = len;
199 309703 : Vstr_node *scan = NULL;
200 309703 : Vstr_node *pos_scan = NULL;
201 309703 : Vstr_node *pos_scan_next = NULL;
202 309703 : size_t orig_pos_scan_len = 0;
203 :
204 309703 : ASSERT_RET(!(!base || !buffer || !len || (pos > base->len)), FALSE);
205 :
206 309703 : VSTR__ADD_BEG(base->conf->buf_sz, BUF, &orig_pos_scan_len);
207 :
208 197863 : if ((scan->type == VSTR_TYPE_NODE_BUF) && (pos == scan->len) &&
209 : (scan->len < base->conf->buf_sz))
210 : {
211 97024 : size_t tmp = (base->conf->buf_sz - scan->len);
212 :
213 97024 : assert(base->node_buf_used);
214 :
215 97024 : if (tmp > len)
216 14293 : tmp = len;
217 :
218 97024 : vstr_wrap_memcpy(((Vstr_node_buf *)scan)->buf + scan->len, buffer, tmp);
219 97024 : scan->len += tmp;
220 97024 : buffer = ((char *)buffer) + tmp;
221 :
222 97024 : vstr__cache_iovec_add_node_end(base, num, tmp);
223 :
224 97024 : base->len += tmp;
225 97024 : len -= tmp;
226 :
227 97024 : if (!len)
228 : {
229 14458 : vstr__cache_add(base, orig_pos, orig_len);
230 :
231 14458 : assert(vstr__check_real_nodes(base));
232 14458 : return (TRUE);
233 : }
234 : }
235 :
236 183405 : VSTR__ADD_MID(base->conf->buf_sz, buf);
237 :
238 345191 : vstr_wrap_memcpy(((Vstr_node_buf *)scan)->buf, buffer, tmp);
239 345191 : buffer = ((char *)buffer) + tmp;
240 :
241 345191 : VSTR__ADD_END(buf, BUF, orig_pos_scan_len);
242 :
243 275390 : return (TRUE);
244 : }
245 :
246 : int vstr_add_ptr(Vstr_base *base, size_t pos,
247 : const void *pass_ptr, size_t len)
248 443894 : {
249 443894 : unsigned int num = 0;
250 443894 : size_t orig_pos = pos;
251 443894 : size_t orig_len = len;
252 443894 : char *ptr = (char *)pass_ptr; /* store as a char *, but _don't_ alter it */
253 443894 : Vstr_node *scan = NULL;
254 443894 : Vstr_node *pos_scan = NULL;
255 443894 : Vstr_node *pos_scan_next = NULL;
256 :
257 443894 : ASSERT_RET(!(!base || (pos > base->len)), FALSE);
258 :
259 443882 : if (!len)
260 40 : return (TRUE);
261 :
262 443842 : VSTR__ADD_BEG(VSTR_MAX_NODE_ALL, PTR, NULL);
263 :
264 326910 : if ((scan->type == VSTR_TYPE_NODE_PTR) &&
265 : ((((char *)((Vstr_node_ptr *)scan)->ptr) + scan->len) == ptr) &&
266 : (pos == scan->len) && (scan->len < VSTR_MAX_NODE_ALL))
267 : {
268 36 : size_t tmp = VSTR_MAX_NODE_ALL - scan->len;
269 :
270 36 : assert(base->node_ptr_used);
271 :
272 36 : if (tmp > len)
273 36 : tmp = len;
274 :
275 36 : scan->len += tmp;
276 :
277 36 : vstr__cache_iovec_add_node_end(base, num, tmp);
278 :
279 36 : base->len += tmp;
280 36 : len -= tmp;
281 :
282 36 : if (!len)
283 : {
284 36 : vstr__cache_add(base, orig_pos, orig_len);
285 :
286 36 : assert(vstr__check_real_nodes(base));
287 36 : return (TRUE);
288 : }
289 : }
290 :
291 326874 : VSTR__ADD_MID(VSTR_MAX_NODE_ALL, ptr);
292 :
293 443605 : base->node_ptr_used = TRUE;
294 443605 : ((Vstr_node_ptr *)scan)->ptr = ptr;
295 443605 : ptr += tmp;
296 :
297 443605 : VSTR__ADD_END(ptr, PTR, pos_scan->len);
298 :
299 443605 : return (TRUE);
300 : }
301 :
302 : int vstr_add_non(Vstr_base *base, size_t pos, size_t len)
303 1614 : {
304 1614 : unsigned int num = 0;
305 1614 : size_t orig_pos = pos;
306 1614 : size_t orig_len = len;
307 1614 : Vstr_node *scan = NULL;
308 1614 : Vstr_node *pos_scan = NULL;
309 1614 : Vstr_node *pos_scan_next = NULL;
310 1614 : size_t orig_pos_scan_len = 0;
311 :
312 1614 : ASSERT_RET(!(!base || (pos > base->len)), FALSE);
313 :
314 1606 : if (!len)
315 15 : return (TRUE);
316 :
317 1591 : VSTR__ADD_BEG(VSTR_MAX_NODE_ALL, NON, &orig_pos_scan_len);
318 :
319 1221 : if ((scan->type == VSTR_TYPE_NODE_NON) && (scan->len < VSTR_MAX_NODE_ALL))
320 : {
321 9 : size_t tmp = VSTR_MAX_NODE_ALL - scan->len;
322 :
323 9 : assert(base->node_non_used);
324 :
325 9 : if (tmp > len)
326 9 : tmp = len;
327 :
328 9 : scan->len += tmp;
329 :
330 9 : vstr__cache_iovec_add_node_end(base, num, tmp);
331 :
332 9 : base->len += tmp;
333 9 : len -= tmp;
334 :
335 9 : if (!len)
336 : {
337 9 : vstr__cache_add(base, orig_pos, orig_len);
338 :
339 9 : assert(vstr__check_real_nodes(base));
340 9 : return (TRUE);
341 : }
342 : }
343 :
344 1212 : VSTR__ADD_MID(VSTR_MAX_NODE_ALL, non);
345 1705 : VSTR__ADD_END(non, NON, orig_pos_scan_len);
346 :
347 1561 : return (TRUE);
348 : }
349 :
350 : int vstr_add_ref(Vstr_base *base, size_t pos,
351 : Vstr_ref *ref, size_t off, size_t len)
352 797745 : {
353 797745 : unsigned int num = 0;
354 797745 : size_t orig_pos = pos;
355 797745 : size_t orig_len = len;
356 797745 : Vstr_node *scan = NULL;
357 797745 : Vstr_node *pos_scan = NULL;
358 797745 : Vstr_node *pos_scan_next = NULL;
359 :
360 797745 : ASSERT_RET(!(!base || !ref || (pos > base->len)), FALSE);
361 :
362 797733 : if (!len)
363 40 : return (TRUE);
364 :
365 797693 : VSTR__ADD_BEG(VSTR_MAX_NODE_ALL, REF, NULL);
366 :
367 792356 : if ((scan->type == VSTR_TYPE_NODE_REF) &&
368 : (((Vstr_node_ref *)scan)->ref == ref) &&
369 : ((((Vstr_node_ref *)scan)->off + scan->len) == off) &&
370 : (pos == scan->len) && (scan->len < VSTR_MAX_NODE_ALL))
371 : {
372 628653 : size_t tmp = VSTR_MAX_NODE_ALL - scan->len;
373 :
374 628653 : assert(base->node_ref_used);
375 :
376 628653 : if (tmp > len)
377 628653 : tmp = len;
378 :
379 628653 : scan->len += tmp;
380 :
381 628653 : vstr__cache_iovec_add_node_end(base, num, tmp);
382 :
383 628653 : base->len += tmp;
384 628653 : len -= tmp;
385 :
386 628653 : if (!len)
387 : {
388 628653 : vstr__cache_add(base, orig_pos, orig_len);
389 :
390 628653 : assert(vstr__check_real_nodes(base));
391 628653 : return (TRUE);
392 : }
393 : }
394 :
395 163703 : VSTR__ADD_MID(VSTR_MAX_NODE_ALL, ref);
396 :
397 168879 : ((Vstr_node_ref *)scan)->ref = vstr_ref_add(ref);
398 168879 : ((Vstr_node_ref *)scan)->off = off;
399 168879 : off += len;
400 :
401 168879 : VSTR__ADD_END(ref, REF, pos_scan->len);
402 :
403 168879 : return (TRUE);
404 : }
405 :
406 : /* replace all buf nodes with ref nodes, we don't need to change the
407 : * vectors if they are there */
408 : static int vstr__convert_buf_ref(Vstr_base *base, size_t pos, size_t len)
409 780809 : {
410 780809 : Vstr_node **scan = NULL;
411 780809 : unsigned int num = 0;
412 :
413 780809 : scan = vstr__base_ptr_pos(base, &pos, &num);
414 780809 : --pos;
415 :
416 780809 : len += pos;
417 780809 : len -= base->used;
418 :
419 793040 : while (*scan)
420 : {
421 793040 : if ((*scan)->type == VSTR_TYPE_NODE_BUF)
422 : {
423 18175 : if (!vstr__chg_node_buf_ref(base, scan, num))
424 29 : return (FALSE);
425 : }
426 :
427 793011 : if (len <= (*scan)->len)
428 780780 : break;
429 12231 : len -= (*scan)->len;
430 :
431 12231 : scan = &(*scan)->next;
432 12231 : ++num;
433 : }
434 780780 : assert(!len || (*scan && ((*scan)->len >= len)));
435 :
436 780780 : return (TRUE);
437 : }
438 :
439 : static int vstr__add_all_ref(Vstr_base *base, size_t pos,
440 : Vstr_base *from_base, size_t from_pos, size_t len)
441 599 : {
442 599 : Vstr_ref *ref = NULL;
443 599 : size_t off = 0;
444 :
445 599 : if (!(ref = vstr_export_ref(from_base, from_pos, len, &off)))
446 : {
447 43 : base->conf->malloc_bad = TRUE;
448 43 : goto add_all_ref_fail;
449 : }
450 :
451 556 : if (!vstr_add_ref(base, pos, ref, off, len))
452 16 : goto add_ref_all_ref_fail;
453 :
454 540 : vstr_ref_del(ref);
455 :
456 540 : return (TRUE);
457 :
458 : add_ref_all_ref_fail:
459 16 : vstr_ref_del(ref);
460 :
461 : add_all_ref_fail:
462 :
463 59 : from_base->conf->malloc_bad = TRUE;
464 59 : return (FALSE);
465 : }
466 :
467 : static int vstr__add_vstr_node(Vstr_base *base, size_t pos,
468 : Vstr_node *scan, size_t off, size_t len,
469 : unsigned int add_type)
470 912187 : {
471 912187 : switch (scan->type)
472 : {
473 : case VSTR_TYPE_NODE_BUF:
474 : /* all bufs should now be refs */
475 115192 : assert(add_type != VSTR_TYPE_ADD_BUF_REF);
476 :
477 115192 : if (add_type == VSTR_TYPE_ADD_BUF_PTR)
478 : {
479 70205 : if (!vstr_add_ptr(base, pos,
480 : ((Vstr_node_buf *)scan)->buf + off, len))
481 57 : return (FALSE);
482 44987 : break;
483 : }
484 :
485 44987 : if (!vstr_add_buf(base, pos, ((Vstr_node_buf *)scan)->buf + off, len))
486 242 : return (FALSE);
487 666 : break;
488 :
489 : case VSTR_TYPE_NODE_NON:
490 666 : if (!vstr_add_non(base, pos, len))
491 16 : return (FALSE);
492 2932 : break;
493 :
494 : case VSTR_TYPE_NODE_PTR:
495 : {
496 2932 : char *ptr = ((Vstr_node_ptr *)scan)->ptr;
497 :
498 2932 : if (add_type == VSTR_TYPE_ADD_ALL_BUF)
499 : {
500 440 : if (!vstr_add_buf(base, pos, ptr + off, len))
501 99 : return (FALSE);
502 2492 : break;
503 : }
504 :
505 2492 : if (!vstr_add_ptr(base, pos, ptr + off, len))
506 133 : return (FALSE);
507 : }
508 793397 : break;
509 :
510 : case VSTR_TYPE_NODE_REF:
511 793397 : off += ((Vstr_node_ref *)scan)->off;
512 793397 : if (add_type == VSTR_TYPE_ADD_ALL_BUF)
513 : {
514 347 : char *ptr = ((Vstr_node_ref *)scan)->ref->ptr;
515 347 : if (!vstr_add_buf(base, pos, ptr + off, len))
516 21 : return (FALSE);
517 793050 : break;
518 : }
519 :
520 793050 : if (!vstr_add_ref(base, pos, ((Vstr_node_ref *)scan)->ref, off, len))
521 119 : return (FALSE);
522 :
523 688009 : ASSERT_NO_SWITCH_DEF();
524 : }
525 :
526 911500 : return (TRUE);
527 : }
528 :
529 : # define DO_CP_LOOP_BEG(x) size_t tmp = scan->len; \
530 : tmp -= (x); \
531 : if (tmp > len) tmp = len
532 :
533 : # define DO_CP_LOOP_END() do { \
534 : pos += tmp; \
535 : len -= tmp; \
536 : \
537 : scan = scan->next; \
538 : } while (FALSE)
539 :
540 : static size_t vstr__add_vstr_nodes(Vstr_base *base, size_t pos,
541 : Vstr_node *scan, size_t from_pos, size_t len,
542 : unsigned int add_type)
543 881528 : {
544 881528 : if (len > 0)
545 : {
546 881528 : size_t off = from_pos - 1;
547 881528 : DO_CP_LOOP_BEG(off);
548 :
549 881528 : if (!vstr__add_vstr_node(base, pos, scan, off, tmp, add_type))
550 247 : return (0);
551 :
552 881281 : DO_CP_LOOP_END();
553 : }
554 :
555 911500 : while (len > 0)
556 : {
557 30659 : DO_CP_LOOP_BEG(0);
558 :
559 30659 : if (!vstr__add_vstr_node(base, pos, scan, 0, tmp, add_type))
560 440 : return (0);
561 :
562 30219 : DO_CP_LOOP_END();
563 : }
564 :
565 880841 : return (pos);
566 : }
567 :
568 : # undef DO_CP_LOOP_BEG
569 : # undef DO_CP_LOOP_END
570 :
571 : /* it's so big it looks cluncky, so wrap in a define */
572 : # define DO_VALID_CHK() do { \
573 : assert(vstr__check_spare_nodes(base->conf)); \
574 : assert(vstr__check_real_nodes(base)); \
575 : assert(vstr__check_spare_nodes(from_base->conf)); \
576 : assert(vstr__check_real_nodes((Vstr_base *)from_base)); \
577 : } while (FALSE)
578 :
579 : int vstr_add_vstr(Vstr_base *base, size_t pos,
580 : const Vstr_base *from_base, size_t from_pos, size_t len,
581 : unsigned int add_type)
582 1285958 : {
583 1285958 : Vstr_base *nonconst_from_base = (Vstr_base *)from_base;
584 1285958 : size_t orig_pos = pos;
585 1285958 : size_t orig_from_pos = from_pos;
586 1285958 : size_t orig_len = len;
587 1285958 : size_t orig_base_len = 0;
588 1285958 : Vstr_node *scan = NULL;
589 1285958 : unsigned int dummy_num = 0;
590 :
591 1285958 : ASSERT_RET(!(!base || (pos > base->len) ||
592 : !from_base || ((from_pos > from_base->len) && len)), FALSE);
593 :
594 1285942 : orig_base_len = base->len;
595 :
596 1285942 : if (!len)
597 403863 : return (TRUE);
598 :
599 882079 : DO_VALID_CHK();
600 :
601 : /* quick short cut instead of using export_cstr_ref() also doesn't change
602 : * from_base in certain cases */
603 882079 : if (add_type == VSTR_TYPE_ADD_ALL_REF)
604 : {
605 599 : if (!vstr__add_all_ref(base, pos, nonconst_from_base, from_pos, len))
606 59 : goto fail_beg;
607 :
608 540 : DO_VALID_CHK();
609 :
610 540 : return (TRUE);
611 : }
612 :
613 : /* make sure there are no buf nodes */
614 881480 : if (add_type == VSTR_TYPE_ADD_BUF_REF)
615 : {
616 780809 : if (!vstr__convert_buf_ref(nonconst_from_base, from_pos, len))
617 29 : goto fail_beg;
618 :
619 860493 : DO_VALID_CHK();
620 : }
621 :
622 881451 : scan = vstr_base__pos(from_base, &from_pos, &dummy_num, TRUE);
623 :
624 : /* do an initial split where it's comming from, if needed (Ie. not a buffer,
625 : * or it's at the start of the buffer), this is just so we don't call
626 : * memcpy() on overlapping data... however with split poisoning it'll do
627 : * bad things */
628 881451 : if ((from_base == base) && (scan->type == VSTR_TYPE_NODE_BUF) &&
629 : (from_pos != (((scan == base->beg) ? base->used : 0U) + 1)))
630 : {
631 83 : if (!(scan = vstr__base_split_node(nonconst_from_base, scan, from_pos - 1)))
632 8 : goto fail_beg;
633 :
634 75 : ASSERT((from_pos - 1) == scan->len);
635 75 : ASSERT(scan->next);
636 75 : scan = scan->next;
637 75 : from_pos = 1;
638 : }
639 :
640 881443 : if ((from_base == base) && (orig_from_pos <= orig_pos) &&
641 : ((orig_from_pos + orig_len - 1) > orig_pos))
642 : { /* ok the vstr has to be copied inside itself, Ie.
643 : *
644 : * aaXXXXaa
645 : *
646 : * Where a is the From vstr data, and X is the To vstr data,
647 : * so we have to copy the first part, skip the middle and copy the
648 : * second part */
649 89 : size_t before = vstr_sc_posdiff(orig_from_pos, orig_pos);
650 : // size_t before = orig_pos - orig_from_pos;
651 :
652 89 : assert(before < len);
653 :
654 89 : if (!(pos = vstr__add_vstr_nodes(base, pos,
655 : scan, from_pos, before, add_type)))
656 4 : goto fail_end;
657 :
658 85 : len -= before;
659 85 : from_pos = orig_from_pos + (before * 2);
660 85 : scan = vstr_base__pos(from_base, &from_pos, &dummy_num, TRUE);
661 : }
662 :
663 881439 : if (!vstr__add_vstr_nodes(base, pos, scan, from_pos, len, add_type))
664 683 : goto fail_end;
665 :
666 880756 : vstr__cache_cstr_cpy(base, orig_pos, orig_len,
667 : nonconst_from_base, orig_from_pos);
668 :
669 880756 : DO_VALID_CHK();
670 :
671 880756 : return (TRUE);
672 :
673 : fail_end:
674 : /* must work as orig_pos must now be at the begining of a node */
675 687 : vstr_del(base, orig_pos + 1, base->len - orig_base_len);
676 687 : assert(base->len == orig_base_len);
677 :
678 : fail_beg:
679 783 : from_base->conf->malloc_bad = TRUE;
680 783 : base->conf->malloc_bad = TRUE;
681 783 : DO_VALID_CHK();
682 :
683 783 : return (FALSE);
684 : }
685 : # undef DO_VALID_CHK
686 :
687 : size_t vstr_add_iovec_buf_beg(Vstr_base *base, size_t pos,
688 : unsigned int min, unsigned int max,
689 : struct iovec **ret_iovs,
690 : unsigned int *num)
691 70905 : {
692 70905 : unsigned int sz = max;
693 70905 : struct iovec *iovs = NULL;
694 70905 : unsigned char *types = NULL;
695 70905 : size_t bytes = 0;
696 70905 : Vstr_node *scan = NULL;
697 :
698 70905 : ASSERT(base && ret_iovs && num);
699 70905 : ASSERT_RET(max && (max >= min), 0);
700 :
701 70905 : ASSERT(vstr__check_spare_nodes(base->conf));
702 70905 : ASSERT(vstr__check_real_nodes(base));
703 :
704 70905 : if (pos != base->len)
705 63 : ++min;
706 :
707 70905 : if (!vstr_cntl_conf(base->conf,
708 : VSTR_CNTL_CONF_SET_NUM_RANGE_SPARE_BUF, min, UINT_MAX))
709 68 : return (0);
710 :
711 70837 : ASSERT(sz == max); /* max to write to at once */
712 70837 : if (sz > base->conf->spare_buf_num)
713 13474 : sz = base->conf->spare_buf_num;
714 :
715 70837 : ASSERT(sz);
716 :
717 70837 : if (!vstr__cache_iovec_alloc(base, base->num + sz))
718 5 : return (0);
719 :
720 70832 : if (!vstr__cache_iovec_valid(base))
721 47327 : assert(FALSE);
722 :
723 70832 : iovs = VSTR__CACHE(base)->vec->v + VSTR__CACHE(base)->vec->off;
724 70832 : types = VSTR__CACHE(base)->vec->t + VSTR__CACHE(base)->vec->off;
725 70832 : *num = 0;
726 :
727 70832 : if (pos)
728 : {
729 26856 : unsigned int scan_num = 0;
730 :
731 26856 : ASSERT(base);
732 26856 : ASSERT_RET((pos <= base->len), 0);
733 :
734 26856 : if (!(scan = vstr__add_setup_pos(base, &pos, &scan_num, NULL)))
735 1 : return (0);
736 :
737 26855 : if ((scan->type == VSTR_TYPE_NODE_BUF) && (base->conf->buf_sz > scan->len))
738 : {
739 12432 : if (sz < max)
740 2851 : ++sz;
741 :
742 12432 : iovs += scan_num - 1;
743 12432 : types += scan_num - 1;
744 :
745 12432 : iovs[0].iov_len = (base->conf->buf_sz - pos);
746 12432 : iovs[0].iov_base = (((Vstr_node_buf *)scan)->buf + pos);
747 :
748 12432 : base->iovec_upto_date = FALSE;
749 :
750 12432 : bytes = iovs[0].iov_len;
751 12432 : *num = 1;
752 : }
753 : else
754 : {
755 14423 : iovs += scan_num;
756 14423 : types += scan_num;
757 :
758 14423 : if (scan != base->end)
759 : /* if we are adding into the middle of the Vstr then we don't keep
760 : * the vec valid for after the point where we are adding.
761 : * This is then updated again in the _end() func */
762 10 : base->iovec_upto_date = FALSE;
763 : }
764 : }
765 43976 : else if (base->len)
766 : /* TODO: maybe work with offset to not damage iovec cache
767 : * non trivial though */
768 12 : base->iovec_upto_date = FALSE;
769 :
770 70831 : scan = (Vstr_node *)base->conf->spare_buf_beg;
771 1416812 : assert(scan);
772 :
773 2311403 : while (*num < sz)
774 : {
775 2240572 : assert(scan->type == VSTR_TYPE_NODE_BUF);
776 :
777 2240572 : iovs[*num].iov_len = base->conf->buf_sz;
778 2240572 : iovs[*num].iov_base = ((Vstr_node_buf *)scan)->buf;
779 2240572 : types[*num] = VSTR_TYPE_NODE_BUF;
780 :
781 2240572 : bytes += iovs[*num].iov_len;
782 2240572 : ++*num;
783 :
784 2240572 : scan = scan->next;
785 : }
786 :
787 70831 : *ret_iovs = iovs;
788 70831 : return (bytes);
789 : }
790 :
791 : void vstr_add_iovec_buf_end(Vstr_base *base, size_t pos, size_t bytes)
792 70831 : {
793 70831 : size_t orig_pos = pos;
794 70831 : size_t orig_bytes = bytes;
795 70831 : struct iovec *iovs = NULL;
796 70831 : unsigned char *types = NULL;
797 70831 : unsigned int count = 0;
798 70831 : Vstr_node *scan = NULL;
799 70831 : Vstr_node **adder = NULL;
800 :
801 70831 : base->node_buf_used |= !!bytes;
802 :
803 70831 : iovs = VSTR__CACHE(base)->vec->v + VSTR__CACHE(base)->vec->off;
804 70831 : types = VSTR__CACHE(base)->vec->t + VSTR__CACHE(base)->vec->off;
805 70831 : if (pos)
806 : {
807 26855 : unsigned int scan_num = 0;
808 :
809 26855 : scan = vstr_base__pos(base, &pos, &scan_num, TRUE);
810 26855 : iovs += scan_num - 1;
811 26855 : types += scan_num - 1;
812 :
813 26855 : assert(pos == scan->len);
814 :
815 26855 : if ((scan->type == VSTR_TYPE_NODE_BUF) && (base->conf->buf_sz > scan->len))
816 : {
817 12432 : size_t first_iov_len = 0;
818 :
819 : /* normally the first case is true ... but it's possible the user could
820 : * lowered the value for some reason -- As in vstr__sc_read_len_fd() */
821 12432 : assert(((base->conf->buf_sz - scan->len) == iovs[0].iov_len) ||
822 : (((base->conf->buf_sz - scan->len) > iovs[0].iov_len) &&
823 : (bytes <= iovs[0].iov_len)));
824 12432 : assert((((Vstr_node_buf *)scan)->buf + scan->len) == iovs[0].iov_base);
825 :
826 12432 : first_iov_len = iovs[0].iov_len;
827 12432 : if (first_iov_len > bytes)
828 9857 : first_iov_len = bytes;
829 :
830 12432 : assert(!base->iovec_upto_date);
831 12432 : if (scan == base->end)
832 : {
833 12427 : base->end = NULL;
834 12427 : base->iovec_upto_date = TRUE;
835 : }
836 :
837 12432 : scan->len += first_iov_len;
838 :
839 12432 : vstr__cache_iovec_reset_node(base, scan, scan_num);
840 :
841 12432 : bytes -= first_iov_len;
842 : }
843 14423 : else if (scan == base->end)
844 : {
845 14413 : base->end = NULL;
846 24993 : assert(base->iovec_upto_date);
847 : }
848 :
849 26855 : ++iovs;
850 26855 : ++types;
851 :
852 26855 : adder = &scan->next;
853 : }
854 : else
855 43976 : adder = &base->beg;
856 :
857 70831 : base->len += orig_bytes;
858 :
859 70831 : if (!bytes)
860 : {
861 16676 : if (!base->end)
862 : {
863 16656 : assert(!*adder);
864 16656 : base->end = scan;
865 : }
866 :
867 16676 : if (!base->iovec_upto_date && base->len)
868 : {
869 20 : count = 0;
870 20 : scan = *adder;
871 160 : while (scan)
872 : {
873 140 : iovs[count].iov_len = scan->len;
874 :
875 140 : if (scan == base->beg)
876 10 : iovs[count].iov_base = vstr_export__node_ptr(scan) + base->used;
877 : else
878 130 : iovs[count].iov_base = vstr_export__node_ptr(scan);
879 :
880 140 : types[count] = scan->type;
881 :
882 140 : ++count;
883 140 : scan = scan->next;
884 : }
885 : }
886 :
887 16676 : if (orig_bytes)
888 7658 : vstr__cache_add(base, orig_pos, orig_bytes);
889 :
890 9919 : assert(vstr__check_spare_nodes(base->conf));
891 9919 : assert(vstr__check_real_nodes(base));
892 :
893 27239 : return;
894 : }
895 :
896 54155 : scan = (Vstr_node *)base->conf->spare_buf_beg;
897 54155 : count = 0;
898 930642 : while (bytes > 0)
899 : {
900 876487 : Vstr_node *scan_next = NULL;
901 876487 : size_t tmp = iovs[count].iov_len;
902 :
903 876487 : assert(scan);
904 876487 : scan_next = scan->next;
905 :
906 876487 : if (tmp > bytes)
907 15358 : tmp = bytes;
908 :
909 876487 : assert(((Vstr_node_buf *)scan)->buf == iovs[count].iov_base);
910 876487 : assert((tmp == base->conf->buf_sz) || (tmp == bytes));
911 :
912 876487 : scan->len = tmp;
913 :
914 876487 : bytes -= tmp;
915 :
916 876487 : if (!bytes)
917 : {
918 54155 : if (!(scan->next = *adder))
919 : {
920 54148 : assert(base->iovec_upto_date);
921 54148 : base->end = scan;
922 : }
923 :
924 54155 : iovs[count].iov_len = tmp;
925 : }
926 :
927 876487 : scan = scan_next;
928 :
929 876487 : ++count;
930 : }
931 54155 : assert(base->conf->spare_buf_num >= count);
932 :
933 54155 : base->num += count;
934 54155 : base->conf->spare_buf_num -= count;
935 :
936 54155 : assert(base->len);
937 :
938 54155 : if (!base->iovec_upto_date)
939 : {
940 7 : Vstr_node *tmp = *adder;
941 :
942 40 : while (tmp)
943 : {
944 33 : iovs[count].iov_len = tmp->len;
945 33 : iovs[count].iov_base = vstr_export__node_ptr(tmp);
946 33 : types[count] = tmp->type;
947 :
948 33 : ++count;
949 33 : tmp = tmp->next;
950 : }
951 :
952 7 : base->iovec_upto_date = TRUE;
953 : }
954 : else
955 54152 : assert(!*adder);
956 :
957 54155 : assert(base->end);
958 :
959 54155 : *adder = (Vstr_node *)base->conf->spare_buf_beg;
960 54155 : base->conf->spare_buf_beg = (Vstr_node_buf *)scan;
961 :
962 54155 : if (orig_bytes)
963 54155 : vstr__cache_add(base, orig_pos, orig_bytes);
964 :
965 67739 : assert(vstr__check_spare_nodes(base->conf));
966 67739 : assert(vstr__check_real_nodes(base));
967 : }
968 :
969 : int vstr_extern_inline_add_rep_chr(Vstr_base *base, size_t pos,
970 : char chr, size_t len)
971 102370 : { /* almost embarassingly similar to add_buf */
972 102370 : unsigned int num = 0;
973 102370 : size_t orig_pos = pos;
974 102370 : size_t orig_len = len;
975 102370 : Vstr_node *scan = NULL;
976 102370 : Vstr_node *pos_scan = NULL;
977 102370 : Vstr_node *pos_scan_next = NULL;
978 102370 : size_t orig_pos_scan_len = 0;
979 :
980 102370 : ASSERT_RET(!(!base || !len || (pos > base->len)), FALSE);
981 :
982 102370 : VSTR__ADD_BEG(base->conf->buf_sz, BUF, &orig_pos_scan_len);
983 :
984 41113 : if ((scan->type == VSTR_TYPE_NODE_BUF) && (pos == scan->len) &&
985 : (scan->len < base->conf->buf_sz))
986 : {
987 25691 : size_t tmp = (base->conf->buf_sz - scan->len);
988 :
989 25691 : assert(base->node_buf_used);
990 :
991 25691 : if (tmp > len)
992 23 : tmp = len;
993 :
994 25691 : vstr_wrap_memset(((Vstr_node_buf *)scan)->buf + scan->len, chr, tmp);
995 25691 : scan->len += tmp;
996 :
997 25691 : vstr__cache_iovec_add_node_end(base, num, tmp);
998 :
999 25691 : base->len += tmp;
1000 25691 : len -= tmp;
1001 :
1002 25691 : if (!len)
1003 : {
1004 23 : vstr__cache_add(base, orig_pos, orig_len);
1005 :
1006 23 : assert(vstr__check_real_nodes(base));
1007 23 : return (TRUE);
1008 : }
1009 : }
1010 :
1011 41090 : VSTR__ADD_MID(base->conf->buf_sz, buf);
1012 :
1013 : /* always do memset -- don't do above */
1014 329563 : vstr_wrap_memset(((Vstr_node_buf *)scan)->buf, chr, tmp);
1015 :
1016 329563 : VSTR__ADD_END(buf, BUF, orig_pos_scan_len);
1017 :
1018 90273 : return (TRUE);
1019 : }
|