8011136: FileInputStream.available and skip inconsistencies
authordxu
Fri, 17 May 2013 12:04:18 -0700
changeset 17691 13931cd9405f
parent 17502 29aab40dee0f
child 17692 685c0741cfbb
child 17693 2d7cbdb1bb53
8011136: FileInputStream.available and skip inconsistencies Summary: Correct the behavior of available() and update related java specs for available() and skip() in InputStream and FileInputStream classes. Reviewed-by: alanb
jdk/src/share/classes/java/io/FileInputStream.java
jdk/src/share/classes/java/io/InputStream.java
jdk/src/share/native/java/io/FileInputStream.c
jdk/test/java/io/FileInputStream/LargeFileAvailable.java
jdk/test/java/io/FileInputStream/NegativeAvailable.java
--- a/jdk/src/share/classes/java/io/FileInputStream.java	Fri May 17 16:44:36 2013 +0100
+++ b/jdk/src/share/classes/java/io/FileInputStream.java	Fri May 17 12:04:18 2013 -0700
@@ -240,13 +240,15 @@
      *
      * <p>The <code>skip</code> method may, for a variety of
      * reasons, end up skipping over some smaller number of bytes,
-     * possibly <code>0</code>. If <code>n</code> is negative, an
-     * <code>IOException</code> is thrown, even though the <code>skip</code>
-     * method of the {@link InputStream} superclass does nothing in this case.
-     * The actual number of bytes skipped is returned.
+     * possibly <code>0</code>. If <code>n</code> is negative, the method
+     * will try to skip backwards. In case the backing file does not support
+     * backward skip at its current position, an <code>IOException</code> is
+     * thrown. The actual number of bytes skipped is returned. If it skips
+     * forwards, it returns a positive value. If it skips backwards, it
+     * returns a negative value.
      *
-     * <p>This method may skip more bytes than are remaining in the backing
-     * file. This produces no exception and the number of bytes skipped
+     * <p>This method may skip more bytes than what are remaining in the
+     * backing file. This produces no exception and the number of bytes skipped
      * may include some number of bytes that were beyond the EOF of the
      * backing file. Attempting to read from the stream after skipping past
      * the end will result in -1 indicating the end of the file.
@@ -261,9 +263,10 @@
     /**
      * Returns an estimate of the number of remaining bytes that can be read (or
      * skipped over) from this input stream without blocking by the next
-     * invocation of a method for this input stream. The next invocation might be
-     * the same thread or another thread.  A single read or skip of this
-     * many bytes will not block, but may read or skip fewer bytes.
+     * invocation of a method for this input stream. Returns 0 when the file
+     * position is beyond EOF. The next invocation might be the same thread
+     * or another thread. A single read or skip of this many bytes will not
+     * block, but may read or skip fewer bytes.
      *
      * <p> In some cases, a non-blocking read (or skip) may appear to be
      * blocked when it is merely slow, for example when reading large
--- a/jdk/src/share/classes/java/io/InputStream.java	Fri May 17 16:44:36 2013 +0100
+++ b/jdk/src/share/classes/java/io/InputStream.java	Fri May 17 12:04:18 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -193,8 +193,10 @@
      * up skipping over some smaller number of bytes, possibly <code>0</code>.
      * This may result from any of a number of conditions; reaching end of file
      * before <code>n</code> bytes have been skipped is only one possibility.
-     * The actual number of bytes skipped is returned.  If <code>n</code> is
-     * negative, no bytes are skipped.
+     * The actual number of bytes skipped is returned. If {@code n} is
+     * negative, the {@code skip} method for class {@code InputStream} always
+     * returns 0, and no bytes are skipped. Subclasses may handle the negative
+     * value differently.
      *
      * <p> The <code>skip</code> method of this class creates a
      * byte array and then repeatedly reads into it until <code>n</code> bytes
--- a/jdk/src/share/native/java/io/FileInputStream.c	Fri May 17 16:44:36 2013 +0100
+++ b/jdk/src/share/native/java/io/FileInputStream.c	Fri May 17 12:04:18 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -100,6 +100,8 @@
     if (IO_Available(fd, &ret)) {
         if (ret > INT_MAX) {
             ret = (jlong) INT_MAX;
+        } else if (ret < 0) {
+            ret = 0;
         }
         return jlong_to_jint(ret);
     }
--- a/jdk/test/java/io/FileInputStream/LargeFileAvailable.java	Fri May 17 16:44:36 2013 +0100
+++ b/jdk/test/java/io/FileInputStream/LargeFileAvailable.java	Fri May 17 12:04:18 2013 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 6402006 7030573
+ * @bug 6402006 7030573 8011136
  * @summary Test if available returns correct value when reading
  *          a large file.
  */
