xref: /netbsd-src/sys/compat/netbsd32/netbsd32_fs.c (revision 0df165c04d0a9ca1adde9ed2b890344c937954a6)
1 /*	$NetBSD: netbsd32_fs.c,v 1.46 2007/08/15 12:07:31 ad 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  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.46 2007/08/15 12:07:31 ad Exp $");
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/malloc.h>
37 #include <sys/mount.h>
38 #include <sys/socket.h>
39 #include <sys/socketvar.h>
40 #include <sys/stat.h>
41 #include <sys/time.h>
42 #include <sys/ktrace.h>
43 #include <sys/resourcevar.h>
44 #include <sys/vnode.h>
45 #include <sys/file.h>
46 #include <sys/filedesc.h>
47 #include <sys/namei.h>
48 #include <sys/statvfs.h>
49 #include <sys/syscallargs.h>
50 #include <sys/proc.h>
51 #include <sys/dirent.h>
52 #include <sys/kauth.h>
53 #include <sys/vfs_syscalls.h>
54 
55 #include <compat/netbsd32/netbsd32.h>
56 #include <compat/netbsd32/netbsd32_syscallargs.h>
57 #include <compat/netbsd32/netbsd32_conv.h>
58 #include <compat/sys/mount.h>
59 
60 
61 static int dofilereadv32 __P((struct lwp *, int, struct file *, struct netbsd32_iovec *,
62 			      int, off_t *, int, register_t *));
63 static int dofilewritev32 __P((struct lwp *, int, struct file *, struct netbsd32_iovec *,
64 			       int,  off_t *, int, register_t *));
65 
66 struct iovec *
67 netbsd32_get_iov(struct netbsd32_iovec *iov32, int iovlen, struct iovec *aiov,
68     int aiov_len)
69 {
70 #define N_IOV32 8
71 	struct netbsd32_iovec aiov32[N_IOV32];
72 	struct iovec *iov = aiov;
73 	struct iovec *iovp;
74 	int i, n, j;
75 	int error;
76 
77 	if (iovlen < 0 || iovlen > IOV_MAX)
78 		return NULL;
79 
80 	if (iovlen > aiov_len)
81 		iov = malloc(iovlen * sizeof (*iov), M_TEMP, M_WAITOK);
82 
83 	iovp = iov;
84 	for (i = 0; i < iovlen; iov32 += N_IOV32, i += N_IOV32) {
85 		n = iovlen - i;
86 		if (n > N_IOV32)
87 			n = N_IOV32;
88 		error = copyin(iov32, aiov32, n * sizeof (*iov32));
89 		if (error != 0) {
90 			if (iov != aiov)
91 				free(iov, M_TEMP);
92 			return NULL;
93 		}
94 		for (j = 0; j < n; iovp++, j++) {
95 			iovp->iov_base = NETBSD32PTR64(aiov32[j].iov_base);
96 			iovp->iov_len = aiov32[j].iov_len;
97 		}
98 	}
99 	return iov;
100 #undef N_IOV32
101 }
102 
103 int
104 netbsd32_readv(l, v, retval)
105 	struct lwp *l;
106 	void *v;
107 	register_t *retval;
108 {
109 	struct netbsd32_readv_args /* {
110 		syscallarg(int) fd;
111 		syscallarg(const netbsd32_iovecp_t) iovp;
112 		syscallarg(int) iovcnt;
113 	} */ *uap = v;
114 	int fd = SCARG(uap, fd);
115 	struct proc *p = l->l_proc;
116 	struct file *fp;
117 	struct filedesc *fdp = p->p_fd;
118 
119 	if ((fp = fd_getfile(fdp, fd)) == NULL)
120 		return (EBADF);
121 
122 	if ((fp->f_flag & FREAD) == 0)
123 		return (EBADF);
124 
125 	FILE_USE(fp);
126 
127 	return (dofilereadv32(l, 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(l, fd, fp, iovp, iovcnt, offset, flags, retval)
135 	struct lwp *l;
136 	int fd;
137 	struct file *fp;
138 	struct netbsd32_iovec *iovp;
139 	int iovcnt;
140 	off_t *offset;
141 	int flags;
142 	register_t *retval;
143 {
144 	struct uio auio;
145 	struct iovec *iov;
146 	struct iovec *needfree;
147 	struct iovec aiov[UIO_SMALLIOV];
148 	long i, cnt, error = 0;
149 	u_int iovlen;
150 	struct iovec *ktriov = NULL;
151 
152 	/* note: can't use iovlen until iovcnt is validated */
153 	iovlen = iovcnt * sizeof(struct iovec);
154 	if ((u_int)iovcnt > UIO_SMALLIOV) {
155 		if ((u_int)iovcnt > IOV_MAX) {
156 			error = EINVAL;
157 			goto out;
158 		}
159 		iov = malloc(iovlen, M_IOV, M_WAITOK);
160 		needfree = iov;
161 	} else if ((u_int)iovcnt > 0) {
162 		iov = aiov;
163 		needfree = NULL;
164 	} else {
165 		error = EINVAL;
166 		goto out;
167 	}
168 
169 	auio.uio_iov = iov;
170 	auio.uio_iovcnt = iovcnt;
171 	auio.uio_rw = UIO_READ;
172 	auio.uio_vmspace = l->l_proc->p_vmspace;
173 	error = netbsd32_to_iovecin(iovp, iov, iovcnt);
174 	if (error)
175 		goto done;
176 	auio.uio_resid = 0;
177 	for (i = 0; i < iovcnt; i++) {
178 		auio.uio_resid += iov->iov_len;
179 		/*
180 		 * Reads return ssize_t because -1 is returned on error.
181 		 * Therefore we must restrict the length to SSIZE_MAX to
182 		 * avoid garbage return values.
183 		 */
184 		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
185 			error = EINVAL;
186 			goto done;
187 		}
188 		iov++;
189 	}
190 
191 	/*
192 	 * if tracing, save a copy of iovec
193 	 */
194 	if (ktrpoint(KTR_GENIO)) {
195 		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
196 		memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen);
197 	}
198 
199 	cnt = auio.uio_resid;
200 	error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags);
201 	if (error)
202 		if (auio.uio_resid != cnt && (error == ERESTART ||
203 		    error == EINTR || error == EWOULDBLOCK))
204 			error = 0;
205 	cnt -= auio.uio_resid;
206 
207 	if (ktriov != NULL) {
208 		ktrgeniov(fd, UIO_READ, ktriov, cnt, error);
209 		free(ktriov, M_TEMP);
210 	}
211 
212 	*retval = cnt;
213 done:
214 	if (needfree)
215 		free(needfree, M_IOV);
216 out:
217 	FILE_UNUSE(fp, l);
218 	return (error);
219 }
220 
221 int
222 netbsd32_writev(l, v, retval)
223 	struct lwp *l;
224 	void *v;
225 	register_t *retval;
226 {
227 	struct netbsd32_writev_args /* {
228 		syscallarg(int) fd;
229 		syscallarg(const netbsd32_iovecp_t) iovp;
230 		syscallarg(int) iovcnt;
231 	} */ *uap = v;
232 	int fd = SCARG(uap, fd);
233 	struct file *fp;
234 	struct proc *p = l->l_proc;
235 	struct filedesc *fdp = p->p_fd;
236 
237 	if ((fp = fd_getfile(fdp, fd)) == NULL)
238 		return (EBADF);
239 
240 	if ((fp->f_flag & FWRITE) == 0)
241 		return (EBADF);
242 
243 	FILE_USE(fp);
244 
245 	return (dofilewritev32(l, fd, fp,
246 	    (struct netbsd32_iovec *)SCARG_P32(uap, iovp),
247 	    SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
248 }
249 
250 int
251 dofilewritev32(l, fd, fp, iovp, iovcnt, offset, flags, retval)
252 	struct lwp *l;
253 	int fd;
254 	struct file *fp;
255 	struct netbsd32_iovec *iovp;
256 	int iovcnt;
257 	off_t *offset;
258 	int flags;
259 	register_t *retval;
260 {
261 	struct uio auio;
262 	struct iovec *iov;
263 	struct iovec *needfree;
264 	struct iovec aiov[UIO_SMALLIOV];
265 	struct proc *p = l->l_proc;
266 	long i, cnt, error = 0;
267 	u_int iovlen;
268 	struct iovec *ktriov = NULL;
269 
270 	/* note: can't use iovlen until iovcnt is validated */
271 	iovlen = iovcnt * sizeof(struct iovec);
272 	if ((u_int)iovcnt > UIO_SMALLIOV) {
273 		if ((u_int)iovcnt > IOV_MAX) {
274 			error = EINVAL;
275 			goto out;
276 		}
277 		iov = malloc(iovlen, M_IOV, M_WAITOK);
278 		needfree = iov;
279 	} else if ((u_int)iovcnt > 0) {
280 		iov = aiov;
281 		needfree = NULL;
282 	} else {
283 		error = EINVAL;
284 		goto out;
285 	}
286 
287 	auio.uio_iov = iov;
288 	auio.uio_iovcnt = iovcnt;
289 	auio.uio_rw = UIO_WRITE;
290 	auio.uio_vmspace = l->l_proc->p_vmspace;
291 	error = netbsd32_to_iovecin(iovp, iov, iovcnt);
292 	if (error)
293 		goto done;
294 	auio.uio_resid = 0;
295 	for (i = 0; i < iovcnt; i++) {
296 		auio.uio_resid += iov->iov_len;
297 		/*
298 		 * Writes return ssize_t because -1 is returned on error.
299 		 * Therefore we must restrict the length to SSIZE_MAX to
300 		 * avoid garbage return values.
301 		 */
302 		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
303 			error = EINVAL;
304 			goto done;
305 		}
306 		iov++;
307 	}
308 
309 	/*
310 	 * if tracing, save a copy of iovec
311 	 */
312 	if (ktrpoint(KTR_GENIO))  {
313 		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
314 		memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen);
315 	}
316 
317 	cnt = auio.uio_resid;
318 	error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags);
319 	if (error) {
320 		if (auio.uio_resid != cnt && (error == ERESTART ||
321 		    error == EINTR || error == EWOULDBLOCK))
322 			error = 0;
323 		if (error == EPIPE) {
324 			mutex_enter(&proclist_mutex);
325 			psignal(p, SIGPIPE);
326 			mutex_exit(&proclist_mutex);
327 		}
328 	}
329 	cnt -= auio.uio_resid;
330 	if (ktriov != NULL) {
331 		ktrgenio(fd, UIO_WRITE, ktriov, cnt, error);
332 		free(ktriov, M_TEMP);
333 	}
334 	*retval = cnt;
335 done:
336 	if (needfree)
337 		free(needfree, M_IOV);
338 out:
339 	FILE_UNUSE(fp, l);
340 	return (error);
341 }
342 
343 /*
344  * Common routine to set access and modification times given a vnode.
345  */
346 static int
347 get_utimes32(const netbsd32_timevalp_t *tptr, struct timeval *tv,
348     struct timeval **tvp)
349 {
350 	int error;
351 	struct netbsd32_timeval tv32[2];
352 
353 	if (tptr == NULL) {
354 		*tvp = NULL;
355 		return 0;
356 	}
357 
358 	error = copyin(tptr, tv32, sizeof(tv32));
359 	if (error)
360 		return error;
361 	netbsd32_to_timeval(&tv32[0], &tv[0]);
362 	netbsd32_to_timeval(&tv32[1], &tv[1]);
363 
364 	*tvp = tv;
365 	return 0;
366 }
367 
368 int
369 netbsd32_utimes(l, v, retval)
370 	struct lwp *l;
371 	void *v;
372 	register_t *retval;
373 {
374 	struct netbsd32_utimes_args /* {
375 		syscallarg(const netbsd32_charp) path;
376 		syscallarg(const netbsd32_timevalp_t) tptr;
377 	} */ *uap = v;
378 	int error;
379 	struct timeval tv[2], *tvp;
380 
381 	error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
382 	if (error != 0)
383 		return error;
384 
385 	return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW,
386 			    tvp, UIO_SYSSPACE);
387 }
388 
389 static int
390 netbds32_copyout_statvfs(const void *kp, void *up, size_t len)
391 {
392 	struct netbsd32_statvfs *sbuf_32;
393 	int error;
394 
395 	sbuf_32 = malloc(sizeof *sbuf_32, M_TEMP, M_WAITOK);
396 	netbsd32_from_statvfs(kp, sbuf_32);
397 	error = copyout(sbuf_32, up, sizeof(*sbuf_32));
398 	free(sbuf_32, M_TEMP);
399 
400 	return error;
401 }
402 
403 int
404 netbsd32_statvfs1(l, v, retval)
405 	struct lwp *l;
406 	void *v;
407 	register_t *retval;
408 {
409 	struct netbsd32_statvfs1_args /* {
410 		syscallarg(const netbsd32_charp) path;
411 		syscallarg(netbsd32_statvfsp_t) buf;
412 		syscallarg(int) flags;
413 	} */ *uap = v;
414 	struct statvfs *sb;
415 	int error;
416 
417 	sb = STATVFSBUF_GET();
418 	error = do_sys_pstatvfs(l, SCARG_P32(uap, path), SCARG(uap, flags), sb);
419 	if (error == 0)
420 		error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
421 	STATVFSBUF_PUT(sb);
422 	return error;
423 }
424 
425 int
426 netbsd32_fstatvfs1(l, v, retval)
427 	struct lwp *l;
428 	void *v;
429 	register_t *retval;
430 {
431 	struct netbsd32_fstatvfs1_args /* {
432 		syscallarg(int) fd;
433 		syscallarg(netbsd32_statvfsp_t) buf;
434 		syscallarg(int) flags;
435 	} */ *uap = v;
436 	struct statvfs *sb;
437 	int error;
438 
439 	sb = STATVFSBUF_GET();
440 	error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb);
441 	if (error == 0)
442 		error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
443 	STATVFSBUF_PUT(sb);
444 	return error;
445 }
446 
447 int
448 netbsd32_getvfsstat(l, v, retval)
449 	struct lwp *l;
450 	void *v;
451 	register_t *retval;
452 {
453 	struct netbsd32_getvfsstat_args /* {
454 		syscallarg(netbsd32_statvfsp_t) buf;
455 		syscallarg(netbsd32_size_t) bufsize;
456 		syscallarg(int) flags;
457 	} */ *uap = v;
458 
459 	return do_sys_getvfsstat(l, SCARG_P32(uap, buf), SCARG(uap, bufsize),
460 	    SCARG(uap, flags), netbds32_copyout_statvfs,
461 	    sizeof (struct netbsd32_statvfs), retval);
462 }
463 
464 int
465 netbsd32___fhstatvfs140(l, v, retval)
466 	struct lwp *l;
467 	void *v;
468 	register_t *retval;
469 {
470 	struct netbsd32___fhstatvfs140_args /* {
471 		syscallarg(const netbsd32_pointer_t) fhp;
472 		syscallarg(netbsd32_size_t) fh_size;
473 		syscallarg(netbsd32_statvfsp_t) buf;
474 		syscallarg(int) flags;
475 	} */ *uap = v;
476 	struct statvfs *sb;
477 	int error;
478 
479 	sb = STATVFSBUF_GET();
480 	error = do_fhstatvfs(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), sb,
481 	    SCARG(uap, flags));
482 
483 	if (error == 0)
484 		error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
485 	STATVFSBUF_PUT(sb);
486 
487 	return error;
488 }
489 
490 int
491 netbsd32_futimes(l, v, retval)
492 	struct lwp *l;
493 	void *v;
494 	register_t *retval;
495 {
496 	struct netbsd32_futimes_args /* {
497 		syscallarg(int) fd;
498 		syscallarg(const netbsd32_timevalp_t) tptr;
499 	} */ *uap = v;
500 	int error;
501 	struct file *fp;
502 	struct timeval tv[2], *tvp;
503 
504 	error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
505 	if (error != 0)
506 		return error;
507 
508 	/* getvnode() will use the descriptor for us */
509 	if ((error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp)) != 0)
510 		return (error);
511 
512 	error = do_sys_utimes(l, fp->f_data, NULL, 0, tvp, UIO_SYSSPACE);
513 
514 	FILE_UNUSE(fp, l);
515 	return (error);
516 }
517 
518 int
519 netbsd32_sys___getdents30(l, v, retval)
520 	struct lwp *l;
521 	void *v;
522 	register_t *retval;
523 {
524 	struct netbsd32_sys___getdents30_args /* {
525 		syscallarg(int) fd;
526 		syscallarg(netbsd32_charp) buf;
527 		syscallarg(netbsd32_size_t) count;
528 	} */ *uap = v;
529 	struct file *fp;
530 	int error, done;
531 	struct proc *p = l->l_proc;
532 
533 	/* getvnode() will use the descriptor for us */
534 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
535 		return (error);
536 	if ((fp->f_flag & FREAD) == 0) {
537 		error = EBADF;
538 		goto out;
539 	}
540 	error = vn_readdir(fp, SCARG_P32(uap, buf),
541 	    UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0);
542 	*retval = done;
543  out:
544 	FILE_UNUSE(fp, l);
545 	return (error);
546 }
547 
548 int
549 netbsd32_lutimes(l, v, retval)
550 	struct lwp *l;
551 	void *v;
552 	register_t *retval;
553 {
554 	struct netbsd32_lutimes_args /* {
555 		syscallarg(const netbsd32_charp) path;
556 		syscallarg(const netbsd32_timevalp_t) tptr;
557 	} */ *uap = v;
558 	int error;
559 	struct timeval tv[2], *tvp;
560 
561 	error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp);
562 	if (error != 0)
563 		return error;
564 
565 	return do_sys_utimes(l, NULL, SCARG_P32(uap, path), NOFOLLOW,
566 			    tvp, UIO_SYSSPACE);
567 }
568 
569 int
570 netbsd32_sys___stat30(l, v, retval)
571 	struct lwp *l;
572 	void *v;
573 	register_t *retval;
574 {
575 	struct netbsd32_sys___stat30_args /* {
576 		syscallarg(const netbsd32_charp) path;
577 		syscallarg(netbsd32_statp_t) ub;
578 	} */ *uap = v;
579 	struct netbsd32_stat sb32;
580 	struct stat sb;
581 	int error;
582 	const char *path;
583 
584 	path = SCARG_P32(uap, path);
585 
586 	error = do_sys_stat(l, path, FOLLOW, &sb);
587 	if (error)
588 		return (error);
589 	netbsd32_from___stat30(&sb, &sb32);
590 	error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32));
591 	return (error);
592 }
593 
594 int
595 netbsd32_sys___fstat30(l, v, retval)
596 	struct lwp *l;
597 	void *v;
598 	register_t *retval;
599 {
600 	struct netbsd32_sys___fstat30_args /* {
601 		syscallarg(int) fd;
602 		syscallarg(netbsd32_statp_t) sb;
603 	} */ *uap = v;
604 	int fd = SCARG(uap, fd);
605 	struct proc *p = l->l_proc;
606 	struct filedesc *fdp = p->p_fd;
607 	struct file *fp;
608 	struct netbsd32_stat sb32;
609 	struct stat ub;
610 	int error = 0;
611 
612 	if ((fp = fd_getfile(fdp, fd)) == NULL)
613 		return (EBADF);
614 
615 	FILE_USE(fp);
616 	error = (*fp->f_ops->fo_stat)(fp, &ub, l);
617 	FILE_UNUSE(fp, l);
618 
619 	if (error == 0) {
620 		netbsd32_from___stat30(&ub, &sb32);
621 		error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb32));
622 	}
623 	return (error);
624 }
625 
626 int
627 netbsd32_sys___lstat30(l, v, retval)
628 	struct lwp *l;
629 	void *v;
630 	register_t *retval;
631 {
632 	struct netbsd32_sys___lstat30_args /* {
633 		syscallarg(const netbsd32_charp) path;
634 		syscallarg(netbsd32_statp_t) ub;
635 	} */ *uap = v;
636 	struct netbsd32_stat sb32;
637 	struct stat sb;
638 	int error;
639 	const char *path;
640 
641 	path = SCARG_P32(uap, path);
642 
643 	error = do_sys_stat(l, path, NOFOLLOW, &sb);
644 	if (error)
645 		return (error);
646 	netbsd32_from___stat30(&sb, &sb32);
647 	error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32));
648 	return (error);
649 }
650 
651 int netbsd32___fhstat40(l, v, retval)
652 	struct lwp *l;
653 	void *v;
654 	register_t *retval;
655 {
656 	struct netbsd32___fhstat40_args /* {
657 		syscallarg(const netbsd32_pointer_t) fhp;
658 		syscallarg(netbsd32_size_t) fh_size;
659 		syscallarg(netbsd32_statp_t) sb;
660 	} */ *uap = v;
661 	struct stat sb;
662 	struct netbsd32_stat sb32;
663 	int error;
664 
665 	error = do_fhstat(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), &sb);
666 	if (error != 0) {
667 		netbsd32_from___stat30(&sb, &sb32);
668 		error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb));
669 	}
670 	return error;
671 }
672 
673 int
674 netbsd32_preadv(l, v, retval)
675 	struct lwp *l;
676 	void *v;
677 	register_t *retval;
678 {
679 	struct netbsd32_preadv_args /* {
680 		syscallarg(int) fd;
681 		syscallarg(const netbsd32_iovecp_t) iovp;
682 		syscallarg(int) iovcnt;
683 		syscallarg(int) pad;
684 		syscallarg(off_t) offset;
685 	} */ *uap = v;
686 	struct proc *p = l->l_proc;
687 	struct filedesc *fdp = p->p_fd;
688 	struct file *fp;
689 	struct vnode *vp;
690 	off_t offset;
691 	int error, fd = SCARG(uap, fd);
692 
693 	if ((fp = fd_getfile(fdp, fd)) == NULL)
694 		return (EBADF);
695 
696 	if ((fp->f_flag & FREAD) == 0)
697 		return (EBADF);
698 
699 	FILE_USE(fp);
700 
701 	vp = (struct vnode *)fp->f_data;
702 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
703 		error = ESPIPE;
704 		goto out;
705 	}
706 
707 	offset = SCARG(uap, offset);
708 
709 	/*
710 	 * XXX This works because no file systems actually
711 	 * XXX take any action on the seek operation.
712 	 */
713 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
714 		goto out;
715 
716 	return (dofilereadv32(l, fd, fp, SCARG_P32(uap, iovp),
717 	    SCARG(uap, iovcnt), &offset, 0, retval));
718 
719 out:
720 	FILE_UNUSE(fp, l);
721 	return (error);
722 }
723 
724 int
725 netbsd32_pwritev(l, v, retval)
726 	struct lwp *l;
727 	void *v;
728 	register_t *retval;
729 {
730 	struct netbsd32_pwritev_args /* {
731 		syscallarg(int) fd;
732 		syscallarg(const netbsd32_iovecp_t) iovp;
733 		syscallarg(int) iovcnt;
734 		syscallarg(int) pad;
735 		syscallarg(off_t) offset;
736 	} */ *uap = v;
737 	struct proc *p = l->l_proc;
738 	struct filedesc *fdp = p->p_fd;
739 	struct file *fp;
740 	struct vnode *vp;
741 	off_t offset;
742 	int error, fd = SCARG(uap, fd);
743 
744 	if ((fp = fd_getfile(fdp, fd)) == NULL)
745 		return (EBADF);
746 
747 	if ((fp->f_flag & FWRITE) == 0)
748 		return (EBADF);
749 
750 	FILE_USE(fp);
751 
752 	vp = (struct vnode *)fp->f_data;
753 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
754 		error = ESPIPE;
755 		goto out;
756 	}
757 
758 	offset = SCARG(uap, offset);
759 
760 	/*
761 	 * XXX This works because no file systems actually
762 	 * XXX take any action on the seek operation.
763 	 */
764 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
765 		goto out;
766 
767 	return (dofilewritev32(l, fd, fp, SCARG_P32(uap, iovp),
768 	    SCARG(uap, iovcnt), &offset, 0, retval));
769 
770 out:
771 	FILE_UNUSE(fp, l);
772 	return (error);
773 }
774 
775 /*
776  * Find pathname of process's current directory.
777  *
778  * Use vfs vnode-to-name reverse cache; if that fails, fall back
779  * to reading directory contents.
780  */
781 /* XXX NH Why does this exist */
782 int
783 getcwd_common __P((struct vnode *, struct vnode *,
784 		   char **, char *, int, int, struct lwp *));
785 
786 int netbsd32___getcwd(l, v, retval)
787 	struct lwp *l;
788 	void   *v;
789 	register_t *retval;
790 {
791 	struct netbsd32___getcwd_args /* {
792 		syscallarg(char *) bufp;
793 		syscallarg(size_t) length;
794 	} */ *uap = v;
795 	struct proc *p = l->l_proc;
796 	int     error;
797 	char   *path;
798 	char   *bp, *bend;
799 	int     len = (int)SCARG(uap, length);
800 	int	lenused;
801 
802 	if (len > MAXPATHLEN*4)
803 		len = MAXPATHLEN*4;
804 	else if (len < 2)
805 		return ERANGE;
806 
807 	path = (char *)malloc(len, M_TEMP, M_WAITOK);
808 	if (!path)
809 		return ENOMEM;
810 
811 	bp = &path[len];
812 	bend = bp;
813 	*(--bp) = '\0';
814 
815 	/*
816 	 * 5th argument here is "max number of vnodes to traverse".
817 	 * Since each entry takes up at least 2 bytes in the output buffer,
818 	 * limit it to N/2 vnodes for an N byte buffer.
819 	 */
820 #define GETCWD_CHECK_ACCESS 0x0001
821 	error = getcwd_common (p->p_cwdi->cwdi_cdir, NULL, &bp, path, len/2,
822 			       GETCWD_CHECK_ACCESS, l);
823 
824 	if (error)
825 		goto out;
826 	lenused = bend - bp;
827 	*retval = lenused;
828 	/* put the result into user buffer */
829 	error = copyout(bp, SCARG_P32(uap, bufp), lenused);
830 
831 out:
832 	free(path, M_TEMP);
833 	return error;
834 }
835