1 /*
   2  * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.io;
  27 
  28 import java.util.ArrayList;
  29 
  30 /**
  31  * Instances of the file descriptor class serve as an opaque handle
  32  * to the underlying machine-specific structure representing an
  33  * open file, an open socket, or another source or sink of bytes.
  34  * The main practical use for a file descriptor is to create a
  35  * {@link FileInputStream} or {@link FileOutputStream} to contain it.
  36  *
  37  * <p>Applications should not create their own file descriptors.
  38  *
  39  * @author  Pavani Diwanji
  40  * @since   JDK1.0
  41  */
  42 public final class FileDescriptor {
  43 
  44     private int fd;
  45 
  46     private long handle;
  47 
  48     private Closeable parent;
  49     private ArrayList<Closeable> otherParents;
  50     boolean closed = false;
  51 
  52     /**
  53      * Constructs an (invalid) FileDescriptor
  54      * object.
  55      */
  56     public /**/ FileDescriptor() {
  57         fd = -1;
  58         handle = -1;
  59     }
  60 
  61     static {
  62         initIDs();
  63     }
  64 
  65     // Set up JavaIOFileDescriptorAccess in SharedSecrets
  66     static {
  67         sun.misc.SharedSecrets.setJavaIOFileDescriptorAccess(
  68             new sun.misc.JavaIOFileDescriptorAccess() {
  69                 public void set(FileDescriptor obj, int fd) {
  70                     obj.fd = fd;
  71                 }
  72 
  73                 public int get(FileDescriptor obj) {
  74                     return obj.fd;
  75                 }
  76 
  77                 public void setHandle(FileDescriptor obj, long handle) {
  78                     obj.handle = handle;
  79                 }
  80 
  81                 public long getHandle(FileDescriptor obj) {
  82                     return obj.handle;
  83                 }
  84             }
  85         );
  86     }
  87 
  88     /**
  89      * A handle to the standard input stream. Usually, this file
  90      * descriptor is not used directly, but rather via the input stream
  91      * known as {@code System.in}.
  92      *
  93      * @see     java.lang.System#in
  94      */
  95     public static final FileDescriptor in = standardStream(0);
  96 
  97     /**
  98      * A handle to the standard output stream. Usually, this file
  99      * descriptor is not used directly, but rather via the output stream
 100      * known as {@code System.out}.
 101      * @see     java.lang.System#out
 102      */
 103     public static final FileDescriptor out = standardStream(1);
 104 
 105     /**
 106      * A handle to the standard error stream. Usually, this file
 107      * descriptor is not used directly, but rather via the output stream
 108      * known as {@code System.err}.
 109      *
 110      * @see     java.lang.System#err
 111      */
 112     public static final FileDescriptor err = standardStream(2);
 113 
 114     /**
 115      * Tests if this file descriptor object is valid.
 116      *
 117      * @return  {@code true} if the file descriptor object represents a
 118      *          valid, open file, socket, or other active I/O connection;
 119      *          {@code false} otherwise.
 120      */
 121     public boolean valid() {
 122         return ((handle != -1) || (fd != -1));
 123     }
 124 
 125     /**
 126      * Force all system buffers to synchronize with the underlying
 127      * device.  This method returns after all modified data and
 128      * attributes of this FileDescriptor have been written to the
 129      * relevant device(s).  In particular, if this FileDescriptor
 130      * refers to a physical storage medium, such as a file in a file
 131      * system, sync will not return until all in-memory modified copies
 132      * of buffers associated with this FileDesecriptor have been
 133      * written to the physical medium.
 134      *
 135      * sync is meant to be used by code that requires physical
 136      * storage (such as a file) to be in a known state  For
 137      * example, a class that provided a simple transaction facility
 138      * might use sync to ensure that all changes to a file caused
 139      * by a given transaction were recorded on a storage medium.
 140      *
 141      * sync only affects buffers downstream of this FileDescriptor.  If
 142      * any in-memory buffering is being done by the application (for
 143      * example, by a BufferedOutputStream object), those buffers must
 144      * be flushed into the FileDescriptor (for example, by invoking
 145      * OutputStream.flush) before that data will be affected by sync.
 146      *
 147      * @exception SyncFailedException
 148      *        Thrown when the buffers cannot be flushed,
 149      *        or because the system cannot guarantee that all the
 150      *        buffers have been synchronized with physical media.
 151      * @since     JDK1.1
 152      */
 153     public native void sync() throws SyncFailedException;
 154 
 155     /* This routine initializes JNI field offsets for the class */
 156     private static native void initIDs();
 157 
 158     private static native long set(int d);
 159 
 160     private static FileDescriptor standardStream(int fd) {
 161         FileDescriptor desc = new FileDescriptor();
 162         desc.handle = set(fd);
 163         return desc;
 164     }
 165 
 166     /*
 167      * Package private methods to track referents.
 168      * If multiple streams point to the same FileDescriptor, we cycle
 169      * through the list of all referents and call close()
 170      */
 171 
 172     /*
 173      * attach a Closeable to this FD for tracking
 174      */
 175     void attach(Closeable c) {
 176         synchronized (this) {
 177             if (parent == null) {
 178                 // constructor gets to do this
 179                 parent = c;
 180             } else if (otherParents == null) {
 181                 otherParents = new ArrayList<>();
 182                 otherParents.add(parent);
 183                 otherParents.add(c);
 184             } else {
 185                 otherParents.add(c);
 186             }
 187         }
 188     }
 189 
 190     /*
 191      * Cycle through all Closeables sharing this FD and call
 192      * close() on each one.
 193      *
 194      * The caller closeable gets to call close0().
 195      */
 196     @SuppressWarnings("try")
 197     synchronized void closeAll(Closeable releaser) throws IOException {
 198         if (!closed) {
 199             closed = true;
 200             IOException ioe = null;
 201             try (Closeable c = releaser) {
 202                 if (otherParents != null) {
 203                     for (Closeable referent : otherParents) {
 204                         try {
 205                             referent.close();
 206                         } catch(IOException x) {
 207                             if (ioe == null) {
 208                                 ioe = x;
 209                             } else {
 210                                 ioe.addSuppressed(x);
 211                             }
 212                         }
 213                     }
 214                 }
 215             } catch(IOException ex) {
 216                 // if releaser close() throws IOException
 217                 // add other exceptions as suppressed
 218                 if (ioe != null) {
 219                     ex.addSuppressed(ioe);
 220                 }
 221                 ioe = ex;
 222             } finally {
 223                 if (ioe != null) {
 224                     throw ioe;
 225                 }
 226             }
 227         }
 228     }
 229 }