@@ -21,7 +21,9 @@ use std::io::{BufRead, BufReader, BufWriter, ErrorKind, Read, Seek, SeekFrom, Wr
2121use std:: path:: Path ;
2222use thiserror:: Error ;
2323use uucore:: display:: Quotable ;
24- use uucore:: error:: { FromIo , UIoError , UResult , USimpleError , UUsageError } ;
24+ use uucore:: error:: {
25+ FromIo , UIoError , UResult , USimpleError , UUsageError , set_exit_code, strip_errno,
26+ } ;
2527use uucore:: translate;
2628
2729use uucore:: parser:: parse_size:: parse_size_u64;
@@ -565,11 +567,48 @@ fn ignorable_io_error(error: &io::Error, settings: &Settings) -> bool {
565567/// If ignorable io error occurs, return number of bytes as if all bytes written
566568/// Should not be used for Kth chunk number sub-strategies
567569/// as those do not work with `--filter` option
568- fn custom_write < T : Write > ( bytes : & [ u8 ] , writer : & mut T , settings : & Settings ) -> io:: Result < usize > {
570+ ///
571+ /// When `error_context` is None, acts as simple write wrapper
572+ /// When `error_context` is Some((filename, error_reported)), enables error reporting and immediate flushing
573+ fn custom_write < T : Write > (
574+ bytes : & [ u8 ] ,
575+ writer : & mut T ,
576+ settings : & Settings ,
577+ error_context : Option < ( & str , & mut bool ) > ,
578+ ) -> io:: Result < usize > {
569579 match writer. write ( bytes) {
570- Ok ( n) => Ok ( n) ,
580+ Ok ( n) => {
581+ // If error reporting is enabled, flush immediately to catch buffered I/O errors
582+ if let Some ( ( filename, error_reported) ) = error_context {
583+ match writer. flush ( ) {
584+ Ok ( ( ) ) => Ok ( n) ,
585+ Err ( e) if ignorable_io_error ( & e, settings) => Ok ( bytes. len ( ) ) ,
586+ Err ( e) => {
587+ if !* error_reported {
588+ uucore:: show_error!( "{}: {}" , filename, strip_errno( & e) ) ;
589+ set_exit_code ( 1 ) ;
590+ * error_reported = true ;
591+ }
592+ Err ( io:: Error :: other ( "" ) )
593+ }
594+ }
595+ } else {
596+ Ok ( n)
597+ }
598+ }
571599 Err ( e) if ignorable_io_error ( & e, settings) => Ok ( bytes. len ( ) ) ,
572- Err ( e) => Err ( e) ,
600+ Err ( e) => {
601+ if let Some ( ( filename, error_reported) ) = error_context {
602+ if !* error_reported {
603+ uucore:: show_error!( "{}: {}" , filename, strip_errno( & e) ) ;
604+ set_exit_code ( 1 ) ;
605+ * error_reported = true ;
606+ }
607+ Err ( io:: Error :: other ( "" ) )
608+ } else {
609+ Err ( e)
610+ }
611+ }
573612 }
574613}
575614
@@ -713,6 +752,12 @@ struct ByteChunkWriter<'a> {
713752
714753 /// Iterator that yields filenames for each chunk.
715754 filename_iterator : FilenameIterator < ' a > ,
755+
756+ /// Current filename being written to.
757+ current_filename : String ,
758+
759+ /// Whether an error has already been reported for the current file.
760+ error_reported : bool ,
716761}
717762
718763impl < ' a > ByteChunkWriter < ' a > {
@@ -732,10 +777,28 @@ impl<'a> ByteChunkWriter<'a> {
732777 num_chunks_written : 0 ,
733778 inner,
734779 filename_iterator,
780+ current_filename : filename,
781+ error_reported : false ,
735782 } )
736783 }
737784}
738785
786+ impl Drop for ByteChunkWriter < ' _ > {
787+ fn drop ( & mut self ) {
788+ // Ensure final flush to catch any buffered write errors, but only report if not already reported
789+ if !self . error_reported {
790+ if let Err ( e) = self . inner . flush ( ) {
791+ uucore:: show_error!(
792+ "split: {}: final flush failed: {}" ,
793+ self . current_filename,
794+ strip_errno( & e)
795+ ) ;
796+ set_exit_code ( 1 ) ;
797+ }
798+ }
799+ }
800+ }
801+
739802impl Write for ByteChunkWriter < ' _ > {
740803 /// Implements `--bytes=SIZE`
741804 fn write ( & mut self , mut buf : & [ u8 ] ) -> io:: Result < usize > {
@@ -751,6 +814,13 @@ impl Write for ByteChunkWriter<'_> {
751814 }
752815
753816 if self . num_bytes_remaining_in_current_chunk == 0 {
817+ // Flush the current writer before switching to a new file to catch any delayed write errors
818+ if let Err ( e) = self . inner . flush ( ) {
819+ uucore:: show_error!( "{}: {}" , self . current_filename, strip_errno( & e) ) ;
820+ set_exit_code ( 1 ) ;
821+ return Err ( io:: Error :: other ( "" ) ) ;
822+ }
823+
754824 // Increment the chunk number, reset the number of bytes remaining, and instantiate the new underlying writer.
755825 self . num_chunks_written += 1 ;
756826 self . num_bytes_remaining_in_current_chunk = self . chunk_size ;
@@ -763,6 +833,8 @@ impl Write for ByteChunkWriter<'_> {
763833 println ! ( "creating file {}" , filename. quote( ) ) ;
764834 }
765835 self . inner = self . settings . instantiate_current_writer ( & filename, true ) ?;
836+ self . current_filename = filename;
837+ self . error_reported = false ;
766838 }
767839
768840 // If the capacity of this chunk is greater than the number of
@@ -771,7 +843,12 @@ impl Write for ByteChunkWriter<'_> {
771843 // the chunk number and repeat.
772844 let buf_len = buf. len ( ) ;
773845 if ( buf_len as u64 ) < self . num_bytes_remaining_in_current_chunk {
774- let num_bytes_written = custom_write ( buf, & mut self . inner , self . settings ) ?;
846+ let num_bytes_written = custom_write (
847+ buf,
848+ & mut self . inner ,
849+ self . settings ,
850+ Some ( ( & self . current_filename , & mut self . error_reported ) ) ,
851+ ) ?;
775852 self . num_bytes_remaining_in_current_chunk -= num_bytes_written as u64 ;
776853 return Ok ( carryover_bytes_written + num_bytes_written) ;
777854 }
@@ -782,7 +859,12 @@ impl Write for ByteChunkWriter<'_> {
782859 // self.num_bytes_remaining_in_current_chunk is lower than
783860 // n, which is already usize.
784861 let i = self . num_bytes_remaining_in_current_chunk as usize ;
785- let num_bytes_written = custom_write ( & buf[ ..i] , & mut self . inner , self . settings ) ?;
862+ let num_bytes_written = custom_write (
863+ & buf[ ..i] ,
864+ & mut self . inner ,
865+ self . settings ,
866+ Some ( ( & self . current_filename , & mut self . error_reported ) ) ,
867+ ) ?;
786868 self . num_bytes_remaining_in_current_chunk -= num_bytes_written as u64 ;
787869
788870 // It's possible that the underlying writer did not
@@ -799,7 +881,14 @@ impl Write for ByteChunkWriter<'_> {
799881 }
800882 }
801883 fn flush ( & mut self ) -> io:: Result < ( ) > {
802- self . inner . flush ( )
884+ match self . inner . flush ( ) {
885+ Ok ( ( ) ) => Ok ( ( ) ) ,
886+ Err ( e) => {
887+ uucore:: show_error!( "{}: {}" , self . current_filename, strip_errno( & e) ) ;
888+ set_exit_code ( 1 ) ;
889+ Err ( io:: Error :: other ( "" ) )
890+ }
891+ }
803892 }
804893}
805894
@@ -891,7 +980,8 @@ impl Write for LineChunkWriter<'_> {
891980 // Write the line, starting from *after* the previous
892981 // separator character and ending *after* the current
893982 // separator character.
894- let num_bytes_written = custom_write ( & buf[ prev..=i] , & mut self . inner , self . settings ) ?;
983+ let num_bytes_written =
984+ custom_write ( & buf[ prev..=i] , & mut self . inner , self . settings , None ) ?;
895985 total_bytes_written += num_bytes_written;
896986 prev = i + 1 ;
897987 self . num_lines_remaining_in_current_chunk -= 1 ;
@@ -907,7 +997,7 @@ impl Write for LineChunkWriter<'_> {
907997 self . num_lines_remaining_in_current_chunk = self . chunk_size ;
908998 }
909999 let num_bytes_written =
910- custom_write ( & buf[ prev..buf. len ( ) ] , & mut self . inner , self . settings ) ?;
1000+ custom_write ( & buf[ prev..buf. len ( ) ] , & mut self . inner , self . settings , None ) ?;
9111001 total_bytes_written += num_bytes_written;
9121002 }
9131003 Ok ( total_bytes_written)
@@ -1606,7 +1696,15 @@ fn split(settings: &Settings) -> UResult<()> {
16061696 // allowable filenames, we use `ErrorKind::Other` to
16071697 // indicate that. A special error message needs to be
16081698 // printed in that case.
1609- ErrorKind :: Other => Err ( USimpleError :: new ( 1 , format ! ( "{e}" ) ) ) ,
1699+ ErrorKind :: Other => {
1700+ let error_msg = format ! ( "{e}" ) ;
1701+ if error_msg. is_empty ( ) {
1702+ // This is a handled error, return error to stop processing
1703+ Err ( USimpleError :: new ( 1 , "" ) )
1704+ } else {
1705+ Err ( USimpleError :: new ( 1 , error_msg) )
1706+ }
1707+ }
16101708 _ => Err ( uio_error ! (
16111709 e,
16121710 "{}" ,
0 commit comments