aboutsummaryrefslogtreecommitdiff
path: root/Emby.Server.Implementations/Library/PathExtensions.cs
diff options
context:
space:
mode:
authorBaronGreenback <jimcartlidge@yahoo.co.uk>2021-03-14 18:40:44 +0000
committerBaronGreenback <jimcartlidge@yahoo.co.uk>2021-03-14 18:40:44 +0000
commit4c7680e186ec76053f6d54e29e5cd67c5a0b17f7 (patch)
treecf21e8a3ac31487d4126aa0fceaa498473f02c43 /Emby.Server.Implementations/Library/PathExtensions.cs
parent6087831aa65398a6305570c4dc84f0bc2613b842 (diff)
parentbd70f562189e81d409caf2f4f67d8d495d4bbf1e (diff)
Merge remote-tracking branch 'upstream/master' into SubnetOverlappFix
Diffstat (limited to 'Emby.Server.Implementations/Library/PathExtensions.cs')
-rw-r--r--Emby.Server.Implementations/Library/PathExtensions.cs63
1 files changed, 63 insertions, 0 deletions
diff --git a/Emby.Server.Implementations/Library/PathExtensions.cs b/Emby.Server.Implementations/Library/PathExtensions.cs
index 06ff3e611..57d0c26b9 100644
--- a/Emby.Server.Implementations/Library/PathExtensions.cs
+++ b/Emby.Server.Implementations/Library/PathExtensions.cs
@@ -1,6 +1,8 @@
#nullable enable
using System;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
using System.Text.RegularExpressions;
namespace Emby.Server.Implementations.Library
@@ -47,5 +49,66 @@ namespace Emby.Server.Implementations.Library
return null;
}
+
+ /// <summary>
+ /// Replaces a sub path with another sub path and normalizes the final path.
+ /// </summary>
+ /// <param name="path">The original path.</param>
+ /// <param name="subPath">The original sub path.</param>
+ /// <param name="newSubPath">The new sub path.</param>
+ /// <param name="newPath">The result of the sub path replacement</param>
+ /// <returns>The path after replacing the sub path.</returns>
+ /// <exception cref="ArgumentNullException"><paramref name="path" />, <paramref name="newSubPath" /> or <paramref name="newSubPath" /> is empty.</exception>
+ public static bool TryReplaceSubPath(
+ [NotNullWhen(true)] this string? path,
+ [NotNullWhen(true)] string? subPath,
+ [NotNullWhen(true)] string? newSubPath,
+ [NotNullWhen(true)] out string? newPath)
+ {
+ newPath = null;
+
+ if (string.IsNullOrEmpty(path)
+ || string.IsNullOrEmpty(subPath)
+ || string.IsNullOrEmpty(newSubPath)
+ || subPath.Length > path.Length)
+ {
+ return false;
+ }
+
+ char oldDirectorySeparatorChar;
+ char newDirectorySeparatorChar;
+ // True normalization is still not possible https://github.com/dotnet/runtime/issues/2162
+ // The reasoning behind this is that a forward slash likely means it's a Linux path and
+ // so the whole path should be normalized to use / and vice versa for Windows (although Windows doesn't care much).
+ if (newSubPath.Contains('/', StringComparison.Ordinal))
+ {
+ oldDirectorySeparatorChar = '\\';
+ newDirectorySeparatorChar = '/';
+ }
+ else
+ {
+ oldDirectorySeparatorChar = '/';
+ newDirectorySeparatorChar = '\\';
+ }
+
+ path = path.Replace(oldDirectorySeparatorChar, newDirectorySeparatorChar);
+ subPath = subPath.Replace(oldDirectorySeparatorChar, newDirectorySeparatorChar);
+
+ // We have to ensure that the sub path ends with a directory separator otherwise we'll get weird results
+ // when the sub path matches a similar but in-complete subpath
+ var oldSubPathEndsWithSeparator = subPath[^1] == newDirectorySeparatorChar;
+ if (!path.StartsWith(subPath, StringComparison.OrdinalIgnoreCase)
+ || (!oldSubPathEndsWithSeparator && path[subPath.Length] != newDirectorySeparatorChar))
+ {
+ return false;
+ }
+
+ var newSubPathTrimmed = newSubPath.AsSpan().TrimEnd(newDirectorySeparatorChar);
+ // Ensure that the path with the old subpath removed starts with a leading dir separator
+ int idx = oldSubPathEndsWithSeparator ? subPath.Length - 1 : subPath.Length;
+ newPath = string.Concat(newSubPathTrimmed, path.AsSpan(idx));
+
+ return true;
+ }
}
}