test: errorlog.c File Reference

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

# errorlog.c File Reference

`#include "iop.h"`
`#include "elfkrnl.h"`

Go to the source code of this file.

## Classes

struct | _IOP_ERROR_LOG_CONTEXT

## Defines

#define | IO_ERROR_NAME_LENGTH 100

## Typedefs

typedef _IOP_ERROR_LOG_CONTEXT | IOP_ERROR_LOG_CONTEXT
typedef _IOP_ERROR_LOG_CONTEXT * | PIOP_ERROR_LOG_CONTEXT

## Functions

BOOLEAN | IopErrorLogConnectPort (VOID)
VOID | IopErrorLogDpc (IN struct _KDPC *Dpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
PLIST_ENTRY | IopErrorLogGetEntry ()
VOID | IopErrorLogQueueRequest (VOID)
VOID | IopErrorLogRequeueEntry (IN PLIST_ENTRY ListEntry)
VOID | IopErrorLogThread (IN PVOID StartContext)

## Variables

WORK_QUEUE_ITEM | IopErrorLogWorkItem
HANDLE | ErrorLogPort
BOOLEAN | ErrorLogPortConnected
BOOLEAN | IopErrorLogPortPending
BOOLEAN | IopErrorLogDisabledThisBoot

## Define Documentation

#define IO_ERROR_NAME_LENGTH 100

| Definition at line 85 of file errorlog.c. Referenced by IopErrorLogThread().

## Typedef Documentation

typedef struct _IOP_ERROR_LOG_CONTEXT IOP_ERROR_LOG_CONTEXT

typedef struct _IOP_ERROR_LOG_CONTEXT * PIOP_ERROR_LOG_CONTEXT

| Referenced by IopErrorLogQueueRequest().

## Function Documentation

BOOLEAN IopErrorLogConnectPort | ( | VOID |  | ) |

Definition at line 566 of file errorlog.c.

References ErrorLogPort, ErrorLogPortConnected, FALSE, IopErrorLogQueueRequest(), NT_SUCCESS, NtClose(), NtConnectPort(), NTSTATUS(), NULL, PAGED_CODE, RtlInitUnicodeString(), and TRUE.

Referenced by IopErrorLogThread().

    00571                    :
    00572
    00573     This routine attempts to connect to the error log port.  If the connection
    00574     was made successfully and the port allows suficiently large messages, then
    00575     the ErrorLogPort to the port handle, ErrorLogPortConnected is set to
    00576     TRUE and TRUE is retuned.  Otherwise a timer is started to queue a
    00577     worker thread at a later time, unless there is a pending connection.
    00578
    00579 Arguments:
    00580
    00581     None.
    00582
    00583 Return Value:
    00584
    00585     Returns TRUE if the port was connected.
    00586
    00587 --*/
    00588
    00589 {
    00590
    00591     UNICODE_STRING errorPortName;
    00592     NTSTATUS status;
    00593     ULONG maxMessageLength;
    00594     SECURITY_QUALITY_OF_SERVICE dynamicQos;
    00595
    00596     PAGED_CODE();
    00597
    00598     //
    00599     // If the ErrorLogPort is connected then return true.
    00600     //
    00601
    00602     if (ErrorLogPortConnected) {
    00603
    00604         //
    00605         // The port is connect return.
    00606         //
    00607
    00608         return(TRUE);
    00609     }
    00610
    00611     //
    00612     // Set up the security quality of service parameters to use over the
    00613     // port.  Use the most efficient (least overhead) - which is dynamic
    00614     // rather than static tracking.
    00615     //
    00616
    00617     dynamicQos.ImpersonationLevel = SecurityImpersonation;
    00618     dynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
    00619     dynamicQos.EffectiveOnly = TRUE;
    00620
    00621     //
    00622     // Generate the string structure for describing the error logger's port.
    00623     //
    00624
    00625     RtlInitUnicodeString( &errorPortName, ELF_PORT_NAME_U );
    00626
    00627     status = NtConnectPort( &ErrorLogPort,
    00628                             &errorPortName,
    00629                             &dynamicQos,
    00630                             (PPORT_VIEW) NULL,
    00631                             (PREMOTE_PORT_VIEW) NULL,
    00632                             &maxMessageLength,
    00633                             (PVOID) NULL,
    00634                             (PULONG) NULL );
    00635
    00636     if (NT_SUCCESS( status )) {
    00637         if (maxMessageLength >= IO_ERROR_LOG_MESSAGE_LENGTH) {
    00638             ErrorLogPortConnected = TRUE;
    00639             return(TRUE);
    00640         } else {
    00641             NtClose(ErrorLogPort);
    00642         }
    00643     }
    00644
    00645     //
    00646     // The port was not successfully opened, or its message size was unsuitable
    00647     // for use here.  Queue a later request to run the error log thread.
    00648     //
    00649
    00650     IopErrorLogQueueRequest();
    00651
    00652     //
    00653     // The port could not be connected at this time return false.
    00654     //
    00655
    00656     return(FALSE);
    00657 }

VOID IopErrorLogDpc | ( | IN struct _KDPC * | Dpc,
|  | IN PVOID | DeferredContext,
|  | IN PVOID | SystemArgument1,
|  | IN PVOID | SystemArgument2
| ) |

Definition at line 660 of file errorlog.c.

References DelayedWorkQueue, ExFreePool(), ExInitializeWorkItem, ExQueueWorkItem(), IopErrorLogThread(), IopErrorLogWorkItem, and NULL.

Referenced by IopErrorLogQueueRequest().

    00669                    :
    00670
    00671     This routine queues a work request to the worker thread to process logged
    00672     errors. It is called by a timer DPC when the error log port cannot be
    00673     connected.  The DPC structure itself is freed by this routine.
    00674
    00675 Arguments:
    00676
    00677     Dpc - Supplies a pointer to the DPC structure.  This structure is freed by
    00678         this routine.
    00679
    00680     DeferredContext - Unused.
    00681
    00682     SystemArgument1 - Unused.
    00683
    00684     SystemArgument2 - Unused.
    00685
    00686 Return Value:
    00687
    00688     None
    00689
    00690 --*/
    00691
    00692 {
    00693     //
    00694     // Free the DPC structure if there is one.
    00695     //
    00696
    00697     if (Dpc != NULL) {
    00698         ExFreePool(Dpc);
    00699     }
    00700
    00701     ExInitializeWorkItem( &IopErrorLogWorkItem, IopErrorLogThread, NULL );
    00702
    00703     ExQueueWorkItem( &IopErrorLogWorkItem, DelayedWorkQueue );
    00704 }

PLIST_ENTRY IopErrorLogGetEntry | ( |  | ) |

Definition at line 707 of file errorlog.c.

References FALSE, IopErrorLogListHead, IopErrorLogLock, IopErrorLogPortPending, and NULL.

Referenced by IopErrorLogThread().

    00712                    :
    00713
    00714     This routine gets the next entry from the head of the error log queue
    00715     and returns it to the caller.
    00716
    00717 Arguments:
    00718
    00719     None.
    00720
    00721 Return Value:
    00722
    00723     The return value is a pointer to the packet removed, or NULL if there were
    00724     no packets on the queue.
    00725
    00726 --*/
    00727
    00728 {
    00729     KIRQL irql;
    00730     PLIST_ENTRY listEntry;
    00731
    00732     //
    00733     // Remove the next packet from the queue, if there is one.
    00734     //
    00735
    00736     ExAcquireSpinLock( &IopErrorLogLock, &irql );
    00737     if (IsListEmpty( &IopErrorLogListHead )) {
    00738
    00739         //
    00740         // Indicate no more work will be done in the context of this worker
    00741         // thread and indicate to the caller that no packets were located.
    00742         //
    00743
    00744         IopErrorLogPortPending = FALSE;
    00745         listEntry = (PLIST_ENTRY) NULL;
    00746     } else {
    00747
    00748         //
    00749         // Remove the next packet from the head of the list.
    00750         //
    00751
    00752         listEntry = RemoveHeadList( &IopErrorLogListHead );
    00753     }
    00754
    00755     ExReleaseSpinLock( &IopErrorLogLock, irql );
    00756     return listEntry;
    00757 }

VOID IopErrorLogQueueRequest | ( | VOID |  | ) |

Definition at line 760 of file errorlog.c.

References _IOP_ERROR_LOG_CONTEXT::ErrorLogDpc, _IOP_ERROR_LOG_CONTEXT::ErrorLogTimer, ExAllocatePool, FALSE, IopErrorLogDpc(), IopErrorLogPortPending, KeInitializeDpc(), KeInitializeTimer(), KeSetTimer(), NonPagedPool, NULL, PAGED_CODE, and PIOP_ERROR_LOG_CONTEXT.

Referenced by IopErrorLogConnectPort(), and IopErrorLogThread().

    00766                    :
    00767
    00768     This routine sets a timer to fire after 30 seconds.  The timer queues a
    00769     DPC which then queues a worker thread request to run the error log thread
    00770     routine.
    00771
    00772 Arguments:
    00773
    00774     None.
    00775
    00776 Return Value:
    00777
    00778     None.
    00779
    00780 --*/
    00781
    00782 {
    00783     LARGE_INTEGER interval;
    00784     PIOP_ERROR_LOG_CONTEXT context;
    00785
    00786     PAGED_CODE();
    00787
    00788     //
    00789     // Allocate a context block which will contain the timer and the DPC.
    00790     //
    00791
    00792     context = ExAllocatePool( NonPagedPool, sizeof( IOP_ERROR_LOG_CONTEXT ) );
    00793
    00794     if (context == NULL) {
    00795
    00796         //
    00797         // The context block could not be allocated. Clear the error log
    00798         // pending bit. If there is another error then a new attempt will
    00799         // be made.  Note the spinlock does not need to be held here since
    00800         // new attempt should be made later not right now, so if another
    00801         // error log packet is currently being queue, it waits with the
    00802         // others.
    00803         //
    00804
    00805         IopErrorLogPortPending = FALSE;
    00806         return;
    00807     }
    00808
    00809     KeInitializeDpc( &context->ErrorLogDpc,
    00810                      IopErrorLogDpc,
    00811                      NULL );
    00812
    00813     KeInitializeTimer( &context->ErrorLogTimer );
    00814
    00815     //
    00816     // Delay for 30 seconds and try for the port again.
    00817     //
    00818
    00819     interval.QuadPart = - 10 * 1000 * 1000 * 30;
    00820
    00821     //
    00822     // Set the timer to fire a DPC in 30 seconds.
    00823     //
    00824
    00825     KeSetTimer( &context->ErrorLogTimer, interval, &context->ErrorLogDpc );
    00826 }

VOID IopErrorLogRequeueEntry | ( | IN PLIST_ENTRY | ListEntry | ) |

Definition at line 829 of file errorlog.c.

References ErrorLogPortConnected, FALSE, IopErrorLogListHead, and IopErrorLogLock.

Referenced by IopErrorLogThread().

    00835                    :
    00836
    00837     This routine puts an error packet back at the head of the error log queue
    00838     since it cannot be processed at the moment.
    00839
    00840 Arguments:
    00841
    00842     ListEntry - Supplies a pointer to the packet to be placed back onto the
    00843         error log queue.
    00844
    00845 Return Value:
    00846
    00847     None.
    00848
    00849 --*/
    00850
    00851 {
    00852     KIRQL irql;
    00853
    00854     //
    00855     // Simply insert the packet back onto the head of the queue, indicate that
    00856     // the error log port is not connected, queue a request to check again
    00857     // soon, and return.
    00858     //
    00859
    00860     ExAcquireSpinLock( &IopErrorLogLock, &irql );
    00861     InsertHeadList( &IopErrorLogListHead, ListEntry );
    00862     ErrorLogPortConnected = FALSE;
    00863     ExReleaseSpinLock( &IopErrorLogLock, irql );
    00864 }
    }

