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; }
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)); } } }
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; } } }
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 { } } }
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)); } } } }
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); }
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); }