示例#1
0
        public static void ProcessPartitionFs(Context ctx)
        {
            if (ctx.Options.OutFile == null)
            {
                ctx.Logger.LogMessage("Output file must be specified.");
                return;
            }

            PartitionFileSystemType type = ctx.Options.BuildHfs
                ? PartitionFileSystemType.Hashed
                : PartitionFileSystemType.Standard;

            var localFs = new LocalFileSystem(ctx.Options.InFile);

            var      builder     = new PartitionFileSystemBuilder(localFs);
            IStorage partitionFs = builder.Build(type);

            ctx.Logger.LogMessage($"Building Partition FS as {ctx.Options.OutFile}");

            using (var outFile = new FileStream(ctx.Options.OutFile, FileMode.Create, FileAccess.ReadWrite))
            {
                partitionFs.CopyToStream(outFile, partitionFs.GetSize(), ctx.Logger);
            }

            ctx.Logger.LogMessage($"Finished writing {ctx.Options.OutFile}");
        }
        private int GetMetaDataAlignment(PartitionFileSystemType type)
        {
            switch (type)
            {
            case PartitionFileSystemType.Standard: return(0x20);

            case PartitionFileSystemType.Hashed: return(0x200);

            default: throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
        }
        private string GetMagicValue(PartitionFileSystemType type)
        {
            switch (type)
            {
            case PartitionFileSystemType.Standard: return("PFS0");

            case PartitionFileSystemType.Hashed: return("HFS0");

            default: throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
        }
        public IStorage Build(PartitionFileSystemType type)
        {
            byte[] meta = BuildMetaData(type);

            var sources = new List <IStorage>();

            sources.Add(new MemoryStorage(meta));

            sources.AddRange(Entries.Select(x => new FileStorage(x.File)));

            return(new ConcatenationStorage(sources, true));
        }
        private int CalcStringTableSize(int startOffset, PartitionFileSystemType type)
        {
            int size = 0;

            foreach (Entry entry in Entries)
            {
                size += entry.NameLength + 1;
            }

            int endOffset = Util.AlignUp(startOffset + size, GetMetaDataAlignment(type));

            return(endOffset - startOffset);
        }
示例#6
0
        public static int GetEntrySize(PartitionFileSystemType type)
        {
            switch (type)
            {
            case PartitionFileSystemType.Standard:
                return(0x18);

            case PartitionFileSystemType.Hashed:
                return(0x40);

            default:
                throw new ArgumentOutOfRangeException(nameof(type), type, null);
            }
        }
        private byte[] BuildMetaData(PartitionFileSystemType type)
        {
            if (type == PartitionFileSystemType.Hashed)
            {
                CalculateHashes();
            }

            int entryTableSize  = Entries.Count * PartitionFileEntry.GetEntrySize(type);
            int stringTableSize = CalcStringTableSize(HeaderSize + entryTableSize, type);
            int metaDataSize    = HeaderSize + entryTableSize + stringTableSize;

            var metaData = new byte[metaDataSize];
            var writer   = new BinaryWriter(new MemoryStream(metaData));

            writer.WriteUTF8(GetMagicValue(type));
            writer.Write(Entries.Count);
            writer.Write(stringTableSize);
            writer.Write(0);

            int stringOffset = 0;

            foreach (Entry entry in Entries)
            {
                writer.Write(entry.Offset);
                writer.Write(entry.Length);
                writer.Write(stringOffset);

                if (type == PartitionFileSystemType.Standard)
                {
                    writer.Write(0);
                }
                else
                {
                    writer.Write(entry.HashLength);
                    writer.Write(entry.HashOffset);
                    writer.Write(entry.Hash);
                }

                stringOffset += entry.NameLength + 1;
            }

            foreach (Entry entry in Entries)
            {
                writer.WriteUTF8Z(entry.Name);
            }

            return(metaData);
        }
示例#8
0
 public PartitionFileEntry(BinaryReader reader, PartitionFileSystemType type)
 {
     Offset            = reader.ReadInt64();
     Size              = reader.ReadInt64();
     StringTableOffset = reader.ReadUInt32();
     if (type == PartitionFileSystemType.Hashed)
     {
         HashedRegionSize   = reader.ReadInt32();
         HashedRegionOffset = reader.ReadInt64();
         Hash = reader.ReadBytes(Crypto.Sha256DigestSize);
     }
     else
     {
         reader.BaseStream.Position += 4;
     }
 }
示例#9
0
        public PartitionFileSystemHeader(BinaryReader reader)
        {
            Magic           = reader.ReadAscii(4);
            NumFiles        = reader.ReadInt32();
            StringTableSize = reader.ReadInt32();
            Reserved        = reader.ReadInt32();

            switch (Magic)
            {
            case "PFS0":
                Type = PartitionFileSystemType.Standard;
                break;

            case "HFS0":
                Type = PartitionFileSystemType.Hashed;
                break;

            default:
                ThrowHelper.ThrowResult(ResultFs.InvalidPartitionFileSystemMagic, $"Invalid Partition FS type \"{Magic}\"");
                break;
            }

            int entrySize         = PartitionFileEntry.GetEntrySize(Type);
            int stringTableOffset = 16 + entrySize * NumFiles;

            HeaderSize = stringTableOffset + StringTableSize;

            Files = new PartitionFileEntry[NumFiles];
            for (int i = 0; i < NumFiles; i++)
            {
                Files[i] = new PartitionFileEntry(reader, Type)
                {
                    Index = i
                };
            }

            for (int i = 0; i < NumFiles; i++)
            {
                reader.BaseStream.Position = stringTableOffset + Files[i].StringTableOffset;
                Files[i].Name = reader.ReadAsciiZ();
            }
        }
示例#10
0
        public static IStorage ProcessPartitionFileSystem(PartitionFileSystem pfs, PartitionFileSystemType pfsType, bool compress)
        {
            PartitionFileSystemBuilder pfsBuilder = new PartitionFileSystemBuilder();

            foreach (DirectoryEntryEx ticketEntry in pfs.EnumerateEntries("/", "*.tik"))
            {
                Result result = pfs.OpenFile(out IFile ticketFile, ticketEntry.FullPath.ToU8Span(), OpenMode.Read);

                if (result.IsSuccess())
                {
                    Ticket ticket = new Ticket(ticketFile.AsStream());

                    KeySet.ExternalKeySet.Add(new RightsId(ticket.RightsId), new AccessKey(ticket.GetTitleKey(KeySet)));
                }
            }

            foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries())
            {
                pfs.OpenFile(out IFile file, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();

                if (compress && Path.GetExtension(fileEntry.Name).ToLower() == ".nca")
                {
                    (IStorage processedNca, byte[] metaBuffer) = ProcessNca(file.AsStorage());
                    IFile zcaFile = new ZraCompressionStorageHack(processedNca, CompressionLevel, FrameSize, metaBuffer, TempPath).AsFile(OpenMode.Read);

                    pfsBuilder.AddFile($"{Path.GetFileNameWithoutExtension(fileEntry.Name)}.zca", zcaFile);
                }
                else if (!compress && Path.GetExtension(fileEntry.Name).ToLower() == ".zca")
                {
                    IStorage ncaStorage = new ZraDecompressionStream(file.AsStream()).AsStorage();
                    IFile    ncaFile    = new Nca(KeySet, ncaStorage).OpenEncryptedNca().AsFile(OpenMode.Read);

                    pfsBuilder.AddFile($"{Path.GetFileNameWithoutExtension(fileEntry.Name)}.nca", ncaFile);
                }
                else
                {
                    pfsBuilder.AddFile(fileEntry.Name, file);
                }
            }

            return(pfsBuilder.Build(pfsType));
        }