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