net_rpc: let get_user_tokens() use wbcListUsers()
[Samba.git] / source / lib / xfile.c
blobee6e5813329bb5e53221ec7101a70eafa66f48d7
1 /*
2 Unix SMB/CIFS implementation.
3 stdio replacement
4 Copyright (C) Andrew Tridgell 2001
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.
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.
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/>.
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.
24 XFILE replaces stdio. It is less efficient, but at least it works
25 when you have lots of files open
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.
31 #include "includes.h"
33 #define XBUFSIZE BUFSIZ
35 static XFILE _x_stdin = { 0, NULL, NULL, XBUFSIZE, 0, O_RDONLY, X_IOFBF, 0 };
36 static XFILE _x_stdout = { 1, NULL, NULL, XBUFSIZE, 0, O_WRONLY, X_IOLBF, 0 };
37 static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
39 XFILE *x_stdin = &_x_stdin;
40 XFILE *x_stdout = &_x_stdout;
41 XFILE *x_stderr = &_x_stderr;
43 #define X_FLAG_EOF 1
44 #define X_FLAG_ERROR 2
45 #define X_FLAG_EINVAL 3
47 /* simulate setvbuf() */
48 int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
50 x_fflush(f);
51 if (f->bufused) return -1;
53 /* on files being read full buffering is the only option */
54 if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
55 mode = X_IOFBF;
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;
66 if (f->buftype == X_IONBF) return 0;
68 /* if buffering then we need some size */
69 if (size == 0) size = XBUFSIZE;
71 f->bufsize = size;
72 f->bufused = 0;
74 return 0;
77 /* allocate the buffer */
78 static int x_allocate_buffer(XFILE *f)
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;
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
93 XFILE *x_fopen(const char *fname, int flags, mode_t mode)
95 XFILE *ret;
97 ret = SMB_MALLOC_P(XFILE);
98 if (!ret) {
99 return NULL;
102 memset(ret, 0, sizeof(XFILE));
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;
112 ret->open_flags = flags;
114 ret->fd = sys_open(fname, flags, mode);
115 if (ret->fd == -1) {
116 SAFE_FREE(ret);
117 return NULL;
120 x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
122 return ret;
125 XFILE *x_fdup(const XFILE *f)
127 XFILE *ret;
128 int fd;
130 fd = dup(x_fileno(f));
131 if (fd < 0) {
132 return NULL;
135 ret = SMB_CALLOC_ARRAY(XFILE, 1);
136 if (!ret) {
137 close(fd);
138 return NULL;
141 ret->fd = fd;
142 ret->open_flags = f->open_flags;
143 x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
144 return ret;
147 /* simulate fclose() */
148 int x_fclose(XFILE *f)
150 int ret;
152 /* make sure we flush any buffered data */
153 x_fflush(f);
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);
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);
168 return ret;
171 /* simulate fwrite() */
172 size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
174 ssize_t ret;
175 size_t total=0;
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;
186 while (total < size*nmemb) {
187 size_t n = f->bufsize - f->bufused;
188 n = MIN(n, (size*nmemb)-total);
190 if (n == 0) {
191 /* it's full, flush it */
192 x_fflush(f);
193 continue;
196 memcpy(f->buf + f->bufused, total+(const char *)p, n);
197 f->bufused += n;
198 total += n;
201 /* when line buffered we need to flush at the last linefeed. This can
202 flush a bit more than necessary, but that is harmless */
203 if (f->buftype == X_IOLBF && f->bufused) {
204 int i;
205 for (i=(size*nmemb)-1; i>=0; i--) {
206 if (*(i+(const char *)p) == '\n') {
207 x_fflush(f);
208 break;
213 return total/size;
216 /* thank goodness for asprintf() */
217 int x_vfprintf(XFILE *f, const char *format, va_list ap)
219 char *p;
220 int len, ret;
221 va_list ap2;
223 VA_COPY(ap2, ap);
225 len = vasprintf(&p, format, ap2);
226 if (len <= 0) {
227 va_end(ap2);
228 return len;
230 ret = x_fwrite(p, 1, len, f);
231 SAFE_FREE(p);
233 va_end(ap2);
235 return ret;
238 int x_fprintf(XFILE *f, const char *format, ...)
240 va_list ap;
241 int ret;
243 va_start(ap, format);
244 ret = x_vfprintf(f, format, ap);
245 va_end(ap);
246 return ret;
249 /* at least fileno() is simple! */
250 int x_fileno(const XFILE *f)
252 return f->fd;
255 /* simulate fflush() */
256 int x_fflush(XFILE *f)
258 int ret;
260 if (f->flags & X_FLAG_ERROR) return -1;
262 if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
263 errno = EINVAL;
264 return -1;
267 if (f->bufused == 0 || !f->buf) return 0;
269 ret = write(f->fd, f->buf, f->bufused);
270 if (ret == -1) return -1;
272 f->bufused -= ret;
273 if (f->bufused > 0) {
274 f->flags |= X_FLAG_ERROR;
275 memmove(f->buf, ret + (char *)f->buf, f->bufused);
276 return -1;
279 return 0;
282 /* simulate setbuffer() */
283 void x_setbuffer(XFILE *f, char *buf, size_t size)
285 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
288 /* simulate setbuf() */
289 void x_setbuf(XFILE *f, char *buf)
291 x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
294 /* simulate setlinebuf() */
295 void x_setlinebuf(XFILE *f)
297 x_setvbuf(f, NULL, X_IOLBF, 0);
301 /* simulate feof() */
302 int x_feof(XFILE *f)
304 if (f->flags & X_FLAG_EOF) return 1;
305 return 0;
308 /* simulate ferror() */
309 int x_ferror(XFILE *f)
311 if (f->flags & X_FLAG_ERROR) return 1;
312 return 0;
315 /* fill the read buffer */
316 static void x_fillbuf(XFILE *f)
318 int n;
320 if (f->bufused) return;
322 if (!f->buf && !x_allocate_buffer(f)) return;
324 n = read(f->fd, f->buf, f->bufsize);
325 if (n <= 0) return;
326 f->bufused = n;
327 f->next = f->buf;
330 /* simulate fgetc() */
331 int x_fgetc(XFILE *f)
333 int ret;
335 if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
337 if (f->bufused == 0) x_fillbuf(f);
339 if (f->bufused == 0) {
340 f->flags |= X_FLAG_EOF;
341 return EOF;
344 ret = *(unsigned char *)(f->next);
345 f->next++;
346 f->bufused--;
347 return ret;
350 /* simulate fread */
351 size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
353 size_t total = 0;
354 while (total < size*nmemb) {
355 int c = x_fgetc(f);
356 if (c == EOF) break;
357 (total+(char *)p)[0] = (char)c;
358 total++;
360 return total/size;
363 /* simulate fgets() */
364 char *x_fgets(char *s, int size, XFILE *stream)
366 char *s0 = s;
367 int l = size;
368 while (l>1) {
369 int c = x_fgetc(stream);
370 if (c == EOF) break;
371 *s++ = (char)c;
372 l--;
373 if (c == '\n') break;
375 if (l==size || x_ferror(stream)) {
376 return 0;
378 *s = 0;
379 return s0;
382 /* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
383 * set then an error is returned */
384 off_t x_tseek(XFILE *f, off_t offset, int whence)
386 if (f->flags & X_FLAG_ERROR)
387 return -1;
389 /* only SEEK_SET and SEEK_END are supported */
390 /* SEEK_CUR needs internal offset counter */
391 if (whence != SEEK_SET && whence != SEEK_END) {
392 f->flags |= X_FLAG_EINVAL;
393 errno = EINVAL;
394 return -1;
397 /* empty the buffer */
398 switch (f->open_flags & O_ACCMODE) {
399 case O_RDONLY:
400 f->bufused = 0;
401 break;
402 case O_WRONLY:
403 if (x_fflush(f) != 0)
404 return -1;
405 break;
406 default:
407 errno = EINVAL;
408 return -1;
411 f->flags &= ~X_FLAG_EOF;
412 return (off_t)sys_lseek(f->fd, offset, whence);