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