示例#1
0
        public Conclusion MembootKexec(Tasker tasker, Object syncObject = null)
        {
            tasker.SetStatus(Resources.Membooting);
            if (!hakchi.Shell.IsOnline)
            {
                return(Conclusion.Abort);
            }

            // load appropriate kernel
            byte[] kernel;
            if (stockKernel != null && stockKernel.Length > 0)
            {
                kernel = stockKernel.ToArray();
            }
            else
            {
                stockKernel = null;
                kernel      = hakchi.Hmod.GetMembootImage().ToArray();
            }

            // memboot using kexec (no way to force clovershell or shell)
            try
            {
                hakchi.Shell.ExecuteSimple("uistop");
                hakchi.Shell.ExecuteSimple("mkdir -p /tmp/kexec/", throwOnNonZero: true);
                hakchi.UploadFile(
                    Path.Combine(Program.BaseDirectoryInternal, "tools", "arm", "kexec.static"),
                    "/tmp/kexec/kexec");
                hakchi.UploadFile(
                    Path.Combine(Program.BaseDirectoryInternal, "tools", "arm", "unpackbootimg.static"),
                    "/tmp/kexec/unpackbootimg");

                TrackableStream kernelStream = new TrackableStream(kernel);
                kernelStream.OnProgress += tasker.OnProgress;
                hakchi.Shell.Execute(
                    command: "cat > /tmp/kexec/boot.img; cd /tmp/kexec/; ./unpackbootimg -i boot.img",
                    stdin: kernelStream,
                    throwOnNonZero: true
                    );

                hakchi.Shell.ExecuteSimple("cd /tmp/kexec/ && ./kexec -l -t zImage boot.img-zImage \"--command-line=$(cat boot.img-cmdline)\" --ramdisk=boot.img-ramdisk.gz --atags", 0, true);
                hakchi.Shell.ExecuteSimple("cd /tmp/; umount -ar", 0);
                try
                {
                    hakchi.Shell.ExecuteSimple("/tmp/kexec/kexec -e", 100);
                }
                catch { } // no-op
            }
            catch
            {
                try
                {
                    hakchi.Shell.ExecuteSimple("uistart");
                }
                catch { } // no-op
                throw;
            }

            return(Conclusion.Success);
        }
示例#2
0
        public static TaskFunc FlashUboot(Fel.UbootType type)
        {
            return((Tasker tasker, Object syncObject) =>
            {
                tasker.SetStatus(Resources.FlashingUboot);
                TrackableStream uboot;
                if (type == Fel.UbootType.Normal)
                {
                    uboot = new TrackableStream(Resources.uboot);
                }
                else
                {
                    uboot = new TrackableStream(Resources.ubootSD);
                }

                if (uboot.Length > 655360)
                {
                    throw new Exception(Resources.InvalidUbootSize + " " + uboot.Length);
                }

                uboot.OnProgress += tasker.OnProgress;

                hakchi.Shell.Execute("cat > /uboot.bin", uboot, null, null, 0, true);
                MemoryStream flashLog = new MemoryStream();
                var splitStream = new SplitterStream(flashLog).AddStreams(Program.debugStreams);
                if (hakchi.Shell.Execute("hakchi flashBoot2 /uboot.bin 8 5", null, splitStream) != 0)
                {
                    using (var sr = new StreamReader(flashLog))
                    {
                        throw new Exception(sr.ReadToEnd());
                    }
                }
                return Conclusion.Success;
            });
        }
