Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenoblink.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ob/oblink.c 00005 * PURPOSE: Implements symbolic links 00006 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) 00007 * David Welch (welch@mcmail.com) 00008 */ 00009 00010 /* INCLUDES *****************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 /* GLOBALS ******************************************************************/ 00017 00018 POBJECT_TYPE ObSymbolicLinkType = NULL; 00019 00020 /* PRIVATE FUNCTIONS *********************************************************/ 00021 00022 VOID 00023 NTAPI 00024 ObpDeleteSymbolicLinkName(IN POBJECT_SYMBOLIC_LINK SymbolicLink) 00025 { 00026 POBJECT_HEADER ObjectHeader; 00027 POBJECT_HEADER_NAME_INFO ObjectNameInfo; 00028 00029 /* FIXME: Need to support Device maps */ 00030 00031 /* Get header data */ 00032 ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink); 00033 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader); 00034 00035 /* Check if we are not actually in a directory with a device map */ 00036 if (!(ObjectNameInfo) || 00037 !(ObjectNameInfo->Directory) /*|| 00038 !(ObjectNameInfo->Directory->DeviceMap)*/) 00039 { 00040 ObpDereferenceNameInfo(ObjectNameInfo); 00041 return; 00042 } 00043 00044 /* Check if it's a DOS drive letter, and remove the entry from drive map if needed */ 00045 if (SymbolicLink->DosDeviceDriveIndex != 0 && 00046 ObjectNameInfo->Name.Length == 2 * sizeof(WCHAR) && 00047 ObjectNameInfo->Name.Buffer[1] == L':' && 00048 ( (ObjectNameInfo->Name.Buffer[0] >= L'A' && 00049 ObjectNameInfo->Name.Buffer[0] <= L'Z') || 00050 (ObjectNameInfo->Name.Buffer[0] >= L'a' && 00051 ObjectNameInfo->Name.Buffer[0] <= L'z') )) 00052 { 00053 /* Remove the drive entry */ 00054 KeAcquireGuardedMutex(&ObpDeviceMapLock); 00055 ObSystemDeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex-1] = 00056 DOSDEVICE_DRIVE_UNKNOWN; 00057 ObSystemDeviceMap->DriveMap &= 00058 ~(1 << (SymbolicLink->DosDeviceDriveIndex-1)); 00059 KeReleaseGuardedMutex(&ObpDeviceMapLock); 00060 00061 /* Reset the drive index, valid drive index starts from 1 */ 00062 SymbolicLink->DosDeviceDriveIndex = 0; 00063 } 00064 00065 ObpDereferenceNameInfo(ObjectNameInfo); 00066 } 00067 00068 NTSTATUS 00069 NTAPI 00070 ObpParseSymbolicLinkToIoDeviceObject(IN POBJECT_DIRECTORY SymbolicLinkDirectory, 00071 IN OUT POBJECT_DIRECTORY *Directory, 00072 IN OUT PUNICODE_STRING TargetPath, 00073 IN OUT POBP_LOOKUP_CONTEXT Context, 00074 OUT PVOID *Object) 00075 { 00076 UNICODE_STRING Name; 00077 BOOLEAN ManualUnlock; 00078 00079 if (! TargetPath || ! Object || ! Context || ! Directory || 00080 ! SymbolicLinkDirectory) 00081 { 00082 return STATUS_INVALID_PARAMETER; 00083 } 00084 00085 /* FIXME: Need to support Device maps */ 00086 00087 /* Try walking the target path and open each part of the path */ 00088 while (TargetPath->Length) 00089 { 00090 /* Strip '\' if present at the beginning of the target path */ 00091 if (TargetPath->Length >= sizeof(OBJ_NAME_PATH_SEPARATOR)&& 00092 TargetPath->Buffer[0] == OBJ_NAME_PATH_SEPARATOR) 00093 { 00094 TargetPath->Buffer++; 00095 TargetPath->Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); 00096 } 00097 00098 /* Remember the current component of the target path */ 00099 Name = *TargetPath; 00100 00101 /* Move forward to the next component of the target path */ 00102 while (TargetPath->Length >= sizeof(OBJ_NAME_PATH_SEPARATOR)) 00103 { 00104 if (TargetPath->Buffer[0] != OBJ_NAME_PATH_SEPARATOR) 00105 { 00106 TargetPath->Buffer++; 00107 TargetPath->Length -= sizeof(OBJ_NAME_PATH_SEPARATOR); 00108 } 00109 else 00110 break; 00111 } 00112 00113 Name.Length -= TargetPath->Length; 00114 00115 /* Finished processing the entire path, stop */ 00116 if (! Name.Length) 00117 break; 00118 00119 /* 00120 * Make sure a deadlock does not occur as an exclusive lock on a pushlock 00121 * would have already taken one in ObpLookupObjectName() on the parent 00122 * directory where the symlink is being created [ObInsertObject()]. 00123 * Prevent recursive locking by faking lock state in the lookup context 00124 * when the current directory is same as the parent directory where 00125 * the symlink is being created. If the lock state is not faked, 00126 * ObpLookupEntryDirectory() will try to get a recursive lock on the 00127 * pushlock and hang. For e.g. this happens when a substed drive is pointed to 00128 * another substed drive. 00129 */ 00130 if (*Directory == SymbolicLinkDirectory && ! Context->DirectoryLocked) 00131 { 00132 /* Fake lock state so that ObpLookupEntryDirectory() doesn't attempt a lock */ 00133 ManualUnlock = TRUE; 00134 Context->DirectoryLocked = TRUE; 00135 } 00136 else 00137 ManualUnlock = FALSE; 00138 00139 *Object = ObpLookupEntryDirectory(*Directory, 00140 &Name, 00141 0, 00142 FALSE, 00143 Context); 00144 00145 /* Locking was faked, undo it now */ 00146 if (*Directory == SymbolicLinkDirectory && ManualUnlock) 00147 Context->DirectoryLocked = FALSE; 00148 00149 /* Lookup failed, stop */ 00150 if (! *Object) 00151 break; 00152 00153 if (OBJECT_TO_OBJECT_HEADER(*Object)->Type == ObDirectoryType) 00154 { 00155 /* Make this current directory, and continue search */ 00156 *Directory = (POBJECT_DIRECTORY)*Object; 00157 } 00158 else if (OBJECT_TO_OBJECT_HEADER(*Object)->Type == ObSymbolicLinkType && 00159 (((POBJECT_SYMBOLIC_LINK)*Object)->DosDeviceDriveIndex == 0)) 00160 { 00161 /* Symlink points to another initialized symlink, ask caller to reparse */ 00162 *Directory = ObpRootDirectoryObject; 00163 TargetPath = &((POBJECT_SYMBOLIC_LINK)*Object)->LinkTarget; 00164 return STATUS_REPARSE_OBJECT; 00165 } 00166 else 00167 { 00168 /* Neither directory or symlink, stop */ 00169 break; 00170 } 00171 } 00172 00173 /* Return a valid object, only if object type is IoDeviceObject */ 00174 if (*Object && 00175 OBJECT_TO_OBJECT_HEADER(*Object)->Type != IoDeviceObjectType) 00176 { 00177 *Object = NULL; 00178 } 00179 return STATUS_SUCCESS; 00180 } 00181 00182 VOID 00183 NTAPI 00184 ObpCreateSymbolicLinkName(IN POBJECT_SYMBOLIC_LINK SymbolicLink) 00185 { 00186 POBJECT_HEADER ObjectHeader; 00187 POBJECT_HEADER_NAME_INFO ObjectNameInfo; 00188 PVOID Object = NULL; 00189 POBJECT_DIRECTORY Directory; 00190 UNICODE_STRING TargetPath; 00191 NTSTATUS Status; 00192 ULONG DriveType = DOSDEVICE_DRIVE_CALCULATE; 00193 ULONG ReparseCnt; 00194 const ULONG MaxReparseAttempts = 20; 00195 OBP_LOOKUP_CONTEXT Context; 00196 00197 /* FIXME: Need to support Device maps */ 00198 00199 /* Get header data */ 00200 ObjectHeader = OBJECT_TO_OBJECT_HEADER(SymbolicLink); 00201 ObjectNameInfo = ObpReferenceNameInfo(ObjectHeader); 00202 00203 /* Check if we are not actually in a directory with a device map */ 00204 if (!(ObjectNameInfo) || 00205 !(ObjectNameInfo->Directory) /*|| 00206 !(ObjectNameInfo->Directory->DeviceMap)*/) 00207 { 00208 ObpDereferenceNameInfo(ObjectNameInfo); 00209 return; 00210 } 00211 00212 /* Check if it's a DOS drive letter, and set the drive index accordingly */ 00213 if (ObjectNameInfo->Name.Length == 2 * sizeof(WCHAR) && 00214 ObjectNameInfo->Name.Buffer[1] == L':' && 00215 ( (ObjectNameInfo->Name.Buffer[0] >= L'A' && 00216 ObjectNameInfo->Name.Buffer[0] <= L'Z') || 00217 (ObjectNameInfo->Name.Buffer[0] >= L'a' && 00218 ObjectNameInfo->Name.Buffer[0] <= L'z') )) 00219 { 00220 SymbolicLink->DosDeviceDriveIndex = 00221 RtlUpcaseUnicodeChar(ObjectNameInfo->Name.Buffer[0]) - L'A'; 00222 /* The Drive index start from 1 */ 00223 SymbolicLink->DosDeviceDriveIndex++; 00224 00225 /* Initialize lookup context */ 00226 ObpInitializeLookupContext(&Context); 00227 00228 /* Start the search from the root */ 00229 Directory = ObpRootDirectoryObject; 00230 TargetPath = SymbolicLink->LinkTarget; 00231 00232 /* 00233 * Locate the IoDeviceObject if any this symbolic link points to. 00234 * To prevent endless reparsing, setting an upper limit on the 00235 * number of reparses. 00236 */ 00237 Status = STATUS_REPARSE_OBJECT; 00238 ReparseCnt = 0; 00239 while (Status == STATUS_REPARSE_OBJECT && 00240 ReparseCnt < MaxReparseAttempts) 00241 { 00242 Status = 00243 ObpParseSymbolicLinkToIoDeviceObject(ObjectNameInfo->Directory, 00244 &Directory, 00245 &TargetPath, 00246 &Context, 00247 &Object); 00248 if (Status == STATUS_REPARSE_OBJECT) 00249 ReparseCnt++; 00250 } 00251 00252 /* Cleanup lookup context */ 00253 ObpReleaseLookupContext(&Context); 00254 00255 /* Error, or max resparse attemtps exceeded */ 00256 if (! NT_SUCCESS(Status) || ReparseCnt >= MaxReparseAttempts) 00257 { 00258 /* Cleanup */ 00259 ObpDereferenceNameInfo(ObjectNameInfo); 00260 return; 00261 } 00262 00263 if (Object) 00264 { 00265 /* Calculate the drive type */ 00266 switch(((PDEVICE_OBJECT)Object)->DeviceType) 00267 { 00268 case FILE_DEVICE_VIRTUAL_DISK: 00269 DriveType = DOSDEVICE_DRIVE_RAMDISK; 00270 break; 00271 case FILE_DEVICE_CD_ROM: 00272 case FILE_DEVICE_CD_ROM_FILE_SYSTEM: 00273 DriveType = DOSDEVICE_DRIVE_CDROM; 00274 break; 00275 case FILE_DEVICE_DISK: 00276 case FILE_DEVICE_DISK_FILE_SYSTEM: 00277 case FILE_DEVICE_FILE_SYSTEM: 00278 if (((PDEVICE_OBJECT)Object)->Characteristics & FILE_REMOVABLE_MEDIA) 00279 DriveType = DOSDEVICE_DRIVE_REMOVABLE; 00280 else 00281 DriveType = DOSDEVICE_DRIVE_FIXED; 00282 break; 00283 case FILE_DEVICE_NETWORK: 00284 case FILE_DEVICE_NETWORK_FILE_SYSTEM: 00285 DriveType = DOSDEVICE_DRIVE_REMOTE; 00286 break; 00287 default: 00288 DPRINT1("Device Type %ld for %wZ is not known or unhandled\n", 00289 ((PDEVICE_OBJECT)Object)->DeviceType, 00290 &SymbolicLink->LinkTarget); 00291 DriveType = DOSDEVICE_DRIVE_UNKNOWN; 00292 } 00293 } 00294 00295 /* Add a new drive entry */ 00296 KeAcquireGuardedMutex(&ObpDeviceMapLock); 00297 ObSystemDeviceMap->DriveType[SymbolicLink->DosDeviceDriveIndex-1] = 00298 (UCHAR)DriveType; 00299 ObSystemDeviceMap->DriveMap |= 00300 1 << (SymbolicLink->DosDeviceDriveIndex-1); 00301 KeReleaseGuardedMutex(&ObpDeviceMapLock); 00302 } 00303 00304 /* Cleanup */ 00305 ObpDereferenceNameInfo(ObjectNameInfo); 00306 } 00307 00308 /*++ 00309 * @name ObpDeleteSymbolicLink 00310 * 00311 * The ObpDeleteSymbolicLink routine <FILLMEIN> 00312 * 00313 * @param ObjectBody 00314 * <FILLMEIN> 00315 * 00316 * @return None. 00317 * 00318 * @remarks None. 00319 * 00320 *--*/ 00321 VOID 00322 NTAPI 00323 ObpDeleteSymbolicLink(PVOID ObjectBody) 00324 { 00325 POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ObjectBody; 00326 00327 /* Make sure that the symbolic link has a name */ 00328 if (SymlinkObject->LinkTarget.Buffer) 00329 { 00330 /* Free the name */ 00331 ExFreePool(SymlinkObject->LinkTarget.Buffer); 00332 SymlinkObject->LinkTarget.Buffer = NULL; 00333 } 00334 } 00335 00336 /*++ 00337 * @name ObpParseSymbolicLink 00338 * 00339 * The ObpParseSymbolicLink routine <FILLMEIN> 00340 * 00341 * @param Object 00342 * <FILLMEIN> 00343 * 00344 * @param NextObject 00345 * <FILLMEIN> 00346 * 00347 * @param FullPath 00348 * <FILLMEIN> 00349 * 00350 * @param RemainingPath 00351 * <FILLMEIN> 00352 * 00353 * @param Attributes 00354 * <FILLMEIN> 00355 * 00356 * @return STATUS_SUCCESS or appropriate error value. 00357 * 00358 * @remarks None. 00359 * 00360 *--*/ 00361 NTSTATUS 00362 NTAPI 00363 ObpParseSymbolicLink(IN PVOID ParsedObject, 00364 IN PVOID ObjectType, 00365 IN OUT PACCESS_STATE AccessState, 00366 IN KPROCESSOR_MODE AccessMode, 00367 IN ULONG Attributes, 00368 IN OUT PUNICODE_STRING FullPath, 00369 IN OUT PUNICODE_STRING RemainingName, 00370 IN OUT PVOID Context OPTIONAL, 00371 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL, 00372 OUT PVOID *NextObject) 00373 { 00374 POBJECT_SYMBOLIC_LINK SymlinkObject = (POBJECT_SYMBOLIC_LINK)ParsedObject; 00375 PUNICODE_STRING TargetPath; 00376 PWSTR NewTargetPath; 00377 ULONG LengthUsed, MaximumLength, TempLength; 00378 NTSTATUS Status; 00379 PAGED_CODE(); 00380 00381 /* Assume failure */ 00382 *NextObject = NULL; 00383 00384 /* Check if we're out of name to parse */ 00385 if (!RemainingName->Length) 00386 { 00387 /* Check if we got an object type */ 00388 if (ObjectType) 00389 { 00390 /* Reference the object only */ 00391 Status = ObReferenceObjectByPointer(ParsedObject, 00392 0, 00393 ObjectType, 00394 AccessMode); 00395 if (NT_SUCCESS(Status)) 00396 { 00397 /* Return it */ 00398 *NextObject = ParsedObject; 00399 } 00400 00401 if ((NT_SUCCESS(Status)) || (Status != STATUS_OBJECT_TYPE_MISMATCH)) 00402 { 00403 /* Fail */ 00404 return Status; 00405 } 00406 } 00407 } 00408 else if (RemainingName->Buffer[0] != OBJ_NAME_PATH_SEPARATOR) 00409 { 00410 /* Symbolic links must start with a backslash */ 00411 return STATUS_OBJECT_TYPE_MISMATCH; 00412 } 00413 00414 /* Check if this symlink is bound to a specific object */ 00415 if (SymlinkObject->LinkTargetObject) 00416 { 00417 UNIMPLEMENTED; 00418 } 00419 00420 /* Set the target path and length */ 00421 TargetPath = &SymlinkObject->LinkTarget; 00422 TempLength = TargetPath->Length; 00423 00424 /* 00425 * Strip off the extra trailing '\', if we don't do this we will end up 00426 * adding a extra '\' between TargetPath and RemainingName 00427 * causing caller's like ObpLookupObjectName() to fail. 00428 */ 00429 if (TempLength && RemainingName->Length) 00430 { 00431 /* The target and remaining names aren't empty, so check for slashes */ 00432 if ((TargetPath->Buffer[TempLength / sizeof(WCHAR) - 1] == 00433 OBJ_NAME_PATH_SEPARATOR) && 00434 (RemainingName->Buffer[0] == OBJ_NAME_PATH_SEPARATOR)) 00435 { 00436 /* Reduce the length by one to cut off the extra '\' */ 00437 TempLength -= sizeof(OBJ_NAME_PATH_SEPARATOR); 00438 } 00439 } 00440 00441 /* Calculate the new length */ 00442 LengthUsed = TempLength + RemainingName->Length; 00443 00444 /* Check if it's not too much */ 00445 if (LengthUsed > 0xFFF0) 00446 return STATUS_NAME_TOO_LONG; 00447 00448 /* Optimization: check if the new name is shorter */ 00449 if (FullPath->MaximumLength <= LengthUsed) 00450 { 00451 /* It's not, allocate a new one */ 00452 MaximumLength = LengthUsed + sizeof(WCHAR); 00453 NewTargetPath = ExAllocatePoolWithTag(NonPagedPool, 00454 MaximumLength, 00455 TAG_SYMLINK_TTARGET); 00456 if (!NewTargetPath) return STATUS_INSUFFICIENT_RESOURCES; 00457 } 00458 else 00459 { 00460 /* It is! Reuse the name... */ 00461 MaximumLength = FullPath->MaximumLength; 00462 NewTargetPath = FullPath->Buffer; 00463 } 00464 00465 /* Make sure we have a length */ 00466 if (RemainingName->Length) 00467 { 00468 /* Copy the new path */ 00469 RtlMoveMemory((PVOID)((ULONG_PTR)NewTargetPath + TempLength), 00470 RemainingName->Buffer, 00471 RemainingName->Length); 00472 } 00473 00474 /* Copy the target path and null-terminate it */ 00475 RtlCopyMemory(NewTargetPath, TargetPath->Buffer, TempLength); 00476 NewTargetPath[LengthUsed / sizeof(WCHAR)] = UNICODE_NULL; 00477 00478 /* If the optimization didn't work, free the old buffer */ 00479 if (NewTargetPath != FullPath->Buffer) ExFreePool(FullPath->Buffer); 00480 00481 /* Update the path values */ 00482 FullPath->Length = (USHORT)LengthUsed; 00483 FullPath->MaximumLength = (USHORT)MaximumLength; 00484 FullPath->Buffer = NewTargetPath; 00485 00486 /* Tell the parse routine to start reparsing */ 00487 return STATUS_REPARSE; 00488 } 00489 00490 /* PUBLIC FUNCTIONS **********************************************************/ 00491 00492 /*++ 00493 * @name NtCreateSymbolicLinkObject 00494 * @implemented NT4 00495 * 00496 * The NtCreateSymbolicLinkObject opens or creates a symbolic link object. 00497 * 00498 * @param LinkHandle 00499 * Variable which receives the symlink handle. 00500 * 00501 * @param DesiredAccess 00502 * Desired access to the symlink. 00503 * 00504 * @param ObjectAttributes 00505 * Structure describing the symlink. 00506 * 00507 * @param LinkTarget 00508 * Unicode string defining the symlink's target 00509 * 00510 * @return STATUS_SUCCESS or appropriate error value. 00511 * 00512 * @remarks None. 00513 * 00514 *--*/ 00515 NTSTATUS 00516 NTAPI 00517 NtCreateSymbolicLinkObject(OUT PHANDLE LinkHandle, 00518 IN ACCESS_MASK DesiredAccess, 00519 IN POBJECT_ATTRIBUTES ObjectAttributes, 00520 IN PUNICODE_STRING LinkTarget) 00521 { 00522 HANDLE hLink; 00523 POBJECT_SYMBOLIC_LINK SymbolicLink; 00524 UNICODE_STRING CapturedLinkTarget; 00525 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00526 NTSTATUS Status; 00527 PAGED_CODE(); 00528 00529 /* Check if we need to probe parameters */ 00530 if (PreviousMode != KernelMode) 00531 { 00532 _SEH2_TRY 00533 { 00534 /* Probe the target */ 00535 CapturedLinkTarget = ProbeForReadUnicodeString(LinkTarget); 00536 ProbeForRead(CapturedLinkTarget.Buffer, 00537 CapturedLinkTarget.MaximumLength, 00538 sizeof(WCHAR)); 00539 00540 /* Probe the return handle */ 00541 ProbeForWriteHandle(LinkHandle); 00542 } 00543 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00544 { 00545 /* Return the exception code */ 00546 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00547 } 00548 _SEH2_END; 00549 } 00550 else 00551 { 00552 /* No need to capture */ 00553 CapturedLinkTarget = *LinkTarget; 00554 } 00555 00556 /* Check if the maximum length is odd */ 00557 if (CapturedLinkTarget.MaximumLength % sizeof(WCHAR)) 00558 { 00559 /* Round it down */ 00560 CapturedLinkTarget.MaximumLength = 00561 (USHORT)ALIGN_DOWN(CapturedLinkTarget.MaximumLength, WCHAR); 00562 } 00563 00564 /* Fail if the length is odd, or if the maximum is smaller or 0 */ 00565 if ((CapturedLinkTarget.Length % sizeof(WCHAR)) || 00566 (CapturedLinkTarget.MaximumLength < CapturedLinkTarget.Length) || 00567 !(CapturedLinkTarget.MaximumLength)) 00568 { 00569 /* This message is displayed on the debugger in Windows */ 00570 DbgPrint("OB: Invalid symbolic link target - %wZ\n", 00571 &CapturedLinkTarget); 00572 return STATUS_INVALID_PARAMETER; 00573 } 00574 00575 /* Create the object */ 00576 Status = ObCreateObject(PreviousMode, 00577 ObSymbolicLinkType, 00578 ObjectAttributes, 00579 PreviousMode, 00580 NULL, 00581 sizeof(OBJECT_SYMBOLIC_LINK), 00582 0, 00583 0, 00584 (PVOID*)&SymbolicLink); 00585 if (NT_SUCCESS(Status)) 00586 { 00587 /* Success! Fill in the creation time immediately */ 00588 KeQuerySystemTime(&SymbolicLink->CreationTime); 00589 00590 /* Setup the target name */ 00591 SymbolicLink->LinkTarget.Length = CapturedLinkTarget.Length; 00592 SymbolicLink->LinkTarget.MaximumLength = CapturedLinkTarget.Length + 00593 sizeof(WCHAR); 00594 SymbolicLink->LinkTarget.Buffer = 00595 ExAllocatePoolWithTag(PagedPool, 00596 CapturedLinkTarget.MaximumLength, 00597 TAG_SYMLINK_TARGET); 00598 if (!SymbolicLink->LinkTarget.Buffer) return STATUS_NO_MEMORY; 00599 00600 /* Copy it */ 00601 RtlCopyMemory(SymbolicLink->LinkTarget.Buffer, 00602 CapturedLinkTarget.Buffer, 00603 CapturedLinkTarget.MaximumLength); 00604 00605 /* Initialize the remaining name, dos drive index and target object */ 00606 SymbolicLink->LinkTargetObject = NULL; 00607 SymbolicLink->DosDeviceDriveIndex = 0; 00608 RtlInitUnicodeString(&SymbolicLink->LinkTargetRemaining, NULL); 00609 00610 /* Insert it into the object tree */ 00611 Status = ObInsertObject(SymbolicLink, 00612 NULL, 00613 DesiredAccess, 00614 0, 00615 NULL, 00616 &hLink); 00617 if (NT_SUCCESS(Status)) 00618 { 00619 _SEH2_TRY 00620 { 00621 /* Return the handle to caller */ 00622 *LinkHandle = hLink; 00623 } 00624 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00625 { 00626 /* Get exception code */ 00627 Status = _SEH2_GetExceptionCode(); 00628 } 00629 _SEH2_END; 00630 } 00631 } 00632 00633 /* Return status to caller */ 00634 return Status; 00635 } 00636 00637 /*++ 00638 * @name NtOpenSymbolicLinkObject 00639 * @implemented NT4 00640 * 00641 * The NtOpenSymbolicLinkObject opens a symbolic link object. 00642 * 00643 * @param LinkHandle 00644 * Variable which receives the symlink handle. 00645 * 00646 * @param DesiredAccess 00647 * Desired access to the symlink. 00648 * 00649 * @param ObjectAttributes 00650 * Structure describing the symlink. 00651 * 00652 * @return STATUS_SUCCESS or appropriate error value. 00653 * 00654 * @remarks None. 00655 * 00656 *--*/ 00657 NTSTATUS 00658 NTAPI 00659 NtOpenSymbolicLinkObject(OUT PHANDLE LinkHandle, 00660 IN ACCESS_MASK DesiredAccess, 00661 IN POBJECT_ATTRIBUTES ObjectAttributes) 00662 { 00663 HANDLE hLink; 00664 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00665 NTSTATUS Status; 00666 PAGED_CODE(); 00667 00668 /* Check if we need to probe parameters */ 00669 if (PreviousMode != KernelMode) 00670 { 00671 _SEH2_TRY 00672 { 00673 /* Probe the return handle */ 00674 ProbeForWriteHandle(LinkHandle); 00675 } 00676 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00677 { 00678 /* Return the exception code */ 00679 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00680 } 00681 _SEH2_END; 00682 } 00683 00684 /* Open the object */ 00685 Status = ObOpenObjectByName(ObjectAttributes, 00686 ObSymbolicLinkType, 00687 PreviousMode, 00688 NULL, 00689 DesiredAccess, 00690 NULL, 00691 &hLink); 00692 if (NT_SUCCESS(Status)) 00693 { 00694 _SEH2_TRY 00695 { 00696 /* Return the handle to caller */ 00697 *LinkHandle = hLink; 00698 } 00699 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00700 { 00701 /* Get exception code */ 00702 Status = _SEH2_GetExceptionCode(); 00703 } 00704 _SEH2_END; 00705 } 00706 00707 /* Return status to caller */ 00708 return Status; 00709 } 00710 00711 /*++ 00712 * @name NtQuerySymbolicLinkObject 00713 * @implemented NT4 00714 * 00715 * The NtQuerySymbolicLinkObject queries a symbolic link object. 00716 * 00717 * @param LinkHandle 00718 * Symlink handle to query 00719 * 00720 * @param LinkTarget 00721 * Unicode string defining the symlink's target 00722 * 00723 * @param ResultLength 00724 * Caller supplied storage for the number of bytes written (or NULL). 00725 * 00726 * @return STATUS_SUCCESS or appropriate error value. 00727 * 00728 * @remarks None. 00729 * 00730 *--*/ 00731 NTSTATUS 00732 NTAPI 00733 NtQuerySymbolicLinkObject(IN HANDLE LinkHandle, 00734 OUT PUNICODE_STRING LinkTarget, 00735 OUT PULONG ResultLength OPTIONAL) 00736 { 00737 UNICODE_STRING SafeLinkTarget = { 0, 0, NULL }; 00738 POBJECT_SYMBOLIC_LINK SymlinkObject; 00739 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00740 NTSTATUS Status; 00741 ULONG LengthUsed; 00742 PAGED_CODE(); 00743 00744 if (PreviousMode != KernelMode) 00745 { 00746 _SEH2_TRY 00747 { 00748 /* Probe the unicode string for read and write */ 00749 ProbeForWriteUnicodeString(LinkTarget); 00750 00751 /* Probe the unicode string's buffer for write */ 00752 SafeLinkTarget = *LinkTarget; 00753 ProbeForWrite(SafeLinkTarget.Buffer, 00754 SafeLinkTarget.MaximumLength, 00755 sizeof(WCHAR)); 00756 00757 /* Probe the return length */ 00758 if (ResultLength) ProbeForWriteUlong(ResultLength); 00759 } 00760 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00761 { 00762 /* Return the exception code */ 00763 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00764 } 00765 _SEH2_END; 00766 } 00767 else 00768 { 00769 /* No need to probe */ 00770 SafeLinkTarget = *LinkTarget; 00771 } 00772 00773 /* Reference the object */ 00774 Status = ObReferenceObjectByHandle(LinkHandle, 00775 SYMBOLIC_LINK_QUERY, 00776 ObSymbolicLinkType, 00777 PreviousMode, 00778 (PVOID *)&SymlinkObject, 00779 NULL); 00780 if (NT_SUCCESS(Status)) 00781 { 00782 /* Lock the object */ 00783 ObpAcquireObjectLock(OBJECT_TO_OBJECT_HEADER(SymlinkObject)); 00784 00785 /* 00786 * So here's the thing: If you specify a return length, then the 00787 * implementation will use the maximum length. If you don't, then 00788 * it will use the length. 00789 */ 00790 LengthUsed = ResultLength ? SymlinkObject->LinkTarget.MaximumLength : 00791 SymlinkObject->LinkTarget.Length; 00792 00793 /* Enter SEH so we can safely copy */ 00794 _SEH2_TRY 00795 { 00796 /* Make sure our buffer will fit */ 00797 if (LengthUsed <= SafeLinkTarget.MaximumLength) 00798 { 00799 /* Copy the buffer */ 00800 RtlCopyMemory(SafeLinkTarget.Buffer, 00801 SymlinkObject->LinkTarget.Buffer, 00802 LengthUsed); 00803 00804 /* Copy the new length */ 00805 LinkTarget->Length = SymlinkObject->LinkTarget.Length; 00806 } 00807 else 00808 { 00809 /* Otherwise set the failure status */ 00810 Status = STATUS_BUFFER_TOO_SMALL; 00811 } 00812 00813 /* In both cases, check if the required length was requested */ 00814 if (ResultLength) 00815 { 00816 /* Then return it */ 00817 *ResultLength = SymlinkObject->LinkTarget.MaximumLength; 00818 } 00819 } 00820 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00821 { 00822 /* Get the error code */ 00823 Status = _SEH2_GetExceptionCode(); 00824 } 00825 _SEH2_END; 00826 00827 /* Unlock and dereference the object */ 00828 ObpReleaseObjectLock(OBJECT_TO_OBJECT_HEADER(SymlinkObject)); 00829 ObDereferenceObject(SymlinkObject); 00830 } 00831 00832 /* Return query status */ 00833 return Status; 00834 } 00835 00836 /* EOF */ Generated on Mon May 28 2012 04:37:34 for ReactOS by
1.7.6.1
|