mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -05:00
287 lines
8.0 KiB
C
287 lines
8.0 KiB
C
/**
|
|
* @file ptfs-main.c
|
|
*
|
|
* @copyright 2015-2022 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 software
|
|
* in accordance with the commercial license agreement provided in
|
|
* conjunction with the software. The terms and conditions of any such
|
|
* commercial license agreement shall govern, supersede, and render
|
|
* ineffective any application of the GPLv3 license to this software,
|
|
* notwithstanding of any reference thereto in the software or
|
|
* associated repository.
|
|
*/
|
|
|
|
#include "ptfs.h"
|
|
|
|
static NTSTATUS EnablePrivileges(PWSTR PrivilegeName, ...)
|
|
{
|
|
va_list ap;
|
|
HANDLE Token = 0;
|
|
TOKEN_PRIVILEGES Privileges;
|
|
WCHAR WarnNames[1024], *WarnNameP = WarnNames;
|
|
NTSTATUS Result;
|
|
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &Token))
|
|
{
|
|
Result = FspNtStatusFromWin32(GetLastError());
|
|
goto exit;
|
|
}
|
|
|
|
va_start(ap, PrivilegeName);
|
|
for (PWSTR Name = PrivilegeName; 0 != Name; Name = va_arg(ap, PWSTR))
|
|
{
|
|
Privileges.PrivilegeCount = 1;
|
|
Privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
|
|
if (!LookupPrivilegeValueW(0, Name, &Privileges.Privileges[0].Luid) ||
|
|
!AdjustTokenPrivileges(Token, FALSE, &Privileges, 0, 0, 0))
|
|
{
|
|
Result = FspNtStatusFromWin32(GetLastError());
|
|
goto exit;
|
|
}
|
|
|
|
if (ERROR_NOT_ALL_ASSIGNED == GetLastError())
|
|
{
|
|
*WarnNameP++ = ' ';
|
|
size_t len = wcslen(Name);
|
|
memcpy(WarnNameP, Name, len * sizeof(WCHAR));
|
|
WarnNameP += len;
|
|
*WarnNameP = '\0';
|
|
}
|
|
}
|
|
va_end(ap);
|
|
|
|
if (WarnNames != WarnNameP)
|
|
warn(L"cannot enable privileges:%s", WarnNames);
|
|
|
|
Result = STATUS_SUCCESS;
|
|
|
|
exit:
|
|
if (0 != Token)
|
|
CloseHandle(Token);
|
|
|
|
return Result;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
|
{
|
|
#define argtos(v) if (arge > ++argp) v = *argp; else goto usage
|
|
#define argtol(v) if (arge > ++argp) v = wcstol_deflt(*argp, v); else goto usage
|
|
|
|
wchar_t **argp, **arge;
|
|
PWSTR RootPath = 0;
|
|
ULONG FileInfoTimeout = INFINITE;
|
|
ULONG FsAttributeMask = 0;
|
|
PWSTR VolumePrefix = 0;
|
|
PWSTR MountPoint = 0;
|
|
PWSTR OptionString = 0;
|
|
PWSTR DebugLogFile = 0;
|
|
ULONG DebugFlags = 0;
|
|
HANDLE DebugLogHandle = INVALID_HANDLE_VALUE;
|
|
WCHAR RootPathBuf[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'o':
|
|
argtos(OptionString);
|
|
if (0 == _wcsicmp(L"ExtraFeatures", OptionString))
|
|
FsAttributeMask |=
|
|
PtfsReparsePoints |
|
|
PtfsNamedStreams |
|
|
PtfsExtendedAttributes |
|
|
PtfsWslFeatures;
|
|
else if (0 == _wcsicmp(L"ReparsePoints", OptionString))
|
|
FsAttributeMask |= PtfsReparsePoints;
|
|
else if (0 == _wcsicmp(L"NamedStreams", OptionString))
|
|
FsAttributeMask |= PtfsNamedStreams;
|
|
else if (0 == _wcsicmp(L"ExtendedAttributes", OptionString))
|
|
FsAttributeMask |= PtfsExtendedAttributes;
|
|
else if (0 == _wcsicmp(L"WslFeatures", OptionString))
|
|
FsAttributeMask |= PtfsWslFeatures;
|
|
else if (0 == _wcsicmp(L"FlushAndPurgeOnCleanup", OptionString))
|
|
FsAttributeMask |= PtfsFlushAndPurgeOnCleanup;
|
|
else if (0 == _wcsicmp(L"SetAllocationSizeOnCleanup", OptionString))
|
|
FsAttributeMask |= PtfsSetAllocationSizeOnCleanup;
|
|
else
|
|
goto usage;
|
|
break;
|
|
case L'p':
|
|
argtos(RootPath);
|
|
break;
|
|
case L't':
|
|
argtol(FileInfoTimeout);
|
|
break;
|
|
case L'u':
|
|
argtos(VolumePrefix);
|
|
break;
|
|
default:
|
|
goto usage;
|
|
}
|
|
}
|
|
|
|
if (arge > argp)
|
|
goto usage;
|
|
|
|
if (0 == RootPath && 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(RootPathBuf, sizeof RootPathBuf, L"%c:%s", P[1], P + 3);
|
|
RootPath = RootPathBuf;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (0 == RootPath || 0 == MountPoint)
|
|
goto usage;
|
|
|
|
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);
|
|
}
|
|
|
|
EnablePrivileges(SE_BACKUP_NAME, SE_RESTORE_NAME, SE_CREATE_SYMBOLIC_LINK_NAME, 0);
|
|
|
|
Result = PtfsCreate(
|
|
RootPath,
|
|
FileInfoTimeout,
|
|
FsAttributeMask,
|
|
VolumePrefix,
|
|
MountPoint,
|
|
DebugFlags,
|
|
&Ptfs);
|
|
if (!NT_SUCCESS(Result))
|
|
{
|
|
fail(L"cannot create file system");
|
|
goto exit;
|
|
}
|
|
|
|
Result = FspFileSystemStartDispatcher(Ptfs->FileSystem, 0);
|
|
if (!NT_SUCCESS(Result))
|
|
{
|
|
fail(L"cannot start file system");
|
|
goto exit;
|
|
}
|
|
|
|
MountPoint = FspFileSystemMountPoint(Ptfs->FileSystem);
|
|
|
|
info(L"%s -t %ld%s%s -p %s -m %s",
|
|
L"" PROGNAME,
|
|
FileInfoTimeout,
|
|
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? L" -u " : L"",
|
|
0 != VolumePrefix && L'\0' != VolumePrefix[0] ? VolumePrefix : L"",
|
|
RootPath,
|
|
MountPoint);
|
|
|
|
Service->UserContext = Ptfs;
|
|
Result = STATUS_SUCCESS;
|
|
|
|
exit:
|
|
if (!NT_SUCCESS(Result) && 0 != Ptfs)
|
|
PtfsDelete(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"
|
|
" -t FileInfoTimeout [millis]\n"
|
|
" -o ExtraFeatures [extra Windows file system features]\n"
|
|
" -o ReparsePoints\n"
|
|
" -o NamedStreams\n"
|
|
" -o ExtendedAttributes\n"
|
|
" -o WslFeatures\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
|
|
}
|
|
|
|
static NTSTATUS SvcStop(FSP_SERVICE *Service)
|
|
{
|
|
PTFS *Ptfs = Service->UserContext;
|
|
|
|
FspFileSystemStopDispatcher(Ptfs->FileSystem);
|
|
PtfsDelete(Ptfs);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
int wmain(int argc, wchar_t **argv)
|
|
{
|
|
if (!NT_SUCCESS(FspLoad(0)))
|
|
return ERROR_DELAY_LOAD_FAILED;
|
|
|
|
return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0);
|
|
}
|