]> git.proxmox.com Git - mirror_qemu.git/blob - bsd-user/freebsd/os-stat.h
bsd-user: Implement freebsd11 stat related syscalls
[mirror_qemu.git] / bsd-user / freebsd / os-stat.h
1 /*
2 * stat related system call shims and definitions
3 *
4 * Copyright (c) 2013 Stacey D. Son
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifndef BSD_USER_FREEBSD_OS_STAT_H
21 #define BSD_USER_FREEBSD_OS_STAT_H
22
23 int freebsd11_stat(const char *path, struct freebsd11_stat *stat);
24 __sym_compat(stat, freebsd11_stat, FBSD_1.0);
25 int freebsd11_lstat(const char *path, struct freebsd11_stat *stat);
26 __sym_compat(lstat, freebsd11_lstat, FBSD_1.0);
27
28 /* stat(2) */
29 static inline abi_long do_freebsd11_stat(abi_long arg1, abi_long arg2)
30 {
31 abi_long ret;
32 void *p;
33 struct freebsd11_stat st;
34
35 LOCK_PATH(p, arg1);
36 ret = get_errno(freebsd11_stat(path(p), &st));
37 UNLOCK_PATH(p, arg1);
38 if (!is_error(ret)) {
39 ret = h2t_freebsd11_stat(arg2, &st);
40 }
41 return ret;
42 }
43
44 /* lstat(2) */
45 static inline abi_long do_freebsd11_lstat(abi_long arg1, abi_long arg2)
46 {
47 abi_long ret;
48 void *p;
49 struct freebsd11_stat st;
50
51 LOCK_PATH(p, arg1);
52 ret = get_errno(freebsd11_lstat(path(p), &st));
53 UNLOCK_PATH(p, arg1);
54 if (!is_error(ret)) {
55 ret = h2t_freebsd11_stat(arg2, &st);
56 }
57 return ret;
58 }
59
60 /* fstat(2) */
61 static inline abi_long do_freebsd_fstat(abi_long arg1, abi_long arg2)
62 {
63 abi_long ret;
64 struct stat st;
65
66 ret = get_errno(fstat(arg1, &st));
67 if (!is_error(ret)) {
68 ret = h2t_freebsd_stat(arg2, &st);
69 }
70 return ret;
71 }
72
73 /* fstatat(2) */
74 static inline abi_long do_freebsd_fstatat(abi_long arg1, abi_long arg2,
75 abi_long arg3, abi_long arg4)
76 {
77 abi_long ret;
78 void *p;
79 struct stat st;
80
81 LOCK_PATH(p, arg2);
82 ret = get_errno(fstatat(arg1, p, &st, arg4));
83 UNLOCK_PATH(p, arg2);
84 if (!is_error(ret) && arg3) {
85 ret = h2t_freebsd_stat(arg3, &st);
86 }
87 return ret;
88 }
89
90 /* undocummented nstat(char *path, struct nstat *ub) syscall */
91 static abi_long do_freebsd11_nstat(abi_long arg1, abi_long arg2)
92 {
93 abi_long ret;
94 void *p;
95 struct freebsd11_stat st;
96
97 LOCK_PATH(p, arg1);
98 ret = get_errno(freebsd11_nstat(path(p), &st));
99 UNLOCK_PATH(p, arg1);
100 if (!is_error(ret)) {
101 ret = h2t_freebsd11_nstat(arg2, &st);
102 }
103 return ret;
104 }
105
106 /* undocummented nfstat(int fd, struct nstat *sb) syscall */
107 static abi_long do_freebsd11_nfstat(abi_long arg1, abi_long arg2)
108 {
109 abi_long ret;
110 struct freebsd11_stat st;
111
112 ret = get_errno(freebsd11_nfstat(arg1, &st));
113 if (!is_error(ret)) {
114 ret = h2t_freebsd11_nstat(arg2, &st);
115 }
116 return ret;
117 }
118
119 /* undocummented nlstat(char *path, struct nstat *ub) syscall */
120 static abi_long do_freebsd11_nlstat(abi_long arg1, abi_long arg2)
121 {
122 abi_long ret;
123 void *p;
124 struct freebsd11_stat st;
125
126 LOCK_PATH(p, arg1);
127 ret = get_errno(freebsd11_nlstat(path(p), &st));
128 UNLOCK_PATH(p, arg1);
129 if (!is_error(ret)) {
130 ret = h2t_freebsd11_nstat(arg2, &st);
131 }
132 return ret;
133 }
134
135 /* getfh(2) */
136 static abi_long do_freebsd_getfh(abi_long arg1, abi_long arg2)
137 {
138 abi_long ret;
139 void *p;
140 fhandle_t host_fh;
141
142 LOCK_PATH(p, arg1);
143 ret = get_errno(getfh(path(p), &host_fh));
144 UNLOCK_PATH(p, arg1);
145 if (is_error(ret)) {
146 return ret;
147 }
148 return h2t_freebsd_fhandle(arg2, &host_fh);
149 }
150
151 /* lgetfh(2) */
152 static inline abi_long do_freebsd_lgetfh(abi_long arg1, abi_long arg2)
153 {
154 abi_long ret;
155 void *p;
156 fhandle_t host_fh;
157
158 LOCK_PATH(p, arg1);
159 ret = get_errno(lgetfh(path(p), &host_fh));
160 UNLOCK_PATH(p, arg1);
161 if (is_error(ret)) {
162 return ret;
163 }
164 return h2t_freebsd_fhandle(arg2, &host_fh);
165 }
166
167 /* fhopen(2) */
168 static inline abi_long do_freebsd_fhopen(abi_long arg1, abi_long arg2)
169 {
170 abi_long ret;
171 fhandle_t host_fh;
172
173 ret = t2h_freebsd_fhandle(&host_fh, arg1);
174 if (is_error(ret)) {
175 return ret;
176 }
177
178 return get_errno(fhopen(&host_fh, arg2));
179 }
180
181 /* fhstat(2) */
182 static inline abi_long do_freebsd_fhstat(abi_long arg1, abi_long arg2)
183 {
184 abi_long ret;
185 fhandle_t host_fh;
186 struct stat host_sb;
187
188 ret = t2h_freebsd_fhandle(&host_fh, arg1);
189 if (is_error(ret)) {
190 return ret;
191 }
192 ret = get_errno(fhstat(&host_fh, &host_sb));
193 if (is_error(ret)) {
194 return ret;
195 }
196 return h2t_freebsd_stat(arg2, &host_sb);
197 }
198
199 /* fhstatfs(2) */
200 static inline abi_long do_freebsd_fhstatfs(abi_ulong target_fhp_addr,
201 abi_ulong target_stfs_addr)
202 {
203 abi_long ret;
204 fhandle_t host_fh;
205 struct statfs host_stfs;
206
207 ret = t2h_freebsd_fhandle(&host_fh, target_fhp_addr);
208 if (is_error(ret)) {
209 return ret;
210 }
211 ret = get_errno(fhstatfs(&host_fh, &host_stfs));
212 if (is_error(ret)) {
213 return ret;
214 }
215 return h2t_freebsd_statfs(target_stfs_addr, &host_stfs);
216 }
217
218 /* statfs(2) */
219 static inline abi_long do_freebsd_statfs(abi_long arg1, abi_long arg2)
220 {
221 abi_long ret;
222 void *p;
223 struct statfs host_stfs;
224
225 LOCK_PATH(p, arg1);
226 ret = get_errno(statfs(path(p), &host_stfs));
227 UNLOCK_PATH(p, arg1);
228 if (is_error(ret)) {
229 return ret;
230 }
231
232 return h2t_freebsd_statfs(arg2, &host_stfs);
233 }
234
235 /* fstatfs(2) */
236 static inline abi_long do_freebsd_fstatfs(abi_long fd, abi_ulong target_addr)
237 {
238 abi_long ret;
239 struct statfs host_stfs;
240
241 ret = get_errno(fstatfs(fd, &host_stfs));
242 if (is_error(ret)) {
243 return ret;
244 }
245
246 return h2t_freebsd_statfs(target_addr, &host_stfs);
247 }
248
249 /* getfsstat(2) */
250 static inline abi_long do_freebsd_getfsstat(abi_ulong target_addr,
251 abi_long bufsize, abi_long flags)
252 {
253 abi_long ret;
254 struct statfs *host_stfs;
255 int count;
256 long host_bufsize;
257
258 count = bufsize / sizeof(struct target_statfs);
259
260 /* if user buffer is NULL then return number of mounted FS's */
261 if (target_addr == 0 || count == 0) {
262 return get_errno(freebsd11_getfsstat(NULL, 0, flags));
263 }
264
265 /* XXX check count to be reasonable */
266 host_bufsize = sizeof(struct statfs) * count;
267 host_stfs = alloca(host_bufsize);
268 if (!host_stfs) {
269 return -TARGET_EINVAL;
270 }
271
272 ret = count = get_errno(getfsstat(host_stfs, host_bufsize, flags));
273 if (is_error(ret)) {
274 return ret;
275 }
276
277 while (count--) {
278 if (h2t_freebsd_statfs((target_addr +
279 (count * sizeof(struct target_statfs))),
280 &host_stfs[count])) {
281 return -TARGET_EFAULT;
282 }
283 }
284 return ret;
285 }
286
287 /* getdents(2) */
288 static inline abi_long do_freebsd11_getdents(abi_long arg1,
289 abi_ulong arg2, abi_long nbytes)
290 {
291 abi_long ret;
292 struct freebsd11_dirent *dirp;
293
294 dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
295 if (dirp == NULL) {
296 return -TARGET_EFAULT;
297 }
298 ret = get_errno(freebsd11_getdents(arg1, (char *)dirp, nbytes));
299 if (!is_error(ret)) {
300 struct freebsd11_dirent *de;
301 int len = ret;
302 int reclen;
303
304 de = dirp;
305 while (len > 0) {
306 reclen = de->d_reclen;
307 if (reclen > len) {
308 return -TARGET_EFAULT;
309 }
310 de->d_reclen = tswap16(reclen);
311 de->d_fileno = tswap32(de->d_fileno);
312 len -= reclen;
313 }
314 }
315 return ret;
316 }
317
318 /* getdirecentries(2) */
319 static inline abi_long do_freebsd_getdirentries(abi_long arg1,
320 abi_ulong arg2, abi_long nbytes, abi_ulong arg4)
321 {
322 abi_long ret;
323 struct dirent *dirp;
324 long basep;
325
326 dirp = lock_user(VERIFY_WRITE, arg2, nbytes, 0);
327 if (dirp == NULL) {
328 return -TARGET_EFAULT;
329 }
330 ret = get_errno(getdirentries(arg1, (char *)dirp, nbytes, &basep));
331 if (!is_error(ret)) {
332 struct dirent *de;
333 int len = ret;
334 int reclen;
335
336 de = dirp;
337 while (len > 0) {
338 reclen = de->d_reclen;
339 if (reclen > len) {
340 return -TARGET_EFAULT;
341 }
342 de->d_fileno = tswap64(de->d_fileno);
343 de->d_off = tswap64(de->d_off);
344 de->d_reclen = tswap16(de->d_reclen);
345 de->d_namlen = tswap16(de->d_namlen);
346 len -= reclen;
347 de = (struct dirent *)((void *)de + reclen);
348 }
349 }
350 unlock_user(dirp, arg2, ret);
351 if (arg4) {
352 if (put_user(basep, arg4, abi_ulong)) {
353 return -TARGET_EFAULT;
354 }
355 }
356 return ret;
357 }
358
359 /* fcntl(2) */
360 static inline abi_long do_freebsd_fcntl(abi_long arg1, abi_long arg2,
361 abi_ulong arg3)
362 {
363 abi_long ret;
364 int host_cmd;
365 struct flock fl;
366 struct target_freebsd_flock *target_fl;
367
368 host_cmd = target_to_host_fcntl_cmd(arg2);
369 if (host_cmd < 0) {
370 return host_cmd;
371 }
372 switch (arg2) {
373 case TARGET_F_GETLK:
374 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
375 return -TARGET_EFAULT;
376 }
377 __get_user(fl.l_type, &target_fl->l_type);
378 __get_user(fl.l_whence, &target_fl->l_whence);
379 __get_user(fl.l_start, &target_fl->l_start);
380 __get_user(fl.l_len, &target_fl->l_len);
381 __get_user(fl.l_pid, &target_fl->l_pid);
382 __get_user(fl.l_sysid, &target_fl->l_sysid);
383 unlock_user_struct(target_fl, arg3, 0);
384 ret = get_errno(safe_fcntl(arg1, host_cmd, &fl));
385 if (!is_error(ret)) {
386 if (!lock_user_struct(VERIFY_WRITE, target_fl, arg3, 0)) {
387 return -TARGET_EFAULT;
388 }
389 __put_user(fl.l_type, &target_fl->l_type);
390 __put_user(fl.l_whence, &target_fl->l_whence);
391 __put_user(fl.l_start, &target_fl->l_start);
392 __put_user(fl.l_len, &target_fl->l_len);
393 __put_user(fl.l_pid, &target_fl->l_pid);
394 __put_user(fl.l_sysid, &target_fl->l_sysid);
395 unlock_user_struct(target_fl, arg3, 1);
396 }
397 break;
398
399 case TARGET_F_SETLK:
400 case TARGET_F_SETLKW:
401 if (!lock_user_struct(VERIFY_READ, target_fl, arg3, 1)) {
402 return -TARGET_EFAULT;
403 }
404 __get_user(fl.l_type, &target_fl->l_type);
405 __get_user(fl.l_whence, &target_fl->l_whence);
406 __get_user(fl.l_start, &target_fl->l_start);
407 __get_user(fl.l_len, &target_fl->l_len);
408 __get_user(fl.l_pid, &target_fl->l_pid);
409 __get_user(fl.l_sysid, &target_fl->l_sysid);
410 unlock_user_struct(target_fl, arg3, 0);
411 ret = get_errno(safe_fcntl(arg1, host_cmd, &fl));
412 break;
413
414 case TARGET_F_DUPFD:
415 case TARGET_F_DUP2FD:
416 case TARGET_F_GETOWN:
417 case TARGET_F_SETOWN:
418 case TARGET_F_GETFD:
419 case TARGET_F_SETFD:
420 case TARGET_F_GETFL:
421 case TARGET_F_SETFL:
422 case TARGET_F_READAHEAD:
423 case TARGET_F_RDAHEAD:
424 case TARGET_F_ADD_SEALS:
425 case TARGET_F_GET_SEALS:
426 default:
427 ret = get_errno(safe_fcntl(arg1, host_cmd, arg3));
428 break;
429 }
430 return ret;
431 }
432
433 #endif /* BSD_USER_FREEBSD_OS_STAT_H */