Пример #1
0
 public SyncTask()
 {
     Games           = new NesMenuCollection();
     exportDirectory = string.Empty;
     uploadPath      = string.Empty;
     exportLinked    = false;
     stats           = new GamesTreeStats();
     localGameSet    = new HashSet <ApplicationFileInfo>();
     transferGameSet = null;
     copyMode        = ConfigIni.Instance.SyncLinked ? NesApplication.CopyMode.LinkedSync : NesApplication.CopyMode.Sync;
 }
Пример #2
0
        private void AddMenu(NesMenuCollection menuCollection, NesApplication.CopyMode copyMode, HashSet <ApplicationFileInfo> localGameSet = null, GamesTreeStats stats = null)
        {
            if (stats == null)
            {
                stats = new GamesTreeStats();
            }
            if (!stats.allMenus.Contains(menuCollection))
            {
                stats.allMenus.Add(menuCollection);
            }
            int    menuIndex       = stats.allMenus.IndexOf(menuCollection);
            string targetDirectory = string.Format("{0:D3}", menuIndex);

            foreach (var element in menuCollection)
            {
                if (element is NesApplication)
                {
                    var game = element as NesApplication;

                    // still use temp directory for game genie games
                    try
                    {
                        if (game is ISupportsGameGenie && File.Exists(game.GameGeniePath))
                        {
                            string tempPath = Path.Combine(tempDirectory, game.Desktop.Code);
                            Shared.EnsureEmptyDirectory(tempPath);
                            NesApplication gameCopy = game.CopyTo(tempDirectory);
                            (gameCopy as ISupportsGameGenie).ApplyGameGenie();
                            game = gameCopy;
                        }
                    }
                    catch (GameGenieFormatException ex)
                    {
                        Trace.WriteLine(string.Format(Resources.GameGenieFormatError, ex.Code, game.Name));
                    }
                    catch (GameGenieNotFoundException ex)
                    {
                        Trace.WriteLine(string.Format(Resources.GameGenieNotFound, ex.Code, game.Name));
                    }

                    long gameSize = game.Size();
                    Trace.WriteLine(string.Format("Processing {0} ('{1}'), size: {2}KB", game.Code, game.Name, gameSize / 1024));
                    gameSize            = game.CopyTo(targetDirectory, localGameSet, copyMode);
                    stats.TotalSize    += gameSize;
                    stats.TransferSize += gameSize;
                    stats.TotalGames++;
                }
                if (element is NesMenuFolder)
                {
                    var folder = element as NesMenuFolder;
                    if (folder.Name == Resources.FolderNameTrashBin)
                    {
                        continue; // skip recycle bin!
                    }
                    if (folder.ChildMenuCollection.Count == 1 && folder.ChildMenuCollection[0].Name == Resources.FolderNameBack)
                    {
                        continue; // skip empty folders
                    }
                    if (!stats.allMenus.Contains(folder.ChildMenuCollection))
                    {
                        stats.allMenus.Add(folder.ChildMenuCollection);
                        AddMenu(folder.ChildMenuCollection, copyMode, localGameSet, stats);
                    }
                    folder.ChildIndex = stats.allMenus.IndexOf(folder.ChildMenuCollection);

                    long folderSize = folder.CopyTo(targetDirectory, localGameSet);
                    stats.TotalSize    += folderSize;
                    stats.TransferSize += folderSize;
                    Trace.WriteLine(string.Format("Processed folder {0} ('{1}'), size: {2}KB", folder.Code, folder.Name, folderSize / 1024));
                }
            }
        }
