diff --git a/DebUnpack.cs b/DebUnpack.cs index ee03d6b..158d68b 100644 --- a/DebUnpack.cs +++ b/DebUnpack.cs @@ -123,7 +123,7 @@ sealed class DebEntry throw new ArgumentException("buffer too short"); } - name = Encoding.ASCII.GetString(buffer[0..16]); + name = Encoding.ASCII.GetString(buffer[0..16]).Trim(); // Trim any trailing whitespace mtime = long.Parse(Encoding.ASCII.GetString(buffer[16..28])); mode = int.Parse(Encoding.ASCII.GetString(buffer[28..34])); gid = int.Parse(Encoding.ASCII.GetString(buffer[34..40])); diff --git a/Program.cs b/Program.cs index 965a547..a4b8e0a 100644 --- a/Program.cs +++ b/Program.cs @@ -3,6 +3,9 @@ using Serilog; using Spectre.Console; using System.Text.Json; using System.Text; +using SharpCompress.Compressors.Xz; +using System.Formats.Tar; +using System.Diagnostics; namespace EdgeInstaller; @@ -222,71 +225,111 @@ public static partial class EdgeInstall RenderPackageAsTable(LatestVersion); - var versionPath = LatestVersion.Filename - .Replace("pool/main/m/", "") - .Replace(".deb", ""); - var versionsDir = Path.Join(Archdir, "Versions"); + var versionDir = Path.Join(versionsDir, LatestVersion.PackageName, LatestVersion.Version.ToString()); + Directory.CreateDirectory(versionDir); // Let's get and unpack the latest version - if (true)//!Directory.Exists(Path.Join(versionsDir, versionPath))) - { - using (MemoryStream debStream = - await AnsiConsole.Progress() - .Columns(new ProgressColumn[] - { + // for the moment we will always just grab + using (MemoryStream debStream = + await AnsiConsole.Progress() + .Columns(new ProgressColumn[] + { new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn(), new RemainingTimeColumn(), new SpinnerColumn(), - }) - .StartAsync(async ctx => - { - var task = ctx.AddTask(LatestVersion.Filename, new ProgressTaskSettings { AutoStart = false }); + }) + .StartAsync(async ctx => + { + var task = ctx.AddTask(LatestVersion.Filename, new ProgressTaskSettings { AutoStart = false }); - return await downloadStream(LatestVersion.Filename, task); - })) + return await downloadStream(LatestVersion.Filename, task); + })) + { + + if (!ValidateChecksum(debStream, LatestVersion.SHA256)) + { + AnsiConsole.MarkupLine("[red b]ERROR:[/] checksum did not validate"); + Environment.Exit(1); + } + + using (DebFile debfile = new DebFile(debStream)) { - if (!ValidateChecksum(debStream, LatestVersion.SHA256)) + // NOTE: deb entries have trailing / + DebEntry? dataEntry = debfile.fileEntries.Find(file => file.name == "data.tar.xz/"); + + if (dataEntry is null) { - AnsiConsole.MarkupLine("[red b]ERROR:[/] checksum did not validate"); + AnsiConsole.MarkupLine("[red b]ERROR:[/] debfile does not contain data.tar.xz"); Environment.Exit(1); } - using (DebFile debfile = new DebFile(debStream)) + // Looks like we have a hit. Lets try and extract it + + if (!debfile.getFile(dataEntry, out Stream dataStream)) { - foreach (var fileEntry in debfile.fileEntries) + AnsiConsole.MarkupLine("[red b]ERROR:[/] couldn't get stream for data.tar.xz"); + Environment.Exit(1); + } + + using (XZStream dataXZStream = new(dataStream)) + { + using (TarReader reader = new(dataXZStream)) { - AnsiConsole.MarkupLineInterpolated($"FileName: {fileEntry.name}"); - AnsiConsole.MarkupLineInterpolated($"FilePos: {fileEntry.offset}"); - AnsiConsole.MarkupLineInterpolated($"FileSize: {fileEntry.sizeBytes}"); - - // NOTE: This is dumb test code - // to verify the files are actually being "extracted" properly - - if (!debfile.getFile(fileEntry, out Stream contents)) + while (true) { - return 1; - } + var tarEntry = reader.GetNextEntry(); + if (tarEntry is null) + { + break; // TarReader returns null when we hit the end of the stream + } - // Now we write this to tmp. - // WARN: Without deleting these you will fill up your ram + AnsiConsole.MarkupLineInterpolated($"TarEntry {tarEntry.Name}"); + // work out where we need to put the extracted file + var filepath = Path.Combine(versionDir, tarEntry.Name); - var temp = Path.GetTempFileName(); + if (tarEntry.EntryType == TarEntryType.Directory) + { + // createDirectory doesn't fail if already exists + Directory.CreateDirectory(filepath); + continue; + } - using (var tmpfile = File.Open(temp, FileMode.Open)) - { - contents.CopyTo(tmpfile); - contents.Dispose(); + if (tarEntry.LinkName != "") + { + // Handle links manually + if (File.Exists(filepath)) + { + File.Delete(filepath); + } + File.CreateSymbolicLink(filepath, tarEntry.LinkName); + continue; // we are done with this file so keep going + } + + tarEntry.ExtractToFile(filepath, overwrite: true); } } } - } - return 0; + // Now assuming nothing broke before now we can copy the files into the system directories. + // WARN: This is dangerous stuff and involves making system calls. + + // NOTE: be sure when calling to other programs to wait until they exit. + + var Mover = new ProcessStartInfo(); + + Mover.FileName = "pkexec"; + Mover.Arguments = $"cp -dri {versionDir}/opt {versionDir}/usr /"; + Mover.UseShellExecute = true; + var pr = Process.Start(Mover); + pr?.WaitForExit(); + } } + + return 0; } /*TODO: - Check version diff --git a/edge-install.csproj b/edge-install.csproj index edd0b22..63b05b6 100644 --- a/edge-install.csproj +++ b/edge-install.csproj @@ -9,9 +9,9 @@ - +