aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Ryujinx.HLE/FileSystem/Content/ContentManager.cs26
-rw-r--r--Ryujinx.HLE/FileSystem/Content/LocationEntry.cs2
-rw-r--r--Ryujinx.HLE/FileSystem/FileSystemProvider.cs313
-rw-r--r--Ryujinx.HLE/FileSystem/IFileSystemProvider.cs43
-rw-r--r--Ryujinx.HLE/FileSystem/PFsProvider.cs152
-rw-r--r--Ryujinx.HLE/FileSystem/RomFsProvider.cs169
-rw-r--r--Ryujinx.HLE/HOS/Font/SharedFontManager.cs26
-rw-r--r--Ryujinx.HLE/HOS/Horizon.cs282
-rw-r--r--Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntry.cs17
-rw-r--r--Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntryType.cs8
-rw-r--r--Ryujinx.HLE/HOS/Services/FspSrv/FileTimestamp.cs11
-rw-r--r--Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs52
-rw-r--r--Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs40
-rw-r--r--Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs321
-rw-r--r--Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs102
-rw-r--r--Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs15
-rw-r--r--Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs4
-rw-r--r--Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs19
-rw-r--r--Ryujinx.HLE/Ryujinx.HLE.csproj2
-rw-r--r--Ryujinx/Configuration.cs2
20 files changed, 451 insertions, 1155 deletions
diff --git a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs
index 94f06475..40109f1c 100644
--- a/Ryujinx.HLE/FileSystem/Content/ContentManager.cs
+++ b/Ryujinx.HLE/FileSystem/Content/ContentManager.cs
@@ -1,5 +1,5 @@
-using LibHac;
-using LibHac.IO;
+using LibHac.Fs;
+using LibHac.Fs.NcaUtils;
using Ryujinx.HLE.Utilities;
using System;
using System.Collections.Generic;
@@ -13,6 +13,7 @@ namespace Ryujinx.HLE.FileSystem.Content
private Dictionary<StorageId, LinkedList<LocationEntry>> _locationEntries;
private Dictionary<string, long> _sharedFontTitleDictionary;
+ private Dictionary<string, string> _sharedFontFilenameDictionary;
private SortedDictionary<(ulong, ContentType), string> _contentDictionary;
@@ -33,6 +34,16 @@ namespace Ryujinx.HLE.FileSystem.Content
{ "FontNintendoExtended", 0x0100000000000810 }
};
+ _sharedFontFilenameDictionary = new Dictionary<string, string>
+ {
+ { "FontStandard", "nintendo_udsg-r_std_003.bfttf" },
+ { "FontChineseSimplified", "nintendo_udsg-r_org_zh-cn_003.bfttf" },
+ { "FontExtendedChineseSimplified", "nintendo_udsg-r_ext_zh-cn_003.bfttf" },
+ { "FontKorean", "nintendo_udsg-r_ko_003.bfttf" },
+ { "FontChineseTraditional", "nintendo_udjxh-db_zh-tw_003.bfttf" },
+ { "FontNintendoExtended", "nintendo_ext_003.bfttf" }
+ };
+
_device = device;
}
@@ -74,7 +85,7 @@ namespace Ryujinx.HLE.FileSystem.Content
using (FileStream ncaFile = new FileStream(Directory.GetFiles(directoryPath)[0], FileMode.Open, FileAccess.Read))
{
- Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage(), false);
+ Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage());
string switchPath = Path.Combine(contentPathString + ":",
ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart('\\'));
@@ -102,7 +113,7 @@ namespace Ryujinx.HLE.FileSystem.Content
using (FileStream ncaFile = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
- Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage(), false);
+ Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage());
string switchPath = Path.Combine(contentPathString + ":",
filePath.Replace(contentDirectory, string.Empty).TrimStart('\\'));
@@ -230,7 +241,7 @@ namespace Ryujinx.HLE.FileSystem.Content
{
using (FileStream file = new FileStream(installedPath, FileMode.Open, FileAccess.Read))
{
- Nca nca = new Nca(_device.System.KeySet, file.AsStorage(), false);
+ Nca nca = new Nca(_device.System.KeySet, file.AsStorage());
bool contentCheck = nca.Header.ContentType == contentType;
return contentCheck;
@@ -287,6 +298,11 @@ namespace Ryujinx.HLE.FileSystem.Content
return _sharedFontTitleDictionary.TryGetValue(fontName, out titleId);
}
+ public bool TryGetFontFilename(string fontName, out string filename)
+ {
+ return _sharedFontFilenameDictionary.TryGetValue(fontName, out filename);
+ }
+
private LocationEntry GetLocation(long titleId, ContentType contentType, StorageId storageId)
{
LinkedList<LocationEntry> locationList = _locationEntries[storageId];
diff --git a/Ryujinx.HLE/FileSystem/Content/LocationEntry.cs b/Ryujinx.HLE/FileSystem/Content/LocationEntry.cs
index eabcfed8..2ab7ea80 100644
--- a/Ryujinx.HLE/FileSystem/Content/LocationEntry.cs
+++ b/Ryujinx.HLE/FileSystem/Content/LocationEntry.cs
@@ -1,4 +1,4 @@
-using LibHac;
+using LibHac.Fs.NcaUtils;
namespace Ryujinx.HLE.FileSystem.Content
{
diff --git a/Ryujinx.HLE/FileSystem/FileSystemProvider.cs b/Ryujinx.HLE/FileSystem/FileSystemProvider.cs
deleted file mode 100644
index f5459eec..00000000
--- a/Ryujinx.HLE/FileSystem/FileSystemProvider.cs
+++ /dev/null
@@ -1,313 +0,0 @@
-using Ryujinx.HLE.HOS;
-using Ryujinx.HLE.HOS.Services.FspSrv;
-using Ryujinx.HLE.Utilities;
-using System;
-using System.Collections.Generic;
-using System.IO;
-
-using static Ryujinx.HLE.HOS.ErrorCode;
-
-namespace Ryujinx.HLE.FileSystem
-{
- class FileSystemProvider : IFileSystemProvider
- {
- private readonly string _basePath;
- private readonly string _rootPath;
-
- public FileSystemProvider(string basePath, string rootPath)
- {
- _basePath = basePath;
- _rootPath = rootPath;
-
- CheckIfDescendentOfRootPath(basePath);
- }
-
- public long CreateDirectory(string name)
- {
- CheckIfDescendentOfRootPath(name);
-
- if (Directory.Exists(name))
- {
- return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
- }
-
- Directory.CreateDirectory(name);
-
- return 0;
- }
-
- public long CreateFile(string name, long size)
- {
- CheckIfDescendentOfRootPath(name);
-
- if (File.Exists(name))
- {
- return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
- }
-
- using (FileStream newFile = File.Create(name))
- {
- newFile.SetLength(size);
- }
-
- return 0;
- }
-
- public long DeleteDirectory(string name, bool recursive)
- {
- CheckIfDescendentOfRootPath(name);
-
- string dirName = name;
-
- if (!Directory.Exists(dirName))
- {
- return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
- }
-
- Directory.Delete(dirName, recursive);
-
- return 0;
- }
-
- public long DeleteFile(string name)
- {
- CheckIfDescendentOfRootPath(name);
-
- if (!File.Exists(name))
- {
- return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
- }
- else
- {
- File.Delete(name);
- }
-
- return 0;
- }
-
- public DirectoryEntry[] GetDirectories(string path)
- {
- CheckIfDescendentOfRootPath(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 DirectoryEntry[] GetEntries(string path)
- {
- CheckIfDescendentOfRootPath(path);
-
- if (Directory.Exists(path))
- {
- 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 entries.ToArray();
- }
-
- return null;
- }
-
- public DirectoryEntry[] GetFiles(string path)
- {
- CheckIfDescendentOfRootPath(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)
- {
- return context.Device.FileSystem.GetDrive().AvailableFreeSpace;
- }
-
- public string GetFullPath(string name)
- {
- if (name.StartsWith("//"))
- {
- name = name.Substring(2);
- }
- else if (name.StartsWith('/'))
- {
- name = name.Substring(1);
- }
- else
- {
- return null;
- }
-
- string fullPath = Path.Combine(_basePath, name);
-
- CheckIfDescendentOfRootPath(fullPath);
-
- return fullPath;
- }
-
- public long GetTotalSpace(ServiceCtx context)
- {
- return context.Device.FileSystem.GetDrive().TotalSize;
- }
-
- public bool DirectoryExists(string name)
- {
- CheckIfDescendentOfRootPath(name);
-
- return Directory.Exists(name);
- }
-
- public bool FileExists(string name)
- {
- CheckIfDescendentOfRootPath(name);
-
- return File.Exists(name);
- }
-
- public long OpenDirectory(string name, int filterFlags, out IDirectory directoryInterface)
- {
- CheckIfDescendentOfRootPath(name);
-
- if (Directory.Exists(name))
- {
- directoryInterface = new IDirectory(name, filterFlags, this);
-
- return 0;
- }
-
- directoryInterface = null;
-
- return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
- }
-
- public long OpenFile(string name, out IFile fileInterface)
- {
- CheckIfDescendentOfRootPath(name);
-
- if (File.Exists(name))
- {
- FileStream stream = new FileStream(name, FileMode.Open);
-
- fileInterface = new IFile(stream, name);
-
- return 0;
- }
-
- fileInterface = null;
-
- return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
- }
-
- public long RenameDirectory(string oldName, string newName)
- {
- CheckIfDescendentOfRootPath(oldName);
- CheckIfDescendentOfRootPath(newName);
-
- if (Directory.Exists(oldName))
- {
- Directory.Move(oldName, newName);
- }
- else
- {
- return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
- }
-
- return 0;
- }
-
- public long RenameFile(string oldName, string newName)
- {
- CheckIfDescendentOfRootPath(oldName);
- CheckIfDescendentOfRootPath(newName);
-
- if (File.Exists(oldName))
- {
- File.Move(oldName, newName);
- }
- else
- {
- return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
- }
-
- return 0;
- }
-
- public void CheckIfDescendentOfRootPath(string path)
- {
- DirectoryInfo pathInfo = new DirectoryInfo(path);
- DirectoryInfo rootInfo = new DirectoryInfo(_rootPath);
-
- while (pathInfo.Parent != null)
- {
- if (pathInfo.Parent.FullName == rootInfo.FullName)
- {
- return;
- }
- else
- {
- pathInfo = pathInfo.Parent;
- }
- }
-
- throw new InvalidOperationException($"Path {path} is not a child directory of {_rootPath}");
- }
-
- public FileTimestamp GetFileTimeStampRaw(string name)
- {
- CheckIfDescendentOfRootPath(name);
-
- DateTime creationDateTime = DateTime.UnixEpoch;
- DateTime modifiedDateTime = DateTime.UnixEpoch;
- DateTime lastAccessDateTime = DateTime.UnixEpoch;
-
- if (File.Exists(name))
- {
- creationDateTime = File.GetCreationTime(name);
- modifiedDateTime = File.GetLastWriteTime(name);
- lastAccessDateTime = File.GetLastAccessTime(name);
- }
- else if (Directory.Exists(name))
- {
- creationDateTime = Directory.GetCreationTime(name);
- modifiedDateTime = Directory.GetLastWriteTime(name);
- lastAccessDateTime = Directory.GetLastAccessTime(name);
- }
-
- return new FileTimestamp
- {
- CreationDateTime = creationDateTime,
- ModifiedDateTime = modifiedDateTime,
- LastAccessDateTime = lastAccessDateTime
- };
- }
- }
-}
diff --git a/Ryujinx.HLE/FileSystem/IFileSystemProvider.cs b/Ryujinx.HLE/FileSystem/IFileSystemProvider.cs
deleted file mode 100644
index 82cdebd9..00000000
--- a/Ryujinx.HLE/FileSystem/IFileSystemProvider.cs
+++ /dev/null
@@ -1,43 +0,0 @@
-using Ryujinx.HLE.HOS;
-using Ryujinx.HLE.HOS.Services.FspSrv;
-using System;
-
-namespace Ryujinx.HLE.FileSystem
-{
- interface IFileSystemProvider
- {
- long CreateFile(string name, long size);
-
- long CreateDirectory(string name);
-
- long RenameFile(string oldName, string newName);
-
- long RenameDirectory(string oldName, string newName);
-
- DirectoryEntry[] GetEntries(string path);
-
- DirectoryEntry[] GetDirectories(string path);
-
- DirectoryEntry[] GetFiles(string path);
-
- long DeleteFile(string name);
-
- long DeleteDirectory(string name, bool recursive);
-
- bool FileExists(string name);
-
- bool DirectoryExists(string name);
-
- long OpenFile(string name, out IFile fileInterface);
-
- long OpenDirectory(string name, int filterFlags, out IDirectory directoryInterface);
-
- string GetFullPath(string name);
-
- long GetFreeSpace(ServiceCtx context);
-
- long GetTotalSpace(ServiceCtx context);
-
- FileTimestamp GetFileTimeStampRaw(string name);
- }
-}
diff --git a/Ryujinx.HLE/FileSystem/PFsProvider.cs b/Ryujinx.HLE/FileSystem/PFsProvider.cs
deleted file mode 100644
index 69e7a9b8..00000000
--- a/Ryujinx.HLE/FileSystem/PFsProvider.cs
+++ /dev/null
@@ -1,152 +0,0 @@
-using LibHac;
-using LibHac.IO;
-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)
- {
- _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 == "/";
- }
-
- 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)
- {
- name = name.TrimStart('/');
-
- if (_pfs.FileExists(name))
- {
- Stream stream = _pfs.OpenFile(name).AsStream();
- fileInterface = new IFile(stream, name);
-
- return 0;
- }
-
- fileInterface = null;
-
- 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();
- }
-
- public FileTimestamp GetFileTimeStampRaw(string name)
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/Ryujinx.HLE/FileSystem/RomFsProvider.cs b/Ryujinx.HLE/FileSystem/RomFsProvider.cs
deleted file mode 100644
index f64d99c7..00000000
--- a/Ryujinx.HLE/FileSystem/RomFsProvider.cs
+++ /dev/null
@@ -1,169 +0,0 @@
-using LibHac;
-using LibHac.IO;
-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 RomFsProvider : IFileSystemProvider
- {
- private Romfs _romFs;
-
- public RomFsProvider(LibHac.IO.IStorage storage)
- {
- _romFs = new Romfs(storage);
- }
-
- 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)
- {
- List<DirectoryEntry> directories = new List<DirectoryEntry>();
-
- foreach(RomfsDir directory in _romFs.Directories)
- {
- DirectoryEntry directoryEntry = new DirectoryEntry(directory.Name, DirectoryEntryType.Directory);
-
- directories.Add(directoryEntry);
- }
-
- return directories.ToArray();
- }
-
- public DirectoryEntry[] GetEntries(string path)
- {
- List<DirectoryEntry> entries = new List<DirectoryEntry>();
-
- foreach (RomfsDir directory in _romFs.Directories)
- {
- DirectoryEntry directoryEntry = new DirectoryEntry(directory.Name, DirectoryEntryType.Directory);
-
- entries.Add(directoryEntry);
- }
-
- foreach (RomfsFile file in _romFs.Files)
- {
- DirectoryEntry directoryEntry = new DirectoryEntry(file.Name, DirectoryEntryType.File, file.DataLength);
-
- entries.Add(directoryEntry);
- }
-
- return entries.ToArray();
- }
-
- public DirectoryEntry[] GetFiles(string path)
- {
- List<DirectoryEntry> files = new List<DirectoryEntry>();
-
- foreach (RomfsFile file in _romFs.Files)
- {
- DirectoryEntry directoryEntry = new DirectoryEntry(file.Name, DirectoryEntryType.File, file.DataLength);
-
- files.Add(directoryEntry);
- }
-
- return files.ToArray();
- }
-
- public long GetFreeSpace(ServiceCtx context)
- {
- return 0;
- }
-
- public string GetFullPath(string name)
- {
- return name;
- }
-
- public long GetTotalSpace(ServiceCtx context)
- {
- return _romFs.Files.Sum(x => x.DataLength);
- }
-
- public bool DirectoryExists(string name)
- {
- return _romFs.Directories.Exists(x=>x.Name == name);
- }
-
- public bool FileExists(string name)
- {
- return _romFs.FileExists(name);
- }
-
- public long OpenDirectory(string name, int filterFlags, out IDirectory directoryInterface)
- {
- RomfsDir directory = _romFs.Directories.Find(x => x.Name == name);
-
- if (directory != null)
- {
- directoryInterface = new IDirectory(name, filterFlags, this);
-
- return 0;
- }
-
- directoryInterface = null;
-
- return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
- }
-
- public long OpenFile(string name, out IFile fileInterface)
- {
- if (_romFs.FileExists(name))
- {
- Stream stream = _romFs.OpenFile(name).AsStream();
-
- fileInterface = new IFile(stream, name);
-
- return 0;
- }
-
- fileInterface = null;
-
- 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();
- }
-
- public FileTimestamp GetFileTimeStampRaw(string name)
- {
- throw new NotImplementedException();
- }
- }
-}
diff --git a/Ryujinx.HLE/HOS/Font/SharedFontManager.cs b/Ryujinx.HLE/HOS/Font/SharedFontManager.cs
index 9eb2c7e5..dfb87f3c 100644
--- a/Ryujinx.HLE/HOS/Font/SharedFontManager.cs
+++ b/Ryujinx.HLE/HOS/Font/SharedFontManager.cs
@@ -1,13 +1,11 @@
-using LibHac;
-using LibHac.IO;
+using LibHac.Fs;
+using LibHac.Fs.NcaUtils;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.Resource;
using Ryujinx.HLE.Utilities;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
-
using static Ryujinx.HLE.Utilities.FontUtils;
namespace Ryujinx.HLE.HOS.Font
@@ -53,29 +51,21 @@ namespace Ryujinx.HLE.HOS.Font
FontInfo CreateFont(string name)
{
- if (contentManager.TryGetFontTitle(name, out long fontTitle))
+ if (contentManager.TryGetFontTitle(name, out long fontTitle) &&
+ contentManager.TryGetFontFilename(name, out string fontFilename))
{
string contentPath = contentManager.GetInstalledContentPath(fontTitle, StorageId.NandSystem, ContentType.Data);
string fontPath = _device.FileSystem.SwitchPathToSystemPath(contentPath);
if (!string.IsNullOrWhiteSpace(fontPath))
{
- int fileIndex = 0;
-
- //Use second file in Chinese Font title for standard
- if(name == "FontChineseSimplified")
- {
- fileIndex = 1;
- }
-
byte[] data;
- using (FileStream ncaFileStream = new FileStream(fontPath, FileMode.Open, FileAccess.Read))
+ using (IStorage ncaFileStream = new LocalStorage(fontPath, FileAccess.Read, FileMode.Open))
{
- Nca nca = new Nca(_device.System.KeySet, ncaFileStream.AsStorage(), false);
- NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
- Romfs romfs = new Romfs(nca.OpenSection(romfsSection.SectionNum, false, _device.System.FsIntegrityCheckLevel, false));
- Stream fontFile = romfs.OpenFile(romfs.Files[fileIndex]).AsStream();
+ Nca nca = new Nca(_device.System.KeySet, ncaFileStream);
+ IFileSystem romfs = nca.OpenFileSystem(NcaSectionType.Data, _device.System.FsIntegrityCheckLevel);
+ Stream fontFile = romfs.OpenFile(fontFilename, OpenMode.Read).AsStream();
data = DecryptFont(fontFile);
}
diff --git a/Ryujinx.HLE/HOS/Horizon.cs b/Ryujinx.HLE/HOS/Horizon.cs
index acb6b1d1..0b55ee0a 100644
--- a/Ryujinx.HLE/HOS/Horizon.cs
+++ b/Ryujinx.HLE/HOS/Horizon.cs
@@ -1,5 +1,6 @@
using LibHac;
-using LibHac.IO;
+using LibHac.Fs;
+using LibHac.Fs.NcaUtils;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Font;
@@ -195,58 +196,9 @@ namespace Ryujinx.HLE.HOS
Device.FileSystem.LoadRomFs(romFsFile);
}
- string npdmFileName = Path.Combine(exeFsDir, "main.npdm");
+ LocalFileSystem codeFs = new LocalFileSystem(exeFsDir);
- Npdm metaData = null;
-
- if (File.Exists(npdmFileName))
- {
- Logger.PrintInfo(LogClass.Loader, $"Loading main.npdm...");
-
- using (FileStream input = new FileStream(npdmFileName, FileMode.Open))
- {
- metaData = new Npdm(input);
- }
- }
- else
- {
- Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
-
- metaData = GetDefaultNpdm();
- }
-
- List<IExecutable> staticObjects = new List<IExecutable>();
-
- void LoadNso(string searchPattern)
- {
- foreach (string file in Directory.GetFiles(exeFsDir, searchPattern))
- {
- if (Path.GetExtension(file) != string.Empty)
- {
- continue;
- }
-
- Logger.PrintInfo(LogClass.Loader, $"Loading {Path.GetFileNameWithoutExtension(file)}...");
-
- using (FileStream input = new FileStream(file, FileMode.Open))
- {
- NxStaticObject staticObject = new NxStaticObject(input);
-
- staticObjects.Add(staticObject);
- }
- }
- }
-
- TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
-
- LoadNso("rtld");
- LoadNso("main");
- LoadNso("subsdk*");
- LoadNso("sdk");
-
- ContentManager.LoadEntries();
-
- ProgramLoader.LoadStaticObjects(this, metaData, staticObjects.ToArray());
+ LoadExeFs(codeFs, out _);
}
public void LoadXci(string xciFile)
@@ -255,7 +207,7 @@ namespace Ryujinx.HLE.HOS
Xci xci = new Xci(KeySet, file.AsStorage());
- (Nca mainNca, Nca controlNca) = GetXciGameData(xci);
+ (Nca mainNca, Nca patchNca, Nca controlNca) = GetXciGameData(xci);
if (mainNca == null)
{
@@ -266,7 +218,7 @@ namespace Ryujinx.HLE.HOS
ContentManager.LoadEntries();
- LoadNca(mainNca, controlNca);
+ LoadNca(mainNca, patchNca, controlNca);
}
public void LoadKip(string kipFile)
@@ -277,9 +229,9 @@ namespace Ryujinx.HLE.HOS
}
}
- private (Nca Main, Nca Control) GetXciGameData(Xci xci)
+ private (Nca Main, Nca patch, Nca Control) GetXciGameData(Xci xci)
{
- if (xci.SecurePartition == null)
+ if (!xci.HasPartition(XciPartitionType.Secure))
{
throw new InvalidDataException("Could not find XCI secure partition");
}
@@ -288,9 +240,11 @@ namespace Ryujinx.HLE.HOS
Nca patchNca = null;
Nca controlNca = null;
- foreach (PfsFileEntry ticketEntry in xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".tik")))
+ XciPartition securePartition = xci.OpenPartition(XciPartitionType.Secure);
+
+ foreach (DirectoryEntry ticketEntry in securePartition.EnumerateEntries("*.tik"))
{
- Ticket ticket = new Ticket(xci.SecurePartition.OpenFile(ticketEntry).AsStream());
+ Ticket ticket = new Ticket(securePartition.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream());
if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId))
{
@@ -298,21 +252,23 @@ namespace Ryujinx.HLE.HOS
}
}
- foreach (PfsFileEntry fileEntry in xci.SecurePartition.Files.Where(x => x.Name.EndsWith(".nca")))
+ foreach (DirectoryEntry fileEntry in securePartition.EnumerateEntries("*.nca"))
{
- IStorage ncaStorage = xci.SecurePartition.OpenFile(fileEntry);
+ IStorage ncaStorage = securePartition.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage();
- Nca nca = new Nca(KeySet, ncaStorage, true);
+ Nca nca = new Nca(KeySet, ncaStorage);
if (nca.Header.ContentType == ContentType.Program)
{
- if (nca.Sections.Any(x => x?.Type == SectionType.Romfs))
+ int dataIndex = Nca.SectionIndexFromType(NcaSectionType.Data, ContentType.Program);
+
+ if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
{
- mainNca = nca;
+ patchNca = nca;
}
- else if (nca.Sections.Any(x => x?.Type == SectionType.Bktr))
+ else
{
- patchNca = nca;
+ mainNca = nca;
}
}
else if (nca.Header.ContentType == ContentType.Control)
@@ -326,50 +282,43 @@ namespace Ryujinx.HLE.HOS
Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided XCI file");
}
- mainNca.SetBaseNca(patchNca);
-
if (controlNca != null)
{
ReadControlData(controlNca);
}
- if (patchNca != null)
- {
- patchNca.SetBaseNca(mainNca);
-
- return (patchNca, controlNca);
- }
-
- return (mainNca, controlNca);
+ return (mainNca, patchNca, controlNca);
}
public void ReadControlData(Nca controlNca)
{
- Romfs controlRomfs = new Romfs(controlNca.OpenSection(0, false, FsIntegrityCheckLevel, true));
+ IFileSystem controlFs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel);
- IStorage controlFile = controlRomfs.OpenFile("/control.nacp");
+ IFile controlFile = controlFs.OpenFile("/control.nacp", OpenMode.Read);
ControlData = new Nacp(controlFile.AsStream());
+
+ TitleName = CurrentTitle = ControlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
}
public void LoadNca(string ncaFile)
{
FileStream file = new FileStream(ncaFile, FileMode.Open, FileAccess.Read);
- Nca nca = new Nca(KeySet, file.AsStorage(false), false);
+ Nca nca = new Nca(KeySet, file.AsStorage(false));
- LoadNca(nca, null);
+ LoadNca(nca, null, null);
}
public void LoadNsp(string nspFile)
{
FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read);
- Pfs nsp = new Pfs(file.AsStorage(false));
+ PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage());
- foreach (PfsFileEntry ticketEntry in nsp.Files.Where(x => x.Name.EndsWith(".tik")))
+ foreach (DirectoryEntry ticketEntry in nsp.EnumerateEntries("*.tik"))
{
- Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry).AsStream());
+ Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream());
if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId))
{
@@ -378,15 +327,27 @@ namespace Ryujinx.HLE.HOS
}
Nca mainNca = null;
+ Nca patchNca = null;
Nca controlNca = null;
- foreach (PfsFileEntry ncaFile in nsp.Files.Where(x => x.Name.EndsWith(".nca")))
+ foreach (DirectoryEntry fileEntry in nsp.EnumerateEntries("*.nca"))
{
- Nca nca = new Nca(KeySet, nsp.OpenFile(ncaFile), true);
+ IStorage ncaStorage = nsp.OpenFile(fileEntry.FullPath, OpenMode.Read).AsStorage();
+
+ Nca nca = new Nca(KeySet, ncaStorage);
if (nca.Header.ContentType == ContentType.Program)
{
- mainNca = nca;
+ int dataIndex = Nca.SectionIndexFromType(NcaSectionType.Data, ContentType.Program);
+
+ if (nca.Header.GetFsHeader(dataIndex).IsPatchSection())
+ {
+ patchNca = nca;
+ }
+ else
+ {
+ mainNca = nca;
+ }
}
else if (nca.Header.ContentType == ContentType.Control)
{
@@ -396,105 +357,112 @@ namespace Ryujinx.HLE.HOS
if (mainNca != null)
{
- LoadNca(mainNca, controlNca);
+ LoadNca(mainNca, patchNca, controlNca);
return;
}
// This is not a normal NSP, it's actually a ExeFS as a NSP
- Npdm metaData = null;
-
- PfsFileEntry npdmFile = nsp.Files.FirstOrDefault(x => x.Name.Equals("main.npdm"));
-
- if (npdmFile != null)
- {
- Logger.PrintInfo(LogClass.Loader, $"Loading main.npdm...");
+ LoadExeFs(nsp, out _);
+ }
- metaData = new Npdm(nsp.OpenFile(npdmFile).AsStream());
- }
- else
+ public void LoadNca(Nca mainNca, Nca patchNca, Nca controlNca)
+ {
+ if (mainNca.Header.ContentType != ContentType.Program)
{
- Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
+ Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");
- metaData = GetDefaultNpdm();
+ return;
}
- List<IExecutable> staticObjects = new List<IExecutable>();
+ IStorage dataStorage = null;
+ IFileSystem codeFs = null;
- void LoadNso(string searchPattern)
+ if (patchNca == null)
{
- PfsFileEntry entry = nsp.Files.FirstOrDefault(x => x.Name.Equals(searchPattern));
-
- if (entry != null)
+ if (mainNca.CanOpenSection(NcaSectionType.Data))
{
- Logger.PrintInfo(LogClass.Loader, $"Loading {entry.Name}...");
-
- NxStaticObject staticObject = new NxStaticObject(nsp.OpenFile(entry).AsStream());
+ dataStorage = mainNca.OpenStorage(NcaSectionType.Data, FsIntegrityCheckLevel);
+ }
- staticObjects.Add(staticObject);
+ if (mainNca.CanOpenSection(NcaSectionType.Code))
+ {
+ codeFs = mainNca.OpenFileSystem(NcaSectionType.Code, FsIntegrityCheckLevel);
}
}
+ else
+ {
+ if (patchNca.CanOpenSection(NcaSectionType.Data))
+ {
+ dataStorage = mainNca.OpenStorageWithPatch(patchNca, NcaSectionType.Data, FsIntegrityCheckLevel);
+ }
- TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
+ if (patchNca.CanOpenSection(NcaSectionType.Code))
+ {
+ codeFs = mainNca.OpenFileSystemWithPatch(patchNca, NcaSectionType.Code, FsIntegrityCheckLevel);
+ }
+ }
- LoadNso("rtld");
- LoadNso("main");
- LoadNso("subsdk*");
- LoadNso("sdk");
+ if (codeFs == null)
+ {
+ Logger.PrintError(LogClass.Loader, "No ExeFS found in NCA");
- ContentManager.LoadEntries();
+ return;
+ }
- if (staticObjects.Count == 0)
+ if (dataStorage == null)
{
- Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file");
+ Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
}
else
{
- ProgramLoader.LoadStaticObjects(this, metaData, staticObjects.ToArray());
+ Device.FileSystem.SetRomFs(dataStorage.AsStream(FileAccess.Read));
}
- }
- public void LoadNca(Nca mainNca, Nca controlNca)
- {
- if (mainNca.Header.ContentType != ContentType.Program)
+ LoadExeFs(codeFs, out Npdm metaData);
+
+ Nacp ReadControlData()
{
- Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA");
+ IFileSystem controlRomfs = controlNca.OpenFileSystem(NcaSectionType.Data, FsIntegrityCheckLevel);
- return;
- }
+ IFile controlFile = controlRomfs.OpenFile("/control.nacp", OpenMode.Read);
+
+ Nacp controlData = new Nacp(controlFile.AsStream());
- IStorage romfsStorage = mainNca.OpenSection(ProgramPartitionType.Data, false, FsIntegrityCheckLevel, false);
- IStorage exefsStorage = mainNca.OpenSection(ProgramPartitionType.Code, false, FsIntegrityCheckLevel, true);
+ TitleName = CurrentTitle = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
+ TitleID = metaData.Aci0.TitleId.ToString("x16");
- if (exefsStorage == null)
- {
- Logger.PrintError(LogClass.Loader, "No ExeFS found in NCA");
+ CurrentTitle = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
- return;
+ if (string.IsNullOrWhiteSpace(CurrentTitle))
+ {
+ TitleName = CurrentTitle = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title;
+ }
+
+ return controlData;
}
- if (romfsStorage == null)
+ if (controlNca != null)
{
- Logger.PrintWarning(LogClass.Loader, "No RomFS found in NCA");
+ ReadControlData();
}
else
{
- Device.FileSystem.SetRomFs(romfsStorage.AsStream(false));
+ TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
}
+ }
- Pfs exefs = new Pfs(exefsStorage);
-
- Npdm metaData = null;
-
- if (exefs.FileExists("main.npdm"))
+ private void LoadExeFs(IFileSystem codeFs, out Npdm metaData)
+ {
+ if (codeFs.FileExists("/main.npdm"))
{
Logger.PrintInfo(LogClass.Loader, "Loading main.npdm...");
- metaData = new Npdm(exefs.OpenFile("main.npdm").AsStream());
+ metaData = new Npdm(codeFs.OpenFile("/main.npdm", OpenMode.Read).AsStream());
}
else
{
- Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!");
+ Logger.PrintWarning(LogClass.Loader, "NPDM file not found, using default values!");
metaData = GetDefaultNpdm();
}
@@ -503,48 +471,22 @@ namespace Ryujinx.HLE.HOS
void LoadNso(string filename)
{
- foreach (PfsFileEntry file in exefs.Files.Where(x => x.Name.StartsWith(filename)))
+ foreach (DirectoryEntry file in codeFs.EnumerateEntries($"{filename}*"))
{
if (Path.GetExtension(file.Name) != string.Empty)
{
continue;
}
- Logger.PrintInfo(LogClass.Loader, $"Loading {filename}...");
+ Logger.PrintInfo(LogClass.Loader, $"Loading {file.Name}...");
- NxStaticObject staticObject = new NxStaticObject(exefs.OpenFile(file).AsStream());
+ NxStaticObject staticObject = new NxStaticObject(codeFs.OpenFile(file.FullPath, OpenMode.Read).AsStream());
staticObjects.Add(staticObject);
}
}
- Nacp ReadControlData()
- {
- Romfs controlRomfs = new Romfs(controlNca.OpenSection(0, false, FsIntegrityCheckLevel, true));
-
- IStorage controlFile = controlRomfs.OpenFile("/control.nacp");
-
- Nacp controlData = new Nacp(controlFile.AsStream());
-
- TitleName = CurrentTitle = controlData.Descriptions[(int)State.DesiredTitleLanguage].Title;
- TitleID = metaData.Aci0.TitleId.ToString("x16");
-
- if (string.IsNullOrWhiteSpace(CurrentTitle))
- {
- TitleName = CurrentTitle = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title;
- }
-
- return controlData;
- }
-
- if (controlNca != null)
- {
- ReadControlData();
- }
- else
- {
- TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
- }
+ TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
LoadNso("rtld");
LoadNso("main");
@@ -613,7 +555,7 @@ namespace Ryujinx.HLE.HOS
ContentManager.LoadEntries();
- TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
+ TitleID = CurrentTitle = metaData.Aci0.TitleId.ToString("x16");
TitleName = metaData.TitleName;
ProgramLoader.LoadStaticObjects(this, metaData, new IExecutable[] { staticObject });
diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntry.cs b/Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntry.cs
deleted file mode 100644
index 6c3dadb1..00000000
--- a/Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntry.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-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)
- {
- Path = path;
- EntryType = directoryEntryType;
- Size = size;
- }
- }
-}
diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntryType.cs b/Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntryType.cs
deleted file mode 100644
index da075a5f..00000000
--- a/Ryujinx.HLE/HOS/Services/FspSrv/DirectoryEntryType.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace Ryujinx.HLE.HOS.Services.FspSrv
-{
- public enum DirectoryEntryType
- {
- Directory,
- File
- }
-}
diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/FileTimestamp.cs b/Ryujinx.HLE/HOS/Services/FspSrv/FileTimestamp.cs
deleted file mode 100644
index 879fb78c..00000000
--- a/Ryujinx.HLE/HOS/Services/FspSrv/FileTimestamp.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-
-namespace Ryujinx.HLE.HOS.Services.FspSrv
-{
- struct FileTimestamp
- {
- public DateTime CreationDateTime;
- public DateTime ModifiedDateTime;
- public DateTime LastAccessDateTime;
- }
-} \ No newline at end of file
diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs
index 5f6235a5..c0ffe767 100644
--- a/Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs
+++ b/Ryujinx.HLE/HOS/Services/FspSrv/IDirectory.cs
@@ -1,8 +1,6 @@
-using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Ipc;
using System;
using System.Collections.Generic;
-using System.IO;
using System.Text;
namespace Ryujinx.HLE.HOS.Services.FspSrv
@@ -15,17 +13,15 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
- private List<DirectoryEntry> _directoryEntries;
-
- private int _currentItemIndex;
+ private IEnumerator<LibHac.Fs.DirectoryEntry> _enumerator;
public event EventHandler<EventArgs> Disposed;
- public string DirectoryPath { get; private set; }
+ public string Path { get; }
- private IFileSystemProvider _provider;
+ private LibHac.Fs.IDirectory _provider;
- public IDirectory(string directoryPath, int flags, IFileSystemProvider provider)
+ public IDirectory(LibHac.Fs.IDirectory directory)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
@@ -33,22 +29,11 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{ 1, GetEntryCount }
};
- _provider = provider;
- DirectoryPath = directoryPath;
+ _provider = directory;
- _directoryEntries = new List<DirectoryEntry>();
+ Path = directory.FullPath;
- if ((flags & 1) != 0)
- {
- _directoryEntries.AddRange(provider.GetDirectories(directoryPath));
- }
-
- if ((flags & 2) != 0)
- {
- _directoryEntries.AddRange(provider.GetFiles(directoryPath));
- }
-
- _currentItemIndex = 0;
+ _enumerator = directory.Read().GetEnumerator();
}
// Read() -> (u64 count, buffer<nn::fssrv::sf::IDirectoryEntry, 6, 0> entries)
@@ -58,41 +43,42 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
long bufferLen = context.Request.ReceiveBuff[0].Size;
int maxReadCount = (int)(bufferLen / DirectoryEntrySize);
+ int readCount = 0;
- int count = Math.Min(_directoryEntries.Count - _currentItemIndex, maxReadCount);
-
- for (int index = 0; index < count; index++)
+ while (readCount < maxReadCount && _enumerator.MoveNext())
{
- long position = bufferPosition + index * DirectoryEntrySize;
+ long position = bufferPosition + readCount * DirectoryEntrySize;
+
+ WriteDirectoryEntry(context, position, _enumerator.Current);
- WriteDirectoryEntry(context, position, _directoryEntries[_currentItemIndex++]);
+ readCount++;
}
- context.ResponseData.Write((long)count);
+ context.ResponseData.Write((long)readCount);
return 0;
}
- private void WriteDirectoryEntry(ServiceCtx context, long position, DirectoryEntry entry)
+ private void WriteDirectoryEntry(ServiceCtx context, long position, LibHac.Fs.DirectoryEntry entry)
{
for (int offset = 0; offset < 0x300; offset += 8)
{
context.Memory.WriteInt64(position + offset, 0);
}
- byte[] nameBuffer = Encoding.UTF8.GetBytes(Path.GetFileName(entry.Path));
+ byte[] nameBuffer = Encoding.UTF8.GetBytes(entry.Name);
context.Memory.WriteBytes(position, nameBuffer);
- context.Memory.WriteInt32(position + 0x300, 0); //Padding?
- context.Memory.WriteInt32(position + 0x304, (byte)entry.EntryType);
+ context.Memory.WriteInt32(position + 0x300, (int)entry.Attributes);
+ context.Memory.WriteInt32(position + 0x304, (byte)entry.Type);
context.Memory.WriteInt64(position + 0x308, entry.Size);
}
// GetEntryCount() -> u64
public long GetEntryCount(ServiceCtx context)
{
- context.ResponseData.Write((long)_directoryEntries.Count);
+ context.ResponseData.Write((long)_provider.GetEntryCount());
return 0;
}
diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs
index c0ff5c64..3cedf4fe 100644
--- a/Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs
+++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFile.cs
@@ -1,7 +1,6 @@
using Ryujinx.HLE.HOS.Ipc;
using System;
using System.Collections.Generic;
-using System.IO;
namespace Ryujinx.HLE.HOS.Services.FspSrv
{
@@ -11,13 +10,13 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
- private Stream _baseStream;
+ private LibHac.Fs.IFile _baseFile;
public event EventHandler<EventArgs> Disposed;
- public string HostPath { get; private set; }
+ public string Path { get; private set; }
- public IFile(Stream baseStream, string hostPath)
+ public IFile(LibHac.Fs.IFile baseFile, string path)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
@@ -28,24 +27,24 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{ 4, GetSize }
};
- _baseStream = baseStream;
- HostPath = hostPath;
+ _baseFile = baseFile;
+ Path = LibHac.Fs.PathTools.Normalize(path);
}
- // Read(u32, u64 offset, u64 size) -> (u64 out_size, buffer<u8, 0x46, 0> out_buf)
+ // Read(u32 readOption, u64 offset, u64 size) -> (u64 out_size, buffer<u8, 0x46, 0> out_buf)
public long Read(ServiceCtx context)
{
long position = context.Request.ReceiveBuff[0].Position;
- long zero = context.RequestData.ReadInt64();
+ int readOption = context.RequestData.ReadInt32();
+ context.RequestData.BaseStream.Position += 4;
+
long offset = context.RequestData.ReadInt64();
long size = context.RequestData.ReadInt64();
byte[] data = new byte[size];
- _baseStream.Seek(offset, SeekOrigin.Begin);
-
- int readSize = _baseStream.Read(data, 0, (int)size);
+ int readSize = _baseFile.Read(data, offset);
context.Memory.WriteBytes(position, data);
@@ -54,19 +53,20 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
return 0;
}
- // Write(u32, u64 offset, u64 size, buffer<u8, 0x45, 0>)
+ // Write(u32 writeOption, u64 offset, u64 size, buffer<u8, 0x45, 0>)
public long Write(ServiceCtx context)
{
long position = context.Request.SendBuff[0].Position;
- long zero = context.RequestData.ReadInt64();
+ int writeOption = context.RequestData.ReadInt32();
+ context.RequestData.BaseStream.Position += 4;
+
long offset = context.RequestData.ReadInt64();
long size = context.RequestData.ReadInt64();
byte[] data = context.Memory.ReadBytes(position, size);
- _baseStream.Seek(offset, SeekOrigin.Begin);
- _baseStream.Write(data, 0, (int)size);
+ _baseFile.Write(data, offset);
return 0;
}
@@ -74,7 +74,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
// Flush()
public long Flush(ServiceCtx context)
{
- _baseStream.Flush();
+ _baseFile.Flush();
return 0;
}
@@ -84,7 +84,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
long size = context.RequestData.ReadInt64();
- _baseStream.SetLength(size);
+ _baseFile.SetSize(size);
return 0;
}
@@ -92,7 +92,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
// GetSize() -> u64 fileSize
public long GetSize(ServiceCtx context)
{
- context.ResponseData.Write(_baseStream.Length);
+ context.ResponseData.Write(_baseFile.GetSize());
return 0;
}
@@ -104,9 +104,9 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
protected virtual void Dispose(bool disposing)
{
- if (disposing && _baseStream != null)
+ if (disposing && _baseFile != null)
{
- _baseStream.Dispose();
+ _baseFile.Dispose();
Disposed?.Invoke(this, EventArgs.Empty);
}
diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs
index bcb9dbaf..9e772213 100644
--- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs
+++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs
@@ -1,9 +1,9 @@
-using Ryujinx.HLE.FileSystem;
+using LibHac.Fs;
using Ryujinx.HLE.HOS.Ipc;
using System;
using System.Collections.Generic;
using System.IO;
-
+using Ryujinx.Common.Logging;
using static Ryujinx.HLE.HOS.ErrorCode;
using static Ryujinx.HLE.Utilities.StringUtils;
@@ -17,11 +17,9 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
private HashSet<string> _openPaths;
- private string _path;
-
- private IFileSystemProvider _provider;
+ private LibHac.Fs.IFileSystem _provider;
- public IFileSystem(string path, IFileSystemProvider provider)
+ public IFileSystem(LibHac.Fs.IFileSystem provider)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
@@ -44,36 +42,50 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
_openPaths = new HashSet<string>();
- _path = path;
_provider = provider;
}
- // CreateFile(u32 mode, u64 size, buffer<bytes<0x301>, 0x19, 0x301> path)
+ // CreateFile(u32 createOption, u64 size, buffer<bytes<0x301>, 0x19, 0x301> path)
public long CreateFile(ServiceCtx context)
{
string name = ReadUtf8String(context);
- long mode = context.RequestData.ReadInt64();
- int size = context.RequestData.ReadInt32();
+ int createOption = context.RequestData.ReadInt32();
+ context.RequestData.BaseStream.Position += 4;
- string fileName = _provider.GetFullPath(name);
+ long size = context.RequestData.ReadInt64();
- if (fileName == null)
+ if (name == null)
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
- if (_provider.FileExists(fileName))
+ if (_provider.FileExists(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
}
- if (IsPathAlreadyInUse(fileName))
+ if (IsPathAlreadyInUse(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
}
- return _provider.CreateFile(fileName, size);
+ try
+ {
+ _provider.CreateFile(name, size, (CreateFileOptions)createOption);
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ Logger.PrintError(LogClass.ServiceFs, $"Unable to access {name}");
+
+ throw;
+ }
+
+ return 0;
}
// DeleteFile(buffer<bytes<0x301>, 0x19, 0x301> path)
@@ -81,19 +93,32 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
string name = ReadUtf8String(context);
- string fileName = _provider.GetFullPath(name);
-
- if (!_provider.FileExists(fileName))
+ if (!_provider.FileExists(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
- if (IsPathAlreadyInUse(fileName))
+ if (IsPathAlreadyInUse(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
}
- return _provider.DeleteFile(fileName);
+ try
+ {
+ _provider.DeleteFile(name);
+ }
+ catch (FileNotFoundException)
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ Logger.PrintError(LogClass.ServiceFs, $"Unable to access {name}");
+
+ throw;
+ }
+
+ return 0;
}
// CreateDirectory(buffer<bytes<0x301>, 0x19, 0x301> path)
@@ -101,24 +126,35 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
string name = ReadUtf8String(context);
- string dirName = _provider.GetFullPath(name);
-
- if (dirName == null)
+ if (name == null)
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
- if (_provider.DirectoryExists(dirName))
+ if (_provider.DirectoryExists(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
}
- if (IsPathAlreadyInUse(dirName))
+ if (IsPathAlreadyInUse(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
}
- _provider.CreateDirectory(dirName);
+ try
+ {
+ _provider.CreateDirectory(name);
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ Logger.PrintError(LogClass.ServiceFs, $"Unable to access {name}");
+
+ throw;
+ }
return 0;
}
@@ -126,32 +162,61 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
// DeleteDirectory(buffer<bytes<0x301>, 0x19, 0x301> path)
public long DeleteDirectory(ServiceCtx context)
{
- return DeleteDirectory(context, false);
+ string name = ReadUtf8String(context);
+
+ if (!_provider.DirectoryExists(name))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ if (IsPathAlreadyInUse(name))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
+ }
+
+ try
+ {
+ _provider.DeleteDirectory(name);
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ Logger.PrintError(LogClass.ServiceFs, $"Unable to access {name}");
+
+ throw;
+ }
+
+ return 0;
}
// DeleteDirectoryRecursively(buffer<bytes<0x301>, 0x19, 0x301> path)
public long DeleteDirectoryRecursively(ServiceCtx context)
{
- return DeleteDirectory(context, true);
- }
-
- private long DeleteDirectory(ServiceCtx context, bool recursive)
- {
string name = ReadUtf8String(context);
- string dirName = _provider.GetFullPath(name);
-
- if (!Directory.Exists(dirName))
+ if (!_provider.DirectoryExists(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
- if (IsPathAlreadyInUse(dirName))
+ if (IsPathAlreadyInUse(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
}
- _provider.DeleteDirectory(dirName, recursive);
+ try
+ {
+ _provider.DeleteDirectoryRecursively(name);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ Logger.PrintError(LogClass.ServiceFs, $"Unable to access {name}");
+
+ throw;
+ }
return 0;
}
@@ -162,25 +227,37 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
string oldName = ReadUtf8String(context, 0);
string newName = ReadUtf8String(context, 1);
- string oldFileName = _provider.GetFullPath(oldName);
- string newFileName = _provider.GetFullPath(newName);
-
- if (_provider.FileExists(oldFileName))
+ if (_provider.FileExists(oldName))
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
- if (_provider.FileExists(newFileName))
+ if (_provider.FileExists(newName))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
}
- if (IsPathAlreadyInUse(oldFileName))
+ if (IsPathAlreadyInUse(oldName))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
}
- return _provider.RenameFile(oldFileName, newFileName);
+ try
+ {
+ _provider.RenameFile(oldName, newName);
+ }
+ catch (FileNotFoundException)
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ Logger.PrintError(LogClass.ServiceFs, $"Unable to access {oldName} or {newName}");
+
+ throw;
+ }
+
+ return 0;
}
// RenameDirectory(buffer<bytes<0x301>, 0x19, 0x301> oldPath, buffer<bytes<0x301>, 0x19, 0x301> newPath)
@@ -189,25 +266,37 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
string oldName = ReadUtf8String(context, 0);
string newName = ReadUtf8String(context, 1);
- string oldDirName = _provider.GetFullPath(oldName);
- string newDirName = _provider.GetFullPath(newName);
-
- if (!_provider.DirectoryExists(oldDirName))
+ if (!_provider.DirectoryExists(oldName))
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
- if (!_provider.DirectoryExists(newDirName))
+ if (!_provider.DirectoryExists(newName))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
}
- if (IsPathAlreadyInUse(oldDirName))
+ if (IsPathAlreadyInUse(oldName))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
}
- return _provider.RenameDirectory(oldDirName, newDirName);
+ try
+ {
+ _provider.RenameFile(oldName, newName);
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ Logger.PrintError(LogClass.ServiceFs, $"Unable to access {oldName} or {newName}");
+
+ throw;
+ }
+
+ return 0;
}
// GetEntryType(buffer<bytes<0x301>, 0x19, 0x301> path) -> nn::fssrv::sf::DirectoryEntryType
@@ -215,17 +304,13 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
string name = ReadUtf8String(context);
- string fileName = _provider.GetFullPath(name);
-
- if (_provider.FileExists(fileName))
- {
- context.ResponseData.Write(1);
- }
- else if (_provider.DirectoryExists(fileName))
+ try
{
- context.ResponseData.Write(0);
+ LibHac.Fs.DirectoryEntryType entryType = _provider.GetEntryType(name);
+
+ context.ResponseData.Write((int)entryType);
}
- else
+ catch (FileNotFoundException)
{
context.ResponseData.Write(0);
@@ -238,81 +323,96 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
// OpenFile(u32 mode, buffer<bytes<0x301>, 0x19, 0x301> path) -> object<nn::fssrv::sf::IFile> file
public long OpenFile(ServiceCtx context)
{
- int filterFlags = context.RequestData.ReadInt32();
+ int mode = context.RequestData.ReadInt32();
string name = ReadUtf8String(context);
- string fileName = _provider.GetFullPath(name);
-
- if (!_provider.FileExists(fileName))
+ if (!_provider.FileExists(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
- if (IsPathAlreadyInUse(fileName))
+ if (IsPathAlreadyInUse(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
}
+ IFile fileInterface;
- long error = _provider.OpenFile(fileName, out IFile fileInterface);
+ try
+ {
+ LibHac.Fs.IFile file = _provider.OpenFile(name, (OpenMode)mode);
- if (error == 0)
+ fileInterface = new IFile(file, name);
+ }
+ catch (UnauthorizedAccessException)
{
- fileInterface.Disposed += RemoveFileInUse;
+ Logger.PrintError(LogClass.ServiceFs, $"Unable to access {name}");
- lock (_openPaths)
- {
- _openPaths.Add(fileName);
- }
+ throw;
+ }
- MakeObject(context, fileInterface);
+ fileInterface.Disposed += RemoveFileInUse;
- return 0;
+ lock (_openPaths)
+ {
+ _openPaths.Add(fileInterface.Path);
}
- return error;
+ MakeObject(context, fileInterface);
+
+ return 0;
}
// OpenDirectory(u32 filter_flags, buffer<bytes<0x301>, 0x19, 0x301> path) -> object<nn::fssrv::sf::IDirectory> directory
public long OpenDirectory(ServiceCtx context)
{
- int filterFlags = context.RequestData.ReadInt32();
+ int mode = context.RequestData.ReadInt32();
string name = ReadUtf8String(context);
- string dirName = _provider.GetFullPath(name);
-
- if (!_provider.DirectoryExists(dirName))
+ if (!_provider.DirectoryExists(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
- if (IsPathAlreadyInUse(dirName))
+ if (IsPathAlreadyInUse(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
}
- long error = _provider.OpenDirectory(dirName, filterFlags, out IDirectory dirInterface);
+ IDirectory dirInterface;
+
+ try
+ {
+ LibHac.Fs.IDirectory dir = _provider.OpenDirectory(name, (OpenDirectoryMode) mode);
- if (error == 0)
+ dirInterface = new IDirectory(dir);
+ }
+ catch (UnauthorizedAccessException)
{
- dirInterface.Disposed += RemoveDirectoryInUse;
+ Logger.PrintError(LogClass.ServiceFs, $"Unable to access {name}");
+
+ throw;
+ }
- lock (_openPaths)
- {
- _openPaths.Add(dirName);
- }
+ dirInterface.Disposed += RemoveDirectoryInUse;
- MakeObject(context, dirInterface);
+ lock (_openPaths)
+ {
+ _openPaths.Add(dirInterface.Path);
}
- return error;
+ MakeObject(context, dirInterface);
+
+ return 0;
}
// Commit()
public long Commit(ServiceCtx context)
{
+ _provider.Commit();
+
return 0;
}
@@ -321,7 +421,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
string name = ReadUtf8String(context);
- context.ResponseData.Write(_provider.GetFreeSpace(context));
+ context.ResponseData.Write(_provider.GetFreeSpaceSize(name));
return 0;
}
@@ -331,7 +431,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
string name = ReadUtf8String(context);
- context.ResponseData.Write(_provider.GetFreeSpace(context));
+ context.ResponseData.Write(_provider.GetTotalSpaceSize(name));
return 0;
}
@@ -341,28 +441,25 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
string name = ReadUtf8String(context);
- string dirName = _provider.GetFullPath(name);
-
- if (!_provider.DirectoryExists(dirName))
+ if (!_provider.DirectoryExists(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
- if (IsPathAlreadyInUse(dirName))
+ if (IsPathAlreadyInUse(name))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
}
- foreach (DirectoryEntry entry in _provider.GetEntries(dirName))
+ try
{
- if (_provider.DirectoryExists(entry.Path))
- {
- _provider.DeleteDirectory(entry.Path, true);
- }
- else if (_provider.FileExists(entry.Path))
- {
- _provider.DeleteFile(entry.Path);
- }
+ _provider.CleanDirectoryRecursively(name);
+ }
+ catch (UnauthorizedAccessException)
+ {
+ Logger.PrintError(LogClass.ServiceFs, $"Unable to access {name}");
+
+ throw;
}
return 0;
@@ -373,15 +470,13 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
string name = ReadUtf8String(context);
- string path = _provider.GetFullPath(name);
-
- if (_provider.FileExists(path) || _provider.DirectoryExists(path))
+ if (_provider.FileExists(name) || _provider.DirectoryExists(name))
{
- FileTimestamp timestamp = _provider.GetFileTimeStampRaw(path);
+ FileTimeStampRaw timestamp = _provider.GetFileTimeStampRaw(name);
- context.ResponseData.Write(new DateTimeOffset(timestamp.CreationDateTime).ToUnixTimeSeconds());
- context.ResponseData.Write(new DateTimeOffset(timestamp.ModifiedDateTime).ToUnixTimeSeconds());
- context.ResponseData.Write(new DateTimeOffset(timestamp.LastAccessDateTime).ToUnixTimeSeconds());
+ context.ResponseData.Write(timestamp.Created);
+ context.ResponseData.Write(timestamp.Modified);
+ context.ResponseData.Write(timestamp.Accessed);
byte[] data = new byte[8];
@@ -412,7 +507,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
fileInterface.Disposed -= RemoveFileInUse;
- _openPaths.Remove(fileInterface.HostPath);
+ _openPaths.Remove(fileInterface.Path);
}
}
@@ -424,7 +519,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
dirInterface.Disposed -= RemoveDirectoryInUse;
- _openPaths.Remove(dirInterface.DirectoryPath);
+ _openPaths.Remove(dirInterface.Path);
}
}
}
diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs
index 878f2e4e..05abb7f0 100644
--- a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs
+++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystemProxy.cs
@@ -1,11 +1,11 @@
using LibHac;
-using LibHac.IO;
+using LibHac.Fs;
+using LibHac.Fs.NcaUtils;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Ipc;
using Ryujinx.HLE.Utilities;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using static Ryujinx.HLE.FileSystem.VirtualFileSystem;
using static Ryujinx.HLE.HOS.ErrorCode;
@@ -79,31 +79,31 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
// OpenBisFileSystem(nn::fssrv::sf::Partition partitionID, buffer<bytes<0x301>, 0x19, 0x301>) -> object<nn::fssrv::sf::IFileSystem> Bis
public long OpenBisFileSystem(ServiceCtx context)
{
- int bisPartitionId = context.RequestData.ReadInt32();
- string partitionString = ReadUtf8String(context);
- string bisPartitonPath = string.Empty;
+ int bisPartitionId = context.RequestData.ReadInt32();
+ string partitionString = ReadUtf8String(context);
+ string bisPartitionPath = string.Empty;
switch (bisPartitionId)
{
case 29:
- bisPartitonPath = SafeNandPath;
+ bisPartitionPath = SafeNandPath;
break;
case 30:
case 31:
- bisPartitonPath = SystemNandPath;
+ bisPartitionPath = SystemNandPath;
break;
case 32:
- bisPartitonPath = UserNandPath;
+ bisPartitionPath = UserNandPath;
break;
default:
return MakeError(ErrorModule.Fs, FsErr.InvalidInput);
}
- string fullPath = context.Device.FileSystem.GetFullPartitionPath(bisPartitonPath);
+ string fullPath = context.Device.FileSystem.GetFullPartitionPath(bisPartitionPath);
- FileSystemProvider fileSystemProvider = new FileSystemProvider(fullPath, context.Device.FileSystem.GetBasePath());
+ LocalFileSystem fileSystem = new LocalFileSystem(fullPath);
- MakeObject(context, new IFileSystem(fullPath, fileSystemProvider));
+ MakeObject(context, new IFileSystem(fileSystem));
return 0;
}
@@ -113,9 +113,9 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{
string sdCardPath = context.Device.FileSystem.GetSdCardPath();
- FileSystemProvider fileSystemProvider = new FileSystemProvider(sdCardPath, context.Device.FileSystem.GetBasePath());
+ LocalFileSystem fileSystem = new LocalFileSystem(sdCardPath);
- MakeObject(context, new IFileSystem(sdCardPath, fileSystemProvider));
+ MakeObject(context, new IFileSystem(fileSystem));
return 0;
}
@@ -139,7 +139,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
// OpenDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage> dataStorage
public long OpenDataStorageByCurrentProcess(ServiceCtx context)
{
- MakeObject(context, new IStorage(context.Device.FileSystem.RomFs));
+ MakeObject(context, new IStorage(context.Device.FileSystem.RomFs.AsStorage()));
return 0;
}
@@ -158,7 +158,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
if (installedStorage == StorageId.None)
{
- contentType = ContentType.AocData;
+ contentType = ContentType.PublicData;
installedStorage =
context.Device.System.ContentManager.GetInstalledStorage(titleId, contentType, storageId);
@@ -175,12 +175,11 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
if (File.Exists(ncaPath))
{
- LibHac.IO.IStorage ncaStorage = new FileStream(ncaPath, FileMode.Open, FileAccess.Read).AsStorage();
- Nca nca = new Nca(context.Device.System.KeySet, ncaStorage, false);
- NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
- Stream romfsStream = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false).AsStream();
+ LibHac.Fs.IStorage ncaStorage = new LocalStorage(ncaPath, FileAccess.Read, FileMode.Open);
+ Nca nca = new Nca(context.Device.System.KeySet, ncaStorage);
+ LibHac.Fs.IStorage romfsStorage = nca.OpenStorage(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel);
- MakeObject(context, new IStorage(romfsStream));
+ MakeObject(context, new IStorage(romfsStorage));
return 0;
}
@@ -201,7 +200,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
// OpenPatchDataStorageByCurrentProcess() -> object<nn::fssrv::sf::IStorage>
public long OpenPatchDataStorageByCurrentProcess(ServiceCtx context)
{
- MakeObject(context, new IStorage(context.Device.FileSystem.RomFs));
+ MakeObject(context, new IStorage(context.Device.FileSystem.RomFs.AsStorage()));
return 0;
}
@@ -224,57 +223,44 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
context.RequestData.ReadInt64(),
context.RequestData.ReadInt64());
- long saveId = context.RequestData.ReadInt64();
- SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadByte();
- SaveInfo saveInfo = new SaveInfo(titleId, saveId, saveDataType, userId, saveSpaceId);
- string savePath = context.Device.FileSystem.GetGameSavePath(saveInfo, context);
- FileSystemProvider fileSystemProvider = new FileSystemProvider(savePath, context.Device.FileSystem.GetBasePath());
+ long saveId = context.RequestData.ReadInt64();
+ SaveDataType saveDataType = (SaveDataType)context.RequestData.ReadByte();
+ SaveInfo saveInfo = new SaveInfo(titleId, saveId, saveDataType, userId, saveSpaceId);
+ string savePath = context.Device.FileSystem.GetGameSavePath(saveInfo, context);
+ LocalFileSystem fileSystem = new LocalFileSystem(savePath);
- MakeObject(context, new IFileSystem(savePath, fileSystemProvider));
+ DirectorySaveDataFileSystem saveFileSystem = new DirectorySaveDataFileSystem(fileSystem);
+
+ MakeObject(context, new IFileSystem(saveFileSystem));
}
private long OpenNsp(ServiceCtx context, string pfsPath)
{
- FileStream pfsFile = new FileStream(pfsPath, FileMode.Open, FileAccess.Read);
- Pfs nsp = new Pfs(pfsFile.AsStorage());
+ LocalStorage storage = new LocalStorage(pfsPath, FileAccess.Read, FileMode.Open);
+ PartitionFileSystem nsp = new PartitionFileSystem(storage);
ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet);
-
-
- IFileSystem nspFileSystem = new IFileSystem(pfsPath, new PFsProvider(nsp));
+
+ IFileSystem nspFileSystem = new IFileSystem(nsp);
MakeObject(context, nspFileSystem);
return 0;
}
- private long OpenNcaFs(ServiceCtx context, string ncaPath, LibHac.IO.IStorage ncaStorage)
+ private long OpenNcaFs(ServiceCtx context, string ncaPath, LibHac.Fs.IStorage ncaStorage)
{
- Nca nca = new Nca(context.Device.System.KeySet, ncaStorage, false);
-
- NcaSection romfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
- NcaSection pfsSection = nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Pfs0);
-
- if (romfsSection != null)
- {
- LibHac.IO.IStorage romfsStorage = nca.OpenSection(romfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false);
- IFileSystem ncaFileSystem = new IFileSystem(ncaPath, new RomFsProvider(romfsStorage));
+ Nca nca = new Nca(context.Device.System.KeySet, ncaStorage);
- MakeObject(context, ncaFileSystem);
- }
- else if(pfsSection != null)
- {
- LibHac.IO.IStorage pfsStorage = nca.OpenSection(pfsSection.SectionNum, false, context.Device.System.FsIntegrityCheckLevel, false);
- Pfs pfs = new Pfs(pfsStorage);
- IFileSystem ncaFileSystem = new IFileSystem(ncaPath, new PFsProvider(pfs));
-
- MakeObject(context, ncaFileSystem);
- }
- else
+ if (!nca.SectionExists(NcaSectionType.Data))
{
return MakeError(ErrorModule.Fs, FsErr.PartitionNotFound);
}
+ LibHac.Fs.IFileSystem fileSystem = nca.OpenFileSystem(NcaSectionType.Data, context.Device.System.FsIntegrityCheckLevel);
+
+ MakeObject(context, new IFileSystem(fileSystem));
+
return 0;
}
@@ -294,7 +280,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
FileMode.Open,
FileAccess.Read);
- Pfs nsp = new Pfs(pfsFile.AsStorage());
+ PartitionFileSystem nsp = new PartitionFileSystem(pfsFile.AsStorage());
ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet);
@@ -302,18 +288,18 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
if (nsp.FileExists(filename))
{
- return OpenNcaFs(context, fullPath, nsp.OpenFile(filename));
+ return OpenNcaFs(context, fullPath, nsp.OpenFile(filename, OpenMode.Read).AsStorage());
}
}
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
- private void ImportTitleKeysFromNsp(Pfs nsp, Keyset keySet)
+ private void ImportTitleKeysFromNsp(LibHac.Fs.IFileSystem nsp, Keyset keySet)
{
- foreach (PfsFileEntry ticketEntry in nsp.Files.Where(x => x.Name.EndsWith(".tik")))
+ foreach (LibHac.Fs.DirectoryEntry ticketEntry in nsp.EnumerateEntries("*.tik"))
{
- Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry).AsStream());
+ Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry.FullPath, OpenMode.Read).AsStream());
if (!keySet.TitleKeys.ContainsKey(ticket.RightsId))
{
diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs
index 85ab2cf6..75f2c9ee 100644
--- a/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs
+++ b/Ryujinx.HLE/HOS/Services/FspSrv/IStorage.cs
@@ -1,6 +1,5 @@
using Ryujinx.HLE.HOS.Ipc;
using System.Collections.Generic;
-using System.IO;
namespace Ryujinx.HLE.HOS.Services.FspSrv
{
@@ -10,9 +9,9 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
- private Stream _baseStream;
+ private LibHac.Fs.IStorage _baseStorage;
- public IStorage(Stream baseStream)
+ public IStorage(LibHac.Fs.IStorage baseStorage)
{
_commands = new Dictionary<int, ServiceProcessRequest>
{
@@ -20,7 +19,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
{ 4, GetSize }
};
- _baseStream = baseStream;
+ _baseStorage = baseStorage;
}
// Read(u64 offset, u64 length) -> buffer<u8, 0x46, 0> buffer
@@ -41,11 +40,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
byte[] data = new byte[size];
- lock (_baseStream)
- {
- _baseStream.Seek(offset, SeekOrigin.Begin);
- _baseStream.Read(data, 0, data.Length);
- }
+ _baseStorage.Read(data, offset);
context.Memory.WriteBytes(buffDesc.Position, data);
}
@@ -56,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Services.FspSrv
// GetSize() -> u64 size
public long GetSize(ServiceCtx context)
{
- context.ResponseData.Write(_baseStream.Length);
+ context.ResponseData.Write(_baseStorage.GetSize());
return 0;
}
diff --git a/Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs b/Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs
index 6c2f1970..dac776f2 100644
--- a/Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs
+++ b/Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs
@@ -1,4 +1,4 @@
-using LibHac;
+using LibHac.Fs.NcaUtils;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.FileSystem.Content;
using Ryujinx.HLE.HOS.Ipc;
@@ -136,7 +136,7 @@ namespace Ryujinx.HLE.HOS.Services.Lr
{
long titleId = context.RequestData.ReadInt64();
- if (ResolvePath(context, titleId, ContentType.Data) || ResolvePath(context, titleId, ContentType.AocData))
+ if (ResolvePath(context, titleId, ContentType.Data) || ResolvePath(context, titleId, ContentType.PublicData))
{
return 0;
}
diff --git a/Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs b/Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs
index 8eec31cf..4a67638b 100644
--- a/Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs
+++ b/Ryujinx.HLE/HOS/Services/Set/ISystemSettingsServer.cs
@@ -1,5 +1,5 @@
-using LibHac;
-using LibHac.IO;
+using LibHac.Fs;
+using LibHac.Fs.NcaUtils;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Ipc;
@@ -184,21 +184,20 @@ namespace Ryujinx.HLE.HOS.Services.Set
string firmwareTitlePath = device.FileSystem.SwitchPathToSystemPath(contentPath);
- using(FileStream firmwareStream = File.Open(firmwareTitlePath, FileMode.Open, FileAccess.Read))
- {
- Nca firmwareContent = new Nca(device.System.KeySet, firmwareStream.AsStorage(), false);
- IStorage romFsStorage = firmwareContent.OpenSection(0, false, device.System.FsIntegrityCheckLevel, false);
+ using(IStorage firmwareStorage = new LocalStorage(firmwareTitlePath, FileAccess.Read))
+ {
+ Nca firmwareContent = new Nca(device.System.KeySet, firmwareStorage);
- if(romFsStorage == null)
+ if (!firmwareContent.CanOpenSection(NcaSectionType.Data))
{
return null;
}
- Romfs firmwareRomFs = new Romfs(romFsStorage);
+ IFileSystem firmwareRomFs = firmwareContent.OpenFileSystem(NcaSectionType.Data, device.System.FsIntegrityCheckLevel);
- IStorage firmwareFile = firmwareRomFs.OpenFile("/file");
+ IFile firmwareFile = firmwareRomFs.OpenFile("/file", OpenMode.Read);
- byte[] data = new byte[firmwareFile.Length];
+ byte[] data = new byte[firmwareFile.GetSize()];
firmwareFile.Read(data, 0);
diff --git a/Ryujinx.HLE/Ryujinx.HLE.csproj b/Ryujinx.HLE/Ryujinx.HLE.csproj
index a653b53f..3c42cf54 100644
--- a/Ryujinx.HLE/Ryujinx.HLE.csproj
+++ b/Ryujinx.HLE/Ryujinx.HLE.csproj
@@ -46,7 +46,7 @@
<ItemGroup>
<PackageReference Include="Concentus" Version="1.1.7" />
- <PackageReference Include="LibHac" Version="0.2.0" />
+ <PackageReference Include="LibHac" Version="0.4.0" />
</ItemGroup>
</Project>
diff --git a/Ryujinx/Configuration.cs b/Ryujinx/Configuration.cs
index a5108544..1f670ca5 100644
--- a/Ryujinx/Configuration.cs
+++ b/Ryujinx/Configuration.cs
@@ -1,4 +1,4 @@
-using LibHac.IO;
+using LibHac.Fs;
using OpenTK.Input;
using Ryujinx.Common;
using Ryujinx.Common.Logging;