summaryrefslogtreecommitdiffstats
path: root/private/nw/rdr/fileinfo.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/nw/rdr/fileinfo.c')
-rw-r--r--private/nw/rdr/fileinfo.c2905
1 files changed, 2905 insertions, 0 deletions
diff --git a/private/nw/rdr/fileinfo.c b/private/nw/rdr/fileinfo.c
new file mode 100644
index 000000000..e9453a317
--- /dev/null
+++ b/private/nw/rdr/fileinfo.c
@@ -0,0 +1,2905 @@
+/*++
+
+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
+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)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)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;
+
+ 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)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)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
+ );
+
+ 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;
+
+ 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);
+ }
+
+ } 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
+ );
+
+ 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;
+
+ //
+ // 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
+ );
+
+ 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;
+}
+#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.
+ //
+
+ 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;
+
+ }
+}
+#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.LowPart = (ULONG)Icb->NpFcb;
+ Buffer->IndexNumber.HighPart = 0;
+
+ 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
+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;
+
+#if 0 // BUGBUG Was I on drugs? Below seems to be false, remove the check
+ ASSERT ( BooleanFlagOn( Fcb->Flags, FCB_FLAGS_ATTRIBUTES_ARE_VALID ) );
+
+ //
+ // Do not allow delete of read-only file, the netware server will
+ // allow it.
+ //
+
+ if ( Icb->NpFcb->Attributes & NW_ATTRIBUTE_READ_ONLY ) {
+ return( STATUS_ACCESS_DENIED );
+ }
+#endif
+
+ 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 ) ) {
+
+ 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 );
+}