source: branches/samba-3.5.x/lib/util/xfile.c@ 1002

Last change on this file since 1002 was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

File size: 8.3 KB
Line 
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 3 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, see <http://www.gnu.org/licenses/>.
18*/
19
20/**
21 * @file
22 * @brief scalable FILE replacement
23 */
24
25/*
26 stdio is very convenient, but on some systems the file descriptor
27 in FILE* is 8 bits, so it fails when more than 255 files are open.
28
29 XFILE replaces stdio. It is less efficient, but at least it works
30 when you have lots of files open
31
32 The main restriction on XFILE is that it doesn't support seeking,
33 and doesn't support O_RDWR. That keeps the code simple.
34*/
35
36#include "includes.h"
37#include "system/filesys.h"
38
39#if _SAMBA_BUILD_ == 3
40#undef malloc
41#endif
42
43#define XBUFSIZE BUFSIZ
44
45static XFILE _x_stdin = { 0, NULL, NULL, XBUFSIZE, 0, O_RDONLY, X_IOFBF, 0 };
46static XFILE _x_stdout = { 1, NULL, NULL, XBUFSIZE, 0, O_WRONLY, X_IOLBF, 0 };
47static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
48
49XFILE *x_stdin = &_x_stdin;
50XFILE *x_stdout = &_x_stdout;
51XFILE *x_stderr = &_x_stderr;
52
53#define X_FLAG_EOF 1
54#define X_FLAG_ERROR 2
55#define X_FLAG_EINVAL 3
56
57/** simulate setvbuf() */
58int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
59{
60 x_fflush(f);
61 if (f->bufused) return -1;
62
63 /* on files being read full buffering is the only option */
64 if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
65 mode = X_IOFBF;
66 }
67
68 /* destroy any earlier buffer */
69 SAFE_FREE(f->buf);
70 f->buf = 0;
71 f->bufsize = 0;
72 f->next = NULL;
73 f->bufused = 0;
74 f->buftype = mode;
75
76 if (f->buftype == X_IONBF) return 0;
77
78 /* if buffering then we need some size */
79 if (size == 0) size = XBUFSIZE;
80
81 f->bufsize = size;
82 f->bufused = 0;
83
84 return 0;
85}
86
87/* allocate the buffer */
88static int x_allocate_buffer(XFILE *f)
89{
90 if (f->buf) return 1;
91 if (f->bufsize == 0) return 0;
92 f->buf = (char *)malloc(f->bufsize);
93 if (!f->buf) return 0;
94 f->next = f->buf;
95 return 1;
96}
97
98
99/** this looks more like open() than fopen(), but that is quite deliberate.
100 I want programmers to *think* about O_EXCL, O_CREAT etc not just
101 get them magically added
102*/
103XFILE *x_fopen(const char *fname, int flags, mode_t mode)
104{
105 XFILE *ret;
106
107 ret = (XFILE *)malloc_p(XFILE);
108 if (!ret) return NULL;
109
110 memset(ret, 0, sizeof(XFILE));
111
112 if ((flags & O_ACCMODE) == O_RDWR) {
113 /* we don't support RDWR in XFILE - use file
114 descriptors instead */
115 SAFE_FREE(ret);
116 errno = EINVAL;
117 return NULL;
118 }
119
120 ret->open_flags = flags;
121
122 ret->fd = open(fname, flags, mode);
123 if (ret->fd == -1) {
124 SAFE_FREE(ret);
125 return NULL;
126 }
127
128 x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
129
130 return ret;
131}
132
133/** simulate fclose() */
134int x_fclose(XFILE *f)
135{
136 int ret;
137
138 /* make sure we flush any buffered data */
139 x_fflush(f);
140
141 ret = close(f->fd);
142 f->fd = -1;
143 if (f->buf) {
144 /* make sure data can't leak into a later malloc */
145 memset(f->buf, 0, f->bufsize);
146 SAFE_FREE(f->buf);
147 }
148 /* check the file descriptor given to the function is NOT one of the static
149 * descriptor of this libreary or we will free unallocated memory
150 * --sss */
151 if (f != x_stdin && f != x_stdout && f != x_stderr) {
152 SAFE_FREE(f);
153 }
154 return ret;
155}
156
157/** simulate fwrite() */
158size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
159{
160 ssize_t ret;
161 size_t total=0;
162
163 /* we might be writing unbuffered */
164 if (f->buftype == X_IONBF ||
165 (!f->buf && !x_allocate_buffer(f))) {
166 ret = write(f->fd, p, size*nmemb);
167 if (ret == -1) return -1;
168 return ret/size;
169 }
170
171
172 while (total < size*nmemb) {
173 size_t n = f->bufsize - f->bufused;
174 n = MIN(n, (size*nmemb)-total);
175
176 if (n == 0) {
177 /* it's full, flush it */
178 x_fflush(f);
179 continue;
180 }
181
182 memcpy(f->buf + f->bufused, total+(const char *)p, n);
183 f->bufused += n;
184 total += n;
185 }
186
187 /* when line buffered we need to flush at the last linefeed. This can
188 flush a bit more than necessary, but that is harmless */
189 if (f->buftype == X_IOLBF && f->bufused) {
190 int i;
191 for (i=(size*nmemb)-1; i>=0; i--) {
192 if (*(i+(const char *)p) == '\n') {
193 x_fflush(f);
194 break;
195 }
196 }
197 }
198
199 return total/size;
200}
201
202/** thank goodness for asprintf() */
203 int x_vfprintf(XFILE *f, const char *format, va_list ap)
204{
205 char *p;
206 int len, ret;
207 va_list ap2;
208
209 va_copy(ap2, ap);
210 len = vasprintf(&p, format, ap2);
211 va_end(ap2);
212 if (len <= 0) return len;
213 ret = x_fwrite(p, 1, len, f);
214 SAFE_FREE(p);
215 return ret;
216}
217
218 int x_fprintf(XFILE *f, const char *format, ...)
219{
220 va_list ap;
221 int ret;
222
223 va_start(ap, format);
224 ret = x_vfprintf(f, format, ap);
225 va_end(ap);
226 return ret;
227}
228
229/* at least fileno() is simple! */
230int x_fileno(const XFILE *f)
231{
232 return f->fd;
233}
234
235/** simulate fflush() */
236int x_fflush(XFILE *f)
237{
238 int ret;
239
240 if (f->flags & X_FLAG_ERROR) return -1;
241
242 if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
243 errno = EINVAL;
244 return -1;
245 }
246
247 if (f->bufused == 0) return 0;
248
249 ret = write(f->fd, f->buf, f->bufused);
250 if (ret == -1) return -1;
251
252 f->bufused -= ret;
253 if (f->bufused > 0) {
254 f->flags |= X_FLAG_ERROR;
255 memmove(f->buf, ret + (char *)f->buf, f->bufused);
256 return -1;
257 }
258
259 return 0;
260}
261
262/** simulate setbuffer() */
263void x_setbuffer(XFILE *f, char *buf, size_t size)
264{
265 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
266}
267
268/** simulate setbuf() */
269void x_setbuf(XFILE *f, char *buf)
270{
271 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
272}
273
274/** simulate setlinebuf() */
275void x_setlinebuf(XFILE *f)
276{
277 x_setvbuf(f, NULL, X_IOLBF, 0);
278}
279
280
281/** simulate feof() */
282int x_feof(XFILE *f)
283{
284 if (f->flags & X_FLAG_EOF) return 1;
285 return 0;
286}
287
288/** simulate ferror() */
289int x_ferror(XFILE *f)
290{
291 if (f->flags & X_FLAG_ERROR) return 1;
292 return 0;
293}
294
295/* fill the read buffer */
296static void x_fillbuf(XFILE *f)
297{
298 int n;
299
300 if (f->bufused) return;
301
302 if (!f->buf && !x_allocate_buffer(f)) return;
303
304 n = read(f->fd, f->buf, f->bufsize);
305 if (n <= 0) return;
306 f->bufused = n;
307 f->next = f->buf;
308}
309
310/** simulate fgetc() */
311int x_fgetc(XFILE *f)
312{
313 int ret;
314
315 if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
316
317 if (f->bufused == 0) x_fillbuf(f);
318
319 if (f->bufused == 0) {
320 f->flags |= X_FLAG_EOF;
321 return EOF;
322 }
323
324 ret = *(uint8_t *)(f->next);
325 f->next++;
326 f->bufused--;
327 return ret;
328}
329
330/** simulate fread */
331size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
332{
333 size_t remaining = size * nmemb;
334 size_t total = 0;
335
336 while (remaining > 0) {
337 size_t thistime;
338
339 x_fillbuf(f);
340
341 if (f->bufused == 0) {
342 f->flags |= X_FLAG_EOF;
343 break;
344 }
345
346 thistime = MIN(f->bufused, remaining);
347
348 memcpy((char *)p+total, f->next, thistime);
349
350 f->next += thistime;
351 f->bufused -= thistime;
352 remaining -= thistime;
353 total += thistime;
354 }
355 return total/size;
356}
357
358/** simulate fgets() */
359char *x_fgets(char *s, int size, XFILE *stream)
360{
361 char *s0 = s;
362 int l = size;
363 while (l>1) {
364 int c = x_fgetc(stream);
365 if (c == EOF) break;
366 *s++ = (char)c;
367 l--;
368 if (c == '\n') break;
369 }
370 if (l==size || x_ferror(stream)) {
371 return 0;
372 }
373 *s = 0;
374 return s0;
375}
376
377/**
378 * trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
379 * set then an error is returned */
380off_t x_tseek(XFILE *f, off_t offset, int whence)
381{
382 if (f->flags & X_FLAG_ERROR)
383 return -1;
384
385 /* only SEEK_SET and SEEK_END are supported */
386 /* SEEK_CUR needs internal offset counter */
387 if (whence != SEEK_SET && whence != SEEK_END) {
388 f->flags |= X_FLAG_EINVAL;
389 errno = EINVAL;
390 return -1;
391 }
392
393 /* empty the buffer */
394 switch (f->open_flags & O_ACCMODE) {
395 case O_RDONLY:
396 f->bufused = 0;
397 break;
398 case O_WRONLY:
399 if (x_fflush(f) != 0)
400 return -1;
401 break;
402 default:
403 errno = EINVAL;
404 return -1;
405 }
406
407 f->flags &= ~X_FLAG_EOF;
408 return lseek(f->fd, offset, whence);
409}
410
411XFILE *x_fdup(const XFILE *f)
412{
413 XFILE *ret;
414 int fd;
415
416 fd = dup(x_fileno(f));
417 if (fd < 0) {
418 return NULL;
419 }
420
421 ret = (XFILE *)malloc_p(XFILE);
422 if (!ret) {
423 close(fd);
424 return NULL;
425 }
426 memset(ret, 0, sizeof(XFILE));
427
428 ret->fd = fd;
429 ret->open_flags = f->open_flags;
430 x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
431 return ret;
432}
Note: See TracBrowser for help on using the repository browser.