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