xref: /third_party/eudev/src/shared/fileio.c (revision 99ca880a)
1/***
2  This file is part of eudev, forked from systemd.
3
4  Copyright 2010 Lennart Poettering
5
6  systemd is free software; you can redistribute it and/or modify it
7  under the terms of the GNU Lesser General Public License as published by
8  the Free Software Foundation; either version 2.1 of the License, or
9  (at your option) any later version.
10
11  systemd is distributed in the hope that it will be useful, but
12  WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Lesser General Public License for more details.
15
16  You should have received a copy of the GNU Lesser General Public License
17  along with systemd; If not, see <http://www.gnu.org/licenses/>.
18***/
19
20#include <unistd.h>
21#include <sys/sendfile.h>
22#include "fileio.h"
23#include "util.h"
24#include "strv.h"
25#include "utf8.h"
26#include "ctype.h"
27
28int write_string_stream(FILE *f, const char *line) {
29        assert(f);
30        assert(line);
31
32        errno = 0;
33
34        fputs(line, f);
35        if (!endswith(line, "\n"))
36                fputc('\n', f);
37
38        fflush(f);
39
40        if (ferror(f))
41                return errno ? -errno : -EIO;
42
43        return 0;
44}
45
46int write_string_file(const char *fn, const char *line) {
47        _cleanup_fclose_ FILE *f = NULL;
48
49        assert(fn);
50        assert(line);
51
52        f = fopen(fn, "we");
53        if (!f)
54                return -errno;
55
56        return write_string_stream(f, line);
57}
58int read_one_line_file(const char *fn, char **line) {
59        _cleanup_fclose_ FILE *f = NULL;
60        char t[LINE_MAX], *c;
61
62        assert(fn);
63        assert(line);
64
65        f = fopen(fn, "re");
66        if (!f)
67                return -errno;
68
69        if (!fgets(t, sizeof(t), f)) {
70
71                if (ferror(f))
72                        return errno ? -errno : -EIO;
73
74                t[0] = 0;
75        }
76
77        c = strdup(t);
78        if (!c)
79                return -ENOMEM;
80        truncate_nl(c);
81
82        *line = c;
83        return 0;
84}
85
86int read_full_stream(FILE *f, char **contents, size_t *size) {
87        size_t n, l;
88        _cleanup_free_ char *buf = NULL;
89        struct stat st;
90
91        assert(f);
92        assert(contents);
93
94        if (fstat(fileno(f), &st) < 0)
95                return -errno;
96
97        n = LINE_MAX;
98
99        if (S_ISREG(st.st_mode)) {
100
101                /* Safety check */
102                if (st.st_size > 4*1024*1024)
103                        return -E2BIG;
104
105                /* Start with the right file size, but be prepared for
106                 * files from /proc which generally report a file size
107                 * of 0 */
108                if (st.st_size > 0)
109                        n = st.st_size;
110        }
111
112        l = 0;
113        for (;;) {
114                char *t;
115                size_t k;
116
117                t = realloc(buf, n+1);
118                if (!t)
119                        return -ENOMEM;
120
121                buf = t;
122                k = fread(buf + l, 1, n - l, f);
123
124                if (k <= 0) {
125                        if (ferror(f))
126                                return -errno;
127
128                        break;
129                }
130
131                l += k;
132                n *= 2;
133
134                /* Safety check */
135                if (n > 4*1024*1024)
136                        return -E2BIG;
137        }
138
139        buf[l] = 0;
140        *contents = buf;
141        buf = NULL; /* do not free */
142
143        if (size)
144                *size = l;
145
146        return 0;
147}
148
149int read_full_file(const char *fn, char **contents, size_t *size) {
150        _cleanup_fclose_ FILE *f = NULL;
151
152        assert(fn);
153        assert(contents);
154
155        f = fopen(fn, "re");
156        if (!f)
157                return -errno;
158
159        return read_full_stream(f, contents, size);
160}
161