2 Unix SMB/Netbios implementation.
5 Copyright (C) Andrew Tridgell 2001
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 stdio is very convenient, but on some systems the file descriptor
24 in FILE* is 8 bits, so it fails when more than 255 files are open.
26 XFILE replaces stdio. It is less efficient, but at least it works
27 when you have lots of files open
29 The main restriction on XFILE is that it doesn't support seeking,
30 and doesn't support O_RDWR. That keeps the code simple.
35 static XFILE _x_stdin = { 0, NULL, NULL, 0, 0, O_RDONLY, X_IOFBF, 0 };
36 static XFILE _x_stdout = { 1, NULL, NULL, 0, 0, O_WRONLY, X_IOLBF, 0 };
37 static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
39 XFILE *x_stdin = &_x_stdin;
40 XFILE *x_stdout = &_x_stdout;
41 XFILE *x_stderr = &_x_stderr;
43 #define XBUFSIZE BUFSIZ
46 #define X_FLAG_ERROR 2
48 /* simulate setvbuf() */
49 int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
52 if (f->bufused) return -1;
54 /* on files being read full buffering is the only option */
55 if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
59 /* destroy any earlier buffer */
67 if (f->buftype == X_IONBF) return 0;
69 /* if buffering then we need some size */
70 if (size == 0) size = XBUFSIZE;
78 /* allocate the buffer */
79 static int x_allocate_buffer(XFILE *f)
82 if (f->bufsize == 0) return 0;
83 f->buf = malloc(f->bufsize);
84 if (!f->buf) return 0;
90 /* this looks more like open() than fopen(), but that is quite deliberate.
91 I want programmers to *think* about O_EXCL, O_CREAT etc not just
92 get them magically added
94 XFILE *x_fopen(const char *fname, int flags, mode_t mode)
98 ret = (XFILE *)malloc(sizeof(XFILE));
99 if (!ret) return NULL;
101 memset(ret, 0, sizeof(XFILE));
103 if ((flags & O_ACCMODE) == O_RDWR) {
104 /* we don't support RDWR in XFILE - use file
105 descriptors instead */
110 ret->open_flags = flags;
112 ret->fd = sys_open(fname, flags, mode);
118 x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
123 /* simulate fclose() */
124 int x_fclose(XFILE *f)
128 /* make sure we flush any buffered data */
134 /* make sure data can't leak into a later malloc */
135 memset(f->buf, 0, f->bufsize);
142 /* simulate fwrite() */
143 int x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
147 /* we might be writing unbuffered */
148 if (f->buftype == X_IONBF ||
149 (!f->buf && !x_allocate_buffer(f))) {
150 ret = write(f->fd, p, size*nmemb);
151 if (ret == -1) return -1;
156 while (total < size*nmemb) {
157 int n = f->bufsize - f->bufused;
158 n = MIN(n, (size*nmemb)-total);
161 /* it's full, flush it */
166 memcpy(f->buf + f->bufused, total+(const char *)p, n);
171 /* when line buffered we need to flush at the last linefeed. This can
172 flush a bit more than necessary, but that is harmless */
173 if (f->buftype == X_IOLBF && f->bufused) {
175 for (i=size-1; i>=0; i--) {
176 if (*(i+(const char *)p) == '\n') {
186 /* thank goodness for asprintf() */
187 int x_vfprintf(XFILE *f, const char *format, va_list ap)
191 len = vasprintf(&p, format, ap);
192 if (len <= 0) return len;
193 ret = x_fwrite(p, 1, len, f);
198 int x_fprintf(XFILE *f, const char *format, ...)
203 va_start(ap, format);
204 ret = x_vfprintf(f, format, ap);
209 /* at least fileno() is simple! */
210 int x_fileno(XFILE *f)
215 /* simulate fflush() */
216 int x_fflush(XFILE *f)
220 if (f->flags & X_FLAG_ERROR) return -1;
222 if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
227 if (f->bufused == 0) return 0;
229 ret = write(f->fd, f->buf, f->bufused);
230 if (ret == -1) return -1;
233 if (f->bufused > 0) {
234 f->flags |= X_FLAG_ERROR;
235 memmove(f->buf, ret + (char *)f->buf, f->bufused);
242 /* simulate setbuffer() */
243 void x_setbuffer(XFILE *f, char *buf, size_t size)
245 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
248 /* simulate setbuf() */
249 void x_setbuf(XFILE *f, char *buf)
251 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
254 /* simulate setlinebuf() */
255 void x_setlinebuf(XFILE *f)
257 x_setvbuf(f, NULL, X_IOLBF, 0);
261 /* simulate feof() */
264 if (f->flags & X_FLAG_EOF) return 1;
268 /* simulate ferror() */
269 int x_ferror(XFILE *f)
271 if (f->flags & X_FLAG_ERROR) return 1;
275 /* fill the read buffer */
276 static void x_fillbuf(XFILE *f)
280 if (f->bufused) return;
282 if (!f->buf && !x_allocate_buffer(f)) return;
284 n = read(f->fd, f->buf, f->bufsize);
290 /* simulate fgetc() */
291 int x_fgetc(XFILE *f)
295 if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
297 if (f->bufused == 0) x_fillbuf(f);
299 if (f->bufused == 0) {
300 f->flags |= X_FLAG_EOF;
304 ret = *(unsigned char *)(f->next);
311 size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
314 while (total < size*nmemb) {
317 (total+(char *)p)[0] = (char)c;
323 /* simulate fgets() */
324 char *x_fgets(char *s, int size, XFILE *stream)
329 int c = x_fgetc(stream);
333 if (c == '\n') break;
335 if (l==size || x_ferror(stream)) {