diff --git a/src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs b/src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs
new file mode 100644
index 00000000..472fea41
--- /dev/null
+++ b/src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs
@@ -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
+{
+ ///
+ /// Helper class for MD5 hashing.
+ ///
+ internal static class Md5HashHelper
+ {
+ ///
+ /// Computes the MD5 hash of and returns it as Base64 string with all chars that are not allowed on file-paths replaced.
+ ///
+ /// The string that is hashed.
+ /// The MD5 has of as a Base64 string with all chars that are not allowed on file-paths replaced.
+ /// If is null or a empty string.
+ [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())
+ {
+ var data = md5.ComputeHash(Encoding.Default.GetBytes(value));
+ return Convert.ToBase64String(data).Replace('+', '-').Replace('/', '_').TrimEnd('=');
+ }
+ }
+ }
+}
diff --git a/src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs.meta b/src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs.meta
new file mode 100644
index 00000000..86ac4927
--- /dev/null
+++ b/src/NuGetForUnity/Editor/Helper/Md5HashHelper.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: fc68e365bd39a6943bfca8c9c13c4321
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/src/NuGetForUnity/Editor/Helper/NugetPackageTextureHelper.cs b/src/NuGetForUnity/Editor/Helper/NugetPackageTextureHelper.cs
index fad02bfc..3bcabbeb 100644
--- a/src/NuGetForUnity/Editor/Helper/NugetPackageTextureHelper.cs
+++ b/src/NuGetForUnity/Editor/Helper/NugetPackageTextureHelper.cs
@@ -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
{
///
@@ -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));
}
}
}
diff --git a/src/NuGetForUnity/Editor/PackageContentManager.cs b/src/NuGetForUnity/Editor/PackageContentManager.cs
index c59e99f4..3c8cf633 100644
--- a/src/NuGetForUnity/Editor/PackageContentManager.cs
+++ b/src/NuGetForUnity/Editor/PackageContentManager.cs
@@ -17,6 +17,8 @@ namespace NugetForUnity
///
internal static class PackageContentManager
{
+ private const int MaxPathLength = 260;
+
///
/// Deletes all files and folders associated with a package.
///
@@ -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))
{
@@ -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)
{
diff --git a/src/NuGetForUnity/Editor/PackageSource/NugetPackageSourceV2.cs b/src/NuGetForUnity/Editor/PackageSource/NugetPackageSourceV2.cs
index 36aee09d..f314e22e 100644
--- a/src/NuGetForUnity/Editor/PackageSource/NugetPackageSourceV2.cs
+++ b/src/NuGetForUnity/Editor/PackageSource/NugetPackageSourceV2.cs
@@ -443,6 +443,17 @@ public void OnAfterDeserialize()
}
}
+ private static void CopyIsManuallyInstalled(List newPackages, ICollection packagesToUpdate)
+ {
+ foreach (var newPackage in newPackages)
+ {
+ newPackage.IsManuallyInstalled =
+ packagesToUpdate.FirstOrDefault(packageToUpdate => packageToUpdate.Id.Equals(newPackage.Id, StringComparison.OrdinalIgnoreCase))
+ ?.IsManuallyInstalled ??
+ false;
+ }
+ }
+
///
/// 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.
@@ -519,16 +530,5 @@ private List GetUpdatesFallback(
NugetLogger.LogVerbose("NugetPackageSource.GetUpdatesFallback took {0} ms", stopwatch.ElapsedMilliseconds);
return updates;
}
-
- private static void CopyIsManuallyInstalled(List newPackages, ICollection packagesToUpdate)
- {
- foreach (var newPackage in newPackages)
- {
- newPackage.IsManuallyInstalled =
- packagesToUpdate.FirstOrDefault(packageToUpdate => packageToUpdate.Id.Equals(newPackage.Id, StringComparison.OrdinalIgnoreCase))
- ?.IsManuallyInstalled ??
- false;
- }
- }
}
}