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.

789 lines
19 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. quota.c
  5. Abstract:
  6. This file contains code for commands that affect quotas.
  7. Author:
  8. Wesley Witt [wesw] 1-March-2000
  9. Revision History:
  10. --*/
  11. #include <precomp.h>
  12. #define BUFFER_SIZE 1024
  13. #define IO_FILE_QUOTA_THRESHOLD 0x40040024L
  14. #define IO_FILE_QUOTA_LIMIT 0x40040025L
  15. #define SID_MAX_LENGTH (FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * SID_MAX_SUB_AUTHORITIES)
  16. INT
  17. QuotaHelp(
  18. IN INT argc,
  19. IN PWSTR argv[]
  20. )
  21. {
  22. DisplayMsg( MSG_USAGE_QUOTA );
  23. return EXIT_CODE_SUCCESS;
  24. }
  25. HANDLE
  26. QuotaOpenVolume(
  27. IN PWSTR Drive
  28. )
  29. {
  30. NTSTATUS Status;
  31. HANDLE hFile;
  32. OBJECT_ATTRIBUTES ObjectAttributes;
  33. IO_STATUS_BLOCK IoStatus;
  34. WCHAR Buffer[MAX_PATH];
  35. UNICODE_STRING FileName;
  36. swprintf(
  37. Buffer,
  38. L"\\DosDevices\\%s\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION",
  39. Drive
  40. );
  41. RtlInitUnicodeString( &FileName, Buffer );
  42. InitializeObjectAttributes(
  43. &ObjectAttributes,
  44. &FileName,
  45. OBJ_CASE_INSENSITIVE,
  46. NULL,
  47. NULL
  48. );
  49. Status = NtOpenFile(
  50. &hFile,
  51. FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
  52. &ObjectAttributes,
  53. &IoStatus,
  54. FILE_SHARE_READ | FILE_SHARE_WRITE,
  55. FILE_SYNCHRONOUS_IO_ALERT | FILE_OPEN_FOR_BACKUP_INTENT
  56. );
  57. if (!NT_SUCCESS( Status )) {
  58. DisplayErrorMsg( RtlNtStatusToDosError( Status ), Drive );
  59. return INVALID_HANDLE_VALUE;
  60. }
  61. return hFile;
  62. }
  63. INT
  64. QuotaControl(
  65. IN PWSTR Drive,
  66. IN ULONG QuotaControlBits
  67. )
  68. {
  69. HANDLE Handle = INVALID_HANDLE_VALUE;
  70. NTSTATUS Status;
  71. IO_STATUS_BLOCK IoStatus;
  72. FILE_FS_CONTROL_INFORMATION ControlInfo;
  73. INT ExitCode = EXIT_CODE_SUCCESS;
  74. do {
  75. if (!IsVolumeLocalNTFS( Drive[0] )) {
  76. DisplayMsg( MSG_NTFS_REQUIRED );
  77. ExitCode = EXIT_CODE_FAILURE;
  78. break;
  79. }
  80. Handle = QuotaOpenVolume( Drive );
  81. if (Handle == INVALID_HANDLE_VALUE) {
  82. ExitCode = EXIT_CODE_FAILURE;
  83. break;
  84. }
  85. //
  86. // get the current state of quota tracking on this volume
  87. //
  88. Status = NtQueryVolumeInformationFile(
  89. Handle,
  90. &IoStatus,
  91. &ControlInfo,
  92. sizeof( ControlInfo ),
  93. FileFsControlInformation
  94. );
  95. if (!NT_SUCCESS( Status )) {
  96. DisplayErrorMsg( RtlNtStatusToDosError( Status ));
  97. ExitCode = EXIT_CODE_FAILURE;
  98. break;
  99. }
  100. //
  101. // Set in the new control bits
  102. //
  103. ControlInfo.FileSystemControlFlags &= ~FILE_VC_QUOTA_MASK;
  104. ControlInfo.FileSystemControlFlags |= QuotaControlBits;
  105. //
  106. // Set the control info back onto the volume
  107. //
  108. Status = NtSetVolumeInformationFile(
  109. Handle,
  110. &IoStatus,
  111. &ControlInfo,
  112. sizeof( ControlInfo ),
  113. FileFsControlInformation
  114. );
  115. if (!NT_SUCCESS( Status )) {
  116. DisplayErrorMsg( RtlNtStatusToDosError( Status ));
  117. ExitCode = EXIT_CODE_FAILURE;
  118. break;
  119. }
  120. } while (FALSE);
  121. if (Handle != INVALID_HANDLE_VALUE) {
  122. CloseHandle( Handle );
  123. }
  124. return ExitCode;
  125. }
  126. INT
  127. DisableQuota(
  128. IN INT argc,
  129. IN PWSTR argv[]
  130. )
  131. /*++
  132. Routine Description:
  133. Disables quotas on a specified volume
  134. Arguments:
  135. argc - The argument count, should be 1
  136. argv - Array of strings, the first one must be a drive
  137. Return Value:
  138. None
  139. --*/
  140. {
  141. if (argc != 1) {
  142. DisplayMsg( MSG_USAGE_QUOTA_DISABLE );
  143. if (argc != 0) {
  144. return EXIT_CODE_FAILURE;
  145. } else {
  146. return EXIT_CODE_SUCCESS;
  147. }
  148. }
  149. return QuotaControl( argv[0], FILE_VC_QUOTA_NONE );
  150. }
  151. INT
  152. TrackQuota(
  153. IN INT argc,
  154. IN PWSTR argv[]
  155. )
  156. /*++
  157. Routine Description:
  158. Tracks quotas on a specified volume
  159. Arguments:
  160. argc - The argument count, should be 1
  161. argv - Array of strings, the first one must be a drive
  162. Return Value:
  163. None
  164. --*/
  165. {
  166. if (argc != 1) {
  167. DisplayMsg( MSG_USAGE_QUOTA_TRACK );
  168. if (argc != 0) {
  169. return EXIT_CODE_FAILURE;
  170. } else {
  171. return EXIT_CODE_SUCCESS;
  172. }
  173. }
  174. return QuotaControl( argv[0], FILE_VC_QUOTA_TRACK );
  175. }
  176. INT
  177. EnforceQuota(
  178. IN INT argc,
  179. IN PWSTR argv[]
  180. )
  181. /*++
  182. Routine Description:
  183. Enforces quotas on a specified volume
  184. Arguments:
  185. argc - The argument count, should be 1
  186. argv - Array of strings, the first one must be a drive
  187. Return Value:
  188. None
  189. --*/
  190. {
  191. if (argc != 1) {
  192. DisplayMsg( MSG_USAGE_QUOTA_ENFORCE );
  193. if (argc != 0) {
  194. return EXIT_CODE_FAILURE;
  195. } else {
  196. return EXIT_CODE_SUCCESS;
  197. }
  198. }
  199. return QuotaControl( argv[0], FILE_VC_QUOTA_ENFORCE );
  200. }
  201. INT
  202. GetDiskQuotaViolation(
  203. IN INT argc,
  204. IN PWSTR argv[]
  205. )
  206. /*++
  207. Routine Description:
  208. This is the routine for querying the disk quota violation.
  209. Arguments:
  210. argc - The argument count.
  211. argv - Array of strings of the form:
  212. ' fscutl getdskqv '
  213. Return Value:
  214. None
  215. --*/
  216. {
  217. HANDLE handle = NULL;
  218. EVENTLOGRECORD *pevlr, *ptr;
  219. PWCHAR EventString;
  220. DWORD dwRead;
  221. DWORD dwNeeded;
  222. BOOLEAN flag = TRUE;
  223. BOOL Status;
  224. PSID psid;
  225. SID_NAME_USE Use;
  226. WCHAR Name[MAX_PATH];
  227. DWORD dwNameSize;
  228. WCHAR Domain[MAX_PATH];
  229. DWORD dwDomainSize;
  230. WCHAR Log[2][16] = { L"System", L"Application" };
  231. WORD index;
  232. INT ExitCode = EXIT_CODE_SUCCESS;
  233. try {
  234. if (argc != 0) {
  235. DisplayMsg( MSG_USAGE_QUOTA_VIOLATIONS );
  236. if (argc != 0) {
  237. ExitCode = EXIT_CODE_FAILURE;
  238. }
  239. leave;
  240. }
  241. for ( index = 0 ; index < 2 ; index++ ) {
  242. handle = OpenEventLog( NULL, Log[index] );
  243. if ( handle == NULL ) {
  244. DisplayMsg( MSG_COULD_NOT_OPEN_EVENTLOG );
  245. DisplayError();
  246. ExitCode = EXIT_CODE_FAILURE;
  247. leave;
  248. }
  249. ptr = pevlr = (EVENTLOGRECORD *) malloc (BUFFER_SIZE);
  250. DisplayMsg( MSG_SEARCHING_EVENTLOG, Log[index] );
  251. while(ReadEventLog(
  252. handle,
  253. EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ,
  254. 0,
  255. pevlr,
  256. BUFFER_SIZE,
  257. &dwRead,
  258. &dwNeeded))
  259. {
  260. while(dwRead > 0) {
  261. if (pevlr->EventID == IO_FILE_QUOTA_THRESHOLD || pevlr->EventID == IO_FILE_QUOTA_LIMIT) {
  262. flag = FALSE;
  263. switch(pevlr->EventID) {
  264. case IO_FILE_QUOTA_THRESHOLD :
  265. DisplayMsg( MSG_QUOTA_THREASHOLD );
  266. break;
  267. case IO_FILE_QUOTA_LIMIT:
  268. DisplayMsg( MSG_QUOTA_LIMIT );
  269. break;
  270. }
  271. DisplayMsg( MSG_EVENT_ID, pevlr->EventID );
  272. switch(pevlr->EventType) {
  273. case EVENTLOG_ERROR_TYPE:
  274. DisplayMsg( MSG_EVENT_TYPE_ERROR );
  275. break;
  276. case EVENTLOG_WARNING_TYPE:
  277. DisplayMsg( MSG_EVENT_TYPE_WARNING );
  278. break;
  279. case EVENTLOG_INFORMATION_TYPE:
  280. DisplayMsg( MSG_EVENT_TYPE_INFORMATION );
  281. break;
  282. case EVENTLOG_AUDIT_SUCCESS:
  283. DisplayMsg( MSG_EVENT_TYPE_AUDIT_SUCCESS );
  284. break;
  285. case EVENTLOG_AUDIT_FAILURE:
  286. DisplayMsg( MSG_EVENT_TYPE_AUDIT_FAILURE );
  287. break;
  288. }
  289. DisplayMsg( MSG_EVENT_CATEGORY, pevlr->EventCategory );
  290. DisplayMsg( MSG_EVENT_SOURCE, (LPWSTR)((LPBYTE) pevlr + sizeof(EVENTLOGRECORD)) );
  291. if (pevlr->UserSidOffset > 0) {
  292. psid = (PSID) ( (PBYTE)pevlr + pevlr->UserSidOffset );
  293. dwNameSize = MAX_PATH;
  294. dwDomainSize = MAX_PATH;
  295. Status = LookupAccountSid(
  296. NULL,
  297. psid,
  298. Name,
  299. &dwNameSize,
  300. Domain,
  301. &dwDomainSize,
  302. &Use
  303. );
  304. if (Status) {
  305. DisplayMsg( MSG_USERNAME, Domain, Name );
  306. }
  307. }
  308. if (pevlr->NumStrings == 2) {
  309. EventString = (PWCHAR) ((PBYTE)pevlr + pevlr->StringOffset);
  310. EventString += wcslen( EventString ) + 1;
  311. DisplayMsg( MSG_EVENT_DATA, EventString );
  312. }
  313. }
  314. dwRead -= pevlr->Length;
  315. pevlr = (EVENTLOGRECORD *)((PBYTE) pevlr + pevlr->Length);
  316. }
  317. pevlr = ptr;
  318. }
  319. CloseEventLog(handle);
  320. handle = NULL;
  321. }
  322. if (flag) {
  323. DisplayMsg( MSG_GOOD_QUOTA );
  324. }
  325. } finally {
  326. if (handle != NULL) {
  327. CloseHandle( handle );
  328. }
  329. }
  330. return ExitCode;
  331. }
  332. PWSTR
  333. FileTimeToString(
  334. PLARGE_INTEGER FileTime
  335. )
  336. {
  337. ULONG ElapsedSeconds;
  338. if (RtlTimeToSecondsSince1970( FileTime, &ElapsedSeconds )) {
  339. PWSTR TimeString = _wctime( (time_t*)&ElapsedSeconds );
  340. if (TimeString) {
  341. TimeString[wcslen(TimeString)-1] = 0;
  342. }
  343. return TimeString;
  344. }
  345. return L"";
  346. }
  347. BOOL
  348. GetUserSid(
  349. PWSTR UserName,
  350. PFILE_QUOTA_INFORMATION *QuotaInfoPtr,
  351. PFILE_GET_QUOTA_INFORMATION *SidListPtr
  352. )
  353. {
  354. WCHAR Domain[128];
  355. ULONG DomainLength;
  356. SID_NAME_USE SidNameUse;
  357. *QuotaInfoPtr = (PFILE_QUOTA_INFORMATION) ((PCHAR) *QuotaInfoPtr + (*QuotaInfoPtr)->NextEntryOffset);
  358. *SidListPtr = (PFILE_GET_QUOTA_INFORMATION) ((PCHAR) *SidListPtr + (*SidListPtr)->NextEntryOffset);
  359. (*QuotaInfoPtr)->SidLength = SID_MAX_LENGTH;
  360. DomainLength = sizeof(Domain);
  361. if (!LookupAccountName(
  362. NULL,
  363. UserName,
  364. &(*QuotaInfoPtr)->Sid,
  365. &(*QuotaInfoPtr)->SidLength,
  366. Domain,
  367. &DomainLength,
  368. &SidNameUse))
  369. {
  370. DomainLength = GetLastError();
  371. return FALSE;
  372. }
  373. //
  374. // Initialize the values to something resonable.
  375. //
  376. (*QuotaInfoPtr)->QuotaThreshold.QuadPart = ~0;
  377. (*QuotaInfoPtr)->QuotaLimit.QuadPart = ~0;
  378. (*QuotaInfoPtr)->SidLength = RtlLengthSid( &(*QuotaInfoPtr)->Sid);
  379. (*QuotaInfoPtr)->NextEntryOffset =
  380. FIELD_OFFSET( FILE_QUOTA_INFORMATION, Sid ) +
  381. QuadAlign((*QuotaInfoPtr)->SidLength);
  382. memcpy( &(*SidListPtr)->Sid, &(*QuotaInfoPtr)->Sid, (*QuotaInfoPtr)->SidLength);
  383. (*SidListPtr)->SidLength = (*QuotaInfoPtr)->SidLength;
  384. (*SidListPtr)->NextEntryOffset =
  385. FIELD_OFFSET( FILE_GET_QUOTA_INFORMATION, Sid ) +
  386. QuadAlign((*SidListPtr)->SidLength);
  387. return TRUE;
  388. }
  389. BOOL
  390. DumpVolumeQuotaInfo(
  391. IN HANDLE hFile,
  392. IN BOOL DisplayAlways
  393. )
  394. {
  395. NTSTATUS Status;
  396. IO_STATUS_BLOCK IoStatus;
  397. FILE_FS_CONTROL_INFORMATION TempControlInfo = {0};
  398. ULONG StatusId;
  399. ULONG LoggingId;
  400. ULONG ValueId;
  401. Status = NtQueryVolumeInformationFile(
  402. hFile,
  403. &IoStatus,
  404. &TempControlInfo,
  405. sizeof(FILE_FS_CONTROL_INFORMATION),
  406. FileFsControlInformation
  407. );
  408. //
  409. // If quotas aren't enforced or tracked, then quotas must be disabled.
  410. //
  411. if ((TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_MASK) == FILE_VC_QUOTA_NONE) {
  412. StatusId = MSG_QUOTA_STATUS_DISABLED;
  413. } else if ((TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_MASK) == FILE_VC_QUOTA_TRACK) {
  414. StatusId = MSG_QUOTA_STATUS_TRACKING;
  415. } else {
  416. ASSERT( TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_ENFORCE );
  417. StatusId = MSG_QUOTA_STATUS_ENFORCE;
  418. }
  419. if (!DisplayAlways) {
  420. return StatusId != MSG_QUOTA_STATUS_DISABLED;
  421. }
  422. switch (TempControlInfo.FileSystemControlFlags & (FILE_VC_LOG_QUOTA_LIMIT | FILE_VC_LOG_QUOTA_THRESHOLD)) {
  423. case FILE_VC_LOG_QUOTA_LIMIT:
  424. LoggingId = MSG_QUOTA_LOGGING_LIMITS;
  425. break;
  426. case FILE_VC_LOG_QUOTA_THRESHOLD:
  427. LoggingId = MSG_QUOTA_LOGGING_THRESH;
  428. break;
  429. case FILE_VC_LOG_QUOTA_LIMIT | FILE_VC_LOG_QUOTA_THRESHOLD:
  430. LoggingId = MSG_QUOTA_LOGGING_BOTH;
  431. break;
  432. case 0:
  433. LoggingId = MSG_QUOTA_LOGGING_EVENTS;
  434. break;
  435. }
  436. if (TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_MASK) {
  437. if (TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTAS_INCOMPLETE) {
  438. ValueId = MSG_QUOTA_VALUES_INCOMPLETE;
  439. } else {
  440. ValueId = MSG_QUOTA_VALUES_GOOD;
  441. }
  442. } else {
  443. ValueId = MSG_QUOTA_VALUES_GOOD;
  444. }
  445. DisplayMsg( MSG_USAGE_QUOTA_VOLUME_INFO, TempControlInfo.FileSystemControlFlags );
  446. DisplayMsg( StatusId );
  447. DisplayMsg( LoggingId );
  448. DisplayMsg( ValueId );
  449. DisplayMsg( MSG_USAGE_QUOTA_LIMITS,
  450. QuadToPaddedHexText( TempControlInfo.DefaultQuotaThreshold.QuadPart ),
  451. QuadToPaddedHexText( TempControlInfo.DefaultQuotaLimit.QuadPart )
  452. );
  453. return TRUE;
  454. }
  455. VOID
  456. DumpQuota (
  457. IN PFILE_QUOTA_INFORMATION FileQuotaInfo,
  458. IN PWSTR ServerName
  459. )
  460. {
  461. NTSTATUS Status;
  462. SID_NAME_USE SidNameUse;
  463. ULONG AccountLength, DomainLength;
  464. WCHAR AccountName[128];
  465. WCHAR DomainName[128];
  466. UNICODE_STRING String;
  467. AccountLength = sizeof(AccountName) - 1;
  468. DomainLength = sizeof(DomainName) - 1;
  469. if (FileQuotaInfo->SidLength == 0) {
  470. DisplayMsg( MSG_QUOTA_DUMP_DEFAULT );
  471. } else if (LookupAccountSid(
  472. ServerName,
  473. &FileQuotaInfo->Sid,
  474. AccountName,
  475. &AccountLength,
  476. DomainName,
  477. &DomainLength,
  478. &SidNameUse))
  479. {
  480. PWSTR String;
  481. AccountName[AccountLength] = 0;
  482. DomainName[DomainLength] = 0;
  483. DisplayMsg( MSG_QUOTA_SID_USER+SidNameUse-1, DomainName, AccountName );
  484. } else {
  485. DisplayError( );
  486. }
  487. DisplayMsg(
  488. MSG_QUOTA_DUMP_INFO,
  489. FileTimeToString(&FileQuotaInfo->ChangeTime),
  490. QuadToDecimalText( FileQuotaInfo->QuotaUsed.QuadPart ),
  491. QuadToDecimalText( FileQuotaInfo->QuotaThreshold.QuadPart ),
  492. QuadToDecimalText( FileQuotaInfo->QuotaLimit.QuadPart )
  493. );
  494. }
  495. INT
  496. QueryDiskQuota(
  497. IN INT argc,
  498. IN PWSTR argv[]
  499. )
  500. {
  501. NTSTATUS Status;
  502. HANDLE hFile;
  503. IO_STATUS_BLOCK IoStatus;
  504. FILE_QUOTA_INFORMATION QuotaInfo[STRUCT_COUNT(10, FILE_QUOTA_INFORMATION, 4)];
  505. INT ExitCode = EXIT_CODE_SUCCESS;
  506. if (argc != 1) {
  507. DisplayMsg( MSG_USAGE_QUOTA_QUERY, argv[1] );
  508. if (argc != 0) {
  509. return EXIT_CODE_FAILURE;
  510. } else {
  511. return EXIT_CODE_SUCCESS;
  512. }
  513. }
  514. if (!IsVolumeLocalNTFS( argv[0][0] )) {
  515. DisplayMsg( MSG_NTFS_REQUIRED );
  516. return EXIT_CODE_FAILURE;
  517. }
  518. hFile = QuotaOpenVolume( argv[0] );
  519. if (hFile == INVALID_HANDLE_VALUE) {
  520. return EXIT_CODE_FAILURE;
  521. }
  522. if (!DumpVolumeQuotaInfo( hFile, FALSE )) {
  523. DisplayMsg( MSG_USAGE_QUOTA_REQUIRED, argv[0] );
  524. CloseHandle( hFile );
  525. return EXIT_CODE_FAILURE;
  526. }
  527. DumpVolumeQuotaInfo( hFile, TRUE );
  528. while (TRUE) {
  529. Status = NtQueryQuotaInformationFile(
  530. hFile, // File Handle
  531. &IoStatus, // IO status block
  532. QuotaInfo, // Buffer
  533. sizeof(QuotaInfo), // Length
  534. TRUE, // Return Single Entry
  535. NULL, // SidList
  536. 0, // SidListLength
  537. NULL, // StartSid
  538. FALSE // RestartScan
  539. );
  540. if (!NT_SUCCESS( Status )) {
  541. if (Status != STATUS_NO_MORE_ENTRIES) {
  542. DisplayErrorMsg( RtlNtStatusToDosError( Status ));
  543. ExitCode = EXIT_CODE_FAILURE;
  544. }
  545. break;
  546. }
  547. DumpQuota( QuotaInfo, NULL );
  548. }
  549. CloseHandle( hFile );
  550. return ExitCode;
  551. }
  552. INT
  553. ChangeDiskQuota(
  554. IN INT argc,
  555. IN PWSTR argv[]
  556. )
  557. {
  558. NTSTATUS Status;
  559. HANDLE hFile;
  560. IO_STATUS_BLOCK IoStatus;
  561. FILE_QUOTA_INFORMATION QuotaInfo[STRUCT_COUNT(10, FILE_QUOTA_INFORMATION, 4)];
  562. FILE_GET_QUOTA_INFORMATION SidList[STRUCT_COUNT(10, FILE_GET_QUOTA_INFORMATION, 4)];
  563. PFILE_QUOTA_INFORMATION QuotaInfoPtr;
  564. PFILE_GET_QUOTA_INFORMATION SidListPtr;
  565. ULONG BufferSize;
  566. ULONG SidListLength;
  567. PWSTR EndPtr;
  568. if (argc != 4) {
  569. DisplayMsg( MSG_USAGE_QUOTA_MODIFY );
  570. if (argc != 0) {
  571. return EXIT_CODE_FAILURE;
  572. } else {
  573. return EXIT_CODE_SUCCESS;
  574. }
  575. }
  576. if (!IsVolumeLocalNTFS( argv[0][0] )) {
  577. DisplayMsg( MSG_NTFS_REQUIRED );
  578. return EXIT_CODE_FAILURE;
  579. }
  580. RtlZeroMemory(&QuotaInfo, sizeof(QuotaInfo));
  581. QuotaInfoPtr = QuotaInfo;
  582. RtlZeroMemory(&SidList, sizeof(SidList));
  583. SidListPtr = SidList;
  584. if (!GetUserSid( argv[3], &QuotaInfoPtr, &SidListPtr )) {
  585. DisplayError();
  586. return EXIT_CODE_FAILURE;
  587. }
  588. QuotaInfoPtr->QuotaThreshold.QuadPart = My_wcstoui64( argv[1], &EndPtr, 0 );
  589. if (UnsignedI64NumberCheck( QuotaInfoPtr->QuotaThreshold.QuadPart, EndPtr )) {
  590. DisplayMsg( MSG_USAGE_QUOTA_MODIFY );
  591. return EXIT_CODE_FAILURE;
  592. }
  593. QuotaInfoPtr->QuotaLimit.QuadPart = My_wcstoui64( argv[2], &EndPtr, 0 );
  594. if (UnsignedI64NumberCheck( QuotaInfoPtr->QuotaLimit.QuadPart, EndPtr )) {
  595. DisplayMsg( MSG_USAGE_QUOTA_MODIFY );
  596. return EXIT_CODE_FAILURE;
  597. }
  598. //
  599. // Terminate the list.
  600. //
  601. BufferSize = (ULONG)((PCHAR) QuotaInfoPtr - (PCHAR) QuotaInfo + QuotaInfoPtr->NextEntryOffset);
  602. QuotaInfoPtr->NextEntryOffset = 0;
  603. SidListLength = (ULONG)((PCHAR) SidListPtr - (PCHAR) SidList + SidListPtr->NextEntryOffset);
  604. SidListPtr->NextEntryOffset = 0;
  605. SidListPtr = SidList;
  606. //
  607. // Change it
  608. //
  609. hFile = QuotaOpenVolume( argv[0] );
  610. if (hFile == INVALID_HANDLE_VALUE) {
  611. DisplayError();
  612. return EXIT_CODE_FAILURE;
  613. }
  614. Status = NtSetQuotaInformationFile(
  615. hFile,
  616. &IoStatus,
  617. &QuotaInfo,
  618. sizeof(QuotaInfo)
  619. );
  620. if (!NT_SUCCESS( Status )) {
  621. DisplayErrorMsg( RtlNtStatusToDosError( Status ));
  622. CloseHandle( hFile );
  623. return EXIT_CODE_FAILURE;
  624. }
  625. CloseHandle( hFile );
  626. return EXIT_CODE_SUCCESS;
  627. }