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