This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[ira/wip.git] / source3 / lib / xfile.c
1 /* 
2    Unix SMB/CIFS implementation.
3    stdio replacement
4    Copyright (C) Andrew Tridgell 2001
5    
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.
10    
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.
15    
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.
19 */
20
21 /*
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. 
24
25   XFILE replaces stdio. It is less efficient, but at least it works
26   when you have lots of files open
27
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.
30 */
31
32 #include "includes.h"
33
34 #define XBUFSIZE BUFSIZ
35
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 };
39
40 XFILE *x_stdin = &_x_stdin;
41 XFILE *x_stdout = &_x_stdout;
42 XFILE *x_stderr = &_x_stderr;
43
44 #define X_FLAG_EOF 1
45 #define X_FLAG_ERROR 2
46
47 /* simulate setvbuf() */
48 int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
49 {
50         x_fflush(f);
51         if (f->bufused) return -1;
52
53         /* on files being read full buffering is the only option */
54         if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
55                 mode = X_IOFBF;
56         }
57
58         /* destroy any earlier buffer */
59         SAFE_FREE(f->buf);
60         f->buf = 0;
61         f->bufsize = 0;
62         f->next = NULL;
63         f->bufused = 0;
64         f->buftype = mode;
65
66         if (f->buftype == X_IONBF) return 0;
67
68         /* if buffering then we need some size */
69         if (size == 0) size = XBUFSIZE;
70
71         f->bufsize = size;
72         f->bufused = 0;
73
74         return 0;
75 }
76
77 /* allocate the buffer */
78 static int x_allocate_buffer(XFILE *f)
79 {
80         if (f->buf) return 1;
81         if (f->bufsize == 0) return 0;
82         f->buf = malloc(f->bufsize);
83         if (!f->buf) return 0;
84         f->next = f->buf;
85         return 1;
86 }
87
88
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 
92 */
93 XFILE *x_fopen(const char *fname, int flags, mode_t mode)
94 {
95         XFILE *ret;
96
97         ret = (XFILE *)malloc(sizeof(XFILE));
98         if (!ret) return NULL;
99
100         memset(ret, 0, sizeof(XFILE));
101
102         if ((flags & O_ACCMODE) == O_RDWR) {
103                 /* we don't support RDWR in XFILE - use file 
104                    descriptors instead */
105                 errno = EINVAL;
106                 return NULL;
107         }
108
109         ret->open_flags = flags;
110
111         ret->fd = sys_open(fname, flags, mode);
112         if (ret->fd == -1) {
113                 SAFE_FREE(ret);
114                 return NULL;
115         }
116
117         x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
118         
119         return ret;
120 }
121
122 /* simulate fclose() */
123 int x_fclose(XFILE *f)
124 {
125         int ret;
126
127         /* make sure we flush any buffered data */
128         x_fflush(f);
129
130         ret = close(f->fd);
131         f->fd = -1;
132         if (f->buf) {
133                 /* make sure data can't leak into a later malloc */
134                 memset(f->buf, 0, f->bufsize);
135                 SAFE_FREE(f->buf);
136         }
137         SAFE_FREE(f);
138         return ret;
139 }
140
141 /* simulate fwrite() */
142 int x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
143 {
144         int ret, total=0;
145
146         /* we might be writing unbuffered */
147         if (f->buftype == X_IONBF || 
148             (!f->buf && !x_allocate_buffer(f))) {
149                 ret = write(f->fd, p, size*nmemb);
150                 if (ret == -1) return -1;
151                 return ret/size;
152         } 
153
154
155         while (total < size*nmemb) {
156                 int n = f->bufsize - f->bufused;
157                 n = MIN(n, (size*nmemb)-total);
158
159                 if (n == 0) {
160                         /* it's full, flush it */
161                         x_fflush(f);
162                         continue;
163                 }
164
165                 memcpy(f->buf + f->bufused, total+(const char *)p, n);
166                 f->bufused += n;
167                 total += n;
168         }
169
170         /* when line buffered we need to flush at the last linefeed. This can
171            flush a bit more than necessary, but that is harmless */
172         if (f->buftype == X_IOLBF && f->bufused) {
173                 int i;
174                 for (i=(size*nmemb)-1; i>=0; i--) {
175                         if (*(i+(const char *)p) == '\n') {
176                                 x_fflush(f);
177                                 break;
178                         }
179                 }
180         }
181
182         return total/size;
183 }
184
185 /* thank goodness for asprintf() */
186 int x_vfprintf(XFILE *f, const char *format, va_list ap)
187 {
188         char *p;
189         int len, ret;
190         va_list ap2;
191
192         VA_COPY(ap2, ap);
193
194         len = vasprintf(&p, format, ap2);
195         if (len <= 0) return len;
196         ret = x_fwrite(p, 1, len, f);
197         SAFE_FREE(p);
198         return ret;
199 }
200
201 int x_fprintf(XFILE *f, const char *format, ...)
202 {
203         va_list ap;
204         int ret;
205
206         va_start(ap, format);
207         ret = x_vfprintf(f, format, ap);
208         va_end(ap);
209         return ret;
210 }
211
212 /* at least fileno() is simple! */
213 int x_fileno(XFILE *f)
214 {
215         return f->fd;
216 }
217
218 /* simulate fflush() */
219 int x_fflush(XFILE *f)
220 {
221         int ret;
222
223         if (f->flags & X_FLAG_ERROR) return -1;
224
225         if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
226                 errno = EINVAL;
227                 return -1;
228         }
229
230         if (f->bufused == 0) return 0;
231
232         ret = write(f->fd, f->buf, f->bufused);
233         if (ret == -1) return -1;
234         
235         f->bufused -= ret;
236         if (f->bufused > 0) {
237                 f->flags |= X_FLAG_ERROR;
238                 memmove(f->buf, ret + (char *)f->buf, f->bufused);
239                 return -1;
240         }
241
242         return 0;
243 }
244
245 /* simulate setbuffer() */
246 void x_setbuffer(XFILE *f, char *buf, size_t size)
247 {
248         x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
249 }
250
251 /* simulate setbuf() */
252 void x_setbuf(XFILE *f, char *buf)
253 {
254         x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
255 }
256
257 /* simulate setlinebuf() */
258 void x_setlinebuf(XFILE *f)
259 {
260         x_setvbuf(f, NULL, X_IOLBF, 0);
261 }
262
263
264 /* simulate feof() */
265 int x_feof(XFILE *f)
266 {
267         if (f->flags & X_FLAG_EOF) return 1;
268         return 0;
269 }
270
271 /* simulate ferror() */
272 int x_ferror(XFILE *f)
273 {
274         if (f->flags & X_FLAG_ERROR) return 1;
275         return 0;
276 }
277
278 /* fill the read buffer */
279 static void x_fillbuf(XFILE *f)
280 {
281         int n;
282
283         if (f->bufused) return;
284
285         if (!f->buf && !x_allocate_buffer(f)) return;
286
287         n = read(f->fd, f->buf, f->bufsize);
288         if (n <= 0) return;
289         f->bufused = n;
290         f->next = f->buf;
291 }
292
293 /* simulate fgetc() */
294 int x_fgetc(XFILE *f)
295 {
296         int ret;
297
298         if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
299         
300         if (f->bufused == 0) x_fillbuf(f);
301
302         if (f->bufused == 0) {
303                 f->flags |= X_FLAG_EOF;
304                 return EOF;
305         }
306
307         ret = *(unsigned char *)(f->next);
308         f->next++;
309         f->bufused--;
310         return ret;
311 }
312
313 /* simulate fread */
314 size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
315 {
316         size_t total = 0;
317         while (total < size*nmemb) {
318                 int c = x_fgetc(f);
319                 if (c == EOF) break;
320                 (total+(char *)p)[0] = (char)c;
321                 total++;
322         }
323         return total/size;
324 }
325
326 /* simulate fgets() */
327 char *x_fgets(char *s, int size, XFILE *stream) 
328 {
329         char *s0 = s;
330         int l = size;
331         while (l>1) {
332                 int c = x_fgetc(stream);
333                 if (c == EOF) break;
334                 *s++ = (char)c;
335                 l--;
336                 if (c == '\n') break;
337         }
338         if (l==size || x_ferror(stream)) {
339                 return 0;
340         }
341         *s = 0;
342         return s0;
343 }