1 #ifndef _BABELTRACE_COMPAT_FCNTL_H
2 #define _BABELTRACE_COMPAT_FCNTL_H
3 
4 /*
5  * babeltrace/compat/fcntl.h
6  *
7  * Copyright 2015 (c) - Jérémie Galarneau <jeremie.galarneau@efficios.com>
8  *
9  * fcntl compatibility layer.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE.
28  */
29 
30 #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE
31 
32 #include <fcntl.h>
33 
34 static inline
bt_posix_fallocate(int fd,off_t offset,off_t len)35 int bt_posix_fallocate(int fd, off_t offset, off_t len)
36 {
37 	return posix_fallocate(fd, offset, len);
38 }
39 
40 #else /* #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE */
41 
42 #include <sys/types.h>
43 #include <unistd.h>
44 #include <string.h>
45 
46 #define BABELTRACE_FALLOCATE_BUFLEN	256
47 
48 #ifndef min_t
49 #define min_t(type, a, b)	\
50 	((type) (a) < (type) (b) ? (type) (a) : (type) (b))
51 #endif
52 
53 static inline
bt_posix_fallocate(int fd,off_t offset,off_t len)54 int bt_posix_fallocate(int fd, off_t offset, off_t len)
55 {
56 	int ret = 0;
57 	ssize_t copy_len;
58 	char buf[BABELTRACE_FALLOCATE_BUFLEN];
59 	off_t i, file_pos, orig_end_offset, range_end;
60 
61 	if (offset < 0 || len < 0) {
62 		ret = EINVAL;
63 		goto end;
64 	}
65 
66 	range_end = offset + len;
67 	if (range_end < 0) {
68 		ret = EFBIG;
69 		goto end;
70 	}
71 
72 	file_pos = lseek(fd, 0, SEEK_CUR);
73 	if (file_pos < 0) {
74 		ret = errno;
75 		goto end;
76 	}
77 
78 	orig_end_offset = lseek(fd, 0, SEEK_END);
79 	if (orig_end_offset < 0) {
80 		ret = errno;
81 		goto end;
82 	}
83 
84 	/* Seek back to original position. */
85 	ret = lseek(fd, file_pos, SEEK_SET);
86 	if (ret) {
87 		ret = errno;
88 		goto end;
89 	}
90 
91 	/*
92 	 * The file may not need to grow, but we want to ensure the
93 	 * space has actually been reserved by the file system. First, copy
94 	 * the "existing" region of the file, then grow the file if needed.
95 	 */
96 	for (i = file_pos; i < min_t(off_t, range_end, orig_end_offset);
97 			i += copy_len) {
98 		ssize_t copy_ret;
99 
100 		copy_len = min_t(size_t, BABELTRACE_FALLOCATE_BUFLEN,
101 				min_t(off_t, range_end - i,
102 					orig_end_offset - i));
103 		copy_ret = pread(fd, &buf, copy_len, i);
104 		if (copy_ret < copy_len) {
105 			/*
106 			 * The caller must handle any EINTR.
107 			 * POSIX_FALLOCATE(3) does not mention EINTR.
108 			 * However, glibc does forward to fallocate()
109 			 * directly on Linux, which may be interrupted.
110 			 */
111 			ret = errno;
112 			goto end;
113 		}
114 
115 		copy_ret = pwrite(fd, &buf, copy_len, i);
116 		if (copy_ret < copy_len) {
117 			/* Same caveat as noted at pread() */
118 			ret = errno;
119 			goto end;
120 		}
121 	}
122 
123 	/* Grow file, as necessary. */
124 	memset(&buf, 0, BABELTRACE_FALLOCATE_BUFLEN);
125 	for (i = orig_end_offset; i < range_end; i += copy_len) {
126 		ssize_t write_ret;
127 
128 		copy_len = min_t(size_t, BABELTRACE_FALLOCATE_BUFLEN,
129 				range_end - i);
130 		write_ret = pwrite(fd, &buf, copy_len, i);
131 		if (write_ret < copy_len) {
132 			ret = errno;
133 			goto end;
134 		}
135 	}
136 end:
137 	return ret;
138 }
139 #endif /* #else #ifdef BABELTRACE_HAVE_POSIX_FALLOCATE */
140 
141 
142 #ifdef BABELTRACE_HAVE_FACCESSAT
143 
144 #include <fcntl.h>
145 #include <unistd.h>
146 
147 static inline
bt_faccessat(int dirfd,const char * dirname,const char * pathname,int mode,int flags)148 int bt_faccessat(int dirfd, const char *dirname,
149 		const char *pathname, int mode, int flags)
150 {
151 	return faccessat(dirfd, pathname, mode, flags);
152 }
153 
154 #else /* #ifdef BABELTRACE_HAVE_FACCESSAT */
155 
156 #include <string.h>
157 #include <unistd.h>
158 
159 static inline
bt_faccessat(int dirfd,const char * dirname,const char * pathname,int mode,int flags)160 int bt_faccessat(int dirfd, const char *dirname,
161 		const char *pathname, int mode, int flags)
162 {
163 	char cpath[PATH_MAX];
164 
165 	if (flags != 0) {
166 		errno = EINVAL;
167 		return -1;
168 	}
169 	/* Includes middle / and final \0. */
170 	if (strlen(dirname) + strlen(pathname) + 2 > PATH_MAX) {
171 		return -1;
172 	}
173 	strcpy(cpath, dirname);
174 	strcat(cpath, "/");
175 	strcat(cpath, pathname);
176 	return access(cpath, mode);
177 }
178 
179 #endif /* #else #ifdef BABELTRACE_HAVE_FACCESSAT */
180 
181 #endif /* _BABELTRACE_COMPAT_FCNTL_H */
182