1 /*
  2  * Copyright (c) 1994, 2023, 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.nio.channels.FileChannel;
 29 import java.util.Arrays;
 30 import jdk.internal.util.ArraysSupport;
 31 import sun.nio.ch.FileChannelImpl;
 32 
 33 /**
 34  * A {@code FileInputStream} obtains input bytes
 35  * from a file in a file system. What files
 36  * are  available depends on the host environment.
 37  *
 38  * <p>{@code FileInputStream} is meant for reading streams of raw bytes
 39  * such as image data. For reading streams of characters, consider using
 40  * {@code FileReader}.
 41  *
 42  * @apiNote
 43  * The {@link #close} method should be called to release resources used by this
 44  * stream, either directly, or with the {@code try}-with-resources statement.
 45  *
 46  * @implSpec
 47  * Subclasses are responsible for the cleanup of resources acquired by the subclass.
 48  * Subclasses requiring that resource cleanup take place after a stream becomes
 49  * unreachable should use {@link java.lang.ref.Cleaner} or some other mechanism.
 50  *
 51  * @author  Arthur van Hoff
 52  * @see     java.io.File
 53  * @see     java.io.FileDescriptor
 54  * @see     java.io.FileOutputStream
 55  * @see     java.nio.file.Files#newInputStream
 56  * @since   1.0
 57  */
 58 public class FileInputStream extends InputStream
 59 {
 60     private static final int DEFAULT_BUFFER_SIZE = 8192;
 61 
 62     /* File Descriptor - handle to the open file */
 63     private final FileDescriptor fd;
 64 
 65     /**
 66      * The path of the referenced file
 67      * (null if the stream is created with a file descriptor)
 68      */
 69     private final String path;
 70 
 71     private volatile FileChannel channel;
 72 
 73     private final Object closeLock = new Object();
 74 
 75     private volatile boolean closed;
 76 
 77     /**
 78      * Creates a {@code FileInputStream} by
 79      * opening a connection to an actual file,
 80      * the file named by the path name {@code name}
 81      * in the file system.  A new {@code FileDescriptor}
 82      * object is created to represent this file
 83      * connection.
 84      * <p>
 85      * First, if there is a security
 86      * manager, its {@code checkRead} method
 87      * is called with the {@code name} argument
 88      * as its argument.
 89      * <p>
 90      * If the named file does not exist, is a directory rather than a regular
 91      * file, or for some other reason cannot be opened for reading then a
 92      * {@code FileNotFoundException} is thrown.
 93      *
 94      * @param      name   the system-dependent file name.
 95      * @throws     FileNotFoundException  if the file does not exist,
 96      *             is a directory rather than a regular file,
 97      *             or for some other reason cannot be opened for
 98      *             reading.
 99      * @throws     SecurityException      if a security manager exists and its
100      *             {@code checkRead} method denies read access
101      *             to the file.
102      * @see        java.lang.SecurityManager#checkRead(java.lang.String)
103      */
104     public FileInputStream(String name) throws FileNotFoundException {
105         this(name != null ? new File(name) : null);
106     }
107 
108     /**
109      * Creates a {@code FileInputStream} by
110      * opening a connection to an actual file,
111      * the file named by the {@code File}
112      * object {@code file} in the file system.
113      * A new {@code FileDescriptor} object
114      * is created to represent this file connection.
115      * <p>
116      * First, if there is a security manager,
117      * its {@code checkRead} method  is called
118      * with the path represented by the {@code file}
119      * argument as its argument.
120      * <p>
121      * If the named file does not exist, is a directory rather than a regular
122      * file, or for some other reason cannot be opened for reading then a
123      * {@code FileNotFoundException} is thrown.
124      *
125      * @param      file   the file to be opened for reading.
126      * @throws     FileNotFoundException  if the file does not exist,
127      *             is a directory rather than a regular file,
128      *             or for some other reason cannot be opened for
129      *             reading.
130      * @throws     SecurityException      if a security manager exists and its
131      *             {@code checkRead} method denies read access to the file.
132      * @see        java.io.File#getPath()
133      * @see        java.lang.SecurityManager#checkRead(java.lang.String)
134      */
135     @SuppressWarnings("this-escape")
136     public FileInputStream(File file) throws FileNotFoundException {
137         String name = (file != null ? file.getPath() : null);
138         @SuppressWarnings("removal")
139         SecurityManager security = System.getSecurityManager();
140         if (security != null) {
141             security.checkRead(name);
142         }
143         if (name == null) {
144             throw new NullPointerException();
145         }
146         if (file.isInvalid()) {
147             throw new FileNotFoundException("Invalid file path");
148         }
149         fd = new FileDescriptor();
150         fd.attach(this);
151         path = name;
152         open(name);
153         FileCleanable.register(fd);       // open set the fd, register the cleanup
154     }
155 
156     /**
157      * Creates a {@code FileInputStream} by using the file descriptor
158      * {@code fdObj}, which represents an existing connection to an
159      * actual file in the file system.
160      * <p>
161      * If there is a security manager, its {@code checkRead} method is
162      * called with the file descriptor {@code fdObj} as its argument to
163      * see if it's ok to read the file descriptor. If read access is denied
164      * to the file descriptor a {@code SecurityException} is thrown.
165      * <p>
166      * If {@code fdObj} is null then a {@code NullPointerException}
167      * is thrown.
168      * <p>
169      * This constructor does not throw an exception if {@code fdObj}
170      * is {@link java.io.FileDescriptor#valid() invalid}.
171      * However, if the methods are invoked on the resulting stream to attempt
172      * I/O on the stream, an {@code IOException} is thrown.
173      *
174      * @param      fdObj   the file descriptor to be opened for reading.
175      * @throws     SecurityException      if a security manager exists and its
176      *             {@code checkRead} method denies read access to the
177      *             file descriptor.
178      * @see        SecurityManager#checkRead(java.io.FileDescriptor)
179      */
180     @SuppressWarnings("this-escape")
181     public FileInputStream(FileDescriptor fdObj) {
182         @SuppressWarnings("removal")
183         SecurityManager security = System.getSecurityManager();
184         if (fdObj == null) {
185             throw new NullPointerException();
186         }
187         if (security != null) {
188             security.checkRead(fdObj);
189         }
190         fd = fdObj;
191         path = null;
192 
193         /*
194          * FileDescriptor is being shared by streams.
195          * Register this stream with FileDescriptor tracker.
196          */
197         fd.attach(this);
198     }
199 
200     /**
201      * Opens the specified file for reading.
202      * @param name the name of the file
203      */
204     private native void open0(String name) throws FileNotFoundException;
205 
206     // wrap native call to allow instrumentation
207     /**
208      * Opens the specified file for reading.
209      * @param name the name of the file
210      */
211     private void open(String name) throws FileNotFoundException {
212         open0(name);
213     }
214 
215     /**
216      * Reads a byte of data from this input stream. This method blocks
217      * if no input is yet available.
218      *
219      * @return     the next byte of data, or {@code -1} if the end of the
220      *             file is reached.
221      * @throws     IOException {@inheritDoc}
222      */
223     @Override
224     public int read() throws IOException {
225         return read0();
226     }
227 
228     private native int read0() throws IOException;
229 
230     /**
231      * Reads a subarray as a sequence of bytes.
232      * @param     b the data to be written
233      * @param     off the start offset in the data
234      * @param     len the number of bytes that are written
235      * @throws    IOException If an I/O error has occurred.
236      */
237     private native int readBytes(byte[] b, int off, int len) throws IOException;
238 
239     /**
240      * Reads up to {@code b.length} bytes of data from this input
241      * stream into an array of bytes. This method blocks until some input
242      * is available.
243      *
244      * @param      b   {@inheritDoc}
245      * @return     the total number of bytes read into the buffer, or
246      *             {@code -1} if there is no more data because the end of
247      *             the file has been reached.
248      * @throws     IOException  if an I/O error occurs.
249      */
250     @Override
251     public int read(byte[] b) throws IOException {
252         return readBytes(b, 0, b.length);
253     }
254 
255     /**
256      * Reads up to {@code len} bytes of data from this input stream
257      * into an array of bytes. If {@code len} is not zero, the method
258      * blocks until some input is available; otherwise, no
259      * bytes are read and {@code 0} is returned.
260      *
261      * @param      b     {@inheritDoc}
262      * @param      off   {@inheritDoc}
263      * @param      len   {@inheritDoc}
264      * @return     {@inheritDoc}
265      * @throws     NullPointerException {@inheritDoc}
266      * @throws     IndexOutOfBoundsException {@inheritDoc}
267      * @throws     IOException  if an I/O error occurs.
268      */
269     @Override
270     public int read(byte[] b, int off, int len) throws IOException {
271         return readBytes(b, off, len);
272     }
273 
274     @Override
275     public byte[] readAllBytes() throws IOException {
276         long length = length();
277         long position = position();
278         long size = length - position;
279 
280         if (length <= 0 || size <= 0)
281             return super.readAllBytes();
282 
283         if (size > (long) Integer.MAX_VALUE) {
284             String msg =
285                 String.format("Required array size too large for %s: %d = %d - %d",
286                     path, size, length, position);
287             throw new OutOfMemoryError(msg);
288         }
289 
290         int capacity = (int)size;
291         byte[] buf = new byte[capacity];
292 
293         int nread = 0;
294         int n;
295         for (;;) {
296             // read to EOF which may read more or less than initial size, e.g.,
297             // file is truncated while we are reading
298             while ((n = read(buf, nread, capacity - nread)) > 0)
299                 nread += n;
300 
301             // if last call to read() returned -1, we are done; otherwise,
302             // try to read one more byte and if that fails we're done too
303             if (n < 0 || (n = read()) < 0)
304                 break;
305 
306             // one more byte was read; need to allocate a larger buffer
307             capacity = Math.max(ArraysSupport.newLength(capacity,
308                                                         1,         // min growth
309                                                         capacity), // pref growth
310                                 DEFAULT_BUFFER_SIZE);
311             buf = Arrays.copyOf(buf, capacity);
312             buf[nread++] = (byte)n;
313         }
314         return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
315     }
316 
317     @Override
318     public byte[] readNBytes(int len) throws IOException {
319         if (len < 0)
320             throw new IllegalArgumentException("len < 0");
321         if (len == 0)
322             return new byte[0];
323 
324         long length = length();
325         long position = position();
326         long size = length - position;
327 
328         if (length <= 0 || size <= 0)
329             return super.readNBytes(len);
330 
331         int capacity = (int)Math.min(len, size);
332         byte[] buf = new byte[capacity];
333 
334         int remaining = capacity;
335         int nread = 0;
336         int n;
337         do {
338             n = read(buf, nread, remaining);
339             if (n > 0) {
340                 nread += n;
341                 remaining -= n;
342             } else if (n == 0) {
343                 // Block until a byte is read or EOF is detected
344                 byte b = (byte)read();
345                 if (b == -1 )
346                     break;
347                 buf[nread++] = b;
348                 remaining--;
349             }
350         } while (n >= 0 && remaining > 0);
351         return (capacity == nread) ? buf : Arrays.copyOf(buf, nread);
352     }
353 
354     /**
355      * {@inheritDoc}
356      */
357     @Override
358     public long transferTo(OutputStream out) throws IOException {
359         long transferred = 0L;
360         if (out instanceof FileOutputStream fos) {
361             FileChannel fc = getChannel();
362             long pos = fc.position();
363             transferred = fc.transferTo(pos, Long.MAX_VALUE, fos.getChannel());
364             long newPos = pos + transferred;
365             fc.position(newPos);
366             if (newPos >= fc.size()) {
367                 return transferred;
368             }
369         }
370         try {
371             return Math.addExact(transferred, super.transferTo(out));
372         } catch (ArithmeticException ignore) {
373             return Long.MAX_VALUE;
374         }
375     }
376 
377     private long length() throws IOException {
378         return length0();
379     }
380     private native long length0() throws IOException;
381 
382     private long position() throws IOException {
383         return position0();
384     }
385     private native long position0() throws IOException;
386 
387     /**
388      * Skips over and discards {@code n} bytes of data from the
389      * input stream.
390      *
391      * <p>The {@code skip} method may, for a variety of
392      * reasons, end up skipping over some smaller number of bytes,
393      * possibly {@code 0}. If {@code n} is negative, the method
394      * will try to skip backwards. In case the backing file does not support
395      * backward skip at its current position, an {@code IOException} is
396      * thrown. The actual number of bytes skipped is returned. If it skips
397      * forwards, it returns a positive value. If it skips backwards, it
398      * returns a negative value.
399      *
400      * <p>This method may skip more bytes than what are remaining in the
401      * backing file. This produces no exception and the number of bytes skipped
402      * may include some number of bytes that were beyond the EOF of the
403      * backing file. Attempting to read from the stream after skipping past
404      * the end will result in -1 indicating the end of the file.
405      *
406      * @param      n   {@inheritDoc}
407      * @return     the actual number of bytes skipped.
408      * @throws     IOException  if n is negative, if the stream does not
409      *             support seek, or if an I/O error occurs.
410      */
411     @Override
412     public long skip(long n) throws IOException {
413         return skip0(n);
414     }
415 
416     private native long skip0(long n) throws IOException;
417 
418     /**
419      * Returns an estimate of the number of remaining bytes that can be read (or
420      * skipped over) from this input stream without blocking by the next
421      * invocation of a method for this input stream. Returns 0 when the file
422      * position is beyond EOF. The next invocation might be the same thread
423      * or another thread. A single read or skip of this many bytes will not
424      * block, but may read or skip fewer bytes.
425      *
426      * <p> In some cases, a non-blocking read (or skip) may appear to be
427      * blocked when it is merely slow, for example when reading large
428      * files over slow networks.
429      *
430      * @return     an estimate of the number of remaining bytes that can be read
431      *             (or skipped over) from this input stream without blocking.
432      * @throws     IOException  if this file input stream has been closed by calling
433      *             {@code close} or an I/O error occurs.
434      */
435     @Override
436     public int available() throws IOException {
437         return available0();
438     }
439 
440     private native int available0() throws IOException;
441 
442     /**
443      * Closes this file input stream and releases any system resources
444      * associated with the stream.
445      *
446      * <p> If this stream has an associated channel then the channel is closed
447      * as well.
448      *
449      * @apiNote
450      * Overriding {@link #close} to perform cleanup actions is reliable
451      * only when called directly or when called by try-with-resources.
452      *
453      * @implSpec
454      * Subclasses requiring that resource cleanup take place after a stream becomes
455      * unreachable should use the {@link java.lang.ref.Cleaner} mechanism.
456      *
457      * <p>
458      * If this stream has an associated channel then this method will close the
459      * channel, which in turn will close this stream. Subclasses that override
460      * this method should be prepared to handle possible reentrant invocation.
461      *
462      * @throws     IOException  {@inheritDoc}
463      */
464     @Override
465     public void close() throws IOException {
466         if (closed) {
467             return;
468         }
469         synchronized (closeLock) {
470             if (closed) {
471                 return;
472             }
473             closed = true;
474         }
475 
476         FileChannel fc = channel;
477         if (fc != null) {
478             // possible race with getChannel(), benign since
479             // FileChannel.close is final and idempotent
480             fc.close();
481         }
482 
483         fd.closeAll(new Closeable() {
484             public void close() throws IOException {
485                fd.close();
486            }
487         });
488     }
489 
490     /**
491      * Returns the {@code FileDescriptor}
492      * object  that represents the connection to
493      * the actual file in the file system being
494      * used by this {@code FileInputStream}.
495      *
496      * @return     the file descriptor object associated with this stream.
497      * @throws     IOException  if an I/O error occurs.
498      * @see        java.io.FileDescriptor
499      */
500     public final FileDescriptor getFD() throws IOException {
501         if (fd != null) {
502             return fd;
503         }
504         throw new IOException();
505     }
506 
507     /**
508      * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
509      * object associated with this file input stream.
510      *
511      * <p> The initial {@link java.nio.channels.FileChannel#position()
512      * position} of the returned channel will be equal to the
513      * number of bytes read from the file so far.  Reading bytes from this
514      * stream will increment the channel's position.  Changing the channel's
515      * position, either explicitly or by reading, will change this stream's
516      * file position.
517      *
518      * @return  the file channel associated with this file input stream
519      *
520      * @since 1.4
521      */
522     public FileChannel getChannel() {
523         FileChannel fc = this.channel;
524         if (fc == null) {
525             synchronized (this) {
526                 fc = this.channel;
527                 if (fc == null) {
528                     fc = FileChannelImpl.open(fd, path, true, false, false, false, this);
529                     this.channel = fc;
530                     if (closed) {
531                         try {
532                             // possible race with close(), benign since
533                             // FileChannel.close is final and idempotent
534                             fc.close();
535                         } catch (IOException ioe) {
536                             throw new InternalError(ioe); // should not happen
537                         }
538                     }
539                 }
540             }
541         }
542         return fc;
543     }
544 
545     private static native void initIDs();
546 
547     static {
548         initIDs();
549     }
550 }