@@ -40,10 +40,18 @@ where
4040 fn non_host_specific ( self , hostname_sep : & str ) -> Self {
4141 unimplemented ! ( )
4242 }
43+ /// Gets the nearest existing parent component of `self`.
44+ fn nearest_existing_parent ( & self ) -> Self {
45+ unimplemented ! ( )
46+ }
4347 /// Checks whether any of the component above `self` is readonly.
4448 fn is_parent_readonly ( & self ) -> bool {
4549 unimplemented ! ( )
4650 }
51+ /// Checks whether any component of `self`'s parent is not a directory.
52+ fn has_file_as_parent ( & self ) -> bool {
53+ unimplemented ! ( )
54+ }
4755 /// Checks whether any of the component refernces its parent.
4856 fn is_twisted ( & self ) -> bool {
4957 unimplemented ! ( )
@@ -232,22 +240,32 @@ impl Operate for PathBuf {
232240 . collect :: < PathBuf > ( )
233241 }
234242
235- /// Checks whether any of the component above `self` is readonly .
236- fn is_parent_readonly ( & self ) -> bool {
243+ /// Gets the nearest existing parent component of `self`.
244+ fn nearest_existing_parent ( & self ) -> Self {
237245 let mut p: & Path = self . as_ref ( ) ;
238- let first_existing_parent = loop {
246+ let p = loop {
239247 if p. exists ( ) {
240248 break p;
241249 }
242250 p = p. parent ( ) . unwrap ( ) ;
243251 } ;
244- first_existing_parent
252+ p. into ( )
253+ }
254+
255+ /// Checks whether any of the component above `self` is readonly.
256+ fn is_parent_readonly ( & self ) -> bool {
257+ self . nearest_existing_parent ( )
245258 . metadata ( )
246259 . unwrap ( )
247260 . permissions ( )
248261 . readonly ( )
249262 }
250263
264+ /// Checks whether any component of `self`'s parent is not a directory.
265+ fn has_file_as_parent ( & self ) -> bool {
266+ self . nearest_existing_parent ( ) . metadata ( ) . unwrap ( ) . is_file ( )
267+ }
268+
251269 /// Checks whether any of the component refernces its parent.
252270 fn is_twisted ( & self ) -> bool {
253271 self . iter ( ) . any ( |comp| comp == ".." )
@@ -460,7 +478,14 @@ impl Operate for PathBuf {
460478 & group. target ,
461479 group. get_renaming_rules ( ) ,
462480 ) ?;
463- std:: fs:: create_dir_all ( tpath. parent ( ) . unwrap ( ) ) ?;
481+ let tparent = tpath. parent ( ) . unwrap ( ) . to_owned ( ) ;
482+ if tparent. has_file_as_parent ( ) {
483+ return Err ( AppError :: PathError ( format ! (
484+ "target path's parent '{}' contains one or more file components thus can not be created as a directory" ,
485+ tparent. display( )
486+ ) ) ) ;
487+ }
488+ std:: fs:: create_dir_all ( tparent) ?;
464489 if group. target . canonicalize ( ) ? == group. base . canonicalize ( ) ? {
465490 return Err ( AppError :: PathError ( format ! (
466491 "base directory and its target point to the same path in group '{}'" ,
@@ -580,7 +605,14 @@ impl Operate for PathBuf {
580605 & group. get_staging_dir ( ) ,
581606 Vec :: new ( ) , // Do not apply renaming on staging path
582607 ) ?;
583- std:: fs:: create_dir_all ( staging_path. parent ( ) . unwrap ( ) ) ?;
608+ let sparent = staging_path. parent ( ) . unwrap ( ) . to_owned ( ) ;
609+ if sparent. has_file_as_parent ( ) {
610+ return Err ( AppError :: PathError ( format ! (
611+ "staging path's parent '{}' contains one or more file component thus can not be created as a directory" ,
612+ sparent. display( )
613+ ) ) ) ;
614+ }
615+ std:: fs:: create_dir_all ( sparent) ?;
584616 if group. global . staging . 0 . canonicalize ( ) ?
585617 == group. base . canonicalize ( ) ?
586618 {
0 commit comments