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