[CRT] Massively improve performance of rand_s
[reactos.git] / modules / rostests / apitests / ntdll / NtWriteFile.c
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 }