dahall / Vanara

A set of .NET libraries for Windows implementing PInvoke calls to many native Windows APIs with supporting wrappers.
MIT License
1.75k stars 190 forks source link

Kernel32.FILE_ID_128.Identifier returns incorrect values #427

Closed B-Hulse closed 10 months ago

B-Hulse commented 10 months ago

Describe the bug and how to reproduce

When using GetFileInformationByHandleEx to query the FILE_ID_INFO of a file, the returned FILE_ID_INFO reports the incorrect File ID if you use the Identifier getter of the FILE_ID_128 member.

This is a code sample from a command line exe that will report the File ID of a given file.

if (args.Length != 1)
{
    Console.WriteLine("No file path provided");
    return;
}

string fileName = args[0];

var fHandle = CreateFile(fileName, FileAccess.FILE_GENERIC_READ, FileShare.None, null, FileMode.Open, 0, IntPtr.Zero);
var fileIdInfo = GetFileInformationByHandleEx<FILE_ID_INFO>(fHandle, FILE_INFO_BY_HANDLE_CLASS.FileIdInfo);

Console.WriteLine("File ID: {0}", string.Join(", ", fileIdInfo.FileId.Identifier));
Console.WriteLine("Volume Serial Number: {0}", fileIdInfo.VolumeSerialNumber);

In a debugger the private members id0 and id1, which represent the low and high bits of the 128 bit identifier, are set as expected. These values are correct for the File ID of the file in question. But Identifier is showing that the high bits (id1) have values other than 0. image

What code is involved

Vanara.PInvoke.Kernel32.FILE_ID_128.Identifier getter.

/// <summary>
/// <para>Defines a 128-bit file identifier.</para>
/// </summary>
// https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_file_id_128 typedef struct _FILE_ID_128 { BYTE
// Identifier[16]; } FILE_ID_128, *PFILE_ID_128;
[PInvokeData("winnt.h", MSDNShortId = "254ea6a9-e1dd-4b97-91f7-2693065c4bb8")]
[StructLayout(LayoutKind.Sequential)]
public struct FILE_ID_128
{
    private readonly ulong id0;
    private readonly ulong id1;

    /// <summary>
    /// <para>A byte array containing the 128 bit identifier.</para>
    /// </summary>
    public byte[] Identifier
    {
        get
        {
            using PinnedObject pin = new(id0);
            return ((IntPtr)pin).ToArray<byte>(16);
        }
        set
        {
        using PinnedObject pin = new(id0);
        Marshal.Copy(value, 0, pin, 16);
        }
    }
}

Expected behavior

The value returned by FILE_ID_128.Identifier should be an array of 16 bytes, where the first 8 are the byte representation of id0 and the later 8 bytes are the byte representation of id1.