16 char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
22 iolayer.c - encapsulates different source of data into a single framework.
26 io_glue *ig = io_new_fd( fileno(stdin) );
27 method = io_reqmeth( IOL_NOSEEK | IOL_MMAP ); // not implemented yet
28 io_glue_commit_types(ig); // always assume IOL_SEEK for now
31 code that uses ig->readcb()
32 to read data goes here.
35 code that uses ig->readcb()
36 to read data goes here.
45 iolayer.c implements the basic functions to create and destroy io_glue
46 objects for Imager. The typical usage pattern for data sources is:
48 1. Create the source (io_new_fd)
49 2. Define how you want to get data from it (io_reqmeth)
50 3. read from it using the interface requested (ig->readdb, ig->mmapcb)
51 4. Close the source, which
52 shouldn't really close the underlying source. (io_glue DESTROY)
54 =head1 FUNCTION REFERENCE
56 Some of these functions are internal.
63 static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
64 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
65 static off_t fd_seek(io_glue *ig, off_t offset, int whence);
66 static void fd_close(io_glue *ig);
67 static ssize_t fd_size(io_glue *ig);
68 static const char *my_strerror(int err);
71 * Callbacks for sources that cannot seek
74 /* fakeseek_read: read method for when emulating a seekable source
77 fakeseek_read(io_glue *ig, void *buf, size_t count) {
78 io_ex_fseek *exdata = ig->exdata;
86 * Callbacks for sources that can seek
90 =item realseek_read(ig, buf, count)
92 Does the reading from a source that can be seeked on
95 buf - buffer to return data in
96 count - number of bytes to read into buffer max
103 realseek_read(io_glue *ig, void *buf, size_t count) {
104 io_ex_rseek *ier = ig->exdata;
105 void *p = ig->source.cb.p;
110 IOL_DEB( printf("realseek_read: fd = %d, ier->cpos = %ld, buf = %p, "
111 "count = %d\n", fd, (long) ier->cpos, buf, count) );
112 /* Is this a good idea? Would it be better to handle differently?
114 while( count!=bc && (rc = ig->source.cb.readcb(p,cbuf+bc,count-bc))>0 ) {
119 IOL_DEB( printf("realseek_read: rc = %d, bc = %d\n", rc, bc) );
125 =item realseek_write(ig, buf, count)
127 Does the writing to a 'source' that can be seeked on
130 buf - buffer that contains data
131 count - number of bytes to write
138 realseek_write(io_glue *ig, const void *buf, size_t count) {
139 io_ex_rseek *ier = ig->exdata;
140 void *p = ig->source.cb.p;
143 char *cbuf = (char*)buf;
145 IOL_DEB( printf("realseek_write: ig = %p, ier->cpos = %ld, buf = %p, "
146 "count = %d\n", ig, (long) ier->cpos, buf, count) );
148 /* Is this a good idea? Would it be better to handle differently?
150 while( count!=bc && (rc = ig->source.cb.writecb(p,cbuf+bc,count-bc))>0 ) {
155 IOL_DEB( printf("realseek_write: rc = %d, bc = %d\n", rc, bc) );
161 =item realseek_close(ig)
163 Closes a source that can be seeked on. Not sure if this should be an
164 actual close or not. Does nothing for now. Should be fixed.
172 realseek_close(io_glue *ig) {
173 mm_log((1, "realseek_close(ig %p)\n", ig));
174 if (ig->source.cb.closecb)
175 ig->source.cb.closecb(ig->source.cb.p);
179 /* realseek_seek(ig, offset, whence)
181 Implements seeking for a source that is seekable, the purpose of having this is to be able to
182 have an offset into a file that is different from what the underlying library thinks.
185 offset - offset into stream
186 whence - whence argument a la lseek
193 realseek_seek(io_glue *ig, off_t offset, int whence) {
194 /* io_ex_rseek *ier = ig->exdata; Needed later */
195 void *p = ig->source.cb.p;
197 IOL_DEB( printf("realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
198 rc = ig->source.cb.seekcb(p, offset, whence);
200 IOL_DEB( printf("realseek_seek: rc %ld\n", (long) rc) );
202 /* FIXME: How about implementing this offset handling stuff? */
206 * Callbacks for sources that are a fixed size buffer
210 =item buffer_read(ig, buf, count)
212 Does the reading from a buffer source
215 buf - buffer to return data in
216 count - number of bytes to read into buffer max
223 buffer_read(io_glue *ig, void *buf, size_t count) {
224 io_ex_buffer *ieb = ig->exdata;
226 IOL_DEB( printf("buffer_read: fd = %d, ier->cpos = %ld, buf = %p, count = %d\n", fd, (long) ier->cpos, buf, count) );
228 if ( ieb->cpos+count > ig->source.buffer.len ) {
229 mm_log((1,"buffer_read: short read: cpos=%d, len=%d, count=%d\n", ieb->cpos, ig->source.buffer.len));
230 count = ig->source.buffer.len - ieb->cpos;
233 memcpy(buf, ig->source.buffer.data+ieb->cpos, count);
235 IOL_DEB( printf("buffer_read: rc = %d, count = %d\n", rc, count) );
241 =item buffer_write(ig, buf, count)
243 Does nothing, returns -1
246 buf - buffer that contains data
247 count - number of bytes to write
254 buffer_write(io_glue *ig, const void *buf, size_t count) {
255 mm_log((1, "buffer_write called, this method should never be called.\n"));
261 =item buffer_close(ig)
263 Closes a source that can be seeked on. Not sure if this should be an actual close
264 or not. Does nothing for now. Should be fixed.
273 buffer_close(io_glue *ig) {
274 mm_log((1, "buffer_close(ig %p)\n", ig));
275 /* FIXME: Do stuff here */
279 /* buffer_seek(ig, offset, whence)
281 Implements seeking for a buffer source.
284 offset - offset into stream
285 whence - whence argument a la lseek
292 buffer_seek(io_glue *ig, off_t offset, int whence) {
293 io_ex_buffer *ieb = ig->exdata;
294 off_t reqpos = offset
295 + (whence == SEEK_CUR)*ieb->cpos
296 + (whence == SEEK_END)*ig->source.buffer.len;
298 if (reqpos > ig->source.buffer.len) {
299 mm_log((1, "seeking out of readable range\n"));
304 IOL_DEB( printf("buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
307 /* FIXME: How about implementing this offset handling stuff? */
315 * Callbacks for sources that are a chain of variable sized buffers
320 /* Helper functions for buffer chains */
327 mm_log((1, "io_blink_new()\n"));
329 ib = mymalloc(sizeof(io_blink));
335 memset(&ib->buf, 0, ib->len);
342 =item io_bchain_advance(ieb)
344 Advances the buffer chain to the next link - extending if
345 necessary. Also adjusts the cpos and tfill counters as needed.
347 ieb - buffer chain object
354 io_bchain_advance(io_ex_bchain *ieb) {
355 if (ieb->cp->next == NULL) {
356 ieb->tail = io_blink_new();
357 ieb->tail->prev = ieb->cp;
358 ieb->cp->next = ieb->tail;
360 ieb->tfill = 0; /* Only set this if we added a new slice */
362 ieb->cp = ieb->cp->next;
369 =item io_bchain_destroy()
371 frees all resources used by a buffer chain.
377 io_destroy_bufchain(io_ex_bchain *ieb) {
379 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
383 io_blink *t = cp->next;
396 bufchain_dump(io_ex_bchain *ieb) {
397 mm_log((1, " buf_chain_dump(ieb %p)\n"));
398 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
399 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
400 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
401 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
402 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
403 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
404 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
405 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
410 * TRUE if lengths are NOT equal
416 chainlencert( io_glue *ig ) {
421 io_ex_bchain *ieb = ig->exdata;
422 io_blink *cp = ieb->head;
425 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
428 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
429 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
430 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
432 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
433 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
435 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
436 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
443 if (!cfl) cpos += clen;
448 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
449 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
455 chaincert( io_glue *ig) {
457 io_ex_bchain *ieb = ig->exdata;
458 io_blink *cp = ieb->head;
460 mm_log((1, "Chain verification.\n"));
462 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
463 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
464 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
465 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
466 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
467 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
468 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
469 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
472 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
473 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
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));
487 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
502 =item bufchain_read(ig, buf, count)
504 Does the reading from a source that can be seeked on
507 buf - buffer to return data in
508 count - number of bytes to read into buffer max
515 bufchain_read(io_glue *ig, void *buf, size_t count) {
516 io_ex_bchain *ieb = ig->exdata;
517 size_t scount = count;
521 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, count));
524 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
525 if (clen == ieb->cpos) {
526 if (ieb->cp == ieb->tail) break; /* EOF */
527 ieb->cp = ieb->cp->next;
529 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
532 sk = clen - ieb->cpos;
533 sk = sk > scount ? scount : sk;
535 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
541 mm_log((1, "bufchain_read: returning %d\n", count-scount));
550 =item bufchain_write(ig, buf, count)
552 Does the writing to a 'source' that can be seeked on
555 buf - buffer that contains data
556 count - number of bytes to write
563 bufchain_write(io_glue *ig, const void *buf, size_t count) {
564 char *cbuf = (char *)buf;
565 io_ex_bchain *ieb = ig->exdata;
566 size_t ocount = count;
569 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %d\n", ig, buf, count));
571 IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %d\n", ig, (long) ieb->cpos, buf, count) );
574 mm_log((2, "bufchain_write: - looping - count = %d\n", count));
575 if (ieb->cp->len == ieb->cpos) {
576 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %d - advancing chain\n", (long) ieb->cpos));
577 io_bchain_advance(ieb);
580 sk = ieb->cp->len - ieb->cpos;
581 sk = sk > count ? count : sk;
582 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
584 if (ieb->cp == ieb->tail) {
585 int extend = ieb->cpos + sk - ieb->tfill;
586 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
588 ieb->length += extend;
589 ieb->tfill += extend;
601 =item bufchain_close(ig)
603 Closes a source that can be seeked on. Not sure if this should be an actual close
604 or not. Does nothing for now. Should be fixed.
613 bufchain_close(io_glue *ig) {
614 mm_log((1, "bufchain_close(ig %p)\n",ig));
615 IOL_DEB( printf("bufchain_close(ig %p)\n", ig) );
616 /* FIXME: Commit a seek point here */
621 /* bufchain_seek(ig, offset, whence)
623 Implements seeking for a source that is seekable, the purpose of having this is to be able to
624 have an offset into a file that is different from what the underlying library thinks.
627 offset - offset into stream
628 whence - whence argument a la lseek
635 bufchain_seek(io_glue *ig, off_t offset, int whence) {
636 io_ex_bchain *ieb = ig->exdata;
641 off_t scount = offset;
644 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence));
647 case SEEK_SET: /* SEEK_SET = 0, From the top */
653 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
654 if (clen == ieb->cpos) {
655 if (ieb->cp == ieb->tail) break; /* EOF */
656 ieb->cp = ieb->cp->next;
658 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
661 sk = clen - ieb->cpos;
662 sk = sk > scount ? scount : sk;
673 * extending file - get ieb into consistent state and then
674 * call write which will get it to the correct position
677 memset(TB, 0, BBSIZ);
678 ieb->gpos = ieb->length;
679 ieb->cpos = ieb->tfill;
682 ssize_t rc, wl = i_min(wrlen, BBSIZ);
683 mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl));
684 rc = bufchain_write( ig, TB, wl );
685 if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n");
693 m_fatal(123, "SEEK_CUR IS NOT IMPLEMENTED\n");
701 while(cof < 0 && ib->prev) {
707 case SEEK_END: /* SEEK_END = 2 */
708 if (cof>0) m_fatal(0, "bufchain_seek: SEEK_END + %d : Extending files via seek not supported!\n", cof);
711 ieb->cpos = ieb->tfill;
717 while(cof<0 && ib->prev) {
722 if (cof<0) m_fatal(0, "bufchain_seek: Tried to seek before start of file\n");
723 ieb->gpos = ieb->length+offset;
728 m_fatal(0, "bufchain_seek: Unhandled seek request: whence = %d\n", whence );
731 mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos));
741 * Methods for setting up data source
745 =item io_obj_setp_buffer(io, p, len)
747 Sets an io_object for reading from a buffer source
749 io - io object that describes a source
750 p - pointer to buffer
751 len - length of buffer
757 io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb, void *closedata) {
758 io->buffer.type = BUFFER;
760 io->buffer.len = len;
761 io->buffer.closecb = closecb;
762 io->buffer.closedata = closedata;
767 =item io_obj_setp_buchain(io)
769 Sets an io_object for reading/writing from a buffer source
771 io - io object that describes a source
772 p - pointer to buffer
773 len - length of buffer
779 io_obj_setp_bufchain(io_obj *io) {
785 =item io_obj_setp_cb2(io, p, readcb, writecb, seekcb, closecb, destroycb)
787 Sets an io_object for reading from a source that uses callbacks
789 io - io object that describes a source
790 p - pointer to data for callbacks
791 readcb - read callback to read from source
792 writecb - write callback to write to source
793 seekcb - seek callback to seek on source
794 closecb - flush any pending data
795 destroycb - release any extra resources
801 io_obj_setp_cb2(io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb, closel closecb, destroyl destroycb) {
802 io->cb.type = CBSEEK;
804 io->cb.readcb = readcb;
805 io->cb.writecb = writecb;
806 io->cb.seekcb = seekcb;
807 io->cb.closecb = closecb;
808 io->cb.destroycb = destroycb;
812 io_obj_setp_cb(io_obj *io, void *p, readl readcb, writel writecb,
814 io_obj_setp_cb2(io, p, readcb, writecb, seekcb, NULL, NULL);
818 =item io_glue_commit_types(ig)
820 Creates buffers and initializes structures to read with the chosen interface.
828 io_glue_commit_types(io_glue *ig) {
829 io_type inn = ig->source.type;
831 mm_log((1, "io_glue_commit_types(ig %p)\n", ig));
832 mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn]));
834 if (ig->flags & 0x01) {
835 mm_log((1, "io_glue_commit_types: type already set up\n"));
842 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
850 ieb->head = io_blink_new();
852 ieb->tail = ieb->head;
855 ig->readcb = bufchain_read;
856 ig->writecb = bufchain_write;
857 ig->seekcb = bufchain_seek;
858 ig->closecb = bufchain_close;
863 io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
869 ig->readcb = realseek_read;
870 ig->writecb = realseek_write;
871 ig->seekcb = realseek_seek;
872 ig->closecb = realseek_close;
877 io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
882 ig->readcb = buffer_read;
883 ig->writecb = buffer_write;
884 ig->seekcb = buffer_seek;
885 ig->closecb = buffer_close;
891 ig->readcb = fd_read;
892 ig->writecb = fd_write;
893 ig->seekcb = fd_seek;
894 ig->closecb = fd_close;
895 ig->sizecb = fd_size;
899 ig->flags |= 0x01; /* indicate source has been setup already */
903 =item io_glue_gettypes(ig, reqmeth)
905 Returns a set of compatible interfaces to read data with.
908 reqmeth - request mask
910 The request mask is a bit mask (of something that hasn't been implemented yet)
911 of interfaces that it would like to read data from the source which the ig
918 io_glue_gettypes(io_glue *ig, int reqmeth) {
923 /* FIXME: Implement this function! */
924 /* if (ig->source.type =
925 if (reqmeth & IO_BUFF) */
931 =item io_new_bufchain()
933 returns a new io_glue object that has the 'empty' source and but can
934 be written to and read from later (like a pseudo file).
942 mm_log((1, "io_new_bufchain()\n"));
943 ig = mymalloc(sizeof(io_glue));
944 memset(ig, 0, sizeof(*ig));
945 io_obj_setp_bufchain(&ig->source);
954 =item io_new_buffer(data, len)
956 Returns a new io_glue object that has the source defined as reading
957 from specified buffer. Note that the buffer is not copied.
959 data - buffer to read from
960 len - length of buffer
966 io_new_buffer(char *data, size_t len, closebufp closecb, void *closedata) {
968 mm_log((1, "io_new_buffer(data %p, len %d, closecb %p, closedata %p)\n", data, len, closecb, closedata));
969 ig = mymalloc(sizeof(io_glue));
970 memset(ig, 0, sizeof(*ig));
971 io_obj_setp_buffer(&ig->source, data, len, closecb, closedata);
980 returns a new io_glue object that has the source defined as reading
981 from specified filedescriptor. Note that the the interface to recieving
982 data from the io_glue callbacks hasn't been done yet.
984 fd - file descriptor to read/write from
992 mm_log((1, "io_new_fd(fd %d)\n", fd));
993 ig = mymalloc(sizeof(io_glue));
994 memset(ig, 0, sizeof(*ig));
995 ig->source.type = FDSEEK;
996 ig->source.fdseek.fd = fd;
1000 io_obj_setp_cb(&ig->source, (void*)fd, _read, _write, _lseek);
1002 io_obj_setp_cb(&ig->source, (void*)fd, read, write, lseek);
1005 mm_log((1, "(%p) <- io_new_fd\n", ig));
1009 io_glue *io_new_cb(void *p, readl readcb, writel writecb, seekl seekcb,
1010 closel closecb, destroyl destroycb) {
1013 mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
1014 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
1015 ig = mymalloc(sizeof(io_glue));
1016 memset(ig, 0, sizeof(*ig));
1017 io_obj_setp_cb2(&ig->source, p, readcb, writecb, seekcb, closecb, destroycb);
1018 mm_log((1, "(%p) <- io_new_cb\n", ig));
1026 Takes the source that the io_glue is bound to and allocates space
1027 for a return buffer and returns the entire content in a single buffer.
1028 Note: This only works for io_glue objects that contain a bufchain. It
1029 is usefull for saving to scalars and such.
1032 c - pointer to a pointer to where data should be copied to
1038 io_slurp(io_glue *ig, unsigned char **c) {
1043 io_type inn = ig->source.type;
1045 if ( inn != BUFCHAIN ) {
1046 m_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
1050 cc = *c = mymalloc( ieb->length );
1054 bufchain_seek(ig, 0, SEEK_SET);
1056 rc = bufchain_read(ig, cc, ieb->length);
1058 if (rc != ieb->length)
1059 m_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
1065 =item fd_read(ig, buf, count)
1069 static ssize_t fd_read(io_glue *ig, void *buf, size_t count) {
1072 result = _read(ig->source.fdseek.fd, buf, count);
1074 result = read(ig->source.fdseek.fd, buf, count);
1077 /* 0 is valid - means EOF */
1079 i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
1085 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count) {
1088 result = _write(ig->source.fdseek.fd, buf, count);
1090 result = write(ig->source.fdseek.fd, buf, count);
1094 i_push_errorf(errno, "write() failure: %s (%d)", my_strerror(errno), errno);
1100 static off_t fd_seek(io_glue *ig, off_t offset, int whence) {
1103 result = _lseek(ig->source.fdseek.fd, offset, whence);
1105 result = lseek(ig->source.fdseek.fd, offset, whence);
1108 if (result == (off_t)-1) {
1109 i_push_errorf(errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
1115 static void fd_close(io_glue *ig) {
1116 /* no, we don't close it */
1119 static ssize_t fd_size(io_glue *ig) {
1120 mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
1126 =item io_glue_DESTROY(ig)
1128 A destructor method for io_glue objects. Should clean up all related buffers.
1129 Might leave us with a dangling pointer issue on some buffers.
1131 ig - io_glue object to destroy.
1137 io_glue_DESTROY(io_glue *ig) {
1138 io_type inn = ig->source.type;
1139 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
1144 io_ex_bchain *ieb = ig->exdata;
1145 io_destroy_bufchain(ieb);
1151 io_ex_rseek *ier = ig->exdata;
1152 if (ig->source.cb.destroycb)
1153 ig->source.cb.destroycb(ig->source.cb.p);
1159 io_ex_buffer *ieb = ig->exdata;
1160 if (ig->source.buffer.closecb) {
1161 mm_log((1,"calling close callback %p for io_buffer\n", ig->source.buffer.closecb));
1162 ig->source.buffer.closecb(ig->source.buffer.closedata);
1176 =head1 INTERNAL FUNCTIONS
1182 Calls strerror() and ensures we don't return NULL.
1184 On some platforms it's possible for strerror() to return NULL, this
1185 wrapper ensures we only get non-NULL values.
1191 const char *my_strerror(int err) {
1192 const char *result = strerror(err);
1195 result = "Unknown error";
1205 Arnar M. Hrafnkelsson <addi@umich.edu>