Vanara/UnitTests/PInvoke/Kernel32/WinBase.FileTests.cs

315 lines
12 KiB
C#

using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using Vanara.Extensions;
using Vanara.InteropServices;
using static Vanara.PInvoke.Kernel32;
using FileAccess = Vanara.PInvoke.Kernel32.FileAccess;
namespace Vanara.PInvoke.Tests
{
[TestFixture]
public partial class WinBaseTests_File
{
private static readonly string bigfn = TestCaseSources.LargeFile;
private static readonly string fn = TestCaseSources.SmallFile;
private const string newfn = @"C:\Temp\help2.ico";
[Test]
public void AreSetFileApisTest()
{
var ansi = false;
Assert.That(() => ansi = AreFileApisANSI(), Throws.Nothing);
if (ansi) SetFileApisToOEM(); else SetFileApisToANSI();
Assert.That(AreFileApisANSI(), Is.EqualTo(!ansi));
if (ansi) SetFileApisToANSI(); else SetFileApisToOEM();
}
[Test]
public void CheckNameLegalDOS8Dot3Test()
{
Assert.That(CheckNameLegalDOS8Dot3("FRED.DOC", null, 0, out _, out var legal), ResultIs.Successful);
Assert.That(legal, Is.True);
var sb = new StringBuilder(50);
Assert.That(CheckNameLegalDOS8Dot3("FRED IS MY FRIEND.DOC", sb, (uint)sb.Capacity, out var sp, out legal), ResultIs.Successful);
Assert.That(legal, Is.False);
TestContext.Write(sb);
}
[Test]
public void CopyFile2Test()
{
var par = COPYFILE2_EXTENDED_PARAMETERS.Default;
par.dwCopyFlags = COPY_FILE.COPY_FILE_RESTARTABLE;
Assert.That(CopyFile2(fn, newfn, ref par), ResultIs.Successful);
Assert.That(DeleteFile(newfn), Is.True);
}
[Test]
public void CopyFileExTest()
{
Assert.That(CopyFileEx(fn, newfn, null, default, false, COPY_FILE.COPY_FILE_RESTARTABLE), ResultIs.Successful);
Assert.That(DeleteFile(newfn), Is.True);
}
[Test]
public void CopyFileTest()
{
Assert.That(CopyFile(fn, newfn, false), ResultIs.Successful);
Assert.That(DeleteFile(newfn), Is.True);
}
[Test]
public void CreateDirectoryExTest()
{
Assert.That(CreateDirectoryEx(TestCaseSources.TempDir, TestCaseSources.TempChildDir), ResultIs.Successful);
Assert.That(RemoveDirectory(TestCaseSources.TempChildDir), ResultIs.Successful);
}
[Test]
public void CreateEnumHardLinkTest()
{
DeleteFile(newfn);
Assert.That(CreateHardLink(newfn, fn), ResultIs.Successful);
Assert.That(EnumHardLinks(fn), Contains.Item(newfn.Substring(2)));
Assert.That(DeleteFile(newfn), Is.True);
}
[Test]
public void CreateSymbolicLinkTest()
{
Assert.That(CreateSymbolicLink(newfn, fn, SymbolicLinkType.SYMBOLIC_LINK_FLAG_FILE), ResultIs.Successful);
Assert.That(DeleteFile(newfn), Is.True);
}
[Test]
public void EnumFileStreamsTest()
{
using (var tmp = new TempFile())
{
using (var str = CreateFile(tmp.FullName + ":stream1", FileAccess.GENERIC_WRITE, FileShare.Write, null, FileMode.OpenOrCreate, 0))
WriteFile(str, Encoding.Unicode.GetBytes("Hello"), 12, out var written);
using (var str = CreateFile(tmp.FullName + ":stream2", FileAccess.GENERIC_WRITE, FileShare.Write, null, FileMode.OpenOrCreate, 0))
WriteFile(str, Encoding.Unicode.GetBytes("Bye"), 8, out var written);
Assert.That(EnumFileStreams(tmp.FullName).ToArray(), Is.Not.Empty);
}
}
[Test]
public void EnumVolumeMountPointsTest()
{
// Setup a new mount on C:
string mntDir = TestCaseSources.TempDirWhack + @"Mounted\";
var sb = new StringBuilder(100);
Assert.That(GetVolumeNameForVolumeMountPoint(@"C:\", sb, (uint)sb.Capacity), ResultIs.Successful);
var cvol = sb.ToString();
Assert.That(GetVolumeNameForVolumeMountPoint(@"D:\", sb, (uint)sb.Capacity), ResultIs.Successful);
var dvol = sb.ToString();
Assert.That(CreateDirectory(mntDir), ResultIs.Successful);
Assert.That(SetVolumeMountPoint(mntDir, dvol), ResultIs.Successful);
try
{
Assert.That(EnumVolumeMountPoints(cvol).ToArray(), Contains.Item(mntDir.Substring(3)));
}
finally
{
// Remove mount
DeleteVolumeMountPoint(mntDir);
RemoveDirectory(mntDir);
}
}
[Test]
public void GetCompressedFileSizeTest()
{
Assert.That(GetCompressedFileSize(fn, out ulong sz), ResultIs.Successful);
Assert.That(sz, Is.GreaterThan(0));
Assert.That(() => GetCompressedFileSize(fn), Throws.Nothing);
Assert.That(() => GetCompressedFileSize(@"C:\NoFile.txt"), Throws.Exception);
}
[Test]
public void GetFileInformationByHandleExTest()
{
using (var tmp = new TempFile(FileAccess.GENERIC_READ, FileShare.Read))
using (var hDir = CreateFile(TestCaseSources.TempDirWhack, FileAccess.GENERIC_READ, FileShare.Read, null, FileMode.Open, FileFlagsAndAttributes.FILE_FLAG_BACKUP_SEMANTICS))
{
var exes = new List<Exception>();
TestHelper.RunForEach<FILE_INFO_BY_HANDLE_CLASS>(typeof(Kernel32), "GetFileInformationByHandleEx", e => new object[] { IsDir(e) ? (HFILE)hDir : (HFILE)tmp.hFile, e },
(e, ex) => { ex.Source = e.ToString(); exes.Add(ex); }, (e, ret, param) => ret.WriteValues(), CorrespondingAction.Get);
if (exes.Count > 0)
throw new AggregateException(exes.ToArray());
}
bool IsDir(FILE_INFO_BY_HANDLE_CLASS e) => e == FILE_INFO_BY_HANDLE_CLASS.FileFullDirectoryInfo || e == FILE_INFO_BY_HANDLE_CLASS.FileFullDirectoryRestartInfo || e == FILE_INFO_BY_HANDLE_CLASS.FileIdBothDirectoryInfo ||
e == FILE_INFO_BY_HANDLE_CLASS.FileIdBothDirectoryRestartInfo || e == FILE_INFO_BY_HANDLE_CLASS.FileIdExtdDirectoryInfo || e == FILE_INFO_BY_HANDLE_CLASS.FileIdExtdDirectoryRestartInfo;
}
[Test]
public void GetSetFileBandwidthReservationTest()
{
using (var tmp = new TempFile(FileAccess.GENERIC_READ, FileShare.Read))
{
// This shouldn't work on NTFS vols.
Assert.That(GetFileBandwidthReservation(tmp.hFile, out var per, out var bpp, out var disc, out var tsz, out var reqs), ResultIs.FailureCode(Win32Error.ERROR_INVALID_FUNCTION));
Assert.That(SetFileBandwidthReservation(tmp.hFile, per, bpp, disc, out tsz, out reqs), ResultIs.FailureCode(Win32Error.ERROR_INVALID_FUNCTION));
}
}
[Test]
public void MoveFileExTest()
{
string newFld = TestCaseSources.TempChildDir;
Assert.That(MoveFileEx(fn, Path.Combine(newFld, Path.GetFileName(fn)), MOVEFILE.MOVEFILE_REPLACE_EXISTING), ResultIs.Successful);
Assert.That(MoveFileEx(Path.Combine(newFld, Path.GetFileName(fn)), fn, MOVEFILE.MOVEFILE_REPLACE_EXISTING), ResultIs.Successful);
}
[Test]
public void MoveFileTest()
{
string newFld = TestCaseSources.TempChildDir;
Assert.That(MoveFile(fn, Path.Combine(newFld, Path.GetFileName(fn))), ResultIs.Successful);
Assert.That(MoveFile(Path.Combine(newFld, Path.GetFileName(fn)), fn), ResultIs.Successful);
}
[Test]
public void MoveFileWithProgressTest()
{
string newFld = TestCaseSources.TempChildDir;
var qtr = 0;
Assert.That(MoveFileWithProgress(bigfn, Path.Combine(newFld, Path.GetFileName(bigfn)), fProgress, default, MOVEFILE.MOVEFILE_REPLACE_EXISTING), ResultIs.Successful);
Assert.That(MoveFileWithProgress(Path.Combine(newFld, Path.GetFileName(bigfn)), bigfn, fProgress, default, MOVEFILE.MOVEFILE_REPLACE_EXISTING), ResultIs.Successful);
CopyProgressResult fProgress(long TotalFileSize, long TotalBytesTransferred, long StreamSize, long StreamBytesTransferred, uint dwStreamNumber, COPY_CALLBACK_REASON dwCallbackReason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData)
{
var prct = TotalBytesTransferred * 100 / TotalFileSize;
if (prct / 25 + 1 > qtr) { TestContext.WriteLine($"{++qtr}/4 Complete: {StreamSize}, {dwStreamNumber}, {dwCallbackReason}"); }
return CopyProgressResult.PROGRESS_CONTINUE;
}
}
[Test]
public void OpenFileTest()
{
var buf = OFSTRUCT.Default;
SafeHFILE hFile;
Assert.That(hFile = OpenFile(fn, ref buf, OpenFileAction.OF_READ), ResultIs.ValidHandle);
hFile.Dispose();
}
[Test]
public unsafe void ReadDirectoryChangesExWTest()
{
var newFile = Path.Combine(Path.GetDirectoryName(fn), "X.ico");
using (var hDir = CreateFile(TestCaseSources.TempDirWhack, FileAccess.GENERIC_READ, FileShare.Read, null, FileMode.Open, FileFlagsAndAttributes.FILE_FLAG_BACKUP_SEMANTICS))
using (var mem = new SafeHGlobalHandle(4096))
{
new Thread(() => { Sleep(100); DeleteFile(newFile); CopyFile(fn, newFile, false); DeleteFile(newFile); }).Start();
Assert.That(ReadDirectoryChangesExW(hDir, (IntPtr)mem, (uint)mem.Size, true, FILE_NOTIFY_CHANGE.FILE_NOTIFY_CHANGE_FILE_NAME, out var ret, null, complete, READ_DIRECTORY_NOTIFY_INFORMATION_CLASS.ReadDirectoryNotifyExtendedInformation), ResultIs.Successful);
Assert.That(ret, Is.GreaterThan(0));
var list = new List<FILE_NOTIFY_EXTENDED_INFORMATION>();
var nxt = 0U;
do
{
var i = mem.DangerousGetHandle().Offset(nxt).ToStructure<FILE_NOTIFY_EXTENDED_INFORMATION>();
i.FileName = StringHelper.GetString(mem.DangerousGetHandle().Offset(nxt + 76), CharSet.Unicode, i.FileNameLength);
nxt += i.NextEntryOffset;
list.Add(i);
} while (nxt > 0);
list.WriteValues();
}
void complete(uint dwErrorCode, uint dwNumberOfBytesTransfered, NativeOverlapped* lpOverlapped)
{
TestContext.WriteLine($"{dwErrorCode}, {dwNumberOfBytesTransfered}");
}
}
[Test]
public void ReadDirectoryChangesTest()
{
var newFile = Path.Combine(Path.GetDirectoryName(fn), "X.ico");
using (var hDir = CreateFile(TestCaseSources.TempDirWhack, FileAccess.GENERIC_READ, FileShare.Read, null, FileMode.Open, FileFlagsAndAttributes.FILE_FLAG_BACKUP_SEMANTICS))
using (var mem = new SafeHGlobalHandle(4096))
{
new Thread(() => { Sleep(100); DeleteFile(newFile); CopyFile(fn, newFile, false); DeleteFile(newFile); }).Start();
Assert.That(ReadDirectoryChanges(hDir, (IntPtr)mem, (uint)mem.Size, true, FILE_NOTIFY_CHANGE.FILE_NOTIFY_CHANGE_FILE_NAME, out var ret, IntPtr.Zero, complete), ResultIs.Successful);
Assert.That(ret, Is.GreaterThan(0));
var list = new List<FILE_NOTIFY_INFORMATION>();
var nxt = 0U;
do
{
var i = mem.DangerousGetHandle().Offset(nxt).ToStructure<FILE_NOTIFY_INFORMATION>();
i.FileName = StringHelper.GetString(mem.DangerousGetHandle().Offset(nxt + 12), CharSet.Unicode, i.FileNameLength);
nxt += i.NextEntryOffset;
list.Add(i);
} while (nxt > 0);
list.WriteValues();
}
void complete(uint dwErrorCode, uint dwNumberOfBytesTransfered, IntPtr lpOverlapped)
{
TestContext.WriteLine($"{dwErrorCode}, {dwNumberOfBytesTransfered}");
}
}
[Test]
public void ReOpenFileTest()
{
using (var tmp = new TempFile(FileAccess.GENERIC_WRITE, FileShare.Read))
{
Assert.That(tmp, ResultIs.ValidHandle);
using (var hRe = ReOpenFile(tmp.hFile, FileAccess.GENERIC_READ, FileShare.ReadWrite, 0))
Assert.That(hRe, ResultIs.ValidHandle);
}
}
[Test]
public void ReplaceFileTest()
{
Assert.That(CopyFile(fn, newfn, false), ResultIs.Successful);
Assert.That(ReplaceFile(newfn, TestCaseSources.BmpFile), ResultIs.Successful);
Assert.That(DeleteFile(newfn), ResultIs.Successful);
}
[Test]
public void SetFileCompletionNotificationModesTest()
{
using (var tmp = new TempFile(FileAccess.GENERIC_WRITE, FileShare.Read, FileMode.Create, FileFlagsAndAttributes.FILE_FLAG_OVERLAPPED))
Assert.That(SetFileCompletionNotificationModes(tmp.hFile, FILE_NOTIFICATION_MODE.FILE_SKIP_SET_EVENT_ON_HANDLE), ResultIs.Successful);
}
[Test]
public void SetFileIoOverlappedRangeTest()
{
using (var priv = new ElevPriv("SeLockMemoryPrivilege"))
using (var tmp = new TempFile(FileAccess.FILE_READ_ATTRIBUTES | FileAccess.GENERIC_READ, FileShare.Read, FileMode.Create, FileFlagsAndAttributes.FILE_FLAG_OVERLAPPED | FileFlagsAndAttributes.FILE_FLAG_NO_BUFFERING))
using (var mem = new AlignedMemory<HGlobalMemoryMethods>(1024, 1024))
Assert.That(SetFileIoOverlappedRange(tmp.hFile, mem, (uint)mem.Size), ResultIs.Failure); // Not sure why I'm having permissions problems.
}
[Test]
public void SetFileShortNameTest()
{
using (new ElevPriv("SeRestorePrivilege"))
using (var tmp = new TempFile(FileAccess.GENERIC_ALL, FileShare.ReadWrite, dwFlagsAndAttributes: FileFlagsAndAttributes.FILE_FLAG_BACKUP_SEMANTICS))
Assert.That(SetFileShortName(tmp.hFile, "SN.TXT"), ResultIs.Successful);
}
[Test]
public void SetVolumeLabelTest()
{
Assert.That(GetVolumeInformation(null, out var curName, out _, out _, out _, out _), ResultIs.Successful);
Assert.That(SetVolumeLabel(null, "TempTestVol"), ResultIs.Successful);
Assert.That(SetVolumeLabel(null, curName), ResultIs.Successful);
}
}
}