Update to version 0.4 of LibHac (#689)

* It compiles

* Print correct name when loading an exefs

* Use DirectorySaveDataFileSystem for savedata

* Handle more errors in IFileSystem

* Remove structs replaced by LibHac structs

* Fix alignment

* Fix alignment again

* Fix IFile and IFileSystem IPC

* Alignment

* Use released libhac version
This commit is contained in:
Alex Barney 2019-05-31 19:31:10 -05:00 committed by Ac_K
parent 92c1726647
commit 5fc1f6a1af
20 changed files with 465 additions and 1169 deletions

View file

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

View file

@ -1,4 +1,4 @@
using LibHac;
using LibHac.Fs.NcaUtils;
namespace Ryujinx.HLE.FileSystem.Content
{

View file

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

View file

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

View file

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

View file

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