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