From 7b3f7f4ad47528540143f7598b22d34ee5a1962d Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 6 Oct 2017 11:47:25 +1100 Subject: [PATCH 1/3] U4-10503 Umbraco plugins cache files should be stored in the same local temp location as the umbraco xml cache file --- .../Configuration/GlobalSettings.cs | 35 ++++++++++++++----- ...ntentXmlStorage.cs => LocalTempStorage.cs} | 2 +- src/Umbraco.Core/IO/SystemFiles.cs | 8 ++--- src/Umbraco.Core/PluginManager.cs | 22 ++++++++++-- src/Umbraco.Core/Umbraco.Core.csproj | 2 +- 5 files changed, 51 insertions(+), 18 deletions(-) rename src/Umbraco.Core/Configuration/{ContentXmlStorage.cs => LocalTempStorage.cs} (75%) diff --git a/src/Umbraco.Core/Configuration/GlobalSettings.cs b/src/Umbraco.Core/Configuration/GlobalSettings.cs index 02f3322ec9..395502d1b2 100644 --- a/src/Umbraco.Core/Configuration/GlobalSettings.cs +++ b/src/Umbraco.Core/Configuration/GlobalSettings.cs @@ -538,24 +538,41 @@ namespace Umbraco.Core.Configuration internal static bool ContentCacheXmlStoredInCodeGen { - get { return ContentCacheXmlStorageLocation == ContentXmlStorage.AspNetTemp; } + get { return LocalTempStorageLocation == LocalTempStorage.AspNetTemp; } } - - internal static ContentXmlStorage ContentCacheXmlStorageLocation + + /// + /// This is the location type to store temporary files such as cache files or other localized files for a given machine + /// + /// + /// Currently used for the xml cache file and the plugin cache files + /// + internal static LocalTempStorage LocalTempStorageLocation { get - { + { + //there's a bunch of backwards compat config checks here.... + + //This is the current one + if (ConfigurationManager.AppSettings.ContainsKey("umbracoLocalTempStorage")) + { + return Enum.Parse(ConfigurationManager.AppSettings["umbracoLocalTempStorage"]); + } + + //This one is old if (ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLStorage")) { - return Enum.Parse(ConfigurationManager.AppSettings["umbracoContentXMLStorage"]); - } + return Enum.Parse(ConfigurationManager.AppSettings["umbracoContentXMLStorage"]); + } + + //This one is older if (ConfigurationManager.AppSettings.ContainsKey("umbracoContentXMLUseLocalTemp")) { return bool.Parse(ConfigurationManager.AppSettings["umbracoContentXMLUseLocalTemp"]) - ? ContentXmlStorage.AspNetTemp - : ContentXmlStorage.Default; + ? LocalTempStorage.AspNetTemp + : LocalTempStorage.Default; } - return ContentXmlStorage.Default; + return LocalTempStorage.Default; } } diff --git a/src/Umbraco.Core/Configuration/ContentXmlStorage.cs b/src/Umbraco.Core/Configuration/LocalTempStorage.cs similarity index 75% rename from src/Umbraco.Core/Configuration/ContentXmlStorage.cs rename to src/Umbraco.Core/Configuration/LocalTempStorage.cs index 7cbbc70675..d41f7d1925 100644 --- a/src/Umbraco.Core/Configuration/ContentXmlStorage.cs +++ b/src/Umbraco.Core/Configuration/LocalTempStorage.cs @@ -1,6 +1,6 @@ namespace Umbraco.Core.Configuration { - internal enum ContentXmlStorage + internal enum LocalTempStorage { Default, AspNetTemp, diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs index 437ddd3ef7..412849d5b0 100644 --- a/src/Umbraco.Core/IO/SystemFiles.cs +++ b/src/Umbraco.Core/IO/SystemFiles.cs @@ -73,11 +73,11 @@ namespace Umbraco.Core.IO { get { - switch (GlobalSettings.ContentCacheXmlStorageLocation) + switch (GlobalSettings.LocalTempStorageLocation) { - case ContentXmlStorage.AspNetTemp: + case LocalTempStorage.AspNetTemp: return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config"); - case ContentXmlStorage.EnvironmentTemp: + case LocalTempStorage.EnvironmentTemp: var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoXml", //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back @@ -85,7 +85,7 @@ namespace Umbraco.Core.IO // utilizing an old path appDomainHash); return Path.Combine(cachePath, "umbraco.config"); - case ContentXmlStorage.Default: + case LocalTempStorage.Default: return IOHelper.ReturnPath("umbracoContentXML", "~/App_Data/umbraco.config"); default: throw new ArgumentOutOfRangeException(); diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index f90163d181..b6a72f74cf 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Reflection; using System.Text; using System.Threading; +using System.Web; using System.Web.Compilation; using Umbraco.Core.Cache; using Umbraco.Core.IO; @@ -15,6 +16,7 @@ using Umbraco.Core.Persistence.SqlSyntax; using Umbraco.Core.Profiling; using Umbraco.Core.PropertyEditors; using umbraco.interfaces; +using Umbraco.Core.Configuration; using File = System.IO.File; namespace Umbraco.Core @@ -426,9 +428,23 @@ namespace Umbraco.Core } private string GetPluginListFilePath() - { - var filename = "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".list"; - return Path.Combine(_tempFolder, filename); + { + switch (GlobalSettings.LocalTempStorageLocation) + { + case LocalTempStorage.AspNetTemp: + return Path.Combine(HttpRuntime.CodegenDir, "umbraco-plugins.list"); + case LocalTempStorage.EnvironmentTemp: + var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); + var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoPlugins", + //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // utilizing an old path + appDomainHash); + return Path.Combine(cachePath, "umbraco-plugins.list"); + case LocalTempStorage.Default: + default: + return Path.Combine(_tempFolder, "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".list"); + } } private string GetPluginHashFilePath() diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index c4c1d58fdc..7de98685da 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -198,7 +198,7 @@ - + From bee75803f7932eec5ee295d969a2cde8a3aea51d Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 6 Oct 2017 11:51:27 +1100 Subject: [PATCH 2/3] Adds file exist checks --- src/Umbraco.Core/PluginManager.cs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index b6a72f74cf..9bcca8982a 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -82,21 +82,23 @@ namespace Umbraco.Core RequiresRescanning = (CachedAssembliesHash != CurrentAssembliesHash) || CachedAssembliesHash == string.Empty; //if they have changed, we need to write the new file if (RequiresRescanning) - { - // if the hash has changed, clear out the persisted list no matter what, this will force - // rescanning of all plugin types including lazy ones. - // http://issues.umbraco.org/issue/U4-4789 - File.Delete(pluginListFile); + { + // if the hash has changed, clear out the persisted list no matter what, this will force + // rescanning of all plugin types including lazy ones. + // http://issues.umbraco.org/issue/U4-4789 + if(File.Exists(pluginListFile)) + File.Delete(pluginListFile); WriteCachePluginsHash(); } } else - { - // if the hash has changed, clear out the persisted list no matter what, this will force - // rescanning of all plugin types including lazy ones. + { + // if the hash has changed, clear out the persisted list no matter what, this will force + // rescanning of all plugin types including lazy ones. // http://issues.umbraco.org/issue/U4-4789 - File.Delete(pluginListFile); + if (File.Exists(pluginListFile)) + File.Delete(pluginListFile); // always set to true if we're not detecting (generally only for testing) RequiresRescanning = true; From 901614711874e51ed7e27dc07c68c7550897ffdd Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 6 Oct 2017 12:11:20 +1100 Subject: [PATCH 3/3] Streamlines temp folder name so it's consistent, ensure the folder exists before writing to it --- src/Umbraco.Core/IO/SystemFiles.cs | 8 +++--- src/Umbraco.Core/PluginManager.cs | 43 +++++++++++++++++++++++------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Core/IO/SystemFiles.cs b/src/Umbraco.Core/IO/SystemFiles.cs index 412849d5b0..ccf8ea5b2c 100644 --- a/src/Umbraco.Core/IO/SystemFiles.cs +++ b/src/Umbraco.Core/IO/SystemFiles.cs @@ -79,10 +79,10 @@ namespace Umbraco.Core.IO return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco.config"); case LocalTempStorage.EnvironmentTemp: var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); - var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoXml", - //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back - // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not - // utilizing an old path + var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", + //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // utilizing an old path appDomainHash); return Path.Combine(cachePath, "umbraco.config"); case LocalTempStorage.Default: diff --git a/src/Umbraco.Core/PluginManager.cs b/src/Umbraco.Core/PluginManager.cs index 9bcca8982a..0489093712 100644 --- a/src/Umbraco.Core/PluginManager.cs +++ b/src/Umbraco.Core/PluginManager.cs @@ -235,6 +235,14 @@ namespace Umbraco.Core private void WriteCachePluginsHash() { var filePath = GetPluginHashFilePath(); + + // be absolutely sure the folder exists + var folder = Path.GetDirectoryName(filePath); + if (folder == null) + throw new InvalidOperationException("The folder could not be determined for the file " + filePath); + if (Directory.Exists(folder) == false) + Directory.CreateDirectory(folder); + File.WriteAllText(filePath, CurrentAssembliesHash.ToString(), Encoding.UTF8); } @@ -434,10 +442,10 @@ namespace Umbraco.Core switch (GlobalSettings.LocalTempStorageLocation) { case LocalTempStorage.AspNetTemp: - return Path.Combine(HttpRuntime.CodegenDir, "umbraco-plugins.list"); + return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco-plugins.list"); case LocalTempStorage.EnvironmentTemp: var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); - var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoPlugins", + var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not // utilizing an old path @@ -451,18 +459,35 @@ namespace Umbraco.Core private string GetPluginHashFilePath() { - var filename = "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".hash"; - return Path.Combine(_tempFolder, filename); + switch (GlobalSettings.LocalTempStorageLocation) + { + case LocalTempStorage.AspNetTemp: + return Path.Combine(HttpRuntime.CodegenDir, @"UmbracoData\umbraco-plugins.hash"); + case LocalTempStorage.EnvironmentTemp: + var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1(); + var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", + //include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back + // to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not + // utilizing an old path + appDomainHash); + return Path.Combine(cachePath, "umbraco-plugins.hash"); + case LocalTempStorage.Default: + default: + return Path.Combine(_tempFolder, "umbraco-plugins." + NetworkHelper.FileSafeMachineName + ".hash"); + } } internal void WriteCache() { - // be absolutely sure - if (Directory.Exists(_tempFolder) == false) - Directory.CreateDirectory(_tempFolder); - - var filePath = GetPluginListFilePath(); + var filePath = GetPluginListFilePath(); + // be absolutely sure the folder exists + var folder = Path.GetDirectoryName(filePath); + if (folder == null) + throw new InvalidOperationException("The folder could not be determined for the file " + filePath); + if (Directory.Exists(folder) == false) + Directory.CreateDirectory(folder); + using (var stream = GetFileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None, ListFileOpenWriteTimeout)) using (var writer = new StreamWriter(stream)) {