mirror of https://github.com/lianthony/NT4.0
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.
2940 lines
74 KiB
2940 lines
74 KiB
/*++
|
|
|
|
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 <stdio.h>
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <ntddnfs.h>
|
|
#include <ctype.h>
|
|
|
|
|
|
#include "tests.h"
|
|
#include "getinfo.h"
|
|
#include "setinfo.h"
|
|
//#include <lui.h>
|
|
|
|
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<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]!=NULL) {
|
|
CHAR Answer[5];
|
|
conprompt("File already in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
RtlInitUnicodeString(&FileNameU, NameBuffer);
|
|
|
|
InitializeObjectAttributes (&ObjectAttributes,
|
|
&FileNameU, ObjAttributes,
|
|
(RootFileNumber==-1? NULL : FileTable[RootFileNumber]),
|
|
NULL); // Null security descriptor.
|
|
|
|
dprintf(("NtOpenFile for file %wZ\n", &FileNameU));
|
|
|
|
Dump_Desired_Access(FileAccess);
|
|
Dump_Object_Attributes(&ObjectAttributes);
|
|
Dump_Sharing_Access(ShareAccess);
|
|
Dump_Options(FileOptions);
|
|
|
|
Status = NtOpenFile(&Handle,
|
|
FileAccess,
|
|
&ObjectAttributes,
|
|
&Iosb,
|
|
ShareAccess,
|
|
FileOptions);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtOpenFile(%Z) failed, Status == %X\n", &FileName,Status));
|
|
return;
|
|
} else {
|
|
Status = Iosb.Status;
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtOpenFile(%Z) failed2, Status == %X\n", &FileName,
|
|
Status));
|
|
return;
|
|
}
|
|
}
|
|
|
|
DumpFinalDisposition(Iosb.Information);
|
|
|
|
dprintf(("Storing handle %lx in table entry %d\n", Handle, FileNumber));
|
|
|
|
FileTable[FileNumber] = Handle;
|
|
|
|
|
|
}
|
|
|
|
TESTPARAMS CreateOptions[] = {
|
|
{ "File Name", String, 0, DD_NFS_DEVICE_NAME "\\NtServer\\Nt", 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 },
|
|
|
|
{ "Allocation", LargeInteger, 0, "0,0", NULL, 0, &FileSize },
|
|
|
|
{ "File Attributes", ParsedInteger, 0, "FILE_ATTRIBUTE_NORMAL",
|
|
FileAttributesTable, sizeoftable(FileAttributesTable),
|
|
&FileAttributes },
|
|
|
|
{ "Sharing Access", ParsedInteger, 0, "0", SharedAccessTable,
|
|
sizeoftable(SharedAccessTable), &ShareAccess },
|
|
|
|
{ "File's Disposition", ParsedInteger, 0, "FILE_OPEN_IF", DispositionTable,
|
|
sizeoftable(DispositionTable), &Disposition },
|
|
|
|
{ "Create Options", ParsedInteger, 0, NULL,
|
|
CreateOptionsTable, sizeoftable(CreateOptionsTable),
|
|
&FileOptions }
|
|
};
|
|
|
|
#define NUM_CREATE_PARAMS sizeoftable(CreateOptions)
|
|
|
|
VOID
|
|
TestCreate(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine tests the functioning of the NtCreateFile API.
|
|
|
|
Create <file> <handle#> <root directory > <access> <allocationsize>
|
|
<attributes> <share access> <disposition> <options>
|
|
|
|
* 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;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]!=NULL) {
|
|
CHAR Answer[5];
|
|
conprompt("File already in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RtlInitString(&FileName, NameBuffer);
|
|
|
|
RtlAnsiStringToUnicodeString(&FileNameU, &FileName, TRUE);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&FileNameU, ObjAttributes,
|
|
(RootFileNumber==-1? NULL : FileTable[RootFileNumber]),
|
|
NULL); // Null security descriptor.
|
|
|
|
dprintf(("NtCreateFile for file %Z\n", &FileName));
|
|
|
|
Dump_Desired_Access(FileAccess);
|
|
Dump_Object_Attributes(&ObjectAttributes);
|
|
Dump_File_Attributes(FileAttributes);
|
|
Dump_Sharing_Access(ShareAccess);
|
|
Dump_Disposition(Disposition);
|
|
Dump_Options(FileOptions);
|
|
Dump_Size(FileSize);
|
|
|
|
Status = NtCreateFile(&Handle,
|
|
FileAccess,
|
|
&ObjectAttributes,
|
|
&Iosb,
|
|
&FileSize,
|
|
FileAttributes,
|
|
ShareAccess,
|
|
Disposition, // File's disposition
|
|
FileOptions,
|
|
NULL,
|
|
0); // No EA support for now.
|
|
|
|
RtlFreeUnicodeString(&FileNameU);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtCreateFile(%Z) failed, Status == %X\n", &FileName,Status));
|
|
return;
|
|
} else {
|
|
Status = Iosb.Status;
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtCreateFile(%Z) failed2, Status == %X\n", &FileName,
|
|
Status));
|
|
return;
|
|
}
|
|
}
|
|
|
|
DumpFinalDisposition(Iosb.Information);
|
|
|
|
dprintf(("Storing handle %lx in table entry %d\n", Handle, FileNumber));
|
|
|
|
FileTable[FileNumber] = Handle;
|
|
|
|
}
|
|
|
|
TESTPARAMS CloseOptions[] = {
|
|
{ "File Handle", Integer, 0, NULL, NULL, 0, &FileNumber},
|
|
};
|
|
#define NUM_CLOSE_OPTIONS sizeoftable(CloseOptions)
|
|
|
|
VOID
|
|
TestClose(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
LONG NumArgs;
|
|
ULONG i;
|
|
NTSTATUS Status;
|
|
|
|
NumArgs = Parse_Options(CloseOptions, NUM_CLOSE_OPTIONS, ArgC, ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]!=NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
conprompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
dprintf(("Closing handle %lx\n", FileTable[FileNumber]));
|
|
|
|
Status = NtClose(FileTable[FileNumber]);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("Close failed, Status == %X", Status));
|
|
}
|
|
|
|
FileTable[FileNumber] = NULL;
|
|
|
|
return;
|
|
}
|
|
|
|
LARGE_INTEGER Offset;
|
|
|
|
ULONG IOLength;
|
|
|
|
ULONG Key;
|
|
|
|
TESTPARAMS IOOptions[] = {
|
|
|
|
{ "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber},
|
|
|
|
{ "Offset ", LargeInteger, 0, "0,0", NULL, 0, &Offset },
|
|
|
|
{ "Length", Integer, 0xffff, NULL, NULL, 0, &IOLength },
|
|
|
|
{ "Key ", Integer, 0, NULL, NULL, 0, &Key }
|
|
|
|
};
|
|
|
|
|
|
VOID
|
|
TestRead(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
HANDLE EventHandle;
|
|
LONG NumArgs;
|
|
PVOID ReadBuffer;
|
|
ULONG i;
|
|
|
|
NumArgs = Parse_Options(IOOptions, sizeoftable(IOOptions), ArgC,ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
ReadBuffer = RtlAllocateHeap(Heap, 0, IOLength);
|
|
|
|
if (ReadBuffer==NULL) {
|
|
dprintf(("Could not allocate buffer for requested read\n"));
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
conprompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NtCreateEvent(
|
|
&EventHandle,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
dprintf(( "NtCreateEvent failed: %X\n", Status ));
|
|
RtlFreeHeap(Heap, 0, ReadBuffer);
|
|
return;
|
|
}
|
|
|
|
|
|
Status = NtReadFile(FileTable[FileNumber],
|
|
EventHandle,
|
|
NULL, // APC routine
|
|
NULL, // APC Context
|
|
&Iosb, // I/O Status block
|
|
ReadBuffer, // Buffer for read
|
|
IOLength, // Length.
|
|
&Offset, // Read offset to file.
|
|
&Key); // Key.
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtReadFile failed immediately, Status = %X\n", Status));
|
|
RtlFreeHeap(Heap, 0, ReadBuffer);
|
|
return;
|
|
}
|
|
|
|
Status = NtWaitForSingleObject(EventHandle, TRUE, NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtWaitForSingleObject failed, Status = %X\n", Status));
|
|
RtlFreeHeap(Heap, 0, ReadBuffer);
|
|
return;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Iosb.Status)) {
|
|
dprintf(("Final return from NtReadFile failed, Status = %X\n",Iosb.Status));
|
|
RtlFreeHeap(Heap, 0, ReadBuffer);
|
|
return;
|
|
}
|
|
|
|
dprintf(("Number of bytes read==%ld\n", Iosb.Information));
|
|
|
|
NtClose(EventHandle);
|
|
|
|
// for (i=0;i<Iosb.Information;i++) {
|
|
// dprintf(("%c", ((PUCHAR )ReadBuffer)[i]));
|
|
// }
|
|
|
|
RtlFreeHeap(Heap, 0, ReadBuffer);
|
|
}
|
|
|
|
TESTPARAMS PeekOptions[] = {
|
|
|
|
{ "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber},
|
|
|
|
{ "Length", Integer, 0xffff, NULL, NULL, 0, &IOLength }
|
|
|
|
};
|
|
|
|
|
|
VOID
|
|
TestPeek(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
HANDLE EventHandle;
|
|
LONG NumArgs;
|
|
PVOID PeekBuffer;
|
|
ULONG i;
|
|
|
|
NumArgs = Parse_Options(PeekOptions, sizeoftable(PeekOptions), ArgC,ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
PeekBuffer = RtlAllocateHeap(Heap, 0, IOLength);
|
|
|
|
if (PeekBuffer==NULL) {
|
|
dprintf(("Could not allocate buffer for requested Peek\n"));
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
DbgPrompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NtCreateEvent(
|
|
&EventHandle,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
dprintf(( "NtCreateEvent failed: %X\n", Status ));
|
|
RtlFreeHeap(Heap, 0, PeekBuffer);
|
|
return;
|
|
}
|
|
|
|
Status = NtFsControlFile(FileTable[FileNumber],
|
|
EventHandle,
|
|
NULL, // APC routine
|
|
NULL, // APC Context
|
|
&Iosb, // I/O Status block
|
|
FSCTL_PIPE_PEEK,// IoControlCode
|
|
NULL, // Buffer for data to the FS
|
|
0, // Length.
|
|
PeekBuffer, // OutputBuffer for data from the FS
|
|
IOLength // OutputBuffer Length
|
|
);
|
|
|
|
if ( Status == STATUS_PENDING) {
|
|
|
|
Status = NtWaitForSingleObject(EventHandle, TRUE, NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtWaitForSingleObject failed, Status = %X\n", Status));
|
|
RtlFreeHeap(Heap, 0, PeekBuffer);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtWaitForSingleObject failed, Status = %X\n", Status));
|
|
}
|
|
|
|
if (NT_ERROR(Iosb.Status)) {
|
|
dprintf(("Final return from NtPeekFile failed, Status = %X\n",Iosb.Status));
|
|
RtlFreeHeap(Heap, 0, PeekBuffer);
|
|
return;
|
|
}
|
|
|
|
if (NT_WARNING(Iosb.Status)) {
|
|
dprintf(("Final return from NtPeekFile warning, Status = %X\n",Iosb.Status));
|
|
}
|
|
|
|
dprintf(("Number of bytes Peeked==%ld\n", Iosb.Information));
|
|
|
|
NtClose(EventHandle);
|
|
|
|
dprintf(("NamedPipeState %lx, ReadDataAvailable %lx \n"
|
|
"NumberOfMessages %lx, MessageLength %lx\n",
|
|
((PFILE_PIPE_PEEK_BUFFER)PeekBuffer)->NamedPipeState,
|
|
((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<Iosb.Information;i++) {
|
|
dprintf(("%c", ((PUCHAR )PeekBuffer)[i]));
|
|
}
|
|
}
|
|
|
|
RtlFreeHeap(Heap, 0, PeekBuffer);
|
|
}
|
|
|
|
ULONG Index;
|
|
|
|
TESTPARAMS QprintOptions[] = {
|
|
|
|
{ "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber},
|
|
{ "Index", Integer, 1, NULL, NULL, 0, &Index }
|
|
|
|
};
|
|
|
|
|
|
|
|
VOID
|
|
TestQprint(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
LONG NumArgs;
|
|
HANDLE EventHandle;
|
|
LMR_REQUEST_PACKET InputBuffer;
|
|
struct {
|
|
LMR_GET_PRINT_QUEUE Info;
|
|
UCHAR Name[UNLEN];
|
|
} Buffer;
|
|
ULONG i;
|
|
|
|
NumArgs = Parse_Options(QprintOptions, sizeoftable(QprintOptions), ArgC,ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
DbgPrompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NtCreateEvent(
|
|
&EventHandle,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
dprintf(( "NtCreateEvent failed: %X\n", Status ));
|
|
return;
|
|
}
|
|
|
|
InputBuffer.Parameters.GetPrintQueue.Index = Index;
|
|
|
|
Status = NtFsControlFile(FileTable[FileNumber],
|
|
EventHandle,
|
|
NULL, // APC routine
|
|
NULL, // APC Context
|
|
&Iosb, // I/O Status block
|
|
FSCTL_LMR_ENUMERATE_PRINT_INFO,// IoControlCode
|
|
&InputBuffer, // Buffer for data to the FS
|
|
sizeof(InputBuffer), // Length.
|
|
&Buffer, // OutputBuffer for data from the FS
|
|
sizeof(Buffer) // OutputBuffer Length
|
|
);
|
|
|
|
if ( Status == STATUS_PENDING) {
|
|
|
|
Status = NtWaitForSingleObject(EventHandle, TRUE, NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtWaitForSingleObject failed, Status = %X\n", Status));
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
if (NT_ERROR(Iosb.Status)) {
|
|
dprintf(("Final return from Qprint failed, Status = %X\n",Iosb.Status));
|
|
return;
|
|
}
|
|
|
|
if (NT_WARNING(Iosb.Status)) {
|
|
dprintf(("Final return from Qprint warning, Status = %X\n",Iosb.Status));
|
|
}
|
|
|
|
NtClose(EventHandle);
|
|
if (NT_SUCCESS(Status)) {
|
|
dprintf((
|
|
"CreateTime= %lx %lx, EntryStatus %lx,\n File %lx, Size %lx,"
|
|
" RestartIndex %lx, ",
|
|
//.OriginatorName,
|
|
Buffer.Info.CreateTime.HighPart,
|
|
Buffer.Info.CreateTime.LowPart,
|
|
Buffer.Info.EntryStatus,
|
|
Buffer.Info.FileNumber,
|
|
Buffer.Info.FileSize,
|
|
Buffer.Info.RestartIndex
|
|
));
|
|
dprintf(("UserName = %Z\n",&Buffer.Info.OriginatorName));
|
|
} else {
|
|
dprintf(("Return from Qprint failed, Status = %X\n",Status));
|
|
return;
|
|
}
|
|
}
|
|
|
|
struct _WaitPipe {
|
|
FILE_PIPE_WAIT_FOR_BUFFER Buffer;
|
|
CHAR namepad[255];
|
|
} WaitPipe;
|
|
|
|
ULONG TimeoutSpecified;
|
|
|
|
TESTPARAMS WaitPipeOptions[] = {
|
|
|
|
{ "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber},
|
|
{ "Timeout", LargeInteger, 0, "0,0", NULL, 0, &WaitPipe.Buffer.Timeout },
|
|
{ "Pipe Name", UnicodeString, 0, NULL, NULL, 0, WaitPipe.Buffer.Name},
|
|
{ "Timeout Specified", IntegerValue, FALSE, "FALSE",
|
|
BooleanTable, sizeoftable(BooleanTable), &TimeoutSpecified}
|
|
};
|
|
|
|
VOID
|
|
TestWaitPipe(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
LONG NumArgs;
|
|
HANDLE EventHandle;
|
|
ULONG i;
|
|
|
|
NumArgs = Parse_Options(WaitPipeOptions, sizeoftable(WaitPipeOptions), ArgC,ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
DbgPrompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NtCreateEvent(
|
|
&EventHandle,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
dprintf(( "NtCreateEvent failed: %X\n", Status ));
|
|
return;
|
|
}
|
|
|
|
WaitPipe.Buffer.NameLength = wcslen(WaitPipe.Buffer.Name);
|
|
WaitPipe.Buffer.TimeoutSpecified = (BOOLEAN)TimeoutSpecified;
|
|
|
|
Status = NtFsControlFile(FileTable[FileNumber],
|
|
EventHandle,
|
|
NULL, // APC routine
|
|
NULL, // APC Context
|
|
&Iosb, // I/O Status block
|
|
FSCTL_PIPE_WAIT,// IoControlCode
|
|
&WaitPipe, // Buffer for data to the FS
|
|
sizeof(WaitPipe), // Length.
|
|
NULL, // OutputBuffer for data from the FS
|
|
0 // OutputBuffer Length
|
|
);
|
|
|
|
if ( Status == STATUS_PENDING) {
|
|
|
|
Status = NtWaitForSingleObject(EventHandle, TRUE, NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtWaitForSingleObject failed, Status = %X\n", Status));
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
if (NT_ERROR(Iosb.Status)) {
|
|
dprintf(("Final return from WaitPipe failed, Status = %X\n",Iosb.Status));
|
|
return;
|
|
}
|
|
|
|
if (NT_WARNING(Iosb.Status)) {
|
|
dprintf(("Final return from WaitPipe warning, Status = %X\n",Iosb.Status));
|
|
}
|
|
|
|
NtClose(EventHandle);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("Return from WaitPipe failed, Status = %X\n",Status));
|
|
return;
|
|
}
|
|
}
|
|
|
|
FILE_PIPE_INFORMATION SetPipeBuffer;
|
|
|
|
PARSETABLE
|
|
ReadModeTable[] = {
|
|
NamedField(FILE_PIPE_BYTE_STREAM_MODE),
|
|
NamedField(FILE_PIPE_MESSAGE_MODE)
|
|
};
|
|
|
|
PARSETABLE
|
|
PipeCompletionModeTable[] = {
|
|
NamedField(FILE_PIPE_QUEUE_OPERATION),
|
|
NamedField(FILE_PIPE_COMPLETE_OPERATION)
|
|
};
|
|
|
|
TESTPARAMS SetPipeOptions[] = {
|
|
|
|
{ "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber},
|
|
{ "ReadMode", ParsedInteger, FILE_PIPE_MESSAGE_MODE,
|
|
"FILE_PIPE_MESSAGE_MODE",
|
|
ReadModeTable, sizeoftable(ReadModeTable),
|
|
&SetPipeBuffer.ReadMode },
|
|
{ "PipeCompletionMode", ParsedInteger,FILE_PIPE_COMPLETE_OPERATION ,
|
|
"FILE_PIPE_COMPLETE_OPERATION",
|
|
PipeCompletionModeTable, sizeoftable(PipeCompletionModeTable),
|
|
&SetPipeBuffer.CompletionMode },
|
|
};
|
|
|
|
VOID
|
|
TestSetPipe(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
LONG NumArgs;
|
|
ULONG i;
|
|
|
|
NumArgs = Parse_Options(SetPipeOptions, sizeoftable(SetPipeOptions), ArgC,ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
DbgPrompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NtSetInformationFile(
|
|
FileTable[FileNumber],
|
|
&Iosb,
|
|
&SetPipeBuffer,
|
|
sizeof(FILE_PIPE_INFORMATION),
|
|
FilePipeInformation );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("Return from NtSetPipeFile failed, Status = %X\n",Status));
|
|
return;
|
|
}
|
|
if (NT_ERROR(Iosb.Status)) {
|
|
dprintf(("return from NtSetPipeFile failed, Status = %X\n",Status));
|
|
return;
|
|
}
|
|
|
|
if (NT_WARNING(Iosb.Status)) {
|
|
dprintf(("return from NtSetPipeFile warning, Status = %X\n",Status));
|
|
}
|
|
|
|
}
|
|
|
|
TESTPARAMS FlushOptions[] = {
|
|
|
|
{ "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber}
|
|
};
|
|
|
|
VOID
|
|
TestFlush(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
LONG NumArgs;
|
|
ULONG i;
|
|
|
|
NumArgs = Parse_Options(FlushOptions, sizeoftable(FlushOptions), ArgC,ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
DbgPrompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NtFlushBuffersFile(
|
|
FileTable[FileNumber],
|
|
&Iosb);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("Return from NtFlushBuffersFile failed, Status = %X\n",Status));
|
|
return;
|
|
}
|
|
if (NT_ERROR(Iosb.Status)) {
|
|
dprintf(("return from NtFlushBuffersFile failed, Status = %X\n",Status));
|
|
return;
|
|
}
|
|
|
|
if (NT_WARNING(Iosb.Status)) {
|
|
dprintf(("return from NtFlushBuffersFile warning, Status = %X\n",Status));
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
TestWrite(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
HANDLE EventHandle;
|
|
LONG NumArgs;
|
|
PVOID WriteBuffer;
|
|
PULONG WriteArea;
|
|
ULONG i;
|
|
|
|
NumArgs = Parse_Options(IOOptions, sizeoftable(IOOptions), ArgC,ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
WriteBuffer = RtlAllocateHeap(Heap, 0, IOLength);
|
|
|
|
if (WriteBuffer==NULL) {
|
|
dprintf(("Could not allocate buffer for requested write\n"));
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
conprompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NtCreateEvent(
|
|
&EventHandle,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
dprintf(( "NtCreateEvent failed: %X\n", Status ));
|
|
return;
|
|
}
|
|
|
|
i = IOLength / sizeof(ULONG);
|
|
WriteArea = WriteBuffer;
|
|
|
|
while (i--) {
|
|
*WriteArea++ = 0xDEADBEEF;
|
|
}
|
|
|
|
Status = NtWriteFile(FileTable[FileNumber],
|
|
EventHandle,
|
|
NULL, // APC routine
|
|
NULL, // APC Context
|
|
&Iosb, // I/O Status block
|
|
WriteBuffer, // Buffer for Write
|
|
IOLength, // Length.
|
|
&Offset, // Write offset to file.
|
|
&Key); // Key.
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtWriteFile failed immediately, Status = %X\n", Status));
|
|
RtlFreeHeap(Heap, 0, WriteBuffer);
|
|
return;
|
|
}
|
|
|
|
Status = NtWaitForSingleObject(EventHandle, TRUE, NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtWaitForSingleObject failed, Status = %X\n", Status));
|
|
RtlFreeHeap(Heap, 0, WriteBuffer);
|
|
NtClose(EventHandle);
|
|
return;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Iosb.Status)) {
|
|
dprintf(("Final return from NtWriteFile failed, Iosb.Status = %X\n",Iosb.Status));
|
|
}
|
|
|
|
dprintf(("Number of bytes written==%ld\n", Iosb.Information));
|
|
|
|
NtClose(EventHandle);
|
|
|
|
RtlFreeHeap(Heap, 0, WriteBuffer);
|
|
}
|
|
|
|
|
|
VOID
|
|
TestNullRead(
|
|
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;
|
|
CHAR NameBuffer[256];
|
|
ULONG i, IterationCount;
|
|
LARGE_INTEGER TestStartTime, TestEndTime;
|
|
LARGE_INTEGER DeltaTime;
|
|
PVOID OutputBuffer;
|
|
ULONG RootFileNumber;
|
|
STRING FileName;
|
|
UNICODE_STRING FileNameU;
|
|
|
|
TESTPARAMS OpenOptions[] = {
|
|
{ "File Name", String, 0, DD_NFS_DEVICE_NAME "\\NtServer\\Nt\\File1", NULL, 0, NameBuffer },
|
|
{ "Root Directory", Integer, -1, NULL, NULL, 0, &RootFileNumber },
|
|
{ "Number Of Iterations", Integer, 100000, NULL, NULL, 0, &IterationCount }
|
|
};
|
|
|
|
NumArgs = Parse_Options(OpenOptions, sizeoftable(OpenOptions), ArgC, ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
RtlInitString(&FileName, NameBuffer);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&FileNameU, OBJ_CASE_INSENSITIVE,
|
|
(RootFileNumber==-1? NULL : FileTable[RootFileNumber]),
|
|
NULL); // Null security descriptor.
|
|
|
|
dprintf(("NtOpenFile for file %Z\n", &FileName));
|
|
|
|
DbgBreakPoint();
|
|
|
|
Status = NtCreateFile(&Handle,
|
|
GENERIC_READ | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&Iosb,
|
|
NULL, // File size
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
FILE_OPEN_IF,
|
|
FILE_NON_DIRECTORY_FILE,
|
|
NULL, // No EA support for now.
|
|
0);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtCreateFile(%Z) failed, Status == %X\n", &FileName,Status));
|
|
return;
|
|
} else {
|
|
Status = Iosb.Status;
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtCreateFile(%Z) failed2, Status == %X\n", &FileName,
|
|
Status));
|
|
return;
|
|
}
|
|
}
|
|
|
|
DumpFinalDisposition(Iosb.Information);
|
|
|
|
Status = NtQuerySystemTime(&TestStartTime);
|
|
|
|
ASSERT (NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Sit in a loop performing synchronous reads to the file.
|
|
//
|
|
|
|
for (i = 0; i < IterationCount ; i++) {
|
|
Status = NtReadFile(Handle, // Handle
|
|
NULL, // Event
|
|
NULL, // APC routine
|
|
NULL, // APC context
|
|
&Iosb, // I/O status block
|
|
OutputBuffer, // Buffer
|
|
0L, // Length
|
|
NULL, // Offset
|
|
NULL); // Key
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtReadFile failed, status %X\n", Status));
|
|
} else if (!NT_SUCCESS(Iosb.Status)) {
|
|
dprintf(("NtReadFile2 failed, status %X\n", Iosb.Status));
|
|
}
|
|
|
|
|
|
}
|
|
|
|
Status = NtQuerySystemTime(&TestEndTime);
|
|
|
|
ASSERT (NT_SUCCESS(Status));
|
|
|
|
DeltaTime.QuadPart = TestEndTime.QuadPart - TestStartTime.QuadPart;
|
|
|
|
dprintf(("%lx Iterations, Time Delta: %lx%lx00 Nanoseconds\n", IterationCount, DeltaTime.HighPart, DeltaTime.LowPart));
|
|
|
|
//
|
|
// Convert the time into milliseconds.
|
|
//
|
|
DeltaTime = RtlExtendedLargeIntegerDivide(DeltaTime, 10000L, NULL);
|
|
|
|
dprintf(("%ld Iterations took 0x%lx%lx milliseconds\n", IterationCount, DeltaTime.HighPart, DeltaTime.LowPart));
|
|
|
|
NtClose(Handle);
|
|
|
|
}
|
|
|
|
VOID
|
|
TestWinNullRead(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine tests the functioning of the NtOpenFile API.
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE Handle;
|
|
LONG NumArgs;
|
|
CHAR NameBuffer[256];
|
|
ULONG i, IterationCount;
|
|
LARGE_INTEGER TestStartTime, TestEndTime;
|
|
LARGE_INTEGER DeltaTime;
|
|
PVOID OutputBuffer;
|
|
ULONG BytesRead;
|
|
|
|
TESTPARAMS OpenOptions [] = {
|
|
{ "File Name", String, 0, "M:\\Nt\\File1", NULL, 0, NameBuffer },
|
|
{ "Number Of Iterations", Integer, 100000, NULL, NULL, 0, &IterationCount }
|
|
};
|
|
|
|
NumArgs = Parse_Options(OpenOptions, sizeoftable(OpenOptions), ArgC, ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
dprintf(("CreateFile for file %s\n", NameBuffer));
|
|
|
|
DbgBreakPoint();
|
|
|
|
Handle = CreateFile(NameBuffer,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
FALSE,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
|
|
if (Handle == (HANDLE )-1) {
|
|
dprintf(("CreateFile(%s) failed, Status == %X\n", NameBuffer, GetLastError()));
|
|
return;
|
|
}
|
|
|
|
Status = NtQuerySystemTime(&TestStartTime);
|
|
|
|
ASSERT (NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Sit in a loop performing synchronous reads to the file.
|
|
//
|
|
|
|
for (i = 0; i < IterationCount ; i++) {
|
|
ReadFile(Handle, OutputBuffer, 0, &BytesRead, NULL);
|
|
}
|
|
|
|
Status = NtQuerySystemTime(&TestEndTime);
|
|
|
|
ASSERT (NT_SUCCESS(Status));
|
|
|
|
DeltaTime.QuadPart = TestStartTime.QuadPart - TestEndTime.QuadPart;
|
|
dprintf(("%lx Iterations, Time Delta: %lx%lx00 Nanoseconds ", IterationCount, DeltaTime.HighPart, DeltaTime.LowPart));
|
|
|
|
//
|
|
// Convert the time into milliseconds.
|
|
//
|
|
DeltaTime = RtlExtendedLargeIntegerDivide(DeltaTime, 10000L, NULL);
|
|
|
|
dprintf(("%lx Iterations took %lx%lx milliseconds", IterationCount, DeltaTime.HighPart, DeltaTime.LowPart));
|
|
|
|
CloseHandle(Handle);
|
|
|
|
}
|
|
|
|
VOID
|
|
TestLock(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
HANDLE EventHandle;
|
|
LONG NumArgs;
|
|
ULONG i;
|
|
|
|
LARGE_INTEGER Offset;
|
|
|
|
ULONG IOLength;
|
|
LARGE_INTEGER TmpLength;
|
|
|
|
ULONG Key;
|
|
|
|
BOOLEAN FailImmediately, ExclusiveLock;
|
|
|
|
TESTPARAMS LockOptions[] = {
|
|
|
|
{ "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber},
|
|
|
|
{ "Offset ", LargeInteger, 0, "0,0", NULL, 0, &Offset },
|
|
|
|
{ "Length", Integer, 0xffff, NULL, NULL, 0, &IOLength },
|
|
|
|
{ "Key ", Integer, 0, NULL, NULL, 0, &Key },
|
|
|
|
{ "FailImmediately ", Integer, 0, NULL, NULL, 0, &FailImmediately },
|
|
|
|
{ "ExclusiveLock ", Integer, 0, NULL, NULL, 0, &ExclusiveLock },
|
|
|
|
};
|
|
|
|
NumArgs = Parse_Options(LockOptions, sizeoftable(LockOptions), ArgC,ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
conprompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
Status = NtCreateEvent(
|
|
&EventHandle,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
NotificationEvent,
|
|
FALSE
|
|
);
|
|
|
|
if ( !NT_SUCCESS(Status) ) {
|
|
dprintf(( "NtCreateEvent failed: %X\n", Status ));
|
|
return;
|
|
}
|
|
|
|
|
|
TmpLength.QuadPart = IOLength;
|
|
Status = NtLockFile(FileTable[FileNumber],
|
|
EventHandle,
|
|
NULL, // APC routine
|
|
NULL, // APC Context
|
|
&Iosb, // I/O Status block
|
|
&Offset, // Read offset to file.
|
|
&TmpLength, // Length.
|
|
Key, // Key.
|
|
FailImmediately,
|
|
ExclusiveLock);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtLockFile failed immediately, Status = %X\n", Status));
|
|
return;
|
|
}
|
|
|
|
Status = NtWaitForSingleObject(EventHandle, TRUE, NULL);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtWaitForSingleObject failed, Status = %X\n", Status));
|
|
return;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Iosb.Status)) {
|
|
dprintf(("Final return from NtLockFile failed, Status = %X\n",Iosb.Status));
|
|
return;
|
|
}
|
|
|
|
dprintf(("NtLockFile succeeded, Status = %X\n", Status));
|
|
|
|
NtClose(EventHandle);
|
|
|
|
}
|
|
|
|
VOID
|
|
TestUnlock(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
IO_STATUS_BLOCK Iosb;
|
|
LONG NumArgs;
|
|
ULONG i;
|
|
|
|
LARGE_INTEGER Offset;
|
|
|
|
ULONG IOLength;
|
|
LARGE_INTEGER TmpLength;
|
|
|
|
ULONG Key;
|
|
|
|
TESTPARAMS LockOptions[] = {
|
|
|
|
{ "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber},
|
|
|
|
{ "Offset ", LargeInteger, 0, "0,0", NULL, 0, &Offset },
|
|
|
|
{ "Length", Integer, 0xffff, NULL, NULL, 0, &IOLength },
|
|
|
|
{ "Key ", Integer, 0, NULL, NULL, 0, &Key }
|
|
|
|
};
|
|
|
|
NumArgs = Parse_Options(LockOptions, sizeoftable(LockOptions), ArgC,ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
conprompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
TmpLength.QuadPart = IOLength;
|
|
Status = NtUnlockFile(FileTable[FileNumber],
|
|
&Iosb, // I/O Status block
|
|
&Offset, // Read offset to file.
|
|
&TmpLength, // Length.
|
|
Key); // Key.
|
|
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtLockFile failed immediately, Status = %X\n", Status));
|
|
return;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Iosb.Status)) {
|
|
dprintf(("Final return from NtLockFile failed, Status = %X\n",Status));
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
FS_INFORMATION_CLASS
|
|
DirInformation;
|
|
|
|
PARSETABLE
|
|
DirTable[] = {
|
|
NamedField(FileNamesInformation),
|
|
NamedField(FileDirectoryInformation),
|
|
NamedField(FileFullDirectoryInformation)
|
|
};
|
|
|
|
ULONG
|
|
Single;
|
|
|
|
ULONG
|
|
RestartScan;
|
|
|
|
//DirNames <handle#> <length> <single> <fs class> <filename> <restart>
|
|
|
|
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<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]==NULL) {
|
|
CHAR Answer[5];
|
|
conprompt("File not in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
RtlInitString(&FileName, NameBuffer);
|
|
|
|
Status = NtQueryDirectoryFile(FileTable[FileNumber],
|
|
NULL, // Wait on handle directly.
|
|
NULL, // APC routine
|
|
NULL, // APC context
|
|
&Iosb, // I/O Status block.
|
|
QDirBuffer, // Output buffer
|
|
IOLength, // Output buffer length,
|
|
DirInformation,
|
|
(BOOLEAN)Single,// Return Single Entry
|
|
(FileName.Length)? &FileName: NULL,
|
|
(BOOLEAN) RestartScan );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtQueryDirectoryFile failed. Status=%X\n", Status));
|
|
if ( Status != STATUS_BUFFER_OVERFLOW ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Iosb.Status)) {
|
|
dprintf(("NtQueryDirectoryFile failed2. Status=%X\n", Iosb.Status));
|
|
if ( Status != STATUS_BUFFER_OVERFLOW ) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
dprintf(("%ld bytes of information returned\n", Iosb.Information));
|
|
switch (DirInformation) {
|
|
|
|
|
|
case FileNamesInformation:
|
|
DumpNamesInformation(QDirBuffer, Iosb.Information);
|
|
break;
|
|
|
|
case FileDirectoryInformation:
|
|
DumpDirectoryInformation(QDirBuffer, Iosb.Information);
|
|
break;
|
|
|
|
case FileFullDirectoryInformation:
|
|
DumpFullDirectoryInformation(QDirBuffer, Iosb.Information);
|
|
break;
|
|
|
|
default:
|
|
dprintf(("Unknown DirInformation class value %lx\n", DirInformation));
|
|
break;
|
|
}
|
|
}
|
|
|
|
UCHAR Buffer[256];
|
|
|
|
TESTPARAMS TypeOptions[] = {
|
|
{ "File Name", String,0, DD_NFS_DEVICE_NAME "\\AutoExec.Bat",NULL,0,Buffer },
|
|
{ "Root Directory", Integer, -1, NULL, NULL, 0, &RootFileNumber }
|
|
};
|
|
|
|
VOID
|
|
TestType(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
{
|
|
ULONG i;
|
|
IO_STATUS_BLOCK Iosb;
|
|
STRING FileName;
|
|
UNICODE_STRING FileNameU;
|
|
HANDLE Handle;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PVOID OutputBuffer;
|
|
LONG NumArgs;
|
|
NTSTATUS Status;
|
|
ULONG OutputBufferLength = 0x10000;
|
|
|
|
OutputBuffer = RtlAllocateHeap(Heap, 0, OutputBufferLength);
|
|
|
|
if (OutputBuffer == NULL) {
|
|
dprintf(("Could not allocate heap to hold file contents\n"));
|
|
return;
|
|
}
|
|
|
|
NumArgs = Parse_Options(TypeOptions, sizeoftable(TypeOptions), ArgC,ArgV);
|
|
|
|
RtlInitString(&FileName, Buffer);
|
|
|
|
RtlAnsiStringToUnicodeString(&FileNameU, &FileName, TRUE);
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&FileNameU, OBJ_CASE_INSENSITIVE,
|
|
(RootFileNumber==-1? NULL : FileTable[RootFileNumber]),
|
|
NULL);
|
|
|
|
dprintf(("NtOpenFile for file %Z\n", &FileName));
|
|
|
|
Status = NtOpenFile(&Handle,
|
|
SYNCHRONIZE | FILE_READ_DATA,
|
|
&ObjectAttributes,
|
|
&Iosb,
|
|
FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_ALERT | FILE_NON_DIRECTORY_FILE);
|
|
|
|
RtlFreeUnicodeString(&FileNameU);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtOpenFile(%Z) failed, Status == %X\n", &FileName,Status));
|
|
RtlFreeHeap(Heap, 0, OutputBuffer);
|
|
|
|
return;
|
|
} else {
|
|
Status = Iosb.Status;
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtOpenFile(%Z) failed2, Status == %X\n", &FileName,
|
|
Status));
|
|
RtlFreeHeap(Heap, 0, OutputBuffer);
|
|
return;
|
|
}
|
|
}
|
|
|
|
DumpFinalDisposition(Iosb.Information);
|
|
|
|
while (NT_SUCCESS(Status) && Status != STATUS_END_OF_FILE) {
|
|
Status = NtReadFile(Handle,
|
|
NULL, // Wait on handle directly.
|
|
NULL, // APC routine
|
|
NULL, // APC context
|
|
&Iosb, // I/O Status block.
|
|
OutputBuffer, // Output buffer
|
|
OutputBufferLength, // Output buffer length,
|
|
NULL, // Offset into file.
|
|
NULL); // Key
|
|
|
|
//
|
|
// If we reached end of file, we're done now.
|
|
//
|
|
|
|
if (Status == STATUS_END_OF_FILE) {
|
|
break;
|
|
}
|
|
|
|
dprintf(("Read %ld bytes from file, Status = %X\n", Iosb.Information, Status));
|
|
|
|
for (i = 0 ; i < Iosb.Information ; i++) {
|
|
dprintf(("%c", ((PUCHAR )OutputBuffer)[i]));
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtReadFile(%Z) failed, Status == %X\n", &FileName,Status));
|
|
RtlFreeHeap(Heap, 0, OutputBuffer);
|
|
NtClose(Handle);
|
|
return;
|
|
} else {
|
|
Status = Iosb.Status;
|
|
if (!NT_SUCCESS(Status)) {
|
|
RtlFreeHeap(Heap, 0, OutputBuffer);
|
|
dprintf(("NtReadFile(%Z) failed2, Status == %X\n", &FileName,
|
|
Status));
|
|
NtClose(Handle);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
NtClose(Handle);
|
|
|
|
RtlFreeHeap(Heap, 0, OutputBuffer);
|
|
}
|
|
|
|
TESTPARAMS TreeConnectOptions[] = {
|
|
{ "Share Name", String,0, DD_NFS_DEVICE_NAME "\\NtServer\\Nt", NULL,0, Buffer },
|
|
{ "File Handle", Integer, -1, NULL, NULL, 0, &FileNumber }
|
|
};
|
|
|
|
VOID
|
|
TestTreeConnect(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine issues the NT version of the MKDIR API.
|
|
|
|
Arguments:
|
|
|
|
IN ULONG ArgC, - [Supplies | Returns] description-of-argument
|
|
IN PSZ ArgV[] - [Supplies | Returns] description-of-argument
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
IO_STATUS_BLOCK Iosb;
|
|
HANDLE Handle;
|
|
OBJECT_ATTRIBUTES ObjAttrib;
|
|
STRING DirName;
|
|
UNICODE_STRING DirNameU;
|
|
LONG NumArgs;
|
|
ULONG Disposition, FileOptions;
|
|
NTSTATUS Status;
|
|
|
|
NumArgs = Parse_Options(TreeConnectOptions ,
|
|
sizeoftable(TreeConnectOptions) , ArgC , ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
if (FileNumber == -1) {
|
|
for (i = 0;i<TEST_MAX_FILES;i++) {
|
|
if (FileTable[i]==NULL) {
|
|
FileNumber = i;
|
|
break;
|
|
}
|
|
}
|
|
} else {
|
|
while (TRUE) {
|
|
if (FileTable[FileNumber]!=NULL) {
|
|
CHAR Answer[5];
|
|
conprompt("File already in use, continue? [N]", Answer, 5);
|
|
if (Answer[0]=='N' || Answer[0]=='n' || Answer[0] == '\0') {
|
|
return;
|
|
}
|
|
if (isdigit(Answer[0])) {
|
|
FileNumber = atoi(Answer);
|
|
continue;
|
|
} else {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
RtlInitString(&DirName, Buffer);
|
|
|
|
RtlAnsiStringToUnicodeString(&DirNameU, &DirName, TRUE);
|
|
|
|
InitializeObjectAttributes(&ObjAttrib, &DirNameU,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL, // Root directory
|
|
NULL);
|
|
|
|
FileOptions = FILE_CREATE_TREE_CONNECTION;
|
|
Disposition = FILE_CREATE;
|
|
|
|
Dump_Object_Attributes(&ObjAttrib);
|
|
Dump_Disposition(Disposition);
|
|
Dump_Options(FileOptions);
|
|
|
|
Status = NtCreateFile(&Handle,
|
|
GENERIC_READ | GENERIC_WRITE | DELETE,
|
|
&ObjAttrib,
|
|
&Iosb,
|
|
NULL, // File Size (not specified).
|
|
FILE_ATTRIBUTE_NORMAL, // Attribute.
|
|
0, // Sharing mode
|
|
Disposition,// File disposition
|
|
FileOptions, // Create Options
|
|
NULL, // EA Buffer
|
|
0); // EA Length
|
|
|
|
RtlFreeUnicodeString(&DirNameU);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtCreateFile failed, status==%X\n", Status));
|
|
return;
|
|
}
|
|
if (!NT_SUCCESS(Iosb.Status)) {
|
|
dprintf(("NtCreateFile failed in status block, Status==%X", Iosb.Status));
|
|
return;
|
|
}
|
|
|
|
DumpFinalDisposition(Iosb.Information);
|
|
|
|
dprintf(("Storing handle %lx in table entry %d\n", Handle, FileNumber));
|
|
|
|
FileTable[FileNumber] = Handle;
|
|
|
|
}
|
|
|
|
|
|
TESTPARAMS MkdirOptions[] = {
|
|
{ "Directory Name", String,0, DD_NFS_DEVICE_NAME "\\Directory",NULL,0, Buffer },
|
|
{ "Root Directory", Integer, -1, NULL, NULL, 0, &RootFileNumber }
|
|
};
|
|
|
|
|
|
VOID
|
|
TestMkdir(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine issues the NT version of the MKDIR API.
|
|
|
|
Arguments:
|
|
|
|
IN ULONG ArgC, - [Supplies | Returns] description-of-argument
|
|
IN PSZ ArgV[] - [Supplies | Returns] description-of-argument
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
IO_STATUS_BLOCK Iosb;
|
|
HANDLE Directory;
|
|
OBJECT_ATTRIBUTES ObjAttrib;
|
|
STRING DirName;
|
|
UNICODE_STRING DirNameU;
|
|
NTSTATUS Status;
|
|
LONG NumArgs;
|
|
|
|
NumArgs = Parse_Options(MkdirOptions,sizeoftable(MkdirOptions),ArgC,ArgV);
|
|
|
|
if (NumArgs < 0) {
|
|
return;
|
|
}
|
|
|
|
RtlInitString(&DirName, Buffer);
|
|
|
|
RtlAnsiStringToUnicodeString(&DirNameU, &DirName, TRUE);
|
|
|
|
InitializeObjectAttributes(&ObjAttrib, &DirNameU,
|
|
OBJ_CASE_INSENSITIVE,
|
|
(RootFileNumber==-1? NULL : FileTable[RootFileNumber]),
|
|
NULL);
|
|
|
|
Status = NtCreateFile(&Directory,
|
|
0,
|
|
&ObjAttrib,
|
|
&Iosb,
|
|
NULL, // File Size (not specified).
|
|
FILE_ATTRIBUTE_NORMAL, // Attribute.
|
|
0, // Sharing mode
|
|
FILE_CREATE,// File disposition
|
|
FILE_DIRECTORY_FILE, // Create Options
|
|
NULL, // EA Buffer
|
|
0); // EA Length
|
|
|
|
RtlFreeUnicodeString(&DirNameU);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
dprintf(("NtCreateFile failed, status==%X\n", Status));
|
|
return;
|
|
}
|
|
if (!NT_SUCCESS(Iosb.Status)) {
|
|
dprintf(("NtCreateFile failed in status block, Status==%X", Iosb.Status));
|
|
return;
|
|
}
|
|
|
|
dprintf(("Final Disposition: %lx\n", Iosb.Information));
|
|
|
|
//
|
|
// Close the directory.
|
|
//
|
|
|
|
NtClose(Directory);
|
|
|
|
}
|
|
TESTPARAMS CmdFileOptions[] = {
|
|
{ "FileName", String,0, "redir",NULL,0, Buffer }
|
|
};
|
|
|
|
|
|
VOID
|
|
CmdFile(
|
|
ULONG ArgC,
|
|
PSZ ArgV[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine reads a file full of reader test commands into
|
|
the buffer.
|
|
|
|
Arguments:
|
|
|
|
IN ULONG ArgC, - [Supplies | Returns] description-of-argument
|
|
IN PSZ ArgV[] - [Supplies | Returns] description-of-argument
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
STRING FileName;
|
|
|
|
if (Parse_Options(CmdFileOptions,sizeoftable(CmdFileOptions),ArgC,ArgV)<0){
|
|
return;
|
|
}
|
|
|
|
RtlInitString(&FileName, Buffer);
|
|
LoadBatchFile(&FileName);
|
|
}
|
|
|
|
LONG
|
|
Parse_Options (
|
|
IN TESTPARAMS Options[],
|
|
IN ULONG TestSize,
|
|
IN ULONG ArgC,
|
|
IN PSZ ArgV[]
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine parses a table
|
|
.
|
|
Arguments:
|
|
|
|
IN PARSE_PARAMS Option, - [Supplies | Returns] description-of-argument
|
|
IN ULONG ArgC, - [Supplies | Returns] description-of-argument
|
|
IN PSZ ArgV[] - [Supplies | Returns] description-of-argument
|
|
|
|
Return Value:
|
|
|
|
LONG = -1 if there was a parse error.
|
|
= The number of parameters "eaten" otherwise.
|
|
--*/
|
|
|
|
{
|
|
ULONG i;
|
|
UCHAR Buffer[100];
|
|
UCHAR Prompt[100];
|
|
PUCHAR NextToken;
|
|
LONG RetVal;
|
|
BOOLEAN Reparse;
|
|
BOOLEAN Error;
|
|
|
|
if (ArgC) {
|
|
ArgC -= 1; // Don't count command in args.
|
|
}
|
|
|
|
RetVal = min(ArgC, TestSize);
|
|
|
|
for (i=0;i<TestSize;i++) {
|
|
switch (Options[i].TestType) {
|
|
case Integer:
|
|
*(PULONG )Options[i].Destination = Options[i].IntegerDefault;
|
|
break;
|
|
|
|
case LargeInteger:
|
|
ParseLargeInteger(Options[i].StringDefault,
|
|
Options[i].Destination);
|
|
break;
|
|
|
|
case String:
|
|
if (Options[i].StringDefault != NULL) {
|
|
strcpy((PSZ )Options[i].Destination, Options[i].StringDefault);
|
|
} else {
|
|
((PSZ )Options[i].Destination)[0] = '\0';
|
|
}
|
|
break;
|
|
|
|
case UnicodeString:
|
|
if (Options[i].StringDefault != NULL) {
|
|
wcscpy((PWSTR )Options[i].Destination, (PWSTR)Options[i].StringDefault);
|
|
} else {
|
|
((PWSTR )Options[i].Destination)[0] = '\0';
|
|
}
|
|
break;
|
|
|
|
case DateAndTime:
|
|
ParseDateAndTime(Options[i].StringDefault, Options[i].Destination);
|
|
break;
|
|
|
|
case ParsedInteger:
|
|
ParseInteger(Options[i].StringDefault, Options[i].ParsedIntTable,
|
|
Options[i].ParsedIntTableSize,
|
|
Options[i].Destination);
|
|
break;
|
|
|
|
case IntegerValue:
|
|
ParseIntegerValue(Options[i].StringDefault, Options[i].ParsedIntTable,
|
|
Options[i].ParsedIntTableSize,
|
|
Options[i].Destination);
|
|
}
|
|
|
|
}
|
|
|
|
// DbgBreakPoint();
|
|
for (i=1;i<=TestSize;i++) {
|
|
PTESTPARAMS ParsePtr = &Options[i-1];
|
|
|
|
//
|
|
// If there is a command line argument, use it for the argument,
|
|
// otherwise prompt for the argument.
|
|
//
|
|
|
|
Reparse = TRUE;
|
|
|
|
if (ArgC >= 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;
|
|
|
|
|
|
}
|