netbsd32_fs.c revision 1.42 1 /* $NetBSD: netbsd32_fs.c,v 1.42 2007/04/30 08:32:15 dsl Exp $ */
2
3 /*
4 * Copyright (c) 1998, 2001 Matthew R. Green
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
29 */
30
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: netbsd32_fs.c,v 1.42 2007/04/30 08:32:15 dsl 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/statvfs.h>
53 #include <sys/syscallargs.h>
54 #include <sys/proc.h>
55 #include <sys/dirent.h>
56 #include <sys/kauth.h>
57 #include <sys/vfs_syscalls.h>
58
59 #include <compat/netbsd32/netbsd32.h>
60 #include <compat/netbsd32/netbsd32_syscallargs.h>
61 #include <compat/netbsd32/netbsd32_conv.h>
62 #include <compat/sys/mount.h>
63
64
65 static int dofilereadv32 __P((struct lwp *, int, struct file *, struct netbsd32_iovec *,
66 int, off_t *, int, register_t *));
67 static int dofilewritev32 __P((struct lwp *, int, struct file *, struct netbsd32_iovec *,
68 int, off_t *, int, register_t *));
69 static int change_utimes32 __P((struct vnode *, netbsd32_timevalp_t, struct lwp *));
70
71 int
72 netbsd32_readv(l, v, retval)
73 struct lwp *l;
74 void *v;
75 register_t *retval;
76 {
77 struct netbsd32_readv_args /* {
78 syscallarg(int) fd;
79 syscallarg(const netbsd32_iovecp_t) iovp;
80 syscallarg(int) iovcnt;
81 } */ *uap = v;
82 int fd = SCARG(uap, fd);
83 struct proc *p = l->l_proc;
84 struct file *fp;
85 struct filedesc *fdp = p->p_fd;
86
87 if ((fp = fd_getfile(fdp, fd)) == NULL)
88 return (EBADF);
89
90 if ((fp->f_flag & FREAD) == 0)
91 return (EBADF);
92
93 FILE_USE(fp);
94
95 return (dofilereadv32(l, fd, fp,
96 (struct netbsd32_iovec *)SCARG_P32(uap, iovp),
97 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
98 }
99
100 /* Damn thing copies in the iovec! */
101 int
102 dofilereadv32(l, fd, fp, iovp, iovcnt, offset, flags, retval)
103 struct lwp *l;
104 int fd;
105 struct file *fp;
106 struct netbsd32_iovec *iovp;
107 int iovcnt;
108 off_t *offset;
109 int flags;
110 register_t *retval;
111 {
112 struct uio auio;
113 struct iovec *iov;
114 struct iovec *needfree;
115 struct iovec aiov[UIO_SMALLIOV];
116 long i, cnt, error = 0;
117 u_int iovlen;
118 #ifdef KTRACE
119 struct iovec *ktriov = NULL;
120 #endif
121
122 /* note: can't use iovlen until iovcnt is validated */
123 iovlen = iovcnt * sizeof(struct iovec);
124 if ((u_int)iovcnt > UIO_SMALLIOV) {
125 if ((u_int)iovcnt > IOV_MAX) {
126 error = EINVAL;
127 goto out;
128 }
129 iov = malloc(iovlen, M_IOV, M_WAITOK);
130 needfree = iov;
131 } else if ((u_int)iovcnt > 0) {
132 iov = aiov;
133 needfree = NULL;
134 } else {
135 error = EINVAL;
136 goto out;
137 }
138
139 auio.uio_iov = iov;
140 auio.uio_iovcnt = iovcnt;
141 auio.uio_rw = UIO_READ;
142 auio.uio_vmspace = l->l_proc->p_vmspace;
143 error = netbsd32_to_iovecin(iovp, iov, iovcnt);
144 if (error)
145 goto done;
146 auio.uio_resid = 0;
147 for (i = 0; i < iovcnt; i++) {
148 auio.uio_resid += iov->iov_len;
149 /*
150 * Reads return ssize_t because -1 is returned on error.
151 * Therefore we must restrict the length to SSIZE_MAX to
152 * avoid garbage return values.
153 */
154 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
155 error = EINVAL;
156 goto done;
157 }
158 iov++;
159 }
160 #ifdef KTRACE
161 /*
162 * if tracing, save a copy of iovec
163 */
164 if (KTRPOINT(l->l_proc, KTR_GENIO)) {
165 ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
166 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen);
167 }
168 #endif
169 cnt = auio.uio_resid;
170 error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags);
171 if (error)
172 if (auio.uio_resid != cnt && (error == ERESTART ||
173 error == EINTR || error == EWOULDBLOCK))
174 error = 0;
175 cnt -= auio.uio_resid;
176 #ifdef KTRACE
177 if (KTRPOINT(l->l_proc, KTR_GENIO))
178 if (error == 0) {
179 ktrgenio(l, fd, UIO_READ, ktriov, cnt,
180 error);
181 free(ktriov, M_TEMP);
182 }
183 #endif
184 *retval = cnt;
185 done:
186 if (needfree)
187 free(needfree, M_IOV);
188 out:
189 FILE_UNUSE(fp, l);
190 return (error);
191 }
192
193 int
194 netbsd32_writev(l, v, retval)
195 struct lwp *l;
196 void *v;
197 register_t *retval;
198 {
199 struct netbsd32_writev_args /* {
200 syscallarg(int) fd;
201 syscallarg(const netbsd32_iovecp_t) iovp;
202 syscallarg(int) iovcnt;
203 } */ *uap = v;
204 int fd = SCARG(uap, fd);
205 struct file *fp;
206 struct proc *p = l->l_proc;
207 struct filedesc *fdp = p->p_fd;
208
209 if ((fp = fd_getfile(fdp, fd)) == NULL)
210 return (EBADF);
211
212 if ((fp->f_flag & FWRITE) == 0)
213 return (EBADF);
214
215 FILE_USE(fp);
216
217 return (dofilewritev32(l, fd, fp,
218 (struct netbsd32_iovec *)SCARG_P32(uap, iovp),
219 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval));
220 }
221
222 int
223 dofilewritev32(l, fd, fp, iovp, iovcnt, offset, flags, retval)
224 struct lwp *l;
225 int fd;
226 struct file *fp;
227 struct netbsd32_iovec *iovp;
228 int iovcnt;
229 off_t *offset;
230 int flags;
231 register_t *retval;
232 {
233 struct uio auio;
234 struct iovec *iov;
235 struct iovec *needfree;
236 struct iovec aiov[UIO_SMALLIOV];
237 struct proc *p = l->l_proc;
238 long i, cnt, error = 0;
239 u_int iovlen;
240 #ifdef KTRACE
241 struct iovec *ktriov = NULL;
242 #endif
243
244 /* note: can't use iovlen until iovcnt is validated */
245 iovlen = iovcnt * sizeof(struct iovec);
246 if ((u_int)iovcnt > UIO_SMALLIOV) {
247 if ((u_int)iovcnt > IOV_MAX) {
248 error = EINVAL;
249 goto out;
250 }
251 iov = malloc(iovlen, M_IOV, M_WAITOK);
252 needfree = iov;
253 } else if ((u_int)iovcnt > 0) {
254 iov = aiov;
255 needfree = NULL;
256 } else {
257 error = EINVAL;
258 goto out;
259 }
260
261 auio.uio_iov = iov;
262 auio.uio_iovcnt = iovcnt;
263 auio.uio_rw = UIO_WRITE;
264 auio.uio_vmspace = l->l_proc->p_vmspace;
265 error = netbsd32_to_iovecin(iovp, iov, iovcnt);
266 if (error)
267 goto done;
268 auio.uio_resid = 0;
269 for (i = 0; i < iovcnt; i++) {
270 auio.uio_resid += iov->iov_len;
271 /*
272 * Writes return ssize_t because -1 is returned on error.
273 * Therefore we must restrict the length to SSIZE_MAX to
274 * avoid garbage return values.
275 */
276 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) {
277 error = EINVAL;
278 goto done;
279 }
280 iov++;
281 }
282 #ifdef KTRACE
283 /*
284 * if tracing, save a copy of iovec
285 */
286 if (KTRPOINT(p, KTR_GENIO)) {
287 ktriov = malloc(iovlen, M_TEMP, M_WAITOK);
288 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen);
289 }
290 #endif
291 cnt = auio.uio_resid;
292 error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags);
293 if (error) {
294 if (auio.uio_resid != cnt && (error == ERESTART ||
295 error == EINTR || error == EWOULDBLOCK))
296 error = 0;
297 if (error == EPIPE)
298 psignal(p, SIGPIPE);
299 }
300 cnt -= auio.uio_resid;
301 #ifdef KTRACE
302 if (KTRPOINT(p, KTR_GENIO))
303 if (error == 0) {
304 ktrgenio(l, fd, UIO_WRITE, ktriov, cnt,
305 error);
306 free(ktriov, M_TEMP);
307 }
308 #endif
309 *retval = cnt;
310 done:
311 if (needfree)
312 free(needfree, M_IOV);
313 out:
314 FILE_UNUSE(fp, l);
315 return (error);
316 }
317
318 int
319 netbsd32_utimes(l, v, retval)
320 struct lwp *l;
321 void *v;
322 register_t *retval;
323 {
324 struct netbsd32_utimes_args /* {
325 syscallarg(const netbsd32_charp) path;
326 syscallarg(const netbsd32_timevalp_t) tptr;
327 } */ *uap = v;
328 int error;
329 struct nameidata nd;
330
331 NDINIT(&nd, LOOKUP, FOLLOW | TRYEMULROOT, UIO_USERSPACE, SCARG_P32(uap, path), l);
332 if ((error = namei(&nd)) != 0)
333 return (error);
334
335 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), l);
336
337 vrele(nd.ni_vp);
338 return (error);
339 }
340
341 /*
342 * Common routine to set access and modification times given a vnode.
343 */
344 static int
345 change_utimes32(vp, tptr, l)
346 struct vnode *vp;
347 netbsd32_timevalp_t tptr;
348 struct lwp *l;
349 {
350 struct netbsd32_timeval tv32[2];
351 struct timeval tv[2];
352 struct vattr vattr;
353 int error;
354
355 VATTR_NULL(&vattr);
356 if (NETBSD32PTR64(tptr) == 0) {
357 microtime(&tv[0]);
358 tv[1] = tv[0];
359 vattr.va_vaflags |= VA_UTIMES_NULL;
360 } else {
361 error = copyin(NETBSD32PTR64(tptr), tv32,
362 sizeof(tv32));
363 if (error)
364 return (error);
365 netbsd32_to_timeval(&tv32[0], &tv[0]);
366 netbsd32_to_timeval(&tv32[1], &tv[1]);
367 }
368 VOP_LEASE(vp, l, l->l_cred, LEASE_WRITE);
369 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
370 vattr.va_atime.tv_sec = tv[0].tv_sec;
371 vattr.va_atime.tv_nsec = tv[0].tv_usec * 1000;
372 vattr.va_mtime.tv_sec = tv[1].tv_sec;
373 vattr.va_mtime.tv_nsec = tv[1].tv_usec * 1000;
374 error = VOP_SETATTR(vp, &vattr, l->l_cred, l);
375 VOP_UNLOCK(vp, 0);
376 return (error);
377 }
378
379 static int
380 netbds32_copyout_statvfs(const void *kp, void *up, size_t len)
381 {
382 struct netbsd32_statvfs *sbuf_32;
383 int error;
384
385 sbuf_32 = malloc(sizeof *sbuf_32, M_TEMP, M_WAITOK);
386 netbsd32_from_statvfs(kp, sbuf_32);
387 error = copyout(sbuf_32, up, sizeof(*sbuf_32));
388 free(sbuf_32, M_TEMP);
389
390 return error;
391 }
392
393 int
394 netbsd32_statvfs1(l, v, retval)
395 struct lwp *l;
396 void *v;
397 register_t *retval;
398 {
399 struct netbsd32_statvfs1_args /* {
400 syscallarg(const netbsd32_charp) path;
401 syscallarg(netbsd32_statvfsp_t) buf;
402 syscallarg(int) flags;
403 } */ *uap = v;
404 struct statvfs *sb;
405 int error;
406
407 sb = STATVFSBUF_GET();
408 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), SCARG(uap, flags), sb);
409 if (error == 0)
410 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
411 STATVFSBUF_PUT(sb);
412 return error;
413 }
414
415 int
416 netbsd32_fstatvfs1(l, v, retval)
417 struct lwp *l;
418 void *v;
419 register_t *retval;
420 {
421 struct netbsd32_fstatvfs1_args /* {
422 syscallarg(int) fd;
423 syscallarg(netbsd32_statvfsp_t) buf;
424 syscallarg(int) flags;
425 } */ *uap = v;
426 struct statvfs *sb;
427 int error;
428
429 sb = STATVFSBUF_GET();
430 error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb);
431 if (error == 0)
432 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
433 STATVFSBUF_PUT(sb);
434 return error;
435 }
436
437 int
438 netbsd32_getvfsstat(l, v, retval)
439 struct lwp *l;
440 void *v;
441 register_t *retval;
442 {
443 struct netbsd32_getvfsstat_args /* {
444 syscallarg(netbsd32_statvfsp_t) buf;
445 syscallarg(netbsd32_size_t) bufsize;
446 syscallarg(int) flags;
447 } */ *uap = v;
448
449 return do_sys_getvfsstat(l, SCARG_P32(uap, buf), SCARG(uap, bufsize),
450 SCARG(uap, flags), netbds32_copyout_statvfs,
451 sizeof (struct netbsd32_statvfs), retval);
452 }
453
454 int
455 netbsd32___fhstatvfs140(l, v, retval)
456 struct lwp *l;
457 void *v;
458 register_t *retval;
459 {
460 struct netbsd32___fhstatvfs140_args /* {
461 syscallarg(const netbsd32_pointer_t) fhp;
462 syscallarg(netbsd32_size_t) fh_size;
463 syscallarg(netbsd32_statvfsp_t) buf;
464 syscallarg(int) flags;
465 } */ *uap = v;
466 struct statvfs *sb;
467 int error;
468
469 sb = STATVFSBUF_GET();
470 error = do_fhstatvfs(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), sb,
471 SCARG(uap, flags));
472
473 if (error == 0)
474 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0);
475 STATVFSBUF_PUT(sb);
476
477 return error;
478 }
479
480 int
481 netbsd32_futimes(l, v, retval)
482 struct lwp *l;
483 void *v;
484 register_t *retval;
485 {
486 struct netbsd32_futimes_args /* {
487 syscallarg(int) fd;
488 syscallarg(const netbsd32_timevalp_t) tptr;
489 } */ *uap = v;
490 int error;
491 struct file *fp;
492 struct proc *p = l->l_proc;
493
494 /* getvnode() will use the descriptor for us */
495 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
496 return (error);
497
498 error = change_utimes32((struct vnode *)fp->f_data,
499 SCARG(uap, tptr), l);
500 FILE_UNUSE(fp, l);
501 return (error);
502 }
503
504 int
505 netbsd32_sys___getdents30(l, v, retval)
506 struct lwp *l;
507 void *v;
508 register_t *retval;
509 {
510 struct netbsd32_sys___getdents30_args /* {
511 syscallarg(int) fd;
512 syscallarg(netbsd32_charp) buf;
513 syscallarg(netbsd32_size_t) count;
514 } */ *uap = v;
515 struct file *fp;
516 int error, done;
517 struct proc *p = l->l_proc;
518
519 /* getvnode() will use the descriptor for us */
520 if ((error = getvnode(p->p_fd, SCARG(uap, fd), &fp)) != 0)
521 return (error);
522 if ((fp->f_flag & FREAD) == 0) {
523 error = EBADF;
524 goto out;
525 }
526 error = vn_readdir(fp, SCARG_P32(uap, buf),
527 UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0);
528 *retval = done;
529 out:
530 FILE_UNUSE(fp, l);
531 return (error);
532 }
533
534 int
535 netbsd32_lutimes(l, v, retval)
536 struct lwp *l;
537 void *v;
538 register_t *retval;
539 {
540 struct netbsd32_lutimes_args /* {
541 syscallarg(const netbsd32_charp) path;
542 syscallarg(const netbsd32_timevalp_t) tptr;
543 } */ *uap = v;
544 int error;
545 struct nameidata nd;
546
547 NDINIT(&nd, LOOKUP, NOFOLLOW | TRYEMULROOT, UIO_USERSPACE, SCARG_P32(uap, path), l);
548 if ((error = namei(&nd)) != 0)
549 return (error);
550
551 error = change_utimes32(nd.ni_vp, SCARG(uap, tptr), l);
552
553 vrele(nd.ni_vp);
554 return (error);
555 }
556
557 int
558 netbsd32_sys___stat30(l, v, retval)
559 struct lwp *l;
560 void *v;
561 register_t *retval;
562 {
563 struct netbsd32_sys___stat30_args /* {
564 syscallarg(const netbsd32_charp) path;
565 syscallarg(netbsd32_statp_t) ub;
566 } */ *uap = v;
567 struct netbsd32_stat sb32;
568 struct stat sb;
569 int error;
570 const char *path;
571
572 path = SCARG_P32(uap, path);
573
574 error = do_sys_stat(l, path, FOLLOW, &sb);
575 if (error)
576 return (error);
577 netbsd32_from___stat30(&sb, &sb32);
578 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32));
579 return (error);
580 }
581
582 int
583 netbsd32_sys___fstat30(l, v, retval)
584 struct lwp *l;
585 void *v;
586 register_t *retval;
587 {
588 struct netbsd32_sys___fstat30_args /* {
589 syscallarg(int) fd;
590 syscallarg(netbsd32_statp_t) sb;
591 } */ *uap = v;
592 int fd = SCARG(uap, fd);
593 struct proc *p = l->l_proc;
594 struct filedesc *fdp = p->p_fd;
595 struct file *fp;
596 struct netbsd32_stat sb32;
597 struct stat ub;
598 int error = 0;
599
600 if ((fp = fd_getfile(fdp, fd)) == NULL)
601 return (EBADF);
602
603 FILE_USE(fp);
604 error = (*fp->f_ops->fo_stat)(fp, &ub, l);
605 FILE_UNUSE(fp, l);
606
607 if (error == 0) {
608 netbsd32_from___stat30(&ub, &sb32);
609 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb32));
610 }
611 return (error);
612 }
613
614 int
615 netbsd32_sys___lstat30(l, v, retval)
616 struct lwp *l;
617 void *v;
618 register_t *retval;
619 {
620 struct netbsd32_sys___lstat30_args /* {
621 syscallarg(const netbsd32_charp) path;
622 syscallarg(netbsd32_statp_t) ub;
623 } */ *uap = v;
624 struct netbsd32_stat sb32;
625 struct stat sb;
626 int error;
627 const char *path;
628
629 path = SCARG_P32(uap, path);
630
631 error = do_sys_stat(l, path, NOFOLLOW, &sb);
632 if (error)
633 return (error);
634 netbsd32_from___stat30(&sb, &sb32);
635 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32));
636 return (error);
637 }
638
639 int netbsd32___fhstat40(l, v, retval)
640 struct lwp *l;
641 void *v;
642 register_t *retval;
643 {
644 struct netbsd32___fhstat40_args /* {
645 syscallarg(const netbsd32_pointer_t) fhp;
646 syscallarg(netbsd32_size_t) fh_size;
647 syscallarg(netbsd32_statp_t) sb;
648 } */ *uap = v;
649 struct stat sb;
650 struct netbsd32_stat sb32;
651 int error;
652
653 error = do_fhstat(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), &sb);
654 if (error != 0) {
655 netbsd32_from___stat30(&sb, &sb32);
656 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb));
657 }
658 return error;
659 }
660
661 int
662 netbsd32_preadv(l, v, retval)
663 struct lwp *l;
664 void *v;
665 register_t *retval;
666 {
667 struct netbsd32_preadv_args /* {
668 syscallarg(int) fd;
669 syscallarg(const netbsd32_iovecp_t) iovp;
670 syscallarg(int) iovcnt;
671 syscallarg(int) pad;
672 syscallarg(off_t) offset;
673 } */ *uap = v;
674 struct proc *p = l->l_proc;
675 struct filedesc *fdp = p->p_fd;
676 struct file *fp;
677 struct vnode *vp;
678 off_t offset;
679 int error, fd = SCARG(uap, fd);
680
681 if ((fp = fd_getfile(fdp, fd)) == NULL)
682 return (EBADF);
683
684 if ((fp->f_flag & FREAD) == 0)
685 return (EBADF);
686
687 FILE_USE(fp);
688
689 vp = (struct vnode *)fp->f_data;
690 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
691 error = ESPIPE;
692 goto out;
693 }
694
695 offset = SCARG(uap, offset);
696
697 /*
698 * XXX This works because no file systems actually
699 * XXX take any action on the seek operation.
700 */
701 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
702 goto out;
703
704 return (dofilereadv32(l, fd, fp, SCARG_P32(uap, iovp),
705 SCARG(uap, iovcnt), &offset, 0, retval));
706
707 out:
708 FILE_UNUSE(fp, l);
709 return (error);
710 }
711
712 int
713 netbsd32_pwritev(l, v, retval)
714 struct lwp *l;
715 void *v;
716 register_t *retval;
717 {
718 struct netbsd32_pwritev_args /* {
719 syscallarg(int) fd;
720 syscallarg(const netbsd32_iovecp_t) iovp;
721 syscallarg(int) iovcnt;
722 syscallarg(int) pad;
723 syscallarg(off_t) offset;
724 } */ *uap = v;
725 struct proc *p = l->l_proc;
726 struct filedesc *fdp = p->p_fd;
727 struct file *fp;
728 struct vnode *vp;
729 off_t offset;
730 int error, fd = SCARG(uap, fd);
731
732 if ((fp = fd_getfile(fdp, fd)) == NULL)
733 return (EBADF);
734
735 if ((fp->f_flag & FWRITE) == 0)
736 return (EBADF);
737
738 FILE_USE(fp);
739
740 vp = (struct vnode *)fp->f_data;
741 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) {
742 error = ESPIPE;
743 goto out;
744 }
745
746 offset = SCARG(uap, offset);
747
748 /*
749 * XXX This works because no file systems actually
750 * XXX take any action on the seek operation.
751 */
752 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0)
753 goto out;
754
755 return (dofilewritev32(l, fd, fp, SCARG_P32(uap, iovp),
756 SCARG(uap, iovcnt), &offset, 0, retval));
757
758 out:
759 FILE_UNUSE(fp, l);
760 return (error);
761 }
762
763 /*
764 * Find pathname of process's current directory.
765 *
766 * Use vfs vnode-to-name reverse cache; if that fails, fall back
767 * to reading directory contents.
768 */
769 /* XXX NH Why does this exist */
770 int
771 getcwd_common __P((struct vnode *, struct vnode *,
772 char **, char *, int, int, struct lwp *));
773
774 int netbsd32___getcwd(l, v, retval)
775 struct lwp *l;
776 void *v;
777 register_t *retval;
778 {
779 struct netbsd32___getcwd_args /* {
780 syscallarg(char *) bufp;
781 syscallarg(size_t) length;
782 } */ *uap = v;
783 struct proc *p = l->l_proc;
784 int error;
785 char *path;
786 char *bp, *bend;
787 int len = (int)SCARG(uap, length);
788 int lenused;
789
790 if (len > MAXPATHLEN*4)
791 len = MAXPATHLEN*4;
792 else if (len < 2)
793 return ERANGE;
794
795 path = (char *)malloc(len, M_TEMP, M_WAITOK);
796 if (!path)
797 return ENOMEM;
798
799 bp = &path[len];
800 bend = bp;
801 *(--bp) = '\0';
802
803 /*
804 * 5th argument here is "max number of vnodes to traverse".
805 * Since each entry takes up at least 2 bytes in the output buffer,
806 * limit it to N/2 vnodes for an N byte buffer.
807 */
808 #define GETCWD_CHECK_ACCESS 0x0001
809 error = getcwd_common (p->p_cwdi->cwdi_cdir, NULL, &bp, path, len/2,
810 GETCWD_CHECK_ACCESS, l);
811
812 if (error)
813 goto out;
814 lenused = bend - bp;
815 *retval = lenused;
816 /* put the result into user buffer */
817 error = copyout(bp, SCARG_P32(uap, bufp), lenused);
818
819 out:
820 free(path, M_TEMP);
821 return error;
822 }
823