+/*
+ * Free a file descriptor.
+ */
+ffree(fp)
+ register struct file *fp;
+{
+ register struct file *fq;
+
+ if (fq = fp->f_filef)
+ fq->f_fileb = fp->f_fileb;
+ *fp->f_fileb = fq;
+ crfree(fp->f_cred);
+#ifdef DIAGNOSTIC
+ fp->f_filef = NULL;
+ fp->f_fileb = NULL;
+ fp->f_count = 0;
+#endif
+ nfiles--;
+ FREE(fp, M_FILE);
+}
+
+/*
+ * Copy a filedesc structure.
+ */
+struct filedesc *
+fdcopy(p)
+ struct proc *p;
+{
+ register struct filedesc *newfdp, *fdp = p->p_fd;
+ register struct file **fpp;
+ register int i;
+
+ MALLOC(newfdp, struct filedesc *, sizeof(struct filedesc0),
+ M_FILEDESC, M_WAITOK);
+ bcopy(fdp, newfdp, sizeof(struct filedesc));
+ VREF(newfdp->fd_cdir);
+ if (newfdp->fd_rdir)
+ VREF(newfdp->fd_rdir);
+ newfdp->fd_refcnt = 1;
+
+ /*
+ * If the number of open files fits in the internal arrays
+ * of the open file structure, use them, otherwise allocate
+ * additional memory for the number of descriptors currently
+ * in use.
+ */
+ if (newfdp->fd_lastfile < NDFILE) {
+ newfdp->fd_ofiles = ((struct filedesc0 *) newfdp)->fd_dfiles;
+ newfdp->fd_ofileflags =
+ ((struct filedesc0 *) newfdp)->fd_dfileflags;
+ i = NDFILE;
+ } else {
+ /*
+ * Compute the smallest multiple of NDEXTENT needed
+ * for the file descriptors currently in use,
+ * allowing the table to shrink.
+ */
+ i = newfdp->fd_nfiles;
+ while (i > 2 * NDEXTENT && i >= newfdp->fd_lastfile * 2)
+ i /= 2;
+ MALLOC(newfdp->fd_ofiles, struct file **, i * OFILESIZE,
+ M_FILEDESC, M_WAITOK);
+ newfdp->fd_ofileflags = (char *) &newfdp->fd_ofiles[i];
+ }
+ newfdp->fd_nfiles = i;
+ bcopy(fdp->fd_ofiles, newfdp->fd_ofiles, i * sizeof(struct file **));
+ bcopy(fdp->fd_ofileflags, newfdp->fd_ofileflags, i * sizeof(char));
+ fpp = newfdp->fd_ofiles;
+ for (i = newfdp->fd_lastfile; i-- >= 0; fpp++)
+ if (*fpp != NULL)
+ (*fpp)->f_count++;
+ return (newfdp);
+}
+
+/*
+ * Release a filedesc structure.
+ */
+void
+fdfree(p)
+ struct proc *p;
+{
+ register struct filedesc *fdp = p->p_fd;
+ struct file **fpp;
+ register int i;
+
+ if (--fdp->fd_refcnt > 0)
+ return;
+ fpp = fdp->fd_ofiles;
+ for (i = fdp->fd_lastfile; i-- >= 0; fpp++)
+ if (*fpp)
+ (void) closef(*fpp, p);
+ if (fdp->fd_nfiles > NDFILE)
+ FREE(fdp->fd_ofiles, M_FILEDESC);
+ vrele(fdp->fd_cdir);
+ if (fdp->fd_rdir)
+ vrele(fdp->fd_rdir);
+ FREE(fdp, M_FILEDESC);
+}
+