kernel32: Implement SetFileValidData. (try 3)

Hans Leidekker hans at codeweavers.com
Tue Dec 4 03:40:16 CST 2012


This version should pass the tests on systems where fallocate is present
but the filesystem doesn't support it.
---
 configure.ac               |    1 +
 dlls/kernel32/file.c       |   12 +++-
 dlls/kernel32/tests/file.c |  136 ++++++++++++++++++++++++++++++++++++++++++++
 dlls/ntdll/file.c          |   31 ++++++++++
 include/ddk/ntddk.h        |    5 ++
 include/winbase.h          |    1 +
 6 files changed, 184 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index c8a5e0d..4c7655a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1976,6 +1976,7 @@ AC_CHECK_FUNCS(\
 	chsize \
 	dlopen \
 	epoll_create \
+	fallocate \
 	ffs \
 	finite \
 	fnmatch \
diff --git a/dlls/kernel32/file.c b/dlls/kernel32/file.c
index 43818b0..73b8416 100644
--- a/dlls/kernel32/file.c
+++ b/dlls/kernel32/file.c
@@ -40,6 +40,7 @@
 #include "winternl.h"
 #include "winioctl.h"
 #include "wincon.h"
+#include "ddk/ntddk.h"
 #include "kernel_private.h"
 
 #include "wine/exception.h"
@@ -1086,8 +1087,15 @@ error:
  */
 BOOL WINAPI SetFileValidData( HANDLE hFile, LONGLONG ValidDataLength )
 {
-    FIXME("stub: %p, %s\n", hFile, wine_dbgstr_longlong(ValidDataLength));
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    FILE_VALID_DATA_LENGTH_INFORMATION info;
+    IO_STATUS_BLOCK io;
+    NTSTATUS status;
+
+    info.ValidDataLength.QuadPart = ValidDataLength;
+    status = NtSetInformationFile( hFile, &io, &info, sizeof(info), FileValidDataLengthInformation );
+
+    if (status == STATUS_SUCCESS) return TRUE;
+    SetLastError( RtlNtStatusToDosError(status) );
     return FALSE;
 }
 
diff --git a/dlls/kernel32/tests/file.c b/dlls/kernel32/tests/file.c
index 92876e4..3d29b28 100644
--- a/dlls/kernel32/tests/file.c
+++ b/dlls/kernel32/tests/file.c
@@ -42,6 +42,7 @@ static BOOL (WINAPI *pGetVolumeNameForVolumeMountPointA)(LPCSTR, LPSTR, DWORD);
 static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);
 static BOOL (WINAPI *pGetFileInformationByHandleEx)(HANDLE, FILE_INFO_BY_HANDLE_CLASS, LPVOID, DWORD);
 static HANDLE (WINAPI *pOpenFileById)(HANDLE, LPFILE_ID_DESCRIPTOR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD);
+static BOOL (WINAPI *pSetFileValidData)(HANDLE, LONGLONG);
 
 /* keep filename and filenameW the same */
 static const char filename[] = "testfile.xxx";
@@ -78,6 +79,7 @@ static void InitFunctionPointers(void)
     pQueueUserAPC = (void *) GetProcAddress(hkernel32, "QueueUserAPC");
     pGetFileInformationByHandleEx = (void *) GetProcAddress(hkernel32, "GetFileInformationByHandleEx");
     pOpenFileById = (void *) GetProcAddress(hkernel32, "OpenFileById");
+    pSetFileValidData = (void *) GetProcAddress(hkernel32, "SetFileValidData");
 }
 
 static void test__hread( void )
@@ -3438,6 +3440,139 @@ static void test_OpenFileById(void)
     DeleteFile(tempFileName);
 }
 
