Move to kernel style SPDX license identifiers
[babeltrace.git] / src / compat / fcntl.h
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2015 (c) Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 *
6 * fcntl compatibility layer.
7 */
8
9 #ifndef _BABELTRACE_COMPAT_FCNTL_H
10 #define _BABELTRACE_COMPAT_FCNTL_H
11
12 #include "common/common.h"
13
14 #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE
15
16 #include <fcntl.h>
17
18 static inline
19 int bt_posix_fallocate(int fd, off_t offset, off_t len)
20 {
21 return posix_fallocate(fd, offset, len);
22 }
23
24 #elif defined(__MINGW32__) /* #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE */
25
26 #include <stdlib.h>
27 #include <windows.h>
28 #include <fcntl.h>
29
30 static inline
31 int bt_posix_fallocate(int fd, off_t offset, off_t len)
32 {
33 HANDLE handle;
34 LARGE_INTEGER pos, file_pos, orig_end_offset, range_end;
35 int ret = 0;
36 char zero = 0;
37 DWORD byteswritten;
38
39 if (offset < 0 || len <= 0) {
40 ret = EINVAL;
41 goto end;
42 }
43
44 range_end.QuadPart = (__int64) offset + (__int64) len;
45
46 /* Get a handle from the fd */
47 handle = (HANDLE) _get_osfhandle(fd);
48 if (handle == INVALID_HANDLE_VALUE) {
49 ret = EBADF;
50 goto end;
51 }
52
53 /* Get the file original end offset */
54 ret = GetFileSizeEx(handle, &orig_end_offset);
55 if (ret == 0) {
56 ret = EBADF;
57 goto end;
58 }
59
60 /* Make sure we don't truncate the file */
61 if (orig_end_offset.QuadPart >= range_end.QuadPart) {
62 ret = 0;
63 goto end;
64 }
65
66 /* Get the current file pointer position */
67 pos.QuadPart = 0;
68 ret = SetFilePointerEx(handle, pos, &file_pos, FILE_CURRENT);
69 if (ret == 0) {
70 ret = EBADF;
71 goto end;
72 }
73
74 /* Move the file pointer to the new end offset */
75 ret = SetFilePointerEx(handle, range_end, NULL, FILE_BEGIN);
76 if (ret == 0) {
77 ret = EBADF;
78 goto end;
79 }
80
81 /* Sets the physical file size to the current position */
82 ret = SetEndOfFile(handle);
83 if (ret == 0) {
84 ret = EINVAL;
85 goto restore;
86 }
87
88 /*
89 * Move the file pointer back 1 byte, and write a single 0 at the
90 * last byte of the new end offset, the operating system will zero
91 * fill the file.
92 */
93 pos.QuadPart = -1;
94 ret = SetFilePointerEx(handle, pos, NULL, FILE_END);
95 if (ret == 0) {
96 ret = EBADF;
97 goto end;
98 }
99
100 ret = WriteFile(handle, &zero, 1, &byteswritten, NULL);
101 if (ret == 0 || byteswritten != 1) {
102 ret = ENOSPC;
103 } else {
104 ret = 0;
105 }
106
107 restore:
108 /* Restore the original file pointer position */
109 if (!SetFilePointerEx(handle, file_pos, NULL, FILE_BEGIN)) {
110 /* We moved the file pointer but failed to restore it. */
111 bt_common_abort();
112 }
113
114 end:
115 return ret;
116 }
117
118 #else
119
120 #include <sys/types.h>
121 #include <unistd.h>
122 #include <string.h>
123
124 #define BABELTRACE_FALLOCATE_BUFLEN 256
125
126 #ifndef min_t
127 #define min_t(type, a, b) \
128 ((type) (a) < (type) (b) ? (type) (a) : (type) (b))
129 #endif
130
131 static inline
132 int bt_posix_fallocate(int fd, off_t offset, off_t len)
133 {
134 int ret = 0;
135 ssize_t copy_len;
136 char buf[BABELTRACE_FALLOCATE_BUFLEN];
137 off_t i, file_pos, orig_end_offset, range_end;
138
139 if (offset < 0 || len < 0) {
140 ret = EINVAL;
141 goto end;
142 }
143
144 range_end = offset + len;
145 if (range_end < 0) {
146 ret = EFBIG;
147 goto end;
148 }
149
150 file_pos = lseek(fd, 0, SEEK_CUR);
151 if (file_pos < 0) {
152 ret = errno;
153 goto end;
154 }
155
156 orig_end_offset = lseek(fd, 0, SEEK_END);
157 if (orig_end_offset < 0) {
158 ret = errno;
159 goto end;
160 }
161
162 /* Seek back to original position. */
163 ret = lseek(fd, file_pos, SEEK_SET);
164 if (ret) {
165 ret = errno;
166 goto end;
167 }
168
169 /*
170 * The file may not need to grow, but we want to ensure the
171 * space has actually been reserved by the file system. First, copy
172 * the "existing" region of the file, then grow the file if needed.
173 */
174 for (i = file_pos; i < min_t(off_t, range_end, orig_end_offset);
175 i += copy_len) {
176 ssize_t copy_ret;
177
178 copy_len = min_t(size_t, BABELTRACE_FALLOCATE_BUFLEN,
179 min_t(off_t, range_end - i,
180 orig_end_offset - i));
181 copy_ret = pread(fd, &buf, copy_len, i);
182 if (copy_ret < copy_len) {
183 /*
184 * The caller must handle any EINTR.
185 * POSIX_FALLOCATE(3) does not mention EINTR.
186 * However, glibc does forward to fallocate()
187 * directly on Linux, which may be interrupted.
188 */
189 ret = errno;
190 goto end;
191 }
192
193 copy_ret = pwrite(fd, &buf, copy_len, i);
194 if (copy_ret < copy_len) {
195 /* Same caveat as noted at pread() */
196 ret = errno;
197 goto end;
198 }
199 }
200
201 /* Grow file, as necessary. */
202 memset(&buf, 0, BABELTRACE_FALLOCATE_BUFLEN);
203 for (i = orig_end_offset; i < range_end; i += copy_len) {
204 ssize_t write_ret;
205
206 copy_len = min_t(size_t, BABELTRACE_FALLOCATE_BUFLEN,
207 range_end - i);
208 write_ret = pwrite(fd, &buf, copy_len, i);
209 if (write_ret < copy_len) {
210 ret = errno;
211 goto end;
212 }
213 }
214 end:
215 return ret;
216 }
217 #endif /* #else #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE */
218
219 #endif /* _BABELTRACE_COMPAT_FCNTL_H */
This page took 0.034107 seconds and 4 git commands to generate.