Пример #3
0
        private void AddMenu(NesMenuCollection menuCollection, Dictionary <string, string> originalGames, GamesTreeStats stats = null)
        {
            if (stats == null)
            {
                stats = new GamesTreeStats();
            }
            if (!stats.allMenus.Contains(menuCollection))
            {
                stats.allMenus.Add(menuCollection);
            }
            int    menuIndex = stats.allMenus.IndexOf(menuCollection);
            string targetDirectory;

            if (menuIndex == 0)
            {
                targetDirectory = tempGamesDirectory;
            }
            else
            {
                targetDirectory = Path.Combine(tempGamesDirectory, string.Format("{0:D3}", menuIndex));
            }
            foreach (var element in menuCollection)
            {
                if (element is NesMiniApplication)
                {
                    if (element is NesDefaultGame)
                    {
                        var game = element as NesDefaultGame;
                        stats.TotalSize         += game.Size;
                        originalGames[game.Code] = menuIndex == 0 ? "." : string.Format("{0:D3}", menuIndex);
                    }
                    else
                    {
                        stats.TotalGames++;
                        var game     = element as NesMiniApplication;
                        var gameSize = game.Size();
                        Debug.WriteLine(string.Format("Processing {0} ('{1}'), size: {2}KB", game.Code, game.Name, gameSize / 1024));
                        var gameCopy = game.CopyTo(targetDirectory);
                        stats.TotalSize    += gameSize;
                        stats.TransferSize += gameSize;
                        stats.TotalGames++;
                        try
                        {
                            if (gameCopy is NesGame && File.Exists((gameCopy as NesGame).GameGeniePath))
                            {
                                (gameCopy as NesGame).ApplyGameGenie();
                                File.Delete((gameCopy as NesGame).GameGeniePath);
                            }
                        }
                        catch (GameGenieFormatException ex)
                        {
                            ShowError(new Exception(string.Format(Resources.GameGenieFormatError, ex.Code, game.Name)), dontStop: true);
                        }
                        catch (GameGenieNotFoundException ex)
                        {
                            ShowError(new Exception(string.Format(Resources.GameGenieNotFound, ex.Code, game.Name)), dontStop: true);
                        }
                    }
                }
                if (element is NesMenuFolder)
                {
                    var folder = element as NesMenuFolder;
                    if (!stats.allMenus.Contains(folder.ChildMenuCollection))
                    {
                        stats.allMenus.Add(folder.ChildMenuCollection);
                        AddMenu(folder.ChildMenuCollection, originalGames, stats);
                    }
                    folder.ChildIndex = stats.allMenus.IndexOf(folder.ChildMenuCollection);
                    var folderDir  = Path.Combine(targetDirectory, folder.Code);
                    var folderSize = folder.Save(folderDir);
                    stats.TotalSize    += folderSize;
                    stats.TransferSize += folderSize;
                }
            }
        }
