1
0
mirror of https://github.com/winfsp/winfsp.git synced 2026-03-21 15:39:34 -05:00
Files
winfsp/tst/passthrough-dotnet/Program.cs
2017-04-07 22:28:57 -07:00

924 lines
29 KiB
C#

/**
* @file Program.cs
*
* @copyright 2015-2017 Bill Zissimopoulos
*/
/*
* This file is part of WinFsp.
*
* You can redistribute it and/or modify it under the terms of the GNU
* General Public License version 3 as published by the Free Software
* Foundation.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* software.
*/
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
using Fsp;
using VolumeInfo = Fsp.Interop.VolumeInfo;
using FileInfo = Fsp.Interop.FileInfo;
namespace passthrough
{
class Ptfs : FileSystem
{
private const int ALLOCATION_UNIT = 4096;
protected class FileDesc
{
public FileSystemInfo Info;
public FileStream Stream;
public FileDesc(FileSystemInfo Info, FileStream Stream)
{
this.Info = Info;
this.Stream = Stream;
}
public UInt32 FileAttributes
{
get
{
return (UInt32)Info.Attributes;
}
set
{
Info.Attributes = 0 == value ?
System.IO.FileAttributes.Normal : (FileAttributes)value;
}
}
}
public Ptfs() : base()
{
SetSectorSize(ALLOCATION_UNIT);
SetSectorsPerAllocationUnit(1);
SetFileInfoTimeout(1000);
SetCaseSensitiveSearch(false);
SetCasePreservedNames(true);
SetUnicodeOnDisk(true);
SetPersistentAcls(true);
SetPostCleanupWhenModifiedOnly(true);
SetPassQueryDirectoryPattern(true);
}
void SetPath(String value)
{
_Path = Path.GetFullPath(value);
SetVolumeCreationTime((UInt64)File.GetCreationTimeUtc(_Path).ToFileTimeUtc());
SetVolumeSerialNumber(0);
}
protected override Int32 ExceptionHandler(Exception ex)
{
Int32 HResult = ex.HResult; /* needs Framework 4.5 */
if (0x80070000 == (HResult & 0xFFFF0000))
return NtStatusFromWin32((UInt32)HResult & 0xFFFF);
return STATUS_UNEXPECTED_IO_ERROR;
}
protected String ConcatPath(String FileName)
{
return Path.Combine(_Path, FileName);
}
protected Int32 GetFileInfoInternal(FileDesc FileDesc, Boolean Refresh,
out FileInfo FileInfo)
{
if (Refresh)
FileDesc.Info.Refresh();
FileInfo.FileAttributes = FileDesc.FileAttributes;
FileInfo.ReparseTag = 0;
FileInfo.FileSize = FileDesc.Info is System.IO.FileInfo ?
(UInt64)((System.IO.FileInfo)FileDesc.Info).Length : 0;
FileInfo.AllocationSize = (FileInfo.FileSize + ALLOCATION_UNIT - 1)
/ ALLOCATION_UNIT * ALLOCATION_UNIT;
FileInfo.CreationTime = (UInt64)FileDesc.Info.CreationTimeUtc.ToFileTimeUtc();
FileInfo.LastAccessTime = (UInt64)FileDesc.Info.LastAccessTimeUtc.ToFileTimeUtc();
FileInfo.LastWriteTime = (UInt64)FileDesc.Info.LastWriteTimeUtc.ToFileTimeUtc();
FileInfo.ChangeTime = FileInfo.LastWriteTime;
FileInfo.IndexNumber = 0;
FileInfo.HardLinks = 0;
return STATUS_SUCCESS;
}
protected override Int32 GetVolumeInfo(
out VolumeInfo VolumeInfo)
{
VolumeInfo = default(VolumeInfo);
try
{
DriveInfo Info = new DriveInfo(_Path);
VolumeInfo.TotalSize = (UInt64)Info.TotalSize;
VolumeInfo.FreeSize = (UInt64)Info.TotalFreeSpace;
}
catch (ArgumentException)
{
/*
* DriveInfo only supports drives and does not support UNC paths.
* It would be better to use GetDiskFreeSpaceEx here.
*/
}
return STATUS_SUCCESS;
}
protected override Int32 GetSecurityByName(
String FileName,
out UInt32 FileAttributes/* or ReparsePointIndex */,
ref Byte[] SecurityDescriptor)
{
FileName = ConcatPath(FileName);
System.IO.FileInfo Info = new System.IO.FileInfo(FileName);
FileAttributes = (UInt32)Info.Attributes;
if (null != SecurityDescriptor)
SecurityDescriptor = Info.GetAccessControl().GetSecurityDescriptorBinaryForm();
return STATUS_SUCCESS;
}
protected override Int32 Create(
String FileName,
UInt32 CreateOptions,
UInt32 GrantedAccess,
UInt32 FileAttributes,
Byte[] SecurityDescriptor,
UInt64 AllocationSize,
out Object FileNode,
out Object FileDesc0,
out FileInfo FileInfo,
out String NormalizedName)
{
FileDesc FileDesc;
FileName = ConcatPath(FileName);
if (0 != (CreateOptions & FILE_DIRECTORY_FILE))
{
DirectorySecurity Security = null;
if (null != SecurityDescriptor)
{
Security = new DirectorySecurity();
Security.SetSecurityDescriptorBinaryForm(SecurityDescriptor);
}
// ???: FILE_DELETE_ON_CLOSE
FileDesc = new FileDesc(
Directory.CreateDirectory(FileName, Security),
null);
}
else
{
FileSecurity Security = null;
if (null != SecurityDescriptor)
{
Security = new FileSecurity();
Security.SetSecurityDescriptorBinaryForm(SecurityDescriptor);
}
FileOptions Options = 0 != (CreateOptions & FILE_DELETE_ON_CLOSE) ?
FileOptions.DeleteOnClose : 0;
FileDesc = new FileDesc(
new System.IO.FileInfo(FileName),
new FileStream(
FileName,
FileMode.CreateNew,
(FileSystemRights)GrantedAccess,
FileShare.Read | FileShare.Write | FileShare.Delete,
4096,
Options,
Security));
}
FileDesc.FileAttributes = FileAttributes;
FileNode = default(Object);
FileDesc0 = FileDesc;
NormalizedName = default(String);
return GetFileInfoInternal(FileDesc, false, out FileInfo);
}
protected override Int32 Open(
String FileName,
UInt32 CreateOptions,
UInt32 GrantedAccess,
out Object FileNode,
out Object FileDesc0,
out FileInfo FileInfo,
out String NormalizedName)
{
FileDesc FileDesc;
FileName = ConcatPath(FileName);
if (Directory.Exists(FileName))
{
// ???: FILE_DELETE_ON_CLOSE
FileDesc = new FileDesc(
new System.IO.DirectoryInfo(FileName),
null);
}
else
{
FileOptions Options = 0 != (CreateOptions & FILE_DELETE_ON_CLOSE) ?
FileOptions.DeleteOnClose : 0;
FileDesc = new FileDesc(
new System.IO.FileInfo(FileName),
new FileStream(
FileName,
FileMode.Open,
(FileSystemRights)GrantedAccess,
FileShare.Read | FileShare.Write | FileShare.Delete,
4096,
Options));
}
FileNode = default(Object);
FileDesc0 = FileDesc;
NormalizedName = default(String);
return GetFileInfoInternal(FileDesc, false, out FileInfo);
}
protected override Int32 Overwrite(
Object FileNode,
Object FileDesc0,
UInt32 FileAttributes,
Boolean ReplaceFileAttributes,
UInt64 AllocationSize,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (ReplaceFileAttributes)
FileDesc.FileAttributes = FileAttributes;
else if (0 != FileAttributes)
FileDesc.FileAttributes |= FileAttributes;
FileDesc.Stream.SetLength(0);
return GetFileInfoInternal(FileDesc, true, out FileInfo);
}
protected override void Cleanup(
Object FileNode,
Object FileDesc0,
String FileName,
UInt32 Flags)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (0 == (Flags & CleanupDelete))
FileDesc.Stream.Dispose();
}
protected override void Close(
Object FileNode,
Object FileDesc0)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
FileDesc.Stream.Dispose();
}
protected override Int32 Read(
Object FileNode,
Object FileDesc0,
IntPtr Buffer,
UInt64 Offset,
UInt32 Length,
out UInt32 PBytesTransferred)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
Byte[] Bytes = new byte[Length];
FileDesc.Stream.Seek((Int64)Offset, SeekOrigin.Begin);
PBytesTransferred = (UInt32)FileDesc.Stream.Read(Bytes, 0, Bytes.Length);
Marshal.Copy(Bytes, 0, Buffer, Bytes.Length);
return STATUS_SUCCESS;
}
protected override Int32 Write(
Object FileNode,
Object FileDesc0,
IntPtr Buffer,
UInt64 Offset,
UInt32 Length,
Boolean WriteToEndOfFile,
Boolean ConstrainedIo,
out UInt32 PBytesTransferred,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
UInt64 FileSize;
if (ConstrainedIo)
{
FileDesc.Info.Refresh();
FileSize = (UInt64)((System.IO.FileInfo)FileDesc.Info).Length;
if (Offset >= FileSize)
{
PBytesTransferred = default(UInt32);
FileInfo = default(FileInfo);
return STATUS_SUCCESS;
}
if (Offset + Length > FileSize)
Length = (UInt32)(FileSize - Offset);
}
Byte[] Bytes = new byte[Length];
Marshal.Copy(Buffer, Bytes, 0, Bytes.Length);
FileDesc.Stream.Seek((Int64)Offset, SeekOrigin.Begin);
FileDesc.Stream.Write(Bytes, 0, Bytes.Length);
PBytesTransferred = (UInt32)Bytes.Length;
return GetFileInfoInternal(FileDesc, true, out FileInfo);
}
protected override Int32 Flush(
Object FileNode,
Object FileDesc0,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (null == FileDesc)
{
/* we do not flush the whole volume, so just return SUCCESS */
FileInfo = default(FileInfo);
return STATUS_SUCCESS;
}
FileDesc.Stream.Flush(true);
return GetFileInfoInternal(FileDesc, true, out FileInfo);
}
protected override Int32 GetFileInfo(
Object FileNode,
Object FileDesc0,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
return GetFileInfoInternal(FileDesc, true, out FileInfo);
}
protected override Int32 SetBasicInfo(
Object FileNode,
Object FileDesc0,
UInt32 FileAttributes,
UInt64 CreationTime,
UInt64 LastAccessTime,
UInt64 LastWriteTime,
UInt64 ChangeTime,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (unchecked((UInt32)(-1)) != FileAttributes)
FileDesc.FileAttributes = FileAttributes;
if (0 != CreationTime)
FileDesc.Info.CreationTimeUtc = DateTime.FromFileTimeUtc((Int64)CreationTime);
if (0 != LastAccessTime)
FileDesc.Info.LastAccessTimeUtc = DateTime.FromFileTimeUtc((Int64)LastAccessTime);
if (0 != LastWriteTime)
FileDesc.Info.LastWriteTimeUtc = DateTime.FromFileTimeUtc((Int64)LastWriteTime);
return GetFileInfoInternal(FileDesc, true, out FileInfo);
}
protected override Int32 SetFileSize(
Object FileNode,
Object FileDesc0,
UInt64 NewSize,
Boolean SetAllocationSize,
out FileInfo FileInfo)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
GetFileInfoInternal(FileDesc, true, out FileInfo);
if (!SetAllocationSize || FileInfo.FileSize > NewSize)
{
/*
* "FileInfo.FileSize > NewSize" explanation:
* Ptfs does not support allocation size. However if the new AllocationSize
* is less than the current FileSize we must truncate the file.
*/
FileDesc.Stream.SetLength((Int64)NewSize);
FileInfo.FileSize = NewSize;
FileInfo.AllocationSize = (FileInfo.FileSize + ALLOCATION_UNIT - 1)
/ ALLOCATION_UNIT * ALLOCATION_UNIT;
}
return STATUS_SUCCESS;
}
protected override Int32 CanDelete(
Object FileNode,
Object FileDesc0,
String FileName)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
FileName = ConcatPath(FileName);
/*
* If a file has an open handle the Delete call below
* will only mark it for disposition.
*/
if (null == FileDesc.Stream)
Directory.Delete(FileName);
else
File.Delete(FileName);
return STATUS_SUCCESS;
}
protected override Int32 Rename(
Object FileNode,
Object FileDesc0,
String FileName,
String NewFileName,
Boolean ReplaceIfExists)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
FileName = ConcatPath(FileName);
NewFileName = ConcatPath(NewFileName);
if (null == FileDesc.Stream)
{
if (ReplaceIfExists)
return STATUS_ACCESS_DENIED;
Directory.Move(FileName, NewFileName);
}
else
{
if (ReplaceIfExists)
File.Delete(NewFileName);
File.Move(FileName, NewFileName);
}
return STATUS_SUCCESS;
}
protected override Int32 GetSecurity(
Object FileNode,
Object FileDesc0,
ref Byte[] SecurityDescriptor)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (null == FileDesc.Stream)
SecurityDescriptor = ((System.IO.DirectoryInfo)FileDesc.Info).GetAccessControl().
GetSecurityDescriptorBinaryForm();
else
SecurityDescriptor = ((System.IO.FileInfo)FileDesc.Info).GetAccessControl().
GetSecurityDescriptorBinaryForm();
return STATUS_SUCCESS;
}
protected override Int32 SetSecurity(
Object FileNode,
Object FileDesc0,
AccessControlSections Sections,
Byte[] SecurityDescriptor)
{
FileDesc FileDesc = (FileDesc)FileDesc0;
if (null == FileDesc.Stream)
{
DirectorySecurity Security = ((System.IO.DirectoryInfo)FileDesc.Info).GetAccessControl();
Security.SetSecurityDescriptorBinaryForm(SecurityDescriptor, Sections);
((System.IO.DirectoryInfo)FileDesc.Info).SetAccessControl(Security);
}
else
{
FileSecurity Security = ((System.IO.FileInfo)FileDesc.Info).GetAccessControl();
Security.SetSecurityDescriptorBinaryForm(SecurityDescriptor, Sections);
((System.IO.FileInfo)FileDesc.Info).SetAccessControl(Security);
}
return STATUS_SUCCESS;
}
protected override Int32 ReadDirectory(
Object FileNode,
Object FileDesc,
String Pattern,
String Marker,
IntPtr Buffer,
UInt32 Length,
out UInt32 PBytesTransferred)
{
PBytesTransferred = default(UInt32);
return STATUS_INVALID_DEVICE_REQUEST;
}
private String _Path;
}
class PtfsService : Service
{
public PtfsService() : base("PtfsService")
{
}
protected override void OnStart(String[] Args)
{
#if false
wchar_t **argp, **arge;
String DebugLogFile = null;
UInt32 DebugFlags = 0;
String VolumePrefix = null;
String PassThrough = null;
String MountPoint = null;
HANDLE DebugLogHandle = INVALID_HANDLE_VALUE;
WCHAR PassThroughBuf[MAX_PATH];
PTFS *Ptfs = 0;
NTSTATUS Result;
for (argp = argv + 1, arge = argv + argc; arge > argp; argp++)
{
if (L'-' != argp[0][0])
break;
switch (argp[0][1])
{
case L'?':
goto usage;
case L'd':
argtol(DebugFlags);
break;
case L'D':
argtos(DebugLogFile);
break;
case L'm':
argtos(MountPoint);
break;
case L'p':
argtos(PassThrough);
break;
case L'u':
argtos(VolumePrefix);
break;
default:
goto usage;
}
}
if (arge > argp)
goto usage;
if (0 == PassThrough && 0 != VolumePrefix)
{
PWSTR P;
P = wcschr(VolumePrefix, L'\\');
if (0 != P && L'\\' != P[1])
{
P = wcschr(P + 1, L'\\');
if (0 != P &&
(
(L'A' <= P[1] && P[1] <= L'Z') ||
(L'a' <= P[1] && P[1] <= L'z')
) &&
L'$' == P[2])
{
StringCbPrintf(PassThroughBuf, sizeof PassThroughBuf, L"%c:%s", P[1], P + 3);
PassThrough = PassThroughBuf;
}
}
}
if (0 == PassThrough || 0 == MountPoint)
goto usage;
EnableBackupRestorePrivileges();
if (0 != DebugLogFile)
{
if (0 == wcscmp(L"-", DebugLogFile))
DebugLogHandle = GetStdHandle(STD_ERROR_HANDLE);
else
DebugLogHandle = CreateFileW(
DebugLogFile,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == DebugLogHandle)
{
fail(L"cannot open debug log file");
goto usage;
}
FspDebugLogSetHandle(DebugLogHandle);
}
Ptfs = new PTFS;
Ptfs->SetPrefix(VolumePrefix);
Result = Ptfs->SetPath(PassThrough);
if (!NT_SUCCESS(Result))
{
fail(L"cannot create file system");
goto exit;
}
Result = Ptfs->Mount(MountPoint, 0, FALSE, DebugFlags);
if (!NT_SUCCESS(Result))
{
fail(L"cannot mount file system");
goto exit;
}
MountPoint = Ptfs->MountPoint();
info(L"%s%s%s -p %s -m %s",
L"" PROGNAME,
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? L" -u " : L"",
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? VolumePrefix : L"",
PassThrough,
MountPoint);
_Ptfs = Ptfs;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result) && 0 != Ptfs)
delete Ptfs;
return Result;
usage:
static wchar_t usage[] = L""
"usage: %s OPTIONS\n"
"\n"
"options:\n"
" -d DebugFlags [-1: enable all debug logs]\n"
" -D DebugLogFile [file path; use - for stderr]\n"
" -u \\Server\\Share [UNC prefix (single backslash)]\n"
" -p Directory [directory to expose as pass through file system]\n"
" -m MountPoint [X:|*|directory]\n";
fail(usage, L"" PROGNAME);
return STATUS_UNSUCCESSFUL;
#endif
}
protected override void OnStop()
{
_Ptfs.Unmount();
_Ptfs = null;
}
private Ptfs _Ptfs;
}
class Program
{
static void Main(string[] args)
{
Environment.ExitCode = new PtfsService().Run();
}
}
}
#if false
using namespace Fsp;
struct PTFS_FILE_DESC
{
PTFS_FILE_DESC() : Handle(INVALID_HANDLE_VALUE), DirBuffer()
{
}
~PTFS_FILE_DESC()
{
CloseHandle(Handle);
PTFS::DeleteDirectoryBuffer(&DirBuffer);
}
HANDLE Handle;
PVOID DirBuffer;
};
NTSTATUS PTFS::ReadDirectory(
const FILE_CONTEXT *FileContext, PWSTR Pattern, PWSTR Marker,
PVOID Buffer, ULONG BufferLength, PULONG PBytesTransferred)
{
PTFS_FILE_DESC *FileDesc = (PTFS_FILE_DESC *)FileContext->FileDesc;
HANDLE Handle = FileDesc->Handle;
WCHAR FullPath[FULLPATH_SIZE];
ULONG Length, PatternLength;
HANDLE FindHandle;
WIN32_FIND_DATAW FindData;
union
{
UINT8 B[FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) + MAX_PATH * sizeof(WCHAR)];
FSP_FSCTL_DIR_INFO D;
} DirInfoBuf;
FSP_FSCTL_DIR_INFO *DirInfo = &DirInfoBuf.D;
NTSTATUS DirBufferResult;
DirBufferResult = STATUS_SUCCESS;
if (AcquireDirectoryBuffer(&FileDesc->DirBuffer, 0 == Marker, &DirBufferResult))
{
if (0 == Pattern)
Pattern = L"*";
PatternLength = (ULONG)wcslen(Pattern);
Length = GetFinalPathNameByHandleW(Handle, FullPath, FULLPATH_SIZE - 1, 0);
if (0 == Length)
DirBufferResult = NtStatusFromWin32(GetLastError());
else if (Length + 1 + PatternLength >= FULLPATH_SIZE)
DirBufferResult = STATUS_OBJECT_NAME_INVALID;
if (!NT_SUCCESS(DirBufferResult))
{
ReleaseDirectoryBuffer(&FileDesc->DirBuffer);
return DirBufferResult;
}
if (L'\\' != FullPath[Length - 1])
FullPath[Length++] = L'\\';
memcpy(FullPath + Length, Pattern, PatternLength * sizeof(WCHAR));
FullPath[Length + PatternLength] = L'\0';
FindHandle = FindFirstFileW(FullPath, &FindData);
if (INVALID_HANDLE_VALUE != FindHandle)
{
do
{
memset(DirInfo, 0, sizeof *DirInfo);
Length = (ULONG)wcslen(FindData.cFileName);
DirInfo->Size = (UINT16)(FIELD_OFFSET(FSP_FSCTL_DIR_INFO, FileNameBuf) + Length * sizeof(WCHAR));
DirInfo->FileInfo.FileAttributes = FindData.dwFileAttributes;
DirInfo->FileInfo.ReparseTag = 0;
DirInfo->FileInfo.FileSize =
((UINT64)FindData.nFileSizeHigh << 32) | (UINT64)FindData.nFileSizeLow;
DirInfo->FileInfo.AllocationSize = (DirInfo->FileInfo.FileSize + ALLOCATION_UNIT - 1)
/ ALLOCATION_UNIT * ALLOCATION_UNIT;
DirInfo->FileInfo.CreationTime = ((PLARGE_INTEGER)&FindData.ftCreationTime)->QuadPart;
DirInfo->FileInfo.LastAccessTime = ((PLARGE_INTEGER)&FindData.ftLastAccessTime)->QuadPart;
DirInfo->FileInfo.LastWriteTime = ((PLARGE_INTEGER)&FindData.ftLastWriteTime)->QuadPart;
DirInfo->FileInfo.ChangeTime = DirInfo->FileInfo.LastWriteTime;
DirInfo->FileInfo.IndexNumber = 0;
DirInfo->FileInfo.HardLinks = 0;
memcpy(DirInfo->FileNameBuf, FindData.cFileName, Length * sizeof(WCHAR));
if (!FillDirectoryBuffer(&FileDesc->DirBuffer, DirInfo, &DirBufferResult))
break;
} while (FindNextFileW(FindHandle, &FindData));
FindClose(FindHandle);
}
ReleaseDirectoryBuffer(&FileDesc->DirBuffer);
}
if (!NT_SUCCESS(DirBufferResult))
return DirBufferResult;
ReadDirectoryBuffer(&FileDesc->DirBuffer,
Marker, Buffer, BufferLength, PBytesTransferred);
return STATUS_SUCCESS;
}
static NTSTATUS EnableBackupRestorePrivileges(VOID)
{
union
{
TOKEN_PRIVILEGES P;
UINT8 B[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
} Privileges;
HANDLE Token;
Privileges.P.PrivilegeCount = 2;
Privileges.P.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
Privileges.P.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
if (!LookupPrivilegeValueW(0, SE_BACKUP_NAME, &Privileges.P.Privileges[0].Luid) ||
!LookupPrivilegeValueW(0, SE_RESTORE_NAME, &Privileges.P.Privileges[1].Luid))
return NtStatusFromWin32(GetLastError());
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &Token))
return NtStatusFromWin32(GetLastError());
if (!AdjustTokenPrivileges(Token, FALSE, &Privileges.P, 0, 0, 0))
{
CloseHandle(Token);
return NtStatusFromWin32(GetLastError());
}
CloseHandle(Token);
return STATUS_SUCCESS;
}
static ULONG wcstol_deflt(wchar_t *w, ULONG deflt)
{
wchar_t *endp;
ULONG ul = wcstol(w, &endp, 0);
return L'\0' != w[0] && L'\0' == *endp ? ul : deflt;
}
NTSTATUS PTFS_SERVICE::OnStart(ULONG argc, PWSTR *argv)
{
wchar_t **argp, **arge;
PWSTR DebugLogFile = 0;
ULONG DebugFlags = 0;
PWSTR VolumePrefix = 0;
PWSTR PassThrough = 0;
PWSTR MountPoint = 0;
HANDLE DebugLogHandle = INVALID_HANDLE_VALUE;
WCHAR PassThroughBuf[MAX_PATH];
PTFS *Ptfs = 0;
NTSTATUS Result;
for (argp = argv + 1, arge = argv + argc; arge > argp; argp++)
{
if (L'-' != argp[0][0])
break;
switch (argp[0][1])
{
case L'?':
goto usage;
case L'd':
argtol(DebugFlags);
break;
case L'D':
argtos(DebugLogFile);
break;
case L'm':
argtos(MountPoint);
break;
case L'p':
argtos(PassThrough);
break;
case L'u':
argtos(VolumePrefix);
break;
default:
goto usage;
}
}
if (arge > argp)
goto usage;
if (0 == PassThrough && 0 != VolumePrefix)
{
PWSTR P;
P = wcschr(VolumePrefix, L'\\');
if (0 != P && L'\\' != P[1])
{
P = wcschr(P + 1, L'\\');
if (0 != P &&
(
(L'A' <= P[1] && P[1] <= L'Z') ||
(L'a' <= P[1] && P[1] <= L'z')
) &&
L'$' == P[2])
{
StringCbPrintf(PassThroughBuf, sizeof PassThroughBuf, L"%c:%s", P[1], P + 3);
PassThrough = PassThroughBuf;
}
}
}
if (0 == PassThrough || 0 == MountPoint)
goto usage;
EnableBackupRestorePrivileges();
if (0 != DebugLogFile)
{
if (0 == wcscmp(L"-", DebugLogFile))
DebugLogHandle = GetStdHandle(STD_ERROR_HANDLE);
else
DebugLogHandle = CreateFileW(
DebugLogFile,
FILE_APPEND_DATA,
FILE_SHARE_READ | FILE_SHARE_WRITE,
0,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0);
if (INVALID_HANDLE_VALUE == DebugLogHandle)
{
fail(L"cannot open debug log file");
goto usage;
}
FspDebugLogSetHandle(DebugLogHandle);
}
Ptfs = new PTFS;
Ptfs->SetPrefix(VolumePrefix);
Result = Ptfs->SetPath(PassThrough);
if (!NT_SUCCESS(Result))
{
fail(L"cannot create file system");
goto exit;
}
Result = Ptfs->Mount(MountPoint, 0, FALSE, DebugFlags);
if (!NT_SUCCESS(Result))
{
fail(L"cannot mount file system");
goto exit;
}
MountPoint = Ptfs->MountPoint();
info(L"%s%s%s -p %s -m %s",
L"" PROGNAME,
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? L" -u " : L"",
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? VolumePrefix : L"",
PassThrough,
MountPoint);
_Ptfs = Ptfs;
Result = STATUS_SUCCESS;
exit:
if (!NT_SUCCESS(Result) && 0 != Ptfs)
delete Ptfs;
return Result;
usage:
static wchar_t usage[] = L""
"usage: %s OPTIONS\n"
"\n"
"options:\n"
" -d DebugFlags [-1: enable all debug logs]\n"
" -D DebugLogFile [file path; use - for stderr]\n"
" -u \\Server\\Share [UNC prefix (single backslash)]\n"
" -p Directory [directory to expose as pass through file system]\n"
" -m MountPoint [X:|*|directory]\n";
fail(usage, L"" PROGNAME);
return STATUS_UNSUCCESSFUL;
#undef argtos
#undef argtol
}
#endif