test: oblink.c Source File

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

# oblink.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1989  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     oblink.c
    00008
    00009 Abstract:
    00010
    00011     Symbolic Link Object routines
    00012
    00013 Author:
    00014
    00015     Steve Wood (stevewo) 3-Aug-1989
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021 #include "obp.h"
    00022
    00023 #if defined(ALLOC_PRAGMA)
    00024 #pragma alloc_text(PAGE,NtCreateSymbolicLinkObject)
    00025 #pragma alloc_text(PAGE,NtOpenSymbolicLinkObject)
    00026 #pragma alloc_text(PAGE,NtQuerySymbolicLinkObject)
    00027 #pragma alloc_text(PAGE,ObpParseSymbolicLink)
    00028 #pragma alloc_text(PAGE,ObpDeleteSymbolicLink)
    00029 #endif
    00030
    00031 //
    00032 //  This is the object type for device objects.
    00033 //
    00034
    00035 extern POBJECT_TYPE IoDeviceObjectType;
    00036
    00037 //
    00038 //  Local procedure prototypes
    00039 //
    00040
    00041 #define CREATE_SYMBOLIC_LINK 0
    00042 #define DELETE_SYMBOLIC_LINK 1
    00043
    00044 VOID
    00045 ObpProcessDosDeviceSymbolicLink (
    00046     POBJECT_SYMBOLIC_LINK SymbolicLink,
    00047     ULONG Action
    00048     );
    00049
    00050
    00051 NTSTATUS
    00052 NtCreateSymbolicLinkObject (
    00053     OUT PHANDLE LinkHandle,
    00054     IN ACCESS_MASK DesiredAccess,
    00055     IN POBJECT_ATTRIBUTES ObjectAttributes,
    00056     IN PUNICODE_STRING LinkTarget
    00057     )
    00058
    00059 /*++
    00060
    00061 Routine Description:
    00062
    00063     This function creates a symbolic link object, sets it initial value to
    00064     value specified in the LinkTarget parameter, and opens a handle to the
    00065     object with the specified desired access.
    00066
    00067 Arguments:
    00068
    00069     LinkHandle - Supplies a pointer to a variable that will receive the
    00070         symbolic link object handle.
    00071
    00072     DesiredAccess - Supplies the desired types of access for the symbolic link
    00073         object.
    00074
    00075     ObjectAttributes - Supplies a pointer to an object attributes structure.
    00076
    00077     LinkTarget - Supplies the target name for the symbolic link object.
    00078
    00079 Return Value:
    00080
    00081     An appropriate status value
    00082
    00083 --*/
    00084
    00085 {
    00086     KPROCESSOR_MODE PreviousMode;
    00087     NTSTATUS Status;
    00088     POBJECT_SYMBOLIC_LINK SymbolicLink;
    00089     PVOID Object;
    00090     HANDLE Handle;
    00091     UNICODE_STRING CapturedLinkTarget;
    00092
    00093     PAGED_CODE();
    00094
    00095     //
    00096     //  Get previous processor mode and probe output arguments if necessary.
    00097     //
    00098
    00099     PreviousMode = KeGetPreviousMode();
    00100
    00101     if (PreviousMode != KernelMode) {
    00102
    00103         try {
    00104
    00105             //
    00106             //  **** we probably don't need to do this first one because
    00107             //  the ob create object will cause the probe to happen for us
    00108             //
    00109
    00110             ProbeForRead( ObjectAttributes,
    00111                           sizeof( OBJECT_ATTRIBUTES ),
    00112                           sizeof( ULONG ));
    00113
    00114             ProbeForRead( LinkTarget,
    00115                           sizeof( *LinkTarget ),
    00116                           sizeof( UCHAR ));
    00117
    00118             CapturedLinkTarget = *LinkTarget;
    00119
    00120             ProbeForRead( CapturedLinkTarget.Buffer,
    00121                           CapturedLinkTarget.MaximumLength,
    00122                           sizeof( UCHAR ));
    00123
    00124             ProbeForWriteHandle( LinkHandle );
    00125
    00126         } except( EXCEPTION_EXECUTE_HANDLER ) {
    00127
    00128             return( GetExceptionCode() );
    00129         }
    00130
    00131     } else {
    00132
    00133         CapturedLinkTarget = *LinkTarget;
    00134     }
    00135
    00136     //
    00137     //  Check if there is an odd MaximumLength
    00138     //
    00139
    00140     if (CapturedLinkTarget.MaximumLength % sizeof( WCHAR )) {
    00141
    00142         //
    00143         //  Round down the MaximumLength to a valid even size
    00144         //
    00145
    00146         CapturedLinkTarget.MaximumLength = (CapturedLinkTarget.MaximumLength / sizeof( WCHAR )) * sizeof( WCHAR );
    00147     }
    00148
    00149     //
    00150     //  Error if link target name length is odd, the length is greater than
    00151     //  the maximum length, or zero and creating.
    00152     //
    00153
    00154     if ((CapturedLinkTarget.MaximumLength == 0) ||
    00155         (CapturedLinkTarget.Length > CapturedLinkTarget.MaximumLength) ||
    00156         (CapturedLinkTarget.Length % sizeof( WCHAR ))) {
    00157
    00158         KdPrint(( "OB: Invalid symbolic link target - %wZ\n", &CapturedLinkTarget ));
    00159
    00160         return( STATUS_INVALID_PARAMETER );
    00161     }
    00162
    00163     //
    00164     //  Create the symbolic link object
    00165     //
    00166
    00167     Status = ObCreateObject( PreviousMode,
    00168                              ObpSymbolicLinkObjectType,
    00169                              ObjectAttributes,
    00170                              PreviousMode,
    00171                              NULL,
    00172                              sizeof( *SymbolicLink ),
    00173                              0,
    00174                              0,
    00175                              (PVOID *)&SymbolicLink );
    00176
    00177     if (!NT_SUCCESS( Status )) {
    00178
    00179         return( Status );
    00180     }
    00181
    00182     //
    00183     //  Fill in symbolic link object with link target name string
    00184     //
    00185
    00186     KeQuerySystemTime( &SymbolicLink->CreationTime );
    00187
    00188     SymbolicLink->DosDeviceDriveIndex = 0;
    00189     SymbolicLink->LinkTargetObject = NULL;
    00190
    00191     RtlInitUnicodeString( &SymbolicLink->LinkTargetRemaining,  NULL );
    00192
    00193     SymbolicLink->LinkTarget.MaximumLength = CapturedLinkTarget.MaximumLength;
    00194     SymbolicLink->LinkTarget.Length = CapturedLinkTarget.Length;
    00195     SymbolicLink->LinkTarget.Buffer = (PWCH)ExAllocatePoolWithTag( PagedPool,
    00196                                                                    CapturedLinkTarget.MaximumLength,
    00197                                                                    'tmyS' );
    00198
    00199     if (SymbolicLink->LinkTarget.Buffer == NULL) {
    00200
    00201         ObDereferenceObject( SymbolicLink );
    00202
    00203         return STATUS_NO_MEMORY;
    00204     }
    00205
    00206     try {
    00207
    00208         RtlMoveMemory( SymbolicLink->LinkTarget.Buffer,
    00209                        CapturedLinkTarget.Buffer,
    00210                        CapturedLinkTarget.MaximumLength );
    00211
    00212     } except( EXCEPTION_EXECUTE_HANDLER ) {
    00213
    00214         ObDereferenceObject( SymbolicLink );
    00215
    00216         return( GetExceptionCode() );
    00217     }
    00218
    00219     //
    00220     //  Insert symbolic link object in the current processes object table,
    00221     //  set symbolic link handle value and return status.
    00222     //
    00223
    00224     Status = ObInsertObject( SymbolicLink,
    00225                              NULL,
    00226                              DesiredAccess,
    00227                              0,
    00228                              (PVOID *)&Object,
    00229                              &Handle );
    00230
    00231     try {
    00232
    00233         *LinkHandle = Handle;
    00234
    00235     } except( EXCEPTION_EXECUTE_HANDLER ) {
    00236
    00237         //
    00238         // Fall through, since we do not want to undo what we have done.
    00239         //
    00240     }
    00241
    00242     return( Status );
    00243 }
    00244
    00245
    00246 NTSTATUS
    00247 NtOpenSymbolicLinkObject (
    00248     OUT PHANDLE LinkHandle,
    00249     IN ACCESS_MASK DesiredAccess,
    00250     IN POBJECT_ATTRIBUTES ObjectAttributes
    00251     )
    00252
    00253 /*++
    00254
    00255 Routine Description:
    00256
    00257     This function opens a handle to an symbolic link object with the specified
    00258     desired access.
    00259
    00260 Arguments:
    00261
    00262     LinkHandle - Supplies a pointer to a variable that will receive the
    00263         symbolic link object handle.
    00264
    00265     DesiredAccess - Supplies the desired types of access for the symbolic link
    00266         object.
    00267
    00268     ObjectAttributes - Supplies a pointer to an object attributes structure.
    00269
    00270 Return Value:
    00271
    00272     An appropriate status value
    00273
    00274 --*/
    00275
    00276 {
    00277     KPROCESSOR_MODE PreviousMode;
    00278     NTSTATUS Status;
    00279     HANDLE Handle;
    00280
    00281     PAGED_CODE();
    00282
    00283     //
    00284     //  Get previous processor mode and probe output arguments if necessary.
    00285     //  The object attributes does not need to be probed because the
    00286     //  ObOpenObjectByName does the probe for us
    00287     //
    00288
    00289     PreviousMode = KeGetPreviousMode();
    00290
    00291     if (PreviousMode != KernelMode) {
    00292
    00293         try {
    00294
    00295             ProbeForWriteHandle( LinkHandle );
    00296
    00297         } except( EXCEPTION_EXECUTE_HANDLER ) {
    00298
    00299             return( GetExceptionCode() );
    00300         }
    00301     }
    00302
    00303     //
    00304     //  Open handle to the symbolic link object with the specified desired
    00305     //  access, set symbolic link handle value, and return service completion
    00306     //  status.
    00307     //
    00308
    00309     Status = ObOpenObjectByName( ObjectAttributes,
    00310                                  ObpSymbolicLinkObjectType,
    00311                                  PreviousMode,
    00312                                  NULL,
    00313                                  DesiredAccess,
    00314                                  NULL,
    00315                                  &Handle );
    00316
    00317     try {
    00318
    00319         *LinkHandle = Handle;
    00320
    00321     } except( EXCEPTION_EXECUTE_HANDLER ) {
    00322
    00323         //
    00324         //  Fall through, since we do not want to undo what we have done.
    00325         //
    00326     }
    00327
    00328     return( Status );
    00329 }
    00330
    00331
    00332 NTSTATUS
    00333 NtQuerySymbolicLinkObject (
    00334     IN HANDLE LinkHandle,
    00335     IN OUT PUNICODE_STRING LinkTarget,
    00336     OUT PULONG ReturnedLength OPTIONAL
    00337     )
    00338
    00339 /*++
    00340
    00341 Routine Description:
    00342
    00343     This function queries the state of a symbolic link object and returns the
    00344     requested information in the specified record structure.
    00345
    00346 Arguments:
    00347
    00348     LinkHandle - Supplies a handle to a symbolic link object.  This handle
    00349         must have SYMBOLIC_LINK_QUERY access granted.
    00350
    00351     LinkTarget - Supplies a pointer to a record that is to receive the
    00352         target name of the symbolic link object.
    00353
    00354     ReturnedLength - Optionally receives the maximum length, in bytes, of
    00355         the link target on return
    00356
    00357 Return Value:
    00358
    00359     An appropriate status value
    00360
    00361 --*/
    00362
    00363 {
    00364     KPROCESSOR_MODE PreviousMode;
    00365     NTSTATUS Status;
    00366     POBJECT_SYMBOLIC_LINK SymbolicLink;
    00367     UNICODE_STRING CapturedLinkTarget;
    00368
    00369     //
    00370     //  Get previous processor mode and probe output arguments if necessary.
    00371     //
    00372
    00373     PAGED_CODE();
    00374
    00375     PreviousMode = KeGetPreviousMode();
    00376
    00377     if (PreviousMode != KernelMode) {
    00378
    00379         try {
    00380
    00381             ProbeForRead( LinkTarget,
    00382                           sizeof( *LinkTarget ),
    00383                           sizeof( WCHAR ) );
    00384
    00385             ProbeForWriteUshort( &LinkTarget->Length );
    00386
    00387             ProbeForWriteUshort( &LinkTarget->MaximumLength );
    00388
    00389             CapturedLinkTarget = *LinkTarget;
    00390
    00391             ProbeForWrite( CapturedLinkTarget.Buffer,
    00392                            CapturedLinkTarget.MaximumLength,
    00393                            sizeof( UCHAR ) );
    00394
    00395             if (ARGUMENT_PRESENT( ReturnedLength )) {
    00396
    00397                 ProbeForWriteUlong( ReturnedLength );
    00398             }
    00399
    00400         } except( EXCEPTION_EXECUTE_HANDLER ) {
    00401
    00402             return( GetExceptionCode() );
    00403         }
    00404
    00405     } else {
    00406
    00407         CapturedLinkTarget = *LinkTarget;
    00408     }
    00409
    00410     //
    00411     //  Reference symbolic link object by handle, read current state, deference
    00412     //  symbolic link object, fill in target name structure and return service
    00413     //  status.
    00414     //
    00415
    00416     Status = ObReferenceObjectByHandle( LinkHandle,
    00417                                         SYMBOLIC_LINK_QUERY,
    00418                                         ObpSymbolicLinkObjectType,
    00419                                         PreviousMode,
    00420                                         (PVOID *)&SymbolicLink,
    00421                                         NULL );
    00422
    00423     if (NT_SUCCESS( Status )) {
    00424
    00425         ObpEnterObjectTypeMutex( ObpSymbolicLinkObjectType );
    00426
    00427         //
    00428         //  If the caller wants a return length and what we found can easily
    00429         //  fit in the output buffer then we copy into the output buffer all
    00430         //  the bytes from the link.
    00431         //
    00432         //  If the caller did not want a return length and we found can still
    00433         //  easily fit in the output buffer then copy over the bytes that just
    00434         //  make up the string and nothing extra
    00435         //
    00436
    00437         if ((ARGUMENT_PRESENT( ReturnedLength ) &&
    00438                 (SymbolicLink->LinkTarget.MaximumLength <= CapturedLinkTarget.MaximumLength))
    00439
    00440                     ||
    00441
    00442             (!ARGUMENT_PRESENT( ReturnedLength ) &&
    00443                 (SymbolicLink->LinkTarget.Length <= CapturedLinkTarget.MaximumLength)) ) {
    00444
    00445             try {
    00446
    00447                 RtlMoveMemory( CapturedLinkTarget.Buffer,
    00448                                SymbolicLink->LinkTarget.Buffer,
    00449                                ARGUMENT_PRESENT( ReturnedLength ) ? SymbolicLink->LinkTarget.MaximumLength
    00450                                                                   : SymbolicLink->LinkTarget.Length );
    00451
    00452                 LinkTarget->Length = SymbolicLink->LinkTarget.Length;
    00453
    00454                 if (ARGUMENT_PRESENT( ReturnedLength )) {
    00455
    00456                     *ReturnedLength = SymbolicLink->LinkTarget.MaximumLength;
    00457                 }
    00458
    00459             } except( EXCEPTION_EXECUTE_HANDLER ) {
    00460
    00461                 //
    00462                 // Fall through, since we do cannot undo what we have done.
    00463                 //
    00464             }
    00465
    00466         } else {
    00467
    00468             //
    00469             //  The output buffer is just too small for the link target, but
    00470             //  we'll tell the user how much is needed if they asked for that
    00471             //  return value
    00472             //
    00473
    00474             if (ARGUMENT_PRESENT( ReturnedLength )) {
    00475
    00476                 try {
    00477
    00478                     *ReturnedLength = SymbolicLink->LinkTarget.MaximumLength;
    00479
    00480                 } except( EXCEPTION_EXECUTE_HANDLER ) {
    00481
    00482                     //
    00483                     // Fall through, since we do cannot undo what we have done.
    00484                     //
    00485                 }
    00486             }
    00487
    00488             Status = STATUS_BUFFER_TOO_SMALL;
    00489         }
    00490
    00491         ObpLeaveObjectTypeMutex( ObpSymbolicLinkObjectType );
    00492
    00493         ObDereferenceObject( SymbolicLink );
    00494     }
    00495
    00496     return( Status );
    00497 }
    00498
    00499
    00500 NTSTATUS
    00501 ObpParseSymbolicLink (
    00502     IN PVOID ParseObject,
    00503     IN PVOID ObjectType,
    00504     IN PACCESS_STATE AccessState,
    00505     IN KPROCESSOR_MODE AccessMode,
    00506     IN ULONG Attributes,
    00507     IN OUT PUNICODE_STRING CompleteName,
    00508     IN OUT PUNICODE_STRING RemainingName,
    00509     IN OUT PVOID Context OPTIONAL,
    00510     IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
    00511     OUT PVOID *Object
    00512     )
    00513
    00514 /*++
    00515
    00516 Routine Description:
    00517
    00518     This is the call back routine for parsing symbolic link objects.  It is invoked
    00519     as part of ObpLookupObjectName
    00520
    00521 Arguments:
    00522
    00523     ParseObject - This will actually be a symbolic link object
    00524
    00525     ObjectType - Specifies the type of the object to lookup
    00526
    00527     AccessState - Current access state, describing already granted access
    00528         types, the privileges used to get them, and any access types yet to
    00529         be granted.  The access masks may not contain any generic access
    00530         types.
    00531
    00532     AccessMode - Specifies the callers processor mode
    00533
    00534     Attributes - Specifies the attributes for the lookup (e.g., case
    00535         insensitive)
    00536
    00537     CompleteName - Supplies a pointer to the complete name that we are trying
    00538         to open.  On return this could be modified to fit the new reparse
    00539         buffer
    00540
    00541     RemainingName - Supplies a pointer to the remaining name that we are
    00542         trying to open.  On return this will point to what remains after
    00543         we processed the symbolic link.
    00544
    00545     Context - Unused
    00546
    00547     SecurityQos - Unused
    00548
    00549     Object - Receives a pointer to the symbolic link object that we
    00550         resolve to
    00551
    00552 Return Value:
    00553
    00554     STATUS_REPARSE_OBJECT if the parse object is already a snapped
    00555         symbolic link meaning we've modified the remaining name and
    00556         and have returned the target object of the symbolic link
    00557
    00558
    00559     STATUS_REPARSE if the parse object has not been snapped.  In this
    00560         case the Complete name has been modified with the link target
    00561         name added in front of the remaining name.  The parameters
    00562         remaining name and object must now be ignored by the caller
    00563
    00564     An appropriate error value
    00565
    00566 --*/
    00567
    00568 {
    00569     ULONG NewLength;
    00570     USHORT Length;
    00571     USHORT MaximumLength;
    00572     PWCHAR NewName, NewRemainingName;
    00573     ULONG InsertAmount;
    00574     NTSTATUS Status;
    00575     POBJECT_SYMBOLIC_LINK SymbolicLink;
    00576     PUNICODE_STRING LinkTargetName;
    00577
    00578     PAGED_CODE();
    00579
    00580     //
    00581     //  This routine needs to be synchonized with the delete symbolic link
    00582     //  operation.  Which uses the root directory mutex.
    00583     //
    00584
    00585     ObpEnterRootDirectoryMutex();
    00586
    00587     try {
    00588
    00589         *Object = NULL;
    00590
    00591         //
    00592         //  If there isn't any name remaining and the caller gave us
    00593         //  an object type then we'll reference the parse object.  If
    00594         //  this is successful then that's the object we return.  Otherwise
    00595         //  if the status is anything but a type mismatch then we'll
    00596         //  return that error status
    00597         //
    00598
    00599         if (RemainingName->Length == 0) {
    00600
    00601             if ( ObjectType ) {
    00602
    00603                 Status = ObReferenceObjectByPointer( ParseObject,
    00604                                                      0,
    00605                                                      ObjectType,
    00606                                                      AccessMode );
    00607
    00608                 if (NT_SUCCESS( Status )) {
    00609
    00610                     *Object = ParseObject;
    00611
    00612                     leave;
    00613
    00614                 } else if (Status != STATUS_OBJECT_TYPE_MISMATCH) {
    00615
    00616                     leave;
    00617                 }
    00618            }
    00619
    00620         //
    00621         //  If the remaining name does not start with a "\" then
    00622         //  its is illformed and we'll call it a type mismatch
    00623         //
    00624
    00625         } else if (*(RemainingName->Buffer) != OBJ_NAME_PATH_SEPARATOR) {
    00626
    00627             Status = STATUS_OBJECT_TYPE_MISMATCH;
    00628             leave;
    00629         }
    00630
    00631         //
    00632         //  A symbolic link has been encountered. See if this link has been snapped
    00633         //  to a particular object.
    00634         //
    00635
    00636         SymbolicLink = (POBJECT_SYMBOLIC_LINK)ParseObject;
    00637
    00638         if (SymbolicLink->LinkTargetObject != NULL) {
    00639
    00640             //
    00641             //  This is a snapped link.  Get the remaining portion of the
    00642             //  symbolic link target, if any.
    00643             //
    00644
    00645             LinkTargetName = &SymbolicLink->LinkTargetRemaining;
    00646
    00647             if (LinkTargetName->Length == 0) {
    00648
    00649                 //
    00650                 //  Remaining link target string is zero, so return to caller
    00651                 //  quickly with snapped object pointer and remaining object name
    00652                 //  which we haven't touched yet.
    00653                 //
    00654
    00655                 *Object = SymbolicLink->LinkTargetObject;
    00656
    00657                 Status = STATUS_REPARSE_OBJECT;
    00658                 leave;
    00659             }
    00660
    00661             //
    00662             //  We have a snapped symbolic link that has additional text.
    00663             //  Insert that in front of the current remaining name, preserving
    00664             //  and text between CompleteName and RemainingName
    00665             //
    00666
    00667             InsertAmount = LinkTargetName->Length;
    00668
    00669             if ((LinkTargetName->Buffer[ (InsertAmount / sizeof( WCHAR )) - 1 ] == OBJ_NAME_PATH_SEPARATOR)
    00670
    00671                     &&
    00672
    00673                 (*(RemainingName->Buffer) == OBJ_NAME_PATH_SEPARATOR)) {
    00674
    00675                 //
    00676                 //  Both the link target name ends in a "\" and the remaining
    00677                 //  starts with a "\" but we only need one when we're done
    00678                 //
    00679
    00680                 InsertAmount -= sizeof( WCHAR );
    00681             }
    00682
    00683             //
    00684             //  **** don't see why we need to bias the differnce between two
    00685             //  pointers with * sizeof(wchar)
    00686             //
    00687
    00688             NewLength = (ULONG)(((RemainingName->Buffer - CompleteName->Buffer) * sizeof( WCHAR )) +
    00689                         InsertAmount +
    00690                         RemainingName->Length);
    00691
    00692             if (NewLength > 0xFFF0) {
    00693
    00694                 Status = STATUS_NAME_TOO_LONG;
    00695                 leave;
    00696             }
    00697
    00698             Length = (USHORT)NewLength;
    00699
    00700             //
    00701             //  Now check if the new computed length is too big for the input
    00702             //  buffer containing the complete name
    00703             //
    00704
    00705             if (CompleteName->MaximumLength <= Length) {
    00706
    00707                 //
    00708                 //  The new concatentated name is larger than the buffer supplied for
    00709                 //  the complete name.  Allocate space for this new string
    00710                 //
    00711
    00712                 MaximumLength = Length + sizeof( UNICODE_NULL );
    00713                 NewName = ExAllocatePoolWithTag( NonPagedPool, MaximumLength, 'mNbO' );
    00714
    00715                 if (NewName == NULL) {
    00716
    00717                     Status = STATUS_INSUFFICIENT_RESOURCES;
    00718                     leave;
    00719                 }
    00720
    00721                 //
    00722                 //  Calculate the pointer within this buffer for the remaining
    00723                 //  name.  This value has not been biased by the new link
    00724                 //  target name
    00725                 //
    00726
    00727                 NewRemainingName = NewName + (RemainingName->Buffer - CompleteName->Buffer);
    00728
    00729                 //
    00730                 //  Copy over all the names that we've processed so far
    00731                 //
    00732
    00733                 RtlMoveMemory( NewName,
    00734                                CompleteName->Buffer,
    00735                                ((RemainingName->Buffer - CompleteName->Buffer) * sizeof( WCHAR )));
    00736
    00737                 //
    00738                 //  If we have some remaining names then those over at the
    00739                 //  the location offset to hold the link target name
    00740                 //
    00741
    00742                 if (RemainingName->Length != 0) {
    00743
    00744                     RtlMoveMemory( (PVOID)((PUCHAR)NewRemainingName + InsertAmount),
    00745                                    RemainingName->Buffer,
    00746                                    RemainingName->Length );
    00747                 }
    00748
    00749                 //
    00750                 //  Now insert the link target name
    00751                 //
    00752
    00753                 RtlMoveMemory( NewRemainingName, LinkTargetName->Buffer, InsertAmount );
    00754
    00755                 //
    00756                 //  Free the old complete name buffer and reset the input
    00757                 //  strings to use the new buffer
    00758                 //
    00759
    00760                 ExFreePool( CompleteName->Buffer );
    00761
    00762                 CompleteName->Buffer = NewName;
    00763                 CompleteName->Length = Length;
    00764                 CompleteName->MaximumLength = MaximumLength;
    00765
    00766                 RemainingName->Buffer = NewRemainingName;
    00767                 RemainingName->Length = Length - (USHORT)((PCHAR)NewRemainingName - (PCHAR)NewName);
    00768                 RemainingName->MaximumLength = RemainingName->Length + sizeof( UNICODE_NULL );
    00769
    00770             } else {
    00771
    00772                 //
    00773                 //  Insert extra text associated with this symbolic link name before
    00774                 //  existing remaining name, if any.
    00775                 //
    00776                 //  First shove over the remaining name to make a hole for the
    00777                 //  link target name
    00778                 //
    00779
    00780                 if (RemainingName->Length != 0) {
    00781
    00782                     RtlMoveMemory( (PVOID)((PUCHAR)RemainingName->Buffer + InsertAmount),
    00783                                    RemainingName->Buffer,
    00784                                    RemainingName->Length );
    00785                 }
    00786
    00787                 //
    00788                 //  Now insert the link target name
    00789                 //
    00790
    00791                 RtlMoveMemory( RemainingName->Buffer, LinkTargetName->Buffer, InsertAmount );
    00792
    00793                 //
    00794                 //  Adjust input strings to account for this inserted text
    00795                 //
    00796
    00797                 CompleteName->Length += LinkTargetName->Length;
    00798
    00799                 RemainingName->Length += LinkTargetName->Length;
    00800                 RemainingName->MaximumLength += RemainingName->Length + sizeof( UNICODE_NULL );
    00801
    00802                 CompleteName->Buffer[ CompleteName->Length / sizeof( WCHAR ) ] = UNICODE_NULL;
    00803             }
    00804
    00805             //
    00806             //  Return the object address associated with snapped symbolic link
    00807             //  and the reparse object status code.
    00808             //
    00809
    00810             *Object = SymbolicLink->LinkTargetObject;
    00811
    00812             Status = STATUS_REPARSE_OBJECT;
    00813             leave;
    00814         }
    00815
    00816         //
    00817         //  The symbolic has not yet been snapped
    00818         //
    00819         //  Compute the size of the new name and check if the name will
    00820         //  fit in the existing complete name buffer.
    00821         //
    00822
    00823         LinkTargetName = &SymbolicLink->LinkTarget;
    00824         NewLength = LinkTargetName->Length + RemainingName->Length;
    00825
    00826         if (NewLength > 0xFFF0) {
    00827
    00828             Status = STATUS_NAME_TOO_LONG;
    00829             leave;
    00830         }
    00831
    00832         Length = (USHORT)NewLength;
    00833
    00834         if (CompleteName->MaximumLength <= Length) {
    00835
    00836             //
    00837             //  The new concatentated name is larger than the buffer supplied for
    00838             //  the complete name.
    00839             //
    00840
    00841             MaximumLength = Length + sizeof( UNICODE_NULL );
    00842             NewName = ExAllocatePoolWithTag( NonPagedPool, MaximumLength, 'mNbO' );
    00843
    00844             if (NewName == NULL) {
    00845
    00846                 Status = STATUS_INSUFFICIENT_RESOURCES;
    00847                 leave;
    00848             }
    00849
    00850         } else {
    00851
    00852             MaximumLength = CompleteName->MaximumLength;
    00853             NewName = CompleteName->Buffer;
    00854         }
    00855
    00856         //
    00857         //  Concatenate the symbolic link name with the remaining name,
    00858         //  if any.  What this does is overwrite the front of the complete
    00859         //  name up to the remaining name with the links target name
    00860         //
    00861
    00862         if (RemainingName->Length != 0) {
    00863
    00864             RtlMoveMemory( (PVOID)((PUCHAR)NewName + LinkTargetName->Length),
    00865                            RemainingName->Buffer,
    00866                            RemainingName->Length );
    00867         }
    00868
    00869         RtlMoveMemory( NewName, LinkTargetName->Buffer, LinkTargetName->Length );
    00870
    00871         NewName[ Length / sizeof( WCHAR ) ] = UNICODE_NULL;
    00872
    00873         //
    00874         //  If a new name buffer was allocated, then free the original complete
    00875         //  name buffer.
    00876         //
    00877
    00878         if (NewName != CompleteName->Buffer) {
    00879
    00880             ExFreePool( CompleteName->Buffer );
    00881         }
    00882
    00883         //
    00884         //  Set the new complete name buffer parameters and return a reparse
    00885         //  status.
    00886         //
    00887
    00888         CompleteName->Buffer = NewName;
    00889         CompleteName->Length = Length;
    00890         CompleteName->MaximumLength = MaximumLength;
    00891
    00892         Status = STATUS_REPARSE;
    00893
    00894     } finally {
    00895
    00896         ObpLeaveRootDirectoryMutex();
    00897     }
    00898
    00899     return Status;
    00900 }
    00901
    00902
    00903 VOID
    00904 ObpDeleteSymbolicLink (
    00905     IN PVOID Object
    00906     )
    00907
    00908 /*++
    00909
    00910 Routine Description:
    00911
    00912     This routine is called when a reference to a symbolic link goes to zero.
    00913     Its job is to clean up the memory used to the symbolic link string
    00914
    00915 Arguments:
    00916
    00917     Object - Supplies a pointer to the symbolic link object being deleted
    00918
    00919 Return Value:
    00920
    00921     None.
    00922
    00923 --*/
    00924
    00925 {
    00926     POBJECT_SYMBOLIC_LINK SymbolicLink = (POBJECT_SYMBOLIC_LINK)Object;
    00927
    00928     PAGED_CODE();
    00929
    00930     //
    00931     //  The only cleaning up we need to do is to free the link target
    00932     //  buffer
    00933     //
    00934
    00935     if (SymbolicLink->LinkTarget.Buffer != NULL) {
    00936
    00937         ExFreePool( SymbolicLink->LinkTarget.Buffer );
    00938     }
    00939
    00940     SymbolicLink->LinkTarget.Buffer = NULL;
    00941
    00942     //
    00943     //  And return to our caller
    00944     //
    00945
    00946     return;
    00947 }
    00948
    00949
    00950 VOID
    00951 ObpDeleteSymbolicLinkName (
    00952     POBJECT_SYMBOLIC_LINK SymbolicLink
    00953     )
    00954
    00955 /*++
    00956
    00957 Routine Description:
    00958
    00959     This routine delete the symbolic from the system
    00960
    00961 Arguments:
    00962
    00963     SymbolicLink - Supplies a pointer to the object body for the symbolic
    00964         link object to delete
    00965
    00966 Return Value:
    00967
    00968     None.
    00969
    00970 --*/
    00971
    00972 {
    00973     PVOID CapturedLinkTargetObject;
    00974
    00975     CapturedLinkTargetObject = NULL;
    00976
    00977     //
    00978     //  Lock the root directory mutex while we look at the target path to
    00979     //  prevent names from disappearing out from under us.  Also protects
    00980     //  against collisions with NtCreateSymbolicLink
    00981     //
    00982
    00983     ObpEnterRootDirectoryMutex();
    00984
    00985     //
    00986     //  Capture the link target object and referenced one more time
    00987     //  to avoid destroying while the RootDirectoryMutex is hold
    00988     //
    00989
    00990     CapturedLinkTargetObject = SymbolicLink->LinkTargetObject;
    00991
    00992     if (CapturedLinkTargetObject != NULL) {
    00993
    00994         ObReferenceObject(CapturedLinkTargetObject);
    00995     }
    00996
    00997     ObpProcessDosDeviceSymbolicLink( SymbolicLink, DELETE_SYMBOLIC_LINK );
    00998
    00999     ObpLeaveRootDirectoryMutex();
    01000
    01001     //
    01002     //  Remove the extra-reference for the link target object
    01003     //
    01004
    01005     if (CapturedLinkTargetObject != NULL) {
    01006
    01007         ObDereferenceObject(CapturedLinkTargetObject);
    01008     }
    01009
    01010     return;
    01011 }
    01012
    01013
    01014 VOID
    01015 ObpCreateSymbolicLinkName (
    01016     POBJECT_SYMBOLIC_LINK SymbolicLink
    01017     )
    01018
    01019 /*++
    01020
    01021 Routine Description:
    01022
    01023     This routine does extra processing for symbolic links being created in
    01024     object directories controlled by device map objects.
    01025
    01026     This processing consists of:
    01027
    01028     1.  Determine if the name of the symbolic link is a drive letter.
    01029         If so, then we will need to update the drive type in the
    01030         associated device map object.
    01031
    01032     2.  Process the link target, trying to resolve it into a pointer to
    01033         an object other than a object directory object.  All object
    01034         directories traversed must grant world traverse access other
    01035         wise we bail out.  If we successfully find a non object
    01036         directory object, then reference the object pointer and store it
    01037         in the symbolic link object, along with a remaining string if
    01038         any.  ObpLookupObjectName will used this cache object pointer to
    01039         short circuit the name lookup directly to the cached object's
    01040         parse routine.  For any object directory objects traversed along
    01041         the way, increment their symbolic link SymbolicLinkUsageCount
    01042         field.  This field is used whenever an object directory is
    01043         deleted or its security is changed such that it no longer grants
    01044         world traverse access.  In either case, if the field is non-zero
    01045         we walk all the symbolic links and resnap them.
    01046
    01047 Arguments:
    01048
    01049     SymbolicLink - pointer to symbolic link object being created.
    01050
    01051 Return Value:
    01052
    01053     None.
    01054
    01055 --*/
    01056
    01057 {
    01058     POBJECT_HEADER ObjectHeader;
    01059     POBJECT_HEADER_NAME_INFO NameInfo;
    01060     WCHAR DosDeviceDriveLetter;
    01061     ULONG DosDeviceDriveIndex;
    01062
    01063     //
    01064     //  Now see if this symbolic link is being created in an object directory
    01065     //  controlled by a device map object.  Since we are only called from
    01066     //  NtCreateSymbolicLinkObject, after the handle to this symbolic link
    01067     //  has been created but before it is returned to the caller the handle can't
    01068     //  be closed while we are executing, unless via a random close,
    01069     //  So no need to hold the type specific mutex while we look at the name.
    01070     //
    01071
    01072     ObjectHeader = OBJECT_TO_OBJECT_HEADER( SymbolicLink );
    01073     NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
    01074
    01075     if ((NameInfo == NULL) ||
    01076         (NameInfo->Directory == NULL) ||
    01077         (NameInfo->Directory->DeviceMap == NULL)) {
    01078
    01079         return;
    01080     }
    01081
    01082     //
    01083     //  Here if we are creating a symbolic link in an object directory controlled
    01084     //  by a device map object.  See if this is a drive letter definition.  If so
    01085     //  calculate the drive letter index and remember in the symbolic link object.
    01086     //
    01087
    01088     DosDeviceDriveIndex = 0;
    01089
    01090     if ((NameInfo->Name.Length == (2 * sizeof( WCHAR ))) &&
    01091         (NameInfo->Name.Buffer[ 1 ] == L':')) {
    01092
    01093         DosDeviceDriveLetter = RtlUpcaseUnicodeChar( NameInfo->Name.Buffer[ 0 ] );
    01094
    01095         if ((DosDeviceDriveLetter >= L'A') && (DosDeviceDriveLetter <= L'Z')) {
    01096
    01097             DosDeviceDriveIndex = DosDeviceDriveLetter - L'A';
    01098             DosDeviceDriveIndex += 1;
    01099
    01100             SymbolicLink->DosDeviceDriveIndex = DosDeviceDriveIndex;
    01101         }
    01102     }
    01103
    01104     //
    01105     //  Now traverse the target path seeing if we can snap the link now.
    01106     //
    01107
    01108     ObpProcessDosDeviceSymbolicLink( SymbolicLink, CREATE_SYMBOLIC_LINK );
    01109
    01110     return;
    01111 }
    01112
    01113
    01114 //
    01115 //  Local support routine
    01116 //
    01117
    01118 #define MAX_DEPTH 16
    01119
    01120 VOID
    01121 ObpProcessDosDeviceSymbolicLink (
    01122     POBJECT_SYMBOLIC_LINK SymbolicLink,
    01123     ULONG Action
    01124     )
    01125
    01126 /*++
    01127
    01128 Routine Description:
    01129
    01130     This function is called whenever a symbolic link is created or deleted
    01131     in an object directory controlled by a device map object.
    01132
    01133     For creates, it attempts to snap the symbolic link to a non-object
    01134     directory object.  It does this by walking the symbolic link target
    01135     string, until it sees a non-directory object or a directory object
    01136     that does NOT allow World traverse access.  It stores a referenced
    01137     pointer to this object in the symbolic link object.  It also
    01138     increments a count in each of the object directory objects that it
    01139     walked over.  This count is used to disallow any attempt to remove
    01140     World traverse access from a directory object after it has
    01141     participated in a snapped symbolic link.
    01142
    01143     For deletes, it repeats the walk of the target string, decrementing
    01144     the count associated with each directory object walked over.  It also
    01145     dereferences the snapped object pointer.
    01146
    01147 Arguments:
    01148
    01149     SymbolicLink - pointer to symbolic link object being created or deleted.
    01150
    01151     Action - describes whether this is a create or a delete action
    01152
    01153 Return Value:
    01154
    01155     None.
    01156
    01157 --*/
    01158
    01159 {
    01160     NTSTATUS Status;
    01161     PVOID Object;
    01162     POBJECT_HEADER ObjectHeader;
    01163     POBJECT_HEADER_NAME_INFO NameInfo;
    01164     PSECURITY_DESCRIPTOR SecurityDescriptor;
    01165     BOOLEAN MemoryAllocated;
    01166     UNICODE_STRING RemainingName;
    01167     UNICODE_STRING ComponentName;
    01168     BOOLEAN HaveWorldTraverseAccess;
    01169     ULONG Depth;
    01170     POBJECT_DIRECTORY Directories[ MAX_DEPTH ], Directory, ParentDirectory;
    01171     PDEVICE_OBJECT DeviceObject;
    01172     PDEVICE_MAP DeviceMap = NULL;
    01173     ULONG DosDeviceDriveType;
    01174     BOOLEAN DeviceMapUsed = FALSE;
    01175
    01176
    01177     Object = NULL;
    01178
    01179     //
    01180     //  Check if we are creating a symbolic link or if the link has already
    01181     //  been snapped
    01182     //
    01183
    01184     if ((Action == CREATE_SYMBOLIC_LINK) ||
    01185         (SymbolicLink->LinkTargetObject != NULL)) {
    01186
    01187         ParentDirectory = NULL;
    01188         Depth    = 0;
    01189         Directory = ObpRootDirectoryObject;
    01190         RemainingName = SymbolicLink->LinkTarget;
    01191
    01192         DeviceMap = PsGetCurrentProcess()->DeviceMap;
    01193
    01194
    01195 ReCalcDeviceMap:
    01196
    01197         if (DeviceMap) {
    01198
    01199
    01200             if (!((ULONG_PTR)(RemainingName.Buffer) & (sizeof(ULONGLONG)-1))
    01201
    01202                         &&
    01203
    01204                 (DeviceMap->DosDevicesDirectory != NULL )) {
    01205
    01206                 //
    01207                 //  Check if the object name is actually equal to the
    01208                 //  global dos devices short name prefix "\??\"
    01209                 //
    01210
    01211                 if ((RemainingName.Length >= ObpDosDevicesShortName.Length)
    01212
    01213                         &&
    01214
    01215                     (*(PULONGLONG)(RemainingName.Buffer) == ObpDosDevicesShortNamePrefix.QuadPart)) {
    01216
    01217                     //
    01218                     //  The user gave us the dos short name prefix so we'll
    01219                     //  look down the directory, and start the search at the
    01220                     //  dos device directory
    01221                     //
    01222
    01223                     Directory = DeviceMap->DosDevicesDirectory;
    01224
    01225                     RemainingName.Buffer += (ObpDosDevicesShortName.Length / sizeof( WCHAR ));
    01226                     RemainingName.Length -= ObpDosDevicesShortName.Length;
    01227
    01228                     DeviceMapUsed = TRUE;
    01229
    01230                 }
    01231             }
    01232         }
    01233
    01234         //
    01235         //  The following loop will dissect the link target checking
    01236         //  that each directory exists and that we have access to
    01237         //  the directory.  When we pop out the local directories
    01238         //  array will contain a list of directories that we need
    01239         //  to traverse to process this action.
    01240         //
    01241
    01242         while (TRUE) {
    01243
    01244             //
    01245             //  Gobble up the "\" in the remaining name
    01246             //
    01247
    01248             if (*(RemainingName.Buffer) == OBJ_NAME_PATH_SEPARATOR) {
    01249
    01250                 RemainingName.Buffer++;
    01251                 RemainingName.Length -= sizeof( OBJ_NAME_PATH_SEPARATOR );
    01252             }
    01253
    01254             //
    01255             //  And dissect the name into its first component and any
    01256             //  remaining part
    01257             //
    01258
    01259             ComponentName = RemainingName;
    01260
    01261             while (RemainingName.Length != 0) {
    01262
    01263                 if (*(RemainingName.Buffer) == OBJ_NAME_PATH_SEPARATOR) {
    01264
    01265                     break;
    01266                 }
    01267
    01268                 RemainingName.Buffer++;
    01269                 RemainingName.Length -= sizeof( OBJ_NAME_PATH_SEPARATOR );
    01270             }
    01271
    01272             ComponentName.Length -= RemainingName.Length;
    01273
    01274             if (ComponentName.Length == 0) {
    01275
    01276                 return;
    01277             }
    01278
    01279             //
    01280             //  See if we have world traverse access to look this name up
    01281             //
    01282
    01283             if (ParentDirectory != NULL) {
    01284
    01285                 HaveWorldTraverseAccess = FALSE;
    01286
    01287                 //
    01288                 //  Obtain the object's security descriptor
    01289                 //
    01290
    01291                 Status = ObGetObjectSecurity( ParentDirectory,
    01292                                               &SecurityDescriptor,
    01293                                               &MemoryAllocated );
    01294
    01295                 if (NT_SUCCESS( Status )) {
    01296
    01297                     //
    01298                     //  Check to see if WORLD has TRAVERSE access and then release
    01299                     //  the security descriptor
    01300                     //
    01301
    01302                     HaveWorldTraverseAccess = SeFastTraverseCheck( SecurityDescriptor,
    01303                                                                    DIRECTORY_TRAVERSE,
    01304                                                                    UserMode );
    01305
    01306                     ObReleaseObjectSecurity( SecurityDescriptor,
    01307                                              MemoryAllocated );
    01308                 }
    01309
    01310                 if (!HaveWorldTraverseAccess) {
    01311
    01312                     Object = NULL;
    01313                     break;
    01314                 }
    01315
    01316                 if (Depth >= MAX_DEPTH) {
    01317
    01318                     Object = NULL;
    01319                     break;
    01320                 }
    01321
    01322                 Directories[ Depth++ ] = ParentDirectory;
    01323             }
    01324
    01325             //
    01326             //  Look this component name up in this directory.  If not found, then
    01327             //  bail.
    01328             //
    01329
    01330             Object = ObpLookupDirectoryEntry( Directory, &ComponentName, 0 );
    01331
    01332             if (Object == NULL) {
    01333
    01334                 break;
    01335             }
    01336
    01337             //
    01338             //  See if this is a object directory object.  If so, keep going
    01339             //
    01340
    01341             ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    01342
    01343             if (ObjectHeader->Type == ObpDirectoryObjectType) {
    01344
    01345                 ParentDirectory = Directory;
    01346                 Directory = (POBJECT_DIRECTORY)Object;
    01347
    01348             } else if ((ObjectHeader->Type == ObpSymbolicLinkObjectType) &&
    01349                        (((POBJECT_SYMBOLIC_LINK)Object)->DosDeviceDriveIndex == 0)) {
    01350
    01351                 //
    01352                 //  Found a symbolic link to another symbolic link that is
    01353                 //  not already snapped.  So switch to its target string
    01354                 //  so we can chase down the real device object
    01355                 //
    01356
    01357                 ParentDirectory = NULL;
    01358                 Depth = 0;
    01359                 Directory = ObpRootDirectoryObject;
    01360                 RemainingName = ((POBJECT_SYMBOLIC_LINK)Object)->LinkTarget;
    01361
    01362                 goto ReCalcDeviceMap;
    01363
    01364             } else {
    01365
    01366                 //
    01367                 //  Not an object directory object, or a symbolic link to an
    01368                 //  unsnapped symbolic link, so all done.  Exit the loop
    01369                 //
    01370
    01371                 break;
    01372             }
    01373         }
    01374
    01375         //
    01376         //  Done walking the target path.  Now update the counts associated
    01377         //  with each directory object walked over.
    01378         //
    01379
    01380         while (Depth--) {
    01381
    01382             Directory = Directories[ Depth ];
    01383
    01384             if (Action == CREATE_SYMBOLIC_LINK) {
    01385
    01386                 if (Object != NULL) {
    01387
    01388                     Directory->SymbolicLinkUsageCount += 1;
    01389                 }
    01390
    01391             } else {
    01392
    01393                 Directory->SymbolicLinkUsageCount -= 1;
    01394             }
    01395         }
    01396     }
    01397
    01398     //
    01399     //  Done processing symbolic link target path.  Update symbolic link
    01400     //  object as appropriate for passed in reason
    01401     //
    01402
    01403     //
    01404     //  If this is a drive letter symbolic link, get the address of the device
    01405     //  map object that is controlling the containing object directory so we
    01406     //  can update the drive type in the device map.
    01407     //
    01408
    01409     DeviceMap = NULL;
    01410
    01411     if (SymbolicLink->DosDeviceDriveIndex != 0) {
    01412
    01413         ObjectHeader = OBJECT_TO_OBJECT_HEADER( SymbolicLink );
    01414         NameInfo = OBJECT_HEADER_TO_NAME_INFO( ObjectHeader );
    01415
    01416         if (NameInfo != NULL && NameInfo->Directory) {
    01417
    01418             DeviceMap = NameInfo->Directory->DeviceMap;
    01419         }
    01420     }
    01421
    01422     //
    01423     //  Check if we are creating a symbolic link
    01424     //
    01425
    01426     if (Action == CREATE_SYMBOLIC_LINK) {
    01427
    01428         DosDeviceDriveType = DOSDEVICE_DRIVE_CALCULATE;
    01429
    01430         if (Object != NULL) {
    01431
    01432
    01433             //
    01434             // We only want to do snapping for console session. When we create a
    01435             // remote session all the symbolic links stored in the console dos devices
    01436             // directory (\??) are copied into the per session DosDevices object directory
    01437             // (\Session<id>\DosDevices). We don't want to do snapping for the copied
    01438             // symbolic links since for each copy we will increment the ref count on the
    01439             // target object. All these counts have to go to zero before the device can be
    01440             // deleted.
    01441             //
    01442             if ((PsGetCurrentProcess()->SessionId == 0) || (DeviceMapUsed)) {
    01443                 //
    01444                 //  Create action.  Store a referenced pointer to the snapped object
    01445                 //  along with the description of any remaining name string.  Also,
    01446                 //  for Dos drive letters, update the drive type in the appropriate
    01447                 //  device map object.
    01448                 //
    01449
    01450                 ObReferenceObject( Object );
    01451
    01452                 SymbolicLink->LinkTargetObject = Object;
    01453
    01454                 if ((*(RemainingName.Buffer) == OBJ_NAME_PATH_SEPARATOR) &&
    01455                     (RemainingName.Length == sizeof( OBJ_NAME_PATH_SEPARATOR))) {
    01456
    01457                     RtlInitUnicodeString( &SymbolicLink->LinkTargetRemaining, NULL );
    01458
    01459                 } else {
    01460
    01461                     SymbolicLink->LinkTargetRemaining = RemainingName;
    01462                 }
    01463             }
    01464
    01465             if (SymbolicLink->DosDeviceDriveIndex != 0) {
    01466
    01467                 //
    01468                 //  Default is to calculate the drive type in user mode if we are
    01469                 //  unable to snap the symbolic link or it does not resolve to a
    01470                 //  DEVICE_OBJECT we know about.
    01471                 //
    01472
    01473                 ObjectHeader = OBJECT_TO_OBJECT_HEADER( Object );
    01474
    01475                 if (ObjectHeader->Type == IoDeviceObjectType) {
    01476
    01477                     DeviceObject = (PDEVICE_OBJECT)Object;
    01478
    01479                     switch (DeviceObject->DeviceType) {
    01480
    01481                     case FILE_DEVICE_CD_ROM:
    01482                     case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
    01483
    01484                         DosDeviceDriveType = DOSDEVICE_DRIVE_CDROM;
    01485
    01486                         break;
    01487
    01488                     case FILE_DEVICE_DISK:
    01489                     case FILE_DEVICE_DISK_FILE_SYSTEM:
    01490                     case FILE_DEVICE_FILE_SYSTEM:
    01491
    01492                         if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) {
    01493
    01494                             DosDeviceDriveType = DOSDEVICE_DRIVE_REMOVABLE;
    01495
    01496                         } else {
    01497
    01498                             DosDeviceDriveType = DOSDEVICE_DRIVE_FIXED;
    01499                         }
    01500
    01501                         break;
    01502
    01503                     case FILE_DEVICE_MULTI_UNC_PROVIDER:
    01504                     case FILE_DEVICE_NETWORK:
    01505                     case FILE_DEVICE_NETWORK_BROWSER:
    01506                     case FILE_DEVICE_NETWORK_REDIRECTOR:
    01507
    01508                         DosDeviceDriveType = DOSDEVICE_DRIVE_REMOTE;
    01509
    01510                         break;
    01511
    01512                     case FILE_DEVICE_NETWORK_FILE_SYSTEM:
    01513
    01514 #if defined(REMOTE_BOOT)
    01515                         //
    01516                         //  If this is a remote boot workstation, the X:
    01517                         //  drive is a redirected drive, but needs to look
    01518                         //  like a local drive.
    01519                         //
    01520
    01521                         if (IoRemoteBootClient &&
    01522                             (SymbolicLink->DosDeviceDriveIndex == 24)) {
    01523
    01524                             DosDeviceDriveType = DOSDEVICE_DRIVE_FIXED;
    01525
    01526                         } else
    01527 #endif // defined(REMOTE_BOOT)
    01528                         {
    01529                             DosDeviceDriveType = DOSDEVICE_DRIVE_REMOTE;
    01530                         }
    01531
    01532                         break;
    01533
    01534                     case FILE_DEVICE_VIRTUAL_DISK:
    01535
    01536                         DosDeviceDriveType = DOSDEVICE_DRIVE_RAMDISK;
    01537
    01538                         break;
    01539
    01540                     default:
    01541
    01542                         DosDeviceDriveType = DOSDEVICE_DRIVE_UNKNOWN;
    01543
    01544                         break;
    01545                     }
    01546                 }
    01547             }
    01548         }
    01549
    01550         //
    01551         //  If this is a drive letter symbolic link, update the drive type and
    01552         //  and mark as valid drive letter.
    01553         //
    01554
    01555         if (DeviceMap != NULL) {
    01556
    01557             DeviceMap->DriveType[ SymbolicLink->DosDeviceDriveIndex-1 ] = (UCHAR)DosDeviceDriveType;
    01558             DeviceMap->DriveMap |= 1 << (SymbolicLink->DosDeviceDriveIndex-1) ;
    01559         }
    01560
    01561     } else {
    01562
    01563         //
    01564         //  Deleting the symbolic link.  Dereference the snapped object pointer if any
    01565         //  and zero out the snapped object fields.
    01566         //
    01567
    01568         RtlInitUnicodeString( &SymbolicLink->LinkTargetRemaining, NULL );
    01569
    01570         Object = SymbolicLink->LinkTargetObject;
    01571
    01572         if (Object != NULL) {
    01573
    01574             SymbolicLink->LinkTargetObject = NULL;
    01575             ObDereferenceObject( Object );
    01576         }
    01577
    01578         //
    01579         //  If this is a drive letter symbolic link, set the drive type to
    01580         //  unknown and clear the bit in the drive letter bit map.
    01581         //
    01582
    01583         if (DeviceMap != NULL) {
    01584
    01585             DeviceMap->DriveMap &= ~(1 << (SymbolicLink->DosDeviceDriveIndex-1));
    01586             DeviceMap->DriveType[ SymbolicLink->DosDeviceDriveIndex-1 ] = DOSDEVICE_DRIVE_UNKNOWN;
    01587
    01588             SymbolicLink->DosDeviceDriveIndex = 0;
    01589         }
    01590
    01591         //
    01592         //  If we allocated a target buffer, free it.
    01593         //
    01594
    01595         if (SymbolicLink->LinkTarget.Buffer != NULL) {
    01596
    01597             ExFreePool( SymbolicLink->LinkTarget.Buffer );
    01598
    01599             RtlInitUnicodeString( &SymbolicLink->LinkTarget, NULL );
    01600         }
    01601     }
    01602
    01603     return;
    01604 }
    01605