Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

dev2dos.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 dev2dos.c 00008 00009 Abstract: 00010 00011 This module implements the device object to DOS name routine. 00012 00013 Author: 00014 00015 Norbert Kusters (norbertk) 21-Oct-1998 00016 00017 Environment: 00018 00019 Kernel Mode. 00020 00021 Revision History: 00022 00023 --*/ 00024 00025 #include <ntrtlp.h> 00026 #include <mountdev.h> 00027 00028 #ifdef POOL_TAGGING 00029 #undef ExAllocatePool 00030 #undef ExAllocatePoolWithQuota 00031 #define ExAllocatePool(a,b) ExAllocatePoolWithTag(a,b,' d2D') 00032 #define ExAllocatePoolWithQuota(a,b) ExAllocatePoolWithQuotaTag(a,b,' d2D') 00033 #endif 00034 00035 NTSTATUS 00036 QuerySymbolicLink( 00037 IN PUNICODE_STRING SymbolicLinkName, 00038 OUT PUNICODE_STRING LinkTarget 00039 ); 00040 00041 NTSTATUS 00042 QueryDeviceNameForPath( 00043 IN PUNICODE_STRING Path, 00044 OUT PUNICODE_STRING DeviceName 00045 ); 00046 00047 NTSTATUS 00048 OpenDeviceReparseIndex( 00049 IN PUNICODE_STRING DeviceName, 00050 OUT PHANDLE Handle 00051 ); 00052 00053 BOOLEAN 00054 IsVolumeName( 00055 IN PUNICODE_STRING Name 00056 ); 00057 00058 NTSTATUS 00059 GetNextReparseVolumePath( 00060 IN HANDLE Handle, 00061 OUT PUNICODE_STRING Path 00062 ); 00063 00064 NTSTATUS 00065 FindPathForDevice( 00066 IN PUNICODE_STRING StartingPath, 00067 IN PUNICODE_STRING DeviceName, 00068 IN OUT PLIST_ENTRY DevicesInPath, 00069 OUT PUNICODE_STRING FinalPath 00070 ); 00071 00072 NTSTATUS 00073 RtlVolumeDeviceToDosName( 00074 IN PVOID VolumeDeviceObject, 00075 OUT PUNICODE_STRING DosName 00076 ); 00077 00078 #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME) 00079 #pragma alloc_text(PAGE,QuerySymbolicLink) 00080 #pragma alloc_text(PAGE,QueryDeviceNameForPath) 00081 #pragma alloc_text(PAGE,OpenDeviceReparseIndex) 00082 #pragma alloc_text(PAGE,IsVolumeName) 00083 #pragma alloc_text(PAGE,GetNextReparseVolumePath) 00084 #pragma alloc_text(PAGE,FindPathForDevice) 00085 #pragma alloc_text(PAGE,RtlVolumeDeviceToDosName) 00086 #endif 00087 00088 typedef struct _DEVICE_NAME_ENTRY { 00089 LIST_ENTRY ListEntry; 00090 UNICODE_STRING DeviceName; 00091 } DEVICE_NAME_ENTRY, *PDEVICE_NAME_ENTRY; 00092 00093 NTSTATUS 00094 QuerySymbolicLink( 00095 IN PUNICODE_STRING SymbolicLinkName, 00096 OUT PUNICODE_STRING LinkTarget 00097 ) 00098 00099 /*++ 00100 00101 Routine Description: 00102 00103 This routine returns the target of the symbolic link name. 00104 00105 Arguments: 00106 00107 SymbolicLinkName - Supplies the symbolic link name. 00108 00109 LinkTarget - Returns the link target. 00110 00111 Return Value: 00112 00113 NTSTATUS 00114 00115 --*/ 00116 00117 { 00118 OBJECT_ATTRIBUTES oa; 00119 NTSTATUS status; 00120 HANDLE h; 00121 00122 InitializeObjectAttributes(&oa, SymbolicLinkName, OBJ_CASE_INSENSITIVE, 00123 0, 0); 00124 00125 status = ZwOpenSymbolicLinkObject(&h, GENERIC_READ, &oa); 00126 if (!NT_SUCCESS(status)) { 00127 return status; 00128 } 00129 00130 LinkTarget->MaximumLength = 200*sizeof(WCHAR); 00131 LinkTarget->Length = 0; 00132 LinkTarget->Buffer = ExAllocatePool(PagedPool, LinkTarget->MaximumLength); 00133 if (!LinkTarget->Buffer) { 00134 ZwClose(h); 00135 return STATUS_INSUFFICIENT_RESOURCES; 00136 } 00137 00138 status = ZwQuerySymbolicLinkObject(h, LinkTarget, NULL); 00139 ZwClose(h); 00140 00141 if (!NT_SUCCESS(status)) { 00142 ExFreePool(LinkTarget->Buffer); 00143 } 00144 00145 return status; 00146 } 00147 00148 NTSTATUS 00149 QueryDeviceNameForPath( 00150 IN PUNICODE_STRING Path, 00151 OUT PUNICODE_STRING DeviceName 00152 ) 00153 00154 /*++ 00155 00156 Routine Description: 00157 00158 This routine returns the device name for the given path. It first checks 00159 to see if the path is a symbolic link and then checks to see if it is a 00160 volume reparse point. 00161 00162 Arguments: 00163 00164 Path - Supplies the path. 00165 00166 DeviceName - Returns the device name. 00167 00168 Return Value: 00169 00170 NTSTATUS 00171 00172 --*/ 00173 00174 { 00175 NTSTATUS status; 00176 OBJECT_ATTRIBUTES oa; 00177 HANDLE h; 00178 IO_STATUS_BLOCK ioStatus; 00179 PREPARSE_DATA_BUFFER reparse; 00180 UNICODE_STRING volumeName; 00181 00182 status = QuerySymbolicLink(Path, DeviceName); 00183 if (NT_SUCCESS(status)) { 00184 return status; 00185 } 00186 00187 InitializeObjectAttributes(&oa, Path, OBJ_CASE_INSENSITIVE, 0, 0); 00188 status = ZwOpenFile(&h, SYNCHRONIZE | FILE_GENERIC_READ, &oa, &ioStatus, 00189 FILE_SHARE_READ | FILE_SHARE_WRITE, 00190 FILE_OPEN_REPARSE_POINT | FILE_SYNCHRONOUS_IO_ALERT); 00191 if (!NT_SUCCESS(status)) { 00192 return status; 00193 } 00194 00195 reparse = ExAllocatePool(PagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 00196 if (!reparse) { 00197 ZwClose(h); 00198 return STATUS_INSUFFICIENT_RESOURCES; 00199 } 00200 00201 status = ZwFsControlFile(h, NULL, NULL, NULL, &ioStatus, 00202 FSCTL_GET_REPARSE_POINT, NULL, 0, reparse, 00203 MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 00204 ZwClose(h); 00205 if (!NT_SUCCESS(status)) { 00206 ExFreePool(reparse); 00207 return status; 00208 } 00209 00210 volumeName.Length = reparse->MountPointReparseBuffer.SubstituteNameLength - 00211 sizeof(WCHAR); 00212 volumeName.MaximumLength = volumeName.Length + sizeof(WCHAR); 00213 volumeName.Buffer = (PWCHAR) 00214 ((PCHAR) reparse->MountPointReparseBuffer.PathBuffer + 00215 reparse->MountPointReparseBuffer.SubstituteNameOffset); 00216 volumeName.Buffer[volumeName.Length/sizeof(WCHAR)] = 0; 00217 00218 status = QuerySymbolicLink(&volumeName, DeviceName); 00219 ExFreePool(reparse); 00220 00221 return status; 00222 } 00223 00224 NTSTATUS 00225 OpenDeviceReparseIndex( 00226 IN PUNICODE_STRING DeviceName, 00227 OUT PHANDLE Handle 00228 ) 00229 00230 /*++ 00231 00232 Routine Description: 00233 00234 This routine opens the reparse index on the given device. 00235 00236 Arguments: 00237 00238 DeviceName - Supplies the device name. 00239 00240 Handle - Returns the handle. 00241 00242 Return Value: 00243 00244 NTSTATUS 00245 00246 --*/ 00247 00248 { 00249 NTSTATUS status; 00250 PFILE_OBJECT fileObject; 00251 PDEVICE_OBJECT deviceObject; 00252 UNICODE_STRING reparseSuffix, reparseName; 00253 OBJECT_ATTRIBUTES oa; 00254 IO_STATUS_BLOCK ioStatus; 00255 00256 status = IoGetDeviceObjectPointer(DeviceName, FILE_READ_ATTRIBUTES, 00257 &fileObject, &deviceObject); 00258 if (!NT_SUCCESS(status)) { 00259 return status; 00260 } 00261 deviceObject = fileObject->DeviceObject; 00262 00263 if (!deviceObject->Vpb || !(deviceObject->Vpb->Flags&VPB_MOUNTED)) { 00264 ObDereferenceObject(fileObject); 00265 return STATUS_UNSUCCESSFUL; 00266 } 00267 00268 ObDereferenceObject(fileObject); 00269 00270 RtlInitUnicodeString(&reparseSuffix, 00271 L"\\$Extend\\$Reparse:$R:$INDEX_ALLOCATION"); 00272 reparseName.Length = DeviceName->Length + reparseSuffix.Length; 00273 reparseName.MaximumLength = reparseName.Length + sizeof(WCHAR); 00274 reparseName.Buffer = ExAllocatePool(PagedPool, reparseName.MaximumLength); 00275 if (!reparseName.Buffer) { 00276 return STATUS_INSUFFICIENT_RESOURCES; 00277 } 00278 00279 RtlCopyMemory(reparseName.Buffer, DeviceName->Buffer, DeviceName->Length); 00280 RtlCopyMemory((PCHAR) reparseName.Buffer + DeviceName->Length, 00281 reparseSuffix.Buffer, reparseSuffix.Length); 00282 reparseName.Buffer[reparseName.Length/sizeof(WCHAR)] = 0; 00283 00284 InitializeObjectAttributes(&oa, &reparseName, OBJ_CASE_INSENSITIVE, 0, 0); 00285 status = ZwOpenFile(Handle, SYNCHRONIZE | FILE_LIST_DIRECTORY, &oa, 00286 &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE, 00287 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT | 00288 FILE_OPEN_FOR_BACKUP_INTENT); 00289 00290 ExFreePool(reparseName.Buffer); 00291 00292 return status; 00293 } 00294 00295 BOOLEAN 00296 IsVolumeName( 00297 IN PUNICODE_STRING Name 00298 ) 00299 00300 { 00301 if (Name->Length == 96 && 00302 Name->Buffer[0] == '\\' && 00303 Name->Buffer[1] == '?' && 00304 Name->Buffer[2] == '?' && 00305 Name->Buffer[3] == '\\' && 00306 Name->Buffer[4] == 'V' && 00307 Name->Buffer[5] == 'o' && 00308 Name->Buffer[6] == 'l' && 00309 Name->Buffer[7] == 'u' && 00310 Name->Buffer[8] == 'm' && 00311 Name->Buffer[9] == 'e' && 00312 Name->Buffer[10] == '{' && 00313 Name->Buffer[19] == '-' && 00314 Name->Buffer[24] == '-' && 00315 Name->Buffer[29] == '-' && 00316 Name->Buffer[34] == '-' && 00317 Name->Buffer[47] == '}') { 00318 00319 return TRUE; 00320 } 00321 00322 return FALSE; 00323 } 00324 00325 NTSTATUS 00326 GetNextReparseVolumePath( 00327 IN HANDLE Handle, 00328 OUT PUNICODE_STRING Path 00329 ) 00330 00331 /*++ 00332 00333 Routine Description: 00334 00335 This routine queries the reparse index for the next volume mount point. 00336 00337 Arguments: 00338 00339 Handle - Supplies the handle. 00340 00341 Path - Returns the path. 00342 00343 00344 Return Value: 00345 00346 NTSTATUS 00347 00348 --*/ 00349 00350 { 00351 NTSTATUS status; 00352 IO_STATUS_BLOCK ioStatus; 00353 FILE_REPARSE_POINT_INFORMATION reparseInfo; 00354 UNICODE_STRING fileId; 00355 OBJECT_ATTRIBUTES oa; 00356 HANDLE h; 00357 PREPARSE_DATA_BUFFER reparse; 00358 UNICODE_STRING volumeName; 00359 ULONG nameInfoSize; 00360 PFILE_NAME_INFORMATION nameInfo; 00361 00362 for (;;) { 00363 00364 status = ZwQueryDirectoryFile(Handle, NULL, NULL, NULL, &ioStatus, 00365 &reparseInfo, sizeof(reparseInfo), 00366 FileReparsePointInformation, TRUE, NULL, 00367 FALSE); 00368 if (!NT_SUCCESS(status)) { 00369 return status; 00370 } 00371 00372 if (reparseInfo.Tag != IO_REPARSE_TAG_MOUNT_POINT) { 00373 continue; 00374 } 00375 00376 fileId.Length = sizeof(reparseInfo.FileReference); 00377 fileId.MaximumLength = fileId.Length; 00378 fileId.Buffer = (PWSTR) &reparseInfo.FileReference; 00379 00380 InitializeObjectAttributes(&oa, &fileId, 0, Handle, NULL); 00381 00382 status = ZwOpenFile(&h, SYNCHRONIZE | FILE_GENERIC_READ, &oa, 00383 &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE, 00384 FILE_OPEN_BY_FILE_ID | FILE_OPEN_REPARSE_POINT | 00385 FILE_SYNCHRONOUS_IO_ALERT); 00386 if (!NT_SUCCESS(status)) { 00387 continue; 00388 } 00389 00390 reparse = ExAllocatePool(PagedPool, MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 00391 if (!reparse) { 00392 ZwClose(h); 00393 return STATUS_INSUFFICIENT_RESOURCES; 00394 } 00395 00396 status = ZwFsControlFile(h, NULL, NULL, NULL, &ioStatus, 00397 FSCTL_GET_REPARSE_POINT, NULL, 0, reparse, 00398 MAXIMUM_REPARSE_DATA_BUFFER_SIZE); 00399 if (!NT_SUCCESS(status)) { 00400 ExFreePool(reparse); 00401 ZwClose(h); 00402 continue; 00403 } 00404 00405 volumeName.Length = reparse->MountPointReparseBuffer.SubstituteNameLength - 00406 sizeof(WCHAR); 00407 volumeName.MaximumLength = volumeName.Length + sizeof(WCHAR); 00408 volumeName.Buffer = (PWCHAR) 00409 ((PCHAR) reparse->MountPointReparseBuffer.PathBuffer + 00410 reparse->MountPointReparseBuffer.SubstituteNameOffset); 00411 volumeName.Buffer[volumeName.Length/sizeof(WCHAR)] = 0; 00412 00413 if (!IsVolumeName(&volumeName)) { 00414 ExFreePool(reparse); 00415 ZwClose(h); 00416 continue; 00417 } 00418 00419 ExFreePool(reparse); 00420 00421 nameInfoSize = 1024; 00422 nameInfo = ExAllocatePool(PagedPool, nameInfoSize); 00423 if (!nameInfo) { 00424 ZwClose(h); 00425 continue; 00426 } 00427 00428 status = ZwQueryInformationFile(h, &ioStatus, nameInfo, nameInfoSize, 00429 FileNameInformation); 00430 ZwClose(h); 00431 if (!NT_SUCCESS(status)) { 00432 continue; 00433 } 00434 00435 Path->Length = (USHORT) nameInfo->FileNameLength; 00436 Path->MaximumLength = Path->Length + sizeof(WCHAR); 00437 Path->Buffer = ExAllocatePool(PagedPool, Path->MaximumLength); 00438 if (!Path->Buffer) { 00439 ExFreePool(nameInfo); 00440 continue; 00441 } 00442 00443 RtlCopyMemory(Path->Buffer, nameInfo->FileName, Path->Length); 00444 Path->Buffer[Path->Length/sizeof(WCHAR)] = 0; 00445 00446 ExFreePool(nameInfo); 00447 break; 00448 } 00449 00450 return status; 00451 } 00452 00453 NTSTATUS 00454 FindPathForDevice( 00455 IN PUNICODE_STRING StartingPath, 00456 IN PUNICODE_STRING DeviceName, 00457 IN OUT PLIST_ENTRY DevicesInPath, 00458 OUT PUNICODE_STRING FinalPath 00459 ) 00460 00461 /*++ 00462 00463 Routine Description: 00464 00465 This routine finds a path (if any) to the given device that begins 00466 with the given starting path. The final path returned includes the 00467 starting path. 00468 00469 Arguments: 00470 00471 StartingPath - Supplies the path to begin the search on. 00472 00473 DeviceName - Supplies the device name whose path we are searching for. 00474 00475 DevicesInPath - Supplies a list of the devices in all proper prefixes 00476 of the path. 00477 00478 FinalPath - Returns the final path to the given device. 00479 00480 Return Value: 00481 00482 NTSTATUS 00483 00484 --*/ 00485 00486 { 00487 NTSTATUS status; 00488 UNICODE_STRING startingDeviceName; 00489 PLIST_ENTRY l; 00490 PDEVICE_NAME_ENTRY entry; 00491 HANDLE h; 00492 UNICODE_STRING path, newStart; 00493 00494 status = QueryDeviceNameForPath(StartingPath, &startingDeviceName); 00495 if (!NT_SUCCESS(status)) { 00496 return status; 00497 } 00498 00499 if (RtlEqualUnicodeString(DeviceName, &startingDeviceName, TRUE)) { 00500 ExFreePool(startingDeviceName.Buffer); 00501 FinalPath->Length = StartingPath->Length; 00502 FinalPath->MaximumLength = FinalPath->Length + sizeof(WCHAR); 00503 FinalPath->Buffer = ExAllocatePool(PagedPool, 00504 FinalPath->MaximumLength); 00505 if (!FinalPath->Buffer) { 00506 return STATUS_INSUFFICIENT_RESOURCES; 00507 } 00508 00509 RtlCopyMemory(FinalPath->Buffer, StartingPath->Buffer, 00510 FinalPath->Length); 00511 FinalPath->Buffer[FinalPath->Length/sizeof(WCHAR)] = 0; 00512 00513 return STATUS_SUCCESS; 00514 } 00515 00516 for (l = DevicesInPath->Flink; l != DevicesInPath; l = l->Flink) { 00517 entry = CONTAINING_RECORD(l, DEVICE_NAME_ENTRY, ListEntry); 00518 if (RtlEqualUnicodeString(&entry->DeviceName, &startingDeviceName, 00519 TRUE)) { 00520 00521 ExFreePool(startingDeviceName.Buffer); 00522 return STATUS_UNSUCCESSFUL; 00523 } 00524 } 00525 00526 status = OpenDeviceReparseIndex(&startingDeviceName, &h); 00527 if (!NT_SUCCESS(status)) { 00528 ExFreePool(startingDeviceName.Buffer); 00529 return status; 00530 } 00531 00532 entry = ExAllocatePool(PagedPool, sizeof(DEVICE_NAME_ENTRY)); 00533 if (!entry) { 00534 ZwClose(h); 00535 ExFreePool(startingDeviceName.Buffer); 00536 return STATUS_INSUFFICIENT_RESOURCES; 00537 } 00538 entry->DeviceName = startingDeviceName; 00539 InsertTailList(DevicesInPath, &entry->ListEntry); 00540 00541 for (;;) { 00542 00543 status = GetNextReparseVolumePath(h, &path); 00544 if (!NT_SUCCESS(status)) { 00545 break; 00546 } 00547 newStart.Length = StartingPath->Length + path.Length; 00548 newStart.MaximumLength = newStart.Length + sizeof(WCHAR); 00549 newStart.Buffer = ExAllocatePool(PagedPool, newStart.MaximumLength); 00550 if (!newStart.Buffer) { 00551 ExFreePool(path.Buffer); 00552 status = STATUS_INSUFFICIENT_RESOURCES; 00553 break; 00554 } 00555 00556 RtlCopyMemory(newStart.Buffer, StartingPath->Buffer, 00557 StartingPath->Length); 00558 RtlCopyMemory((PCHAR) newStart.Buffer + StartingPath->Length, 00559 path.Buffer, path.Length); 00560 newStart.Buffer[newStart.Length/sizeof(WCHAR)] = 0; 00561 ExFreePool(path.Buffer); 00562 00563 status = FindPathForDevice(&newStart, DeviceName, DevicesInPath, 00564 FinalPath); 00565 ExFreePool(newStart.Buffer); 00566 if (NT_SUCCESS(status)) { 00567 break; 00568 } 00569 } 00570 00571 RemoveEntryList(&entry->ListEntry); 00572 ExFreePool(entry); 00573 ZwClose(h); 00574 ExFreePool(startingDeviceName.Buffer); 00575 00576 return status; 00577 } 00578 00579 NTSTATUS 00580 RtlVolumeDeviceToDosName( 00581 IN PVOID VolumeDeviceObject, 00582 OUT PUNICODE_STRING DosName 00583 ) 00584 00585 /*++ 00586 00587 Routine Description: 00588 00589 This routine returns a valid DOS path for the given device object. 00590 This caller of this routine must call ExFreePool on DosName->Buffer 00591 when it is no longer needed. 00592 00593 Arguments: 00594 00595 VolumeDeviceObject - Supplies the volume device object. 00596 00597 DosName - Returns the DOS name for the volume 00598 00599 Return Value: 00600 00601 NTSTATUS 00602 00603 --*/ 00604 00605 { 00606 PDEVICE_OBJECT volumeDeviceObject = VolumeDeviceObject; 00607 PMOUNTDEV_NAME name; 00608 CHAR output[512]; 00609 KEVENT event; 00610 PIRP irp; 00611 IO_STATUS_BLOCK ioStatus; 00612 NTSTATUS status; 00613 UNICODE_STRING deviceName; 00614 WCHAR buffer[30]; 00615 UNICODE_STRING driveLetterName; 00616 WCHAR c; 00617 UNICODE_STRING linkTarget; 00618 LIST_ENTRY devicesInPath; 00619 00620 name = (PMOUNTDEV_NAME) output; 00621 KeInitializeEvent(&event, NotificationEvent, FALSE); 00622 irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME, 00623 volumeDeviceObject, NULL, 0, name, 512, 00624 FALSE, &event, &ioStatus); 00625 if (!irp) { 00626 return STATUS_INSUFFICIENT_RESOURCES; 00627 } 00628 00629 status = IoCallDriver(volumeDeviceObject, irp); 00630 if (status == STATUS_PENDING) { 00631 KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL); 00632 status = ioStatus.Status; 00633 } 00634 00635 if (!NT_SUCCESS(status)) { 00636 return status; 00637 } 00638 00639 deviceName.MaximumLength = deviceName.Length = name->NameLength; 00640 deviceName.Buffer = name->Name; 00641 00642 swprintf(buffer, L"\\??\\C:"); 00643 RtlInitUnicodeString(&driveLetterName, buffer); 00644 00645 for (c = 'A'; c <= 'Z'; c++) { 00646 driveLetterName.Buffer[4] = c; 00647 00648 status = QuerySymbolicLink(&driveLetterName, &linkTarget); 00649 if (!NT_SUCCESS(status)) { 00650 continue; 00651 } 00652 00653 if (RtlEqualUnicodeString(&linkTarget, &deviceName, TRUE)) { 00654 ExFreePool(linkTarget.Buffer); 00655 break; 00656 } 00657 00658 ExFreePool(linkTarget.Buffer); 00659 } 00660 00661 if (c <= 'Z') { 00662 DosName->Buffer = ExAllocatePool(PagedPool, 3*sizeof(WCHAR)); 00663 if (!DosName->Buffer) { 00664 return STATUS_INSUFFICIENT_RESOURCES; 00665 } 00666 DosName->MaximumLength = 6; 00667 DosName->Length = 4; 00668 DosName->Buffer[0] = c; 00669 DosName->Buffer[1] = ':'; 00670 DosName->Buffer[2] = 0; 00671 return STATUS_SUCCESS; 00672 } 00673 00674 for (c = 'A'; c <= 'Z'; c++) { 00675 driveLetterName.Buffer[4] = c; 00676 InitializeListHead(&devicesInPath); 00677 status = FindPathForDevice(&driveLetterName, &deviceName, 00678 &devicesInPath, DosName); 00679 00680 if (NT_SUCCESS(status)) { 00681 DosName->Length -= 4*sizeof(WCHAR); 00682 RtlMoveMemory(DosName->Buffer, &DosName->Buffer[4], 00683 DosName->Length); 00684 DosName->Buffer[DosName->Length/sizeof(WCHAR)] = 0; 00685 return status; 00686 } 00687 } 00688 00689 return status; 00690 }

Generated on Sat May 15 19:39:40 2004 for test by doxygen 1.3.7