Example #1
0
NTSTATUS
Ext2DoExtentExpand(
    IN PEXT2_IRP_CONTEXT    IrpContext,
    IN PEXT2_VCB            Vcb,
    IN PEXT2_MCB            Mcb,
    IN ULONG                Index,
    IN OUT PULONG           Block,
    IN OUT PULONG           Number
)
{
    EXT4_EXTENT_HEADER *eh;
    struct buffer_head bh_got;
    int    rc, flags;

    if (IsMcbDirectory(Mcb) || IrpContext->MajorFunction == IRP_MJ_WRITE) {
        flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT;
    } else {
        flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
    }

    memset(&bh_got, 0, sizeof(struct buffer_head));
    eh = get_ext4_header(&Mcb->Inode);

    if (eh->eh_magic != EXT4_EXT_MAGIC) {
        ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode);
    }

    if ((rc = ext4_ext_get_blocks( IrpContext, NULL, &Mcb->Inode, Index,
                                  *Number, &bh_got, 1, flags)) < 0) {
        DEBUG(DL_ERR, ("Expand Block insufficient resources, Number: %u,"
                       " err: %d\n", *Number, rc));
        DbgBreak();
        return Ext2WinntError(rc);
    }

    if (Number)
        *Number = rc ? rc : 1;
    if (Block)
        *Block = (ULONG)bh_got.b_blocknr;

    Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);

    return STATUS_SUCCESS;
}
Example #2
0
NTSTATUS
Ext2MapExtent(
    IN PEXT2_IRP_CONTEXT    IrpContext,
    IN PEXT2_VCB            Vcb,
    IN PEXT2_MCB            Mcb,
    IN ULONG                Index,
    IN BOOLEAN              Alloc,
    OUT PULONG              Block,
    OUT PULONG              Number
)
{
    EXT4_EXTENT_HEADER *eh;
    struct buffer_head bh_got;
    int    flags, rc;
	ULONG max_blocks = 0;

    memset(&bh_got, 0, sizeof(struct buffer_head));
    eh = get_ext4_header(&Mcb->Inode);

    if (eh->eh_magic != EXT4_EXT_MAGIC) {
        if (Alloc) {
            /* now initialize inode extent root node */
            ext4_ext_tree_init(IrpContext, NULL, &Mcb->Inode);
        } else {
            /* return empty-mapping when inode extent isn't initialized */
            if (Block)
                *Block = 0;
            if (Number) {
                LONGLONG  _len = _len = Mcb->Inode.i_size;
                if (Mcb->Fcb)
                    _len = Mcb->Fcb->Header.AllocationSize.QuadPart;
                *Number = (ULONG)((_len + BLOCK_SIZE - 1) >> BLOCK_BITS);
            }
            return STATUS_SUCCESS;
        }
    }

    /* IrpContext is NULL when called during journal initialization */
    if (IsMcbDirectory(Mcb) || IrpContext == NULL ||
        IrpContext->MajorFunction == IRP_MJ_WRITE || !Alloc){
        flags = EXT4_GET_BLOCKS_IO_CONVERT_EXT;
		max_blocks = EXT_INIT_MAX_LEN;
    } else {
        flags = EXT4_GET_BLOCKS_IO_CREATE_EXT;
		max_blocks = EXT_UNWRITTEN_MAX_LEN;
    }

    if ((rc = ext4_ext_get_blocks(
                            IrpContext,
                            NULL,
                            &Mcb->Inode,
                            Index,
                            max_blocks,
                            &bh_got,
                            Alloc,
                            flags)) < 0) {
        DEBUG(DL_ERR, ("Block insufficient resources, err: %d\n", rc));
        return Ext2WinntError(rc);
    }
    if (Alloc)
        Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
    if (Number)
        *Number = rc ? rc : 1;
    if (Block)
        *Block = (ULONG)bh_got.b_blocknr;

    return STATUS_SUCCESS;
}
Example #3
0
File: write.c Project: jrfl/ext2fsd
NTSTATUS
Ext2WriteInode (
    IN PEXT2_IRP_CONTEXT    IrpContext,
    IN PEXT2_VCB            Vcb,
    IN PEXT2_MCB            Mcb,
    IN ULONGLONG            Offset,
    IN PVOID                Buffer,
    IN ULONG                Size,
    IN BOOLEAN              bDirectIo,
    OUT PULONG              BytesWritten
)
{
    PEXT2_EXTENT    Chain = NULL;
    NTSTATUS        Status = STATUS_UNSUCCESSFUL;

    __try {

        if (BytesWritten) {
            *BytesWritten = 0;
        }

        Status = Ext2BuildExtents (
                     IrpContext,
                     Vcb,
                     Mcb,
                     Offset,
                     Size,
                     IsMcbDirectory(Mcb) ? FALSE : TRUE,
                     &Chain
                 );

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

        if (Chain == NULL) {
            Status = STATUS_SUCCESS;
            __leave;
        }

        if (bDirectIo) {

            ASSERT(IrpContext != NULL);

            //
            // We assume the offset is aligned.
            //

            Status = Ext2ReadWriteBlocks(
                         IrpContext,
                         Vcb,
                         Chain,
                         Size
                     );

        } else {

            PEXT2_EXTENT Extent;
            for (Extent = Chain; Extent != NULL; Extent = Extent->Next) {

                if ( !Ext2SaveBuffer(
                            IrpContext,
                            Vcb,
                            Extent->Lba,
                            Extent->Length,
                            (PVOID)((PUCHAR)Buffer + Extent->Offset)
                        )) {
                    __leave;
                }
            }

            if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {

                DEBUG(DL_FLP, ("Ext2WriteInode is starting FlushingDpc...\n"));
                Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
            }

            Status = STATUS_SUCCESS;
        }

    } __finally {

        if (Chain) {
            Ext2DestroyExtentChain(Chain);
        }

        if (NT_SUCCESS(Status) && BytesWritten) {
            *BytesWritten = Size;
        }
    }

    return Status;
}
Example #4
0
NTSTATUS
Ext2Cleanup (IN PEXT2_IRP_CONTEXT IrpContext)
{
    PDEVICE_OBJECT  DeviceObject;
    NTSTATUS        Status = STATUS_SUCCESS;
    PEXT2_VCB       Vcb;
    PFILE_OBJECT    FileObject;
    PEXT2_FCB       Fcb;
    PEXT2_CCB       Ccb;
    PIRP            Irp;
    PEXT2_MCB       Mcb;


    BOOLEAN         VcbResourceAcquired = FALSE;
    BOOLEAN         FcbResourceAcquired = FALSE;
    BOOLEAN         FcbPagingIoResourceAcquired = FALSE;

    __try {

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

        DeviceObject = IrpContext->DeviceObject;
        if (IsExt2FsDevice(DeviceObject))  {
            Status = STATUS_SUCCESS;
            __leave;
        }

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

        if (!IsVcbInited(Vcb)) {
            Status = STATUS_SUCCESS;
            __leave;
        }

        FileObject = IrpContext->FileObject;
        Fcb = (PEXT2_FCB) FileObject->FsContext;
        if (!Fcb || (Fcb->Identifier.Type != EXT2VCB &&
                     Fcb->Identifier.Type != EXT2FCB)) {
            Status = STATUS_SUCCESS;
            __leave;
        }
        Mcb = Fcb->Mcb;
        Ccb = (PEXT2_CCB) FileObject->FsContext2;

        if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
            Status = STATUS_SUCCESS;
            __leave;
        }

        VcbResourceAcquired =
            ExAcquireResourceExclusiveLite(
                &Vcb->MainResource,
                IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)
            );

        if (Fcb->Identifier.Type == EXT2VCB) {

            if (IsFlagOn(Vcb->Flags, VCB_VOLUME_LOCKED) &&
                    (Vcb->LockFile == FileObject) ) {

                ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
                Vcb->LockFile = NULL;
                Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
            }

            if (Ccb) {
                Ext2DerefXcb(&Vcb->OpenHandleCount);
                Ext2DerefXcb(&Vcb->OpenVolumeCount);
            }

            IoRemoveShareAccess(FileObject, &Vcb->ShareAccess);

            Status = STATUS_SUCCESS;
            __leave;
        }

        ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
               (Fcb->Identifier.Size == sizeof(EXT2_FCB)));

        if (IsFlagOn(FileObject->Flags, FO_CLEANUP_COMPLETE)) {
            if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
                    IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK) &&
                    !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) {
                Status = Ext2FlushFile(IrpContext, Fcb, Ccb);
            }
            __leave;
        }

        if (Ccb == NULL) {
            Status = STATUS_SUCCESS;
            __leave;
        }

        if (IsDirectory(Fcb)) {
            if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE))  {
                SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);

                FsRtlNotifyFullChangeDirectory(
                    Vcb->NotifySync,
                    &Vcb->NotifyList,
                    Ccb,
                    NULL,
                    FALSE,
                    FALSE,
                    0,
                    NULL,
                    NULL,
                    NULL );
            }

            FsRtlNotifyCleanup(Vcb->NotifySync, &Vcb->NotifyList, Ccb);

        }

        ExReleaseResourceLite(&Vcb->MainResource);
        VcbResourceAcquired = FALSE;

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

        ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
               (Ccb->Identifier.Size == sizeof(EXT2_CCB)));

        Ext2DerefXcb(&Vcb->OpenHandleCount);
        Ext2DerefXcb(&Fcb->OpenHandleCount);

        if (IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED)) {
            Fcb->Mcb->FileAttr |= FILE_ATTRIBUTE_ARCHIVE;
        }

        if (IsDirectory(Fcb)) {

            ext3_release_dir(Fcb->Inode, &Ccb->filp);

        } else {

            if ( IsFlagOn(FileObject->Flags, FO_FILE_MODIFIED) &&
                    !IsFlagOn(Ccb->Flags, CCB_LAST_WRITE_UPDATED)) {

                LARGE_INTEGER   SysTime;
                KeQuerySystemTime(&SysTime);

                Fcb->Inode->i_atime =
                    Fcb->Inode->i_mtime = Ext2LinuxTime(SysTime);
                Fcb->Mcb->LastAccessTime =
                    Fcb->Mcb->LastWriteTime = Ext2NtTime(Fcb->Inode->i_atime);

                Ext2SaveInode(IrpContext, Vcb, Fcb->Inode);

                Ext2NotifyReportChange(
                    IrpContext,
                    Vcb,
                    Fcb->Mcb,
                    FILE_NOTIFY_CHANGE_ATTRIBUTES |
                    FILE_NOTIFY_CHANGE_LAST_WRITE |
                    FILE_NOTIFY_CHANGE_LAST_ACCESS,
                    FILE_ACTION_MODIFIED );
            }

            FsRtlCheckOplock( &Fcb->Oplock,
                              Irp,
                              IrpContext,
                              NULL,
                              NULL );

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

            if (!IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED)) {
                Fcb->NonCachedOpenCount--;
            }

            if (IsFlagOn(Ccb->Flags, CCB_DELETE_ON_CLOSE))  {
                SetLongFlag(Fcb->Flags, FCB_DELETE_PENDING);
            }

            //
            // Drop any byte range locks this process may have on the file.
            //

            FsRtlFastUnlockAll(
                &Fcb->FileLockAnchor,
                FileObject,
                IoGetRequestorProcess(Irp),
                NULL  );

            //
            // If there are no byte range locks owned by other processes on the
            // file the fast I/O read/write functions doesn't have to check for
            // locks so we set IsFastIoPossible to FastIoIsPossible again.
            //
            if (!FsRtlGetNextFileLock(&Fcb->FileLockAnchor, TRUE)) {
                if (Fcb->Header.IsFastIoPossible != FastIoIsPossible) {
#if EXT2_DEBUG
                    DEBUG(DL_INF, (": %-16.16s %-31s %wZ\n",
                                   Ext2GetCurrentProcessName(),
                                   "FastIoIsPossible",
                                   &Fcb->Mcb->FullName
                                  ));
#endif

                    Fcb->Header.IsFastIoPossible = FastIoIsPossible;
                }
            }

            if (Fcb->OpenHandleCount == 0 &&
                    (IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_CREATE) ||
                     IsFlagOn(Fcb->Flags, FCB_ALLOC_IN_WRITE)) ) {

                LARGE_INTEGER Size;

                ExAcquireResourceExclusiveLite(&Fcb->PagingIoResource, TRUE);
                FcbPagingIoResourceAcquired = TRUE;

                Size.QuadPart = CEILING_ALIGNED(ULONGLONG,
                                                (ULONGLONG)Fcb->Mcb->Inode.i_size,
                                                (ULONGLONG)BLOCK_SIZE);
                if (!IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {

                    Ext2TruncateFile(IrpContext, Vcb, Fcb->Mcb, &Size);
                    Fcb->Header.ValidDataLength.QuadPart =
                        Fcb->Header.FileSize.QuadPart = Fcb->Mcb->Inode.i_size;
                    Fcb->Header.AllocationSize = Size;
                    if (CcIsFileCached(FileObject)) {
                        CcSetFileSizes(FileObject,
                                       (PCC_FILE_SIZES)(&(Fcb->Header.AllocationSize)));
                    }
                }
                ClearLongFlag(Fcb->Flags, FCB_ALLOC_IN_CREATE|FCB_ALLOC_IN_WRITE);
                ExReleaseResourceLite(&Fcb->PagingIoResource);
                FcbPagingIoResourceAcquired = FALSE;
            }
        }

        if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) {

            if (Fcb->OpenHandleCount == 0 || (Mcb = Ccb->SymLink)) {

                //
                // Ext2DeleteFile will acquire these lock inside
                //

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

                //
                //  this file is to be deleted ...
                //
                if (Ccb->SymLink) {
                    Mcb = Ccb->SymLink;
                    FileObject->DeletePending = FALSE;
                }

                Status = Ext2DeleteFile(IrpContext, Vcb, Fcb, Mcb);

                if (NT_SUCCESS(Status)) {
                    if (IsMcbDirectory(Mcb)) {
                        Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
                                                FILE_NOTIFY_CHANGE_DIR_NAME,
                                                FILE_ACTION_REMOVED );
                    } else {
                        Ext2NotifyReportChange( IrpContext, Vcb, Mcb,
                                                FILE_NOTIFY_CHANGE_FILE_NAME,
                                                FILE_ACTION_REMOVED );
                    }
                }

                //
                // re-acquire the main resource lock
                //

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

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

        if (!IsDirectory(Fcb)) {

            if ( IsFlagOn(FileObject->Flags, FO_CACHE_SUPPORTED) &&
                    (Fcb->NonCachedOpenCount + 1 == Fcb->ReferenceCount) &&
                    (Fcb->SectionObject.DataSectionObject != NULL)) {

                if (!IsFlagOn(Vcb->Flags, VCB_READ_ONLY) &&
                        !IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED) ) {
                    CcFlushCache(&Fcb->SectionObject, NULL, 0, NULL);
                }

                if (ExAcquireResourceExclusiveLite(&(Fcb->PagingIoResource), TRUE)) {
                    ExReleaseResourceLite(&(Fcb->PagingIoResource));
                }

                CcPurgeCacheSection( &Fcb->SectionObject,
                                     NULL,
                                     0,
                                     FALSE );
            }

            CcUninitializeCacheMap(FileObject, NULL, NULL);
        }

        IoRemoveShareAccess(FileObject, &Fcb->ShareAccess);

        DEBUG(DL_INF, ( "Ext2Cleanup: OpenCount=%u ReferCount=%u NonCahcedCount=%xh %wZ\n",
                        Fcb->OpenHandleCount, Fcb->ReferenceCount, Fcb->NonCachedOpenCount, &Fcb->Mcb->FullName));

        Status = STATUS_SUCCESS;

        if (FileObject) {
            SetFlag(FileObject->Flags, FO_CLEANUP_COMPLETE);
        }

    } __finally {

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

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

        if (VcbResourceAcquired) {
            ExReleaseResourceLite(&Vcb->MainResource);
        }

        if (!IrpContext->ExceptionInProgress) {
            if (Status == STATUS_PENDING) {
                Ext2QueueRequest(IrpContext);
            } else {
                IrpContext->Irp->IoStatus.Status = Status;
                Ext2CompleteIrpContext(IrpContext, Status);
            }
        }
    }

    return Status;
}
Example #5
0
NTSTATUS
Ext2ExpandLast(
    IN PEXT2_IRP_CONTEXT    IrpContext,
    IN PEXT2_VCB            Vcb,
    IN PEXT2_MCB            Mcb,
    IN ULONG                Base,
    IN ULONG                Layer,
    IN PULONG *             Data,
    IN PULONG               Hint,
    IN PULONG               Block,
    IN OUT PULONG           Number
)
{
    PULONG      pData = NULL;
    ULONG       i;
    NTSTATUS    Status = STATUS_SUCCESS;

    if (Layer > 0 || IsMcbDirectory(Mcb)) {

        /* allocate buffer for new block */
        pData = (ULONG *) Ext2AllocatePool(
                    PagedPool,
                    BLOCK_SIZE,
                    EXT2_DATA_MAGIC
                );
        if (!pData) {
            DEBUG(DL_ERR, ( "Ex2ExpandBlock: failed to allocate memory for Data.\n"));
            Status = STATUS_INSUFFICIENT_RESOURCES;
            goto errorout;
        }
        RtlZeroMemory(pData, BLOCK_SIZE);
        INC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE);
    }

    /* allocate block from disk */
    Status = Ext2NewBlock(
                 IrpContext,
                 Vcb,
                 (Mcb->Inode.i_ino - 1) / BLOCKS_PER_GROUP,
                 *Hint,
                 Block,
                 Number
             );

    if (!NT_SUCCESS(Status)) {
        goto errorout;
    }

    /* increase inode i_blocks */
    Mcb->Inode.i_blocks += (*Number << (BLOCK_BITS - 9));

    if (Layer == 0) {

        if (IsMcbDirectory(Mcb)) {
            /* for directory we need initialize it's entry structure */
            PEXT2_DIR_ENTRY2 pEntry;
            pEntry = (PEXT2_DIR_ENTRY2) pData;
            pEntry->rec_len = (USHORT)(BLOCK_SIZE);
            ASSERT(*Number == 1);
            Ext2SaveBlock(IrpContext, Vcb, *Block, (PVOID)pData);
        }

        /* add new Extent into Mcb */
        if (!Ext2AddBlockExtent(Vcb, Mcb, Base, (*Block), *Number)) {
            DbgBreak();
            ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
            Ext2ClearAllExtents(&Mcb->Extents);
        }

    } else {

        /* zero the content of all meta blocks */
        for (i = 0; i < *Number; i++) {
            Ext2SaveBlock(IrpContext, Vcb, *Block + i, (PVOID)pData);
            /* add block to meta extents */
            if (!Ext2AddMcbMetaExts(Vcb, Mcb, *Block + i, 1)) {
                DbgBreak();
                Ext2Sleep(500);
                Ext2AddMcbMetaExts(Vcb, Mcb, *Block + i, 1);
            }
        }
    }

errorout:

    if (NT_SUCCESS(Status)) {
        *Hint = *Block + *Number;
        if (Data) {
            *Data = pData;
            ASSERT(*Number == 1);
        } else {
            if (pData) {
                Ext2FreePool(pData, EXT2_DATA_MAGIC);
                DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE);
            }
        }
    } else {
        if (pData) {
            Ext2FreePool(pData, EXT2_DATA_MAGIC);
            DEC_MEM_COUNT(PS_BLOCK_DATA, pData, BLOCK_SIZE);
        }
        if (*Block) {
            Ext2FreeBlock(IrpContext, Vcb, *Block, *Number);
            Mcb->Inode.i_blocks -= (*Number << (BLOCK_BITS - 9));
            *Block = 0;
        }
    }

    return Status;
}