diff --git a/src/Umbraco.Core/IO/PhysicalFileSystem.cs b/src/Umbraco.Core/IO/PhysicalFileSystem.cs index 66ef095b04..e4edb2b86b 100644 --- a/src/Umbraco.Core/IO/PhysicalFileSystem.cs +++ b/src/Umbraco.Core/IO/PhysicalFileSystem.cs @@ -304,7 +304,13 @@ namespace Umbraco.Core.IO // permissions to reach that path, but it may nevertheless be outside of // our root path, due to relative segments, so better check if (IOHelper.PathStartsWith(path, _rootPath, Path.DirectorySeparatorChar)) + { + // this says that 4.7.2 supports long paths - but Windows does not + // https://docs.microsoft.com/en-us/dotnet/api/system.io.pathtoolongexception?view=netframework-4.7.2 + if (path.Length > 260) + throw new PathTooLongException($"Path {path} is too long."); return path; + } // nothing prevents us to reach the file, security-wise, yet it is outside // this filesystem's root - throw diff --git a/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs b/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs index 91e764c184..ab9b2cf73d 100644 --- a/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs +++ b/src/Umbraco.Tests/IO/PhysicalFileSystemTests.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Text; using System.Threading; using NUnit.Framework; @@ -44,6 +42,34 @@ namespace Umbraco.Tests.IO return "/Media/" + path; } + private string Repeat(string pattern, int count) + { + var text = new StringBuilder(); + for (var i = 0; i < count; i++) + text.Append(pattern); + return text.ToString(); + } + + [Test] + public void SaveFileTest() + { + var basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FileSysTests"); + + using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) + _fileSystem.AddFile("sub/f3.txt", ms); + + Assert.IsTrue(File.Exists(Path.Combine(basePath, "sub/f3.txt"))); + + var path = Repeat("bah/bah/", 50); + Assert.Less(260, path.Length); + + Assert.Throws(() => + { + using (var ms = new MemoryStream(Encoding.UTF8.GetBytes("foo"))) + _fileSystem.AddFile(path + "f3.txt", ms); + }); + } + [Test] public void GetFullPathTest() { @@ -60,14 +86,31 @@ namespace Umbraco.Tests.IO // - does properly normalize separators // - does throw on invalid paths + // works var path = _fileSystem.GetFullPath("foo.tmp"); Assert.AreEqual(Path.Combine(basePath, @"foo.tmp"), path); + // a very long relative path, which ends up being a short path, works + path = Repeat("bah/../", 50); + Assert.Less(260, path.Length); + path = _fileSystem.GetFullPath(path + "foo.tmp"); + Assert.AreEqual(Path.Combine(basePath, @"foo.tmp"), path); + + // works too path = _fileSystem.GetFullPath("foo/bar.tmp"); Assert.AreEqual(Path.Combine(basePath, @"foo\bar.tmp"), path); // that path is invalid as it would be outside the root directory Assert.Throws(() => _fileSystem.GetFullPath("../../foo.tmp")); + + // a very long path, which ends up being very long, works + path = Repeat("bah/bah/", 50); + Assert.Less(260, path.Length); + Assert.Throws(() => + { + path = _fileSystem.GetFullPath(path + "foo.tmp"); + Assert.Less(260, path.Length); // gets a >260 path and it's fine (but Windows will not like it) + }); } } }