1
2/*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10
11
12ngx_buf_t *
13ngx_create_temp_buf(ngx_pool_t *pool, size_t size)
14{
15    ngx_buf_t *b;
16
17    b = ngx_calloc_buf(pool);
18    if (b == NULL) {
19        return NULL;
20    }
21
22    b->start = ngx_palloc(pool, size);
23    if (b->start == NULL) {
24        return NULL;
25    }
26
27    /*
28     * set by ngx_calloc_buf():
29     *
30     *     b->file_pos = 0;
31     *     b->file_last = 0;
32     *     b->file = NULL;
33     *     b->shadow = NULL;
34     *     b->tag = 0;
35     *     and flags
36     */
37
38    b->pos = b->start;
39    b->last = b->start;
40    b->end = b->last + size;
41    b->temporary = 1;
42
43    return b;
44}
45
46
47ngx_chain_t *
48ngx_alloc_chain_link(ngx_pool_t *pool)
49{
50    ngx_chain_t  *cl;
51
52    cl = pool->chain;
53
54    if (cl) {
55        pool->chain = cl->next;
56        return cl;
57    }
58
59    cl = ngx_palloc(pool, sizeof(ngx_chain_t));
60    if (cl == NULL) {
61        return NULL;
62    }
63
64    return cl;
65}
66
67
68ngx_chain_t *
69ngx_create_chain_of_bufs(ngx_pool_t *pool, ngx_bufs_t *bufs)
70{
71    u_char       *p;
72    ngx_int_t     i;
73    ngx_buf_t    *b;
74    ngx_chain_t  *chain, *cl, **ll;
75
76    p = ngx_palloc(pool, bufs->num * bufs->size);
77    if (p == NULL) {
78        return NULL;
79    }
80
81    ll = &chain;
82
83    for (i = 0; i < bufs->num; i++) {
84
85        b = ngx_calloc_buf(pool);
86        if (b == NULL) {
87            return NULL;
88        }
89
90        /*
91         * set by ngx_calloc_buf():
92         *
93         *     b->file_pos = 0;
94         *     b->file_last = 0;
95         *     b->file = NULL;
96         *     b->shadow = NULL;
97         *     b->tag = 0;
98         *     and flags
99         *
100         */
101
102        b->pos = p;
103        b->last = p;
104        b->temporary = 1;
105
106        b->start = p;
107        p += bufs->size;
108        b->end = p;
109
110        cl = ngx_alloc_chain_link(pool);
111        if (cl == NULL) {
112            return NULL;
113        }
114
115        cl->buf = b;
116        *ll = cl;
117        ll = &cl->next;
118    }
119
120    *ll = NULL;
121
122    return chain;
123}
124
125
126ngx_int_t
127ngx_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in)
128{
129    ngx_chain_t  *cl, **ll;
130
131    ll = chain;
132
133    for (cl = *chain; cl; cl = cl->next) {
134        ll = &cl->next;
135    }
136
137    while (in) {
138        cl = ngx_alloc_chain_link(pool);
139        if (cl == NULL) {
140            return NGX_ERROR;
141        }
142
143        cl->buf = in->buf;
144        *ll = cl;
145        ll = &cl->next;
146        in = in->next;
147    }
148
149    *ll = NULL;
150
151    return NGX_OK;
152}
153
154
155ngx_chain_t *
156ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free)
157{
158    ngx_chain_t  *cl;
159
160    if (*free) {
161        cl = *free;
162        *free = cl->next;
163        cl->next = NULL;
164        return cl;
165    }
166
167    cl = ngx_alloc_chain_link(p);
168    if (cl == NULL) {
169        return NULL;
170    }
171
172    cl->buf = ngx_calloc_buf(p);
173    if (cl->buf == NULL) {
174        return NULL;
175    }
176
177    cl->next = NULL;
178
179    return cl;
180}
181
182
183void
184ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
185    ngx_chain_t **out, ngx_buf_tag_t tag)
186{
187    ngx_chain_t  *cl;
188
189    if (*out) {
190        if (*busy == NULL) {
191            *busy = *out;
192
193        } else {
194            for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
195
196            cl->next = *out;
197        }
198
199        *out = NULL;
200    }
201
202    while (*busy) {
203        cl = *busy;
204
205        if (ngx_buf_size(cl->buf) != 0) {
206            break;
207        }
208
209        if (cl->buf->tag != tag) {
210            *busy = cl->next;
211            ngx_free_chain(p, cl);
212            continue;
213        }
214
215        cl->buf->pos = cl->buf->start;
216        cl->buf->last = cl->buf->start;
217
218        *busy = cl->next;
219        cl->next = *free;
220        *free = cl;
221    }
222}
223
224
225off_t
226ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit)
227{
228    off_t         total, size, aligned, fprev;
229    ngx_fd_t      fd;
230    ngx_chain_t  *cl;
231
232    total = 0;
233
234    cl = *in;
235    fd = cl->buf->file->fd;
236
237    do {
238        size = cl->buf->file_last - cl->buf->file_pos;
239
240        if (size > limit - total) {
241            size = limit - total;
242
243            aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
244                       & ~((off_t) ngx_pagesize - 1);
245
246            if (aligned <= cl->buf->file_last) {
247                size = aligned - cl->buf->file_pos;
248            }
249
250            total += size;
251            break;
252        }
253
254        total += size;
255        fprev = cl->buf->file_pos + size;
256        cl = cl->next;
257
258    } while (cl
259             && cl->buf->in_file
260             && total < limit
261             && fd == cl->buf->file->fd
262             && fprev == cl->buf->file_pos);
263
264    *in = cl;
265
266    return total;
267}
268
269
270ngx_chain_t *
271ngx_chain_update_sent(ngx_chain_t *in, off_t sent)
272{
273    off_t  size;
274
275    for ( /* void */ ; in; in = in->next) {
276
277        if (ngx_buf_special(in->buf)) {
278            continue;
279        }
280
281        if (sent == 0) {
282            break;
283        }
284
285        size = ngx_buf_size(in->buf);
286
287        if (sent >= size) {
288            sent -= size;
289
290            if (ngx_buf_in_memory(in->buf)) {
291                in->buf->pos = in->buf->last;
292            }
293
294            if (in->buf->in_file) {
295                in->buf->file_pos = in->buf->file_last;
296            }
297
298            continue;
299        }
300
301        if (ngx_buf_in_memory(in->buf)) {
302            in->buf->pos += (size_t) sent;
303        }
304
305        if (in->buf->in_file) {
306            in->buf->file_pos += sent;
307        }
308
309        break;
310    }
311
312    return in;
313}
314