lib:util: Fix undefined behavior in bitmap.c
[bbaumbach/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/debug.h"
28
29 /**
30  * Read one line (data until next newline or eof) and allocate it
31  */
32 _PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint)
33 {
34         char *data = NULL;
35         ssize_t alloc_size = 0, offset = 0, ret;
36         int p;
37
38         if (hint <= 0) hint = 0x100;
39
40         do {
41                 alloc_size += hint;
42
43                 data = talloc_realloc(mem_ctx, data, char, alloc_size);
44
45                 if (!data)
46                         return NULL;
47
48                 ret = read(fd, data + offset, hint);
49
50                 if (ret == 0) {
51                         return NULL;
52                 }
53
54                 if (ret == -1) {
55                         talloc_free(data);
56                         return NULL;
57                 }
58
59                 /* Find newline */
60                 for (p = 0; p < ret; p++) {
61                         if (data[offset + p] == '\n')
62                                 break;
63                 }
64
65                 if (p < ret) {
66                         data[offset + p] = '\0';
67
68                         /* Go back to position of newline */
69                         lseek(fd, p - ret + 1, SEEK_CUR);
70                         return data;
71                 }
72
73                 offset += ret;
74
75         } while (ret == hint);
76
77         data[offset] = '\0';
78
79         return data;
80 }
81
82 char *fgets_slash(TALLOC_CTX *mem_ctx, char *s2, size_t maxlen, FILE *f)
83 {
84         char *s = s2;
85         size_t len = 0;
86         int c;
87         bool start_of_line = true;
88
89         if (feof(f)) {
90                 return NULL;
91         }
92
93         if (maxlen < 2) {
94                 return NULL;
95         }
96
97         if (s2 == NULL) {
98                 maxlen = MIN(maxlen,8);
99                 s = talloc_array(mem_ctx, char, maxlen);
100         }
101
102         if (s == NULL) {
103                 return NULL;
104         }
105
106         *s = 0;
107
108         while (len < maxlen-1) {
109                 c = getc(f);
110                 switch (c)
111                 {
112                     case '\r':
113                             break;
114                     case '\n':
115                             while (len > 0 && s[len-1] == ' ') {
116                                     s[--len] = 0;
117                             }
118                             if (len > 0 && s[len-1] == '\\') {
119                                     s[--len] = 0;
120                                     start_of_line = true;
121                                     break;
122                             }
123                             return s;
124                     case EOF:
125                             if (len <= 0 && (s2 == NULL)) {
126                                     TALLOC_FREE(s);
127                             }
128                             return (len>0) ? s : NULL;
129                     case ' ':
130                             if (start_of_line) {
131                                     break;
132                             }
133
134                             FALL_THROUGH;
135                     default:
136                             start_of_line = false;
137                             s[len++] = c;
138                             s[len] = 0;
139                 }
140                 if ((s2 == NULL) && (len > maxlen-3)) {
141                         int m;
142                         char *t;
143
144                         m = maxlen * 2;
145                         if (m < maxlen) {
146                                 DBG_ERR("length overflow");
147                                 TALLOC_FREE(s);
148                                 return NULL;
149                         }
150                         maxlen = m;
151
152                         t = talloc_realloc(mem_ctx, s, char, maxlen);
153                         if (t == NULL) {
154                                 DBG_ERR("failed to expand buffer!\n");
155                                 TALLOC_FREE(s);
156                                 return NULL;
157                         }
158
159                         s = t;
160                 }
161         }
162
163         return s;
164 }
165
166 /**
167 load a file into memory from a fd.
168 **/
169 _PUBLIC_ char *fd_load(int fd, size_t *psize, size_t maxsize, TALLOC_CTX *mem_ctx)
170 {
171         struct stat sbuf;
172         char *p;
173         size_t size;
174
175         if (fstat(fd, &sbuf) != 0) return NULL;
176
177         size = sbuf.st_size;
178
179         if (maxsize) {
180                 size = MIN(size, maxsize);
181         }
182
183         p = (char *)talloc_size(mem_ctx, size+1);
184         if (!p) return NULL;
185
186         if (read(fd, p, size) != size) {
187                 talloc_free(p);
188                 return NULL;
189         }
190         p[size] = 0;
191
192         if (psize) *psize = size;
193
194         return p;
195 }
196
197 /**
198 load a file into memory
199 **/
200 _PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx)
201 {
202         int fd;
203         char *p;
204
205         if (!fname || !*fname) return NULL;
206
207         fd = open(fname,O_RDONLY);
208         if (fd == -1) return NULL;
209
210         p = fd_load(fd, size, maxsize, mem_ctx);
211
212         close(fd);
213
214         return p;
215 }
216
217 /**
218 parse a buffer into lines
219 'p' will be freed on error, and otherwise will be made a child of the returned array
220 **/
221 char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx)
222 {
223         int i;
224         char *s, **ret;
225
226         if (!p) return NULL;
227
228         for (s = p, i=0; s < p+size; s++) {
229                 if (s[0] == '\n') i++;
230         }
231
232         ret = talloc_zero_array(mem_ctx, char *, i+2);
233         if (!ret) {
234                 talloc_free(p);
235                 return NULL;
236         }
237
238         talloc_steal(ret, p);
239
240         ret[0] = p;
241         for (s = p, i=0; s < p+size; s++) {
242                 if (s[0] == '\n') {
243                         s[0] = 0;
244                         i++;
245                         ret[i] = s+1;
246                 }
247                 if (s[0] == '\r') s[0] = 0;
248         }
249
250         /* remove any blank lines at the end */
251         while (i > 0 && ret[i-1][0] == 0) {
252                 i--;
253         }
254
255         if (numlines) *numlines = i;
256
257         return ret;
258 }
259
260
261 /**
262 load a file into memory and return an array of pointers to lines in the file
263 must be freed with talloc_free().
264 **/
265 _PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
266 {
267         char *p;
268         size_t size;
269
270         p = file_load(fname, &size, maxsize, mem_ctx);
271         if (!p) return NULL;
272
273         return file_lines_parse(p, size, numlines, mem_ctx);
274 }
275
276 /**
277 load a fd into memory and return an array of pointers to lines in the file
278 must be freed with talloc_free(). If convert is true calls unix_to_dos on
279 the list.
280 **/
281 _PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx)
282 {
283         char *p;
284         size_t size;
285
286         p = fd_load(fd, &size, maxsize, mem_ctx);
287         if (!p) return NULL;
288
289         return file_lines_parse(p, size, numlines, mem_ctx);
290 }
291
292 _PUBLIC_ bool file_save_mode(const char *fname, const void *packet,
293                              size_t length, mode_t mode)
294 {
295         int fd;
296         fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, mode);
297         if (fd == -1) {
298                 return false;
299         }
300         if (write(fd, packet, length) != (size_t)length) {
301                 close(fd);
302                 return false;
303         }
304         close(fd);
305         return true;
306 }
307
308 /**
309   save a lump of data into a file. Mostly used for debugging
310 */
311 _PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length)
312 {
313         return file_save_mode(fname, packet, length, 0644);
314 }
315
316 _PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap)
317 {
318         char *p;
319         int len, ret;
320         va_list ap2;
321
322         va_copy(ap2, ap);
323         len = vasprintf(&p, format, ap2);
324         va_end(ap2);
325         if (len <= 0) return len;
326         ret = write(fd, p, len);
327         SAFE_FREE(p);
328         return ret;
329 }
330
331 _PUBLIC_ int fdprintf(int fd, const char *format, ...)
332 {
333         va_list ap;
334         int ret;
335
336         va_start(ap, format);
337         ret = vfdprintf(fd, format, ap);
338         va_end(ap);
339         return ret;
340 }
341
342
343 /*
344   compare two files, return true if the two files have the same content
345  */
346 bool file_compare(const char *path1, const char *path2)
347 {
348         size_t size1, size2;
349         char *p1, *p2;
350         TALLOC_CTX *mem_ctx = talloc_new(NULL);
351
352         p1 = file_load(path1, &size1, 0, mem_ctx);
353         p2 = file_load(path2, &size2, 0, mem_ctx);
354         if (!p1 || !p2 || size1 != size2) {
355                 talloc_free(mem_ctx);
356                 return false;
357         }
358         if (memcmp(p1, p2, size1) != 0) {
359                 talloc_free(mem_ctx);
360                 return false;
361         }
362         talloc_free(mem_ctx);
363         return true;
364 }