From 68b654ad2fe18aad6b9b0d0128656753f6639442 Mon Sep 17 00:00:00 2001 From: Martin Storsjo Date: Wed, 20 May 2015 20:44:56 +0300 Subject: [PATCH] kernel32: Implement a few more classes in GetFileInformationByHandleEx. --- dlls/kernel32/file.c | 31 ++++++++-------- dlls/kernel32/tests/file.c | 72 ++++++++++++++++++++++++++++++++++++-- include/winbase.h | 21 +++++++++++ 3 files changed, 107 insertions(+), 17 deletions(-) diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c index 006db1c207e..a680ab2ff14 100644 --- a/dlls/kernel32/file.c +++ b/dlls/kernel32/file.c @@ -897,8 +897,6 @@ BOOL WINAPI GetFileInformationByHandleEx( HANDLE handle, FILE_INFO_BY_HANDLE_CLA switch (class) { - case FileBasicInfo: - case FileStandardInfo: case FileRenameInfo: case FileDispositionInfo: case FileAllocationInfo: @@ -919,31 +917,36 @@ BOOL WINAPI GetFileInformationByHandleEx( HANDLE handle, FILE_INFO_BY_HANDLE_CLA SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); return FALSE; + case FileBasicInfo: + status = NtQueryInformationFile( handle, &io, info, size, FileBasicInformation ); + break; + + case FileStandardInfo: + status = NtQueryInformationFile( handle, &io, info, size, FileStandardInformation ); + break; + case FileNameInfo: status = NtQueryInformationFile( handle, &io, info, size, FileNameInformation ); - if (status != STATUS_SUCCESS) - { - SetLastError( RtlNtStatusToDosError( status ) ); - return FALSE; - } - return TRUE; + break; case FileIdBothDirectoryRestartInfo: case FileIdBothDirectoryInfo: status = NtQueryDirectoryFile( handle, NULL, NULL, NULL, &io, info, size, FileIdBothDirectoryInformation, FALSE, NULL, (class == FileIdBothDirectoryRestartInfo) ); - if (status != STATUS_SUCCESS) - { - SetLastError( RtlNtStatusToDosError( status ) ); - return FALSE; - } - return TRUE; + break; default: SetLastError( ERROR_INVALID_PARAMETER ); return FALSE; } + + if (status != STATUS_SUCCESS) + { + SetLastError( RtlNtStatusToDosError( status ) ); + return FALSE; + } + return TRUE; } diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c index 64b0b8b0264..bd85e01fdd9 100644 --- a/dlls/kernel32/tests/file.c +++ b/dlls/kernel32/tests/file.c @@ -3821,11 +3821,15 @@ else static void test_GetFileInformationByHandleEx(void) { int i; - char tempPath[MAX_PATH], tempFileName[MAX_PATH], buffer[1024]; + char tempPath[MAX_PATH], tempFileName[MAX_PATH], buffer[1024], *strPtr; BOOL ret; - DWORD ret2; - HANDLE directory; + DWORD ret2, written; + HANDLE directory, file; FILE_ID_BOTH_DIR_INFO *bothDirInfo; + FILE_BASIC_INFO *basicInfo; + FILE_STANDARD_INFO *standardInfo; + FILE_NAME_INFO *nameInfo; + LARGE_INTEGER prevWrite; struct { FILE_INFO_BY_HANDLE_CLASS handleClass; void *ptr; @@ -3888,6 +3892,68 @@ static void test_GetFileInformationByHandleEx(void) } CloseHandle(directory); + + file = CreateFileA(tempFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "GetFileInformationByHandleEx: failed to open the temp file, " + "got error %u.\n", GetLastError()); + + /* Test FileBasicInfo; make sure the write time changes when a file is updated */ + memset(buffer, 0xff, sizeof(buffer)); + ret = pGetFileInformationByHandleEx(file, FileBasicInfo, buffer, sizeof(buffer)); + ok(ret, "GetFileInformationByHandleEx: failed to get FileBasicInfo, %u\n", GetLastError()); + basicInfo = (FILE_BASIC_INFO *)buffer; + prevWrite = basicInfo->LastWriteTime; + CloseHandle(file); + + Sleep(30); /* Make sure a new write time is different from the previous */ + + /* Write something to the file, to make sure the write time has changed */ + file = CreateFileA(tempFileName, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "GetFileInformationByHandleEx: failed to open the temp file, " + "got error %u.\n", GetLastError()); + ret = WriteFile(file, tempFileName, strlen(tempFileName), &written, NULL); + ok(ret, "GetFileInformationByHandleEx: Write failed\n"); + CloseHandle(file); + + file = CreateFileA(tempFileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, 0, NULL); + ok(file != INVALID_HANDLE_VALUE, "GetFileInformationByHandleEx: failed to open the temp file, " + "got error %u.\n", GetLastError()); + + memset(buffer, 0xff, sizeof(buffer)); + ret = pGetFileInformationByHandleEx(file, FileBasicInfo, buffer, sizeof(buffer)); + ok(ret, "GetFileInformationByHandleEx: failed to get FileBasicInfo, %u\n", GetLastError()); + basicInfo = (FILE_BASIC_INFO *)buffer; + /* Could also check that the creation time didn't change - on windows + * it doesn't, but on wine, it does change even if it shouldn't. */ + ok(basicInfo->LastWriteTime.QuadPart != prevWrite.QuadPart, + "GetFileInformationByHandleEx: last write time didn't change\n"); + + /* Test FileStandardInfo, check some basic parameters */ + memset(buffer, 0xff, sizeof(buffer)); + ret = pGetFileInformationByHandleEx(file, FileStandardInfo, buffer, sizeof(buffer)); + ok(ret, "GetFileInformationByHandleEx: failed to get FileStandardInfo, %u\n", GetLastError()); + standardInfo = (FILE_STANDARD_INFO *)buffer; + ok(standardInfo->NumberOfLinks == 1, "GetFileInformationByHandleEx: Unexpcted number of links\n"); + ok(standardInfo->DeletePending == FALSE, "GetFileInformationByHandleEx: Unexpcted pending delete\n"); + ok(standardInfo->Directory == FALSE, "GetFileInformationByHandleEx: Incorrect directory flag\n"); + + /* Test FileNameInfo */ + memset(buffer, 0xff, sizeof(buffer)); + ret = pGetFileInformationByHandleEx(file, FileNameInfo, buffer, sizeof(buffer)); + ok(ret, "GetFileInformationByHandleEx: failed to get FileNameInfo, %u\n", GetLastError()); + nameInfo = (FILE_NAME_INFO *)buffer; + strPtr = strchr(tempFileName, '\\'); + ok(strPtr != NULL, "GetFileInformationByHandleEx: Temp filename didn't contain backslash\n"); + ok(nameInfo->FileNameLength == strlen(strPtr) * 2, + "GetFileInformationByHandleEx: Incorrect file name length\n"); + for (i = 0; i < nameInfo->FileNameLength/2; i++) + ok(strPtr[i] == nameInfo->FileName[i], "Incorrect filename char %d: %c vs %c\n", + i, strPtr[i], nameInfo->FileName[i]); + CloseHandle(file); + DeleteFileA(tempFileName); } diff --git a/include/winbase.h b/include/winbase.h index 7540e6d558f..3601051d518 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -823,6 +823,27 @@ typedef struct _FILE_ID_BOTH_DIR_INFO { WCHAR FileName[1]; } FILE_ID_BOTH_DIR_INFO, *PFILE_ID_BOTH_DIR_INFO; +typedef struct _FILE_BASIC_INFO { + LARGE_INTEGER CreationTime; + LARGE_INTEGER LastAccessTime; + LARGE_INTEGER LastWriteTime; + LARGE_INTEGER ChangeTime; + DWORD FileAttributes; +} FILE_BASIC_INFO, *PFILE_BASIC_INFO; + +typedef struct _FILE_STANDARD_INFO { + LARGE_INTEGER AllocationSize; + LARGE_INTEGER EndOfFile; + DWORD NumberOfLinks; + BOOLEAN DeletePending; + BOOLEAN Directory; +} FILE_STANDARD_INFO, *PFILE_STANDARD_INFO; + +typedef struct _FILE_NAME_INFO { + DWORD FileNameLength; + WCHAR FileName[1]; +} FILE_NAME_INFO, *PFILE_NAME_INFO; + #define PIPE_ACCESS_INBOUND 1 #define PIPE_ACCESS_OUTBOUND 2 #define PIPE_ACCESS_DUPLEX 3