On macOS (and Linux), downloading and extracting ModCompile fails due to Zip library
See original GitHub issueDescription
Steps to Reproduce
- Install
tModLoader.Mac.v0.11.2.2.zip
with the installer - Install Visual Studio for macOS, go to Check for Updates and change to the Beta or Preview to satisfy Mono >v5.20 requirement
- Start Terraria, go to the Enable Developer Mode view
- Click through until you hit “Extra libraries are required to build mods”.
- Click on Download
Expected behavior
Download should complete and the view should update to indicate that ModCompiler has been downloaded.
Actual behavior
The download bar finishes but the view does not update.
The following lines appear in the log file:
[04:26:30] [1/DEBUG] [tML]: Web Request: https://github.com/tModLoader/tModLoader/releases/download/v0.11.2.2/ModCompile_XNA.zip
[04:26:30] [Thread Pool Worker/DEBUG] [tML]: Web Request: https://github-production-release-asset-2e65be.s3.amazonaws.com/39425864/d1e9ad80-a79c-11e9-8b6a-30eca7de68fc?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20190720%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20190720T012926Z&X-Amz-Expires=300&X-Amz-Signature=80b183f8e6371440807d15461d3602fc7d3f2276735609296afb20b9e9a408e2&X-Amz-SignedHeaders=host&actor_id=0&response-content-disposition=attachment%3B filename%3DModCompile_XNA.zip&response-content-type=application%2Foctet-stream
[04:26:33] [Thread Pool Worker/ERROR] [tML]: Problem during extracting of mod compile files for
System.ArgumentException: Path cannot be the empty string or all whitespace.
Parameter name: path
at System.IO.Directory.CreateDirectory (String path) [0x00016] in mscorlib.dll
at Ionic.Zip.ZipEntry.InternalExtract (String baseDir, Stream outstream, String password) [0x00298] in data-0x108cd2000
at Ionic.Zip.ZipEntry.Extract (String baseDirectory) [0x00000] in data-0x108cd2000
at Ionic.Zip.ZipFile._InternalExtractAll (String path, Boolean overrideExtractExistingProperty) [0x00152] in data-0x108cd2000
at Ionic.Zip.ZipFile.ExtractAll (String path, ExtractExistingFileAction extractExistingFile) [0x00007] in data-0x108cd2000
at Terraria.ModLoader.UI.UIDeveloperModeHelp.Extract (String zipFile, Boolean deleteFiles) [0x0005f] in tModLoader.exe
at Terraria.ModLoader.UI.UIDeveloperModeHelp+<>c__DisplayClass14_0.<DownloadModCompile>b__1 () [0x00000] in tModLoader.exe
Reproduction frequency
Every time.
Versions
tModLoader v0.11.2.2
Mods
None
Additional Information
The zip library seems to be so old that it’s archived on CodePlex. I was able to download and compile it to investigate the problem.
Ultimately the issue is that the library replaces all forward slashes (/
) with backslashes (\
), then goes to use Path.GetDirectoryName
on it, producing an empty string on macOS. This occurs because the directory separator on macOS is the forward slash, instead of the backslash. The replacement is probably done because the library only supported Windows and Mono support was coincidental:
Is this thing supported on Mono/Linux? It’s not supported at all. But, it apparently works on Mono/Ubuntu. I don’t test it that way. If you’d like to volunteer, let me know.
private void InternalExtract(string baseDir, Stream outstream, string password)
{
// ...
// ↓ 1. The filename is processed to `targetFileName`
// This method does various replacements but most importantly:
// outFileName = outFileName.Replace("/","\\");
if (ValidateOutput(baseDir, outstream, out targetFileName))
{
// ...
}
// ...
if (targetFileName != null)
{
// ...
targetFileName += ".tmp";
// ↓ 2. Due to the path being invalid, this method returns an empty string
var dirName = Path.GetDirectoryName(targetFileName);
if (!Directory.Exists(dirName))
{
// ↓ 3. Exception occurs here because dirName is empty
Directory.CreateDirectory(dirName);
}
One solution could be to download and include the project from the CodePlex archive and patch it like so:
diff --git a/ZipEntry.Extract.cs b/ZipEntry.Extract.cs
index 4c1613b..13ecac2 100644
--- a/ZipEntry.Extract.cs
+++ b/ZipEntry.Extract.cs
@@ -1414,7 +1414,7 @@ namespace Ionic.Zip
outFileName = Path.Combine(basedir, f);
// workitem 10639
- outFileName = outFileName.Replace("/","\\");
+ outFileName = outFileName.Replace("/", Path.DirectorySeparatorChar.ToString());
// check if it is a directory
if ((IsDirectory) || (FileName.EndsWith("/")))
A better solution would probably be to find an alternative Zip library that has cross-platform support, or if .NET’s zip support is better nowadays, use that.
Issue Analytics
- State:
- Created 4 years ago
- Comments:6 (2 by maintainers)
Honestly now that we actually target .NET 4.5 this is an option, but to save us changing too much, we’ll probably just patch it with MonoMod, or use the fork
Seems relevant to me assuming it beeing issue with downloading + extracting said data on tModLoader on Unix for
ModCompile
dir.