diff options
author | Torsten Marek <shlomme@debian.org> | 2005-11-27 14:39:54 +0000 |
---|---|---|
committer | Torsten Marek <shlomme@debian.org> | 2005-11-27 14:39:54 +0000 |
commit | 701d5359518f46aadc89655d38ff91e6eae4496d (patch) | |
tree | 5e47b76785345f850e9d9d196461d66c3e8e8828 /src/chunk.c | |
download | lighttpd-701d5359518f46aadc89655d38ff91e6eae4496d.tar.gz |
[svn-inject] Installing original source of lighttpd
Diffstat (limited to 'src/chunk.c')
-rw-r--r-- | src/chunk.c | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/src/chunk.c b/src/chunk.c new file mode 100644 index 0000000..3903428 --- /dev/null +++ b/src/chunk.c @@ -0,0 +1,385 @@ +/** + * the network chunk-API + * + * + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/mman.h> + +#include <stdlib.h> +#include <fcntl.h> +#include <unistd.h> + +#include <stdio.h> +#include <errno.h> +#include <string.h> + +#include "chunk.h" + +chunkqueue *chunkqueue_init(void) { + chunkqueue *cq; + + cq = calloc(1, sizeof(*cq)); + + cq->first = NULL; + cq->last = NULL; + + cq->unused = NULL; + + return cq; +} + +static chunk *chunk_init(void) { + chunk *c; + + c = calloc(1, sizeof(*c)); + + c->mem = buffer_init(); + c->file.name = buffer_init(); + c->file.fd = -1; + c->file.mmap.start = MAP_FAILED; + c->next = NULL; + + return c; +} + +static void chunk_free(chunk *c) { + if (!c) return; + + buffer_free(c->mem); + buffer_free(c->file.name); + + free(c); +} + +static void chunk_reset(chunk *c) { + if (!c) return; + + buffer_reset(c->mem); + + if (c->file.is_temp && !buffer_is_empty(c->file.name)) { + unlink(c->file.name->ptr); + } + + buffer_reset(c->file.name); + + if (c->file.fd != -1) { + close(c->file.fd); + c->file.fd = -1; + } + if (MAP_FAILED != c->file.mmap.start) { + munmap(c->file.mmap.start, c->file.mmap.length); + c->file.mmap.start = MAP_FAILED; + } +} + + +void chunkqueue_free(chunkqueue *cq) { + chunk *c, *pc; + + if (!cq) return; + + for (c = cq->first; c; ) { + pc = c; + c = c->next; + chunk_free(pc); + } + + for (c = cq->unused; c; ) { + pc = c; + c = c->next; + chunk_free(pc); + } + + free(cq); +} + +static chunk *chunkqueue_get_unused_chunk(chunkqueue *cq) { + chunk *c; + + /* check if we have a unused chunk */ + if (!cq->unused) { + c = chunk_init(); + } else { + /* take the first element from the list (a stack) */ + c = cq->unused; + cq->unused = c->next; + c->next = NULL; + cq->unused_chunks--; + } + + return c; +} + +static int chunkqueue_prepend_chunk(chunkqueue *cq, chunk *c) { + c->next = cq->first; + cq->first = c; + + if (cq->last == NULL) { + cq->last = c; + } + + return 0; +} + +static int chunkqueue_append_chunk(chunkqueue *cq, chunk *c) { + if (cq->last) { + cq->last->next = c; + } + cq->last = c; + + if (cq->first == NULL) { + cq->first = c; + } + + return 0; +} + +void chunkqueue_reset(chunkqueue *cq) { + chunk *c; + /* move everything to the unused queue */ + + /* mark all read written */ + for (c = cq->first; c; c = c->next) { + switch(c->type) { + case MEM_CHUNK: + c->offset = c->mem->used - 1; + break; + case FILE_CHUNK: + c->offset = c->file.length; + break; + default: + break; + } + } + + chunkqueue_remove_finished_chunks(cq); + cq->bytes_in = 0; + cq->bytes_out = 0; +} + +int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) { + chunk *c; + + if (len == 0) return 0; + + c = chunkqueue_get_unused_chunk(cq); + + c->type = FILE_CHUNK; + + buffer_copy_string_buffer(c->file.name, fn); + c->file.start = offset; + c->file.length = len; + c->offset = 0; + + chunkqueue_append_chunk(cq, c); + + return 0; +} + +int chunkqueue_append_buffer(chunkqueue *cq, buffer *mem) { + chunk *c; + + if (mem->used == 0) return 0; + + c = chunkqueue_get_unused_chunk(cq); + c->type = MEM_CHUNK; + c->offset = 0; + buffer_copy_string_buffer(c->mem, mem); + + chunkqueue_append_chunk(cq, c); + + return 0; +} + +int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) { + chunk *c; + + if (mem->used == 0) return 0; + + c = chunkqueue_get_unused_chunk(cq); + c->type = MEM_CHUNK; + c->offset = 0; + buffer_copy_string_buffer(c->mem, mem); + + chunkqueue_prepend_chunk(cq, c); + + return 0; +} + +int chunkqueue_append_mem(chunkqueue *cq, const char * mem, size_t len) { + chunk *c; + + if (len == 0) return 0; + + c = chunkqueue_get_unused_chunk(cq); + c->type = MEM_CHUNK; + c->offset = 0; + buffer_copy_string_len(c->mem, mem, len - 1); + + chunkqueue_append_chunk(cq, c); + + return 0; +} + +buffer * chunkqueue_get_prepend_buffer(chunkqueue *cq) { + chunk *c; + + c = chunkqueue_get_unused_chunk(cq); + + c->type = MEM_CHUNK; + c->offset = 0; + buffer_reset(c->mem); + + chunkqueue_prepend_chunk(cq, c); + + return c->mem; +} + +buffer *chunkqueue_get_append_buffer(chunkqueue *cq) { + chunk *c; + + c = chunkqueue_get_unused_chunk(cq); + + c->type = MEM_CHUNK; + c->offset = 0; + buffer_reset(c->mem); + + chunkqueue_append_chunk(cq, c); + + return c->mem; +} + +int chunkqueue_set_tempdirs(chunkqueue *cq, array *tempdirs) { + if (!cq) return -1; + + cq->tempdirs = tempdirs; + + return 0; +} + +chunk *chunkqueue_get_append_tempfile(chunkqueue *cq) { + chunk *c; + buffer *template = buffer_init_string("/var/tmp/lighttpd-upload-XXXXXX"); + + c = chunkqueue_get_unused_chunk(cq); + + c->type = FILE_CHUNK; + c->offset = 0; + + if (cq->tempdirs && cq->tempdirs->used) { + size_t i; + + /* we have several tempdirs, only if all of them fail we jump out */ + + for (i = 0; i < cq->tempdirs->used; i++) { + data_string *ds = (data_string *)cq->tempdirs->data[i]; + + buffer_copy_string_buffer(template, ds->value); + BUFFER_APPEND_SLASH(template); + BUFFER_APPEND_STRING_CONST(template, "lighttpd-upload-XXXXXX"); + + if (-1 != (c->file.fd = mkstemp(template->ptr))) { + /* only trigger the unlink if we created the temp-file successfully */ + c->file.is_temp = 1; + break; + } + } + } else { + if (-1 != (c->file.fd = mkstemp(template->ptr))) { + /* only trigger the unlink if we created the temp-file successfully */ + c->file.is_temp = 1; + } + } + + buffer_copy_string_buffer(c->file.name, template); + c->file.length = 0; + + chunkqueue_append_chunk(cq, c); + + buffer_free(template); + + return c; +} + + +off_t chunkqueue_length(chunkqueue *cq) { + off_t len = 0; + chunk *c; + + for (c = cq->first; c; c = c->next) { + switch (c->type) { + case MEM_CHUNK: + len += c->mem->used ? c->mem->used - 1 : 0; + break; + case FILE_CHUNK: + len += c->file.length; + break; + default: + break; + } + } + + return len; +} + +off_t chunkqueue_written(chunkqueue *cq) { + off_t len = 0; + chunk *c; + + for (c = cq->first; c; c = c->next) { + switch (c->type) { + case MEM_CHUNK: + case FILE_CHUNK: + len += c->offset; + break; + default: + break; + } + } + + return len; +} + +int chunkqueue_is_empty(chunkqueue *cq) { + return cq->first ? 0 : 1; +} + +int chunkqueue_remove_finished_chunks(chunkqueue *cq) { + chunk *c; + + for (c = cq->first; c; c = cq->first) { + int is_finished = 0; + + switch (c->type) { + case MEM_CHUNK: + if (c->offset == (off_t)c->mem->used - 1) is_finished = 1; + break; + case FILE_CHUNK: + if (c->offset == c->file.length) is_finished = 1; + break; + default: + break; + } + + if (!is_finished) break; + + chunk_reset(c); + + cq->first = c->next; + if (c == cq->last) cq->last = NULL; + + /* keep at max 4 chunks in the 'unused'-cache */ + if (cq->unused_chunks > 4) { + chunk_free(c); + } else { + c->next = cq->unused; + cq->unused = c; + cq->unused_chunks++; + } + } + + return 0; +} |