Double direct-blocks bug #13

Open
opened 2026-07-29 02:32:29 -05:00 by Zubastic · 1 comment
Zubastic commented 2026-07-29 02:32:29 -05:00 (Migrated from github.com)

Hello. I using https://github.com/jdros15/dump2ufs-gui It uses UFS2Tool under hood. So when I converting PS5 games (Stray, PPSA02100) I having error:

System.NotSupportedException: Memory stream is not expandable.
   at System.IO.MemoryStream.set_Capacity(Int32 value)
   at System.IO.MemoryStream.EnsureCapacity(Int32 value)
   at System.IO.MemoryStream.Write(ReadOnlySpan`1 buffer)
   at System.IO.BinaryWriter.Write(Int64 value)
   at UFS2Tool.Ufs2ImageCreator.AllocateAndWriteFile(FileStream fs, BinaryWriter writer, String filePath, Int64 fileSize, Ufs2Superblock sb, Int32 fragsPerBlock, Int32 fragsPerGroup, Int32 dataStartFrag, Int32& nextDataFragInCg, Int32& currentCg, Int32[] perCgHighWater, Int64 totalFrags, Action`1 onDataBytesWritten) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 2531
   at UFS2Tool.Ufs2ImageCreator.ProcessDirectoryContents(FileStream fs, BinaryWriter writer, BinaryReader reader, String dirPath, UInt32 parentInode, Ufs2Superblock sb, Int64 inodeTableOffset, Int32 inodeSize, Int32 fragsPerBlock, Int32 fragsPerGroup, Int32 dataStartFrag, UInt32& nextInode, Int32& nextDataFragInCg, Int32& currentCg, Int32& dirCount, Int32& filesWritten, List`1 parentEntries, Int64 timestamp, Int32[] dirsPerCg, Int32[] perCgHighWater, Int64 totalFrags, HashSet`1 tailFreeFrags, UInt32 parentDirDepth, Action`2 onCopyProgress) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 2212
   at UFS2Tool.Ufs2ImageCreator.ProcessDirectoryContents(FileStream fs, BinaryWriter writer, BinaryReader reader, String dirPath, UInt32 parentInode, Ufs2Superblock sb, Int64 inodeTableOffset, Int32 inodeSize, Int32 fragsPerBlock, Int32 fragsPerGroup, Int32 dataStartFrag, UInt32& nextInode, Int32& nextDataFragInCg, Int32& currentCg, Int32& dirCount, Int32& filesWritten, List`1 parentEntries, Int64 timestamp, Int32[] dirsPerCg, Int32[] perCgHighWater, Int64 totalFrags, HashSet`1 tailFreeFrags, UInt32 parentDirDepth, Action`2 onCopyProgress) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 2149
   at UFS2Tool.Ufs2ImageCreator.ProcessDirectoryContents(FileStream fs, BinaryWriter writer, BinaryReader reader, String dirPath, UInt32 parentInode, Ufs2Superblock sb, Int64 inodeTableOffset, Int32 inodeSize, Int32 fragsPerBlock, Int32 fragsPerGroup, Int32 dataStartFrag, UInt32& nextInode, Int32& nextDataFragInCg, Int32& currentCg, Int32& dirCount, Int32& filesWritten, List`1 parentEntries, Int64 timestamp, Int32[] dirsPerCg, Int32[] perCgHighWater, Int64 totalFrags, HashSet`1 tailFreeFrags, UInt32 parentDirDepth, Action`2 onCopyProgress) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 2149
   at UFS2Tool.Ufs2ImageCreator.ProcessDirectoryContents(FileStream fs, BinaryWriter writer, BinaryReader reader, String dirPath, UInt32 parentInode, Ufs2Superblock sb, Int64 inodeTableOffset, Int32 inodeSize, Int32 fragsPerBlock, Int32 fragsPerGroup, Int32 dataStartFrag, UInt32& nextInode, Int32& nextDataFragInCg, Int32& currentCg, Int32& dirCount, Int32& filesWritten, List`1 parentEntries, Int64 timestamp, Int32[] dirsPerCg, Int32[] perCgHighWater, Int64 totalFrags, HashSet`1 tailFreeFrags, UInt32 parentDirDepth, Action`2 onCopyProgress) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 2149
   at UFS2Tool.Ufs2ImageCreator.PopulateFromDirectory(String imagePath, String directoryPath) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 1998
   at UFS2Tool.Ufs2ImageCreator.CreateImageFromDirectory(String imagePath, String directoryPath, Int64 totalSizeBytes) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 1662
   at Ufs2Tool.Program.HandleNewFsImage(Ufs2ImageCreator creator, String imagePath, List`1 positional) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Program.cs:line 922
   at Ufs2Tool.Program.HandleNewFs(String[] args) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Program.cs:line 281
   at Ufs2Tool.Program.Main(String[] args) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Program.cs:line 26

I guess, problem here: https://github.com/SvenGDK/UFS2Tool/blob/main/Ufs2ImageCreator.cs#L2510

            // Handle double-indirect blocks if needed
            if (remaining > 0)
            {
                // Allocate the double-indirect block itself
                var (dindFragOffset, dindCgIdx) = AllocateDataBlock(
                    fragsPerBlock, fragsPerGroup, dataStartFrag,
                    ref nextDataFragInCg, ref currentCg, sb.NumCylGroups, perCgHighWater,
                    totalFrags);
                long doubleIndirectBlockFrag = (long)dindCgIdx * fragsPerGroup + dindFragOffset;
                result.DoubleIndirectBlockFrag = doubleIndirectBlockFrag;
                result.MetadataBlockCount++;

                // Problem that secondLevelCount could be more than sb.BSize could be. So it would be stream overflow.
                int secondLevelCount = (int)((remaining + pointersPerBlock - 1) / pointersPerBlock);

                byte[] dindBlock = new byte[sb.BSize];
                using var dindMs = new MemoryStream(dindBlock);
                using var dindWriter = new BinaryWriter(dindMs);

                for (int i = 0; i < secondLevelCount; i++)
                {
                    int thisCount = (int)Math.Min(remaining, pointersPerBlock);

                    // Allocate the single-indirect block for this entry
                    var (sindFragOffset, sindCgIdx) = AllocateDataBlock(
                        fragsPerBlock, fragsPerGroup, dataStartFrag,
                        ref nextDataFragInCg, ref currentCg, sb.NumCylGroups, perCgHighWater,
                        totalFrags);
                    long sindBlockFrag = (long)sindCgIdx * fragsPerGroup + sindFragOffset;
                    result.MetadataBlockCount++;

                    if (FilesystemFormat == 1)
                        dindWriter.Write((int)sindBlockFrag);
                    else
                        dindWriter.Write(sindBlockFrag);

                    AllocateAndWriteSingleIndirectBlock(fs, writer, fileStream, buffer,
                        thisCount, sb, sindBlockFrag,
                        fragsPerBlock, fragsPerGroup, dataStartFrag,
                        ref nextDataFragInCg, ref currentCg,
                        ref lastDataBlockFrag, perCgHighWater, totalFrags,
                        onDataBytesWritten);

                    remaining -= thisCount;
                }

                // Write the double-indirect pointer block
                fs.Position = doubleIndirectBlockFrag * sb.FSize;
                writer.Write(dindBlock);
            }

I dont know how to fix it (just adding Min int secondLevelCount = Math.Min((int)((remaining + pointersPerBlock - 1) / pointersPerBlock), pointersPerBlock); corrupt target file).

Hello. I using https://github.com/jdros15/dump2ufs-gui It uses UFS2Tool under hood. So when I converting PS5 games (Stray, PPSA02100) I having error: ```c# System.NotSupportedException: Memory stream is not expandable. at System.IO.MemoryStream.set_Capacity(Int32 value) at System.IO.MemoryStream.EnsureCapacity(Int32 value) at System.IO.MemoryStream.Write(ReadOnlySpan`1 buffer) at System.IO.BinaryWriter.Write(Int64 value) at UFS2Tool.Ufs2ImageCreator.AllocateAndWriteFile(FileStream fs, BinaryWriter writer, String filePath, Int64 fileSize, Ufs2Superblock sb, Int32 fragsPerBlock, Int32 fragsPerGroup, Int32 dataStartFrag, Int32& nextDataFragInCg, Int32& currentCg, Int32[] perCgHighWater, Int64 totalFrags, Action`1 onDataBytesWritten) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 2531 at UFS2Tool.Ufs2ImageCreator.ProcessDirectoryContents(FileStream fs, BinaryWriter writer, BinaryReader reader, String dirPath, UInt32 parentInode, Ufs2Superblock sb, Int64 inodeTableOffset, Int32 inodeSize, Int32 fragsPerBlock, Int32 fragsPerGroup, Int32 dataStartFrag, UInt32& nextInode, Int32& nextDataFragInCg, Int32& currentCg, Int32& dirCount, Int32& filesWritten, List`1 parentEntries, Int64 timestamp, Int32[] dirsPerCg, Int32[] perCgHighWater, Int64 totalFrags, HashSet`1 tailFreeFrags, UInt32 parentDirDepth, Action`2 onCopyProgress) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 2212 at UFS2Tool.Ufs2ImageCreator.ProcessDirectoryContents(FileStream fs, BinaryWriter writer, BinaryReader reader, String dirPath, UInt32 parentInode, Ufs2Superblock sb, Int64 inodeTableOffset, Int32 inodeSize, Int32 fragsPerBlock, Int32 fragsPerGroup, Int32 dataStartFrag, UInt32& nextInode, Int32& nextDataFragInCg, Int32& currentCg, Int32& dirCount, Int32& filesWritten, List`1 parentEntries, Int64 timestamp, Int32[] dirsPerCg, Int32[] perCgHighWater, Int64 totalFrags, HashSet`1 tailFreeFrags, UInt32 parentDirDepth, Action`2 onCopyProgress) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 2149 at UFS2Tool.Ufs2ImageCreator.ProcessDirectoryContents(FileStream fs, BinaryWriter writer, BinaryReader reader, String dirPath, UInt32 parentInode, Ufs2Superblock sb, Int64 inodeTableOffset, Int32 inodeSize, Int32 fragsPerBlock, Int32 fragsPerGroup, Int32 dataStartFrag, UInt32& nextInode, Int32& nextDataFragInCg, Int32& currentCg, Int32& dirCount, Int32& filesWritten, List`1 parentEntries, Int64 timestamp, Int32[] dirsPerCg, Int32[] perCgHighWater, Int64 totalFrags, HashSet`1 tailFreeFrags, UInt32 parentDirDepth, Action`2 onCopyProgress) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 2149 at UFS2Tool.Ufs2ImageCreator.ProcessDirectoryContents(FileStream fs, BinaryWriter writer, BinaryReader reader, String dirPath, UInt32 parentInode, Ufs2Superblock sb, Int64 inodeTableOffset, Int32 inodeSize, Int32 fragsPerBlock, Int32 fragsPerGroup, Int32 dataStartFrag, UInt32& nextInode, Int32& nextDataFragInCg, Int32& currentCg, Int32& dirCount, Int32& filesWritten, List`1 parentEntries, Int64 timestamp, Int32[] dirsPerCg, Int32[] perCgHighWater, Int64 totalFrags, HashSet`1 tailFreeFrags, UInt32 parentDirDepth, Action`2 onCopyProgress) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 2149 at UFS2Tool.Ufs2ImageCreator.PopulateFromDirectory(String imagePath, String directoryPath) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 1998 at UFS2Tool.Ufs2ImageCreator.CreateImageFromDirectory(String imagePath, String directoryPath, Int64 totalSizeBytes) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Ufs2ImageCreator.cs:line 1662 at Ufs2Tool.Program.HandleNewFsImage(Ufs2ImageCreator creator, String imagePath, List`1 positional) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Program.cs:line 922 at Ufs2Tool.Program.HandleNewFs(String[] args) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Program.cs:line 281 at Ufs2Tool.Program.Main(String[] args) in C:\Users\SvenGDK\Documents\GitHub\UFS2-Tool\Program.cs:line 26 ``` I guess, problem here: https://github.com/SvenGDK/UFS2Tool/blob/main/Ufs2ImageCreator.cs#L2510 ```c# // Handle double-indirect blocks if needed if (remaining > 0) { // Allocate the double-indirect block itself var (dindFragOffset, dindCgIdx) = AllocateDataBlock( fragsPerBlock, fragsPerGroup, dataStartFrag, ref nextDataFragInCg, ref currentCg, sb.NumCylGroups, perCgHighWater, totalFrags); long doubleIndirectBlockFrag = (long)dindCgIdx * fragsPerGroup + dindFragOffset; result.DoubleIndirectBlockFrag = doubleIndirectBlockFrag; result.MetadataBlockCount++; // Problem that secondLevelCount could be more than sb.BSize could be. So it would be stream overflow. int secondLevelCount = (int)((remaining + pointersPerBlock - 1) / pointersPerBlock); byte[] dindBlock = new byte[sb.BSize]; using var dindMs = new MemoryStream(dindBlock); using var dindWriter = new BinaryWriter(dindMs); for (int i = 0; i < secondLevelCount; i++) { int thisCount = (int)Math.Min(remaining, pointersPerBlock); // Allocate the single-indirect block for this entry var (sindFragOffset, sindCgIdx) = AllocateDataBlock( fragsPerBlock, fragsPerGroup, dataStartFrag, ref nextDataFragInCg, ref currentCg, sb.NumCylGroups, perCgHighWater, totalFrags); long sindBlockFrag = (long)sindCgIdx * fragsPerGroup + sindFragOffset; result.MetadataBlockCount++; if (FilesystemFormat == 1) dindWriter.Write((int)sindBlockFrag); else dindWriter.Write(sindBlockFrag); AllocateAndWriteSingleIndirectBlock(fs, writer, fileStream, buffer, thisCount, sb, sindBlockFrag, fragsPerBlock, fragsPerGroup, dataStartFrag, ref nextDataFragInCg, ref currentCg, ref lastDataBlockFrag, perCgHighWater, totalFrags, onDataBytesWritten); remaining -= thisCount; } // Write the double-indirect pointer block fs.Position = doubleIndirectBlockFrag * sb.FSize; writer.Write(dindBlock); } ``` I dont know how to fix it (just adding Min `int secondLevelCount = Math.Min((int)((remaining + pointersPerBlock - 1) / pointersPerBlock), pointersPerBlock);` corrupt target file).
Zubastic commented 2026-08-02 10:05:42 -05:00 (Migrated from github.com)

@Nielk1 or @SvenGDK please look at it

@Nielk1 or @SvenGDK please look at it
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-SvenGDK/UFS2Tool#13
No description provided.