2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								# include  <map> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "file.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "logger.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# include  "config.h" 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# ifndef WIN32 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # include  <stdio.h> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# endif 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								using  namespace  std ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-12-07 22:27:20 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								# ifndef WIN32 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # define EXPERIMENTAL_FS 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# endif 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								# ifdef EXPERIMENTAL_FS 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # include  <experimental/filesystem> 
 
							 
						 
					
						
							
								
									
										
										
										
											2019-12-07 22:27:20 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    # include  <iostream> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    namespace  fs  =  std : : experimental : : filesystem ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								# else 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    # include  <filesystem> 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    namespace  fs  =  std : : filesystem ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# endif 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								using  namespace  log_helper ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								std : : map < std : : string ,  std : : string >  move_back ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								std : : map < std : : string ,  std : : string >  backup_mapping ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								bool  rename_or_move ( const  fs : : path &  source ,  const  fs : : path &  target ,  std : : string &  error )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										fs : : rename ( source ,  target ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									}  catch ( const  fs : : filesystem_error &  ex )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# ifndef WIN32 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										if ( ex . code ( )  = =  errc : : cross_device_link )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											/* try with move command */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											char  buffer [ 2048 ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											auto  length  =  snprintf ( buffer ,  2048 ,  R " (%s  " % s "   " % s " ) " ,  " mv " ,  source . c_str ( ) ,  target . c_str ( ) ) ;  /* build the move command */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if ( length  <  1  | |  length  > =  2049 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												error  =  " failed to prepare move command! " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											auto  code  =  system ( buffer ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											if ( code  ! =  0 )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												error  =  " move command resulted in  "  +  to_string ( code ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
												return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
											return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# endif 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										error  =  " rename returned error code  "  +  to_string ( ex . code ( ) . value ( ) )  +  "  ( "  +  ex . code ( ) . message ( )  +  " ) " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								bool  file : : move ( std : : string  & error ,  const  std : : string  & source ,  const  std : : string  & target )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    auto  source_path  =  fs : : u8path ( source ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if ( ! fs : : exists ( source_path ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        error  =  " source file does not exists " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    source_path  =  fs : : absolute ( source_path ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if ( target . empty ( )  | |  target  = =  " /dev/null " )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        /* delete the file or directory */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        logger : : debug ( " Deleting file  "  +  argument_t < fs : : path : : value_type > : : value ,  source_path . c_str ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if ( config : : backup )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            auto  backup_target  =  file : : register_backup ( source_path . string ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            if ( backup_target . empty ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                drop_backup ( backup_target ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                error  =  " failed to register backup " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            if ( ! rename_or_move ( source_path ,  fs : : u8path ( backup_target ) ,  error ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									            drop_backup ( backup_target ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									            error  =  " failed to move file to backup target ( "  +  error  +  " ) " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            if ( fs : : is_directory ( source_path ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    if ( ! fs : : remove_all ( source_path ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                        throw  fs : : filesystem_error ( " invalid result " ,  error_code ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                }  catch ( const  fs : : filesystem_error &  ex )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    error  =  " failed to delete directory ( "  +  string ( ex . what ( ) )  +  " ) " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    if ( ! fs : : remove ( source_path ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                        throw  fs : : filesystem_error ( " invalid result " ,  error_code ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                }  catch ( const  fs : : filesystem_error &  ex )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    error  =  " failed to delete file ( "  +  string ( ex . what ( ) )  +  " ) " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    auto  target_path  =  fs : : u8path ( target ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    target_path  =  fs : : absolute ( target_path ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if ( ! fs : : is_directory ( target_path . parent_path ( ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if ( ! fs : : exists ( target_path . parent_path ( ) ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                fs : : create_directories ( target_path . parent_path ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            }  catch ( const  fs : : filesystem_error &  ex )  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								                error  =  " failed to create target directories ( "  +  std : : string { ex . what ( ) }  +  " ) " ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								                return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            error  =  " target isn't a directory! " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    logger : : debug ( " Moving file  "  +  argument_t < fs : : path : : value_type > : : value  +  "  to  "  +  argument_t < fs : : path : : value_type > : : value ,  source_path . c_str ( ) ,  target_path . c_str ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if ( fs : : exists ( target_path ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        logger : : debug ( " Target file already exists. Deleting it " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if ( config : : backup )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            auto  path  =  file : : register_backup ( target_path . string ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            if ( path . empty ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                drop_backup ( path ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                error  =  " failed to create backup path " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									        if ( ! rename_or_move ( target_path ,  fs : : u8path ( path ) ,  error ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										        drop_backup ( path ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										        error  =  " failed to delete old target file ( "  +  error  +  " ) " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										        return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        }  else  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                if ( fs : : is_directory ( target_path ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    fs : : remove_all ( target_path ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    fs : : remove ( target_path ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            }   catch ( const  fs : : filesystem_error &  ex )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                error  =  " failed to delete old target file:  "  +  string ( ex . what ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    move_back [ target_path . string ( ) ]  =  source_path . string ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									if ( ! rename_or_move ( source_path ,  target_path ,  error ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										error  =  " failed to move file ( "  +  error  +  " ) " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
										return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
									} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								string  random_string ( size_t  length )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    static  const  char  alphanum [ ]  = 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            " 0123456789 " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            " ABCDEFGHIJKLMNOPQRSTUVWXYZ " 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            " abcdefghijklmnopqrstuvwxyz " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    string  result ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    result . resize ( length ,  ' \0 ' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for ( char &  c  :  result ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        c  =  alphanum [ rand ( )  %  ( sizeof ( alphanum )  -  1 ) ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  result ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								std : : string  file : : register_backup ( const  std : : string  & source )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        auto  path  =  fs : : u8path ( config : : backup_directory ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if ( ! fs : : exists ( path ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                fs : : create_directories ( path ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } catch ( const  fs : : filesystem_error &  ex )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                logger : : error ( " Failed to create backup directory  \" "  +  argument_t < fs : : path : : value_type > : : value  +  " \" : %s " ,  path . c_str ( ) ,  ex . what ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                return  " " ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    std : : string  key ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    while ( backup_mapping . count ( ( key  =  random_string ( 20 ) ) )  >  0 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    backup_mapping [ key ]  =  source ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  fs : : absolute ( fs : : u8path ( config : : backup_directory )  /  key ) . string ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								void  file : : drop_backup ( const  std : : string  & source )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    for ( const  auto &  entry  :  backup_mapping )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if ( entry . second  = =  source )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            backup_mapping . erase ( entry . first ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								void  file : : rollback ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if ( ! config : : backup ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    logger : : info ( " Rollbacking %d moved files " ,  move_back . size ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    for ( const  auto &  [ backup ,  original ]  :  move_back )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        logger : : debug ( " Attempting to moveback %s to %s " ,  backup . c_str ( ) ,  original . c_str ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								        try  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								            fs : : rename ( fs : : u8path ( backup ) ,  fs : : u8path ( original ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								        }  catch ( const  fs : : filesystem_error &  ex )  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								            logger : : warn ( " Failed to moveback file from %s to %s (%s) " ,  backup . c_str ( ) ,  original . c_str ( ) ,  ex . what ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								            continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        logger : : debug ( " => success " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    logger : : info ( " Rollbacking %d deleted files " ,  backup_mapping . size ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								    for ( const  auto &  [ backup ,  original ]  :  backup_mapping )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        logger : : debug ( " Attempting to restore %s to %s " ,  backup . c_str ( ) ,  original . c_str ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								        try  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								            auto  source  =  fs : : absolute ( fs : : u8path ( config : : backup_directory )  /  backup ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								            if ( ! fs : : exists ( source ) )  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								                logger : : warn ( " Failed to restore file %s (Source file missing) " ,  original . c_str ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								                continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								            auto  target  =  fs : : u8path ( original ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								            fs : : rename ( source ,  target ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        }  catch ( const  fs : : filesystem_error &  ex )  { 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								            logger : : warn ( " Failed to restore file %s (%s) " ,  original . c_str ( ) ,  ex . what ( ) ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								            continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        logger : : debug ( " => success " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    logger : : info ( " Rollback done " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								void  file : : commit ( )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if ( ! config : : backup ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if ( ! fs : : remove_all ( config : : backup_directory ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            throw  fs : : filesystem_error ( " invalid result " ,  error_code ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    }  catch ( const  fs : : filesystem_error &  ex )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        logger : : warn ( " Failed to cleanup backup directory ( "  +  string { ex . what ( ) }  +  " ) " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    backup_mapping . clear ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								# ifdef WIN32 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    bool  file : : file_locked ( const  std : : string  & file )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        auto  file_handle  =  CreateFile ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                ( LPCSTR )  file . c_str ( ) ,  /* file name*/ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                ( DWORD )  GENERIC_WRITE , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                ( DWORD )  0 ,  /* we dont want to share */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                ( LPSECURITY_ATTRIBUTES )  nullptr , 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								                ( DWORD )  OPEN_EXISTING ,  /* file should be available */ 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								                FILE_ATTRIBUTE_NORMAL , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                nullptr 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if ( file_handle  = =  INVALID_HANDLE_VALUE )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            if ( GetLastError ( )  = =  ERROR_SHARING_VIOLATION ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                return  true ;  /* file is beeing used */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            wchar_t  buf [ 256 ] ; 
							 
						 
					
						
							
								
									
										
										
										
											2019-10-27 21:50:25 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								            FormatMessageW ( FORMAT_MESSAGE_FROM_SYSTEM  |  FORMAT_MESSAGE_IGNORE_INSERTS ,  nullptr ,  GetLastError ( ) ,  MAKELANGID ( LANG_NEUTRAL ,  SUBLANG_DEFAULT ) ,  buf ,  ( sizeof ( buf )  /  sizeof ( wchar_t ) ) ,  nullptr ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            buf [ 255 ]  =  L ' \0 ' ;  /* even if FormatMessageW fails we've a 0 terminator */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            auto  r  =  wcschr ( buf ,  L ' \r ' ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            if ( r )  * r  =  L ' \0 ' ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            
							 
						 
					
						
							
								
									
										
										
										
											2019-10-26 01:51:40 +02:00 
										
									 
								 
							 
							
								
							 
							
								 
							 
							
							
								            logger : : info ( " Failed to open file! (%S) (%d) " ,  buf ,  GetLastError ( ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        CloseHandle ( file_handle ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# else 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    bool  file : : file_locked ( const  std : : string  & file )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        auto  handle  =  fopen ( file . c_str ( ) ,  " a+ " ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if ( handle )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            fclose ( handle ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        return  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2020-12-02 18:08:49 +01:00 
										
									 
								 
							 
							
								
									
										 
									 
								
							 
							
								 
							 
							
							
								# endif 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# ifdef WIN32 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								bool  CanAccessFolder ( LPCTSTR  folderName ,  DWORD  genericAccessRights ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								{ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    bool  bRet  =  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    DWORD  length  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    if  ( ! : : GetFileSecurity ( folderName ,  OWNER_SECURITY_INFORMATION  |  GROUP_SECURITY_INFORMATION  |  DACL_SECURITY_INFORMATION ,  nullptr ,  0 ,  & length )  & &  ERROR_INSUFFICIENT_BUFFER  = =  : : GetLastError ( ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        auto  security  =  static_cast < PSECURITY_DESCRIPTOR > ( : : malloc ( length ) ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        if  ( security  & &  : : GetFileSecurity ( folderName ,  OWNER_SECURITY_INFORMATION  |  GROUP_SECURITY_INFORMATION  |  DACL_SECURITY_INFORMATION ,  security ,  length ,  & length  ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            HANDLE  hToken  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            if  ( : : OpenProcessToken (  : : GetCurrentProcess ( ) ,  TOKEN_IMPERSONATE  |  TOKEN_QUERY  | 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                                                           TOKEN_DUPLICATE  |  STANDARD_RIGHTS_READ ,  & hToken  ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                HANDLE  hImpersonatedToken  =  NULL ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                if  ( : : DuplicateToken (  hToken ,  SecurityImpersonation ,  & hImpersonatedToken  ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    GENERIC_MAPPING  mapping  =  {  0xFFFFFFFF  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    PRIVILEGE_SET  privileges  =  {  0  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    DWORD  grantedAccess  =  0 ,  privilegesLength  =  sizeof (  privileges  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    BOOL  result  =  FALSE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    mapping . GenericRead  =  FILE_GENERIC_READ ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    mapping . GenericWrite  =  FILE_GENERIC_WRITE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    mapping . GenericExecute  =  FILE_GENERIC_EXECUTE ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    mapping . GenericAll  =  FILE_ALL_ACCESS ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    : : MapGenericMask (  & genericAccessRights ,  & mapping  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    if  ( : : AccessCheck (  security ,  hImpersonatedToken ,  genericAccessRights , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                                       & mapping ,  & privileges ,  & privilegesLength ,  & grantedAccess ,  & result  ) )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                        bRet  =  ( result  = =  TRUE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                    : : CloseHandle (  hImpersonatedToken  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								                : : CloseHandle (  hToken  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								            : : free (  security  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  bRet ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								} 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# endif 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								bool  file : : directory_writeable ( const  std : : string  & path )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# ifdef WIN32 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  CanAccessFolder ( path . c_str ( ) ,  GENERIC_WRITE ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# else 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    /* TODO: Check for file permissions? Is this method even needed? */ 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								    return  false ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								# endif 
 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							 
							
							
								}