mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3648 lines
107 KiB
3648 lines
107 KiB
/*++
|
|
|
|
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 );
|
|
}
|
|
|