source: vendor/current/lib/util/xfile.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

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