From 05abf2143f967cd85b1b1b777ee412a581979cf1 Mon Sep 17 00:00:00 2001 From: Colin Walters <walters@verbum.org> Date: Mon, 12 Jun 2017 17:00:53 -0400 Subject: [PATCH] fdio: Add glnx_try_fallocate() The glibc `posix_fallocate()` implementation has a bad fallback, and further we need to handle `EOPNOTSUPP` for musl. https://github.com/flatpak/flatpak/issues/802 --- glnx-fdio.c | 13 ++----------- glnx-fdio.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/glnx-fdio.c b/glnx-fdio.c index 19de9ec21..87e2dbb98 100644 --- a/glnx-fdio.c +++ b/glnx-fdio.c @@ -920,7 +920,6 @@ glnx_file_replace_contents_with_perms_at (int dfd, GCancellable *cancellable, GError **error) { - int r; char *dnbuf = strdupa (subpath); const char *dn = dirname (dnbuf); @@ -940,16 +939,8 @@ glnx_file_replace_contents_with_perms_at (int dfd, if (len == -1) len = strlen ((char*)buf); - /* Note that posix_fallocate does *not* set errno but returns it. */ - if (len > 0) - { - r = posix_fallocate (tmpf.fd, 0, len); - if (r != 0) - { - errno = r; - return glnx_throw_errno_prefix (error, "fallocate"); - } - } + if (!glnx_try_fallocate (tmpf.fd, 0, len, error)) + return FALSE; if (glnx_loop_write (tmpf.fd, buf, len) < 0) return glnx_throw_errno (error); diff --git a/glnx-fdio.h b/glnx-fdio.h index dda32d1a7..e52c82377 100644 --- a/glnx-fdio.h +++ b/glnx-fdio.h @@ -166,6 +166,38 @@ int glnx_renameat2_noreplace (int olddirfd, const char *oldpath, int glnx_renameat2_exchange (int olddirfd, const char *oldpath, int newdirfd, const char *newpath); +/** + * glnx_try_fallocate: + * @fd: File descriptor + * @size: Size + * @error: Error + * + * Wrapper for Linux fallocate(). Explicitly ignores a @size of zero. + * Also, will silently do nothing if the underlying filesystem doesn't + * support it. Use this instead of posix_fallocate(), since the glibc fallback + * is bad: https://sourceware.org/bugzilla/show_bug.cgi?id=18515 + */ +static inline gboolean +glnx_try_fallocate (int fd, + off_t offset, + off_t size, + GError **error) +{ + /* This is just nicer than throwing an error */ + if (size == 0) + return TRUE; + + if (fallocate (fd, 0, offset, size) < 0) + { + if (errno == ENOSYS || errno == EOPNOTSUPP) + ; /* Ignore */ + else + return glnx_throw_errno_prefix (error, "fallocate"); + } + + return TRUE; +} + /** * glnx_fstat: * @fd: FD to stat -- GitLab