add pfs support, write directoryentry info for romfs files
This commit is contained in:
parent
220cd16380
commit
cacac0ea6e
9 changed files with 291 additions and 54 deletions
|
@ -1,6 +1,7 @@
|
|||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.HLE.HOS.Services.FspSrv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using static Ryujinx.HLE.HOS.ErrorCode;
|
||||
|
@ -76,26 +77,60 @@ namespace Ryujinx.HLE.FileSystem
|
|||
return 0;
|
||||
}
|
||||
|
||||
public string[] GetDirectories(string Path)
|
||||
public DirectoryEntry[] GetDirectories(string Path)
|
||||
{
|
||||
return Directory.GetDirectories(Path);
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach(string Directory in Directory.EnumerateDirectories(Path))
|
||||
{
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(Directory, DirectoryEntryType.Directory);
|
||||
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return Entries.ToArray();
|
||||
}
|
||||
|
||||
public string[] GetEntries(string Path)
|
||||
public DirectoryEntry[] GetEntries(string Path)
|
||||
{
|
||||
string DirName = GetFullPath(Path);
|
||||
|
||||
if (Directory.Exists(DirName))
|
||||
if (Directory.Exists(Path))
|
||||
{
|
||||
return Directory.GetFileSystemEntries(DirName);
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach (string Directory in Directory.EnumerateDirectories(Path))
|
||||
{
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(Directory, DirectoryEntryType.Directory);
|
||||
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
foreach (string File in Directory.EnumerateFiles(Path))
|
||||
{
|
||||
FileInfo FileInfo = new FileInfo(File);
|
||||
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File, DirectoryEntryType.File, FileInfo.Length);
|
||||
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public string[] GetFiles(string Path)
|
||||
public DirectoryEntry[] GetFiles(string Path)
|
||||
{
|
||||
return Directory.GetFiles(Path);
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach (string File in Directory.EnumerateFiles(Path))
|
||||
{
|
||||
FileInfo FileInfo = new FileInfo(File);
|
||||
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File, DirectoryEntryType.File, FileInfo.Length);
|
||||
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return Entries.ToArray();
|
||||
}
|
||||
|
||||
public long GetFreeSpace(ServiceCtx Context)
|
||||
|
|
|
@ -13,11 +13,11 @@ namespace Ryujinx.HLE.FileSystem
|
|||
|
||||
long RenameDirectory(string OldName, string NewName);
|
||||
|
||||
string[] GetEntries(string Path);
|
||||
DirectoryEntry[] GetEntries(string Path);
|
||||
|
||||
string[] GetDirectories(string Path);
|
||||
DirectoryEntry[] GetDirectories(string Path);
|
||||
|
||||
string[] GetFiles(string Path);
|
||||
DirectoryEntry[] GetFiles(string Path);
|
||||
|
||||
long DeleteFile(string Name);
|
||||
|
||||
|
|
147
Ryujinx.HLE/FileSystem/PFsProvider.cs
Normal file
147
Ryujinx.HLE/FileSystem/PFsProvider.cs
Normal file
|
@ -0,0 +1,147 @@
|
|||
using LibHac;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using Ryujinx.HLE.HOS.Services.FspSrv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using static Ryujinx.HLE.HOS.ErrorCode;
|
||||
|
||||
namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
class PFsProvider : IFileSystemProvider
|
||||
{
|
||||
private Pfs Pfs;
|
||||
|
||||
public PFsProvider(Pfs Pfs)
|
||||
{
|
||||
this.Pfs = Pfs;
|
||||
}
|
||||
|
||||
public long CreateDirectory(string Name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long CreateFile(string Name, long Size)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long DeleteDirectory(string Name, bool Recursive)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long DeleteFile(string Name)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetDirectories(string Path)
|
||||
{
|
||||
return new DirectoryEntry[0];
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetEntries(string Path)
|
||||
{
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach (PfsFileEntry File in Pfs.Files)
|
||||
{
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File.Name, DirectoryEntryType.File, File.Size);
|
||||
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return Entries.ToArray();
|
||||
}
|
||||
|
||||
public DirectoryEntry[] GetFiles(string Path)
|
||||
{
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach (PfsFileEntry File in Pfs.Files)
|
||||
{
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File.Name, DirectoryEntryType.File, File.Size);
|
||||
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return Entries.ToArray();
|
||||
}
|
||||
|
||||
public long GetFreeSpace(ServiceCtx Context)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public string GetFullPath(string Name)
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
public long GetTotalSpace(ServiceCtx Context)
|
||||
{
|
||||
return Pfs.Files.Sum(x => x.Size);
|
||||
}
|
||||
|
||||
public bool DirectoryExists(string Name)
|
||||
{
|
||||
return Name == "/" ? true : false;
|
||||
}
|
||||
|
||||
public bool FileExists(string Name)
|
||||
{
|
||||
Name = Name.TrimStart('/');
|
||||
|
||||
return Pfs.FileExists(Name);
|
||||
}
|
||||
|
||||
public long OpenDirectory(string Name, int FilterFlags, out IDirectory DirectoryInterface)
|
||||
{
|
||||
if (Name == "/")
|
||||
{
|
||||
DirectoryInterface = new IDirectory(Name, FilterFlags, this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long OpenFile(string Name, out IFile FileInterface)
|
||||
{
|
||||
FileInterface = null;
|
||||
|
||||
Name = Name.TrimStart('/');
|
||||
|
||||
if (Pfs.FileExists(Name))
|
||||
{
|
||||
Stream Stream = Pfs.OpenFile(Name);
|
||||
|
||||
FileInterface = new IFile(Stream, Name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
}
|
||||
|
||||
public long RenameDirectory(string OldName, string NewName)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public long RenameFile(string OldName, string NewName)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public void CheckIfOutsideBasePath(string Path)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,11 +10,11 @@ using static Ryujinx.HLE.HOS.ErrorCode;
|
|||
|
||||
namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
class RomFileSystemProvider : IFileSystemProvider
|
||||
class RomFsProvider : IFileSystemProvider
|
||||
{
|
||||
private Romfs RomFs;
|
||||
|
||||
public RomFileSystemProvider(Stream StorageStream)
|
||||
public RomFsProvider(Stream StorageStream)
|
||||
{
|
||||
RomFs = new Romfs(StorageStream);
|
||||
}
|
||||
|
@ -39,42 +39,50 @@ namespace Ryujinx.HLE.FileSystem
|
|||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public string[] GetDirectories(string Path)
|
||||
public DirectoryEntry[] GetDirectories(string Path)
|
||||
{
|
||||
List<string> Directories = new List<string>();
|
||||
List<DirectoryEntry> Directories = new List<DirectoryEntry>();
|
||||
|
||||
foreach(RomfsDir Directory in RomFs.Directories)
|
||||
{
|
||||
Directories.Add(Directory.Name);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(Directory.Name, DirectoryEntryType.Directory);
|
||||
|
||||
Directories.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return Directories.ToArray();
|
||||
}
|
||||
|
||||
public string[] GetEntries(string Path)
|
||||
public DirectoryEntry[] GetEntries(string Path)
|
||||
{
|
||||
List<string> Entries = new List<string>();
|
||||
List<DirectoryEntry> Entries = new List<DirectoryEntry>();
|
||||
|
||||
foreach (RomfsDir Directory in RomFs.Directories)
|
||||
{
|
||||
Entries.Add(Directory.Name);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(Directory.Name, DirectoryEntryType.Directory);
|
||||
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
foreach (RomfsFile File in RomFs.Files)
|
||||
{
|
||||
Entries.Add(File.Name);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File.Name, DirectoryEntryType.File, File.DataLength);
|
||||
|
||||
Entries.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return Entries.ToArray();
|
||||
}
|
||||
|
||||
public string[] GetFiles(string Path)
|
||||
public DirectoryEntry[] GetFiles(string Path)
|
||||
{
|
||||
List<string> Files = new List<string>();
|
||||
List<DirectoryEntry> Files = new List<DirectoryEntry>();
|
||||
|
||||
foreach (RomfsFile File in RomFs.Files)
|
||||
{
|
||||
Files.Add(File.Name);
|
||||
DirectoryEntry DirectoryEntry = new DirectoryEntry(File.Name, DirectoryEntryType.File, File.DataLength);
|
||||
|
||||
Files.Add(DirectoryEntry);
|
||||
}
|
||||
|
||||
return Files.ToArray();
|
||||
|
@ -114,6 +122,8 @@ namespace Ryujinx.HLE.FileSystem
|
|||
if (Directory != null)
|
||||
{
|
||||
DirectoryInterface = new IDirectory(Name, FilterFlags, this);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
||||
|
@ -123,7 +133,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||
{
|
||||
FileInterface = null;
|
||||
|
||||
if (File.Exists(Name))
|
||||
if (RomFs.FileExists(Name))
|
||||
{
|
||||
Stream Stream = RomFs.OpenFile(Name);
|
||||
|
21
Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntry.cs
Normal file
21
Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntry.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.FspSrv
|
||||
{
|
||||
public struct DirectoryEntry
|
||||
{
|
||||
public string Path { get; private set; }
|
||||
public long Size { get; private set; }
|
||||
|
||||
public DirectoryEntryType EntryType { get; set; }
|
||||
|
||||
public DirectoryEntry(string Path, DirectoryEntryType DirectoryEntryType, long Size = 0)
|
||||
{
|
||||
this.Path = Path;
|
||||
this.EntryType = DirectoryEntryType;
|
||||
this.Size = Size;
|
||||
}
|
||||
}
|
||||
}
|
8
Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntryType.cs
Normal file
8
Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntryType.cs
Normal file
|
@ -0,0 +1,8 @@
|
|||
namespace Ryujinx.HLE.HOS.Services.FspSrv
|
||||
{
|
||||
public enum DirectoryEntryType : byte
|
||||
{
|
||||
Directory,
|
||||
File
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
|
||||
|
||||
private List<string> DirectoryEntries;
|
||||
private List<DirectoryEntry> DirectoryEntries;
|
||||
|
||||
private int CurrentItemIndex;
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
|
||||
this.DirectoryPath = DirectoryPath;
|
||||
|
||||
DirectoryEntries = new List<string>();
|
||||
DirectoryEntries = new List<DirectoryEntry>();
|
||||
|
||||
if ((Flags & 1) != 0)
|
||||
{
|
||||
|
@ -73,29 +73,20 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
return 0;
|
||||
}
|
||||
|
||||
private void WriteDirectoryEntry(ServiceCtx Context, long Position, string FullPath)
|
||||
private void WriteDirectoryEntry(ServiceCtx Context, long Position, DirectoryEntry Entry)
|
||||
{
|
||||
for (int Offset = 0; Offset < 0x300; Offset += 8)
|
||||
{
|
||||
Context.Memory.WriteInt64(Position + Offset, 0);
|
||||
}
|
||||
|
||||
byte[] NameBuffer = Encoding.UTF8.GetBytes(Path.GetFileName(FullPath));
|
||||
byte[] NameBuffer = Encoding.UTF8.GetBytes(Path.GetFileName(Entry.Path));
|
||||
|
||||
Context.Memory.WriteBytes(Position, NameBuffer);
|
||||
|
||||
int Type = 0;
|
||||
long Size = 0;
|
||||
|
||||
if (File.Exists(FullPath))
|
||||
{
|
||||
Type = 1;
|
||||
Size = new FileInfo(FullPath).Length;
|
||||
}
|
||||
|
||||
Context.Memory.WriteInt32(Position + 0x300, 0); //Padding?
|
||||
Context.Memory.WriteInt32(Position + 0x304, Type);
|
||||
Context.Memory.WriteInt64(Position + 0x308, Size);
|
||||
Context.Memory.WriteInt32(Position + 0x304, (byte)Entry.EntryType);
|
||||
Context.Memory.WriteInt64(Position + 0x308, Entry.Size);
|
||||
}
|
||||
|
||||
public long GetEntryCount(ServiceCtx Context)
|
||||
|
|
|
@ -340,15 +340,15 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
|
||||
}
|
||||
|
||||
foreach (string Entry in Provider.GetEntries(DirName))
|
||||
foreach (DirectoryEntry Entry in Provider.GetEntries(DirName))
|
||||
{
|
||||
if (Provider.DirectoryExists(Entry))
|
||||
if (Provider.DirectoryExists(Entry.Path))
|
||||
{
|
||||
Provider.DeleteDirectory(Entry, true);
|
||||
Provider.DeleteDirectory(Entry.Path, true);
|
||||
}
|
||||
else if (Provider.FileExists(Entry))
|
||||
else if (Provider.FileExists(Entry.Path))
|
||||
{
|
||||
Provider.DeleteFile(Entry);
|
||||
Provider.DeleteFile(Entry.Path);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,23 +79,48 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
|
|||
|
||||
long TitleId = Context.RequestData.ReadInt64();
|
||||
|
||||
string Path = ReadUtf8String(Context);
|
||||
string SwitchPath = ReadUtf8String(Context);
|
||||
|
||||
string FullPath = Context.Device.FileSystem.SwitchPathToSystemPath(Path);
|
||||
string FullPath = Context.Device.FileSystem.SwitchPathToSystemPath(SwitchPath);
|
||||
|
||||
FileStream FileStream = new FileStream(FullPath, FileMode.Open, FileAccess.Read);
|
||||
|
||||
Nca Nca = new Nca(Context.Device.System.KeySet, FileStream, false);
|
||||
string Extension = Path.GetExtension(FullPath);
|
||||
|
||||
NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
|
||||
if (RomfsSection != null)
|
||||
if (Extension == ".nca")
|
||||
{
|
||||
Stream RomfsStream = Nca.OpenSection(RomfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel);
|
||||
Nca Nca = new Nca(Context.Device.System.KeySet, FileStream, false);
|
||||
|
||||
IFileSystem NcaFileSystem = new IFileSystem(Path, new RomFileSystemProvider(RomfsStream));
|
||||
NcaSection RomfsSection = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
|
||||
|
||||
MakeObject(Context, NcaFileSystem);
|
||||
if (RomfsSection != null)
|
||||
{
|
||||
Stream RomfsStream = Nca.OpenSection(RomfsSection.SectionNum, false, Context.Device.System.FsIntegrityCheckLevel);
|
||||
|
||||
IFileSystem NcaFileSystem = new IFileSystem(SwitchPath, new RomFsProvider(RomfsStream));
|
||||
|
||||
MakeObject(Context, NcaFileSystem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (Extension == ".nsp")
|
||||
{
|
||||
Pfs Nsp = new Pfs(FileStream);
|
||||
|
||||
PfsFileEntry TicketFile = Nsp.Files.FirstOrDefault(x => x.Name.EndsWith(".tik"));
|
||||
|
||||
if (TicketFile != null)
|
||||
{
|
||||
Ticket Ticket = new Ticket(Nsp.OpenFile(TicketFile));
|
||||
|
||||
Context.Device.System.KeySet.TitleKeys[Ticket.RightsId] =
|
||||
Ticket.GetTitleKey(Context.Device.System.KeySet);
|
||||
}
|
||||
|
||||
IFileSystem NspFileSystem = new IFileSystem(SwitchPath, new PFsProvider(Nsp));
|
||||
|
||||
MakeObject(Context, NspFileSystem);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue