[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)
[reactos.git] / modules / rostests / apitests / kernel32 / DeviceIoControl.c
1 /*
2 * PROJECT: ReactOS api tests
3 * LICENSE: GPLv2+ - See COPYING in the top level directory
4 * PURPOSE: Test for DeviceIoControl
5 * PROGRAMMER: Pierre Schweitzer <pierre@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 #include <winioctl.h>
11 #include <mountdev.h>
12
13 WCHAR Letter;
14 HANDLE Device;
15 UINT DriveType;
16
17 #define ok_type(condition, format, ...) ok(condition, "(%d): " format, DriveType, ##__VA_ARGS__)
18 #define skip_type(format, ...) skip("(%d): " format, DriveType, ##__VA_ARGS__)
19
20 static
21 BOOL
22 GetDiskGeometry(VOID)
23 {
24 UINT Ret;
25 DISK_GEOMETRY DG;
26 DWORD Size, Error;
27 DISK_GEOMETRY_EX DGE;
28
29 Size = 0;
30 Ret = DeviceIoControl(Device, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DG, sizeof(DG) - 1, &Size, NULL);
31 ok_type(Ret == 0, "DeviceIoControl succeed\n");
32 Error = GetLastError();
33 ok_type(Error == ERROR_INSUFFICIENT_BUFFER, "Expecting ERROR_INSUFFICIENT_BUFFER, got %ld\n", Error);
34 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
35
36 Size = 0;
37 Ret = DeviceIoControl(Device, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0, &DG, sizeof(DG), &Size, NULL);
38 /* Specific for CDROM, no disk present */
39 if (Ret == 0 && GetLastError() == ERROR_NOT_READY)
40 {
41 skip_type("No CDROM present\n");
42 return FALSE;
43 }
44 ok_type(Ret != 0, "DeviceIoControl failed: %ld\n", GetLastError());
45 ok_type(Size == sizeof(DG), "Invalid output size: %ld\n", Size);
46
47 Size = 0;
48 Ret = DeviceIoControl(Device, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &DGE, FIELD_OFFSET(DISK_GEOMETRY_EX, Data) - 1, &Size, NULL);
49 ok_type(Ret == 0, "DeviceIoControl succeed\n");
50 Error = GetLastError();
51 ok_type(Error == ERROR_INSUFFICIENT_BUFFER, "Expecting ERROR_INSUFFICIENT_BUFFER, got %ld\n", Error);
52 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
53
54 Size = 0;
55 Ret = DeviceIoControl(Device, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &DGE, FIELD_OFFSET(DISK_GEOMETRY_EX, Data), &Size, NULL);
56 ok_type(Ret != 0, "DeviceIoControl failed: %ld\n", GetLastError());
57 ok_type(Size == FIELD_OFFSET(DISK_GEOMETRY_EX, Data), "Invalid output size: %ld\n", Size);
58
59 Size = 0;
60 Ret = DeviceIoControl(Device, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &DGE, sizeof(DGE), &Size, NULL);
61 ok_type(Ret != 0, "DeviceIoControl failed: %ld\n", GetLastError());
62 if (DriveType == DRIVE_FIXED)
63 {
64 ok_type(Size == sizeof(DGE), "Invalid output size: %ld\n", Size);
65 }
66 else
67 {
68 ok_type(Size == FIELD_OFFSET(DISK_GEOMETRY_EX, Data), "Invalid output size: %ld\n", Size);
69 }
70
71 return TRUE;
72 }
73
74 static
75 VOID
76 QueryDeviceName(VOID)
77 {
78 UINT Ret;
79 BOOL IsValid;
80 DWORD Size, Error;
81 MOUNTDEV_NAME MDN, *AllocatedMDN;
82
83 Size = 0;
84 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &MDN, sizeof(MDN) - 1, &Size, NULL);
85 ok_type(Ret == 0, "DeviceIoControl succeed\n");
86 Error = GetLastError();
87 if (DriveType == DRIVE_FIXED)
88 {
89 ok_type(Error == ERROR_INVALID_PARAMETER, "Expecting ERROR_INVALID_PARAMETER, got %ld\n", Error);
90 }
91 else
92 {
93 ok_type(Error == ERROR_INSUFFICIENT_BUFFER, "Expecting ERROR_INSUFFICIENT_BUFFER, got %ld\n", Error);
94 }
95 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
96
97 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, &MDN, sizeof(MDN), &Size, NULL);
98 ok_type(Ret == 0, "DeviceIoControl succeed\n");
99 Error = GetLastError();
100 ok_type(Error == ERROR_MORE_DATA, "Expecting ERROR_MORE_DATA, got %ld\n", Error);
101 ok_type(Size == sizeof(MOUNTDEV_NAME), "Invalid output size: %ld\n", Size);
102
103 AllocatedMDN = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MOUNTDEV_NAME, Name) + MDN.NameLength + sizeof(UNICODE_NULL));
104 if (AllocatedMDN == NULL)
105 {
106 skip_type("Memory allocation failure\n");
107 return;
108 }
109
110 Size = 0;
111 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, NULL, 0, AllocatedMDN, FIELD_OFFSET(MOUNTDEV_NAME, Name) + MDN.NameLength, &Size, NULL);
112 ok_type(Ret != 0, "DeviceIoControl failed: %ld\n", GetLastError());
113 ok_type(Size == FIELD_OFFSET(MOUNTDEV_NAME, Name) + MDN.NameLength, "Invalid output size: %ld\n", Size);
114 ok_type(AllocatedMDN->NameLength == MDN.NameLength, "Mismatching sizes: %d %d\n", AllocatedMDN->NameLength, MDN.NameLength);
115
116 if (Ret != 0)
117 {
118 IsValid = FALSE;
119 AllocatedMDN->Name[AllocatedMDN->NameLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
120
121 if ((DriveType == DRIVE_FIXED && wcsstr(AllocatedMDN->Name, L"\\Device\\HarddiskVolume") != NULL) ||
122 (DriveType == DRIVE_CDROM && wcsstr(AllocatedMDN->Name, L"\\Device\\CdRom") != NULL))
123 {
124 IsValid = TRUE;
125 }
126 else if (wcsstr(AllocatedMDN->Name, L"\\DosDevices\\") != NULL)
127 {
128 IsValid = (AllocatedMDN->Name[12] == Letter && AllocatedMDN->Name[13] == L':');
129 }
130
131 ok_type(IsValid, "Invalid name: %.*S\n", AllocatedMDN->NameLength, AllocatedMDN->Name);
132 }
133 else
134 {
135 skip_type("Failed to query device name\n");
136 }
137
138 HeapFree(GetProcessHeap(), 0, AllocatedMDN);
139 }
140
141 static
142 VOID
143 QueryUniqueId(VOID)
144 {
145 UINT Ret;
146 DWORD Size, Error;
147 MOUNTDEV_UNIQUE_ID MUI, *AllocatedMUI;
148
149 Size = 0;
150 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_UNIQUE_ID, NULL, 0, &MUI, sizeof(MUI) - 1, &Size, NULL);
151 ok_type(Ret == 0, "DeviceIoControl succeed\n");
152 Error = GetLastError();
153 if (DriveType == DRIVE_FIXED)
154 {
155 ok_type(Error == ERROR_INVALID_PARAMETER, "Expecting ERROR_INVALID_PARAMETER, got %ld\n", Error);
156 }
157 else
158 {
159 ok_type(Error == ERROR_INSUFFICIENT_BUFFER, "Expecting ERROR_INSUFFICIENT_BUFFER, got %ld\n", Error);
160 }
161 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
162
163 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_UNIQUE_ID, NULL, 0, &MUI, sizeof(MUI), &Size, NULL);
164 ok_type(Ret == 0, "DeviceIoControl succeed\n");
165 Error = GetLastError();
166 ok_type(Error == ERROR_MORE_DATA, "Expecting ERROR_MORE_DATA, got %ld\n", Error);
167 ok_type(Size == sizeof(MOUNTDEV_UNIQUE_ID), "Invalid output size: %ld\n", Size);
168
169 AllocatedMUI = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + MUI.UniqueIdLength + sizeof(UNICODE_NULL));
170 if (AllocatedMUI == NULL)
171 {
172 skip_type("Memory allocation failure\n");
173 return;
174 }
175
176 Size = 0;
177 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_UNIQUE_ID, NULL, 0, AllocatedMUI, FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + MUI.UniqueIdLength, &Size, NULL);
178 ok_type(Ret != 0, "DeviceIoControl failed: %ld\n", GetLastError());
179 ok_type(Size == FIELD_OFFSET(MOUNTDEV_UNIQUE_ID, UniqueId) + MUI.UniqueIdLength, "Invalid output size: %ld\n", Size);
180 ok_type(AllocatedMUI->UniqueIdLength == MUI.UniqueIdLength, "Mismatching sizes: %d %d\n", AllocatedMUI->UniqueIdLength, MUI.UniqueIdLength);
181
182 HeapFree(GetProcessHeap(), 0, AllocatedMUI);
183 }
184
185 static
186 VOID
187 QuerySuggestedLinkName(VOID)
188 {
189 UINT Ret;
190 DWORD Size, Error;
191 MOUNTDEV_SUGGESTED_LINK_NAME MSLN;
192
193 Size = 0;
194 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME, NULL, 0, &MSLN, sizeof(MSLN) - 1, &Size, NULL);
195 ok_type(Ret == 0, "DeviceIoControl succeed\n");
196 Error = GetLastError();
197 if (DriveType == DRIVE_FIXED)
198 {
199 ok_type(Error == ERROR_INVALID_PARAMETER, "Expecting ERROR_INVALID_PARAMETER, got %ld\n", Error);
200 }
201 else
202 {
203 ok_type(Error == ERROR_INSUFFICIENT_BUFFER, "Expecting ERROR_INSUFFICIENT_BUFFER, got %ld\n", Error);
204 }
205 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
206
207 Ret = DeviceIoControl(Device, IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME, NULL, 0, &MSLN, sizeof(MSLN), &Size, NULL);
208 ok_type(Ret == 0, "DeviceIoControl succeed\n");
209 Error = GetLastError();
210 if (DriveType == DRIVE_FIXED)
211 {
212 ok_type(Error == ERROR_NOT_FOUND, "Expecting ERROR_NOT_FOUND, got %ld\n", Error);
213 }
214 else
215 {
216 ok_type(Error == ERROR_FILE_NOT_FOUND, "Expecting ERROR_FILE_NOT_FOUND, got %ld\n", Error);
217 }
218 ok_type(Size == 0, "Invalid output size: %ld\n", Size);
219 }
220
221 START_TEST(DeviceIoControl)
222 {
223 UINT Ret;
224 WCHAR Path[MAX_PATH];
225 DWORD DriveMap, Current;
226 BOOL DiskDone, CdRomDone;
227
228 DiskDone = FALSE;
229 CdRomDone = FALSE;
230 DriveMap = GetLogicalDrives();
231 for (Current = 0; Current < 26; ++Current)
232 {
233 if (DriveMap & (1 << Current))
234 {
235 Ret = StringCchPrintfW(Path, MAX_PATH, L"%c:\\", Current + L'A');
236 ok(Ret == S_OK, "StringCchPrintfW failed: %d\n", Ret);
237
238 DriveType = GetDriveTypeW(Path);
239 if ((DriveType == DRIVE_FIXED && !DiskDone) ||
240 (DriveType == DRIVE_CDROM && !CdRomDone))
241 {
242 Ret = StringCchPrintfW(Path, MAX_PATH, L"\\\\?\\%c:", Current + L'A');
243 ok(Ret == S_OK, "StringCchPrintfW failed: %d\n", Ret);
244
245 Device = CreateFileW(Path, 0, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
246 if (Device == INVALID_HANDLE_VALUE)
247 {
248 skip_type("CreateFileW for %S failed: %ld\n", Path, GetLastError());
249 continue;
250 }
251
252 DiskDone = (DiskDone || (DriveType == DRIVE_FIXED));
253 CdRomDone = (CdRomDone || (DriveType == DRIVE_CDROM));
254
255 if (GetDiskGeometry())
256 {
257 QueryDeviceName();
258 QueryUniqueId();
259 QuerySuggestedLinkName();
260 }
261
262 CloseHandle(Device);
263 }
264
265 if (CdRomDone && DiskDone)
266 {
267 break;
268 }
269 }
270 }
271
272 if (!DiskDone)
273 {
274 skip("No disk drive found\n");
275 }
276
277 if (!CdRomDone)
278 {
279 skip("No CDROM drive found\n");
280 }
281 }