source: branches/samba-3.3.x/source/lib/xfile.c@ 206

Last change on this file since 206 was 206, checked in by Herwig Bauernfeind, 16 years ago

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

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