From a2687bfb59eadd3cd46c697de54607a37e50f834 Mon Sep 17 00:00:00 2001 From: Steve Lee Date: Sun, 5 Mar 2017 22:05:10 -0800 Subject: [PATCH] Allow profile directory creation failures for Service Account scenarios (#3244) XDG profile directory creation can fail for accounts that do not have home directories. The module analysis was trying to persist it's cache in an XDG profile directory. The cache is less critical than it once was, so it's reasonable to not cache if there is no good place to do so. Fixes #3011 --- .../CoreCLR/CorePsPlatform.cs | 36 ++++++++++++++++--- .../engine/Modules/AnalysisCache.cs | 17 +++++++-- test/powershell/Host/ConsoleHost.Tests.ps1 | 22 ++++++++++++ 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs index 62f84e8545..e9960a2abe 100644 --- a/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs +++ b/src/System.Management.Automation/CoreCLR/CorePsPlatform.cs @@ -261,7 +261,14 @@ namespace System.Management.Automation // create the xdg folder if needed if (!Directory.Exists(xdgDataHomeDefault)) { - Directory.CreateDirectory(xdgDataHomeDefault); + try + { + Directory.CreateDirectory(xdgDataHomeDefault); + } + catch (UnauthorizedAccessException) + { + //service accounts won't have permission to create user folder + } } return xdgDataHomeDefault; } @@ -277,7 +284,14 @@ namespace System.Management.Automation //xdg values have not been set if (!Directory.Exists(xdgModuleDefault)) //module folder not always guaranteed to exist { - Directory.CreateDirectory(xdgModuleDefault); + try + { + Directory.CreateDirectory(xdgModuleDefault); + } + catch (UnauthorizedAccessException) + { + //service accounts won't have permission to create user folder + } } return xdgModuleDefault; } @@ -296,7 +310,14 @@ namespace System.Management.Automation //xdg values have not been set if (!Directory.Exists(xdgCacheDefault)) //module folder not always guaranteed to exist { - Directory.CreateDirectory(xdgCacheDefault); + try + { + Directory.CreateDirectory(xdgCacheDefault); + } + catch (UnauthorizedAccessException) + { + //service accounts won't have permission to create user folder + } } return xdgCacheDefault; @@ -306,7 +327,14 @@ namespace System.Management.Automation { if (!Directory.Exists(Path.Combine(xdgcachehome, "powershell"))) { - Directory.CreateDirectory(Path.Combine(xdgcachehome, "powershell")); + try + { + Directory.CreateDirectory(Path.Combine(xdgcachehome, "powershell")); + } + catch (UnauthorizedAccessException) + { + //service accounts won't have permission to create user folder + } } return Path.Combine(xdgcachehome, "powershell"); diff --git a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs index 3e626f5402..1980958955 100644 --- a/src/System.Management.Automation/engine/Modules/AnalysisCache.cs +++ b/src/System.Management.Automation/engine/Modules/AnalysisCache.cs @@ -618,6 +618,8 @@ namespace System.Management.Automation private int _saveCacheToDiskQueued; + private bool _saveCacheToDisk = true; + public void QueueSerialization() { // We expect many modules to rapidly call for serialization. @@ -625,7 +627,7 @@ namespace System.Management.Automation // after it seems like we've stopped adding stuff to write out. This is // avoids blocking the pipeline thread waiting for the write to finish. // We want to make sure we only queue one task. - if (Interlocked.Increment(ref _saveCacheToDiskQueued) == 1) + if (_saveCacheToDisk && Interlocked.Increment(ref _saveCacheToDiskQueued) == 1) { Task.Run(async delegate { @@ -694,6 +696,8 @@ namespace System.Management.Automation private void Serialize(string filename) { AnalysisCacheData fromOtherProcess = null; + Diagnostics.Assert(_saveCacheToDisk != false, "Serialize should never be called without going through QueueSerialization which has a check"); + try { if (Utils.NativeFileExists(filename)) @@ -710,7 +714,16 @@ namespace System.Management.Automation var folder = Path.GetDirectoryName(filename); if (!Directory.Exists(folder)) { - Directory.CreateDirectory(folder); + try + { + Directory.CreateDirectory(folder); + } + catch (UnauthorizedAccessException) + { + // service accounts won't be able to create directory + _saveCacheToDisk = false; + return; + } } } } diff --git a/test/powershell/Host/ConsoleHost.Tests.ps1 b/test/powershell/Host/ConsoleHost.Tests.ps1 index 531187fc77..434a1dba99 100644 --- a/test/powershell/Host/ConsoleHost.Tests.ps1 +++ b/test/powershell/Host/ConsoleHost.Tests.ps1 @@ -381,6 +381,28 @@ foo } } } + + Context "Data, Config, and Cache locations" { + BeforeEach { + $XDG_CACHE_HOME = $env:XDG_CACHE_HOME + $XDG_DATA_HOME = $env:XDG_DATA_HOME + $XDG_CONFIG_HOME = $env:XDG_CONFIG_HOME + } + + AfterEach { + $env:XDG_CACHE_HOME = $XDG_CACHE_HOME + $env:XDG_DATA_HOME = $XDG_DATA_HOME + $env:XDG_CONFIG_HOME = $XDG_CONFIG_HOME + } + + It "Should start if Data, Config, and Cache location is not accessible" -skip:($IsWindows) { + $env:XDG_CACHE_HOME = "/dev/cpu" + $env:XDG_DATA_HOME = "/dev/cpu" + $env:XDG_CONFIG_HOME = "/dev/cpu" + $output = & powershell -noprofile -Command { (get-command).count } + [int]$output | Should BeGreaterThan 0 + } + } } Describe "Console host api tests" -Tag CI {