Example #1
0
        public static PfsHeader ReadFromStream(System.IO.Stream s)
        {
            var start = s.Position;
            var hdr   = new PfsHeader
            {
                Version          = s.ReadInt64LE(),
                Magic            = s.ReadInt64LE(),
                Id               = s.ReadInt64LE(),
                Fmode            = s.ReadUInt8(),
                Clean            = s.ReadUInt8(),
                ReadOnly         = s.ReadUInt8(),
                Rsv              = s.ReadUInt8(),
                Mode             = (PfsMode)s.ReadUInt16LE(),
                Unk1             = s.ReadUInt16LE(),
                BlockSize        = s.ReadUInt32LE(),
                NBackup          = s.ReadUInt32LE(),
                NBlock           = s.ReadInt64LE(),
                DinodeCount      = s.ReadInt64LE(),
                Ndblock          = s.ReadInt64LE(),
                DinodeBlockCount = s.ReadInt64LE(),
            };

            s.Position       += 8; // skip a 64-bit zero
            hdr.InodeBlockSig = DinodeS64.ReadFromStream(s);
            if (hdr.Version != 1 || hdr.Magic != 20130315)
            {
                throw new InvalidDataException($"Invalid PFS superblock version ({hdr.Version}) or magic ({hdr.Magic})");
            }
            s.Position = start + 0x370;
            hdr.Seed   = s.ReadBytes(16);
            return(hdr);
        }
        public static PfsHeader ReadFromStream(System.IO.Stream s)
        {
            var start = s.Position;
            var hdr   = new PfsHeader
            {
                Version          = s.ReadInt64LE(),
                Magic            = s.ReadInt64LE(),
                Id               = s.ReadInt64LE(),
                Fmode            = s.ReadUInt8(),
                Clean            = s.ReadUInt8(),
                ReadOnly         = s.ReadUInt8(),
                Rsv              = s.ReadUInt8(),
                Mode             = (PfsMode)s.ReadUInt16LE(),
                Unk1             = s.ReadUInt16LE(),
                BlockSize        = s.ReadUInt32LE(),
                NBackup          = s.ReadUInt32LE(),
                NBlock           = s.ReadInt64LE(),
                DinodeCount      = s.ReadInt64LE(),
                Ndblock          = s.ReadInt64LE(),
                DinodeBlockCount = s.ReadInt64LE(),
                InodeBlockSig    = DinodeS64.ReadFromStream(s)
            };

            s.Position = start + 0x370;
            hdr.Seed   = s.ReadBytes(16);
            return(hdr);
        }
        public PfsReader(IMemoryReader r, byte[] ekpfs = null)
        {
            reader = r;
            var buf = new byte[0x400];

            reader.Read(0, buf, 0, 0x400);

            using (var ms = new MemoryStream(buf))
            {
                hdr = PfsHeader.ReadFromStream(ms);
            }
            int dinodeSize;
            Func <Stream, inode> dinodeReader;

            if (hdr.Mode.HasFlag(PfsMode.Signed))
            {
                dinodes      = new DinodeS32[hdr.DinodeCount];
                dinodeReader = DinodeS32.ReadFromStream;
                dinodeSize   = 0x2C8;
            }
            else
            {
                dinodes      = new DinodeD32[hdr.DinodeCount];
                dinodeReader = DinodeD32.ReadFromStream;
                dinodeSize   = 0xA8;
            }
            if (hdr.Mode.HasFlag(PfsMode.Encrypted))
            {
                if (ekpfs == null)
                {
                    throw new ArgumentException("PFS image is encrypted but no EKPFS was provided");
                }
                var(tweakKey, dataKey) = Crypto.PfsGenEncKey(ekpfs, hdr.Seed);
                reader = new XtsDecryptReader(reader, dataKey, tweakKey, 16, 0x1000);
            }
            var total = 0;

            var maxPerSector = hdr.BlockSize / dinodeSize;

            sectorBuf    = new byte[hdr.BlockSize];
            sectorStream = new MemoryStream(sectorBuf);
            for (var i = 0; i < hdr.DinodeBlockCount; i++)
            {
                var position = hdr.BlockSize + hdr.BlockSize * i;
                reader.Read(position, sectorBuf, 0, sectorBuf.Length);
                sectorStream.Position = 0;
                for (var j = 0; j < maxPerSector && total < hdr.DinodeCount; j++)
                {
                    dinodes[total++] = dinodeReader(sectorStream);
                }
            }
            root  = LoadDir(0, null, "");
            uroot = root.Get("uroot") as Dir;
            if (uroot == null)
            {
                throw new Exception("Invalid PFS image (no uroot)");
            }
            uroot.parent = null;
            uroot.name   = "";
        }
