1bde9fb805ba906c95ca4ec24df9d1dc921994af
[petitboot] / lib / file / file.c
1 /*
2  *  Copyright (C) 2013 Jeremy Kerr <jk@ozlabs.org>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; version 2 of the License.
7  *
8  *  This program is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  *  GNU General Public License for more details.
12  *
13  *  You should have received a copy of the GNU General Public License
14  *  along with this program; if not, write to the Free Software
15  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 #include <fcntl.h>
19 #include <unistd.h>
20 #include <stdlib.h>
21 #include <errno.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24
25 #include <talloc/talloc.h>
26
27 #include "file.h"
28
29 static const int max_file_size = 1024 * 1024;
30
31 int read_file(void *ctx, const char *filename, char **bufp, int *lenp)
32 {
33         struct stat statbuf;
34         int rc, fd, i, len;
35         char *buf;
36
37         fd = open(filename, O_RDONLY);
38         if (fd < 0)
39                 return -1;
40
41         rc = fstat(fd, &statbuf);
42         if (rc < 0)
43                 goto err_close;
44
45         len = statbuf.st_size;
46         if (len > max_file_size)
47                 goto err_close;
48
49         buf = talloc_array(ctx, char, len + 1);
50         if (!buf)
51                 goto err_close;
52
53         for (i = 0; i < len; i += rc) {
54                 rc = read(fd, buf + i, len - i);
55
56                 /* unexpected EOF: trim and return */
57                 if (rc == 0) {
58                         len = i;
59                         break;
60                 }
61
62                 if (rc < 0)
63                         goto err_free;
64
65         }
66
67         buf[len] = '\0';
68
69         close(fd);
70         *bufp = buf;
71         *lenp = len;
72         return 0;
73
74 err_free:
75         talloc_free(buf);
76 err_close:
77         close(fd);
78         return -1;
79 }
80
81 static int write_fd(int fd, char *buf, int len)
82 {
83         int i, rc;
84
85         for (i = 0; i < len; i += rc) {
86                 rc = write(fd, buf + i, len - i);
87                 if (rc < 0 && errno != -EINTR)
88                         return rc;
89         }
90
91         return 0;
92 }
93
94 int replace_file(const char *filename, char *buf, int len)
95 {
96         char *tempfile;
97         mode_t oldmask;
98         int rc, fd;
99
100         tempfile = talloc_asprintf(NULL, "%s.XXXXXX", filename);
101
102         oldmask = umask(0644);
103         fd = mkstemp(tempfile);
104         umask(oldmask);
105         if (fd < 0) {
106                 talloc_free(tempfile);
107                 return fd;
108         }
109
110         rc = write_fd(fd, buf, len);
111         if (rc) {
112                 unlink(tempfile);
113         } else {
114                 rc = rename(tempfile, filename);
115         }
116
117         talloc_free(tempfile);
118
119         fchmod(fd, 0644);
120
121         close(fd);
122         return rc;
123 }