221d5a49fdb85d9579a2252fc5646dd9690fc163
[samba.git] / lib / util / util_file.c
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 "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"
31
32 /**
33  * Read one line (data until next newline or eof) and allocate it
34  */
35 _PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint)
36 {
37         char *data = NULL;
38         ssize_t alloc_size = 0, offset = 0, ret;
39         int p;
40
41         if (hint <= 0) hint = 0x100;
42
43         do {
44                 alloc_size += hint;
45
46                 data = talloc_realloc(mem_ctx, data, char, alloc_size);
47
48                 if (!data)
49                         return NULL;
50
51                 ret = read(fd, data + offset, hint);
52
53                 if (ret == 0) {
54                         return NULL;
55                 }
56
57                 if (ret == -1) {
58                         talloc_free(data);
59                         return NULL;
60                 }
61
62                 /* Find newline */
63                 for (p = 0; p < ret; p++) {
64                         if (data[offset + p] == '\n')
65                                 break;
66                 }
67
68                 if (p < ret) {
69                         data[offset + p] = '\0';
70
71                         /* Go back to position of newline */
72                         lseek(fd, p - ret + 1, SEEK_CUR);
73                         return data;
74                 }
75
76                 offset += ret;
77
78         } while ((size_t)ret == hint);
79
80         data[offset] = '\0';
81
82         return data;
83 }
84
85 char *fgets_slash(TALLOC_CTX *mem_ctx, char *s2, size_t maxlen, FILE *f)
86 {
87         char *s = s2;
88         size_t len = 0;
89         int c;
90         bool start_of_line = true;
91
92         if (feof(f)) {
93                 return NULL;
94         }
95
96         if (maxlen < 2) {
97                 return NULL;
98         }
99
100         if (s2 == NULL) {
101                 maxlen = MIN(maxlen,8);
102                 s = talloc_array(mem_ctx, char, maxlen);
103         }
104
105         if (s == NULL) {
106                 return NULL;
107         }
108
109         *s = 0;
110
111         while (len < maxlen-1) {
112                 c = getc(f);
113                 switch (c)
114                 {
115                     case '\r':
116                             break;
117                     case '\n':
118                             while (len > 0 && s[len-1] == ' ') {
119                                     s[--len] = 0;
120                             }
121                             if (len > 0 && s[len-1] == '\\') {
122                                     s[--len] = 0;
123                                     start_of_line = true;
124                                     break;
125                             }
126                             return s;
127                     case EOF:
128                             if (len <= 0 && (s2 == NULL)) {
129                                     TALLOC_FREE(s);
130                             }
131                             return (len>0) ? s : NULL;
132                     case ' ':
133                             if (start_of_line) {
134                                     break;
135                             }
136
137                             FALL_THROUGH;
138                     default:
139                             start_of_line = false;
140                             s[len++] = c;
141                             s[len] = 0;
142                 }
143                 if ((s2 == NULL) && (len > maxlen-3)) {
144                         size_t m;
145                         char *t;
146
147                         m = maxlen * 2;
148                         if (m < maxlen) {
149                                 DBG_ERR("length overflow\n");
150                                 TALLOC_FREE(s);
151                                 return NULL;
152                         }
153                         maxlen = m;
154
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;
160                         }
161
162                         s = t;
163                 }
164         }
165
166         return s;
167 }
168
169 /**
170 load a file into memory from a fd.
171 **/
172 _PUBLIC_ char *fd_load(int fd, size_t *psize, size_t maxsize, TALLOC_CTX *mem_ctx)
173 {
174         FILE *file;
175         char *p = NULL;
176         size_t size = 0;
177         size_t chunk = 1024;
178         int err;
179         int fd_dup;
180
181         if (maxsize == 0) {
182                 maxsize = SIZE_MAX;
183         }
184
185         fd_dup = dup(fd);
186         if (fd_dup == -1) {
187                 return NULL;
188         }
189
190         file = fdopen(fd_dup, "r");
191         if (file == NULL) {
192                 close(fd_dup);
193                 return NULL;
194         }
195
196         while (size < maxsize) {
197                 size_t newbufsize;
198                 size_t nread;
199
200                 chunk = MIN(chunk, (maxsize - size));
201
202                 newbufsize = size + (chunk+1); /* chunk+1 can't overflow */
203                 if (newbufsize < size) {
204                         goto fail; /* overflow */
205                 }
206
207                 p = talloc_realloc(mem_ctx, p, char, newbufsize);
208                 if (p == NULL) {
209                         goto fail;
210                 }
211
212                 nread = fread(p+size, 1, chunk, file);
213                 size += nread;
214
215                 if (nread != chunk) {
216                         break;
217                 }
218         }
219
220         err = ferror(file);
221         if (err != 0) {
222                 goto fail;
223         }
224
225         p[size] = '\0';
226
227         if (psize != NULL) {
228                 *psize = size;
229         }
230
231         fclose(file);
232         return p;
233
234 fail:
235         TALLOC_FREE(p);
236         fclose(file);
237         return NULL;
238 }
239
240 /**
241 load a file into memory
242 **/
243 _PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx)
244 {
245         int fd;
246         char *p;
247
248         if (!fname || !*fname) return NULL;
249
250         fd = open(fname,O_RDONLY);
251         if (fd == -1) return NULL;
252
253         p = fd_load(fd, size, maxsize, mem_ctx);
254
255         close(fd);
256
257         return p;
258 }
259
260 /**
261 parse a buffer into lines
262 'p' will be freed on error, and otherwise will be made a child of the returned array
263 **/
264 static char **file_lines_parse_internal(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx)
265 {
266         unsigned int i;
267         char *s, **ret;
268
269         if (!p) return NULL;
270
271         for (s = p, i=0; s < p+size; s++) {
272                 if (s[0] == '\n') i++;
273         }
274
275         ret = talloc_zero_array(mem_ctx, char *, i+2);
276         if (!ret) {
277                 talloc_free(p);
278                 return NULL;
279         }
280
281         talloc_steal(ret, p);
282
283         ret[0] = p;
284         for (s = p, i=1; s < p+size; s++) {
285                 if (s[0] == '\n') {
286                         s[0] = 0;
287                         ret[i] = s+1;
288                         i++;
289                 }
290                 if (s[0] == '\r') s[0] = 0;
291         }
292
293         /* remove any blank lines at the end */
294         while (i > 0 && ret[i-1][0] == 0) {
295                 i--;
296         }
297
298         if (numlines) *numlines = i;
299
300         return ret;
301 }
302
303
304 /**
305 load a file into memory and return an array of pointers to lines in the file
306 must be freed with talloc_free().
307 **/
308 _PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
309 {
310         char *p;
311         size_t size;
312
313         p = file_load(fname, &size, maxsize, mem_ctx);
314         if (!p) return NULL;
315
316         return file_lines_parse_internal(p, size, numlines, mem_ctx);
317 }
318
319 /**
320 load a fd into memory and return an array of pointers to lines in the file
321 must be freed with talloc_free(). If convert is true calls unix_to_dos on
322 the list.
323 **/
324 _PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
325 {
326         char *p;
327         size_t size;
328
329         p = fd_load(fd, &size, maxsize, mem_ctx);
330         if (!p) return NULL;
331
332         return file_lines_parse_internal(p, size, numlines, mem_ctx);
333 }
334
335 _PUBLIC_ char **file_lines_parse(const char *p_in,
336                         size_t size,
337                         int *numlines,
338                         TALLOC_CTX *mem_ctx)
339 {
340         /*
341          * Copy the incoming string so it can end up
342          * being owned by the returned pointer and
343          * freed when that is.
344          */
345         char *p = talloc_strdup(mem_ctx, p_in);
346         if (p == NULL) {
347                 return NULL;
348         }
349         return file_lines_parse_internal(p, size, numlines, mem_ctx);
350 }
351
352 _PUBLIC_ bool file_save_mode(const char *fname, const void *packet,
353                              size_t length, mode_t mode)
354 {
355         ssize_t num_written;
356         int fd;
357         fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, mode);
358         if (fd == -1) {
359                 return false;
360         }
361         num_written = write(fd, packet, length);
362         if (num_written == -1 || (size_t)num_written != length) {
363                 close(fd);
364                 return false;
365         }
366         close(fd);
367         return true;
368 }
369
370 /**
371   save a lump of data into a file. Mostly used for debugging
372 */
373 _PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length)
374 {
375         return file_save_mode(fname, packet, length, 0644);
376 }
377
378 _PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap)
379 {
380         char *p;
381         int len, ret;
382         va_list ap2;
383
384         va_copy(ap2, ap);
385         len = vasprintf(&p, format, ap2);
386         va_end(ap2);
387         if (len <= 0) return len;
388         ret = write(fd, p, len);
389         SAFE_FREE(p);
390         return ret;
391 }
392
393 _PUBLIC_ int fdprintf(int fd, const char *format, ...)
394 {
395         va_list ap;
396         int ret;
397
398         va_start(ap, format);
399         ret = vfdprintf(fd, format, ap);
400         va_end(ap);
401         return ret;
402 }
403
404
405 /*
406   compare two files, return true if the two files have the same content
407  */
408 bool file_compare(const char *path1, const char *path2)
409 {
410         FILE *f1 = NULL, *f2 = NULL;
411         uint8_t buf1[1024], buf2[1024];
412         bool ret = false;
413
414         f1 = fopen(path1, "r");
415         if (f1 == NULL) {
416                 goto done;
417         }
418         f2 = fopen(path2, "r");
419         if (f2 == NULL) {
420                 goto done;
421         }
422
423         while (!feof(f1)) {
424                 size_t n1 = fread(buf1, 1, sizeof(buf1), f1);
425                 size_t n2 = fread(buf2, 1, sizeof(buf2), f2);
426
427                 if (n1 != n2) {
428                         goto done;
429                 }
430                 if (n1 == 0) {
431                         ret = (feof(f1) && feof(f2));
432                         goto done;
433                 }
434                 if (memcmp(buf1, buf2, n1) != 0) {
435                         goto done;
436                 }
437                 if (n1 < sizeof(buf1)) {
438                         bool has_error = (ferror(f1) || ferror(f2));
439                         if (has_error) {
440                                 goto done;
441                         }
442                 }
443         }
444         ret = true;
445 done:
446         if (f2 != NULL) {
447                 fclose(f2);
448         }
449         if (f1 != NULL) {
450                 fclose(f1);
451         }
452         return ret;
453 }
454
455 /**
456  Load from a pipe into memory.
457 **/
458 char *file_ploadv(char * const argl[], size_t *size)
459 {
460         int fd, n;
461         char *p = NULL;
462         char buf[1024];
463         size_t total;
464
465         fd = sys_popenv(argl);
466         if (fd == -1) {
467                 return NULL;
468         }
469
470         total = 0;
471
472         while ((n = sys_read(fd, buf, sizeof(buf))) > 0) {
473                 p = talloc_realloc(NULL, p, char, total + n + 1);
474                 if (p == NULL) {
475                         DBG_ERR("failed to expand buffer!\n");
476                         close(fd);
477                         return NULL;
478                 }
479                 memcpy(p+total, buf, n);
480                 total += n;
481         }
482
483         if (p != NULL) {
484                 p[total] = 0;
485         }
486
487         /*
488          * FIXME: Perhaps ought to check that the command completed
489          * successfully (returned 0); if not the data may be
490          * truncated.
491          */
492         sys_pclose(fd);
493
494         if (size) {
495                 *size = total;
496         }
497
498         return p;
499 }