Пример #1
0
        public static STF_VOLUME_DESCRIPTOR Default()
        {
            var descriptor = new STF_VOLUME_DESCRIPTOR();

            descriptor.DescriptorLength                   = 0x24;
            descriptor.Version                            = 0;
            descriptor.Flags                              = 0;
            descriptor.DirectoryAllocationBlocks          = 1;
            descriptor.DirectoryFirstBlockNumber0         =
                descriptor.DirectoryFirstBlockNumber1     =
                    descriptor.DirectoryFirstBlockNumber2 = 0;
            descriptor.RootHash                           = new byte[0x14];
            descriptor.NumberOfTotalBlocks                = 1;
            descriptor.NumberOfFreeBlocks                 = 0;
            return(descriptor);
        }
Пример #2
0
        void StfsInit()
        {
            if (Position == 0)
            {
                Position = Stream.Position;
            }

            // Set ConsoleSignature if this is a cache partition, so metadata.ini can reflect it
            if (CacheHeader.IsValid && CachePartitionIndex != -1)
            {
                IsConsoleSigned  = true;
                ConsoleSignature = CacheHeader.Signature;
            }

            // Read in XContent/PEC header if the volume descriptor isn't already set:
            if (StfsVolumeDescriptor.DescriptorLength != 0x24)
            {
                var fatHeader = Stream.ReadStruct <FAT_VOLUME_METADATA>();
                Stream.Position = Position;
                if (fatHeader.Signature == FatxFileSystem.kMagicFatx || fatHeader.Signature == FatxFileSystem.kMagicFatxBE)
                {
                    // STFC partition (uses FATX header for some reason, but has an invalid chainmap)
                    // TODO: find where the descriptor is located (the HDD dump I'm testing with might be missing the first cluster)
                    // For now we'll disable hash checks & use a default descriptor...
                    StfsVolumeDescriptor = STF_VOLUME_DESCRIPTOR.Default();
                    // Should be fine to set directory block count to 100, it'll exit out once the hash chain ends
                    StfsVolumeDescriptor.DirectoryAllocationBlocks = 100;
                    // We don't have a volume descriptor, so we don't have a root hash: disable hash checks ;_;
                    SkipHashChecks = true;
                }
                else
                {
                    PecHeader = Stream.ReadStruct <PEC_HEADER>();
                    PecHeader.EndianSwap();
                    if (PecHeader.ConsoleSignature.IsStructureValid)
                    {
                        IsXContent           = false;
                        IsConsoleSigned      = true;
                        ConsoleSignature     = PecHeader.ConsoleSignature;
                        StfsVolumeDescriptor = PecHeader.StfsVolumeDescriptor;
                    }
                    else
                    {
                        IsXContent = true;
                        Stream.Seek(0, SeekOrigin.Begin);

                        Header = Stream.ReadStruct <XCONTENT_HEADER>();
                        Header.EndianSwap();

                        if (Header.SignatureType != XCONTENT_HEADER.kSignatureTypeConBE &&
                            Header.SignatureType != XCONTENT_HEADER.kSignatureTypeLiveBE &&
                            Header.SignatureType != XCONTENT_HEADER.kSignatureTypePirsBE)
                        {
                            throw new FileSystemParseException("File has invalid header magic");
                        }

                        if (Header.SizeOfHeaders == 0)
                        {
                            throw new FileSystemParseException("Package doesn't contain STFS filesystem");
                        }

                        if (Header.SignatureType == XCONTENT_HEADER.kSignatureTypeConBE)
                        {
                            IsConsoleSigned  = true;
                            ConsoleSignature = Header.ConsoleSignature;
                        }

                        Stream.Position = 0x344;
                        Metadata        = Stream.ReadStruct <XCONTENT_METADATA>();
                        Metadata.EndianSwap();

                        if (Header.SizeOfHeaders > 0x971A)
                        {
                            Stream.Position   = 0x971A;
                            InstallerMetadata = Stream.ReadStruct <XCONTENT_METADATA_INSTALLER>();
                            InstallerMetadata.EndianSwap();
                        }

                        if (Metadata.VolumeType != 0)
                        {
                            throw new FileSystemParseException("Package contains unsupported SVOD filesystem");
                        }

                        StfsVolumeDescriptor = Metadata.StfsVolumeDescriptor;
                    }
                }

                if (StfsVolumeDescriptor.DescriptorLength != 0x24)
                {
                    throw new FileSystemParseException("File has invalid descriptor length");
                }
            }
            StfsInitValues();

            // Read in our directory entries...

            int directoryBlock = StfsVolumeDescriptor.DirectoryFirstBlockNumber;
            var entries        = new List <FileEntry>();

            for (int i = 0; i < StfsVolumeDescriptor.DirectoryAllocationBlocks; i++)
            {
                if (directoryBlock == 0xFFFFFF)
                {
                    Console.WriteLine("Premature directory exit 1!!!");
                    break;
                }

                Stream.Position = StfsDataBlockToOffset(directoryBlock);

                bool noMoreEntries = false;
                for (int ent = 0; ent < (0x1000 / 0x40); ent++)
                {
                    var entry = new FileEntry(this);
                    if (!entry.Read(Stream))
                    {
                        noMoreEntries = true;
                        break;
                    }
                    if (entry.CreationTime < CreationTime)
                    {
                        CreationTime = entry.CreationTime;
                    }

                    if (!entry.IsDirectory)
                    {
                        BytesInUse += entry.DirEntry.FileSize;
                    }

                    entries.Add(entry);
                }


                // Find next directory block...
                var blockHashEntry = StfsGetLevel0HashEntry(directoryBlock);
                directoryBlock = blockHashEntry.Level0NextBlock;

                if (noMoreEntries)
                {
                    if (i + 1 < StfsVolumeDescriptor.DirectoryAllocationBlocks)
                    {
                        Console.WriteLine("Premature directory exit 2!!!");
                    }
                    break;
                }
            }

            // Create metadata.ini/metadata_thumbnail/etc..
            InitMetadataFiles(ref entries);

            // Connect entries up with their parents/children
            var rootEntries = new List <IFileEntry>();

            for (int i = 0; i < entries.Count; i++)
            {
                var ent = entries[i];
                if (ent.DirEntry.DirectoryIndex == -1)
                {
                    rootEntries.Add(ent);
                }

                if (!ent.IsDirectory)
                {
                    continue;
                }

                var children = new List <IFileEntry>();
                foreach (var ent2 in entries)
                {
                    if (ent2.DirEntry.DirectoryIndex == i)
                    {
                        children.Add(ent2);
                        ent2.Parent = ent;
                    }
                }

                children.Sort((x, y) => x.Name.CompareTo(y.Name));
                ent.Children = children;
            }

            // Make sure to sort so that ReadDirectoryEntry doesn't make windows loop forever...
            rootEntries.Sort((x, y) => x.Name.CompareTo(y.Name));

            Children  = entries.ToArray();
            RootFiles = rootEntries;
        }