Skip to content

Commit

Permalink
QueryDirectoryFile requires 64 bit alignment to work on ARM32. (dotne…
Browse files Browse the repository at this point in the history
…t/corefx#33713)

* QueryDirectoryFile requires 64 bit alignment to work on ARM32. Using Marshal.AllocHGlobal instead of byte[] will do that (and avoid the need to pin).

* Address feedback.


Commit migrated from dotnet/corefx@a75f96a
  • Loading branch information
JeremyKuhne authored Nov 29, 2018
1 parent ad66b62 commit 07cbca2
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public unsafe static extern int NtQueryDirectoryFile(
IntPtr ApcRoutine,
IntPtr ApcContext,
out IO_STATUS_BLOCK IoStatusBlock,
byte[] FileInformation,
IntPtr FileInformation,
uint Length,
FILE_INFORMATION_CLASS FileInformationClass,
BOOLEAN ReturnSingleEntry,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ internal partial class Kernel32
{
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa364953.aspx
[DllImport(Libraries.Kernel32, SetLastError = true, CharSet = CharSet.Unicode, ExactSpelling = true)]
public unsafe static extern bool GetFileInformationByHandleEx(
public static extern bool GetFileInformationByHandleEx(
IntPtr hFile,
FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
byte[] lpFileInformation,
IntPtr lpFileInformation,
uint dwBufferSize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ private unsafe bool GetData()
ApcContext: IntPtr.Zero,
IoStatusBlock: out Interop.NtDll.IO_STATUS_BLOCK statusBlock,
FileInformation: _buffer,
Length: (uint)_buffer.Length,
Length: (uint)_bufferLength,
FileInformationClass: Interop.NtDll.FILE_INFORMATION_CLASS.FileFullDirectoryInformation,
ReturnSingleEntry: Interop.BOOLEAN.FALSE,
FileName: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ private unsafe bool GetData()
_directoryHandle,
Interop.Kernel32.FILE_INFO_BY_HANDLE_CLASS.FileFullDirectoryInfo,
_buffer,
(uint)_buffer.Length))
(uint)_bufferLength))
{
int error = Marshal.GetLastWin32Error();
switch (error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ public unsafe abstract partial class FileSystemEnumerator<TResult> : CriticalFin
private Interop.NtDll.FILE_FULL_DIR_INFORMATION* _entry;
private TResult _current;

private byte[] _buffer;
private IntPtr _buffer;
private int _bufferLength;
private IntPtr _directoryHandle;
private string _currentPath;
private bool _lastEntryFound;
private Queue<(IntPtr Handle, string Path)> _pending;
private GCHandle _pinnedBuffer;

/// <summary>
/// Encapsulates a find operation.
Expand Down Expand Up @@ -67,13 +67,15 @@ public FileSystemEnumerator(string directory, EnumerationOptions options = null)
_currentPath = _rootDirectory;

int requestedBufferSize = _options.BufferSize;
int bufferSize = requestedBufferSize <= 0 ? StandardBufferSize
_bufferLength = requestedBufferSize <= 0 ? StandardBufferSize
: Math.Max(MinimumBufferSize, requestedBufferSize);

try
{
_buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
_pinnedBuffer = GCHandle.Alloc(_buffer, GCHandleType.Pinned);
// NtQueryDirectoryFile needs its buffer to be 64bit aligned to work
// successfully with FileFullDirectoryInformation on ARM32. AllocHGlobal
// will return pointers aligned as such, new byte[] does not.
_buffer = Marshal.AllocHGlobal(_bufferLength);
}
catch
{
Expand Down Expand Up @@ -209,7 +211,7 @@ private unsafe void FindNextEntry()

// We need more data
if (GetData())
_entry = (Interop.NtDll.FILE_FULL_DIR_INFORMATION*)_pinnedBuffer.AddrOfPinnedObject();
_entry = (Interop.NtDll.FILE_FULL_DIR_INFORMATION*)_buffer;
}

private bool DequeueNextDirectory()
Expand Down Expand Up @@ -239,13 +241,12 @@ private void InternalDispose(bool disposing)
_pending = null;
}

if (_pinnedBuffer.IsAllocated)
_pinnedBuffer.Free();

if (_buffer != null)
ArrayPool<byte>.Shared.Return(_buffer);
if (_buffer != default)
{
Marshal.FreeHGlobal(_buffer);
}

_buffer = null;
_buffer = default;
}
}

Expand Down

0 comments on commit 07cbca2

Please sign in to comment.