Cleanup - file permission helper
This commit is contained in:
@@ -1,158 +1,195 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.IO;
|
||||
using Umbraco.Core.IO;
|
||||
using umbraco;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.PublishedCache.XmlPublishedCache;
|
||||
|
||||
namespace Umbraco.Web.Install
|
||||
{
|
||||
internal class FilePermissionHelper
|
||||
{
|
||||
internal static readonly string[] PermissionDirs = { SystemDirectories.Css, SystemDirectories.Config, SystemDirectories.Data, SystemDirectories.Media, SystemDirectories.Masterpages, SystemDirectories.Xslt, SystemDirectories.UserControls, SystemDirectories.Preview };
|
||||
internal static readonly string[] PermissionFiles = { };
|
||||
internal static readonly string[] PackagesPermissionsDirs = { SystemDirectories.Bin, SystemDirectories.Umbraco, SystemDirectories.UserControls, SystemDirectories.Packages };
|
||||
// ensure that these directories exist and Umbraco can write to them
|
||||
private static readonly string[] PermissionDirs = { SystemDirectories.Css, SystemDirectories.Config, SystemDirectories.Data, SystemDirectories.Media, SystemDirectories.Masterpages, SystemDirectories.Xslt, SystemDirectories.UserControls, SystemDirectories.Preview };
|
||||
private static readonly string[] PackagesPermissionsDirs = { SystemDirectories.Bin, SystemDirectories.Umbraco, SystemDirectories.UserControls, SystemDirectories.Packages };
|
||||
|
||||
public static bool RunFilePermissionTestSuite(out Dictionary<string, List<string>> errorReport)
|
||||
// ensure Umbraco can write to these files (the directories must exist)
|
||||
private static readonly string[] PermissionFiles = { };
|
||||
|
||||
public static bool RunFilePermissionTestSuite(out Dictionary<string, IEnumerable<string>> report)
|
||||
{
|
||||
errorReport = new Dictionary<string, List<string>>();
|
||||
report = new Dictionary<string, IEnumerable<string>>();
|
||||
|
||||
List<string> errors;
|
||||
IEnumerable<string> errors;
|
||||
|
||||
if (TestDirectories(PermissionDirs, out errors) == false)
|
||||
errorReport["Folder creation failed"] = errors.ToList();
|
||||
if (EnsureDirectories(PermissionDirs, out errors) == false)
|
||||
report["Folder creation failed"] = errors.ToList();
|
||||
|
||||
if (TestDirectories(PackagesPermissionsDirs, out errors) == false)
|
||||
errorReport["File writing for packages failed"] = errors.ToList();
|
||||
if (EnsureDirectories(PackagesPermissionsDirs, out errors) == false)
|
||||
report["File writing for packages failed"] = errors.ToList();
|
||||
|
||||
if (TestFiles(PermissionFiles, out errors) == false)
|
||||
errorReport["File writing failed"] = errors.ToList();
|
||||
if (EnsureFiles(PermissionFiles, out errors) == false)
|
||||
report["File writing failed"] = errors.ToList();
|
||||
|
||||
if (TestContentXml(out errors) == false)
|
||||
errorReport["Cache file writing failed"] = errors.ToList();
|
||||
if (TestFacade(out errors) == false)
|
||||
report["Facade environment check failed"] = errors.ToList();
|
||||
|
||||
if (TestFolderCreation(SystemDirectories.Media, out errors) == false)
|
||||
errorReport["Media folder creation failed"] = errors.ToList();
|
||||
if (EnsureCanCreateSubDirectory(SystemDirectories.Media, out errors) == false)
|
||||
report["Media folder creation failed"] = errors.ToList();
|
||||
|
||||
return errorReport.Any() == false;
|
||||
return report.Count == 0;
|
||||
}
|
||||
|
||||
public static bool TestDirectories(string[] directories, out List<string> errorReport)
|
||||
public static bool EnsureDirectories(string[] dirs, out IEnumerable<string> errors)
|
||||
{
|
||||
errorReport = new List<string>();
|
||||
bool succes = true;
|
||||
foreach (string dir in directories)
|
||||
List<string> temp = null;
|
||||
var success = true;
|
||||
foreach (var dir in dirs)
|
||||
{
|
||||
if (Directory.Exists(dir) == false) continue;
|
||||
// we don't want to create/ship unnecessary directories, so
|
||||
// here we just ensure we can access the directory, not create it
|
||||
var tryAccess = TryAccessDirectory(dir);
|
||||
if (tryAccess) continue;
|
||||
|
||||
bool result = SaveAndDeleteFile(IOHelper.MapPath(dir + "/configWizardPermissionTest.txt"));
|
||||
|
||||
if (result == false)
|
||||
{
|
||||
succes = false;
|
||||
errorReport.Add(dir);
|
||||
}
|
||||
if (temp == null) temp = new List<string>();
|
||||
temp.Add(dir);
|
||||
success = false;
|
||||
}
|
||||
|
||||
return succes;
|
||||
errors = success ? Enumerable.Empty<string>() : temp;
|
||||
return success;
|
||||
}
|
||||
|
||||
public static bool TestFiles(string[] files, out List<string> errorReport)
|
||||
public static bool EnsureFiles(string[] files, out IEnumerable<string> errors)
|
||||
{
|
||||
errorReport = new List<string>();
|
||||
bool succes = true;
|
||||
foreach (string file in files)
|
||||
List<string> temp = null;
|
||||
var success = true;
|
||||
foreach (var file in files)
|
||||
{
|
||||
bool result = OpenFileForWrite(IOHelper.MapPath(file));
|
||||
if (result == false)
|
||||
{
|
||||
errorReport.Add(file);
|
||||
succes = false;
|
||||
}
|
||||
var canWrite = TryWriteFile(file);
|
||||
if (canWrite) continue;
|
||||
|
||||
if (temp == null) temp = new List<string>();
|
||||
temp.Add(file);
|
||||
success = false;
|
||||
}
|
||||
|
||||
return succes;
|
||||
errors = success ? Enumerable.Empty<string>() : temp;
|
||||
return success;
|
||||
}
|
||||
|
||||
public static bool TestFolderCreation(string folder, out List<string> errorReport)
|
||||
public static bool EnsureCanCreateSubDirectory(string dir, out IEnumerable<string> errors)
|
||||
{
|
||||
errorReport = new List<string>();
|
||||
try
|
||||
{
|
||||
string tempDir = IOHelper.MapPath(folder + "/testCreatedByConfigWizard");
|
||||
Directory.CreateDirectory(tempDir);
|
||||
Directory.Delete(tempDir);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
errorReport.Add(folder);
|
||||
return false;
|
||||
}
|
||||
return EnsureCanCreateSubDirectories(new[] { dir }, out errors);
|
||||
}
|
||||
|
||||
public static bool TestContentXml(out List<string> errorReport)
|
||||
public static bool EnsureCanCreateSubDirectories(IEnumerable<string> dirs, out IEnumerable<string> errors)
|
||||
{
|
||||
errorReport = new List<string>();
|
||||
|
||||
// makes sense for xml cache only
|
||||
// fixme and to nucache that writes files too?
|
||||
var svc = FacadeServiceResolver.Current.Service as FacadeService;
|
||||
if (svc == null) return true;
|
||||
|
||||
// Test creating/saving/deleting a file in the same location as the content xml file
|
||||
// NOTE: We cannot modify the xml file directly because a background thread is responsible for
|
||||
// that and we might get lock issues.
|
||||
try
|
||||
List<string> temp = null;
|
||||
var success = true;
|
||||
foreach (var dir in dirs)
|
||||
{
|
||||
// xml cache will persist file, other caches may do something else
|
||||
svc.XmlStore.EnsureFilePermission();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
errorReport.Add(SystemFiles.ContentCacheXml);
|
||||
return false;
|
||||
var canCreate = TryCreateSubDirectory(dir);
|
||||
if (canCreate) continue;
|
||||
|
||||
if (temp == null) temp = new List<string>();
|
||||
temp.Add(dir);
|
||||
success = false;
|
||||
}
|
||||
|
||||
errors = success ? Enumerable.Empty<string>() : temp;
|
||||
return success;
|
||||
}
|
||||
|
||||
private static bool SaveAndDeleteFile(string file)
|
||||
public static bool TestFacade(out IEnumerable<string> errors)
|
||||
{
|
||||
var facadeService = FacadeServiceResolver.Current.Service;
|
||||
return facadeService.EnsureEnvironment(out errors);
|
||||
}
|
||||
|
||||
// tries to create a sub-directory
|
||||
// if successful, the sub-directory is deleted
|
||||
// creates the directory if needed - does not delete it
|
||||
private static bool TryCreateSubDirectory(string dir)
|
||||
{
|
||||
try
|
||||
{
|
||||
//first check if the directory of the file exists, and if not try to create that first.
|
||||
FileInfo fi = new FileInfo(file);
|
||||
if (fi.Directory.Exists == false)
|
||||
{
|
||||
fi.Directory.Create();
|
||||
}
|
||||
|
||||
File.WriteAllText(file,
|
||||
"This file has been created by the umbraco configuration wizard. It is safe to delete it!");
|
||||
File.Delete(file);
|
||||
var path = IOHelper.MapPath(dir + "/" + CreateRandomName());
|
||||
Directory.CreateDirectory(path);
|
||||
Directory.Delete(path);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static bool OpenFileForWrite(string file)
|
||||
// tries to create a file
|
||||
// if successful, the file is deleted
|
||||
// creates the directory if needed - does not delete it
|
||||
public static bool TryCreateDirectory(string dir)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.AppendText(file).Close();
|
||||
var dirPath = IOHelper.MapPath(dir);
|
||||
|
||||
if (Directory.Exists(dirPath) == false)
|
||||
Directory.CreateDirectory(dirPath);
|
||||
|
||||
var filePath = dirPath + "/" + CreateRandomName() + ".tmp";
|
||||
File.WriteAllText(filePath, "This is an Umbraco internal test file. It is safe to delete it.");
|
||||
File.Delete(filePath);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// tries to create a file
|
||||
// if successful, the file is deleted
|
||||
// if the directory does not exist, do nothing & success
|
||||
public static bool TryAccessDirectory(string dir)
|
||||
{
|
||||
try
|
||||
{
|
||||
var dirPath = IOHelper.MapPath(dir);
|
||||
|
||||
if (Directory.Exists(dirPath) == false)
|
||||
return true;
|
||||
|
||||
var filePath = dirPath + "/" + CreateRandomName() + ".tmp";
|
||||
File.WriteAllText(filePath, "This is an Umbraco internal test file. It is safe to delete it.");
|
||||
File.Delete(filePath);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// tries to write into a file
|
||||
// fails if the directory does not exist
|
||||
private static bool TryWriteFile(string file)
|
||||
{
|
||||
try
|
||||
{
|
||||
var path = IOHelper.MapPath(file);
|
||||
File.AppendText(path).Close();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static string CreateRandomName()
|
||||
{
|
||||
return "umbraco-test." + Guid.NewGuid().ToString("N").Substring(0, 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,17 +15,13 @@ namespace Umbraco.Web.Install.InstallSteps
|
||||
{
|
||||
public override InstallSetupResult Execute(object model)
|
||||
{
|
||||
//first validate file permissions
|
||||
var permissionsOk = true;
|
||||
Dictionary<string, List<string>> reportParts;
|
||||
|
||||
permissionsOk = FilePermissionHelper.RunFilePermissionTestSuite(out reportParts);
|
||||
// validate file permissions
|
||||
Dictionary<string, IEnumerable<string>> report;
|
||||
var permissionsOk = FilePermissionHelper.RunFilePermissionTestSuite(out report);
|
||||
|
||||
if (permissionsOk == false)
|
||||
{
|
||||
throw new InstallException("Permission check failed", "permissionsreport", new { errors = reportParts });
|
||||
}
|
||||
|
||||
throw new InstallException("Permission check failed", "permissionsreport", new { errors = report });
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -21,6 +22,8 @@ namespace Umbraco.Web.PublishedCache
|
||||
|
||||
protected IFacade CurrentFacade => FacadeAccessor.Facade;
|
||||
|
||||
public abstract bool EnsureEnvironment(out IEnumerable<string> errors);
|
||||
|
||||
public abstract IPublishedProperty CreateFragmentProperty(PublishedPropertyType propertyType, Guid itemKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null);
|
||||
|
||||
public abstract string EnterPreview(IUser user, int contentId);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -44,6 +45,13 @@ namespace Umbraco.Web.PublishedCache
|
||||
/// </summary>
|
||||
IFacadeAccessor FacadeAccessor { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that the facade has the proper environment to run.
|
||||
/// </summary>
|
||||
/// <param name="errors">The errors, if any.</param>
|
||||
/// <returns>A value indicating whether the facade has the proper environment to run.</returns>
|
||||
bool EnsureEnvironment(out IEnumerable<string> errors);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Preview
|
||||
|
||||
@@ -8,6 +8,7 @@ using CSharpTest.Net.Collections;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
@@ -21,6 +22,7 @@ using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Changes;
|
||||
using Umbraco.Web.Cache;
|
||||
using Umbraco.Web.Install;
|
||||
using Umbraco.Web.PublishedCache.NuCache.DataSource;
|
||||
using Umbraco.Web.PublishedCache.XmlPublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
@@ -210,6 +212,18 @@ namespace Umbraco.Web.PublishedCache.NuCache
|
||||
|
||||
#endregion
|
||||
|
||||
#region Environment
|
||||
|
||||
public override bool EnsureEnvironment(out IEnumerable<string> errors)
|
||||
{
|
||||
// must have app_data and be able to write files into it
|
||||
var ok = FilePermissionHelper.TryCreateDirectory(SystemDirectories.Data);
|
||||
errors = ok ? Enumerable.Empty<string>() : new[] { "NuCache local DB files." };
|
||||
return ok;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Populate Stores
|
||||
|
||||
// sudden panic... but in RepeatableRead can a content that I haven't already read, be removed
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
@@ -80,7 +81,29 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublishedCachesService Caches
|
||||
#region Environment
|
||||
|
||||
public override bool EnsureEnvironment(out IEnumerable<string> errors)
|
||||
{
|
||||
// Test creating/saving/deleting a file in the same location as the content xml file
|
||||
// NOTE: We cannot modify the xml file directly because a background thread is responsible for
|
||||
// that and we might get lock issues.
|
||||
try
|
||||
{
|
||||
XmlStore.EnsureFilePermission();
|
||||
errors = Enumerable.Empty<string>();
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
errors = new[] { SystemFiles.ContentCacheXml };
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Caches
|
||||
|
||||
public override IFacade CreateFacade(string previewToken)
|
||||
{
|
||||
@@ -100,7 +123,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublishedCachesService Preview
|
||||
#region Preview
|
||||
|
||||
public override string EnterPreview(IUser user, int contentId)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user