source: branches/samba-3.0/source/lib/xfile.c@ 165

Last change on this file since 165 was 134, checked in by Paul Smedley, 17 years ago

Update source to 3.0.29

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