Home | History | Annotate | Line # | Download | only in netbsd32
netbsd32_fs.c revision 1.46.10.1
      1 /*	$NetBSD: netbsd32_fs.c,v 1.46.10.1 2007/12/08 17:56:58 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.10.1 2007/12/08 17:56:58 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(struct lwp *, int, struct file *, struct netbsd32_iovec *,
     62 			      int, off_t *, int, register_t *);
     63 static int dofilewritev32(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(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