mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -05:00
launcher: SvcInstance implementation
This commit is contained in:
parent
dc4109fc22
commit
457e151fa5
@ -175,6 +175,9 @@
|
|||||||
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
|
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\..\src\shared\minimal.h" />
|
||||||
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
<ImportGroup Label="ExtensionTargets">
|
<ImportGroup Label="ExtensionTargets">
|
||||||
</ImportGroup>
|
</ImportGroup>
|
||||||
|
@ -5,10 +5,21 @@
|
|||||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Include">
|
||||||
|
<UniqueIdentifier>{11e7c0f2-7782-43ee-84fa-9e56efbe39de}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
|
<Filter Include="Include\shared">
|
||||||
|
<UniqueIdentifier>{d83ea433-d9f7-494c-90b9-3a8997483cd9}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="..\..\..\src\launcher\launcher.c">
|
<ClCompile Include="..\..\..\src\launcher\launcher.c">
|
||||||
<Filter>Source</Filter>
|
<Filter>Source</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ClInclude Include="..\..\..\src\shared\minimal.h">
|
||||||
|
<Filter>Include\shared</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -16,21 +16,289 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <winfsp/winfsp.h>
|
#include <winfsp/winfsp.h>
|
||||||
|
#include <shared/minimal.h>
|
||||||
|
#include <sddl.h>
|
||||||
|
|
||||||
#define PROGNAME "winfsp-launcher"
|
#define PROGNAME "WinFsp-Launcher"
|
||||||
|
#define REGKEY "SYSTEM\\CurrentControlSet\\Services\\" PROGNAME "\\Services"
|
||||||
|
|
||||||
NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
HANDLE ProcessHeap;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
{
|
{
|
||||||
|
PWSTR ClassName;
|
||||||
|
PWSTR InstanceName;
|
||||||
|
PWSTR CommandLine;
|
||||||
|
DWORD ProcessId;
|
||||||
|
HANDLE Process;
|
||||||
|
HANDLE ProcessWait;
|
||||||
|
LIST_ENTRY ListEntry;
|
||||||
|
WCHAR Buffer[];
|
||||||
|
} SVC_INSTANCE;
|
||||||
|
|
||||||
|
static CRITICAL_SECTION SvcInstanceLock;
|
||||||
|
static LIST_ENTRY SvcInstanceList = { &SvcInstanceList, &SvcInstanceList };
|
||||||
|
|
||||||
|
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Fired);
|
||||||
|
|
||||||
|
static SVC_INSTANCE *SvcInstanceFromName(PWSTR InstanceName)
|
||||||
|
{
|
||||||
|
SVC_INSTANCE *SvcInstance;
|
||||||
|
PLIST_ENTRY ListEntry;
|
||||||
|
|
||||||
|
for (ListEntry = SvcInstanceList.Flink;
|
||||||
|
&SvcInstanceList != ListEntry;
|
||||||
|
ListEntry = ListEntry->Flink)
|
||||||
|
{
|
||||||
|
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
|
||||||
|
|
||||||
|
if (0 == lstrcmpW(InstanceName, SvcInstance->InstanceName))
|
||||||
|
return SvcInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ULONG SvcInstanceArgumentLength(PWSTR Arg)
|
||||||
|
{
|
||||||
|
ULONG Length;
|
||||||
|
|
||||||
|
Length = 2; /* for beginning and ending quotes */
|
||||||
|
for (PWSTR P = Arg; *P; P++)
|
||||||
|
if (L'"' != *P)
|
||||||
|
Length++;
|
||||||
|
|
||||||
|
return Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PWSTR SvcInstanceArgumentCopy(PWSTR Dest, PWSTR Arg)
|
||||||
|
{
|
||||||
|
*Dest++ = L'"';
|
||||||
|
for (PWSTR P = Arg; *P; P++)
|
||||||
|
if (L'"' != *P)
|
||||||
|
*Dest++ = *P;
|
||||||
|
*Dest++ = L'"';
|
||||||
|
|
||||||
|
return Dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Argv,
|
||||||
|
PWSTR *PNewString)
|
||||||
|
{
|
||||||
|
PWSTR NewString = 0;
|
||||||
|
ULONG Length;
|
||||||
|
|
||||||
|
*PNewString = 0;
|
||||||
|
|
||||||
|
Length = 0;
|
||||||
|
for (PWSTR P = String; *P; P++)
|
||||||
|
{
|
||||||
|
switch (*P)
|
||||||
|
{
|
||||||
|
case L'%':
|
||||||
|
P++;
|
||||||
|
if (L'0' <= *P && *P <= '9' && Argc > (ULONG)(*P - L'0'))
|
||||||
|
Length += SvcInstanceArgumentLength(Argv[*P - L'0']);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Length++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NewString = MemAlloc((Length + 1) * sizeof(WCHAR));
|
||||||
|
if (0 == NewString)
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
|
||||||
|
*PNewString = NewString;
|
||||||
|
for (PWSTR P = String, Q = NewString; *P; P++)
|
||||||
|
{
|
||||||
|
switch (*P)
|
||||||
|
{
|
||||||
|
case L'%':
|
||||||
|
P++;
|
||||||
|
if (L'0' <= *P && *P <= '9' && Argc > (ULONG)(*P - L'0'))
|
||||||
|
Q = SvcInstanceArgumentCopy(Q, Argv[*P - L'0']);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Q++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS SvcStop(FSP_SERVICE *Service)
|
NTSTATUS SvcInstanceCreate(PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv,
|
||||||
|
SVC_INSTANCE **PSvcInstance)
|
||||||
{
|
{
|
||||||
|
SVC_INSTANCE *SvcInstance = 0;
|
||||||
|
HKEY RegKey = 0;
|
||||||
|
DWORD RegResult, RegSize;
|
||||||
|
DWORD ClassNameSize, InstanceNameSize;
|
||||||
|
WCHAR Executable[MAX_PATH], CommandLine[512];
|
||||||
|
STARTUPINFOW StartupInfo;
|
||||||
|
PROCESS_INFORMATION ProcessInfo;
|
||||||
|
NTSTATUS Result;
|
||||||
|
|
||||||
|
*PSvcInstance = 0;
|
||||||
|
|
||||||
|
EnterCriticalSection(&SvcInstanceLock);
|
||||||
|
|
||||||
|
if (0 != SvcInstanceFromName(InstanceName))
|
||||||
|
{
|
||||||
|
Result = STATUS_OBJECT_NAME_COLLISION;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" REGKEY, 0, KEY_READ, &RegKey);
|
||||||
|
if (ERROR_SUCCESS != RegResult)
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(RegResult);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegSize = sizeof Executable;
|
||||||
|
RegResult = RegGetValueW(RegKey, ClassName, L"Executable", RRF_RT_REG_SZ, 0,
|
||||||
|
&Executable, &RegSize);
|
||||||
|
if (ERROR_SUCCESS != RegResult)
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(RegResult);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegSize = sizeof CommandLine;
|
||||||
|
RegResult = RegGetValueW(RegKey, ClassName, L"CommandLine", RRF_RT_REG_SZ, 0,
|
||||||
|
&CommandLine, &RegSize);
|
||||||
|
if (ERROR_SUCCESS != RegResult)
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(RegResult);
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegCloseKey(RegKey);
|
||||||
|
RegKey = 0;
|
||||||
|
|
||||||
|
ClassNameSize = (lstrlenW(ClassName) + 1) * sizeof(WCHAR);
|
||||||
|
InstanceNameSize = (lstrlenW(InstanceName) + 1) * sizeof(WCHAR);
|
||||||
|
|
||||||
|
SvcInstance = MemAlloc(sizeof *SvcInstance + ClassNameSize + InstanceNameSize);
|
||||||
|
if (0 == SvcInstance)
|
||||||
|
{
|
||||||
|
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(SvcInstance, 0, sizeof *SvcInstance);
|
||||||
|
memcpy(SvcInstance->Buffer, ClassName, ClassNameSize);
|
||||||
|
memcpy(SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR), InstanceName, InstanceNameSize);
|
||||||
|
SvcInstance->ClassName = SvcInstance->Buffer;
|
||||||
|
SvcInstance->InstanceName = SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR);
|
||||||
|
|
||||||
|
Result = SvcInstanceReplaceArguments(CommandLine, Argc, Argv, &SvcInstance->CommandLine);
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
memset(&StartupInfo, 0, sizeof StartupInfo);
|
||||||
|
StartupInfo.cb = sizeof StartupInfo;
|
||||||
|
if (!CreateProcessW(0, SvcInstance->CommandLine, 0, 0, FALSE, CREATE_NEW_PROCESS_GROUP, 0, 0,
|
||||||
|
&StartupInfo, &ProcessInfo))
|
||||||
|
{
|
||||||
|
Result = FspNtStatusFromWin32(GetLastError());
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(ProcessInfo.hThread);
|
||||||
|
SvcInstance->ProcessId = ProcessInfo.dwProcessId;
|
||||||
|
SvcInstance->Process = ProcessInfo.hProcess;
|
||||||
|
|
||||||
|
if (!RegisterWaitForSingleObject(&SvcInstance->ProcessWait, SvcInstance->Process,
|
||||||
|
SvcInstanceTerminated, SvcInstance, INFINITE, WT_EXECUTEONLYONCE))
|
||||||
|
{
|
||||||
|
/* we have no way when the new process will terminate so go ahead and close its handle */
|
||||||
|
FspServiceLog(EVENTLOG_WARNING_TYPE,
|
||||||
|
L"RegisterWaitForSingleObject = %ld", GetLastError());
|
||||||
|
CloseHandle(SvcInstance->Process);
|
||||||
|
SvcInstance->Process = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
InsertTailList(&SvcInstanceList, &SvcInstance->ListEntry);
|
||||||
|
|
||||||
|
*PSvcInstance = SvcInstance;
|
||||||
|
|
||||||
|
Result = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
if (!NT_SUCCESS(Result))
|
||||||
|
{
|
||||||
|
MemFree(SvcInstance->CommandLine);
|
||||||
|
MemFree(SvcInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 != RegKey)
|
||||||
|
RegCloseKey(RegKey);
|
||||||
|
|
||||||
|
LeaveCriticalSection(&SvcInstanceLock);
|
||||||
|
|
||||||
|
return Result;
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SvcInstanceDelete(SVC_INSTANCE *SvcInstance)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&SvcInstanceLock);
|
||||||
|
RemoveEntryList(&SvcInstance->ListEntry);
|
||||||
|
LeaveCriticalSection(&SvcInstanceLock);
|
||||||
|
|
||||||
|
if (0 != SvcInstance->ProcessWait)
|
||||||
|
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
||||||
|
if (0 != SvcInstance->Process)
|
||||||
|
CloseHandle(SvcInstance->Process);
|
||||||
|
MemFree(SvcInstance->CommandLine);
|
||||||
|
MemFree(SvcInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Fired)
|
||||||
|
{
|
||||||
|
SVC_INSTANCE *SvcInstance = Context;
|
||||||
|
|
||||||
|
SvcInstanceDelete(SvcInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS SvcInstanceStart(PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv)
|
||||||
|
{
|
||||||
|
SVC_INSTANCE *SvcInstance;
|
||||||
|
|
||||||
|
return SvcInstanceCreate(ClassName, InstanceName, Argc, Argv, &SvcInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
VOID SvcInstanceStop(PWSTR InstanceName)
|
||||||
|
{
|
||||||
|
SVC_INSTANCE *SvcInstance;
|
||||||
|
|
||||||
|
EnterCriticalSection(&SvcInstanceLock);
|
||||||
|
SvcInstance = SvcInstanceFromName(InstanceName);
|
||||||
|
if (0 != SvcInstance)
|
||||||
|
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, SvcInstance->ProcessId);
|
||||||
|
LeaveCriticalSection(&SvcInstanceLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||||
|
{
|
||||||
|
InitializeCriticalSection(&SvcInstanceLock);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NTSTATUS SvcStop(FSP_SERVICE *Service)
|
||||||
|
{
|
||||||
|
DeleteCriticalSection(&SvcInstanceLock);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wmain(int argc, wchar_t **argv)
|
int wmain(int argc, wchar_t **argv)
|
||||||
{
|
{
|
||||||
|
ProcessHeap = GetProcessHeap();
|
||||||
|
if (0 == ProcessHeap)
|
||||||
|
return GetLastError();
|
||||||
return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0);
|
return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user