Classify NTFS paths via DFS metadata
This commit is contained in:
@@ -47,6 +47,7 @@ namespace C4IT.LIAM
|
||||
public eNtfsPathKind Kind { get; set; } = eNtfsPathKind.Unknown;
|
||||
public string BoundaryPath { get; set; } = string.Empty;
|
||||
public string ParentBoundaryPath { get; set; } = string.Empty;
|
||||
public string ParentPath { get; set; } = string.Empty;
|
||||
public string DisplayName { get; set; } = string.Empty;
|
||||
public int Level { get; set; } = -1;
|
||||
}
|
||||
@@ -55,6 +56,7 @@ namespace C4IT.LIAM
|
||||
public readonly cNtfsBase ntfsBase = new cNtfsBase();
|
||||
public readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
|
||||
private readonly Dictionary<string, HashSet<string>> publishedShareCache = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
|
||||
private readonly Dictionary<string, string> dfsEntryPathCache = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
//public readonly bool WithoutPrivateFolders = true;
|
||||
|
||||
@@ -274,7 +276,10 @@ namespace C4IT.LIAM
|
||||
? new DirectoryInfo(classification.NormalizedPath).CreationTimeUtc.ToString("s")
|
||||
: DateTime.MinValue.ToString("s")
|
||||
};
|
||||
var folder = new cLiamNtfsFolder(this, null, null, folderData, classification.ParentBoundaryPath);
|
||||
var parentPath = !string.IsNullOrWhiteSpace(classification.ParentPath)
|
||||
? classification.ParentPath
|
||||
: classification.ParentBoundaryPath;
|
||||
var folder = new cLiamNtfsFolder(this, null, null, folderData, parentPath);
|
||||
await folder.ResolvePermissionGroupsAsync(folder.TechnicalName);
|
||||
return folder;
|
||||
}
|
||||
@@ -303,59 +308,128 @@ namespace C4IT.LIAM
|
||||
if (segments.Length < 2)
|
||||
return classification;
|
||||
|
||||
var serverName = segments[0];
|
||||
var publishedShares = GetPublishedShareNames(serverName);
|
||||
var firstBoundaryPath = BuildUncPath(segments, 2);
|
||||
classification.ParentPath = segments.Length > 2
|
||||
? BuildUncPath(segments, segments.Length - 1)
|
||||
: string.Empty;
|
||||
|
||||
if (segments.Length == 2)
|
||||
var dfsPrefixes = GetDfsObjectPrefixes(normalizedPath);
|
||||
if (dfsPrefixes.Count > 0)
|
||||
{
|
||||
if (publishedShares.Contains(segments[1]))
|
||||
{
|
||||
classification.Kind = eNtfsPathKind.ClassicShare;
|
||||
classification.BoundaryPath = normalizedPath;
|
||||
return classification;
|
||||
}
|
||||
var namespaceRootPath = dfsPrefixes[0];
|
||||
var deepestDfsPath = dfsPrefixes[dfsPrefixes.Count - 1];
|
||||
|
||||
if (Directory.Exists(normalizedPath))
|
||||
if (PathsEqual(normalizedPath, namespaceRootPath))
|
||||
{
|
||||
classification.Kind = eNtfsPathKind.DfsNamespaceRoot;
|
||||
classification.BoundaryPath = normalizedPath;
|
||||
return classification;
|
||||
}
|
||||
|
||||
return classification;
|
||||
}
|
||||
|
||||
if (publishedShares.Contains(segments[1]))
|
||||
{
|
||||
classification.Kind = eNtfsPathKind.Folder;
|
||||
classification.BoundaryPath = firstBoundaryPath;
|
||||
classification.ParentBoundaryPath = segments.Length == 3
|
||||
? firstBoundaryPath
|
||||
: BuildUncPath(segments, segments.Length - 1);
|
||||
return classification;
|
||||
}
|
||||
|
||||
if (Directory.Exists(firstBoundaryPath))
|
||||
{
|
||||
if (segments.Length == 3)
|
||||
if (PathsEqual(normalizedPath, deepestDfsPath))
|
||||
{
|
||||
classification.Kind = eNtfsPathKind.DfsLink;
|
||||
classification.BoundaryPath = normalizedPath;
|
||||
classification.ParentBoundaryPath = firstBoundaryPath;
|
||||
classification.BoundaryPath = deepestDfsPath;
|
||||
classification.ParentBoundaryPath = dfsPrefixes.Count > 1
|
||||
? dfsPrefixes[dfsPrefixes.Count - 2]
|
||||
: namespaceRootPath;
|
||||
return classification;
|
||||
}
|
||||
|
||||
classification.Kind = eNtfsPathKind.Folder;
|
||||
classification.BoundaryPath = BuildUncPath(segments, 3);
|
||||
classification.ParentBoundaryPath = segments.Length == 4
|
||||
? BuildUncPath(segments, 3)
|
||||
: BuildUncPath(segments, segments.Length - 1);
|
||||
classification.BoundaryPath = deepestDfsPath;
|
||||
classification.ParentBoundaryPath = classification.ParentPath;
|
||||
return classification;
|
||||
}
|
||||
|
||||
var shareBoundaryPath = GetPublishedShareBoundaryPath(segments);
|
||||
if (!string.IsNullOrWhiteSpace(shareBoundaryPath))
|
||||
{
|
||||
if (PathsEqual(normalizedPath, shareBoundaryPath))
|
||||
{
|
||||
classification.Kind = eNtfsPathKind.ClassicShare;
|
||||
classification.BoundaryPath = shareBoundaryPath;
|
||||
return classification;
|
||||
}
|
||||
|
||||
classification.Kind = eNtfsPathKind.Folder;
|
||||
classification.BoundaryPath = shareBoundaryPath;
|
||||
classification.ParentBoundaryPath = classification.ParentPath;
|
||||
return classification;
|
||||
}
|
||||
|
||||
if (Directory.Exists(normalizedPath))
|
||||
{
|
||||
classification.Kind = eNtfsPathKind.Folder;
|
||||
classification.ParentBoundaryPath = classification.ParentPath;
|
||||
}
|
||||
|
||||
return classification;
|
||||
}
|
||||
|
||||
private List<string> GetDfsObjectPrefixes(string path)
|
||||
{
|
||||
var normalizedPath = NormalizeUncPath(path);
|
||||
var segments = GetUncSegments(normalizedPath);
|
||||
var prefixes = new List<string>();
|
||||
|
||||
for (var segmentCount = 2; segmentCount <= segments.Length; segmentCount++)
|
||||
{
|
||||
var prefix = BuildUncPath(segments, segmentCount);
|
||||
string entryPath;
|
||||
if (!TryGetDfsEntryPath(prefix, out entryPath))
|
||||
continue;
|
||||
|
||||
prefixes.Add(!string.IsNullOrWhiteSpace(entryPath)
|
||||
? NormalizeUncPath(entryPath)
|
||||
: prefix);
|
||||
}
|
||||
|
||||
return prefixes
|
||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||
.OrderBy(i => GetUncSegments(i).Length)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private bool TryGetDfsEntryPath(string path, out string entryPath)
|
||||
{
|
||||
var normalizedPath = NormalizeUncPath(path);
|
||||
if (dfsEntryPathCache.TryGetValue(normalizedPath, out entryPath))
|
||||
return !string.IsNullOrWhiteSpace(entryPath);
|
||||
|
||||
string resolvedEntryPath;
|
||||
if (cNetworkConnection.TryGetDfsEntryPath(normalizedPath, out resolvedEntryPath))
|
||||
{
|
||||
entryPath = NormalizeUncPath(string.IsNullOrWhiteSpace(resolvedEntryPath) ? normalizedPath : resolvedEntryPath);
|
||||
dfsEntryPathCache[normalizedPath] = entryPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
dfsEntryPathCache[normalizedPath] = string.Empty;
|
||||
entryPath = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
private string GetPublishedShareBoundaryPath(string[] segments)
|
||||
{
|
||||
if (segments == null || segments.Length < 2)
|
||||
return string.Empty;
|
||||
|
||||
var serverName = segments[0];
|
||||
var publishedShares = GetPublishedShareNames(serverName);
|
||||
if (!publishedShares.Contains(segments[1]))
|
||||
return string.Empty;
|
||||
|
||||
return BuildUncPath(segments, 2);
|
||||
}
|
||||
|
||||
private bool PathsEqual(string left, string right)
|
||||
{
|
||||
return string.Equals(
|
||||
NormalizeUncPath(left),
|
||||
NormalizeUncPath(right),
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private string NormalizeUncPath(string path)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(path))
|
||||
|
||||
@@ -101,6 +101,35 @@ namespace C4IT_IAM
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryGetDfsEntryPath(string dfsEntryPath, out string entryPath)
|
||||
{
|
||||
entryPath = string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(dfsEntryPath))
|
||||
return false;
|
||||
|
||||
IntPtr buffer = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
int result = NetDfsGetInfo(dfsEntryPath, null, null, 1, ref buffer);
|
||||
if (result != NERR_Success || buffer == IntPtr.Zero)
|
||||
return false;
|
||||
|
||||
DFS_INFO_1 info = (DFS_INFO_1)Marshal.PtrToStructure(buffer, typeof(DFS_INFO_1));
|
||||
entryPath = info.EntryPath ?? dfsEntryPath;
|
||||
return !string.IsNullOrWhiteSpace(entryPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
DefaultLogger.LogException(ex);
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (buffer != IntPtr.Zero)
|
||||
NetApiBufferFree(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
[DllImport("mpr.dll")]
|
||||
private static extern int WNetAddConnection2(NetResource netResource,
|
||||
string password, string username, int flags);
|
||||
@@ -123,6 +152,15 @@ namespace C4IT_IAM
|
||||
ref int resume_handle
|
||||
);
|
||||
|
||||
[DllImport("Netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern int NetDfsGetInfo(
|
||||
string DfsEntryPath,
|
||||
string ServerName,
|
||||
string ShareName,
|
||||
int Level,
|
||||
ref IntPtr Buffer
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
@@ -205,4 +243,10 @@ namespace C4IT_IAM
|
||||
return shi1_netname;
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct DFS_INFO_1
|
||||
{
|
||||
public string EntryPath;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user