From f07621e10b2ed85391eee7f489d843fb3f01ff6a Mon Sep 17 00:00:00 2001 From: Michael Pratt Date: Mon, 10 Jun 2024 04:04:41 -0400 Subject: [PATCH] tools/gnulib: add fallocate-posix module Add a module to gnulib to support posix_fallocate() for macOS and other systems that are missing it. Apple-specific code is sourced from Mozilla, and the rest from glibc, both licensed under LGPL. Signed-off-by: Michael Pratt Link: https://github.com/openwrt/openwrt/pull/15690 Signed-off-by: Robert Marko --- .../patches/320-modules-fallocate-posix.patch | 326 ++++++++++++++++++ 1 file changed, 326 insertions(+) create mode 100644 tools/gnulib/patches/320-modules-fallocate-posix.patch diff --git a/tools/gnulib/patches/320-modules-fallocate-posix.patch b/tools/gnulib/patches/320-modules-fallocate-posix.patch new file mode 100644 index 0000000000..e30a7172aa --- /dev/null +++ b/tools/gnulib/patches/320-modules-fallocate-posix.patch @@ -0,0 +1,326 @@ +--- /dev/null ++++ b/modules/fallocate-posix +@@ -0,0 +1,43 @@ ++Description: ++posix_fallocate function that is glibc compatible. ++ ++Files: ++lib/posix_fallocate.c ++m4/fcntl_h.m4 ++m4/posix_fallocate.m4 ++ ++Depends-on: ++errno [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] ++fcntl [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] ++fstat [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] ++ftruncate [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] ++pread [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] ++pwrite [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] ++stdint [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] ++sys_stat [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] ++unistd [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] ++fcntl-h ++ ++configure.ac: ++gl_FUNC_POSIX_FALLOCATE ++gl_CONDITIONAL([GL_COND_OBJ_POSIX_FALLOCATE], ++ [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]) ++AM_COND_IF([GL_COND_OBJ_POSIX_FALLOCATE], [ ++ gl_PREREQ_POSIX_FALLOCATE ++]) ++gl_MODULE_INDICATOR([fallocate-posix]) ++gl_FCNTL_MODULE_INDICATOR([fallocate-posix]) ++ ++Makefile.am: ++if GL_COND_OBJ_POSIX_FALLOCATE ++lib_SOURCES += posix_fallocate.c ++endif ++ ++Include: ++ ++ ++License: ++LGPLv2+ ++ ++Maintainer: ++all +--- /dev/null ++++ b/m4/posix_fallocate.m4 +@@ -0,0 +1,20 @@ ++# posix_fallocate.m4 serial 1 ++dnl Copyright (C) 2024 Free Software Foundation, Inc. ++dnl This file is free software; the Free Software Foundation ++dnl gives unlimited permission to copy and/or distribute it, ++dnl with or without modifications, as long as this notice is preserved. ++ ++AC_DEFUN([gl_FUNC_POSIX_FALLOCATE], ++[ ++ AC_REQUIRE([gl_FCNTL_H_DEFAULTS]) ++ gl_CHECK_FUNCS_ANDROID([posix_fallocate], [[#include ]]) ++ if test "$ac_cv_func_posix_fallocate" = no; then ++ HAVE_FALLOCATE_POSIX=0 ++ case "$gl_cv_onwards_func_posix_fallocate" in ++ future*) REPLACE_FALLOCATE_POSIX=1 ;; ++ esac ++ fi ++]) ++ ++# Prerequisites of lib/posix_fallocate.c. ++AC_DEFUN([gl_PREREQ_POSIX_FALLOCATE], [:]) +--- a/m4/fcntl_h.m4 ++++ b/m4/fcntl_h.m4 +@@ -23,7 +23,7 @@ AC_DEFUN_ONCE([gl_FCNTL_H], + dnl corresponding gnulib module is not in use, if it is not common + dnl enough to be declared everywhere. + gl_WARN_ON_USE_PREPARE([[#include +- ]], [fcntl openat]) ++ ]], [fcntl openat posix_fallocate]) + ]) + + # gl_FCNTL_MODULE_INDICATOR([modulename]) +@@ -50,6 +50,7 @@ AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS], + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NONBLOCKING]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPEN]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPENAT]) ++ gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FALLOCATE_POSIX]) + dnl Support Microsoft deprecated alias function names by default. + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CREAT], [1]) + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_OPEN], [1]) +@@ -61,10 +62,12 @@ AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS], + AC_DEFUN([gl_FCNTL_H_DEFAULTS], + [ + dnl Assume proper GNU behavior unless another module says otherwise. +- HAVE_FCNTL=1; AC_SUBST([HAVE_FCNTL]) +- HAVE_OPENAT=1; AC_SUBST([HAVE_OPENAT]) +- REPLACE_CREAT=0; AC_SUBST([REPLACE_CREAT]) +- REPLACE_FCNTL=0; AC_SUBST([REPLACE_FCNTL]) +- REPLACE_OPEN=0; AC_SUBST([REPLACE_OPEN]) +- REPLACE_OPENAT=0; AC_SUBST([REPLACE_OPENAT]) ++ HAVE_FCNTL=1; AC_SUBST([HAVE_FCNTL]) ++ HAVE_OPENAT=1; AC_SUBST([HAVE_OPENAT]) ++ HAVE_FALLOCATE_POSIX=1; AC_SUBST([HAVE_FALLOCATE_POSIX]) ++ REPLACE_CREAT=0; AC_SUBST([REPLACE_CREAT]) ++ REPLACE_FCNTL=0; AC_SUBST([REPLACE_FCNTL]) ++ REPLACE_OPEN=0; AC_SUBST([REPLACE_OPEN]) ++ REPLACE_OPENAT=0; AC_SUBST([REPLACE_OPENAT]) ++ REPLACE_FALLOCATE_POSIX=0; AC_SUBST([REPLACE_FALLOCATE_POSIX]) + ]) +--- a/modules/fcntl-h ++++ b/modules/fcntl-h +@@ -40,14 +40,17 @@ fcntl.h: fcntl.in.h $(top_builddir)/conf + -e 's/@''GNULIB_NONBLOCKING''@/$(GNULIB_NONBLOCKING)/g' \ + -e 's/@''GNULIB_OPEN''@/$(GNULIB_OPEN)/g' \ + -e 's/@''GNULIB_OPENAT''@/$(GNULIB_OPENAT)/g' \ ++ -e 's/@''GNULIB_FALLOCATE_POSIX''@/$(GNULIB_FALLOCATE_POSIX)/g' \ + -e 's/@''GNULIB_MDA_CREAT''@/$(GNULIB_MDA_CREAT)/g' \ + -e 's/@''GNULIB_MDA_OPEN''@/$(GNULIB_MDA_OPEN)/g' \ + -e 's|@''HAVE_FCNTL''@|$(HAVE_FCNTL)|g' \ + -e 's|@''HAVE_OPENAT''@|$(HAVE_OPENAT)|g' \ ++ -e 's|@''HAVE_FALLOCATE_POSIX''@|$(HAVE_FALLOCATE_POSIX)|g' \ + -e 's|@''REPLACE_CREAT''@|$(REPLACE_CREAT)|g' \ + -e 's|@''REPLACE_FCNTL''@|$(REPLACE_FCNTL)|g' \ + -e 's|@''REPLACE_OPEN''@|$(REPLACE_OPEN)|g' \ + -e 's|@''REPLACE_OPENAT''@|$(REPLACE_OPENAT)|g' \ ++ -e 's|@''REPLACE_FALLOCATE_POSIX''@|$(REPLACE_FALLOCATE_POSIX)|g' \ + -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ + -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ + -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ +--- a/lib/fcntl.in.h ++++ b/lib/fcntl.in.h +@@ -238,6 +238,33 @@ _GL_WARN_ON_USE (openat, "openat is not + # endif + #endif + ++#if @GNULIB_FALLOCATE_POSIX@ ++# if @REPLACE_FALLOCATE_POSIX@ ++# if !(defined __cplusplus && defined GNULIB_NAMESPACE) ++# undef posix_fallocate ++# define posix_fallocate rpl_posix_fallocate ++# endif ++_GL_FUNCDECL_RPL (posix_fallocate, int, ++ (int fd, off_t offset, off_t len)); ++_GL_CXXALIAS_RPL (posix_fallocate, int, ++ (int fd, off_t offset, off_t len)); ++# else ++# if !@HAVE_FALLOCATE_POSIX@ ++_GL_FUNCDECL_SYS (posix_fallocate, int, ++ (int fd, off_t offset, off_t len)); ++# endif ++_GL_CXXALIAS_SYS (posix_fallocate, int, ++ (int fd, off_t offset, off_t len)); ++# endif ++_GL_CXXALIASWARN (posix_fallocate); ++#elif defined GNULIB_POSIXCHECK ++# undef posix_fallocate ++# if HAVE_RAW_DECL_POSIX_FALLOCATE ++_GL_WARN_ON_USE (posix_fallocate, "posix_fallocate is not portable - " ++ "use gnulib module fallocate-posix for portability"); ++# endif ++#endif ++ + + /* Fix up the FD_* macros, only known to be missing on mingw. */ + +--- /dev/null ++++ b/lib/posix_fallocate.c +@@ -0,0 +1,150 @@ ++/* posix_fallocate function that is glibc compatible. ++ ++ Copyright (C) 2024 Free Software Foundation, Inc. ++ ++ This file is free software: you can redistribute it and/or modify ++ it under the terms of the GNU Lesser General Public License as ++ published by the Free Software Foundation; either version 2.1 of the ++ License, or (at your option) any later version. ++ ++ This file is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ GNU Lesser General Public License for more details. ++ ++ You should have received a copy of the GNU Lesser General Public License ++ along with this program. If not, see . */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef __APPLE__ ++# include ++# include ++#else ++# include ++#endif ++ ++/* Reserve storage for the data of the file associated with FD. This ++ emulation is far from perfect, but the kernel cannot do not much ++ better for network file systems, either. */ ++ ++int ++posix_fallocate (int fd, off_t offset, off_t len) ++{ ++ int ret; ++ struct stat st; ++ ++ if (fd < 0 || offset < 0 || len < 0) ++ return EINVAL; ++ ++ /* Perform overflow check. The outer cast relies on a GCC ++ extension. */ ++ if ((off_t) ((uint64_t) offset + (uint64_t) len) < 0) ++ return EFBIG; ++ ++ /* pwrite below will not do the right thing in O_APPEND mode. */ ++ { ++ int flags = fcntl (fd, F_GETFL, 0); ++ if (flags < 0 || (flags & O_APPEND) != 0) ++ return EBADF; ++ } ++ ++ /* We have to make sure that this is really a regular file. */ ++ if (fstat (fd, &st) != 0) ++ return EBADF; ++ if (S_ISFIFO (st.st_mode)) ++ return ESPIPE; ++ if (! S_ISREG (st.st_mode)) ++ return ENODEV; ++ ++ if (len == 0) ++ { ++ /* This is racy, but there is no good way to satisfy a ++ zero-length allocation request. */ ++ if (st.st_size < offset) ++ { ++ ret = ftruncate (fd, offset); ++ ++ if (ret != 0) ++ ret = errno; ++ return ret; ++ } ++ return ret; ++ } ++ ++#ifdef __APPLE__ ++ fstore_t sto = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, offset + len, 0}; ++ /* allocate continuous */ ++ ret = fcntl (fd, F_PREALLOCATE, &sto); ++ if (ret < 0) ++ { ++ /* allocate non-continuous */ ++ sto.fst_flags = F_ALLOCATEALL; ++ ret = fcntl (fd, F_PREALLOCATE, &sto); ++ if (ret < 0) ++ { ++ return ret; ++ } ++ } ++ ret = ftruncate(fd, offset + len); ++#else ++ ++ /* Minimize data transfer for network file systems, by issuing ++ single-byte write requests spaced by the file system block size. ++ (Most local file systems have fallocate support, so this fallback ++ code is not used there.) */ ++ ++ unsigned increment; ++ { ++ struct statfs f; ++ ++ if (fstatfs (fd, &f) != 0) ++ return errno; ++ if (f.f_bsize == 0) ++ increment = 512; ++ else if (f.f_bsize < 4096) ++ increment = f.f_bsize; ++ else ++ /* NFS does not propagate the block size of the underlying ++ storage and may report a much larger value which would still ++ leave holes after the loop below, so we cap the increment at ++ 4096. */ ++ increment = 4096; ++ } ++ ++ /* Write a null byte to every block. This is racy; we currently ++ lack a better option. Compare-and-swap against a file mapping ++ might additional local races, but requires interposition of a ++ signal handler to catch SIGBUS. */ ++ for (offset += (len - 1) % increment; len > 0; offset += increment) ++ { ++ len -= increment; ++ ++ if (offset < st.st_size) ++ { ++ unsigned char c; ++ ssize_t rsize = pread (fd, &c, 1, offset); ++ ++ if (rsize < 0) ++ return errno; ++ /* If there is a non-zero byte, the block must have been ++ allocated already. */ ++ else if (rsize == 1 && c != 0) ++ continue; ++ } ++ ++ if (pwrite (fd, "", 1, offset) != 1) ++ return errno; ++ } ++ ++#endif /* __APPLE__ */ ++ ++ return ret; ++} +--- a/MODULES.html.sh ++++ b/MODULES.html.sh +@@ -2552,6 +2552,7 @@ func_all_modules () + func_module execve + func_module execvp + func_module execvpe ++ func_module fallocate-posix + func_module fchdir + func_module fclose + func_module fcntl-h