2020-05-12 22:17:06 +02:00
|
|
|
|
using LibHac.Common;
|
|
|
|
|
using LibHac.Fs;
|
|
|
|
|
using Xunit;
|
|
|
|
|
|
|
|
|
|
namespace LibHac.Tests.Fs.IFileSystemTestBase
|
|
|
|
|
{
|
|
|
|
|
public abstract partial class CommittableIFileSystemTests
|
|
|
|
|
{
|
|
|
|
|
[Fact]
|
|
|
|
|
public void Commit_AfterSuccessfulCommit_CanReadCommittedData()
|
|
|
|
|
{
|
|
|
|
|
// "Random" test data
|
|
|
|
|
var data1 = new byte[] { 7, 4, 1, 0, 8, 5, 2, 9, 6, 3 };
|
|
|
|
|
var data2 = new byte[] { 6, 1, 6, 8, 0, 3, 9, 7, 5, 1 };
|
|
|
|
|
|
|
|
|
|
IReopenableFileSystemCreator fsCreator = GetFileSystemCreator();
|
|
|
|
|
IFileSystem fs = fsCreator.Create();
|
|
|
|
|
|
|
|
|
|
// Make sure to test both directories and files
|
|
|
|
|
fs.CreateDirectory("/dir1".ToU8Span()).ThrowIfFailure();
|
|
|
|
|
fs.CreateDirectory("/dir2".ToU8Span()).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
fs.CreateFile("/dir1/file".ToU8Span(), data1.Length, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
fs.CreateFile("/dir2/file".ToU8Span(), data2.Length, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
fs.OpenFile(out IFile file1, "/dir1/file".ToU8Span(), OpenMode.Write).ThrowIfFailure();
|
|
|
|
|
fs.OpenFile(out IFile file2, "/dir2/file".ToU8Span(), OpenMode.Write).ThrowIfFailure();
|
|
|
|
|
|
2020-06-06 23:18:03 +02:00
|
|
|
|
file1.Write(0, data1, WriteOptionFlag.Flush).ThrowIfFailure();
|
|
|
|
|
file2.Write(0, data2, WriteOptionFlag.Flush).ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
|
|
|
|
|
file1.Dispose();
|
|
|
|
|
file2.Dispose();
|
|
|
|
|
|
|
|
|
|
fs.Commit().ThrowIfFailure();
|
|
|
|
|
fs.Dispose();
|
|
|
|
|
|
|
|
|
|
// Reopen after committing
|
|
|
|
|
fs = fsCreator.Create();
|
|
|
|
|
|
|
|
|
|
var readData1 = new byte[data1.Length];
|
|
|
|
|
var readData2 = new byte[data2.Length];
|
|
|
|
|
|
|
|
|
|
Assert.Success(fs.OpenFile(out file1, "/dir1/file".ToU8Span(), OpenMode.Read));
|
|
|
|
|
|
|
|
|
|
using (file1)
|
|
|
|
|
{
|
2020-06-06 23:18:03 +02:00
|
|
|
|
Assert.Success(file1.Read(out long bytesRead, 0, readData1, ReadOptionFlag.None));
|
2020-05-12 22:17:06 +02:00
|
|
|
|
Assert.Equal(data1.Length, bytesRead);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Assert.Equal(data1, readData1);
|
|
|
|
|
|
|
|
|
|
Assert.Success(fs.OpenFile(out file2, "/dir2/file".ToU8Span(), OpenMode.Read));
|
|
|
|
|
|
|
|
|
|
using (file2)
|
|
|
|
|
{
|
2020-06-06 23:18:03 +02:00
|
|
|
|
Assert.Success(file2.Read(out long bytesRead, 0, readData2, ReadOptionFlag.None));
|
2020-05-12 22:17:06 +02:00
|
|
|
|
Assert.Equal(data2.Length, bytesRead);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Assert.Equal(data2, readData2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void Rollback_CreateFileThenRollback_FileDoesNotExist()
|
|
|
|
|
{
|
|
|
|
|
IFileSystem fs = CreateFileSystem();
|
|
|
|
|
|
|
|
|
|
fs.CreateDirectory("/dir".ToU8Span()).ThrowIfFailure();
|
|
|
|
|
fs.CreateFile("/dir/file".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
// Rollback should succeed
|
|
|
|
|
Assert.Success(fs.Rollback());
|
|
|
|
|
|
|
|
|
|
// Make sure the file and directory are gone
|
|
|
|
|
Assert.Result(ResultFs.PathNotFound, fs.GetEntryType(out _, "/dir".ToU8Span()));
|
|
|
|
|
Assert.Result(ResultFs.PathNotFound, fs.GetEntryType(out _, "/dir/file".ToU8Span()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void Rollback_CreateFileThenCloseFs_FileDoesNotExist()
|
|
|
|
|
{
|
|
|
|
|
IReopenableFileSystemCreator fsCreator = GetFileSystemCreator();
|
|
|
|
|
IFileSystem fs = fsCreator.Create();
|
|
|
|
|
|
|
|
|
|
fs.CreateDirectory("/dir".ToU8Span()).ThrowIfFailure();
|
|
|
|
|
fs.CreateFile("/dir/file".ToU8Span(), 0, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
// Close without committing and reopen the file system
|
|
|
|
|
fs.Dispose();
|
|
|
|
|
fs = fsCreator.Create();
|
|
|
|
|
|
|
|
|
|
// Make sure the file and directory are gone
|
|
|
|
|
Assert.Result(ResultFs.PathNotFound, fs.GetEntryType(out _, "/dir".ToU8Span()));
|
|
|
|
|
Assert.Result(ResultFs.PathNotFound, fs.GetEntryType(out _, "/dir/file".ToU8Span()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
|
|
public void Rollback_AfterChangingExistingFiles_GoesBackToOriginalData()
|
|
|
|
|
{
|
|
|
|
|
// "Random" test data
|
|
|
|
|
var data1 = new byte[] { 7, 4, 1, 0, 8, 5, 2, 9, 6, 3 };
|
|
|
|
|
var data2 = new byte[] { 6, 1, 6, 8, 0, 3, 9, 7, 5, 1 };
|
|
|
|
|
|
|
|
|
|
IReopenableFileSystemCreator fsCreator = GetFileSystemCreator();
|
|
|
|
|
IFileSystem fs = fsCreator.Create();
|
|
|
|
|
|
|
|
|
|
fs.CreateDirectory("/dir".ToU8Span()).ThrowIfFailure();
|
|
|
|
|
fs.CreateFile("/dir/file".ToU8Span(), data1.Length, CreateFileOptions.None).ThrowIfFailure();
|
|
|
|
|
|
|
|
|
|
fs.OpenFile(out IFile file, "/dir/file".ToU8Span(), OpenMode.Write).ThrowIfFailure();
|
2020-06-06 23:18:03 +02:00
|
|
|
|
file.Write(0, data1, WriteOptionFlag.Flush).ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
file.Dispose();
|
|
|
|
|
|
|
|
|
|
// Commit and reopen the file system
|
|
|
|
|
fs.Commit().ThrowIfFailure();
|
|
|
|
|
fs.Dispose();
|
|
|
|
|
|
|
|
|
|
fs = fsCreator.Create();
|
|
|
|
|
|
|
|
|
|
// Make changes to the file
|
|
|
|
|
fs.OpenFile(out file, "/dir/file".ToU8Span(), OpenMode.Write).ThrowIfFailure();
|
2020-06-06 23:18:03 +02:00
|
|
|
|
file.Write(0, data2, WriteOptionFlag.Flush).ThrowIfFailure();
|
2020-05-12 22:17:06 +02:00
|
|
|
|
file.Dispose();
|
|
|
|
|
|
|
|
|
|
Assert.Success(fs.Rollback());
|
|
|
|
|
|
|
|
|
|
// The file should contain the original data after the rollback
|
|
|
|
|
var readData = new byte[data1.Length];
|
|
|
|
|
|
|
|
|
|
Assert.Success(fs.OpenFile(out file, "/dir/file".ToU8Span(), OpenMode.Read));
|
|
|
|
|
|
|
|
|
|
using (file)
|
|
|
|
|
{
|
2020-06-06 23:18:03 +02:00
|
|
|
|
Assert.Success(file.Read(out long bytesRead, 0, readData, ReadOptionFlag.None));
|
2020-05-12 22:17:06 +02:00
|
|
|
|
Assert.Equal(data1.Length, bytesRead);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Assert.Equal(data1, readData);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|