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