2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2001
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 stdio is very convenient, but on some systems the file descriptor
23 in FILE* is 8 bits, so it fails when more than 255 files are open.
25 XFILE replaces stdio. It is less efficient, but at least it works
26 when you have lots of files open
28 The main restriction on XFILE is that it doesn't support seeking,
29 and doesn't support O_RDWR. That keeps the code simple.
34 #define XBUFSIZE BUFSIZ
36 static XFILE _x_stdin = { 0, NULL, NULL, XBUFSIZE, 0, O_RDONLY, X_IOFBF, 0 };
37 static XFILE _x_stdout = { 1, NULL, NULL, XBUFSIZE, 0, O_WRONLY, X_IOLBF, 0 };
38 static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
40 XFILE *x_stdin = &_x_stdin;
41 XFILE *x_stdout = &_x_stdout;
42 XFILE *x_stderr = &_x_stderr;
45 #define X_FLAG_ERROR 2
47 /* simulate setvbuf() */
48 int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
51 if (f->bufused) return -1;
53 /* on files being read full buffering is the only option */
54 if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
58 /* destroy any earlier buffer */
66 if (f->buftype == X_IONBF) return 0;
68 /* if buffering then we need some size */
69 if (size == 0) size = XBUFSIZE;
77 /* allocate the buffer */
78 static int x_allocate_buffer(XFILE *f)
81 if (f->bufsize == 0) return 0;
82 f->buf = malloc(f->bufsize);
83 if (!f->buf) return 0;
89 /* this looks more like open() than fopen(), but that is quite deliberate.
90 I want programmers to *think* about O_EXCL, O_CREAT etc not just
91 get them magically added
93 XFILE *x_fopen(const char *fname, int flags, mode_t mode)
97 ret = (XFILE *)malloc(sizeof(XFILE));
98 if (!ret) return NULL;
100 memset(ret, 0, sizeof(XFILE));
102 if ((flags & O_ACCMODE) == O_RDWR) {
103 /* we don't support RDWR in XFILE - use file
104 descriptors instead */
109 ret->open_flags = flags;
111 ret->fd = sys_open(fname, flags, mode);
117 x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
122 /* simulate fclose() */
123 int x_fclose(XFILE *f)
127 /* make sure we flush any buffered data */
133 /* make sure data can't leak into a later malloc */
134 memset(f->buf, 0, f->bufsize);
141 /* simulate fwrite() */
142 int x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
146 /* we might be writing unbuffered */
147 if (f->buftype == X_IONBF ||
148 (!f->buf && !x_allocate_buffer(f))) {
149 ret = write(f->fd, p, size*nmemb);
150 if (ret == -1) return -1;
155 while (total < size*nmemb) {
156 int n = f->bufsize - f->bufused;
157 n = MIN(n, (size*nmemb)-total);
160 /* it's full, flush it */
165 memcpy(f->buf + f->bufused, total+(const char *)p, n);
170 /* when line buffered we need to flush at the last linefeed. This can
171 flush a bit more than necessary, but that is harmless */
172 if (f->buftype == X_IOLBF && f->bufused) {
174 for (i=(size*nmemb)-1; i>=0; i--) {
175 if (*(i+(const char *)p) == '\n') {
185 /* thank goodness for asprintf() */
186 int x_vfprintf(XFILE *f, const char *format, va_list ap)
194 len = vasprintf(&p, format, ap2);
195 if (len <= 0) return len;
196 ret = x_fwrite(p, 1, len, f);
201 int x_fprintf(XFILE *f, const char *format, ...)
206 va_start(ap, format);
207 ret = x_vfprintf(f, format, ap);
212 /* at least fileno() is simple! */
213 int x_fileno(XFILE *f)
218 /* simulate fflush() */
219 int x_fflush(XFILE *f)
223 if (f->flags & X_FLAG_ERROR) return -1;
225 if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
230 if (f->bufused == 0) return 0;
232 ret = write(f->fd, f->buf, f->bufused);
233 if (ret == -1) return -1;
236 if (f->bufused > 0) {
237 f->flags |= X_FLAG_ERROR;
238 memmove(f->buf, ret + (char *)f->buf, f->bufused);
245 /* simulate setbuffer() */
246 void x_setbuffer(XFILE *f, char *buf, size_t size)
248 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
251 /* simulate setbuf() */
252 void x_setbuf(XFILE *f, char *buf)
254 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
257 /* simulate setlinebuf() */
258 void x_setlinebuf(XFILE *f)
260 x_setvbuf(f, NULL, X_IOLBF, 0);
264 /* simulate feof() */
267 if (f->flags & X_FLAG_EOF) return 1;
271 /* simulate ferror() */
272 int x_ferror(XFILE *f)
274 if (f->flags & X_FLAG_ERROR) return 1;
278 /* fill the read buffer */
279 static void x_fillbuf(XFILE *f)
283 if (f->bufused) return;
285 if (!f->buf && !x_allocate_buffer(f)) return;
287 n = read(f->fd, f->buf, f->bufsize);
293 /* simulate fgetc() */
294 int x_fgetc(XFILE *f)
298 if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
300 if (f->bufused == 0) x_fillbuf(f);
302 if (f->bufused == 0) {
303 f->flags |= X_FLAG_EOF;
307 ret = *(unsigned char *)(f->next);
314 size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
317 while (total < size*nmemb) {
320 (total+(char *)p)[0] = (char)c;
326 /* simulate fgets() */
327 char *x_fgets(char *s, int size, XFILE *stream)
332 int c = x_fgetc(stream);
336 if (c == '\n') break;
338 if (l==size || x_ferror(stream)) {