1955 lines
51 KiB
C
1955 lines
51 KiB
C
|
#include "brian.h"
|
|||
|
|
|||
|
#define PEAN_INDEX_DEFAULT 0
|
|||
|
#define PEAN_OFFSET_DEFAULT 0
|
|||
|
#define PEAN_NEXT_OFFSET_DEFAULT NULL
|
|||
|
#define PEAN_ACT_NEXT_OFF_DEFAULT 0
|
|||
|
#define PEAN_NAME_DEFAULT NULL
|
|||
|
#define PEAN_VERBOSE_DEFAULT TRUE
|
|||
|
#define PEAN_DISPLAY_PARMS_DEFAULT FALSE
|
|||
|
#define PEAN_MORE_EAS_DEFAULT FALSE
|
|||
|
|
|||
|
#define FEA_INDEX_DEFAULT 0
|
|||
|
#define FEA_OFFSET_DEFAULT 0
|
|||
|
#define FEA_NEXT_OFFSET_DEFAULT NULL
|
|||
|
#define FEA_ACT_NEXT_OFF_DEFAULT 0
|
|||
|
#define FEA_NAME_DEFAULT NULL
|
|||
|
#define FEA_VALUE_DEFAULT NULL
|
|||
|
#define FEA_FLAGS_DEFAULT NULL
|
|||
|
#define FEA_ACTUAL_FLAGS_DEFAULT 0
|
|||
|
#define FEA_VERBOSE_DEFAULT TRUE
|
|||
|
#define FEA_DISPLAY_PARMS_DEFAULT FALSE
|
|||
|
#define FEA_MORE_EAS_DEFAULT FALSE
|
|||
|
|
|||
|
#define QEA_FILE_HANDLE_DEFAULT 0
|
|||
|
#define QEA_BUFFER_INDEX_DEFAULT 0
|
|||
|
#define QEA_BUFFER_LENGTH_DEFAULT NULL
|
|||
|
#define QEA_RETURN_SINGLE_DEFAULT FALSE
|
|||
|
#define QEA_EA_NAME_BUFFER_DEFAULT NULL
|
|||
|
#define QEA_EA_NAME_BUFFER_LEN_DEFAULT NULL
|
|||
|
#define QEA_EA_INDEX_DEFAULT NULL
|
|||
|
#define QEA_RESTART_SCAN_DEFAULT FALSE
|
|||
|
#define QEA_VERBOSE_DEFAULT TRUE
|
|||
|
|
|||
|
#define SEA_FILE_HANDLE_DEFAULT 0
|
|||
|
#define SEA_BUFFER_INDEX_DEFAULT 0
|
|||
|
#define SEA_BUFFER_LENGTH_DEFAULT NULL
|
|||
|
#define SEA_VERBOSE_DEFAULT FALSE
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PutEaName(
|
|||
|
IN ULONG BufferIndex,
|
|||
|
IN ULONG Offset,
|
|||
|
IN PULONG NextOffset,
|
|||
|
IN PSTRING Name,
|
|||
|
IN BOOLEAN Verbose,
|
|||
|
IN BOOLEAN DisplayParms,
|
|||
|
IN BOOLEAN MoreEas
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FillEaBuffer(
|
|||
|
IN ULONG BufferIndex,
|
|||
|
IN ULONG Offset,
|
|||
|
IN PULONG NextOffset,
|
|||
|
IN PUCHAR Flags,
|
|||
|
IN PSTRING Name,
|
|||
|
IN PSTRING Value,
|
|||
|
IN BOOLEAN MoreEas,
|
|||
|
IN BOOLEAN Verbose,
|
|||
|
IN BOOLEAN DisplayParms
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
QueryEa(
|
|||
|
IN ULONG FileHandleIndex,
|
|||
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
|||
|
IN ULONG BufferIndex,
|
|||
|
IN PULONG BufferLength OPTIONAL,
|
|||
|
IN BOOLEAN ReturnSingleEntry,
|
|||
|
IN PULONG EaNameBuffer OPTIONAL,
|
|||
|
IN PULONG EaNameBufferLength OPTIONAL,
|
|||
|
IN PULONG EaIndex,
|
|||
|
IN BOOLEAN RestartScan,
|
|||
|
IN BOOLEAN VerboseResults,
|
|||
|
IN BOOLEAN DisplayParms
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SetEa(
|
|||
|
IN ULONG FileHandleIndex,
|
|||
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
|||
|
IN ULONG BufferIndex,
|
|||
|
IN PULONG BufferLength OPTIONAL,
|
|||
|
IN BOOLEAN VerboseResults,
|
|||
|
IN BOOLEAN DisplayParms
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
InputPutEaName(
|
|||
|
IN PCHAR ParamBuffer
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG BufferIndex;
|
|||
|
ULONG Offset;
|
|||
|
PULONG NextOffset;
|
|||
|
ULONG ActualNextOffset;
|
|||
|
PSTRING Name;
|
|||
|
STRING ActualName;
|
|||
|
BOOLEAN VerboseResults;
|
|||
|
BOOLEAN DisplayParms;
|
|||
|
BOOLEAN ParamReceived;
|
|||
|
BOOLEAN LastInput;
|
|||
|
PCHAR EaNameTemp;
|
|||
|
BOOLEAN MoreEas;
|
|||
|
|
|||
|
BufferIndex = PEAN_INDEX_DEFAULT;
|
|||
|
Offset = PEAN_OFFSET_DEFAULT;
|
|||
|
NextOffset = PEAN_NEXT_OFFSET_DEFAULT;
|
|||
|
ActualNextOffset = PEAN_ACT_NEXT_OFF_DEFAULT;
|
|||
|
Name = PEAN_NAME_DEFAULT;
|
|||
|
VerboseResults = PEAN_VERBOSE_DEFAULT;
|
|||
|
DisplayParms = PEAN_DISPLAY_PARMS_DEFAULT;
|
|||
|
MoreEas = PEAN_MORE_EAS_DEFAULT;
|
|||
|
|
|||
|
ParamReceived = FALSE;
|
|||
|
LastInput = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// While there is more input, analyze the parameter and update the
|
|||
|
// query flags.
|
|||
|
//
|
|||
|
|
|||
|
while(TRUE) {
|
|||
|
|
|||
|
ULONG DummyCount;
|
|||
|
|
|||
|
//
|
|||
|
// Swallow leading white spaces.
|
|||
|
//
|
|||
|
ParamBuffer = SwallowWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
if (*ParamBuffer) {
|
|||
|
|
|||
|
//
|
|||
|
// If the next parameter is legal then check the paramter value.
|
|||
|
// Update the parameter value.
|
|||
|
//
|
|||
|
if((*ParamBuffer == '-'
|
|||
|
|| *ParamBuffer == '/')
|
|||
|
&& (ParamBuffer++, *ParamBuffer != '\0')) {
|
|||
|
|
|||
|
//
|
|||
|
// Switch on the next character.
|
|||
|
//
|
|||
|
|
|||
|
switch (*ParamBuffer) {
|
|||
|
|
|||
|
//
|
|||
|
// Update buffer to use.
|
|||
|
//
|
|||
|
case 'b' :
|
|||
|
case 'B' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
BufferIndex = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Check if we're adding more eas.
|
|||
|
//
|
|||
|
|
|||
|
case 'm' :
|
|||
|
case 'M' :
|
|||
|
|
|||
|
//
|
|||
|
// Legal values for params are T/t or F/f.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
if (*ParamBuffer == 'T'
|
|||
|
|| *ParamBuffer == 't') {
|
|||
|
|
|||
|
MoreEas = TRUE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
} else if (*ParamBuffer == 'F'
|
|||
|
|| *ParamBuffer == 'f' ) {
|
|||
|
|
|||
|
MoreEas = FALSE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Get the Ea name.
|
|||
|
//
|
|||
|
case 'n' :
|
|||
|
case 'N' :
|
|||
|
|
|||
|
//
|
|||
|
// Remember the buffer offset and get the filename.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
EaNameTemp = ParamBuffer;
|
|||
|
DummyCount = 0;
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
//
|
|||
|
// If the name length is 0, then ignore this entry.
|
|||
|
//
|
|||
|
if (DummyCount) {
|
|||
|
|
|||
|
ActualName.Buffer = EaNameTemp;
|
|||
|
ActualName.Length = (SHORT) DummyCount;
|
|||
|
ActualName.MaximumLength = (SHORT) DummyCount;
|
|||
|
Name = &ActualName;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Name = NULL;
|
|||
|
}
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update offset to store the information.
|
|||
|
//
|
|||
|
case 'o' :
|
|||
|
case 'O' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
Offset = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update the next offset field.
|
|||
|
//
|
|||
|
case 'x' :
|
|||
|
case 'X' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
ActualNextOffset = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
NextOffset = &ActualNextOffset;
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case 'v' :
|
|||
|
case 'V' :
|
|||
|
|
|||
|
//
|
|||
|
// Legal values for params are T/t or F/f.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
if (*ParamBuffer == 'T'
|
|||
|
|| *ParamBuffer == 't') {
|
|||
|
|
|||
|
VerboseResults = TRUE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
} else if (*ParamBuffer == 'F'
|
|||
|
|| *ParamBuffer == 'f') {
|
|||
|
|
|||
|
VerboseResults = FALSE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case 'y' :
|
|||
|
case 'Y' :
|
|||
|
|
|||
|
//
|
|||
|
// Set the display parms flag and jump over this
|
|||
|
// character.
|
|||
|
//
|
|||
|
DisplayParms = TRUE;
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case 'z' :
|
|||
|
case 'Z' :
|
|||
|
|
|||
|
//
|
|||
|
// Set flag for more input and jump over this char.
|
|||
|
//
|
|||
|
LastInput = FALSE;
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default :
|
|||
|
|
|||
|
//
|
|||
|
// Swallow to the next white space and continue the
|
|||
|
// loop.
|
|||
|
//
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Else the text is invalid, skip the entire block.
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Else if there is no input then exit.
|
|||
|
//
|
|||
|
} else if (LastInput) {
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Else try to read another line for open parameters.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If no parameters were received then display the syntax message.
|
|||
|
//
|
|||
|
if( !ParamReceived ) {
|
|||
|
|
|||
|
printf( "\n Usage: pea [options]* -b<digits> [options]*\n" );
|
|||
|
printf( "\n Options:" );
|
|||
|
printf( "\n -b<digits> Buffer index" );
|
|||
|
printf( "\n -n<ea name> EaName to store in buffer" );
|
|||
|
printf( "\n -o<digits> Offset in buffer to store data" );
|
|||
|
printf( "\n -x<digits> Value for next offset field" );
|
|||
|
printf( "\n -m[t|f] More Eas coming (Fills next offset field)" );
|
|||
|
printf( "\n -v[t|f] Verbose results" );
|
|||
|
printf( "\n -y Display parameters to query" );
|
|||
|
printf( "\n -z Additional input line" );
|
|||
|
printf( "\n\n" );
|
|||
|
|
|||
|
//
|
|||
|
// Else call our put ea name routine.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
PutEaName( BufferIndex,
|
|||
|
Offset,
|
|||
|
NextOffset,
|
|||
|
Name,
|
|||
|
VerboseResults,
|
|||
|
DisplayParms,
|
|||
|
MoreEas );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
PutEaName(
|
|||
|
IN ULONG BufferIndex,
|
|||
|
IN ULONG Offset,
|
|||
|
IN PULONG NextOffset,
|
|||
|
IN PSTRING Name,
|
|||
|
IN BOOLEAN Verbose,
|
|||
|
IN BOOLEAN DisplayParms,
|
|||
|
IN BOOLEAN MoreEas
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
ULONG DataLength;
|
|||
|
|
|||
|
//
|
|||
|
// Display parameters if requested.
|
|||
|
//
|
|||
|
|
|||
|
if (DisplayParms) {
|
|||
|
|
|||
|
printf( "\nPut Ea Name Parameters" );
|
|||
|
printf( "\n Buffer index -> %ld", BufferIndex );
|
|||
|
printf( "\n Buffer offset -> %08lx", Offset );
|
|||
|
if (NextOffset) {
|
|||
|
|
|||
|
printf( "\n Next offset -> %08lx", *NextOffset );
|
|||
|
|
|||
|
}
|
|||
|
if (Name) {
|
|||
|
|
|||
|
printf( "\n Ea name -> %S", &Name );
|
|||
|
}
|
|||
|
|
|||
|
printf( "\n MoreEas -> %d", MoreEas );
|
|||
|
printf( "\n\n" );
|
|||
|
}
|
|||
|
|
|||
|
if (Name) {
|
|||
|
|
|||
|
DataLength = 6 + Name->Length;
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DataLength = 5;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the index is unused, display message but take no action.
|
|||
|
//
|
|||
|
|
|||
|
if (!Buffers[BufferIndex].Used) {
|
|||
|
|
|||
|
printf( "\nPutEaName: Index refers to invalid buffer" );
|
|||
|
Status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// Else if the start offset is invalid, then display error
|
|||
|
// message.
|
|||
|
//
|
|||
|
|
|||
|
} else if (Offset >= Buffers[BufferIndex].Length) {
|
|||
|
|
|||
|
printf( "\nPutEaName: Start offset is invalid" );
|
|||
|
Status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// Else if length is insufficient to store all of the data
|
|||
|
// display message.
|
|||
|
//
|
|||
|
|
|||
|
} else if (DataLength >= Buffers[BufferIndex].Length) {
|
|||
|
|
|||
|
printf( "\nPutEaName: Data won't fit in buffer" );
|
|||
|
Status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// Else store the data in the buffer.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
PFILE_GET_EA_INFORMATION EaNameBuffer;
|
|||
|
|
|||
|
EaNameBuffer = (PFILE_GET_EA_INFORMATION)
|
|||
|
(Buffers[BufferIndex].Buffer + Offset);
|
|||
|
|
|||
|
//
|
|||
|
// Store the next offset if specified.
|
|||
|
//
|
|||
|
|
|||
|
if (NextOffset) {
|
|||
|
|
|||
|
EaNameBuffer->NextEntryOffset = *NextOffset;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Store the name and name length if specified.
|
|||
|
//
|
|||
|
|
|||
|
if (Name) {
|
|||
|
|
|||
|
EaNameBuffer->EaNameLength = (UCHAR) Name->Length;
|
|||
|
RtlMoveMemory( EaNameBuffer->EaName, Name->Buffer, Name->Length );
|
|||
|
}
|
|||
|
|
|||
|
if (MoreEas) {
|
|||
|
|
|||
|
EaNameBuffer->NextEntryOffset = (DataLength + 3) & ~3;
|
|||
|
}
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
if (Verbose) {
|
|||
|
|
|||
|
printf( "\nPutEaName: Status -> %08lx\n", Status );
|
|||
|
printf( " Following offset -> %ld\n",
|
|||
|
(DataLength + Offset + 3) & ~3 );
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
InputFillEaBuffer(
|
|||
|
IN PCHAR ParamBuffer
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG BufferIndex;
|
|||
|
ULONG Offset;
|
|||
|
PULONG NextOffset;
|
|||
|
ULONG ActualNextOffset;
|
|||
|
PSTRING Name;
|
|||
|
STRING ActualName;
|
|||
|
PSTRING Value;
|
|||
|
STRING ActualValue;
|
|||
|
PUCHAR Flags;
|
|||
|
UCHAR ActualFlags;
|
|||
|
BOOLEAN VerboseResults;
|
|||
|
BOOLEAN DisplayParms;
|
|||
|
BOOLEAN ParamReceived;
|
|||
|
BOOLEAN LastInput;
|
|||
|
BOOLEAN MoreEas;
|
|||
|
PCHAR StringTemp;
|
|||
|
|
|||
|
BufferIndex = FEA_INDEX_DEFAULT;
|
|||
|
Offset = FEA_OFFSET_DEFAULT;
|
|||
|
NextOffset = FEA_NEXT_OFFSET_DEFAULT;
|
|||
|
ActualNextOffset = FEA_ACT_NEXT_OFF_DEFAULT;
|
|||
|
Name = FEA_NAME_DEFAULT;
|
|||
|
Value = FEA_VALUE_DEFAULT;
|
|||
|
Flags = FEA_FLAGS_DEFAULT;
|
|||
|
ActualFlags = FEA_ACTUAL_FLAGS_DEFAULT;
|
|||
|
MoreEas = FEA_MORE_EAS_DEFAULT;
|
|||
|
VerboseResults = FEA_VERBOSE_DEFAULT;
|
|||
|
DisplayParms = FEA_DISPLAY_PARMS_DEFAULT;
|
|||
|
|
|||
|
ParamReceived = FALSE;
|
|||
|
LastInput = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// While there is more input, analyze the parameter and update the
|
|||
|
// query flags.
|
|||
|
//
|
|||
|
|
|||
|
while (TRUE) {
|
|||
|
|
|||
|
ULONG DummyCount;
|
|||
|
|
|||
|
//
|
|||
|
// Swallow leading white spaces.
|
|||
|
//
|
|||
|
ParamBuffer = SwallowWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
if (*ParamBuffer) {
|
|||
|
|
|||
|
//
|
|||
|
// If the next parameter is legal then check the paramter value.
|
|||
|
// Update the parameter value.
|
|||
|
//
|
|||
|
if((*ParamBuffer == '-'
|
|||
|
|| *ParamBuffer == '/')
|
|||
|
&& (ParamBuffer++, *ParamBuffer != '\0')) {
|
|||
|
|
|||
|
BOOLEAN SwitchBool;
|
|||
|
|
|||
|
//
|
|||
|
// Switch on the next character.
|
|||
|
//
|
|||
|
|
|||
|
switch (*ParamBuffer) {
|
|||
|
|
|||
|
//
|
|||
|
// Update buffer to use.
|
|||
|
//
|
|||
|
case 'b' :
|
|||
|
case 'B' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
BufferIndex = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update the flags field.
|
|||
|
//
|
|||
|
case 'f' :
|
|||
|
case 'F' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
SwitchBool = TRUE;
|
|||
|
while( *ParamBuffer
|
|||
|
&& *ParamBuffer != ' '
|
|||
|
&& *ParamBuffer != '\t' ) {
|
|||
|
|
|||
|
//
|
|||
|
// Perform switch on character.
|
|||
|
//
|
|||
|
switch (*ParamBuffer) {
|
|||
|
|
|||
|
case 'a' :
|
|||
|
case 'A' :
|
|||
|
ActualFlags |= FILE_NEED_EA;
|
|||
|
|
|||
|
Flags = &ActualFlags;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default :
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
SwitchBool = FALSE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (!SwitchBool) {
|
|||
|
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
ParamBuffer++;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Get the Ea name.
|
|||
|
//
|
|||
|
case 'n' :
|
|||
|
case 'N' :
|
|||
|
|
|||
|
//
|
|||
|
// Remember the buffer offset and get the filename.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
StringTemp = ParamBuffer;
|
|||
|
DummyCount = 0;
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
ActualName.Buffer = StringTemp;
|
|||
|
ActualName.Length = (SHORT) DummyCount;
|
|||
|
ActualName.MaximumLength = (SHORT) DummyCount;
|
|||
|
Name = &ActualName;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Get the Ea value.
|
|||
|
//
|
|||
|
case 'l' :
|
|||
|
case 'L' :
|
|||
|
|
|||
|
//
|
|||
|
// Remember the buffer offset and get the value.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
StringTemp = ParamBuffer;
|
|||
|
DummyCount = 0;
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
ActualValue.Buffer = StringTemp;
|
|||
|
ActualValue.Length = (SHORT) DummyCount;
|
|||
|
ActualValue.MaximumLength = (SHORT) DummyCount;
|
|||
|
Value = &ActualValue;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Check if we're adding more eas.
|
|||
|
//
|
|||
|
|
|||
|
case 'm' :
|
|||
|
case 'M' :
|
|||
|
|
|||
|
//
|
|||
|
// Legal values for params are T/t or F/f.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
if (*ParamBuffer == 'T'
|
|||
|
|| *ParamBuffer == 't') {
|
|||
|
|
|||
|
MoreEas = TRUE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
} else if (*ParamBuffer == 'F'
|
|||
|
|| *ParamBuffer == 'f') {
|
|||
|
|
|||
|
MoreEas = FALSE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update offset to store the information.
|
|||
|
//
|
|||
|
case 'o' :
|
|||
|
case 'O' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
Offset = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update the next offset field.
|
|||
|
//
|
|||
|
case 'x' :
|
|||
|
case 'X' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
ActualNextOffset = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
NextOffset = &ActualNextOffset;
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case 'v' :
|
|||
|
case 'V' :
|
|||
|
|
|||
|
//
|
|||
|
// Legal values for params are T/t or F/f.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
if (*ParamBuffer == 'T'
|
|||
|
|| *ParamBuffer == 't') {
|
|||
|
|
|||
|
VerboseResults = TRUE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
} else if (*ParamBuffer == 'F'
|
|||
|
|| *ParamBuffer == 'f') {
|
|||
|
|
|||
|
VerboseResults = FALSE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case 'y' :
|
|||
|
case 'Y' :
|
|||
|
|
|||
|
//
|
|||
|
// Set the display parms flag and jump over this
|
|||
|
// character.
|
|||
|
//
|
|||
|
DisplayParms = TRUE;
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case 'z' :
|
|||
|
case 'Z' :
|
|||
|
|
|||
|
//
|
|||
|
// Set flag for more input and jump over this char.
|
|||
|
//
|
|||
|
LastInput = FALSE;
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default :
|
|||
|
|
|||
|
//
|
|||
|
// Swallow to the next white space and continue the
|
|||
|
// loop.
|
|||
|
//
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Else the text is invalid, skip the entire block.
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Else if there is no input then exit.
|
|||
|
//
|
|||
|
} else if (LastInput) {
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Else try to read another line for open parameters.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If no parameters were received then display the syntax message.
|
|||
|
//
|
|||
|
if (!ParamReceived) {
|
|||
|
|
|||
|
printf( "\n Usage: fea [options]* -b<digits> [options]*\n" );
|
|||
|
printf( "\n Options:" );
|
|||
|
printf( "\n -b<digits> Buffer index" );
|
|||
|
printf( "\n -f<chars> Ea flags to store in buffer" );
|
|||
|
printf( "\n -n<chars> EaName to store in buffer" );
|
|||
|
printf( "\n -l<chars> Ea value to store in buffer" );
|
|||
|
printf( "\n -m[t|f] More Eas coming (Fills next offset field)" );
|
|||
|
printf( "\n -o<digits> Offset in buffer to store data" );
|
|||
|
printf( "\n -x<digits> Value for next offset field" );
|
|||
|
printf( "\n -v[t|f] Verbose results" );
|
|||
|
printf( "\n -y Display parameters to query" );
|
|||
|
printf( "\n -z Additional input line" );
|
|||
|
printf( "\n\n" );
|
|||
|
|
|||
|
//
|
|||
|
// Else call our put ea name routine.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
FillEaBuffer( BufferIndex,
|
|||
|
Offset,
|
|||
|
NextOffset,
|
|||
|
Flags,
|
|||
|
Name,
|
|||
|
Value,
|
|||
|
MoreEas,
|
|||
|
VerboseResults,
|
|||
|
DisplayParms );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
FillEaBuffer(
|
|||
|
IN ULONG BufferIndex,
|
|||
|
IN ULONG Offset,
|
|||
|
IN PULONG NextOffset,
|
|||
|
IN PUCHAR Flags,
|
|||
|
IN PSTRING Name,
|
|||
|
IN PSTRING Value,
|
|||
|
IN BOOLEAN MoreEas,
|
|||
|
IN BOOLEAN Verbose,
|
|||
|
IN BOOLEAN DisplayParms
|
|||
|
)
|
|||
|
{
|
|||
|
|
|||
|
NTSTATUS Status;
|
|||
|
ULONG DataLength;
|
|||
|
|
|||
|
//
|
|||
|
// Display parameters if requested.
|
|||
|
//
|
|||
|
|
|||
|
if (DisplayParms) {
|
|||
|
|
|||
|
printf( "\nFill Ea Buffer Parameters" );
|
|||
|
printf( "\n Buffer index -> %ld", BufferIndex );
|
|||
|
printf( "\n Buffer offset -> %08lx", Offset );
|
|||
|
if (NextOffset) {
|
|||
|
|
|||
|
printf( "\n Next offset -> %08lx", *NextOffset );
|
|||
|
}
|
|||
|
|
|||
|
if (Flags) {
|
|||
|
|
|||
|
printf( "\n Flags -> %02x", *Flags );
|
|||
|
}
|
|||
|
|
|||
|
if (Name) {
|
|||
|
|
|||
|
printf( "\n Ea name -> %S", Name );
|
|||
|
}
|
|||
|
|
|||
|
if (Value) {
|
|||
|
|
|||
|
printf( "\n Value -> %S", Value );
|
|||
|
}
|
|||
|
|
|||
|
printf( "\n MoreEas -> %d", MoreEas );
|
|||
|
printf( "\n\n" );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
DataLength = 0;
|
|||
|
|
|||
|
if (NextOffset) {
|
|||
|
|
|||
|
DataLength = 4;
|
|||
|
}
|
|||
|
|
|||
|
if (Flags) {
|
|||
|
|
|||
|
DataLength = 5;
|
|||
|
}
|
|||
|
|
|||
|
if (Name) {
|
|||
|
|
|||
|
DataLength = 9 + Name->Length;
|
|||
|
|
|||
|
if (Value) {
|
|||
|
|
|||
|
if (Value->Length) {
|
|||
|
|
|||
|
DataLength += (Value->Length + 4);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} else if (Value) {
|
|||
|
|
|||
|
DataLength = 9;
|
|||
|
|
|||
|
if (Value->Length) {
|
|||
|
|
|||
|
DataLength = 9 + (Value->Length + 4);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If the index is unused, display message but take no action.
|
|||
|
//
|
|||
|
|
|||
|
if (!Buffers[BufferIndex].Used) {
|
|||
|
|
|||
|
printf( "\nFillEaBuffer: Index refers to invalid buffer" );
|
|||
|
Status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// Else if the start offset is invalid, then display error
|
|||
|
// message.
|
|||
|
//
|
|||
|
|
|||
|
} else if (Offset >= Buffers[BufferIndex].Length) {
|
|||
|
|
|||
|
printf( "\nFillEaBuffer: Start offset is invalid" );
|
|||
|
Status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// Else if length is insufficient to store all of the data
|
|||
|
// display message.
|
|||
|
//
|
|||
|
|
|||
|
} else if (DataLength >= Buffers[BufferIndex].Length) {
|
|||
|
|
|||
|
printf( "\nFillEaBuffer: Data won't fit in buffer" );
|
|||
|
Status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// Else store the data in the buffer.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
PFILE_FULL_EA_INFORMATION EaBuffer;
|
|||
|
|
|||
|
EaBuffer = (PFILE_FULL_EA_INFORMATION)
|
|||
|
(Buffers[BufferIndex].Buffer + Offset);
|
|||
|
|
|||
|
//
|
|||
|
// Store the next offset if specified.
|
|||
|
//
|
|||
|
|
|||
|
if (NextOffset) {
|
|||
|
|
|||
|
EaBuffer->NextEntryOffset = *NextOffset;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Store the flags if specified.
|
|||
|
//
|
|||
|
|
|||
|
if (Flags) {
|
|||
|
|
|||
|
EaBuffer->Flags = *Flags;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Store the name and name length if specified.
|
|||
|
//
|
|||
|
|
|||
|
if (Name) {
|
|||
|
|
|||
|
EaBuffer->EaNameLength = (UCHAR) Name->Length;
|
|||
|
RtlMoveMemory( EaBuffer->EaName, Name->Buffer, Name->Length );
|
|||
|
EaBuffer->EaName[Name->Length] = '\0';
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Store the value if specified.
|
|||
|
//
|
|||
|
|
|||
|
if (Value) {
|
|||
|
|
|||
|
ULONG Index;
|
|||
|
USHORT ValueLength;
|
|||
|
PUSHORT ActualValueLength;
|
|||
|
|
|||
|
ValueLength = (USHORT) (Value->Length ? Value->Length + 4 : 0);
|
|||
|
|
|||
|
Index = DataLength - 8 - Value->Length - 4;
|
|||
|
|
|||
|
EaBuffer->EaValueLength = ValueLength;
|
|||
|
|
|||
|
if (ValueLength) {
|
|||
|
|
|||
|
EaBuffer->EaName[Index++] = (CHAR) 0xFD;
|
|||
|
EaBuffer->EaName[Index++] = (CHAR) 0xFF;
|
|||
|
|
|||
|
ActualValueLength = (PUSHORT) &EaBuffer->EaName[Index++];
|
|||
|
|
|||
|
*ActualValueLength = Value->Length;
|
|||
|
|
|||
|
Index++;
|
|||
|
|
|||
|
RtlMoveMemory( &EaBuffer->EaName[Index],
|
|||
|
Value->Buffer,
|
|||
|
Value->Length );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update the next entry field automatically.
|
|||
|
//
|
|||
|
|
|||
|
if (MoreEas && !NextOffset) {
|
|||
|
|
|||
|
EaBuffer->NextEntryOffset = (DataLength + 3) & ~3;
|
|||
|
}
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
if (Verbose) {
|
|||
|
|
|||
|
printf( "\nFillEaBuffer: Status -> %08lx\n", Status );
|
|||
|
printf( " Following offset -> %ld\n",
|
|||
|
(DataLength + Offset + 3) & ~3 );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
InputQueryEa(
|
|||
|
IN PCHAR ParamBuffer
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG FileHandleIndex;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
ULONG BufferIndex;
|
|||
|
PULONG BufferLength;
|
|||
|
ULONG ActualBufferLength;
|
|||
|
BOOLEAN ReturnSingleEntry;
|
|||
|
PULONG EaNameBuffer;
|
|||
|
ULONG ActualEaNameBuffer;
|
|||
|
PULONG EaNameBufferLength;
|
|||
|
ULONG ActualEaNameBufferLength;
|
|||
|
PULONG EaIndex;
|
|||
|
ULONG ActualEaIndex;
|
|||
|
BOOLEAN RestartScan;
|
|||
|
|
|||
|
BOOLEAN VerboseResults;
|
|||
|
BOOLEAN DisplayParms;
|
|||
|
BOOLEAN ParamReceived;
|
|||
|
BOOLEAN LastInput;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize to the default value.
|
|||
|
//
|
|||
|
|
|||
|
FileHandleIndex = QEA_FILE_HANDLE_DEFAULT;
|
|||
|
BufferIndex = QEA_BUFFER_INDEX_DEFAULT;
|
|||
|
BufferLength = QEA_BUFFER_LENGTH_DEFAULT;
|
|||
|
ReturnSingleEntry = QEA_RETURN_SINGLE_DEFAULT;
|
|||
|
EaNameBuffer = QEA_EA_NAME_BUFFER_DEFAULT;
|
|||
|
EaNameBufferLength = QEA_EA_NAME_BUFFER_LEN_DEFAULT;
|
|||
|
EaIndex = QEA_EA_INDEX_DEFAULT;
|
|||
|
RestartScan = QEA_RESTART_SCAN_DEFAULT;
|
|||
|
VerboseResults = QEA_VERBOSE_DEFAULT;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the other interesting values.
|
|||
|
//
|
|||
|
|
|||
|
ActualBufferLength = 0;
|
|||
|
ActualEaNameBuffer = 0;
|
|||
|
ActualEaNameBufferLength = 0;
|
|||
|
ActualEaIndex = 0;
|
|||
|
DisplayParms = FALSE;
|
|||
|
ParamReceived = FALSE;
|
|||
|
LastInput = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// While there is more input, analyze the parameter and update the
|
|||
|
// query flags.
|
|||
|
//
|
|||
|
|
|||
|
while (TRUE) {
|
|||
|
|
|||
|
ULONG DummyCount;
|
|||
|
|
|||
|
//
|
|||
|
// Swallow leading white spaces.
|
|||
|
//
|
|||
|
|
|||
|
ParamBuffer = SwallowWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
if (*ParamBuffer) {
|
|||
|
|
|||
|
//
|
|||
|
// If the next parameter is legal then check the paramter value.
|
|||
|
// Update the parameter value.
|
|||
|
//
|
|||
|
if ((*ParamBuffer == '-'
|
|||
|
|| *ParamBuffer == '/')
|
|||
|
&& (ParamBuffer++, *ParamBuffer != '\0')) {
|
|||
|
|
|||
|
//
|
|||
|
// Switch on the next character.
|
|||
|
//
|
|||
|
|
|||
|
switch (*ParamBuffer) {
|
|||
|
|
|||
|
//
|
|||
|
// Update buffer to use.
|
|||
|
//
|
|||
|
case 'b' :
|
|||
|
case 'B' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
BufferIndex = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update the length of the Ea name buffer.
|
|||
|
//
|
|||
|
|
|||
|
case 'g' :
|
|||
|
case 'G' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
ActualEaNameBufferLength = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
EaNameBufferLength = &ActualEaNameBufferLength;
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update the file handle index.
|
|||
|
//
|
|||
|
case 'i' :
|
|||
|
case 'I' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
FileHandleIndex = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update the EA index to start from.
|
|||
|
//
|
|||
|
case 'e' :
|
|||
|
case 'E' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
ActualEaIndex = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
EaIndex = &ActualEaIndex;
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update buffer length to pass.
|
|||
|
//
|
|||
|
case 'l' :
|
|||
|
case 'L' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
ActualBufferLength = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
BufferLength = &ActualBufferLength;
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update the ea name buffer to use.
|
|||
|
//
|
|||
|
case 'n' :
|
|||
|
case 'N' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
ActualEaNameBuffer = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
EaNameBuffer = &ActualEaNameBuffer;
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Set or clear the restart flag
|
|||
|
//
|
|||
|
|
|||
|
case 'r' :
|
|||
|
case 'R' :
|
|||
|
|
|||
|
//
|
|||
|
// Legal values for params are T/t or F/f.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
if (*ParamBuffer == 'T'
|
|||
|
|| *ParamBuffer == 't') {
|
|||
|
|
|||
|
RestartScan = TRUE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
} else if (*ParamBuffer == 'F'
|
|||
|
|| *ParamBuffer == 'f') {
|
|||
|
|
|||
|
RestartScan = FALSE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Set or clear the single ea flag.
|
|||
|
//
|
|||
|
|
|||
|
case 's' :
|
|||
|
case 'S' :
|
|||
|
|
|||
|
//
|
|||
|
// Legal values for params are T/t or F/f.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
if (*ParamBuffer == 'T'
|
|||
|
|| *ParamBuffer == 't') {
|
|||
|
|
|||
|
ReturnSingleEntry = TRUE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
} else if (*ParamBuffer == 'F'
|
|||
|
|| *ParamBuffer == 'f') {
|
|||
|
|
|||
|
ReturnSingleEntry = FALSE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case 'v' :
|
|||
|
case 'V' :
|
|||
|
|
|||
|
//
|
|||
|
// Legal values for params are T/t or F/f.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
if (*ParamBuffer == 'T'
|
|||
|
|| *ParamBuffer == 't') {
|
|||
|
|
|||
|
VerboseResults = TRUE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
} else if (*ParamBuffer == 'F'
|
|||
|
|| *ParamBuffer == 'f') {
|
|||
|
|
|||
|
VerboseResults = FALSE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
|
|||
|
case 'y' :
|
|||
|
case 'Y' :
|
|||
|
|
|||
|
//
|
|||
|
// Set the display parms flag and jump over this
|
|||
|
// character.
|
|||
|
//
|
|||
|
DisplayParms = TRUE;
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case 'z' :
|
|||
|
case 'Z' :
|
|||
|
|
|||
|
//
|
|||
|
// Set flag for more input and jump over this char.
|
|||
|
//
|
|||
|
LastInput = FALSE;
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default :
|
|||
|
|
|||
|
//
|
|||
|
// Swallow to the next white space and continue the
|
|||
|
// loop.
|
|||
|
//
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Else the text is invalid, skip the entire block.
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Else if there is no input then exit.
|
|||
|
//
|
|||
|
} else if (LastInput) {
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Else try to read another line for open parameters.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If no parameters were received then display the syntax message.
|
|||
|
//
|
|||
|
if (!ParamReceived) {
|
|||
|
|
|||
|
printf( "\n Usage: qea [options]*\n" );
|
|||
|
printf( "\n Options:" );
|
|||
|
printf( "\n -i<digits> Open file handle" );
|
|||
|
printf( "\n -b<digits> Output buffer index" );
|
|||
|
printf( "\n -l<digits> Declared length of output buffer (Optional)" );
|
|||
|
printf( "\n -n<digits> Ea name buffer index" );
|
|||
|
printf( "\n -g<digits> Declared length of ea name buffer (Optional)" );
|
|||
|
printf( "\n -e<digits> Ea index to start from" );
|
|||
|
printf( "\n -r[t|f] Restart scan" );
|
|||
|
printf( "\n -s[t|f] Return single entry" );
|
|||
|
printf( "\n -v[t|f] Verbose results" );
|
|||
|
printf( "\n -y Display parameters to query" );
|
|||
|
printf( "\n -z Additional input line" );
|
|||
|
printf( "\n\n" );
|
|||
|
|
|||
|
//
|
|||
|
// Else call our query ea routine.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
QueryEa( FileHandleIndex,
|
|||
|
&IoStatusBlock,
|
|||
|
BufferIndex,
|
|||
|
BufferLength,
|
|||
|
ReturnSingleEntry,
|
|||
|
EaNameBuffer,
|
|||
|
EaNameBufferLength,
|
|||
|
EaIndex,
|
|||
|
RestartScan,
|
|||
|
VerboseResults,
|
|||
|
DisplayParms );
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
QueryEa (
|
|||
|
IN ULONG FileHandleIndex,
|
|||
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
|||
|
IN ULONG BufferIndex,
|
|||
|
IN PULONG BufferLength OPTIONAL,
|
|||
|
IN BOOLEAN ReturnSingleEntry,
|
|||
|
IN PULONG EaNameBuffer OPTIONAL,
|
|||
|
IN PULONG EaNameBufferLength OPTIONAL,
|
|||
|
IN PULONG EaIndex,
|
|||
|
IN BOOLEAN RestartScan,
|
|||
|
IN BOOLEAN VerboseResults,
|
|||
|
IN BOOLEAN DisplayParms
|
|||
|
)
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
//
|
|||
|
// Perform initialization.
|
|||
|
//
|
|||
|
|
|||
|
IoStatusBlock->Status = STATUS_SUCCESS;
|
|||
|
IoStatusBlock->Information = 0;
|
|||
|
|
|||
|
//
|
|||
|
// If the buffer index is unused, display an error message.
|
|||
|
//
|
|||
|
|
|||
|
if (!Buffers[BufferIndex].Used) {
|
|||
|
|
|||
|
printf( "\nQueryEa: Index refers to invalid buffer" );
|
|||
|
IoStatusBlock->Status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// Else if the ea name buffer is specified but unused, display
|
|||
|
// an error message.
|
|||
|
//
|
|||
|
|
|||
|
} else if (EaNameBuffer && !Buffers[*EaNameBuffer].Used) {
|
|||
|
|
|||
|
printf( "\nQueryEa: Index refers to invalid buffer" );
|
|||
|
IoStatusBlock->Status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// Display the parameters if requested, then call the query Ea
|
|||
|
// routine. Display the results if requested.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
if (DisplayParms) {
|
|||
|
|
|||
|
printf( "\nQuery Ea Parameters" );
|
|||
|
printf( "\n Handle index -> %ld", FileHandleIndex );
|
|||
|
printf( "\n Buffer index length -> %lx",
|
|||
|
BufferLength ? *BufferLength : Buffers[BufferIndex].Length );
|
|||
|
printf( "\n Return single entry -> %ld", ReturnSingleEntry );
|
|||
|
if (EaNameBuffer) {
|
|||
|
|
|||
|
printf( "\n Ea name buffer index -> %ld",
|
|||
|
*EaNameBuffer );
|
|||
|
|
|||
|
printf( "\n Ea name buffer length -> %lx",
|
|||
|
EaNameBufferLength ? *EaNameBufferLength : Buffers[*EaNameBuffer].Length );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if (EaIndex) {
|
|||
|
|
|||
|
printf( "\n Ea index to start at -> %ld", *EaIndex );
|
|||
|
|
|||
|
}
|
|||
|
printf( "\n Restart scan -> %ld", RestartScan );
|
|||
|
printf( "\n\n" );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Status = NtQueryEaFile( Handles[FileHandleIndex].Handle,
|
|||
|
IoStatusBlock,
|
|||
|
Buffers[BufferIndex].Buffer,
|
|||
|
BufferLength
|
|||
|
? *BufferLength
|
|||
|
: Buffers[BufferIndex].Length,
|
|||
|
ReturnSingleEntry,
|
|||
|
EaNameBuffer
|
|||
|
? Buffers[*EaNameBuffer].Buffer
|
|||
|
: NULL,
|
|||
|
EaNameBuffer
|
|||
|
? (EaNameBufferLength
|
|||
|
? *EaNameBufferLength
|
|||
|
: Buffers[*EaNameBuffer].Length)
|
|||
|
: 0,
|
|||
|
EaIndex,
|
|||
|
RestartScan );
|
|||
|
}
|
|||
|
|
|||
|
if (VerboseResults) {
|
|||
|
|
|||
|
printf( "\nQuery Ea: Status -> %08lx\n", Status );
|
|||
|
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
|
|||
|
printf( " Iosb.Information -> %08lx\n", IoStatusBlock->Information );
|
|||
|
printf( " Iosb.Status -> %08lx", IoStatusBlock->Status );
|
|||
|
}
|
|||
|
|
|||
|
printf( "\n" );
|
|||
|
}
|
|||
|
|
|||
|
return Status;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
InputSetEa(
|
|||
|
IN PCHAR ParamBuffer
|
|||
|
)
|
|||
|
{
|
|||
|
ULONG FileHandleIndex;
|
|||
|
IO_STATUS_BLOCK IoStatusBlock;
|
|||
|
ULONG BufferIndex;
|
|||
|
PULONG BufferLength;
|
|||
|
ULONG ActualBufferLength;
|
|||
|
|
|||
|
BOOLEAN VerboseResults;
|
|||
|
BOOLEAN DisplayParms;
|
|||
|
BOOLEAN ParamReceived;
|
|||
|
BOOLEAN LastInput;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize to the default value.
|
|||
|
//
|
|||
|
|
|||
|
FileHandleIndex = SEA_FILE_HANDLE_DEFAULT;
|
|||
|
BufferIndex = SEA_BUFFER_INDEX_DEFAULT;
|
|||
|
BufferLength = SEA_BUFFER_LENGTH_DEFAULT;
|
|||
|
VerboseResults = SEA_VERBOSE_DEFAULT;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the other interesting values.
|
|||
|
//
|
|||
|
|
|||
|
ActualBufferLength = 0;
|
|||
|
DisplayParms = FALSE;
|
|||
|
ParamReceived = FALSE;
|
|||
|
LastInput = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// While there is more input, analyze the parameter and update the
|
|||
|
// query flags.
|
|||
|
//
|
|||
|
|
|||
|
while (TRUE) {
|
|||
|
|
|||
|
ULONG DummyCount;
|
|||
|
|
|||
|
//
|
|||
|
// Swallow leading white spaces.
|
|||
|
//
|
|||
|
ParamBuffer = SwallowWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
if (*ParamBuffer) {
|
|||
|
|
|||
|
//
|
|||
|
// If the next parameter is legal then check the paramter value.
|
|||
|
// Update the parameter value.
|
|||
|
//
|
|||
|
if ((*ParamBuffer == '-'
|
|||
|
|| *ParamBuffer == '/')
|
|||
|
&& (ParamBuffer++, *ParamBuffer != '\0')) {
|
|||
|
|
|||
|
//
|
|||
|
// Switch on the next character.
|
|||
|
//
|
|||
|
|
|||
|
switch (*ParamBuffer) {
|
|||
|
|
|||
|
//
|
|||
|
// Update buffer to use.
|
|||
|
//
|
|||
|
case 'b' :
|
|||
|
case 'B' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
BufferIndex = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update the file handle index.
|
|||
|
//
|
|||
|
case 'i' :
|
|||
|
case 'I' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
FileHandleIndex = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
ParamReceived =TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Update buffer length to pass.
|
|||
|
//
|
|||
|
case 'l' :
|
|||
|
case 'L' :
|
|||
|
|
|||
|
//
|
|||
|
// Move to the next character, as long as there
|
|||
|
// are no white spaces continue analyzing letters.
|
|||
|
// On the first bad letter, skip to the next
|
|||
|
// parameter.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
ActualBufferLength = AsciiToInteger( ParamBuffer );
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
BufferLength = &ActualBufferLength;
|
|||
|
|
|||
|
ParamReceived = TRUE;
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case 'v' :
|
|||
|
case 'V' :
|
|||
|
|
|||
|
//
|
|||
|
// Legal values for params are T/t or F/f.
|
|||
|
//
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
if( *ParamBuffer == 'T'
|
|||
|
|| *ParamBuffer == 't' ) {
|
|||
|
|
|||
|
VerboseResults = TRUE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
} else if( *ParamBuffer == 'F'
|
|||
|
|| *ParamBuffer == 'f' ) {
|
|||
|
|
|||
|
VerboseResults = FALSE;
|
|||
|
ParamBuffer++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
|
|||
|
case 'y' :
|
|||
|
case 'Y' :
|
|||
|
|
|||
|
//
|
|||
|
// Set the display parms flag and jump over this
|
|||
|
// character.
|
|||
|
//
|
|||
|
DisplayParms = TRUE;
|
|||
|
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
break;
|
|||
|
|
|||
|
case 'z' :
|
|||
|
case 'Z' :
|
|||
|
|
|||
|
//
|
|||
|
// Set flag for more input and jump over this char.
|
|||
|
//
|
|||
|
LastInput = FALSE;
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default :
|
|||
|
|
|||
|
//
|
|||
|
// Swallow to the next white space and continue the
|
|||
|
// loop.
|
|||
|
//
|
|||
|
ParamBuffer = SwallowNonWhite( ParamBuffer, &DummyCount );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Else the text is invalid, skip the entire block.
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Else if there is no input then exit.
|
|||
|
//
|
|||
|
} else if (LastInput) {
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
//
|
|||
|
// Else try to read another line for open parameters.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If no parameters were received then display the syntax message.
|
|||
|
//
|
|||
|
if (!ParamReceived) {
|
|||
|
|
|||
|
printf( "\n Usage: sea [options]*\n" );
|
|||
|
printf( "\n Options:" );
|
|||
|
printf( "\n -i<digits> Open file handle" );
|
|||
|
printf( "\n -b<digits> Output buffer index" );
|
|||
|
printf( "\n -l<digits> Declared length of output buffer (Optional)" );
|
|||
|
printf( "\n -v[t|f] Verbose results" );
|
|||
|
printf( "\n -y Display parameters to query" );
|
|||
|
printf( "\n -z Additional input line" );
|
|||
|
printf( "\n\n" );
|
|||
|
|
|||
|
//
|
|||
|
// Else call our query ea routine.
|
|||
|
//
|
|||
|
} else {
|
|||
|
|
|||
|
SetEa( FileHandleIndex,
|
|||
|
&IoStatusBlock,
|
|||
|
BufferIndex,
|
|||
|
BufferLength,
|
|||
|
VerboseResults,
|
|||
|
DisplayParms );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SetEa(
|
|||
|
IN ULONG FileHandleIndex,
|
|||
|
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
|||
|
IN ULONG BufferIndex,
|
|||
|
IN PULONG BufferLength OPTIONAL,
|
|||
|
IN BOOLEAN VerboseResults,
|
|||
|
IN BOOLEAN DisplayParms
|
|||
|
)
|
|||
|
{
|
|||
|
NTSTATUS Status;
|
|||
|
|
|||
|
if (DisplayParms) {
|
|||
|
|
|||
|
printf( "\nSet Ea Parameters" );
|
|||
|
printf( "\n Handle index -> %ld", FileHandleIndex );
|
|||
|
printf( "\n Buffer index -> %ld", BufferIndex );
|
|||
|
printf( "\n Buffer index length -> %lx",
|
|||
|
BufferLength ? *BufferLength : Buffers[BufferIndex].Length );
|
|||
|
printf( "\n\n" );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Perform initialization.
|
|||
|
//
|
|||
|
|
|||
|
Status = STATUS_SUCCESS;
|
|||
|
IoStatusBlock->Status = STATUS_SUCCESS;
|
|||
|
IoStatusBlock->Information = 0;
|
|||
|
|
|||
|
//
|
|||
|
// If the buffer index is unused, display an error message.
|
|||
|
//
|
|||
|
|
|||
|
if (!Buffers[BufferIndex].Used) {
|
|||
|
|
|||
|
printf( "\nSetEa: Index refers to invalid buffer" );
|
|||
|
IoStatusBlock->Status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// If the handle index is unused, display an error message.
|
|||
|
//
|
|||
|
|
|||
|
} else if (!Handles[FileHandleIndex].Used) {
|
|||
|
|
|||
|
printf( "\nSetEa: Index refers to invalid file handle" );
|
|||
|
IoStatusBlock->Status = STATUS_INVALID_HANDLE;
|
|||
|
|
|||
|
//
|
|||
|
// Display the parameters if requested, then call the query Ea
|
|||
|
// routine. Display the results if requested.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
Status = NtSetEaFile( Handles[FileHandleIndex].Handle,
|
|||
|
IoStatusBlock,
|
|||
|
Buffers[BufferIndex].Buffer,
|
|||
|
BufferLength
|
|||
|
? *BufferLength
|
|||
|
: Buffers[BufferIndex].Length );
|
|||
|
}
|
|||
|
|
|||
|
if (VerboseResults) {
|
|||
|
|
|||
|
printf( "\nSet Ea: Status -> %08lx\n", Status );
|
|||
|
|
|||
|
if (NT_SUCCESS( Status )) {
|
|||
|
|
|||
|
printf( " Iosb.Information -> %08lx\n", IoStatusBlock->Information );
|
|||
|
printf( " Iosb.Status -> %08lx", IoStatusBlock->Status );
|
|||
|
}
|
|||
|
|
|||
|
printf( "\n" );
|
|||
|
}
|
|||
|
|
|||
|
return IoStatusBlock->Status;
|
|||
|
}
|