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 void 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: fd = %d, ier->cpos = %ld, buf = %p, "
161 "count = %d\n", fd, (long) ier->cpos, buf, count) );
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 ig->source.cb.closecb(ig->source.cb.p);
229 /* realseek_seek(ig, offset, whence)
231 Implements seeking for a source that is seekable, the purpose of having this is to be able to
232 have an offset into a file that is different from what the underlying library thinks.
235 offset - offset into stream
236 whence - whence argument a la lseek
243 realseek_seek(io_glue *ig, off_t offset, int whence) {
244 /* io_ex_rseek *ier = ig->exdata; Needed later */
245 void *p = ig->source.cb.p;
247 IOL_DEB( printf("realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
248 rc = ig->source.cb.seekcb(p, offset, whence);
250 IOL_DEB( printf("realseek_seek: rc %ld\n", (long) rc) );
252 /* FIXME: How about implementing this offset handling stuff? */
257 realseek_destroy(io_glue *ig) {
258 io_ex_rseek *ier = ig->exdata;
260 if (ig->source.cb.destroycb)
261 ig->source.cb.destroycb(ig->source.cb.p);
267 * Callbacks for sources that are a fixed size buffer
271 =item buffer_read(ig, buf, count)
273 Does the reading from a buffer source
276 buf - buffer to return data in
277 count - number of bytes to read into buffer max
284 buffer_read(io_glue *ig, void *buf, size_t count) {
285 io_ex_buffer *ieb = ig->exdata;
287 IOL_DEB( printf("buffer_read: fd = %d, ier->cpos = %ld, buf = %p, count = %d\n", fd, (long) ier->cpos, buf, count) );
289 if ( ieb->cpos+count > ig->source.buffer.len ) {
290 mm_log((1,"buffer_read: short read: cpos=%d, len=%d, count=%d\n", ieb->cpos, ig->source.buffer.len));
291 count = ig->source.buffer.len - ieb->cpos;
294 memcpy(buf, ig->source.buffer.data+ieb->cpos, count);
296 IOL_DEB( printf("buffer_read: rc = %d, count = %d\n", rc, count) );
302 =item buffer_write(ig, buf, count)
304 Does nothing, returns -1
307 buf - buffer that contains data
308 count - number of bytes to write
315 buffer_write(io_glue *ig, const void *buf, size_t count) {
316 mm_log((1, "buffer_write called, this method should never be called.\n"));
322 =item buffer_close(ig)
324 Closes a source that can be seeked on. Not sure if this should be an actual close
325 or not. Does nothing for now. Should be fixed.
334 buffer_close(io_glue *ig) {
335 mm_log((1, "buffer_close(ig %p)\n", ig));
336 /* FIXME: Do stuff here */
340 /* buffer_seek(ig, offset, whence)
342 Implements seeking for a buffer source.
345 offset - offset into stream
346 whence - whence argument a la lseek
353 buffer_seek(io_glue *ig, off_t offset, int whence) {
354 io_ex_buffer *ieb = ig->exdata;
356 calc_seek_offset(ieb->cpos, ig->source.buffer.len, offset, whence);
358 if (reqpos > ig->source.buffer.len) {
359 mm_log((1, "seeking out of readable range\n"));
363 i_push_error(0, "seek before beginning of file");
368 IOL_DEB( printf("buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
371 /* FIXME: How about implementing this offset handling stuff? */
376 buffer_destroy(io_glue *ig) {
377 io_ex_buffer *ieb = ig->exdata;
379 if (ig->source.buffer.closecb) {
380 mm_log((1,"calling close callback %p for io_buffer\n",
381 ig->source.buffer.closecb));
382 ig->source.buffer.closecb(ig->source.buffer.closedata);
390 * Callbacks for sources that are a chain of variable sized buffers
395 /* Helper functions for buffer chains */
402 mm_log((1, "io_blink_new()\n"));
404 ib = mymalloc(sizeof(io_blink));
410 memset(&ib->buf, 0, ib->len);
417 =item io_bchain_advance(ieb)
419 Advances the buffer chain to the next link - extending if
420 necessary. Also adjusts the cpos and tfill counters as needed.
422 ieb - buffer chain object
429 io_bchain_advance(io_ex_bchain *ieb) {
430 if (ieb->cp->next == NULL) {
431 ieb->tail = io_blink_new();
432 ieb->tail->prev = ieb->cp;
433 ieb->cp->next = ieb->tail;
435 ieb->tfill = 0; /* Only set this if we added a new slice */
437 ieb->cp = ieb->cp->next;
444 =item io_bchain_destroy()
446 frees all resources used by a buffer chain.
452 io_destroy_bufchain(io_ex_bchain *ieb) {
454 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
458 io_blink *t = cp->next;
471 bufchain_dump(io_ex_bchain *ieb) {
472 mm_log((1, " buf_chain_dump(ieb %p)\n"));
473 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
474 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
475 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
476 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
477 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
478 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
479 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
480 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
485 * TRUE if lengths are NOT equal
491 chainlencert( io_glue *ig ) {
496 io_ex_bchain *ieb = ig->exdata;
497 io_blink *cp = ieb->head;
500 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
503 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
504 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
505 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
507 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
508 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
510 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
511 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
518 if (!cfl) cpos += clen;
523 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
524 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
530 chaincert( io_glue *ig) {
532 io_ex_bchain *ieb = ig->exdata;
533 io_blink *cp = ieb->head;
535 mm_log((1, "Chain verification.\n"));
537 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
538 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
539 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
540 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
541 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
542 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
543 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
544 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
547 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
548 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
549 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
550 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
552 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
553 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
555 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
556 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
562 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
577 =item bufchain_read(ig, buf, count)
579 Does the reading from a source that can be seeked on
582 buf - buffer to return data in
583 count - number of bytes to read into buffer max
590 bufchain_read(io_glue *ig, void *buf, size_t count) {
591 io_ex_bchain *ieb = ig->exdata;
592 size_t scount = count;
596 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, count));
599 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
600 if (clen == ieb->cpos) {
601 if (ieb->cp == ieb->tail) break; /* EOF */
602 ieb->cp = ieb->cp->next;
604 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
607 sk = clen - ieb->cpos;
608 sk = sk > scount ? scount : sk;
610 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
616 mm_log((1, "bufchain_read: returning %d\n", count-scount));
625 =item bufchain_write(ig, buf, count)
627 Does the writing to a 'source' that can be seeked on
630 buf - buffer that contains data
631 count - number of bytes to write
638 bufchain_write(io_glue *ig, const void *buf, size_t count) {
639 char *cbuf = (char *)buf;
640 io_ex_bchain *ieb = ig->exdata;
641 size_t ocount = count;
644 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %d\n", ig, buf, count));
646 IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %d\n", ig, (long) ieb->cpos, buf, count) );
649 mm_log((2, "bufchain_write: - looping - count = %d\n", count));
650 if (ieb->cp->len == ieb->cpos) {
651 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %d - advancing chain\n", (long) ieb->cpos));
652 io_bchain_advance(ieb);
655 sk = ieb->cp->len - ieb->cpos;
656 sk = sk > count ? count : sk;
657 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
659 if (ieb->cp == ieb->tail) {
660 int extend = ieb->cpos + sk - ieb->tfill;
661 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
663 ieb->length += extend;
664 ieb->tfill += extend;
676 =item bufchain_close(ig)
678 Closes a source that can be seeked on. Not sure if this should be an actual close
679 or not. Does nothing for now. Should be fixed.
688 bufchain_close(io_glue *ig) {
689 mm_log((1, "bufchain_close(ig %p)\n",ig));
690 IOL_DEB( printf("bufchain_close(ig %p)\n", ig) );
691 /* FIXME: Commit a seek point here */
696 /* bufchain_seek(ig, offset, whence)
698 Implements seeking for a source that is seekable, the purpose of having this is to be able to
699 have an offset into a file that is different from what the underlying library thinks.
702 offset - offset into stream
703 whence - whence argument a la lseek
710 bufchain_seek(io_glue *ig, off_t offset, int whence) {
711 io_ex_bchain *ieb = ig->exdata;
714 off_t scount = calc_seek_offset(ieb->gpos, ieb->length, offset, whence);
717 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence));
720 i_push_error(0, "invalid whence supplied or seek before start of file");
729 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
730 if (clen == ieb->cpos) {
731 if (ieb->cp == ieb->tail) break; /* EOF */
732 ieb->cp = ieb->cp->next;
734 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
737 sk = clen - ieb->cpos;
738 sk = sk > scount ? scount : sk;
749 * extending file - get ieb into consistent state and then
750 * call write which will get it to the correct position
753 memset(TB, 0, BBSIZ);
754 ieb->gpos = ieb->length;
755 ieb->cpos = ieb->tfill;
758 ssize_t rc, wl = i_min(wrlen, BBSIZ);
759 mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl));
760 rc = bufchain_write( ig, TB, wl );
761 if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n");
766 mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos));
772 bufchain_destroy(io_glue *ig) {
773 io_ex_bchain *ieb = ig->exdata;
775 io_destroy_bufchain(ieb);
781 * Methods for setting up data source
785 =item io_obj_setp_buffer(io, p, len)
787 Sets an io_object for reading from a buffer source
789 io - io object that describes a source
790 p - pointer to buffer
791 len - length of buffer
797 io_obj_setp_buffer(io_obj *io, char *p, size_t len, i_io_closebufp_t closecb,
799 io->buffer.type = BUFFER;
801 io->buffer.len = len;
802 io->buffer.closecb = closecb;
803 io->buffer.closedata = closedata;
809 =item io_obj_setp_cb2(io, p, readcb, writecb, seekcb, closecb, destroycb)
811 Sets an io_object for reading from a source that uses callbacks
813 io - io object that describes a source
814 p - pointer to data for callbacks
815 readcb - read callback to read from source
816 writecb - write callback to write to source
817 seekcb - seek callback to seek on source
818 closecb - flush any pending data
819 destroycb - release any extra resources
825 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) {
826 io->cb.type = CBSEEK;
828 io->cb.readcb = readcb;
829 io->cb.writecb = writecb;
830 io->cb.seekcb = seekcb;
831 io->cb.closecb = closecb;
832 io->cb.destroycb = destroycb;
836 =item io_glue_commit_types(ig)
838 This is now effectively a no-op.
844 io_glue_commit_types(io_glue *ig) {
845 io_type inn = ig->source.type;
847 mm_log((1, "io_glue_commit_types(ig %p)\n", ig));
848 mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn]));
850 if (ig->flags & 0x01) {
851 mm_log((1, "io_glue_commit_types: type already set up\n"));
855 ig->flags |= 0x01; /* indicate source has been setup already */
859 =item io_glue_gettypes(ig, reqmeth)
861 Returns a set of compatible interfaces to read data with.
864 reqmeth - request mask
866 The request mask is a bit mask (of something that hasn't been implemented yet)
867 of interfaces that it would like to read data from the source which the ig
874 io_glue_gettypes(io_glue *ig, int reqmeth) {
879 /* FIXME: Implement this function! */
880 /* if (ig->source.type =
881 if (reqmeth & IO_BUFF) */
887 =item io_new_bufchain()
889 returns a new io_glue object that has the 'empty' source and but can
890 be written to and read from later (like a pseudo file).
898 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
900 mm_log((1, "io_new_bufchain()\n"));
902 ig = mymalloc(sizeof(io_glue));
903 memset(ig, 0, sizeof(*ig));
904 ig->source.type = BUFCHAIN;
912 ieb->head = io_blink_new();
914 ieb->tail = ieb->head;
917 ig->readcb = bufchain_read;
918 ig->writecb = bufchain_write;
919 ig->seekcb = bufchain_seek;
920 ig->closecb = bufchain_close;
921 ig->destroycb = bufchain_destroy;
927 =item io_new_buffer(data, len)
929 Returns a new io_glue object that has the source defined as reading
930 from specified buffer. Note that the buffer is not copied.
932 data - buffer to read from
933 len - length of buffer
939 io_new_buffer(char *data, size_t len, i_io_closebufp_t closecb, void *closedata) {
941 io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
943 mm_log((1, "io_new_buffer(data %p, len %d, closecb %p, closedata %p)\n", data, len, closecb, closedata));
945 ig = mymalloc(sizeof(io_glue));
946 memset(ig, 0, sizeof(*ig));
947 io_obj_setp_buffer(&ig->source, data, len, closecb, closedata);
954 ig->readcb = buffer_read;
955 ig->writecb = buffer_write;
956 ig->seekcb = buffer_seek;
957 ig->closecb = buffer_close;
958 ig->destroycb = buffer_destroy;
967 returns a new io_glue object that has the source defined as reading
968 from specified filedescriptor. Note that the the interface to recieving
969 data from the io_glue callbacks hasn't been done yet.
971 fd - file descriptor to read/write from
980 mm_log((1, "io_new_fd(fd %d)\n", fd));
982 ig = mymalloc(sizeof(io_glue));
983 memset(ig, 0, sizeof(*ig));
984 ig->source.type = FDSEEK;
985 ig->source.fdseek.fd = fd;
989 ig->readcb = fd_read;
990 ig->writecb = fd_write;
991 ig->seekcb = fd_seek;
992 ig->closecb = fd_close;
993 ig->sizecb = fd_size;
994 ig->destroycb = NULL;
996 mm_log((1, "(%p) <- io_new_fd\n", ig));
1000 io_glue *io_new_cb(void *p, i_io_readl_t readcb, i_io_writel_t writecb,
1001 i_io_seekl_t seekcb, i_io_closel_t closecb,
1002 i_io_destroyl_t destroycb) {
1004 io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
1006 mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
1007 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
1008 ig = mymalloc(sizeof(io_glue));
1009 memset(ig, 0, sizeof(*ig));
1010 io_obj_setp_cb2(&ig->source, p, readcb, writecb, seekcb, closecb, destroycb);
1011 mm_log((1, "(%p) <- io_new_cb\n", ig));
1017 ig->readcb = realseek_read;
1018 ig->writecb = realseek_write;
1019 ig->seekcb = realseek_seek;
1020 ig->closecb = realseek_close;
1021 ig->destroycb = realseek_destroy;
1029 Takes the source that the io_glue is bound to and allocates space
1030 for a return buffer and returns the entire content in a single buffer.
1031 Note: This only works for io_glue objects that contain a bufchain. It
1032 is usefull for saving to scalars and such.
1035 c - pointer to a pointer to where data should be copied to
1041 io_slurp(io_glue *ig, unsigned char **c) {
1046 io_type inn = ig->source.type;
1048 if ( inn != BUFCHAIN ) {
1049 m_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
1053 cc = *c = mymalloc( ieb->length );
1057 bufchain_seek(ig, 0, SEEK_SET);
1059 rc = bufchain_read(ig, cc, ieb->length);
1061 if (rc != ieb->length)
1062 m_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
1068 =item fd_read(ig, buf, count)
1072 static ssize_t fd_read(io_glue *ig, void *buf, size_t count) {
1075 result = _read(ig->source.fdseek.fd, buf, count);
1077 result = read(ig->source.fdseek.fd, buf, count);
1080 /* 0 is valid - means EOF */
1082 i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
1088 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count) {
1091 result = _write(ig->source.fdseek.fd, buf, count);
1093 result = write(ig->source.fdseek.fd, buf, count);
1097 i_push_errorf(errno, "write() failure: %s (%d)", my_strerror(errno), errno);
1103 static off_t fd_seek(io_glue *ig, off_t offset, int whence) {
1106 result = _lseek(ig->source.fdseek.fd, offset, whence);
1108 result = lseek(ig->source.fdseek.fd, offset, whence);
1111 if (result == (off_t)-1) {
1112 i_push_errorf(errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
1118 static void fd_close(io_glue *ig) {
1119 /* no, we don't close it */
1122 static ssize_t fd_size(io_glue *ig) {
1123 mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
1129 =item io_glue_destroy(ig)
1131 A destructor method for io_glue objects. Should clean up all related buffers.
1132 Might leave us with a dangling pointer issue on some buffers.
1134 ig - io_glue object to destroy.
1140 io_glue_destroy(io_glue *ig) {
1141 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
1152 =head1 INTERNAL FUNCTIONS
1158 Calls strerror() and ensures we don't return NULL.
1160 On some platforms it's possible for strerror() to return NULL, this
1161 wrapper ensures we only get non-NULL values.
1167 const char *my_strerror(int err) {
1168 const char *result = strerror(err);
1171 result = "Unknown error";
1181 Arnar M. Hrafnkelsson <addi@umich.edu>