3649 lines
107 KiB
C
3649 lines
107 KiB
C
/*++
|
||
|
||
Copyright (c) 1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Create.c
|
||
|
||
Abstract:
|
||
|
||
This module implements the File Create routine for the NetWare
|
||
redirector called by the dispatch driver.
|
||
|
||
Author:
|
||
|
||
Colin Watson [ColinW] 19-Dec-1992
|
||
Manny Weiser [MannyW] 15-Feb-1993
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "Procs.h"
|
||
|
||
NTSTATUS
|
||
NwCommonCreate (
|
||
IN PIRP_CONTEXT IrpContext
|
||
);
|
||
|
||
IO_STATUS_BLOCK
|
||
OpenRedirector(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
ULONG DesiredAccess,
|
||
ULONG ShareAccess,
|
||
PFILE_OBJECT FileObject
|
||
);
|
||
|
||
IO_STATUS_BLOCK
|
||
CreateRemoteFile(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PUNICODE_STRING DriveName
|
||
);
|
||
|
||
IO_STATUS_BLOCK
|
||
ChangeDirectory(
|
||
PIRP_CONTEXT IrpContext,
|
||
PVCB Vcb,
|
||
PICB Icb
|
||
);
|
||
|
||
IO_STATUS_BLOCK
|
||
CreateDir(
|
||
PIRP_CONTEXT IrpContext,
|
||
PVCB Vcb,
|
||
PICB Icb
|
||
);
|
||
|
||
NTSTATUS
|
||
FileOrDirectoryExists(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PVCB Vcb,
|
||
IN PICB Icb,
|
||
PUNICODE_STRING Name,
|
||
OUT PBOOLEAN IsAFile
|
||
);
|
||
|
||
IO_STATUS_BLOCK
|
||
OpenFile(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PVCB Vcb,
|
||
IN PICB Icb,
|
||
IN BYTE SearchFlags,
|
||
IN BYTE ShareFlags
|
||
);
|
||
|
||
IO_STATUS_BLOCK
|
||
CreateNewFile(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PVCB Vcb,
|
||
IN PICB Icb,
|
||
IN BYTE SearchFlags,
|
||
IN BYTE ShareFlags
|
||
);
|
||
|
||
IO_STATUS_BLOCK
|
||
CreateOrOverwriteFile(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PVCB Vcb,
|
||
IN PICB Icb,
|
||
IN BYTE CreateAttributes,
|
||
IN BYTE OpenFlags,
|
||
IN BOOLEAN CreateOperation
|
||
);
|
||
|
||
IO_STATUS_BLOCK
|
||
OpenRenameTarget(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PVCB Vcb,
|
||
IN PDCB Dcb,
|
||
IN PICB* Icb
|
||
);
|
||
|
||
IO_STATUS_BLOCK
|
||
CreatePrintJob(
|
||
PIRP_CONTEXT IrpContext,
|
||
PVCB Vcb,
|
||
PICB Icb,
|
||
PUNICODE_STRING DriveName
|
||
);
|
||
|
||
VOID
|
||
CloseFile(
|
||
PIRP_CONTEXT pIrpContext,
|
||
PICB pIcb
|
||
);
|
||
|
||
|
||
BOOLEAN
|
||
MmDisableModifiedWriteOfSection (
|
||
IN PSECTION_OBJECT_POINTERS SectionObjectPointer
|
||
);
|
||
|
||
//
|
||
// The debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_CREATE)
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( PAGE, NwFsdCreate )
|
||
#pragma alloc_text( PAGE, NwCommonCreate )
|
||
#pragma alloc_text( PAGE, ReadAttachEas )
|
||
#pragma alloc_text( PAGE, OpenRedirector )
|
||
#pragma alloc_text( PAGE, CreateRemoteFile )
|
||
#pragma alloc_text( PAGE, ChangeDirectory )
|
||
#pragma alloc_text( PAGE, CreateDir )
|
||
#pragma alloc_text( PAGE, FileOrDirectoryExists )
|
||
#pragma alloc_text( PAGE, OpenFile )
|
||
#pragma alloc_text( PAGE, CreateNewFile )
|
||
#pragma alloc_text( PAGE, CreateOrOverwriteFile )
|
||
#pragma alloc_text( PAGE, OpenRenameTarget )
|
||
#pragma alloc_text( PAGE, CreatePrintJob )
|
||
#pragma alloc_text( PAGE, CloseFile )
|
||
#endif
|
||
|
||
|
||
NTSTATUS
|
||
NwFsdCreate (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine implements the FSD part of the NtCreateFile and NtOpenFile
|
||
API calls.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - Supplies the device object for the redirector.
|
||
|
||
Irp - Supplies the Irp being processed
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The Fsd status for the Irp
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
PIRP_CONTEXT IrpContext = NULL;
|
||
BOOLEAN TopLevel;
|
||
|
||
PAGED_CODE();
|
||
|
||
TimerStart(Dbg);
|
||
DebugTrace(+1, Dbg, "NwFsdCreate\n", 0);
|
||
|
||
//
|
||
// Call the common create routine, with block allowed if the operation
|
||
// is synchronous.
|
||
//
|
||
|
||
FsRtlEnterFileSystem();
|
||
TopLevel = NwIsIrpTopLevel( Irp );
|
||
|
||
try {
|
||
|
||
IrpContext = AllocateIrpContext( Irp );
|
||
Status = NwCommonCreate( IrpContext );
|
||
|
||
} except( NwExceptionFilter( Irp, GetExceptionInformation() )) {
|
||
|
||
if ( IrpContext == NULL ) {
|
||
|
||
//
|
||
// If we couldn't allocate an irp context, just complete
|
||
// irp without any fanfare.
|
||
//
|
||
|
||
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
Irp->IoStatus.Status = Status;
|
||
Irp->IoStatus.Information = 0;
|
||
IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
|
||
|
||
} else {
|
||
|
||
//
|
||
// We had some trouble trying to perform the requested
|
||
// operation, so we'll abort the I/O request with
|
||
// the error Status that we get back from the
|
||
// execption code
|
||
//
|
||
|
||
Status = NwProcessException( IrpContext, GetExceptionCode() );
|
||
}
|
||
}
|
||
|
||
if ( IrpContext ) {
|
||
NwDequeueIrpContext( IrpContext, FALSE );
|
||
NwCompleteRequest( IrpContext, Status );
|
||
}
|
||
|
||
if ( TopLevel ) {
|
||
NwSetTopLevelIrp( NULL );
|
||
}
|
||
FsRtlExitFileSystem();
|
||
|
||
//
|
||
// And return to our caller
|
||
//
|
||
|
||
DebugTrace(-1, Dbg, "NwFsdCreate -> %08lx\n", Status );
|
||
|
||
TimerStop(Dbg,"NwFsdCreate");
|
||
|
||
return Status;
|
||
|
||
UNREFERENCED_PARAMETER(DeviceObject);
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NwCommonCreate (
|
||
IN PIRP_CONTEXT IrpContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the common routine for creating/opening a file called by
|
||
both the fsd and fsp threads.
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies the context information for the IRP to process
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - the return status for the operation
|
||
|
||
--*/
|
||
|
||
{
|
||
IO_STATUS_BLOCK Iosb;
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
|
||
PFILE_OBJECT FileObject;
|
||
ACCESS_MASK DesiredAccess;
|
||
USHORT ShareAccess;
|
||
ULONG Options;
|
||
BOOLEAN CreateTreeConnection;
|
||
BOOLEAN DeleteOnClose;
|
||
BOOLEAN DeferredLogon;
|
||
BOOLEAN DereferenceCodeSection = FALSE;
|
||
BOOLEAN OpenedTreeHandle = FALSE;
|
||
|
||
BOOLEAN fNDSLookupFirst = FALSE;
|
||
USHORT iBufferIndex = 0;
|
||
DWORD dwSlashCount = 0;
|
||
|
||
UNICODE_STRING CreateFileName;
|
||
UNICODE_STRING Drive;
|
||
UNICODE_STRING Server;
|
||
UNICODE_STRING Volume;
|
||
UNICODE_STRING Path;
|
||
UNICODE_STRING FileName;
|
||
UNICODE_STRING UserName, Password;
|
||
ULONG ShareType;
|
||
WCHAR DriveLetter;
|
||
DWORD dwExtendedCreate = FALSE;
|
||
|
||
PSCB Scb = NULL;
|
||
PICB Icb;
|
||
UNICODE_STRING DefaultServer;
|
||
SECURITY_SUBJECT_CONTEXT SubjectContext;
|
||
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Get the current IRP stack location
|
||
//
|
||
|
||
Irp = IrpContext->pOriginalIrp;
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
//
|
||
// tommye - MS bug 30091 / MCS 262 - added some safety nets around those pointers
|
||
// containing pointers so we don't bugcheck in the debug code.
|
||
//
|
||
|
||
DebugTrace(+1, Dbg, "NwCommonCreate\n", 0 );
|
||
DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp );
|
||
DebugTrace( 0, Dbg, "->Flags = %08lx\n", Irp->Flags );
|
||
DebugTrace( 0, Dbg, "->FileObject = %08lx\n", IrpSp->FileObject );
|
||
if (IrpSp->FileObject) {
|
||
DebugTrace( 0, Dbg, " ->RelatedFileObject = %08lx\n", IrpSp->FileObject->RelatedFileObject );
|
||
DebugTrace( 0, Dbg, " ->FileName = \"%wZ\"\n", &IrpSp->FileObject->FileName );
|
||
}
|
||
DebugTrace( 0, Dbg, "->AllocationSize.LowPart = %08lx\n", Irp->Overlay.AllocationSize.LowPart );
|
||
DebugTrace( 0, Dbg, "->AllocationSize.HighPart = %08lx\n", Irp->Overlay.AllocationSize.HighPart );
|
||
DebugTrace( 0, Dbg, "->SystemBuffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer );
|
||
DebugTrace( 0, Dbg, "->IrpSp->Flags = %08lx\n", IrpSp->Flags );
|
||
if (IrpSp->Parameters.Create.SecurityContext) {
|
||
DebugTrace( 0, Dbg, "->DesiredAccess = %08lx\n", IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
|
||
}
|
||
DebugTrace( 0, Dbg, "->Options = %08lx\n", IrpSp->Parameters.Create.Options );
|
||
DebugTrace( 0, Dbg, "->Disposition = %08lx\n", (IrpSp->Parameters.Create.Options >> 24) & 0x000000ff);
|
||
DebugTrace( 0, Dbg, "->FileAttributes = %04x\n", IrpSp->Parameters.Create.FileAttributes );
|
||
DebugTrace( 0, Dbg, "->ShareAccess = %04x\n", IrpSp->Parameters.Create.ShareAccess );
|
||
DebugTrace( 0, Dbg, "->EaLength = %08lx\n", IrpSp->Parameters.Create.EaLength );
|
||
|
||
CreateFileName = IrpSp->FileObject->FileName;
|
||
Options = IrpSp->Parameters.Create.Options;
|
||
DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
|
||
ShareAccess = IrpSp->Parameters.Create.ShareAccess;
|
||
|
||
CreateTreeConnection = BooleanFlagOn( Options, FILE_CREATE_TREE_CONNECTION );
|
||
DeleteOnClose = BooleanFlagOn( Options, FILE_DELETE_ON_CLOSE );
|
||
|
||
DefaultServer.Buffer = NULL;
|
||
|
||
//
|
||
// Make sure the input large integer is valid
|
||
//
|
||
|
||
if (Irp->Overlay.AllocationSize.HighPart != 0) {
|
||
|
||
DebugTrace(-1, Dbg, "NwCommonCreate -> STATUS_INVALID_PARAMETER\n", 0);
|
||
return STATUS_INVALID_PARAMETER;
|
||
}
|
||
|
||
//
|
||
// Fail requests that don't have the proper impersonation level.
|
||
//
|
||
|
||
if ( IrpSp->Parameters.Create.SecurityContext ) {
|
||
|
||
if ( IrpSp->Parameters.Create.SecurityContext->SecurityQos ) {
|
||
|
||
if ( IrpSp->Parameters.Create.SecurityContext->SecurityQos->ImpersonationLevel <
|
||
SecurityImpersonation ) {
|
||
|
||
DebugTrace(-1, Dbg, "NwCommonCreate -> Insufficient impersation level.\n", 0);
|
||
return STATUS_ACCESS_DENIED;
|
||
}
|
||
}
|
||
}
|
||
|
||
Iosb.Status = STATUS_SUCCESS;
|
||
|
||
FileObject = IrpSp->FileObject;
|
||
IrpContext->pNpScb = NULL;
|
||
|
||
IrpContext->Specific.Create.UserUid =
|
||
GetUid(&IrpSp->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext);
|
||
|
||
try {
|
||
|
||
if ( IrpSp->FileObject->RelatedFileObject != NULL ) {
|
||
|
||
//
|
||
// If we open a handle then the DereferenceCodeSection flag
|
||
// will be set to false. The dereference will eventually
|
||
// happen when the file is closed.
|
||
//
|
||
|
||
NwReferenceUnlockableCodeSection();
|
||
DereferenceCodeSection = TRUE;
|
||
|
||
//
|
||
// Record the relative file name for this open.
|
||
//
|
||
|
||
IrpContext->Specific.Create.FullPathName = CreateFileName;
|
||
|
||
Iosb = CreateRemoteFile( IrpContext, NULL );
|
||
|
||
//
|
||
// If we succeeded, we want to keep the code section
|
||
// referenced because we have opened a handle.
|
||
//
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
DereferenceCodeSection = FALSE;
|
||
}
|
||
|
||
try_return( Iosb.Status );
|
||
}
|
||
|
||
Iosb.Status = CrackPath (
|
||
&CreateFileName,
|
||
&Drive,
|
||
&DriveLetter,
|
||
&Server,
|
||
&Volume,
|
||
&Path,
|
||
&FileName,
|
||
NULL );
|
||
|
||
if ( !NT_SUCCESS(Iosb.Status)) {
|
||
try_return(Iosb.Status);
|
||
}
|
||
|
||
//
|
||
// Remember this good info.
|
||
//
|
||
|
||
IrpContext->Specific.Create.VolumeName = Volume;
|
||
IrpContext->Specific.Create.PathName = Path;
|
||
IrpContext->Specific.Create.DriveLetter = DriveLetter;
|
||
IrpContext->Specific.Create.FileName = FileName;
|
||
IrpContext->Specific.Create.FullPathName = CreateFileName;
|
||
|
||
RtlInitUnicodeString( &IrpContext->Specific.Create.UidConnectName, NULL );
|
||
|
||
|
||
//
|
||
// For now assume default username and password
|
||
//
|
||
|
||
ShareType = RESOURCETYPE_ANY;
|
||
RtlInitUnicodeString( &UserName, NULL );
|
||
RtlInitUnicodeString( &Password, NULL );
|
||
|
||
if ( Server.Length == 0) {
|
||
|
||
//
|
||
// Opened the redirector itself
|
||
//
|
||
|
||
Iosb = OpenRedirector(
|
||
IrpContext,
|
||
DesiredAccess,
|
||
ShareAccess,
|
||
FileObject );
|
||
|
||
} else if ( Server.Length == Volume.Length - sizeof( WCHAR ) ) {
|
||
|
||
if (IpxHandle == 0 ) {
|
||
|
||
//
|
||
// We're not bound to the transport and the user is not
|
||
// opening the redirector to tell us to bind so return failed.
|
||
//
|
||
|
||
try_return( Iosb.Status = STATUS_REDIRECTOR_NOT_STARTED );
|
||
}
|
||
|
||
NwReferenceUnlockableCodeSection();
|
||
DereferenceCodeSection = TRUE;
|
||
|
||
//
|
||
// If the only requested access is FILE_LIST_DIRECTORY,
|
||
// defer the logon. This will allow all CreateScb to
|
||
// succeed with when the user or password is invalid, so
|
||
// that the user can see volumes, or enumerate servers
|
||
// on the server.
|
||
//
|
||
|
||
if ( (DesiredAccess & ~( FILE_LIST_DIRECTORY | SYNCHRONIZE ) ) == 0 ) {
|
||
DeferredLogon = TRUE;
|
||
} else {
|
||
DeferredLogon = FALSE;
|
||
}
|
||
|
||
//
|
||
// Server = "Server", Volume = "\Server"
|
||
//
|
||
|
||
if ( Server.Length == sizeof(WCHAR) && Server.Buffer[0] == L'*') {
|
||
|
||
//
|
||
// Attempt to open \\*, open a handle to the preferred
|
||
// server
|
||
//
|
||
|
||
PLOGON Logon;
|
||
|
||
NwAcquireExclusiveRcb( &NwRcb, TRUE );
|
||
|
||
Logon = FindUser( &IrpContext->Specific.Create.UserUid, FALSE);
|
||
ASSERT( Logon != NULL );
|
||
|
||
//
|
||
// Capture the name to avoid holding Rcb or referencing
|
||
// the logon structure.
|
||
//
|
||
|
||
Iosb.Status = DuplicateUnicodeStringWithString (
|
||
&DefaultServer,
|
||
&Logon->ServerName,
|
||
PagedPool);
|
||
|
||
NwReleaseRcb( &NwRcb );
|
||
|
||
if (!NT_SUCCESS(Iosb.Status)) {
|
||
try_return( Iosb.Status );
|
||
}
|
||
|
||
//
|
||
// If the user specified a preferred server and we managed
|
||
// to capture the name, try and connect to it.
|
||
//
|
||
|
||
if (DefaultServer.Length != 0) {
|
||
|
||
Iosb.Status = CreateScb(
|
||
&Scb,
|
||
IrpContext,
|
||
&DefaultServer,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
DeferredLogon,
|
||
FALSE );
|
||
|
||
|
||
} else {
|
||
|
||
//
|
||
// Record that we could not get to the server specified
|
||
// in the login structure and that we should attempt to
|
||
// use the nearest server.
|
||
//
|
||
|
||
Iosb.Status = STATUS_BAD_NETWORK_PATH;
|
||
}
|
||
|
||
if ( !NT_SUCCESS(Iosb.Status)) {
|
||
|
||
PNONPAGED_SCB NpScb;
|
||
|
||
//
|
||
// First dequeue the IRP context, in case it was left
|
||
// on an SCB queue.
|
||
//
|
||
|
||
NwDequeueIrpContext( IrpContext, FALSE );
|
||
|
||
//
|
||
// Cannot get to the Preferred server so use any
|
||
// server we have a connection to.
|
||
//
|
||
|
||
|
||
NpScb = SelectConnection( NULL );
|
||
|
||
if (NpScb != NULL ) {
|
||
|
||
Scb = NpScb->pScb;
|
||
|
||
Iosb.Status = CreateScb(
|
||
&Scb,
|
||
IrpContext,
|
||
&NpScb->ServerName,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
DeferredLogon,
|
||
FALSE );
|
||
|
||
//
|
||
// Release the SCB reference we obtained from
|
||
// SelectConnection().
|
||
//
|
||
|
||
NwDereferenceScb( NpScb );
|
||
}
|
||
}
|
||
|
||
if ( !NT_SUCCESS(Iosb.Status)) {
|
||
|
||
//
|
||
// First dequeue the IRP context, in case it was left
|
||
// on an SCB queue.
|
||
//
|
||
|
||
NwDequeueIrpContext( IrpContext, FALSE );
|
||
|
||
//
|
||
// Let CreateScb try and find a nearest server to talk
|
||
// to.
|
||
//
|
||
|
||
Iosb.Status = CreateScb(
|
||
&Scb,
|
||
IrpContext,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
DeferredLogon,
|
||
FALSE );
|
||
}
|
||
|
||
if ( !NT_SUCCESS(Iosb.Status)) {
|
||
try_return( Iosb.Status );
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// On handle opens to a server or tree we support the concept
|
||
// of an open with supplemental credentials. In this case, we return
|
||
// a handle to the server or a dir server using the provided
|
||
// credentials regardless of whether or not there are existing
|
||
// connections to the resource. This is primarily for admin
|
||
// tools like OleDs.
|
||
//
|
||
|
||
ReadAttachEas( Irp, &UserName, &Password, &ShareType, &dwExtendedCreate );
|
||
|
||
if ( dwExtendedCreate ) {
|
||
|
||
ASSERT( UserName.Length > 0 );
|
||
|
||
IrpContext->Specific.Create.fExCredentialCreate = TRUE;
|
||
IrpContext->Specific.Create.puCredentialName = &UserName;
|
||
|
||
//
|
||
// Reference the credentials before doing the create so
|
||
// we are guaranteed not to lose them. This call will
|
||
// create a credential shell if none exists. This keeps
|
||
// our reference counting consistent. We track the
|
||
// credentials pointer in the irp context specific data.
|
||
//
|
||
|
||
Iosb.Status = ExCreateReferenceCredentials( IrpContext, &Server );
|
||
|
||
if ( !NT_SUCCESS( Iosb.Status ) ) {
|
||
try_return( Iosb.Status );
|
||
}
|
||
|
||
}
|
||
|
||
if (PreferNDSBrowsing) {
|
||
|
||
//
|
||
// Attempt to open \\TREE
|
||
//
|
||
|
||
Iosb.Status = NdsCreateTreeScb( IrpContext,
|
||
&Scb, // dest scb
|
||
&Server, // tree we want
|
||
&UserName,
|
||
&Password,
|
||
DeferredLogon,
|
||
DeleteOnClose );
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
OpenedTreeHandle = TRUE;
|
||
}
|
||
|
||
if ( ( Iosb.Status == STATUS_REMOTE_NOT_LISTENING ) ||
|
||
( Iosb.Status == STATUS_BAD_NETWORK_PATH ) ||
|
||
( Iosb.Status == STATUS_UNSUCCESSFUL ) ) {
|
||
|
||
//
|
||
// If we couldn't find the server or something
|
||
// inexplicable occurred, attempt to open \\server
|
||
//
|
||
|
||
Iosb.Status = CreateScb(
|
||
&Scb,
|
||
IrpContext,
|
||
&Server,
|
||
NULL,
|
||
&UserName,
|
||
&Password,
|
||
DeferredLogon,
|
||
DeleteOnClose );
|
||
}
|
||
|
||
}else{
|
||
|
||
//
|
||
// Attempt to open \\server
|
||
//
|
||
|
||
Iosb.Status = CreateScb(
|
||
&Scb,
|
||
IrpContext,
|
||
&Server,
|
||
NULL,
|
||
&UserName,
|
||
&Password,
|
||
DeferredLogon,
|
||
DeleteOnClose );
|
||
|
||
if ( ( Iosb.Status == STATUS_REMOTE_NOT_LISTENING ) ||
|
||
( Iosb.Status == STATUS_BAD_NETWORK_PATH ) ||
|
||
( Iosb.Status == STATUS_UNSUCCESSFUL ) ) {
|
||
|
||
//
|
||
// If we couldn't find the server or something
|
||
// inexplicable occurred, attempt to open \\tree.
|
||
//
|
||
|
||
Iosb.Status = NdsCreateTreeScb( IrpContext,
|
||
&Scb, // dest scb
|
||
&Server, // tree we want
|
||
&UserName,
|
||
&Password,
|
||
DeferredLogon,
|
||
DeleteOnClose );
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
OpenedTreeHandle = TRUE;
|
||
}
|
||
}
|
||
}
|
||
|
||
// if( IsTerminalServer() ) clause below has been shifted down as we are more
|
||
// likely to be opening a tree or server than a pserver.
|
||
// so we need to check there first.
|
||
|
||
if (IsTerminalServer()) {
|
||
|
||
/*
|
||
* This is an attempt to get GUEST to work for printman.
|
||
* I.E. If you have no connection, try the guest
|
||
* connection.
|
||
*/
|
||
if ( ( !NT_SUCCESS(Iosb.Status) ) &&
|
||
( Iosb.Status == STATUS_NO_SUCH_USER ) &&
|
||
( !CreateTreeConnection ) &&
|
||
( !DeferredLogon ) ) {
|
||
|
||
DebugTrace( -1, Dbg, " Attempting default GUEST logon for %wZ\n", &Server );
|
||
|
||
Iosb.Status = CreateScb(
|
||
&Scb,
|
||
IrpContext,
|
||
&Server,
|
||
NULL,
|
||
&Guest.UserName,
|
||
&Guest.PassWord,
|
||
DeferredLogon,
|
||
DeleteOnClose );
|
||
}
|
||
}
|
||
|
||
if ( !NT_SUCCESS( Iosb.Status ) ) {
|
||
|
||
//
|
||
// If we failed to get the bindery server for
|
||
// some legitimate reason, bail out now.
|
||
//
|
||
try_return( Iosb.Status );
|
||
}
|
||
|
||
//
|
||
// We must have a connection at this point. We don't tree
|
||
// connect the dir server since it's virtual.
|
||
//
|
||
|
||
if ( !OpenedTreeHandle && CreateTreeConnection && !DeleteOnClose ) {
|
||
TreeConnectScb( Scb );
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Now create the ICB.
|
||
//
|
||
|
||
ASSERT( Iosb.Status == STATUS_SUCCESS );
|
||
ASSERT( Scb != NULL );
|
||
|
||
Icb = NwCreateIcb( NW_NTC_ICB_SCB, Scb );
|
||
Icb->FileObject = FileObject;
|
||
NwSetFileObject( FileObject, NULL, Icb );
|
||
|
||
//
|
||
// Indicate that the SCB was opened.
|
||
//
|
||
|
||
Icb->State = ICB_STATE_OPENED;
|
||
|
||
//
|
||
// Is this a tree handle?
|
||
//
|
||
|
||
Icb->IsTreeHandle = OpenedTreeHandle;
|
||
|
||
//
|
||
// If this was an extended create, associate this handle
|
||
// with its extended credentials so that we can cleanup
|
||
// when all the handles are closed.
|
||
//
|
||
|
||
if ( IrpContext->Specific.Create.fExCredentialCreate ) {
|
||
|
||
ASSERT( IrpContext->Specific.Create.pExCredentials != NULL );
|
||
Icb->pContext = IrpContext->Specific.Create.pExCredentials;
|
||
Icb->IsExCredentialHandle = TRUE;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
NwReferenceUnlockableCodeSection();
|
||
DereferenceCodeSection = TRUE;
|
||
|
||
DeferredLogon = FALSE;
|
||
|
||
if ( CreateTreeConnection ) {
|
||
|
||
//
|
||
// We ignore the extended create attribute here because
|
||
// we DO NOT support extended credential creates to random
|
||
// files and directories!
|
||
//
|
||
|
||
ReadAttachEas( Irp, &UserName, &Password, &ShareType, NULL );
|
||
|
||
if ( DeleteOnClose ) {
|
||
|
||
//
|
||
// Opening a directory to delete a volume. Do not
|
||
// force logon.
|
||
//
|
||
|
||
DeferredLogon = TRUE;
|
||
}
|
||
}
|
||
|
||
IrpContext->Specific.Create.ShareType = ShareType;
|
||
IrpContext->Specific.Create.NdsCreate = FALSE;
|
||
|
||
//
|
||
// Check to see if this is an NDS object, if so set the flag to check NDS first.
|
||
// The only way a DOT can be in the Volume name is if it is an NDS Object,
|
||
// between the third and fourth slashes.
|
||
//
|
||
|
||
fNDSLookupFirst = FALSE;
|
||
|
||
for (iBufferIndex=0; iBufferIndex < (USHORT)(Volume.Length/sizeof(WCHAR)); iBufferIndex++ ) {
|
||
if (Volume.Buffer[iBufferIndex] == L'\\')
|
||
dwSlashCount++;
|
||
|
||
if (dwSlashCount > 3) {
|
||
fNDSLookupFirst = FALSE;
|
||
break;
|
||
}
|
||
if (Volume.Buffer[iBufferIndex] == L'.') {
|
||
fNDSLookupFirst = TRUE;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (fNDSLookupFirst) {
|
||
|
||
IrpContext->Specific.Create.NdsCreate = TRUE;
|
||
IrpContext->Specific.Create.NeedNdsData = TRUE;
|
||
|
||
Iosb.Status = NdsCreateTreeScb( IrpContext,
|
||
&Scb,
|
||
&Server,
|
||
&UserName,
|
||
&Password,
|
||
DeferredLogon,
|
||
DeleteOnClose );
|
||
|
||
|
||
|
||
if ( Iosb.Status == STATUS_REMOTE_NOT_LISTENING ||
|
||
Iosb.Status == STATUS_BAD_NETWORK_PATH ||
|
||
Iosb.Status == STATUS_UNSUCCESSFUL ) {
|
||
|
||
//
|
||
// Not found, do a bindery lookup
|
||
//
|
||
|
||
IrpContext->Specific.Create.NdsCreate = FALSE;
|
||
IrpContext->Specific.Create.NeedNdsData = FALSE;
|
||
|
||
Iosb.Status = CreateScb(
|
||
&Scb,
|
||
IrpContext,
|
||
&Server,
|
||
NULL,
|
||
&UserName,
|
||
&Password,
|
||
DeferredLogon,
|
||
DeleteOnClose );
|
||
}
|
||
|
||
|
||
}else {
|
||
|
||
//
|
||
// Object appears to be bindery, check there first.
|
||
//
|
||
|
||
Iosb.Status = CreateScb(
|
||
&Scb,
|
||
IrpContext,
|
||
&Server,
|
||
NULL,
|
||
&UserName,
|
||
&Password,
|
||
DeferredLogon,
|
||
DeleteOnClose );
|
||
|
||
|
||
if ( Iosb.Status == STATUS_REMOTE_NOT_LISTENING ||
|
||
Iosb.Status == STATUS_BAD_NETWORK_PATH ||
|
||
Iosb.Status == STATUS_UNSUCCESSFUL ) {
|
||
|
||
//
|
||
// If we couldn't find the server or something
|
||
// inexplicable occurred, attempt to open \\tree.
|
||
//
|
||
|
||
IrpContext->Specific.Create.NdsCreate = TRUE;
|
||
IrpContext->Specific.Create.NeedNdsData = TRUE;
|
||
|
||
Iosb.Status = NdsCreateTreeScb( IrpContext,
|
||
&Scb,
|
||
&Server,
|
||
&UserName,
|
||
&Password,
|
||
DeferredLogon,
|
||
DeleteOnClose );
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we have success, then there's a volume to connect.
|
||
//
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
|
||
NTSTATUS CreateScbStatus;
|
||
|
||
ASSERT( Scb != NULL );
|
||
|
||
//
|
||
// Remember the status from create SCB, since it might
|
||
// be an interesting warning.
|
||
//
|
||
|
||
CreateScbStatus = Iosb.Status;
|
||
|
||
//
|
||
// We catch this exception in case we have to retry the
|
||
// create on the NDS path. This is horrable, as does the
|
||
// exception structure in this code right now, but it's
|
||
// legacy and now is not the time to change it.
|
||
//
|
||
|
||
try {
|
||
|
||
Iosb = CreateRemoteFile(
|
||
IrpContext,
|
||
&Drive );
|
||
|
||
} except ( EXCEPTION_EXECUTE_HANDLER ) {
|
||
|
||
Iosb.Status = GetExceptionCode();
|
||
}
|
||
|
||
//
|
||
// If this is a server whose name is the same as the tree
|
||
// that it is a member of, and the create was marked as
|
||
// non-nds and it failed, retry an nds create.
|
||
//
|
||
|
||
if ( ( !NT_SUCCESS( Iosb.Status) ) &&
|
||
( !(IrpContext->Specific.Create.NdsCreate) ) &&
|
||
( RtlEqualUnicodeString( &(Scb->pNpScb->ServerName),
|
||
&(Scb->NdsTreeName),
|
||
TRUE ) ) ) {
|
||
|
||
IrpContext->Specific.Create.NdsCreate = TRUE;
|
||
IrpContext->Specific.Create.NeedNdsData = TRUE;
|
||
|
||
Iosb = CreateRemoteFile(
|
||
IrpContext,
|
||
&Drive );
|
||
|
||
//
|
||
// If this fails, it will raise status before setting IOSB
|
||
// and we'll return the status from the original create,
|
||
// which is the more interesting one.
|
||
//
|
||
|
||
}
|
||
|
||
//
|
||
// If we successfully open the remote file, return the
|
||
// CreateScb status instead.
|
||
//
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = CreateScbStatus;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
//
|
||
// If we succeeded, we want to keep the code section
|
||
// referenced because we have opened a handle.
|
||
//
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
DereferenceCodeSection = FALSE;
|
||
}
|
||
|
||
try_exit: NOTHING;
|
||
} finally {
|
||
|
||
//
|
||
// Track the Scb in the IrpContext, not in the local Scb
|
||
// variable since we may have been routed to another server
|
||
// in process.
|
||
//
|
||
|
||
if (( Scb != NULL ) && ( IrpContext->pNpScb != NULL )) {
|
||
NwDereferenceScb( IrpContext->pNpScb );
|
||
}
|
||
|
||
if ( DefaultServer.Buffer != NULL ) {
|
||
FREE_POOL( DefaultServer.Buffer );
|
||
}
|
||
|
||
if ( ( IrpContext->Specific.Create.fExCredentialCreate ) &&
|
||
( IrpContext->Specific.Create.pExCredentials ) &&
|
||
( !NT_SUCCESS( Iosb.Status ) ) ) {
|
||
|
||
ExCreateDereferenceCredentials(
|
||
IrpContext,
|
||
IrpContext->Specific.Create.pExCredentials
|
||
);
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "NwCommonCreate -> %08lx\n", Iosb.Status);
|
||
|
||
if ( DereferenceCodeSection ) {
|
||
NwDereferenceUnlockableCodeSection ();
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Map a timeout error to server not found, so that MPR will
|
||
// try to connect on the next network provider instead of giving up,
|
||
// which is wrong wrong wrong.
|
||
//
|
||
|
||
if ( Iosb.Status == STATUS_REMOTE_NOT_LISTENING ) {
|
||
Iosb.Status = STATUS_BAD_NETWORK_PATH;
|
||
}
|
||
|
||
//
|
||
// Map an unbound transport error to server not found, so that MPR
|
||
// will try to connect on the next provider.
|
||
//
|
||
|
||
if ( Iosb.Status == STATUS_NETWORK_UNREACHABLE ) {
|
||
Iosb.Status = STATUS_BAD_NETWORK_PATH;
|
||
}
|
||
|
||
return Iosb.Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
ReadAttachEas(
|
||
IN PIRP Irp,
|
||
OUT PUNICODE_STRING UserName,
|
||
OUT PUNICODE_STRING Password,
|
||
OUT PULONG ShareType,
|
||
OUT PDWORD CredentialExtension
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine processes the EAs provided when the caller attempts
|
||
to attach to a remote server.
|
||
|
||
Note: This routine does not create additional storage for the names.
|
||
It is the callers responsibility to save them if required.
|
||
|
||
Arguments:
|
||
|
||
Irp - Supplies all the information
|
||
|
||
UserName - Returns the value of the User name EA
|
||
|
||
Password - Returns the value of the password EA
|
||
|
||
ShareType - Returns the value of the share type EA
|
||
|
||
CredentialExtension - Returns whether or not this create
|
||
should use the provided credentials for an credential
|
||
extended connection. This is primarily for OleDs
|
||
accessing the ds in multiple security contexts.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status of operation
|
||
|
||
--*/
|
||
{
|
||
|
||
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
PFILE_FULL_EA_INFORMATION EaBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
PAGED_CODE();
|
||
|
||
RtlInitUnicodeString( UserName, NULL );
|
||
RtlInitUnicodeString( Password, NULL );
|
||
*ShareType = RESOURCETYPE_ANY;
|
||
if ( CredentialExtension ) {
|
||
*CredentialExtension = FALSE;
|
||
}
|
||
|
||
DebugTrace(+1, Dbg, "ReadAttachEas....\n", 0);
|
||
|
||
if ( EaBuffer != NULL) {
|
||
|
||
while (TRUE) {
|
||
ULONG EaNameLength = EaBuffer->EaNameLength;
|
||
|
||
if (strcmp(EaBuffer->EaName, EA_NAME_USERNAME) == 0) {
|
||
|
||
UserName->Length = EaBuffer->EaValueLength;
|
||
UserName->MaximumLength = EaBuffer->EaValueLength;
|
||
UserName->Buffer = (PWSTR)(EaBuffer->EaName+EaNameLength+1);
|
||
|
||
} else if (strcmp(EaBuffer->EaName, EA_NAME_PASSWORD) == 0) {
|
||
|
||
Password->Length = EaBuffer->EaValueLength;
|
||
Password->MaximumLength = EaBuffer->EaValueLength;
|
||
Password->Buffer = (PWSTR)(EaBuffer->EaName+EaNameLength+1);
|
||
|
||
} else if ((strcmp(EaBuffer->EaName, EA_NAME_TYPE) == 0) &&
|
||
(EaBuffer->EaValueLength >= sizeof(ULONG))) {
|
||
|
||
*ShareType = *(ULONG UNALIGNED *)(EaBuffer->EaName+EaNameLength+1);
|
||
|
||
} else if (strcmp(EaBuffer->EaName, EA_NAME_CREDENTIAL_EX) == 0) {
|
||
|
||
if ( CredentialExtension ) {
|
||
*CredentialExtension = TRUE;
|
||
DebugTrace(0, Dbg, "ReadAttachEas signals a credential extension.\n", 0 );
|
||
}
|
||
|
||
} else {
|
||
DebugTrace(0, Dbg, "ReadAttachEas Unknown EA -> %s\n", EaBuffer->EaName);
|
||
}
|
||
|
||
if (EaBuffer->NextEntryOffset == 0) {
|
||
break;
|
||
} else {
|
||
EaBuffer = (PFILE_FULL_EA_INFORMATION) ((PCHAR) EaBuffer+EaBuffer->NextEntryOffset);
|
||
}
|
||
}
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "ReadAttachEas -> %08lx\n", STATUS_SUCCESS);
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
|
||
IO_STATUS_BLOCK
|
||
OpenRedirector(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
ULONG DesiredAccess,
|
||
ULONG ShareAccess,
|
||
PFILE_OBJECT FileObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines opens a handle to the redirector device.
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies all the information
|
||
|
||
DesiredAccess - The requested access to the redirector.
|
||
|
||
ShareAccess - The requested share access to the redirector.
|
||
|
||
FileObject - A pointer to the caller file object.
|
||
|
||
Return Value:
|
||
|
||
IO_STATUS_BLOCK - Status of operation
|
||
|
||
--*/
|
||
|
||
{
|
||
IO_STATUS_BLOCK iosb;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Note that the object manager will only allow an administrator
|
||
// to open the redir itself. This is good.
|
||
//
|
||
|
||
DebugTrace(+1, Dbg, "NwOpenRedirector\n", 0);
|
||
|
||
NwAcquireExclusiveRcb( &NwRcb, TRUE );
|
||
|
||
try {
|
||
|
||
//
|
||
// Set the new share access
|
||
//
|
||
|
||
if (!NT_SUCCESS(iosb.Status = IoCheckShareAccess( DesiredAccess,
|
||
ShareAccess,
|
||
FileObject,
|
||
&NwRcb.ShareAccess,
|
||
TRUE ))) {
|
||
|
||
DebugTrace(0, Dbg, "bad share access\n", 0);
|
||
|
||
try_return( NOTHING );
|
||
}
|
||
|
||
NwSetFileObject( FileObject, NULL, &NwRcb );
|
||
++NwRcb.OpenCount;
|
||
|
||
//
|
||
// Set the return status.
|
||
//
|
||
|
||
iosb.Status = STATUS_SUCCESS;
|
||
iosb.Information = FILE_OPENED;
|
||
|
||
try_exit: NOTHING;
|
||
} finally {
|
||
|
||
NwReleaseRcb( &NwRcb );
|
||
DebugTrace(-1, Dbg, "NwOpenRedirector -> Iosb.Status = %08lx\n", iosb.Status);
|
||
|
||
}
|
||
|
||
//
|
||
// Return to the caller.
|
||
//
|
||
|
||
return iosb;
|
||
}
|
||
|
||
|
||
IO_STATUS_BLOCK
|
||
CreateRemoteFile(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PUNICODE_STRING DriveName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines opens a remote file or directory.
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies all the information
|
||
|
||
DriveName - The drive name. One of three forms X:, LPTx, or NULL.
|
||
|
||
Return Value:
|
||
|
||
IO_STATUS_BLOCK - Status of operation
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK Iosb;
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
|
||
ULONG DesiredAccess;
|
||
ULONG ShareAccess;
|
||
PFILE_OBJECT FileObject;
|
||
|
||
UNICODE_STRING FileName;
|
||
PFILE_OBJECT RelatedFileObject;
|
||
ULONG Options;
|
||
ULONG FileAttributes;
|
||
|
||
BOOLEAN CreateDirectory;
|
||
BOOLEAN OpenDirectory;
|
||
BOOLEAN DirectoryFile;
|
||
BOOLEAN NonDirectoryFile;
|
||
BOOLEAN DeleteOnClose;
|
||
BOOLEAN OpenTargetDirectory;
|
||
ULONG AllocationSize;
|
||
|
||
// Unhandled open features.
|
||
|
||
// PFILE_FULL_EA_INFORMATION EaBuffer;
|
||
// ULONG EaLength;
|
||
// BOOLEAN SequentialOnly;
|
||
// BOOLEAN NoIntermediateBuffering;
|
||
// BOOLEAN IsPagingFile;
|
||
// BOOLEAN NoEaKnowledge;
|
||
|
||
ULONG CreateDisposition;
|
||
|
||
PFCB Fcb = NULL;
|
||
PICB Icb = NULL;
|
||
PDCB Dcb;
|
||
PVCB Vcb = NULL;
|
||
PSCB Scb;
|
||
|
||
BOOLEAN IsAFile;
|
||
BOOLEAN MayBeADirectory = FALSE;
|
||
BOOLEAN OwnOpenLock = FALSE;
|
||
BOOLEAN SetShareAccess = FALSE;
|
||
|
||
BYTE SearchFlags;
|
||
BYTE ShareFlags;
|
||
|
||
BOOLEAN CreateTreeConnection = FALSE;
|
||
PUNICODE_STRING VolumeName;
|
||
|
||
NTSTATUS Status;
|
||
UNICODE_STRING NdsConnectName;
|
||
WCHAR ConnectBuffer[MAX_NDS_NAME_CHARS];
|
||
BOOLEAN MadeUidNdsName = FALSE;
|
||
|
||
PAGED_CODE();
|
||
|
||
Irp = IrpContext->pOriginalIrp;
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
DesiredAccess = IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
|
||
ShareAccess = IrpSp->Parameters.Create.ShareAccess;
|
||
FileObject = IrpSp->FileObject;
|
||
OpenTargetDirectory = BooleanFlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY );
|
||
|
||
//
|
||
// It is ok to attempt a reconnect if this request fails with a
|
||
// connection error.
|
||
//
|
||
|
||
SetFlag( IrpContext->Flags, IRP_FLAG_RECONNECTABLE );
|
||
|
||
|
||
try {
|
||
|
||
//
|
||
// Reference our input parameters to make things easier
|
||
//
|
||
|
||
RelatedFileObject = FileObject->RelatedFileObject;
|
||
|
||
//
|
||
// We actually want the parsed file name.
|
||
// FileName = FileObject->FileName;
|
||
//
|
||
FileName = IrpContext->Specific.Create.FullPathName;
|
||
Options = IrpSp->Parameters.Create.Options;
|
||
FileAttributes = IrpSp->Parameters.Create.FileAttributes;
|
||
AllocationSize = Irp->Overlay.AllocationSize.LowPart;
|
||
|
||
//
|
||
// Short circuit an attempt to open a wildcard name.
|
||
//
|
||
|
||
if ( FsRtlDoesNameContainWildCards( &FileName ) ) {
|
||
try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID );
|
||
}
|
||
|
||
// Decipher Option flags and values
|
||
//
|
||
|
||
DirectoryFile = BooleanFlagOn( Options, FILE_DIRECTORY_FILE );
|
||
NonDirectoryFile = BooleanFlagOn( Options, FILE_NON_DIRECTORY_FILE );
|
||
DeleteOnClose = BooleanFlagOn( Options, FILE_DELETE_ON_CLOSE );
|
||
|
||
//
|
||
// Things we currently ignore, because netware servers don't support it.
|
||
//
|
||
|
||
// SequentialOnly = BooleanFlagOn( Options, FILE_SEQUENTIAL_ONLY );
|
||
// NoIntermediateBuffering = BooleanFlagOn( Options, FILE_NO_INTERMEDIATE_BUFFERING );
|
||
// NoEaKnowledge = BooleanFlagOn( Options, FILE_NO_EA_KNOWLEDGE );
|
||
// EaBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||
// EaLength = IrpSp->Parameters.Create.EaLength;
|
||
// IsPagingFile = BooleanFlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE );
|
||
|
||
if ( BooleanFlagOn( Options, FILE_CREATE_TREE_CONNECTION ) ) {
|
||
CreateDisposition = FILE_OPEN;
|
||
} else {
|
||
CreateDisposition = (Options >> 24) & 0x000000ff;
|
||
}
|
||
|
||
CreateDirectory = (BOOLEAN)(DirectoryFile &&
|
||
((CreateDisposition == FILE_CREATE) ||
|
||
(CreateDisposition == FILE_OPEN_IF)));
|
||
|
||
OpenDirectory = (BOOLEAN)(DirectoryFile &&
|
||
((CreateDisposition == FILE_OPEN) ||
|
||
(CreateDisposition == FILE_OPEN_IF)));
|
||
|
||
Dcb = NULL;
|
||
if ( RelatedFileObject != NULL ) {
|
||
|
||
PNONPAGED_DCB NonPagedDcb;
|
||
|
||
NonPagedDcb = RelatedFileObject->FsContext;
|
||
|
||
if ( NonPagedDcb ) {
|
||
Dcb = NonPagedDcb->Fcb;
|
||
}
|
||
|
||
//
|
||
// If there is a related file object then this is a relative open
|
||
// and it better be a DCB.
|
||
//
|
||
|
||
if ( !Dcb || (NodeType( Dcb ) != NW_NTC_DCB) ) {
|
||
|
||
DebugTrace(0, Dbg, "Bad file name\n", 0);
|
||
Iosb.Status = STATUS_OBJECT_NAME_INVALID;
|
||
try_return( Iosb );
|
||
}
|
||
|
||
|
||
//
|
||
// Obtain SCB pointers.
|
||
//
|
||
|
||
IrpContext->pScb = Dcb->Scb;
|
||
IrpContext->pNpScb = Dcb->Scb->pNpScb;
|
||
}
|
||
|
||
//
|
||
// We are about ready to send a packet. Append this IRP context
|
||
// the SCB workqueue, and wait until it gets to the front.
|
||
//
|
||
|
||
NwAppendToQueueAndWait( IrpContext );
|
||
ASSERT( IrpContext->pNpScb->Requests.Flink == &IrpContext->NextRequest );
|
||
|
||
//
|
||
// Acquire the Global FCB resource to ensure that one thread
|
||
// can't access the half created FCB of another thread.
|
||
//
|
||
|
||
NwAcquireOpenLock( );
|
||
OwnOpenLock = TRUE;
|
||
|
||
//
|
||
// Find the volume for this file.
|
||
//
|
||
|
||
CreateTreeConnection = BooleanFlagOn( Options, FILE_CREATE_TREE_CONNECTION );
|
||
|
||
if ( CreateTreeConnection ) {
|
||
VolumeName = &IrpContext->Specific.Create.FullPathName;
|
||
} else {
|
||
VolumeName = &IrpContext->Specific.Create.VolumeName;
|
||
}
|
||
|
||
if ( Dcb == NULL ) {
|
||
|
||
RetryFindVcb:
|
||
|
||
Vcb = NwFindVcb(
|
||
IrpContext,
|
||
VolumeName,
|
||
IrpContext->Specific.Create.ShareType,
|
||
IrpContext->Specific.Create.DriveLetter,
|
||
CreateTreeConnection,
|
||
( BOOLEAN )( CreateTreeConnection && DeleteOnClose ) );
|
||
|
||
if ( Vcb == NULL ) {
|
||
|
||
//
|
||
// If this create failed because we need nds data, get
|
||
// the data from the ds and resubmit the request.
|
||
//
|
||
|
||
if ( IrpContext->Specific.Create.NdsCreate &&
|
||
IrpContext->Specific.Create.NeedNdsData ) {
|
||
|
||
//
|
||
// Release the open resource so we can move around.
|
||
//
|
||
|
||
NwReleaseOpenLock( );
|
||
OwnOpenLock = FALSE;
|
||
|
||
//
|
||
// Take the volume name and build the server/share
|
||
// connect name.
|
||
//
|
||
|
||
NdsConnectName.Buffer = ConnectBuffer;
|
||
NdsConnectName.MaximumLength = sizeof( ConnectBuffer );
|
||
NdsConnectName.Length = 0;
|
||
|
||
//
|
||
// Get the ds information. We may jump servers here.
|
||
//
|
||
|
||
Status = NdsMapObjectToServerShare( IrpContext,
|
||
&Scb,
|
||
&NdsConnectName,
|
||
CreateTreeConnection,
|
||
&(IrpContext->Specific.Create.dwNdsOid) );
|
||
|
||
if( !NT_SUCCESS( Status ) ) {
|
||
ExRaiseStatus( Status );
|
||
}
|
||
|
||
//
|
||
// Make sure we are on the scb queue after all the
|
||
// possible server jumping.
|
||
//
|
||
|
||
NwAppendToQueueAndWait( IrpContext );
|
||
|
||
NwAcquireOpenLock( );
|
||
OwnOpenLock = TRUE;
|
||
|
||
//
|
||
// Prepend the Uid to the server/share name.
|
||
//
|
||
|
||
MergeStrings( &IrpContext->Specific.Create.UidConnectName,
|
||
&Scb->UnicodeUid,
|
||
&NdsConnectName,
|
||
PagedPool );
|
||
|
||
MadeUidNdsName = TRUE;
|
||
|
||
//
|
||
// We have the data, so re-do the connect.
|
||
//
|
||
|
||
IrpContext->Specific.Create.NeedNdsData = FALSE;
|
||
goto RetryFindVcb;
|
||
|
||
} else {
|
||
|
||
//
|
||
// If this was an open to delete a tree connect, and we failed
|
||
// to find the VCB, simply return the error.
|
||
//
|
||
|
||
Iosb.Status = STATUS_BAD_NETWORK_PATH;
|
||
try_return ( Iosb );
|
||
|
||
}
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
Vcb = Dcb->Vcb;
|
||
NwReferenceVcb( Vcb );
|
||
|
||
}
|
||
|
||
ASSERT( Vcb->Scb == IrpContext->pScb );
|
||
|
||
//
|
||
// If this is the target name for a rename then we want to find the
|
||
// DCB for the parent directory.
|
||
//
|
||
|
||
if (OpenTargetDirectory) {
|
||
|
||
Iosb = OpenRenameTarget(IrpContext, Vcb, Dcb, &Icb );
|
||
if (Icb != NULL) {
|
||
Fcb = Icb->SuperType.Fcb;
|
||
}
|
||
try_return ( Iosb );
|
||
|
||
}
|
||
|
||
//
|
||
// Find the FCB for this file. If the FCB exists, we get a
|
||
// referenced pointer. Otherwise a new FCB is created.
|
||
//
|
||
|
||
Fcb = NwFindFcb( IrpContext->pScb, Vcb, &FileName, Dcb );
|
||
// in rare cases, NwFindFcb might return NULL instead of throwing an exception
|
||
// Raid # 432500
|
||
if (Fcb == NULL) {
|
||
DebugTrace(0, Dbg, "NwFindFcb returned NULL in CreateRemoteFile\n", 0);
|
||
Iosb.Status = STATUS_INVALID_PARAMETER;
|
||
try_return( Iosb );
|
||
}
|
||
|
||
//
|
||
// Check the share access for this file. The share access
|
||
// is updated if access is granted.
|
||
//
|
||
if (!IsTerminalServer() ||
|
||
!FlagOn( Vcb->Flags, VCB_FLAG_PRINT_QUEUE )) {
|
||
if ( Fcb->IcbCount > 0 ) {
|
||
NwAcquireSharedFcb( Fcb->NonPagedFcb, TRUE );
|
||
|
||
Iosb.Status = IoCheckShareAccess(
|
||
DesiredAccess,
|
||
ShareAccess,
|
||
FileObject,
|
||
&Fcb->ShareAccess,
|
||
TRUE );
|
||
|
||
NwReleaseFcb( Fcb->NonPagedFcb );
|
||
|
||
if ( !NT_SUCCESS( Iosb.Status ) ) {
|
||
try_return( Iosb );
|
||
}
|
||
|
||
} else {
|
||
|
||
NwAcquireExclusiveFcb( Fcb->NonPagedFcb, TRUE );
|
||
|
||
IoSetShareAccess(
|
||
DesiredAccess,
|
||
ShareAccess,
|
||
FileObject,
|
||
&Fcb->ShareAccess );
|
||
|
||
NwReleaseFcb( Fcb->NonPagedFcb );
|
||
}
|
||
|
||
SetShareAccess = TRUE;
|
||
}
|
||
//
|
||
// Now create the ICB.
|
||
//
|
||
|
||
Icb = NwCreateIcb( NW_NTC_ICB, Fcb );
|
||
Icb->FileObject = FileObject;
|
||
NwSetFileObject( FileObject, Fcb->NonPagedFcb, Icb );
|
||
|
||
#ifndef QFE_BUILD
|
||
|
||
//
|
||
// Supply a resource for the modified page write to grab when
|
||
// writing mem mapped files. We do this because it is imposed
|
||
// on us by the system, we do not require the resource for any
|
||
// real serialization.
|
||
//
|
||
|
||
Fcb->NonPagedFcb->Header.Flags = 0;
|
||
Fcb->NonPagedFcb->Header.Resource = NULL;
|
||
|
||
#endif
|
||
|
||
#ifdef NWFASTIO
|
||
//
|
||
// Initialize private cache map so that the i/o system will call
|
||
// our fast path.
|
||
//
|
||
|
||
FileObject->PrivateCacheMap = (PVOID)1;
|
||
#endif
|
||
|
||
IrpContext->Icb = Icb;
|
||
|
||
//
|
||
// Allocate an 8 bit PID for this ICB. Use different thread so
|
||
// each Wow program gets its own id. This is because if the same id
|
||
// has locks using two handles and closes just one of them the locks
|
||
// on that handle are not discarded.
|
||
//
|
||
|
||
Iosb.Status = NwMapPid(IrpContext->pNpScb, (ULONG_PTR)PsGetCurrentThread(), &Icb->Pid );
|
||
|
||
if ( !NT_SUCCESS( Iosb.Status ) ) {
|
||
try_return( Iosb.Status );
|
||
}
|
||
|
||
//
|
||
// Try to figure out what it is we're expected to open.
|
||
//
|
||
|
||
Iosb.Status = STATUS_SUCCESS;
|
||
|
||
if ( FlagOn( Vcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
|
||
|
||
//
|
||
// Opening a print queue job.
|
||
//
|
||
|
||
Iosb = CreatePrintJob( IrpContext, Vcb, Icb, DriveName );
|
||
|
||
} else if ( DirectoryFile ||
|
||
( Fcb->State == FCB_STATE_OPENED &&
|
||
Fcb->NodeTypeCode == NW_NTC_DCB ) ) {
|
||
|
||
//
|
||
// Opening a directory.
|
||
//
|
||
|
||
MayBeADirectory = TRUE;
|
||
|
||
switch ( CreateDisposition ) {
|
||
|
||
case FILE_OPEN:
|
||
Iosb = ChangeDirectory( IrpContext, Vcb, Icb );
|
||
break;
|
||
|
||
case FILE_CREATE:
|
||
Iosb = CreateDir( IrpContext, Vcb, Icb );
|
||
break;
|
||
|
||
case FILE_OPEN_IF:
|
||
Iosb.Status = FileOrDirectoryExists( IrpContext,
|
||
Vcb,
|
||
Icb,
|
||
&Icb->SuperType.Fcb->RelativeFileName,
|
||
&IsAFile );
|
||
|
||
//
|
||
// If the opener specified a directory, fail this request
|
||
// if the object is a file.
|
||
//
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) && IsAFile ) {
|
||
Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
||
} else if ( !NT_SUCCESS( Iosb.Status )) {
|
||
Iosb = CreateDir( IrpContext, Vcb, Icb );
|
||
}
|
||
break;
|
||
|
||
case FILE_SUPERSEDE:
|
||
case FILE_OVERWRITE:
|
||
case FILE_OVERWRITE_IF:
|
||
Iosb.Status = STATUS_INVALID_PARAMETER;
|
||
break;
|
||
|
||
default:
|
||
KeBugCheck( RDR_FILE_SYSTEM );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
SearchFlags = NtAttributesToNwAttributes( FileAttributes );
|
||
ShareFlags = NtToNwShareFlags( DesiredAccess, ShareAccess );
|
||
|
||
IsAFile = NonDirectoryFile ||
|
||
(Fcb->State == FCB_STATE_OPENED &&
|
||
Fcb->NodeTypeCode == NW_NTC_FCB );
|
||
//
|
||
// Assume we are opening a file. If that fails, and it makes
|
||
// sense try to open a directory.
|
||
//
|
||
|
||
switch ( CreateDisposition ) {
|
||
|
||
case FILE_OPEN:
|
||
|
||
//
|
||
// If the disposition is FILE_OPEN try to avoid an unneeded
|
||
// open, for some desired access types.
|
||
//
|
||
|
||
switch ( DesiredAccess & ~SYNCHRONIZE ) {
|
||
|
||
case FILE_WRITE_ATTRIBUTES:
|
||
case FILE_READ_ATTRIBUTES:
|
||
case DELETE:
|
||
|
||
Iosb.Status = FileOrDirectoryExists(
|
||
IrpContext,
|
||
Vcb,
|
||
Icb,
|
||
&Icb->SuperType.Fcb->RelativeFileName,
|
||
&IsAFile );
|
||
|
||
if ( !IsAFile) {
|
||
MayBeADirectory = TRUE;
|
||
}
|
||
|
||
//
|
||
// Fail open of read only file for delete access,
|
||
// since the netware server won't fail the delete.
|
||
//
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) &&
|
||
CreateDisposition == DELETE &&
|
||
FlagOn( Icb->NpFcb->Attributes, NW_ATTRIBUTE_READ_ONLY ) ) {
|
||
|
||
Iosb.Status = STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
if ( ( Iosb.Status == STATUS_OBJECT_NAME_NOT_FOUND ) &&
|
||
( (DesiredAccess & ~SYNCHRONIZE) == DELETE ) ) {
|
||
//
|
||
// we may not have scan rights. fake the return as OK.
|
||
// NW allows the delete without scan rights.
|
||
//
|
||
Iosb.Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
|
||
Iosb = OpenFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags );
|
||
|
||
if ( ( Iosb.Status == STATUS_OBJECT_NAME_NOT_FOUND ||
|
||
Iosb.Status == STATUS_FILE_IS_A_DIRECTORY )
|
||
&& !IsAFile) {
|
||
|
||
//
|
||
// Opener didn't specify file or directory, and open
|
||
// file failed. So try open directory.
|
||
//
|
||
|
||
Iosb = ChangeDirectory( IrpContext, Vcb, Icb );
|
||
MayBeADirectory = TRUE;
|
||
|
||
} else if ( (Iosb.Status == STATUS_SHARING_VIOLATION) &&
|
||
((ShareFlags == (NW_OPEN_FOR_READ | NW_DENY_WRITE)) ||
|
||
(ShareFlags == (NW_OPEN_FOR_READ)))) {
|
||
|
||
//
|
||
// if the file was already open exclusive (eg. GENERIC_EXECUTE)
|
||
// then a debugger opening it again for read will fail with
|
||
// sharing violation. In this case, we will try open exclusive
|
||
// again to see if that passes.
|
||
//
|
||
|
||
ShareFlags |= NW_OPEN_EXCLUSIVE ;
|
||
ShareFlags &= ~(NW_DENY_WRITE | NW_DENY_READ);
|
||
Iosb = OpenFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags );
|
||
}
|
||
|
||
break;
|
||
|
||
}
|
||
|
||
break;
|
||
|
||
case FILE_CREATE:
|
||
Iosb = CreateNewFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags );
|
||
break;
|
||
|
||
case FILE_OPEN_IF:
|
||
Iosb.Status = FileOrDirectoryExists( IrpContext,
|
||
Vcb,
|
||
Icb,
|
||
&Icb->SuperType.Fcb->RelativeFileName,
|
||
&IsAFile );
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb = OpenFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags );
|
||
} else {
|
||
Iosb = CreateNewFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags );
|
||
}
|
||
|
||
if ( !NT_SUCCESS( Iosb.Status ) && !IsAFile) {
|
||
|
||
//
|
||
// Opener didn't specify file or directory, and open
|
||
// file and create new file both failed. So try open
|
||
// or create directory.
|
||
//
|
||
|
||
MayBeADirectory = TRUE;
|
||
Iosb.Status = FileOrDirectoryExists(
|
||
IrpContext,
|
||
Vcb,
|
||
Icb,
|
||
&Icb->SuperType.Fcb->RelativeFileName,
|
||
&IsAFile);
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Information = FILE_OPENED;
|
||
} else {
|
||
Iosb = CreateDir( IrpContext, Vcb, Icb );
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
//
|
||
// None of the below make sense for directories so if the
|
||
// file operation fails, just return the failure status
|
||
// to the user.
|
||
//
|
||
|
||
case FILE_SUPERSEDE:
|
||
case FILE_OVERWRITE_IF:
|
||
|
||
//
|
||
// Actually, if Overwrite is chosen, we are supposed to
|
||
// get the attributes for a file and OR them with the
|
||
// new attributes.
|
||
//
|
||
|
||
Iosb = CreateOrOverwriteFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags, FALSE );
|
||
break;
|
||
|
||
case FILE_OVERWRITE:
|
||
Iosb.Status = FileOrDirectoryExists(
|
||
IrpContext,
|
||
Vcb,
|
||
Icb,
|
||
&Icb->SuperType.Fcb->RelativeFileName,
|
||
&IsAFile );
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb = CreateOrOverwriteFile( IrpContext, Vcb, Icb, SearchFlags, ShareFlags, FALSE );
|
||
}
|
||
|
||
break;
|
||
|
||
default:
|
||
KeBugCheck( RDR_FILE_SYSTEM );
|
||
}
|
||
|
||
|
||
}
|
||
|
||
try_exit: NOTHING;
|
||
|
||
} finally {
|
||
|
||
if ( Vcb != NULL ) {
|
||
NwDereferenceVcb( Vcb, IrpContext, FALSE );
|
||
}
|
||
|
||
if ( MadeUidNdsName ) {
|
||
FREE_POOL( IrpContext->Specific.Create.UidConnectName.Buffer );
|
||
}
|
||
|
||
if ( AbnormalTermination() || !NT_SUCCESS( Iosb.Status ) ) {
|
||
|
||
//
|
||
// Remove the share access if necessary
|
||
//
|
||
|
||
if ( SetShareAccess ) {
|
||
|
||
NwAcquireExclusiveFcb( Fcb->NonPagedFcb, TRUE );
|
||
IoRemoveShareAccess( FileObject, &Fcb->ShareAccess );
|
||
NwReleaseFcb( Fcb->NonPagedFcb );
|
||
}
|
||
|
||
//
|
||
// Failed to create
|
||
//
|
||
|
||
if ( Icb != NULL ) {
|
||
|
||
if ( Icb->Pid != 0 ) {
|
||
NwUnmapPid(IrpContext->pNpScb, Icb->Pid, NULL );
|
||
}
|
||
//
|
||
// dfergus 19 Apr 2001 #330484
|
||
//
|
||
NwDeleteIcb( NULL, Icb );
|
||
// added to fix 330484
|
||
IrpContext->Icb = NULL;
|
||
}
|
||
|
||
//
|
||
// If this was a tree connect, derefence the extra
|
||
// reference on the VCB.
|
||
//
|
||
|
||
if ( CreateTreeConnection && !DeleteOnClose ) {
|
||
if ( Vcb != NULL ) {
|
||
NwDereferenceVcb( Vcb, IrpContext, FALSE );
|
||
}
|
||
}
|
||
|
||
NwDequeueIrpContext( IrpContext, FALSE );
|
||
|
||
} else {
|
||
|
||
Icb->State = ICB_STATE_OPENED;
|
||
if ( Fcb->State == FCB_STATE_OPEN_PENDING ) {
|
||
Fcb->State = FCB_STATE_OPENED;
|
||
}
|
||
|
||
if ( DeleteOnClose && !CreateTreeConnection ) {
|
||
SetFlag( Fcb->Flags, FCB_FLAGS_DELETE_ON_CLOSE );
|
||
}
|
||
|
||
FileObject->SectionObjectPointer = &Fcb->NonPagedFcb->SegmentObject;
|
||
|
||
if ( MayBeADirectory ) {
|
||
|
||
//
|
||
// We successfully opened the file as a directory.
|
||
// If the DCB is newly created, it will be marked
|
||
// type FCB, update it.
|
||
//
|
||
|
||
Fcb->NodeTypeCode = NW_NTC_DCB;
|
||
}
|
||
|
||
NwDequeueIrpContext( IrpContext, FALSE );
|
||
|
||
}
|
||
|
||
if ( OwnOpenLock ) {
|
||
NwReleaseOpenLock( );
|
||
}
|
||
|
||
}
|
||
|
||
return( Iosb );
|
||
}
|
||
|
||
|
||
IO_STATUS_BLOCK
|
||
ChangeDirectory(
|
||
PIRP_CONTEXT IrpContext,
|
||
PVCB Vcb,
|
||
PICB Icb
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines sets the directory for a remote drive.
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies all the information
|
||
|
||
Vcb - A pointer to the VCB for the remote drive.
|
||
|
||
Icb - A pointer to the file we are opening.
|
||
|
||
Return Value:
|
||
|
||
IO_STATUS_BLOCK - Status of operation
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK Iosb;
|
||
PFCB Fcb;
|
||
BYTE Attributes;
|
||
BOOLEAN FirstTime = TRUE;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// No need to send a packet if we are opening the root of the volume.
|
||
//
|
||
|
||
if ( Icb->SuperType.Fcb->RelativeFileName.Length == 0 ) {
|
||
|
||
Iosb.Status = STATUS_SUCCESS;
|
||
Iosb.Information = FILE_OPENED;
|
||
|
||
return( Iosb );
|
||
}
|
||
|
||
Retry:
|
||
|
||
if ( !BooleanFlagOn( Icb->SuperType.Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"FwbbJ",
|
||
NCP_SEARCH_FILE,
|
||
-1,
|
||
Vcb->Specific.Disk.Handle,
|
||
SEARCH_ALL_DIRECTORIES,
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"N==_b",
|
||
14,
|
||
&Attributes );
|
||
}
|
||
|
||
|
||
} else {
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"LbbWDbDbC",
|
||
NCP_LFN_GET_INFO,
|
||
Vcb->Specific.Disk.LongNameSpace,
|
||
Vcb->Specific.Disk.LongNameSpace,
|
||
SEARCH_ALL_DIRECTORIES,
|
||
LFN_FLAG_INFO_ATTRIBUTES |
|
||
LFN_FLAG_INFO_MODIFY_TIME,
|
||
Vcb->Specific.Disk.VolumeNumber,
|
||
Vcb->Specific.Disk.Handle,
|
||
0,
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"N_b",
|
||
4,
|
||
&Attributes );
|
||
}
|
||
|
||
//
|
||
// Unfortunately, this succeeds even if the file in question
|
||
// is not a directory.
|
||
//
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) &&
|
||
( !FlagOn( Attributes, NW_ATTRIBUTE_DIRECTORY ) ) ) {
|
||
|
||
Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
||
}
|
||
}
|
||
|
||
if ((Iosb.Status == STATUS_INVALID_HANDLE) &&
|
||
(FirstTime)) {
|
||
|
||
//
|
||
// Check to see if Volume handle is invalid. Caused when volume
|
||
// is unmounted and then remounted.
|
||
//
|
||
|
||
FirstTime = FALSE;
|
||
|
||
NwReopenVcbHandle( IrpContext, Vcb );
|
||
|
||
goto Retry;
|
||
}
|
||
|
||
Fcb = Icb->SuperType.Fcb;
|
||
|
||
Fcb->NonPagedFcb->Attributes = (UCHAR)Attributes;
|
||
SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
|
||
|
||
//
|
||
// Set information field assuming success. It will be ignored
|
||
// if the NCP failed.
|
||
//
|
||
|
||
Iosb.Information = FILE_OPENED;
|
||
|
||
if ( Iosb.Status == STATUS_UNSUCCESSFUL ) {
|
||
Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND;
|
||
}
|
||
|
||
return( Iosb );
|
||
}
|
||
|
||
|
||
IO_STATUS_BLOCK
|
||
CreateDir(
|
||
PIRP_CONTEXT IrpContext,
|
||
PVCB Vcb,
|
||
PICB Icb
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines create a new directory.
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies all the information
|
||
|
||
Vcb - A pointer to the VCB for the remote drive.
|
||
|
||
Return Value:
|
||
|
||
IO_STATUS_BLOCK - Status of operation
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK Iosb;
|
||
|
||
PAGED_CODE();
|
||
|
||
if ( Icb->SuperType.Fcb->RelativeFileName.Length == 0 ) {
|
||
Iosb.Status = STATUS_ACCESS_DENIED;
|
||
return( Iosb );
|
||
}
|
||
|
||
if ( !BooleanFlagOn( Icb->SuperType.Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
||
|
||
if (!IsFatNameValid(&Icb->SuperType.Fcb->RelativeFileName)) {
|
||
|
||
Iosb.Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
|
||
|
||
return( Iosb );
|
||
|
||
}
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"SbbJ",
|
||
NCP_DIR_FUNCTION, NCP_CREATE_DIRECTORY,
|
||
Vcb->Specific.Disk.Handle,
|
||
0xFF,
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
|
||
} else {
|
||
|
||
Iosb.Status = ExchangeWithWait(
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"LbbWDDWbDbC",
|
||
NCP_LFN_OPEN_CREATE,
|
||
Vcb->Specific.Disk.LongNameSpace,
|
||
LFN_FLAG_OM_CREATE,
|
||
0, // Search Flags,
|
||
0, // Return Info Mask
|
||
NW_ATTRIBUTE_DIRECTORY,
|
||
0x00ff, // Desired access
|
||
Vcb->Specific.Disk.VolumeNumber,
|
||
Vcb->Specific.Disk.Handle,
|
||
0, // Short directory flag
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
|
||
}
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"N" );
|
||
}
|
||
|
||
//
|
||
// Set information field assuming success. It will be ignored
|
||
// if the NCP failed.
|
||
//
|
||
|
||
Iosb.Information = FILE_CREATED;
|
||
|
||
if ( Iosb.Status == STATUS_UNSUCCESSFUL ) {
|
||
Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
|
||
}
|
||
|
||
return( Iosb );
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
FileOrDirectoryExists(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PVCB Vcb,
|
||
IN PICB Icb OPTIONAL,
|
||
PUNICODE_STRING Name,
|
||
OUT PBOOLEAN IsAFile
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines looks to see if a file or directory exists.
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies allx the information
|
||
|
||
Vcb - A pointer to the VCB for the remote drive.
|
||
|
||
Icb - A pointer to the ICB for the file we are looking for.
|
||
|
||
Name - Fully qualified name.
|
||
|
||
IsAFile - Returns TRUE is the found file is a file, FALSE if it is
|
||
a directory. Return nothing if the function returns FALSE.
|
||
|
||
Return Value:
|
||
|
||
IO_STATUS_BLOCK - Status of operation
|
||
|
||
--*/
|
||
{
|
||
ULONG Attributes;
|
||
ULONG FileSize;
|
||
USHORT LastModifiedDate;
|
||
USHORT LastModifiedTime;
|
||
USHORT CreationDate;
|
||
USHORT CreationTime = DEFAULT_TIME;
|
||
USHORT LastAccessDate;
|
||
NTSTATUS Status;
|
||
PFCB Fcb;
|
||
BOOLEAN FirstTime = TRUE;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// No need to send a packet if we are searching for the root of the volume.
|
||
//
|
||
|
||
if ( Name->Length == 0 ) {
|
||
*IsAFile = FALSE;
|
||
|
||
return( STATUS_SUCCESS );
|
||
}
|
||
|
||
//
|
||
// Decide how to handle this request. If we have an ICB, use the FCB
|
||
// to determine the file name type, otherwise we have to make the
|
||
// decision here.
|
||
//
|
||
|
||
if ( Icb != NULL &&
|
||
!BooleanFlagOn( Icb->SuperType.Fcb->Flags, FCB_FLAGS_LONG_NAME ) ||
|
||
|
||
Vcb->Specific.Disk.LongNameSpace == LFN_NO_OS2_NAME_SPACE ||
|
||
|
||
IsFatNameValid( Name ) ) {
|
||
Retry:
|
||
//
|
||
// First try a file
|
||
//
|
||
|
||
IrpContext->ResponseLength = 0;
|
||
|
||
Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"FwbbJ",
|
||
NCP_SEARCH_FILE,
|
||
-1,
|
||
Vcb->Specific.Disk.Handle,
|
||
SEARCH_ALL_FILES,
|
||
Name );
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"N==_b-dwwww",
|
||
14,
|
||
&Attributes,
|
||
&FileSize,
|
||
&CreationDate,
|
||
&LastAccessDate,
|
||
&LastModifiedDate,
|
||
&LastModifiedTime );
|
||
}
|
||
|
||
if ((Status == STATUS_INVALID_HANDLE) &&
|
||
(FirstTime)) {
|
||
|
||
//
|
||
// Check to see if Volume handle is invalid. Caused when volume
|
||
// is unmounted and then remounted.
|
||
//
|
||
|
||
FirstTime = FALSE;
|
||
|
||
NwReopenVcbHandle( IrpContext, Vcb );
|
||
|
||
goto Retry;
|
||
}
|
||
|
||
if ( Status == STATUS_UNSUCCESSFUL ) {
|
||
|
||
//
|
||
// Not a file, Is it a directory?
|
||
//
|
||
|
||
Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"FwbbJ",
|
||
NCP_SEARCH_FILE,
|
||
-1,
|
||
Vcb->Specific.Disk.Handle,
|
||
SEARCH_ALL_DIRECTORIES,
|
||
Name );
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"N==_b",
|
||
14,
|
||
&Attributes );
|
||
}
|
||
|
||
//
|
||
// If the exchange or ParseResponse fails then exit with not found
|
||
//
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
return( STATUS_OBJECT_NAME_NOT_FOUND );
|
||
}
|
||
|
||
*IsAFile = FALSE;
|
||
ASSERT( (Attributes & NW_ATTRIBUTE_DIRECTORY) != 0 );
|
||
|
||
} else {
|
||
|
||
if ( Status == STATUS_UNEXPECTED_NETWORK_ERROR &&
|
||
IrpContext->ResponseLength >= sizeof( NCP_RESPONSE ) ) {
|
||
|
||
//
|
||
// Work-around for netware bug. If netware returns short
|
||
// packet, just return success. We exit prematurely
|
||
// because we have no attributes to record.
|
||
//
|
||
|
||
Icb = NULL;
|
||
*IsAFile = TRUE;
|
||
return ( STATUS_SUCCESS );
|
||
}
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
return( Status );
|
||
}
|
||
|
||
*IsAFile = TRUE;
|
||
ASSERT( ( Attributes & NW_ATTRIBUTE_DIRECTORY ) == 0 );
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"LbbWDbDbC",
|
||
NCP_LFN_GET_INFO,
|
||
Vcb->Specific.Disk.LongNameSpace,
|
||
Vcb->Specific.Disk.LongNameSpace,
|
||
SEARCH_ALL_DIRECTORIES,
|
||
LFN_FLAG_INFO_ATTRIBUTES |
|
||
LFN_FLAG_INFO_FILE_SIZE |
|
||
LFN_FLAG_INFO_MODIFY_TIME |
|
||
LFN_FLAG_INFO_CREATION_TIME,
|
||
Vcb->Specific.Disk.VolumeNumber,
|
||
Vcb->Specific.Disk.Handle,
|
||
0,
|
||
Name );
|
||
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"N_e=e_xx_xx_x",
|
||
4,
|
||
&Attributes,
|
||
&FileSize,
|
||
6,
|
||
&CreationTime,
|
||
&CreationDate,
|
||
4,
|
||
&LastModifiedTime,
|
||
&LastModifiedDate,
|
||
4,
|
||
&LastAccessDate );
|
||
}
|
||
|
||
//
|
||
// If the exchange or ParseResponse fails then exit with not found
|
||
//
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
return( STATUS_OBJECT_NAME_NOT_FOUND );
|
||
}
|
||
|
||
if ( Attributes & NW_ATTRIBUTE_DIRECTORY) {
|
||
*IsAFile = FALSE;
|
||
} else {
|
||
*IsAFile = TRUE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If the caller supplied an ICB, update the FCB attributes.
|
||
// We'll use this info if the caller does a query attributes
|
||
// on the ICB.
|
||
//
|
||
|
||
if ( Icb != NULL && *IsAFile ) {
|
||
|
||
Fcb = Icb->SuperType.Fcb;
|
||
ASSERT( Fcb->NodeTypeCode == NW_NTC_FCB );
|
||
|
||
Fcb->NonPagedFcb->Attributes = (UCHAR)Attributes;
|
||
Fcb->NonPagedFcb->Header.FileSize.QuadPart = FileSize;
|
||
Fcb->LastModifiedDate = LastModifiedDate;
|
||
Fcb->LastModifiedTime = LastModifiedTime;
|
||
Fcb->CreationTime = CreationTime;
|
||
Fcb->CreationDate = CreationDate;
|
||
Fcb->LastAccessDate = LastAccessDate;
|
||
|
||
DebugTrace( 0, Dbg, "Attributes -> %08lx\n", Fcb->NonPagedFcb->Attributes );
|
||
DebugTrace( 0, Dbg, "FileSize.Low-> %08lx\n", Fcb->NonPagedFcb->Header.FileSize.LowPart );
|
||
DebugTrace( 0, Dbg, "ModifiedDate-> %08lx\n", Fcb->LastModifiedDate );
|
||
DebugTrace( 0, Dbg, "ModifiedTime-> %08lx\n", Fcb->LastModifiedTime );
|
||
DebugTrace( 0, Dbg, "CreationTime-> %08lx\n", Fcb->CreationTime );
|
||
DebugTrace( 0, Dbg, "CreationDate-> %08lx\n", Fcb->CreationDate );
|
||
DebugTrace( 0, Dbg, "LastAccDate -> %08lx\n", Fcb->LastAccessDate );
|
||
|
||
SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
|
||
}
|
||
|
||
return( STATUS_SUCCESS );
|
||
}
|
||
|
||
|
||
IO_STATUS_BLOCK
|
||
OpenFile(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PVCB Vcb,
|
||
IN PICB Icb,
|
||
IN BYTE Attributes,
|
||
IN BYTE OpenFlags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines sets opens a file on a netware server. It fails if
|
||
the file does not exist.
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies all the information
|
||
|
||
Vcb - A pointer to the VCB for the remote drive.
|
||
|
||
Icb - A pointer to the ICB we are opening.
|
||
|
||
Attributes - Open attributes.
|
||
|
||
OpenFlags - Open mode and sharing mode flags.
|
||
|
||
Return Value:
|
||
|
||
IO_STATUS_BLOCK - Status of operation
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK Iosb;
|
||
PFCB Fcb;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// No need to send a packet if we are trying to open the root of
|
||
// the volume as a file.
|
||
//
|
||
|
||
if ( Icb->SuperType.Fcb->RelativeFileName.Length == 0 ) {
|
||
Iosb.Status = STATUS_FILE_IS_A_DIRECTORY;
|
||
return( Iosb );
|
||
}
|
||
|
||
Fcb = Icb->SuperType.Fcb;
|
||
ASSERT( NodeType( Fcb ) == NW_NTC_FCB );
|
||
|
||
//
|
||
// Send the open request and wait for the response.
|
||
//
|
||
|
||
if ( !BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"FbbbJ",
|
||
NCP_OPEN_FILE,
|
||
Vcb->Specific.Disk.Handle,
|
||
SEARCH_ALL_FILES,
|
||
OpenFlags,
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
|
||
if ( ( ReadExecOnlyFiles ) &&
|
||
( !NT_SUCCESS( Iosb.Status ) ) ) {
|
||
|
||
//
|
||
// Retry the open with the appropriate flags for
|
||
// execute only files.
|
||
//
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"FbbbJ",
|
||
NCP_OPEN_FILE,
|
||
Vcb->Specific.Disk.Handle,
|
||
SEARCH_EXEC_ONLY_FILES,
|
||
OpenFlags,
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
}
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"Nr=_b-dwwww",
|
||
Icb->Handle,
|
||
sizeof( Icb->Handle ),
|
||
14,
|
||
&Fcb->NonPagedFcb->Attributes,
|
||
&Fcb->NonPagedFcb->Header.FileSize,
|
||
&Fcb->CreationDate,
|
||
&Fcb->LastAccessDate,
|
||
&Fcb->LastModifiedDate,
|
||
&Fcb->LastModifiedTime );
|
||
|
||
Fcb->CreationTime = DEFAULT_TIME;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"LbbWDDWbDbC",
|
||
NCP_LFN_OPEN_CREATE,
|
||
Vcb->Specific.Disk.LongNameSpace,
|
||
LFN_FLAG_OM_OPEN,
|
||
NW_ATTRIBUTE_HIDDEN | NW_ATTRIBUTE_SYSTEM, // Search Flags,
|
||
LFN_FLAG_INFO_ATTRIBUTES |
|
||
LFN_FLAG_INFO_FILE_SIZE |
|
||
LFN_FLAG_INFO_MODIFY_TIME |
|
||
LFN_FLAG_INFO_CREATION_TIME,
|
||
0, // Create attributes
|
||
OpenFlags, // Desired access
|
||
Vcb->Specific.Disk.VolumeNumber,
|
||
Vcb->Specific.Disk.Handle,
|
||
0, // Short directory flag
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
|
||
if ( ( ReadExecOnlyFiles ) &&
|
||
( !NT_SUCCESS( Iosb.Status ) ) ) {
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"LbbWDDWbDbC",
|
||
NCP_LFN_OPEN_CREATE,
|
||
Vcb->Specific.Disk.LongNameSpace,
|
||
LFN_FLAG_OM_OPEN,
|
||
NW_ATTRIBUTE_EXEC_ONLY,
|
||
LFN_FLAG_INFO_ATTRIBUTES |
|
||
LFN_FLAG_INFO_FILE_SIZE |
|
||
LFN_FLAG_INFO_MODIFY_TIME |
|
||
LFN_FLAG_INFO_CREATION_TIME,
|
||
0, // Create attributes
|
||
OpenFlags, // Desired access
|
||
Vcb->Specific.Disk.VolumeNumber,
|
||
Vcb->Specific.Disk.Handle,
|
||
0, // Short directory flag
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
}
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"Ne_e=e_xx_xx_x",
|
||
&Icb->Handle[2],
|
||
6,
|
||
&Fcb->NonPagedFcb->Attributes,
|
||
&Fcb->NonPagedFcb->Header.FileSize,
|
||
6,
|
||
&Fcb->CreationTime,
|
||
&Fcb->CreationDate,
|
||
4,
|
||
&Fcb->LastModifiedTime,
|
||
&Fcb->LastModifiedDate,
|
||
4,
|
||
&Fcb->LastAccessDate );
|
||
}
|
||
}
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
|
||
//
|
||
// NT does not allow you to open a read only file for write access.
|
||
// Netware does. To fake NT semantics, check to see if we should
|
||
// fail the open that the netware server just succeeded.
|
||
//
|
||
|
||
if ( ( Fcb->NonPagedFcb->Attributes & NW_ATTRIBUTE_READ_ONLY ) &&
|
||
( OpenFlags & NW_OPEN_FOR_WRITE ) ) {
|
||
|
||
CloseFile( IrpContext, Icb );
|
||
Iosb.Status = STATUS_ACCESS_DENIED;
|
||
}
|
||
|
||
SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
|
||
Icb->HasRemoteHandle = TRUE;
|
||
|
||
|
||
DebugTrace( 0, Dbg, "Attributes -> %08lx\n", Fcb->NonPagedFcb->Attributes );
|
||
DebugTrace( 0, Dbg, "FileSize.Low-> %08lx\n", Fcb->NonPagedFcb->Header.FileSize.LowPart );
|
||
DebugTrace( 0, Dbg, "ModifiedDate-> %08lx\n", Fcb->LastModifiedDate );
|
||
DebugTrace( 0, Dbg, "ModifiedTime-> %08lx\n", Fcb->LastModifiedTime );
|
||
DebugTrace( 0, Dbg, "CreationDate-> %08lx\n", Fcb->CreationDate );
|
||
DebugTrace( 0, Dbg, "CreationTime-> %08lx\n", Fcb->CreationTime );
|
||
DebugTrace( 0, Dbg, "LastAccDate -> %08lx\n", Fcb->LastAccessDate );
|
||
|
||
}
|
||
|
||
//
|
||
// Set information field assuming success. It will be ignored
|
||
// if the NCP failed.
|
||
//
|
||
|
||
Iosb.Information = FILE_OPENED;
|
||
|
||
if ( Iosb.Status == STATUS_UNSUCCESSFUL ) {
|
||
Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||
}
|
||
|
||
return( Iosb );
|
||
}
|
||
|
||
|
||
IO_STATUS_BLOCK
|
||
CreateNewFile(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PVCB Vcb,
|
||
IN PICB Icb,
|
||
IN BYTE CreateAttributes,
|
||
IN BYTE OpenFlags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines creates a new file on a netware server. It fails
|
||
if the file exists.
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies all the information
|
||
|
||
Vcb - A pointer to the VCB for the remote drive.
|
||
|
||
Icb - A pointer to the ICB we are opening.
|
||
|
||
CreateAttributes - Create attributes.
|
||
|
||
OpenFlags - Open mode and sharing mode flags.
|
||
|
||
Return Value:
|
||
|
||
IO_STATUS_BLOCK - Status of operation
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK Iosb;
|
||
PFCB Fcb;
|
||
UCHAR DelayedAttributes;
|
||
BOOLEAN CloseAndReopen;
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// If the user opens the file for shared access, then we will need to
|
||
// create the file close, then reopen it (since we have no NCP to say
|
||
// create with shared access). If the file is being created read-only,
|
||
// and the creator requests write access then we pull the additional
|
||
// trick of creating the file without the read-only, and set it later,
|
||
// so that the second open can succeed.
|
||
//
|
||
|
||
CloseAndReopen = FALSE;
|
||
DelayedAttributes = 0;
|
||
|
||
if ( OpenFlags != NW_OPEN_EXCLUSIVE ) {
|
||
CloseAndReopen = TRUE;
|
||
|
||
if ( ( CreateAttributes & NW_ATTRIBUTE_READ_ONLY ) &&
|
||
( OpenFlags & NW_OPEN_FOR_WRITE ) ) {
|
||
|
||
DelayedAttributes = CreateAttributes;
|
||
CreateAttributes = 0;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Send the create request and wait for the response.
|
||
//
|
||
|
||
Fcb = Icb->SuperType.Fcb;
|
||
|
||
if ( !BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
||
|
||
if (!IsFatNameValid(&Icb->SuperType.Fcb->RelativeFileName)) {
|
||
|
||
Iosb.Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
|
||
|
||
return( Iosb );
|
||
|
||
}
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"FbbJ", // NCP Create New File
|
||
NCP_CREATE_NEW_FILE,
|
||
Vcb->Specific.Disk.Handle,
|
||
CreateAttributes,
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"Nr=_b-dwwww",
|
||
Icb->Handle, sizeof( Icb->Handle ),
|
||
14,
|
||
&Fcb->NonPagedFcb->Attributes,
|
||
&Fcb->NonPagedFcb->Header.FileSize,
|
||
&Fcb->CreationDate,
|
||
&Fcb->LastAccessDate,
|
||
&Fcb->LastModifiedDate,
|
||
&Fcb->LastModifiedTime );
|
||
|
||
Fcb->CreationTime = DEFAULT_TIME;
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"LbbWDDWbDbC",
|
||
NCP_LFN_OPEN_CREATE,
|
||
Vcb->Specific.Disk.LongNameSpace,
|
||
LFN_FLAG_OM_CREATE,
|
||
0, // Search Flags
|
||
LFN_FLAG_INFO_ATTRIBUTES |
|
||
LFN_FLAG_INFO_FILE_SIZE |
|
||
LFN_FLAG_INFO_MODIFY_TIME |
|
||
LFN_FLAG_INFO_CREATION_TIME,
|
||
CreateAttributes,
|
||
0, // Desired access
|
||
Vcb->Specific.Disk.VolumeNumber,
|
||
Vcb->Specific.Disk.Handle,
|
||
0, // Short directory flag
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"Ne_e=e_xx_xx_x",
|
||
&Icb->Handle[2],
|
||
6,
|
||
&Fcb->NonPagedFcb->Attributes,
|
||
&Fcb->NonPagedFcb->Header.FileSize,
|
||
6,
|
||
&Fcb->CreationTime,
|
||
&Fcb->CreationDate,
|
||
4,
|
||
&Fcb->LastModifiedTime,
|
||
&Fcb->LastModifiedDate,
|
||
4,
|
||
&Fcb->LastAccessDate );
|
||
}
|
||
}
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
|
||
Icb->HasRemoteHandle = TRUE;
|
||
DebugTrace( 0, Dbg, "Attributes -> %08lx\n", Fcb->NonPagedFcb->Attributes );
|
||
DebugTrace( 0, Dbg, "FileSize.Low-> %08lx\n", Fcb->NonPagedFcb->Header.FileSize.LowPart );
|
||
DebugTrace( 0, Dbg, "ModifiedDate-> %08lx\n", Fcb->LastModifiedDate );
|
||
DebugTrace( 0, Dbg, "ModifiedTime-> %08lx\n", Fcb->LastModifiedTime );
|
||
DebugTrace( 0, Dbg, "CreationDate-> %08lx\n", Fcb->CreationDate );
|
||
DebugTrace( 0, Dbg, "CreationTime-> %08lx\n", Fcb->CreationTime );
|
||
DebugTrace( 0, Dbg, "LastAcceDate-> %08lx\n", Fcb->LastAccessDate );
|
||
}
|
||
|
||
if ( Iosb.Status == STATUS_UNSUCCESSFUL ) {
|
||
Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
|
||
}
|
||
|
||
if ( !NT_SUCCESS( Iosb.Status ) ) {
|
||
return( Iosb );
|
||
}
|
||
|
||
|
||
//
|
||
// We've created the file, and the users wants shared access to the
|
||
// file. Close the file and reopen in sharing mode.
|
||
//
|
||
|
||
if ( CloseAndReopen ) {
|
||
CloseFile( IrpContext, Icb );
|
||
Iosb = OpenFile( IrpContext, Vcb, Icb, CreateAttributes, OpenFlags );
|
||
}
|
||
|
||
//
|
||
// If we need to set attributes, do it now. Ignore errors, if any.
|
||
//
|
||
|
||
if ( DelayedAttributes != 0 ) {
|
||
|
||
ExchangeWithWait(
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"FbbbU",
|
||
NCP_SET_FILE_ATTRIBUTES,
|
||
DelayedAttributes,
|
||
Fcb->Vcb->Specific.Disk.Handle,
|
||
SEARCH_ALL_FILES,
|
||
&Fcb->RelativeFileName );
|
||
|
||
}
|
||
|
||
//
|
||
// Set information field assuming success. It will be ignored
|
||
// if the NCP failed.
|
||
//
|
||
|
||
Iosb.Information = FILE_CREATED;
|
||
return( Iosb );
|
||
}
|
||
|
||
|
||
IO_STATUS_BLOCK
|
||
CreateOrOverwriteFile(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PVCB Vcb,
|
||
IN PICB Icb,
|
||
IN BYTE CreateAttributes,
|
||
IN BYTE OpenFlags,
|
||
IN BOOLEAN CreateOperation
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines creates a file on a netware server. If the file
|
||
exists it is overwritten.
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies all the information
|
||
|
||
Vcb - A pointer to the VCB for the remote drive.
|
||
|
||
Icb - A pointer to the ICB we are opening.
|
||
|
||
Attributes - Open attributes.
|
||
|
||
OpenFlags - Open mode and sharing mode flags.
|
||
|
||
Return Value:
|
||
|
||
IO_STATUS_BLOCK - Status of operation
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK Iosb;
|
||
PFCB Fcb;
|
||
UCHAR DelayedAttributes;
|
||
BOOLEAN CloseAndReopen;
|
||
|
||
PAGED_CODE();
|
||
|
||
Fcb = Icb->SuperType.Fcb;
|
||
|
||
//
|
||
// Send the request and wait for the response.
|
||
//
|
||
|
||
if ( !BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
||
|
||
if (!IsFatNameValid(&Icb->SuperType.Fcb->RelativeFileName)) {
|
||
|
||
Iosb.Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
|
||
|
||
return( Iosb );
|
||
|
||
}
|
||
|
||
//
|
||
// If the user opens the file for shared access, then we will need to
|
||
// create the file close, then reopen it (since we have no NCP to say
|
||
// create with shared access). If the file is being created read-only,
|
||
// and the creator requests write access then we pull the additional
|
||
// trick of creating the file without the read-only, and set it later,
|
||
// so that the second open can succeed.
|
||
//
|
||
|
||
if ( ( CreateAttributes & NW_ATTRIBUTE_READ_ONLY ) &&
|
||
( OpenFlags & NW_OPEN_FOR_WRITE ) ) {
|
||
|
||
DelayedAttributes = CreateAttributes;
|
||
CreateAttributes = 0;
|
||
} else {
|
||
DelayedAttributes = 0;
|
||
}
|
||
|
||
//
|
||
// Dos namespace create always returns the file exclusive.
|
||
//
|
||
|
||
if (!FlagOn(OpenFlags, NW_OPEN_EXCLUSIVE)) {
|
||
CloseAndReopen = TRUE;
|
||
} else {
|
||
CloseAndReopen = FALSE;
|
||
}
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"FbbJ",
|
||
NCP_CREATE_FILE,
|
||
Vcb->Specific.Disk.Handle,
|
||
CreateAttributes,
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"Nr=_b-dwwww",
|
||
Icb->Handle,
|
||
sizeof( Icb->Handle ),
|
||
14,
|
||
&Fcb->NonPagedFcb->Attributes,
|
||
&Fcb->NonPagedFcb->Header.FileSize,
|
||
&Fcb->CreationDate,
|
||
&Fcb->LastAccessDate,
|
||
&Fcb->LastModifiedDate,
|
||
&Fcb->LastModifiedTime );
|
||
|
||
Fcb->CreationTime = DEFAULT_TIME;
|
||
|
||
}
|
||
|
||
//
|
||
// We've created the file, and the users wants shared access to the
|
||
// file. Close the file and reopen in sharing mode.
|
||
//
|
||
|
||
if (( NT_SUCCESS( Iosb.Status ) ) &&
|
||
( CloseAndReopen )) {
|
||
|
||
CloseFile( IrpContext, Icb );
|
||
Iosb = OpenFile( IrpContext, Vcb, Icb, CreateAttributes, OpenFlags );
|
||
}
|
||
|
||
if ( DelayedAttributes != 0 ) {
|
||
ExchangeWithWait(
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"FbbbU",
|
||
NCP_SET_FILE_ATTRIBUTES,
|
||
DelayedAttributes,
|
||
Fcb->Vcb->Specific.Disk.Handle,
|
||
SEARCH_ALL_FILES,
|
||
&Fcb->RelativeFileName );
|
||
}
|
||
|
||
} else {
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"LbbWDDWbDbC",
|
||
NCP_LFN_OPEN_CREATE,
|
||
Vcb->Specific.Disk.LongNameSpace,
|
||
LFN_FLAG_OM_OVERWRITE,
|
||
0, // Search Flags
|
||
LFN_FLAG_INFO_ATTRIBUTES |
|
||
LFN_FLAG_INFO_FILE_SIZE |
|
||
LFN_FLAG_INFO_MODIFY_TIME |
|
||
LFN_FLAG_INFO_CREATION_TIME,
|
||
CreateAttributes,
|
||
OpenFlags, // DesiredAccess
|
||
Vcb->Specific.Disk.VolumeNumber,
|
||
Vcb->Specific.Disk.Handle,
|
||
0, // Short directory flag
|
||
&Icb->SuperType.Fcb->RelativeFileName );
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"Ne_e=e_xx_xx_x",
|
||
&Icb->Handle[2],
|
||
6,
|
||
&Fcb->NonPagedFcb->Attributes,
|
||
&Fcb->NonPagedFcb->Header.FileSize,
|
||
6,
|
||
&Fcb->CreationTime,
|
||
&Fcb->CreationDate,
|
||
4,
|
||
&Fcb->LastModifiedTime,
|
||
&Fcb->LastModifiedDate,
|
||
4,
|
||
&Fcb->LastAccessDate );
|
||
}
|
||
}
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
|
||
Icb->HasRemoteHandle = TRUE;
|
||
DebugTrace( 0, Dbg, "Attributes -> %08lx\n", Fcb->NonPagedFcb->Attributes );
|
||
DebugTrace( 0, Dbg, "FileSize.Low-> %08lx\n", Fcb->NonPagedFcb->Header.FileSize.LowPart );
|
||
DebugTrace( 0, Dbg, "ModifiedDate-> %08lx\n", Fcb->LastModifiedDate );
|
||
DebugTrace( 0, Dbg, "ModifiedTime-> %08lx\n", Fcb->LastModifiedTime );
|
||
DebugTrace( 0, Dbg, "CreationDate-> %08lx\n", Fcb->CreationDate );
|
||
DebugTrace( 0, Dbg, "CreationTime-> %08lx\n", Fcb->CreationTime );
|
||
DebugTrace( 0, Dbg, "LastAccDate -> %08lx\n", Fcb->LastAccessDate );
|
||
} else {
|
||
return( Iosb );
|
||
}
|
||
|
||
//
|
||
// Set information field assuming success. It will be ignored
|
||
// if the NCP failed.
|
||
//
|
||
|
||
if ( CreateOperation) {
|
||
Iosb.Information = FILE_CREATED;
|
||
} else {
|
||
Iosb.Information = FILE_OVERWRITTEN;
|
||
}
|
||
|
||
return( Iosb );
|
||
}
|
||
|
||
|
||
IO_STATUS_BLOCK
|
||
OpenRenameTarget(
|
||
IN PIRP_CONTEXT IrpContext,
|
||
IN PVCB Vcb,
|
||
IN PDCB Dcb,
|
||
IN PICB* Icb
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens a directory. If the filename provided specifies
|
||
a directory then the file/directory to be renamed will be put in this
|
||
directory.
|
||
|
||
If the target foo\bar does not exist or is a file then the source of
|
||
the rename must be a file and will end up in the directory foo with
|
||
the name bar
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies all the information
|
||
|
||
Vcb - A pointer to the VCB for the remote drive.
|
||
|
||
Dcb - A pointer to the DCB for relative opens. If NULL the FileName
|
||
is an full path name. If non NUL the FileName is relative to
|
||
this directory.
|
||
|
||
Icb - A pointer to where the address of the Icb is to be stored.
|
||
|
||
Return Value:
|
||
|
||
NT_STATUS - Status of operation
|
||
|
||
--*/
|
||
{
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
|
||
IO_STATUS_BLOCK Iosb;
|
||
PFCB Fcb;
|
||
BOOLEAN FullNameIsAFile;
|
||
BOOLEAN FullNameExists;
|
||
BOOLEAN PathIsAFile;
|
||
|
||
#if 0
|
||
UNICODE_STRING Drive;
|
||
WCHAR DriveLetter;
|
||
UNICODE_STRING Server;
|
||
UNICODE_STRING Volume;
|
||
UNICODE_STRING FileName;
|
||
#endif
|
||
UNICODE_STRING Path;
|
||
UNICODE_STRING FullName;
|
||
UNICODE_STRING CompleteName;
|
||
UNICODE_STRING VcbName;
|
||
PWCH pTrailingSlash;
|
||
|
||
USHORT i;
|
||
USHORT DcbNameLength;
|
||
|
||
PAGED_CODE();
|
||
|
||
DebugTrace(+1, Dbg, "OpenRenameTarget\n", 0);
|
||
|
||
//
|
||
// Get the current IRP stack location
|
||
//
|
||
|
||
Irp = IrpContext->pOriginalIrp;
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
//
|
||
// Build a complete filename of the form \g:\server\volume\dir1\file
|
||
//
|
||
|
||
if ( Dcb != NULL ) {
|
||
|
||
//
|
||
// Strip to UID portion of the DCB name.
|
||
//
|
||
|
||
for ( i = 0 ; i < Dcb->FullFileName.Length / sizeof(WCHAR) ; i++ ) {
|
||
if ( Dcb->FullFileName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
ASSERT( Dcb->FullFileName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR );
|
||
|
||
//
|
||
// Now build the full name by appending the file name to the DCB name.
|
||
//
|
||
|
||
DcbNameLength = Dcb->FullFileName.Length - ( i * sizeof(WCHAR) );
|
||
CompleteName.Length = DcbNameLength + IrpSp->FileObject->FileName.Length + sizeof( WCHAR);
|
||
CompleteName.MaximumLength = CompleteName.Length;
|
||
CompleteName.Buffer = ALLOCATE_POOL_EX( PagedPool, CompleteName.Length );
|
||
|
||
RtlCopyMemory(
|
||
CompleteName.Buffer,
|
||
Dcb->FullFileName.Buffer + i,
|
||
DcbNameLength );
|
||
|
||
CompleteName.Buffer[ DcbNameLength / sizeof(WCHAR) ] = L'\\';
|
||
|
||
RtlCopyMemory(
|
||
CompleteName.Buffer + DcbNameLength / sizeof(WCHAR ) + 1,
|
||
IrpSp->FileObject->FileName.Buffer,
|
||
IrpSp->FileObject->FileName.Length );
|
||
|
||
Dcb = NULL;
|
||
|
||
} else {
|
||
|
||
CompleteName = IrpSp->FileObject->FileName;
|
||
|
||
}
|
||
|
||
//
|
||
// Calculate the VCB name, without the UID prefix.
|
||
//
|
||
|
||
VcbName.Buffer = wcschr( Vcb->Name.Buffer, L'\\' );
|
||
VcbName.Length = (USHORT) (Vcb->Name.Length -
|
||
( (PCHAR)VcbName.Buffer - (PCHAR)Vcb->Name.Buffer ));
|
||
|
||
//
|
||
// Calculate the target relative name. This is simply the complete
|
||
// name minus the VcbName and the leading backslash.
|
||
//
|
||
|
||
FullName.Buffer = CompleteName.Buffer + ( VcbName.Length / sizeof(WCHAR) ) + 1;
|
||
FullName.Length = (USHORT) (CompleteName.Length -
|
||
( (PCHAR)FullName.Buffer - (PCHAR)CompleteName.Buffer ));
|
||
|
||
//
|
||
// Calculate the target directory relative name. This the the target
|
||
// full name, minus the last component of the name.
|
||
//
|
||
|
||
pTrailingSlash = FullName.Buffer + FullName.Length / sizeof(WCHAR) - 1;
|
||
for ( i = 0; i < FullName.Length ; i += sizeof(WCHAR) ) {
|
||
if ( *pTrailingSlash == L'\\' ) {
|
||
break;
|
||
}
|
||
--pTrailingSlash;
|
||
}
|
||
|
||
|
||
Path.Buffer = FullName.Buffer;
|
||
|
||
if ( i == FullName.Length ) {
|
||
|
||
//
|
||
// If no trailing slash was found, the the target path is the
|
||
// root directory.
|
||
//
|
||
|
||
Path.Length = 0;
|
||
|
||
} else {
|
||
|
||
Path.Length = (USHORT) ((PCHAR)pTrailingSlash - (PCHAR)FullName.Buffer);
|
||
|
||
}
|
||
|
||
#if 0
|
||
Iosb.Status = CrackPath(
|
||
&CompleteName,
|
||
&Drive,
|
||
&DriveLetter,
|
||
&Server,
|
||
&Volume,
|
||
&Path,
|
||
&FileName,
|
||
&FullName );
|
||
#endif
|
||
|
||
Iosb.Status = FileOrDirectoryExists( IrpContext,
|
||
Vcb,
|
||
NULL,
|
||
&Path,
|
||
&PathIsAFile );
|
||
|
||
if ( !NT_SUCCESS( Iosb.Status) ) {
|
||
|
||
// The directory containing the file does not exist
|
||
|
||
return(Iosb);
|
||
}
|
||
|
||
Iosb.Status = FileOrDirectoryExists( IrpContext,
|
||
Vcb,
|
||
NULL,
|
||
&FullName,
|
||
&FullNameIsAFile );
|
||
|
||
if ( !NT_SUCCESS( Iosb.Status ) ) {
|
||
FullNameExists = FALSE;
|
||
Iosb.Information = FILE_DOES_NOT_EXIST;
|
||
} else {
|
||
FullNameExists = TRUE;
|
||
Iosb.Information = 0;
|
||
}
|
||
|
||
DebugTrace( 0, Dbg, "FullNameExists = %08lx\n", FullNameExists);
|
||
DebugTrace( 0, Dbg, "FullNameIsAFile = %08lx\n", FullNameIsAFile);
|
||
|
||
try {
|
||
UNICODE_STRING TargetPath;
|
||
|
||
//
|
||
// Find the FCB for this file. If the FCB exists, we get a
|
||
// referenced pointer. Otherwise a new FCB is created.
|
||
// The file is the complete path minus the target filename.
|
||
//
|
||
|
||
TargetPath = CompleteName;
|
||
|
||
Fcb = NwFindFcb( IrpContext->pScb, Vcb, &TargetPath, Dcb );
|
||
// in rare cases, NwFindFcb might return NULL instead of throwing an exception
|
||
// Raid # 432500
|
||
if (Fcb == NULL) {
|
||
DebugTrace(0, Dbg, "NwFindFcb returned NULL in OpenRenameTarget\n", 0);
|
||
Iosb.Status = STATUS_INVALID_PARAMETER;
|
||
try_return( Iosb );
|
||
}
|
||
|
||
//
|
||
// Now create the ICB.
|
||
//
|
||
|
||
*Icb = NwCreateIcb( NW_NTC_ICB, Fcb );
|
||
|
||
(*Icb)->FileObject = IrpSp->FileObject;
|
||
NwSetFileObject( IrpSp->FileObject, Fcb->NonPagedFcb, *Icb );
|
||
(*Icb)->Exists = FullNameExists;
|
||
(*Icb)->IsAFile = FullNameIsAFile;
|
||
|
||
try_return(Iosb.Status = STATUS_SUCCESS);
|
||
|
||
try_exit: NOTHING;
|
||
|
||
} finally {
|
||
|
||
|
||
if ( AbnormalTermination() || !NT_SUCCESS( Iosb.Status ) ) {
|
||
|
||
//
|
||
// Failed to create
|
||
//
|
||
|
||
if ( *Icb != NULL ) {
|
||
NwDeleteIcb( NULL, *Icb );
|
||
*Icb = NULL;
|
||
}
|
||
}
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "OpenRenameTarget\n", Iosb.Status);
|
||
|
||
return( Iosb );
|
||
}
|
||
|
||
|
||
IO_STATUS_BLOCK
|
||
CreatePrintJob(
|
||
PIRP_CONTEXT IrpContext,
|
||
PVCB Vcb,
|
||
PICB Icb,
|
||
PUNICODE_STRING DriveName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines create a new directory.
|
||
|
||
Arguments:
|
||
|
||
IrpContext - Supplies all the information
|
||
|
||
Vcb - A pointer to the VCB for the remote print queue.
|
||
|
||
Icb - A pointer to the newly created ICB.
|
||
|
||
DriveName - LPTx
|
||
|
||
Return Value:
|
||
|
||
IO_STATUS_BLOCK - Status of operation
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK Iosb;
|
||
PFCB Fcb;
|
||
ANSI_STRING ODriveName;
|
||
static CHAR LptName[] = "LPT" ;
|
||
ULONG PrintOptions;
|
||
PLOGON Logon;
|
||
PUNICODE_STRING BannerName;
|
||
|
||
PAGED_CODE();
|
||
|
||
BannerName = &IrpContext->pScb->UserName;
|
||
NwAcquireExclusiveRcb( &NwRcb, TRUE );
|
||
Logon = FindUser( &IrpContext->pScb->UserUid, TRUE );
|
||
if ( Logon == NULL ) {
|
||
PrintOptions = NwPrintOptions;
|
||
} else {
|
||
PrintOptions = Logon->NwPrintOptions;
|
||
/*
|
||
* If user name is GUEST, use the validated user name
|
||
*/
|
||
if ((BannerName->Length == 0 ) ||
|
||
(RtlCompareUnicodeString( BannerName, &Guest.UserName, TRUE ) == 0 )) {
|
||
BannerName = &Logon->UserName;
|
||
}
|
||
}
|
||
NwReleaseRcb( &NwRcb );
|
||
|
||
//
|
||
// Make sure the print queue name is correct.
|
||
//
|
||
|
||
if ( Icb->SuperType.Fcb->RelativeFileName.Length != 0 ) {
|
||
Iosb.Status = STATUS_OBJECT_PATH_SYNTAX_BAD;
|
||
return( Iosb );
|
||
}
|
||
|
||
//
|
||
// Send a create queue job packet, and wait the response.
|
||
//
|
||
|
||
if ((DriveName->Length == 0 ) ||
|
||
(!NT_SUCCESS(RtlUnicodeStringToOemString( &ODriveName, DriveName, TRUE )))) {
|
||
//
|
||
// if we dont have a name, use the string "LPT". we do this because
|
||
// some printers insist on a name.
|
||
//
|
||
|
||
RtlInitString(&ODriveName, LptName);
|
||
}
|
||
|
||
|
||
Iosb.Status = ExchangeWithWait (
|
||
IrpContext,
|
||
SynchronousResponseCallback,
|
||
"Sd_ddw_b_r_bbwwww_x-x_", // Format string
|
||
NCP_ADMIN_FUNCTION, NCP_CREATE_QUEUE_JOB,
|
||
Vcb->Specific.Print.QueueId,// Queue ID
|
||
6, // Skip bytes
|
||
0xffffffff, // Target Server ID number
|
||
0xffffffff, 0xffff, // Target Execution time
|
||
11, // Skip bytes
|
||
0x00, // Job Control Flags
|
||
26, // Skip bytes
|
||
ODriveName.Buffer, ODriveName.Length, // Description
|
||
50 - ODriveName.Length , // Description pad
|
||
0, // Version number
|
||
8, // Tab Size
|
||
1, // Number of copies
|
||
PrintOptions, // Control Flags
|
||
0x3C, // Maximum lines
|
||
0x84, // Maximum characters
|
||
22, // Skip bytes
|
||
BannerName, 13, // Banner Name
|
||
&Vcb->ShareName, 12, // Header Name
|
||
1+14+80 // null last string & skip rest of client area
|
||
);
|
||
|
||
|
||
//
|
||
// free the string if it was allocated
|
||
//
|
||
if (ODriveName.Buffer != LptName)
|
||
RtlFreeAnsiString(&ODriveName);
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
Iosb.Status = ParseResponse(
|
||
IrpContext,
|
||
IrpContext->rsp,
|
||
IrpContext->ResponseLength,
|
||
"N_w_r",
|
||
22,
|
||
&Icb->JobId,
|
||
18,
|
||
Icb->Handle, sizeof(Icb->Handle) );
|
||
|
||
}
|
||
|
||
if ( NT_SUCCESS( Iosb.Status ) ) {
|
||
|
||
Fcb = Icb->SuperType.Fcb;
|
||
|
||
Fcb->NonPagedFcb->Attributes = 0;
|
||
Fcb->CreationDate = 0;
|
||
Fcb->LastAccessDate = 0;
|
||
Fcb->LastModifiedDate = 0;
|
||
Fcb->LastModifiedTime = 0;
|
||
|
||
Icb->HasRemoteHandle = TRUE;
|
||
Icb->IsPrintJob = TRUE;
|
||
Icb->ActuallyPrinted = FALSE;
|
||
|
||
SetFlag( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID );
|
||
|
||
}
|
||
|
||
//
|
||
// Set information field assuming success. It will be ignored
|
||
// if the NCP failed.
|
||
//
|
||
|
||
Iosb.Information = FILE_CREATED;
|
||
|
||
if ( Iosb.Status == STATUS_UNSUCCESSFUL ) {
|
||
Iosb.Status = STATUS_OBJECT_NAME_COLLISION;
|
||
}
|
||
|
||
|
||
return( Iosb );
|
||
}
|
||
|
||
VOID
|
||
CloseFile(
|
||
PIRP_CONTEXT pIrpContext,
|
||
PICB pIcb
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routines closes an opened file.
|
||
|
||
Arguments:
|
||
|
||
pIrpContext - Supplies all the information
|
||
|
||
pIcb - A pointer to the newly created ICB.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
PAGED_CODE();
|
||
|
||
ExchangeWithWait(
|
||
pIrpContext,
|
||
SynchronousResponseCallback,
|
||
"F-r",
|
||
NCP_CLOSE,
|
||
pIcb->Handle, 6 );
|
||
}
|
||
|