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 3 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, see <http://www.gnu.org/licenses/>.
21 stdio is very convenient, but on some systems the file descriptor
22 in FILE* is 8 bits, so it fails when more than 255 files are open.
24 XFILE replaces stdio. It is less efficient, but at least it works
25 when you have lots of files open
27 The main restriction on XFILE is that it doesn't support seeking,
28 and doesn't support O_RDWR. That keeps the code simple.
33 #define XBUFSIZE BUFSIZ
35 static XFILE _x_stdin
= { 0, NULL
, NULL
, XBUFSIZE
, 0, O_RDONLY
, X_IOFBF
, 0 };
36 static XFILE _x_stdout
= { 1, NULL
, NULL
, XBUFSIZE
, 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
;
44 #define X_FLAG_ERROR 2
45 #define X_FLAG_EINVAL 3
47 /* simulate setvbuf() */
48 int x_setvbuf(XFILE
*f
, char *buf
, int mode
, size_t size
)
50 if (x_fflush(f
) != 0) return -1;
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
= (char *)SMB_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
= SMB_MALLOC_P(XFILE
);
102 memset(ret
, 0, sizeof(XFILE
));
104 if ((flags
& O_ACCMODE
) == O_RDWR
) {
105 /* we don't support RDWR in XFILE - use file
106 descriptors instead */
112 ret
->open_flags
= flags
;
114 ret
->fd
= sys_open(fname
, flags
, mode
);
120 x_setvbuf(ret
, NULL
, X_IOFBF
, XBUFSIZE
);
125 XFILE
*x_fdup(const XFILE
*f
)
130 fd
= dup(x_fileno(f
));
135 ret
= SMB_CALLOC_ARRAY(XFILE
, 1);
142 ret
->open_flags
= f
->open_flags
;
143 x_setvbuf(ret
, NULL
, X_IOFBF
, XBUFSIZE
);
147 /* simulate fclose() */
148 int x_fclose(XFILE
*f
)
152 /* make sure we flush any buffered data */
158 /* make sure data can't leak into a later malloc */
159 memset(f
->buf
, 0, f
->bufsize
);
162 /* check the file descriptor given to the function is NOT one of the static
163 * descriptor of this libreary or we will free unallocated memory
165 if (f
!= x_stdin
&& f
!= x_stdout
&& f
!= x_stderr
) {
171 /* simulate fwrite() */
172 size_t x_fwrite(const void *p
, size_t size
, size_t nmemb
, XFILE
*f
)
177 /* we might be writing unbuffered */
178 if (f
->buftype
== X_IONBF
||
179 (!f
->buf
&& !x_allocate_buffer(f
))) {
180 ret
= write(f
->fd
, p
, size
*nmemb
);
181 if (ret
== -1) return -1;
186 while (total
< size
*nmemb
) {
187 size_t n
= f
->bufsize
- f
->bufused
;
188 n
= MIN(n
, (size
*nmemb
)-total
);
191 /* it's full, flush it */
192 if (x_fflush(f
) != 0) {
198 memcpy(f
->buf
+ f
->bufused
, total
+(const char *)p
, n
);
203 /* when line buffered we need to flush at the last linefeed. This can
204 flush a bit more than necessary, but that is harmless */
205 if (f
->buftype
== X_IOLBF
&& f
->bufused
) {
207 for (i
=(size
*nmemb
)-1; i
>=0; i
--) {
208 if (*(i
+(const char *)p
) == '\n') {
209 if (x_fflush(f
) != 0) {
220 /* thank goodness for asprintf() */
221 int x_vfprintf(XFILE
*f
, const char *format
, va_list ap
)
229 len
= vasprintf(&p
, format
, ap2
);
234 ret
= x_fwrite(p
, 1, len
, f
);
242 int x_fprintf(XFILE
*f
, const char *format
, ...)
247 va_start(ap
, format
);
248 ret
= x_vfprintf(f
, format
, ap
);
253 /* at least fileno() is simple! */
254 int x_fileno(const XFILE
*f
)
259 /* simulate fflush() */
260 int x_fflush(XFILE
*f
)
264 if (f
->flags
& X_FLAG_ERROR
) return -1;
266 if (f
->bufused
== 0 || !f
->buf
) return 0;
268 if ((f
->open_flags
& O_ACCMODE
) != O_WRONLY
) {
273 ret
= write(f
->fd
, f
->buf
, f
->bufused
);
274 if (ret
== -1) return -1;
277 if (f
->bufused
> 0) {
278 f
->flags
|= X_FLAG_ERROR
;
279 memmove(f
->buf
, ret
+ (char *)f
->buf
, f
->bufused
);
286 /* simulate setbuffer() */
287 void x_setbuffer(XFILE
*f
, char *buf
, size_t size
)
289 x_setvbuf(f
, buf
, buf
?X_IOFBF
:X_IONBF
, size
);
292 /* simulate setbuf() */
293 void x_setbuf(XFILE
*f
, char *buf
)
295 x_setvbuf(f
, buf
, buf
?X_IOFBF
:X_IONBF
, XBUFSIZE
);
298 /* simulate setlinebuf() */
299 void x_setlinebuf(XFILE
*f
)
301 x_setvbuf(f
, NULL
, X_IOLBF
, 0);
305 /* simulate feof() */
308 if (f
->flags
& X_FLAG_EOF
) return 1;
312 /* simulate ferror() */
313 int x_ferror(XFILE
*f
)
315 if (f
->flags
& X_FLAG_ERROR
) return 1;
319 /* fill the read buffer */
320 static void x_fillbuf(XFILE
*f
)
324 if (f
->bufused
) return;
326 if (!f
->buf
&& !x_allocate_buffer(f
)) return;
328 n
= read(f
->fd
, f
->buf
, f
->bufsize
);
334 /* simulate fgetc() */
335 int x_fgetc(XFILE
*f
)
339 if (f
->flags
& (X_FLAG_EOF
| X_FLAG_ERROR
)) return EOF
;
341 if (f
->bufused
== 0) x_fillbuf(f
);
343 if (f
->bufused
== 0) {
344 f
->flags
|= X_FLAG_EOF
;
348 ret
= *(unsigned char *)(f
->next
);
355 size_t x_fread(void *p
, size_t size
, size_t nmemb
, XFILE
*f
)
357 size_t remaining
= size
* nmemb
;
360 while (remaining
> 0) {
365 if (f
->bufused
== 0) {
366 f
->flags
|= X_FLAG_EOF
;
370 thistime
= MIN(f
->bufused
, remaining
);
372 memcpy((char *)p
+total
, f
->next
, thistime
);
375 f
->bufused
-= thistime
;
376 remaining
-= thistime
;
382 /* simulate fgets() */
383 char *x_fgets(char *s
, int size
, XFILE
*stream
)
388 int c
= x_fgetc(stream
);
392 if (c
== '\n') break;
394 if (l
==size
|| x_ferror(stream
)) {
401 /* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
402 * set then an error is returned */
403 off_t
x_tseek(XFILE
*f
, off_t offset
, int whence
)
405 if (f
->flags
& X_FLAG_ERROR
)
408 /* only SEEK_SET and SEEK_END are supported */
409 /* SEEK_CUR needs internal offset counter */
410 if (whence
!= SEEK_SET
&& whence
!= SEEK_END
) {
411 f
->flags
|= X_FLAG_EINVAL
;
416 /* empty the buffer */
417 switch (f
->open_flags
& O_ACCMODE
) {
422 if (x_fflush(f
) != 0)
430 f
->flags
&= ~X_FLAG_EOF
;
431 return (off_t
)sys_lseek(f
->fd
, offset
, whence
);