diff --git a/Tests/LibraryTests/SquashFs/SquashFixtures.cs b/Tests/LibraryTests/SquashFs/SquashFixtures.cs
index 7ff6f2cb9..b66cb5f1e 100644
--- a/Tests/LibraryTests/SquashFs/SquashFixtures.cs
+++ b/Tests/LibraryTests/SquashFs/SquashFixtures.cs
@@ -33,14 +33,15 @@ namespace LibraryTests.SquashFs;
///
/// The SquashFS test images. When squashfs-tools (4.5 or later) is on the machine, they are built fresh from the
/// recipe below by that mksquashfs, once per test run, and the reader tests run on those; the images embedded in the
-/// assembly, made the same way with squashfs-tools 4.7.5, are only the fallback where the tool is absent. So on a
-/// machine with the tool, nothing in the repository's binaries is trusted or even opened.
+/// assembly, made the same way with squashfs-tools 4.7.5, are the fallback where the tool is absent. If the tool
+/// was built without xattr support, only the xattr image uses its embedded fallback; the other images are built
+/// fresh and all reader tests still run.
///
internal static class SquashFixtures
{
private const string TextLine = "a line of text that compresses well, over and over\n";
private static readonly object Gate = new();
- private static string? _built;
+ private static IReadOnlyDictionary? _built;
/// The 300,000-byte text of text.bin.
public static string Text
@@ -88,14 +89,13 @@ public static byte[] Mixed
}
}
- /// A seekable copy of an image: freshly built when mksquashfs is available, else the embedded one.
+ /// A seekable copy of an image: freshly built when supported by mksquashfs, else the embedded one.
public static Stream Open(string name)
{
- var built = Built();
var image = new MemoryStream();
- if (built is not null)
+ if (Built().TryGetValue(name, out var path))
{
- using var file = File.OpenRead(Path.Combine(built, name));
+ using var file = File.OpenRead(path);
file.CopyTo(image);
}
else
@@ -108,23 +108,22 @@ public static Stream Open(string name)
return image;
}
- /// The folder holding the freshly built images, or null when they cannot be built here.
- private static string? Built()
+ /// The freshly built images; missing entries use their embedded fallback.
+ private static IReadOnlyDictionary Built()
{
lock (Gate)
{
if (_built is not null)
{
- return _built.Length == 0 ? null : _built;
+ return _built;
}
if (Environment.OSVersion.Platform != PlatformID.Unix || !ToolExists("mksquashfs") || !ToolExists("ln"))
{
- _built = "";
- return null;
+ _built = new Dictionary();
+ return _built;
}
var work = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "squashfs-fixtures-" + Path.GetRandomFileName()));
- Build(work.FullName);
- _built = work.FullName;
+ _built = Build(work.FullName);
return _built;
}
}
@@ -142,7 +141,7 @@ public static Stream Open(string name)
/// -xattrs-add, which puts an attribute on every inode: the link is an extended symlink inode and the image
/// has an xattr table. The other three are built with -no-xattrs.
///
- private static void Build(string work)
+ private static IReadOnlyDictionary Build(string work)
{
var ext = Path.Combine(work, "ext");
Directory.CreateDirectory(Path.Combine(ext, "dir"));
@@ -187,11 +186,28 @@ private static void Build(string work)
Run("mksquashfs", new[] { ext, Path.Combine(work, "extended-inodes.sqsh"), "-comp", "gzip", "-Xcompression-level", "6", "-b", "128K" }.Concat(noXattrs).ToArray());
Run("mksquashfs", new[] { huge, Path.Combine(work, "huge-sparse.sqsh"), "-comp", "gzip", "-Xcompression-level", "6", "-b", "1M" }.Concat(noXattrs).ToArray());
Run("mksquashfs", new[] { bigRoot, Path.Combine(work, "big-root.sqsh"), "-comp", "gzip", "-b", "128K" }.Concat(noXattrs).ToArray());
- Run("mksquashfs", new[] { xattrSymlink, Path.Combine(work, "xattr-symlink.sqsh"), "-comp", "gzip", "-b", "128K", "-xattrs-add", "trusted.test=1" }.Concat(flags).ToArray());
+ var xattrImage = Path.Combine(work, "xattr-symlink.sqsh");
+ var builtXattrs = Run("mksquashfs", new[] { xattrSymlink, xattrImage, "-comp", "gzip", "-b", "128K", "-xattrs-add", "trusted.test=1" }.Concat(flags).ToArray(), allowUnsupportedXattrs: true);
+ if (!builtXattrs)
+ {
+ File.Delete(xattrImage);
+ }
Directory.Delete(ext, recursive: true);
Directory.Delete(huge, recursive: true);
Directory.Delete(bigRoot, recursive: true);
Directory.Delete(xattrSymlink, recursive: true);
+
+ var images = new Dictionary
+ {
+ ["extended-inodes.sqsh"] = Path.Combine(work, "extended-inodes.sqsh"),
+ ["huge-sparse.sqsh"] = Path.Combine(work, "huge-sparse.sqsh"),
+ ["big-root.sqsh"] = Path.Combine(work, "big-root.sqsh")
+ };
+ if (builtXattrs)
+ {
+ images.Add("xattr-symlink.sqsh", xattrImage);
+ }
+ return images;
}
private static void Write(Stream stream, string ascii)
@@ -215,6 +231,11 @@ private static bool ToolExists(string tool)
}
private static void Run(string tool, params string[] args)
+ {
+ Run(tool, args, allowUnsupportedXattrs: false);
+ }
+
+ private static bool Run(string tool, string[] args, bool allowUnsupportedXattrs)
{
// quoted by hand: ProcessStartInfo.ArgumentList is not in .NET Framework
var arguments = string.Join(" ", args.Select(a => "\"" + a.Replace("\"", "\\\"") + "\""));
@@ -224,7 +245,12 @@ private static void Run(string tool, params string[] args)
process.WaitForExit();
if (process.ExitCode != 0)
{
+ if (allowUnsupportedXattrs && process.ExitCode == 1 && error.Trim() == "mksquashfs: xattrs are unsupported in this build")
+ {
+ return false;
+ }
throw new InvalidOperationException($"{tool} failed ({process.ExitCode}): {error}");
}
+ return true;
}
}