mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-07-03 08:13:18 +02:00
INTFileStore interface was added for better separation between the object store layer and the SMB layer
This commit is contained in:
parent
cc170322ed
commit
fb43fb966d
43 changed files with 1715 additions and 1487 deletions
29
SMBLibrary/NTFileStore/Adapter/FileHandle.cs
Normal file
29
SMBLibrary/NTFileStore/Adapter/FileHandle.cs
Normal file
|
@ -0,0 +1,29 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace SMBLibrary
|
||||
{
|
||||
public class FileHandle
|
||||
{
|
||||
public string Path;
|
||||
public bool IsDirectory;
|
||||
public Stream Stream;
|
||||
public bool DeleteOnClose;
|
||||
|
||||
public FileHandle(string path, bool isDirectory, Stream stream, bool deleteOnClose)
|
||||
{
|
||||
Path = path;
|
||||
IsDirectory = isDirectory;
|
||||
Stream = stream;
|
||||
DeleteOnClose = deleteOnClose;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,36 +9,33 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server
|
||||
namespace SMBLibrary
|
||||
{
|
||||
public partial class NTFileSystemHelper
|
||||
public partial class NTFileSystemAdapter
|
||||
{
|
||||
public static NTStatus GetNamedPipeInformation(out FileInformation result, FileInformationClass informationClass)
|
||||
public NTStatus GetFileInformation(out FileInformation result, object handle, FileInformationClass informationClass)
|
||||
{
|
||||
switch (informationClass)
|
||||
FileHandle fileHandle = (FileHandle)handle;
|
||||
string path = fileHandle.Path;
|
||||
FileSystemEntry entry;
|
||||
try
|
||||
{
|
||||
case FileInformationClass.FileBasicInformation:
|
||||
{
|
||||
FileBasicInformation information = new FileBasicInformation();
|
||||
information.FileAttributes = FileAttributes.Temporary;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case FileInformationClass.FileStandardInformation:
|
||||
{
|
||||
FileStandardInformation information = new FileStandardInformation();
|
||||
information.DeletePending = true;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
default:
|
||||
result = null;
|
||||
return NTStatus.STATUS_INVALID_INFO_CLASS;
|
||||
entry = m_fileSystem.GetEntry(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
Log(Severity.Debug, "GetFileInformation on '{0}' failed. {1}", path, status);
|
||||
result = null;
|
||||
return status;
|
||||
}
|
||||
|
||||
if (entry == null)
|
||||
{
|
||||
result = null;
|
||||
return NTStatus.STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
}
|
||||
|
||||
public static NTStatus GetFileInformation(out FileInformation result, FileSystemEntry entry, bool deletePending, FileInformationClass informationClass)
|
||||
{
|
||||
switch (informationClass)
|
||||
{
|
||||
case FileInformationClass.FileBasicInformation:
|
||||
|
@ -55,10 +52,10 @@ namespace SMBLibrary.Server
|
|||
case FileInformationClass.FileStandardInformation:
|
||||
{
|
||||
FileStandardInformation information = new FileStandardInformation();
|
||||
information.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
information.AllocationSize = (long)GetAllocationSize(entry.Size);
|
||||
information.EndOfFile = (long)entry.Size;
|
||||
information.Directory = entry.IsDirectory;
|
||||
information.DeletePending = deletePending;
|
||||
information.DeletePending = fileHandle.DeleteOnClose;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -118,7 +115,7 @@ namespace SMBLibrary.Server
|
|||
information.StandardInformation.AllocationSize = (long)GetAllocationSize(entry.Size);
|
||||
information.StandardInformation.EndOfFile = (long)entry.Size;
|
||||
information.StandardInformation.Directory = entry.IsDirectory;
|
||||
information.StandardInformation.DeletePending = deletePending;
|
||||
information.StandardInformation.DeletePending = fileHandle.DeleteOnClose;
|
||||
information.NameInformation.FileName = entry.Name;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
|
@ -134,7 +131,7 @@ namespace SMBLibrary.Server
|
|||
// A buffer of FileStreamInformation data elements is returned by the server.
|
||||
FileStreamInformation information = new FileStreamInformation();
|
||||
information.StreamSize = (long)entry.Size;
|
||||
information.StreamAllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
information.StreamAllocationSize = (long)GetAllocationSize(entry.Size);
|
||||
information.StreamName = "::$DATA";
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
|
@ -166,7 +163,7 @@ namespace SMBLibrary.Server
|
|||
information.LastAccessTime = entry.LastAccessTime;
|
||||
information.LastWriteTime = entry.LastWriteTime;
|
||||
information.ChangeTime = entry.LastWriteTime;
|
||||
information.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
information.AllocationSize = (long)GetAllocationSize(entry.Size);
|
||||
information.EndOfFile = (long)entry.Size;
|
||||
information.FileAttributes = GetFileAttributes(entry);
|
||||
result = information;
|
|
@ -0,0 +1,261 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary
|
||||
{
|
||||
public partial class NTFileSystemAdapter
|
||||
{
|
||||
/// <param name="fileName">Expression as described in [MS-FSA] 2.1.4.4</param>
|
||||
public NTStatus QueryDirectory(out List<QueryDirectoryFileInformation> result, object handle, string fileName, FileInformationClass informationClass)
|
||||
{
|
||||
result = null;
|
||||
FileHandle directoryHandle = (FileHandle)handle;
|
||||
if (!directoryHandle.IsDirectory)
|
||||
{
|
||||
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (fileName == String.Empty)
|
||||
{
|
||||
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
string path = directoryHandle.Path;
|
||||
bool findExactName = !ContainsWildcardCharacters(fileName);
|
||||
|
||||
List<FileSystemEntry> entries;
|
||||
if (!findExactName)
|
||||
{
|
||||
try
|
||||
{
|
||||
entries = m_fileSystem.ListEntriesInDirectory(path);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
return NTStatus.STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
entries = GetFiltered(entries, fileName);
|
||||
|
||||
// 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 = m_fileSystem.GetEntry(path);
|
||||
currentDirectory.Name = ".";
|
||||
FileSystemEntry parentDirectory = m_fileSystem.GetEntry(FileSystem.GetParentDirectory(path));
|
||||
parentDirectory.Name = "..";
|
||||
entries.Insert(0, parentDirectory);
|
||||
entries.Insert(0, currentDirectory);
|
||||
}
|
||||
else
|
||||
{
|
||||
path = FileSystem.GetDirectoryPath(path);
|
||||
FileSystemEntry entry = m_fileSystem.GetEntry(path + fileName);
|
||||
if (entry == null)
|
||||
{
|
||||
return NTStatus.STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
entries = new List<FileSystemEntry>();
|
||||
entries.Add(entry);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
result = FromFileSystemEntries(entries, informationClass);
|
||||
}
|
||||
catch (UnsupportedInformationLevelException)
|
||||
{
|
||||
return NTStatus.STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/// <param name="expression">Expression as described in [MS-FSA] 2.1.4.4</param>
|
||||
private static List<FileSystemEntry> GetFiltered(List<FileSystemEntry> entries, string expression)
|
||||
{
|
||||
if (expression == "*")
|
||||
{
|
||||
return entries;
|
||||
}
|
||||
|
||||
List<FileSystemEntry> result = new List<FileSystemEntry>();
|
||||
foreach (FileSystemEntry entry in entries)
|
||||
{
|
||||
if (IsFileNameInExpression(entry.Name, expression))
|
||||
{
|
||||
result.Add(entry);
|
||||
}
|
||||
}
|
||||
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
|
||||
// The FileName is string compared with Expression using the following wildcard rules:
|
||||
// * (asterisk) Matches zero or more characters.
|
||||
// ? (question mark) Matches a single character.
|
||||
// DOS_DOT (" quotation mark) Matches either a period or zero characters beyond the name string.
|
||||
// DOS_QM (> greater than) Matches any single character or, upon encountering a period or end of name string, advances the expression to the end of the set of contiguous DOS_QMs.
|
||||
// DOS_STAR (< less than) Matches zero or more characters until encountering and matching the final . in the name.
|
||||
private static bool IsFileNameInExpression(string fileName, string expression)
|
||||
{
|
||||
if (expression == "*")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (expression.EndsWith("*")) // expression.Length > 1
|
||||
{
|
||||
string desiredFileNameStart = expression.Substring(0, expression.Length - 1);
|
||||
bool findExactNameWithoutExtension = false;
|
||||
if (desiredFileNameStart.EndsWith("\""))
|
||||
{
|
||||
findExactNameWithoutExtension = true;
|
||||
desiredFileNameStart = desiredFileNameStart.Substring(0, desiredFileNameStart.Length - 1);
|
||||
}
|
||||
|
||||
if (!findExactNameWithoutExtension)
|
||||
{
|
||||
if (fileName.StartsWith(desiredFileNameStart, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fileName.StartsWith(desiredFileNameStart + ".", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
fileName.Equals(desiredFileNameStart, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (expression.StartsWith("<"))
|
||||
{
|
||||
string desiredFileNameEnd = expression.Substring(1);
|
||||
if (fileName.EndsWith(desiredFileNameEnd, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (String.Equals(fileName, expression, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static List<QueryDirectoryFileInformation> FromFileSystemEntries(List<FileSystemEntry> entries, FileInformationClass informationClass)
|
||||
{
|
||||
List<QueryDirectoryFileInformation> result = new List<QueryDirectoryFileInformation>();
|
||||
foreach (FileSystemEntry entry in entries)
|
||||
{
|
||||
QueryDirectoryFileInformation information = FromFileSystemEntry(entry, informationClass);
|
||||
result.Add(information);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static QueryDirectoryFileInformation FromFileSystemEntry(FileSystemEntry entry, FileInformationClass informationClass)
|
||||
{
|
||||
switch (informationClass)
|
||||
{
|
||||
case FileInformationClass.FileBothDirectoryInformation:
|
||||
{
|
||||
FileBothDirectoryInformation result = new FileBothDirectoryInformation();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.ChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)GetAllocationSize(entry.Size);
|
||||
result.FileAttributes = GetFileAttributes(entry);
|
||||
result.EaSize = 0;
|
||||
result.ShortName = GetShortName(entry.Name);
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FileInformationClass.FileDirectoryInformation:
|
||||
{
|
||||
FileDirectoryInformation result = new FileDirectoryInformation();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.ChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)GetAllocationSize(entry.Size);
|
||||
result.FileAttributes = GetFileAttributes(entry);
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FileInformationClass.FileFullDirectoryInformation:
|
||||
{
|
||||
FileFullDirectoryInformation result = new FileFullDirectoryInformation();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.ChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)GetAllocationSize(entry.Size);
|
||||
result.FileAttributes = GetFileAttributes(entry);
|
||||
result.EaSize = 0;
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FileInformationClass.FileIdBothDirectoryInformation:
|
||||
{
|
||||
FileIdBothDirectoryInformation result = new FileIdBothDirectoryInformation();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.ChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)GetAllocationSize(entry.Size);
|
||||
result.FileAttributes = GetFileAttributes(entry);
|
||||
result.EaSize = 0;
|
||||
result.ShortName = GetShortName(entry.Name);
|
||||
result.FileId = 0;
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FileInformationClass.FileIdFullDirectoryInformation:
|
||||
{
|
||||
FileIdFullDirectoryInformation result = new FileIdFullDirectoryInformation();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.ChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)GetAllocationSize(entry.Size);
|
||||
result.FileAttributes = GetFileAttributes(entry);
|
||||
result.EaSize = 0;
|
||||
result.FileId = 0;
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FileInformationClass.FileNamesInformation:
|
||||
{
|
||||
FileNamesInformation result = new FileNamesInformation();
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new UnsupportedInformationLevelException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,11 +9,11 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server
|
||||
namespace SMBLibrary
|
||||
{
|
||||
public partial class NTFileSystemHelper
|
||||
public partial class NTFileSystemAdapter
|
||||
{
|
||||
public static NTStatus GetFileSystemInformation(out FileSystemInformation result, FileSystemInformationClass informationClass, IFileSystem fileSystem)
|
||||
public NTStatus GetFileSystemInformation(out FileSystemInformation result, FileSystemInformationClass informationClass)
|
||||
{
|
||||
switch (informationClass)
|
||||
{
|
||||
|
@ -27,10 +27,10 @@ namespace SMBLibrary.Server
|
|||
case FileSystemInformationClass.FileFsSizeInformation:
|
||||
{
|
||||
FileFsSizeInformation information = new FileFsSizeInformation();
|
||||
information.TotalAllocationUnits = fileSystem.Size / NTFileSystemHelper.ClusterSize;
|
||||
information.AvailableAllocationUnits = fileSystem.FreeSpace / NTFileSystemHelper.ClusterSize;
|
||||
information.SectorsPerAllocationUnit = NTFileSystemHelper.ClusterSize / NTFileSystemHelper.BytesPerSector;
|
||||
information.BytesPerSector = NTFileSystemHelper.BytesPerSector;
|
||||
information.TotalAllocationUnits = m_fileSystem.Size / ClusterSize;
|
||||
information.AvailableAllocationUnits = m_fileSystem.FreeSpace / ClusterSize;
|
||||
information.SectorsPerAllocationUnit = ClusterSize / BytesPerSector;
|
||||
information.BytesPerSector = BytesPerSector;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ namespace SMBLibrary.Server
|
|||
FileFsAttributeInformation information = new FileFsAttributeInformation();
|
||||
information.FileSystemAttributes = FileSystemAttributes.UnicodeOnDisk;
|
||||
information.MaximumComponentNameLength = 255;
|
||||
information.FileSystemName = fileSystem.Name;
|
||||
information.FileSystemName = m_fileSystem.Name;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -63,11 +63,11 @@ namespace SMBLibrary.Server
|
|||
case FileSystemInformationClass.FileFsFullSizeInformation:
|
||||
{
|
||||
FileFsFullSizeInformation information = new FileFsFullSizeInformation();
|
||||
information.TotalAllocationUnits = fileSystem.Size / NTFileSystemHelper.ClusterSize;
|
||||
information.CallerAvailableAllocationUnits = fileSystem.FreeSpace / NTFileSystemHelper.ClusterSize;
|
||||
information.ActualAvailableAllocationUnits = fileSystem.FreeSpace / NTFileSystemHelper.ClusterSize;
|
||||
information.SectorsPerAllocationUnit = NTFileSystemHelper.ClusterSize / NTFileSystemHelper.BytesPerSector;
|
||||
information.BytesPerSector = NTFileSystemHelper.BytesPerSector;
|
||||
information.TotalAllocationUnits = m_fileSystem.Size / ClusterSize;
|
||||
information.CallerAvailableAllocationUnits = m_fileSystem.FreeSpace / ClusterSize;
|
||||
information.ActualAvailableAllocationUnits = m_fileSystem.FreeSpace / ClusterSize;
|
||||
information.SectorsPerAllocationUnit = ClusterSize / BytesPerSector;
|
||||
information.BytesPerSector = BytesPerSector;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
@ -81,10 +81,10 @@ namespace SMBLibrary.Server
|
|||
case FileSystemInformationClass.FileFsSectorSizeInformation:
|
||||
{
|
||||
FileFsSectorSizeInformation information = new FileFsSectorSizeInformation();
|
||||
information.LogicalBytesPerSector = NTFileSystemHelper.BytesPerSector;
|
||||
information.PhysicalBytesPerSectorForAtomicity = NTFileSystemHelper.BytesPerSector;
|
||||
information.PhysicalBytesPerSectorForPerformance = NTFileSystemHelper.BytesPerSector;
|
||||
information.FileSystemEffectivePhysicalBytesPerSectorForAtomicity = NTFileSystemHelper.BytesPerSector;
|
||||
information.LogicalBytesPerSector = BytesPerSector;
|
||||
information.PhysicalBytesPerSectorForAtomicity = BytesPerSector;
|
||||
information.PhysicalBytesPerSectorForPerformance = BytesPerSector;
|
||||
information.FileSystemEffectivePhysicalBytesPerSectorForAtomicity = BytesPerSector;
|
||||
information.ByteOffsetForSectorAlignment = 0;
|
||||
information.ByteOffsetForPartitionAlignment = 0;
|
||||
result = information;
|
|
@ -9,12 +9,13 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server
|
||||
namespace SMBLibrary
|
||||
{
|
||||
public partial class NTFileSystemHelper
|
||||
public partial class NTFileSystemAdapter
|
||||
{
|
||||
public static NTStatus SetFileInformation(IFileSystem fileSystem, OpenFileObject openFile, FileInformation information, ConnectionState state)
|
||||
public NTStatus SetFileInformation(object handle, FileInformation information)
|
||||
{
|
||||
FileHandle fileHandle = (FileHandle)handle;
|
||||
if (information is FileBasicInformation)
|
||||
{
|
||||
FileBasicInformation basicInformation = (FileBasicInformation)information;
|
||||
|
@ -23,23 +24,23 @@ namespace SMBLibrary.Server
|
|||
bool isArchived = (basicInformation.FileAttributes & FileAttributes.Archive) > 0;
|
||||
try
|
||||
{
|
||||
fileSystem.SetAttributes(openFile.Path, isHidden, isReadonly, isArchived);
|
||||
m_fileSystem.SetAttributes(fileHandle.Path, isHidden, isReadonly, isArchived);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Failed to set file attributes on '{0}'. {1}.", openFile.Path, status);
|
||||
Log(Severity.Debug, "SetFileInformation: Failed to set file attributes on '{0}'. {1}.", fileHandle.Path, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fileSystem.SetDates(openFile.Path, basicInformation.CreationTime, basicInformation.LastWriteTime, basicInformation.LastAccessTime);
|
||||
m_fileSystem.SetDates(fileHandle.Path, basicInformation.CreationTime, basicInformation.LastWriteTime, basicInformation.LastAccessTime);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Failed to set file dates on '{0}'. {1}.", openFile.Path, status);
|
||||
Log(Severity.Debug, "SetFileInformation: Failed to set file dates on '{0}'. {1}.", fileHandle.Path, status);
|
||||
return status;
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
|
@ -52,28 +53,28 @@ namespace SMBLibrary.Server
|
|||
{
|
||||
destination = @"\" + destination;
|
||||
}
|
||||
|
||||
if (openFile.Stream != null)
|
||||
|
||||
if (fileHandle.Stream != null)
|
||||
{
|
||||
openFile.Stream.Close();
|
||||
fileHandle.Stream.Close();
|
||||
}
|
||||
|
||||
// Note: it's possible that we just want to upcase / downcase a filename letter.
|
||||
try
|
||||
{
|
||||
if (renameInformation.ReplaceIfExists && (fileSystem.GetEntry(destination) != null ))
|
||||
if (renameInformation.ReplaceIfExists && (m_fileSystem.GetEntry(destination) != null))
|
||||
{
|
||||
fileSystem.Delete(destination);
|
||||
m_fileSystem.Delete(destination);
|
||||
}
|
||||
fileSystem.Move(openFile.Path, destination);
|
||||
m_fileSystem.Move(fileHandle.Path, destination);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Cannot rename '{0}'. {1}.", openFile.Path, status);
|
||||
Log(Severity.Debug, "SetFileInformation: Cannot rename '{0}'. {1}.", fileHandle.Path, status);
|
||||
return status;
|
||||
}
|
||||
openFile.Path = destination;
|
||||
fileHandle.Path = destination;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
else if (information is FileDispositionInformation)
|
||||
|
@ -81,20 +82,20 @@ namespace SMBLibrary.Server
|
|||
if (((FileDispositionInformation)information).DeletePending)
|
||||
{
|
||||
// We're supposed to delete the file on close, but it's too late to report errors at this late stage
|
||||
if (openFile.Stream != null)
|
||||
if (fileHandle.Stream != null)
|
||||
{
|
||||
openFile.Stream.Close();
|
||||
fileHandle.Stream.Close();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
state.LogToServer(Severity.Information, "SetFileInformation: Deleting file '{0}'", openFile.Path);
|
||||
fileSystem.Delete(openFile.Path);
|
||||
Log(Severity.Information, "SetFileInformation: Deleting file '{0}'", fileHandle.Path);
|
||||
m_fileSystem.Delete(fileHandle.Path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Error deleting '{0}'. {1}.", openFile.Path, status);
|
||||
Log(Severity.Information, "SetFileInformation: Error deleting '{0}'. {1}.", status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
@ -105,12 +106,12 @@ namespace SMBLibrary.Server
|
|||
long allocationSize = ((FileAllocationInformation)information).AllocationSize;
|
||||
try
|
||||
{
|
||||
openFile.Stream.SetLength(allocationSize);
|
||||
fileHandle.Stream.SetLength(allocationSize);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set allocation for '{0}'. {1}.", openFile.Path, status);
|
||||
Log(Severity.Debug, "SetFileInformation: Cannot set allocation for '{0}'. {1}.", fileHandle.Path, status);
|
||||
return status;
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
|
@ -120,12 +121,12 @@ namespace SMBLibrary.Server
|
|||
long endOfFile = ((FileEndOfFileInformation)information).EndOfFile;
|
||||
try
|
||||
{
|
||||
openFile.Stream.SetLength(endOfFile);
|
||||
fileHandle.Stream.SetLength(endOfFile);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set end of file for '{0}'. {1}.", openFile.Path, status);
|
||||
Log(Severity.Debug, "SetFileInformation: Cannot set end of file for '{0}'. {1}.", fileHandle.Path, status);
|
||||
return status;
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
|
@ -7,23 +7,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SMBLibrary.Services;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server
|
||||
namespace SMBLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to access the FileSystemShare / NamedPipeShare in an NT-like manner dictated by the SMB protocol
|
||||
/// </summary>
|
||||
public partial class NTFileSystemHelper
|
||||
public partial class NTFileSystemAdapter : INTFileStore
|
||||
{
|
||||
public const int BytesPerSector = 512;
|
||||
public const int ClusterSize = 4096;
|
||||
private const int BytesPerSector = 512;
|
||||
private const int ClusterSize = 4096;
|
||||
|
||||
public static NTStatus CreateFile(out FileSystemEntry entry, out Stream stream, out FileStatus fileStatus, IFileSystem fileSystem, string path, AccessMask desiredAccess, ShareAccess shareAccess, CreateDisposition createDisposition, CreateOptions createOptions, ConnectionState state)
|
||||
private IFileSystem m_fileSystem;
|
||||
|
||||
public event EventHandler<LogEntry> OnLogEntry;
|
||||
|
||||
public NTFileSystemAdapter(IFileSystem fileSystem)
|
||||
{
|
||||
m_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
public NTStatus CreateFile(out object handle, out FileStatus fileStatus, string path, AccessMask desiredAccess, ShareAccess shareAccess, CreateDisposition createDisposition, CreateOptions createOptions)
|
||||
{
|
||||
handle = null;
|
||||
fileStatus = FileStatus.FILE_DOES_NOT_EXIST;
|
||||
stream = null;
|
||||
FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(desiredAccess, createDisposition);
|
||||
bool requestedWriteAccess = (createAccess & FileAccess.Write) > 0;
|
||||
|
||||
|
@ -35,7 +40,6 @@ namespace SMBLibrary.Server
|
|||
createDisposition != CreateDisposition.FILE_OPEN_IF &&
|
||||
createDisposition != CreateDisposition.FILE_SUPERSEDE))
|
||||
{
|
||||
entry = null;
|
||||
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
|
@ -43,19 +47,18 @@ namespace SMBLibrary.Server
|
|||
if (path.Contains(":"))
|
||||
{
|
||||
// Windows Server 2003 will return STATUS_OBJECT_NAME_NOT_FOUND
|
||||
entry = null;
|
||||
return NTStatus.STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
|
||||
FileSystemEntry entry;
|
||||
try
|
||||
{
|
||||
entry = fileSystem.GetEntry(path);
|
||||
entry = m_fileSystem.GetEntry(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "CreateFile: Error retrieving '{0}'. {1}.", path, status);
|
||||
entry = null;
|
||||
Log(Severity.Debug, "CreateFile: Error retrieving '{0}'. {1}.", path, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -82,7 +85,7 @@ namespace SMBLibrary.Server
|
|||
if (entry != null)
|
||||
{
|
||||
// File already exists, fail the request
|
||||
state.LogToServer(Severity.Debug, "CreateFile: File '{0}' already exist", path);
|
||||
Log(Severity.Debug, "CreateFile: File '{0}' already exist", path);
|
||||
fileStatus = FileStatus.FILE_EXISTS;
|
||||
return NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
||||
}
|
||||
|
@ -96,19 +99,19 @@ namespace SMBLibrary.Server
|
|||
{
|
||||
if (forceDirectory)
|
||||
{
|
||||
state.LogToServer(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
||||
entry = fileSystem.CreateDirectory(path);
|
||||
Log(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
||||
entry = m_fileSystem.CreateDirectory(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.LogToServer(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
||||
entry = fileSystem.CreateFile(path);
|
||||
Log(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
||||
entry = m_fileSystem.CreateFile(path);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "CreateFile: Error creating '{0}'. {1}.", path, status);
|
||||
Log(Severity.Debug, "CreateFile: Error creating '{0}'. {1}.", path, status);
|
||||
return status;
|
||||
}
|
||||
fileStatus = FileStatus.FILE_CREATED;
|
||||
|
@ -134,19 +137,19 @@ namespace SMBLibrary.Server
|
|||
{
|
||||
if (forceDirectory)
|
||||
{
|
||||
state.LogToServer(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
||||
entry = fileSystem.CreateDirectory(path);
|
||||
Log(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
||||
entry = m_fileSystem.CreateDirectory(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.LogToServer(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
||||
entry = fileSystem.CreateFile(path);
|
||||
Log(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
||||
entry = m_fileSystem.CreateFile(path);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "CreateFile: Error creating '{0}'. {1}.", path, status);
|
||||
Log(Severity.Debug, "CreateFile: Error creating '{0}'. {1}.", path, status);
|
||||
return status;
|
||||
}
|
||||
fileStatus = FileStatus.FILE_CREATED;
|
||||
|
@ -165,13 +168,13 @@ namespace SMBLibrary.Server
|
|||
// Truncate the file
|
||||
try
|
||||
{
|
||||
Stream temp = fileSystem.OpenFile(path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
Stream temp = m_fileSystem.OpenFile(path, FileMode.Truncate, FileAccess.ReadWrite, FileShare.ReadWrite);
|
||||
temp.Close();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "CreateFile: Error truncating '{0}'. {1}.", path, status);
|
||||
Log(Severity.Debug, "CreateFile: Error truncating '{0}'. {1}.", path, status);
|
||||
return status;
|
||||
}
|
||||
fileStatus = FileStatus.FILE_OVERWRITTEN;
|
||||
|
@ -181,12 +184,12 @@ namespace SMBLibrary.Server
|
|||
// Delete the old file
|
||||
try
|
||||
{
|
||||
fileSystem.Delete(path);
|
||||
m_fileSystem.Delete(path);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "CreateFile: Error deleting '{0}'. {1}.", path, status);
|
||||
Log(Severity.Debug, "CreateFile: Error deleting '{0}'. {1}.", path, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -194,19 +197,19 @@ namespace SMBLibrary.Server
|
|||
{
|
||||
if (forceDirectory)
|
||||
{
|
||||
state.LogToServer(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
||||
entry = fileSystem.CreateDirectory(path);
|
||||
Log(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
||||
entry = m_fileSystem.CreateDirectory(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
state.LogToServer(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
||||
entry = fileSystem.CreateFile(path);
|
||||
Log(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
||||
entry = m_fileSystem.CreateFile(path);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "CreateFile: Error creating '{0}'. {1}.", path, status);
|
||||
Log(Severity.Debug, "CreateFile: Error creating '{0}'. {1}.", path, status);
|
||||
return status;
|
||||
}
|
||||
fileStatus = FileStatus.FILE_SUPERSEDED;
|
||||
|
@ -219,6 +222,7 @@ namespace SMBLibrary.Server
|
|||
}
|
||||
|
||||
FileAccess fileAccess = NTFileStoreHelper.ToFileAccess(desiredAccess.File);
|
||||
Stream stream;
|
||||
bool deleteOnClose = false;
|
||||
if (fileAccess == (FileAccess)0 || entry.IsDirectory)
|
||||
{
|
||||
|
@ -227,13 +231,14 @@ namespace SMBLibrary.Server
|
|||
else
|
||||
{
|
||||
deleteOnClose = (createOptions & CreateOptions.FILE_DELETE_ON_CLOSE) > 0;
|
||||
NTStatus openStatus = OpenFileStream(out stream, fileSystem, path, fileAccess, shareAccess, createOptions, state);
|
||||
NTStatus openStatus = OpenFileStream(out stream, path, fileAccess, shareAccess, createOptions);
|
||||
if (openStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return openStatus;
|
||||
}
|
||||
}
|
||||
|
||||
handle = new FileHandle(path, entry.IsDirectory, stream, deleteOnClose);
|
||||
if (fileStatus != FileStatus.FILE_CREATED &&
|
||||
fileStatus != FileStatus.FILE_OVERWRITTEN &&
|
||||
fileStatus != FileStatus.FILE_SUPERSEDED)
|
||||
|
@ -243,7 +248,7 @@ namespace SMBLibrary.Server
|
|||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public static NTStatus OpenFileStream(out Stream stream, IFileSystem fileSystem, string path, FileAccess fileAccess, ShareAccess shareAccess, CreateOptions openOptions, ConnectionState state)
|
||||
private NTStatus OpenFileStream(out Stream stream, string path, FileAccess fileAccess, ShareAccess shareAccess, CreateOptions openOptions)
|
||||
{
|
||||
stream = null;
|
||||
// When FILE_OPEN_REPARSE_POINT is specified, the operation should continue normally if the file is not a reparse point.
|
||||
|
@ -253,15 +258,15 @@ namespace SMBLibrary.Server
|
|||
bool disableBuffering = (openOptions & CreateOptions.FILE_NO_INTERMEDIATE_BUFFERING) > 0;
|
||||
bool buffered = (openOptions & CreateOptions.FILE_SEQUENTIAL_ONLY) > 0 && !disableBuffering && !openReparsePoint;
|
||||
FileShare fileShare = NTFileStoreHelper.ToFileShare(shareAccess);
|
||||
state.LogToServer(Severity.Verbose, "OpenFile: Opening '{0}', Access={1}, Share={2}, Buffered={3}", path, fileAccess, fileShare, buffered);
|
||||
Log(Severity.Verbose, "OpenFileStream: Opening '{0}', Access={1}, Share={2}, Buffered={3}", path, fileAccess, fileShare, buffered);
|
||||
try
|
||||
{
|
||||
stream = fileSystem.OpenFile(path, FileMode.Open, fileAccess, fileShare);
|
||||
stream = m_fileSystem.OpenFile(path, FileMode.Open, fileAccess, fileShare);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "OpenFile: Cannot open '{0}'. {1}.", path, status);
|
||||
Log(Severity.Debug, "OpenFile: Cannot open '{0}'. {1}.", path, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -273,86 +278,111 @@ namespace SMBLibrary.Server
|
|||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public static NTStatus ReadFile(out byte[] data, OpenFileObject openFile, long offset, int maxCount, ConnectionState state)
|
||||
public NTStatus CloseFile(object handle)
|
||||
{
|
||||
data = null;
|
||||
string openFilePath = openFile.Path;
|
||||
Stream stream = openFile.Stream;
|
||||
if (stream is RPCPipeStream)
|
||||
FileHandle fileHandle = (FileHandle)handle;
|
||||
if (fileHandle.Stream != null)
|
||||
{
|
||||
data = new byte[maxCount];
|
||||
int bytesRead = stream.Read(data, 0, maxCount);
|
||||
if (bytesRead < maxCount)
|
||||
{
|
||||
// EOF, we must trim the response data array
|
||||
data = ByteReader.ReadBytes(data, 0, bytesRead);
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
fileHandle.Stream.Close();
|
||||
}
|
||||
else // File
|
||||
{
|
||||
if (stream == null || !stream.CanRead)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "ReadFile: Cannot read '{0}', Invalid Operation.", openFilePath);
|
||||
return NTStatus.STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
int bytesRead;
|
||||
if (fileHandle.DeleteOnClose)
|
||||
{
|
||||
try
|
||||
{
|
||||
stream.Seek(offset, SeekOrigin.Begin);
|
||||
data = new byte[maxCount];
|
||||
bytesRead = stream.Read(data, 0, maxCount);
|
||||
m_fileSystem.Delete(fileHandle.Path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "ReadFile: Cannot read '{0}'. {1}.", openFilePath, status);
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (bytesRead < maxCount)
|
||||
{
|
||||
// EOF, we must trim the response data array
|
||||
data = ByteReader.ReadBytes(data, 0, bytesRead);
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
public NTStatus ReadFile(out byte[] data, object handle, long offset, int maxCount)
|
||||
{
|
||||
data = null;
|
||||
FileHandle fileHandle = (FileHandle)handle;
|
||||
string path = fileHandle.Path;
|
||||
Stream stream = fileHandle.Stream;
|
||||
if (stream == null || !stream.CanRead)
|
||||
{
|
||||
Log(Severity.Debug, "ReadFile: Cannot read '{0}', Invalid Operation.", path);
|
||||
return NTStatus.STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
int bytesRead;
|
||||
try
|
||||
{
|
||||
stream.Seek(offset, SeekOrigin.Begin);
|
||||
data = new byte[maxCount];
|
||||
bytesRead = stream.Read(data, 0, maxCount);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
Log(Severity.Debug, "ReadFile: Cannot read '{0}'. {1}.", path, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
if (bytesRead < maxCount)
|
||||
{
|
||||
// EOF, we must trim the response data array
|
||||
data = ByteReader.ReadBytes(data, 0, bytesRead);
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public NTStatus WriteFile(out int numberOfBytesWritten, object handle, long offset, byte[] data)
|
||||
{
|
||||
numberOfBytesWritten = 0;
|
||||
FileHandle fileHandle = (FileHandle)handle;
|
||||
string path = fileHandle.Path;
|
||||
Stream stream = fileHandle.Stream;
|
||||
if (stream == null || !stream.CanWrite)
|
||||
{
|
||||
Log(Severity.Debug, "WriteFile: Cannot write '{0}'. Invalid Operation.", path);
|
||||
return NTStatus.STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
stream.Seek(offset, SeekOrigin.Begin);
|
||||
stream.Write(data, 0, data.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
Log(Severity.Debug, "WriteFile: Cannot write '{0}'. {1}.", path, status);
|
||||
return status;
|
||||
}
|
||||
numberOfBytesWritten = data.Length;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public NTStatus FlushFileBuffers(object handle)
|
||||
{
|
||||
FileHandle fileHandle = (FileHandle)handle;
|
||||
if (fileHandle.Stream != null)
|
||||
{
|
||||
fileHandle.Stream.Flush();
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public void Log(Severity severity, string message)
|
||||
{
|
||||
// To be thread-safe we must capture the delegate reference first
|
||||
EventHandler<LogEntry> handler = OnLogEntry;
|
||||
if (handler != null)
|
||||
{
|
||||
handler(this, new LogEntry(DateTime.Now, severity, "NT FileSystem", message));
|
||||
}
|
||||
}
|
||||
|
||||
public static NTStatus WriteFile(out int numberOfBytesWritten, OpenFileObject openFile, long offset, byte[] data, ConnectionState state)
|
||||
public void Log(Severity severity, string message, params object[] args)
|
||||
{
|
||||
numberOfBytesWritten = 0;
|
||||
string openFilePath = openFile.Path;
|
||||
Stream stream = openFile.Stream;
|
||||
if (stream is RPCPipeStream)
|
||||
{
|
||||
stream.Write(data, 0, data.Length);
|
||||
numberOfBytesWritten = data.Length;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
else // File
|
||||
{
|
||||
if (stream == null || !stream.CanWrite)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "WriteFile: Cannot write '{0}'. Invalid Operation.", openFilePath);
|
||||
return NTStatus.STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
stream.Seek(offset, SeekOrigin.Begin);
|
||||
stream.Write(data, 0, data.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
state.LogToServer(Severity.Debug, "WriteFile: Cannot write '{0}'. {1}.", openFilePath, status);
|
||||
return status;
|
||||
}
|
||||
numberOfBytesWritten = data.Length;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
Log(severity, String.Format(message, args));
|
||||
}
|
||||
|
||||
/// <param name="exception">IFileSystem exception</param>
|
37
SMBLibrary/NTFileStore/INTFileStore.cs
Normal file
37
SMBLibrary/NTFileStore/INTFileStore.cs
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* Copyright (C) 2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary
|
||||
{
|
||||
/// <summary>
|
||||
/// A file store (a.k.a. object store) interface to allow access to a file system or a named pipe in an NT-like manner dictated by the SMB protocol.
|
||||
/// </summary>
|
||||
public interface INTFileStore
|
||||
{
|
||||
NTStatus CreateFile(out object handle, out FileStatus fileStatus, string path, AccessMask desiredAccess, ShareAccess shareAccess, CreateDisposition createDisposition, CreateOptions createOptions);
|
||||
|
||||
NTStatus CloseFile(object handle);
|
||||
|
||||
NTStatus ReadFile(out byte[] data, object handle, long offset, int maxCount);
|
||||
|
||||
NTStatus WriteFile(out int numberOfBytesWritten, object handle, long offset, byte[] data);
|
||||
|
||||
NTStatus FlushFileBuffers(object handle);
|
||||
|
||||
NTStatus QueryDirectory(out List<QueryDirectoryFileInformation> result, object handle, string fileName, FileInformationClass informationClass);
|
||||
|
||||
NTStatus GetFileInformation(out FileInformation result, object handle, FileInformationClass informationClass);
|
||||
|
||||
NTStatus SetFileInformation(object handle, FileInformation information);
|
||||
|
||||
NTStatus GetFileSystemInformation(out FileSystemInformation result, FileSystemInformationClass informationClass);
|
||||
}
|
||||
}
|
|
@ -98,5 +98,36 @@ namespace SMBLibrary
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static FileNetworkOpenInformation GetNetworkOpenInformation(INTFileStore fileStore, string path)
|
||||
{
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
NTStatus openStatus = fileStore.CreateFile(out handle, out fileStatus, path, FileAccessMask.FILE_READ_ATTRIBUTES, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OPEN, 0);
|
||||
if (openStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
FileInformation fileInfo;
|
||||
NTStatus queryStatus = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileNetworkOpenInformation);
|
||||
fileStore.CloseFile(handle);
|
||||
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return (FileNetworkOpenInformation)fileInfo;
|
||||
}
|
||||
|
||||
public static FileNetworkOpenInformation GetNetworkOpenInformation(INTFileStore fileStore, object handle)
|
||||
{
|
||||
FileInformation fileInfo;
|
||||
NTStatus status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileNetworkOpenInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return (FileNetworkOpenInformation)fileInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
150
SMBLibrary/NTFileStore/NamedPipeStore.cs
Normal file
150
SMBLibrary/NTFileStore/NamedPipeStore.cs
Normal file
|
@ -0,0 +1,150 @@
|
|||
/* Copyright (C) 2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using SMBLibrary.RPC;
|
||||
using SMBLibrary.Services;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary
|
||||
{
|
||||
public class NamedPipeStore : INTFileStore
|
||||
{
|
||||
private List<RemoteService> m_services;
|
||||
|
||||
public NamedPipeStore(List<RemoteService> services)
|
||||
{
|
||||
m_services = services;
|
||||
}
|
||||
|
||||
public NTStatus CreateFile(out object handle, out FileStatus fileStatus, string path, AccessMask desiredAccess, ShareAccess shareAccess, CreateDisposition createDisposition, CreateOptions createOptions)
|
||||
{
|
||||
fileStatus = FileStatus.FILE_DOES_NOT_EXIST;
|
||||
// It is possible to have a named pipe that does not use RPC (e.g. MS-WSP),
|
||||
// However this is not currently needed by our implementation.
|
||||
RemoteService service = GetService(path);
|
||||
if (service != null)
|
||||
{
|
||||
// All instances of a named pipe share the same pipe name, but each instance has its own buffers and handles,
|
||||
// and provides a separate conduit for client/server communication.
|
||||
RPCPipeStream stream = new RPCPipeStream(service);
|
||||
handle = new FileHandle(path, false, stream, false);
|
||||
fileStatus = FileStatus.FILE_OPENED;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
handle = null;
|
||||
return NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
public NTStatus CloseFile(object handle)
|
||||
{
|
||||
FileHandle fileHandle = (FileHandle)handle;
|
||||
if (fileHandle.Stream != null)
|
||||
{
|
||||
fileHandle.Stream.Close();
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
private RemoteService GetService(string path)
|
||||
{
|
||||
if (path.StartsWith(@"\"))
|
||||
{
|
||||
path = path.Substring(1);
|
||||
}
|
||||
|
||||
foreach (RemoteService service in m_services)
|
||||
{
|
||||
if (String.Equals(path, service.PipeName, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return service;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public NTStatus ReadFile(out byte[] data, object handle, long offset, int maxCount)
|
||||
{
|
||||
Stream stream = ((FileHandle)handle).Stream;
|
||||
data = new byte[maxCount];
|
||||
int bytesRead = stream.Read(data, 0, maxCount);
|
||||
if (bytesRead < maxCount)
|
||||
{
|
||||
// EOF, we must trim the response data array
|
||||
data = ByteReader.ReadBytes(data, 0, bytesRead);
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public NTStatus WriteFile(out int numberOfBytesWritten, object handle, long offset, byte[] data)
|
||||
{
|
||||
Stream stream = ((FileHandle)handle).Stream;
|
||||
stream.Write(data, 0, data.Length);
|
||||
numberOfBytesWritten = data.Length;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public NTStatus FlushFileBuffers(object handle)
|
||||
{
|
||||
FileHandle fileHandle = (FileHandle)handle;
|
||||
if (fileHandle.Stream != null)
|
||||
{
|
||||
fileHandle.Stream.Flush();
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public NTStatus QueryDirectory(out List<QueryDirectoryFileInformation> result, object directoryHandle, string fileName, FileInformationClass informationClass)
|
||||
{
|
||||
result = null;
|
||||
return NTStatus.STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
public NTStatus GetFileInformation(out FileInformation result, object handle, FileInformationClass informationClass)
|
||||
{
|
||||
switch (informationClass)
|
||||
{
|
||||
case FileInformationClass.FileBasicInformation:
|
||||
{
|
||||
FileBasicInformation information = new FileBasicInformation();
|
||||
information.FileAttributes = FileAttributes.Temporary;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case FileInformationClass.FileStandardInformation:
|
||||
{
|
||||
FileStandardInformation information = new FileStandardInformation();
|
||||
information.DeletePending = false;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case FileInformationClass.FileNetworkOpenInformation:
|
||||
{
|
||||
FileNetworkOpenInformation information = new FileNetworkOpenInformation();
|
||||
information.FileAttributes = FileAttributes.Temporary;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
default:
|
||||
result = null;
|
||||
return NTStatus.STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
}
|
||||
|
||||
public NTStatus SetFileInformation(object handle, FileInformation information)
|
||||
{
|
||||
return NTStatus.STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
public NTStatus GetFileSystemInformation(out FileSystemInformation result, FileSystemInformationClass informationClass)
|
||||
{
|
||||
result = null;
|
||||
return NTStatus.STATUS_NOT_SUPPORTED;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -77,7 +77,13 @@
|
|||
<Compile Include="NetBios\SessionPackets\SessionPacket.cs" />
|
||||
<Compile Include="NetBios\SessionPackets\SessionRequestPacket.cs" />
|
||||
<Compile Include="NetBios\SessionPackets\SessionRetargetResponsePacket.cs" />
|
||||
<Compile Include="NTFileStore\Adapter\FileHandle.cs" />
|
||||
<Compile Include="NTFileStore\Adapter\IOExceptionHelper.cs" />
|
||||
<Compile Include="NTFileStore\Adapter\NTFileSystemAdapter.cs" />
|
||||
<Compile Include="NTFileStore\Adapter\NTFileSystemAdapter.Query.cs" />
|
||||
<Compile Include="NTFileStore\Adapter\NTFileSystemAdapter.QueryDirectory.cs" />
|
||||
<Compile Include="NTFileStore\Adapter\NTFileSystemAdapter.QueryFileSystem.cs" />
|
||||
<Compile Include="NTFileStore\Adapter\NTFileSystemAdapter.Set.cs" />
|
||||
<Compile Include="NTFileStore\Enums\FileInformation\CompressionFormat.cs" />
|
||||
<Compile Include="NTFileStore\Enums\FileInformation\FileAttributes.cs" />
|
||||
<Compile Include="NTFileStore\Enums\FileInformation\FileInformationClass.cs" />
|
||||
|
@ -91,6 +97,8 @@
|
|||
<Compile Include="NTFileStore\Enums\NtCreateFile\CreateOptions.cs" />
|
||||
<Compile Include="NTFileStore\Enums\NtCreateFile\FileStatus.cs" />
|
||||
<Compile Include="NTFileStore\Enums\NtCreateFile\ShareAccess.cs" />
|
||||
<Compile Include="NTFileStore\INTFileStore.cs" />
|
||||
<Compile Include="NTFileStore\NamedPipeStore.cs" />
|
||||
<Compile Include="NTFileStore\NTFileStoreHelper.cs" />
|
||||
<Compile Include="NTFileStore\Structures\ACE\AccessAllowedACE.cs" />
|
||||
<Compile Include="NTFileStore\Structures\ACE\ACE.cs" />
|
||||
|
@ -174,11 +182,6 @@
|
|||
<Compile Include="Server\Exceptions\EmptyPasswordNotAllowedException.cs" />
|
||||
<Compile Include="Server\Exceptions\InvalidRequestException.cs" />
|
||||
<Compile Include="Server\Exceptions\UnsupportedInformationLevelException.cs" />
|
||||
<Compile Include="Server\Helpers\NTFileSystemHelper.cs" />
|
||||
<Compile Include="Server\Helpers\NTFileSystemHelper.Find.cs" />
|
||||
<Compile Include="Server\Helpers\NTFileSystemHelper.Query.cs" />
|
||||
<Compile Include="Server\Helpers\NTFileSystemHelper.QueryFileSystem.cs" />
|
||||
<Compile Include="Server\Helpers\NTFileSystemHelper.Set.cs" />
|
||||
<Compile Include="Server\Helpers\ServerPathUtils.cs" />
|
||||
<Compile Include="Server\IndependentUserCollection.cs" />
|
||||
<Compile Include="Server\INTLMAuthenticationProvider.cs" />
|
||||
|
@ -195,10 +198,11 @@
|
|||
<Compile Include="Server\SMB1\ReadWriteResponseHelper.cs" />
|
||||
<Compile Include="Server\SMB1\ServerResponseHelper.cs" />
|
||||
<Compile Include="Server\SMB1\SessionSetupHelper.cs" />
|
||||
<Compile Include="Server\SMB1\SMB1FileSystemHelper.Find.cs" />
|
||||
<Compile Include="Server\SMB1\SMB1FileSystemHelper.Query.cs" />
|
||||
<Compile Include="Server\SMB1\SMB1FileSystemHelper.QueryFileSystem.cs" />
|
||||
<Compile Include="Server\SMB1\SMB1FileSystemHelper.Set.cs" />
|
||||
<Compile Include="Server\SMB1\SMB1FileStoreHelper.cs" />
|
||||
<Compile Include="Server\SMB1\SMB1FileStoreHelper.Query.cs" />
|
||||
<Compile Include="Server\SMB1\SMB1FileStoreHelper.QueryDirectory.cs" />
|
||||
<Compile Include="Server\SMB1\SMB1FileStoreHelper.QueryFileSystem.cs" />
|
||||
<Compile Include="Server\SMB1\SMB1FileStoreHelper.Set.cs" />
|
||||
<Compile Include="Server\SMB1\Transaction2SubcommandHelper.cs" />
|
||||
<Compile Include="Server\SMB1\TransactionHelper.cs" />
|
||||
<Compile Include="Server\SMB1\TransactionSubcommandHelper.cs" />
|
||||
|
|
|
@ -14,14 +14,12 @@ namespace SMBLibrary.Server
|
|||
public class OpenFileObject
|
||||
{
|
||||
public string Path;
|
||||
public Stream Stream;
|
||||
public bool DeleteOnClose;
|
||||
public object Handle;
|
||||
|
||||
public OpenFileObject(string path, Stream stream, bool deleteOnClose)
|
||||
public OpenFileObject(string path, object handle)
|
||||
{
|
||||
Path = path;
|
||||
Stream = stream;
|
||||
DeleteOnClose = deleteOnClose;
|
||||
Handle = handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,10 +12,10 @@ namespace SMBLibrary.Server
|
|||
{
|
||||
public class OpenSearch
|
||||
{
|
||||
public List<FileSystemEntry> Entries;
|
||||
public List<QueryDirectoryFileInformation> Entries;
|
||||
public int EnumerationLocation;
|
||||
|
||||
public OpenSearch(List<FileSystemEntry> entries, int enumerationLocation)
|
||||
public OpenSearch(List<QueryDirectoryFileInformation> entries, int enumerationLocation)
|
||||
{
|
||||
Entries = entries;
|
||||
EnumerationLocation = enumerationLocation;
|
||||
|
|
|
@ -70,17 +70,12 @@ namespace SMBLibrary.Server
|
|||
return AddOpenFile(relativePath, null);
|
||||
}
|
||||
|
||||
public ushort? AddOpenFile(string relativePath, Stream stream)
|
||||
{
|
||||
return AddOpenFile(relativePath, stream, false);
|
||||
}
|
||||
|
||||
public ushort? AddOpenFile(string relativePath, Stream stream, bool deleteOnClose)
|
||||
public ushort? AddOpenFile(string relativePath, object handle)
|
||||
{
|
||||
ushort? fileID = m_connection.AllocateFileID();
|
||||
if (fileID.HasValue)
|
||||
{
|
||||
m_openFiles.Add(fileID.Value, new OpenFileObject(relativePath, stream, deleteOnClose));
|
||||
m_openFiles.Add(fileID.Value, new OpenFileObject(relativePath, handle));
|
||||
}
|
||||
return fileID;
|
||||
}
|
||||
|
@ -94,11 +89,6 @@ namespace SMBLibrary.Server
|
|||
|
||||
public void RemoveOpenFile(ushort fileID)
|
||||
{
|
||||
Stream stream = m_openFiles[fileID].Stream;
|
||||
if (stream != null)
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
m_openFiles.Remove(fileID);
|
||||
}
|
||||
|
||||
|
@ -120,7 +110,7 @@ namespace SMBLibrary.Server
|
|||
return null;
|
||||
}
|
||||
|
||||
public ushort? AddOpenSearch(List<FileSystemEntry> entries, int enumerationLocation)
|
||||
public ushort? AddOpenSearch(List<QueryDirectoryFileInformation> entries, int enumerationLocation)
|
||||
{
|
||||
ushort? searchHandle = AllocateSearchHandle();
|
||||
if (searchHandle.HasValue)
|
||||
|
|
|
@ -90,24 +90,13 @@ namespace SMBLibrary.Server
|
|||
return m_connectedTrees.ContainsKey(treeID);
|
||||
}
|
||||
|
||||
/// <param name="relativePath">Should include the path relative to the share</param>
|
||||
/// <returns>The persistent portion of the FileID</returns>
|
||||
public ulong? AddOpenFile(string relativePath)
|
||||
{
|
||||
return AddOpenFile(relativePath, null);
|
||||
}
|
||||
|
||||
public ulong? AddOpenFile(string relativePath, Stream stream)
|
||||
{
|
||||
return AddOpenFile(relativePath, stream, false);
|
||||
}
|
||||
|
||||
public ulong? AddOpenFile(string relativePath, Stream stream, bool deleteOnClose)
|
||||
public ulong? AddOpenFile(string relativePath, object handle)
|
||||
{
|
||||
ulong? persistentID = m_connection.AllocatePersistentFileID();
|
||||
if (persistentID.HasValue)
|
||||
{
|
||||
m_openFiles.Add(persistentID.Value, new OpenFileObject(relativePath, stream, deleteOnClose));
|
||||
m_openFiles.Add(persistentID.Value, new OpenFileObject(relativePath, handle));
|
||||
}
|
||||
return persistentID;
|
||||
}
|
||||
|
@ -126,16 +115,11 @@ namespace SMBLibrary.Server
|
|||
|
||||
public void RemoveOpenFile(ulong fileID)
|
||||
{
|
||||
Stream stream = m_openFiles[fileID].Stream;
|
||||
if (stream != null)
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
m_openFiles.Remove(fileID);
|
||||
m_openSearches.Remove(fileID);
|
||||
}
|
||||
|
||||
public OpenSearch AddOpenSearch(ulong fileID, List<FileSystemEntry> entries, int enumerationLocation)
|
||||
public OpenSearch AddOpenSearch(ulong fileID, List<QueryDirectoryFileInformation> entries, int enumerationLocation)
|
||||
{
|
||||
OpenSearch openSearch = new OpenSearch(entries, enumerationLocation);
|
||||
m_openSearches.Add(fileID, openSearch);
|
||||
|
|
|
@ -1,155 +0,0 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server
|
||||
{
|
||||
public partial class NTFileSystemHelper
|
||||
{
|
||||
/// <param name="fileName">Expression as described in [MS-FSA] 2.1.4.4</param>
|
||||
public static NTStatus FindEntries(out List<FileSystemEntry> entries, IFileSystem fileSystem, string path, string fileName)
|
||||
{
|
||||
entries = null;
|
||||
FileSystemEntry entry = fileSystem.GetEntry(path);
|
||||
if (entry == null)
|
||||
{
|
||||
return NTStatus.STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (fileName == String.Empty)
|
||||
{
|
||||
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
bool findExactName = !ContainsWildcardCharacters(fileName);
|
||||
|
||||
if (!findExactName)
|
||||
{
|
||||
try
|
||||
{
|
||||
entries = fileSystem.ListEntriesInDirectory(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NTStatus status = ToNTStatus(ex);
|
||||
return status; ;
|
||||
}
|
||||
|
||||
entries = GetFiltered(entries, fileName);
|
||||
|
||||
// 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
|
||||
{
|
||||
path = FileSystem.GetDirectoryPath(path);
|
||||
entry = fileSystem.GetEntry(path + fileName);
|
||||
if (entry == null)
|
||||
{
|
||||
return NTStatus.STATUS_NO_SUCH_FILE;
|
||||
}
|
||||
entries = new List<FileSystemEntry>();
|
||||
entries.Add(entry);
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/// <param name="expression">Expression as described in [MS-FSA] 2.1.4.4</param>
|
||||
private static List<FileSystemEntry> GetFiltered(List<FileSystemEntry> entries, string expression)
|
||||
{
|
||||
if (expression == "*")
|
||||
{
|
||||
return entries;
|
||||
}
|
||||
|
||||
List<FileSystemEntry> result = new List<FileSystemEntry>();
|
||||
foreach (FileSystemEntry entry in entries)
|
||||
{
|
||||
if (IsFileNameInExpression(entry.Name, expression))
|
||||
{
|
||||
result.Add(entry);
|
||||
}
|
||||
}
|
||||
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
|
||||
// The FileName is string compared with Expression using the following wildcard rules:
|
||||
// * (asterisk) Matches zero or more characters.
|
||||
// ? (question mark) Matches a single character.
|
||||
// DOS_DOT (" quotation mark) Matches either a period or zero characters beyond the name string.
|
||||
// DOS_QM (> greater than) Matches any single character or, upon encountering a period or end of name string, advances the expression to the end of the set of contiguous DOS_QMs.
|
||||
// DOS_STAR (< less than) Matches zero or more characters until encountering and matching the final . in the name.
|
||||
private static bool IsFileNameInExpression(string fileName, string expression)
|
||||
{
|
||||
if (expression == "*")
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (expression.EndsWith("*")) // expression.Length > 1
|
||||
{
|
||||
string desiredFileNameStart = expression.Substring(0, expression.Length - 1);
|
||||
bool findExactNameWithoutExtension = false;
|
||||
if (desiredFileNameStart.EndsWith("\""))
|
||||
{
|
||||
findExactNameWithoutExtension = true;
|
||||
desiredFileNameStart = desiredFileNameStart.Substring(0, desiredFileNameStart.Length - 1);
|
||||
}
|
||||
|
||||
if (!findExactNameWithoutExtension)
|
||||
{
|
||||
if (fileName.StartsWith(desiredFileNameStart, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fileName.StartsWith(desiredFileNameStart + ".", StringComparison.InvariantCultureIgnoreCase) ||
|
||||
fileName.Equals(desiredFileNameStart, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (expression.StartsWith("<"))
|
||||
{
|
||||
string desiredFileNameEnd = expression.Substring(1);
|
||||
if (fileName.EndsWith(desiredFileNameEnd, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (String.Equals(fileName, expression, StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,22 +23,10 @@ namespace SMBLibrary.Server.SMB1
|
|||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
try
|
||||
header.Status = SMB1FileStoreHelper.CreateDirectory(share.FileStore, request.DirectoryName);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
fileSystem.CreateDirectory(request.DirectoryName);
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "CreateDirectory: Cannot create '{0}'", request.DirectoryName);
|
||||
header.Status = NTStatus.STATUS_OBJECT_NAME_INVALID;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "CreateDirectory: Cannot create '{0}', Access Denied", request.DirectoryName);
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
|
@ -53,51 +41,13 @@ namespace SMBLibrary.Server.SMB1
|
|||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
FileSystemEntry entry = fileSystem.GetEntry(request.DirectoryName);
|
||||
if (entry == null)
|
||||
header.Status = SMB1FileStoreHelper.DeleteDirectory(share.FileStore, request.DirectoryName);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fileSystem.Delete(request.DirectoryName);
|
||||
return new DeleteDirectoryResponse();
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "DeleteDirectory: Cannot delete '{0}'", request.DirectoryName);
|
||||
header.Status = NTStatus.STATUS_CANNOT_DELETE;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "DeleteDirectory: Cannot delete '{0}', Access Denied", request.DirectoryName);
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
}
|
||||
|
||||
internal static SMB1Command GetCheckDirectoryResponse(SMB1Header header, CheckDirectoryRequest request, FileSystemShare share)
|
||||
{
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
FileSystemEntry entry = fileSystem.GetEntry(request.DirectoryName);
|
||||
if (entry == null || !entry.IsDirectory)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
return new CheckDirectoryResponse();
|
||||
return new DeleteDirectoryResponse();
|
||||
}
|
||||
|
||||
internal static SMB1Command GetDeleteResponse(SMB1Header header, DeleteRequest request, FileSystemShare share, SMB1ConnectionState state)
|
||||
|
@ -108,39 +58,14 @@ namespace SMBLibrary.Server.SMB1
|
|||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
|
||||
if (entry == null)
|
||||
// [MS-CIFS] This command cannot delete directories or volumes.
|
||||
header.Status = SMB1FileStoreHelper.DeleteFile(share.FileStore, request.FileName);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if (!entry.IsDirectory && (request.SearchAttributes & SMBFileAttributes.Directory) > 0
|
||||
|| entry.IsDirectory && (request.SearchAttributes & SMBFileAttributes.Directory) == 0)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fileSystem.Delete(request.FileName);
|
||||
return new DeleteResponse();
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "Delete: Cannot delete '{0}'", request.FileName);
|
||||
header.Status = NTStatus.STATUS_CANNOT_DELETE;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "DeleteDirectory: Cannot delete '{0}', Access Denied", request.FileName);
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
return new DeleteResponse();
|
||||
}
|
||||
|
||||
internal static SMB1Command GetRenameResponse(SMB1Header header, RenameRequest request, FileSystemShare share, SMB1ConnectionState state)
|
||||
|
@ -156,59 +81,53 @@ namespace SMBLibrary.Server.SMB1
|
|||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
FileSystemEntry sourceEntry = fileSystem.GetEntry(request.OldFileName);
|
||||
if (sourceEntry == null)
|
||||
header.Status = SMB1FileStoreHelper.Rename(share.FileStore, request.OldFileName, request.NewFileName, request.SearchAttributes);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
return new RenameResponse();
|
||||
}
|
||||
|
||||
// The file must not already exist unless we just want to upcase / downcase a filename letter
|
||||
FileSystemEntry destinationEntry = fileSystem.GetEntry(request.NewFileName);
|
||||
if (destinationEntry != null &&
|
||||
!String.Equals(request.OldFileName, request.NewFileName, StringComparison.InvariantCultureIgnoreCase))
|
||||
internal static SMB1Command GetCheckDirectoryResponse(SMB1Header header, CheckDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
|
||||
{
|
||||
SMB1Session session = state.GetSession(header.UID);
|
||||
if (!share.HasReadAccess(session.UserName, request.DirectoryName, state.ClientEndPoint))
|
||||
{
|
||||
// The new file already exists.
|
||||
header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fileSystem.Move(request.OldFileName, request.NewFileName);
|
||||
return new RenameResponse();
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "Rename: Sharing violation renaming '{0}'", request.OldFileName);
|
||||
header.Status = NTStatus.STATUS_SHARING_VIOLATION;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "Rename: Cannot rename '{0}', Access Denied", request.OldFileName);
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
header.Status = SMB1FileStoreHelper.CheckDirectory(share.FileStore, request.DirectoryName);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
return new CheckDirectoryResponse();
|
||||
}
|
||||
|
||||
internal static SMB1Command GetQueryInformationResponse(SMB1Header header, QueryInformationRequest request, FileSystemShare share)
|
||||
internal static SMB1Command GetQueryInformationResponse(SMB1Header header, QueryInformationRequest request, FileSystemShare share, SMB1ConnectionState state)
|
||||
{
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
|
||||
if (entry == null)
|
||||
SMB1Session session = state.GetSession(header.UID);
|
||||
if (!share.HasReadAccess(session.UserName, request.FileName, state.ClientEndPoint))
|
||||
{
|
||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
FileNetworkOpenInformation fileInfo;
|
||||
header.Status = SMB1FileStoreHelper.QueryInformation(out fileInfo, share.FileStore, request.FileName);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
QueryInformationResponse response = new QueryInformationResponse();
|
||||
response.FileAttributes = SMB1FileSystemHelper.GetFileAttributes(entry);
|
||||
response.LastWriteTime = entry.LastWriteTime;
|
||||
response.FileSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
|
||||
|
||||
response.FileAttributes = SMB1FileStoreHelper.GetFileAttributes(fileInfo.FileAttributes);
|
||||
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||
response.FileSize = (uint)Math.Min(UInt32.MaxValue, fileInfo.EndOfFile);
|
||||
return response;
|
||||
}
|
||||
|
||||
|
@ -220,37 +139,13 @@ namespace SMBLibrary.Server.SMB1
|
|||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
|
||||
if (entry == null)
|
||||
header.Status = SMB1FileStoreHelper.SetInformation(share.FileStore, request.FileName, request.FileAttributes, request.LastWriteTime);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
bool? isHidden = null;
|
||||
bool? isReadOnly = null;
|
||||
bool? isArchived = null;
|
||||
if ((request.FileAttributes & SMBFileAttributes.Hidden) > 0)
|
||||
{
|
||||
isHidden = true;
|
||||
}
|
||||
if ((request.FileAttributes & SMBFileAttributes.ReadOnly) > 0)
|
||||
{
|
||||
isReadOnly = true;
|
||||
}
|
||||
if ((request.FileAttributes & SMBFileAttributes.Archive) > 0)
|
||||
{
|
||||
isArchived = true;
|
||||
}
|
||||
fileSystem.SetAttributes(request.FileName, isHidden, isReadOnly, isArchived);
|
||||
|
||||
if (request.LastWriteTime.HasValue)
|
||||
{
|
||||
fileSystem.SetDates(request.FileName, null, request.LastWriteTime, null);
|
||||
}
|
||||
|
||||
return new SetInformationResponse();
|
||||
}
|
||||
|
||||
|
@ -269,9 +164,13 @@ namespace SMBLibrary.Server.SMB1
|
|||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
|
||||
fileSystem.SetDates(openFile.Path, request.CreationDateTime, request.LastWriteDateTime, request.LastAccessDateTime);
|
||||
header.Status = SMB1FileStoreHelper.SetInformation2(share.FileStore, openFile.Handle, request.CreationDateTime, request.LastAccessDateTime, request.LastWriteDateTime);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
return new SetInformation2Response();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,60 +31,40 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
}
|
||||
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
NTStatus createStatus = share.FileStore.CreateFile(out handle, out fileStatus, path, request.DesiredAccess, request.ShareAccess, request.CreateDisposition, request.CreateOptions);
|
||||
if (createStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
header.Status = createStatus;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
ushort? fileID = session.AddOpenFile(path, handle);
|
||||
if (!fileID.HasValue)
|
||||
{
|
||||
share.FileStore.CloseFile(handle);
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
if (share is NamedPipeShare)
|
||||
{
|
||||
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
|
||||
if (pipeStream != null)
|
||||
if (isExtended)
|
||||
{
|
||||
ushort? fileID = session.AddOpenFile(path, pipeStream);
|
||||
if (!fileID.HasValue)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
if (isExtended)
|
||||
{
|
||||
return CreateResponseExtendedForNamedPipe(fileID.Value, FileStatus.FILE_OPENED);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED);
|
||||
}
|
||||
return CreateResponseExtendedForNamedPipe(fileID.Value, FileStatus.FILE_OPENED);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED);
|
||||
}
|
||||
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
else // FileSystemShare
|
||||
{
|
||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
||||
|
||||
FileSystemEntry entry;
|
||||
Stream stream;
|
||||
FileStatus fileStatus;
|
||||
NTStatus createStatus = NTFileSystemHelper.CreateFile(out entry, out stream, out fileStatus, fileSystemShare.FileSystem, path, request.DesiredAccess, request.ShareAccess, request.CreateDisposition, request.CreateOptions, state);
|
||||
if (createStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
header.Status = createStatus;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
FileAccess fileAccess = NTFileStoreHelper.ToFileAccess(request.DesiredAccess);
|
||||
|
||||
bool deleteOnClose = (stream != null) && ((request.CreateOptions & CreateOptions.FILE_DELETE_ON_CLOSE) > 0);
|
||||
ushort? fileID = session.AddOpenFile(path, stream, deleteOnClose);
|
||||
if (!fileID.HasValue)
|
||||
{
|
||||
if (stream != null)
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
|
||||
if (isExtended)
|
||||
{
|
||||
NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileSystemEntry(entry, fileID.Value, fileStatus);
|
||||
NTCreateAndXResponseExtended response = CreateResponseExtendedFromFileInformation(fileInfo, fileID.Value, fileStatus);
|
||||
if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
|
||||
{
|
||||
response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
|
||||
|
@ -93,7 +73,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
else
|
||||
{
|
||||
NTCreateAndXResponse response = CreateResponseFromFileSystemEntry(entry, fileID.Value, fileStatus);
|
||||
NTCreateAndXResponse response = CreateResponseFromFileInformation(fileInfo, fileID.Value, fileStatus);
|
||||
if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
|
||||
{
|
||||
response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
|
||||
|
@ -140,52 +120,38 @@ namespace SMBLibrary.Server.SMB1
|
|||
return response;
|
||||
}
|
||||
|
||||
private static NTCreateAndXResponse CreateResponseFromFileSystemEntry(FileSystemEntry entry, ushort fileID, FileStatus fileStatus)
|
||||
private static NTCreateAndXResponse CreateResponseFromFileInformation(FileNetworkOpenInformation fileInfo, ushort fileID, FileStatus fileStatus)
|
||||
{
|
||||
NTCreateAndXResponse response = new NTCreateAndXResponse();
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
response.ExtFileAttributes = ExtendedFileAttributes.Directory;
|
||||
response.Directory = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ExtFileAttributes = ExtendedFileAttributes.Normal;
|
||||
}
|
||||
response.FID = fileID;
|
||||
response.CreateDisposition = ToCreateDisposition(fileStatus);
|
||||
response.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
response.EndOfFile = (long)entry.Size;
|
||||
response.CreateTime = entry.CreationTime;
|
||||
response.LastAccessTime = entry.LastAccessTime;
|
||||
response.LastWriteTime = entry.LastWriteTime;
|
||||
response.LastChangeTime = entry.LastWriteTime;
|
||||
response.CreateTime = fileInfo.CreationTime;
|
||||
response.LastAccessTime = fileInfo.LastAccessTime;
|
||||
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||
response.LastChangeTime = fileInfo.LastWriteTime;
|
||||
response.AllocationSize = fileInfo.AllocationSize;
|
||||
response.EndOfFile = fileInfo.EndOfFile;
|
||||
response.ExtFileAttributes = (ExtendedFileAttributes)fileInfo.FileAttributes;
|
||||
response.ResourceType = ResourceType.FileTypeDisk;
|
||||
response.Directory = fileInfo.IsDirectory;
|
||||
return response;
|
||||
}
|
||||
|
||||
private static NTCreateAndXResponseExtended CreateResponseExtendedFromFileSystemEntry(FileSystemEntry entry, ushort fileID, FileStatus fileStatus)
|
||||
private static NTCreateAndXResponseExtended CreateResponseExtendedFromFileInformation(FileNetworkOpenInformation fileInfo, ushort fileID, FileStatus fileStatus)
|
||||
{
|
||||
NTCreateAndXResponseExtended response = new NTCreateAndXResponseExtended();
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
response.ExtFileAttributes = ExtendedFileAttributes.Directory;
|
||||
response.Directory = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.ExtFileAttributes = ExtendedFileAttributes.Normal;
|
||||
}
|
||||
response.FID = fileID;
|
||||
response.CreateDisposition = ToCreateDisposition(fileStatus);
|
||||
response.CreateTime = entry.CreationTime;
|
||||
response.LastAccessTime = entry.LastAccessTime;
|
||||
response.LastWriteTime = entry.LastWriteTime;
|
||||
response.LastChangeTime = entry.LastWriteTime;
|
||||
response.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
response.EndOfFile = (long)entry.Size;
|
||||
response.CreateTime = fileInfo.CreationTime;
|
||||
response.LastAccessTime = fileInfo.LastAccessTime;
|
||||
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||
response.LastChangeTime = fileInfo.LastWriteTime;
|
||||
response.ExtFileAttributes = (ExtendedFileAttributes)fileInfo.FileAttributes;
|
||||
response.AllocationSize = fileInfo.AllocationSize;
|
||||
response.EndOfFile = fileInfo.EndOfFile;
|
||||
response.ResourceType = ResourceType.FileTypeDisk;
|
||||
response.FileStatusFlags = FileStatusFlags.NO_EAS | FileStatusFlags.NO_SUBSTREAMS | FileStatusFlags.NO_REPARSETAG;
|
||||
response.Directory = fileInfo.IsDirectory;
|
||||
response.MaximalAccessRights.File = FileAccessMask.FILE_READ_DATA | FileAccessMask.FILE_WRITE_DATA | FileAccessMask.FILE_APPEND_DATA |
|
||||
FileAccessMask.FILE_READ_EA | FileAccessMask.FILE_WRITE_EA |
|
||||
FileAccessMask.FILE_EXECUTE |
|
||||
|
|
|
@ -48,38 +48,18 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
}
|
||||
|
||||
FileSystemEntry entry = null;
|
||||
Stream stream = null;
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
if (share is NamedPipeShare)
|
||||
header.Status = share.FileStore.CreateFile(out handle, out fileStatus, path, desiredAccess, shareAccess, createDisposition, createOptions);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
|
||||
if (pipeStream == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
fileStatus = FileStatus.FILE_OPENED;
|
||||
}
|
||||
else // FileSystemShare
|
||||
{
|
||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
||||
IFileSystem fileSystem = fileSystemShare.FileSystem;
|
||||
|
||||
header.Status = NTFileSystemHelper.CreateFile(out entry, out stream, out fileStatus, fileSystem, path, desiredAccess, shareAccess, createDisposition, createOptions, state);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
ushort? fileID = session.AddOpenFile(path, stream);
|
||||
ushort? fileID = session.AddOpenFile(path, handle);
|
||||
if (!fileID.HasValue)
|
||||
{
|
||||
if (stream != null)
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
share.FileStore.CloseFile(handle);
|
||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
@ -98,13 +78,14 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
else // FileSystemShare
|
||||
{
|
||||
FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
|
||||
if (isExtended)
|
||||
{
|
||||
return CreateResponseExtendedFromFileSystemEntry(entry, fileID.Value, openResult);
|
||||
return CreateResponseExtendedFromFileInfo(fileInfo, fileID.Value, openResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CreateResponseFromFileSystemEntry(entry, fileID.Value, openResult);
|
||||
return CreateResponseFromFileInfo(fileInfo, fileID.Value, openResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -288,40 +269,26 @@ namespace SMBLibrary.Server.SMB1
|
|||
return response;
|
||||
}
|
||||
|
||||
private static OpenAndXResponse CreateResponseFromFileSystemEntry(FileSystemEntry entry, ushort fileID, OpenResult openResult)
|
||||
private static OpenAndXResponse CreateResponseFromFileInfo(FileNetworkOpenInformation fileInfo, ushort fileID, OpenResult openResult)
|
||||
{
|
||||
OpenAndXResponse response = new OpenAndXResponse();
|
||||
response.FID = fileID;
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
response.FileAttrs = SMBFileAttributes.Directory;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.FileAttrs = SMBFileAttributes.Normal;
|
||||
}
|
||||
response.LastWriteTime = entry.LastWriteTime;
|
||||
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
|
||||
response.FileAttrs = SMB1FileStoreHelper.GetFileAttributes(fileInfo.FileAttributes);
|
||||
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, fileInfo.EndOfFile);
|
||||
response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;
|
||||
response.ResourceType = ResourceType.FileTypeDisk;
|
||||
response.OpenResults.OpenResult = openResult;
|
||||
return response;
|
||||
}
|
||||
|
||||
private static OpenAndXResponseExtended CreateResponseExtendedFromFileSystemEntry(FileSystemEntry entry, ushort fileID, OpenResult openResult)
|
||||
private static OpenAndXResponseExtended CreateResponseExtendedFromFileInfo(FileNetworkOpenInformation fileInfo, ushort fileID, OpenResult openResult)
|
||||
{
|
||||
OpenAndXResponseExtended response = new OpenAndXResponseExtended();
|
||||
response.FID = fileID;
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
response.FileAttrs = SMBFileAttributes.Directory;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.FileAttrs = SMBFileAttributes.Normal;
|
||||
}
|
||||
response.LastWriteTime = entry.LastWriteTime;
|
||||
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
|
||||
response.FileAttrs = SMB1FileStoreHelper.GetFileAttributes(fileInfo.FileAttributes);
|
||||
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, fileInfo.EndOfFile);
|
||||
response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;
|
||||
response.ResourceType = ResourceType.FileTypeDisk;
|
||||
response.OpenResults.OpenResult = openResult;
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
|
||||
byte[] data;
|
||||
header.Status = NTFileSystemHelper.ReadFile(out data, openFile, request.ReadOffsetInBytes, request.CountOfBytesToRead, state);
|
||||
header.Status = share.FileStore.ReadFile(out data, openFile.Handle, request.ReadOffsetInBytes, request.CountOfBytesToRead);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName);
|
||||
|
@ -74,7 +74,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
maxCount = request.MaxCountLarge;
|
||||
}
|
||||
byte[] data;
|
||||
header.Status = NTFileSystemHelper.ReadFile(out data, openFile, (long)request.Offset, (int)maxCount, state);
|
||||
header.Status = share.FileStore.ReadFile(out data, openFile.Handle, (long)request.Offset, (int)maxCount);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName);
|
||||
|
@ -108,9 +108,9 @@ namespace SMBLibrary.Server.SMB1
|
|||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int numberOfBytesWritten;
|
||||
header.Status = NTFileSystemHelper.WriteFile(out numberOfBytesWritten, openFile, request.WriteOffsetInBytes, request.Data, state);
|
||||
header.Status = share.FileStore.WriteFile(out numberOfBytesWritten, openFile.Handle, request.WriteOffsetInBytes, request.Data);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName);
|
||||
|
@ -129,7 +129,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
|
||||
|
||||
if (share is FileSystemShare)
|
||||
{
|
||||
if (!((FileSystemShare)share).HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||
|
@ -140,7 +140,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
|
||||
int numberOfBytesWritten;
|
||||
header.Status = NTFileSystemHelper.WriteFile(out numberOfBytesWritten, openFile, (long)request.Offset, request.Data, state);
|
||||
header.Status = share.FileStore.WriteFile(out numberOfBytesWritten, openFile.Handle, (long)request.Offset, request.Data);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName);
|
||||
|
|
200
SMBLibrary/Server/SMB1/SMB1FileStoreHelper.Query.cs
Normal file
200
SMBLibrary/Server/SMB1/SMB1FileStoreHelper.Query.cs
Normal file
|
@ -0,0 +1,200 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SMBLibrary.SMB1;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server.SMB1
|
||||
{
|
||||
public partial class SMB1FileStoreHelper
|
||||
{
|
||||
public static NTStatus GetFileInformation(out QueryInformation result, INTFileStore fileStore, string path, QueryInformationLevel informationLevel)
|
||||
{
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
NTStatus openStatus = fileStore.CreateFile(out handle, out fileStatus, path, FileAccessMask.FILE_READ_ATTRIBUTES, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OPEN, 0);
|
||||
if (openStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
result = null;
|
||||
return openStatus;
|
||||
}
|
||||
NTStatus returnStatus = GetFileInformation(out result, fileStore, handle, informationLevel);
|
||||
fileStore.CloseFile(handle);
|
||||
return returnStatus;
|
||||
}
|
||||
|
||||
public static NTStatus GetFileInformation(out QueryInformation result, INTFileStore fileStore, object handle, QueryInformationLevel informationLevel)
|
||||
{
|
||||
result = null;
|
||||
FileInformation fileInfo;
|
||||
switch (informationLevel)
|
||||
{
|
||||
case QueryInformationLevel.SMB_INFO_QUERY_ALL_EAS:
|
||||
{
|
||||
result = null;
|
||||
return NTStatus.STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
case QueryInformationLevel.SMB_INFO_IS_NAME_VALID:
|
||||
{
|
||||
result = null;
|
||||
return NTStatus.STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_BASIC_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileBasicInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileBasicInformation fileBasicInfo = (FileBasicInformation)fileInfo;
|
||||
|
||||
QueryFileBasicInfo information = new QueryFileBasicInfo();
|
||||
information.CreationTime = fileBasicInfo.CreationTime;
|
||||
information.LastAccessTime = fileBasicInfo.LastAccessTime;
|
||||
information.LastWriteTime = fileBasicInfo.LastWriteTime;
|
||||
information.LastChangeTime = fileBasicInfo.LastWriteTime;
|
||||
information.ExtFileAttributes = (ExtendedFileAttributes)fileBasicInfo.FileAttributes;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_STANDARD_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileStandardInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileStandardInformation fileStandardInfo = (FileStandardInformation)fileInfo;
|
||||
|
||||
QueryFileStandardInfo information = new QueryFileStandardInfo();
|
||||
information.AllocationSize = fileStandardInfo.AllocationSize;
|
||||
information.EndOfFile = fileStandardInfo.EndOfFile;
|
||||
information.DeletePending = fileStandardInfo.DeletePending;
|
||||
information.Directory = fileStandardInfo.Directory;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_EA_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileEaInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileEaInformation fileEAInfo = (FileEaInformation)fileInfo;
|
||||
|
||||
QueryFileExtendedAttributeInfo information = new QueryFileExtendedAttributeInfo();
|
||||
information.EASize = fileEAInfo.EaSize;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_NAME_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileNameInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileNameInformation fileNameInfo = (FileNameInformation)fileInfo;
|
||||
|
||||
QueryFileNameInfo information = new QueryFileNameInfo();
|
||||
information.FileName = fileNameInfo.FileName;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_ALL_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileAllInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileAllInformation fileAllInfo = (FileAllInformation)fileInfo;
|
||||
|
||||
QueryFileAllInfo information = new QueryFileAllInfo();
|
||||
information.CreationDateTime = fileAllInfo.BasicInformation.CreationTime;
|
||||
information.LastAccessDateTime = fileAllInfo.BasicInformation.LastAccessTime;
|
||||
information.LastWriteDateTime = fileAllInfo.BasicInformation.LastWriteTime;
|
||||
information.LastChangeTime = fileAllInfo.BasicInformation.LastWriteTime;
|
||||
information.ExtFileAttributes = (ExtendedFileAttributes)fileAllInfo.BasicInformation.FileAttributes;
|
||||
information.AllocationSize = fileAllInfo.StandardInformation.AllocationSize;
|
||||
information.EndOfFile = fileAllInfo.StandardInformation.EndOfFile;
|
||||
information.DeletePending = fileAllInfo.StandardInformation.DeletePending;
|
||||
information.Directory = fileAllInfo.StandardInformation.Directory;
|
||||
information.EASize = fileAllInfo.EaInformation.EaSize;
|
||||
information.FileName = fileAllInfo.NameInformation.FileName;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_ALT_NAME_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileAlternateNameInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileAlternateNameInformation fileAltNameInfo = (FileAlternateNameInformation)fileInfo;
|
||||
|
||||
QueryFileAltNameInfo information = new QueryFileAltNameInfo();
|
||||
information.FileName = fileAltNameInfo.FileName;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_STREAM_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileStreamInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileStreamInformation fileStreamInfo = (FileStreamInformation)fileInfo;
|
||||
|
||||
QueryFileStreamInfo information = new QueryFileStreamInfo();
|
||||
information.StreamSize = fileStreamInfo.StreamSize;
|
||||
information.StreamAllocationSize = fileStreamInfo.StreamAllocationSize;
|
||||
information.StreamName = fileStreamInfo.StreamName;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_COMPRESSION_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileInformation(out fileInfo, handle, FileInformationClass.FileCompressionInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileCompressionInformation fileCompressionInfo = (FileCompressionInformation)fileInfo;
|
||||
|
||||
QueryFileCompressionInfo information = new QueryFileCompressionInfo();
|
||||
information.CompressedFileSize = fileCompressionInfo.CompressedFileSize;
|
||||
information.CompressionFormat = fileCompressionInfo.CompressionFormat;
|
||||
information.CompressionUnitShift = fileCompressionInfo.CompressionUnitShift;
|
||||
information.ChunkShift = fileCompressionInfo.ChunkShift;
|
||||
information.ClusterShift = fileCompressionInfo.ClusterShift;
|
||||
information.Reserved = fileCompressionInfo.Reserved;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
default:
|
||||
{
|
||||
result = null;
|
||||
return NTStatus.STATUS_OS2_INVALID_LEVEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
139
SMBLibrary/Server/SMB1/SMB1FileStoreHelper.QueryDirectory.cs
Normal file
139
SMBLibrary/Server/SMB1/SMB1FileStoreHelper.QueryDirectory.cs
Normal file
|
@ -0,0 +1,139 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SMBLibrary.SMB1;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server.SMB1
|
||||
{
|
||||
public partial class SMB1FileStoreHelper
|
||||
{
|
||||
// Filename pattern examples:
|
||||
// '\Directory' - Get the directory entry
|
||||
// '\Directory\*' - List the directory files
|
||||
// '\Directory\s*' - List the directory files starting with s (cmd.exe will use this syntax when entering 's' and hitting tab for autocomplete)
|
||||
// '\Directory\<.inf' (Update driver will use this syntax)
|
||||
// '\Directory\exefile"*' (cmd.exe will use this syntax when entering an exe without its extension, explorer will use this opening a directory from the run menu)
|
||||
/// <param name="fileNamePattern">The filename pattern to search for. This field MAY contain wildcard characters</param>
|
||||
/// <exception cref="System.UnauthorizedAccessException"></exception>
|
||||
public static NTStatus QueryDirectory(out List<QueryDirectoryFileInformation> result, INTFileStore fileStore, string fileNamePattern, FileInformationClass fileInformation)
|
||||
{
|
||||
int separatorIndex = fileNamePattern.LastIndexOf('\\');
|
||||
if (separatorIndex >= 0)
|
||||
{
|
||||
string path = fileNamePattern.Substring(0, separatorIndex + 1);
|
||||
string fileName = fileNamePattern.Substring(separatorIndex + 1);
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
NTStatus createStatus = fileStore.CreateFile(out handle, out fileStatus, path, DirectoryAccessMask.FILE_LIST_DIRECTORY | DirectoryAccessMask.FILE_TRAVERSE, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE);
|
||||
if (createStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
result = null;
|
||||
return createStatus;
|
||||
}
|
||||
return fileStore.QueryDirectory(out result, handle, fileName, fileInformation);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = null;
|
||||
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
/// <exception cref="SMBLibrary.UnsupportedInformationLevelException"></exception>
|
||||
public static FindInformationList GetFindInformationList(List<QueryDirectoryFileInformation> entries, FindInformationLevel informationLevel, bool isUnicode, bool returnResumeKeys, int maxLength)
|
||||
{
|
||||
FindInformationList result = new FindInformationList();
|
||||
for (int index = 0; index < entries.Count; index++)
|
||||
{
|
||||
FindInformation infoEntry = GetFindInformation(entries[index], informationLevel, isUnicode, returnResumeKeys);
|
||||
result.Add(infoEntry);
|
||||
if (result.GetLength(isUnicode) > maxLength)
|
||||
{
|
||||
result.RemoveAt(result.Count - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <exception cref="SMBLibrary.UnsupportedInformationLevelException"></exception>
|
||||
public static FindInformation GetFindInformation(QueryDirectoryFileInformation entry, FindInformationLevel informationLevel, bool isUnicode, bool returnResumeKeys)
|
||||
{
|
||||
switch (informationLevel)
|
||||
{
|
||||
case FindInformationLevel.SMB_FIND_FILE_DIRECTORY_INFO:
|
||||
{
|
||||
FileDirectoryInformation fileDirectoryInfo = (FileDirectoryInformation)entry;
|
||||
|
||||
FindFileDirectoryInfo result = new FindFileDirectoryInfo();
|
||||
result.FileIndex = fileDirectoryInfo.FileIndex;
|
||||
result.CreationTime = fileDirectoryInfo.CreationTime;
|
||||
result.LastAccessTime = fileDirectoryInfo.LastAccessTime;
|
||||
result.LastWriteTime = fileDirectoryInfo.LastWriteTime;
|
||||
result.LastAttrChangeTime = fileDirectoryInfo.LastWriteTime;
|
||||
result.EndOfFile = fileDirectoryInfo.EndOfFile;
|
||||
result.AllocationSize = fileDirectoryInfo.AllocationSize;
|
||||
result.ExtFileAttributes = (ExtendedFileAttributes)fileDirectoryInfo.FileAttributes;
|
||||
result.FileName = fileDirectoryInfo.FileName;
|
||||
return result;
|
||||
}
|
||||
case FindInformationLevel.SMB_FIND_FILE_FULL_DIRECTORY_INFO:
|
||||
{
|
||||
FileFullDirectoryInformation fileFullDirectoryInfo = (FileFullDirectoryInformation)entry;
|
||||
|
||||
FindFileFullDirectoryInfo result = new FindFileFullDirectoryInfo();
|
||||
result.FileIndex = fileFullDirectoryInfo.FileIndex;
|
||||
result.CreationTime = fileFullDirectoryInfo.CreationTime;
|
||||
result.LastAccessTime = fileFullDirectoryInfo.LastAccessTime;
|
||||
result.LastWriteTime = fileFullDirectoryInfo.LastWriteTime;
|
||||
result.LastAttrChangeTime = fileFullDirectoryInfo.LastWriteTime;
|
||||
result.EndOfFile = fileFullDirectoryInfo.EndOfFile;
|
||||
result.AllocationSize = fileFullDirectoryInfo.AllocationSize;
|
||||
result.ExtFileAttributes = (ExtendedFileAttributes)fileFullDirectoryInfo.FileAttributes;
|
||||
result.EASize = fileFullDirectoryInfo.EaSize;
|
||||
result.FileName = fileFullDirectoryInfo.FileName;
|
||||
return result;
|
||||
}
|
||||
case FindInformationLevel.SMB_FIND_FILE_NAMES_INFO:
|
||||
{
|
||||
FileNamesInformation fileNamesInfo = (FileNamesInformation)entry;
|
||||
|
||||
FindFileNamesInfo result = new FindFileNamesInfo();
|
||||
result.FileIndex = fileNamesInfo.FileIndex;
|
||||
result.FileName = fileNamesInfo.FileName;
|
||||
return result;
|
||||
}
|
||||
case FindInformationLevel.SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
|
||||
{
|
||||
FileBothDirectoryInformation fileBothDirectoryInfo = (FileBothDirectoryInformation)entry;
|
||||
|
||||
FindFileBothDirectoryInfo result = new FindFileBothDirectoryInfo();
|
||||
result.FileIndex = fileBothDirectoryInfo.FileIndex;
|
||||
result.CreationTime = fileBothDirectoryInfo.CreationTime;
|
||||
result.LastAccessTime = fileBothDirectoryInfo.LastAccessTime;
|
||||
result.LastWriteTime = fileBothDirectoryInfo.LastWriteTime;
|
||||
result.LastChangeTime = fileBothDirectoryInfo.LastWriteTime;
|
||||
result.EndOfFile = fileBothDirectoryInfo.EndOfFile;
|
||||
result.AllocationSize = fileBothDirectoryInfo.AllocationSize;
|
||||
result.ExtFileAttributes = (ExtendedFileAttributes)fileBothDirectoryInfo.FileAttributes;
|
||||
result.EASize = fileBothDirectoryInfo.EaSize;
|
||||
result.Reserved = fileBothDirectoryInfo.Reserved;
|
||||
result.ShortName = fileBothDirectoryInfo.ShortName;
|
||||
result.FileName = fileBothDirectoryInfo.FileName;
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new UnsupportedInformationLevelException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SMBLibrary.SMB1;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server.SMB1
|
||||
{
|
||||
public partial class SMB1FileStoreHelper
|
||||
{
|
||||
public static NTStatus GetFileSystemInformation(out QueryFSInformation result, INTFileStore fileStore, QueryFSInformationLevel informationLevel)
|
||||
{
|
||||
result = null;
|
||||
|
||||
FileSystemInformation fsInfo;
|
||||
switch (informationLevel)
|
||||
{
|
||||
case QueryFSInformationLevel.SMB_QUERY_FS_VOLUME_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileSystemInformation(out fsInfo, FileSystemInformationClass.FileFsVolumeInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileFsVolumeInformation volumeInfo = (FileFsVolumeInformation)fsInfo;
|
||||
|
||||
QueryFSVolumeInfo information = new QueryFSVolumeInfo();
|
||||
information.VolumeCreationTime = volumeInfo.VolumeCreationTime;
|
||||
information.SerialNumber = volumeInfo.VolumeSerialNumber;
|
||||
information.VolumeLabel = volumeInfo.VolumeLabel;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryFSInformationLevel.SMB_QUERY_FS_SIZE_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileSystemInformation(out fsInfo, FileSystemInformationClass.FileFsSizeInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileFsSizeInformation fsSizeInfo = (FileFsSizeInformation)fsInfo;
|
||||
|
||||
QueryFSSizeInfo information = new QueryFSSizeInfo();
|
||||
information.TotalAllocationUnits = fsSizeInfo.TotalAllocationUnits;
|
||||
information.TotalFreeAllocationUnits = fsSizeInfo.AvailableAllocationUnits;
|
||||
information.BytesPerSector = fsSizeInfo.BytesPerSector;
|
||||
information.SectorsPerAllocationUnit = fsSizeInfo.SectorsPerAllocationUnit;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryFSInformationLevel.SMB_QUERY_FS_DEVICE_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileSystemInformation(out fsInfo, FileSystemInformationClass.FileFsDeviceInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileFsDeviceInformation fsDeviceInfo = (FileFsDeviceInformation)fsInfo;
|
||||
|
||||
QueryFSDeviceInfo information = new QueryFSDeviceInfo();
|
||||
information.DeviceType = fsDeviceInfo.DeviceType;
|
||||
information.DeviceCharacteristics = fsDeviceInfo.Characteristics;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryFSInformationLevel.SMB_QUERY_FS_ATTRIBUTE_INFO:
|
||||
{
|
||||
NTStatus status = fileStore.GetFileSystemInformation(out fsInfo, FileSystemInformationClass.FileFsAttributeInformation);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
FileFsAttributeInformation fsAttributeInfo = (FileFsAttributeInformation)fsInfo;
|
||||
|
||||
QueryFSAttibuteInfo information = new QueryFSAttibuteInfo();
|
||||
information.FileSystemAttributes = fsAttributeInfo.FileSystemAttributes;
|
||||
information.MaxFileNameLengthInBytes = fsAttributeInfo.MaximumComponentNameLength;
|
||||
information.FileSystemName = fsAttributeInfo.FileSystemName;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
default:
|
||||
{
|
||||
return NTStatus.STATUS_OS2_INVALID_LEVEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
58
SMBLibrary/Server/SMB1/SMB1FileStoreHelper.Set.cs
Normal file
58
SMBLibrary/Server/SMB1/SMB1FileStoreHelper.Set.cs
Normal file
|
@ -0,0 +1,58 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SMBLibrary.SMB1;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server.SMB1
|
||||
{
|
||||
public partial class SMB1FileStoreHelper
|
||||
{
|
||||
public static NTStatus SetFileInformation(INTFileStore fileStore, object handle, SetInformation information)
|
||||
{
|
||||
if (information is SetFileBasicInfo)
|
||||
{
|
||||
SetFileBasicInfo basicInfo = (SetFileBasicInfo)information;
|
||||
FileBasicInformation fileBasicInfo = new FileBasicInformation();
|
||||
fileBasicInfo.CreationTime = basicInfo.CreationTime;
|
||||
fileBasicInfo.LastAccessTime = basicInfo.LastAccessTime;
|
||||
fileBasicInfo.LastWriteTime = basicInfo.LastWriteTime;
|
||||
fileBasicInfo.ChangeTime = basicInfo.LastChangeTime;
|
||||
fileBasicInfo.FileAttributes = (FileAttributes)basicInfo.ExtFileAttributes;
|
||||
fileBasicInfo.Reserved = basicInfo.Reserved;
|
||||
return fileStore.SetFileInformation(handle, fileBasicInfo);
|
||||
}
|
||||
else if (information is SetFileDispositionInfo)
|
||||
{
|
||||
FileDispositionInformation fileDispositionInfo = new FileDispositionInformation();
|
||||
fileDispositionInfo.DeletePending = ((SetFileDispositionInfo)information).DeletePending;
|
||||
return fileStore.SetFileInformation(handle, fileDispositionInfo);
|
||||
}
|
||||
else if (information is SetFileAllocationInfo)
|
||||
{
|
||||
// This information level is used to set the file length in bytes.
|
||||
// Note: the input will NOT be a multiple of the cluster size / bytes per sector.
|
||||
FileAllocationInformation fileAllocationInfo = new FileAllocationInformation();
|
||||
fileAllocationInfo.AllocationSize = ((SetFileAllocationInfo)information).AllocationSize;
|
||||
return fileStore.SetFileInformation(handle, fileAllocationInfo);
|
||||
}
|
||||
else if (information is SetFileEndOfFileInfo)
|
||||
{
|
||||
FileEndOfFileInformation fileEndOfFileInfo = new FileEndOfFileInformation();
|
||||
fileEndOfFileInfo.EndOfFile = ((SetFileEndOfFileInfo)information).EndOfFile;
|
||||
return fileStore.SetFileInformation(handle, fileEndOfFileInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
return NTStatus.STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
184
SMBLibrary/Server/SMB1/SMB1FileStoreHelper.cs
Normal file
184
SMBLibrary/Server/SMB1/SMB1FileStoreHelper.cs
Normal file
|
@ -0,0 +1,184 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SMBLibrary.SMB1;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server.SMB1
|
||||
{
|
||||
public partial class SMB1FileStoreHelper
|
||||
{
|
||||
public static NTStatus CreateDirectory(INTFileStore fileStore, string path)
|
||||
{
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
NTStatus createStatus = fileStore.CreateFile(out handle, out fileStatus, path, DirectoryAccessMask.FILE_ADD_SUBDIRECTORY, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_CREATE, CreateOptions.FILE_DIRECTORY_FILE);
|
||||
if (createStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return createStatus;
|
||||
}
|
||||
fileStore.CloseFile(handle);
|
||||
return createStatus;
|
||||
}
|
||||
|
||||
public static NTStatus DeleteDirectory(INTFileStore fileStore, string path)
|
||||
{
|
||||
return Delete(fileStore, path, CreateOptions.FILE_DIRECTORY_FILE);
|
||||
}
|
||||
|
||||
public static NTStatus DeleteFile(INTFileStore fileStore, string path)
|
||||
{
|
||||
return Delete(fileStore, path, CreateOptions.FILE_NON_DIRECTORY_FILE);
|
||||
}
|
||||
|
||||
public static NTStatus Delete(INTFileStore fileStore, string path, CreateOptions createOptions)
|
||||
{
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
NTStatus openStatus = fileStore.CreateFile(out handle, out fileStatus, path, DirectoryAccessMask.DELETE, 0, CreateDisposition.FILE_OPEN, createOptions);
|
||||
if (openStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return openStatus;
|
||||
}
|
||||
FileDispositionInformation fileDispositionInfo = new FileDispositionInformation();
|
||||
fileDispositionInfo.DeletePending = true;
|
||||
NTStatus setStatus = fileStore.SetFileInformation(handle, fileDispositionInfo);
|
||||
if (setStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return setStatus;
|
||||
}
|
||||
NTStatus closeStatus = fileStore.CloseFile(handle);
|
||||
return closeStatus;
|
||||
}
|
||||
|
||||
public static NTStatus Rename(INTFileStore fileStore, string oldName, string newName, SMBFileAttributes searchAttributes)
|
||||
{
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
CreateOptions createOptions = 0;
|
||||
if (searchAttributes == SMBFileAttributes.Normal)
|
||||
{
|
||||
createOptions = CreateOptions.FILE_NON_DIRECTORY_FILE;
|
||||
}
|
||||
else if ((searchAttributes & SMBFileAttributes.Directory) > 0)
|
||||
{
|
||||
createOptions = CreateOptions.FILE_DIRECTORY_FILE;
|
||||
}
|
||||
NTStatus openStatus = fileStore.CreateFile(out handle, out fileStatus, oldName, DirectoryAccessMask.DELETE, 0, CreateDisposition.FILE_OPEN, createOptions);
|
||||
if (openStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return openStatus;
|
||||
}
|
||||
FileRenameInformationType2 renameInfo = new FileRenameInformationType2();
|
||||
renameInfo.ReplaceIfExists = false;
|
||||
renameInfo.FileName = newName;
|
||||
NTStatus setStatus = fileStore.SetFileInformation(handle, renameInfo);
|
||||
if (setStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return setStatus;
|
||||
}
|
||||
NTStatus closeStatus = fileStore.CloseFile(handle);
|
||||
return closeStatus;
|
||||
}
|
||||
|
||||
public static NTStatus CheckDirectory(INTFileStore fileStore, string path)
|
||||
{
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
NTStatus openStatus = fileStore.CreateFile(out handle, out fileStatus, path, (AccessMask)0, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE);
|
||||
if (openStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return openStatus;
|
||||
}
|
||||
|
||||
fileStore.CloseFile(handle);
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public static NTStatus QueryInformation(out FileNetworkOpenInformation fileInfo, INTFileStore fileStore, string path)
|
||||
{
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
NTStatus openStatus = fileStore.CreateFile(out handle, out fileStatus, path, FileAccessMask.FILE_READ_ATTRIBUTES, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OPEN, 0);
|
||||
if (openStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
fileInfo = null;
|
||||
return openStatus;
|
||||
}
|
||||
|
||||
fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(fileStore, handle);
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public static NTStatus SetInformation(INTFileStore fileStore, string path, SMBFileAttributes fileAttributes, DateTime? lastWriteTime)
|
||||
{
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
NTStatus openStatus = fileStore.CreateFile(out handle, out fileStatus, path, FileAccessMask.FILE_WRITE_ATTRIBUTES, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OPEN, 0);
|
||||
if (openStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return openStatus;
|
||||
}
|
||||
|
||||
FileBasicInformation basicInfo = new FileBasicInformation();
|
||||
basicInfo.LastWriteTime = lastWriteTime;
|
||||
|
||||
if ((fileAttributes & SMBFileAttributes.Hidden) > 0)
|
||||
{
|
||||
basicInfo.FileAttributes |= FileAttributes.Hidden;
|
||||
}
|
||||
|
||||
if ((fileAttributes & SMBFileAttributes.ReadOnly) > 0)
|
||||
{
|
||||
basicInfo.FileAttributes |= FileAttributes.ReadOnly;
|
||||
}
|
||||
|
||||
if ((fileAttributes & SMBFileAttributes.Archive) > 0)
|
||||
{
|
||||
basicInfo.FileAttributes |= FileAttributes.Archive;
|
||||
}
|
||||
|
||||
return fileStore.SetFileInformation(handle, basicInfo);
|
||||
}
|
||||
|
||||
public static NTStatus SetInformation2(INTFileStore fileStore, object handle, DateTime? creationTime, DateTime? lastAccessTime, DateTime? lastWriteTime)
|
||||
{
|
||||
FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(fileStore, handle);
|
||||
FileBasicInformation basicInfo = new FileBasicInformation();
|
||||
basicInfo.FileAttributes = fileInfo.FileAttributes;
|
||||
basicInfo.CreationTime = creationTime;
|
||||
basicInfo.LastAccessTime = lastAccessTime;
|
||||
basicInfo.LastWriteTime = lastWriteTime;
|
||||
return fileStore.SetFileInformation(handle, basicInfo);
|
||||
}
|
||||
|
||||
public static SMBFileAttributes GetFileAttributes(FileAttributes attributes)
|
||||
{
|
||||
SMBFileAttributes result = SMBFileAttributes.Normal;
|
||||
if ((attributes & FileAttributes.Hidden) > 0)
|
||||
{
|
||||
result |= SMBFileAttributes.Hidden;
|
||||
}
|
||||
if ((attributes & FileAttributes.ReadOnly) > 0)
|
||||
{
|
||||
result |= SMBFileAttributes.ReadOnly;
|
||||
}
|
||||
if ((attributes & FileAttributes.Archive) > 0)
|
||||
{
|
||||
result |= SMBFileAttributes.Archive;
|
||||
}
|
||||
if ((attributes & FileAttributes.Directory) > 0)
|
||||
{
|
||||
result |= SMBFileAttributes.Directory;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SMBLibrary.SMB1;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server.SMB1
|
||||
{
|
||||
public partial class SMB1FileSystemHelper
|
||||
{
|
||||
// Filename pattern examples:
|
||||
// '\Directory' - Get the directory entry
|
||||
// '\Directory\*' - List the directory files
|
||||
// '\Directory\s*' - List the directory files starting with s (cmd.exe will use this syntax when entering 's' and hitting tab for autocomplete)
|
||||
// '\Directory\<.inf' (Update driver will use this syntax)
|
||||
// '\Directory\exefile"*' (cmd.exe will use this syntax when entering an exe without its extension, explorer will use this opening a directory from the run menu)
|
||||
/// <param name="fileNamePattern">The filename pattern to search for. This field MAY contain wildcard characters</param>
|
||||
/// <exception cref="System.UnauthorizedAccessException"></exception>
|
||||
public static NTStatus FindEntries(out List<FileSystemEntry> entries, IFileSystem fileSystem, string fileNamePattern)
|
||||
{
|
||||
int separatorIndex = fileNamePattern.LastIndexOf('\\');
|
||||
if (separatorIndex >= 0)
|
||||
{
|
||||
string path = fileNamePattern.Substring(0, separatorIndex + 1);
|
||||
string fileName = fileNamePattern.Substring(separatorIndex + 1);
|
||||
return NTFileSystemHelper.FindEntries(out entries, fileSystem, path, fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
entries = null;
|
||||
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
/// <exception cref="SMBLibrary.UnsupportedInformationLevelException"></exception>
|
||||
public static FindInformationList GetFindInformationList(List<FileSystemEntry> entries, FindInformationLevel informationLevel, bool isUnicode, bool returnResumeKeys, int maxLength)
|
||||
{
|
||||
FindInformationList result = new FindInformationList();
|
||||
for (int index = 0; index < entries.Count; index++)
|
||||
{
|
||||
FindInformation infoEntry = GetFindInformation(entries[index], informationLevel, isUnicode, returnResumeKeys);
|
||||
result.Add(infoEntry);
|
||||
if (result.GetLength(isUnicode) > maxLength)
|
||||
{
|
||||
result.RemoveAt(result.Count - 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <exception cref="SMBLibrary.UnsupportedInformationLevelException"></exception>
|
||||
public static FindInformation GetFindInformation(FileSystemEntry entry, FindInformationLevel informationLevel, bool isUnicode, bool returnResumeKeys)
|
||||
{
|
||||
switch (informationLevel)
|
||||
{
|
||||
case FindInformationLevel.SMB_FIND_FILE_DIRECTORY_INFO:
|
||||
{
|
||||
FindFileDirectoryInfo result = new FindFileDirectoryInfo();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.LastAttrChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
result.ExtFileAttributes = GetExtendedFileAttributes(entry);
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FindInformationLevel.SMB_FIND_FILE_FULL_DIRECTORY_INFO:
|
||||
{
|
||||
FindFileFullDirectoryInfo result = new FindFileFullDirectoryInfo();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.LastAttrChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
result.ExtFileAttributes = GetExtendedFileAttributes(entry);
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FindInformationLevel.SMB_FIND_FILE_NAMES_INFO:
|
||||
{
|
||||
FindFileNamesInfo result = new FindFileNamesInfo();
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FindInformationLevel.SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
|
||||
{
|
||||
FindFileBothDirectoryInfo result = new FindFileBothDirectoryInfo();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.LastChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
result.ExtFileAttributes = GetExtendedFileAttributes(entry);
|
||||
result.ShortName = NTFileSystemHelper.GetShortName(entry.Name);
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new UnsupportedInformationLevelException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SMBLibrary.SMB1;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server.SMB1
|
||||
{
|
||||
public partial class SMB1FileSystemHelper
|
||||
{
|
||||
public static NTStatus GetFileInformation(out QueryInformation result, FileSystemEntry entry, bool deletePending, QueryInformationLevel informationLevel)
|
||||
{
|
||||
switch (informationLevel)
|
||||
{
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_BASIC_INFO:
|
||||
{
|
||||
QueryFileBasicInfo information = new QueryFileBasicInfo();
|
||||
information.CreationTime = entry.CreationTime;
|
||||
information.LastAccessTime = entry.LastAccessTime;
|
||||
information.LastWriteTime = entry.LastWriteTime;
|
||||
information.LastChangeTime = entry.LastWriteTime;
|
||||
information.ExtFileAttributes = GetExtendedFileAttributes(entry);
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_STANDARD_INFO:
|
||||
{
|
||||
QueryFileStandardInfo information = new QueryFileStandardInfo();
|
||||
information.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
information.EndOfFile = (long)entry.Size;
|
||||
information.DeletePending = deletePending;
|
||||
information.Directory = entry.IsDirectory;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_EA_INFO:
|
||||
{
|
||||
QueryFileExtendedAttributeInfo information = new QueryFileExtendedAttributeInfo();
|
||||
information.EASize = 0;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_NAME_INFO:
|
||||
{
|
||||
QueryFileNameInfo information = new QueryFileNameInfo();
|
||||
information.FileName = entry.Name;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_ALL_INFO:
|
||||
{
|
||||
QueryFileAllInfo information = new QueryFileAllInfo();
|
||||
information.CreationDateTime = entry.CreationTime;
|
||||
information.LastAccessDateTime = entry.LastAccessTime;
|
||||
information.LastWriteDateTime = entry.LastWriteTime;
|
||||
information.ExtFileAttributes = GetExtendedFileAttributes(entry);
|
||||
information.LastChangeTime = entry.LastWriteTime;
|
||||
information.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
information.EndOfFile = (long)entry.Size;
|
||||
information.DeletePending = deletePending;
|
||||
information.Directory = entry.IsDirectory;
|
||||
information.EASize = 0;
|
||||
information.FileName = entry.Name;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_ALT_NAME_INFO:
|
||||
{
|
||||
QueryFileAltNameInfo information = new QueryFileAltNameInfo();
|
||||
information.FileName = NTFileSystemHelper.GetShortName(entry.Name);
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_STREAM_INFO:
|
||||
{
|
||||
QueryFileStreamInfo information = new QueryFileStreamInfo();
|
||||
information.StreamSize = (long)entry.Size;
|
||||
information.StreamAllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
information.StreamName = "::$DATA";
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryInformationLevel.SMB_QUERY_FILE_COMPRESSION_INFO:
|
||||
{
|
||||
QueryFileCompressionInfo information = new QueryFileCompressionInfo();
|
||||
information.CompressionFormat = CompressionFormat.COMPRESSION_FORMAT_NONE;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
default:
|
||||
{
|
||||
result = null;
|
||||
return NTStatus.STATUS_OS2_INVALID_LEVEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SMBFileAttributes GetFileAttributes(FileSystemEntry entry)
|
||||
{
|
||||
SMBFileAttributes attributes = SMBFileAttributes.Normal;
|
||||
if (entry.IsHidden)
|
||||
{
|
||||
attributes |= SMBFileAttributes.Hidden;
|
||||
}
|
||||
if (entry.IsReadonly)
|
||||
{
|
||||
attributes |= SMBFileAttributes.ReadOnly;
|
||||
}
|
||||
if (entry.IsArchived)
|
||||
{
|
||||
attributes |= SMBFileAttributes.Archive;
|
||||
}
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
attributes |= SMBFileAttributes.Directory;
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public static ExtendedFileAttributes GetExtendedFileAttributes(FileSystemEntry entry)
|
||||
{
|
||||
ExtendedFileAttributes attributes = 0;
|
||||
if (entry.IsHidden)
|
||||
{
|
||||
attributes |= ExtendedFileAttributes.Hidden;
|
||||
}
|
||||
if (entry.IsReadonly)
|
||||
{
|
||||
attributes |= ExtendedFileAttributes.Readonly;
|
||||
}
|
||||
if (entry.IsArchived)
|
||||
{
|
||||
attributes |= ExtendedFileAttributes.Archive;
|
||||
}
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
attributes |= ExtendedFileAttributes.Directory;
|
||||
}
|
||||
|
||||
if ((uint)attributes == 0)
|
||||
{
|
||||
attributes = ExtendedFileAttributes.Normal;
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using SMBLibrary.SMB1;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server.SMB1
|
||||
{
|
||||
public partial class SMB1FileSystemHelper
|
||||
{
|
||||
public static NTStatus GetFileSystemInformation(out QueryFSInformation result, QueryFSInformationLevel informationLevel, IFileSystem fileSystem)
|
||||
{
|
||||
switch (informationLevel)
|
||||
{
|
||||
case QueryFSInformationLevel.SMB_QUERY_FS_VOLUME_INFO:
|
||||
{
|
||||
QueryFSVolumeInfo information = new QueryFSVolumeInfo();
|
||||
information.VolumeCreationTime = DateTime.Now;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryFSInformationLevel.SMB_QUERY_FS_SIZE_INFO:
|
||||
{
|
||||
QueryFSSizeInfo information = new QueryFSSizeInfo();
|
||||
information.TotalAllocationUnits = fileSystem.Size / NTFileSystemHelper.ClusterSize;
|
||||
information.TotalFreeAllocationUnits = fileSystem.FreeSpace / NTFileSystemHelper.ClusterSize;
|
||||
information.BytesPerSector = NTFileSystemHelper.BytesPerSector;
|
||||
information.SectorsPerAllocationUnit = NTFileSystemHelper.ClusterSize / NTFileSystemHelper.BytesPerSector;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryFSInformationLevel.SMB_QUERY_FS_DEVICE_INFO:
|
||||
{
|
||||
QueryFSDeviceInfo information = new QueryFSDeviceInfo();
|
||||
information.DeviceCharacteristics = DeviceCharacteristics.IsMounted;
|
||||
information.DeviceType = DeviceType.Disk;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
case QueryFSInformationLevel.SMB_QUERY_FS_ATTRIBUTE_INFO:
|
||||
{
|
||||
QueryFSAttibuteInfo information = new QueryFSAttibuteInfo();
|
||||
information.FileSystemAttributes = FileSystemAttributes.UnicodeOnDisk;
|
||||
information.MaxFileNameLengthInBytes = 255;
|
||||
information.FileSystemName = fileSystem.Name;
|
||||
result = information;
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
default:
|
||||
{
|
||||
result = null;
|
||||
return NTStatus.STATUS_OS2_INVALID_LEVEL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
||||
*
|
||||
* You can redistribute this program and/or modify it under the terms of
|
||||
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||
* either version 3 of the License, or (at your option) any later version.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using SMBLibrary.SMB1;
|
||||
using Utilities;
|
||||
|
||||
namespace SMBLibrary.Server.SMB1
|
||||
{
|
||||
public partial class SMB1FileSystemHelper
|
||||
{
|
||||
public static NTStatus SetFileInformation(IFileSystem fileSystem, OpenFileObject openFile, SetInformation information, ConnectionState state)
|
||||
{
|
||||
if (information is SetFileBasicInfo)
|
||||
{
|
||||
SetFileBasicInfo basicInfo = (SetFileBasicInfo)information;
|
||||
bool isHidden = (basicInfo.ExtFileAttributes & ExtendedFileAttributes.Hidden) > 0;
|
||||
bool isReadonly = (basicInfo.ExtFileAttributes & ExtendedFileAttributes.Readonly) > 0;
|
||||
bool isArchived = (basicInfo.ExtFileAttributes & ExtendedFileAttributes.Archive) > 0;
|
||||
try
|
||||
{
|
||||
fileSystem.SetAttributes(openFile.Path, isHidden, isReadonly, isArchived);
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Failed to set file attributes on '{0}'. Access Denied.", openFile.Path);
|
||||
return NTStatus.STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fileSystem.SetDates(openFile.Path, basicInfo.CreationTime, basicInfo.LastWriteTime, basicInfo.LastAccessTime);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
|
||||
if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
// Returning STATUS_SHARING_VIOLATION is undocumented but apparently valid
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Failed to set file dates on '{0}'. Sharing Violation.", openFile.Path);
|
||||
return NTStatus.STATUS_SHARING_VIOLATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Failed to set file dates on '{0}'. Data Error.", openFile.Path);
|
||||
return NTStatus.STATUS_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Failed to set file dates on '{0}'. Access Denied.", openFile.Path);
|
||||
return NTStatus.STATUS_ACCESS_DENIED;
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
else if (information is SetFileDispositionInfo)
|
||||
{
|
||||
if (((SetFileDispositionInfo)information).DeletePending)
|
||||
{
|
||||
// We're supposed to delete the file on close, but it's too late to report errors at this late stage
|
||||
if (openFile.Stream != null)
|
||||
{
|
||||
openFile.Stream.Close();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
state.LogToServer(Severity.Information, "SetFileInformation: Deleting file '{0}'", openFile.Path);
|
||||
fileSystem.Delete(openFile.Path);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
|
||||
if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
state.LogToServer(Severity.Information, "SetFileInformation: Error deleting '{0}'. Sharing Violation.", openFile.Path);
|
||||
return NTStatus.STATUS_SHARING_VIOLATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.LogToServer(Severity.Information, "SetFileInformation: Error deleting '{0}'. Data Error.", openFile.Path);
|
||||
return NTStatus.STATUS_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Information, "SetFileInformation: Error deleting '{0}', Access Denied.", openFile.Path);
|
||||
return NTStatus.STATUS_ACCESS_DENIED;
|
||||
}
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
else if (information is SetFileAllocationInfo)
|
||||
{
|
||||
// This information level is used to set the file length in bytes.
|
||||
// Note: the input will NOT be a multiple of the cluster size / bytes per sector.
|
||||
long allocationSize = ((SetFileAllocationInfo)information).AllocationSize;
|
||||
try
|
||||
{
|
||||
openFile.Stream.SetLength(allocationSize);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
|
||||
if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set allocation for '{0}'. Sharing Violation.", openFile.Path);
|
||||
return NTStatus.STATUS_SHARING_VIOLATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set allocation for '{0}'. Data Error.", openFile.Path);
|
||||
return NTStatus.STATUS_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set allocation for '{0}'. Access Denied.", openFile.Path);
|
||||
return NTStatus.STATUS_ACCESS_DENIED;
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
else if (information is SetFileEndOfFileInfo)
|
||||
{
|
||||
long endOfFile = ((SetFileEndOfFileInfo)information).EndOfFile;
|
||||
try
|
||||
{
|
||||
openFile.Stream.SetLength(endOfFile);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
ushort errorCode = IOExceptionHelper.GetWin32ErrorCode(ex);
|
||||
if (errorCode == (ushort)Win32Error.ERROR_SHARING_VIOLATION)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set end of file for '{0}'. Sharing Violation.", openFile.Path);
|
||||
return NTStatus.STATUS_SHARING_VIOLATION;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set end of file for '{0}'. Data Error.", openFile.Path);
|
||||
return NTStatus.STATUS_DATA_ERROR;
|
||||
}
|
||||
}
|
||||
catch (UnauthorizedAccessException)
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "SetFileInformation: Cannot set end of file for '{0}'. Access Denied.", openFile.Path);
|
||||
return NTStatus.STATUS_ACCESS_DENIED;
|
||||
}
|
||||
return NTStatus.STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NTStatus.STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -26,20 +26,14 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
|
||||
state.LogToServer(Severity.Verbose, "Close: Closing file '{0}'", openFile.Path);
|
||||
session.RemoveOpenFile(request.FID);
|
||||
if (openFile.DeleteOnClose && share is FileSystemShare)
|
||||
header.Status = share.FileStore.CloseFile(openFile.Handle);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
try
|
||||
{
|
||||
((FileSystemShare)share).FileSystem.Delete(openFile.Path);
|
||||
}
|
||||
catch
|
||||
{
|
||||
state.LogToServer(Severity.Debug, "Close: Cannot delete '{0}'", openFile.Path);
|
||||
}
|
||||
return new ErrorResponse(request.CommandName);
|
||||
}
|
||||
CloseResponse response = new CloseResponse();
|
||||
return response;
|
||||
|
||||
session.RemoveOpenFile(request.FID);
|
||||
return new CloseResponse();
|
||||
}
|
||||
|
||||
internal static SMB1Command GetFindClose2Request(SMB1Header header, FindClose2Request request, SMB1ConnectionState state)
|
||||
|
|
|
@ -18,11 +18,21 @@ namespace SMBLibrary.Server.SMB1
|
|||
internal static Transaction2FindFirst2Response GetSubcommandResponse(SMB1Header header, Transaction2FindFirst2Request subcommand, FileSystemShare share, SMB1ConnectionState state)
|
||||
{
|
||||
SMB1Session session = state.GetSession(header.UID);
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
string fileNamePattern = subcommand.FileName;
|
||||
|
||||
List<FileSystemEntry> entries;
|
||||
NTStatus searchStatus = SMB1FileSystemHelper.FindEntries(out entries, fileSystem, fileNamePattern);
|
||||
List<QueryDirectoryFileInformation> entries;
|
||||
FileInformationClass informationClass;
|
||||
try
|
||||
{
|
||||
informationClass = GetFileInformationClass(subcommand.InformationLevel);
|
||||
}
|
||||
catch (UnsupportedInformationLevelException)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL;
|
||||
return null;
|
||||
}
|
||||
|
||||
NTStatus searchStatus = SMB1FileStoreHelper.QueryDirectory(out entries, share.FileStore, fileNamePattern, informationClass);
|
||||
if (searchStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
state.LogToServer(Severity.Verbose, "FindFirst2: Searched for '{0}', NTStatus: {1}", fileNamePattern, searchStatus.ToString());
|
||||
|
@ -41,18 +51,9 @@ namespace SMBLibrary.Server.SMB1
|
|||
|
||||
bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
|
||||
int entriesToReturn = Math.Min(subcommand.SearchCount, entries.Count);
|
||||
List<FileSystemEntry> segment = entries.GetRange(0, entriesToReturn);
|
||||
List<QueryDirectoryFileInformation> segment = entries.GetRange(0, entriesToReturn);
|
||||
int maxLength = (int)state.GetMaxDataCount(header.PID).Value;
|
||||
FindInformationList findInformationList;
|
||||
try
|
||||
{
|
||||
findInformationList = SMB1FileSystemHelper.GetFindInformationList(segment, subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys, maxLength);
|
||||
}
|
||||
catch (UnsupportedInformationLevelException)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL;
|
||||
return null;
|
||||
}
|
||||
FindInformationList findInformationList = SMB1FileStoreHelper.GetFindInformationList(segment, subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys, maxLength);
|
||||
int returnCount = findInformationList.Count;
|
||||
Transaction2FindFirst2Response response = new Transaction2FindFirst2Response();
|
||||
response.SetFindInformationList(findInformationList, header.UnicodeFlag);
|
||||
|
@ -91,11 +92,11 @@ namespace SMBLibrary.Server.SMB1
|
|||
bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
|
||||
int maxLength = (int)state.GetMaxDataCount(header.PID).Value;
|
||||
int maxCount = Math.Min(openSearch.Entries.Count - openSearch.EnumerationLocation, subcommand.SearchCount);
|
||||
List<FileSystemEntry> segment = openSearch.Entries.GetRange(openSearch.EnumerationLocation, maxCount);
|
||||
List<QueryDirectoryFileInformation> segment = openSearch.Entries.GetRange(openSearch.EnumerationLocation, maxCount);
|
||||
FindInformationList findInformationList;
|
||||
try
|
||||
{
|
||||
findInformationList = SMB1FileSystemHelper.GetFindInformationList(segment, subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys, maxLength);
|
||||
findInformationList = SMB1FileStoreHelper.GetFindInformationList(segment, subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys, maxLength);
|
||||
}
|
||||
catch (UnsupportedInformationLevelException)
|
||||
{
|
||||
|
@ -125,7 +126,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
|
||||
Transaction2QueryFSInformationResponse response = new Transaction2QueryFSInformationResponse();
|
||||
QueryFSInformation queryFSInformation;
|
||||
NTStatus queryStatus = SMB1FileSystemHelper.GetFileSystemInformation(out queryFSInformation, subcommand.InformationLevel, share.FileSystem);
|
||||
NTStatus queryStatus = SMB1FileStoreHelper.GetFileSystemInformation(out queryFSInformation, share.FileStore, subcommand.InformationLevel);
|
||||
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
state.LogToServer(Severity.Verbose, "GetFileSystemInformation failed. Information level: {0}, NTStatus: {1}", subcommand.InformationLevel, queryStatus);
|
||||
|
@ -145,20 +146,9 @@ namespace SMBLibrary.Server.SMB1
|
|||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||
return null;
|
||||
}
|
||||
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
FileSystemEntry entry = fileSystem.GetEntry(path);
|
||||
if (entry == null)
|
||||
{
|
||||
// Windows Server 2003 will return STATUS_OBJECT_NAME_NOT_FOUND
|
||||
// Returning STATUS_NO_SUCH_FILE caused an issue when executing ImageX.exe from WinPE 3.0 (32-bit)
|
||||
state.LogToServer(Severity.Debug, "Transaction2QueryPathInformation: File not found, Path: '{0}'", path);
|
||||
header.Status = NTStatus.STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
return null;
|
||||
}
|
||||
Transaction2QueryPathInformationResponse response = new Transaction2QueryPathInformationResponse();
|
||||
QueryInformation queryInformation;
|
||||
NTStatus queryStatus = SMB1FileSystemHelper.GetFileInformation(out queryInformation, entry, false, subcommand.InformationLevel);
|
||||
NTStatus queryStatus = SMB1FileStoreHelper.GetFileInformation(out queryInformation, share.FileStore, path, subcommand.InformationLevel);
|
||||
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}' failed. Information level: {1}, NTStatus: {2}", path, subcommand.InformationLevel, queryStatus);
|
||||
|
@ -172,7 +162,6 @@ namespace SMBLibrary.Server.SMB1
|
|||
internal static Transaction2QueryFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryFileInformationRequest subcommand, FileSystemShare share, SMB1ConnectionState state)
|
||||
{
|
||||
SMB1Session session = state.GetSession(header.UID);
|
||||
IFileSystem fileSystem = share.FileSystem;
|
||||
OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);
|
||||
if (openFile == null)
|
||||
{
|
||||
|
@ -186,15 +175,9 @@ namespace SMBLibrary.Server.SMB1
|
|||
return null;
|
||||
}
|
||||
|
||||
FileSystemEntry entry = fileSystem.GetEntry(openFile.Path);
|
||||
if (entry == null)
|
||||
{
|
||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
||||
return null;
|
||||
}
|
||||
Transaction2QueryFileInformationResponse response = new Transaction2QueryFileInformationResponse();
|
||||
QueryInformation queryInformation;
|
||||
NTStatus queryStatus = SMB1FileSystemHelper.GetFileInformation(out queryInformation, entry, openFile.DeleteOnClose, subcommand.InformationLevel);
|
||||
NTStatus queryStatus = SMB1FileStoreHelper.GetFileInformation(out queryInformation, share.FileStore, openFile.Handle, subcommand.InformationLevel);
|
||||
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}' failed. Information level: {1}, NTStatus: {2}", openFile.Path, subcommand.InformationLevel, queryStatus);
|
||||
|
@ -237,7 +220,7 @@ namespace SMBLibrary.Server.SMB1
|
|||
return null;
|
||||
}
|
||||
|
||||
NTStatus status = SMB1FileSystemHelper.SetFileInformation(share.FileSystem, openFile, information, state);
|
||||
NTStatus status = SMB1FileStoreHelper.SetFileInformation(share.FileStore, openFile.Handle, information);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}' failed. Information level: {1}, NTStatus: {2}", openFile.Path, information.InformationLevel, status);
|
||||
|
@ -247,5 +230,28 @@ namespace SMBLibrary.Server.SMB1
|
|||
Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse();
|
||||
return response;
|
||||
}
|
||||
|
||||
private static FileInformationClass GetFileInformationClass(FindInformationLevel informationLevel)
|
||||
{
|
||||
switch (informationLevel)
|
||||
{
|
||||
case FindInformationLevel.SMB_INFO_STANDARD:
|
||||
return FileInformationClass.FileDirectoryInformation;
|
||||
case FindInformationLevel.SMB_INFO_QUERY_EA_SIZE:
|
||||
return FileInformationClass.FileFullDirectoryInformation;
|
||||
case FindInformationLevel.SMB_INFO_QUERY_EAS_FROM_LIST:
|
||||
return FileInformationClass.FileDirectoryInformation;
|
||||
case FindInformationLevel.SMB_FIND_FILE_DIRECTORY_INFO:
|
||||
return FileInformationClass.FileDirectoryInformation;
|
||||
case FindInformationLevel.SMB_FIND_FILE_FULL_DIRECTORY_INFO:
|
||||
return FileInformationClass.FileFullDirectoryInformation;
|
||||
case FindInformationLevel.SMB_FIND_FILE_NAMES_INFO:
|
||||
return FileInformationClass.FileNamesInformation;
|
||||
case FindInformationLevel.SMB_FIND_FILE_BOTH_DIRECTORY_INFO:
|
||||
return FileInformationClass.FileBothDirectoryInformation;
|
||||
default:
|
||||
throw new UnsupportedInformationLevelException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,8 +27,18 @@ namespace SMBLibrary.Server.SMB1
|
|||
}
|
||||
|
||||
TransactionTransactNamedPipeResponse response = new TransactionTransactNamedPipeResponse();
|
||||
openFile.Stream.Write(subcommand.WriteData, 0, subcommand.WriteData.Length);
|
||||
response.ReadData = ByteReader.ReadAllBytes(openFile.Stream);
|
||||
int numberOfBytesWritten;
|
||||
header.Status = share.FileStore.WriteFile(out numberOfBytesWritten, openFile.Handle, 0, subcommand.WriteData);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
int maxCount = UInt16.MaxValue;
|
||||
header.Status = share.FileStore.ReadFile(out response.ReadData, openFile.Handle, 0, maxCount);
|
||||
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,29 +22,21 @@ namespace SMBLibrary.Server.SMB2
|
|||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED);
|
||||
}
|
||||
string path = openFile.Path;
|
||||
share.FileStore.CloseFile(openFile.Handle);
|
||||
session.RemoveOpenFile(request.FileId.Persistent);
|
||||
CloseResponse response = new CloseResponse();
|
||||
if (request.PostQueryAttributes)
|
||||
{
|
||||
if (share is NamedPipeShare)
|
||||
FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, openFile.Path);
|
||||
if (fileInfo != null)
|
||||
{
|
||||
response.FileAttributes = FileAttributes.Temporary;
|
||||
}
|
||||
else // FileSystemShare
|
||||
{
|
||||
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
||||
FileSystemEntry entry = fileSystem.GetEntry(path);
|
||||
if (entry != null)
|
||||
{
|
||||
response.CreationTime = entry.CreationTime;
|
||||
response.LastAccessTime = entry.LastAccessTime;
|
||||
response.LastWriteTime = entry.LastWriteTime;
|
||||
response.ChangeTime = entry.LastWriteTime;
|
||||
response.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
response.EndofFile = (long)entry.Size;
|
||||
response.FileAttributes = NTFileSystemHelper.GetFileAttributes(entry);
|
||||
}
|
||||
response.CreationTime = fileInfo.CreationTime;
|
||||
response.LastAccessTime = fileInfo.LastAccessTime;
|
||||
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||
response.ChangeTime = fileInfo.ChangeTime;
|
||||
response.AllocationSize = fileInfo.AllocationSize;
|
||||
response.EndofFile = fileInfo.EndOfFile;
|
||||
response.FileAttributes = fileInfo.FileAttributes;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
|
|
|
@ -32,48 +32,29 @@ namespace SMBLibrary.Server.SMB2
|
|||
}
|
||||
}
|
||||
|
||||
object handle;
|
||||
FileStatus fileStatus;
|
||||
NTStatus createStatus = share.FileStore.CreateFile(out handle, out fileStatus, path, request.DesiredAccess, request.ShareAccess, request.CreateDisposition, request.CreateOptions);
|
||||
if (createStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, createStatus);
|
||||
}
|
||||
|
||||
ulong? persistentFileID = session.AddOpenFile(path, handle);
|
||||
if (!persistentFileID.HasValue)
|
||||
{
|
||||
share.FileStore.CloseFile(handle);
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_TOO_MANY_OPENED_FILES);
|
||||
}
|
||||
|
||||
if (share is NamedPipeShare)
|
||||
{
|
||||
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
|
||||
if (pipeStream != null)
|
||||
{
|
||||
ulong? persistentFileID = session.AddOpenFile(path, pipeStream);
|
||||
if (!persistentFileID.HasValue)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_TOO_MANY_OPENED_FILES);
|
||||
}
|
||||
return CreateResponseForNamedPipe(persistentFileID.Value, FileStatus.FILE_OPENED);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_OBJECT_PATH_NOT_FOUND);
|
||||
}
|
||||
return CreateResponseForNamedPipe(persistentFileID.Value, FileStatus.FILE_OPENED);
|
||||
}
|
||||
else
|
||||
{
|
||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
||||
|
||||
FileSystemEntry entry;
|
||||
Stream stream;
|
||||
FileStatus fileStatus;
|
||||
NTStatus createStatus = NTFileSystemHelper.CreateFile(out entry, out stream, out fileStatus, fileSystemShare.FileSystem, path, request.DesiredAccess, request.ShareAccess, request.CreateDisposition, request.CreateOptions, state);
|
||||
if (createStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, createStatus);
|
||||
}
|
||||
|
||||
bool deleteOnClose = (stream != null) && ((request.CreateOptions & CreateOptions.FILE_DELETE_ON_CLOSE) > 0);
|
||||
ulong? persistentFileID = session.AddOpenFile(path, stream, deleteOnClose);
|
||||
if (!persistentFileID.HasValue)
|
||||
{
|
||||
if (stream != null)
|
||||
{
|
||||
stream.Close();
|
||||
}
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_TOO_MANY_OPENED_FILES);
|
||||
}
|
||||
|
||||
CreateResponse response = CreateResponseFromFileSystemEntry(entry, persistentFileID.Value, fileStatus);
|
||||
FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
|
||||
CreateResponse response = CreateResponseFromFileSystemEntry(fileInfo, persistentFileID.Value, fileStatus);
|
||||
if (request.RequestedOplockLevel == OplockLevel.Batch)
|
||||
{
|
||||
response.OplockLevel = OplockLevel.Batch;
|
||||
|
@ -91,24 +72,17 @@ namespace SMBLibrary.Server.SMB2
|
|||
return response;
|
||||
}
|
||||
|
||||
private static CreateResponse CreateResponseFromFileSystemEntry(FileSystemEntry entry, ulong persistentFileID, FileStatus fileStatus)
|
||||
private static CreateResponse CreateResponseFromFileSystemEntry(FileNetworkOpenInformation fileInfo, ulong persistentFileID, FileStatus fileStatus)
|
||||
{
|
||||
CreateResponse response = new CreateResponse();
|
||||
if (entry.IsDirectory)
|
||||
{
|
||||
response.FileAttributes = FileAttributes.Directory;
|
||||
}
|
||||
else
|
||||
{
|
||||
response.FileAttributes = FileAttributes.Normal;
|
||||
}
|
||||
response.CreateAction = (CreateAction)fileStatus;
|
||||
response.CreationTime = entry.CreationTime;
|
||||
response.LastWriteTime = entry.LastWriteTime;
|
||||
response.ChangeTime = entry.LastWriteTime;
|
||||
response.LastAccessTime = entry.LastAccessTime;
|
||||
response.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
response.EndofFile = (long)entry.Size;
|
||||
response.CreationTime = fileInfo.CreationTime;
|
||||
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||
response.ChangeTime = fileInfo.LastWriteTime;
|
||||
response.LastAccessTime = fileInfo.LastAccessTime;
|
||||
response.AllocationSize = fileInfo.AllocationSize;
|
||||
response.EndofFile = fileInfo.EndOfFile;
|
||||
response.FileAttributes = fileInfo.FileAttributes;
|
||||
response.FileId.Persistent = persistentFileID;
|
||||
return response;
|
||||
}
|
||||
|
|
|
@ -39,8 +39,18 @@ namespace SMBLibrary.Server.SMB2
|
|||
{
|
||||
IOCtlResponse response = new IOCtlResponse();
|
||||
response.CtlCode = request.CtlCode;
|
||||
openFile.Stream.Write(request.Input, 0, request.Input.Length);
|
||||
response.Output = ByteReader.ReadAllBytes(openFile.Stream);
|
||||
int numberOfBytesWritten;
|
||||
NTStatus writeStatus = share.FileStore.WriteFile(out numberOfBytesWritten, openFile.Handle, 0, request.Input);
|
||||
if (writeStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, writeStatus);
|
||||
}
|
||||
int maxCount = (int)request.MaxOutputResponse;
|
||||
NTStatus readStatus = share.FileStore.ReadFile(out response.Output, openFile.Handle, 0, maxCount);
|
||||
if (readStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, readStatus);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,19 +34,6 @@ namespace SMBLibrary.Server.SMB2
|
|||
}
|
||||
|
||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
||||
IFileSystem fileSystem = fileSystemShare.FileSystem;
|
||||
|
||||
if (!fileSystem.GetEntry(openFile.Path).IsDirectory)
|
||||
{
|
||||
if ((request.Flags & QueryDirectoryFlags.SMB2_REOPEN) > 0)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
}
|
||||
|
||||
ulong fileID = request.FileId.Persistent;
|
||||
OpenSearch openSearch = session.GetOpenSearch(fileID);
|
||||
|
@ -56,8 +43,8 @@ namespace SMBLibrary.Server.SMB2
|
|||
{
|
||||
session.RemoveOpenSearch(fileID);
|
||||
}
|
||||
List<FileSystemEntry> entries;
|
||||
NTStatus searchStatus = NTFileSystemHelper.FindEntries(out entries, fileSystemShare.FileSystem, openFile.Path, request.FileName);
|
||||
List<QueryDirectoryFileInformation> entries;
|
||||
NTStatus searchStatus = share.FileStore.QueryDirectory(out entries, openFile.Handle, request.FileName, request.FileInformationClass);
|
||||
if (searchStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
state.LogToServer(Severity.Verbose, "Query Directory: Path: '{0}', Searched for '{1}', NTStatus: {2}", openFile.Path, request.FileName, searchStatus.ToString());
|
||||
|
@ -88,14 +75,11 @@ namespace SMBLibrary.Server.SMB2
|
|||
int pageLength = 0;
|
||||
for (int index = openSearch.EnumerationLocation; index < openSearch.Entries.Count; index++)
|
||||
{
|
||||
QueryDirectoryFileInformation fileInformation;
|
||||
try
|
||||
QueryDirectoryFileInformation fileInformation = openSearch.Entries[index];
|
||||
if (fileInformation.FileInformationClass != request.FileInformationClass)
|
||||
{
|
||||
fileInformation = FromFileSystemEntry(openSearch.Entries[index], request.FileInformationClass);
|
||||
}
|
||||
catch (UnsupportedInformationLevelException)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_INFO_CLASS);
|
||||
// We do not support changing FileInformationClass during a search (unless SMB2_REOPEN is set).
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
if (pageLength + fileInformation.Length <= request.OutputBufferLength)
|
||||
|
@ -119,95 +103,5 @@ namespace SMBLibrary.Server.SMB2
|
|||
response.SetFileInformationList(page);
|
||||
return response;
|
||||
}
|
||||
|
||||
internal static QueryDirectoryFileInformation FromFileSystemEntry(FileSystemEntry entry, FileInformationClass informationClass)
|
||||
{
|
||||
switch (informationClass)
|
||||
{
|
||||
case FileInformationClass.FileBothDirectoryInformation:
|
||||
{
|
||||
FileBothDirectoryInformation result = new FileBothDirectoryInformation();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.ChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
result.FileAttributes = NTFileSystemHelper.GetFileAttributes(entry);
|
||||
result.EaSize = 0;
|
||||
result.ShortName = NTFileSystemHelper.GetShortName(entry.Name);
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FileInformationClass.FileDirectoryInformation:
|
||||
{
|
||||
FileDirectoryInformation result = new FileDirectoryInformation();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.ChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
result.FileAttributes = NTFileSystemHelper.GetFileAttributes(entry);
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FileInformationClass.FileFullDirectoryInformation:
|
||||
{
|
||||
FileFullDirectoryInformation result = new FileFullDirectoryInformation();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.ChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
result.FileAttributes = NTFileSystemHelper.GetFileAttributes(entry);
|
||||
result.EaSize = 0;
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FileInformationClass.FileIdBothDirectoryInformation:
|
||||
{
|
||||
FileIdBothDirectoryInformation result = new FileIdBothDirectoryInformation();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.ChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
result.FileAttributes = NTFileSystemHelper.GetFileAttributes(entry);
|
||||
result.EaSize = 0;
|
||||
result.ShortName = NTFileSystemHelper.GetShortName(entry.Name);
|
||||
result.FileId = 0;
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FileInformationClass.FileIdFullDirectoryInformation:
|
||||
{
|
||||
FileIdFullDirectoryInformation result = new FileIdFullDirectoryInformation();
|
||||
result.CreationTime = entry.CreationTime;
|
||||
result.LastAccessTime = entry.LastAccessTime;
|
||||
result.LastWriteTime = entry.LastWriteTime;
|
||||
result.ChangeTime = entry.LastWriteTime;
|
||||
result.EndOfFile = (long)entry.Size;
|
||||
result.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
||||
result.FileAttributes = NTFileSystemHelper.GetFileAttributes(entry);
|
||||
result.EaSize = 0;
|
||||
result.FileId = 0;
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
case FileInformationClass.FileNamesInformation:
|
||||
{
|
||||
FileNamesInformation result = new FileNamesInformation();
|
||||
result.FileName = entry.Name;
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new UnsupportedInformationLevelException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,27 +25,16 @@ namespace SMBLibrary.Server.SMB2
|
|||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED);
|
||||
}
|
||||
|
||||
FileInformation fileInformation;
|
||||
NTStatus queryStatus;
|
||||
if (share is NamedPipeShare)
|
||||
{
|
||||
queryStatus = NTFileSystemHelper.GetNamedPipeInformation(out fileInformation, request.FileInformationClass);
|
||||
}
|
||||
else // FileSystemShare
|
||||
if (share is FileSystemShare)
|
||||
{
|
||||
if (!((FileSystemShare)share).HasReadAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||
}
|
||||
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
||||
FileSystemEntry entry = fileSystem.GetEntry(openFile.Path);
|
||||
if (entry == null)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_NO_SUCH_FILE);
|
||||
}
|
||||
queryStatus = NTFileSystemHelper.GetFileInformation(out fileInformation, entry, openFile.DeleteOnClose, request.FileInformationClass);
|
||||
}
|
||||
|
||||
FileInformation fileInformation;
|
||||
NTStatus queryStatus = share.FileStore.GetFileInformation(out fileInformation, openFile.Handle, request.FileInformationClass);
|
||||
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}' failed. Information class: {1}, NTStatus: {2}", openFile.Path, request.FileInformationClass, queryStatus);
|
||||
|
@ -64,9 +53,9 @@ namespace SMBLibrary.Server.SMB2
|
|||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||
}
|
||||
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
||||
|
||||
FileSystemInformation fileSystemInformation;
|
||||
NTStatus queryStatus = NTFileSystemHelper.GetFileSystemInformation(out fileSystemInformation, request.FileSystemInformationClass, fileSystem);
|
||||
NTStatus queryStatus = share.FileStore.GetFileSystemInformation(out fileSystemInformation, request.FileSystemInformationClass);
|
||||
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
state.LogToServer(Severity.Verbose, "GetFileSystemInformation failed. Information class: {0}, NTStatus: {1}", request.FileSystemInformationClass, queryStatus);
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace SMBLibrary.Server.SMB2
|
|||
}
|
||||
|
||||
byte[] data;
|
||||
NTStatus readStatus = NTFileSystemHelper.ReadFile(out data, openFile, (long)request.Offset, (int)request.ReadLength, state);
|
||||
NTStatus readStatus = share.FileStore.ReadFile(out data, openFile.Handle, (long)request.Offset, (int)request.ReadLength);
|
||||
if (readStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, readStatus);
|
||||
|
@ -44,7 +44,7 @@ namespace SMBLibrary.Server.SMB2
|
|||
}
|
||||
|
||||
int numberOfBytesWritten;
|
||||
NTStatus writeStatus = NTFileSystemHelper.WriteFile(out numberOfBytesWritten, openFile, (long)request.Offset, request.Data, state);
|
||||
NTStatus writeStatus = share.FileStore.WriteFile(out numberOfBytesWritten, openFile.Handle, (long)request.Offset, request.Data);
|
||||
if (writeStatus != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, writeStatus);
|
||||
|
|
|
@ -27,47 +27,37 @@ namespace SMBLibrary.Server.SMB2
|
|||
|
||||
if (share is FileSystemShare)
|
||||
{
|
||||
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
||||
if (!((FileSystemShare)share).HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||
}
|
||||
|
||||
FileInformation information;
|
||||
try
|
||||
{
|
||||
information = FileInformation.GetFileInformation(request.Buffer, 0, request.FileInformationClass);
|
||||
}
|
||||
catch (UnsupportedInformationLevelException)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_INFO_CLASS);
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
if (information is FileRenameInformationType2)
|
||||
{
|
||||
string newFileName = ((FileRenameInformationType2)information).FileName;
|
||||
if (!((FileSystemShare)share).HasWriteAccess(session.UserName, newFileName, state.ClientEndPoint))
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||
}
|
||||
}
|
||||
|
||||
NTStatus status = NTFileSystemHelper.SetFileInformation(fileSystem, openFile, information, state);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}' failed. Information class: {1}, NTStatus: {2}", openFile.Path, information.FileInformationClass, status);
|
||||
return new ErrorResponse(request.CommandName, status);
|
||||
}
|
||||
return new SetInfoResponse();
|
||||
}
|
||||
|
||||
FileInformation information;
|
||||
try
|
||||
{
|
||||
information = FileInformation.GetFileInformation(request.Buffer, 0, request.FileInformationClass);
|
||||
}
|
||||
catch (UnsupportedInformationLevelException)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_INFO_CLASS);
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
NTStatus status = share.FileStore.SetFileInformation(openFile.Handle, information);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}' failed. Information class: {1}, NTStatus: {2}", openFile.Path, information.FileInformationClass, status);
|
||||
return new ErrorResponse(request.CommandName, status);
|
||||
}
|
||||
return new SetInfoResponse();
|
||||
}
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED);
|
||||
}
|
||||
|
|
|
@ -199,7 +199,7 @@ namespace SMBLibrary.Server
|
|||
return new ErrorResponse(command.CommandName);
|
||||
}
|
||||
QueryInformationRequest request = (QueryInformationRequest)command;
|
||||
return FileSystemResponseHelper.GetQueryInformationResponse(header, request, (FileSystemShare)share);
|
||||
return FileSystemResponseHelper.GetQueryInformationResponse(header, request, (FileSystemShare)share, state);
|
||||
}
|
||||
else if (command is SetInformationRequest)
|
||||
{
|
||||
|
@ -229,7 +229,7 @@ namespace SMBLibrary.Server
|
|||
return new ErrorResponse(command.CommandName);
|
||||
}
|
||||
CheckDirectoryRequest request = (CheckDirectoryRequest)command;
|
||||
return FileSystemResponseHelper.GetCheckDirectoryResponse(header, request, (FileSystemShare)share);
|
||||
return FileSystemResponseHelper.GetCheckDirectoryResponse(header, request, (FileSystemShare)share, state);
|
||||
}
|
||||
else if (command is WriteRawRequest)
|
||||
{
|
||||
|
|
|
@ -177,7 +177,11 @@ namespace SMBLibrary.Server
|
|||
{
|
||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED);
|
||||
}
|
||||
openFile.Stream.Flush();
|
||||
NTStatus status = share.FileStore.FlushFileBuffers(openFile.Handle);
|
||||
if (status != NTStatus.STATUS_SUCCESS)
|
||||
{
|
||||
return new ErrorResponse(request.CommandName, status);
|
||||
}
|
||||
return new FlushResponse();
|
||||
}
|
||||
else if (command is CloseRequest)
|
||||
|
|
|
@ -33,14 +33,20 @@ namespace SMBLibrary.Server
|
|||
public class FileSystemShare : ISMBShare
|
||||
{
|
||||
private string m_name;
|
||||
public IFileSystem m_fileSystem;
|
||||
private INTFileStore m_fileSystem;
|
||||
|
||||
public event EventHandler<AccessRequestArgs> OnAccessRequest;
|
||||
|
||||
public FileSystemShare(string shareName, INTFileStore fileSystem)
|
||||
{
|
||||
m_name = shareName;
|
||||
m_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
public FileSystemShare(string shareName, IFileSystem fileSystem)
|
||||
{
|
||||
m_name = shareName;
|
||||
m_fileSystem = fileSystem;
|
||||
m_fileSystem = new NTFileSystemAdapter(fileSystem);
|
||||
}
|
||||
|
||||
public bool HasReadAccess(string userName, string path, IPEndPoint clientEndPoint)
|
||||
|
@ -74,7 +80,7 @@ namespace SMBLibrary.Server
|
|||
}
|
||||
}
|
||||
|
||||
public IFileSystem FileSystem
|
||||
public INTFileStore FileStore
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -14,5 +14,10 @@ namespace SMBLibrary.Server
|
|||
{
|
||||
get;
|
||||
}
|
||||
|
||||
INTFileStore FileStore
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,45 +12,19 @@ using SMBLibrary.Services;
|
|||
|
||||
namespace SMBLibrary.Server
|
||||
{
|
||||
public class NamedPipeShare : List<RemoteService>, ISMBShare
|
||||
public class NamedPipeShare : ISMBShare
|
||||
{
|
||||
// A pipe share, as defined by the SMB Protocol, MUST always have the name "IPC$".
|
||||
public const string NamedPipeShareName = "IPC$";
|
||||
|
||||
private NamedPipeStore m_store;
|
||||
|
||||
public NamedPipeShare(List<string> shareList)
|
||||
{
|
||||
this.Add(new ServerService(Environment.MachineName, shareList));
|
||||
this.Add(new WorkstationService(Environment.MachineName, Environment.MachineName));
|
||||
}
|
||||
|
||||
public Stream OpenPipe(string path)
|
||||
{
|
||||
// It is possible to have a named pipe that does not use RPC (e.g. MS-WSP),
|
||||
// However this is not currently needed by our implementation.
|
||||
RemoteService service = GetService(path);
|
||||
if (service != null)
|
||||
{
|
||||
// All instances of a named pipe share the same pipe name, but each instance has its own buffers and handles,
|
||||
// and provides a separate conduit for client/server communication.
|
||||
return new RPCPipeStream(service);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private RemoteService GetService(string path)
|
||||
{
|
||||
if (path.StartsWith(@"\"))
|
||||
{
|
||||
path = path.Substring(1);
|
||||
}
|
||||
foreach (RemoteService service in this)
|
||||
{
|
||||
if (String.Equals(path, service.PipeName, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
return service;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
List<RemoteService> services = new List<RemoteService>();
|
||||
services.Add(new ServerService(Environment.MachineName, shareList));
|
||||
services.Add(new WorkstationService(Environment.MachineName, Environment.MachineName));
|
||||
m_store = new NamedPipeStore(services);
|
||||
}
|
||||
|
||||
public string Name
|
||||
|
@ -60,5 +34,13 @@ namespace SMBLibrary.Server
|
|||
return NamedPipeShareName;
|
||||
}
|
||||
}
|
||||
|
||||
public INTFileStore FileStore
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_store;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue