diff --git a/Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs b/Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs
new file mode 100644
index 00000000..82867451
--- /dev/null
+++ b/Ryujinx/OsHle/Objects/FspSrv/IDirectory.cs
@@ -0,0 +1,133 @@
+using ChocolArm64.Memory;
+using Ryujinx.OsHle.Ipc;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Ryujinx.OsHle.Objects.FspSrv
+{
+    [StructLayout(LayoutKind.Sequential, Size = 0x310)]
+    struct DirectoryEntry
+    {
+        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x300)]
+        public byte[] Name;
+        public int Unknown;
+        public byte Type;
+        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)]
+        public byte[] Padding;
+        public long Size;
+    }
+
+    enum DirectoryEntryType
+    {
+        Directory,
+        File
+    }
+
+    class IDirectory : IIpcInterface
+    {
+        private List<DirectoryEntry> DirectoryEntries = new List<DirectoryEntry>();
+        private Dictionary<int, ServiceProcessRequest> m_Commands;
+
+        public IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+        private string HostPath;
+
+        public IDirectory(string HostPath, int flags)
+        {
+            m_Commands = new Dictionary<int, ServiceProcessRequest>()
+            {
+                {  0, Read          },
+                {  1, GetEntryCount }
+            };
+
+            this.HostPath = HostPath;
+
+            if ((flags & 1) == 1)
+            {
+                string[] Directories = Directory.GetDirectories(HostPath, "*", SearchOption.TopDirectoryOnly).
+                             Where(x => (new FileInfo(x).Attributes & FileAttributes.Hidden) == 0).ToArray();
+
+                foreach (string Directory in Directories)
+                {
+                    DirectoryEntry Info = new DirectoryEntry
+                    {
+                        Name = Encoding.UTF8.GetBytes(Directory),
+                        Type = (byte)DirectoryEntryType.Directory,
+                        Size = 0
+                    };
+
+                    Array.Resize(ref Info.Name, 0x300);
+                    DirectoryEntries.Add(Info);
+                }
+            }
+
+            if ((flags & 2) == 2)
+            {
+                string[] Files = Directory.GetFiles(HostPath, "*", SearchOption.TopDirectoryOnly).
+                       Where(x => (new FileInfo(x).Attributes & FileAttributes.Hidden) == 0).ToArray();
+
+                foreach (string FileName in Files)
+                {
+                    DirectoryEntry Info = new DirectoryEntry
+                    {
+                        Name = Encoding.UTF8.GetBytes(Path.GetFileName(FileName)),
+                        Type = (byte)DirectoryEntryType.File,
+                        Size = new FileInfo(Path.Combine(HostPath, FileName)).Length
+                    };
+
+                    Array.Resize(ref Info.Name, 0x300);
+                    DirectoryEntries.Add(Info);
+                }
+            }
+        }
+
+        private int LastItem = 0;
+        public long Read(ServiceCtx Context)
+        {
+            long BufferPosition = Context.Request.ReceiveBuff[0].Position;
+            long BufferLen = Context.Request.ReceiveBuff[0].Size;
+            long MaxDirectories = BufferLen / Marshal.SizeOf(typeof(DirectoryEntry));
+
+            if (MaxDirectories > DirectoryEntries.Count - LastItem)
+            {
+                MaxDirectories = DirectoryEntries.Count - LastItem;
+            }
+
+            int CurrentIndex;
+            for (CurrentIndex = 0; CurrentIndex < MaxDirectories; CurrentIndex++)
+            {
+                int CurrentItem = LastItem + CurrentIndex;
+
+                byte[] DirectoryEntry = new byte[Marshal.SizeOf(typeof(DirectoryEntry))];
+                IntPtr Ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(DirectoryEntry)));
+                Marshal.StructureToPtr(DirectoryEntries[CurrentItem], Ptr, true);
+                Marshal.Copy(Ptr, DirectoryEntry, 0, Marshal.SizeOf(typeof(DirectoryEntry)));
+                Marshal.FreeHGlobal(Ptr);
+
+                AMemoryHelper.WriteBytes(Context.Memory, BufferPosition + Marshal.SizeOf(typeof(DirectoryEntry)) * CurrentIndex, DirectoryEntry);
+            }
+
+            if (LastItem < DirectoryEntries.Count)
+            {
+                LastItem += CurrentIndex;
+                Context.ResponseData.Write((long)CurrentIndex); // index = number of entries written this call.
+            }
+            else
+            {
+                Context.ResponseData.Write((long)0);
+            }
+
+            return 0;
+        }
+
+        public long GetEntryCount(ServiceCtx Context)
+        {
+            Context.ResponseData.Write((long)DirectoryEntries.Count);
+            return 0;
+        }
+    }
+}
diff --git a/Ryujinx/OsHle/Objects/FspSrv/IFile.cs b/Ryujinx/OsHle/Objects/FspSrv/IFile.cs
index 1c6cc2e2..2f389990 100644
--- a/Ryujinx/OsHle/Objects/FspSrv/IFile.cs
+++ b/Ryujinx/OsHle/Objects/FspSrv/IFile.cs
@@ -19,7 +19,10 @@ namespace Ryujinx.OsHle.Objects.FspSrv
             m_Commands = new Dictionary<int, ServiceProcessRequest>()
             {
                 { 0, Read  },
-                { 1, Write }
+                { 1, Write },
+                // { 2, Flush },
+                { 3, SetSize },
+                { 4, GetSize }
             };
 
             this.BaseStream = BaseStream;
