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