@@ -25,6 +25,41 @@ use crate::matrix::verification::handle_verification_request;
2525/// https://url.spec.whatwg.org/#fragment-percent-encode-set
2626const FRAGMENT : & AsciiSet = & CONTROLS . add ( b' ' ) . add ( b'"' ) . add ( b'<' ) . add ( b'>' ) . add ( b'`' ) ;
2727
28+ async fn generate_fresh_file ( dir : PathBuf , filename : & str ) -> Result < ( tokio:: fs:: File , String ) > {
29+ let fresh_filepath = tokio:: task:: spawn_blocking ( {
30+ let filename = String :: from ( filename) ;
31+ move || -> Result < PathBuf > {
32+ let firstdotidx = filename. find ( '.' ) ;
33+ let ( prefix, suffix) = match firstdotidx {
34+ Some ( idx) => filename. split_at ( idx) ,
35+ None => ( filename. as_str ( ) , "" ) ,
36+ } ;
37+ let ( _, tmpfile) = tempfile:: Builder :: new ( )
38+ . prefix ( & ( prefix. to_owned ( ) + "-" ) )
39+ . suffix ( & suffix)
40+ . tempfile_in ( dir) ?
41+ . keep ( ) ?;
42+ Ok ( tmpfile)
43+ }
44+ } )
45+ . await ??;
46+ let fresh_filename = fresh_filepath
47+ . file_name ( )
48+ . context ( "Internal error: No filename component" ) ?
49+ . to_str ( )
50+ . context ( "Internal error: Non-utf8 filename" ) ?
51+ . to_owned ( ) ;
52+ Ok ( (
53+ fs:: OpenOptions :: new ( )
54+ . write ( true )
55+ . create ( true )
56+ . truncate ( true )
57+ . open ( fresh_filepath)
58+ . await ?,
59+ fresh_filename,
60+ ) )
61+ }
62+
2863#[ async_trait]
2964pub trait SourceUri {
3065 async fn to_uri ( & self , client : & Client , body : & str ) -> Result < String > ;
@@ -54,12 +89,28 @@ impl SourceUri for MediaSource {
5489 . await ?
5590 }
5691 let file = dir. join ( filename) ;
57- fs:: File :: create ( file) . await ?. write_all ( & content) . await ?;
92+ let plainfh = fs:: OpenOptions :: new ( )
93+ . write ( true )
94+ . create_new ( true )
95+ . open ( file)
96+ . await ;
97+ let outfiletuple = match plainfh {
98+ Ok ( fh) => Ok ( ( fh, filename. to_owned ( ) ) ) ,
99+ Err ( err) => {
100+ if err. kind ( ) == std:: io:: ErrorKind :: AlreadyExists {
101+ generate_fresh_file ( dir, filename) . await
102+ } else {
103+ Err ( anyhow:: Error :: from ( err) )
104+ }
105+ }
106+ } ;
107+ let ( mut fh, filename) = outfiletuple?;
108+ fh. write_all ( & content) . await ?;
58109 let url = args ( ) . media_url . as_ref ( ) . unwrap_or ( dir_path) ;
59110 Ok ( format ! (
60111 "{}/{}" ,
61112 url,
62- utf8_percent_encode( filename, FRAGMENT )
113+ utf8_percent_encode( & filename, FRAGMENT )
63114 ) )
64115 }
65116}
0 commit comments