 f07621e10b
			
		
	
	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
 |