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? */
251 * Callbacks for sources that are a fixed size buffer
255 =item buffer_read(ig, buf, count)
257 Does the reading from a buffer source
260 buf - buffer to return data in
261 count - number of bytes to read into buffer max
268 buffer_read(io_glue *ig, void *buf, size_t count) {
269 io_ex_buffer *ieb = ig->exdata;
271 IOL_DEB( printf("buffer_read: fd = %d, ier->cpos = %ld, buf = %p, count = %d\n", fd, (long) ier->cpos, buf, count) );
273 if ( ieb->cpos+count > ig->source.buffer.len ) {
274 mm_log((1,"buffer_read: short read: cpos=%d, len=%d, count=%d\n", ieb->cpos, ig->source.buffer.len));
275 count = ig->source.buffer.len - ieb->cpos;
278 memcpy(buf, ig->source.buffer.data+ieb->cpos, count);
280 IOL_DEB( printf("buffer_read: rc = %d, count = %d\n", rc, count) );
286 =item buffer_write(ig, buf, count)
288 Does nothing, returns -1
291 buf - buffer that contains data
292 count - number of bytes to write
299 buffer_write(io_glue *ig, const void *buf, size_t count) {
300 mm_log((1, "buffer_write called, this method should never be called.\n"));
306 =item buffer_close(ig)
308 Closes a source that can be seeked on. Not sure if this should be an actual close
309 or not. Does nothing for now. Should be fixed.
318 buffer_close(io_glue *ig) {
319 mm_log((1, "buffer_close(ig %p)\n", ig));
320 /* FIXME: Do stuff here */
324 /* buffer_seek(ig, offset, whence)
326 Implements seeking for a buffer source.
329 offset - offset into stream
330 whence - whence argument a la lseek
337 buffer_seek(io_glue *ig, off_t offset, int whence) {
338 io_ex_buffer *ieb = ig->exdata;
339 off_t reqpos = offset
340 + (whence == SEEK_CUR)*ieb->cpos
341 + (whence == SEEK_END)*ig->source.buffer.len;
343 if (reqpos > ig->source.buffer.len) {
344 mm_log((1, "seeking out of readable range\n"));
349 IOL_DEB( printf("buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
352 /* FIXME: How about implementing this offset handling stuff? */
360 * Callbacks for sources that are a chain of variable sized buffers
365 /* Helper functions for buffer chains */
372 mm_log((1, "io_blink_new()\n"));
374 ib = mymalloc(sizeof(io_blink));
380 memset(&ib->buf, 0, ib->len);
387 =item io_bchain_advance(ieb)
389 Advances the buffer chain to the next link - extending if
390 necessary. Also adjusts the cpos and tfill counters as needed.
392 ieb - buffer chain object
399 io_bchain_advance(io_ex_bchain *ieb) {
400 if (ieb->cp->next == NULL) {
401 ieb->tail = io_blink_new();
402 ieb->tail->prev = ieb->cp;
403 ieb->cp->next = ieb->tail;
405 ieb->tfill = 0; /* Only set this if we added a new slice */
407 ieb->cp = ieb->cp->next;
414 =item io_bchain_destroy()
416 frees all resources used by a buffer chain.
422 io_destroy_bufchain(io_ex_bchain *ieb) {
424 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
428 io_blink *t = cp->next;
441 bufchain_dump(io_ex_bchain *ieb) {
442 mm_log((1, " buf_chain_dump(ieb %p)\n"));
443 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
444 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
445 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
446 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
447 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
448 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
449 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
450 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
455 * TRUE if lengths are NOT equal
461 chainlencert( io_glue *ig ) {
466 io_ex_bchain *ieb = ig->exdata;
467 io_blink *cp = ieb->head;
470 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
473 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
474 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
475 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
477 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
478 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
480 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
481 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
488 if (!cfl) cpos += clen;
493 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
494 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
500 chaincert( io_glue *ig) {
502 io_ex_bchain *ieb = ig->exdata;
503 io_blink *cp = ieb->head;
505 mm_log((1, "Chain verification.\n"));
507 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
508 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
509 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
510 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
511 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
512 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
513 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
514 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
517 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
518 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
519 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
520 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
522 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
523 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
525 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
526 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
532 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
547 =item bufchain_read(ig, buf, count)
549 Does the reading from a source that can be seeked on
552 buf - buffer to return data in
553 count - number of bytes to read into buffer max
560 bufchain_read(io_glue *ig, void *buf, size_t count) {
561 io_ex_bchain *ieb = ig->exdata;
562 size_t scount = count;
566 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, count));
569 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
570 if (clen == ieb->cpos) {
571 if (ieb->cp == ieb->tail) break; /* EOF */
572 ieb->cp = ieb->cp->next;
574 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
577 sk = clen - ieb->cpos;
578 sk = sk > scount ? scount : sk;
580 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
586 mm_log((1, "bufchain_read: returning %d\n", count-scount));
595 =item bufchain_write(ig, buf, count)
597 Does the writing to a 'source' that can be seeked on
600 buf - buffer that contains data
601 count - number of bytes to write
608 bufchain_write(io_glue *ig, const void *buf, size_t count) {
609 char *cbuf = (char *)buf;
610 io_ex_bchain *ieb = ig->exdata;
611 size_t ocount = count;
614 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %d\n", ig, buf, count));
616 IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %d\n", ig, (long) ieb->cpos, buf, count) );
619 mm_log((2, "bufchain_write: - looping - count = %d\n", count));
620 if (ieb->cp->len == ieb->cpos) {
621 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %d - advancing chain\n", (long) ieb->cpos));
622 io_bchain_advance(ieb);
625 sk = ieb->cp->len - ieb->cpos;
626 sk = sk > count ? count : sk;
627 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
629 if (ieb->cp == ieb->tail) {
630 int extend = ieb->cpos + sk - ieb->tfill;
631 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
633 ieb->length += extend;
634 ieb->tfill += extend;
646 =item bufchain_close(ig)
648 Closes a source that can be seeked on. Not sure if this should be an actual close
649 or not. Does nothing for now. Should be fixed.
658 bufchain_close(io_glue *ig) {
659 mm_log((1, "bufchain_close(ig %p)\n",ig));
660 IOL_DEB( printf("bufchain_close(ig %p)\n", ig) );
661 /* FIXME: Commit a seek point here */
666 /* bufchain_seek(ig, offset, whence)
668 Implements seeking for a source that is seekable, the purpose of having this is to be able to
669 have an offset into a file that is different from what the underlying library thinks.
672 offset - offset into stream
673 whence - whence argument a la lseek
680 bufchain_seek(io_glue *ig, off_t offset, int whence) {
681 io_ex_bchain *ieb = ig->exdata;
686 off_t scount = offset;
689 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence));
692 case SEEK_SET: /* SEEK_SET = 0, From the top */
698 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
699 if (clen == ieb->cpos) {
700 if (ieb->cp == ieb->tail) break; /* EOF */
701 ieb->cp = ieb->cp->next;
703 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
706 sk = clen - ieb->cpos;
707 sk = sk > scount ? scount : sk;
718 * extending file - get ieb into consistent state and then
719 * call write which will get it to the correct position
722 memset(TB, 0, BBSIZ);
723 ieb->gpos = ieb->length;
724 ieb->cpos = ieb->tfill;
727 ssize_t rc, wl = i_min(wrlen, BBSIZ);
728 mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl));
729 rc = bufchain_write( ig, TB, wl );
730 if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n");
738 m_fatal(123, "SEEK_CUR IS NOT IMPLEMENTED\n");
746 while(cof < 0 && ib->prev) {
752 case SEEK_END: /* SEEK_END = 2 */
753 if (cof>0) m_fatal(0, "bufchain_seek: SEEK_END + %d : Extending files via seek not supported!\n", cof);
756 ieb->cpos = ieb->tfill;
762 while(cof<0 && ib->prev) {
767 if (cof<0) m_fatal(0, "bufchain_seek: Tried to seek before start of file\n");
768 ieb->gpos = ieb->length+offset;
773 m_fatal(0, "bufchain_seek: Unhandled seek request: whence = %d\n", whence );
776 mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos));
786 * Methods for setting up data source
790 =item io_obj_setp_buffer(io, p, len)
792 Sets an io_object for reading from a buffer source
794 io - io object that describes a source
795 p - pointer to buffer
796 len - length of buffer
802 io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb,
804 io->buffer.type = BUFFER;
806 io->buffer.len = len;
807 io->buffer.closecb = closecb;
808 io->buffer.closedata = closedata;
814 =item io_obj_setp_cb2(io, p, readcb, writecb, seekcb, closecb, destroycb)
816 Sets an io_object for reading from a source that uses callbacks
818 io - io object that describes a source
819 p - pointer to data for callbacks
820 readcb - read callback to read from source
821 writecb - write callback to write to source
822 seekcb - seek callback to seek on source
823 closecb - flush any pending data
824 destroycb - release any extra resources
830 io_obj_setp_cb2(io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb, closel closecb, destroyl destroycb) {
831 io->cb.type = CBSEEK;
833 io->cb.readcb = readcb;
834 io->cb.writecb = writecb;
835 io->cb.seekcb = seekcb;
836 io->cb.closecb = closecb;
837 io->cb.destroycb = destroycb;
841 =item io_glue_commit_types(ig)
843 This is now effectively a no-op.
849 io_glue_commit_types(io_glue *ig) {
850 io_type inn = ig->source.type;
852 mm_log((1, "io_glue_commit_types(ig %p)\n", ig));
853 mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn]));
855 if (ig->flags & 0x01) {
856 mm_log((1, "io_glue_commit_types: type already set up\n"));
860 ig->flags |= 0x01; /* indicate source has been setup already */
864 =item io_glue_gettypes(ig, reqmeth)
866 Returns a set of compatible interfaces to read data with.
869 reqmeth - request mask
871 The request mask is a bit mask (of something that hasn't been implemented yet)
872 of interfaces that it would like to read data from the source which the ig
879 io_glue_gettypes(io_glue *ig, int reqmeth) {
884 /* FIXME: Implement this function! */
885 /* if (ig->source.type =
886 if (reqmeth & IO_BUFF) */
892 =item io_new_bufchain()
894 returns a new io_glue object that has the 'empty' source and but can
895 be written to and read from later (like a pseudo file).
903 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
905 mm_log((1, "io_new_bufchain()\n"));
907 ig = mymalloc(sizeof(io_glue));
908 memset(ig, 0, sizeof(*ig));
909 ig->source.type = BUFCHAIN;
917 ieb->head = io_blink_new();
919 ieb->tail = ieb->head;
922 ig->readcb = bufchain_read;
923 ig->writecb = bufchain_write;
924 ig->seekcb = bufchain_seek;
925 ig->closecb = bufchain_close;
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, closebufp closecb, void *closedata) {
945 io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
947 mm_log((1, "io_new_buffer(data %p, len %d, closecb %p, closedata %p)\n", data, 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;
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;
998 mm_log((1, "(%p) <- io_new_fd\n", ig));
1002 io_glue *io_new_cb(void *p, readl readcb, writel writecb, seekl seekcb,
1003 closel closecb, destroyl destroycb) {
1005 io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
1007 mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
1008 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
1009 ig = mymalloc(sizeof(io_glue));
1010 memset(ig, 0, sizeof(*ig));
1011 io_obj_setp_cb2(&ig->source, p, readcb, writecb, seekcb, closecb, destroycb);
1012 mm_log((1, "(%p) <- io_new_cb\n", ig));
1018 ig->readcb = realseek_read;
1019 ig->writecb = realseek_write;
1020 ig->seekcb = realseek_seek;
1021 ig->closecb = realseek_close;
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 io_type inn = ig->source.type;
1142 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
1147 io_ex_bchain *ieb = ig->exdata;
1148 io_destroy_bufchain(ieb);
1154 io_ex_rseek *ier = ig->exdata;
1155 if (ig->source.cb.destroycb)
1156 ig->source.cb.destroycb(ig->source.cb.p);
1162 io_ex_buffer *ieb = ig->exdata;
1163 if (ig->source.buffer.closecb) {
1164 mm_log((1,"calling close callback %p for io_buffer\n", ig->source.buffer.closecb));
1165 ig->source.buffer.closecb(ig->source.buffer.closedata);
1179 =head1 INTERNAL FUNCTIONS
1185 Calls strerror() and ensures we don't return NULL.
1187 On some platforms it's possible for strerror() to return NULL, this
1188 wrapper ensures we only get non-NULL values.
1194 const char *my_strerror(int err) {
1195 const char *result = strerror(err);
1198 result = "Unknown error";
1208 Arnar M. Hrafnkelsson <addi@umich.edu>