aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2018-08-16 20:47:36 -0300
committerGitHub <noreply@github.com>2018-08-16 20:47:36 -0300
commit521751795a1c97c0d97f6f8904a3be69b13d3a9d (patch)
tree942a05899c40e2de6d92a38b93a494bd96ee64b8 /Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs
parent182d716867ae477c2b15a5332430dc2641fa1cc3 (diff)
Code style fixes and nits on the HLE project (#355)
* Some style fixes and nits on ITimeZoneService * Remove some unneeded usings * Remove the Ryujinx.HLE.OsHle.Handles namespace * Remove hbmenu automatic load on process exit * Rename Ns to Device, rename Os to System, rename SystemState to State * Move Exceptions and Utilities out of OsHle * Rename OsHle to HOS * Rename OsHle folder to HOS * IManagerDisplayService and ISystemDisplayService style fixes * BsdError shouldn't be public * Add a empty new line before using static * Remove unused file * Some style fixes on NPDM * Exit gracefully when the application is closed * Code style fixes on IGeneralService * Add 0x prefix on values printed as hex * Small improvements on finalization code * Move ProcessId and ThreadId out of AThreadState * Rename VFs to FileSystem * FsAccessHeader shouldn't be public. Also fix file names casing * More case changes on NPDM * Remove unused files * Move using to the correct place on NPDM * Use properties on KernelAccessControlMmio * Address PR feedback
Diffstat (limited to 'Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs')
-rw-r--r--Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs412
1 files changed, 412 insertions, 0 deletions
diff --git a/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs
new file mode 100644
index 00000000..b77043bd
--- /dev/null
+++ b/Ryujinx.HLE/HOS/Services/FspSrv/IFileSystem.cs
@@ -0,0 +1,412 @@
+using Ryujinx.HLE.HOS.Ipc;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+
+using static Ryujinx.HLE.HOS.ErrorCode;
+
+namespace Ryujinx.HLE.HOS.Services.FspSrv
+{
+ class IFileSystem : IpcService
+ {
+ private Dictionary<int, ServiceProcessRequest> m_Commands;
+
+ public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => m_Commands;
+
+ private HashSet<string> OpenPaths;
+
+ private string Path;
+
+ public IFileSystem(string Path)
+ {
+ m_Commands = new Dictionary<int, ServiceProcessRequest>()
+ {
+ { 0, CreateFile },
+ { 1, DeleteFile },
+ { 2, CreateDirectory },
+ { 3, DeleteDirectory },
+ { 4, DeleteDirectoryRecursively },
+ { 5, RenameFile },
+ { 6, RenameDirectory },
+ { 7, GetEntryType },
+ { 8, OpenFile },
+ { 9, OpenDirectory },
+ { 10, Commit },
+ { 11, GetFreeSpaceSize },
+ { 12, GetTotalSpaceSize },
+ { 13, CleanDirectoryRecursively },
+ //{ 14, GetFileTimeStampRaw }
+ };
+
+ OpenPaths = new HashSet<string>();
+
+ this.Path = Path;
+ }
+
+ public long CreateFile(ServiceCtx Context)
+ {
+ string Name = ReadUtf8String(Context);
+
+ long Mode = Context.RequestData.ReadInt64();
+ int Size = Context.RequestData.ReadInt32();
+
+ string FileName = Context.Device.FileSystem.GetFullPath(Path, Name);
+
+ if (FileName == null)
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ if (File.Exists(FileName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
+ }
+
+ if (IsPathAlreadyInUse(FileName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
+ }
+
+ using (FileStream NewFile = File.Create(FileName))
+ {
+ NewFile.SetLength(Size);
+ }
+
+ return 0;
+ }
+
+ public long DeleteFile(ServiceCtx Context)
+ {
+ string Name = ReadUtf8String(Context);
+
+ string FileName = Context.Device.FileSystem.GetFullPath(Path, Name);
+
+ if (!File.Exists(FileName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ if (IsPathAlreadyInUse(FileName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
+ }
+
+ File.Delete(FileName);
+
+ return 0;
+ }
+
+ public long CreateDirectory(ServiceCtx Context)
+ {
+ string Name = ReadUtf8String(Context);
+
+ string DirName = Context.Device.FileSystem.GetFullPath(Path, Name);
+
+ if (DirName == null)
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ if (Directory.Exists(DirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
+ }
+
+ if (IsPathAlreadyInUse(DirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
+ }
+
+ Directory.CreateDirectory(DirName);
+
+ return 0;
+ }
+
+ public long DeleteDirectory(ServiceCtx Context)
+ {
+ return DeleteDirectory(Context, false);
+ }
+
+ public long DeleteDirectoryRecursively(ServiceCtx Context)
+ {
+ return DeleteDirectory(Context, true);
+ }
+
+ private long DeleteDirectory(ServiceCtx Context, bool Recursive)
+ {
+ string Name = ReadUtf8String(Context);
+
+ string DirName = Context.Device.FileSystem.GetFullPath(Path, Name);
+
+ if (!Directory.Exists(DirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ if (IsPathAlreadyInUse(DirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
+ }
+
+ Directory.Delete(DirName, Recursive);
+
+ return 0;
+ }
+
+ public long RenameFile(ServiceCtx Context)
+ {
+ string OldName = ReadUtf8String(Context, 0);
+ string NewName = ReadUtf8String(Context, 1);
+
+ string OldFileName = Context.Device.FileSystem.GetFullPath(Path, OldName);
+ string NewFileName = Context.Device.FileSystem.GetFullPath(Path, NewName);
+
+ if (!File.Exists(OldFileName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ if (File.Exists(NewFileName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
+ }
+
+ if (IsPathAlreadyInUse(OldFileName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
+ }
+
+ File.Move(OldFileName, NewFileName);
+
+ return 0;
+ }
+
+ public long RenameDirectory(ServiceCtx Context)
+ {
+ string OldName = ReadUtf8String(Context, 0);
+ string NewName = ReadUtf8String(Context, 1);
+
+ string OldDirName = Context.Device.FileSystem.GetFullPath(Path, OldName);
+ string NewDirName = Context.Device.FileSystem.GetFullPath(Path, NewName);
+
+ if (!Directory.Exists(OldDirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ if (Directory.Exists(NewDirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
+ }
+
+ if (IsPathAlreadyInUse(OldDirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
+ }
+
+ Directory.Move(OldDirName, NewDirName);
+
+ return 0;
+ }
+
+ public long GetEntryType(ServiceCtx Context)
+ {
+ string Name = ReadUtf8String(Context);
+
+ string FileName = Context.Device.FileSystem.GetFullPath(Path, Name);
+
+ if (File.Exists(FileName))
+ {
+ Context.ResponseData.Write(1);
+ }
+ else if (Directory.Exists(FileName))
+ {
+ Context.ResponseData.Write(0);
+ }
+ else
+ {
+ Context.ResponseData.Write(0);
+
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ return 0;
+ }
+
+ public long OpenFile(ServiceCtx Context)
+ {
+ int FilterFlags = Context.RequestData.ReadInt32();
+
+ string Name = ReadUtf8String(Context);
+
+ string FileName = Context.Device.FileSystem.GetFullPath(Path, Name);
+
+ if (!File.Exists(FileName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ if (IsPathAlreadyInUse(FileName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
+ }
+
+ FileStream Stream = new FileStream(FileName, FileMode.Open);
+
+ IFile FileInterface = new IFile(Stream, FileName);
+
+ FileInterface.Disposed += RemoveFileInUse;
+
+ lock (OpenPaths)
+ {
+ OpenPaths.Add(FileName);
+ }
+
+ MakeObject(Context, FileInterface);
+
+ return 0;
+ }
+
+ public long OpenDirectory(ServiceCtx Context)
+ {
+ int FilterFlags = Context.RequestData.ReadInt32();
+
+ string Name = ReadUtf8String(Context);
+
+ string DirName = Context.Device.FileSystem.GetFullPath(Path, Name);
+
+ if (!Directory.Exists(DirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ if (IsPathAlreadyInUse(DirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
+ }
+
+ IDirectory DirInterface = new IDirectory(DirName, FilterFlags);
+
+ DirInterface.Disposed += RemoveDirectoryInUse;
+
+ lock (OpenPaths)
+ {
+ OpenPaths.Add(DirName);
+ }
+
+ MakeObject(Context, DirInterface);
+
+ return 0;
+ }
+
+ public long Commit(ServiceCtx Context)
+ {
+ return 0;
+ }
+
+ public long GetFreeSpaceSize(ServiceCtx Context)
+ {
+ string Name = ReadUtf8String(Context);
+
+ Context.ResponseData.Write(Context.Device.FileSystem.GetDrive().AvailableFreeSpace);
+
+ return 0;
+ }
+
+ public long GetTotalSpaceSize(ServiceCtx Context)
+ {
+ string Name = ReadUtf8String(Context);
+
+ Context.ResponseData.Write(Context.Device.FileSystem.GetDrive().TotalSize);
+
+ return 0;
+ }
+
+ public long CleanDirectoryRecursively(ServiceCtx Context)
+ {
+ string Name = ReadUtf8String(Context);
+
+ string DirName = Context.Device.FileSystem.GetFullPath(Path, Name);
+
+ if (!Directory.Exists(DirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
+ }
+
+ if (IsPathAlreadyInUse(DirName))
+ {
+ return MakeError(ErrorModule.Fs, FsErr.PathAlreadyInUse);
+ }
+
+ foreach (string Entry in Directory.EnumerateFileSystemEntries(DirName))
+ {
+ if (Directory.Exists(Entry))
+ {
+ Directory.Delete(Entry, true);
+ }
+ else if (File.Exists(Entry))
+ {
+ File.Delete(Entry);
+ }
+ }
+
+ return 0;
+ }
+
+ private bool IsPathAlreadyInUse(string Path)
+ {
+ lock (OpenPaths)
+ {
+ return OpenPaths.Contains(Path);
+ }
+ }
+
+ private void RemoveFileInUse(object sender, EventArgs e)
+ {
+ IFile FileInterface = (IFile)sender;
+
+ lock (OpenPaths)
+ {
+ FileInterface.Disposed -= RemoveFileInUse;
+
+ OpenPaths.Remove(FileInterface.HostPath);
+ }
+ }
+
+ private void RemoveDirectoryInUse(object sender, EventArgs e)
+ {
+ IDirectory DirInterface = (IDirectory)sender;
+
+ lock (OpenPaths)
+ {
+ DirInterface.Disposed -= RemoveDirectoryInUse;
+
+ OpenPaths.Remove(DirInterface.HostPath);
+ }
+ }
+
+ private string ReadUtf8String(ServiceCtx Context, int Index = 0)
+ {
+ long Position = Context.Request.PtrBuff[Index].Position;
+ long Size = Context.Request.PtrBuff[Index].Size;
+
+ using (MemoryStream MS = new MemoryStream())
+ {
+ while (Size-- > 0)
+ {
+ byte Value = Context.Memory.ReadByte(Position++);
+
+ if (Value == 0)
+ {
+ break;
+ }
+
+ MS.WriteByte(Value);
+ }
+
+ return Encoding.UTF8.GetString(MS.ToArray());
+ }
+ }
+ }
+} \ No newline at end of file