Skip to content

Commit

Permalink
add special handeling of too long path's
Browse files Browse the repository at this point in the history
  • Loading branch information
JoC0de committed Jan 5, 2025
1 parent 0751451 commit 703bdb6
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 51 deletions.
49 changes: 49 additions & 0 deletions src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#pragma warning disable SA1512,SA1124 // Single-line comments should not be followed by blank line

#region No ReShaper

using System;
using System.Security.Cryptography;
using System.Text;
using JetBrains.Annotations;

// ReSharper disable All
// needed because 'JetBrains.Annotations.NotNull' and 'System.Diagnostics.CodeAnalysis.NotNull' collide if this file is compiled with a never version of Unity / C#
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;

// ReSharper restore All

#endregion

#pragma warning restore SA1512,SA1124 // Single-line comments should not be followed by blank line

namespace NugetForUnity.Helper
{
/// <summary>
/// Helper class for MD5 hashing.
/// </summary>
internal static class Md5HashHelper
{
/// <summary>
/// Computes the MD5 hash of <paramref name="value" /> and returns it as Base64 string with all chars that are not allowed on file-paths replaced.
/// </summary>
/// <param name="value">The string that is hashed.</param>
/// <returns>The MD5 has of <paramref name="value" /> as a Base64 string with all chars that are not allowed on file-paths replaced.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="value" /> is null or a empty string.</exception>
[SuppressMessage("Design", "CA5351", Justification = "Only use MD5 hash as cache key / not security relevant.")]
[NotNull]
public static string GetFileNameSafeHash([NotNull] string value)
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentNullException(nameof(value));
}

using (var md5 = new MD5CryptoServiceProvider())

Check warning on line 42 in src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs

View workflow job for this annotation

GitHub Actions / Pack .NET Core Global Tool (CLI) and PluginAPI

'MD5CryptoServiceProvider' is obsolete: 'Derived cryptographic types are obsolete. Use the Create method on the base type instead.' (https://aka.ms/dotnet-warnings/SYSLIB0021)

Check warning on line 42 in src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs

View workflow job for this annotation

GitHub Actions / Pack .NET Core Global Tool (CLI) and PluginAPI

'MD5CryptoServiceProvider' is obsolete: 'Derived cryptographic types are obsolete. Use the Create method on the base type instead.' (https://aka.ms/dotnet-warnings/SYSLIB0021)

Check warning on line 42 in src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs

View workflow job for this annotation

GitHub Actions / Pack .NET Core Global Tool (CLI) and PluginAPI

'MD5CryptoServiceProvider' is obsolete: 'Derived cryptographic types are obsolete. Use the Create method on the base type instead.' (https://aka.ms/dotnet-warnings/SYSLIB0021)
{
var data = md5.ComputeHash(Encoding.Default.GetBytes(value));
return Convert.ToBase64String(data).Replace('+', '-').Replace('/', '_').TrimEnd('=');
}
}
}
}
11 changes: 11 additions & 0 deletions src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

36 changes: 2 additions & 34 deletions src/NuGetForUnity/Editor/Helper/NugetPackageTextureHelper.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,14 @@
#pragma warning disable SA1512,SA1124 // Single-line comments should not be followed by blank line

#if UNITY_2022_1_OR_NEWER
#if UNITY_2022_1_OR_NEWER
using UnityEditor;
#endif

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using UnityEngine;
using UnityEngine.Networking;

#region No ReShaper

// ReSharper disable All
// needed because 'JetBrains.Annotations.NotNull' and 'System.Diagnostics.CodeAnalysis.NotNull' collide if this file is compiled with a never version of Unity / C#
using SuppressMessageAttribute = System.Diagnostics.CodeAnalysis.SuppressMessageAttribute;

// ReSharper restore All

#endregion

#pragma warning restore SA1512,SA1124 // Single-line comments should not be followed by blank line

namespace NugetForUnity.Helper
{
/// <summary>
Expand Down Expand Up @@ -129,23 +113,7 @@ private static void CacheTextureOnDisk([NotNull] string cacheFilePath, [NotNull]
[NotNull]
private static string GetCacheFilePath([NotNull] string url)
{
return Path.Combine(Application.temporaryCachePath, GetHash(url));
}

[SuppressMessage("Design", "CA5351", Justification = "Only use MD5 hash as cache key / not security relevant.")]
[NotNull]
private static string GetHash([NotNull] string s)
{
if (string.IsNullOrEmpty(s))
{
throw new ArgumentNullException(nameof(s));
}

using (var md5 = new MD5CryptoServiceProvider())
{
var data = md5.ComputeHash(Encoding.Default.GetBytes(s));
return Convert.ToBase64String(data).Replace('+', '-').Replace('/', '_').TrimEnd('=');
}
return Path.Combine(Application.temporaryCachePath, Md5HashHelper.GetFileNameSafeHash(url));
}
}
}
50 changes: 44 additions & 6 deletions src/NuGetForUnity/Editor/PackageContentManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ namespace NugetForUnity
/// </summary>
internal static class PackageContentManager
{
private const int MaxPathLength = 260;

/// <summary>
/// Deletes all files and folders associated with a package.
/// </summary>
Expand Down Expand Up @@ -316,15 +318,31 @@ internal static string ExtractPackageEntry([NotNull] ZipArchiveEntry entry, [Not
return null;
}

var directory = Path.GetDirectoryName(filePath) ?? throw new InvalidOperationException($"Failed to get directory name of '{filePath}'");
Directory.CreateDirectory(directory);
if (Directory.Exists(filePath))
try
{
Debug.LogWarning($"The path {filePath} refers to an existing directory. Overwriting it may lead to data loss.");
return null;
if (Directory.Exists(filePath))
{
Debug.LogWarning($"The path {filePath} refers to an existing directory. Overwriting it may lead to data loss.");
return null;
}

var directory = Path.GetDirectoryName(filePath) ??
throw new InvalidOperationException($"Failed to get directory name of '{filePath}'");
Directory.CreateDirectory(directory);

entry.ExtractToFile(filePath, true);
}
catch (Exception exception) when (exception is PathTooLongException ||
(exception is DirectoryNotFoundException && filePath.Length >= MaxPathLength))
{
// path is to long (normally on windows) -> try to use shorter path
// we only do this when we get a exception because it can be that we are on a system that supports longer paths
var longFilePath = filePath;
filePath = DetermineShorterFilePath(entry, baseDir);

entry.ExtractToFile(filePath, true);
NugetLogger.LogVerbose("The target file path '{0}' was to long -> we shortened it to '{1}'.", longFilePath, filePath);
entry.ExtractToFile(filePath, true);
}

if (filePath.EndsWith(".pdb", StringComparison.OrdinalIgnoreCase) && !PortableSymbolFileHelper.IsPortableSymbolFile(filePath))
{
Expand Down Expand Up @@ -402,6 +420,26 @@ internal static void MoveInstalledPackages(string oldPath, string newPath)
}
}

private static string DetermineShorterFilePath(ZipArchiveEntry entry, string baseDir)
{
var filePath = Path.GetFullPath(Path.Combine(baseDir, entry.Name));
if (filePath.Length < MaxPathLength && !File.Exists(filePath))
{
// placing the file in the base-directory is enough to make the path usable.
return filePath;
}

filePath = Path.GetFullPath(Path.Combine(baseDir, Md5HashHelper.GetFileNameSafeHash(entry.FullName)));
if (filePath.Length + entry.Name.Length + 1 < MaxPathLength)
{
// we have enough space to keep the file name
return $"{filePath}_{entry.Name}";
}

// only add the file extension
return filePath + Path.GetExtension(entry.Name);
}

[NotNull]
private static string GetPackageOutsideInstallDirectory([NotNull] INugetPackageIdentifier package)
{
Expand Down
22 changes: 11 additions & 11 deletions src/NuGetForUnity/Editor/PackageSource/NugetPackageSourceV2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,17 @@ public void OnAfterDeserialize()
}
}

private static void CopyIsManuallyInstalled(List<INugetPackage> newPackages, ICollection<INugetPackage> packagesToUpdate)
{
foreach (var newPackage in newPackages)
{
newPackage.IsManuallyInstalled =
packagesToUpdate.FirstOrDefault(packageToUpdate => packageToUpdate.Id.Equals(newPackage.Id, StringComparison.OrdinalIgnoreCase))
?.IsManuallyInstalled ??
false;
}
}

/// <summary>
/// Builds a list of NugetPackages from the XML returned from the HTTP GET request issued at the given URL.
/// Note that NuGet uses an Atom-feed (XML Syndicaton) superset called OData.
Expand Down Expand Up @@ -519,16 +530,5 @@ private List<INugetPackage> GetUpdatesFallback(
NugetLogger.LogVerbose("NugetPackageSource.GetUpdatesFallback took {0} ms", stopwatch.ElapsedMilliseconds);
return updates;
}

private static void CopyIsManuallyInstalled(List<INugetPackage> newPackages, ICollection<INugetPackage> packagesToUpdate)
{
foreach (var newPackage in newPackages)
{
newPackage.IsManuallyInstalled =
packagesToUpdate.FirstOrDefault(packageToUpdate => packageToUpdate.Id.Equals(newPackage.Id, StringComparison.OrdinalIgnoreCase))
?.IsManuallyInstalled ??
false;
}
}
}
}

0 comments on commit 703bdb6

Please sign in to comment.