s3:smbd: fix NULL dereference in case of readlink failure
[Samba.git] / lib / util / util_file.c
blob46e67f0a4a6d29e6d06cd280fa2ea36a9149d4bd
1 /*
2 * Unix SMB/CIFS implementation.
3 * SMB parameters and setup
4 * Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
6 * Added afdgets() Jelmer Vernooij 2005
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.
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.
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/>.
22 #include "replace.h"
23 #include "system/shmem.h"
24 #include "system/filesys.h"
25 #include <talloc.h>
26 #include "lib/util/samba_util.h"
27 #include "lib/util/util_file.h"
28 #include "lib/util/sys_popen.h"
29 #include "lib/util/sys_rw.h"
30 #include "lib/util/debug.h"
32 /**
33 * Read one line (data until next newline or eof) and allocate it
35 _PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint)
37 char *data = NULL;
38 ssize_t alloc_size = 0, offset = 0, ret;
39 int p;
41 if (hint <= 0) hint = 0x100;
43 do {
44 alloc_size += hint;
46 data = talloc_realloc(mem_ctx, data, char, alloc_size);
48 if (!data)
49 return NULL;
51 ret = read(fd, data + offset, hint);
53 if (ret == 0) {
54 return NULL;
57 if (ret == -1) {
58 talloc_free(data);
59 return NULL;
62 /* Find newline */
63 for (p = 0; p < ret; p++) {
64 if (data[offset + p] == '\n')
65 break;
68 if (p < ret) {
69 data[offset + p] = '\0';
71 /* Go back to position of newline */
72 lseek(fd, p - ret + 1, SEEK_CUR);
73 return data;
76 offset += ret;
78 } while ((size_t)ret == hint);
80 data[offset] = '\0';
82 return data;
85 char *fgets_slash(TALLOC_CTX *mem_ctx, char *s2, size_t maxlen, FILE *f)
87 char *s = s2;
88 size_t len = 0;
89 int c;
90 bool start_of_line = true;
92 if (feof(f)) {
93 return NULL;
96 if (maxlen < 2) {
97 return NULL;
100 if (s2 == NULL) {
101 maxlen = MIN(maxlen,8);
102 s = talloc_array(mem_ctx, char, maxlen);
105 if (s == NULL) {
106 return NULL;
109 *s = 0;
111 while (len < maxlen-1) {
112 c = getc(f);
113 switch (c)
115 case '\r':
116 break;
117 case '\n':
118 while (len > 0 && s[len-1] == ' ') {
119 s[--len] = 0;
121 if (len > 0 && s[len-1] == '\\') {
122 s[--len] = 0;
123 start_of_line = true;
124 break;
126 return s;
127 case EOF:
128 if (len <= 0 && (s2 == NULL)) {
129 TALLOC_FREE(s);
131 return (len>0) ? s : NULL;
132 case ' ':
133 if (start_of_line) {
134 break;
137 FALL_THROUGH;
138 default:
139 start_of_line = false;
140 s[len++] = c;
141 s[len] = 0;
143 if ((s2 == NULL) && (len > maxlen-3)) {
144 size_t m;
145 char *t;
147 m = maxlen * 2;
148 if (m < maxlen) {
149 DBG_ERR("length overflow\n");
150 TALLOC_FREE(s);
151 return NULL;
153 maxlen = m;
155 t = talloc_realloc(mem_ctx, s, char, maxlen);
156 if (t == NULL) {
157 DBG_ERR("failed to expand buffer!\n");
158 TALLOC_FREE(s);
159 return NULL;
162 s = t;
166 return s;
170 load a file into memory from a fd.
172 _PUBLIC_ char *fd_load(int fd, size_t *psize, size_t maxsize, TALLOC_CTX *mem_ctx)
174 FILE *file;
175 char *p = NULL;
176 size_t size = 0;
177 size_t chunk = 1024;
178 int err;
180 if (maxsize == 0) {
181 maxsize = SIZE_MAX;
184 file = fdopen_keepfd(fd, "r");
185 if (file == NULL) {
186 return NULL;
189 while (size < maxsize) {
190 size_t newbufsize;
191 size_t nread;
193 chunk = MIN(chunk, (maxsize - size));
195 newbufsize = size + (chunk+1); /* chunk+1 can't overflow */
196 if (newbufsize < size) {
197 goto fail; /* overflow */
200 p = talloc_realloc(mem_ctx, p, char, newbufsize);
201 if (p == NULL) {
202 goto fail;
205 nread = fread(p+size, 1, chunk, file);
206 size += nread;
208 if (nread != chunk) {
209 break;
213 err = ferror(file);
214 if (err != 0) {
215 goto fail;
218 p[size] = '\0';
220 if (psize != NULL) {
221 *psize = size;
224 fclose(file);
225 return p;
227 fail:
228 TALLOC_FREE(p);
229 fclose(file);
230 return NULL;
234 load a file into memory
236 _PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx)
238 int fd;
239 char *p;
241 if (!fname || !*fname) return NULL;
243 fd = open(fname,O_RDONLY);
244 if (fd == -1) return NULL;
246 p = fd_load(fd, size, maxsize, mem_ctx);
248 close(fd);
250 return p;
254 parse a buffer into lines
255 'p' will be freed on error, and otherwise will be made a child of the returned array
257 static char **file_lines_parse_internal(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx)
259 unsigned int i;
260 char *s, **ret;
262 if (!p) return NULL;
264 for (s = p, i=0; s < p+size; s++) {
265 if (s[0] == '\n') i++;
268 ret = talloc_zero_array(mem_ctx, char *, i+2);
269 if (!ret) {
270 talloc_free(p);
271 return NULL;
274 talloc_steal(ret, p);
276 ret[0] = p;
277 for (s = p, i=1; s < p+size; s++) {
278 if (s[0] == '\n') {
279 s[0] = 0;
280 ret[i] = s+1;
281 i++;
283 if (s[0] == '\r') s[0] = 0;
286 /* remove any blank lines at the end */
287 while (i > 0 && ret[i-1][0] == 0) {
288 i--;
291 if (numlines) *numlines = i;
293 return ret;
298 load a file into memory and return an array of pointers to lines in the file
299 must be freed with talloc_free().
301 _PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
303 char *p;
304 size_t size;
306 p = file_load(fname, &size, maxsize, mem_ctx);
307 if (!p) return NULL;
309 return file_lines_parse_internal(p, size, numlines, mem_ctx);
313 load a fd into memory and return an array of pointers to lines in the file
314 must be freed with talloc_free(). If convert is true calls unix_to_dos on
315 the list.
317 _PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
319 char *p;
320 size_t size;
322 p = fd_load(fd, &size, maxsize, mem_ctx);
323 if (!p) return NULL;
325 return file_lines_parse_internal(p, size, numlines, mem_ctx);
328 _PUBLIC_ char **file_lines_parse(const char *p_in,
329 size_t size,
330 int *numlines,
331 TALLOC_CTX *mem_ctx)
334 * Copy the incoming string so it can end up
335 * being owned by the returned pointer and
336 * freed when that is.
338 char *p = talloc_strdup(mem_ctx, p_in);
339 if (p == NULL) {
340 return NULL;
342 return file_lines_parse_internal(p, size, numlines, mem_ctx);
345 _PUBLIC_ bool file_save_mode(const char *fname, const void *packet,
346 size_t length, mode_t mode)
348 ssize_t num_written;
349 int fd;
350 fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, mode);
351 if (fd == -1) {
352 return false;
354 num_written = write(fd, packet, length);
355 if (num_written == -1 || (size_t)num_written != length) {
356 close(fd);
357 return false;
359 close(fd);
360 return true;
364 save a lump of data into a file. Mostly used for debugging
366 _PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length)
368 return file_save_mode(fname, packet, length, 0644);
371 _PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap)
373 char *p;
374 int len, ret;
375 va_list ap2;
377 va_copy(ap2, ap);
378 len = vasprintf(&p, format, ap2);
379 va_end(ap2);
380 if (len <= 0) return len;
381 ret = write(fd, p, len);
382 SAFE_FREE(p);
383 return ret;
386 _PUBLIC_ int fdprintf(int fd, const char *format, ...)
388 va_list ap;
389 int ret;
391 va_start(ap, format);
392 ret = vfdprintf(fd, format, ap);
393 va_end(ap);
394 return ret;
399 compare two files, return true if the two files have the same content
401 bool file_compare(const char *path1, const char *path2)
403 FILE *f1 = NULL, *f2 = NULL;
404 uint8_t buf1[1024], buf2[1024];
405 bool ret = false;
407 f1 = fopen(path1, "r");
408 if (f1 == NULL) {
409 goto done;
411 f2 = fopen(path2, "r");
412 if (f2 == NULL) {
413 goto done;
416 while (!feof(f1)) {
417 size_t n1 = fread(buf1, 1, sizeof(buf1), f1);
418 size_t n2 = fread(buf2, 1, sizeof(buf2), f2);
420 if (n1 != n2) {
421 goto done;
423 if (n1 == 0) {
424 ret = (feof(f1) && feof(f2));
425 goto done;
427 if (memcmp(buf1, buf2, n1) != 0) {
428 goto done;
430 if (n1 < sizeof(buf1)) {
431 bool has_error = (ferror(f1) || ferror(f2));
432 if (has_error) {
433 goto done;
437 ret = true;
438 done:
439 if (f2 != NULL) {
440 fclose(f2);
442 if (f1 != NULL) {
443 fclose(f1);
445 return ret;
449 Load from a pipe into memory.
451 char *file_ploadv(char * const argl[], size_t *size)
453 int fd, n;
454 char *p = NULL;
455 char buf[1024];
456 size_t total;
458 fd = sys_popenv(argl);
459 if (fd == -1) {
460 return NULL;
463 total = 0;
465 while ((n = sys_read(fd, buf, sizeof(buf))) > 0) {
466 p = talloc_realloc(NULL, p, char, total + n + 1);
467 if (p == NULL) {
468 DBG_ERR("failed to expand buffer!\n");
469 close(fd);
470 return NULL;
472 memcpy(p+total, buf, n);
473 total += n;
476 if (p != NULL) {
477 p[total] = 0;
481 * FIXME: Perhaps ought to check that the command completed
482 * successfully (returned 0); if not the data may be
483 * truncated.
485 sys_pclose(fd);
487 if (size) {
488 *size = total;
491 return p;
495 * fopen a dup'ed fd. Prevent fclose to close the fd passed in.
497 * Don't use on fd's that have fcntl locks, on error it will close the
498 * dup'ed fd, thus killing your fcntl locks.
500 FILE *fdopen_keepfd(int fd, const char *mode)
502 FILE *f = NULL;
503 int dup_fd;
505 dup_fd = dup(fd);
506 if (dup_fd == -1) {
507 return NULL;
510 f = fdopen(dup_fd, mode);
511 if (f == NULL) {
512 int err = errno;
513 close(dup_fd);
514 errno = err;
515 return NULL;
518 return f;