mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-31 12:08:41 -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_SECURITY_NAME, 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);
 | |
| }
 |