17 char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
19 typedef struct io_blink {
22 size_t len; /* How large is this buffer = BBZIS for now */
23 struct io_blink *next;
24 struct io_blink *prev;
28 /* Structures that describe callback interfaces */
46 off_t offset; /* Offset of the source - not used */
47 off_t length; /* Total length of chain in bytes */
48 io_blink *head; /* Start of chain */
49 io_blink *tail; /* End of chain */
50 off_t tfill; /* End of stream in last link */
51 io_blink *cp; /* Current element of list */
52 off_t cpos; /* Offset within the current */
53 off_t gpos; /* Global position in stream */
57 off_t offset; /* Offset of the source - not used */
58 off_t cpos; /* Offset within the current */
61 static void io_obj_setp_buffer(io_obj *io, char *p, size_t len, i_io_closebufp_t closecb, void *closedata);
62 static void io_obj_setp_cb2 (io_obj *io, void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb);
64 /* turn current offset, file length, whence and offset into a new offset */
65 #define calc_seek_offset(curr_off, length, offset, whence) \
66 (((whence) == SEEK_SET) ? (offset) : \
67 ((whence) == SEEK_CUR) ? (curr_off) + (offset) : \
68 ((whence) == SEEK_END) ? (length) + (offset) : -1)
73 iolayer.c - encapsulates different source of data into a single framework.
77 io_glue *ig = io_new_fd( fileno(stdin) );
78 method = io_reqmeth( IOL_NOSEEK | IOL_MMAP ); // not implemented yet
79 io_glue_commit_types(ig); // always assume IOL_SEEK for now
82 code that uses ig->readcb()
83 to read data goes here.
86 code that uses ig->readcb()
87 to read data goes here.
96 iolayer.c implements the basic functions to create and destroy io_glue
97 objects for Imager. The typical usage pattern for data sources is:
99 1. Create the source (io_new_fd)
100 2. Define how you want to get data from it (io_reqmeth)
101 3. read from it using the interface requested (ig->readdb, ig->mmapcb)
102 4. Close the source, which
103 shouldn't really close the underlying source. (io_glue DESTROY)
105 =head1 FUNCTION REFERENCE
107 Some of these functions are internal.
114 static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
115 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
116 static off_t fd_seek(io_glue *ig, off_t offset, int whence);
117 static int fd_close(io_glue *ig);
118 static ssize_t fd_size(io_glue *ig);
119 static const char *my_strerror(int err);
122 * Callbacks for sources that cannot seek
125 /* fakeseek_read: read method for when emulating a seekable source
128 fakeseek_read(io_glue *ig, void *buf, size_t count) {
129 io_ex_fseek *exdata = ig->exdata;
137 * Callbacks for sources that can seek
141 =item realseek_read(ig, buf, count)
143 Does the reading from a source that can be seeked on
146 buf - buffer to return data in
147 count - number of bytes to read into buffer max
154 realseek_read(io_glue *ig, void *buf, size_t count) {
155 io_ex_rseek *ier = ig->exdata;
156 void *p = ig->source.cb.p;
161 IOL_DEB( printf("realseek_read: buf = %p, count = %d\n",
163 /* Is this a good idea? Would it be better to handle differently?
165 while( count!=bc && (rc = ig->source.cb.readcb(p,cbuf+bc,count-bc))>0 ) {
170 IOL_DEB( printf("realseek_read: rc = %d, bc = %d\n", rc, bc) );
171 return rc < 0 ? rc : bc;
176 =item realseek_write(ig, buf, count)
178 Does the writing to a 'source' that can be seeked on
181 buf - buffer that contains data
182 count - number of bytes to write
189 realseek_write(io_glue *ig, const void *buf, size_t count) {
190 io_ex_rseek *ier = ig->exdata;
191 void *p = ig->source.cb.p;
194 char *cbuf = (char*)buf;
196 IOL_DEB( printf("realseek_write: ig = %p, ier->cpos = %ld, buf = %p, "
197 "count = %d\n", ig, (long) ier->cpos, buf, count) );
199 /* Is this a good idea? Would it be better to handle differently?
201 while( count!=bc && (rc = ig->source.cb.writecb(p,cbuf+bc,count-bc))>0 ) {
206 IOL_DEB( printf("realseek_write: rc = %d, bc = %d\n", rc, bc) );
207 return rc < 0 ? rc : bc;
212 =item realseek_close(ig)
214 Closes a source that can be seeked on. Not sure if this should be an
215 actual close or not. Does nothing for now. Should be fixed.
223 realseek_close(io_glue *ig) {
224 mm_log((1, "realseek_close(ig %p)\n", ig));
225 if (ig->source.cb.closecb)
226 return ig->source.cb.closecb(ig->source.cb.p);
232 /* realseek_seek(ig, offset, whence)
234 Implements seeking for a source that is seekable, the purpose of having this is to be able to
235 have an offset into a file that is different from what the underlying library thinks.
238 offset - offset into stream
239 whence - whence argument a la lseek
246 realseek_seek(io_glue *ig, off_t offset, int whence) {
247 /* io_ex_rseek *ier = ig->exdata; Needed later */
248 void *p = ig->source.cb.p;
250 IOL_DEB( printf("realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
251 rc = ig->source.cb.seekcb(p, offset, whence);
253 IOL_DEB( printf("realseek_seek: rc %ld\n", (long) rc) );
255 /* FIXME: How about implementing this offset handling stuff? */
260 realseek_destroy(io_glue *ig) {
261 io_ex_rseek *ier = ig->exdata;
263 if (ig->source.cb.destroycb)
264 ig->source.cb.destroycb(ig->source.cb.p);
270 * Callbacks for sources that are a fixed size buffer
274 =item buffer_read(ig, buf, count)
276 Does the reading from a buffer source
279 buf - buffer to return data in
280 count - number of bytes to read into buffer max
287 buffer_read(io_glue *ig, void *buf, size_t count) {
288 io_ex_buffer *ieb = ig->exdata;
290 IOL_DEB( printf("buffer_read: ieb->cpos = %ld, buf = %p, count = %d\n", (long) ieb->cpos, buf, count) );
292 if ( ieb->cpos+count > ig->source.buffer.len ) {
293 mm_log((1,"buffer_read: short read: cpos=%ld, len=%ld, count=%ld\n", (long)ieb->cpos, (long)ig->source.buffer.len, (long)count));
294 count = ig->source.buffer.len - ieb->cpos;
297 memcpy(buf, ig->source.buffer.data+ieb->cpos, count);
299 IOL_DEB( printf("buffer_read: count = %ld\n", (long)count) );
305 =item buffer_write(ig, buf, count)
307 Does nothing, returns -1
310 buf - buffer that contains data
311 count - number of bytes to write
318 buffer_write(io_glue *ig, const void *buf, size_t count) {
319 mm_log((1, "buffer_write called, this method should never be called.\n"));
325 =item buffer_close(ig)
327 Closes a source that can be seeked on. Not sure if this should be an actual close
328 or not. Does nothing for now. Should be fixed.
337 buffer_close(io_glue *ig) {
338 mm_log((1, "buffer_close(ig %p)\n", ig));
344 /* buffer_seek(ig, offset, whence)
346 Implements seeking for a buffer source.
349 offset - offset into stream
350 whence - whence argument a la lseek
357 buffer_seek(io_glue *ig, off_t offset, int whence) {
358 io_ex_buffer *ieb = ig->exdata;
360 calc_seek_offset(ieb->cpos, ig->source.buffer.len, offset, whence);
362 if (reqpos > ig->source.buffer.len) {
363 mm_log((1, "seeking out of readable range\n"));
367 i_push_error(0, "seek before beginning of file");
372 IOL_DEB( printf("buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
375 /* FIXME: How about implementing this offset handling stuff? */
380 buffer_destroy(io_glue *ig) {
381 io_ex_buffer *ieb = ig->exdata;
383 if (ig->source.buffer.closecb) {
384 mm_log((1,"calling close callback %p for io_buffer\n",
385 ig->source.buffer.closecb));
386 ig->source.buffer.closecb(ig->source.buffer.closedata);
394 * Callbacks for sources that are a chain of variable sized buffers
399 /* Helper functions for buffer chains */
406 mm_log((1, "io_blink_new()\n"));
408 ib = mymalloc(sizeof(io_blink));
414 memset(&ib->buf, 0, ib->len);
421 =item io_bchain_advance(ieb)
423 Advances the buffer chain to the next link - extending if
424 necessary. Also adjusts the cpos and tfill counters as needed.
426 ieb - buffer chain object
433 io_bchain_advance(io_ex_bchain *ieb) {
434 if (ieb->cp->next == NULL) {
435 ieb->tail = io_blink_new();
436 ieb->tail->prev = ieb->cp;
437 ieb->cp->next = ieb->tail;
439 ieb->tfill = 0; /* Only set this if we added a new slice */
441 ieb->cp = ieb->cp->next;
448 =item io_bchain_destroy()
450 frees all resources used by a buffer chain.
456 io_destroy_bufchain(io_ex_bchain *ieb) {
458 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
462 io_blink *t = cp->next;
475 bufchain_dump(io_ex_bchain *ieb) {
476 mm_log((1, " buf_chain_dump(ieb %p)\n"));
477 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
478 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
479 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
480 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
481 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
482 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
483 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
484 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
489 * TRUE if lengths are NOT equal
495 chainlencert( io_glue *ig ) {
500 io_ex_bchain *ieb = ig->exdata;
501 io_blink *cp = ieb->head;
504 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
507 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
508 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
509 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
511 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
512 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
514 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
515 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
522 if (!cfl) cpos += clen;
527 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
528 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
534 chaincert( io_glue *ig) {
536 io_ex_bchain *ieb = ig->exdata;
537 io_blink *cp = ieb->head;
539 mm_log((1, "Chain verification.\n"));
541 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
542 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
543 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
544 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
545 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
546 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
547 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
548 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
551 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
552 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
553 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
554 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
556 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
557 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
559 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
560 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
566 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
581 =item bufchain_read(ig, buf, count)
583 Does the reading from a source that can be seeked on
586 buf - buffer to return data in
587 count - number of bytes to read into buffer max
594 bufchain_read(io_glue *ig, void *buf, size_t count) {
595 io_ex_bchain *ieb = ig->exdata;
596 size_t scount = count;
600 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, (long)count));
603 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
604 if (clen == ieb->cpos) {
605 if (ieb->cp == ieb->tail) break; /* EOF */
606 ieb->cp = ieb->cp->next;
608 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
611 sk = clen - ieb->cpos;
612 sk = sk > scount ? scount : sk;
614 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
620 mm_log((1, "bufchain_read: returning %ld\n", (long)(count-scount)));
629 =item bufchain_write(ig, buf, count)
631 Does the writing to a 'source' that can be seeked on
634 buf - buffer that contains data
635 count - number of bytes to write
642 bufchain_write(io_glue *ig, const void *buf, size_t count) {
643 char *cbuf = (char *)buf;
644 io_ex_bchain *ieb = ig->exdata;
645 size_t ocount = count;
648 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %ld\n", ig, buf, (long)count));
650 IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %ld\n", ig, (long) ieb->cpos, buf, (long)count) );
653 mm_log((2, "bufchain_write: - looping - count = %ld\n", (long)count));
654 if (ieb->cp->len == ieb->cpos) {
655 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %ld - advancing chain\n", (long) ieb->cpos));
656 io_bchain_advance(ieb);
659 sk = ieb->cp->len - ieb->cpos;
660 sk = sk > count ? count : sk;
661 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
663 if (ieb->cp == ieb->tail) {
664 int extend = ieb->cpos + sk - ieb->tfill;
665 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
667 ieb->length += extend;
668 ieb->tfill += extend;
680 =item bufchain_close(ig)
682 Closes a source that can be seeked on. Not sure if this should be an actual close
683 or not. Does nothing for now. Should be fixed.
692 bufchain_close(io_glue *ig) {
693 mm_log((1, "bufchain_close(ig %p)\n",ig));
694 IOL_DEB( printf("bufchain_close(ig %p)\n", ig) );
700 /* bufchain_seek(ig, offset, whence)
702 Implements seeking for a source that is seekable, the purpose of having this is to be able to
703 have an offset into a file that is different from what the underlying library thinks.
706 offset - offset into stream
707 whence - whence argument a la lseek
714 bufchain_seek(io_glue *ig, off_t offset, int whence) {
715 io_ex_bchain *ieb = ig->exdata;
718 off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence);
721 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, (long)offset, whence));
724 i_push_error(0, "invalid whence supplied or seek before start of file");
733 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
734 if (clen == ieb->cpos) {
735 if (ieb->cp == ieb->tail) break; /* EOF */
736 ieb->cp = ieb->cp->next;
738 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
741 sk = clen - ieb->cpos;
742 sk = sk > scount ? scount : sk;
753 * extending file - get ieb into consistent state and then
754 * call write which will get it to the correct position
757 memset(TB, 0, BBSIZ);
758 ieb->gpos = ieb->length;
759 ieb->cpos = ieb->tfill;
762 ssize_t rc, wl = i_min(wrlen, BBSIZ);
763 mm_log((1, "bufchain_seek: wrlen = %d, wl = %ld\n", wrlen, (long)wl));
764 rc = bufchain_write( ig, TB, wl );
765 if (rc != wl) i_fatal(0, "bufchain_seek: Unable to extend file\n");
770 mm_log((2, "bufchain_seek: returning ieb->gpos = %ld\n", (long)ieb->gpos));
776 bufchain_destroy(io_glue *ig) {
777 io_ex_bchain *ieb = ig->exdata;
779 io_destroy_bufchain(ieb);
785 * Methods for setting up data source
789 =item io_obj_setp_buffer(io, p, len)
791 Sets an io_object for reading from a buffer source
793 io - io object that describes a source
794 p - pointer to buffer
795 len - length of buffer
801 io_obj_setp_buffer(io_obj *io, char *p, size_t len, i_io_closebufp_t closecb,
803 io->buffer.type = BUFFER;
805 io->buffer.len = len;
806 io->buffer.closecb = closecb;
807 io->buffer.closedata = closedata;
813 =item io_obj_setp_cb2(io, p, readcb, writecb, seekcb, closecb, destroycb)
815 Sets an io_object for reading from a source that uses callbacks
817 io - io object that describes a source
818 p - pointer to data for callbacks
819 readcb - read callback to read from source
820 writecb - write callback to write to source
821 seekcb - seek callback to seek on source
822 closecb - flush any pending data
823 destroycb - release any extra resources
829 io_obj_setp_cb2(io_obj *io, void *p, i_io_readl_t readcb, i_io_writel_t writecb, i_io_seekl_t seekcb, i_io_closel_t closecb, i_io_destroyl_t destroycb) {
830 io->cb.type = CBSEEK;
832 io->cb.readcb = readcb;
833 io->cb.writecb = writecb;
834 io->cb.seekcb = seekcb;
835 io->cb.closecb = closecb;
836 io->cb.destroycb = destroycb;
840 =item io_glue_commit_types(ig)
842 This is now effectively a no-op.
848 io_glue_commit_types(io_glue *ig) {
849 io_type inn = ig->source.type;
851 mm_log((1, "io_glue_commit_types(ig %p)\n", ig));
852 mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn]));
854 if (ig->flags & 0x01) {
855 mm_log((1, "io_glue_commit_types: type already set up\n"));
859 ig->flags |= 0x01; /* indicate source has been setup already */
863 =item io_glue_gettypes(ig, reqmeth)
865 Returns a set of compatible interfaces to read data with.
868 reqmeth - request mask
870 The request mask is a bit mask (of something that hasn't been implemented yet)
871 of interfaces that it would like to read data from the source which the ig
878 io_glue_gettypes(io_glue *ig, int reqmeth) {
883 /* FIXME: Implement this function! */
884 /* if (ig->source.type =
885 if (reqmeth & IO_BUFF) */
891 =item io_new_bufchain()
893 returns a new io_glue object that has the 'empty' source and but can
894 be written to and read from later (like a pseudo file).
902 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
904 mm_log((1, "io_new_bufchain()\n"));
906 ig = mymalloc(sizeof(io_glue));
907 memset(ig, 0, sizeof(*ig));
908 ig->source.type = BUFCHAIN;
916 ieb->head = io_blink_new();
918 ieb->tail = ieb->head;
921 ig->readcb = bufchain_read;
922 ig->writecb = bufchain_write;
923 ig->seekcb = bufchain_seek;
924 ig->closecb = bufchain_close;
925 ig->destroycb = bufchain_destroy;
931 =item io_new_buffer(data, len)
933 Returns a new io_glue object that has the source defined as reading
934 from specified buffer. Note that the buffer is not copied.
936 data - buffer to read from
937 len - length of buffer
943 io_new_buffer(char *data, size_t len, i_io_closebufp_t closecb, void *closedata) {
945 io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
947 mm_log((1, "io_new_buffer(data %p, len %ld, closecb %p, closedata %p)\n", data, (long)len, closecb, closedata));
949 ig = mymalloc(sizeof(io_glue));
950 memset(ig, 0, sizeof(*ig));
951 io_obj_setp_buffer(&ig->source, data, len, closecb, closedata);
958 ig->readcb = buffer_read;
959 ig->writecb = buffer_write;
960 ig->seekcb = buffer_seek;
961 ig->closecb = buffer_close;
962 ig->destroycb = buffer_destroy;
971 returns a new io_glue object that has the source defined as reading
972 from specified filedescriptor. Note that the the interface to recieving
973 data from the io_glue callbacks hasn't been done yet.
975 fd - file descriptor to read/write from
984 mm_log((1, "io_new_fd(fd %d)\n", fd));
986 ig = mymalloc(sizeof(io_glue));
987 memset(ig, 0, sizeof(*ig));
988 ig->source.type = FDSEEK;
989 ig->source.fdseek.fd = fd;
993 ig->readcb = fd_read;
994 ig->writecb = fd_write;
995 ig->seekcb = fd_seek;
996 ig->closecb = fd_close;
997 ig->sizecb = fd_size;
998 ig->destroycb = NULL;
1000 mm_log((1, "(%p) <- io_new_fd\n", ig));
1004 io_glue *io_new_cb(void *p, i_io_readl_t readcb, i_io_writel_t writecb,
1005 i_io_seekl_t seekcb, i_io_closel_t closecb,
1006 i_io_destroyl_t destroycb) {
1008 io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
1010 mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
1011 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
1012 ig = mymalloc(sizeof(io_glue));
1013 memset(ig, 0, sizeof(*ig));
1014 io_obj_setp_cb2(&ig->source, p, readcb, writecb, seekcb, closecb, destroycb);
1015 mm_log((1, "(%p) <- io_new_cb\n", ig));
1021 ig->readcb = realseek_read;
1022 ig->writecb = realseek_write;
1023 ig->seekcb = realseek_seek;
1024 ig->closecb = realseek_close;
1025 ig->destroycb = realseek_destroy;
1033 Takes the source that the io_glue is bound to and allocates space
1034 for a return buffer and returns the entire content in a single buffer.
1035 Note: This only works for io_glue objects that contain a bufchain. It
1036 is usefull for saving to scalars and such.
1039 c - pointer to a pointer to where data should be copied to
1045 io_slurp(io_glue *ig, unsigned char **c) {
1050 io_type inn = ig->source.type;
1052 if ( inn != BUFCHAIN ) {
1053 i_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
1057 cc = *c = mymalloc( ieb->length );
1061 bufchain_seek(ig, 0, SEEK_SET);
1063 rc = bufchain_read(ig, cc, ieb->length);
1065 if (rc != ieb->length)
1066 i_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
1072 =item fd_read(ig, buf, count)
1076 static ssize_t fd_read(io_glue *ig, void *buf, size_t count) {
1079 result = _read(ig->source.fdseek.fd, buf, count);
1081 result = read(ig->source.fdseek.fd, buf, count);
1084 /* 0 is valid - means EOF */
1086 i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
1092 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count) {
1095 result = _write(ig->source.fdseek.fd, buf, count);
1097 result = write(ig->source.fdseek.fd, buf, count);
1101 i_push_errorf(errno, "write() failure: %s (%d)", my_strerror(errno), errno);
1107 static off_t fd_seek(io_glue *ig, off_t offset, int whence) {
1110 result = _lseek(ig->source.fdseek.fd, offset, whence);
1112 result = lseek(ig->source.fdseek.fd, offset, whence);
1115 if (result == (off_t)-1) {
1116 i_push_errorf(errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
1122 static int fd_close(io_glue *ig) {
1123 /* no, we don't close it */
1127 static ssize_t fd_size(io_glue *ig) {
1128 mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
1134 =item io_glue_destroy(ig)
1136 A destructor method for io_glue objects. Should clean up all related buffers.
1137 Might leave us with a dangling pointer issue on some buffers.
1139 ig - io_glue object to destroy.
1145 io_glue_destroy(io_glue *ig) {
1146 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
1157 =head1 INTERNAL FUNCTIONS
1163 Calls strerror() and ensures we don't return NULL.
1165 On some platforms it's possible for strerror() to return NULL, this
1166 wrapper ensures we only get non-NULL values.
1172 const char *my_strerror(int err) {
1173 const char *result = strerror(err);
1176 result = "Unknown error";
1186 Arnar M. Hrafnkelsson <addi@umich.edu>