Skip to content

Commit 15b9cd9

Browse files
authored
IDokanOperations2 library implementation (#374)
IDokanOperations2 library implementation * IDokanOperations2 is a new way to implement Dokan file systems in .NET with less CPU and memory pressure. * Includes several other minor optimizations as well. * Existing IDokanOperation and IDokanOperationUnsafe implementations get wrapped in a compatibility layer called DokanOperationsAdapter, that in turn implements the new IDokanOperations2 interface. * Removed "-windows" suffix from target frameworks to allow library to be consumed by applicaitons that chose between Windows and other OS implementations at runtime. * Removed .NET Framework 4.0 from target frameworks and added 4.6 and 4.8 (last supported on Windows Vista and last supported on Windows 7). * DokanNetMirror with IDokanOperations2. Old DokanNetMirror moved to DokanNetMirrorLegacy. * Added some logic to keep a reference to DokanInstance and associated operations alive while file system is mounted, to avoid crashes in native code if the last reference is collected by GC.
1 parent a1e4a63 commit 15b9cd9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+8894
-5877
lines changed

Directory.Build.props

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<Project>
2+
3+
<PropertyGroup>
4+
<LangVersion>latest</LangVersion>
5+
<Nullable>enable</Nullable>
6+
</PropertyGroup>
7+
8+
</Project>
9+

DokanNet.Tests/BufferPoolTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public void BufferPoolBasicTest()
4242
for (int i = 0; i < 1000; i++)
4343
{
4444
int size = random.Next(0, 2 * MB);
45-
buffer = pool.RentBuffer((uint)size, logger);
45+
buffer = pool.RentBuffer(size, logger);
4646
Assert.AreEqual(size, buffer.Length, "Wrong buffer size.");
4747
pool.ReturnBuffer(buffer, logger);
4848
}

DokanNet.Tests/ContextTests.cs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,15 @@ public static void ClassInitialize(TestContext context)
2424
{
2525
smallData = new byte[4096];
2626
for (var i = 0; i < smallData.Length; ++i)
27-
smallData[i] = (byte) (i%256);
27+
{
28+
smallData[i] = (byte)(i % 256);
29+
}
2830

29-
largeData = new byte[5*FILE_BUFFER_SIZE + 65536];
31+
largeData = new byte[5 * FILE_BUFFER_SIZE + 65536];
3032
for (var i = 0; i < largeData.Length; ++i)
31-
largeData[i] = (byte) (i%251);
33+
{
34+
largeData[i] = (byte)(i % 251);
35+
}
3236
}
3337

3438
[ClassCleanup]
@@ -131,6 +135,11 @@ public void OpenRead_WithLargeFile_PassesContextCorrectly()
131135
do
132136
{
133137
totalReadBytes += stream.Read(target, totalReadBytes, target.Length - totalReadBytes);
138+
139+
if (totalReadBytes == 0)
140+
{
141+
throw new EndOfStreamException("Unexpected end of file");
142+
}
134143
} while (totalReadBytes < largeData.Length);
135144
}
136145

@@ -163,7 +172,7 @@ public void OpenRead_WithLargeFile_InParallel_PassesContextCorrectly()
163172

