[PATCH] kernel32: Implement a few more classes in GetFileInformationByHandleEx

Martin Storsjo martin at martin.st
Wed May 20 12:44:56 CDT 2015


Implement FileBasicInfo and FileStandardInfo. The common error handling
within the function is factorized and shared.

Also add tests tests for them, and for FileNameInfo. Using these
classes requires adding the right structs in winbase.h (even though
the implementation of GetFileInformationByHandleEx don't use them).
These structs are equal to the corresponding ones on the ntdll level,
that already exist.

The tests do some rudimentary but not exhaustive checks of the behaviour
of these info structs.
---
Changed comments to use /* */ instead of //, wrapped some very
long lines in the test.
---
 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 006db1c..a680ab2 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 64b0b8b..bd85e01 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 7540e6d..3601051 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
-- 
1.8.1.2




More information about the wine-patches mailing list