Make 3.0.x in sync with 3.2 here.
[Samba.git] / source / lib / xfile.c
blob1ecaaa00406f55781445e142f1ab7f0916fbcb0f
1 /*
2 Unix SMB/CIFS implementation.
3 stdio replacement
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.
32 #include "includes.h"
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;
44 #define X_FLAG_EOF 1
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) {
56 mode = X_IOFBF;
59 /* destroy any earlier buffer */
60 SAFE_FREE(f->buf);
61 f->buf = 0;
62 f->bufsize = 0;
63 f->next = NULL;
64 f->bufused = 0;
65 f->buftype = mode;
67 if (f->buftype == X_IONBF) return 0;
69 /* if buffering then we need some size */
70 if (size == 0) size = XBUFSIZE;
72 f->bufsize = size;
73 f->bufused = 0;
75 return 0;
78 /* allocate the buffer */
79 static int x_allocate_buffer(XFILE *f)
81 if (f->buf) return 1;
82 if (f->bufsize == 0) return 0;
83 f->buf = (char *)SMB_MALLOC(f->bufsize);
84 if (!f->buf) return 0;
85 f->next = f->buf;
86 return 1;
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)
96 XFILE *ret;
98 ret = SMB_MALLOC_P(XFILE);
99 if (!ret) {
100 return NULL;
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 */
108 SAFE_FREE(ret);
109 errno = EINVAL;
110 return NULL;
113 ret->open_flags = flags;
115 ret->fd = sys_open(fname, flags, mode);
116 if (ret->fd == -1) {
117 SAFE_FREE(ret);
118 return NULL;
121 x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
123 return ret;
126 XFILE *x_fdup(const XFILE *f)
128 XFILE *ret;
129 int fd;
131 fd = dup(x_fileno(f));
132 if (fd < 0) {
133 return NULL;
136 ret = SMB_CALLOC_ARRAY(XFILE, 1);
137 if (!ret) {
138 close(fd);
139 return NULL;
142 ret->fd = fd;
143 ret->open_flags = f->open_flags;
144 x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
145 return ret;
148 /* simulate fclose() */
149 int x_fclose(XFILE *f)
151 int ret;
153 /* make sure we flush any buffered data */
154 (void)x_fflush(f);
156 ret = close(f->fd);
157 f->fd = -1;
158 if (f->buf) {
159 /* make sure data can't leak into a later malloc */
160 memset(f->buf, 0, f->bufsize);
161 SAFE_FREE(f->buf);
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
165 * --sss */
166 if (f != x_stdin && f != x_stdout && f != x_stderr) {
167 SAFE_FREE(f);
169 return ret;
172 /* simulate fwrite() */
173 size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
175 ssize_t ret;
176 size_t total=0;
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;
183 return ret/size;
187 while (total < size*nmemb) {
188 size_t n = f->bufsize - f->bufused;
189 n = MIN(n, (size*nmemb)-total);
191 if (n == 0) {
192 /* it's full, flush it */
193 if (x_fflush(f) != 0) {
194 return -1;
196 continue;
199 memcpy(f->buf + f->bufused, total+(const char *)p, n);
200 f->bufused += n;
201 total += 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) {
207 int i;
208 for (i=(size*nmemb)-1; i>=0; i--) {
209 if (*(i+(const char *)p) == '\n') {
210 if (x_fflush(f) != 0) {
211 return -1;
213 break;
218 return total/size;
221 /* thank goodness for asprintf() */
222 int x_vfprintf(XFILE *f, const char *format, va_list ap)
224 char *p;
225 int len, ret;
226 va_list ap2;
228 VA_COPY(ap2, ap);
230 len = vasprintf(&p, format, ap2);
231 if (len <= 0) return len;
232 ret = x_fwrite(p, 1, len, f);
233 SAFE_FREE(p);
234 return ret;
237 int x_fprintf(XFILE *f, const char *format, ...)
239 va_list ap;
240 int ret;
242 va_start(ap, format);
243 ret = x_vfprintf(f, format, ap);
244 va_end(ap);
245 return ret;
248 /* at least fileno() is simple! */
249 int x_fileno(const XFILE *f)
251 return f->fd;
254 /* simulate fflush() */
255 int x_fflush(XFILE *f)
257 int ret;
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) {
264 errno = EINVAL;
265 return -1;
268 ret = write(f->fd, f->buf, f->bufused);
269 if (ret == -1) return -1;
271 f->bufused -= ret;
272 if (f->bufused > 0) {
273 f->flags |= X_FLAG_ERROR;
274 memmove(f->buf, ret + (char *)f->buf, f->bufused);
275 return -1;
278 return 0;
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() */
301 int x_feof(XFILE *f)
303 if (f->flags & X_FLAG_EOF) return 1;
304 return 0;
307 /* simulate ferror() */
308 int x_ferror(XFILE *f)
310 if (f->flags & X_FLAG_ERROR) return 1;
311 return 0;
314 /* fill the read buffer */
315 static void x_fillbuf(XFILE *f)
317 int n;
319 if (f->bufused) return;
321 if (!f->buf && !x_allocate_buffer(f)) return;
323 n = read(f->fd, f->buf, f->bufsize);
324 if (n <= 0) return;
325 f->bufused = n;
326 f->next = f->buf;
329 /* simulate fgetc() */
330 int x_fgetc(XFILE *f)
332 int ret;
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;
340 return EOF;
343 ret = *(unsigned char *)(f->next);
344 f->next++;
345 f->bufused--;
346 return ret;
349 /* simulate fread */
350 size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
352 size_t total = 0;
353 while (total < size*nmemb) {
354 int c = x_fgetc(f);
355 if (c == EOF) break;
356 (total+(char *)p)[0] = (char)c;
357 total++;
359 return total/size;
362 /* simulate fgets() */
363 char *x_fgets(char *s, int size, XFILE *stream)
365 char *s0 = s;
366 int l = size;
367 while (l>1) {
368 int c = x_fgetc(stream);
369 if (c == EOF) break;
370 *s++ = (char)c;
371 l--;
372 if (c == '\n') break;
374 if (l==size || x_ferror(stream)) {
375 return 0;
377 *s = 0;
378 return s0;
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)
386 return -1;
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;
392 errno = EINVAL;
393 return -1;
396 /* empty the buffer */
397 switch (f->open_flags & O_ACCMODE) {
398 case O_RDONLY:
399 f->bufused = 0;
400 break;
401 case O_WRONLY:
402 if (x_fflush(f) != 0)
403 return -1;
404 break;
405 default:
406 errno = EINVAL;
407 return -1;
410 f->flags &= ~X_FLAG_EOF;
411 return (off_t)sys_lseek(f->fd, offset, whence);