1 /*
2  * PROJECT:         ReactOS API tests
3  * LICENSE:         LGPLv2.1+ - See COPYING.LIB in the top level directory
4  * PURPOSE:         Test for NtWriteFile
5  * PROGRAMMER:      Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #include "precomp.h"
9 
10 static
11 BOOL
12 Is64BitSystem(VOID)
13 {
14 #ifdef _WIN64
15     return TRUE;
16 #else
17     NTSTATUS Status;
18     ULONG_PTR IsWow64;
19 
20     Status = NtQueryInformationProcess(NtCurrentProcess(),
21                                        ProcessWow64Information,
22                                        &IsWow64,
23                                        sizeof(IsWow64),
24                                        NULL);
25     if (NT_SUCCESS(Status))
26     {
27         return IsWow64 != 0;
28     }
29 
30     return FALSE;
31 #endif
32 }
33 
34 static
35 ULONG
36 SizeOfMdl(VOID)
37 {
38     return Is64BitSystem() ? 48 : 28;
39 }
40 
41 START_TEST(NtWriteFile)
42 {
43     NTSTATUS Status;
44     HANDLE FileHandle;
45     UNICODE_STRING FileName = RTL_CONSTANT_STRING(L"\\SystemRoot\\ntdll-apitest-NtWriteFile-test.bin");
46     PVOID Buffer;
47     SIZE_T BufferSize;
48     LARGE_INTEGER ByteOffset;
49     OBJECT_ATTRIBUTES ObjectAttributes;
50     IO_STATUS_BLOCK IoStatus;
51     FILE_DISPOSITION_INFORMATION DispositionInfo;
52     ULONG TooLargeDataSize = (MAXUSHORT + 1 - SizeOfMdl()) / sizeof(ULONG_PTR) * PAGE_SIZE; // 0x3FF9000 on x86
53     ULONG LargeMdlMaxDataSize = TooLargeDataSize - PAGE_SIZE;
54 
55     trace("System is %d bits, Size of MDL: %lu\n", Is64BitSystem() ? 64 : 32, SizeOfMdl());
56     trace("Max MDL data size: 0x%lx bytes\n", LargeMdlMaxDataSize);
57 
58     ByteOffset.QuadPart = 0;
59 
60     Buffer = NULL;
61     BufferSize = TooLargeDataSize;
62     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
63                                      &Buffer,
64                                      0,
65                                      &BufferSize,
66                                      MEM_RESERVE | MEM_COMMIT,
67                                      PAGE_READONLY);
68     if (!NT_SUCCESS(Status))
69     {
70         skip("Failed to allocate memory, status %lx\n", Status);
71         return;
72     }
73 
74     InitializeObjectAttributes(&ObjectAttributes,
75                                &FileName,
76                                OBJ_CASE_INSENSITIVE,
77                                NULL,
78                                NULL);
79     Status = NtCreateFile(&FileHandle,
80                           FILE_WRITE_DATA | DELETE | SYNCHRONIZE,
81                           &ObjectAttributes,
82                           &IoStatus,
83                           NULL,
84                           0,
85                           0,
86                           FILE_SUPERSEDE,
87                           FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
88                                                     FILE_NO_INTERMEDIATE_BUFFERING,
89                           NULL,
90                           0);
91     ok_hex(Status, STATUS_SUCCESS);
92 
93     /* non-cached, max size -- succeeds */
94     Status = NtWriteFile(FileHandle,
95                          NULL,
96                          NULL,
97                          NULL,
98                          &IoStatus,
99                          Buffer,
100                          LargeMdlMaxDataSize - PAGE_SIZE,
101                          &ByteOffset,
102                          NULL);
103     ok_hex(Status, STATUS_SUCCESS);
104 
105     /* non-cached, max size -- succeeds */
106     Status = NtWriteFile(FileHandle,
107                          NULL,
108                          NULL,
109                          NULL,
110                          &IoStatus,
111                          Buffer,
112                          LargeMdlMaxDataSize,
113                          &ByteOffset,
114                          NULL);
115     ok_hex(Status, STATUS_SUCCESS);
116 
117     /* non-cached, too large -- fails to allocate MDL
118      * Note: this returns STATUS_SUCCESS on Win7 -- higher MDL size limit */
119     Status = NtWriteFile(FileHandle,
120                          NULL,
121                          NULL,
122                          NULL,
123                          &IoStatus,
124                          Buffer,
125                          LargeMdlMaxDataSize + PAGE_SIZE,
126                          &ByteOffset,
127                          NULL);
128     ok_hex(Status, STATUS_INSUFFICIENT_RESOURCES);
129 
130     /* non-cached, unaligned -- fails with invalid parameter */
131     Status = NtWriteFile(FileHandle,
132                          NULL,
133                          NULL,
134                          NULL,
135                          &IoStatus,
136                          Buffer,
137                          LargeMdlMaxDataSize + 1,
138                          &ByteOffset,
139                          NULL);
140     ok_hex(Status, STATUS_INVALID_PARAMETER);
141 
142     DispositionInfo.DeleteFile = TRUE;
143     Status = NtSetInformationFile(FileHandle,
144                                   &IoStatus,
145                                   &DispositionInfo,
146                                   sizeof(DispositionInfo),
147                                   FileDispositionInformation);
148     ok_hex(Status, STATUS_SUCCESS);
149     Status = NtClose(FileHandle);
150     ok_hex(Status, STATUS_SUCCESS);
151 
152     Status = NtCreateFile(&FileHandle,
153                           FILE_WRITE_DATA | DELETE | SYNCHRONIZE,
154                           &ObjectAttributes,
155                           &IoStatus,
156                           NULL,
157                           0,
158                           0,
159                           FILE_SUPERSEDE,
160                           FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
161                           NULL,
162                           0);
163     ok_hex(Status, STATUS_SUCCESS);
164 
165     /* cached: succeeds with arbitrary length */
166     Status = NtWriteFile(FileHandle,
167                          NULL,
168                          NULL,
169                          NULL,
170                          &IoStatus,
171                          Buffer,
172                          LargeMdlMaxDataSize,
173                          &ByteOffset,
174                          NULL);
175     ok_hex(Status, STATUS_SUCCESS);
176 
177     Status = NtWriteFile(FileHandle,
178                          NULL,
179                          NULL,
180                          NULL,
181                          &IoStatus,
182                          Buffer,
183                          LargeMdlMaxDataSize + 1,
184                          &ByteOffset,
185                          NULL);
186     ok_hex(Status, STATUS_SUCCESS);
187 
188     Status = NtWriteFile(FileHandle,
189                          NULL,
190                          NULL,
191                          NULL,
192                          &IoStatus,
193                          Buffer,
194                          TooLargeDataSize,
195                          &ByteOffset,
196                          NULL);
197     ok_hex(Status, STATUS_SUCCESS);
198 
199     DispositionInfo.DeleteFile = TRUE;
200     Status = NtSetInformationFile(FileHandle,
201                                   &IoStatus,
202                                   &DispositionInfo,
203                                   sizeof(DispositionInfo),
204                                   FileDispositionInformation);
205     ok_hex(Status, STATUS_SUCCESS);
206     Status = NtClose(FileHandle);
207     ok_hex(Status, STATUS_SUCCESS);
208 
209     Status = NtFreeVirtualMemory(NtCurrentProcess(),
210                                  &Buffer,
211                                  &BufferSize,
212                                  MEM_RELEASE);
213     ok_hex(Status, STATUS_SUCCESS);
214 }
215