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.

650 lines
20 KiB

  1. /*++
  2. Copyright (c) 1989 - 1995 Microsoft Corporation
  3. Module Name:
  4. qsquota.c
  5. Abstract:
  6. This module contains the code to implement the NtQueryQuotaInformationFile
  7. and the NtSetQuotaInformationFile system services for the NT I/O system.
  8. Author:
  9. Darryl E. Havens (darrylh) 20-Jun-1995
  10. Environment:
  11. Kernel mode only
  12. Revision History:
  13. --*/
  14. #include "iomgr.h"
  15. #ifdef ALLOC_PRAGMA
  16. #pragma alloc_text(PAGE, NtQueryQuotaInformationFile)
  17. #pragma alloc_text(PAGE, NtSetQuotaInformationFile)
  18. #endif
  19. NTSTATUS
  20. NtQueryQuotaInformationFile(
  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 SidList OPTIONAL,
  27. IN ULONG SidListLength,
  28. IN PULONG StartSid OPTIONAL,
  29. IN BOOLEAN RestartScan
  30. )
  31. /*++
  32. Routine Description:
  33. This service returns quota entries associated with the volume specified
  34. by the FileHandle parameter. The amount of information returned is based
  35. on the size of the quota information associated with the volume, the size
  36. of the buffer, and whether or not a specific set of entries has been
  37. requested.
  38. Arguments:
  39. FileHandle - Supplies a handle to the file/volume for which the quota
  40. information is returned.
  41. IoStatusBlock - Address of the caller's I/O status block.
  42. Buffer - Supplies a buffer to receive the quota information for the volume.
  43. Length - Supplies the length, in bytes, of the buffer.
  44. ReturnSingleEntry - Indicates that only a single entry should be returned
  45. rather than filling the buffer with as many entries as possible.
  46. SidList - Optionally supplies a list of SIDs whose quota information is to
  47. be returned.
  48. SidListLength - Supplies the length of the SID list, if one was specified.
  49. StartSid - Supplies an optional SID that indicates that the returned
  50. information is to start with an entry other than the first. This
  51. parameter is ignored if a SidList is specified.
  52. RestartScan - Indicates whether the scan of the quota information is to be
  53. restarted from the beginning.
  54. Return Value:
  55. The status returned is the final completion status of the operation.
  56. --*/
  57. {
  58. #define ALIGN_LONG( Address ) ( (Address + 3) & ~3 )
  59. PIRP irp;
  60. NTSTATUS status;
  61. PFILE_OBJECT fileObject;
  62. PDEVICE_OBJECT deviceObject;
  63. PKEVENT event = (PKEVENT) NULL;
  64. PCHAR auxiliaryBuffer = (PCHAR) NULL;
  65. ULONG startSidLength = 0;
  66. PSID startSid = (PSID) NULL;
  67. PFILE_GET_QUOTA_INFORMATION sidList = (PFILE_GET_QUOTA_INFORMATION) NULL;
  68. KPROCESSOR_MODE requestorMode;
  69. PIO_STACK_LOCATION irpSp;
  70. IO_STATUS_BLOCK localIoStatus;
  71. BOOLEAN synchronousIo;
  72. UCHAR subCount;
  73. PETHREAD CurrentThread;
  74. PAGED_CODE();
  75. //
  76. // Get the previous mode; i.e., the mode of the caller.
  77. //
  78. CurrentThread = PsGetCurrentThread ();
  79. requestorMode = KeGetPreviousModeByThread(&CurrentThread->Tcb);
  80. if (requestorMode != KernelMode) {
  81. //
  82. // The caller's access mode is not kernel so probe each of the arguments
  83. // and capture them as necessary. If any failures occur, the condition
  84. // handler will be invoked to handle them. It will simply cleanup and
  85. // return an access violation status code back to the system service
  86. // dispatcher.
  87. //
  88. try {
  89. //
  90. // The IoStatusBlock parameter must be writeable by the caller.
  91. //
  92. ProbeForWriteIoStatus( IoStatusBlock );
  93. //
  94. // The buffer must be writeable by the caller.
  95. //
  96. #if defined(_X86_)
  97. ProbeForWrite( Buffer, Length, sizeof( ULONG ) );
  98. #elif defined(_WIN64)
  99. //
  100. // If we are a wow64 process, follow the X86 rules
  101. //
  102. if (PsGetCurrentProcessByThread(CurrentThread)->Wow64Process) {
  103. ProbeForWrite( Buffer, Length, sizeof( ULONG ) );
  104. } else {
  105. ProbeForWrite( Buffer, Length, sizeof( ULONGLONG ) );
  106. }
  107. #else
  108. ProbeForWrite( Buffer, Length, sizeof( ULONGLONG ) );
  109. #endif
  110. //
  111. // If the optional StartSid parameter was specified, then it must
  112. // be readable by the caller. Begin by capturing the length of
  113. // the SID so that the SID itself can be captured.
  114. //
  115. if (ARGUMENT_PRESENT( StartSid )) {
  116. subCount = ProbeAndReadUchar( &(((SID *)(StartSid))->SubAuthorityCount) );
  117. startSidLength = RtlLengthRequiredSid( subCount );
  118. ProbeForRead( StartSid, startSidLength, sizeof( ULONG ) );
  119. }
  120. //
  121. // If the optional SidList parameter was specified, then it must
  122. // be readable by the caller. Validate that the buffer contains
  123. // a legal get information structure.
  124. //
  125. if (ARGUMENT_PRESENT( SidList ) && SidListLength) {
  126. ProbeForRead( SidList, SidListLength, sizeof( ULONG ) );
  127. auxiliaryBuffer = ExAllocatePoolWithQuota( NonPagedPool,
  128. ALIGN_LONG( SidListLength ) +
  129. startSidLength );
  130. sidList = (PFILE_GET_QUOTA_INFORMATION) auxiliaryBuffer;
  131. RtlCopyMemory( auxiliaryBuffer, SidList, SidListLength );
  132. } else {
  133. //
  134. // No SidList was specified. Check to see whether or not a
  135. // StartSid was specified and, if so, capture it. Note that
  136. // the SID has already been probed.
  137. //
  138. SidListLength = 0;
  139. if (ARGUMENT_PRESENT( StartSid )) {
  140. auxiliaryBuffer = ExAllocatePoolWithQuota( PagedPool,
  141. startSidLength );
  142. }
  143. }
  144. //
  145. // If a StartSid was specified tack it onto the end of the auxiliary
  146. // buffer.
  147. //
  148. if (ARGUMENT_PRESENT( StartSid )) {
  149. startSid = (PSID) (auxiliaryBuffer + ALIGN_LONG( SidListLength ));
  150. RtlCopyMemory( startSid, StartSid, startSidLength );
  151. ((SID *) startSid)->SubAuthorityCount = subCount;
  152. }
  153. } except(EXCEPTION_EXECUTE_HANDLER) {
  154. //
  155. // An exception was incurred while probing the caller's
  156. // parameters, allocating the pool buffer, or copying the
  157. // caller's EA list to the buffer. Cleanup and return an
  158. // appropriate error status code.
  159. //
  160. if (auxiliaryBuffer) {
  161. ExFreePool( auxiliaryBuffer );
  162. }
  163. return GetExceptionCode();
  164. }
  165. } else {
  166. //
  167. // The caller's mode was KernelMode. Simply allocate pool for the
  168. // SidList, if one was specified, and copy the string to it. Also,
  169. // if a StartSid was specified copy it as well.
  170. //
  171. if (ARGUMENT_PRESENT( SidList ) && SidListLength) {
  172. sidList = SidList;
  173. }
  174. if (ARGUMENT_PRESENT( StartSid )) {
  175. startSid = StartSid;
  176. }
  177. }
  178. //
  179. // Always check the validity of the buffer since the server uses this
  180. // routine.
  181. //
  182. if (sidList != NULL) {
  183. status = IopCheckGetQuotaBufferValidity( sidList,
  184. SidListLength,
  185. &IoStatusBlock->Information );
  186. if (!NT_SUCCESS( status )) {
  187. if (auxiliaryBuffer != NULL) {
  188. ExFreePool( auxiliaryBuffer );
  189. }
  190. return status;
  191. }
  192. }
  193. if (startSid != NULL) {
  194. if (!RtlValidSid( startSid )) {
  195. if (auxiliaryBuffer != NULL) {
  196. ExFreePool( auxiliaryBuffer );
  197. }
  198. return STATUS_INVALID_SID;
  199. }
  200. }
  201. //
  202. // There were no blatant errors so far, so reference the file object so
  203. // the target device object can be found. Note that if the handle does
  204. // not refer to a file object, or if the caller does not have the required
  205. // access to the file, then it will fail.
  206. //
  207. status = ObReferenceObjectByHandle( FileHandle,
  208. 0,
  209. IoFileObjectType,
  210. requestorMode,
  211. (PVOID *) &fileObject,
  212. NULL );
  213. if (!NT_SUCCESS( status )) {
  214. if (auxiliaryBuffer) {
  215. ExFreePool( auxiliaryBuffer );
  216. }
  217. return status;
  218. }
  219. //
  220. // Make a special check here to determine whether this is a synchronous
  221. // I/O operation. If it is, then wait here until the file is owned by
  222. // the current thread. If this is not a (serialized) synchronous I/O
  223. // operation, then allocate and initialize the local event.
  224. //
  225. if (fileObject->Flags & FO_SYNCHRONOUS_IO) {
  226. BOOLEAN interrupted;
  227. if (!IopAcquireFastLock( fileObject )) {
  228. status = IopAcquireFileObjectLock( fileObject,
  229. requestorMode,
  230. (BOOLEAN) ((fileObject->Flags & FO_ALERTABLE_IO) != 0),
  231. &interrupted );
  232. if (interrupted) {
  233. if (auxiliaryBuffer) {
  234. ExFreePool( auxiliaryBuffer );
  235. }
  236. ObDereferenceObject( fileObject );
  237. return status;
  238. }
  239. }
  240. synchronousIo = TRUE;
  241. } else {
  242. //
  243. // This is a synchronous API being invoked for a file that is opened
  244. // for asynchronous I/O. This means that this system service is
  245. // to synchronize the completion of the operation before returning
  246. // to the caller. A local event is used to do this.
  247. //
  248. event = ExAllocatePool( NonPagedPool, sizeof( KEVENT ) );
  249. if (!event) {
  250. if (auxiliaryBuffer) {
  251. ExFreePool( auxiliaryBuffer );
  252. }
  253. ObDereferenceObject( fileObject );
  254. return STATUS_INSUFFICIENT_RESOURCES;
  255. }
  256. KeInitializeEvent( event, SynchronizationEvent, FALSE );
  257. synchronousIo = FALSE;
  258. }
  259. //
  260. // Set the file object to the Not-Signaled state.
  261. //
  262. KeClearEvent( &fileObject->Event );
  263. //
  264. // Get the address of the target device object.
  265. //
  266. deviceObject = IoGetRelatedDeviceObject( fileObject );
  267. //
  268. // Allocate and initialize the I/O Request Packet (IRP) for this operation.
  269. // The allocation is performed with an exception handler in case the
  270. // caller does not have enough quota to allocate the packet.
  271. irp = IoAllocateIrp( deviceObject->StackSize, TRUE );
  272. if (!irp) {
  273. //
  274. // An IRP could not be allocated. Cleanup and return an appropriate
  275. // error status code.
  276. //
  277. if (!(fileObject->Flags & FO_SYNCHRONOUS_IO)) {
  278. ExFreePool( event );
  279. }
  280. IopAllocateIrpCleanup( fileObject, (PKEVENT) NULL );
  281. if (auxiliaryBuffer) {
  282. ExFreePool( auxiliaryBuffer );
  283. }
  284. return STATUS_INSUFFICIENT_RESOURCES;
  285. }
  286. irp->Tail.Overlay.OriginalFileObject = fileObject;
  287. irp->Tail.Overlay.Thread = CurrentThread;
  288. irp->RequestorMode = requestorMode;
  289. //
  290. // Fill in the service independent parameters in the IRP.
  291. //
  292. if (synchronousIo) {
  293. irp->UserEvent = (PKEVENT) NULL;
  294. irp->UserIosb = IoStatusBlock;
  295. } else {
  296. irp->UserEvent = event;
  297. irp->UserIosb = &localIoStatus;
  298. irp->Flags = IRP_SYNCHRONOUS_API;
  299. }
  300. irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE) NULL;
  301. //
  302. // Get a pointer to the stack location for the first driver. This will be
  303. // used to pass the original function codes and parameters.
  304. //
  305. irpSp = IoGetNextIrpStackLocation( irp );
  306. irpSp->MajorFunction = IRP_MJ_QUERY_QUOTA;
  307. irpSp->FileObject = fileObject;
  308. //
  309. // If the caller specified an SID list of names to be queried, then pass
  310. // the address of the intermediary buffer containing the list to the
  311. // driver.
  312. //
  313. irp->Tail.Overlay.AuxiliaryBuffer = auxiliaryBuffer;
  314. irpSp->Parameters.QueryQuota.SidList = sidList;
  315. irpSp->Parameters.QueryQuota.SidListLength = SidListLength;
  316. //
  317. // Now determine whether this driver expects to have data buffered
  318. // to it or whether it performs direct I/O. This is based on the
  319. // DO_BUFFERED_IO flag in the device object. If the flag is set,
  320. // then a system buffer is allocated and the driver's data will be
  321. // copied to it. If the DO_DIRECT_IO flag is set in the device
  322. // object, then a Memory Descriptor List (MDL) is allocated and
  323. // the caller's buffer is locked down using it. Finally, if the
  324. // driver specifies neither of the flags, then simply pass the
  325. // address and length of the buffer and allow the driver to perform
  326. // all of the checking and buffering if any is required.
  327. //
  328. if (deviceObject->Flags & DO_BUFFERED_IO) {
  329. //
  330. // The driver wishes the caller's buffered be copied into an
  331. // intermediary buffer. Allocate the system buffer and specify
  332. // that it should be deallocated on completion. Also indicate
  333. // that this is an input operation so the data will be copied
  334. // into the caller's buffer. This is done using an exception
  335. // handler that will perform cleanup if the operation fails.
  336. //
  337. if (Length) {
  338. try {
  339. //
  340. // Allocate the intermediary system buffer from nonpaged
  341. // pool and charge quota for it.
  342. //
  343. irp->AssociatedIrp.SystemBuffer =
  344. ExAllocatePoolWithQuota( NonPagedPool, Length );
  345. } except(EXCEPTION_EXECUTE_HANDLER) {
  346. //
  347. // An exception was incurred while either probing the
  348. // caller's buffer or allocating the system buffer.
  349. // Determine what actually happened, clean everything
  350. // up, and return an appropriate error status code.
  351. //
  352. IopExceptionCleanup( fileObject,
  353. irp,
  354. (PKEVENT) NULL,
  355. event );
  356. if (auxiliaryBuffer) {
  357. ExFreePool( auxiliaryBuffer );
  358. }
  359. return GetExceptionCode();
  360. }
  361. //
  362. // Remember the address of the caller's buffer so the copy can
  363. // take place during I/O completion. Also, set the flags so
  364. // that the completion code knows to do the copy and to deallocate
  365. // the buffer.
  366. //
  367. irp->UserBuffer = Buffer;
  368. irp->Flags |= (ULONG) (IRP_BUFFERED_IO |
  369. IRP_DEALLOCATE_BUFFER |
  370. IRP_INPUT_OPERATION);
  371. } else {
  372. irp->AssociatedIrp.SystemBuffer = NULL;
  373. irp->UserBuffer = Buffer;
  374. }
  375. } else if (deviceObject->Flags & DO_DIRECT_IO) {
  376. PMDL mdl;
  377. //
  378. // This is a direct I/O operation. Allocate an MDL and invoke
  379. // the memory management routine to lock the buffer into memory.
  380. // This is done using an exception handler that will perform
  381. // cleanup if the operation fails.
  382. //
  383. mdl = (PMDL) NULL;
  384. if (Length) {
  385. try {
  386. //
  387. // Allocate an MDL, charging quota for it, and hang it off
  388. // of the IRP. Probe and lock the pages associated with
  389. // the caller's buffer for write access and fill in the MDL
  390. // with the PFNs of those pages.
  391. //
  392. mdl = IoAllocateMdl( Buffer, Length, FALSE, TRUE, irp );
  393. if (!mdl) {
  394. ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
  395. }
  396. MmProbeAndLockPages( mdl, requestorMode, IoWriteAccess );
  397. } except(EXCEPTION_EXECUTE_HANDLER) {
  398. //
  399. // An exception was incurred while either probing the
  400. // caller's buffer or allocating the MDL. Determine what
  401. // actually happened, clean everything up, and return an
  402. // appropriate error status code.
  403. //
  404. IopExceptionCleanup( fileObject,
  405. irp,
  406. (PKEVENT) NULL,
  407. event );
  408. if (auxiliaryBuffer) {
  409. ExFreePool( auxiliaryBuffer );
  410. }
  411. return GetExceptionCode();
  412. }
  413. }
  414. } else {
  415. //
  416. // Pass the address of the user's buffer so the driver has access
  417. // to it. It is now the driver's responsibility to do everything.
  418. //
  419. irp->UserBuffer = Buffer;
  420. }
  421. //
  422. // Copy the caller's parameters to the service-specific portion of the
  423. // IRP.
  424. //
  425. irpSp->Parameters.QueryQuota.Length = Length;
  426. irpSp->Parameters.QueryQuota.StartSid = StartSid;
  427. irpSp->Flags = 0;
  428. if (RestartScan) {
  429. irpSp->Flags = SL_RESTART_SCAN;
  430. }
  431. if (ReturnSingleEntry) {
  432. irpSp->Flags |= SL_RETURN_SINGLE_ENTRY;
  433. }
  434. if (ARGUMENT_PRESENT( StartSid )) {
  435. irpSp->Flags |= SL_INDEX_SPECIFIED;
  436. }
  437. //
  438. // Queue the packet, call the driver, and synchronize appropriately with
  439. // I/O completion.
  440. //
  441. status = IopSynchronousServiceTail( deviceObject,
  442. irp,
  443. fileObject,
  444. FALSE,
  445. requestorMode,
  446. synchronousIo,
  447. OtherTransfer );
  448. //
  449. // If the file for this operation was not opened for synchronous I/O, then
  450. // synchronization of completion of the I/O operation has not yet occurred
  451. // since the allocated event must be used for synchronous APIs on files
  452. // opened for asynchronous I/O. Synchronize the completion of the I/O
  453. // operation now.
  454. //
  455. if (!synchronousIo) {
  456. status = IopSynchronousApiServiceTail( status,
  457. event,
  458. irp,
  459. requestorMode,
  460. &localIoStatus,
  461. IoStatusBlock );
  462. }
  463. return status;
  464. }
  465. NTSTATUS
  466. NtSetQuotaInformationFile(
  467. IN HANDLE FileHandle,
  468. OUT PIO_STATUS_BLOCK IoStatusBlock,
  469. IN PVOID Buffer,
  470. IN ULONG Length
  471. )
  472. /*++
  473. Routine Description:
  474. This service changes quota entries for the volume associated with the
  475. FileHandle parameter. All of the quota entries in the specified buffer
  476. are applied to the volume.
  477. Arguments:
  478. FileHandle - Supplies a handle to the file/volume for which the quota
  479. entries are to be applied.
  480. IoStatusBlock - Address of the caller's I/O status block.
  481. Buffer - Supplies a buffer containing the new quota entries that should
  482. be applied to the volume.
  483. Length - Supplies the length, in bytes, of the buffer.
  484. Return Value:
  485. The status returned is the final completion status of the operation.
  486. --*/
  487. {
  488. PAGED_CODE();
  489. //
  490. // Simply return the status from the internal common routine for setting
  491. // EAs on a file or quotas on a volume.
  492. //
  493. return IopSetEaOrQuotaInformationFile( FileHandle,
  494. IoStatusBlock,
  495. Buffer,
  496. Length,
  497. FALSE );
  498. }