Annotation of embedaddon/lighttpd/src/chunk.c, revision 1.1.1.1
1.1 misho 1: /**
2: * the network chunk-API
3: *
4: *
5: */
6:
7: #include "chunk.h"
8:
9: #include <sys/types.h>
10: #include <sys/stat.h>
11: #include <sys/mman.h>
12:
13: #include <stdlib.h>
14: #include <fcntl.h>
15: #include <unistd.h>
16:
17: #include <stdio.h>
18: #include <errno.h>
19: #include <string.h>
20:
21: chunkqueue *chunkqueue_init(void) {
22: chunkqueue *cq;
23:
24: cq = calloc(1, sizeof(*cq));
25:
26: cq->first = NULL;
27: cq->last = NULL;
28:
29: cq->unused = NULL;
30:
31: return cq;
32: }
33:
34: static chunk *chunk_init(void) {
35: chunk *c;
36:
37: c = calloc(1, sizeof(*c));
38:
39: c->mem = buffer_init();
40: c->file.name = buffer_init();
41: c->file.fd = -1;
42: c->file.mmap.start = MAP_FAILED;
43: c->next = NULL;
44:
45: return c;
46: }
47:
48: static void chunk_free(chunk *c) {
49: if (!c) return;
50:
51: buffer_free(c->mem);
52: buffer_free(c->file.name);
53:
54: free(c);
55: }
56:
57: static void chunk_reset(chunk *c) {
58: if (!c) return;
59:
60: buffer_reset(c->mem);
61:
62: if (c->file.is_temp && !buffer_is_empty(c->file.name)) {
63: unlink(c->file.name->ptr);
64: }
65:
66: buffer_reset(c->file.name);
67:
68: if (c->file.fd != -1) {
69: close(c->file.fd);
70: c->file.fd = -1;
71: }
72: if (MAP_FAILED != c->file.mmap.start) {
73: munmap(c->file.mmap.start, c->file.mmap.length);
74: c->file.mmap.start = MAP_FAILED;
75: }
76: }
77:
78:
79: void chunkqueue_free(chunkqueue *cq) {
80: chunk *c, *pc;
81:
82: if (!cq) return;
83:
84: for (c = cq->first; c; ) {
85: pc = c;
86: c = c->next;
87: chunk_free(pc);
88: }
89:
90: for (c = cq->unused; c; ) {
91: pc = c;
92: c = c->next;
93: chunk_free(pc);
94: }
95:
96: free(cq);
97: }
98:
99: static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) {
100: chunk *c;
101:
102: /* check if we have a unused chunk */
103: if (!cq->unused) {
104: c = chunk_init();
105: } else {
106: /* take the first element from the list (a stack) */
107: c = cq->unused;
108: cq->unused = c->next;
109: c->next = NULL;
110: cq->unused_chunks--;
111: }
112:
113: return c;
114: }
115:
116: static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) {
117: c->next = cq->first;
118: cq->first = c;
119:
120: if (cq->last == NULL) {
121: cq->last = c;
122: }
123:
124: return 0;
125: }
126:
127: static int chunkqueue_append_chunk(chunkqueue *cq, chunk *c) {
128: if (cq->last) {
129: cq->last->next = c;
130: }
131: cq->last = c;
132:
133: if (cq->first == NULL) {
134: cq->first = c;
135: }
136:
137: return 0;
138: }
139:
140: void chunkqueue_reset(chunkqueue *cq) {
141: chunk *c;
142: /* move everything to the unused queue */
143:
144: /* mark all read written */
145: for (c = cq->first; c; c = c->next) {
146: switch(c->type) {
147: case MEM_CHUNK:
148: c->offset = c->mem->used - 1;
149: break;
150: case FILE_CHUNK:
151: c->offset = c->file.length;
152: break;
153: default:
154: break;
155: }
156: }
157:
158: chunkqueue_remove_finished_chunks(cq);
159: cq->bytes_in = 0;
160: cq->bytes_out = 0;
161: }
162:
163: int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
164: chunk *c;
165:
166: if (len == 0) return 0;
167:
168: c = chunkqueue_get_unused_chunk(cq);
169:
170: c->type = FILE_CHUNK;
171:
172: buffer_copy_string_buffer(c->file.name, fn);
173: c->file.start = offset;
174: c->file.length = len;
175: c->offset = 0;
176:
177: chunkqueue_append_chunk(cq, c);
178:
179: return 0;
180: }
181:
182: int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) {
183: chunk *c;
184:
185: if (mem->used == 0) return 0;
186:
187: c = chunkqueue_get_unused_chunk(cq);
188: c->type = MEM_CHUNK;
189: c->offset = 0;
190: buffer_copy_string_buffer(c->mem, mem);
191:
192: chunkqueue_append_chunk(cq, c);
193:
194: return 0;
195: }
196:
197: int chunkqueue_append_buffer_weak(chunkqueue *cq, buffer *mem) {
198: chunk *c;
199:
200: c = chunkqueue_get_unused_chunk(cq);
201: c->type = MEM_CHUNK;
202: c->offset = 0;
203: if (c->mem) buffer_free(c->mem);
204: c->mem = mem;
205:
206: chunkqueue_append_chunk(cq, c);
207:
208: return 0;
209: }
210:
211: int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
212: chunk *c;
213:
214: if (mem->used == 0) return 0;
215:
216: c = chunkqueue_get_unused_chunk(cq);
217: c->type = MEM_CHUNK;
218: c->offset = 0;
219: buffer_copy_string_buffer(c->mem, mem);
220:
221: chunkqueue_prepend_chunk(cq, c);
222:
223: return 0;
224: }
225:
226:
227: int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) {
228: chunk *c;
229:
230: if (len == 0) return 0;
231:
232: c = chunkqueue_get_unused_chunk(cq);
233: c->type = MEM_CHUNK;
234: c->offset = 0;
235: buffer_copy_string_len(c->mem, mem, len - 1);
236:
237: chunkqueue_append_chunk(cq, c);
238:
239: return 0;
240: }
241:
242: buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) {
243: chunk *c;
244:
245: c = chunkqueue_get_unused_chunk(cq);
246:
247: c->type = MEM_CHUNK;
248: c->offset = 0;
249: buffer_reset(c->mem);
250:
251: chunkqueue_prepend_chunk(cq, c);
252:
253: return c->mem;
254: }
255:
256: buffer *chunkqueue_get_append_buffer(chunkqueue *cq) {
257: chunk *c;
258:
259: c = chunkqueue_get_unused_chunk(cq);
260:
261: c->type = MEM_CHUNK;
262: c->offset = 0;
263: buffer_reset(c->mem);
264:
265: chunkqueue_append_chunk(cq, c);
266:
267: return c->mem;
268: }
269:
270: int chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) {
271: if (!cq) return -1;
272:
273: cq->tempdirs = tempdirs;
274:
275: return 0;
276: }
277:
278: chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) {
279: chunk *c;
280: buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX");
281:
282: c = chunkqueue_get_unused_chunk(cq);
283:
284: c->type = FILE_CHUNK;
285: c->offset = 0;
286:
287: if (cq->tempdirs && cq->tempdirs->used) {
288: size_t i;
289:
290: /* we have several tempdirs, only if all of them fail we jump out */
291:
292: for (i = 0; i < cq->tempdirs->used; i++) {
293: data_string *ds = (data_string *)cq->tempdirs->data[i];
294:
295: buffer_copy_string_buffer(template, ds->value);
296: BUFFER_APPEND_SLASH(template);
297: buffer_append_string_len(template, CONST_STR_LEN("lighttpd-upload-XXXXXX"));
298:
299: if (-1 != (c->file.fd = mkstemp(template->ptr))) {
300: /* only trigger the unlink if we created the temp-file successfully */
301: c->file.is_temp = 1;
302: break;
303: }
304: }
305: } else {
306: if (-1 != (c->file.fd = mkstemp(template->ptr))) {
307: /* only trigger the unlink if we created the temp-file successfully */
308: c->file.is_temp = 1;
309: }
310: }
311:
312: buffer_copy_string_buffer(c->file.name, template);
313: c->file.length = 0;
314:
315: chunkqueue_append_chunk(cq, c);
316:
317: buffer_free(template);
318:
319: return c;
320: }
321:
322:
323: off_t chunkqueue_length(chunkqueue *cq) {
324: off_t len = 0;
325: chunk *c;
326:
327: for (c = cq->first; c; c = c->next) {
328: switch (c->type) {
329: case MEM_CHUNK:
330: len += c->mem->used ? c->mem->used - 1 : 0;
331: break;
332: case FILE_CHUNK:
333: len += c->file.length;
334: break;
335: default:
336: break;
337: }
338: }
339:
340: return len;
341: }
342:
343: off_t chunkqueue_written(chunkqueue *cq) {
344: off_t len = 0;
345: chunk *c;
346:
347: for (c = cq->first; c; c = c->next) {
348: switch (c->type) {
349: case MEM_CHUNK:
350: case FILE_CHUNK:
351: len += c->offset;
352: break;
353: default:
354: break;
355: }
356: }
357:
358: return len;
359: }
360:
361: int chunkqueue_is_empty(chunkqueue *cq) {
362: return cq->first ? 0 : 1;
363: }
364:
365: int chunkqueue_remove_finished_chunks(chunkqueue *cq) {
366: chunk *c;
367:
368: for (c = cq->first; c; c = cq->first) {
369: int is_finished = 0;
370:
371: switch (c->type) {
372: case MEM_CHUNK:
373: if (c->mem->used == 0 || (c->offset == (off_t)c->mem->used - 1)) is_finished = 1;
374: break;
375: case FILE_CHUNK:
376: if (c->offset == c->file.length) is_finished = 1;
377: break;
378: default:
379: break;
380: }
381:
382: if (!is_finished) break;
383:
384: chunk_reset(c);
385:
386: cq->first = c->next;
387: if (c == cq->last) cq->last = NULL;
388:
389: /* keep at max 4 chunks in the 'unused'-cache */
390: if (cq->unused_chunks > 4) {
391: chunk_free(c);
392: } else {
393: c->next = cq->unused;
394: cq->unused = c;
395: cq->unused_chunks++;
396: }
397: }
398:
399: return 0;
400: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>