From fe8fbb6fb9b85a528ddfa4848ec8e35fd9a5e9a5 Mon Sep 17 00:00:00 2001
From: emmauss <emmausssss@gmail.com>
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/FileSystem/FileSystemProvider.cs | 281 +++++++++++++++++++++++++++
 1 file changed, 281 insertions(+)
 create mode 100644 Ryujinx.HLE/FileSystem/FileSystemProvider.cs

(limited to 'Ryujinx.HLE/FileSystem/FileSystemProvider.cs')

diff --git a/Ryujinx.HLE/FileSystem/FileSystemProvider.cs b/Ryujinx.HLE/FileSystem/FileSystemProvider.cs
new file mode 100644
index 00000000..37ccfb10
--- /dev/null
+++ b/Ryujinx.HLE/FileSystem/FileSystemProvider.cs
@@ -0,0 +1,281 @@
+using Ryujinx.HLE.HOS;
+using Ryujinx.HLE.HOS.Services.FspSrv;
+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)
+        {
+            this.BasePath = BasePath;
+            this.RootPath = RootPath;
+
+            CheckIfDecendentOfRootPath(BasePath);
+        }
+
+        public long CreateDirectory(string Name)
+        {
+            CheckIfDecendentOfRootPath(Name);
+
+            if (Directory.Exists(Name))
+            {
+                return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
+            }
+
+            Directory.CreateDirectory(Name);
+
+            return 0;
+        }
+
+        public long CreateFile(string Name, long Size)
+        {
+            CheckIfDecendentOfRootPath(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)
+        {
+            CheckIfDecendentOfRootPath(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)
+        {
+            CheckIfDecendentOfRootPath(Name);
+
+            if (!File.Exists(Name))
+            {
+                return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+            }
+            else
+            {
+                File.Delete(Name);
+            }
+
+            return 0;
+        }
+
+        public DirectoryEntry[] GetDirectories(string Path)
+        {
+            CheckIfDecendentOfRootPath(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)
+        {
+            CheckIfDecendentOfRootPath(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 null;
+        }
+
+        public DirectoryEntry[] GetFiles(string Path)
+        {
+            CheckIfDecendentOfRootPath(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);
+
+            CheckIfDecendentOfRootPath(FullPath);
+
+            return FullPath;
+        }
+
+        public long GetTotalSpace(ServiceCtx Context)
+        {
+            return Context.Device.FileSystem.GetDrive().TotalSize;
+        }
+
+        public bool DirectoryExists(string Name)
+        {
+            CheckIfDecendentOfRootPath(Name);
+
+            return Directory.Exists(Name);
+        }
+
+        public bool FileExists(string Name)
+        {
+            CheckIfDecendentOfRootPath(Name);
+
+            return File.Exists(Name);
+        }
+
+        public long OpenDirectory(string Name, int FilterFlags, out IDirectory DirectoryInterface)
+        {
+            CheckIfDecendentOfRootPath(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)
+        {
+            CheckIfDecendentOfRootPath(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)
+        {
+            CheckIfDecendentOfRootPath(OldName);
+            CheckIfDecendentOfRootPath(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)
+        {
+            CheckIfDecendentOfRootPath(OldName);
+            CheckIfDecendentOfRootPath(NewName);
+
+            if (File.Exists(OldName))
+            {
+                File.Move(OldName, NewName);
+            }
+            else
+            {
+                return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+            }
+
+            return 0;
+        }
+
+        public void CheckIfDecendentOfRootPath(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}");
+        }
+    }
+}
-- 
cgit v1.2.3-70-g09d2