Example #4
0
        /// <summary>
        /// Builds and saves a PFS image.
        /// </summary>
        /// <param name="p"></param>
        public void BuildPfs(PfsProperties p)
        {
            // TODO: Combine the superroot-specific stuff with the rest of the data block writing.
            // I think this is as simple as adding superroot and flat_path_table to allNodes

            hdr = new PfsHeader {
                BlockSize = p.BlockSize
            };
            inodes  = new List <PfsDinode32>();
            dirents = new List <List <PfsDirent> >();

            Console.WriteLine("Setting up root structure...");
            SetupRootStructure();
            BuildFSTree(root, p.proj, p.projDir);
            allDirs  = root.GetAllChildrenDirs();
            allFiles = root.GetAllChildrenFiles();
            allNodes = new List <FSNode>(allDirs);
            allNodes.AddRange(allFiles);

            Console.WriteLine("Creating directory inodes ({0})...", allDirs.Count);
            addDirInodes();

            Console.WriteLine("Creating file inodes ({0})...", allFiles.Count);
            addFileInodes();

            Console.WriteLine("Creating flat_path_table...");
            fpt = new FlatPathTable(allNodes);


            Console.WriteLine("Calculating data block layout...");
            allNodes.Insert(0, root);
            CalculateDataBlockLayout();

            Console.WriteLine("Writing image file...");
            hdr.Ndblock = allFiles.Sum((f) => CeilDiv(f.Size, hdr.BlockSize));
            {
                var stream = p.output;
                Console.WriteLine("Writing header...");
                hdr.WriteToStream(stream);
                Console.WriteLine("Writing inodes...");
                WriteInodes(stream);
                Console.WriteLine("Writing superroot dirents");
                WriteSuperrootDirents(stream);

                Console.WriteLine("Writing flat_path_table");
                stream.Position = fpt_ino.db[0] * hdr.BlockSize;
                fpt.WriteToStream(stream);

                Console.WriteLine("Writing data blocks...");
                for (var x = 0; x < allNodes.Count; x++)
                {
                    var f = allNodes[x];
                    stream.Position = f.ino.db[0] * hdr.BlockSize;
                    WriteFSNode(stream, f);
                }
            }
        }
Example #5
0
        void Setup()
        {
            // TODO: Combine the superroot-specific stuff with the rest of the data block writing.
            // I think this is as simple as adding superroot and flat_path_table to allNodes

            // This doesn't seem to really matter when verifying a PKG so use all zeroes for now
            var seed = new byte[16];

            // Insert header digest to be calculated with the rest of the digests
            sig_order.Push(new BlockSigInfo(0, 0x380, 0x5A0));
            hdr = new PfsHeader {
                BlockSize = properties.BlockSize,
                ReadOnly  = 1,
                Mode      = (properties.Sign ? PfsMode.Signed : 0)
                            | (properties.Encrypt ? PfsMode.Encrypted : 0)
                            | PfsMode.UnknownFlagAlwaysSet,
                UnknownIndex = 1,
                Seed         = properties.Encrypt || properties.Sign ? seed : null
            };
            inodes = new List <inode>();

            Log("Setting up root structure...");
            SetupRootStructure();
            allDirs  = root.GetAllChildrenDirs();
            allFiles = root.GetAllChildrenFiles();
            allNodes = new List <FSNode>(allDirs);
            allNodes.AddRange(allFiles);

            Log(string.Format("Creating directory inodes ({0})...", allDirs.Count));
            addDirInodes();

            Log(string.Format("Creating file inodes ({0})...", allFiles.Count));
            addFileInodes();

            Log("Creating flat_path_table...");
            fpt = new FlatPathTable(allNodes);

            Log("Calculating data block layout...");
            allNodes.Insert(0, root);
            CalculateDataBlockLayout();
        }
