On 14.02.2017 19:21, Jonathan Doron wrote:
> Signed-off-by: Jonathan Doron <jond(a)wizery.com>
> ---
> dlls/ntdll/file.c | 29 ++++++++++++++++++++++++-
> dlls/ntdll/tests/file.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++
> include/winternl.h | 9 ++++++++
> 3 files changed, 93 insertions(+), 1 deletion(-)
I have just sent a series (patch 130340 - 130343) based on your work which implements
initial support for FileIdInformation. There are some tasks left, however I believe it
is easier for all of us, when the basic stuff is already upstream, and we only have to
discuss about the missing pieces. ;)
>
> diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
> index a6c1098..182db56 100644
> --- a/dlls/ntdll/file.c
> +++ b/dlls/ntdll/file.c
> @@ -2377,7 +2377,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
> 0, /* FileRenameInformationBypassAccessCheck */
> 0, /* FileLinkInformationBypassAccessCheck */
> 0, /* FileVolumeNameInformation */
> - 0, /* FileIdInformation */
> + sizeof(FILE_ID_INFORMATION), /* FileIdInformation */
> 0, /* FileIdExtdDirectoryInformation */
> 0, /* FileReplaceCompletionInformation */
> 0, /* FileHardLinkFullIdInformation */
> @@ -2619,6 +2619,33 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE hFile, PIO_STATUS_BLOCK io,
> }
> }
> break;
> + case FileIdInformation:
> + {
> + if (fstat(fd, &st) == -1)
> + {
> + io->u.Status = FILE_GetNtStatus();
> + }
> + else
> + {
> + FILE_ID_INFORMATION *info = ptr;
> +#if defined(HAVE_FSTATFS)
> + struct statfs volstats;
> + if (fstatfs(fd, &volstats) == -1)
> + {
> + io->u.Status = FILE_GetNtStatus();
> + break;
> + }
> +
> + memcpy(&info->VolumeSerialNumber,
> + &volstats.f_fsid,
> + min(sizeof(info->VolumeSerialNumber), sizeof(volstats.f_fsid)));
> +#else
> + memset(&info->VolumeSerialNumber, 0, sizeof(info->VolumeSerialNumber));
> +#endif
It might be fine to implement the volume serial number like that, but I believe it is
even more important that all functions return the same information. If its required for
your application, please also update kernel32 and other places where it is returned.
> + ((LARGE_INTEGER *)&info->FileId)->QuadPart = st.st_ino;
> + }
> + }
> + break;
> default:
> FIXME("Unsupported class (%d)\n", class);
> io->u.Status = STATUS_NOT_IMPLEMENTED;
> diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
> index 57d7df9..926b8f8 100644
> --- a/dlls/ntdll/tests/file.c
> +++ b/dlls/ntdll/tests/file.c
> @@ -1444,6 +1444,61 @@ static void test_file_basic_information(void)
> CloseHandle( h );
> }
>
> +static void test_file_id_information(void)
> +{
> + IO_STATUS_BLOCK io;
> + FILE_ID_INFORMATION fid1, fid2;
> + HANDLE h = INVALID_HANDLE_VALUE;
> + NTSTATUS res;
> + char path[MAX_PATH], buffer[MAX_PATH];
> +
> + GetTempPathA(MAX_PATH, path);
> + GetTempFileNameA(path, "foo", 0, buffer);
> +
> + h = CreateFileA(buffer, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
> + ok(h != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
> +
> + /* Query the temp file unique id */
> + memset(&fid1, 0, sizeof(fid1));
The memsets with same value hide that some bytes of FileId are uninitialized.
> + res = pNtQueryInformationFile(h, &io, &fid1, sizeof(fid1), FileIdInformation);
> + if (res == STATUS_NOT_IMPLEMENTED || res == STATUS_INVALID_INFO_CLASS)
> + {
> + CloseHandle(h);
> + DeleteFileA(buffer);
> + win_skip("FileIdInformation not supported\n");
> + return;
> + }
> +
> + ok(res == STATUS_SUCCESS, "can't get fid1, res %x\n", res);
> +
> + CloseHandle(h);
> +
> + h = CreateFileA(buffer, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
> + ok(h != INVALID_HANDLE_VALUE, "CreateFile error %d\n", GetLastError());
> +
> + memset(&fid2, 0, sizeof(fid2));
> + res = pNtQueryInformationFile(h, &io, &fid2, sizeof(fid2), FileIdInformation);
> + ok(res == STATUS_SUCCESS, "can't get fid2, res %x\n", res);
> +
> + /* Verify we got the same unique id for the file */
> + ok(memcmp(&fid1, &fid2, sizeof(fid1)) == 0, "file id is not unique\n");
> +
> + CloseHandle(h);
> +
> + h = create_temp_file(0);
> + ok(h != NULL, "error creating new file %d\n", GetLastError());
> +
> + memset(&fid2, 0, sizeof(fid2));
> + res = pNtQueryInformationFile(h, &io, &fid2, sizeof(fid2), FileIdInformation);
> + ok(res == STATUS_SUCCESS, "can't get new fid2, res %x\n", res);
> +
> + /* Verify we got the different unique id for the new file */
> + ok(memcmp(&fid1, &fid2, sizeof(fid1)) != 0, "file id is not unique\n");
> +
Some of those patches can probably be added again if you want. For now I have
only added a test to compare the result with GetFileInformationByHandle.
> + CloseHandle(h);
> + DeleteFileA(buffer);
> +}
> +
> static void test_file_all_information(void)
> {
> IO_STATUS_BLOCK io;
> @@ -4262,4 +4317,5 @@ START_TEST(file)
> test_file_disposition_information();
> test_query_volume_information_file();
> test_query_attribute_information_file();
> + test_file_id_information();
> }
> diff --git a/include/winternl.h b/include/winternl.h
> index 891b6a7..2f2ea86 100644
> --- a/include/winternl.h
> +++ b/include/winternl.h
> @@ -571,6 +571,15 @@ typedef struct _FILE_INTERNAL_INFORMATION {
> LARGE_INTEGER IndexNumber;
> } FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION;
>
> +typedef struct _FILE_ID_128 {
> + UCHAR Identifier[16];
> +} FILE_ID_128, *PFILE_ID_128;
> +
> +typedef struct _FILE_ID_INFORMATION {
> + ULONGLONG VolumeSerialNumber;
> + FILE_ID_128 FileId;
> +} FILE_ID_INFORMATION, *PFILE_ID_INFORMATION;
> +
> typedef struct _FILE_EA_INFORMATION {
> ULONG EaSize;
> } FILE_EA_INFORMATION, *PFILE_EA_INFORMATION;
>