Beispiel #1
0
        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);
        }
Beispiel #2
0
 public FileEntry(FileEntry parent, FatxFileSystem fileSystem)
 {
     Parent     = parent;
     FileSystem = fileSystem;
 }
Beispiel #3
0
        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;
            // }
        }