15 char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
21 iolayer.c - encapsulates different source of data into a single framework.
25 io_glue *ig = io_new_fd( fileno(stdin) );
26 method = io_reqmeth( IOL_NOSEEK | IOL_MMAP ); // not implemented yet
27 io_glue_commit_types(ig); // always assume IOL_SEEK for now
30 code that uses ig->readcb()
31 to read data goes here.
34 code that uses ig->readcb()
35 to read data goes here.
44 iolayer.c implements the basic functions to create and destroy io_glue
45 objects for Imager. The typical usage pattern for data sources is:
47 1. Create the source (io_new_fd)
48 2. Define how you want to get data from it (io_reqmeth)
49 3. read from it using the interface requested (ig->readdb, ig->mmapcb)
50 4. Close the source, which
51 shouldn't really close the underlying source. (io_glue DESTROY)
53 =head1 FUNCTION REFERENCE
55 Some of these functions are internal.
62 static ssize_t fd_read(io_glue *ig, void *buf, size_t count);
63 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count);
64 static off_t fd_seek(io_glue *ig, off_t offset, int whence);
65 static void fd_close(io_glue *ig);
66 static ssize_t fd_size(io_glue *ig);
67 static const char *my_strerror(int err);
70 * Callbacks for sources that cannot seek
73 /* fakeseek_read: read method for when emulating a seekable source
76 fakeseek_read(io_glue *ig, void *buf, size_t count) {
77 io_ex_fseek *exdata = ig->exdata;
85 * Callbacks for sources that can seek
89 =item realseek_read(ig, buf, count)
91 Does the reading from a source that can be seeked on
94 buf - buffer to return data in
95 count - number of bytes to read into buffer max
102 realseek_read(io_glue *ig, void *buf, size_t count) {
103 io_ex_rseek *ier = ig->exdata;
104 void *p = ig->source.cb.p;
109 IOL_DEB( printf("realseek_read: fd = %d, ier->cpos = %ld, buf = %p, "
110 "count = %d\n", fd, (long) ier->cpos, buf, count) );
111 /* Is this a good idea? Would it be better to handle differently?
113 while( count!=bc && (rc = ig->source.cb.readcb(p,cbuf+bc,count-bc))>0 ) {
118 IOL_DEB( printf("realseek_read: rc = %d, bc = %d\n", rc, bc) );
124 =item realseek_write(ig, buf, count)
126 Does the writing to a 'source' that can be seeked on
129 buf - buffer that contains data
130 count - number of bytes to write
137 realseek_write(io_glue *ig, const void *buf, size_t count) {
138 io_ex_rseek *ier = ig->exdata;
139 void *p = ig->source.cb.p;
142 char *cbuf = (char*)buf;
144 IOL_DEB( printf("realseek_write: ig = %p, ier->cpos = %ld, buf = %p, "
145 "count = %d\n", ig, (long) ier->cpos, buf, count) );
147 /* Is this a good idea? Would it be better to handle differently?
149 while( count!=bc && (rc = ig->source.cb.writecb(p,cbuf+bc,count-bc))>0 ) {
154 IOL_DEB( printf("realseek_write: rc = %d, bc = %d\n", rc, bc) );
160 =item realseek_close(ig)
162 Closes a source that can be seeked on. Not sure if this should be an
163 actual close or not. Does nothing for now. Should be fixed.
171 realseek_close(io_glue *ig) {
172 mm_log((1, "realseek_close(ig %p)\n", ig));
173 if (ig->source.cb.closecb)
174 ig->source.cb.closecb(ig->source.cb.p);
178 /* realseek_seek(ig, offset, whence)
180 Implements seeking for a source that is seekable, the purpose of having this is to be able to
181 have an offset into a file that is different from what the underlying library thinks.
184 offset - offset into stream
185 whence - whence argument a la lseek
192 realseek_seek(io_glue *ig, off_t offset, int whence) {
193 /* io_ex_rseek *ier = ig->exdata; Needed later */
194 void *p = ig->source.cb.p;
196 IOL_DEB( printf("realseek_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
197 rc = ig->source.cb.seekcb(p, offset, whence);
199 IOL_DEB( printf("realseek_seek: rc %ld\n", (long) rc) );
201 /* FIXME: How about implementing this offset handling stuff? */
205 * Callbacks for sources that are a fixed size buffer
209 =item buffer_read(ig, buf, count)
211 Does the reading from a buffer source
214 buf - buffer to return data in
215 count - number of bytes to read into buffer max
222 buffer_read(io_glue *ig, void *buf, size_t count) {
223 io_ex_buffer *ieb = ig->exdata;
225 IOL_DEB( printf("buffer_read: fd = %d, ier->cpos = %ld, buf = %p, count = %d\n", fd, (long) ier->cpos, buf, count) );
227 if ( ieb->cpos+count > ig->source.buffer.len ) {
228 mm_log((1,"buffer_read: short read: cpos=%d, len=%d, count=%d\n", ieb->cpos, ig->source.buffer.len));
229 count = ig->source.buffer.len - ieb->cpos;
232 memcpy(buf, ig->source.buffer.data+ieb->cpos, count);
234 IOL_DEB( printf("buffer_read: rc = %d, count = %d\n", rc, count) );
240 =item buffer_write(ig, buf, count)
242 Does nothing, returns -1
245 buf - buffer that contains data
246 count - number of bytes to write
253 buffer_write(io_glue *ig, const void *buf, size_t count) {
254 mm_log((1, "buffer_write called, this method should never be called.\n"));
260 =item buffer_close(ig)
262 Closes a source that can be seeked on. Not sure if this should be an actual close
263 or not. Does nothing for now. Should be fixed.
272 buffer_close(io_glue *ig) {
273 mm_log((1, "buffer_close(ig %p)\n", ig));
274 /* FIXME: Do stuff here */
278 /* buffer_seek(ig, offset, whence)
280 Implements seeking for a buffer source.
283 offset - offset into stream
284 whence - whence argument a la lseek
291 buffer_seek(io_glue *ig, off_t offset, int whence) {
292 io_ex_buffer *ieb = ig->exdata;
293 off_t reqpos = offset
294 + (whence == SEEK_CUR)*ieb->cpos
295 + (whence == SEEK_END)*ig->source.buffer.len;
297 if (reqpos > ig->source.buffer.len) {
298 mm_log((1, "seeking out of readable range\n"));
303 IOL_DEB( printf("buffer_seek(ig %p, offset %ld, whence %d)\n", ig, (long) offset, whence) );
306 /* FIXME: How about implementing this offset handling stuff? */
314 * Callbacks for sources that are a chain of variable sized buffers
319 /* Helper functions for buffer chains */
326 mm_log((1, "io_blink_new()\n"));
328 ib = mymalloc(sizeof(io_blink));
334 memset(&ib->buf, 0, ib->len);
341 =item io_bchain_advance(ieb)
343 Advances the buffer chain to the next link - extending if
344 necessary. Also adjusts the cpos and tfill counters as needed.
346 ieb - buffer chain object
353 io_bchain_advance(io_ex_bchain *ieb) {
354 if (ieb->cp->next == NULL) {
355 ieb->tail = io_blink_new();
356 ieb->tail->prev = ieb->cp;
357 ieb->cp->next = ieb->tail;
359 ieb->tfill = 0; /* Only set this if we added a new slice */
361 ieb->cp = ieb->cp->next;
368 =item io_bchain_destroy()
370 frees all resources used by a buffer chain.
376 io_destroy_bufchain(io_ex_bchain *ieb) {
378 mm_log((1, "io_destroy_bufchain(ieb %p)\n", ieb));
382 io_blink *t = cp->next;
395 bufchain_dump(io_ex_bchain *ieb) {
396 mm_log((1, " buf_chain_dump(ieb %p)\n"));
397 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
398 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
399 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
400 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
401 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
402 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
403 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
404 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
409 * TRUE if lengths are NOT equal
415 chainlencert( io_glue *ig ) {
420 io_ex_bchain *ieb = ig->exdata;
421 io_blink *cp = ieb->head;
424 if (ieb->gpos > ieb->length) mm_log((1, "BBAR : ieb->gpos = %d, ieb->length = %d\n", ieb->gpos, ieb->length));
427 clen = (cp == ieb->tail) ? ieb->tfill : cp->len;
428 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
429 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
431 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
432 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
434 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
435 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
442 if (!cfl) cpos += clen;
447 if (( csize != ieb->length )) mm_log((1, "BAR : csize = %d, ieb->length = %d\n", csize, ieb->length));
448 if (( cpos != ieb->gpos )) mm_log((1, "BAR : cpos = %d, ieb->gpos = %d\n", cpos, ieb->gpos ));
454 chaincert( io_glue *ig) {
456 io_ex_bchain *ieb = ig->exdata;
457 io_blink *cp = ieb->head;
459 mm_log((1, "Chain verification.\n"));
461 mm_log((1, " buf_chain_dump: ieb->offset = %d\n", ieb->offset));
462 mm_log((1, " buf_chain_dump: ieb->length = %d\n", ieb->length));
463 mm_log((1, " buf_chain_dump: ieb->head = %p\n", ieb->head ));
464 mm_log((1, " buf_chain_dump: ieb->tail = %p\n", ieb->tail ));
465 mm_log((1, " buf_chain_dump: ieb->tfill = %d\n", ieb->tfill ));
466 mm_log((1, " buf_chain_dump: ieb->cp = %p\n", ieb->cp ));
467 mm_log((1, " buf_chain_dump: ieb->cpos = %d\n", ieb->cpos ));
468 mm_log((1, " buf_chain_dump: ieb->gpos = %d\n", ieb->gpos ));
471 int clen = cp == ieb->tail ? ieb->tfill : cp->len;
472 mm_log((1, "link: %p <- %p -> %p\n", cp->prev, cp, cp->next));
473 if (ieb->head == cp && cp->prev) mm_log((1, "Head of chain has a non null prev\n"));
474 if (ieb->tail == cp && cp->next) mm_log((1, "Tail of chain has a non null next\n"));
476 if (ieb->head != cp && !cp->prev) mm_log((1, "Middle of chain has a null prev\n"));
477 if (ieb->tail != cp && !cp->next) mm_log((1, "Middle of chain has a null next\n"));
479 if (cp->prev && cp->prev->next != cp) mm_log((1, "%p = cp->prev->next != cp\n", cp->prev->next));
480 if (cp->next && cp->next->prev != cp) mm_log((1, "%p cp->next->prev != cp\n", cp->next->prev));
486 mm_log((1, "csize = %d %s ieb->length = %d\n", csize, csize == ieb->length ? "==" : "!=", ieb->length));
501 =item bufchain_read(ig, buf, count)
503 Does the reading from a source that can be seeked on
506 buf - buffer to return data in
507 count - number of bytes to read into buffer max
514 bufchain_read(io_glue *ig, void *buf, size_t count) {
515 io_ex_bchain *ieb = ig->exdata;
516 size_t scount = count;
520 mm_log((1, "bufchain_read(ig %p, buf %p, count %ld)\n", ig, buf, count));
523 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
524 if (clen == ieb->cpos) {
525 if (ieb->cp == ieb->tail) break; /* EOF */
526 ieb->cp = ieb->cp->next;
528 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
531 sk = clen - ieb->cpos;
532 sk = sk > scount ? scount : sk;
534 memcpy(&cbuf[count-scount], &ieb->cp->buf[ieb->cpos], sk);
540 mm_log((1, "bufchain_read: returning %d\n", count-scount));
549 =item bufchain_write(ig, buf, count)
551 Does the writing to a 'source' that can be seeked on
554 buf - buffer that contains data
555 count - number of bytes to write
562 bufchain_write(io_glue *ig, const void *buf, size_t count) {
563 char *cbuf = (char *)buf;
564 io_ex_bchain *ieb = ig->exdata;
565 size_t ocount = count;
568 mm_log((1, "bufchain_write: ig = %p, buf = %p, count = %d\n", ig, buf, count));
570 IOL_DEB( printf("bufchain_write: ig = %p, ieb->cpos = %ld, buf = %p, count = %d\n", ig, (long) ieb->cpos, buf, count) );
573 mm_log((2, "bufchain_write: - looping - count = %d\n", count));
574 if (ieb->cp->len == ieb->cpos) {
575 mm_log((1, "bufchain_write: cp->len == ieb->cpos = %d - advancing chain\n", (long) ieb->cpos));
576 io_bchain_advance(ieb);
579 sk = ieb->cp->len - ieb->cpos;
580 sk = sk > count ? count : sk;
581 memcpy(&ieb->cp->buf[ieb->cpos], &cbuf[ocount-count], sk);
583 if (ieb->cp == ieb->tail) {
584 int extend = ieb->cpos + sk - ieb->tfill;
585 mm_log((2, "bufchain_write: extending tail by %d\n", extend));
587 ieb->length += extend;
588 ieb->tfill += extend;
600 =item bufchain_close(ig)
602 Closes a source that can be seeked on. Not sure if this should be an actual close
603 or not. Does nothing for now. Should be fixed.
612 bufchain_close(io_glue *ig) {
613 mm_log((1, "bufchain_close(ig %p)\n",ig));
614 IOL_DEB( printf("bufchain_close(ig %p)\n", ig) );
615 /* FIXME: Commit a seek point here */
620 /* bufchain_seek(ig, offset, whence)
622 Implements seeking for a source that is seekable, the purpose of having this is to be able to
623 have an offset into a file that is different from what the underlying library thinks.
626 offset - offset into stream
627 whence - whence argument a la lseek
634 bufchain_seek(io_glue *ig, off_t offset, int whence) {
635 io_ex_bchain *ieb = ig->exdata;
640 off_t scount = offset;
643 mm_log((1, "bufchain_seek(ig %p, offset %ld, whence %d)\n", ig, offset, whence));
646 case SEEK_SET: /* SEEK_SET = 0, From the top */
652 int clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
653 if (clen == ieb->cpos) {
654 if (ieb->cp == ieb->tail) break; /* EOF */
655 ieb->cp = ieb->cp->next;
657 clen = (ieb->cp == ieb->tail) ? ieb->tfill : ieb->cp->len;
660 sk = clen - ieb->cpos;
661 sk = sk > scount ? scount : sk;
672 * extending file - get ieb into consistent state and then
673 * call write which will get it to the correct position
676 memset(TB, 0, BBSIZ);
677 ieb->gpos = ieb->length;
678 ieb->cpos = ieb->tfill;
681 ssize_t rc, wl = i_min(wrlen, BBSIZ);
682 mm_log((1, "bufchain_seek: wrlen = %d, wl = %d\n", wrlen, wl));
683 rc = bufchain_write( ig, TB, wl );
684 if (rc != wl) m_fatal(0, "bufchain_seek: Unable to extend file\n");
692 m_fatal(123, "SEEK_CUR IS NOT IMPLEMENTED\n");
700 while(cof < 0 && ib->prev) {
706 case SEEK_END: /* SEEK_END = 2 */
707 if (cof>0) m_fatal(0, "bufchain_seek: SEEK_END + %d : Extending files via seek not supported!\n", cof);
710 ieb->cpos = ieb->tfill;
716 while(cof<0 && ib->prev) {
721 if (cof<0) m_fatal(0, "bufchain_seek: Tried to seek before start of file\n");
722 ieb->gpos = ieb->length+offset;
727 m_fatal(0, "bufchain_seek: Unhandled seek request: whence = %d\n", whence );
730 mm_log((2, "bufchain_seek: returning ieb->gpos = %d\n", ieb->gpos));
740 * Methods for setting up data source
744 =item io_obj_setp_buffer(io, p, len)
746 Sets an io_object for reading from a buffer source
748 io - io object that describes a source
749 p - pointer to buffer
750 len - length of buffer
756 io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb, void *closedata) {
757 io->buffer.type = BUFFER;
759 io->buffer.len = len;
760 io->buffer.closecb = closecb;
761 io->buffer.closedata = closedata;
766 =item io_obj_setp_buchain(io)
768 Sets an io_object for reading/writing from a buffer source
770 io - io object that describes a source
771 p - pointer to buffer
772 len - length of buffer
778 io_obj_setp_bufchain(io_obj *io) {
784 =item io_obj_setp_cb2(io, p, readcb, writecb, seekcb, closecb, destroycb)
786 Sets an io_object for reading from a source that uses callbacks
788 io - io object that describes a source
789 p - pointer to data for callbacks
790 readcb - read callback to read from source
791 writecb - write callback to write to source
792 seekcb - seek callback to seek on source
793 closecb - flush any pending data
794 destroycb - release any extra resources
800 io_obj_setp_cb2(io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb, closel closecb, destroyl destroycb) {
801 io->cb.type = CBSEEK;
803 io->cb.readcb = readcb;
804 io->cb.writecb = writecb;
805 io->cb.seekcb = seekcb;
806 io->cb.closecb = closecb;
807 io->cb.destroycb = destroycb;
811 io_obj_setp_cb(io_obj *io, void *p, readl readcb, writel writecb,
813 io_obj_setp_cb2(io, p, readcb, writecb, seekcb, NULL, NULL);
817 =item io_glue_commit_types(ig)
819 Creates buffers and initializes structures to read with the chosen interface.
827 io_glue_commit_types(io_glue *ig) {
828 io_type inn = ig->source.type;
830 mm_log((1, "io_glue_commit_types(ig %p)\n", ig));
831 mm_log((1, "io_glue_commit_types: source type %d (%s)\n", inn, io_type_names[inn]));
833 if (ig->flags & 0x01) {
834 mm_log((1, "io_glue_commit_types: type already set up\n"));
841 io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
849 ieb->head = io_blink_new();
851 ieb->tail = ieb->head;
854 ig->readcb = bufchain_read;
855 ig->writecb = bufchain_write;
856 ig->seekcb = bufchain_seek;
857 ig->closecb = bufchain_close;
862 io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
868 ig->readcb = realseek_read;
869 ig->writecb = realseek_write;
870 ig->seekcb = realseek_seek;
871 ig->closecb = realseek_close;
876 io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
881 ig->readcb = buffer_read;
882 ig->writecb = buffer_write;
883 ig->seekcb = buffer_seek;
884 ig->closecb = buffer_close;
890 ig->readcb = fd_read;
891 ig->writecb = fd_write;
892 ig->seekcb = fd_seek;
893 ig->closecb = fd_close;
897 ig->flags |= 0x01; /* indicate source has been setup already */
901 =item io_glue_gettypes(ig, reqmeth)
903 Returns a set of compatible interfaces to read data with.
906 reqmeth - request mask
908 The request mask is a bit mask (of something that hasn't been implemented yet)
909 of interfaces that it would like to read data from the source which the ig
916 io_glue_gettypes(io_glue *ig, int reqmeth) {
921 /* FIXME: Implement this function! */
922 /* if (ig->source.type =
923 if (reqmeth & IO_BUFF) */
929 =item io_new_bufchain()
931 returns a new io_glue object that has the 'empty' source and but can
932 be written to and read from later (like a pseudo file).
940 mm_log((1, "io_new_bufchain()\n"));
941 ig = mymalloc(sizeof(io_glue));
942 memset(ig, 0, sizeof(*ig));
943 io_obj_setp_bufchain(&ig->source);
952 =item io_new_buffer(data, len)
954 Returns a new io_glue object that has the source defined as reading
955 from specified buffer. Note that the buffer is not copied.
957 data - buffer to read from
958 len - length of buffer
964 io_new_buffer(char *data, size_t len, closebufp closecb, void *closedata) {
966 mm_log((1, "io_new_buffer(data %p, len %d, closecb %p, closedata %p)\n", data, len, closecb, closedata));
967 ig = mymalloc(sizeof(io_glue));
968 memset(ig, 0, sizeof(*ig));
969 io_obj_setp_buffer(&ig->source, data, len, closecb, closedata);
978 returns a new io_glue object that has the source defined as reading
979 from specified filedescriptor. Note that the the interface to recieving
980 data from the io_glue callbacks hasn't been done yet.
982 fd - file descriptor to read/write from
990 mm_log((1, "io_new_fd(fd %d)\n", fd));
991 ig = mymalloc(sizeof(io_glue));
992 memset(ig, 0, sizeof(*ig));
993 ig->source.type = FDSEEK;
994 ig->source.fdseek.fd = fd;
998 io_obj_setp_cb(&ig->source, (void*)fd, _read, _write, _lseek);
1000 io_obj_setp_cb(&ig->source, (void*)fd, read, write, lseek);
1003 mm_log((1, "(%p) <- io_new_fd\n", ig));
1007 io_glue *io_new_cb(void *p, readl readcb, writel writecb, seekl seekcb,
1008 closel closecb, destroyl destroycb) {
1011 mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
1012 "destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
1013 ig = mymalloc(sizeof(io_glue));
1014 memset(ig, 0, sizeof(*ig));
1015 io_obj_setp_cb2(&ig->source, p, readcb, writecb, seekcb, closecb, destroycb);
1016 mm_log((1, "(%p) <- io_new_cb\n", ig));
1024 Takes the source that the io_glue is bound to and allocates space
1025 for a return buffer and returns the entire content in a single buffer.
1026 Note: This only works for io_glue objects that contain a bufchain. It
1027 is usefull for saving to scalars and such.
1030 c - pointer to a pointer to where data should be copied to
1036 io_slurp(io_glue *ig, unsigned char **c) {
1041 io_type inn = ig->source.type;
1043 if ( inn != BUFCHAIN ) {
1044 m_fatal(0, "io_slurp: called on a source that is not from a bufchain\n");
1048 cc = *c = mymalloc( ieb->length );
1052 bufchain_seek(ig, 0, SEEK_SET);
1054 rc = bufchain_read(ig, cc, ieb->length);
1056 if (rc != ieb->length)
1057 m_fatal(1, "io_slurp: bufchain_read returned an incomplete read: rc = %d, request was %d\n", rc, ieb->length);
1063 =item fd_read(ig, buf, count)
1067 static ssize_t fd_read(io_glue *ig, void *buf, size_t count) {
1070 result = _read(ig->source.fdseek.fd, buf, count);
1072 result = read(ig->source.fdseek.fd, buf, count);
1075 /* 0 is valid - means EOF */
1077 i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
1083 static ssize_t fd_write(io_glue *ig, const void *buf, size_t count) {
1086 result = _write(ig->source.fdseek.fd, buf, count);
1088 result = write(ig->source.fdseek.fd, buf, count);
1092 i_push_errorf(errno, "write() failure: %s (%d)", my_strerror(errno), errno);
1098 static off_t fd_seek(io_glue *ig, off_t offset, int whence) {
1101 result = _lseek(ig->source.fdseek.fd, offset, whence);
1103 result = lseek(ig->source.fdseek.fd, offset, whence);
1106 if (result == (off_t)-1) {
1107 i_push_errorf(errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
1113 static void fd_close(io_glue *ig) {
1114 /* no, we don't close it */
1117 static ssize_t fd_size(io_glue *ig) {
1118 mm_log((1, "fd_size(ig %p) unimplemented\n", ig));
1124 =item io_glue_DESTROY(ig)
1126 A destructor method for io_glue objects. Should clean up all related buffers.
1127 Might leave us with a dangling pointer issue on some buffers.
1129 ig - io_glue object to destroy.
1135 io_glue_DESTROY(io_glue *ig) {
1136 io_type inn = ig->source.type;
1137 mm_log((1, "io_glue_DESTROY(ig %p)\n", ig));
1142 io_ex_bchain *ieb = ig->exdata;
1143 io_destroy_bufchain(ieb);
1149 io_ex_rseek *ier = ig->exdata;
1150 if (ig->source.cb.destroycb)
1151 ig->source.cb.destroycb(ig->source.cb.p);
1157 io_ex_buffer *ieb = ig->exdata;
1158 if (ig->source.buffer.closecb) {
1159 mm_log((1,"calling close callback %p for io_buffer\n", ig->source.buffer.closecb));
1160 ig->source.buffer.closecb(ig->source.buffer.closedata);
1174 =head1 INTERNAL FUNCTIONS
1180 Calls strerror() and ensures we don't return NULL.
1182 On some platforms it's possible for strerror() to return NULL, this
1183 wrapper ensures we only get non-NULL values.
1189 const char *my_strerror(int err) {
1190 const char *result = strerror(err);
1193 result = "Unknown error";
1203 Arnar M. Hrafnkelsson <addi@umich.edu>