xref: /netbsd-src/sys/compat/netbsd32/netbsd32_fs.c (revision 4d12bfcd155352508213ace5ccc59ce930ea2974)
1 /*	$NetBSD: netbsd32_fs.c,v 1.68 2013/07/30 17:22:31 njoly Exp $	*/
2 
3 /*
4  * Copyright (c) 1998, 2001 Matthew R. Green
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.68 2013/07/30 17:22:31 njoly Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/mount.h>
35 #include <sys/socket.h>
36 #include <sys/socketvar.h>
37 #include <sys/stat.h>
38 #include <sys/time.h>
39 #include <sys/ktrace.h>
40 #include <sys/resourcevar.h>
41 #include <sys/vnode.h>
42 #include <sys/file.h>
43 #include <sys/filedesc.h>
44 #include <sys/namei.h>
45 #include <sys/statvfs.h>
46 #include <sys/syscallargs.h>
47 #include <sys/proc.h>
48 #include <sys/dirent.h>
49 #include <sys/kauth.h>
50 #include <sys/vfs_syscalls.h>
51 
52 #include <fs/cd9660/cd9660_mount.h>
53 #include <fs/msdosfs/bpb.h>
54 #include <fs/msdosfs/msdosfsmount.h>
55 #include <ufs/ufs/ufsmount.h>
56 
57 #define NFS_ARGS_ONLY
58 #include <nfs/nfsmount.h>
59 
60 #include <compat/netbsd32/netbsd32.h>
61 #include <compat/netbsd32/netbsd32_syscallargs.h>
62 #include <compat/netbsd32/netbsd32_conv.h>
63 #include <compat/sys/mount.h>
64 
65 
66 static int dofilereadv32(int, struct file *, struct netbsd32_iovec *,
67 			      int, off_t *, int, register_t *);
68 static int dofilewritev32(int, struct file *, struct netbsd32_iovec *,
69 			       int,  off_t *, int, register_t *);
70 
71 struct iovec *
72 netbsd32_get_iov(struct netbsd32_iovec *iov32, int iovlen, struct iovec *aiov,
73     int aiov_len)
74 {
75 #define N_IOV32 8
76 	struct netbsd32_iovec aiov32[N_IOV32];
77 	struct iovec *iov = aiov;
78 	struct iovec *iovp;
79 	int i, n, j;
80 	int error;
81 
82 	if (iovlen < 0 || iovlen > IOV_MAX)
83 		return NULL;
84 
85 	if (iovlen > aiov_len)
86 		iov = kmem_alloc(iovlen * sizeof(*iov), KM_SLEEP);
87 
88 	iovp = iov;
89 	for (i = 0; i < iovlen; iov32 += N_IOV32, i += N_IOV32) {
90 		n = iovlen - i;
91 		if (n > N_IOV32)
92 			n = N_IOV32;
93 		error = copyin(iov32, aiov32, n * sizeof (*iov32));
94 		if (error != 0) {
95 			if (iov != aiov)
96 				kmem_free(iov, iovlen * sizeof(*iov));
97 			return NULL;
98 		}
99 		for (j = 0; j < n; iovp++, j++) {
100 			iovp->iov_base = NETBSD32PTR64(aiov32[j].iov_base);
101 			iovp->iov_len = aiov32[j].iov_len;
102 		}
103 	}
104 	return iov;
105 #undef N_IOV32
106 }
107 
108 int
109 netbsd32_readv(struct lwp *l, const struct netbsd32_readv_args *uap, register_t *retval)
110 {
111 	/* {
112 		syscallarg(int) fd;
113 		syscallarg(const netbsd32_iovecp_t) iovp;
114 		syscallarg(int) iovcnt;
115 	} */
116 	int fd = SCARG(uap, fd);
117 	file_t *fp;
118 
119 	if ((fp = fd_getfile(fd)) == NULL)
120 		return (EBADF);
121 
122 	if ((fp->f_flag & FREAD) == 0) {
123 		fd_putfile(fd);
124 		return (EBADF);
125 	}
126 
127 	return (dofilereadv32(fd, fp,
128 	    (struct netbsd32_iovec *)SCARG_P32(uap, iovp),
129 	    SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
130 }
131 
132 /* Damn thing copies in the iovec! */
133 int
134 dofilereadv32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval)
135 {
136 	struct uio auio;
137 	struct iovec *iov;
138 	struct iovec *needfree;
139 	struct iovec aiov[UIO_SMALLIOV];
140 	long i, cnt, error = 0;
141 	u_int iovlen;
142 	struct iovec *ktriov = NULL;
143 
144 	/* note: can't use iovlen until iovcnt is validated */
145 	iovlen = iovcnt * sizeof(struct iovec);
146 	if ((u_int)iovcnt > UIO_SMALLIOV) {
147 		if ((u_int)iovcnt > IOV_MAX) {
148 			error = EINVAL;
149 			goto out;
150 		}
151 		iov = kmem_alloc(iovlen, KM_SLEEP);
152 		needfree = iov;
153 	} else if ((u_int)iovcnt > 0) {
154 		iov = aiov;
155 		needfree = NULL;
156 	} else {
157 		error = EINVAL;
158 		goto out;
159 	}
160 
161 	auio.uio_iov = iov;
162 	auio.uio_iovcnt = iovcnt;
163 	auio.uio_rw = UIO_READ;
164 	auio.uio_vmspace = curproc->p_vmspace;
165 	error = netbsd32_to_iovecin(iovp, iov, iovcnt);
166 	if (error)
167 		goto done;
168 	auio.uio_resid = 0;
169 	for (i = 0; i < iovcnt; i++) {
170 		auio.uio_resid += iov->iov_len;
171 		/*
172 		 * Reads return ssize_t because -1 is returned on error.
173 		 * Therefore we must restrict the length to SSIZE_MAX to
174 		 * avoid garbage return values.
175 		 */
176 		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
177 			error = EINVAL;
178 			goto done;
179 		}
180 		iov++;
181 	}
182 
183 	/*
184 	 * if tracing, save a copy of iovec
185 	 */
186 	if (ktrpoint(KTR_GENIO)) {
187 		ktriov = kmem_alloc(iovlen, KM_SLEEP);
188 		memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen);
189 	}
190 
191 	cnt = auio.uio_resid;
192 	error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags);
193 	if (error)
194 		if (auio.uio_resid != cnt && (error == ERESTART ||
195 		    error == EINTR || error == EWOULDBLOCK))
196 			error = 0;
197 	cnt -= auio.uio_resid;
198 
199 	if (ktriov != NULL) {
200 		ktrgeniov(fd, UIO_READ, ktriov, cnt, error);
201 		kmem_free(ktriov, iovlen);
202 	}
203 
204 	*retval = cnt;
205 done:
206 	if (needfree)
207 		kmem_free(needfree, iovlen);
208 out:
209 	fd_putfile(fd);
210 	return (error);
211 }
212 
213 int
214 netbsd32_writev(struct lwp *l, const struct netbsd32_writev_args *uap, register_t *retval)
215 {
216 	/* {
217 		syscallarg(int) fd;
218 		syscallarg(const netbsd32_iovecp_t) iovp;
219 		syscallarg(int) iovcnt;
220 	} */
221 	int fd = SCARG(uap, fd);
222 	file_t *fp;
223 
224 	if ((fp = fd_getfile(fd)) == NULL)
225 		return (EBADF);
226 
227 	if ((fp->f_flag & FWRITE) == 0) {
228 		fd_putfile(fd);
229 		return (EBADF);
230 	}
231 
232 	return (dofilewritev32(fd, fp,
233 	    (struct netbsd32_iovec *)SCARG_P32(uap, iovp),
234 	    SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
235 }
236 
237 int
238 dofilewritev32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval)
239 {
240 	struct uio auio;
241 	struct iovec *iov;
242 	struct iovec *needfree;
243 	struct iovec aiov[UIO_SMALLIOV];
244 	long i, cnt, error = 0;
245 	u_int iovlen;
246 	struct iovec *ktriov = NULL;
247 
248 	/* note: can't use iovlen until iovcnt is validated */
249 	iovlen = iovcnt * sizeof(struct iovec);
250 	if ((u_int)iovcnt > UIO_SMALLIOV) {
251 		if ((u_int)iovcnt > IOV_MAX) {
252 			error = EINVAL;
253 			goto out;
254 		}
255 		iov = kmem_alloc(iovlen, KM_SLEEP);
256 		needfree = iov;
257 	} else if ((u_int)iovcnt > 0) {
258 		iov = aiov;
259 		needfree = NULL;
260 	} else {
261 		error = EINVAL;
262 		goto out;
263 	}
264 
265 	auio.uio_iov = iov;
266 	auio.uio_iovcnt = iovcnt;
267 	auio.uio_rw = UIO_WRITE;
268 	auio.uio_vmspace = curproc->p_vmspace;
269 	error = netbsd32_to_iovecin(iovp, iov, iovcnt);
270 	if (error)
271 		goto done;
272 	auio.uio_resid = 0;
273 	for (i = 0; i < iovcnt; i++) {
274 		auio.uio_resid += iov->iov_len;
275 		/*
276 		 * Writes return ssize_t because -1 is returned on error.
277 		 * Therefore we must restrict the length to SSIZE_MAX to
278 		 * avoid garbage return values.
279 		 */
280 		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
281 			error = EINVAL;
282 			goto done;
283 		}
284 		iov++;
285 	}
286 
287 	/*
288 	 * if tracing, save a copy of iovec
289 	 */
290 	if (ktrpoint(KTR_GENIO))  {
291 		ktriov = kmem_alloc(iovlen, KM_SLEEP);
292 		memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen);
293 	}
294 
295 	cnt = auio.uio_resid;
296 	error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags);
297 	if (error) {
298 		if (auio.uio_resid != cnt && (error == ERESTART ||
299 		    error == EINTR || error == EWOULDBLOCK))
300 			error = 0;
301 		if (error == EPIPE && (fp->f_flag & FNOSIGPIPE) == 0) {
302 			mutex_enter(proc_lock);
303 			psignal(curproc, SIGPIPE);
304 			mutex_exit(proc_lock);
305 		}
306 	}
307 	cnt -= auio.uio_resid;
308 	if (ktriov != NULL) {
309 		ktrgenio(fd, UIO_WRITE, ktriov, cnt, error);
310 		kmem_free(ktriov, iovlen);
311 	}
312 	*retval = cnt;
313 done:
314 	if (needfree)
315 		kmem_free(needfree, iovlen);
316 out:
317 	fd_putfile(fd);
318 	return (error);
319 }
320 
321 /*
322  * Common routines to set access and modification times given a vnode.
323  */
324 static int
325 get_utimes32(const netbsd32_timevalp_t *tptr, struct timeval *tv,
326     struct timeval **tvp)
327 {
328 	int error;
329 	struct netbsd32_timeval tv32[2];
330 
331 	if (tptr == NULL) {
332 		*tvp = NULL;
333 		return 0;
334 	}
335 
336 	error = copyin(tptr, tv32, sizeof(tv32));
337 	if (error)
338 		return error;
339 	netbsd32_to_timeval(&tv32[0], &tv[0]);
340 	netbsd32_to_timeval(&tv32[1], &tv[1]);
341 
342 	*tvp = tv;
343 	return 0;
344 }
345 
346 static int
347 get_utimens32(const netbsd32_timespecp_t *tptr, struct timespec *ts,
348     struct timespec **tsp)
349 {
350 	int error;
351 	struct netbsd32_timespec ts32[2];
352 
353 	if (tptr == NULL) {
354 		*tsp = NULL;
355 		return 0;
356 	}
357 
358 	error = copyin(tptr, ts32, sizeof(ts32));
359 	if (error)
360 		return error;
361 	netbsd32_to_timespec(&ts32[0], &ts[0]);
362 	netbsd32_to_timespec(&ts32[1], &ts[1]);
363 
364 	*tsp = ts;
365 	return 0;
366 }
367 
368 int
369 netbsd32___utimes50(struct lwp *l, const struct netbsd32___utimes50_args *uap, register_t *retval)
370 {
371 	/* {
372 		syscallarg(const netbsd32_charp) path;
373 		syscallarg(const netbsd32_timevalp_t) tptr;
374 	} */
375 	int error;
376 	struct timeval tv[2], *tvp;
377 
378 	error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
379 	if (error != 0)
380 		return error;
381 
382 	return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW,
383 			    tvp, UIO_SYSSPACE);
384 }
385 
386 static int
387 netbds32_copyout_statvfs(const void *kp, void *up, size_t len)
388 {
389 	struct netbsd32_statvfs *sbuf_32;
390 	int error;
391 
392 	sbuf_32 = kmem_alloc(sizeof(*sbuf_32), KM_SLEEP);
393 	netbsd32_from_statvfs(kp, sbuf_32);
394 	error = copyout(sbuf_32, up, sizeof(*sbuf_32));
395 	kmem_free(sbuf_32, sizeof(*sbuf_32));
396 
397 	return error;
398 }
399 
400 int
401 netbsd32_statvfs1(struct lwp *l, const struct netbsd32_statvfs1_args *uap, register_t *retval)
402 {
403 	/* {
404 		syscallarg(const netbsd32_charp) path;
405 		syscallarg(netbsd32_statvfsp_t) buf;
406 		syscallarg(int) flags;
407 	} */
408 	struct statvfs *sb;
409 	int error;
410 
411 	sb = STATVFSBUF_GET();
412 	error = do_sys_pstatvfs(l, SCARG_P32(uap, path), SCARG(uap, flags), sb);
413 	if (error == 0)
414 		error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
415 	STATVFSBUF_PUT(sb);
416 	return error;
417 }
418 
419 int
420 netbsd32_fstatvfs1(struct lwp *l, const struct netbsd32_fstatvfs1_args *uap, register_t *retval)
421 {
422 	/* {
423 		syscallarg(int) fd;
424 		syscallarg(netbsd32_statvfsp_t) buf;
425 		syscallarg(int) flags;
426 	} */
427 	struct statvfs *sb;
428 	int error;
429 
430 	sb = STATVFSBUF_GET();
431 	error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb);
432 	if (error == 0)
433 		error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
434 	STATVFSBUF_PUT(sb);
435 	return error;
436 }
437 
438 int
439 netbsd32_getvfsstat(struct lwp *l, const struct netbsd32_getvfsstat_args *uap, register_t *retval)
440 {
441 	/* {
442 		syscallarg(netbsd32_statvfsp_t) buf;
443 		syscallarg(netbsd32_size_t) bufsize;
444 		syscallarg(int) flags;
445 	} */
446 
447 	return do_sys_getvfsstat(l, SCARG_P32(uap, buf), SCARG(uap, bufsize),
448 	    SCARG(uap, flags), netbds32_copyout_statvfs,
449 	    sizeof (struct netbsd32_statvfs), retval);
450 }
451 
452 int
453 netbsd32___fhstatvfs140(struct lwp *l, const struct netbsd32___fhstatvfs140_args *uap, register_t *retval)
454 {
455 	/* {
456 		syscallarg(const netbsd32_pointer_t) fhp;
457 		syscallarg(netbsd32_size_t) fh_size;
458 		syscallarg(netbsd32_statvfsp_t) buf;
459 		syscallarg(int) flags;
460 	} */
461 	struct statvfs *sb;
462 	int error;
463 
464 	sb = STATVFSBUF_GET();
465 	error = do_fhstatvfs(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), sb,
466 	    SCARG(uap, flags));
467 
468 	if (error == 0)
469 		error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
470 	STATVFSBUF_PUT(sb);
471 
472 	return error;
473 }
474 
475 int
476 netbsd32___futimes50(struct lwp *l, const struct netbsd32___futimes50_args *uap, register_t *retval)
477 {
478 	/* {
479 		syscallarg(int) fd;
480 		syscallarg(const netbsd32_timevalp_t) tptr;
481 	} */
482 	int error;
483 	file_t *fp;
484 	struct timeval tv[2], *tvp;
485 
486 	error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
487 	if (error != 0)
488 		return error;
489 
490 	/* fd_getvnode() will use the descriptor for us */
491 	if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
492 		return (error);
493 
494 	error = do_sys_utimes(l, fp->f_data, NULL, 0, tvp, UIO_SYSSPACE);
495 
496 	fd_putfile(SCARG(uap, fd));
497 	return (error);
498 }
499 
500 int
501 netbsd32___getdents30(struct lwp *l,
502     const struct netbsd32___getdents30_args *uap, register_t *retval)
503 {
504 	/* {
505 		syscallarg(int) fd;
506 		syscallarg(netbsd32_charp) buf;
507 		syscallarg(netbsd32_size_t) count;
508 	} */
509 	file_t *fp;
510 	int error, done;
511 
512 	/* fd_getvnode() will use the descriptor for us */
513 	if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
514 		return (error);
515 	if ((fp->f_flag & FREAD) == 0) {
516 		error = EBADF;
517 		goto out;
518 	}
519 	error = vn_readdir(fp, SCARG_P32(uap, buf),
520 	    UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0);
521 	*retval = done;
522  out:
523 	fd_putfile(SCARG(uap, fd));
524 	return (error);
525 }
526 
527 int
528 netbsd32___lutimes50(struct lwp *l,
529     const struct netbsd32___lutimes50_args *uap, register_t *retval)
530 {
531 	/* {
532 		syscallarg(const netbsd32_charp) path;
533 		syscallarg(const netbsd32_timevalp_t) tptr;
534 	} */
535 	int error;
536 	struct timeval tv[2], *tvp;
537 
538 	error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
539 	if (error != 0)
540 		return error;
541 
542 	return do_sys_utimes(l, NULL, SCARG_P32(uap, path), NOFOLLOW,
543 			    tvp, UIO_SYSSPACE);
544 }
545 
546 int
547 netbsd32___stat50(struct lwp *l, const struct netbsd32___stat50_args *uap, register_t *retval)
548 {
549 	/* {
550 		syscallarg(const netbsd32_charp) path;
551 		syscallarg(netbsd32_statp_t) ub;
552 	} */
553 	struct netbsd32_stat sb32;
554 	struct stat sb;
555 	int error;
556 	const char *path;
557 
558 	path = SCARG_P32(uap, path);
559 
560 	error = do_sys_stat(path, FOLLOW, &sb);
561 	if (error)
562 		return (error);
563 	netbsd32_from_stat(&sb, &sb32);
564 	error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32));
565 	return (error);
566 }
567 
568 int
569 netbsd32___fstat50(struct lwp *l, const struct netbsd32___fstat50_args *uap, register_t *retval)
570 {
571 	/* {
572 		syscallarg(int) fd;
573 		syscallarg(netbsd32_statp_t) sb;
574 	} */
575 	struct netbsd32_stat sb32;
576 	struct stat ub;
577 	int error;
578 
579 	error = do_sys_fstat(SCARG(uap, fd), &ub);
580 	if (error == 0) {
581 		netbsd32_from_stat(&ub, &sb32);
582 		error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb32));
583 	}
584 	return (error);
585 }
586 
587 int
588 netbsd32___lstat50(struct lwp *l, const struct netbsd32___lstat50_args *uap, register_t *retval)
589 {
590 	/* {
591 		syscallarg(const netbsd32_charp) path;
592 		syscallarg(netbsd32_statp_t) ub;
593 	} */
594 	struct netbsd32_stat sb32;
595 	struct stat sb;
596 	int error;
597 	const char *path;
598 
599 	path = SCARG_P32(uap, path);
600 
601 	error = do_sys_stat(path, NOFOLLOW, &sb);
602 	if (error)
603 		return (error);
604 	netbsd32_from_stat(&sb, &sb32);
605 	error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32));
606 	return (error);
607 }
608 
609 int
610 netbsd32___fhstat50(struct lwp *l, const struct netbsd32___fhstat50_args *uap, register_t *retval)
611 {
612 	/* {
613 		syscallarg(const netbsd32_pointer_t) fhp;
614 		syscallarg(netbsd32_size_t) fh_size;
615 		syscallarg(netbsd32_statp_t) sb;
616 	} */
617 	struct stat sb;
618 	struct netbsd32_stat sb32;
619 	int error;
620 
621 	error = do_fhstat(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), &sb);
622 	if (error == 0) {
623 		netbsd32_from_stat(&sb, &sb32);
624 		error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb));
625 	}
626 	return error;
627 }
628 
629 int
630 netbsd32_preadv(struct lwp *l, const struct netbsd32_preadv_args *uap, register_t *retval)
631 {
632 	/* {
633 		syscallarg(int) fd;
634 		syscallarg(const netbsd32_iovecp_t) iovp;
635 		syscallarg(int) iovcnt;
636 		syscallarg(int) pad;
637 		syscallarg(off_t) offset;
638 	} */
639 	file_t *fp;
640 	struct vnode *vp;
641 	off_t offset;
642 	int error, fd = SCARG(uap, fd);
643 
644 	if ((fp = fd_getfile(fd)) == NULL)
645 		return (EBADF);
646 
647 	if ((fp->f_flag & FREAD) == 0) {
648 		fd_putfile(fd);
649 		return (EBADF);
650 	}
651 
652 	vp = fp->f_data;
653 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
654 		error = ESPIPE;
655 		goto out;
656 	}
657 
658 	offset = SCARG(uap, offset);
659 
660 	/*
661 	 * XXX This works because no file systems actually
662 	 * XXX take any action on the seek operation.
663 	 */
664 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
665 		goto out;
666 
667 	return (dofilereadv32(fd, fp, SCARG_P32(uap, iovp),
668 	    SCARG(uap, iovcnt), &offset, 0, retval));
669 
670 out:
671 	fd_putfile(fd);
672 	return (error);
673 }
674 
675 int
676 netbsd32_pwritev(struct lwp *l, const struct netbsd32_pwritev_args *uap, register_t *retval)
677 {
678 	/* {
679 		syscallarg(int) fd;
680 		syscallarg(const netbsd32_iovecp_t) iovp;
681 		syscallarg(int) iovcnt;
682 		syscallarg(int) pad;
683 		syscallarg(off_t) offset;
684 	} */
685 	file_t *fp;
686 	struct vnode *vp;
687 	off_t offset;
688 	int error, fd = SCARG(uap, fd);
689 
690 	if ((fp = fd_getfile(fd)) == NULL)
691 		return (EBADF);
692 
693 	if ((fp->f_flag & FWRITE) == 0) {
694 		fd_putfile(fd);
695 		return (EBADF);
696 	}
697 
698 	vp = fp->f_data;
699 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
700 		error = ESPIPE;
701 		goto out;
702 	}
703 
704 	offset = SCARG(uap, offset);
705 
706 	/*
707 	 * XXX This works because no file systems actually
708 	 * XXX take any action on the seek operation.
709 	 */
710 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
711 		goto out;
712 
713 	return (dofilewritev32(fd, fp, SCARG_P32(uap, iovp),
714 	    SCARG(uap, iovcnt), &offset, 0, retval));
715 
716 out:
717 	fd_putfile(fd);
718 	return (error);
719 }
720 
721 /*
722  * Find pathname of process's current directory.
723  *
724  * Use vfs vnode-to-name reverse cache; if that fails, fall back
725  * to reading directory contents.
726  */
727 /* XXX NH Why does this exist */
728 int
729 getcwd_common(struct vnode *, struct vnode *,
730 		   char **, char *, int, int, struct lwp *);
731 
732 int
733 netbsd32___getcwd(struct lwp *l, const struct netbsd32___getcwd_args *uap, register_t *retval)
734 {
735 	/* {
736 		syscallarg(char *) bufp;
737 		syscallarg(size_t) length;
738 	} */
739 	struct proc *p = l->l_proc;
740 	int     error;
741 	char   *path;
742 	char   *bp, *bend;
743 	int     len = (int)SCARG(uap, length);
744 	int	lenused;
745 	struct	cwdinfo *cwdi;
746 
747 	if (len > MAXPATHLEN*4)
748 		len = MAXPATHLEN*4;
749 	else if (len < 2)
750 		return ERANGE;
751 
752 	path = kmem_alloc(len, KM_SLEEP);
753 	if (!path)
754 		return ENOMEM;
755 
756 	bp = &path[len];
757 	bend = bp;
758 	*(--bp) = '\0';
759 
760 	/*
761 	 * 5th argument here is "max number of vnodes to traverse".
762 	 * Since each entry takes up at least 2 bytes in the output buffer,
763 	 * limit it to N/2 vnodes for an N byte buffer.
764 	 */
765 #define GETCWD_CHECK_ACCESS 0x0001
766 	cwdi = p->p_cwdi;
767 	rw_enter(&cwdi->cwdi_lock, RW_READER);
768 	error = getcwd_common (cwdi->cwdi_cdir, NULL, &bp, path, len/2,
769 			       GETCWD_CHECK_ACCESS, l);
770 	rw_exit(&cwdi->cwdi_lock);
771 
772 	if (error)
773 		goto out;
774 	lenused = bend - bp;
775 	*retval = lenused;
776 	/* put the result into user buffer */
777 	error = copyout(bp, SCARG_P32(uap, bufp), lenused);
778 
779 out:
780 	kmem_free(path, len);
781 	return error;
782 }
783 
784 int
785 netbsd32___mount50(struct lwp *l, const struct netbsd32___mount50_args *uap,
786 	register_t *retval)
787 {
788 	/* {
789 		syscallarg(netbsd32_charp) type;
790 		syscallarg(netbsd32_charp) path;
791 		syscallarg(int) flags;
792 		syscallarg(netbsd32_voidp) data;
793 		syscallarg(netbsd32_size_t) data_len;
794 	} */
795 	char mtype[MNAMELEN];
796 	union {
797 		struct netbsd32_ufs_args ufs_args;
798 		struct netbsd32_mfs_args mfs_args;
799 		struct netbsd32_iso_args iso_args;
800 		struct netbsd32_nfs_args nfs_args;
801 		struct netbsd32_msdosfs_args msdosfs_args;
802 	} fs_args32;
803 	union {
804 		struct ufs_args ufs_args;
805 		struct mfs_args mfs_args;
806 		struct iso_args iso_args;
807 		struct nfs_args nfs_args;
808 		struct msdosfs_args msdosfs_args;
809 	} fs_args;
810 	const char *type = SCARG_P32(uap, type);
811 	const char *path = SCARG_P32(uap, path);
812 	int flags = SCARG(uap, flags);
813 	void *data = SCARG_P32(uap, data);
814 	size_t data_len = SCARG(uap, data_len);
815 	enum uio_seg data_seg;
816 	size_t len;
817 	int error;
818 
819 	error = copyinstr(type, mtype, sizeof(mtype), &len);
820 	if (error)
821 		return error;
822 	if (strcmp(mtype, MOUNT_MFS) == 0) {
823 		if (data_len != sizeof(fs_args32.mfs_args))
824 			return EINVAL;
825 		if ((flags & MNT_GETARGS) == 0) {
826 			error = copyin(data, &fs_args32.mfs_args,
827 			    sizeof(fs_args32.mfs_args));
828 			if (error)
829 				return error;
830 			fs_args.mfs_args.fspec =
831 			    NETBSD32PTR64(fs_args32.mfs_args.fspec);
832 			memset(&fs_args.mfs_args._pad1, 0,
833 			    sizeof(fs_args.mfs_args._pad1));
834 			fs_args.mfs_args.base =
835 			    NETBSD32PTR64(fs_args32.mfs_args.base);
836 			fs_args.mfs_args.size = fs_args32.mfs_args.size;
837 		}
838 		data_seg = UIO_SYSSPACE;
839 		data = &fs_args.mfs_args;
840 		data_len = sizeof(fs_args.mfs_args);
841 	} else if ((strcmp(mtype, MOUNT_UFS) == 0) ||
842 		   (strcmp(mtype, MOUNT_EXT2FS) == 0) ||
843 		   (strcmp(mtype, MOUNT_LFS) == 0)) {
844 		if (data_len > sizeof(fs_args32.ufs_args))
845 			return EINVAL;
846 		if ((flags & MNT_GETARGS) == 0) {
847 			error = copyin(data, &fs_args32.ufs_args,
848 			    sizeof(fs_args32.ufs_args));
849 			if (error)
850 				return error;
851 			fs_args.ufs_args.fspec =
852 			    NETBSD32PTR64(fs_args32.ufs_args.fspec);
853 		}
854 		data_seg = UIO_SYSSPACE;
855 		data = &fs_args.ufs_args;
856 		data_len = sizeof(fs_args.ufs_args);
857 	} else if (strcmp(mtype, MOUNT_CD9660) == 0) {
858 		if (data_len != sizeof(fs_args32.iso_args))
859 			return EINVAL;
860 		if ((flags & MNT_GETARGS) == 0) {
861 			error = copyin(data, &fs_args32.iso_args,
862 			    sizeof(fs_args32.iso_args));
863 			if (error)
864 				return error;
865 			fs_args.iso_args.fspec =
866 			    NETBSD32PTR64(fs_args32.iso_args.fspec);
867 			memset(&fs_args.iso_args._pad1, 0,
868 			    sizeof(fs_args.iso_args._pad1));
869 			fs_args.iso_args.flags = fs_args32.iso_args.flags;
870 		}
871 		data_seg = UIO_SYSSPACE;
872 		data = &fs_args.iso_args;
873 		data_len = sizeof(fs_args.iso_args);
874 	} else if (strcmp(mtype, MOUNT_MSDOS) == 0) {
875 		if (data_len != sizeof(fs_args32.msdosfs_args))
876 			return EINVAL;
877 		if ((flags & MNT_GETARGS) == 0) {
878 			error = copyin(data, &fs_args32.msdosfs_args,
879 			    sizeof(fs_args32.msdosfs_args));
880 			if (error)
881 				return error;
882 			fs_args.msdosfs_args.fspec =
883 			    NETBSD32PTR64(fs_args32.msdosfs_args.fspec);
884 			memset(&fs_args.msdosfs_args._pad1, 0,
885 			    sizeof(fs_args.msdosfs_args._pad1));
886 			fs_args.msdosfs_args.uid =
887 			    fs_args32.msdosfs_args.uid;
888 			fs_args.msdosfs_args.gid =
889 			    fs_args32.msdosfs_args.gid;
890 			fs_args.msdosfs_args.mask =
891 			    fs_args32.msdosfs_args.mask;
892 			fs_args.msdosfs_args.flags =
893 			    fs_args32.msdosfs_args.flags;
894 			fs_args.msdosfs_args.version =
895 			    fs_args32.msdosfs_args.version;
896 			fs_args.msdosfs_args.dirmask =
897 			    fs_args32.msdosfs_args.dirmask;
898 			fs_args.msdosfs_args.gmtoff =
899 			    fs_args32.msdosfs_args.gmtoff;
900 		}
901 		data_seg = UIO_SYSSPACE;
902 		data = &fs_args.msdosfs_args;
903 		data_len = sizeof(fs_args.msdosfs_args);
904 	} else if (strcmp(mtype, MOUNT_NFS) == 0) {
905 		if (data_len != sizeof(fs_args32.nfs_args))
906 			return EINVAL;
907 		if ((flags & MNT_GETARGS) == 0) {
908 			error = copyin(data, &fs_args32.nfs_args,
909 			    sizeof(fs_args32.nfs_args));
910 			if (error)
911 				return error;
912 			fs_args.nfs_args.version = fs_args32.nfs_args.version;
913 			fs_args.nfs_args.addr =
914 			    NETBSD32PTR64(fs_args32.nfs_args.addr);
915 			memcpy(&fs_args.nfs_args.addrlen,
916 			    &fs_args32.nfs_args.addrlen,
917 			    offsetof(struct nfs_args, fh)
918 				- offsetof(struct nfs_args, addrlen));
919 			fs_args.nfs_args.fh =
920 			    NETBSD32PTR64(fs_args32.nfs_args.fh);
921 			memcpy(&fs_args.nfs_args.fhsize,
922 			    &fs_args32.nfs_args.fhsize,
923 			    offsetof(struct nfs_args, hostname)
924 				- offsetof(struct nfs_args, fhsize));
925 			fs_args.nfs_args.hostname =
926 			    NETBSD32PTR64(fs_args32.nfs_args.hostname);
927 		}
928 		data_seg = UIO_SYSSPACE;
929 		data = &fs_args.nfs_args;
930 		data_len = sizeof(fs_args.nfs_args);
931 	} else {
932 		data_seg = UIO_USERSPACE;
933 	}
934 	error = do_sys_mount(l, NULL, type, path, flags, data, data_seg,
935 	    data_len, retval);
936 	if (error)
937 		return error;
938 	if (flags & MNT_GETARGS) {
939 		data_len = *retval;
940 		if (strcmp(mtype, MOUNT_MFS) == 0) {
941 			if (data_len != sizeof(fs_args.mfs_args))
942 				return EINVAL;
943 			NETBSD32PTR32(fs_args32.mfs_args.fspec,
944 			    fs_args.mfs_args.fspec);
945 			memset(&fs_args32.mfs_args._pad1, 0,
946 			    sizeof(fs_args32.mfs_args._pad1));
947 			NETBSD32PTR32(fs_args32.mfs_args.base,
948 			    fs_args.mfs_args.base);
949 			fs_args32.mfs_args.size = fs_args.mfs_args.size;
950 			error = copyout(&fs_args32.mfs_args, data,
951 				    sizeof(fs_args32.mfs_args));
952 		} else if (strcmp(mtype, MOUNT_UFS) == 0) {
953 			if (data_len != sizeof(fs_args.ufs_args))
954 				return EINVAL;
955 			NETBSD32PTR32(fs_args32.ufs_args.fspec,
956 			    fs_args.ufs_args.fspec);
957 			error = copyout(&fs_args32.ufs_args, data,
958 			    sizeof(fs_args32.ufs_args));
959 		} else if (strcmp(mtype, MOUNT_CD9660) == 0) {
960 			if (data_len != sizeof(fs_args.iso_args))
961 				return EINVAL;
962 			NETBSD32PTR32(fs_args32.iso_args.fspec,
963 			    fs_args.iso_args.fspec);
964 			memset(&fs_args32.iso_args._pad1, 0,
965 			    sizeof(fs_args32.iso_args._pad1));
966 			fs_args32.iso_args.flags = fs_args.iso_args.flags;
967 			error = copyout(&fs_args32.iso_args, data,
968 				    sizeof(fs_args32.iso_args));
969 		} else if (strcmp(mtype, MOUNT_NFS) == 0) {
970 			if (data_len != sizeof(fs_args.nfs_args))
971 				return EINVAL;
972 			error = copyin(data, &fs_args32.nfs_args,
973 			    sizeof(fs_args32.nfs_args));
974 			if (error)
975 				return error;
976 			fs_args.nfs_args.version = fs_args32.nfs_args.version;
977 			NETBSD32PTR32(fs_args32.nfs_args.addr,
978 			    fs_args.nfs_args.addr);
979 			memcpy(&fs_args32.nfs_args.addrlen,
980 			    &fs_args.nfs_args.addrlen,
981 			    offsetof(struct nfs_args, fh)
982 				- offsetof(struct nfs_args, addrlen));
983 			NETBSD32PTR32(fs_args32.nfs_args.fh,
984 			    fs_args.nfs_args.fh);
985 			memcpy(&fs_args32.nfs_args.fhsize,
986 			    &fs_args.nfs_args.fhsize,
987 			    offsetof(struct nfs_args, hostname)
988 				- offsetof(struct nfs_args, fhsize));
989 			NETBSD32PTR32(fs_args32.nfs_args.hostname,
990 			    fs_args.nfs_args.hostname);
991 			error = copyout(&fs_args32.nfs_args, data,
992 			    sizeof(fs_args32.nfs_args));
993 		}
994 	}
995 	return error;
996 }
997 
998 int
999 netbsd32_linkat(struct lwp *l, const struct netbsd32_linkat_args *uap,
1000 		 register_t *retval)
1001 {
1002 	/* {
1003 		syscallarg(int) fd1;
1004 		syscallarg(const netbsd32_charp) name1;
1005 		syscallarg(int) fd2;
1006 		syscallarg(const netbsd32_charp) name2;
1007 		syscallarg(int) flags;
1008 	} */
1009 	struct sys_linkat_args ua;
1010 
1011 	NETBSD32TO64_UAP(fd1);
1012 	NETBSD32TOP_UAP(name1, const char);
1013 	NETBSD32TO64_UAP(fd2);
1014 	NETBSD32TOP_UAP(name2, const char);
1015 	NETBSD32TO64_UAP(flags);
1016 
1017 	return sys_linkat(l, &ua, retval);
1018 }
1019 
1020 int
1021 netbsd32_renameat(struct lwp *l, const struct netbsd32_renameat_args *uap,
1022 		 register_t *retval)
1023 {
1024 	/* {
1025 		syscallarg(int) fromfd;
1026 		syscallarg(const netbsd32_charp) from;
1027 		syscallarg(int) tofd;
1028 		syscallarg(const netbsd32_charp) to;
1029 	} */
1030 	struct sys_renameat_args ua;
1031 
1032 	NETBSD32TO64_UAP(fromfd);
1033 	NETBSD32TOP_UAP(from, const char);
1034 	NETBSD32TO64_UAP(tofd);
1035 	NETBSD32TOP_UAP(to, const char);
1036 
1037 	return sys_renameat(l, &ua, retval);
1038 }
1039 
1040 int
1041 netbsd32_mkfifoat(struct lwp *l, const struct netbsd32_mkfifoat_args *uap,
1042 		 register_t *retval)
1043 {
1044 	/* {
1045 		syscallarg(int) fd;
1046 		syscallarg(const netbsd32_charp) path;
1047 		syscallarg(mode_t) mode;
1048 	} */
1049 	struct sys_mkfifoat_args ua;
1050 
1051 	NETBSD32TO64_UAP(fd);
1052 	NETBSD32TOP_UAP(path, const char);
1053 	NETBSD32TO64_UAP(mode);
1054 
1055 	return sys_mkfifoat(l, &ua, retval);
1056 }
1057 
1058 int
1059 netbsd32_mknodat(struct lwp *l, const struct netbsd32_mknodat_args *uap,
1060 		 register_t *retval)
1061 {
1062 	/* {
1063 		syscallarg(int) fd;
1064 		syscallarg(netbsd32_charp) path;
1065 		syscallarg(mode_t) mode;
1066 		syscallarg(uint32_t) dev;
1067 	} */
1068 	struct sys_mknodat_args ua;
1069 
1070 	NETBSD32TO64_UAP(fd);
1071 	NETBSD32TOP_UAP(path, const char);
1072 	NETBSD32TO64_UAP(mode);
1073 	NETBSD32TO64_UAP(dev);
1074 
1075 	return sys_mknodat(l, &ua, retval);
1076 }
1077 
1078 int
1079 netbsd32_mkdirat(struct lwp *l, const struct netbsd32_mkdirat_args *uap,
1080 		 register_t *retval)
1081 {
1082 	/* {
1083 		syscallarg(int) fd;
1084 		syscallarg(netbsd32_charp) path;
1085 		syscallarg(mode_t) mode;
1086 	} */
1087 	struct sys_mkdirat_args ua;
1088 
1089 	NETBSD32TO64_UAP(fd);
1090 	NETBSD32TOP_UAP(path, const char);
1091 	NETBSD32TO64_UAP(mode);
1092 
1093 	return sys_mkdirat(l, &ua, retval);
1094 }
1095 
1096 int
1097 netbsd32_faccessat(struct lwp *l, const struct netbsd32_faccessat_args *uap,
1098 		 register_t *retval)
1099 {
1100 	/* {
1101 		syscallarg(int) fd;
1102 		syscallarg(netbsd32_charp) path;
1103 		syscallarg(int) amode;
1104 		syscallarg(int) flag;
1105 	} */
1106 	struct sys_faccessat_args ua;
1107 
1108 	NETBSD32TO64_UAP(fd);
1109 	NETBSD32TOP_UAP(path, const char);
1110 	NETBSD32TO64_UAP(amode);
1111 	NETBSD32TO64_UAP(flag);
1112 
1113 	return sys_faccessat(l, &ua, retval);
1114 }
1115 
1116 int
1117 netbsd32_fchmodat(struct lwp *l, const struct netbsd32_fchmodat_args *uap,
1118 		 register_t *retval)
1119 {
1120 	/* {
1121 		syscallarg(int) fd;
1122 		syscallarg(netbsd32_charp) path;
1123 		syscallarg(mode_t) mode;
1124 		syscallarg(int) flag;
1125 	} */
1126 	struct sys_fchmodat_args ua;
1127 
1128 	NETBSD32TO64_UAP(fd);
1129 	NETBSD32TOP_UAP(path, const char);
1130 	NETBSD32TO64_UAP(mode);
1131 	NETBSD32TO64_UAP(flag);
1132 
1133 	return sys_fchmodat(l, &ua, retval);
1134 }
1135 
1136 int
1137 netbsd32_fchownat(struct lwp *l, const struct netbsd32_fchownat_args *uap,
1138 		 register_t *retval)
1139 {
1140 	/* {
1141 		syscallarg(int) fd;
1142 		syscallarg(netbsd32_charp) path;
1143 		syscallarg(uid_t) owner;
1144 		syscallarg(gid_t) group;
1145 		syscallarg(int) flag;
1146 	} */
1147 	struct sys_fchownat_args ua;
1148 
1149 	NETBSD32TO64_UAP(fd);
1150 	NETBSD32TOP_UAP(path, const char);
1151 	NETBSD32TO64_UAP(owner);
1152 	NETBSD32TO64_UAP(group);
1153 	NETBSD32TO64_UAP(flag);
1154 
1155 	return sys_fchownat(l, &ua, retval);
1156 }
1157 
1158 int
1159 netbsd32_fstatat(struct lwp *l, const struct netbsd32_fstatat_args *uap,
1160 		 register_t *retval)
1161 {
1162 	/* {
1163 		syscallarg(int) fd;
1164 		syscallarg(netbsd32_charp) path;
1165 		syscallarg(netbsd32_statp_t) buf;
1166 		syscallarg(int) flag;
1167 	} */
1168 	struct netbsd32_stat sb32;
1169 	struct stat sb;
1170 	int follow;
1171 	int error;
1172 
1173 	follow = (SCARG(uap, flag) & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
1174 
1175 	error = do_sys_statat(l, SCARG(uap, fd), SCARG_P32(uap, path),
1176 	    follow, &sb);
1177 	if (error)
1178 		return error;
1179 	netbsd32_from_stat(&sb, &sb32);
1180 	return copyout(&sb32, SCARG_P32(uap, buf), sizeof(sb32));
1181 }
1182 
1183 int
1184 netbsd32_utimensat(struct lwp *l, const struct netbsd32_utimensat_args *uap,
1185 		 register_t *retval)
1186 {
1187 	/* {
1188 		syscallarg(int) fd;
1189 		syscallarg(netbsd32_charp) path;
1190 		syscallarg(netbsd32_timespecp_t) tptr;
1191 		syscallarg(int) flag;
1192 	} */
1193 	struct timespec ts[2], *tsp;
1194 	int follow;
1195 	int error;
1196 
1197 	error = get_utimens32(SCARG_P32(uap, tptr), ts, &tsp);
1198 	if (error != 0)
1199 		return error;
1200 
1201 	follow = (SCARG(uap, flag) & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW;
1202 
1203 	return do_sys_utimensat(l, SCARG(uap, fd), NULL,
1204 	    SCARG_P32(uap, path), follow, tsp, UIO_SYSSPACE);
1205 }
1206 
1207 int
1208 netbsd32_openat(struct lwp *l, const struct netbsd32_openat_args *uap,
1209 		 register_t *retval)
1210 {
1211 	/* {
1212 		syscallarg(int) fd;
1213 		syscallarg(netbsd32_charp) path;
1214 		syscallarg(int) oflags;
1215 		syscallarg(mode_t) mode;
1216 	} */
1217 	struct sys_openat_args ua;
1218 
1219 	NETBSD32TO64_UAP(fd);
1220 	NETBSD32TOP_UAP(path, const char);
1221 	NETBSD32TO64_UAP(oflags);
1222 	NETBSD32TO64_UAP(mode);
1223 
1224 	return sys_openat(l, &ua, retval);
1225 }
1226 
1227 int
1228 netbsd32_readlinkat(struct lwp *l, const struct netbsd32_readlinkat_args *uap,
1229 		 register_t *retval)
1230 {
1231 	/* {
1232 		syscallarg(int) fd;
1233 		syscallarg(netbsd32_charp) path;
1234 		syscallarg(netbsd32_charp) buf;
1235 		syscallarg(netbsd32_size_t) bufsize;
1236 	} */
1237 	struct sys_readlinkat_args ua;
1238 
1239 	NETBSD32TO64_UAP(fd);
1240 	NETBSD32TOP_UAP(path, const char *);
1241 	NETBSD32TOP_UAP(buf, char *);
1242 	NETBSD32TOX_UAP(bufsize, size_t);
1243 
1244 	return sys_readlinkat(l, &ua, retval);
1245 }
1246 
1247 int
1248 netbsd32_symlinkat(struct lwp *l, const struct netbsd32_symlinkat_args *uap,
1249 		 register_t *retval)
1250 {
1251 	/* {
1252 		syscallarg(netbsd32_charp) path1;
1253 		syscallarg(int) fd;
1254 		syscallarg(netbsd32_charp) path2;
1255 	} */
1256 	struct sys_symlinkat_args ua;
1257 
1258 	NETBSD32TOP_UAP(path1, const char *);
1259 	NETBSD32TO64_UAP(fd);
1260 	NETBSD32TOP_UAP(path2, const char *);
1261 
1262 	return sys_symlinkat(l, &ua, retval);
1263 }
1264 
1265 int
1266 netbsd32_unlinkat(struct lwp *l, const struct netbsd32_unlinkat_args *uap,
1267 		 register_t *retval)
1268 {
1269 	/* {
1270 		syscallarg(int) fd;
1271 		syscallarg(netbsd32_charp) path;
1272 		syscallarg(int) flag;
1273 	} */
1274 	struct sys_unlinkat_args ua;
1275 
1276 	NETBSD32TO64_UAP(fd);
1277 	NETBSD32TOP_UAP(path, const char *);
1278 	NETBSD32TO64_UAP(flag);
1279 
1280 	return sys_unlinkat(l, &ua, retval);
1281 }
1282 
1283 int
1284 netbsd32_futimens(struct lwp *l, const struct netbsd32_futimens_args *uap,
1285 		 register_t *retval)
1286 {
1287 	/* {
1288 		syscallarg(int) fd;
1289 		syscallarg(netbsd32_timespecp_t) tptr;
1290 	} */
1291 	struct timespec ts[2], *tsp;
1292 	file_t *fp;
1293 	int error;
1294 
1295 	error = get_utimens32(SCARG_P32(uap, tptr), ts, &tsp);
1296 	if (error != 0)
1297 		return error;
1298 
1299 	/* fd_getvnode() will use the descriptor for us */
1300 	if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0)
1301 		return (error);
1302 	error = do_sys_utimensat(l, AT_FDCWD, fp->f_data, NULL, 0,
1303 	    tsp, UIO_SYSSPACE);
1304 	fd_putfile(SCARG(uap, fd));
1305 	return (error);
1306 }
1307