16 char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
18 typedef struct io_blink {
21 size_t len; /* How large is this buffer = BBZIS for now */
22 struct io_blink *next;
23 struct io_blink *prev;
27 /* Structures that describe callback interfaces */
45 off_t offset; /* Offset of the source - not used */
46 off_t length; /* Total length of chain in bytes */
47 io_blink *head; /* Start of chain */
48 io_blink *tail; /* End of chain */
49 off_t tfill; /* End of stream in last link */
50 io_blink *cp; /* Current element of list */
51 off_t cpos; /* Offset within the current */
52 off_t gpos; /* Global position in stream */
56 off_t offset; /* Offset of the source - not used */
57 off_t cpos; /* Offset within the current */
60 static void io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb, void *closedata);
61 static void io_obj_setp_cb2 (io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb, closel closecb, destroyl destroycb);
67 iolayer.c - encapsulates different source of data into a single framework.
71 io_glue *ig = io_new_fd( fileno(stdin) );
72 method = io_reqmeth( IOL_NOSEEK | IOL_MMAP ); // not implemented yet
73 io_glue_commit_types(ig); // always assume IOL_SEEK for now
76 code that uses ig->readcb()
77 to read data goes here.
80 code that uses ig->readcb()
81 to read data goes here.
90 iolayer.c implements the basic functions to create and destroy io_glue
91 objects for Imager. The typical usage pattern for data sources is:
93 1. Create the source (io_new_fd)
94 2. Define how you want to get data from it (io_reqmeth)
95 3. read from it using the interface requested (ig->readdb, ig->mmapcb)
96 4. Close the source, which
97 shouldn't really close the underlying source. (io_glue DESTROY)
99 =head1 FUNCTION REFERENCE
101 Some of these functions are internal.
108 static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
109 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
110 static off_t fd_seek(io_glue *ig, off_t offset, int whence);
111 static void fd_close(io_glue *ig);
112 static ssize_t fd_size(io_glue *ig);
113 static const char *my_strerror(int err);
116 * Callbacks for sources that cannot seek
119 /* fakeseek_read: read method for when emulating a seekable source
122 fakeseek_read(io_glue *ig, void *buf, size_t count) {
123 io_ex_fseek *exdata = ig->exdata;
131 * Callbacks for sources that can seek
135 =item realseek_read(ig, buf, count)
137 Does the reading from a source that can be seeked on
140 buf - buffer to return data in
141 count - number of bytes to read into buffer max
148 realseek_read(io_glue *ig, void *buf, size_t count) {
149 io_ex_rseek *ier = ig->exdata;
150 void *p = ig->source.cb.p;
155 IOL_DEB( printf("realseek_read: fd = %d, ier->cpos = %ld, buf = %p, "
156 "count = %d\n", fd, (long) ier->cpos, buf, count) );
157 /* Is this a good idea? Would it be better to handle differently?
159 while( count!=bc && (rc = ig->source.cb.readcb(p,cbuf+bc,count-bc))>0 ) {
164 IOL_DEB( printf("realseek_read: rc = %d, bc = %d\n", rc, bc) );
170 =item realseek_write(ig, buf, count)
172 Does the writing to a 'source' that can be seeked on
175 buf - buffer that contains data
176 count - number of bytes to write
183 realseek_write(io_glue *ig, const void *buf, size_t count) {
184 io_ex_rseek *ier = ig->exdata;
185 void *p = ig->source.cb.p;
188 char *cbuf = (char*)buf;
190 IOL_DEB( printf("realseek_write: ig = %p, ier->cpos = %ld, buf = %p, "
191 "count = %d\n", ig, (long) ier->cpos, buf, count) );
193 /* Is this a good idea? Would it be better to handle differently?
195 while( count!=bc && (rc = ig->source.cb.writecb(p,cbuf+bc,count-bc))>0 ) {
200 IOL_DEB( printf("realseek_write: rc = %d, bc = %d\n", rc, bc) );
206 =item realseek_close(ig)
208 Closes a source that can be seeked on. Not sure if this should be an
209 actual close or not. Does nothing for now. Should be fixed.
217 realseek_close(io_glue *ig) {
218 mm_log((1, "realseek_close(ig %p)\n", ig));
219 if (ig->source.cb.closecb)
220 ig->source.cb.closecb(ig->source.cb.p);
224 /* realseek_seek(ig, offset, whence)
226 Implements seeking for a source that is seekable, the purpose of having this is to be able to
227 have an offset into a file that is different from what the underlying library thinks.
230 offset - offset into stream
231 whence - whence argument a la lseek
238 realseek_seek(io_glue *ig, off_t offset, int whence) {
239 /* io_ex_rseek *ier = ig->exdata; Needed later */
240 void *p = ig->source.cb.p;
242 IOL_DEB( printf("realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
243 rc = ig->source.cb.seekcb(p, offset, whence);
245 IOL_DEB( printf("realseek_seek: rc %ld\n", (long) rc) );
247 /* FIXME: How about implementing this offset handling stuff? */
252 realseek_destroy(io_glue *ig) {
253 io_ex_rseek *ier = ig->exdata;
255 if (ig->source.cb.destroycb)
256 ig->source.cb.destroycb(ig->source.cb.p);
262 * Callbacks for sources that are a fixed size buffer
266 =item buffer_read(ig, buf, count)
268 Does the reading from a buffer source
271 buf - buffer to return data in
272 count - number of bytes to read into buffer max
279 buffer_read(io_glue *ig, void *buf, size_t count) {
280 io_ex_buffer *ieb = ig->exdata;
282 IOL_DEB( printf("buffer_read: fd = %d, ier->cpos = %ld, buf = %p, count = %d\n", fd, (long) ier->cpos, buf, count) );
284 if ( ieb->cpos+count > ig->source.buffer.len ) {
285 mm_log((1,"buffer_read: short read: cpos=%d, len=%d, count=%d\n", ieb->cpos, ig->source.buffer.len));
286 count = ig->source.buffer.len - ieb->cpos;
289 memcpy(buf, ig->source.buffer.data+ieb->cpos, count);
291 IOL_DEB( printf("buffer_read: rc = %d, count = %d\n", rc, count) );
297 =item buffer_write(ig, buf, count)
299 Does nothing, returns -1
302 buf - buffer that contains data
303 count - number of bytes to write
310 buffer_write(io_glue *ig, const void *buf, size_t count) {
311 mm_log((1, "buffer_write called, this method should never be called.\n"));
317 =item buffer_close(ig)
319 Closes a source that can be seeked on. Not sure if this should be an actual close
320 or not. Does nothing for now. Should be fixed.
329 buffer_close(io_glue *ig) {
330 mm_log((1, "buffer_close(ig %p)\n", ig));
331 /* FIXME: Do stuff here */
335 /* buffer_seek(ig, offset, whence)
337 Implements seeking for a buffer source.
340 offset - offset into stream
341 whence - whence argument a la lseek
348 buffer_seek(io_glue *ig, off_t offset, int whence) {
349 io_ex_buffer *ieb = ig->exdata;
350 off_t reqpos = offset
351 + (whence == SEEK_CUR)*ieb->cpos
352 + (whence == SEEK_END)*ig->source.buffer.len;
354 if (reqpos > ig->source.buffer.len) {
355 mm_log((1, "seeking out of readable range\n"));
360 IOL_DEB( printf("buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
363 /* FIXME: How about implementing this offset handling stuff? */
368 buffer_destroy(io_glue *ig) {
369 io_ex_buffer *ieb = ig->exdata;
371 if (ig->source.buffer.closecb) {
372 mm_log((1,"calling close callback %p for io_buffer\n",
373 ig->source.buffer.closecb));
374 ig->source.buffer.closecb(ig->source.buffer.closedata);
382 * Callbacks for sources that are a chain of variable sized buffers
387 /* Helper functions for buffer chains */
394 mm_log((1, "io_blink_new()\n"));
396 ib = mymalloc(sizeof(io_blink));
402 memset(&ib->buf, 0, ib->len);
409 =item io_bchain_advance(ieb)
411 Advances the buffer chain to the next link - extending if
412 necessary. Also adjusts the cpos and tfill counters as needed.
414 ieb - buffer chain object
421 io_bchain_advance(io_ex_bchain *ieb) {
422 if (ieb->cp->next == NULL) {
423 ieb->tail = io_blink_new();
424 ieb->tail->prev = ieb->cp;
425 ieb->cp->next = ieb->tail;
427 ieb->tfill = 0; /* Only set this if we added a new slice */
429 ieb->cp = ieb->cp->next;
436 =item io_bchain_destroy()
438 frees all resources used by a buffer chain.
444 io_destroy_bufchain(io_ex_bchain *ieb) {
446 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
450 io_blink *t = cp->next;
463 bufchain_dump(io_ex_bchain *ieb) {
464 mm_log((1, " buf_chain_dump(ieb %p)\n"));
465 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
466 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
467 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
468 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
469 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
470 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
471 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
472 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
477 * TRUE if lengths are NOT equal
483 chainlencert( io_glue *ig ) {
488 io_ex_bchain *ieb = ig->exdata;
489 io_blink *cp = ieb->head;
492 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
495 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
496 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
497 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
499 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
500 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
502 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
503 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
510 if (!cfl) cpos += clen;
515 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
516 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
522 chaincert( io_glue *ig) {
524 io_ex_bchain *ieb = ig->exdata;
525 io_blink *cp = ieb->head;
527 mm_log((1, "Chain verification.\n"));
529 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
530 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
531 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
532 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
533 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
534 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
535 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
536 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
539 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
540 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
541 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
542 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
544 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
545 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
547 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
548 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
554 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
569 =item bufchain_read(ig, buf, count)
571 Does the reading from a source that can be seeked on
574 buf - buffer to return data in
575 count - number of bytes to read into buffer max
582 bufchain_read(io_glue *ig, void *buf, size_t count) {
583 io_ex_bchain *ieb = ig->exdata;
584 size_t scount = count;
588 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, count));
591 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
592 if (clen == ieb->cpos) {
593 if (ieb->cp == ieb->tail) break; /* EOF */
594 ieb->cp = ieb->cp->next;
596 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
599 sk = clen - ieb->cpos;
600 sk = sk > scount ? scount : sk;
602 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
608 mm_log((1, "bufchain_read: returning %d\n", count-scount));
617 =item bufchain_write(ig, buf, count)
619 Does the writing to a 'source' that can be seeked on
622 buf - buffer that contains data
623 count - number of bytes to write
630 bufchain_write(io_glue *ig, const void *buf, size_t count) {
631 char *cbuf = (char *)buf;
632 io_ex_bchain *ieb = ig->exdata;
633 size_t ocount = count;
636 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %d\n", ig, buf, count));
638 IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %d\n", ig, (long) ieb->cpos, buf, count) );
641 mm_log((2, "bufchain_write: - looping - count = %d\n", count));
642 if (ieb->cp->len == ieb->cpos) {
643 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %d - advancing chain\n", (long) ieb->cpos));
644 io_bchain_advance(ieb);
647 sk = ieb->cp->len - ieb->cpos;
648 sk = sk > count ? count : sk;
649 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
651 if (ieb->cp == ieb->tail) {
652 int extend = ieb->cpos + sk - ieb->tfill;
653 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
655 ieb->length += extend;
656 ieb->tfill += extend;
668 =item bufchain_close(ig)
670 Closes a source that can be seeked on. Not sure if this should be an actual close
671 or not. Does nothing for now. Should be fixed.
680 bufchain_close(io_glue *ig) {
681 mm_log((1, "bufchain_close(ig %p)\n",ig));
682 IOL_DEB( printf("bufchain_close(ig %p)\n", ig) );
683 /* FIXME: Commit a seek point here */
688 /* bufchain_seek(ig, offset, whence)
690 Implements seeking for a source that is seekable, the purpose of having this is to be able to
691 have an offset into a file that is different from what the underlying library thinks.
694 offset - offset into stream
695 whence - whence argument a la lseek
702 bufchain_seek(io_glue *ig, off_t offset, int whence) {
703 io_ex_bchain *ieb = ig->exdata;
708 off_t scount = offset;
711 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence));
714 case SEEK_SET: /* SEEK_SET = 0, From the top */
720 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
721 if (clen == ieb->cpos) {
722 if (ieb->cp == ieb->tail) break; /* EOF */
723 ieb->cp = ieb->cp->next;
725 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
728 sk = clen - ieb->cpos;
729 sk = sk > scount ? scount : sk;
740 * extending file - get ieb into consistent state and then
741 * call write which will get it to the correct position
744 memset(TB, 0, BBSIZ);
745 ieb->gpos = ieb->length;
746 ieb->cpos = ieb->tfill;
749 ssize_t rc, wl = i_min(wrlen, BBSIZ);
750 mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl));
751 rc = bufchain_write( ig, TB, wl );
752 if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n");
760 m_fatal(123, "SEEK_CUR IS NOT IMPLEMENTED\n");
768 while(cof < 0 && ib->prev) {
774 case SEEK_END: /* SEEK_END = 2 */
775 if (cof>0) m_fatal(0, "bufchain_seek: SEEK_END + %d : Extending files via seek not supported!\n", cof);
778 ieb->cpos = ieb->tfill;
784 while(cof<0 && ib->prev) {
789 if (cof<0) m_fatal(0, "bufchain_seek: Tried to seek before start of file\n");
790 ieb->gpos = ieb->length+offset;
795 m_fatal(0, "bufchain_seek: Unhandled seek request: whence = %d\n", whence );
798 mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos));
804 bufchain_destroy(io_glue *ig) {
805 io_ex_bchain *ieb = ig->exdata;
807 io_destroy_bufchain(ieb);
813 * Methods for setting up data source
817 =item io_obj_setp_buffer(io, p, len)
819 Sets an io_object for reading from a buffer source
821 io - io object that describes a source
822 p - pointer to buffer
823 len - length of buffer
829 io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb,
831 io->buffer.type = BUFFER;
833 io->buffer.len = len;
834 io->buffer.closecb = closecb;
835 io->buffer.closedata = closedata;
841 =item io_obj_setp_cb2(io, p, readcb, writecb, seekcb, closecb, destroycb)
843 Sets an io_object for reading from a source that uses callbacks
845 io - io object that describes a source
846 p - pointer to data for callbacks
847 readcb - read callback to read from source
848 writecb - write callback to write to source
849 seekcb - seek callback to seek on source
850 closecb - flush any pending data
851 destroycb - release any extra resources
857 io_obj_setp_cb2(io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb, closel closecb, destroyl destroycb) {
858 io->cb.type = CBSEEK;
860 io->cb.readcb = readcb;
861 io->cb.writecb = writecb;
862 io->cb.seekcb = seekcb;
863 io->cb.closecb = closecb;
864 io->cb.destroycb = destroycb;
868 =item io_glue_commit_types(ig)
870 This is now effectively a no-op.
876 io_glue_commit_types(io_glue *ig) {
877 io_type inn = ig->source.type;
879 mm_log((1, "io_glue_commit_types(ig %p)\n", ig));
880 mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn]));
882 if (ig->flags & 0x01) {
883 mm_log((1, "io_glue_commit_types: type already set up\n"));
887 ig->flags |= 0x01; /* indicate source has been setup already */
891 =item io_glue_gettypes(ig, reqmeth)
893 Returns a set of compatible interfaces to read data with.
896 reqmeth - request mask
898 The request mask is a bit mask (of something that hasn't been implemented yet)
899 of interfaces that it would like to read data from the source which the ig
906 io_glue_gettypes(io_glue *ig, int reqmeth) {
911 /* FIXME: Implement this function! */
912 /* if (ig->source.type =
913 if (reqmeth & IO_BUFF) */
919 =item io_new_bufchain()
921 returns a new io_glue object that has the 'empty' source and but can
922 be written to and read from later (like a pseudo file).
930 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
932 mm_log((1, "io_new_bufchain()\n"));
934 ig = mymalloc(sizeof(io_glue));
935 memset(ig, 0, sizeof(*ig));
936 ig->source.type = BUFCHAIN;
944 ieb->head = io_blink_new();
946 ieb->tail = ieb->head;
949 ig->readcb = bufchain_read;
950 ig->writecb = bufchain_write;
951 ig->seekcb = bufchain_seek;
952 ig->closecb = bufchain_close;
953 ig->destroycb = bufchain_destroy;
959 =item io_new_buffer(data, len)
961 Returns a new io_glue object that has the source defined as reading
962 from specified buffer. Note that the buffer is not copied.
964 data - buffer to read from
965 len - length of buffer
971 io_new_buffer(char *data, size_t len, closebufp closecb, void *closedata) {
973 io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
975 mm_log((1, "io_new_buffer(data %p, len %d, closecb %p, closedata %p)\n", data, len, closecb, closedata));
977 ig = mymalloc(sizeof(io_glue));
978 memset(ig, 0, sizeof(*ig));
979 io_obj_setp_buffer(&ig->source, data, len, closecb, closedata);
986 ig->readcb = buffer_read;
987 ig->writecb = buffer_write;
988 ig->seekcb = buffer_seek;
989 ig->closecb = buffer_close;
990 ig->destroycb = buffer_destroy;
999 returns a new io_glue object that has the source defined as reading
1000 from specified filedescriptor. Note that the the interface to recieving
1001 data from the io_glue callbacks hasn't been done yet.
1003 fd - file descriptor to read/write from
1012 mm_log((1, "io_new_fd(fd %d)\n", fd));
1014 ig = mymalloc(sizeof(io_glue));
1015 memset(ig, 0, sizeof(*ig));
1016 ig->source.type = FDSEEK;
1017 ig->source.fdseek.fd = fd;
1021 ig->readcb = fd_read;
1022 ig->writecb = fd_write;
1023 ig->seekcb = fd_seek;
1024 ig->closecb = fd_close;
1025 ig->sizecb = fd_size;
1026 ig->destroycb = NULL;
1028 mm_log((1, "(%p) <- io_new_fd\n", ig));
1032 io_glue *io_new_cb(void *p, readl readcb, writel writecb, seekl seekcb,
1033 closel closecb, destroyl destroycb) {
1035 io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
1037 mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
1038 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
1039 ig = mymalloc(sizeof(io_glue));
1040 memset(ig, 0, sizeof(*ig));
1041 io_obj_setp_cb2(&ig->source, p, readcb, writecb, seekcb, closecb, destroycb);
1042 mm_log((1, "(%p) <- io_new_cb\n", ig));
1048 ig->readcb = realseek_read;
1049 ig->writecb = realseek_write;
1050 ig->seekcb = realseek_seek;
1051 ig->closecb = realseek_close;
1052 ig->destroycb = realseek_destroy;
1060 Takes the source that the io_glue is bound to and allocates space
1061 for a return buffer and returns the entire content in a single buffer.
1062 Note: This only works for io_glue objects that contain a bufchain. It
1063 is usefull for saving to scalars and such.
1066 c - pointer to a pointer to where data should be copied to
1072 io_slurp(io_glue *ig, unsigned char **c) {
1077 io_type inn = ig->source.type;
1079 if ( inn != BUFCHAIN ) {
1080 m_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
1084 cc = *c = mymalloc( ieb->length );
1088 bufchain_seek(ig, 0, SEEK_SET);
1090 rc = bufchain_read(ig, cc, ieb->length);
1092 if (rc != ieb->length)
1093 m_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
1099 =item fd_read(ig, buf, count)
1103 static ssize_t fd_read(io_glue *ig, void *buf, size_t count) {
1106 result = _read(ig->source.fdseek.fd, buf, count);
1108 result = read(ig->source.fdseek.fd, buf, count);
1111 /* 0 is valid - means EOF */
1113 i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
1119 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count) {
1122 result = _write(ig->source.fdseek.fd, buf, count);
1124 result = write(ig->source.fdseek.fd, buf, count);
1128 i_push_errorf(errno, "write() failure: %s (%d)", my_strerror(errno), errno);
1134 static off_t fd_seek(io_glue *ig, off_t offset, int whence) {
1137 result = _lseek(ig->source.fdseek.fd, offset, whence);
1139 result = lseek(ig->source.fdseek.fd, offset, whence);
1142 if (result == (off_t)-1) {
1143 i_push_errorf(errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
1149 static void fd_close(io_glue *ig) {
1150 /* no, we don't close it */
1153 static ssize_t fd_size(io_glue *ig) {
1154 mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
1160 =item io_glue_destroy(ig)
1162 A destructor method for io_glue objects. Should clean up all related buffers.
1163 Might leave us with a dangling pointer issue on some buffers.
1165 ig - io_glue object to destroy.
1171 io_glue_destroy(io_glue *ig) {
1172 io_type inn = ig->source.type;
1173 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
1184 =head1 INTERNAL FUNCTIONS
1190 Calls strerror() and ensures we don't return NULL.
1192 On some platforms it's possible for strerror() to return NULL, this
1193 wrapper ensures we only get non-NULL values.
1199 const char *my_strerror(int err) {
1200 const char *result = strerror(err);
1203 result = "Unknown error";
1213 Arnar M. Hrafnkelsson <addi@umich.edu>