xref: /netbsd-src/sys/compat/netbsd32/netbsd32_fs.c (revision 4b896b232495b7a9b8b94a1cf1e21873296d53b8)
1 /*	$NetBSD: netbsd32_fs.c,v 1.17 2004/04/22 14:32:09 hannken 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.17 2004/04/22 14:32:09 hannken Exp $");
33 
34 #if defined(_KERNEL_OPT)
35 #include "opt_ktrace.h"
36 #endif
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
41 #include <sys/mount.h>
42 #include <sys/socket.h>
43 #include <sys/socketvar.h>
44 #include <sys/stat.h>
45 #include <sys/time.h>
46 #include <sys/ktrace.h>
47 #include <sys/resourcevar.h>
48 #include <sys/vnode.h>
49 #include <sys/file.h>
50 #include <sys/filedesc.h>
51 #include <sys/namei.h>
52 #include <sys/sa.h>
53 #include <sys/syscallargs.h>
54 #include <sys/proc.h>
55 
56 #include <compat/netbsd32/netbsd32.h>
57 #include <compat/netbsd32/netbsd32_syscallargs.h>
58 #include <compat/netbsd32/netbsd32_conv.h>
59 
60 
61 static int dofilereadv32 __P((struct proc *, int, struct file *, struct netbsd32_iovec *,
62 			      int, off_t *, int, register_t *));
63 static int dofilewritev32 __P((struct proc *, int, struct file *, struct netbsd32_iovec *,
64 			       int,  off_t *, int, register_t *));
65 static int change_utimes32 __P((struct vnode *, netbsd32_timevalp_t, struct proc *));
66 
67 int
68 netbsd32_getfsstat(l, v, retval)
69 	struct lwp *l;
70 	void *v;
71 	register_t *retval;
72 {
73 	struct netbsd32_getfsstat_args /* {
74 		syscallarg(netbsd32_statfsp_t) buf;
75 		syscallarg(netbsd32_long) bufsize;
76 		syscallarg(int) flags;
77 	} */ *uap = v;
78 	struct mount *mp, *nmp;
79 	struct statvfs *sp;
80 	struct netbsd32_statfs sb32;
81 	caddr_t sfsp;
82 	long count, maxcount, error;
83 	struct proc *p = l->l_proc;
84 
85 	maxcount = SCARG(uap, bufsize) / sizeof(struct netbsd32_statfs);
86 	sfsp = (caddr_t)NETBSD32PTR64(SCARG(uap, buf));
87 	simple_lock(&mountlist_slock);
88 	count = 0;
89 	for (mp = mountlist.cqh_first; mp != (void *)&mountlist; mp = nmp) {
90 		if (vfs_busy(mp, LK_NOWAIT, &mountlist_slock)) {
91 			nmp = mp->mnt_list.cqe_next;
92 			continue;
93 		}
94 		if (sfsp && count < maxcount) {
95 			sp = &mp->mnt_stat;
96 			/*
97 			 * If MNT_NOWAIT or MNT_LAZY is specified, do not
98 			 * refresh the fsstat cache. MNT_WAIT or MNT_LAXY
99 			 * overrides MNT_NOWAIT.
100 			 */
101 			if (SCARG(uap, flags) != MNT_NOWAIT &&
102 			    SCARG(uap, flags) != MNT_LAZY &&
103 			    (SCARG(uap, flags) == MNT_WAIT ||
104 			     SCARG(uap, flags) == 0) &&
105 			    (error = VFS_STATVFS(mp, sp, p)) != 0) {
106 				simple_lock(&mountlist_slock);
107 				nmp = mp->mnt_list.cqe_next;
108 				vfs_unbusy(mp);
109 				continue;
110 			}
111 			sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
112 			netbsd32_from_statvfs(sp, &sb32);
113 			error = copyout(&sb32, sfsp, sizeof(sb32));
114 			if (error) {
115 				vfs_unbusy(mp);
116 				return (error);
117 			}
118 			sfsp += sizeof(sb32);
119 		}
120 		count++;
121 		simple_lock(&mountlist_slock);
122 		nmp = mp->mnt_list.cqe_next;
123 		vfs_unbusy(mp);
124 	}
125 	simple_unlock(&mountlist_slock);
126 	if (sfsp && count > maxcount)
127 		*retval = maxcount;
128 	else
129 		*retval = count;
130 	return (0);
131 }
132 
133 int
134 netbsd32_readv(l, v, retval)
135 	struct lwp *l;
136 	void *v;
137 	register_t *retval;
138 {
139 	struct netbsd32_readv_args /* {
140 		syscallarg(int) fd;
141 		syscallarg(const netbsd32_iovecp_t) iovp;
142 		syscallarg(int) iovcnt;
143 	} */ *uap = v;
144 	int fd = SCARG(uap, fd);
145 	struct proc *p = l->l_proc;
146 	struct file *fp;
147 	struct filedesc *fdp = p->p_fd;
148 
149 	if ((fp = fd_getfile(fdp, fd)) == NULL)
150 		return (EBADF);
151 
152 	if ((fp->f_flag & FREAD) == 0)
153 		return (EBADF);
154 
155 	FILE_USE(fp);
156 
157 	return (dofilereadv32(p, fd, fp,
158 	    (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)),
159 	    SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
160 }
161 
162 /* Damn thing copies in the iovec! */
163 int
164 dofilereadv32(p, fd, fp, iovp, iovcnt, offset, flags, retval)
165 	struct proc *p;
166 	int fd;
167 	struct file *fp;
168 	struct netbsd32_iovec *iovp;
169 	int iovcnt;
170 	off_t *offset;
171 	int flags;
172 	register_t *retval;
173 {
174 	struct uio auio;
175 	struct iovec *iov;
176 	struct iovec *needfree;
177 	struct iovec aiov[UIO_SMALLIOV];
178 	long i, cnt, error = 0;
179 	u_int iovlen;
180 #ifdef KTRACE
181 	struct iovec *ktriov = NULL;
182 #endif
183 
184 	/* note: can't use iovlen until iovcnt is validated */
185 	iovlen = iovcnt * sizeof(struct iovec);
186 	if ((u_int)iovcnt > UIO_SMALLIOV) {
187 		if ((u_int)iovcnt > IOV_MAX) {
188 			error = EINVAL;
189 			goto out;
190 		}
191 		iov = malloc(iovlen, M_IOV, M_WAITOK);
192 		needfree = iov;
193 	} else if ((u_int)iovcnt > 0) {
194 		iov = aiov;
195 		needfree = NULL;
196 	} else {
197 		error = EINVAL;
198 		goto out;
199 	}
200 
201 	auio.uio_iov = iov;
202 	auio.uio_iovcnt = iovcnt;
203 	auio.uio_rw = UIO_READ;
204 	auio.uio_segflg = UIO_USERSPACE;
205 	auio.uio_procp = p;
206 	error = netbsd32_to_iovecin(iovp, iov, iovcnt);
207 	if (error)
208 		goto done;
209 	auio.uio_resid = 0;
210 	for (i = 0; i < iovcnt; i++) {
211 		auio.uio_resid += iov->iov_len;
212 		/*
213 		 * Reads return ssize_t because -1 is returned on error.
214 		 * Therefore we must restrict the length to SSIZE_MAX to
215 		 * avoid garbage return values.
216 		 */
217 		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
218 			error = EINVAL;
219 			goto done;
220 		}
221 		iov++;
222 	}
223 #ifdef KTRACE
224 	/*
225 	 * if tracing, save a copy of iovec
226 	 */
227 	if (KTRPOINT(p, KTR_GENIO))  {
228 		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
229 		memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen);
230 	}
231 #endif
232 	cnt = auio.uio_resid;
233 	error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags);
234 	if (error)
235 		if (auio.uio_resid != cnt && (error == ERESTART ||
236 		    error == EINTR || error == EWOULDBLOCK))
237 			error = 0;
238 	cnt -= auio.uio_resid;
239 #ifdef KTRACE
240 	if (KTRPOINT(p, KTR_GENIO))
241 		if (error == 0) {
242 			ktrgenio(p, fd, UIO_READ, ktriov, cnt,
243 			    error);
244 		free(ktriov, M_TEMP);
245 	}
246 #endif
247 	*retval = cnt;
248 done:
249 	if (needfree)
250 		free(needfree, M_IOV);
251 out:
252 	FILE_UNUSE(fp, p);
253 	return (error);
254 }
255 
256 int
257 netbsd32_writev(l, v, retval)
258 	struct lwp *l;
259 	void *v;
260 	register_t *retval;
261 {
262 	struct netbsd32_writev_args /* {
263 		syscallarg(int) fd;
264 		syscallarg(const netbsd32_iovecp_t) iovp;
265 		syscallarg(int) iovcnt;
266 	} */ *uap = v;
267 	int fd = SCARG(uap, fd);
268 	struct file *fp;
269 	struct proc *p = l->l_proc;
270 	struct filedesc *fdp = p->p_fd;
271 
272 	if ((fp = fd_getfile(fdp, fd)) == NULL)
273 		return (EBADF);
274 
275 	if ((fp->f_flag & FWRITE) == 0)
276 		return (EBADF);
277 
278 	FILE_USE(fp);
279 
280 	return (dofilewritev32(p, fd, fp,
281 	    (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)),
282 	    SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
283 }
284 
285 int
286 dofilewritev32(p, fd, fp, iovp, iovcnt, offset, flags, retval)
287 	struct proc *p;
288 	int fd;
289 	struct file *fp;
290 	struct netbsd32_iovec *iovp;
291 	int iovcnt;
292 	off_t *offset;
293 	int flags;
294 	register_t *retval;
295 {
296 	struct uio auio;
297 	struct iovec *iov;
298 	struct iovec *needfree;
299 	struct iovec aiov[UIO_SMALLIOV];
300 	long i, cnt, error = 0;
301 	u_int iovlen;
302 #ifdef KTRACE
303 	struct iovec *ktriov = NULL;
304 #endif
305 
306 	/* note: can't use iovlen until iovcnt is validated */
307 	iovlen = iovcnt * sizeof(struct iovec);
308 	if ((u_int)iovcnt > UIO_SMALLIOV) {
309 		if ((u_int)iovcnt > IOV_MAX) {
310 			error = EINVAL;
311 			goto out;
312 		}
313 		iov = malloc(iovlen, M_IOV, M_WAITOK);
314 		needfree = iov;
315 	} else if ((u_int)iovcnt > 0) {
316 		iov = aiov;
317 		needfree = NULL;
318 	} else {
319 		error = EINVAL;
320 		goto out;
321 	}
322 
323 	auio.uio_iov = iov;
324 	auio.uio_iovcnt = iovcnt;
325 	auio.uio_rw = UIO_WRITE;
326 	auio.uio_segflg = UIO_USERSPACE;
327 	auio.uio_procp = p;
328 	error = netbsd32_to_iovecin(iovp, iov, iovcnt);
329 	if (error)
330 		goto done;
331 	auio.uio_resid = 0;
332 	for (i = 0; i < iovcnt; i++) {
333 		auio.uio_resid += iov->iov_len;
334 		/*
335 		 * Writes return ssize_t because -1 is returned on error.
336 		 * Therefore we must restrict the length to SSIZE_MAX to
337 		 * avoid garbage return values.
338 		 */
339 		if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
340 			error = EINVAL;
341 			goto done;
342 		}
343 		iov++;
344 	}
345 #ifdef KTRACE
346 	/*
347 	 * if tracing, save a copy of iovec
348 	 */
349 	if (KTRPOINT(p, KTR_GENIO))  {
350 		ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
351 		memcpy((caddr_t)ktriov, (caddr_t)auio.uio_iov, iovlen);
352 	}
353 #endif
354 	cnt = auio.uio_resid;
355 	error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags);
356 	if (error) {
357 		if (auio.uio_resid != cnt && (error == ERESTART ||
358 		    error == EINTR || error == EWOULDBLOCK))
359 			error = 0;
360 		if (error == EPIPE)
361 			psignal(p, SIGPIPE);
362 	}
363 	cnt -= auio.uio_resid;
364 #ifdef KTRACE
365 	if (KTRPOINT(p, KTR_GENIO))
366 		if (error == 0) {
367 			ktrgenio(p, fd, UIO_WRITE, ktriov, cnt,
368 			    error);
369 		free(ktriov, M_TEMP);
370 	}
371 #endif
372 	*retval = cnt;
373 done:
374 	if (needfree)
375 		free(needfree, M_IOV);
376 out:
377 	FILE_UNUSE(fp, p);
378 	return (error);
379 }
380 
381 int
382 netbsd32_utimes(l, v, retval)
383 	struct lwp *l;
384 	void *v;
385 	register_t *retval;
386 {
387 	struct netbsd32_utimes_args /* {
388 		syscallarg(const netbsd32_charp) path;
389 		syscallarg(const netbsd32_timevalp_t) tptr;
390 	} */ *uap = v;
391 	int error;
392 	struct nameidata nd;
393 	struct proc *p = l->l_proc;
394 
395 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
396 	    (char *)NETBSD32PTR64(SCARG(uap, path)), p);
397 	if ((error = namei(&nd)) != 0)
398 		return (error);
399 
400 	error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), p);
401 
402 	vrele(nd.ni_vp);
403 	return (error);
404 }
405 
406 /*
407  * Common routine to set access and modification times given a vnode.
408  */
409 static int
410 change_utimes32(vp, tptr, p)
411 	struct vnode *vp;
412 	netbsd32_timevalp_t tptr;
413 	struct proc *p;
414 {
415 	struct netbsd32_timeval tv32[2];
416 	struct timeval tv[2];
417 	struct vattr vattr;
418 	int error;
419 
420 	VATTR_NULL(&vattr);
421 	if (tptr == 0) {
422 		microtime(&tv[0]);
423 		tv[1] = tv[0];
424 		vattr.va_vaflags |= VA_UTIMES_NULL;
425 	} else {
426 		error = copyin((caddr_t)NETBSD32PTR64(tptr), tv32,
427 		    sizeof(tv32));
428 		if (error)
429 			return (error);
430 		netbsd32_to_timeval(&tv32[0], &tv[0]);
431 		netbsd32_to_timeval(&tv32[1], &tv[1]);
432 	}
433 	VOP_LEASE(vp, p, p->p_ucred, LEASE_WRITE);
434 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
435 	vattr.va_atime.tv_sec = tv[0].tv_sec;
436 	vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
437 	vattr.va_mtime.tv_sec = tv[1].tv_sec;
438 	vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
439 	error = VOP_SETATTR(vp, &vattr, p->p_ucred, p);
440 	VOP_UNLOCK(vp, 0);
441 	return (error);
442 }
443 
444 int
445 netbsd32_statfs(l, v, retval)
446 	struct lwp *l;
447 	void *v;
448 	register_t *retval;
449 {
450 	struct netbsd32_statfs_args /* {
451 		syscallarg(const netbsd32_charp) path;
452 		syscallarg(netbsd32_statfsp_t) buf;
453 	} */ *uap = v;
454 	struct mount *mp;
455 	struct statvfs *sp;
456 	struct netbsd32_statfs s32;
457 	int error;
458 	struct nameidata nd;
459 	struct proc *p = l->l_proc;
460 
461 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE,
462 	    (char *)NETBSD32PTR64(SCARG(uap, path)), p);
463 	if ((error = namei(&nd)) != 0)
464 		return (error);
465 	mp = nd.ni_vp->v_mount;
466 	sp = &mp->mnt_stat;
467 	vrele(nd.ni_vp);
468 	if ((error = VFS_STATVFS(mp, sp, p)) != 0)
469 		return (error);
470 	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
471 	netbsd32_from_statvfs(sp, &s32);
472 	return (copyout(&s32, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)),
473 	    sizeof(s32)));
474 }
475 
476 int
477 netbsd32_fstatfs(l, v, retval)
478 	struct lwp *l;
479 	void *v;
480 	register_t *retval;
481 {
482 	struct netbsd32_fstatfs_args /* {
483 		syscallarg(int) fd;
484 		syscallarg(netbsd32_statfsp_t) buf;
485 	} */ *uap = v;
486 	struct file *fp;
487 	struct mount *mp;
488 	struct statvfs *sp;
489 	struct netbsd32_statfs s32;
490 	int error;
491 	struct proc *p = l->l_proc;
492 
493 	/* getvnode() will use the descriptor for us */
494 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
495 		return (error);
496 	mp = ((struct vnode *)fp->f_data)->v_mount;
497 	sp = &mp->mnt_stat;
498 	if ((error = VFS_STATVFS(mp, sp, p)) != 0)
499 		goto out;
500 	sp->f_flag = mp->mnt_flag & MNT_VISFLAGMASK;
501 	netbsd32_from_statvfs(sp, &s32);
502 	error = copyout(&s32, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)),
503 	    sizeof(s32));
504  out:
505 	FILE_UNUSE(fp, p);
506 	return (error);
507 }
508 
509 int
510 netbsd32_futimes(l, v, retval)
511 	struct lwp *l;
512 	void *v;
513 	register_t *retval;
514 {
515 	struct netbsd32_futimes_args /* {
516 		syscallarg(int) fd;
517 		syscallarg(const netbsd32_timevalp_t) tptr;
518 	} */ *uap = v;
519 	int error;
520 	struct file *fp;
521 	struct proc *p = l->l_proc;
522 
523 	/* getvnode() will use the descriptor for us */
524 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
525 		return (error);
526 
527 	error = change_utimes32((struct vnode *)fp->f_data,
528 				SCARG(uap, tptr), p);
529 	FILE_UNUSE(fp, p);
530 	return (error);
531 }
532 
533 int
534 netbsd32_getdents(l, v, retval)
535 	struct lwp *l;
536 	void *v;
537 	register_t *retval;
538 {
539 	struct netbsd32_getdents_args /* {
540 		syscallarg(int) fd;
541 		syscallarg(netbsd32_charp) buf;
542 		syscallarg(netbsd32_size_t) count;
543 	} */ *uap = v;
544 	struct file *fp;
545 	int error, done;
546 	struct proc *p = l->l_proc;
547 
548 	/* getvnode() will use the descriptor for us */
549 	if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
550 		return (error);
551 	if ((fp->f_flag & FREAD) == 0) {
552 		error = EBADF;
553 		goto out;
554 	}
555 	error = vn_readdir(fp, (caddr_t)NETBSD32PTR64(SCARG(uap, buf)),
556 	    UIO_USERSPACE, SCARG(uap, count), &done, p, 0, 0);
557 	*retval = done;
558  out:
559 	FILE_UNUSE(fp, p);
560 	return (error);
561 }
562 
563 int
564 netbsd32_lutimes(l, v, retval)
565 	struct lwp *l;
566 	void *v;
567 	register_t *retval;
568 {
569 	struct netbsd32_lutimes_args /* {
570 		syscallarg(const netbsd32_charp) path;
571 		syscallarg(const netbsd32_timevalp_t) tptr;
572 	} */ *uap = v;
573 	int error;
574 	struct nameidata nd;
575 	struct proc *p = l->l_proc;
576 
577 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE,
578 	    (caddr_t)NETBSD32PTR64(SCARG(uap, path)), p);
579 	if ((error = namei(&nd)) != 0)
580 		return (error);
581 
582 	error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), p);
583 
584 	vrele(nd.ni_vp);
585 	return (error);
586 }
587 
588 int
589 netbsd32___stat13(l, v, retval)
590 	struct lwp *l;
591 	void *v;
592 	register_t *retval;
593 {
594 	struct netbsd32___stat13_args /* {
595 		syscallarg(const netbsd32_charp) path;
596 		syscallarg(netbsd32_statp_t) ub;
597 	} */ *uap = v;
598 	struct netbsd32_stat sb32;
599 	struct stat sb;
600 	int error;
601 	struct nameidata nd;
602 	caddr_t sg;
603 	const char *path;
604 	struct proc *p = l->l_proc;
605 
606 	path = (char *)NETBSD32PTR64(SCARG(uap, path));
607 	sg = stackgap_init(p, 0);
608 	CHECK_ALT_EXIST(p, &sg, path);
609 
610 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, path, p);
611 	if ((error = namei(&nd)) != 0)
612 		return (error);
613 	error = vn_stat(nd.ni_vp, &sb, p);
614 	vput(nd.ni_vp);
615 	if (error)
616 		return (error);
617 	netbsd32_from___stat13(&sb, &sb32);
618 	error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, ub)),
619 	    sizeof(sb32));
620 	return (error);
621 }
622 
623 int
624 netbsd32___fstat13(l, v, retval)
625 	struct lwp *l;
626 	void *v;
627 	register_t *retval;
628 {
629 	struct netbsd32___fstat13_args /* {
630 		syscallarg(int) fd;
631 		syscallarg(netbsd32_statp_t) sb;
632 	} */ *uap = v;
633 	int fd = SCARG(uap, fd);
634 	struct proc *p = l->l_proc;
635 	struct filedesc *fdp = p->p_fd;
636 	struct file *fp;
637 	struct netbsd32_stat sb32;
638 	struct stat ub;
639 	int error = 0;
640 
641 	if ((fp = fd_getfile(fdp, fd)) == NULL)
642 		return (EBADF);
643 
644 	FILE_USE(fp);
645 	error = (*fp->f_ops->fo_stat)(fp, &ub, p);
646 	FILE_UNUSE(fp, p);
647 
648 	if (error == 0) {
649 		netbsd32_from___stat13(&ub, &sb32);
650 		error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, sb)),
651 		    sizeof(sb32));
652 	}
653 	return (error);
654 }
655 
656 int
657 netbsd32___lstat13(l, v, retval)
658 	struct lwp *l;
659 	void *v;
660 	register_t *retval;
661 {
662 	struct netbsd32___lstat13_args /* {
663 		syscallarg(const netbsd32_charp) path;
664 		syscallarg(netbsd32_statp_t) ub;
665 	} */ *uap = v;
666 	struct netbsd32_stat sb32;
667 	struct stat sb;
668 	int error;
669 	struct nameidata nd;
670 	caddr_t sg;
671 	const char *path;
672 	struct proc *p = l->l_proc;
673 
674 	path = (char *)NETBSD32PTR64(SCARG(uap, path));
675 	sg = stackgap_init(p, 0);
676 	CHECK_ALT_EXIST(p, &sg, path);
677 
678 	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, path, p);
679 	if ((error = namei(&nd)) != 0)
680 		return (error);
681 	error = vn_stat(nd.ni_vp, &sb, p);
682 	vput(nd.ni_vp);
683 	if (error)
684 		return (error);
685 	netbsd32_from___stat13(&sb, &sb32);
686 	error = copyout(&sb32, (caddr_t)NETBSD32PTR64(SCARG(uap, ub)),
687 	    sizeof(sb32));
688 	return (error);
689 }
690 
691 int
692 netbsd32_preadv(l, v, retval)
693 	struct lwp *l;
694 	void *v;
695 	register_t *retval;
696 {
697 	struct netbsd32_preadv_args /* {
698 		syscallarg(int) fd;
699 		syscallarg(const netbsd32_iovecp_t) iovp;
700 		syscallarg(int) iovcnt;
701 		syscallarg(int) pad;
702 		syscallarg(off_t) offset;
703 	} */ *uap = v;
704 	struct proc *p = l->l_proc;
705 	struct filedesc *fdp = p->p_fd;
706 	struct file *fp;
707 	struct vnode *vp;
708 	off_t offset;
709 	int error, fd = SCARG(uap, fd);
710 
711 	if ((fp = fd_getfile(fdp, fd)) == NULL)
712 		return (EBADF);
713 
714 	if ((fp->f_flag & FREAD) == 0)
715 		return (EBADF);
716 
717 	FILE_USE(fp);
718 
719 	vp = (struct vnode *)fp->f_data;
720 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
721 		error = ESPIPE;
722 		goto out;
723 	}
724 
725 	offset = SCARG(uap, offset);
726 
727 	/*
728 	 * XXX This works because no file systems actually
729 	 * XXX take any action on the seek operation.
730 	 */
731 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
732 		goto out;
733 
734 	return (dofilereadv32(p, fd, fp,
735 	    (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)),
736 	    SCARG(uap, iovcnt), &offset, 0, retval));
737 
738 out:
739 	FILE_UNUSE(fp, p);
740 	return (error);
741 }
742 
743 int
744 netbsd32_pwritev(l, v, retval)
745 	struct lwp *l;
746 	void *v;
747 	register_t *retval;
748 {
749 	struct netbsd32_pwritev_args /* {
750 		syscallarg(int) fd;
751 		syscallarg(const netbsd32_iovecp_t) iovp;
752 		syscallarg(int) iovcnt;
753 		syscallarg(int) pad;
754 		syscallarg(off_t) offset;
755 	} */ *uap = v;
756 	struct proc *p = l->l_proc;
757 	struct filedesc *fdp = p->p_fd;
758 	struct file *fp;
759 	struct vnode *vp;
760 	off_t offset;
761 	int error, fd = SCARG(uap, fd);
762 
763 	if ((fp = fd_getfile(fdp, fd)) == NULL)
764 		return (EBADF);
765 
766 	if ((fp->f_flag & FWRITE) == 0)
767 		return (EBADF);
768 
769 	FILE_USE(fp);
770 
771 	vp = (struct vnode *)fp->f_data;
772 	if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
773 		error = ESPIPE;
774 		goto out;
775 	}
776 
777 	offset = SCARG(uap, offset);
778 
779 	/*
780 	 * XXX This works because no file systems actually
781 	 * XXX take any action on the seek operation.
782 	 */
783 	if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
784 		goto out;
785 
786 	return (dofilewritev32(p, fd, fp,
787 	    (struct netbsd32_iovec *)NETBSD32PTR64(SCARG(uap, iovp)),
788 	    SCARG(uap, iovcnt), &offset, 0, retval));
789 
790 out:
791 	FILE_UNUSE(fp, p);
792 	return (error);
793 }
794 
795 /*
796  * Find pathname of process's current directory.
797  *
798  * Use vfs vnode-to-name reverse cache; if that fails, fall back
799  * to reading directory contents.
800  */
801 int
802 getcwd_common __P((struct vnode *, struct vnode *,
803 		   char **, char *, int, int, struct proc *));
804 
805 int netbsd32___getcwd(l, v, retval)
806 	struct lwp *l;
807 	void   *v;
808 	register_t *retval;
809 {
810 	struct netbsd32___getcwd_args /* {
811 		syscallarg(char *) bufp;
812 		syscallarg(size_t) length;
813 	} */ *uap = v;
814 	struct proc *p = l->l_proc;
815 	int     error;
816 	char   *path;
817 	char   *bp, *bend;
818 	int     len = (int)SCARG(uap, length);
819 	int	lenused;
820 
821 	if (len > MAXPATHLEN*4)
822 		len = MAXPATHLEN*4;
823 	else if (len < 2)
824 		return ERANGE;
825 
826 	path = (char *)malloc(len, M_TEMP, M_WAITOK);
827 	if (!path)
828 		return ENOMEM;
829 
830 	bp = &path[len];
831 	bend = bp;
832 	*(--bp) = '\0';
833 
834 	/*
835 	 * 5th argument here is "max number of vnodes to traverse".
836 	 * Since each entry takes up at least 2 bytes in the output buffer,
837 	 * limit it to N/2 vnodes for an N byte buffer.
838 	 */
839 #define GETCWD_CHECK_ACCESS 0x0001
840 	error = getcwd_common (p->p_cwdi->cwdi_cdir, NULL, &bp, path, len/2,
841 			       GETCWD_CHECK_ACCESS, p);
842 
843 	if (error)
844 		goto out;
845 	lenused = bend - bp;
846 	*retval = lenused;
847 	/* put the result into user buffer */
848 	error = copyout(bp, (caddr_t)NETBSD32PTR64(SCARG(uap, bufp)), lenused);
849 
850 out:
851 	free(path, M_TEMP);
852 	return error;
853 }
854