FileStreamInformation的NtQueryInformationFile在64位中成功进行32位失败

时间:2015-11-13 14:10:45

标签: windows smb

编辑:这个问题最初是关于C ++和C#中的代码之间的行为差​​异,但事实证明这是一个红色的鲱鱼。问题已被重写,以更好地反映我遇到的问题。

我尝试使用NtQueryInformationFile函数列出SMB服务器上托管的文件的备用流。到目前为止,我编写的代码可以正常使用大多数服务器,但有时在非samba Mac OS X SMB服务器上运行时会失败。

我已将应用程序的代码缩减为可靠地再现问题的以下代码:

using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;

namespace Streams
{
    class Program
    {
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public class NETRESOURCE
        {
            public uint dwScope;
            public uint dwType;
            public uint dwDisplayType;
            public uint dwUsage;

            public string lpLocalName;
            public string lpRemoteName;
            public string lpComment;
            public string lpProvider;
        }

        [DllImport("ntdll.dll", SetLastError = false, CharSet = CharSet.Unicode)]
        public static extern uint NtQueryInformationFile(
            SafeFileHandle handle,
            IntPtr IoStatusBlock,
            IntPtr pInfoBlock,
            uint length,
            uint fileInformationClass);


        [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
        public static extern SafeFileHandle CreateFile(
            string fileName,
            uint desiredAccessMask,
            uint shareMode,
            IntPtr lpSecurityAttributes,
            uint creationDisposition,
            uint flagsAndAttributes,
            IntPtr hTemplateFile);

        [DllImport("mpr.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern uint WNetAddConnection2(NETRESOURCE netResource, [MarshalAs(UnmanagedType.LPTStr)] string password, [MarshalAs(UnmanagedType.LPTStr)] string username, uint flags);

        static void Main(string[] args)
        {
            var server = args[0];
            var username = args[1];
            var password = args[2];
            var uncPath = args[3];

            NETRESOURCE netResource = new NETRESOURCE();
            netResource.dwType = 0x1 /* DISK */;
            netResource.lpRemoteName = server;
            WNetAddConnection2(netResource, password, username, 0x00000004 /* CONNECT_TEMPORARY */);

            var fh = CreateFile(
                uncPath,
                0x80000000 /* GENERIC_READ */,
                (uint)(FileShare.Read | FileShare.Write | FileShare.Delete), 
                IntPtr.Zero,
                3 /* OPEN_EXISTING */,
                0x08000000 /* SequentialScan */ | 0x02000000 /* BackupSemantics */, 
                IntPtr.Zero
                );

            IntPtr status = Marshal.AllocHGlobal(1024);
            uint bufferSize = 64*1024;
            IntPtr buffer = Marshal.AllocHGlobal((int)bufferSize);

            uint ntStatus = NtQueryInformationFile(fh, status, buffer, bufferSize, 22 /* FileStreamInformation */);

            Console.WriteLine($"NtQueryFileInformation returned {ntStatus}");
            Console.ReadKey();
        }
    }
}

在大多数情况下,ntStatus的值是STATUS_OK,如预期的那样。当我尝试在具有Mac OS X SMB服务器的备用数据流的文件上使用它时,我得到STATUS_INVALID_NETWORK_RESPONSE。该错误代码似乎表明来自服务器的响应不正确,但是当我使用Wireshark进行检查时,与返回STATUS_OK时相比没有差异。

为了使事情变得更奇怪,当我以32位模式运行它时,此代码有效(在Visual Studio项目设置中设置'首选32位')。在64位模式下运行时,我总是得到错误代码。 那么明显的错误就是所讨论的代码不是64位干净,而是AFAICT上面的代码。

我也尝试用GetFileInformationByHandleEx调用替换NtQueryInformationFile调用,但这给了我相同的结果(当然使用Win32错误代码而不是NT状态代码)。

什么可以解释32位和64位模式之间的行为差​​异?

0 个答案:

没有答案