diff --git a/core/src/raw/oio/read.rs b/core/src/raw/oio/read.rs index 9b18b31e0bce..e3bce7a06585 100644 --- a/core/src/raw/oio/read.rs +++ b/core/src/raw/oio/read.rs @@ -149,6 +149,17 @@ impl Read for Box { } } +fn convert_to_io_error(err: Error) -> io::Error { + let kind = match err.kind() { + ErrorKind::NotFound => io::ErrorKind::NotFound, + ErrorKind::PermissionDenied => io::ErrorKind::PermissionDenied, + ErrorKind::InvalidInput => io::ErrorKind::InvalidInput, + _ => io::ErrorKind::Interrupted, + }; + + io::Error::new(kind, err) +} + impl futures::AsyncRead for dyn Read { fn poll_read( mut self: Pin<&mut Self>, @@ -156,8 +167,7 @@ impl futures::AsyncRead for dyn Read { buf: &mut [u8], ) -> Poll> { let this: &mut dyn Read = &mut *self; - this.poll_read(cx, buf) - .map_err(|err| io::Error::new(io::ErrorKind::Interrupted, err)) + this.poll_read(cx, buf).map_err(convert_to_io_error) } } @@ -168,8 +178,7 @@ impl futures::AsyncSeek for dyn Read { pos: io::SeekFrom, ) -> Poll> { let this: &mut dyn Read = &mut *self; - this.poll_seek(cx, pos) - .map_err(|err| io::Error::new(io::ErrorKind::Interrupted, err)) + this.poll_seek(cx, pos).map_err(convert_to_io_error) } } @@ -350,8 +359,7 @@ impl io::Read for dyn BlockingRead { #[inline] fn read(&mut self, buf: &mut [u8]) -> io::Result { let this: &mut dyn BlockingRead = &mut *self; - this.read(buf) - .map_err(|err| io::Error::new(io::ErrorKind::Interrupted, err)) + this.read(buf).map_err(convert_to_io_error) } } @@ -359,8 +367,7 @@ impl io::Seek for dyn BlockingRead { #[inline] fn seek(&mut self, pos: io::SeekFrom) -> io::Result { let this: &mut dyn BlockingRead = &mut *self; - this.seek(pos) - .map_err(|err| io::Error::new(io::ErrorKind::Interrupted, err)) + this.seek(pos).map_err(convert_to_io_error) } } diff --git a/core/src/types/error.rs b/core/src/types/error.rs index b530c16a179e..e4266a96f9dc 100644 --- a/core/src/types/error.rs +++ b/core/src/types/error.rs @@ -347,6 +347,7 @@ impl From for io::Error { let kind = match err.kind() { ErrorKind::NotFound => io::ErrorKind::NotFound, ErrorKind::PermissionDenied => io::ErrorKind::PermissionDenied, + ErrorKind::InvalidInput => io::ErrorKind::InvalidInput, _ => io::ErrorKind::Other, }; diff --git a/core/tests/behavior/write.rs b/core/tests/behavior/write.rs index f147d5883663..4ef2a6208a71 100644 --- a/core/tests/behavior/write.rs +++ b/core/tests/behavior/write.rs @@ -86,7 +86,8 @@ pub fn behavior_write_tests(op: &Operator) -> Vec { test_writer_copy, test_writer_abort, test_writer_futures_copy, - test_fuzz_unsized_writer + test_fuzz_unsized_writer, + test_invalid_reader_seek ) } @@ -1233,3 +1234,28 @@ pub async fn test_fuzz_unsized_writer(op: Operator) -> Result<()> { op.delete(&path).await.expect("delete must succeed"); Ok(()) } + +/// seeking a negative position should return a InvalidInput error +pub async fn test_invalid_reader_seek(op: Operator) -> Result<()> { + let path = uuid::Uuid::new_v4().to_string(); + debug!("Generate a random file: {}", &path); + let (content, _) = gen_bytes(); + + op.write(&path, content.clone()) + .await + .expect("write must succeed"); + + let mut r = op.reader(&path).await?; + let res = r.seek(std::io::SeekFrom::Current(-1024)).await; + + assert!(res.is_err()); + + assert_eq!( + res.unwrap_err().kind(), + std::io::ErrorKind::InvalidInput, + "seeking a negative position should return a InvalidInput error" + ); + + op.delete(&path).await.expect("delete must succeed"); + Ok(()) +}