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