]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/posix/posix_fallocate64.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / posix / posix_fallocate64.c
CommitLineData
04277e02 1/* Copyright (C) 2000-2019 Free Software Foundation, Inc.
bb8e0116
UD
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
bb8e0116
UD
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 12 Lesser General Public License for more details.
bb8e0116 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6
PE
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
bb8e0116
UD
17
18#include <errno.h>
19#include <fcntl.h>
20#include <unistd.h>
7fe9e2e0
FW
21#include <stdint.h>
22#include <sys/fcntl.h>
bb8e0116
UD
23#include <sys/stat.h>
24#include <sys/statfs.h>
25
7fe9e2e0
FW
26/* Reserve storage for the data of the file associated with FD. This
27 emulation is far from perfect, but the kernel cannot do not much
28 better for network file systems, either. */
bb8e0116
UD
29
30int
089d05d5 31__posix_fallocate64_l64 (int fd, __off64_t offset, __off64_t len)
bb8e0116
UD
32{
33 struct stat64 st;
bb8e0116 34
089d05d5 35 if (offset < 0 || len < 0)
bb8e0116 36 return EINVAL;
7fe9e2e0
FW
37
38 /* Perform overflow check. The outer cast relies on a GCC
39 extension. */
543ef578 40 if ((__off64_t) ((uint64_t) offset + (uint64_t) len) < 0)
bb8e0116
UD
41 return EFBIG;
42
7fe9e2e0
FW
43 /* pwrite64 below will not do the right thing in O_APPEND mode. */
44 {
45 int flags = __fcntl (fd, F_GETFL, 0);
46 if (flags < 0 || (flags & O_APPEND) != 0)
47 return EBADF;
48 }
49
50 /* We have to make sure that this is really a regular file. */
bb8e0116
UD
51 if (__fxstat64 (_STAT_VER, fd, &st) != 0)
52 return EBADF;
53 if (S_ISFIFO (st.st_mode))
54 return ESPIPE;
55 if (! S_ISREG (st.st_mode))
56 return ENODEV;
57
fe80efd5
UD
58 if (len == 0)
59 {
7fe9e2e0
FW
60 /* This is racy, but there is no good way to satisfy a
61 zero-length allocation request. */
fe80efd5
UD
62 if (st.st_size < offset)
63 {
64 int ret = __ftruncate64 (fd, offset);
65
66 if (ret != 0)
67 ret = errno;
68 return ret;
69 }
70 return 0;
71 }
72
7fe9e2e0
FW
73 /* Minimize data transfer for network file systems, by issuing
74 single-byte write requests spaced by the file system block size.
75 (Most local file systems have fallocate support, so this fallback
76 code is not used there.) */
77
78 unsigned increment;
79 {
80 struct statfs64 f;
81
82 if (__fstatfs64 (fd, &f) != 0)
83 return errno;
84 if (f.f_bsize == 0)
85 increment = 512;
86 else if (f.f_bsize < 4096)
87 increment = f.f_bsize;
88 else
89 /* NFS clients do not propagate the block size of the underlying
90 storage and may report a much larger value which would still
91 leave holes after the loop below, so we cap the increment at
92 4096. */
93 increment = 4096;
94 }
95
96 /* Write a null byte to every block. This is racy; we currently
97 lack a better option. Compare-and-swap against a file mapping
98 might address local races, but requires interposition of a signal
99 handler to catch SIGBUS. */
100 for (offset += (len - 1) % increment; len > 0; offset += increment)
bb8e0116 101 {
7fe9e2e0 102 len -= increment;
fe80efd5
UD
103
104 if (offset < st.st_size)
105 {
106 unsigned char c;
0e66ade5 107 ssize_t rsize = __libc_pread64 (fd, &c, 1, offset);
fe80efd5
UD
108
109 if (rsize < 0)
110 return errno;
111 /* If there is a non-zero byte, the block must have been
112 allocated already. */
113 else if (rsize == 1 && c != 0)
114 continue;
115 }
a334319f 116
0e66ade5 117 if (__libc_pwrite64 (fd, "", 1, offset) != 1)
bb8e0116 118 return errno;
bb8e0116
UD
119 }
120
121 return 0;
122}
089d05d5 123
a95a608f 124#undef __posix_fallocate64_l64
089d05d5
UD
125#include <shlib-compat.h>
126#include <bits/wordsize.h>
127
128#if __WORDSIZE == 32 && SHLIB_COMPAT(libc, GLIBC_2_2, GLIBC_2_3_3)
129
130int
4a381a81 131attribute_compat_text_section
089d05d5
UD
132__posix_fallocate64_l32 (int fd, off64_t offset, size_t len)
133{
134 return __posix_fallocate64_l64 (fd, offset, len);
135}
136
137versioned_symbol (libc, __posix_fallocate64_l64, posix_fallocate64,
138 GLIBC_2_3_3);
139compat_symbol (libc, __posix_fallocate64_l32, posix_fallocate64, GLIBC_2_2);
140#else
141strong_alias (__posix_fallocate64_l64, posix_fallocate64);
142#endif