示例#3
0
        public static Conclusion Memboot(Tasker tasker, Object syncObject = null)
        {
            tasker.SetStatus(Resources.Membooting);
            if (!hakchi.Shell.IsOnline)
            {
                return(Conclusion.Abort);
            }

            // get kernel image (only custom kernel with this method)
            byte[] kernel = hakchi.Hmod.GetMembootImage().ToArray();

            // override arguments
            string addedArgs = "";

            if (ConfigIni.Instance.ForceClovershell)
            {
                addedArgs = " hakchi-clovershell";
            }
            else if (ConfigIni.Instance.ForceNetwork)
            {
                addedArgs = " hakchi-shell";
            }

            // use detached-fallback script and up-to-date boot.img
            try
            {
                hakchi.Shell.ExecuteSimple("uistop");
                hakchi.Shell.ExecuteSimple("mkdir -p /tmp/kexec/", throwOnNonZero: true);
                hakchi.UploadFile(
                    Path.Combine(Program.BaseDirectoryInternal, "tools", "arm", "kexec.static"),
                    "/tmp/kexec/kexec");
                hakchi.UploadFile(
                    Path.Combine(Program.BaseDirectoryInternal, "tools", "arm", "detached-fallback"),
                    "/tmp/kexec/detached-fallback");

                TrackableStream kernelStream = new TrackableStream(kernel);
                kernelStream.OnProgress += tasker.OnProgress;
                hakchi.UploadFile(kernelStream, "/tmp/kexec/boot.img", false);

                try
                {
                    hakchi.Shell.ExecuteSimple("cd /tmp/kexec/; /bin/sh /tmp/kexec/detached-fallback recovery /tmp/kexec/boot.img" + addedArgs, 100);
                }
                catch { } // no-op
            }
            catch
            {
                try
                {
                    hakchi.Shell.ExecuteSimple("uistart");
                }
                catch { } // no-op
                throw;
            }

            return(Conclusion.Success);
        }
示例#4
0
 public static TaskFunc TransferBaseHmods(string transferPath = "/hakchi/transfer")
 {
     return((Tasker tasker, Object syncObject) =>
     {
         tasker.SetStatus(Resources.TransferringMods);
         var escapedTransferPath = Shared.EscapeShellArgument(transferPath);
         var hmodStream = new TrackableStream(Resources.baseHmods);
         hmodStream.OnProgress += tasker.OnProgress;
         hakchi.Shell.Execute($"mkdir -p {escapedTransferPath}", null, null, null, 0, true);
         hakchi.Shell.Execute($"tar -xvC {escapedTransferPath}", hmodStream, null, null, 0, true);
         return Conclusion.Success;
     });
 }
示例#5
0
        public static TaskFunc TransferBaseHmods(string transferPath = "/hakchi/transfer")
        {
            return((Tasker tasker, Object syncObject) =>
            {
                tasker.SetStatus(Resources.TransferringMods);
                var escapedTransferPath = Shared.EscapeShellArgument(transferPath);

                using (var baseHmods = File.OpenRead(Path.Combine(Program.BaseDirectoryInternal, "basehmods.tar")))
                    using (var hmodStream = new TrackableStream(baseHmods))
                    {
                        hmodStream.OnProgress += tasker.OnProgress;
                        hakchi.Shell.Execute($"mkdir -p {escapedTransferPath}", null, null, null, 0, true);
                        hakchi.Shell.Execute($"tar -xvC {escapedTransferPath} --exclude='./hakchi.hmod'", hmodStream, null, null, 0, true);
                    }
                return Conclusion.Success;
            });
        }
示例#6
0
        public static TaskFunc TransferHmod(string transferPath, string hmod)
        {
            return((Tasker tasker, Object syncObject) =>
            {
                tasker.SetStatus(Resources.TransferringMods);
                var modName = hmod + ".hmod";
                foreach (var dir in Shared.hmodDirectories)
                {
                    string hmodHakchiPath = Shared.EscapeShellArgument($"{transferPath}/{modName}");
                    if (Directory.Exists(Path.Combine(dir, modName)))
                    {
                        hakchi.Shell.ExecuteSimple($"mkdir -p {hmodHakchiPath}");
                        using (var hmodTar = new TarStream(Path.Combine(dir, modName)))
                        {
                            if (hmodTar.Length > 0)
                            {
                                using (TrackableStream hmodStream = new TrackableStream(hmodTar))
                                {
                                    hmodStream.OnProgress += tasker.OnProgress;

                                    hakchi.Shell.Execute($"tar -xvC {hmodHakchiPath}", hmodStream, null, null, 0, true);
                                }
                            }
                        }
                        break;
                    }
                    if (File.Exists(Path.Combine(dir, modName)))
                    {
                        hakchi.Shell.ExecuteSimple($"mkdir -p {hmodHakchiPath}");
                        using (var hmodStream = new TrackableFileStream(Path.Combine(dir, modName), FileMode.Open))
                        {
                            hmodStream.OnProgress += tasker.OnProgress;

                            hakchi.Shell.Execute($"tar -xzvC {hmodHakchiPath}", hmodStream, null, null, 0, true);
                        }
                        break;
                    }
                }
                return Conclusion.Success;
            });
        }
