mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-27 17:18:59 +00:00
f07621e10b
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 <mcpratt@pm.me> Link: https://github.com/openwrt/openwrt/pull/15690 Signed-off-by: Robert Marko <robimarko@gmail.com>
327 lines
11 KiB
Diff
327 lines
11 KiB
Diff
--- /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
|