Пример #4
0
        public void UploadGames()
        {
            const string gamesPath   = "/usr/share/games/nes/kachikachi";
            const string rootFsPath  = "/var/lib/hakchi/rootfs";
            const string installPath = "/var/lib/hakchi";
            int          progress    = 0;
            int          maxProgress = 400;

            if (Games == null || Games.Count == 0)
            {
                throw new Exception("there are no games");
            }
            SetStatus(Resources.BuildingFolders);
            if (FoldersMode == NesMenuCollection.SplitStyle.Custom)
            {
                if (FoldersManagerFromThread(Games) != System.Windows.Forms.DialogResult.OK)
                {
                    DialogResult = DialogResult.Abort;
                    return;
                }
                Games.AddBack();
            }
            else
            {
                Games.Split(FoldersMode, MaxGamesPerFolder);
            }
            progress += 5;
            SetProgress(progress, maxProgress);

            var clovershell = MainForm.Clovershell;

            try
            {
                if (WaitForClovershellFromThread() != DialogResult.OK)
                {
                    DialogResult = DialogResult.Abort;
                    return;
                }
                progress += 5;
                SetProgress(progress, maxProgress);

                new clovershell.ClovershellWrapper(clovershell).ShowSplashScreen();


                SetStatus(Resources.BuildingFolders);
                if (Directory.Exists(tempDirectory))
                {
                    Directory.Delete(tempDirectory, true);
                }
                Directory.CreateDirectory(tempDirectory);
                // Games!
                tempGamesDirectory = Path.Combine(tempDirectory, "games");
                Directory.CreateDirectory(tempDirectory);
                Directory.CreateDirectory(tempGamesDirectory);
                Dictionary <string, string> originalGames = new Dictionary <string, string>();
                var stats = new GamesTreeStats();
                AddMenu(Games, originalGames, stats);
                progress += 5;
                SetProgress(progress, maxProgress);

                GetMemoryStats();
                var maxGamesSize = (NandCFree + WritedGamesSize) - ReservedMemory * 1024 * 1024;
                if (stats.TotalSize > maxGamesSize)
                {
                    throw new Exception(string.Format(Resources.MemoryFull, stats.TotalSize / 1024 / 1024) + "\r\n\r\n" +
                                        string.Format(Resources.MemoryStats.Replace("|", "\r\n"),
                                                      NandCTotal / 1024.0 / 1024.0,
                                                      (NandCFree + WritedGamesSize - ReservedMemory * 1024 * 1024) / 1024 / 1024,
                                                      SaveStatesSize / 1024.0 / 1024.0,
                                                      (NandCUsed - WritedGamesSize - SaveStatesSize) / 1024.0 / 1024.0));
                }

                int startProgress = progress;
                using (var gamesTar = new TarStream(tempGamesDirectory))
                {
                    maxProgress = (int)(gamesTar.Length / 1024 / 1024 + 20 + originalGames.Count() * 2);
                    SetProgress(progress, maxProgress);

                    clovershell.ExecuteSimple(string.Format("umount {0}", gamesPath));
                    clovershell.ExecuteSimple(string.Format("rm -rf {0}{1}/CLV-* {0}{1}/??? {2}/menu", rootFsPath, gamesPath, installPath), 5000, true);

                    if (gamesTar.Length > 0)
                    {
                        gamesTar.OnReadProgress += delegate(long pos, long len)
                        {
                            progress = (int)(startProgress + pos / 1024 / 1024);
                            SetProgress(progress, maxProgress);
                        };

                        SetStatus(Resources.UploadingGames);
                        clovershell.Execute(string.Format("tar -xvC {0}{1}", rootFsPath, gamesPath), gamesTar, null, null, 30000, true);
                    }
                }

                SetStatus(Resources.UploadingOriginalGames);
                startProgress = progress;
                foreach (var originalCode in originalGames.Keys)
                {
                    clovershell.ExecuteSimple(string.Format(@"mkdir -p ""{2}{3}/{1}/{0}/"" && rsync -ac ""{3}/{0}/"" ""{2}{3}/{1}/{0}/"" && sed -i -e 's/\/usr\/bin\/clover-kachikachi/\/bin\/clover-kachikachi-wr/g' ""{2}{3}/{1}/{0}/{0}.desktop""", originalCode, originalGames[originalCode], rootFsPath, gamesPath), 5000, true);
                    progress += 2;
                    SetProgress(progress, maxProgress);
                }
                ;

                SetStatus(Resources.UploadingConfig);
                SyncConfig(Config);
#if !DEBUG
                Directory.Delete(tempDirectory, true);
#endif
                SetStatus(Resources.Done);
                SetProgress(maxProgress, maxProgress);
            }
            finally
            {
                try
                {
                    if (clovershell.IsOnline)
                    {
                        clovershell.ExecuteSimple("reboot", 100);
                    }
                }
                catch { }
            }
        }