示例#7
0
        public static TaskFunc ExtractArchive(String fileName, string destinationFolder)
        {
            return((Tasker tasker, Object syncObject) =>
            {
                using (var fileStream = File.OpenRead(fileName))
                    using (var trackStream = new TrackableStream(fileStream))
                    {
                        trackStream.OnProgress += tasker.OnProgress;

                        using (var reader = ReaderFactory.Open(trackStream))
                        {
                            reader.WriteAllToDirectory(destinationFolder, new SharpCompress.Common.ExtractionOptions()
                            {
                                ExtractFullPath = true, Overwrite = true, PreserveFileTime = true
                            });

                            return Conclusion.Success;
                        }
                    }
            });
        }
示例#8
0
        public override Stream OpenWrite()
        {
            string tempFileName    = Path.GetTempFileName();
            var    trackableStream = new TrackableStream(new FileStream(tempFileName, FileMode.Create, FileAccess.ReadWrite, FileShare.None));

            trackableStream.Closing += delegate(object source, EventArgs e)
            {
                var innerStream = ((TrackableStream)source).InnerStream;
                innerStream.Seek(0L, SeekOrigin.Begin);
                Write(innerStream);
            };
            trackableStream.Closed += delegate
            {
                var fileInfo = new FileInfo(tempFileName);
                if (fileInfo.Exists)
                {
                    fileInfo.Delete();
                }
            };
            return(trackableStream);
        }
示例#9
0
        public Conclusion Memboot(Tasker tasker, Object syncObject = null)
        {
            // load appropriate kernel
            byte[] kernel;
            if (stockKernel != null && stockKernel.Length > 0)
            {
                kernel = stockKernel.ToArray();
            }
            else
            {
                stockKernel = null; // double-safety
                kernel      = hakchi.GetMembootImage().ToArray();
            }

            tasker.SetStatus(Resources.Membooting);
            if (hakchi.Shell.IsOnline)
            {
                // override arguments
                string addedArgs = ConfigIni.Instance.ForceClovershell ? " hakchi-clovershell" : "";

                // skip to built-in recovery if running latest version
                if (stockKernel == null && hakchi.CanInteract && !hakchi.SystemEligibleForRootfsUpdate())
                {
                    if (hakchi.Shell.Execute("[ -e /bin/detached ]") == 0) // detached recovery function?
                    {
                        try
                        {
                            hakchi.Shell.ExecuteSimple("/bin/detached recovery" + addedArgs, 100);
                        }
                        catch { } // no-op
                        return(Conclusion.Success);
                    }
                }

                try
                {
                    hakchi.Shell.ExecuteSimple("uistop");
                    hakchi.Shell.ExecuteSimple("mkdir -p /tmp/kexec/", throwOnNonZero: true);
                    hakchi.UploadFile(
                        Path.Combine(Program.BaseDirectoryInternal, "tools", "arm", "kexec.static"),
                        "/tmp/kexec/kexec");

                    TrackableStream kernelStream = new TrackableStream(kernel);
                    kernelStream.OnProgress += tasker.OnProgress;
                    if (stockKernel == null)
                    {
                        hakchi.UploadFile(
                            Path.Combine(Program.BaseDirectoryInternal, "tools", "arm", "detached-fallback"),
                            "/tmp/kexec/detached-fallback");
                        hakchi.UploadFile(kernelStream, "/tmp/kexec/boot.img", false);
                        try
                        {
                            hakchi.Shell.ExecuteSimple("cd /tmp/kexec/; /bin/sh /tmp/kexec/detached-fallback recovery /tmp/kexec/boot.img" + addedArgs, 100);
                        }
                        catch { } // no-op
                    }
                    else
                    {
                        hakchi.UploadFile(
                            Path.Combine(Program.BaseDirectoryInternal, "tools", "arm", "unpackbootimg.static"),
                            "/tmp/kexec/unpackbootimg");
                        hakchi.Shell.Execute(
                            command: "cat > /tmp/kexec/boot.img; cd /tmp/kexec/; ./unpackbootimg -i boot.img",
                            stdin: kernelStream,
                            throwOnNonZero: true
                            );
                        hakchi.Shell.ExecuteSimple("cd /tmp/kexec/ && ./kexec -l -t zImage boot.img-zImage \"--command-line=$(cat boot.img-cmdline)\" --ramdisk=boot.img-ramdisk.gz --atags", 0, true);
                        hakchi.Shell.ExecuteSimple("cd /tmp/; umount -ar", 0);
                        try
                        {
                            hakchi.Shell.ExecuteSimple("/tmp/kexec/kexec -e", 100);
                        }
                        catch { } // no-op
                    }
                }
                catch
                {
                    try
                    {
                        hakchi.Shell.ExecuteSimple("uistart");
                    }
                    catch { } // no-op
                    throw;
                }
            }
            else
            {
                // check and adjust kernel size
                var size = Shared.CalcKernelSize(kernel);
                if (size > kernel.Length || size > Fel.transfer_max_size)
                {
                    throw new Exception(Resources.InvalidKernelSize + " " + size);
                }
                size = (size + Fel.sector_size - 1) / Fel.sector_size;
                size = size * Fel.sector_size;
                if (kernel.Length != size)
                {
                    var newK = new byte[size];
                    Array.Copy(kernel, newK, kernel.Length);
                    kernel = newK;
                }

                // clovershell override "hex-edit" boot.img
                if (stockKernel == null && ConfigIni.Instance.ForceClovershell)
                {
                    kernel.InPlaceStringEdit(64, 512, 0, (string str) => {
                        if (str.IndexOf("hakchi-shell") != -1)
                        {
                            return(str.Replace("hakchi-shell", "hakchi-clovershell"));
                        }
                        else
                        {
                            return(str + " hakchi-clovershell");
                        }
                    });
                }

                // upload kernel through fel
                int progress    = 0;
                int maxProgress = (int)((double)kernel.Length / (double)67000 + 50);
                fel.WriteMemory(Fel.transfer_base_m, kernel,
                                delegate(Fel.CurrentAction action, string command)
                {
                    switch (action)
                    {
                    case Fel.CurrentAction.WritingMemory:
                        tasker.SetStatus(Resources.UploadingKernel);
                        break;
                    }
                    progress++;
                    tasker.SetProgress(progress, maxProgress);
                }
                                );

                var bootCommand = string.Format("boota {0:x}", Fel.transfer_base_m);
                tasker.SetStatus(Resources.ExecutingCommand + " " + bootCommand);
                fel.RunUbootCmd(bootCommand, true);
            }
            return(Conclusion.Success);
        }
