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.
*/