Пример #5
0
        private void AddMenu(NesMenuCollection menuCollection, GamesTreeStats stats = null)
        {
            if (stats == null)
            {
                stats = new GamesTreeStats();
            }
            if (!stats.allMenus.Contains(menuCollection))
            {
                stats.allMenus.Add(menuCollection);
            }
            int    menuIndex = stats.allMenus.IndexOf(menuCollection);
            string targetDirectory;

            if (menuIndex == 0)
            {
                targetDirectory = tempGamesDirectory;
            }
            else
            {
                targetDirectory = Path.Combine(tempGamesDirectory, string.Format("{0:D3}", menuIndex));
            }
            foreach (var element in menuCollection)
            {
                if (element is NesMiniApplication)
                {
                    stats.GamesTotal++;
                    if (stats.Size >= maxRamfsSize)
                    {
                        continue;
                    }
                    stats.GamesProceed++;
                    if (stats.GamesStart >= stats.GamesProceed)
                    {
                        continue;
                    }
                    var game = element as NesMiniApplication;
                    Debug.Write(string.Format("Processing {0} ('{1}'), #{2}", game.Code, game.Name, stats.GamesProceed));
                    var gameCopy = game.CopyTo(targetDirectory);
                    stats.Size += gameCopy.Size();
                    if (stats.Size >= maxRamfsSize)
                    {
                        // Rollback. Just in case of huge last game
                        stats.GamesProceed--;
                        Directory.Delete(gameCopy.GamePath, true);
                        continue;
                    }
                    Debug.WriteLine(string.Format(", total size: {0}", stats.Size));
                    try
                    {
                        if (gameCopy is NesGame && File.Exists((gameCopy as NesGame).GameGeniePath))
                        {
                            (gameCopy as NesGame).ApplyGameGenie();
                            File.Delete((gameCopy as NesGame).GameGeniePath);
                        }
                    }
                    catch (GameGenieFormatException ex)
                    {
                        ShowError(new GameGenieFormatException(string.Format(Resources.GameGenieFormatError, ex.Code, game)), dontStop: true);
                    }
                    catch (GameGenieNotFoundException ex)
                    {
                        ShowError(new GameGenieNotFoundException(string.Format(Resources.GameGenieNotFound, ex.Code, game.Name)), dontStop: true);
                    }
                }
                if (element is NesMenuFolder)
                {
                    var folder = element as NesMenuFolder;
                    if (!stats.allMenus.Contains(folder.ChildMenuCollection))
                    {
                        stats.allMenus.Add(folder.ChildMenuCollection);
                        AddMenu(folder.ChildMenuCollection, stats);
                    }
                    if (stats.GamesStart == 0)
                    {
                        folder.ChildIndex = stats.allMenus.IndexOf(folder.ChildMenuCollection);
                        var folderDir = Path.Combine(targetDirectory, folder.Code);
                        folder.Save(folderDir);
                    }
                }
                if (element is NesDefaultGame)
                {
                    if (stats.GamesStart == 0)
                    {
                        var game      = element as NesDefaultGame;
                        var gfilePath = Path.Combine(originalGamesConfigDirectory, string.Format("gpath-{0}", game.Code));
                        File.WriteAllText(gfilePath, menuIndex == 0 ? "." : string.Format("{0:D3}", menuIndex));
                    }
                }
            }
        }
