r3220: merging current 3.0 code to release branch
[Samba.git] / source / lib / xfile.c
blobda5ec126c1f9b94db09549eebe72e59b294424f2
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 x_fflush(f);
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 = 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 = (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 */
106 errno = EINVAL;
107 return NULL;
110 ret->open_flags = flags;
112 ret->fd = sys_open(fname, flags, mode);
113 if (ret->fd == -1) {
114 SAFE_FREE(ret);
115 return NULL;
118 x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
120 return ret;
123 /* simulate fclose() */
124 int x_fclose(XFILE *f)
126 int ret;
128 /* make sure we flush any buffered data */
129 x_fflush(f);
131 ret = close(f->fd);
132 f->fd = -1;
133 if (f->buf) {
134 /* make sure data can't leak into a later malloc */
135 memset(f->buf, 0, f->bufsize);
136 SAFE_FREE(f->buf);
138 /* check the file descriptor given to the function is NOT one of the static
139 * descriptor of this libreary or we will free unallocated memory
140 * --sss */
141 if (f != x_stdin && f != x_stdout && f != x_stderr) {
142 SAFE_FREE(f);
144 return ret;
147 /* simulate fwrite() */
148 size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
150 ssize_t ret;
151 size_t total=0;
153 /* we might be writing unbuffered */
154 if (f->buftype == X_IONBF ||
155 (!f->buf && !x_allocate_buffer(f))) {
156 ret = write(f->fd, p, size*nmemb);
157 if (ret == -1) return -1;
158 return ret/size;
162 while (total < size*nmemb) {
163 size_t n = f->bufsize - f->bufused;
164 n = MIN(n, (size*nmemb)-total);
166 if (n == 0) {
167 /* it's full, flush it */
168 x_fflush(f);
169 continue;
172 memcpy(f->buf + f->bufused, total+(const char *)p, n);
173 f->bufused += n;
174 total += n;
177 /* when line buffered we need to flush at the last linefeed. This can
178 flush a bit more than necessary, but that is harmless */
179 if (f->buftype == X_IOLBF && f->bufused) {
180 int i;
181 for (i=(size*nmemb)-1; i>=0; i--) {
182 if (*(i+(const char *)p) == '\n') {
183 x_fflush(f);
184 break;
189 return total/size;
192 /* thank goodness for asprintf() */
193 int x_vfprintf(XFILE *f, const char *format, va_list ap)
195 char *p;
196 int len, ret;
197 va_list ap2;
199 VA_COPY(ap2, ap);
201 len = vasprintf(&p, format, ap2);
202 if (len <= 0) return len;
203 ret = x_fwrite(p, 1, len, f);
204 SAFE_FREE(p);
205 return ret;
208 int x_fprintf(XFILE *f, const char *format, ...)
210 va_list ap;
211 int ret;
213 va_start(ap, format);
214 ret = x_vfprintf(f, format, ap);
215 va_end(ap);
216 return ret;
219 /* at least fileno() is simple! */
220 int x_fileno(XFILE *f)
222 return f->fd;
225 /* simulate fflush() */
226 int x_fflush(XFILE *f)
228 int ret;
230 if (f->flags & X_FLAG_ERROR) return -1;
232 if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
233 errno = EINVAL;
234 return -1;
237 if (f->bufused == 0) return 0;
239 ret = write(f->fd, f->buf, f->bufused);
240 if (ret == -1) return -1;
242 f->bufused -= ret;
243 if (f->bufused > 0) {
244 f->flags |= X_FLAG_ERROR;
245 memmove(f->buf, ret + (char *)f->buf, f->bufused);
246 return -1;
249 return 0;
252 /* simulate setbuffer() */
253 void x_setbuffer(XFILE *f, char *buf, size_t size)
255 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
258 /* simulate setbuf() */
259 void x_setbuf(XFILE *f, char *buf)
261 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
264 /* simulate setlinebuf() */
265 void x_setlinebuf(XFILE *f)
267 x_setvbuf(f, NULL, X_IOLBF, 0);
271 /* simulate feof() */
272 int x_feof(XFILE *f)
274 if (f->flags & X_FLAG_EOF) return 1;
275 return 0;
278 /* simulate ferror() */
279 int x_ferror(XFILE *f)
281 if (f->flags & X_FLAG_ERROR) return 1;
282 return 0;
285 /* fill the read buffer */
286 static void x_fillbuf(XFILE *f)
288 int n;
290 if (f->bufused) return;
292 if (!f->buf && !x_allocate_buffer(f)) return;
294 n = read(f->fd, f->buf, f->bufsize);
295 if (n <= 0) return;
296 f->bufused = n;
297 f->next = f->buf;
300 /* simulate fgetc() */
301 int x_fgetc(XFILE *f)
303 int ret;
305 if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
307 if (f->bufused == 0) x_fillbuf(f);
309 if (f->bufused == 0) {
310 f->flags |= X_FLAG_EOF;
311 return EOF;
314 ret = *(unsigned char *)(f->next);
315 f->next++;
316 f->bufused--;
317 return ret;
320 /* simulate fread */
321 size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
323 size_t total = 0;
324 while (total < size*nmemb) {
325 int c = x_fgetc(f);
326 if (c == EOF) break;
327 (total+(char *)p)[0] = (char)c;
328 total++;
330 return total/size;
333 /* simulate fgets() */
334 char *x_fgets(char *s, int size, XFILE *stream)
336 char *s0 = s;
337 int l = size;
338 while (l>1) {
339 int c = x_fgetc(stream);
340 if (c == EOF) break;
341 *s++ = (char)c;
342 l--;
343 if (c == '\n') break;
345 if (l==size || x_ferror(stream)) {
346 return 0;
348 *s = 0;
349 return s0;
352 /* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
353 * set then an error is returned */
354 off_t x_tseek(XFILE *f, off_t offset, int whence)
356 if (f->flags & X_FLAG_ERROR)
357 return -1;
359 /* only SEEK_SET and SEEK_END are supported */
360 /* SEEK_CUR needs internal offset counter */
361 if (whence != SEEK_SET && whence != SEEK_END) {
362 f->flags |= X_FLAG_EINVAL;
363 errno = EINVAL;
364 return -1;
367 /* empty the buffer */
368 switch (f->open_flags & O_ACCMODE) {
369 case O_RDONLY:
370 f->bufused = 0;
371 break;
372 case O_WRONLY:
373 if (x_fflush(f) != 0)
374 return -1;
375 break;
376 default:
377 errno = EINVAL;
378 return -1;
381 f->flags &= ~X_FLAG_EOF;
382 return (off_t)sys_lseek(f->fd, offset, whence);