From cc7897a79a945626ea6d0c19e8a6b32cbf547d1d Mon Sep 17 00:00:00 2001 From: Rory& Date: Fri, 14 Aug 2026 11:32:13 +0200 Subject: Fix some consistency issues, some documentation --- Rhea.Nar/NarConsts.cs | 44 +++++++++++++++++++++++++ Rhea.Nar/NarWriter.cs | 84 ++++++++++++++++++++++-------------------------- Rhea.Nar/Rhea.Nar.csproj | 2 ++ 3 files changed, 84 insertions(+), 46 deletions(-) create mode 100644 Rhea.Nar/NarConsts.cs (limited to 'Rhea.Nar') diff --git a/Rhea.Nar/NarConsts.cs b/Rhea.Nar/NarConsts.cs new file mode 100644 index 0000000..f821449 --- /dev/null +++ b/Rhea.Nar/NarConsts.cs @@ -0,0 +1,44 @@ +namespace Rhea.Nar; + +/// Common strings/flags in NAR archives +public static class NarConsts +{ + /// Nix archive header + public static readonly byte[] Header = NarWriter.GetLengthPrefixedPadded("nix-archive-1"u8); + + /// Start of object marker + public static readonly byte[] LeftParen = NarWriter.GetLengthPrefixedPadded("("u8); + + /// End of object marker + public static readonly byte[] RightParen = NarWriter.GetLengthPrefixedPadded(")"u8); + + /// Indicates the node is a regular file + public static readonly byte[] Regular = NarWriter.GetLengthPrefixedPadded("regular"u8); + + /// Indicates the node is a directory + public static readonly byte[] Directory = NarWriter.GetLengthPrefixedPadded("directory"u8); + + /// Indicates the node is a symlink + public static readonly byte[] Symlink = NarWriter.GetLengthPrefixedPadded("symlink"u8); + + /// Indicates a directory entry + public static readonly byte[] Entry = NarWriter.GetLengthPrefixedPadded("entry"u8); + + /// Indicates a directory entry + public static readonly byte[] Node = NarWriter.GetLengthPrefixedPadded("node"u8); + + /// Indicates the name of a directory entry + public static readonly byte[] Name = NarWriter.GetLengthPrefixedPadded("name"u8); + + /// Indicates the target of a symlink + public static readonly byte[] Target = NarWriter.GetLengthPrefixedPadded("target"u8); + + /// Indicates the type of an entry + public static readonly byte[] Type = NarWriter.GetLengthPrefixedPadded("type"u8); + + /// Indicates that a regular file is executable + public static readonly byte[] Executable = NarWriter.GetLengthPrefixedPadded("executable"u8); + + /// Indicates the start of regular file contents + public static readonly byte[] Contents = NarWriter.GetLengthPrefixedPadded("contents"u8); +} \ No newline at end of file diff --git a/Rhea.Nar/NarWriter.cs b/Rhea.Nar/NarWriter.cs index 424f52a..49b5eb6 100644 --- a/Rhea.Nar/NarWriter.cs +++ b/Rhea.Nar/NarWriter.cs @@ -1,31 +1,8 @@ -using System.IO.Enumeration; -using System.Runtime.InteropServices; using ArcaneLibs; using ArcaneLibs.Extensions; namespace Rhea.Nar; -public ref struct NarConsts -{ - public static readonly byte[] Header = NarWriter.GetLengthPrefixedPadded("nix-archive-1"u8); - - public static readonly byte[] LeftParen = NarWriter.GetLengthPrefixedPadded("("u8); - public static readonly byte[] RightParen = NarWriter.GetLengthPrefixedPadded(")"u8); - - public static readonly byte[] Regular = NarWriter.GetLengthPrefixedPadded("regular"u8); - public static readonly byte[] Directory = NarWriter.GetLengthPrefixedPadded("directory"u8); - public static readonly byte[] Symlink = NarWriter.GetLengthPrefixedPadded("symlink"u8); - - public static readonly byte[] Entry = NarWriter.GetLengthPrefixedPadded("entry"u8); - public static readonly byte[] Name = NarWriter.GetLengthPrefixedPadded("name"u8); - public static readonly byte[] Target = NarWriter.GetLengthPrefixedPadded("target"u8); - public static readonly byte[] Node = NarWriter.GetLengthPrefixedPadded("node"u8); - public static readonly byte[] Type = NarWriter.GetLengthPrefixedPadded("type"u8); - public static readonly byte[] Executable = NarWriter.GetLengthPrefixedPadded("executable"u8); - - public static readonly byte[] Contents = NarWriter.GetLengthPrefixedPadded("contents"u8); -} - public class NarWriter { public Span GetHeader() @@ -42,19 +19,19 @@ public class NarWriter public IEnumerable GetNarStreamContentsInner(string path) { FileAttributes fattr = File.GetAttributes(path); - if (fattr.HasFlag(FileAttributes.Directory)) - foreach (var chunk in GetNarDirectoryContents(new DirectoryInfo(path))) - yield return chunk; - else + var linkTarget = new FileInfo(path).LinkTarget; + if (string.IsNullOrWhiteSpace(linkTarget)) { - var linkTarget = new FileInfo(path).LinkTarget; - if (string.IsNullOrWhiteSpace(linkTarget)) - foreach (var chunk in GetNarFileContents(new FileInfo(path))) + if (fattr.HasFlag(FileAttributes.Directory)) + foreach (var chunk in GetNarDirectoryContents(new DirectoryInfo(path))) yield return chunk; else - foreach (var chunk in GetNarSymlinkContents(new FileInfo(path))) + foreach (var chunk in GetNarFileContents(new FileInfo(path))) yield return chunk; } + else + foreach (var chunk in GetNarSymlinkContents(new FileInfo(path))) + yield return chunk; } private IEnumerable GetNarDirectoryContents(DirectoryInfo de) @@ -62,15 +39,19 @@ public class NarWriter yield return NarConsts.LeftParen; yield return NarConsts.Type; yield return NarConsts.Directory; - - foreach (var fe in FileUtils.EnumerateDirectory(de.FullName).OrderBy(x => x.Name)) + + foreach (var fe in FileUtils.EnumerateDirectory(de.FullName) + // .OrderBy(x=>x is DirectoryInfo ? 0 : 1) + // .ThenBy(x => x.Name, StringComparer.InvariantCultureIgnoreCase) + .OrderBy(x => x.Name, StringComparer.Ordinal) + ) { yield return NarConsts.Entry; yield return NarConsts.LeftParen; yield return NarConsts.Name; yield return GetLengthPrefixedPadded(fe.Name.AsBytes().ToArray()); - + yield return NarConsts.Node; foreach (var chunk in GetNarStreamContentsInner(fe.FullName)) yield return chunk; @@ -83,14 +64,26 @@ public class NarWriter private IEnumerable GetNarSymlinkContents(FileInfo fe) { - yield return NarConsts.LeftParen; - - yield return NarConsts.Type; - yield return NarConsts.Symlink; - yield return NarConsts.Target; - yield return GetLengthPrefixedPadded(fe.LinkTarget!.AsBytes().ToArray()); - - yield return NarConsts.RightParen; + // yield return NarConsts.LeftParen; + // + // yield return NarConsts.Type; + // yield return NarConsts.Symlink; + // yield return NarConsts.Target; + // yield return GetLengthPrefixedPadded(fe.LinkTarget!.AsBytes().ToArray()); + // + // yield return NarConsts.RightParen; + + yield return + [ + ..NarConsts.LeftParen, + + ..NarConsts.Type, + ..NarConsts.Symlink, + ..NarConsts.Target, + ..GetLengthPrefixedPadded(fe.LinkTarget!.AsBytes().ToArray()), + + ..NarConsts.RightParen + ]; } private IEnumerable GetNarFileContents(FileInfo fe) @@ -104,7 +97,10 @@ public class NarWriter || fe.UnixFileMode.HasFlag(UnixFileMode.GroupExecute) || fe.UnixFileMode.HasFlag(UnixFileMode.OtherExecute) ) + { yield return NarConsts.Executable; + yield return new byte[8]; + } var targetLength = Math.Ceiling(fe.Length / 8d) * 8UL; yield return NarConsts.Contents; @@ -135,11 +131,7 @@ public class NarWriter { byte[] unpadded = [..BitConverter.GetBytes((ulong)data.Length), .. data]; var targetLength = Math.Ceiling(unpadded.Length / 8d) * 8; - // Console.Write($"{unpadded.Length:X2} - "); - // unpadded.HexDump(); Array.Resize(ref unpadded, (int)targetLength); - // Console.Write($"{unpadded.Length:X2} - "); - // unpadded.HexDump(); return unpadded; } diff --git a/Rhea.Nar/Rhea.Nar.csproj b/Rhea.Nar/Rhea.Nar.csproj index bcfc328..7057327 100644 --- a/Rhea.Nar/Rhea.Nar.csproj +++ b/Rhea.Nar/Rhea.Nar.csproj @@ -5,6 +5,8 @@ enable enable true + true + true -- cgit 1.5.1