1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System.Diagnostics;
6 using Xunit;
7 
8 namespace System.IO.Tests
9 {
10     public abstract partial class FileSystemTest : RemoteExecutorTestBase
11     {
12         public static readonly byte[] TestBuffer = { 0xBA, 0x5E, 0xBA, 0x11, 0xF0, 0x07, 0xBA, 0x11 };
13 
14         protected const TestPlatforms CaseInsensitivePlatforms = TestPlatforms.Windows | TestPlatforms.OSX;
15         protected const TestPlatforms CaseSensitivePlatforms = TestPlatforms.AnyUnix & ~TestPlatforms.OSX;
16 
17         public static bool AreAllLongPathsAvailable => PathFeatures.AreAllLongPathsAvailable();
18 
19         public static bool LongPathsAreNotBlocked => !PathFeatures.AreLongPathsBlocked();
20 
21         public static bool UsingNewNormalization => !PathFeatures.IsUsingLegacyPathNormalization();
22 
23         public static TheoryData<string> PathsWithInvalidColons = TestData.PathsWithInvalidColons;
24         public static TheoryData<string> PathsWithInvalidCharacters = TestData.PathsWithInvalidCharacters;
25         public static TheoryData<char> TrailingCharacters = TestData.TrailingCharacters;
26         public static TheoryData ValidPathComponentNames = IOInputs.GetValidPathComponentNames().ToTheoryData();
27         public static TheoryData SimpleWhiteSpace = IOInputs.GetSimpleWhiteSpace().ToTheoryData();
28         public static TheoryData WhiteSpace = IOInputs.GetWhiteSpace().ToTheoryData();
29         public static TheoryData UncPathsWithoutShareName = IOInputs.GetUncPathsWithoutShareName().ToTheoryData();
30         public static TheoryData PathsWithReservedDeviceNames = IOInputs.GetPathsWithReservedDeviceNames().ToTheoryData();
31         public static TheoryData PathsWithAlternativeDataStreams = IOInputs.GetPathsWithAlternativeDataStreams().ToTheoryData();
32         public static TheoryData PathsWithComponentLongerThanMaxComponent = IOInputs.GetPathsWithComponentLongerThanMaxComponent().ToTheoryData();
33         public static TheoryData ControlWhiteSpace = IOInputs.GetControlWhiteSpace().ToTheoryData();
34         public static TheoryData NonControlWhiteSpace = IOInputs.GetNonControlWhiteSpace().ToTheoryData();
35 
36         /// <summary>
37         /// In some cases (such as when running without elevated privileges),
38         /// the symbolic link may fail to create. Only run this test if it creates
39         /// links successfully.
40         /// </summary>
41         protected static bool CanCreateSymbolicLinks => s_canCreateSymbolicLinks.Value;
42 
43         private static readonly Lazy<bool> s_canCreateSymbolicLinks = new Lazy<bool>(() =>
44         {
45             // Verify file symlink creation
46             string path = Path.GetTempFileName();
47             string linkPath = path + ".link";
48             bool success = MountHelper.CreateSymbolicLink(linkPath, path, isDirectory: false);
49             try { File.Delete(path); } catch { }
50             try { File.Delete(linkPath); } catch { }
51 
52             // Verify directory symlink creation
53             path = Path.GetTempFileName();
54             linkPath = path + ".link";
55             success = success && MountHelper.CreateSymbolicLink(linkPath, path, isDirectory: true);
56             try { Directory.Delete(path); } catch { }
57             try { Directory.Delete(linkPath); } catch { }
58 
59             return success;
60         });
61 
GetNamedPipeServerStreamName()62         protected string GetNamedPipeServerStreamName()
63         {
64             if (PlatformDetection.IsInAppContainer)
65             {
66                 return @"LOCAL\" + Guid.NewGuid().ToString("N");
67             }
68             return Guid.NewGuid().ToString("N");
69         }
70 
71         /// <summary>
72         /// Do a test action against read only file system (for Unix).
73         /// </summary>
74         /// <param name="testAction">Test action to perform. The string argument will be read only directory.</param>
75         /// <param name="subDirectoryName">Optional subdirectory to create.</param>
ReadOnly_FileSystemHelper(Action<string> testAction, string subDirectoryName = null)76         protected void ReadOnly_FileSystemHelper(Action<string> testAction, string subDirectoryName = null)
77         {
78             // Set up read only file system
79             // Set up the source directory
80             string sourceDirectory = GetTestFilePath();
81             if (subDirectoryName == null)
82             {
83                 Directory.CreateDirectory(sourceDirectory);
84             }
85             else
86             {
87                 string sourceSubDirectory = Path.Combine(sourceDirectory, subDirectoryName);
88                 Directory.CreateDirectory(sourceSubDirectory);
89             }
90 
91             // Set up the target directory and mount as a read only
92             string readOnlyDirectory = GetTestFilePath();
93             Directory.CreateDirectory(readOnlyDirectory);
94 
95             Assert.Equal(0, AdminHelpers.RunAsSudo($"mount --bind {sourceDirectory} {readOnlyDirectory}"));
96 
97             try
98             {
99                 Assert.Equal(0, AdminHelpers.RunAsSudo($"mount -o remount,ro,bind {sourceDirectory} {readOnlyDirectory}"));
100                 testAction(readOnlyDirectory);
101             }
102             finally
103             {
104                 // Clean up test environment
105                 Assert.Equal(0, AdminHelpers.RunAsSudo($"umount {readOnlyDirectory}"));
106             }
107         }
108     }
109 }
110