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