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.

965 lines
30 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. qsfs.c
  5. Abstract:
  6. This module contains the code to implement the NtQueryVolumeInformationFile
  7. and NtSetVolumeInformationFile system services for the NT I/O system.
  8. Author:
  9. Darryl E. Havens (darrylh) 22-Jun-1989
  10. Environment:
  11. Kernel mode only
  12. Revision History:
  13. --*/
  14. #include "iomgr.h"
  15. #pragma hdrstop
  16. #include <ioevent.h>
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE, NtQueryVolumeInformationFile)
  19. #pragma alloc_text(PAGE, NtSetVolumeInformationFile)
  20. #endif
  21. NTSTATUS
  22. NtQueryVolumeInformationFile(
  23. IN HANDLE FileHandle,
  24. OUT PIO_STATUS_BLOCK IoStatusBlock,
  25. OUT PVOID FsInformation,
  26. IN ULONG Length,
  27. IN FS_INFORMATION_CLASS FsInformationClass
  28. )
  29. /*++
  30. Routine Description:
  31. This service returns information about the volume associated with the
  32. FileHandle parameter. The information returned in the buffer is defined
  33. by the FsInformationClass parameter. The legal values for this parameter
  34. are as follows:
  35. o FileFsVolumeInformation
  36. o FileFsSizeInformation
  37. o FileFsDeviceInformation
  38. o FileFsAttributeInformation
  39. Arguments:
  40. FileHandle - Supplies a handle to an open volume, directory, or file
  41. for which information about the volume is returned.
  42. IoStatusBlock - Address of the caller's I/O status block.
  43. FsInformation - Supplies a buffer to receive the requested information
  44. returned about the volume.
  45. Length - Supplies the length, in bytes, of the FsInformation buffer.
  46. FsInformationClass - Specifies the type of information which should be
  47. returned about the volume.
  48. Return Value:
  49. The status returned is the final completion status of the operation.
  50. --*/
  51. {
  52. PIRP irp;
  53. NTSTATUS status;
  54. PFILE_OBJECT fileObject;
  55. PDEVICE_OBJECT deviceObject;
  56. PKEVENT event = (PKEVENT) NULL;
  57. KPROCESSOR_MODE requestorMode;
  58. PIO_STACK_LOCATION irpSp;
  59. IO_STATUS_BLOCK localIoStatus;
  60. BOOLEAN synchronousIo;
  61. PETHREAD CurrentThread;
  62. PAGED_CODE();
  63. //
  64. // Get the previous mode; i.e., the mode of the caller.
  65. //
  66. CurrentThread = PsGetCurrentThread ();
  67. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  68. if (requestorMode != KernelMode) {
  69. //
  70. // Ensure that the FsInformationClass parameter is legal for querying
  71. // information about the volume.
  72. //
  73. if ((ULONG) FsInformationClass >= FileFsMaximumInformation ||
  74. IopQueryFsOperationLength[FsInformationClass] == 0) {
  75. return STATUS_INVALID_INFO_CLASS;
  76. }
  77. //
  78. // Finally, ensure that the supplied buffer is large enough to contain
  79. // the information associated with the specified query operation that
  80. // is to be performed.
  81. //
  82. if (Length < (ULONG) IopQueryFsOperationLength[FsInformationClass]) {
  83. return STATUS_INFO_LENGTH_MISMATCH;
  84. }
  85. //
  86. // The caller's access mode is not kernel so probe each of the arguments
  87. // and capture them as necessary. If any failures occur, the condition
  88. // handler will be invoked to handle them. It will simply cleanup and
  89. // return an access violation status code back to the system service
  90. // dispatcher.
  91. //
  92. try {
  93. //
  94. // The IoStatusBlock parameter must be writeable by the caller.
  95. //
  96. ProbeForWriteIoStatus( IoStatusBlock );
  97. //
  98. // The FsInformation buffer must be writeable by the caller.
  99. //
  100. #if defined(_X86_)
  101. ProbeForWrite( FsInformation, Length, sizeof( ULONG ) );
  102. #elif defined(_WIN64)
  103. //
  104. // If we are a wow64 process, follow the X86 rules
  105. //
  106. if (PsGetCurrentProcessByThread(CurrentThread)->Wow64Process) {
  107. ProbeForWrite( FsInformation, Length, sizeof( ULONG ) );
  108. } else {
  109. ProbeForWrite( FsInformation,
  110. Length,
  111. IopQuerySetFsAlignmentRequirement[FsInformationClass] );
  112. }
  113. #else
  114. ProbeForWrite( FsInformation,
  115. Length,
  116. IopQuerySetFsAlignmentRequirement[FsInformationClass] );
  117. #endif
  118. } except(EXCEPTION_EXECUTE_HANDLER) {
  119. //
  120. // An exception was incurred probing the caller's parameters.
  121. // Simply return an appropriate error status code.
  122. //
  123. return GetExceptionCode();
  124. }
  125. }
  126. //
  127. // There were no blatant errors so far, so reference the file object so
  128. // the target device object can be found. Note that if the handle does
  129. // not refer to a file object, or if the caller does not have the required
  130. // access to the file, then it will fail.
  131. //
  132. status = ObReferenceObjectByHandle( FileHandle,
  133. IopQueryFsOperationAccess[FsInformationClass],
  134. IoFileObjectType,
  135. requestorMode,
  136. (PVOID *) &fileObject,
  137. NULL );
  138. if (!NT_SUCCESS( status )) {
  139. return status;
  140. }
  141. //
  142. // If this open file object represents an open device that was explicitly
  143. // opened for querying the device's attributes, then ensure that the type
  144. // of information class was device information.
  145. //
  146. if ((fileObject->Flags & FO_DIRECT_DEVICE_OPEN) &&
  147. FsInformationClass != FileFsDeviceInformation) {
  148. ObDereferenceObject( fileObject );
  149. return STATUS_INVALID_DEVICE_REQUEST;
  150. }
  151. //
  152. // Make a special check here to determine whether this is a synchronous
  153. // I/O operation. If it is, then wait here until the file is owned by
  154. // the current thread. If this is not a (serialized) synchronous I/O
  155. // operation, then allocate and initialize the local event.
  156. //
  157. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  158. BOOLEAN interrupted;
  159. if (!IopAcquireFastLock( fileObject )) {
  160. status = IopAcquireFileObjectLock( fileObject,
  161. requestorMode,
  162. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  163. &interrupted );
  164. if (interrupted) {
  165. ObDereferenceObject( fileObject );
  166. return status;
  167. }
  168. }
  169. synchronousIo = TRUE;
  170. } else {
  171. synchronousIo = FALSE;
  172. }
  173. //
  174. // Get the address of the target device object. A special check is made
  175. // here to determine whether this query is for device information. If
  176. // it is, and either:
  177. //
  178. // a) The open was for the device itself, or
  179. //
  180. // b) The open was for a file but this is not a redirected device,
  181. //
  182. // then perform the query operation in-line. That is, do not allocate
  183. // an IRP and call the driver, rather, simply copy the device type and
  184. // characteristics information from the target device object pointed
  185. // to by the device object in the file object (the "real" device object
  186. // in a mass storage device stack).
  187. //
  188. if (FsInformationClass == FileFsDeviceInformation &&
  189. (fileObject->Flags & FO_DIRECT_DEVICE_OPEN ||
  190. fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM)) {
  191. PFILE_FS_DEVICE_INFORMATION deviceAttributes;
  192. BOOLEAN deviceMounted = FALSE;
  193. //
  194. // This query operation can be performed in-line. Simply copy the
  195. // information directly from the target device object and indicate
  196. // that the operation was successful. Begin, however, by determining
  197. // whether or not the device is mounted. This cannot be done at the
  198. // same time as attempting to touch the user's buffer, as looking at
  199. // the mounted bit occurs at raised IRQL.
  200. //
  201. deviceObject = fileObject->DeviceObject;
  202. if (deviceObject->Vpb) {
  203. deviceMounted = IopGetMountFlag( deviceObject );
  204. }
  205. //
  206. // Copy the characteristics information from the device's object
  207. // into the caller's buffer.
  208. //
  209. deviceAttributes = (PFILE_FS_DEVICE_INFORMATION) FsInformation;
  210. try {
  211. deviceAttributes->DeviceType = deviceObject->DeviceType;
  212. deviceAttributes->Characteristics = deviceObject->Characteristics;
  213. if (deviceMounted) {
  214. deviceAttributes->Characteristics |= FILE_DEVICE_IS_MOUNTED;
  215. }
  216. IoStatusBlock->Status = STATUS_SUCCESS;
  217. IoStatusBlock->Information = sizeof( FILE_FS_DEVICE_INFORMATION );
  218. status = STATUS_SUCCESS;
  219. } except( EXCEPTION_EXECUTE_HANDLER ) {
  220. //
  221. // An error occurred attempting to write into one of the caller's
  222. // buffers. Simply indicate that the error occurred, and fall
  223. // through.
  224. //
  225. status = GetExceptionCode();
  226. }
  227. //
  228. // If this operation was performed as synchronous I/O, then release
  229. // the file object lock.
  230. //
  231. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  232. IopReleaseFileObjectLock( fileObject );
  233. }
  234. //
  235. // Now simply cleanup and return the final status of the operation.
  236. //
  237. ObDereferenceObject( fileObject );
  238. return status;
  239. }
  240. if (FsInformationClass == FileFsDriverPathInformation) {
  241. PFILE_FS_DRIVER_PATH_INFORMATION systemBuffer = NULL;
  242. PFILE_FS_DRIVER_PATH_INFORMATION userBuffer = FsInformation;
  243. try {
  244. systemBuffer = ExAllocatePoolWithQuota( NonPagedPool, Length );
  245. RtlCopyMemory( systemBuffer,
  246. userBuffer,
  247. Length );
  248. status = IopGetDriverPathInformation(fileObject, systemBuffer, Length);
  249. if (!NT_SUCCESS(status)) {
  250. ExRaiseStatus(status);
  251. }
  252. userBuffer->DriverInPath = systemBuffer->DriverInPath;
  253. ExFreePool(systemBuffer);
  254. IoStatusBlock->Status = STATUS_SUCCESS;
  255. IoStatusBlock->Information = sizeof( FILE_FS_DRIVER_PATH_INFORMATION );
  256. } except(EXCEPTION_EXECUTE_HANDLER) {
  257. //
  258. // An exception was incurred while allocating the intermediary
  259. // system buffer or while copying the caller's data into the
  260. // buffer. Cleanup and return an appropriate error status code.
  261. //
  262. status = GetExceptionCode();
  263. if (systemBuffer) {
  264. ExFreePool(systemBuffer);
  265. }
  266. }
  267. //
  268. // If this operation was performed as synchronous I/O, then release
  269. // the file object lock.
  270. //
  271. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  272. IopReleaseFileObjectLock( fileObject );
  273. }
  274. ObDereferenceObject( fileObject);
  275. return status;
  276. }
  277. //
  278. // This is either a query that is not for device characteristics
  279. // information, or it is a query for device information, but it is
  280. // a query for a redirected device. Take the long route and actually
  281. // invoke the driver for the target device to get the information.
  282. //
  283. // Set the file object to the Not-Signaled state.
  284. //
  285. KeClearEvent( &fileObject->Event );
  286. //
  287. // Get a pointer to the device object for the target device.
  288. //
  289. deviceObject = IoGetRelatedDeviceObject( fileObject );
  290. //
  291. // If this I/O operation is not being performed as synchronous I/O,
  292. // then allocate an event that will be used to synchronize the
  293. // completion of this operation. That is, this system service is
  294. // a synchronous API being invoked for a file that is opened for
  295. // asynchronous I/O.
  296. //
  297. if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  298. event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
  299. if (event == NULL) {
  300. ObDereferenceObject( fileObject );
  301. return STATUS_INSUFFICIENT_RESOURCES;
  302. }
  303. KeInitializeEvent( event, SynchronizationEvent, FALSE );
  304. }
  305. //
  306. // Allocate and initialize the I/O Request Packet (IRP) for this
  307. // operation. The allocation is performed with an exception handler
  308. // in case the caller does not have enough quota to allocate the packet.
  309. irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
  310. if (!irp) {
  311. //
  312. // An IRP could not be allocated. Cleanup and return an
  313. // appropriate error status code.
  314. //
  315. if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  316. ExFreePool( event );
  317. }
  318. IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
  319. return STATUS_INSUFFICIENT_RESOURCES;
  320. }
  321. irp->Tail.Overlay.OriginalFileObject = fileObject;
  322. irp->Tail.Overlay.Thread = CurrentThread;
  323. irp->RequestorMode = requestorMode;
  324. //
  325. // Fill in the service independent parameters in the IRP.
  326. //
  327. if (synchronousIo) {
  328. irp->UserEvent = (PKEVENT) NULL;
  329. irp->UserIosb = IoStatusBlock;
  330. } else {
  331. irp->UserEvent = event;
  332. irp->UserIosb = &localIoStatus;
  333. irp->Flags = IRP_SYNCHRONOUS_API;
  334. }
  335. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  336. //
  337. // Get a pointer to the stack location for the first driver. This will
  338. // be used to pass the original function codes and parameters.
  339. //
  340. irpSp = IoGetNextIrpStackLocation( irp );
  341. irpSp->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
  342. irpSp->FileObject = fileObject;
  343. //
  344. // Allocate a buffer which should be used to put the information into
  345. // by the driver. This will be copied back to the caller's buffer when
  346. // the service completes. This is done by setting the flag which says
  347. // that this is an input operation.
  348. //
  349. irp->UserBuffer = FsInformation;
  350. irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
  351. irp->MdlAddress = (PMDL) NULL;
  352. //
  353. // Allocate the system buffer using an exception handler in case the
  354. // caller doesn't have enough quota remaining.
  355. //
  356. try {
  357. irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota( NonPagedPool,
  358. Length );
  359. } except(EXCEPTION_EXECUTE_HANDLER) {
  360. //
  361. // An exception was incurred attempting to allocate the inter-
  362. // mediary buffer. Cleanup and return with an appropriate error
  363. // status code.
  364. //
  365. IopExceptionCleanup( fileObject,
  366. irp,
  367. (PKEVENT) NULL,
  368. event );
  369. return GetExceptionCode();
  370. }
  371. irp->Flags |= (ULONG) (IRP_BUFFERED_IO |
  372. IRP_DEALLOCATE_BUFFER |
  373. IRP_INPUT_OPERATION |
  374. IRP_DEFER_IO_COMPLETION);
  375. //
  376. // Copy the caller's parameters to the service-specific portion of the
  377. // IRP.
  378. //
  379. irpSp->Parameters.QueryVolume.Length = Length;
  380. irpSp->Parameters.QueryVolume.FsInformationClass = FsInformationClass;
  381. //
  382. // Queue the packet, call the driver, and synchronize appopriately with
  383. // I/O completion.
  384. //
  385. status = IopSynchronousServiceTail( deviceObject,
  386. irp,
  387. fileObject,
  388. TRUE,
  389. requestorMode,
  390. synchronousIo,
  391. OtherTransfer );
  392. //
  393. // If the file for this operation was not opened for synchronous I/O, then
  394. // synchronization of completion of the I/O operation has not yet occurred
  395. // since the allocated event must be used for synchronous APIs on files
  396. // opened for asynchronous I/O. Synchronize the completion of the I/O
  397. // operation now.
  398. //
  399. if (!synchronousIo) {
  400. status = IopSynchronousApiServiceTail( status,
  401. event,
  402. irp,
  403. requestorMode,
  404. &localIoStatus,
  405. IoStatusBlock );
  406. }
  407. return status;
  408. }
  409. NTSTATUS
  410. NtSetVolumeInformationFile(
  411. IN HANDLE FileHandle,
  412. OUT PIO_STATUS_BLOCK IoStatusBlock,
  413. IN PVOID FsInformation,
  414. IN ULONG Length,
  415. IN FS_INFORMATION_CLASS FsInformationClass
  416. )
  417. /*++
  418. Routine Description:
  419. This service changes information about the volume "mounted" on the device
  420. specified by the FileHandle parameter. The information to be changed is
  421. in the FsInformation buffer. Its contents are defined by the FsInformation-
  422. Class parameter, whose values may be as follows:
  423. o FileFsLabelInformation
  424. Arguments:
  425. FileHandle - Supplies a handle to the volume whose information should be
  426. changed.
  427. IoStatusBlock - Address of the caller's I/O status block.
  428. FsInformation - Supplies a buffer containing the information which should
  429. be changed on the volume.
  430. Length - Supplies the length, in bytes, of the FsInformation buffer.
  431. FsInformationClass - Specifies the type of information which should be
  432. changed about the volume.
  433. Return Value:
  434. The status returned is the final completion status of the operation.
  435. block.
  436. --*/
  437. {
  438. PIRP irp;
  439. NTSTATUS status;
  440. PFILE_OBJECT fileObject;
  441. PDEVICE_OBJECT deviceObject;
  442. PKEVENT event = (PKEVENT) NULL;
  443. KPROCESSOR_MODE requestorMode;
  444. PIO_STACK_LOCATION irpSp;
  445. IO_STATUS_BLOCK localIoStatus;
  446. PFILE_FS_LABEL_INFORMATION labelInformation;
  447. BOOLEAN synchronousIo;
  448. PDEVICE_OBJECT targetDeviceObject;
  449. PETHREAD CurrentThread;
  450. PAGED_CODE();
  451. //
  452. // Get the previous mode; i.e., the mode of the caller.
  453. //
  454. CurrentThread = PsGetCurrentThread ();
  455. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  456. if (requestorMode != KernelMode) {
  457. //
  458. // Ensure that the FsInformationClass parameter is legal for setting
  459. // information about the volume.
  460. //
  461. if ((ULONG) FsInformationClass >= FileFsMaximumInformation ||
  462. IopSetFsOperationLength[FsInformationClass] == 0) {
  463. return STATUS_INVALID_INFO_CLASS;
  464. }
  465. //
  466. // Finally, ensure that the supplied buffer is large enough to contain
  467. // the information associated with the specified set operation that is
  468. // to be performed.
  469. //
  470. if (Length < (ULONG) IopSetFsOperationLength[FsInformationClass]) {
  471. return STATUS_INFO_LENGTH_MISMATCH;
  472. }
  473. //
  474. // The caller's access mode is user, so probe each of the arguments
  475. // and capture them as necessary. If any failures occur, the condition
  476. // handler will be invoked to handle them. It will simply cleanup and
  477. // return an access violation status code back to the system service
  478. // dispatcher.
  479. //
  480. try {
  481. //
  482. // The IoStatusBlock parameter must be writeable by the caller.
  483. //
  484. ProbeForWriteIoStatus( IoStatusBlock );
  485. //
  486. // The FsInformation buffer must be readable by the caller.
  487. //
  488. #if defined(_X86_)
  489. ProbeForRead( FsInformation, Length, sizeof( ULONG ) );
  490. #elif defined(_IA64_)
  491. // If we are a wow64 process, follow the X86 rules
  492. if (PsGetCurrentProcessByThread(CurrentThread)->Wow64Process) {
  493. ProbeForRead( FsInformation, Length, sizeof( ULONG ) );
  494. }
  495. else {
  496. ProbeForRead( FsInformation,
  497. Length,
  498. IopQuerySetFsAlignmentRequirement[FsInformationClass] );
  499. }
  500. #else
  501. ProbeForRead( FsInformation,
  502. Length,
  503. IopQuerySetFsAlignmentRequirement[FsInformationClass] );
  504. #endif
  505. } except(EXCEPTION_EXECUTE_HANDLER) {
  506. //
  507. // An exception was incurred probing the caller's parameters.
  508. // Simply return an appropriate error status code.
  509. //
  510. return GetExceptionCode();
  511. }
  512. }
  513. //
  514. // There were no blatant errors so far, so reference the file object so
  515. // the target device object can be found. Note that if the handle does
  516. // not refer to a file object, or if the caller does not have the required
  517. // access to the file, then it will fail.
  518. //
  519. status = ObReferenceObjectByHandle( FileHandle,
  520. IopSetFsOperationAccess[FsInformationClass],
  521. IoFileObjectType,
  522. requestorMode,
  523. (PVOID *) &fileObject,
  524. NULL );
  525. if (!NT_SUCCESS( status )) {
  526. return status;
  527. }
  528. //
  529. // Retrieve the device object associated with this file handle.
  530. //
  531. status = IoGetRelatedTargetDevice( fileObject, &targetDeviceObject );
  532. if (NT_SUCCESS( status )) {
  533. //
  534. // The PDO associated with the devnode we got back from
  535. // IoGetRelatedTargetDevice has already been referenced by that
  536. // routine. Store this reference away in the notification entry,
  537. // so we can deref it later when the notification entry is unregistered.
  538. //
  539. ASSERT(targetDeviceObject);
  540. } else {
  541. targetDeviceObject = NULL;
  542. }
  543. //
  544. // Make a special check here to determine whether this is a synchronous
  545. // I/O operation. If it is, then wait here until the file is owned by
  546. // the current thread. if this is not a (serialized) synchronous I/O
  547. // operation, then allocate and initialize the local event.
  548. //
  549. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  550. BOOLEAN interrupted;
  551. if (!IopAcquireFastLock( fileObject )) {
  552. status = IopAcquireFileObjectLock( fileObject,
  553. requestorMode,
  554. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  555. &interrupted );
  556. if (interrupted) {
  557. ObDereferenceObject( fileObject );
  558. if (targetDeviceObject != NULL) {
  559. ObDereferenceObject( targetDeviceObject );
  560. }
  561. return status;
  562. }
  563. }
  564. synchronousIo = TRUE;
  565. } else {
  566. //
  567. // This is a synchronous API being invoked for a file that is opened
  568. // for asynchronous I/O. This means that this system service is
  569. // to synchronize the completion of the operation before returning
  570. // to the caller. A local event is used to do this.
  571. //
  572. event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
  573. if (event == NULL) {
  574. ObDereferenceObject( fileObject );
  575. if (targetDeviceObject != NULL) {
  576. ObDereferenceObject( targetDeviceObject );
  577. }
  578. return STATUS_INSUFFICIENT_RESOURCES;
  579. }
  580. KeInitializeEvent( event, SynchronizationEvent, FALSE );
  581. synchronousIo = FALSE;
  582. }
  583. //
  584. // Set the file object to the Not-Signaled state.
  585. //
  586. KeClearEvent( &fileObject->Event );
  587. //
  588. // Get the address of the target device object.
  589. //
  590. deviceObject = IoGetRelatedDeviceObject( fileObject );
  591. //
  592. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  593. // The allocation is performed with an exception handler in case the
  594. // caller does not have enough quota to allocate the packet.
  595. irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
  596. if (!irp) {
  597. //
  598. // An IRP could not be allocated. Cleanup and return an appropriate
  599. // error status code.
  600. //
  601. if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  602. ExFreePool( event );
  603. }
  604. IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
  605. if (targetDeviceObject != NULL) {
  606. ObDereferenceObject( targetDeviceObject );
  607. }
  608. return STATUS_INSUFFICIENT_RESOURCES;
  609. }
  610. irp->Tail.Overlay.OriginalFileObject = fileObject;
  611. irp->Tail.Overlay.Thread = CurrentThread;
  612. irp->RequestorMode = requestorMode;
  613. //
  614. // Fill in the service independent parameters in the IRP.
  615. //
  616. if (synchronousIo) {
  617. irp->UserEvent = (PKEVENT) NULL;
  618. irp->UserIosb = IoStatusBlock;
  619. } else {
  620. irp->UserEvent = event;
  621. irp->UserIosb = &localIoStatus;
  622. irp->Flags = IRP_SYNCHRONOUS_API;
  623. }
  624. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  625. //
  626. // Get a pointer to the stack location for the first driver. This will be
  627. // used to pass the original function codes and parameters.
  628. //
  629. irpSp = IoGetNextIrpStackLocation( irp );
  630. irpSp->MajorFunction = IRP_MJ_SET_VOLUME_INFORMATION;
  631. irpSp->FileObject = fileObject;
  632. //
  633. // Allocate a buffer and copy the information that is to be set on the
  634. // file into it. Also, set the flags so that the completion code will
  635. // properly handle getting rid of the buffer and will not attempt to
  636. // copy data.
  637. //
  638. irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
  639. irp->MdlAddress = (PMDL) NULL;
  640. try {
  641. irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuota( NonPagedPool,
  642. Length );
  643. RtlCopyMemory( irp->AssociatedIrp.SystemBuffer, FsInformation, Length );
  644. } except(EXCEPTION_EXECUTE_HANDLER) {
  645. //
  646. // An exception was incurred attempting to allocate the intermediary
  647. // buffer or while copying the caller's data to the buffer. Determine
  648. // what happened, cleanup, and return an appropriate error status
  649. // code.
  650. //
  651. IopExceptionCleanup( fileObject,
  652. irp,
  653. (PKEVENT) NULL,
  654. event );
  655. if (targetDeviceObject != NULL) {
  656. ObDereferenceObject( targetDeviceObject );
  657. }
  658. return GetExceptionCode();
  659. }
  660. //
  661. // If the previous mode was not kernel, check the captured label buffer
  662. // for consistency.
  663. //
  664. if (requestorMode != KernelMode &&
  665. FsInformationClass == FileFsLabelInformation) {
  666. //
  667. // The previous mode was something other than kernel. Check to see
  668. // whether or not the length of the label specified within the label
  669. // structure is consistent with the overall length of the structure
  670. // itself. If not, then cleanup and get out.
  671. //
  672. labelInformation = (PFILE_FS_LABEL_INFORMATION) irp->AssociatedIrp.SystemBuffer;
  673. if ((LONG) labelInformation->VolumeLabelLength < 0 ||
  674. labelInformation->VolumeLabelLength +
  675. FIELD_OFFSET( FILE_FS_LABEL_INFORMATION, VolumeLabel ) > Length) {
  676. IopExceptionCleanup( fileObject,
  677. irp,
  678. (PKEVENT) NULL,
  679. event );
  680. if (targetDeviceObject != NULL) {
  681. ObDereferenceObject( targetDeviceObject );
  682. }
  683. return STATUS_INVALID_PARAMETER;
  684. }
  685. }
  686. irp->Flags |= (ULONG) (IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER);
  687. //
  688. // Copy the caller's parameters to the service-specific portion of the
  689. // IRP.
  690. //
  691. irpSp->Parameters.SetVolume.Length = Length;
  692. irpSp->Parameters.SetVolume.FsInformationClass = FsInformationClass;
  693. //
  694. // Queue the packet, call the driver, and synchronize appopriately with
  695. // I/O completion.
  696. //
  697. status = IopSynchronousServiceTail( deviceObject,
  698. irp,
  699. fileObject,
  700. FALSE,
  701. requestorMode,
  702. synchronousIo,
  703. OtherTransfer );
  704. //
  705. // If the file for this operation was not opened for synchronous I/O, then
  706. // synchronization of completion of the I/O operation has not yet occurred
  707. // since the allocated event must be used for synchronous APIs on files
  708. // opened for asynchronous I/O. Synchronize the completion of the I/O
  709. // operation now.
  710. //
  711. if (!synchronousIo) {
  712. status = IopSynchronousApiServiceTail( status,
  713. event,
  714. irp,
  715. requestorMode,
  716. &localIoStatus,
  717. IoStatusBlock );
  718. }
  719. //
  720. // Notify anyone who cares about the label change
  721. //
  722. if (targetDeviceObject != NULL) {
  723. if (NT_SUCCESS( status )) {
  724. TARGET_DEVICE_CUSTOM_NOTIFICATION ChangeEvent;
  725. ChangeEvent.Version = 1;
  726. ChangeEvent.FileObject = NULL;
  727. ChangeEvent.NameBufferOffset = -1;
  728. ChangeEvent.Size = (USHORT)FIELD_OFFSET( TARGET_DEVICE_CUSTOM_NOTIFICATION, CustomDataBuffer );
  729. RtlCopyMemory( &ChangeEvent.Event, &GUID_IO_VOLUME_CHANGE, sizeof( GUID_IO_VOLUME_CHANGE ));
  730. IoReportTargetDeviceChange( targetDeviceObject, &ChangeEvent );
  731. }
  732. ObDereferenceObject( targetDeviceObject );
  733. }
  734. return status;
  735. }