164173
Parallel.For(0, DokanOperationsFixture.NumberOfChunks(FILE_BUFFER_SIZE, largeData.Length), i =>
165174
{
166-
var origin = i*FILE_BUFFER_SIZE;
175+
var origin = i * FILE_BUFFER_SIZE;
167176
var count = Math.Min(FILE_BUFFER_SIZE, target.Length - origin);
168177
lock (stream)
169178
{
@@ -267,7 +276,7 @@ public void OpenWrite_WithLargeFile_InParallel_PassesContextCorrectly()
267276

268277
Parallel.For(0, DokanOperationsFixture.NumberOfChunks(FILE_BUFFER_SIZE, largeData.Length), i =>
269278
{
270-
var origin = i*FILE_BUFFER_SIZE;
279+
var origin = i * FILE_BUFFER_SIZE;
271280
var count = Math.Min(FILE_BUFFER_SIZE, largeData.Length - origin);
272281
lock (stream)
273282
{

DokanNet.Tests/DirectoryInfoTest.cs

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,15 @@ public void Create_WhereTargetIsFile_CallsApiCorrectly()
219219
fixture.ExpectCreateFile(path.AsRootedPath(), ReadAttributesAccess, ReadWriteShare, FileMode.Open);
220220
fixture.ExpectGetFileInformation(path.AsRootedPath(), FileAttributes.Normal);
221221
fixture.ExpectOpenDirectory(DokanOperationsFixture.RootName, FileAccess.Synchronize, FileShare.None);
222-
fixture.ExpectFindFiles(DokanOperationsFixture.RootName, new[]
223-
{
222+
fixture.ExpectFindFiles(DokanOperationsFixture.RootName,
223+
[
224224
new FileInformation()
225225
{
226226
FileName = path, Attributes = FileAttributes.Normal,
227227
Length = 0,
228228
CreationTime = DateTime.Today, LastWriteTime = DateTime.Today, LastAccessTime = DateTime.Today
229229
}
230-
});
230+
]);
231231
fixture.ExpectCreateDirectoryToFail(path.AsRootedPath(), DokanResult.FileExists);
232232
#endif
233233

@@ -340,7 +340,7 @@ public void Delete_WhereRecurseIsFalse_CallsApiCorrectly()
340340
}
341341

342342
public static IEnumerable<object[]> ConfigFindFilesData
343-
=> new object[][] { new object[] { true }, new object[] { false } };
343+
=> [[true], [false]];
344344

345345
[DataTestMethod, TestCategory(TestCategories.Success), DynamicData(nameof(ConfigFindFilesData))]
346346
public void Delete_WhereRecurseIsTrueAndDirectoryIsNonempty_CallsApiCorrectly(bool supportsPatternSearch)
@@ -358,29 +358,30 @@ public void Delete_WhereRecurseIsTrueAndDirectoryIsNonempty_CallsApiCorrectly(bo
358358
fixture.ExpectOpenDirectory(path);
359359
if (supportsPatternSearch)
360360
{
361-
fixture.ExpectFindFilesWithPattern(path, "*", DokanOperationsFixture.GetEmptyDirectoryDefaultFiles().Concat(new[]
362-
{
361+
fixture.ExpectFindFilesWithPattern(path, "*", DokanOperationsFixture.GetEmptyDirectoryDefaultFiles().Concat(
362+
[
363363
new FileInformation()
364364
{
365365
FileName = subFileName, Attributes = FileAttributes.Normal,
366366
Length = 100,
367367
CreationTime = DateTime.Today, LastWriteTime = DateTime.Today, LastAccessTime = DateTime.Today
368368
}
369-
}).ToArray());
369+
]).ToArray());
370370
}
371371
else
372372
{
373373
fixture.ExpectFindFilesWithPatternToFail(path, "*", DokanResult.NotImplemented);
374-
fixture.ExpectFindFiles(path, DokanOperationsFixture.GetEmptyDirectoryDefaultFiles().Concat(new[]
375-
{
374+
fixture.ExpectFindFiles(path, DokanOperationsFixture.GetEmptyDirectoryDefaultFiles().Concat(
375+
[
376376
new FileInformation()
377377
{
378378
FileName = subFileName, Attributes = FileAttributes.Normal,
379379
Length = 100,
380380
CreationTime = DateTime.Today, LastWriteTime = DateTime.Today, LastAccessTime = DateTime.Today
381381
}
382-
}).ToArray());
382+
]).ToArray());
383383
}
384+
384385
fixture.ExpectCreateFile(path + subFilePath, DeleteAccess, ReadWriteShare, FileMode.Open, deleteOnClose: true);
385386
fixture.ExpectGetFileInformation(path + subFilePath, FileAttributes.Normal);
386387
fixture.ExpectDeleteFile(path + subFilePath);
@@ -418,6 +419,7 @@ public void Delete_WhereRecurseIsTrueAndDirectoryIsEmpty_CallsApiCorrectly(bool
418419
fixture.ExpectFindFilesWithPatternToFail(path, "*", DokanResult.NotImplemented);
419420
fixture.ExpectFindFiles(path, DokanOperationsFixture.GetEmptyDirectoryDefaultFiles());
420421
}
422+
421423
fixture.ExpectOpenDirectory(path, DeleteFromDirectoryAccess);
422424
fixture.ExpectDeleteDirectory(path);
423425
#endif
@@ -939,6 +941,7 @@ public void MoveTo_WhereParentIsDirectory_CallsApiCorrectly()
939941
destination = Path.Combine(fixture.DestinationDirectoryName, fixture.DestinationSubDirectoryName),
940942
path = origin.AsRootedPath(),
941943
destinationPath = destination.AsRootedPath();
944+
942945
#if LOGONLY
943946
fixture.PermitAny();
944947
#else
@@ -1026,13 +1029,14 @@ public void SetAccessControl_CallsApiCorrectly(bool supportsPatternSearch)
10261029
fixture.ExpectOpenDirectory(path.AsRootedPath(), share: FileShare.ReadWrite);
10271030
if (supportsPatternSearch)
10281031
{
1029-
fixture.ExpectFindFilesWithPattern(path.AsRootedPath(), "*", new FileInformation[0]);
1032+
fixture.ExpectFindFilesWithPattern(path.AsRootedPath(), "*", []);
10301033
}
10311034
else
10321035
{
10331036
fixture.ExpectFindFilesWithPatternToFail(path.AsRootedPath(), "*", DokanResult.NotImplemented);
1034-
fixture.ExpectFindFiles(path.AsRootedPath(), new FileInformation[0]);
1037+
fixture.ExpectFindFiles(path.AsRootedPath(), []);
10351038
}
1039+
10361040
fixture.ExpectSetFileSecurity(path.AsRootedPath(), security);
10371041
fixture.ExpectCreateFile(DokanOperationsFixture.RootName, ReadPermissionsAccess, ReadWriteShare, FileMode.Open);
10381042
fixture.ExpectGetFileInformation(DokanOperationsFixture.RootName, FileAttributes.Directory);

DokanNet.Tests/DokanNet.Tests.csproj

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,41 +15,36 @@
1515
net4.6 net4.6
1616
netstandard1.3 <missing>
1717
-->
18-
<TargetFrameworks>net462</TargetFrameworks>
19-
18+
<TargetFrameworks>net48</TargetFrameworks>
2019
<!--Add the Target Framework to the output file names. -->
21-
<AssemblyName>$(MSBuildProjectName).$(TargetFramework)</AssemblyName>
20+
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
2221
<CLSCompliant>True</CLSCompliant>
22+
<Nullable>disable</Nullable>
2323
<!-- We need to sign the test assembly to use it in InternalsVisibleTo for DokanNet.dll. -->
24-
<SignAssembly>true</SignAssembly>
24+
<SignAssembly>false</SignAssembly>
2525
<AssemblyOriginatorKeyFile>..\DokanNet\Dokan.snk</AssemblyOriginatorKeyFile>
2626
</PropertyGroup>
27-
2827
<ItemGroup>
2928
<Content Include="OverlappedTests.Configuration.xml">
3029
<DependentUpon>OverlappedTests.cs</DependentUpon>
3130
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
3231
</Content>
3332
</ItemGroup>
34-
3533
<ItemGroup>
36-
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
34+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.13.0" />
3735
<PackageReference Include="Moq" Version="4.7.1" />
38-
<PackageReference Include="MSTest.TestAdapter" Version="2.2.8" />
39-
<PackageReference Include="MSTest.TestFramework" Version="2.2.8" />
36+
<PackageReference Include="MSTest.TestAdapter" Version="3.8.3" />
37+
<PackageReference Include="MSTest.TestFramework" Version="3.8.3" />
4038
</ItemGroup>
41-
4239
<ItemGroup>
4340
<ProjectReference Include="..\DokanNet\DokanNet.csproj" />
4441
</ItemGroup>
45-
4642
<ItemGroup>
4743
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
4844
</ItemGroup>
49-
5045
<PropertyGroup Condition="'$(Configuration)' == 'Release'">
5146
<CodeAnalysisRuleSet>DokanNet.Tests.ruleset</CodeAnalysisRuleSet>
5247
<!--Set to True to run Code Analysis-->
5348
<RunCodeAnalysis>False</RunCodeAnalysis>
5449
</PropertyGroup>
55-
</Project>
50+
</Project>

0 commit comments

Comments
 (0)