NT4/private/ntos/rdr/print.c
2020-09-30 17:12:29 +02:00

920 lines
23 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
print.c
Abstract:
This module implements the routines that support remote print devices.
Author:
Colin Watson (ColinW) 24-Dec-1990
Revision History:
24-Dec-1990 ColinW
Created
Notes:
--*/
#define INCLUDE_SMB_PRINT
#define INCLUDE_SMB_READ_WRITE
#define INCLUDE_SMB_TRANSACTION
#include "precomp.h"
#pragma hdrstop
#define SPOOLER_DEVICE 0x53
#define GET_PRINTER_ID 0x60
typedef struct _PrintOpenContext {
TRANCEIVE_HEADER Header; // Generic transaction context header
PICB Icb; // ICB to fill in.
ULONG OpenAction; // Action taken on open.
} PRINTOPENCONTEXT, *PPRINTOPENCONTEXT;
typedef
struct _PRINT_WRITE_CONTEXT {
TRANCEIVE_HEADER Header;
ULONG WriteAmount; // Number of bytes actually written.
} PRINT_WRITE_CONTEXT, *PPRINT_WRITE_CONTEXT;
//
// Force misalignment of the following structure
//
#ifndef NO_PACKING
#include <packon.h>
#endif // ndef NO_PACKING
typedef struct _PRINT_QUEUE_INFORMATION {
RESP_GET_PRINT_QUEUE Header;
_USHORT( DataLength ); // Length of data
SMB_DATE CreationDate;
SMB_TIME CreationTime;
UCHAR Status;
_USHORT( FileNumber );
_ULONG( FileDataSize ); // File end of data
UCHAR Reserved;
UCHAR UserName[UNLEN];
} PRINT_QUEUE_INFORMATION, *PPRINT_QUEUE_INFORMATION;
typedef struct _SMB_RESP_PRINT_JOB_ID {
USHORT JobId;
UCHAR ServerName[LM20_CNLEN+1];
UCHAR QueueName[LM20_QNLEN+1];
UCHAR Padding; // Unknown what this padding is..
} SMB_RESP_PRINT_JOB_ID, *PSMB_RESP_PRINT_JOB_ID;
//
// Turn structure packing back off
//
#ifndef NO_PACKING
#include <packoff.h>
#endif // ndef NO_PACKING
typedef
struct _GET_JOBID_CONTEXT {
TRANCEIVE_HEADER Header;
PICB Icb;
SMB_RESP_PRINT_JOB_ID Response;
} GET_JOBID_CONTEXT, *PGET_JOBID_CONTEXT;
DBGSTATIC
STANDARD_CALLBACK_HEADER (
CreatePrintCallback
);
DBGSTATIC
STANDARD_CALLBACK_HEADER(
GetJobIdCallback
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, RdrCreatePrintFile)
#pragma alloc_text(PAGE, RdrWritePrintFile)
#pragma alloc_text(PAGE, RdrEnumPrintFile)
#pragma alloc_text(PAGE, RdrGetPrintJobId)
#pragma alloc_text(PAGE3FILE, GetJobIdCallback)
#pragma alloc_text(PAGE3FILE, CreatePrintCallback)
#endif
NTSTATUS
RdrCreatePrintFile (
IN PICB Icb,
IN PIRP Irp
)
/*++
Routine Description:
This routine creates a print file over the network.
Arguments:
IN PICB Icb - Supplies the ICB containing the file information
IN PIRP Irp - Supplies the IRP to be used for the Open request
Return Value:
NTSTATUS - Status of open.
--*/
{
PSMB_BUFFER SmbBuffer;
PSMB_HEADER Smb;
PREQ_OPEN_PRINT_FILE Open;
PSZ Buffer;
PPRINTOPENCONTEXT OpenContext = NULL;
PCONNECTLISTENTRY Connection = Icb->Fcb->Connection;
PSECURITY_ENTRY Se = Icb->Se;
NTSTATUS Status;
PAGED_CODE();
dprintf(DPRT_CREATE, ("Create Print file %wZ.\n",&Icb->Fcb->FileName));
ASSERT(Se->Signature == STRUCTURE_SIGNATURE_SECURITYENTRY);
ASSERT(Connection->Signature == STRUCTURE_SIGNATURE_CONNECTLISTENTRY);
if ((SmbBuffer = RdrAllocateSMBBuffer())==NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
OpenContext = ALLOCATE_POOL(NonPagedPool, sizeof(PRINTOPENCONTEXT), POOL_OPENPRINTCONTEXT);
if (OpenContext == NULL) {
RdrFreeSMBBuffer(SmbBuffer);
return STATUS_INSUFFICIENT_RESOURCES;
}
Smb = (PSMB_HEADER )SmbBuffer->Buffer;
Smb->Command = SMB_COM_OPEN_PRINT_FILE;
Open = (PREQ_OPEN_PRINT_FILE) (Smb+1);
Open->WordCount = 2;
SmbPutUshort(&Open->Mode, 1); // Hard code to Graphics- dont expand tabs
Buffer = (PSZ)Open->Buffer;
*Buffer++ = SMB_FORMAT_ASCII;
//
// Copy the username into the buffer.
//
if (Connection->Server->Capabilities & DF_UNICODE) {
Buffer = ALIGN_SMB_WSTR(Buffer);
RdrCopyUnicodeUserName((PWSTR *)&Buffer, Se);
*((PWCH)Buffer)++ = UNICODE_NULL; // Null terminate the user's name.
} else {
RdrCopyUserName(&Buffer, Se);
*Buffer++ = 0; // Null terminate the users name.
}
SmbPutUshort(&Open->SetupLength, 0); // No setup data supported
SmbPutUshort(&Open->ByteCount,
(USHORT )(Buffer-(PUCHAR )Open->Buffer));
SmbBuffer->Mdl->ByteCount = Buffer - (PUCHAR )Smb;
OpenContext->Header.Type = CONTEXT_PRINT_OPEN;
OpenContext->Header.TransferSize = SmbBuffer->Mdl->ByteCount + sizeof(RESP_OPEN_PRINT_FILE);
OpenContext->Icb = Icb;
Status = RdrNetTranceiveWithCallback(
NT_NORMAL,
Irp, // Irp
Connection,
SmbBuffer->Mdl,
OpenContext,
CreatePrintCallback,
Se,
NULL);
RdrFreeSMBBuffer(SmbBuffer);
if (!NT_SUCCESS(Status)) {
FREE_POOL(OpenContext);
return Status;
}
Irp->IoStatus.Information = RdrUnmapDisposition(FILE_OPENED);
Icb->Type = PrinterFile;
Icb->NonPagedFcb->Type = PrinterFile;
Icb->NonPagedFcb->FileType = FileTypePrinter;
Icb->Fcb->ServerFileId = 0;
Icb->Fcb->AccessGranted = SMB_ACCESS_WRITE_ONLY;
Icb->Fcb->Attribute = FILE_ATTRIBUTE_NORMAL;
//
// The SpoolOpen SMB doesn't give us these other time fields.
//
Icb->Fcb->LastWriteTime.HighPart = 0;
Icb->Fcb->LastWriteTime.LowPart = 0;
Icb->Fcb->CreationTime.HighPart = 0;
Icb->Fcb->CreationTime.LowPart = 0;
Icb->Fcb->LastAccessTime.HighPart = 0;
Icb->Fcb->LastAccessTime.LowPart = 0;
Icb->Fcb->ChangeTime.HighPart = 0;
Icb->Fcb->ChangeTime.LowPart = 0;
Icb->Fcb->Header.FileSize.HighPart = 0x7fffffff;
Icb->Fcb->Header.FileSize.LowPart = 0xffffffff;
//
// Flag that this ICB has a handle associated with it, and
// thus that it must be closed when the local file is closed.
//
Icb->Flags |= ICB_HASHANDLE;
FREE_POOL(OpenContext);
return Status;
}
DBGSTATIC
STANDARD_CALLBACK_HEADER (
CreatePrintCallback
)
/*++
Routine Description:
This routine is the callback routine for the processing of an Open SMB.
It copies the resulting information from the Open SMB into either
the context block or the ICB supplied directly.
Arguments:
IN PSMB_HEADER Smb - SMB response from server.
IN PMPX_ENTRY MpxTable - MPX table entry for request.
IN POPENANDXCONTEXT Context- Context from caller.
IN BOOLEAN ErrorIndicator - TRUE if error indication
IN NTSTATUS NetworkErrorCode OPTIONAL - Network error if error indication.
IN OUT PIRP *Irp - IRP from TDI
Return Value:
NTSTATUS - STATUS_PENDING if we are to complete the request
--*/
{
PRESP_OPEN_PRINT_FILE OpenResponse;
PPRINTOPENCONTEXT Context = Ctx;
PFCB Fcb = Context->Icb->Fcb;
NTSTATUS Status;
ASSERT(Context->Header.Type == CONTEXT_PRINT_OPEN);
DISCARDABLE_CODE(RdrFileDiscardableSection);
dprintf(DPRT_CREATE, ("OpenComplete\n"));
Context->Header.ErrorType = NoError; // Assume no error at first.
//
// If we are called because the VC dropped, indicate it in the response
//
if (ErrorIndicator) {
Context->Header.ErrorType = NetError;
Context->Header.ErrorCode = RdrMapNetworkError(NetworkErrorCode);
goto ReturnStatus;
}
if (!NT_SUCCESS(Status = RdrMapSmbError(Smb, Server))) {
Context->Header.ErrorType = SMBError;
Context->Header.ErrorCode = Status;
goto ReturnStatus;
}
OpenResponse = (PRESP_OPEN_PRINT_FILE)(Smb+1);
Context->Icb->FileId = SmbGetUshort(&OpenResponse->Fid);
ReturnStatus:
KeSetEvent(&Context->Header.KernelEvent, IO_NETWORK_INCREMENT, FALSE);
return STATUS_SUCCESS;
UNREFERENCED_PARAMETER(MpxEntry);
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(SmbLength);
UNREFERENCED_PARAMETER(Server);
}
NTSTATUS
RdrWritePrintFile(
IN PIRP Irp OPTIONAL,
IN PFILE_OBJECT FileObject,
IN PMDL DataMdl,
IN PCHAR TransferStart,
IN ULONG Length,
IN BOOLEAN WaitForCompletion,
IN PWRITE_COMPLETION_ROUTINE CompletionRoutine,
IN PVOID CompletionContext,
OUT PBOOLEAN AllDataWritten,
OUT PULONG AmountActuallyWritten
)
/*++
Routine Description:
This routine uses the core SMB write protocol to write from the specified
file.
Arguments:
IN PIRP Irp - Supplies an IRP to use for the raw write request.
IN PICB Icb - Supplies an ICB for the file to write.
IN PMDL DataMdl - Supplies the Mdl containing the data to write.
IN PCHAR TransferStart - Supplies the address of the start of the Xfer.
IN ULONG Length - Supplies the total number of bytes to write.
OUT PBOOLEAN AllDataWritten - Returns true if all the data requested were written
OUT PULONG AmountActuallyWritten - Returns the number of bytes written.
Return Value:
NTSTATUS - Status of write request.
--*/
{
PSMB_BUFFER SmbBuffer = NULL;
PSMB_HEADER Smb;
PREQ_WRITE_PRINT_FILE Write;
NTSTATUS Status;
PMDL PartialMdl;
PICB Icb = FileObject->FsContext2;
ULONG SrvWriteSize = Icb->Fcb->Connection->Server->BufferSize -
(sizeof(SMB_HEADER)+sizeof(REQ_WRITE));
ULONG AmountRequestedToWrite = MIN(Length, SrvWriteSize);
PAGED_CODE();
//
// Allocate an SMB buffer for the write operation.
//
// Since write is a "little data" operation, we can use
// NetTranceiveWithCallback and forgo creating an SMB buffer
// for the receive. This is ok, since we are only interested in the
// amount of data actually written anyway.
//
if ((SmbBuffer = RdrAllocateSMBBuffer())==NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ReturnError;
}
Smb = (PSMB_HEADER )(SmbBuffer->Buffer);
Smb->Command = SMB_COM_WRITE_PRINT_FILE;
Write = (PREQ_WRITE_PRINT_FILE )(Smb+1);
Write->WordCount = 1;
SmbPutUshort(&Write->Fid, Icb->FileId);
SmbPutUshort(&Write->ByteCount, (USHORT)( AmountRequestedToWrite + 3));
Write->Buffer[0] = SMB_FORMAT_DATA;
SmbPutUshort((PUSHORT)&Write->Buffer[1], (USHORT)AmountRequestedToWrite);
//
// Set the number of bytes to send in this request.
//
SmbBuffer->Mdl->ByteCount = sizeof(SMB_HEADER)+
FIELD_OFFSET(REQ_WRITE_PRINT_FILE, Buffer[3]);
//
// Allocate an MDL large enough to hold this piece of
// the request.
//
PartialMdl = IoAllocateMdl(TransferStart,
AmountRequestedToWrite, // Length
FALSE, // Secondary Buffer
FALSE, // Charge Quota
NULL);
if (PartialMdl == NULL) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ReturnError;
}
//
// If there is no MDL for this read, probe the data MDL to lock it's
// pages down.
//
// Otherwise, use the data MDL as a partial MDL and lock the pages
// accordingly
//
if (!ARGUMENT_PRESENT(DataMdl)) {
try {
if (ARGUMENT_PRESENT(Irp)) {
MmProbeAndLockPages(PartialMdl, Irp->RequestorMode, IoReadAccess);
} else {
MmProbeAndLockPages(PartialMdl, KernelMode, IoReadAccess);
}
} except (EXCEPTION_EXECUTE_HANDLER) {
IoFreeMdl(PartialMdl);
Status = GetExceptionCode();
goto ReturnError;
}
} else {
IoBuildPartialMdl(DataMdl, PartialMdl,
TransferStart,
AmountRequestedToWrite);
}
ASSERT( PartialMdl->ByteCount==AmountRequestedToWrite );
//
// Now link this new MDL into the SMB buffer we allocated for
// the receive.
//
SmbBuffer->Mdl->Next = PartialMdl;
Status = RdrNetTranceive(NT_NORMAL, // Flags
Irp,
Icb->Fcb->Connection,
SmbBuffer->Mdl,
NULL, // Only interested in the error code.
Icb->Se);
if (Status == STATUS_INVALID_HANDLE) {
RdrInvalidateFileId(Icb->NonPagedFcb, Icb->FileId);
}
if (!ARGUMENT_PRESENT(DataMdl)) {
MmUnlockPages(PartialMdl);
}
IoFreeMdl(PartialMdl);
if (!NT_SUCCESS(Status)) {
//
// Bail out on failure.
//
goto ReturnError;
}
*AllDataWritten = TRUE;
*AmountActuallyWritten = AmountRequestedToWrite;
ReturnError:
if (SmbBuffer!=NULL) {
RdrFreeSMBBuffer(SmbBuffer);
}
return Status;
}
NTSTATUS
RdrEnumPrintFile (
IN PICB Icb,
IN PIRP Irp,
IN ULONG Index,
OUT PLMR_GET_PRINT_QUEUE UserBuffer
)
/*++
Routine Description:
This routine returns information on a particular print file over
the network from any server. It is intended for core servers but
will work on any server.
Arguments:
IN PICB Icb - Supplies the ICB containing the file information
IN PIRP Irp - Supplies the IRP to be used for the request
IN ULONG Index - Supplies the entry in the print queue to return
OUT PLMR_GET_PRINT_QUEUE UserBuffer
Return Value:
NTSTATUS - Status of operation.
--*/
{
PSMB_BUFFER SmbBuffer;
PSMB_BUFFER ReceiveSmbBuffer;
PSMB_HEADER Smb;
PSMB_HEADER ReceiveSmb;
PREQ_GET_PRINT_QUEUE Request;
PPRINT_QUEUE_INFORMATION Response;
SMB_TIME Time;
SMB_DATE Date;
NTSTATUS Status;
PAGED_CODE();
if (((SmbBuffer = RdrAllocateSMBBuffer())==NULL) ||
((ReceiveSmbBuffer = RdrAllocateSMBBuffer())==NULL)) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ReturnError;
}
Smb = (PSMB_HEADER )SmbBuffer->Buffer;
Smb->Command = SMB_COM_GET_PRINT_QUEUE;
Request = (PREQ_GET_PRINT_QUEUE) (Smb+1);
Request->WordCount = 2;
SmbPutUshort(&Request->MaxCount, 1);
SmbPutUshort(&Request->StartIndex, (USHORT)Index);
SmbPutUshort(&Request->ByteCount, 0 );
SmbBuffer->Mdl->ByteCount = sizeof(SMB_HEADER)+sizeof(REQ_GET_PRINT_QUEUE);
//
// Set the size of the data to be received into the SMB buffer.
//
ReceiveSmbBuffer->Mdl->ByteCount = sizeof(SMB_HEADER) +
sizeof(PRINT_QUEUE_INFORMATION);
Status = RdrNetTranceive(NT_NORMAL | NT_NORECONNECT,
Irp,
Icb->Fcb->Connection,
SmbBuffer->Mdl,
ReceiveSmbBuffer->Mdl,
Icb->Se);
ReceiveSmb = (PSMB_HEADER )ReceiveSmbBuffer->Buffer;
Response = (PPRINT_QUEUE_INFORMATION) (ReceiveSmb+1);
if (NT_SUCCESS(Status) &&
(SmbGetUshort(&Response->Header.Count) == 1)) {
// Copy in the UserName as a string
UserBuffer->OriginatorName.MaximumLength = UNLEN;
UserBuffer->OriginatorName.Length = UNLEN;
UserBuffer->OriginatorName.Buffer = (PCHAR)Irp->UserBuffer
+ sizeof(LMR_GET_PRINT_QUEUE);
//
// Calculate the real length of the user name. Take whatever
// came from the server and remove trailing null and space
// characters.
//
NAME_LENGTH(UserBuffer->OriginatorName.Length,
Response->UserName,
MIN( UNLEN, SmbGetUshort(&Response->DataLength)-12));
RtlCopyMemory( (PCHAR)UserBuffer + sizeof(LMR_GET_PRINT_QUEUE),
Response->UserName,
UserBuffer->OriginatorName.Length);
// Now we have the username, fill in all other values
SmbMoveTime (&Time, &Response->CreationTime);
SmbMoveDate (&Date, &Response->CreationDate);
UserBuffer->CreateTime = RdrConvertSmbTimeToTime(Time, Date, Icb->Fcb->Connection->Server);
UserBuffer->EntryStatus = Response->Status;
UserBuffer->FileNumber = SmbGetUshort( &Response->FileNumber );
UserBuffer->FileSize = SmbGetUlong( &Response->FileDataSize );
UserBuffer->RestartIndex =
SmbGetUshort(&Response->Header.RestartIndex);
} else {
// Some down level servers forget to return an error at end of queue
Status = STATUS_NO_MORE_FILES;
}
ReturnError:
if (SmbBuffer!=NULL) {
RdrFreeSMBBuffer(SmbBuffer);
}
if (ReceiveSmbBuffer!=NULL) {
RdrFreeSMBBuffer(ReceiveSmbBuffer);
}
return Status;
}
NTSTATUS
RdrGetPrintJobId (
IN PICB Icb,
IN PIRP Irp,
OUT PQUERY_PRINT_JOB_INFO OutputBuffer
)
/*++
Routine Description:
This routine returns the print job ID of the specified print job on the
remote server.
Arguments:
IN PICB Icb - Supplies the ICB containing the file information
IN PIRP Irp - Supplies the IRP to be used for the request
OUT PULONG JobId
Return Value:
NTSTATUS - Status of operation.
--*/
{
PSMB_BUFFER SmbBuffer = NULL;
PSMB_HEADER Smb;
PREQ_IOCTL Request;
NTSTATUS Status;
GET_JOBID_CONTEXT Context;
UNICODE_STRING UnicodeString;
OEM_STRING OemString;
BOOLEAN FcbLocked = FALSE;
PAGED_CODE();
//
// This API is only supported to OS/2 servers.
//
try {
if (!FlagOn(Icb->Fcb->Connection->Server->Capabilities, DF_LANMAN10)) {
try_return(Status = STATUS_NOT_SUPPORTED);
}
if (Icb->Flags & ICB_DEFERREDOPEN) {
RdrAcquireFcbLock(Icb->Fcb, ExclusiveLock, TRUE);
FcbLocked = TRUE;
//
// If this print file isn't opened yet, create a print job.
//
if (!NT_SUCCESS(Status = RdrCreatePrintFile(Icb, Irp))) {
try_return(Status);
}
Icb->Flags &= ~ICB_DEFERREDOPEN;
} else {
RdrAcquireFcbLock(Icb->Fcb, SharedLock, TRUE);
FcbLocked = TRUE;
}
Context.Header.Type = CONTEXT_GET_JOBID;
Context.Icb = Icb;
if ((SmbBuffer = RdrAllocateSMBBuffer()) == NULL) {
try_return(Status = STATUS_INSUFFICIENT_RESOURCES);
}
Smb = (PSMB_HEADER )SmbBuffer->Buffer;
Smb->Command = SMB_COM_IOCTL;
Request = (PREQ_IOCTL) (Smb+1);
RtlZeroMemory( Request, sizeof(REQ_IOCTL) );
Request->WordCount = 14;
SmbPutUshort( &Request->Fid, Icb->FileId );
SmbPutUshort( &Request->Category, SPOOLER_DEVICE );
SmbPutUshort( &Request->Function, GET_PRINTER_ID );
//
// Set the size of the data to be received into the SMB buffer.
//
SmbBuffer->Mdl->ByteCount = sizeof(SMB_HEADER)+FIELD_OFFSET(REQ_IOCTL, Buffer);
Context.Header.TransferSize = sizeof(SMB_HEADER)+FIELD_OFFSET(REQ_IOCTL, Buffer) +
sizeof(SMB_HEADER)+FIELD_OFFSET(RESP_IOCTL, Buffer) +
sizeof(SMB_RESP_PRINT_JOB_ID);
Status = RdrNetTranceiveWithCallback(NT_NORMAL | NT_NORECONNECT,
Irp,
Icb->Fcb->Connection,
SmbBuffer->Mdl,
&Context,
GetJobIdCallback,
Icb->Se,
NULL);
if (!NT_SUCCESS(Status)) {
try_return(Status);
}
//
// Now convert the output buffer into something we can use on NT.
//
OutputBuffer->JobId = Context.Response.JobId;
RtlInitAnsiString(&OemString, Context.Response.ServerName);
UnicodeString.Buffer = OutputBuffer->ServerName;
UnicodeString.MaximumLength = sizeof(OutputBuffer->ServerName);
Status = RtlOemStringToUnicodeString(&UnicodeString, &OemString, FALSE);
if (!NT_SUCCESS(Status)) {
try_return(Status);
}
RtlInitAnsiString(&OemString, Context.Response.QueueName);
UnicodeString.Buffer = OutputBuffer->QueueName;
UnicodeString.MaximumLength = sizeof(OutputBuffer->QueueName);
Status = RtlOemStringToUnicodeString(&UnicodeString, &OemString, FALSE);
if (!NT_SUCCESS(Status)) {
try_return(Status);
}
try_exit:NOTHING;
} finally {
if (SmbBuffer!=NULL) {
RdrFreeSMBBuffer(SmbBuffer);
}
if (FcbLocked) {
RdrReleaseFcbLock(Icb->Fcb);
}
}
return Status;
}
DBGSTATIC
STANDARD_CALLBACK_HEADER(
GetJobIdCallback
)
/*++
Routine Description:
This routine is the callback routine for the processing of a Write SMB.
It copies the interesting information from the Write SMB response into
into the context structure. As of now, we are only interested in
amount written in the SMB.
Arguments:
IN PSMB_HEADER Smb - SMB response from server.
IN PMPX_ENTRY MpxTable - MPX table entry for request.
IN PWRITE_CONTEXT Context - Context from caller.
IN BOOLEAN ErrorIndicator - TRUE if error indication
IN NTSTATUS NetworkErrorCode OPTIONAL - Network error if error indication.
IN OUT PIRP *Irp - IRP from TDI
Return Value:
NTSTATUS - STATUS_PENDING if we are to complete the request
--*/
{
PRESP_IOCTL IoctlResponse;
PGET_JOBID_CONTEXT Context = Ctx;
NTSTATUS Status;
DISCARDABLE_CODE(RdrFileDiscardableSection);
ASSERT(Context->Header.Type == CONTEXT_GET_JOBID);
dprintf(DPRT_PRINT, ("GetPrintJobId\n"));
Context->Header.ErrorType = NoError; // Assume no error at first.
//
// If we are called because the VC dropped, indicate it in the response
//
if (ErrorIndicator) {
Context->Header.ErrorType = NetError;
Context->Header.ErrorCode = RdrMapNetworkError(NetworkErrorCode);
goto ReturnStatus;
}
if (!NT_SUCCESS(Status = RdrMapSmbError(Smb, Server))) {
if (Status == STATUS_INVALID_HANDLE) {
RdrInvalidateFileId(Context->Icb->NonPagedFcb, Context->Icb->FileId);
}
Context->Header.ErrorType = SMBError;
Context->Header.ErrorCode = Status;
goto ReturnStatus;
}
IoctlResponse = (PRESP_IOCTL )(Smb+1);
ASSERT (IoctlResponse->WordCount==8);
ASSERT (SmbGetUshort(&IoctlResponse->DataCount) == sizeof(SMB_RESP_PRINT_JOB_ID));
if (IoctlResponse->DataCount == sizeof(SMB_RESP_PRINT_JOB_ID)) {
TdiCopyLookaheadData(&Context->Response,
(PCHAR)Smb+SmbGetUshort(&IoctlResponse->DataOffset),
SmbGetUshort(&IoctlResponse->DataCount),
ReceiveFlags);
Context->Header.ErrorCode = STATUS_SUCCESS;
} else {
Context->Header.ErrorCode = STATUS_UNEXPECTED_NETWORK_ERROR;
Context->Header.ErrorType = SMBError;
}
ReturnStatus:
KeSetEvent(&Context->Header.KernelEvent, IO_NETWORK_INCREMENT, FALSE);
return STATUS_SUCCESS;
if (SmbLength || MpxEntry || Irp || Server);
}