1 /*
2 * Copyright (C) 2004-2008 Christos Tsantilas
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1301 USA.
18 */
19
20 #include "common.h"
21 #include "c-icap.h"
22 #include <stdio.h>
23 #include "body.h"
24 #include "debug.h"
25 #include "simple_api.h"
26 #include "util.h"
27 #include <assert.h>
28 #include <errno.h>
29 #ifdef _WIN32
30 #include <io.h>
31 #include <fcntl.h>
32 #endif
33 #if defined USE_POSIX_MAPPED_FILES
34 #include <sys/mman.h>
35 #endif
36
37
38 #define STARTLEN 8192 /*8*1024*1024 */
39 #define INCSTEP 4096
40
41 #define min(x,y) ((x)>(y)?(y):(x))
42 #define max(x,y) ((x)>(y)?(x):(y))
43
44 static int MEMBUF_POOL = -1;
45 static int CACHED_FILE_POOL = -1;
46 static int SIMPLE_FILE_POOL = -1;
47 static int RING_BUF_POOL = -1;
48
init_body_system()49 CI_DECLARE_FUNC(int) init_body_system()
50 {
51 MEMBUF_POOL = ci_object_pool_register("ci_membuf_t",
52 sizeof(ci_membuf_t));
53 if (MEMBUF_POOL < 0)
54 return CI_ERROR;
55
56 CACHED_FILE_POOL = ci_object_pool_register("ci_cached_file_t",
57 sizeof(ci_cached_file_t));
58 if (CACHED_FILE_POOL < 0)
59 return CI_ERROR;
60
61 SIMPLE_FILE_POOL = ci_object_pool_register("ci_simple_file_t",
62 sizeof(ci_simple_file_t));
63 if (SIMPLE_FILE_POOL < 0)
64 return CI_ERROR;
65
66 RING_BUF_POOL = ci_object_pool_register("ci_ring_buf_t",
67 sizeof(ci_ring_buf_t));
68 if (RING_BUF_POOL < 0)
69 return CI_ERROR;
70
71 return CI_OK;
72 }
73
release_body_system()74 void release_body_system()
75 {
76 ci_object_pool_unregister(MEMBUF_POOL);
77 ci_object_pool_unregister(CACHED_FILE_POOL);
78 ci_object_pool_unregister(SIMPLE_FILE_POOL);
79 ci_object_pool_unregister(RING_BUF_POOL);
80 }
81
ci_membuf_new()82 struct ci_membuf *ci_membuf_new()
83 {
84 return ci_membuf_new_sized(STARTLEN);
85 }
86
ci_membuf_new_sized(int size)87 struct ci_membuf *ci_membuf_new_sized(int size)
88 {
89 struct ci_membuf *b;
90 b = ci_object_pool_alloc(MEMBUF_POOL);
91 if (!b)
92 return NULL;
93
94 b->endpos = 0;
95 b->readpos = 0;
96 b->flags = 0;
97 b->buf = ci_buffer_alloc(size * sizeof(char));
98 if (b->buf == NULL) {
99 ci_object_pool_free(b);
100 return NULL;
101 }
102 b->bufsize = size;
103 b->unlocked = -1;
104 b->attributes = NULL;
105 return b;
106 }
107
ci_membuf_from_content(char * buf,size_t buf_size,size_t content_size,unsigned int flags)108 struct ci_membuf *ci_membuf_from_content(char *buf, size_t buf_size, size_t content_size, unsigned int flags)
109 {
110 struct ci_membuf *b;
111
112 if (!buf || buf_size <= 0 || buf_size < content_size) {
113 ci_debug_printf(1, "ci_membuf_from_content: Wrong arguments: %p, of size=%u and content size=%u\n", buf, (unsigned int)buf_size, (unsigned int)content_size);
114 return NULL;
115 }
116
117 if ((flags & CI_MEMBUF_FROM_CONTENT_FLAGS) != flags) {
118 ci_debug_printf(1, "ci_membuf_from_content: Wrong flags: %u\n", flags);
119 return NULL;
120 }
121
122 if ((flags & CI_MEMBUF_NULL_TERMINATED)) {
123 if (buf[content_size - 1] == '\0')
124 content_size--;
125 else if (content_size >= buf_size || buf[content_size] != '\0') {
126 ci_debug_printf(1, "ci_membuf_from_content: content is not NULL terminated!\n");
127 return NULL;
128 }
129 }
130
131 b = ci_object_pool_alloc(MEMBUF_POOL);
132 if (!b) {
133 ci_debug_printf(1, "ci_membuf_from_content: memory allocation failed\n");
134 return NULL;
135 }
136
137 b->flags = CI_MEMBUF_FOREIGN_BUF | flags;
138 b->endpos = content_size;
139 b->readpos = 0;
140 b->buf = buf;
141 b->bufsize = buf_size;
142 b->unlocked = -1;
143 b->attributes = NULL;
144 return b;
145 }
146
ci_membuf_free(struct ci_membuf * b)147 void ci_membuf_free(struct ci_membuf *b)
148 {
149 if (!b)
150 return;
151 if (b->buf && !(b->flags & CI_MEMBUF_FOREIGN_BUF))
152 ci_buffer_free(b->buf);
153 if (b->attributes)
154 ci_array_destroy(b->attributes);
155 ci_object_pool_free(b);
156 }
157
ci_membuf_set_flag(struct ci_membuf * body,unsigned int flag)158 unsigned int ci_membuf_set_flag(struct ci_membuf *body, unsigned int flag)
159 {
160 if (!(flag & CI_MEMBUF_USER_FLAGS))
161 return 0;
162
163 body->flags |= flag;
164 return body->flags;
165 }
166
ci_membuf_write(struct ci_membuf * b,const char * data,int len,int iseof)167 int ci_membuf_write(struct ci_membuf *b, const char *data, int len, int iseof)
168 {
169 int remains, newsize;
170 char *newbuf;
171 int terminate = b->flags & CI_MEMBUF_NULL_TERMINATED;
172
173 if ((b->flags & CI_MEMBUF_RO) || (b->flags & CI_MEMBUF_CONST)) {
174 ci_debug_printf(1, "ci_membuf_write: can not write: buffer is read-only!\n");
175 return 0;
176 }
177
178 if ((b->flags & CI_MEMBUF_HAS_EOF)) {
179 if (len > 0) {
180 ci_debug_printf(1, "Cannot write to membuf: the eof flag is set!\n");
181 }
182 return 0;
183 }
184
185 if (iseof) {
186 b->flags |= CI_MEMBUF_HAS_EOF;
187 /* ci_debug_printf(10,"Buffer size=%d, Data size=%d\n ",
188 ((struct membuf *)b)->bufsize,((struct membuf *)b)->endpos);
189 */
190 }
191
192 remains = b->bufsize - b->endpos - (terminate ? 1 : 0);
193 assert(remains >= -1); /*can be -1 when NULL_TERMINATED flag just set by user and no space to*/
194
195 while (remains < len) {
196 newsize = b->bufsize + INCSTEP;
197 newbuf = ci_buffer_realloc(b->buf, newsize);
198 if (newbuf == NULL) {
199 ci_debug_printf(1, "ci_membuf_write: Failed to grow membuf for new data!\n");
200 if (remains >= 0) {
201 if (remains)
202 memcpy(b->buf + b->endpos, data, remains);
203 if (terminate) {
204 b->endpos = b->bufsize - 1;
205 b->buf[b->endpos] = '\0';
206 } else
207 b->endpos = b->bufsize;
208 } else {
209 ci_debug_printf(1, "ci_membuf_write: Failed to NULL terminate membuf!\n");
210 }
211 return remains;
212 }
213 b->buf = newbuf;
214 b->bufsize = newsize;
215 remains = b->bufsize - b->endpos - (terminate ? 1 : 0);
216 } /*while remains<len */
217 if (len) {
218 memcpy(b->buf + b->endpos, data, len);
219 b->endpos += len;
220 }
221 if (terminate)
222 b->buf[b->endpos] = '\0';
223
224 return len;
225 }
226
ci_membuf_read(struct ci_membuf * b,char * data,int len)227 int ci_membuf_read(struct ci_membuf *b, char *data, int len)
228 {
229 int remains, copybytes;
230 if (b->unlocked >= 0)
231 remains = b->unlocked - b->readpos;
232 else
233 remains = b->endpos - b->readpos;
234 assert(remains >= 0);
235 if (remains == 0 && (b->flags & CI_MEMBUF_HAS_EOF))
236 return CI_EOF;
237 copybytes = (len <= remains ? len : remains);
238 if (copybytes) {
239 memcpy(data, b->buf + b->readpos, copybytes);
240 b->readpos += copybytes;
241 }
242
243 return copybytes;
244 }
245
246 #define BODY_ATTRS_SIZE 1024
ci_membuf_attr_add(struct ci_membuf * body,const char * attr,const void * val,size_t val_size)247 int ci_membuf_attr_add(struct ci_membuf *body,const char *attr, const void *val, size_t val_size)
248 {
249
250 if (!body->attributes)
251 body->attributes = ci_array_new(BODY_ATTRS_SIZE);
252
253 if (body->attributes)
254 return (ci_array_add(body->attributes, attr, val, val_size) != NULL);
255
256 return 0;
257 }
258
ci_membuf_attr_get(struct ci_membuf * body,const char * attr)259 const void * ci_membuf_attr_get(struct ci_membuf *body,const char *attr)
260 {
261 if (body->attributes)
262 return ci_array_search(body->attributes, attr);
263 return NULL;
264 }
265
ci_membuf_truncate(struct ci_membuf * body,int new_size)266 int ci_membuf_truncate(struct ci_membuf *body, int new_size)
267 {
268 if (body->endpos < new_size)
269 return 0;
270 body->endpos = new_size;
271
272 if (body->flags & CI_MEMBUF_NULL_TERMINATED)
273 body->buf[body->endpos] = '\0';
274
275 if (body->readpos > body->endpos)
276 body->readpos = body->endpos;
277
278 if (body->unlocked > body->endpos)
279 body->unlocked = body->endpos;
280
281 return 1;
282 }
283
284 /****/
do_write(int fd,const void * buf,size_t count)285 int do_write(int fd, const void *buf, size_t count)
286 {
287 int bytes;
288 errno = 0;
289 do {
290 bytes = write(fd, buf, count);
291 } while (bytes < 0 && errno == EINTR);
292
293 return bytes;
294 }
295
do_read(int fd,void * buf,size_t count)296 int do_read(int fd, void *buf, size_t count)
297 {
298 int bytes;
299 errno = 0;
300 do {
301 bytes = read(fd, buf, count);
302 } while (bytes < 0 && errno == EINTR);
303
304 return bytes;
305 }
306
307 #ifdef _WIN32
308 #define F_PERM S_IREAD|S_IWRITE
309 #else
310 #define F_PERM S_IREAD|S_IWRITE|S_IRGRP|S_IROTH
311 #endif
312
do_open(const char * pathname,int flags)313 int do_open(const char *pathname, int flags)
314 {
315 int fd;
316 errno = 0;
317 do {
318 fd = open(pathname, flags, F_PERM);
319 } while (fd < 0 && errno == EINTR);
320
321 return fd;
322 }
323
do_close(int fd)324 void do_close(int fd)
325 {
326 errno = 0;
327 while (close(fd) < 0 && errno == EINTR);
328 }
329
330 /**************************************************************************/
331 /* */
332 /* */
333
334 #define tmp_template "CI_TMP_XXXXXX"
335
336 /*
337 extern int BODY_MAX_MEM;
338 extern char *TMPDIR;
339 */
340
341 int CI_BODY_MAX_MEM = 131072;
342 char *CI_TMPDIR = "/var/tmp/";
343
344 /*
345 int open_tmp_file(char *tmpdir,char *filename){
346 return ci_mktemp_file(tmpdir,tmp_template,filename);
347 }
348 */
349
resize_buffer(ci_cached_file_t * body,int new_size)350 int resize_buffer(ci_cached_file_t * body, int new_size)
351 {
352 char *newbuf;
353
354 if (new_size < body->bufsize)
355 return 1;
356 if (new_size > CI_BODY_MAX_MEM)
357 return 0;
358
359 newbuf = ci_buffer_realloc(body->buf, new_size);
360 if (newbuf) {
361 body->buf = newbuf;
362 body->bufsize = new_size;
363 }
364 return 1;
365 }
366
ci_cached_file_new(int size)367 ci_cached_file_t *ci_cached_file_new(int size)
368 {
369 ci_cached_file_t *body;
370 if (!(body = ci_object_pool_alloc(CACHED_FILE_POOL)))
371 return NULL;
372
373 if (size == 0)
374 size = CI_BODY_MAX_MEM;
375
376 if (size > 0 && size <= CI_BODY_MAX_MEM) {
377 body->buf = ci_buffer_alloc(size * sizeof(char));
378 } else
379 body->buf = NULL;
380
381 if (body->buf == NULL) {
382 body->bufsize = 0;
383 if ((body->fd =
384 ci_mktemp_file(CI_TMPDIR, tmp_template, body->filename)) < 0) {
385 ci_debug_printf(1,
386 "Can not open temporary filename in directory:%s\n",
387 CI_TMPDIR);
388 ci_object_pool_free(body);
389 return NULL;
390 }
391 } else {
392 body->bufsize = size;
393 body->fd = -1;
394 }
395 body->endpos = 0;
396 body->readpos = 0;
397 body->flags = 0;
398 body->unlocked = 0;
399 body->attributes = NULL;
400 return body;
401 }
402
ci_cached_file_reset(ci_cached_file_t * body,int new_size)403 void ci_cached_file_reset(ci_cached_file_t * body, int new_size)
404 {
405
406 if (body->fd > 0) {
407 do_close(body->fd);
408 unlink(body->filename); /*Comment out for debuging reasons */
409 }
410
411 body->endpos = 0;
412 body->readpos = 0;
413 body->flags = 0;
414 body->unlocked = 0;
415 body->fd = -1;
416
417 if (body->attributes)
418 ci_array_destroy(body->attributes);
419 body->attributes = NULL;
420
421 if (!resize_buffer(body, new_size)) {
422 /*free memory and open a file. */
423 }
424 }
425
426
427
ci_cached_file_destroy(ci_cached_file_t * body)428 void ci_cached_file_destroy(ci_cached_file_t * body)
429 {
430 if (!body)
431 return;
432 if (body->buf)
433 ci_buffer_free(body->buf);
434
435 if (body->fd >= 0) {
436 do_close(body->fd);
437 unlink(body->filename); /*Comment out for debuging reasons */
438 }
439
440 if (body->attributes)
441 ci_array_destroy(body->attributes);
442
443 ci_object_pool_free(body);
444 }
445
446
ci_cached_file_release(ci_cached_file_t * body)447 void ci_cached_file_release(ci_cached_file_t * body)
448 {
449 if (!body)
450 return;
451 if (body->buf)
452 ci_buffer_free(body->buf);
453
454 if (body->fd >= 0) {
455 do_close(body->fd);
456 }
457
458 if (body->attributes)
459 ci_array_destroy(body->attributes);
460
461 ci_object_pool_free(body);
462 }
463
464
465
ci_cached_file_write(ci_cached_file_t * body,const char * buf,int len,int iseof)466 int ci_cached_file_write(ci_cached_file_t * body, const char *buf, int len, int iseof)
467 {
468 int remains;
469 int ret;
470
471 if (iseof) {
472 body->flags |= CI_FILE_HAS_EOF;
473 ci_debug_printf(10, "Buffer size=%d, Data size=%" PRINTF_OFF_T "\n ",
474 ((ci_cached_file_t *) body)->bufsize,
475 (CAST_OFF_T) ((ci_cached_file_t *) body)->endpos);
476 }
477
478 if (len == 0) /*If no data to write just return 0;*/
479 return 0;
480
481 if (body->fd > 0) { /*A file was open so write the data at the end of file....... */
482 lseek(body->fd, 0, SEEK_END);
483 if ((ret = do_write(body->fd, buf, len)) < 0) {
484 ci_debug_printf(1, "Cannot write to file!!! (errno=%d)\n",
485 errno);
486 }
487 body->endpos += len;
488 return len;
489 }
490
491 remains = body->bufsize - body->endpos;
492 assert(remains >= 0);
493 if (remains < len) {
494
495 if ((body->fd =
496 ci_mktemp_file(CI_TMPDIR, tmp_template, body->filename)) < 0) {
497 ci_debug_printf(1,
498 "I cannot create the temporary file: %s!!!!!!\n",
499 body->filename);
500 return -1;
501 }
502 ret = do_write(body->fd, body->buf, body->endpos);
503 if (ret >= 0 && do_write(body->fd, buf, len) >= 0) {
504 body->endpos += len;
505 return len;
506 } else {
507 ci_debug_printf(1, "Cannot write to cachefile: %s\n", strerror(errno));
508 return CI_ERROR;
509 }
510 } /* if remains<len */
511
512 if (len > 0) {
513 memcpy(body->buf + body->endpos, buf, len);
514 body->endpos += len;
515 }
516 return len;
517
518 }
519
520 /*
521 body->unlocked=?
522 */
523
ci_cached_file_read(ci_cached_file_t * body,char * buf,int len)524 int ci_cached_file_read(ci_cached_file_t * body, char *buf, int len)
525 {
526 int remains, bytes;
527
528 if ((body->readpos == body->endpos) && (body->flags & CI_FILE_HAS_EOF))
529 return CI_EOF;
530
531 if (len == 0) /*If no data to read just return 0*/
532 return 0;
533
534
535 if (body->fd > 0) {
536 if ((body->flags & CI_FILE_USELOCK) && body->unlocked >= 0)
537 remains = body->unlocked - body->readpos;
538 else
539 remains = len;
540
541 assert(remains >= 0);
542
543 bytes = (remains > len ? len : remains); /*Number of bytes that we are going to read from file..... */
544
545 lseek(body->fd, body->readpos, SEEK_SET);
546 if ((bytes = do_read(body->fd, buf, bytes)) > 0)
547 body->readpos += bytes;
548 return bytes;
549 }
550
551 if ((body->flags & CI_FILE_USELOCK) && body->unlocked >= 0)
552 remains = body->unlocked - body->readpos;
553 else
554 remains = body->endpos - body->readpos;
555
556 assert(remains >= 0);
557
558 bytes = (len <= remains ? len : remains);
559 if (bytes > 0) {
560 memcpy(buf, body->buf + body->readpos, bytes);
561 body->readpos += bytes;
562 } else { /*?????????????????????????????? */
563 bytes = 0;
564 ci_debug_printf(10, "Read 0, %" PRINTF_OFF_T " %" PRINTF_OFF_T "\n",
565 (CAST_OFF_T) body->readpos, (CAST_OFF_T) body->endpos);
566 }
567 return bytes;
568 }
569
570
571 /********************************************************************************/
572 /*ci_simple_file function implementation */
573
ci_simple_file_new(ci_off_t maxsize)574 ci_simple_file_t *ci_simple_file_new(ci_off_t maxsize)
575 {
576 ci_simple_file_t *body;
577
578 if (!(body = ci_object_pool_alloc(SIMPLE_FILE_POOL)))
579 return NULL;
580
581 if ((body->fd =
582 ci_mktemp_file(CI_TMPDIR, tmp_template, body->filename)) < 0) {
583 char err_buf[512];
584 ci_debug_printf(1,
585 "ci_simple_file_new: Can not open temporary filename in directory:%s (%d/%s)\n", CI_TMPDIR, errno, ci_strerror(errno, err_buf, sizeof(err_buf)));
586 ci_object_pool_free(body);
587 return NULL;
588 }
589 ci_debug_printf(5, "ci_simple_file_new: Use temporary filename: %s\n", body->filename);
590 body->endpos = 0;
591 body->readpos = 0;
592 body->flags = 0;
593 body->unlocked = 0; /*Not use look */
594 body->max_store_size = (maxsize>0?maxsize:0);
595 body->bytes_in = 0;
596 body->bytes_out = 0;
597 body->attributes = NULL;
598 #if defined(USE_POSIX_MAPPED_FILES)
599 body->mmap_addr = NULL;
600 body->mmap_size = 0;
601 #endif
602
603 return body;
604 }
605
606
607
ci_simple_file_named_new(char * dir,char * filename,ci_off_t maxsize)608 ci_simple_file_t *ci_simple_file_named_new(char *dir, char *filename,ci_off_t maxsize)
609 {
610 ci_simple_file_t *body;
611
612 if (!(body = ci_object_pool_alloc(SIMPLE_FILE_POOL)))
613 return NULL;
614
615 if (filename) {
616 snprintf(body->filename, CI_FILENAME_LEN, "%s/%s", dir, filename);
617 if ((body->fd = do_open(body->filename, O_CREAT | O_RDWR | O_EXCL)) < 0) {
618 char err_buf[512];
619 ci_debug_printf(1, "Can not open temporary filename: %s (%d/%s)\n",
620 body->filename,
621 errno,
622 ci_strerror(errno, err_buf, sizeof(err_buf)));
623 ci_object_pool_free(body);
624 return NULL;
625 }
626 } else if ((body->fd = ci_mktemp_file(dir, tmp_template, body->filename)) < 0) {
627 char err_buf[512];
628 ci_debug_printf(1,
629 "Can not open temporary filename in directory: %s (%d/%s)\n",
630 dir,
631 errno,
632 ci_strerror(errno, err_buf, sizeof(err_buf))
633 );
634 ci_object_pool_free(body);
635 return NULL;
636 }
637 body->endpos = 0;
638 body->readpos = 0;
639 body->flags = 0;
640 body->unlocked = 0;
641 body->max_store_size = (maxsize>0?maxsize:0);
642 body->bytes_in = 0;
643 body->bytes_out = 0;
644 body->attributes = NULL;
645 #if defined(USE_POSIX_MAPPED_FILES)
646 body->mmap_addr = NULL;
647 body->mmap_size = 0;
648 #endif
649
650 return body;
651 }
652
653
ci_simple_file_destroy(ci_simple_file_t * body)654 void ci_simple_file_destroy(ci_simple_file_t * body)
655 {
656 if (!body)
657 return;
658
659 if (body->fd >= 0) {
660 do_close(body->fd);
661 unlink(body->filename); /*Comment out for debuging reasons */
662 }
663
664 if (body->attributes)
665 ci_array_destroy(body->attributes);
666
667 #if defined(USE_POSIX_MAPPED_FILES)
668 if (body->mmap_addr)
669 munmap(body->mmap_addr, body->mmap_size);
670 #endif
671
672 ci_object_pool_free(body);
673 }
674
675
ci_simple_file_release(ci_simple_file_t * body)676 void ci_simple_file_release(ci_simple_file_t * body)
677 {
678 if (!body)
679 return;
680
681 if (body->fd >= 0) {
682 do_close(body->fd);
683 }
684
685 if (body->attributes)
686 ci_array_destroy(body->attributes);
687
688 #if defined(USE_POSIX_MAPPED_FILES)
689 if (body->mmap_addr)
690 munmap(body->mmap_addr, body->mmap_size);
691 #endif
692
693 ci_object_pool_free(body);
694 }
695
696
ci_simple_file_write(ci_simple_file_t * body,const char * buf,int len,int iseof)697 int ci_simple_file_write(ci_simple_file_t * body, const char *buf, int len, int iseof)
698 {
699 int ret;
700 int wsize = 0;
701
702 if (body->flags & CI_FILE_HAS_EOF) {
703 if (len > 0) {
704 ci_debug_printf(1, "Cannot write to file: '%s', the eof flag is set!\n", body->filename);
705 }
706 return 0;
707 }
708
709 if (len <= 0) {
710 if (iseof)
711 body->flags |= CI_FILE_HAS_EOF;
712 return 0;
713 }
714
715 if (body->endpos < body->readpos) {
716 wsize = min(body->readpos-body->endpos-1, len);
717 } else if (body->max_store_size && body->endpos >= body->max_store_size) {
718 /*If we are going to entre ring mode. If we are using locking we can not enter ring mode.*/
719 if (body->readpos != 0 && (body->flags & CI_FILE_USELOCK) == 0) {
720 body->endpos = 0;
721 if (!(body->flags & CI_FILE_RING_MODE)) {
722 body->flags |= CI_FILE_RING_MODE;
723 ci_debug_printf(9, "Entering Ring mode!\n");
724 }
725 wsize = min(body->readpos-body->endpos-1, len);
726 } else {
727 if ((body->flags & CI_FILE_USELOCK) != 0)
728 ci_debug_printf(1, "File locked and no space on file for writing data, (Is this a bug?)!\n");
729 return 0;
730 }
731 } else {
732 if (body->max_store_size)
733 wsize = min(body->max_store_size - body->endpos, len);
734 else
735 wsize = len;
736 }
737
738 lseek(body->fd, body->endpos, SEEK_SET);
739 if ((ret = do_write(body->fd, buf, wsize)) < 0) {
740 ci_debug_printf(1, "Cannot write to file: %s\n", strerror(errno));
741 } else {
742 body->endpos += ret;
743 body->bytes_in += ret;
744 }
745
746 if (iseof && ret == len) {
747 body->flags |= CI_FILE_HAS_EOF;
748 ci_debug_printf(9, "Body data size=%" PRINTF_OFF_T "\n ",
749 (CAST_OFF_T) body->endpos);
750 }
751
752 return ret;
753 }
754
755
756
ci_simple_file_read(ci_simple_file_t * body,char * buf,int len)757 int ci_simple_file_read(ci_simple_file_t * body, char *buf, int len)
758 {
759 int remains, bytes;
760
761 if (len <= 0)
762 return 0;
763
764 if (body->readpos == body->endpos) {
765 if ((body->flags & CI_FILE_HAS_EOF)) {
766 ci_debug_printf(9, "Has EOF and no data to read, send EOF\n");
767 return CI_EOF;
768 } else {
769 return 0;
770 }
771 }
772
773 if (body->max_store_size && body->readpos == body->max_store_size) {
774 body->readpos = 0;
775 }
776
777 if ((body->flags & CI_FILE_USELOCK) && body->unlocked >= 0) {
778 remains = body->unlocked - body->readpos;
779 } else if (body->endpos > body->readpos) {
780 remains = body->endpos - body->readpos;
781 } else {
782 if (body->max_store_size) {
783 remains = body->max_store_size - body->readpos;
784 } else {
785 ci_debug_printf(9, "Error? anyway send EOF\n");
786 return CI_EOF;
787 }
788 }
789
790 assert(remains >= 0);
791 bytes = (remains > len ? len : remains); /*Number of bytes that we are going to read from file..... */
792 lseek(body->fd, body->readpos, SEEK_SET);
793 if ((bytes = do_read(body->fd, buf, bytes)) > 0) {
794 body->readpos += bytes;
795 body->bytes_out += bytes;
796 }
797 return bytes;
798
799 }
800
ci_simple_file_truncate(ci_simple_file_t * body,ci_off_t new_size)801 int ci_simple_file_truncate(ci_simple_file_t *body, ci_off_t new_size)
802 {
803 if (new_size > body->endpos)
804 return 0;
805
806 if (new_size == 0) {
807 new_size = lseek(body->fd, 0, SEEK_END);
808 if (new_size > body->endpos) /* ????? */
809 return 0;
810 } else {
811 if (ftruncate(body->fd, new_size) != 0)
812 return 0; /*failed to resize*/
813 }
814
815 body->endpos = new_size;
816
817 if (body->readpos > new_size)
818 body->readpos = new_size;
819
820 if (body->unlocked > new_size)
821 body->unlocked = new_size;
822
823 return 1;
824 }
825
ci_simple_file_to_const_string(ci_simple_file_t * body)826 const char * ci_simple_file_to_const_string(ci_simple_file_t *body)
827 {
828 #if defined(USE_POSIX_MAPPED_FILES)
829 ci_off_t map_size;
830 char *addr = NULL;
831 if (!(body->flags & CI_FILE_HAS_EOF)) {
832 ci_debug_printf(1, "mmap to file: '%s' failed, the eof flag is not set!\n", body->filename);
833 return NULL;
834 }
835
836 /* We need one more byte for string termination*/
837 map_size = body->endpos + 1;
838 if (ftruncate(body->fd, map_size) != 0)
839 return NULL; /*failed to resize*/
840
841 if (body->mmap_addr == NULL) {
842 addr = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, body->fd, 0);
843 if (!addr)
844 return NULL;
845
846 /*Terminate buffer (already terminated by ftruncate?) */
847 addr[map_size - 1] = '\0';
848 body->mmap_addr = addr;
849 body->mmap_size = map_size;
850 }
851 return body->mmap_addr;
852 #else
853 ci_debug_printf( 1, "ci_simple_file_to_const_string: Requires posix mapped files to work, which is not supported.");
854 return NULL;
855 #endif
856 }
857
858 #define CI_MEMBUF_SF_FLAGS (CI_MEMBUF_CONST | CI_MEMBUF_RO | CI_MEMBUF_NULL_TERMINATED)
ci_simple_file_to_membuf(ci_simple_file_t * body,unsigned int flags)859 ci_membuf_t *ci_simple_file_to_membuf(ci_simple_file_t *body, unsigned int flags)
860 {
861 assert((CI_MEMBUF_SF_FLAGS & flags) == flags);
862 assert(flags & CI_MEMBUF_CONST);
863 void *addr = (void *)ci_simple_file_to_const_string(body);
864 if (!addr)
865 return NULL;
866 return ci_membuf_from_content(body->mmap_addr, body->mmap_size, body->endpos, CI_MEMBUF_CONST | CI_MEMBUF_RO | CI_MEMBUF_NULL_TERMINATED | CI_MEMBUF_HAS_EOF);
867 }
868
869 /*******************************************************************/
870 /*ring memory buffer implementation */
871
ci_ring_buf_new(int size)872 struct ci_ring_buf *ci_ring_buf_new(int size)
873 {
874 struct ci_ring_buf *buf = ci_object_pool_alloc(RING_BUF_POOL);
875 if (!buf)
876 return NULL;
877
878 buf->buf = ci_buffer_alloc(size);
879 if (!buf->buf) {
880 ci_object_pool_free(buf);
881 return NULL;
882 }
883
884 buf->end_buf = buf->buf+size-1;
885 buf->read_pos = buf->buf;
886 buf->write_pos = buf->buf;
887 buf->full = 0;
888 return buf;
889 }
890
ci_ring_buf_destroy(struct ci_ring_buf * buf)891 void ci_ring_buf_destroy(struct ci_ring_buf *buf)
892 {
893 ci_buffer_free(buf->buf);
894 ci_object_pool_free(buf);
895 }
896
ci_ring_buf_is_empty(struct ci_ring_buf * buf)897 int ci_ring_buf_is_empty(struct ci_ring_buf *buf)
898 {
899 return (buf->read_pos == buf->write_pos) && (buf->full == 0);
900 }
901
ci_ring_buf_write_block(struct ci_ring_buf * buf,char ** wb,int * len)902 int ci_ring_buf_write_block(struct ci_ring_buf *buf, char **wb, int *len)
903 {
904 if (buf->read_pos == buf->write_pos && buf->full == 0) {
905 *wb = buf->write_pos;
906 *len = buf->end_buf - buf->write_pos + 1;
907 return 0;
908 } else if (buf->read_pos >= buf->write_pos) {
909 *wb = buf->write_pos;
910 *len = buf->read_pos - buf->write_pos;
911 return 0;
912 } else { /*buf->read_pos < buf->write_pos*/
913 *wb = buf->write_pos;
914 *len = buf->end_buf - buf->write_pos + 1;
915 return 1;
916 }
917 }
918
ci_ring_buf_read_block(struct ci_ring_buf * buf,char ** rb,int * len)919 int ci_ring_buf_read_block(struct ci_ring_buf *buf, char **rb, int *len)
920 {
921 if (buf->read_pos == buf->write_pos && buf->full == 0) {
922 *rb = buf->read_pos;
923 *len = 0;
924 return 0;
925 } else if (buf->read_pos >= buf->write_pos) {
926 *rb = buf->read_pos;
927 *len = buf->end_buf - buf->read_pos +1;
928 return (buf->read_pos != buf->buf? 1:0);
929 } else { /*buf->read_pos < buf->write_pos*/
930 *rb = buf->read_pos;
931 *len = buf->write_pos - buf->read_pos;
932 return 0;
933 }
934 }
935
ci_ring_buf_consume(struct ci_ring_buf * buf,int len)936 void ci_ring_buf_consume(struct ci_ring_buf *buf, int len)
937 {
938 if (len <= 0)
939 return;
940 buf->read_pos += len;
941 if (buf->read_pos > buf->end_buf)
942 buf->read_pos = buf->buf;
943 if (buf->full)
944 buf->full = 0;
945 }
946
ci_ring_buf_produce(struct ci_ring_buf * buf,int len)947 void ci_ring_buf_produce(struct ci_ring_buf *buf, int len)
948 {
949 if (len <= 0)
950 return;
951 buf->write_pos += len;
952 if (buf->write_pos > buf->end_buf)
953 buf->write_pos = buf->buf;
954
955 if (buf->write_pos == buf->read_pos)
956 buf->full = 1;
957
958 }
959
ci_ring_buf_write(struct ci_ring_buf * buf,const char * data,int size)960 int ci_ring_buf_write(struct ci_ring_buf *buf, const char *data,int size)
961 {
962 char *wb;
963 int wb_len, ret, written;
964 written = 0;
965 do {
966 ret = ci_ring_buf_write_block(buf, &wb, &wb_len);
967 if (wb_len) {
968 wb_len = min(size, wb_len);
969 memcpy(wb, data, wb_len);
970 ci_ring_buf_produce(buf, wb_len);
971 size -= wb_len;
972 data += wb_len;
973 written += wb_len;
974 }
975 } while ((ret != 0) && (size > 0));
976 return written;
977 }
978
979
ci_ring_buf_read(struct ci_ring_buf * buf,char * data,int size)980 int ci_ring_buf_read(struct ci_ring_buf *buf, char *data,int size)
981 {
982 char *rb;
983 int rb_len, ret, data_read;
984 data_read = 0;
985 do {
986 ret = ci_ring_buf_read_block(buf, &rb, &rb_len);
987 if (rb_len) {
988 rb_len = min(size, rb_len);
989 memcpy(data, rb, rb_len);
990 ci_ring_buf_consume(buf, rb_len);
991 size -= rb_len;
992 data += rb_len;
993 data_read += rb_len;
994 }
995 } while ((ret != 0) && (size > 0));
996 return data_read;
997 }
998