blob: e30a7172aaf3b0e513fea0c70abba9f8e4447bfa [file] [log] [blame]
b.liue9582032025-04-17 19:18:16 +08001--- /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