示例#10
0
        public void Load()
        {
            string[] list = new string[] { };

            var repoResponse = HTTPHelpers.GetHTTPResponseStreamAsync(RepositoryPackURL);

            repoResponse.Wait();

            if (repoResponse.Result.Status == HttpStatusCode.OK)
            {
                // Start pack processing
                var tempDict        = new Dictionary <string, Item>();
                var trackableStream = new TrackableStream(repoResponse.Result.Stream);
                trackableStream.OnProgress += (long current, long total) => {
                    RepositoryProgress?.Invoke(current, repoResponse.Result.Length);
                };
                using (var reader = ReaderFactory.Open(trackableStream))
                {
                    while (reader.MoveToNextEntry())
                    {
                        if (Regex.Match(reader.Entry.Key, @"^(?:\./)?list$", RegexOptions.IgnoreCase).Success)
                        {
                            list = Regex.Replace(StreamToString(reader.OpenEntryStream()), @"[\r\n]+", "\n").Split("\n"[0]);
                        }

                        if (Regex.Match(reader.Entry.Key, @"^(?:\./)?readme.md$", RegexOptions.IgnoreCase).Success)
                        {
                            Readme = StreamToString(reader.OpenEntryStream());
                        }

                        var match = Regex.Match(reader.Entry.Key, @"^(?:\./)?([^/]+)/(extract|link|md5|sha1|readme(?:\.(?:md|txt)?)?)$", RegexOptions.IgnoreCase);
                        if (match.Success)
                        {
                            var mod      = match.Groups[1].ToString();
                            var fileName = match.Groups[2].ToString();

                            Item item;

                            if (!tempDict.TryGetValue(mod, out item))
                            {
                                item = new Item(mod);
                                tempDict.Add(mod, item);
                            }

                            switch (fileName.ToLower())
                            {
                            case "extract":
                                item.setExtract(true);
                                break;

                            case "link":
                                item.setURL(StreamToString(reader.OpenEntryStream()).Trim());
                                break;

                            case "md5":
                                item.setMD5(StreamToString(reader.OpenEntryStream()).Trim());
                                break;

                            case "sha1":
                                item.setSHA1(StreamToString(reader.OpenEntryStream()).Trim());
                                break;

                            case "readme":
                            case "readme.txt":
                            case "readme.md":
                                item.setReadme(StreamToString(reader.OpenEntryStream()).Trim(), fileName.EndsWith(".md"));
                                break;
                            }
                        }
                    }
                }

                if (list.Length == 0)
                {
                    list = tempDict.Keys.ToArray();
                }

                foreach (var key in tempDict.Keys.ToArray())
                {
                    var item = tempDict[key];
                    if (list.Contains(key))
                    {
                        Items.Add(item);
                    }
                    tempDict.Remove(key);
                }
                tempDict.Clear();
                tempDict = null;
                Items.Sort((x, y) => x.Name.CompareTo(y.Name));
                RepositoryLoaded?.Invoke(Items.ToArray());
                return;
                // End pack processing
            }

            var taskList = HTTPHelpers.GetHTTPResponseStringAsync(RepositoryListURL);

            taskList.Wait();

            list = (taskList.Result ?? "").Split("\n"[0]);

            for (int i = 0; i < list.Length; i++)
            {
                var  mod         = list[i];
                Item item        = new Item(mod);
                var  taskExtract = HTTPHelpers.GetHTTPStatusCodeAsync($"{RepositoryURL}{mod}/extract");
                var  taskURL     = HTTPHelpers.GetHTTPResponseStringAsync($"{RepositoryURL}{mod}/link");
                var  taskMD5     = HTTPHelpers.GetHTTPResponseStringAsync($"{RepositoryURL}{mod}/md5");
                var  taskSHA1    = HTTPHelpers.GetHTTPResponseStringAsync($"{RepositoryURL}{mod}/sha1");

                taskExtract.Wait();
                taskURL.Wait();
                taskMD5.Wait();
                taskSHA1.Wait();

                item.setExtract(taskExtract.Result == HttpStatusCode.OK);
                item.setURL(taskURL.Result);
                item.setMD5(taskMD5.Result);
                item.setSHA1(taskSHA1.Result);

                for (var x = 0; x < HmodReadme.readmeFiles.Length; x++)
                {
                    var taskReadme = HTTPHelpers.GetHTTPResponseStringAsync($"{RepositoryURL}{mod}/{HmodReadme.readmeFiles[x]}");

                    taskReadme.Wait();

                    if (taskReadme.Result != null)
                    {
                        item.setReadme(taskReadme.Result, HmodReadme.readmeFiles[x].EndsWith(".md"));
                        break;
                    }
                }

                Items.Add(item);
                RepositoryProgress?.Invoke(i + 1, list.Length);
            }
            RepositoryLoaded?.Invoke(Items.ToArray());

            return;
        }
