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