@@ -19,10 +19,10 @@ use std::sync::Arc;
1919use std:: { io, path} ;
2020
2121use bytes:: Bytes ;
22- use tracing:: { instrument, trace, warn} ;
22+ use tracing:: { error , instrument, trace, warn} ;
2323use url:: Url ;
2424
25- use super :: { Error , ListDir , Metadata , Result } ;
25+ use super :: { Error , ListDir , Metadata , Result , WriteMode } ;
2626
2727pub ( super ) struct Protocol {
2828 path : PathBuf ,
@@ -68,28 +68,31 @@ impl super::Protocol for Protocol {
6868 }
6969
7070 #[ instrument( skip( self , content) ) ]
71- fn write_file ( & self , relpath : & str , content : & [ u8 ] ) -> Result < ( ) > {
71+ fn write_file ( & self , relpath : & str , content : & [ u8 ] , write_mode : WriteMode ) -> Result < ( ) > {
7272 // TODO: Just write directly; remove if the write fails.
7373 let full_path = self . full_path ( relpath) ;
74- let dir = full_path . parent ( ) . unwrap ( ) ;
75- let context = |err| super :: Error :: io_error ( & full_path , err ) ;
76- let mut temp = tempfile :: Builder :: new ( )
77- . prefix ( crate :: TMP_PREFIX )
78- . tempfile_in ( dir )
79- . map_err ( context ) ? ;
80- if let Err ( err ) = temp . write_all ( content ) {
81- let _ = temp . close ( ) ;
82- warn ! ( "Failed to write {:?}: {:?}" , relpath , err ) ;
83- return Err ( context ( err ) ) ;
74+ let oops = |err| super :: Error :: io_error ( & full_path , err ) ;
75+ let mut options = File :: options ( ) ;
76+ options . write ( true ) ;
77+ match write_mode {
78+ WriteMode :: CreateNew => {
79+ options . create_new ( true ) ;
80+ }
81+ WriteMode :: Overwrite => {
82+ options . create ( true ) . truncate ( true ) ;
83+ }
8484 }
85- if let Err ( persist_error) = temp. persist ( & full_path) {
86- warn ! ( "Failed to persist {:?}: {:?}" , full_path, persist_error) ;
87- persist_error. file . close ( ) . map_err ( context) ?;
88- Err ( context ( persist_error. error ) )
89- } else {
90- trace ! ( "Wrote {} bytes" , content. len( ) ) ;
91- Ok ( ( ) )
85+ let mut file = options. open ( & full_path) . map_err ( oops) ?;
86+ if let Err ( err) = file. write_all ( content) {
87+ error ! ( "Failed to write {full_path:?}: {err:?}" ) ;
88+ drop ( file) ;
89+ if let Err ( err2) = remove_file ( & full_path) {
90+ error ! ( "Failed to remove {full_path:?}: {err2:?}" ) ;
91+ }
92+ return Err ( oops ( err) ) ;
9293 }
94+ trace ! ( "Wrote {} bytes" , content. len( ) ) ;
95+ Ok ( ( ) )
9396 }
9497
9598 fn list_dir ( & self , relpath : & str ) -> Result < ListDir > {
@@ -257,7 +260,11 @@ mod test {
257260
258261 transport. create_dir ( "subdir" ) . unwrap ( ) ;
259262 transport
260- . write_file ( "subdir/subfile" , b"Must I paint you a picture?" )
263+ . write_file (
264+ "subdir/subfile" ,
265+ b"Must I paint you a picture?" ,
266+ WriteMode :: CreateNew ,
267+ )
261268 . unwrap ( ) ;
262269
263270 temp. child ( "subdir" ) . assert ( predicate:: path:: is_dir ( ) ) ;
@@ -291,10 +298,10 @@ mod test {
291298 let transport = Transport :: local ( temp. path ( ) ) ;
292299 let filename = "filename" ;
293300 transport
294- . write_file ( filename, b"original content" )
301+ . write_file ( filename, b"original content" , WriteMode :: Overwrite )
295302 . expect ( "first write succeeds" ) ;
296303 transport
297- . write_file ( filename, b"new content" )
304+ . write_file ( filename, b"new content" , WriteMode :: Overwrite )
298305 . expect ( "write over existing file succeeds" ) ;
299306 assert_eq ! (
300307 transport. read_file( filename) . unwrap( ) . as_ref( ) ,
0 commit comments