diff --git a/.github/workflows/p4vfs-verify.yml b/.github/workflows/p4vfs-verify.yml index 0c8681a..24d5f07 100644 --- a/.github/workflows/p4vfs-verify.yml +++ b/.github/workflows/p4vfs-verify.yml @@ -38,7 +38,7 @@ jobs: Write-Output "ImageVersion=$env:ImageVersion" >> $env:GITHUB_ENV - name: Checkout the repo - uses: actions/checkout@v4.1.7 + uses: actions/checkout@v4.2.2 - name: Setup MSBuild uses: microsoft/setup-msbuild@v2 @@ -46,7 +46,7 @@ jobs: msbuild-architecture: x64 - name: Cache OpenSSL ${{env.ImageOS}} ${{env.ImageVersion}} - uses: actions/cache@v4.0.2 + uses: actions/cache@v4.2.0 with: path: | external/OpenSSL diff --git a/README.md b/README.md index fe9776d..fbd044a 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ For example, you can use the P4VFS to perform a "virtual sync" to a Perforce fil # Installation You can install the latest signed release of P4VFS from here: -> [P4VFS.Setup](https://github.com/microsoft/p4vfs/releases/download/v1.28.0.0/P4VFS.Setup-1.28.0.0.exe) +> [P4VFS.Setup](https://github.com/microsoft/p4vfs/releases/download/v1.28.3.0/P4VFS.Setup-1.28.3.0.exe) The entire history of release notes is included with the installer. > [Release Notes](https://github.com/microsoft/p4vfs/blob/main/source/P4VFS.Console/P4VFS.Notes.txt) @@ -49,8 +49,8 @@ The tool respects P4CONFIG file usage, as well as supports typical configuration ### Build Requirments: 1. Visual Studio 2022 version 17.5.0 or later -1. Windows SDK version 10.0.22621.0 (22H2) -1. Windows WDK version 10.0.22621.382 (22H2) +1. Windows SDK version 10.0.26100.1742 +1. Windows WDK version 10.0.26100.2454 Details for installing Visual Studio 2022, the Windows Software Development Kit (SDK), and the Windows Driver Kit (WDK) can be found here: > [Download the Windows Driver Kit](https://learn.microsoft.com/en-us/windows-hardware/drivers/download-the-wdk) diff --git a/source/P4VFS.Console/P4VFS.Notes.txt b/source/P4VFS.Console/P4VFS.Notes.txt index fcfea58..4991160 100644 --- a/source/P4VFS.Console/P4VFS.Notes.txt +++ b/source/P4VFS.Console/P4VFS.Notes.txt @@ -1,5 +1,11 @@ Microsoft P4VFS Release Notes +Version [1.28.3.0] +* Fixing service initialization error if registry ImagePath value contains quotes + under key "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\P4VFS.Service". + Including a new unit test to verify handling of user settings paths. +* Updating driver WDK to 10.0.26100 + Version [1.28.2.0] * Fixing support for specifying a value for P4TICKETS from within a P4CONFIG file, and correctly used from working directory of p4vfs.exe, or placeholder file folder diff --git a/source/P4VFS.Driver/Include/DriverVersion.h b/source/P4VFS.Driver/Include/DriverVersion.h index 7a62b84..61b7acb 100644 --- a/source/P4VFS.Driver/Include/DriverVersion.h +++ b/source/P4VFS.Driver/Include/DriverVersion.h @@ -4,7 +4,7 @@ #define P4VFS_VER_MAJOR 1 // Increment this number almost never #define P4VFS_VER_MINOR 28 // Increment this number whenever the driver changes -#define P4VFS_VER_BUILD 2 // Increment this number when a major user mode change has been made +#define P4VFS_VER_BUILD 3 // Increment this number when a major user mode change has been made #define P4VFS_VER_REVISION 0 // Increment this number when we rebuild with any change #define P4VFS_VER_STRINGIZE_EX(v) L#v diff --git a/source/P4VFS.Driver/P4VFS.Driver.vcxproj b/source/P4VFS.Driver/P4VFS.Driver.vcxproj index 75f92f9..23ad7cd 100644 --- a/source/P4VFS.Driver/P4VFS.Driver.vcxproj +++ b/source/P4VFS.Driver/P4VFS.Driver.vcxproj @@ -19,7 +19,7 @@ x64 Microsoft::P4VFS::Driver /msft - 10.0.22621.0 + 10.0.26100.0 diff --git a/source/P4VFS.Extensions/Source/Common/VirtualFileSystem.cs b/source/P4VFS.Extensions/Source/Common/VirtualFileSystem.cs index b80c43b..29e350c 100644 --- a/source/P4VFS.Extensions/Source/Common/VirtualFileSystem.cs +++ b/source/P4VFS.Extensions/Source/Common/VirtualFileSystem.cs @@ -231,7 +231,7 @@ public static string PublicSettingsFilePath { get { - string publicProfile = Environment.GetEnvironmentVariable("PUBLIC"); + string publicProfile = Environment.GetEnvironmentVariable("PUBLIC")?.Trim('"'); return String.IsNullOrEmpty(publicProfile) ? String.Empty : Path.GetFullPath(String.Format("{0}\\{1}", publicProfile, SettingsFile)); } } @@ -247,6 +247,7 @@ public static string InstalledSettingsFilePath { string serviceFilePath = null; RegistryInfo.GetTypedValue(Microsoft.Win32.Registry.LocalMachine, ServiceRegistryKey, "ImagePath", ref serviceFilePath); + serviceFilePath = serviceFilePath?.Trim('"'); return String.IsNullOrEmpty(serviceFilePath) ? String.Empty : Path.GetFullPath(String.Format("{0}\\{1}", Path.GetDirectoryName(serviceFilePath), SettingsFile)); } } diff --git a/source/P4VFS.Extensions/Source/Utilities/RegistryInfo.cs b/source/P4VFS.Extensions/Source/Utilities/RegistryInfo.cs index b9ddc9c..c9e9ef7 100644 --- a/source/P4VFS.Extensions/Source/Utilities/RegistryInfo.cs +++ b/source/P4VFS.Extensions/Source/Utilities/RegistryInfo.cs @@ -1,20 +1,16 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. using System; -using System.Collections.Generic; -using System.Linq; using System.Text; using System.Runtime.InteropServices; using System.Security; -using System.Security.Permissions; using Microsoft.Win32; using Microsoft.Win32.SafeHandles; namespace Microsoft.P4VFS.Extensions.Utilities { /// - /// Class to help with the nitty-gritty details of accessing the two registries (32 and 64 bit) - /// from managed code. + /// Class to help with the nitty-gritty details of accessing the two registries (32 and 64 bit) from managed code. /// public static class RegistryInfo { @@ -34,19 +30,6 @@ public static string StrRegError /// Retrieves the specified key/value and casts to type T, where possible. Expected errors (such as could not open key) /// stored in StrRegError. Use GetValueType() or T=object if uncertain what type of value the key stores. /// - /// The type to cast the key value to. - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "ifFaceName". - /// Stores the casted value if RegistryCmd access succeeded. - /// Success true/false. - /// A null argument was passed in. - /// sub_key or name is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. - /// The key value could not be cast to requested type. public static bool GetTypedValue(RegistryKey hive_key, string sub_key, string name, ref T value) { return RegistryInfo.GetTypedValueWithOptions(hive_key, sub_key, name, RegistryValueOptions.None, ref value); @@ -56,20 +39,6 @@ public static bool GetTypedValue(RegistryKey hive_key, string sub_key, string /// Retrieves the specified key/value and casts to type T, where possible. Expected errors (such as could not open key) /// stored in StrRegError. Use GetValueType() or T=object if uncertain what type of value the key stores. /// - /// The type to cast the key value to. - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "ifFaceName". - /// The options to use when querying the registry. - /// Stores the casted value if RegistryCmd access succeeded. - /// Success true/false. - /// A null argument was passed in. - /// sub_key or name is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. - /// The key value could not be cast to requested type. public static bool GetTypedValueWithOptions(RegistryKey hive_key, string sub_key, string name, RegistryValueOptions options, ref T value) { object obj_data = RegistryInfo.GetValue(hive_key, sub_key, name, options); @@ -85,16 +54,6 @@ public static bool GetTypedValueWithOptions(RegistryKey hive_key, string sub_ /// /// Sets/creates the specified String value. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "ifFaceName". - /// String data value to write. - /// A null argument was passed in. - /// value is an unsupported data type. -or- name is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. public static void SetStringValue(RegistryKey hive_key, string sub_key, string name, string value) { RegistryInfo.SetValue(hive_key, sub_key, name, value, RegistryValueKind.String); @@ -103,16 +62,6 @@ public static void SetStringValue(RegistryKey hive_key, string sub_key, string n /// /// Sets/creates the specified ExpandString value. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "ifFaceName". - /// String data value to write. - /// A null argument was passed in. - /// value is an unsupported data type. -or- name is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. public static void SetStringExpandValue(RegistryKey hive_key, string sub_key, string name, string value) { RegistryInfo.SetValue(hive_key, sub_key, name, value, RegistryValueKind.ExpandString); @@ -121,16 +70,6 @@ public static void SetStringExpandValue(RegistryKey hive_key, string sub_key, st /// /// Sets/creates the specified DWORD value. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "iPointSize". - /// DWORD data value to write. - /// A null argument was passed in. - /// value is an unsupported data type. -or- name is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. public static void SetDWORDValue(RegistryKey hive_key, string sub_key, string name, int value) { RegistryInfo.SetValue(hive_key, sub_key, name, value, RegistryValueKind.DWord); @@ -139,16 +78,6 @@ public static void SetDWORDValue(RegistryKey hive_key, string sub_key, string na /// /// Sets/creates the specified Binary value. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "iPointSize" sic. - /// Binary data value to write. - /// A null argument was passed in. - /// value is an unsupported data type. -or- name is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. public static void SetBinaryValue(RegistryKey hive_key, string sub_key, string name, byte[] value) { RegistryInfo.SetValue(hive_key, sub_key, name, value, RegistryValueKind.Binary); @@ -157,16 +86,6 @@ public static void SetBinaryValue(RegistryKey hive_key, string sub_key, string n /// /// Sets/creates the specified String Array value. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "iPointSize" sic. - /// String Array value to write. - /// A null argument was passed in. - /// value is an unsupported data type. -or- name is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. public static void SetStringArrayValue(RegistryKey hive_key, string sub_key, string name, string[] value) { RegistryInfo.SetValue(hive_key, sub_key, name, value, RegistryValueKind.MultiString); @@ -175,17 +94,6 @@ public static void SetStringArrayValue(RegistryKey hive_key, string sub_key, str /// /// Sets/creates the specified value. Casts where able to RegistryValueKind. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "iPointSize" sic. - /// Binary data value to write. - /// Microsoft.Win32.RegistryValueKind to store the value as. - /// A null argument was passed in. - /// value is an unsupported data type. -or- name is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. public static void SetValue(RegistryKey hive_key, string sub_key, string name, object value, RegistryValueKind kind) { StrRegError = null; @@ -204,15 +112,6 @@ public static void SetValue(RegistryKey hive_key, string sub_key, string name, o /// /// Creates a new subkey or opens an existing subkey. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// A null argument was passed in. - /// sub_key is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. - /// The Microsoft.Win32.RegistryKey created from hive_key and sub_key. public static RegistryKey CreateSubKey(RegistryKey hive_key, string sub_key) { StrRegError = null; @@ -228,13 +127,6 @@ public static RegistryKey CreateSubKey(RegistryKey hive_key, string sub_key) /// /// Deletes a subkey and any child subkeys recursively. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// A null argument was passed in. - /// Deletion of a root hive is attempted. -or- subkey does not specify a valid registry subkey. - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The user does not have the necessary registry rights. public static void DeleteSubKeyTree(RegistryKey hive_key, string sub_key) { StrRegError = null; @@ -244,15 +136,6 @@ public static void DeleteSubKeyTree(RegistryKey hive_key, string sub_key) /// /// Deletes the specified value from this (current) key. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "iPointSize". - /// A null argument was passed in. - /// name is not a valid reference to a value. - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. public static void DeleteValue(RegistryKey hive_key, string sub_key, string name) { StrRegError = null; @@ -277,34 +160,40 @@ public static void DeleteValue(RegistryKey hive_key, string sub_key, string name /// /// Retrieves the type of the specified RegistryCmd value. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "iPointSize". - /// System.Type. Exceptions/errors stored in StrRegError. - /// A null argument was passed in. - /// sub_key or name is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. public static Type GetValueType(RegistryKey hive_key, string sub_key, string name) { return RegistryInfo.GetValue(hive_key, sub_key, name, RegistryValueOptions.None).GetType(); } + /// + /// Retrieves the RegistryValueKind of the specified RegistryCmd value. Exceptions/errors stored in StrRegError. + /// + public static RegistryValueKind GetValueKind(RegistryKey hive_key, string sub_key, string name) + { + StrRegError = null; + using (RegistryKey subKey = hive_key.OpenSubKey(sub_key)) + { + if (subKey == null) + { + StrRegError = "Cannot open the specified sub-key"; + return RegistryValueKind.Unknown; + } + + try + { + return subKey.GetValueKind(name); + } + catch (Exception ex) + { + StrRegError = ex.Message; + return RegistryValueKind.Unknown; + } + } + } + /// /// Determines the existence of a value. Exceptions/errors stored in StrRegError. /// - /// Identifies which hive to look in, such as Microsoft.Win32.Registry.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "iPointSize". - /// Whether the value exists by boolean. Exceptions/errors stored in StrRegError. - /// A null argument was passed in. - /// sub_key or name is longer than the maximum length allowed (255 characters). - /// The Microsoft.Win32.RegistryKey is closed (closed keys cannot be accessed). - /// The user does not have the permissions required to read the registry key. - /// The Microsoft.Win32.RegistryKey that contains the specified key has been marked for deletion. - /// The user does not have the necessary registry rights. public static bool ValueExists(RegistryKey hive_key, string sub_key, string name) { StrRegError = null; @@ -333,10 +222,6 @@ public static bool ValueExists(RegistryKey hive_key, string sub_key, string name /// Wraps up the Win32 RegistryCmd access to a single line. OpenSubKey and GetValue can throw several exceptions, /// but for now we will let those hit the user (exceptions listed on public accessors to this function). /// - /// Identifies which hive to look in, such as Microsoft.Win32.RegistryCmd.LocalMachine. - /// Path from hive key to target node. Such as "SOFTWARE\\MICROSOFT\\Notepad\DefaultFonts. - /// The key to act on. Such as "iPointSize". - /// Object from RegistryKey.OpenSubKey. private static object GetValue(RegistryKey hive_key, string sub_key, string name, RegistryValueOptions options) { object objData = null; @@ -657,14 +542,8 @@ public static bool GetDWORDValueFromRegistryHandle(SafeRegistryHandle safe_handl /// - /// Horrible stuff to be able to access the 64-bit registry from a managed app, regardless of - /// the app's bitness. + /// Horrible stuff to be able to access the 64-bit registry from a managed app, regardless of the app's bitness. /// - /// The hive to read from (HKLM, HKCU, etc). - /// The key itself. - /// The value to query. - /// Additional flags to pass directly to the Win32 API. - /// String value stored in the registry, or empty string if not available. public static string GetStringValueFromRegistryWithFlags(RegistryHive reg_hive, string key, string value, int flags) { string return_value = String.Empty; @@ -684,26 +563,16 @@ public static string GetStringValueFromRegistryWithFlags(RegistryHive reg_hive, } /// - /// Horrible stuff to be able to access the 32-bit registry from a managed app, regardless of - /// the app's bitness. + /// Horrible stuff to be able to access the 32-bit registry from a managed app, regardless of the app's bitness. /// - /// The hive to read from (HKLM, HKCU, etc). - /// The key itself. - /// The value to query. - /// String value stored in the 32-bit registry, or empty string if not available. public string GetStringValueFrom32BitRegistry(RegistryHive reg_hive, string key, string value) { return GetStringValueFromRegistryWithFlags(reg_hive, key, value, KEY_WOW64_32KEY); } /// - /// Horrible stuff to be able to access the 64-bit registry from a managed app, regardless of - /// the app's bitness. + /// Horrible stuff to be able to access the 64-bit registry from a managed app, regardless of the app's bitness. /// - /// The hive to read from (HKLM, HKCU, etc). - /// The key itself. - /// The value to query. - /// String value stored in the 64-bit registry, or empty string if not available. public string GetStringValueFrom64BitRegistry(RegistryHive reg_hive, string key, string value) { return GetStringValueFromRegistryWithFlags(reg_hive, key, value, KEY_WOW64_64KEY); diff --git a/source/P4VFS.UnitTest/Source/UnitTestInstall.cs b/source/P4VFS.UnitTest/Source/UnitTestInstall.cs index fd64459..2bbe034 100644 --- a/source/P4VFS.UnitTest/Source/UnitTestInstall.cs +++ b/source/P4VFS.UnitTest/Source/UnitTestInstall.cs @@ -334,6 +334,43 @@ public void DriverOperationsTest() Assert(VirtualFileSystem.IsVirtualFileSystemAvailable()); } + [TestMethod, Priority(9)] + public void InstalledSettingsFilePathTest() + { + // Verifications of the simple settings file path + Assert(String.IsNullOrEmpty(VirtualFileSystem.UserSettingsFilePath) == false); + Assert(String.IsNullOrEmpty(VirtualFileSystem.AssemblySettingsFilePath) == false); + + // Verifications of the public settings file path given differences in the PUBLIC environment variable + string originalPublicSettingsFilePath = VirtualFileSystem.PublicSettingsFilePath; + Assert(String.IsNullOrEmpty(VirtualFileSystem.PublicSettingsFilePath) == false); + using (new SetEnvironmentVariableScope("PUBLIC", "")) + Assert(String.IsNullOrEmpty(VirtualFileSystem.PublicSettingsFilePath)); + using (new SetEnvironmentVariableScope("PUBLIC", Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData))) + Assert(String.Equals(VirtualFileSystem.PublicSettingsFilePath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), VirtualFileSystem.SettingsFile), StringComparison.InvariantCultureIgnoreCase)); + using (new SetEnvironmentVariableScope("PUBLIC", $"\"{Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)}\"")) + Assert(String.Equals(VirtualFileSystem.PublicSettingsFilePath, Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), VirtualFileSystem.SettingsFile), StringComparison.InvariantCultureIgnoreCase)); + Assert(originalPublicSettingsFilePath == VirtualFileSystem.PublicSettingsFilePath); + + // Verifications of the installed settings file path given the service registry key + string originalInstalledSettingsFilePath = VirtualFileSystem.InstalledSettingsFilePath; + Assert(String.IsNullOrEmpty(VirtualFileSystem.InstalledSettingsFilePath) == false); + Assert(String.Equals(VirtualFileSystem.InstalledSettingsFilePath, Path.Combine(Path.GetDirectoryName(InstalledP4vfsExe), VirtualFileSystem.SettingsFile), StringComparison.InvariantCultureIgnoreCase)); + Assert(RegistryInfo.GetValueKind(Microsoft.Win32.Registry.LocalMachine, VirtualFileSystem.ServiceRegistryKey, "ImagePath") == Microsoft.Win32.RegistryValueKind.ExpandString); + string installedImagePath = null; + Assert(RegistryInfo.GetTypedValue(Microsoft.Win32.Registry.LocalMachine, VirtualFileSystem.ServiceRegistryKey, "ImagePath", ref installedImagePath)); + Assert(Directory.Exists(Path.GetDirectoryName(installedImagePath))); + Assert(String.Equals(Path.GetDirectoryName(installedImagePath), Path.GetDirectoryName(InstalledP4vfsExe), StringComparison.InvariantCultureIgnoreCase)); + AssertLambda(() => RegistryInfo.SetValue(Microsoft.Win32.Registry.LocalMachine, VirtualFileSystem.ServiceRegistryKey, "ImagePath", $"\"{installedImagePath}\"", Win32.RegistryValueKind.ExpandString)); + string quotedInstalledImagePath = null; + Assert(RegistryInfo.GetTypedValue(Microsoft.Win32.Registry.LocalMachine, VirtualFileSystem.ServiceRegistryKey, "ImagePath", ref quotedInstalledImagePath)); + Assert(quotedInstalledImagePath == $"\"{installedImagePath}\""); + Assert(originalInstalledSettingsFilePath == VirtualFileSystem.InstalledSettingsFilePath); + AssertLambda(() => RegistryInfo.SetValue(Microsoft.Win32.Registry.LocalMachine, VirtualFileSystem.ServiceRegistryKey, "ImagePath", installedImagePath, Win32.RegistryValueKind.ExpandString)); + Assert(RegistryInfo.GetValueKind(Microsoft.Win32.Registry.LocalMachine, VirtualFileSystem.ServiceRegistryKey, "ImagePath") == Microsoft.Win32.RegistryValueKind.ExpandString); + Assert(originalInstalledSettingsFilePath == VirtualFileSystem.InstalledSettingsFilePath); + } + public bool IsInstallationSigned() { string p4vfsExe = InstalledP4vfsExe; diff --git a/source/P4VFS.UnitTest/Source/UnitTestUtilities.cs b/source/P4VFS.UnitTest/Source/UnitTestUtilities.cs index 52a7c10..ed2101c 100644 --- a/source/P4VFS.UnitTest/Source/UnitTestUtilities.cs +++ b/source/P4VFS.UnitTest/Source/UnitTestUtilities.cs @@ -53,7 +53,7 @@ public void FileAttributeTest() Assert(ReconcilePreview(clientFolder).Any() == false); Assert(IsPlaceholderFile(clientFile) == false); - Assert(getAttr(clientFile) == FileAttributes.ReadOnly); + Assert(getAttr(clientFile).HasFlag(FileAttributes.ReadOnly)); File.SetAttributes(clientFile, FileAttributes.Normal); Assert(getAttr(clientFile) == FileAttributes.Normal);