|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1995, 1997 Apple Computer, Inc. All Rights Reserved */ ! 23: /* ! 24: * Copyright (c) 1982, 1986, 1989, 1991, 1993 ! 25: * The Regents of the University of California. All rights reserved. ! 26: * (c) UNIX System Laboratories, Inc. ! 27: * All or some portions of this file are derived from material licensed ! 28: * to the University of California by American Telephone and Telegraph ! 29: * Co. or Unix System Laboratories, Inc. and are reproduced herein with ! 30: * the permission of UNIX System Laboratories, Inc. ! 31: * ! 32: * Redistribution and use in source and binary forms, with or without ! 33: * modification, are permitted provided that the following conditions ! 34: * are met: ! 35: * 1. Redistributions of source code must retain the above copyright ! 36: * notice, this list of conditions and the following disclaimer. ! 37: * 2. Redistributions in binary form must reproduce the above copyright ! 38: * notice, this list of conditions and the following disclaimer in the ! 39: * documentation and/or other materials provided with the distribution. ! 40: * 3. All advertising materials mentioning features or use of this software ! 41: * must display the following acknowledgement: ! 42: * This product includes software developed by the University of ! 43: * California, Berkeley and its contributors. ! 44: * 4. Neither the name of the University nor the names of its contributors ! 45: * may be used to endorse or promote products derived from this software ! 46: * without specific prior written permission. ! 47: * ! 48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 58: * SUCH DAMAGE. ! 59: * ! 60: * @(#)kern_descrip.c 8.8 (Berkeley) 2/14/95 ! 61: * ! 62: * History: ! 63: * CHW 8/5/98 Added F_SETSIZE command to truncate without ! 64: * zero filling space ! 65: * CHW 7/6/98 Updated Preallocate command to take a structure ! 66: * and return output. ! 67: * CHW 6/25/98 Fixed a bug in the lock call in fcntl ! 68: * Preallocate command ! 69: */ ! 70: ! 71: #include <sys/param.h> ! 72: #include <sys/systm.h> ! 73: #include <sys/filedesc.h> ! 74: #include <sys/kernel.h> ! 75: #include <sys/vnode.h> ! 76: #include <sys/proc.h> ! 77: #include <sys/file.h> ! 78: #include <sys/socket.h> ! 79: #include <sys/socketvar.h> ! 80: #include <sys/stat.h> ! 81: #include <sys/ioctl.h> ! 82: #include <sys/fcntl.h> ! 83: #include <sys/malloc.h> ! 84: #include <sys/syslog.h> ! 85: #include <sys/unistd.h> ! 86: #include <sys/resourcevar.h> ! 87: ! 88: #include <sys/mount.h> ! 89: ! 90: /* ! 91: * Descriptor management. ! 92: */ ! 93: struct filelist filehead; /* head of list of open files */ ! 94: int nfiles; /* actual number of open files */ ! 95: ! 96: /* ! 97: * System calls on descriptors. ! 98: */ ! 99: /* ARGSUSED */ ! 100: int ! 101: getdtablesize(p, uap, retval) ! 102: struct proc *p; ! 103: void *uap; ! 104: register_t *retval; ! 105: { ! 106: ! 107: *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); ! 108: return (0); ! 109: } ! 110: ! 111: /* ARGSUSED */ ! 112: int ! 113: ogetdtablesize(p, uap, retval) ! 114: struct proc *p; ! 115: void *uap; ! 116: register_t *retval; ! 117: { ! 118: ! 119: *retval = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, NOFILE); ! 120: return (0); ! 121: } ! 122: ! 123: static __inline__ ! 124: void _fdrelse(fdp, fd) ! 125: register struct filedesc *fdp; ! 126: register int fd; ! 127: { ! 128: if (fd < fdp->fd_freefile) ! 129: fdp->fd_freefile = fd; ! 130: #if DIAGNOSTIC ! 131: if (fd > fdp->fd_lastfile) ! 132: panic("fdrelse: fd_lastfile inconsistent"); ! 133: #endif ! 134: fdp->fd_ofiles[fd] = NULL; ! 135: fdp->fd_ofileflags[fd] = 0; ! 136: while ((fd = fdp->fd_lastfile) > 0 && ! 137: fdp->fd_ofiles[fd] == NULL && ! 138: !(fdp->fd_ofileflags[fd] & UF_RESERVED)) ! 139: fdp->fd_lastfile--; ! 140: } ! 141: ! 142: /* ! 143: * Duplicate a file descriptor. ! 144: */ ! 145: struct dup_args { ! 146: u_int fd; ! 147: }; ! 148: /* ARGSUSED */ ! 149: int ! 150: dup(p, uap, retval) ! 151: struct proc *p; ! 152: struct dup_args *uap; ! 153: register_t *retval; ! 154: { ! 155: register struct filedesc *fdp = p->p_fd; ! 156: register int old = uap->fd; ! 157: int new, error; ! 158: ! 159: if ((u_int)old >= fdp->fd_nfiles || ! 160: fdp->fd_ofiles[old] == NULL || ! 161: (fdp->fd_ofileflags[old] & UF_RESERVED)) ! 162: return (EBADF); ! 163: if (error = fdalloc(p, 0, &new)) ! 164: return (error); ! 165: return (finishdup(fdp, old, new, retval)); ! 166: } ! 167: ! 168: /* ! 169: * Duplicate a file descriptor to a particular value. ! 170: */ ! 171: struct dup2_args { ! 172: u_int from; ! 173: u_int to; ! 174: }; ! 175: /* ARGSUSED */ ! 176: int ! 177: dup2(p, uap, retval) ! 178: struct proc *p; ! 179: struct dup2_args *uap; ! 180: register_t *retval; ! 181: { ! 182: register struct filedesc *fdp = p->p_fd; ! 183: register int old = uap->from, new = uap->to; ! 184: int i, error; ! 185: ! 186: if ((u_int)old >= fdp->fd_nfiles || ! 187: fdp->fd_ofiles[old] == NULL || ! 188: (fdp->fd_ofileflags[old] & UF_RESERVED) || ! 189: (u_int)new >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || ! 190: (u_int)new >= maxfiles) ! 191: return (EBADF); ! 192: if (old == new) { ! 193: *retval = new; ! 194: return (0); ! 195: } ! 196: if ((u_int)new >= fdp->fd_nfiles) { ! 197: if (error = fdalloc(p, new, &i)) ! 198: return (error); ! 199: if (new != i) { ! 200: _fdrelse(fdp, i); ! 201: goto closeit; ! 202: } ! 203: } ! 204: else { ! 205: struct file **fpp; ! 206: char flags; ! 207: closeit: ! 208: if ((flags = fdp->fd_ofileflags[new]) & UF_RESERVED) ! 209: return (EBADF); ! 210: fdp->fd_ofileflags[new] = (flags & ~UF_MAPPED) | UF_RESERVED; ! 211: /* ! 212: * dup2() must succeed even if the close has an error. ! 213: */ ! 214: if (*(fpp = &fdp->fd_ofiles[new])) { ! 215: struct file *fp = *fpp; ! 216: ! 217: *fpp = NULL; (void) closef(fp, p); ! 218: } ! 219: } ! 220: return (finishdup(fdp, old, new, retval)); ! 221: } ! 222: ! 223: /* ! 224: * The file control system call. ! 225: */ ! 226: struct fcntl_args { ! 227: int fd; ! 228: int cmd; ! 229: int arg; ! 230: }; ! 231: /* ARGSUSED */ ! 232: int ! 233: fcntl(p, uap, retval) ! 234: struct proc *p; ! 235: register struct fcntl_args *uap; ! 236: register_t *retval; ! 237: { ! 238: int fd = uap->fd; ! 239: register struct filedesc *fdp = p->p_fd; ! 240: register struct file *fp; ! 241: register char *pop; ! 242: struct vnode *vp; ! 243: int i, tmp, error, error2, flg = F_POSIX; ! 244: struct flock fl; ! 245: fstore_t alloc_struct; /* structure for allocate command */ ! 246: u_int32_t alloc_flags = 0; ! 247: off_t offset; /* used for F_SETSIZE */ ! 248: int newmin; ! 249: struct radvisory ra_struct; ! 250: fbootstraptransfer_t fbt_struct; /* for F_READBOOTSTRAP and F_WRITEBOOTSTRAP */ ! 251: ! 252: if ((u_int)fd >= fdp->fd_nfiles || ! 253: (fp = fdp->fd_ofiles[fd]) == NULL || ! 254: (fdp->fd_ofileflags[fd] & UF_RESERVED)) ! 255: return (EBADF); ! 256: pop = &fdp->fd_ofileflags[fd]; ! 257: switch (uap->cmd) { ! 258: ! 259: case F_DUPFD: ! 260: newmin = (long)uap->arg; ! 261: if ((u_int)newmin >= p->p_rlimit[RLIMIT_NOFILE].rlim_cur || ! 262: (u_int)newmin >= maxfiles) ! 263: return (EINVAL); ! 264: if (error = fdalloc(p, newmin, &i)) ! 265: return (error); ! 266: return (finishdup(fdp, fd, i, retval)); ! 267: ! 268: case F_GETFD: ! 269: *retval = (*pop & UF_EXCLOSE)? 1 : 0; ! 270: return (0); ! 271: ! 272: case F_SETFD: ! 273: *pop = (*pop &~ UF_EXCLOSE) | ! 274: ((long)(uap->arg) & 1)? UF_EXCLOSE : 0; ! 275: return (0); ! 276: ! 277: case F_GETFL: ! 278: *retval = OFLAGS(fp->f_flag); ! 279: return (0); ! 280: ! 281: case F_SETFL: ! 282: fp->f_flag &= ~FCNTLFLAGS; ! 283: fp->f_flag |= FFLAGS((long)uap->arg) & FCNTLFLAGS; ! 284: tmp = fp->f_flag & FNONBLOCK; ! 285: error = (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); ! 286: if (error) ! 287: return (error); ! 288: tmp = fp->f_flag & FASYNC; ! 289: error = (*fp->f_ops->fo_ioctl)(fp, FIOASYNC, (caddr_t)&tmp, p); ! 290: if (!error) ! 291: return (0); ! 292: fp->f_flag &= ~FNONBLOCK; ! 293: tmp = 0; ! 294: (void) (*fp->f_ops->fo_ioctl)(fp, FIONBIO, (caddr_t)&tmp, p); ! 295: return (error); ! 296: ! 297: case F_GETOWN: ! 298: if (fp->f_type == DTYPE_SOCKET) { ! 299: *retval = ((struct socket *)fp->f_data)->so_pgid; ! 300: return (0); ! 301: } ! 302: error = (*fp->f_ops->fo_ioctl) ! 303: (fp, (int)TIOCGPGRP, (caddr_t)retval, p); ! 304: *retval = -*retval; ! 305: return (error); ! 306: ! 307: case F_SETOWN: ! 308: if (fp->f_type == DTYPE_SOCKET) { ! 309: ((struct socket *)fp->f_data)->so_pgid = ! 310: (long)uap->arg; ! 311: return (0); ! 312: } ! 313: if ((long)uap->arg <= 0) { ! 314: uap->arg = (void *)(-(long)(uap->arg)); ! 315: } else { ! 316: struct proc *p1 = pfind((long)uap->arg); ! 317: if (p1 == 0) ! 318: return (ESRCH); ! 319: uap->arg = (void *)(long)p1->p_pgrp->pg_id; ! 320: } ! 321: return ((*fp->f_ops->fo_ioctl) ! 322: (fp, (int)TIOCSPGRP, (caddr_t)&uap->arg, p)); ! 323: ! 324: case F_SETLKW: ! 325: flg |= F_WAIT; ! 326: /* Fall into F_SETLK */ ! 327: ! 328: case F_SETLK: ! 329: if (fp->f_type != DTYPE_VNODE) ! 330: return (EBADF); ! 331: vp = (struct vnode *)fp->f_data; ! 332: /* Copy in the lock structure */ ! 333: error = copyin((caddr_t)uap->arg, (caddr_t)&fl, ! 334: sizeof (fl)); ! 335: if (error) ! 336: return (error); ! 337: if (fl.l_whence == SEEK_CUR) ! 338: fl.l_start += fp->f_offset; ! 339: switch (fl.l_type) { ! 340: ! 341: case F_RDLCK: ! 342: if ((fp->f_flag & FREAD) == 0) ! 343: return (EBADF); ! 344: p->p_flag |= P_ADVLOCK; ! 345: return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); ! 346: ! 347: case F_WRLCK: ! 348: if ((fp->f_flag & FWRITE) == 0) ! 349: return (EBADF); ! 350: p->p_flag |= P_ADVLOCK; ! 351: return (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &fl, flg)); ! 352: ! 353: case F_UNLCK: ! 354: return (VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &fl, ! 355: F_POSIX)); ! 356: ! 357: default: ! 358: return (EINVAL); ! 359: } ! 360: ! 361: case F_GETLK: ! 362: if (fp->f_type != DTYPE_VNODE) ! 363: return (EBADF); ! 364: vp = (struct vnode *)fp->f_data; ! 365: /* Copy in the lock structure */ ! 366: error = copyin((caddr_t)uap->arg, (caddr_t)&fl, ! 367: sizeof (fl)); ! 368: if (error) ! 369: return (error); ! 370: if (fl.l_whence == SEEK_CUR) ! 371: fl.l_start += fp->f_offset; ! 372: if (error = VOP_ADVLOCK(vp, (caddr_t)p, F_GETLK, &fl, F_POSIX)) ! 373: return (error); ! 374: return (copyout((caddr_t)&fl, (caddr_t)uap->arg, ! 375: sizeof (fl))); ! 376: ! 377: case F_PREALLOCATE: ! 378: ! 379: /* Copy in the structure */ ! 380: ! 381: error = copyin((caddr_t)uap->arg, (caddr_t)&alloc_struct, ! 382: sizeof (alloc_struct)); ! 383: ! 384: if (error) ! 385: return (error); ! 386: ! 387: /* now set the space allocated to 0 and pass it out in ! 388: case we get a parameter checking error */ ! 389: ! 390: alloc_struct.fst_bytesalloc = 0; ! 391: ! 392: error = copyout((caddr_t)&alloc_struct, (caddr_t)uap->arg, ! 393: sizeof (alloc_struct)); ! 394: ! 395: if (error) ! 396: return(error); ! 397: ! 398: /* First make sure that we have write permission */ ! 399: ! 400: if ((fp->f_flag & FWRITE) == 0) ! 401: return (EBADF); ! 402: ! 403: ! 404: /* Do some simple parameter checking */ ! 405: ! 406: ! 407: /* set up the flags */ ! 408: ! 409: alloc_flags |= PREALLOCATE; ! 410: ! 411: if (alloc_struct.fst_flags & F_ALLOCATECONTIG) { ! 412: alloc_flags |= ALLOCATECONTIG; ! 413: } ! 414: ! 415: if (alloc_struct.fst_flags & F_ALLOCATEALL) { ! 416: alloc_flags |= ALLOCATEALL; ! 417: } ! 418: ! 419: /* Do any position mode specific stuff. The only */ ! 420: /* position mode supported now is PEOFPOSMODE */ ! 421: ! 422: switch (alloc_struct.fst_posmode) { ! 423: ! 424: case F_PEOFPOSMODE: ! 425: ! 426: if ((alloc_struct.fst_offset != 0) || ! 427: (alloc_struct.fst_length < 0)) ! 428: return (EINVAL); ! 429: ! 430: alloc_flags |= ALLOCATEFROMPEOF; ! 431: break; ! 432: ! 433: default: ! 434: ! 435: return(EINVAL); ! 436: ! 437: } ! 438: ! 439: ! 440: /* Now lock the vnode and call allocate to get the space */ ! 441: ! 442: vp = (struct vnode *)fp->f_data; ! 443: ! 444: VOP_LOCK(vp,LK_EXCLUSIVE,p); ! 445: error = VOP_ALLOCATE(vp,alloc_struct.fst_length,alloc_flags, ! 446: &alloc_struct.fst_bytesalloc,fp->f_cred,p); ! 447: VOP_UNLOCK(vp,0,p); ! 448: ! 449: if (error2 = (copyout((caddr_t)&alloc_struct, (caddr_t)uap->arg, ! 450: sizeof (alloc_struct)))) { ! 451: if (error) { ! 452: return(error); ! 453: } else { ! 454: return(error2); ! 455: } ! 456: } ! 457: ! 458: return(error); ! 459: ! 460: case F_SETSIZE: ! 461: ! 462: /* Copy in the structure */ ! 463: ! 464: error = copyin((caddr_t)uap->arg, (caddr_t)&offset, ! 465: sizeof (off_t)); ! 466: ! 467: if (error) ! 468: return (error); ! 469: ! 470: ! 471: /* First make sure that we are root. Growing a file */ ! 472: /* without zero filling the data is a security hole */ ! 473: /* root would have access anyway so we'll allow it */ ! 474: ! 475: if (!is_suser()) { ! 476: return (EACCES); ! 477: } ! 478: ! 479: /* Now lock the vnode and call allocate to get the space */ ! 480: ! 481: vp = (struct vnode *)fp->f_data; ! 482: ! 483: VOP_LOCK(vp,LK_EXCLUSIVE,p); ! 484: error = VOP_TRUNCATE(vp,offset,IO_NOZEROFILL,fp->f_cred,p); ! 485: VOP_UNLOCK(vp,0,p); ! 486: ! 487: return(error); ! 488: ! 489: case F_RDAHEAD: ! 490: vp = (struct vnode *)fp->f_data; ! 491: ! 492: simple_lock(&vp->v_interlock); ! 493: if (uap->arg) ! 494: vp->v_flag &= ~VRAOFF; ! 495: else ! 496: vp->v_flag |= VRAOFF; ! 497: simple_unlock(&vp->v_interlock); ! 498: ! 499: return (0); ! 500: ! 501: case F_RDADVISE: ! 502: vp = (struct vnode *)fp->f_data; ! 503: ! 504: if (error = copyin((caddr_t)uap->arg, (caddr_t)&ra_struct, sizeof (ra_struct))) ! 505: return(error); ! 506: return (VOP_IOCTL(vp, 1, &ra_struct, 0, fp->f_cred, p)); ! 507: ! 508: case F_READBOOTSTRAP: ! 509: case F_WRITEBOOTSTRAP: ! 510: ! 511: /* Copy in the structure */ ! 512: ! 513: error = copyin((caddr_t)uap->arg, (caddr_t)&fbt_struct, ! 514: sizeof (fbt_struct)); ! 515: ! 516: if (error) ! 517: return (error); ! 518: ! 519: ! 520: if (uap->cmd == F_WRITEBOOTSTRAP) { ! 521: /* First make sure that we are root. Updating the */ ! 522: /* bootstrap on a disk could be a security hole */ ! 523: ! 524: if (!is_suser()) { ! 525: return (EACCES); ! 526: } ! 527: }; ! 528: ! 529: /* Now lock the vnode and call VOP_IOCTL to handle the I/O: */ ! 530: ! 531: vp = (struct vnode *)fp->f_data; ! 532: if (vp->v_tag != VT_HFS) { ! 533: error = EINVAL; ! 534: } else { ! 535: VOP_LOCK(vp,LK_EXCLUSIVE,p); ! 536: error = VOP_IOCTL(vp, (uap->cmd == F_WRITEBOOTSTRAP) ? 3 : 2, &fbt_struct, 0, fp->f_cred, p); ! 537: VOP_UNLOCK(vp,0,p); ! 538: }; ! 539: ! 540: return(error); ! 541: ! 542: ! 543: default: ! 544: return (EINVAL); ! 545: } ! 546: /* NOTREACHED */ ! 547: } ! 548: ! 549: /* ! 550: * Common code for dup, dup2, and fcntl(F_DUPFD). ! 551: */ ! 552: int ! 553: finishdup(fdp, old, new, retval) ! 554: register struct filedesc *fdp; ! 555: register int old, new; ! 556: register_t *retval; ! 557: { ! 558: register struct file *fp; ! 559: ! 560: if ((fp = fdp->fd_ofiles[old]) == NULL || ! 561: (fdp->fd_ofileflags[old] & UF_RESERVED)) { ! 562: _fdrelse(fdp, new); ! 563: return (EBADF); ! 564: } ! 565: fdp->fd_ofiles[new] = fp; ! 566: fdp->fd_ofileflags[new] = fdp->fd_ofileflags[old] &~ UF_EXCLOSE; ! 567: if (++fp->f_count <= 0) ! 568: panic("finishdup f_count"); ! 569: if (new > fdp->fd_lastfile) ! 570: fdp->fd_lastfile = new; ! 571: *retval = new; ! 572: return (0); ! 573: } ! 574: ! 575: /* ! 576: * Close a file descriptor. ! 577: */ ! 578: struct close_args { ! 579: int fd; ! 580: }; ! 581: /* ARGSUSED */ ! 582: int ! 583: close(p, uap, retval) ! 584: struct proc *p; ! 585: struct close_args *uap; ! 586: register_t *retval; ! 587: { ! 588: int fd = uap->fd; ! 589: register struct filedesc *fdp = p->p_fd; ! 590: register struct file *fp; ! 591: ! 592: if ((u_int)fd >= fdp->fd_nfiles || ! 593: (fp = fdp->fd_ofiles[fd]) == NULL || ! 594: (fdp->fd_ofileflags[fd] & UF_RESERVED)) ! 595: return (EBADF); ! 596: _fdrelse(fdp, fd); ! 597: return (closef(fp, p)); ! 598: } ! 599: ! 600: /* ! 601: * Return status information about a file descriptor. ! 602: */ ! 603: struct fstat_args { ! 604: int fd; ! 605: struct stat *sb; ! 606: }; ! 607: /* ARGSUSED */ ! 608: int ! 609: fstat(p, uap, retval) ! 610: struct proc *p; ! 611: register struct fstat_args *uap; ! 612: register_t *retval; ! 613: { ! 614: int fd = uap->fd; ! 615: register struct filedesc *fdp = p->p_fd; ! 616: register struct file *fp; ! 617: struct stat ub; ! 618: int error; ! 619: ! 620: if ((u_int)fd >= fdp->fd_nfiles || ! 621: (fp = fdp->fd_ofiles[fd]) == NULL || ! 622: (fdp->fd_ofileflags[fd] & UF_RESERVED)) ! 623: return (EBADF); ! 624: switch (fp->f_type) { ! 625: ! 626: case DTYPE_VNODE: ! 627: error = vn_stat((struct vnode *)fp->f_data, &ub, p); ! 628: break; ! 629: ! 630: case DTYPE_SOCKET: ! 631: error = soo_stat((struct socket *)fp->f_data, &ub); ! 632: break; ! 633: ! 634: case DTYPE_PSXSHM: ! 635: error = pshm_stat((void *)fp->f_data, &ub); ! 636: break; ! 637: default: ! 638: panic("fstat"); ! 639: /*NOTREACHED*/ ! 640: } ! 641: if (error == 0) ! 642: error = copyout((caddr_t)&ub, (caddr_t)uap->sb, ! 643: sizeof (ub)); ! 644: return (error); ! 645: } ! 646: ! 647: #if COMPAT_43 ! 648: /* ! 649: * Return status information about a file descriptor. ! 650: */ ! 651: struct ofstat_args { ! 652: int fd; ! 653: struct ostat *sb; ! 654: }; ! 655: /* ARGSUSED */ ! 656: ofstat(p, uap, retval) ! 657: struct proc *p; ! 658: register struct ofstat_args *uap; ! 659: register_t *retval; ! 660: { ! 661: int fd = uap->fd; ! 662: register struct filedesc *fdp = p->p_fd; ! 663: register struct file *fp; ! 664: struct stat ub; ! 665: struct ostat oub; ! 666: int error; ! 667: ! 668: if ((u_int)fd >= fdp->fd_nfiles || ! 669: (fp = fdp->fd_ofiles[fd]) == NULL || ! 670: (fdp->fd_ofileflags[fd] & UF_RESERVED)) ! 671: return (EBADF); ! 672: switch (fp->f_type) { ! 673: ! 674: case DTYPE_VNODE: ! 675: error = vn_stat((struct vnode *)fp->f_data, &ub, p); ! 676: break; ! 677: ! 678: case DTYPE_SOCKET: ! 679: error = soo_stat((struct socket *)fp->f_data, &ub); ! 680: break; ! 681: ! 682: default: ! 683: panic("ofstat"); ! 684: /*NOTREACHED*/ ! 685: } ! 686: cvtstat(&ub, &oub); ! 687: if (error == 0) ! 688: error = copyout((caddr_t)&oub, (caddr_t)uap->sb, ! 689: sizeof (oub)); ! 690: return (error); ! 691: } ! 692: #endif /* COMPAT_43 */ ! 693: ! 694: /* ! 695: * Return pathconf information about a file descriptor. ! 696: */ ! 697: struct fpathconf_args { ! 698: int fd; ! 699: int name; ! 700: }; ! 701: /* ARGSUSED */ ! 702: fpathconf(p, uap, retval) ! 703: struct proc *p; ! 704: register struct fpathconf_args *uap; ! 705: register_t *retval; ! 706: { ! 707: int fd = uap->fd; ! 708: struct filedesc *fdp = p->p_fd; ! 709: struct file *fp; ! 710: struct vnode *vp; ! 711: ! 712: if ((u_int)fd >= fdp->fd_nfiles || ! 713: (fp = fdp->fd_ofiles[fd]) == NULL || ! 714: (fdp->fd_ofileflags[fd] & UF_RESERVED)) ! 715: return (EBADF); ! 716: switch (fp->f_type) { ! 717: ! 718: case DTYPE_SOCKET: ! 719: if (uap->name != _PC_PIPE_BUF) ! 720: return (EINVAL); ! 721: *retval = PIPE_BUF; ! 722: return (0); ! 723: ! 724: case DTYPE_VNODE: ! 725: vp = (struct vnode *)fp->f_data; ! 726: return (VOP_PATHCONF(vp, uap->name, retval)); ! 727: ! 728: default: ! 729: panic("fpathconf"); ! 730: } ! 731: /*NOTREACHED*/ ! 732: } ! 733: ! 734: /* ! 735: * Allocate a file descriptor for the process. ! 736: */ ! 737: int fdexpand; ! 738: ! 739: int ! 740: fdalloc(p, want, result) ! 741: struct proc *p; ! 742: int want; ! 743: int *result; ! 744: { ! 745: register struct filedesc *fdp = p->p_fd; ! 746: register int i; ! 747: int lim, last, nfiles, oldnfiles; ! 748: struct file **newofiles, **ofiles; ! 749: char *newofileflags, *ofileflags; ! 750: ! 751: /* ! 752: * Search for a free descriptor starting at the higher ! 753: * of want or fd_freefile. If that fails, consider ! 754: * expanding the ofile array. ! 755: */ ! 756: lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); ! 757: for (;;) { ! 758: last = min(fdp->fd_nfiles, lim); ! 759: if ((i = want) < fdp->fd_freefile) ! 760: i = fdp->fd_freefile; ! 761: ofiles = &fdp->fd_ofiles[i]; ! 762: ofileflags = &fdp->fd_ofileflags[i]; ! 763: for (; i < last; i++) { ! 764: if (*ofiles == NULL && !(*ofileflags & UF_RESERVED)) { ! 765: *ofileflags = UF_RESERVED; ! 766: if (i > fdp->fd_lastfile) ! 767: fdp->fd_lastfile = i; ! 768: if (want <= fdp->fd_freefile) ! 769: fdp->fd_freefile = i; ! 770: *result = i; ! 771: return (0); ! 772: } ! 773: ofiles++; ofileflags++; ! 774: } ! 775: ! 776: /* ! 777: * No space in current array. Expand? ! 778: */ ! 779: if (fdp->fd_nfiles >= lim) ! 780: return (EMFILE); ! 781: if (fdp->fd_nfiles < NDEXTENT) ! 782: nfiles = NDEXTENT; ! 783: else ! 784: nfiles = 2 * fdp->fd_nfiles; ! 785: /* Enforce lim */ ! 786: if (nfiles > lim) ! 787: nfiles = lim; ! 788: MALLOC_ZONE(newofiles, struct file **, ! 789: nfiles * OFILESIZE, M_OFILETABL, M_WAITOK); ! 790: if (fdp->fd_nfiles >= nfiles) { ! 791: FREE_ZONE(newofiles, nfiles * OFILESIZE, M_OFILETABL); ! 792: continue; ! 793: } ! 794: newofileflags = (char *) &newofiles[nfiles]; ! 795: /* ! 796: * Copy the existing ofile and ofileflags arrays ! 797: * and zero the new portion of each array. ! 798: */ ! 799: oldnfiles = fdp->fd_nfiles; ! 800: (void) memcpy(newofiles, fdp->fd_ofiles, ! 801: oldnfiles * sizeof *fdp->fd_ofiles); ! 802: (void) memset(&newofiles[oldnfiles], 0, ! 803: (nfiles - oldnfiles) * sizeof *fdp->fd_ofiles); ! 804: ! 805: (void) memcpy(newofileflags, fdp->fd_ofileflags, ! 806: oldnfiles * sizeof *fdp->fd_ofileflags); ! 807: (void) memset(&newofileflags[oldnfiles], 0, ! 808: (nfiles - oldnfiles) * ! 809: sizeof *fdp->fd_ofileflags); ! 810: ofiles = fdp->fd_ofiles; ! 811: fdp->fd_ofiles = newofiles; ! 812: fdp->fd_ofileflags = newofileflags; ! 813: fdp->fd_nfiles = nfiles; ! 814: FREE_ZONE(ofiles, oldnfiles * OFILESIZE, M_OFILETABL); ! 815: fdexpand++; ! 816: } ! 817: } ! 818: ! 819: /* ! 820: * Check to see whether n user file descriptors ! 821: * are available to the process p. ! 822: */ ! 823: int ! 824: fdavail(p, n) ! 825: struct proc *p; ! 826: register int n; ! 827: { ! 828: register struct filedesc *fdp = p->p_fd; ! 829: register struct file **fpp; ! 830: register char *flags; ! 831: register int i, lim; ! 832: ! 833: lim = min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles); ! 834: if ((i = lim - fdp->fd_nfiles) > 0 && (n -= i) <= 0) ! 835: return (1); ! 836: fpp = &fdp->fd_ofiles[fdp->fd_freefile]; ! 837: flags = &fdp->fd_ofileflags[fdp->fd_freefile]; ! 838: for (i = fdp->fd_nfiles - fdp->fd_freefile; --i >= 0; fpp++, flags++) ! 839: if (*fpp == NULL && !(*flags & UF_RESERVED) && --n <= 0) ! 840: return (1); ! 841: return (0); ! 842: } ! 843: ! 844: void ! 845: fdrelse(p, fd) ! 846: struct proc *p; ! 847: int fd; ! 848: { ! 849: _fdrelse(p->p_fd, fd); ! 850: } ! 851: ! 852: int ! 853: fdgetf(p, fd, resultfp) ! 854: register struct proc *p; ! 855: register int fd; ! 856: struct file **resultfp; ! 857: { ! 858: register struct filedesc *fdp = p->p_fd; ! 859: struct file *fp; ! 860: ! 861: if ((u_int)fd >= fdp->fd_nfiles || ! 862: (fp = fdp->fd_ofiles[fd]) == NULL || ! 863: (fdp->fd_ofileflags[fd] & UF_RESERVED)) ! 864: return (EBADF); ! 865: ! 866: if (resultfp) ! 867: *resultfp = fp; ! 868: return (0); ! 869: } ! 870: ! 871: /* ! 872: * Create a new open file structure and allocate ! 873: * a file decriptor for the process that refers to it. ! 874: */ ! 875: int ! 876: falloc(p, resultfp, resultfd) ! 877: register struct proc *p; ! 878: struct file **resultfp; ! 879: int *resultfd; ! 880: { ! 881: register struct file *fp, *fq; ! 882: int error, i; ! 883: ! 884: if (error = fdalloc(p, 0, &i)) ! 885: return (error); ! 886: if (nfiles >= maxfiles) { ! 887: tablefull("file"); ! 888: return (ENFILE); ! 889: } ! 890: /* ! 891: * Allocate a new file descriptor. ! 892: * If the process has file descriptor zero open, add to the list ! 893: * of open files at that point, otherwise put it at the front of ! 894: * the list of open files. ! 895: */ ! 896: nfiles++; ! 897: MALLOC_ZONE(fp, struct file *, sizeof(struct file), M_FILE, M_WAITOK); ! 898: bzero(fp, sizeof(struct file)); ! 899: if (fq = p->p_fd->fd_ofiles[0]) { ! 900: LIST_INSERT_AFTER(fq, fp, f_list); ! 901: } else { ! 902: LIST_INSERT_HEAD(&filehead, fp, f_list); ! 903: } ! 904: p->p_fd->fd_ofiles[i] = fp; ! 905: fp->f_count = 1; ! 906: fp->f_cred = p->p_ucred; ! 907: crhold(fp->f_cred); ! 908: if (resultfp) ! 909: *resultfp = fp; ! 910: if (resultfd) ! 911: *resultfd = i; ! 912: return (0); ! 913: } ! 914: ! 915: /* ! 916: * Free a file structure. ! 917: */ ! 918: void ! 919: ffree(fp) ! 920: register struct file *fp; ! 921: { ! 922: register struct file *fq; ! 923: struct ucred *cred; ! 924: ! 925: LIST_REMOVE(fp, f_list); ! 926: cred = fp->f_cred; ! 927: if (cred != NOCRED) { ! 928: fp->f_cred = NOCRED; ! 929: crfree(cred); ! 930: } ! 931: #if DIAGNOSTIC ! 932: fp->f_count = 0; ! 933: #endif ! 934: nfiles--; ! 935: FREE_ZONE(fp, sizeof *fp, M_FILE); ! 936: } ! 937: ! 938: void ! 939: fdexec(p) ! 940: struct proc *p; ! 941: { ! 942: register struct filedesc *fdp = p->p_fd; ! 943: register int i = fdp->fd_lastfile; ! 944: register struct file **fpp = &fdp->fd_ofiles[i]; ! 945: register char *flags = &fdp->fd_ofileflags[i]; ! 946: ! 947: while (i >= 0) { ! 948: if ((*flags & (UF_RESERVED|UF_EXCLOSE)) == UF_EXCLOSE) { ! 949: register struct file *fp = *fpp; ! 950: ! 951: *fpp = NULL; *flags = 0; ! 952: if (i == fdp->fd_lastfile && i > 0) ! 953: fdp->fd_lastfile--; ! 954: closef(fp, p); ! 955: } ! 956: else ! 957: *flags &= ~UF_MAPPED; ! 958: ! 959: i--; fpp--; flags--; ! 960: } ! 961: } ! 962: ! 963: /* ! 964: * Copy a filedesc structure. ! 965: */ ! 966: struct filedesc * ! 967: fdcopy(p) ! 968: struct proc *p; ! 969: { ! 970: register struct filedesc *newfdp, *fdp = p->p_fd; ! 971: register int i; ! 972: ! 973: MALLOC_ZONE(newfdp, struct filedesc *, ! 974: sizeof *newfdp, M_FILEDESC, M_WAITOK); ! 975: (void) memcpy(newfdp, fdp, sizeof *newfdp); ! 976: VREF(newfdp->fd_cdir); ! 977: if (newfdp->fd_rdir) ! 978: VREF(newfdp->fd_rdir); ! 979: newfdp->fd_refcnt = 1; ! 980: ! 981: /* ! 982: * If the number of open files fits in the internal arrays ! 983: * of the open file structure, use them, otherwise allocate ! 984: * additional memory for the number of descriptors currently ! 985: * in use. ! 986: */ ! 987: if (newfdp->fd_lastfile < NDFILE) ! 988: i = NDFILE; ! 989: else { ! 990: /* ! 991: * Compute the smallest multiple of NDEXTENT needed ! 992: * for the file descriptors currently in use, ! 993: * allowing the table to shrink. ! 994: */ ! 995: i = newfdp->fd_nfiles; ! 996: while (i > 2 * NDEXTENT && i > newfdp->fd_lastfile * 2) ! 997: i /= 2; ! 998: } ! 999: MALLOC_ZONE(newfdp->fd_ofiles, struct file **, ! 1000: i * OFILESIZE, M_OFILETABL, M_WAITOK); ! 1001: newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i]; ! 1002: newfdp->fd_nfiles = i; ! 1003: if (fdp->fd_nfiles > 0) { ! 1004: register struct file **fpp; ! 1005: register char *flags; ! 1006: ! 1007: (void) memcpy(newfdp->fd_ofiles, fdp->fd_ofiles, ! 1008: i * sizeof *fdp->fd_ofiles); ! 1009: (void) memcpy(newfdp->fd_ofileflags, fdp->fd_ofileflags, ! 1010: i * sizeof *fdp->fd_ofileflags); ! 1011: ! 1012: fpp = newfdp->fd_ofiles; ! 1013: flags = newfdp->fd_ofileflags; ! 1014: for (i = newfdp->fd_lastfile; i-- >= 0; fpp++, flags++) ! 1015: if (*fpp != NULL && !(*flags & UF_RESERVED)) { ! 1016: if (++(*fpp)->f_count <= 0) ! 1017: panic("fdcopy f_count"); ! 1018: } else { ! 1019: *fpp = NULL; *flags = 0; ! 1020: } ! 1021: } ! 1022: else ! 1023: (void) memset(newfdp->fd_ofiles, 0, i * OFILESIZE); ! 1024: ! 1025: return (newfdp); ! 1026: } ! 1027: ! 1028: /* ! 1029: * Release a filedesc structure. ! 1030: */ ! 1031: void ! 1032: fdfree(p) ! 1033: struct proc *p; ! 1034: { ! 1035: register struct filedesc *fdp; ! 1036: register struct file **fpp; ! 1037: register int i; ! 1038: ! 1039: if ((fdp = p->p_fd) == NULL) ! 1040: return; ! 1041: if (--fdp->fd_refcnt > 0) ! 1042: return; ! 1043: p->p_fd = NULL; ! 1044: if (fdp->fd_nfiles > 0) { ! 1045: fpp = fdp->fd_ofiles; ! 1046: for (i = fdp->fd_lastfile; i-- >= 0; fpp++) ! 1047: if (*fpp) ! 1048: (void) closef(*fpp, p); ! 1049: FREE_ZONE(fdp->fd_ofiles, ! 1050: fdp->fd_nfiles * OFILESIZE, M_OFILETABL); ! 1051: } ! 1052: vrele(fdp->fd_cdir); ! 1053: if (fdp->fd_rdir) ! 1054: vrele(fdp->fd_rdir); ! 1055: FREE_ZONE(fdp, sizeof *fdp, M_FILEDESC); ! 1056: } ! 1057: ! 1058: /* ! 1059: * Internal form of close. ! 1060: * Decrement reference count on file structure. ! 1061: * Note: p may be NULL when closing a file ! 1062: * that was being passed in a message. ! 1063: */ ! 1064: int ! 1065: closef(fp, p) ! 1066: register struct file *fp; ! 1067: register struct proc *p; ! 1068: { ! 1069: struct vnode *vp; ! 1070: struct flock lf; ! 1071: int error; ! 1072: ! 1073: if (fp == NULL) ! 1074: return (0); ! 1075: /* ! 1076: * POSIX record locking dictates that any close releases ALL ! 1077: * locks owned by this process. This is handled by setting ! 1078: * a flag in the unlock to free ONLY locks obeying POSIX ! 1079: * semantics, and not to free BSD-style file locks. ! 1080: * If the descriptor was in a message, POSIX-style locks ! 1081: * aren't passed with the descriptor. ! 1082: */ ! 1083: if (p && (p->p_flag & P_ADVLOCK) && fp->f_type == DTYPE_VNODE) { ! 1084: lf.l_whence = SEEK_SET; ! 1085: lf.l_start = 0; ! 1086: lf.l_len = 0; ! 1087: lf.l_type = F_UNLCK; ! 1088: vp = (struct vnode *)fp->f_data; ! 1089: (void) VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_POSIX); ! 1090: } ! 1091: if (--fp->f_count > 0) ! 1092: return (0); ! 1093: if (fp->f_count < 0) ! 1094: panic("closef: count < 0"); ! 1095: if ((fp->f_flag & FHASLOCK) && fp->f_type == DTYPE_VNODE) { ! 1096: lf.l_whence = SEEK_SET; ! 1097: lf.l_start = 0; ! 1098: lf.l_len = 0; ! 1099: lf.l_type = F_UNLCK; ! 1100: vp = (struct vnode *)fp->f_data; ! 1101: (void) VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK); ! 1102: } ! 1103: if (fp->f_ops) ! 1104: error = (*fp->f_ops->fo_close)(fp, p); ! 1105: else ! 1106: error = 0; ! 1107: ffree(fp); ! 1108: return (error); ! 1109: } ! 1110: ! 1111: /* ! 1112: * Apply an advisory lock on a file descriptor. ! 1113: * ! 1114: * Just attempt to get a record lock of the requested type on ! 1115: * the entire file (l_whence = SEEK_SET, l_start = 0, l_len = 0). ! 1116: */ ! 1117: struct flock_args { ! 1118: int fd; ! 1119: int how; ! 1120: }; ! 1121: /* ARGSUSED */ ! 1122: int ! 1123: flock(p, uap, retval) ! 1124: struct proc *p; ! 1125: register struct flock_args *uap; ! 1126: register_t *retval; ! 1127: { ! 1128: int fd = uap->fd; ! 1129: int how = uap->how; ! 1130: register struct filedesc *fdp = p->p_fd; ! 1131: register struct file *fp; ! 1132: struct vnode *vp; ! 1133: struct flock lf; ! 1134: ! 1135: if ((u_int)fd >= fdp->fd_nfiles || ! 1136: (fp = fdp->fd_ofiles[fd]) == NULL || ! 1137: (fdp->fd_ofileflags[fd] & UF_RESERVED)) ! 1138: return (EBADF); ! 1139: if (fp->f_type != DTYPE_VNODE) ! 1140: return (EOPNOTSUPP); ! 1141: vp = (struct vnode *)fp->f_data; ! 1142: lf.l_whence = SEEK_SET; ! 1143: lf.l_start = 0; ! 1144: lf.l_len = 0; ! 1145: if (how & LOCK_UN) { ! 1146: lf.l_type = F_UNLCK; ! 1147: fp->f_flag &= ~FHASLOCK; ! 1148: return (VOP_ADVLOCK(vp, (caddr_t)fp, F_UNLCK, &lf, F_FLOCK)); ! 1149: } ! 1150: if (how & LOCK_EX) ! 1151: lf.l_type = F_WRLCK; ! 1152: else if (how & LOCK_SH) ! 1153: lf.l_type = F_RDLCK; ! 1154: else ! 1155: return (EBADF); ! 1156: fp->f_flag |= FHASLOCK; ! 1157: if (how & LOCK_NB) ! 1158: return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK)); ! 1159: return (VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf, F_FLOCK|F_WAIT)); ! 1160: } ! 1161: ! 1162: /* ! 1163: * File Descriptor pseudo-device driver (/dev/fd/). ! 1164: * ! 1165: * Opening minor device N dup()s the file (if any) connected to file ! 1166: * descriptor N belonging to the calling process. Note that this driver ! 1167: * consists of only the ``open()'' routine, because all subsequent ! 1168: * references to this file will be direct to the other driver. ! 1169: */ ! 1170: /* ARGSUSED */ ! 1171: int ! 1172: fdopen(dev, mode, type, p) ! 1173: dev_t dev; ! 1174: int mode, type; ! 1175: struct proc *p; ! 1176: { ! 1177: ! 1178: /* ! 1179: * XXX Kludge: set curproc->p_dupfd to contain the value of the ! 1180: * the file descriptor being sought for duplication. The error ! 1181: * return ensures that the vnode for this device will be released ! 1182: * by vn_open. Open will detect this special error and take the ! 1183: * actions in dupfdopen below. Other callers of vn_open or VOP_OPEN ! 1184: * will simply report the error. ! 1185: */ ! 1186: p->p_dupfd = minor(dev); ! 1187: return (ENODEV); ! 1188: } ! 1189: ! 1190: /* ! 1191: * Duplicate the specified descriptor to a free descriptor. ! 1192: */ ! 1193: int ! 1194: dupfdopen(fdp, indx, dfd, mode, error) ! 1195: register struct filedesc *fdp; ! 1196: register int indx, dfd; ! 1197: int mode; ! 1198: int error; ! 1199: { ! 1200: register struct file *wfp; ! 1201: struct file *fp; ! 1202: ! 1203: /* ! 1204: * If the to-be-dup'd fd number is greater than the allowed number ! 1205: * of file descriptors, or the fd to be dup'd has already been ! 1206: * closed, reject. Note, check for new == old is necessary as ! 1207: * falloc could allocate an already closed to-be-dup'd descriptor ! 1208: * as the new descriptor. ! 1209: */ ! 1210: fp = fdp->fd_ofiles[indx]; ! 1211: if ((u_int)dfd >= fdp->fd_nfiles || ! 1212: (wfp = fdp->fd_ofiles[dfd]) == NULL || wfp == fp || ! 1213: (fdp->fd_ofileflags[dfd] & UF_RESERVED)) ! 1214: return (EBADF); ! 1215: ! 1216: /* ! 1217: * There are two cases of interest here. ! 1218: * ! 1219: * For ENODEV simply dup (dfd) to file descriptor ! 1220: * (indx) and return. ! 1221: * ! 1222: * For ENXIO steal away the file structure from (dfd) and ! 1223: * store it in (indx). (dfd) is effectively closed by ! 1224: * this operation. ! 1225: * ! 1226: * Any other error code is just returned. ! 1227: */ ! 1228: switch (error) { ! 1229: case ENODEV: ! 1230: /* ! 1231: * Check that the mode the file is being opened for is a ! 1232: * subset of the mode of the existing descriptor. ! 1233: */ ! 1234: if (((mode & (FREAD|FWRITE)) | wfp->f_flag) != wfp->f_flag) ! 1235: return (EACCES); ! 1236: if (++wfp->f_count <= 0) ! 1237: panic("dupfdopen f_count"); ! 1238: if (indx > fdp->fd_lastfile) ! 1239: fdp->fd_lastfile = indx;; ! 1240: fdp->fd_ofiles[indx] = wfp; ! 1241: fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; ! 1242: return (0); ! 1243: ! 1244: case ENXIO: ! 1245: /* ! 1246: * Steal away the file pointer from dfd, and stuff it into indx. ! 1247: */ ! 1248: if (indx > fdp->fd_lastfile) ! 1249: fdp->fd_lastfile = indx;; ! 1250: fdp->fd_ofiles[indx] = fdp->fd_ofiles[dfd]; ! 1251: fdp->fd_ofileflags[indx] = fdp->fd_ofileflags[dfd]; ! 1252: _fdrelse(fdp, dfd); ! 1253: return (0); ! 1254: ! 1255: default: ! 1256: return (error); ! 1257: } ! 1258: /* NOTREACHED */ ! 1259: } ! 1260:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.