add pfs support, write directoryentry info for romfs files

This commit is contained in:
emmaus 2018-11-04 20:56:20 +00:00
parent 220cd16380
commit cacac0ea6e
9 changed files with 291 additions and 54 deletions

View file

@ -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)

View file

@ -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);

View 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();
}
}
}

View file

@ -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);

View 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;
}
}
}

View file

@ -0,0 +1,8 @@
namespace Ryujinx.HLE.HOS.Services.FspSrv
{
public enum DirectoryEntryType : byte
{
Directory,
File
}
}

View 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)

View file

@ -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);
}
}

View file

@ -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;
}