From ac26bde9ee2b1d2d4247b7f9ecec5a05b14937ed Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Thu, 17 Dec 2020 15:20:02 -0800 Subject: [PATCH] tst: notifyfs: add file system to demo file notification mechanism --- tst/notifyfs/.gitignore | 8 + tst/notifyfs/notifyfs.c | 520 ++++++++++++++++++++++++++ tst/notifyfs/notifyfs.sln | 31 ++ tst/notifyfs/notifyfs.vcxproj | 175 +++++++++ tst/notifyfs/notifyfs.vcxproj.filters | 14 + 5 files changed, 748 insertions(+) create mode 100644 tst/notifyfs/.gitignore create mode 100644 tst/notifyfs/notifyfs.c create mode 100644 tst/notifyfs/notifyfs.sln create mode 100644 tst/notifyfs/notifyfs.vcxproj create mode 100644 tst/notifyfs/notifyfs.vcxproj.filters diff --git a/tst/notifyfs/.gitignore b/tst/notifyfs/.gitignore new file mode 100644 index 00000000..1f4596af --- /dev/null +++ b/tst/notifyfs/.gitignore @@ -0,0 +1,8 @@ +build +*.ncb +*.suo +*.vcproj.* +*.vcxproj.user +*.VC.db +*.VC.opendb +.vs diff --git a/tst/notifyfs/notifyfs.c b/tst/notifyfs/notifyfs.c new file mode 100644 index 00000000..19243e53 --- /dev/null +++ b/tst/notifyfs/notifyfs.c @@ -0,0 +1,520 @@ +/** + * @file notifyfs.c + * + * @copyright 2015-2020 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 +#include + +#define DEBUGFLAGS 0 +//#define DEBUGFLAGS -1 + +#define PROGNAME "notifyfs" +#define ALLOCATION_UNIT 4096 + +#define info(format, ...) FspServiceLog(EVENTLOG_INFORMATION_TYPE, format, __VA_ARGS__) +#define warn(format, ...) FspServiceLog(EVENTLOG_WARNING_TYPE, format, __VA_ARGS__) +#define fail(format, ...) FspServiceLog(EVENTLOG_ERROR_TYPE, format, __VA_ARGS__) + +typedef struct +{ + FSP_FILE_SYSTEM *FileSystem; + PTP_TIMER Timer; + UINT32 Ticks; +} NOTIFYFS; + +static PSECURITY_DESCRIPTOR DefaultSecurity; +static ULONG DefaultSecuritySize; + +static UINT32 CountFromTicks(UINT32 Ticks) +{ + /* + * The formula below produces the periodic sequence: + * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + * 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, + * ... + */ + UINT32 div10 = (Ticks % 20) / 10; + UINT32 mod10 = Ticks % 10; + UINT32 mdv10 = 1 - div10; + UINT32 mmd10 = 10 - mod10; + return mdv10 * mod10 + div10 * mmd10; +} + +static UINT32 FileCount(NOTIFYFS *Notifyfs) +{ + UINT32 Ticks = InterlockedOr(&Notifyfs->Ticks, 0); + return CountFromTicks(Ticks); +} + +static UINT32 FileLookup(NOTIFYFS *Notifyfs, PWSTR FileName) +{ + FileName++; + PWSTR Endp; + UINT32 Count = FileCount(Notifyfs); + UINT32 Index = wcstoul(FileName, &Endp, 10); + if ('\0' != *Endp || (FileName != Endp && (0 == Index || Index > Count))) + return -1; /* not found */ + if (FileName == Endp) + return 0; /* root */ + return Index; /* regular file named 1, 2, ..., Count */ +} + +static UINT32 FileContents(UINT32 Index, WCHAR P[32]) +{ + WCHAR Buffer[32]; + if (0 == P) + P = Buffer; + if (0 == Index) + P[0] = '\0'; + else + wsprintfW(P, L"%u\n", (unsigned)Index); + return lstrlenW(P); +} + +static VOID FillFileInfo(UINT32 Index, FSP_FSCTL_FILE_INFO *FileInfo) +{ + FILETIME SystemTime; + + GetSystemTimeAsFileTime(&SystemTime); + + memset(FileInfo, 0, sizeof FileInfo); + FileInfo->FileAttributes = 0 == Index ? FILE_ATTRIBUTE_DIRECTORY : 0; + FileInfo->FileSize = FileContents(Index, 0); + FileInfo->AllocationSize = (FileInfo->FileSize + ALLOCATION_UNIT - 1) + / ALLOCATION_UNIT * ALLOCATION_UNIT; + FileInfo->CreationTime = + FileInfo->LastAccessTime = + FileInfo->LastWriteTime = + FileInfo->ChangeTime = *(PUINT64)&SystemTime; +} + +static BOOLEAN AddDirInfo(PWSTR FileName, UINT32 Index, + PVOID Buffer, ULONG Length, PULONG PBytesTransferred) +{ + 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; + + memset(DirInfo->Padding, 0, sizeof DirInfo->Padding); + if (0 != FileName) + lstrcpyW(DirInfo->FileNameBuf, FileName); + else + wsprintfW(DirInfo->FileNameBuf, L"%u", (unsigned)Index); + DirInfo->Size = (UINT16)(sizeof(FSP_FSCTL_DIR_INFO) + wcslen(DirInfo->FileNameBuf) * sizeof(WCHAR)); + FillFileInfo(Index, &DirInfo->FileInfo); + + return FspFileSystemAddDirInfo(DirInfo, Buffer, Length, PBytesTransferred); +} + +static NTSTATUS GetVolumeInfo(FSP_FILE_SYSTEM *FileSystem, + FSP_FSCTL_VOLUME_INFO *VolumeInfo) +{ + memset(VolumeInfo, 0, sizeof *VolumeInfo); + + return STATUS_SUCCESS; +} + +static NTSTATUS GetSecurityByName(FSP_FILE_SYSTEM *FileSystem, + PWSTR FileName, PUINT32 PFileAttributes, + PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize) +{ + NOTIFYFS *Notifyfs = (NOTIFYFS *)FileSystem->UserContext; + UINT32 Index; + + Index = FileLookup(Notifyfs, FileName); + if (-1 == Index) + return STATUS_OBJECT_NAME_NOT_FOUND; + + if (0 != PFileAttributes) + *PFileAttributes = 0 == Index ? FILE_ATTRIBUTE_DIRECTORY : 0; + + if (0 != PSecurityDescriptorSize) + { + if (DefaultSecuritySize > *PSecurityDescriptorSize) + { + *PSecurityDescriptorSize = DefaultSecuritySize; + return STATUS_BUFFER_OVERFLOW; + } + + *PSecurityDescriptorSize = DefaultSecuritySize; + if (0 != SecurityDescriptor) + memcpy(SecurityDescriptor, DefaultSecurity, DefaultSecuritySize); + } + + return STATUS_SUCCESS; +} + +static NTSTATUS Create(FSP_FILE_SYSTEM *FileSystem, + PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess, + UINT32 FileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, UINT64 AllocationSize, + PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo) +{ + return STATUS_INVALID_DEVICE_REQUEST; +} + +static NTSTATUS Open(FSP_FILE_SYSTEM *FileSystem, + PWSTR FileName, UINT32 CreateOptions, UINT32 GrantedAccess, + PVOID *PFileContext, FSP_FSCTL_FILE_INFO *FileInfo) +{ + NOTIFYFS *Notifyfs = (NOTIFYFS *)FileSystem->UserContext; + FSP_FSCTL_TRANSACT_FULL_CONTEXT *FullContext = (PVOID)PFileContext; + UINT32 Index; + + Index = FileLookup(Notifyfs, FileName); + if (-1 == Index) + return STATUS_OBJECT_NAME_NOT_FOUND; + + FullContext->UserContext = Index; + FullContext->UserContext2 = 0; + + FillFileInfo(Index, FileInfo); + + return STATUS_SUCCESS; +} + +static NTSTATUS Overwrite(FSP_FILE_SYSTEM *FileSystem, + PVOID FileContext, UINT32 FileAttributes, BOOLEAN ReplaceFileAttributes, UINT64 AllocationSize, + FSP_FSCTL_FILE_INFO *FileInfo) +{ + return STATUS_INVALID_DEVICE_REQUEST; +} + +static NTSTATUS Read(FSP_FILE_SYSTEM *FileSystem, + PVOID FileContext, PVOID Buffer, UINT64 Offset, ULONG Length, + PULONG PBytesTransferred) +{ + NOTIFYFS *Notifyfs = (NOTIFYFS *)FileSystem->UserContext; + FSP_FSCTL_TRANSACT_FULL_CONTEXT *FullContext = FileContext; + UINT32 Index = (UINT32)FullContext->UserContext; + UINT64 EndOffset; + WCHAR ContentBuf[32]; + UINT32 ContentLen; + + ContentLen = FileContents(Index, ContentBuf); + + if (Offset >= ContentLen) + return STATUS_END_OF_FILE; + + EndOffset = Offset + Length; + if (EndOffset > ContentLen) + EndOffset = ContentLen; + + memcpy(Buffer, (PUINT8)ContentBuf + Offset, (size_t)(EndOffset - Offset)); + + *PBytesTransferred = (ULONG)(EndOffset - Offset); + + return STATUS_SUCCESS; +} + +static NTSTATUS GetFileInfo(FSP_FILE_SYSTEM *FileSystem, + PVOID FileContext, + FSP_FSCTL_FILE_INFO *FileInfo) +{ + NOTIFYFS *Notifyfs = (NOTIFYFS *)FileSystem->UserContext; + FSP_FSCTL_TRANSACT_FULL_CONTEXT *FullContext = FileContext; + UINT32 Index = (UINT32)FullContext->UserContext; + + FillFileInfo(Index, FileInfo); + + return STATUS_SUCCESS; +} + +static NTSTATUS ReadDirectory(FSP_FILE_SYSTEM *FileSystem, + PVOID FileContext, PWSTR Pattern, PWSTR Marker, + PVOID Buffer, ULONG Length, PULONG PBytesTransferred) +{ + NOTIFYFS *Notifyfs = (NOTIFYFS *)FileSystem->UserContext; + UINT32 Count = FileCount(Notifyfs); + UINT32 Index; + + if (0 == Marker) + { + if (!AddDirInfo(L".", 0, Buffer, Length, PBytesTransferred)) + return STATUS_SUCCESS; + } + if (0 == Marker || (L'.' == Marker[0] && L'\0' == Marker[1])) + { + if (!AddDirInfo(L"..", 0, Buffer, Length, PBytesTransferred)) + return STATUS_SUCCESS; + Marker = 0; + } + + Index = 0 == Marker ? 1 : wcstoul(Marker, 0, 10) + 1; + for (; Count >= Index; Index++) + if (!AddDirInfo(0, Index, Buffer, Length, PBytesTransferred)) + break; + FspFileSystemAddDirInfo(0, Buffer, Length, PBytesTransferred); + + return STATUS_SUCCESS; +} + +static FSP_FILE_SYSTEM_INTERFACE NotifyfsInterface = +{ + .GetVolumeInfo = GetVolumeInfo, + .GetSecurityByName = GetSecurityByName, + .Create = Create, + .Open = Open, + .Overwrite = Overwrite, + .Read = Read, + .GetFileInfo = GetFileInfo, + .ReadDirectory = ReadDirectory, +}; + +static VOID CALLBACK NotifyfsTick(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_TIMER Timer) +{ + NOTIFYFS *Notifyfs = Context; + UINT32 Ticks = InterlockedIncrement(&Notifyfs->Ticks); + UINT32 OldCount = CountFromTicks(Ticks - 1); + UINT32 NewCount = CountFromTicks(Ticks); + union + { + UINT8 B[FIELD_OFFSET(FSP_FSCTL_NOTIFY_INFO, FileNameBuf) + MAX_PATH * sizeof(WCHAR)]; + FSP_FSCTL_NOTIFY_INFO V; + } NotifyInfoBuf; + FSP_FSCTL_NOTIFY_INFO *NotifyInfo = &NotifyInfoBuf.V; + + memset(NotifyInfo, 0, sizeof NotifyInfo); + if (OldCount < NewCount) + { + wsprintfW(NotifyInfo->FileNameBuf, L"\\%u", (unsigned)NewCount); + NotifyInfo->Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + + wcslen(NotifyInfo->FileNameBuf) * sizeof(WCHAR)); + NotifyInfo->Action = FILE_ACTION_ADDED; + NotifyInfo->Filter = FILE_NOTIFY_CHANGE_FILE_NAME; + FspDebugLog("CREATE \\%u\n", (unsigned)NewCount); + } + else if (OldCount > NewCount) + { + wsprintfW(NotifyInfo->FileNameBuf, L"\\%u", (unsigned)OldCount); + NotifyInfo->Size = (UINT16)(sizeof(FSP_FSCTL_NOTIFY_INFO) + + wcslen(NotifyInfo->FileNameBuf) * sizeof(WCHAR)); + NotifyInfo->Action = FILE_ACTION_REMOVED; + NotifyInfo->Filter = FILE_NOTIFY_CHANGE_FILE_NAME; + FspDebugLog("REMOVE \\%u\n", (unsigned)OldCount); + } + + if (OldCount != NewCount) + { + if (STATUS_SUCCESS == FspFileSystemNotifyBegin(Notifyfs->FileSystem, 500)) + { + FspFileSystemNotify(Notifyfs->FileSystem, NotifyInfo, NotifyInfo->Size); + FspFileSystemNotifyEnd(Notifyfs->FileSystem); + } + } +} + +static VOID NotifyfsDelete(NOTIFYFS *Notifyfs); + +static NTSTATUS NotifyfsCreate(PWSTR VolumePrefix, PWSTR MountPoint, NOTIFYFS **PNotifyfs) +{ + FSP_FSCTL_VOLUME_PARAMS VolumeParams; + NOTIFYFS *Notifyfs = 0; + INT64 TimerDue; + NTSTATUS Result; + + *PNotifyfs = 0; + + if (!ConvertStringSecurityDescriptorToSecurityDescriptorW( + L"O:BAG:BAD:P(A;;FA;;;SY)(A;;FA;;;BA)(A;;FA;;;WD)", SDDL_REVISION_1, + &DefaultSecurity, &DefaultSecuritySize)) + { + Result = FspNtStatusFromWin32(GetLastError()); + goto exit; + } + + Notifyfs = malloc(sizeof *Notifyfs); + if (0 == Notifyfs) + { + Result = STATUS_INSUFFICIENT_RESOURCES; + goto exit; + } + memset(Notifyfs, 0, sizeof *Notifyfs); + + memset(&VolumeParams, 0, sizeof VolumeParams); + VolumeParams.SectorSize = ALLOCATION_UNIT; + VolumeParams.SectorsPerAllocationUnit = 1; + VolumeParams.VolumeCreationTime = 0; + VolumeParams.VolumeSerialNumber = 0; + VolumeParams.FileInfoTimeout = 1000; + VolumeParams.CaseSensitiveSearch = 0; + VolumeParams.CasePreservedNames = 1; + VolumeParams.UnicodeOnDisk = 1; + VolumeParams.PersistentAcls = 0; + VolumeParams.PostCleanupWhenModifiedOnly = 1; + VolumeParams.UmFileContextIsFullContext = 1; + if (0 != VolumePrefix) + wcscpy_s(VolumeParams.Prefix, sizeof VolumeParams.Prefix / sizeof(WCHAR), VolumePrefix); + wcscpy_s(VolumeParams.FileSystemName, sizeof VolumeParams.FileSystemName / sizeof(WCHAR), + L"" PROGNAME); + + Result = FspFileSystemCreate( + VolumeParams.Prefix[0] ? L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME, + &VolumeParams, + &NotifyfsInterface, + &Notifyfs->FileSystem); + if (!NT_SUCCESS(Result)) + goto exit; + Notifyfs->FileSystem->UserContext = Notifyfs; + + FspFileSystemSetDebugLog(Notifyfs->FileSystem, DEBUGFLAGS); + + Result = FspFileSystemSetMountPoint(Notifyfs->FileSystem, MountPoint); + if (!NT_SUCCESS(Result)) + goto exit; + + Notifyfs->Timer = CreateThreadpoolTimer(NotifyfsTick, Notifyfs, 0); + if (0 == Notifyfs->Timer) + { + Result = FspNtStatusFromWin32(GetLastError()); + goto exit; + } + + TimerDue = -1000; + SetThreadpoolTimer(Notifyfs->Timer, (PVOID)&TimerDue, 1000, 0); + + Result = STATUS_SUCCESS; + +exit: + if (NT_SUCCESS(Result)) + *PNotifyfs = Notifyfs; + else if (0 != Notifyfs) + NotifyfsDelete(Notifyfs); + + return Result; +} + +static VOID NotifyfsDelete(NOTIFYFS *Notifyfs) +{ + if (0 != Notifyfs->Timer) + { + SetThreadpoolTimer(Notifyfs->Timer, 0, 0, 0); + WaitForThreadpoolTimerCallbacks(Notifyfs->Timer, TRUE); + CloseThreadpoolTimer(Notifyfs->Timer); + } + + if (0 != Notifyfs->FileSystem) + FspFileSystemDelete(Notifyfs->FileSystem); + + free(Notifyfs); +} + +static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) +{ +#define argtos(v) if (arge > ++argp) v = *argp; else goto usage + + wchar_t **argp, **arge; + PWSTR VolumePrefix = 0; + PWSTR MountPoint = 0; + NOTIFYFS *Notifyfs = 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'm': + argtos(MountPoint); + break; + case L'u': + argtos(VolumePrefix); + break; + default: + goto usage; + } + } + + if (arge > argp) + goto usage; + + if (0 == MountPoint) + goto usage; + + FspDebugLogSetHandle(GetStdHandle(STD_ERROR_HANDLE)); + + Result = NotifyfsCreate(VolumePrefix, MountPoint, &Notifyfs); + if (!NT_SUCCESS(Result)) + { + fail(L"cannot create file system"); + goto exit; + } + + Result = FspFileSystemStartDispatcher(Notifyfs->FileSystem, 0); + if (!NT_SUCCESS(Result)) + { + fail(L"cannot start file system"); + goto exit; + } + + MountPoint = FspFileSystemMountPoint(Notifyfs->FileSystem); + + info(L"%s%s%s -m %s", + L"" PROGNAME, + 0 != VolumePrefix && L'\0' != VolumePrefix[0] ? L" -u " : L"", + 0 != VolumePrefix && L'\0' != VolumePrefix[0] ? VolumePrefix : L"", + MountPoint); + + Service->UserContext = Notifyfs; + Result = STATUS_SUCCESS; + +exit: + if (!NT_SUCCESS(Result) && 0 != Notifyfs) + NotifyfsDelete(Notifyfs); + + return Result; + +usage:; + static wchar_t usage[] = L"" + "usage: %s OPTIONS\n" + "\n" + "options:\n" + " -u \\Server\\Share [UNC prefix (single backslash)]\n" + " -m MountPoint [X:|*|directory]\n"; + + fail(usage, L"" PROGNAME); + + return STATUS_UNSUCCESSFUL; + +#undef argtos +} + +static NTSTATUS SvcStop(FSP_SERVICE *Service) +{ + NOTIFYFS *Notifyfs = Service->UserContext; + + FspFileSystemStopDispatcher(Notifyfs->FileSystem); + NotifyfsDelete(Notifyfs); + + 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); +} diff --git a/tst/notifyfs/notifyfs.sln b/tst/notifyfs/notifyfs.sln new file mode 100644 index 00000000..10a7118d --- /dev/null +++ b/tst/notifyfs/notifyfs.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30717.126 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "notifyfs", "notifyfs.vcxproj", "{4BA1DED0-4268-408A-A4E2-8E1A6D55A99C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4BA1DED0-4268-408A-A4E2-8E1A6D55A99C}.Debug|x64.ActiveCfg = Debug|x64 + {4BA1DED0-4268-408A-A4E2-8E1A6D55A99C}.Debug|x64.Build.0 = Debug|x64 + {4BA1DED0-4268-408A-A4E2-8E1A6D55A99C}.Debug|x86.ActiveCfg = Debug|Win32 + {4BA1DED0-4268-408A-A4E2-8E1A6D55A99C}.Debug|x86.Build.0 = Debug|Win32 + {4BA1DED0-4268-408A-A4E2-8E1A6D55A99C}.Release|x64.ActiveCfg = Release|x64 + {4BA1DED0-4268-408A-A4E2-8E1A6D55A99C}.Release|x64.Build.0 = Release|x64 + {4BA1DED0-4268-408A-A4E2-8E1A6D55A99C}.Release|x86.ActiveCfg = Release|Win32 + {4BA1DED0-4268-408A-A4E2-8E1A6D55A99C}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {3CD0763B-2BFD-4D73-9539-13273788C41E} + EndGlobalSection +EndGlobal diff --git a/tst/notifyfs/notifyfs.vcxproj b/tst/notifyfs/notifyfs.vcxproj new file mode 100644 index 00000000..fdf7e0c3 --- /dev/null +++ b/tst/notifyfs/notifyfs.vcxproj @@ -0,0 +1,175 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {4ba1ded0-4268-408a-a4e2-8e1a6d55a99c} + notifyfs + $(LatestTargetPlatformVersion) + + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + Application + true + $(DefaultPlatformToolset) + Unicode + + + Application + false + $(DefaultPlatformToolset) + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + false + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + true + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + false + $(SolutionDir)build\$(Configuration)\ + $(SolutionDir)build\$(ProjectName).build\$(Configuration)\$(PlatformTarget)\ + $(ProjectName)-$(PlatformTarget) + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + + + Console + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + + + Console + true + true + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + + + Console + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + Level3 + true + true + true + NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + $(MSBuildProgramFiles32)\WinFsp\inc + MultiThreaded + + + Console + true + true + true + $(MSBuildProgramFiles32)\WinFsp\lib\winfsp-$(PlatformTarget).lib;%(AdditionalDependencies) + winfsp-$(PlatformTarget).dll + + + + + + + + + \ No newline at end of file diff --git a/tst/notifyfs/notifyfs.vcxproj.filters b/tst/notifyfs/notifyfs.vcxproj.filters new file mode 100644 index 00000000..4b5892ae --- /dev/null +++ b/tst/notifyfs/notifyfs.vcxproj.filters @@ -0,0 +1,14 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx + + + + + Source + + + \ No newline at end of file