|
|
/*++
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 ); }
|