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