1 /*
2  * PROJECT:         ReactOS api tests
3  * LICENSE:         GPLv2+ - See COPYING in the top level directory
4  * PURPOSE:         Test for PrivMoveFileIdentityW
5  * PROGRAMMER:      Pierre Schweitzer <pierre@reactos.org>
6  */
7 
8 #include "precomp.h"
9 
10 #include <ndk/iofuncs.h>
11 
12 static const WCHAR FileName[] = L"TestFile.xxx";
13 static const CHAR FileNameA[] = "TestFile.xxx";
14 static const WCHAR FileName2[] = L"TestFile2.xxx";
15 
16 static BOOL (WINAPI * pPrivMoveFileIdentityW)(LPCWSTR, LPCWSTR, DWORD);
17 
18 static
19 BOOL
20 QueryFileInfo(
21     LPCWSTR File,
22     PFILE_BASIC_INFORMATION FileBasicInfo,
23     PFILE_STANDARD_INFORMATION FileStandardInfo)
24 {
25     HANDLE hFile;
26     IO_STATUS_BLOCK IoStatusBlock;
27     NTSTATUS Status;
28 
29     hFile = CreateFileW(File, FILE_READ_ATTRIBUTES | SYNCHRONIZE,
30                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
31                         OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_SYNCHRONOUS_IO_NONALERT,
32                         NULL);
33     if (hFile == INVALID_HANDLE_VALUE)
34     {
35         return FALSE;
36     }
37 
38     Status = NtQueryInformationFile(hFile, &IoStatusBlock, FileBasicInfo,
39                                     sizeof(FILE_BASIC_INFORMATION), FileBasicInformation);
40     if (!NT_SUCCESS(Status))
41     {
42         CloseHandle(hFile);
43         return FALSE;
44     }
45 
46     Status = NtQueryInformationFile(hFile, &IoStatusBlock, FileStandardInfo,
47                                     sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation);
48 
49     CloseHandle(hFile);
50     return NT_SUCCESS(Status);
51 }
52 
53 static
54 VOID
55 TestPrivMoveFileIdentityW(VOID)
56 {
57     FILE_BASIC_INFORMATION FileBasicInfo;
58     FILE_STANDARD_INFORMATION FileStandardInfo;
59     LARGE_INTEGER CreationTime, EndOfFile;
60     HANDLE hDest;
61     WCHAR Self[MAX_PATH];
62     OFSTRUCT ReOpen;
63     BOOL Ret;
64 
65     DeleteFileW(FileName);
66     DeleteFileW(FileName2);
67 
68     if (GetModuleFileNameW(NULL, Self, MAX_PATH) == 0)
69     {
70         win_skip("Failed finding self\n");
71         return;
72     }
73 
74     if (!QueryFileInfo(Self, &FileBasicInfo, &FileStandardInfo))
75     {
76         win_skip("Failed querying self\n");
77         return;
78     }
79 
80     CreationTime = FileBasicInfo.CreationTime;
81     EndOfFile = FileStandardInfo.EndOfFile;
82 
83     Sleep(150);
84 
85     hDest = CreateFileW(FileName, GENERIC_WRITE | SYNCHRONIZE,
86                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
87                         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_SYNCHRONOUS_IO_NONALERT,
88                         NULL);
89     if (hDest == INVALID_HANDLE_VALUE)
90     {
91         win_skip("Failed creating new\n");
92         return;
93     }
94 
95     CloseHandle(hDest);
96 
97     ok(QueryFileInfo(FileName, &FileBasicInfo, &FileStandardInfo) == TRUE, "QueryFileInfo returned FALSE\n");
98     ok(FileBasicInfo.CreationTime.QuadPart != CreationTime.QuadPart, "Equal creation times\n");
99     ok(FileStandardInfo.EndOfFile.QuadPart == 0LL, "File wasn't created empty: %I64d\n", FileStandardInfo.EndOfFile.QuadPart);
100     SetLastError(0xdeadbeef);
101     Ret = pPrivMoveFileIdentityW(Self, FileName, 0);
102     ok(Ret == FALSE, "PrivMoveFileIdentityW succeeded unexpectedly\n");
103     ok(GetLastError() == ERROR_SHARING_VIOLATION, "Last error: %#lx\n", GetLastError());
104     ok(QueryFileInfo(FileName, &FileBasicInfo, &FileStandardInfo) == TRUE, "QueryFileInfo returned FALSE\n");
105     ok(FileBasicInfo.CreationTime.QuadPart != CreationTime.QuadPart, "Equal creation times\n");
106     ok(FileStandardInfo.EndOfFile.QuadPart == 0LL, "File wasn't created empty: %I64d\n", FileStandardInfo.EndOfFile.QuadPart);
107     SetLastError(0xdeadbeef);
108     Ret = pPrivMoveFileIdentityW(Self, FileName, 2);
109     ok(Ret == TRUE, "PrivMoveFileIdentityW failed with %#lx\n", GetLastError());
110     ok(QueryFileInfo(FileName, &FileBasicInfo, &FileStandardInfo) == TRUE, "QueryFileInfo returned FALSE\n");
111     ok(FileBasicInfo.CreationTime.QuadPart == CreationTime.QuadPart, "Creation time didn't change\n");
112     ok(FileStandardInfo.EndOfFile.QuadPart == 0LL, "File not empty anymore: %I64d\n", FileStandardInfo.EndOfFile.QuadPart);
113     ok(QueryFileInfo(Self, &FileBasicInfo, &FileStandardInfo) == TRUE, "QueryFileInfo returned FALSE\n");
114     ok(FileBasicInfo.CreationTime.QuadPart == CreationTime.QuadPart, "Creation time changed\n");
115     ok(FileStandardInfo.EndOfFile.QuadPart == EndOfFile.QuadPart, "File size changed: %I64d\n", FileStandardInfo.EndOfFile.QuadPart);
116 
117     hDest = CreateFileW(FileName2, GENERIC_WRITE | SYNCHRONIZE,
118                         FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
119                         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_SYNCHRONOUS_IO_NONALERT,
120                         NULL);
121     if (hDest == INVALID_HANDLE_VALUE)
122     {
123         win_skip("Failed creating new\n");
124         return;
125     }
126 
127     CloseHandle(hDest);
128 
129     ok(QueryFileInfo(FileName2, &FileBasicInfo, &FileStandardInfo) == TRUE, "QueryFileInfo returned FALSE\n");
130     ok(FileBasicInfo.CreationTime.QuadPart != CreationTime.QuadPart, "Equal creation times\n");
131     SetLastError(0xdeadbeef);
132     Ret = pPrivMoveFileIdentityW(FileName, FileName2, 3);
133     ok(Ret == TRUE, "PrivMoveFileIdentityW failed with %#lx\n", GetLastError());
134     ok(QueryFileInfo(FileName2, &FileBasicInfo, &FileStandardInfo) == TRUE, "QueryFileInfo returned FALSE\n");
135     ok(FileBasicInfo.CreationTime.QuadPart == CreationTime.QuadPart, "Creation time didn't change\n");
136     ok(OpenFile(FileNameA, &ReOpen, OF_EXIST) == HFILE_ERROR, "Source file still exists\n");
137 
138     DeleteFileW(FileName2);
139     DeleteFileW(FileName);
140 }
141 
142 START_TEST(PrivMoveFileIdentityW)
143 {
144     HMODULE hKern = GetModuleHandleA("kernel32.dll");
145     pPrivMoveFileIdentityW = (void *)GetProcAddress(hKern, "PrivMoveFileIdentityW");
146 
147     TestPrivMoveFileIdentityW();
148 }
149