Skip to content

Commit

Permalink
tools/gnulib: add fallocate-posix module
Browse files Browse the repository at this point in the history
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 <[email protected]>
Link: openwrt/openwrt#15690
Signed-off-by: Robert Marko <[email protected]>
  • Loading branch information
mcprat authored and robimarko committed Jun 19, 2024
1 parent 447093f commit f07621e
Showing 1 changed file with 326 additions and 0 deletions.
326 changes: 326 additions & 0 deletions tools/gnulib/patches/320-modules-fallocate-posix.patch
Original file line number Diff line number Diff line change
@@ -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:
+<fcntl.h>
+
+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 <fcntl.h>]])
+ 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.h>
- ]], [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 <https://www.gnu.org/licenses/>. */
+
+#include <config.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+
+#ifdef __APPLE__
+# include <sys/param.h>
+# include <sys/mount.h>
+#else
+# include <sys/statfs.h>
+#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

0 comments on commit f07621e

Please sign in to comment.