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 System.IO;
|
||||||
using Utilities;
|
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:
|
entry = m_fileSystem.GetEntry(path);
|
||||||
{
|
}
|
||||||
FileBasicInformation information = new FileBasicInformation();
|
catch (Exception ex)
|
||||||
information.FileAttributes = FileAttributes.Temporary;
|
{
|
||||||
result = information;
|
NTStatus status = ToNTStatus(ex);
|
||||||
return NTStatus.STATUS_SUCCESS;
|
Log(Severity.Debug, "GetFileInformation on '{0}' failed. {1}", path, status);
|
||||||
}
|
result = null;
|
||||||
case FileInformationClass.FileStandardInformation:
|
return status;
|
||||||
{
|
}
|
||||||
FileStandardInformation information = new FileStandardInformation();
|
|
||||||
information.DeletePending = true;
|
if (entry == null)
|
||||||
result = information;
|
{
|
||||||
return NTStatus.STATUS_SUCCESS;
|
result = null;
|
||||||
}
|
return NTStatus.STATUS_NO_SUCH_FILE;
|
||||||
default:
|
|
||||||
result = null;
|
|
||||||
return NTStatus.STATUS_INVALID_INFO_CLASS;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public static NTStatus GetFileInformation(out FileInformation result, FileSystemEntry entry, bool deletePending, FileInformationClass informationClass)
|
|
||||||
{
|
|
||||||
switch (informationClass)
|
switch (informationClass)
|
||||||
{
|
{
|
||||||
case FileInformationClass.FileBasicInformation:
|
case FileInformationClass.FileBasicInformation:
|
||||||
|
@ -55,10 +52,10 @@ namespace SMBLibrary.Server
|
||||||
case FileInformationClass.FileStandardInformation:
|
case FileInformationClass.FileStandardInformation:
|
||||||
{
|
{
|
||||||
FileStandardInformation information = new FileStandardInformation();
|
FileStandardInformation information = new FileStandardInformation();
|
||||||
information.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
information.AllocationSize = (long)GetAllocationSize(entry.Size);
|
||||||
information.EndOfFile = (long)entry.Size;
|
information.EndOfFile = (long)entry.Size;
|
||||||
information.Directory = entry.IsDirectory;
|
information.Directory = entry.IsDirectory;
|
||||||
information.DeletePending = deletePending;
|
information.DeletePending = fileHandle.DeleteOnClose;
|
||||||
result = information;
|
result = information;
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +115,7 @@ namespace SMBLibrary.Server
|
||||||
information.StandardInformation.AllocationSize = (long)GetAllocationSize(entry.Size);
|
information.StandardInformation.AllocationSize = (long)GetAllocationSize(entry.Size);
|
||||||
information.StandardInformation.EndOfFile = (long)entry.Size;
|
information.StandardInformation.EndOfFile = (long)entry.Size;
|
||||||
information.StandardInformation.Directory = entry.IsDirectory;
|
information.StandardInformation.Directory = entry.IsDirectory;
|
||||||
information.StandardInformation.DeletePending = deletePending;
|
information.StandardInformation.DeletePending = fileHandle.DeleteOnClose;
|
||||||
information.NameInformation.FileName = entry.Name;
|
information.NameInformation.FileName = entry.Name;
|
||||||
result = information;
|
result = information;
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
|
@ -134,7 +131,7 @@ namespace SMBLibrary.Server
|
||||||
// A buffer of FileStreamInformation data elements is returned by the server.
|
// A buffer of FileStreamInformation data elements is returned by the server.
|
||||||
FileStreamInformation information = new FileStreamInformation();
|
FileStreamInformation information = new FileStreamInformation();
|
||||||
information.StreamSize = (long)entry.Size;
|
information.StreamSize = (long)entry.Size;
|
||||||
information.StreamAllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
information.StreamAllocationSize = (long)GetAllocationSize(entry.Size);
|
||||||
information.StreamName = "::$DATA";
|
information.StreamName = "::$DATA";
|
||||||
result = information;
|
result = information;
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
|
@ -166,7 +163,7 @@ namespace SMBLibrary.Server
|
||||||
information.LastAccessTime = entry.LastAccessTime;
|
information.LastAccessTime = entry.LastAccessTime;
|
||||||
information.LastWriteTime = entry.LastWriteTime;
|
information.LastWriteTime = entry.LastWriteTime;
|
||||||
information.ChangeTime = 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.EndOfFile = (long)entry.Size;
|
||||||
information.FileAttributes = GetFileAttributes(entry);
|
information.FileAttributes = GetFileAttributes(entry);
|
||||||
result = information;
|
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 System.IO;
|
||||||
using Utilities;
|
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)
|
switch (informationClass)
|
||||||
{
|
{
|
||||||
|
@ -27,10 +27,10 @@ namespace SMBLibrary.Server
|
||||||
case FileSystemInformationClass.FileFsSizeInformation:
|
case FileSystemInformationClass.FileFsSizeInformation:
|
||||||
{
|
{
|
||||||
FileFsSizeInformation information = new FileFsSizeInformation();
|
FileFsSizeInformation information = new FileFsSizeInformation();
|
||||||
information.TotalAllocationUnits = fileSystem.Size / NTFileSystemHelper.ClusterSize;
|
information.TotalAllocationUnits = m_fileSystem.Size / ClusterSize;
|
||||||
information.AvailableAllocationUnits = fileSystem.FreeSpace / NTFileSystemHelper.ClusterSize;
|
information.AvailableAllocationUnits = m_fileSystem.FreeSpace / ClusterSize;
|
||||||
information.SectorsPerAllocationUnit = NTFileSystemHelper.ClusterSize / NTFileSystemHelper.BytesPerSector;
|
information.SectorsPerAllocationUnit = ClusterSize / BytesPerSector;
|
||||||
information.BytesPerSector = NTFileSystemHelper.BytesPerSector;
|
information.BytesPerSector = BytesPerSector;
|
||||||
result = information;
|
result = information;
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -47,7 +47,7 @@ namespace SMBLibrary.Server
|
||||||
FileFsAttributeInformation information = new FileFsAttributeInformation();
|
FileFsAttributeInformation information = new FileFsAttributeInformation();
|
||||||
information.FileSystemAttributes = FileSystemAttributes.UnicodeOnDisk;
|
information.FileSystemAttributes = FileSystemAttributes.UnicodeOnDisk;
|
||||||
information.MaximumComponentNameLength = 255;
|
information.MaximumComponentNameLength = 255;
|
||||||
information.FileSystemName = fileSystem.Name;
|
information.FileSystemName = m_fileSystem.Name;
|
||||||
result = information;
|
result = information;
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -63,11 +63,11 @@ namespace SMBLibrary.Server
|
||||||
case FileSystemInformationClass.FileFsFullSizeInformation:
|
case FileSystemInformationClass.FileFsFullSizeInformation:
|
||||||
{
|
{
|
||||||
FileFsFullSizeInformation information = new FileFsFullSizeInformation();
|
FileFsFullSizeInformation information = new FileFsFullSizeInformation();
|
||||||
information.TotalAllocationUnits = fileSystem.Size / NTFileSystemHelper.ClusterSize;
|
information.TotalAllocationUnits = m_fileSystem.Size / ClusterSize;
|
||||||
information.CallerAvailableAllocationUnits = fileSystem.FreeSpace / NTFileSystemHelper.ClusterSize;
|
information.CallerAvailableAllocationUnits = m_fileSystem.FreeSpace / ClusterSize;
|
||||||
information.ActualAvailableAllocationUnits = fileSystem.FreeSpace / NTFileSystemHelper.ClusterSize;
|
information.ActualAvailableAllocationUnits = m_fileSystem.FreeSpace / ClusterSize;
|
||||||
information.SectorsPerAllocationUnit = NTFileSystemHelper.ClusterSize / NTFileSystemHelper.BytesPerSector;
|
information.SectorsPerAllocationUnit = ClusterSize / BytesPerSector;
|
||||||
information.BytesPerSector = NTFileSystemHelper.BytesPerSector;
|
information.BytesPerSector = BytesPerSector;
|
||||||
result = information;
|
result = information;
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -81,10 +81,10 @@ namespace SMBLibrary.Server
|
||||||
case FileSystemInformationClass.FileFsSectorSizeInformation:
|
case FileSystemInformationClass.FileFsSectorSizeInformation:
|
||||||
{
|
{
|
||||||
FileFsSectorSizeInformation information = new FileFsSectorSizeInformation();
|
FileFsSectorSizeInformation information = new FileFsSectorSizeInformation();
|
||||||
information.LogicalBytesPerSector = NTFileSystemHelper.BytesPerSector;
|
information.LogicalBytesPerSector = BytesPerSector;
|
||||||
information.PhysicalBytesPerSectorForAtomicity = NTFileSystemHelper.BytesPerSector;
|
information.PhysicalBytesPerSectorForAtomicity = BytesPerSector;
|
||||||
information.PhysicalBytesPerSectorForPerformance = NTFileSystemHelper.BytesPerSector;
|
information.PhysicalBytesPerSectorForPerformance = BytesPerSector;
|
||||||
information.FileSystemEffectivePhysicalBytesPerSectorForAtomicity = NTFileSystemHelper.BytesPerSector;
|
information.FileSystemEffectivePhysicalBytesPerSectorForAtomicity = BytesPerSector;
|
||||||
information.ByteOffsetForSectorAlignment = 0;
|
information.ByteOffsetForSectorAlignment = 0;
|
||||||
information.ByteOffsetForPartitionAlignment = 0;
|
information.ByteOffsetForPartitionAlignment = 0;
|
||||||
result = information;
|
result = information;
|
|
@ -9,12 +9,13 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Utilities;
|
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)
|
if (information is FileBasicInformation)
|
||||||
{
|
{
|
||||||
FileBasicInformation basicInformation = (FileBasicInformation)information;
|
FileBasicInformation basicInformation = (FileBasicInformation)information;
|
||||||
|
@ -23,23 +24,23 @@ namespace SMBLibrary.Server
|
||||||
bool isArchived = (basicInformation.FileAttributes & FileAttributes.Archive) > 0;
|
bool isArchived = (basicInformation.FileAttributes & FileAttributes.Archive) > 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
fileSystem.SetAttributes(openFile.Path, isHidden, isReadonly, isArchived);
|
m_fileSystem.SetAttributes(fileHandle.Path, isHidden, isReadonly, isArchived);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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 status;
|
||||||
}
|
}
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
|
@ -53,27 +54,27 @@ namespace SMBLibrary.Server
|
||||||
destination = @"\" + destination;
|
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.
|
// Note: it's possible that we just want to upcase / downcase a filename letter.
|
||||||
try
|
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)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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;
|
return status;
|
||||||
}
|
}
|
||||||
openFile.Path = destination;
|
fileHandle.Path = destination;
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
else if (information is FileDispositionInformation)
|
else if (information is FileDispositionInformation)
|
||||||
|
@ -81,20 +82,20 @@ namespace SMBLibrary.Server
|
||||||
if (((FileDispositionInformation)information).DeletePending)
|
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
|
// 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
|
try
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Information, "SetFileInformation: Deleting file '{0}'", openFile.Path);
|
Log(Severity.Information, "SetFileInformation: Deleting file '{0}'", fileHandle.Path);
|
||||||
fileSystem.Delete(openFile.Path);
|
m_fileSystem.Delete(fileHandle.Path);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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;
|
return status;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,12 +106,12 @@ namespace SMBLibrary.Server
|
||||||
long allocationSize = ((FileAllocationInformation)information).AllocationSize;
|
long allocationSize = ((FileAllocationInformation)information).AllocationSize;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
openFile.Stream.SetLength(allocationSize);
|
fileHandle.Stream.SetLength(allocationSize);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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 status;
|
||||||
}
|
}
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
||||||
|
@ -120,12 +121,12 @@ namespace SMBLibrary.Server
|
||||||
long endOfFile = ((FileEndOfFileInformation)information).EndOfFile;
|
long endOfFile = ((FileEndOfFileInformation)information).EndOfFile;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
openFile.Stream.SetLength(endOfFile);
|
fileHandle.Stream.SetLength(endOfFile);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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 status;
|
||||||
}
|
}
|
||||||
return NTStatus.STATUS_SUCCESS;
|
return NTStatus.STATUS_SUCCESS;
|
|
@ -7,23 +7,28 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using SMBLibrary.Services;
|
|
||||||
using Utilities;
|
using Utilities;
|
||||||
|
|
||||||
namespace SMBLibrary.Server
|
namespace SMBLibrary
|
||||||
{
|
{
|
||||||
/// <summary>
|
public partial class NTFileSystemAdapter : INTFileStore
|
||||||
/// Helper class to access the FileSystemShare / NamedPipeShare in an NT-like manner dictated by the SMB protocol
|
|
||||||
/// </summary>
|
|
||||||
public partial class NTFileSystemHelper
|
|
||||||
{
|
{
|
||||||
public const int BytesPerSector = 512;
|
private const int BytesPerSector = 512;
|
||||||
public const int ClusterSize = 4096;
|
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;
|
fileStatus = FileStatus.FILE_DOES_NOT_EXIST;
|
||||||
stream = null;
|
|
||||||
FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(desiredAccess, createDisposition);
|
FileAccess createAccess = NTFileStoreHelper.ToCreateFileAccess(desiredAccess, createDisposition);
|
||||||
bool requestedWriteAccess = (createAccess & FileAccess.Write) > 0;
|
bool requestedWriteAccess = (createAccess & FileAccess.Write) > 0;
|
||||||
|
|
||||||
|
@ -35,7 +40,6 @@ namespace SMBLibrary.Server
|
||||||
createDisposition != CreateDisposition.FILE_OPEN_IF &&
|
createDisposition != CreateDisposition.FILE_OPEN_IF &&
|
||||||
createDisposition != CreateDisposition.FILE_SUPERSEDE))
|
createDisposition != CreateDisposition.FILE_SUPERSEDE))
|
||||||
{
|
{
|
||||||
entry = null;
|
|
||||||
return NTStatus.STATUS_INVALID_PARAMETER;
|
return NTStatus.STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,19 +47,18 @@ namespace SMBLibrary.Server
|
||||||
if (path.Contains(":"))
|
if (path.Contains(":"))
|
||||||
{
|
{
|
||||||
// Windows Server 2003 will return STATUS_OBJECT_NAME_NOT_FOUND
|
// Windows Server 2003 will return STATUS_OBJECT_NAME_NOT_FOUND
|
||||||
entry = null;
|
|
||||||
return NTStatus.STATUS_NO_SUCH_FILE;
|
return NTStatus.STATUS_NO_SUCH_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileSystemEntry entry;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
entry = fileSystem.GetEntry(path);
|
entry = m_fileSystem.GetEntry(path);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(ex);
|
NTStatus status = ToNTStatus(ex);
|
||||||
state.LogToServer(Severity.Debug, "CreateFile: Error retrieving '{0}'. {1}.", path, status);
|
Log(Severity.Debug, "CreateFile: Error retrieving '{0}'. {1}.", path, status);
|
||||||
entry = null;
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +85,7 @@ namespace SMBLibrary.Server
|
||||||
if (entry != null)
|
if (entry != null)
|
||||||
{
|
{
|
||||||
// File already exists, fail the request
|
// 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;
|
fileStatus = FileStatus.FILE_EXISTS;
|
||||||
return NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
return NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
||||||
}
|
}
|
||||||
|
@ -96,19 +99,19 @@ namespace SMBLibrary.Server
|
||||||
{
|
{
|
||||||
if (forceDirectory)
|
if (forceDirectory)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
Log(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
||||||
entry = fileSystem.CreateDirectory(path);
|
entry = m_fileSystem.CreateDirectory(path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
Log(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
||||||
entry = fileSystem.CreateFile(path);
|
entry = m_fileSystem.CreateFile(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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;
|
return status;
|
||||||
}
|
}
|
||||||
fileStatus = FileStatus.FILE_CREATED;
|
fileStatus = FileStatus.FILE_CREATED;
|
||||||
|
@ -134,19 +137,19 @@ namespace SMBLibrary.Server
|
||||||
{
|
{
|
||||||
if (forceDirectory)
|
if (forceDirectory)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
Log(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
||||||
entry = fileSystem.CreateDirectory(path);
|
entry = m_fileSystem.CreateDirectory(path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
Log(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
||||||
entry = fileSystem.CreateFile(path);
|
entry = m_fileSystem.CreateFile(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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;
|
return status;
|
||||||
}
|
}
|
||||||
fileStatus = FileStatus.FILE_CREATED;
|
fileStatus = FileStatus.FILE_CREATED;
|
||||||
|
@ -165,13 +168,13 @@ namespace SMBLibrary.Server
|
||||||
// Truncate the file
|
// Truncate the file
|
||||||
try
|
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();
|
temp.Close();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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;
|
return status;
|
||||||
}
|
}
|
||||||
fileStatus = FileStatus.FILE_OVERWRITTEN;
|
fileStatus = FileStatus.FILE_OVERWRITTEN;
|
||||||
|
@ -181,12 +184,12 @@ namespace SMBLibrary.Server
|
||||||
// Delete the old file
|
// Delete the old file
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
fileSystem.Delete(path);
|
m_fileSystem.Delete(path);
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch(Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,19 +197,19 @@ namespace SMBLibrary.Server
|
||||||
{
|
{
|
||||||
if (forceDirectory)
|
if (forceDirectory)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
Log(Severity.Information, "CreateFile: Creating directory '{0}'", path);
|
||||||
entry = fileSystem.CreateDirectory(path);
|
entry = m_fileSystem.CreateDirectory(path);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
Log(Severity.Information, "CreateFile: Creating file '{0}'", path);
|
||||||
entry = fileSystem.CreateFile(path);
|
entry = m_fileSystem.CreateFile(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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;
|
return status;
|
||||||
}
|
}
|
||||||
fileStatus = FileStatus.FILE_SUPERSEDED;
|
fileStatus = FileStatus.FILE_SUPERSEDED;
|
||||||
|
@ -219,6 +222,7 @@ namespace SMBLibrary.Server
|
||||||
}
|
}
|
||||||
|
|
||||||
FileAccess fileAccess = NTFileStoreHelper.ToFileAccess(desiredAccess.File);
|
FileAccess fileAccess = NTFileStoreHelper.ToFileAccess(desiredAccess.File);
|
||||||
|
Stream stream;
|
||||||
bool deleteOnClose = false;
|
bool deleteOnClose = false;
|
||||||
if (fileAccess == (FileAccess)0 || entry.IsDirectory)
|
if (fileAccess == (FileAccess)0 || entry.IsDirectory)
|
||||||
{
|
{
|
||||||
|
@ -227,13 +231,14 @@ namespace SMBLibrary.Server
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
deleteOnClose = (createOptions & CreateOptions.FILE_DELETE_ON_CLOSE) > 0;
|
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)
|
if (openStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
return openStatus;
|
return openStatus;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handle = new FileHandle(path, entry.IsDirectory, stream, deleteOnClose);
|
||||||
if (fileStatus != FileStatus.FILE_CREATED &&
|
if (fileStatus != FileStatus.FILE_CREATED &&
|
||||||
fileStatus != FileStatus.FILE_OVERWRITTEN &&
|
fileStatus != FileStatus.FILE_OVERWRITTEN &&
|
||||||
fileStatus != FileStatus.FILE_SUPERSEDED)
|
fileStatus != FileStatus.FILE_SUPERSEDED)
|
||||||
|
@ -243,7 +248,7 @@ namespace SMBLibrary.Server
|
||||||
return NTStatus.STATUS_SUCCESS;
|
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;
|
stream = null;
|
||||||
// When FILE_OPEN_REPARSE_POINT is specified, the operation should continue normally if the file is not a reparse point.
|
// 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 disableBuffering = (openOptions & CreateOptions.FILE_NO_INTERMEDIATE_BUFFERING) > 0;
|
||||||
bool buffered = (openOptions & CreateOptions.FILE_SEQUENTIAL_ONLY) > 0 && !disableBuffering && !openReparsePoint;
|
bool buffered = (openOptions & CreateOptions.FILE_SEQUENTIAL_ONLY) > 0 && !disableBuffering && !openReparsePoint;
|
||||||
FileShare fileShare = NTFileStoreHelper.ToFileShare(shareAccess);
|
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
|
try
|
||||||
{
|
{
|
||||||
stream = fileSystem.OpenFile(path, FileMode.Open, fileAccess, fileShare);
|
stream = m_fileSystem.OpenFile(path, FileMode.Open, fileAccess, fileShare);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
NTStatus status = ToNTStatus(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;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,86 +278,111 @@ namespace SMBLibrary.Server
|
||||||
return NTStatus.STATUS_SUCCESS;
|
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;
|
FileHandle fileHandle = (FileHandle)handle;
|
||||||
string openFilePath = openFile.Path;
|
if (fileHandle.Stream != null)
|
||||||
Stream stream = openFile.Stream;
|
|
||||||
if (stream is RPCPipeStream)
|
|
||||||
{
|
{
|
||||||
data = new byte[maxCount];
|
fileHandle.Stream.Close();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
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
|
try
|
||||||
{
|
{
|
||||||
stream.Seek(offset, SeekOrigin.Begin);
|
m_fileSystem.Delete(fileHandle.Path);
|
||||||
data = new byte[maxCount];
|
|
||||||
bytesRead = stream.Read(data, 0, maxCount);
|
|
||||||
}
|
}
|
||||||
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)
|
public NTStatus ReadFile(out byte[] data, object handle, long offset, int maxCount)
|
||||||
{
|
{
|
||||||
// EOF, we must trim the response data array
|
data = null;
|
||||||
data = ByteReader.ReadBytes(data, 0, bytesRead);
|
FileHandle fileHandle = (FileHandle)handle;
|
||||||
}
|
string path = fileHandle.Path;
|
||||||
return NTStatus.STATUS_SUCCESS;
|
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;
|
Log(severity, String.Format(message, args));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <param name="exception">IFileSystem exception</param>
|
/// <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;
|
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\SessionPacket.cs" />
|
||||||
<Compile Include="NetBios\SessionPackets\SessionRequestPacket.cs" />
|
<Compile Include="NetBios\SessionPackets\SessionRequestPacket.cs" />
|
||||||
<Compile Include="NetBios\SessionPackets\SessionRetargetResponsePacket.cs" />
|
<Compile Include="NetBios\SessionPackets\SessionRetargetResponsePacket.cs" />
|
||||||
|
<Compile Include="NTFileStore\Adapter\FileHandle.cs" />
|
||||||
<Compile Include="NTFileStore\Adapter\IOExceptionHelper.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\CompressionFormat.cs" />
|
||||||
<Compile Include="NTFileStore\Enums\FileInformation\FileAttributes.cs" />
|
<Compile Include="NTFileStore\Enums\FileInformation\FileAttributes.cs" />
|
||||||
<Compile Include="NTFileStore\Enums\FileInformation\FileInformationClass.cs" />
|
<Compile Include="NTFileStore\Enums\FileInformation\FileInformationClass.cs" />
|
||||||
|
@ -91,6 +97,8 @@
|
||||||
<Compile Include="NTFileStore\Enums\NtCreateFile\CreateOptions.cs" />
|
<Compile Include="NTFileStore\Enums\NtCreateFile\CreateOptions.cs" />
|
||||||
<Compile Include="NTFileStore\Enums\NtCreateFile\FileStatus.cs" />
|
<Compile Include="NTFileStore\Enums\NtCreateFile\FileStatus.cs" />
|
||||||
<Compile Include="NTFileStore\Enums\NtCreateFile\ShareAccess.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\NTFileStoreHelper.cs" />
|
||||||
<Compile Include="NTFileStore\Structures\ACE\AccessAllowedACE.cs" />
|
<Compile Include="NTFileStore\Structures\ACE\AccessAllowedACE.cs" />
|
||||||
<Compile Include="NTFileStore\Structures\ACE\ACE.cs" />
|
<Compile Include="NTFileStore\Structures\ACE\ACE.cs" />
|
||||||
|
@ -174,11 +182,6 @@
|
||||||
<Compile Include="Server\Exceptions\EmptyPasswordNotAllowedException.cs" />
|
<Compile Include="Server\Exceptions\EmptyPasswordNotAllowedException.cs" />
|
||||||
<Compile Include="Server\Exceptions\InvalidRequestException.cs" />
|
<Compile Include="Server\Exceptions\InvalidRequestException.cs" />
|
||||||
<Compile Include="Server\Exceptions\UnsupportedInformationLevelException.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\Helpers\ServerPathUtils.cs" />
|
||||||
<Compile Include="Server\IndependentUserCollection.cs" />
|
<Compile Include="Server\IndependentUserCollection.cs" />
|
||||||
<Compile Include="Server\INTLMAuthenticationProvider.cs" />
|
<Compile Include="Server\INTLMAuthenticationProvider.cs" />
|
||||||
|
@ -195,10 +198,11 @@
|
||||||
<Compile Include="Server\SMB1\ReadWriteResponseHelper.cs" />
|
<Compile Include="Server\SMB1\ReadWriteResponseHelper.cs" />
|
||||||
<Compile Include="Server\SMB1\ServerResponseHelper.cs" />
|
<Compile Include="Server\SMB1\ServerResponseHelper.cs" />
|
||||||
<Compile Include="Server\SMB1\SessionSetupHelper.cs" />
|
<Compile Include="Server\SMB1\SessionSetupHelper.cs" />
|
||||||
<Compile Include="Server\SMB1\SMB1FileSystemHelper.Find.cs" />
|
<Compile Include="Server\SMB1\SMB1FileStoreHelper.cs" />
|
||||||
<Compile Include="Server\SMB1\SMB1FileSystemHelper.Query.cs" />
|
<Compile Include="Server\SMB1\SMB1FileStoreHelper.Query.cs" />
|
||||||
<Compile Include="Server\SMB1\SMB1FileSystemHelper.QueryFileSystem.cs" />
|
<Compile Include="Server\SMB1\SMB1FileStoreHelper.QueryDirectory.cs" />
|
||||||
<Compile Include="Server\SMB1\SMB1FileSystemHelper.Set.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\Transaction2SubcommandHelper.cs" />
|
||||||
<Compile Include="Server\SMB1\TransactionHelper.cs" />
|
<Compile Include="Server\SMB1\TransactionHelper.cs" />
|
||||||
<Compile Include="Server\SMB1\TransactionSubcommandHelper.cs" />
|
<Compile Include="Server\SMB1\TransactionSubcommandHelper.cs" />
|
||||||
|
|
|
@ -14,14 +14,12 @@ namespace SMBLibrary.Server
|
||||||
public class OpenFileObject
|
public class OpenFileObject
|
||||||
{
|
{
|
||||||
public string Path;
|
public string Path;
|
||||||
public Stream Stream;
|
public object Handle;
|
||||||
public bool DeleteOnClose;
|
|
||||||
|
|
||||||
public OpenFileObject(string path, Stream stream, bool deleteOnClose)
|
public OpenFileObject(string path, object handle)
|
||||||
{
|
{
|
||||||
Path = path;
|
Path = path;
|
||||||
Stream = stream;
|
Handle = handle;
|
||||||
DeleteOnClose = deleteOnClose;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,10 +12,10 @@ namespace SMBLibrary.Server
|
||||||
{
|
{
|
||||||
public class OpenSearch
|
public class OpenSearch
|
||||||
{
|
{
|
||||||
public List<FileSystemEntry> Entries;
|
public List<QueryDirectoryFileInformation> Entries;
|
||||||
public int EnumerationLocation;
|
public int EnumerationLocation;
|
||||||
|
|
||||||
public OpenSearch(List<FileSystemEntry> entries, int enumerationLocation)
|
public OpenSearch(List<QueryDirectoryFileInformation> entries, int enumerationLocation)
|
||||||
{
|
{
|
||||||
Entries = entries;
|
Entries = entries;
|
||||||
EnumerationLocation = enumerationLocation;
|
EnumerationLocation = enumerationLocation;
|
||||||
|
|
|
@ -70,17 +70,12 @@ namespace SMBLibrary.Server
|
||||||
return AddOpenFile(relativePath, null);
|
return AddOpenFile(relativePath, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ushort? AddOpenFile(string relativePath, Stream stream)
|
public ushort? AddOpenFile(string relativePath, object handle)
|
||||||
{
|
|
||||||
return AddOpenFile(relativePath, stream, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ushort? AddOpenFile(string relativePath, Stream stream, bool deleteOnClose)
|
|
||||||
{
|
{
|
||||||
ushort? fileID = m_connection.AllocateFileID();
|
ushort? fileID = m_connection.AllocateFileID();
|
||||||
if (fileID.HasValue)
|
if (fileID.HasValue)
|
||||||
{
|
{
|
||||||
m_openFiles.Add(fileID.Value, new OpenFileObject(relativePath, stream, deleteOnClose));
|
m_openFiles.Add(fileID.Value, new OpenFileObject(relativePath, handle));
|
||||||
}
|
}
|
||||||
return fileID;
|
return fileID;
|
||||||
}
|
}
|
||||||
|
@ -94,11 +89,6 @@ namespace SMBLibrary.Server
|
||||||
|
|
||||||
public void RemoveOpenFile(ushort fileID)
|
public void RemoveOpenFile(ushort fileID)
|
||||||
{
|
{
|
||||||
Stream stream = m_openFiles[fileID].Stream;
|
|
||||||
if (stream != null)
|
|
||||||
{
|
|
||||||
stream.Close();
|
|
||||||
}
|
|
||||||
m_openFiles.Remove(fileID);
|
m_openFiles.Remove(fileID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +110,7 @@ namespace SMBLibrary.Server
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ushort? AddOpenSearch(List<FileSystemEntry> entries, int enumerationLocation)
|
public ushort? AddOpenSearch(List<QueryDirectoryFileInformation> entries, int enumerationLocation)
|
||||||
{
|
{
|
||||||
ushort? searchHandle = AllocateSearchHandle();
|
ushort? searchHandle = AllocateSearchHandle();
|
||||||
if (searchHandle.HasValue)
|
if (searchHandle.HasValue)
|
||||||
|
|
|
@ -90,24 +90,13 @@ namespace SMBLibrary.Server
|
||||||
return m_connectedTrees.ContainsKey(treeID);
|
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>
|
/// <returns>The persistent portion of the FileID</returns>
|
||||||
public ulong? AddOpenFile(string relativePath)
|
public ulong? AddOpenFile(string relativePath, object handle)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
ulong? persistentID = m_connection.AllocatePersistentFileID();
|
ulong? persistentID = m_connection.AllocatePersistentFileID();
|
||||||
if (persistentID.HasValue)
|
if (persistentID.HasValue)
|
||||||
{
|
{
|
||||||
m_openFiles.Add(persistentID.Value, new OpenFileObject(relativePath, stream, deleteOnClose));
|
m_openFiles.Add(persistentID.Value, new OpenFileObject(relativePath, handle));
|
||||||
}
|
}
|
||||||
return persistentID;
|
return persistentID;
|
||||||
}
|
}
|
||||||
|
@ -126,16 +115,11 @@ namespace SMBLibrary.Server
|
||||||
|
|
||||||
public void RemoveOpenFile(ulong fileID)
|
public void RemoveOpenFile(ulong fileID)
|
||||||
{
|
{
|
||||||
Stream stream = m_openFiles[fileID].Stream;
|
|
||||||
if (stream != null)
|
|
||||||
{
|
|
||||||
stream.Close();
|
|
||||||
}
|
|
||||||
m_openFiles.Remove(fileID);
|
m_openFiles.Remove(fileID);
|
||||||
m_openSearches.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);
|
OpenSearch openSearch = new OpenSearch(entries, enumerationLocation);
|
||||||
m_openSearches.Add(fileID, openSearch);
|
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;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(request.CommandName);
|
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);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,51 +41,13 @@ namespace SMBLibrary.Server.SMB1
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
IFileSystem fileSystem = share.FileSystem;
|
|
||||||
|
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(request.DirectoryName);
|
header.Status = SMB1FileStoreHelper.DeleteDirectory(share.FileStore, request.DirectoryName);
|
||||||
if (entry == null)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
|
return new DeleteDirectoryResponse();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static SMB1Command GetDeleteResponse(SMB1Header header, DeleteRequest request, FileSystemShare share, SMB1ConnectionState state)
|
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;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
IFileSystem fileSystem = share.FileSystem;
|
|
||||||
|
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
|
// [MS-CIFS] This command cannot delete directories or volumes.
|
||||||
if (entry == null)
|
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 ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
|
return new DeleteResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static SMB1Command GetRenameResponse(SMB1Header header, RenameRequest request, FileSystemShare share, SMB1ConnectionState state)
|
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;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
IFileSystem fileSystem = share.FileSystem;
|
|
||||||
|
|
||||||
FileSystemEntry sourceEntry = fileSystem.GetEntry(request.OldFileName);
|
header.Status = SMB1FileStoreHelper.Rename(share.FileStore, request.OldFileName, request.NewFileName, request.SearchAttributes);
|
||||||
if (sourceEntry == null)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
|
return new RenameResponse();
|
||||||
|
}
|
||||||
|
|
||||||
// The file must not already exist unless we just want to upcase / downcase a filename letter
|
internal static SMB1Command GetCheckDirectoryResponse(SMB1Header header, CheckDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
|
||||||
FileSystemEntry destinationEntry = fileSystem.GetEntry(request.NewFileName);
|
{
|
||||||
if (destinationEntry != null &&
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
!String.Equals(request.OldFileName, request.NewFileName, StringComparison.InvariantCultureIgnoreCase))
|
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;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(request.CommandName);
|
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;
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
|
if (!share.HasReadAccess(session.UserName, request.FileName, state.ClientEndPoint))
|
||||||
if (entry == null)
|
{
|
||||||
|
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);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryInformationResponse response = new QueryInformationResponse();
|
QueryInformationResponse response = new QueryInformationResponse();
|
||||||
response.FileAttributes = SMB1FileSystemHelper.GetFileAttributes(entry);
|
response.FileAttributes = SMB1FileStoreHelper.GetFileAttributes(fileInfo.FileAttributes);
|
||||||
response.LastWriteTime = entry.LastWriteTime;
|
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||||
response.FileSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
|
response.FileSize = (uint)Math.Min(UInt32.MaxValue, fileInfo.EndOfFile);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,37 +139,13 @@ namespace SMBLibrary.Server.SMB1
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
IFileSystem fileSystem = share.FileSystem;
|
|
||||||
|
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
|
header.Status = SMB1FileStoreHelper.SetInformation(share.FileStore, request.FileName, request.FileAttributes, request.LastWriteTime);
|
||||||
if (entry == null)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
|
||||||
return new ErrorResponse(request.CommandName);
|
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();
|
return new SetInformationResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -269,9 +164,13 @@ namespace SMBLibrary.Server.SMB1
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return new ErrorResponse(request.CommandName);
|
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();
|
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)
|
if (share is NamedPipeShare)
|
||||||
{
|
{
|
||||||
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
|
if (isExtended)
|
||||||
if (pipeStream != null)
|
|
||||||
{
|
{
|
||||||
ushort? fileID = session.AddOpenFile(path, pipeStream);
|
return CreateResponseExtendedForNamedPipe(fileID.Value, FileStatus.FILE_OPENED);
|
||||||
if (!fileID.HasValue)
|
}
|
||||||
{
|
else
|
||||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
{
|
||||||
return new ErrorResponse(request.CommandName);
|
return CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED);
|
||||||
}
|
|
||||||
if (isExtended)
|
|
||||||
{
|
|
||||||
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
|
else // FileSystemShare
|
||||||
{
|
{
|
||||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
if (isExtended)
|
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)
|
if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
|
||||||
{
|
{
|
||||||
response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
|
response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
|
||||||
|
@ -93,7 +73,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NTCreateAndXResponse response = CreateResponseFromFileSystemEntry(entry, fileID.Value, fileStatus);
|
NTCreateAndXResponse response = CreateResponseFromFileInformation(fileInfo, fileID.Value, fileStatus);
|
||||||
if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
|
if ((request.Flags & NTCreateFlags.NT_CREATE_REQUEST_OPBATCH) > 0)
|
||||||
{
|
{
|
||||||
response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
|
response.OpLockLevel = OpLockLevel.BatchOpLockGranted;
|
||||||
|
@ -140,52 +120,38 @@ namespace SMBLibrary.Server.SMB1
|
||||||
return response;
|
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();
|
NTCreateAndXResponse response = new NTCreateAndXResponse();
|
||||||
if (entry.IsDirectory)
|
|
||||||
{
|
|
||||||
response.ExtFileAttributes = ExtendedFileAttributes.Directory;
|
|
||||||
response.Directory = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.ExtFileAttributes = ExtendedFileAttributes.Normal;
|
|
||||||
}
|
|
||||||
response.FID = fileID;
|
response.FID = fileID;
|
||||||
response.CreateDisposition = ToCreateDisposition(fileStatus);
|
response.CreateDisposition = ToCreateDisposition(fileStatus);
|
||||||
response.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
response.CreateTime = fileInfo.CreationTime;
|
||||||
response.EndOfFile = (long)entry.Size;
|
response.LastAccessTime = fileInfo.LastAccessTime;
|
||||||
response.CreateTime = entry.CreationTime;
|
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||||
response.LastAccessTime = entry.LastAccessTime;
|
response.LastChangeTime = fileInfo.LastWriteTime;
|
||||||
response.LastWriteTime = entry.LastWriteTime;
|
response.AllocationSize = fileInfo.AllocationSize;
|
||||||
response.LastChangeTime = entry.LastWriteTime;
|
response.EndOfFile = fileInfo.EndOfFile;
|
||||||
|
response.ExtFileAttributes = (ExtendedFileAttributes)fileInfo.FileAttributes;
|
||||||
response.ResourceType = ResourceType.FileTypeDisk;
|
response.ResourceType = ResourceType.FileTypeDisk;
|
||||||
|
response.Directory = fileInfo.IsDirectory;
|
||||||
return response;
|
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();
|
NTCreateAndXResponseExtended response = new NTCreateAndXResponseExtended();
|
||||||
if (entry.IsDirectory)
|
|
||||||
{
|
|
||||||
response.ExtFileAttributes = ExtendedFileAttributes.Directory;
|
|
||||||
response.Directory = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.ExtFileAttributes = ExtendedFileAttributes.Normal;
|
|
||||||
}
|
|
||||||
response.FID = fileID;
|
response.FID = fileID;
|
||||||
response.CreateDisposition = ToCreateDisposition(fileStatus);
|
response.CreateDisposition = ToCreateDisposition(fileStatus);
|
||||||
response.CreateTime = entry.CreationTime;
|
response.CreateTime = fileInfo.CreationTime;
|
||||||
response.LastAccessTime = entry.LastAccessTime;
|
response.LastAccessTime = fileInfo.LastAccessTime;
|
||||||
response.LastWriteTime = entry.LastWriteTime;
|
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||||
response.LastChangeTime = entry.LastWriteTime;
|
response.LastChangeTime = fileInfo.LastWriteTime;
|
||||||
response.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
response.ExtFileAttributes = (ExtendedFileAttributes)fileInfo.FileAttributes;
|
||||||
response.EndOfFile = (long)entry.Size;
|
response.AllocationSize = fileInfo.AllocationSize;
|
||||||
|
response.EndOfFile = fileInfo.EndOfFile;
|
||||||
response.ResourceType = ResourceType.FileTypeDisk;
|
response.ResourceType = ResourceType.FileTypeDisk;
|
||||||
response.FileStatusFlags = FileStatusFlags.NO_EAS | FileStatusFlags.NO_SUBSTREAMS | FileStatusFlags.NO_REPARSETAG;
|
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 |
|
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_READ_EA | FileAccessMask.FILE_WRITE_EA |
|
||||||
FileAccessMask.FILE_EXECUTE |
|
FileAccessMask.FILE_EXECUTE |
|
||||||
|
|
|
@ -48,38 +48,18 @@ namespace SMBLibrary.Server.SMB1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystemEntry entry = null;
|
object handle;
|
||||||
Stream stream = null;
|
|
||||||
FileStatus fileStatus;
|
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);
|
return new ErrorResponse(request.CommandName);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ushort? fileID = session.AddOpenFile(path, stream);
|
ushort? fileID = session.AddOpenFile(path, handle);
|
||||||
if (!fileID.HasValue)
|
if (!fileID.HasValue)
|
||||||
{
|
{
|
||||||
if (stream != null)
|
share.FileStore.CloseFile(handle);
|
||||||
{
|
|
||||||
stream.Close();
|
|
||||||
}
|
|
||||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
}
|
}
|
||||||
|
@ -98,13 +78,14 @@ namespace SMBLibrary.Server.SMB1
|
||||||
}
|
}
|
||||||
else // FileSystemShare
|
else // FileSystemShare
|
||||||
{
|
{
|
||||||
|
FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
|
||||||
if (isExtended)
|
if (isExtended)
|
||||||
{
|
{
|
||||||
return CreateResponseExtendedFromFileSystemEntry(entry, fileID.Value, openResult);
|
return CreateResponseExtendedFromFileInfo(fileInfo, fileID.Value, openResult);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return CreateResponseFromFileSystemEntry(entry, fileID.Value, openResult);
|
return CreateResponseFromFileInfo(fileInfo, fileID.Value, openResult);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,40 +269,26 @@ namespace SMBLibrary.Server.SMB1
|
||||||
return response;
|
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();
|
OpenAndXResponse response = new OpenAndXResponse();
|
||||||
response.FID = fileID;
|
response.FID = fileID;
|
||||||
if (entry.IsDirectory)
|
response.FileAttrs = SMB1FileStoreHelper.GetFileAttributes(fileInfo.FileAttributes);
|
||||||
{
|
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||||
response.FileAttrs = SMBFileAttributes.Directory;
|
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, fileInfo.EndOfFile);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.FileAttrs = SMBFileAttributes.Normal;
|
|
||||||
}
|
|
||||||
response.LastWriteTime = entry.LastWriteTime;
|
|
||||||
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
|
|
||||||
response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;
|
response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;
|
||||||
response.ResourceType = ResourceType.FileTypeDisk;
|
response.ResourceType = ResourceType.FileTypeDisk;
|
||||||
response.OpenResults.OpenResult = openResult;
|
response.OpenResults.OpenResult = openResult;
|
||||||
return response;
|
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();
|
OpenAndXResponseExtended response = new OpenAndXResponseExtended();
|
||||||
response.FID = fileID;
|
response.FID = fileID;
|
||||||
if (entry.IsDirectory)
|
response.FileAttrs = SMB1FileStoreHelper.GetFileAttributes(fileInfo.FileAttributes);
|
||||||
{
|
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||||
response.FileAttrs = SMBFileAttributes.Directory;
|
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, fileInfo.EndOfFile);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.FileAttrs = SMBFileAttributes.Normal;
|
|
||||||
}
|
|
||||||
response.LastWriteTime = entry.LastWriteTime;
|
|
||||||
response.FileDataSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
|
|
||||||
response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;
|
response.AccessRights = AccessRights.SMB_DA_ACCESS_READ;
|
||||||
response.ResourceType = ResourceType.FileTypeDisk;
|
response.ResourceType = ResourceType.FileTypeDisk;
|
||||||
response.OpenResults.OpenResult = openResult;
|
response.OpenResults.OpenResult = openResult;
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] data;
|
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)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
|
@ -74,7 +74,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
maxCount = request.MaxCountLarge;
|
maxCount = request.MaxCountLarge;
|
||||||
}
|
}
|
||||||
byte[] data;
|
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)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
|
@ -110,7 +110,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
}
|
}
|
||||||
|
|
||||||
int numberOfBytesWritten;
|
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)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName);
|
return new ErrorResponse(request.CommandName);
|
||||||
|
@ -140,7 +140,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
}
|
}
|
||||||
|
|
||||||
int numberOfBytesWritten;
|
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)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName);
|
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);
|
state.LogToServer(Severity.Verbose, "Close: Closing file '{0}'", openFile.Path);
|
||||||
session.RemoveOpenFile(request.FID);
|
header.Status = share.FileStore.CloseFile(openFile.Handle);
|
||||||
if (openFile.DeleteOnClose && share is FileSystemShare)
|
if (header.Status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
try
|
return new ErrorResponse(request.CommandName);
|
||||||
{
|
|
||||||
((FileSystemShare)share).FileSystem.Delete(openFile.Path);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
state.LogToServer(Severity.Debug, "Close: Cannot delete '{0}'", openFile.Path);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
CloseResponse response = new CloseResponse();
|
|
||||||
return response;
|
session.RemoveOpenFile(request.FID);
|
||||||
|
return new CloseResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static SMB1Command GetFindClose2Request(SMB1Header header, FindClose2Request request, SMB1ConnectionState state)
|
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)
|
internal static Transaction2FindFirst2Response GetSubcommandResponse(SMB1Header header, Transaction2FindFirst2Request subcommand, FileSystemShare share, SMB1ConnectionState state)
|
||||||
{
|
{
|
||||||
SMB1Session session = state.GetSession(header.UID);
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
IFileSystem fileSystem = share.FileSystem;
|
|
||||||
string fileNamePattern = subcommand.FileName;
|
string fileNamePattern = subcommand.FileName;
|
||||||
|
|
||||||
List<FileSystemEntry> entries;
|
List<QueryDirectoryFileInformation> entries;
|
||||||
NTStatus searchStatus = SMB1FileSystemHelper.FindEntries(out entries, fileSystem, fileNamePattern);
|
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)
|
if (searchStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Verbose, "FindFirst2: Searched for '{0}', NTStatus: {1}", fileNamePattern, searchStatus.ToString());
|
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;
|
bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
|
||||||
int entriesToReturn = Math.Min(subcommand.SearchCount, entries.Count);
|
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;
|
int maxLength = (int)state.GetMaxDataCount(header.PID).Value;
|
||||||
FindInformationList findInformationList;
|
FindInformationList findInformationList = SMB1FileStoreHelper.GetFindInformationList(segment, subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys, maxLength);
|
||||||
try
|
|
||||||
{
|
|
||||||
findInformationList = SMB1FileSystemHelper.GetFindInformationList(segment, subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys, maxLength);
|
|
||||||
}
|
|
||||||
catch (UnsupportedInformationLevelException)
|
|
||||||
{
|
|
||||||
header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
int returnCount = findInformationList.Count;
|
int returnCount = findInformationList.Count;
|
||||||
Transaction2FindFirst2Response response = new Transaction2FindFirst2Response();
|
Transaction2FindFirst2Response response = new Transaction2FindFirst2Response();
|
||||||
response.SetFindInformationList(findInformationList, header.UnicodeFlag);
|
response.SetFindInformationList(findInformationList, header.UnicodeFlag);
|
||||||
|
@ -91,11 +92,11 @@ namespace SMBLibrary.Server.SMB1
|
||||||
bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
|
bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
|
||||||
int maxLength = (int)state.GetMaxDataCount(header.PID).Value;
|
int maxLength = (int)state.GetMaxDataCount(header.PID).Value;
|
||||||
int maxCount = Math.Min(openSearch.Entries.Count - openSearch.EnumerationLocation, subcommand.SearchCount);
|
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;
|
FindInformationList findInformationList;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
findInformationList = SMB1FileSystemHelper.GetFindInformationList(segment, subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys, maxLength);
|
findInformationList = SMB1FileStoreHelper.GetFindInformationList(segment, subcommand.InformationLevel, header.UnicodeFlag, returnResumeKeys, maxLength);
|
||||||
}
|
}
|
||||||
catch (UnsupportedInformationLevelException)
|
catch (UnsupportedInformationLevelException)
|
||||||
{
|
{
|
||||||
|
@ -125,7 +126,7 @@ namespace SMBLibrary.Server.SMB1
|
||||||
|
|
||||||
Transaction2QueryFSInformationResponse response = new Transaction2QueryFSInformationResponse();
|
Transaction2QueryFSInformationResponse response = new Transaction2QueryFSInformationResponse();
|
||||||
QueryFSInformation queryFSInformation;
|
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)
|
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Verbose, "GetFileSystemInformation failed. Information level: {0}, NTStatus: {1}", subcommand.InformationLevel, queryStatus);
|
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;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
return null;
|
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();
|
Transaction2QueryPathInformationResponse response = new Transaction2QueryPathInformationResponse();
|
||||||
QueryInformation queryInformation;
|
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)
|
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}' failed. Information level: {1}, NTStatus: {2}", path, subcommand.InformationLevel, queryStatus);
|
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)
|
internal static Transaction2QueryFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryFileInformationRequest subcommand, FileSystemShare share, SMB1ConnectionState state)
|
||||||
{
|
{
|
||||||
SMB1Session session = state.GetSession(header.UID);
|
SMB1Session session = state.GetSession(header.UID);
|
||||||
IFileSystem fileSystem = share.FileSystem;
|
|
||||||
OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);
|
OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);
|
||||||
if (openFile == null)
|
if (openFile == null)
|
||||||
{
|
{
|
||||||
|
@ -186,15 +175,9 @@ namespace SMBLibrary.Server.SMB1
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(openFile.Path);
|
|
||||||
if (entry == null)
|
|
||||||
{
|
|
||||||
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
Transaction2QueryFileInformationResponse response = new Transaction2QueryFileInformationResponse();
|
Transaction2QueryFileInformationResponse response = new Transaction2QueryFileInformationResponse();
|
||||||
QueryInformation queryInformation;
|
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)
|
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}' failed. Information level: {1}, NTStatus: {2}", openFile.Path, subcommand.InformationLevel, queryStatus);
|
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;
|
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)
|
if (status != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}' failed. Information level: {1}, NTStatus: {2}", openFile.Path, information.InformationLevel, status);
|
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();
|
Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse();
|
||||||
return response;
|
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();
|
TransactionTransactNamedPipeResponse response = new TransactionTransactNamedPipeResponse();
|
||||||
openFile.Stream.Write(subcommand.WriteData, 0, subcommand.WriteData.Length);
|
int numberOfBytesWritten;
|
||||||
response.ReadData = ByteReader.ReadAllBytes(openFile.Stream);
|
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;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,29 +22,21 @@ namespace SMBLibrary.Server.SMB2
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED);
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED);
|
||||||
}
|
}
|
||||||
string path = openFile.Path;
|
share.FileStore.CloseFile(openFile.Handle);
|
||||||
session.RemoveOpenFile(request.FileId.Persistent);
|
session.RemoveOpenFile(request.FileId.Persistent);
|
||||||
CloseResponse response = new CloseResponse();
|
CloseResponse response = new CloseResponse();
|
||||||
if (request.PostQueryAttributes)
|
if (request.PostQueryAttributes)
|
||||||
{
|
{
|
||||||
if (share is NamedPipeShare)
|
FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, openFile.Path);
|
||||||
|
if (fileInfo != null)
|
||||||
{
|
{
|
||||||
response.FileAttributes = FileAttributes.Temporary;
|
response.CreationTime = fileInfo.CreationTime;
|
||||||
}
|
response.LastAccessTime = fileInfo.LastAccessTime;
|
||||||
else // FileSystemShare
|
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||||
{
|
response.ChangeTime = fileInfo.ChangeTime;
|
||||||
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
response.AllocationSize = fileInfo.AllocationSize;
|
||||||
FileSystemEntry entry = fileSystem.GetEntry(path);
|
response.EndofFile = fileInfo.EndOfFile;
|
||||||
if (entry != null)
|
response.FileAttributes = fileInfo.FileAttributes;
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return response;
|
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)
|
if (share is NamedPipeShare)
|
||||||
{
|
{
|
||||||
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
|
return CreateResponseForNamedPipe(persistentFileID.Value, FileStatus.FILE_OPENED);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle);
|
||||||
|
CreateResponse response = CreateResponseFromFileSystemEntry(fileInfo, persistentFileID.Value, fileStatus);
|
||||||
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);
|
|
||||||
if (request.RequestedOplockLevel == OplockLevel.Batch)
|
if (request.RequestedOplockLevel == OplockLevel.Batch)
|
||||||
{
|
{
|
||||||
response.OplockLevel = OplockLevel.Batch;
|
response.OplockLevel = OplockLevel.Batch;
|
||||||
|
@ -91,24 +72,17 @@ namespace SMBLibrary.Server.SMB2
|
||||||
return response;
|
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();
|
CreateResponse response = new CreateResponse();
|
||||||
if (entry.IsDirectory)
|
|
||||||
{
|
|
||||||
response.FileAttributes = FileAttributes.Directory;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
response.FileAttributes = FileAttributes.Normal;
|
|
||||||
}
|
|
||||||
response.CreateAction = (CreateAction)fileStatus;
|
response.CreateAction = (CreateAction)fileStatus;
|
||||||
response.CreationTime = entry.CreationTime;
|
response.CreationTime = fileInfo.CreationTime;
|
||||||
response.LastWriteTime = entry.LastWriteTime;
|
response.LastWriteTime = fileInfo.LastWriteTime;
|
||||||
response.ChangeTime = entry.LastWriteTime;
|
response.ChangeTime = fileInfo.LastWriteTime;
|
||||||
response.LastAccessTime = entry.LastAccessTime;
|
response.LastAccessTime = fileInfo.LastAccessTime;
|
||||||
response.AllocationSize = (long)NTFileSystemHelper.GetAllocationSize(entry.Size);
|
response.AllocationSize = fileInfo.AllocationSize;
|
||||||
response.EndofFile = (long)entry.Size;
|
response.EndofFile = fileInfo.EndOfFile;
|
||||||
|
response.FileAttributes = fileInfo.FileAttributes;
|
||||||
response.FileId.Persistent = persistentFileID;
|
response.FileId.Persistent = persistentFileID;
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,18 @@ namespace SMBLibrary.Server.SMB2
|
||||||
{
|
{
|
||||||
IOCtlResponse response = new IOCtlResponse();
|
IOCtlResponse response = new IOCtlResponse();
|
||||||
response.CtlCode = request.CtlCode;
|
response.CtlCode = request.CtlCode;
|
||||||
openFile.Stream.Write(request.Input, 0, request.Input.Length);
|
int numberOfBytesWritten;
|
||||||
response.Output = ByteReader.ReadAllBytes(openFile.Stream);
|
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;
|
return response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,19 +34,6 @@ namespace SMBLibrary.Server.SMB2
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
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;
|
ulong fileID = request.FileId.Persistent;
|
||||||
OpenSearch openSearch = session.GetOpenSearch(fileID);
|
OpenSearch openSearch = session.GetOpenSearch(fileID);
|
||||||
|
@ -56,8 +43,8 @@ namespace SMBLibrary.Server.SMB2
|
||||||
{
|
{
|
||||||
session.RemoveOpenSearch(fileID);
|
session.RemoveOpenSearch(fileID);
|
||||||
}
|
}
|
||||||
List<FileSystemEntry> entries;
|
List<QueryDirectoryFileInformation> entries;
|
||||||
NTStatus searchStatus = NTFileSystemHelper.FindEntries(out entries, fileSystemShare.FileSystem, openFile.Path, request.FileName);
|
NTStatus searchStatus = share.FileStore.QueryDirectory(out entries, openFile.Handle, request.FileName, request.FileInformationClass);
|
||||||
if (searchStatus != NTStatus.STATUS_SUCCESS)
|
if (searchStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Verbose, "Query Directory: Path: '{0}', Searched for '{1}', NTStatus: {2}", openFile.Path, request.FileName, searchStatus.ToString());
|
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;
|
int pageLength = 0;
|
||||||
for (int index = openSearch.EnumerationLocation; index < openSearch.Entries.Count; index++)
|
for (int index = openSearch.EnumerationLocation; index < openSearch.Entries.Count; index++)
|
||||||
{
|
{
|
||||||
QueryDirectoryFileInformation fileInformation;
|
QueryDirectoryFileInformation fileInformation = openSearch.Entries[index];
|
||||||
try
|
if (fileInformation.FileInformationClass != request.FileInformationClass)
|
||||||
{
|
{
|
||||||
fileInformation = FromFileSystemEntry(openSearch.Entries[index], request.FileInformationClass);
|
// We do not support changing FileInformationClass during a search (unless SMB2_REOPEN is set).
|
||||||
}
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_PARAMETER);
|
||||||
catch (UnsupportedInformationLevelException)
|
|
||||||
{
|
|
||||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_INVALID_INFO_CLASS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pageLength + fileInformation.Length <= request.OutputBufferLength)
|
if (pageLength + fileInformation.Length <= request.OutputBufferLength)
|
||||||
|
@ -119,95 +103,5 @@ namespace SMBLibrary.Server.SMB2
|
||||||
response.SetFileInformationList(page);
|
response.SetFileInformationList(page);
|
||||||
return response;
|
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);
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED);
|
||||||
}
|
}
|
||||||
|
|
||||||
FileInformation fileInformation;
|
if (share is FileSystemShare)
|
||||||
NTStatus queryStatus;
|
|
||||||
if (share is NamedPipeShare)
|
|
||||||
{
|
|
||||||
queryStatus = NTFileSystemHelper.GetNamedPipeInformation(out fileInformation, request.FileInformationClass);
|
|
||||||
}
|
|
||||||
else // FileSystemShare
|
|
||||||
{
|
{
|
||||||
if (!((FileSystemShare)share).HasReadAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
if (!((FileSystemShare)share).HasReadAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
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)
|
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}' failed. Information class: {1}, NTStatus: {2}", openFile.Path, request.FileInformationClass, queryStatus);
|
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);
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
||||||
}
|
}
|
||||||
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
|
||||||
FileSystemInformation fileSystemInformation;
|
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)
|
if (queryStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
state.LogToServer(Severity.Verbose, "GetFileSystemInformation failed. Information class: {0}, NTStatus: {1}", request.FileSystemInformationClass, queryStatus);
|
state.LogToServer(Severity.Verbose, "GetFileSystemInformation failed. Information class: {0}, NTStatus: {1}", request.FileSystemInformationClass, queryStatus);
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace SMBLibrary.Server.SMB2
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] data;
|
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)
|
if (readStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName, readStatus);
|
return new ErrorResponse(request.CommandName, readStatus);
|
||||||
|
@ -44,7 +44,7 @@ namespace SMBLibrary.Server.SMB2
|
||||||
}
|
}
|
||||||
|
|
||||||
int numberOfBytesWritten;
|
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)
|
if (writeStatus != NTStatus.STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName, writeStatus);
|
return new ErrorResponse(request.CommandName, writeStatus);
|
||||||
|
|
|
@ -27,47 +27,37 @@ namespace SMBLibrary.Server.SMB2
|
||||||
|
|
||||||
if (share is FileSystemShare)
|
if (share is FileSystemShare)
|
||||||
{
|
{
|
||||||
IFileSystem fileSystem = ((FileSystemShare)share).FileSystem;
|
|
||||||
if (!((FileSystemShare)share).HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
if (!((FileSystemShare)share).HasWriteAccess(session.UserName, openFile.Path, state.ClientEndPoint))
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_ACCESS_DENIED);
|
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);
|
return new ErrorResponse(request.CommandName, NTStatus.STATUS_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,7 +199,7 @@ namespace SMBLibrary.Server
|
||||||
return new ErrorResponse(command.CommandName);
|
return new ErrorResponse(command.CommandName);
|
||||||
}
|
}
|
||||||
QueryInformationRequest request = (QueryInformationRequest)command;
|
QueryInformationRequest request = (QueryInformationRequest)command;
|
||||||
return FileSystemResponseHelper.GetQueryInformationResponse(header, request, (FileSystemShare)share);
|
return FileSystemResponseHelper.GetQueryInformationResponse(header, request, (FileSystemShare)share, state);
|
||||||
}
|
}
|
||||||
else if (command is SetInformationRequest)
|
else if (command is SetInformationRequest)
|
||||||
{
|
{
|
||||||
|
@ -229,7 +229,7 @@ namespace SMBLibrary.Server
|
||||||
return new ErrorResponse(command.CommandName);
|
return new ErrorResponse(command.CommandName);
|
||||||
}
|
}
|
||||||
CheckDirectoryRequest request = (CheckDirectoryRequest)command;
|
CheckDirectoryRequest request = (CheckDirectoryRequest)command;
|
||||||
return FileSystemResponseHelper.GetCheckDirectoryResponse(header, request, (FileSystemShare)share);
|
return FileSystemResponseHelper.GetCheckDirectoryResponse(header, request, (FileSystemShare)share, state);
|
||||||
}
|
}
|
||||||
else if (command is WriteRawRequest)
|
else if (command is WriteRawRequest)
|
||||||
{
|
{
|
||||||
|
|
|
@ -177,7 +177,11 @@ namespace SMBLibrary.Server
|
||||||
{
|
{
|
||||||
return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED);
|
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();
|
return new FlushResponse();
|
||||||
}
|
}
|
||||||
else if (command is CloseRequest)
|
else if (command is CloseRequest)
|
||||||
|
|
|
@ -33,14 +33,20 @@ namespace SMBLibrary.Server
|
||||||
public class FileSystemShare : ISMBShare
|
public class FileSystemShare : ISMBShare
|
||||||
{
|
{
|
||||||
private string m_name;
|
private string m_name;
|
||||||
public IFileSystem m_fileSystem;
|
private INTFileStore m_fileSystem;
|
||||||
|
|
||||||
public event EventHandler<AccessRequestArgs> OnAccessRequest;
|
public event EventHandler<AccessRequestArgs> OnAccessRequest;
|
||||||
|
|
||||||
|
public FileSystemShare(string shareName, INTFileStore fileSystem)
|
||||||
|
{
|
||||||
|
m_name = shareName;
|
||||||
|
m_fileSystem = fileSystem;
|
||||||
|
}
|
||||||
|
|
||||||
public FileSystemShare(string shareName, IFileSystem fileSystem)
|
public FileSystemShare(string shareName, IFileSystem fileSystem)
|
||||||
{
|
{
|
||||||
m_name = shareName;
|
m_name = shareName;
|
||||||
m_fileSystem = fileSystem;
|
m_fileSystem = new NTFileSystemAdapter(fileSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasReadAccess(string userName, string path, IPEndPoint clientEndPoint)
|
public bool HasReadAccess(string userName, string path, IPEndPoint clientEndPoint)
|
||||||
|
@ -74,7 +80,7 @@ namespace SMBLibrary.Server
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IFileSystem FileSystem
|
public INTFileStore FileStore
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,5 +14,10 @@ namespace SMBLibrary.Server
|
||||||
{
|
{
|
||||||
get;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INTFileStore FileStore
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,45 +12,19 @@ using SMBLibrary.Services;
|
||||||
|
|
||||||
namespace SMBLibrary.Server
|
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$".
|
// A pipe share, as defined by the SMB Protocol, MUST always have the name "IPC$".
|
||||||
public const string NamedPipeShareName = "IPC$";
|
public const string NamedPipeShareName = "IPC$";
|
||||||
|
|
||||||
|
private NamedPipeStore m_store;
|
||||||
|
|
||||||
public NamedPipeShare(List<string> shareList)
|
public NamedPipeShare(List<string> shareList)
|
||||||
{
|
{
|
||||||
this.Add(new ServerService(Environment.MachineName, shareList));
|
List<RemoteService> services = new List<RemoteService>();
|
||||||
this.Add(new WorkstationService(Environment.MachineName, Environment.MachineName));
|
services.Add(new ServerService(Environment.MachineName, shareList));
|
||||||
}
|
services.Add(new WorkstationService(Environment.MachineName, Environment.MachineName));
|
||||||
|
m_store = new NamedPipeStore(services);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Name
|
public string Name
|
||||||
|
@ -60,5 +34,13 @@ namespace SMBLibrary.Server
|
||||||
return NamedPipeShareName;
|
return NamedPipeShareName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public INTFileStore FileStore
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_store;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue