1 /* $NetBSD: netbsd32_fs.c,v 1.53 2008/04/24 15:35:27 ad 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.53 2008/04/24 15:35:27 ad Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/malloc.h> 37 #include <sys/mount.h> 38 #include <sys/socket.h> 39 #include <sys/socketvar.h> 40 #include <sys/stat.h> 41 #include <sys/time.h> 42 #include <sys/ktrace.h> 43 #include <sys/resourcevar.h> 44 #include <sys/vnode.h> 45 #include <sys/file.h> 46 #include <sys/filedesc.h> 47 #include <sys/namei.h> 48 #include <sys/statvfs.h> 49 #include <sys/syscallargs.h> 50 #include <sys/proc.h> 51 #include <sys/dirent.h> 52 #include <sys/kauth.h> 53 #include <sys/vfs_syscalls.h> 54 55 #include <compat/netbsd32/netbsd32.h> 56 #include <compat/netbsd32/netbsd32_syscallargs.h> 57 #include <compat/netbsd32/netbsd32_conv.h> 58 #include <compat/sys/mount.h> 59 60 61 static int dofilereadv32(int, struct file *, struct netbsd32_iovec *, 62 int, off_t *, int, register_t *); 63 static int dofilewritev32(int, struct file *, struct netbsd32_iovec *, 64 int, off_t *, int, register_t *); 65 66 struct iovec * 67 netbsd32_get_iov(struct netbsd32_iovec *iov32, int iovlen, struct iovec *aiov, 68 int aiov_len) 69 { 70 #define N_IOV32 8 71 struct netbsd32_iovec aiov32[N_IOV32]; 72 struct iovec *iov = aiov; 73 struct iovec *iovp; 74 int i, n, j; 75 int error; 76 77 if (iovlen < 0 || iovlen > IOV_MAX) 78 return NULL; 79 80 if (iovlen > aiov_len) 81 iov = malloc(iovlen * sizeof (*iov), M_TEMP, M_WAITOK); 82 83 iovp = iov; 84 for (i = 0; i < iovlen; iov32 += N_IOV32, i += N_IOV32) { 85 n = iovlen - i; 86 if (n > N_IOV32) 87 n = N_IOV32; 88 error = copyin(iov32, aiov32, n * sizeof (*iov32)); 89 if (error != 0) { 90 if (iov != aiov) 91 free(iov, M_TEMP); 92 return NULL; 93 } 94 for (j = 0; j < n; iovp++, j++) { 95 iovp->iov_base = NETBSD32PTR64(aiov32[j].iov_base); 96 iovp->iov_len = aiov32[j].iov_len; 97 } 98 } 99 return iov; 100 #undef N_IOV32 101 } 102 103 int 104 netbsd32_readv(struct lwp *l, const struct netbsd32_readv_args *uap, register_t *retval) 105 { 106 /* { 107 syscallarg(int) fd; 108 syscallarg(const netbsd32_iovecp_t) iovp; 109 syscallarg(int) iovcnt; 110 } */ 111 int fd = SCARG(uap, fd); 112 file_t *fp; 113 114 if ((fp = fd_getfile(fd)) == NULL) 115 return (EBADF); 116 117 if ((fp->f_flag & FREAD) == 0) { 118 fd_putfile(fd); 119 return (EBADF); 120 } 121 122 return (dofilereadv32(fd, fp, 123 (struct netbsd32_iovec *)SCARG_P32(uap, iovp), 124 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 125 } 126 127 /* Damn thing copies in the iovec! */ 128 int 129 dofilereadv32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval) 130 { 131 struct uio auio; 132 struct iovec *iov; 133 struct iovec *needfree; 134 struct iovec aiov[UIO_SMALLIOV]; 135 long i, cnt, error = 0; 136 u_int iovlen; 137 struct iovec *ktriov = NULL; 138 139 /* note: can't use iovlen until iovcnt is validated */ 140 iovlen = iovcnt * sizeof(struct iovec); 141 if ((u_int)iovcnt > UIO_SMALLIOV) { 142 if ((u_int)iovcnt > IOV_MAX) { 143 error = EINVAL; 144 goto out; 145 } 146 iov = malloc(iovlen, M_IOV, M_WAITOK); 147 needfree = iov; 148 } else if ((u_int)iovcnt > 0) { 149 iov = aiov; 150 needfree = NULL; 151 } else { 152 error = EINVAL; 153 goto out; 154 } 155 156 auio.uio_iov = iov; 157 auio.uio_iovcnt = iovcnt; 158 auio.uio_rw = UIO_READ; 159 auio.uio_vmspace = curproc->p_vmspace; 160 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 161 if (error) 162 goto done; 163 auio.uio_resid = 0; 164 for (i = 0; i < iovcnt; i++) { 165 auio.uio_resid += iov->iov_len; 166 /* 167 * Reads return ssize_t because -1 is returned on error. 168 * Therefore we must restrict the length to SSIZE_MAX to 169 * avoid garbage return values. 170 */ 171 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 172 error = EINVAL; 173 goto done; 174 } 175 iov++; 176 } 177 178 /* 179 * if tracing, save a copy of iovec 180 */ 181 if (ktrpoint(KTR_GENIO)) { 182 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 183 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); 184 } 185 186 cnt = auio.uio_resid; 187 error = (*fp->f_ops->fo_read)(fp, offset, &auio, fp->f_cred, flags); 188 if (error) 189 if (auio.uio_resid != cnt && (error == ERESTART || 190 error == EINTR || error == EWOULDBLOCK)) 191 error = 0; 192 cnt -= auio.uio_resid; 193 194 if (ktriov != NULL) { 195 ktrgeniov(fd, UIO_READ, ktriov, cnt, error); 196 free(ktriov, M_TEMP); 197 } 198 199 *retval = cnt; 200 done: 201 if (needfree) 202 free(needfree, M_IOV); 203 out: 204 fd_putfile(fd); 205 return (error); 206 } 207 208 int 209 netbsd32_writev(struct lwp *l, const struct netbsd32_writev_args *uap, register_t *retval) 210 { 211 /* { 212 syscallarg(int) fd; 213 syscallarg(const netbsd32_iovecp_t) iovp; 214 syscallarg(int) iovcnt; 215 } */ 216 int fd = SCARG(uap, fd); 217 file_t *fp; 218 219 if ((fp = fd_getfile(fd)) == NULL) 220 return (EBADF); 221 222 if ((fp->f_flag & FWRITE) == 0) { 223 fd_putfile(fd); 224 return (EBADF); 225 } 226 227 return (dofilewritev32(fd, fp, 228 (struct netbsd32_iovec *)SCARG_P32(uap, iovp), 229 SCARG(uap, iovcnt), &fp->f_offset, FOF_UPDATE_OFFSET, retval)); 230 } 231 232 int 233 dofilewritev32(int fd, struct file *fp, struct netbsd32_iovec *iovp, int iovcnt, off_t *offset, int flags, register_t *retval) 234 { 235 struct uio auio; 236 struct iovec *iov; 237 struct iovec *needfree; 238 struct iovec aiov[UIO_SMALLIOV]; 239 long i, cnt, error = 0; 240 u_int iovlen; 241 struct iovec *ktriov = NULL; 242 243 /* note: can't use iovlen until iovcnt is validated */ 244 iovlen = iovcnt * sizeof(struct iovec); 245 if ((u_int)iovcnt > UIO_SMALLIOV) { 246 if ((u_int)iovcnt > IOV_MAX) { 247 error = EINVAL; 248 goto out; 249 } 250 iov = malloc(iovlen, M_IOV, M_WAITOK); 251 needfree = iov; 252 } else if ((u_int)iovcnt > 0) { 253 iov = aiov; 254 needfree = NULL; 255 } else { 256 error = EINVAL; 257 goto out; 258 } 259 260 auio.uio_iov = iov; 261 auio.uio_iovcnt = iovcnt; 262 auio.uio_rw = UIO_WRITE; 263 auio.uio_vmspace = curproc->p_vmspace; 264 error = netbsd32_to_iovecin(iovp, iov, iovcnt); 265 if (error) 266 goto done; 267 auio.uio_resid = 0; 268 for (i = 0; i < iovcnt; i++) { 269 auio.uio_resid += iov->iov_len; 270 /* 271 * Writes return ssize_t because -1 is returned on error. 272 * Therefore we must restrict the length to SSIZE_MAX to 273 * avoid garbage return values. 274 */ 275 if (iov->iov_len > SSIZE_MAX || auio.uio_resid > SSIZE_MAX) { 276 error = EINVAL; 277 goto done; 278 } 279 iov++; 280 } 281 282 /* 283 * if tracing, save a copy of iovec 284 */ 285 if (ktrpoint(KTR_GENIO)) { 286 ktriov = malloc(iovlen, M_TEMP, M_WAITOK); 287 memcpy((void *)ktriov, (void *)auio.uio_iov, iovlen); 288 } 289 290 cnt = auio.uio_resid; 291 error = (*fp->f_ops->fo_write)(fp, offset, &auio, fp->f_cred, flags); 292 if (error) { 293 if (auio.uio_resid != cnt && (error == ERESTART || 294 error == EINTR || error == EWOULDBLOCK)) 295 error = 0; 296 if (error == EPIPE) { 297 mutex_enter(proc_lock); 298 psignal(curproc, SIGPIPE); 299 mutex_exit(proc_lock); 300 } 301 } 302 cnt -= auio.uio_resid; 303 if (ktriov != NULL) { 304 ktrgenio(fd, UIO_WRITE, ktriov, cnt, error); 305 free(ktriov, M_TEMP); 306 } 307 *retval = cnt; 308 done: 309 if (needfree) 310 free(needfree, M_IOV); 311 out: 312 fd_putfile(fd); 313 return (error); 314 } 315 316 /* 317 * Common routine to set access and modification times given a vnode. 318 */ 319 static int 320 get_utimes32(const netbsd32_timevalp_t *tptr, struct timeval *tv, 321 struct timeval **tvp) 322 { 323 int error; 324 struct netbsd32_timeval tv32[2]; 325 326 if (tptr == NULL) { 327 *tvp = NULL; 328 return 0; 329 } 330 331 error = copyin(tptr, tv32, sizeof(tv32)); 332 if (error) 333 return error; 334 netbsd32_to_timeval(&tv32[0], &tv[0]); 335 netbsd32_to_timeval(&tv32[1], &tv[1]); 336 337 *tvp = tv; 338 return 0; 339 } 340 341 int 342 netbsd32_utimes(struct lwp *l, const struct netbsd32_utimes_args *uap, register_t *retval) 343 { 344 /* { 345 syscallarg(const netbsd32_charp) path; 346 syscallarg(const netbsd32_timevalp_t) tptr; 347 } */ 348 int error; 349 struct timeval tv[2], *tvp; 350 351 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 352 if (error != 0) 353 return error; 354 355 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), FOLLOW, 356 tvp, UIO_SYSSPACE); 357 } 358 359 static int 360 netbds32_copyout_statvfs(const void *kp, void *up, size_t len) 361 { 362 struct netbsd32_statvfs *sbuf_32; 363 int error; 364 365 sbuf_32 = malloc(sizeof *sbuf_32, M_TEMP, M_WAITOK); 366 netbsd32_from_statvfs(kp, sbuf_32); 367 error = copyout(sbuf_32, up, sizeof(*sbuf_32)); 368 free(sbuf_32, M_TEMP); 369 370 return error; 371 } 372 373 int 374 netbsd32_statvfs1(struct lwp *l, const struct netbsd32_statvfs1_args *uap, register_t *retval) 375 { 376 /* { 377 syscallarg(const netbsd32_charp) path; 378 syscallarg(netbsd32_statvfsp_t) buf; 379 syscallarg(int) flags; 380 } */ 381 struct statvfs *sb; 382 int error; 383 384 sb = STATVFSBUF_GET(); 385 error = do_sys_pstatvfs(l, SCARG_P32(uap, path), SCARG(uap, flags), sb); 386 if (error == 0) 387 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 388 STATVFSBUF_PUT(sb); 389 return error; 390 } 391 392 int 393 netbsd32_fstatvfs1(struct lwp *l, const struct netbsd32_fstatvfs1_args *uap, register_t *retval) 394 { 395 /* { 396 syscallarg(int) fd; 397 syscallarg(netbsd32_statvfsp_t) buf; 398 syscallarg(int) flags; 399 } */ 400 struct statvfs *sb; 401 int error; 402 403 sb = STATVFSBUF_GET(); 404 error = do_sys_fstatvfs(l, SCARG(uap, fd), SCARG(uap, flags), sb); 405 if (error == 0) 406 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 407 STATVFSBUF_PUT(sb); 408 return error; 409 } 410 411 int 412 netbsd32_getvfsstat(struct lwp *l, const struct netbsd32_getvfsstat_args *uap, register_t *retval) 413 { 414 /* { 415 syscallarg(netbsd32_statvfsp_t) buf; 416 syscallarg(netbsd32_size_t) bufsize; 417 syscallarg(int) flags; 418 } */ 419 420 return do_sys_getvfsstat(l, SCARG_P32(uap, buf), SCARG(uap, bufsize), 421 SCARG(uap, flags), netbds32_copyout_statvfs, 422 sizeof (struct netbsd32_statvfs), retval); 423 } 424 425 int 426 netbsd32___fhstatvfs140(struct lwp *l, const struct netbsd32___fhstatvfs140_args *uap, register_t *retval) 427 { 428 /* { 429 syscallarg(const netbsd32_pointer_t) fhp; 430 syscallarg(netbsd32_size_t) fh_size; 431 syscallarg(netbsd32_statvfsp_t) buf; 432 syscallarg(int) flags; 433 } */ 434 struct statvfs *sb; 435 int error; 436 437 sb = STATVFSBUF_GET(); 438 error = do_fhstatvfs(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), sb, 439 SCARG(uap, flags)); 440 441 if (error == 0) 442 error = netbds32_copyout_statvfs(sb, SCARG_P32(uap, buf), 0); 443 STATVFSBUF_PUT(sb); 444 445 return error; 446 } 447 448 int 449 netbsd32_futimes(struct lwp *l, const struct netbsd32_futimes_args *uap, register_t *retval) 450 { 451 /* { 452 syscallarg(int) fd; 453 syscallarg(const netbsd32_timevalp_t) tptr; 454 } */ 455 int error; 456 file_t *fp; 457 struct timeval tv[2], *tvp; 458 459 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 460 if (error != 0) 461 return error; 462 463 /* getvnode() will use the descriptor for us */ 464 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 465 return (error); 466 467 error = do_sys_utimes(l, fp->f_data, NULL, 0, tvp, UIO_SYSSPACE); 468 469 fd_putfile(SCARG(uap, fd)); 470 return (error); 471 } 472 473 int 474 netbsd32_sys___getdents30(struct lwp *l, const struct netbsd32_sys___getdents30_args *uap, register_t *retval) 475 { 476 /* { 477 syscallarg(int) fd; 478 syscallarg(netbsd32_charp) buf; 479 syscallarg(netbsd32_size_t) count; 480 } */ 481 file_t *fp; 482 int error, done; 483 484 /* getvnode() will use the descriptor for us */ 485 if ((error = fd_getvnode(SCARG(uap, fd), &fp)) != 0) 486 return (error); 487 if ((fp->f_flag & FREAD) == 0) { 488 error = EBADF; 489 goto out; 490 } 491 error = vn_readdir(fp, SCARG_P32(uap, buf), 492 UIO_USERSPACE, SCARG(uap, count), &done, l, 0, 0); 493 *retval = done; 494 out: 495 fd_putfile(SCARG(uap, fd)); 496 return (error); 497 } 498 499 int 500 netbsd32_lutimes(struct lwp *l, const struct netbsd32_lutimes_args *uap, register_t *retval) 501 { 502 /* { 503 syscallarg(const netbsd32_charp) path; 504 syscallarg(const netbsd32_timevalp_t) tptr; 505 } */ 506 int error; 507 struct timeval tv[2], *tvp; 508 509 error = get_utimes32(SCARG_P32(uap, tptr), tv, &tvp); 510 if (error != 0) 511 return error; 512 513 return do_sys_utimes(l, NULL, SCARG_P32(uap, path), NOFOLLOW, 514 tvp, UIO_SYSSPACE); 515 } 516 517 int 518 netbsd32_sys___stat30(struct lwp *l, const struct netbsd32_sys___stat30_args *uap, register_t *retval) 519 { 520 /* { 521 syscallarg(const netbsd32_charp) path; 522 syscallarg(netbsd32_statp_t) ub; 523 } */ 524 struct netbsd32_stat sb32; 525 struct stat sb; 526 int error; 527 const char *path; 528 529 path = SCARG_P32(uap, path); 530 531 error = do_sys_stat(path, FOLLOW, &sb); 532 if (error) 533 return (error); 534 netbsd32_from___stat30(&sb, &sb32); 535 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32)); 536 return (error); 537 } 538 539 int 540 netbsd32_sys___fstat30(struct lwp *l, const struct netbsd32_sys___fstat30_args *uap, register_t *retval) 541 { 542 /* { 543 syscallarg(int) fd; 544 syscallarg(netbsd32_statp_t) sb; 545 } */ 546 int fd = SCARG(uap, fd); 547 file_t *fp; 548 struct netbsd32_stat sb32; 549 struct stat ub; 550 int error = 0; 551 552 if ((fp = fd_getfile(fd)) == NULL) 553 return (EBADF); 554 error = (*fp->f_ops->fo_stat)(fp, &ub); 555 fd_putfile(fd); 556 if (error == 0) { 557 netbsd32_from___stat30(&ub, &sb32); 558 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb32)); 559 } 560 return (error); 561 } 562 563 int 564 netbsd32_sys___lstat30(struct lwp *l, const struct netbsd32_sys___lstat30_args *uap, register_t *retval) 565 { 566 /* { 567 syscallarg(const netbsd32_charp) path; 568 syscallarg(netbsd32_statp_t) ub; 569 } */ 570 struct netbsd32_stat sb32; 571 struct stat sb; 572 int error; 573 const char *path; 574 575 path = SCARG_P32(uap, path); 576 577 error = do_sys_stat(path, NOFOLLOW, &sb); 578 if (error) 579 return (error); 580 netbsd32_from___stat30(&sb, &sb32); 581 error = copyout(&sb32, SCARG_P32(uap, ub), sizeof(sb32)); 582 return (error); 583 } 584 585 int 586 netbsd32___fhstat40(struct lwp *l, const struct netbsd32___fhstat40_args *uap, register_t *retval) 587 { 588 /* { 589 syscallarg(const netbsd32_pointer_t) fhp; 590 syscallarg(netbsd32_size_t) fh_size; 591 syscallarg(netbsd32_statp_t) sb; 592 } */ 593 struct stat sb; 594 struct netbsd32_stat sb32; 595 int error; 596 597 error = do_fhstat(l, SCARG_P32(uap, fhp), SCARG(uap, fh_size), &sb); 598 if (error != 0) { 599 netbsd32_from___stat30(&sb, &sb32); 600 error = copyout(&sb32, SCARG_P32(uap, sb), sizeof(sb)); 601 } 602 return error; 603 } 604 605 int 606 netbsd32_preadv(struct lwp *l, const struct netbsd32_preadv_args *uap, register_t *retval) 607 { 608 /* { 609 syscallarg(int) fd; 610 syscallarg(const netbsd32_iovecp_t) iovp; 611 syscallarg(int) iovcnt; 612 syscallarg(int) pad; 613 syscallarg(off_t) offset; 614 } */ 615 file_t *fp; 616 struct vnode *vp; 617 off_t offset; 618 int error, fd = SCARG(uap, fd); 619 620 if ((fp = fd_getfile(fd)) == NULL) 621 return (EBADF); 622 623 if ((fp->f_flag & FREAD) == 0) { 624 fd_putfile(fd); 625 return (EBADF); 626 } 627 628 vp = fp->f_data; 629 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 630 error = ESPIPE; 631 goto out; 632 } 633 634 offset = SCARG(uap, offset); 635 636 /* 637 * XXX This works because no file systems actually 638 * XXX take any action on the seek operation. 639 */ 640 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 641 goto out; 642 643 return (dofilereadv32(fd, fp, SCARG_P32(uap, iovp), 644 SCARG(uap, iovcnt), &offset, 0, retval)); 645 646 out: 647 fd_putfile(fd); 648 return (error); 649 } 650 651 int 652 netbsd32_pwritev(struct lwp *l, const struct netbsd32_pwritev_args *uap, register_t *retval) 653 { 654 /* { 655 syscallarg(int) fd; 656 syscallarg(const netbsd32_iovecp_t) iovp; 657 syscallarg(int) iovcnt; 658 syscallarg(int) pad; 659 syscallarg(off_t) offset; 660 } */ 661 file_t *fp; 662 struct vnode *vp; 663 off_t offset; 664 int error, fd = SCARG(uap, fd); 665 666 if ((fp = fd_getfile(fd)) == NULL) 667 return (EBADF); 668 669 if ((fp->f_flag & FWRITE) == 0) { 670 fd_putfile(fd); 671 return (EBADF); 672 } 673 674 vp = fp->f_data; 675 if (fp->f_type != DTYPE_VNODE || vp->v_type == VFIFO) { 676 error = ESPIPE; 677 goto out; 678 } 679 680 offset = SCARG(uap, offset); 681 682 /* 683 * XXX This works because no file systems actually 684 * XXX take any action on the seek operation. 685 */ 686 if ((error = VOP_SEEK(vp, fp->f_offset, offset, fp->f_cred)) != 0) 687 goto out; 688 689 return (dofilewritev32(fd, fp, SCARG_P32(uap, iovp), 690 SCARG(uap, iovcnt), &offset, 0, retval)); 691 692 out: 693 fd_putfile(fd); 694 return (error); 695 } 696 697 /* 698 * Find pathname of process's current directory. 699 * 700 * Use vfs vnode-to-name reverse cache; if that fails, fall back 701 * to reading directory contents. 702 */ 703 /* XXX NH Why does this exist */ 704 int 705 getcwd_common(struct vnode *, struct vnode *, 706 char **, char *, int, int, struct lwp *); 707 708 int 709 netbsd32___getcwd(struct lwp *l, const struct netbsd32___getcwd_args *uap, register_t *retval) 710 { 711 /* { 712 syscallarg(char *) bufp; 713 syscallarg(size_t) length; 714 } */ 715 struct proc *p = l->l_proc; 716 int error; 717 char *path; 718 char *bp, *bend; 719 int len = (int)SCARG(uap, length); 720 int lenused; 721 struct cwdinfo *cwdi; 722 723 if (len > MAXPATHLEN*4) 724 len = MAXPATHLEN*4; 725 else if (len < 2) 726 return ERANGE; 727 728 path = (char *)malloc(len, M_TEMP, M_WAITOK); 729 if (!path) 730 return ENOMEM; 731 732 bp = &path[len]; 733 bend = bp; 734 *(--bp) = '\0'; 735 736 /* 737 * 5th argument here is "max number of vnodes to traverse". 738 * Since each entry takes up at least 2 bytes in the output buffer, 739 * limit it to N/2 vnodes for an N byte buffer. 740 */ 741 #define GETCWD_CHECK_ACCESS 0x0001 742 cwdi = p->p_cwdi; 743 rw_enter(&cwdi->cwdi_lock, RW_READER); 744 error = getcwd_common (cwdi->cwdi_cdir, NULL, &bp, path, len/2, 745 GETCWD_CHECK_ACCESS, l); 746 rw_exit(&cwdi->cwdi_lock); 747 748 if (error) 749 goto out; 750 lenused = bend - bp; 751 *retval = lenused; 752 /* put the result into user buffer */ 753 error = copyout(bp, SCARG_P32(uap, bufp), lenused); 754 755 out: 756 free(path, M_TEMP); 757 return error; 758 } 759