@@ -264,7 +264,7 @@ private void DeleteFolder(string path)
264
264
{
265
265
if ( Directory . Exists ( path ) )
266
266
{
267
- Directory . Delete ( path , true ) ;
267
+ SaferFileUtils . DeleteDirectoryAndContents ( path , this ) ;
268
268
LogSuccess ( "Folder deleted at '{0}'." , path ) ;
269
269
}
270
270
else
@@ -285,7 +285,7 @@ private void DeleteFile(string path)
285
285
{
286
286
if ( File . Exists ( path ) )
287
287
{
288
- File . Delete ( path ) ;
288
+ SaferFileUtils . FileDelete ( path , this ) ;
289
289
LogSuccess ( "File deleted at '{0}'." , path ) ;
290
290
}
291
291
else
@@ -480,7 +480,7 @@ private void MigrateNewRelicXml()
480
480
session . Log ( "Attempting to move file from {0} to {1}." , sourcePath , destinationPath ) ;
481
481
try
482
482
{
483
- File . Copy ( sourcePath , destinationPath ) ;
483
+ SaferFileUtils . FileCopy ( sourcePath , destinationPath , this ) ;
484
484
session . Log ( "Moved file from {0} to {1}." , sourcePath , destinationPath ) ;
485
485
}
486
486
catch ( IOException )
@@ -543,7 +543,7 @@ private void MigrateCustomInstrumentation()
543
543
}
544
544
}
545
545
546
- private static void CopyFolderContents ( string source , string destination )
546
+ private void CopyFolderContents ( string source , string destination )
547
547
{
548
548
if ( source == null ) return ;
549
549
if ( destination == null ) return ;
@@ -561,7 +561,7 @@ private static void CopyFolderContents(string source, string destination)
561
561
// If the subfolder already exists don't try to copy.
562
562
if ( Directory . Exists ( destinationPath ) ) continue ;
563
563
564
- Directory . Move ( sourceDirectoryPath , destinationPath ) ;
564
+ SaferFileUtils . DirectoryMove ( sourceDirectoryPath , destinationPath , this ) ;
565
565
}
566
566
567
567
// Copy all the files in the root of the directory.
@@ -571,9 +571,156 @@ private static void CopyFolderContents(string source, string destination)
571
571
string fileName = Path . GetFileName ( sourceFilePath ) ;
572
572
string destinationPath = destination + fileName ;
573
573
574
- File . Copy ( sourceFilePath , destinationPath , true ) ;
575
- File . Delete ( sourceFilePath ) ;
574
+ SaferFileUtils . FileCopy ( sourceFilePath , destinationPath , true , this ) ;
575
+ SaferFileUtils . FileDelete ( sourceFilePath , this ) ;
576
576
}
577
577
}
578
578
}
579
+
580
+ /// <summary>
581
+ /// This class is wrapper around the standard File and Directory classes
582
+ /// that will check the file and directory structure for symlinks and junctions
583
+ /// before attempting to copy or delete the file or directory. This code uses
584
+ /// the presence of reparse points to approximate the usage of junctions or
585
+ /// symlinks. No agent file or directory is expected to have a reparse point
586
+ /// defined.
587
+ /// </summary>
588
+ internal static class SaferFileUtils
589
+ {
590
+ internal static void FileCopy ( string source , string destination , MySession logger )
591
+ {
592
+ if ( ! FileIsSafeToUse ( source , logger ) )
593
+ {
594
+ logger . Log ( "{0} was not copied." , source ) ;
595
+ return ;
596
+ }
597
+
598
+ File . Copy ( source , destination ) ;
599
+ }
600
+
601
+ internal static void FileCopy ( string source , string destination , bool overwrite , MySession logger )
602
+ {
603
+ if ( ! FileIsSafeToUse ( source , logger ) )
604
+ {
605
+ logger . Log ( "{0} was not copied." , source ) ;
606
+ return ;
607
+ }
608
+
609
+ File . Copy ( source , destination , overwrite ) ;
610
+ }
611
+
612
+ internal static void FileDelete ( string fileNameAndPath , MySession logger )
613
+ {
614
+ if ( ! FileIsSafeToUse ( fileNameAndPath , logger ) )
615
+ {
616
+ logger . Log ( "{0} was not deleted." , fileNameAndPath ) ;
617
+ return ;
618
+ }
619
+
620
+ File . Delete ( fileNameAndPath ) ;
621
+ }
622
+
623
+ internal static void DeleteDirectoryAndContents ( string path , MySession logger )
624
+ {
625
+ if ( ! DirectoryIsSafeToUse ( path , logger ) )
626
+ {
627
+ logger . Log ( "{0} was not deleted." , path ) ;
628
+ return ;
629
+ }
630
+
631
+ Directory . Delete ( path , true ) ;
632
+ }
633
+
634
+ internal static void DirectoryMove ( string source , string destination , MySession logger )
635
+ {
636
+ if ( ! DirectoryIsSafeToUse ( source , logger ) )
637
+ {
638
+ logger . Log ( "{0} was not moved." , source ) ;
639
+ return ;
640
+ }
641
+
642
+ Directory . Move ( source , destination ) ;
643
+ }
644
+
645
+ private static bool FileIsSafeToUse ( string fileNameAndPath , MySession logger )
646
+ {
647
+ if ( ! File . Exists ( fileNameAndPath ) )
648
+ {
649
+ return false ;
650
+ }
651
+
652
+ var fileInfo = new FileInfo ( fileNameAndPath ) ;
653
+
654
+ if ( FileSystemReportsAReparsePoint ( fileInfo , logger ) )
655
+ {
656
+ return false ;
657
+ }
658
+
659
+ for ( var directory = fileInfo . Directory ; directory != null ; directory = directory . Parent )
660
+ {
661
+ if ( FileSystemReportsAReparsePoint ( directory , logger ) )
662
+ {
663
+ return false ;
664
+ }
665
+ }
666
+
667
+ return DirectoryAndParentsAreSafe ( fileInfo . Directory , logger ) ;
668
+ }
669
+
670
+ private static bool DirectoryIsSafeToUse ( string path , MySession logger )
671
+ {
672
+ if ( ! Directory . Exists ( path ) )
673
+ {
674
+ return false ;
675
+ }
676
+
677
+ var directory = new DirectoryInfo ( path ) ;
678
+ if ( ! DirectoryAndParentsAreSafe ( directory , logger ) )
679
+ {
680
+ return false ;
681
+ }
682
+
683
+ foreach ( var childDirectory in directory . GetDirectories ( "*" , SearchOption . AllDirectories ) )
684
+ {
685
+ if ( FileSystemReportsAReparsePoint ( childDirectory , logger ) )
686
+ {
687
+ return false ;
688
+ }
689
+ }
690
+
691
+ foreach ( var childFile in directory . GetFiles ( "*" , SearchOption . AllDirectories ) )
692
+ {
693
+ if ( FileSystemReportsAReparsePoint ( childFile , logger ) )
694
+ {
695
+ return false ;
696
+ }
697
+ }
698
+
699
+ return true ;
700
+ }
701
+
702
+ private static bool DirectoryAndParentsAreSafe ( DirectoryInfo directoryToCheck , MySession logger )
703
+ {
704
+ for ( var directory = directoryToCheck ; directory != null ; directory = directory . Parent )
705
+ {
706
+ if ( FileSystemReportsAReparsePoint ( directory , logger ) )
707
+ {
708
+ return false ;
709
+ }
710
+ }
711
+
712
+ return true ;
713
+ }
714
+
715
+ private static bool FileSystemReportsAReparsePoint ( FileSystemInfo fsInfo , MySession logger )
716
+ {
717
+ if ( ( fsInfo . Attributes & System . IO . FileAttributes . ReparsePoint ) != 0 )
718
+ {
719
+ logger . Log ( "Reparse point detected for {0}." , fsInfo . FullName ) ;
720
+ return true ;
721
+ }
722
+
723
+ return false ;
724
+ }
725
+ }
579
726
}
0 commit comments