WindowsXP-SP1/base/fs/ntfs/tests/quota.c
2020-09-30 16:53:49 +02:00

834 lines
25 KiB
C

#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <windows.h>
#define QuadAlign(n) (((n) + (sizeof(LONGLONG) - 1)) & ~(sizeof(LONGLONG) - 1))
#define DwordAlign(n)(((n) + (sizeof(ULONG) - 1)) & ~(sizeof(ULONG) - 1))
#define STRUCT_COUNT(n, type, name_length) \
((((n) * QuadAlign(sizeof(type)) + ((name_length) * sizeof(WCHAR))) + \
sizeof(type) - 1) / \
sizeof(type))
#define SID_MAX_LENGTH \
(FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * SID_MAX_SUB_AUTHORITIES)
#define DISK_EVENT_MODULE "System"
#define IO_FILE_QUOTA_THRESHOLD ((NTSTATUS)0x40040024L)
#define IO_FILE_QUOTA_LIMIT ((NTSTATUS)0x80040025L)
VOID
DumpQuota (
IN PFILE_QUOTA_INFORMATION pfqi,
IN PCHAR SeverName
);
CHAR *
FileTimeToString(
FILETIME *pft
);
VOID
PrintError(
ULONG ErrorCode
);
VOID
Usage();
BOOLEAN QuickSid;
VOID
STDMETHODVCALLTYPE
main(
int Argc,
char *Argv[]
)
{
HANDLE FileHandle;
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
ANSI_STRING DiskName;
UNICODE_STRING NameString;
IO_STATUS_BLOCK IoStatus;
ULONG BufferSize;
ULONG SidListLength;
LONG i;
PWCHAR Wstr;
PEVENTLOGRECORD EventLogRecord;
FILE_QUOTA_INFORMATION QuotaInfo[STRUCT_COUNT(10, FILE_QUOTA_INFORMATION, 4)];
FILE_QUOTA_INFORMATION TempQuotaInfo[STRUCT_COUNT(1, FILE_QUOTA_INFORMATION, 32)];
FILE_GET_QUOTA_INFORMATION SidList[STRUCT_COUNT(10, FILE_GET_QUOTA_INFORMATION, 4)];
PFILE_GET_QUOTA_INFORMATION SidListPtr;
PFILE_QUOTA_INFORMATION QuotaInfoPtr;
FILE_FS_CONTROL_INFORMATION ControlInfo;
FILE_FS_CONTROL_INFORMATION TempControlInfo;
PCHAR ServerName = NULL;
SID_NAME_USE SidNameUse;
LARGE_INTEGER TempLargeInt;
ULONG ErrorCode;
ULONG DomainLength;
CHAR Domain[100];
PCHAR TempPtr;
BOOLEAN UserGiven = 0;
BOOLEAN DriveLetter = 0;
BOOLEAN EventLog = 0;
BOOLEAN SettingDefault = 0;
BOOLEAN DefaultGiven = 0;
BOOLEAN DeletingUser = 0;
struct {
UCHAR DefaultLimit : 1;
UCHAR DefaultThreshold : 1;
UCHAR Flags : 1;
} DefaultFlags = { 0, 0, 0 };
if (Argc < 2) {
printf ( "Processor feature is %d\n", IsProcessorFeaturePresent(0));
Usage();
exit(1);
}
RtlZeroMemory(&QuotaInfo, sizeof(QuotaInfo));
QuotaInfoPtr = QuotaInfo;
RtlZeroMemory(&SidList, sizeof(SidList));
SidListPtr = SidList;
RtlInitString( &DiskName, "\\DosDevices\\d:\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION" );
RtlAnsiStringToUnicodeString( &NameString, &DiskName, TRUE );
// Look for the d and repleace it with the requested Argument.
for (Wstr = NameString.Buffer; *Wstr != L'd'; Wstr++);
for (i = 1; i < Argc; i++) {
if (*Argv[i] != '-') {
if (DriveLetter || !isalpha(*Argv[i])) {
Usage();
exit(1);
}
TempPtr = Argv[i];
*Wstr = RtlAnsiCharToUnicodeChar( &TempPtr );
DriveLetter++;
continue;
}
switch (Argv[i][1]) {
case 'd':
DefaultGiven = 1;
SettingDefault = 1;
break;
case 'e':
if (EventLog) {
Usage();
exit(1);
}
if (Argv[i][2] == '\0') {
i++;
if (i < Argc && Argv[i][0] == '\\') {
ServerName = Argv[i];
}
} else {
ServerName = &Argv[i][2];
}
EventLog++;
break;
case 'u':
QuotaInfoPtr = (PFILE_QUOTA_INFORMATION) ((PCHAR) QuotaInfoPtr +
QuotaInfoPtr->NextEntryOffset);
SidListPtr = (PFILE_GET_QUOTA_INFORMATION) ((PCHAR) SidListPtr +
SidListPtr->NextEntryOffset);
if (Argv[i][2] == '\0') {
i++;
if (i >= Argc) {
printf("%s: Missing user name\n", Argv[0] );
exit(1);
}
TempPtr = Argv[i];
} else {
TempPtr = Argv[i];
TempPtr += 2;
}
QuotaInfoPtr->SidLength = SID_MAX_LENGTH;
DomainLength = sizeof(Domain);
if (!LookupAccountName( NULL,
TempPtr,
&QuotaInfoPtr->Sid,
&QuotaInfoPtr->SidLength,
Domain,
&DomainLength,
&SidNameUse)) {
printf("%s: Bad acccount name %s. Error = %d\n",
Argv[0],
TempPtr,
ErrorCode = GetLastError());
PrintError( ErrorCode );
exit(1);
}
//
// Initialize the values to something resonable.
//
QuotaInfoPtr->QuotaThreshold.QuadPart = ~0I64;
QuotaInfoPtr->QuotaLimit.QuadPart = ~0I64;
QuotaInfoPtr->SidLength = RtlLengthSid( &QuotaInfoPtr->Sid);
QuotaInfoPtr->NextEntryOffset =
FIELD_OFFSET( FILE_QUOTA_INFORMATION, Sid ) +
QuadAlign(QuotaInfoPtr->SidLength);
memcpy( &SidListPtr->Sid, &QuotaInfoPtr->Sid, QuotaInfoPtr->SidLength);
SidListPtr->SidLength = QuotaInfoPtr->SidLength;
SidListPtr->NextEntryOffset =
FIELD_OFFSET( FILE_GET_QUOTA_INFORMATION, Sid ) +
QuadAlign(SidListPtr->SidLength);
SettingDefault = 0;
UserGiven++;
break;
case 't':
if (Argv[i][2] == '\0') {
i++;
if (i >= Argc) {
printf("%s: Missing Argument\n", Argv[0] );
exit(1);
}
TempPtr = Argv[i];
} else {
TempPtr = Argv[i];
TempPtr += 2;
}
if (!sscanf( TempPtr, "%I64i", &TempLargeInt)) {
printf("%s: Missing threshold value\n", Argv[0] );
exit(1);
}
if (SettingDefault) {
ControlInfo.DefaultQuotaThreshold = TempLargeInt;
DefaultFlags.DefaultThreshold = TRUE;
} else {
QuotaInfoPtr->QuotaThreshold = TempLargeInt;
}
break;
case 'l':
if (Argv[i][2] == '\0') {
i++;
if (i >= Argc) {
printf("%s: Missing limit value\n", Argv[0] );
exit(1);
}
TempPtr = Argv[i];
} else {
TempPtr = Argv[i];
TempPtr += 2;
}
if (!sscanf( TempPtr, "%I64i", &TempLargeInt)) {
printf("%s: Missing value\n", Argv[0] );
exit(1);
}
if (SettingDefault) {
ControlInfo.DefaultQuotaLimit = TempLargeInt;
DefaultFlags.DefaultLimit = TRUE;
} else {
QuotaInfoPtr->QuotaLimit = TempLargeInt;
if (TempLargeInt.QuadPart == -2i64) {
DeletingUser = TRUE;
}
}
break;
case 'q':
QuickSid++;
break;
case 'f':
if (Argv[i][2] == '\0') {
i++;
if (i >= Argc) {
printf("%s: Missing flag setting\n", Argv[0] );
exit(1);
}
TempPtr = Argv[i];
} else {
TempPtr = Argv[i];
TempPtr += 2;
}
switch (*TempPtr) {
case 'e':
ControlInfo.FileSystemControlFlags |= FILE_VC_QUOTA_ENFORCE;
break;
case 't':
ControlInfo.FileSystemControlFlags |= FILE_VC_QUOTA_TRACK;
break;
case 'd':
ControlInfo.FileSystemControlFlags &= ~(FILE_VC_QUOTA_MASK |
FILE_VC_LOG_QUOTA_LIMIT |
FILE_VC_LOG_QUOTA_THRESHOLD);
break;
default:
printf("%s: Invalid or missing flag setting.\n", Argv[0] );
Usage();
exit(1);
}
while (*++TempPtr != '\0') {
switch (*TempPtr) {
case 'l':
ControlInfo.FileSystemControlFlags |= FILE_VC_LOG_QUOTA_LIMIT;
break;
case 't':
ControlInfo.FileSystemControlFlags |= FILE_VC_LOG_QUOTA_THRESHOLD;
break;
default:
printf("%s: Invalid flag setting.\n", Argv[0] );
Usage();
exit(1);
}
}
DefaultGiven = 1;
DefaultFlags.Flags = TRUE;
break;
default:
printf("%s: Invalid or missing flag setting.\n", Argv[0] );
case '?':
Usage();
exit(1);
break;
}
}
if (DriveLetter == 0 && EventLog == 0 ) {
printf("%s: Missing drive-letter\n", Argv[0] );
}
if (EventLog &&
(DriveLetter || UserGiven)) {
Usage();
exit(1);
}
if (EventLog) {
//
// Open the event log and read andy events.
//
FileHandle = OpenEventLog( ServerName, DISK_EVENT_MODULE );
if (FileHandle == NULL) {
printf("%s: Event log open failed. %s. Error = %d\n",
Argv[0],
ServerName == NULL ? "Local machine" : ServerName,
ErrorCode = GetLastError());
PrintError( ErrorCode );
exit(1);
}
while (ReadEventLog( FileHandle,
EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
0,
QuotaInfo,
sizeof(QuotaInfo),
&BufferSize,
&i )) {
if (BufferSize == 0) {
break;
}
for (EventLogRecord = (PEVENTLOGRECORD) QuotaInfo;
(PCHAR) EventLogRecord < (PCHAR) QuotaInfo + BufferSize;
EventLogRecord = (PEVENTLOGRECORD)((PCHAR) EventLogRecord +
EventLogRecord->Length)) {
if (EventLogRecord->EventID == IO_FILE_QUOTA_THRESHOLD) {
printf( "Quota threshold event at: %s",
ctime( &EventLogRecord->TimeGenerated ));
} else if (EventLogRecord->EventID == IO_FILE_QUOTA_LIMIT) {
printf( "Quota limit event at: %s",
ctime( &EventLogRecord->TimeGenerated ));
} else {
continue;
}
//
// Look for the device name. It is the second string.
//
TempPtr = ((PCHAR) EventLogRecord +
EventLogRecord->StringOffset);
printf( " on device %s\n", TempPtr );
TempPtr = ((PCHAR) EventLogRecord +
EventLogRecord->DataOffset +
FIELD_OFFSET( IO_ERROR_LOG_PACKET, DumpData ));
//
// Need to align the buffer.
//
RtlCopyMemory( TempQuotaInfo,
TempPtr,
EventLogRecord->DataLength -
FIELD_OFFSET( IO_ERROR_LOG_PACKET, DumpData ));
DumpQuota( TempQuotaInfo, ServerName );
}
}
ErrorCode = GetLastError();
if (ErrorCode =! ERROR_HANDLE_EOF) {
printf("%s: Event log read failed. Error = %d\n",
Argv[0],
ErrorCode);
PrintError( ErrorCode );
}
CloseEventLog( FileHandle );
exit(0);
}
//
// Terminate the list.
//
BufferSize = (PCHAR) QuotaInfoPtr - (PCHAR) QuotaInfo +
QuotaInfoPtr->NextEntryOffset;
QuotaInfoPtr->NextEntryOffset = 0;
SidListLength = (PCHAR) SidListPtr - (PCHAR) SidList +
SidListPtr->NextEntryOffset;
SidListPtr->NextEntryOffset = 0;
SidListPtr = SidList;
InitializeObjectAttributes( &ObjectAttributes,
&NameString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );
Status = NtOpenFile( &FileHandle,
FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
&ObjectAttributes,
&IoStatus,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_ALERT | FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS( Status )) {
printf( "Error opening input file %S; error was: %lx\n", NameString.Buffer, Status );
PrintError( Status );
exit(1);
}
if (DefaultGiven) {
Status = NtQueryVolumeInformationFile( FileHandle,
&IoStatus,
&TempControlInfo,
sizeof( FILE_FS_CONTROL_INFORMATION ),
FileFsControlInformation );
if (!NT_SUCCESS( Status )) {
printf( "Error NtQueryVolumeInformationFile; error was %lx\n", Status );
PrintError( Status );
exit(1);
}
if (DefaultFlags.Flags) {
TempControlInfo.FileSystemControlFlags &= ~FILE_VC_QUOTA_MASK;
TempControlInfo.FileSystemControlFlags |=
ControlInfo.FileSystemControlFlags;
}
if (DefaultFlags.DefaultLimit) {
TempControlInfo.DefaultQuotaLimit = ControlInfo.DefaultQuotaLimit;
}
if (DefaultFlags.DefaultThreshold) {
TempControlInfo.DefaultQuotaThreshold = ControlInfo.DefaultQuotaThreshold;
}
Status = NtSetVolumeInformationFile( FileHandle,
&IoStatus,
&TempControlInfo,
sizeof( FILE_FS_CONTROL_INFORMATION ),
FileFsControlInformation );
if (!NT_SUCCESS( Status )) {
printf( "Error NtSetVolumeInformationFile; error was %lx\n", Status );
PrintError( Status );
exit(1);
}
}
Status = NtQueryVolumeInformationFile( FileHandle,
&IoStatus,
&TempControlInfo,
sizeof( FILE_FS_CONTROL_INFORMATION ),
FileFsControlInformation );
printf( "FileSystemControlFlags = %8lx\n", TempControlInfo.FileSystemControlFlags);
if ((TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_MASK) ==
FILE_VC_QUOTA_NONE) {
TempPtr = "Quotas are disabled on this volume";
} else if ((TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_MASK) ==
FILE_VC_QUOTA_TRACK) {
TempPtr = "Quota tracking is enabled on this volume";
}else if (TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_ENFORCE) {
TempPtr = "Quota tracking and enforment is enabled on this volume";
}
printf("%s.\n", TempPtr);
switch (TempControlInfo.FileSystemControlFlags &
(FILE_VC_LOG_QUOTA_LIMIT | FILE_VC_LOG_QUOTA_THRESHOLD)) {
case FILE_VC_LOG_QUOTA_LIMIT:
printf("Logging enable for quota limits.\n");
break;
case FILE_VC_LOG_QUOTA_THRESHOLD:
printf("Logging enable for quota thresholds.\n");
break;
case FILE_VC_LOG_QUOTA_LIMIT | FILE_VC_LOG_QUOTA_THRESHOLD:
printf("Logging enable for quota limits and threshold.\n");
break;
case 0:
printf("Logging for quota events is not enabled.\n");
break;
}
if (TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_MASK) {
if (TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTAS_INCOMPLETE) {
TempPtr = "The quota values are incomplete.\n";
} else
{
TempPtr = "The quota values are up to date.\n";
}
printf(TempPtr);
}
printf("Default Quota Threshold = %16I64x\n", TempControlInfo.DefaultQuotaThreshold.QuadPart);
printf("Default Quota Limit = %16I64x\n\n", TempControlInfo.DefaultQuotaLimit.QuadPart);
if (UserGiven) {
Status = NtSetQuotaInformationFile( FileHandle,
&IoStatus,
QuotaInfo,
BufferSize );
if (!NT_SUCCESS( Status )) {
printf( "Error NtSetVolumeInformationFile; error was %lx\n", Status );
PrintError( Status );
exit(1);
}
}
if (!UserGiven || DeletingUser) {
SidListPtr = NULL;
SidListLength = 0;
}
do {
Status = NtQueryQuotaInformationFile( FileHandle,
&IoStatus,
QuotaInfo,
sizeof(QuotaInfo),
FALSE,
SidListPtr,
SidListLength,
NULL,
FALSE );
if (!NT_SUCCESS( Status ) && Status != STATUS_NO_MORE_ENTRIES) {
printf( "Error NtQueryVolumeInformationFile; error was %lx\n", Status );
PrintError( Status );
exit(1);
}
QuotaInfoPtr = QuotaInfo;
while (TRUE) {
DumpQuota( QuotaInfoPtr, ServerName );
if (QuotaInfoPtr->NextEntryOffset == 0) {
break;
}
QuotaInfoPtr = (PFILE_QUOTA_INFORMATION) ((PCHAR) QuotaInfoPtr +
QuotaInfoPtr->NextEntryOffset);
}
} while ( Status != STATUS_NO_MORE_ENTRIES );
NtClose( FileHandle );
}
VOID
DumpQuota (
IN PFILE_QUOTA_INFORMATION FileQuotaInfo,
IN PCHAR ServerName
)
{
SID_NAME_USE SidNameUse;
ULONG AccountLength, DomainLength;
ULONG ErrorCode;
char AccountName[128];
char DomainName[128];
UNICODE_STRING String;
NTSTATUS Status;
AccountLength = sizeof(AccountName) - 1;
DomainLength = sizeof(DomainName) - 1;
if (FileQuotaInfo->SidLength == 0) {
printf( "Default quota values \n" );
} else if (QuickSid) {
String.Buffer = (PWCHAR) AccountName;
String.MaximumLength = sizeof( AccountName );
String.Length = 0;
Status = RtlConvertSidToUnicodeString( &String,
&FileQuotaInfo->Sid,
FALSE );
if (!NT_SUCCESS(Status)) {
printf("DumpQuota: RtlConvertSidToUnicodeString failed. Error = %d\n",
Status);
PrintError( Status );
} else {
printf( "SID Value = %S\n", String.Buffer );
}
} else if (LookupAccountSidA(
ServerName,
&FileQuotaInfo->Sid,
AccountName,
&AccountLength,
DomainName,
&DomainLength,
&SidNameUse))
{
char *String;
AccountName[AccountLength] = '\0';
DomainName[DomainLength] = '\0';
switch (SidNameUse)
{
case SidTypeUser: String = "User"; break;
case SidTypeGroup: String = "Group"; break;
case SidTypeDomain: String = "Domain"; break;
case SidTypeAlias: String = "Alias"; break;
case SidTypeWellKnownGroup: String = "WellKnownGroup"; break;
case SidTypeDeletedAccount: String = "DeletedAccount"; break;
case SidTypeInvalid: String = "Invalid"; break;
default: String = "Unknown"; break;
}
printf(
"SID Name = %s\\%s (%s)\n",
DomainName,
AccountName,
String);
} else {
printf("DumpQuota: Bad acccount SID. Error = %d\n",
ErrorCode = GetLastError());
PrintError( ErrorCode );
}
printf("Change time = %s\n", FileTimeToString((PFILETIME) &FileQuotaInfo->ChangeTime));
printf("Quota Used = %16I64x\n", FileQuotaInfo->QuotaUsed.QuadPart);
printf("Quota Threshold = %16I64x\n", FileQuotaInfo->QuotaThreshold.QuadPart);
printf("Quota Limit = %16I64x\n\n", FileQuotaInfo->QuotaLimit.QuadPart);
}
char *Days[] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};
char *Months[] =
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
CHAR *
FileTimeToString(FILETIME *FileTime)
{
FILETIME LocalFileTime;
SYSTEMTIME SystemTime;
static char Buffer[32];
Buffer[0] = '\0';
if (FileTime->dwHighDateTime != 0 || FileTime->dwLowDateTime != 0)
{
if (!FileTimeToLocalFileTime(FileTime, &LocalFileTime) ||
!FileTimeToSystemTime(&LocalFileTime, &SystemTime))
{
return("Time???");
}
sprintf(
Buffer,
"%s %s %2d %2d:%02d:%02d %4d",
Days[SystemTime.wDayOfWeek],
Months[SystemTime.wMonth - 1],
SystemTime.wDay,
SystemTime.wHour,
SystemTime.wMinute,
SystemTime.wSecond,
SystemTime.wYear);
}
return(Buffer);
}
VOID
PrintError(ULONG ErrorCode)
{
UCHAR ErrorBuffer[80];
ULONG Count;
HMODULE FileHandle = NULL;
ULONG Flags = FORMAT_MESSAGE_FROM_SYSTEM;
if (ErrorCode > MAXLONG) {
Flags = FORMAT_MESSAGE_FROM_HMODULE;
FileHandle = LoadLibrary( "ntdll" );
if (FileHandle == NULL) {
ULONG ErrorCode;
printf("PrintError: LoadLibrary filed. Error = %d\n",
ErrorCode = GetLastError());
PrintError( ErrorCode );
}
}
Count = FormatMessage(Flags,
FileHandle,
ErrorCode,
0,
ErrorBuffer,
sizeof(ErrorBuffer),
NULL
);
if (Count != 0) {
printf("Error was: %s\n", ErrorBuffer);
} else {
printf("Format message failed. Error: %d\n", GetLastError());
}
if (FileHandle != NULL) {
FreeLibrary( FileHandle );
}
}
VOID
Usage()
{
printf( "Usage: %s -e [\\ServerName] | drive-letter [-q ] [ -f e|t|d [lt] ] [-d | -u account-name -t Threshold -l Limit] \n", __argv[0] );
printf( " -e [\\ServerName] Print quota events from specified server default is local.\n");
printf( " [-q] Quick print Sids. \n");
printf( " [-f e|t|d[lt] ] Set volume quota flags (For example -f elt ): \n");
printf( " [e]nforce quota limits.\n" );
printf( " [t]rack quota usage.\n" );
printf( " [d]isable quotas.\n" );
printf( " [l]imit events should be logged.\n" );
printf( " [t]threhold events should be logged.\n" );
printf( " [-d] Set default user quota values.\n");
printf( " [-u AccountName] Set quota values for user. \n");
printf( " [-l Limit] Set 64-Bit limit value preivously specified user. \n");
printf( " A limit of -2 indicates a defunct user can be removed. \n");
printf( " [-t Threshold] Set 64-Bit threshold value preivously specified user. \n\n");
printf( " Example:\n %s d -f elt -d -t 4194304 -l 5242880 -u administrators -l 0xffffffffffffffff -t 0xffffffffffffffff\n", __argv[0] );
}