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