+static void test_SetFileValidData(void)
+{
+    BOOL ret;
+    HANDLE handle;
+    DWORD error, count;
+    char path[MAX_PATH], filename[MAX_PATH];
+    TOKEN_PRIVILEGES privs;
+    HANDLE token = NULL;
+
+    if (!pSetFileValidData)
+    {
+        win_skip("SetFileValidData is missing\n");
+        return;
+    }
+    GetTempPathA(sizeof(path), path);
+    GetTempFileNameA(path, "tst", 0, filename);
+    handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+    WriteFile(handle, "test", sizeof("test") - 1, &count, NULL);
+    CloseHandle(handle);
+
+    SetLastError(0xdeadbeef);
+    ret = pSetFileValidData(INVALID_HANDLE_VALUE, 0);
+    error = GetLastError();
+    ok(!ret, "SetFileValidData succeeded\n");
+    ok(error == ERROR_INVALID_HANDLE, "got %u\n", error);
+
+    SetLastError(0xdeadbeef);
+    ret = pSetFileValidData(INVALID_HANDLE_VALUE, -1);
+    error = GetLastError();
+    ok(!ret, "SetFileValidData succeeded\n");
+    ok(error == ERROR_INVALID_HANDLE, "got %u\n", error);
+
+    /* file opened for reading */
+    handle = CreateFileA(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+    SetLastError(0xdeadbeef);
+    ret = pSetFileValidData(handle, 0);
+    ok(!ret, "SetFileValidData succeeded\n");
+    error = GetLastError();
+    ok(error == ERROR_ACCESS_DENIED, "got %u\n", error);
+
+    SetLastError(0xdeadbeef);
+    ret = pSetFileValidData(handle, -1);
+    error = GetLastError();
+    ok(!ret, "SetFileValidData succeeded\n");
+    ok(error == ERROR_ACCESS_DENIED, "got %u\n", error);
+    CloseHandle(handle);
+
+    handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+    SetLastError(0xdeadbeef);
+    ret = pSetFileValidData(handle, 0);
+    error = GetLastError();
+    ok(!ret, "SetFileValidData succeeded\n");
+    todo_wine ok(error == ERROR_PRIVILEGE_NOT_HELD, "got %u\n", error);
+    CloseHandle(handle);
+
+    privs.PrivilegeCount = 1;
+    privs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+    if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token) ||
+        !LookupPrivilegeValue(NULL, SE_MANAGE_VOLUME_NAME, &privs.Privileges[0].Luid) ||
+        !AdjustTokenPrivileges(token, FALSE, &privs, sizeof(privs), NULL, NULL))
+    {
+        win_skip("cannot enable SE_MANAGE_VOLUME_NAME privilege\n");
+        CloseHandle(token);
+        return;
+    }
+    handle = CreateFileA(filename, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+    SetLastError(0xdeadbeef);
+    ret = pSetFileValidData(handle, 0);
+    error = GetLastError();
+    ok(!ret, "SetFileValidData succeeded\n");
+    ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error);
+
+    SetLastError(0xdeadbeef);
+    ret = pSetFileValidData(handle, -1);
+    error = GetLastError();
+    ok(!ret, "SetFileValidData succeeded\n");
+    ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error);
+
+    SetLastError(0xdeadbeef);
+    ret = pSetFileValidData(handle, 2);
+    error = GetLastError();
+    todo_wine ok(!ret, "SetFileValidData succeeded\n");
+    todo_wine ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error);
+
+    ret = pSetFileValidData(handle, 4);
+    ok(ret, "SetFileValidData failed %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pSetFileValidData(handle, 8);
+    error = GetLastError();
+    ok(!ret, "SetFileValidData succeeded\n");
+    ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error);
+
+    count = SetFilePointer(handle, 1024, NULL, FILE_END);
+    ok(count != INVALID_SET_FILE_POINTER, "SetFilePointer failed %u\n", GetLastError());
+    ret = SetEndOfFile(handle);
+    ok(ret, "SetEndOfFile failed %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pSetFileValidData(handle, 2);
+    error = GetLastError();
+    todo_wine ok(!ret, "SetFileValidData succeeded\n");
+    todo_wine ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error);
+
+    ret = pSetFileValidData(handle, 4);
+    ok(ret, "SetFileValidData failed %u\n", GetLastError());
+
+    ret = pSetFileValidData(handle, 8);
+    ok(ret, "SetFileValidData failed %u\n", GetLastError());
+
+    ret = pSetFileValidData(handle, 4);
+    error = GetLastError();
+    todo_wine ok(!ret, "SetFileValidData succeeded\n");
+    todo_wine ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error);
+
+    ret = pSetFileValidData(handle, 1024);
+    ok(ret, "SetFileValidData failed %u\n", GetLastError());
+
+    ret = pSetFileValidData(handle, 2048);
+    error = GetLastError();
+    ok(!ret, "SetFileValidData succeeded\n");
+    ok(error == ERROR_INVALID_PARAMETER, "got %u\n", error);
+
+    privs.Privileges[0].Attributes = 0;
+    AdjustTokenPrivileges(token, FALSE, &privs, sizeof(privs), NULL, NULL);
+    CloseHandle(token);
+    DeleteFile(filename);
+}
+
 START_TEST(file)
 {
     InitFunctionPointers();
@@ -3479,4 +3614,5 @@ START_TEST(file)
     test_ReplaceFileW();
     test_GetFileInformationByHandleEx();
     test_OpenFileById();
+    test_SetFileValidData();
 }
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 93695f0..54401b1 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -81,6 +81,7 @@
 
 #include "winternl.h"
 #include "winioctl.h"
