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

qsea.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 qsea.c 00008 00009 Abstract: 00010 00011 This module contains the code to implement the NtQueryEaFile and the 00012 NtSetEaFile system services for the NT I/O system. 00013 00014 Author: 00015 00016 Darryl E. Havens (darrylh) 20-Jun-1989 00017 00018 Environment: 00019 00020 Kernel mode only 00021 00022 Revision History: 00023 00024 00025 --*/ 00026 00027 #include "iop.h" 00028 00029 #ifdef ALLOC_PRAGMA 00030 #pragma alloc_text(PAGE, NtQueryEaFile) 00031 #pragma alloc_text(PAGE, NtSetEaFile) 00032 #endif 00033 00034 NTSTATUS 00035 NtQueryEaFile( 00036 IN HANDLE FileHandle, 00037 OUT PIO_STATUS_BLOCK IoStatusBlock, 00038 OUT PVOID Buffer, 00039 IN ULONG Length, 00040 IN BOOLEAN ReturnSingleEntry, 00041 IN PVOID EaList OPTIONAL, 00042 IN ULONG EaListLength, 00043 IN PULONG EaIndex OPTIONAL, 00044 IN BOOLEAN RestartScan 00045 ) 00046 00047 /*++ 00048 00049 Routine Description: 00050 00051 This service returns the Extended Attributes (EAs) associated with the 00052 file specified by the FileHandle parameter. The amount of information 00053 returned is based on the size of the EAs, and the size of the buffer. 00054 That is, either all of the EAs are written to the buffer, or the buffer 00055 is filled with complete EAs if the buffer is not large enough to contain 00056 all of the EAs. Only complete EAs are ever written to the buffer; no 00057 partial EAs will ever be returned. 00058 00059 Arguments: 00060 00061 FileHandle - Supplies a handle to the file for which the EAs are returned. 00062 00063 IoStatusBlock - Address of the caller's I/O status block. 00064 00065 Buffer - Supplies a buffer to receive the EAs for the file. 00066 00067 Length - Supplies the length, in bytes, of the buffer. 00068 00069 ReturnSingleEntry - Indicates that only a single entry should be returned 00070 rather than filling the buffer with as many EAs as possible. 00071 00072 EaList - Optionally supplies a list of EA names whose values are returned. 00073 00074 EaListLength - Supplies the length of the EA list, if an EA list was 00075 specified. 00076 00077 EaIndex - Supplies the optional index of an EA whose value is to be 00078 returned. If specified, then only that EA is returned. 00079 00080 RestartScan - Indicates whether the scan of the EAs should be restarted 00081 from the beginning. 00082 00083 Return Value: 00084 00085 The status returned is the final completion status of the operation. 00086 00087 --*/ 00088 00089 #define GET_OFFSET_LENGTH( CurrentEa, EaBase ) ( \ 00090 (ULONG) ((PCHAR) CurrentEa - (PCHAR) EaBase) ) 00091 00092 00093 { 00094 PIRP irp; 00095 NTSTATUS status; 00096 PFILE_OBJECT fileObject; 00097 PDEVICE_OBJECT deviceObject; 00098 PKEVENT event = (PKEVENT) NULL; 00099 PCHAR auxiliaryBuffer = (PCHAR) NULL; 00100 BOOLEAN eaListPresent = FALSE; 00101 ULONG eaIndexValue = 0L; 00102 KPROCESSOR_MODE requestorMode; 00103 PIO_STACK_LOCATION irpSp; 00104 IO_STATUS_BLOCK localIoStatus; 00105 BOOLEAN synchronousIo; 00106 00107 PAGED_CODE(); 00108 00109 // 00110 // Get the previous mode; i.e., the mode of the caller. 00111 // 00112 00113 requestorMode = KeGetPreviousMode(); 00114 00115 if (requestorMode != KernelMode) { 00116 00117 // 00118 // The caller's access mode is not kernel so probe each of the arguments 00119 // and capture them as necessary. If any failures occur, the condition 00120 // handler will be invoked to handle them. It will simply cleanup and 00121 // return an access violation status code back to the system service 00122 // dispatcher. 00123 // 00124 00125 try { 00126 00127 // 00128 // The IoStatusBlock parameter must be writeable by the caller. 00129 // 00130 00131 ProbeForWriteIoStatus( IoStatusBlock ); 00132 00133 // 00134 // The buffer must be writeable by the caller. 00135 // 00136 00137 ProbeForWrite( Buffer, Length, sizeof( ULONG ) ); 00138 00139 // 00140 // If the optional EaIndex parameter was specified, then it must be 00141 // readable by the caller. Capture its value. 00142 // 00143 00144 if (ARGUMENT_PRESENT( EaIndex )) { 00145 eaIndexValue = ProbeAndReadUlong( EaIndex ); 00146 } 00147 00148 // 00149 // If the optional EaList parameter was specified, then it must be 00150 // readable by the caller. Validate that the buffer contains a 00151 // legal get information structure. 00152 // 00153 00154 if (ARGUMENT_PRESENT( EaList ) && EaListLength != 0) { 00155 00156 PFILE_GET_EA_INFORMATION eas; 00157 LONG tempLength; 00158 ULONG entrySize; 00159 00160 eaListPresent = TRUE; 00161 00162 ProbeForRead( EaList, EaListLength, sizeof( ULONG ) ); 00163 auxiliaryBuffer = ExAllocatePoolWithQuota( NonPagedPool, 00164 EaListLength ); 00165 RtlCopyMemory( auxiliaryBuffer, EaList, EaListLength ); 00166 00167 eas = (PFILE_GET_EA_INFORMATION) auxiliaryBuffer; 00168 tempLength = EaListLength; 00169 00170 // 00171 // Walk the request buffer and ensure that its format is 00172 // valid. That is, ensure that it does not walk off the 00173 // end of the buffer that has been captured. 00174 // 00175 00176 for (;;) { 00177 00178 // 00179 // Get the size of the current entry in the buffer. 00180 // 00181 00182 if (tempLength < FIELD_OFFSET( FILE_GET_EA_INFORMATION, EaName[0])) { 00183 tempLength = 0; 00184 ExFreePool( auxiliaryBuffer ); 00185 auxiliaryBuffer = (PVOID) NULL; 00186 IoStatusBlock->Status = STATUS_EA_LIST_INCONSISTENT; 00187 IoStatusBlock->Information = tempLength; 00188 return STATUS_EA_LIST_INCONSISTENT; 00189 } 00190 00191 entrySize = FIELD_OFFSET( FILE_GET_EA_INFORMATION, EaName[0] ) + eas->EaNameLength + 1; 00192 00193 if ((ULONG) tempLength < entrySize) { 00194 tempLength = GET_OFFSET_LENGTH( eas, auxiliaryBuffer ); 00195 ExFreePool( auxiliaryBuffer ); 00196 auxiliaryBuffer = (PVOID) NULL; 00197 IoStatusBlock->Status = STATUS_EA_LIST_INCONSISTENT; 00198 IoStatusBlock->Information = tempLength; 00199 return STATUS_EA_LIST_INCONSISTENT; 00200 } 00201 00202 if (eas->NextEntryOffset != 0) { 00203 00204 // 00205 // There is another entry in the buffer and it must 00206 // be longword aligned. Ensure that the offset 00207 // indicates that it is. If it isn't, return an 00208 // invalid parameter status. 00209 // 00210 00211 if ((((entrySize + 3) & ~3) != eas->NextEntryOffset) || 00212 ((LONG) eas->NextEntryOffset < 0)) { 00213 tempLength = GET_OFFSET_LENGTH( eas, auxiliaryBuffer ); 00214 ExFreePool( auxiliaryBuffer ); 00215 auxiliaryBuffer = (PVOID) NULL; 00216 IoStatusBlock->Status = STATUS_EA_LIST_INCONSISTENT; 00217 IoStatusBlock->Information = tempLength; 00218 return STATUS_EA_LIST_INCONSISTENT; 00219 00220 } else { 00221 00222 // 00223 // There is another entry in the buffer, so 00224 // account for the size of the current entry 00225 // in the length and get a pointer to the next 00226 // entry. 00227 // 00228 00229 tempLength -= eas->NextEntryOffset; 00230 if (tempLength < 0) { 00231 tempLength = GET_OFFSET_LENGTH( eas, auxiliaryBuffer ); 00232 ExFreePool( auxiliaryBuffer ); 00233 auxiliaryBuffer = (PVOID) NULL; 00234 IoStatusBlock->Status = STATUS_EA_LIST_INCONSISTENT; 00235 IoStatusBlock->Information = tempLength; 00236 return STATUS_EA_LIST_INCONSISTENT; 00237 } 00238 eas = (PFILE_GET_EA_INFORMATION) ((PCHAR) eas + eas->NextEntryOffset); 00239 } 00240 00241 } else { 00242 00243 // 00244 // There are no other entries in the buffer. Simply 00245 // account for the overall buffer length according 00246 // to the size of the current entry and exit the 00247 // loop. 00248 // 00249 00250 tempLength -= entrySize; 00251 break; 00252 } 00253 } 00254 00255 // 00256 // All of the entries in the buffer have been processed. 00257 // Check to see whether the overall buffer length went 00258 // negative. If so, return an error. 00259 // 00260 00261 if (tempLength < 0) { 00262 tempLength = GET_OFFSET_LENGTH( eas, auxiliaryBuffer ); 00263 ExFreePool( auxiliaryBuffer ); 00264 auxiliaryBuffer = (PVOID) NULL; 00265 IoStatusBlock->Status = STATUS_EA_LIST_INCONSISTENT; 00266 IoStatusBlock->Information = tempLength; 00267 return STATUS_EA_LIST_INCONSISTENT; 00268 } 00269 00270 } 00271 00272 } except(EXCEPTION_EXECUTE_HANDLER) { 00273 00274 // 00275 // An exception was incurred while probing the caller's 00276 // parameters, allocating the pool buffer, or copying the 00277 // caller's EA list to the buffer. Cleanup and return an 00278 // appropriate error status code. 00279 // 00280 00281 if (auxiliaryBuffer != NULL) { 00282 ExFreePool( auxiliaryBuffer ); 00283 } 00284 00285 return GetExceptionCode(); 00286 00287 } 00288 00289 } else { 00290 00291 // 00292 // The caller's mode was KernelMode. Simply allocate pool for the 00293 // EaList, if one was specified, and copy the string to it. Also, 00294 // if an EaIndex was specified copy it as well. 00295 // 00296 00297 if (ARGUMENT_PRESENT( EaList ) && (EaListLength != 0)) { 00298 eaListPresent = TRUE; 00299 try { 00300 auxiliaryBuffer = ExAllocatePoolWithQuota( NonPagedPool, 00301 EaListLength ); 00302 } except(EXCEPTION_EXECUTE_HANDLER) { 00303 return GetExceptionCode(); 00304 } 00305 RtlCopyMemory( auxiliaryBuffer, EaList, EaListLength ); 00306 } 00307 00308 if (ARGUMENT_PRESENT( EaIndex )) { 00309 eaIndexValue = *EaIndex; 00310 } 00311 } 00312 00313 // 00314 // There were no blatant errors so far, so reference the file object so 00315 // the target device object can be found. Note that if the handle does 00316 // not refer to a file object, or if the caller does not have the required 00317 // access to the file, then it will fail. 00318 // 00319 00320 status = ObReferenceObjectByHandle( FileHandle, 00321 FILE_READ_EA, 00322 IoFileObjectType, 00323 requestorMode, 00324 (PVOID *) &fileObject, 00325 NULL ); 00326 if (!NT_SUCCESS( status )) { 00327 if (eaListPresent) { 00328 ExFreePool( auxiliaryBuffer ); 00329 } 00330 return status; 00331 } 00332 00333 // 00334 // Make a special check here to determine whether this is a synchronous 00335 // I/O operation. If it is, then wait here until the file is owned by 00336 // the current thread. If this is not a (serialized) synchronous I/O 00337 // operation, then allocate and initialize the local event. 00338 // 00339 00340 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 00341 00342 BOOLEAN interrupted; 00343 00344 if (!IopAcquireFastLock( fileObject )) { 00345 status = IopAcquireFileObjectLock( fileObject, 00346 requestorMode, 00347 (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), 00348 &interrupted ); 00349 if (interrupted) { 00350 if (eaListPresent) { 00351 ExFreePool( auxiliaryBuffer ); 00352 } 00353 ObDereferenceObject( fileObject ); 00354 return status; 00355 } 00356 } 00357 synchronousIo = TRUE; 00358 } else { 00359 00360 // 00361 // This is a synchronous API being invoked for a file that is opened 00362 // for asynchronous I/O. This means that this system service is 00363 // to synchronize the completion of the operation before returning 00364 // to the caller. A local event is used to do this. 00365 // 00366 00367 event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) ); 00368 if (event == NULL) { 00369 if (eaListPresent) { 00370 ExFreePool( auxiliaryBuffer ); 00371 } 00372 ObDereferenceObject( fileObject ); 00373 return STATUS_INSUFFICIENT_RESOURCES; 00374 } 00375 KeInitializeEvent( event, SynchronizationEvent, FALSE ); 00376 synchronousIo = FALSE; 00377 } 00378 00379 // 00380 // Set the file object to the Not-Signaled state. 00381 // 00382 00383 KeClearEvent( &fileObject->Event ); 00384 00385 // 00386 // Get the address of the target device object. 00387 // 00388 00389 deviceObject = IoGetRelatedDeviceObject( fileObject ); 00390 00391 // 00392 // Allocate and initialize the I/O Request Packet (IRP) for this operation. 00393 // The allocation is performed with an exception handler in case the 00394 // caller does not have enough quota to allocate the packet. 00395 00396 irp = IoAllocateIrp( deviceObject->StackSize, TRUE ); 00397 if (!irp) { 00398 00399 // 00400 // An IRP could not be allocated. Cleanup and return an appropriate 00401 // error status code. 00402 // 00403 00404 if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) { 00405 ExFreePool( event ); 00406 } 00407 00408 IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL ); 00409 00410 if (eaListPresent) { 00411 ExFreePool( auxiliaryBuffer ); 00412 } 00413 00414 return STATUS_INSUFFICIENT_RESOURCES; 00415 } 00416 irp->Tail.Overlay.OriginalFileObject = fileObject; 00417 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00418 irp->RequestorMode = requestorMode; 00419 00420 // 00421 // Fill in the service independent parameters in the IRP. 00422 // 00423 00424 if (synchronousIo) { 00425 irp->UserEvent = (PKEVENT) NULL; 00426 irp->UserIosb = IoStatusBlock; 00427 } else { 00428 irp->UserEvent = event; 00429 irp->UserIosb = &localIoStatus; 00430 irp->Flags = IRP_SYNCHRONOUS_API; 00431 } 00432 irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL; 00433 00434 // 00435 // Get a pointer to the stack location for the first driver. This will be 00436 // used to pass the original function codes and parameters. 00437 // 00438 00439 irpSp = IoGetNextIrpStackLocation( irp ); 00440 irpSp->MajorFunction = IRP_MJ_QUERY_EA; 00441 irpSp->FileObject = fileObject; 00442 00443 // 00444 // If the caller specified an EA list of names to be queried, then pass 00445 // the address of the intermediary buffer containing the list to the 00446 // driver. 00447 // 00448 00449 if (eaListPresent) { 00450 irp->Tail.Overlay.AuxiliaryBuffer = auxiliaryBuffer; 00451 irpSp->Parameters.QueryEa.EaList = auxiliaryBuffer; 00452 irpSp->Parameters.QueryEa.EaListLength = EaListLength; 00453 } 00454 00455 // 00456 // Now determine whether this driver expects to have data buffered 00457 // to it or whether it performs direct I/O. This is based on the 00458 // DO_BUFFERED_IO flag in the device object. If the flag is set, 00459 // then a system buffer is allocated and the driver's data will be 00460 // copied to it. If the DO_DIRECT_IO flag is set in the device 00461 // object, then a Memory Descriptor List (MDL) is allocated and 00462 // the caller's buffer is locked down using it. Finally, if the 00463 // driver specifies neither of the flags, then simply pass the 00464 // address and length of the buffer and allow the driver to perform 00465 // all of the checking and buffering if any is required. 00466 // 00467 00468 if (deviceObject->Flags & DO_BUFFERED_IO) { 00469 00470 // 00471 // The driver wishes the caller's buffered be copied into an 00472 // intermediary buffer. Allocate the system buffer and specify 00473 // that it should be deallocated on completion. Also indicate 00474 // that this is an input operation so the data will be copied 00475 // into the caller's buffer. This is done using an exception 00476 // handler that will perform cleanup if the operation fails. 00477 // 00478 00479 if (Length) { 00480 try { 00481 00482 // 00483 // Allocate the intermediary system buffer from nonpaged 00484 // pool and charge quota for it. 00485 // 00486 00487 irp->AssociatedIrp.SystemBuffer = 00488 ExAllocatePoolWithQuota( NonPagedPool, Length ); 00489 00490 } except(EXCEPTION_EXECUTE_HANDLER) { 00491 00492 // 00493 // An exception was incurred while either probing the 00494 // caller's buffer or allocating the system buffer. 00495 // Determine what actually happened, clean everything 00496 // up, and return an appropriate error status code. 00497 // 00498 00499 IopExceptionCleanup( fileObject, 00500 irp, 00501 (PKEVENT) NULL, 00502 event ); 00503 00504 if (auxiliaryBuffer != NULL) { 00505 ExFreePool( auxiliaryBuffer ); 00506 } 00507 00508 return GetExceptionCode(); 00509 00510 } 00511 00512 // 00513 // Remember the address of the caller's buffer so the copy can 00514 // take place during I/O completion. Also, set the flags so 00515 // that the completion code knows to do the copy and to deallocate 00516 // the buffer. 00517 // 00518 00519 irp->UserBuffer = Buffer; 00520 irp->Flags |= (ULONG) (IRP_BUFFERED_IO | 00521 IRP_DEALLOCATE_BUFFER | 00522 IRP_INPUT_OPERATION); 00523 } else { 00524 // 00525 // This is a zero-length request. Simply indicate that this is 00526 // buffered I/O, and pass along the request. The buffer will 00527 // not be set to deallocate so the completion path does not 00528 // have to special-case the length. 00529 // 00530 00531 irp->AssociatedIrp.SystemBuffer = NULL; 00532 irp->Flags |= (ULONG) (IRP_BUFFERED_IO | IRP_INPUT_OPERATION); 00533 00534 } 00535 00536 } else if (deviceObject->Flags & DO_DIRECT_IO) { 00537 00538 PMDL mdl; 00539 00540 // 00541 // This is a direct I/O operation. Allocate an MDL and invoke 00542 // the memory management routine to lock the buffer into memory. 00543 // This is done using an exception handler that will perform 00544 // cleanup if the operation fails. 00545 // 00546 00547 if (Length) { 00548 mdl = (PMDL) NULL; 00549 00550 try { 00551 00552 // 00553 // Allocate an MDL, charging quota for it, and hang it off 00554 // of the IRP. Probe and lock the pages associated with 00555 // the caller's buffer for write access and fill in the MDL 00556 // with the PFNs of those pages. 00557 // 00558 00559 mdl = IoAllocateMdl( Buffer, Length, FALSE, TRUE, irp ); 00560 if (mdl == NULL) { 00561 ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); 00562 } 00563 MmProbeAndLockPages( mdl, requestorMode, IoWriteAccess ); 00564 00565 } except(EXCEPTION_EXECUTE_HANDLER) { 00566 00567 // 00568 // An exception was incurred while either probing the 00569 // caller's buffer or allocating the MDL. Determine what 00570 // actually happened, clean everything up, and return an 00571 // appropriate error status code. 00572 // 00573 00574 IopExceptionCleanup( fileObject, 00575 irp, 00576 (PKEVENT) NULL, 00577 event ); 00578 00579 if (auxiliaryBuffer != NULL) { 00580 ExFreePool( auxiliaryBuffer ); 00581 } 00582 00583 return GetExceptionCode(); 00584 00585 } 00586 } 00587 00588 } else { 00589 00590 // 00591 // Pass the address of the user's buffer so the driver has access 00592 // to it. It is now the driver's responsibility to do everything. 00593 // 00594 00595 irp->UserBuffer = Buffer; 00596 00597 } 00598 00599 // 00600 // Copy the caller's parameters to the service-specific portion of the 00601 // IRP. 00602 // 00603 00604 irpSp->Parameters.QueryEa.Length = Length; 00605 irpSp->Parameters.QueryEa.EaIndex = eaIndexValue; 00606 irpSp->Flags = 0; 00607 if (RestartScan) { 00608 irpSp->Flags = SL_RESTART_SCAN; 00609 } 00610 if (ReturnSingleEntry) { 00611 irpSp->Flags |= SL_RETURN_SINGLE_ENTRY; 00612 } 00613 if (ARGUMENT_PRESENT( EaIndex )) { 00614 irpSp->Flags |= SL_INDEX_SPECIFIED; 00615 } 00616 00617 // 00618 // Queue the packet, call the driver, and synchronize appopriately with 00619 // I/O completion. 00620 // 00621 00622 status = IopSynchronousServiceTail( deviceObject, 00623 irp, 00624 fileObject, 00625 FALSE, 00626 requestorMode, 00627 synchronousIo, 00628 OtherTransfer ); 00629 00630 // 00631 // If the file for this operation was not opened for synchronous I/O, then 00632 // synchronization of completion of the I/O operation has not yet occurred 00633 // since the allocated event must be used for synchronous APIs on files 00634 // opened for asynchronous I/O. Synchronize the completion of the I/O 00635 // operation now. 00636 // 00637 00638 if (!synchronousIo) { 00639 00640 status = IopSynchronousApiServiceTail( status, 00641 event, 00642 irp, 00643 requestorMode, 00644 &localIoStatus, 00645 IoStatusBlock ); 00646 } 00647 00648 return status; 00649 } 00650 00651 NTSTATUS 00652 NtSetEaFile( 00653 IN HANDLE FileHandle, 00654 OUT PIO_STATUS_BLOCK IoStatusBlock, 00655 IN PVOID Buffer, 00656 IN ULONG Length 00657 ) 00658 00659 /*++ 00660 00661 Routine Description: 00662 00663 This service replaces the Extended Attributes (EAs) associated with the file 00664 specified by the FileHandle parameter. All of the EAs associated with the 00665 file are replaced by the EAs in the specified buffer. 00666 00667 Arguments: 00668 00669 FileHandle - Supplies a handle to the file whose EAs should be changed. 00670 00671 IoStatusBlock - Address of the caller's I/O status block. 00672 00673 FileInformation - Supplies a buffer containing the new EAs which should be 00674 used to replace the EAs currently associated with the file. 00675 00676 Length - Supplies the length, in bytes, of the buffer. 00677 00678 Return Value: 00679 00680 The status returned is the final completion status of the operation. 00681 00682 --*/ 00683 00684 { 00685 PIRP irp; 00686 NTSTATUS status; 00687 PFILE_OBJECT fileObject; 00688 PDEVICE_OBJECT deviceObject; 00689 PKEVENT event = (PKEVENT) NULL; 00690 KPROCESSOR_MODE requestorMode; 00691 PIO_STACK_LOCATION irpSp; 00692 IO_STATUS_BLOCK localIoStatus; 00693 BOOLEAN synchronousIo; 00694 00695 PAGED_CODE(); 00696 00697 // 00698 // Get the previous mode; i.e., the mode of the caller. 00699 // 00700 00701 requestorMode = KeGetPreviousMode(); 00702 00703 if (requestorMode != KernelMode) { 00704 00705 // 00706 // The caller's access mode is user, so probe each of the arguments 00707 // and capture them as necessary. If any failures occur, the condition 00708 // handler will be invoked to handle them. It will simply cleanup and 00709 // return an access violation status code back to the system service 00710 // dispatcher. 00711 // 00712 00713 try { 00714 00715 // 00716 // The IoStatusBlock parameter must be writeable by the caller. 00717 // 00718 00719 ProbeForWriteIoStatus( IoStatusBlock ); 00720 00721 // 00722 // The Buffer parameter must be readable by the caller. 00723 // 00724 00725 ProbeForRead( Buffer, Length, sizeof( ULONG ) ); 00726 00727 } except(EXCEPTION_EXECUTE_HANDLER) { 00728 00729 // 00730 // An exception was incurred while probing the caller's parameters. 00731 // Cleanup and return an appropriate error status code. 00732 // 00733 00734 return GetExceptionCode(); 00735 } 00736 } 00737 00738 00739 // 00740 // There were no blatant errors so far, so reference the file object so 00741 // the target device object can be found. Note that if the handle does 00742 // not refer to a file object, or if the caller does not have the required 00743 // access to the file, then it will fail. 00744 // 00745 00746 status = ObReferenceObjectByHandle( FileHandle, 00747 FILE_WRITE_EA, 00748 IoFileObjectType, 00749 requestorMode, 00750 (PVOID *) &fileObject, 00751 NULL ); 00752 if (!NT_SUCCESS( status )) { 00753 return status; 00754 } 00755 00756 // 00757 // Make a special check here to determine whether this is a synchronous 00758 // I/O operation. If it is, then wait here until the file is owned by 00759 // the current thread. If this is not a (serialized) synchronous I/O 00760 // operation, then allocate and initialize the local event. 00761 // 00762 00763 if (fileObject->Flags & FO_SYNCHRONOUS_IO) { 00764 00765 BOOLEAN interrupted; 00766 00767 if (!IopAcquireFastLock( fileObject )) { 00768 status = IopAcquireFileObjectLock( fileObject, 00769 requestorMode, 00770 (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0), 00771 &interrupted ); 00772 if (interrupted) { 00773 ObDereferenceObject( fileObject ); 00774 return status; 00775 } 00776 } 00777 synchronousIo = TRUE; 00778 } else { 00779 00780 // 00781 // This is a synchronous API being invoked for a file that is opened 00782 // for asynchronous I/O. This means that this system service is 00783 // to synchronize the completion of the operation before returning 00784 // to the caller. A local event is used to do this. 00785 // 00786 00787 event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) ); 00788 if (event == NULL) { 00789 ObDereferenceObject( fileObject ); 00790 return STATUS_INSUFFICIENT_RESOURCES; 00791 } 00792 KeInitializeEvent( event, SynchronizationEvent, FALSE ); 00793 synchronousIo = FALSE; 00794 } 00795 00796 // 00797 // Set the file object to the Not-Signaled state. 00798 // 00799 00800 KeClearEvent( &fileObject->Event ); 00801 00802 // 00803 // Get the address of the target device object. 00804 // 00805 00806 deviceObject = IoGetRelatedDeviceObject( fileObject ); 00807 00808 // 00809 // Allocate and initialize the I/O Request Packet (IRP) for this operation. 00810 // The allocation is performed with an exception handler in case the 00811 // caller does not have enough quota to allocate the packet. 00812 00813 irp = IoAllocateIrp( deviceObject->StackSize, TRUE ); 00814 if (!irp) { 00815 00816 // 00817 // An IRP could not be allocated. Cleanup and return an appropriate 00818 // error status code. 00819 // 00820 00821 if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) { 00822 ExFreePool( event ); 00823 } 00824 00825 IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL ); 00826 00827 return STATUS_INSUFFICIENT_RESOURCES; 00828 } 00829 irp->Tail.Overlay.OriginalFileObject = fileObject; 00830 irp->Tail.Overlay.Thread = PsGetCurrentThread(); 00831 irp->RequestorMode = requestorMode; 00832 00833 // 00834 // Fill in the service independent parameters in the IRP. 00835 // 00836 00837 if (synchronousIo) { 00838 irp->UserEvent = (PKEVENT) NULL; 00839 irp->UserIosb = IoStatusBlock; 00840 } else { 00841 irp->UserEvent = event; 00842 irp->UserIosb = &localIoStatus; 00843 irp->Flags = IRP_SYNCHRONOUS_API; 00844 } 00845 irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL; 00846 00847 // 00848 // Get a pointer to the stack location for the first driver. This will be 00849 // used to pass the original function codes and parameters. 00850 // 00851 00852 irpSp = IoGetNextIrpStackLocation( irp ); 00853 irpSp->MajorFunction = IRP_MJ_SET_EA; 00854 irpSp->FileObject = fileObject; 00855 00856 // 00857 // Now determine whether this driver expects to have data buffered to it 00858 // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO 00859 // flag in the device object. if the flag is set, then a system buffer is 00860 // allocated and driver's data is copied to it. If the DO_DIRECT_IO flag 00861 // is set in the device object, then a Memory Descriptor List (MDL) is 00862 // allocated and the caller's buffer is locked down using it. Finally, if 00863 // the driver specifies neither of the flags, then simply pass the address 00864 // and length of the buffer and allow the driver to perform all of the 00865 // checking and buffering if any is required. 00866 // 00867 00868 if (deviceObject->Flags & DO_BUFFERED_IO) { 00869 00870 PFILE_FULL_EA_INFORMATION systemBuffer; 00871 ULONG errorOffset; 00872 00873 // 00874 // The driver wishes the caller's buffer to be copied into an 00875 // intermediary buffer. Allocate the system buffer and specify 00876 // that it should be deallocated on completion. Also check to 00877 // ensure that the caller's EA list is valid. All of this is 00878 // performed within an exception handler that will perform 00879 // cleanup if the operation fails. 00880 // 00881 00882 if (Length) { 00883 try { 00884 00885 // 00886 // Allocate the intermediary system buffer and charge the caller 00887 // quota for its allocation. Copy the caller's EA buffer into the 00888 // buffer and check to ensure that it is valid. 00889 // 00890 00891 systemBuffer = ExAllocatePoolWithQuota( NonPagedPool, Length ); 00892 00893 irp->AssociatedIrp.SystemBuffer = systemBuffer; 00894 00895 RtlCopyMemory( systemBuffer, Buffer, Length ); 00896 00897 status = IoCheckEaBufferValidity( systemBuffer, 00898 Length, 00899 &errorOffset ); 00900 00901 if (!NT_SUCCESS( status )) { 00902 IoStatusBlock->Status = status; 00903 IoStatusBlock->Information = errorOffset; 00904 ExRaiseStatus( status ); 00905 } 00906 00907 } except(EXCEPTION_EXECUTE_HANDLER) { 00908 00909 // 00910 // An exception was incurred while allocating the buffer, copying 00911 // the caller's data into it, or walking the EA buffer. Determine 00912 // what happened, cleanup, and return an appropriate error status 00913 // code. 00914 // 00915 00916 IopExceptionCleanup( fileObject, 00917 irp, 00918 (PKEVENT) NULL, 00919 event ); 00920 00921 return GetExceptionCode(); 00922 00923 } 00924 00925 // 00926 // Set the flags so that the completion code knows to deallocate the 00927 // buffer. 00928 // 00929 00930 irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER; 00931 } else { 00932 irp->AssociatedIrp.SystemBuffer = NULL; 00933 } 00934 00935 00936 } else if (deviceObject->Flags & DO_DIRECT_IO) { 00937 00938 PMDL mdl; 00939 00940 // 00941 // This is a direct I/O operation. Allocate an MDL and invoke the 00942 // memory management routine to lock the buffer into memory. This is 00943 // done using an exception handler that will perform cleanup if the 00944 // operation fails. 00945 // 00946 00947 mdl = (PMDL) NULL; 00948 00949 if (Length) { 00950 try { 00951 00952 // 00953 // Allocate an MDL, charging quota for it, and hang it off of the 00954 // IRP. Probe and lock the pages associated with the caller's 00955 // buffer for read access and fill in the MDL with the PFNs of those 00956 // pages. 00957 // 00958 00959 mdl = IoAllocateMdl( Buffer, Length, FALSE, TRUE, irp ); 00960 if (mdl == NULL) { 00961 ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES ); 00962 } 00963 MmProbeAndLockPages( mdl, requestorMode, IoReadAccess ); 00964 00965 } except(EXCEPTION_EXECUTE_HANDLER) { 00966 00967 // 00968 // An exception was incurred while either probing the caller's 00969 // buffer or allocating the MDL. Determine what actually happened, 00970 // clean everything up, and return an appropriate error status code. 00971 // 00972 00973 IopExceptionCleanup( fileObject, 00974 irp, 00975 (PKEVENT) NULL, 00976 event ); 00977 00978 return GetExceptionCode(); 00979 00980 } 00981 } 00982 00983 } else { 00984 00985 // 00986 // Pass the address of the user's buffer so the driver has access to 00987 // it. It is now the driver's responsibility to do everything. 00988 // 00989 00990 irp->UserBuffer = Buffer; 00991 00992 } 00993 00994 // 00995 // Copy the caller's parameters to the service-specific portion of the 00996 // IRP. 00997 // 00998 00999 irpSp->Parameters.SetEa.Length = Length; 01000 01001 01002 // 01003 // Queue the packet, call the driver, and synchronize appopriately with 01004 // I/O completion. 01005 // 01006 01007 status = IopSynchronousServiceTail( deviceObject, 01008 irp, 01009 fileObject, 01010 FALSE, 01011 requestorMode, 01012 synchronousIo, 01013 OtherTransfer ); 01014 01015 // 01016 // If the file for this operation was not opened for synchronous I/O, then 01017 // synchronization of completion of the I/O operation has not yet occurred 01018 // since the allocated event must be used for synchronous APIs on files 01019 // opened for asynchronous I/O. Synchronize the completion of the I/O 01020 // operation now. 01021 // 01022 01023 if (!synchronousIo) { 01024 01025 status = IopSynchronousApiServiceTail( status, 01026 event, 01027 irp, 01028 requestorMode, 01029 &localIoStatus, 01030 IoStatusBlock ); 01031 } 01032 01033 return status; 01034 }

Generated on Sat May 15 19:41:33 2004 for test by doxygen 1.3.7