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
46 #define X_FLAG_EINVAL 3
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 size_t x_fwrite(const void *p
, size_t size
, size_t nmemb
, XFILE
*f
)
148 /* we might be writing unbuffered */
149 if (f
->buftype
== X_IONBF
||
150 (!f
->buf
&& !x_allocate_buffer(f
))) {
151 ret
= write(f
->fd
, p
, size
*nmemb
);
152 if (ret
== -1) return -1;
157 while (total
< size
*nmemb
) {
158 size_t n
= f
->bufsize
- f
->bufused
;
159 n
= MIN(n
, (size
*nmemb
)-total
);
162 /* it's full, flush it */
167 memcpy(f
->buf
+ f
->bufused
, total
+(const char *)p
, n
);
172 /* when line buffered we need to flush at the last linefeed. This can
173 flush a bit more than necessary, but that is harmless */
174 if (f
->buftype
== X_IOLBF
&& f
->bufused
) {
176 for (i
=(size
*nmemb
)-1; i
>=0; i
--) {
177 if (*(i
+(const char *)p
) == '\n') {
187 /* thank goodness for asprintf() */
188 int x_vfprintf(XFILE
*f
, const char *format
, va_list ap
)
196 len
= vasprintf(&p
, format
, ap2
);
197 if (len
<= 0) return len
;
198 ret
= x_fwrite(p
, 1, len
, f
);
203 int x_fprintf(XFILE
*f
, const char *format
, ...)
208 va_start(ap
, format
);
209 ret
= x_vfprintf(f
, format
, ap
);
214 /* at least fileno() is simple! */
215 int x_fileno(XFILE
*f
)
220 /* simulate fflush() */
221 int x_fflush(XFILE
*f
)
225 if (f
->flags
& X_FLAG_ERROR
) return -1;
227 if ((f
->open_flags
& O_ACCMODE
) != O_WRONLY
) {
232 if (f
->bufused
== 0) return 0;
234 ret
= write(f
->fd
, f
->buf
, f
->bufused
);
235 if (ret
== -1) return -1;
238 if (f
->bufused
> 0) {
239 f
->flags
|= X_FLAG_ERROR
;
240 memmove(f
->buf
, ret
+ (char *)f
->buf
, f
->bufused
);
247 /* simulate setbuffer() */
248 void x_setbuffer(XFILE
*f
, char *buf
, size_t size
)
250 x_setvbuf(f
, buf
, buf
?X_IOFBF
:X_IONBF
, size
);
253 /* simulate setbuf() */
254 void x_setbuf(XFILE
*f
, char *buf
)
256 x_setvbuf(f
, buf
, buf
?X_IOFBF
:X_IONBF
, XBUFSIZE
);
259 /* simulate setlinebuf() */
260 void x_setlinebuf(XFILE
*f
)
262 x_setvbuf(f
, NULL
, X_IOLBF
, 0);
266 /* simulate feof() */
269 if (f
->flags
& X_FLAG_EOF
) return 1;
273 /* simulate ferror() */
274 int x_ferror(XFILE
*f
)
276 if (f
->flags
& X_FLAG_ERROR
) return 1;
280 /* fill the read buffer */
281 static void x_fillbuf(XFILE
*f
)
285 if (f
->bufused
) return;
287 if (!f
->buf
&& !x_allocate_buffer(f
)) return;
289 n
= read(f
->fd
, f
->buf
, f
->bufsize
);
295 /* simulate fgetc() */
296 int x_fgetc(XFILE
*f
)
300 if (f
->flags
& (X_FLAG_EOF
| X_FLAG_ERROR
)) return EOF
;
302 if (f
->bufused
== 0) x_fillbuf(f
);
304 if (f
->bufused
== 0) {
305 f
->flags
|= X_FLAG_EOF
;
309 ret
= *(unsigned char *)(f
->next
);
316 size_t x_fread(void *p
, size_t size
, size_t nmemb
, XFILE
*f
)
319 while (total
< size
*nmemb
) {
322 (total
+(char *)p
)[0] = (char)c
;
328 /* simulate fgets() */
329 char *x_fgets(char *s
, int size
, XFILE
*stream
)
334 int c
= x_fgetc(stream
);
338 if (c
== '\n') break;
340 if (l
==size
|| x_ferror(stream
)) {
347 /* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
348 * set then an error is returned */
349 off_t
x_tseek(XFILE
*f
, off_t offset
, int whence
)
351 if (f
->flags
& X_FLAG_ERROR
)
354 /* only SEEK_SET and SEEK_END are supported */
355 /* SEEK_CUR needs internal offset counter */
356 if (whence
!= SEEK_SET
&& whence
!= SEEK_END
) {
357 f
->flags
|= X_FLAG_EINVAL
;
362 /* empty the buffer */
363 switch (f
->open_flags
& O_ACCMODE
) {
368 if (x_fflush(f
) != 0)
376 f
->flags
&= ~X_FLAG_EOF
;
377 return (off_t
)sys_lseek(f
->fd
, offset
, whence
);