]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/apr-util/buckets/apr_brigade.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / apr-util / buckets / apr_brigade.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr.h"
18 #include "apr_lib.h"
19 #include "apr_strings.h"
20 #include "apr_pools.h"
21 #include "apr_tables.h"
22 #include "apr_buckets.h"
23 #include "apr_errno.h"
24 #define APR_WANT_MEMFUNC
25 #define APR_WANT_STRFUNC
26 #include "apr_want.h"
27
28 #if APR_HAVE_SYS_UIO_H
29 #include <sys/uio.h>
30 #endif
31
32 static apr_status_t brigade_cleanup(void *data) 
33 {
34     return apr_brigade_cleanup(data);
35 }
36
37 APU_DECLARE(apr_status_t) apr_brigade_cleanup(void *data)
38 {
39     apr_bucket_brigade *b = data;
40     apr_bucket *e;
41
42     while (!APR_BRIGADE_EMPTY(b)) {
43         e = APR_BRIGADE_FIRST(b);
44         apr_bucket_delete(e);
45     }
46     /* We don't need to free(bb) because it's allocated from a pool. */
47     return APR_SUCCESS;
48 }
49
50 APU_DECLARE(apr_status_t) apr_brigade_destroy(apr_bucket_brigade *b)
51 {
52     apr_pool_cleanup_kill(b->p, b, brigade_cleanup);
53     return apr_brigade_cleanup(b);
54 }
55
56 APU_DECLARE(apr_bucket_brigade *) apr_brigade_create(apr_pool_t *p,
57                                                      apr_bucket_alloc_t *list)
58 {
59     apr_bucket_brigade *b;
60
61     b = apr_palloc(p, sizeof(*b));
62     b->p = p;
63     b->bucket_alloc = list;
64
65     APR_RING_INIT(&b->list, apr_bucket, link);
66
67     apr_pool_cleanup_register(b->p, b, brigade_cleanup, apr_pool_cleanup_null);
68     return b;
69 }
70
71 APU_DECLARE(apr_bucket_brigade *) apr_brigade_split_ex(apr_bucket_brigade *b,
72                                                        apr_bucket *e,
73                                                        apr_bucket_brigade *a)
74 {
75     apr_bucket *f;
76
77     if (!a) {
78         a = apr_brigade_create(b->p, b->bucket_alloc);
79     }
80     else if (!APR_BRIGADE_EMPTY(a)) {
81         apr_brigade_cleanup(a);
82     }
83     /* Return an empty brigade if there is nothing left in 
84      * the first brigade to split off 
85      */
86     if (e != APR_BRIGADE_SENTINEL(b)) {
87         f = APR_RING_LAST(&b->list);
88         APR_RING_UNSPLICE(e, f, link);
89         APR_RING_SPLICE_HEAD(&a->list, e, f, apr_bucket, link);
90     }
91
92     APR_BRIGADE_CHECK_CONSISTENCY(a);
93     APR_BRIGADE_CHECK_CONSISTENCY(b);
94
95     return a;
96 }
97
98 APU_DECLARE(apr_bucket_brigade *) apr_brigade_split(apr_bucket_brigade *b,
99                                                     apr_bucket *e)
100 {
101     return apr_brigade_split_ex(b, e, NULL);
102 }
103
104 APU_DECLARE(apr_status_t) apr_brigade_partition(apr_bucket_brigade *b,
105                                                 apr_off_t point,
106                                                 apr_bucket **after_point)
107 {
108     apr_bucket *e;
109     const char *s;
110     apr_size_t len;
111     apr_uint64_t point64;
112     apr_status_t rv;
113
114     if (point < 0) {
115         /* this could cause weird (not necessarily SEGV) things to happen */
116         return APR_EINVAL;
117     }
118     if (point == 0) {
119         *after_point = APR_BRIGADE_FIRST(b);
120         return APR_SUCCESS;
121     }
122
123     /*
124      * Try to reduce the following casting mess: We know that point will be
125      * larger equal 0 now and forever and thus that point (apr_off_t) and
126      * apr_size_t will fit into apr_uint64_t in any case.
127      */
128     point64 = (apr_uint64_t)point;
129
130     APR_BRIGADE_CHECK_CONSISTENCY(b);
131
132     for (e = APR_BRIGADE_FIRST(b);
133          e != APR_BRIGADE_SENTINEL(b);
134          e = APR_BUCKET_NEXT(e))
135     {
136         /* For an unknown length bucket, while 'point64' is beyond the possible
137          * size contained in apr_size_t, read and continue...
138          */
139         if ((e->length == (apr_size_t)(-1))
140             && (point64 > (apr_uint64_t)APR_SIZE_MAX)) {
141             /* point64 is too far out to simply split this bucket,
142              * we must fix this bucket's size and keep going... */
143             rv = apr_bucket_read(e, &s, &len, APR_BLOCK_READ);
144             if (rv != APR_SUCCESS) {
145                 *after_point = e;
146                 return rv;
147             }
148         }
149         else if ((point64 < (apr_uint64_t)e->length)
150                  || (e->length == (apr_size_t)(-1))) {
151             /* We already consumed buckets where point64 is beyond
152              * our interest ( point64 > APR_SIZE_MAX ), above.
153              * Here point falls between 0 and APR_SIZE_MAX
154              * and is within this bucket, or this bucket's len
155              * is undefined, so now we are ready to split it.
156              * First try to split the bucket natively... */
157             if ((rv = apr_bucket_split(e, (apr_size_t)point64)) 
158                     != APR_ENOTIMPL) {
159                 *after_point = APR_BUCKET_NEXT(e);
160                 return rv;
161             }
162
163             /* if the bucket cannot be split, we must read from it,
164              * changing its type to one that can be split */
165             rv = apr_bucket_read(e, &s, &len, APR_BLOCK_READ);
166             if (rv != APR_SUCCESS) {
167                 *after_point = e;
168                 return rv;
169             }
170
171             /* this assumes that len == e->length, which is okay because e
172              * might have been morphed by the apr_bucket_read() above, but
173              * if it was, the length would have been adjusted appropriately */
174             if (point64 < (apr_uint64_t)e->length) {
175                 rv = apr_bucket_split(e, (apr_size_t)point64);
176                 *after_point = APR_BUCKET_NEXT(e);
177                 return rv;
178             }
179         }
180         if (point64 == (apr_uint64_t)e->length) {
181             *after_point = APR_BUCKET_NEXT(e);
182             return APR_SUCCESS;
183         }
184         point64 -= (apr_uint64_t)e->length;
185     }
186     *after_point = APR_BRIGADE_SENTINEL(b); 
187     return APR_INCOMPLETE;
188 }
189
190 APU_DECLARE(apr_status_t) apr_brigade_length(apr_bucket_brigade *bb,
191                                              int read_all, apr_off_t *length)
192 {
193     apr_off_t total = 0;
194     apr_bucket *bkt;
195     apr_status_t status = APR_SUCCESS;
196
197     for (bkt = APR_BRIGADE_FIRST(bb);
198          bkt != APR_BRIGADE_SENTINEL(bb);
199          bkt = APR_BUCKET_NEXT(bkt))
200     {
201         if (bkt->length == (apr_size_t)(-1)) {
202             const char *ignore;
203             apr_size_t len;
204
205             if (!read_all) {
206                 total = -1;
207                 break;
208             }
209
210             if ((status = apr_bucket_read(bkt, &ignore, &len,
211                                           APR_BLOCK_READ)) != APR_SUCCESS) {
212                 break;
213             }
214         }
215
216         total += bkt->length;
217     }
218
219     *length = total;
220     return status;
221 }
222
223 APU_DECLARE(apr_status_t) apr_brigade_flatten(apr_bucket_brigade *bb,
224                                               char *c, apr_size_t *len)
225 {
226     apr_size_t actual = 0;
227     apr_bucket *b;
228  
229     for (b = APR_BRIGADE_FIRST(bb);
230          b != APR_BRIGADE_SENTINEL(bb);
231          b = APR_BUCKET_NEXT(b))
232     {
233         const char *str;
234         apr_size_t str_len;
235         apr_status_t status;
236
237         status = apr_bucket_read(b, &str, &str_len, APR_BLOCK_READ);
238         if (status != APR_SUCCESS) {
239             return status;
240         }
241
242         /* If we would overflow. */
243         if (str_len + actual > *len) {
244             str_len = *len - actual;
245         }
246
247         /* XXX: It appears that overflow of the final bucket
248          * is DISCARDED without any warning to the caller.
249          *
250          * No, we only copy the data up to their requested size.  -- jre
251          */
252         memcpy(c, str, str_len);
253
254         c += str_len;
255         actual += str_len;
256
257         /* This could probably be actual == *len, but be safe from stray
258          * photons. */
259         if (actual >= *len) {
260             break;
261         }
262     }
263
264     *len = actual;
265     return APR_SUCCESS;
266 }
267
268 APU_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb,
269                                                char **c,
270                                                apr_size_t *len,
271                                                apr_pool_t *pool)
272 {
273     apr_off_t actual;
274     apr_size_t total;
275     apr_status_t rv;
276
277     apr_brigade_length(bb, 1, &actual);
278     
279     /* XXX: This is dangerous beyond belief.  At least in the
280      * apr_brigade_flatten case, the user explicitly stated their
281      * buffer length - so we don't up and palloc 4GB for a single
282      * file bucket.  This API must grow a useful max boundry,
283      * either compiled-in or preset via the *len value.
284      *
285      * Shouldn't both fn's grow an additional return value for 
286      * the case that the brigade couldn't be flattened into the
287      * provided or allocated buffer (such as APR_EMOREDATA?)
288      * Not a failure, simply an advisory result.
289      */
290     total = (apr_size_t)actual;
291
292     *c = apr_palloc(pool, total);
293     
294     rv = apr_brigade_flatten(bb, *c, &total);
295
296     if (rv != APR_SUCCESS) {
297         return rv;
298     }
299
300     *len = total;
301     return APR_SUCCESS;
302 }
303
304 APU_DECLARE(apr_status_t) apr_brigade_split_line(apr_bucket_brigade *bbOut,
305                                                  apr_bucket_brigade *bbIn,
306                                                  apr_read_type_e block,
307                                                  apr_off_t maxbytes)
308 {
309     apr_off_t readbytes = 0;
310
311     while (!APR_BRIGADE_EMPTY(bbIn)) {
312         const char *pos;
313         const char *str;
314         apr_size_t len;
315         apr_status_t rv;
316         apr_bucket *e;
317
318         e = APR_BRIGADE_FIRST(bbIn);
319         rv = apr_bucket_read(e, &str, &len, block);
320
321         if (rv != APR_SUCCESS) {
322             return rv;
323         }
324
325         pos = memchr(str, APR_ASCII_LF, len);
326         /* We found a match. */
327         if (pos != NULL) {
328             apr_bucket_split(e, pos - str + 1);
329             APR_BUCKET_REMOVE(e);
330             APR_BRIGADE_INSERT_TAIL(bbOut, e);
331             return APR_SUCCESS;
332         }
333         APR_BUCKET_REMOVE(e);
334         if (APR_BUCKET_IS_METADATA(e) || len > APR_BUCKET_BUFF_SIZE/4) {
335             APR_BRIGADE_INSERT_TAIL(bbOut, e);
336         }
337         else {
338             if (len > 0) {
339                 rv = apr_brigade_write(bbOut, NULL, NULL, str, len);
340                 if (rv != APR_SUCCESS) {
341                     return rv;
342                 }
343             }
344             apr_bucket_destroy(e);
345         }
346         readbytes += len;
347         /* We didn't find an APR_ASCII_LF within the maximum line length. */
348         if (readbytes >= maxbytes) {
349             break;
350         }
351     }
352
353     return APR_SUCCESS;
354 }
355
356
357 APU_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b, 
358                                                struct iovec *vec, int *nvec)
359 {
360     int left = *nvec;
361     apr_bucket *e;
362     struct iovec *orig;
363     apr_size_t iov_len;
364     const char *iov_base;
365     apr_status_t rv;
366
367     orig = vec;
368
369     for (e = APR_BRIGADE_FIRST(b);
370          e != APR_BRIGADE_SENTINEL(b);
371          e = APR_BUCKET_NEXT(e))
372     {
373         if (left-- == 0)
374             break;
375
376         rv = apr_bucket_read(e, &iov_base, &iov_len, APR_NONBLOCK_READ);
377         if (rv != APR_SUCCESS)
378             return rv;
379         /* Set indirectly since types differ: */
380         vec->iov_len = iov_len;
381         vec->iov_base = (void *)iov_base;
382         ++vec;
383     }
384
385     *nvec = (int)(vec - orig);
386     return APR_SUCCESS;
387 }
388
389 APU_DECLARE(apr_status_t) apr_brigade_vputstrs(apr_bucket_brigade *b, 
390                                                apr_brigade_flush flush,
391                                                void *ctx,
392                                                va_list va)
393 {
394 #define MAX_VECS    8
395     struct iovec vec[MAX_VECS];
396     apr_size_t i = 0;
397
398     for (;;) {
399         char *str = va_arg(va, char *);
400         apr_status_t rv;
401
402         if (str == NULL)
403             break;
404
405         vec[i].iov_base = str;
406         vec[i].iov_len = strlen(str);
407         i++;
408
409         if (i == MAX_VECS) {
410             rv = apr_brigade_writev(b, flush, ctx, vec, i);
411             if (rv != APR_SUCCESS)
412                 return rv;
413             i = 0;
414         }
415     }
416     if (i != 0)
417        return apr_brigade_writev(b, flush, ctx, vec, i);
418
419     return APR_SUCCESS;
420 }
421
422 APU_DECLARE(apr_status_t) apr_brigade_putc(apr_bucket_brigade *b,
423                                            apr_brigade_flush flush, void *ctx,
424                                            const char c)
425 {
426     return apr_brigade_write(b, flush, ctx, &c, 1);
427 }
428
429 APU_DECLARE(apr_status_t) apr_brigade_write(apr_bucket_brigade *b,
430                                             apr_brigade_flush flush,
431                                             void *ctx, 
432                                             const char *str, apr_size_t nbyte)
433 {
434     apr_bucket *e = APR_BRIGADE_LAST(b);
435     apr_size_t remaining = APR_BUCKET_BUFF_SIZE;
436     char *buf = NULL;
437
438     /*
439      * If the last bucket is a heap bucket and its buffer is not shared with
440      * another bucket, we may write into that bucket.
441      */
442     if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)
443         && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) {
444         apr_bucket_heap *h = e->data;
445
446         /* HEAP bucket start offsets are always in-memory, safe to cast */
447         remaining = h->alloc_len - (e->length + (apr_size_t)e->start);
448         buf = h->base + e->start + e->length;
449     }
450
451     if (nbyte > remaining) {
452         /* either a buffer bucket exists but is full, 
453          * or no buffer bucket exists and the data is too big
454          * to buffer.  In either case, we should flush.  */
455         if (flush) {
456             e = apr_bucket_transient_create(str, nbyte, b->bucket_alloc);
457             APR_BRIGADE_INSERT_TAIL(b, e);
458             return flush(b, ctx);
459         }
460         else {
461             e = apr_bucket_heap_create(str, nbyte, NULL, b->bucket_alloc);
462             APR_BRIGADE_INSERT_TAIL(b, e);
463             return APR_SUCCESS;
464         }
465     }
466     else if (!buf) {
467         /* we don't have a buffer, but the data is small enough
468          * that we don't mind making a new buffer */
469         buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc);
470         e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE,
471                                    apr_bucket_free, b->bucket_alloc);
472         APR_BRIGADE_INSERT_TAIL(b, e);
473         e->length = 0;   /* We are writing into the brigade, and
474                           * allocating more memory than we need.  This
475                           * ensures that the bucket thinks it is empty just
476                           * after we create it.  We'll fix the length
477                           * once we put data in it below.
478                           */
479     }
480
481     /* there is a sufficiently big buffer bucket available now */
482     memcpy(buf, str, nbyte);
483     e->length += nbyte;
484
485     return APR_SUCCESS;
486 }
487
488 APU_DECLARE(apr_status_t) apr_brigade_writev(apr_bucket_brigade *b,
489                                              apr_brigade_flush flush,
490                                              void *ctx,
491                                              const struct iovec *vec,
492                                              apr_size_t nvec)
493 {
494     apr_bucket *e;
495     apr_size_t total_len;
496     apr_size_t i;
497     char *buf;
498
499     /* Compute the total length of the data to be written.
500      */
501     total_len = 0;
502     for (i = 0; i < nvec; i++) {
503        total_len += vec[i].iov_len;
504     }
505
506     /* If the data to be written is very large, try to convert
507      * the iovec to transient buckets rather than copying.
508      */
509     if (total_len > APR_BUCKET_BUFF_SIZE) {
510         if (flush) {
511             for (i = 0; i < nvec; i++) {
512                 e = apr_bucket_transient_create(vec[i].iov_base,
513                                                 vec[i].iov_len,
514                                                 b->bucket_alloc);
515                 APR_BRIGADE_INSERT_TAIL(b, e);
516             }
517             return flush(b, ctx);
518         }
519         else {
520             for (i = 0; i < nvec; i++) {
521                 e = apr_bucket_heap_create((const char *) vec[i].iov_base,
522                                            vec[i].iov_len, NULL,
523                                            b->bucket_alloc);
524                 APR_BRIGADE_INSERT_TAIL(b, e);
525             }
526             return APR_SUCCESS;
527         }
528     }
529
530     i = 0;
531
532     /* If there is a heap bucket at the end of the brigade
533      * already, and its refcount is 1, copy into the existing bucket.
534      */
535     e = APR_BRIGADE_LAST(b);
536     if (!APR_BRIGADE_EMPTY(b) && APR_BUCKET_IS_HEAP(e)
537         && ((apr_bucket_heap *)(e->data))->refcount.refcount == 1) {
538         apr_bucket_heap *h = e->data;
539         apr_size_t remaining = h->alloc_len -
540             (e->length + (apr_size_t)e->start);
541         buf = h->base + e->start + e->length;
542
543         if (remaining >= total_len) {
544             /* Simple case: all the data will fit in the
545              * existing heap bucket
546              */
547             for (; i < nvec; i++) {
548                 apr_size_t len = vec[i].iov_len;
549                 memcpy(buf, (const void *) vec[i].iov_base, len);
550                 buf += len;
551             }
552             e->length += total_len;
553             return APR_SUCCESS;
554         }
555         else {
556             /* More complicated case: not all of the data
557              * will fit in the existing heap bucket.  The
558              * total data size is <= APR_BUCKET_BUFF_SIZE,
559              * so we'll need only one additional bucket.
560              */
561             const char *start_buf = buf;
562             for (; i < nvec; i++) {
563                 apr_size_t len = vec[i].iov_len;
564                 if (len > remaining) {
565                     break;
566                 }
567                 memcpy(buf, (const void *) vec[i].iov_base, len);
568                 buf += len;
569                 remaining -= len;
570             }
571             e->length += (buf - start_buf);
572             total_len -= (buf - start_buf);
573
574             if (flush) {
575                 apr_status_t rv = flush(b, ctx);
576                 if (rv != APR_SUCCESS) {
577                     return rv;
578                 }
579             }
580
581             /* Now fall through into the case below to
582              * allocate another heap bucket and copy the
583              * rest of the array.  (Note that i is not
584              * reset to zero here; it holds the index
585              * of the first vector element to be
586              * written to the new bucket.)
587              */
588         }
589     }
590
591     /* Allocate a new heap bucket, and copy the data into it.
592      * The checks above ensure that the amount of data to be
593      * written here is no larger than APR_BUCKET_BUFF_SIZE.
594      */
595     buf = apr_bucket_alloc(APR_BUCKET_BUFF_SIZE, b->bucket_alloc);
596     e = apr_bucket_heap_create(buf, APR_BUCKET_BUFF_SIZE,
597                                apr_bucket_free, b->bucket_alloc);
598     for (; i < nvec; i++) {
599         apr_size_t len = vec[i].iov_len;
600         memcpy(buf, (const void *) vec[i].iov_base, len);
601         buf += len;
602     }
603     e->length = total_len;
604     APR_BRIGADE_INSERT_TAIL(b, e);
605
606     return APR_SUCCESS;
607 }
608
609 APU_DECLARE(apr_status_t) apr_brigade_puts(apr_bucket_brigade *bb,
610                                            apr_brigade_flush flush, void *ctx,
611                                            const char *str)
612 {
613     return apr_brigade_write(bb, flush, ctx, str, strlen(str));
614 }
615
616 APU_DECLARE_NONSTD(apr_status_t) apr_brigade_putstrs(apr_bucket_brigade *b, 
617                                                      apr_brigade_flush flush,
618                                                      void *ctx, ...)
619 {
620     va_list va;
621     apr_status_t rv;
622
623     va_start(va, ctx);
624     rv = apr_brigade_vputstrs(b, flush, ctx, va);
625     va_end(va);
626     return rv;
627 }
628
629 APU_DECLARE_NONSTD(apr_status_t) apr_brigade_printf(apr_bucket_brigade *b, 
630                                                     apr_brigade_flush flush,
631                                                     void *ctx, 
632                                                     const char *fmt, ...)
633 {
634     va_list ap;
635     apr_status_t rv;
636
637     va_start(ap, fmt);
638     rv = apr_brigade_vprintf(b, flush, ctx, fmt, ap);
639     va_end(ap);
640     return rv;
641 }
642
643 struct brigade_vprintf_data_t {
644     apr_vformatter_buff_t vbuff;
645
646     apr_bucket_brigade *b;  /* associated brigade */
647     apr_brigade_flush *flusher; /* flushing function */
648     void *ctx;
649
650     char *cbuff; /* buffer to flush from */
651 };
652
653 static apr_status_t brigade_flush(apr_vformatter_buff_t *buff)
654 {
655     /* callback function passed to ap_vformatter to be
656      * called when vformatter needs to buff and
657      * buff.curpos > buff.endpos
658      */
659
660     /* "downcast," have really passed a brigade_vprintf_data_t* */
661     struct brigade_vprintf_data_t *vd = (struct brigade_vprintf_data_t*)buff;
662     apr_status_t res = APR_SUCCESS;
663
664     res = apr_brigade_write(vd->b, *vd->flusher, vd->ctx, vd->cbuff,
665                           APR_BUCKET_BUFF_SIZE);
666
667     if(res != APR_SUCCESS) {
668       return -1;
669     }
670
671     vd->vbuff.curpos = vd->cbuff;
672     vd->vbuff.endpos = vd->cbuff + APR_BUCKET_BUFF_SIZE;
673
674     return res;
675 }
676
677 APU_DECLARE(apr_status_t) apr_brigade_vprintf(apr_bucket_brigade *b,
678                                               apr_brigade_flush flush,
679                                               void *ctx,
680                                               const char *fmt, va_list va)
681 {
682     /* the cast, in order of appearance */
683     struct brigade_vprintf_data_t vd;
684     char buf[APR_BUCKET_BUFF_SIZE];
685     int written;
686
687     vd.vbuff.curpos = buf;
688     vd.vbuff.endpos = buf + APR_BUCKET_BUFF_SIZE;
689     vd.b = b;
690     vd.flusher = &flush;
691     vd.ctx = ctx;
692     vd.cbuff = buf;
693
694     written = apr_vformatter(brigade_flush, &vd.vbuff, fmt, va);
695
696     if (written == -1) {
697       return -1;
698     }
699
700     /* write out what remains in the buffer */
701     return apr_brigade_write(b, flush, ctx, buf, vd.vbuff.curpos - buf);
702 }
703
704 /* A "safe" maximum bucket size, 1Gb */
705 #define MAX_BUCKET_SIZE (0x40000000)
706
707 APU_DECLARE(apr_bucket *) apr_brigade_insert_file(apr_bucket_brigade *bb,
708                                                   apr_file_t *f,
709                                                   apr_off_t start,
710                                                   apr_off_t length,
711                                                   apr_pool_t *p)
712 {
713     apr_bucket *e;
714
715     if (sizeof(apr_off_t) == sizeof(apr_size_t) || length < MAX_BUCKET_SIZE) {
716         e = apr_bucket_file_create(f, start, (apr_size_t)length, p, 
717                                    bb->bucket_alloc);
718     }
719     else {
720         /* Several buckets are needed. */        
721         e = apr_bucket_file_create(f, start, MAX_BUCKET_SIZE, p, 
722                                    bb->bucket_alloc);
723
724         while (length > MAX_BUCKET_SIZE) {
725             apr_bucket *ce;
726             apr_bucket_copy(e, &ce);
727             APR_BRIGADE_INSERT_TAIL(bb, ce);
728             e->start += MAX_BUCKET_SIZE;
729             length -= MAX_BUCKET_SIZE;
730         }
731         e->length = (apr_size_t)length; /* Resize just the last bucket */
732     }
733     
734     APR_BRIGADE_INSERT_TAIL(bb, e);
735     return e;
736 }