@@ -23,6 +23,19 @@ fn path(prefix: &Path, file: &str) -> String {
2323 path_buf. as_path ( ) . to_str ( ) . unwrap ( ) . to_owned ( )
2424}
2525
26+ // Return an open(2) mode, modified as needed to support binary files on the target platform.
27+ fn binary_mode ( mode : c_int ) -> c_int {
28+ #[ cfg( target_os = "windows" ) ]
29+ {
30+ mode | libc:: O_BINARY
31+ }
32+
33+ #[ cfg( not( target_os = "windows" ) ) ]
34+ {
35+ mode
36+ }
37+ }
38+
2639// Try to gzopen a file path with a specified mode, and panic if the result is unexpected.
2740// NOTE: This is a macro, instead of a function, so that the test runner will report errors
2841// with the line number where it is invoked.
@@ -287,6 +300,58 @@ fn gzread_special_cases() {
287300 ) ;
288301 assert_eq ! ( unsafe { gzclose( file) } , Z_ERRNO ) ;
289302 }
303+
304+ // Create a gzip file with some junk data after the end of the deflate stream.
305+ // gzread should ignore the junk data.
306+ // Create a temporary directory that will be automatically removed when
307+ // temp_dir goes out of scope.
308+ let temp_dir_path = temp_base ( ) ;
309+ let temp_dir = tempfile:: TempDir :: new_in ( temp_dir_path) . unwrap ( ) ;
310+ let temp_path = temp_dir. path ( ) ;
311+ let file_name = path ( temp_path, "output.gz" ) ;
312+ let file = unsafe {
313+ gzopen (
314+ CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) ,
315+ CString :: new ( "w" ) . unwrap ( ) . as_ptr ( ) ,
316+ )
317+ } ;
318+ assert ! ( !file. is_null( ) ) ;
319+ const STRING1 : & [ u8 ] = b"deflated contents" ;
320+ const STRING2 : & [ u8 ] = b"\n trailing data" ;
321+ assert_eq ! (
322+ unsafe { gzwrite( file, STRING1 . as_ptr( ) . cast:: <c_void>( ) , STRING1 . len( ) as _) } ,
323+ STRING1 . len( ) as _
324+ ) ;
325+ assert_eq ! ( unsafe { gzclose( file) } , Z_OK ) ;
326+ let old_size = file_size ( & file_name) . unwrap ( ) ;
327+ let fd = unsafe {
328+ libc:: open (
329+ CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) ,
330+ binary_mode ( libc:: O_APPEND | libc:: O_WRONLY ) ,
331+ )
332+ } ;
333+ assert_ne ! ( fd, -1 ) ;
334+ assert_eq ! (
335+ unsafe { libc:: write( fd, STRING2 . as_ptr( ) . cast:: <c_void>( ) , STRING2 . len( ) as _) } ,
336+ STRING2 . len( ) as _
337+ ) ;
338+ assert_eq ! ( unsafe { libc:: close( fd) } , 0 ) ;
339+ let new_size = file_size ( & file_name) . unwrap ( ) ;
340+ assert_eq ! ( new_size, old_size + STRING2 . len( ) ) ;
341+ let file = unsafe {
342+ gzopen (
343+ CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) ,
344+ CString :: new ( "r" ) . unwrap ( ) . as_ptr ( ) ,
345+ )
346+ } ;
347+ assert ! ( !file. is_null( ) ) ;
348+ // Read more than expected to make sure we get everything.
349+ let mut buf = [ 0u8 ; STRING1 . len ( ) + 1 ] ;
350+ assert_eq ! (
351+ unsafe { gzread( file, buf. as_mut_ptr( ) . cast:: <c_void>( ) , buf. len( ) as _) } ,
352+ STRING1 . len( ) as _
353+ ) ;
354+ assert_eq ! ( unsafe { gzclose( file) } , Z_OK ) ;
290355}
291356
292357#[ test]
@@ -720,16 +785,10 @@ fn gzoffset_gztell_read() {
720785 // header. This should affect the return values of gzoffset but not gztell.
721786 const OFFSET : usize = 123 ;
722787 const PADDING : & [ u8 ] = & [ 0u8 ; OFFSET ] ;
723- let mut mode = libc:: O_CREAT ;
724- mode |= libc:: O_WRONLY ;
725- #[ cfg( target_os = "windows" ) ]
726- {
727- mode |= libc:: O_BINARY ;
728- }
729788 let fd = unsafe {
730789 libc:: open (
731790 CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) ,
732- mode ,
791+ binary_mode ( libc :: O_CREAT | libc :: O_WRONLY ) ,
733792 0o644 ,
734793 )
735794 } ;
@@ -739,11 +798,7 @@ fn gzoffset_gztell_read() {
739798 OFFSET as _
740799 ) ;
741800 let source_name = crate_path ( "src/test-data/issue-109.gz" ) ;
742- mode = libc:: O_RDONLY ;
743- #[ cfg( target_os = "windows" ) ]
744- {
745- mode |= libc:: O_BINARY ;
746- }
801+ let mode = binary_mode ( libc:: O_RDONLY ) ;
747802 let source_fd =
748803 unsafe { libc:: open ( CString :: new ( source_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) , mode) } ;
749804 assert_ne ! ( source_fd, -1 ) ;
@@ -910,12 +965,7 @@ fn gzputc_basic() {
910965 assert_eq ! ( unsafe { gzclose( file) } , Z_OK ) ;
911966
912967 // Validate that the file contains the expected bytes.
913- let mut mode = 0 ;
914- #[ cfg( target_os = "windows" ) ]
915- {
916- mode |= libc:: O_BINARY ;
917- }
918- mode |= libc:: O_RDONLY ;
968+ let mode = binary_mode ( libc:: O_RDONLY ) ;
919969 let fd = unsafe { libc:: open ( CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) , mode) } ;
920970 assert_ne ! ( fd, -1 ) ;
921971 // Try to read more than the expected amount of data, to ensure we get everything.
@@ -988,12 +1038,7 @@ fn gzputs_basic() {
9881038
9891039 // Validate that the file contains the expected bytes.
9901040 const EXPECTED : & str = "zlib string larger than the buffer size" ;
991- let mut mode = 0 ;
992- #[ cfg( target_os = "windows" ) ]
993- {
994- mode |= libc:: O_BINARY ;
995- }
996- mode |= libc:: O_RDONLY ;
1041+ let mode = binary_mode ( libc:: O_RDONLY ) ;
9971042 let fd = unsafe { libc:: open ( CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) , mode) } ;
9981043 assert_ne ! ( fd, -1 ) ;
9991044 // Try to read more than the expected amount of data, to ensure we get everything.
@@ -1446,12 +1491,7 @@ fn gzfwrite_basic() {
14461491 assert_eq ! ( unsafe { gzclose( file) } , Z_OK ) ;
14471492
14481493 // Read in the file and verify that the contents match what was passed to gzfwrite.
1449- let mut mode = 0 ;
1450- #[ cfg( target_os = "windows" ) ]
1451- {
1452- mode |= libc:: O_BINARY ;
1453- }
1454- mode |= libc:: O_RDONLY ;
1494+ let mode = binary_mode ( libc:: O_RDONLY ) ;
14551495 let fd = unsafe { libc:: open ( CString :: new ( file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) , mode) } ;
14561496 assert_ne ! ( fd, -1 ) ;
14571497 const EXPECTED : & [ u8 ] = b"test of gzfwrite" ;
@@ -1642,16 +1682,10 @@ fn gzseek_read() {
16421682 // all the implementation paths for gzseek.
16431683 let gzip_file_name = crate_path ( "src/test-data/issue-109.gz" ) ;
16441684 let direct_file_name = path ( temp_path, "uncompressed" ) ;
1645- let mut mode = libc:: O_CREAT ;
1646- #[ cfg( target_os = "windows" ) ]
1647- {
1648- mode |= libc:: O_BINARY ;
1649- }
1650- mode |= libc:: O_WRONLY ;
16511685 let fd = unsafe {
16521686 libc:: open (
16531687 CString :: new ( direct_file_name. as_str ( ) ) . unwrap ( ) . as_ptr ( ) ,
1654- mode ,
1688+ binary_mode ( libc :: O_CREAT | libc :: O_WRONLY ) ,
16551689 0o644 ,
16561690 )
16571691 } ;
@@ -1883,7 +1917,10 @@ fn gzseek_gzsetparams() {
18831917
18841918 // Write some content to the file handle.
18851919 const STRING1 : & [ u8 ] = b"hello" ;
1886- assert_eq ! ( unsafe { gzwrite( file, STRING1 . as_ptr( ) . cast:: <c_void>( ) , STRING1 . len( ) as _) } , STRING1 . len( ) as _) ;
1920+ assert_eq ! (
1921+ unsafe { gzwrite( file, STRING1 . as_ptr( ) . cast:: <c_void>( ) , STRING1 . len( ) as _) } ,
1922+ STRING1 . len( ) as _
1923+ ) ;
18871924
18881925 // Call gzseek to schedule a pending write of some zeros to the compressed stream.
18891926 const SEEK_AMOUNT : usize = 4 ;
@@ -1897,7 +1934,10 @@ fn gzseek_gzsetparams() {
18971934 // Write some more content to the file handle. This will end up in the second gzip stream
18981935 // in the file.
18991936 const STRING2 : & [ u8 ] = b"world" ;
1900- assert_eq ! ( unsafe { gzwrite( file, STRING2 . as_ptr( ) . cast:: <c_void>( ) , STRING2 . len( ) as _) } , STRING2 . len( ) as _) ;
1937+ assert_eq ! (
1938+ unsafe { gzwrite( file, STRING2 . as_ptr( ) . cast:: <c_void>( ) , STRING2 . len( ) as _) } ,
1939+ STRING2 . len( ) as _
1940+ ) ;
19011941
19021942 // Close the file handle to flush any buffered output to the file.
19031943 assert_eq ! ( unsafe { gzclose( file) } , Z_OK ) ;
@@ -1913,13 +1953,19 @@ fn gzseek_gzsetparams() {
19131953
19141954 // Read back the content to validate that it was written correctly.
19151955 let mut buf = [ 127u8 ; STRING1 . len ( ) ] ;
1916- assert_eq ! ( unsafe { gzread( file, buf. as_mut_ptr( ) . cast:: <c_void>( ) , buf. len( ) as _) } , buf. len( ) as _) ;
1956+ assert_eq ! (
1957+ unsafe { gzread( file, buf. as_mut_ptr( ) . cast:: <c_void>( ) , buf. len( ) as _) } ,
1958+ buf. len( ) as _
1959+ ) ;
19171960 assert_eq ! ( & buf, STRING1 ) ;
19181961 for _ in 0 ..SEEK_AMOUNT {
19191962 assert_eq ! ( unsafe { gzgetc( file) } , 0 ) ;
19201963 }
19211964 let mut buf = [ 127u8 ; STRING2 . len ( ) + 1 ] ;
1922- assert_eq ! ( unsafe { gzread( file, buf. as_mut_ptr( ) . cast:: <c_void>( ) , buf. len( ) as _) } , ( buf. len( ) - 1 ) as _) ;
1965+ assert_eq ! (
1966+ unsafe { gzread( file, buf. as_mut_ptr( ) . cast:: <c_void>( ) , buf. len( ) as _) } ,
1967+ ( buf. len( ) - 1 ) as _
1968+ ) ;
19231969 assert_eq ! ( & buf[ ..STRING2 . len( ) ] , STRING2 ) ;
19241970
19251971 assert_eq ! ( unsafe { gzclose( file) } , Z_OK ) ;
0 commit comments