protected override void OnStart(String[] Args) { try { String DebugLogFile = null; UInt32 DebugFlags = 0; String VolumePrefix = null; String ImagePath = null; String MountPoint = null; IntPtr DebugLogHandle = (IntPtr)(-1); bool SetupFS = false; bool RemoveFS = false; FileSystemHost Host = null; GdfxFileSystem Gdfx = null; StfsFileSystem Stfs = null; FatxFileSystem Fatx = null; int I; for (I = 1; Args.Length > I; I++) { String Arg = Args[I]; if ('-' != Arg[0]) { break; } switch (Arg[1]) { case '?': throw new CommandLineUsageException(); case 'd': argtol(Args, ref I, ref DebugFlags); break; case 'D': argtos(Args, ref I, ref DebugLogFile); break; case 'm': argtos(Args, ref I, ref MountPoint); break; case 'i': argtos(Args, ref I, ref ImagePath); break; case 'u': argtos(Args, ref I, ref VolumePrefix); break; case 's': SetupFS = true; break; case 'r': RemoveFS = true; break; default: throw new CommandLineUsageException(); } } if (Args.Length > I) { throw new CommandLineUsageException(); } if (SetupFS) { try { Console.WriteLine("\r\nSetting up Xbox filesystems...\r\n"); // Add to WinFsp services list, allows using "net use X: \\xbox-winfps\C$\game.iso" Registry.SetValue(@"HKEY_LOCAL_MACHINE\Software\WinFsp\Services\xbox-winfsp", "CommandLine", "-u %1 -m %2", RegistryValueKind.String); Registry.SetValue(@"HKEY_LOCAL_MACHINE\Software\WinFsp\Services\xbox-winfsp", "Executable", System.Reflection.Assembly.GetEntryAssembly().Location, RegistryValueKind.String); Registry.SetValue(@"HKEY_LOCAL_MACHINE\Software\WinFsp\Services\xbox-winfsp", "Security", "D:P(A;;RPWPLC;;;WD)", RegistryValueKind.String); Registry.SetValue(@"HKEY_LOCAL_MACHINE\Software\WinFsp\Services\xbox-winfsp", "JobControl", 1, RegistryValueKind.DWord); // Context menu item for all files (since STFS has no extension...) Registry.SetValue(@"HKEY_LOCAL_MACHINE\Software\Classes\*\shell\Mount as Xbox STFS/GDF\command", null, $"\"{System.Reflection.Assembly.GetEntryAssembly().Location}\" -i \"%1\" -m *"); Console.WriteLine("Successfully setup filesystems, you may need to restart for changes to take effect.\r\n"); } catch { Console.WriteLine("Error: Failed to setup filesystems, maybe try running as admin?\r\n"); } } if (RemoveFS) { try { bool error = false; Console.WriteLine("\r\nRemoving any Xbox filesystems...\r\n"); try { RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\WinFsp\Services", true); if (key != null) { key.DeleteSubKeyTree("xbox-winfsp", true); } } catch { Console.WriteLine("Error: Failed to remove xbox-winfsp key!\r\n"); error = true; } try { RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\Classes\*\shell", true); if (key != null) { key.DeleteSubKeyTree("Mount as Xbox STFS/GDF"); } } catch { Console.WriteLine("Error: Failed to remove context-menu key!\r\n"); error = true; } if (error) { throw new Exception(); } Console.WriteLine("Removed Xbox filesystems successfully.\r\n"); } catch { Console.WriteLine("An error was encountered, maybe try running as admin?\r\n"); } } if (null == ImagePath && null != VolumePrefix) { I = VolumePrefix.IndexOf('\\'); if (-1 != I && VolumePrefix.Length > I && '\\' != VolumePrefix[I + 1]) { I = VolumePrefix.IndexOf('\\', I + 1); if (-1 != I && VolumePrefix.Length > I + 1 && ( ('A' <= VolumePrefix[I + 1] && VolumePrefix[I + 1] <= 'Z') || ('a' <= VolumePrefix[I + 1] && VolumePrefix[I + 1] <= 'z') ) && '$' == VolumePrefix[I + 2]) { ImagePath = String.Format("{0}:{1}", VolumePrefix[I + 1], VolumePrefix.Substring(I + 3)); } } } if (null != DebugLogFile) { if (0 > FileSystemHost.SetDebugLogFile(DebugLogFile)) { throw new CommandLineUsageException("cannot open debug log file"); } } if (!string.IsNullOrEmpty(ImagePath) && !string.IsNullOrEmpty(MountPoint)) { // For some reason WinFsp needs MountPoint to be null for wildcard to work without elevation... bool openExplorer = false; if (MountPoint == "*") { MountPoint = null; openExplorer = true; // Open mounted drive in explorer if the mountPoint is wildcard - QoL :) } var fileStream = File.OpenRead(ImagePath); Host = new FileSystemHost(Fatx = new FatxFileSystem(fileStream, ImagePath)); Host.Prefix = VolumePrefix; if (Host.Mount(MountPoint, null, true, DebugFlags) < 0) { Fatx = null; fileStream.Position = 0; Host = new FileSystemHost(Stfs = new StfsFileSystem(fileStream, ImagePath)); Host.Prefix = VolumePrefix; if (Host.Mount(MountPoint, null, true, DebugFlags) < 0) { Stfs = null; fileStream.Position = 0; Host = new FileSystemHost(Gdfx = new GdfxFileSystem(fileStream, ImagePath)); Host.Prefix = VolumePrefix; if (Host.Mount(MountPoint, null, true, DebugFlags) < 0) { throw new IOException("cannot mount file system"); } } } MountPoint = Host.MountPoint(); _Host = Host; if (openExplorer) { System.Diagnostics.Process.Start("explorer.exe", MountPoint); } Log(EVENTLOG_INFORMATION_TYPE, String.Format("{0}{1}{2} -p {3} -m {4}", PROGNAME, null != VolumePrefix && 0 < VolumePrefix.Length ? " -u " : "", null != VolumePrefix && 0 < VolumePrefix.Length ? VolumePrefix : "", ImagePath, MountPoint)); Console.Title = $"{MountPoint} - xbox-winfsp"; Console.WriteLine($"\r\n{ImagePath}:\r\n Mounted to {MountPoint}, hit CTRL+C in this window to unmount.\r\n"); } else { _Hosts = new List <FileSystemHost>(); string connectedDrives = ""; if (Utility.IsAdministrator()) { Log(EVENTLOG_INFORMATION_TYPE, "Loading Xbox partitions from physical drives..."); for (int i = 1; i < 11; i++) { try { var device = new FatxDevice(i); if (!device.IsFatxDevice()) { continue; } var partitions = device.LoadPartitions(DebugFlags); if (partitions.Count > 0) { connectedDrives += $"{i} "; } _Hosts.AddRange(partitions); } catch { } } Log(EVENTLOG_INFORMATION_TYPE, $"Loaded {_Hosts.Count} Xbox partitions from drives."); } if (_Hosts.Count <= 0) { throw new CommandLineUsageException(); } Console.Title = $"HDD {connectedDrives}- xbox-winfsp"; Console.WriteLine("\r\nHit CTRL+C in this window to unmount."); } } catch (CommandLineUsageException ex) { Log(EVENTLOG_ERROR_TYPE, String.Format( "{0}" + "usage: {1} OPTIONS\n" + "\n" + "options:\n" + " -d DebugFlags [-1: enable all debug logs]\n" + " -D DebugLogFile [file path; use - for stderr]\n" + " -i ImagePath [path to GDFX/STFS image to be mounted]\n" + " -u \\Server\\ImagePath [UNC prefix (single backslash)]\n" + " -m MountPoint [X:|*|directory]\n" + " -s [installs xbox-winfsp filesystems, may need elevation!]\n" + " -r [removes any xbox-winfsp filesystems, may need elevation!]\n", ex.HasMessage ? ex.Message + "\n" : "", PROGNAME));; throw; } //} //catch (Exception ex) //{ // Log(EVENTLOG_ERROR_TYPE, String.Format("{0}", ex.Message)); // throw; // } }
public List <FileSystemHost> LoadPartitions(uint DebugLogLevel = 0) { if (!IsFatxDevice()) { return(null); } var filesystems = new List <FileSystemHost>(); // Filter kXboxPartitions to the ones that could fit onto this drive/image var partitions = kXboxPartitions.Where(partition => partition.Item2 < DriveSize && partition.Item2 + partition.Item3 <= DriveSize).ToList(); // Try reading in devkit partition table Stream.Position = 0; var devkitTable = Stream.ReadStruct <FATX_DEVKIT_PARTITION_TABLE>(); devkitTable.EndianSwap(); if (devkitTable.IsValid) { // Add any non-zero partitions to our partition list for (int i = 0; i < devkitTable.Partitions.Length; i++) { var partition = devkitTable.Partitions[i]; if (partition.Offset != 0 && partition.Size != 0) { var partitionName = kDevkitPartitionNames[i]; if (partitionName == "Dump") // Dump can contain multiple partitions, see kDumpPartitions { foreach (var dumpPartition in kDumpPartitions) { partitions.Add(new Tuple <string, long, long>( $"DevKit {dumpPartition.Item1}", partition.Offset + dumpPartition.Item2, dumpPartition.Item3)); } } else { partitions.Add(new Tuple <string, long, long>( $"DevKit {kDevkitPartitionNames[i]}", partition.Offset, partition.Size)); } } } } // Read in cache partition data Stream.Position = 0x800; CacheHeader = Stream.ReadStruct <CACHE_PARTITION_DATA>(); CacheHeader.EndianSwap(); // Check partition validity & remove any invalid ones var removeList = new List <int>(); for (int i = 0; i < partitions.Count; i++) { Stream.Seek(partitions[i].Item2, SeekOrigin.Begin); var header = Stream.ReadStruct <FAT_VOLUME_METADATA>(); if (!header.IsValid) { removeList.Add(i); } } removeList.Reverse(); foreach (var index in removeList) { partitions.RemoveAt(index); } // Sort partitions by their offset partitions.OrderBy(p => p.Item2).ToList(); // Work out the retail data partition size // (We check all partitions for size == 0 here, because devkit partitions could be added after) // (Even though any retail data partition would be invalid/corrupt by devkit partition presence, it's worth trying to salvage it) for (int i = 0; i < partitions.Count; i++) { var partition = partitions[i]; long size = 0x377FFC000; // 20GB HDD if (DriveSize != 0x04AB440C00) // 20GB HDD { size = DriveSize - partition.Item2; } if (partition.Item3 == 0) { partitions[i] = new Tuple <string, long, long>(partition.Item1, partition.Item2, size); } } // TODO: check if any partitions interfere with each other (eg. devkit Partition1 located inside retail Partition1 space), and mark the drive label if so ("CORRUPT" or something similar) // Load in the filesystems & mount them: int stfcIndex = 0; int driveIndex = -1; foreach (var partition in partitions) { if (partition.Item3 == 0) { continue; // Couldn't figure out size of it ? } driveIndex++; Stream.Position = partition.Item2; var fatx = new FatxFileSystem(Stream, partition.Item1, partition.Item2, partition.Item3); fatx.StreamLock = StreamLock; var Host = new FileSystemHost(fatx); Host.Prefix = null; if (Host.Mount(null, null, false, DebugLogLevel) < 0) { if (true) { Stream.Position = partition.Item2; var stfs = new StfsFileSystem(Stream, partition.Item1, partition.Item2); stfs.StreamLock = StreamLock; stfs.SkipHashChecks = true; // TODO! if (stfcIndex < 2 && CacheHeader.IsValid) { stfs.CacheHeader = CacheHeader; stfs.CachePartitionIndex = stfcIndex; stfs.StfsVolumeDescriptor = CacheHeader.VolumeDescriptor[stfcIndex]; } stfcIndex++; if (stfcIndex >= 2) { stfcIndex = 0; // Reset index for devkit cache partitions } Host = new FileSystemHost(stfs); Host.Prefix = null; if (Host.Mount(null, null, false, DebugLogLevel) < 0) { continue; } } } filesystems.Add(Host); } return(filesystems); }
public FileEntry(StfsFileSystem fileSystem) { FileSystem = fileSystem; }