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

qsinfo.c File Reference

#include "iop.h"

Go to the source code of this file.

Defines

#define FSIO_A   FILE_SYNCHRONOUS_IO_ALERT
#define FSIO_NA   FILE_SYNCHRONOUS_IO_NONALERT

Functions

ULONG IopGetModeInformation (IN PFILE_OBJECT FileObject)
NTSTATUS NtQueryInformationFile (IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, OUT PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass)
NTSTATUS NtSetInformationFile (IN HANDLE FileHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN PVOID FileInformation, IN ULONG Length, IN FILE_INFORMATION_CLASS FileInformationClass)


Define Documentation

#define FSIO_A   FILE_SYNCHRONOUS_IO_ALERT
 

Definition at line 34 of file qsinfo.c.

Referenced by NtSetInformationFile().

#define FSIO_NA   FILE_SYNCHRONOUS_IO_NONALERT
 

Definition at line 35 of file qsinfo.c.

Referenced by NtSetInformationFile().


Function Documentation

ULONG IopGetModeInformation IN PFILE_OBJECT  FileObject  ) 
 

Definition at line 54 of file qsinfo.c.

References FO_ALERTABLE_IO, FO_DELETE_ON_CLOSE, FO_NO_INTERMEDIATE_BUFFERING, FO_SEQUENTIAL_ONLY, FO_SYNCHRONOUS_IO, and FO_WRITE_THROUGH.

Referenced by NtQueryInformationFile().

00060 : 00061 00062 This encapsulates extracting and translating the mode bits from 00063 the passed file object, to be returned from a query information call. 00064 00065 Arguments: 00066 00067 FileObject - Specifies the file object for which to return Mode info. 00068 00069 Return Value: 00070 00071 The translated mode information is returned. 00072 00073 --*/ 00074 00075 { 00076 ULONG mode = 0; 00077 00078 if (FileObject->Flags & FO_WRITE_THROUGH) { 00079 mode = FILE_WRITE_THROUGH; 00080 } 00081 if (FileObject->Flags & FO_SEQUENTIAL_ONLY) { 00082 mode |= FILE_SEQUENTIAL_ONLY; 00083 } 00084 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) { 00085 mode |= FILE_NO_INTERMEDIATE_BUFFERING; 00086 } 00087 if (FileObject->Flags & FO_SYNCHRONOUS_IO) { 00088 if (FileObject->Flags & FO_ALERTABLE_IO) { 00089 mode |= FILE_SYNCHRONOUS_IO_ALERT; 00090 } else { 00091 mode |= FILE_SYNCHRONOUS_IO_NONALERT; 00092 } 00093 } 00094 if (FileObject->Flags & FO_DELETE_ON_CLOSE) { 00095 mode |= FILE_DELETE_ON_CLOSE; 00096 } 00097 return mode; 00098 }

NTSTATUS NtQueryInformationFile IN HANDLE  FileHandle,
OUT PIO_STATUS_BLOCK  IoStatusBlock,
OUT PVOID  FileInformation,
IN ULONG  Length,
IN FILE_INFORMATION_CLASS  FileInformationClass
 

Definition at line 101 of file qsinfo.c.

References _DEVICE_OBJECT::AlignmentRequirement, APC_LEVEL, _IRP::AssociatedIrp, _DEVICE_OBJECT::DriverObject, ExAllocatePool, ExAllocatePoolWithQuota, EXCEPTION_EXECUTE_HANDLER, Executive, ExFreePool(), FALSE, _DRIVER_OBJECT::FastIoDispatch, _FAST_IO_DISPATCH::FastIoQueryBasicInfo, _FAST_IO_DISPATCH::FastIoQueryStandardInfo, _IO_STACK_LOCATION::FileObject, _IRP::Flags, FO_ALERTABLE_IO, FO_DIRECT_DEVICE_OPEN, FO_SYNCHRONOUS_IO, _OBJECT_HANDLE_INFORMATION::GrantedAccess, IoAllocateIrp(), IoCallDriver, IoFileObjectType, IoGetAttachedDevice(), IoGetNextIrpStackLocation, IoGetRelatedDeviceObject(), IopAcquireFastLock, IopAcquireFileObjectLock(), IopAllocateIrpCleanup(), IopCancelAlertedRequest(), IopCompleteRequest(), IopExceptionCleanup(), IopGetModeInformation(), IopQueryOperationAccess, IopQueryOperationLength, IopQuerySetAlignmentRequirement, IopQueueThreadIrp, IopReleaseFileObjectLock, IopUpdateOtherOperationCount(), _IRP::IoStatus, IRP_BUFFERED_IO, IRP_DEALLOCATE_BUFFER, IRP_DEFER_IO_COMPLETION, IRP_INPUT_OPERATION, IRP_MJ_QUERY_INFORMATION, IRP_SYNCHRONOUS_API, KeClearEvent, KeInitializeEvent, KeLowerIrql(), KeRaiseIrql(), KernelMode, KeWaitForSingleObject(), KPROCESSOR_MODE, _IO_STACK_LOCATION::MajorFunction, _IRP::MdlAddress, NonPagedPool, NT_SUCCESS, NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), _IRP::Overlay, PAGED_CODE, _IO_STACK_LOCATION::Parameters, PKNORMAL_ROUTINE, ProbeForWrite(), ProbeForWriteIoStatus, PsGetCurrentProcess, PsGetCurrentThread, _IRP::RequestorMode, _DEVICE_OBJECT::StackSize, _IRP::Tail, TRUE, _IRP::UserBuffer, _IRP::UserEvent, and _IRP::UserIosb.

Referenced by CopyRestrictedFile(), LdrVerifyImageMatchesChecksum(), main(), NTFastDOSIO(), RegLoadAsciiFileAsUnicode(), and RegReadBinaryFile().

