Annotation of embedaddon/lighttpd/src/chunk.c, revision 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>