diff --git a/Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs b/Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs new file mode 100644 index 0000000000..eafcc88d55 --- /dev/null +++ b/Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs @@ -0,0 +1,105 @@ +using ChocolArm64.Memory; +using Ryujinx.OsHle.Ipc; +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace Ryujinx.OsHle.Objects.FspSrv +{ + struct DirectoryEntry + { + public string Name; + public byte Type; + public long Size; + } + + class IDirectory : IIpcInterface + { + private List DirectoryEntries; + private int CurrentItem; + private Dictionary m_Commands; + + public IReadOnlyDictionary Commands => m_Commands; + + private string HostPath; + + const int DirectoryEntryType_Directory = 0; + const int DirectoryEntryType_File = 0; + public IDirectory(string HostPath, int flags) + { + m_Commands = new Dictionary() + { + { 0, Read }, + { 1, GetEntryCount } + }; + + this.HostPath = HostPath; + + if((flags & 1) == 1) + { + string[] Directories = Directory.GetDirectories(HostPath, "*", SearchOption.TopDirectoryOnly); + foreach(string Directory in Directories) + { + DirectoryEntry Info = new DirectoryEntry(); + Info.Name = Directory; + Info.Type = DirectoryEntryType_Directory; + Info.Size = 0; + DirectoryEntries.Add(Info); + } + } + + if((flags & 2) == 2) + { + string[] Files = Directory.GetFiles(HostPath, "*", SearchOption.TopDirectoryOnly); + foreach (string FileName in Files) + { + DirectoryEntry Info = new DirectoryEntry(); + Info.Name = FileName; + Info.Type = DirectoryEntryType_File; + Info.Size = new FileInfo(FileName).Length; + DirectoryEntries.Add(Info); + } + } + } + + const int DirectoryEntrySize = 0x310; + public long Read(ServiceCtx Context) + { + long BufferPosition = Context.Request.PtrBuff[0].Position; + long BufferLen = Context.Request.PtrBuff[0].Size; + long MaxDirectories = BufferLen / DirectoryEntrySize; + + if(MaxDirectories == DirectoryEntries.Count) + { + MaxDirectories = DirectoryEntries.Count; + } + + int CurrentIndex = 0; + byte[] DirectoryEntry = new byte[DirectoryEntrySize]; + for(; CurrentItem < MaxDirectories; CurrentItem++) + { + MemoryStream MemStream = new MemoryStream(); + BinaryWriter Writer = new BinaryWriter(MemStream); + Writer.Write(Encoding.UTF8.GetBytes(DirectoryEntries[CurrentItem].Name)); + Writer.Seek(0x304, SeekOrigin.Begin); + Writer.Write(DirectoryEntries[CurrentItem].Type); + Writer.Seek(0x308, SeekOrigin.Begin); + Writer.Write(DirectoryEntries[CurrentItem].Size); + + MemStream.Seek(0, SeekOrigin.Begin); + MemStream.Read(DirectoryEntry, 0, 0x310); + AMemoryHelper.WriteBytes(Context.Memory, BufferPosition + DirectoryEntrySize * CurrentIndex, DirectoryEntry); + CurrentIndex++; + } + + Context.ResponseData.Write(CurrentIndex + 1); + return 0; + } + + public long GetEntryCount(ServiceCtx Context) + { + Context.ResponseData.Write((long)DirectoryEntries.Count); + return 0; + } + } +} \ No newline at end of file diff --git a/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs b/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs index 29b4242db3..64c01c97c5 100644 --- a/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs +++ b/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs @@ -22,14 +22,14 @@ namespace Ryujinx.OsHle.Objects.FspSrv { { 0, CreateFile }, { 1, DeleteFile }, - //{ 2, CreateDirectory }, - //{ 3, DeleteDirectory }, - //{ 4, DeleteDirectoryRecursively }, - //{ 5, RenameFile }, - //{ 6, GetEntryType }, + { 2, CreateDirectory }, + { 3, DeleteDirectory }, + { 4, DeleteDirectoryRecursively }, + { 5, RenameFile }, + { 6, RenameDirectory }, { 7, GetEntryType }, { 8, OpenFile }, - //{ 9, OpenDirectory }, + { 9, OpenDirectory }, { 10, Commit }, //{ 11, GetFreeSpaceSize }, //{ 12, GetTotalSpaceSize }, @@ -76,6 +76,88 @@ namespace Ryujinx.OsHle.Objects.FspSrv return -1; } + public long CreateDirectory(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string FileName = Context.Ns.VFs.GetFullPath(Path, Name); + + if (FileName != null) + { + Directory.CreateDirectory(FileName); + return 0; + } + + //TODO: Correct error code. + return -1; + } + + public long DeleteDirectory(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string FileName = Context.Ns.VFs.GetFullPath(Path, Name); + + if (FileName != null) + { + Directory.Delete(FileName); + return 0; + } + + return -1; + } + + public long DeleteDirectoryRecursively(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + string FileName = Context.Ns.VFs.GetFullPath(Path, Name); + + if (FileName != null) + { + Directory.Delete(FileName, true); // recursive = true + return 0; + } + + return -1; + } + + public long RenameFile(ServiceCtx Context) + { + long OldPosition = Context.Request.PtrBuff[0].Position; + long NewPosition = Context.Request.PtrBuff[0].Position; + string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); + string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); + string OldFileName = Context.Ns.VFs.GetFullPath(Path, OldName); + string NewFileName = Context.Ns.VFs.GetFullPath(Path, NewName); + + if (OldFileName != null && NewFileName != null) + { + File.Move(OldFileName, NewFileName); + return 0; + } + + return -1; + } + + public long RenameDirectory(ServiceCtx Context) + { + long OldPosition = Context.Request.PtrBuff[0].Position; + long NewPosition = Context.Request.PtrBuff[0].Position; + string OldName = AMemoryHelper.ReadAsciiString(Context.Memory, OldPosition); + string NewName = AMemoryHelper.ReadAsciiString(Context.Memory, NewPosition); + string OldDirName = Context.Ns.VFs.GetFullPath(Path, OldName); + string NewDirName = Context.Ns.VFs.GetFullPath(Path, NewName); + + if (OldDirName != null && NewDirName != null) + { + Directory.Move(OldDirName, NewDirName); + return 0; + } + + return -1; + } + public long GetEntryType(ServiceCtx Context) { long Position = Context.Request.PtrBuff[0].Position; @@ -125,6 +207,26 @@ namespace Ryujinx.OsHle.Objects.FspSrv return -1; } + public long OpenDirectory(ServiceCtx Context) + { + long Position = Context.Request.PtrBuff[0].Position; + + int FilterFlags = Context.RequestData.ReadInt32(); + + string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position); + + string DirName = Context.Ns.VFs.GetFullPath(Path, Name); + + if(DirName != null) + { + MakeObject(Context, new IDirectory(DirName, FilterFlags)); + return 0; + } + + // TODO: Correct error code. + return -1; + } + public long Commit(ServiceCtx Context) { return 0;