@@ -61,9 +61,12 @@
             remaining -= skipBytes(fis, bigSkip, remaining);
             remaining -= skipBytes(fis, 10L, remaining);
             remaining -= skipBytes(fis, bigSkip, remaining);
-            if (fis.available() != (int) remaining) {
-                 throw new RuntimeException("available() returns "
-                     + fis.available() + " but expected " + remaining);
+            int expected = (remaining >= Integer.MAX_VALUE)
+                           ? Integer.MAX_VALUE
+                           : (remaining > 0 ? (int) remaining : 0);
+            if (fis.available() != expected) {
+                throw new RuntimeException("available() returns "
+                        + fis.available() + " but expected " + expected);
             }
         } finally {
             file.delete();
@@ -77,19 +80,18 @@
         long skip = is.skip(toSkip);
         if (skip != toSkip) {
             throw new RuntimeException("skip() returns " + skip
-                + " but expected " + toSkip);
+                                       + " but expected " + toSkip);
         }
         long remaining = avail - skip;
-        int expected = remaining >= Integer.MAX_VALUE
-                           ? Integer.MAX_VALUE
-                           : (int) remaining;
+        int expected = (remaining >= Integer.MAX_VALUE)
+                       ? Integer.MAX_VALUE
+                       : (remaining > 0 ? (int) remaining : 0);
 
-        System.out.println("Skipped " + skip + " bytes "
-            + " available() returns " + expected +
-            " remaining=" + remaining);
+        System.out.println("Skipped " + skip + " bytes, available() returns "
+                           + expected + ", remaining " + remaining);
         if (is.available() != expected) {
             throw new RuntimeException("available() returns "
-                + is.available() + " but expected " + expected);
+                    + is.available() + " but expected " + expected);
         }
         return skip;
     }
--- a/jdk/test/java/io/FileInputStream/NegativeAvailable.java	Fri May 17 16:44:36 2013 +0100
+++ b/jdk/test/java/io/FileInputStream/NegativeAvailable.java	Fri May 17 12:04:18 2013 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8010837
+ * @bug 8010837 8011136
  * @summary Test if available returns correct value when skipping beyond
  *          the end of a file.
  * @author Dan Xu
@@ -42,6 +42,7 @@
     public static void main(String[] args) throws IOException {
         final int SIZE = 10;
         final int SKIP = 5;
+        final int NEGATIVE_SKIP = -5;
 
         // Create a temporary file with size of 10 bytes.
         Path tmp = Files.createTempFile(null, null);
@@ -56,12 +57,15 @@
         try (FileInputStream fis = new FileInputStream(tempFile)) {
             if (tempFile.length() != SIZE) {
                 throw new RuntimeException("unexpected file size = "
-                    + tempFile.length());
+                                           + tempFile.length());
             }
             long space = skipBytes(fis, SKIP, SIZE);
+            space = skipBytes(fis, NEGATIVE_SKIP, space);
             space = skipBytes(fis, SKIP, space);
             space = skipBytes(fis, SKIP, space);
             space = skipBytes(fis, SKIP, space);
+            space = skipBytes(fis, NEGATIVE_SKIP, space);
+            space = skipBytes(fis, NEGATIVE_SKIP, space);
         }
         Files.deleteIfExists(tmp);
     }
@@ -74,17 +78,18 @@
         long skip = fis.skip(toSkip);
         if (skip != toSkip) {
             throw new RuntimeException("skip() returns " + skip
-                + " but expected " + toSkip);
+                                       + " but expected " + toSkip);
         }
-        long remaining = space - toSkip;
+        long newSpace = space - toSkip;
+        long remaining = newSpace > 0 ? newSpace : 0;
         int avail = fis.available();
         if (avail != remaining) {
             throw new RuntimeException("available() returns " + avail
-                + " but expected " + remaining);
+                                       + " but expected " + remaining);
         }
 
         System.out.println("Skipped " + skip + " bytes "
-            + " available() returns " + avail);
-        return remaining;
+                           + " available() returns " + avail);
+        return newSpace;
     }
 }