1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * FILE: dll/win32/kernel32/client/dosdev.c 5 * PURPOSE: Dos device functions 6 * PROGRAMMER: Ariadne (ariadne@xs4all.nl) 7 * UPDATE HISTORY: 8 * Created 01/11/98 9 */ 10 11 /* INCLUDES ******************************************************************/ 12 13 #include <k32.h> 14 15 #define NDEBUG 16 #include <debug.h> 17 #include <dbt.h> 18 DEBUG_CHANNEL(kernel32file); 19 20 /* FUNCTIONS *****************************************************************/ 21 22 /* 23 * @implemented 24 */ 25 BOOL 26 WINAPI 27 DefineDosDeviceA( 28 DWORD dwFlags, 29 LPCSTR lpDeviceName, 30 LPCSTR lpTargetPath 31 ) 32 { 33 UNICODE_STRING DeviceNameU = {0}; 34 UNICODE_STRING TargetPathU = {0}; 35 BOOL Result; 36 37 if (lpDeviceName && 38 !RtlCreateUnicodeStringFromAsciiz(&DeviceNameU, lpDeviceName)) 39 { 40 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 41 return 0; 42 } 43 44 if (lpTargetPath && 45 !RtlCreateUnicodeStringFromAsciiz(&TargetPathU, lpTargetPath)) 46 { 47 if (DeviceNameU.Buffer) 48 { 49 RtlFreeUnicodeString(&DeviceNameU); 50 } 51 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 52 return 0; 53 } 54 55 Result = DefineDosDeviceW(dwFlags, 56 DeviceNameU.Buffer, 57 TargetPathU.Buffer); 58 59 if (TargetPathU.Buffer) 60 { 61 RtlFreeUnicodeString(&TargetPathU); 62 } 63 64 if (DeviceNameU.Buffer) 65 { 66 RtlFreeUnicodeString(&DeviceNameU); 67 } 68 return Result; 69 } 70 71 72 /* 73 * @implemented 74 */ 75 BOOL 76 WINAPI 77 DefineDosDeviceW( 78 DWORD dwFlags, 79 LPCWSTR lpDeviceName, 80 LPCWSTR lpTargetPath 81 ) 82 { 83 ULONG ArgumentCount; 84 ULONG BufferSize; 85 BASE_API_MESSAGE ApiMessage; 86 PBASE_DEFINE_DOS_DEVICE DefineDosDeviceRequest = &ApiMessage.Data.DefineDosDeviceRequest; 87 PCSR_CAPTURE_BUFFER CaptureBuffer; 88 UNICODE_STRING NtTargetPathU; 89 UNICODE_STRING DeviceNameU; 90 UNICODE_STRING DeviceUpcaseNameU; 91 HANDLE hUser32; 92 DEV_BROADCAST_VOLUME dbcv; 93 BOOL Result = TRUE; 94 DWORD dwRecipients; 95 typedef long (WINAPI *BSM_type)(DWORD, LPDWORD, UINT, WPARAM, LPARAM); 96 BSM_type BSM_ptr; 97 98 if ( (dwFlags & 0xFFFFFFF0) || 99 ((dwFlags & DDD_EXACT_MATCH_ON_REMOVE) && 100 ! (dwFlags & DDD_REMOVE_DEFINITION)) ) 101 { 102 SetLastError(ERROR_INVALID_PARAMETER); 103 return FALSE; 104 } 105 106 ArgumentCount = 1; 107 BufferSize = 0; 108 if (!lpTargetPath) 109 { 110 RtlInitUnicodeString(&NtTargetPathU, 111 NULL); 112 } 113 else 114 { 115 if (dwFlags & DDD_RAW_TARGET_PATH) 116 { 117 RtlInitUnicodeString(&NtTargetPathU, 118 lpTargetPath); 119 } 120 else 121 { 122 if (!RtlDosPathNameToNtPathName_U(lpTargetPath, 123 &NtTargetPathU, 124 NULL, 125 NULL)) 126 { 127 WARN("RtlDosPathNameToNtPathName_U() failed\n"); 128 BaseSetLastNTError(STATUS_OBJECT_NAME_INVALID); 129 return FALSE; 130 } 131 } 132 ArgumentCount = 2; 133 BufferSize += NtTargetPathU.Length; 134 } 135 136 RtlInitUnicodeString(&DeviceNameU, 137 lpDeviceName); 138 RtlUpcaseUnicodeString(&DeviceUpcaseNameU, 139 &DeviceNameU, 140 TRUE); 141 BufferSize += DeviceUpcaseNameU.Length; 142 143 CaptureBuffer = CsrAllocateCaptureBuffer(ArgumentCount, 144 BufferSize); 145 if (!CaptureBuffer) 146 { 147 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 148 Result = FALSE; 149 } 150 else 151 { 152 DefineDosDeviceRequest->Flags = dwFlags; 153 154 CsrCaptureMessageBuffer(CaptureBuffer, 155 DeviceUpcaseNameU.Buffer, 156 DeviceUpcaseNameU.Length, 157 (PVOID*)&DefineDosDeviceRequest->DeviceName.Buffer); 158 159 DefineDosDeviceRequest->DeviceName.Length = 160 DeviceUpcaseNameU.Length; 161 DefineDosDeviceRequest->DeviceName.MaximumLength = 162 DeviceUpcaseNameU.Length; 163 164 if (NtTargetPathU.Buffer) 165 { 166 CsrCaptureMessageBuffer(CaptureBuffer, 167 NtTargetPathU.Buffer, 168 NtTargetPathU.Length, 169 (PVOID*)&DefineDosDeviceRequest->TargetPath.Buffer); 170 } 171 DefineDosDeviceRequest->TargetPath.Length = 172 NtTargetPathU.Length; 173 DefineDosDeviceRequest->TargetPath.MaximumLength = 174 NtTargetPathU.Length; 175 176 CsrClientCallServer((PCSR_API_MESSAGE)&ApiMessage, 177 CaptureBuffer, 178 CSR_CREATE_API_NUMBER(BASESRV_SERVERDLL_INDEX, BasepDefineDosDevice), 179 sizeof(*DefineDosDeviceRequest)); 180 CsrFreeCaptureBuffer(CaptureBuffer); 181 182 if (!NT_SUCCESS(ApiMessage.Status)) 183 { 184 WARN("CsrClientCallServer() failed (Status %lx)\n", ApiMessage.Status); 185 BaseSetLastNTError(ApiMessage.Status); 186 Result = FALSE; 187 } 188 else 189 { 190 if (! (dwFlags & DDD_NO_BROADCAST_SYSTEM) && 191 DeviceUpcaseNameU.Length == 2 * sizeof(WCHAR) && 192 DeviceUpcaseNameU.Buffer[1] == L':' && 193 ( (DeviceUpcaseNameU.Buffer[0] - L'A') < 26 )) 194 { 195 hUser32 = LoadLibraryA("user32.dll"); 196 if (hUser32) 197 { 198 BSM_ptr = (BSM_type) 199 GetProcAddress(hUser32, "BroadcastSystemMessageW"); 200 if (BSM_ptr) 201 { 202 dwRecipients = BSM_APPLICATIONS; 203 dbcv.dbcv_size = sizeof(DEV_BROADCAST_VOLUME); 204 dbcv.dbcv_devicetype = DBT_DEVTYP_VOLUME; 205 dbcv.dbcv_reserved = 0; 206 dbcv.dbcv_unitmask |= 207 (1 << (DeviceUpcaseNameU.Buffer[0] - L'A')); 208 dbcv.dbcv_flags = DBTF_NET; 209 (void) BSM_ptr(BSF_SENDNOTIFYMESSAGE | BSF_FLUSHDISK, 210 &dwRecipients, 211 WM_DEVICECHANGE, 212 (WPARAM)DBT_DEVICEARRIVAL, 213 (LPARAM)&dbcv); 214 } 215 FreeLibrary(hUser32); 216 } 217 } 218 } 219 } 220 221 if (NtTargetPathU.Buffer && 222 NtTargetPathU.Buffer != lpTargetPath) 223 { 224 RtlFreeHeap(RtlGetProcessHeap(), 225 0, 226 NtTargetPathU.Buffer); 227 } 228 RtlFreeUnicodeString(&DeviceUpcaseNameU); 229 return Result; 230 } 231 232 233 /* 234 * @implemented 235 */ 236 DWORD 237 WINAPI 238 QueryDosDeviceA( 239 LPCSTR lpDeviceName, 240 LPSTR lpTargetPath, 241 DWORD ucchMax 242 ) 243 { 244 UNICODE_STRING DeviceNameU; 245 UNICODE_STRING TargetPathU; 246 ANSI_STRING TargetPathA; 247 DWORD Length; 248 DWORD CurrentLength; 249 PWCHAR Buffer; 250 251 if (lpDeviceName) 252 { 253 if (!RtlCreateUnicodeStringFromAsciiz(&DeviceNameU, 254 (LPSTR)lpDeviceName)) 255 { 256 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 257 return 0; 258 } 259 } 260 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, ucchMax * sizeof(WCHAR)); 261 if (Buffer == NULL) 262 { 263 if (lpDeviceName) 264 { 265 RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer); 266 } 267 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 268 return 0; 269 } 270 271 Length = QueryDosDeviceW(lpDeviceName ? DeviceNameU.Buffer : NULL, 272 Buffer, ucchMax); 273 if (Length != 0) 274 { 275 TargetPathA.Buffer = lpTargetPath; 276 TargetPathU.Buffer = Buffer; 277 ucchMax = Length; 278 279 while (ucchMax) 280 { 281 CurrentLength = min(ucchMax, MAXUSHORT / 2); 282 TargetPathU.MaximumLength = TargetPathU.Length = (USHORT)CurrentLength * sizeof(WCHAR); 283 284 TargetPathA.Length = 0; 285 TargetPathA.MaximumLength = (USHORT)CurrentLength; 286 287 RtlUnicodeStringToAnsiString(&TargetPathA, &TargetPathU, FALSE); 288 ucchMax -= CurrentLength; 289 TargetPathA.Buffer += TargetPathA.Length; 290 TargetPathU.Buffer += TargetPathU.Length / sizeof(WCHAR); 291 } 292 } 293 294 RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer); 295 if (lpDeviceName) 296 { 297 RtlFreeHeap(RtlGetProcessHeap(), 0, DeviceNameU.Buffer); 298 } 299 return Length; 300 } 301 302 303 /* 304 * @implemented 305 */ 306 DWORD 307 WINAPI 308 QueryDosDeviceW( 309 LPCWSTR lpDeviceName, 310 LPWSTR lpTargetPath, 311 DWORD ucchMax 312 ) 313 { 314 POBJECT_DIRECTORY_INFORMATION DirInfo; 315 OBJECT_ATTRIBUTES ObjectAttributes; 316 UNICODE_STRING UnicodeString; 317 HANDLE DirectoryHandle; 318 HANDLE DeviceHandle; 319 ULONG ReturnLength; 320 ULONG NameLength; 321 ULONG Length; 322 ULONG Context; 323 BOOLEAN RestartScan; 324 NTSTATUS Status; 325 UCHAR Buffer[512]; 326 PWSTR Ptr; 327 328 /* Open the '\??' directory */ 329 RtlInitUnicodeString(&UnicodeString, L"\\??"); 330 InitializeObjectAttributes(&ObjectAttributes, 331 &UnicodeString, 332 OBJ_CASE_INSENSITIVE, 333 NULL, 334 NULL); 335 Status = NtOpenDirectoryObject(&DirectoryHandle, 336 DIRECTORY_QUERY, 337 &ObjectAttributes); 338 if (!NT_SUCCESS(Status)) 339 { 340 WARN("NtOpenDirectoryObject() failed (Status %lx)\n", Status); 341 BaseSetLastNTError(Status); 342 return 0; 343 } 344 345 Length = 0; 346 347 if (lpDeviceName != NULL) 348 { 349 /* Open the lpDeviceName link object */ 350 RtlInitUnicodeString(&UnicodeString, (PWSTR)lpDeviceName); 351 InitializeObjectAttributes(&ObjectAttributes, 352 &UnicodeString, 353 OBJ_CASE_INSENSITIVE, 354 DirectoryHandle, 355 NULL); 356 Status = NtOpenSymbolicLinkObject(&DeviceHandle, 357 SYMBOLIC_LINK_QUERY, 358 &ObjectAttributes); 359 if (!NT_SUCCESS(Status)) 360 { 361 WARN("NtOpenSymbolicLinkObject() failed (Status %lx)\n", Status); 362 NtClose(DirectoryHandle); 363 BaseSetLastNTError(Status); 364 return 0; 365 } 366 367 /* Query link target */ 368 UnicodeString.Length = 0; 369 UnicodeString.MaximumLength = (USHORT)ucchMax * sizeof(WCHAR); 370 UnicodeString.Buffer = lpTargetPath; 371 372 ReturnLength = 0; 373 Status = NtQuerySymbolicLinkObject(DeviceHandle, 374 &UnicodeString, 375 &ReturnLength); 376 NtClose(DeviceHandle); 377 NtClose(DirectoryHandle); 378 if (!NT_SUCCESS(Status)) 379 { 380 WARN("NtQuerySymbolicLinkObject() failed (Status %lx)\n", Status); 381 BaseSetLastNTError(Status); 382 return 0; 383 } 384 385 TRACE("ReturnLength: %lu\n", ReturnLength); 386 TRACE("TargetLength: %hu\n", UnicodeString.Length); 387 TRACE("Target: '%wZ'\n", &UnicodeString); 388 389 Length = UnicodeString.Length / sizeof(WCHAR); 390 if (Length < ucchMax) 391 { 392 /* Append null-character */ 393 lpTargetPath[Length] = UNICODE_NULL; 394 Length++; 395 } 396 else 397 { 398 TRACE("Buffer is too small\n"); 399 BaseSetLastNTError(STATUS_BUFFER_TOO_SMALL); 400 return 0; 401 } 402 } 403 else 404 { 405 RestartScan = TRUE; 406 Context = 0; 407 Ptr = lpTargetPath; 408 DirInfo = (POBJECT_DIRECTORY_INFORMATION)Buffer; 409 410 while (TRUE) 411 { 412 Status = NtQueryDirectoryObject(DirectoryHandle, 413 Buffer, 414 sizeof(Buffer), 415 TRUE, 416 RestartScan, 417 &Context, 418 &ReturnLength); 419 if (!NT_SUCCESS(Status)) 420 { 421 if (Status == STATUS_NO_MORE_ENTRIES) 422 { 423 /* Terminate the buffer */ 424 *Ptr = UNICODE_NULL; 425 Length++; 426 427 Status = STATUS_SUCCESS; 428 } 429 else 430 { 431 Length = 0; 432 } 433 BaseSetLastNTError(Status); 434 break; 435 } 436 437 if (!wcscmp(DirInfo->TypeName.Buffer, L"SymbolicLink")) 438 { 439 TRACE("Name: '%wZ'\n", &DirInfo->Name); 440 441 NameLength = DirInfo->Name.Length / sizeof(WCHAR); 442 if (Length + NameLength + 1 >= ucchMax) 443 { 444 Length = 0; 445 BaseSetLastNTError(STATUS_BUFFER_TOO_SMALL); 446 break; 447 } 448 449 memcpy(Ptr, DirInfo->Name.Buffer, DirInfo->Name.Length); 450 Ptr += NameLength; 451 Length += NameLength; 452 *Ptr = UNICODE_NULL; 453 Ptr++; 454 Length++; 455 } 456 457 RestartScan = FALSE; 458 } 459 460 NtClose(DirectoryHandle); 461 } 462 463 return Length; 464 } 465 466 /* EOF */ 467