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

Last change on this file since 105 was 1, checked in by Paul Smedley, 18 years ago

Initial code import

File size: 8.0 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 x_fflush(f);
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 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 x_fflush(f);
194 continue;
195 }
196
197 memcpy(f->buf + f->bufused, total+(const char *)p, n);
198 f->bufused += n;
199 total += n;
200 }
201
202 /* when line buffered we need to flush at the last linefeed. This can
203 flush a bit more than necessary, but that is harmless */
204 if (f->buftype == X_IOLBF && f->bufused) {
205 int i;
206 for (i=(size*nmemb)-1; i>=0; i--) {
207 if (*(i+(const char *)p) == '\n') {
208 x_fflush(f);
209 break;
210 }
211 }
212 }
213
214 return total/size;
215}
216
217/* thank goodness for asprintf() */
218 int x_vfprintf(XFILE *f, const char *format, va_list ap)
219{
220 char *p;
221 int len, ret;
222 va_list ap2;
223
224 VA_COPY(ap2, ap);
225
226 len = vasprintf(&p, format, ap2);
227 if (len <= 0) return len;
228 ret = x_fwrite(p, 1, len, f);
229 SAFE_FREE(p);
230 return ret;
231}
232
233 int x_fprintf(XFILE *f, const char *format, ...)
234{
235 va_list ap;
236 int ret;
237
238 va_start(ap, format);
239 ret = x_vfprintf(f, format, ap);
240 va_end(ap);
241 return ret;
242}
243
244/* at least fileno() is simple! */
245int x_fileno(const XFILE *f)
246{
247 return f->fd;
248}
249
250/* simulate fflush() */
251int x_fflush(XFILE *f)
252{
253 int ret;
254
255 if (f->flags & X_FLAG_ERROR) return -1;
256
257 if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
258 errno = EINVAL;
259 return -1;
260 }
261
262 if (f->bufused == 0 || !f->buf) return 0;
263
264 ret = write(f->fd, f->buf, f->bufused);
265 if (ret == -1) return -1;
266
267 f->bufused -= ret;
268 if (f->bufused > 0) {
269 f->flags |= X_FLAG_ERROR;
270 memmove(f->buf, ret + (char *)f->buf, f->bufused);
271 return -1;
272 }
273
274 return 0;
275}
276
277/* simulate setbuffer() */
278void x_setbuffer(XFILE *f, char *buf, size_t size)
279{
280 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
281}
282
283/* simulate setbuf() */
284void x_setbuf(XFILE *f, char *buf)
285{
286 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
287}
288
289/* simulate setlinebuf() */
290void x_setlinebuf(XFILE *f)
291{
292 x_setvbuf(f, NULL, X_IOLBF, 0);
293}
294
295
296/* simulate feof() */
297int x_feof(XFILE *f)
298{
299 if (f->flags & X_FLAG_EOF) return 1;
300 return 0;
301}
302
303/* simulate ferror() */
304int x_ferror(XFILE *f)
305{
306 if (f->flags & X_FLAG_ERROR) return 1;
307 return 0;
308}
309
310/* fill the read buffer */
311static void x_fillbuf(XFILE *f)
312{
313 int n;
314
315 if (f->bufused) return;
316
317 if (!f->buf && !x_allocate_buffer(f)) return;
318
319 n = read(f->fd, f->buf, f->bufsize);
320 if (n <= 0) return;
321 f->bufused = n;
322 f->next = f->buf;
323}
324
325/* simulate fgetc() */
326int x_fgetc(XFILE *f)
327{
328 int ret;
329
330 if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
331
332 if (f->bufused == 0) x_fillbuf(f);
333
334 if (f->bufused == 0) {
335 f->flags |= X_FLAG_EOF;
336 return EOF;
337 }
338
339 ret = *(unsigned char *)(f->next);
340 f->next++;
341 f->bufused--;
342 return ret;
343}
344
345/* simulate fread */
346size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
347{
348 size_t total = 0;
349 while (total < size*nmemb) {
350 int c = x_fgetc(f);
351 if (c == EOF) break;
352 (total+(char *)p)[0] = (char)c;
353 total++;
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/* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
378 * set then an error is returned */
379off_t x_tseek(XFILE *f, off_t offset, int whence)
380{
381 if (f->flags & X_FLAG_ERROR)
382 return -1;
383
384 /* only SEEK_SET and SEEK_END are supported */
385 /* SEEK_CUR needs internal offset counter */
386 if (whence != SEEK_SET && whence != SEEK_END) {
387 f->flags |= X_FLAG_EINVAL;
388 errno = EINVAL;
389 return -1;
390 }
391
392 /* empty the buffer */
393 switch (f->open_flags & O_ACCMODE) {
394 case O_RDONLY:
395 f->bufused = 0;
396 break;
397 case O_WRONLY:
398 if (x_fflush(f) != 0)
399 return -1;
400 break;
401 default:
402 errno = EINVAL;
403 return -1;
404 }
405
406 f->flags &= ~X_FLAG_EOF;
407 return (off_t)sys_lseek(f->fd, offset, whence);
408}
Note: See TracBrowser for help on using the repository browser.