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

misc.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 misc.c 00008 00009 Abstract: 00010 00011 This module contains the code to implement the NtFlushBuffersFile, 00012 NtSetNewSizeFile, IoQueueWorkItem, and NtCancelIoFile system services 00013 for the NT I/O system. 00014 00015 Author: 00016 00017 Darryl E. Havens (darrylh) 22-Jun-1989 00018 00019 Environment: 00020 00021 Kernel mode only 00022 00023 Revision History: 00024 00025 00026 --*/ 00027 00028 #include "iop.h" 00029 00030 #ifdef ALLOC_PRAGMA 00031 #pragma alloc_text(PAGE, NtCancelIoFile) 00032 #pragma alloc_text(PAGE, NtDeleteFile) 00033 #pragma alloc_text(PAGE, NtFlushBuffersFile) 00034 #pragma alloc_text(PAGE, NtQueryAttributesFile) 00035 #pragma alloc_text(PAGE, NtQueryFullAttributesFile) 00036 #endif 00037 00038 // 00039 // Local function prototypes follow 00040 // 00041 00042 VOID 00043 IopProcessWorkItem( 00044 IN PVOID Parameter 00045 ); 00046 00047 00048 NTSTATUS 00049 NtCancelIoFile( 00050 IN HANDLE FileHandle, 00051 OUT PIO_STATUS_BLOCK IoStatusBlock 00052 ) 00053 00054 /*++ 00055 00056 Routine Description: 00057 00058 This service causes all pending I/O operations for the specified file to be 00059 marked as canceled. Most types of operations can be canceled immediately, 00060 while others may continue toward completion before they are actually 00061 canceled and the caller is notified. 00062 00063 Only those pending operations that were issued by the current thread using 00064 the specified handle are canceled. Any operations issued for the file by 00065 any other thread or any other process continues normally. 00066 00067 Arguments: 00068 00069 FileHandle - Supplies a handle to the file whose operations are to be 00070 canceled. 00071 00072 IoStatusBlock - Address of the caller's I/O status block. 00073 00074 Return Value: 00075 00076 The status returned is the final completion status of the operation. 00077 00078 --*/ 00079 00080 { 00081 PIRP irp; 00082 NTSTATUS status; 00083 PFILE_OBJECT fileObject; 00084 KPROCESSOR_MODE requestorMode; 00085 PETHREAD thread; 00086 BOOLEAN found = FALSE; 00087 PLIST_ENTRY header; 00088 PLIST_ENTRY entry; 00089 KIRQL irql; 00090 00091 PAGED_CODE(); 00092 00093 // 00094 // Get the previous mode; i.e., the mode of the caller. 00095 // 00096 00097 requestorMode = KeGetPreviousMode(); 00098 00099 if (requestorMode != KernelMode) { 00100 00101 // 00102 // The caller's access mode is user, so probe each of the arguments 00103 // and capture them as necessary. If any failures occur, the condition 00104 // handler will be invoked to handle them. It will simply cleanup and 00105 // return an access violation status code back to the system service 00106 // dispatcher. 00107 // 00108 00109 try { 00110 00111 // 00112 // The IoStatusBlock parameter must be writeable by the caller. 00113 // 00114 00115 ProbeForWriteIoStatus( IoStatusBlock ); 00116 00117 } except(EXCEPTION_EXECUTE_HANDLER) { 00118 00119 // 00120 // An exception was incurred attempting to probe the caller' 00121 // I/O status block. Simply return an appropriate error status 00122 // code. 00123 // 00124 00125 return GetExceptionCode(); 00126 } 00127 } 00128 00129 // 00130 // There were no blatant errors so far, so reference the file object so 00131 // the target device object can be found. Note that if the handle does 00132 // not refer to a file object, or if the caller does not have the required 00133 // access to the file, then it will fail. 00134 // 00135 00136 status = ObReferenceObjectByHandle( FileHandle, 00137 0, 00138 IoFileObjectType, 00139 requestorMode, 00140 (PVOID *) &fileObject, 00141 NULL ); 00142 if (!NT_SUCCESS( status )) { 00143 return(status); 00144 } 00145 00146 // 00147 // Note that here the I/O system would normally make a check to determine 00148 // whether or not the file was opened for synchronous I/O. If it was, then 00149 // it would attempt to exclusively acquire the file object lock. However, 00150 // since this service is attempting to cancel all of the I/O for the file, 00151 // it does not make much sense to wait until it has all completed before 00152 // attempting to cancel it. 00153 // 00154 00155 // 00156 // Get the address of the current thread. The thread contains a list of 00157 // the pending operations for this file. 00158 // 00159 00160 thread = PsGetCurrentThread(); 00161 00162 // 00163 // Update the operation count statistic for the current process for 00164 // operations other than read and write. 00165 // 00166 00167 IopUpdateOtherOperationCount(); 00168 00169 // 00170 // Walk the list of IRPs on the thread's pending I/O queue looking for IRPs 00171 // which specify the same file as the FileHandle refers to. For each IRP 00172 // found, set its cancel flag. If no IRPs are found, simply complete the 00173 // I/O here. The only synchronization needed here is to block out all APCs 00174 // for this thread so that no I/O can complete and remove packets from the 00175 // queue. No considerations need be made for multi-processing since this 00176 // thread can only be running on one processor at a time and this routine 00177 // has control of the thread for now. 00178 // 00179 00180 KeRaiseIrql( APC_LEVEL, &irql ); 00181 00182 header = &thread->IrpList; 00183 entry = thread->IrpList.Flink; 00184 00185 while (header != entry) { 00186 00187 // 00188 // An IRP has been found for this thread. If the IRP refers to the 00189 // appropriate file object, set its cancel flag and remember that it 00190 // was found; otherwise, simply continue the loop. 00191 // 00192 00193 irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry ); 00194 if (irp->Tail.Overlay.OriginalFileObject == fileObject) { 00195 found = TRUE; 00196 IoCancelIrp( irp ); 00197 } 00198 00199 entry = entry->Flink; 00200 } 00201 00202 // 00203 // Lower the IRQL back down to what it was on entry to this procedure. 00204 // 00205 00206 KeLowerIrql( irql ); 00207 00208 if (found) { 00209 00210 LARGE_INTEGER interval; 00211 00212 // 00213 // Delay execution for a time and let the request 00214 // finish. The delay time is 10ms. 00215 // 00216 00217 interval.QuadPart = -10 * 1000 * 10; 00218 00219 // 00220 // Wait for a while so the canceled requests can complete. 00221 // 00222 00223 while (found) { 00224 00225 (VOID) KeDelayExecutionThread( KernelMode, FALSE, &interval ); 00226 00227 found = FALSE; 00228 00229 // 00230 // Raise the IRQL to prevent modification to the IRP list by the 00231 // thread's APC routine. 00232 // 00233 00234 KeRaiseIrql( APC_LEVEL, &irql ); 00235 00236 // 00237 // Check the IRP list for requests which refer to the specified 00238 // file object. 00239 // 00240 00241 entry = thread->IrpList.Flink; 00242 00243 while (header != entry) { 00244 00245 // 00246 // An IRP has been found for this thread. If the IRP refers 00247 // to the appropriate file object, remember that it 00248 // was found; otherwise, simply continue the loop. 00249 // 00250 00251 irp = CONTAINING_RECORD( entry, IRP, ThreadListEntry ); 00252 if (irp->Tail.Overlay.OriginalFileObject == fileObject) { 00253 found = TRUE; 00254 break; 00255 } 00256 00257 entry = entry->Flink; 00258 } 00259 00260 // 00261 // Lower the IRQL back down to what it was on entry to this procedure. 00262 // 00263 00264 KeLowerIrql( irql ); 00265 00266 } 00267 } 00268 00269 try { 00270 00271 // 00272 // Write the status back to the user. 00273 // 00274 00275 IoStatusBlock->Status = STATUS_SUCCESS; 00276 IoStatusBlock->Information = 0L; 00277 00278 } except(EXCEPTION_EXECUTE_HANDLER) { 00279 00280 // 00281 // An exception was incurred attempting to write the caller's 00282 // I/O status block; however, the service completed sucessfully so 00283 // just return sucess. 00284 // 00285 00286 } 00287 00288 // 00289 // Dereference the file object. 00290 // 00291 00292 ObDereferenceObject( fileObject ); 00293 00294 return STATUS_SUCCESS; 00295 } 00296 00297 NTSTATUS 00298 NtDeleteFile( 00299 IN POBJECT_ATTRIBUTES ObjectAttributes 00300 ) 00301 00302 /*++ 00303 00304 Routine Description: 00305 00306 This service deletes the specified file. 00307 00308 Arguments: 00309 00310 ObjectAttributes - Supplies the attributes to be used for file object (name, 00311 SECURITY_DESCRIPTOR, etc.) 00312 00313 Return Value: 00314 00315 The status returned is the final completion status of the operation. 00316 00317 --*/ 00318 00319 { 00320 KPROCESSOR_MODE requestorMode; 00321 NTSTATUS status; 00322 OPEN_PACKET openPacket; 00323 DUMMY_FILE_OBJECT localFileObject; 00324 HANDLE handle; 00325 00326 PAGED_CODE(); 00327 00328 // 00329 // Get the previous mode; i.e., the mode of the caller. 00330 // 00331 00332 requestorMode = KeGetPreviousMode(); 00333 00334 // 00335 // Build a parse open packet that tells the parse method to open the file 00336 // for open for delete access w/the delete bit set, and then close it. 00337 // 00338 00339 RtlZeroMemory( &openPacket, sizeof( OPEN_PACKET ) ); 00340 00341 openPacket.Type = IO_TYPE_OPEN_PACKET; 00342 openPacket.Size = sizeof( OPEN_PACKET ); 00343 openPacket.CreateOptions = FILE_DELETE_ON_CLOSE; 00344 openPacket.ShareAccess = (USHORT) FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; 00345 openPacket.Disposition = FILE_OPEN; 00346 openPacket.DeleteOnly = TRUE; 00347 openPacket.LocalFileObject = &localFileObject; 00348 00349 // 00350 // Update the open count for this process. 00351 // 00352 00353 IopUpdateOtherOperationCount(); 00354 00355 // 00356 // Open the object by its name. Because of the special DeleteOnly flag 00357 // set in the open packet, the parse routine will open the file, and 00358 // then realize that it is only deleting the file, and will therefore 00359 // immediately dereference the file. This will cause the cleanup and 00360 // the close to be sent to the file system, thus causing the file to 00361 // be deleted. 00362 // 00363 00364 status = ObOpenObjectByName( ObjectAttributes, 00365 (POBJECT_TYPE) NULL, 00366 requestorMode, 00367 NULL, 00368 DELETE, 00369 &openPacket, 00370 &handle ); 00371 00372 // 00373 // The operation is successful if the parse check field of the open packet 00374 // indicates that the parse routine was actually invoked, and the final 00375 // status field of the packet is set to success. 00376 // 00377 00378 if (openPacket.ParseCheck != OPEN_PACKET_PATTERN) { 00379 return status; 00380 } else { 00381 return openPacket.FinalStatus; 00382 } 00383 } 00384 00385 NTSTATUS 00386 NtFlushBuffersFile( 00387 IN HANDLE FileHandle, 00388 OUT PIO_STATUS_BLOCK IoStatusBlock 00389 ) 00390 00391 /*++ 00392 00393 Routine Description: 00394 00395 This service causes all buffered data to the file to be written. 00396 00397 Arguments: 00398 00399 FileHandle - Supplies a handle to the file whose buffers should be flushed. 00400 00401 IoStatusBlock - Address of the caller's I/O status block. 00402 00403 Return Value: 00404 00405 The status returned is the final completion status of the operation. 00406 00407 --*/ 00408 00409 { 00410 PIRP irp; 00411 NTSTATUS status; 00412 PFILE_OBJECT fileObject; 00413 PDEVICE_OBJECT deviceObject; 00414 PKEVENT event; 00415 KPROCESSOR_MODE requestorMode; 00416 PIO_STACK_LOCATION irpSp; 00417 IO_STATUS_BLOCK localIoStatus; 00418 OBJECT_HANDLE_INFORMATION objectHandleInformation; 00419 BOOLEAN synchronousIo; 00420 00421 PAGED_CODE(); 00422 00423 // 00424 // Get the previous mode; i.e., the mode of the caller. 00425 // 00426 00427 requestorMode = KeGetPreviousMode(); 00428 00429 if (requestorMode != KernelMode) { 00430 00431 // 00432 // The caller's access mode is not kernel so probe each of the arguments 00433 // and capture them as necessary. If any failures occur, the condition 00434 // handler will be invoked to handle them. It will simply cleanup and 00435 // return an access violation status code back to the system service 00436 // dispatcher. 00437 // 00438 00439 try { 00440 00441 // 00442 // The IoStatusBlock parameter must be writeable by the caller. 00443 // 00444 00445 ProbeForWriteIoStatus( IoStatusBlock ); 00446 00447 } except(EXCEPTION_EXECUTE_HANDLER) { 00448 00449 // 00450 // An exception was incurred attempting to probe the caller's 00451 // I/O status block. Simply return an appropriate error status 00452 // code. 00453 // 00454 00455 return GetExceptionCode(); 00456 00457 } 00458 } 00459 00460 // 00461 // There were no blatant errors so far, so reference the file object so 00462 // the target device object can be found. Note that if the handle does 00463 // not refer to a file object, or if the caller does not have the required 00464 // access to the file, then it will fail. 00465 // 00466 00467 status = ObReferenceObjectByHandle( FileHandle, 00468 0, 00469 IoFileObjectType, 00470 requestorMode, 00471 (PVOID *) &fileObject, 00472 &objectHandleInformation ); 00473 if (!NT_SUCCESS( status )) { 00474 return status; 00475 } 00476 00477 // 00478 // Ensure that the caller has either WRITE or APPEND access to the file 00479 // before allowing this call to continue. This is especially important 00480 // if the caller opened a volume, where a flush operation may flush more 00481 // than what this opener has written to buffers. Note however that if 00482 // this is a pipe, then the APPEND access cannot be made since this 00483 // access code is overlaid with the CREATE_PIPE_INSTANCE access. 00484 // 00485 00486 if (SeComputeGrantedAccesses( objectHandleInformation.GrantedAccess, 00487 (!(fileObject->Flags & FO_NAMED_PIPE) ? 00488 FILE_APPEND_DATA : 0) | 00489 FILE_WRITE_DATA ) == 0) { 00490 ObDereferenceObject( fileObject ); 00491 return STATUS_ACCESS_DENIED; 00492 } 00493 00494 // 00495 // Make a special check here to determine whether this is a synchronous 00496 // I/O operation. If it is, then wait here until the file is owned by 00497 // the current thread. If this is not a (serialized) synchronous I/O 00498 // operation, then allocate and initialize the local event. 00499 // 00500 00501 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 00502 00503 BOOLEAN interrupted; 00504 00505 if (!IopAcquireFastLock( fileObject )) { 00506 status = IopAcquireFileObjectLock( fileObject, 00507 requestorMode, 00508 (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), 00509 &interrupted ); 00510 if (interrupted) { 00511 ObDereferenceObject( fileObject ); 00512 return status; 00513 } 00514 } 00515 synchronousIo = TRUE; 00516 } else { 00517 00518 // 00519 // This is a synchronous API being invoked for a file that is opened 00520 // for asynchronous I/O. This means that this system service is 00521 // to synchronize the completion of the operation before returning 00522 // to the caller. A local event is used to do this. 00523 // 00524 00525 event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) ); 00526 if (event == NULL) { 00527 ObDereferenceObject( fileObject ); 00528 return STATUS_INSUFFICIENT_RESOURCES; 00529 } 00530 KeInitializeEvent( event, SynchronizationEvent, FALSE ); 00531 synchronousIo = FALSE; 00532 } 00533 00534 // 00535 // Set the file object to the Not-Signaled state. 00536 // 00537 00538 KeClearEvent( &fileObject->Event ); 00539 00540 // 00541 // Get the address of the target device object. 00542 // 00543 00544 deviceObject = IoGetRelatedDeviceObject( fileObject ); 00545 00546 // 00547 // Allocate and initialize the I/O Request Packet (IRP) for this operation. 00548 // The allocation is performed with an exception handler in case the 00549 // caller does not have enough quota to allocate the packet. 00550 00551 irp = IoAllocateIrp( deviceObject->StackSize, TRUE ); 00552 if (!irp) { 00553 00554 // 00555 // An exception was incurred while attempting to allocate the IRP. 00556 // Cleanup and return an appropriate error status code. 00557 // 00558 00559 if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) { 00560 ExFreePool( event ); 00561 } 00562 00563 IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL ); 00564 00565 return STATUS_INSUFFICIENT_RESOURCES; 00566 } 00567 irp->Tail.Overlay.OriginalFileObject = fileObject; 00568 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00569 irp->RequestorMode = requestorMode; 00570 00571 // 00572 // Fill in the service independent parameters in the IRP. 00573 // 00574 00575 if (synchronousIo) { 00576 irp->UserEvent = (PKEVENT) NULL; 00577 irp->UserIosb = IoStatusBlock; 00578 } else { 00579 irp->UserEvent = event; 00580 irp->UserIosb = &localIoStatus; 00581 irp->Flags = IRP_SYNCHRONOUS_API; 00582 } 00583 irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL; 00584 00585 // 00586 // Get a pointer to the stack location for the first driver. This is used 00587 // to pass the original function codes and parameters. 00588 // 00589 00590 irpSp = IoGetNextIrpStackLocation( irp ); 00591 irpSp->MajorFunction = IRP_MJ_FLUSH_BUFFERS; 00592 irpSp->FileObject = fileObject; 00593 00594 // 00595 // Queue the packet, call the driver, and synchronize appopriately with 00596 // I/O completion. 00597 // 00598 00599 status = IopSynchronousServiceTail( deviceObject, 00600 irp, 00601 fileObject, 00602 FALSE, 00603 requestorMode, 00604 synchronousIo, 00605 OtherTransfer ); 00606 00607 // 00608 // If the file for this operation was not opened for synchronous I/O, then 00609 // synchronization of completion of the I/O operation has not yet occurred 00610 // since the allocated event must be used for synchronous APIs on files 00611 // opened for asynchronous I/O. Synchronize the completion of the I/O 00612 // operation now. 00613 // 00614 00615 if (!synchronousIo) { 00616 00617 status = IopSynchronousApiServiceTail( status, 00618 event, 00619 irp, 00620 requestorMode, 00621 &localIoStatus, 00622 IoStatusBlock ); 00623 } 00624 00625 return status; 00626 } 00627 00628 NTSTATUS 00629 NtQueryAttributesFile( 00630 IN POBJECT_ATTRIBUTES ObjectAttributes, 00631 OUT PFILE_BASIC_INFORMATION FileInformation 00632 ) 00633 00634 /*++ 00635 00636 Routine Description: 00637 00638 This service queries the basic attributes information for a specified file. 00639 00640 Arguments: 00641 00642 ObjectAttributes - Supplies the attributes to be used for file object (name, 00643 SECURITY_DESCRIPTOR, etc.) 00644 00645 FileInformation - Supplies an output buffer to receive the returned file 00646 attributes information. 00647 00648 Return Value: 00649 00650 The status returned is the final completion status of the operation. 00651 00652 --*/ 00653 00654 { 00655 KPROCESSOR_MODE requestorMode; 00656 NTSTATUS status; 00657 OPEN_PACKET openPacket; 00658 DUMMY_FILE_OBJECT localFileObject; 00659 FILE_NETWORK_OPEN_INFORMATION networkInformation; 00660 HANDLE handle; 00661 00662 PAGED_CODE(); 00663 00664 // 00665 // Get the previous mode; i.e., the mode of the caller. 00666 // 00667 00668 requestorMode = KeGetPreviousMode(); 00669 00670 if (requestorMode != KernelMode) { 00671 00672 try { 00673 00674 // 00675 // The caller's mode is not kernel, so probe the output buffer. 00676 // 00677 00678 ProbeForWrite( FileInformation, 00679 sizeof( FILE_BASIC_INFORMATION ), 00680 sizeof( ULONG )); 00681 00682 } except(EXCEPTION_EXECUTE_HANDLER) { 00683 00684 // 00685 // An exception was incurred while probing the caller's parameters. 00686 // Simply return an appropriate error status code. 00687 // 00688 00689 return GetExceptionCode(); 00690 } 00691 } 00692 00693 // 00694 // Build a parse open packet that tells the parse method to open the file, 00695 // query the file's basic attributes, and close the file. 00696 // 00697 00698 RtlZeroMemory( &openPacket, sizeof( OPEN_PACKET ) ); 00699 00700 openPacket.Type = IO_TYPE_OPEN_PACKET; 00701 openPacket.Size = sizeof( OPEN_PACKET ); 00702 openPacket.ShareAccess = (USHORT) FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; 00703 openPacket.Disposition = FILE_OPEN; 00704 openPacket.CreateOptions = FILE_OPEN_REPARSE_POINT; 00705 openPacket.BasicInformation = FileInformation; 00706 openPacket.NetworkInformation = &networkInformation; 00707 openPacket.QueryOnly = TRUE; 00708 openPacket.LocalFileObject = &localFileObject; 00709 00710 // 00711 // Update the open count for this process. 00712 // 00713 00714 IopUpdateOtherOperationCount(); 00715 00716 // 00717 // Open the object by its name. Because of the special QueryOnly flag set 00718 // in the open packet, the parse routine will open the file, and then 00719 // realize that it is only performing a query. It will therefore perform 00720 // the query, and immediately close the file. 00721 // 00722 00723 status = ObOpenObjectByName( ObjectAttributes, 00724 (POBJECT_TYPE) NULL, 00725 requestorMode, 00726 NULL, 00727 FILE_READ_ATTRIBUTES, 00728 &openPacket, 00729 &handle ); 00730 00731 // 00732 // The operation is successful if the parse check field of the open packet 00733 // indicates that the parse routine was actually invoked, and the final 00734 // status field of the packet is set to success. 00735 // 00736 00737 if (openPacket.ParseCheck != OPEN_PACKET_PATTERN) { 00738 return status; 00739 } else { 00740 return openPacket.FinalStatus; 00741 } 00742 } 00743 00744 NTSTATUS 00745 NtQueryFullAttributesFile( 00746 IN POBJECT_ATTRIBUTES ObjectAttributes, 00747 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation 00748 ) 00749 00750 /*++ 00751 00752 Routine Description: 00753 00754 This service queries the network attributes information for a specified 00755 file. 00756 00757 Arguments: 00758 00759 ObjectAttributes - Supplies the attributes to be used for file object (name, 00760 SECURITY_DESCRIPTOR, etc.) 00761 00762 FileInformation - Supplies an output buffer to receive the returned file 00763 attributes information. 00764 00765 Return Value: 00766 00767 The status returned is the final completion status of the operation. 00768 00769 --*/ 00770 00771 { 00772 KPROCESSOR_MODE requestorMode; 00773 NTSTATUS status; 00774 OPEN_PACKET openPacket; 00775 DUMMY_FILE_OBJECT localFileObject; 00776 FILE_NETWORK_OPEN_INFORMATION networkInformation; 00777 HANDLE handle; 00778 00779 PAGED_CODE(); 00780 00781 // 00782 // Get the previous mode; i.e., the mode of the caller. 00783 // 00784 00785 requestorMode = KeGetPreviousMode(); 00786 00787 if (requestorMode != KernelMode) { 00788 00789 try { 00790 00791 // 00792 // The caller's mode is not kernel, so probe the output buffer. 00793 // 00794 00795 ProbeForWrite( FileInformation, 00796 sizeof( FILE_NETWORK_OPEN_INFORMATION ), 00797 #if defined(_X86_) 00798 sizeof( LONG )); 00799 #else 00800 sizeof( LONGLONG )); 00801 #endif // defined(_X86_) 00802 00803 } except(EXCEPTION_EXECUTE_HANDLER) { 00804 00805 // 00806 // An exception was incurred while probing the caller's parameters. 00807 // Simply return an appropriate error status code. 00808 // 00809 00810 return GetExceptionCode(); 00811 } 00812 } 00813 00814 // 00815 // Build a parse open packet that tells the parse method to open the file, 00816 // query the file's full attributes, and close the file. 00817 // 00818 00819 RtlZeroMemory( &openPacket, sizeof( OPEN_PACKET ) ); 00820 00821 openPacket.Type = IO_TYPE_OPEN_PACKET; 00822 openPacket.Size = sizeof( OPEN_PACKET ); 00823 openPacket.ShareAccess = (USHORT) FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; 00824 openPacket.Disposition = FILE_OPEN; 00825 openPacket.CreateOptions = FILE_OPEN_REPARSE_POINT; 00826 openPacket.QueryOnly = TRUE; 00827 openPacket.FullAttributes = TRUE; 00828 openPacket.LocalFileObject = &localFileObject; 00829 if (requestorMode != KernelMode) { 00830 openPacket.NetworkInformation = &networkInformation; 00831 } else { 00832 openPacket.NetworkInformation = FileInformation; 00833 } 00834 00835 // 00836 // Update the open count for this process. 00837 // 00838 00839 IopUpdateOtherOperationCount(); 00840 00841 // 00842 // Open the object by its name. Because of the special QueryOnly flag set 00843 // in the open packet, the parse routine will open the file, and then 00844 // realize that it is only performing a query. It will therefore perform 00845 // the query, and immediately close the file. 00846 // 00847 00848 status = ObOpenObjectByName( ObjectAttributes, 00849 (POBJECT_TYPE) NULL, 00850 requestorMode, 00851 NULL, 00852 FILE_READ_ATTRIBUTES, 00853 &openPacket, 00854 &handle ); 00855 00856 // 00857 // The operation is successful if the parse check field of the open packet 00858 // indicates that the parse routine was actually invoked, and the final 00859 // status field of the packet is set to success. 00860 // 00861 00862 if (openPacket.ParseCheck != OPEN_PACKET_PATTERN) { 00863 return status; 00864 } else { 00865 status = openPacket.FinalStatus; 00866 } 00867 00868 if (NT_SUCCESS( status )) { 00869 if (requestorMode != KernelMode) { 00870 try { 00871 00872 // 00873 // The query worked, so copy the returned information to the 00874 // caller's output buffer. 00875 // 00876 00877 RtlMoveMemory( FileInformation, 00878 &networkInformation, 00879 sizeof( FILE_NETWORK_OPEN_INFORMATION ) ); 00880 00881 } except(EXCEPTION_EXECUTE_HANDLER) { 00882 status = GetExceptionCode(); 00883 } 00884 } 00885 } 00886 00887 return status; 00888 } 00889 00890 PIO_WORKITEM 00891 IoAllocateWorkItem( 00892 PDEVICE_OBJECT DeviceObject 00893 ) 00894 { 00895 PIO_WORKITEM ioWorkItem; 00896 PWORK_QUEUE_ITEM exWorkItem; 00897 00898 // 00899 // Allocate a new workitem structure. 00900 // 00901 00902 ioWorkItem = ExAllocatePool( NonPagedPool, sizeof( IO_WORKITEM )); 00903 if (ioWorkItem != NULL) { 00904 00905 // 00906 // Initialize the invariant portions of both ioWorkItem and 00907 // exWorkItem. 00908 // 00909 00910 #if DBG 00911 ioWorkItem->Size = sizeof( IO_WORKITEM ); 00912 #endif 00913 00914 ioWorkItem->DeviceObject = DeviceObject; 00915 00916 exWorkItem = &ioWorkItem->WorkItem; 00917 ExInitializeWorkItem( exWorkItem, IopProcessWorkItem, ioWorkItem ); 00918 } 00919 00920 return ioWorkItem; 00921 } 00922 00923 VOID 00924 IoFreeWorkItem( 00925 PIO_WORKITEM IoWorkItem 00926 ) 00927 00928 /*++ 00929 00930 Routine Description: 00931 00932 This function is the "wrapper" routine for IoQueueWorkItem. It calls 00933 the original worker function, then dereferences the device object to 00934 (possibly) allow the driver object to go away. 00935 00936 Arguments: 00937 00938 Parameter - Supplies a pointer to an IO_WORKITEM for us to process. 00939 00940 Return Value: 00941 00942 None 00943 00944 --*/ 00945 00946 { 00947 ASSERT( IoWorkItem->Size == sizeof( IO_WORKITEM )); 00948 00949 ExFreePool( IoWorkItem ); 00950 } 00951 00952 VOID 00953 IoQueueWorkItem( 00954 IN PIO_WORKITEM IoWorkItem, 00955 IN PIO_WORKITEM_ROUTINE WorkerRoutine, 00956 IN WORK_QUEUE_TYPE QueueType, 00957 IN PVOID Context 00958 ) 00959 /*++ 00960 00961 Routine Description: 00962 00963 This function inserts a work item into a work queue that is processed 00964 by a worker thread of the corresponding type. It effectively 00965 "wraps" ExQueueWorkItem, ensuring that the device object is referenced 00966 for the duration of the call. 00967 00968 Arguments: 00969 00970 IoWorkItem - Supplies a pointer to the work item to add the the queue. 00971 This structure must have been allocated via IoAllocateWorkItem(). 00972 00973 WorkerRoutine - Supplies a pointer to the routine that is to be called 00974 in system thread context. 00975 00976 QueueType - Specifies the type of work queue that the work item 00977 should be placed in. 00978 00979 Context - Supplies the context parameter for the callback routine. 00980 00981 Return Value: 00982 00983 None 00984 00985 --*/ 00986 00987 { 00988 PWORK_QUEUE_ITEM exWorkItem; 00989 00990 ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); 00991 ASSERT( IoWorkItem->Size == sizeof( IO_WORKITEM )); 00992 00993 // 00994 // Keep a reference on the device object so it doesn't go away. 00995 // 00996 00997 ObReferenceObject( IoWorkItem->DeviceObject ); 00998 00999 // 01000 // Initialize the fields in IoWorkItem 01001 // 01002 01003 IoWorkItem->Routine = WorkerRoutine; 01004 IoWorkItem->Context = Context; 01005 01006 // 01007 // Get a pointer to the ExWorkItem, queue it, and return. 01008 // IopProcessWorkItem() will perform the dereference. 01009 // 01010 01011 exWorkItem = &IoWorkItem->WorkItem; 01012 ExQueueWorkItem( exWorkItem, QueueType ); 01013 } 01014 01015 VOID 01016 IopProcessWorkItem( 01017 IN PVOID Parameter 01018 ) 01019 01020 /*++ 01021 01022 Routine Description: 01023 01024 This function is the "wrapper" routine for IoQueueWorkItem. It calls 01025 the original worker function, then dereferences the device object to 01026 (possibly) allow the driver object to go away. 01027 01028 Arguments: 01029 01030 Parameter - Supplies a pointer to an IO_WORKITEM for us to process. 01031 01032 Return Value: 01033 01034 None 01035 01036 --*/ 01037 01038 { 01039 PIO_WORKITEM ioWorkItem; 01040 PDEVICE_OBJECT deviceObject; 01041 01042 PAGED_CODE(); 01043 01044 // 01045 // Get a pointer to the ioWorkItem and store a copy of DeviceObject 01046 // locally. This allow us to function properly if the worker routine 01047 // elects to free the work item. 01048 // 01049 01050 ioWorkItem = (PIO_WORKITEM)Parameter; 01051 deviceObject = ioWorkItem->DeviceObject; 01052 01053 // 01054 // Call the original worker. 01055 // 01056 01057 ioWorkItem->Routine( deviceObject, 01058 ioWorkItem->Context ); 01059 01060 // 01061 // Now we can dereference the device object, since its code is no longer 01062 // being executed for this work item. 01063 // 01064 01065 ObDereferenceObject( deviceObject ); 01066 } 01067

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