root/lib/util/xfile.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. x_setvbuf
  2. x_allocate_buffer
  3. x_fopen
  4. x_fclose
  5. x_fwrite
  6. x_vfprintf
  7. x_fprintf
  8. x_fileno
  9. x_fflush
  10. x_setbuffer
  11. x_setbuf
  12. x_setlinebuf
  13. x_feof
  14. x_ferror
  15. x_fillbuf
  16. x_fgetc
  17. x_fread
  18. x_fgets
  19. x_tseek
  20. x_fdup

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

/* [<][>][^][v][top][bottom][index][help] */