From fe8fbb6fb9b85a528ddfa4848ec8e35fd9a5e9a5 Mon Sep 17 00:00:00 2001 From: emmauss Date: Sun, 18 Nov 2018 21:37:41 +0200 Subject: Implement ContentManager and related services (#438) * Implement contentmanager and related services * small changes * read system firmware version from nand * add pfs support, write directoryentry info for romfs files * add file check in fsp-srv:8 * add support for open fs of internal files * fix filename when accessing pfs * use switch style paths for contentpath * close nca after verifying type * removed publishing profiles, align directory entry * fix style * lots of style fixes * yasf(yet another style fix) * yasf(yet another style fix) plus symbols * enforce path check on every fs access * change enum type to default * fix typo --- Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs | 265 +++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs (limited to 'Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs') diff --git a/Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs b/Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs new file mode 100644 index 00000000..dc057bc1 --- /dev/null +++ b/Ryujinx.HLE/HOS/Services/Lr/ILocationResolver.cs @@ -0,0 +1,265 @@ +using LibHac; +using Ryujinx.HLE.FileSystem; +using Ryujinx.HLE.FileSystem.Content; +using Ryujinx.HLE.HOS.Ipc; +using System.Collections.Generic; +using System.Text; + +using static Ryujinx.HLE.HOS.ErrorCode; +using static Ryujinx.HLE.Utilities.StringUtils; + +namespace Ryujinx.HLE.HOS.Services.Lr +{ + class ILocationResolver : IpcService + { + private Dictionary m_Commands; + + public override IReadOnlyDictionary Commands => m_Commands; + + private StorageId StorageId; + + public ILocationResolver(StorageId StorageId) + { + m_Commands = new Dictionary() + { + { 0, ResolveProgramPath }, + { 1, RedirectProgramPath }, + { 2, ResolveApplicationControlPath }, + { 3, ResolveApplicationHtmlDocumentPath }, + { 4, ResolveDataPath }, + { 5, RedirectApplicationControlPath }, + { 6, RedirectApplicationHtmlDocumentPath }, + { 7, ResolveApplicationLegalInformationPath }, + { 8, RedirectApplicationLegalInformationPath }, + { 9, Refresh }, + { 10, SetProgramNcaPath2 }, + { 11, ClearLocationResolver2 }, + { 12, DeleteProgramNcaPath }, + { 13, DeleteControlNcaPath }, + { 14, DeleteDocHtmlNcaPath }, + { 15, DeleteInfoHtmlNcaPath } + }; + + this.StorageId = StorageId; + } + + // DeleteInfoHtmlNcaPath() + public long DeleteInfoHtmlNcaPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + DeleteContentPath(Context, TitleId, ContentType.Manual); + + return 0; + } + + // DeleteDocHtmlNcaPath() + public long DeleteDocHtmlNcaPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + DeleteContentPath(Context, TitleId, ContentType.Manual); + + return 0; + } + + // DeleteControlNcaPath() + public long DeleteControlNcaPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + DeleteContentPath(Context, TitleId, ContentType.Control); + + return 0; + } + + // DeleteProgramNcaPath() + public long DeleteProgramNcaPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + DeleteContentPath(Context, TitleId, ContentType.Program); + + return 0; + } + + // ClearLocationResolver2() + public long ClearLocationResolver2(ServiceCtx Context) + { + Context.Device.System.ContentManager.RefreshEntries(StorageId, 1); + + return 0; + } + + // SetProgramNcaPath2() + public long SetProgramNcaPath2(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + RedirectPath(Context, TitleId, 1, ContentType.Program); + + return 0; + } + + // RedirectApplicationControlPath() + public long RedirectApplicationControlPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + RedirectPath(Context, TitleId, 1, ContentType.Control); + + return 0; + } + + // RedirectApplicationHtmlDocumentPath() + public long RedirectApplicationHtmlDocumentPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + RedirectPath(Context, TitleId, 1, ContentType.Manual); + + return 0; + } + + // RedirectApplicationLegalInformationPath() + public long RedirectApplicationLegalInformationPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + RedirectPath(Context, TitleId, 1, ContentType.Manual); + + return 0; + } + + // ResolveDataPath() + public long ResolveDataPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + if (ResolvePath(Context, TitleId, ContentType.Data) || ResolvePath(Context, TitleId, ContentType.AocData)) + { + return 0; + } + else + { + return MakeError(ErrorModule.Lr, LrErr.AccessDenied); + } + } + + // ResolveApplicationHtmlDocumentPath() + public long ResolveApplicationHtmlDocumentPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + if (ResolvePath(Context, TitleId, ContentType.Manual)) + { + return 0; + } + else + { + return MakeError(ErrorModule.Lr, LrErr.AccessDenied); + } + } + + // ResolveApplicationLegalInformationPath() + public long ResolveApplicationLegalInformationPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + if (ResolvePath(Context, TitleId, ContentType.Manual)) + { + return 0; + } + else + { + return MakeError(ErrorModule.Lr, LrErr.AccessDenied); + } + } + + // ResolveApplicationControlPath() + public long ResolveApplicationControlPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + if (ResolvePath(Context, TitleId, ContentType.Control)) + { + return 0; + } + else + { + return MakeError(ErrorModule.Lr, LrErr.AccessDenied); + } + } + + // RedirectProgramPath() + public long RedirectProgramPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + RedirectPath(Context, TitleId, 0, ContentType.Program); + + return 0; + } + + // Refresh() + public long Refresh(ServiceCtx Context) + { + Context.Device.System.ContentManager.RefreshEntries(StorageId, 1); + + return 0; + } + + // ResolveProgramPath() + public long ResolveProgramPath(ServiceCtx Context) + { + long TitleId = Context.RequestData.ReadInt64(); + + if (ResolvePath(Context, TitleId, ContentType.Program)) + { + return 0; + } + else + { + return MakeError(ErrorModule.Lr, LrErr.ProgramLocationEntryNotFound); + } + } + + private void RedirectPath(ServiceCtx Context, long TitleId, int Flag, ContentType ContentType) + { + string ContentPath = ReadUtf8String(Context); + LocationEntry NewLocation = new LocationEntry(ContentPath, Flag, TitleId, ContentType); + + Context.Device.System.ContentManager.RedirectLocation(NewLocation, StorageId); + } + + private bool ResolvePath(ServiceCtx Context, long TitleId,ContentType ContentType) + { + ContentManager ContentManager = Context.Device.System.ContentManager; + string ContentPath = ContentManager.GetInstalledContentPath(TitleId, StorageId, ContentType.Program); + + if (!string.IsNullOrWhiteSpace(ContentPath)) + { + long Position = Context.Request.RecvListBuff[0].Position; + long Size = Context.Request.RecvListBuff[0].Size; + + byte[] ContentPathBuffer = Encoding.UTF8.GetBytes(ContentPath); + + Context.Memory.WriteBytes(Position, ContentPathBuffer); + } + else + { + return false; + } + + return true; + } + + private void DeleteContentPath(ServiceCtx Context, long TitleId, ContentType ContentType) + { + ContentManager ContentManager = Context.Device.System.ContentManager; + string ContentPath = ContentManager.GetInstalledContentPath(TitleId, StorageId, ContentType.Manual); + + ContentManager.ClearEntry(TitleId, ContentType.Manual, StorageId); + } + } +} -- cgit v1.2.3