Beispiel #1
0
NTSTATUS
FFSWriteFile(
	IN PFFS_IRP_CONTEXT IrpContext)
{
	NTSTATUS            Status = STATUS_UNSUCCESSFUL;

	PFFS_VCB            Vcb  = NULL;
	PFFS_FCB            Fcb  = NULL;
	PFFS_CCB            Ccb =  NULL;
	PFILE_OBJECT        FileObject  = NULL;
	PFILE_OBJECT        CacheObject;

	PDEVICE_OBJECT      DeviceObject  = NULL;

	PIRP                Irp  = NULL;
	PIO_STACK_LOCATION  IoStackLocation  = NULL;

	ULONG               Length;
	ULONG               ReturnedLength = 0;
	LARGE_INTEGER       ByteOffset;

	BOOLEAN             PagingIo;
	BOOLEAN             Nocache;
	BOOLEAN             SynchronousIo;
	BOOLEAN             MainResourceAcquired = FALSE;
	BOOLEAN             PagingIoResourceAcquired = FALSE;

	BOOLEAN             bNeedExtending = FALSE;
	BOOLEAN             bAppendFile = FALSE;

	BOOLEAN             bDeferred = FALSE;

	PUCHAR              Buffer = NULL;

	__try
	{
		ASSERT(IrpContext);

		ASSERT((IrpContext->Identifier.Type == FFSICX) &&
				(IrpContext->Identifier.Size == sizeof(FFS_IRP_CONTEXT)));

		DeviceObject = IrpContext->DeviceObject;

		Vcb = (PFFS_VCB)DeviceObject->DeviceExtension;

		ASSERT(Vcb != NULL);

		ASSERT((Vcb->Identifier.Type == FFSVCB) &&
				(Vcb->Identifier.Size == sizeof(FFS_VCB)));

		FileObject = IrpContext->FileObject;

		Fcb = (PFFS_FCB)FileObject->FsContext;

		ASSERT(Fcb);

		ASSERT((Fcb->Identifier.Type == FFSFCB) &&
				(Fcb->Identifier.Size == sizeof(FFS_FCB)));

		Ccb = (PFFS_CCB)FileObject->FsContext2;

		Irp = IrpContext->Irp;

		IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

		Length = IoStackLocation->Parameters.Write.Length;
		ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;

		PagingIo = (Irp->Flags & IRP_PAGING_IO ? TRUE : FALSE);
		Nocache = (Irp->Flags & IRP_NOCACHE ? TRUE : FALSE);
		SynchronousIo = (FileObject->Flags & FO_SYNCHRONOUS_IO ? TRUE : FALSE);

		FFSPrint((DBG_INFO, "FFSWriteFile: Off=%I64xh Len=%xh Paging=%xh Nocache=%xh\n",
					ByteOffset.QuadPart, Length, PagingIo, Nocache));

		/*
		if (IsFlagOn(Fcb->Flags, FCB_FILE_DELETED))
		{
			Status = STATUS_FILE_DELETED;
			__leave;
		}

		if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING))
		{
			Status = STATUS_DELETE_PENDING;
			__leave;
		}
		*/

		if (Length == 0)
		{
			Irp->IoStatus.Information = 0;
			Status = STATUS_SUCCESS;
			__leave;
		}

		if (Nocache &&
				(ByteOffset.LowPart & (SECTOR_SIZE - 1) ||
				 Length & (SECTOR_SIZE - 1)))
		{
			Status = STATUS_INVALID_PARAMETER;
			__leave;
		}

		if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC))
		{
			ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
			Status = STATUS_PENDING;
			__leave;
		}

#if FALSE
		if (!Nocache)
		{
			BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
			BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
			BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);

			if (!CcCanIWrite(
						FileObject,
						Length,
						(bWait && bQueue),
						bAgain))
			{
				SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);

				CcDeferWrite(FileObject,
						(PCC_POST_DEFERRED_WRITE)FFSDeferWrite,
						IrpContext,
						Irp,
						Length,
						bAgain);

				bDeferred = TRUE;

				FFSBreakPoint();

				Status = STATUS_PENDING;
				__leave;
			}
		}

