Ryujinx/Ryujinx.HLE/FileSystem/FileSystemProvider.cs

281 lines
7.4 KiB
C#

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;
CheckIfDescendentOfRootPath(BasePath);
}
public long CreateDirectory(string Name)
{
CheckIfDescendentOfRootPath(Name);
if (Directory.Exists(Name))
{
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
}
Directory.CreateDirectory(Name);
return 0;
}
public long CreateFile(string Name, long Size)
{
CheckIfDescendentOfRootPath(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)
{
CheckIfDescendentOfRootPath(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)
{
CheckIfDescendentOfRootPath(Name);
if (!File.Exists(Name))
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
else
{
File.Delete(Name);
}
return 0;
}
public DirectoryEntry[] GetDirectories(string Path)
{
CheckIfDescendentOfRootPath(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)
{
CheckIfDescendentOfRootPath(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)
{
CheckIfDescendentOfRootPath(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);
CheckIfDescendentOfRootPath(FullPath);
return FullPath;
}
public long GetTotalSpace(ServiceCtx Context)
{
return Context.Device.FileSystem.GetDrive().TotalSize;
}
public bool DirectoryExists(string Name)
{
CheckIfDescendentOfRootPath(Name);
return Directory.Exists(Name);
}
public bool FileExists(string Name)
{
CheckIfDescendentOfRootPath(Name);
return File.Exists(Name);
}
public long OpenDirectory(string Name, int FilterFlags, out IDirectory DirectoryInterface)
{
CheckIfDescendentOfRootPath(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)
{
CheckIfDescendentOfRootPath(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)
{
CheckIfDescendentOfRootPath(OldName);
CheckIfDescendentOfRootPath(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)
{
CheckIfDescendentOfRootPath(OldName);
CheckIfDescendentOfRootPath(NewName);
if (File.Exists(OldName))
{
File.Move(OldName, NewName);
}
else
{
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
}
return 0;
}
public void CheckIfDescendentOfRootPath(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}");
}
}
}