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 eNtfsPathKind Kind { get; set; } = eNtfsPathKind.Unknown;
|
||||||
public string BoundaryPath { get; set; } = string.Empty;
|
public string BoundaryPath { get; set; } = string.Empty;
|
||||||
public string ParentBoundaryPath { 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 string DisplayName { get; set; } = string.Empty;
|
||||||
public int Level { get; set; } = -1;
|
public int Level { get; set; } = -1;
|
||||||
}
|
}
|
||||||
@@ -55,6 +56,7 @@ namespace C4IT.LIAM
|
|||||||
public readonly cNtfsBase ntfsBase = new cNtfsBase();
|
public readonly cNtfsBase ntfsBase = new cNtfsBase();
|
||||||
public readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
|
public readonly cActiveDirectoryBase activeDirectoryBase = new cActiveDirectoryBase();
|
||||||
private readonly Dictionary<string, HashSet<string>> publishedShareCache = new Dictionary<string, HashSet<string>>(StringComparer.OrdinalIgnoreCase);
|
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;
|
//public readonly bool WithoutPrivateFolders = true;
|
||||||
|
|
||||||
@@ -274,7 +276,10 @@ namespace C4IT.LIAM
|
|||||||
? new DirectoryInfo(classification.NormalizedPath).CreationTimeUtc.ToString("s")
|
? new DirectoryInfo(classification.NormalizedPath).CreationTimeUtc.ToString("s")
|
||||||
: DateTime.MinValue.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);
|
await folder.ResolvePermissionGroupsAsync(folder.TechnicalName);
|
||||||
return folder;
|
return folder;
|
||||||
}
|
}
|
||||||
@@ -303,57 +308,126 @@ namespace C4IT.LIAM
|
|||||||
if (segments.Length < 2)
|
if (segments.Length < 2)
|
||||||
return classification;
|
return classification;
|
||||||
|
|
||||||
var serverName = segments[0];
|
classification.ParentPath = segments.Length > 2
|
||||||
var publishedShares = GetPublishedShareNames(serverName);
|
? BuildUncPath(segments, segments.Length - 1)
|
||||||
var firstBoundaryPath = BuildUncPath(segments, 2);
|
: string.Empty;
|
||||||
|
|
||||||
if (segments.Length == 2)
|
var dfsPrefixes = GetDfsObjectPrefixes(normalizedPath);
|
||||||
|
if (dfsPrefixes.Count > 0)
|
||||||
{
|
{
|
||||||
if (publishedShares.Contains(segments[1]))
|
var namespaceRootPath = dfsPrefixes[0];
|
||||||
|
var deepestDfsPath = dfsPrefixes[dfsPrefixes.Count - 1];
|
||||||
|
|
||||||
|
if (PathsEqual(normalizedPath, namespaceRootPath))
|
||||||
|
{
|
||||||
|
classification.Kind = eNtfsPathKind.DfsNamespaceRoot;
|
||||||
|
classification.BoundaryPath = normalizedPath;
|
||||||
|
return classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PathsEqual(normalizedPath, deepestDfsPath))
|
||||||
|
{
|
||||||
|
classification.Kind = eNtfsPathKind.DfsLink;
|
||||||
|
classification.BoundaryPath = deepestDfsPath;
|
||||||
|
classification.ParentBoundaryPath = dfsPrefixes.Count > 1
|
||||||
|
? dfsPrefixes[dfsPrefixes.Count - 2]
|
||||||
|
: namespaceRootPath;
|
||||||
|
return classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
classification.Kind = eNtfsPathKind.Folder;
|
||||||
|
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.Kind = eNtfsPathKind.ClassicShare;
|
||||||
classification.BoundaryPath = normalizedPath;
|
classification.BoundaryPath = shareBoundaryPath;
|
||||||
|
return classification;
|
||||||
|
}
|
||||||
|
|
||||||
|
classification.Kind = eNtfsPathKind.Folder;
|
||||||
|
classification.BoundaryPath = shareBoundaryPath;
|
||||||
|
classification.ParentBoundaryPath = classification.ParentPath;
|
||||||
return classification;
|
return classification;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Directory.Exists(normalizedPath))
|
if (Directory.Exists(normalizedPath))
|
||||||
{
|
|
||||||
classification.Kind = eNtfsPathKind.DfsNamespaceRoot;
|
|
||||||
classification.BoundaryPath = normalizedPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
return classification;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (publishedShares.Contains(segments[1]))
|
|
||||||
{
|
{
|
||||||
classification.Kind = eNtfsPathKind.Folder;
|
classification.Kind = eNtfsPathKind.Folder;
|
||||||
classification.BoundaryPath = firstBoundaryPath;
|
classification.ParentBoundaryPath = classification.ParentPath;
|
||||||
classification.ParentBoundaryPath = segments.Length == 3
|
}
|
||||||
? firstBoundaryPath
|
|
||||||
: BuildUncPath(segments, segments.Length - 1);
|
|
||||||
return classification;
|
return classification;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Directory.Exists(firstBoundaryPath))
|
private List<string> GetDfsObjectPrefixes(string path)
|
||||||
{
|
{
|
||||||
if (segments.Length == 3)
|
var normalizedPath = NormalizeUncPath(path);
|
||||||
|
var segments = GetUncSegments(normalizedPath);
|
||||||
|
var prefixes = new List<string>();
|
||||||
|
|
||||||
|
for (var segmentCount = 2; segmentCount <= segments.Length; segmentCount++)
|
||||||
{
|
{
|
||||||
classification.Kind = eNtfsPathKind.DfsLink;
|
var prefix = BuildUncPath(segments, segmentCount);
|
||||||
classification.BoundaryPath = normalizedPath;
|
string entryPath;
|
||||||
classification.ParentBoundaryPath = firstBoundaryPath;
|
if (!TryGetDfsEntryPath(prefix, out entryPath))
|
||||||
return classification;
|
continue;
|
||||||
|
|
||||||
|
prefixes.Add(!string.IsNullOrWhiteSpace(entryPath)
|
||||||
|
? NormalizeUncPath(entryPath)
|
||||||
|
: prefix);
|
||||||
}
|
}
|
||||||
|
|
||||||
classification.Kind = eNtfsPathKind.Folder;
|
return prefixes
|
||||||
classification.BoundaryPath = BuildUncPath(segments, 3);
|
.Distinct(StringComparer.OrdinalIgnoreCase)
|
||||||
classification.ParentBoundaryPath = segments.Length == 4
|
.OrderBy(i => GetUncSegments(i).Length)
|
||||||
? BuildUncPath(segments, 3)
|
.ToList();
|
||||||
: BuildUncPath(segments, segments.Length - 1);
|
|
||||||
return classification;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return classification;
|
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)
|
private string NormalizeUncPath(string 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")]
|
[DllImport("mpr.dll")]
|
||||||
private static extern int WNetAddConnection2(NetResource netResource,
|
private static extern int WNetAddConnection2(NetResource netResource,
|
||||||
string password, string username, int flags);
|
string password, string username, int flags);
|
||||||
@@ -123,6 +152,15 @@ namespace C4IT_IAM
|
|||||||
ref int resume_handle
|
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)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
@@ -205,4 +243,10 @@ namespace C4IT_IAM
|
|||||||
return shi1_netname;
|
return shi1_netname;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||||
|
public struct DFS_INFO_1
|
||||||
|
{
|
||||||
|
public string EntryPath;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user