@@ -35,14 +38,12 @@ namespace Ryujinx.OsHle.Objects.FspSrv
 
             byte[] Data = new byte[Size];
 
+            BaseStream.Seek(Offset, SeekOrigin.Begin);
             int ReadSize = BaseStream.Read(Data, 0, (int)Size);
 
             AMemoryHelper.WriteBytes(Context.Memory, Position, Data);
 
-            //TODO: Use ReadSize, we need to return the size that was REALLY read from the file.
-            //This is a workaround because we are doing something wrong and the game expects to read
-            //data from a file that doesn't yet exists -- and breaks if it can't read anything.
-            Context.ResponseData.Write((long)Size);
+            Context.ResponseData.Write((long)ReadSize);
 
             return 0;
         }
@@ -63,6 +64,19 @@ namespace Ryujinx.OsHle.Objects.FspSrv
             return 0;
         }
 
+        public long GetSize(ServiceCtx Context)
+        {
+            Context.ResponseData.Write(BaseStream.Length);
+            return 0;
+        }
+
+        public long SetSize(ServiceCtx Context)
+        {
+            long Size = Context.RequestData.ReadInt64();
+            BaseStream.SetLength(Size);
+            return 0;
+        }
+
         public void Dispose()
         {
             Dispose(true);
diff --git a/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs b/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs
index bf501594..c3edf271 100644
--- a/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs
+++ b/Ryujinx/OsHle/Objects/FspSrv/IFileSystem.cs
@@ -17,16 +17,151 @@ namespace Ryujinx.OsHle.Objects.FspSrv
 
         public IFileSystem(string Path)
         {
+            //TODO: implement.
             m_Commands = new Dictionary<int, ServiceProcessRequest>()
             {
+                {  0, CreateFile   },
+                {  1, DeleteFile   },
+                {  2, CreateDirectory },
+                {  3, DeleteDirectory },
+                {  4, DeleteDirectoryRecursively },
+                {  5, RenameFile },
+                {  6, RenameDirectory },
                 {  7, GetEntryType },
                 {  8, OpenFile     },
-                { 10, Commit       }
+                {  9, OpenDirectory },
+                { 10, Commit       },
+                //{ 11, GetFreeSpaceSize },
+                //{ 12, GetTotalSpaceSize },
+                //{ 13, CleanDirectoryRecursively },
+                //{ 14, GetFileTimeStampRaw }
             };
 
             this.Path = Path;
         }
 
+        public long CreateFile(ServiceCtx Context)
+        {
+            long Position = Context.Request.PtrBuff[0].Position;
+            string Name = AMemoryHelper.ReadAsciiString(Context.Memory, Position);
+            ulong Mode = Context.RequestData.ReadUInt64();
+            uint Size = Context.RequestData.ReadUInt32();
+            string FileName = Context.Ns.VFs.GetFullPath(Path, Name);
+
+            if (FileName != null)
+            {
+                FileStream NewFile = File.Create(FileName);
+                NewFile.SetLength(Size);
+                NewFile.Close();
+                return 0;
+            }
+
+            //TODO: Correct error code.
+            return -1;
+        }
+
+        public long DeleteFile(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)
+            {
+                File.Delete(FileName);
+                return 0;
+            }
+
+            //TODO: Correct error code.
+            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;
+            }
+
+            // TODO: Correct error code.
+            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;
+            }
+
+            // TODO: Correct error code.
+            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;
+            }
+
+            // TODO: Correct error code.
+            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;
+            }
+
+            // TODO: Correct error code.
+            return -1;
+        }
+
         public long GetEntryType(ServiceCtx Context)
         {
             long Position = Context.Request.PtrBuff[0].Position;
@@ -64,11 +199,44 @@ namespace Ryujinx.OsHle.Objects.FspSrv
                 return -1;
             }
 
-            FileStream Stream = new FileStream(FileName, FileMode.OpenOrCreate);
+            if (File.Exists(FileName))
+            {
+                FileStream Stream = new FileStream(FileName, FileMode.OpenOrCreate);
+                MakeObject(Context, new IFile(Stream));
 
-            MakeObject(Context, new IFile(Stream));
+                return 0;
+            }
 
-            return 0;
+            //TODO: Correct error code.
+            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)
+            {
+                if (Directory.Exists(DirName))
+                {
+                    MakeObject(Context, new IDirectory(DirName, FilterFlags));
+                    return 0;
+                }
+                else
+                {
+                    // TODO: correct error code.
+                    return -1;
+                }
+            }
+
+            // TODO: Correct error code.
+            return -1;
         }
 
         public long Commit(ServiceCtx Context)