diff options
Diffstat (limited to 'cursor/os-compatibility.c')
-rw-r--r-- | cursor/os-compatibility.c | 34 |
1 files changed, 27 insertions, 7 deletions
diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c index 8d51e52..f2445ce 100644 --- a/cursor/os-compatibility.c +++ b/cursor/os-compatibility.c @@ -31,7 +31,9 @@ #include <unistd.h> #include <fcntl.h> #include <errno.h> +#include <signal.h> #include <string.h> +#include <stdio.h> #include <stdlib.h> #ifdef HAVE_MEMFD_CREATE @@ -118,6 +120,7 @@ os_create_anonymous_file(off_t size) static const char template[] = "/wayland-cursor-shared-XXXXXX"; const char *path; char *name; + size_t name_size; int fd; #ifdef HAVE_MEMFD_CREATE @@ -134,17 +137,17 @@ os_create_anonymous_file(off_t size) #endif { path = getenv("XDG_RUNTIME_DIR"); - if (!path) { + if (!path || path[0] != '/') { errno = ENOENT; return -1; } - name = malloc(strlen(path) + sizeof(template)); + name_size = strlen(path) + sizeof(template); + name = malloc(name_size); if (!name) return -1; - strcpy(name, path); - strcat(name, template); + snprintf(name, name_size, "%s%s", path, template); fd = create_tmpfile_cloexec(name); @@ -166,11 +169,28 @@ int os_resize_anonymous_file(int fd, off_t size) { #ifdef HAVE_POSIX_FALLOCATE - /* - * Filesystems that do support fallocate will return EINVAL or + sigset_t mask; + sigset_t old_mask; + + /* + * posix_fallocate() might be interrupted, so we need to check + * for EINTR and retry in that case. + * However, in the presence of an alarm, the interrupt may trigger + * repeatedly and prevent a large posix_fallocate() to ever complete + * successfully, so we need to first block SIGALRM to prevent + * this. + */ + sigemptyset(&mask); + sigaddset(&mask, SIGALRM); + sigprocmask(SIG_BLOCK, &mask, &old_mask); + /* + * Filesystems that do not support fallocate will return EINVAL or * EOPNOTSUPP. In this case we need to fall back to ftruncate */ - errno = posix_fallocate(fd, 0, size); + do { + errno = posix_fallocate(fd, 0, size); + } while (errno == EINTR); + sigprocmask(SIG_SETMASK, &old_mask, NULL); if (errno == 0) return 0; else if (errno != EINVAL && errno != EOPNOTSUPP) |