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
)
51 if (x_fflush(f
) != 0) return -1;
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
= (char *)SMB_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
= SMB_MALLOC_P(XFILE
);
103 memset(ret
, 0, sizeof(XFILE
));
105 if ((flags
& O_ACCMODE
) == O_RDWR
) {
106 /* we don't support RDWR in XFILE - use file
107 descriptors instead */
113 ret
->open_flags
= flags
;
115 ret
->fd
= sys_open(fname
, flags
, mode
);
121 x_setvbuf(ret
, NULL
, X_IOFBF
, XBUFSIZE
);
126 XFILE
*x_fdup(const XFILE
*f
)
131 fd
= dup(x_fileno(f
));
136 ret
= SMB_CALLOC_ARRAY(XFILE
, 1);
143 ret
->open_flags
= f
->open_flags
;
144 x_setvbuf(ret
, NULL
, X_IOFBF
, XBUFSIZE
);
148 /* simulate fclose() */
149 int x_fclose(XFILE
*f
)
153 /* make sure we flush any buffered data */
159 /* make sure data can't leak into a later malloc */
160 memset(f
->buf
, 0, f
->bufsize
);
163 /* check the file descriptor given to the function is NOT one of the static
164 * descriptor of this libreary or we will free unallocated memory
166 if (f
!= x_stdin
&& f
!= x_stdout
&& f
!= x_stderr
) {
172 /* simulate fwrite() */
173 size_t x_fwrite(const void *p
, size_t size
, size_t nmemb
, XFILE
*f
)
178 /* we might be writing unbuffered */
179 if (f
->buftype
== X_IONBF
||
180 (!f
->buf
&& !x_allocate_buffer(f
))) {
181 ret
= write(f
->fd
, p
, size
*nmemb
);
182 if (ret
== -1) return -1;
187 while (total
< size
*nmemb
) {
188 size_t n
= f
->bufsize
- f
->bufused
;
189 n
= MIN(n
, (size
*nmemb
)-total
);
192 /* it's full, flush it */
193 if (x_fflush(f
) != 0) {
199 memcpy(f
->buf
+ f
->bufused
, total
+(const char *)p
, n
);
204 /* when line buffered we need to flush at the last linefeed. This can
205 flush a bit more than necessary, but that is harmless */
206 if (f
->buftype
== X_IOLBF
&& f
->bufused
) {
208 for (i
=(size
*nmemb
)-1; i
>=0; i
--) {
209 if (*(i
+(const char *)p
) == '\n') {
210 if (x_fflush(f
) != 0) {
221 /* thank goodness for asprintf() */
222 int x_vfprintf(XFILE
*f
, const char *format
, va_list ap
)
230 len
= vasprintf(&p
, format
, ap2
);
231 if (len
<= 0) return len
;
232 ret
= x_fwrite(p
, 1, len
, f
);
237 int x_fprintf(XFILE
*f
, const char *format
, ...)
242 va_start(ap
, format
);
243 ret
= x_vfprintf(f
, format
, ap
);
248 /* at least fileno() is simple! */
249 int x_fileno(const XFILE
*f
)
254 /* simulate fflush() */
255 int x_fflush(XFILE
*f
)
259 if (f
->flags
& X_FLAG_ERROR
) return -1;
261 if (f
->bufused
== 0 || !f
->buf
) return 0;
263 if ((f
->open_flags
& O_ACCMODE
) != O_WRONLY
) {
268 ret
= write(f
->fd
, f
->buf
, f
->bufused
);
269 if (ret
== -1) return -1;
272 if (f
->bufused
> 0) {
273 f
->flags
|= X_FLAG_ERROR
;
274 memmove(f
->buf
, ret
+ (char *)f
->buf
, f
->bufused
);
281 /* simulate setbuffer() */
282 void x_setbuffer(XFILE
*f
, char *buf
, size_t size
)
284 x_setvbuf(f
, buf
, buf
?X_IOFBF
:X_IONBF
, size
);
287 /* simulate setbuf() */
288 void x_setbuf(XFILE
*f
, char *buf
)
290 x_setvbuf(f
, buf
, buf
?X_IOFBF
:X_IONBF
, XBUFSIZE
);
293 /* simulate setlinebuf() */
294 void x_setlinebuf(XFILE
*f
)
296 x_setvbuf(f
, NULL
, X_IOLBF
, 0);
300 /* simulate feof() */
303 if (f
->flags
& X_FLAG_EOF
) return 1;
307 /* simulate ferror() */
308 int x_ferror(XFILE
*f
)
310 if (f
->flags
& X_FLAG_ERROR
) return 1;
314 /* fill the read buffer */
315 static void x_fillbuf(XFILE
*f
)
319 if (f
->bufused
) return;
321 if (!f
->buf
&& !x_allocate_buffer(f
)) return;
323 n
= read(f
->fd
, f
->buf
, f
->bufsize
);
329 /* simulate fgetc() */
330 int x_fgetc(XFILE
*f
)
334 if (f
->flags
& (X_FLAG_EOF
| X_FLAG_ERROR
)) return EOF
;
336 if (f
->bufused
== 0) x_fillbuf(f
);
338 if (f
->bufused
== 0) {
339 f
->flags
|= X_FLAG_EOF
;
343 ret
= *(unsigned char *)(f
->next
);
350 size_t x_fread(void *p
, size_t size
, size_t nmemb
, XFILE
*f
)
353 while (total
< size
*nmemb
) {
356 (total
+(char *)p
)[0] = (char)c
;
362 /* simulate fgets() */
363 char *x_fgets(char *s
, int size
, XFILE
*stream
)
368 int c
= x_fgetc(stream
);
372 if (c
== '\n') break;
374 if (l
==size
|| x_ferror(stream
)) {
381 /* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
382 * set then an error is returned */
383 off_t
x_tseek(XFILE
*f
, off_t offset
, int whence
)
385 if (f
->flags
& X_FLAG_ERROR
)
388 /* only SEEK_SET and SEEK_END are supported */
389 /* SEEK_CUR needs internal offset counter */
390 if (whence
!= SEEK_SET
&& whence
!= SEEK_END
) {
391 f
->flags
|= X_FLAG_EINVAL
;
396 /* empty the buffer */
397 switch (f
->open_flags
& O_ACCMODE
) {
402 if (x_fflush(f
) != 0)
410 f
->flags
&= ~X_FLAG_EOF
;
411 return (off_t
)sys_lseek(f
->fd
, offset
, whence
);