Пример #6
0
        private byte[] CreatePatchedKernel(GamesTreeStats stats = null)
        {
            if (stats == null)
            {
                stats = new GamesTreeStats();
            }
            bool first   = stats.GamesProceed == 0;
            bool partial = stats.GamesProceed > 0;

            SetStatus(Resources.BuildingCustom);
            if (first)
            {
                if (Directory.Exists(tempDirectory))
                {
                    Directory.Delete(tempDirectory, true);
                }
                Directory.CreateDirectory(tempDirectory);
                Directory.CreateDirectory(kernelDirectory);
                Directory.CreateDirectory(ramfsDirectory);
                if (!ExecuteTool("unpackbootimg.exe", string.Format("-i \"{0}\" -o \"{1}\"", KernelDump, kernelDirectory)))
                {
                    throw new Exception("Can't unpack kernel image");
                }
                if (!ExecuteTool("lzop.exe", string.Format("-d \"{0}\" -o \"{1}\"",
                                                           Path.Combine(kernelDirectory, "kernel.img-ramdisk.gz"), initramfs_cpio)))
                {
                    throw new Exception("Can't unpack ramdisk");
                }
                ExecuteTool("cpio.exe", string.Format("-imd --no-preserve-owner --quiet -I \"{0}\"",
                                                      @"..\initramfs.cpio"), ramfsDirectory);
                if (!File.Exists(Path.Combine(ramfsDirectory, "init"))) // cpio.exe fails on Windows XP for some reason. But working!
                {
                    throw new Exception("Can't unpack ramdisk 2");
                }
                if (Directory.Exists(hakchiDirectory))
                {
                    Directory.Delete(hakchiDirectory, true);
                }
                NesMiniApplication.DirectoryCopy(Path.Combine(modsDirectory, Mod), ramfsDirectory, true);
                var ramfsFiles = Directory.GetFiles(ramfsDirectory, "*.*", SearchOption.AllDirectories);
                foreach (var file in ramfsFiles)
                {
                    var fInfo = new FileInfo(file);
                    if (fInfo.Length > 10 && fInfo.Length < 100 && ((fInfo.Attributes & FileAttributes.System) == 0) &&
                        (Encoding.ASCII.GetString(File.ReadAllBytes(file), 0, 10)) == "!<symlink>")
                    {
                        fInfo.Attributes |= FileAttributes.System;
                    }
                }
            }

            if (!first && Directory.Exists(transferDirectory))
            {
                Debug.WriteLine("Clearing transfer directory");
                Directory.Delete(transferDirectory, true);
            }

            // Games!
            if (Games != null)
            {
                Directory.CreateDirectory(tempGamesDirectory);
                if (first)
                {
                    File.WriteAllBytes(Path.Combine(tempGamesDirectory, "clear"), new byte[0]);
                    Directory.CreateDirectory(originalGamesConfigDirectory);
                    if (HiddenGames != null && HiddenGames.Length > 0)
                    {
                        StringBuilder h = new StringBuilder();
                        foreach (var game in HiddenGames)
                        {
                            h.Append(game + "\n");
                        }
                        File.WriteAllText(hiddenPath, h.ToString());
                    }
                }

                stats.Next();
                AddMenu(Games, stats);
                Debug.WriteLine(string.Format("Games copied: {0}/{1}, part size: {2}", stats.GamesProceed, stats.GamesTotal, stats.Size));
            }

            bool last = stats.GamesProceed >= stats.GamesTotal;

            if (last && hmodsInstall != null && hmodsInstall.Count > 0)
            {
                Directory.CreateDirectory(tempHmodsDirectory);
                foreach (var hmod in hmodsInstall)
                {
                    var modName = hmod + ".hmod";
                    foreach (var dir in hmodDirectories)
                    {
                        if (Directory.Exists(Path.Combine(dir, modName)))
                        {
                            NesMiniApplication.DirectoryCopy(Path.Combine(dir, modName), Path.Combine(tempHmodsDirectory, modName), true);
                            break;
                        }
                        if (File.Exists(Path.Combine(dir, modName)))
                        {
                            File.Copy(Path.Combine(dir, modName), Path.Combine(tempHmodsDirectory, modName));
                            break;
                        }
                    }
                }
            }
            if (last && hmodsUninstall != null && hmodsUninstall.Count > 0)
            {
                Directory.CreateDirectory(tempHmodsDirectory);
                var mods = new StringBuilder();
                foreach (var hmod in hmodsUninstall)
                {
                    mods.AppendFormat("{0}.hmod\n", hmod);
                }
                File.WriteAllText(Path.Combine(tempHmodsDirectory, "uninstall"), mods.ToString());
            }

            // Writing config
            if (Config != null && Config.Count > 0)
            {
                Directory.CreateDirectory(transferDirectory);
                var config = new StringBuilder();
                foreach (var key in Config.Keys)
                {
                    config.AppendFormat("cfg_{0}='{1}'\n", key, Config[key].Replace(@"'", @"\'"));
                }
                File.WriteAllText(configPath, config.ToString());
            }

            // Building image
            if (first && Games != null && Games.Count > 0) // There is no reason to compress cryptsetup when we do not uploading games
            {
                ExecuteTool("upx.exe", "--best sbin\\cryptsetup", ramfsDirectory);
            }
            byte[] ramdisk;
            if (!ExecuteTool("mkbootfs.exe", string.Format("\"{0}\"", ramfsDirectory), out ramdisk))
            {
                throw new Exception("Can't repack ramdisk");
            }
            File.WriteAllBytes(initramfs_cpioPatched, ramdisk);
            var argCmdline    = File.ReadAllText(Path.Combine(kernelDirectory, "kernel.img-cmdline")).Trim();
            var argBoard      = File.ReadAllText(Path.Combine(kernelDirectory, "kernel.img-board")).Trim();
            var argBase       = File.ReadAllText(Path.Combine(kernelDirectory, "kernel.img-base")).Trim();
            var argPagesize   = File.ReadAllText(Path.Combine(kernelDirectory, "kernel.img-pagesize")).Trim();
            var argKerneloff  = File.ReadAllText(Path.Combine(kernelDirectory, "kernel.img-kerneloff")).Trim();
            var argRamdiscoff = File.ReadAllText(Path.Combine(kernelDirectory, "kernel.img-ramdiskoff")).Trim();
            var argTagsoff    = File.ReadAllText(Path.Combine(kernelDirectory, "kernel.img-tagsoff")).Trim();

            if (!ExecuteTool("lzop.exe", string.Format("--best -f -o \"{0}\" \"{1}\"",
                                                       ramdiskPatched, initramfs_cpioPatched)))
            {
                throw new Exception("Can't repack ramdisk 2");
            }
            if (!ExecuteTool("mkbootimg.exe", string.Format("--kernel \"{0}\" --ramdisk \"{1}\" --cmdline \"{2}\" --board \"{3}\" --base \"{4}\" --pagesize \"{5}\" --kernel_offset \"{6}\" --ramdisk_offset \"{7}\" --tags_offset \"{8}\" -o \"{9}\"",
                                                            Path.Combine(kernelDirectory, "kernel.img-zImage"), ramdiskPatched, argCmdline, argBoard, argBase, argPagesize, argKerneloff, argRamdiscoff, argTagsoff, kernelPatched)))
            {
                throw new Exception("Can't rebuild kernel");
            }

            var result = File.ReadAllBytes(kernelPatched);

#if !DEBUG
            if (last)
            {
                Directory.Delete(tempDirectory, true);
            }
#endif
            if (result.Length > Fel.kernel_max_size)
            {
                throw new Exception("Kernel is too big");
            }
            GC.Collect();
            return(result);
        }
