Exemplo n.º 1
0
BOOLEAN
FFSZeroHoles(
	IN PFFS_IRP_CONTEXT IrpContext,
	IN PFFS_VCB         Vcb,
	IN PFILE_OBJECT     FileObject,
	IN LONGLONG         Offset,
	IN LONGLONG         Count)
{
	LARGE_INTEGER StartAddr = {0, 0};
	LARGE_INTEGER EndAddr = {0, 0};

	StartAddr.QuadPart = (Offset + (SECTOR_SIZE - 1)) &
		~((LONGLONG)SECTOR_SIZE - 1);

	EndAddr.QuadPart = (Offset + Count + (SECTOR_SIZE - 1)) &
		~((LONGLONG)SECTOR_SIZE - 1);

	if (StartAddr.QuadPart < EndAddr.QuadPart)
	{
		return CcZeroData(FileObject,
				&StartAddr,
				&EndAddr,
				IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
	}

	return TRUE;
}
Exemplo n.º 2
0
Arquivo: write.c Projeto: jrfl/ext2fsd
BOOLEAN
Ext2ZeroData (
    IN PEXT2_IRP_CONTEXT IrpContext,
    IN PEXT2_VCB         Vcb,
    IN PFILE_OBJECT      FileObject,
    IN PLARGE_INTEGER    Start,
    IN PLARGE_INTEGER    End
    )
{
    PEXT2_FCB       Fcb;
    PBCB            Bcb;
    PVOID           Ptr;
    ULONG           Size;
    BOOLEAN         rc = TRUE;

    ASSERT (End && Start && End->QuadPart > Start->QuadPart);
    Fcb = (PEXT2_FCB) FileObject->FsContext;

    /* skip data zero if we've already tracked unwritten part */
    if (0 == (  End->LowPart & (BLOCK_SIZE -1)) &&
        0 == (Start->LowPart & (BLOCK_SIZE -1))) {

        if (INODE_HAS_EXTENT(Fcb->Inode)) {
            return TRUE;
        } else {
#if !EXT2_PRE_ALLOCATION_SUPPORT
            return TRUE;
#endif
        }
    }

    /* clear data in range [Start, End) */
    return CcZeroData(FileObject, Start, End, Ext2CanIWait());
}
Exemplo n.º 3
0
BOOLEAN
Ext2ZeroHoles (
    IN PEXT2_IRP_CONTEXT IrpContext,
    IN PEXT2_VCB Vcb,
    IN PFILE_OBJECT FileObject,
    IN LONGLONG Offset,
    IN LONGLONG Count
)
{
    LARGE_INTEGER Start, End;

    Start.QuadPart = Offset;
    End.QuadPart = Offset + Count;

    if (Count > 0) {
        return CcZeroData(FileObject, &Start, &End, PIN_WAIT);
    }

    return TRUE;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
NTSTATUS
Ext2WriteFile(IN PEXT2_IRP_CONTEXT IrpContext)
{
    NTSTATUS            Status = STATUS_UNSUCCESSFUL;

    PEXT2_VCB           Vcb;
    PEXT2_FCB           Fcb;
    PEXT2_CCB           Ccb;
    PFILE_OBJECT        FileObject;
    PFILE_OBJECT        CacheObject;

    PDEVICE_OBJECT      DeviceObject;

    PIRP                Irp;
    PIO_STACK_LOCATION  IoStackLocation;

    ULONG               Length;
    LARGE_INTEGER       ByteOffset;
    ULONG               ReturnedLength = 0;

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

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

    BOOLEAN             bDeferred = FALSE;
    BOOLEAN             FileSizesChanged = FALSE;

    PUCHAR              Buffer;

    __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)) {
            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 (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 (!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 (IsEndOfFile(ByteOffset)) {
            ByteOffset.QuadPart = Fcb->Header.FileSize.QuadPart;
        }

        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)) {

                    RecursiveWriteThrough = TRUE;
                }
            }
        }

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

            MainResourceAcquired =
                ExAcquireResourceExclusiveLite( &Fcb->MainResource,
                                                IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));

            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),
                                 (PLARGE_INTEGER)&(ByteOffset),
                                 CEILING_ALIGNED(ULONG, Length, BLOCK_SIZE),
                                 FALSE );

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

        if (!PagingIo) {

            if (!ExAcquireResourceExclusiveLite(
                        &Fcb->MainResource,
                        IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
                Status = STATUS_PENDING;
                __leave;
            }

            MainResourceAcquired = TRUE;

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

        } else {

            if (!ExAcquireResourceSharedLite(
                        &Fcb->PagingIoResource,
                        IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
                Status = STATUS_PENDING;
                __leave;
            }

            PagingIoResourceAcquired = TRUE;
        }

        if (!IsDirectory(Fcb) && 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);
        }

        if (PagingIo) {

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

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

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

                } else {

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

        } else {

            if (IsDirectory(Fcb)) {
                __leave;
            }

            //
            //  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;

                Last.QuadPart = Fcb->Header.AllocationSize.QuadPart;
                AllocationSize.QuadPart = (LONGLONG)(ByteOffset.QuadPart + Length);
                AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
                                          (ULONGLONG)AllocationSize.QuadPart,
                                          (ULONGLONG)BLOCK_SIZE);
                Status = Ext2ExpandFile(IrpContext, Vcb, Fcb->Mcb, &AllocationSize);
                if (AllocationSize.QuadPart > Last.QuadPart) {
                    Fcb->Header.AllocationSize.QuadPart = AllocationSize.QuadPart;
                    SetLongFlag(Fcb->Flags, FCB_ALLOC_IN_WRITE);
                }

                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)));
                    if (AllocationSize.QuadPart > Last.QuadPart)
                        CcZeroData(FileObject, &Last, &AllocationSize, FALSE);
                }

                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 );
            }

            CacheObject = FileObject;

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

                CcPrepareMdlWrite(
                    CacheObject,
                    (&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 (!CcCopyWrite(
                            CacheObject,
                            (PLARGE_INTEGER)&ByteOffset,
                            Length,
                            IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT),
                            Buffer  )) {
                    Status = STATUS_PENDING;
                    DbgBreak();
                    __leave;
                }

                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 && CcIsFileCached(FileObject) && !RecursiveWriteThrough &&
                    Fcb->LazyWriterThread != PsGetCurrentThread() &&
                    ByteOffset.QuadPart > Fcb->Header.ValidDataLength.QuadPart) {

                Ext2ZeroHoles( IrpContext, Vcb, FileObject, Fcb->Header.ValidDataLength.QuadPart,
                               ByteOffset.QuadPart - Fcb->Header.ValidDataLength.QuadPart );
            }

            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;
        }

        /* Update files's ValidDateLength */
        if (NT_SUCCESS(Status) && !PagingIo && CcIsFileCached(FileObject) &&
                !RecursiveWriteThrough && Fcb->LazyWriterThread != PsGetCurrentThread()) {

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

            if (Fcb->Mcb->Inode.i_size < (loff_t) (Fcb->Header.ValidDataLength.QuadPart)) {
                Fcb->Header.ValidDataLength.QuadPart = Fcb->Mcb->Inode.i_size;
                FileSizesChanged = TRUE;
            }

            if (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) {
            Ext2NotifyReportChange( IrpContext,  Vcb, Fcb->Mcb,
                                    FILE_NOTIFY_CHANGE_SIZE,
                                    FILE_ACTION_MODIFIED );
        }

    } __finally {

        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)) {

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

                        if (!PagingIo) {
                            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;
}
Exemplo n.º 6
0
BOOLEAN
NtfsZeroData (
    IN PIRP_CONTEXT IrpContext,
    IN PSCB Scb,
    IN PFILE_OBJECT FileObject,
    IN LONGLONG StartingZero,
    IN LONGLONG ByteCount,
    IN OUT PLONGLONG CommittedFileSize OPTIONAL
    )

/*++

Routine Description:

    This routine is called to zero a range of a file in order to
    advance valid data length.

Arguments:

    Scb - Scb for the stream to zero.

    FileObject - FileObject for the stream.

    StartingZero - Offset to begin the zero operation.

    ByteCount - Length of range to zero.

    CommittedFileSize - If we write the file sizes and commit the
        transaction then we want to let our caller know what
        point to roll back file size on a subsequent failure.  On entry
        it has the size our caller wants to roll back the file size to.
        On exit it has the new size to roll back to which takes into
        account any updates to the file size which have been logged.

Return Value:

    BOOLEAN - TRUE if the entire range was zeroed, FALSE if the request
        is broken up or the cache manager would block.

--*/

{
    LONGLONG Temp;

#ifdef  COMPRESS_ON_WIRE
    IO_STATUS_BLOCK IoStatus;
#endif

    ULONG SectorSize;

    BOOLEAN Finished;
    BOOLEAN CompleteZero = TRUE;
    BOOLEAN ScbAcquired = FALSE;

    PVCB Vcb = Scb->Vcb;

    LONGLONG ZeroStart;
    LONGLONG BeyondZeroEnd;
    ULONG CompressionUnit = Scb->CompressionUnit;

    BOOLEAN Wait;

    PAGED_CODE();

    Wait = (BOOLEAN) FlagOn( IrpContext->State, IRP_CONTEXT_STATE_WAIT );

    SectorSize = Vcb->BytesPerSector;

    //
    //  We may be able to simplify the zero operation (sparse file or when writing
    //  compressed) by deallocating large ranges of the file.  Otherwise we have to
    //  generate zeroes for the entire range.  If that is the case we want to split
    //  this operation up.
    //

    if ((ByteCount > MAX_ZERO_THRESHOLD) &&
        !FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ) &&
        !FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) {

        ByteCount = MAX_ZERO_THRESHOLD;
        CompleteZero = FALSE;
    }

    ZeroStart = StartingZero + (SectorSize - 1);
    (ULONG)ZeroStart &= ~(SectorSize - 1);

    BeyondZeroEnd = StartingZero + ByteCount + (SectorSize - 1);
    (ULONG)BeyondZeroEnd &= ~(SectorSize - 1);

    //
    //  We must flush the first compression unit in case it is partially populated
    //  in the compressed stream.
    //

#ifdef  COMPRESS_ON_WIRE

    if ((Scb->NonpagedScb->SegmentObjectC.DataSectionObject != NULL) &&
        ((StartingZero & (CompressionUnit - 1)) != 0)) {

        (ULONG)StartingZero &= ~(CompressionUnit - 1);
        CcFlushCache( &Scb->NonpagedScb->SegmentObjectC,
                      (PLARGE_INTEGER)&StartingZero,
                      CompressionUnit,
                      &IoStatus );

        if (!NT_SUCCESS(IoStatus.Status)) {
            NtfsNormalizeAndRaiseStatus( IrpContext, IoStatus.Status, STATUS_UNEXPECTED_IO_ERROR );
        }
    }
#endif

    //
    //  If this is a sparse or compressed file and we are zeroing a lot, then let's
    //  just delete the space instead of writing tons of zeros and deleting
    //  the space in the noncached path!  If we are currently decompressing
    //  a compressed file we can't take this path.
    //

    if ((FlagOn( Scb->ScbState, SCB_STATE_WRITE_COMPRESSED ) ||
         FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_SPARSE )) &&
        (ByteCount > (Scb->CompressionUnit * 2))) {

        //
        //  Find the end of the first compression unit being zeroed.
        //

        Temp = ZeroStart + (CompressionUnit - 1);
        (ULONG)Temp &= ~(CompressionUnit - 1);

        //
        //  Zero the first compression unit.
        //

        if ((ULONG)Temp != (ULONG)ZeroStart) {

            Finished = CcZeroData( FileObject, (PLARGE_INTEGER)&ZeroStart, (PLARGE_INTEGER)&Temp, Wait );

            if (!Finished) {return FALSE;}

            ZeroStart = Temp;
        }

        //
        //  Now delete all of the compression units in between.
        //

        //
        //  Calculate the start of the last compression unit in bytes.
        //

        Temp = BeyondZeroEnd;
        (ULONG)Temp &= ~(CompressionUnit - 1);

        //
        //  If the caller has not already started a transaction (like write.c),
        //  then let's just do the delete as an atomic action.
        //

        if (!NtfsIsExclusiveScb( Scb )) {

            NtfsAcquireExclusiveScb( IrpContext, Scb );
            ScbAcquired = TRUE;

            if (ARGUMENT_PRESENT( CommittedFileSize )) {

                NtfsMungeScbSnapshot( IrpContext, Scb, *CommittedFileSize );
            }
        }

        try {

            //
            //  Delete the space.
            //

            NtfsDeleteAllocation( IrpContext,
                                  FileObject,
                                  Scb,
                                  LlClustersFromBytes( Vcb, ZeroStart ),
                                  LlClustersFromBytesTruncate( Vcb, Temp ) - 1,
                                  TRUE,
                                  TRUE );

            //
            //  If we didn't raise then update the Scb values for compressed files.
            //

            if (FlagOn( Scb->AttributeFlags, ATTRIBUTE_FLAG_COMPRESSION_MASK )) {
                Scb->ValidDataToDisk = Temp;
            }

            //
            //  If we succeed, commit the atomic action.  Release all of the exclusive
            //  resources if our user explicitly acquired the Fcb here.
            //

            if (ScbAcquired) {
                NtfsCheckpointCurrentTransaction( IrpContext );

                if (ARGUMENT_PRESENT( CommittedFileSize )) {

                    ASSERT( Scb->ScbSnapshot != NULL );
                    *CommittedFileSize = Scb->ScbSnapshot->FileSize;
                }

                while (!IsListEmpty( &IrpContext->ExclusiveFcbList )) {

                    NtfsReleaseFcb( IrpContext,
                                    (PFCB)CONTAINING_RECORD( IrpContext->ExclusiveFcbList.Flink,
                                                             FCB,
                                                             ExclusiveFcbLinks ));
                }

                ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_RELEASE_USN_JRNL |
                                              IRP_CONTEXT_FLAG_RELEASE_MFT );

                ScbAcquired = FALSE;
            }

            if (FlagOn( Scb->ScbState, SCB_STATE_UNNAMED_DATA )) {

                Scb->Fcb->Info.AllocatedLength = Scb->TotalAllocated;
                SetFlag( Scb->Fcb->InfoFlags, FCB_INFO_CHANGED_ALLOC_SIZE );
            }

        } finally {

            if (ScbAcquired) {
                NtfsReleaseScb( IrpContext, Scb );
            }
        }

        //
        //  Zero the beginning of the last compression unit.
        //

        if ((ULONG)Temp != (ULONG)BeyondZeroEnd) {

            Finished = CcZeroData( FileObject, (PLARGE_INTEGER)&Temp, (PLARGE_INTEGER)&BeyondZeroEnd, Wait );

            if (!Finished) {return FALSE;}

            BeyondZeroEnd = Temp;
        }

        return TRUE;
    }