diff --git a/GVFS/GVFS.Platform.Windows/ProjFSFilter.cs b/GVFS/GVFS.Platform.Windows/ProjFSFilter.cs
index b4f035983..ec092e984 100644
--- a/GVFS/GVFS.Platform.Windows/ProjFSFilter.cs
+++ b/GVFS/GVFS.Platform.Windows/ProjFSFilter.cs
@@ -5,7 +5,6 @@
using Microsoft.Windows.ProjFS;
using System;
using System.ComponentModel;
-using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
@@ -27,7 +26,6 @@ public class ProjFSFilter : IKernelDriver
private const string PrjFltAutoLoggerStartValue = "Start";
private const string System32LogFilesRoot = @"%SystemRoot%\System32\LogFiles";
- private const string System32DriversRoot = @"%SystemRoot%\System32\drivers";
// From "Autologger" section of prjflt.inf
private const string FilterLoggerGuid = "ee4206ff-4a4d-452f-be56-6bd0ed272b44";
@@ -87,6 +85,34 @@ public static bool TryAttach(string enlistmentRoot, out string errorMessage)
return true;
}
+ ///
+ /// Attempts to attach the ProjFS filter driver to the volume containing the enlistment.
+ /// If FilterAttach returns ACCESS_DENIED but the ProjFS service is already running,
+ /// the filter is presumed to already be attached and the call succeeds.
+ ///
+ public static bool TryAttachToVolume(string enlistmentRoot, ITracer tracer, out string errorMessage)
+ {
+ if (TryAttach(enlistmentRoot, out errorMessage))
+ {
+ return true;
+ }
+
+ // FilterAttach requires SE_LOAD_DRIVER_PRIVILEGE, which is typically only
+ // granted to administrators. When the caller lacks this privilege but the
+ // ProjFS service is confirmed running, the filter is probably already
+ // attached to the volume — treat ACCESS_DENIED as success in that case.
+ if (errorMessage != null
+ && errorMessage.Contains(AccessDeniedResult.ToString())
+ && IsServiceRunning(tracer))
+ {
+ tracer.RelatedInfo($"{nameof(TryAttachToVolume)}: FilterAttach returned ACCESS_DENIED, but ProjFS service is running. Proceeding.");
+ errorMessage = null;
+ return true;
+ }
+
+ return false;
+ }
+
public static bool IsServiceRunning(ITracer tracer)
{
try
@@ -243,22 +269,22 @@ public static bool TryEnableOrInstallDriver(
out bool isProjFSFeatureAvailable)
{
isProjFSFeatureAvailable = false;
- if (!TryGetIsInboxProjFSFinalAPI(tracer, out windowsBuildNumber, out isInboxProjFSFinalAPI))
+
+ // Log build number for telemetry. ProjFS is inbox on all supported OS versions
+ // (Windows 10 1809 / build 17763+), so this is informational only.
+ if (!TryGetWindowsBuildNumber(tracer, out windowsBuildNumber))
{
- return false;
+ tracer.RelatedWarning($"{nameof(TryEnableOrInstallDriver)}: Could not determine Windows build number");
}
- if (isInboxProjFSFinalAPI)
- {
- if (TryEnableProjFSOptionalFeature(tracer, fileSystem, out isProjFSFeatureAvailable))
- {
- return true;
- }
+ isInboxProjFSFinalAPI = true;
- return false;
+ if (TryEnableProjFSOptionalFeature(tracer, fileSystem, out isProjFSFeatureAvailable))
+ {
+ return true;
}
- return TryInstallProjFSViaINF(tracer, fileSystem);
+ return false;
}
public static bool IsNativeLibInstalled(ITracer tracer, PhysicalFileSystem fileSystem)
@@ -266,105 +292,22 @@ public static bool IsNativeLibInstalled(ITracer tracer, PhysicalFileSystem fileS
string system32Path = Path.Combine(Environment.SystemDirectory, ProjFSNativeLibFileName);
bool existsInSystem32 = fileSystem.FileExists(system32Path);
- string gvfsAppDirectory = ProcessHelper.GetCurrentProcessLocation();
- string nonInboxNativeLibInstallPath;
- string packagedNativeLibPath;
- GetNativeLibPaths(gvfsAppDirectory, out packagedNativeLibPath, out nonInboxNativeLibInstallPath);
- bool existsInAppDirectory = fileSystem.FileExists(nonInboxNativeLibInstallPath);
-
EventMetadata metadata = CreateEventMetadata();
metadata.Add(nameof(system32Path), system32Path);
metadata.Add(nameof(existsInSystem32), existsInSystem32);
- metadata.Add(nameof(gvfsAppDirectory), gvfsAppDirectory);
- metadata.Add(nameof(nonInboxNativeLibInstallPath), nonInboxNativeLibInstallPath);
- metadata.Add(nameof(packagedNativeLibPath), packagedNativeLibPath);
- metadata.Add(nameof(existsInAppDirectory), existsInAppDirectory);
- tracer.RelatedEvent(EventLevel.Informational, nameof(IsNativeLibInstalled), metadata);
- return existsInSystem32 || existsInAppDirectory;
- }
-
- public static bool TryCopyNativeLibIfDriverVersionsMatch(ITracer tracer, PhysicalFileSystem fileSystem, out string copyNativeDllError)
- {
- string system32NativeLibraryPath = Path.Combine(Environment.SystemDirectory, ProjFSNativeLibFileName);
- if (fileSystem.FileExists(system32NativeLibraryPath))
- {
- copyNativeDllError = $"{ProjFSNativeLibFileName} already exists at {system32NativeLibraryPath}";
- return false;
- }
-
- string gvfsProcessLocation = ProcessHelper.GetCurrentProcessLocation();
- string nonInboxNativeLibInstallPath;
- string packagedNativeLibPath;
- GetNativeLibPaths(gvfsProcessLocation, out packagedNativeLibPath, out nonInboxNativeLibInstallPath);
- if (fileSystem.FileExists(nonInboxNativeLibInstallPath))
- {
- copyNativeDllError = $"{ProjFSNativeLibFileName} already exists at {nonInboxNativeLibInstallPath}";
- return false;
- }
-
- if (!fileSystem.FileExists(packagedNativeLibPath))
- {
- copyNativeDllError = $"{packagedNativeLibPath} not found, no {ProjFSNativeLibFileName} available to copy";
- return false;
- }
-
- string packagedPrjfltDriverPath = Path.Combine(gvfsProcessLocation, "Filter", DriverFileName);
- if (!fileSystem.FileExists(packagedPrjfltDriverPath))
- {
- copyNativeDllError = $"{packagedPrjfltDriverPath} not found, unable to validate that packaged driver matches installed driver";
- return false;
- }
-
- string system32PrjfltDriverPath = Path.Combine(Environment.ExpandEnvironmentVariables(System32DriversRoot), DriverFileName);
- if (!fileSystem.FileExists(system32PrjfltDriverPath))
- {
- copyNativeDllError = $"{system32PrjfltDriverPath} not found, unable to validate that packaged driver matches installed driver";
- return false;
- }
-
- FileVersionInfo packagedDriverVersion;
- FileVersionInfo system32DriverVersion;
- try
- {
- packagedDriverVersion = fileSystem.GetVersionInfo(packagedPrjfltDriverPath);
- system32DriverVersion = fileSystem.GetVersionInfo(system32PrjfltDriverPath);
- if (!fileSystem.FileVersionsMatch(packagedDriverVersion, system32DriverVersion))
- {
- copyNativeDllError = $"Packaged sys FileVersion '{packagedDriverVersion.FileVersion}' does not match System32 sys FileVersion '{system32DriverVersion.FileVersion}'";
- return false;
- }
-
- if (!fileSystem.ProductVersionsMatch(packagedDriverVersion, system32DriverVersion))
- {
- copyNativeDllError = $"Packaged sys ProductVersion '{packagedDriverVersion.ProductVersion}' does not match System32 sys ProductVersion '{system32DriverVersion.ProductVersion}'";
- return false;
- }
- }
- catch (FileNotFoundException e)
- {
- EventMetadata metadata = CreateEventMetadata(e);
- tracer.RelatedWarning(
- metadata,
- $"{nameof(TryCopyNativeLibIfDriverVersionsMatch)}: Exception caught while comparing sys versions");
- copyNativeDllError = $"Exception caught while comparing sys versions: {e.Message}";
- return false;
- }
-
- EventMetadata driverVersionMetadata = CreateEventMetadata();
- driverVersionMetadata.Add($"{nameof(packagedDriverVersion)}.FileVersion", packagedDriverVersion.FileVersion.ToString());
- driverVersionMetadata.Add($"{nameof(system32DriverVersion)}.FileVersion", system32DriverVersion.FileVersion.ToString());
- driverVersionMetadata.Add($"{nameof(packagedDriverVersion)}.ProductVersion", packagedDriverVersion.ProductVersion.ToString());
- driverVersionMetadata.Add($"{nameof(system32DriverVersion)}.ProductVersion", system32DriverVersion.ProductVersion.ToString());
- tracer.RelatedInfo(driverVersionMetadata, $"{nameof(TryCopyNativeLibIfDriverVersionsMatch)}: Copying native library");
- if (!TryCopyNativeLibToNonInboxInstallLocation(tracer, fileSystem, gvfsProcessLocation))
+ // Check for stale app-local native library from legacy non-inbox installs.
+ // This file should not exist on current builds; warn if found so admins can clean it up.
+ string appLocalPath = Path.Combine(ProcessHelper.GetCurrentProcessLocation(), ProjFSNativeLibFileName);
+ bool staleAppLocalLibExists = fileSystem.FileExists(appLocalPath);
+ if (staleAppLocalLibExists)
{
- copyNativeDllError = "Failed to copy native library";
- return false;
+ metadata.Add(nameof(appLocalPath), appLocalPath);
+ metadata.Add(TracingConstants.MessageKey.WarningMessage, "Stale app-local ProjectedFSLib.dll found from legacy non-inbox ProjFS install");
}
- copyNativeDllError = null;
- return true;
+ tracer.RelatedEvent(EventLevel.Informational, nameof(IsNativeLibInstalled), metadata);
+ return existsInSystem32;
}
public bool IsGVFSUpgradeSupported()
@@ -469,23 +412,15 @@ public bool IsReady(JsonTracer tracer, string enlistmentRoot, TextWriter output,
if (!IsNativeLibInstalled(tracer, new PhysicalFileSystem()))
{
- error = "ProjFS native library is not installed";
+ error = "ProjFS native library (ProjectedFSLib.dll) is not installed. "
+ + "Ensure the Windows Projected File System optional feature is enabled. "
+ + "From an elevated PowerShell prompt, run: "
+ + "Enable-WindowsOptionalFeature -Online -FeatureName Client-ProjFS";
return false;
}
- if (!TryAttach(enlistmentRoot, out error))
+ if (!TryAttachToVolume(enlistmentRoot, tracer, out error))
{
- // FilterAttach requires SE_LOAD_DRIVER_PRIVILEGE (admin). When running
- // non-elevated on a machine where ProjFS is already set up, the filter
- // is already attached to the volume and the only failure is ACCESS_DENIED.
- // Allow the mount to proceed in that specific case.
- if (error.Contains(AccessDeniedResult.ToString()))
- {
- tracer.RelatedInfo($"IsReady: TryAttach returned ACCESS_DENIED, but ProjFS service is running. Proceeding.");
- error = string.Empty;
- return true;
- }
-
return false;
}
@@ -508,134 +443,20 @@ private static bool IsInboxAndEnabled()
return getOptionalFeatureResult.ExitCode == (int)ProjFSInboxStatus.Enabled;
}
- private static bool TryGetIsInboxProjFSFinalAPI(ITracer tracer, out uint windowsBuildNumber, out bool isProjFSInbox)
+ private static bool TryGetWindowsBuildNumber(ITracer tracer, out uint windowsBuildNumber)
{
- isProjFSInbox = false;
windowsBuildNumber = 0;
try
{
windowsBuildNumber = Common.NativeMethods.GetWindowsBuildNumber();
- tracer.RelatedInfo($"{nameof(TryGetIsInboxProjFSFinalAPI)}: Build number = {windowsBuildNumber}");
- }
- catch (Win32Exception e)
- {
- tracer.RelatedError(CreateEventMetadata(e), $"{nameof(TryGetIsInboxProjFSFinalAPI)}: Exception while trying to get Windows build number");
- return false;
- }
-
- const uint MinRS4inboxVersion = 17121;
- const uint FirstRS5Version = 17600;
- const uint MinRS5inboxVersion = 17626;
- isProjFSInbox = !(windowsBuildNumber < MinRS4inboxVersion || (windowsBuildNumber >= FirstRS5Version && windowsBuildNumber < MinRS5inboxVersion));
- return true;
- }
-
- private static bool TryInstallProjFSViaINF(ITracer tracer, PhysicalFileSystem fileSystem)
- {
- string gvfsAppDirectory = ProcessHelper.GetCurrentProcessLocation();
- if (!TryCopyNativeLibToNonInboxInstallLocation(tracer, fileSystem, gvfsAppDirectory))
- {
- return false;
- }
-
- ProcessResult result = ProcessHelper.Run("RUNDLL32.EXE", $"SETUPAPI.DLL,InstallHinfSection DefaultInstall 128 {gvfsAppDirectory}\\Filter\\prjflt.inf");
- if (result.ExitCode == 0)
- {
- tracer.RelatedInfo($"{nameof(TryInstallProjFSViaINF)}: Installed PrjFlt via INF");
+ tracer.RelatedInfo($"{nameof(TryGetWindowsBuildNumber)}: Build number = {windowsBuildNumber}");
return true;
}
- else
- {
- EventMetadata metadata = CreateEventMetadata();
- metadata.Add("resultExitCode", result.ExitCode);
- metadata.Add("resultOutput", result.Output);
- tracer.RelatedError(metadata, $"{nameof(TryInstallProjFSViaINF)}: RUNDLL32.EXE failed to install PrjFlt");
- }
-
- return false;
- }
-
- private static bool TryCopyNativeLibToNonInboxInstallLocation(ITracer tracer, PhysicalFileSystem fileSystem, string gvfsAppDirectory)
- {
- string packagedNativeLibPath;
- string nonInboxNativeLibInstallPath;
- GetNativeLibPaths(gvfsAppDirectory, out packagedNativeLibPath, out nonInboxNativeLibInstallPath);
-
- EventMetadata pathMetadata = CreateEventMetadata();
- pathMetadata.Add(nameof(gvfsAppDirectory), gvfsAppDirectory);
- pathMetadata.Add(nameof(packagedNativeLibPath), packagedNativeLibPath);
- pathMetadata.Add(nameof(nonInboxNativeLibInstallPath), nonInboxNativeLibInstallPath);
-
- if (fileSystem.FileExists(packagedNativeLibPath))
- {
- tracer.RelatedEvent(EventLevel.Informational, $"{nameof(TryCopyNativeLibToNonInboxInstallLocation)}_CopyingNativeLib", pathMetadata);
-
- try
- {
- fileSystem.CopyFile(packagedNativeLibPath, nonInboxNativeLibInstallPath, overwrite: true);
-
- try
- {
- fileSystem.FlushFileBuffers(nonInboxNativeLibInstallPath);
- }
- catch (Win32Exception e)
- {
- EventMetadata metadata = CreateEventMetadata(e);
- metadata.Add(nameof(nonInboxNativeLibInstallPath), nonInboxNativeLibInstallPath);
- metadata.Add(nameof(packagedNativeLibPath), packagedNativeLibPath);
- tracer.RelatedWarning(metadata, $"{nameof(TryCopyNativeLibToNonInboxInstallLocation)}: Win32Exception while trying to flush file buffers", Keywords.Telemetry);
- }
- }
- catch (UnauthorizedAccessException e)
- {
- EventMetadata metadata = CreateEventMetadata(e);
- tracer.RelatedError(metadata, $"{nameof(TryCopyNativeLibToNonInboxInstallLocation)}: UnauthorizedAccessException caught while trying to copy native lib");
- return false;
- }
- catch (DirectoryNotFoundException e)
- {
- EventMetadata metadata = CreateEventMetadata(e);
- tracer.RelatedError(metadata, $"{nameof(TryCopyNativeLibToNonInboxInstallLocation)}: DirectoryNotFoundException caught while trying to copy native lib");
- return false;
- }
- catch (FileNotFoundException e)
- {
- EventMetadata metadata = CreateEventMetadata(e);
- tracer.RelatedError(metadata, $"{nameof(TryCopyNativeLibToNonInboxInstallLocation)}: FileNotFoundException caught while trying to copy native lib");
- return false;
- }
- catch (IOException e)
- {
- EventMetadata metadata = CreateEventMetadata(e);
- tracer.RelatedWarning(metadata, $"{nameof(TryCopyNativeLibToNonInboxInstallLocation)}: IOException caught while trying to copy native lib");
-
- if (fileSystem.FileExists(nonInboxNativeLibInstallPath))
- {
- tracer.RelatedWarning(
- CreateEventMetadata(),
- "Could not copy native lib to app directory, but file already exists, continuing with install",
- Keywords.Telemetry);
- }
- else
- {
- tracer.RelatedError($"{nameof(TryCopyNativeLibToNonInboxInstallLocation)}: Failed to copy native lib to app directory");
- return false;
- }
- }
- }
- else
+ catch (Win32Exception e)
{
- tracer.RelatedError(pathMetadata, $"{nameof(TryCopyNativeLibToNonInboxInstallLocation)}: Native lib does not exist in install directory");
+ tracer.RelatedWarning(CreateEventMetadata(e), $"{nameof(TryGetWindowsBuildNumber)}: Exception while trying to get Windows build number");
return false;
}
-
- return true;
- }
-
- private static void GetNativeLibPaths(string gvfsAppDirectory, out string packagedNativeLibPath, out string nonInboxNativeLibInstallPath)
- {
- packagedNativeLibPath = Path.Combine(gvfsAppDirectory, "ProjFS", ProjFSNativeLibFileName);
- nonInboxNativeLibInstallPath = Path.Combine(gvfsAppDirectory, ProjFSNativeLibFileName);
}
private static bool TryEnableProjFSOptionalFeature(ITracer tracer, PhysicalFileSystem fileSystem, out bool isProjFSFeatureAvailable)
diff --git a/GVFS/GVFS.Service/Handlers/EnableAndAttachProjFSHandler.cs b/GVFS/GVFS.Service/Handlers/EnableAndAttachProjFSHandler.cs
index b8ec2ac5d..704f30006 100644
--- a/GVFS/GVFS.Service/Handlers/EnableAndAttachProjFSHandler.cs
+++ b/GVFS/GVFS.Service/Handlers/EnableAndAttachProjFSHandler.cs
@@ -61,7 +61,9 @@ public static bool TryEnablePrjFlt(ITracer tracer, out string error)
}
else
{
- error = "Failed to install (or enable) PrjFlt";
+ error = "Failed to enable ProjFS. Ensure the Windows Projected File System optional feature is enabled. "
+ + "From an elevated PowerShell prompt, run: "
+ + "Enable-WindowsOptionalFeature -Online -FeatureName Client-ProjFS";
tracer.RelatedError($"{nameof(TryEnablePrjFlt)}: {error}");
}
@@ -89,42 +91,11 @@ public static bool TryEnablePrjFlt(ITracer tracer, out string error)
isNativeProjFSLibInstalled = ProjFSFilter.IsNativeLibInstalled(tracer, fileSystem);
if (!isNativeProjFSLibInstalled)
{
- if (isPrjfltServiceRunning)
- {
- tracer.RelatedInfo($"{nameof(TryEnablePrjFlt)}: Native ProjFS library is not installed, attempting to copy version packaged with VFS for Git");
-
- EventLevel eventLevel;
- EventMetadata copyNativeLibMetadata = new EventMetadata();
- copyNativeLibMetadata.Add("Area", EtwArea);
- string copyNativeDllError = string.Empty;
- if (ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch(tracer, new PhysicalFileSystem(), out copyNativeDllError))
- {
- isNativeProjFSLibInstalled = true;
-
- eventLevel = EventLevel.Warning;
- copyNativeLibMetadata.Add(TracingConstants.MessageKey.WarningMessage, $"{nameof(TryEnablePrjFlt)}: Successfully copied ProjFS native library");
- }
- else
- {
- error = $"Native ProjFS library is not installed and could not be copied: {copyNativeDllError}";
-
- eventLevel = EventLevel.Error;
- copyNativeLibMetadata.Add(nameof(copyNativeDllError), copyNativeDllError);
- copyNativeLibMetadata.Add(TracingConstants.MessageKey.ErrorMessage, $"{nameof(TryEnablePrjFlt)}: Failed to copy ProjFS native library");
- }
-
- copyNativeLibMetadata.Add(nameof(isNativeProjFSLibInstalled), isNativeProjFSLibInstalled);
- tracer.RelatedEvent(
- eventLevel,
- $"{nameof(TryEnablePrjFlt)}_{nameof(ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch)}",
- copyNativeLibMetadata,
- Keywords.Telemetry);
- }
- else
- {
- error = "Native ProjFS library is not installed, did not attempt to copy library because prjflt service is not running";
- tracer.RelatedError($"{nameof(TryEnablePrjFlt)}: {error}");
- }
+ error = "ProjFS native library (ProjectedFSLib.dll) is not installed in System32. "
+ + "Ensure the Windows Projected File System optional feature is enabled. "
+ + "From an elevated PowerShell prompt, run: "
+ + "Enable-WindowsOptionalFeature -Online -FeatureName Client-ProjFS";
+ tracer.RelatedError($"{nameof(TryEnablePrjFlt)}: {error}");
}
bool isAutoLoggerEnabled = ProjFSFilter.IsAutoLoggerEnabled(tracer);
@@ -155,7 +126,7 @@ public static bool TryEnablePrjFlt(ITracer tracer, out string error)
public void Run()
{
- string errorMessage;
+ string errorMessage = null;
NamedPipeMessages.CompletionState state = NamedPipeMessages.CompletionState.Success;
if (!TryEnablePrjFlt(this.tracer, out errorMessage))
@@ -164,12 +135,15 @@ public void Run()
this.tracer.RelatedError("Unable to install or enable PrjFlt. Enlistment root: {0} \nError: {1} ", this.request.EnlistmentRoot, errorMessage);
}
- if (!string.IsNullOrEmpty(this.request.EnlistmentRoot))
+ if (state == NamedPipeMessages.CompletionState.Success
+ && !string.IsNullOrEmpty(this.request.EnlistmentRoot))
{
- if (!ProjFSFilter.TryAttach(this.request.EnlistmentRoot, out errorMessage))
+ string attachError;
+ if (!ProjFSFilter.TryAttachToVolume(this.request.EnlistmentRoot, this.tracer, out attachError))
{
state = NamedPipeMessages.CompletionState.Failure;
- this.tracer.RelatedError("Unable to attach filter to volume. Enlistment root: {0} \nError: {1} ", this.request.EnlistmentRoot, errorMessage);
+ errorMessage = attachError;
+ this.tracer.RelatedError("Unable to attach filter to volume. Enlistment root: {0} \nError: {1} ", this.request.EnlistmentRoot, attachError);
}
}
diff --git a/GVFS/GVFS.UnitTests/Windows/Platform/ProjFSFilterTests.cs b/GVFS/GVFS.UnitTests/Windows/Platform/ProjFSFilterTests.cs
index c8c11f05d..8eaced813 100644
--- a/GVFS/GVFS.UnitTests/Windows/Platform/ProjFSFilterTests.cs
+++ b/GVFS/GVFS.UnitTests/Windows/Platform/ProjFSFilterTests.cs
@@ -2,34 +2,21 @@
using GVFS.Common.FileSystem;
using GVFS.Platform.Windows;
using GVFS.Tests.Should;
-using GVFS.UnitTests.Category;
using GVFS.UnitTests.Mock.Common;
using Moq;
using NUnit.Framework;
using System;
-using System.Diagnostics;
using System.IO;
-using System.Reflection;
namespace GVFS.UnitTests.Windows.Platform
{
[TestFixture]
public class ProjFSFilterTests
{
- private const string System32DriversRoot = @"%SystemRoot%\System32\drivers";
- private const string PrjFltDriverName = "prjflt.sys";
private const string ProjFSNativeLibFileName = "ProjectedFSLib.dll";
private readonly string system32NativeLibPath = Path.Combine(Environment.SystemDirectory, ProjFSNativeLibFileName);
- private readonly string nonInboxNativeLibInstallPath = Path.Combine(ProcessHelper.GetCurrentProcessLocation(), ProjFSNativeLibFileName);
- private readonly string packagedNativeLibPath = Path.Combine(ProcessHelper.GetCurrentProcessLocation(), "ProjFS", ProjFSNativeLibFileName);
-
- private readonly string packagedDriverPath = Path.Combine(ProcessHelper.GetCurrentProcessLocation(), "Filter", PrjFltDriverName);
- private readonly string system32DriverPath = Path.Combine(Environment.ExpandEnvironmentVariables(System32DriversRoot), PrjFltDriverName);
-
- // .NET doesn't allow us to create custom FileVersionInfos, and so use the version for our assembly and mock
- // the version comparison methods
- private readonly FileVersionInfo dummyVersionInfo = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
+ private readonly string appLocalNativeLibPath = Path.Combine(ProcessHelper.GetCurrentProcessLocation(), ProjFSNativeLibFileName);
private Mock mockFileSystem;
private MockTracer mockTracer;
@@ -51,137 +38,26 @@ public void TearDown()
public void IsNativeLibInstalled_ReturnsTrueWhenLibInSystem32()
{
this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.nonInboxNativeLibInstallPath)).Returns(false);
+ this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.appLocalNativeLibPath)).Returns(false);
ProjFSFilter.IsNativeLibInstalled(this.mockTracer, this.mockFileSystem.Object).ShouldBeTrue();
}
[TestCase]
- public void IsNativeLibInstalled_ReturnsTrueWhenLibInNonInboxInstallLocation()
+ public void IsNativeLibInstalled_ReturnsFalseWhenLibNotInSystem32()
{
this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.nonInboxNativeLibInstallPath)).Returns(true);
- ProjFSFilter.IsNativeLibInstalled(this.mockTracer, this.mockFileSystem.Object).ShouldBeTrue();
- }
-
- [TestCase]
- public void IsNativeLibInstalled_ReturnsFalseWhenNativeLibraryDoesNotExistInAnyInstallLocation()
- {
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(It.IsAny())).Returns(false);
+ this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.appLocalNativeLibPath)).Returns(false);
ProjFSFilter.IsNativeLibInstalled(this.mockTracer, this.mockFileSystem.Object).ShouldBeFalse();
}
[TestCase]
- public void TryCopyNativeLibIfDriverVersionsMatch_ReturnsFalseWhenLibInSystem32()
- {
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(true);
- ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch(this.mockTracer, this.mockFileSystem.Object, out string _).ShouldBeFalse();
- }
-
- [TestCase]
- public void TryCopyNativeLibIfDriverVersionsMatch_ReturnsFalseWhenLibAtNonInboxInstallLocation()
- {
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.nonInboxNativeLibInstallPath)).Returns(true);
- ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch(this.mockTracer, this.mockFileSystem.Object, out string _).ShouldBeFalse();
- }
-
- [TestCase]
- public void TryCopyNativeLibIfDriverVersionsMatch_ReturnsFalseWhenLibMissingFromPackagedLocation()
- {
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.nonInboxNativeLibInstallPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedNativeLibPath)).Returns(false);
- ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch(this.mockTracer, this.mockFileSystem.Object, out string _).ShouldBeFalse();
- }
-
- [TestCase]
- public void TryCopyNativeLibIfDriverVersionsMatch_ReturnsFalseWhenDriverMissingFromPackagedLocation()
- {
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.nonInboxNativeLibInstallPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedNativeLibPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedDriverPath)).Returns(false);
- ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch(this.mockTracer, this.mockFileSystem.Object, out string _).ShouldBeFalse();
- }
-
- [TestCase]
- public void TryCopyNativeLibIfDriverVersionsMatch_ReturnsFalseWhenDriverMissingFromSystem32()
+ public void IsNativeLibInstalled_ReturnsFalseWhenOnlyAppLocalLibExists()
{
+ // App-local lib from a legacy non-inbox install should NOT count as installed.
+ // Only the System32 copy (from the Windows optional feature) is valid.
this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.nonInboxNativeLibInstallPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedNativeLibPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedDriverPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32DriverPath)).Returns(false);
- ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch(this.mockTracer, this.mockFileSystem.Object, out string _).ShouldBeFalse();
- }
-
- [TestCase]
- public void TryCopyNativeLibIfDriverVersionsMatch_ReturnsFalseWhenFileVersionDoesNotMatch()
- {
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.nonInboxNativeLibInstallPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedNativeLibPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedDriverPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32DriverPath)).Returns(true);
-
- this.mockFileSystem.Setup(fileSystem => fileSystem.GetVersionInfo(this.packagedDriverPath)).Returns(this.dummyVersionInfo);
- this.mockFileSystem.Setup(fileSystem => fileSystem.GetVersionInfo(this.system32DriverPath)).Returns(this.dummyVersionInfo);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileVersionsMatch(this.dummyVersionInfo, this.dummyVersionInfo)).Returns(false);
- ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch(this.mockTracer, this.mockFileSystem.Object, out string _).ShouldBeFalse();
- }
-
- [TestCase]
- public void TryCopyNativeLibIfDriverVersionsMatch_ReturnsFalseWhenProductVersionDoesNotMatch()
- {
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.nonInboxNativeLibInstallPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedNativeLibPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedDriverPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32DriverPath)).Returns(true);
-
- this.mockFileSystem.Setup(fileSystem => fileSystem.GetVersionInfo(this.packagedDriverPath)).Returns(this.dummyVersionInfo);
- this.mockFileSystem.Setup(fileSystem => fileSystem.GetVersionInfo(this.system32DriverPath)).Returns(this.dummyVersionInfo);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileVersionsMatch(this.dummyVersionInfo, this.dummyVersionInfo)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.ProductVersionsMatch(this.dummyVersionInfo, this.dummyVersionInfo)).Returns(false);
- ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch(this.mockTracer, this.mockFileSystem.Object, out string _).ShouldBeFalse();
- }
-
- [TestCase]
- [Category(CategoryConstants.ExceptionExpected)]
- public void TryCopyNativeLibIfDriverVersionsMatch_ReturnsFalseWhenCopyingNativeLibFails()
- {
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.nonInboxNativeLibInstallPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedNativeLibPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedDriverPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32DriverPath)).Returns(true);
-
- this.mockFileSystem.Setup(fileSystem => fileSystem.GetVersionInfo(this.packagedDriverPath)).Returns(this.dummyVersionInfo);
- this.mockFileSystem.Setup(fileSystem => fileSystem.GetVersionInfo(this.system32DriverPath)).Returns(this.dummyVersionInfo);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileVersionsMatch(this.dummyVersionInfo, this.dummyVersionInfo)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.ProductVersionsMatch(this.dummyVersionInfo, this.dummyVersionInfo)).Returns(true);
-
- this.mockFileSystem.Setup(fileSystem => fileSystem.CopyFile(this.packagedNativeLibPath, this.nonInboxNativeLibInstallPath, true)).Throws(new IOException());
- ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch(this.mockTracer, this.mockFileSystem.Object, out string _).ShouldBeFalse();
- }
-
- [TestCase]
- public void TryCopyNativeLibIfDriverVersionsMatch_ReturnsTrueOnSuccess()
- {
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32NativeLibPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.nonInboxNativeLibInstallPath)).Returns(false);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedNativeLibPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.packagedDriverPath)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.system32DriverPath)).Returns(true);
-
- this.mockFileSystem.Setup(fileSystem => fileSystem.GetVersionInfo(this.packagedDriverPath)).Returns(this.dummyVersionInfo);
- this.mockFileSystem.Setup(fileSystem => fileSystem.GetVersionInfo(this.system32DriverPath)).Returns(this.dummyVersionInfo);
- this.mockFileSystem.Setup(fileSystem => fileSystem.FileVersionsMatch(this.dummyVersionInfo, this.dummyVersionInfo)).Returns(true);
- this.mockFileSystem.Setup(fileSystem => fileSystem.ProductVersionsMatch(this.dummyVersionInfo, this.dummyVersionInfo)).Returns(true);
-
- this.mockFileSystem.Setup(fileSystem => fileSystem.CopyFile(this.packagedNativeLibPath, this.nonInboxNativeLibInstallPath, true));
- this.mockFileSystem.Setup(fileSystem => fileSystem.FlushFileBuffers(this.nonInboxNativeLibInstallPath));
- ProjFSFilter.TryCopyNativeLibIfDriverVersionsMatch(this.mockTracer, this.mockFileSystem.Object, out string _).ShouldBeTrue();
+ this.mockFileSystem.Setup(fileSystem => fileSystem.FileExists(this.appLocalNativeLibPath)).Returns(true);
+ ProjFSFilter.IsNativeLibInstalled(this.mockTracer, this.mockFileSystem.Object).ShouldBeFalse();
}
}
}