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