diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index 76c864b736..c2872541a4 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -608,6 +608,9 @@ Release 2.0.3-alpha - Unreleased HDFS-3507. DFS#isInSafeMode needs to execute only on Active NameNode. (Vinay via atm) + HDFS-4156. Seeking to a negative position should throw an IOE. + (Eli Reisman via eli) + Release 2.0.2-alpha - 2012-09-07 INCOMPATIBLE CHANGES diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSInputStream.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSInputStream.java index 891afa33f3..1e986cd135 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSInputStream.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/DFSInputStream.java @@ -1076,6 +1076,9 @@ public class DFSInputStream extends FSInputStream implements ByteBufferReadable if (targetPos > getFileLength()) { throw new IOException("Cannot seek after EOF"); } + if (targetPos < 0) { + throw new IOException("Cannot seek to negative offset"); + } if (closed) { throw new IOException("Stream is closed!"); } diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestSeekBug.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestSeekBug.java index 2ff1c291c1..c9f5293e1d 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestSeekBug.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestSeekBug.java @@ -133,7 +133,69 @@ public class TestSeekBug { cluster.shutdown(); } } - + + /** + * Test (expected to throw IOE) for negative + * FSDataInpuStream#seek argument + */ + @Test (expected=IOException.class) + public void testNegativeSeek() throws IOException { + Configuration conf = new HdfsConfiguration(); + MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf).build(); + FileSystem fs = cluster.getFileSystem(); + try { + Path seekFile = new Path("seekboundaries.dat"); + DFSTestUtil.createFile( + fs, + seekFile, + ONEMB, + ONEMB, + fs.getDefaultBlockSize(seekFile), + fs.getDefaultReplication(seekFile), + seed); + FSDataInputStream stream = fs.open(seekFile); + // Perform "safe seek" (expected to pass) + stream.seek(65536); + assertEquals(65536, stream.getPos()); + // expect IOE for this call + stream.seek(-73); + } finally { + fs.close(); + cluster.shutdown(); + } + } + + /** + * Test (expected to throw IOE) for FSDataInpuStream#seek + * when the position argument is larger than the file size. + */ + @Test (expected=IOException.class) + public void testSeekPastFileSize() throws IOException { + Configuration conf = new HdfsConfiguration(); + MiniDFSCluster cluster = new MiniDFSCluster.Builder(conf).build(); + FileSystem fs = cluster.getFileSystem(); + try { + Path seekFile = new Path("seekboundaries.dat"); + DFSTestUtil.createFile( + fs, + seekFile, + ONEMB, + ONEMB, + fs.getDefaultBlockSize(seekFile), + fs.getDefaultReplication(seekFile), + seed); + FSDataInputStream stream = fs.open(seekFile); + // Perform "safe seek" (expected to pass) + stream.seek(65536); + assertEquals(65536, stream.getPos()); + // expect IOE for this call + stream.seek(ONEMB + ONEMB + ONEMB); + } finally { + fs.close(); + cluster.shutdown(); + } + } + /** * Tests if the seek bug exists in FSDataInputStream in LocalFS. */