VOID IopErrorLogThread | ( | IN PVOID | StartContext | ) |

Definition at line 88 of file errorlog.c.

References CHAR, _ERROR_LOG_ENTRY::DeviceObject, _DRIVER_OBJECT::DriverName, _ERROR_LOG_ENTRY::DriverObject, ERROR_LOG_ENTRY, ErrorLogPort, ExAllocatePool, ExFreePool(), ExInterlockedAddUlong(), IO_ERROR_NAME_LENGTH, IO_TYPE_ERROR_MESSAGE, IopErrorLogAllocation, IopErrorLogAllocationLock, IopErrorLogConnectPort(), IopErrorLogGetEntry(), IopErrorLogQueueRequest(), IopErrorLogRequeueEntry(), L, _ERROR_LOG_ENTRY::ListEntry, NT_SUCCESS, NtClose(), NtRequestPort(), NTSTATUS(), NULL, ObDereferenceObject, ObQueryNameString(), PAGED_CODE, PagedPool, PERROR_LOG_ENTRY, _ERROR_LOG_ENTRY::Size, _ERROR_LOG_ENTRY::TimeStamp, and USHORT.

Referenced by IopErrorLogDpc(), and IoWriteErrorLogEntry().

    00094                    :
    00095
    00096     This is the main loop for the I/O error log thread which executes in the
    00097     system process context.  This routine is started when the system is
    00098     initialized.
    00099
    00100 Arguments:
    00101
    00102     StartContext - Startup context; not used.
    00103
    00104 Return Value:
    00105
    00106     None.
    00107
    00108 --*/
    00109
    00110 {
    00111     PERROR_LOG_ENTRY errorLogEntry;
    00112     UNICODE_STRING nameString;
    00113     PLIST_ENTRY listEntry;
    00114     PIO_ERROR_LOG_MESSAGE errorMessage;
    00115     NTSTATUS status;
    00116     PELF_PORT_MSG portMessage;
    00117     PCHAR objectName;
    00118     ULONG messageLength;
    00119     ULONG driverNameLength;
    00120     ULONG deviceNameLength;
    00121     ULONG objectNameLength;
    00122     ULONG remainingLength;
    00123     ULONG stringLength;
    00124     CHAR nameBuffer[IO_ERROR_NAME_LENGTH+sizeof( OBJECT_NAME_INFORMATION )];
    00125     PDRIVER_OBJECT driverObject;
    00126     POBJECT_NAME_INFORMATION nameInformation;
    00127     PIO_ERROR_LOG_PACKET errorData;
    00128     PWSTR string;
    00129
    00130     PAGED_CODE();
    00131
    00132     UNREFERENCED_PARAMETER( StartContext );
    00133
    00134     //
    00135     // Check to see whether a connection has been made to the error log
    00136     // port.  If the port is not connected return.
    00137     //
    00138
    00139     if (!IopErrorLogConnectPort()) {
    00140
    00141         //
    00142         // The port could not be connected.  A timer was started that will
    00143         // try again later.
    00144         //
    00145
    00146         return;
    00147     }
    00148
    00149     //
    00150     // Allocate and zero the port message structure, include space for the
    00151     // name of the device and driver.
    00152     //
    00153
    00154     messageLength = IO_ERROR_LOG_MESSAGE_LENGTH;
    00155     portMessage = ExAllocatePool(PagedPool, messageLength);
    00156
    00157     if (portMessage == NULL) {
    00158
    00159         //
    00160         // The message buffer could not be allocated. Request that
    00161         // the error log thread routine be called again later.
    00162         //
    00163
    00164         IopErrorLogQueueRequest();
    00165         return;
    00166     }
    00167
    00168     RtlZeroMemory( portMessage, sizeof( *portMessage ) );
    00169     portMessage->MessageType = IO_ERROR_LOG;
    00170     errorMessage = &portMessage->u.IoErrorLogMessage;
    00171
    00172     nameInformation = (PVOID) &nameBuffer;
    00173
    00174     //
    00175     // Now enter the main loop for this thread.  This thread performs the
    00176     // following operations:
    00177     //
    00178     //   1)  If a connection has been made to the error log port, dequeue a
    00179     //       packet from the queue head and attempt to send it to the port.
    00180     //
    00181     //   2)  If the send works, loop sending packets until there are no more
    00182     //       packets;  otherwise, indicate that the connection has been broken,
    00183     //       cleanup, place the packet back onto the head of the queue and
    00184     //       return.
    00185     //
    00186     //   3)  After all the packets are sent clear the pending variable and
    00187     //       return.
    00188     //
    00189
    00190     for (;;) {
    00191
    00192         //
    00193         // Loop dequeueing  packets from the queue head and attempt to send
    00194         // each to the port.
    00195         //
    00196         // If the send works, continue looping until there are no more packets.
    00197         // Otherwise, indicate that the connection has been broken, cleanup,
    00198         // place the packet back onto the head of the queue, and start from the
    00199         // top of the loop again.
    00200         //
    00201
    00202         if (!(listEntry = IopErrorLogGetEntry())) {
    00203             break;
    00204         }
    00205
    00206         errorLogEntry = CONTAINING_RECORD( listEntry,
    00207                                            ERROR_LOG_ENTRY,
    00208                                            ListEntry );
    00209
    00210         //
    00211         // The size of errorLogEntry is ERROR_LOG_ENTRY +
    00212         // IO_ERROR_LOG_PACKET + (Extra Dump data).  The size of the
    00213         // initial message length should be IO_ERROR_LOG_MESSAGE +
    00214         // (Extra Dump data), since IO_ERROR_LOG_MESSAGE contains an
    00215         // IO_ERROR_LOG_PACKET. Using the above calculations set the
    00216         // message length.
    00217         //
    00218
    00219         messageLength = sizeof( IO_ERROR_LOG_MESSAGE ) -
    00220             sizeof( ERROR_LOG_ENTRY ) - sizeof( IO_ERROR_LOG_PACKET ) +
    00221             errorLogEntry->Size;
    00222
    00223         errorData = (PIO_ERROR_LOG_PACKET) (errorLogEntry + 1);
    00224
    00225         //
    00226         // Copy the error log packet and the extra data to the message.
    00227         //
    00228
    00229         RtlMoveMemory( &errorMessage->EntryData,
    00230                        errorData,
    00231                        errorLogEntry->Size - sizeof( ERROR_LOG_ENTRY ) );
    00232
    00233         errorMessage->TimeStamp = errorLogEntry->TimeStamp;
    00234         errorMessage->Type = IO_TYPE_ERROR_MESSAGE;
    00235
    00236         //
    00237         // Add the driver and device name string.  These strings go
    00238         // before the error log strings.  Just write over the current
    00239         // strings and they will be recopied later.
    00240         //
    00241
    00242         if (errorData->NumberOfStrings != 0) {
    00243
    00244             //
    00245             // Start the driver and device strings where the current
    00246             // strings start.
    00247             //
    00248
    00249             objectName = (PCHAR) (&errorMessage->EntryData) +
    00250                                  errorData->StringOffset;
    00251
    00252         } else {
    00253
    00254             //
    00255             // Put the driver and device strings at the end of the
    00256             // data.
    00257             //
    00258
    00259             objectName = (PCHAR) errorMessage + messageLength;
    00260
    00261         }
    00262
    00263         //
    00264         // Make sure the driver offset starts on an even bountry.
    00265         //
    00266
    00267         objectName = (PCHAR) ((ULONG_PTR) (objectName + sizeof(WCHAR) - 1) &
    00268             ~(ULONG_PTR)(sizeof(WCHAR) - 1));
    00269
    00270         errorMessage->DriverNameOffset = (ULONG)(objectName - (PCHAR) errorMessage);
    00271
    00272         remainingLength = (ULONG)((PCHAR) portMessage + IO_ERROR_LOG_MESSAGE_LENGTH
    00273                             - objectName);
    00274
    00275         //
    00276         // Calculate the length of the driver name and
    00277         // the device name. If the driver object has a name then get
    00278         // it from there; otherwise try to query the device object.
    00279         //
    00280
    00281         driverObject = errorLogEntry->DriverObject;
    00282         driverNameLength = 0;
    00283
    00284         if (driverObject != NULL) {
    00285             if (driverObject->DriverName.Buffer != NULL) {
    00286
    00287                 nameString.Buffer = driverObject->DriverName.Buffer;
    00288                 driverNameLength = driverObject->DriverName.Length;
    00289             }
    00290
    00291             if (driverNameLength == 0) {
    00292
    00293                 //
    00294                 // Try to query the driver object for a name.
    00295                 //
    00296
    00297                 status = ObQueryNameString( driverObject,
    00298                                             nameInformation,
    00299                                             IO_ERROR_NAME_LENGTH + sizeof( OBJECT_NAME_INFORMATION ),
    00300                                             &objectNameLength );
    00301
    00302                 if (!NT_SUCCESS( status ) || !nameInformation->Name.Length) {
    00303
    00304                     //
    00305                     // No driver name was available.
    00306                     //
    00307
    00308                     driverNameLength = 0;
    00309
    00310                 } else {
    00311                     nameString = nameInformation->Name;
    00312                 }
    00313
    00314             }
    00315
    00316         } else {
    00317
    00318             //
    00319             // If no driver object, this message must be from the
    00320             // kernel.   We need to point the eventlog service to
    00321             // an event message file containing ntstatus messages,
    00322             // ie, ntdll, we do this by claiming this event is an
    00323             // application popup.
    00324             //
    00325
    00326             nameString.Buffer = L"Application Popup";
    00327             driverNameLength = wcslen(nameString.Buffer) * sizeof(WCHAR);
    00328         }
    00329
    00330         if (driverNameLength != 0 ) {
    00331
    00332             //
    00333             // Pick out the module name.
    00334             //
    00335
    00336             string = nameString.Buffer +
    00337                 (driverNameLength / sizeof(WCHAR));
    00338
    00339             driverNameLength = sizeof(WCHAR);
    00340             string--;
    00341             while (*string != L'\\' && string != nameString.Buffer) {
    00342                 string--;
    00343                 driverNameLength += sizeof(WCHAR);
    00344             }
    00345
    00346             if (*string == L'\\') {
    00347                 string++;
    00348                 driverNameLength -= sizeof(WCHAR);
    00349             }
    00350
    00351             //
    00352             // Ensure there is enough room for the driver name.
    00353             // Save space for 3 NULLs one for the driver name,
    00354             // one for the device name and one for strings.
    00355             //
    00356
    00357             if (driverNameLength > remainingLength - (3 * sizeof(WCHAR))) {
    00358                 driverNameLength = remainingLength - (3 * sizeof(WCHAR));
    00359             }
    00360
    00361             RtlMoveMemory(
    00362                 objectName,
    00363                 string,
    00364                 driverNameLength
    00365                 );
    00366
    00367         }
    00368
    00369         //
    00370         // Add a null after the driver name even if there is no
    00371         // driver name.
    00372         //
    00373
    00374        *((PWSTR) (objectName + driverNameLength)) = L'\0';
    00375        driverNameLength += sizeof(WCHAR);
    00376
    00377         //
    00378         // Determine where the next string goes.
    00379         //
    00380
    00381         objectName += driverNameLength;
    00382         remainingLength -= driverNameLength;
    00383
    00384         errorMessage->EntryData.StringOffset = (USHORT)(objectName - (PCHAR) errorMessage);
    00385
    00386         if (errorLogEntry->DeviceObject != NULL) {
    00387
    00388             status = ObQueryNameString( errorLogEntry->DeviceObject,
    00389                                         nameInformation,
    00390                                         IO_ERROR_NAME_LENGTH + sizeof( OBJECT_NAME_INFORMATION ) - driverNameLength,
    00391                                         &objectNameLength );
    00392
    00393             if (!NT_SUCCESS( status ) || !nameInformation->Name.Length) {
    00394
    00395                 //
    00396                 // No device name was available. Add a Null string.
    00397                 //
    00398
    00399                 nameInformation->Name.Length = 0;
    00400                 nameInformation->Name.Buffer = L"\0";
    00401
    00402             }
    00403
    00404             //
    00405             // No device name was available. Add a Null string.
    00406             // Always add a device name string so that the
    00407             // insertion string counts are correct.
    00408             //
    00409
    00410         } else {
    00411
    00412                 //
    00413                 // No device name was available. Add a Null string.
    00414                 // Always add a device name string so that the
    00415                 // insertion string counts are correct.
    00416                 //
    00417
    00418                 nameInformation->Name.Length = 0;
    00419                 nameInformation->Name.Buffer = L"\0";
    00420
    00421         }
    00422
    00423         deviceNameLength = nameInformation->Name.Length;
    00424
    00425         //
    00426         // Ensure there is enough room for the device name.
    00427         // Save space for a NULL.
    00428         //
    00429
    00430         if (deviceNameLength > remainingLength - (2 * sizeof(WCHAR))) {
    00431
    00432             deviceNameLength = remainingLength - (2 * sizeof(WCHAR));
    00433
    00434         }
    00435
    00436         RtlMoveMemory( objectName,
    00437                        nameInformation->Name.Buffer,
    00438                        deviceNameLength );
    00439
    00440         //
    00441         // Add a null after the device name even if there is no
    00442         // device name.
    00443         //
    00444
    00445         *((PWSTR) (objectName + deviceNameLength)) = L'\0';
    00446         deviceNameLength += sizeof(WCHAR);
    00447
    00448         //
    00449         // Update the string count for the device object.
    00450         //
    00451
    00452         errorMessage->EntryData.NumberOfStrings++;
    00453         objectName += deviceNameLength;
    00454         remainingLength -= deviceNameLength;
    00455
    00456         if (errorData->NumberOfStrings) {
    00457
    00458             stringLength = errorLogEntry->Size - sizeof( ERROR_LOG_ENTRY ) -
    00459                             errorData->StringOffset;
    00460
    00461             //
    00462             // Ensure there is enough room for the strings.
    00463             // Save space for a NULL.
    00464             //
    00465
    00466             if (stringLength > remainingLength - sizeof(WCHAR)) {
    00467
    00468
    00469                 messageLength -= stringLength - remainingLength;
    00470                 stringLength = remainingLength - sizeof(WCHAR);
    00471
    00472             }
    00473
    00474             //
    00475             // Copy the strings to the end of the message.
    00476             //
    00477
    00478             RtlMoveMemory( objectName,
    00479                            (PCHAR) errorData + errorData->StringOffset,
    00480                            stringLength );
    00481
    00482             //
    00483             // Add a null after the strings
    00484             //
    00485             //
    00486
    00487            *((PWSTR) (objectName + stringLength)) = L'\0';
    00488
    00489         }
    00490
    00491         //
    00492         // Update the message length.
    00493         //
    00494
    00495         errorMessage->DriverNameLength = (USHORT) driverNameLength;
    00496         messageLength += deviceNameLength + driverNameLength;
    00497         errorMessage->Size = (USHORT) messageLength;
    00498
    00499         messageLength += FIELD_OFFSET ( ELF_PORT_MSG, u ) -
    00500             FIELD_OFFSET (ELF_PORT_MSG, MessageType);
    00501
    00502         portMessage->PortMessage.u1.s1.TotalLength = (USHORT)
    00503             (sizeof( PORT_MESSAGE ) + messageLength);
    00504         portMessage->PortMessage.u1.s1.DataLength = (USHORT) (messageLength);
    00505         status = NtRequestPort( ErrorLogPort, (PPORT_MESSAGE) portMessage );
    00506
    00507         if (!NT_SUCCESS( status )) {
    00508
    00509             //
    00510             // The send failed.  Place the packet back onto the head of
    00511             // the error log queue, forget the current connection since
    00512             // it no longer works, and close the handle to the port.
    00513             // Set a timer up for another attempt later.
    00514             // Finally, exit the loop since there is no connection
    00515             // to do any work on.
    00516             //
    00517
    00518             NtClose( ErrorLogPort );
    00519
    00520             IopErrorLogRequeueEntry( &errorLogEntry->ListEntry );
    00521
    00522             IopErrorLogQueueRequest();
    00523
    00524             break;
    00525
    00526         } else {
    00527
    00528             //
    00529             // The send worked fine.  Free the packet and the update
    00530             // the allocation count.
    00531             //
    00532
    00533             ExInterlockedAddUlong( &IopErrorLogAllocation,
    00534                                    (ULONG) ( -errorLogEntry->Size ),
    00535                                    &IopErrorLogAllocationLock );
    00536
    00537             //
    00538             // Dereference the object pointers now that the name has been
    00539             // captured.
    00540             //
    00541
    00542
    00543             if (errorLogEntry->DeviceObject != NULL) {
    00544                 ObDereferenceObject( errorLogEntry->DeviceObject );
    00545             }
    00546
    00547             if (driverObject != NULL) {
    00548                 ObDereferenceObject( errorLogEntry->DriverObject );
    00549             }
    00550
    00551             ExFreePool( errorLogEntry );
    00552
    00553         } // if
    00554
    00555     } // for
    00556
    00557     //
    00558     // Finally, free the message buffer and return.
    00559     //
    00560
    00561     ExFreePool(portMessage);
    00562
    00563 }

## Variable Documentation

HANDLE ErrorLogPort

| Definition at line 76 of file errorlog.c. Referenced by IopErrorLogConnectPort(), and IopErrorLogThread().

BOOLEAN ErrorLogPortConnected

| Definition at line 77 of file errorlog.c. Referenced by IopErrorLogConnectPort(), and IopErrorLogRequeueEntry().

BOOLEAN IopErrorLogDisabledThisBoot

| Definition at line 79 of file errorlog.c. Referenced by IoInitSystem(), and IoWriteErrorLogEntry().

BOOLEAN IopErrorLogPortPending

| Definition at line 78 of file errorlog.c. Referenced by IopErrorLogGetEntry(), IopErrorLogQueueRequest(), and IoWriteErrorLogEntry().

WORK_QUEUE_ITEM IopErrorLogWorkItem

| Definition at line 75 of file errorlog.c. Referenced by IopErrorLogDpc(), and IoWriteErrorLogEntry().