Leaked source code of windows server 2003
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.

566 lines
14 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. Quota.c
  5. Abstract:
  6. This module implements the File set and query Quota routines for Ntfs called
  7. by the dispatch driver.
  8. Author:
  9. Jeff Havens [Jhavens] 12-Jul-1996
  10. Revision History:
  11. --*/
  12. #include "NtfsProc.h"
  13. //
  14. // The local debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_QUOTA)
  17. //
  18. // Define a tag for general pool allocations from this module
  19. //
  20. #undef MODULE_POOL_TAG
  21. #define MODULE_POOL_TAG ('QFtN')
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGE, NtfsCommonQueryQuota)
  24. #pragma alloc_text(PAGE, NtfsCommonSetQuota)
  25. #endif
  26. NTSTATUS
  27. NtfsCommonQueryQuota (
  28. IN PIRP_CONTEXT IrpContext,
  29. IN PIRP Irp
  30. )
  31. /*++
  32. Routine Description:
  33. This is the common routine for query Quota called by both the fsd and fsp
  34. threads.
  35. Arguments:
  36. Irp - Supplies the Irp to process
  37. Return Value:
  38. NTSTATUS - The return status for the operation
  39. --*/
  40. {
  41. NTSTATUS Status;
  42. PIO_STACK_LOCATION IrpSp;
  43. PFILE_OBJECT FileObject;
  44. TYPE_OF_OPEN TypeOfOpen;
  45. PVCB Vcb;
  46. PFCB Fcb;
  47. PSCB Scb;
  48. PCCB Ccb;
  49. PFILE_GET_QUOTA_INFORMATION UserSidList;
  50. PFILE_QUOTA_INFORMATION QuotaBuffer = NULL;
  51. PFILE_QUOTA_INFORMATION MappedQuotaBuffer = NULL;
  52. PFILE_QUOTA_INFORMATION OriginalQuotaBuffer;
  53. ULONG OriginalBufferLength;
  54. ULONG UserBufferLength;
  55. ULONG UserSidListLength;
  56. PSID UserStartSid;
  57. ULONG OwnerId;
  58. BOOLEAN RestartScan;
  59. BOOLEAN ReturnSingleEntry;
  60. BOOLEAN IndexSpecified;
  61. BOOLEAN TempBufferAllocated = FALSE;
  62. ASSERT_IRP_CONTEXT( IrpContext );
  63. ASSERT_IRP( Irp );
  64. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  65. PAGED_CODE();
  66. //
  67. // Get the current Irp stack location
  68. //
  69. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  70. DebugTrace( +1, Dbg, ("NtfsCommonQueryQuota\n") );
  71. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  72. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  73. DebugTrace( 0, Dbg, ("SystemBuffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer) );
  74. DebugTrace( 0, Dbg, ("Length = %08lx\n", IrpSp->Parameters.QueryQuota.Length) );
  75. DebugTrace( 0, Dbg, ("SidList = %08lx\n", IrpSp->Parameters.QueryQuota.SidList) );
  76. DebugTrace( 0, Dbg, ("SidListLength = %08lx\n", IrpSp->Parameters.QueryQuota.SidListLength) );
  77. DebugTrace( 0, Dbg, ("StartSid = %08lx\n", IrpSp->Parameters.QueryQuota.StartSid) );
  78. DebugTrace( 0, Dbg, ("RestartScan = %08lx\n", FlagOn(IrpSp->Flags, SL_RESTART_SCAN)) );
  79. DebugTrace( 0, Dbg, ("ReturnSingleEntry = %08lx\n", FlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY)) );
  80. DebugTrace( 0, Dbg, ("IndexSpecified = %08lx\n", FlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED)) );
  81. //
  82. // Extract and decode the file object
  83. //
  84. FileObject = IrpSp->FileObject;
  85. UserBufferLength = IrpSp->Parameters.QueryQuota.Length;
  86. UserSidList = IrpSp->Parameters.QueryQuota.SidList;
  87. UserSidListLength = IrpSp->Parameters.QueryQuota.SidListLength;
  88. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  89. //
  90. // This must be a user file or directory and the Ccb must indicate that
  91. // the caller opened the entire file. We don't like zero length user buffers or SidLists either.
  92. //
  93. if (((TypeOfOpen != UserFileOpen) &&
  94. (TypeOfOpen != UserDirectoryOpen) &&
  95. (TypeOfOpen != UserVolumeOpen) &&
  96. (TypeOfOpen != UserViewIndexOpen)) ||
  97. (UserBufferLength == 0) ||
  98. ((UserSidList != NULL) && (UserSidListLength == 0)) ||
  99. (Ccb == NULL) ||
  100. !FlagOn( Ccb->Flags, CCB_FLAG_OPEN_AS_FILE )) {
  101. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_PARAMETER );
  102. DebugTrace( -1, Dbg, ("NtfsCommonQueryQuota -> %08lx\n", STATUS_INVALID_PARAMETER) );
  103. return STATUS_INVALID_PARAMETER;
  104. }
  105. //
  106. // Return nothing if quotas are not enabled.
  107. //
  108. if (Vcb->QuotaTableScb == NULL) {
  109. NtfsCompleteRequest( IrpContext, Irp, STATUS_INVALID_DEVICE_REQUEST );
  110. return STATUS_INVALID_DEVICE_REQUEST;
  111. }
  112. //
  113. // Acquire the Vcb Shared.
  114. //
  115. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  116. //
  117. // Use a try-finally to facilitate cleanup.
  118. //
  119. try {
  120. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  121. Status = STATUS_VOLUME_DISMOUNTED;
  122. leave;
  123. }
  124. //
  125. // Reference our input parameters to make things easier
  126. //
  127. UserStartSid = IrpSp->Parameters.QueryQuota.StartSid;
  128. RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
  129. ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
  130. IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);
  131. //
  132. // Initialize our local variables.
  133. //
  134. Status = STATUS_SUCCESS;
  135. //
  136. // Map the user's buffer.
  137. //
  138. QuotaBuffer = NtfsMapUserBuffer( Irp, NormalPagePriority );
  139. //
  140. // Allocate our own output buffer out of paranoia.
  141. //
  142. if (Irp->RequestorMode != KernelMode) {
  143. MappedQuotaBuffer = QuotaBuffer;
  144. QuotaBuffer = NtfsAllocatePool( PagedPool, UserBufferLength );
  145. TempBufferAllocated = TRUE;
  146. }
  147. OriginalBufferLength = UserBufferLength;
  148. OriginalQuotaBuffer = QuotaBuffer;
  149. //
  150. // Let's clear the output buffer.
  151. //
  152. RtlZeroMemory( QuotaBuffer, UserBufferLength );
  153. //
  154. // We now satisfy the user's request depending on whether he
  155. // specified an Quota name list, an Quota index or restarting the
  156. // search.
  157. //
  158. //
  159. // The user has supplied a list of Quota names.
  160. //
  161. if (UserSidList != NULL) {
  162. Status = NtfsQueryQuotaUserSidList( IrpContext,
  163. Vcb,
  164. UserSidList,
  165. QuotaBuffer,
  166. &UserBufferLength,
  167. ReturnSingleEntry );
  168. } else {
  169. //
  170. // The user supplied an index into the Quota list.
  171. //
  172. if (IndexSpecified) {
  173. OwnerId = NtfsGetOwnerId( IrpContext,
  174. UserStartSid,
  175. FALSE,
  176. NULL );
  177. if (OwnerId == QUOTA_INVALID_ID) {
  178. //
  179. // Fail the request.
  180. //
  181. Status = STATUS_INVALID_PARAMETER;
  182. leave;
  183. }
  184. } else {
  185. //
  186. // Start at the begining of the list if restart specified.
  187. //
  188. OwnerId = RestartScan ? QUOTA_FISRT_USER_ID - 1 : Ccb->LastOwnerId;
  189. }
  190. Status = NtfsFsQuotaQueryInfo( IrpContext,
  191. Vcb,
  192. OwnerId,
  193. ReturnSingleEntry,
  194. &QuotaBuffer,
  195. &UserBufferLength,
  196. Ccb );
  197. //
  198. // If we specified SingleEntry, NextEntryOffset would still be uninitialized.
  199. //
  200. if (NT_SUCCESS( Status ) && ReturnSingleEntry) {
  201. QuotaBuffer->NextEntryOffset = 0;
  202. }
  203. }
  204. //
  205. // Copy the data onto the user buffer if we ended up allocating
  206. // a temporary buffer to work on. Check if there's anything to copy, too.
  207. // UserBufferLength reflects how much of the buffer is left.
  208. //
  209. if (TempBufferAllocated &&
  210. (UserBufferLength < OriginalBufferLength)) {
  211. try {
  212. RtlCopyMemory( MappedQuotaBuffer, OriginalQuotaBuffer,
  213. OriginalBufferLength - UserBufferLength );
  214. } except( EXCEPTION_EXECUTE_HANDLER ) {
  215. try_return( Status = STATUS_INVALID_USER_BUFFER );
  216. }
  217. }
  218. if (UserBufferLength <= OriginalBufferLength) {
  219. Irp->IoStatus.Information = OriginalBufferLength - UserBufferLength;
  220. } else {
  221. ASSERT( FALSE );
  222. Irp->IoStatus.Information = 0;
  223. }
  224. Irp->IoStatus.Status = Status;
  225. try_exit: NOTHING;
  226. } finally {
  227. DebugUnwind( NtfsCommonQueryQuota );
  228. //
  229. // Release the Vcb.
  230. //
  231. NtfsReleaseVcb( IrpContext, Vcb );
  232. if (TempBufferAllocated) {
  233. NtfsFreePool( OriginalQuotaBuffer );
  234. }
  235. if (!AbnormalTermination()) {
  236. NtfsCompleteRequest( IrpContext, Irp, Status );
  237. }
  238. //
  239. // And return to our caller
  240. //
  241. DebugTrace( -1, Dbg, ("NtfsCommonQueryQuota -> %08lx\n", Status) );
  242. }
  243. return Status;
  244. }
  245. NTSTATUS
  246. NtfsCommonSetQuota (
  247. IN PIRP_CONTEXT IrpContext,
  248. IN PIRP Irp
  249. )
  250. /*++
  251. Routine Description:
  252. This is the common routine for set Quota called by both the fsd and fsp
  253. threads.
  254. Arguments:
  255. Irp - Supplies the Irp to process
  256. Return Value:
  257. NTSTATUS - The return status for the operation
  258. --*/
  259. {
  260. NTSTATUS Status;
  261. PIO_STACK_LOCATION IrpSp;
  262. PFILE_OBJECT FileObject;
  263. TYPE_OF_OPEN TypeOfOpen;
  264. PVCB Vcb;
  265. PFCB Fcb;
  266. PSCB Scb;
  267. PCCB Ccb;
  268. PFILE_QUOTA_INFORMATION Buffer;
  269. PFILE_QUOTA_INFORMATION SafeBuffer = NULL;
  270. ULONG UserBufferLength;
  271. ASSERT_IRP_CONTEXT( IrpContext );
  272. ASSERT_IRP( Irp );
  273. ASSERT( FlagOn( IrpContext->TopLevelIrpContext->State, IRP_CONTEXT_STATE_OWNS_TOP_LEVEL ));
  274. PAGED_CODE();
  275. //
  276. // Get the current Irp stack location
  277. //
  278. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  279. DebugTrace( +1, Dbg, ("NtfsCommonSetQuota\n") );
  280. DebugTrace( 0, Dbg, ("IrpContext = %08lx\n", IrpContext) );
  281. DebugTrace( 0, Dbg, ("Irp = %08lx\n", Irp) );
  282. //
  283. // Extract and decode the file object
  284. //
  285. FileObject = IrpSp->FileObject;
  286. TypeOfOpen = NtfsDecodeFileObject( IrpContext, FileObject, &Vcb, &Fcb, &Scb, &Ccb, TRUE );
  287. //
  288. // Initialize the IoStatus values.
  289. //
  290. Irp->IoStatus.Information = 0;
  291. Irp->IoStatus.Status = STATUS_SUCCESS;
  292. UserBufferLength = IrpSp->Parameters.SetQuota.Length;
  293. //
  294. // Check that the file object is associated with either a user file or
  295. // user directory open or an open by file ID.
  296. //
  297. if ((Ccb == NULL) ||
  298. (!FlagOn( Ccb->AccessFlags, MANAGE_VOLUME_ACCESS) &&
  299. ((TypeOfOpen != UserViewIndexOpen) || (Fcb != Vcb->QuotaTableScb->Fcb))) ||
  300. (UserBufferLength == 0) ||
  301. !FlagOn( Ccb->Flags, CCB_FLAG_OPEN_AS_FILE )) {
  302. if (UserBufferLength != 0) {
  303. Status = STATUS_ACCESS_DENIED;
  304. } else {
  305. Status = STATUS_INVALID_PARAMETER;
  306. }
  307. NtfsCompleteRequest( IrpContext, Irp, Status );
  308. DebugTrace( -1, Dbg, ("NtfsCommonQueryQuota -> %08lx\n", Status) );
  309. return Status;
  310. }
  311. //
  312. // We must be writable.
  313. //
  314. if (NtfsIsVolumeReadOnly( Vcb )) {
  315. Status = STATUS_MEDIA_WRITE_PROTECTED;
  316. NtfsCompleteRequest( IrpContext, Irp, Status );
  317. DebugTrace( -1, Dbg, ("NtfsCommonSetQuota -> %08lx\n", Status) );
  318. return Status;
  319. }
  320. //
  321. // We must be waitable.
  322. //
  323. if (!FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT )) {
  324. Status = NtfsPostRequest( IrpContext, Irp );
  325. DebugTrace( -1, Dbg, ("NtfsCommonSetQuota -> %08lx\n", Status) );
  326. return Status;
  327. }
  328. //
  329. // Acquire the vcb shared.
  330. //
  331. NtfsAcquireSharedVcb( IrpContext, Vcb, TRUE );
  332. //
  333. // Use a try-finally to facilitate cleanup.
  334. //
  335. try {
  336. if (!FlagOn( Vcb->VcbState, VCB_STATE_VOLUME_MOUNTED )) {
  337. Status = STATUS_VOLUME_DISMOUNTED;
  338. leave;
  339. }
  340. //
  341. // Map the user's Quota buffer.
  342. //
  343. Buffer = NtfsMapUserBuffer( Irp, NormalPagePriority );
  344. //
  345. // Be paranoid and copy the user buffer into kernel space.
  346. //
  347. if (Irp->RequestorMode != KernelMode) {
  348. SafeBuffer = NtfsAllocatePool( PagedPool, UserBufferLength );
  349. try {
  350. RtlCopyMemory( SafeBuffer, Buffer, UserBufferLength );
  351. } except( EXCEPTION_EXECUTE_HANDLER ) {
  352. Status = STATUS_INVALID_USER_BUFFER;
  353. leave;
  354. }
  355. Buffer = SafeBuffer;
  356. }
  357. //
  358. // Update the caller's Iosb.
  359. //
  360. Irp->IoStatus.Information = 0;
  361. Status = STATUS_SUCCESS;
  362. Status = NtfsFsQuotaSetInfo( IrpContext,
  363. Vcb,
  364. Buffer,
  365. UserBufferLength );
  366. //
  367. // Check if there are transactions to cleanup.
  368. //
  369. NtfsCleanupTransaction( IrpContext, Status, FALSE );
  370. } finally {
  371. DebugUnwind( NtfsCommonSetQuota );
  372. //
  373. // Release the Vcb.
  374. //
  375. NtfsReleaseVcb( IrpContext, Vcb );
  376. //
  377. // If we allocated a temporary buffer, free it.
  378. //
  379. if (SafeBuffer != NULL) {
  380. NtfsFreePool( SafeBuffer );
  381. }
  382. //
  383. // Complete the Irp.
  384. //
  385. if (!AbnormalTermination()) {
  386. NtfsCompleteRequest( IrpContext, Irp, Status );
  387. }
  388. DebugTrace( -1, Dbg, ("NtfsCommonSetQuota -> %08lx\n", Status) );
  389. }
  390. return Status;
  391. }