lib/xfile.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    stdio replacement
00004    Copyright (C) Andrew Tridgell 2001
00005    
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License as published by
00008    the Free Software Foundation; either version 2 of the License, or
00009    (at your option) any later version.
00010    
00011    This program is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014    GNU General Public License for more details.
00015    
00016    You should have received a copy of the GNU General Public License
00017    along with this program; if not, write to the Free Software
00018    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019 */
00020 
00021 /*
00022   stdio is very convenient, but on some systems the file descriptor
00023   in FILE* is 8 bits, so it fails when more than 255 files are open. 
00024 
00025   XFILE replaces stdio. It is less efficient, but at least it works
00026   when you have lots of files open
00027 
00028   The main restriction on XFILE is that it doesn't support seeking,
00029   and doesn't support O_RDWR. That keeps the code simple.
00030 */
00031 
00032 #include "includes.h"
00033 
00034 #define XBUFSIZE BUFSIZ
00035 
00036 static XFILE _x_stdin =  { 0, NULL, NULL, XBUFSIZE, 0, O_RDONLY, X_IOFBF, 0 };
00037 static XFILE _x_stdout = { 1, NULL, NULL, XBUFSIZE, 0, O_WRONLY, X_IOLBF, 0 };
00038 static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
00039 
00040 XFILE *x_stdin = &_x_stdin;
00041 XFILE *x_stdout = &_x_stdout;
00042 XFILE *x_stderr = &_x_stderr;
00043 
00044 #define X_FLAG_EOF 1
00045 #define X_FLAG_ERROR 2
00046 #define X_FLAG_EINVAL 3
00047 
00048 /* simulate setvbuf() */
00049 int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
00050 {
00051         if (x_fflush(f) != 0) return -1;
00052         if (f->bufused) return -1;
00053 
00054         /* on files being read full buffering is the only option */
00055         if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
00056                 mode = X_IOFBF;
00057         }
00058 
00059         /* destroy any earlier buffer */
00060         SAFE_FREE(f->buf);
00061         f->buf = 0;
00062         f->bufsize = 0;
00063         f->next = NULL;
00064         f->bufused = 0;
00065         f->buftype = mode;
00066 
00067         if (f->buftype == X_IONBF) return 0;
00068 
00069         /* if buffering then we need some size */
00070         if (size == 0) size = XBUFSIZE;
00071 
00072         f->bufsize = size;
00073         f->bufused = 0;
00074 
00075         return 0;
00076 }
00077 
00078 /* allocate the buffer */
00079 static int x_allocate_buffer(XFILE *f)
00080 {
00081         if (f->buf) return 1;
00082         if (f->bufsize == 0) return 0;
00083         f->buf = (char *)SMB_MALLOC(f->bufsize);
00084         if (!f->buf) return 0;
00085         f->next = f->buf;
00086         return 1;
00087 }
00088 
00089 
00090 /* this looks more like open() than fopen(), but that is quite deliberate.
00091    I want programmers to *think* about O_EXCL, O_CREAT etc not just
00092    get them magically added 
00093 */
00094 XFILE *x_fopen(const char *fname, int flags, mode_t mode)
00095 {
00096         XFILE *ret;
00097 
00098         ret = SMB_MALLOC_P(XFILE);
00099         if (!ret) {
00100                 return NULL;
00101         }
00102 
00103         memset(ret, 0, sizeof(XFILE));
00104 
00105         if ((flags & O_ACCMODE) == O_RDWR) {
00106                 /* we don't support RDWR in XFILE - use file 
00107                    descriptors instead */
00108                 SAFE_FREE(ret);
00109                 errno = EINVAL;
00110                 return NULL;
00111         }
00112 
00113         ret->open_flags = flags;
00114 
00115         ret->fd = sys_open(fname, flags, mode);
00116         if (ret->fd == -1) {
00117                 SAFE_FREE(ret);
00118                 return NULL;
00119         }
00120 
00121         x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
00122         
00123         return ret;
00124 }
00125 
00126 XFILE *x_fdup(const XFILE *f)
00127 {
00128         XFILE *ret;
00129         int fd;
00130 
00131         fd = dup(x_fileno(f));
00132         if (fd < 0) {
00133                 return NULL;
00134         }
00135 
00136         ret = SMB_CALLOC_ARRAY(XFILE, 1);
00137         if (!ret) {
00138                 close(fd);
00139                 return NULL;
00140         }
00141 
00142         ret->fd = fd;
00143         ret->open_flags = f->open_flags;
00144         x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
00145         return ret;
00146 }
00147 
00148 /* simulate fclose() */
00149 int x_fclose(XFILE *f)
00150 {
00151         int ret;
00152 
00153         /* make sure we flush any buffered data */
00154         (void)x_fflush(f);
00155 
00156         ret = close(f->fd);
00157         f->fd = -1;
00158         if (f->buf) {
00159                 /* make sure data can't leak into a later malloc */
00160                 memset(f->buf, 0, f->bufsize);
00161                 SAFE_FREE(f->buf);
00162         }
00163         /* check the file descriptor given to the function is NOT one of the static
00164          * descriptor of this libreary or we will free unallocated memory
00165          * --sss */
00166         if (f != x_stdin && f != x_stdout && f != x_stderr) {
00167                 SAFE_FREE(f);
00168         }
00169         return ret;
00170 }
00171 
00172 /* simulate fwrite() */
00173 size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
00174 {
00175         ssize_t ret;
00176         size_t total=0;
00177 
00178         /* we might be writing unbuffered */
00179         if (f->buftype == X_IONBF || 
00180             (!f->buf && !x_allocate_buffer(f))) {
00181                 ret = write(f->fd, p, size*nmemb);
00182                 if (ret == -1) return -1;
00183                 return ret/size;
00184         } 
00185 
00186 
00187         while (total < size*nmemb) {
00188                 size_t n = f->bufsize - f->bufused;
00189                 n = MIN(n, (size*nmemb)-total);
00190 
00191                 if (n == 0) {
00192                         /* it's full, flush it */
00193                         if (x_fflush(f) != 0) {
00194                                 return -1;
00195                         }
00196                         continue;
00197                 }
00198 
00199                 memcpy(f->buf + f->bufused, total+(const char *)p, n);
00200                 f->bufused += n;
00201                 total += n;
00202         }
00203 
00204         /* when line buffered we need to flush at the last linefeed. This can
00205            flush a bit more than necessary, but that is harmless */
00206         if (f->buftype == X_IOLBF && f->bufused) {
00207                 int i;
00208                 for (i=(size*nmemb)-1; i>=0; i--) {
00209                         if (*(i+(const char *)p) == '\n') {
00210                                 if (x_fflush(f) != 0) {
00211                                         return -1;
00212                                 }
00213                                 break;
00214                         }
00215                 }
00216         }
00217 
00218         return total/size;
00219 }
00220 
00221 /* thank goodness for asprintf() */
00222  int x_vfprintf(XFILE *f, const char *format, va_list ap)
00223 {
00224         char *p;
00225         int len, ret;
00226         va_list ap2;
00227 
00228         VA_COPY(ap2, ap);
00229 
00230         len = vasprintf(&p, format, ap2);
00231         if (len <= 0) return len;
00232         ret = x_fwrite(p, 1, len, f);
00233         SAFE_FREE(p);
00234         return ret;
00235 }
00236 
00237  int x_fprintf(XFILE *f, const char *format, ...)
00238 {
00239         va_list ap;
00240         int ret;
00241 
00242         va_start(ap, format);
00243         ret = x_vfprintf(f, format, ap);
00244         va_end(ap);
00245         return ret;
00246 }
00247 
00248 /* at least fileno() is simple! */
00249 int x_fileno(const XFILE *f)
00250 {
00251         return f->fd;
00252 }
00253 
00254 /* simulate fflush() */
00255 int x_fflush(XFILE *f)
00256 {
00257         int ret;
00258 
00259         if (f->flags & X_FLAG_ERROR) return -1;
00260 
00261         if (f->bufused == 0 || !f->buf) return 0;
00262 
00263         if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
00264                 errno = EINVAL;
00265                 return -1;
00266         }
00267 
00268         ret = write(f->fd, f->buf, f->bufused);
00269         if (ret == -1) return -1;
00270         
00271         f->bufused -= ret;
00272         if (f->bufused > 0) {
00273                 f->flags |= X_FLAG_ERROR;
00274                 memmove(f->buf, ret + (char *)f->buf, f->bufused);
00275                 return -1;
00276         }
00277 
00278         return 0;
00279 }
00280 
00281 /* simulate setbuffer() */
00282 void x_setbuffer(XFILE *f, char *buf, size_t size)
00283 {
00284         x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
00285 }
00286 
00287 /* simulate setbuf() */
00288 void x_setbuf(XFILE *f, char *buf)
00289 {
00290         x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
00291 }
00292 
00293 /* simulate setlinebuf() */
00294 void x_setlinebuf(XFILE *f)
00295 {
00296         x_setvbuf(f, NULL, X_IOLBF, 0);
00297 }
00298 
00299 
00300 /* simulate feof() */
00301 int x_feof(XFILE *f)
00302 {
00303         if (f->flags & X_FLAG_EOF) return 1;
00304         return 0;
00305 }
00306 
00307 /* simulate ferror() */
00308 int x_ferror(XFILE *f)
00309 {
00310         if (f->flags & X_FLAG_ERROR) return 1;
00311         return 0;
00312 }
00313 
00314 /* fill the read buffer */
00315 static void x_fillbuf(XFILE *f)
00316 {
00317         int n;
00318 
00319         if (f->bufused) return;
00320 
00321         if (!f->buf && !x_allocate_buffer(f)) return;
00322 
00323         n = read(f->fd, f->buf, f->bufsize);
00324         if (n <= 0) return;
00325         f->bufused = n;
00326         f->next = f->buf;
00327 }
00328 
00329 /* simulate fgetc() */
00330 int x_fgetc(XFILE *f)
00331 {
00332         int ret;
00333 
00334         if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
00335         
00336         if (f->bufused == 0) x_fillbuf(f);
00337 
00338         if (f->bufused == 0) {
00339                 f->flags |= X_FLAG_EOF;
00340                 return EOF;
00341         }
00342 
00343         ret = *(unsigned char *)(f->next);
00344         f->next++;
00345         f->bufused--;
00346         return ret;
00347 }
00348 
00349 /* simulate fread */
00350 size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
00351 {
00352         size_t total = 0;
00353         while (total < size*nmemb) {
00354                 int c = x_fgetc(f);
00355                 if (c == EOF) break;
00356                 (total+(char *)p)[0] = (char)c;
00357                 total++;
00358         }
00359         return total/size;
00360 }
00361 
00362 /* simulate fgets() */
00363 char *x_fgets(char *s, int size, XFILE *stream) 
00364 {
00365         char *s0 = s;
00366         int l = size;
00367         while (l>1) {
00368                 int c = x_fgetc(stream);
00369                 if (c == EOF) break;
00370                 *s++ = (char)c;
00371                 l--;
00372                 if (c == '\n') break;
00373         }
00374         if (l==size || x_ferror(stream)) {
00375                 return 0;
00376         }
00377         *s = 0;
00378         return s0;
00379 }
00380 
00381 /* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
00382  * set then an error is returned */
00383 off_t x_tseek(XFILE *f, off_t offset, int whence)
00384 {
00385         if (f->flags & X_FLAG_ERROR)
00386                 return -1;
00387 
00388         /* only SEEK_SET and SEEK_END are supported */
00389         /* SEEK_CUR needs internal offset counter */
00390         if (whence != SEEK_SET && whence != SEEK_END) {
00391                 f->flags |= X_FLAG_EINVAL;
00392                 errno = EINVAL;
00393                 return -1;
00394         }
00395 
00396         /* empty the buffer */
00397         switch (f->open_flags & O_ACCMODE) {
00398         case O_RDONLY:
00399                 f->bufused = 0;
00400                 break;
00401         case O_WRONLY:
00402                 if (x_fflush(f) != 0)
00403                         return -1;
00404                 break;
00405         default:
00406                 errno = EINVAL;
00407                 return -1;
00408         }
00409 
00410         f->flags &= ~X_FLAG_EOF;
00411         return (off_t)sys_lseek(f->fd, offset, whence);
00412 }

Sambaに対してSat Aug 29 21:23:00 2009に生成されました。  doxygen 1.4.7