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