Example #6
0
        /// <summary>
        /// This gets called by the constructor.
        /// </summary>
        void Setup()
        {
            // TODO: Combine the superroot-specific stuff with the rest of the data block writing.
            // I think this is as simple as adding superroot and flat_path_table to allNodes

            // This doesn't seem to really matter when verifying a PKG so use all zeroes for now
            var seed = new byte[16];

            // Insert header digest to be calculated with the rest of the digests
            final_sigs.Push(new BlockSigInfo(0, 0x380, 0x5A0));
            hdr = new PfsHeader {
                BlockSize = properties.BlockSize,
                ReadOnly  = 1,
                Mode      = (properties.Sign ? PfsMode.Signed : 0)
                            | (properties.Encrypt ? PfsMode.Encrypted : 0)
                            | PfsMode.UnknownFlagAlwaysSet,
                UnknownIndex = 1,
                Seed         = properties.Encrypt || properties.Sign ? seed : null
            };
            inodes = new List <inode>();

            Log("Setting up filesystem structure...");
            SetupRootStructure();
            allDirs  = root.GetAllChildrenDirs();
            allFiles = root.GetAllChildrenFiles().Where(f => f.Parent?.name != "sce_sys" || !PKG.EntryNames.NameToId.ContainsKey(f.name)).ToList();
            allNodes = new List <FSNode>(allDirs);
            allNodes.AddRange(allFiles);

            Log($"Creating inodes ({allDirs.Count} dirs and {allFiles.Count} files)...");
            addDirInodes();
            addFileInodes();

            fpt = new FlatPathTable(allNodes);

            Log("Calculating data block layout...");
            allNodes.Insert(0, root);
            CalculateDataBlockLayout();
        }
Example #7
0
        /// <summary>
        /// This gets called by the constructor.
        /// </summary>
        void Setup()
        {
            // TODO: Combine the superroot-specific stuff with the rest of the data block writing.
            // I think this is as simple as adding superroot and flat_path_table to allNodes

            // Insert header digest to be calculated with the rest of the digests
            final_sigs.Push(new BlockSigInfo(0, 0x380, 0x5A0));
            hdr = new PfsHeader {
                BlockSize = properties.BlockSize,
                ReadOnly  = 1,
                Mode      = (properties.Sign ? PfsMode.Signed : 0)
                            | (properties.Encrypt ? PfsMode.Encrypted : 0)
                            | PfsMode.UnknownFlagAlwaysSet,
                UnknownIndex = 1,
                Seed         = properties.Encrypt || properties.Sign ? properties.Seed : null
            };
            inodes = new List <inode>();

            Log("Setting up filesystem structure...");
            allDirs  = properties.root.GetAllChildrenDirs();
            allFiles = properties.root.GetAllChildrenFiles().Where(f => f.Parent?.name != "sce_sys" || !PKG.EntryNames.NameToId.ContainsKey(f.name)).ToList();
            allNodes = new List <FSNode>(allDirs.OrderBy(d => d.FullPath()).ToList());
            allNodes.AddRange(allFiles);

            SetupRootStructure(FlatPathTable.HasCollision(allNodes));

            Log($"Creating inodes ({allDirs.Count} dirs and {allFiles.Count} files)...");
            addDirInodes();
            addFileInodes();

            (fpt, colResolver) = FlatPathTable.Create(allNodes);

            Log("Calculating data block layout...");
            allNodes.Insert(0, properties.root);
            CalculateDataBlockLayout();
        }