1
2
3
4
5
6
7
8
9
10
11
12
13#ifndef QEMU_9P_UTIL_H
14#define QEMU_9P_UTIL_H
15
16#include "qemu/error-report.h"
17
18#ifdef O_PATH
19#define O_PATH_9P_UTIL O_PATH
20#else
21#define O_PATH_9P_UTIL 0
22#endif
23
24#if !defined(CONFIG_LINUX)
25
26
27
28
29
30
31
32
33
34static inline uint64_t makedev_dotl(uint32_t dev_major, uint32_t dev_minor)
35{
36 uint64_t dev;
37
38
39 dev = (((uint64_t) (dev_major & 0x00000fffu)) << 8);
40 dev |= (((uint64_t) (dev_major & 0xfffff000u)) << 32);
41 dev |= (((uint64_t) (dev_minor & 0x000000ffu)) << 0);
42 dev |= (((uint64_t) (dev_minor & 0xffffff00u)) << 12);
43 return dev;
44}
45
46#endif
47
48
49
50
51
52
53
54static inline uint64_t host_dev_to_dotl_dev(dev_t dev)
55{
56#ifdef CONFIG_LINUX
57 return dev;
58#else
59 return makedev_dotl(major(dev), minor(dev));
60#endif
61}
62
63
64static inline int errno_to_dotl(int err) {
65#if defined(CONFIG_LINUX)
66
67#elif defined(CONFIG_DARWIN)
68
69
70
71
72
73
74 if (err == ENAMETOOLONG) {
75 err = 36;
76 } else if (err == ENOTEMPTY) {
77 err = 39;
78 } else if (err == ELOOP) {
79 err = 40;
80 } else if (err == ENOATTR) {
81 err = 61;
82 } else if (err == ENOTSUP) {
83 err = 95;
84 } else if (err == EOPNOTSUPP) {
85 err = 95;
86 }
87#else
88#error Missing errno translation to Linux for this host system
89#endif
90 return err;
91}
92
93#ifdef CONFIG_DARWIN
94#define qemu_fgetxattr(...) fgetxattr(__VA_ARGS__, 0, 0)
95#else
96#define qemu_fgetxattr fgetxattr
97#endif
98
99#define qemu_openat openat
100#define qemu_fstat fstat
101#define qemu_fstatat fstatat
102#define qemu_mkdirat mkdirat
103#define qemu_renameat renameat
104#define qemu_utimensat utimensat
105#define qemu_unlinkat unlinkat
106
107static inline void close_preserve_errno(int fd)
108{
109 int serrno = errno;
110 close(fd);
111 errno = serrno;
112}
113
114
115
116
117
118
119
120
121
122
123
124
125static inline int close_if_special_file(int fd)
126{
127 struct stat stbuf;
128
129 if (qemu_fstat(fd, &stbuf) < 0) {
130 close_preserve_errno(fd);
131 return -1;
132 }
133 if (!S_ISREG(stbuf.st_mode) && !S_ISDIR(stbuf.st_mode)) {
134 error_report_once(
135 "9p: broken or compromised client detected; attempt to open "
136 "special file (i.e. neither regular file, nor directory)"
137 );
138 close(fd);
139 errno = ENXIO;
140 return -1;
141 }
142
143 return 0;
144}
145
146static inline int openat_dir(int dirfd, const char *name)
147{
148 return qemu_openat(dirfd, name,
149 O_DIRECTORY | O_RDONLY | O_NOFOLLOW | O_PATH_9P_UTIL);
150}
151
152static inline int openat_file(int dirfd, const char *name, int flags,
153 mode_t mode)
154{
155 int fd, serrno, ret;
156
157#ifndef CONFIG_DARWIN
158again:
159#endif
160 fd = qemu_openat(dirfd, name, flags | O_NOFOLLOW | O_NOCTTY | O_NONBLOCK,
161 mode);
162 if (fd == -1) {
163#ifndef CONFIG_DARWIN
164 if (errno == EPERM && (flags & O_NOATIME)) {
165
166
167
168
169
170
171
172
173 flags &= ~O_NOATIME;
174 goto again;
175 }
176#endif
177 return -1;
178 }
179
180 if (close_if_special_file(fd) < 0) {
181 return -1;
182 }
183
184 serrno = errno;
185
186
187
188
189 if (!(flags & O_PATH_9P_UTIL)) {
190 ret = fcntl(fd, F_SETFL, flags);
191 assert(!ret);
192 }
193 errno = serrno;
194 return fd;
195}
196
197ssize_t fgetxattrat_nofollow(int dirfd, const char *path, const char *name,
198 void *value, size_t size);
199int fsetxattrat_nofollow(int dirfd, const char *path, const char *name,
200 void *value, size_t size, int flags);
201ssize_t flistxattrat_nofollow(int dirfd, const char *filename,
202 char *list, size_t size);
203ssize_t fremovexattrat_nofollow(int dirfd, const char *filename,
204 const char *name);
205
206
207
208
209
210
211
212static inline off_t qemu_dirent_off(struct dirent *dent)
213{
214#ifdef CONFIG_DARWIN
215 return dent->d_seekoff;
216#else
217 return dent->d_off;
218#endif
219}
220
221
222
223
224
225
226
227
228
229
230
231
232static inline struct dirent *qemu_dirent_dup(struct dirent *dent)
233{
234 size_t sz = 0;
235#if defined _DIRENT_HAVE_D_RECLEN
236
237 sz = dent->d_reclen;
238#endif
239
240
241
242
243 if (sz == 0) {
244
245 sz = offsetof(struct dirent, d_name) +
246 strlen(dent->d_name) + 1;
247 }
248 return g_memdup(dent, sz);
249}
250
251
252
253
254
255
256
257
258#if defined CONFIG_DARWIN && defined CONFIG_PTHREAD_FCHDIR_NP
259int pthread_fchdir_np(int fd) __attribute__((weak_import));
260#endif
261int qemu_mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev);
262
263#endif
264