Пример #7
0
        public void Memboot()
        {
            int progress    = 0;
            int maxProgress = -1;
            var stats       = new GamesTreeStats();

            if (Games != null)
            {
                SetStatus(Resources.BuildingFolders);
                if (FoldersMode == NesMenuCollection.SplitStyle.Custom)
                {
                    if (FolderManagerFromThread(Games) != System.Windows.Forms.DialogResult.OK)
                    {
                        DialogResult = DialogResult.Abort;
                        return;
                    }
                    Games.AddBack();
                }
                else
                {
                    Games.Split(FoldersMode, MaxGamesPerFolder);
                }
            }
            progress += 5;
            SetProgress(progress, 300);

            do
            {
                if (stats.GamesProceed > 0)
                {
                    ShowMessage(Resources.ParticallyBody, Resources.ParticallyTitle);
                }
                GC.Collect();

                // Connecting to NES Mini
                if (WaitForDeviceFromThread() != DialogResult.OK)
                {
                    DialogResult = DialogResult.Abort;
                    return;
                }
                progress += 5;
                SetProgress(progress, maxProgress > 0 ? maxProgress : 300);

                byte[] kernel;
                if (!string.IsNullOrEmpty(Mod))
                {
                    kernel = CreatePatchedKernel(stats);
                }
                else
                {
                    kernel = File.ReadAllBytes(KernelDump);
                }
                var size = CalKernelSize(kernel);
                if (size > kernel.Length || size > Fel.kernel_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;
                }
                progress += 5;
                if (maxProgress < 0)
                {
                    if (stats.GamesProceed > 0)
                    {
                        maxProgress = (kernel.Length / 67000 + 20) * stats.GamesTotal / stats.GamesProceed + 75 * ((int)Math.Ceiling((float)stats.GamesTotal / (float)stats.GamesProceed) - 1);
                    }
                    else
                    {
                        maxProgress = (kernel.Length / 67000 + 20);
                    }
                }
                SetProgress(progress, maxProgress);

                SetStatus(Resources.UploadingKernel);
                fel.WriteMemory(Fel.flash_mem_base, kernel,
                                delegate(Fel.CurrentAction action, string command)
                {
                    switch (action)
                    {
                    case Fel.CurrentAction.WritingMemory:
                        SetStatus(Resources.UploadingKernel);
                        break;
                    }
                    progress++;
                    SetProgress(progress, maxProgress);
                }
                                );

                var bootCommand = string.Format("boota {0:x}", Fel.kernel_base_m);
                SetStatus(Resources.ExecutingCommand + " " + bootCommand);
                fel.RunUbootCmd(bootCommand, true);
            } while (stats.GamesProceed < stats.GamesTotal);
            SetStatus(Resources.Done);
            SetProgress(maxProgress, maxProgress);
        }