|
|
|
@ -1,5 +1,6 @@
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Text.RegularExpressions;
|
|
|
|
|
using NzbDrone.Common.Extensions;
|
|
|
|
|
|
|
|
|
|
namespace NzbDrone.Common.Disk
|
|
|
|
@ -9,6 +10,8 @@ namespace NzbDrone.Common.Disk
|
|
|
|
|
private readonly string _path;
|
|
|
|
|
private readonly OsPathKind _kind;
|
|
|
|
|
|
|
|
|
|
private static readonly Regex UncPathRegex = new Regex(@"(?<unc>^\\\\(?:\?\\UNC\\)?[^\\]+\\[^\\]+)(?:\\|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
|
|
|
|
|
|
|
|
|
public OsPath(string path)
|
|
|
|
|
{
|
|
|
|
|
if (path == null)
|
|
|
|
@ -96,6 +99,19 @@ namespace NzbDrone.Common.Disk
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string TrimTrailingSlash(string path, OsPathKind kind)
|
|
|
|
|
{
|
|
|
|
|
switch (kind)
|
|
|
|
|
{
|
|
|
|
|
case OsPathKind.Windows when !path.EndsWith(":\\"):
|
|
|
|
|
return path.TrimEnd('\\');
|
|
|
|
|
case OsPathKind.Unix when path != "/":
|
|
|
|
|
return path.TrimEnd('/');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public OsPathKind Kind => _kind;
|
|
|
|
|
|
|
|
|
|
public bool IsWindowsPath => _kind == OsPathKind.Windows;
|
|
|
|
@ -130,7 +146,19 @@ namespace NzbDrone.Common.Disk
|
|
|
|
|
|
|
|
|
|
if (index == -1)
|
|
|
|
|
{
|
|
|
|
|
return new OsPath(null);
|
|
|
|
|
return Null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rootLength = GetRootLength();
|
|
|
|
|
|
|
|
|
|
if (rootLength == _path.Length)
|
|
|
|
|
{
|
|
|
|
|
return Null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (rootLength > index + 1)
|
|
|
|
|
{
|
|
|
|
|
return new OsPath(_path.Substring(0, rootLength));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new OsPath(_path.Substring(0, index), _kind).AsDirectory();
|
|
|
|
@ -139,6 +167,8 @@ namespace NzbDrone.Common.Disk
|
|
|
|
|
|
|
|
|
|
public string FullPath => _path;
|
|
|
|
|
|
|
|
|
|
public string PathWithoutTrailingSlash => TrimTrailingSlash(_path, _kind);
|
|
|
|
|
|
|
|
|
|
public string FileName
|
|
|
|
|
{
|
|
|
|
|
get
|
|
|
|
@ -161,6 +191,30 @@ namespace NzbDrone.Common.Disk
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Name
|
|
|
|
|
{
|
|
|
|
|
// Meant to behave similar to DirectoryInfo.Name
|
|
|
|
|
|
|
|
|
|
get
|
|
|
|
|
{
|
|
|
|
|
var index = GetFileNameIndex();
|
|
|
|
|
|
|
|
|
|
if (index == -1)
|
|
|
|
|
{
|
|
|
|
|
return PathWithoutTrailingSlash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var rootLength = GetRootLength();
|
|
|
|
|
|
|
|
|
|
if (rootLength > index + 1)
|
|
|
|
|
{
|
|
|
|
|
return _path.Substring(0, rootLength);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TrimTrailingSlash(_path.Substring(index).TrimStart('/', '\\'), _kind);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool IsValid => _path.IsPathValid(PathValidationType.CurrentOs);
|
|
|
|
|
|
|
|
|
|
private int GetFileNameIndex()
|
|
|
|
@ -190,11 +244,50 @@ namespace NzbDrone.Common.Disk
|
|
|
|
|
return index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private int GetRootLength()
|
|
|
|
|
{
|
|
|
|
|
if (!IsRooted)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_kind == OsPathKind.Unix)
|
|
|
|
|
{
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (_kind == OsPathKind.Windows)
|
|
|
|
|
{
|
|
|
|
|
if (HasWindowsDriveLetter(_path))
|
|
|
|
|
{
|
|
|
|
|
return 3;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var uncMatch = UncPathRegex.Match(_path);
|
|
|
|
|
|
|
|
|
|
// \\?\UNC\server\share\ or \\server\share
|
|
|
|
|
if (uncMatch.Success)
|
|
|
|
|
{
|
|
|
|
|
return uncMatch.Groups["unc"].Length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// \\?\C:\
|
|
|
|
|
if (_path.StartsWith(@"\\?\"))
|
|
|
|
|
{
|
|
|
|
|
return 7;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string[] GetFragments()
|
|
|
|
|
{
|
|
|
|
|
return _path.Split(new char[] { '\\', '/' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static OsPath Null => new (null);
|
|
|
|
|
|
|
|
|
|
public override string ToString()
|
|
|
|
|
{
|
|
|
|
|
return _path;
|
|
|
|
@ -267,6 +360,11 @@ namespace NzbDrone.Common.Disk
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool Equals(OsPath other)
|
|
|
|
|
{
|
|
|
|
|
return Equals(other, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool Equals(OsPath other, bool ignoreTrailingSlash)
|
|
|
|
|
{
|
|
|
|
|
if (ReferenceEquals(other, null))
|
|
|
|
|
{
|
|
|
|
@ -278,8 +376,8 @@ namespace NzbDrone.Common.Disk
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var left = _path;
|
|
|
|
|
var right = other._path;
|
|
|
|
|
var left = ignoreTrailingSlash ? PathWithoutTrailingSlash : _path;
|
|
|
|
|
var right = ignoreTrailingSlash ? other.PathWithoutTrailingSlash : other._path;
|
|
|
|
|
|
|
|
|
|
if (Kind == OsPathKind.Windows || other.Kind == OsPathKind.Windows)
|
|
|
|
|
{
|
|
|
|
|