/*++ Copyright (c) 1990 Microsoft Corporation Module Name: tests.c Abstract: This module contains the routine definitions for the NT test programs Author: Larry Osterman (LarryO) 1-Aug-1990 Revision History: 1-Aug-1990 LarryO Created --*/ #include #include #include #include #include #include #include #include #include #include "tests.h" #include "getinfo.h" #include "setinfo.h" //#include HANDLE FileTable[TEST_MAX_FILES]; VOID ParseLargeInteger ( IN UCHAR Buffer[], OUT PLARGE_INTEGER Ret ); USHORT ParseDateAndTime ( IN UCHAR Buffer[], OUT PLARGE_INTEGER Ret ); LONG ParseInteger ( IN UCHAR Buffer[], IN PARSETABLE ParseTable[], IN ULONG ParseTableSize, OUT PULONG Ret ); LONG ParseIntegerValue ( IN UCHAR Buffer[], IN PPARSETABLE ParseTable, IN ULONG ParseTableSize, OUT PULONG Ret ); ULONG DumpCurrentColumn = 0; VOID Dump_Desired_Access( ULONG Access ) { dprintf((" Desired Access:")); DumpNewLine(); DumpBitfield(Access, DELETE); DumpBitfield(Access, READ_CONTROL); DumpBitfield(Access, WRITE_DAC); DumpBitfield(Access, WRITE_OWNER); DumpBitfield(Access, FILE_APPEND_DATA); DumpBitfield(Access, GENERIC_EXECUTE); DumpBitfield(Access, SYNCHRONIZE); DumpBitfield(Access, FILE_EXECUTE); DumpBitfield(Access, GENERIC_READ); DumpBitfield(Access, FILE_READ_DATA); DumpBitfield(Access, FILE_READ_ATTRIBUTES); DumpBitfield(Access, FILE_READ_EA); DumpBitfield(Access, GENERIC_WRITE); DumpBitfield(Access, FILE_WRITE_DATA); DumpBitfield(Access, FILE_WRITE_ATTRIBUTES); DumpBitfield(Access, FILE_WRITE_EA); DumpBitfield(Access, FILE_LIST_DIRECTORY); DumpBitfield(Access, FILE_TRAVERSE); DumpNewLine(); } VOID Dump_File_Attributes( ULONG Attributes ) { dprintf((" File Attributes: ")); DumpNewLine(); DumpBitfield(Attributes, FILE_ATTRIBUTE_NORMAL); DumpBitfield(Attributes, FILE_ATTRIBUTE_READONLY); DumpBitfield(Attributes, FILE_ATTRIBUTE_HIDDEN); DumpBitfield(Attributes, FILE_ATTRIBUTE_SYSTEM); DumpBitfield(Attributes, FILE_ATTRIBUTE_ARCHIVE); DumpNewLine(); } VOID Dump_Sharing_Access( ULONG Access ) { dprintf((" Sharing Access: ")); DumpNewLine(); DumpBitfield(Access, FILE_SHARE_READ); DumpBitfield(Access, FILE_SHARE_WRITE); DumpBitfield(Access, FILE_SHARE_DELETE); DumpNewLine(); } VOID Dump_Disposition( ULONG Disposition ) { dprintf((" Disposition: ")); DumpNewLine(); if (Disposition == FILE_SUPERSEDE) DumpLabel(FILE_SUPERSEDE, 18); if (Disposition == FILE_CREATE) DumpLabel(FILE_CREATE, 18); if (Disposition == FILE_OPEN) DumpLabel(FILE_OPEN, 18); if (Disposition == FILE_OPEN_IF) DumpLabel(FILE_OPEN_IF, 18); if (Disposition == FILE_OVERWRITE) DumpLabel(FILE_OVERWRITE, 18); if (Disposition == FILE_OVERWRITE_IF) DumpLabel(FILE_OVERWRITE_IF, 18); DumpNewLine(); } VOID DumpFinalDisposition( ULONG Disposition ) { dprintf(("Final Disposition:")); DumpNewLine(); switch (Disposition) { case FILE_SUPERSEDED: DumpLabel(FILE_SUPERSEDED, 18); break; case FILE_OPENED: DumpLabel(FILE_OPENED, 18); break; case FILE_CREATED: DumpLabel(FILE_CREATED, 18); break; case FILE_OVERWRITTEN: DumpLabel(FILE_OVERWRITTEN, 18); break; default: dprintf(("Unknown disposition %lx\n",Disposition)); } DumpNewLine(); } VOID Dump_Options( ULONG Options ) { dprintf((" Options: ")); DumpNewLine(); DumpBitfield(Options, FILE_DIRECTORY_FILE); DumpBitfield(Options, FILE_NON_DIRECTORY_FILE); DumpBitfield(Options, FILE_WRITE_THROUGH); DumpBitfield(Options, FILE_SEQUENTIAL_ONLY); DumpBitfield(Options, FILE_NO_INTERMEDIATE_BUFFERING); DumpBitfield(Options, FILE_SYNCHRONOUS_IO_ALERT); DumpBitfield(Options, FILE_SYNCHRONOUS_IO_NONALERT); DumpBitfield(Options, FILE_CREATE_TREE_CONNECTION); DumpNewLine(); } VOID Dump_Object_Attributes( POBJECT_ATTRIBUTES Ptr ) { dprintf((" Object Attributes: ")); DumpNewLine(); DumpField(Length); DumpUName(ObjectName->Buffer, Ptr->ObjectName->Length); DumpField(RootDirectory); DumpField(SecurityDescriptor); DumpBitfield(Ptr->Attributes, OBJ_INHERIT); DumpBitfield(Ptr->Attributes, OBJ_PERMANENT); DumpBitfield(Ptr->Attributes, OBJ_EXCLUSIVE); DumpBitfield(Ptr->Attributes, OBJ_CASE_INSENSITIVE); DumpBitfield(Ptr->Attributes, OBJ_OPENIF); DumpNewLine(); } VOID Dump_Size( LARGE_INTEGER Size ) { PLARGE_INTEGER Ptr = &Size; dprintf((" File Size: ")); DumpNewLine(); DumpField(HighPart); DumpField(LowPart); DumpNewLine(); } CHAR NameBuffer[256]; ULONG FileNumber, RootFileNumber; ULONG FileAccess, FileAttributes, ShareAccess, Disposition; ULONG FileOptions, ObjAttributes; LARGE_INTEGER FileSize; PARSETABLE BooleanTable[] = { NamedField(TRUE), NamedField(FALSE) }; PARSETABLE ObjAttribsTable[] = { NamedField(OBJ_CASE_INSENSITIVE), NamedField(OBJ_INHERIT), }; PARSETABLE DesiredAccessTable[] = { NamedField(GENERIC_READ), NamedField(GENERIC_WRITE), NamedField(GENERIC_EXECUTE), NamedField(FILE_READ_DATA), NamedField(FILE_LIST_DIRECTORY), NamedField(FILE_WRITE_DATA), NamedField(FILE_ADD_FILE), NamedField(FILE_APPEND_DATA), NamedField(FILE_ADD_SUBDIRECTORY), NamedField(FILE_READ_EA), NamedField(FILE_WRITE_EA), NamedField(FILE_EXECUTE), NamedField(FILE_TRAVERSE), NamedField(FILE_DELETE_CHILD), NamedField(FILE_READ_ATTRIBUTES), NamedField(FILE_WRITE_ATTRIBUTES), NamedField(FILE_ALL_ACCESS), NamedField(DELETE), NamedField(READ_CONTROL), NamedField(WRITE_DAC), NamedField(WRITE_OWNER), NamedField(SYNCHRONIZE), NamedField(STANDARD_RIGHTS_REQUIRED), NamedField(STANDARD_RIGHTS_READ), NamedField(STANDARD_RIGHTS_WRITE), NamedField(STANDARD_RIGHTS_EXECUTE), NamedField(STANDARD_RIGHTS_ALL), NamedField(GENERIC_ALL) }; PARSETABLE SharedAccessTable[] = { NamedField(FILE_SHARE_READ), NamedField(FILE_SHARE_WRITE), NamedField(FILE_SHARE_DELETE), { "READ", FILE_SHARE_READ }, { "WRITE", FILE_SHARE_WRITE }, { "DELETE", FILE_SHARE_DELETE } }; PARSETABLE DispositionTable[] = { NamedField(FILE_SUPERSEDE), NamedField(FILE_OPEN), NamedField(FILE_CREATE), NamedField(FILE_OPEN_IF), NamedField(FILE_OVERWRITE), NamedField(FILE_OVERWRITE_IF), }; PARSETABLE CreateOptionsTable[] = { NamedField(FILE_DIRECTORY_FILE), NamedField(FILE_WRITE_THROUGH), NamedField(FILE_SEQUENTIAL_ONLY), NamedField(FILE_NO_INTERMEDIATE_BUFFERING), NamedField(FILE_SYNCHRONOUS_IO_ALERT), NamedField(FILE_SYNCHRONOUS_IO_NONALERT), NamedField(FILE_NON_DIRECTORY_FILE), NamedField(FILE_CREATE_TREE_CONNECTION), { "WRITE_THROUGH", FILE_WRITE_THROUGH}, { "SEQUENTIAL_ONLY", FILE_SEQUENTIAL_ONLY}, { "NO_INTERMEDIATE_BUFFERING", FILE_NO_INTERMEDIATE_BUFFERING}, { "SYNCHRONOUS_IO_ALERT", FILE_SYNCHRONOUS_IO_ALERT}, { "SYNCHRONOUS_IO_NONALERT", FILE_SYNCHRONOUS_IO_NONALERT}, { "NON_DIRECTORY_FILE", FILE_NON_DIRECTORY_FILE}, { "TREE_CONNECTION", FILE_CREATE_TREE_CONNECTION}, { "NO_INTERMEDIATE_BUFFERING", FILE_NO_INTERMEDIATE_BUFFERING}, { "NON_DIRECTORY_FILE", FILE_NON_DIRECTORY_FILE}, { "DIRECTORY_FILE", FILE_DIRECTORY_FILE} }; PARSETABLE FileInformationTable[] = { NamedField(FileBasicInformation), NamedField(FileStandardInformation), NamedField(FileInternalInformation), NamedField(FileEaInformation), NamedField(FileAccessInformation), NamedField(FileNameInformation), NamedField(FileRenameInformation), NamedField(FileLinkInformation), NamedField(FileNamesInformation), NamedField(FileDispositionInformation), NamedField(FilePositionInformation), NamedField(FileFullEaInformation), NamedField(FileModeInformation), NamedField(FileAlignmentInformation), NamedField(FileAllInformation), NamedField(FileAllocationInformation), NamedField(FileEndOfFileInformation) }; ULONG FileInformationSize = sizeoftable(FileInformationTable); PARSETABLE FileAttributesTable [] = { NamedField(FILE_ATTRIBUTE_READONLY), NamedField(FILE_ATTRIBUTE_HIDDEN), NamedField(FILE_ATTRIBUTE_SYSTEM), NamedField(FILE_ATTRIBUTE_ARCHIVE), NamedField(FILE_ATTRIBUTE_NORMAL), NamedField(FILE_ATTRIBUTE_DIRECTORY), { "READONLY", FILE_ATTRIBUTE_READONLY }, { "HIDDEN", FILE_ATTRIBUTE_HIDDEN }, { "SYSTEM", FILE_ATTRIBUTE_SYSTEM }, { "ARCHIVE", FILE_ATTRIBUTE_ARCHIVE }, { "NORMAL", FILE_ATTRIBUTE_NORMAL }, { "DIRECTORY", FILE_ATTRIBUTE_DIRECTORY } }; PARSETABLE FsInformationTable[] = { NamedField(FileFsVolumeInformation), NamedField(FileFsLabelInformation), NamedField(FileFsDeviceInformation), NamedField(FileFsSizeInformation), NamedField(FileFsAttributeInformation) }; ULONG FsInformationTableSize = sizeoftable(FsInformationTable); ULONG FileAttributesTableSize = sizeoftable(FileAttributesTable); PARSETABLE OpenOptionsTable[] = { NamedField(FILE_DIRECTORY_FILE), NamedField(FILE_WRITE_THROUGH), NamedField(FILE_SEQUENTIAL_ONLY), NamedField(FILE_NO_INTERMEDIATE_BUFFERING), NamedField(FILE_SYNCHRONOUS_IO_ALERT), NamedField(FILE_SYNCHRONOUS_IO_NONALERT), NamedField(FILE_NON_DIRECTORY_FILE), { "DIRECTORY_FILE", FILE_DIRECTORY_FILE }, { "WRITE_THROUGH", FILE_WRITE_THROUGH }, { "SEQUENTIAL_ONLY", FILE_SEQUENTIAL_ONLY }, { "NO_INTERMEDIATE_BUFFERING", FILE_NO_INTERMEDIATE_BUFFERING }, { "SYNCHRONOUS_IO_ALERT", FILE_SYNCHRONOUS_IO_ALERT }, { "SYNCHRONOUS_IO_NONALERT", FILE_SYNCHRONOUS_IO_NONALERT }, { "NON_DIRECTORY_FILE", FILE_NON_DIRECTORY_FILE }, }; ULONG OpenOptionsTableSize = sizeoftable(OpenOptionsTable); TESTPARAMS OpenOptions[] = { { "File Name", UnicodeString, 0, DD_NFS_DEVICE_NAME_U L"\\NtServer\\Nt\\File1", NULL, 0, NameBuffer}, { "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber}, { "Root Directory", Integer, -1, NULL, NULL, 0, &RootFileNumber }, { "Object Attributes", ParsedInteger, 0, "OBJ_CASE_INSENSITIVE", ObjAttribsTable, sizeoftable(ObjAttribsTable), &ObjAttributes }, { "Desired Access", ParsedInteger, 0, "SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE", DesiredAccessTable, sizeoftable(DesiredAccessTable), &FileAccess }, { "Share Access", ParsedInteger, 0, "0", SharedAccessTable, sizeoftable(SharedAccessTable), &ShareAccess }, { "Open Options", ParsedInteger, 0, NULL, OpenOptionsTable, sizeoftable(OpenOptionsTable), &FileOptions } }; #define NUM_OPEN_PARAMS sizeoftable(OpenOptions) VOID TestOpen( ULONG ArgC, PSZ ArgV[] ) /*++ Routine Description: This routine tests the functioning of the NtOpenFile API. Arguments: None. Return Value: None. --*/ { NTSTATUS Status; IO_STATUS_BLOCK Iosb; HANDLE Handle; OBJECT_ATTRIBUTES ObjectAttributes; LONG NumArgs; STRING FileName; UNICODE_STRING FileNameU; ULONG i; NumArgs = Parse_Options(OpenOptions, NUM_OPEN_PARAMS, ArgC, ArgV); if (NumArgs < 0) { return; } if (FileNumber == -1) { for (i = 0;i * in the first character of the name indicates \Device\LanmanRedirector should be prepended to the name. Arguments: None. Return Value: None. --*/ { NTSTATUS Status; IO_STATUS_BLOCK Iosb; HANDLE Handle; OBJECT_ATTRIBUTES ObjectAttributes; LONG NumArgs; STRING FileName; UNICODE_STRING FileNameU; ULONG i; NumArgs = Parse_Options(CreateOptions, NUM_CREATE_PARAMS, ArgC, ArgV); if (NumArgs < 0) { return; } if (FileNumber == -1) { for (i = 0;iNamedPipeState, ((PFILE_PIPE_PEEK_BUFFER)PeekBuffer)->ReadDataAvailable, ((PFILE_PIPE_PEEK_BUFFER)PeekBuffer)->NumberOfMessages, ((PFILE_PIPE_PEEK_BUFFER)PeekBuffer)->MessageLength)); if (!NT_ERROR(Iosb.Status)) { for (i=16;i TESTPARAMS DirOptions[] = { { "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber}, { "Length", Integer, 256, NULL, NULL, 0, &IOLength}, { "Single", IntegerValue, FALSE, "FALSE", BooleanTable, sizeoftable(BooleanTable), &Single}, { "Fs Information Class", IntegerValue, 0, "FileNamesInformation", DirTable, sizeoftable(DirTable), &DirInformation }, { "File Name", String, 0, NULL, NULL, 0, NameBuffer}, { "RestartScan", IntegerValue, FALSE, "FALSE", BooleanTable, sizeoftable(BooleanTable), &RestartScan} }; VOID TestDir( ULONG ArgC, PSZ ArgV[] ) { NTSTATUS Status; IO_STATUS_BLOCK Iosb; LONG NumArgs; PVOID QDirBuffer; STRING FileName; ULONG i; NumArgs = Parse_Options(DirOptions,sizeoftable(DirOptions),ArgC,ArgV); if (NumArgs < 0) { return; } QDirBuffer = RtlAllocateHeap(Heap, 0, IOLength); if (QDirBuffer==NULL) { dprintf(("Could not allocate buffer for requested IOLength\n")); return; } if (FileNumber == -1) { for (i = 0;i= i) { strcpy(Buffer, ArgV[i]); } else { strcpy(Prompt, ParsePtr->TestPrompt); strcat(Prompt, " ["); switch (ParsePtr->TestType) { case Integer: { CHAR Int[20]; _ltoa(ParsePtr->IntegerDefault, Int , 16); strcat(Prompt, Int); } break; case IntegerValue: case ParsedInteger: case LargeInteger: case DateAndTime: case String: if (ParsePtr->StringDefault!=NULL) { strcat(Prompt, ParsePtr->StringDefault); } break; case UnicodeString: if (ParsePtr->StringDefault!=NULL) { UNICODE_STRING UString; ANSI_STRING AString; RtlInitUnicodeString(&UString, (PWSTR)ParsePtr->StringDefault); RtlUnicodeStringToAnsiString(&AString, &UString, TRUE); strcat(Prompt, AString.Buffer); RtlFreeAnsiString(&AString); } break; } strcat(Prompt, "] >"); conprompt(Prompt, Buffer, 100); } if (Buffer[0]==';') { break; } if (Buffer[0]=='-' || Buffer[0]=='\0') { continue; } while (Reparse) { // DbgBreakPoint(); Error = FALSE; switch (ParsePtr->TestType) { case Integer: *(PULONG )ParsePtr->Destination = strtoul(Buffer, &NextToken, 0); Reparse = FALSE; break; case String: if (Buffer[0]=='%') { strcpy((PSZ)ParsePtr->Destination, DD_NFS_DEVICE_NAME); strcat((PSZ)ParsePtr->Destination, &Buffer[1]); } else { strcpy((PSZ)ParsePtr->Destination, Buffer); } break; case UnicodeString: { ANSI_STRING AString; UNICODE_STRING UString; RtlInitAnsiString(&AString, Buffer); RtlAnsiStringToUnicodeString(&UString, &AString, TRUE); if (UString.Buffer[0] == L'%') { wcscpy((PWSTR)ParsePtr->Destination, DD_NFS_DEVICE_NAME_U); wcscat((PWSTR)ParsePtr->Destination, &UString.Buffer[1]); } else { wcscpy((PWSTR)ParsePtr->Destination, UString.Buffer); } RtlFreeUnicodeString(&UString); } Reparse = FALSE; break; case ParsedInteger: if (ParseInteger(Buffer, ParsePtr->ParsedIntTable, ParsePtr->ParsedIntTableSize, ParsePtr->Destination) != 0) { Error = TRUE; } Reparse = FALSE; break; case IntegerValue: if (ParseIntegerValue(Buffer, ParsePtr->ParsedIntTable, ParsePtr->ParsedIntTableSize, ParsePtr->Destination) != 0) { Error = TRUE; } Reparse = FALSE; break; case LargeInteger: ParseLargeInteger(Buffer, ParsePtr->Destination); Reparse = FALSE; break; case DateAndTime: if (ParseDateAndTime(Buffer, ParsePtr->Destination) != 0) { Error = TRUE; } Reparse = FALSE; break; } if (Error) { conprompt("Error parsing answer, Reparse? [N]", Buffer, 100); if (Buffer[0]=='\0' || Buffer[0] == 'N' || Buffer[0] == 'n') { return -1; } else { conprompt(Prompt, Buffer, 100); Reparse = TRUE; } } } } return RetVal; } VOID ParseLargeInteger ( IN UCHAR Buffer[], OUT PLARGE_INTEGER Ret ) /*++ Routine Description: This routine parses a "parsed integer" and returns it to the caller. Arguments: IN PSZ Buffer, - [Supplies | Returns] description-of-argument IN PPARSETABLE ParseTable, - [Supplies | Returns] description-of-argument IN ULONG ParseTableSize - [Supplies | Returns] description-of-argument Return Value: ULONG --*/ { PUCHAR NextToken; ULONG HighPart; ULONG LowPart; HighPart = strtoul(Buffer, &NextToken, 0); LowPart = strtoul(++NextToken, &NextToken, 0); Ret->HighPart = HighPart; Ret->LowPart = LowPart; } USHORT ParseDateAndTime ( IN UCHAR Buffer[], OUT PLARGE_INTEGER Ret ) /*++ Routine Description: This routine parses a "parsed integer" and returns it to the caller. Arguments: IN PSZ Buffer, - [Supplies | Returns] description-of-argument Return Value: ULONG --*/ { ULONG ParseLength; if (!Buffer || *Buffer=='\0') { Ret->LowPart = Ret->HighPart = 0; return 0; } if (LUI_ParseDateTime(Buffer, Ret, &ParseLength, 0) != 0) { dprintf(("Invalid time %s passed into ParseDateAndTime\n", Buffer)); return -1; } return 0; } LONG ParseInteger ( IN UCHAR Buffer[], IN PPARSETABLE ParseTable, IN ULONG ParseTableSize, OUT PULONG Ret ) /*++ Routine Description: This routine parses a "parsed integer" and returns it to the caller. Arguments: IN UCHAR Buffer[], - [Supplies | Returns] description-of-argument IN PPARSETABLE ParseTable, - [Supplies | Returns] description-of-argument IN ULONG ParseTableSize - [Supplies | Returns] description-of-argument OUT PULONG Ret Return Value: ULONG --*/ { PSZ Token = Buffer; PSZ NextToken = Buffer; // Anything that isn't NULL. ULONG i; if (Buffer==NULL) { *Ret = 0; return 0; } // // If the user specified an absolute number, return that. // if (isdigit(*Token)) { *Ret = strtoul(Token, &NextToken, 0); return 0; } // // Nope, the user passed in a string, parse that. // // // Initialize the initial value of the returned value to NULL. // *Ret = 0; while (NextToken != NULL) { UCHAR saveToken; PUCHAR savePointer = NULL; NextToken = strpbrk(Token, "+|"); if (NextToken!=NULL) { saveToken = *NextToken; savePointer = NextToken; *NextToken++ = '\0'; } for (i = 0 ; i < ParseTableSize ; i++ ) { if (_stricmp(Token, ParseTable[i].FieldName)==0) { *Ret |= ParseTable[i].FieldValue; break; } } if (i == ParseTableSize) { dprintf(("Unknown option %s passed to ParseInteger. Values are:\n", Token)); for (i = 0; i < ParseTableSize ; i++) { dprintf(("\t%s\n", ParseTable[i].FieldName)); } return -1; } if (savePointer != NULL) { *savePointer = saveToken; // Restore byte trompled on. } Token = NextToken; } return 0; } LONG ParseIntegerValue ( IN UCHAR Buffer[], IN PPARSETABLE ParseTable, IN ULONG ParseTableSize, OUT PULONG Ret ) /*++ Routine Description: This routine parses a "parsed integer" and returns it to the caller. Arguments: IN UCHAR Buffer[], - [Supplies | Returns] description-of-argument IN PPARSETABLE ParseTable, - [Supplies | Returns] description-of-argument IN ULONG ParseTableSize - [Supplies | Returns] description-of-argument OUT PULONG Ret Return Value: ULONG --*/ { PSZ NextToken; // Anything that isn't NULL. ULONG i; if (Buffer==NULL) { *Ret = 0; return 0; } // // If the user specified an absolute number, return that. // if (isdigit(*Buffer)) { *Ret = strtoul(Buffer, &NextToken, 0); return 0; } // // Nope, the user passed in a string, parse that. // for (i = 0 ; i < ParseTableSize ; i++ ) { if (_stricmp(Buffer, ParseTable[i].FieldName)==0) { *Ret = ParseTable[i].FieldValue; return 0; } } dprintf(("Unknown option %s passed to ParseInteger. Values are:\n",Buffer)); for (i = 0; i < ParseTableSize ; i++) { dprintf(("\t%s\n", ParseTable[i].FieldName)); } return -1; }