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>