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/>.
22 * @brief scalable FILE replacement
26 stdio is very convenient, but on some systems the file descriptor
27 in FILE* is 8 bits, so it fails when more than 255 files are open.
29 XFILE replaces stdio. It is less efficient, but at least it works
30 when you have lots of files open
32 The main restriction on XFILE is that it doesn't support seeking,
33 and doesn't support O_RDWR. That keeps the code simple.
37 #include "system/filesys.h"
39 #if _SAMBA_BUILD_ == 3
43 #define XBUFSIZE BUFSIZ
45 static XFILE _x_stdin
= { 0, NULL
, NULL
, XBUFSIZE
, 0, O_RDONLY
, X_IOFBF
, 0 };
46 static XFILE _x_stdout
= { 1, NULL
, NULL
, XBUFSIZE
, 0, O_WRONLY
, X_IOLBF
, 0 };
47 static XFILE _x_stderr
= { 2, NULL
, NULL
, 0, 0, O_WRONLY
, X_IONBF
, 0 };
49 XFILE
*x_stdin
= &_x_stdin
;
50 XFILE
*x_stdout
= &_x_stdout
;
51 XFILE
*x_stderr
= &_x_stderr
;
54 #define X_FLAG_ERROR 2
55 #define X_FLAG_EINVAL 3
57 /** simulate setvbuf() */
58 int x_setvbuf(XFILE
*f
, char *buf
, int mode
, size_t size
)
61 if (f
->bufused
) return -1;
63 /* on files being read full buffering is the only option */
64 if ((f
->open_flags
& O_ACCMODE
) == O_RDONLY
) {
68 /* destroy any earlier buffer */
76 if (f
->buftype
== X_IONBF
) return 0;
78 /* if buffering then we need some size */
79 if (size
== 0) size
= XBUFSIZE
;
87 /* allocate the buffer */
88 static int x_allocate_buffer(XFILE
*f
)
91 if (f
->bufsize
== 0) return 0;
92 f
->buf
= (char *)malloc(f
->bufsize
);
93 if (!f
->buf
) return 0;
99 /** this looks more like open() than fopen(), but that is quite deliberate.
100 I want programmers to *think* about O_EXCL, O_CREAT etc not just
101 get them magically added
103 XFILE
*x_fopen(const char *fname
, int flags
, mode_t mode
)
107 ret
= (XFILE
*)malloc_p(XFILE
);
108 if (!ret
) return NULL
;
110 memset(ret
, 0, sizeof(XFILE
));
112 if ((flags
& O_ACCMODE
) == O_RDWR
) {
113 /* we don't support RDWR in XFILE - use file
114 descriptors instead */
120 ret
->open_flags
= flags
;
122 ret
->fd
= open(fname
, flags
, mode
);
128 x_setvbuf(ret
, NULL
, X_IOFBF
, XBUFSIZE
);
133 /** simulate fclose() */
134 int x_fclose(XFILE
*f
)
138 /* make sure we flush any buffered data */
144 /* make sure data can't leak into a later malloc */
145 memset(f
->buf
, 0, f
->bufsize
);
148 /* check the file descriptor given to the function is NOT one of the static
149 * descriptor of this libreary or we will free unallocated memory
151 if (f
!= x_stdin
&& f
!= x_stdout
&& f
!= x_stderr
) {
157 /** simulate fwrite() */
158 size_t x_fwrite(const void *p
, size_t size
, size_t nmemb
, XFILE
*f
)
163 /* we might be writing unbuffered */
164 if (f
->buftype
== X_IONBF
||
165 (!f
->buf
&& !x_allocate_buffer(f
))) {
166 ret
= write(f
->fd
, p
, size
*nmemb
);
167 if (ret
== -1) return -1;
172 while (total
< size
*nmemb
) {
173 size_t n
= f
->bufsize
- f
->bufused
;
174 n
= MIN(n
, (size
*nmemb
)-total
);
177 /* it's full, flush it */
182 memcpy(f
->buf
+ f
->bufused
, total
+(const char *)p
, n
);
187 /* when line buffered we need to flush at the last linefeed. This can
188 flush a bit more than necessary, but that is harmless */
189 if (f
->buftype
== X_IOLBF
&& f
->bufused
) {
191 for (i
=(size
*nmemb
)-1; i
>=0; i
--) {
192 if (*(i
+(const char *)p
) == '\n') {
202 /** thank goodness for asprintf() */
203 int x_vfprintf(XFILE
*f
, const char *format
, va_list ap
)
210 len
= vasprintf(&p
, format
, ap2
);
212 if (len
<= 0) return len
;
213 ret
= x_fwrite(p
, 1, len
, f
);
218 int x_fprintf(XFILE
*f
, const char *format
, ...)
223 va_start(ap
, format
);
224 ret
= x_vfprintf(f
, format
, ap
);
229 /* at least fileno() is simple! */
230 int x_fileno(const XFILE
*f
)
235 /** simulate fflush() */
236 int x_fflush(XFILE
*f
)
240 if (f
->flags
& X_FLAG_ERROR
) return -1;
242 if ((f
->open_flags
& O_ACCMODE
) != O_WRONLY
) {
247 if (f
->bufused
== 0) return 0;
249 ret
= write(f
->fd
, f
->buf
, f
->bufused
);
250 if (ret
== -1) return -1;
253 if (f
->bufused
> 0) {
254 f
->flags
|= X_FLAG_ERROR
;
255 memmove(f
->buf
, ret
+ (char *)f
->buf
, f
->bufused
);
262 /** simulate setbuffer() */
263 void x_setbuffer(XFILE
*f
, char *buf
, size_t size
)
265 x_setvbuf(f
, buf
, buf
?X_IOFBF
:X_IONBF
, size
);
268 /** simulate setbuf() */
269 void x_setbuf(XFILE
*f
, char *buf
)
271 x_setvbuf(f
, buf
, buf
?X_IOFBF
:X_IONBF
, XBUFSIZE
);
274 /** simulate setlinebuf() */
275 void x_setlinebuf(XFILE
*f
)
277 x_setvbuf(f
, NULL
, X_IOLBF
, 0);
281 /** simulate feof() */
284 if (f
->flags
& X_FLAG_EOF
) return 1;
288 /** simulate ferror() */
289 int x_ferror(XFILE
*f
)
291 if (f
->flags
& X_FLAG_ERROR
) return 1;
295 /* fill the read buffer */
296 static void x_fillbuf(XFILE
*f
)
300 if (f
->bufused
) return;
302 if (!f
->buf
&& !x_allocate_buffer(f
)) return;
304 n
= read(f
->fd
, f
->buf
, f
->bufsize
);
310 /** simulate fgetc() */
311 int x_fgetc(XFILE
*f
)
315 if (f
->flags
& (X_FLAG_EOF
| X_FLAG_ERROR
)) return EOF
;
317 if (f
->bufused
== 0) x_fillbuf(f
);
319 if (f
->bufused
== 0) {
320 f
->flags
|= X_FLAG_EOF
;
324 ret
= *(uint8_t *)(f
->next
);
330 /** simulate fread */
331 size_t x_fread(void *p
, size_t size
, size_t nmemb
, XFILE
*f
)
333 size_t remaining
= size
* nmemb
;
336 while (remaining
> 0) {
341 if (f
->bufused
== 0) {
342 f
->flags
|= X_FLAG_EOF
;
346 thistime
= MIN(f
->bufused
, remaining
);
348 memcpy((char *)p
+total
, f
->next
, thistime
);
351 f
->bufused
-= thistime
;
352 remaining
-= thistime
;
358 /** simulate fgets() */
359 char *x_fgets(char *s
, int size
, XFILE
*stream
)
364 int c
= x_fgetc(stream
);
368 if (c
== '\n') break;
370 if (l
==size
|| x_ferror(stream
)) {
378 * trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
379 * set then an error is returned */
380 off_t
x_tseek(XFILE
*f
, off_t offset
, int whence
)
382 if (f
->flags
& X_FLAG_ERROR
)
385 /* only SEEK_SET and SEEK_END are supported */
386 /* SEEK_CUR needs internal offset counter */
387 if (whence
!= SEEK_SET
&& whence
!= SEEK_END
) {
388 f
->flags
|= X_FLAG_EINVAL
;
393 /* empty the buffer */
394 switch (f
->open_flags
& O_ACCMODE
) {
399 if (x_fflush(f
) != 0)
407 f
->flags
&= ~X_FLAG_EOF
;
408 return lseek(f
->fd
, offset
, whence
);
411 XFILE
*x_fdup(const XFILE
*f
)
416 fd
= dup(x_fileno(f
));
421 ret
= (XFILE
*)malloc_p(XFILE
);
426 memset(ret
, 0, sizeof(XFILE
));
429 ret
->open_flags
= f
->open_flags
;
430 x_setvbuf(ret
, NULL
, X_IOFBF
, XBUFSIZE
);