]> git.ozlabs.org Git - ccan/blob - ccan/tal/grab_file/grab_file.c
tal/grab_file: be robust against EINTR.
[ccan] / ccan / tal / grab_file / grab_file.c
1 /* Licensed under LGPLv2+ - see LICENSE file for details */
2 #include "grab_file.h"
3 #include <ccan/tal/tal.h>
4 #include <ccan/noerr/noerr.h>
5 #include <unistd.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <errno.h>
9 #include <fcntl.h>
10
11 void *grab_fd(const void *ctx, int fd)
12 {
13         int ret;
14         size_t max, size;
15         char *buffer;
16         struct stat st;
17
18         size = 0;
19
20         if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode))
21                 max = st.st_size;
22         else
23                 max = 16384;
24
25         buffer = tal_arr(ctx, char, max+1);
26         while ((ret = read(fd, buffer + size, max - size)) != 0) {
27                 if (ret < 0) {
28                         if (errno == EINTR)
29                                 continue;
30                         return tal_free(buffer);
31                 }
32                 size += ret;
33                 if (size == max) {
34                         size_t extra = max;
35                         if (extra > 1024 * 1024)
36                                 extra = 1024 * 1024;
37
38                         if (!tal_resize(&buffer, max+extra+1))
39                                 return NULL;
40
41                         max += extra;
42                 }
43         }
44         buffer[size] = '\0';
45         tal_resize(&buffer, size+1);
46
47         return buffer;
48 }
49
50 void *grab_file(const void *ctx, const char *filename)
51 {
52         int fd;
53         char *buffer;
54
55         if (!filename)
56                 fd = dup(STDIN_FILENO);
57         else
58                 fd = open(filename, O_RDONLY, 0);
59
60         if (fd < 0)
61                 return NULL;
62
63         buffer = grab_fd(ctx, fd);
64         close_noerr(fd);
65         return buffer;
66 }