+#include "ddk/ntddk.h"
 #include "ddk/ntddser.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
@@ -2245,6 +2246,36 @@ NTSTATUS WINAPI NtSetInformationFile(HANDLE handle, PIO_STATUS_BLOCK io,
         io->u.Status = STATUS_INVALID_INFO_CLASS;
         break;
 
+    case FileValidDataLengthInformation:
+        if (len >= sizeof(FILE_VALID_DATA_LENGTH_INFORMATION))
+        {
+            struct stat st;
+            const FILE_VALID_DATA_LENGTH_INFORMATION *info = ptr;
+
+            if ((io->u.Status = server_get_unix_fd( handle, FILE_WRITE_DATA, &fd, &needs_close, NULL, NULL )))
+                return io->u.Status;
+
+            if (fstat( fd, &st ) == -1) io->u.Status = FILE_GetNtStatus();
+            else if (info->ValidDataLength.QuadPart <= 0 || (off_t)info->ValidDataLength.QuadPart > st.st_size)
+                io->u.Status = STATUS_INVALID_PARAMETER;
+            else
+            {
+#ifdef HAVE_FALLOCATE
+                if (fallocate( fd, 0, 0, (off_t)info->ValidDataLength.QuadPart ) == -1)
+                {
+                    NTSTATUS status = FILE_GetNtStatus();
+                    if (status == ERROR_NOT_SUPPORTED) WARN( "fallocate not supported on this filesystem\n" );
+                    else io->u.Status = status;
+                }
+#else
+                FIXME( "setting valid data length not supported\n" );
+#endif
+            }
+            if (needs_close) close( fd );
+        }
+        else io->u.Status = STATUS_INVALID_PARAMETER_3;
+        break;
+
     default:
         FIXME("Unsupported class (%d)\n", class);
         io->u.Status = STATUS_NOT_IMPLEMENTED;
diff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.h
index df58951..f6aef8f 100644
--- a/include/ddk/ntddk.h
+++ b/include/ddk/ntddk.h
@@ -127,6 +127,11 @@ typedef struct _IMAGE_INFO
     ULONG  ImageSectionNumber;
 } IMAGE_INFO, *PIMAGE_INFO;
 
+typedef struct _FILE_VALID_DATA_LENGTH_INFORMATION
+{
+  LARGE_INTEGER ValidDataLength;
+} FILE_VALID_DATA_LENGTH_INFORMATION, *PFILE_VALID_DATA_LENGTH_INFORMATION;
+
 typedef VOID (WINAPI *PDRIVER_REINITIALIZE)(PDRIVER_OBJECT,PVOID,ULONG);
 typedef VOID (WINAPI *PLOAD_IMAGE_NOTIFY_ROUTINE)(PUNICODE_STRING,HANDLE,PIMAGE_INFO);
 typedef NTSTATUS (WINAPI *PIO_QUERY_DEVICE_ROUTINE)(PVOID,PUNICODE_STRING,INTERFACE_TYPE,ULONG,
diff --git a/include/winbase.h b/include/winbase.h
index a9abb30..902af92 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -2188,6 +2188,7 @@ WINADVAPI  BOOL        WINAPI SetFileSecurityA(LPCSTR,SECURITY_INFORMATION,PSECU
 WINADVAPI  BOOL        WINAPI SetFileSecurityW(LPCWSTR,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
 #define                       SetFileSecurity WINELIB_NAME_AW(SetFileSecurity)
 WINBASEAPI BOOL        WINAPI SetFileTime(HANDLE,const FILETIME*,const FILETIME*,const FILETIME*);
+WINBASEAPI BOOL        WINAPI SetFileValidData(HANDLE,LONGLONG);
 WINBASEAPI UINT        WINAPI SetHandleCount(UINT);
 WINBASEAPI BOOL        WINAPI SetHandleInformation(HANDLE,DWORD,DWORD);
 WINBASEAPI BOOL        WINAPI SetInformationJobObject(HANDLE,JOBOBJECTINFOCLASS,LPVOID,DWORD);
-- 
1.7.10.4






More information about the wine-patches mailing list