示例#11
0
        public static TaskFunc DownloadFile(string url, string fileName, bool successOnError = false, bool onlyLatest = false, DateTime?comparisonDate = null, bool gunzip = false)
        {
            return((Tasker tasker, Object sync) =>
            {
                Conclusion result = Conclusion.Success;

                Debug.WriteLine($"Downloading: {url} to {fileName}");

                if (comparisonDate == null && File.Exists(fileName))
                {
                    comparisonDate = File.GetLastWriteTime(fileName);
                }

                var wr = HttpWebRequest.Create(url) as HttpWebRequest;
                wr.UserAgent = HakchiWebClient.UserAgent;

                try
                {
                    using (var response = wr.GetResponse())
                    {
                        var headers = response.Headers;
                        var contentLength = headers.AllKeys.Contains("Content-Length") ? response.ContentLength : 0;

                        var date = DateTime.Now;

                        if (headers.AllKeys.Contains("Last-Modified"))
                        {
                            date = DateTime.ParseExact(headers["Last-Modified"],
                                                       "ddd, dd MMM yyyy HH:mm:ss 'GMT'",
                                                       CultureInfo.InvariantCulture.DateTimeFormat,
                                                       DateTimeStyles.AssumeUniversal);

                            if (onlyLatest && comparisonDate != null && comparisonDate >= date)
                            {
                                response.Close();
                                return Conclusion.Success;
                            }
                        }

                        using (var webStream = response.GetResponseStream())
                            using (var trackableStream = new TrackableStream(webStream))
                            {
                                trackableStream.OnProgress += (progress, max) =>
                                {
                                    tasker.SetStatus($"{Shared.SizeSuffix(progress)}{(contentLength > 0 ? $" / {Shared.SizeSuffix(contentLength)}" : "")}");
                                    tasker.SetProgress(progress, contentLength);
                                };

                                using (var outputFile = File.Create(fileName))
                                {
                                    if (gunzip)
                                    {
                                        using (var gzipStream = new GZipStream(trackableStream, CompressionMode.Decompress))
                                        {
                                            gzipStream.CopyTo(outputFile);
                                        }
                                    }
                                    else
                                    {
                                        trackableStream.CopyTo(outputFile);
                                    }
                                }
                                File.SetLastWriteTime(fileName, date);
                            }
                    }
                }
                catch (ThreadAbortException) { }
                catch (Exception e)
                {
                    if (!successOnError)
                    {
                        throw e;
                    }
                }

                return result;
            });
        }
