Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1038 lines
34 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. qsea.c
  5. Abstract:
  6. This module contains the code to implement the NtQueryEaFile and the
  7. NtSetEaFile system services for the NT I/O system.
  8. Author:
  9. Darryl E. Havens (darrylh) 20-Jun-1989
  10. Environment:
  11. Kernel mode only
  12. Revision History:
  13. --*/
  14. #include "iomgr.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, NtQueryEaFile)
  17. #pragma alloc_text(PAGE, NtSetEaFile)
  18. #endif
  19. NTSTATUS
  20. NtQueryEaFile(
  21. IN HANDLE FileHandle,
  22. OUT PIO_STATUS_BLOCK IoStatusBlock,
  23. OUT PVOID Buffer,
  24. IN ULONG Length,
  25. IN BOOLEAN ReturnSingleEntry,
  26. IN PVOID EaList OPTIONAL,
  27. IN ULONG EaListLength,
  28. IN PULONG EaIndex OPTIONAL,
  29. IN BOOLEAN RestartScan
  30. )
  31. /*++
  32. Routine Description:
  33. This service returns the Extended Attributes (EAs) associated with the
  34. file specified by the FileHandle parameter. The amount of information
  35. returned is based on the size of the EAs, and the size of the buffer.
  36. That is, either all of the EAs are written to the buffer, or the buffer
  37. is filled with complete EAs if the buffer is not large enough to contain
  38. all of the EAs. Only complete EAs are ever written to the buffer; no
  39. partial EAs will ever be returned.
  40. Arguments:
  41. FileHandle - Supplies a handle to the file for which the EAs are returned.
  42. IoStatusBlock - Address of the caller's I/O status block.
  43. Buffer - Supplies a buffer to receive the EAs for the file.
  44. Length - Supplies the length, in bytes, of the buffer.
  45. ReturnSingleEntry - Indicates that only a single entry should be returned
  46. rather than filling the buffer with as many EAs as possible.
  47. EaList - Optionally supplies a list of EA names whose values are returned.
  48. EaListLength - Supplies the length of the EA list, if an EA list was
  49. specified.
  50. EaIndex - Supplies the optional index of an EA whose value is to be
  51. returned. If specified, then only that EA is returned.
  52. RestartScan - Indicates whether the scan of the EAs should be restarted
  53. from the beginning.
  54. Return Value:
  55. The status returned is the final completion status of the operation.
  56. --*/
  57. #define GET_OFFSET_LENGTH( CurrentEa, EaBase ) ( \
  58. (ULONG) ((PCHAR) CurrentEa - (PCHAR) EaBase) )
  59. {
  60. PIRP irp;
  61. NTSTATUS status;
  62. PFILE_OBJECT fileObject;
  63. PDEVICE_OBJECT deviceObject;
  64. PKEVENT event = (PKEVENT) NULL;
  65. PCHAR auxiliaryBuffer = (PCHAR) NULL;
  66. BOOLEAN eaListPresent = FALSE;
  67. ULONG eaIndexValue = 0L;
  68. KPROCESSOR_MODE requestorMode;
  69. PIO_STACK_LOCATION irpSp;
  70. IO_STATUS_BLOCK localIoStatus;
  71. BOOLEAN synchronousIo;
  72. PETHREAD CurrentThread;
  73. PAGED_CODE();
  74. //
  75. // Get the previous mode; i.e., the mode of the caller.
  76. //
  77. CurrentThread = PsGetCurrentThread ();
  78. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  79. if (requestorMode != KernelMode) {
  80. //
  81. // The caller's access mode is not kernel so probe each of the arguments
  82. // and capture them as necessary. If any failures occur, the condition
  83. // handler will be invoked to handle them. It will simply cleanup and
  84. // return an access violation status code back to the system service
  85. // dispatcher.
  86. //
  87. try {
  88. //
  89. // The IoStatusBlock parameter must be writeable by the caller.
  90. //
  91. ProbeForWriteIoStatus( IoStatusBlock );
  92. //
  93. // The buffer must be writeable by the caller.
  94. //
  95. ProbeForWrite( Buffer, Length, sizeof( ULONG ) );
  96. //
  97. // If the optional EaIndex parameter was specified, then it must be
  98. // readable by the caller. Capture its value.
  99. //
  100. if (ARGUMENT_PRESENT( EaIndex )) {
  101. eaIndexValue = ProbeAndReadUlong( EaIndex );
  102. }
  103. //
  104. // If the optional EaList parameter was specified, then it must be
  105. // readable by the caller. Validate that the buffer contains a
  106. // legal get information structure.
  107. //
  108. if (ARGUMENT_PRESENT( EaList ) && EaListLength != 0) {
  109. PFILE_GET_EA_INFORMATION eas;
  110. LONG tempLength;
  111. ULONG entrySize;
  112. eaListPresent = TRUE;
  113. ProbeForRead( EaList, EaListLength, sizeof( ULONG ) );
  114. auxiliaryBuffer = ExAllocatePoolWithQuota( NonPagedPool,
  115. EaListLength );
  116. RtlCopyMemory( auxiliaryBuffer, EaList, EaListLength );
  117. eas = (PFILE_GET_EA_INFORMATION) auxiliaryBuffer;
  118. tempLength = EaListLength;
  119. //
  120. // Walk the request buffer and ensure that its format is
  121. // valid. That is, ensure that it does not walk off the
  122. // end of the buffer that has been captured.
  123. //
  124. for (;;) {
  125. //
  126. // Get the size of the current entry in the buffer.
  127. //
  128. if (tempLength < FIELD_OFFSET( FILE_GET_EA_INFORMATION, EaName[0])) {
  129. tempLength = 0;
  130. ExFreePool( auxiliaryBuffer );
  131. auxiliaryBuffer = (PVOID) NULL;
  132. IoStatusBlock->Status = STATUS_EA_LIST_INCONSISTENT;
  133. IoStatusBlock->Information = tempLength;
  134. return STATUS_EA_LIST_INCONSISTENT;
  135. }
  136. entrySize = FIELD_OFFSET( FILE_GET_EA_INFORMATION, EaName[0] ) + eas->EaNameLength + 1;
  137. if ((ULONG) tempLength < entrySize) {
  138. tempLength = GET_OFFSET_LENGTH( eas, auxiliaryBuffer );
  139. ExFreePool( auxiliaryBuffer );
  140. auxiliaryBuffer = (PVOID) NULL;
  141. IoStatusBlock->Status = STATUS_EA_LIST_INCONSISTENT;
  142. IoStatusBlock->Information = tempLength;
  143. return STATUS_EA_LIST_INCONSISTENT;
  144. }
  145. if (eas->NextEntryOffset != 0) {
  146. //
  147. // There is another entry in the buffer and it must
  148. // be longword aligned. Ensure that the offset
  149. // indicates that it is. If it isn't, return an
  150. // invalid parameter status.
  151. //
  152. if ((((entrySize + 3) & ~3) != eas->NextEntryOffset) ||
  153. ((LONG) eas->NextEntryOffset < 0)) {
  154. tempLength = GET_OFFSET_LENGTH( eas, auxiliaryBuffer );
  155. ExFreePool( auxiliaryBuffer );
  156. auxiliaryBuffer = (PVOID) NULL;
  157. IoStatusBlock->Status = STATUS_EA_LIST_INCONSISTENT;
  158. IoStatusBlock->Information = tempLength;
  159. return STATUS_EA_LIST_INCONSISTENT;
  160. } else {
  161. //
  162. // There is another entry in the buffer, so
  163. // account for the size of the current entry
  164. // in the length and get a pointer to the next
  165. // entry.
  166. //
  167. tempLength -= eas->NextEntryOffset;
  168. if (tempLength < 0) {
  169. tempLength = GET_OFFSET_LENGTH( eas, auxiliaryBuffer );
  170. ExFreePool( auxiliaryBuffer );
  171. auxiliaryBuffer = (PVOID) NULL;
  172. IoStatusBlock->Status = STATUS_EA_LIST_INCONSISTENT;
  173. IoStatusBlock->Information = tempLength;
  174. return STATUS_EA_LIST_INCONSISTENT;
  175. }
  176. eas = (PFILE_GET_EA_INFORMATION) ((PCHAR) eas + eas->NextEntryOffset);
  177. }
  178. } else {
  179. //
  180. // There are no other entries in the buffer. Simply
  181. // account for the overall buffer length according
  182. // to the size of the current entry and exit the
  183. // loop.
  184. //
  185. tempLength -= entrySize;
  186. break;
  187. }
  188. }
  189. //
  190. // All of the entries in the buffer have been processed.
  191. // Check to see whether the overall buffer length went
  192. // negative. If so, return an error.
  193. //
  194. if (tempLength < 0) {
  195. tempLength = GET_OFFSET_LENGTH( eas, auxiliaryBuffer );
  196. ExFreePool( auxiliaryBuffer );
  197. auxiliaryBuffer = (PVOID) NULL;
  198. IoStatusBlock->Status = STATUS_EA_LIST_INCONSISTENT;
  199. IoStatusBlock->Information = tempLength;
  200. return STATUS_EA_LIST_INCONSISTENT;
  201. }
  202. }
  203. } except(EXCEPTION_EXECUTE_HANDLER) {
  204. //
  205. // An exception was incurred while probing the caller's
  206. // parameters, allocating the pool buffer, or copying the
  207. // caller's EA list to the buffer. Cleanup and return an
  208. // appropriate error status code.
  209. //
  210. if (auxiliaryBuffer != NULL) {
  211. ExFreePool( auxiliaryBuffer );
  212. }
  213. return GetExceptionCode();
  214. }
  215. } else {
  216. //
  217. // The caller's mode was KernelMode. Simply allocate pool for the
  218. // EaList, if one was specified, and copy the string to it. Also,
  219. // if an EaIndex was specified copy it as well.
  220. //
  221. if (ARGUMENT_PRESENT( EaList ) && (EaListLength != 0)) {
  222. eaListPresent = TRUE;
  223. try {
  224. auxiliaryBuffer = ExAllocatePoolWithQuota( NonPagedPool,
  225. EaListLength );
  226. } except(EXCEPTION_EXECUTE_HANDLER) {
  227. return GetExceptionCode();
  228. }
  229. RtlCopyMemory( auxiliaryBuffer, EaList, EaListLength );
  230. }
  231. if (ARGUMENT_PRESENT( EaIndex )) {
  232. eaIndexValue = *EaIndex;
  233. }
  234. }
  235. //
  236. // There were no blatant errors so far, so reference the file object so
  237. // the target device object can be found. Note that if the handle does
  238. // not refer to a file object, or if the caller does not have the required
  239. // access to the file, then it will fail.
  240. //
  241. status = ObReferenceObjectByHandle( FileHandle,
  242. FILE_READ_EA,
  243. IoFileObjectType,
  244. requestorMode,
  245. (PVOID *) &fileObject,
  246. NULL );
  247. if (!NT_SUCCESS( status )) {
  248. if (eaListPresent) {
  249. ExFreePool( auxiliaryBuffer );
  250. }
  251. return status;
  252. }
  253. //
  254. // Make a special check here to determine whether this is a synchronous
  255. // I/O operation. If it is, then wait here until the file is owned by
  256. // the current thread. If this is not a (serialized) synchronous I/O
  257. // operation, then allocate and initialize the local event.
  258. //
  259. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  260. BOOLEAN interrupted;
  261. if (!IopAcquireFastLock( fileObject )) {
  262. status = IopAcquireFileObjectLock( fileObject,
  263. requestorMode,
  264. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  265. &interrupted );
  266. if (interrupted) {
  267. if (eaListPresent) {
  268. ExFreePool( auxiliaryBuffer );
  269. }
  270. ObDereferenceObject( fileObject );
  271. return status;
  272. }
  273. }
  274. synchronousIo = TRUE;
  275. } else {
  276. //
  277. // This is a synchronous API being invoked for a file that is opened
  278. // for asynchronous I/O. This means that this system service is
  279. // to synchronize the completion of the operation before returning
  280. // to the caller. A local event is used to do this.
  281. //
  282. event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
  283. if (event == NULL) {
  284. if (eaListPresent) {
  285. ExFreePool( auxiliaryBuffer );
  286. }
  287. ObDereferenceObject( fileObject );
  288. return STATUS_INSUFFICIENT_RESOURCES;
  289. }
  290. KeInitializeEvent( event, SynchronizationEvent, FALSE );
  291. synchronousIo = FALSE;
  292. }
  293. //
  294. // Set the file object to the Not-Signaled state.
  295. //
  296. KeClearEvent( &fileObject->Event );
  297. //
  298. // Get the address of the target device object.
  299. //
  300. deviceObject = IoGetRelatedDeviceObject( fileObject );
  301. //
  302. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  303. // The allocation is performed with an exception handler in case the
  304. // caller does not have enough quota to allocate the packet.
  305. irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
  306. if (!irp) {
  307. //
  308. // An IRP could not be allocated. Cleanup and return an appropriate
  309. // error status code.
  310. //
  311. if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  312. ExFreePool( event );
  313. }
  314. IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
  315. if (eaListPresent) {
  316. ExFreePool( auxiliaryBuffer );
  317. }
  318. return STATUS_INSUFFICIENT_RESOURCES;
  319. }
  320. irp->Tail.Overlay.OriginalFileObject = fileObject;
  321. irp->Tail.Overlay.Thread = CurrentThread;
  322. irp->RequestorMode = requestorMode;
  323. //
  324. // Fill in the service independent parameters in the IRP.
  325. //
  326. if (synchronousIo) {
  327. irp->UserEvent = (PKEVENT) NULL;
  328. irp->UserIosb = IoStatusBlock;
  329. } else {
  330. irp->UserEvent = event;
  331. irp->UserIosb = &localIoStatus;
  332. irp->Flags = IRP_SYNCHRONOUS_API;
  333. }
  334. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  335. //
  336. // Get a pointer to the stack location for the first driver. This will be
  337. // used to pass the original function codes and parameters.
  338. //
  339. irpSp = IoGetNextIrpStackLocation( irp );
  340. irpSp->MajorFunction = IRP_MJ_QUERY_EA;
  341. irpSp->FileObject = fileObject;
  342. //
  343. // If the caller specified an EA list of names to be queried, then pass
  344. // the address of the intermediary buffer containing the list to the
  345. // driver.
  346. //
  347. if (eaListPresent) {
  348. irp->Tail.Overlay.AuxiliaryBuffer = auxiliaryBuffer;
  349. irpSp->Parameters.QueryEa.EaList = auxiliaryBuffer;
  350. irpSp->Parameters.QueryEa.EaListLength = EaListLength;
  351. }
  352. //
  353. // Now determine whether this driver expects to have data buffered
  354. // to it or whether it performs direct I/O. This is based on the
  355. // DO_BUFFERED_IO flag in the device object. If the flag is set,
  356. // then a system buffer is allocated and the driver's data will be
  357. // copied to it. If the DO_DIRECT_IO flag is set in the device
  358. // object, then a Memory Descriptor List (MDL) is allocated and
  359. // the caller's buffer is locked down using it. Finally, if the
  360. // driver specifies neither of the flags, then simply pass the
  361. // address and length of the buffer and allow the driver to perform
  362. // all of the checking and buffering if any is required.
  363. //
  364. if (deviceObject->Flags & DO_BUFFERED_IO) {
  365. //
  366. // The driver wishes the caller's buffered be copied into an
  367. // intermediary buffer. Allocate the system buffer and specify
  368. // that it should be deallocated on completion. Also indicate
  369. // that this is an input operation so the data will be copied
  370. // into the caller's buffer. This is done using an exception
  371. // handler that will perform cleanup if the operation fails.
  372. //
  373. if (Length) {
  374. try {
  375. //
  376. // Allocate the intermediary system buffer from nonpaged
  377. // pool and charge quota for it.
  378. //
  379. irp->AssociatedIrp.SystemBuffer =
  380. ExAllocatePoolWithQuota( NonPagedPool, Length );
  381. } except(EXCEPTION_EXECUTE_HANDLER) {
  382. //
  383. // An exception was incurred while either probing the
  384. // caller's buffer or allocating the system buffer.
  385. // Determine what actually happened, clean everything
  386. // up, and return an appropriate error status code.
  387. //
  388. IopExceptionCleanup( fileObject,
  389. irp,
  390. (PKEVENT) NULL,
  391. event );
  392. if (auxiliaryBuffer != NULL) {
  393. ExFreePool( auxiliaryBuffer );
  394. }
  395. return GetExceptionCode();
  396. }
  397. //
  398. // Remember the address of the caller's buffer so the copy can
  399. // take place during I/O completion. Also, set the flags so
  400. // that the completion code knows to do the copy and to deallocate
  401. // the buffer.
  402. //
  403. irp->UserBuffer = Buffer;
  404. irp->Flags |= (ULONG) (IRP_BUFFERED_IO |
  405. IRP_DEALLOCATE_BUFFER |
  406. IRP_INPUT_OPERATION);
  407. } else {
  408. //
  409. // This is a zero-length request. Simply indicate that this is
  410. // buffered I/O, and pass along the request. The buffer will
  411. // not be set to deallocate so the completion path does not
  412. // have to special-case the length.
  413. //
  414. irp->AssociatedIrp.SystemBuffer = NULL;
  415. irp->Flags |= (ULONG) (IRP_BUFFERED_IO | IRP_INPUT_OPERATION);
  416. }
  417. } else if (deviceObject->Flags & DO_DIRECT_IO) {
  418. PMDL mdl;
  419. //
  420. // This is a direct I/O operation. Allocate an MDL and invoke
  421. // the memory management routine to lock the buffer into memory.
  422. // This is done using an exception handler that will perform
  423. // cleanup if the operation fails.
  424. //
  425. if (Length) {
  426. mdl = (PMDL) NULL;
  427. try {
  428. //
  429. // Allocate an MDL, charging quota for it, and hang it off
  430. // of the IRP. Probe and lock the pages associated with
  431. // the caller's buffer for write access and fill in the MDL
  432. // with the PFNs of those pages.
  433. //
  434. mdl = IoAllocateMdl( Buffer, Length, FALSE, TRUE, irp );
  435. if (mdl == NULL) {
  436. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  437. }
  438. MmProbeAndLockPages( mdl, requestorMode, IoWriteAccess );
  439. } except(EXCEPTION_EXECUTE_HANDLER) {
  440. //
  441. // An exception was incurred while either probing the
  442. // caller's buffer or allocating the MDL. Determine what
  443. // actually happened, clean everything up, and return an
  444. // appropriate error status code.
  445. //
  446. IopExceptionCleanup( fileObject,
  447. irp,
  448. (PKEVENT) NULL,
  449. event );
  450. if (auxiliaryBuffer != NULL) {
  451. ExFreePool( auxiliaryBuffer );
  452. }
  453. return GetExceptionCode();
  454. }
  455. }
  456. } else {
  457. //
  458. // Pass the address of the user's buffer so the driver has access
  459. // to it. It is now the driver's responsibility to do everything.
  460. //
  461. irp->UserBuffer = Buffer;
  462. }
  463. //
  464. // Copy the caller's parameters to the service-specific portion of the
  465. // IRP.
  466. //
  467. irpSp->Parameters.QueryEa.Length = Length;
  468. irpSp->Parameters.QueryEa.EaIndex = eaIndexValue;
  469. irpSp->Flags = 0;
  470. if (RestartScan) {
  471. irpSp->Flags = SL_RESTART_SCAN;
  472. }
  473. if (ReturnSingleEntry) {
  474. irpSp->Flags |= SL_RETURN_SINGLE_ENTRY;
  475. }
  476. if (ARGUMENT_PRESENT( EaIndex )) {
  477. irpSp->Flags |= SL_INDEX_SPECIFIED;
  478. }
  479. //
  480. // Queue the packet, call the driver, and synchronize appopriately with
  481. // I/O completion.
  482. //
  483. status = IopSynchronousServiceTail( deviceObject,
  484. irp,
  485. fileObject,
  486. FALSE,
  487. requestorMode,
  488. synchronousIo,
  489. OtherTransfer );
  490. //
  491. // If the file for this operation was not opened for synchronous I/O, then
  492. // synchronization of completion of the I/O operation has not yet occurred
  493. // since the allocated event must be used for synchronous APIs on files
  494. // opened for asynchronous I/O. Synchronize the completion of the I/O
  495. // operation now.
  496. //
  497. if (!synchronousIo) {
  498. status = IopSynchronousApiServiceTail( status,
  499. event,
  500. irp,
  501. requestorMode,
  502. &localIoStatus,
  503. IoStatusBlock );
  504. }
  505. return status;
  506. }
  507. NTSTATUS
  508. NtSetEaFile(
  509. IN HANDLE FileHandle,
  510. OUT PIO_STATUS_BLOCK IoStatusBlock,
  511. IN PVOID Buffer,
  512. IN ULONG Length
  513. )
  514. /*++
  515. Routine Description:
  516. This service replaces the Extended Attributes (EAs) associated with the file
  517. specified by the FileHandle parameter. All of the EAs associated with the
  518. file are replaced by the EAs in the specified buffer.
  519. Arguments:
  520. FileHandle - Supplies a handle to the file whose EAs should be changed.
  521. IoStatusBlock - Address of the caller's I/O status block.
  522. FileInformation - Supplies a buffer containing the new EAs which should be
  523. used to replace the EAs currently associated with the file.
  524. Length - Supplies the length, in bytes, of the buffer.
  525. Return Value:
  526. The status returned is the final completion status of the operation.
  527. --*/
  528. {
  529. PIRP irp;
  530. NTSTATUS status;
  531. PFILE_OBJECT fileObject;
  532. PDEVICE_OBJECT deviceObject;
  533. PKEVENT event = (PKEVENT) NULL;
  534. KPROCESSOR_MODE requestorMode;
  535. PIO_STACK_LOCATION irpSp;
  536. IO_STATUS_BLOCK localIoStatus;
  537. BOOLEAN synchronousIo;
  538. PETHREAD CurrentThread;
  539. PAGED_CODE();
  540. //
  541. // Get the previous mode; i.e., the mode of the caller.
  542. //
  543. CurrentThread = PsGetCurrentThread ();
  544. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  545. if (requestorMode != KernelMode) {
  546. //
  547. // The caller's access mode is user, so probe each of the arguments
  548. // and capture them as necessary. If any failures occur, the condition
  549. // handler will be invoked to handle them. It will simply cleanup and
  550. // return an access violation status code back to the system service
  551. // dispatcher.
  552. //
  553. try {
  554. //
  555. // The IoStatusBlock parameter must be writeable by the caller.
  556. //
  557. ProbeForWriteIoStatus( IoStatusBlock );
  558. //
  559. // The Buffer parameter must be readable by the caller.
  560. //
  561. ProbeForRead( Buffer, Length, sizeof( ULONG ) );
  562. } except(EXCEPTION_EXECUTE_HANDLER) {
  563. //
  564. // An exception was incurred while probing the caller's parameters.
  565. // Cleanup and return an appropriate error status code.
  566. //
  567. return GetExceptionCode();
  568. }
  569. }
  570. //
  571. // There were no blatant errors so far, so reference the file object so
  572. // the target device object can be found. Note that if the handle does
  573. // not refer to a file object, or if the caller does not have the required
  574. // access to the file, then it will fail.
  575. //
  576. status = ObReferenceObjectByHandle( FileHandle,
  577. FILE_WRITE_EA,
  578. IoFileObjectType,
  579. requestorMode,
  580. (PVOID *) &fileObject,
  581. NULL );
  582. if (!NT_SUCCESS( status )) {
  583. return status;
  584. }
  585. //
  586. // Make a special check here to determine whether this is a synchronous
  587. // I/O operation. If it is, then wait here until the file is owned by
  588. // the current thread. If this is not a (serialized) synchronous I/O
  589. // operation, then allocate and initialize the local event.
  590. //
  591. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  592. BOOLEAN interrupted;
  593. if (!IopAcquireFastLock( fileObject )) {
  594. status = IopAcquireFileObjectLock( fileObject,
  595. requestorMode,
  596. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  597. &interrupted );
  598. if (interrupted) {
  599. ObDereferenceObject( fileObject );
  600. return status;
  601. }
  602. }
  603. synchronousIo = TRUE;
  604. } else {
  605. //
  606. // This is a synchronous API being invoked for a file that is opened
  607. // for asynchronous I/O. This means that this system service is
  608. // to synchronize the completion of the operation before returning
  609. // to the caller. A local event is used to do this.
  610. //
  611. event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
  612. if (event == NULL) {
  613. ObDereferenceObject( fileObject );
  614. return STATUS_INSUFFICIENT_RESOURCES;
  615. }
  616. KeInitializeEvent( event, SynchronizationEvent, FALSE );
  617. synchronousIo = FALSE;
  618. }
  619. //
  620. // Set the file object to the Not-Signaled state.
  621. //
  622. KeClearEvent( &fileObject->Event );
  623. //
  624. // Get the address of the target device object.
  625. //
  626. deviceObject = IoGetRelatedDeviceObject( fileObject );
  627. //
  628. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  629. // The allocation is performed with an exception handler in case the
  630. // caller does not have enough quota to allocate the packet.
  631. irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
  632. if (!irp) {
  633. //
  634. // An IRP could not be allocated. Cleanup and return an appropriate
  635. // error status code.
  636. //
  637. if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  638. ExFreePool( event );
  639. }
  640. IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
  641. return STATUS_INSUFFICIENT_RESOURCES;
  642. }
  643. irp->Tail.Overlay.OriginalFileObject = fileObject;
  644. irp->Tail.Overlay.Thread = CurrentThread;
  645. irp->RequestorMode = requestorMode;
  646. //
  647. // Fill in the service independent parameters in the IRP.
  648. //
  649. if (synchronousIo) {
  650. irp->UserEvent = (PKEVENT) NULL;
  651. irp->UserIosb = IoStatusBlock;
  652. } else {
  653. irp->UserEvent = event;
  654. irp->UserIosb = &localIoStatus;
  655. irp->Flags = IRP_SYNCHRONOUS_API;
  656. }
  657. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  658. //
  659. // Get a pointer to the stack location for the first driver. This will be
  660. // used to pass the original function codes and parameters.
  661. //
  662. irpSp = IoGetNextIrpStackLocation( irp );
  663. irpSp->MajorFunction = IRP_MJ_SET_EA;
  664. irpSp->FileObject = fileObject;
  665. //
  666. // Now determine whether this driver expects to have data buffered to it
  667. // or whether it performs direct I/O. This is based on the DO_BUFFERED_IO
  668. // flag in the device object. if the flag is set, then a system buffer is
  669. // allocated and driver's data is copied to it. If the DO_DIRECT_IO flag
  670. // is set in the device object, then a Memory Descriptor List (MDL) is
  671. // allocated and the caller's buffer is locked down using it. Finally, if
  672. // the driver specifies neither of the flags, then simply pass the address
  673. // and length of the buffer and allow the driver to perform all of the
  674. // checking and buffering if any is required.
  675. //
  676. if (deviceObject->Flags & DO_BUFFERED_IO) {
  677. PFILE_FULL_EA_INFORMATION systemBuffer;
  678. ULONG errorOffset;
  679. //
  680. // The driver wishes the caller's buffer to be copied into an
  681. // intermediary buffer. Allocate the system buffer and specify
  682. // that it should be deallocated on completion. Also check to
  683. // ensure that the caller's EA list is valid. All of this is
  684. // performed within an exception handler that will perform
  685. // cleanup if the operation fails.
  686. //
  687. if (Length) {
  688. try {
  689. //
  690. // Allocate the intermediary system buffer and charge the caller
  691. // quota for its allocation. Copy the caller's EA buffer into the
  692. // buffer and check to ensure that it is valid.
  693. //
  694. systemBuffer = ExAllocatePoolWithQuota( NonPagedPool, Length );
  695. irp->AssociatedIrp.SystemBuffer = systemBuffer;
  696. RtlCopyMemory( systemBuffer, Buffer, Length );
  697. status = IoCheckEaBufferValidity( systemBuffer,
  698. Length,
  699. &errorOffset );
  700. if (!NT_SUCCESS( status )) {
  701. IoStatusBlock->Status = status;
  702. IoStatusBlock->Information = errorOffset;
  703. ExRaiseStatus( status );
  704. }
  705. } except(EXCEPTION_EXECUTE_HANDLER) {
  706. //
  707. // An exception was incurred while allocating the buffer, copying
  708. // the caller's data into it, or walking the EA buffer. Determine
  709. // what happened, cleanup, and return an appropriate error status
  710. // code.
  711. //
  712. IopExceptionCleanup( fileObject,
  713. irp,
  714. (PKEVENT) NULL,
  715. event );
  716. return GetExceptionCode();
  717. }
  718. //
  719. // Set the flags so that the completion code knows to deallocate the
  720. // buffer.
  721. //
  722. irp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  723. } else {
  724. irp->AssociatedIrp.SystemBuffer = NULL;
  725. }
  726. } else if (deviceObject->Flags & DO_DIRECT_IO) {
  727. PMDL mdl;
  728. //
  729. // This is a direct I/O operation. Allocate an MDL and invoke the
  730. // memory management routine to lock the buffer into memory. This is
  731. // done using an exception handler that will perform cleanup if the
  732. // operation fails.
  733. //
  734. mdl = (PMDL) NULL;
  735. if (Length) {
  736. try {
  737. //
  738. // Allocate an MDL, charging quota for it, and hang it off of the
  739. // IRP. Probe and lock the pages associated with the caller's
  740. // buffer for read access and fill in the MDL with the PFNs of those
  741. // pages.
  742. //
  743. mdl = IoAllocateMdl( Buffer, Length, FALSE, TRUE, irp );
  744. if (mdl == NULL) {
  745. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  746. }
  747. MmProbeAndLockPages( mdl, requestorMode, IoReadAccess );
  748. } except(EXCEPTION_EXECUTE_HANDLER) {
  749. //
  750. // An exception was incurred while either probing the caller's
  751. // buffer or allocating the MDL. Determine what actually happened,
  752. // clean everything up, and return an appropriate error status code.
  753. //
  754. IopExceptionCleanup( fileObject,
  755. irp,
  756. (PKEVENT) NULL,
  757. event );
  758. return GetExceptionCode();
  759. }
  760. }
  761. } else {
  762. //
  763. // Pass the address of the user's buffer so the driver has access to
  764. // it. It is now the driver's responsibility to do everything.
  765. //
  766. irp->UserBuffer = Buffer;
  767. }
  768. //
  769. // Copy the caller's parameters to the service-specific portion of the
  770. // IRP.
  771. //
  772. irpSp->Parameters.SetEa.Length = Length;
  773. //
  774. // Queue the packet, call the driver, and synchronize appopriately with
  775. // I/O completion.
  776. //
  777. status = IopSynchronousServiceTail( deviceObject,
  778. irp,
  779. fileObject,
  780. FALSE,
  781. requestorMode,
  782. synchronousIo,
  783. OtherTransfer );
  784. //
  785. // If the file for this operation was not opened for synchronous I/O, then
  786. // synchronization of completion of the I/O operation has not yet occurred
  787. // since the allocated event must be used for synchronous APIs on files
  788. // opened for asynchronous I/O. Synchronize the completion of the I/O
  789. // operation now.
  790. //
  791. if (!synchronousIo) {
  792. status = IopSynchronousApiServiceTail( status,
  793. event,
  794. irp,
  795. requestorMode,
  796. &localIoStatus,
  797. IoStatusBlock );
  798. }
  799. return status;
  800. }