diff options
| author | BaronGreenback <jimcartlidge@yahoo.co.uk> | 2021-03-14 18:40:44 +0000 |
|---|---|---|
| committer | BaronGreenback <jimcartlidge@yahoo.co.uk> | 2021-03-14 18:40:44 +0000 |
| commit | 4c7680e186ec76053f6d54e29e5cd67c5a0b17f7 (patch) | |
| tree | cf21e8a3ac31487d4126aa0fceaa498473f02c43 /Emby.Server.Implementations/Library/PathExtensions.cs | |
| parent | 6087831aa65398a6305570c4dc84f0bc2613b842 (diff) | |
| parent | bd70f562189e81d409caf2f4f67d8d495d4bbf1e (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.cs | 63 |
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; + } } } |
