├── .editorconfig
├── .gitignore
├── CHANGELOG.md
├── Directory.Build.props
├── DokanNet.Tests
├── BufferPoolTests.cs
├── ContextTests.cs
├── DirectoryInfoTest.cs
├── DokanNet.Tests.csproj
├── DokanNet.Tests.ruleset
├── DokanOperationsFixture.cs
├── DriveInfoTests.cs
├── FileAccessUtils.cs
├── FileInfoTests.cs
├── FileInfoTestsUnsafe.cs
├── FileSettings.cs
├── FileSystemSecurityExtensions.cs
├── FormatProviderTests.cs
├── GlobalSuppressions.cs
├── LogExtensions.cs
├── Mounter.cs
├── OverlappedTests.Configuration.xml
├── OverlappedTests.cs
├── StringExtensions.cs
└── TestCategories.cs
├── DokanNet.runsettings
├── DokanNet.sln
├── DokanNet.testsettings
├── DokanNet
├── BufferPool.cs
├── ByHandleFileInformation.cs
├── Dokan.cs
├── Dokan.snk
├── DokanException.cs
├── DokanFileInfo.cs
├── DokanHandle.cs
├── DokanHelper.cs
├── DokanInstance.cs
├── DokanInstanceBuilder.cs
├── DokanInstanceNotifyCompletion.cs
├── DokanNet.csproj
├── DokanOperationProxy.cs
├── DokanOptions.cs
├── DokanResult.cs
├── DokanStatus.cs
├── FileAccess.cs
├── FileInformation.cs
├── FileSystemFeatures.cs
├── FindFileInformation.cs
├── IDokanFileInfo.cs
├── IDokanOperations.cs
├── IDokanOperations2.cs
├── IDokanOperationsUnsafe.cs
├── Legacy
│ └── DokanOperationsAdapter.cs
├── Logging
│ ├── ConsoleLogger.cs
│ ├── DebugViewLogger.cs
│ ├── ILogger.cs
│ ├── Logger.cs
│ ├── LoggerExtensions.cs
│ ├── NullLogger.cs
│ └── TraceLogger.cs
├── MockDokanFileInfo.cs
├── Native
│ ├── BY_HANDLE_FILE_INFORMATION.cs
│ ├── DOKAN_OPERATIONS.cs
│ ├── DOKAN_OPTIONS.cs
│ ├── NativeMethods.cs
│ ├── SECURITY_INFORMATION.cs
│ ├── WIN32_FIND_DATA.cs
│ └── WIN32_FIND_STREAM_DATA.cs
├── NtStatus.cs
├── NullFormatProvider.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.de.resx
│ ├── Resources.fr.resx
│ ├── Resources.resx
│ └── Resources.sv.resx
└── documentations
│ ├── Doxyfile
│ ├── mainpage.md
│ └── resources
│ ├── customdoxygen.css
│ ├── doxy-boot.js
│ ├── footer.html
│ └── header.html
├── README.md
├── UpgradeLog.htm
├── appveyor.yml
├── dokan_logo.png
├── license.txt
└── sample
├── DokanNetMirror
├── DokanNetMirror.csproj
├── Extensions.cs
├── Mirror.cs
├── NativeMethods.cs
├── Notify.cs
├── Program.cs
└── UnsafeMirror.cs
├── DokanNetMirrorLegacy
├── DokanNetMirrorLegacy.csproj
├── Extensions.cs
├── Mirror.cs
├── NativeMethods.cs
├── Notify.cs
├── Program.cs
└── UnsafeMirror.cs
└── RegistryFS
├── Program.cs
├── Properties
└── launchSettings.json
├── RFS.cs
└── RegistryFS.csproj
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome:http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Don't use tabs for indentation.
7 | [*]
8 | indent_style = space
9 | # (Please don't specify an indent_size here; that has too many unintended consequences.)
10 |
11 | # Code files
12 | [*.{cs,csx,vb,vbx}]
13 | indent_size = 4
14 |
15 | # Xml project files
16 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
17 | indent_size = 2
18 |
19 | # Xml config files
20 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
21 | indent_size = 2
22 |
23 | # JSON files
24 | [*.json]
25 | indent_size = 2
26 |
27 | # Dotnet code style settings:
28 | [*.{cs,vb}]
29 | # Sort using and Import directives with System.* appearing first
30 | dotnet_sort_system_directives_first = true
31 | # Avoid "this." and "Me." if not necessary
32 | dotnet_style_qualification_for_field = false:suggestion
33 | dotnet_style_qualification_for_property = false:suggestion
34 | dotnet_style_qualification_for_method = false:suggestion
35 | dotnet_style_qualification_for_event = false:suggestion
36 |
37 | # Use language keywords instead of framework type names for type references
38 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
39 | dotnet_style_predefined_type_for_member_access = true:suggestion
40 |
41 | # Suggest more modern language features when available
42 | dotnet_style_object_initializer = true:suggestion
43 | dotnet_style_collection_initializer = true:suggestion
44 | dotnet_style_coalesce_expression = true:suggestion
45 | dotnet_style_null_propagation = true:suggestion
46 | dotnet_style_explicit_tuple_names = true:suggestion
47 |
48 | # CSharp code style settings:
49 | [*.cs]
50 | # Prefer "var" everywhere
51 | csharp_style_var_for_built_in_types = true:suggestion
52 | csharp_style_var_when_type_is_apparent = true:suggestion
53 | csharp_style_var_elsewhere = true:suggestion
54 |
55 | # Prefer method-like constructs to have a block body
56 | csharp_style_expression_bodied_methods = false:none
57 | csharp_style_expression_bodied_constructors = false:none
58 | csharp_style_expression_bodied_operators = false:none
59 |
60 | # Prefer property-like constructs to have an expression-body
61 | csharp_style_expression_bodied_properties = true:none
62 | csharp_style_expression_bodied_indexers = true:none
63 | csharp_style_expression_bodied_accessors = true:none
64 |
65 | # Suggest more modern language features when available
66 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
67 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
68 | csharp_style_inlined_variable_declaration = true:suggestion
69 | csharp_style_throw_expression = true:suggestion
70 | csharp_style_conditional_delegate_call = true:suggestion
71 |
72 | # Newline settings
73 | csharp_new_line_before_open_brace = all
74 | csharp_new_line_before_else = true
75 | csharp_new_line_before_catch = true
76 | csharp_new_line_before_finally = true
77 | csharp_new_line_before_members_in_object_initializers = true
78 | csharp_new_line_before_members_in_anonymous_types = true
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.suo
2 | *.user
3 | *.nupkg
4 | bin
5 | obj
6 | packages
7 | TestResults
8 | /DokanNet/documentations/doc
9 | *.lock.json
10 | *.db
11 | *.opendb
12 | .vs
13 | *.DotSettings
14 | **/launchSettings.json
--------------------------------------------------------------------------------
/Directory.Build.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | latest
5 | enable
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/DokanNet.Tests/BufferPoolTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DokanNet.Logging;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace DokanNet.Tests
6 | {
7 | ///
8 | /// Tests for .
9 | ///
10 | [TestClass]
11 | public sealed class BufferPoolTests
12 | {
13 | ///
14 | /// Rudimentary test for .
15 | ///
16 | [TestMethod, TestCategory(TestCategories.Success)]
17 | public void BufferPoolBasicTest()
18 | {
19 | BufferPool pool = new BufferPool();
20 | ILogger logger = new TraceLogger();
21 |
22 | // Verify buffer is pooled.
23 | const int MB = 1024 * 1024;
24 | byte[] buffer = pool.RentBuffer(MB, logger);
25 | pool.ReturnBuffer(buffer, logger);
26 |
27 | byte[] buffer2 = pool.RentBuffer(MB, logger);
28 | Assert.AreSame(buffer, buffer2, "Expected recycling of 1 MB buffer.");
29 |
30 | // Verify buffer that buffer not power of 2 is not pooled.
31 | buffer = pool.RentBuffer(MB - 1, logger);
32 | pool.ReturnBuffer(buffer, logger);
33 |
34 | buffer2 = pool.RentBuffer(MB - 1, logger);
35 | Assert.AreNotSame(buffer, buffer2, "Did not expect recycling of 1 MB - 1 byte buffer.");
36 |
37 | // Run through a bunch of random buffer sizes and make sure we always get a buffer of the right size.
38 | int seed = Environment.TickCount;
39 | Console.WriteLine($"Random seed: {seed}");
40 | Random random = new Random(seed);
41 |
42 | for (int i = 0; i < 1000; i++)
43 | {
44 | int size = random.Next(0, 2 * MB);
45 | buffer = pool.RentBuffer(size, logger);
46 | Assert.AreEqual(size, buffer.Length, "Wrong buffer size.");
47 | pool.ReturnBuffer(buffer, logger);
48 | }
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/DokanNet.Tests/DokanNet.Tests.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
18 | net48
19 |
20 | $(MSBuildProjectName)
21 | True
22 | disable
23 |
24 | false
25 | ..\DokanNet\Dokan.snk
26 |
27 |
28 |
29 | OverlappedTests.cs
30 | PreserveNewest
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 | DokanNet.Tests.ruleset
47 |
48 | False
49 |
50 |
--------------------------------------------------------------------------------
/DokanNet.Tests/DokanNet.Tests.ruleset:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/DokanNet.Tests/DriveInfoTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 | using static DokanNet.Tests.FileSettings;
5 |
6 | namespace DokanNet.Tests
7 | {
8 | [TestClass]
9 | public sealed class DriveInfoTests
10 | {
11 | public TestContext TestContext { get; set; }
12 |
13 | [TestInitialize]
14 | public void Initialize()
15 | {
16 | DokanOperationsFixture.InitInstance(TestContext.TestName);
17 | }
18 |
19 | [TestCleanup]
20 | public void Cleanup()
21 | {
22 | DokanOperationsFixture.ClearInstance(out bool hasUnmatchedInvocations);
23 | Assert.IsFalse(hasUnmatchedInvocations, "Found Mock invocations without corresponding setups");
24 | }
25 |
26 | [TestMethod, TestCategory(TestCategories.Success)]
27 | public void GetAvailableFreeSpace_CallsApiCorrectly()
28 | {
29 | var fixture = DokanOperationsFixture.Instance;
30 |
31 | #if LOGONLY
32 | fixture.PermitAny();
33 | #else
34 | var availableFreeSpace = 1 << 10;
35 | fixture.ExpectGetDiskFreeSpace(freeBytesAvailable: availableFreeSpace);
36 | #endif
37 |
38 | var sut = new DriveInfo(DokanOperationsFixture.MOUNT_POINT);
39 |
40 | #if LOGONLY
41 | Assert.AreEqual(0, sut.AvailableFreeSpace, nameof(sut.AvailableFreeSpace));
42 | #else
43 | Assert.AreEqual(availableFreeSpace, sut.AvailableFreeSpace, nameof(sut.AvailableFreeSpace));
44 |
45 | fixture.Verify();
46 | #endif
47 | }
48 |
49 | [TestMethod, TestCategory(TestCategories.Success)]
50 | public void GetDriveFormat_CallsApiCorrectly()
51 | {
52 | var fixture = DokanOperationsFixture.Instance;
53 |
54 | #if LOGONLY
55 | fixture.PermitAny();
56 | #else
57 | fixture.ExpectOpenDirectory(DokanOperationsFixture.RootName, FileAccess.Synchronize, FileShare.ReadWrite);
58 | fixture.ExpectGetVolumeInformation(DokanOperationsFixture.VOLUME_LABEL, DokanOperationsFixture.FILESYSTEM_NAME, 256);
59 | #endif
60 |
61 | var sut = new DriveInfo(DokanOperationsFixture.MOUNT_POINT);
62 |
63 | #if LOGONLY
64 | Assert.IsNotNull(sut.DriveFormat, nameof(sut.DriveFormat));
65 | Console.WriteLine(sut.DriveFormat);
66 | #else
67 | Assert.AreEqual(DokanOperationsFixture.FILESYSTEM_NAME, sut.DriveFormat, nameof(sut.DriveFormat));
68 |
69 | fixture.Verify();
70 | #endif
71 | }
72 |
73 | [TestMethod, TestCategory(TestCategories.Success)]
74 | public void GetDriveType_CallsApiCorrectly()
75 | {
76 | var sut = new DriveInfo(DokanOperationsFixture.MOUNT_POINT);
77 |
78 | #if NETWORK_DRIVE
79 | Assert.AreEqual(DriveType.Network, sut.DriveType, nameof(sut.DriveType));
80 | #else
81 | Assert.AreEqual(DriveType.Removable, sut.DriveType, nameof(sut.DriveType));
82 | #endif
83 | }
84 |
85 | [TestMethod, TestCategory(TestCategories.Success)]
86 | public void GetIsReady_CallsApiCorrectly()
87 | {
88 | var fixture = DokanOperationsFixture.Instance;
89 |
90 | var path = DokanOperationsFixture.RootName;
91 | #if LOGONLY
92 | fixture.PermitAny();
93 | #else
94 | var anyDateTime = new DateTime(2000, 1, 1, 12, 0, 0);
95 | fixture.ExpectCreateFile(path, ReadAttributesAccess, ReadWriteShare, FileMode.Open);
96 | fixture.ExpectGetFileInformation(path, FileAttributes.Directory, creationTime: anyDateTime, lastWriteTime: anyDateTime, lastAccessTime: anyDateTime);
97 | #endif
98 |
99 | var sut = new DriveInfo(DokanOperationsFixture.MOUNT_POINT);
100 |
101 | #if LOGONLY
102 | Console.WriteLine($"sut.IsReady {sut.IsReady}");
103 | #else
104 | Assert.IsTrue(sut.IsReady, nameof(sut.IsReady));
105 | #endif
106 | }
107 |
108 | [TestMethod, TestCategory(TestCategories.Success)]
109 | public void GetName_CallsApiCorrectly()
110 | {
111 | var path = DokanOperationsFixture.RootName.AsDriveBasedPath();
112 |
113 | var sut = new DriveInfo(DokanOperationsFixture.MOUNT_POINT);
114 |
115 | Assert.AreEqual(path, sut.Name, nameof(sut.Name));
116 | }
117 |
118 | [TestMethod, TestCategory(TestCategories.Success)]
119 | public void GetRootDirectory_CallsApiCorrectly()
120 | {
121 | var path = DokanOperationsFixture.RootName.AsDriveBasedPath();
122 |
123 | #if LOGONLY
124 | var fixture = DokanOperationsFixture.Instance;
125 | fixture.PermitAny();
126 | #endif
127 |
128 | var sut = new DriveInfo(DokanOperationsFixture.MOUNT_POINT);
129 |
130 | #if LOGONLY
131 | Assert.IsNotNull(sut.RootDirectory, nameof(sut.RootDirectory));
132 | Console.WriteLine(sut.RootDirectory);
133 | #else
134 | Assert.AreEqual(path, sut.RootDirectory.Name, nameof(sut.RootDirectory));
135 | #endif
136 | }
137 |
138 | [TestMethod, TestCategory(TestCategories.Success)]
139 | public void GetTotalFreeSpace_CallsApiCorrectly()
140 | {
141 | var fixture = DokanOperationsFixture.Instance;
142 |
143 | #if LOGONLY
144 | fixture.PermitAny();
145 | #else
146 | var totalFreeSpace = 1 << 14;
147 | fixture.ExpectGetDiskFreeSpace(totalNumberOfFreeBytes: totalFreeSpace);
148 | #endif
149 |
150 | var sut = new DriveInfo(DokanOperationsFixture.MOUNT_POINT);
151 |
152 | #if LOGONLY
153 | Assert.AreEqual(0, sut.TotalFreeSpace, nameof(sut.TotalFreeSpace));
154 | #else
155 | Assert.AreEqual(totalFreeSpace, sut.TotalFreeSpace, nameof(sut.TotalFreeSpace));
156 |
157 | fixture.Verify();
158 | #endif
159 | }
160 |
161 | [TestMethod, TestCategory(TestCategories.Success)]
162 | public void GetTotalSize_CallsApiCorrectly()
163 | {
164 | var fixture = DokanOperationsFixture.Instance;
165 |
166 | #if LOGONLY
167 | fixture.PermitAny();
168 | #else
169 | var totalSize = 1 << 20;
170 | fixture.ExpectGetDiskFreeSpace(totalNumberOfBytes: totalSize);
171 | #endif
172 |
173 | var sut = new DriveInfo(DokanOperationsFixture.MOUNT_POINT);
174 |
175 | #if LOGONLY
176 | Assert.AreEqual(0, sut.TotalSize, nameof(sut.TotalSize));
177 | #else
178 | Assert.AreEqual(totalSize, sut.TotalSize, nameof(sut.TotalSize));
179 |
180 | fixture.Verify();
181 | #endif
182 | }
183 |
184 | [TestMethod, TestCategory(TestCategories.Success)]
185 | public void GetVolumeLabel_CallsApiCorrectly()
186 | {
187 | var fixture = DokanOperationsFixture.Instance;
188 |
189 | #if LOGONLY
190 | fixture.PermitAny();
191 | #else
192 | fixture.ExpectOpenDirectory(DokanOperationsFixture.RootName, FileAccess.Synchronize, FileShare.ReadWrite);
193 | fixture.ExpectGetVolumeInformation(DokanOperationsFixture.VOLUME_LABEL, DokanOperationsFixture.FILESYSTEM_NAME, 256);
194 | #endif
195 |
196 | var sut = new DriveInfo(DokanOperationsFixture.MOUNT_POINT);
197 |
198 | #if LOGONLY
199 | Assert.IsNotNull(sut.VolumeLabel, nameof(sut.VolumeLabel));
200 | Console.WriteLine(sut.VolumeLabel);
201 | #else
202 | Assert.AreEqual(DokanOperationsFixture.VOLUME_LABEL, sut.VolumeLabel, nameof(sut.VolumeLabel));
203 |
204 | fixture.Verify();
205 | #endif
206 | }
207 | }
208 | }
--------------------------------------------------------------------------------
/DokanNet.Tests/FileAccessUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 |
4 | namespace DokanNet.Tests
5 | {
6 | static class FileAccessUtils
7 | {
8 | private const FileAccess FILE_GENERIC_READ =
9 | FileAccess.ReadAttributes |
10 | FileAccess.ReadData |
11 | FileAccess.ReadExtendedAttributes |
12 | FileAccess.ReadPermissions |
13 | FileAccess.Synchronize;
14 |
15 | private const FileAccess FILE_GENERIC_WRITE =
16 | FileAccess.AppendData |
17 | FileAccess.WriteAttributes |
18 | FileAccess.WriteData |
19 | FileAccess.WriteExtendedAttributes |
20 | FileAccess.ReadPermissions |
21 | FileAccess.Synchronize;
22 |
23 | private const FileAccess FILE_GENERIC_EXECUTE =
24 | FileAccess.Execute |
25 | FileAccess.ReadAttributes |
26 | FileAccess.ReadPermissions |
27 | FileAccess.Synchronize;
28 |
29 | private static readonly FileAccess FILE_ALL_ACCESS = (FileAccess)Enum.GetValues(typeof(FileAccess)).Cast().Sum();
30 |
31 | public static FileAccess MapSpecificToGenericAccess(FileAccess desiredAccess)
32 | {
33 | var outDesiredAccess = desiredAccess;
34 |
35 | var genericRead = false;
36 | var genericWrite = false;
37 | var genericExecute = false;
38 | var genericAll = false;
39 | if ((outDesiredAccess & FILE_GENERIC_READ) == FILE_GENERIC_READ)
40 | {
41 | outDesiredAccess |= FileAccess.GenericRead;
42 | genericRead = true;
43 | }
44 |
45 | if ((outDesiredAccess & FILE_GENERIC_WRITE) == FILE_GENERIC_WRITE)
46 | {
47 | outDesiredAccess |= FileAccess.GenericWrite;
48 | genericWrite = true;
49 | }
50 |
51 | if ((outDesiredAccess & FILE_GENERIC_EXECUTE) == FILE_GENERIC_EXECUTE)
52 | {
53 | outDesiredAccess |= FileAccess.GenericExecute;
54 | genericExecute = true;
55 | }
56 |
57 | if ((outDesiredAccess & FILE_ALL_ACCESS) == FILE_ALL_ACCESS)
58 | {
59 | outDesiredAccess |= FileAccess.GenericAll;
60 | genericAll = true;
61 | }
62 |
63 | if (genericRead)
64 | {
65 | outDesiredAccess &= ~FILE_GENERIC_READ;
66 | }
67 |
68 | if (genericWrite)
69 | {
70 | outDesiredAccess &= ~FILE_GENERIC_WRITE;
71 | }
72 |
73 | if (genericExecute)
74 | {
75 | outDesiredAccess &= ~FILE_GENERIC_EXECUTE;
76 | }
77 |
78 | if (genericAll)
79 | {
80 | outDesiredAccess &= ~FILE_ALL_ACCESS;
81 | }
82 |
83 | return outDesiredAccess;
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/DokanNet.Tests/FileInfoTestsUnsafe.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.VisualStudio.TestTools.UnitTesting;
2 |
3 | namespace DokanNet.Tests
4 | {
5 | ///
6 | /// Tests for . This is leveraging the same set of tests as
7 | /// by deriving from that class, but by calling
8 | /// DokanOperationsFixture.InitInstance(unsafeOperations: true) from setup to send all
9 | /// Read/WriteFile calls through the Read/WriteFile(IntPtr buffer, uint bufferLength) overloads instead
10 | /// of the Read/WriteFile(byte[] buffer) overloads.
11 | ///
12 | [TestClass]
13 | public sealed class FileInfoTestsUnsafe : FileInfoTests
14 | {
15 | [ClassInitialize]
16 | public static new void ClassInitialize(TestContext context)
17 | {
18 | // Just invoke the base class init.
19 | FileInfoTests.ClassInitialize(context);
20 | }
21 |
22 | [ClassCleanup]
23 | public static new void ClassCleanup()
24 | {
25 | // Just invoke the base class cleanup.
26 | FileInfoTests.ClassCleanup();
27 | }
28 |
29 | [TestInitialize]
30 | public override void Initialize()
31 | {
32 | // Clear the buffer pool (so we can validate in Cleanup()) and init test fixture.
33 | BufferPool.Default.Clear();
34 | DokanOperationsFixture.InitInstance(TestContext.TestName, unsafeOperations: true);
35 | }
36 |
37 | [TestCleanup]
38 | public override void Cleanup()
39 | {
40 | // Verify no buffers were pooled and then call base class Cleanup().
41 | Assert.AreEqual(0, BufferPool.Default.ServedBytes, "Expected zero buffer pooling activity when using IDokanOperationsUnsafe.");
42 | BufferPool.Default.Clear();
43 | base.Cleanup();
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/DokanNet.Tests/FileSettings.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 |
3 | namespace DokanNet.Tests
4 | {
5 | internal static class FileSettings
6 | {
7 | public const FileAccess ReadAttributesAccess = FileAccess.ReadAttributes;
8 |
9 | public const FileAccess ReadPermissionsAccess = FileAccess.ReadPermissions;
10 |
11 | public const FileAccess ReadAttributesPermissionsAccess = ReadAttributesAccess | ReadPermissionsAccess;
12 |
13 | public const FileAccess ChangePermissionsAccess = FileAccess.ReadAttributes | FileAccess.ReadPermissions | FileAccess.ChangePermissions;
14 |
15 | public const FileAccess ReadAccess = FileAccess.ReadData | FileAccess.ReadExtendedAttributes | FileAccess.ReadAttributes | FileAccess.ReadPermissions | FileAccess.Synchronize;
16 |
17 | public const FileAccess WriteAccess =
18 | FileAccess.WriteData | FileAccess.AppendData | FileAccess.WriteExtendedAttributes |
19 | FileAccess.ReadAttributes | FileAccess.WriteAttributes | FileAccess.ReadPermissions | FileAccess.Synchronize;
20 |
21 | public const FileAccess ReadWriteAccess = ReadAccess | WriteAccess;
22 |
23 | public const FileAccess SetOwnershipAccess = ReadAccess | WriteAccess | FileAccess.Delete | FileAccess.ChangePermissions | FileAccess.SetOwnership;
24 |
25 | public const FileAccess DeleteAccess = FileAccess.ReadAttributes | FileAccess.Delete;
26 |
27 | public const FileAccess CopyToAccess = ReadAccess | WriteAccess | FileAccess.Delete | FileAccess.ChangePermissions;
28 |
29 | public const FileAccess MoveFromAccess = FileAccess.ReadAttributes | FileAccess.Delete | FileAccess.Synchronize;
30 |
31 | public const FileAccess ReplaceAccess = FileAccess.WriteData | FileAccess.ReadExtendedAttributes | FileAccess.ReadAttributes | FileAccess.Delete | FileAccess.ReadPermissions | FileAccess.Synchronize;
32 |
33 | public const FileAccess OpenDirectoryAccess = FileAccess.Synchronize;
34 |
35 | public const FileAccess ReadDirectoryAccess = FileAccess.ReadData | FileAccess.Synchronize;
36 |
37 | public const FileAccess WriteDirectoryAccess = FileAccess.WriteData | FileAccess.Synchronize;
38 |
39 | public const FileAccess AppendToDirectoryAccess = FileAccess.AppendData | FileAccess.Synchronize;
40 |
41 | public const FileAccess DeleteFromDirectoryAccess = FileAccess.Delete | FileAccess.ReadAttributes | FileAccess.Synchronize;
42 |
43 | public const FileShare ReadOnlyShare = FileShare.Read;
44 |
45 | public const FileShare ReadShare = FileShare.Read | FileShare.Delete;
46 |
47 | public const FileShare ReadWriteShare = FileShare.ReadWrite | FileShare.Delete;
48 |
49 | public const FileShare WriteShare = FileShare.None;
50 |
51 | public const FileShare OpenDirectoryShare = FileShare.None;
52 |
53 | public const FileOptions ReadFileOptions = FileOptions.None;
54 |
55 | public const FileOptions WriteFileOptions = FileOptions.None;
56 |
57 | public const FileOptions OpenReparsePointOptions = (FileOptions)0x00200000;
58 |
59 | public const FileOptions OpenNoBufferingOptions = (FileOptions)0x20000000;
60 | }
61 | }
--------------------------------------------------------------------------------
/DokanNet.Tests/FileSystemSecurityExtensions.cs:
--------------------------------------------------------------------------------
1 | using System.Security.AccessControl;
2 |
3 | namespace DokanNet.Tests
4 | {
5 | internal static class FileSystemSecurityExtensions
6 | {
7 | public static string AsString(this FileSystemSecurity security)
8 | => security.GetSecurityDescriptorSddlForm(AccessControlSections.Access | AccessControlSections.Owner | AccessControlSections.Group);
9 | }
10 | }
--------------------------------------------------------------------------------
/DokanNet.Tests/FormatProviderTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Microsoft.VisualStudio.TestTools.UnitTesting;
3 |
4 | namespace DokanNet.Tests
5 | {
6 | [TestClass]
7 | public sealed class FormatProviderTests
8 | {
9 | [TestMethod, TestCategory(TestCategories.Success)]
10 | public void NullValuesShouldBeVisible()
11 | {
12 | DateTime? obj = null;
13 | Assert.AreEqual(FormatProviders.NullStringRepresentation, string.Format(FormatProviders.DefaultFormatProvider, "{0}", obj));
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/DokanNet.Tests/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dokan-dev/dokan-dotnet/7271b35414a31b2607c4abe59db9782bc2d6a572/DokanNet.Tests/GlobalSuppressions.cs
--------------------------------------------------------------------------------
/DokanNet.Tests/LogExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace DokanNet.Tests
2 | {
3 | internal static class LogExtensions
4 | {
5 | public static string Log(this IDokanFileInfo info)
6 | => $"{nameof(DokanFileInfo)} {{{info.Context ?? ""}, {(info.DeletePending ? nameof(info.DeletePending) : "")}, {(info.IsDirectory ? nameof(info.IsDirectory) : "")}, {(info.NoCache ? nameof(info.NoCache) : "")}, {(info.PagingIo ? nameof(info.PagingIo) : "")}, {info.ProcessId}, {(info.SynchronousIo ? nameof(info.SynchronousIo) : "")}, {(info.WriteToEndOfFile ? nameof(info.WriteToEndOfFile) : "")}}}";
7 |
8 | public static string Log(this FileInformation fileInfo)
9 | => $"{nameof(FileInformation)} {{{fileInfo.FileName}, [{fileInfo.Attributes}], {fileInfo.CreationTime?.ToString() ?? ""}, {fileInfo.LastWriteTime?.ToString() ?? ""}, {fileInfo.LastAccessTime?.ToString() ?? ""}, {fileInfo.Length}}}";
10 | }
11 | }
--------------------------------------------------------------------------------
/DokanNet.Tests/Mounter.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Threading;
3 | using Microsoft.VisualStudio.TestTools.UnitTesting;
4 |
5 | namespace DokanNet.Tests
6 | {
7 | [TestClass]
8 | public static class Mounter
9 | {
10 | private static Logging.NullLogger NullLogger = new Logging.NullLogger();
11 | private static Dokan Dokan;
12 | private static DokanInstance safeMount;
13 | private static DokanInstance unsafeMount;
14 |
15 | [AssemblyInitialize]
16 | public static void AssemblyInitialize(TestContext context)
17 | {
18 | var dokanOptions = DokanOptions.DebugMode | DokanOptions.MountManager | DokanOptions.CurrentSession;
19 | #if NETWORK_DRIVE
20 | dokanOptions |= DokanOptions.NetworkDrive;
21 | #else
22 | dokanOptions |= DokanOptions.RemovableDrive;
23 | #endif
24 | #if USER_MODE_LOCK
25 | dokanOptions |= DokanOptions.UserModeLock;
26 | #endif
27 |
28 | Dokan = new Dokan(NullLogger);
29 | var safeDokanBuilder = new DokanInstanceBuilder(Dokan)
30 | .ConfigureOptions(options =>
31 | {
32 | options.Options = dokanOptions;
33 | options.MountPoint = DokanOperationsFixture.NormalMountPoint;
34 | });
35 |
36 | safeMount = safeDokanBuilder.Build(DokanOperationsFixture.Operations);
37 |
38 | var unsafeDokanBuilder = new DokanInstanceBuilder(Dokan)
39 | .ConfigureOptions(options =>
40 | {
41 | options.Options = dokanOptions;
42 | options.MountPoint = DokanOperationsFixture.UnsafeMountPoint;
43 | });
44 | unsafeMount = unsafeDokanBuilder.Build(DokanOperationsFixture.UnsafeOperations);
45 | var drive = new DriveInfo(DokanOperationsFixture.NormalMountPoint);
46 | var drive2 = new DriveInfo(DokanOperationsFixture.UnsafeMountPoint);
47 | while (!drive.IsReady || !drive2.IsReady)
48 | {
49 | Thread.Sleep(50);
50 | }
51 |
52 | while (DokanOperationsFixture.HasPendingFiles)
53 | {
54 | Thread.Sleep(50);
55 | }
56 | }
57 |
58 | [AssemblyCleanup]
59 | public static void AssemblyCleanup()
60 | {
61 | safeMount.Dispose();
62 | unsafeMount.Dispose();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/DokanNet.Tests/StringExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace DokanNet.Tests
2 | {
3 | internal static class StringExtensions
4 | {
5 | public static string AsRootedPath(this string path) => DokanOperationsFixture.RootedPath(path);
6 |
7 | public static string AsDriveBasedPath(this string path) => DokanOperationsFixture.DriveBasedPath(path);
8 | }
9 | }
--------------------------------------------------------------------------------
/DokanNet.Tests/TestCategories.cs:
--------------------------------------------------------------------------------
1 | namespace DokanNet.Tests
2 | {
3 | internal static class TestCategories
4 | {
5 | public const string Success = nameof(Success);
6 |
7 | public const string Failure = nameof(Failure);
8 |
9 | public const string Timing = nameof(Timing);
10 |
11 | public const string Manual = nameof(Manual);
12 |
13 | public const string NoPatternSearch = nameof(NoPatternSearch);
14 | }
15 | }
--------------------------------------------------------------------------------
/DokanNet.runsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
5 | x64
6 |
--------------------------------------------------------------------------------
/DokanNet.testsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 | These are default test settings for a local test run.
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/DokanNet/ByHandleFileInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Runtime.InteropServices;
5 |
6 | namespace DokanNet;
7 |
8 | ///
9 | /// Used to provide file information to %Dokan during operations by
10 | /// -
11 | /// -
12 | /// -
13 | /// - .
14 | ///
15 | [StructLayout(LayoutKind.Auto)]
16 | [DebuggerDisplay("{Length}, {CreationTime}, {LastWriteTime}, {LastAccessTime}, {Attributes}")]
17 | public struct ByHandleFileInformation
18 | {
19 | ///
20 | /// Initializes with set to 1.
21 | ///
22 | public ByHandleFileInformation()
23 | {
24 | this = default;
25 | NumberOfLinks = 1;
26 | }
27 |
28 | ///
29 | /// Gets or sets the for the file or directory.
30 | ///
31 | public FileAttributes Attributes { get; set; }
32 |
33 | ///
34 | /// Gets or sets the creation time of the file or directory.
35 | /// If equal to null, the value will not be set or the file has no creation time.
36 | ///
37 | public DateTime? CreationTime { get; set; }
38 |
39 | ///
40 | /// Gets or sets the last access time of the file or directory.
41 | /// If equal to null, the value will not be set or the file has no last access time.
42 | ///
43 | public DateTime? LastAccessTime { get; set; }
44 |
45 | ///
46 | /// Gets or sets the last write time of the file or directory.
47 | /// If equal to null, the value will not be set or the file has no last write time.
48 | ///
49 | public DateTime? LastWriteTime { get; set; }
50 |
51 | ///
52 | /// Gets or sets the length of the file.
53 | ///
54 | public long Length { get; set; }
55 |
56 | ///
57 | /// Number of links to the same file.
58 | ///
59 | public int NumberOfLinks { get; set; }
60 |
61 | ///
62 | /// Index number of file in the file system.
63 | ///
64 | public long FileIndex { get; set; }
65 | }
66 |
--------------------------------------------------------------------------------
/DokanNet/Dokan.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dokan-dev/dokan-dotnet/7271b35414a31b2607c4abe59db9782bc2d6a572/DokanNet/Dokan.snk
--------------------------------------------------------------------------------
/DokanNet/DokanException.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DokanNet.Properties;
3 |
4 | namespace DokanNet
5 | {
6 | ///
7 | /// The dokan exception.
8 | ///
9 | [Serializable]
10 | public class DokanException : Exception
11 | {
12 | ///
13 | /// Initializes a new instance of the class with a .
14 | ///
15 | ///
16 | /// The error status also written to .
17 | ///
18 | internal DokanException(DokanStatus status)
19 | : this(status, GetStatusErrorMessage(status)) { }
20 |
21 | ///
22 | /// Initializes a new instance of the class with a .
23 | ///
24 | ///
25 | /// The error status also written to .
26 | ///
27 | ///
28 | /// The error message.
29 | ///
30 | internal DokanException(DokanStatus status, string message)
31 | : base(message)
32 | {
33 | ErrorStatus = status;
34 | HResult = (int)status;
35 | }
36 |
37 | private static string GetStatusErrorMessage(DokanStatus status)
38 | {
39 | switch (status)
40 | {
41 | case DokanStatus.Error:
42 | return Resources.ErrorDokan;
43 | case DokanStatus.DriveLetterError:
44 | return Resources.ErrorBadDriveLetter;
45 | case DokanStatus.DriverInstallError:
46 | return Resources.ErrorDriverInstall;
47 | case DokanStatus.MountError:
48 | return Resources.ErrorAssignDriveLetter;
49 | case DokanStatus.StartError:
50 | return Resources.ErrorStart;
51 | case DokanStatus.MountPointError:
52 | return Resources.ErrorMountPointInvalid;
53 | case DokanStatus.VersionError:
54 | return Resources.ErrorVersion;
55 | default:
56 | return Resources.ErrorUnknown;
57 | }
58 | }
59 |
60 | ///
61 | /// Dokan error status .
62 | ///
63 | public DokanStatus ErrorStatus { get; private set; }
64 | }
65 | }
--------------------------------------------------------------------------------
/DokanNet/DokanFileInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using System.Runtime.Versioning;
3 | using System.Security.Principal;
4 | using DokanNet.Native;
5 | using Microsoft.Win32.SafeHandles;
6 | using static DokanNet.FormatProviders;
7 |
8 | namespace DokanNet;
9 |
10 | ///
11 | /// %Dokan file information on the current operation.
12 | ///
13 | ///
14 | /// This class cannot be instantiated in C#, it is created by the kernel %Dokan driver.
15 | /// This is the same structure as _DOKAN_FILE_INFO (dokan.h) in the C version of Dokan.
16 | ///
17 | #if NET5_0_OR_GREATER
18 | [SupportedOSPlatform("windows")]
19 | #endif
20 | [StructLayout(LayoutKind.Sequential, Pack = 4)]
21 | public struct DokanFileInfo
22 | {
23 | private long context;
24 |
25 | ///
26 | /// Used internally, never modify.
27 | ///
28 | private readonly ulong dokanContext;
29 |
30 | ///
31 | /// A pointer to the which was passed to .
32 | ///
33 | private readonly nint dokanOptions;
34 |
35 | ///
36 | /// Reserved. Used internally by Dokan library. Never modify.
37 | /// If the processing for the event requires extra data to be associated with it
38 | /// then a pointer to that data can be placed here
39 | ///
40 | private readonly nint processingContext;
41 |
42 | ///
43 | /// Process id for the thread that originally requested a given I/O
44 | /// operation.
45 | ///
46 | public readonly int ProcessId { get; }
47 |
48 | private byte isDirectory;
49 | private byte deletePending;
50 | private readonly byte pagingIo;
51 | private readonly byte synchronousIo;
52 | private readonly byte noCache;
53 | private readonly byte writeToEndOfFile;
54 |
55 | ///
56 | /// Gets or sets a value indicating whether it requesting a directory
57 | /// file. Must be set in if
58 | /// the file appear to be a folder.
59 | ///
60 | public bool IsDirectory { readonly get => isDirectory != 0; set => isDirectory = value ? (byte)1 : (byte)0; }
61 |
62 | ///
63 | /// Gets or sets a value indicating whether the file has to be deleted
64 | /// during the event.
65 | ///
66 | public bool DeletePending { readonly get => deletePending != 0; set => deletePending = value ? (byte)1 : (byte)0; }
67 |
68 | ///
69 | /// Read or write is paging IO.
70 | ///
71 | public readonly bool PagingIo => pagingIo != 0;
72 |
73 | ///
74 | /// Read or write is synchronous IO.
75 | ///
76 | public readonly bool SynchronousIo => synchronousIo != 0;
77 |
78 | ///
79 | /// Read or write directly from data source without cache.
80 | ///
81 | public readonly bool NoCache => noCache != 0;
82 |
83 | ///
84 | /// If true, write to the current end of file instead
85 | /// of using the Offset parameter.
86 | ///
87 | public readonly bool WriteToEndOfFile => writeToEndOfFile != 0;
88 |
89 | ///
90 | /// Gets or sets context that can be used to carry information between operation.
91 | /// The Context can carry whatever type like , struct, int,
92 | /// or internal reference that will help the implementation understand the request context of the event.
93 | ///
94 | public object? Context
95 | {
96 | readonly get
97 | {
98 | if (context != 0)
99 | {
100 | return ((GCHandle)(nint)context).Target;
101 | }
102 |
103 | return null;
104 | }
105 |
106 | set
107 | {
108 | if (context != 0)
109 | {
110 | ((GCHandle)(nint)context).Free();
111 | context = 0;
112 | }
113 |
114 | if (value is not null)
115 | {
116 | context = (nint)GCHandle.Alloc(value);
117 | }
118 | }
119 | }
120 |
121 | ///
122 | /// This method needs to be called in .
123 | ///
124 | /// An with the access token.
125 | public readonly WindowsIdentity GetRequestor()
126 | {
127 | using var sfh = GetRequestorToken();
128 |
129 | return new(sfh.DangerousGetHandle());
130 | }
131 |
132 | ///
133 | /// This method needs to be called in .
134 | ///
135 | /// A with the access token.
136 | public readonly SafeAccessTokenHandle GetRequestorToken() => NativeMethods.DokanOpenRequestorToken(this);
137 |
138 | ///
139 | /// Extends the time out of the current IO operation in driver.
140 | ///
141 | /// Number of milliseconds to extend with.
142 | /// If the operation was successful.
143 | public readonly bool TryResetTimeout(int milliseconds) => NativeMethods.DokanResetTimeout((uint)milliseconds, this);
144 |
145 | /// Returns a string that represents the current object.
146 | /// A string that represents the current object.
147 | public override readonly string ToString() => DokanFormat(
148 | $"{{{nameof(Context)}=0x{context:X}:'{Context}', {nameof(DeletePending)}={DeletePending}, {nameof(IsDirectory)}={IsDirectory}, {nameof(NoCache)}={NoCache}, {nameof(PagingIo)}={PagingIo}, {nameof(ProcessId)}={ProcessId}, {nameof(SynchronousIo)}={SynchronousIo}, {nameof(WriteToEndOfFile)}={WriteToEndOfFile}}}")!;
149 | }
150 |
--------------------------------------------------------------------------------
/DokanNet/DokanHandle.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using System.Runtime.Versioning;
3 | using DokanNet.Native;
4 | using Microsoft.Win32.SafeHandles;
5 |
6 | namespace DokanNet
7 | {
8 | ///
9 | /// This class wraps a native DOKAN_HANDLE.
10 | ///
11 | /// Since this class derives form SafeHandle, it is automatically marshalled as
12 | /// the native handle it represents to and from native code in for example P/Invoke
13 | /// calls. It also uses reference counting and guaranteed to stay alive during such calls.
14 | ///
15 | ///
16 | #if NET5_0_OR_GREATER
17 | [SupportedOSPlatform("windows")]
18 | #endif
19 | internal class DokanHandle : SafeHandleZeroOrMinusOneIsInvalid
20 | {
21 | ///
22 | /// Initializes a new empty instance, specifying whether the handle is to be reliably released.
23 | /// Used internally by native marshaller and not intended to be used directly from user code.
24 | ///
25 | /// true to reliably release the handle during the finalization phase; false to prevent
26 | /// reliable release (not recommended).
27 | public DokanHandle(bool ownsHandle) : base(ownsHandle)
28 | {
29 | }
30 |
31 | ///
32 | /// Initializes an empty instance. Used internally by native marshaller and
33 | /// not intended to be used directly from user code.
34 | ///
35 | public DokanHandle() : base(ownsHandle: true)
36 | {
37 | }
38 |
39 | ///
40 | /// Releases the native DOKAN_HANDLE wrapped by this instance.
41 | ///
42 | /// Always returns true
43 | protected override bool ReleaseHandle()
44 | {
45 | NativeMethods.DokanCloseHandle(handle);
46 | return true;
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/DokanNet/DokanInstanceBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics.CodeAnalysis;
3 | using System.Runtime.Versioning;
4 | using DokanNet.Legacy;
5 | using DokanNet.Logging;
6 | using DokanNet.Native;
7 |
8 | namespace DokanNet;
9 |
10 | ///
11 | /// Dokan FileSystem build helper. Allows to create one or multiple based on a given configuration.
12 | ///
13 | public class DokanInstanceBuilder
14 | {
15 | ///
16 | /// Delegate used by to customize th internal .
17 | ///
18 | public delegate void OptionsConfigurationDelegate(DOKAN_OPTIONS options);
19 |
20 | ///
21 | /// The Dokan version that DokanNet is compatible with.
22 | ///
23 | ///
24 | public const ushort DOKAN_VERSION = 200;
25 |
26 | private readonly DOKAN_OPTIONS _options;
27 |
28 | private readonly Dokan _dokan;
29 |
30 | private ILogger _logger;
31 |
32 | ///
33 | /// Constructure an object with a and default that will use the given .
34 | ///
35 | public DokanInstanceBuilder(Dokan dokan)
36 | {
37 | _logger = new NullLogger();
38 | _options = new DOKAN_OPTIONS
39 | {
40 | Version = DOKAN_VERSION,
41 | MountPoint = "",
42 | UNCName = string.Empty,
43 | SingleThread = false,
44 | Options = DokanOptions.FixedDrive,
45 | TimeOut = TimeSpan.FromSeconds(20),
46 | AllocationUnitSize = 512,
47 | SectorSize = 512,
48 | VolumeSecurityDescriptorLength = 0,
49 |
50 | };
51 | _dokan = dokan;
52 | }
53 |
54 | ///
55 | /// Allows to set a custom like , to be used
56 | /// for the instance created by .
57 | ///
58 | public DokanInstanceBuilder ConfigureLogger(Func IlogegrFactory)
59 | {
60 | _logger = IlogegrFactory();
61 | return this;
62 | }
63 |
64 | ///
65 | /// Allows to personalize the use for .
66 | ///
67 | public DokanInstanceBuilder ConfigureOptions(OptionsConfigurationDelegate optionsConfigurationDelegate)
68 | {
69 | optionsConfigurationDelegate(_options);
70 | return this;
71 | }
72 |
73 | ///
74 | /// Verify that the provided configuration is valid.
75 | /// Note: Has no effect for now.
76 | ///
77 | public DokanInstanceBuilder Validate()
78 | {
79 | // throw on errors
80 | return this;
81 | }
82 |
83 | ///
84 | /// Create a based on the previously provided information
85 | /// through and .
86 | ///
87 | #if NET5_0_OR_GREATER
88 | [SupportedOSPlatform("windows")]
89 | #endif
90 | public DokanInstance Build(IDokanOperations2 operations)
91 | {
92 | return new DokanInstance(_logger, _options, _dokan, operations);
93 | }
94 |
95 | ///
96 | /// Create a based on the previously provided information
97 | /// through and .
98 | ///
99 | #if NET5_0_OR_GREATER
100 | [SupportedOSPlatform("windows")]
101 | #endif
102 | public DokanInstance Build(IDokanOperations operations)
103 | {
104 | return new DokanInstance(_logger, _options, _dokan, new DokanOperationsAdapter(operations, _logger));
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/DokanNet/DokanInstanceNotifyCompletion.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 | using System.Threading;
5 | using System;
6 | using DokanNet.Native;
7 | using System.Runtime.Versioning;
8 |
9 | namespace DokanNet;
10 |
11 | #if NET45_OR_GREATER || NETSTANDARD || NETCOREAPP
12 |
13 | ///
14 | /// Support for async/await operation on DokanInstance objects
15 | ///
16 | #if NET5_0_OR_GREATER
17 | [SupportedOSPlatform("windows")]
18 | #endif
19 | internal sealed class DokanInstanceNotifyCompletion : ICriticalNotifyCompletion
20 | {
21 | public DokanInstanceNotifyCompletion(DokanInstance dokanInstance, uint milliSeconds)
22 | {
23 | DokanInstance = dokanInstance;
24 | MilliSeconds = milliSeconds;
25 | }
26 |
27 | public DokanInstance DokanInstance { get; }
28 | public uint MilliSeconds { get; }
29 | public bool IsCompleted => !DokanInstance.IsFileSystemRunning();
30 | private nint waitHandle;
31 | private bool timedOut;
32 | private Action? continuation;
33 |
34 | public DokanInstanceNotifyCompletion GetAwaiter() => this;
35 |
36 | public void OnCompleted(Action continuation) => throw new NotSupportedException();
37 |
38 | public void UnsafeOnCompleted(Action continuation)
39 | {
40 | this.continuation = continuation;
41 |
42 | if (!NativeMethods.DokanRegisterWaitForFileSystemClosed(DokanInstance.DokanHandle,
43 | out waitHandle,
44 | Callback,
45 | (nint)GCHandle.Alloc(this),
46 | MilliSeconds))
47 | {
48 | throw new Win32Exception();
49 | }
50 | }
51 |
52 | private static void Callback(nint state, bool timedOut)
53 | {
54 | var handle = GCHandle.FromIntPtr(state);
55 | var target = (DokanInstanceNotifyCompletion)handle.Target!;
56 |
57 | handle.Free();
58 |
59 | while (target.waitHandle == 0)
60 | {
61 | Thread.Sleep(20);
62 | }
63 |
64 | NativeMethods.DokanUnregisterWaitForFileSystemClosed(target.waitHandle,
65 | waitForCallbacks: false);
66 |
67 | target.waitHandle = 0;
68 |
69 | target.timedOut = timedOut;
70 |
71 | target.continuation!();
72 | }
73 |
74 | ///
75 | /// Gets a value indicating whether DokanInstance was closed or if await timed out
76 | ///
77 | /// True if DokanInstance was closed or false if await timed out
78 | public bool GetResult()
79 | {
80 | if (timedOut)
81 | {
82 | return false;
83 | }
84 |
85 | if (!IsCompleted)
86 | {
87 | throw new InvalidOperationException($"Invalid state for {nameof(GetResult)}");
88 | }
89 |
90 | return true;
91 | }
92 | }
93 |
94 | #endif
95 |
--------------------------------------------------------------------------------
/DokanNet/DokanNet.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0;netstandard2.1;net48;net46;net8.0;net9.0
5 | DokanNet
6 | DokanNet
7 | A user mode file system for windows.
8 |
9 | This is a .NET wrapper over Dokan, and allows you to create your own file systems in Windows.
10 | Copyright (C) 2025
11 | 2.3.0.1
12 | 2.3.0.1
13 | 2.3.0.1
14 | True
15 | true
16 | README.md
17 | Dokan-dev
18 | AdrienJ, MaximeC, Hiroki Asakawa
19 | https://dokan-dev.github.io/
20 | MIT
21 | dokan_logo.png
22 | https://github.com/dokan-dev/dokan-dotnet
23 | git
24 | dokan file files disk directory storage filesystem io filestore FAT NTFS FUSE
25 | Dokan.snk
26 | false
27 | True
28 | Latest
29 | true
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/DokanNet/DokanOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using DokanNet.Native;
3 |
4 | namespace DokanNet
5 | {
6 | ///
7 | /// Dokan mount options used to describe dokan device behavior.
8 | ///
9 | /// \if PRIVATE
10 | ///
11 | /// \endif
12 | [Flags]
13 | public enum DokanOptions : uint
14 | {
15 | /// Fixed Drive.
16 | FixedDrive = 0,
17 |
18 | /// Enable output debug message.
19 | DebugMode = 1,
20 |
21 | /// Enable output debug message to stderr.
22 | StderrOutput = 2,
23 |
24 | /// Use alternate stream.
25 | AltStream = 4,
26 |
27 | /// Enable mount drive as write-protected.
28 | WriteProtection = 8,
29 |
30 | /// Use network drive - Dokan network provider need to be installed.
31 | NetworkDrive = 16,
32 |
33 | /// Use removable drive.
34 | RemovableDrive = 32,
35 |
36 | /// Use mount manager.
37 | MountManager = 64,
38 |
39 | /// Mount the drive on current session only.
40 | CurrentSession = 128,
41 |
42 | /// Enable Lockfile/Unlockfile operations.
43 | UserModeLock = 256,
44 |
45 | ///
46 | /// Enable methods in , which require this library to maintain a special
47 | /// handle while the file system is mounted.
48 | /// Without this flag, the methods in that inner class always return false if invoked.
49 | ///
50 | EnableNotificationAPI = 512,
51 |
52 | ///
53 | /// Enable Case sensitive path.
54 | /// By default all path are case insensitive.
55 | /// For case sensitive: \\dir\\File and \\diR\\file are different files
56 | /// but for case insensitive they are the same.
57 | ///
58 | CaseSensitive = 1024,
59 |
60 | ///
61 | /// Enables unmounting of network drives via file explorer
62 | ///
63 | EnableNetworkUnmount = 2048,
64 |
65 | ///
66 | /// Forward the kernel driver global and volume logs to the userland
67 | ///
68 | DispatchDriverLogs = 4096,
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/DokanNet/DokanResult.cs:
--------------------------------------------------------------------------------
1 | namespace DokanNet;
2 |
3 | ///
4 | /// Defines common result status codes in for %Dokan
5 | /// operations.
6 | ///
7 | public static class DokanResult
8 | {
9 | ///
10 | /// Success - The operation completed successfully.
11 | ///
12 | public const NtStatus Success = NtStatus.Success;
13 |
14 | ///
15 | /// Error - Incorrect function.
16 | ///
17 | public const NtStatus Error = NtStatus.Error;
18 |
19 | ///
20 | /// Error - The system cannot find the file specified.
21 | ///
22 | public const NtStatus FileNotFound = NtStatus.ObjectNameNotFound;
23 |
24 | ///
25 | /// Error - The system cannot find the path specified.
26 | ///
27 | public const NtStatus PathNotFound = NtStatus.ObjectPathNotFound;
28 |
29 | ///
30 | /// Error - Access is denied.
31 | ///
32 | public const NtStatus AccessDenied = NtStatus.AccessDenied;
33 |
34 | ///
35 | /// Error - The handle is invalid.
36 | ///
37 | public const NtStatus InvalidHandle = NtStatus.InvalidHandle;
38 |
39 | ///
40 | /// Warning - The device is not ready.
41 | ///
42 | public const NtStatus NotReady = NtStatus.DeviceBusy;
43 |
44 | ///
45 | /// Error - The process cannot access the file because it is being used
46 | /// by another process.
47 | ///
48 | public const NtStatus SharingViolation = NtStatus.SharingViolation;
49 |
50 | ///
51 | /// Error - The file exists.
52 | ///
53 | public const NtStatus FileExists = NtStatus.ObjectNameCollision;
54 |
55 | ///
56 | /// Error - There is not enough space on the disk.
57 | ///
58 | public const NtStatus DiskFull = NtStatus.DiskFull;
59 |
60 | ///
61 | /// Error - This function is not supported on this system.
62 | ///
63 | public const NtStatus NotImplemented = NtStatus.NotImplemented;
64 |
65 | ///
66 | /// Error - The data area passed to a system call is too small.
67 | ///
68 | public const NtStatus BufferTooSmall = NtStatus.BufferTooSmall;
69 |
70 | ///
71 | /// Warning - The data area passed to a system call is too small.
72 | ///
73 | public const NtStatus BufferOverflow = NtStatus.BufferOverflow;
74 |
75 | ///
76 | /// Error - The filename, directory name, or volume label syntax is
77 | /// incorrect.
78 | ///
79 | public const NtStatus InvalidName = NtStatus.ObjectNameInvalid;
80 |
81 | ///
82 | /// Error - The directory is not empty.
83 | ///
84 | public const NtStatus DirectoryNotEmpty = NtStatus.DirectoryNotEmpty;
85 |
86 | ///
87 | /// Error - Cannot create a file when that file already exists.
88 | ///
89 | public const NtStatus AlreadyExists = NtStatus.ObjectNameCollision;
90 |
91 | ///
92 | /// Error - An exception occurred in the service when handling the
93 | /// control request.
94 | ///
95 | public const NtStatus InternalError = NtStatus.InternalError;
96 |
97 | ///
98 | /// Error - A required privilege is not held by the client.
99 | ///
100 | public const NtStatus PrivilegeNotHeld = NtStatus.PrivilegeNotHeld;
101 |
102 | ///
103 | /// Error - The requested operation was unsuccessful.
104 | ///
105 | public const NtStatus Unsuccessful = NtStatus.Unsuccessful;
106 |
107 | ///
108 | /// Error - A directory semantics call was made but the accessed file was not a directory.
109 | ///
110 | public const NtStatus NotADirectory = NtStatus.NotADirectory;
111 |
112 | ///
113 | /// Error - The parameter is incorrect.
114 | ///
115 | public const NtStatus InvalidParameter = NtStatus.InvalidParameter;
116 | }
--------------------------------------------------------------------------------
/DokanNet/DokanStatus.cs:
--------------------------------------------------------------------------------
1 | namespace DokanNet
2 | {
3 | ///
4 | /// Error codes returned by DokanMain.
5 | ///
6 | public enum DokanStatus : int
7 | {
8 | ///
9 | /// Dokan mount succeed.
10 | ///
11 | Success = 0,
12 |
13 | ///
14 | /// Dokan mount error.
15 | ///
16 | Error = -1,
17 |
18 | ///
19 | /// Dokan mount failed - Bad drive letter.
20 | ///
21 | DriveLetterError = -2,
22 |
23 | ///
24 | /// Dokan mount failed - Can't install driver.
25 | ///
26 | DriverInstallError = -3,
27 |
28 | ///
29 | /// Dokan mount failed - Driver answer that something is wrong.
30 | ///
31 | StartError = -4,
32 |
33 | ///
34 | /// Dokan mount failed.
35 | /// Can't assign a drive letter or mount point.
36 | /// Probably already used by another volume.
37 | ///
38 | MountError = -5,
39 |
40 | ///
41 | /// Dokan mount failed.
42 | /// Mount point is invalid.
43 | ///
44 | MountPointError = -6,
45 |
46 | ///
47 | /// Dokan mount failed.
48 | /// Requested an incompatible version.
49 | ///
50 | VersionError = -7
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/DokanNet/FileInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Runtime.InteropServices;
5 |
6 | namespace DokanNet
7 | {
8 | ///
9 | /// Used to provide file information to %Dokan during operations by
10 | /// -
11 | /// -
12 | /// -
13 | /// - .
14 | ///
15 | [StructLayout(LayoutKind.Auto)]
16 | [DebuggerDisplay("{FileName}, {Length}, {CreationTime}, {LastWriteTime}, {LastAccessTime}, {Attributes}")]
17 | public struct FileInformation
18 | {
19 | ///
20 | /// Gets or sets the name of the file or directory.
21 | /// required the file path
22 | /// when other operations only need the file name.
23 | ///
24 | public string FileName { get; set; }
25 |
26 | ///
27 | /// Gets or sets the for the file or directory.
28 | ///
29 | public FileAttributes Attributes { get; set; }
30 |
31 | ///
32 | /// Gets or sets the creation time of the file or directory.
33 | /// If equal to null, the value will not be set or the file has no creation time.
34 | ///
35 | public DateTime? CreationTime { get; set; }
36 |
37 | ///
38 | /// Gets or sets the last access time of the file or directory.
39 | /// If equal to null, the value will not be set or the file has no last access time.
40 | ///
41 | public DateTime? LastAccessTime { get; set; }
42 |
43 | ///
44 | /// Gets or sets the last write time of the file or directory.
45 | /// If equal to null, the value will not be set or the file has no last write time.
46 | ///
47 | public DateTime? LastWriteTime { get; set; }
48 |
49 | ///
50 | /// Gets or sets the length of the file.
51 | ///
52 | public long Length { get; set; }
53 | }
54 | }
--------------------------------------------------------------------------------
/DokanNet/FileSystemFeatures.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DokanNet;
4 |
5 | ///
6 | /// Defines feature flags for the file system.
7 | ///
8 | /// \see File System Attribute Extensions (MSDN)
9 | [Flags]
10 | #pragma warning disable 3009
11 | public enum FileSystemFeatures : uint
12 | #pragma warning restore 3009
13 | {
14 | ///
15 | /// No features defined.
16 | ///
17 | None = 0,
18 |
19 | ///
20 | /// The file system supports case-sensitive file names.
21 | ///
22 | CaseSensitiveSearch = 1,
23 |
24 | ///
25 | /// The file system preserves the case of file names when it stores the name on disk.
26 | ///
27 | CasePreservedNames = 2,
28 |
29 | ///
30 | /// The file system supports Unicode in file names.
31 | ///
32 | UnicodeOnDisk = 4,
33 |
34 | ///
35 | /// The file system preserves and enforces access control lists.
36 | ///
37 | PersistentAcls = 8,
38 |
39 | ///
40 | /// The file system supports per-user quotas.
41 | ///
42 | VolumeQuotas = 0x20,
43 |
44 | ///
45 | /// The file system supports sparse files.
46 | ///
47 | /// This feature allows programs to create very large files, but to consume disk space only as needed.
48 | /// A sparse file is a file that contains much of zeros, and a file system that support
49 | /// this are removing repeating zeros to save space.
50 | ///
51 | /// \see Sparse Files (MSDN)
52 | SupportsSparseFiles = 0x40,
53 |
54 | ///
55 | /// The file system supports reparse points.
56 | ///
57 | /// Programs can trap open operations against objects in the file system and run their
58 | /// own code before returning file data. This feature can be used to extend file
59 | /// system features such as mount points, which you can use to redirect data read
60 | /// and written from a folder to another volume or physical disk.
61 | ///
62 | SupportsReparsePoints = 0x80,
63 |
64 | ///
65 | /// The file system supports remote storage.
66 | ///
67 | SupportsRemoteStorage = 0x100,
68 |
69 | ///
70 | /// Volume is a compressed volume. This flag is incompatible with FILE_FILE_COMPRESSION.
71 | /// This does not affect how data is transferred over the network.
72 | ///
73 | VolumeIsCompressed = 0x00008000,
74 |
75 | ///
76 | /// File system supports object identifiers.
77 | ///
78 | SupportsObjectIDs = 0x00010000,
79 |
80 | ///
81 | /// File system supports encryption.
82 | ///
83 | SupportsEncryption = 0x00020000,
84 |
85 | ///
86 | /// File system supports multiple named data streams for a file.
87 | ///
88 | /// The unnamed data stream is the stream where the content in the file is stored.
89 | /// A named stream is a stream where extra data can be stored. The data is connected to the file
90 | /// and if the file is moved, the data is copied to the new place if that file system support it.
91 | /// \see Alternate Data Streams in NTFS (TechNet)
92 | ///
93 | NamedStreams = 0x00040000,
94 |
95 | ///
96 | /// Specified volume is read-only.
97 | ///
98 | ReadOnlyVolume = 0x00080000,
99 |
100 | ///
101 | /// Specified volume can be written to one time only. The write MUST be performed in sequential order.
102 | ///
103 | SequentialWriteOnce = 0x00100000,
104 |
105 | ///
106 | /// The file system supports transaction processing to group changes to files into a transaction.
107 | /// The transaction will guarantee that all changes happens, or none of them.
108 | /// \see About KTM (MSDN)
109 | ///
110 | SupportsTransactions = 0x00200000
111 | }
--------------------------------------------------------------------------------
/DokanNet/FindFileInformation.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.IO;
4 | using System.Runtime.InteropServices;
5 |
6 | namespace DokanNet;
7 |
8 | ///
9 | /// Used to provide file information to %Dokan during operations by
10 | /// -
11 | /// -
12 | /// -
13 | /// - .
14 | ///
15 | [StructLayout(LayoutKind.Auto)]
16 | [DebuggerDisplay("{FileName}, {Length}, {CreationTime}, {LastWriteTime}, {LastAccessTime}, {Attributes}")]
17 | public struct FindFileInformation
18 | {
19 | ///
20 | /// Gets or sets the name of the file or directory.
21 | /// required the file path
22 | /// when other operations only need the file name.
23 | ///
24 | public ReadOnlyMemory FileName { get; set; }
25 |
26 | ///
27 | /// Gets or sets the for the file or directory.
28 | ///
29 | public FileAttributes Attributes { get; set; }
30 |
31 | ///
32 | /// Gets or sets the creation time of the file or directory.
33 | /// If equal to null, the value will not be set or the file has no creation time.
34 | ///
35 | public DateTime? CreationTime { get; set; }
36 |
37 | ///
38 | /// Gets or sets the last access time of the file or directory.
39 | /// If equal to null, the value will not be set or the file has no last access time.
40 | ///
41 | public DateTime? LastAccessTime { get; set; }
42 |
43 | ///
44 | /// Gets or sets the last write time of the file or directory.
45 | /// If equal to null, the value will not be set or the file has no last write time.
46 | ///
47 | public DateTime? LastWriteTime { get; set; }
48 |
49 | ///
50 | /// Gets or sets the length of the file.
51 | ///
52 | public long Length { get; set; }
53 |
54 | ///
55 | /// Short file name in 8.3 format.
56 | ///
57 | public ReadOnlyMemory ShortFileName { get; set; }
58 |
59 | ///
60 | /// Returns value of property converted to a .
61 | ///
62 | ///
63 | public override readonly string ToString() => FileName.ToString();
64 | }
65 |
--------------------------------------------------------------------------------
/DokanNet/IDokanFileInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Principal;
2 |
3 | namespace DokanNet
4 | {
5 | ///
6 | /// %Dokan file information interface.
7 | ///
8 | ///
9 | /// This interface can be inherited in order to testunit user implementation.
10 | ///
11 | public interface IDokanFileInfo
12 | {
13 | ///
14 | /// Gets or sets context that can be used to carry information between operation.
15 | /// The Context can carry whatever type like , struct, int,
16 | /// or internal reference that will help the implementation understand the request context of the event.
17 | ///
18 | object? Context { get; set; }
19 |
20 | ///
21 | /// Gets or sets a value indicating whether the file has to be delete
22 | /// during the event.
23 | ///
24 | bool DeletePending { get; set; }
25 |
26 | ///
27 | /// Gets or sets a value indicating whether it requesting a directory
28 | /// file. Must be set in if
29 | /// the file appear to be a folder.
30 | ///
31 | bool IsDirectory { get; set; }
32 |
33 | ///
34 | /// Read or write directly from data source without cache.
35 | ///
36 | bool NoCache { get; }
37 |
38 | ///
39 | /// Read or write is paging IO.
40 | ///
41 | bool PagingIo { get; }
42 |
43 | ///
44 | /// Process id for the thread that originally requested a given I/O
45 | /// operation.
46 | ///
47 | int ProcessId { get; }
48 |
49 | ///
50 | /// Read or write is synchronous IO.
51 | ///
52 | bool SynchronousIo { get; }
53 |
54 | ///
55 | /// If true, write to the current end of file instead
56 | /// of using the Offset parameter.
57 | ///
58 | bool WriteToEndOfFile { get; }
59 |
60 | ///
61 | /// This method needs to be called in .
62 | ///
63 | /// An with the access token,
64 | /// -or- null if the operation was not successful.
65 | WindowsIdentity GetRequestor();
66 |
67 | ///
68 | /// Extends the time out of the current IO operation in driver.
69 | ///
70 | /// Number of milliseconds to extend with.
71 | /// If the operation was successful.
72 | bool TryResetTimeout(int milliseconds);
73 | }
74 | }
--------------------------------------------------------------------------------
/DokanNet/IDokanOperationsUnsafe.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DokanNet
4 | {
5 | ///
6 | /// This is a sub-interface of that can optionally be implemented
7 | /// to get access to the raw, unmanaged buffers for ReadFile() and WriteFile() for performance optimization.
8 | /// Marshalling the unmanaged buffers to and from byte[] arrays for every call of these APIs incurs an extra copy
9 | /// that can be avoided by reading from or writing directly to the unmanaged buffers.
10 | ///
11 | /// Implementation of this interface is optional. If it is implemented, the overloads of
12 | /// Read/WriteFile(IntPtr, length) will be called instead of Read/WriteFile(byte[]). The caller can fill or read
13 | /// from the unmanaged API with Marshal.Copy, Buffer.MemoryCopy or similar.
14 | ///
15 | public interface IDokanOperationsUnsafe : IDokanOperations
16 | {
17 | ///
18 | /// ReadFile callback on the file previously opened in .
19 | /// It can be called by different thread at the same time,
20 | /// therefore the read has to be thread safe.
21 | ///
22 | /// File path requested by the Kernel on the FileSystem.
23 | /// Read buffer that has to be fill with the read result.
24 | /// The size of 'buffer' in bytes.
25 | /// The buffer size depends of the read size requested by the kernel.
26 | /// Total number of bytes that has been read.
27 | /// Offset from where the read has to be proceed.
28 | /// An with information about the file or directory.
29 | /// or appropriate to the request result.
30 | ///
31 | NtStatus ReadFile(string fileName, IntPtr buffer, uint bufferLength, out int bytesRead, long offset, IDokanFileInfo info);
32 |
33 | ///
34 | /// WriteFile callback on the file previously opened in
35 | /// It can be called by different thread at the same time,
36 | /// therefore the write/context has to be thread safe.
37 | ///
38 | /// File path requested by the Kernel on the FileSystem.
39 | /// Data that has to be written.
40 | /// The size of 'buffer' in bytes.
41 | /// Total number of bytes that has been write.
42 | /// Offset from where the write has to be proceed.
43 | /// An with information about the file or directory.
44 | /// or appropriate to the request result.
45 | ///
46 | NtStatus WriteFile(string fileName, IntPtr buffer, uint bufferLength, out int bytesWritten, long offset, IDokanFileInfo info);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/DokanNet/Logging/ConsoleLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Concurrent;
3 | using System.Globalization;
4 | using System.Threading.Tasks;
5 |
6 | namespace DokanNet.Logging
7 | {
8 | ///
9 | /// Log to the console.
10 | ///
11 | public class ConsoleLogger : ILogger, IDisposable
12 | {
13 | private readonly string _loggerName;
14 | private readonly DateTimeFormatInfo? _dateTimeFormatInfo;
15 | private readonly BlockingCollection<(string Message, ConsoleColor Color)> _PendingLogs = [];
16 |
17 | private readonly Task? _WriterTask = null;
18 | private bool _disposed;
19 |
20 | ///
21 | /// Initializes a new instance of the class.
22 | ///
23 | /// Optional name to be added to each log line.
24 | /// An object that supplies format information for DateTime.
25 | public ConsoleLogger(string loggerName = "", DateTimeFormatInfo? dateTimeFormatInfo = null)
26 | {
27 | _loggerName = loggerName;
28 | _dateTimeFormatInfo = dateTimeFormatInfo;
29 | _WriterTask = Task.Factory.StartNew(() =>
30 | {
31 | foreach (var (Message, Color) in _PendingLogs.GetConsumingEnumerable())
32 | {
33 | WriteMessage(Message, Color);
34 | }
35 | });
36 | }
37 |
38 | ///
39 | public bool DebugEnabled => true;
40 |
41 | ///
42 | public void Debug(string message, params object[] args)
43 | {
44 | EnqueueMessage(Console.ForegroundColor, message, args);
45 | }
46 |
47 | ///
48 | public void Info(string message, params object[] args)
49 | {
50 | EnqueueMessage(Console.ForegroundColor, message, args);
51 | }
52 |
53 | ///
54 | public void Warn(string message, params object[] args)
55 | {
56 | EnqueueMessage(ConsoleColor.DarkYellow, message, args);
57 | }
58 |
59 | ///
60 | public void Error(string message, params object[] args)
61 | {
62 | EnqueueMessage(ConsoleColor.Red, message, args);
63 | }
64 |
65 | ///
66 | public void Fatal(string message, params object[] args)
67 | {
68 | EnqueueMessage(ConsoleColor.Red, message, args);
69 | }
70 |
71 | private void EnqueueMessage(ConsoleColor newColor, string message, params object[] args)
72 | {
73 | if (args.Length > 0)
74 | {
75 | message = string.Format(message, args);
76 | }
77 |
78 | _PendingLogs.Add((message, newColor));
79 | }
80 |
81 | private void WriteMessage(string message, ConsoleColor newColor)
82 | {
83 | lock (Console.Out) // we only need this lock because we want to have more than one logger in this version
84 | {
85 | var origForegroundColor = Console.ForegroundColor;
86 | Console.ForegroundColor = newColor;
87 | Console.WriteLine(message.FormatMessageForLogging(true, loggerName: _loggerName, dateTimeFormatInfo: _dateTimeFormatInfo));
88 | Console.ForegroundColor = origForegroundColor;
89 | }
90 | }
91 |
92 | ///
93 | /// Dispose the object from the native resources.
94 | ///
95 | /// Whether it was call by
96 | protected virtual void Dispose(bool disposing)
97 | {
98 | if (!_disposed)
99 | {
100 | if (disposing)
101 | {
102 | // dispose managed state (managed objects)
103 | _PendingLogs.CompleteAdding();
104 | _WriterTask?.Wait();
105 | }
106 |
107 | // free unmanaged resources (unmanaged objects) and override finalizer
108 | // set large fields to null
109 | _disposed = true;
110 | }
111 | }
112 |
113 | ///
114 | /// Dispose the object from the native resources.
115 | ///
116 | public void Dispose()
117 | {
118 | // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
119 | Dispose(disposing: true);
120 | GC.SuppressFinalize(this);
121 | }
122 | }
123 | }
--------------------------------------------------------------------------------
/DokanNet/Logging/DebugViewLogger.cs:
--------------------------------------------------------------------------------
1 | using System.Globalization;
2 |
3 | namespace DokanNet.Logging
4 | {
5 | ///
6 | /// Write log using OutputDebugString
7 | ///
8 | ///
9 | /// To see the output in visual studio
10 | /// Project + %Properties, Debug tab, check "Enable unmanaged code debugging".
11 | ///
12 | public class DebugViewLogger : ILogger
13 | {
14 | private readonly string _loggerName;
15 | private readonly DateTimeFormatInfo? _dateTimeFormatInfo;
16 |
17 | ///
18 | /// Initializes a new instance of the class.
19 | ///
20 | /// Optional name to be added to each log line.
21 | /// An object that supplies format information for DateTime.
22 | public DebugViewLogger(string loggerName = "", DateTimeFormatInfo? dateTimeFormatInfo = null)
23 | {
24 | _loggerName = loggerName;
25 | _dateTimeFormatInfo = dateTimeFormatInfo;
26 | }
27 |
28 | ///
29 | public bool DebugEnabled => true;
30 |
31 | ///
32 | public void Debug(string message, params object[] args)
33 | {
34 | WriteMessageToDebugView("debug", message, args);
35 | }
36 |
37 | ///
38 | public void Info(string message, params object[] args)
39 | {
40 | WriteMessageToDebugView("info", message, args);
41 | }
42 |
43 | ///
44 | public void Warn(string message, params object[] args)
45 | {
46 | WriteMessageToDebugView("warn", message, args);
47 | }
48 |
49 | ///
50 | public void Error(string message, params object[] args)
51 | {
52 | WriteMessageToDebugView("error", message, args);
53 | }
54 |
55 | ///
56 | public void Fatal(string message, params object[] args)
57 | {
58 | WriteMessageToDebugView("fatal", message, args);
59 | }
60 |
61 | private void WriteMessageToDebugView(string category, string message, params object[] args)
62 | {
63 | if (args?.Length > 0)
64 | {
65 | message = string.Format(message, args);
66 | }
67 |
68 | System.Diagnostics.Debug.WriteLine(message.FormatMessageForLogging(category, _loggerName, _dateTimeFormatInfo));
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/DokanNet/Logging/ILogger.cs:
--------------------------------------------------------------------------------
1 | namespace DokanNet.Logging
2 | {
3 | ///
4 | /// The %Logger interface.
5 | ///
6 | public interface ILogger
7 | {
8 | ///
9 | /// Gets a value indicating whether the logger wishes to receive debug messages.
10 | ///
11 | bool DebugEnabled { get; }
12 |
13 | ///
14 | /// Log a debug message
15 | ///
16 | /// The message to write to the log
17 | /// Arguments to use to format the
18 | void Debug(string message, params object[] args);
19 |
20 | ///
21 | /// Log a info message
22 | ///
23 | /// The message to write to the log
24 | /// Arguments to use to format the
25 | void Info(string message, params object[] args);
26 |
27 | ///
28 | /// Log a warning message
29 | ///
30 | /// The message to write to the log
31 | /// Arguments to use to format the
32 | void Warn(string message, params object[] args);
33 |
34 | ///
35 | /// Log a error message
36 | ///
37 | /// The message to write to the log
38 | /// Arguments to use to format the
39 | void Error(string message, params object[] args);
40 |
41 | ///
42 | /// Log a fatal error message
43 | ///
44 | /// The message to write to the log
45 | /// Arguments to use to format the
46 | void Fatal(string message, params object[] args);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/DokanNet/Logging/Logger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DokanNet.Logging
4 | {
5 | ///
6 | /// Handle log messages with callbacks
7 | ///
8 | public class Logger : ILogger
9 | {
10 | private readonly Action _debug;
11 | private readonly Action _info;
12 | private readonly Action _warn;
13 | private readonly Action _error;
14 | private readonly Action _fatal;
15 |
16 | ///
17 | /// Initializes a new instance of the class.
18 | ///
19 | /// An that are called when a debug log message are arriving.
20 | /// An that are called when a information log message are arriving
21 | /// An that are called when a warning log message are arriving
22 | /// An that are called when a error log message are arriving
23 | /// An that are called when a fatal error log message are arriving
24 | public Logger(
25 | Action debug,
26 | Action info,
27 | Action warn,
28 | Action error,
29 | Action fatal)
30 | {
31 | _debug = debug;
32 | _info = info;
33 | _warn = warn;
34 | _error = error;
35 | _fatal = fatal;
36 | }
37 |
38 | ///
39 | public bool DebugEnabled => _debug != null;
40 |
41 | ///
42 | public void Debug(string message, params object[] args)
43 | {
44 | _debug(message, args);
45 | }
46 |
47 | ///
48 | public void Info(string message, params object[] args)
49 | {
50 | _info(message, args);
51 | }
52 |
53 | ///
54 | public void Warn(string message, params object[] args)
55 | {
56 | _warn(message, args);
57 | }
58 |
59 | ///
60 | public void Error(string message, params object[] args)
61 | {
62 | _error(message, args);
63 | }
64 |
65 | ///
66 | public void Fatal(string message, params object[] args)
67 | {
68 | _fatal(message, args);
69 | }
70 | }
71 | }
--------------------------------------------------------------------------------
/DokanNet/Logging/LoggerExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Text;
4 |
5 | namespace DokanNet.Logging
6 | {
7 | ///
8 | /// Extension functions to log messages.
9 | ///
10 | public static class LoggerExtensions
11 | {
12 | ///
13 | /// Format a log message.
14 | ///
15 | /// Message to format.
16 | /// Optional category to add to the log message.
17 | /// Optional log name to at to the log message.
18 | /// An object that supplies format information for DateTime.
19 | /// A formated log message.
20 | public static string FormatMessageForLogging(
21 | this string message,
22 | string? category = null,
23 | string loggerName = "",
24 | DateTimeFormatInfo? dateTimeFormatInfo = null)
25 | {
26 | return message.FormatMessageForLogging(false, category, loggerName, dateTimeFormatInfo);
27 | }
28 |
29 | ///
30 | /// Format a log message.
31 | ///
32 | /// Message to format.
33 | /// If date and time shout be added to the log message.
34 | /// Optional category to add to the log message.
35 | /// Optional log name to at to the log message.
36 | /// An object that supplies format information for DateTime.
37 | /// A formated log message.
38 | public static string FormatMessageForLogging(
39 | this string message,
40 | bool addDateTime = false,
41 | string? category = null,
42 | string loggerName = "",
43 | DateTimeFormatInfo? dateTimeFormatInfo = null)
44 | {
45 | var stringBuilder = new StringBuilder();
46 | if (addDateTime)
47 | {
48 | stringBuilder.AppendFormat("{0} - ", DateTime.Now.ToString((IFormatProvider?)dateTimeFormatInfo ?? CultureInfo.InvariantCulture));
49 | }
50 |
51 | if (!string.IsNullOrEmpty(loggerName))
52 | {
53 | stringBuilder.Append(loggerName);
54 | }
55 |
56 | if (!string.IsNullOrEmpty(category))
57 | {
58 | stringBuilder.Append($"{category} ");
59 | }
60 |
61 | stringBuilder.Append(message);
62 | return stringBuilder.ToString();
63 | }
64 | }
65 | }
--------------------------------------------------------------------------------
/DokanNet/Logging/NullLogger.cs:
--------------------------------------------------------------------------------
1 | namespace DokanNet.Logging
2 | {
3 | ///
4 | /// Ignore all log messages.
5 | ///
6 | public class NullLogger : ILogger
7 | {
8 | ///
9 | public bool DebugEnabled => false;
10 |
11 | ///
12 | public void Debug(string message, params object[] args)
13 | {
14 | }
15 |
16 | ///
17 | public void Error(string message, params object[] args)
18 | {
19 | }
20 |
21 | ///
22 | public void Fatal(string message, params object[] args)
23 | {
24 | }
25 |
26 | ///
27 | public void Info(string message, params object[] args)
28 | {
29 | }
30 |
31 | ///
32 | public void Warn(string message, params object[] args)
33 | {
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/DokanNet/Logging/TraceLogger.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace DokanNet.Logging
4 | {
5 | ///
6 | /// Write all log messages to the .
7 | ///
8 | public class TraceLogger : ILogger
9 | {
10 | ///
11 | public bool DebugEnabled => true;
12 |
13 | ///
14 | public void Debug(string message, params object[] args)
15 | {
16 | Trace.TraceInformation(message, args);
17 | }
18 |
19 | ///
20 | public void Info(string message, params object[] args)
21 | {
22 | Trace.TraceInformation(message, args);
23 | }
24 |
25 | ///
26 | public void Warn(string message, params object[] args)
27 | {
28 | Trace.TraceWarning(message, args);
29 | }
30 |
31 | ///
32 | public void Error(string message, params object[] args)
33 | {
34 | Trace.TraceError(message, args);
35 | }
36 |
37 | ///
38 | public void Fatal(string message, params object[] args)
39 | {
40 | Trace.TraceError(message, args);
41 | }
42 | }
43 | }
--------------------------------------------------------------------------------
/DokanNet/MockDokanFileInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.Versioning;
2 | using System.Security.Principal;
3 | using DokanNet.Native;
4 | using static DokanNet.FormatProviders;
5 |
6 | #pragma warning disable 649,169
7 |
8 | namespace DokanNet
9 | {
10 | ///
11 | /// Mockable Dokan file information on the current operation.
12 | ///
13 | ///
14 | /// Because cannot be instantiated in C#, it's very difficult to write
15 | /// test harnesses for unit testing. This class implements the same public interface so it's
16 | /// possible to mock it, such that the implementor of IDokanOperations can essentially act like
17 | /// the dokany kernel driver and call into that implementation to verify correct behavior. It
18 | /// also has support methods available to cause it (and the Dokan.Net library) to behave in certain
19 | /// ways useful for testing all potential returns, both success and failure.
20 | ///
21 | #if NET5_0_OR_GREATER
22 | [SupportedOSPlatform("windows")]
23 | #endif
24 | public sealed class MockDokanFileInfo : IDokanFileInfo
25 | {
26 | ///
27 | /// A structure used to help the kernel notification functions work.
28 | ///
29 | private DOKAN_OPTIONS _dokanOptions = new DOKAN_OPTIONS();
30 |
31 | ///
32 | /// This must be set to a potentially valid path. Examples might be @"M:\\" or @"C:\\JunctionPoint".
33 | ///
34 | /// The trailing backslash is not optional for drive letters, and must be omitted for paths.
35 | public string? MountPoint
36 | {
37 | get => _dokanOptions.MountPoint;
38 | set => _dokanOptions.MountPoint = value;
39 | }
40 |
41 | ///
42 | /// Gets or sets context that can be used to carry information between operation.
43 | /// The Context can carry an arbitrary type, like , struct, int,
44 | /// or internal reference that will help the implementation understand the request context of the event.
45 | ///
46 | public object? Context
47 | {
48 | get; set;
49 | }
50 |
51 | ///
52 | /// Process id for the thread that originally requested a given I/O
53 | /// operation.
54 | ///
55 | public int ProcessId { get; set; }
56 |
57 | ///
58 | /// Gets or sets a value indicating whether a filename references a directory.
59 | /// Must be set in if the file is to
60 | /// appear to be a folder.
61 | ///
62 | public bool IsDirectory { get; set; }
63 |
64 | ///
65 | /// Gets or sets a value indicating whether the file has to be deleted
66 | /// during the event.
67 | ///
68 | public bool DeletePending { get; set; }
69 |
70 | ///
71 | /// Read or write is paging IO.
72 | ///
73 | public bool PagingIo { get; set; }
74 |
75 | ///
76 | /// Read or write is synchronous IO.
77 | ///
78 | public bool SynchronousIo { get; set; }
79 |
80 | ///
81 | /// Read or write directly from data source without cache.
82 | ///
83 | public bool NoCache { get; set; }
84 |
85 | ///
86 | /// If true, write to the current end of file instead
87 | /// of using the Offset parameter.
88 | ///
89 | public bool WriteToEndOfFile { get; set; }
90 |
91 | ///
92 | /// Set this to null if you want to test against token unavailability.
93 | ///
94 | /// Initialized to the current process token, which is the only
95 | /// token a standard user account can get.
96 | public WindowsIdentity WhatGetRequestorShouldReturn = WindowsIdentity.GetCurrent();
97 |
98 | ///
99 | /// This method needs to be called in to
100 | /// determine what account and what privileges are available to the filesystem client.
101 | ///
102 | /// An with the access token,
103 | /// -or- null if the operation was not successful.
104 | /// This Mock implementation returns .
105 | ///
106 | public WindowsIdentity GetRequestor() => WhatGetRequestorShouldReturn;
107 |
108 | ///
109 | /// Set this to false if you want to test against TryResetTimeout failure
110 | ///
111 | public bool WhatTryResetTimeoutShouldReturn { get; set; }
112 |
113 | ///
114 | /// Extends the time out of the current IO operation in driver.
115 | ///
116 | /// Number of milliseconds to extend with.
117 | /// true if the operation was successful.
118 | /// This Mock implementation returns .
119 | ///
120 | public bool TryResetTimeout(int milliseconds) => WhatTryResetTimeoutShouldReturn;
121 |
122 | /// Returns a string that represents the current object.
123 | /// A string that represents the current object.
124 | public override string ToString()
125 | {
126 | return
127 | DokanFormat(
128 | $"mock: {{{Context}, {DeletePending}, {IsDirectory}, {NoCache}, {PagingIo}, #{ProcessId}, {SynchronousIo}, {WriteToEndOfFile}}}");
129 | }
130 | }
131 | }
132 |
133 | #pragma warning restore 649, 169
--------------------------------------------------------------------------------
/DokanNet/Native/BY_HANDLE_FILE_INFORMATION.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 | using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
3 |
4 | namespace DokanNet.Native;
5 |
6 | ///
7 | /// Contains information that the function retrieves.
8 | ///
9 | ///
10 | /// The identifier that is stored in the nFileIndexHigh and nFileIndexLow members is called the file ID.
11 | /// Support for file IDs is file system-specific. File IDs are not guaranteed to be unique over time,
12 | /// because file systems are free to reuse them. In some cases, the file ID for a file can change over time.
13 | ///
14 | /// In the FAT file system, the file ID is generated from the first cluster of the containing directory
15 | /// and the byte offset within the directory of the entry for the file. Some defragmentation products
16 | /// change this byte offset. (Windows in-box defragmentation does not.) Thus, a FAT file ID can change
17 | /// over time.Renaming a file in the FAT file system can also change the file ID, but only if the new
18 | /// file name is longer than the old one.
19 | ///
20 | /// In the NTFS file system, a file keeps the same file ID until it is deleted. You can replace one file
21 | /// with another file without changing the file ID by using the ReplaceFile function. However, the file ID
22 | /// of the replacement file, not the replaced file, is retained as the file ID of the resulting file.
23 | ///
24 | /// Not all file systems can record creation and last access time, and not all file systems record them
25 | /// in the same manner. For example, on a Windows FAT file system, create time has a resolution of
26 | /// 10 milliseconds, write time has a resolution of 2 seconds, and access time has a resolution of
27 | /// 1 day (the access date). On the NTFS file system, access time has a resolution of 1 hour.
28 | ///
29 | /// \see BY_HANDLE_FILE_INFORMATION structure (MSDN)
30 | [StructLayout(LayoutKind.Sequential, Pack = 4)]
31 | internal struct BY_HANDLE_FILE_INFORMATION
32 | {
33 | ///
34 | /// The file attributes. For possible values and their descriptions.
35 | ///
36 | public uint dwFileAttributes;
37 |
38 | ///
39 | /// A structure that specifies when a file or directory is created.
40 | /// If the underlying file system does not support creation time, this member is zero (0).
41 | ///
42 | public FILETIME ftCreationTime;
43 |
44 | ///
45 | /// A structure.
46 | /// For a file, the structure specifies the last time that a file is read from or written to.
47 | /// For a directory, the structure specifies when the directory is created.
48 | /// For both files and directories, the specified date is correct, but the time of day is always set to midnight.
49 | /// If the underlying file system does not support the last access time, this member is zero (0).
50 | ///
51 | public FILETIME ftLastAccessTime;
52 |
53 | ///
54 | /// A structure.
55 | /// For a file, the structure specifies the last time that a file is written to.
56 | /// For a directory, the structure specifies when the directory is created.
57 | /// If the underlying file system does not support the last write time, this member is zero (0).
58 | ///
59 | public FILETIME ftLastWriteTime;
60 |
61 | ///
62 | /// The serial number of the volume that contains a file.
63 | ///
64 | public uint dwVolumeSerialNumber;
65 |
66 | ///
67 | /// The high-order part of the file size.
68 | ///
69 | public uint nFileSizeHigh;
70 |
71 | ///
72 | /// The low-order part of the file size.
73 | ///
74 | public uint nFileSizeLow;
75 |
76 | ///
77 | /// The number of links to this file.
78 | /// For the FAT file system this member is always 1.
79 | /// For the NTFS file system, it can be more than 1.
80 | ///
81 | public int dwNumberOfLinks;
82 |
83 | ///
84 | /// The high-order part of a unique identifier that is associated with a file.
85 | /// For more information, see .
86 | ///
87 | public uint nFileIndexHigh;
88 |
89 | ///
90 | /// The low-order part of a unique identifier that is associated with a file.
91 | ///
92 | /// The identifier (low and high parts) and the volume serial number uniquely
93 | /// identify a file on a single computer. To determine whether two open handles
94 | /// represent the same file, combine the identifier and the volume serial number
95 | /// for each file and compare them.
96 | ///
97 | /// The ReFS file system, introduced with Windows Server 2012, includes 128-bit
98 | /// file identifiers. To retrieve the 128-bit file identifier use the
99 | /// GetFileInformationByHandleEx function with FileIdInfo to retrieve
100 | /// the FILE_ID_INFO structure. The 64-bit identifier in this structure is not
101 | /// guaranteed to be unique on ReFS.
102 | ///
103 | public uint nFileIndexLow;
104 | }
105 |
--------------------------------------------------------------------------------
/DokanNet/Native/DOKAN_OPTIONS.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.InteropServices;
2 |
3 | namespace DokanNet.Native;
4 |
5 | ///
6 | /// Dokan mount options used to describe dokan device behaviour
7 | ///
8 | ///
9 | /// This is the same structure as PDOKAN_OPTIONS (dokan.h) in the C version of Dokan.
10 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
11 | public sealed class DOKAN_OPTIONS
12 | {
13 | ///
14 | /// Version of the dokan features requested (version "123" is equal to Dokan version 1.2.3).
15 | ///
16 | public ushort Version { get; set; }
17 |
18 | ///
19 | /// Only use a single thread to process events. This is highly not recommended as can easily create a bottleneck.
20 | ///
21 | [field: MarshalAs(UnmanagedType.U1)]
22 | public bool SingleThread { get; set; }
23 |
24 | ///
25 | /// Features enable for the mount. See .
26 | ///
27 | public DokanOptions Options { get; set; }
28 |
29 | ///
30 | /// FileSystem can store anything here.
31 | ///
32 | public ulong GlobalContext { get; set; }
33 |
34 | ///
35 | /// Mount point.
36 | /// Can be M:\\(drive letter) or C:\\mount\\dokan (path in NTFS).
37 | ///
38 | [field: MarshalAs(UnmanagedType.LPWStr)]
39 | public string? MountPoint { get; set; }
40 |
41 | ///
42 | /// UNC name used for network volume.
43 | ///
44 | [field: MarshalAs(UnmanagedType.LPWStr)]
45 | public string? UNCName { get; set; }
46 |
47 | private uint Timeout;
48 | ///
49 | /// Max timeout in milliseconds of each request before Dokan give up.
50 | ///
51 | public System.TimeSpan TimeOut
52 | {
53 | get => System.TimeSpan.FromMilliseconds(Timeout);
54 | set => Timeout = (uint)value.TotalMilliseconds;
55 | }
56 |
57 | ///
58 | /// Allocation Unit Size of the volume. This will behave on the file size.
59 | ///
60 | public int AllocationUnitSize { get; set; }
61 |
62 | ///
63 | /// Sector Size of the volume. This will behave on the file size.
64 | ///
65 | public int SectorSize { get; set; }
66 | ///
67 | /// Length of the optional VolumeSecurityDescriptor provided. Set 0 will disable the option.
68 | ///
69 | public int VolumeSecurityDescriptorLength { get; set; }
70 |
71 | ///
72 | /// Optional Volume Security descriptor. See InitializeSecurityDescriptor
73 | ///
74 | [field: MarshalAs(UnmanagedType.ByValArray, SizeConst = 16384, ArraySubType = UnmanagedType.U1)]
75 | public byte[]? VolumeSecurityDescriptor { get; set; }
76 | }
77 |
--------------------------------------------------------------------------------
/DokanNet/Native/SECURITY_INFORMATION.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DokanNet.Native
4 | {
5 | ///
6 | /// Identifies the object-related security information being set or queried.
7 | /// This security information includes:
8 | ///
9 | /// - The owner of an object.
10 | /// - The primary group of an object.
11 | /// - The discretionary access control list(DACL) of an object.
12 | /// - The system access control list(SACL) of an object.
13 | ///
14 | ///
15 | /// Structure taken from pinvoke.net
16 | /// \see SECURITY_INFORMATION (MSDN)
17 | [Flags]
18 | internal enum SECURITY_INFORMATION : uint
19 | {
20 | ///
21 | /// The owner identifier of the object is being referenced.
22 | ///
23 | OWNER_SECURITY_INFORMATION = 0x00000001,
24 |
25 | ///
26 | /// The primary group identifier of the object is being referenced.
27 | ///
28 | GROUP_SECURITY_INFORMATION = 0x00000002,
29 |
30 | ///
31 | /// The DACL of the object is being referenced.
32 | ///
33 | DACL_SECURITY_INFORMATION = 0x00000004,
34 |
35 | ///
36 | /// The SACL of the object is being referenced.
37 | ///
38 | SACL_SECURITY_INFORMATION = 0x00000008,
39 |
40 | ///
41 | /// The SACL inherits ACEs from the parent object.
42 | ///
43 | /// Dokan may not be passing Label ?? 0x00000010
44 | UNPROTECTED_SACL_SECURITY_INFORMATION = 0x10000000,
45 |
46 | ///
47 | /// The DACL inherits ACEs from the parent object.
48 | ///
49 | UNPROTECTED_DACL_SECURITY_INFORMATION = 0x20000000,
50 |
51 | ///
52 | /// The SACL cannot inherit ACEs.
53 | ///
54 | PROTECTED_SACL_SECURITY_INFORMATION = 0x40000000,
55 |
56 | ///
57 | /// The DACL cannot inherit access control entries (ACEs).
58 | ///
59 | PROTECTED_DACL_SECURITY_INFORMATION = 0x80000000
60 | }
61 | }
--------------------------------------------------------------------------------
/DokanNet/Native/WIN32_FIND_DATA.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 | using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;
5 |
6 | namespace DokanNet.Native;
7 |
8 | ///
9 | /// Contains information about the file that is found by the FindFirstFile, FindFirstFileEx, or FindNextFile function.
10 | ///
11 | ///
12 | /// If a file has a long file name, the complete name appears in the cFileName member, and the 8.3 format truncated version
13 | /// of the name appears in the member. Otherwise, is empty. If the FindFirstFileEx function
14 | /// was called with a value of FindExInfoBasic in the fInfoLevelId parameter, the member will always contain
15 | /// a NULL string value. This remains true for all subsequent calls to the FindNextFile function. As an alternative method of
16 | /// retrieving the 8.3 format version of a file name, you can use the GetShortPathName function. For more information about
17 | /// file names, see Naming Files, Paths, and Namespaces (MSDN).
18 | ///
19 | /// Not all file systems can record creation and last access times, and not all file systems record them in the same manner.
20 | /// For example, on the FAT file system, create time has a resolution of 10 milliseconds, write time has a resolution of
21 | /// 2 seconds, and access time has a resolution of 1 day. The NTFS file system delays updates to the last access time for
22 | /// a file by up to 1 hour after the last access.For more information, see File Times (MSDN).
23 | ///
24 | /// \see WIN32_FIND_DATA structure (MSDN)
25 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
26 | internal struct WIN32_FIND_DATA
27 | {
28 | ///
29 | /// The file attributes of a file.
30 | ///
31 | /// For possible values and their descriptions, see .
32 | /// The attribute on the file is set if any of
33 | /// the streams of the file have ever been sparse.
34 | ///
35 | public FileAttributes dwFileAttributes;
36 |
37 | ///
38 | /// A structure that specifies when a file or directory was created.
39 | /// If the underlying file system does not support creation time, this member is zero.
40 | ///
41 | public FILETIME ftCreationTime;
42 |
43 | ///
44 | /// A structure.
45 | ///
46 | /// For a file, the structure specifies when the file was last read from, written to, or for executable files, run.
47 | ///
48 | /// For a directory, the structure specifies when the directory is created.
49 | /// If the underlying file system does not support last access time, this member is zero.
50 | ///
51 | /// On the FAT file system, the specified date for both files and directories is correct,
52 | /// but the time of day is always set to midnight.
53 | ///
54 | public FILETIME ftLastAccessTime;
55 |
56 | ///
57 | /// A structure.
58 | ///
59 | /// For a file, the structure specifies when the file was last written to,
60 | /// truncated, or overwritten, for example, when WriteFile or SetEndOfFile
61 | /// are used. The date and time are not updated when file attributes or
62 | /// security descriptors are changed.
63 | ///
64 | /// For a directory, the structure specifies when the directory is created.
65 | /// If the underlying file system does not support last write time,
66 | /// this member is zero.
67 | ///
68 | public FILETIME ftLastWriteTime;
69 |
70 | ///
71 | /// The high-order DWORD value of the file size, in bytes.
72 | ///
73 | /// This value is zero unless the file size is greater than MAXDWORD.
74 | ///
75 | /// The size of the file is equal to (nFileSizeHigh* (MAXDWORD+1)) + nFileSizeLow.
76 | ///
77 | public uint nFileSizeHigh;
78 |
79 | ///
80 | /// The low-order DWORD value of the file size, in bytes.
81 | ///
82 | public uint nFileSizeLow;
83 |
84 | ///
85 | /// If the member includes the attribute,
86 | /// this member specifies the reparse point tag.
87 | /// Otherwise, this value is undefined and should not be used.
88 | ///
89 | /// \see Reparse Point Tags (MSDN)
90 | private readonly uint dwReserved0;
91 |
92 | ///
93 | /// Reserved for future use.
94 | ///
95 | private readonly uint dwReserved1;
96 |
97 | ///
98 | /// The name of the file.
99 | ///
100 | public unsafe fixed char cFileName[260];
101 |
102 | #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP
103 | public unsafe ReadOnlySpan FileName
104 | {
105 | set => value.CopyTo(MemoryMarshal.CreateSpan(ref cFileName[0], 260));
106 | }
107 | #else
108 | public unsafe ReadOnlySpan FileName
109 | {
110 | set
111 | {
112 | fixed (char* ptr = cFileName)
113 | {
114 | value.CopyTo(new(ptr, 260));
115 | }
116 | }
117 | }
118 | #endif
119 |
120 | ///
121 | /// An alternative name for the file.
122 | /// This name is in the classic 8.3 file name format.
123 | ///
124 | public unsafe fixed char cAlternateFileName[14];
125 |
126 | #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP
127 | public unsafe ReadOnlySpan AlternateFileName
128 | {
129 | set => value.CopyTo(MemoryMarshal.CreateSpan(ref cAlternateFileName[0], 14));
130 | }
131 | #else
132 | public unsafe ReadOnlySpan AlternateFileName
133 | {
134 | set
135 | {
136 | fixed (char* ptr = cAlternateFileName)
137 | {
138 | value.CopyTo(new(ptr, 14));
139 | }
140 | }
141 | }
142 | #endif
143 |
144 | ///
145 | /// Obsolete. Do not use.
146 | ///
147 | public uint dwFileType;
148 |
149 | ///
150 | /// Obsolete. Do not use.
151 | ///
152 | public uint dwCreatorType;
153 |
154 | ///
155 | /// Obsolete. Do not use.
156 | ///
157 | public ushort wFinderFlags;
158 | }
159 |
--------------------------------------------------------------------------------
/DokanNet/Native/WIN32_FIND_STREAM_DATA.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.InteropServices;
3 |
4 | namespace DokanNet.Native;
5 |
6 | ///
7 | /// Contains information about the stream found by the FindFirstStreamW (MSDN)
8 | /// or FindNextStreamW (MSDN) function.
9 | ///
10 | /// \see WIN32_FIND_STREAM_DATA structure (MSDN)
11 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 4)]
12 | internal struct WIN32_FIND_STREAM_DATA
13 | {
14 | ///
15 | /// A long value that specifies the size of the stream, in bytes.
16 | ///
17 | public long StreamSize { get; set; }
18 |
19 | ///
20 | /// The name of the stream. The string name format is ":streamname:$streamtype".
21 | ///
22 | public unsafe fixed char cStreamName[260];
23 |
24 | #if NETSTANDARD2_1_OR_GREATER || NETCOREAPP
25 | public unsafe ReadOnlySpan StreamName
26 | {
27 | set => value.CopyTo(MemoryMarshal.CreateSpan(ref cStreamName[0], 260));
28 | }
29 | #else
30 | public unsafe ReadOnlySpan StreamName
31 | {
32 | set
33 | {
34 | fixed (char* ptr = cStreamName)
35 | {
36 | value.CopyTo(new(ptr, 260));
37 | }
38 | }
39 | }
40 | #endif
41 | }
42 |
--------------------------------------------------------------------------------
/DokanNet/NullFormatProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace DokanNet
4 | {
5 | ///
6 | /// Provide support to format object with null.
7 | ///
8 | public class FormatProviders : IFormatProvider, ICustomFormatter
9 | {
10 | ///
11 | /// A Singleton instance of this class.
12 | ///
13 | public static readonly FormatProviders DefaultFormatProvider = new FormatProviders();
14 |
15 | ///
16 | /// A constant string that represents what to use if the formated object is null.
17 | ///
18 | public const string NullStringRepresentation = "";
19 |
20 | ///
21 | /// Prevents a default instance of the class from being created.
22 | ///
23 | private FormatProviders()
24 | {
25 | }
26 |
27 | ///
28 | /// Format a using .
29 | ///
30 | /// The to format.
31 | /// The formated string.
32 | #pragma warning disable 3001
33 | public static string DokanFormat(FormattableString formattable)
34 | => formattable.ToString(DefaultFormatProvider);
35 | #pragma warning restore 3001
36 |
37 | ///
38 | /// Returns an object that provides formatting services for the
39 | /// specified type.
40 | ///
41 | /// An instance of the object specified by
42 | /// , if the
43 | /// implementation can supply
44 | /// that type of object; otherwise, null.
45 | /// An object that specifies the type of format
46 | /// object to return.
47 | public object? GetFormat(Type? formatType)
48 | {
49 | return formatType == typeof(ICustomFormatter) ? this : null;
50 | }
51 |
52 | ///
53 | /// Converts the value of a specified object to an equivalent string
54 | /// representation using specified format and culture-specific
55 | /// formatting information.
56 | ///
57 | /// The string representation of the value of
58 | /// , formatted as specified by
59 | /// and .
60 | ///
61 | /// A format string containing formatting
62 | /// specifications.
63 | /// An object to format.
64 | /// An object that supplies format
65 | /// information about the current instance.
66 | public string Format(string? format, object? arg, IFormatProvider? formatProvider)
67 | {
68 | if (arg == null)
69 | {
70 | return NullStringRepresentation;
71 | }
72 |
73 | var formattable = arg as IFormattable;
74 |
75 | return formattable?.ToString(format, formatProvider)
76 | ?? arg.ToString() ?? "";
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/DokanNet/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.CompilerServices;
2 |
3 | // Make internals visible to tests.
4 | [assembly: InternalsVisibleTo("DokanNet.Tests")]
5 |
--------------------------------------------------------------------------------
/DokanNet/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace DokanNet.Properties {
12 | using System;
13 | using System.Reflection;
14 |
15 |
16 | ///
17 | /// A strongly-typed resource class, for looking up localized strings, etc.
18 | ///
19 | // This class was auto-generated by the StronglyTypedResourceBuilder
20 | // class via a tool like ResGen or Visual Studio.
21 | // To add or remove a member, edit your .ResX file then rerun ResGen
22 | // with the /str option, or rebuild your VS project.
23 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
24 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
25 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
26 | internal class Resources {
27 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources() {
34 | }
35 |
36 | ///
37 | /// Returns the cached ResourceManager instance used by this class.
38 | ///
39 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
40 | internal static global::System.Resources.ResourceManager ResourceManager {
41 | get {
42 | if (object.ReferenceEquals(resourceMan, null)) {
43 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DokanNet.Properties.Resources", typeof(Resources).GetTypeInfo().Assembly);
44 | resourceMan = temp;
45 | }
46 | return resourceMan;
47 | }
48 | }
49 |
50 | ///
51 | /// Overrides the current thread's CurrentUICulture property for all
52 | /// resource lookups using this strongly typed resource class.
53 | ///
54 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
55 | internal static global::System.Globalization.CultureInfo Culture {
56 | get {
57 | return resourceCulture;
58 | }
59 | set {
60 | resourceCulture = value;
61 | }
62 | }
63 |
64 | ///
65 | /// Looks up a localized string similar to Can't assign a drive letter or mount point.
66 | ///
67 | internal static string ErrorAssignDriveLetter {
68 | get {
69 | return ResourceManager.GetString("ErrorAssignDriveLetter", resourceCulture);
70 | }
71 | }
72 |
73 | ///
74 | /// Looks up a localized string similar to Bad drive letter.
75 | ///
76 | internal static string ErrorBadDriveLetter {
77 | get {
78 | return ResourceManager.GetString("ErrorBadDriveLetter", resourceCulture);
79 | }
80 | }
81 |
82 | ///
83 | /// Looks up a localized string similar to Dokan error.
84 | ///
85 | internal static string ErrorDokan {
86 | get {
87 | return ResourceManager.GetString("ErrorDokan", resourceCulture);
88 | }
89 | }
90 |
91 | ///
92 | /// Looks up a localized string similar to Can't install the Dokan driver.
93 | ///
94 | internal static string ErrorDriverInstall {
95 | get {
96 | return ResourceManager.GetString("ErrorDriverInstall", resourceCulture);
97 | }
98 | }
99 |
100 | ///
101 | /// Looks up a localized string similar to Mount point is invalid.
102 | ///
103 | internal static string ErrorMountPointInvalid {
104 | get {
105 | return ResourceManager.GetString("ErrorMountPointInvalid", resourceCulture);
106 | }
107 | }
108 |
109 | ///
110 | /// Looks up a localized string similar to Something's wrong with the Dokan driver.
111 | ///
112 | internal static string ErrorStart {
113 | get {
114 | return ResourceManager.GetString("ErrorStart", resourceCulture);
115 | }
116 | }
117 |
118 | ///
119 | /// Looks up a localized string similar to Unknown error.
120 | ///
121 | internal static string ErrorUnknown {
122 | get {
123 | return ResourceManager.GetString("ErrorUnknown", resourceCulture);
124 | }
125 | }
126 |
127 | ///
128 | /// Looks up a localized string similar to Version error.
129 | ///
130 | internal static string ErrorVersion {
131 | get {
132 | return ResourceManager.GetString("ErrorVersion", resourceCulture);
133 | }
134 | }
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/DokanNet/Properties/Resources.de.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Ungültiger Laufwerksbuchstabe
122 |
123 |
124 | Der Dokan Driver kann nicht installiert werden
125 |
126 |
127 | Das Laufwerk bzw. die Verknüpfung kann nicht zugewiesen werden.
128 |
129 |
130 | Es ist ein Fehler im Dokan Treiber aufgetreten
131 |
132 |
133 | Die Verknüpfung ist ungültig
134 |
135 |
136 | Version Fehler
137 |
138 |
139 | Dokan Fehler
140 |
141 |
--------------------------------------------------------------------------------
/DokanNet/Properties/Resources.fr.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 | text/microsoft-resx
90 |
91 |
92 | 1.3
93 |
94 |
95 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
96 |
97 |
98 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
99 |
100 |
101 | Mauvaise lettre de lecteur
102 |
103 |
104 | Impossible d'installer le driver Dokan
105 |
106 |
107 | Impossible d'assigner la lettre ou le point de montage
108 |
109 |
110 | Il y a eu une erreur dans le driver Dokan
111 |
112 |
113 | Le point de montage est invalide
114 |
115 |
116 | Erreur de version
117 |
118 |
119 | Erreur Dokan
120 |
121 |
--------------------------------------------------------------------------------
/DokanNet/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Bad drive letter
122 |
123 |
124 | Can't install the Dokan driver
125 |
126 |
127 | Can't assign a drive letter or mount point
128 |
129 |
130 | Something's wrong with the Dokan driver
131 |
132 |
133 | Mount point is invalid
134 |
135 |
136 | Version error
137 |
138 |
139 | Dokan error
140 |
141 |
142 | Unknown error
143 |
144 |
--------------------------------------------------------------------------------
/DokanNet/Properties/Resources.sv.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | Felaktig enhetsbokstav
122 |
123 |
124 | Kan inte installera Dokan-drivrutinen
125 |
126 |
127 | Kan inte tilldela en enhetsbokstav eller monteringspunkt
128 |
129 |
130 | Något är fel med Dokan-drivrutinen
131 |
132 |
133 | Monteringspunkt är felaktig
134 |
135 |
136 | Versionsfel
137 |
138 |
139 | Dokan-fel
140 |
141 |
142 | Okänt fel
143 |
144 |
--------------------------------------------------------------------------------
/DokanNet/documentations/mainpage.md:
--------------------------------------------------------------------------------
1 | Dokan-dotnet Doxygen {#mainpage}
2 | ==================================================
3 |
4 | This is the homepage of the Doxygen generated documentation for
5 | Dokan-dotnet.
6 |
7 | Dokan-dotnet is a wrapper for Dokan User mode file system library.
8 |
9 | We recommend you take a look at [our wiki](https://github.com/dokan-dev/dokany/wiki) for
10 | an introduction of how to use Dokan.
11 | You may find Mirror and RegistryFS samples [here](https://github.com/dokan-dev/dokan-dotnet/tree/master/sample) useful.
12 |
--------------------------------------------------------------------------------
/DokanNet/documentations/resources/customdoxygen.css:
--------------------------------------------------------------------------------
1 | h1, .h1, h2, .h2, h3, .h3{
2 | font-weight: 200 !important;
3 | }
4 |
5 | #navrow1, #navrow2, #navrow3, #navrow4, #navrow5{
6 | border-bottom: 1px solid #EEEEEE;
7 | }
8 |
9 | .adjust-right {
10 | margin-left: 30px !important;
11 | font-size: 1.15em !important;
12 | }
13 | .navbar{
14 | border: 0px solid #222 !important;
15 | }
16 | table{
17 | white-space:pre-wrap !important;
18 | }
19 | /*
20 | ===========================
21 | */
22 |
23 |
24 | /* Sticky footer styles
25 | -------------------------------------------------- */
26 | html,
27 | body {
28 | height: 100%;
29 | /* The html and body elements cannot have any padding or margin. */
30 | }
31 |
32 | /* Wrapper for page content to push down footer */
33 | #wrap {
34 | min-height: 100%;
35 | height: auto;
36 | /* Negative indent footer by its height */
37 | margin: 0 auto -60px;
38 | /* Pad bottom by footer height */
39 | padding: 0 0 60px;
40 | }
41 |
42 | /* Set the fixed height of the footer here */
43 | #footer {
44 | font-size: 0.9em;
45 | padding: 8px 0px;
46 | background-color: #f5f5f5;
47 | }
48 |
49 | .footer-row {
50 | line-height: 44px;
51 | }
52 |
53 | #footer > .container {
54 | padding-left: 15px;
55 | padding-right: 15px;
56 | }
57 |
58 | .footer-follow-icon {
59 | margin-left: 3px;
60 | text-decoration: none !important;
61 | }
62 |
63 | .footer-follow-icon img {
64 | width: 20px;
65 | }
66 |
67 | .footer-link {
68 | padding-top: 5px;
69 | display: inline-block;
70 | color: #999999;
71 | text-decoration: none;
72 | }
73 |
74 | .footer-copyright {
75 | text-align: center;
76 | }
77 |
78 |
79 | @media (min-width: 992px) {
80 | .footer-row {
81 | text-align: left;
82 | }
83 |
84 | .footer-icons {
85 | text-align: right;
86 | }
87 | }
88 | @media (max-width: 991px) {
89 | .footer-row {
90 | text-align: center;
91 | }
92 |
93 | .footer-icons {
94 | text-align: center;
95 | }
96 | }
97 |
98 | /* DOXYGEN Code Styles
99 | ----------------------------------- */
100 |
101 |
102 | a.qindex {
103 | font-weight: bold;
104 | }
105 |
106 | a.qindexHL {
107 | font-weight: bold;
108 | background-color: #9CAFD4;
109 | color: #ffffff;
110 | border: 1px double #869DCA;
111 | }
112 |
113 | .contents a.qindexHL:visited {
114 | color: #ffffff;
115 | }
116 |
117 | a.code, a.code:visited, a.line, a.line:visited {
118 | color: #4665A2;
119 | }
120 |
121 | a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
122 | color: #4665A2;
123 | }
124 |
125 | /* @end */
126 |
127 | dl.el {
128 | margin-left: -1cm;
129 | }
130 |
131 | pre.fragment {
132 | border: 1px solid #C4CFE5;
133 | background-color: #FBFCFD;
134 | padding: 4px 6px;
135 | margin: 4px 8px 4px 2px;
136 | overflow: auto;
137 | word-wrap: break-word;
138 | font-size: 9pt;
139 | line-height: 125%;
140 | font-family: monospace, fixed;
141 | font-size: 105%;
142 | }
143 |
144 | div.fragment {
145 | padding: 4px 6px;
146 | margin: 4px 8px 4px 2px;
147 | border: 1px solid #C4CFE5;
148 | }
149 |
150 | div.line {
151 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
152 | font-size: 12px;
153 | min-height: 13px;
154 | line-height: 1.0;
155 | text-wrap: unrestricted;
156 | white-space: -moz-pre-wrap; /* Moz */
157 | white-space: -pre-wrap; /* Opera 4-6 */
158 | white-space: -o-pre-wrap; /* Opera 7 */
159 | white-space: pre-wrap; /* CSS3 */
160 | word-wrap: normal; /* IE 5.5+ */
161 | text-indent: -53px;
162 | padding-left: 53px;
163 | padding-bottom: 0px;
164 | margin: 0px;
165 | -webkit-transition-property: background-color, box-shadow;
166 | -webkit-transition-duration: 0.5s;
167 | -moz-transition-property: background-color, box-shadow;
168 | -moz-transition-duration: 0.5s;
169 | -ms-transition-property: background-color, box-shadow;
170 | -ms-transition-duration: 0.5s;
171 | -o-transition-property: background-color, box-shadow;
172 | -o-transition-duration: 0.5s;
173 | transition-property: background-color, box-shadow;
174 | transition-duration: 0.5s;
175 | }
176 | div.line:hover{
177 | background-color: #FBFF00;
178 | }
179 |
180 | div.line.glow {
181 | background-color: cyan;
182 | box-shadow: 0 0 10px cyan;
183 | }
184 |
185 |
186 | span.lineno {
187 | padding-right: 4px;
188 | text-align: right;
189 | color:rgba(0,0,0,0.3);
190 | border-right: 1px solid #EEE;
191 | border-left: 1px solid #EEE;
192 | background-color: #FFF;
193 | white-space: pre;
194 | font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace ;
195 | }
196 | span.lineno a {
197 | background-color: #FAFAFA;
198 | cursor:pointer;
199 | }
200 |
201 | span.lineno a:hover {
202 | background-color: #EFE200;
203 | color: #1e1e1e;
204 | }
205 |
206 | div.groupHeader {
207 | margin-left: 16px;
208 | margin-top: 12px;
209 | font-weight: bold;
210 | }
211 |
212 | div.groupText {
213 | margin-left: 16px;
214 | font-style: italic;
215 | }
216 |
217 | /* @group Code Colorization */
218 |
219 | span.keyword {
220 | color: #008000
221 | }
222 |
223 | span.keywordtype {
224 | color: #604020
225 | }
226 |
227 | span.keywordflow {
228 | color: #e08000
229 | }
230 |
231 | span.comment {
232 | color: #800000
233 | }
234 |
235 | span.preprocessor {
236 | color: #806020
237 | }
238 |
239 | span.stringliteral {
240 | color: #002080
241 | }
242 |
243 | span.charliteral {
244 | color: #008080
245 | }
246 |
247 | span.vhdldigit {
248 | color: #ff00ff
249 | }
250 |
251 | span.vhdlchar {
252 | color: #000000
253 | }
254 |
255 | span.vhdlkeyword {
256 | color: #700070
257 | }
258 |
259 | span.vhdllogic {
260 | color: #ff0000
261 | }
262 |
263 | blockquote {
264 | background-color: #F7F8FB;
265 | border-left: 2px solid #9CAFD4;
266 | margin: 0 24px 0 4px;
267 | padding: 0 12px 0 16px;
268 | }
269 |
270 | /*---------------- Search Box */
271 |
272 | #search-box {
273 | margin: 10px 0px;
274 | }
275 | #search-box .close {
276 | display: none;
277 | position: absolute;
278 | right: 0px;
279 | padding: 6px 12px;
280 | z-index: 5;
281 | }
282 |
283 | /*---------------- Search results window */
284 |
285 | #search-results-window {
286 | display: none;
287 | }
288 |
289 | iframe#MSearchResults {
290 | width: 100%;
291 | height: 15em;
292 | }
293 |
294 | .SRChildren {
295 | padding-left: 3ex; padding-bottom: .5em
296 | }
297 | .SRPage .SRChildren {
298 | display: none;
299 | }
300 | a.SRScope {
301 | display: block;
302 | }
303 | a.SRSymbol:focus, a.SRSymbol:active,
304 | a.SRScope:focus, a.SRScope:active {
305 | text-decoration: underline;
306 | }
307 | span.SRScope {
308 | padding-left: 4px;
309 | }
310 | .SRResult {
311 | display: none;
312 | }
313 |
314 | /* class and file list */
315 | .directory .icona,
316 | .directory .arrow {
317 | height: auto;
318 | }
319 | .directory .icona .icon {
320 | height: 16px;
321 | }
322 | .directory .icondoc {
323 | background-position: 0px 0px;
324 | height: 20px;
325 | }
326 | .directory .iconfopen {
327 | background-position: 0px 0px;
328 | }
329 | .directory td.entry {
330 | padding: 7px 8px 6px 8px;
331 | }
332 |
333 | .table > tbody > tr > td.memSeparator {
334 | line-height: 0;
335 | .table-hover;
336 |
337 | }
338 |
339 | .memItemLeft, .memTemplItemLeft {
340 | white-space: normal;
341 | }
342 |
343 | /* enumerations */
344 | .panel-body thead > tr {
345 | background-color: #e0e0e0;
346 | }
347 |
348 | /* todo lists */
349 | .todoname,
350 | .todoname a {
351 | font-weight: bold;
352 | }
353 |
354 | /* Class title */
355 | .summary {
356 | margin-top: 25px;
357 | }
358 | .page-header {
359 | margin: 20px 0px !important;
360 | }
361 | .page-header .title {
362 | display: inline-block;
363 | }
364 | .page-header .pull-right {
365 | margin-top: 0.3em;
366 | margin-left: 0.5em;
367 | }
368 | .page-header .label {
369 | font-size: 50%;
370 | }
371 |
--------------------------------------------------------------------------------
/DokanNet/documentations/resources/footer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
24 |
25 |