b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame] | 1 | --- /dev/null |
| 2 | +++ b/modules/fallocate-posix |
| 3 | @@ -0,0 +1,43 @@ |
| 4 | +Description: |
| 5 | +posix_fallocate function that is glibc compatible. |
| 6 | + |
| 7 | +Files: |
| 8 | +lib/posix_fallocate.c |
| 9 | +m4/fcntl_h.m4 |
| 10 | +m4/posix_fallocate.m4 |
| 11 | + |
| 12 | +Depends-on: |
| 13 | +errno [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] |
| 14 | +fcntl [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] |
| 15 | +fstat [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] |
| 16 | +ftruncate [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] |
| 17 | +pread [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] |
| 18 | +pwrite [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] |
| 19 | +stdint [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] |
| 20 | +sys_stat [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] |
| 21 | +unistd [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1] |
| 22 | +fcntl-h |
| 23 | + |
| 24 | +configure.ac: |
| 25 | +gl_FUNC_POSIX_FALLOCATE |
| 26 | +gl_CONDITIONAL([GL_COND_OBJ_POSIX_FALLOCATE], |
| 27 | + [test $HAVE_FALLOCATE_POSIX = 0 || test $REPLACE_FALLOCATE_POSIX = 1]) |
| 28 | +AM_COND_IF([GL_COND_OBJ_POSIX_FALLOCATE], [ |
| 29 | + gl_PREREQ_POSIX_FALLOCATE |
| 30 | +]) |
| 31 | +gl_MODULE_INDICATOR([fallocate-posix]) |
| 32 | +gl_FCNTL_MODULE_INDICATOR([fallocate-posix]) |
| 33 | + |
| 34 | +Makefile.am: |
| 35 | +if GL_COND_OBJ_POSIX_FALLOCATE |
| 36 | +lib_SOURCES += posix_fallocate.c |
| 37 | +endif |
| 38 | + |
| 39 | +Include: |
| 40 | +<fcntl.h> |
| 41 | + |
| 42 | +License: |
| 43 | +LGPLv2+ |
| 44 | + |
| 45 | +Maintainer: |
| 46 | +all |
| 47 | --- /dev/null |
| 48 | +++ b/m4/posix_fallocate.m4 |
| 49 | @@ -0,0 +1,20 @@ |
| 50 | +# posix_fallocate.m4 serial 1 |
| 51 | +dnl Copyright (C) 2024 Free Software Foundation, Inc. |
| 52 | +dnl This file is free software; the Free Software Foundation |
| 53 | +dnl gives unlimited permission to copy and/or distribute it, |
| 54 | +dnl with or without modifications, as long as this notice is preserved. |
| 55 | + |
| 56 | +AC_DEFUN([gl_FUNC_POSIX_FALLOCATE], |
| 57 | +[ |
| 58 | + AC_REQUIRE([gl_FCNTL_H_DEFAULTS]) |
| 59 | + gl_CHECK_FUNCS_ANDROID([posix_fallocate], [[#include <fcntl.h>]]) |
| 60 | + if test "$ac_cv_func_posix_fallocate" = no; then |
| 61 | + HAVE_FALLOCATE_POSIX=0 |
| 62 | + case "$gl_cv_onwards_func_posix_fallocate" in |
| 63 | + future*) REPLACE_FALLOCATE_POSIX=1 ;; |
| 64 | + esac |
| 65 | + fi |
| 66 | +]) |
| 67 | + |
| 68 | +# Prerequisites of lib/posix_fallocate.c. |
| 69 | +AC_DEFUN([gl_PREREQ_POSIX_FALLOCATE], [:]) |
| 70 | --- a/m4/fcntl_h.m4 |
| 71 | +++ b/m4/fcntl_h.m4 |
| 72 | @@ -23,7 +23,7 @@ AC_DEFUN_ONCE([gl_FCNTL_H], |
| 73 | dnl corresponding gnulib module is not in use, if it is not common |
| 74 | dnl enough to be declared everywhere. |
| 75 | gl_WARN_ON_USE_PREPARE([[#include <fcntl.h> |
| 76 | - ]], [fcntl openat]) |
| 77 | + ]], [fcntl openat posix_fallocate]) |
| 78 | ]) |
| 79 | |
| 80 | # gl_FCNTL_MODULE_INDICATOR([modulename]) |
| 81 | @@ -50,6 +50,7 @@ AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS], |
| 82 | gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_NONBLOCKING]) |
| 83 | gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPEN]) |
| 84 | gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_OPENAT]) |
| 85 | + gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_FALLOCATE_POSIX]) |
| 86 | dnl Support Microsoft deprecated alias function names by default. |
| 87 | gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_CREAT], [1]) |
| 88 | gl_MODULE_INDICATOR_INIT_VARIABLE([GNULIB_MDA_OPEN], [1]) |
| 89 | @@ -61,10 +62,12 @@ AC_DEFUN([gl_FCNTL_H_REQUIRE_DEFAULTS], |
| 90 | AC_DEFUN([gl_FCNTL_H_DEFAULTS], |
| 91 | [ |
| 92 | dnl Assume proper GNU behavior unless another module says otherwise. |
| 93 | - HAVE_FCNTL=1; AC_SUBST([HAVE_FCNTL]) |
| 94 | - HAVE_OPENAT=1; AC_SUBST([HAVE_OPENAT]) |
| 95 | - REPLACE_CREAT=0; AC_SUBST([REPLACE_CREAT]) |
| 96 | - REPLACE_FCNTL=0; AC_SUBST([REPLACE_FCNTL]) |
| 97 | - REPLACE_OPEN=0; AC_SUBST([REPLACE_OPEN]) |
| 98 | - REPLACE_OPENAT=0; AC_SUBST([REPLACE_OPENAT]) |
| 99 | + HAVE_FCNTL=1; AC_SUBST([HAVE_FCNTL]) |
| 100 | + HAVE_OPENAT=1; AC_SUBST([HAVE_OPENAT]) |
| 101 | + HAVE_FALLOCATE_POSIX=1; AC_SUBST([HAVE_FALLOCATE_POSIX]) |
| 102 | + REPLACE_CREAT=0; AC_SUBST([REPLACE_CREAT]) |
| 103 | + REPLACE_FCNTL=0; AC_SUBST([REPLACE_FCNTL]) |
| 104 | + REPLACE_OPEN=0; AC_SUBST([REPLACE_OPEN]) |
| 105 | + REPLACE_OPENAT=0; AC_SUBST([REPLACE_OPENAT]) |
| 106 | + REPLACE_FALLOCATE_POSIX=0; AC_SUBST([REPLACE_FALLOCATE_POSIX]) |
| 107 | ]) |
| 108 | --- a/modules/fcntl-h |
| 109 | +++ b/modules/fcntl-h |
| 110 | @@ -40,14 +40,17 @@ fcntl.h: fcntl.in.h $(top_builddir)/conf |
| 111 | -e 's/@''GNULIB_NONBLOCKING''@/$(GNULIB_NONBLOCKING)/g' \ |
| 112 | -e 's/@''GNULIB_OPEN''@/$(GNULIB_OPEN)/g' \ |
| 113 | -e 's/@''GNULIB_OPENAT''@/$(GNULIB_OPENAT)/g' \ |
| 114 | + -e 's/@''GNULIB_FALLOCATE_POSIX''@/$(GNULIB_FALLOCATE_POSIX)/g' \ |
| 115 | -e 's/@''GNULIB_MDA_CREAT''@/$(GNULIB_MDA_CREAT)/g' \ |
| 116 | -e 's/@''GNULIB_MDA_OPEN''@/$(GNULIB_MDA_OPEN)/g' \ |
| 117 | -e 's|@''HAVE_FCNTL''@|$(HAVE_FCNTL)|g' \ |
| 118 | -e 's|@''HAVE_OPENAT''@|$(HAVE_OPENAT)|g' \ |
| 119 | + -e 's|@''HAVE_FALLOCATE_POSIX''@|$(HAVE_FALLOCATE_POSIX)|g' \ |
| 120 | -e 's|@''REPLACE_CREAT''@|$(REPLACE_CREAT)|g' \ |
| 121 | -e 's|@''REPLACE_FCNTL''@|$(REPLACE_FCNTL)|g' \ |
| 122 | -e 's|@''REPLACE_OPEN''@|$(REPLACE_OPEN)|g' \ |
| 123 | -e 's|@''REPLACE_OPENAT''@|$(REPLACE_OPENAT)|g' \ |
| 124 | + -e 's|@''REPLACE_FALLOCATE_POSIX''@|$(REPLACE_FALLOCATE_POSIX)|g' \ |
| 125 | -e '/definitions of _GL_FUNCDECL_RPL/r $(CXXDEFS_H)' \ |
| 126 | -e '/definition of _GL_ARG_NONNULL/r $(ARG_NONNULL_H)' \ |
| 127 | -e '/definition of _GL_WARN_ON_USE/r $(WARN_ON_USE_H)' \ |
| 128 | --- a/lib/fcntl.in.h |
| 129 | +++ b/lib/fcntl.in.h |
| 130 | @@ -238,6 +238,33 @@ _GL_WARN_ON_USE (openat, "openat is not |
| 131 | # endif |
| 132 | #endif |
| 133 | |
| 134 | +#if @GNULIB_FALLOCATE_POSIX@ |
| 135 | +# if @REPLACE_FALLOCATE_POSIX@ |
| 136 | +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) |
| 137 | +# undef posix_fallocate |
| 138 | +# define posix_fallocate rpl_posix_fallocate |
| 139 | +# endif |
| 140 | +_GL_FUNCDECL_RPL (posix_fallocate, int, |
| 141 | + (int fd, off_t offset, off_t len)); |
| 142 | +_GL_CXXALIAS_RPL (posix_fallocate, int, |
| 143 | + (int fd, off_t offset, off_t len)); |
| 144 | +# else |
| 145 | +# if !@HAVE_FALLOCATE_POSIX@ |
| 146 | +_GL_FUNCDECL_SYS (posix_fallocate, int, |
| 147 | + (int fd, off_t offset, off_t len)); |
| 148 | +# endif |
| 149 | +_GL_CXXALIAS_SYS (posix_fallocate, int, |
| 150 | + (int fd, off_t offset, off_t len)); |
| 151 | +# endif |
| 152 | +_GL_CXXALIASWARN (posix_fallocate); |
| 153 | +#elif defined GNULIB_POSIXCHECK |
| 154 | +# undef posix_fallocate |
| 155 | +# if HAVE_RAW_DECL_POSIX_FALLOCATE |
| 156 | +_GL_WARN_ON_USE (posix_fallocate, "posix_fallocate is not portable - " |
| 157 | + "use gnulib module fallocate-posix for portability"); |
| 158 | +# endif |
| 159 | +#endif |
| 160 | + |
| 161 | |
| 162 | /* Fix up the FD_* macros, only known to be missing on mingw. */ |
| 163 | |
| 164 | --- /dev/null |
| 165 | +++ b/lib/posix_fallocate.c |
| 166 | @@ -0,0 +1,150 @@ |
| 167 | +/* posix_fallocate function that is glibc compatible. |
| 168 | + |
| 169 | + Copyright (C) 2024 Free Software Foundation, Inc. |
| 170 | + |
| 171 | + This file is free software: you can redistribute it and/or modify |
| 172 | + it under the terms of the GNU Lesser General Public License as |
| 173 | + published by the Free Software Foundation; either version 2.1 of the |
| 174 | + License, or (at your option) any later version. |
| 175 | + |
| 176 | + This file is distributed in the hope that it will be useful, |
| 177 | + but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 178 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 179 | + GNU Lesser General Public License for more details. |
| 180 | + |
| 181 | + You should have received a copy of the GNU Lesser General Public License |
| 182 | + along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
| 183 | + |
| 184 | +#include <config.h> |
| 185 | + |
| 186 | +#include <errno.h> |
| 187 | +#include <fcntl.h> |
| 188 | +#include <unistd.h> |
| 189 | +#include <stdint.h> |
| 190 | +#include <sys/fcntl.h> |
| 191 | +#include <sys/stat.h> |
| 192 | + |
| 193 | +#ifdef __APPLE__ |
| 194 | +# include <sys/param.h> |
| 195 | +# include <sys/mount.h> |
| 196 | +#else |
| 197 | +# include <sys/statfs.h> |
| 198 | +#endif |
| 199 | + |
| 200 | +/* Reserve storage for the data of the file associated with FD. This |
| 201 | + emulation is far from perfect, but the kernel cannot do not much |
| 202 | + better for network file systems, either. */ |
| 203 | + |
| 204 | +int |
| 205 | +posix_fallocate (int fd, off_t offset, off_t len) |
| 206 | +{ |
| 207 | + int ret; |
| 208 | + struct stat st; |
| 209 | + |
| 210 | + if (fd < 0 || offset < 0 || len < 0) |
| 211 | + return EINVAL; |
| 212 | + |
| 213 | + /* Perform overflow check. The outer cast relies on a GCC |
| 214 | + extension. */ |
| 215 | + if ((off_t) ((uint64_t) offset + (uint64_t) len) < 0) |
| 216 | + return EFBIG; |
| 217 | + |
| 218 | + /* pwrite below will not do the right thing in O_APPEND mode. */ |
| 219 | + { |
| 220 | + int flags = fcntl (fd, F_GETFL, 0); |
| 221 | + if (flags < 0 || (flags & O_APPEND) != 0) |
| 222 | + return EBADF; |
| 223 | + } |
| 224 | + |
| 225 | + /* We have to make sure that this is really a regular file. */ |
| 226 | + if (fstat (fd, &st) != 0) |
| 227 | + return EBADF; |
| 228 | + if (S_ISFIFO (st.st_mode)) |
| 229 | + return ESPIPE; |
| 230 | + if (! S_ISREG (st.st_mode)) |
| 231 | + return ENODEV; |
| 232 | + |
| 233 | + if (len == 0) |
| 234 | + { |
| 235 | + /* This is racy, but there is no good way to satisfy a |
| 236 | + zero-length allocation request. */ |
| 237 | + if (st.st_size < offset) |
| 238 | + { |
| 239 | + ret = ftruncate (fd, offset); |
| 240 | + |
| 241 | + if (ret != 0) |
| 242 | + ret = errno; |
| 243 | + return ret; |
| 244 | + } |
| 245 | + return ret; |
| 246 | + } |
| 247 | + |
| 248 | +#ifdef __APPLE__ |
| 249 | + fstore_t sto = {F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, offset + len, 0}; |
| 250 | + /* allocate continuous */ |
| 251 | + ret = fcntl (fd, F_PREALLOCATE, &sto); |
| 252 | + if (ret < 0) |
| 253 | + { |
| 254 | + /* allocate non-continuous */ |
| 255 | + sto.fst_flags = F_ALLOCATEALL; |
| 256 | + ret = fcntl (fd, F_PREALLOCATE, &sto); |
| 257 | + if (ret < 0) |
| 258 | + { |
| 259 | + return ret; |
| 260 | + } |
| 261 | + } |
| 262 | + ret = ftruncate(fd, offset + len); |
| 263 | +#else |
| 264 | + |
| 265 | + /* Minimize data transfer for network file systems, by issuing |
| 266 | + single-byte write requests spaced by the file system block size. |
| 267 | + (Most local file systems have fallocate support, so this fallback |
| 268 | + code is not used there.) */ |
| 269 | + |
| 270 | + unsigned increment; |
| 271 | + { |
| 272 | + struct statfs f; |
| 273 | + |
| 274 | + if (fstatfs (fd, &f) != 0) |
| 275 | + return errno; |
| 276 | + if (f.f_bsize == 0) |
| 277 | + increment = 512; |
| 278 | + else if (f.f_bsize < 4096) |
| 279 | + increment = f.f_bsize; |
| 280 | + else |
| 281 | + /* NFS does not propagate the block size of the underlying |
| 282 | + storage and may report a much larger value which would still |
| 283 | + leave holes after the loop below, so we cap the increment at |
| 284 | + 4096. */ |
| 285 | + increment = 4096; |
| 286 | + } |
| 287 | + |
| 288 | + /* Write a null byte to every block. This is racy; we currently |
| 289 | + lack a better option. Compare-and-swap against a file mapping |
| 290 | + might additional local races, but requires interposition of a |
| 291 | + signal handler to catch SIGBUS. */ |
| 292 | + for (offset += (len - 1) % increment; len > 0; offset += increment) |
| 293 | + { |
| 294 | + len -= increment; |
| 295 | + |
| 296 | + if (offset < st.st_size) |
| 297 | + { |
| 298 | + unsigned char c; |
| 299 | + ssize_t rsize = pread (fd, &c, 1, offset); |
| 300 | + |
| 301 | + if (rsize < 0) |
| 302 | + return errno; |
| 303 | + /* If there is a non-zero byte, the block must have been |
| 304 | + allocated already. */ |
| 305 | + else if (rsize == 1 && c != 0) |
| 306 | + continue; |
| 307 | + } |
| 308 | + |
| 309 | + if (pwrite (fd, "", 1, offset) != 1) |
| 310 | + return errno; |
| 311 | + } |
| 312 | + |
| 313 | +#endif /* __APPLE__ */ |
| 314 | + |
| 315 | + return ret; |
| 316 | +} |
| 317 | --- a/MODULES.html.sh |
| 318 | +++ b/MODULES.html.sh |
| 319 | @@ -2552,6 +2552,7 @@ func_all_modules () |
| 320 | func_module execve |
| 321 | func_module execvp |
| 322 | func_module execvpe |
| 323 | + func_module fallocate-posix |
| 324 | func_module fchdir |
| 325 | func_module fclose |
| 326 | func_module fcntl-h |