Skip to content

Instantly share code, notes, and snippets.

@tugberkugurlu
Last active November 11, 2016 09:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tugberkugurlu/bb198435cdc40ea0213003d89254c773 to your computer and use it in GitHub Desktop.
Save tugberkugurlu/bb198435cdc40ea0213003d89254c773 to your computer and use it in GitHub Desktop.
Directory validation for write access
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