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>