From c019083240e70b52fb119dad469bb8c6cfda4ade Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Tue, 4 Dec 2012 10:40:16 +0100 Subject: [PATCH] kernel32: Implement SetFileValidData. --- configure | 1 + configure.ac | 1 + dlls/kernel32/file.c | 12 +++- dlls/kernel32/tests/file.c | 136 +++++++++++++++++++++++++++++++++++++ dlls/ntdll/file.c | 31 +++++++++ include/config.h.in | 3 + include/ddk/ntddk.h | 5 ++ include/winbase.h | 1 + 8 files changed, 188 insertions(+), 2 deletions(-) diff --git a/configure b/configure index 61f3f9a25fc..99efc84dd82 100755 --- a/configure +++ b/configure @@ -12931,6 +12931,7 @@ for ac_func in \ chsize \ dlopen \ epoll_create \ + fallocate \ ffs \ finite \ fnmatch \ diff --git a/configure.ac b/configure.ac index c8a5e0d8cd6..4c7655a7568 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 43818b033d0..73b8416aba1 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 92876e49fac..3d29b28e700 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 93695f0bd6e..1b292d4a684 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 == STATUS_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/config.h.in b/include/config.h.in index 0081c25d90d..9dc3e14b32f 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -98,6 +98,9 @@ /* Define to 1 if you have the `epoll_create' function. */ #undef HAVE_EPOLL_CREATE +/* Define to 1 if you have the `fallocate' function. */ +#undef HAVE_FALLOCATE + /* Define to 1 if you have the `ffs' function. */ #undef HAVE_FFS diff --git a/include/ddk/ntddk.h b/include/ddk/ntddk.h index df589518475..f6aef8f0a32 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 a9abb3064cd..902af923364 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);