示例#12
0
        public static TaskFunc GameCopyTask(FoundGame game)
        {
            return((Tasker tasker, Object sync) =>
            {
                if (game.Desktop.Code.StartsWith("CLV-"))
                {
                    long dataTransferred = 0;
                    var destinationPath = Path.Combine(NesApplication.GamesDirectory, game.Desktop.Code);
                    tasker?.SetStatus($"{game.Desktop.Name}");

                    if (Directory.Exists(destinationPath))
                    {
                        Directory.Delete(destinationPath, true);
                    }

                    Directory.CreateDirectory(destinationPath);

                    foreach (var folder in hakchi.Shell.ExecuteSimple($"cd {Shared.EscapeShellArgument(game.RemotePath)}; find -type d").Split('\n'))
                    {
                        Directory.CreateDirectory(Path.Combine(destinationPath, folder));
                    }

                    FtpClient ftp = null;

                    if (hakchi.Shell is INetworkShell)
                    {
                        ftp = new FtpClient(new Uri($"ftp://{(hakchi.Shell as INetworkShell).IPAddress}"), new NetworkCredential("root", "root"));
                    }

                    foreach (Match match in new Regex(@"^(\d+)\s*\./(.*)$", RegexOptions.Multiline).Matches(hakchi.Shell.ExecuteSimple($"cd {Shared.EscapeShellArgument(game.RemotePath)}; find -type f -exec du {"{}"} \\;")))
                    {
                        var size = long.Parse(match.Groups[1].Value) * 1024;
                        var filename = match.Groups[2].Value;

                        using (var file = File.Create(Path.Combine(destinationPath, filename)))
                            using (var tracker = new TrackableStream(file))
                            {
                                tracker.OnProgress += (long transferred, long length) =>
                                {
                                    var totalTransferred = Math.Min(dataTransferred + transferred, game.Size);
                                    tasker?.SetProgress(totalTransferred, game.Size);
                                    tasker?.SetStatus($"{game.Desktop.Name} ({Shared.SizeSuffix(totalTransferred, 2)} / {Shared.SizeSuffix(game.Size, 2)})");
                                };

                                if (hakchi.Shell is INetworkShell)
                                {
                                    using (var ftpStream = ftp.Retr($"{game.RemotePath}/{filename}"))
                                    {
                                        ftpStream.CopyTo(tracker);
                                    }
                                }
                                else
                                {
                                    hakchi.Shell.Execute($"cat {Shared.EscapeShellArgument($"{game.RemotePath}/{filename}")}", null, tracker, throwOnNonZero: true);
                                }

                                dataTransferred += size;
                            }
                    }

                    ftp?.Dispose();
                    ftp = null;

                    game.Desktop.Save(Path.Combine(destinationPath, $"{game.Desktop.Code}.desktop"));

                    if (!ConfigIni.Instance.SelectedGames.Contains(game.Desktop.Code))
                    {
                        ConfigIni.Instance.SelectedGames.Add(game.Desktop.Code);
                    }

                    return Conclusion.Success;
                }

                return Conclusion.Error;
            });
        }