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, i_io_closebufp_t closecb, void *closedata);
61 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);
63 /* turn current offset, file length, whence and offset into a new offset */
64 #define calc_seek_offset(curr_off, length, offset, whence) \
65 (((whence) == SEEK_SET) ? (offset) : \
66 ((whence) == SEEK_CUR) ? (curr_off) + (offset) : \
67 ((whence) == SEEK_END) ? (length) + (offset) : -1)
72 iolayer.c - encapsulates different source of data into a single framework.
76 io_glue *ig = io_new_fd( fileno(stdin) );
77 method = io_reqmeth( IOL_NOSEEK | IOL_MMAP ); // not implemented yet
78 io_glue_commit_types(ig); // always assume IOL_SEEK for now
81 code that uses ig->readcb()
82 to read data goes here.
85 code that uses ig->readcb()
86 to read data goes here.
95 iolayer.c implements the basic functions to create and destroy io_glue
96 objects for Imager. The typical usage pattern for data sources is:
98 1. Create the source (io_new_fd)
99 2. Define how you want to get data from it (io_reqmeth)
100 3. read from it using the interface requested (ig->readdb, ig->mmapcb)
101 4. Close the source, which
102 shouldn't really close the underlying source. (io_glue DESTROY)
104 =head1 FUNCTION REFERENCE
106 Some of these functions are internal.
113 static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
114 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
115 static off_t fd_seek(io_glue *ig, off_t offset, int whence);
116 static int fd_close(io_glue *ig);
117 static ssize_t fd_size(io_glue *ig);
118 static const char *my_strerror(int err);
121 * Callbacks for sources that cannot seek
124 /* fakeseek_read: read method for when emulating a seekable source
127 fakeseek_read(io_glue *ig, void *buf, size_t count) {
128 io_ex_fseek *exdata = ig->exdata;
136 * Callbacks for sources that can seek
140 =item realseek_read(ig, buf, count)
142 Does the reading from a source that can be seeked on
145 buf - buffer to return data in
146 count - number of bytes to read into buffer max
153 realseek_read(io_glue *ig, void *buf, size_t count) {
154 io_ex_rseek *ier = ig->exdata;
155 void *p = ig->source.cb.p;
160 IOL_DEB( printf("realseek_read: buf = %p, count = %d\n",
162 /* Is this a good idea? Would it be better to handle differently?
164 while( count!=bc && (rc = ig->source.cb.readcb(p,cbuf+bc,count-bc))>0 ) {
169 IOL_DEB( printf("realseek_read: rc = %d, bc = %d\n", rc, bc) );
175 =item realseek_write(ig, buf, count)
177 Does the writing to a 'source' that can be seeked on
180 buf - buffer that contains data
181 count - number of bytes to write
188 realseek_write(io_glue *ig, const void *buf, size_t count) {
189 io_ex_rseek *ier = ig->exdata;
190 void *p = ig->source.cb.p;
193 char *cbuf = (char*)buf;
195 IOL_DEB( printf("realseek_write: ig = %p, ier->cpos = %ld, buf = %p, "
196 "count = %d\n", ig, (long) ier->cpos, buf, count) );
198 /* Is this a good idea? Would it be better to handle differently?
200 while( count!=bc && (rc = ig->source.cb.writecb(p,cbuf+bc,count-bc))>0 ) {
205 IOL_DEB( printf("realseek_write: rc = %d, bc = %d\n", rc, bc) );
211 =item realseek_close(ig)
213 Closes a source that can be seeked on. Not sure if this should be an
214 actual close or not. Does nothing for now. Should be fixed.
222 realseek_close(io_glue *ig) {
223 mm_log((1, "realseek_close(ig %p)\n", ig));
224 if (ig->source.cb.closecb)
225 return ig->source.cb.closecb(ig->source.cb.p);
231 /* realseek_seek(ig, offset, whence)
233 Implements seeking for a source that is seekable, the purpose of having this is to be able to
234 have an offset into a file that is different from what the underlying library thinks.
237 offset - offset into stream
238 whence - whence argument a la lseek
245 realseek_seek(io_glue *ig, off_t offset, int whence) {
246 /* io_ex_rseek *ier = ig->exdata; Needed later */
247 void *p = ig->source.cb.p;
249 IOL_DEB( printf("realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
250 rc = ig->source.cb.seekcb(p, offset, whence);
252 IOL_DEB( printf("realseek_seek: rc %ld\n", (long) rc) );
254 /* FIXME: How about implementing this offset handling stuff? */
259 realseek_destroy(io_glue *ig) {
260 io_ex_rseek *ier = ig->exdata;
262 if (ig->source.cb.destroycb)
263 ig->source.cb.destroycb(ig->source.cb.p);
269 * Callbacks for sources that are a fixed size buffer
273 =item buffer_read(ig, buf, count)
275 Does the reading from a buffer source
278 buf - buffer to return data in
279 count - number of bytes to read into buffer max
286 buffer_read(io_glue *ig, void *buf, size_t count) {
287 io_ex_buffer *ieb = ig->exdata;
289 IOL_DEB( printf("buffer_read: ieb->cpos = %ld, buf = %p, count = %d\n", (long) ieb->cpos, buf, count) );
291 if ( ieb->cpos+count > ig->source.buffer.len ) {
292 mm_log((1,"buffer_read: short read: cpos=%d, len=%d, count=%d\n", ieb->cpos, ig->source.buffer.len));
293 count = ig->source.buffer.len - ieb->cpos;
296 memcpy(buf, ig->source.buffer.data+ieb->cpos, count);
298 IOL_DEB( printf("buffer_read: count = %d\n", count) );
304 =item buffer_write(ig, buf, count)
306 Does nothing, returns -1
309 buf - buffer that contains data
310 count - number of bytes to write
317 buffer_write(io_glue *ig, const void *buf, size_t count) {
318 mm_log((1, "buffer_write called, this method should never be called.\n"));
324 =item buffer_close(ig)
326 Closes a source that can be seeked on. Not sure if this should be an actual close
327 or not. Does nothing for now. Should be fixed.
336 buffer_close(io_glue *ig) {
337 mm_log((1, "buffer_close(ig %p)\n", ig));
343 /* buffer_seek(ig, offset, whence)
345 Implements seeking for a buffer source.
348 offset - offset into stream
349 whence - whence argument a la lseek
356 buffer_seek(io_glue *ig, off_t offset, int whence) {
357 io_ex_buffer *ieb = ig->exdata;
359 calc_seek_offset(ieb->cpos, ig->source.buffer.len, offset, whence);
361 if (reqpos > ig->source.buffer.len) {
362 mm_log((1, "seeking out of readable range\n"));
366 i_push_error(0, "seek before beginning of file");
371 IOL_DEB( printf("buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
374 /* FIXME: How about implementing this offset handling stuff? */
379 buffer_destroy(io_glue *ig) {
380 io_ex_buffer *ieb = ig->exdata;
382 if (ig->source.buffer.closecb) {
383 mm_log((1,"calling close callback %p for io_buffer\n",
384 ig->source.buffer.closecb));
385 ig->source.buffer.closecb(ig->source.buffer.closedata);
393 * Callbacks for sources that are a chain of variable sized buffers
398 /* Helper functions for buffer chains */
405 mm_log((1, "io_blink_new()\n"));
407 ib = mymalloc(sizeof(io_blink));
413 memset(&ib->buf, 0, ib->len);
420 =item io_bchain_advance(ieb)
422 Advances the buffer chain to the next link - extending if
423 necessary. Also adjusts the cpos and tfill counters as needed.
425 ieb - buffer chain object
432 io_bchain_advance(io_ex_bchain *ieb) {
433 if (ieb->cp->next == NULL) {
434 ieb->tail = io_blink_new();
435 ieb->tail->prev = ieb->cp;
436 ieb->cp->next = ieb->tail;
438 ieb->tfill = 0; /* Only set this if we added a new slice */
440 ieb->cp = ieb->cp->next;
447 =item io_bchain_destroy()
449 frees all resources used by a buffer chain.
455 io_destroy_bufchain(io_ex_bchain *ieb) {
457 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
461 io_blink *t = cp->next;
474 bufchain_dump(io_ex_bchain *ieb) {
475 mm_log((1, " buf_chain_dump(ieb %p)\n"));
476 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
477 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
478 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
479 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
480 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
481 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
482 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
483 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
488 * TRUE if lengths are NOT equal
494 chainlencert( io_glue *ig ) {
499 io_ex_bchain *ieb = ig->exdata;
500 io_blink *cp = ieb->head;
503 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
506 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
507 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
508 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
510 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
511 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
513 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
514 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
521 if (!cfl) cpos += clen;
526 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
527 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
533 chaincert( io_glue *ig) {
535 io_ex_bchain *ieb = ig->exdata;
536 io_blink *cp = ieb->head;
538 mm_log((1, "Chain verification.\n"));
540 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
541 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
542 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
543 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
544 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
545 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
546 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
547 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
550 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
551 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
552 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
553 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
555 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
556 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
558 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
559 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
565 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
580 =item bufchain_read(ig, buf, count)
582 Does the reading from a source that can be seeked on
585 buf - buffer to return data in
586 count - number of bytes to read into buffer max
593 bufchain_read(io_glue *ig, void *buf, size_t count) {
594 io_ex_bchain *ieb = ig->exdata;
595 size_t scount = count;
599 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, count));
602 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
603 if (clen == ieb->cpos) {
604 if (ieb->cp == ieb->tail) break; /* EOF */
605 ieb->cp = ieb->cp->next;
607 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
610 sk = clen - ieb->cpos;
611 sk = sk > scount ? scount : sk;
613 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
619 mm_log((1, "bufchain_read: returning %d\n", count-scount));
628 =item bufchain_write(ig, buf, count)
630 Does the writing to a 'source' that can be seeked on
633 buf - buffer that contains data
634 count - number of bytes to write
641 bufchain_write(io_glue *ig, const void *buf, size_t count) {
642 char *cbuf = (char *)buf;
643 io_ex_bchain *ieb = ig->exdata;
644 size_t ocount = count;
647 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %d\n", ig, buf, count));
649 IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %d\n", ig, (long) ieb->cpos, buf, count) );
652 mm_log((2, "bufchain_write: - looping - count = %d\n", count));
653 if (ieb->cp->len == ieb->cpos) {
654 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %d - advancing chain\n", (long) ieb->cpos));
655 io_bchain_advance(ieb);
658 sk = ieb->cp->len - ieb->cpos;
659 sk = sk > count ? count : sk;
660 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
662 if (ieb->cp == ieb->tail) {
663 int extend = ieb->cpos + sk - ieb->tfill;
664 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
666 ieb->length += extend;
667 ieb->tfill += extend;
679 =item bufchain_close(ig)
681 Closes a source that can be seeked on. Not sure if this should be an actual close
682 or not. Does nothing for now. Should be fixed.
691 bufchain_close(io_glue *ig) {
692 mm_log((1, "bufchain_close(ig %p)\n",ig));
693 IOL_DEB( printf("bufchain_close(ig %p)\n", ig) );
699 /* bufchain_seek(ig, offset, whence)
701 Implements seeking for a source that is seekable, the purpose of having this is to be able to
702 have an offset into a file that is different from what the underlying library thinks.
705 offset - offset into stream
706 whence - whence argument a la lseek
713 bufchain_seek(io_glue *ig, off_t offset, int whence) {
714 io_ex_bchain *ieb = ig->exdata;
717 off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence);
720 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence));
723 i_push_error(0, "invalid whence supplied or seek before start of file");
732 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
733 if (clen == ieb->cpos) {
734 if (ieb->cp == ieb->tail) break; /* EOF */
735 ieb->cp = ieb->cp->next;
737 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
740 sk = clen - ieb->cpos;
741 sk = sk > scount ? scount : sk;
752 * extending file - get ieb into consistent state and then
753 * call write which will get it to the correct position
756 memset(TB, 0, BBSIZ);
757 ieb->gpos = ieb->length;
758 ieb->cpos = ieb->tfill;
761 ssize_t rc, wl = i_min(wrlen, BBSIZ);
762 mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl));
763 rc = bufchain_write( ig, TB, wl );
764 if (rc != wl) i_fatal(0, "bufchain_seek: Unable to extend file\n");
769 mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos));
775 bufchain_destroy(io_glue *ig) {
776 io_ex_bchain *ieb = ig->exdata;
778 io_destroy_bufchain(ieb);
784 * Methods for setting up data source
788 =item io_obj_setp_buffer(io, p, len)
790 Sets an io_object for reading from a buffer source
792 io - io object that describes a source
793 p - pointer to buffer
794 len - length of buffer
800 io_obj_setp_buffer(io_obj *io, char *p, size_t len, i_io_closebufp_t closecb,
802 io->buffer.type = BUFFER;
804 io->buffer.len = len;
805 io->buffer.closecb = closecb;
806 io->buffer.closedata = closedata;
812 =item io_obj_setp_cb2(io, p, readcb, writecb, seekcb, closecb, destroycb)
814 Sets an io_object for reading from a source that uses callbacks
816 io - io object that describes a source
817 p - pointer to data for callbacks
818 readcb - read callback to read from source
819 writecb - write callback to write to source
820 seekcb - seek callback to seek on source
821 closecb - flush any pending data
822 destroycb - release any extra resources
828 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) {
829 io->cb.type = CBSEEK;
831 io->cb.readcb = readcb;
832 io->cb.writecb = writecb;
833 io->cb.seekcb = seekcb;
834 io->cb.closecb = closecb;
835 io->cb.destroycb = destroycb;
839 =item io_glue_commit_types(ig)
841 This is now effectively a no-op.
847 io_glue_commit_types(io_glue *ig) {
848 io_type inn = ig->source.type;
850 mm_log((1, "io_glue_commit_types(ig %p)\n", ig));
851 mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn]));
853 if (ig->flags & 0x01) {
854 mm_log((1, "io_glue_commit_types: type already set up\n"));
858 ig->flags |= 0x01; /* indicate source has been setup already */
862 =item io_glue_gettypes(ig, reqmeth)
864 Returns a set of compatible interfaces to read data with.
867 reqmeth - request mask
869 The request mask is a bit mask (of something that hasn't been implemented yet)
870 of interfaces that it would like to read data from the source which the ig
877 io_glue_gettypes(io_glue *ig, int reqmeth) {
882 /* FIXME: Implement this function! */
883 /* if (ig->source.type =
884 if (reqmeth & IO_BUFF) */
890 =item io_new_bufchain()
892 returns a new io_glue object that has the 'empty' source and but can
893 be written to and read from later (like a pseudo file).
901 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
903 mm_log((1, "io_new_bufchain()\n"));
905 ig = mymalloc(sizeof(io_glue));
906 memset(ig, 0, sizeof(*ig));
907 ig->source.type = BUFCHAIN;
915 ieb->head = io_blink_new();
917 ieb->tail = ieb->head;
920 ig->readcb = bufchain_read;
921 ig->writecb = bufchain_write;
922 ig->seekcb = bufchain_seek;
923 ig->closecb = bufchain_close;
924 ig->destroycb = bufchain_destroy;
930 =item io_new_buffer(data, len)
932 Returns a new io_glue object that has the source defined as reading
933 from specified buffer. Note that the buffer is not copied.
935 data - buffer to read from
936 len - length of buffer
942 io_new_buffer(char *data, size_t len, i_io_closebufp_t closecb, void *closedata) {
944 io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
946 mm_log((1, "io_new_buffer(data %p, len %d, closecb %p, closedata %p)\n", data, len, closecb, closedata));
948 ig = mymalloc(sizeof(io_glue));
949 memset(ig, 0, sizeof(*ig));
950 io_obj_setp_buffer(&ig->source, data, len, closecb, closedata);
957 ig->readcb = buffer_read;
958 ig->writecb = buffer_write;
959 ig->seekcb = buffer_seek;
960 ig->closecb = buffer_close;
961 ig->destroycb = buffer_destroy;
970 returns a new io_glue object that has the source defined as reading
971 from specified filedescriptor. Note that the the interface to recieving
972 data from the io_glue callbacks hasn't been done yet.
974 fd - file descriptor to read/write from
983 mm_log((1, "io_new_fd(fd %d)\n", fd));
985 ig = mymalloc(sizeof(io_glue));
986 memset(ig, 0, sizeof(*ig));
987 ig->source.type = FDSEEK;
988 ig->source.fdseek.fd = fd;
992 ig->readcb = fd_read;
993 ig->writecb = fd_write;
994 ig->seekcb = fd_seek;
995 ig->closecb = fd_close;
996 ig->sizecb = fd_size;
997 ig->destroycb = NULL;
999 mm_log((1, "(%p) <- io_new_fd\n", ig));
1003 io_glue *io_new_cb(void *p, i_io_readl_t readcb, i_io_writel_t writecb,
1004 i_io_seekl_t seekcb, i_io_closel_t closecb,
1005 i_io_destroyl_t destroycb) {
1007 io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
1009 mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
1010 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
1011 ig = mymalloc(sizeof(io_glue));
1012 memset(ig, 0, sizeof(*ig));
1013 io_obj_setp_cb2(&ig->source, p, readcb, writecb, seekcb, closecb, destroycb);
1014 mm_log((1, "(%p) <- io_new_cb\n", ig));
1020 ig->readcb = realseek_read;
1021 ig->writecb = realseek_write;
1022 ig->seekcb = realseek_seek;
1023 ig->closecb = realseek_close;
1024 ig->destroycb = realseek_destroy;
1032 Takes the source that the io_glue is bound to and allocates space
1033 for a return buffer and returns the entire content in a single buffer.
1034 Note: This only works for io_glue objects that contain a bufchain. It
1035 is usefull for saving to scalars and such.
1038 c - pointer to a pointer to where data should be copied to
1044 io_slurp(io_glue *ig, unsigned char **c) {
1049 io_type inn = ig->source.type;
1051 if ( inn != BUFCHAIN ) {
1052 i_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
1056 cc = *c = mymalloc( ieb->length );
1060 bufchain_seek(ig, 0, SEEK_SET);
1062 rc = bufchain_read(ig, cc, ieb->length);
1064 if (rc != ieb->length)
1065 i_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
1071 =item fd_read(ig, buf, count)
1075 static ssize_t fd_read(io_glue *ig, void *buf, size_t count) {
1078 result = _read(ig->source.fdseek.fd, buf, count);
1080 result = read(ig->source.fdseek.fd, buf, count);
1083 /* 0 is valid - means EOF */
1085 i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
1091 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count) {
1094 result = _write(ig->source.fdseek.fd, buf, count);
1096 result = write(ig->source.fdseek.fd, buf, count);
1100 i_push_errorf(errno, "write() failure: %s (%d)", my_strerror(errno), errno);
1106 static off_t fd_seek(io_glue *ig, off_t offset, int whence) {
1109 result = _lseek(ig->source.fdseek.fd, offset, whence);
1111 result = lseek(ig->source.fdseek.fd, offset, whence);
1114 if (result == (off_t)-1) {
1115 i_push_errorf(errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
1121 static int fd_close(io_glue *ig) {
1122 /* no, we don't close it */
1126 static ssize_t fd_size(io_glue *ig) {
1127 mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
1133 =item io_glue_destroy(ig)
1135 A destructor method for io_glue objects. Should clean up all related buffers.
1136 Might leave us with a dangling pointer issue on some buffers.
1138 ig - io_glue object to destroy.
1144 io_glue_destroy(io_glue *ig) {
1145 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
1156 =head1 INTERNAL FUNCTIONS
1162 Calls strerror() and ensures we don't return NULL.
1164 On some platforms it's possible for strerror() to return NULL, this
1165 wrapper ensures we only get non-NULL values.
1171 const char *my_strerror(int err) {
1172 const char *result = strerror(err);
1175 result = "Unknown error";
1185 Arnar M. Hrafnkelsson <addi@umich.edu>