diff --git a/glnx-fdio.c b/glnx-fdio.c index 19de9ec21b5df1a52f0bfce5ed29dc607c3125fa..87e2dbb9853883a236b4b32f2f7feaedf8ff22d0 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 dda32d1a79e7c2ab72cea2bb7751794aeb112a5b..e52c823776231a8cf837e849d7d8b8ed061a0f11 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