Move to kernel style SPDX license identifiers
[babeltrace.git] / src / compat / fcntl.h
CommitLineData
a323afb2 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
a323afb2 3 *
0235b0db 4 * Copyright 2015 (c) Jérémie Galarneau <jeremie.galarneau@efficios.com>
a323afb2 5 *
0235b0db 6 * fcntl compatibility layer.
a323afb2
JG
7 */
8
0235b0db
MJ
9#ifndef _BABELTRACE_COMPAT_FCNTL_H
10#define _BABELTRACE_COMPAT_FCNTL_H
11
498e7994
PP
12#include "common/common.h"
13
a323afb2
JG
14#ifdef BABELTRACE_HAVE_POSIX_FALLOCATE
15
16#include <fcntl.h>
17
18static inline
19int bt_posix_fallocate(int fd, off_t offset, off_t len)
20{
21 return posix_fallocate(fd, offset, len);
22}
23
26fdbcef
MJ
24#elif defined(__MINGW32__) /* #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE */
25
f23a034a 26#include <stdlib.h>
26fdbcef
MJ
27#include <windows.h>
28#include <fcntl.h>
29
30static inline
31int 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
107restore:
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. */
498e7994 111 bt_common_abort();
26fdbcef
MJ
112 }
113
114end:
115 return ret;
116}
117
118#else
a323afb2
JG
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
131static inline
132int 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 }
214end:
215 return ret;
216}
217#endif /* #else #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE */
218
219#endif /* _BABELTRACE_COMPAT_FCNTL_H */
This page took 0.073577 seconds and 4 git commands to generate.