Branch data Line data Source code
1 : : /* SPDX-License-Identifier: GPL-2.0-only */
2 : : /*
3 : : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : : */
5 : :
6 : : #include "bpfilter/helper.h"
7 : :
8 : : #include <ctype.h>
9 : : #include <errno.h>
10 : : #include <fcntl.h>
11 : : #include <libgen.h>
12 : : #include <limits.h>
13 : : #include <stdio.h>
14 : : #include <stdlib.h>
15 : : #include <string.h>
16 : : #include <sys/types.h>
17 : : #include <unistd.h>
18 : :
19 : : #include "bpfilter/logger.h"
20 : :
21 : : #define OPEN_MODE_644 (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
22 : :
23 : : /// FNV-1a 64-bit offset basis (the initial hash value).
24 : : #define _BF_FNV1A_INIT 0xcbf29ce484222325ULL
25 : : /// FNV-1a 64-bit prime.
26 : : #define _BF_FNV1A_PRIME 0x100000001b3ULL
27 : :
28 : 95080 : void closep(int *fd)
29 : : {
30 [ + + ]: 95080 : if (*fd < 0)
31 : : return;
32 : :
33 [ + + ]: 54907 : if (close(*fd))
34 [ + - ]: 2 : bf_warn_r(errno, "failed to close fd %d, assuming file is closed", *fd);
35 : :
36 : 54907 : *fd = -1;
37 : : }
38 : :
39 : 16951 : int bf_strncpy(char *dst, size_t len, const char *src)
40 : : {
41 : : size_t src_len;
42 : : size_t copy_len;
43 : :
44 : : assert(dst);
45 : : assert(src);
46 : : assert(len);
47 : :
48 : 16951 : src_len = strlen(src);
49 : 16951 : copy_len = bf_min(src_len, len - 1);
50 : :
51 : 16951 : memcpy(dst, src, copy_len);
52 : 16951 : dst[copy_len] = '\0';
53 : :
54 [ + + ]: 16951 : return copy_len != src_len ? -E2BIG : 0;
55 : : }
56 : :
57 : 8669 : int bf_realloc(void **ptr, size_t size)
58 : : {
59 : : _cleanup_free_ void *_ptr;
60 : :
61 : : assert(ptr);
62 : :
63 : 8669 : _ptr = realloc(*ptr, size);
64 [ + - ]: 8669 : if (!_ptr)
65 : : return -ENOMEM;
66 : :
67 : 8669 : *ptr = TAKE_PTR(_ptr);
68 : :
69 : 8669 : return 0;
70 : : }
71 : :
72 : 6 : int bf_read_file(const char *path, void **buf, size_t *len)
73 : : {
74 : 6 : _cleanup_close_ int fd = -1;
75 : : _cleanup_free_ void *_buf = NULL;
76 : : size_t _len;
77 : : ssize_t r;
78 : :
79 : : assert(path);
80 : : assert(buf);
81 : : assert(len);
82 : :
83 : 6 : fd = open(path, O_RDONLY);
84 [ + + ]: 6 : if (fd < 0)
85 [ + - ]: 1 : return bf_err_r(errno, "failed to open %s", path);
86 : :
87 : 5 : _len = lseek(fd, 0, SEEK_END);
88 : 5 : lseek(fd, 0, SEEK_SET);
89 : :
90 : 5 : _buf = malloc(_len);
91 [ - + ]: 5 : if (!_buf)
92 [ # # ]: 0 : return bf_err_r(errno, "failed to allocate memory");
93 : :
94 : 5 : r = read(fd, _buf, _len);
95 [ - + ]: 5 : if (r < 0)
96 [ # # ]: 0 : return bf_err_r(errno, "failed to read serialized data");
97 [ - + ]: 5 : if ((size_t)r != _len)
98 [ # # ]: 0 : return bf_err_r(EIO, "can't read full serialized data");
99 : :
100 : 5 : closep(&fd);
101 : :
102 : 5 : *buf = TAKE_PTR(_buf);
103 : 5 : *len = _len;
104 : :
105 : 5 : return 0;
106 : : }
107 : :
108 : 6 : static int _bf_get_tmpfile_fd(const char *base,
109 : : char tmpfile_path[static PATH_MAX])
110 : : {
111 : : _cleanup_free_ char *tmp = NULL;
112 : : size_t path_len;
113 : : char *dir;
114 : : int fd;
115 : :
116 : : /* The dirname call may modify its argument. */
117 : 6 : tmp = strdup(base);
118 [ - + ]: 6 : if (!tmp)
119 [ # # ]: 0 : return bf_err_r(ENOMEM, "could not duplicate path %s", base);
120 : :
121 : 6 : dir = dirname(tmp);
122 : :
123 : 6 : path_len =
124 : 6 : snprintf(tmpfile_path, PATH_MAX, "%s%s", dir, "/bpfilter.tmp.XXXXXX");
125 [ - + ]: 6 : if (path_len >= PATH_MAX)
126 [ # # ]: 0 : return bf_err_r(ENAMETOOLONG, "tmpfile name too long (%lu bytes)",
127 : : path_len);
128 : :
129 : 6 : fd = mkstemp(tmpfile_path);
130 [ - + ]: 6 : if (fd < 0)
131 [ # # ]: 0 : return bf_err_r(errno, "failed to open %s", tmpfile_path);
132 : :
133 : : return fd;
134 : : }
135 : :
136 : 6 : int bf_write_file(const char *path, const void *buf, size_t len)
137 : : {
138 : 6 : _cleanup_close_ int fd = -1;
139 : : ssize_t r;
140 : : int err;
141 : : char tmpfile_path[PATH_MAX];
142 : :
143 : : assert(path);
144 : : assert(buf);
145 : :
146 : 6 : fd = _bf_get_tmpfile_fd(path, tmpfile_path);
147 [ - + ]: 6 : if (fd < 0)
148 [ # # ]: 0 : return bf_err_r(fd, "failed to get temporary file name");
149 : :
150 : 6 : r = write(fd, buf, len);
151 [ - + ]: 6 : if (r < 0)
152 [ # # ]: 0 : return bf_err_r(errno, "failed to write to %s", tmpfile_path);
153 [ - + ]: 6 : if ((size_t)r != len)
154 [ # # ]: 0 : return bf_err_r(EIO, "can't write full data to %s", tmpfile_path);
155 : :
156 : 6 : closep(&fd);
157 : :
158 [ - + ]: 6 : if (rename(tmpfile_path, path) < 0) {
159 : 0 : err = errno;
160 : 0 : unlink(tmpfile_path);
161 [ # # ]: 0 : return bf_err_r(err, "failed to move %s to %s", tmpfile_path, path);
162 : : }
163 : :
164 : : return 0;
165 : : }
166 : :
167 : 1137 : char *bf_ltrim(char *str)
168 : : {
169 : : assert(str);
170 : :
171 [ + + ]: 3067 : while (isspace(*str))
172 : 1930 : str++;
173 : 1137 : return str;
174 : : }
175 : :
176 : 1138 : char *bf_rtrim(char *str)
177 : : {
178 : : assert(str);
179 : :
180 : 1138 : char *back = str + strlen(str);
181 : :
182 [ + + ]: 1138 : if (back == str)
183 : : return str;
184 : :
185 : : do {
186 : 1192 : --back;
187 [ + + + + ]: 1192 : } while (back > str && isspace(*back));
188 : :
189 [ + + + + ]: 1081 : if (back == str && isspace(*back))
190 : 1 : *back = '\0';
191 : : else
192 : 1080 : *(back + 1) = '\0';
193 : :
194 : : return str;
195 : : }
196 : :
197 : 1129 : char *bf_trim(char *str)
198 : : {
199 : : assert(str);
200 : :
201 : 1129 : return bf_rtrim(bf_ltrim(str));
202 : : }
203 : :
204 : 4204 : uint64_t bf_fnv1a_init(void)
205 : : {
206 : 4204 : return _BF_FNV1A_INIT;
207 : : }
208 : :
209 : 4205 : uint64_t bf_fnv1a(const void *data, size_t len, uint64_t hash)
210 : : {
211 : : const uint8_t *bytes;
212 : :
213 : : assert(data);
214 : :
215 : : bytes = data;
216 : :
217 [ + + ]: 29403 : for (size_t i = 0; i < len; ++i) {
218 : 25198 : hash ^= bytes[i];
219 : 25198 : hash *= _BF_FNV1A_PRIME;
220 : : }
221 : :
222 : 4205 : return hash;
223 : : }
|