Line | Count | Source |
1 | | /* |
2 | | * Various trivial helper wrappers around standard functions |
3 | | */ |
4 | | |
5 | | #define DISABLE_SIGN_COMPARE_WARNINGS |
6 | | |
7 | | #include "git-compat-util.h" |
8 | | #include "abspath.h" |
9 | | #include "parse.h" |
10 | | #include "gettext.h" |
11 | | #include "strbuf.h" |
12 | | #include "trace2.h" |
13 | | |
14 | | #ifdef HAVE_RTLGENRANDOM |
15 | | /* This is required to get access to RtlGenRandom. */ |
16 | | #define SystemFunction036 NTAPI SystemFunction036 |
17 | | #include <ntsecapi.h> |
18 | | #undef SystemFunction036 |
19 | | #endif |
20 | | |
21 | | static int memory_limit_check(size_t size, int gentle) |
22 | 6.72k | { |
23 | 6.72k | static size_t limit = 0; |
24 | 6.72k | if (!limit) { |
25 | 1 | limit = git_env_ulong("GIT_ALLOC_LIMIT", 0); |
26 | 1 | if (!limit) |
27 | 1 | limit = SIZE_MAX; |
28 | 1 | } |
29 | 6.72k | if (size > limit) { |
30 | 0 | if (gentle) { |
31 | 0 | error("attempting to allocate %"PRIuMAX" over limit %"PRIuMAX, |
32 | 0 | (uintmax_t)size, (uintmax_t)limit); |
33 | 0 | return -1; |
34 | 0 | } else |
35 | 0 | die("attempting to allocate %"PRIuMAX" over limit %"PRIuMAX, |
36 | 0 | (uintmax_t)size, (uintmax_t)limit); |
37 | 0 | } |
38 | 6.72k | return 0; |
39 | 6.72k | } |
40 | | |
41 | | char *xstrdup(const char *str) |
42 | 0 | { |
43 | 0 | char *ret = strdup(str); |
44 | 0 | if (!ret) |
45 | 0 | die("Out of memory, strdup failed"); |
46 | 0 | return ret; |
47 | 0 | } |
48 | | |
49 | | static void *do_xmalloc(size_t size, int gentle) |
50 | 6.69k | { |
51 | 6.69k | void *ret; |
52 | | |
53 | 6.69k | if (memory_limit_check(size, gentle)) |
54 | 0 | return NULL; |
55 | 6.69k | ret = malloc(size); |
56 | 6.69k | if (!ret && !size) |
57 | 0 | ret = malloc(1); |
58 | 6.69k | if (!ret) { |
59 | 0 | if (!gentle) |
60 | 0 | die("Out of memory, malloc failed (tried to allocate %lu bytes)", |
61 | 0 | (unsigned long)size); |
62 | 0 | else { |
63 | 0 | error("Out of memory, malloc failed (tried to allocate %lu bytes)", |
64 | 0 | (unsigned long)size); |
65 | 0 | return NULL; |
66 | 0 | } |
67 | 0 | } |
68 | | #ifdef XMALLOC_POISON |
69 | | memset(ret, 0xA5, size); |
70 | | #endif |
71 | 6.69k | return ret; |
72 | 6.69k | } |
73 | | |
74 | | void *xmalloc(size_t size) |
75 | 0 | { |
76 | 0 | return do_xmalloc(size, 0); |
77 | 0 | } |
78 | | |
79 | | static void *do_xmallocz(size_t size, int gentle) |
80 | 6.69k | { |
81 | 6.69k | void *ret; |
82 | 6.69k | if (unsigned_add_overflows(size, 1)) { |
83 | 0 | if (gentle) { |
84 | 0 | error("Data too large to fit into virtual memory space."); |
85 | 0 | return NULL; |
86 | 0 | } else |
87 | 0 | die("Data too large to fit into virtual memory space."); |
88 | 0 | } |
89 | 6.69k | ret = do_xmalloc(size + 1, gentle); |
90 | 6.69k | if (ret) |
91 | 6.69k | ((char*)ret)[size] = 0; |
92 | 6.69k | return ret; |
93 | 6.69k | } |
94 | | |
95 | | void *xmallocz(size_t size) |
96 | 6.69k | { |
97 | 6.69k | return do_xmallocz(size, 0); |
98 | 6.69k | } |
99 | | |
100 | | void *xmallocz_gently(size_t size) |
101 | 0 | { |
102 | 0 | return do_xmallocz(size, 1); |
103 | 0 | } |
104 | | |
105 | | /* |
106 | | * xmemdupz() allocates (len + 1) bytes of memory, duplicates "len" bytes of |
107 | | * "data" to the allocated memory, zero terminates the allocated memory, |
108 | | * and returns a pointer to the allocated memory. If the allocation fails, |
109 | | * the program dies. |
110 | | */ |
111 | | void *xmemdupz(const void *data, size_t len) |
112 | 6.69k | { |
113 | 6.69k | return memcpy(xmallocz(len), data, len); |
114 | 6.69k | } |
115 | | |
116 | | char *xstrndup(const char *str, size_t len) |
117 | 0 | { |
118 | 0 | const char *p = memchr(str, '\0', len); |
119 | 0 | return xmemdupz(str, p ? p - str : len); |
120 | 0 | } |
121 | | |
122 | | int xstrncmpz(const char *s, const char *t, size_t len) |
123 | 0 | { |
124 | 0 | int res = strncmp(s, t, len); |
125 | 0 | if (res) |
126 | 0 | return res; |
127 | 0 | return s[len] == '\0' ? 0 : 1; |
128 | 0 | } |
129 | | |
130 | | void *xrealloc(void *ptr, size_t size) |
131 | 31 | { |
132 | 31 | void *ret; |
133 | | |
134 | 31 | if (!size) { |
135 | 0 | free(ptr); |
136 | 0 | return xmalloc(0); |
137 | 0 | } |
138 | | |
139 | 31 | memory_limit_check(size, 0); |
140 | 31 | ret = realloc(ptr, size); |
141 | 31 | if (!ret) |
142 | 0 | die("Out of memory, realloc failed"); |
143 | 31 | return ret; |
144 | 31 | } |
145 | | |
146 | | void *xcalloc(size_t nmemb, size_t size) |
147 | 0 | { |
148 | 0 | void *ret; |
149 | |
|
150 | 0 | if (unsigned_mult_overflows(nmemb, size)) |
151 | 0 | die("data too large to fit into virtual memory space"); |
152 | | |
153 | 0 | memory_limit_check(size * nmemb, 0); |
154 | 0 | ret = calloc(nmemb, size); |
155 | 0 | if (!ret && (!nmemb || !size)) |
156 | 0 | ret = calloc(1, 1); |
157 | 0 | if (!ret) |
158 | 0 | die("Out of memory, calloc failed"); |
159 | 0 | return ret; |
160 | 0 | } |
161 | | |
162 | | void xsetenv(const char *name, const char *value, int overwrite) |
163 | 0 | { |
164 | 0 | if (setenv(name, value, overwrite)) |
165 | 0 | die_errno(_("could not setenv '%s'"), name ? name : "(null)"); |
166 | 0 | } |
167 | | |
168 | | /** |
169 | | * xopen() is the same as open(), but it die()s if the open() fails. |
170 | | */ |
171 | | int xopen(const char *path, int oflag, ...) |
172 | 0 | { |
173 | 0 | mode_t mode = 0; |
174 | 0 | va_list ap; |
175 | | |
176 | | /* |
177 | | * va_arg() will have undefined behavior if the specified type is not |
178 | | * compatible with the argument type. Since integers are promoted to |
179 | | * ints, we fetch the next argument as an int, and then cast it to a |
180 | | * mode_t to avoid undefined behavior. |
181 | | */ |
182 | 0 | va_start(ap, oflag); |
183 | 0 | if (oflag & O_CREAT) |
184 | 0 | mode = va_arg(ap, int); |
185 | 0 | va_end(ap); |
186 | |
|
187 | 0 | for (;;) { |
188 | 0 | int fd = open(path, oflag, mode); |
189 | 0 | if (fd >= 0) |
190 | 0 | return fd; |
191 | 0 | if (errno == EINTR) |
192 | 0 | continue; |
193 | | |
194 | 0 | if ((oflag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) |
195 | 0 | die_errno(_("unable to create '%s'"), path); |
196 | 0 | else if ((oflag & O_RDWR) == O_RDWR) |
197 | 0 | die_errno(_("could not open '%s' for reading and writing"), path); |
198 | 0 | else if ((oflag & O_WRONLY) == O_WRONLY) |
199 | 0 | die_errno(_("could not open '%s' for writing"), path); |
200 | 0 | else |
201 | 0 | die_errno(_("could not open '%s' for reading"), path); |
202 | 0 | } |
203 | 0 | } |
204 | | |
205 | | static int handle_nonblock(int fd, short poll_events, int err) |
206 | 0 | { |
207 | 0 | struct pollfd pfd; |
208 | |
|
209 | 0 | if (err != EAGAIN && err != EWOULDBLOCK) |
210 | 0 | return 0; |
211 | | |
212 | 0 | pfd.fd = fd; |
213 | 0 | pfd.events = poll_events; |
214 | | |
215 | | /* |
216 | | * no need to check for errors, here; |
217 | | * a subsequent read/write will detect unrecoverable errors |
218 | | */ |
219 | 0 | poll(&pfd, 1, -1); |
220 | 0 | return 1; |
221 | 0 | } |
222 | | |
223 | | /* |
224 | | * xread() is the same a read(), but it automatically restarts read() |
225 | | * operations with a recoverable error (EAGAIN and EINTR). xread() |
226 | | * DOES NOT GUARANTEE that "len" bytes is read even if the data is available. |
227 | | */ |
228 | | ssize_t xread(int fd, void *buf, size_t len) |
229 | 0 | { |
230 | 0 | ssize_t nr; |
231 | 0 | if (len > MAX_IO_SIZE) |
232 | 0 | len = MAX_IO_SIZE; |
233 | 0 | while (1) { |
234 | 0 | nr = read(fd, buf, len); |
235 | 0 | if (nr < 0) { |
236 | 0 | if (errno == EINTR) |
237 | 0 | continue; |
238 | 0 | if (handle_nonblock(fd, POLLIN, errno)) |
239 | 0 | continue; |
240 | 0 | } |
241 | 0 | return nr; |
242 | 0 | } |
243 | 0 | } |
244 | | |
245 | | /* |
246 | | * xwrite() is the same a write(), but it automatically restarts write() |
247 | | * operations with a recoverable error (EAGAIN and EINTR). xwrite() DOES NOT |
248 | | * GUARANTEE that "len" bytes is written even if the operation is successful. |
249 | | */ |
250 | | ssize_t xwrite(int fd, const void *buf, size_t len) |
251 | 0 | { |
252 | 0 | ssize_t nr; |
253 | 0 | if (len > MAX_IO_SIZE) |
254 | 0 | len = MAX_IO_SIZE; |
255 | 0 | while (1) { |
256 | 0 | nr = write(fd, buf, len); |
257 | 0 | if (nr < 0) { |
258 | 0 | if (errno == EINTR) |
259 | 0 | continue; |
260 | 0 | if (handle_nonblock(fd, POLLOUT, errno)) |
261 | 0 | continue; |
262 | 0 | } |
263 | | |
264 | 0 | return nr; |
265 | 0 | } |
266 | 0 | } |
267 | | |
268 | | /* |
269 | | * xpread() is the same as pread(), but it automatically restarts pread() |
270 | | * operations with a recoverable error (EAGAIN and EINTR). xpread() DOES |
271 | | * NOT GUARANTEE that "len" bytes is read even if the data is available. |
272 | | */ |
273 | | ssize_t xpread(int fd, void *buf, size_t len, off_t offset) |
274 | 0 | { |
275 | 0 | ssize_t nr; |
276 | 0 | if (len > MAX_IO_SIZE) |
277 | 0 | len = MAX_IO_SIZE; |
278 | 0 | while (1) { |
279 | 0 | nr = pread(fd, buf, len, offset); |
280 | 0 | if ((nr < 0) && (errno == EAGAIN || errno == EINTR)) |
281 | 0 | continue; |
282 | 0 | return nr; |
283 | 0 | } |
284 | 0 | } |
285 | | |
286 | | ssize_t read_in_full(int fd, void *buf, size_t count) |
287 | 0 | { |
288 | 0 | char *p = buf; |
289 | 0 | ssize_t total = 0; |
290 | |
|
291 | 0 | while (count > 0) { |
292 | 0 | ssize_t loaded = xread(fd, p, count); |
293 | 0 | if (loaded < 0) |
294 | 0 | return -1; |
295 | 0 | if (loaded == 0) |
296 | 0 | return total; |
297 | 0 | count -= loaded; |
298 | 0 | p += loaded; |
299 | 0 | total += loaded; |
300 | 0 | } |
301 | | |
302 | 0 | return total; |
303 | 0 | } |
304 | | |
305 | | ssize_t write_in_full(int fd, const void *buf, size_t count) |
306 | 0 | { |
307 | 0 | const char *p = buf; |
308 | 0 | ssize_t total = 0; |
309 | |
|
310 | 0 | while (count > 0) { |
311 | 0 | ssize_t written = xwrite(fd, p, count); |
312 | 0 | if (written < 0) |
313 | 0 | return -1; |
314 | 0 | if (!written) { |
315 | 0 | errno = ENOSPC; |
316 | 0 | return -1; |
317 | 0 | } |
318 | 0 | count -= written; |
319 | 0 | p += written; |
320 | 0 | total += written; |
321 | 0 | } |
322 | | |
323 | 0 | return total; |
324 | 0 | } |
325 | | |
326 | | ssize_t writev_in_full(int fd, struct iovec *iov, int iovcnt) |
327 | 0 | { |
328 | 0 | ssize_t total_written = 0; |
329 | |
|
330 | 0 | while (iovcnt) { |
331 | 0 | ssize_t bytes_written = writev(fd, iov, iovcnt); |
332 | 0 | if (bytes_written < 0) { |
333 | 0 | if (errno == EINTR || errno == EAGAIN) |
334 | 0 | continue; |
335 | 0 | return -1; |
336 | 0 | } |
337 | 0 | if (!bytes_written) { |
338 | 0 | errno = ENOSPC; |
339 | 0 | return -1; |
340 | 0 | } |
341 | | |
342 | 0 | total_written += bytes_written; |
343 | | |
344 | | /* |
345 | | * We first need to discard any iovec entities that have been |
346 | | * fully written. |
347 | | */ |
348 | 0 | while (iovcnt && (size_t)bytes_written >= iov->iov_len) { |
349 | 0 | bytes_written -= iov->iov_len; |
350 | 0 | iov++; |
351 | 0 | iovcnt--; |
352 | 0 | } |
353 | | |
354 | | /* |
355 | | * Finally, we need to adjust the last iovec in case we have |
356 | | * performed a partial write. |
357 | | */ |
358 | 0 | if (iovcnt && bytes_written) { |
359 | 0 | iov->iov_base = (char *) iov->iov_base + bytes_written; |
360 | 0 | iov->iov_len -= bytes_written; |
361 | 0 | } |
362 | 0 | } |
363 | | |
364 | 0 | return total_written; |
365 | 0 | } |
366 | | |
367 | | ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset) |
368 | 0 | { |
369 | 0 | char *p = buf; |
370 | 0 | ssize_t total = 0; |
371 | |
|
372 | 0 | while (count > 0) { |
373 | 0 | ssize_t loaded = xpread(fd, p, count, offset); |
374 | 0 | if (loaded < 0) |
375 | 0 | return -1; |
376 | 0 | if (loaded == 0) |
377 | 0 | return total; |
378 | 0 | count -= loaded; |
379 | 0 | p += loaded; |
380 | 0 | total += loaded; |
381 | 0 | offset += loaded; |
382 | 0 | } |
383 | | |
384 | 0 | return total; |
385 | 0 | } |
386 | | |
387 | | int xdup(int fd) |
388 | 0 | { |
389 | 0 | int ret = dup(fd); |
390 | 0 | if (ret < 0) |
391 | 0 | die_errno("dup failed"); |
392 | 0 | return ret; |
393 | 0 | } |
394 | | |
395 | | /** |
396 | | * xfopen() is the same as fopen(), but it die()s if the fopen() fails. |
397 | | */ |
398 | | FILE *xfopen(const char *path, const char *mode) |
399 | 0 | { |
400 | 0 | for (;;) { |
401 | 0 | FILE *fp = fopen(path, mode); |
402 | 0 | if (fp) |
403 | 0 | return fp; |
404 | 0 | if (errno == EINTR) |
405 | 0 | continue; |
406 | | |
407 | 0 | if (*mode && mode[1] == '+') |
408 | 0 | die_errno(_("could not open '%s' for reading and writing"), path); |
409 | 0 | else if (*mode == 'w' || *mode == 'a') |
410 | 0 | die_errno(_("could not open '%s' for writing"), path); |
411 | 0 | else |
412 | 0 | die_errno(_("could not open '%s' for reading"), path); |
413 | 0 | } |
414 | 0 | } |
415 | | |
416 | | FILE *xfdopen(int fd, const char *mode) |
417 | 0 | { |
418 | 0 | FILE *stream = fdopen(fd, mode); |
419 | 0 | if (!stream) |
420 | 0 | die_errno("Out of memory? fdopen failed"); |
421 | 0 | return stream; |
422 | 0 | } |
423 | | |
424 | | FILE *fopen_for_writing(const char *path) |
425 | 0 | { |
426 | 0 | FILE *ret = fopen(path, "w"); |
427 | |
|
428 | 0 | if (!ret && errno == EPERM) { |
429 | 0 | if (!unlink(path)) |
430 | 0 | ret = fopen(path, "w"); |
431 | 0 | else |
432 | 0 | errno = EPERM; |
433 | 0 | } |
434 | 0 | return ret; |
435 | 0 | } |
436 | | |
437 | | static void warn_on_inaccessible(const char *path) |
438 | 0 | { |
439 | 0 | warning_errno(_("unable to access '%s'"), path); |
440 | 0 | } |
441 | | |
442 | | int warn_on_fopen_errors(const char *path) |
443 | 0 | { |
444 | 0 | if (errno != ENOENT && errno != ENOTDIR) { |
445 | 0 | warn_on_inaccessible(path); |
446 | 0 | return -1; |
447 | 0 | } |
448 | | |
449 | 0 | return 0; |
450 | 0 | } |
451 | | |
452 | | FILE *fopen_or_warn(const char *path, const char *mode) |
453 | 0 | { |
454 | 0 | FILE *fp = fopen(path, mode); |
455 | |
|
456 | 0 | if (fp) |
457 | 0 | return fp; |
458 | | |
459 | 0 | warn_on_fopen_errors(path); |
460 | 0 | return NULL; |
461 | 0 | } |
462 | | |
463 | | int xmkstemp(char *filename_template) |
464 | 0 | { |
465 | 0 | return xmkstemp_mode(filename_template, 0600); |
466 | 0 | } |
467 | | |
468 | | /* Adapted from libiberty's mkstemp.c. */ |
469 | | |
470 | | #undef TMP_MAX |
471 | 0 | #define TMP_MAX 16384 |
472 | | |
473 | | /* |
474 | | * Returns -1 on error, 0 if it created a directory, or an open file |
475 | | * descriptor to the created regular file. |
476 | | */ |
477 | | static int git_mkdstemps_mode(char *pattern, int suffix_len, int mode, bool dir) |
478 | 0 | { |
479 | 0 | static const char letters[] = |
480 | 0 | "abcdefghijklmnopqrstuvwxyz" |
481 | 0 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
482 | 0 | "0123456789"; |
483 | 0 | static const int num_letters = ARRAY_SIZE(letters) - 1; |
484 | 0 | static const char x_pattern[] = "XXXXXX"; |
485 | 0 | static const int num_x = ARRAY_SIZE(x_pattern) - 1; |
486 | 0 | char *filename_template; |
487 | 0 | size_t len; |
488 | 0 | int fd, count; |
489 | |
|
490 | 0 | len = strlen(pattern); |
491 | |
|
492 | 0 | if (len < num_x + suffix_len) { |
493 | 0 | errno = EINVAL; |
494 | 0 | return -1; |
495 | 0 | } |
496 | | |
497 | 0 | if (strncmp(&pattern[len - num_x - suffix_len], x_pattern, num_x)) { |
498 | 0 | errno = EINVAL; |
499 | 0 | return -1; |
500 | 0 | } |
501 | | |
502 | | /* |
503 | | * Replace pattern's XXXXXX characters with randomness. |
504 | | * Try TMP_MAX different filenames. |
505 | | */ |
506 | 0 | filename_template = &pattern[len - num_x - suffix_len]; |
507 | 0 | for (count = 0; count < TMP_MAX; ++count) { |
508 | 0 | int i; |
509 | 0 | uint64_t v; |
510 | 0 | if (csprng_bytes(&v, sizeof(v), 0) < 0) |
511 | 0 | return error_errno("unable to get random bytes for temporary file"); |
512 | | |
513 | | /* Fill in the random bits. */ |
514 | 0 | for (i = 0; i < num_x; i++) { |
515 | 0 | filename_template[i] = letters[v % num_letters]; |
516 | 0 | v /= num_letters; |
517 | 0 | } |
518 | |
|
519 | 0 | if (dir) |
520 | 0 | fd = mkdir(pattern, mode); |
521 | 0 | else |
522 | 0 | fd = open(pattern, O_CREAT | O_EXCL | O_RDWR, mode); |
523 | 0 | if (fd >= 0) |
524 | 0 | return fd; |
525 | | /* |
526 | | * Fatal error (EPERM, ENOSPC etc). |
527 | | * It doesn't make sense to loop. |
528 | | */ |
529 | 0 | if (errno != EEXIST) |
530 | 0 | break; |
531 | 0 | } |
532 | | /* We return the null string if we can't find a unique file name. */ |
533 | 0 | pattern[0] = '\0'; |
534 | 0 | return -1; |
535 | 0 | } |
536 | | |
537 | | char *git_mkdtemp(char *pattern) |
538 | 0 | { |
539 | 0 | return git_mkdstemps_mode(pattern, 0, 0700, true) ? NULL : pattern; |
540 | 0 | } |
541 | | |
542 | | int git_mkstemps_mode(char *pattern, int suffix_len, int mode) |
543 | 0 | { |
544 | 0 | return git_mkdstemps_mode(pattern, suffix_len, mode, false); |
545 | 0 | } |
546 | | |
547 | | int git_mkstemp_mode(char *pattern, int mode) |
548 | 0 | { |
549 | | /* mkstemp is just mkstemps with no suffix */ |
550 | 0 | return git_mkstemps_mode(pattern, 0, mode); |
551 | 0 | } |
552 | | |
553 | | int xmkstemp_mode(char *filename_template, int mode) |
554 | 0 | { |
555 | 0 | int fd; |
556 | 0 | char origtemplate[PATH_MAX]; |
557 | 0 | strlcpy(origtemplate, filename_template, sizeof(origtemplate)); |
558 | |
|
559 | 0 | fd = git_mkstemp_mode(filename_template, mode); |
560 | 0 | if (fd < 0) { |
561 | 0 | int saved_errno = errno; |
562 | 0 | const char *nonrelative_template; |
563 | |
|
564 | 0 | if (!filename_template[0]) |
565 | 0 | filename_template = origtemplate; |
566 | |
|
567 | 0 | nonrelative_template = absolute_path(filename_template); |
568 | 0 | errno = saved_errno; |
569 | 0 | die_errno("Unable to create temporary file '%s'", |
570 | 0 | nonrelative_template); |
571 | 0 | } |
572 | 0 | return fd; |
573 | 0 | } |
574 | | |
575 | | /* |
576 | | * Some platforms return EINTR from fsync. Since fsync is invoked in some |
577 | | * cases by a wrapper that dies on failure, do not expose EINTR to callers. |
578 | | */ |
579 | | static int fsync_loop(int fd) |
580 | 0 | { |
581 | 0 | int err; |
582 | |
|
583 | 0 | do { |
584 | 0 | err = fsync(fd); |
585 | 0 | } while (err < 0 && errno == EINTR); |
586 | 0 | return err; |
587 | 0 | } |
588 | | |
589 | | int git_fsync(int fd, enum fsync_action action) |
590 | 0 | { |
591 | 0 | switch (action) { |
592 | 0 | case FSYNC_WRITEOUT_ONLY: |
593 | 0 | trace2_counter_add(TRACE2_COUNTER_ID_FSYNC_WRITEOUT_ONLY, 1); |
594 | |
|
595 | | #ifdef __APPLE__ |
596 | | /* |
597 | | * On macOS, fsync just causes filesystem cache writeback but |
598 | | * does not flush hardware caches. |
599 | | */ |
600 | | return fsync_loop(fd); |
601 | | #endif |
602 | |
|
603 | 0 | #ifdef HAVE_SYNC_FILE_RANGE |
604 | | /* |
605 | | * On linux 2.6.17 and above, sync_file_range is the way to |
606 | | * issue a writeback without a hardware flush. An offset of |
607 | | * 0 and size of 0 indicates writeout of the entire file and the |
608 | | * wait flags ensure that all dirty data is written to the disk |
609 | | * (potentially in a disk-side cache) before we continue. |
610 | | */ |
611 | |
|
612 | 0 | return sync_file_range(fd, 0, 0, SYNC_FILE_RANGE_WAIT_BEFORE | |
613 | 0 | SYNC_FILE_RANGE_WRITE | |
614 | 0 | SYNC_FILE_RANGE_WAIT_AFTER); |
615 | 0 | #endif |
616 | | |
617 | | #ifdef fsync_no_flush |
618 | | return fsync_no_flush(fd); |
619 | | #endif |
620 | | |
621 | 0 | errno = ENOSYS; |
622 | 0 | return -1; |
623 | | |
624 | 0 | case FSYNC_HARDWARE_FLUSH: |
625 | 0 | trace2_counter_add(TRACE2_COUNTER_ID_FSYNC_HARDWARE_FLUSH, 1); |
626 | | |
627 | | /* |
628 | | * On macOS, a special fcntl is required to really flush the |
629 | | * caches within the storage controller. As of this writing, |
630 | | * this is a very expensive operation on Apple SSDs. |
631 | | */ |
632 | | #ifdef __APPLE__ |
633 | | return fcntl(fd, F_FULLFSYNC); |
634 | | #else |
635 | 0 | return fsync_loop(fd); |
636 | 0 | #endif |
637 | 0 | default: |
638 | 0 | BUG("unexpected git_fsync(%d) call", action); |
639 | 0 | } |
640 | 0 | } |
641 | | |
642 | | static int warn_if_unremovable(const char *op, const char *file, int rc) |
643 | 0 | { |
644 | 0 | int err; |
645 | 0 | if (!rc || errno == ENOENT) |
646 | 0 | return 0; |
647 | 0 | err = errno; |
648 | 0 | warning_errno("unable to %s '%s'", op, file); |
649 | 0 | errno = err; |
650 | 0 | return rc; |
651 | 0 | } |
652 | | |
653 | | int unlink_or_msg(const char *file, struct strbuf *err) |
654 | 0 | { |
655 | 0 | int rc = unlink(file); |
656 | |
|
657 | 0 | assert(err); |
658 | |
|
659 | 0 | if (!rc || errno == ENOENT) |
660 | 0 | return 0; |
661 | | |
662 | 0 | strbuf_addf(err, "unable to unlink '%s': %s", |
663 | 0 | file, strerror(errno)); |
664 | 0 | return -1; |
665 | 0 | } |
666 | | |
667 | | int unlink_or_warn(const char *file) |
668 | 0 | { |
669 | 0 | return warn_if_unremovable("unlink", file, unlink(file)); |
670 | 0 | } |
671 | | |
672 | | int rmdir_or_warn(const char *file) |
673 | 0 | { |
674 | 0 | return warn_if_unremovable("rmdir", file, rmdir(file)); |
675 | 0 | } |
676 | | |
677 | | static int access_error_is_ok(int err, unsigned flag) |
678 | 0 | { |
679 | 0 | return (is_missing_file_error(err) || |
680 | 0 | ((flag & ACCESS_EACCES_OK) && err == EACCES)); |
681 | 0 | } |
682 | | |
683 | | int access_or_warn(const char *path, int mode, unsigned flag) |
684 | 0 | { |
685 | 0 | int ret = access(path, mode); |
686 | 0 | if (ret && !access_error_is_ok(errno, flag)) |
687 | 0 | warn_on_inaccessible(path); |
688 | 0 | return ret; |
689 | 0 | } |
690 | | |
691 | | int access_or_die(const char *path, int mode, unsigned flag) |
692 | 0 | { |
693 | 0 | int ret = access(path, mode); |
694 | 0 | if (ret && !access_error_is_ok(errno, flag)) |
695 | 0 | die_errno(_("unable to access '%s'"), path); |
696 | 0 | return ret; |
697 | 0 | } |
698 | | |
699 | | char *xgetcwd(void) |
700 | 0 | { |
701 | 0 | struct strbuf sb = STRBUF_INIT; |
702 | 0 | if (strbuf_getcwd(&sb)) |
703 | 0 | die_errno(_("unable to get current working directory")); |
704 | 0 | return strbuf_detach(&sb, NULL); |
705 | 0 | } |
706 | | |
707 | | int xsnprintf(char *dst, size_t max, const char *fmt, ...) |
708 | 0 | { |
709 | 0 | va_list ap; |
710 | 0 | int len; |
711 | |
|
712 | 0 | va_start(ap, fmt); |
713 | 0 | len = vsnprintf(dst, max, fmt, ap); |
714 | 0 | va_end(ap); |
715 | |
|
716 | 0 | if (len < 0) |
717 | 0 | die(_("unable to format message: %s"), fmt); |
718 | 0 | if (len >= max) |
719 | 0 | BUG("attempt to snprintf into too-small buffer"); |
720 | 0 | return len; |
721 | 0 | } |
722 | | |
723 | | void write_file_buf(const char *path, const char *buf, size_t len) |
724 | 0 | { |
725 | 0 | int fd = xopen(path, O_WRONLY | O_CREAT | O_TRUNC, 0666); |
726 | 0 | if (write_in_full(fd, buf, len) < 0) |
727 | 0 | die_errno(_("could not write to '%s'"), path); |
728 | 0 | if (close(fd)) |
729 | 0 | die_errno(_("could not close '%s'"), path); |
730 | 0 | } |
731 | | |
732 | | void write_file(const char *path, const char *fmt, ...) |
733 | 0 | { |
734 | 0 | va_list params; |
735 | 0 | struct strbuf sb = STRBUF_INIT; |
736 | |
|
737 | 0 | va_start(params, fmt); |
738 | 0 | strbuf_vaddf(&sb, fmt, params); |
739 | 0 | va_end(params); |
740 | |
|
741 | 0 | strbuf_complete_line(&sb); |
742 | |
|
743 | 0 | write_file_buf(path, sb.buf, sb.len); |
744 | 0 | strbuf_release(&sb); |
745 | 0 | } |
746 | | |
747 | | void sleep_millisec(int millisec) |
748 | 0 | { |
749 | 0 | poll(NULL, 0, millisec); |
750 | 0 | } |
751 | | |
752 | | int xgethostname(char *buf, size_t len) |
753 | 0 | { |
754 | | /* |
755 | | * If the full hostname doesn't fit in buf, POSIX does not |
756 | | * specify whether the buffer will be null-terminated, so to |
757 | | * be safe, do it ourselves. |
758 | | */ |
759 | 0 | int ret = gethostname(buf, len); |
760 | 0 | if (!ret) |
761 | 0 | buf[len - 1] = 0; |
762 | 0 | return ret; |
763 | 0 | } |
764 | | |
765 | | int is_missing_file(const char *filename) |
766 | 0 | { |
767 | 0 | struct stat st; |
768 | |
|
769 | 0 | if (stat(filename, &st) < 0) { |
770 | 0 | if (errno == ENOENT) |
771 | 0 | return 1; |
772 | 0 | die_errno(_("could not stat %s"), filename); |
773 | 0 | } |
774 | | |
775 | 0 | return 0; |
776 | 0 | } |
777 | | |
778 | | int is_empty_or_missing_file(const char *filename) |
779 | 0 | { |
780 | 0 | struct stat st; |
781 | |
|
782 | 0 | if (stat(filename, &st) < 0) { |
783 | 0 | if (errno == ENOENT) |
784 | 0 | return 1; |
785 | 0 | die_errno(_("could not stat %s"), filename); |
786 | 0 | } |
787 | | |
788 | 0 | return !st.st_size; |
789 | 0 | } |
790 | | |
791 | | int open_nofollow(const char *path, int flags) |
792 | 0 | { |
793 | 0 | #ifdef O_NOFOLLOW |
794 | 0 | int ret = open(path, flags | O_NOFOLLOW); |
795 | | /* |
796 | | * NetBSD sets errno to EFTYPE when path is a symlink. The only other |
797 | | * time this errno occurs when O_REGULAR is used. Since we don't use |
798 | | * it anywhere we can avoid an lstat here. FreeBSD does the same with |
799 | | * EMLINK. |
800 | | */ |
801 | | # ifdef __NetBSD__ |
802 | | # define SYMLINK_ERRNO EFTYPE |
803 | | # elif defined(__FreeBSD__) |
804 | | # define SYMLINK_ERRNO EMLINK |
805 | | # endif |
806 | | # if SYMLINK_ERRNO |
807 | | if (ret < 0 && errno == SYMLINK_ERRNO) { |
808 | | errno = ELOOP; |
809 | | return -1; |
810 | | } |
811 | | # undef SYMLINK_ERRNO |
812 | | # endif |
813 | 0 | return ret; |
814 | | #else |
815 | | struct stat st; |
816 | | if (lstat(path, &st) < 0) |
817 | | return -1; |
818 | | if (S_ISLNK(st.st_mode)) { |
819 | | errno = ELOOP; |
820 | | return -1; |
821 | | } |
822 | | return open(path, flags); |
823 | | #endif |
824 | 0 | } |
825 | | |
826 | | int csprng_bytes(void *buf, size_t len, MAYBE_UNUSED unsigned flags) |
827 | 0 | { |
828 | | #if defined(HAVE_ARC4RANDOM) || defined(HAVE_ARC4RANDOM_LIBBSD) |
829 | | /* This function never returns an error. */ |
830 | | arc4random_buf(buf, len); |
831 | | return 0; |
832 | | #elif defined(HAVE_GETRANDOM) |
833 | | ssize_t res; |
834 | 0 | char *p = buf; |
835 | 0 | while (len) { |
836 | 0 | res = getrandom(p, len, 0); |
837 | 0 | if (res < 0) |
838 | 0 | return -1; |
839 | 0 | len -= res; |
840 | 0 | p += res; |
841 | 0 | } |
842 | 0 | return 0; |
843 | | #elif defined(HAVE_GETENTROPY) |
844 | | int res; |
845 | | char *p = buf; |
846 | | while (len) { |
847 | | /* getentropy has a maximum size of 256 bytes. */ |
848 | | size_t chunk = len < 256 ? len : 256; |
849 | | res = getentropy(p, chunk); |
850 | | if (res < 0) |
851 | | return -1; |
852 | | len -= chunk; |
853 | | p += chunk; |
854 | | } |
855 | | return 0; |
856 | | #elif defined(HAVE_RTLGENRANDOM) |
857 | | if (!RtlGenRandom(buf, len)) |
858 | | return -1; |
859 | | return 0; |
860 | | #elif defined(HAVE_OPENSSL_CSPRNG) |
861 | | switch (RAND_pseudo_bytes(buf, len)) { |
862 | | case 1: |
863 | | return 0; |
864 | | case 0: |
865 | | if (flags & CSPRNG_BYTES_INSECURE) |
866 | | return 0; |
867 | | errno = EIO; |
868 | | return -1; |
869 | | default: |
870 | | errno = ENOTSUP; |
871 | | return -1; |
872 | | } |
873 | | #else |
874 | | ssize_t res; |
875 | | char *p = buf; |
876 | | int fd, err; |
877 | | fd = open("/dev/urandom", O_RDONLY); |
878 | | if (fd < 0) |
879 | | return -1; |
880 | | while (len) { |
881 | | res = xread(fd, p, len); |
882 | | if (res < 0) { |
883 | | err = errno; |
884 | | close(fd); |
885 | | errno = err; |
886 | | return -1; |
887 | | } |
888 | | len -= res; |
889 | | p += res; |
890 | | } |
891 | | close(fd); |
892 | | return 0; |
893 | | #endif |
894 | 0 | } |
895 | | |
896 | | uint32_t git_rand(unsigned flags) |
897 | 0 | { |
898 | 0 | uint32_t result; |
899 | |
|
900 | 0 | if (csprng_bytes(&result, sizeof(result), flags) < 0) |
901 | 0 | die(_("unable to get random bytes")); |
902 | | |
903 | 0 | return result; |
904 | 0 | } |
905 | | |
906 | | static void mmap_limit_check(size_t length) |
907 | 0 | { |
908 | 0 | static size_t limit = 0; |
909 | 0 | if (!limit) { |
910 | 0 | limit = git_env_ulong("GIT_MMAP_LIMIT", 0); |
911 | 0 | if (!limit) |
912 | 0 | limit = SIZE_MAX; |
913 | 0 | } |
914 | 0 | if (length > limit) |
915 | 0 | die(_("attempting to mmap %"PRIuMAX" over limit %"PRIuMAX), |
916 | 0 | (uintmax_t)length, (uintmax_t)limit); |
917 | 0 | } |
918 | | |
919 | | void *xmmap_gently(void *start, size_t length, |
920 | | int prot, int flags, int fd, off_t offset) |
921 | 0 | { |
922 | 0 | void *ret; |
923 | |
|
924 | 0 | mmap_limit_check(length); |
925 | 0 | ret = mmap(start, length, prot, flags, fd, offset); |
926 | 0 | if (ret == MAP_FAILED && !length) |
927 | 0 | ret = NULL; |
928 | 0 | return ret; |
929 | 0 | } |
930 | | |
931 | | const char *mmap_os_err(void) |
932 | 0 | { |
933 | 0 | static const char blank[] = ""; |
934 | 0 | #if defined(__linux__) |
935 | 0 | if (errno == ENOMEM) { |
936 | | /* this continues an existing error message: */ |
937 | 0 | static const char enomem[] = |
938 | 0 | ", check sys.vm.max_map_count and/or RLIMIT_DATA"; |
939 | 0 | return enomem; |
940 | 0 | } |
941 | 0 | #endif /* OS-specific bits */ |
942 | 0 | return blank; |
943 | 0 | } |
944 | | |
945 | | void *xmmap(void *start, size_t length, |
946 | | int prot, int flags, int fd, off_t offset) |
947 | 0 | { |
948 | 0 | void *ret = xmmap_gently(start, length, prot, flags, fd, offset); |
949 | 0 | if (ret == MAP_FAILED) |
950 | 0 | die_errno(_("mmap failed%s"), mmap_os_err()); |
951 | 0 | return ret; |
952 | 0 | } |