]> git.ipfire.org Git - thirdparty/glibc.git/blame - sysdeps/posix/posix_fallocate.c
Update copyright dates with scripts/update-copyrights.
[thirdparty/glibc.git] / sysdeps / posix / posix_fallocate.c
CommitLineData
f7a9f785 1/* Copyright (C) 2000-2016 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 31posix_fallocate (int fd, __off_t offset, __off_t len)
bb8e0116 32{
8edf6e0d 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 ((__off_t) ((uint64_t) offset + (uint64_t) len) < 0)
bb8e0116
UD
41 return EFBIG;
42
7fe9e2e0
FW
43 /* pwrite 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. */
8edf6e0d 51 if (__fxstat64 (_STAT_VER, fd, &st) != 0)
bb8e0116
UD
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 = __ftruncate (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 does 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 additional local races, but requires interposition of a
99 signal 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;
107 ssize_t rsize = __pread (fd, &c, 1, offset);
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 }
bb8e0116 116
4aebaa6b 117 if (__pwrite (fd, "", 1, offset) != 1)
bb8e0116 118 return errno;
bb8e0116
UD
119 }
120
121 return 0;
122}