Last active
November 11, 2016 09:01
-
-
Save tugberkugurlu/bb198435cdc40ea0213003d89254c773 to your computer and use it in GitHub Desktop.
Directory validation for write access
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Linq; | |
namespace ConsoleApplication4 | |
{ | |
// see: http://stackoverflow.com/a/6371533/463785 | |
// see: http://stackoverflow.com/questions/1281620/checking-for-directory-and-file-write-permissions-in-net | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var pathToTest = @"C:\Windows\System32"; | |
var pathValidationResult = DirectoryPathValidationResult.Chain(pathToTest, | |
IsDirectoryPathTooLong, | |
IsPathValid, | |
DirectoryExists, | |
IsDirectoryWriteable); | |
Console.WriteLine(pathValidationResult.IsSuccess); | |
if (!pathValidationResult.IsSuccess) | |
{ | |
Console.WriteLine(pathValidationResult.ErrorMessage); | |
} | |
} | |
private static DirectoryPathValidationResult IsDirectoryPathTooLong(NonNullable<string> directoryPath) | |
{ | |
try | |
{ | |
var _ = new DirectoryInfo(directoryPath); | |
} | |
catch (PathTooLongException) | |
{ | |
return DirectoryPathValidationResult.Failed($"The directory Path '{directoryPath}' is too long. On Windows-based platforms, paths must be less than 248 characters."); | |
} | |
catch (Exception) | |
{ | |
// swallow as we are only checking whether the path is too long for .NET to handle. | |
} | |
return DirectoryPathValidationResult.Success(); | |
} | |
private static DirectoryPathValidationResult IsPathValid(NonNullable<string> directoryPath) | |
{ | |
return (directoryPath.GetValue().IndexOfAny(Path.GetInvalidPathChars()) >= 0) == false | |
? DirectoryPathValidationResult.Success() | |
: DirectoryPathValidationResult.Failed($"The directory Path '{directoryPath}' contains invalid characters"); | |
} | |
private static DirectoryPathValidationResult DirectoryExists(NonNullable<string> directoryPath) | |
{ | |
return Directory.Exists(directoryPath) | |
? DirectoryPathValidationResult.Success() | |
: DirectoryPathValidationResult.Failed($"The directory '{directoryPath}' does not exist or the windows account does not access to it"); | |
} | |
private static DirectoryPathValidationResult IsDirectoryWriteable(NonNullable<string> directoryPath) | |
{ | |
var randomFileName = Guid.NewGuid().ToString("N"); | |
var combinedTestPath = Path.Combine(directoryPath, randomFileName); | |
try | |
{ | |
using (File.Create(combinedTestPath, 1, FileOptions.DeleteOnClose)) { } | |
} | |
catch (UnauthorizedAccessException) | |
{ | |
return DirectoryPathValidationResult.Failed($"Windows user account does not have write access for directory path '{directoryPath}'"); | |
} | |
catch (Exception ex) | |
{ | |
return DirectoryPathValidationResult.Failed($"Unable to check the write permissions for directory path '{directoryPath}': {ex.Message}"); | |
} | |
return DirectoryPathValidationResult.Success(); | |
} | |
} | |
/// <summary> | |
/// Wraps a reference type value which should not be null | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
public struct NonNullable<T> where T : class | |
{ | |
private readonly T _value; | |
/// <exception cref="ArgumentNullException">Thrown when the reference type <see cref="T" /> value is <code>null</code>.</exception> | |
public NonNullable(T value) | |
{ | |
if (value == null) throw new ArgumentNullException(nameof(value)); | |
_value = value; | |
} | |
/// <summary> | |
/// Unwaraps the reference type value of <see cref="NonNullable{T}" /> as <see cref="T" />. | |
/// </summary> | |
/// <remarks>See https://msdn.microsoft.com/en-us/library/ms229054(v=vs.100).aspx on why this is a method rather than a property.</remarks> | |
/// <returns>The reference type <see cref="T" /> value.</returns> | |
/// <exception cref="InvalidOperationException">Thrown when the reference type <see cref="T" /> value is <code>null</code>.</exception> | |
public T GetValue() | |
{ | |
if (_value == null) | |
{ | |
throw new InvalidOperationException($"Cannot access the Value of '{GetType()}' when it is null"); | |
} | |
return _value; | |
} | |
public override string ToString() => GetValue().ToString(); | |
public override int GetHashCode() => GetValue().GetHashCode(); | |
public override bool Equals(object obj) => GetValue().Equals(obj); | |
/// <exception cref="InvalidOperationException">Thrown when the reference type <see cref="T" /> value is <code>null</code>.</exception> | |
public static implicit operator T(NonNullable<T> value) | |
{ | |
return value.GetValue(); | |
} | |
/// <exception cref="ArgumentNullException">Thrown when the reference type <see cref="T" /> value is <code>null</code>.</exception> | |
public static implicit operator NonNullable<T>(T value) | |
{ | |
return new NonNullable<T>(value); | |
} | |
} | |
public class DirectoryPathValidationResult | |
{ | |
private DirectoryPathValidationResult() | |
{ | |
IsSuccess = true; | |
} | |
private DirectoryPathValidationResult(string errorMessage) | |
{ | |
if (errorMessage == null) throw new ArgumentNullException(nameof(errorMessage)); | |
IsSuccess = false; | |
ErrorMessage = errorMessage; | |
} | |
public bool IsSuccess { get; } | |
public string ErrorMessage { get; } | |
public static DirectoryPathValidationResult Success() => new DirectoryPathValidationResult(); | |
public static DirectoryPathValidationResult Failed(string message) => new DirectoryPathValidationResult(message); | |
public static DirectoryPathValidationResult Chain(NonNullable<string> directoryPath, params Func<NonNullable<string>, DirectoryPathValidationResult>[] funcs) | |
{ | |
if (funcs == null) throw new ArgumentNullException(nameof(funcs)); | |
return funcs.Aggregate<Func<NonNullable<string>, DirectoryPathValidationResult>, DirectoryPathValidationResult>(DirectoryPathValidationResult.Success(), | |
(toChainOn, toChainWith) => toChainOn.IsSuccess ? toChainWith(directoryPath) : toChainOn); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment