r13121: Tag 4.0.0TP1
[Samba.git] / source / lib / xfile.c
blob794e3f0f5e83ae8530f894c27dd392f3e024640a
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"
33 #include "system/filesys.h"
35 #define XBUFSIZE BUFSIZ
37 static XFILE _x_stdin = { 0, NULL, NULL, XBUFSIZE, 0, O_RDONLY, X_IOFBF, 0 };
38 static XFILE _x_stdout = { 1, NULL, NULL, XBUFSIZE, 0, O_WRONLY, X_IOLBF, 0 };
39 static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
41 XFILE *x_stdin = &_x_stdin;
42 XFILE *x_stdout = &_x_stdout;
43 XFILE *x_stderr = &_x_stderr;
45 #define X_FLAG_EOF 1
46 #define X_FLAG_ERROR 2
47 #define X_FLAG_EINVAL 3
49 /* simulate setvbuf() */
50 int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
52 x_fflush(f);
53 if (f->bufused) return -1;
55 /* on files being read full buffering is the only option */
56 if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
57 mode = X_IOFBF;
60 /* destroy any earlier buffer */
61 SAFE_FREE(f->buf);
62 f->buf = 0;
63 f->bufsize = 0;
64 f->next = NULL;
65 f->bufused = 0;
66 f->buftype = mode;
68 if (f->buftype == X_IONBF) return 0;
70 /* if buffering then we need some size */
71 if (size == 0) size = XBUFSIZE;
73 f->bufsize = size;
74 f->bufused = 0;
76 return 0;
79 /* allocate the buffer */
80 static int x_allocate_buffer(XFILE *f)
82 if (f->buf) return 1;
83 if (f->bufsize == 0) return 0;
84 f->buf = malloc(f->bufsize);
85 if (!f->buf) return 0;
86 f->next = f->buf;
87 return 1;
91 /* this looks more like open() than fopen(), but that is quite deliberate.
92 I want programmers to *think* about O_EXCL, O_CREAT etc not just
93 get them magically added
95 XFILE *x_fopen(const char *fname, int flags, mode_t mode)
97 XFILE *ret;
99 ret = malloc_p(XFILE);
100 if (!ret) return NULL;
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 */
107 errno = EINVAL;
108 return NULL;
111 ret->open_flags = flags;
113 ret->fd = open(fname, flags, mode);
114 if (ret->fd == -1) {
115 SAFE_FREE(ret);
116 return NULL;
119 x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
121 return ret;
124 /* simulate fclose() */
125 int x_fclose(XFILE *f)
127 int ret;
129 /* make sure we flush any buffered data */
130 x_fflush(f);
132 ret = close(f->fd);
133 f->fd = -1;
134 if (f->buf) {
135 /* make sure data can't leak into a later malloc */
136 memset(f->buf, 0, f->bufsize);
137 SAFE_FREE(f->buf);
139 /* check the file descriptor given to the function is NOT one of the static
140 * descriptor of this libreary or we will free unallocated memory
141 * --sss */
142 if (f != x_stdin && f != x_stdout && f != x_stderr) {
143 SAFE_FREE(f);
145 return ret;
148 /* simulate fwrite() */
149 size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
151 ssize_t ret;
152 size_t total=0;
154 /* we might be writing unbuffered */
155 if (f->buftype == X_IONBF ||
156 (!f->buf && !x_allocate_buffer(f))) {
157 ret = write(f->fd, p, size*nmemb);
158 if (ret == -1) return -1;
159 return ret/size;
163 while (total < size*nmemb) {
164 size_t n = f->bufsize - f->bufused;
165 n = MIN(n, (size*nmemb)-total);
167 if (n == 0) {
168 /* it's full, flush it */
169 x_fflush(f);
170 continue;
173 memcpy(f->buf + f->bufused, total+(const char *)p, n);
174 f->bufused += n;
175 total += n;
178 /* when line buffered we need to flush at the last linefeed. This can
179 flush a bit more than necessary, but that is harmless */
180 if (f->buftype == X_IOLBF && f->bufused) {
181 int i;
182 for (i=(size*nmemb)-1; i>=0; i--) {
183 if (*(i+(const char *)p) == '\n') {
184 x_fflush(f);
185 break;
190 return total/size;
193 /* thank goodness for asprintf() */
194 int x_vfprintf(XFILE *f, const char *format, va_list ap)
196 char *p;
197 int len, ret;
198 va_list ap2;
200 VA_COPY(ap2, ap);
202 len = vasprintf(&p, format, ap2);
203 if (len <= 0) return len;
204 ret = x_fwrite(p, 1, len, f);
205 SAFE_FREE(p);
206 return ret;
209 int x_fprintf(XFILE *f, const char *format, ...)
211 va_list ap;
212 int ret;
214 va_start(ap, format);
215 ret = x_vfprintf(f, format, ap);
216 va_end(ap);
217 return ret;
220 /* at least fileno() is simple! */
221 int x_fileno(XFILE *f)
223 return f->fd;
226 /* simulate fflush() */
227 int x_fflush(XFILE *f)
229 int ret;
231 if (f->flags & X_FLAG_ERROR) return -1;
233 if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
234 errno = EINVAL;
235 return -1;
238 if (f->bufused == 0) return 0;
240 ret = write(f->fd, f->buf, f->bufused);
241 if (ret == -1) return -1;
243 f->bufused -= ret;
244 if (f->bufused > 0) {
245 f->flags |= X_FLAG_ERROR;
246 memmove(f->buf, ret + (char *)f->buf, f->bufused);
247 return -1;
250 return 0;
253 /* simulate setbuffer() */
254 void x_setbuffer(XFILE *f, char *buf, size_t size)
256 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
259 /* simulate setbuf() */
260 void x_setbuf(XFILE *f, char *buf)
262 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
265 /* simulate setlinebuf() */
266 void x_setlinebuf(XFILE *f)
268 x_setvbuf(f, NULL, X_IOLBF, 0);
272 /* simulate feof() */
273 int x_feof(XFILE *f)
275 if (f->flags & X_FLAG_EOF) return 1;
276 return 0;
279 /* simulate ferror() */
280 int x_ferror(XFILE *f)
282 if (f->flags & X_FLAG_ERROR) return 1;
283 return 0;
286 /* fill the read buffer */
287 static void x_fillbuf(XFILE *f)
289 int n;
291 if (f->bufused) return;
293 if (!f->buf && !x_allocate_buffer(f)) return;
295 n = read(f->fd, f->buf, f->bufsize);
296 if (n <= 0) return;
297 f->bufused = n;
298 f->next = f->buf;
301 /* simulate fgetc() */
302 int x_fgetc(XFILE *f)
304 int ret;
306 if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
308 if (f->bufused == 0) x_fillbuf(f);
310 if (f->bufused == 0) {
311 f->flags |= X_FLAG_EOF;
312 return EOF;
315 ret = *(uint8_t *)(f->next);
316 f->next++;
317 f->bufused--;
318 return ret;
321 /* simulate fread */
322 size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
324 size_t total = 0;
325 while (total < size*nmemb) {
326 int c = x_fgetc(f);
327 if (c == EOF) break;
328 (total+(char *)p)[0] = (char)c;
329 total++;
331 return total/size;
334 /* simulate fgets() */
335 char *x_fgets(char *s, int size, XFILE *stream)
337 char *s0 = s;
338 int l = size;
339 while (l>1) {
340 int c = x_fgetc(stream);
341 if (c == EOF) break;
342 *s++ = (char)c;
343 l--;
344 if (c == '\n') break;
346 if (l==size || x_ferror(stream)) {
347 return 0;
349 *s = 0;
350 return s0;
353 /* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
354 * set then an error is returned */
355 off_t x_tseek(XFILE *f, off_t offset, int whence)
357 if (f->flags & X_FLAG_ERROR)
358 return -1;
360 /* only SEEK_SET and SEEK_END are supported */
361 /* SEEK_CUR needs internal offset counter */
362 if (whence != SEEK_SET && whence != SEEK_END) {
363 f->flags |= X_FLAG_EINVAL;
364 errno = EINVAL;
365 return -1;
368 /* empty the buffer */
369 switch (f->open_flags & O_ACCMODE) {
370 case O_RDONLY:
371 f->bufused = 0;
372 break;
373 case O_WRONLY:
374 if (x_fflush(f) != 0)
375 return -1;
376 break;
377 default:
378 errno = EINVAL;
379 return -1;
382 f->flags &= ~X_FLAG_EOF;
383 return lseek(f->fd, offset, whence);