#endif

		if (IsEndOfFile(ByteOffset))
		{
			bAppendFile = TRUE;
			ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
		}

		if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY) && !PagingIo)
		{
			Status = STATUS_INVALID_DEVICE_REQUEST;
			__leave;
		}

		//
		//  Do flushing for such cases
		//
		if (Nocache && !PagingIo && (Fcb->SectionObject.DataSectionObject != NULL)) 
		{
			ExAcquireResourceExclusive(&Fcb->MainResource, 
					IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));

			MainResourceAcquired = TRUE;

			ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
			ExReleaseResource(&Fcb->PagingIoResource);

			CcFlushCache(&(Fcb->SectionObject),
					&ByteOffset,
					Length,
					&(Irp->IoStatus));
			ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);

			if (!NT_SUCCESS(Irp->IoStatus.Status)) 
			{
				Status = Irp->IoStatus.Status;
				__leave;
			}

			ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
			ExReleaseResource(&Fcb->PagingIoResource);

			CcPurgeCacheSection(&(Fcb->SectionObject),
					(PLARGE_INTEGER)&(ByteOffset),
					Length,
					FALSE);

			ExReleaseResource(&Fcb->MainResource);
			MainResourceAcquired = FALSE;
		}

		if (!PagingIo)
		{
			if (!ExAcquireResourceExclusiveLite(
						&Fcb->MainResource,
						IrpContext->IsSynchronous))
			{
				Status = STATUS_PENDING;
				__leave;
			}

			MainResourceAcquired = TRUE;
		}
		else
		{
			/*
			ULONG ResShCnt, ResExCnt; 
			ResShCnt = ExIsResourceAcquiredSharedLite(&Fcb->PagingIoResource);
			ResExCnt = ExIsResourceAcquiredExclusiveLite(&Fcb->PagingIoResource);

			FFSPrint((DBG_USER, "FFSWriteFile: Inode=%xh %S PagingIo: %xh:%xh Synchronous=%xh\n",
			Fcb->FFSMcb->Inode, Fcb->FFSMcb->ShortName.Buffer, ResShCnt, ResExCnt, IrpContext->IsSynchronous));
			*/
			if (!ExAcquireResourceSharedLite(
						&Fcb->PagingIoResource,
						IrpContext->IsSynchronous))
			{
				Status = STATUS_PENDING;
				__leave;
			}

			PagingIoResourceAcquired = TRUE;
		}

		if (!PagingIo)
		{
			if (!FsRtlCheckLockForWriteAccess(
						&Fcb->FileLockAnchor,
						Irp))
			{
				Status = STATUS_FILE_LOCK_CONFLICT;
				__leave;
			}
		}

		if (Nocache)
		{
			if ((ByteOffset.QuadPart + Length) >
					Fcb->Header.AllocationSize.QuadPart)
			{
				if (ByteOffset.QuadPart >= 
						Fcb->Header.AllocationSize.QuadPart)
				{
					Status = STATUS_SUCCESS;
					Irp->IoStatus.Information = 0;
					__leave;
				}
				else
				{
					if (Length > (ULONG)(Fcb->Header.AllocationSize.QuadPart
								- ByteOffset.QuadPart))
					{
						Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart
								- ByteOffset.QuadPart);
					}
				}
			}
		}

		if (!Nocache)
		{
			if (FlagOn(Fcb->FFSMcb->FileAttr, FILE_ATTRIBUTE_DIRECTORY))
			{
				__leave;
			}

			if (FileObject->PrivateCacheMap == NULL)
			{
				CcInitializeCacheMap(
						FileObject,
						(PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
						FALSE,
						&FFSGlobal->CacheManagerCallbacks,
						Fcb);

				CcSetReadAheadGranularity(
						FileObject,
						READ_AHEAD_GRANULARITY);

				CcSetFileSizes(
						FileObject, 
						(PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
			}

			CacheObject = FileObject;

			//
			//  Need extending the size of inode ?
			//
			if ((bAppendFile) || ((ULONG)(ByteOffset.QuadPart + Length) >
						(ULONG)(Fcb->Header.FileSize.QuadPart)))
			{

				LARGE_INTEGER   ExtendSize;
				LARGE_INTEGER   FileSize;

				bNeedExtending = TRUE;
				FileSize = Fcb->Header.FileSize;
				ExtendSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length);

				if (ExtendSize.QuadPart > Fcb->Header.AllocationSize.QuadPart)
				{
					if (!FFSExpandFile(IrpContext, Vcb, Fcb, &ExtendSize))
					{
						Status = STATUS_INSUFFICIENT_RESOURCES;
						__leave;
					}
				}

				{
					Fcb->Header.FileSize.QuadPart = ExtendSize.QuadPart;
					Fcb->dinode1->di_size = (ULONG)ExtendSize.QuadPart;
				}

				if (FileObject->PrivateCacheMap)
				{
					CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));

					if (ByteOffset.QuadPart > FileSize.QuadPart)
					{
						FFSZeroHoles(IrpContext, Vcb, FileObject, FileSize.QuadPart, 
								ByteOffset.QuadPart - FileSize.QuadPart);
					}

					if (Fcb->Header.AllocationSize.QuadPart > ExtendSize.QuadPart)
					{
						FFSZeroHoles(IrpContext, Vcb, FileObject, ExtendSize.QuadPart, 
								Fcb->Header.AllocationSize.QuadPart - ExtendSize.QuadPart);
					}
				}

				if (FFSv1SaveInode(IrpContext, Vcb, Fcb->FFSMcb->Inode, Fcb->dinode1))
				{
					Status = STATUS_SUCCESS;
				}

				FFSNotifyReportChange(
						IrpContext,
						Vcb,
						Fcb,
						FILE_NOTIFY_CHANGE_SIZE,
						FILE_ACTION_MODIFIED);
			}

			if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL))
			{
				CcPrepareMdlWrite(
						CacheObject,
						(&ByteOffset),
						Length,
						&Irp->MdlAddress,
						&Irp->IoStatus);

				Status = Irp->IoStatus.Status;
			}
			else
			{
				Buffer = FFSGetUserBuffer(Irp);

				if (Buffer == NULL)
				{
					FFSBreakPoint();
					Status = STATUS_INVALID_USER_BUFFER;
					__leave;
				}

				if (!CcCopyWrite(
							CacheObject,
							(PLARGE_INTEGER)&ByteOffset,
							Length,
							IrpContext->IsSynchronous,
							Buffer))
				{
					Status = STATUS_PENDING;
					__leave;
				}

				Status = Irp->IoStatus.Status;
			}

			if (NT_SUCCESS(Status))
			{
				Irp->IoStatus.Information = Length;

				if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK))
				{
					FFSPrint((DBG_USER, "FFSWriteFile is starting FlushingDpc...\n"));
					FFSStartFloppyFlushDpc(Vcb, Fcb, FileObject);
				}
			}
		}
		else
		{
			ReturnedLength = Length;

			Status = FFSLockUserBuffer(
					IrpContext->Irp,
					Length,
					IoReadAccess);

			if (!NT_SUCCESS(Status))
			{
				__leave;
			}

			Irp->IoStatus.Status = STATUS_SUCCESS;
			Irp->IoStatus.Information = Length;

			Status = 
				FFSv1WriteInode(
						IrpContext,
						Vcb,
						Fcb->dinode1,
						(ULONGLONG)(ByteOffset.QuadPart),
						NULL,
						Length,
						TRUE,
						&ReturnedLength);

			Irp = IrpContext->Irp;

		}
	}

	__finally
	{
		if (PagingIoResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Fcb->PagingIoResource,
					ExGetCurrentResourceThread());
		}

		if (MainResourceAcquired)
		{
			ExReleaseResourceForThreadLite(
					&Fcb->MainResource,
					ExGetCurrentResourceThread());
		}

		if (!IrpContext->ExceptionInProgress)
		{
			if (Irp)
			{
				if (Status == STATUS_PENDING)
				{
					if (!bDeferred)
					{
						Status = FFSLockUserBuffer(
									IrpContext->Irp,
									Length,
									IoReadAccess);

						if (NT_SUCCESS(Status))
						{
							Status = FFSQueueRequest(IrpContext);
						}
						else
						{
							FFSCompleteIrpContext(IrpContext, Status);
						}
					}
				}
				else
				{
					if (NT_SUCCESS(Status))
					{
						if (SynchronousIo && !PagingIo)
						{
							FileObject->CurrentByteOffset.QuadPart =
								ByteOffset.QuadPart + Irp->IoStatus.Information;
						}

						if (!PagingIo)
						{
							SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
							SetFlag(Fcb->Flags, FCB_FILE_MODIFIED);
						}
					}

					FFSCompleteIrpContext(IrpContext, Status);
				}
			}
			else
			{
				FFSFreeIrpContext(IrpContext);
			}
		}
	}

	return Status;

}
Beispiel #2
0
NTSTATUS
VfatWrite(
    PVFAT_IRP_CONTEXT IrpContext)
{
    PVFATFCB Fcb;
    PERESOURCE Resource = NULL;
    LARGE_INTEGER ByteOffset;
    LARGE_INTEGER OldFileSize;
    NTSTATUS Status = STATUS_SUCCESS;
    ULONG Length = 0;
    PVOID Buffer;
    ULONG BytesPerSector;

    ASSERT(IrpContext);

    DPRINT("VfatWrite(IrpContext %p)\n", IrpContext);

    ASSERT(IrpContext->DeviceObject);

    // This request is not allowed on the main device object
    if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject)
    {
        DPRINT("VfatWrite is called with the main device object.\n");
        Status = STATUS_INVALID_DEVICE_REQUEST;
        goto ByeBye;
    }

    ASSERT(IrpContext->DeviceExt);
    ASSERT(IrpContext->FileObject);
    Fcb = IrpContext->FileObject->FsContext;
    ASSERT(Fcb);

    if (Fcb->Flags & FCB_IS_PAGE_FILE)
    {
        PFATINFO FatInfo = &IrpContext->DeviceExt->FatInfo;
        IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart += FatInfo->dataStart * FatInfo->BytesPerSector;
        IoSkipCurrentIrpStackLocation(IrpContext->Irp);
        DPRINT("Write to page file, disk offset %I64x\n", IrpContext->Stack->Parameters.Write.ByteOffset.QuadPart);
        Status = IoCallDriver(IrpContext->DeviceExt->StorageDevice, IrpContext->Irp);
        VfatFreeIrpContext(IrpContext);
        return Status;
    }

    DPRINT("<%wZ>\n", &Fcb->PathNameU);

    /* fail if file is a directory and no paged read */
    if (*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY && !(IrpContext->Irp->Flags & IRP_PAGING_IO))
    {
        Status = STATUS_INVALID_PARAMETER;
        goto ByeBye;
    }

    ByteOffset = IrpContext->Stack->Parameters.Write.ByteOffset;
    if (ByteOffset.u.LowPart == FILE_WRITE_TO_END_OF_FILE &&
        ByteOffset.u.HighPart == -1)
    {
        ByteOffset.QuadPart = Fcb->RFCB.FileSize.QuadPart;
    }
    Length = IrpContext->Stack->Parameters.Write.Length;
    BytesPerSector = IrpContext->DeviceExt->FatInfo.BytesPerSector;

    if (ByteOffset.u.HighPart && !(Fcb->Flags & FCB_IS_VOLUME))
    {
        Status = STATUS_INVALID_PARAMETER;
        goto ByeBye;
    }

    if (Fcb->Flags & (FCB_IS_FAT | FCB_IS_VOLUME) ||
        vfatDirEntryGetFirstCluster(IrpContext->DeviceExt, &Fcb->entry) == 1)
    {
        if (ByteOffset.QuadPart + Length > Fcb->RFCB.FileSize.QuadPart)
        {
            // we can't extend the FAT, the volume or the root on FAT12/FAT16
            Status = STATUS_END_OF_FILE;
            goto ByeBye;
        }
    }

    if (IrpContext->Irp->Flags & (IRP_PAGING_IO|IRP_NOCACHE) || (Fcb->Flags & FCB_IS_VOLUME))
    {
        if (ByteOffset.u.LowPart % BytesPerSector != 0 || Length % BytesPerSector != 0)
        {
            // non cached write must be sector aligned
            Status = STATUS_INVALID_PARAMETER;
            goto ByeBye;
        }
    }

    if (Length == 0)
    {
        /* FIXME: Update last write time */
        IrpContext->Irp->IoStatus.Information = 0;
        Status = STATUS_SUCCESS;
        goto ByeBye;
    }

    if (IrpContext->Irp->Flags & IRP_PAGING_IO)
    {
        if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
        {
            Status = STATUS_INVALID_PARAMETER;
            goto ByeBye;
        }

        if (ByteOffset.u.LowPart + Length > ROUND_UP(Fcb->RFCB.AllocationSize.u.LowPart, BytesPerSector))
        {
            Length =  ROUND_UP(Fcb->RFCB.FileSize.u.LowPart, BytesPerSector) - ByteOffset.u.LowPart;
        }
    }

    if (Fcb->Flags & FCB_IS_VOLUME)
    {
        Resource = &IrpContext->DeviceExt->DirResource;
    }
    else if (IrpContext->Irp->Flags & IRP_PAGING_IO)
    {
        Resource = &Fcb->PagingIoResource;
    }
    else
    {
        Resource = &Fcb->MainResource;
    }

    if (Fcb->Flags & FCB_IS_PAGE_FILE)
    {
        if (!ExAcquireResourceSharedLite(Resource,
                                         (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
        {
            Resource = NULL;
            Status = STATUS_PENDING;
            goto ByeBye;
        }
    }
    else
    {
        if (!ExAcquireResourceExclusiveLite(Resource,
                                            (BOOLEAN)(IrpContext->Flags & IRPCONTEXT_CANWAIT)))
        {
            Resource = NULL;
            Status = STATUS_PENDING;
            goto ByeBye;
        }
    }

    if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
        FsRtlAreThereCurrentFileLocks(&Fcb->FileLock))
    {
        if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLock, IrpContext->Irp))
        {
            Status = STATUS_FILE_LOCK_CONFLICT;
            goto ByeBye;
        }
    }

    if (!(IrpContext->Flags & IRPCONTEXT_CANWAIT) && !(Fcb->Flags & FCB_IS_VOLUME))
    {
        if (ByteOffset.u.LowPart + Length > Fcb->RFCB.AllocationSize.u.LowPart)
        {
            Status = STATUS_PENDING;
            goto ByeBye;
        }
    }

    OldFileSize = Fcb->RFCB.FileSize;

    Buffer = VfatGetUserBuffer(IrpContext->Irp);
    if (!Buffer)
    {
        Status = STATUS_INVALID_USER_BUFFER;
        goto ByeBye;
    }


    if (!(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)) &&
        !(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
        ByteOffset.u.LowPart + Length > Fcb->RFCB.FileSize.u.LowPart)
    {
        LARGE_INTEGER AllocationSize;
        AllocationSize.QuadPart = ByteOffset.u.LowPart + Length;
        Status = VfatSetAllocationSizeInformation(IrpContext->FileObject, Fcb,
                                                  IrpContext->DeviceExt, &AllocationSize);
        if (!NT_SUCCESS (Status))
        {
            goto ByeBye;
        }
    }

    if (!(IrpContext->Irp->Flags & (IRP_NOCACHE|IRP_PAGING_IO)) &&
        !(Fcb->Flags & (FCB_IS_PAGE_FILE|FCB_IS_VOLUME)))
    {
        // cached write

        if (IrpContext->FileObject->PrivateCacheMap == NULL)
        {
            CcInitializeCacheMap(IrpContext->FileObject,
                                 (PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
                                 FALSE,
                                 &VfatGlobalData->CacheMgrCallbacks,
                                 Fcb);
        }

        if (ByteOffset.QuadPart > OldFileSize.QuadPart)
        {
            CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
        }

        if (CcCopyWrite(IrpContext->FileObject, &ByteOffset, Length,
                        1 /*IrpContext->Flags & IRPCONTEXT_CANWAIT*/, Buffer))
        {
            IrpContext->Irp->IoStatus.Information = Length;
            Status = STATUS_SUCCESS;
        }
        else
        {
            Status = STATUS_UNSUCCESSFUL;
        }
    }
    else
    {
        // non cached write

        if (ByteOffset.QuadPart > OldFileSize.QuadPart)
        {
            CcZeroData(IrpContext->FileObject, &OldFileSize, &ByteOffset, TRUE);
        }

        Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
        if (!NT_SUCCESS(Status))
        {
            goto ByeBye;
        }

        Status = VfatWriteFileData(IrpContext, Length, ByteOffset);
        if (NT_SUCCESS(Status))
        {
            IrpContext->Irp->IoStatus.Information = Length;
        }
    }

    if (!(IrpContext->Irp->Flags & IRP_PAGING_IO) &&
        !(Fcb->Flags & (FCB_IS_FAT|FCB_IS_VOLUME)))
    {
        if(!(*Fcb->Attributes & FILE_ATTRIBUTE_DIRECTORY))
        {
            LARGE_INTEGER SystemTime;
            // set dates and times
            KeQuerySystemTime (&SystemTime);
            if (Fcb->Flags & FCB_IS_FATX_ENTRY)
            {
                FsdSystemTimeToDosDateTime(IrpContext->DeviceExt,
                                           &SystemTime, &Fcb->entry.FatX.UpdateDate,
                                           &Fcb->entry.FatX.UpdateTime);
                Fcb->entry.FatX.AccessDate = Fcb->entry.FatX.UpdateDate;
                Fcb->entry.FatX.AccessTime = Fcb->entry.FatX.UpdateTime;
            }
            else
            {
                FsdSystemTimeToDosDateTime(IrpContext->DeviceExt,
                                           &SystemTime, &Fcb->entry.Fat.UpdateDate,
                                           &Fcb->entry.Fat.UpdateTime);
                Fcb->entry.Fat.AccessDate = Fcb->entry.Fat.UpdateDate;
            }
            /* set date and times to dirty */
            Fcb->Flags |= FCB_IS_DIRTY;
        }
    }

ByeBye:
    if (Resource)
    {
        ExReleaseResourceLite(Resource);
    }

    if (Status == STATUS_PENDING)
    {
        Status = VfatLockUserBuffer(IrpContext->Irp, Length, IoReadAccess);
        if (NT_SUCCESS(Status))
        {
            Status = VfatQueueRequest(IrpContext);
        }
        else
        {
            IrpContext->Irp->IoStatus.Status = Status;
            IoCompleteRequest(IrpContext->Irp, IO_NO_INCREMENT);
            VfatFreeIrpContext(IrpContext);
        }
    }
    else
    {
        IrpContext->Irp->IoStatus.Status = Status;
        if (IrpContext->FileObject->Flags & FO_SYNCHRONOUS_IO &&
            !(IrpContext->Irp->Flags & IRP_PAGING_IO) && NT_SUCCESS(Status))
        {
            IrpContext->FileObject->CurrentByteOffset.QuadPart =
                ByteOffset.QuadPart + IrpContext->Irp->IoStatus.Information;
        }

        IoCompleteRequest(IrpContext->Irp,
                          (CCHAR)(NT_SUCCESS(Status) ? IO_DISK_INCREMENT : IO_NO_INCREMENT));
        VfatFreeIrpContext(IrpContext);
    }
    DPRINT("%x\n", Status);
    return Status;
}
Beispiel #3
0
static NTSTATUS FspFsvolWriteCached(
    PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
    BOOLEAN CanWait)
{
    PAGED_CODE();

    /* assert: must be top-level IRP */
    ASSERT(0 == FspIrpTopFlags(Irp));

    NTSTATUS Result;
    BOOLEAN Retrying = 0 != FspIrpRequest(Irp);
    PFILE_OBJECT FileObject = IrpSp->FileObject;
    FSP_FILE_NODE *FileNode = FileObject->FsContext;
    LARGE_INTEGER WriteOffset = IrpSp->Parameters.Write.ByteOffset;
    ULONG WriteLength = IrpSp->Parameters.Write.Length;
    BOOLEAN WriteToEndOfFile =
        FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart;
    BOOLEAN SynchronousIo = BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);
    FSP_FSCTL_FILE_INFO FileInfo;
    CC_FILE_SIZES FileSizes;
    FILE_END_OF_FILE_INFORMATION EndOfFileInformation;
    UINT64 WriteEndOffset;
    BOOLEAN ExtendingFile;
    BOOLEAN Success;

    /* should we defer the write? */
    Success = DEBUGTEST(90) && CcCanIWrite(FileObject, WriteLength, CanWait, Retrying);
    if (!Success)
    {
        Result = FspWqCreateIrpWorkItem(Irp, FspFsvolWriteCached, 0);
        if (NT_SUCCESS(Result))
        {
            IoMarkIrpPending(Irp);
            CcDeferWrite(FileObject, FspFsvolWriteCachedDeferred, Irp, 0, WriteLength, Retrying);

            return STATUS_PENDING;
        }

        /* if we are unable to defer we will go ahead and (try to) service the IRP now! */
    }

    /* try to acquire the FileNode Main exclusive */
    Success = DEBUGTEST(90) &&
        FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireMain, CanWait);
    if (!Success)
        return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteCached, 0);

    /* perform oplock check */
    Result = FspFileNodeOplockCheckAsync(
        FileNode, FspFileNodeAcquireMain, FspFsvolWriteCached,
        Irp);
    if (STATUS_PENDING == Result)
        return Result;
    if (!NT_SUCCESS(Result))
    {
        FspFileNodeRelease(FileNode, Main);
        return Result;
    }

    /* check the file locks */
    if (!FsRtlCheckLockForWriteAccess(&FileNode->FileLock, Irp))
    {
        FspFileNodeRelease(FileNode, Main);
        return STATUS_FILE_LOCK_CONFLICT;
    }

    /* compute new file size */
    ASSERT(FspTimeoutInfinity32 ==
        FspFsvolDeviceExtension(FsvolDeviceObject)->VolumeParams.FileInfoTimeout);
    FspFileNodeGetFileInfo(FileNode, &FileInfo);
    if (WriteToEndOfFile)
        WriteOffset.QuadPart = FileInfo.FileSize;
    WriteEndOffset = WriteOffset.QuadPart + WriteLength;
    ExtendingFile = FileInfo.FileSize < WriteEndOffset;
    if (ExtendingFile && !CanWait)
    {
        /* need CanWait==TRUE for FspSendSetInformationIrp */
        FspFileNodeRelease(FileNode, Main);
        return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteCached, 0);
    }

    /* initialize cache if not already initialized! */
    if (0 == FileObject->PrivateCacheMap)
    {
        FileSizes.AllocationSize.QuadPart = FileInfo.AllocationSize;
        FileSizes.FileSize.QuadPart = FileInfo.FileSize;
        FileSizes.ValidDataLength.QuadPart = MAXLONGLONG;

        Result = FspCcInitializeCacheMap(FileObject, &FileSizes, FALSE,
            &FspCacheManagerCallbacks, FileNode);
        if (!NT_SUCCESS(Result))
        {
            FspFileNodeRelease(FileNode, Main);
            return Result;
        }
    }

    /* are we extending the file? */
    if (ExtendingFile)
    {
        ASSERT(CanWait);

        /* send EndOfFileInformation IRP; this will also set TruncateOnClose, etc. */
        EndOfFileInformation.EndOfFile.QuadPart = WriteEndOffset;
        Result = FspSendSetInformationIrp(FsvolDeviceObject/* bypass filters */, FileObject,
            FileEndOfFileInformation, &EndOfFileInformation, sizeof EndOfFileInformation);
        if (!NT_SUCCESS(Result))
        {
            FspFileNodeRelease(FileNode, Main);
            return Result;
        }

        /* double-check that the cache still exists in case CcSetFileSizes failed */
        if (0 == FileObject->SectionObjectPointer->SharedCacheMap)
        {
            FspFileNodeRelease(FileNode, Main);
            return STATUS_INSUFFICIENT_RESOURCES; // or STATUS_SECTION_TOO_BIG?
        }
    }

    /*
     * From this point forward we must jump to the CLEANUP label on failure.
     */

    /* are we using the copy or MDL interface? */
    if (!FlagOn(IrpSp->MinorFunction, IRP_MN_MDL))
    {
        PVOID Buffer;

        Buffer = 0 == Irp->MdlAddress ?
            Irp->UserBuffer : MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
        if (0 == Buffer)
        {
            Result = STATUS_INSUFFICIENT_RESOURCES;
            goto cleanup;
        }

        Result = FspCcCopyWrite(FileObject, &WriteOffset, WriteLength, CanWait, Buffer);
        if (!NT_SUCCESS(Result) || STATUS_PENDING == Result)
            goto cleanup;

        Irp->IoStatus.Information = WriteLength;
    }
    else
    {
        Result = FspCcPrepareMdlWrite(FileObject, &WriteOffset, WriteLength, &Irp->MdlAddress,
            &Irp->IoStatus);
        if (!NT_SUCCESS(Result))
            goto cleanup;
        ASSERT(STATUS_PENDING != Result);
    }

    /* update the current file offset if synchronous I/O */
    if (SynchronousIo)
        FileObject->CurrentByteOffset.QuadPart = WriteEndOffset;

    /* mark the file object as modified (if not paging I/O) */
    SetFlag(FileObject->Flags, FO_FILE_MODIFIED);

    FspFileNodeRelease(FileNode, Main);

    return STATUS_SUCCESS;

