/
FileSystemEnumerator.cs
121 lines (100 loc) · 5.96 KB
/
FileSystemEnumerator.cs
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
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
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
110
111
112
113
114
115
116
117
118
119
120
121
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.ConstrainedExecution;
namespace System.IO.Enumeration
{
/// <summary>Enumerates the file system elements of the provided type that are being searched and filtered by a <see cref="FileSystemEnumerable{T}" />.</summary>
/// <typeparam name="TResult">The type of the result produced by this file system enumerator.</typeparam>
public abstract unsafe partial class FileSystemEnumerator<TResult> : CriticalFinalizerObject, IEnumerator<TResult>
{
private int _remainingRecursionDepth;
/// <summary>Encapsulates a find operation.</summary>
/// <param name="directory">The directory to search in.</param>
/// <param name="options">Enumeration options to use.</param>
public FileSystemEnumerator(string directory, EnumerationOptions? options = null)
: this(directory, isNormalized: false, options)
{
}
/// <summary>
/// Encapsulates a find operation.
/// </summary>
/// <param name="directory">The directory to search in.</param>
/// <param name="isNormalized">Whether the directory path is already normalized or not.</param>
/// <param name="options">Enumeration options to use.</param>
internal FileSystemEnumerator(string directory, bool isNormalized, EnumerationOptions? options = null)
{
ArgumentNullException.ThrowIfNull(directory);
_originalRootDirectory = directory;
string path = isNormalized ? directory : Path.GetFullPath(directory);
_rootDirectory = Path.TrimEndingDirectorySeparator(path);
_options = options ?? EnumerationOptions.Default;
_remainingRecursionDepth = _options.MaxRecursionDepth;
Init();
}
/// <summary>When overridden in a derived class, determines whether the specified file system entry should be included in the results.</summary>
/// <param name="entry">A file system entry reference.</param>
/// <returns><see langword="true" /> if the specified file system entry should be included in the results; otherwise, <see langword="false" />.</returns>
protected virtual bool ShouldIncludeEntry(ref FileSystemEntry entry) => true;
/// <summary>When overridden in a derived class, determines whether the specified file system entry should be recursed.</summary>
/// <param name="entry">A file system entry reference.</param>
/// <returns><see langword="true" /> if the specified directory entry should be recursed into; otherwise, <see langword="false" />.</returns>
protected virtual bool ShouldRecurseIntoEntry(ref FileSystemEntry entry) => true;
/// <summary>When overridden in a derived class, generates the result type from the current entry.</summary>
/// <param name="entry">A file system entry reference.</param>
/// <returns>The result type from the current entry.</returns>
protected abstract TResult TransformEntry(ref FileSystemEntry entry);
/// <summary>When overridden in a derived class, this method is called whenever the end of a directory is reached.</summary>
/// <param name="directory">The directory path as a read-only span.</param>
protected virtual void OnDirectoryFinished(ReadOnlySpan<char> directory) { }
/// <summary>When overridden in a derived class, returns a value that indicates whether to continue execution or throw the default exception.</summary>
/// <param name="error">The native error code.</param>
/// <returns><see langword="true" /> to continue; <see langword="false" /> to throw the default exception for the given error.</returns>
protected virtual bool ContinueOnError(int error) => false;
/// <summary>Gets the currently visited element.</summary>
/// <value>The currently visited element.</value>
public TResult Current => _current!;
/// <summary>Gets the currently visited object.</summary>
/// <value>The currently visited object.</value>
/// <remarks>This member is an explicit interface member implementation. It can be used only when the <see cref="FileSystemEnumerator{T}" /> instance is cast to an <see cref="System.Collections.IEnumerator" /> interface.</remarks>
object? IEnumerator.Current => Current;
private void DirectoryFinished()
{
_entry = default;
// Close the handle now that we're done
CloseDirectoryHandle();
OnDirectoryFinished(_currentPath.AsSpan());
// Attempt to grab another directory to process
if (!DequeueNextDirectory())
{
_lastEntryFound = true;
}
else
{
FindNextEntry();
}
}
/// <summary>Always throws <see cref="System.NotSupportedException" />.</summary>
public void Reset()
{
throw new NotSupportedException();
}
/// <summary>Releases the resources used by the current instance of the <see cref="Enumeration.FileSystemEnumerator{T}" /> class.</summary>
public void Dispose()
{
InternalDispose(disposing: true);
GC.SuppressFinalize(this);
}
/// <summary>When overridden in a derived class, releases the unmanaged resources used by the <see cref="Enumeration.FileSystemEnumerator{T}" /> class and optionally releases the managed resources.</summary>
/// <param name="disposing"><see langword="true" /> to release both managed and unmanaged resources; <see langword="false" /> to release only unmanaged resources.</param>
protected virtual void Dispose(bool disposing)
{
}
~FileSystemEnumerator()
{
InternalDispose(disposing: false);
}
}
}