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.
3072 lines
81 KiB
3072 lines
81 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
fileinfo.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the get / set file information routines for
|
|
Netware Redirector.
|
|
|
|
Author:
|
|
|
|
Manny Weiser (mannyw) 4-Mar-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "procs.h"
|
|
|
|
//
|
|
// The debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_FILEINFO)
|
|
|
|
//
|
|
// local procedure prototypes
|
|
//
|
|
|
|
NTSTATUS
|
|
NwCommonQueryInformation (
|
|
IN PIRP_CONTEXT pIrpContext
|
|
);
|
|
|
|
NTSTATUS
|
|
NwCommonSetInformation (
|
|
IN PIRP_CONTEXT pIrpContet
|
|
);
|
|
|
|
NTSTATUS
|
|
NwQueryBasicInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_BASIC_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NwQueryStandardInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_STANDARD_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NwQueryInternalInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_INTERNAL_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NwQueryEaInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_EA_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NwQueryNameInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_NAME_INFORMATION Buffer,
|
|
IN OUT PULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
NwQueryAltNameInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_NAME_INFORMATION Buffer,
|
|
IN OUT PULONG Length
|
|
);
|
|
|
|
NTSTATUS
|
|
NwQueryPositionInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_POSITION_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NwSetBasicInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_BASIC_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NwSetDispositionInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_DISPOSITION_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NwSetRenameInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_RENAME_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NwSetPositionInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_POSITION_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NwSetAllocationInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_ALLOCATION_INFORMATION Buffer
|
|
);
|
|
|
|
NTSTATUS
|
|
NwSetEndOfFileInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_END_OF_FILE_INFORMATION Buffer
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, NwFsdQueryInformation )
|
|
#pragma alloc_text( PAGE, NwFsdSetInformation )
|
|
#pragma alloc_text( PAGE, NwCommonQueryInformation )
|
|
#pragma alloc_text( PAGE, NwCommonSetInformation )
|
|
#pragma alloc_text( PAGE, NwQueryStandardInfo )
|
|
#pragma alloc_text( PAGE, NwQueryInternalInfo )
|
|
#pragma alloc_text( PAGE, NwQueryEaInfo )
|
|
#pragma alloc_text( PAGE, NwQueryNameInfo )
|
|
#pragma alloc_text( PAGE, NwQueryPositionInfo )
|
|
#pragma alloc_text( PAGE, NwSetBasicInfo )
|
|
#pragma alloc_text( PAGE, NwSetDispositionInfo )
|
|
#pragma alloc_text( PAGE, NwDeleteFile )
|
|
#pragma alloc_text( PAGE, NwSetRenameInfo )
|
|
#pragma alloc_text( PAGE, NwSetPositionInfo )
|
|
#pragma alloc_text( PAGE, NwSetAllocationInfo )
|
|
#pragma alloc_text( PAGE, NwSetEndOfFileInfo )
|
|
#pragma alloc_text( PAGE, OccurenceCount )
|
|
|
|
#ifndef QFE_BUILD
|
|
#pragma alloc_text( PAGE1, NwQueryBasicInfo )
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if 0 // Not pageable
|
|
|
|
// see ifndef QFE_BUILD above
|
|
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
NwFsdQueryInformation (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the FSD part of the NtQueryInformationFile API
|
|
calls.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies a pointer to the device object to use.
|
|
|
|
Irp - Supplies a pointer to the Irp to process.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The Fsd status for the Irp
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PIRP_CONTEXT pIrpContext = NULL;
|
|
BOOLEAN TopLevel;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(+1, Dbg, "NwFsdQueryInformation\n", 0);
|
|
|
|
//
|
|
// Call the common query information routine.
|
|
//
|
|
|
|
FsRtlEnterFileSystem();
|
|
TopLevel = NwIsIrpTopLevel( Irp );
|
|
|
|
try {
|
|
|
|
pIrpContext = AllocateIrpContext( Irp );
|
|
status = NwCommonQueryInformation( pIrpContext );
|
|
|
|
} except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
|
|
|
|
if ( pIrpContext == 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( pIrpContext, GetExceptionCode() );
|
|
}
|
|
}
|
|
|
|
if ( pIrpContext ) {
|
|
|
|
if ( status != STATUS_PENDING ) {
|
|
NwDequeueIrpContext( pIrpContext, FALSE );
|
|
}
|
|
|
|
NwCompleteRequest( pIrpContext, status );
|
|
}
|
|
|
|
if ( TopLevel ) {
|
|
NwSetTopLevelIrp( NULL );
|
|
}
|
|
FsRtlExitFileSystem();
|
|
|
|
//
|
|
// Return to the caller.
|
|
//
|
|
|
|
DebugTrace(-1, Dbg, "NwFsdQueryInformation -> %08lx\n", status );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwFsdSetInformation (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the FSD part of the NtSetInformationFile API
|
|
calls.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies the device object to use.
|
|
|
|
Irp - Supplies the Irp being processed
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The Fsd status for the Irp
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PIRP_CONTEXT pIrpContext = NULL;
|
|
BOOLEAN TopLevel;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(+1, Dbg, "NwFsdSetInformation\n", 0);
|
|
|
|
//
|
|
// Call the common Set Information routine.
|
|
//
|
|
|
|
FsRtlEnterFileSystem();
|
|
TopLevel = NwIsIrpTopLevel( Irp );
|
|
|
|
try {
|
|
|
|
pIrpContext = AllocateIrpContext( Irp );
|
|
status = NwCommonSetInformation( pIrpContext );
|
|
|
|
} except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
|
|
|
|
if ( pIrpContext == 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( pIrpContext, GetExceptionCode() );
|
|
}
|
|
|
|
}
|
|
|
|
if ( pIrpContext ) {
|
|
|
|
if ( status != STATUS_PENDING ) {
|
|
NwDequeueIrpContext( pIrpContext, FALSE );
|
|
}
|
|
|
|
NwCompleteRequest( pIrpContext, status );
|
|
}
|
|
|
|
if ( TopLevel ) {
|
|
NwSetTopLevelIrp( NULL );
|
|
}
|
|
FsRtlExitFileSystem();
|
|
|
|
//
|
|
// Return to the caller.
|
|
//
|
|
|
|
DebugTrace(-1, Dbg, "NwFsdSetInformation -> %08lx\n", status );
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwCommonQueryInformation (
|
|
IN PIRP_CONTEXT pIrpContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common routine for querying information on a file.
|
|
|
|
Arguments:
|
|
|
|
pIrpContext - Supplies Irp context information.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - the return status for the operation.
|
|
|
|
--*/
|
|
{
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
|
|
ULONG length;
|
|
FILE_INFORMATION_CLASS fileInformationClass;
|
|
PVOID buffer;
|
|
|
|
NODE_TYPE_CODE nodeTypeCode;
|
|
PICB icb;
|
|
PFCB fcb;
|
|
|
|
PVOID fsContext, fsContext2;
|
|
|
|
PFILE_ALL_INFORMATION AllInfo;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Get the current stack location.
|
|
//
|
|
|
|
Irp = pIrpContext->pOriginalIrp;
|
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
DebugTrace(+1, Dbg, "NwCommonQueryInformation...\n", 0);
|
|
DebugTrace( 0, Dbg, " Irp = %08lx\n", (ULONG_PTR)Irp);
|
|
DebugTrace( 0, Dbg, " ->Length = %08lx\n", irpSp->Parameters.QueryFile.Length);
|
|
DebugTrace( 0, Dbg, " ->FileInformationClass = %08lx\n", irpSp->Parameters.QueryFile.FileInformationClass);
|
|
DebugTrace( 0, Dbg, " ->Buffer = %08lx\n", (ULONG_PTR)Irp->AssociatedIrp.SystemBuffer);
|
|
|
|
//
|
|
// Find out who are.
|
|
//
|
|
|
|
if ((nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
|
|
&fsContext,
|
|
&fsContext2 )) == NTC_UNDEFINED) {
|
|
|
|
status = STATUS_INVALID_HANDLE;
|
|
|
|
DebugTrace(-1, Dbg, "NwCommonQueryInformation -> %08lx\n", status );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Make sure that this the user is querying an ICB.
|
|
//
|
|
|
|
switch (nodeTypeCode) {
|
|
|
|
case NW_NTC_ICB:
|
|
|
|
icb = (PICB)fsContext2;
|
|
break;
|
|
|
|
default: // This is an illegal file object to query
|
|
|
|
DebugTrace(0, Dbg, "Node type code is not incorrect\n", 0);
|
|
|
|
DebugTrace(-1, Dbg, "NwCommonQueryInformation -> STATUS_INVALID_PARAMETER\n", 0);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
pIrpContext->Icb = icb;
|
|
|
|
//
|
|
// Make local copies of the input parameters.
|
|
//
|
|
|
|
length = irpSp->Parameters.QueryFile.Length;
|
|
fileInformationClass = irpSp->Parameters.QueryFile.FileInformationClass;
|
|
buffer = Irp->AssociatedIrp.SystemBuffer;
|
|
|
|
//
|
|
// Now acquire shared access to the FCB
|
|
//
|
|
|
|
fcb = icb->SuperType.Fcb;
|
|
|
|
try {
|
|
|
|
NwVerifyIcbSpecial( icb );
|
|
|
|
//
|
|
// Based on the information class we'll do different actions. Each
|
|
// of the procedure that we're calling fill up as much of the
|
|
// buffer as possible and return the remaining length, and status
|
|
// This is done so that we can use them to build up the
|
|
// FileAllInformation request. These procedures do not complete the
|
|
// IRP, instead this procedure must complete the IRP.
|
|
//
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
switch (fileInformationClass) {
|
|
|
|
case FileAllInformation:
|
|
|
|
AllInfo = buffer;
|
|
|
|
//
|
|
// First call all the Query Info handlers we can call
|
|
// synchronously.
|
|
//
|
|
|
|
NwQueryInternalInfo( pIrpContext, icb, &AllInfo->InternalInformation );
|
|
NwQueryEaInfo( pIrpContext, &AllInfo->EaInformation );
|
|
NwQueryPositionInfo( pIrpContext, icb, &AllInfo->PositionInformation );
|
|
|
|
length -= FIELD_OFFSET( FILE_ALL_INFORMATION, NameInformation );
|
|
|
|
status = NwQueryNameInfo( pIrpContext, icb, &AllInfo->NameInformation, &length );
|
|
|
|
if ( !NT_ERROR( status ) ) {
|
|
status = NwQueryStandardInfo( pIrpContext, icb, &AllInfo->StandardInformation );
|
|
}
|
|
|
|
if ( !NT_ERROR( status ) ) {
|
|
status = NwQueryBasicInfo( pIrpContext, icb, &AllInfo->BasicInformation );
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
case FileBasicInformation:
|
|
|
|
length -= sizeof( FILE_BASIC_INFORMATION );
|
|
status = NwQueryBasicInfo( pIrpContext, icb, buffer );
|
|
|
|
break;
|
|
|
|
case FileStandardInformation:
|
|
|
|
//
|
|
// We will handle this call for information asynchronously.
|
|
// The callback routine will fill in the missing data, and
|
|
// complete the IRP.
|
|
//
|
|
// Remember the buffer length, and status to return.
|
|
//
|
|
|
|
length -= sizeof( FILE_STANDARD_INFORMATION );
|
|
status = NwQueryStandardInfo( pIrpContext, icb, buffer );
|
|
break;
|
|
|
|
case FileInternalInformation:
|
|
|
|
status = NwQueryInternalInfo( pIrpContext, icb, buffer );
|
|
length -= sizeof( FILE_INTERNAL_INFORMATION );
|
|
break;
|
|
|
|
case FileEaInformation:
|
|
|
|
status = NwQueryEaInfo( pIrpContext, buffer );
|
|
length -= sizeof( FILE_EA_INFORMATION );
|
|
break;
|
|
|
|
case FilePositionInformation:
|
|
|
|
status = NwQueryPositionInfo( pIrpContext, icb, buffer );
|
|
length -= sizeof( FILE_POSITION_INFORMATION );
|
|
break;
|
|
|
|
case FileNameInformation:
|
|
|
|
status = NwQueryNameInfo( pIrpContext, icb, buffer, &length );
|
|
break;
|
|
|
|
case FileAlternateNameInformation:
|
|
|
|
if (!DisableAltFileName) {
|
|
status = NwQueryAltNameInfo( pIrpContext, icb, buffer, &length);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Set the information field to the number of bytes actually
|
|
// filled in and then complete the request. (This is
|
|
// irrelavent if the Query worker function returned
|
|
// STATUS_PENDING).
|
|
//
|
|
|
|
if ( status != STATUS_PENDING ) {
|
|
Irp->IoStatus.Information =
|
|
irpSp->Parameters.QueryFile.Length - length;
|
|
}
|
|
|
|
} finally {
|
|
|
|
DebugTrace(-1, Dbg, "NwCommonQueryInformation -> %08lx\n", status );
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwCommonSetInformation (
|
|
IN PIRP_CONTEXT IrpContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common routine for setting information on a file.
|
|
|
|
Arguments:
|
|
|
|
IrpContext - Supplies the Irp to process
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - the return status for the operation
|
|
|
|
--*/
|
|
{
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
|
|
ULONG length;
|
|
FILE_INFORMATION_CLASS fileInformationClass;
|
|
PVOID buffer;
|
|
|
|
NODE_TYPE_CODE nodeTypeCode;
|
|
PICB icb;
|
|
PFCB fcb;
|
|
PVOID fsContext;
|
|
|
|
//
|
|
// Get the current Irp stack location.
|
|
//
|
|
|
|
irp = IrpContext->pOriginalIrp;
|
|
irpSp = IoGetCurrentIrpStackLocation( irp );
|
|
|
|
DebugTrace(+1, Dbg, "NwCommonSetInformation...\n", 0);
|
|
DebugTrace( 0, Dbg, " Irp = %08lx\n", (ULONG_PTR)irp);
|
|
DebugTrace( 0, Dbg, " ->Length = %08lx\n", irpSp->Parameters.SetFile.Length);
|
|
DebugTrace( 0, Dbg, " ->FileInformationClass = %08lx\n", irpSp->Parameters.SetFile.FileInformationClass);
|
|
DebugTrace( 0, Dbg, " ->Buffer = %08lx\n", (ULONG_PTR)irp->AssociatedIrp.SystemBuffer);
|
|
|
|
//
|
|
// Get a pointer to the FCB and ensure that this is a server side
|
|
// handler to a file.
|
|
//
|
|
|
|
if ((nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
|
|
&fsContext,
|
|
(PVOID *)&icb )) == NTC_UNDEFINED ) {
|
|
|
|
status = STATUS_INVALID_HANDLE;
|
|
|
|
DebugTrace(-1, Dbg, "NwCommonSetInformation -> %08lx\n", status );
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Make sure that this the user is querying an ICB.
|
|
//
|
|
|
|
switch (nodeTypeCode) {
|
|
|
|
case NW_NTC_ICB:
|
|
|
|
fcb = icb->SuperType.Fcb;
|
|
break;
|
|
|
|
default: // This is an illegal file object to query
|
|
|
|
DebugTrace(0, Dbg, "Node type code is not incorrect\n", 0);
|
|
|
|
DebugTrace(-1, Dbg, "NwCommonSetInformation -> STATUS_INVALID_PARAMETER\n", 0);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
IrpContext->Icb = icb;
|
|
|
|
//
|
|
// Make local copies of the input parameters.
|
|
//
|
|
|
|
length = irpSp->Parameters.SetFile.Length;
|
|
fileInformationClass = irpSp->Parameters.SetFile.FileInformationClass;
|
|
buffer = irp->AssociatedIrp.SystemBuffer;
|
|
|
|
try {
|
|
|
|
NwVerifyIcb( icb );
|
|
|
|
//
|
|
// Based on the information class we'll do different actions. Each
|
|
// procedure that we're calling will complete the request.
|
|
//
|
|
|
|
switch (fileInformationClass) {
|
|
|
|
case FileBasicInformation:
|
|
|
|
status = NwSetBasicInfo( IrpContext, icb, buffer );
|
|
break;
|
|
|
|
case FileDispositionInformation:
|
|
|
|
status = NwSetDispositionInfo( IrpContext, icb, buffer );
|
|
break;
|
|
|
|
case FileRenameInformation:
|
|
|
|
status = NwSetRenameInfo( IrpContext, icb, buffer );
|
|
break;
|
|
|
|
case FilePositionInformation:
|
|
|
|
status = NwSetPositionInfo( IrpContext, icb, buffer );
|
|
break;
|
|
|
|
case FileLinkInformation:
|
|
|
|
status = STATUS_INVALID_DEVICE_REQUEST;
|
|
break;
|
|
|
|
case FileAllocationInformation:
|
|
|
|
status = NwSetAllocationInfo( IrpContext, icb, buffer );
|
|
break;
|
|
|
|
case FileEndOfFileInformation:
|
|
|
|
status = NwSetEndOfFileInfo( IrpContext, icb, buffer );
|
|
break;
|
|
|
|
default:
|
|
|
|
status = STATUS_INVALID_PARAMETER;
|
|
break;
|
|
}
|
|
|
|
} finally {
|
|
|
|
DebugTrace(-1, Dbg, "NwCommonSetInformation -> %08lx\n", status);
|
|
}
|
|
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwQueryBasicInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
OUT PFILE_BASIC_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the query basic information operation.
|
|
This routine cannot be paged, it is called from QueryStandardInfoCallback.
|
|
|
|
Arguments:
|
|
|
|
Icb - Supplies a pointer the ICB for the file being querying.
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is
|
|
to be returned.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCB Fcb;
|
|
NTSTATUS Status;
|
|
ULONG Attributes;
|
|
USHORT CreationDate;
|
|
USHORT CreationTime = DEFAULT_TIME;
|
|
USHORT LastAccessDate;
|
|
USHORT LastModifiedDate;
|
|
USHORT LastModifiedTime;
|
|
BOOLEAN FirstTime = TRUE;
|
|
|
|
DebugTrace(0, Dbg, "QueryBasicInfo...\n", 0);
|
|
|
|
//
|
|
// Zero out the buffer.
|
|
//
|
|
|
|
RtlZeroMemory( Buffer, sizeof(FILE_BASIC_INFORMATION) );
|
|
Fcb = Icb->SuperType.Fcb;
|
|
|
|
//
|
|
// It is ok to attempt a reconnect if this request fails with a
|
|
// connection error.
|
|
//
|
|
|
|
SetFlag( IrpContext->Flags, IRP_FLAG_RECONNECTABLE );
|
|
|
|
NwAcquireSharedFcb( Fcb->NonPagedFcb, TRUE );
|
|
|
|
//
|
|
// If we already know the file attributes, simply return them.
|
|
//
|
|
|
|
if ( FlagOn( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID ) ) {
|
|
|
|
//
|
|
// Set the various fields in the record
|
|
//
|
|
|
|
Buffer->CreationTime = NwDateTimeToNtTime(
|
|
Fcb->CreationDate,
|
|
Fcb->CreationTime
|
|
);
|
|
|
|
Buffer->LastAccessTime = NwDateTimeToNtTime(
|
|
Fcb->LastAccessDate,
|
|
DEFAULT_TIME
|
|
);
|
|
|
|
Buffer->LastWriteTime = NwDateTimeToNtTime(
|
|
Fcb->LastModifiedDate,
|
|
Fcb->LastModifiedTime
|
|
);
|
|
|
|
Buffer->ChangeTime.QuadPart = 0;
|
|
|
|
DebugTrace(0, Dbg, "QueryBasic known %wZ\n", &Fcb->RelativeFileName);
|
|
DebugTrace(0, Dbg, "LastModifiedDate %x\n", Fcb->LastModifiedDate);
|
|
DebugTrace(0, Dbg, "LastModifiedTime %x\n", Fcb->LastModifiedTime);
|
|
DebugTrace(0, Dbg, "CreationDate %x\n", Fcb->CreationDate );
|
|
DebugTrace(0, Dbg, "CreationTime %x\n", Fcb->CreationTime );
|
|
DebugTrace(0, Dbg, "LastAccessDate %x\n", Fcb->LastAccessDate );
|
|
|
|
Buffer->FileAttributes = Fcb->NonPagedFcb->Attributes;
|
|
|
|
if ( Buffer->FileAttributes == 0 ) {
|
|
Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
}
|
|
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
return STATUS_SUCCESS;
|
|
|
|
} else if ( Fcb->RelativeFileName.Length == 0 ) {
|
|
|
|
//
|
|
// Allow 'cd \' to work.
|
|
//
|
|
|
|
Buffer->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
|
|
|
|
Buffer->CreationTime = NwDateTimeToNtTime(
|
|
DEFAULT_DATE,
|
|
DEFAULT_TIME
|
|
);
|
|
|
|
Buffer->LastAccessTime = Buffer->CreationTime;
|
|
Buffer->LastWriteTime = Buffer->CreationTime;
|
|
Buffer->ChangeTime.QuadPart = 0;
|
|
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
return STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
|
|
IrpContext->pNpScb = Fcb->Scb->pNpScb;
|
|
Retry:
|
|
if ( !BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
|
|
|
DebugTrace(0, Dbg, "QueryBasic short %wZ\n", &Fcb->RelativeFileName);
|
|
|
|
Status = ExchangeWithWait (
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"FwbbJ",
|
|
NCP_SEARCH_FILE,
|
|
-1,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
Fcb->NodeTypeCode == NW_NTC_FCB ?
|
|
SEARCH_ALL_FILES : SEARCH_ALL_DIRECTORIES,
|
|
&Icb->SuperType.Fcb->RelativeFileName );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
Status = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"N==_b-==wwww",
|
|
14,
|
|
&Attributes,
|
|
&CreationDate,
|
|
&LastAccessDate,
|
|
&LastModifiedDate,
|
|
&LastModifiedTime);
|
|
|
|
//
|
|
// If this was a directory, there's no usable
|
|
// time/date info from the server.
|
|
//
|
|
|
|
if ( ( NT_SUCCESS( Status ) ) &&
|
|
( Attributes & NW_ATTRIBUTE_DIRECTORY ) ) {
|
|
|
|
CreationDate = DEFAULT_DATE;
|
|
LastAccessDate = DEFAULT_DATE;
|
|
LastModifiedDate = DEFAULT_DATE;
|
|
LastModifiedTime = DEFAULT_TIME;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
DebugTrace(0, Dbg, "QueryBasic long %wZ\n", &Fcb->RelativeFileName);
|
|
|
|
Status = ExchangeWithWait (
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"LbbWDbDbC",
|
|
NCP_LFN_GET_INFO,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
Fcb->NodeTypeCode == NW_NTC_FCB ?
|
|
SEARCH_ALL_FILES : SEARCH_ALL_DIRECTORIES,
|
|
LFN_FLAG_INFO_ATTRIBUTES |
|
|
LFN_FLAG_INFO_MODIFY_TIME |
|
|
LFN_FLAG_INFO_CREATION_TIME,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
0,
|
|
&Icb->SuperType.Fcb->RelativeFileName );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
Status = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"N_e_xx_xx_x",
|
|
4,
|
|
&Attributes,
|
|
12,
|
|
&CreationTime,
|
|
&CreationDate,
|
|
4,
|
|
&LastModifiedTime,
|
|
&LastModifiedDate,
|
|
4,
|
|
&LastAccessDate );
|
|
|
|
}
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
//
|
|
// Set the various fields in the record
|
|
//
|
|
|
|
Buffer->CreationTime = NwDateTimeToNtTime(
|
|
CreationDate,
|
|
CreationTime
|
|
);
|
|
|
|
Buffer->LastAccessTime = NwDateTimeToNtTime(
|
|
LastAccessDate,
|
|
DEFAULT_TIME
|
|
);
|
|
|
|
Buffer->LastWriteTime = NwDateTimeToNtTime(
|
|
LastModifiedDate,
|
|
LastModifiedTime
|
|
);
|
|
|
|
Buffer->ChangeTime.QuadPart = 0;
|
|
|
|
DebugTrace(0, Dbg, "CreationDate %x\n", CreationDate );
|
|
DebugTrace(0, Dbg, "CreationTime %x\n", CreationTime );
|
|
DebugTrace(0, Dbg, "LastAccessDate %x\n", LastAccessDate );
|
|
DebugTrace(0, Dbg, "LastModifiedDate %x\n", LastModifiedDate);
|
|
DebugTrace(0, Dbg, "LastModifiedTime %x\n", LastModifiedTime);
|
|
|
|
Buffer->FileAttributes = (UCHAR)Attributes;
|
|
|
|
if ( Buffer->FileAttributes == 0 ) {
|
|
Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
}
|
|
|
|
} else 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, Fcb->Vcb );
|
|
|
|
goto Retry;
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
}
|
|
|
|
#if NWFASTIO
|
|
|
|
BOOLEAN
|
|
NwFastQueryBasicInfo (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN BOOLEAN Wait,
|
|
IN OUT PFILE_BASIC_INFORMATION Buffer,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is for the fast query call for standard file information.
|
|
|
|
Arguments:
|
|
|
|
FileObject - Supplies the file object used in this operation
|
|
|
|
Wait - Indicates if we are allowed to wait for the information
|
|
|
|
Buffer - Supplies the output buffer to receive the basic information
|
|
|
|
IoStatus - Receives the final status of the operation
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
|
|
needs to take the long route.
|
|
|
|
--*/
|
|
|
|
{
|
|
NODE_TYPE_CODE NodeTypeCode;
|
|
PICB Icb;
|
|
PFCB Fcb;
|
|
PVOID FsContext;
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
try {
|
|
//
|
|
// Find out who are.
|
|
//
|
|
|
|
if ((NodeTypeCode = NwDecodeFileObject( FileObject,
|
|
&FsContext,
|
|
&Icb )) != NW_NTC_ICB ) {
|
|
|
|
DebugTrace(-1, Dbg, "NwFastQueryStandardInfo -> FALSE\n", 0 );
|
|
return FALSE;
|
|
}
|
|
|
|
Fcb = Icb->SuperType.Fcb;
|
|
|
|
NwAcquireExclusiveFcb( Fcb->NonPagedFcb, TRUE );
|
|
|
|
//
|
|
// If we don't have the info handy, we can't use the fast path.
|
|
//
|
|
|
|
if ( !FlagOn( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID ) ) {
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
return( FALSE );
|
|
}
|
|
|
|
//
|
|
// Set the various fields in the record
|
|
//
|
|
|
|
Buffer->CreationTime = NwDateTimeToNtTime(
|
|
Fcb->CreationDate,
|
|
Fcb->CreationTime
|
|
);
|
|
|
|
Buffer->LastAccessTime = NwDateTimeToNtTime(
|
|
Fcb->LastAccessDate,
|
|
DEFAULT_TIME
|
|
);
|
|
|
|
Buffer->LastWriteTime = NwDateTimeToNtTime(
|
|
Fcb->LastModifiedDate,
|
|
Fcb->LastModifiedTime
|
|
);
|
|
|
|
Buffer->ChangeTime.QuadPart = 0;
|
|
|
|
DebugTrace(0, Dbg, "QueryBasic known %wZ\n", &Fcb->RelativeFileName);
|
|
DebugTrace(0, Dbg, "LastModifiedDate %x\n", Fcb->LastModifiedDate);
|
|
DebugTrace(0, Dbg, "LastModifiedTime %x\n", Fcb->LastModifiedTime);
|
|
DebugTrace(0, Dbg, "CreationDate %x\n", Fcb->CreationDate );
|
|
DebugTrace(0, Dbg, "CreationTime %x\n", Fcb->CreationTime );
|
|
DebugTrace(0, Dbg, "LastAccessDate %x\n", Fcb->LastAccessDate );
|
|
|
|
Buffer->FileAttributes = Fcb->NonPagedFcb->Attributes;
|
|
|
|
if ( Buffer->FileAttributes == 0 ) {
|
|
Buffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
|
|
}
|
|
|
|
IoStatus->Status = STATUS_SUCCESS;
|
|
IoStatus->Information = sizeof( *Buffer );
|
|
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
return TRUE;
|
|
|
|
} finally {
|
|
|
|
FsRtlExitFileSystem();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
NwQueryStandardInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_STANDARD_INFORMATION Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine perforNw the query standard information operation.
|
|
|
|
Arguments:
|
|
|
|
Fcb - Supplies the FCB of the being queried
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is
|
|
to be returned
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PFCB Fcb;
|
|
ULONG FileSize;
|
|
BOOLEAN FirstTime = TRUE;
|
|
|
|
PAGED_CODE();
|
|
|
|
Fcb = Icb->SuperType.Fcb;
|
|
|
|
//
|
|
// Zero out the buffer.
|
|
//
|
|
|
|
RtlZeroMemory( Buffer, sizeof(FILE_STANDARD_INFORMATION) );
|
|
|
|
//
|
|
// Fill in the answers we already know.
|
|
//
|
|
|
|
Buffer->NumberOfLinks = 1;
|
|
|
|
Buffer->DeletePending = (BOOLEAN)FlagOn( Fcb->Flags, FCB_FLAGS_DELETE_ON_CLOSE );
|
|
|
|
if ( Fcb->NodeTypeCode == NW_NTC_FCB ) {
|
|
Buffer->Directory = FALSE;
|
|
} else {
|
|
Buffer->Directory = TRUE;
|
|
}
|
|
|
|
if ( !Icb->HasRemoteHandle ) {
|
|
|
|
//
|
|
// It is ok to attempt a reconnect if this request fails with a
|
|
// connection error.
|
|
//
|
|
|
|
SetFlag( IrpContext->Flags, IRP_FLAG_RECONNECTABLE );
|
|
|
|
if ( Fcb->NodeTypeCode == NW_NTC_DCB ||
|
|
FlagOn( Fcb->Vcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
|
|
|
|
//
|
|
// Allow 'cd \' to work.
|
|
//
|
|
|
|
Buffer->AllocationSize.QuadPart = 0;
|
|
Buffer->EndOfFile.QuadPart = 0;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
//
|
|
// No open handle for this file. Use a path based NCP
|
|
// to get the file size.
|
|
//
|
|
Retry:
|
|
IrpContext->pNpScb = Fcb->Scb->pNpScb;
|
|
|
|
if ( !BooleanFlagOn( Icb->SuperType.Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
|
|
|
Status = ExchangeWithWait (
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"FwbbJ",
|
|
NCP_SEARCH_FILE,
|
|
-1,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
SEARCH_ALL_FILES,
|
|
&Fcb->RelativeFileName );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
Status = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"N_d",
|
|
20,
|
|
&FileSize );
|
|
}
|
|
|
|
} else {
|
|
|
|
Status = ExchangeWithWait (
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"LbbWDbDbC",
|
|
NCP_LFN_GET_INFO,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
SEARCH_ALL_FILES,
|
|
LFN_FLAG_INFO_FILE_SIZE,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
0,
|
|
&Fcb->RelativeFileName );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
Status = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"N_e",
|
|
10,
|
|
&FileSize );
|
|
}
|
|
|
|
}
|
|
|
|
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, Fcb->Vcb );
|
|
|
|
goto Retry;
|
|
}
|
|
|
|
Buffer->AllocationSize.QuadPart = FileSize;
|
|
Buffer->EndOfFile.QuadPart = FileSize;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// Start a Get file size NCP
|
|
//
|
|
|
|
IrpContext->pNpScb = Fcb->Scb->pNpScb;
|
|
|
|
if ( Fcb->NodeTypeCode == NW_NTC_FCB ) {
|
|
AcquireFcbAndFlushCache( IrpContext, Fcb->NonPagedFcb );
|
|
}
|
|
|
|
Status = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"F-r",
|
|
NCP_GET_FILE_SIZE,
|
|
&Icb->Handle, sizeof(Icb->Handle ) );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
//
|
|
// Get the data from the response.
|
|
//
|
|
|
|
Status = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"Nd",
|
|
&FileSize );
|
|
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
//
|
|
// Fill in Allocation size and EOF, based on the response.
|
|
//
|
|
|
|
Buffer->AllocationSize.QuadPart = FileSize;
|
|
Buffer->EndOfFile.QuadPart = Buffer->AllocationSize.QuadPart;
|
|
|
|
}
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
#if NWFASTIO
|
|
|
|
BOOLEAN
|
|
NwFastQueryStandardInfo (
|
|
IN PFILE_OBJECT FileObject,
|
|
IN BOOLEAN Wait,
|
|
IN OUT PFILE_STANDARD_INFORMATION Buffer,
|
|
OUT PIO_STATUS_BLOCK IoStatus,
|
|
IN PDEVICE_OBJECT DeviceObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is for the fast query call for standard file information.
|
|
|
|
Arguments:
|
|
|
|
FileObject - Supplies the file object used in this operation
|
|
|
|
Wait - Indicates if we are allowed to wait for the information
|
|
|
|
Buffer - Supplies the output buffer to receive the basic information
|
|
|
|
IoStatus - Receives the final status of the operation
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if the operation succeeded and FALSE if the caller
|
|
needs to take the long route.
|
|
|
|
--*/
|
|
{
|
|
NODE_TYPE_CODE NodeTypeCode;
|
|
PICB Icb;
|
|
PFCB Fcb;
|
|
PVOID FsContext;
|
|
|
|
//
|
|
// Find out who are.
|
|
//
|
|
|
|
try {
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
if ((NodeTypeCode = NwDecodeFileObject( FileObject,
|
|
&FsContext,
|
|
&Icb )) != NW_NTC_ICB ) {
|
|
|
|
DebugTrace(-1, Dbg, "NwFastQueryStandardInfo -> FALSE\n", 0 );
|
|
return FALSE;
|
|
}
|
|
|
|
Fcb = Icb->SuperType.Fcb;
|
|
|
|
//
|
|
// If we have the info handy, we can use the fast path.
|
|
//
|
|
|
|
if ( Fcb->NodeTypeCode == NW_NTC_DCB ||
|
|
FlagOn( Fcb->Vcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
|
|
|
|
Buffer->AllocationSize.QuadPart = 0;
|
|
Buffer->EndOfFile.QuadPart = 0;
|
|
|
|
Buffer->NumberOfLinks = 1;
|
|
Buffer->DeletePending = (BOOLEAN)FlagOn( Fcb->Flags, FCB_FLAGS_DELETE_ON_CLOSE );
|
|
|
|
Buffer->Directory = TRUE;
|
|
|
|
IoStatus->Status = STATUS_SUCCESS;
|
|
IoStatus->Information = sizeof( *Buffer );
|
|
|
|
return TRUE;
|
|
|
|
} else {
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
} finally {
|
|
|
|
FsRtlExitFileSystem();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
NwQueryInternalInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_INTERNAL_INFORMATION Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine perforNw the query internal information operation.
|
|
|
|
Arguments:
|
|
|
|
Fcb - Supplies the FCB of the being queried.
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is
|
|
to be returned.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(0, Dbg, "QueryInternalInfo...\n", 0);
|
|
|
|
//
|
|
// Zero out the buffer.
|
|
//
|
|
|
|
RtlZeroMemory( Buffer, sizeof(FILE_INTERNAL_INFORMATION) );
|
|
|
|
//
|
|
// Set the internal index number to be the address of the ICB.
|
|
//
|
|
|
|
Buffer->IndexNumber.HighPart = 0;
|
|
Buffer->IndexNumber.QuadPart = (ULONG_PTR)Icb->NpFcb;
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwQueryEaInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PFILE_EA_INFORMATION Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the query Ea information operation.
|
|
|
|
Arguments:
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is
|
|
to be returned
|
|
|
|
Return Value:
|
|
|
|
VOID - The result of this query
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(0, Dbg, "QueryEaInfo...\n", 0);
|
|
|
|
//
|
|
// Zero out the buffer.
|
|
//
|
|
|
|
RtlZeroMemory(Buffer, sizeof(FILE_EA_INFORMATION));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwQueryNameInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_NAME_INFORMATION Buffer,
|
|
IN PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the query name information operation.
|
|
|
|
Arguments:
|
|
|
|
Fcb - Supplies the FCB of the file to query.
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is
|
|
to be returned
|
|
|
|
Length - Supplies and receives the length of the buffer in bytes.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The result of this query.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG bytesToCopy;
|
|
ULONG fileNameSize;
|
|
PFCB Fcb = Icb->SuperType.Fcb;
|
|
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(0, Dbg, "QueryNameInfo...\n", 0);
|
|
|
|
//
|
|
// Win32 expects the root directory name to be '\' terminated,
|
|
// the netware server does not. So if this is a root directory,
|
|
// (i.e RelativeFileName length is 0) append a '\' to the path name.
|
|
//
|
|
|
|
//
|
|
// See if the buffer is large enough, and decide how many bytes to copy.
|
|
//
|
|
|
|
*Length -= FIELD_OFFSET( FILE_NAME_INFORMATION, FileName[0] );
|
|
|
|
fileNameSize = Fcb->FullFileName.Length;
|
|
if ( Fcb->RelativeFileName.Length == 0 ) {
|
|
fileNameSize += sizeof(L'\\');
|
|
}
|
|
Buffer->FileNameLength = fileNameSize;
|
|
|
|
if ( *Length >= fileNameSize ) {
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
bytesToCopy = fileNameSize;
|
|
|
|
} else {
|
|
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
|
|
bytesToCopy = *Length;
|
|
}
|
|
|
|
//
|
|
// Copy over the file name and its length.
|
|
//
|
|
|
|
RtlMoveMemory(
|
|
Buffer->FileName,
|
|
Fcb->FullFileName.Buffer,
|
|
bytesToCopy);
|
|
|
|
//
|
|
// If this is a root directory, and there is space in the buffer
|
|
// append a '\' to make win32 happy.
|
|
//
|
|
|
|
if ( Fcb->RelativeFileName.Length == 0 && status == STATUS_SUCCESS ) {
|
|
Buffer->FileName[ fileNameSize/sizeof(WCHAR) - 1 ] = L'\\';
|
|
}
|
|
|
|
*Length -= bytesToCopy;
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NwQueryAltNameInfo (
|
|
IN PIRP_CONTEXT pIrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_NAME_INFORMATION Buffer,
|
|
IN PULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the AltName query name information operation.
|
|
|
|
Arguments:
|
|
|
|
Fcb - Supplies the FCB of the file to query.
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is
|
|
to be returned
|
|
|
|
Length - Supplies and receives the length of the buffer in bytes.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The result of this query.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG bytesToCopy;
|
|
ULONG fileNameSize;
|
|
PFCB Fcb = Icb->SuperType.Fcb;
|
|
|
|
UNICODE_STRING ShortName;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(0, Dbg, "QueryAltNameInfo...\n", 0);
|
|
|
|
pIrpContext->pNpScb = Fcb->Scb->pNpScb;
|
|
|
|
//
|
|
// See if the buffer is large enough, and decide how many bytes to copy.
|
|
//
|
|
|
|
*Length -= FIELD_OFFSET( FILE_NAME_INFORMATION, FileName[0] );
|
|
|
|
|
|
ShortName.MaximumLength = MAX_PATH;
|
|
ShortName.Buffer=NULL;
|
|
ShortName.Length = 0;
|
|
|
|
|
|
status = ExchangeWithWait (
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"LbbWDbDbC",
|
|
NCP_LFN_GET_INFO,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
0x0, //0x0 DOS Nam
|
|
SEARCH_ALL_DIRECTORIES,
|
|
LFN_FLAG_INFO_NAME,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
0,
|
|
&Fcb->RelativeFileName );
|
|
|
|
if (!NT_SUCCESS( status ) ){
|
|
return status;
|
|
}
|
|
|
|
|
|
ShortName.Buffer= ALLOCATE_POOL(NonPagedPool,
|
|
ShortName.MaximumLength+sizeof(WCHAR));
|
|
if (ShortName.Buffer == NULL){
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = ParseResponse(
|
|
pIrpContext,
|
|
pIrpContext->rsp,
|
|
pIrpContext->ResponseLength,
|
|
"N_P",
|
|
76,
|
|
&ShortName);
|
|
|
|
if ( NT_SUCCESS( status ) ) {
|
|
|
|
fileNameSize = ShortName.Length;
|
|
|
|
if ( *Length >= fileNameSize ) {
|
|
|
|
status = STATUS_SUCCESS;
|
|
bytesToCopy = fileNameSize;
|
|
|
|
} else {
|
|
|
|
status = STATUS_BUFFER_OVERFLOW;
|
|
bytesToCopy = *Length;
|
|
}
|
|
|
|
Buffer->FileNameLength = fileNameSize;
|
|
|
|
RtlMoveMemory(
|
|
Buffer->FileName,
|
|
ShortName.Buffer,
|
|
bytesToCopy);
|
|
|
|
*Length -= bytesToCopy;
|
|
|
|
}
|
|
|
|
|
|
FREE_POOL(ShortName.Buffer);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwQueryPositionInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_POSITION_INFORMATION Buffer
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine performs the query position information operation.
|
|
|
|
Arguments:
|
|
|
|
Fcb - Supplies the FCB of the file being queried.
|
|
|
|
Buffer - Supplies a pointer to the buffer where the information is
|
|
to be returned.
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(0, Dbg, "QueryPositionInfo...\n", 0);
|
|
|
|
//
|
|
// Return the current byte offset. This info is totally
|
|
// bogus for asynchronous files. Also note that we don't
|
|
// use the FilePosition member of the ICB for anything.
|
|
//
|
|
|
|
if ( Icb->FileObject ) {
|
|
Buffer->CurrentByteOffset.QuadPart = Icb->FileObject->CurrentByteOffset.QuadPart;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwSetBasicInfo (
|
|
IN PIRP_CONTEXT pIrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_BASIC_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the basic information for a file.
|
|
|
|
Arguments:
|
|
|
|
pIrpContext - Supplies Irp context information.
|
|
|
|
Icb - Supplies the ICB for the file being modified.
|
|
|
|
Buffer - Supplies the buffer containing the data being set.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Returns our completion status.
|
|
|
|
--*/
|
|
|
|
{
|
|
PFCB Fcb;
|
|
NTSTATUS Status;
|
|
BOOLEAN SetTime = FALSE;
|
|
BOOLEAN SetAttributes = FALSE;
|
|
ULONG LfnFlag = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(0, Dbg, "SetBasicInfo...\n", 0);
|
|
|
|
Fcb = Icb->SuperType.Fcb;
|
|
|
|
pIrpContext->pNpScb = Fcb->Scb->pNpScb;
|
|
|
|
//
|
|
// Append this IRP context and wait to get to the front.
|
|
// then grab from FCB
|
|
//
|
|
|
|
NwAppendToQueueAndWait( pIrpContext );
|
|
NwAcquireExclusiveFcb( Fcb->NonPagedFcb, TRUE );
|
|
|
|
//
|
|
// It is ok to attempt a reconnect if this request fails with a
|
|
// connection error.
|
|
//
|
|
|
|
SetFlag( pIrpContext->Flags, IRP_FLAG_RECONNECTABLE );
|
|
|
|
if (Buffer->CreationTime.QuadPart != 0) {
|
|
|
|
//
|
|
// Modify the creation time.
|
|
//
|
|
|
|
Status = NwNtTimeToNwDateTime(
|
|
Buffer->CreationTime,
|
|
&Fcb->CreationDate,
|
|
&Fcb->CreationTime );
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
return( Status );
|
|
}
|
|
|
|
SetTime = TRUE;
|
|
LfnFlag |= LFN_FLAG_SET_INFO_CREATE_DATE | LFN_FLAG_SET_INFO_CREATE_TIME;
|
|
}
|
|
|
|
if (Buffer->LastAccessTime.QuadPart != 0) {
|
|
|
|
USHORT Dummy;
|
|
|
|
//
|
|
// Modify the last access time.
|
|
//
|
|
|
|
Status = NwNtTimeToNwDateTime(
|
|
Buffer->LastAccessTime,
|
|
&Fcb->LastAccessDate,
|
|
&Dummy );
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
return( Status );
|
|
}
|
|
|
|
SetTime = TRUE;
|
|
LfnFlag |= LFN_FLAG_SET_INFO_LASTACCESS_DATE;
|
|
|
|
// Set the last access flag in the ICB so that we update
|
|
// last access time for real when we close this handle!
|
|
|
|
Icb->UserSetLastAccessTime = TRUE;
|
|
}
|
|
|
|
if (Buffer->LastWriteTime.QuadPart != 0) {
|
|
|
|
//
|
|
// Modify the last write time
|
|
//
|
|
|
|
Status = NwNtTimeToNwDateTime(
|
|
Buffer->LastWriteTime,
|
|
&Fcb->LastModifiedDate,
|
|
&Fcb->LastModifiedTime );
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
return( Status );
|
|
}
|
|
|
|
LfnFlag |= LFN_FLAG_SET_INFO_MODIFY_DATE | LFN_FLAG_SET_INFO_MODIFY_TIME;
|
|
}
|
|
|
|
|
|
if (Buffer->FileAttributes != 0) {
|
|
LfnFlag |= LFN_FLAG_SET_INFO_ATTRIBUTES;
|
|
}
|
|
|
|
if ( LfnFlag == 0 ) {
|
|
|
|
//
|
|
// Nothing to set, simply return success.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if ( Fcb->NodeTypeCode == NW_NTC_FCB ) {
|
|
|
|
//
|
|
// Call plain FlushCache - we don't want to acquire and
|
|
// release the NpFcb. We are already at the front and have the Fcb
|
|
// exclusive.
|
|
//
|
|
|
|
FlushCache( pIrpContext, Fcb->NonPagedFcb );
|
|
}
|
|
|
|
if ( BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
|
|
|
Status = ExchangeWithWait(
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"LbbWDW--WW==WW==_W_bDbC",
|
|
NCP_LFN_SET_INFO,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
Fcb->NodeTypeCode == NW_NTC_FCB ?
|
|
SEARCH_ALL_FILES : SEARCH_ALL_DIRECTORIES,
|
|
LfnFlag,
|
|
NtAttributesToNwAttributes( Buffer->FileAttributes ),
|
|
Fcb->CreationDate,
|
|
Fcb->CreationTime,
|
|
Fcb->LastModifiedDate,
|
|
Fcb->LastModifiedTime,
|
|
8,
|
|
Fcb->LastAccessDate,
|
|
8,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
0,
|
|
&Fcb->RelativeFileName );
|
|
|
|
} else {
|
|
|
|
if ( LfnFlag & LFN_FLAG_SET_INFO_ATTRIBUTES ) {
|
|
Status = ExchangeWithWait(
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"FbbbU",
|
|
NCP_SET_FILE_ATTRIBUTES,
|
|
NtAttributesToNwAttributes( Buffer->FileAttributes ),
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
Fcb->NodeTypeCode == NW_NTC_FCB ?
|
|
SEARCH_ALL_FILES : SEARCH_ALL_DIRECTORIES,
|
|
&Fcb->RelativeFileName );
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
return( Status );
|
|
}
|
|
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// We could conceivably use ScanDir/SetDir to update last access
|
|
// and create time. Not supported yet.
|
|
//
|
|
|
|
if ( LfnFlag & ( LFN_FLAG_SET_INFO_LASTACCESS_DATE | LFN_FLAG_SET_INFO_CREATE_DATE ) ) {
|
|
|
|
ULONG SearchIndex;
|
|
ULONG Directory;
|
|
|
|
Status = ExchangeWithWait(
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"SbbdU",
|
|
0x16, 0x1E, // Scan dir entry
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
0x06, // Search attributes
|
|
-1, // Search index
|
|
&Fcb->RelativeFileName );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
Status = ParseResponse(
|
|
pIrpContext,
|
|
pIrpContext->rsp,
|
|
pIrpContext->ResponseLength,
|
|
"Ndd",
|
|
&SearchIndex,
|
|
&Directory );
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
Status = ExchangeWithWait(
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"Sbbdddw=----_ww==ww==ww",
|
|
0x16, 0x25, // Set dir entry
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
0x06, // Search attributes
|
|
SearchIndex,
|
|
0, // Change Bits?
|
|
Directory,
|
|
12,
|
|
Fcb->CreationDate,
|
|
0,
|
|
Fcb->LastAccessDate,
|
|
0,
|
|
Fcb->LastModifiedDate,
|
|
Fcb->LastModifiedTime );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( LfnFlag & LFN_FLAG_SET_INFO_MODIFY_DATE ) {
|
|
Status = ExchangeWithWait(
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"F-rww-",
|
|
NCP_SET_FILE_TIME,
|
|
&Icb->Handle, sizeof( Icb->Handle ),
|
|
Fcb->LastModifiedTime,
|
|
Fcb->LastModifiedDate );
|
|
}
|
|
}
|
|
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwSetDispositionInfo (
|
|
IN PIRP_CONTEXT pIrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_DISPOSITION_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the disposition information for a file.
|
|
|
|
Arguments:
|
|
|
|
pIrpContext - Supplies Irp context information.
|
|
|
|
Icb - Supplies the ICB for the file being modified.
|
|
|
|
Buffer - Supplies the buffer containing the data being set.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - Returns our completion status.
|
|
|
|
--*/
|
|
{
|
|
PFCB Fcb;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(0, Dbg, "SetDispositionInfo...\n", 0);
|
|
|
|
Fcb = Icb->SuperType.Fcb;
|
|
|
|
if ( FlagOn( Fcb->Vcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
|
|
|
|
//
|
|
// This is a print queue, just pretend this IRP succeeded.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
//
|
|
// This is a real file or directory. Mark it delete pending.
|
|
//
|
|
|
|
SetFlag( Fcb->Flags, FCB_FLAGS_DELETE_ON_CLOSE );
|
|
|
|
pIrpContext->pNpScb = Fcb->Scb->pNpScb;
|
|
pIrpContext->Icb = Icb;
|
|
|
|
Icb->State = ICB_STATE_CLOSE_PENDING;
|
|
|
|
//
|
|
// Go ahead, delete the file.
|
|
//
|
|
|
|
Status = NwDeleteFile( pIrpContext );
|
|
}
|
|
|
|
return( Status );
|
|
}
|
|
|
|
NTSTATUS
|
|
NwDeleteFile(
|
|
PIRP_CONTEXT pIrpContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine continues processing of the SetDispositionInfo request.
|
|
It must run in the redirector FSP.
|
|
|
|
Arguments:
|
|
|
|
pIrpContext - A pointer to the IRP context information for the
|
|
request in progress.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
PICB Icb;
|
|
PFCB Fcb;
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
Icb = pIrpContext->Icb;
|
|
Fcb = Icb->SuperType.Fcb;
|
|
|
|
ClearFlag( Fcb->Flags, FCB_FLAGS_DELETE_ON_CLOSE );
|
|
|
|
//
|
|
// To a delete a file, first close the remote handle.
|
|
//
|
|
|
|
if ( Icb->HasRemoteHandle ) {
|
|
|
|
Icb->HasRemoteHandle = FALSE;
|
|
|
|
Status = ExchangeWithWait(
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"F-r",
|
|
NCP_CLOSE,
|
|
Icb->Handle, sizeof( Icb->Handle ) );
|
|
}
|
|
|
|
//
|
|
// Note that this request cannot be reconnectable since, it can
|
|
// be called via NwCloseIcb(). See comment in that routine for
|
|
// more info.
|
|
//
|
|
|
|
if ( Fcb->NodeTypeCode == NW_NTC_FCB ) {
|
|
|
|
if ( !BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
|
|
|
Status = ExchangeWithWait(
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"FbbJ",
|
|
NCP_DELETE_FILE,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
SEARCH_ALL_FILES,
|
|
&Fcb->RelativeFileName );
|
|
|
|
} else {
|
|
|
|
Status = ExchangeWithWait(
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"LbbW-DbC",
|
|
NCP_LFN_DELETE_FILE,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
NW_ATTRIBUTE_SYSTEM | NW_ATTRIBUTE_HIDDEN,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
LFN_FLAG_SHORT_DIRECTORY,
|
|
&Fcb->RelativeFileName );
|
|
}
|
|
|
|
} else {
|
|
|
|
ASSERT( Fcb->NodeTypeCode == NW_NTC_DCB );
|
|
|
|
if ( !BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
|
|
|
Status = ExchangeWithWait(
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"SbbJ",
|
|
NCP_DIR_FUNCTION, NCP_DELETE_DIRECTORY,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
SEARCH_ALL_DIRECTORIES,
|
|
&Fcb->RelativeFileName );
|
|
} else {
|
|
|
|
Status = ExchangeWithWait(
|
|
pIrpContext,
|
|
SynchronousResponseCallback,
|
|
"LbbW-DbC",
|
|
NCP_LFN_DELETE_FILE,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
SEARCH_ALL_DIRECTORIES,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
LFN_FLAG_SHORT_DIRECTORY,
|
|
&Fcb->RelativeFileName );
|
|
}
|
|
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status )) {
|
|
|
|
Status = ParseResponse(
|
|
pIrpContext,
|
|
pIrpContext->rsp,
|
|
pIrpContext->ResponseLength,
|
|
"N" );
|
|
|
|
} else {
|
|
|
|
//
|
|
// We can map all failures to STATUS_NO_SUCH_FILE
|
|
// except ACCESS_DENIED, which happens with a read
|
|
// only file.
|
|
//
|
|
|
|
if ( Status != STATUS_ACCESS_DENIED ) {
|
|
Status = STATUS_NO_SUCH_FILE;
|
|
}
|
|
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NwSetRenameInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_RENAME_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine set rename information for a file.
|
|
|
|
Arguments:
|
|
|
|
pIrpContext - A pointer to the IRP context information for the
|
|
request in progress.
|
|
|
|
Icb - A pointer to the ICB of the file to set.
|
|
|
|
Buffer - The request buffer.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
NTSTATUS Status;
|
|
NTSTATUS Status2;
|
|
PFCB Fcb;
|
|
PFCB TargetFcb;
|
|
BOOLEAN HandleAllocated = FALSE;
|
|
BYTE Handle;
|
|
PICB TargetIcb = NULL;
|
|
|
|
UNICODE_STRING OldDrive;
|
|
UNICODE_STRING OldServer;
|
|
UNICODE_STRING OldVolume;
|
|
UNICODE_STRING OldPath;
|
|
UNICODE_STRING OldFileName;
|
|
UNICODE_STRING OldFullName;
|
|
WCHAR OldDriveLetter;
|
|
UNICODE_STRING OldFcbFullName;
|
|
|
|
UNICODE_STRING NewDrive;
|
|
UNICODE_STRING NewServer;
|
|
UNICODE_STRING NewVolume;
|
|
UNICODE_STRING NewPath;
|
|
UNICODE_STRING NewFileName;
|
|
UNICODE_STRING NewFullName;
|
|
WCHAR NewDriveLetter;
|
|
UNICODE_STRING NewFcbFullName;
|
|
|
|
USHORT i;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(+1, Dbg, "SetRenameInfo...\n", 0);
|
|
|
|
//
|
|
// Can't try to set rename info on a print queue.
|
|
//
|
|
|
|
Fcb = Icb->SuperType.Fcb;
|
|
|
|
if ( FlagOn( Fcb->Vcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// It is ok to attempt a reconnect if this request fails with a
|
|
// connection error.
|
|
//
|
|
|
|
SetFlag( IrpContext->Flags, IRP_FLAG_RECONNECTABLE );
|
|
|
|
//
|
|
// Get the current stack location.
|
|
//
|
|
|
|
Irp = IrpContext->pOriginalIrp;
|
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
DebugTrace( 0, Dbg, " ->FullFileName = %wZ\n",
|
|
&Fcb->FullFileName);
|
|
|
|
if (irpSp->Parameters.SetFile.FileObject != NULL) {
|
|
|
|
TargetIcb = irpSp->Parameters.SetFile.FileObject->FsContext2;
|
|
|
|
DebugTrace( 0, Dbg, " ->FullFileName = %wZ\n",
|
|
&TargetIcb->SuperType.Fcb->FullFileName);
|
|
|
|
if ( TargetIcb->SuperType.Fcb->Scb != Icb->SuperType.Fcb->Scb ) {
|
|
return STATUS_NOT_SAME_DEVICE;
|
|
}
|
|
|
|
} else {
|
|
|
|
DebugTrace( 0, Dbg, " ->FullFileName in users buffer\n", 0);
|
|
DebugTrace(-1, Dbg, "SetRenameInfo %08lx\n", STATUS_NOT_IMPLEMENTED);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
DebugTrace( 0, Dbg, " ->TargetFileName = %wZ\n",
|
|
&irpSp->Parameters.SetFile.FileObject->FileName);
|
|
|
|
TargetFcb = ((PNONPAGED_FCB)irpSp->Parameters.SetFile.FileObject->FsContext)->Fcb;
|
|
|
|
|
|
IrpContext->pNpScb = Fcb->Scb->pNpScb;
|
|
|
|
NwAppendToQueueAndWait( IrpContext );
|
|
NwAcquireExclusiveFcb( Fcb->NonPagedFcb, TRUE );
|
|
|
|
try {
|
|
|
|
//
|
|
// If either source or destination is a long name, use
|
|
// the long name path.
|
|
//
|
|
|
|
if ( !BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) &&
|
|
IsFatNameValid( &TargetFcb->RelativeFileName ) &&
|
|
!BooleanFlagOn( Fcb->Vcb->Flags, VCB_FLAG_LONG_NAME ) ) {
|
|
|
|
//
|
|
// Strip to UID portion of the FCB name.
|
|
//
|
|
|
|
for ( i = 0 ; i < Fcb->FullFileName.Length / sizeof(WCHAR) ; i++ ) {
|
|
if ( Fcb->FullFileName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT( Fcb->FullFileName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR );
|
|
|
|
OldFcbFullName.Length = Fcb->FullFileName.Length - i*sizeof(WCHAR);
|
|
OldFcbFullName.Buffer = Fcb->FullFileName.Buffer + i;
|
|
|
|
Status = CrackPath (
|
|
&OldFcbFullName,
|
|
&OldDrive,
|
|
&OldDriveLetter,
|
|
&OldServer,
|
|
&OldVolume,
|
|
&OldPath,
|
|
&OldFileName,
|
|
&OldFullName );
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Strip to UID portion of the FCB name.
|
|
//
|
|
|
|
TargetFcb = ((PNONPAGED_FCB)(irpSp->Parameters.SetFile.FileObject->FsContext))->Fcb;
|
|
|
|
for ( i = 0 ; i < TargetFcb->FullFileName.Length / sizeof(WCHAR) ; i++ ) {
|
|
if ( TargetFcb->FullFileName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
ASSERT( TargetFcb->FullFileName.Buffer[i] == OBJ_NAME_PATH_SEPARATOR );
|
|
|
|
NewFcbFullName.Length = TargetFcb->FullFileName.Length - i*sizeof(WCHAR);
|
|
NewFcbFullName.Buffer = TargetFcb->FullFileName.Buffer + i;
|
|
|
|
Status = CrackPath (
|
|
&NewFcbFullName,
|
|
&NewDrive,
|
|
&NewDriveLetter,
|
|
&NewServer,
|
|
&NewVolume,
|
|
&NewPath,
|
|
&NewFileName,
|
|
&NewFullName );
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Make sure that this is the same volume.
|
|
//
|
|
|
|
if ( RtlCompareUnicodeString( &NewVolume, &OldVolume, TRUE ) != 0 ) {
|
|
try_return( Status = STATUS_NOT_SAME_DEVICE );
|
|
}
|
|
|
|
if (Icb->SuperType.Fcb->IcbCount != 1) {
|
|
try_return( Status = STATUS_ACCESS_DENIED );
|
|
}
|
|
|
|
//
|
|
// After a rename, the only operation allowed on the handle is an
|
|
// NtClose.
|
|
//
|
|
|
|
Icb->State = ICB_STATE_CLOSE_PENDING;
|
|
|
|
if ((irpSp->Parameters.SetFile.ReplaceIfExists ) &&
|
|
(TargetIcb->Exists)) {
|
|
|
|
// Delete the file
|
|
|
|
Status2 = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"Fb-J",
|
|
NCP_DELETE_FILE,
|
|
TargetFcb->Vcb->Specific.Disk.Handle,
|
|
&TargetFcb->RelativeFileName );
|
|
|
|
#ifdef NWDBG
|
|
if ( NT_SUCCESS( Status2 ) ) {
|
|
Status2 = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"N" );
|
|
}
|
|
|
|
ASSERT(NT_SUCCESS(Status2));
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Need to create a handle to the directory containing the old
|
|
// file/directory name because directory rename does not contain a
|
|
// path and there might not be room for two paths in a file rename.
|
|
//
|
|
// The way we do this is to allocate a temporary handle on the server.
|
|
// This request is at the front of the Scb->Requests queue and so can
|
|
// use the temporary handle and delete it without affecting any other
|
|
// requests.
|
|
//
|
|
|
|
if ( OldPath.Length == 0 ) {
|
|
|
|
// In the root so use the VCB handle.
|
|
|
|
Handle = Fcb->Vcb->Specific.Disk.Handle;
|
|
|
|
} else {
|
|
|
|
Status = ExchangeWithWait (
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"SbbJ", // NCP Allocate temporary directory handle
|
|
NCP_DIR_FUNCTION, NCP_ALLOCATE_TEMP_DIR_HANDLE,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
'[',
|
|
&OldPath );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
Status = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"Nb",
|
|
&Handle );
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
try_return(Status);
|
|
}
|
|
|
|
HandleAllocated = TRUE;
|
|
}
|
|
|
|
if ( Fcb->NodeTypeCode == NW_NTC_DCB ) {
|
|
|
|
//
|
|
// We can only rename files in the same directory
|
|
//
|
|
|
|
if ( RtlCompareUnicodeString( &NewPath, &OldPath, TRUE ) != 0 ) {
|
|
try_return(Status = STATUS_NOT_SUPPORTED);
|
|
|
|
} else {
|
|
|
|
Status = ExchangeWithWait ( IrpContext,
|
|
SynchronousResponseCallback,
|
|
"SbJJ",
|
|
NCP_DIR_FUNCTION, NCP_RENAME_DIRECTORY,
|
|
Handle,
|
|
&OldFileName,
|
|
&NewFileName);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// We have to close the handle associated with the Icb that
|
|
// is doing the rename. Close that handle or the rename will
|
|
// fail for sure.
|
|
//
|
|
|
|
if ( Icb->HasRemoteHandle ) {
|
|
|
|
Status2 = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"F-r",
|
|
NCP_CLOSE,
|
|
Icb->Handle, sizeof( Icb->Handle ) );
|
|
|
|
Icb->HasRemoteHandle = FALSE;
|
|
|
|
#ifdef NWDBG
|
|
if ( NT_SUCCESS( Status2 ) ) {
|
|
Status2 = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"N" );
|
|
}
|
|
|
|
ASSERT(NT_SUCCESS(Status2));
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Do the file rename Ncp.
|
|
//
|
|
|
|
Status = ExchangeWithWait (
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"FbbJbJ",
|
|
NCP_RENAME_FILE,
|
|
Handle,
|
|
SEARCH_ALL_FILES,
|
|
&OldFileName,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
&NewFullName);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// We are going through the long name path. Ensure that the
|
|
// VCB supports long names.
|
|
//
|
|
|
|
if ( Icb->SuperType.Fcb->Vcb->Specific.Disk.LongNameSpace ==
|
|
LFN_NO_OS2_NAME_SPACE) {
|
|
try_return( Status = STATUS_OBJECT_PATH_SYNTAX_BAD );
|
|
}
|
|
|
|
if (Icb->SuperType.Fcb->IcbCount != 1) {
|
|
try_return( Status = STATUS_ACCESS_DENIED);
|
|
}
|
|
|
|
//
|
|
// After a rename, the only operation allowed on the handle is an
|
|
// NtClose.
|
|
//
|
|
|
|
Icb->State = ICB_STATE_CLOSE_PENDING;
|
|
|
|
if ((irpSp->Parameters.SetFile.ReplaceIfExists ) &&
|
|
(TargetIcb->Exists)) {
|
|
|
|
// Delete the file
|
|
|
|
Status = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"LbbW-DbC",
|
|
NCP_LFN_DELETE_FILE,
|
|
TargetFcb->Vcb->Specific.Disk.LongNameSpace,
|
|
TargetFcb->Vcb->Specific.Disk.VolumeNumber,
|
|
SEARCH_ALL_FILES,
|
|
TargetFcb->Vcb->Specific.Disk.Handle,
|
|
LFN_FLAG_SHORT_DIRECTORY,
|
|
&TargetFcb->RelativeFileName );
|
|
|
|
#ifdef NWDBG
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
Status2 = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"N" );
|
|
}
|
|
|
|
ASSERT(NT_SUCCESS(Status2));
|
|
#endif
|
|
}
|
|
|
|
if ( Fcb->NodeTypeCode == NW_NTC_DCB ) {
|
|
|
|
//
|
|
// We can only rename files in the same directory
|
|
//
|
|
|
|
if ( Fcb->Vcb != TargetFcb->Vcb ) {
|
|
try_return(Status = STATUS_NOT_SUPPORTED);
|
|
|
|
} else {
|
|
|
|
Status = ExchangeWithWait (
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"LbbWbDbbbDbbNN",
|
|
NCP_LFN_RENAME_FILE,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
0, // Rename flag
|
|
SEARCH_ALL_DIRECTORIES,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
LFN_FLAG_SHORT_DIRECTORY,
|
|
OccurenceCount( &Fcb->RelativeFileName, OBJ_NAME_PATH_SEPARATOR ) + 1,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
LFN_FLAG_SHORT_DIRECTORY,
|
|
OccurenceCount( &TargetFcb->RelativeFileName, OBJ_NAME_PATH_SEPARATOR ) + 1,
|
|
&Fcb->RelativeFileName,
|
|
&TargetFcb->RelativeFileName );
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// We have to close the handle associated with the Icb that
|
|
// is doing the rename. Close that handle or the rename will
|
|
// fail for sure.
|
|
//
|
|
|
|
if ( Icb->HasRemoteHandle ) {
|
|
|
|
Status2 = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"F-r",
|
|
NCP_CLOSE,
|
|
Icb->Handle, sizeof( Icb->Handle ) );
|
|
|
|
Icb->HasRemoteHandle = FALSE;
|
|
|
|
#ifdef NWDBG
|
|
if ( NT_SUCCESS( Status2 ) ) {
|
|
Status2 = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"N" );
|
|
}
|
|
|
|
ASSERT(NT_SUCCESS(Status2));
|
|
#endif
|
|
}
|
|
|
|
//
|
|
// Do the file rename Ncp.
|
|
//
|
|
|
|
Status = ExchangeWithWait (
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"LbbWbDbbbDbbNN",
|
|
NCP_LFN_RENAME_FILE,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
0, // Rename flag
|
|
SEARCH_ALL_FILES,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
LFN_FLAG_SHORT_DIRECTORY,
|
|
OccurenceCount( &Fcb->RelativeFileName, OBJ_NAME_PATH_SEPARATOR ) + 1,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
LFN_FLAG_SHORT_DIRECTORY,
|
|
OccurenceCount( &TargetFcb->RelativeFileName, OBJ_NAME_PATH_SEPARATOR ) + 1,
|
|
&Fcb->RelativeFileName,
|
|
&TargetFcb->RelativeFileName );
|
|
}
|
|
}
|
|
|
|
try_exit: NOTHING;
|
|
} finally {
|
|
|
|
if (HandleAllocated) {
|
|
|
|
Status2 = ExchangeWithWait (
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"Sb", // NCP Deallocate directory handle
|
|
NCP_DIR_FUNCTION, NCP_DEALLOCATE_DIR_HANDLE,
|
|
Handle);
|
|
#ifdef NWDBG
|
|
if ( NT_SUCCESS( Status2 ) ) {
|
|
Status2 = ParseResponse(
|
|
IrpContext,
|
|
IrpContext->rsp,
|
|
IrpContext->ResponseLength,
|
|
"N" );
|
|
}
|
|
|
|
ASSERT(NT_SUCCESS(Status2));
|
|
#endif
|
|
|
|
}
|
|
|
|
NwReleaseFcb( Fcb->NonPagedFcb );
|
|
}
|
|
|
|
DebugTrace(-1, Dbg, "SetRenameInfo %08lx\n", Status );
|
|
|
|
//
|
|
// We're done with this request. Dequeue the IRP context from
|
|
// SCB and complete the request.
|
|
//
|
|
|
|
if ( Status != STATUS_PENDING ) {
|
|
NwDequeueIrpContext( IrpContext, FALSE );
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NwSetPositionInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_POSITION_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets position information for a file.
|
|
|
|
Arguments:
|
|
|
|
pIrpContext - A pointer to the IRP context information for the
|
|
request in progress.
|
|
|
|
Icb - A pointer to the ICB of the file to set.
|
|
|
|
Buffer - The request buffer.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
PAGED_CODE();
|
|
|
|
ASSERT( Buffer->CurrentByteOffset.HighPart == 0 );
|
|
|
|
if ( Icb->FileObject ) {
|
|
Icb->FileObject->CurrentByteOffset.QuadPart = Buffer->CurrentByteOffset.QuadPart;
|
|
}
|
|
|
|
return( STATUS_SUCCESS );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwSetAllocationInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_ALLOCATION_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets allocation information for a file.
|
|
|
|
Arguments:
|
|
|
|
pIrpContext - A pointer to the IRP context information for the
|
|
request in progress.
|
|
|
|
Icb - A pointer to the ICB of the file to set.
|
|
|
|
Buffer - The request buffer.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PFCB fcb = (PFCB)Icb->SuperType.Fcb;
|
|
PULONG pFileSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT( Buffer->AllocationSize.HighPart == 0);
|
|
|
|
if ( fcb->NodeTypeCode == NW_NTC_FCB ) {
|
|
|
|
pFileSize = &Icb->NpFcb->Header.FileSize.LowPart;
|
|
|
|
IrpContext->pNpScb = fcb->Scb->pNpScb;
|
|
|
|
if (BooleanFlagOn( fcb->Vcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
|
|
if (IsTerminalServer()) {
|
|
// 2/10/97 cjc Fix problem for binary files not printing correctly
|
|
// if done via the COPY command. Works with NT RDR so
|
|
// changed this to behave same way.
|
|
return(STATUS_INVALID_PARAMETER);
|
|
} else {
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
} else if ( fcb->NodeTypeCode == NW_NTC_SCB ) {
|
|
|
|
pFileSize = &Icb->FileSize;
|
|
|
|
IrpContext->pNpScb = ((PSCB)fcb)->pNpScb;
|
|
|
|
} else {
|
|
|
|
DebugTrace(0, Dbg, "Not a file or a server\n", 0);
|
|
|
|
DebugTrace( 0, Dbg, "NwSetAllocationInfo -> %08lx\n", STATUS_INVALID_PARAMETER );
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
NwAppendToQueueAndWait( IrpContext );
|
|
|
|
if ( !Icb->HasRemoteHandle ) {
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else if ( Buffer->AllocationSize.LowPart == *pFileSize ) {
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
irp = IrpContext->pOriginalIrp;
|
|
irpSp = IoGetCurrentIrpStackLocation( irp );
|
|
|
|
#ifndef QFE_BUILD
|
|
if ( Buffer->AllocationSize.LowPart < *pFileSize ) {
|
|
|
|
//
|
|
// Before we actually truncate, check to see if the purge
|
|
// is going to fail.
|
|
//
|
|
|
|
if (!MmCanFileBeTruncated( irpSp->FileObject->SectionObjectPointer,
|
|
&Buffer->AllocationSize )) {
|
|
|
|
return( STATUS_USER_MAPPED_FILE );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( fcb->NodeTypeCode == NW_NTC_FCB ) {
|
|
AcquireFcbAndFlushCache( IrpContext, fcb->NonPagedFcb );
|
|
}
|
|
|
|
Status = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"F-rd=",
|
|
NCP_WRITE_FILE,
|
|
&Icb->Handle, sizeof( Icb->Handle ),
|
|
Buffer->AllocationSize.LowPart );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
*pFileSize = Buffer->AllocationSize.LowPart;
|
|
}
|
|
}
|
|
|
|
NwDequeueIrpContext( IrpContext, FALSE );
|
|
|
|
return( Status );
|
|
}
|
|
|
|
NTSTATUS
|
|
NwSetEndOfFileInfo (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb,
|
|
IN PFILE_END_OF_FILE_INFORMATION Buffer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets end of file information for a file.
|
|
|
|
Arguments:
|
|
|
|
pIrpContext - A pointer to the IRP context information for the
|
|
request in progress.
|
|
|
|
Icb - A pointer to the ICB of the file to set.
|
|
|
|
Buffer - The request buffer.
|
|
|
|
Return Value:
|
|
|
|
The status of the operation.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PIRP irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PFCB fcb = (PFCB)Icb->SuperType.Fcb;
|
|
PULONG pFileSize;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT( Buffer->EndOfFile.HighPart == 0);
|
|
|
|
if ( fcb->NodeTypeCode == NW_NTC_FCB ) {
|
|
|
|
pFileSize = &Icb->NpFcb->Header.FileSize.LowPart;
|
|
|
|
IrpContext->pNpScb = fcb->Scb->pNpScb;
|
|
|
|
if (BooleanFlagOn( fcb->Vcb->Flags, VCB_FLAG_PRINT_QUEUE ) ) {
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
} else if ( fcb->NodeTypeCode == NW_NTC_SCB ) {
|
|
|
|
pFileSize = &Icb->FileSize;
|
|
|
|
IrpContext->pNpScb = ((PSCB)fcb)->pNpScb;
|
|
|
|
} else {
|
|
|
|
DebugTrace(0, Dbg, "Not a file or a server\n", 0);
|
|
|
|
DebugTrace( 0, Dbg, "NwSetAllocationInfo -> %08lx\n", STATUS_INVALID_PARAMETER );
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
NwAppendToQueueAndWait( IrpContext );
|
|
|
|
if ( !Icb->HasRemoteHandle ) {
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
} else if ( Buffer->EndOfFile.LowPart == *pFileSize ) {
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
irp = IrpContext->pOriginalIrp;
|
|
irpSp = IoGetCurrentIrpStackLocation( irp );
|
|
|
|
#ifndef QFE_BUILD
|
|
|
|
if ( Buffer->EndOfFile.LowPart < *pFileSize ) {
|
|
|
|
//
|
|
// Before we actually truncate, check to see if the purge
|
|
// is going to fail.
|
|
//
|
|
|
|
if (!MmCanFileBeTruncated( irpSp->FileObject->SectionObjectPointer,
|
|
&Buffer->EndOfFile )) {
|
|
|
|
return( STATUS_USER_MAPPED_FILE );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( fcb->NodeTypeCode == NW_NTC_FCB ) {
|
|
AcquireFcbAndFlushCache( IrpContext, fcb->NonPagedFcb );
|
|
}
|
|
|
|
Status = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"F-rd=",
|
|
NCP_WRITE_FILE,
|
|
&Icb->Handle, sizeof( Icb->Handle ),
|
|
Buffer->EndOfFile.LowPart );
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
*pFileSize = Buffer->EndOfFile.LowPart;
|
|
}
|
|
}
|
|
|
|
NwDequeueIrpContext( IrpContext, FALSE );
|
|
|
|
return( Status );
|
|
}
|
|
|
|
|
|
ULONG
|
|
OccurenceCount (
|
|
IN PUNICODE_STRING String,
|
|
IN WCHAR SearchChar
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine counts the number of occurences of a search character
|
|
in a string
|
|
|
|
Arguments:
|
|
|
|
String - The string to search
|
|
|
|
SearchChar - The character to search for.
|
|
|
|
Return Value:
|
|
|
|
The occurence count.
|
|
|
|
--*/
|
|
{
|
|
PWCH currentChar;
|
|
PWCH endOfString;
|
|
ULONG count = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
currentChar = String->Buffer;
|
|
endOfString = &String->Buffer[ String->Length / sizeof(WCHAR) ];
|
|
|
|
while ( currentChar < endOfString ) {
|
|
if ( *currentChar == SearchChar ) {
|
|
count++;
|
|
}
|
|
currentChar++;
|
|
}
|
|
|
|
return( count );
|
|
}
|