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/** 36read a line from a file with possible \ continuation chars. 37Blanks at the start or end of a line are stripped. 38The string will be allocated if s2 is NULL 39**/ 40_PUBLIC_ char *fgets_slash(char *s2,int maxlen,XFILE *f) 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) 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/** 165load 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) 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/** 196load a file into memory 197**/ 198_PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx) 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/** 217mmap (if possible) or read a file 218**/ 219_PUBLIC_ void *map_file(const char *fname, size_t size) 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 255bool unmap_file(void *start, size_t size) 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/** 272parse a buffer into lines 273'p' will be freed on error, and otherwise will be made a child of the returned array 274**/ 275char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx) 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/** 318load a file into memory and return an array of pointers to lines in the file 319must be freed with talloc_free(). 320**/ 321_PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx) 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/** 333load a fd into memory and return an array of pointers to lines in the file 334must be freed with talloc_free(). If convert is true calls unix_to_dos on 335the list. 336**/ 337_PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx) 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/** 350take a list of lines and modify them to produce a list where \ continues 351a line 352**/ 353_PUBLIC_ void file_lines_slashcont(char **lines) 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) 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 close(fd); 384 return false; 385 } 386 close(fd); 387 return true; 388} 389 390_PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap) 391{ 392 char *p; 393 int len, ret; 394 va_list ap2; 395 396 va_copy(ap2, ap); 397 len = vasprintf(&p, format, ap2); 398 va_end(ap2); 399 if (len <= 0) return len; 400 ret = write(fd, p, len); 401 SAFE_FREE(p); 402 return ret; 403} 404 405_PUBLIC_ int fdprintf(int fd, const char *format, ...) 406{ 407 va_list ap; 408 int ret; 409 410 va_start(ap, format); 411 ret = vfdprintf(fd, format, ap); 412 va_end(ap); 413 return ret; 414} 415 416 417/* 418 try to determine if the filesystem supports large files 419*/ 420_PUBLIC_ bool large_file_support(const char *path) 421{ 422 int fd; 423 ssize_t ret; 424 char c; 425 426 fd = open(path, O_RDWR|O_CREAT, 0600); 427 unlink(path); 428 if (fd == -1) { 429 /* have to assume large files are OK */ 430 return true; 431 } 432 ret = pread(fd, &c, 1, ((uint64_t)1)<<32); 433 close(fd); 434 return ret == 0; 435} 436 437 438