diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index cd7b5bedd81..df8262d81ff 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -250,6 +250,9 @@ Release 2.0.3-alpha - Unreleased HDFS-4105. The SPNEGO user for secondary namenode should use the web keytab. (Arpit Gupta via jitendra) + 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 891afa33f33..1e986cd1350 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 c2f1cf39c3c..a8bdd3dcfe7 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 @@ -141,7 +141,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. */