2018-11-18 19:37:41 +00:00
|
|
|
|
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
|
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
private readonly string _basePath;
|
|
|
|
|
private readonly string _rootPath;
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public FileSystemProvider(string basePath, string rootPath)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:24:37 +00:00
|
|
|
|
_basePath = basePath;
|
|
|
|
|
_rootPath = rootPath;
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(basePath);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public long CreateDirectory(string name)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (Directory.Exists(name))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
|
|
|
|
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
Directory.CreateDirectory(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public long CreateFile(string name, long size)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (File.Exists(name))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
|
|
|
|
return MakeError(ErrorModule.Fs, FsErr.PathAlreadyExists);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
using (FileStream newFile = File.Create(name))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
newFile.SetLength(size);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public long DeleteDirectory(string name, bool recursive)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
string dirName = name;
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (!Directory.Exists(dirName))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
|
|
|
|
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
Directory.Delete(dirName, recursive);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public long DeleteFile(string name)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (!File.Exists(name))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
|
|
|
|
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
File.Delete(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public DirectoryEntry[] GetDirectories(string path)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(path);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
List<DirectoryEntry> entries = new List<DirectoryEntry>();
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
foreach(string directory in Directory.EnumerateDirectories(path))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
DirectoryEntry directoryEntry = new DirectoryEntry(directory, DirectoryEntryType.Directory);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
entries.Add(directoryEntry);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
return entries.ToArray();
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public DirectoryEntry[] GetEntries(string path)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(path);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (Directory.Exists(path))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
List<DirectoryEntry> entries = new List<DirectoryEntry>();
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
foreach (string directory in Directory.EnumerateDirectories(path))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
DirectoryEntry directoryEntry = new DirectoryEntry(directory, DirectoryEntryType.Directory);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
entries.Add(directoryEntry);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
foreach (string file in Directory.EnumerateFiles(path))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
FileInfo fileInfo = new FileInfo(file);
|
|
|
|
|
DirectoryEntry directoryEntry = new DirectoryEntry(file, DirectoryEntryType.File, fileInfo.Length);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
entries.Add(directoryEntry);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public DirectoryEntry[] GetFiles(string path)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(path);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
List<DirectoryEntry> entries = new List<DirectoryEntry>();
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
foreach (string file in Directory.EnumerateFiles(path))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
FileInfo fileInfo = new FileInfo(file);
|
|
|
|
|
DirectoryEntry directoryEntry = new DirectoryEntry(file, DirectoryEntryType.File, fileInfo.Length);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
entries.Add(directoryEntry);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
return entries.ToArray();
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public long GetFreeSpace(ServiceCtx context)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
return context.Device.FileSystem.GetDrive().AvailableFreeSpace;
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public string GetFullPath(string name)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (name.StartsWith("//"))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
name = name.Substring(2);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
2018-12-01 20:01:59 +00:00
|
|
|
|
else if (name.StartsWith('/'))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
name = name.Substring(1);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
string fullPath = Path.Combine(_basePath, name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(fullPath);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
return fullPath;
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public long GetTotalSpace(ServiceCtx context)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
return context.Device.FileSystem.GetDrive().TotalSize;
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public bool DirectoryExists(string name)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
return Directory.Exists(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public bool FileExists(string name)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
return File.Exists(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public long OpenDirectory(string name, int filterFlags, out IDirectory directoryInterface)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (Directory.Exists(name))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
directoryInterface = new IDirectory(name, filterFlags, this);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
directoryInterface = null;
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
|
|
|
|
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public long OpenFile(string name, out IFile fileInterface)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (File.Exists(name))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
FileStream stream = new FileStream(name, FileMode.Open);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
fileInterface = new IFile(stream, name);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
fileInterface = null;
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
|
|
|
|
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public long RenameDirectory(string oldName, string newName)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(oldName);
|
|
|
|
|
CheckIfDescendentOfRootPath(newName);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (Directory.Exists(oldName))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
Directory.Move(oldName, newName);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public long RenameFile(string oldName, string newName)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
CheckIfDescendentOfRootPath(oldName);
|
|
|
|
|
CheckIfDescendentOfRootPath(newName);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (File.Exists(oldName))
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
File.Move(oldName, newName);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
public void CheckIfDescendentOfRootPath(string path)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
DirectoryInfo pathInfo = new DirectoryInfo(path);
|
|
|
|
|
DirectoryInfo rootInfo = new DirectoryInfo(_rootPath);
|
2018-11-18 19:37:41 +00:00
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
while (pathInfo.Parent != null)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
if (pathInfo.Parent.FullName == rootInfo.FullName)
|
2018-11-18 19:37:41 +00:00
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-12-01 20:01:59 +00:00
|
|
|
|
pathInfo = pathInfo.Parent;
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-12-01 20:01:59 +00:00
|
|
|
|
throw new InvalidOperationException($"Path {path} is not a child directory of {_rootPath}");
|
2018-11-18 19:37:41 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|