util: Merge util_format_read_4* functions.
[mesa.git] / src / util / anon_file.c
1 /*
2 * Copyright © 2012 Collabora, Ltd.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 /*
27 * Based on weston shared/os-compatibility.c
28 */
29
30 #ifndef _WIN32
31 #include "anon_file.h"
32
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <errno.h>
36
37 #ifdef __FreeBSD__
38 #include <sys/mman.h>
39 #elif defined(HAVE_MEMFD_CREATE) || defined(ANDROID)
40 #include <sys/syscall.h>
41 #include <linux/memfd.h>
42 #include <stdlib.h>
43 #else
44 #include <stdio.h>
45 #include <stdlib.h>
46 #endif
47
48 #if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(HAVE_MKOSTEMP) || defined(ANDROID))
49 static int
50 set_cloexec_or_close(int fd)
51 {
52 long flags;
53
54 if (fd == -1)
55 return -1;
56
57 flags = fcntl(fd, F_GETFD);
58 if (flags == -1)
59 goto err;
60
61 if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
62 goto err;
63
64 return fd;
65
66 err:
67 close(fd);
68 return -1;
69 }
70 #endif
71
72 #if !(defined(__FreeBSD__) || defined(HAVE_MEMFD_CREATE) || defined(ANDROID))
73 static int
74 create_tmpfile_cloexec(char *tmpname)
75 {
76 int fd;
77
78 #ifdef HAVE_MKOSTEMP
79 fd = mkostemp(tmpname, O_CLOEXEC);
80 #else
81 fd = mkstemp(tmpname);
82 #endif
83
84 if (fd < 0) {
85 return fd;
86 }
87
88 #ifndef HAVE_MKOSTEMP
89 fd = set_cloexec_or_close(fd);
90 #endif
91
92 unlink(tmpname);
93 return fd;
94 }
95 #endif
96
97 /*
98 * Create a new, unique, anonymous file of the given size, and
99 * return the file descriptor for it. The file descriptor is set
100 * CLOEXEC. The file is immediately suitable for mmap()'ing
101 * the given size at offset zero.
102 *
103 * An optional name for debugging can be provided as the second argument.
104 *
105 * The file should not have a permanent backing store like a disk,
106 * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
107 *
108 * If memfd or SHM_ANON is supported, the filesystem is not touched at all.
109 * Otherwise, the file name is deleted from the file system.
110 *
111 * The file is suitable for buffer sharing between processes by
112 * transmitting the file descriptor over Unix sockets using the
113 * SCM_RIGHTS methods.
114 */
115 int
116 os_create_anonymous_file(off_t size, const char *debug_name)
117 {
118 int fd, ret;
119 #ifdef __FreeBSD__
120 (void*)debug_name;
121 fd = shm_open(SHM_ANON, O_CREAT | O_RDWR | O_CLOEXEC, 0600);
122 #elif defined(HAVE_MEMFD_CREATE) || defined(ANDROID)
123 if (!debug_name)
124 debug_name = "mesa-shared";
125 fd = syscall(SYS_memfd_create, debug_name, MFD_CLOEXEC);
126 #else
127 const char *path;
128 char *name;
129
130 path = getenv("XDG_RUNTIME_DIR");
131 if (!path) {
132 errno = ENOENT;
133 return -1;
134 }
135
136 if (debug_name)
137 asprintf(&name, "%s/mesa-shared-%s-XXXXXX", path, debug_name);
138 else
139 asprintf(&name, "%s/mesa-shared-XXXXXX", path);
140 if (!name)
141 return -1;
142
143 fd = create_tmpfile_cloexec(name);
144
145 free(name);
146 #endif
147
148 if (fd < 0)
149 return -1;
150
151 ret = ftruncate(fd, size);
152 if (ret < 0) {
153 close(fd);
154 return -1;
155 }
156
157 return fd;
158 }
159 #endif