cleanup:
    FspFileNodeRelease(FileNode, Main);

    if (STATUS_PENDING == Result)
        return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteCached, 0);

    return Result;
}
Beispiel #4
0
NTSTATUS
Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
{
    PEXT2_VCB           Vcb = NULL;
    PEXT2_FCB           Fcb = NULL;
    PEXT2_CCB           Ccb = NULL;
    PFILE_OBJECT        FileObject = NULL;

    PDEVICE_OBJECT      DeviceObject = NULL;

    PIRP                Irp = NULL;
    PIO_STACK_LOCATION  IoStackLocation = NULL;
    PUCHAR              Buffer = NULL;

    LARGE_INTEGER       ByteOffset;
    ULONG               ReturnedLength = 0;
    ULONG               Length;

    NTSTATUS            Status = STATUS_UNSUCCESSFUL;

    BOOLEAN             OpPostIrp = FALSE;
    BOOLEAN             PagingIo = FALSE;
    BOOLEAN             Nocache = FALSE;
    BOOLEAN             SynchronousIo = FALSE;

    BOOLEAN             RecursiveWriteThrough = FALSE;
    BOOLEAN             MainResourceAcquired = FALSE;
    BOOLEAN             PagingIoResourceAcquired = FALSE;

    BOOLEAN             bDeferred = FALSE;
    BOOLEAN             UpdateFileValidSize = FALSE;
    BOOLEAN             FileSizesChanged = FALSE;
    BOOLEAN             rc;


    __try {

        ASSERT(IrpContext);
        ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
               (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));

        DeviceObject = IrpContext->DeviceObject;
        Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
        ASSERT(Vcb != NULL);
        ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
               (Vcb->Identifier.Size == sizeof(EXT2_VCB)));

        FileObject = IrpContext->FileObject;
        Fcb = (PEXT2_FCB) FileObject->FsContext;
        Ccb = (PEXT2_CCB) FileObject->FsContext2;
        ASSERT(Fcb);
        ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
               (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

        Irp = IrpContext->Irp;
        IoStackLocation = IoGetCurrentIrpStackLocation(Irp);

        Length = IoStackLocation->Parameters.Write.Length;
        ByteOffset = IoStackLocation->Parameters.Write.ByteOffset;

        PagingIo = IsFlagOn(Irp->Flags, IRP_PAGING_IO);
        Nocache = IsFlagOn(Irp->Flags, IRP_NOCACHE);
        SynchronousIo = IsFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO);

        if (PagingIo) {
            ASSERT(Nocache);
        }

        DEBUG(DL_INF, ("Ext2WriteFile: %wZ Offset=%I64xh Length=%xh Paging=%xh Nocache=%xh\n",
                       &Fcb->Mcb->ShortName, ByteOffset.QuadPart, Length, PagingIo, Nocache));

        if (IsSpecialFile(Fcb) || IsInodeSymLink(Fcb->Inode) ) {
            Status = STATUS_INVALID_DEVICE_REQUEST;
            __leave;
        }

        if (IsFileDeleted(Fcb->Mcb) ||
            (IsSymLink(Fcb) && IsFileDeleted(Fcb->Mcb->Target)) ) {
            Status = STATUS_FILE_DELETED;
            __leave;
        }

        if (Length == 0) {
            Irp->IoStatus.Information = 0;
            Status = STATUS_SUCCESS;
            __leave;
        }

        if (ByteOffset.LowPart == FILE_USE_FILE_POINTER_POSITION &&
            ByteOffset.HighPart == -1) {
            ByteOffset = FileObject->CurrentByteOffset;
        } else if (IsWritingToEof(ByteOffset)) {
            ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
        }

        if (Nocache && !PagingIo &&
            ( (ByteOffset.LowPart & (SECTOR_SIZE - 1)) ||
               (Length & (SECTOR_SIZE - 1))) ) {
            Status = STATUS_INVALID_PARAMETER;
            __leave;
        }

        if (FlagOn(IrpContext->MinorFunction, IRP_MN_DPC)) {
            ClearFlag(IrpContext->MinorFunction, IRP_MN_DPC);
            Status = STATUS_PENDING;
            __leave;
        }

        if (!Nocache) {

            BOOLEAN bAgain = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
            BOOLEAN bWait  = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
            BOOLEAN bQueue = IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_REQUEUED);

            if ( !CcCanIWrite(
                        FileObject,
                        Length,
                        (bWait && bQueue),
                        bAgain ) ) {

                Status = Ext2LockUserBuffer(
                             IrpContext->Irp,
                             Length,
                             IoReadAccess);

                if (NT_SUCCESS(Status)) {
                    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_DEFERRED);
                    CcDeferWrite( FileObject,
                                  (PCC_POST_DEFERRED_WRITE)Ext2DeferWrite,
                                  IrpContext,
                                  Irp,
                                  Length,
                                  bAgain );
                    bDeferred = TRUE;
                    Status = STATUS_PENDING;
                    __leave;
                }
            }
        }

        if (IsDirectory(Fcb) && !PagingIo) {
            Status = STATUS_INVALID_DEVICE_REQUEST;
            __leave;
        }

        if (IsFlagOn(Irp->Flags, IRP_SYNCHRONOUS_PAGING_IO) && !IrpContext->IsTopLevel) {

            PIRP TopIrp;

            TopIrp = IoGetTopLevelIrp();

            if ( (ULONG_PTR)TopIrp > FSRTL_MAX_TOP_LEVEL_IRP_FLAG &&
                    NodeType(TopIrp) == IO_TYPE_IRP) {

                PIO_STACK_LOCATION IrpStack;

                IrpStack = IoGetCurrentIrpStackLocation(TopIrp);

                if ((IrpStack->MajorFunction == IRP_MJ_WRITE) &&
                    (IrpStack->FileObject->FsContext == FileObject->FsContext) &&
                    !FlagOn(TopIrp->Flags, IRP_NOCACHE) ) {

                    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
                    RecursiveWriteThrough = TRUE;
                }
            }
        }

        if (PagingIo) {

            if (!ExAcquireResourceSharedLite(&Fcb->PagingIoResource, TRUE)) {
                Status = STATUS_PENDING;
                __leave;
            }
            PagingIoResourceAcquired = TRUE;

            if ( (ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) {

                if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {

                    Status = STATUS_SUCCESS;
                    Irp->IoStatus.Information = 0;
                    __leave;

                } else {

                    ReturnedLength = (ULONG)(Fcb->Header.FileSize.QuadPart - ByteOffset.QuadPart);
                    if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart)
                        Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
                }

            } else {

                ReturnedLength = Length;
            }

        } else {

            if (!Ext2CheckFileAccess(Vcb, Fcb->Mcb, Ext2FileCanWrite)) {
                Status = STATUS_ACCESS_DENIED;
                __leave;
            }

            if (IsDirectory(Fcb)) {
                __leave;
            }

            if (!ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE)) {
                Status = STATUS_PENDING;
                __leave;
            }
            MainResourceAcquired = TRUE;

            //
            //  Do flushing for such cases
            //
            if (Nocache && Ccb != NULL && Fcb->SectionObject.DataSectionObject != NULL)  {

                ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE);
                ExReleaseResourceLite(&Fcb->PagingIoResource);

                CcFlushCache( &(Fcb->SectionObject),
                              &ByteOffset,
                              CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE),
                              &(Irp->IoStatus));
                ClearLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);

                if (!NT_SUCCESS(Irp->IoStatus.Status)) {
                    Status = Irp->IoStatus.Status;
                    __leave;
                }

                ExAcquireSharedStarveExclusive( &Fcb->PagingIoResource, TRUE);
                ExReleaseResourceLite(&Fcb->PagingIoResource);

                CcPurgeCacheSection( &(Fcb->SectionObject),
                                     &(ByteOffset),
                                     CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE),
                                     FALSE );
            }

            if (!FsRtlCheckLockForWriteAccess(&Fcb->FileLockAnchor, Irp)) {
                Status = STATUS_FILE_LOCK_CONFLICT;
                __leave;
            }

            if (Ccb != NULL) {

                Status = FsRtlCheckOplock( &Fcb->Oplock,
                                           Irp,
                                           IrpContext,
                                           Ext2OplockComplete,
                                           Ext2LockIrp );

                if (Status != STATUS_SUCCESS) {
                    OpPostIrp = TRUE;
                    __leave;
                }

                //
                //  Set the flag indicating if Fast I/O is possible
                //

                Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
            }

            //
            //  Extend the inode size when the i/o is beyond the file end ?
            //

            if ((ByteOffset.QuadPart + Length) > Fcb->Header.FileSize.QuadPart) {

                LARGE_INTEGER AllocationSize, Last;

                if (!ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE)) {
                    Status = STATUS_PENDING;
                    __leave;
                }
                PagingIoResourceAcquired = TRUE;

                /* let this irp wait, since it has to be synchronous */
                SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);

                Last.QuadPart = Fcb->Header.AllocationSize.QuadPart;
                AllocationSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length);
                AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
                                          (ULONGLONG)AllocationSize.QuadPart,
                                          (ULONGLONG)BLOCK_SIZE);

                /* tell Ext2ExpandFile to allocate unwritten extent or NULL blocks
                   for indirect files, otherwise we might get gabage data in holes */
                IrpContext->MajorFunction += IRP_MJ_MAXIMUM_FUNCTION;
                Status = Ext2ExpandFile(IrpContext, Vcb, Fcb->Mcb, &AllocationSize);
                IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION;
                if (AllocationSize.QuadPart > Last.QuadPart) {
                    Fcb->Header.AllocationSize.QuadPart = AllocationSize.QuadPart;
                    SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_WRITE);
                }
                ExReleaseResourceLite(&Fcb->PagingIoResource);
                PagingIoResourceAcquired = FALSE;

                if (ByteOffset.QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
                    if (NT_SUCCESS(Status)) {
                        DbgBreak();
                        Status = STATUS_UNSUCCESSFUL;
                    }
                    __leave;
                }

                if (ByteOffset.QuadPart + Length > Fcb->Header.AllocationSize.QuadPart) {
                    Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - ByteOffset.QuadPart);
                }

                Fcb->Header.FileSize.QuadPart = Fcb->Inode->i_size = ByteOffset.QuadPart + Length;
                Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);

                if (CcIsFileCached(FileObject)) {
                    CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                }

                FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED;
                FileSizesChanged = TRUE;

                if (Fcb->Header.FileSize.QuadPart >= 0x80000000 &&
                        !IsFlagOn(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE)) {
                    SetFlag(SUPER_BLOCK->s_feature_ro_compat, EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
                    Ext2SaveSuper(IrpContext, Vcb);
                }

                DEBUG(DL_IO, ("Ext2WriteFile: expanding %wZ to FS: %I64xh FA: %I64xh\n",
                              &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart,
                              Fcb->Header.AllocationSize.QuadPart));
            }

            ReturnedLength = Length;
        }

        if (!Nocache) {

            if (FileObject->PrivateCacheMap == NULL) {
                CcInitializeCacheMap(
                    FileObject,
                    (PCC_FILE_SIZES)(&Fcb->Header.AllocationSize),
                    FALSE,
                    &Ext2Global->CacheManagerCallbacks,
                    Fcb );

                CcSetReadAheadGranularity(
                    FileObject,
                    READ_AHEAD_GRANULARITY );
            }

            if (FlagOn(IrpContext->MinorFunction, IRP_MN_MDL)) {

                CcPrepareMdlWrite(
                    FileObject,
                    &ByteOffset,
                    Length,
                    &Irp->MdlAddress,
                    &Irp->IoStatus );

                Status = Irp->IoStatus.Status;

            } else {

                Buffer = Ext2GetUserBuffer(Irp);
                if (Buffer == NULL) {
                    DbgBreak();
                    Status = STATUS_INVALID_USER_BUFFER;
                    __leave;
                }

                if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {

                    /* let this irp wait, since it has to be synchronous */
                    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);

                    rc = Ext2ZeroData(IrpContext, Vcb, FileObject,
                                      &Fcb->Header.ValidDataLength, &ByteOffset);
                    if (!rc) {
                        Status = STATUS_PENDING;
                        DbgBreak();
                        __leave;
                    }
                }

                if (!CcCopyWrite(FileObject, &ByteOffset, Length, Ext2CanIWait(), Buffer)) {
                    if (Ext2CanIWait() || 
                        !CcCopyWrite(FileObject,  &ByteOffset, Length, TRUE, Buffer)) {
                        Status = STATUS_PENDING;
                        DbgBreak();
                        __leave;
                    }
                }

                if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {

                    if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) {
                        Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
                    } else {
                        if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length)
                            Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length;
                    }

                    CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                    FileSizesChanged = TRUE;
                }

                Status = STATUS_SUCCESS;
            }

            if (NT_SUCCESS(Status)) {
                Irp->IoStatus.Information = Length;
                if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
                    DEBUG(DL_FLP, ("Ext2WriteFile is starting FlushingDpc...\n"));
                    Ext2StartFloppyFlushDpc(Vcb, Fcb, FileObject);
                }
            }

        } else {

            if (!PagingIo && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {
                if (ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {

                    /* let this irp wait, since it has to be synchronous */
                    SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
                    rc = Ext2ZeroData(IrpContext, Vcb, FileObject,
                                      &Fcb->Header.ValidDataLength,
                                      &ByteOffset);
                    if (!rc) {
                        Status = STATUS_PENDING;
                        DbgBreak();
                        __leave;
                    }
                }
            }

            Status = Ext2LockUserBuffer(
                         IrpContext->Irp,
                         Length,
                         IoReadAccess );

            if (!NT_SUCCESS(Status)) {
                __leave;
            }

            Irp->IoStatus.Status = STATUS_SUCCESS;
            Irp->IoStatus.Information = ReturnedLength;

            Status = Ext2WriteInode(
                         IrpContext,
                         Vcb,
                         Fcb->Mcb,
                         (ULONGLONG)(ByteOffset.QuadPart),
                         NULL,
                         ReturnedLength,
                         TRUE,
                         &Length
                     );

            Irp = IrpContext->Irp;

            if (NT_SUCCESS(Status) && !RecursiveWriteThrough && !IsLazyWriter(Fcb)) {

                if (ByteOffset.QuadPart + Length > Fcb->Header.ValidDataLength.QuadPart ) {

                    FileSizesChanged = TRUE;

                    if (Fcb->Header.FileSize.QuadPart < ByteOffset.QuadPart + Length) {
                        if (!PagingIo)
                            Fcb->Header.FileSize.QuadPart = ByteOffset.QuadPart + Length;
                        Fcb->Header.ValidDataLength.QuadPart = Fcb->Header.FileSize.QuadPart;
                    } else {
                        if (Fcb->Header.ValidDataLength.QuadPart < ByteOffset.QuadPart + Length)
                            Fcb->Header.ValidDataLength.QuadPart = ByteOffset.QuadPart + Length;
                    }

                    if (!PagingIo && CcIsFileCached(FileObject)) {
                        CcSetFileSizes(FileObject, (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                    }

                    DEBUG(DL_IO, ("Ext2WriteFile: %wZ written FS: %I64xh FA: %I64xh BO: %I64xh LEN: %u\n",
                                  &Fcb->Mcb->ShortName, Fcb->Header.FileSize.QuadPart,
                                   Fcb->Header.AllocationSize.QuadPart, ByteOffset.QuadPart, Length));
                }
            }
        }

        if (FileSizesChanged) {
            FileObject->Flags |= FO_FILE_SIZE_CHANGED | FO_FILE_MODIFIED;
            Ext2NotifyReportChange( IrpContext,  Vcb, Fcb->Mcb,
                                    FILE_NOTIFY_CHANGE_SIZE,
                                    FILE_ACTION_MODIFIED );
        }

    } __finally {

        /*
         *  in case we got excpetions, we need revert MajorFunction
         *  back to IRP_MJ_WRITE. The reason we do this, is to tell
         *  Ext2ExpandFile to allocate unwritten extent or don't add
         *  new blocks for indirect files.
         */
        if (IrpContext->MajorFunction > IRP_MJ_MAXIMUM_FUNCTION)
            IrpContext->MajorFunction -= IRP_MJ_MAXIMUM_FUNCTION;

        if (Irp) {
            if (PagingIoResourceAcquired) {
                ExReleaseResourceLite(&Fcb->PagingIoResource);
            }

            if (MainResourceAcquired) {
                ExReleaseResourceLite(&Fcb->MainResource);
            }
        }

        if (!OpPostIrp && !IrpContext->ExceptionInProgress) {

            if (Irp) {

                if (Status == STATUS_PENDING ||
                        Status == STATUS_CANT_WAIT ) {

                    if (!bDeferred) {
                        Status = Ext2QueueRequest(IrpContext);
                    }

                } else {

                    if (NT_SUCCESS(Status) && !PagingIo) {

                        if (SynchronousIo) {
                            FileObject->CurrentByteOffset.QuadPart =
                                ByteOffset.QuadPart + Irp->IoStatus.Information;
                        }

                        SetFlag(FileObject->Flags, FO_FILE_MODIFIED);
                        SetLongFlag(Fcb->Flags, FCB_FILE_MODIFIED);
                    }

                    Ext2CompleteIrpContext(IrpContext, Status);
                }
            } else {
                Ext2FreeIrpContext(IrpContext);
            }
        }
    }

    DEBUG(DL_IO, ("Ext2WriteFile: %wZ written at Offset=%I64xh Length=%xh PagingIo=%d Nocache=%d "
                  "RetLen=%xh VDL=%I64xh FileSize=%I64xh i_size=%I64xh Status=%xh\n",
                  &Fcb->Mcb->ShortName, ByteOffset, Length, PagingIo, Nocache, ReturnedLength,
                  Fcb->Header.ValidDataLength.QuadPart,Fcb->Header.FileSize.QuadPart,
                  Fcb->Inode->i_size, Status));

    return Status;
}
Beispiel #5
0
static NTSTATUS FspFsvolWriteNonCached(
    PDEVICE_OBJECT FsvolDeviceObject, PIRP Irp, PIO_STACK_LOCATION IrpSp,
    BOOLEAN CanWait)
{
    PAGED_CODE();

    /* assert: either a top-level IRP or Paging I/O */
    ASSERT(0 == FspIrpTopFlags(Irp) || FlagOn(Irp->Flags, IRP_PAGING_IO));

    NTSTATUS Result;
    PFILE_OBJECT FileObject = IrpSp->FileObject;
    FSP_FILE_NODE *FileNode = FileObject->FsContext;
    FSP_FILE_DESC *FileDesc = FileObject->FsContext2;
    LARGE_INTEGER WriteOffset = IrpSp->Parameters.Write.ByteOffset;
    ULONG WriteLength = IrpSp->Parameters.Write.Length;
    ULONG WriteKey = IrpSp->Parameters.Write.Key;
    BOOLEAN WriteToEndOfFile =
        FILE_WRITE_TO_END_OF_FILE == WriteOffset.LowPart && -1L == WriteOffset.HighPart;
    BOOLEAN PagingIo = BooleanFlagOn(Irp->Flags, IRP_PAGING_IO);
    FSP_FSCTL_TRANSACT_REQ *Request;
    BOOLEAN Success;

    ASSERT(FileNode == FileDesc->FileNode);

    /* no MDL requests on the non-cached path */
    if (FlagOn(IrpSp->MinorFunction, IRP_MN_MDL))
        return STATUS_INVALID_PARAMETER;

    /* paging I/O cannot change the file size */
    if (PagingIo && WriteToEndOfFile)
        return STATUS_INVALID_PARAMETER;

    /* stop CcWriteBehind from calling me! */
    if (FspIoqStopped(FspFsvolDeviceExtension(FsvolDeviceObject)->Ioq))
        return FspFsvolDeviceStoppedStatus(FsvolDeviceObject);

    /* probe and lock the user buffer */
    Result = FspLockUserBuffer(Irp, WriteLength, IoReadAccess);
    if (!NT_SUCCESS(Result))
        return Result;

    /* acquire FileNode exclusive Full */
    Success = DEBUGTEST(90) &&
        FspFileNodeTryAcquireExclusiveF(FileNode, FspFileNodeAcquireFull, CanWait);
    if (!Success)
        return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteNonCached, 0);

    /* perform oplock check */
    if (!PagingIo)
    {
        Result = FspFileNodeOplockCheckAsync(
            FileNode, FspFileNodeAcquireFull, FspFsvolWriteNonCached,
            Irp);
        if (STATUS_PENDING == Result)
            return Result;
        if (!NT_SUCCESS(Result))
        {
            FspFileNodeRelease(FileNode, Full);
            return Result;
        }
    }

    /* check the file locks */
    if (!PagingIo && !FsRtlCheckLockForWriteAccess(&FileNode->FileLock, Irp))
    {
        FspFileNodeRelease(FileNode, Full);
        return STATUS_FILE_LOCK_CONFLICT;
    }

    /* if this is a non-cached transfer on a cached file then flush and purge the file */
    if (!PagingIo && 0 != FileObject->SectionObjectPointer->DataSectionObject)
    {
        if (!CanWait)
        {
            FspFileNodeRelease(FileNode, Full);
            return FspWqRepostIrpWorkItem(Irp, FspFsvolWriteNonCached, 0);
        }

        Result = FspFileNodeFlushAndPurgeCache(FileNode,
            IrpSp->Parameters.Write.ByteOffset.QuadPart,
            IrpSp->Parameters.Write.Length,
            TRUE);
        if (!NT_SUCCESS(Result))
        {
            FspFileNodeRelease(FileNode, Full);
            return Result;
        }
    }

    Request = FspIrpRequest(Irp);
    if (0 == Request)
    {
        /* create request */
        Result = FspIopCreateRequestEx(Irp, 0, 0, FspFsvolWriteNonCachedRequestFini, &Request);
        if (!NT_SUCCESS(Result))
        {
            FspFileNodeRelease(FileNode, Full);
            return Result;
        }
    }
    else
    {
        /* reuse existing request */
        ASSERT(Request->Size == sizeof *Request);
        ASSERT(Request->Hint == (UINT_PTR)Irp);
        FspIopResetRequest(Request, FspFsvolWriteNonCachedRequestFini);
        RtlZeroMemory(&Request->Req,
            sizeof *Request - FIELD_OFFSET(FSP_FSCTL_TRANSACT_REQ, Req));
    }


    Request->Kind = FspFsctlTransactWriteKind;
    Request->Req.Write.UserContext = FileNode->UserContext;
    Request->Req.Write.UserContext2 = FileDesc->UserContext2;
    Request->Req.Write.Offset = WriteOffset.QuadPart;
    Request->Req.Write.Length = WriteLength;
    Request->Req.Write.Key = WriteKey;
    Request->Req.Write.ConstrainedIo = !!PagingIo;

    FspFileNodeSetOwner(FileNode, Full, Request);
    FspIopRequestContext(Request, RequestIrp) = Irp;

    FSP_STATISTICS *Statistics = FspFsvolDeviceStatistics(FsvolDeviceObject);
    if (PagingIo)
    {
        FspStatisticsInc(Statistics, Base.UserFileWrites);
        FspStatisticsAdd(Statistics, Base.UserFileWriteBytes, WriteLength);
        FspStatisticsInc(Statistics, Base.UserDiskWrites);
    }
    else
    {
        FspStatisticsInc(Statistics, Specific.NonCachedWrites);
        FspStatisticsAdd(Statistics, Specific.NonCachedWriteBytes, WriteLength);
        FspStatisticsInc(Statistics, Specific.NonCachedDiskWrites);
    }

    return FSP_STATUS_IOQ_POST;
}