ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

oblink.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.