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 static XFILE _x_stdin = { 0, NULL, NULL, 0, 0, O_RDONLY, X_IOFBF, 0 };
35 static XFILE _x_stdout = { 1, NULL, NULL, 0, 0, O_WRONLY, X_IOLBF, 0 };
36 static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
38 XFILE *x_stdin = &_x_stdin;
39 XFILE *x_stdout = &_x_stdout;
40 XFILE *x_stderr = &_x_stderr;
42 #define XBUFSIZE BUFSIZ
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-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)
190 len = vasprintf(&p, format, ap);
191 if (len <= 0) return len;
192 ret = x_fwrite(p, 1, len, f);
197 int x_fprintf(XFILE *f, const char *format, ...)
202 va_start(ap, format);
203 ret = x_vfprintf(f, format, ap);
208 /* at least fileno() is simple! */
209 int x_fileno(XFILE *f)
214 /* simulate fflush() */
215 int x_fflush(XFILE *f)
219 if (f->flags & X_FLAG_ERROR) return -1;
221 if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
226 if (f->bufused == 0) return 0;
228 ret = write(f->fd, f->buf, f->bufused);
229 if (ret == -1) return -1;
232 if (f->bufused > 0) {
233 f->flags |= X_FLAG_ERROR;
234 memmove(f->buf, ret + (char *)f->buf, f->bufused);
241 /* simulate setbuffer() */
242 void x_setbuffer(XFILE *f, char *buf, size_t size)
244 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
247 /* simulate setbuf() */
248 void x_setbuf(XFILE *f, char *buf)
250 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
253 /* simulate setlinebuf() */
254 void x_setlinebuf(XFILE *f)
256 x_setvbuf(f, NULL, X_IOLBF, 0);
260 /* simulate feof() */
263 if (f->flags & X_FLAG_EOF) return 1;
267 /* simulate ferror() */
268 int x_ferror(XFILE *f)
270 if (f->flags & X_FLAG_ERROR) return 1;
274 /* fill the read buffer */
275 static void x_fillbuf(XFILE *f)
279 if (f->bufused) return;
281 if (!f->buf && !x_allocate_buffer(f)) return;
283 n = read(f->fd, f->buf, f->bufsize);
289 /* simulate fgetc() */
290 int x_fgetc(XFILE *f)
294 if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
296 if (f->bufused == 0) x_fillbuf(f);
298 if (f->bufused == 0) {
299 f->flags |= X_FLAG_EOF;
303 ret = *(unsigned char *)(f->next);
310 size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
313 while (total < size*nmemb) {
316 (total+(char *)p)[0] = (char)c;
322 /* simulate fgets() */
323 char *x_fgets(char *s, int size, XFILE *stream)
328 int c = x_fgetc(stream);
332 if (c == '\n') break;
334 if (l==size || x_ferror(stream)) {