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 
12 ngx_buf_t *
ngx_create_temp_buf(ngx_pool_t * pool,size_t size)13 ngx_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 
47 ngx_chain_t *
ngx_alloc_chain_link(ngx_pool_t * pool)48 ngx_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 
68 ngx_chain_t *
ngx_create_chain_of_bufs(ngx_pool_t * pool,ngx_bufs_t * bufs)69 ngx_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 
126 ngx_int_t
ngx_chain_add_copy(ngx_pool_t * pool,ngx_chain_t ** chain,ngx_chain_t * in)127 ngx_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             *ll = NULL;
141             return NGX_ERROR;
142         }
143 
144         cl->buf = in->buf;
145         *ll = cl;
146         ll = &cl->next;
147         in = in->next;
148     }
149 
150     *ll = NULL;
151 
152     return NGX_OK;
153 }
154 
155 
156 ngx_chain_t *
ngx_chain_get_free_buf(ngx_pool_t * p,ngx_chain_t ** free)157 ngx_chain_get_free_buf(ngx_pool_t *p, ngx_chain_t **free)
158 {
159     ngx_chain_t  *cl;
160 
161     if (*free) {
162         cl = *free;
163         *free = cl->next;
164         cl->next = NULL;
165         return cl;
166     }
167 
168     cl = ngx_alloc_chain_link(p);
169     if (cl == NULL) {
170         return NULL;
171     }
172 
173     cl->buf = ngx_calloc_buf(p);
174     if (cl->buf == NULL) {
175         return NULL;
176     }
177 
178     cl->next = NULL;
179 
180     return cl;
181 }
182 
183 
184 void
ngx_chain_update_chains(ngx_pool_t * p,ngx_chain_t ** free,ngx_chain_t ** busy,ngx_chain_t ** out,ngx_buf_tag_t tag)185 ngx_chain_update_chains(ngx_pool_t *p, ngx_chain_t **free, ngx_chain_t **busy,
186     ngx_chain_t **out, ngx_buf_tag_t tag)
187 {
188     ngx_chain_t  *cl;
189 
190     if (*out) {
191         if (*busy == NULL) {
192             *busy = *out;
193 
194         } else {
195             for (cl = *busy; cl->next; cl = cl->next) { /* void */ }
196 
197             cl->next = *out;
198         }
199 
200         *out = NULL;
201     }
202 
203     while (*busy) {
204         cl = *busy;
205 
206         if (cl->buf->tag != tag) {
207             *busy = cl->next;
208             ngx_free_chain(p, cl);
209             continue;
210         }
211 
212         if (ngx_buf_size(cl->buf) != 0) {
213             break;
214         }
215 
216         cl->buf->pos = cl->buf->start;
217         cl->buf->last = cl->buf->start;
218 
219         *busy = cl->next;
220         cl->next = *free;
221         *free = cl;
222     }
223 }
224 
225 
226 off_t
ngx_chain_coalesce_file(ngx_chain_t ** in,off_t limit)227 ngx_chain_coalesce_file(ngx_chain_t **in, off_t limit)
228 {
229     off_t         total, size, aligned, fprev;
230     ngx_fd_t      fd;
231     ngx_chain_t  *cl;
232 
233     total = 0;
234 
235     cl = *in;
236     fd = cl->buf->file->fd;
237 
238     do {
239         size = cl->buf->file_last - cl->buf->file_pos;
240 
241         if (size > limit - total) {
242             size = limit - total;
243 
244             aligned = (cl->buf->file_pos + size + ngx_pagesize - 1)
245                        & ~((off_t) ngx_pagesize - 1);
246 
247             if (aligned <= cl->buf->file_last) {
248                 size = aligned - cl->buf->file_pos;
249             }
250 
251             total += size;
252             break;
253         }
254 
255         total += size;
256         fprev = cl->buf->file_pos + size;
257         cl = cl->next;
258 
259     } while (cl
260              && cl->buf->in_file
261              && total < limit
262              && fd == cl->buf->file->fd
263              && fprev == cl->buf->file_pos);
264 
265     *in = cl;
266 
267     return total;
268 }
269 
270 
271 ngx_chain_t *
ngx_chain_update_sent(ngx_chain_t * in,off_t sent)272 ngx_chain_update_sent(ngx_chain_t *in, off_t sent)
273 {
274     off_t  size;
275 
276     for ( /* void */ ; in; in = in->next) {
277 
278         if (ngx_buf_special(in->buf)) {
279             continue;
280         }
281 
282         if (sent == 0) {
283             break;
284         }
285 
286         size = ngx_buf_size(in->buf);
287 
288         if (sent >= size) {
289             sent -= size;
290 
291             if (ngx_buf_in_memory(in->buf)) {
292                 in->buf->pos = in->buf->last;
293             }
294 
295             if (in->buf->in_file) {
296                 in->buf->file_pos = in->buf->file_last;
297             }
298 
299             continue;
300         }
301 
302         if (ngx_buf_in_memory(in->buf)) {
303             in->buf->pos += (size_t) sent;
304         }
305 
306         if (in->buf->in_file) {
307             in->buf->file_pos += sent;
308         }
309 
310         break;
311     }
312 
313     return in;
314 }
315