root/lib/util/util_file.c

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

DEFINITIONS

This source file includes following definitions.
  1. fgets_slash
  2. afdgets
  3. fd_load
  4. file_load
  5. map_file
  6. unmap_file
  7. file_lines_parse
  8. file_lines_load
  9. fd_lines_load
  10. file_lines_slashcont
  11. file_save
  12. vfdprintf
  13. fdprintf
  14. large_file_support

   1 /*
   2  * Unix SMB/CIFS implementation.
   3  * SMB parameters and setup
   4  * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
   5  *
   6  * Added afdgets() Jelmer Vernooij 2005
   7  * 
   8  * This program is free software; you can redistribute it and/or modify it under
   9  * the terms of the GNU General Public License as published by the Free
  10  * Software Foundation; either version 3 of the License, or (at your option)
  11  * any later version.
  12  * 
  13  * This program is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  16  * more details.
  17  * 
  18  * You should have received a copy of the GNU General Public License along with
  19  * this program; if not, see <http://www.gnu.org/licenses/>.
  20  */
  21 
  22 #include "includes.h"
  23 #include "system/shmem.h"
  24 #include "system/filesys.h"
  25 #if _SAMBA_BUILD_ == 3
  26 #undef malloc
  27 #undef realloc
  28 #endif
  29 
  30 /**
  31  * @file
  32  * @brief File-related utility functions
  33  */
  34 
  35 /**
  36 read a line from a file with possible \ continuation chars. 
  37 Blanks at the start or end of a line are stripped.
  38 The string will be allocated if s2 is NULL
  39 **/
  40 _PUBLIC_ char *fgets_slash(char *s2,int maxlen,XFILE *f)
     /* [<][>][^][v][top][bottom][index][help] */
  41 {
  42   char *s=s2;
  43   int len = 0;
  44   int c;
  45   bool start_of_line = true;
  46 
  47   if (x_feof(f))
  48     return(NULL);
  49 
  50   if (maxlen <2) return(NULL);
  51 
  52   if (!s2)
  53     {
  54       maxlen = MIN(maxlen,8);
  55       s = (char *)malloc(maxlen);
  56     }
  57 
  58   if (!s) return(NULL);
  59 
  60   *s = 0;
  61 
  62   while (len < maxlen-1)
  63     {
  64       c = x_getc(f);
  65       switch (c)
  66         {
  67         case '\r':
  68           break;
  69         case '\n':
  70           while (len > 0 && s[len-1] == ' ')
  71             {
  72               s[--len] = 0;
  73             }
  74           if (len > 0 && s[len-1] == '\\')
  75             {
  76               s[--len] = 0;
  77               start_of_line = true;
  78               break;
  79             }
  80           return(s);
  81         case EOF:
  82           if (len <= 0 && !s2) 
  83             SAFE_FREE(s);
  84           return(len>0?s:NULL);
  85         case ' ':
  86           if (start_of_line)
  87             break;
  88           /* fall through */
  89         default:
  90           start_of_line = false;
  91           s[len++] = c;
  92           s[len] = 0;
  93         }
  94       if (!s2 && len > maxlen-3)
  95         {
  96           char *t;
  97           
  98           maxlen *= 2;
  99           t = realloc_p(s, char, maxlen);
 100           if (!t) {
 101             DEBUG(0,("fgets_slash: failed to expand buffer!\n"));
 102             SAFE_FREE(s);
 103             return(NULL);
 104           } else s = t;
 105         }
 106     }
 107   return(s);
 108 }
 109 
 110 /**
 111  * Read one line (data until next newline or eof) and allocate it 
 112  */
 113 _PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint)
     /* [<][>][^][v][top][bottom][index][help] */
 114 {
 115         char *data = NULL;
 116         ssize_t alloc_size = 0, offset = 0, ret;
 117         int p;
 118 
 119         if (hint <= 0) hint = 0x100;
 120 
 121         do {
 122                 alloc_size += hint;
 123 
 124                 data = talloc_realloc(mem_ctx, data, char, alloc_size);
 125 
 126                 if (!data)
 127                         return NULL;
 128 
 129                 ret = read(fd, data + offset, hint);
 130 
 131                 if (ret == 0) {
 132                         return NULL;
 133                 }
 134 
 135                 if (ret == -1) {
 136                         talloc_free(data);
 137                         return NULL;
 138                 }
 139 
 140                 /* Find newline */
 141                 for (p = 0; p < ret; p++) {
 142                         if (data[offset + p] == '\n')
 143                                 break;
 144                 }
 145 
 146                 if (p < ret) {
 147                         data[offset + p] = '\0';
 148 
 149                         /* Go back to position of newline */
 150                         lseek(fd, p - ret + 1, SEEK_CUR);
 151                         return data;
 152                 }
 153 
 154                 offset += ret;
 155 
 156         } while (ret == hint);
 157 
 158         data[offset] = '\0';
 159 
 160         return data;
 161 }
 162 
 163 
 164 /**
 165 load a file into memory from a fd.
 166 **/
 167 _PUBLIC_ char *fd_load(int fd, size_t *psize, size_t maxsize, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 168 {
 169         struct stat sbuf;
 170         char *p;
 171         size_t size;
 172 
 173         if (fstat(fd, &sbuf) != 0) return NULL;
 174 
 175         size = sbuf.st_size;
 176 
 177         if (maxsize) {
 178                 size = MIN(size, maxsize);
 179         }
 180 
 181         p = (char *)talloc_size(mem_ctx, size+1);
 182         if (!p) return NULL;
 183 
 184         if (read(fd, p, size) != size) {
 185                 talloc_free(p);
 186                 return NULL;
 187         }
 188         p[size] = 0;
 189 
 190         if (psize) *psize = size;
 191 
 192         return p;
 193 }
 194 
 195 /**
 196 load a file into memory
 197 **/
 198 _PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 199 {
 200         int fd;
 201         char *p;
 202 
 203         if (!fname || !*fname) return NULL;
 204         
 205         fd = open(fname,O_RDONLY);
 206         if (fd == -1) return NULL;
 207 
 208         p = fd_load(fd, size, maxsize, mem_ctx);
 209 
 210         close(fd);
 211 
 212         return p;
 213 }
 214 
 215 
 216 /**
 217 mmap (if possible) or read a file
 218 **/
 219 _PUBLIC_ void *map_file(const char *fname, size_t size)
     /* [<][>][^][v][top][bottom][index][help] */
 220 {
 221         size_t s2 = 0;
 222         void *p = NULL;
 223 #ifdef HAVE_MMAP
 224         int fd;
 225         fd = open(fname, O_RDONLY, 0);
 226         if (fd == -1) {
 227                 DEBUG(2,("Failed to load %s - %s\n", fname, strerror(errno)));
 228                 return NULL;
 229         }
 230         p = mmap(NULL, size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
 231         close(fd);
 232         if (p == MAP_FAILED) {
 233                 DEBUG(1,("Failed to mmap %s - %s\n", fname, strerror(errno)));
 234                 return NULL;
 235         }
 236 #endif
 237         if (!p) {
 238                 p = file_load(fname, &s2, 0, talloc_autofree_context());
 239                 if (!p) return NULL;
 240                 if (s2 != size) {
 241                         DEBUG(1,("incorrect size for %s - got %d expected %d\n",
 242                                  fname, (int)s2, (int)size));
 243                         talloc_free(p);
 244                         return NULL;
 245                 }
 246         }
 247 
 248         return p;
 249 }
 250 
 251 /**
 252  unmap or free memory
 253 **/
 254 
 255 bool unmap_file(void *start, size_t size)
     /* [<][>][^][v][top][bottom][index][help] */
 256 {
 257 #ifdef HAVE_MMAP
 258         if (munmap( start, size ) != 0) {
 259                 DEBUG( 1, ("map_file: Failed to unmap address %p "
 260                         "of size %u - %s\n", 
 261                         start, (unsigned int)size, strerror(errno) ));
 262                 return false;
 263         }
 264         return true;
 265 #else
 266         talloc_free(start);
 267         return true;
 268 #endif
 269 }
 270 
 271 /**
 272 parse a buffer into lines
 273 'p' will be freed on error, and otherwise will be made a child of the returned array
 274 **/
 275 char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 276 {
 277         int i;
 278         char *s, **ret;
 279 
 280         if (!p) return NULL;
 281 
 282         for (s = p, i=0; s < p+size; s++) {
 283                 if (s[0] == '\n') i++;
 284         }
 285 
 286         ret = talloc_array(mem_ctx, char *, i+2);
 287         if (!ret) {
 288                 talloc_free(p);
 289                 return NULL;
 290         }       
 291         
 292         talloc_steal(ret, p);
 293         
 294         memset(ret, 0, sizeof(ret[0])*(i+2));
 295 
 296         ret[0] = p;
 297         for (s = p, i=0; s < p+size; s++) {
 298                 if (s[0] == '\n') {
 299                         s[0] = 0;
 300                         i++;
 301                         ret[i] = s+1;
 302                 }
 303                 if (s[0] == '\r') s[0] = 0;
 304         }
 305 
 306         /* remove any blank lines at the end */
 307         while (i > 0 && ret[i-1][0] == 0) {
 308                 i--;
 309         }
 310 
 311         if (numlines) *numlines = i;
 312 
 313         return ret;
 314 }
 315 
 316 
 317 /**
 318 load a file into memory and return an array of pointers to lines in the file
 319 must be freed with talloc_free(). 
 320 **/
 321 _PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 322 {
 323         char *p;
 324         size_t size;
 325 
 326         p = file_load(fname, &size, maxsize, mem_ctx);
 327         if (!p) return NULL;
 328 
 329         return file_lines_parse(p, size, numlines, mem_ctx);
 330 }
 331 
 332 /**
 333 load a fd into memory and return an array of pointers to lines in the file
 334 must be freed with talloc_free(). If convert is true calls unix_to_dos on
 335 the list.
 336 **/
 337 _PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 338 {
 339         char *p;
 340         size_t size;
 341 
 342         p = fd_load(fd, &size, maxsize, mem_ctx);
 343         if (!p) return NULL;
 344 
 345         return file_lines_parse(p, size, numlines, mem_ctx);
 346 }
 347 
 348 
 349 /**
 350 take a list of lines and modify them to produce a list where \ continues
 351 a line
 352 **/
 353 _PUBLIC_ void file_lines_slashcont(char **lines)
     /* [<][>][^][v][top][bottom][index][help] */
 354 {
 355         int i, j;
 356 
 357         for (i=0; lines[i];) {
 358                 int len = strlen(lines[i]);
 359                 if (lines[i][len-1] == '\\') {
 360                         lines[i][len-1] = ' ';
 361                         if (lines[i+1]) {
 362                                 char *p = &lines[i][len];
 363                                 while (p < lines[i+1]) *p++ = ' ';
 364                                 for (j = i+1; lines[j]; j++) lines[j] = lines[j+1];
 365                         }
 366                 } else {
 367                         i++;
 368                 }
 369         }
 370 }
 371 
 372 /**
 373   save a lump of data into a file. Mostly used for debugging 
 374 */
 375 _PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length)
     /* [<][>][^][v][top][bottom][index][help] */
 376 {
 377         int fd;
 378         fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
 379         if (fd == -1) {
 380                 return false;
 381         }
 382         if (write(fd, packet, length) != (size_t)length) {
 383                 return false;
 384         }
 385         close(fd);
 386         return true;
 387 }
 388 
 389 _PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap)
     /* [<][>][^][v][top][bottom][index][help] */
 390 {
 391         char *p;
 392         int len, ret;
 393         va_list ap2;
 394 
 395         va_copy(ap2, ap);
 396         len = vasprintf(&p, format, ap2);
 397         va_end(ap2);
 398         if (len <= 0) return len;
 399         ret = write(fd, p, len);
 400         SAFE_FREE(p);
 401         return ret;
 402 }
 403 
 404 _PUBLIC_ int fdprintf(int fd, const char *format, ...)
     /* [<][>][^][v][top][bottom][index][help] */
 405 {
 406         va_list ap;
 407         int ret;
 408 
 409         va_start(ap, format);
 410         ret = vfdprintf(fd, format, ap);
 411         va_end(ap);
 412         return ret;
 413 }
 414 
 415 
 416 /*
 417   try to determine if the filesystem supports large files
 418 */
 419 _PUBLIC_ bool large_file_support(const char *path)
     /* [<][>][^][v][top][bottom][index][help] */
 420 {
 421         int fd;
 422         ssize_t ret;
 423         char c;
 424 
 425         fd = open(path, O_RDWR|O_CREAT, 0600);
 426         unlink(path);
 427         if (fd == -1) {
 428                 /* have to assume large files are OK */
 429                 return true;
 430         }
 431         ret = pread(fd, &c, 1, ((uint64_t)1)<<32);
 432         close(fd);
 433         return ret == 0;
 434 }
 435 
 436 

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