920 lines
23 KiB
C
920 lines
23 KiB
C
/*++
|
||
|
||
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);
|
||
|
||
}
|
||
|