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