github.com/afumu/libc@v0.0.6/musl/src/stdio/fopencookie.c (about) 1 #define _GNU_SOURCE 2 #include "stdio_impl.h" 3 #include <stdlib.h> 4 #include <sys/ioctl.h> 5 #include <fcntl.h> 6 #include <errno.h> 7 #include <string.h> 8 9 struct fcookie { 10 void *cookie; 11 cookie_io_functions_t iofuncs; 12 }; 13 14 struct cookie_FILE { 15 FILE f; 16 struct fcookie fc; 17 unsigned char buf[UNGET+BUFSIZ]; 18 }; 19 20 static size_t cookieread(FILE *f, unsigned char *buf, size_t len) 21 { 22 struct fcookie *fc = f->cookie; 23 ssize_t ret = -1; 24 size_t remain = len, readlen = 0; 25 size_t len2 = len - !!f->buf_size; 26 27 if (!fc->iofuncs.read) goto bail; 28 29 if (len2) { 30 ret = fc->iofuncs.read(fc->cookie, (char *) buf, len2); 31 if (ret <= 0) goto bail; 32 33 readlen += ret; 34 remain -= ret; 35 } 36 37 if (!f->buf_size || remain > !!f->buf_size) return readlen; 38 39 f->rpos = f->buf; 40 ret = fc->iofuncs.read(fc->cookie, (char *) f->rpos, f->buf_size); 41 if (ret <= 0) goto bail; 42 f->rend = f->rpos + ret; 43 44 buf[readlen++] = *f->rpos++; 45 46 return readlen; 47 48 bail: 49 f->flags |= ret == 0 ? F_EOF : F_ERR; 50 f->rpos = f->rend = f->buf; 51 return readlen; 52 } 53 54 static size_t cookiewrite(FILE *f, const unsigned char *buf, size_t len) 55 { 56 struct fcookie *fc = f->cookie; 57 ssize_t ret; 58 size_t len2 = f->wpos - f->wbase; 59 if (!fc->iofuncs.write) return len; 60 if (len2) { 61 f->wpos = f->wbase; 62 if (cookiewrite(f, f->wpos, len2) < len2) return 0; 63 } 64 ret = fc->iofuncs.write(fc->cookie, (const char *) buf, len); 65 if (ret < 0) { 66 f->wpos = f->wbase = f->wend = 0; 67 f->flags |= F_ERR; 68 return 0; 69 } 70 return ret; 71 } 72 73 static off_t cookieseek(FILE *f, off_t off, int whence) 74 { 75 struct fcookie *fc = f->cookie; 76 int res; 77 if (whence > 2U) { 78 errno = EINVAL; 79 return -1; 80 } 81 if (!fc->iofuncs.seek) { 82 errno = ENOTSUP; 83 return -1; 84 } 85 res = fc->iofuncs.seek(fc->cookie, &off, whence); 86 if (res < 0) 87 return res; 88 return off; 89 } 90 91 static int cookieclose(FILE *f) 92 { 93 struct fcookie *fc = f->cookie; 94 if (fc->iofuncs.close) return fc->iofuncs.close(fc->cookie); 95 return 0; 96 } 97 98 FILE *fopencookie(void *cookie, const char *mode, cookie_io_functions_t iofuncs) 99 { 100 struct cookie_FILE *f; 101 102 /* Check for valid initial mode character */ 103 if (!strchr("rwa", *mode)) { 104 errno = EINVAL; 105 return 0; 106 } 107 108 /* Allocate FILE+fcookie+buffer or fail */ 109 if (!(f=malloc(sizeof *f))) return 0; 110 111 /* Zero-fill only the struct, not the buffer */ 112 memset(&f->f, 0, sizeof f->f); 113 114 /* Impose mode restrictions */ 115 if (!strchr(mode, '+')) f->f.flags = (*mode == 'r') ? F_NOWR : F_NORD; 116 117 /* Set up our fcookie */ 118 f->fc.cookie = cookie; 119 f->fc.iofuncs = iofuncs; 120 121 f->f.fd = -1; 122 f->f.cookie = &f->fc; 123 f->f.buf = f->buf + UNGET; 124 f->f.buf_size = sizeof f->buf - UNGET; 125 f->f.lbf = EOF; 126 127 /* Initialize op ptrs. No problem if some are unneeded. */ 128 f->f.read = cookieread; 129 f->f.write = cookiewrite; 130 f->f.seek = cookieseek; 131 f->f.close = cookieclose; 132 133 /* Add new FILE to open file list */ 134 return __ofl_add(&f->f); 135 }