This commit was manufactured by cvs2svn to create branch 'SAMBA_3_0'.(This used to...
[tprouty/samba.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 static XFILE _x_stdin =  { 0, NULL, NULL, 0, 0, O_RDONLY, X_IOFBF, 0 };
35 static XFILE _x_stdout = { 1, NULL, NULL, 0, 0, O_WRONLY, X_IOLBF, 0 };
36 static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
37
38 XFILE *x_stdin = &_x_stdin;
39 XFILE *x_stdout = &_x_stdout;
40 XFILE *x_stderr = &_x_stderr;
41
42 #define XBUFSIZE BUFSIZ
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-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         len = vasprintf(&p, format, ap);
191         if (len <= 0) return len;
192         ret = x_fwrite(p, 1, len, f);
193         SAFE_FREE(p);
194         return ret;
195 }
196
197 int x_fprintf(XFILE *f, const char *format, ...)
198 {
199         va_list ap;
200         int ret;
201
202         va_start(ap, format);
203         ret = x_vfprintf(f, format, ap);
204         va_end(ap);
205         return ret;
206 }
207
208 /* at least fileno() is simple! */
209 int x_fileno(XFILE *f)
210 {
211         return f->fd;
212 }
213
214 /* simulate fflush() */
215 int x_fflush(XFILE *f)
216 {
217         int ret;
218
219         if (f->flags & X_FLAG_ERROR) return -1;
220
221         if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
222                 errno = EINVAL;
223                 return -1;
224         }
225
226         if (f->bufused == 0) return 0;
227
228         ret = write(f->fd, f->buf, f->bufused);
229         if (ret == -1) return -1;
230         
231         f->bufused -= ret;
232         if (f->bufused > 0) {
233                 f->flags |= X_FLAG_ERROR;
234                 memmove(f->buf, ret + (char *)f->buf, f->bufused);
235                 return -1;
236         }
237
238         return 0;
239 }
240
241 /* simulate setbuffer() */
242 void x_setbuffer(XFILE *f, char *buf, size_t size)
243 {
244         x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
245 }
246
247 /* simulate setbuf() */
248 void x_setbuf(XFILE *f, char *buf)
249 {
250         x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
251 }
252
253 /* simulate setlinebuf() */
254 void x_setlinebuf(XFILE *f)
255 {
256         x_setvbuf(f, NULL, X_IOLBF, 0);
257 }
258
259
260 /* simulate feof() */
261 int x_feof(XFILE *f)
262 {
263         if (f->flags & X_FLAG_EOF) return 1;
264         return 0;
265 }
266
267 /* simulate ferror() */
268 int x_ferror(XFILE *f)
269 {
270         if (f->flags & X_FLAG_ERROR) return 1;
271         return 0;
272 }
273
274 /* fill the read buffer */
275 static void x_fillbuf(XFILE *f)
276 {
277         int n;
278
279         if (f->bufused) return;
280
281         if (!f->buf && !x_allocate_buffer(f)) return;
282
283         n = read(f->fd, f->buf, f->bufsize);
284         if (n <= 0) return;
285         f->bufused = n;
286         f->next = f->buf;
287 }
288
289 /* simulate fgetc() */
290 int x_fgetc(XFILE *f)
291 {
292         int ret;
293
294         if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
295         
296         if (f->bufused == 0) x_fillbuf(f);
297
298         if (f->bufused == 0) {
299                 f->flags |= X_FLAG_EOF;
300                 return EOF;
301         }
302
303         ret = *(unsigned char *)(f->next);
304         f->next++;
305         f->bufused--;
306         return ret;
307 }
308
309 /* simulate fread */
310 size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
311 {
312         size_t total = 0;
313         while (total < size*nmemb) {
314                 int c = x_fgetc(f);
315                 if (c == EOF) break;
316                 (total+(char *)p)[0] = (char)c;
317                 total++;
318         }
319         return total/size;
320 }
321
322 /* simulate fgets() */
323 char *x_fgets(char *s, int size, XFILE *stream) 
324 {
325         char *s0 = s;
326         int l = size;
327         while (l>1) {
328                 int c = x_fgetc(stream);
329                 if (c == EOF) break;
330                 *s++ = (char)c;
331                 l--;
332                 if (c == '\n') break;
333         }
334         if (l==size || x_ferror(stream)) {
335                 return 0;
336         }
337         *s = 0;
338         return s0;
339 }