00111 : 00112 00113 This service returns the requested information about a specified file. 00114 The information returned is determined by the FileInformationClass that 00115 is specified, and it is placed into the caller's FileInformation buffer. 00116 00117 Arguments: 00118 00119 FileHandle - Supplies a handle to the file about which the requested 00120 information should be returned. 00121 00122 IoStatusBlock - Address of the caller's I/O status block. 00123 00124 FileInformation - Supplies a buffer to receive the requested information 00125 returned about the file. 00126 00127 Length - Supplies the length, in bytes, of the FileInformation buffer. 00128 00129 FileInformationClass - Specifies the type of information which should be 00130 returned about the file. 00131 00132 Return Value: 00133 00134 The status returned is the final completion status of the operation. 00135 00136 --*/ 00137 00138 { 00139 PIRP irp; 00140 NTSTATUS status; 00141 PFILE_OBJECT fileObject; 00142 PDEVICE_OBJECT deviceObject; 00143 PFAST_IO_DISPATCH fastIoDispatch; 00144 PKEVENT event = (PKEVENT) NULL; 00145 KPROCESSOR_MODE requestorMode; 00146 PIO_STACK_LOCATION irpSp; 00147 IO_STATUS_BLOCK localIoStatus; 00148 OBJECT_HANDLE_INFORMATION handleInformation; 00149 BOOLEAN synchronousIo; 00150 BOOLEAN skipDriver; 00151 00152 PAGED_CODE(); 00153 00154 // 00155 // Get the previous mode; i.e., the mode of the caller. 00156 // 00157 00158 requestorMode = KeGetPreviousMode(); 00159 00160 if (requestorMode != KernelMode) { 00161 00162 // 00163 // Ensure that the FileInformationClass parameter is legal for querying 00164 // information about the file. 00165 // 00166 00167 if ((ULONG) FileInformationClass >= FileMaximumInformation || 00168 !IopQueryOperationLength[FileInformationClass]) { 00169 return STATUS_INVALID_INFO_CLASS; 00170 } 00171 00172 // 00173 // Ensure that the supplied buffer is large enough to contain the 00174 // information associated with the specified set operation that is 00175 // to be performed. 00176 // 00177 00178 if (Length < (ULONG) IopQueryOperationLength[FileInformationClass]) { 00179 return STATUS_INFO_LENGTH_MISMATCH; 00180 } 00181 00182 // 00183 // The caller's access mode is not kernel so probe each of the arguments 00184 // and capture them as necessary. If any failures occur, the condition 00185 // handler will be invoked to handle them. It will simply cleanup and 00186 // return an access violation status code back to the system service 00187 // dispatcher. 00188 // 00189 00190 try { 00191 00192 // 00193 // The IoStatusBlock parameter must be writeable by the caller. 00194 // 00195 00196 ProbeForWriteIoStatus( IoStatusBlock ); 00197 00198 // 00199 // The FileInformation buffer must be writeable by the caller. 00200 // 00201 00202 #if defined(_X86_) 00203 ProbeForWrite( FileInformation, Length, sizeof( ULONG ) ); 00204 #elif defined(_WIN64) 00205 00206 // 00207 // If we are a wow64 process, follow the X86 rules 00208 // 00209 00210 if (PsGetCurrentProcess()->Wow64Process) { 00211 ProbeForWrite( FileInformation, Length, sizeof( ULONG ) ); 00212 } else { 00213 ProbeForWrite( FileInformation, 00214 Length, 00215 IopQuerySetAlignmentRequirement[FileInformationClass] ); 00216 } 00217 #else 00218 ProbeForWrite( FileInformation, 00219 Length, 00220 IopQuerySetAlignmentRequirement[FileInformationClass] ); 00221 #endif 00222 00223 } except(EXCEPTION_EXECUTE_HANDLER) { 00224 00225 // 00226 // An exception was incurred while probing the caller's 00227 // parameters. Simply return an appropriate error status 00228 // code. 00229 // 00230 00231 #if DBG 00232 if (GetExceptionCode() == STATUS_DATATYPE_MISALIGNMENT) { 00233 DbgBreakPoint(); 00234 } 00235 #endif // DBG 00236 00237 return GetExceptionCode(); 00238 } 00239 00240 #if DBG 00241 00242 } else { 00243 00244 // 00245 // The caller's mode is kernel. Ensure that at least the information 00246 // class and lengths are appropriate. 00247 // 00248 00249 if ((ULONG) FileInformationClass >= FileMaximumInformation || 00250 !IopQueryOperationLength[FileInformationClass]) { 00251 return STATUS_INVALID_INFO_CLASS; 00252 } 00253 00254 if (Length < (ULONG) IopQueryOperationLength[FileInformationClass]) { 00255 return STATUS_INFO_LENGTH_MISMATCH; 00256 } 00257 00258 #endif // DBG 00259 00260 } 00261 00262 // 00263 // There were no blatant errors so far, so reference the file object so 00264 // the target device object can be found. Note that if the handle does 00265 // not refer to a file object, or if the caller does not have the required 00266 // access to the file, then it will fail. 00267 // 00268 00269 status = ObReferenceObjectByHandle( FileHandle, 00270 IopQueryOperationAccess[FileInformationClass], 00271 IoFileObjectType, 00272 requestorMode, 00273 (PVOID *) &fileObject, 00274 &handleInformation); 00275 00276 if (!NT_SUCCESS( status )) { 00277 return status; 00278 } 00279 00280 // 00281 // Get the address of the target device object. If this file represents 00282 // a device that was opened directly, then simply use the device or its 00283 // attached device(s) directly. Also get the address of the Fast Io 00284 // dispatch structure. 00285 // 00286 00287 if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { 00288 deviceObject = IoGetRelatedDeviceObject( fileObject ); 00289 } else { 00290 deviceObject = IoGetAttachedDevice( fileObject->DeviceObject ); 00291 } 00292 fastIoDispatch = deviceObject->DriverObject->FastIoDispatch; 00293 00294 // 00295 // Make a special check here to determine whether this is a synchronous 00296 // I/O operation. If it is, then wait here until the file is owned by 00297 // the current thread. If this is not a (serialized) synchronous I/O 00298 // operation, then allocate and initialize the local event. 00299 // 00300 00301 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 00302 00303 BOOLEAN interrupted; 00304 00305 if (!IopAcquireFastLock( fileObject )) { 00306 status = IopAcquireFileObjectLock( fileObject, 00307 requestorMode, 00308 (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), 00309 &interrupted ); 00310 if (interrupted) { 00311 ObDereferenceObject( fileObject ); 00312 return status; 00313 } 00314 } 00315 00316 // 00317 // Make a special check here to determine whether or not the caller 00318 // is attempting to query the file position pointer. If so, then 00319 // return it immediately and get out. 00320 // 00321 00322 if (FileInformationClass == FilePositionInformation) { 00323 00324 // 00325 // The caller has requested the current file position context 00326 // information. This is a relatively frequent call, so it is 00327 // optimized here to cut through the normal IRP path. 00328 // 00329 // Begin by establishing a condition handler and attempting to 00330 // return both the file position information as well as the I/O 00331 // status block. If writing the output buffer fails, then return 00332 // an appropriate error status code. If writing the I/O status 00333 // block fails, then ignore the error. This is what would 00334 // normally happen were everything to go through normal special 00335 // kernel APC processing. 00336 // 00337 00338 BOOLEAN writingBuffer = TRUE; 00339 PFILE_POSITION_INFORMATION fileInformation = FileInformation; 00340 00341 try { 00342 00343 // 00344 // Return the current position information. 00345 // 00346 00347 fileInformation->CurrentByteOffset = fileObject->CurrentByteOffset; 00348 writingBuffer = FALSE; 00349 00350 // 00351 // Write the I/O status block. 00352 // 00353 00354 IoStatusBlock->Status = STATUS_SUCCESS; 00355 IoStatusBlock->Information = sizeof( FILE_POSITION_INFORMATION ); 00356 00357 } except( EXCEPTION_EXECUTE_HANDLER ) { 00358 00359 // 00360 // One of writing the caller's buffer or writing the I/O 00361 // status block failed. Set the final status appropriately. 00362 // 00363 00364 if (writingBuffer) { 00365 status = GetExceptionCode(); 00366 } 00367 00368 } 00369 00370 // 00371 // Note that the state of the event in the file object has not yet 00372 // been reset, so it need not be set either. Therefore, simply 00373 // cleanup and return. 00374 // 00375 00376 IopReleaseFileObjectLock( fileObject ); 00377 ObDereferenceObject( fileObject ); 00378 return status; 00379 00380 // 00381 // Also do a special check if the caller it doing a query for basic or 00382 // standard information and if so then try the fast query calls if they 00383 // exist. 00384 // 00385 00386 } else if (fastIoDispatch && 00387 (((FileInformationClass == FileBasicInformation) && 00388 fastIoDispatch->FastIoQueryBasicInfo) || 00389 ((FileInformationClass == FileStandardInformation) && 00390 fastIoDispatch->FastIoQueryStandardInfo))) { 00391 00392 IO_STATUS_BLOCK localIoStatus; 00393 BOOLEAN queryResult = FALSE; 00394 BOOLEAN writingStatus = FALSE; 00395 00396 // 00397 // Do the query and setting of the IoStatusBlock inside an exception 00398 // handler. Note that if an exception occurs, other than writing 00399 // the status back, then the IRP route will be taken. If an error 00400 // occurs attempting to write the status back to the caller's buffer 00401 // then it will be ignored, just as it would be on the long path. 00402 // 00403 00404 try { 00405 00406 if (FileInformationClass == FileBasicInformation) { 00407 queryResult = fastIoDispatch->FastIoQueryBasicInfo( fileObject, 00408 TRUE, 00409 FileInformation, 00410 &localIoStatus, 00411 deviceObject ); 00412 } else { 00413 queryResult = fastIoDispatch->FastIoQueryStandardInfo( fileObject, 00414 TRUE, 00415 FileInformation, 00416 &localIoStatus, 00417 deviceObject ); 00418 } 00419 00420 if (queryResult) { 00421 status = localIoStatus.Status; 00422 writingStatus = TRUE; 00423 *IoStatusBlock = localIoStatus; 00424 } 00425 00426 } except( EXCEPTION_EXECUTE_HANDLER ) { 00427 00428 // 00429 // If the result of the preceeding block is an exception that 00430 // occurred after the Fast I/O path itself, then the query 00431 // actually succeeded so everything is done already, but the 00432 // user's I/O status buffer is not writable. This case is 00433 // ignored to be consistent w/the long path. 00434 // 00435 00436 if (!writingStatus) { 00437 status = GetExceptionCode(); 00438 } 00439 } 00440 00441 // 00442 // If the results of the preceeding statement block is true, then 00443 // the fast query call succeeeded, so simply cleanup and return. 00444 // 00445 00446 if (queryResult) { 00447 00448 // 00449 // Note that once again, the event in the file object has not 00450 // yet been set reset, so it need not be set to the Signaled 00451 // state, so simply cleanup and return. 00452 // 00453 00454 IopReleaseFileObjectLock( fileObject ); 00455 ObDereferenceObject( fileObject ); 00456 return status; 00457 } 00458 } 00459 synchronousIo = TRUE; 00460 } else { 00461 00462 // 00463 // This is a synchronous API being invoked for a file that is opened 00464 // for asynchronous I/O. This means that this system service is 00465 // to synchronize the completion of the operation before returning 00466 // to the caller. A local event is used to do this. 00467 // 00468 00469 event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) ); 00470 if (event == NULL) { 00471 ObDereferenceObject( fileObject ); 00472 return STATUS_INSUFFICIENT_RESOURCES; 00473 } 00474 KeInitializeEvent( event, SynchronizationEvent, FALSE ); 00475 synchronousIo = FALSE; 00476 } 00477 00478 // 00479 // Set the file object to the Not-Signaled state. 00480 // 00481 00482 KeClearEvent( &fileObject->Event ); 00483 00484 // 00485 // Allocate and initialize the I/O Request Packet (IRP) for this operation. 00486 // The allocation is performed with an exception handler in case the 00487 // caller does not have enough quota to allocate the packet. 00488 // 00489 00490 irp = IoAllocateIrp( deviceObject->StackSize, TRUE ); 00491 if (!irp) { 00492 00493 // 00494 // An IRP could not be allocated. Cleanup and return an appropriate 00495 // error status code. 00496 // 00497 00498 if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) { 00499 ExFreePool( event ); 00500 } 00501 00502 IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL ); 00503 00504 return STATUS_INSUFFICIENT_RESOURCES; 00505 } 00506 irp->Tail.Overlay.OriginalFileObject = fileObject; 00507 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00508 irp->RequestorMode = requestorMode; 00509 00510 // 00511 // Fill in the service independent parameters in the IRP. 00512 // 00513 00514 if (synchronousIo) { 00515 irp->UserEvent = (PKEVENT) NULL; 00516 irp->UserIosb = IoStatusBlock; 00517 } else { 00518 irp->UserEvent = event; 00519 irp->UserIosb = &localIoStatus; 00520 irp->Flags = IRP_SYNCHRONOUS_API; 00521 } 00522 irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL; 00523 00524 // 00525 // Get a pointer to the stack location for the first driver. This will be 00526 // used to pass the original function codes and parameters. 00527 // 00528 00529 irpSp = IoGetNextIrpStackLocation( irp ); 00530 irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION; 00531 irpSp->FileObject = fileObject; 00532 00533 // 00534 // Allocate a buffer which should be used to put the information into by 00535 // the driver. This will be copied back to the caller's buffer when the 00536 // service completes. This is done by setting the flag which says that 00537 // this is an input operation. 00538 // 00539 00540 irp->UserBuffer = FileInformation; 00541 irp->AssociatedIrp.SystemBuffer = (PVOID) NULL; 00542 irp->MdlAddress = (PMDL) NULL; 00543 00544 try { 00545 00546 // 00547 // Allocate the system buffer using an exception handler so that 00548 // errors can be caught and handled. 00549 // 00550 00551 irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota( NonPagedPool, 00552 Length ); 00553 } except(EXCEPTION_EXECUTE_HANDLER) { 00554 00555 // 00556 // An exception was incurred by attempting to allocate the intermediary 00557 // system buffer. Cleanup everything and return an appropriate error 00558 // status code. 00559 // 00560 00561 IopExceptionCleanup( fileObject, 00562 irp, 00563 (PKEVENT) NULL, 00564 event ); 00565 00566 return GetExceptionCode(); 00567 } 00568 00569 irp->Flags |= IRP_BUFFERED_IO | 00570 IRP_DEALLOCATE_BUFFER | 00571 IRP_INPUT_OPERATION | 00572 IRP_DEFER_IO_COMPLETION; 00573 00574 // 00575 // Copy the caller's parameters to the service-specific portion of the 00576 // IRP. 00577 // 00578 00579 irpSp->Parameters.QueryFile.Length = Length; 00580 irpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass; 00581 00582 // 00583 // Insert the packet at the head of the IRP list for the thread. 00584 // 00585 00586 IopQueueThreadIrp( irp ); 00587 00588 // 00589 // Update the operation count statistic for the current process for 00590 // operations other than read and write. 00591 // 00592 00593 IopUpdateOtherOperationCount(); 00594 00595 // 00596 // Everything is now set to invoke the device driver with this request. 00597 // However, it is possible that the information that the caller wants 00598 // is device independent. If this is the case, then the request can 00599 // be satisfied here without having to have all of the drivers implement 00600 // the same code. Note that having the IRP is still necessary since 00601 // the I/O completion code requires it. 00602 // 00603 00604 skipDriver = FALSE; 00605 00606 if (FileInformationClass == FileAccessInformation) { 00607 00608 PFILE_ACCESS_INFORMATION accessBuffer = irp->AssociatedIrp.SystemBuffer; 00609 00610 // 00611 // Return the access information for this file. 00612 // 00613 00614 accessBuffer->AccessFlags = handleInformation.GrantedAccess; 00615 00616 // 00617 // Complete the I/O operation. 00618 // 00619 00620 irp->IoStatus.Information = sizeof( FILE_ACCESS_INFORMATION ); 00621 skipDriver = TRUE; 00622 00623 } else if (FileInformationClass == FileModeInformation) { 00624 00625 PFILE_MODE_INFORMATION modeBuffer = irp->AssociatedIrp.SystemBuffer; 00626 00627 // 00628 // Return the mode information for this file. 00629 // 00630 00631 modeBuffer->Mode = IopGetModeInformation( fileObject ); 00632 00633 // 00634 // Complete the I/O operation. 00635 // 00636 00637 irp->IoStatus.Information = sizeof( FILE_MODE_INFORMATION ); 00638 skipDriver = TRUE; 00639 00640 } else if (FileInformationClass == FileAlignmentInformation) { 00641 00642 PFILE_ALIGNMENT_INFORMATION alignmentInformation = irp->AssociatedIrp.SystemBuffer; 00643 00644 // 00645 // Return the alignment information for this file. 00646 // 00647 00648 alignmentInformation->AlignmentRequirement = deviceObject->AlignmentRequirement; 00649 00650 // 00651 // Complete the I/O operation. 00652 // 00653 00654 irp->IoStatus.Information = sizeof( FILE_ALIGNMENT_INFORMATION ); 00655 skipDriver = TRUE; 00656 00657 } else if (FileInformationClass == FileAllInformation) { 00658 00659 PFILE_ALL_INFORMATION allInformation = irp->AssociatedIrp.SystemBuffer; 00660 00661 // 00662 // The caller has requested all of the information about the file. 00663 // This request is handled specially because the service will fill 00664 // in the Access and Mode and Alignment information in the buffer 00665 // and then pass the buffer to the driver to fill in the remainder. 00666 // 00667 // Begin by returning the Access information for the file. 00668 // 00669 00670 allInformation->AccessInformation.AccessFlags = 00671 handleInformation.GrantedAccess; 00672 00673 // 00674 // Return the mode information for this file. 00675 // 00676 00677 allInformation->ModeInformation.Mode = 00678 IopGetModeInformation( fileObject ); 00679 00680 // 00681 // Return the alignment information for this file. 00682 // 00683 00684 allInformation->AlignmentInformation.AlignmentRequirement = 00685 deviceObject->AlignmentRequirement; 00686 00687 // 00688 // Finally, set the information field of the IoStatus block in the IRP 00689 // to account for the amount information already filled in and invoke 00690 // the driver to fill in the remainder. 00691 // 00692 00693 irp->IoStatus.Information = sizeof( FILE_ACCESS_INFORMATION ) + 00694 sizeof( FILE_MODE_INFORMATION ) + 00695 sizeof( FILE_ALIGNMENT_INFORMATION ); 00696 } 00697 00698 if (skipDriver) { 00699 00700 // 00701 // The requested operation has already been performed. Simply 00702 // set the final status in the packet and the return state. 00703 // 00704 00705 status = STATUS_SUCCESS; 00706 irp->IoStatus.Status = STATUS_SUCCESS; 00707 00708 } else { 00709 00710 // 00711 // This is not a request that can be [completely] performed here, so 00712 // invoke the driver at its appropriate dispatch entry with the IRP. 00713 // 00714 00715 status = IoCallDriver( deviceObject, irp ); 00716 } 00717 00718 // 00719 // If this operation was a synchronous I/O operation, check the return 00720 // status to determine whether or not to wait on the file object. If 00721 // the file object is to be waited on, wait for the operation to complete 00722 // and obtain the final status from the file object itself. 00723 // 00724 00725 if (status == STATUS_PENDING) { 00726 00727 if (synchronousIo) { 00728 00729 status = KeWaitForSingleObject( &fileObject->Event, 00730 Executive, 00731 requestorMode, 00732 (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), 00733 (PLARGE_INTEGER) NULL ); 00734 00735 if (status == STATUS_ALERTED || status == STATUS_USER_APC) { 00736 00737 // 00738 // The wait request has ended either because the thread was 00739 // alerted or an APC was queued to this thread, because of 00740 // thread rundown or CTRL/C processing. In either case, try 00741 // to bail out of this I/O request carefully so that the IRP 00742 // completes before this routine exists so that synchronization 00743 // with the file object will remain intact. 00744 // 00745 00746 IopCancelAlertedRequest( &fileObject->Event, irp ); 00747 00748 } 00749 00750 status = fileObject->FinalStatus; 00751 00752 IopReleaseFileObjectLock( fileObject ); 00753 00754 } else { 00755 00756 // 00757 // This is a normal synchronous I/O operation, as opposed to a 00758 // serialized synchronous I/O operation. For this case, wait for 00759 // the local event and copy the final status information back to 00760 // the caller. 00761 // 00762 00763 status = KeWaitForSingleObject( event, 00764 Executive, 00765 requestorMode, 00766 FALSE, 00767 (PLARGE_INTEGER) NULL ); 00768 00769 if (status == STATUS_ALERTED || status == STATUS_USER_APC) { 00770 00771 // 00772 // The wait request has ended either because the thread was 00773 // alerted or an APC was queued to this thread, because of 00774 // thread rundown or CTRL/C processing. In either case, try 00775 // to bail out of this I/O request carefully so that the IRP 00776 // completes before this routine exists or the event will not 00777 // be around to set to the Signaled state. 00778 // 00779 00780 IopCancelAlertedRequest( event, irp ); 00781 00782 } 00783 00784 status = localIoStatus.Status; 00785 00786 try { 00787 00788 *IoStatusBlock = localIoStatus; 00789 00790 } except(EXCEPTION_EXECUTE_HANDLER) { 00791 00792 // 00793 // An exception occurred attempting to write the caller's I/O 00794 // status block. Simply change the final status of the operation 00795 // to the exception code. 00796 // 00797 00798 status = GetExceptionCode(); 00799 } 00800 00801 ExFreePool( event ); 00802 00803 } 00804 00805 } else { 00806 00807 // 00808 // The I/O operation finished without return a status of pending. 00809 // This means that the operation has not been through I/O completion, 00810 // so it must be done here. 00811 // 00812 00813 PKNORMAL_ROUTINE normalRoutine; 00814 PVOID normalContext; 00815 KIRQL irql; 00816 00817 if (!synchronousIo) { 00818 00819 // 00820 // This is not a synchronous I/O operation, it is a synchronous 00821 // I/O API to a file opened for asynchronous I/O. Since this 00822 // code path need never wait on the allocated and supplied event, 00823 // get rid of it so that it doesn't have to be set to the 00824 // Signaled state by the I/O completion code. 00825 // 00826 00827 irp->UserEvent = (PKEVENT) NULL; 00828 ExFreePool( event ); 00829 } 00830 00831 irp->UserIosb = IoStatusBlock; 00832 KeRaiseIrql( APC_LEVEL, &irql ); 00833 IopCompleteRequest( &irp->Tail.Apc, 00834 &normalRoutine, 00835 &normalContext, 00836 (PVOID *) &fileObject, 00837 &normalContext ); 00838 KeLowerIrql( irql ); 00839 00840 if (synchronousIo) { 00841 IopReleaseFileObjectLock( fileObject ); 00842 } 00843 } 00844 00845 return status; 00846 }

NTSTATUS NtSetInformationFile IN HANDLE  FileHandle,
OUT PIO_STATUS_BLOCK  IoStatusBlock,
IN PVOID  FileInformation,
IN ULONG  Length,
IN FILE_INFORMATION_CLASS  FileInformationClass
 

Definition at line 849 of file qsinfo.c.

References APC_LEVEL, ASSERT, _IRP::AssociatedIrp, ExAllocatePool, ExAllocatePoolWithQuota, ExAllocatePoolWithTag, EXCEPTION_EXECUTE_HANDLER, Executive, ExFreePool(), ExRaiseStatus(), FALSE, FileName, _IO_STACK_LOCATION::FileObject, _IRP::Flags, FO_ALERTABLE_IO, FO_DIRECT_DEVICE_OPEN, FO_NO_INTERMEDIATE_BUFFERING, FO_SEQUENTIAL_ONLY, FO_SYNCHRONOUS_IO, FO_WRITE_THROUGH, FSIO_A, FSIO_NA, IoAllocateIrp(), IoCallDriver, IoCompletionObjectType, IoFileObjectType, IoGetAttachedDevice(), IoGetNextIrpStackLocation, IoGetRelatedDeviceObject(), IopAcquireFastLock, IopAcquireFileObjectLock(), IopAllocateIrpCleanup(), IopCancelAlertedRequest(), IopCompleteRequest(), IopExceptionCleanup(), IopOpenLinkOrRenameTarget(), IopQuerySetAlignmentRequirement, IopQueueThreadIrp, IopReleaseFileObjectLock, IopSetOperationAccess, IopSetOperationLength, IopTrackLink(), IopUpdateOtherOperationCount(), IopUpdateOtherTransferCount(), _IRP::IoStatus, IRP_BUFFERED_IO, IRP_DEALLOCATE_BUFFER, IRP_DEFER_IO_COMPLETION, IRP_MJ_SET_INFORMATION, IRP_SYNCHRONOUS_API, KeClearEvent, KeInitializeEvent, KeLowerIrql(), KeRaiseIrql(), KernelMode, KeWaitForSingleObject(), _IO_COMPLETION_CONTEXT::Key, KPROCESSOR_MODE, L, _IO_STACK_LOCATION::MajorFunction, _IRP::MdlAddress, NonPagedPool, NT_SUCCESS, NtClose(), NTSTATUS(), NULL, ObDereferenceObject, ObReferenceObjectByHandle(), _IRP::Overlay, PAGED_CODE, PagedPool, _IO_STACK_LOCATION::Parameters, PKNORMAL_ROUTINE, _IO_COMPLETION_CONTEXT::Port, ProbeForRead, ProbeForWriteIoStatus, PsGetCurrentProcess, PsGetCurrentThread, _IRP::RequestorMode, _DEVICE_OBJECT::SectorSize, _DEVICE_OBJECT::StackSize, _IRP::Tail, TRUE, _IRP::UserEvent, and _IRP::UserIosb.

Referenced by CopyRestrictedFile(), MemPrintWriteThread(), NTFastDOSIO(), RtlSetIoCompletionCallback(), SepClientOpenPipe(), and ZwSetInformationFile().

00859 : 00860 00861 This service changes the provided information about a specified file. The 00862 information that is changed is determined by the FileInformationClass that 00863 is specified. The new information is taken from the FileInformation buffer. 00864 00865 Arguments: 00866 00867 FileHandle - Supplies a handle to the file whose information should be 00868 changed. 00869 00870 IoStatusBlock - Address of the caller's I/O status block. 00871 00872 FileInformation - Supplies a buffer containing the information which should 00873 be changed on the file. 00874 00875 Length - Supplies the length, in bytes, of the FileInformation buffer. 00876 00877 FileInformationClass - Specifies the type of information which should be 00878 changed about the file. 00879 00880 Return Value: 00881 00882 The status returned is the final completion status of the operation. 00883 00884 --*/ 00885 00886 { 00887 PIRP irp; 00888 NTSTATUS status; 00889 PFILE_OBJECT fileObject; 00890 PDEVICE_OBJECT deviceObject; 00891 PKEVENT event = (PKEVENT) NULL; 00892 KPROCESSOR_MODE requestorMode; 00893 PIO_STACK_LOCATION irpSp; 00894 IO_STATUS_BLOCK localIoStatus; 00895 HANDLE targetHandle = (HANDLE) NULL; 00896 BOOLEAN synchronousIo; 00897 00898 PAGED_CODE(); 00899 00900 // 00901 // Get the previous mode; i.e., the mode of the caller. 00902 // 00903 00904 requestorMode = KeGetPreviousMode(); 00905 00906 if (requestorMode != KernelMode) { 00907 00908 // 00909 // Ensure that the FileInformationClass parameter is legal for setting 00910 // information about the file. 00911 // 00912 00913 if ((ULONG) FileInformationClass >= FileMaximumInformation || 00914 !IopSetOperationLength[FileInformationClass]) { 00915 return STATUS_INVALID_INFO_CLASS; 00916 } 00917 00918 // 00919 // Ensure that the supplied buffer is large enough to contain the 00920 // information associated with the specified set operation that is 00921 // to be performed. 00922 // 00923 00924 if (Length < (ULONG) IopSetOperationLength[FileInformationClass]) { 00925 return STATUS_INFO_LENGTH_MISMATCH; 00926 } 00927 00928 // 00929 // The caller's access mode is user, so probe each of the arguments 00930 // and capture them as necessary. If any failures occur, the condition 00931 // handler will be invoked to handle them. It will simply cleanup and 00932 // return an access violation status code back to the system service 00933 // dispatcher. 00934 // 00935 00936 try { 00937 00938 // 00939 // The IoStatusBlock parameter must be writeable by the caller. 00940 // 00941 00942 ProbeForWriteIoStatus( IoStatusBlock ); 00943 00944 // 00945 // The FileInformation buffer must be readable by the caller. 00946 // 00947 00948 #if defined(_X86_) 00949 ProbeForRead( FileInformation, 00950 Length, 00951 Length == sizeof( BOOLEAN ) ? sizeof( BOOLEAN ) : sizeof( ULONG ) ); 00952 #elif defined(_WIN64) 00953 // If we are a wow64 process, follow the X86 rules 00954 if (PsGetCurrentProcess()->Wow64Process) { 00955 ProbeForRead( FileInformation, 00956 Length, 00957 Length == sizeof( BOOLEAN ) ? sizeof( BOOLEAN ) : sizeof( ULONG ) ); 00958 } 00959 else { 00960 ProbeForRead( FileInformation, 00961 Length, 00962 IopQuerySetAlignmentRequirement[FileInformationClass] ); 00963 } 00964 #else 00965 ProbeForRead( FileInformation, 00966 Length, 00967 IopQuerySetAlignmentRequirement[FileInformationClass] ); 00968 #endif 00969 00970 } except(EXCEPTION_EXECUTE_HANDLER) { 00971 00972 // 00973 // An exception was incurred while probing the caller's parameters. 00974 // Simply return an appropriate error status code. 00975 // 00976 00977 #if DBG 00978 if (GetExceptionCode() == STATUS_DATATYPE_MISALIGNMENT) { 00979 DbgBreakPoint(); 00980 } 00981 #endif // DBG 00982 00983 return GetExceptionCode(); 00984 00985 } 00986 00987 #if DBG 00988 00989 } else { 00990 00991 // 00992 // The caller's mode is kernel. Ensure that at least the information 00993 // class and lengths are appropriate. 00994 // 00995 00996 if ((ULONG) FileInformationClass >= FileMaximumInformation || 00997 !IopSetOperationLength[FileInformationClass]) { 00998 return STATUS_INVALID_INFO_CLASS; 00999 } 01000 01001 if (Length < (ULONG) IopSetOperationLength[FileInformationClass]) { 01002 return STATUS_INFO_LENGTH_MISMATCH; 01003 } 01004 01005 #endif // DBG 01006 01007 } 01008 01009 // 01010 // There were no blatant errors so far, so reference the file object so 01011 // the target device object can be found. Note that if the handle does 01012 // not refer to a file object, or if the caller does not have the required 01013 // access to the file, then it will fail. 01014 // 01015 01016 status = ObReferenceObjectByHandle( FileHandle, 01017 IopSetOperationAccess[FileInformationClass], 01018 IoFileObjectType, 01019 requestorMode, 01020 (PVOID *) &fileObject, 01021 NULL ); 01022 if (!NT_SUCCESS( status )) { 01023 return status; 01024 } 01025 01026 // 01027 // Get the address of the target device object. If this file represents 01028 // a device that was opened directly, then simply use the device or its 01029 // attached device(s) directly. 01030 // 01031 01032 if (!(fileObject->Flags & FO_DIRECT_DEVICE_OPEN)) { 01033 deviceObject = IoGetRelatedDeviceObject( fileObject ); 01034 } else { 01035 deviceObject = IoGetAttachedDevice( fileObject->DeviceObject ); 01036 } 01037 01038 // 01039 // Make a special check here to determine whether this is a synchronous 01040 // I/O operation. If it is, then wait here until the file is owned by 01041 // the current thread. If this is not a (serialized) synchronous I/O 01042 // operation, then allocate and initialize the local event. 01043 // 01044 01045 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 01046 01047 BOOLEAN interrupted; 01048 01049 if (!IopAcquireFastLock( fileObject )) { 01050 status = IopAcquireFileObjectLock( fileObject, 01051 requestorMode, 01052 (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), 01053 &interrupted ); 01054 if (interrupted) { 01055 ObDereferenceObject( fileObject ); 01056 return status; 01057 } 01058 } 01059 01060 // 01061 // Make a special check here to determine whether or not the caller 01062 // is attempting to set the file position pointer information. If so, 01063 // then set it immediately and get out. 01064 // 01065 01066 if (FileInformationClass == FilePositionInformation) { 01067 01068 // 01069 // The caller has requested setting the current file position 01070 // context information. This is a relatively frequent call, so 01071 // it is optimized here to cut through the normal IRP path. 01072 // 01073 // Begin by checking to see whether the file was opened with no 01074 // intermediate buffering. If so, then the file pointer must be 01075 // set in a manner consistent with the alignment requirement of 01076 // read and write operations to a non-buffered file. 01077 // 01078 01079 PFILE_POSITION_INFORMATION fileInformation = FileInformation; 01080 LARGE_INTEGER currentByteOffset; 01081 01082 try { 01083 01084 // 01085 // Attempt to read the position information from the buffer. 01086 // 01087 01088 currentByteOffset.QuadPart = fileInformation->CurrentByteOffset.QuadPart; 01089 01090 } except( EXCEPTION_EXECUTE_HANDLER ) { 01091 01092 IopReleaseFileObjectLock( fileObject ); 01093 ObDereferenceObject( fileObject ); 01094 return GetExceptionCode(); 01095 } 01096 01097 if ((fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING && 01098 (deviceObject->SectorSize && 01099 (currentByteOffset.LowPart & 01100 (deviceObject->SectorSize - 1)))) || 01101 currentByteOffset.HighPart < 0) { 01102 01103 status = STATUS_INVALID_PARAMETER; 01104 01105 } else { 01106 01107 // 01108 // Set the current file position information. 01109 // 01110 01111 fileObject->CurrentByteOffset.QuadPart = currentByteOffset.QuadPart; 01112 01113 try { 01114 01115 // 01116 // Write the I/O status block. 01117 // 01118 01119 IoStatusBlock->Status = STATUS_SUCCESS; 01120 IoStatusBlock->Information = 0; 01121 01122 } except( EXCEPTION_EXECUTE_HANDLER ) { 01123 01124 // 01125 // Writes to I/O status blocks are ignored since the 01126 // operation succeeded. 01127 // 01128 01129 NOTHING; 01130 01131 } 01132 01133 } 01134 01135 // 01136 // Update the transfer count statistic for the current process for 01137 // operations other than read and write. 01138 // 01139 01140 IopUpdateOtherTransferCount( Length ); 01141 01142 // 01143 // Note that the file object's event has not yet been reset, 01144 // so it is not necessary to set it to the Signaled state, since 01145 // that is it's state at this point by definition. Therefore, 01146 // simply cleanup and return. 01147 // 01148 01149 IopReleaseFileObjectLock( fileObject ); 01150 ObDereferenceObject( fileObject ); 01151 return status; 01152 } 01153 synchronousIo = TRUE; 01154 } else { 01155 01156 // 01157 // This is a synchronous API being invoked for a file that is opened 01158 // for asynchronous I/O. This means that this system service is 01159 // to synchronize the completion of the operation before returning 01160 // to the caller. A local event is used to do this. 01161 // 01162 01163 event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) ); 01164 if (event == NULL) { 01165 ObDereferenceObject( fileObject ); 01166 return STATUS_INSUFFICIENT_RESOURCES; 01167 } 01168 KeInitializeEvent( event, SynchronizationEvent, FALSE ); 01169 synchronousIo = FALSE; 01170 } 01171 01172 // 01173 // Set the file object to the Not-Signaled state. 01174 // 01175 01176 KeClearEvent( &fileObject->Event ); 01177 01178 // 01179 // If a link is being tracked, handle this out-of-line. 01180 // 01181 01182 if (FileInformationClass == FileTrackingInformation) { 01183 status = IopTrackLink( fileObject, 01184 &localIoStatus, 01185 FileInformation, 01186 Length, 01187 synchronousIo ? &fileObject->Event : event, 01188 requestorMode ); 01189 if (NT_SUCCESS( status )) { 01190 try { 01191 IoStatusBlock->Information = 0; 01192 IoStatusBlock->Status = status; 01193 } except(EXCEPTION_EXECUTE_HANDLER) { 01194 NOTHING; 01195 } 01196 } 01197 01198 if (synchronousIo) { 01199 IopReleaseFileObjectLock( fileObject ); 01200 } else { 01201 ExFreePool( event ); 01202 } 01203 ObDereferenceObject( fileObject ); 01204 return status; 01205 } 01206 01207 // 01208 // Allocate and initialize the I/O Request Packet (IRP) for this operation. 01209 // The allocation is performed with an exception handler in case the 01210 // caller does not have enough quota to allocate the packet. 01211 01212 irp = IoAllocateIrp( deviceObject->StackSize, TRUE ); 01213 if (!irp) { 01214 01215 // 01216 // An IRP could not be allocated. Cleanup and return an appropriate 01217 // error status code. 01218 // 01219 01220 if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) { 01221 ExFreePool( event ); 01222 } 01223 01224 IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL ); 01225 01226 return STATUS_INSUFFICIENT_RESOURCES; 01227 } 01228 irp->Tail.Overlay.OriginalFileObject = fileObject; 01229 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 01230 irp->RequestorMode = requestorMode; 01231 01232 // 01233 // Fill in the service independent parameters in the IRP. 01234 // 01235 01236 if (synchronousIo) { 01237 irp->UserEvent = (PKEVENT) NULL; 01238 irp->UserIosb = IoStatusBlock; 01239 } else { 01240 irp->UserEvent = event; 01241 irp->UserIosb = &localIoStatus; 01242 irp->Flags = IRP_SYNCHRONOUS_API; 01243 } 01244 irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL; 01245 01246 // 01247 // Get a pointer to the stack location for the first driver. This will 01248 // be used to pass the original function codes and parameters. 01249 // 01250 01251 irpSp = IoGetNextIrpStackLocation( irp ); 01252 irpSp->MajorFunction = IRP_MJ_SET_INFORMATION; 01253 irpSp->FileObject = fileObject; 01254 01255 // 01256 // Allocate a buffer and copy the information that is to be set on the 01257 // file into it. Also, set the flags so that the completion code will 01258 // properly handle getting rid of the buffer and will not attempt to 01259 // copy data. 01260 // 01261 01262 irp->AssociatedIrp.SystemBuffer = (PVOID) NULL; 01263 irp->MdlAddress = (PMDL) NULL; 01264 01265 try { 01266 01267 PVOID systemBuffer; 01268 01269 systemBuffer = 01270 irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota( NonPagedPool, 01271 Length ); 01272 RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, 01273 FileInformation, 01274 Length ); 01275 01276 // 01277 // Negative file offsets are illegal. 01278 // 01279 01280 ASSERT((FIELD_OFFSET(FILE_END_OF_FILE_INFORMATION, EndOfFile) | 01281 FIELD_OFFSET(FILE_ALLOCATION_INFORMATION, AllocationSize) | 01282 FIELD_OFFSET(FILE_POSITION_INFORMATION, CurrentByteOffset)) == 0); 01283 01284 if (((FileInformationClass == FileEndOfFileInformation) || 01285 (FileInformationClass == FileAllocationInformation) || 01286 (FileInformationClass == FilePositionInformation)) && 01287 (((PFILE_POSITION_INFORMATION)systemBuffer)->CurrentByteOffset.HighPart < 0)) { 01288 01289 ExRaiseStatus(STATUS_INVALID_PARAMETER); 01290 } 01291 01292 01293 01294 } except(EXCEPTION_EXECUTE_HANDLER) { 01295 01296 // 01297 // An exception was incurred while allocating the intermediary 01298 // system buffer or while copying the caller's data into the 01299 // buffer. Cleanup and return an appropriate error status code. 01300 // 01301 01302 IopExceptionCleanup( fileObject, 01303 irp, 01304 (PKEVENT) NULL, 01305 event ); 01306 01307 return GetExceptionCode(); 01308 01309 } 01310 01311 irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_DEFER_IO_COMPLETION; 01312 01313 // 01314 // Copy the caller's parameters to the service-specific portion of the 01315 // IRP. 01316 // 01317 01318 irpSp->Parameters.SetFile.Length = Length; 01319 irpSp->Parameters.SetFile.FileInformationClass = FileInformationClass; 01320 01321 // 01322 // Insert the packet at the head of the IRP list for the thread. 01323 // 01324 01325 IopQueueThreadIrp( irp ); 01326 01327 // 01328 // Update the operation count statistic for the current process for 01329 // operations other than read and write. 01330 // 01331 01332 IopUpdateOtherOperationCount(); 01333 01334 01335 // 01336 // Everything is now set to invoke the device driver with this request. 01337 // However, it is possible that the information that the caller wants 01338 // to set is device independent. If this is the case, then the request 01339 // can be satisfied here without having to have all of the drivers 01340 // implement the same code. Note that having the IRP is still necessary 01341 // since the I/O completion code requires it. 01342 // 01343 01344 if (FileInformationClass == FileModeInformation) { 01345 01346 PFILE_MODE_INFORMATION modeBuffer = irp->AssociatedIrp.SystemBuffer; 01347 01348 // 01349 // Set the various flags in the mode field for the file object, if 01350 // they are reasonable. There are 4 different invalid combinations 01351 // that the caller may not specify: 01352 // 01353 // 1) An invalid flag was set in the mode field. Not all Create/ 01354 // Open options may be changed. 01355 // 01356 // 2) The caller set one of the synchronous I/O flags (alert or 01357 // nonalert), but the file is not opened for synchronous I/O. 01358 // 01359 // 3) The file is opened for synchronous I/O but the caller did 01360 // not set either of the synchronous I/O flags (alert or non- 01361 // alert). 01362 // 01363 // 4) The caller set both of the synchronous I/O flags (alert and 01364 // nonalert). 01365 // 01366 01367 if ((modeBuffer->Mode & ~FILE_VALID_SET_FLAGS) || 01368 ((modeBuffer->Mode & (FSIO_A | FSIO_NA)) && (!(fileObject->Flags & FO_SYNCHRONOUS_IO))) || 01369 ((!(modeBuffer->Mode & (FSIO_A | FSIO_NA))) && (fileObject->Flags & FO_SYNCHRONOUS_IO)) || 01370 (((modeBuffer->Mode & FSIO_A) && (modeBuffer->Mode & FSIO_NA) ))) { 01371 status = STATUS_INVALID_PARAMETER; 01372 01373 } else { 01374 01375 // 01376 // Set or clear the appropriate flags in the file object. 01377 // 01378 01379 if (!(fileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING)) { 01380 if (modeBuffer->Mode & FILE_WRITE_THROUGH) { 01381 fileObject->Flags |= FO_WRITE_THROUGH; 01382 } else { 01383 fileObject->Flags &= ~FO_WRITE_THROUGH; 01384 } 01385 } 01386 01387 if (modeBuffer->Mode & FILE_SEQUENTIAL_ONLY) { 01388 fileObject->Flags |= FO_SEQUENTIAL_ONLY; 01389 } else { 01390 fileObject->Flags &= ~FO_SEQUENTIAL_ONLY; 01391 } 01392 01393 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 01394 if (modeBuffer->Mode & FSIO_A) { 01395 fileObject->Flags |= FO_ALERTABLE_IO; 01396 } else { 01397 fileObject->Flags &= ~FO_ALERTABLE_IO; 01398 } 01399 } 01400 01401 status = STATUS_SUCCESS; 01402 } 01403 01404 // 01405 // Complete the I/O operation. 01406 // 01407 01408 irp->IoStatus.Status = status; 01409 irp->IoStatus.Information = 0L; 01410 01411 } else if (FileInformationClass == FileRenameInformation || 01412 FileInformationClass == FileLinkInformation || 01413 FileInformationClass == FileMoveClusterInformation) { 01414 01415 // 01416 // Note that following code depends on the fact that the rename 01417 // information, link information and copy-on-write information 01418 // structures look exactly the same. 01419 // 01420 01421 PFILE_RENAME_INFORMATION renameBuffer = irp->AssociatedIrp.SystemBuffer; 01422 01423 // 01424 // The information being set is a variable-length structure with 01425 // embedded size information. Walk the structure to ensure that 01426 // it is valid so the driver does not walk off the end and incur 01427 // an access violation in kernel mode. 01428 // 01429 01430 if ((ULONG) (Length - FIELD_OFFSET( FILE_RENAME_INFORMATION, FileName[0] )) < renameBuffer->FileNameLength) { 01431 status = STATUS_INVALID_PARAMETER; 01432 irp->IoStatus.Status = status; 01433 01434 } else { 01435 01436 // 01437 // Copy the value of the replace BOOLEAN (or the ClusterCount field) 01438 // from the caller's buffer to the I/O stack location parameter 01439 // field where it is expected by file systems. 01440 // 01441 01442 if (FileInformationClass == FileMoveClusterInformation) { 01443 irpSp->Parameters.SetFile.ClusterCount = 01444 ((FILE_MOVE_CLUSTER_INFORMATION *) renameBuffer)->ClusterCount; 01445 } else { 01446 irpSp->Parameters.SetFile.ReplaceIfExists = renameBuffer->ReplaceIfExists; 01447 } 01448 01449 // 01450 // Check to see whether or not a fully qualified pathname was 01451 // supplied. If so, then more processing is required. 01452 // 01453 01454 if (renameBuffer->FileName[0] == (WCHAR) OBJ_NAME_PATH_SEPARATOR || 01455 renameBuffer->RootDirectory) { 01456 01457 // 01458 // A fully qualified file name was specified as the target of 01459 // the rename operation. Attempt to open the target file and 01460 // ensure that the replacement policy for the file is consistent 01461 // with the caller's request, and ensure that the file is on the 01462 // same volume. 01463 // 01464 01465 status = IopOpenLinkOrRenameTarget( &targetHandle, 01466 irp, 01467 renameBuffer, 01468 fileObject ); 01469 if (!NT_SUCCESS( status )) { 01470 irp->IoStatus.Status = status; 01471 01472 } else { 01473 01474 // 01475 // The fully qualified file name specifies a file on the 01476 // same volume and if it exists, then the caller specified 01477 // that it should be replaced. 01478 // 01479 01480 status = IoCallDriver( deviceObject, irp ); 01481 01482 } 01483 01484 } else { 01485 01486 // 01487 // This is a simple rename operation, so call the driver and 01488 // let it perform the rename operation within the same directory 01489 // as the source file. 01490 // 01491 01492 status = IoCallDriver( deviceObject, irp ); 01493 01494 } 01495 } 01496 01497 } else if (FileInformationClass == FileDispositionInformation) { 01498 01499 PFILE_DISPOSITION_INFORMATION disposition = irp->AssociatedIrp.SystemBuffer; 01500 01501 // 01502 // Check to see whether the disposition delete field has been set to 01503 // TRUE and, if so, copy the handle being used to do this to the IRP 01504 // stack location parameter. 01505 // 01506 01507 if (disposition->DeleteFile) { 01508 irpSp->Parameters.SetFile.DeleteHandle = FileHandle; 01509 } 01510 01511 // 01512 // Simply invoke the driver to perform the (un)delete operation. 01513 // 01514 01515 status = IoCallDriver( deviceObject, irp ); 01516 01517 } else if (FileInformationClass == FileCompletionInformation) { 01518 01519 PFILE_COMPLETION_INFORMATION completion = irp->AssociatedIrp.SystemBuffer; 01520 PIO_COMPLETION_CONTEXT context; 01521 PVOID portObject; 01522 01523 // 01524 // It is an error if this file object already has an LPC port associated 01525 // with it. 01526 // 01527 01528 if (fileObject->CompletionContext || fileObject->Flags & FO_SYNCHRONOUS_IO) { 01529 01530 status = STATUS_INVALID_PARAMETER; 01531 01532 } else { 01533 01534 // 01535 // Attempt to reference the port object by its handle and convert it 01536 // into a pointer to the port object itself. 01537 // 01538 01539 status = ObReferenceObjectByHandle( completion->Port, 01540 IO_COMPLETION_MODIFY_STATE, 01541 IoCompletionObjectType, 01542 requestorMode, 01543 (PVOID *) &portObject, 01544 NULL ); 01545 if (NT_SUCCESS( status )) { 01546 01547 // 01548 // Allocate the memory to be associated w/this file object 01549 // 01550 01551 context = ExAllocatePoolWithTag( PagedPool, 01552 sizeof( IO_COMPLETION_CONTEXT ), 01553 'cCoI' ); 01554 if (!context) { 01555 01556 ObDereferenceObject( portObject ); 01557 status = STATUS_INSUFFICIENT_RESOURCES; 01558 01559 } else { 01560 01561 // 01562 // Everything was successful. Capture the completion port 01563 // and the key. 01564 // 01565 01566 context->Port = portObject; 01567 context->Key = completion->Key; 01568 01569 if (!InterlockedCompareExchangePointer( &fileObject->CompletionContext, context, NULL )) { 01570 01571 status = STATUS_SUCCESS; 01572 01573 } else { 01574 01575 // 01576 // Someone set the completion context after the check. 01577 // Simply drop everything on the floor and return an 01578 // error. 01579 // 01580 01581 ExFreePool( context ); 01582 ObDereferenceObject( portObject ); 01583 status = STATUS_INVALID_PARAMETER; 01584 } 01585 } 01586 } 01587 } 01588 01589 // 01590 // Complete the I/O operation. 01591 // 01592 01593 irp->IoStatus.Status = status; 01594 irp->IoStatus.Information = 0; 01595 01596 } else { 01597 01598 // 01599 // This is not a request that can be performed here, so invoke the 01600 // driver at its appropriate dispatch entry with the IRP. 01601 // 01602 01603 status = IoCallDriver( deviceObject, irp ); 01604 } 01605 01606 // 01607 // If this operation was a synchronous I/O operation, check the return 01608 // status to determine whether or not to wait on the file object. If 01609 // the file object is to be waited on, wait for the operation to complete 01610 // and obtain the final status from the file object itself. 01611 // 01612 01613 if (status == STATUS_PENDING) { 01614 01615 if (synchronousIo) { 01616 01617 status = KeWaitForSingleObject( &fileObject->Event, 01618 Executive, 01619 requestorMode, 01620 (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), 01621 (PLARGE_INTEGER) NULL ); 01622 01623 if (status == STATUS_ALERTED || status == STATUS_USER_APC) { 01624 01625 // 01626 // The wait request has ended either because the thread was 01627 // alerted or an APC was queued to this thread, because of 01628 // thread rundown or CTRL/C processing. In either case, try 01629 // to bail out of this I/O request carefully so that the IRP 01630 // completes before this routine exists so that synchronization 01631 // with the file object will remain intact. 01632 // 01633 01634 IopCancelAlertedRequest( &fileObject->Event, irp ); 01635 01636 } 01637 01638 status = fileObject->FinalStatus; 01639 01640 IopReleaseFileObjectLock( fileObject ); 01641 01642 } else { 01643 01644 // 01645 // This is a normal synchronous I/O operation, as opposed to a 01646 // serialized synchronous I/O operation. For this case, wait for 01647 // the local event and copy the final status information back to 01648 // the caller. 01649 // 01650 01651 status = KeWaitForSingleObject( event, 01652 Executive, 01653 requestorMode, 01654 FALSE, 01655 (PLARGE_INTEGER) NULL ); 01656 01657 if (status == STATUS_ALERTED || status == STATUS_USER_APC) { 01658 01659 // 01660 // The wait request has ended either because the thread was 01661 // alerted or an APC was queued to this thread, because of 01662 // thread rundown or CTRL/C processing. In either case, try 01663 // to bail out of this I/O request carefully so that the IRP 01664 // completes before this routine exists or the event will not 01665 // be around to set to the Signaled state. 01666 // 01667 01668 IopCancelAlertedRequest( event, irp ); 01669 01670 } 01671 01672 status = localIoStatus.Status; 01673 01674 try { 01675 01676 *IoStatusBlock = localIoStatus; 01677 01678 } except(EXCEPTION_EXECUTE_HANDLER) { 01679 01680 // 01681 // An exception occurred attempting to write the caller's I/O 01682 // status block. Simply change the final status of the 01683 // operation to the exception code. 01684 // 01685 01686 status = GetExceptionCode(); 01687 } 01688 01689 ExFreePool( event ); 01690 01691 } 01692 01693 } else { 01694 01695 // 01696 // The I/O operation finished without return a status of pending. 01697 // This means that the operation has not been through I/O completion, 01698 // so it must be done here. 01699 // 01700 01701 PKNORMAL_ROUTINE normalRoutine; 01702 PVOID normalContext; 01703 KIRQL irql; 01704 01705 if (!synchronousIo) { 01706 01707 // 01708 // This is not a synchronous I/O operation, it is a synchronous 01709 // I/O API to a file opened for asynchronous I/O. Since this 01710 // code path need never wait on the allocated and supplied event, 01711 // get rid of it so that it doesn't have to be set to the 01712 // Signaled state by the I/O completion code. 01713 // 01714 01715 irp->UserEvent = (PKEVENT) NULL; 01716 ExFreePool( event ); 01717 } 01718 01719 irp->UserIosb = IoStatusBlock; 01720 KeRaiseIrql( APC_LEVEL, &irql ); 01721 IopCompleteRequest( &irp->Tail.Apc, 01722 &normalRoutine, 01723 &normalContext, 01724 (PVOID *) &fileObject, 01725 &normalContext ); 01726 KeLowerIrql( irql ); 01727 01728 if (synchronousIo) { 01729 IopReleaseFileObjectLock( fileObject ); 01730 } 01731 01732 } 01733 01734 // 01735 // If there was a target handle generated because of a rename operation, 01736 // close it now. 01737 // 01738 01739 if (targetHandle) { 01740 NtClose( targetHandle ); 01741 } 01742 01743 return status; 01744 } }


Generated on Sat May 15 19:45:24 2004 for test by doxygen 1.3.7