mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-07-14 05:15:03 +02:00
Improved NTFileSystemHelper's FindEntries implementation
This commit is contained in:
parent
bf9d519e9f
commit
dd4839e2f1
2 changed files with 72 additions and 54 deletions
|
@ -13,11 +13,6 @@ namespace SMBLibrary.Server
|
||||||
{
|
{
|
||||||
public partial class NTFileSystemHelper
|
public partial class NTFileSystemHelper
|
||||||
{
|
{
|
||||||
// Windows servers will return "." and ".." when enumerating directory files, Windows clients do not require it.
|
|
||||||
// It seems that Ubuntu 10.04.4 and 13.10 expect at least one entry in the response (so empty directory listing cause a problem when omitting both).
|
|
||||||
private const bool IncludeCurrentDirectoryInResults = true;
|
|
||||||
private const bool IncludeParentDirectoryInResults = true;
|
|
||||||
|
|
||||||
// Filename pattern examples:
|
// Filename pattern examples:
|
||||||
// '\Directory' - Get the directory entry
|
// '\Directory' - Get the directory entry
|
||||||
// '\Directory\*' - List the directory files
|
// '\Directory\*' - List the directory files
|
||||||
|
@ -27,55 +22,75 @@ namespace SMBLibrary.Server
|
||||||
/// <param name="fileNamePattern">The filename pattern to search for. This field MAY contain wildcard characters</param>
|
/// <param name="fileNamePattern">The filename pattern to search for. This field MAY contain wildcard characters</param>
|
||||||
/// <returns>null if the path does not exist</returns>
|
/// <returns>null if the path does not exist</returns>
|
||||||
/// <exception cref="System.UnauthorizedAccessException"></exception>
|
/// <exception cref="System.UnauthorizedAccessException"></exception>
|
||||||
public static List<FileSystemEntry> FindEntries(IFileSystem fileSystem, string path)
|
public static NTStatus FindEntries(out List<FileSystemEntry> entries, IFileSystem fileSystem, string fileNamePattern)
|
||||||
{
|
{
|
||||||
bool isDirectoryEnumeration = false;
|
int separatorIndex = fileNamePattern.LastIndexOf('\\');
|
||||||
string searchPattern = String.Empty;
|
if (separatorIndex >= 0)
|
||||||
if (path.Contains("*") || path.Contains("<"))
|
|
||||||
{
|
{
|
||||||
isDirectoryEnumeration = true;
|
string path = fileNamePattern.Substring(0, separatorIndex + 1);
|
||||||
int separatorIndex = path.LastIndexOf('\\');
|
string expression = fileNamePattern.Substring(separatorIndex + 1);
|
||||||
searchPattern = path.Substring(separatorIndex + 1);
|
return FindEntries(out entries, fileSystem, path, expression);
|
||||||
path = path.Substring(0, separatorIndex + 1);
|
|
||||||
}
|
|
||||||
bool exactNameWithoutExtension = searchPattern.Contains("\"");
|
|
||||||
|
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(path);
|
|
||||||
if (entry == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<FileSystemEntry> entries;
|
|
||||||
if (isDirectoryEnumeration)
|
|
||||||
{
|
|
||||||
entries = fileSystem.ListEntriesInDirectory(path);
|
|
||||||
|
|
||||||
if (searchPattern != String.Empty)
|
|
||||||
{
|
|
||||||
entries = GetFiltered(entries, searchPattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!exactNameWithoutExtension)
|
|
||||||
{
|
|
||||||
if (IncludeParentDirectoryInResults)
|
|
||||||
{
|
|
||||||
entries.Insert(0, fileSystem.GetEntry(FileSystem.GetParentDirectory(path)));
|
|
||||||
entries[0].Name = "..";
|
|
||||||
}
|
|
||||||
if (IncludeCurrentDirectoryInResults)
|
|
||||||
{
|
|
||||||
entries.Insert(0, fileSystem.GetEntry(path));
|
|
||||||
entries[0].Name = ".";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
entries = null;
|
||||||
|
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <param name="expression">Expression as described in [MS-FSA] 2.1.4.4</param>
|
||||||
|
/// <returns>null if the path does not exist</returns>
|
||||||
|
public static NTStatus FindEntries(out List<FileSystemEntry> entries, IFileSystem fileSystem, string path, string expression)
|
||||||
|
{
|
||||||
|
entries = null;
|
||||||
|
FileSystemEntry entry = fileSystem.GetEntry(path);
|
||||||
|
if (entry == null)
|
||||||
|
{
|
||||||
|
return NTStatus.STATUS_NO_SUCH_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expression == String.Empty)
|
||||||
|
{
|
||||||
|
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool findExactName = !ContainsWildcardCharacters(expression);
|
||||||
|
|
||||||
|
if (!findExactName)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
entries = fileSystem.ListEntriesInDirectory(path);
|
||||||
|
}
|
||||||
|
catch (UnauthorizedAccessException)
|
||||||
|
{
|
||||||
|
return NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
}
|
||||||
|
|
||||||
|
entries = GetFiltered(entries, expression);
|
||||||
|
|
||||||
|
// Windows will return "." and ".." when enumerating directory files.
|
||||||
|
// The SMB1 / SMB2 specifications mandate that when zero entries are found, the server SHOULD / MUST return STATUS_NO_SUCH_FILE.
|
||||||
|
// For this reason, we MUST include the current directory and/or parent directory when enumerating a directory
|
||||||
|
// in order to diffrentiate between a directory that does not exist and a directory with no entries.
|
||||||
|
FileSystemEntry currentDirectory = fileSystem.GetEntry(path);
|
||||||
|
currentDirectory.Name = ".";
|
||||||
|
FileSystemEntry parentDirectory = fileSystem.GetEntry(FileSystem.GetParentDirectory(path));
|
||||||
|
parentDirectory.Name = "..";
|
||||||
|
entries.Insert(0, parentDirectory);
|
||||||
|
entries.Insert(0, currentDirectory);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
entry = fileSystem.GetEntry(path + expression);
|
||||||
|
if (entry == null)
|
||||||
|
{
|
||||||
|
return NTStatus.STATUS_NO_SUCH_FILE;
|
||||||
|
}
|
||||||
entries = new List<FileSystemEntry>();
|
entries = new List<FileSystemEntry>();
|
||||||
entries.Add(entry);
|
entries.Add(entry);
|
||||||
}
|
}
|
||||||
return entries;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <param name="expression">Expression as described in [MS-FSA] 2.1.4.4</param>
|
/// <param name="expression">Expression as described in [MS-FSA] 2.1.4.4</param>
|
||||||
|
@ -97,6 +112,11 @@ namespace SMBLibrary.Server
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool ContainsWildcardCharacters(string expression)
|
||||||
|
{
|
||||||
|
return (expression.Contains("?") || expression.Contains("*") || expression.Contains("\"") || expression.Contains(">") || expression.Contains("<"));
|
||||||
|
}
|
||||||
|
|
||||||
// [MS-FSA] 2.1.4.4
|
// [MS-FSA] 2.1.4.4
|
||||||
// The FileName is string compared with Expression using the following wildcard rules:
|
// The FileName is string compared with Expression using the following wildcard rules:
|
||||||
// * (asterisk) Matches zero or more characters.
|
// * (asterisk) Matches zero or more characters.
|
||||||
|
|
|
@ -22,19 +22,17 @@ namespace SMBLibrary.Server.SMB1
|
||||||
string fileNamePattern = subcommand.FileName;
|
string fileNamePattern = subcommand.FileName;
|
||||||
|
|
||||||
List<FileSystemEntry> entries;
|
List<FileSystemEntry> entries;
|
||||||
try
|
NTStatus searchStatus = NTFileSystemHelper.FindEntries(out entries, fileSystem, fileNamePattern);
|
||||||
|
if (searchStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
entries = NTFileSystemHelper.FindEntries(fileSystem, fileNamePattern);
|
state.LogToServer(Severity.Verbose, "FindFirst2: Searched for '{0}', NTStatus: {1}", fileNamePattern, searchStatus.ToString());
|
||||||
}
|
header.Status = searchStatus;
|
||||||
catch (UnauthorizedAccessException)
|
|
||||||
{
|
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
state.LogToServer(Severity.Verbose, "FindFirst2: Searched for '{0}', found {1} matching entries", fileNamePattern, entries != null ? entries.Count.ToString() : "no");
|
state.LogToServer(Severity.Verbose, "FindFirst2: Searched for '{0}', found {1} matching entries", fileNamePattern, entries.Count);
|
||||||
|
|
||||||
// [MS-CIFS] If no matching entries are found, the server SHOULD fail the request with STATUS_NO_SUCH_FILE.
|
// [MS-CIFS] If no matching entries are found, the server SHOULD fail the request with STATUS_NO_SUCH_FILE.
|
||||||
if (entries == null || entries.Count == 0)
|
if (entries.Count == 0)
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||||
return null;
|
return null;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue