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 static
42 ULONG
43 SizeOfSector(VOID)
44 {
45     BOOL Ret;
46     ULONG SectorSize;
47 
48     /* FIXME: Would be better to actually open systemroot */
49     Ret = GetDiskFreeSpaceW(NULL, NULL, &SectorSize, NULL, NULL);
50     ok(Ret != FALSE, "GetDiskFreeSpaceW failed: %lx\n", GetLastError());
51     if (!Ret)
52     {
53         SectorSize = 4096; /* On failure, assume max size */
54     }
55 
56     return SectorSize;
57 }
58 
59 START_TEST(NtWriteFile)
60 {
61     NTSTATUS Status;
62     HANDLE FileHandle;
63     UNICODE_STRING FileName = RTL_CONSTANT_STRING(L"\\SystemRoot\\ntdll-apitest-NtWriteFile-test.bin");
64     PVOID Buffer;
65     SIZE_T BufferSize;
66     LARGE_INTEGER ByteOffset;
67     OBJECT_ATTRIBUTES ObjectAttributes;
68     IO_STATUS_BLOCK IoStatus;
69     FILE_DISPOSITION_INFORMATION DispositionInfo;
70     ULONG TooLargeDataSize = (MAXUSHORT + 1 - SizeOfMdl()) / sizeof(ULONG_PTR) * PAGE_SIZE; // 0x3FF9000 on x86
71     ULONG LargeMdlMaxDataSize = TooLargeDataSize - PAGE_SIZE;
72 
73     trace("System is %d bits, Size of MDL: %lu\n", Is64BitSystem() ? 64 : 32, SizeOfMdl());
74     trace("Max MDL data size: 0x%lx bytes\n", LargeMdlMaxDataSize);
75 
76     ByteOffset.QuadPart = 0;
77 
78     Buffer = NULL;
79     BufferSize = TooLargeDataSize;
80     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
81                                      &Buffer,
82                                      0,
83                                      &BufferSize,
84                                      MEM_RESERVE | MEM_COMMIT,
85                                      PAGE_READONLY);
86     if (!NT_SUCCESS(Status))
87     {
88         skip("Failed to allocate memory, status %lx\n", Status);
89         return;
90     }
91 
92     InitializeObjectAttributes(&ObjectAttributes,
93                                &FileName,
94                                OBJ_CASE_INSENSITIVE,
95                                NULL,
96                                NULL);
97     Status = NtCreateFile(&FileHandle,
98                           FILE_WRITE_DATA | DELETE | SYNCHRONIZE,
99                           &ObjectAttributes,
100                           &IoStatus,
101                           NULL,
102                           0,
103                           0,
104                           FILE_SUPERSEDE,
105                           FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
106                                                     FILE_NO_INTERMEDIATE_BUFFERING,
107                           NULL,
108                           0);
109     ok_hex(Status, STATUS_SUCCESS);
110 
111     /* non-cached, max size -- succeeds */
112     Status = NtWriteFile(FileHandle,
113                          NULL,
114                          NULL,
115                          NULL,
116                          &IoStatus,
117                          Buffer,
118                          LargeMdlMaxDataSize - PAGE_SIZE,
119                          &ByteOffset,
120                          NULL);
121     ok_hex(Status, STATUS_SUCCESS);
122 
123     /* non-cached, max size -- succeeds */
124     Status = NtWriteFile(FileHandle,
125                          NULL,
126                          NULL,
127                          NULL,
128                          &IoStatus,
129                          Buffer,
130                          LargeMdlMaxDataSize,
131                          &ByteOffset,
132                          NULL);
133     ok_hex(Status, STATUS_SUCCESS);
134 
135     /* non-cached, too large -- fails to allocate MDL
136      * Note: this returns STATUS_SUCCESS on Win7 -- higher MDL size limit */
137     Status = NtWriteFile(FileHandle,
138                          NULL,
139                          NULL,
140                          NULL,
141                          &IoStatus,
142                          Buffer,
143                          LargeMdlMaxDataSize + PAGE_SIZE,
144                          &ByteOffset,
145                          NULL);
146     ok_hex(Status, STATUS_INSUFFICIENT_RESOURCES);
147 
148     /* non-cached, unaligned -- fails with invalid parameter */
149     Status = NtWriteFile(FileHandle,
150                          NULL,
151                          NULL,
152                          NULL,
153                          &IoStatus,
154                          Buffer,
155                          LargeMdlMaxDataSize + 1,
156                          &ByteOffset,
157                          NULL);
158     ok_hex(Status, STATUS_INVALID_PARAMETER);
159 
160     DispositionInfo.DeleteFile = TRUE;
161     Status = NtSetInformationFile(FileHandle,
162                                   &IoStatus,
163                                   &DispositionInfo,
164                                   sizeof(DispositionInfo),
165                                   FileDispositionInformation);
166     ok_hex(Status, STATUS_SUCCESS);
167     Status = NtClose(FileHandle);
168     ok_hex(Status, STATUS_SUCCESS);
169 
170     Status = NtCreateFile(&FileHandle,
171                           FILE_WRITE_DATA | DELETE | SYNCHRONIZE,
172                           &ObjectAttributes,
173                           &IoStatus,
174                           NULL,
175                           0,
176                           0,
177                           FILE_SUPERSEDE,
178                           FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
179                           NULL,
180                           0);
181     ok_hex(Status, STATUS_SUCCESS);
182 
183     /* cached: succeeds with arbitrary length */
184     Status = NtWriteFile(FileHandle,
185                          NULL,
186                          NULL,
187                          NULL,
188                          &IoStatus,
189                          Buffer,
190                          LargeMdlMaxDataSize,
191                          &ByteOffset,
192                          NULL);
193     ok_hex(Status, STATUS_SUCCESS);
194 
195     Status = NtWriteFile(FileHandle,
196                          NULL,
197                          NULL,
198                          NULL,
199                          &IoStatus,
200                          Buffer,
201                          LargeMdlMaxDataSize + 1,
202                          &ByteOffset,
203                          NULL);
204     ok_hex(Status, STATUS_SUCCESS);
205 
206     Status = NtWriteFile(FileHandle,
207                          NULL,
208                          NULL,
209                          NULL,
210                          &IoStatus,
211                          Buffer,
212                          TooLargeDataSize,
213                          &ByteOffset,
214                          NULL);
215     ok_hex(Status, STATUS_SUCCESS);
216 
217     DispositionInfo.DeleteFile = TRUE;
218     Status = NtSetInformationFile(FileHandle,
219                                   &IoStatus,
220                                   &DispositionInfo,
221                                   sizeof(DispositionInfo),
222                                   FileDispositionInformation);
223     ok_hex(Status, STATUS_SUCCESS);
224     Status = NtClose(FileHandle);
225     ok_hex(Status, STATUS_SUCCESS);
226 
227     Status = NtFreeVirtualMemory(NtCurrentProcess(),
228                                  &Buffer,
229                                  &BufferSize,
230                                  MEM_RELEASE);
231     ok_hex(Status, STATUS_SUCCESS);
232 
233     /* Now, testing aligned/non aligned writes */
234 
235     BufferSize = SizeOfSector();
236     trace("Sector is %ld bytes\n", BufferSize);
237 
238     Status = NtAllocateVirtualMemory(NtCurrentProcess(),
239                                      &Buffer,
240                                      0,
241                                      &BufferSize,
242                                      MEM_RESERVE | MEM_COMMIT,
243                                      PAGE_READONLY);
244     if (!NT_SUCCESS(Status))
245     {
246         skip("Failed to allocate memory, status %lx\n", Status);
247         return;
248     }
249 
250     Status = NtCreateFile(&FileHandle,
251                           FILE_WRITE_DATA | DELETE | SYNCHRONIZE,
252                           &ObjectAttributes,
253                           &IoStatus,
254                           NULL,
255                           0,
256                           0,
257                           FILE_SUPERSEDE,
258                           FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT |
259                                                     FILE_NO_INTERMEDIATE_BUFFERING |
260                                                     FILE_WRITE_THROUGH,
261                           NULL,
262                           0);
263     ok_hex(Status, STATUS_SUCCESS);
264 
265     /* non-cached, broken length -- fails with invalid parameter */
266     ByteOffset.QuadPart = 0;
267     Status = NtWriteFile(FileHandle,
268                          NULL,
269                          NULL,
270                          NULL,
271                          &IoStatus,
272                          Buffer,
273                          4,
274                          &ByteOffset,
275                          NULL);
276     ok_hex(Status, STATUS_INVALID_PARAMETER);
277 
278     /* non-cached, broken offset -- fails with invalid parameter */
279     ByteOffset.QuadPart = 4;
280     Status = NtWriteFile(FileHandle,
281                          NULL,
282                          NULL,
283                          NULL,
284                          &IoStatus,
285                          Buffer,
286                          BufferSize,
287                          &ByteOffset,
288                          NULL);
289     ok_hex(Status, STATUS_INVALID_PARAMETER);
290 
291     /* non-cached, good length and offset -- succeeds */
292     ByteOffset.QuadPart = 0;
293     Status = NtWriteFile(FileHandle,
294                          NULL,
295                          NULL,
296                          NULL,
297                          &IoStatus,
298                          Buffer,
299                          BufferSize,
300                          &ByteOffset,
301                          NULL);
302     ok_hex(Status, STATUS_SUCCESS);
303 
304     DispositionInfo.DeleteFile = TRUE;
305     Status = NtSetInformationFile(FileHandle,
306                                   &IoStatus,
307                                   &DispositionInfo,
308                                   sizeof(DispositionInfo),
309                                   FileDispositionInformation);
310     ok_hex(Status, STATUS_SUCCESS);
311     Status = NtClose(FileHandle);
312     ok_hex(Status, STATUS_SUCCESS);
313 
314     Status = NtFreeVirtualMemory(NtCurrentProcess(),
315                                  &Buffer,
316                                  &BufferSize,
317                                  MEM_RELEASE);
318     ok_hex(Status, STATUS_SUCCESS);
319 }
320