diff --git a/Ext4Fsd/Ext4Fsd.vcxproj b/Ext4Fsd/Ext4Fsd.vcxproj
index 10d9344..f7b1a48 100644
--- a/Ext4Fsd/Ext4Fsd.vcxproj
+++ b/Ext4Fsd/Ext4Fsd.vcxproj
@@ -208,6 +208,7 @@
+
diff --git a/Ext4Fsd/Ext4Fsd.vcxproj.filters b/Ext4Fsd/Ext4Fsd.vcxproj.filters
index f110844..bbee764 100644
--- a/Ext4Fsd/Ext4Fsd.vcxproj.filters
+++ b/Ext4Fsd/Ext4Fsd.vcxproj.filters
@@ -274,6 +274,9 @@
Source Files\nls
+
+ Source Files\ext4
+
diff --git a/Ext4Fsd/ext3/generic.c b/Ext4Fsd/ext3/generic.c
index b1bbe71..1ca0d95 100644
--- a/Ext4Fsd/ext3/generic.c
+++ b/Ext4Fsd/ext3/generic.c
@@ -1,3102 +1,3036 @@
-/*
- * COPYRIGHT: See COPYRIGHT.TXT
- * PROJECT: Ext2 File System Driver for WinNT/2K/XP
- * FILE: generic.c
- * PROGRAMMER: Matt Wu
- * HOMEPAGE: http://www.ext2fsd.com
- * UPDATE HISTORY:
- */
-
-/* INCLUDES *****************************************************************/
-
-#include "ext2fs.h"
-#include "linux\ext4.h"
-
-/* GLOBALS ***************************************************************/
-
-extern PEXT2_GLOBAL Ext2Global;
-
-/* DEFINITIONS *************************************************************/
-
-
-/* FUNCTIONS ***************************************************************/
-
-NTSTATUS
-Ext2LoadSuper(IN PEXT2_VCB Vcb,
- IN BOOLEAN bVerify,
- OUT PEXT2_SUPER_BLOCK * Sb)
-{
- NTSTATUS Status;
- PEXT2_SUPER_BLOCK Ext2Sb = NULL;
-
- Ext2Sb = (PEXT2_SUPER_BLOCK)
- Ext2AllocatePool(
- PagedPool,
- SUPER_BLOCK_SIZE,
- EXT2_SB_MAGIC
- );
- if (!Ext2Sb) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
-
- Status = Ext2ReadDisk(
- Vcb,
- (ULONGLONG) SUPER_BLOCK_OFFSET,
- SUPER_BLOCK_SIZE,
- (PVOID) Ext2Sb,
- bVerify );
-
- if (!NT_SUCCESS(Status)) {
- Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
- Ext2Sb = NULL;
- }
-
-errorout:
-
- *Sb = Ext2Sb;
- return Status;
-}
-
-
-BOOLEAN
-Ext2SaveSuper(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb
-)
-{
- LONGLONG offset;
- BOOLEAN rc;
-
- offset = (LONGLONG) SUPER_BLOCK_OFFSET;
- rc = Ext2SaveBuffer( IrpContext,
- Vcb,
- offset,
- SUPER_BLOCK_SIZE,
- Vcb->SuperBlock
- );
-
- if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
- Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
- }
-
- return rc;
-}
-
-
-BOOLEAN
-Ext2RefreshSuper (
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb
-)
-{
- LONGLONG offset;
- IO_STATUS_BLOCK iosb;
-
- offset = (LONGLONG) SUPER_BLOCK_OFFSET;
- if (!CcCopyRead(
- Vcb->Volume,
- (PLARGE_INTEGER)&offset,
- SUPER_BLOCK_SIZE,
- TRUE,
- (PVOID)Vcb->SuperBlock,
- &iosb )) {
- return FALSE;
- }
-
- if (!NT_SUCCESS(iosb.Status)) {
- return FALSE;
- }
-
- /* reload root inode */
- if (Vcb->McbTree) {
-
- if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode))
- return FALSE;
-
- /* initializeroot node */
- Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime);
- Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime);
- Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
- Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
- }
-
- return TRUE;
-}
-
-VOID
-Ext2DropGroupBH(IN PEXT2_VCB Vcb)
-{
- struct ext3_sb_info *sbi = &Vcb->sbi;
- unsigned long i;
-
- if (NULL == Vcb->sbi.s_gd) {
- return;
- }
-
- for (i = 0; i < Vcb->sbi.s_gdb_count; i++) {
- if (Vcb->sbi.s_gd[i].bh) {
- fini_bh(&sbi->s_gd[i].bh);
- Vcb->sbi.s_gd[i].bh = NULL;
- }
- }
-}
-
-VOID
-Ext2PutGroup(IN PEXT2_VCB Vcb)
-{
- struct ext3_sb_info *sbi = &Vcb->sbi;
- unsigned long i;
-
-
- if (NULL == Vcb->sbi.s_gd) {
- return;
- }
-
- Ext2DropGroupBH(Vcb);
-
- kfree(Vcb->sbi.s_gd);
- Vcb->sbi.s_gd = NULL;
-
- ClearFlag(Vcb->Flags, VCB_GD_LOADED);
-}
-
-
-BOOLEAN
-Ext2LoadGroupBH(IN PEXT2_VCB Vcb)
-{
- struct super_block *sb = &Vcb->sb;
- struct ext3_sb_info *sbi = &Vcb->sbi;
- unsigned long i;
- BOOLEAN rc = FALSE;
-
- __try {
-
- ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
- ASSERT (NULL != sbi->s_gd);
-
- for (i = 0; i < sbi->s_gdb_count; i++) {
- ASSERT (sbi->s_gd[i].block);
- if (sbi->s_gd[i].bh)
- continue;
- sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block);
- if (!sbi->s_gd[i].bh) {
- DEBUG(DL_ERR, ("Ext2LoadGroupBH: can't read group descriptor %d\n", i));
- DbgBreak();
- __leave;
- }
- sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data;
- }
-
- rc = TRUE;
-
- } __finally {
-
- ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
- }
-
- return rc;
-}
-
-
-BOOLEAN
-Ext2LoadGroup(IN PEXT2_VCB Vcb)
-{
- struct super_block *sb = &Vcb->sb;
- struct ext3_sb_info *sbi = &Vcb->sbi;
- ext3_fsblk_t sb_block = 1;
- unsigned long i;
- BOOLEAN rc = FALSE;
-
- __try {
-
- ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
-
- if (NULL == sbi->s_gd) {
- sbi->s_gd = kzalloc(sbi->s_gdb_count * sizeof(struct ext3_gd),
- GFP_KERNEL);
- }
- if (sbi->s_gd == NULL) {
- DEBUG(DL_ERR, ("Ext2LoadGroup: not enough memory.\n"));
- __leave;
- }
-
- if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) {
- sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE;
- }
-
- for (i = 0; i < sbi->s_gdb_count; i++) {
- sbi->s_gd[i].block = descriptor_loc(sb, sb_block, i);
- if (!sbi->s_gd[i].block) {
- DEBUG(DL_ERR, ("Ext2LoadGroup: can't locate group descriptor %d\n", i));
- __leave;
- }
- }
-
- if (!Ext2LoadGroupBH(Vcb)) {
- DEBUG(DL_ERR, ("Ext2LoadGroup: Failed to load group descriptions !\n"));
- __leave;
- }
-
- if (!ext4_check_descriptors(sb)) {
- DbgBreak();
- DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted !\n"));
- __leave;
- }
-
- SetFlag(Vcb->Flags, VCB_GD_LOADED);
- rc = TRUE;
-
- } __finally {
-
- if (!rc)
- Ext2PutGroup(Vcb);
-
- ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
- }
-
- return rc;
-}
-
-VOID
-Ext2DropBH(IN PEXT2_VCB Vcb)
-{
- struct ext3_sb_info *sbi = &Vcb->sbi;
-
- /* do nothing if Vcb is not initialized yet */
- if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED))
- return;
-
- __try {
-
- /* acquire bd lock to avoid bh creation */
- ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
-
- SetFlag(Vcb->Flags, VCB_BEING_DROPPED);
- Ext2DropGroupBH(Vcb);
-
- while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
- struct buffer_head *bh;
- PLIST_ENTRY l;
- l = RemoveHeadList(&Vcb->bd.bd_bh_free);
- bh = CONTAINING_RECORD(l, struct buffer_head, b_link);
- InitializeListHead(&bh->b_link);
- if (0 == atomic_read(&bh->b_count)) {
- buffer_head_remove(&Vcb->bd, bh);
- free_buffer_head(bh);
- }
- }
-
- } __finally {
- ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
- }
-
- ClearFlag(Vcb->Flags, VCB_BEING_DROPPED);
-}
-
-
-VOID
-Ext2FlushRange(IN PEXT2_VCB Vcb, LARGE_INTEGER s, LARGE_INTEGER e)
-{
- ULONG len;
-
- if (e.QuadPart <= s.QuadPart)
- return;
-
- /* loop per 2G */
- while (s.QuadPart < e.QuadPart) {
- if (e.QuadPart > s.QuadPart + 1024 * 1024 * 1024) {
- len = 1024 * 1024 * 1024;
- } else {
- len = (ULONG) (e.QuadPart - s.QuadPart);
- }
- CcFlushCache(&Vcb->SectionObject, &s, len, NULL);
- s.QuadPart += len;
- }
-}
-
-NTSTATUS
-Ext2FlushVcb(IN PEXT2_VCB Vcb)
-{
- LARGE_INTEGER s = {0}, o;
- struct ext3_sb_info *sbi = &Vcb->sbi;
- struct rb_node *node;
- struct buffer_head *bh;
-
- if (!IsFlagOn(Vcb->Flags, VCB_GD_LOADED)) {
- CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
- goto errorout;
- }
-
- ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->MainResource));
-
- __try {
-
- /* acqurie gd block */
- ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
-
- /* acquire bd lock to avoid bh creation */
- ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
-
- /* drop unused bh */
- Ext2DropBH(Vcb);
-
- /* flush volume with all outstanding bh skipped */
-
- node = rb_first(&Vcb->bd.bd_bh_root);
- while (node) {
-
- bh = container_of(node, struct buffer_head, b_rb_node);
- node = rb_next(node);
-
- o.QuadPart = bh->b_blocknr << BLOCK_BITS;
- ASSERT(o.QuadPart >= s.QuadPart);
-
- if (o.QuadPart == s.QuadPart) {
- s.QuadPart = s.QuadPart + bh->b_size;
- continue;
- }
-
- if (o.QuadPart > s.QuadPart) {
- Ext2FlushRange(Vcb, s, o);
- s.QuadPart = (bh->b_blocknr << BLOCK_BITS) + bh->b_size;
- continue;
- }
- }
-
- o = Vcb->PartitionInformation.PartitionLength;
- Ext2FlushRange(Vcb, s, o);
-
- } __finally {
-
- ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
- ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
- }
-
-errorout:
- return STATUS_SUCCESS;
-}
-
-
-BOOLEAN
-Ext2SaveGroup(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN ULONG Group
-)
-{
- struct ext4_group_desc *gd;
- struct buffer_head *gb = NULL;
- unsigned long i;
-
- gd = ext4_get_group_desc(&Vcb->sb, Group, &gb);
- if (!gd)
- return 0;
-
- gd->bg_checksum = ext4_group_desc_csum(&Vcb->sbi, Group, gd);
- mark_buffer_dirty(gb);
- fini_bh(&gb);
-
- return TRUE;
-}
-
-
-BOOLEAN
-Ext2RefreshGroup(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb
-)
-{
- return TRUE;
-}
-
-BOOLEAN
-Ext2GetInodeLba (
- IN PEXT2_VCB Vcb,
- IN ULONG inode,
- OUT PLONGLONG offset
-)
-{
- PEXT2_GROUP_DESC gd;
- struct buffer_head *bh = NULL;
- ext4_fsblk_t loc;
- int group;
-
- if (inode < 1 || inode > INODES_COUNT) {
- DEBUG(DL_ERR, ( "Ext2GetInodeLba: Inode value %xh is invalid.\n",inode));
- *offset = 0;
- return FALSE;
- }
-
- group = (inode - 1) / INODES_PER_GROUP ;
- gd = ext4_get_group_desc(&Vcb->sb, group, &bh);
- if (!bh) {
- *offset = 0;
- DbgBreak();
- return FALSE;
- }
- loc = (LONGLONG)ext4_inode_table(&Vcb->sb, gd);
- loc = loc << BLOCK_BITS;
- loc = loc + ((inode - 1) % INODES_PER_GROUP) * Vcb->InodeSize;
-
- *offset = loc;
- __brelse(bh);
-
- return TRUE;
-}
-
-void Ext2DecodeInode(struct inode *dst, struct ext3_inode *src)
-{
- dst->i_mode = src->i_mode;
- dst->i_flags = src->i_flags;
- dst->i_uid = src->i_uid;
- dst->i_gid = src->i_gid;
- dst->i_nlink = src->i_links_count;
- dst->i_generation = src->i_generation;
- dst->i_size = src->i_size;
- if (S_ISREG(src->i_mode)) {
- dst->i_size |= (loff_t)src->i_size_high << 32;
- }
- dst->i_file_acl = src->i_file_acl_lo;
- dst->i_file_acl |= (ext4_fsblk_t)src->osd2.linux2.l_i_file_acl_high << 32;
- dst->i_atime = src->i_atime;
- dst->i_ctime = src->i_ctime;
- dst->i_mtime = src->i_mtime;
- dst->i_dtime = src->i_dtime;
- dst->i_blocks = ext3_inode_blocks(src, dst);
- memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
- if (EXT3_HAS_RO_COMPAT_FEATURE(dst->i_sb,
- EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
- dst->i_extra_isize = src->i_extra_isize;
- else
- dst->i_extra_isize = 0;
-}
-
-void Ext2EncodeInode(struct ext3_inode *dst, struct inode *src)
-{
- dst->i_mode = src->i_mode;
- dst->i_flags = src->i_flags;
- dst->i_uid = src->i_uid;
- dst->i_gid = src->i_gid;
- dst->i_links_count = src->i_nlink;
- dst->i_generation = src->i_generation;
- dst->i_size = (__u32)src->i_size;
- if (S_ISREG(src->i_mode)) {
- dst->i_size_high = (__u32)(src->i_size >> 32);
- }
- dst->i_file_acl_lo = (__u32)src->i_file_acl;
- dst->osd2.linux2.l_i_file_acl_high |= (__u16)(src->i_file_acl >> 32);
- dst->i_atime = src->i_atime;
- dst->i_ctime = src->i_ctime;
- dst->i_mtime = src->i_mtime;
- dst->i_dtime = src->i_dtime;
- dst->i_extra_isize = src->i_extra_isize;
- ASSERT(src->i_sb);
- ext3_inode_blocks_set(dst, src);
- memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
- if (EXT3_HAS_RO_COMPAT_FEATURE(src->i_sb,
- EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
- dst->i_extra_isize = src->i_extra_isize;
-}
-
-
-BOOLEAN
-Ext2LoadInode (IN PEXT2_VCB Vcb,
- IN struct inode *Inode)
-{
- struct ext3_inode ext3i = {0};
- LONGLONG offset;
-
- if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &offset)) {
- DEBUG(DL_ERR, ("Ext2LoadInode: failed inode %u.\n", Inode->i_ino));
- return FALSE;
- }
-
- if (!Ext2LoadBuffer(NULL, Vcb, offset, sizeof(ext3i), &ext3i)) {
- return FALSE;
- }
-
- Ext2DecodeInode(Inode, &ext3i);
-
- return TRUE;
-}
-
-
-BOOLEAN
-Ext2ClearInode (
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN ULONG Inode)
-{
- LONGLONG Offset = 0;
- BOOLEAN rc;
-
- rc = Ext2GetInodeLba(Vcb, Inode, &Offset);
- if (!rc) {
- DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode));
- goto errorout;
- }
-
- rc = Ext2ZeroBuffer(IrpContext, Vcb, Offset, Vcb->InodeSize);
-
-errorout:
-
- return rc;
-}
-
-BOOLEAN
-Ext2SaveInode ( IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN struct inode *Inode)
-{
- struct ext3_inode ext3i = {0};
-
- LONGLONG Offset = 0;
- ULONG InodeSize = sizeof(ext3i);
- BOOLEAN rc = 0;
-
- DEBUG(DL_INF, ( "Ext2SaveInode: Saving Inode %xh: Mode=%xh Size=%xh\n",
- Inode->i_ino, Inode->i_mode, Inode->i_size));
- rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset);
- if (!rc) {
- DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode->i_ino));
- goto errorout;
- }
-
- rc = Ext2LoadBuffer(NULL, Vcb, Offset, InodeSize, &ext3i);
- if (!rc) {
- DEBUG(DL_ERR, ( "Ext2SaveInode: failed reading inode %u.\n", Inode->i_ino));
- goto errorout;;
- }
-
- Ext2EncodeInode(&ext3i, Inode);
- if (InodeSize > Vcb->InodeSize)
- InodeSize = Vcb->InodeSize;
- rc = Ext2SaveBuffer(IrpContext, Vcb, Offset, InodeSize, &ext3i);
-
- if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
- Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
- }
-
-errorout:
- return rc;
-}
-
-BOOLEAN
-Ext2LoadInodeXattr(IN PEXT2_VCB Vcb,
- IN struct inode *Inode,
- IN PEXT2_INODE InodeXattr)
-{
- IO_STATUS_BLOCK IoStatus;
- LONGLONG Offset;
-
- if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset)) {
- DEBUG(DL_ERR, ("Ext2LoadRawInode: error get inode(%xh)'s addr.\n", Inode->i_ino));
- return FALSE;
- }
-
- if (!CcCopyRead(
- Vcb->Volume,
- (PLARGE_INTEGER)&Offset,
- Vcb->InodeSize,
- PIN_WAIT,
- (PVOID)InodeXattr,
- &IoStatus)) {
- return FALSE;
- }
-
- if (!NT_SUCCESS(IoStatus.Status)) {
- return FALSE;
- }
-
- Ext2EncodeInode(InodeXattr, Inode);
- return TRUE;
-}
-
-BOOLEAN
-Ext2SaveInodeXattr(IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN struct inode *Inode,
- IN PEXT2_INODE InodeXattr)
-{
- IO_STATUS_BLOCK IoStatus;
- LONGLONG Offset = 0;
- ULONG InodeSize = Vcb->InodeSize;
- BOOLEAN rc = 0;
-
- /* There is no way to put EA information in such a small inode */
- if (InodeSize == EXT2_GOOD_OLD_INODE_SIZE)
- return FALSE;
-
- DEBUG(DL_INF, ("Ext2SaveInodeXattr: Saving Inode %xh: Mode=%xh Size=%xh\n",
- Inode->i_ino, Inode->i_mode, Inode->i_size));
- rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset);
- if (!rc) {
- DEBUG(DL_ERR, ("Ext2SaveInodeXattr: error get inode(%xh)'s addr.\n", Inode->i_ino));
- goto errorout;
- }
-
- rc = Ext2SaveBuffer(IrpContext,
- Vcb,
- Offset + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize,
- InodeSize - EXT2_GOOD_OLD_INODE_SIZE - Inode->i_extra_isize,
- (char *)InodeXattr + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize);
-
- if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
- Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
- }
-
-errorout:
- return rc;
-}
-
-
-BOOLEAN
-Ext2LoadBlock (IN PEXT2_VCB Vcb,
- IN ULONG Index,
- IN PVOID Buffer )
-{
- struct buffer_head *bh = NULL;
- BOOLEAN rc = 0;
-
- __try {
-
- bh = sb_getblk(&Vcb->sb, (sector_t)Index);
-
- if (!bh) {
- DEBUG(DL_ERR, ("Ext2Loadblock: can't load block %u\n", Index));
- DbgBreak();
- __leave;
- }
-
- if (!buffer_uptodate(bh)) {
- int err = bh_submit_read(bh);
- if (err < 0) {
- DEBUG(DL_ERR, ("Ext2LoadBlock: reading failed %d\n", err));
- __leave;
- }
- }
-
- RtlCopyMemory(Buffer, bh->b_data, BLOCK_SIZE);
- rc = TRUE;
-
- } __finally {
-
- if (bh)
- fini_bh(&bh);
- }
-
- return rc;
-}
-
-
-BOOLEAN
-Ext2SaveBlock ( IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN ULONG Index,
- IN PVOID Buf )
-{
- struct buffer_head *bh = NULL;
- BOOLEAN rc = 0;
-
- __try {
-
- bh = sb_getblk_zero(&Vcb->sb, (sector_t)Index);
-
- if (!bh) {
- DEBUG(DL_ERR, ("Ext2Saveblock: can't load block %u\n", Index));
- DbgBreak();
- __leave;
- }
-
- if (!buffer_uptodate(bh)) {
- }
-
- RtlCopyMemory(bh->b_data, Buf, BLOCK_SIZE);
- mark_buffer_dirty(bh);
- rc = TRUE;
-
- } __finally {
-
- if (bh)
- fini_bh(&bh);
- }
-
- return rc;
-}
-
-BOOLEAN
-Ext2LoadBuffer( IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN LONGLONG offset,
- IN ULONG size,
- IN PVOID buf )
-{
- struct buffer_head *bh = NULL;
- BOOLEAN rc;
-
- __try {
-
- while (size) {
-
- sector_t block;
- ULONG len = 0, delta = 0;
-
- block = (sector_t) (offset >> BLOCK_BITS);
- delta = (ULONG)offset & (BLOCK_SIZE - 1);
- len = BLOCK_SIZE - delta;
- if (size < len)
- len = size;
-
- bh = sb_getblk(&Vcb->sb, block);
- if (!bh) {
- DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
- DbgBreak();
- __leave;
- }
-
- if (!buffer_uptodate(bh)) {
- int err = bh_submit_read(bh);
- if (err < 0) {
- DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
- __leave;
- }
- }
-
- __try {
- RtlCopyMemory(buf, bh->b_data + delta, len);
- } __finally {
- fini_bh(&bh);
- }
-
- buf = (PUCHAR)buf + len;
- offset = offset + len;
- size = size - len;
- }
-
- rc = TRUE;
-
- } __finally {
-
- if (bh)
- fini_bh(&bh);
-
- }
-
- return rc;
-}
-
-
-BOOLEAN
-Ext2ZeroBuffer( IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN LONGLONG offset,
- IN ULONG size
- )
-{
- struct buffer_head *bh = NULL;
- BOOLEAN rc = 0;
-
- __try {
-
- while (size) {
-
- sector_t block;
- ULONG len = 0, delta = 0;
-
- block = (sector_t) (offset >> BLOCK_BITS);
- delta = (ULONG)offset & (BLOCK_SIZE - 1);
- len = BLOCK_SIZE - delta;
- if (size < len)
- len = size;
-
- if (delta == 0 && len >= BLOCK_SIZE) {
- bh = sb_getblk_zero(&Vcb->sb, block);
- } else {
- bh = sb_getblk(&Vcb->sb, block);
- }
-
- if (!bh) {
- DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
- DbgBreak();
- __leave;
- }
-
- if (!buffer_uptodate(bh)) {
- int err = bh_submit_read(bh);
- if (err < 0) {
- DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
- __leave;
- }
- }
-
- __try {
- if (delta == 0 && len >= BLOCK_SIZE) {
- /* bh (cache) was already cleaned as zero */
- } else {
- RtlZeroMemory(bh->b_data + delta, len);
- }
- mark_buffer_dirty(bh);
- } __finally {
- fini_bh(&bh);
- }
-
- offset = offset + len;
- size = size - len;
- }
-
- rc = TRUE;
-
- } __finally {
-
- if (bh)
- fini_bh(&bh);
-
- }
-
- return rc;
-}
-
-
-BOOLEAN
-Ext2SaveBuffer( IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN LONGLONG offset,
- IN ULONG size,
- IN PVOID buf )
-{
- struct buffer_head *bh = NULL;
- BOOLEAN rc = 0;
-
- __try {
-
- while (size) {
-
- sector_t block;
- ULONG len = 0, delta = 0;
-
- block = (sector_t) (offset >> BLOCK_BITS);
- delta = (ULONG)offset & (BLOCK_SIZE - 1);
- len = BLOCK_SIZE - delta;
- if (size < len)
- len = size;
-
- if (delta == 0 && len >= BLOCK_SIZE) {
- bh = sb_getblk_zero(&Vcb->sb, block);
- } else {
- bh = sb_getblk(&Vcb->sb, block);
- }
-
- if (!bh) {
- DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
- DbgBreak();
- __leave;
- }
-
- if (!buffer_uptodate(bh)) {
- int err = bh_submit_read(bh);
- if (err < 0) {
- DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
- __leave;
- }
- }
-
- __try {
- RtlCopyMemory(bh->b_data + delta, buf, len);
- mark_buffer_dirty(bh);
- } __finally {
- fini_bh(&bh);
- }
-
- buf = (PUCHAR)buf + len;
- offset = offset + len;
- size = size - len;
- }
-
- rc = TRUE;
-
- } __finally {
-
- if (bh)
- fini_bh(&bh);
-
- }
-
- return rc;
-}
-
-
-VOID
-Ext2UpdateVcbStat(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb
-)
-{
- Vcb->SuperBlock->s_free_inodes_count = ext4_count_free_inodes(&Vcb->sb);
- ext3_free_blocks_count_set(SUPER_BLOCK, ext4_count_free_blocks(&Vcb->sb));
- Ext2SaveSuper(IrpContext, Vcb);
-}
-
-NTSTATUS
-Ext2NewBlock(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN ULONG GroupHint,
- IN ULONG BlockHint,
- OUT PULONG Block,
- IN OUT PULONG Number
-)
-{
- struct super_block *sb = &Vcb->sb;
- PEXT2_GROUP_DESC gd;
- struct buffer_head *gb = NULL;
- struct buffer_head *bh = NULL;
- ext4_fsblk_t bitmap_blk;
-
- RTL_BITMAP BlockBitmap;
-
- ULONG Group = 0;
- ULONG Index = 0xFFFFFFFF;
- ULONG dwHint = 0;
- ULONG Count = 0;
- ULONG Length = 0;
-
- NTSTATUS Status = STATUS_DISK_FULL;
-
- *Block = 0;
-
- ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
-
- /* validate the hint group and hint block */
- if (GroupHint >= Vcb->sbi.s_groups_count) {
- DbgBreak();
- GroupHint = Vcb->sbi.s_groups_count - 1;
- }
-
- if (BlockHint != 0) {
- GroupHint = (BlockHint - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
- dwHint = (BlockHint - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
- }
-
- Group = GroupHint;
-
-Again:
-
- if (bh)
- fini_bh(&bh);
-
- if (gb)
- fini_bh(&gb);
-
- gd = ext4_get_group_desc(sb, Group, &gb);
- if (!gd) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
-
- bitmap_blk = ext4_block_bitmap(sb, gd);
-
- if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
- bh = sb_getblk_zero(sb, bitmap_blk);
- if (!bh) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
- gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
- ext4_init_block_bitmap(sb, bh, Group, gd);
- set_buffer_uptodate(bh);
- gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
- Ext2SaveGroup(IrpContext, Vcb, Group);
- } else {
- bh = sb_getblk(sb, bitmap_blk);
- if (!bh) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
- }
-
- if (!buffer_uptodate(bh)) {
- int err = bh_submit_read(bh);
- if (err < 0) {
- DbgPrint("bh_submit_read error! err: %d\n", err);
- Status = Ext2WinntError(err);
- goto errorout;
- }
- }
-
- if (ext4_free_blks_count(sb, gd)) {
-
- if (Group == Vcb->sbi.s_groups_count - 1) {
-
- Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
-
- /* s_blocks_count is integer multiple of s_blocks_per_group */
- if (Length == 0) {
- Length = BLOCKS_PER_GROUP;
- }
- } else {
- Length = BLOCKS_PER_GROUP;
- }
-
- /* initialize bitmap buffer */
- RtlInitializeBitMap(&BlockBitmap, (PULONG)bh->b_data, Length);
-
- /* try to find a clear bit range */
- Index = RtlFindClearBits(&BlockBitmap, *Number, dwHint);
-
- /* We could not get new block in the prefered group */
- if (Index == 0xFFFFFFFF) {
-
- /* search clear bits from the hint block */
- Count = RtlFindNextForwardRunClear(&BlockBitmap, dwHint, &Index);
- if (dwHint != 0 && Count == 0) {
- /* search clear bits from the very beginning */
- Count = RtlFindNextForwardRunClear(&BlockBitmap, 0, &Index);
- }
-
- if (Count == 0) {
-
- RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
-
- /* no blocks found: set bg_free_blocks_count to 0 */
- ext4_free_blks_set(sb, gd, 0);
- Ext2SaveGroup(IrpContext, Vcb, Group);
-
- /* will try next group */
- goto Again;
-
- } else {
-
- /* we got free blocks */
- if (Count <= *Number) {
- *Number = Count;
- }
- }
- }
-
- } else {
-
- /* try next group */
- dwHint = 0;
- Group = (Group + 1) % Vcb->sbi.s_groups_count;
- if (Group != GroupHint) {
- goto Again;
- }
-
- Index = 0xFFFFFFFF;
- }
-
- if (Index < Length) {
-
- /* mark block bits as allocated */
- RtlSetBits(&BlockBitmap, Index, *Number);
-
- /* set block bitmap dirty in cache */
- mark_buffer_dirty(bh);
-
- /* update group description */
- ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
- Ext2SaveGroup(IrpContext, Vcb, Group);
-
- /* update Vcb free blocks */
- Ext2UpdateVcbStat(IrpContext, Vcb);
-
- /* validate the new allocated block number */
- *Block = Index + EXT2_FIRST_DATA_BLOCK + Group * BLOCKS_PER_GROUP;
- if (*Block >= TOTAL_BLOCKS || *Block + *Number > TOTAL_BLOCKS) {
- DbgBreak();
- dwHint = 0;
- goto Again;
- }
-
- if (ext4_block_bitmap(sb, gd) == *Block ||
- ext4_inode_bitmap(sb, gd) == *Block ||
- ext4_inode_table(sb, gd) == *Block ) {
- DbgBreak();
- dwHint = 0;
- goto Again;
- }
-
- /* Always remove dirty MCB to prevent Volume's lazy writing.
- Metadata blocks will be re-added during modifications.*/
- if (Ext2RemoveBlockExtent(Vcb, NULL, *Block, *Number)) {
- } else {
- DbgBreak();
- Ext2RemoveBlockExtent(Vcb, NULL, *Block, *Number);
- }
-
- DEBUG(DL_INF, ("Ext2NewBlock: Block %xh - %x allocated.\n",
- *Block, *Block + *Number));
- Status = STATUS_SUCCESS;
- }
-
-errorout:
-
- ExReleaseResourceLite(&Vcb->MetaBlock);
-
- if (bh)
- fini_bh(&bh);
-
- if (gb)
- fini_bh(&gb);
-
- return Status;
-}
-
-NTSTATUS
-Ext2FreeBlock(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN ULONG Block,
- IN ULONG Number
-)
-{
- struct super_block *sb = &Vcb->sb;
- PEXT2_GROUP_DESC gd;
- struct buffer_head *gb = NULL;
- ext4_fsblk_t bitmap_blk;
-
- RTL_BITMAP BlockBitmap;
- LARGE_INTEGER Offset;
-
- PBCB BitmapBcb;
- PVOID BitmapCache;
-
- ULONG Group;
- ULONG Index;
- ULONG Length;
- ULONG Count;
-
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
-
- ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
-
- DEBUG(DL_INF, ("Ext2FreeBlock: Block %xh - %x to be freed.\n",
- Block, Block + Number));
-
- Group = (Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
- Index = (Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
-
-Again:
-
- if (gb)
- fini_bh(&gb);
-
- if ( Block < EXT2_FIRST_DATA_BLOCK ||
- Block >= TOTAL_BLOCKS ||
- Group >= Vcb->sbi.s_groups_count) {
-
- DbgBreak();
- Status = STATUS_SUCCESS;
-
- } else {
-
- gd = ext4_get_group_desc(sb, Group, &gb);
- if (!gd) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
- bitmap_blk = ext4_block_bitmap(sb, gd);
-
- /* check the block is valid or not */
- if (bitmap_blk >= TOTAL_BLOCKS) {
- DbgBreak();
- Status = STATUS_DISK_CORRUPT_ERROR;
- goto errorout;
- }
-
- /* get bitmap block offset and length */
- Offset.QuadPart = bitmap_blk;
- Offset.QuadPart = Offset.QuadPart << BLOCK_BITS;
-
- if (Group == Vcb->sbi.s_groups_count - 1) {
-
- Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
-
- /* s_blocks_count is integer multiple of s_blocks_per_group */
- if (Length == 0) {
- Length = BLOCKS_PER_GROUP;
- }
-
- } else {
- Length = BLOCKS_PER_GROUP;
- }
-
- /* read and initialize bitmap */
- if (!CcPinRead( Vcb->Volume,
- &Offset,
- Vcb->BlockSize,
- PIN_WAIT,
- &BitmapBcb,
- &BitmapCache ) ) {
-
- DEBUG(DL_ERR, ("Ext2FreeBlock: failed to PinLock bitmap block %xh.\n",
- bitmap_blk));
- Status = STATUS_CANT_WAIT;
- DbgBreak();
- goto errorout;
- }
-
- /* clear usused bits */
- RtlInitializeBitMap(&BlockBitmap, BitmapCache, Length);
- Count = min(Length - Index, Number);
- RtlClearBits(&BlockBitmap, Index, Count);
-
- /* update group description table */
- ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
-
- /* indict the cache range is dirty */
- CcSetDirtyPinnedData(BitmapBcb, NULL );
- Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
- CcUnpinData(BitmapBcb);
- BitmapBcb = NULL;
- BitmapCache = NULL;
- Ext2SaveGroup(IrpContext, Vcb, Group);
-
- /* remove dirty MCB to prevent Volume's lazy writing. */
- if (Ext2RemoveBlockExtent(Vcb, NULL, Block, Count)) {
- } else {
- DbgBreak();
- Ext2RemoveBlockExtent(Vcb, NULL, Block, Count);
- }
-
- /* save super block (used/unused blocks statics) */
- Ext2UpdateVcbStat(IrpContext, Vcb);
-
- /* try next group to clear all remaining */
- Number -= Count;
- if (Number) {
- Group += 1;
- if (Group < Vcb->sbi.s_groups_count) {
- Index = 0;
- Block += Count;
- goto Again;
- } else {
- DEBUG(DL_ERR, ("Ext2FreeBlock: block number beyonds max group.\n"));
- goto errorout;
- }
- }
- }
-
- Status = STATUS_SUCCESS;
-
-errorout:
-
- if (gb)
- fini_bh(&gb);
-
- ExReleaseResourceLite(&Vcb->MetaBlock);
-
- return Status;
-}
-
-
-NTSTATUS
-Ext2NewInode(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN ULONG GroupHint,
- IN ULONG Type,
- OUT PULONG Inode
-)
-{
- struct super_block *sb = &Vcb->sb;
- PEXT2_GROUP_DESC gd;
- struct buffer_head *gb = NULL;
- struct buffer_head *bh = NULL;
- ext4_fsblk_t bitmap_blk;
-
- RTL_BITMAP InodeBitmap;
-
- ULONG Group, i, j;
- ULONG Average, Length;
-
- ULONG dwInode;
-
- NTSTATUS Status = STATUS_DISK_FULL;
-
- *Inode = dwInode = 0XFFFFFFFF;
-
- ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
-
- if (GroupHint >= Vcb->sbi.s_groups_count)
- GroupHint = GroupHint % Vcb->sbi.s_groups_count;
-
-repeat:
-
- if (bh)
- fini_bh(&bh);
-
- if (gb)
- fini_bh(&gb);
-
- Group = i = 0;
- gd = NULL;
-
- if (Type == EXT2_FT_DIR) {
-
- Average = Vcb->SuperBlock->s_free_inodes_count / Vcb->sbi.s_groups_count;
-
- for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
-
- i = (j + GroupHint) % (Vcb->sbi.s_groups_count);
- gd = ext4_get_group_desc(sb, i, &gb);
- if (!gd) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
-
- if ((gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) ||
- (ext4_used_dirs_count(sb, gd) << 8 <
- ext4_free_inodes_count(sb, gd)) ) {
- Group = i + 1;
- break;
- }
- fini_bh(&gb);
- }
-
- if (!Group) {
-
- PEXT2_GROUP_DESC desc = NULL;
-
- gd = NULL;
-
- /* get the group with the biggest vacancy */
- for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
-
- struct buffer_head *gt = NULL;
- desc = ext4_get_group_desc(sb, j, >);
- if (!desc) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
-
- /* return the group if it's not initialized yet */
- if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
- Group = j + 1;
- gd = desc;
-
- if (gb)
- fini_bh(&gb);
- gb = gt;
- gt = NULL;
- break;
- }
-
- if (!gd) {
- if (ext4_free_inodes_count(sb, desc) > 0) {
- Group = j + 1;
- gd = desc;
- if (gb)
- fini_bh(&gb);
- gb = gt;
- gt = NULL;
- }
- } else {
- if (ext4_free_inodes_count(sb, desc) >
- ext4_free_inodes_count(sb, gd)) {
- Group = j + 1;
- gd = desc;
- if (gb)
- fini_bh(&gb);
- gb = gt;
- gt = NULL;
- break;
- }
- }
- if (gt)
- fini_bh(>);
- }
- }
-
- } else {
-
- /*
- * Try to place the inode in its parent directory (GroupHint)
- */
-
- gd = ext4_get_group_desc(sb, GroupHint, &gb);
- if (!gb) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
-
- if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
- ext4_free_inodes_count(sb, gd)) {
-
- Group = GroupHint + 1;
-
- } else {
-
- /* this group is 100% cocucpied */
- fini_bh(&gb);
-
- i = GroupHint;
-
- /*
- * Use a quadratic hash to find a group with a free inode
- */
-
- for (j = 1; j < Vcb->sbi.s_groups_count; j <<= 1) {
-
-
- i = (i + j) % Vcb->sbi.s_groups_count;
- gd = ext4_get_group_desc(sb, i, &gb);
- if (!gd) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
-
- if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
- ext4_free_inodes_count(sb, gd)) {
- Group = i + 1;
- break;
- }
-
- fini_bh(&gb);
- }
- }
-
- if (!Group) {
- /*
- * That failed: try linear search for a free inode
- */
- i = GroupHint;
- for (j = 2; j < Vcb->sbi.s_groups_count; j++) {
-
- i = (i + 1) % Vcb->sbi.s_groups_count;
- gd = ext4_get_group_desc(sb, i, &gb);
- if (!gd) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
-
- if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
- ext4_free_inodes_count(sb, gd)) {
- Group = i + 1;
- break;
- }
-
- fini_bh(&gb);
- }
- }
- }
-
- if (gd == NULL || Group == 0) {
- goto errorout;
- }
-
- /* finally we got the group, but is it valid ? */
- if (Group > Vcb->sbi.s_groups_count) {
- DbgBreak();
- goto errorout;
- }
-
- /* valid group number starts from 1, not 0 */
- Group -= 1;
-
- ASSERT(gd);
- bitmap_blk = ext4_inode_bitmap(sb, gd);
- /* check the block is valid or not */
- if (bitmap_blk == 0 || bitmap_blk >= TOTAL_BLOCKS) {
- DbgBreak();
- Status = STATUS_DISK_CORRUPT_ERROR;
- goto errorout;
- }
-
- if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
- bh = sb_getblk_zero(sb, bitmap_blk);
- if (!bh) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
- gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
- ext4_init_inode_bitmap(sb, bh, Group, gd);
- set_buffer_uptodate(bh);
- gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
- Ext2SaveGroup(IrpContext, Vcb, Group);
- } else {
- bh = sb_getblk(sb, bitmap_blk);
- if (!bh) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
- }
-
- if (!buffer_uptodate(bh)) {
- int err = bh_submit_read(bh);
- if (err < 0) {
- DbgPrint("bh_submit_read error! err: %d\n", err);
- Status = Ext2WinntError(err);
- goto errorout;
- }
- }
-
- if (Vcb->sbi.s_groups_count == 1) {
- Length = INODES_COUNT;
- } else {
- if (Group + 1 == Vcb->sbi.s_groups_count) {
- Length = INODES_COUNT % INODES_PER_GROUP;
- if (!Length) {
- /* INODES_COUNT is integer multiple of INODES_PER_GROUP */
- Length = INODES_PER_GROUP;
- }
- } else {
- Length = INODES_PER_GROUP;
- }
- }
-
- RtlInitializeBitMap(&InodeBitmap, (PULONG)bh->b_data, Length);
- dwInode = RtlFindClearBits(&InodeBitmap, 1, 0);
-
- if (dwInode == 0xFFFFFFFF || dwInode >= Length) {
-
- RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
- if (ext4_free_inodes_count(sb, gd) > 0) {
- ext4_free_inodes_set(sb, gd, 0);
- Ext2SaveGroup(IrpContext, Vcb, Group);
- }
- goto repeat;
-
- } else {
-
- __u32 count = 0;
-
- /* update unused inodes count */
- count = ext4_free_inodes_count(sb, gd) - 1;
- ext4_free_inodes_set(sb, gd, count);
-
- RtlSetBits(&InodeBitmap, dwInode, 1);
-
- /* set block bitmap dirty in cache */
- mark_buffer_dirty(bh);
-
- /* If we didn't allocate from within the initialized part of the inode
- * table then we need to initialize up to this inode. */
- if (EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
-
- __u32 free;
-
- if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
- gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
- /* When marking the block group with
- * ~EXT4_BG_INODE_UNINIT we don't want to depend
- * on the value of bg_itable_unused even though
- * mke2fs could have initialized the same for us.
- * Instead we calculated the value below
- */
-
- free = 0;
- } else {
- free = EXT3_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, gd);
- }
-
- /*
- * Check the relative inode number against the last used
- * relative inode number in this group. if it is greater
- * we need to update the bg_itable_unused count
- *
- */
- if (dwInode + 1 > free) {
- ext4_itable_unused_set(sb, gd,
- (EXT3_INODES_PER_GROUP(sb) - 1 - dwInode));
- }
-
- /* We may have to initialize the block bitmap if it isn't already */
- if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
-
- struct buffer_head *block_bitmap_bh = NULL;
-
- /* recheck and clear flag under lock if we still need to */
- block_bitmap_bh = sb_getblk_zero(sb, ext4_block_bitmap(sb, gd));
- if (block_bitmap_bh) {
- gd->bg_checksum = ext4_group_desc_csum(EXT3_SB(sb), Group, gd);
- free = ext4_init_block_bitmap(sb, block_bitmap_bh, Group, gd);
- set_buffer_uptodate(block_bitmap_bh);
- brelse(block_bitmap_bh);
- gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
- ext4_free_blks_set(sb, gd, free);
- Ext2SaveGroup(IrpContext, Vcb, Group);
- }
- }
- }
-
- *Inode = dwInode + 1 + Group * INODES_PER_GROUP;
-
- /* update group_desc / super_block */
- if (Type == EXT2_FT_DIR) {
- ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) + 1);
- }
- Ext2SaveGroup(IrpContext, Vcb, Group);
- Ext2UpdateVcbStat(IrpContext, Vcb);
- Status = STATUS_SUCCESS;
- }
-
-errorout:
-
- ExReleaseResourceLite(&Vcb->MetaInode);
-
- if (bh)
- fini_bh(&bh);
-
- if (gb)
- fini_bh(&gb);
-
-
- return Status;
-}
-
-NTSTATUS
-Ext2UpdateGroupDirStat(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN ULONG group
- )
-{
- struct super_block *sb = &Vcb->sb;
- PEXT2_GROUP_DESC gd;
- struct buffer_head *gb = NULL;
- NTSTATUS status;
-
- ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
-
- /* get group desc */
- gd = ext4_get_group_desc(sb, group, &gb);
- if (!gd) {
- status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
-
- /* update group_desc and super_block */
- ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) - 1);
- Ext2SaveGroup(IrpContext, Vcb, group);
- Ext2UpdateVcbStat(IrpContext, Vcb);
- status = STATUS_SUCCESS;
-
-errorout:
-
- ExReleaseResourceLite(&Vcb->MetaInode);
-
- if (gb)
- fini_bh(&gb);
-
- return status;
-}
-
-
-NTSTATUS
-Ext2FreeInode(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN ULONG Inode,
- IN ULONG Type
-)
-{
- struct super_block *sb = &Vcb->sb;
- PEXT2_GROUP_DESC gd;
- struct buffer_head *gb = NULL;
- struct buffer_head *bh = NULL;
- ext4_fsblk_t bitmap_blk;
-
- RTL_BITMAP InodeBitmap;
- ULONG Group;
- ULONG Length;
- LARGE_INTEGER Offset;
-
- ULONG dwIno;
- BOOLEAN bModified = FALSE;
-
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
-
- ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
-
- Group = (Inode - 1) / INODES_PER_GROUP;
- dwIno = (Inode - 1) % INODES_PER_GROUP;
-
- DEBUG(DL_INF, ( "Ext2FreeInode: Inode: %xh (Group/Off = %xh/%xh)\n",
- Inode, Group, dwIno));
-
- if (Group >= Vcb->sbi.s_groups_count) {
- DbgBreak();
- goto errorout;
- }
-
- gd = ext4_get_group_desc(sb, Group, &gb);
- if (!gd) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
-
- bitmap_blk = ext4_inode_bitmap(sb, gd);
- bh = sb_getblk(sb, bitmap_blk);
- if (!bh) {
- DbgBreak();
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
- if (!buffer_uptodate(bh)) {
- int err = bh_submit_read(bh);
- if (err < 0) {
- DbgPrint("bh_submit_read error! err: %d\n", err);
- Status = Ext2WinntError(err);
- goto errorout;
- }
- }
-
- if (Group == Vcb->sbi.s_groups_count - 1) {
-
- Length = INODES_COUNT % INODES_PER_GROUP;
- if (!Length) {
- /* s_inodes_count is integer multiple of s_inodes_per_group */
- Length = INODES_PER_GROUP;
- }
- } else {
- Length = INODES_PER_GROUP;
- }
-
- RtlInitializeBitMap(&InodeBitmap, (PULONG)bh->b_data, Length);
-
- if (RtlCheckBit(&InodeBitmap, dwIno) == 0) {
- DbgBreak();
- Status = STATUS_SUCCESS;
- } else {
- RtlClearBits(&InodeBitmap, dwIno, 1);
- bModified = TRUE;
- }
-
- if (bModified) {
- /* update group free inodes */
- ext4_free_inodes_set(sb, gd,
- RtlNumberOfClearBits(&InodeBitmap));
-
- /* set inode block dirty and add to vcb dirty range */
- mark_buffer_dirty(bh);
-
- /* update group_desc and super_block */
- if (Type == EXT2_FT_DIR) {
- ext4_used_dirs_set(sb, gd,
- ext4_used_dirs_count(sb, gd) - 1);
- }
- Ext2SaveGroup(IrpContext, Vcb, Group);
- Ext2UpdateVcbStat(IrpContext, Vcb);
- Status = STATUS_SUCCESS;
- }
-
-errorout:
-
- ExReleaseResourceLite(&Vcb->MetaInode);
-
- if (bh)
- fini_bh(&bh);
-
- if (gb)
- fini_bh(&gb);
-
- return Status;
-}
-
-
-NTSTATUS
-Ext2AddEntry (
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN PEXT2_FCB Dcb,
- IN struct inode *Inode,
- IN PUNICODE_STRING FileName,
- struct dentry **Dentry
-)
-{
- struct dentry *de = NULL;
-
- NTSTATUS status = STATUS_UNSUCCESSFUL;
- OEM_STRING oem;
- int rc;
-
- BOOLEAN MainResourceAcquired = FALSE;
-
- if (!IsDirectory(Dcb)) {
- DbgBreak();
- return STATUS_NOT_A_DIRECTORY;
- }
-
- ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
- MainResourceAcquired = TRUE;
-
- __try {
-
- Ext2ReferXcb(&Dcb->ReferenceCount);
- de = Ext2BuildEntry(Vcb, Dcb->Mcb, FileName);
- if (!de) {
- status = STATUS_INSUFFICIENT_RESOURCES;
- __leave;
- }
- de->d_inode = Inode;
-
- rc = ext3_add_entry(IrpContext, de, Inode);
- status = Ext2WinntError(rc);
- if (NT_SUCCESS(status)) {
-
- /* increase dir inode's nlink for .. */
- if (S_ISDIR(Inode->i_mode)) {
- ext3_inc_count(Dcb->Inode);
- ext3_mark_inode_dirty(IrpContext, Dcb->Inode);
- }
-
- /* increase inode nlink reference */
- ext3_inc_count(Inode);
- ext3_mark_inode_dirty(IrpContext, Inode);
-
- if (Dentry) {
- *Dentry = de;
- de = NULL;
- }
- }
-
- } __finally {
-
- Ext2DerefXcb(&Dcb->ReferenceCount);
-
- if (MainResourceAcquired) {
- ExReleaseResourceLite(&Dcb->MainResource);
- }
-
- if (de)
- Ext2FreeEntry(de);
- }
-
- return status;
-}
-
-
-NTSTATUS
-Ext2SetFileType (
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN PEXT2_FCB Dcb,
- IN PEXT2_MCB Mcb,
- IN umode_t mode
- )
-{
- struct inode *dir = Dcb->Inode;
- struct buffer_head *bh = NULL;
- struct ext3_dir_entry_2 *de;
- struct inode *inode;
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
- BOOLEAN MainResourceAcquired = FALSE;
-
- if (!EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) {
- return STATUS_SUCCESS;
- }
-
- if (!IsDirectory(Dcb)) {
- return STATUS_NOT_A_DIRECTORY;
- }
-
- ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
- MainResourceAcquired = TRUE;
-
- __try {
-
- Ext2ReferXcb(&Dcb->ReferenceCount);
-
- bh = ext3_find_entry(IrpContext, Mcb->de, &de);
- if (!bh)
- __leave;
-
- inode = &Mcb->Inode;
- if (le32_to_cpu(de->inode) != inode->i_ino)
- __leave;
-
- ext3_set_de_type(inode->i_sb, de, mode);
- mark_buffer_dirty(bh);
-
- if (S_ISDIR(inode->i_mode) == S_ISDIR(mode)) {
- } else if (S_ISDIR(inode->i_mode)) {
- ext3_dec_count(dir);
- } else if (S_ISDIR(mode)) {
- ext3_inc_count(dir);
- }
- dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
- ext3_mark_inode_dirty(IrpContext, dir);
-
- inode->i_mode = mode;
- ext3_mark_inode_dirty(IrpContext, inode);
-
- Status = STATUS_SUCCESS;
-
- } __finally {
-
- Ext2DerefXcb(&Dcb->ReferenceCount);
-
- if (MainResourceAcquired)
- ExReleaseResourceLite(&Dcb->MainResource);
-
- if (bh)
- brelse(bh);
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2RemoveEntry (
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN PEXT2_FCB Dcb,
- IN PEXT2_MCB Mcb
-)
-{
- struct inode *dir = Dcb->Inode;
- struct buffer_head *bh = NULL;
- struct ext3_dir_entry_2 *de;
- struct inode *inode;
- int rc = -ENOENT;
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
- BOOLEAN MainResourceAcquired = FALSE;
-
- if (!IsDirectory(Dcb)) {
- return STATUS_NOT_A_DIRECTORY;
- }
-
- ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
- MainResourceAcquired = TRUE;
-
- __try {
-
- Ext2ReferXcb(&Dcb->ReferenceCount);
-
- bh = ext3_find_entry(IrpContext, Mcb->de, &de);
- if (!bh)
- __leave;
-
- inode = &Mcb->Inode;
- if (le32_to_cpu(de->inode) != inode->i_ino)
- __leave;
-
- if (!inode->i_nlink) {
- ext3_warning (inode->i_sb, "ext3_unlink",
- "Deleting nonexistent file (%lu), %d",
- inode->i_ino, inode->i_nlink);
- inode->i_nlink = 1;
- }
- rc = ext3_delete_entry(IrpContext, dir, de, bh);
- if (rc) {
- Status = Ext2WinntError(rc);
- __leave;
- }
- /*
- if (!inode->i_nlink)
- ext3_orphan_add(handle, inode);
- */
- inode->i_ctime = dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
- ext3_dec_count(inode);
- ext3_mark_inode_dirty(IrpContext, inode);
-
- /* decrease dir inode's nlink for .. */
- if (S_ISDIR(inode->i_mode)) {
- ext3_update_dx_flag(dir);
- ext3_dec_count(dir);
- ext3_mark_inode_dirty(IrpContext, dir);
- }
-
- Status = STATUS_SUCCESS;
-
- } __finally {
-
- Ext2DerefXcb(&Dcb->ReferenceCount);
-
- if (MainResourceAcquired)
- ExReleaseResourceLite(&Dcb->MainResource);
-
- if (bh)
- brelse(bh);
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2SetParentEntry (
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN PEXT2_FCB Dcb,
- IN ULONG OldParent,
- IN ULONG NewParent )
-{
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
-
- PEXT2_DIR_ENTRY2 pSelf = NULL;
- PEXT2_DIR_ENTRY2 pParent = NULL;
-
- ULONG dwBytes = 0;
-
- BOOLEAN MainResourceAcquired = FALSE;
-
- ULONG Offset = 0;
-
- if (!IsDirectory(Dcb)) {
- return STATUS_NOT_A_DIRECTORY;
- }
-
- if (OldParent == NewParent) {
- return STATUS_SUCCESS;
- }
-
- MainResourceAcquired =
- ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
-
- __try {
-
- Ext2ReferXcb(&Dcb->ReferenceCount);
-
- pSelf = (PEXT2_DIR_ENTRY2)
- Ext2AllocatePool(
- PagedPool,
- EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2),
- EXT2_DENTRY_MAGIC
- );
- if (!pSelf) {
- DEBUG(DL_ERR, ( "Ex2SetParentEntry: failed to allocate pSelf.\n"));
- Status = STATUS_INSUFFICIENT_RESOURCES;
- __leave;
- }
-
- dwBytes = 0;
-
- //
- // Reading the DCB contents
- //
-
- Status = Ext2ReadInode(
- IrpContext,
- Vcb,
- Dcb->Mcb,
- (ULONGLONG)Offset,
- (PVOID)pSelf,
- EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2),
- FALSE,
- &dwBytes );
-
- if (!NT_SUCCESS(Status)) {
- DEBUG(DL_ERR, ( "Ext2SetParentEntry: failed to read directory.\n"));
- __leave;
- }
-
- ASSERT(dwBytes == EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2));
-
- pParent = (PEXT2_DIR_ENTRY2)((PUCHAR)pSelf + pSelf->rec_len);
-
- if (pSelf->name_len == 1 && pSelf->name[0] == '.' &&
- pParent->name_len == 2 && pParent->name[0] == '.' &&
- pParent->name[1] == '.') {
-
- if (pParent->inode != OldParent) {
- DbgBreak();
- }
- pParent->inode = NewParent;
-
- Status = Ext2WriteInode(
- IrpContext,
- Vcb,
- Dcb->Mcb,
- (ULONGLONG)Offset,
- pSelf,
- dwBytes,
- FALSE,
- &dwBytes );
- } else {
- DbgBreak();
- }
-
- } __finally {
-
-
- if (Ext2DerefXcb(&Dcb->ReferenceCount) == 0) {
- DEBUG(DL_ERR, ( "Ext2SetParentEntry: Dcb reference goes to ZERO.\n"));
- }
-
- if (MainResourceAcquired) {
- ExReleaseResourceLite(&Dcb->MainResource);
- }
-
- if (pSelf) {
- Ext2FreePool(pSelf, EXT2_DENTRY_MAGIC);
- }
- }
-
- return Status;
-}
-
-int ext3_check_dir_entry (const char * function, struct inode * dir,
- struct ext3_dir_entry_2 * de,
- struct buffer_head * bh,
- unsigned long offset)
-{
- const char * error_msg = NULL;
- const int rlen = ext3_rec_len_from_disk(de->rec_len);
-
- if (rlen < EXT3_DIR_REC_LEN(1))
- error_msg = "rec_len is smaller than minimal";
- else if (rlen % 4 != 0)
- error_msg = "rec_len % 4 != 0";
- else if (rlen < EXT3_DIR_REC_LEN(de->name_len))
- error_msg = "rec_len is too small for name_len";
- else if ((char *) de + rlen > bh->b_data + dir->i_sb->s_blocksize)
- error_msg = "directory entry across blocks";
- else if (le32_to_cpu(de->inode) >
- le32_to_cpu(EXT3_SB(dir->i_sb)->s_es->s_inodes_count))
- error_msg = "inode out of bounds";
-
- if (error_msg != NULL) {
- DEBUG(DL_ERR, ("%s: bad entry in directory %u: %s - "
- "offset=%u, inode=%u, rec_len=%d, name_len=%d\n",
- function, dir->i_ino, error_msg, offset,
- (unsigned long) le32_to_cpu(de->inode),
- rlen, de->name_len));
- }
- return error_msg == NULL ? 1 : 0;
-}
-
-
-/*
- * p is at least 6 bytes before the end of page
- */
-struct ext3_dir_entry_2 *
- ext3_next_entry(struct ext3_dir_entry_2 *p)
-{
- return (struct ext3_dir_entry_2 *)((char *)p +
- ext3_rec_len_from_disk(p->rec_len));
-}
-
-#define MAX_LFS_FILESIZE 0x7fffffffffffffff
-
-/*
- * Maximal extent format file size.
- * Resulting logical blkno at s_maxbytes must fit in our on-disk
- * extent format containers, within a sector_t, and within i_blocks
- * in the vfs. ext4 inode has 48 bits of i_block in fsblock units,
- * so that won't be a limiting factor.
- *
- * Note, this does *not* consider any metadata overhead for vfs i_blocks.
- */
-static loff_t ext4_max_size(int blkbits, int has_huge_files)
-{
- loff_t res;
- loff_t upper_limit = MAX_LFS_FILESIZE;
-
- /* small i_blocks in vfs inode? */
- if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
- /*
- * CONFIG_LBD is not enabled implies the inode
- * i_block represent total blocks in 512 bytes
- * 32 == size of vfs inode i_blocks * 8
- */
- upper_limit = (1LL << 32) - 1;
-
- /* total blocks in file system block size */
- upper_limit >>= (blkbits - 9);
- upper_limit <<= blkbits;
- }
-
- /* 32-bit extent-start container, ee_block */
- res = 1LL << 32;
- res <<= blkbits;
- res -= 1;
-
- /* Sanity check against vm- & vfs- imposed limits */
- if (res > upper_limit)
- res = upper_limit;
-
- return res;
-}
-
-/*
- * Maximal extent format file size.
- * Resulting logical blkno at s_maxbytes must fit in our on-disk
- * extent format containers, within a sector_t, and within i_blocks
- * in the vfs. ext4 inode has 48 bits of i_block in fsblock units,
- * so that won't be a limiting factor.
- *
- * Note, this does *not* consider any metadata overhead for vfs i_blocks.
- */
-loff_t ext3_max_size(int blkbits, int has_huge_files)
-{
- loff_t res;
- loff_t upper_limit = MAX_LFS_FILESIZE;
-
- /* small i_blocks in vfs inode? */
- if (!has_huge_files) {
- /*
- * CONFIG_LBD is not enabled implies the inode
- * i_block represent total blocks in 512 bytes
- * 32 == size of vfs inode i_blocks * 8
- */
- upper_limit = ((loff_t)1 << 32) - 1;
-
- /* total blocks in file system block size */
- upper_limit >>= (blkbits - 9);
- upper_limit <<= blkbits;
- }
-
- /* 32-bit extent-start container, ee_block */
- res = (loff_t)1 << 32;
- res <<= blkbits;
- res -= 1;
-
- /* Sanity check against vm- & vfs- imposed limits */
- if (res > upper_limit)
- res = upper_limit;
-
- return res;
-}
-
-/*
- * Maximal bitmap file size. There is a direct, and {,double-,triple-}indirect
- * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks.
- * We need to be 1 filesystem block less than the 2^48 sector limit.
- */
-loff_t ext3_max_bitmap_size(int bits, int has_huge_files)
-{
- loff_t res = EXT3_NDIR_BLOCKS;
- int meta_blocks;
- loff_t upper_limit;
- /* This is calculated to be the largest file size for a
- * dense, bitmapped file such that the total number of
- * sectors in the file, including data and all indirect blocks,
- * does not exceed 2^48 -1
- * __u32 i_blocks_lo and _u16 i_blocks_high representing the
- * total number of 512 bytes blocks of the file
- */
-
- if (!has_huge_files) {
- /*
- * !has_huge_files or CONFIG_LBD is not enabled
- * implies the inode i_block represent total blocks in
- * 512 bytes 32 == size of vfs inode i_blocks * 8
- */
- upper_limit = ((loff_t)1 << 32) - 1;
-
- /* total blocks in file system block size */
- upper_limit >>= (bits - 9);
-
- } else {
- /*
- * We use 48 bit ext4_inode i_blocks
- * With EXT4_HUGE_FILE_FL set the i_blocks
- * represent total number of blocks in
- * file system block size
- */
- upper_limit = ((loff_t)1 << 48) - 1;
-
- }
-
- /* indirect blocks */
- meta_blocks = 1;
- /* double indirect blocks */
- meta_blocks += 1 + ((loff_t)1 << (bits-2));
- /* tripple indirect blocks */
- meta_blocks += 1 + ((loff_t)1 << (bits-2)) + ((loff_t)1 << (2*(bits-2)));
-
- upper_limit -= meta_blocks;
- upper_limit <<= bits;
-
- res += (loff_t)1 << (bits-2);
- res += (loff_t)1 << (2*(bits-2));
- res += (loff_t)1 << (3*(bits-2));
- res <<= bits;
- if (res > upper_limit)
- res = upper_limit;
-
- if (res > MAX_LFS_FILESIZE)
- res = MAX_LFS_FILESIZE;
-
- return res;
-}
-
-blkcnt_t ext3_inode_blocks(struct ext3_inode *raw_inode,
- struct inode *inode)
-{
- blkcnt_t i_blocks ;
- struct super_block *sb = inode->i_sb;
- PEXT2_VCB Vcb = (PEXT2_VCB)sb->s_priv;
-
- if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
- EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
- /* we are using combined 48 bit field */
- i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 |
- le32_to_cpu(raw_inode->i_blocks);
- if (inode->i_flags & EXT4_HUGE_FILE_FL) {
- /* i_blocks represent file system block size */
- return i_blocks << (BLOCK_BITS - 9);
- } else {
- return i_blocks;
- }
- } else {
- return le32_to_cpu(raw_inode->i_blocks);
- }
-}
-
-int ext3_inode_blocks_set(struct ext3_inode *raw_inode,
- struct inode * inode)
-{
- u64 i_blocks = inode->i_blocks;
- struct super_block *sb = inode->i_sb;
- PEXT2_VCB Vcb = (PEXT2_VCB)sb->s_priv;
-
- if (i_blocks < 0x100000000) {
- /*
- * i_blocks can be represnted in a 32 bit variable
- * as multiple of 512 bytes
- */
- raw_inode->i_blocks = cpu_to_le32(i_blocks);
- raw_inode->i_blocks_high = 0;
- inode->i_flags &= ~EXT4_HUGE_FILE_FL;
- return 0;
- }
-
- if (!EXT3_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
- EXT3_SET_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
- Ext2SaveSuper(NULL, Vcb);
- }
-
- if (i_blocks <= 0xffffffffffff) {
- /*
- * i_blocks can be represented in a 48 bit variable
- * as multiple of 512 bytes
- */
- raw_inode->i_blocks = (__u32)cpu_to_le32(i_blocks);
- raw_inode->i_blocks_high = (__u16)cpu_to_le16(i_blocks >> 32);
- inode->i_flags &= ~EXT4_HUGE_FILE_FL;
- } else {
- inode->i_flags |= EXT4_HUGE_FILE_FL;
- /* i_block is stored in file system block size */
- i_blocks = i_blocks >> (BLOCK_BITS - 9);
- raw_inode->i_blocks = (__u32)cpu_to_le32(i_blocks);
- raw_inode->i_blocks_high = (__u16)cpu_to_le16(i_blocks >> 32);
- }
- return 0;
-}
-
-ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
- struct ext4_group_desc *bg)
-{
- return le32_to_cpu(bg->bg_block_bitmap) |
- (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
- (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
-}
-
-ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
- struct ext4_group_desc *bg)
-{
- return le32_to_cpu(bg->bg_inode_bitmap) |
- (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
- (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
-}
-
-ext4_fsblk_t ext4_inode_table(struct super_block *sb,
- struct ext4_group_desc *bg)
-{
- return le32_to_cpu(bg->bg_inode_table) |
- (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
- (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
-}
-
-__u32 ext4_free_blks_count(struct super_block *sb,
- struct ext4_group_desc *bg)
-{
- return le16_to_cpu(bg->bg_free_blocks_count) |
- (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
- (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0);
-}
-
-__u32 ext4_free_inodes_count(struct super_block *sb,
- struct ext4_group_desc *bg)
-{
- return le16_to_cpu(bg->bg_free_inodes_count) |
- (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
- (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0);
-}
-
-__u32 ext4_used_dirs_count(struct super_block *sb,
- struct ext4_group_desc *bg)
-{
- return le16_to_cpu(bg->bg_used_dirs_count) |
- (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
- (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0);
-}
-
-__u32 ext4_itable_unused_count(struct super_block *sb,
- struct ext4_group_desc *bg)
-{
- return le16_to_cpu(bg->bg_itable_unused) |
- (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
- (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0);
-}
-
-void ext4_block_bitmap_set(struct super_block *sb,
- struct ext4_group_desc *bg, ext4_fsblk_t blk)
-{
- bg->bg_block_bitmap = cpu_to_le32((u32)blk);
- if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
- bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32);
-}
-
-void ext4_inode_bitmap_set(struct super_block *sb,
- struct ext4_group_desc *bg, ext4_fsblk_t blk)
-{
- bg->bg_inode_bitmap = cpu_to_le32((u32)blk);
- if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
- bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32);
-}
-
-void ext4_inode_table_set(struct super_block *sb,
- struct ext4_group_desc *bg, ext4_fsblk_t blk)
-{
- bg->bg_inode_table = cpu_to_le32((u32)blk);
- if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
- bg->bg_inode_table_hi = cpu_to_le32(blk >> 32);
-}
-
-void ext4_free_blks_set(struct super_block *sb,
- struct ext4_group_desc *bg, __u32 count)
-{
- bg->bg_free_blocks_count = cpu_to_le16((__u16)count);
- if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
- bg->bg_free_blocks_count_hi = cpu_to_le16(count >> 16);
-}
-
-void ext4_free_inodes_set(struct super_block *sb,
- struct ext4_group_desc *bg, __u32 count)
-{
- bg->bg_free_inodes_count = cpu_to_le16((__u16)count);
- if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
- bg->bg_free_inodes_count_hi = cpu_to_le16(count >> 16);
-}
-
-void ext4_used_dirs_set(struct super_block *sb,
- struct ext4_group_desc *bg, __u32 count)
-{
- bg->bg_used_dirs_count = cpu_to_le16((__u16)count);
- if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
- bg->bg_used_dirs_count_hi = cpu_to_le16(count >> 16);
-}
-
-void ext4_itable_unused_set(struct super_block *sb,
- struct ext4_group_desc *bg, __u32 count)
-{
- bg->bg_itable_unused = cpu_to_le16((__u16)count);
- if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
- bg->bg_itable_unused_hi = cpu_to_le16(count >> 16);
-}
-
-/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */
-__u16 const crc16_table[256] = {
- 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
- 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
- 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
- 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
- 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
- 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
- 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
- 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
- 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
- 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
- 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
- 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
- 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
- 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
- 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
- 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
- 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
- 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
- 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
- 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
- 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
- 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
- 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
- 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
- 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
- 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
- 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
- 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
- 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
- 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
- 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
- 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
-};
-
-static inline __u16 crc16_byte(__u16 crc, const __u8 data)
-{
- return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
-}
-
-__u16 crc16(__u16 crc, __u8 const *buffer, size_t len)
-{
- while (len--)
- crc = crc16_byte(crc, *buffer++);
- return crc;
-}
-
-__le16 ext4_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group,
- struct ext4_group_desc *gdp)
-{
- int offset;
- __u16 crc = 0;
- __le32 le_group = cpu_to_le32(block_group);
-
- /* old crc16 code */
- if (!(sbi->s_es->s_feature_ro_compat &
- cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
- return 0;
-
- offset = offsetof(struct ext4_group_desc, bg_checksum);
-
- crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
- crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
- crc = crc16(crc, (__u8 *)gdp, offset);
- offset += sizeof(gdp->bg_checksum); /* skip checksum */
- /* for checksum of struct ext4_group_desc do the rest...*/
- if ((sbi->s_es->s_feature_incompat &
- cpu_to_le32(EXT4_FEATURE_INCOMPAT_64BIT)) &&
- offset < le16_to_cpu(sbi->s_es->s_desc_size))
- crc = crc16(crc, (__u8 *)gdp + offset,
- le16_to_cpu(sbi->s_es->s_desc_size) -
- offset);
-
- return cpu_to_le16(crc);
-}
-
-int ext4_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group,
- struct ext4_group_desc *gdp)
-{
- if ((sbi->s_es->s_feature_ro_compat & cpu_to_le32(EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) &&
- (gdp->bg_checksum != ext4_group_desc_csum(sbi, block_group, gdp)))
- return 0;
-
- return 1;
-}
-
-
-static inline int test_root(ext3_group_t a, ext3_group_t b)
-{
- ext3_group_t num = b;
-
- while (a > num)
- num *= b;
- return num == a;
-}
-
-static int ext3_group_sparse(ext3_group_t group)
-{
- if (group <= 1)
- return 1;
- if (!(group & 1))
- return 0;
- return (test_root(group, 7) || test_root(group, 5) ||
- test_root(group, 3));
-}
-
-/**
- * ext4_bg_has_super - number of blocks used by the superblock in group
- * @sb: superblock for filesystem
- * @group: group number to check
- *
- * Return the number of blocks used by the superblock (primary or backup)
- * in this group. Currently this will be only 0 or 1.
- */
-int ext3_bg_has_super(struct super_block *sb, ext3_group_t group)
-{
- if (EXT3_HAS_RO_COMPAT_FEATURE(sb,
- EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
- !ext3_group_sparse(group))
- return 0;
- return 1;
-}
-
-static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb,
- ext4_group_t group)
-{
- unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
- ext4_group_t first = metagroup * EXT4_DESC_PER_BLOCK(sb);
- ext4_group_t last = first + EXT4_DESC_PER_BLOCK(sb) - 1;
-
- if (group == first || group == first + 1 || group == last)
- return 1;
- return 0;
-}
-
-static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb,
- ext4_group_t group)
-{
- return ext3_bg_has_super(sb, group) ? EXT3_SB(sb)->s_gdb_count : 0;
-}
-
-/**
- * ext4_bg_num_gdb - number of blocks used by the group table in group
- * @sb: superblock for filesystem
- * @group: group number to check
- *
- * Return the number of blocks used by the group descriptor table
- * (primary or backup) in this group. In the future there may be a
- * different number of descriptor blocks in each group.
- */
-unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
-{
- unsigned long first_meta_bg =
- le32_to_cpu(EXT3_SB(sb)->s_es->s_first_meta_bg);
- unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
-
- if (!EXT3_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) ||
- metagroup < first_meta_bg)
- return ext4_bg_num_gdb_nometa(sb, group);
-
- return ext4_bg_num_gdb_meta(sb,group);
-
-}
-
-ext3_fsblk_t descriptor_loc(struct super_block *sb,
- ext3_fsblk_t logical_sb_block, unsigned int nr)
-{
- struct ext3_sb_info *sbi = EXT3_SB(sb);
- ext3_group_t bg, first_meta_bg;
- int has_super = 0;
-
- first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
-
- if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
- nr < first_meta_bg)
- return logical_sb_block + nr + 1;
- bg = sbi->s_desc_per_block * nr;
- if (ext3_bg_has_super(sb, bg))
- has_super = 1;
- return (has_super + ext3_group_first_block_no(sb, bg));
-}
-
-#define ext4_set_bit(n, p) set_bit((int)(n), (unsigned long *)(p))
-
-/*
- * The free inodes are managed by bitmaps. A file system contains several
- * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
- * block for inodes, N blocks for the inode table and data blocks.
- *
- * The file system contains group descriptors which are located after the
- * super block. Each descriptor contains the number of the bitmap block and
- * the free blocks count in the block.
- */
-
-/*
- * To avoid calling the atomic setbit hundreds or thousands of times, we only
- * need to use it within a single byte (to ensure we get endianness right).
- * We can use memset for the rest of the bitmap as there are no other users.
- */
-void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
-{
- int i;
-
- if (start_bit >= end_bit)
- return;
-
- DEBUG(DL_INF, ("mark end bits +%d through +%d used\n", start_bit, end_bit));
- for (i = start_bit; (unsigned)i < ((start_bit + 7) & ~7UL); i++)
- ext4_set_bit(i, bitmap);
- if (i < end_bit)
- memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
-}
-
-/* Initializes an uninitialized inode bitmap */
-unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh,
- ext4_group_t block_group,
- struct ext4_group_desc *gdp)
-{
- struct ext3_sb_info *sbi = EXT3_SB(sb);
-
- mark_buffer_dirty(bh);
-
- /* If checksum is bad mark all blocks and inodes use to prevent
- * allocation, essentially implementing a per-group read-only flag. */
- if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
- ext4_error(sb, __FUNCTION__, "Checksum bad for group %u",
- block_group);
- ext4_free_blks_set(sb, gdp, 0);
- ext4_free_inodes_set(sb, gdp, 0);
- ext4_itable_unused_set(sb, gdp, 0);
- memset(bh->b_data, 0xff, sb->s_blocksize);
- return 0;
- }
-
- memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
- mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
- bh->b_data);
- ext4_itable_unused_set(sb, gdp, EXT4_INODES_PER_GROUP(sb));
-
- return EXT4_INODES_PER_GROUP(sb);
-}
-
-/*
- * Calculate the block group number and offset, given a block number
- */
-void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
- ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp)
-{
- struct ext3_super_block *es = EXT3_SB(sb)->s_es;
- ext4_grpblk_t offset;
-
- blocknr = blocknr - le32_to_cpu(es->s_first_data_block);
- offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb));
- if (offsetp)
- *offsetp = offset;
- if (blockgrpp)
- *blockgrpp = (ext4_grpblk_t)blocknr;
-
-}
-
-static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
- ext4_group_t block_group)
-{
- ext4_group_t actual_group;
- ext4_get_group_no_and_offset(sb, block, &actual_group, NULL);
- if (actual_group == block_group)
- return 1;
- return 0;
-}
-
-static int ext4_group_used_meta_blocks(struct super_block *sb,
- ext4_group_t block_group)
-{
- ext4_fsblk_t tmp;
- struct ext3_sb_info *sbi = EXT3_SB(sb);
- /* block bitmap, inode bitmap, and inode table blocks */
- int used_blocks = sbi->s_itb_per_group + 2;
-
- if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
- struct ext4_group_desc *gdp;
- struct buffer_head *bh = NULL;
-
- gdp = ext4_get_group_desc(sb, block_group, &bh);
- if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp),
- block_group))
- used_blocks--;
-
- if (!ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp),
- block_group))
- used_blocks--;
-
- tmp = ext4_inode_table(sb, gdp);
- for (; tmp < ext4_inode_table(sb, gdp) +
- sbi->s_itb_per_group; tmp++) {
- if (!ext4_block_in_group(sb, tmp, block_group))
- used_blocks -= 1;
- }
- if (bh)
- fini_bh(&bh);
- }
- return used_blocks;
-}
-
-/* Initializes an uninitialized block bitmap if given, and returns the
- * number of blocks free in the group. */
-unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
- ext4_group_t block_group, struct ext4_group_desc *gdp)
-{
- int bit, bit_max;
- unsigned free_blocks, group_blocks;
- struct ext3_sb_info *sbi = EXT3_SB(sb);
-
- if (bh) {
- mark_buffer_dirty(bh);
- /* If checksum is bad mark all blocks used to prevent allocation
- * essentially implementing a per-group read-only flag. */
- if (!ext4_group_desc_csum_verify(sbi, block_group, gdp)) {
- ext4_error(sb, __FUNCTION__,
- "Checksum bad for group %u", block_group);
- ext4_free_blks_set(sb, gdp, 0);
- ext4_free_inodes_set(sb, gdp, 0);
- ext4_itable_unused_set(sb, gdp, 0);
- memset(bh->b_data, 0xff, sb->s_blocksize);
- return 0;
- }
- memset(bh->b_data, 0, sb->s_blocksize);
- }
-
- /* Check for superblock and gdt backups in this group */
- bit_max = ext3_bg_has_super(sb, block_group);
-
- if (!EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
- block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
- sbi->s_desc_per_block) {
- if (bit_max) {
- bit_max += ext4_bg_num_gdb(sb, block_group);
- bit_max +=
- le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
- }
- } else { /* For META_BG_BLOCK_GROUPS */
- bit_max += ext4_bg_num_gdb(sb, block_group);
- }
-
- if (block_group == sbi->s_groups_count - 1) {
- /*
- * Even though mke2fs always initialize first and last group
- * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
- * to make sure we calculate the right free blocks
- */
- group_blocks = (unsigned int)(ext3_blocks_count(sbi->s_es) -
- le32_to_cpu(sbi->s_es->s_first_data_block) -
- (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1)));
- } else {
- group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
- }
-
- free_blocks = group_blocks - bit_max;
-
- if (bh) {
- ext4_fsblk_t start, tmp;
- int flex_bg = 0;
-
- for (bit = 0; bit < bit_max; bit++)
- ext4_set_bit(bit, bh->b_data);
-
- start = ext3_group_first_block_no(sb, block_group);
-
- if (EXT3_HAS_INCOMPAT_FEATURE(sb,
- EXT4_FEATURE_INCOMPAT_FLEX_BG))
- flex_bg = 1;
-
- /* Set bits for block and inode bitmaps, and inode table */
- tmp = ext4_block_bitmap(sb, gdp);
- if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
- ext4_set_bit(tmp - start, bh->b_data);
-
- tmp = ext4_inode_bitmap(sb, gdp);
- if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
- ext4_set_bit(tmp - start, bh->b_data);
-
- tmp = ext4_inode_table(sb, gdp);
- for (; tmp < ext4_inode_table(sb, gdp) +
- sbi->s_itb_per_group; tmp++) {
- if (!flex_bg ||
- ext4_block_in_group(sb, tmp, block_group))
- ext4_set_bit(tmp - start, bh->b_data);
- }
- /*
- * Also if the number of blocks within the group is
- * less than the blocksize * 8 ( which is the size
- * of bitmap ), set rest of the block bitmap to 1
- */
- mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);
- }
- return free_blocks - ext4_group_used_meta_blocks(sb, block_group);
-}
-
-/**
- * ext4_get_group_desc() -- load group descriptor from disk
- * @sb: super block
- * @block_group: given block group
- * @bh: pointer to the buffer head to store the block
- * group descriptor
- */
-struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
- ext4_group_t block_group, struct buffer_head **bh)
-{
- struct ext4_group_desc *desc = NULL;
- struct ext3_sb_info *sbi = EXT3_SB(sb);
- PEXT2_VCB vcb = sb->s_priv;
- ext4_group_t group;
- ext4_group_t offset;
-
- if (bh)
- *bh = NULL;
-
- if (block_group >= sbi->s_groups_count) {
- ext4_error(sb, "ext4_get_group_desc",
- "block_group >= groups_count - "
- "block_group = %u, groups_count = %u",
- block_group, sbi->s_groups_count);
-
- return NULL;
- }
-
- __try {
-
- group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
- offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
-
- if (!sbi->s_gd) {
- if (!Ext2LoadGroup(vcb)) {
- __leave;
- }
- } else if ( !sbi->s_gd[group].block ||
- !sbi->s_gd[group].bh) {
- if (!Ext2LoadGroupBH(vcb)) {
- __leave;
- }
- }
-
- desc = (struct ext4_group_desc *)((PCHAR)sbi->s_gd[group].gd +
- offset * EXT4_DESC_SIZE(sb));
- if (bh) {
- atomic_inc(&sbi->s_gd[group].bh->b_count);
- *bh = sbi->s_gd[group].bh;
- }
- } __finally {
- /* do cleanup */
- }
-
- return desc;
-}
-
-
-/**
- * ext4_count_free_blocks() -- count filesystem free blocks
- * @sb: superblock
- *
- * Adds up the number of free blocks from each block group.
- */
-ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
-{
- ext4_fsblk_t desc_count;
- struct ext4_group_desc *gdp;
- struct buffer_head *bh = NULL;
- ext4_group_t i;
- ext4_group_t ngroups = EXT3_SB(sb)->s_groups_count;
-
- desc_count = 0;
- smp_rmb();
- for (i = 0; i < ngroups; i++) {
- gdp = ext4_get_group_desc(sb, i, &bh);
- if (!bh)
- continue;
- desc_count += ext4_free_blks_count(sb, gdp);
- fini_bh(&bh);
- }
-
- return desc_count;
-}
-
-unsigned long ext4_count_free_inodes(struct super_block *sb)
-{
- unsigned long desc_count;
- struct ext4_group_desc *gdp;
- struct buffer_head *bh = NULL;
- ext4_group_t i;
-
- desc_count = 0;
- for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
- gdp = ext4_get_group_desc(sb, i, &bh);
- if (!bh)
- continue;
- desc_count += ext4_free_inodes_count(sb, gdp);
- fini_bh(&bh);
- }
- return desc_count;
-}
-
-/* Called at mount-time, super-block is locked */
-unsigned long ext4_count_dirs(struct super_block * sb)
-{
- struct ext4_group_desc *gdp;
- struct buffer_head *bh = NULL;
- unsigned long count = 0;
- ext4_group_t i;
-
- for (i = 0; i < EXT3_SB(sb)->s_groups_count; i++) {
- gdp = ext4_get_group_desc(sb, i, &bh);
- if (!bh)
- continue;
- count += ext4_used_dirs_count(sb, gdp);
- fini_bh(&bh);
- }
- return count;
-}
-
-/* Called at mount-time, super-block is locked */
-int ext4_check_descriptors(struct super_block *sb)
-{
- PEXT2_VCB Vcb = sb->s_priv;
- struct ext3_sb_info *sbi = EXT3_SB(sb);
- ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
- ext4_fsblk_t last_block;
- ext4_fsblk_t block_bitmap;
- ext4_fsblk_t inode_bitmap;
- ext4_fsblk_t inode_table;
- int flexbg_flag = 0;
- ext4_group_t i;
-
- if (EXT3_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
- flexbg_flag = 1;
-
- DEBUG(DL_INF, ("Checking group descriptors"));
-
- for (i = 0; i < sbi->s_groups_count; i++) {
-
- struct buffer_head *bh = NULL;
- struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, &bh);
-
- if (!bh)
- continue;
-
- if (i == sbi->s_groups_count - 1 || flexbg_flag)
- last_block = ext3_blocks_count(sbi->s_es) - 1;
- else
- last_block = first_block +
- (EXT3_BLOCKS_PER_GROUP(sb) - 1);
-
- block_bitmap = ext4_block_bitmap(sb, gdp);
- if (block_bitmap < first_block || block_bitmap > last_block) {
- printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
- "Block bitmap for group %u not in group "
- "(block %llu)!\n", i, block_bitmap);
- __brelse(bh);
- return 0;
- }
- inode_bitmap = ext4_inode_bitmap(sb, gdp);
- if (inode_bitmap < first_block || inode_bitmap > last_block) {
- printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
- "Inode bitmap for group %u not in group "
- "(block %llu)!\n", i, inode_bitmap);
- __brelse(bh);
- return 0;
- }
- inode_table = ext4_inode_table(sb, gdp);
- if (inode_table < first_block ||
- inode_table + sbi->s_itb_per_group - 1 > last_block) {
- printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
- "Inode table for group %u not in group "
- "(block %llu)!\n", i, inode_table);
- __brelse(bh);
- return 0;
- }
-
- if (!ext4_group_desc_csum_verify(sbi, i, gdp)) {
- printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
- "Checksum for group %u failed (%u!=%u)\n",
- i, le16_to_cpu(ext4_group_desc_csum(sbi, i,
- gdp)),
- le16_to_cpu(gdp->bg_checksum));
- if (!IsVcbReadOnly(Vcb)) {
- __brelse(bh);
- return 0;
- }
- }
-
- if (!flexbg_flag)
- first_block += EXT4_BLOCKS_PER_GROUP(sb);
-
- __brelse(bh);
- }
-
- ext3_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
- sbi->s_es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
- return 1;
-}
+/*
+ * COPYRIGHT: See COPYRIGHT.TXT
+ * PROJECT: Ext2 File System Driver for WinNT/2K/XP
+ * FILE: generic.c
+ * PROGRAMMER: Matt Wu
+ * HOMEPAGE: http://www.ext2fsd.com
+ * UPDATE HISTORY:
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "ext2fs.h"
+#include "linux\ext4.h"
+
+/* GLOBALS ***************************************************************/
+
+extern PEXT2_GLOBAL Ext2Global;
+
+/* DEFINITIONS *************************************************************/
+
+
+/* FUNCTIONS ***************************************************************/
+
+NTSTATUS
+Ext2LoadSuper(IN PEXT2_VCB Vcb,
+ IN BOOLEAN bVerify,
+ OUT PEXT2_SUPER_BLOCK * Sb)
+{
+ NTSTATUS Status;
+ PEXT2_SUPER_BLOCK Ext2Sb = NULL;
+
+ Ext2Sb = (PEXT2_SUPER_BLOCK)
+ Ext2AllocatePool(
+ PagedPool,
+ sizeof(EXT2_SUPER_BLOCK),
+ EXT2_SB_MAGIC
+ );
+ if (!Ext2Sb) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ Status = Ext2ReadDisk(
+ Vcb,
+ (ULONGLONG) SUPER_BLOCK_OFFSET,
+ sizeof(EXT2_SUPER_BLOCK),
+ (PVOID) Ext2Sb,
+ bVerify );
+
+ if (!NT_SUCCESS(Status)) {
+ Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
+ Ext2Sb = NULL;
+ }
+
+errorout:
+
+ *Sb = Ext2Sb;
+ return Status;
+}
+
+
+BOOLEAN
+Ext2SaveSuper(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb
+)
+{
+ LONGLONG offset;
+ BOOLEAN rc;
+
+ ext4_superblock_csum_set(&Vcb->sb);
+ offset = (LONGLONG) SUPER_BLOCK_OFFSET;
+ rc = Ext2SaveBuffer( IrpContext,
+ Vcb,
+ offset,
+ sizeof(EXT2_SUPER_BLOCK),
+ Vcb->SuperBlock
+ );
+
+ if (IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
+ Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Ext2RefreshSuper (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb
+)
+{
+ LONGLONG offset;
+ IO_STATUS_BLOCK iosb;
+
+ offset = (LONGLONG) SUPER_BLOCK_OFFSET;
+ if (!CcCopyRead(
+ Vcb->Volume,
+ (PLARGE_INTEGER)&offset,
+ sizeof(EXT2_SUPER_BLOCK),
+ TRUE,
+ (PVOID)Vcb->SuperBlock,
+ &iosb )) {
+ return FALSE;
+ }
+
+ if (!NT_SUCCESS(iosb.Status)) {
+ return FALSE;
+ }
+
+ /* reload root inode */
+ if (Vcb->McbTree) {
+
+ if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode))
+ return FALSE;
+
+ /* initializeroot node */
+ Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime);
+ Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime);
+ Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
+ Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
+ }
+
+ return TRUE;
+}
+
+VOID
+Ext2DropGroupBH(IN PEXT2_VCB Vcb)
+{
+ struct ext4_sb_info *sbi = &Vcb->sbi;
+ unsigned long i;
+
+ if (NULL == Vcb->sbi.s_gd) {
+ return;
+ }
+
+ for (i = 0; i < Vcb->sbi.s_gdb_count; i++) {
+ if (Vcb->sbi.s_gd[i].bh) {
+ fini_bh(&sbi->s_gd[i].bh);
+ Vcb->sbi.s_gd[i].bh = NULL;
+ }
+ }
+}
+
+VOID
+Ext2PutGroup(IN PEXT2_VCB Vcb)
+{
+ struct ext4_sb_info *sbi = &Vcb->sbi;
+ unsigned long i;
+
+
+ if (NULL == Vcb->sbi.s_gd) {
+ return;
+ }
+
+ Ext2DropGroupBH(Vcb);
+
+ kfree(Vcb->sbi.s_gd);
+ Vcb->sbi.s_gd = NULL;
+
+ ClearFlag(Vcb->Flags, VCB_GD_LOADED);
+}
+
+
+BOOLEAN
+Ext2LoadGroupBH(IN PEXT2_VCB Vcb)
+{
+ struct super_block *sb = &Vcb->sb;
+ struct ext4_sb_info *sbi = &Vcb->sbi;
+ unsigned long i;
+ BOOLEAN rc = FALSE;
+
+ __try {
+
+ ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
+ ASSERT (NULL != sbi->s_gd);
+
+ for (i = 0; i < sbi->s_gdb_count; i++) {
+ ASSERT (sbi->s_gd[i].block);
+ if (sbi->s_gd[i].bh)
+ continue;
+ sbi->s_gd[i].bh = sb_getblk(sb, sbi->s_gd[i].block);
+ if (!sbi->s_gd[i].bh) {
+ DEBUG(DL_ERR, ("Ext2LoadGroupBH: can't read group descriptor %d\n", i));
+ DbgBreak();
+ __leave;
+ }
+ sbi->s_gd[i].gd = (struct ext4_group_desc *)sbi->s_gd[i].bh->b_data;
+ }
+
+ rc = TRUE;
+
+ } __finally {
+
+ ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Ext2LoadGroup(IN PEXT2_VCB Vcb)
+{
+ struct super_block *sb = &Vcb->sb;
+ struct ext4_sb_info *sbi = &Vcb->sbi;
+ ext3_fsblk_t sb_block = 1;
+ unsigned long i;
+ BOOLEAN rc = FALSE;
+
+ __try {
+
+ ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
+
+ if (NULL == sbi->s_gd) {
+ sbi->s_gd = kzalloc(sbi->s_gdb_count * sizeof(struct ext3_gd),
+ GFP_KERNEL);
+ }
+ if (sbi->s_gd == NULL) {
+ DEBUG(DL_ERR, ("Ext2LoadGroup: not enough memory.\n"));
+ __leave;
+ }
+
+ if (BLOCK_SIZE != EXT3_MIN_BLOCK_SIZE) {
+ sb_block = EXT4_MIN_BLOCK_SIZE / BLOCK_SIZE;
+ }
+
+ for (i = 0; i < sbi->s_gdb_count; i++) {
+ sbi->s_gd[i].block = descriptor_loc(sb, sb_block, i);
+ if (!sbi->s_gd[i].block) {
+ DEBUG(DL_ERR, ("Ext2LoadGroup: can't locate group descriptor %d\n", i));
+ __leave;
+ }
+ }
+
+ if (!Ext2LoadGroupBH(Vcb)) {
+ DEBUG(DL_ERR, ("Ext2LoadGroup: Failed to load group descriptions !\n"));
+ __leave;
+ }
+
+ if (!ext4_check_descriptors(sb)) {
+ DbgBreak();
+ DEBUG(DL_ERR, ("Ext2LoadGroup: group descriptors corrupted !\n"));
+ __leave;
+ }
+
+ SetFlag(Vcb->Flags, VCB_GD_LOADED);
+ rc = TRUE;
+
+ } __finally {
+
+ if (!rc)
+ Ext2PutGroup(Vcb);
+
+ ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+ }
+
+ return rc;
+}
+
+VOID
+Ext2DropBH(IN PEXT2_VCB Vcb)
+{
+ struct ext4_sb_info *sbi = &Vcb->sbi;
+
+ /* do nothing if Vcb is not initialized yet */
+ if (!IsFlagOn(Vcb->Flags, VCB_INITIALIZED))
+ return;
+
+ __try {
+
+ /* acquire bd lock to avoid bh creation */
+ ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
+
+ SetFlag(Vcb->Flags, VCB_BEING_DROPPED);
+ Ext2DropGroupBH(Vcb);
+
+ while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
+ struct buffer_head *bh;
+ PLIST_ENTRY l;
+ l = RemoveHeadList(&Vcb->bd.bd_bh_free);
+ bh = CONTAINING_RECORD(l, struct buffer_head, b_link);
+ InitializeListHead(&bh->b_link);
+ if (0 == atomic_read(&bh->b_count)) {
+ buffer_head_remove(&Vcb->bd, bh);
+ free_buffer_head(bh);
+ }
+ }
+
+ } __finally {
+ ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
+ }
+
+ ClearFlag(Vcb->Flags, VCB_BEING_DROPPED);
+}
+
+
+VOID
+Ext2FlushRange(IN PEXT2_VCB Vcb, LARGE_INTEGER s, LARGE_INTEGER e)
+{
+ ULONG len;
+
+ if (e.QuadPart <= s.QuadPart)
+ return;
+
+ /* loop per 2G */
+ while (s.QuadPart < e.QuadPart) {
+ if (e.QuadPart > s.QuadPart + 1024 * 1024 * 1024) {
+ len = 1024 * 1024 * 1024;
+ } else {
+ len = (ULONG) (e.QuadPart - s.QuadPart);
+ }
+ CcFlushCache(&Vcb->SectionObject, &s, len, NULL);
+ s.QuadPart += len;
+ }
+}
+
+NTSTATUS
+Ext2FlushVcb(IN PEXT2_VCB Vcb)
+{
+ LARGE_INTEGER s = {0}, o;
+ struct ext4_sb_info *sbi = &Vcb->sbi;
+ struct rb_node *node;
+ struct buffer_head *bh;
+
+ if (!IsFlagOn(Vcb->Flags, VCB_GD_LOADED)) {
+ CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
+ goto errorout;
+ }
+
+ ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->MainResource));
+
+ __try {
+
+ /* acqurie gd block */
+ ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
+
+ /* acquire bd lock to avoid bh creation */
+ ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
+
+ /* drop unused bh */
+ Ext2DropBH(Vcb);
+
+ /* flush volume with all outstanding bh skipped */
+
+ node = rb_first(&Vcb->bd.bd_bh_root);
+ while (node) {
+
+ bh = container_of(node, struct buffer_head, b_rb_node);
+ node = rb_next(node);
+
+ o.QuadPart = bh->b_blocknr << BLOCK_BITS;
+ ASSERT(o.QuadPart >= s.QuadPart);
+
+ if (o.QuadPart == s.QuadPart) {
+ s.QuadPart = s.QuadPart + bh->b_size;
+ continue;
+ }
+
+ if (o.QuadPart > s.QuadPart) {
+ Ext2FlushRange(Vcb, s, o);
+ s.QuadPart = (bh->b_blocknr << BLOCK_BITS) + bh->b_size;
+ continue;
+ }
+ }
+
+ o = Vcb->PartitionInformation.PartitionLength;
+ Ext2FlushRange(Vcb, s, o);
+
+ } __finally {
+
+ ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
+ ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+ }
+
+errorout:
+ return STATUS_SUCCESS;
+}
+
+
+BOOLEAN
+Ext2SaveGroup(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN ULONG Group
+)
+{
+ struct ext4_group_desc *gd;
+ struct buffer_head *gb = NULL;
+ unsigned long i;
+
+ gd = ext4_get_group_desc(&Vcb->sb, Group, &gb);
+ if (!gd)
+ return 0;
+
+ ext4_group_desc_csum_set(&Vcb->sb, Group, gd);
+ mark_buffer_dirty(gb);
+ fini_bh(&gb);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+Ext2RefreshGroup(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb
+)
+{
+ return TRUE;
+}
+
+BOOLEAN
+Ext2GetInodeLba (
+ IN PEXT2_VCB Vcb,
+ IN ULONG inode,
+ OUT PLONGLONG offset
+)
+{
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *bh = NULL;
+ ext4_fsblk_t loc;
+ int group;
+
+ if (inode < 1 || inode > INODES_COUNT) {
+ DEBUG(DL_ERR, ( "Ext2GetInodeLba: Inode value %xh is invalid.\n",inode));
+ *offset = 0;
+ return FALSE;
+ }
+
+ group = (inode - 1) / INODES_PER_GROUP ;
+ gd = ext4_get_group_desc(&Vcb->sb, group, &bh);
+ if (!bh) {
+ *offset = 0;
+ DbgBreak();
+ return FALSE;
+ }
+ loc = (LONGLONG)ext4_inode_table(&Vcb->sb, gd);
+ loc = loc << BLOCK_BITS;
+ loc = loc + ((inode - 1) % INODES_PER_GROUP) * Vcb->InodeSize;
+
+ *offset = loc;
+ __brelse(bh);
+
+ return TRUE;
+}
+
+void Ext2DecodeInode(struct inode *dst, struct ext4_inode *src)
+{
+ dst->i_mode = src->i_mode;
+ dst->i_flags = src->i_flags;
+ dst->i_uid = src->i_uid;
+ dst->i_gid = src->i_gid;
+ dst->i_nlink = src->i_links_count;
+ dst->i_generation = src->i_generation;
+ dst->i_size = src->i_size_lo;
+ if (S_ISREG(src->i_mode)) {
+ dst->i_size |= (loff_t)src->i_size_high << 32;
+ }
+ dst->i_file_acl = src->i_file_acl_lo;
+ dst->i_file_acl |= (ext4_fsblk_t)src->osd2.linux2.l_i_file_acl_high << 32;
+ dst->i_atime = src->i_atime;
+ dst->i_ctime = src->i_ctime;
+ dst->i_mtime = src->i_mtime;
+ dst->i_dtime = src->i_dtime;
+ dst->i_blocks = ext3_inode_blocks(src, dst);
+ memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
+ if (EXT4_HAS_RO_COMPAT_FEATURE(dst->i_sb,
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
+ dst->i_extra_isize = src->i_extra_isize;
+ else
+ dst->i_extra_isize = 0;
+}
+
+void Ext2EncodeInode(struct ext4_inode *dst, struct inode *src)
+{
+ dst->i_mode = src->i_mode;
+ dst->i_flags = src->i_flags;
+ dst->i_uid = src->i_uid;
+ dst->i_gid = src->i_gid;
+ dst->i_links_count = src->i_nlink;
+ dst->i_generation = src->i_generation;
+ dst->i_size_lo = (__u32)src->i_size;
+ if (S_ISREG(src->i_mode)) {
+ dst->i_size_high = (__u32)(src->i_size >> 32);
+ }
+ dst->i_file_acl_lo = (__u32)src->i_file_acl;
+ dst->osd2.linux2.l_i_file_acl_high |= (__u16)(src->i_file_acl >> 32);
+ dst->i_atime = src->i_atime;
+ dst->i_ctime = src->i_ctime;
+ dst->i_mtime = src->i_mtime;
+ dst->i_dtime = src->i_dtime;
+ dst->i_extra_isize = src->i_extra_isize;
+ ASSERT(src->i_sb);
+ ext3_inode_blocks_set(dst, src);
+ memcpy(&dst->i_block[0], &src->i_block[0], sizeof(__u32) * 15);
+ if (EXT4_HAS_RO_COMPAT_FEATURE(src->i_sb,
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE))
+ dst->i_extra_isize = src->i_extra_isize;
+}
+
+
+BOOLEAN
+Ext2LoadInode (IN PEXT2_VCB Vcb,
+ IN struct inode *Inode)
+{
+ struct ext4_inode ext3i = {0};
+ struct ext4_inode_info ei = {0};
+ LONGLONG offset;
+
+ if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &offset)) {
+ DEBUG(DL_ERR, ("Ext2LoadInode: failed inode %u.\n", Inode->i_ino));
+ return FALSE;
+ }
+
+ if (!Ext2LoadBuffer(NULL, Vcb, offset, sizeof(ext3i), &ext3i)) {
+ return FALSE;
+ }
+
+ Ext2DecodeInode(Inode, &ext3i);
+
+ if (!ext4_inode_csum_verify(Inode, &ext3i, &ei)) {
+ //DbgPrint("inod %d checksum invalid\n", Inode->i_ino);
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+Ext2ClearInode (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN ULONG Inode)
+{
+ LONGLONG Offset = 0;
+ BOOLEAN rc;
+
+ rc = Ext2GetInodeLba(Vcb, Inode, &Offset);
+ if (!rc) {
+ DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode));
+ goto errorout;
+ }
+
+ rc = Ext2ZeroBuffer(IrpContext, Vcb, Offset, Vcb->InodeSize);
+
+errorout:
+
+ return rc;
+}
+
+BOOLEAN
+Ext2SaveInode ( IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN struct inode *Inode)
+{
+ struct ext4_inode ext4i = {0};
+ struct ext4_inode_info ei = {0};
+
+ LONGLONG Offset = 0;
+ ULONG InodeSize = sizeof(ext4i);
+ BOOLEAN rc = 0;
+
+ DEBUG(DL_INF, ( "Ext2SaveInode: Saving Inode %xh: Mode=%xh Size=%xh\n",
+ Inode->i_ino, Inode->i_mode, Inode->i_size));
+ rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset);
+ if (!rc) {
+ DEBUG(DL_ERR, ( "Ext2SaveInode: failed inode %u.\n", Inode->i_ino));
+ goto errorout;
+ }
+
+ rc = Ext2LoadBuffer(NULL, Vcb, Offset, InodeSize, &ext4i);
+ if (!rc) {
+ DEBUG(DL_ERR, ( "Ext2SaveInode: failed reading inode %u.\n", Inode->i_ino));
+ goto errorout;;
+ }
+
+ Ext2EncodeInode(&ext4i, Inode);
+
+ ext4_inode_csum_set(Inode, &ext4i, &ei);
+
+ if (InodeSize > Vcb->InodeSize)
+ {
+ DbgPrint("InodeSize > Vcb->InodeSize\n");
+ InodeSize = Vcb->InodeSize;
+ }
+ rc = Ext2SaveBuffer(IrpContext, Vcb, Offset, InodeSize, &ext4i);
+
+ if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
+ Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
+ }
+
+errorout:
+ return rc;
+}
+
+BOOLEAN
+Ext2LoadInodeXattr(IN PEXT2_VCB Vcb,
+ IN struct inode *Inode,
+ IN PEXT2_INODE InodeXattr)
+{
+ IO_STATUS_BLOCK IoStatus;
+ LONGLONG Offset;
+
+ if (!Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset)) {
+ DEBUG(DL_ERR, ("Ext2LoadRawInode: error get inode(%xh)'s addr.\n", Inode->i_ino));
+ return FALSE;
+ }
+
+ if (!CcCopyRead(
+ Vcb->Volume,
+ (PLARGE_INTEGER)&Offset,
+ Vcb->InodeSize,
+ PIN_WAIT,
+ (PVOID)InodeXattr,
+ &IoStatus)) {
+ return FALSE;
+ }
+
+ if (!NT_SUCCESS(IoStatus.Status)) {
+ return FALSE;
+ }
+
+ Ext2EncodeInode(InodeXattr, Inode);
+ return TRUE;
+}
+
+BOOLEAN
+Ext2SaveInodeXattr(IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN struct inode *Inode,
+ IN PEXT2_INODE InodeXattr)
+{
+ IO_STATUS_BLOCK IoStatus;
+ LONGLONG Offset = 0;
+ ULONG InodeSize = Vcb->InodeSize;
+ BOOLEAN rc = 0;
+
+ /* There is no way to put EA information in such a small inode */
+ if (InodeSize == EXT2_GOOD_OLD_INODE_SIZE)
+ return FALSE;
+
+ DEBUG(DL_INF, ("Ext2SaveInodeXattr: Saving Inode %xh: Mode=%xh Size=%xh\n",
+ Inode->i_ino, Inode->i_mode, Inode->i_size));
+ rc = Ext2GetInodeLba(Vcb, Inode->i_ino, &Offset);
+ if (!rc) {
+ DEBUG(DL_ERR, ("Ext2SaveInodeXattr: error get inode(%xh)'s addr.\n", Inode->i_ino));
+ goto errorout;
+ }
+
+ rc = Ext2SaveBuffer(IrpContext,
+ Vcb,
+ Offset + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize,
+ InodeSize - EXT2_GOOD_OLD_INODE_SIZE - Inode->i_extra_isize,
+ (char *)InodeXattr + EXT2_GOOD_OLD_INODE_SIZE + Inode->i_extra_isize);
+
+ if (rc && IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) {
+ Ext2StartFloppyFlushDpc(Vcb, NULL, NULL);
+ }
+
+errorout:
+ return rc;
+}
+
+
+BOOLEAN
+Ext2LoadBlock (IN PEXT2_VCB Vcb,
+ IN ULONG Index,
+ IN PVOID Buffer )
+{
+ struct buffer_head *bh = NULL;
+ BOOLEAN rc = 0;
+
+ __try {
+
+ bh = sb_getblk(&Vcb->sb, (sector_t)Index);
+
+ if (!bh) {
+ DEBUG(DL_ERR, ("Ext2Loadblock: can't load block %u\n", Index));
+ DbgBreak();
+ __leave;
+ }
+
+ if (!buffer_uptodate(bh)) {
+ int err = bh_submit_read(bh);
+ if (err < 0) {
+ DEBUG(DL_ERR, ("Ext2LoadBlock: reading failed %d\n", err));
+ __leave;
+ }
+ }
+
+ RtlCopyMemory(Buffer, bh->b_data, BLOCK_SIZE);
+ rc = TRUE;
+
+ } __finally {
+
+ if (bh)
+ fini_bh(&bh);
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Ext2SaveBlock ( IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN ULONG Index,
+ IN PVOID Buf )
+{
+ struct buffer_head *bh = NULL;
+ BOOLEAN rc = 0;
+
+ __try {
+
+ bh = sb_getblk_zero(&Vcb->sb, (sector_t)Index);
+
+ if (!bh) {
+ DEBUG(DL_ERR, ("Ext2Saveblock: can't load block %u\n", Index));
+ DbgBreak();
+ __leave;
+ }
+
+ if (!buffer_uptodate(bh)) {
+ }
+
+ RtlCopyMemory(bh->b_data, Buf, BLOCK_SIZE);
+ mark_buffer_dirty(bh);
+ rc = TRUE;
+
+ } __finally {
+
+ if (bh)
+ fini_bh(&bh);
+ }
+
+ return rc;
+}
+
+BOOLEAN
+Ext2LoadBuffer( IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN LONGLONG offset,
+ IN ULONG size,
+ IN PVOID buf )
+{
+ struct buffer_head *bh = NULL;
+ BOOLEAN rc;
+
+ __try {
+
+ while (size) {
+
+ sector_t block;
+ ULONG len = 0, delta = 0;
+
+ block = (sector_t) (offset >> BLOCK_BITS);
+ delta = (ULONG)offset & (BLOCK_SIZE - 1);
+ len = BLOCK_SIZE - delta;
+ if (size < len)
+ len = size;
+
+ bh = sb_getblk(&Vcb->sb, block);
+ if (!bh) {
+ DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
+ DbgBreak();
+ __leave;
+ }
+
+ if (!buffer_uptodate(bh)) {
+ int err = bh_submit_read(bh);
+ if (err < 0) {
+ DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
+ __leave;
+ }
+ }
+
+ __try {
+ RtlCopyMemory(buf, bh->b_data + delta, len);
+ } __finally {
+ fini_bh(&bh);
+ }
+
+ buf = (PUCHAR)buf + len;
+ offset = offset + len;
+ size = size - len;
+ }
+
+ rc = TRUE;
+
+ } __finally {
+
+ if (bh)
+ fini_bh(&bh);
+
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Ext2ZeroBuffer( IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN LONGLONG offset,
+ IN ULONG size
+ )
+{
+ struct buffer_head *bh = NULL;
+ BOOLEAN rc = 0;
+
+ __try {
+
+ while (size) {
+
+ sector_t block;
+ ULONG len = 0, delta = 0;
+
+ block = (sector_t) (offset >> BLOCK_BITS);
+ delta = (ULONG)offset & (BLOCK_SIZE - 1);
+ len = BLOCK_SIZE - delta;
+ if (size < len)
+ len = size;
+
+ if (delta == 0 && len >= BLOCK_SIZE) {
+ bh = sb_getblk_zero(&Vcb->sb, block);
+ } else {
+ bh = sb_getblk(&Vcb->sb, block);
+ }
+
+ if (!bh) {
+ DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
+ DbgBreak();
+ __leave;
+ }
+
+ if (!buffer_uptodate(bh)) {
+ int err = bh_submit_read(bh);
+ if (err < 0) {
+ DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
+ __leave;
+ }
+ }
+
+ __try {
+ if (delta == 0 && len >= BLOCK_SIZE) {
+ /* bh (cache) was already cleaned as zero */
+ } else {
+ RtlZeroMemory(bh->b_data + delta, len);
+ }
+ mark_buffer_dirty(bh);
+ } __finally {
+ fini_bh(&bh);
+ }
+
+ offset = offset + len;
+ size = size - len;
+ }
+
+ rc = TRUE;
+
+ } __finally {
+
+ if (bh)
+ fini_bh(&bh);
+
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Ext2SaveBuffer( IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN LONGLONG offset,
+ IN ULONG size,
+ IN PVOID buf )
+{
+ struct buffer_head *bh = NULL;
+ BOOLEAN rc = 0;
+
+ __try {
+
+ while (size) {
+
+ sector_t block;
+ ULONG len = 0, delta = 0;
+
+ block = (sector_t) (offset >> BLOCK_BITS);
+ delta = (ULONG)offset & (BLOCK_SIZE - 1);
+ len = BLOCK_SIZE - delta;
+ if (size < len)
+ len = size;
+
+ if (delta == 0 && len >= BLOCK_SIZE) {
+ bh = sb_getblk_zero(&Vcb->sb, block);
+ } else {
+ bh = sb_getblk(&Vcb->sb, block);
+ }
+
+ if (!bh) {
+ DEBUG(DL_ERR, ("Ext2SaveBuffer: can't load block %I64u\n", block));
+ DbgBreak();
+ __leave;
+ }
+
+ if (!buffer_uptodate(bh)) {
+ int err = bh_submit_read(bh);
+ if (err < 0) {
+ DEBUG(DL_ERR, ("Ext2SaveBuffer: bh_submit_read failed: %d\n", err));
+ __leave;
+ }
+ }
+
+ __try {
+ RtlCopyMemory(bh->b_data + delta, buf, len);
+ mark_buffer_dirty(bh);
+ } __finally {
+ fini_bh(&bh);
+ }
+
+ buf = (PUCHAR)buf + len;
+ offset = offset + len;
+ size = size - len;
+ }
+
+ rc = TRUE;
+
+ } __finally {
+
+ if (bh)
+ fini_bh(&bh);
+
+ }
+
+ return rc;
+}
+
+
+VOID
+Ext2UpdateVcbStat(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb
+)
+{
+ Vcb->SuperBlock->s_free_inodes_count = ext4_count_free_inodes(&Vcb->sb);
+ ext3_free_blocks_count_set(SUPER_BLOCK, ext4_count_free_blocks(&Vcb->sb));
+ Ext2SaveSuper(IrpContext, Vcb);
+}
+
+NTSTATUS
+Ext2NewBlock(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN ULONG GroupHint,
+ IN ULONG BlockHint,
+ OUT PULONG Block,
+ IN OUT PULONG Number
+)
+{
+ struct super_block *sb = &Vcb->sb;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
+ struct buffer_head *bh = NULL;
+ ext4_fsblk_t bitmap_blk;
+
+ RTL_BITMAP BlockBitmap;
+
+ ULONG Group = 0;
+ ULONG Index = 0xFFFFFFFF;
+ ULONG dwHint = 0;
+ ULONG Count = 0;
+ ULONG Length = 0;
+
+ NTSTATUS Status = STATUS_DISK_FULL;
+
+ *Block = 0;
+
+ ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
+
+ /* validate the hint group and hint block */
+ if (GroupHint >= Vcb->sbi.s_groups_count) {
+ DbgBreak();
+ GroupHint = Vcb->sbi.s_groups_count - 1;
+ }
+
+ if (BlockHint != 0) {
+ GroupHint = (BlockHint - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
+ dwHint = (BlockHint - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
+ }
+
+ Group = GroupHint;
+
+Again:
+
+ if (bh)
+ fini_bh(&bh);
+
+ if (gb)
+ fini_bh(&gb);
+
+ gd = ext4_get_group_desc(sb, Group, &gb);
+ if (!gd) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ bitmap_blk = ext4_block_bitmap(sb, gd);
+
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+ bh = sb_getblk_zero(sb, bitmap_blk);
+ if (!bh) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+ ext4_group_desc_csum_set(sb, Group, gd);
+ ext4_init_block_bitmap(sb, bh, Group, gd);
+ set_buffer_uptodate(bh);
+ gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
+ Ext2SaveGroup(IrpContext, Vcb, Group);
+ } else {
+ bh = sb_getblk(sb, bitmap_blk);
+ if (!bh) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+ }
+
+ if (!buffer_uptodate(bh)) {
+ int err = bh_submit_read(bh);
+ if (err < 0) {
+ DbgPrint("bh_submit_read error! err: %d\n", err);
+ Status = Ext2WinntError(err);
+ goto errorout;
+ }
+ }
+
+ if (ext4_free_blks_count(sb, gd)) {
+
+ if (Group == Vcb->sbi.s_groups_count - 1) {
+
+ Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
+
+ /* s_blocks_count is integer multiple of s_blocks_per_group */
+ if (Length == 0) {
+ Length = BLOCKS_PER_GROUP;
+ }
+ } else {
+ Length = BLOCKS_PER_GROUP;
+ }
+
+ /* initialize bitmap buffer */
+ RtlInitializeBitMap(&BlockBitmap, (PULONG)bh->b_data, Length);
+
+ /* try to find a clear bit range */
+ Index = RtlFindClearBits(&BlockBitmap, *Number, dwHint);
+
+ /* We could not get new block in the prefered group */
+ if (Index == 0xFFFFFFFF) {
+
+ /* search clear bits from the hint block */
+ Count = RtlFindNextForwardRunClear(&BlockBitmap, dwHint, &Index);
+ if (dwHint != 0 && Count == 0) {
+ /* search clear bits from the very beginning */
+ Count = RtlFindNextForwardRunClear(&BlockBitmap, 0, &Index);
+ }
+
+ if (Count == 0) {
+
+ RtlZeroMemory(&BlockBitmap, sizeof(RTL_BITMAP));
+
+ /* no blocks found: set bg_free_blocks_count to 0 */
+ ext4_free_blks_set(sb, gd, 0);
+ Ext2SaveGroup(IrpContext, Vcb, Group);
+
+ /* will try next group */
+ goto Again;
+
+ } else {
+
+ /* we got free blocks */
+ if (Count <= *Number) {
+ *Number = Count;
+ }
+ }
+ }
+
+ } else {
+
+ /* try next group */
+ dwHint = 0;
+ Group = (Group + 1) % Vcb->sbi.s_groups_count;
+ if (Group != GroupHint) {
+ goto Again;
+ }
+
+ Index = 0xFFFFFFFF;
+ }
+
+ if (Index < Length) {
+
+ /* mark block bits as allocated */
+ RtlSetBits(&BlockBitmap, Index, *Number);
+
+ /* set block bitmap dirty in cache */
+ mark_buffer_dirty(bh);
+
+ /* update group description */
+ ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
+ ext4_block_bitmap_csum_set(sb, Group, gd, bh);
+ Ext2SaveGroup(IrpContext, Vcb, Group);
+
+ /* update Vcb free blocks */
+ Ext2UpdateVcbStat(IrpContext, Vcb);
+
+ /* validate the new allocated block number */
+ *Block = Index + EXT2_FIRST_DATA_BLOCK + Group * BLOCKS_PER_GROUP;
+ if (*Block >= TOTAL_BLOCKS || *Block + *Number > TOTAL_BLOCKS) {
+ DbgBreak();
+ dwHint = 0;
+ goto Again;
+ }
+
+ if (ext4_block_bitmap(sb, gd) == *Block ||
+ ext4_inode_bitmap(sb, gd) == *Block ||
+ ext4_inode_table(sb, gd) == *Block ) {
+ DbgBreak();
+ dwHint = 0;
+ goto Again;
+ }
+
+ /* Always remove dirty MCB to prevent Volume's lazy writing.
+ Metadata blocks will be re-added during modifications.*/
+ if (Ext2RemoveBlockExtent(Vcb, NULL, *Block, *Number)) {
+ } else {
+ DbgBreak();
+ Ext2RemoveBlockExtent(Vcb, NULL, *Block, *Number);
+ }
+
+ DEBUG(DL_INF, ("Ext2NewBlock: Block %xh - %x allocated.\n",
+ *Block, *Block + *Number));
+ Status = STATUS_SUCCESS;
+ }
+
+errorout:
+
+ ExReleaseResourceLite(&Vcb->MetaBlock);
+
+ if (bh)
+ fini_bh(&bh);
+
+ if (gb)
+ fini_bh(&gb);
+
+ return Status;
+}
+
+NTSTATUS
+Ext2FreeBlock(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN ULONG Block,
+ IN ULONG Number
+)
+{
+ struct super_block *sb = &Vcb->sb;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
+ struct buffer_head bh;
+ ext4_fsblk_t bitmap_blk;
+
+ RTL_BITMAP BlockBitmap;
+ LARGE_INTEGER Offset;
+
+ PBCB BitmapBcb;
+ PVOID BitmapCache;
+
+ ULONG Group;
+ ULONG Index;
+ ULONG Length;
+ ULONG Count;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ ExAcquireResourceExclusiveLite(&Vcb->MetaBlock, TRUE);
+
+ DEBUG(DL_INF, ("Ext2FreeBlock: Block %xh - %x to be freed.\n",
+ Block, Block + Number));
+
+ Group = (Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
+ Index = (Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
+
+Again:
+
+ if (gb)
+ fini_bh(&gb);
+
+ if ( Block < EXT2_FIRST_DATA_BLOCK ||
+ Block >= TOTAL_BLOCKS ||
+ Group >= Vcb->sbi.s_groups_count) {
+
+ DbgBreak();
+ Status = STATUS_SUCCESS;
+
+ } else {
+
+ gd = ext4_get_group_desc(sb, Group, &gb);
+ if (!gd) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+ bitmap_blk = ext4_block_bitmap(sb, gd);
+
+ /* check the block is valid or not */
+ if (bitmap_blk >= TOTAL_BLOCKS) {
+ DbgBreak();
+ Status = STATUS_DISK_CORRUPT_ERROR;
+ goto errorout;
+ }
+
+ /* get bitmap block offset and length */
+ Offset.QuadPart = bitmap_blk;
+ Offset.QuadPart = Offset.QuadPart << BLOCK_BITS;
+
+ if (Group == Vcb->sbi.s_groups_count - 1) {
+
+ Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
+
+ /* s_blocks_count is integer multiple of s_blocks_per_group */
+ if (Length == 0) {
+ Length = BLOCKS_PER_GROUP;
+ }
+
+ } else {
+ Length = BLOCKS_PER_GROUP;
+ }
+
+ /* read and initialize bitmap */
+ if (!CcPinRead( Vcb->Volume,
+ &Offset,
+ Vcb->BlockSize,
+ PIN_WAIT,
+ &BitmapBcb,
+ &BitmapCache ) ) {
+
+ DEBUG(DL_ERR, ("Ext2FreeBlock: failed to PinLock bitmap block %xh.\n",
+ bitmap_blk));
+ Status = STATUS_CANT_WAIT;
+ DbgBreak();
+ goto errorout;
+ }
+
+ /* clear usused bits */
+ RtlInitializeBitMap(&BlockBitmap, BitmapCache, Length);
+ Count = min(Length - Index, Number);
+ RtlClearBits(&BlockBitmap, Index, Count);
+
+ /* update group description table */
+ ext4_free_blks_set(sb, gd, RtlNumberOfClearBits(&BlockBitmap));
+
+ bh.b_data = BitmapCache;
+ ext4_block_bitmap_csum_set(sb, Group, gd, &bh);
+
+ /* indict the cache range is dirty */
+ CcSetDirtyPinnedData(BitmapBcb, NULL );
+ Ext2AddVcbExtent(Vcb, Offset.QuadPart, (LONGLONG)Vcb->BlockSize);
+ CcUnpinData(BitmapBcb);
+ BitmapBcb = NULL;
+ BitmapCache = NULL;
+ Ext2SaveGroup(IrpContext, Vcb, Group);
+
+ /* remove dirty MCB to prevent Volume's lazy writing. */
+ if (Ext2RemoveBlockExtent(Vcb, NULL, Block, Count)) {
+ } else {
+ DbgBreak();
+ Ext2RemoveBlockExtent(Vcb, NULL, Block, Count);
+ }
+
+ /* save super block (used/unused blocks statics) */
+ Ext2UpdateVcbStat(IrpContext, Vcb);
+
+ /* try next group to clear all remaining */
+ Number -= Count;
+ if (Number) {
+ Group += 1;
+ if (Group < Vcb->sbi.s_groups_count) {
+ Index = 0;
+ Block += Count;
+ goto Again;
+ } else {
+ DEBUG(DL_ERR, ("Ext2FreeBlock: block number beyonds max group.\n"));
+ goto errorout;
+ }
+ }
+ }
+
+ Status = STATUS_SUCCESS;
+
+errorout:
+
+ if (gb)
+ fini_bh(&gb);
+
+ ExReleaseResourceLite(&Vcb->MetaBlock);
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2NewInode(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN ULONG GroupHint,
+ IN ULONG Type,
+ OUT PULONG Inode
+)
+{
+ struct super_block *sb = &Vcb->sb;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
+ struct buffer_head *bh = NULL;
+ ext4_fsblk_t bitmap_blk;
+
+ RTL_BITMAP InodeBitmap;
+
+ ULONG Group, i, j;
+ ULONG Average, Length;
+
+ ULONG dwInode;
+
+ NTSTATUS Status = STATUS_DISK_FULL;
+
+ *Inode = dwInode = 0XFFFFFFFF;
+
+ ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
+
+ if (GroupHint >= Vcb->sbi.s_groups_count)
+ GroupHint = GroupHint % Vcb->sbi.s_groups_count;
+
+repeat:
+
+ if (bh)
+ fini_bh(&bh);
+
+ if (gb)
+ fini_bh(&gb);
+
+ Group = i = 0;
+ gd = NULL;
+
+ if (Type == EXT2_FT_DIR) {
+
+ Average = Vcb->SuperBlock->s_free_inodes_count / Vcb->sbi.s_groups_count;
+
+ for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
+
+ i = (j + GroupHint) % (Vcb->sbi.s_groups_count);
+ gd = ext4_get_group_desc(sb, i, &gb);
+ if (!gd) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ if ((gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) ||
+ (ext4_used_dirs_count(sb, gd) << 8 <
+ ext4_free_inodes_count(sb, gd)) ) {
+ Group = i + 1;
+ break;
+ }
+ fini_bh(&gb);
+ }
+
+ if (!Group) {
+
+ PEXT2_GROUP_DESC desc = NULL;
+
+ gd = NULL;
+
+ /* get the group with the biggest vacancy */
+ for (j = 0; j < Vcb->sbi.s_groups_count; j++) {
+
+ struct buffer_head *gt = NULL;
+ desc = ext4_get_group_desc(sb, j, >);
+ if (!desc) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ /* return the group if it's not initialized yet */
+ if (desc->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
+ Group = j + 1;
+ gd = desc;
+
+ if (gb)
+ fini_bh(&gb);
+ gb = gt;
+ gt = NULL;
+ break;
+ }
+
+ if (!gd) {
+ if (ext4_free_inodes_count(sb, desc) > 0) {
+ Group = j + 1;
+ gd = desc;
+ if (gb)
+ fini_bh(&gb);
+ gb = gt;
+ gt = NULL;
+ }
+ } else {
+ if (ext4_free_inodes_count(sb, desc) >
+ ext4_free_inodes_count(sb, gd)) {
+ Group = j + 1;
+ gd = desc;
+ if (gb)
+ fini_bh(&gb);
+ gb = gt;
+ gt = NULL;
+ break;
+ }
+ }
+ if (gt)
+ fini_bh(>);
+ }
+ }
+
+ } else {
+
+ /*
+ * Try to place the inode in its parent directory (GroupHint)
+ */
+
+ gd = ext4_get_group_desc(sb, GroupHint, &gb);
+ if (!gb) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
+ ext4_free_inodes_count(sb, gd)) {
+
+ Group = GroupHint + 1;
+
+ } else {
+
+ /* this group is 100% cocucpied */
+ fini_bh(&gb);
+
+ i = GroupHint;
+
+ /*
+ * Use a quadratic hash to find a group with a free inode
+ */
+
+ for (j = 1; j < Vcb->sbi.s_groups_count; j <<= 1) {
+
+
+ i = (i + j) % Vcb->sbi.s_groups_count;
+ gd = ext4_get_group_desc(sb, i, &gb);
+ if (!gd) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
+ ext4_free_inodes_count(sb, gd)) {
+ Group = i + 1;
+ break;
+ }
+
+ fini_bh(&gb);
+ }
+ }
+
+ if (!Group) {
+ /*
+ * That failed: try linear search for a free inode
+ */
+ i = GroupHint;
+ for (j = 2; j < Vcb->sbi.s_groups_count; j++) {
+
+ i = (i + 1) % Vcb->sbi.s_groups_count;
+ gd = ext4_get_group_desc(sb, i, &gb);
+ if (!gd) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT) ||
+ ext4_free_inodes_count(sb, gd)) {
+ Group = i + 1;
+ break;
+ }
+
+ fini_bh(&gb);
+ }
+ }
+ }
+
+ if (gd == NULL || Group == 0) {
+ goto errorout;
+ }
+
+ /* finally we got the group, but is it valid ? */
+ if (Group > Vcb->sbi.s_groups_count) {
+ DbgBreak();
+ goto errorout;
+ }
+
+ /* valid group number starts from 1, not 0 */
+ Group -= 1;
+
+ ASSERT(gd);
+ bitmap_blk = ext4_inode_bitmap(sb, gd);
+ /* check the block is valid or not */
+ if (bitmap_blk == 0 || bitmap_blk >= TOTAL_BLOCKS) {
+ DbgBreak();
+ Status = STATUS_DISK_CORRUPT_ERROR;
+ goto errorout;
+ }
+
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
+ bh = sb_getblk_zero(sb, bitmap_blk);
+ if (!bh) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+ ext4_init_inode_bitmap(sb, bh, Group, gd);
+ set_buffer_uptodate(bh);
+ gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
+ ext4_inode_bitmap_csum_set(sb, Group, gd, bh, EXT4_INODES_PER_GROUP(sb) / 8);
+ ext4_group_desc_csum_set(sb, Group, gd);
+ Ext2SaveGroup(IrpContext, Vcb, Group);
+ } else {
+ bh = sb_getblk(sb, bitmap_blk);
+ if (!bh) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+ }
+
+ if (!buffer_uptodate(bh)) {
+ int err = bh_submit_read(bh);
+ if (err < 0) {
+ DbgPrint("bh_submit_read error! err: %d\n", err);
+ Status = Ext2WinntError(err);
+ goto errorout;
+ }
+ }
+
+ if (Vcb->sbi.s_groups_count == 1) {
+ Length = INODES_COUNT;
+ } else {
+ if (Group + 1 == Vcb->sbi.s_groups_count) {
+ Length = INODES_COUNT % INODES_PER_GROUP;
+ if (!Length) {
+ /* INODES_COUNT is integer multiple of INODES_PER_GROUP */
+ Length = INODES_PER_GROUP;
+ }
+ } else {
+ Length = INODES_PER_GROUP;
+ }
+ }
+
+ RtlInitializeBitMap(&InodeBitmap, (PULONG)bh->b_data, Length);
+ dwInode = RtlFindClearBits(&InodeBitmap, 1, 0);
+
+ if (dwInode == 0xFFFFFFFF || dwInode >= Length) {
+
+ RtlZeroMemory(&InodeBitmap, sizeof(RTL_BITMAP));
+ if (ext4_free_inodes_count(sb, gd) > 0) {
+ ext4_free_inodes_set(sb, gd, 0);
+ Ext2SaveGroup(IrpContext, Vcb, Group);
+ }
+ goto repeat;
+
+ } else {
+
+ __u32 count = 0;
+
+ /* update unused inodes count */
+ count = ext4_free_inodes_count(sb, gd) - 1;
+ ext4_free_inodes_set(sb, gd, count);
+
+ RtlSetBits(&InodeBitmap, dwInode, 1);
+
+ /* set block bitmap dirty in cache */
+ mark_buffer_dirty(bh);
+
+ /* If we didn't allocate from within the initialized part of the inode
+ * table then we need to initialize up to this inode. */
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_GDT_CSUM)) {
+
+ __u32 free;
+
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_INODE_UNINIT)) {
+ gd->bg_flags &= cpu_to_le16(~EXT4_BG_INODE_UNINIT);
+ /* When marking the block group with
+ * ~EXT4_BG_INODE_UNINIT we don't want to depend
+ * on the value of bg_itable_unused even though
+ * mke2fs could have initialized the same for us.
+ * Instead we calculated the value below
+ */
+
+ free = 0;
+ } else {
+ free = EXT3_INODES_PER_GROUP(sb) - ext4_itable_unused_count(sb, gd);
+ }
+
+ /*
+ * Check the relative inode number against the last used
+ * relative inode number in this group. if it is greater
+ * we need to update the bg_itable_unused count
+ *
+ */
+ if (dwInode + 1 > free) {
+ ext4_itable_unused_set(sb, gd,
+ (EXT3_INODES_PER_GROUP(sb) - 1 - dwInode));
+ }
+
+ /* We may have to initialize the block bitmap if it isn't already */
+ if (gd->bg_flags & cpu_to_le16(EXT4_BG_BLOCK_UNINIT)) {
+
+ struct buffer_head *block_bitmap_bh = NULL;
+
+ /* recheck and clear flag under lock if we still need to */
+ block_bitmap_bh = sb_getblk_zero(sb, ext4_block_bitmap(sb, gd));
+ if (block_bitmap_bh) {
+ ext4_block_bitmap_csum_set(sb, Group, gd,
+ block_bitmap_bh);
+ ext4_group_desc_csum_set(sb, Group, gd);
+ free = ext4_init_block_bitmap(sb, block_bitmap_bh, Group, gd);
+ set_buffer_uptodate(block_bitmap_bh);
+ brelse(block_bitmap_bh);
+ gd->bg_flags &= cpu_to_le16(~EXT4_BG_BLOCK_UNINIT);
+ ext4_free_blks_set(sb, gd, free);
+ Ext2SaveGroup(IrpContext, Vcb, Group);
+ }
+ }
+ }
+
+ *Inode = dwInode + 1 + Group * INODES_PER_GROUP;
+
+ /* update group_desc / super_block */
+ if (Type == EXT2_FT_DIR) {
+ ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) + 1);
+ }
+ ext4_inode_bitmap_csum_set(sb, Group, gd, bh, EXT4_INODES_PER_GROUP(sb) / 8);
+ ext4_group_desc_csum_set(sb, Group, gd);
+ Ext2SaveGroup(IrpContext, Vcb, Group);
+ Ext2UpdateVcbStat(IrpContext, Vcb);
+ Status = STATUS_SUCCESS;
+ }
+
+errorout:
+
+ ExReleaseResourceLite(&Vcb->MetaInode);
+
+ if (bh)
+ fini_bh(&bh);
+
+ if (gb)
+ fini_bh(&gb);
+
+
+ return Status;
+}
+
+NTSTATUS
+Ext2UpdateGroupDirStat(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN ULONG group
+ )
+{
+ struct super_block *sb = &Vcb->sb;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
+ NTSTATUS status;
+
+ ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
+
+ /* get group desc */
+ gd = ext4_get_group_desc(sb, group, &gb);
+ if (!gd) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ /* update group_desc and super_block */
+ ext4_used_dirs_set(sb, gd, ext4_used_dirs_count(sb, gd) - 1);
+ Ext2SaveGroup(IrpContext, Vcb, group);
+ Ext2UpdateVcbStat(IrpContext, Vcb);
+ status = STATUS_SUCCESS;
+
+errorout:
+
+ ExReleaseResourceLite(&Vcb->MetaInode);
+
+ if (gb)
+ fini_bh(&gb);
+
+ return status;
+}
+
+
+NTSTATUS
+Ext2FreeInode(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN ULONG Inode,
+ IN ULONG Type
+)
+{
+ struct super_block *sb = &Vcb->sb;
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
+ struct buffer_head *bh = NULL;
+ ext4_fsblk_t bitmap_blk;
+
+ RTL_BITMAP InodeBitmap;
+ ULONG Group;
+ ULONG Length;
+ LARGE_INTEGER Offset;
+
+ ULONG dwIno;
+ BOOLEAN bModified = FALSE;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ ExAcquireResourceExclusiveLite(&Vcb->MetaInode, TRUE);
+
+ Group = (Inode - 1) / INODES_PER_GROUP;
+ dwIno = (Inode - 1) % INODES_PER_GROUP;
+
+ DEBUG(DL_INF, ( "Ext2FreeInode: Inode: %xh (Group/Off = %xh/%xh)\n",
+ Inode, Group, dwIno));
+
+ if (Group >= Vcb->sbi.s_groups_count) {
+ DbgBreak();
+ goto errorout;
+ }
+
+ gd = ext4_get_group_desc(sb, Group, &gb);
+ if (!gd) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+
+ bitmap_blk = ext4_inode_bitmap(sb, gd);
+ bh = sb_getblk(sb, bitmap_blk);
+ if (!bh) {
+ DbgBreak();
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+ if (!buffer_uptodate(bh)) {
+ int err = bh_submit_read(bh);
+ if (err < 0) {
+ DbgPrint("bh_submit_read error! err: %d\n", err);
+ Status = Ext2WinntError(err);
+ goto errorout;
+ }
+ }
+
+ if (Group == Vcb->sbi.s_groups_count - 1) {
+
+ Length = INODES_COUNT % INODES_PER_GROUP;
+ if (!Length) {
+ /* s_inodes_count is integer multiple of s_inodes_per_group */
+ Length = INODES_PER_GROUP;
+ }
+ } else {
+ Length = INODES_PER_GROUP;
+ }
+
+ RtlInitializeBitMap(&InodeBitmap, (PULONG)bh->b_data, Length);
+
+ if (RtlCheckBit(&InodeBitmap, dwIno) == 0) {
+ DbgBreak();
+ Status = STATUS_SUCCESS;
+ } else {
+ RtlClearBits(&InodeBitmap, dwIno, 1);
+ bModified = TRUE;
+ }
+
+ if (bModified) {
+ /* update group free inodes */
+ ext4_free_inodes_set(sb, gd,
+ RtlNumberOfClearBits(&InodeBitmap));
+
+ /* set inode block dirty and add to vcb dirty range */
+ mark_buffer_dirty(bh);
+
+ /* update group_desc and super_block */
+ if (Type == EXT2_FT_DIR) {
+ ext4_used_dirs_set(sb, gd,
+ ext4_used_dirs_count(sb, gd) - 1);
+ }
+ ext4_inode_bitmap_csum_set(sb, Group, gd, bh, EXT4_INODES_PER_GROUP(sb) / 8);
+ ext4_group_desc_csum_set(sb, Group, gd);
+ Ext2SaveGroup(IrpContext, Vcb, Group);
+ Ext2UpdateVcbStat(IrpContext, Vcb);
+ Status = STATUS_SUCCESS;
+ }
+
+errorout:
+
+ ExReleaseResourceLite(&Vcb->MetaInode);
+
+ if (bh)
+ fini_bh(&bh);
+
+ if (gb)
+ fini_bh(&gb);
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2AddEntry (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_FCB Dcb,
+ IN struct inode *Inode,
+ IN PUNICODE_STRING FileName,
+ struct dentry **Dentry
+)
+{
+ struct dentry *de = NULL;
+
+ NTSTATUS status = STATUS_UNSUCCESSFUL;
+ OEM_STRING oem;
+ int rc;
+
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ if (!IsDirectory(Dcb)) {
+ DbgBreak();
+ return STATUS_NOT_A_DIRECTORY;
+ }
+
+ ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
+ MainResourceAcquired = TRUE;
+
+ __try {
+
+ Ext2ReferXcb(&Dcb->ReferenceCount);
+ de = Ext2BuildEntry(Vcb, Dcb->Mcb, FileName);
+ if (!de) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ __leave;
+ }
+ de->d_inode = Inode;
+
+ rc = ext3_add_entry(IrpContext, de, Inode);
+ status = Ext2WinntError(rc);
+ if (NT_SUCCESS(status)) {
+
+ /* increase dir inode's nlink for .. */
+ if (S_ISDIR(Inode->i_mode)) {
+ ext3_inc_count(Dcb->Inode);
+ ext3_mark_inode_dirty(IrpContext, Dcb->Inode);
+ }
+
+ /* increase inode nlink reference */
+ ext3_inc_count(Inode);
+ ext3_mark_inode_dirty(IrpContext, Inode);
+
+ if (Dentry) {
+ *Dentry = de;
+ de = NULL;
+ }
+ }
+
+ } __finally {
+
+ Ext2DerefXcb(&Dcb->ReferenceCount);
+
+ if (MainResourceAcquired) {
+ ExReleaseResourceLite(&Dcb->MainResource);
+ }
+
+ if (de)
+ Ext2FreeEntry(de);
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+Ext2SetFileType (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_FCB Dcb,
+ IN PEXT2_MCB Mcb,
+ IN umode_t mode
+ )
+{
+ struct inode *dir = Dcb->Inode;
+ struct buffer_head *bh = NULL;
+ struct ext3_dir_entry_2 *de;
+ struct inode *inode;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ if (!EXT4_HAS_INCOMPAT_FEATURE(dir->i_sb, EXT3_FEATURE_INCOMPAT_FILETYPE)) {
+ return STATUS_SUCCESS;
+ }
+
+ if (!IsDirectory(Dcb)) {
+ return STATUS_NOT_A_DIRECTORY;
+ }
+
+ ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
+ MainResourceAcquired = TRUE;
+
+ __try {
+
+ Ext2ReferXcb(&Dcb->ReferenceCount);
+
+ bh = ext3_find_entry(IrpContext, Mcb->de, &de);
+ if (!bh)
+ __leave;
+
+ inode = &Mcb->Inode;
+ if (le32_to_cpu(de->inode) != inode->i_ino)
+ __leave;
+
+ ext3_set_de_type(inode->i_sb, de, mode);
+ mark_buffer_dirty(bh);
+
+ if (S_ISDIR(inode->i_mode) == S_ISDIR(mode)) {
+ } else if (S_ISDIR(inode->i_mode)) {
+ ext3_dec_count(dir);
+ } else if (S_ISDIR(mode)) {
+ ext3_inc_count(dir);
+ }
+ dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
+ ext3_mark_inode_dirty(IrpContext, dir);
+
+ inode->i_mode = mode;
+ ext3_mark_inode_dirty(IrpContext, inode);
+
+ Status = STATUS_SUCCESS;
+
+ } __finally {
+
+ Ext2DerefXcb(&Dcb->ReferenceCount);
+
+ if (MainResourceAcquired)
+ ExReleaseResourceLite(&Dcb->MainResource);
+
+ if (bh)
+ brelse(bh);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2RemoveEntry (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_FCB Dcb,
+ IN PEXT2_MCB Mcb
+)
+{
+ struct inode *dir = Dcb->Inode;
+ struct buffer_head *bh = NULL;
+ struct ext3_dir_entry_2 *de;
+ struct inode *inode;
+ int rc = -ENOENT;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ if (!IsDirectory(Dcb)) {
+ return STATUS_NOT_A_DIRECTORY;
+ }
+
+ ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
+ MainResourceAcquired = TRUE;
+
+ __try {
+
+ Ext2ReferXcb(&Dcb->ReferenceCount);
+
+ bh = ext3_find_entry(IrpContext, Mcb->de, &de);
+ if (!bh)
+ __leave;
+
+ inode = &Mcb->Inode;
+ if (le32_to_cpu(de->inode) != inode->i_ino)
+ __leave;
+
+ if (!inode->i_nlink) {
+ ext3_warning (inode->i_sb, "ext3_unlink",
+ "Deleting nonexistent file (%lu), %d",
+ inode->i_ino, inode->i_nlink);
+ inode->i_nlink = 1;
+ }
+ rc = ext3_delete_entry(IrpContext, dir, de, bh);
+ if (rc) {
+ Status = Ext2WinntError(rc);
+ __leave;
+ }
+ /*
+ if (!inode->i_nlink)
+ ext3_orphan_add(handle, inode);
+ */
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = ext3_current_time(dir);
+ ext3_dec_count(inode);
+ ext3_mark_inode_dirty(IrpContext, inode);
+
+ /* decrease dir inode's nlink for .. */
+ if (S_ISDIR(inode->i_mode)) {
+ ext3_update_dx_flag(dir);
+ ext3_dec_count(dir);
+ ext3_mark_inode_dirty(IrpContext, dir);
+ }
+
+ Status = STATUS_SUCCESS;
+
+ } __finally {
+
+ Ext2DerefXcb(&Dcb->ReferenceCount);
+
+ if (MainResourceAcquired)
+ ExReleaseResourceLite(&Dcb->MainResource);
+
+ if (bh)
+ brelse(bh);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2SetParentEntry (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_FCB Dcb,
+ IN ULONG OldParent,
+ IN ULONG NewParent )
+{
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ PEXT2_DIR_ENTRY2 pSelf = NULL;
+ PEXT2_DIR_ENTRY2 pParent = NULL;
+
+ ULONG dwBytes = 0;
+
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ ULONG Offset = 0;
+
+ if (!IsDirectory(Dcb)) {
+ return STATUS_NOT_A_DIRECTORY;
+ }
+
+ if (OldParent == NewParent) {
+ return STATUS_SUCCESS;
+ }
+
+ MainResourceAcquired =
+ ExAcquireResourceExclusiveLite(&Dcb->MainResource, TRUE);
+
+ __try {
+
+ Ext2ReferXcb(&Dcb->ReferenceCount);
+
+ pSelf = (PEXT2_DIR_ENTRY2)
+ Ext2AllocatePool(
+ PagedPool,
+ EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2),
+ EXT2_DENTRY_MAGIC
+ );
+ if (!pSelf) {
+ DEBUG(DL_ERR, ( "Ex2SetParentEntry: failed to allocate pSelf.\n"));
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ __leave;
+ }
+
+ dwBytes = 0;
+
+ //
+ // Reading the DCB contents
+ //
+
+ Status = Ext2ReadInode(
+ IrpContext,
+ Vcb,
+ Dcb->Mcb,
+ (ULONGLONG)Offset,
+ (PVOID)pSelf,
+ EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2),
+ FALSE,
+ &dwBytes );
+
+ if (!NT_SUCCESS(Status)) {
+ DEBUG(DL_ERR, ( "Ext2SetParentEntry: failed to read directory.\n"));
+ __leave;
+ }
+
+ ASSERT(dwBytes == EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2));
+
+ pParent = (PEXT2_DIR_ENTRY2)((PUCHAR)pSelf + pSelf->rec_len);
+
+ if (pSelf->name_len == 1 && pSelf->name[0] == '.' &&
+ pParent->name_len == 2 && pParent->name[0] == '.' &&
+ pParent->name[1] == '.') {
+
+ if (pParent->inode != OldParent) {
+ DbgBreak();
+ }
+ pParent->inode = NewParent;
+
+ Status = Ext2WriteInode(
+ IrpContext,
+ Vcb,
+ Dcb->Mcb,
+ (ULONGLONG)Offset,
+ pSelf,
+ dwBytes,
+ FALSE,
+ &dwBytes );
+ } else {
+ DbgBreak();
+ }
+
+ } __finally {
+
+
+ if (Ext2DerefXcb(&Dcb->ReferenceCount) == 0) {
+ DEBUG(DL_ERR, ( "Ext2SetParentEntry: Dcb reference goes to ZERO.\n"));
+ }
+
+ if (MainResourceAcquired) {
+ ExReleaseResourceLite(&Dcb->MainResource);
+ }
+
+ if (pSelf) {
+ Ext2FreePool(pSelf, EXT2_DENTRY_MAGIC);
+ }
+ }
+
+ return Status;
+}
+
+int ext3_check_dir_entry (const char * function, struct inode * dir,
+ struct ext3_dir_entry_2 * de,
+ struct buffer_head * bh,
+ unsigned long offset)
+{
+ const char * error_msg = NULL;
+ const int rlen = ext3_rec_len_from_disk(de->rec_len);
+
+ if (rlen < EXT3_DIR_REC_LEN(1))
+ error_msg = "rec_len is smaller than minimal";
+ else if (rlen % 4 != 0)
+ error_msg = "rec_len % 4 != 0";
+ else if (rlen < EXT3_DIR_REC_LEN(de->name_len))
+ error_msg = "rec_len is too small for name_len";
+ else if ((char *) de + rlen > bh->b_data + dir->i_sb->s_blocksize)
+ error_msg = "directory entry across blocks";
+ else if (le32_to_cpu(de->inode) >
+ le32_to_cpu(EXT4_SB(dir->i_sb)->s_es->s_inodes_count))
+ error_msg = "inode out of bounds";
+
+ if (error_msg != NULL) {
+ DEBUG(DL_ERR, ("%s: bad entry in directory %u: %s - "
+ "offset=%u, inode=%u, rec_len=%d, name_len=%d\n",
+ function, dir->i_ino, error_msg, offset,
+ (unsigned long) le32_to_cpu(de->inode),
+ rlen, de->name_len));
+ }
+ return error_msg == NULL ? 1 : 0;
+}
+
+
+/*
+ * p is at least 6 bytes before the end of page
+ */
+struct ext3_dir_entry_2 *
+ ext3_next_entry(struct ext3_dir_entry_2 *p)
+{
+ return (struct ext3_dir_entry_2 *)((char *)p +
+ ext3_rec_len_from_disk(p->rec_len));
+}
+
+#define MAX_LFS_FILESIZE 0x7fffffffffffffff
+
+/*
+ * Maximal extent format file size.
+ * Resulting logical blkno at s_maxbytes must fit in our on-disk
+ * extent format containers, within a sector_t, and within i_blocks
+ * in the vfs. ext4 inode has 48 bits of i_block in fsblock units,
+ * so that won't be a limiting factor.
+ *
+ * Note, this does *not* consider any metadata overhead for vfs i_blocks.
+ */
+static loff_t ext4_max_size(int blkbits, int has_huge_files)
+{
+ loff_t res;
+ loff_t upper_limit = MAX_LFS_FILESIZE;
+
+ /* small i_blocks in vfs inode? */
+ if (!has_huge_files || sizeof(blkcnt_t) < sizeof(u64)) {
+ /*
+ * CONFIG_LBD is not enabled implies the inode
+ * i_block represent total blocks in 512 bytes
+ * 32 == size of vfs inode i_blocks * 8
+ */
+ upper_limit = (1LL << 32) - 1;
+
+ /* total blocks in file system block size */
+ upper_limit >>= (blkbits - 9);
+ upper_limit <<= blkbits;
+ }
+
+ /* 32-bit extent-start container, ee_block */
+ res = 1LL << 32;
+ res <<= blkbits;
+ res -= 1;
+
+ /* Sanity check against vm- & vfs- imposed limits */
+ if (res > upper_limit)
+ res = upper_limit;
+
+ return res;
+}
+
+/*
+ * Maximal extent format file size.
+ * Resulting logical blkno at s_maxbytes must fit in our on-disk
+ * extent format containers, within a sector_t, and within i_blocks
+ * in the vfs. ext4 inode has 48 bits of i_block in fsblock units,
+ * so that won't be a limiting factor.
+ *
+ * Note, this does *not* consider any metadata overhead for vfs i_blocks.
+ */
+loff_t ext3_max_size(int blkbits, int has_huge_files)
+{
+ loff_t res;
+ loff_t upper_limit = MAX_LFS_FILESIZE;
+
+ /* small i_blocks in vfs inode? */
+ if (!has_huge_files) {
+ /*
+ * CONFIG_LBD is not enabled implies the inode
+ * i_block represent total blocks in 512 bytes
+ * 32 == size of vfs inode i_blocks * 8
+ */
+ upper_limit = ((loff_t)1 << 32) - 1;
+
+ /* total blocks in file system block size */
+ upper_limit >>= (blkbits - 9);
+ upper_limit <<= blkbits;
+ }
+
+ /* 32-bit extent-start container, ee_block */
+ res = (loff_t)1 << 32;
+ res <<= blkbits;
+ res -= 1;
+
+ /* Sanity check against vm- & vfs- imposed limits */
+ if (res > upper_limit)
+ res = upper_limit;
+
+ return res;
+}
+
+/*
+ * Maximal bitmap file size. There is a direct, and {,double-,triple-}indirect
+ * block limit, and also a limit of (2^48 - 1) 512-byte sectors in i_blocks.
+ * We need to be 1 filesystem block less than the 2^48 sector limit.
+ */
+loff_t ext3_max_bitmap_size(int bits, int has_huge_files)
+{
+ loff_t res = EXT3_NDIR_BLOCKS;
+ int meta_blocks;
+ loff_t upper_limit;
+ /* This is calculated to be the largest file size for a
+ * dense, bitmapped file such that the total number of
+ * sectors in the file, including data and all indirect blocks,
+ * does not exceed 2^48 -1
+ * __u32 i_blocks_lo and _u16 i_blocks_high representing the
+ * total number of 512 bytes blocks of the file
+ */
+
+ if (!has_huge_files) {
+ /*
+ * !has_huge_files or CONFIG_LBD is not enabled
+ * implies the inode i_block represent total blocks in
+ * 512 bytes 32 == size of vfs inode i_blocks * 8
+ */
+ upper_limit = ((loff_t)1 << 32) - 1;
+
+ /* total blocks in file system block size */
+ upper_limit >>= (bits - 9);
+
+ } else {
+ /*
+ * We use 48 bit ext4_inode i_blocks
+ * With EXT4_HUGE_FILE_FL set the i_blocks
+ * represent total number of blocks in
+ * file system block size
+ */
+ upper_limit = ((loff_t)1 << 48) - 1;
+
+ }
+
+ /* indirect blocks */
+ meta_blocks = 1;
+ /* double indirect blocks */
+ meta_blocks += 1 + ((loff_t)1 << (bits-2));
+ /* tripple indirect blocks */
+ meta_blocks += 1 + ((loff_t)1 << (bits-2)) + ((loff_t)1 << (2*(bits-2)));
+
+ upper_limit -= meta_blocks;
+ upper_limit <<= bits;
+
+ res += (loff_t)1 << (bits-2);
+ res += (loff_t)1 << (2*(bits-2));
+ res += (loff_t)1 << (3*(bits-2));
+ res <<= bits;
+ if (res > upper_limit)
+ res = upper_limit;
+
+ if (res > MAX_LFS_FILESIZE)
+ res = MAX_LFS_FILESIZE;
+
+ return res;
+}
+
+blkcnt_t ext3_inode_blocks(struct ext4_inode *raw_inode,
+ struct inode *inode)
+{
+ blkcnt_t i_blocks ;
+ struct super_block *sb = inode->i_sb;
+ PEXT2_VCB Vcb = (PEXT2_VCB)sb->s_priv;
+
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
+ /* we are using combined 48 bit field */
+ i_blocks = ((u64)le16_to_cpu(raw_inode->i_blocks_high)) << 32 |
+ le32_to_cpu(raw_inode->i_blocks_lo);
+ if (inode->i_flags & EXT4_HUGE_FILE_FL) {
+ /* i_blocks represent file system block size */
+ return i_blocks << (BLOCK_BITS - 9);
+ } else {
+ return i_blocks;
+ }
+ } else {
+ return le32_to_cpu(raw_inode->i_blocks_lo);
+ }
+}
+
+int ext3_inode_blocks_set(struct ext4_inode *raw_inode,
+ struct inode * inode)
+{
+ u64 i_blocks = inode->i_blocks;
+ struct super_block *sb = inode->i_sb;
+ PEXT2_VCB Vcb = (PEXT2_VCB)sb->s_priv;
+
+ if (i_blocks < 0x100000000) {
+ /*
+ * i_blocks can be represnted in a 32 bit variable
+ * as multiple of 512 bytes
+ */
+ raw_inode->i_blocks_lo = cpu_to_le32(i_blocks);
+ raw_inode->i_blocks_high = 0;
+ inode->i_flags &= ~EXT4_HUGE_FILE_FL;
+ return 0;
+ }
+
+ if (!EXT4_HAS_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE)) {
+ EXT3_SET_RO_COMPAT_FEATURE(sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
+ Ext2SaveSuper(NULL, Vcb);
+ }
+
+ if (i_blocks <= 0xffffffffffff) {
+ /*
+ * i_blocks can be represented in a 48 bit variable
+ * as multiple of 512 bytes
+ */
+ raw_inode->i_blocks_lo = (__u32)cpu_to_le32(i_blocks);
+ raw_inode->i_blocks_high = (__u16)cpu_to_le16(i_blocks >> 32);
+ inode->i_flags &= ~EXT4_HUGE_FILE_FL;
+ } else {
+ inode->i_flags |= EXT4_HUGE_FILE_FL;
+ /* i_block is stored in file system block size */
+ i_blocks = i_blocks >> (BLOCK_BITS - 9);
+ raw_inode->i_blocks_lo = (__u32)cpu_to_le32(i_blocks);
+ raw_inode->i_blocks_high = (__u16)cpu_to_le16(i_blocks >> 32);
+ }
+ return 0;
+}
+
+ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
+ struct ext4_group_desc *bg)
+{
+ return le32_to_cpu(bg->bg_block_bitmap_lo) |
+ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
+ (ext4_fsblk_t)le32_to_cpu(bg->bg_block_bitmap_hi) << 32 : 0);
+}
+
+ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
+ struct ext4_group_desc *bg)
+{
+ return le32_to_cpu(bg->bg_inode_bitmap_lo) |
+ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
+ (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_bitmap_hi) << 32 : 0);
+}
+
+ext4_fsblk_t ext4_inode_table(struct super_block *sb,
+ struct ext4_group_desc *bg)
+{
+ return le32_to_cpu(bg->bg_inode_table_lo) |
+ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
+ (ext4_fsblk_t)le32_to_cpu(bg->bg_inode_table_hi) << 32 : 0);
+}
+
+__u32 ext4_free_blks_count(struct super_block *sb,
+ struct ext4_group_desc *bg)
+{
+ return le16_to_cpu(bg->bg_free_blocks_count_lo) |
+ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
+ (__u32)le16_to_cpu(bg->bg_free_blocks_count_hi) << 16 : 0);
+}
+
+__u32 ext4_free_inodes_count(struct super_block *sb,
+ struct ext4_group_desc *bg)
+{
+ return le16_to_cpu(bg->bg_free_inodes_count_lo) |
+ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
+ (__u32)le16_to_cpu(bg->bg_free_inodes_count_hi) << 16 : 0);
+}
+
+__u32 ext4_used_dirs_count(struct super_block *sb,
+ struct ext4_group_desc *bg)
+{
+ return le16_to_cpu(bg->bg_used_dirs_count_lo) |
+ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
+ (__u32)le16_to_cpu(bg->bg_used_dirs_count_hi) << 16 : 0);
+}
+
+__u32 ext4_itable_unused_count(struct super_block *sb,
+ struct ext4_group_desc *bg)
+{
+ return le16_to_cpu(bg->bg_itable_unused_lo) |
+ (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT ?
+ (__u32)le16_to_cpu(bg->bg_itable_unused_hi) << 16 : 0);
+}
+
+void ext4_block_bitmap_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk)
+{
+ bg->bg_block_bitmap_lo = cpu_to_le32((u32)blk);
+ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
+ bg->bg_block_bitmap_hi = cpu_to_le32(blk >> 32);
+}
+
+void ext4_inode_bitmap_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk)
+{
+ bg->bg_inode_bitmap_lo = cpu_to_le32((u32)blk);
+ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
+ bg->bg_inode_bitmap_hi = cpu_to_le32(blk >> 32);
+}
+
+void ext4_inode_table_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk)
+{
+ bg->bg_inode_table_lo = cpu_to_le32((u32)blk);
+ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
+ bg->bg_inode_table_hi = cpu_to_le32(blk >> 32);
+}
+
+void ext4_free_blks_set(struct super_block *sb,
+ struct ext4_group_desc *bg, __u32 count)
+{
+ bg->bg_free_blocks_count_lo = cpu_to_le16((__u16)count);
+ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
+ bg->bg_free_blocks_count_hi = cpu_to_le16(count >> 16);
+}
+
+void ext4_free_inodes_set(struct super_block *sb,
+ struct ext4_group_desc *bg, __u32 count)
+{
+ bg->bg_free_inodes_count_lo = cpu_to_le16((__u16)count);
+ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
+ bg->bg_free_inodes_count_hi = cpu_to_le16(count >> 16);
+}
+
+void ext4_used_dirs_set(struct super_block *sb,
+ struct ext4_group_desc *bg, __u32 count)
+{
+ bg->bg_used_dirs_count_lo = cpu_to_le16((__u16)count);
+ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
+ bg->bg_used_dirs_count_hi = cpu_to_le16(count >> 16);
+}
+
+void ext4_itable_unused_set(struct super_block *sb,
+ struct ext4_group_desc *bg, __u32 count)
+{
+ bg->bg_itable_unused_lo = cpu_to_le16((__u16)count);
+ if (EXT4_DESC_SIZE(sb) >= EXT4_MIN_DESC_SIZE_64BIT)
+ bg->bg_itable_unused_hi = cpu_to_le16(count >> 16);
+}
+
+static inline int test_root(ext3_group_t a, ext3_group_t b)
+{
+ ext3_group_t num = b;
+
+ while (a > num)
+ num *= b;
+ return num == a;
+}
+
+static int ext3_group_sparse(ext3_group_t group)
+{
+ if (group <= 1)
+ return 1;
+ if (!(group & 1))
+ return 0;
+ return (test_root(group, 7) || test_root(group, 5) ||
+ test_root(group, 3));
+}
+
+/**
+ * ext4_bg_has_super - number of blocks used by the superblock in group
+ * @sb: superblock for filesystem
+ * @group: group number to check
+ *
+ * Return the number of blocks used by the superblock (primary or backup)
+ * in this group. Currently this will be only 0 or 1.
+ */
+int ext3_bg_has_super(struct super_block *sb, ext3_group_t group)
+{
+ if (EXT4_HAS_RO_COMPAT_FEATURE(sb,
+ EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) &&
+ !ext3_group_sparse(group))
+ return 0;
+ return 1;
+}
+
+static unsigned long ext4_bg_num_gdb_meta(struct super_block *sb,
+ ext4_group_t group)
+{
+ unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
+ ext4_group_t first = metagroup * EXT4_DESC_PER_BLOCK(sb);
+ ext4_group_t last = first + EXT4_DESC_PER_BLOCK(sb) - 1;
+
+ if (group == first || group == first + 1 || group == last)
+ return 1;
+ return 0;
+}
+
+static unsigned long ext4_bg_num_gdb_nometa(struct super_block *sb,
+ ext4_group_t group)
+{
+ return ext3_bg_has_super(sb, group) ? EXT4_SB(sb)->s_gdb_count : 0;
+}
+
+/**
+ * ext4_bg_num_gdb - number of blocks used by the group table in group
+ * @sb: superblock for filesystem
+ * @group: group number to check
+ *
+ * Return the number of blocks used by the group descriptor table
+ * (primary or backup) in this group. In the future there may be a
+ * different number of descriptor blocks in each group.
+ */
+unsigned long ext4_bg_num_gdb(struct super_block *sb, ext4_group_t group)
+{
+ unsigned long first_meta_bg =
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_meta_bg);
+ unsigned long metagroup = group / EXT4_DESC_PER_BLOCK(sb);
+
+ if (!EXT4_HAS_INCOMPAT_FEATURE(sb,EXT4_FEATURE_INCOMPAT_META_BG) ||
+ metagroup < first_meta_bg)
+ return ext4_bg_num_gdb_nometa(sb, group);
+
+ return ext4_bg_num_gdb_meta(sb,group);
+
+}
+
+ext3_fsblk_t descriptor_loc(struct super_block *sb,
+ ext3_fsblk_t logical_sb_block, unsigned int nr)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ ext3_group_t bg, first_meta_bg;
+ int has_super = 0;
+
+ first_meta_bg = le32_to_cpu(sbi->s_es->s_first_meta_bg);
+
+ if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
+ nr < first_meta_bg)
+ return logical_sb_block + nr + 1;
+ bg = sbi->s_desc_per_block * nr;
+ if (ext3_bg_has_super(sb, bg))
+ has_super = 1;
+ return (has_super + ext3_group_first_block_no(sb, bg));
+}
+
+#define ext4_set_bit(n, p) set_bit((int)(n), (unsigned long *)(p))
+
+/*
+ * The free inodes are managed by bitmaps. A file system contains several
+ * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
+ * block for inodes, N blocks for the inode table and data blocks.
+ *
+ * The file system contains group descriptors which are located after the
+ * super block. Each descriptor contains the number of the bitmap block and
+ * the free blocks count in the block.
+ */
+
+/*
+ * To avoid calling the atomic setbit hundreds or thousands of times, we only
+ * need to use it within a single byte (to ensure we get endianness right).
+ * We can use memset for the rest of the bitmap as there are no other users.
+ */
+void mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
+{
+ int i;
+
+ if (start_bit >= end_bit)
+ return;
+
+ DEBUG(DL_INF, ("mark end bits +%d through +%d used\n", start_bit, end_bit));
+ for (i = start_bit; (unsigned)i < ((start_bit + 7) & ~7UL); i++)
+ ext4_set_bit(i, bitmap);
+ if (i < end_bit)
+ memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
+}
+
+/* Initializes an uninitialized inode bitmap */
+unsigned ext4_init_inode_bitmap(struct super_block *sb, struct buffer_head *bh,
+ ext4_group_t block_group,
+ struct ext4_group_desc *gdp)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+ mark_buffer_dirty(bh);
+
+ /* If checksum is bad mark all blocks and inodes use to prevent
+ * allocation, essentially implementing a per-group read-only flag. */
+ if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
+ ext4_error(sb, __FUNCTION__, "Checksum bad for group %u",
+ block_group);
+ ext4_free_blks_set(sb, gdp, 0);
+ ext4_free_inodes_set(sb, gdp, 0);
+ ext4_itable_unused_set(sb, gdp, 0);
+ memset(bh->b_data, 0xff, sb->s_blocksize);
+ return 0;
+ }
+
+ memset(bh->b_data, 0, (EXT4_INODES_PER_GROUP(sb) + 7) / 8);
+ mark_bitmap_end(EXT4_INODES_PER_GROUP(sb), sb->s_blocksize * 8,
+ bh->b_data);
+ ext4_itable_unused_set(sb, gdp, EXT4_INODES_PER_GROUP(sb));
+
+ return EXT4_INODES_PER_GROUP(sb);
+}
+
+/*
+ * Calculate the block group number and offset, given a block number
+ */
+void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
+ ext4_group_t *blockgrpp, ext4_grpblk_t *offsetp)
+{
+ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+ ext4_grpblk_t offset;
+
+ blocknr = blocknr - le32_to_cpu(es->s_first_data_block);
+ offset = do_div(blocknr, EXT4_BLOCKS_PER_GROUP(sb));
+ if (offsetp)
+ *offsetp = offset;
+ if (blockgrpp)
+ *blockgrpp = (ext4_grpblk_t)blocknr;
+
+}
+
+static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
+ ext4_group_t block_group)
+{
+ ext4_group_t actual_group;
+ ext4_get_group_no_and_offset(sb, block, &actual_group, NULL);
+ if (actual_group == block_group)
+ return 1;
+ return 0;
+}
+
+static int ext4_group_used_meta_blocks(struct super_block *sb,
+ ext4_group_t block_group)
+{
+ ext4_fsblk_t tmp;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ /* block bitmap, inode bitmap, and inode table blocks */
+ int used_blocks = sbi->s_itb_per_group + 2;
+
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG)) {
+ struct ext4_group_desc *gdp;
+ struct buffer_head *bh = NULL;
+
+ gdp = ext4_get_group_desc(sb, block_group, &bh);
+ if (!ext4_block_in_group(sb, ext4_block_bitmap(sb, gdp),
+ block_group))
+ used_blocks--;
+
+ if (!ext4_block_in_group(sb, ext4_inode_bitmap(sb, gdp),
+ block_group))
+ used_blocks--;
+
+ tmp = ext4_inode_table(sb, gdp);
+ for (; tmp < ext4_inode_table(sb, gdp) +
+ sbi->s_itb_per_group; tmp++) {
+ if (!ext4_block_in_group(sb, tmp, block_group))
+ used_blocks -= 1;
+ }
+ if (bh)
+ fini_bh(&bh);
+ }
+ return used_blocks;
+}
+
+/* Initializes an uninitialized block bitmap if given, and returns the
+ * number of blocks free in the group. */
+unsigned ext4_init_block_bitmap(struct super_block *sb, struct buffer_head *bh,
+ ext4_group_t block_group, struct ext4_group_desc *gdp)
+{
+ int bit, bit_max;
+ unsigned free_blocks, group_blocks;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+ if (bh) {
+ mark_buffer_dirty(bh);
+ /* If checksum is bad mark all blocks used to prevent allocation
+ * essentially implementing a per-group read-only flag. */
+ if (!ext4_group_desc_csum_verify(sb, block_group, gdp)) {
+ ext4_error(sb, __FUNCTION__,
+ "Checksum bad for group %u", block_group);
+ ext4_free_blks_set(sb, gdp, 0);
+ ext4_free_inodes_set(sb, gdp, 0);
+ ext4_itable_unused_set(sb, gdp, 0);
+ memset(bh->b_data, 0xff, sb->s_blocksize);
+ return 0;
+ }
+ memset(bh->b_data, 0, sb->s_blocksize);
+ }
+
+ /* Check for superblock and gdt backups in this group */
+ bit_max = ext3_bg_has_super(sb, block_group);
+
+ if (!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||
+ block_group < le32_to_cpu(sbi->s_es->s_first_meta_bg) *
+ sbi->s_desc_per_block) {
+ if (bit_max) {
+ bit_max += ext4_bg_num_gdb(sb, block_group);
+ bit_max +=
+ le16_to_cpu(sbi->s_es->s_reserved_gdt_blocks);
+ }
+ } else { /* For META_BG_BLOCK_GROUPS */
+ bit_max += ext4_bg_num_gdb(sb, block_group);
+ }
+
+ if (block_group == sbi->s_groups_count - 1) {
+ /*
+ * Even though mke2fs always initialize first and last group
+ * if some other tool enabled the EXT4_BG_BLOCK_UNINIT we need
+ * to make sure we calculate the right free blocks
+ */
+ group_blocks = (unsigned int)(ext3_blocks_count(sbi->s_es) -
+ le32_to_cpu(sbi->s_es->s_first_data_block) -
+ (EXT4_BLOCKS_PER_GROUP(sb) * (sbi->s_groups_count - 1)));
+ } else {
+ group_blocks = EXT4_BLOCKS_PER_GROUP(sb);
+ }
+
+ free_blocks = group_blocks - bit_max;
+
+ if (bh) {
+ ext4_fsblk_t start, tmp;
+ int flex_bg = 0;
+
+ for (bit = 0; bit < bit_max; bit++)
+ ext4_set_bit(bit, bh->b_data);
+
+ start = ext3_group_first_block_no(sb, block_group);
+
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb,
+ EXT4_FEATURE_INCOMPAT_FLEX_BG))
+ flex_bg = 1;
+
+ /* Set bits for block and inode bitmaps, and inode table */
+ tmp = ext4_block_bitmap(sb, gdp);
+ if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
+ ext4_set_bit(tmp - start, bh->b_data);
+
+ tmp = ext4_inode_bitmap(sb, gdp);
+ if (!flex_bg || ext4_block_in_group(sb, tmp, block_group))
+ ext4_set_bit(tmp - start, bh->b_data);
+
+ tmp = ext4_inode_table(sb, gdp);
+ for (; tmp < ext4_inode_table(sb, gdp) +
+ sbi->s_itb_per_group; tmp++) {
+ if (!flex_bg ||
+ ext4_block_in_group(sb, tmp, block_group))
+ ext4_set_bit(tmp - start, bh->b_data);
+ }
+ /*
+ * Also if the number of blocks within the group is
+ * less than the blocksize * 8 ( which is the size
+ * of bitmap ), set rest of the block bitmap to 1
+ */
+ mark_bitmap_end(group_blocks, sb->s_blocksize * 8, bh->b_data);
+ }
+ return free_blocks - ext4_group_used_meta_blocks(sb, block_group);
+}
+
+/**
+ * ext4_get_group_desc() -- load group descriptor from disk
+ * @sb: super block
+ * @block_group: given block group
+ * @bh: pointer to the buffer head to store the block
+ * group descriptor
+ */
+struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
+ ext4_group_t block_group, struct buffer_head **bh)
+{
+ struct ext4_group_desc *desc = NULL;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ PEXT2_VCB vcb = sb->s_priv;
+ ext4_group_t group;
+ ext4_group_t offset;
+
+ if (bh)
+ *bh = NULL;
+
+ if (block_group >= sbi->s_groups_count) {
+ ext4_error(sb, "ext4_get_group_desc",
+ "block_group >= groups_count - "
+ "block_group = %u, groups_count = %u",
+ block_group, sbi->s_groups_count);
+
+ return NULL;
+ }
+
+ __try {
+
+ group = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
+ offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
+
+ if (!sbi->s_gd) {
+ if (!Ext2LoadGroup(vcb)) {
+ __leave;
+ }
+ } else if ( !sbi->s_gd[group].block ||
+ !sbi->s_gd[group].bh) {
+ if (!Ext2LoadGroupBH(vcb)) {
+ __leave;
+ }
+ }
+
+ desc = (struct ext4_group_desc *)((PCHAR)sbi->s_gd[group].gd +
+ offset * EXT4_DESC_SIZE(sb));
+ if (bh) {
+ atomic_inc(&sbi->s_gd[group].bh->b_count);
+ *bh = sbi->s_gd[group].bh;
+ }
+ } __finally {
+ /* do cleanup */
+ }
+
+ return desc;
+}
+
+
+/**
+ * ext4_count_free_blocks() -- count filesystem free blocks
+ * @sb: superblock
+ *
+ * Adds up the number of free blocks from each block group.
+ */
+ext4_fsblk_t ext4_count_free_blocks(struct super_block *sb)
+{
+ ext4_fsblk_t desc_count;
+ struct ext4_group_desc *gdp;
+ struct buffer_head *bh = NULL;
+ ext4_group_t i;
+ ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
+
+ desc_count = 0;
+ smp_rmb();
+ for (i = 0; i < ngroups; i++) {
+ gdp = ext4_get_group_desc(sb, i, &bh);
+ if (!bh)
+ continue;
+ desc_count += ext4_free_blks_count(sb, gdp);
+ fini_bh(&bh);
+ }
+
+ return desc_count;
+}
+
+unsigned long ext4_count_free_inodes(struct super_block *sb)
+{
+ unsigned long desc_count;
+ struct ext4_group_desc *gdp;
+ struct buffer_head *bh = NULL;
+ ext4_group_t i;
+
+ desc_count = 0;
+ for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
+ gdp = ext4_get_group_desc(sb, i, &bh);
+ if (!bh)
+ continue;
+ desc_count += ext4_free_inodes_count(sb, gdp);
+ fini_bh(&bh);
+ }
+ return desc_count;
+}
+
+/* Called at mount-time, super-block is locked */
+unsigned long ext4_count_dirs(struct super_block * sb)
+{
+ struct ext4_group_desc *gdp;
+ struct buffer_head *bh = NULL;
+ unsigned long count = 0;
+ ext4_group_t i;
+
+ for (i = 0; i < EXT4_SB(sb)->s_groups_count; i++) {
+ gdp = ext4_get_group_desc(sb, i, &bh);
+ if (!bh)
+ continue;
+ count += ext4_used_dirs_count(sb, gdp);
+ fini_bh(&bh);
+ }
+ return count;
+}
+
+/* Called at mount-time, super-block is locked */
+int ext4_check_descriptors(struct super_block *sb)
+{
+ PEXT2_VCB Vcb = sb->s_priv;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ ext4_fsblk_t first_block = le32_to_cpu(sbi->s_es->s_first_data_block);
+ ext4_fsblk_t last_block;
+ ext4_fsblk_t block_bitmap;
+ ext4_fsblk_t inode_bitmap;
+ ext4_fsblk_t inode_table;
+ int flexbg_flag = 0;
+ ext4_group_t i;
+
+ if (EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_FLEX_BG))
+ flexbg_flag = 1;
+
+ DEBUG(DL_INF, ("Checking group descriptors"));
+
+ for (i = 0; i < sbi->s_groups_count; i++) {
+
+ struct buffer_head *bh = NULL;
+ struct ext4_group_desc *gdp = ext4_get_group_desc(sb, i, &bh);
+
+ if (!bh)
+ continue;
+
+ if (i == sbi->s_groups_count - 1 || flexbg_flag)
+ last_block = ext3_blocks_count(sbi->s_es) - 1;
+ else
+ last_block = first_block +
+ (EXT3_BLOCKS_PER_GROUP(sb) - 1);
+
+ block_bitmap = ext4_block_bitmap(sb, gdp);
+ if (block_bitmap < first_block || block_bitmap > last_block) {
+ printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+ "Block bitmap for group %u not in group "
+ "(block %llu)!\n", i, block_bitmap);
+ __brelse(bh);
+ return 0;
+ }
+ inode_bitmap = ext4_inode_bitmap(sb, gdp);
+ if (inode_bitmap < first_block || inode_bitmap > last_block) {
+ printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+ "Inode bitmap for group %u not in group "
+ "(block %llu)!\n", i, inode_bitmap);
+ __brelse(bh);
+ return 0;
+ }
+ inode_table = ext4_inode_table(sb, gdp);
+ if (inode_table < first_block ||
+ inode_table + sbi->s_itb_per_group - 1 > last_block) {
+ printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+ "Inode table for group %u not in group "
+ "(block %llu)!\n", i, inode_table);
+ __brelse(bh);
+ return 0;
+ }
+
+ if (!ext4_group_desc_csum_verify(sb, i, gdp)) {
+ printk(KERN_ERR "EXT4-fs: ext4_check_descriptors: "
+ "Checksum for group %u failed.\n", i);
+ if (!IsVcbReadOnly(Vcb)) {
+ //__brelse(bh);
+ //return 0;
+ }
+ }
+
+ if (!flexbg_flag)
+ first_block += EXT4_BLOCKS_PER_GROUP(sb);
+
+ __brelse(bh);
+ }
+
+ ext3_free_blocks_count_set(sbi->s_es, ext4_count_free_blocks(sb));
+ sbi->s_es->s_free_inodes_count = cpu_to_le32(ext4_count_free_inodes(sb));
+ return 1;
+}
diff --git a/Ext4Fsd/ext3/htree.c b/Ext4Fsd/ext3/htree.c
index 709f394..8bc397f 100644
--- a/Ext4Fsd/ext3/htree.c
+++ b/Ext4Fsd/ext3/htree.c
@@ -758,7 +758,7 @@ static int call_filldir(struct file * filp, void * cookie,
}
return 0;
}
-
+#if 0
struct fake_dirent
{
__le32 inode;
@@ -823,7 +823,7 @@ struct dx_map_entry
__u16 offs;
__u16 size;
};
-
+#endif
/*
* Future: use high four bits of block for coalesce-on-delete flags
* Mask them off for now.
diff --git a/Ext4Fsd/ext3/recover.c b/Ext4Fsd/ext3/recover.c
index ff3e07e..e30a80c 100644
--- a/Ext4Fsd/ext3/recover.c
+++ b/Ext4Fsd/ext3/recover.c
@@ -11,7 +11,6 @@
#include
#include
-#include
/* GLOBALS ***************************************************************/
diff --git a/Ext4Fsd/ext4/SOURCES b/Ext4Fsd/ext4/SOURCES
index 4655235..7214bf8 100644
--- a/Ext4Fsd/ext4/SOURCES
+++ b/Ext4Fsd/ext4/SOURCES
@@ -25,5 +25,5 @@ DRIVERTYPE=FS
INCLUDES=.;..;..\include;$(DRIVER_INC_PATH);
# The source code:
-SOURCES= ext4_bh.c ext4_extents.c ext4_jbd2.c extents.c \
- ext4_xattr.c
+SOURCES= ext4_bh.c ext4_csum.c ext4_extents.c ext4_jbd2.c ext4_xattr.c \
+ extents.c
diff --git a/Ext4Fsd/ext4/ext4_csum.c b/Ext4Fsd/ext4/ext4_csum.c
new file mode 100644
index 0000000..1dd5c80
--- /dev/null
+++ b/Ext4Fsd/ext4/ext4_csum.c
@@ -0,0 +1,757 @@
+/*
+ * COPYRIGHT: See COPYRIGHT.TXT
+ * PROJECT: Ext2-Ext4 File System Driver for WinXP-Win10
+ * FILE: ext4_csum.c
+ * PROGRAMMER: Bo Brantén
+ * HOMEPAGE: http://www.ext2fsd.com
+ * UPDATE HISTORY:
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "ext2fs.h"
+#include "linux\ext4.h"
+#include "linux\ext4_xattr.h"
+
+/* GLOBALS ***************************************************************/
+
+extern PEXT2_GLOBAL Ext2Global;
+
+/* DEFINITIONS *************************************************************/
+
+
+/* FUNCTIONS ***************************************************************/
+
+/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */
+__u16 const crc16_table[256] = {
+ 0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
+ 0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
+ 0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
+ 0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
+ 0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
+ 0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
+ 0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
+ 0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
+ 0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
+ 0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
+ 0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
+ 0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
+ 0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
+ 0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
+ 0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
+ 0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
+ 0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
+ 0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
+ 0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
+ 0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
+ 0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
+ 0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
+ 0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
+ 0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
+ 0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
+ 0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
+ 0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
+ 0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
+ 0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
+ 0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
+ 0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
+ 0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
+};
+
+static inline __u16 crc16_byte(__u16 crc, const __u8 data)
+{
+ return (crc >> 8) ^ crc16_table[(crc ^ data) & 0xff];
+}
+
+static __u16 crc16(__u16 crc, __u8 const *buffer, size_t len)
+{
+ while (len--)
+ crc = crc16_byte(crc, *buffer++);
+ return crc;
+}
+
+/*
+ * This is the CRC-32C table
+ * Generated with:
+ * width = 32 bits
+ * poly = 0x1EDC6F41
+ * reflect input bytes = true
+ * reflect output bytes = true
+ */
+
+static const __u32 crc32c_table[256] = {
+ 0x00000000L, 0xF26B8303L, 0xE13B70F7L, 0x1350F3F4L,
+ 0xC79A971FL, 0x35F1141CL, 0x26A1E7E8L, 0xD4CA64EBL,
+ 0x8AD958CFL, 0x78B2DBCCL, 0x6BE22838L, 0x9989AB3BL,
+ 0x4D43CFD0L, 0xBF284CD3L, 0xAC78BF27L, 0x5E133C24L,
+ 0x105EC76FL, 0xE235446CL, 0xF165B798L, 0x030E349BL,
+ 0xD7C45070L, 0x25AFD373L, 0x36FF2087L, 0xC494A384L,
+ 0x9A879FA0L, 0x68EC1CA3L, 0x7BBCEF57L, 0x89D76C54L,
+ 0x5D1D08BFL, 0xAF768BBCL, 0xBC267848L, 0x4E4DFB4BL,
+ 0x20BD8EDEL, 0xD2D60DDDL, 0xC186FE29L, 0x33ED7D2AL,
+ 0xE72719C1L, 0x154C9AC2L, 0x061C6936L, 0xF477EA35L,
+ 0xAA64D611L, 0x580F5512L, 0x4B5FA6E6L, 0xB93425E5L,
+ 0x6DFE410EL, 0x9F95C20DL, 0x8CC531F9L, 0x7EAEB2FAL,
+ 0x30E349B1L, 0xC288CAB2L, 0xD1D83946L, 0x23B3BA45L,
+ 0xF779DEAEL, 0x05125DADL, 0x1642AE59L, 0xE4292D5AL,
+ 0xBA3A117EL, 0x4851927DL, 0x5B016189L, 0xA96AE28AL,
+ 0x7DA08661L, 0x8FCB0562L, 0x9C9BF696L, 0x6EF07595L,
+ 0x417B1DBCL, 0xB3109EBFL, 0xA0406D4BL, 0x522BEE48L,
+ 0x86E18AA3L, 0x748A09A0L, 0x67DAFA54L, 0x95B17957L,
+ 0xCBA24573L, 0x39C9C670L, 0x2A993584L, 0xD8F2B687L,
+ 0x0C38D26CL, 0xFE53516FL, 0xED03A29BL, 0x1F682198L,
+ 0x5125DAD3L, 0xA34E59D0L, 0xB01EAA24L, 0x42752927L,
+ 0x96BF4DCCL, 0x64D4CECFL, 0x77843D3BL, 0x85EFBE38L,
+ 0xDBFC821CL, 0x2997011FL, 0x3AC7F2EBL, 0xC8AC71E8L,
+ 0x1C661503L, 0xEE0D9600L, 0xFD5D65F4L, 0x0F36E6F7L,
+ 0x61C69362L, 0x93AD1061L, 0x80FDE395L, 0x72966096L,
+ 0xA65C047DL, 0x5437877EL, 0x4767748AL, 0xB50CF789L,
+ 0xEB1FCBADL, 0x197448AEL, 0x0A24BB5AL, 0xF84F3859L,
+ 0x2C855CB2L, 0xDEEEDFB1L, 0xCDBE2C45L, 0x3FD5AF46L,
+ 0x7198540DL, 0x83F3D70EL, 0x90A324FAL, 0x62C8A7F9L,
+ 0xB602C312L, 0x44694011L, 0x5739B3E5L, 0xA55230E6L,
+ 0xFB410CC2L, 0x092A8FC1L, 0x1A7A7C35L, 0xE811FF36L,
+ 0x3CDB9BDDL, 0xCEB018DEL, 0xDDE0EB2AL, 0x2F8B6829L,
+ 0x82F63B78L, 0x709DB87BL, 0x63CD4B8FL, 0x91A6C88CL,
+ 0x456CAC67L, 0xB7072F64L, 0xA457DC90L, 0x563C5F93L,
+ 0x082F63B7L, 0xFA44E0B4L, 0xE9141340L, 0x1B7F9043L,
+ 0xCFB5F4A8L, 0x3DDE77ABL, 0x2E8E845FL, 0xDCE5075CL,
+ 0x92A8FC17L, 0x60C37F14L, 0x73938CE0L, 0x81F80FE3L,
+ 0x55326B08L, 0xA759E80BL, 0xB4091BFFL, 0x466298FCL,
+ 0x1871A4D8L, 0xEA1A27DBL, 0xF94AD42FL, 0x0B21572CL,
+ 0xDFEB33C7L, 0x2D80B0C4L, 0x3ED04330L, 0xCCBBC033L,
+ 0xA24BB5A6L, 0x502036A5L, 0x4370C551L, 0xB11B4652L,
+ 0x65D122B9L, 0x97BAA1BAL, 0x84EA524EL, 0x7681D14DL,
+ 0x2892ED69L, 0xDAF96E6AL, 0xC9A99D9EL, 0x3BC21E9DL,
+ 0xEF087A76L, 0x1D63F975L, 0x0E330A81L, 0xFC588982L,
+ 0xB21572C9L, 0x407EF1CAL, 0x532E023EL, 0xA145813DL,
+ 0x758FE5D6L, 0x87E466D5L, 0x94B49521L, 0x66DF1622L,
+ 0x38CC2A06L, 0xCAA7A905L, 0xD9F75AF1L, 0x2B9CD9F2L,
+ 0xFF56BD19L, 0x0D3D3E1AL, 0x1E6DCDEEL, 0xEC064EEDL,
+ 0xC38D26C4L, 0x31E6A5C7L, 0x22B65633L, 0xD0DDD530L,
+ 0x0417B1DBL, 0xF67C32D8L, 0xE52CC12CL, 0x1747422FL,
+ 0x49547E0BL, 0xBB3FFD08L, 0xA86F0EFCL, 0x5A048DFFL,
+ 0x8ECEE914L, 0x7CA56A17L, 0x6FF599E3L, 0x9D9E1AE0L,
+ 0xD3D3E1ABL, 0x21B862A8L, 0x32E8915CL, 0xC083125FL,
+ 0x144976B4L, 0xE622F5B7L, 0xF5720643L, 0x07198540L,
+ 0x590AB964L, 0xAB613A67L, 0xB831C993L, 0x4A5A4A90L,
+ 0x9E902E7BL, 0x6CFBAD78L, 0x7FAB5E8CL, 0x8DC0DD8FL,
+ 0xE330A81AL, 0x115B2B19L, 0x020BD8EDL, 0xF0605BEEL,
+ 0x24AA3F05L, 0xD6C1BC06L, 0xC5914FF2L, 0x37FACCF1L,
+ 0x69E9F0D5L, 0x9B8273D6L, 0x88D28022L, 0x7AB90321L,
+ 0xAE7367CAL, 0x5C18E4C9L, 0x4F48173DL, 0xBD23943EL,
+ 0xF36E6F75L, 0x0105EC76L, 0x12551F82L, 0xE03E9C81L,
+ 0x34F4F86AL, 0xC69F7B69L, 0xD5CF889DL, 0x27A40B9EL,
+ 0x79B737BAL, 0x8BDCB4B9L, 0x988C474DL, 0x6AE7C44EL,
+ 0xBE2DA0A5L, 0x4C4623A6L, 0x5F16D052L, 0xAD7D5351L
+};
+
+/*
+ * Steps through buffer one byte at at time, calculates reflected
+ * crc using table.
+ */
+
+static __u32 crc32c(__u32 crc, const __u8 *data, unsigned int length)
+{
+ while (length--)
+ crc = crc32c_table[(crc ^ *data++) & 0xFFL] ^ (crc >> 8);
+
+ return crc;
+}
+
+__u32 ext4_chksum(struct ext4_sb_info *sbi, __u32 crc,
+ const void *buffer, unsigned int length)
+{
+ return crc32c(crc, buffer, length);
+}
+
+/*
+ * Metadata checksum functions for the superblock.
+ */
+
+static __le32 ext4_superblock_csum(struct super_block *sb,
+ struct ext4_super_block *es)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ int offset = offsetof(struct ext4_super_block, s_checksum);
+ __u32 csum;
+
+ csum = ext4_chksum(sbi, ~0, (char *)es, offset);
+
+ return cpu_to_le32(csum);
+}
+
+int ext4_superblock_csum_verify(struct super_block *sb,
+ struct ext4_super_block *es)
+{
+ if (!ext4_has_feature_metadata_csum(sb))
+ return 1;
+
+ return es->s_checksum == ext4_superblock_csum(sb, es);
+}
+
+void ext4_superblock_csum_set(struct super_block *sb)
+{
+ struct ext4_super_block *es = EXT4_SB(sb)->s_es;
+
+ if (!ext4_has_feature_metadata_csum(sb))
+ return;
+
+ es->s_checksum = ext4_superblock_csum(sb, es);
+}
+
+/*
+ * Metadata checksum functions for the group descriptors.
+ */
+
+static __le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group,
+ struct ext4_group_desc *gdp)
+{
+ unsigned int offset = offsetof(struct ext4_group_desc, bg_checksum);
+ __u16 crc;
+ __le32 le_group = cpu_to_le32(block_group);
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+ if (ext4_has_feature_metadata_csum(sb)) {
+ /* Use new metadata_csum algorithm */
+ __u32 csum32;
+ __u16 dummy_csum = 0;
+
+ csum32 = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&le_group,
+ sizeof(le_group));
+ csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp, offset);
+ csum32 = ext4_chksum(sbi, csum32, (__u8 *)&dummy_csum,
+ sizeof(dummy_csum));
+ offset += sizeof(dummy_csum);
+ if (offset < sbi->s_desc_size)
+ csum32 = ext4_chksum(sbi, csum32, (__u8 *)gdp + offset,
+ sbi->s_desc_size - offset);
+
+ crc = csum32 & 0xFFFF;
+ } else if (ext4_has_feature_gdt_csum(sb)) {
+ /* old crc16 code */
+ crc = crc16(~0, sbi->s_es->s_uuid, sizeof(sbi->s_es->s_uuid));
+ crc = crc16(crc, (__u8 *)&le_group, sizeof(le_group));
+ crc = crc16(crc, (__u8 *)gdp, offset);
+ offset += sizeof(gdp->bg_checksum); /* skip checksum */
+ /* for checksum of struct ext4_group_desc do the rest...*/
+ if (ext4_has_feature_64bit(sb) &&
+ offset < le16_to_cpu(sbi->s_es->s_desc_size))
+ crc = crc16(crc, (__u8 *)gdp + offset,
+ le16_to_cpu(sbi->s_es->s_desc_size) -
+ offset);
+ } else {
+ crc = 0;
+ }
+
+ return cpu_to_le16(crc);
+}
+
+int ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group,
+ struct ext4_group_desc *gdp)
+{
+ if (!ext4_has_feature_metadata_csum(sb))
+ return 1;
+
+ return gdp->bg_checksum == ext4_group_desc_csum(sb, block_group, gdp);
+}
+
+void ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group,
+ struct ext4_group_desc *gdp)
+{
+ if (!ext4_has_group_desc_csum(sb))
+ return;
+
+ gdp->bg_checksum = ext4_group_desc_csum(sb, block_group, gdp);
+}
+
+/*
+ * Metadata checksum functions for the inode bitmap.
+ */
+
+int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
+ struct ext4_group_desc *gdp,
+ struct buffer_head *bh, int sz)
+{
+ __u32 hi;
+ __u32 provided, calculated;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+ if (!ext4_has_feature_metadata_csum(sb))
+ return 1;
+
+ provided = le16_to_cpu(gdp->bg_inode_bitmap_csum_lo);
+ calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
+ if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END) {
+ hi = le16_to_cpu(gdp->bg_inode_bitmap_csum_hi);
+ provided |= (hi << 16);
+ } else
+ calculated &= 0xFFFF;
+
+ return provided == calculated;
+}
+
+void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
+ struct ext4_group_desc *gdp,
+ struct buffer_head *bh, int sz)
+{
+ __u32 csum;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+ if (!ext4_has_feature_metadata_csum(sb))
+ return;
+
+ csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
+ gdp->bg_inode_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF);
+ if (sbi->s_desc_size >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
+ gdp->bg_inode_bitmap_csum_hi = cpu_to_le16(csum >> 16);
+}
+
+/*
+ * Metadata checksum functions for the block bitmap.
+ */
+
+int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
+ struct ext4_group_desc *gdp,
+ struct buffer_head *bh)
+{
+ __u32 hi;
+ __u32 provided, calculated;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ int sz = EXT4_CLUSTERS_PER_GROUP(sb) / 8;
+
+ if (!ext4_has_feature_metadata_csum(sb))
+ return 1;
+
+ provided = le16_to_cpu(gdp->bg_block_bitmap_csum_lo);
+ calculated = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
+ if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END) {
+ hi = le16_to_cpu(gdp->bg_block_bitmap_csum_hi);
+ provided |= (hi << 16);
+ } else
+ calculated &= 0xFFFF;
+
+ return provided == calculated;
+}
+
+void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
+ struct ext4_group_desc *gdp,
+ struct buffer_head *bh)
+{
+ int sz = EXT4_CLUSTERS_PER_GROUP(sb) / 8;
+ __u32 csum;
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+
+ if (!ext4_has_feature_metadata_csum(sb))
+ return;
+
+ csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)bh->b_data, sz);
+ gdp->bg_block_bitmap_csum_lo = cpu_to_le16(csum & 0xFFFF);
+ if (sbi->s_desc_size >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_END)
+ gdp->bg_block_bitmap_csum_hi = cpu_to_le16(csum >> 16);
+}
+
+/*
+ * Metadata checksum functions for the inodes.
+ */
+
+static __le32 ext4_inode_csum_seed(struct inode *inode)
+{
+ /* Precompute checksum seed for inode metadata */
+ if (ext4_has_feature_metadata_csum(inode->i_sb)) {
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ __u32 csum;
+ __le32 inum = cpu_to_le32(inode->i_ino);
+ __le32 gen = inode->i_generation;
+ csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&inum, sizeof(inum));
+ return ext4_chksum(sbi, csum, (__u8 *)&gen, sizeof(gen));
+ }
+
+ return 0;
+}
+
+static __u32 ext4_inode_csum(struct inode *inode, struct ext4_inode *raw,
+ struct ext4_inode_info *ei)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ __u32 csum;
+ __u16 dummy_csum = 0;
+ int offset = offsetof(struct ext4_inode, i_checksum_lo);
+ unsigned int csum_size = sizeof(dummy_csum);
+
+ csum = ext4_chksum(sbi, ext4_inode_csum_seed(inode), (__u8 *)raw, offset);
+ csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, csum_size);
+ offset += csum_size;
+ csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
+ EXT4_GOOD_OLD_INODE_SIZE - offset);
+
+ if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE) {
+ offset = offsetof(struct ext4_inode, i_checksum_hi);
+ csum = ext4_chksum(sbi, csum, (__u8 *)raw +
+ EXT4_GOOD_OLD_INODE_SIZE,
+ offset - EXT4_GOOD_OLD_INODE_SIZE);
+ if (EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi)) {
+ csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum,
+ csum_size);
+ offset += csum_size;
+ }
+ csum = ext4_chksum(sbi, csum, (__u8 *)raw + offset,
+ EXT4_INODE_SIZE(inode->i_sb) - offset);
+ }
+
+ return csum;
+}
+
+int ext4_inode_csum_verify(struct inode *inode, struct ext4_inode *raw,
+ struct ext4_inode_info *ei)
+{
+ __u32 provided, calculated, isz;
+
+ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
+ cpu_to_le32(EXT4_OS_LINUX) ||
+ !ext4_has_feature_metadata_csum(inode->i_sb))
+ return 1;
+
+ provided = le16_to_cpu(raw->i_checksum_lo);
+ calculated = ext4_inode_csum(inode, raw, ei);
+ if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
+ EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
+ {provided |= ((__u32)le16_to_cpu(raw->i_checksum_hi)) << 16;isz=EXT4_INODE_SIZE(inode->i_sb);}
+ else
+ {calculated &= 0xFFFF;isz=EXT4_GOOD_OLD_INODE_SIZE;}
+
+ if (provided != calculated) {
+ DbgPrint("inod %d checksum invalid: %lx!=%lx, isz=%u\n", inode->i_ino, provided, calculated, isz);
+ }
+
+ return provided == calculated;
+}
+
+void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw,
+ struct ext4_inode_info *ei)
+{
+ __u32 csum;
+
+ if (EXT4_SB(inode->i_sb)->s_es->s_creator_os !=
+ cpu_to_le32(EXT4_OS_LINUX) ||
+ !ext4_has_feature_metadata_csum(inode->i_sb))
+ return;
+
+ csum = ext4_inode_csum(inode, raw, ei);
+ raw->i_checksum_lo = cpu_to_le16(csum & 0xFFFF);
+ if (EXT4_INODE_SIZE(inode->i_sb) > EXT4_GOOD_OLD_INODE_SIZE &&
+ EXT4_FITS_IN_INODE(raw, ei, i_checksum_hi))
+ raw->i_checksum_hi = cpu_to_le16(csum >> 16);
+}
+
+/*
+ * Metadata checksum functions for the extent blocks.
+ */
+
+static __le32 ext4_extent_block_csum(struct inode *inode,
+ struct ext4_extent_header *eh)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ __u32 csum;
+
+ csum = ext4_chksum(sbi, ext4_inode_csum_seed(inode), (__u8 *)eh, EXT4_EXTENT_TAIL_OFFSET(eh));
+
+ return cpu_to_le32(csum);
+}
+
+int ext4_extent_block_csum_verify(struct inode *inode,
+ struct ext4_extent_header *eh)
+{
+ struct ext4_extent_tail *et;
+
+ if (!ext4_has_feature_metadata_csum(inode->i_sb))
+ return 1;
+
+ et = find_ext4_extent_tail(eh);
+ return et->et_checksum == ext4_extent_block_csum(inode, eh);
+}
+
+void ext4_extent_block_csum_set(struct inode *inode,
+ struct ext4_extent_header *eh)
+{
+ struct ext4_extent_tail *et;
+
+ if (!ext4_has_feature_metadata_csum(inode->i_sb))
+ return;
+
+ et = find_ext4_extent_tail(eh);
+ et->et_checksum = ext4_extent_block_csum(inode, eh);
+}
+
+/*
+ * Metadata checksum functions for the directory entrys.
+ */
+
+static void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
+ unsigned int blocksize)
+{
+ memset(t, 0, sizeof(struct ext4_dir_entry_tail));
+ t->det_rec_len = ext4_rec_len_to_disk(
+ sizeof(struct ext4_dir_entry_tail), blocksize);
+ t->det_reserved_ft = EXT4_FT_DIR_CSUM;
+}
+
+/* Walk through a dirent block to find a checksum "dirent" at the tail */
+static struct ext4_dir_entry_tail *get_dirent_tail(struct inode *inode,
+ struct ext4_dir_entry *de)
+{
+ struct ext4_dir_entry_tail *t;
+
+#ifdef PARANOID
+ struct ext4_dir_entry *d, *top;
+
+ d = de;
+ top = (struct ext4_dir_entry *)(((void *)de) +
+ (EXT4_BLOCK_SIZE(inode->i_sb) -
+ sizeof(struct ext4_dir_entry_tail)));
+ while (d < top && d->rec_len)
+ d = (struct ext4_dir_entry *)(((void *)d) +
+ le16_to_cpu(d->rec_len));
+
+ if (d != top)
+ return NULL;
+
+ t = (struct ext4_dir_entry_tail *)d;
+#else
+ t = EXT4_DIRENT_TAIL(de, EXT4_BLOCK_SIZE(inode->i_sb));
+#endif
+
+ if (t->det_reserved_zero1 ||
+ le16_to_cpu(t->det_rec_len) != sizeof(struct ext4_dir_entry_tail) ||
+ t->det_reserved_zero2 ||
+ t->det_reserved_ft != EXT4_FT_DIR_CSUM)
+ return NULL;
+
+ return t;
+}
+
+static __le32 ext4_dirent_csum(struct inode *inode,
+ struct ext4_dir_entry *dirent, int size)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ __u32 csum;
+
+ csum = ext4_chksum(sbi, ext4_inode_csum_seed(inode), (__u8 *)dirent, size);
+
+ return cpu_to_le32(csum);
+}
+
+int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent)
+{
+ struct ext4_dir_entry_tail *t;
+
+ if (!ext4_has_feature_metadata_csum(inode->i_sb))
+ return 1;
+
+ t = get_dirent_tail(inode, dirent);
+ if (!t) {
+ DbgPrint("No space for directory leaf checksum. Please run e2fsck -D.\n");
+ return 0;
+ }
+
+ if (t->det_checksum != ext4_dirent_csum(inode, dirent,
+ (unsigned int)((unsigned char *)t - (unsigned char *)dirent)))
+ return 0;
+
+ return 1;
+}
+
+void ext4_dirent_csum_set(struct inode *inode,
+ struct ext4_dir_entry *dirent)
+{
+ struct ext4_dir_entry_tail *t;
+
+ if (!ext4_has_feature_metadata_csum(inode->i_sb))
+ return;
+
+ t = get_dirent_tail(inode, dirent);
+ if (!t) {
+ DbgPrint("No space for directory leaf checksum. Please run e2fsck -D.\n");
+ return;
+ }
+
+ t->det_checksum = ext4_dirent_csum(inode, dirent,
+ (unsigned int)((unsigned char *)t - (unsigned char *)dirent));
+}
+
+static struct dx_countlimit *get_dx_countlimit(struct inode *inode,
+ struct ext4_dir_entry *dirent,
+ int *offset)
+{
+ struct ext4_dir_entry *dp;
+ struct dx_root_info *root;
+ int count_offset;
+
+ if (le16_to_cpu(dirent->rec_len) == EXT4_BLOCK_SIZE(inode->i_sb))
+ count_offset = 8;
+ else if (le16_to_cpu(dirent->rec_len) == 12) {
+ dp = (struct ext4_dir_entry *)(((unsigned char *)dirent) + 12);
+ if (le16_to_cpu(dp->rec_len) !=
+ EXT4_BLOCK_SIZE(inode->i_sb) - 12)
+ return NULL;
+ root = (struct dx_root_info *)(((unsigned char *)dp + 12));
+ if (root->reserved_zero ||
+ root->info_length != sizeof(struct dx_root_info))
+ return NULL;
+ count_offset = 32;
+ } else
+ return NULL;
+
+ if (offset)
+ *offset = count_offset;
+ return (struct dx_countlimit *)(((unsigned char *)dirent) + count_offset);
+}
+
+static __le32 ext4_dx_csum(struct inode *inode, struct ext4_dir_entry *dirent,
+ int count_offset, int count, struct dx_tail *t)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ __u32 csum;
+ int size;
+ __u32 dummy_csum = 0;
+ int offset = offsetof(struct dx_tail, dt_checksum);
+
+ size = count_offset + (count * sizeof(struct dx_entry));
+ csum = ext4_chksum(sbi, ext4_inode_csum_seed(inode), (__u8 *)dirent, size);
+ csum = ext4_chksum(sbi, csum, (__u8 *)t, offset);
+ csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum));
+
+ return cpu_to_le32(csum);
+}
+
+int ext4_dx_csum_verify(struct inode *inode,
+ struct ext4_dir_entry *dirent)
+{
+ struct dx_countlimit *c;
+ struct dx_tail *t;
+ int count_offset, limit, count;
+
+ if (!ext4_has_feature_metadata_csum(inode->i_sb))
+ return 1;
+
+ c = get_dx_countlimit(inode, dirent, &count_offset);
+ if (!c) {
+ DbgPrint("dir seems corrupt? Run e2fsck -D.");
+ return 0;
+ }
+ limit = le16_to_cpu(c->limit);
+ count = le16_to_cpu(c->count);
+ if (count_offset + (limit * sizeof(struct dx_entry)) >
+ EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) {
+ DbgPrint("warn_no_space_for_csum in inode\n");
+ return 0;
+ }
+ t = (struct dx_tail *)(((struct dx_entry *)c) + limit);
+
+ return t->dt_checksum == ext4_dx_csum(inode, dirent, count_offset, count, t);
+}
+
+void ext4_dx_csum_set(struct inode *inode, struct ext4_dir_entry *dirent)
+{
+ struct dx_countlimit *c;
+ struct dx_tail *t;
+ int count_offset, limit, count;
+
+ if (!ext4_has_feature_metadata_csum(inode->i_sb))
+ return;
+
+ c = get_dx_countlimit(inode, dirent, &count_offset);
+ if (!c) {
+ DbgPrint("dir seems corrupt? Run e2fsck -D.");
+ return;
+ }
+ limit = le16_to_cpu(c->limit);
+ count = le16_to_cpu(c->count);
+ if (count_offset + (limit * sizeof(struct dx_entry)) >
+ EXT4_BLOCK_SIZE(inode->i_sb) - sizeof(struct dx_tail)) {
+ DbgPrint("warn_no_space_for_csum in inode\n");
+ return;
+ }
+ t = (struct dx_tail *)(((struct dx_entry *)c) + limit);
+
+ t->dt_checksum = ext4_dx_csum(inode, dirent, count_offset, count, t);
+}
+
+/*
+ * Metadata checksum functions for the multiple mount point structure.
+ */
+
+static __le32 ext4_mmp_csum(struct super_block *sb, struct mmp_struct *mmp)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(sb);
+ int offset = offsetof(struct mmp_struct, mmp_checksum);
+ __u32 csum;
+
+ csum = ext4_chksum(sbi, sbi->s_csum_seed, (char *)mmp, offset);
+
+ return cpu_to_le32(csum);
+}
+
+int ext4_mmp_csum_verify(struct super_block *sb, struct mmp_struct *mmp)
+{
+ if (!ext4_has_feature_metadata_csum(sb))
+ return 1;
+
+ return mmp->mmp_checksum == ext4_mmp_csum(sb, mmp);
+}
+
+void ext4_mmp_csum_set(struct super_block *sb, struct mmp_struct *mmp)
+{
+ if (!ext4_has_feature_metadata_csum(sb))
+ return;
+
+ mmp->mmp_checksum = ext4_mmp_csum(sb, mmp);
+}
+
+/*
+ * Metadata checksum functions for the extended attributes.
+ */
+
+static __le32 ext4_xattr_block_csum(struct inode *inode,
+ sector_t block_nr,
+ struct ext4_xattr_header *hdr)
+{
+ struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);
+ __u32 csum;
+ __le64 dsk_block_nr = cpu_to_le64(block_nr);
+ __u32 dummy_csum = 0;
+ int offset = offsetof(struct ext4_xattr_header, h_checksum);
+
+ csum = ext4_chksum(sbi, sbi->s_csum_seed, (__u8 *)&dsk_block_nr,
+ sizeof(dsk_block_nr));
+ csum = ext4_chksum(sbi, csum, (__u8 *)hdr, offset);
+ csum = ext4_chksum(sbi, csum, (__u8 *)&dummy_csum, sizeof(dummy_csum));
+ offset += sizeof(dummy_csum);
+ csum = ext4_chksum(sbi, csum, (__u8 *)hdr + offset,
+ EXT4_BLOCK_SIZE(inode->i_sb) - offset);
+
+ return cpu_to_le32(csum);
+}
+
+int ext4_xattr_block_csum_verify(struct inode *inode,
+ struct buffer_head *bh)
+{
+ struct ext4_xattr_header *hdr = EXT4_XATTR_BHDR(bh);
+ int ret = 1;
+
+ if (ext4_has_feature_metadata_csum(inode->i_sb)) {
+ lock_buffer(bh);
+ ret = (hdr->h_checksum == ext4_xattr_block_csum(inode,
+ bh->b_blocknr, hdr));
+ unlock_buffer(bh);
+ }
+ return ret;
+}
+
+void ext4_xattr_block_csum_set(struct inode *inode,
+ struct buffer_head *bh)
+{
+ if (ext4_has_feature_metadata_csum(inode->i_sb))
+ EXT4_XATTR_BHDR(bh)->h_checksum = ext4_xattr_block_csum(inode,
+ bh->b_blocknr, EXT4_XATTR_BHDR(bh));
+}
diff --git a/Ext4Fsd/ext4/ext4_jbd2.c b/Ext4Fsd/ext4/ext4_jbd2.c
index 9f1d2a4..5421355 100644
--- a/Ext4Fsd/ext4/ext4_jbd2.c
+++ b/Ext4Fsd/ext4/ext4_jbd2.c
@@ -1,71 +1,72 @@
-#include "ext2fs.h"
-#include "linux\ext4.h"
-
-static handle_t no_journal;
-
-handle_t *__ext4_journal_start_sb(void *icb, struct super_block *sb, unsigned int line,
- int type, int blocks, int rsv_blocks)
-{
- return &no_journal;
-}
-
-int __ext4_journal_stop(const char *where, unsigned int line, void *icb, handle_t *handle)
-{
- return 0;
-}
-
-void ext4_journal_abort_handle(const char *caller, unsigned int line,
- const char *err_fn, struct buffer_head *bh,
- handle_t *handle, int err)
-{
-}
-
-int __ext4_journal_get_write_access(const char *where, unsigned int line,
- void *icb, handle_t *handle, struct buffer_head *bh)
-{
- int err = 0;
- return err;
-}
-
-/*
- * The ext4 forget function must perform a revoke if we are freeing data
- * which has been journaled. Metadata (eg. indirect blocks) must be
- * revoked in all cases.
- *
- * "bh" may be NULL: a metadata block may have been freed from memory
- * but there may still be a record of it in the journal, and that record
- * still needs to be revoked.
- *
- * If the handle isn't valid we're not journaling, but we still need to
- * call into ext4_journal_revoke() to put the buffer head.
- */
-int __ext4_forget(const char *where, unsigned int line, void *icb, handle_t *handle,
- int is_metadata, struct inode *inode,
- struct buffer_head *bh, ext4_fsblk_t blocknr)
-{
- int err = 0;
- return err;
-}
-
-int __ext4_journal_get_create_access(const char *where, unsigned int line,
- void *icb, handle_t *handle, struct buffer_head *bh)
-{
- int err = 0;
- return err;
-}
-
-int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
- void *icb, handle_t *handle, struct inode *inode,
- struct buffer_head *bh)
-{
- int err = 0;
-
- extents_mark_buffer_dirty(bh);
- return err;
-}
-
-int __ext4_handle_dirty_super(const char *where, unsigned int line,
- handle_t *handle, struct super_block *sb)
-{
- return 0;
-}
+#include "ext2fs.h"
+#include "linux\ext4.h"
+#include "linux\jbd.h"
+
+static handle_t no_journal;
+
+handle_t *__ext4_journal_start_sb(void *icb, struct super_block *sb, unsigned int line,
+ int type, int blocks, int rsv_blocks)
+{
+ return &no_journal;
+}
+
+int __ext4_journal_stop(const char *where, unsigned int line, void *icb, handle_t *handle)
+{
+ return 0;
+}
+
+void ext4_journal_abort_handle(const char *caller, unsigned int line,
+ const char *err_fn, struct buffer_head *bh,
+ handle_t *handle, int err)
+{
+}
+
+int __ext4_journal_get_write_access(const char *where, unsigned int line,
+ void *icb, handle_t *handle, struct buffer_head *bh)
+{
+ int err = 0;
+ return err;
+}
+
+/*
+ * The ext4 forget function must perform a revoke if we are freeing data
+ * which has been journaled. Metadata (eg. indirect blocks) must be
+ * revoked in all cases.
+ *
+ * "bh" may be NULL: a metadata block may have been freed from memory
+ * but there may still be a record of it in the journal, and that record
+ * still needs to be revoked.
+ *
+ * If the handle isn't valid we're not journaling, but we still need to
+ * call into ext4_journal_revoke() to put the buffer head.
+ */
+int __ext4_forget(const char *where, unsigned int line, void *icb, handle_t *handle,
+ int is_metadata, struct inode *inode,
+ struct buffer_head *bh, ext4_fsblk_t blocknr)
+{
+ int err = 0;
+ return err;
+}
+
+int __ext4_journal_get_create_access(const char *where, unsigned int line,
+ void *icb, handle_t *handle, struct buffer_head *bh)
+{
+ int err = 0;
+ return err;
+}
+
+int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
+ void *icb, handle_t *handle, struct inode *inode,
+ struct buffer_head *bh)
+{
+ int err = 0;
+
+ extents_mark_buffer_dirty(bh);
+ return err;
+}
+
+int __ext4_handle_dirty_super(const char *where, unsigned int line,
+ handle_t *handle, struct super_block *sb)
+{
+ return 0;
+}
diff --git a/Ext4Fsd/fsctl.c b/Ext4Fsd/fsctl.c
index 9007eed..5450766 100644
--- a/Ext4Fsd/fsctl.c
+++ b/Ext4Fsd/fsctl.c
@@ -1,2877 +1,2881 @@
-/*
- * COPYRIGHT: See COPYRIGHT.TXT
- * PROJECT: Ext2 File System Driver for WinNT/2K/XP
- * FILE: fsctl.c
- * PROGRAMMER: Matt Wu
- * HOMEPAGE: http://www.ext2fsd.com
- * UPDATE HISTORY:
- */
-
-/* INCLUDES *****************************************************************/
-
-#include "ext2fs.h"
-
-/* GLOBALS ***************************************************************/
-
-extern PEXT2_GLOBAL Ext2Global;
-
-/* DEFINITIONS *************************************************************/
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, Ext2IsHandleCountZero)
-#pragma alloc_text(PAGE, Ext2LockVcb)
-#pragma alloc_text(PAGE, Ext2LockVolume)
-#pragma alloc_text(PAGE, Ext2UnlockVcb)
-#pragma alloc_text(PAGE, Ext2UnlockVolume)
-#pragma alloc_text(PAGE, Ext2AllowExtendedDasdIo)
-#pragma alloc_text(PAGE, Ext2GetRetrievalPointerBase)
-#pragma alloc_text(PAGE, Ext2QueryExtentMappings)
-#pragma alloc_text(PAGE, Ext2QueryRetrievalPointers)
-#pragma alloc_text(PAGE, Ext2GetRetrievalPointers)
-#pragma alloc_text(PAGE, Ext2UserFsRequest)
-#pragma alloc_text(PAGE, Ext2IsMediaWriteProtected)
-#pragma alloc_text(PAGE, Ext2MountVolume)
-#pragma alloc_text(PAGE, Ext2PurgeVolume)
-#pragma alloc_text(PAGE, Ext2PurgeFile)
-#pragma alloc_text(PAGE, Ext2DismountVolume)
-#pragma alloc_text(PAGE, Ext2IsVolumeMounted)
-#pragma alloc_text(PAGE, Ext2VerifyVolume)
-#pragma alloc_text(PAGE, Ext2FileSystemControl)
-#endif
-
-
-VOID
-Ext2SetVpbFlag (
- IN PVPB Vpb,
- IN USHORT Flag )
-{
- KIRQL OldIrql;
-
- IoAcquireVpbSpinLock(&OldIrql);
- Vpb->Flags |= Flag;
- IoReleaseVpbSpinLock(OldIrql);
-}
-
-VOID
-Ext2ClearVpbFlag (
- IN PVPB Vpb,
- IN USHORT Flag )
-{
- KIRQL OldIrql;
-
- IoAcquireVpbSpinLock(&OldIrql);
- Vpb->Flags &= ~Flag;
- IoReleaseVpbSpinLock(OldIrql);
-}
-
-BOOLEAN
-Ext2IsHandleCountZero(IN PEXT2_VCB Vcb)
-{
- PEXT2_FCB Fcb;
- PLIST_ENTRY List;
-
- for ( List = Vcb->FcbList.Flink;
- List != &Vcb->FcbList;
- List = List->Flink ) {
-
- Fcb = CONTAINING_RECORD(List, EXT2_FCB, Next);
-
- ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
- (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
-
- DEBUG(DL_INF, ( "Ext2IsHandleCountZero: Inode:%xh File:%S OpenHandleCount=%xh\n",
- Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer, Fcb->OpenHandleCount));
-
- if (Fcb->OpenHandleCount) {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-NTSTATUS
-Ext2LockVcb (IN PEXT2_VCB Vcb,
- IN PFILE_OBJECT FileObject)
-{
- NTSTATUS Status = STATUS_SUCCESS;
-
- __try {
-
- if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
- DEBUG(DL_INF, ( "Ext2LockVolume: Volume is already locked.\n"));
- Status = STATUS_ACCESS_DENIED;
- __leave;
- }
-
- if (Vcb->OpenHandleCount > (ULONG)(FileObject ? 1 : 0)) {
- DEBUG(DL_INF, ( "Ext2LockVcb: There are still opened files.\n"));
-
- Status = STATUS_ACCESS_DENIED;
- __leave;
- }
-
- if (!Ext2IsHandleCountZero(Vcb)) {
- DEBUG(DL_INF, ( "Ext2LockVcb: Thare are still opened files.\n"));
-
- Status = STATUS_ACCESS_DENIED;
- __leave;
- }
-
- SetLongFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
- Ext2SetVpbFlag(Vcb->Vpb, VPB_LOCKED);
- Vcb->LockFile = FileObject;
-
- DEBUG(DL_INF, ( "Ext2LockVcb: Volume locked.\n"));
-
- } __finally {
- // Nothing
- }
-
- return Status;
-}
-
-
-NTSTATUS
-Ext2LockVolume (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- PIO_STACK_LOCATION IrpSp;
- PDEVICE_OBJECT DeviceObject;
- PEXT2_VCB Vcb = NULL;
- NTSTATUS Status;
- BOOLEAN VcbResourceAcquired = FALSE;
-
- __try {
-
- ASSERT(IrpContext != NULL);
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- DeviceObject = IrpContext->DeviceObject;
-
- Status = STATUS_UNSUCCESSFUL;
-
- //
- // This request is not allowed on the main device object
- //
- if (IsExt2FsDevice(DeviceObject)) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
-
- ASSERT(Vcb != NULL);
-
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
-
- ASSERT(IsMounted(Vcb));
-
- IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
-
-#if (_WIN32_WINNT >= 0x0500)
- CcWaitForCurrentLazyWriterActivity();
-#endif
- ExAcquireResourceExclusiveLite(
- &Vcb->MainResource,
- TRUE );
-
- VcbResourceAcquired = TRUE;
-
- /* flush dirty data before locking the volume */
- if (!IsVcbReadOnly(Vcb)) {
- Ext2FlushFiles(IrpContext, Vcb, FALSE);
- Ext2FlushVolume(IrpContext, Vcb, FALSE);
- }
-
- Status = Ext2LockVcb(Vcb, IrpSp->FileObject);
-
- } __finally {
-
- if (VcbResourceAcquired) {
- ExReleaseResourceLite(&Vcb->MainResource);
- }
-
- if (!IrpContext->ExceptionInProgress) {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2UnlockVcb ( IN PEXT2_VCB Vcb,
- IN PFILE_OBJECT FileObject )
-{
- NTSTATUS Status;
-
- __try {
-
- if (FileObject && FileObject->FsContext != Vcb) {
- Status = STATUS_NOT_LOCKED;
- __leave;
- }
-
- if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
- DEBUG(DL_ERR, ( ": Ext2UnlockVcb: Volume is not locked.\n"));
- Status = STATUS_NOT_LOCKED;
- __leave;
- }
-
- if (Vcb->LockFile == FileObject) {
- ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
- Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
- DEBUG(DL_INF, ( "Ext2UnlockVcb: Volume unlocked.\n"));
- Status = STATUS_SUCCESS;
- } else {
- Status = STATUS_NOT_LOCKED;
- }
-
- } __finally {
- // Nothing
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2UnlockVolume (
- IN PEXT2_IRP_CONTEXT IrpContext
-)
-{
- PIO_STACK_LOCATION IrpSp = NULL;
- PDEVICE_OBJECT DeviceObject = NULL;
- PEXT2_VCB Vcb = NULL;
- NTSTATUS Status;
- BOOLEAN VcbResourceAcquired = FALSE;
-
- __try {
-
- ASSERT(IrpContext != NULL);
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- DeviceObject = IrpContext->DeviceObject;
- IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
-
- //
- // This request is not allowed on the main device object
- //
- if (IsExt2FsDevice(DeviceObject)) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
- ASSERT(Vcb != NULL);
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
-
- ExAcquireResourceExclusiveLite(
- &Vcb->MainResource,
- TRUE );
- VcbResourceAcquired = TRUE;
-
- Status = Ext2UnlockVcb(Vcb, IrpSp->FileObject);
-
- } __finally {
-
- if (VcbResourceAcquired) {
- ExReleaseResourceLite(&Vcb->MainResource);
- }
-
- if (!IrpContext->ExceptionInProgress) {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
-
- return Status;
-}
-
-
-NTSTATUS
-Ext2InvalidateVolumes ( IN PEXT2_IRP_CONTEXT IrpContext )
-{
- NTSTATUS Status;
- PIRP Irp;
- PIO_STACK_LOCATION IrpSp;
-
- PVPB NewVpb = NULL;
- HANDLE Handle;
- PLIST_ENTRY ListEntry;
-
- ULONG InputLength = 0;
- PFILE_OBJECT FileObject;
- PDEVICE_OBJECT DeviceObject;
- BOOLEAN GlobalResourceAcquired = FALSE;
-
- LUID Privilege = {SE_TCB_PRIVILEGE, 0};
-
- __try {
-
- Irp = IrpContext->Irp;
- IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
- if (!IsExt2FsDevice(IrpSp->DeviceObject)) {
- Status = STATUS_INVALID_DEVICE_REQUEST;
- __leave;
- }
-
- if (!SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode)) {
- Status = STATUS_PRIVILEGE_NOT_HELD;
- __leave;
- }
-
-
-#ifndef _GNU_NTIFS_
- InputLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
-#else
- InputLength = ((PEXTENDED_IO_STACK_LOCATION)(IrpSp))->
- Parameters.FileSystemControl.InputBufferLength;
-#endif
-
-#if defined(_WIN64)
- if (IoIs32bitProcess(Irp)) {
- if (InputLength != sizeof(UINT32)) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
- Handle = (HANDLE) LongToHandle( (*(PUINT32)Irp->AssociatedIrp.SystemBuffer) );
- } else
-#endif
- {
- if (InputLength != sizeof(HANDLE)) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
- Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
- }
-
- Status = ObReferenceObjectByHandle( Handle,
- 0,
- *IoFileObjectType,
- KernelMode,
- &FileObject,
- NULL );
-
- if (!NT_SUCCESS(Status)) {
- __leave;
- } else {
- DeviceObject = FileObject->DeviceObject;
- ObDereferenceObject(FileObject);
- }
-
- ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE);
- GlobalResourceAcquired = TRUE;
-
- ListEntry = Ext2Global->VcbList.Flink;
- while (ListEntry != &Ext2Global->VcbList) {
-
- PEXT2_VCB Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next);
- ListEntry = ListEntry->Flink;
-
- DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Vcb=%xh Vcb->Vpb=%xh "
- "Blink = %p &Vcb->Next = %p\n",
- Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next));
-
- if (Vcb->Vpb && (Vcb->Vpb->RealDevice == DeviceObject)) {
-
- DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Got Vcb=%xh Vcb->Vpb=%xh "
- "Blink = %p &Vcb->Next = %p\n",
- Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next));
- /* dismount the volume */
- Ext2CheckDismount(IrpContext, Vcb, FALSE);
- }
- }
-
- } __finally {
-
- if (GlobalResourceAcquired) {
- ExReleaseResourceLite(&Ext2Global->Resource);
- }
-
- if (!IrpContext->ExceptionInProgress) {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2AllowExtendedDasdIo(IN PEXT2_IRP_CONTEXT IrpContext)
-{
- PIO_STACK_LOCATION IrpSp;
- PEXT2_VCB Vcb;
- PEXT2_CCB Ccb;
- NTSTATUS status;
-
- IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
-
- Vcb = (PEXT2_VCB) IrpSp->FileObject->FsContext;
- Ccb = (PEXT2_CCB) IrpSp->FileObject->FsContext2;
-
- ASSERT(Vcb != NULL);
-
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
-
- ASSERT(IsMounted(Vcb));
-
- if (Ccb) {
- SetLongFlag(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO);
- status = STATUS_SUCCESS;
- } else {
- status = STATUS_INVALID_PARAMETER;
- }
-
- Ext2CompleteIrpContext(IrpContext, status);
- return status;
-}
-
-/*
- * Ext2OplockRequest
- *
- * oplock requests handler routine
- *
- * Arguments:
- * IrpContext: the ext2 irp context
- *
- * Return Value:
- * NTSTATUS: The return status for the operation
- *
- */
-
-NTSTATUS
-Ext2OplockRequest (
- IN PEXT2_IRP_CONTEXT IrpContext
-)
-{
- NTSTATUS Status;
-
- ULONG FsCtrlCode;
- PDEVICE_OBJECT DeviceObject;
- PFILE_OBJECT FileObject;
-
- PIRP Irp = NULL;
- PIO_STACK_LOCATION IrpSp;
- PEXTENDED_IO_STACK_LOCATION EIrpSp;
-
- PEXT2_VCB Vcb = NULL;
- PEXT2_FCB Fcb = NULL;
- PEXT2_CCB Ccb = NULL;
-
- ULONG OplockCount = 0;
-
- BOOLEAN VcbResourceAcquired = FALSE;
- BOOLEAN FcbResourceAcquired = FALSE;
-
- ASSERT(IrpContext);
-
- __try {
-
- Irp = IrpContext->Irp;
- ASSERT(Irp);
-
- IrpSp = IoGetCurrentIrpStackLocation(Irp);
- ASSERT(IrpSp);
- EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- DeviceObject = IrpContext->DeviceObject;
-
- //
- // This request is not allowed on the main device object
- //
- if (IsExt2FsDevice(DeviceObject)) {
- Status = STATUS_INVALID_DEVICE_REQUEST;
- __leave;
- }
-
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
-
- ASSERT(Vcb != NULL);
-
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
-
- ASSERT(IsMounted(Vcb));
-
- FileObject = IrpContext->FileObject;
-
- Fcb = (PEXT2_FCB) FileObject->FsContext;
-
- //
- // This request is not allowed on volumes
- //
-
- if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
- (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
-
- if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
- Status = STATUS_FILE_DELETED;
- __leave;
- }
-
- Ccb = (PEXT2_CCB) FileObject->FsContext2;
- if (Ccb == NULL) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
-
- ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
- (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
-
- FsCtrlCode = EIrpSp->Parameters.FileSystemControl.FsControlCode;
-
- switch (FsCtrlCode) {
-
- case FSCTL_REQUEST_OPLOCK_LEVEL_1:
- case FSCTL_REQUEST_OPLOCK_LEVEL_2:
- case FSCTL_REQUEST_BATCH_OPLOCK:
-
- VcbResourceAcquired =
- ExAcquireResourceSharedLite(
- &Vcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
-
- ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
-
- FcbResourceAcquired =
- ExAcquireResourceExclusiveLite (
- &Fcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
-
- if (FsCtrlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
- OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks(&Fcb->FileLockAnchor);
- } else {
- OplockCount = Fcb->OpenHandleCount;
- }
-
- break;
-
- case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
- case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
- case FSCTL_OPLOCK_BREAK_NOTIFY:
- case FSCTL_OPLOCK_BREAK_ACK_NO_2:
-
- FcbResourceAcquired =
- ExAcquireResourceSharedLite (
- &Fcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
-
- break;
-
- default:
-
- Ext2BugCheck(EXT2_BUGCHK_FSCTL, FsCtrlCode, 0, 0);
- }
-
-
- //
- // Call the FsRtl routine to grant/acknowledge oplock.
- //
-
- Status = FsRtlOplockFsctrl( &Fcb->Oplock,
- Irp,
- OplockCount );
-
- //
- // Set the flag indicating if Fast I/O is possible
- //
-
- Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
- IrpContext->Irp = NULL;
-
- } __finally {
-
- if (FcbResourceAcquired) {
- ExReleaseResourceLite(&Fcb->MainResource);
- }
-
- if (VcbResourceAcquired) {
- ExReleaseResourceLite(&Vcb->MainResource);
- }
-
- if (!AbnormalTermination()) {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2IsVolumeDirty (
- IN PEXT2_IRP_CONTEXT IrpContext
-)
-{
- NTSTATUS status = STATUS_SUCCESS;
- PIRP Irp;
- PEXTENDED_IO_STACK_LOCATION IrpSp;
- PULONG VolumeState;
-
- __try {
-
- Irp = IrpContext->Irp;
- IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
-
- //
- // Get a pointer to the output buffer. Look at the system buffer field in th
- // irp first. Then the Irp Mdl.
- //
-
- if (Irp->AssociatedIrp.SystemBuffer != NULL) {
-
- VolumeState = Irp->AssociatedIrp.SystemBuffer;
-
- } else if (Irp->MdlAddress != NULL) {
-
- VolumeState = MmGetSystemAddressForMdl( Irp->MdlAddress );
-
- } else {
-
- status = STATUS_INVALID_USER_BUFFER;
- __leave;
- }
-
- if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
- status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- *VolumeState = 0;
-
- } __finally {
-
- if (!IrpContext->ExceptionInProgress) {
- Ext2CompleteIrpContext(IrpContext, status);
- }
- }
-
- return status;
-}
-
-
-NTSTATUS
-Ext2QueryExtentMappings(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN PEXT2_FCB Fcb,
- IN PLARGE_INTEGER RequestVbn,
- OUT PLARGE_INTEGER * pMappedRuns
-)
-{
- PLARGE_INTEGER MappedRuns = NULL;
- PLARGE_INTEGER PartialRuns = NULL;
-
- PEXT2_EXTENT Chain = NULL;
- PEXT2_EXTENT Extent = NULL;
-
- LONGLONG Vbn = 0;
- ULONG Length = 0;
- ULONG i = 0;
-
- NTSTATUS Status = STATUS_SUCCESS;
-
- __try {
-
- /* now building all the request extents */
- while (Vbn < RequestVbn->QuadPart) {
-
- Length = 0x80000000; /* 2g bytes */
- if (RequestVbn->QuadPart < Vbn + Length) {
- Length = (ULONG)(RequestVbn->QuadPart - Vbn);
- }
-
- /* build extents for sub-range */
- Extent = NULL;
- Status = Ext2BuildExtents(
- IrpContext,
- Vcb,
- Fcb->Mcb,
- Vbn,
- Length,
- FALSE,
- &Extent);
-
- if (!NT_SUCCESS(Status)) {
- __leave;
- }
-
- if (Chain) {
- Ext2JointExtents(Chain, Extent);
- } else {
- Chain = Extent;
- }
-
- /* allocate extent array */
- PartialRuns = Ext2AllocatePool(
- NonPagedPool,
- (Ext2CountExtents(Chain) + 2) *
- (2 * sizeof(LARGE_INTEGER)),
- 'RE2E');
-
- if (PartialRuns == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- __leave;
- }
- RtlZeroMemory( PartialRuns,
- (Ext2CountExtents(Chain) + 2) *
- (2 * sizeof(LARGE_INTEGER)));
-
- if (MappedRuns) {
- RtlMoveMemory(PartialRuns,
- MappedRuns,
- i * 2 * sizeof(LARGE_INTEGER));
- Ext2FreePool(MappedRuns, 'RE2E');
- }
- MappedRuns = PartialRuns;
-
- /* walk all the Mcb runs in Extent */
- for (; Extent != NULL; Extent = Extent->Next) {
- MappedRuns[i*2 + 0].QuadPart = Vbn + Extent->Offset;
- MappedRuns[i*2 + 1].QuadPart = Extent->Lba;
- i = i+1;
- }
-
- Vbn = Vbn + Length;
- }
-
- *pMappedRuns = MappedRuns;
-
- } __finally {
-
- if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) {
- if (MappedRuns) {
- Ext2FreePool(MappedRuns, 'RE2E');
- }
- *pMappedRuns = NULL;
- }
-
- if (Chain) {
- Ext2DestroyExtentChain(Chain);
- }
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2QueryRetrievalPointers (
- IN PEXT2_IRP_CONTEXT IrpContext
-)
-{
- PIRP Irp = NULL;
- PIO_STACK_LOCATION IrpSp;
- PEXTENDED_IO_STACK_LOCATION EIrpSp;
-
- PDEVICE_OBJECT DeviceObject;
- PFILE_OBJECT FileObject;
-
- PEXT2_VCB Vcb = NULL;
- PEXT2_FCB Fcb = NULL;
- PEXT2_CCB Ccb = NULL;
-
- PLARGE_INTEGER RequestVbn;
- PLARGE_INTEGER * pMappedRuns;
-
- ULONG InputSize;
- ULONG OutputSize;
-
- NTSTATUS Status = STATUS_SUCCESS;
-
- BOOLEAN FcbResourceAcquired = FALSE;
-
- __try {
-
- ASSERT(IrpContext);
- Irp = IrpContext->Irp;
- ASSERT(Irp);
-
- IrpSp = IoGetCurrentIrpStackLocation(Irp);
- EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
- ASSERT(IrpSp);
-
- InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength;
- OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- DeviceObject = IrpContext->DeviceObject;
-
- DbgBreak();
-
- /* This request is not allowed on the main device object */
- if (IsExt2FsDevice(DeviceObject)) {
- Status = STATUS_INVALID_DEVICE_REQUEST;
- __leave;
- }
-
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
- ASSERT(Vcb != NULL);
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
- ASSERT(IsMounted(Vcb));
-
- FileObject = IrpContext->FileObject;
- Fcb = (PEXT2_FCB) FileObject->FsContext;
-
- /* check Fcb is valid or not */
- if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
- (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
- if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
- Status = STATUS_FILE_DELETED;
- __leave;
- }
-
- Ccb = (PEXT2_CCB) FileObject->FsContext2;
- if (Ccb == NULL) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
- (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
-
- /* Is requstor in kernel and Fcb a paging file ? */
- if (Irp->RequestorMode != KernelMode ||
- !IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) ||
- InputSize != sizeof(LARGE_INTEGER) ||
- OutputSize != sizeof(PVOID)) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- if (!ExAcquireResourceExclusiveLite (
- &Fcb->MainResource, Ext2CanIWait())) {
- Status = STATUS_PENDING;
- __leave;
- }
- FcbResourceAcquired = TRUE;
-
- RequestVbn = EIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
- pMappedRuns = Irp->UserBuffer;
-
- DbgBreak();
-
- /* request size beyonds whole file size */
- if (RequestVbn->QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
- Status = STATUS_END_OF_FILE;
- __leave;
- }
-
- Status = Ext2QueryExtentMappings(
- IrpContext,
- Vcb,
- Fcb,
- RequestVbn,
- pMappedRuns
- );
-
- } __finally {
-
- if (FcbResourceAcquired) {
- ExReleaseResourceLite(&Fcb->MainResource);
- }
-
- if (!AbnormalTermination()) {
- if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
- Status = Ext2QueueRequest(IrpContext);
- } else {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
- }
-
- return Status;
-}
-
-
-NTSTATUS
-Ext2GetRetrievalPointers (
- IN PEXT2_IRP_CONTEXT IrpContext
-)
-{
- PIRP Irp = NULL;
- PIO_STACK_LOCATION IrpSp;
- PEXTENDED_IO_STACK_LOCATION EIrpSp;
-
- PDEVICE_OBJECT DeviceObject;
- PFILE_OBJECT FileObject;
-
- PEXT2_VCB Vcb = NULL;
- PEXT2_FCB Fcb = NULL;
- PEXT2_CCB Ccb = NULL;
-
- PSTARTING_VCN_INPUT_BUFFER SVIB;
- PRETRIEVAL_POINTERS_BUFFER RPSB;
-
- PEXT2_EXTENT Chain = NULL;
- PEXT2_EXTENT Extent = NULL;
-
- LONGLONG Vbn = 0;
- ULONG Length = 0;
- ULONG i = 0;
-
- ULONG UsedSize = 0;
- ULONG InputSize;
- ULONG OutputSize;
-
- NTSTATUS Status = STATUS_SUCCESS;
-
- BOOLEAN FcbResourceAcquired = FALSE;
-
- __try {
-
- ASSERT(IrpContext);
- Irp = IrpContext->Irp;
- ASSERT(Irp);
-
- IrpSp = IoGetCurrentIrpStackLocation(Irp);
- EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
- ASSERT(IrpSp);
-
- InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength;
- OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- DeviceObject = IrpContext->DeviceObject;
-
- /* This request is not allowed on the main device object */
- if (IsExt2FsDevice(DeviceObject)) {
- Status = STATUS_INVALID_DEVICE_REQUEST;
- __leave;
- }
-
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
- ASSERT(Vcb != NULL);
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
- ASSERT(IsMounted(Vcb));
-
- FileObject = IrpContext->FileObject;
- Fcb = (PEXT2_FCB) FileObject->FsContext;
-
- /* check Fcb is valid or not */
- if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
- (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
-
- if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
- Status = STATUS_FILE_DELETED;
- __leave;
- }
-
- Ccb = (PEXT2_CCB) FileObject->FsContext2;
- if (Ccb == NULL) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
- (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
-
- if (InputSize < sizeof(STARTING_VCN_INPUT_BUFFER) ||
- OutputSize < sizeof(RETRIEVAL_POINTERS_BUFFER) ) {
- Status = STATUS_BUFFER_TOO_SMALL;
- __leave;
- }
-
- if (!ExAcquireResourceExclusiveLite (
- &Fcb->MainResource, Ext2CanIWait())) {
- Status = STATUS_PENDING;
- __leave;
- }
- FcbResourceAcquired = TRUE;
-
- SVIB = (PSTARTING_VCN_INPUT_BUFFER)
- EIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
- RPSB = (PRETRIEVAL_POINTERS_BUFFER) Ext2GetUserBuffer(Irp);
-
- /* probe user buffer */
-
- __try {
- if (Irp->RequestorMode != KernelMode) {
- ProbeForRead (SVIB, InputSize, sizeof(UCHAR));
- ProbeForWrite(RPSB, OutputSize, sizeof(UCHAR));
- }
- } __except(EXCEPTION_EXECUTE_HANDLER) {
- Status = STATUS_INVALID_USER_BUFFER;
- }
-
- if (!NT_SUCCESS(Status)) {
- __leave;
- }
-
- UsedSize = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0]);
-
- /* request size beyonds whole file size ? */
- DEBUG(DL_DBG, ("Ext2GetRetrievalPointers: Startin from Vbn: %I64xh\n",
- SVIB->StartingVcn.QuadPart));
- Vbn = (SVIB->StartingVcn.QuadPart << BLOCK_BITS);
- if (Vbn >= Fcb->Header.AllocationSize.QuadPart ) {
- Status = STATUS_END_OF_FILE;
- __leave;
- }
-
- /* now building all the request extents */
- while (Vbn < Fcb->Header.AllocationSize.QuadPart) {
-
- ASSERT(Chain == NULL);
- Length = 0x80000000; /* 2g bytes */
- if (Fcb->Header.AllocationSize.QuadPart < Vbn + Length) {
- Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - Vbn);
- }
-
- /* build extents for sub-range */
- Status = Ext2BuildExtents(
- IrpContext,
- Vcb,
- Fcb->Mcb,
- Vbn,
- Length,
- FALSE,
- &Chain);
-
- if (!NT_SUCCESS(Status)) {
- DbgBreak();
- __leave;
- }
-
- /* fill user buffer of RETRIEVAL_POINTERS_BUFFER */
- Extent = Chain;
- while (Extent) {
-
- DEBUG(DL_MAP, ("Ext2GetRetrievalPointers: %wZ %d Vbn = %I64xh Lbn = %I64xh\n",
- &Fcb->Mcb->FullName, i,
- ((Vbn + Extent->Offset) >> BLOCK_BITS),
- Extent->Lba));
-
- RPSB->Extents[i].Lcn.QuadPart = (Extent->Lba >> BLOCK_BITS);
- RPSB->Extents[i].NextVcn.QuadPart = ((Vbn + Extent->Offset + Extent->Length) >> BLOCK_BITS);
- if (i == 0) {
- RPSB->StartingVcn.QuadPart = ((Vbn + Extent->Offset) >> BLOCK_BITS);
- } else {
- ASSERT(RPSB->Extents[i-1].NextVcn.QuadPart == ((Vbn + Extent->Offset) >> BLOCK_BITS));
- }
- if (UsedSize + sizeof(RETRIEVAL_POINTERS_BUFFER) > OutputSize) {
- Status = STATUS_BUFFER_OVERFLOW;
- __leave;
- }
- UsedSize += sizeof(LARGE_INTEGER) * 2;
- Irp->IoStatus.Information = (ULONG_PTR)UsedSize;
- RPSB->ExtentCount = ++i;
- Extent = Extent->Next;
- }
-
- if (Chain) {
- Ext2DestroyExtentChain(Chain);
- Chain = NULL;
- }
-
- Vbn = Vbn + Length;
- }
-
-#if 0
- {
- NTSTATUS _s;
- ULONG _i = 0;
- LARGE_INTEGER RequestVbn = Fcb->Header.AllocationSize;
- PLARGE_INTEGER MappedRuns = NULL;
-
- _s = Ext2QueryExtentMappings(
- IrpContext,
- Vcb,
- Fcb,
- &RequestVbn,
- &MappedRuns
- );
- if (!NT_SUCCESS(_s) || NULL == MappedRuns) {
- DbgBreak();
- goto exit_to_get_rps;
- }
-
- while (MappedRuns[_i*2 + 0].QuadPart != 0 ||
- MappedRuns[_i*2 + 1].QuadPart != 0 ) {
- DEBUG(DL_MAP, ("Ext2QueryExtentMappings: %wZ %d Vbn = %I64xh Lbn = %I64xh\n",
- &Fcb->Mcb->FullName, _i,
- MappedRuns[_i*2 + 0].QuadPart,
- MappedRuns[_i*2 + 1].QuadPart));
- _i++;
- }
-
-exit_to_get_rps:
-
- if (MappedRuns) {
- Ext2FreePool(MappedRuns, 'RE2E');
- }
- }
-#endif
-
- } __finally {
-
- if (FcbResourceAcquired) {
- ExReleaseResourceLite(&Fcb->MainResource);
- }
-
- if (Chain) {
- Ext2DestroyExtentChain(Chain);
- }
-
- if (!AbnormalTermination()) {
- if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
- Status = Ext2QueueRequest(IrpContext);
- } else {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2GetRetrievalPointerBase (
- IN PEXT2_IRP_CONTEXT IrpContext
-)
-{
- PIRP Irp = NULL;
- PIO_STACK_LOCATION IrpSp;
- PEXTENDED_IO_STACK_LOCATION EIrpSp;
-
- PDEVICE_OBJECT DeviceObject;
- PFILE_OBJECT FileObject;
-
- PEXT2_VCB Vcb = NULL;
- PEXT2_FCB Fcb = NULL;
- PEXT2_CCB Ccb = NULL;
-
- PLARGE_INTEGER FileAreaOffset;
-
- ULONG OutputSize;
-
- NTSTATUS Status = STATUS_SUCCESS;
-
- BOOLEAN FcbResourceAcquired = FALSE;
-
- __try {
-
- ASSERT(IrpContext);
- Irp = IrpContext->Irp;
- ASSERT(Irp);
-
- IrpSp = IoGetCurrentIrpStackLocation(Irp);
- EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
- ASSERT(IrpSp);
-
- OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- DeviceObject = IrpContext->DeviceObject;
-
- /* This request is not allowed on the main device object */
- if (IsExt2FsDevice(DeviceObject)) {
- Status = STATUS_INVALID_DEVICE_REQUEST;
- __leave;
- }
-
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
- ASSERT(Vcb != NULL);
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
- ASSERT(IsMounted(Vcb));
-
- FileObject = IrpContext->FileObject;
- Fcb = (PEXT2_FCB) FileObject->FsContext;
-
- /* check Fcb is valid or not */
- if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
- (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
-
- if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
- Status = STATUS_FILE_DELETED;
- __leave;
- }
-
- Ccb = (PEXT2_CCB) FileObject->FsContext2;
- if (Ccb == NULL) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
-
- ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
- (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
-
- if (OutputSize < sizeof(LARGE_INTEGER)) {
- Status = STATUS_BUFFER_TOO_SMALL;
- __leave;
- }
-
- if (!ExAcquireResourceExclusiveLite (
- &Fcb->MainResource, Ext2CanIWait())) {
- Status = STATUS_PENDING;
- __leave;
- }
- FcbResourceAcquired = TRUE;
-
- FileAreaOffset = (PLARGE_INTEGER) Ext2GetUserBuffer(Irp);
-
- /* probe user buffer */
-
- __try {
- if (Irp->RequestorMode != KernelMode) {
- ProbeForWrite(FileAreaOffset, OutputSize, sizeof(UCHAR));
- }
-
- } __except(EXCEPTION_EXECUTE_HANDLER) {
-
- Status = STATUS_INVALID_USER_BUFFER;
- }
-
- if (!NT_SUCCESS(Status)) {
- __leave;
- }
-
- DEBUG(DL_DBG, ("Ext2GetRetrievalPointerBase: FileAreaOffset is 0.\n"));
-
- FileAreaOffset->QuadPart = 0; // sector offset to the first allocatable unit on the filesystem
-
- Irp->IoStatus.Information = sizeof(LARGE_INTEGER);
-
- } __finally {
-
- if (FcbResourceAcquired) {
- ExReleaseResourceLite(&Fcb->MainResource);
- }
-
- if (!AbnormalTermination()) {
- if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
- Status = Ext2QueueRequest(IrpContext);
- } else {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2InspectReparseData(
- IN PREPARSE_DATA_BUFFER RDB,
- IN ULONG InputBufferLength
-)
-{
- NTSTATUS Status = STATUS_SUCCESS;
-
- if (!RDB) {
- Status = STATUS_INVALID_PARAMETER;
- goto out;
- }
-
- if (InputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
- Status = STATUS_BUFFER_OVERFLOW;
- goto out;
- }
-
- if (InputBufferLength < RDB->ReparseDataLength) {
- Status = STATUS_BUFFER_OVERFLOW;
- goto out;
- }
-
- if (RDB->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
- Status = STATUS_NOT_IMPLEMENTED;
- goto out;
- }
-
- if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
- + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset
- + RDB->SymbolicLinkReparseBuffer.SubstituteNameLength
- > (PUCHAR)RDB + InputBufferLength ) {
- Status = STATUS_BUFFER_OVERFLOW;
- goto out;
- }
-
- if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
- + RDB->SymbolicLinkReparseBuffer.PrintNameOffset
- + RDB->SymbolicLinkReparseBuffer.PrintNameLength
- > (PUCHAR)RDB + InputBufferLength) {
- Status = STATUS_BUFFER_OVERFLOW;
- goto out;
- }
-
- if (RDB->SymbolicLinkReparseBuffer.Flags != SYMLINK_FLAG_RELATIVE) {
- Status = STATUS_NOT_IMPLEMENTED;
- goto out;
- }
-
-out:
- return Status;
-}
-
-VOID
-Ext2InitializeReparseData(IN PREPARSE_DATA_BUFFER RDB, USHORT PathBufferLength)
-{
- ASSERT(FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset) ==
- REPARSE_DATA_BUFFER_HEADER_SIZE);
- RDB->ReparseTag = IO_REPARSE_TAG_SYMLINK;
- RDB->ReparseDataLength = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
- FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
- PathBufferLength * sizeof(WCHAR);
- RDB->Reserved = 0;
- RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset = PathBufferLength;
- RDB->SymbolicLinkReparseBuffer.SubstituteNameLength = PathBufferLength;
- RDB->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
- RDB->SymbolicLinkReparseBuffer.PrintNameLength = PathBufferLength;
- RDB->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
- RtlZeroMemory(&RDB->SymbolicLinkReparseBuffer.PathBuffer, PathBufferLength * 2);
-}
-
-NTSTATUS
-Ext2ReadSymlink (
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN PVOID Buffer,
- IN ULONG Size,
- OUT PULONG BytesRead
- )
-{
- return Ext2ReadInode ( IrpContext,
- Vcb,
- Mcb,
- 0,
- Buffer,
- Size,
- FALSE,
- BytesRead);
-}
-
-
-
-NTSTATUS
-Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- PIRP Irp = NULL;
- PIO_STACK_LOCATION IrpSp;
- PEXTENDED_IO_STACK_LOCATION EIrpSp;
-
- PDEVICE_OBJECT DeviceObject;
-
- PEXT2_VCB Vcb = NULL;
- PEXT2_CCB Ccb = NULL;
- PEXT2_MCB Mcb = NULL;
-
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
- BOOLEAN MainResourceAcquired = FALSE;
-
- PVOID OutputBuffer;
- ULONG OutputBufferLength;
- ULONG BytesRead = 0;
-
- PREPARSE_DATA_BUFFER RDB;
-
- UNICODE_STRING UniName;
- OEM_STRING OemName;
-
- PCHAR OemNameBuffer = NULL;
- int OemNameLength = 0, i;
-
- Ccb = IrpContext->Ccb;
- ASSERT(Ccb != NULL);
- ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
- (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
- DeviceObject = IrpContext->DeviceObject;
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
- Mcb = IrpContext->Fcb->Mcb;
- Irp = IrpContext->Irp;
- IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
- __try {
-
- if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
- !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
- Status = STATUS_NOT_A_REPARSE_POINT;
- __leave;
- }
-
- OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
- OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
-
- RDB = (PREPARSE_DATA_BUFFER)OutputBuffer;
- if (!RDB) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
- if (OutputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
- Status = STATUS_BUFFER_OVERFLOW;
- __leave;
- }
-
- OemNameLength = (ULONG)Mcb->Inode.i_size;
- if (OemNameLength > USHRT_MAX) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
- OemName.Length = (USHORT)OemNameLength;
- OemName.MaximumLength = OemNameLength + 1;
- OemNameBuffer = OemName.Buffer = Ext2AllocatePool(NonPagedPool,
- OemName.MaximumLength,
- 'NL2E');
- if (!OemNameBuffer) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- __leave;
- }
-
- Status = Ext2ReadSymlink(IrpContext,
- Vcb,
- Mcb,
- OemNameBuffer,
- OemNameLength,
- &BytesRead
- );
- OemName.Buffer[OemName.Length] = '\0';
- for (i = 0;i < OemName.Length;i++) {
- if (OemName.Buffer[i] == '/') {
- OemName.Buffer[i] = '\\';
- }
- }
-
- if (OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) > USHRT_MAX) {
- UniName.Length = USHRT_MAX;
- } else {
- UniName.Length = (USHORT)OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer);
- }
- UniName.MaximumLength = UniName.Length;
- UniName.Length = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName);
- Irp->IoStatus.Information = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + 2 * UniName.Length;
- if (UniName.MaximumLength < 2*UniName.Length) {
- Status = STATUS_BUFFER_TOO_SMALL;
- __leave;
- }
-
- Ext2InitializeReparseData(RDB, UniName.Length);
- UniName.Buffer = RDB->SymbolicLinkReparseBuffer.PathBuffer;
- /*
- (PWCHAR)((PUCHAR)&
- + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
- */
- Ext2OEMToUnicode(Vcb, &UniName, &OemName);
- RtlMoveMemory( (PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer +
- RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset,
- UniName.Buffer, UniName.Length);
-
- Status = STATUS_SUCCESS;
-
- } __finally {
-
- if (OemNameBuffer) {
- Ext2FreePool(OemNameBuffer, 'NL2E');
- }
-
- if (!AbnormalTermination()) {
- if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
- Status = Ext2QueueRequest(IrpContext);
- } else {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
- }
-
- return Status;
-}
-
-
-NTSTATUS
-Ext2WriteSymlink (
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN PVOID Buffer,
- IN ULONG Size,
- OUT PULONG BytesWritten
-)
-{
- NTSTATUS Status = STATUS_SUCCESS;
- PUCHAR Data = (PUCHAR)(&Mcb->Inode.i_block[0]);
-
- if (Size >= EXT2_LINKLEN_IN_INODE) {
-
- /* initialize inode i_block[] */
- if (0 == Mcb->Inode.i_blocks) {
- memset(Data, 0, EXT2_LINKLEN_IN_INODE);
- ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
- Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
- }
-
- Status = Ext2WriteInode(IrpContext, Vcb, Mcb,
- 0, Buffer, Size,
- FALSE, BytesWritten);
- if (!NT_SUCCESS(Status)) {
- goto out;
- }
-
- } else {
-
- /* free inode blocks before writing in line */
- if (Mcb->Inode.i_blocks) {
- LARGE_INTEGER Zero = {0, 0};
- Ext2TruncateFile(IrpContext, Vcb, Mcb, &Zero);
- }
-
- ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
- memset(Data, 0, EXT2_LINKLEN_IN_INODE);
- RtlCopyMemory(Data, Buffer, Size);
- }
-
- Mcb->Inode.i_size = Size;
- Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
-
- if (BytesWritten) {
- *BytesWritten = Size;
- }
-
-out:
- return Status;
-}
-
-NTSTATUS
-Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- PIRP Irp = NULL;
- PIO_STACK_LOCATION IrpSp;
-
- PDEVICE_OBJECT DeviceObject;
-
- PEXT2_VCB Vcb = NULL;
- PEXT2_FCB Fcb = NULL;
- PEXT2_CCB Ccb = NULL;
- PEXT2_MCB Mcb = NULL;
-
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
-
- PVOID InputBuffer;
- ULONG InputBufferLength;
- ULONG BytesWritten = 0;
-
- PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
- PEXT2_MCB ParentMcb = NULL;
-
- PREPARSE_DATA_BUFFER RDB;
-
- UNICODE_STRING UniName;
- OEM_STRING OemName;
-
- PCHAR OemNameBuffer = NULL;
- int OemNameLength = 0, i;
-
- BOOLEAN MainResourceAcquired = FALSE;
- BOOLEAN FcbLockAcquired = FALSE;
-
- __try {
-
- Ccb = IrpContext->Ccb;
- ASSERT(Ccb != NULL);
- ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
- (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
- DeviceObject = IrpContext->DeviceObject;
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
- Fcb = IrpContext->Fcb;
- Mcb = Fcb->Mcb;
- Irp = IrpContext->Irp;
- IrpSp = IoGetCurrentIrpStackLocation(Irp);
-
- ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
- FcbLockAcquired = TRUE;
-
- ParentMcb = Mcb->Parent;
- ParentDcb = ParentMcb->Fcb;
- if (ParentDcb == NULL) {
- ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
- }
- if (ParentDcb) {
- Ext2ReferXcb(&ParentDcb->ReferenceCount);
- }
-
- if (!Mcb)
- __leave;
-
- if (FcbLockAcquired) {
- ExReleaseResourceLite(&Vcb->FcbLock);
- FcbLockAcquired = FALSE;
- }
-
- if (!ExAcquireResourceSharedLite(
- &Fcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
- Status = STATUS_PENDING;
- __leave;
- }
- MainResourceAcquired = TRUE;
-
- InputBuffer = Irp->AssociatedIrp.SystemBuffer;
- InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
-
- RDB = (PREPARSE_DATA_BUFFER)InputBuffer;
- Status = Ext2InspectReparseData(RDB, InputBufferLength);
- if (!NT_SUCCESS(Status)) {
- __leave;
- }
-
- UniName.Length = RDB->SymbolicLinkReparseBuffer.SubstituteNameLength;
- UniName.MaximumLength = UniName.Length;
- UniName.Buffer =
- (PWCHAR)((PUCHAR)&RDB->SymbolicLinkReparseBuffer.PathBuffer
- + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
-
- OemNameLength = Ext2UnicodeToOEMSize(Vcb, &UniName);
- if (OemNameLength > USHRT_MAX) {
- Status = STATUS_INVALID_PARAMETER;
- __leave;
- }
- OemName.Length = (USHORT)OemNameLength;
- OemName.MaximumLength = OemNameLength + 1;
- OemNameBuffer = OemName.Buffer = Ext2AllocatePool(PagedPool,
- OemName.MaximumLength,
- 'NL2E');
- if (!OemNameBuffer) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- __leave;
- }
-
- Ext2UnicodeToOEM(Vcb, &OemName, &UniName);
- OemName.Buffer[OemName.Length] = '\0';
- for (i = 0;i < OemName.Length;i++) {
- if (OemName.Buffer[i] == '\\') {
- OemName.Buffer[i] = '/';
- }
- }
-
- /* free all data blocks of the inode (to be set as symlink) */
- {
- LARGE_INTEGER zero = {0};
- Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &zero);
- }
-
- /* decrease dir count of group desc and vcb stat */
- if (S_ISDIR(Mcb->Inode.i_mode)) {
-
- ULONG group = (Mcb->Inode.i_ino - 1) / INODES_PER_GROUP;
- Ext2UpdateGroupDirStat(IrpContext, Vcb, group);
-
- /* drop extra reference for dir inode */
- ext3_dec_count(&Mcb->Inode);
- }
-
- /* overwrite inode mode as type SYMLINK */
- Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
- SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
-
- Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
- OemNameLength, &BytesWritten);
- if (NT_SUCCESS(Status)) {
- Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb,
- S_IFLNK | S_IRWXUGO);
- }
-
- } __finally {
-
- if (FcbLockAcquired) {
- ExReleaseResourceLite(&Vcb->FcbLock);
- FcbLockAcquired = FALSE;
- }
-
- if (MainResourceAcquired) {
- ExReleaseResourceLite(&Fcb->MainResource);
- }
-
- if (OemNameBuffer) {
- Ext2FreePool(OemNameBuffer, 'NL2E');
- }
-
- if (NT_SUCCESS(Status)) {
- Ext2NotifyReportChange(
- IrpContext,
- Vcb,
- Mcb,
- FILE_NOTIFY_CHANGE_ATTRIBUTES,
- FILE_ACTION_MODIFIED );
- }
-
- if (!AbnormalTermination()) {
- if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
- Status = Ext2QueueRequest(IrpContext);
- } else {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
-
- if (ParentDcb) {
- Ext2ReleaseFcb(ParentDcb);
- }
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2TruncateSymlink(
- PEXT2_IRP_CONTEXT IrpContext,
- PEXT2_VCB Vcb,
- PEXT2_MCB Mcb,
- ULONG Size
- )
-{
- NTSTATUS status = STATUS_SUCCESS;
- PUCHAR data = (PUCHAR)&Mcb->Inode.i_block;
- ULONG len = (ULONG)Mcb->Inode.i_size;
- LARGE_INTEGER NewSize;
-
- if (len < EXT2_LINKLEN_IN_INODE && !Mcb->Inode.i_blocks) {
-
- RtlZeroMemory(data + Size, EXT2_LINKLEN_IN_INODE - Size);
- Mcb->Inode.i_size = Size;
- Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
-
- } else {
- NewSize.QuadPart = Size;
- status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
- if (!NT_SUCCESS(status)) {
- goto out;
- }
- }
-
-out:
- return status;
-}
-
-
-/* FIXME: We can only handle one reparse point right now. */
-NTSTATUS
-Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- PIRP Irp = NULL;
-
- PDEVICE_OBJECT DeviceObject;
-
- PEXT2_VCB Vcb = NULL;
- PEXT2_FCB Fcb = NULL;
- PEXT2_CCB Ccb = NULL;
- PEXT2_MCB Mcb = NULL;
-
- PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
- PEXT2_MCB ParentMcb = NULL;
-
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
-
- BOOLEAN FcbLockAcquired = FALSE;
- BOOLEAN MainResourceAcquired = FALSE;
-
-
- __try {
-
- Ccb = IrpContext->Ccb;
- ASSERT(Ccb != NULL);
- ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
- (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
- DeviceObject = IrpContext->DeviceObject;
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
- Mcb = IrpContext->Fcb->Mcb;
- Irp = IrpContext->Irp;
-
- ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
- FcbLockAcquired = TRUE;
-
- ParentMcb = Mcb->Parent;
- ParentDcb = ParentMcb->Fcb;
- if (ParentDcb == NULL) {
- ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
- }
- if (ParentDcb) {
- Ext2ReferXcb(&ParentDcb->ReferenceCount);
- }
-
- if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
- !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
- Status = STATUS_NOT_A_REPARSE_POINT;
- __leave;
- }
-
- Fcb = Ext2AllocateFcb (Vcb, Mcb);
- if (Fcb) {
- Ext2ReferXcb(&Fcb->ReferenceCount);
- } else {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- __leave;
- }
-
- if (FcbLockAcquired) {
- ExReleaseResourceLite(&Vcb->FcbLock);
- FcbLockAcquired = FALSE;
- }
-
- if (!ExAcquireResourceSharedLite(
- &Fcb->MainResource,
- IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
- Status = STATUS_PENDING;
- __leave;
- }
- MainResourceAcquired = TRUE;
-
- Status = Ext2TruncateSymlink(IrpContext, Vcb, Mcb, 0);
- if (!NT_SUCCESS(Status)) {
- __leave;
- }
-
- /* inode is to be removed */
- SetFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE);
-
- } __finally {
-
- if (FcbLockAcquired) {
- ExReleaseResourceLite(&Vcb->FcbLock);
- }
-
- if (MainResourceAcquired) {
- ExReleaseResourceLite(&Fcb->MainResource);
- }
-
- if (NT_SUCCESS(Status)) {
- Ext2NotifyReportChange(
- IrpContext,
- Vcb,
- Mcb,
- FILE_NOTIFY_CHANGE_ATTRIBUTES,
- FILE_ACTION_MODIFIED );
-
- }
-
- if (!AbnormalTermination()) {
- if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
- Status = Ext2QueueRequest(IrpContext);
- } else {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
-
- if (ParentDcb) {
- Ext2ReleaseFcb(ParentDcb);
- }
-
- if (Fcb) {
- Ext2ReleaseFcb(Fcb);
- }
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- PIRP Irp;
- PIO_STACK_LOCATION IoStackLocation;
- ULONG FsControlCode;
- NTSTATUS Status;
-
- ASSERT(IrpContext);
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- Irp = IrpContext->Irp;
- IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
-
-#ifndef _GNU_NTIFS_
- FsControlCode =
- IoStackLocation->Parameters.FileSystemControl.FsControlCode;
-#else
- FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)
- IoStackLocation)->Parameters.FileSystemControl.FsControlCode;
-#endif
-
- switch (FsControlCode) {
-
- case FSCTL_GET_REPARSE_POINT:
- Status = Ext2GetReparsePoint(IrpContext);
- break;
-
- case FSCTL_SET_REPARSE_POINT:
- Status = Ext2SetReparsePoint(IrpContext);
- break;
-
- case FSCTL_DELETE_REPARSE_POINT:
- Status = Ext2DeleteReparsePoint(IrpContext);
- break;
-
- case FSCTL_LOCK_VOLUME:
- Status = Ext2LockVolume(IrpContext);
- break;
-
- case FSCTL_UNLOCK_VOLUME:
- Status = Ext2UnlockVolume(IrpContext);
- break;
-
- case FSCTL_DISMOUNT_VOLUME:
- Status = Ext2DismountVolume(IrpContext);
- break;
-
- case FSCTL_IS_VOLUME_MOUNTED:
- Status = Ext2IsVolumeMounted(IrpContext);
- break;
-
- case FSCTL_INVALIDATE_VOLUMES:
- Status = Ext2InvalidateVolumes(IrpContext);
- break;
-
-#if (_WIN32_WINNT >= 0x0500)
- case FSCTL_ALLOW_EXTENDED_DASD_IO:
- Status = Ext2AllowExtendedDasdIo(IrpContext);
- break;
-#endif //(_WIN32_WINNT >= 0x0500)
-
- case FSCTL_REQUEST_OPLOCK_LEVEL_1:
- case FSCTL_REQUEST_OPLOCK_LEVEL_2:
- case FSCTL_REQUEST_BATCH_OPLOCK:
- case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
- case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
- case FSCTL_OPLOCK_BREAK_NOTIFY:
- case FSCTL_OPLOCK_BREAK_ACK_NO_2:
-
- Status = Ext2OplockRequest(IrpContext);
- break;
-
- case FSCTL_IS_VOLUME_DIRTY:
- Status = Ext2IsVolumeDirty(IrpContext);
- break;
-
- case FSCTL_QUERY_RETRIEVAL_POINTERS:
- Status = Ext2QueryRetrievalPointers(IrpContext);
- break;
-
- case FSCTL_GET_RETRIEVAL_POINTERS:
- Status = Ext2GetRetrievalPointers(IrpContext);
- break;
-
- case FSCTL_GET_RETRIEVAL_POINTER_BASE:
- Status = Ext2GetRetrievalPointerBase(IrpContext);
- break;
-
- default:
-
- DEBUG(DL_INF, ( "Ext2UserFsRequest: Invalid User Request: %xh.\n", FsControlCode));
- Status = STATUS_INVALID_DEVICE_REQUEST;
-
- Ext2CompleteIrpContext(IrpContext, Status);
- }
-
- return Status;
-}
-
-BOOLEAN
-Ext2IsMediaWriteProtected (
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PDEVICE_OBJECT TargetDevice
-)
-{
- PIRP Irp;
- KEVENT Event;
- NTSTATUS Status;
- IO_STATUS_BLOCK IoStatus;
-
- KeInitializeEvent(&Event, NotificationEvent, FALSE);
-
- Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE,
- TargetDevice,
- NULL,
- 0,
- NULL,
- 0,
- FALSE,
- &Event,
- &IoStatus );
-
- if (Irp == NULL) {
- return FALSE;
- }
-
- SetFlag(IoGetNextIrpStackLocation(Irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME);
-
- Status = IoCallDriver(TargetDevice, Irp);
-
- if (Status == STATUS_PENDING) {
-
- (VOID) KeWaitForSingleObject( &Event,
- Executive,
- KernelMode,
- FALSE,
- (PLARGE_INTEGER)NULL );
-
- Status = IoStatus.Status;
- }
-
- return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED);
-}
-
-NTSTATUS
-Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- PDEVICE_OBJECT MainDeviceObject;
- BOOLEAN GlobalDataResourceAcquired = FALSE;
- PIRP Irp;
- PIO_STACK_LOCATION IoStackLocation;
- PDEVICE_OBJECT TargetDeviceObject;
- NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
- PDEVICE_OBJECT VolumeDeviceObject = NULL;
- PEXT2_VCB Vcb = NULL, OldVcb = NULL;
- PVPB OldVpb = NULL, Vpb = NULL;
- PEXT2_SUPER_BLOCK Ext2Sb = NULL;
- ULONG dwBytes;
- DISK_GEOMETRY DiskGeometry;
-
- __try {
-
- ASSERT(IrpContext != NULL);
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- MainDeviceObject = IrpContext->DeviceObject;
-
- //
- // Make sure we can wait.
- //
-
- SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
-
- //
- // This request is only allowed on the main device object
- //
- if (!IsExt2FsDevice(MainDeviceObject)) {
- Status = STATUS_INVALID_DEVICE_REQUEST;
- __leave;
- }
-
- if (IsFlagOn(Ext2Global->Flags, EXT2_UNLOAD_PENDING)) {
- Status = STATUS_UNRECOGNIZED_VOLUME;
- __leave;
- }
-
-#if 0
- if (IrpContext->RealDevice->Size >= sizeof(ULONG) + sizeof(DEVICE_OBJECT) &&
- *((PULONG)IrpContext->RealDevice->DeviceExtension) == 'DSSA') {
- } else {
- Status = STATUS_UNRECOGNIZED_VOLUME;
- __leave;
- }
-#endif
-
- Irp = IrpContext->Irp;
- IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
- TargetDeviceObject =
- IoStackLocation->Parameters.MountVolume.DeviceObject;
-
- dwBytes = sizeof(DISK_GEOMETRY);
- Status = Ext2DiskIoControl(
- TargetDeviceObject,
- IOCTL_DISK_GET_DRIVE_GEOMETRY,
- NULL,
- 0,
- &DiskGeometry,
- &dwBytes );
-
- if (!NT_SUCCESS(Status)) {
- __leave;
- }
-
- Status = IoCreateDevice(
- MainDeviceObject->DriverObject,
- sizeof(EXT2_VCB),
- NULL,
- FILE_DEVICE_DISK_FILE_SYSTEM,
- 0,
- FALSE,
- &VolumeDeviceObject );
-
- if (!NT_SUCCESS(Status)) {
- __leave;
- }
- INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
-
-#ifdef _PNP_POWER_
- /* don't care about power management requests */
- VolumeDeviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
-#endif
-
- VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
- ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
-
-/*
- These are for buffer-address alignment requirements.
- Never do this check, unless you want fail user requests :)
-
- if (TargetDeviceObject->AlignmentRequirement >
- VolumeDeviceObject->AlignmentRequirement) {
-
- VolumeDeviceObject->AlignmentRequirement =
- TargetDeviceObject->AlignmentRequirement;
- }
-
- if (DiskGeometry.BytesPerSector - 1 >
- VolumeDeviceObject->AlignmentRequirement) {
- VolumeDeviceObject->AlignmentRequirement =
- DiskGeometry.BytesPerSector - 1;
- TargetDeviceObject->AlignmentRequirement =
- DiskGeometry.BytesPerSector - 1;
- }
-*/
- (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
- VolumeDeviceObject;
- Vpb = IoStackLocation->Parameters.MountVolume.Vpb;
-
- Vcb = (PEXT2_VCB) VolumeDeviceObject->DeviceExtension;
-
- RtlZeroMemory(Vcb, sizeof(EXT2_VCB));
- Vcb->Identifier.Type = EXT2VCB;
- Vcb->Identifier.Size = sizeof(EXT2_VCB);
- Vcb->TargetDeviceObject = TargetDeviceObject;
- Vcb->DiskGeometry = DiskGeometry;
- InitializeListHead(&Vcb->Next);
-
- Status = Ext2LoadSuper(Vcb, FALSE, &Ext2Sb);
- if (!NT_SUCCESS(Status)) {
- Vcb = NULL;
- Status = STATUS_UNRECOGNIZED_VOLUME;
- __leave;
- }
- ASSERT (NULL != Ext2Sb);
-
- /* check Linux Ext2/Ext3 volume magic */
- if (Ext2Sb->s_magic == EXT2_SUPER_MAGIC) {
- DEBUG(DL_INF, ( "Volume of ext2 file system is found.\n"));
- } else {
- Status = STATUS_UNRECOGNIZED_VOLUME;
- Vcb = NULL;
- __leave;
- }
-
- DEBUG(DL_DBG, ("Ext2MountVolume: DevObject=%p Vcb=%p\n", VolumeDeviceObject, Vcb));
-
- /* initialize Vcb structure */
- Status = Ext2InitializeVcb( IrpContext, Vcb, Ext2Sb,
- TargetDeviceObject,
- VolumeDeviceObject, Vpb);
-
- if (NT_SUCCESS(Status)) {
-
- PLIST_ENTRY List;
-
- ExAcquireResourceExclusiveLite(&(Ext2Global->Resource), TRUE);
- GlobalDataResourceAcquired = TRUE;
-
- for (List = Ext2Global->VcbList.Flink;
- List != &Ext2Global->VcbList;
- List = List->Flink) {
-
- OldVcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
- OldVpb = OldVcb->Vpb;
-
- /* in case we are already in the queue, should not happen */
- if (OldVpb == Vpb) {
- continue;
- }
-
- if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
- (!IsMounted(OldVcb)) && (IsFlagOn(OldVcb->Flags, VCB_NEW_VPB)) &&
- (OldVpb->RealDevice == TargetDeviceObject) &&
- (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
- (RtlEqualMemory(&OldVpb->VolumeLabel[0],
- &Vpb->VolumeLabel[0],
- Vpb->VolumeLabelLength)) &&
- (RtlEqualMemory(&OldVcb->SuperBlock->s_uuid[0],
- &Vcb->SuperBlock->s_uuid[0], 16)) ) {
- ClearFlag(OldVcb->Flags, VCB_MOUNTED);
- }
- }
-
- SetLongFlag(Vcb->Flags, VCB_MOUNTED);
- SetFlag(Vcb->Vpb->Flags, VPB_MOUNTED);
- Ext2InsertVcb(Vcb);
- Vcb = NULL;
- Vpb = NULL;
- ObDereferenceObject(TargetDeviceObject);
-
- } else {
-
- Vcb = NULL;
- }
-
- } __finally {
-
- if (GlobalDataResourceAcquired) {
- ExReleaseResourceLite(&Ext2Global->Resource);
- }
-
- if (!NT_SUCCESS(Status)) {
-
- if (!NT_SUCCESS(Status)) {
- if ( Vpb != NULL ) {
- Vpb->DeviceObject = NULL;
- }
- }
-
- if (Vcb) {
- Ext2DestroyVcb(Vcb);
- } else {
- if (Ext2Sb) {
- Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
- }
- if (VolumeDeviceObject) {
- IoDeleteDevice(VolumeDeviceObject);
- DEC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
- }
- }
- }
-
- if (!IrpContext->ExceptionInProgress) {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
-
- return Status;
-}
-
-VOID
-Ext2VerifyVcb (IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb )
-{
- NTSTATUS Status = STATUS_SUCCESS;
-
- BOOLEAN bVerify = FALSE;
- ULONG ChangeCount = 0;
- ULONG dwBytes;
-
- PIRP Irp;
- PEXTENDED_IO_STACK_LOCATION IrpSp;
-
- __try {
-
- ASSERT(IrpContext != NULL);
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- Irp = IrpContext->Irp;
- IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
-
- bVerify = IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
-
- if ( (IsFlagOn(Vcb->Flags, VCB_REMOVABLE_MEDIA) ||
- IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) && !bVerify ) {
-
- dwBytes = sizeof(ULONG);
- Status = Ext2DiskIoControl(
- Vcb->TargetDeviceObject,
- IOCTL_DISK_CHECK_VERIFY,
- NULL,
- 0,
- &ChangeCount,
- &dwBytes );
-
- if ( STATUS_VERIFY_REQUIRED == Status ||
- STATUS_DEVICE_NOT_READY == Status ||
- STATUS_NO_MEDIA_IN_DEVICE == Status ||
- (NT_SUCCESS(Status) &&
- (ChangeCount != Vcb->ChangeCount))) {
-
- KIRQL Irql;
-
- IoAcquireVpbSpinLock(&Irql);
- if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
- SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
- }
- IoReleaseVpbSpinLock(Irql);
-
- } else {
-
- if (!NT_SUCCESS(Status)) {
- Ext2NormalizeAndRaiseStatus(IrpContext, Status);
- }
- }
- }
-
- if ( IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
- IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
- Ext2NormalizeAndRaiseStatus ( IrpContext,
- STATUS_VERIFY_REQUIRED );
- }
-
- if (IsMounted(Vcb)) {
-
- if ( (IrpContext->MajorFunction == IRP_MJ_WRITE) ||
- (IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) ||
- (IrpContext->MajorFunction == IRP_MJ_SET_EA) ||
- (IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) ||
- (IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) ||
- (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
- IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST &&
- IrpSp->Parameters.FileSystemControl.FsControlCode ==
- FSCTL_MARK_VOLUME_DIRTY)) {
-
- if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
-
- KIRQL Irql;
-
- IoAcquireVpbSpinLock(&Irql);
- if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
- SetFlag (Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
- }
- IoReleaseVpbSpinLock(Irql);
-
- IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
-
- Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
- }
- }
- }
-
- } __finally {
-
- }
-
-}
-
-
-NTSTATUS
-Ext2VerifyVolume (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- PDEVICE_OBJECT DeviceObject;
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_SUPER_BLOCK ext2_sb = NULL;
- PEXT2_VCB Vcb = NULL;
- BOOLEAN VcbResourceAcquired = FALSE;
- PIRP Irp;
- ULONG ChangeCount = 0;
- ULONG dwBytes;
-
- __try {
-
- ASSERT(IrpContext != NULL);
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- DeviceObject = IrpContext->DeviceObject;
- //
- // This request is not allowed on the main device object
- //
- if (IsExt2FsDevice(DeviceObject)) {
- Status = STATUS_INVALID_DEVICE_REQUEST;
- __leave;
- }
-
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
- ASSERT(Vcb != NULL);
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
-
- VcbResourceAcquired =
- ExAcquireResourceExclusiveLite(
- &Vcb->MainResource,
- TRUE );
-
- if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) {
- Status = STATUS_SUCCESS;
- __leave;
- }
-
- if (!IsMounted(Vcb)) {
- Status = STATUS_WRONG_VOLUME;
- __leave;
- }
-
- dwBytes = sizeof(ULONG);
- Status = Ext2DiskIoControl(
- Vcb->TargetDeviceObject,
- IOCTL_DISK_CHECK_VERIFY,
- NULL,
- 0,
- &ChangeCount,
- &dwBytes );
-
-
- if (!NT_SUCCESS(Status)) {
- Status = STATUS_WRONG_VOLUME;
- __leave;
- } else {
- Vcb->ChangeCount = ChangeCount;
- }
-
- Irp = IrpContext->Irp;
-
- Status = Ext2LoadSuper(Vcb, TRUE, &ext2_sb);
-
- if (!NT_SUCCESS(Status)) {
- __leave;
- }
-
- ASSERT(NULL != ext2_sb);
- if ((ext2_sb->s_magic == EXT2_SUPER_MAGIC) &&
- (memcmp(ext2_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) &&
- (memcmp(ext2_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)) {
-
- ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
-
- if (Ext2IsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
- SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
- } else {
- ClearLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
- }
-
- DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify succeeded.\n"));
-
- } else {
-
- Status = STATUS_WRONG_VOLUME;
- Ext2PurgeVolume(Vcb, FALSE);
-
- SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
- ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
-
- DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify failed.\n"));
- }
-
- } __finally {
-
- if (ext2_sb)
- Ext2FreePool(ext2_sb, EXT2_SB_MAGIC);
-
- if (VcbResourceAcquired) {
- ExReleaseResourceLite(&Vcb->MainResource);
- }
-
- if (!IrpContext->ExceptionInProgress) {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
-
- return Status;
-}
-
-
-NTSTATUS
-Ext2IsVolumeMounted (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- PDEVICE_OBJECT DeviceObject;
- PEXT2_VCB Vcb = 0;
- NTSTATUS Status = STATUS_SUCCESS;
-
- ASSERT(IrpContext);
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
-
- DeviceObject = IrpContext->DeviceObject;
-
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
-
- ASSERT(IsMounted(Vcb));
-
- Ext2VerifyVcb (IrpContext, Vcb);
-
- Ext2CompleteIrpContext(IrpContext, Status);
-
- return Status;
-}
-
-
-NTSTATUS
-Ext2DismountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- PDEVICE_OBJECT DeviceObject;
- NTSTATUS Status = STATUS_UNSUCCESSFUL;
- PEXT2_VCB Vcb = NULL;
- BOOLEAN VcbResourceAcquired = FALSE;
-
- __try {
-
- ASSERT(IrpContext != NULL);
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- DeviceObject = IrpContext->DeviceObject;
-
- //
- // This request is not allowed on the main device object
- //
- if (IsExt2FsDevice(DeviceObject)) {
- Status = STATUS_INVALID_DEVICE_REQUEST;
- __leave;
- }
-
- Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
-
- ASSERT(Vcb != NULL);
-
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
-
- ASSERT(IsMounted(Vcb));
-
- ExAcquireResourceExclusiveLite(
- &Vcb->MainResource,
- TRUE );
-
- VcbResourceAcquired = TRUE;
-
- if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
- Status = STATUS_VOLUME_DISMOUNTED;
- __leave;
- }
-
- Ext2FlushFiles(IrpContext, Vcb, FALSE);
- Ext2FlushVolume(IrpContext, Vcb, FALSE);
-
- ExReleaseResourceLite(&Vcb->MainResource);
- VcbResourceAcquired = FALSE;
-
- Ext2PurgeVolume(Vcb, TRUE);
- Ext2CheckDismount(IrpContext, Vcb, TRUE);
-
- DEBUG(DL_INF, ( "Ext2Dismount: Volume dismount pending.\n"));
- Status = STATUS_SUCCESS;
-
- } __finally {
-
- if (VcbResourceAcquired) {
- ExReleaseResourceLite(&Vcb->MainResource);
- }
-
- if (!IrpContext->ExceptionInProgress) {
- Ext2CompleteIrpContext(IrpContext, Status);
- }
- }
-
- return Status;
-}
-
-BOOLEAN
-Ext2CheckDismount (
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN BOOLEAN bForce )
-{
- KIRQL Irql;
- PVPB Vpb = Vcb->Vpb, NewVpb = NULL;
- BOOLEAN bDeleted = FALSE, bTearDown = FALSE;
- ULONG UnCleanCount = 0;
-
- NewVpb = ExAllocatePoolWithTag(NonPagedPool, VPB_SIZE, TAG_VPB);
- if (NewVpb == NULL) {
- DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n"));
- return FALSE;
- }
- DEBUG(DL_DBG, ("Ext2CheckDismount: NewVpb allocated: %p\n", NewVpb));
- INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
- memset(NewVpb, '_', VPB_SIZE);
- RtlZeroMemory(NewVpb, sizeof(VPB));
-
- ExAcquireResourceExclusiveLite(
- &Ext2Global->Resource, TRUE );
-
- ExAcquireResourceExclusiveLite(
- &Vcb->MainResource, TRUE );
-
- if (IrpContext &&
- IrpContext->MajorFunction == IRP_MJ_CREATE &&
- IrpContext->RealDevice == Vcb->RealDevice) {
- UnCleanCount = 2;
- } else {
- UnCleanCount = 1;
- }
-
- IoAcquireVpbSpinLock (&Irql);
-
- DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n",
- Vpb, Vpb->ReferenceCount, Vpb->RealDevice));
-
- if (Vpb->ReferenceCount <= UnCleanCount) {
-
- if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
-
- ClearFlag(Vpb->Flags, VPB_MOUNTED);
- ClearFlag(Vpb->Flags, VPB_LOCKED);
-
- if ((Vcb->RealDevice != Vpb->RealDevice) &&
- (Vcb->RealDevice->Vpb == Vpb)) {
- SetFlag(Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING);
- SetFlag(Vpb->Flags, VPB_PERSISTENT );
- }
-
- Ext2RemoveVcb(Vcb);
- SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
- }
-
- if (Vpb->ReferenceCount) {
- bTearDown = TRUE;
- } else {
- bDeleted = TRUE;
- Vpb->DeviceObject = NULL;
- }
-
- DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb: %p bDeleted=%d bTearDown=%d\n",
- Vpb, bDeleted, bTearDown));
-
-
- } else if (bForce) {
-
- DEBUG(DL_DBG, ( "Ext2CheckDismount: New/Old Vpb %p/%p Realdevice = %p\n",
- NewVpb, Vcb->Vpb, Vpb->RealDevice));
-
- /* keep vpb president and later we'll free it */
- SetFlag(Vpb->Flags, VPB_PERSISTENT);
-
- Vcb->Vpb2 = Vcb->Vpb;
- NewVpb->Type = IO_TYPE_VPB;
- NewVpb->Size = sizeof(VPB);
- NewVpb->Flags = Vpb->Flags & VPB_REMOVE_PENDING;
- NewVpb->RealDevice = Vpb->RealDevice;
- NewVpb->RealDevice->Vpb = NewVpb;
- NewVpb = NULL;
- ClearFlag(Vpb->Flags, VPB_MOUNTED);
- SetLongFlag(Vcb->Flags, VCB_NEW_VPB);
- ClearLongFlag(Vcb->Flags, VCB_MOUNTED);
- }
-
- IoReleaseVpbSpinLock(Irql);
-
- ExReleaseResourceLite(&Vcb->MainResource);
- ExReleaseResourceLite(&Ext2Global->Resource);
-
- if (bTearDown) {
- DEBUG(DL_DBG, ( "Ext2CheckDismount: Tearing vcb %p ...\n", Vcb));
- Ext2TearDownStream(Vcb);
- }
-
- if (bDeleted) {
- DEBUG(DL_DBG, ( "Ext2CheckDismount: Deleting vcb %p ...\n", Vcb));
- Ext2DestroyVcb(Vcb);
- }
-
- if (NewVpb != NULL) {
- DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing new Vpb %p\n", NewVpb));
- ExFreePoolWithTag(NewVpb, TAG_VPB);
- DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
- }
-
- return bDeleted;
-}
-
-NTSTATUS
-Ext2PurgeVolume (IN PEXT2_VCB Vcb,
- IN BOOLEAN FlushBeforePurge )
-{
- PEXT2_FCB Fcb;
- LIST_ENTRY List, *Next;
-
- BOOLEAN VcbResourceAcquired = FALSE;
- BOOLEAN FcbResourceAcquired = FALSE;
- BOOLEAN gdResourceAcquired = FALSE;
-
- __try {
-
- ASSERT(Vcb != NULL);
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
-
- ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
- VcbResourceAcquired = TRUE;
-
- if (IsVcbReadOnly(Vcb)) {
- FlushBeforePurge = FALSE;
- }
-
- InitializeListHead(&List);
-
- ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
- FcbResourceAcquired = TRUE;
-
- while (!IsListEmpty(&Vcb->FcbList)) {
-
- Next = RemoveHeadList(&Vcb->FcbList);
- Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next);
-
- DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n",
- &Fcb->Mcb->FullName, Fcb->ReferenceCount));
- InsertTailList(&List, &Fcb->Next);
- }
-
- while (!IsListEmpty(&List)) {
-
- Next = RemoveHeadList(&List);
- Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next);
-
- if (ExAcquireResourceExclusiveLite(
- &Fcb->MainResource,
- TRUE )) {
-
- Ext2PurgeFile(Fcb, FlushBeforePurge);
-
- if (Fcb->ReferenceCount <= 1) {
- Fcb->TsDrop.QuadPart = 0;
- InsertHeadList(&Vcb->FcbList, &Fcb->Next);
- } else {
- InsertTailList(&Vcb->FcbList, &Fcb->Next);
- }
- ExReleaseResourceLite(&Fcb->MainResource);
- }
- }
-
- if (FcbResourceAcquired) {
- ExReleaseResourceLite(&Vcb->FcbLock);
- FcbResourceAcquired = FALSE;
- }
-
- /* acquire bd lock to avoid bh creation */
- ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
- gdResourceAcquired = TRUE;
-
- /* discard buffer_headers for group_desc */
- Ext2DropBH(Vcb);
-
- if (FlushBeforePurge) {
- ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
- ExReleaseResourceLite(&Vcb->PagingIoResource);
-
- CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
- }
-
- if (Vcb->SectionObject.ImageSectionObject) {
- MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite);
- }
-
- if (Vcb->SectionObject.DataSectionObject) {
- CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE);
- }
-
- DEBUG(DL_INF, ( "Ext2PurgeVolume: Volume flushed and purged.\n"));
-
- } __finally {
-
- if (gdResourceAcquired) {
- ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
- }
-
- if (FcbResourceAcquired) {
- ExReleaseResourceLite(&Vcb->FcbLock);
- }
-
- if (VcbResourceAcquired) {
- ExReleaseResourceLite(&Vcb->MainResource);
- }
- }
-
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-Ext2PurgeFile ( IN PEXT2_FCB Fcb,
- IN BOOLEAN FlushBeforePurge )
-{
- IO_STATUS_BLOCK IoStatus;
-
- ASSERT(Fcb != NULL);
-
- ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
- (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
-
-
- if (!IsVcbReadOnly(Fcb->Vcb) && FlushBeforePurge) {
- DEBUG(DL_INF, ( "Ext2PurgeFile: CcFlushCache on %wZ.\n",
- &Fcb->Mcb->FullName));
- ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
- ExReleaseResourceLite(&Fcb->PagingIoResource);
- CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus);
- ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
- }
-
- if (Fcb->SectionObject.ImageSectionObject) {
- DEBUG(DL_INF, ( "Ext2PurgeFile: MmFlushImageSection on %wZ.\n",
- &Fcb->Mcb->FullName));
- MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite);
- }
-
- if (Fcb->SectionObject.DataSectionObject) {
- DEBUG(DL_INF, ( "Ext2PurgeFile: CcPurgeCacheSection on %wZ.\n",
- &Fcb->Mcb->FullName));
- CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
- }
-
- return STATUS_SUCCESS;
-}
-
-
-NTSTATUS
-Ext2FileSystemControl (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- NTSTATUS Status;
-
- ASSERT(IrpContext);
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- switch (IrpContext->MinorFunction) {
-
- case IRP_MN_USER_FS_REQUEST:
- Status = Ext2UserFsRequest(IrpContext);
- break;
-
- case IRP_MN_MOUNT_VOLUME:
- Status = Ext2MountVolume(IrpContext);
- break;
-
- case IRP_MN_VERIFY_VOLUME:
- Status = Ext2VerifyVolume(IrpContext);
- break;
-
- default:
-
- DEBUG(DL_ERR, ( "Ext2FilsSystemControl: Invalid Device Request.\n"));
- Status = STATUS_INVALID_DEVICE_REQUEST;
- Ext2CompleteIrpContext(IrpContext, Status);
- }
-
- return Status;
-}
+/*
+ * COPYRIGHT: See COPYRIGHT.TXT
+ * PROJECT: Ext2 File System Driver for WinNT/2K/XP
+ * FILE: fsctl.c
+ * PROGRAMMER: Matt Wu
+ * HOMEPAGE: http://www.ext2fsd.com
+ * UPDATE HISTORY:
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "ext2fs.h"
+
+/* GLOBALS ***************************************************************/
+
+extern PEXT2_GLOBAL Ext2Global;
+
+/* DEFINITIONS *************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, Ext2IsHandleCountZero)
+#pragma alloc_text(PAGE, Ext2LockVcb)
+#pragma alloc_text(PAGE, Ext2LockVolume)
+#pragma alloc_text(PAGE, Ext2UnlockVcb)
+#pragma alloc_text(PAGE, Ext2UnlockVolume)
+#pragma alloc_text(PAGE, Ext2AllowExtendedDasdIo)
+#pragma alloc_text(PAGE, Ext2GetRetrievalPointerBase)
+#pragma alloc_text(PAGE, Ext2QueryExtentMappings)
+#pragma alloc_text(PAGE, Ext2QueryRetrievalPointers)
+#pragma alloc_text(PAGE, Ext2GetRetrievalPointers)
+#pragma alloc_text(PAGE, Ext2UserFsRequest)
+#pragma alloc_text(PAGE, Ext2IsMediaWriteProtected)
+#pragma alloc_text(PAGE, Ext2MountVolume)
+#pragma alloc_text(PAGE, Ext2PurgeVolume)
+#pragma alloc_text(PAGE, Ext2PurgeFile)
+#pragma alloc_text(PAGE, Ext2DismountVolume)
+#pragma alloc_text(PAGE, Ext2IsVolumeMounted)
+#pragma alloc_text(PAGE, Ext2VerifyVolume)
+#pragma alloc_text(PAGE, Ext2FileSystemControl)
+#endif
+
+
+VOID
+Ext2SetVpbFlag (
+ IN PVPB Vpb,
+ IN USHORT Flag )
+{
+ KIRQL OldIrql;
+
+ IoAcquireVpbSpinLock(&OldIrql);
+ Vpb->Flags |= Flag;
+ IoReleaseVpbSpinLock(OldIrql);
+}
+
+VOID
+Ext2ClearVpbFlag (
+ IN PVPB Vpb,
+ IN USHORT Flag )
+{
+ KIRQL OldIrql;
+
+ IoAcquireVpbSpinLock(&OldIrql);
+ Vpb->Flags &= ~Flag;
+ IoReleaseVpbSpinLock(OldIrql);
+}
+
+BOOLEAN
+Ext2IsHandleCountZero(IN PEXT2_VCB Vcb)
+{
+ PEXT2_FCB Fcb;
+ PLIST_ENTRY List;
+
+ for ( List = Vcb->FcbList.Flink;
+ List != &Vcb->FcbList;
+ List = List->Flink ) {
+
+ Fcb = CONTAINING_RECORD(List, EXT2_FCB, Next);
+
+ ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
+ (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+
+ DEBUG(DL_INF, ( "Ext2IsHandleCountZero: Inode:%xh File:%S OpenHandleCount=%xh\n",
+ Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer, Fcb->OpenHandleCount));
+
+ if (Fcb->OpenHandleCount) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+NTSTATUS
+Ext2LockVcb (IN PEXT2_VCB Vcb,
+ IN PFILE_OBJECT FileObject)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ __try {
+
+ if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
+ DEBUG(DL_INF, ( "Ext2LockVolume: Volume is already locked.\n"));
+ Status = STATUS_ACCESS_DENIED;
+ __leave;
+ }
+
+ if (Vcb->OpenHandleCount > (ULONG)(FileObject ? 1 : 0)) {
+ DEBUG(DL_INF, ( "Ext2LockVcb: There are still opened files.\n"));
+
+ Status = STATUS_ACCESS_DENIED;
+ __leave;
+ }
+
+ if (!Ext2IsHandleCountZero(Vcb)) {
+ DEBUG(DL_INF, ( "Ext2LockVcb: Thare are still opened files.\n"));
+
+ Status = STATUS_ACCESS_DENIED;
+ __leave;
+ }
+
+ SetLongFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
+ Ext2SetVpbFlag(Vcb->Vpb, VPB_LOCKED);
+ Vcb->LockFile = FileObject;
+
+ DEBUG(DL_INF, ( "Ext2LockVcb: Volume locked.\n"));
+
+ } __finally {
+ // Nothing
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2LockVolume (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIO_STACK_LOCATION IrpSp;
+ PDEVICE_OBJECT DeviceObject;
+ PEXT2_VCB Vcb = NULL;
+ NTSTATUS Status;
+ BOOLEAN VcbResourceAcquired = FALSE;
+
+ __try {
+
+ ASSERT(IrpContext != NULL);
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ DeviceObject = IrpContext->DeviceObject;
+
+ Status = STATUS_UNSUCCESSFUL;
+
+ //
+ // This request is not allowed on the main device object
+ //
+ if (IsExt2FsDevice(DeviceObject)) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+
+ ASSERT(Vcb != NULL);
+
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+
+ ASSERT(IsMounted(Vcb));
+
+ IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
+
+#if (_WIN32_WINNT >= 0x0500)
+ CcWaitForCurrentLazyWriterActivity();
+#endif
+ ExAcquireResourceExclusiveLite(
+ &Vcb->MainResource,
+ TRUE );
+
+ VcbResourceAcquired = TRUE;
+
+ /* flush dirty data before locking the volume */
+ if (!IsVcbReadOnly(Vcb)) {
+ Ext2FlushFiles(IrpContext, Vcb, FALSE);
+ Ext2FlushVolume(IrpContext, Vcb, FALSE);
+ }
+
+ Status = Ext2LockVcb(Vcb, IrpSp->FileObject);
+
+ } __finally {
+
+ if (VcbResourceAcquired) {
+ ExReleaseResourceLite(&Vcb->MainResource);
+ }
+
+ if (!IrpContext->ExceptionInProgress) {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2UnlockVcb ( IN PEXT2_VCB Vcb,
+ IN PFILE_OBJECT FileObject )
+{
+ NTSTATUS Status;
+
+ __try {
+
+ if (FileObject && FileObject->FsContext != Vcb) {
+ Status = STATUS_NOT_LOCKED;
+ __leave;
+ }
+
+ if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) {
+ DEBUG(DL_ERR, ( ": Ext2UnlockVcb: Volume is not locked.\n"));
+ Status = STATUS_NOT_LOCKED;
+ __leave;
+ }
+
+ if (Vcb->LockFile == FileObject) {
+ ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED);
+ Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED);
+ DEBUG(DL_INF, ( "Ext2UnlockVcb: Volume unlocked.\n"));
+ Status = STATUS_SUCCESS;
+ } else {
+ Status = STATUS_NOT_LOCKED;
+ }
+
+ } __finally {
+ // Nothing
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2UnlockVolume (
+ IN PEXT2_IRP_CONTEXT IrpContext
+)
+{
+ PIO_STACK_LOCATION IrpSp = NULL;
+ PDEVICE_OBJECT DeviceObject = NULL;
+ PEXT2_VCB Vcb = NULL;
+ NTSTATUS Status;
+ BOOLEAN VcbResourceAcquired = FALSE;
+
+ __try {
+
+ ASSERT(IrpContext != NULL);
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ DeviceObject = IrpContext->DeviceObject;
+ IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
+
+ //
+ // This request is not allowed on the main device object
+ //
+ if (IsExt2FsDevice(DeviceObject)) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ ASSERT(Vcb != NULL);
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+
+ ExAcquireResourceExclusiveLite(
+ &Vcb->MainResource,
+ TRUE );
+ VcbResourceAcquired = TRUE;
+
+ Status = Ext2UnlockVcb(Vcb, IrpSp->FileObject);
+
+ } __finally {
+
+ if (VcbResourceAcquired) {
+ ExReleaseResourceLite(&Vcb->MainResource);
+ }
+
+ if (!IrpContext->ExceptionInProgress) {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2InvalidateVolumes ( IN PEXT2_IRP_CONTEXT IrpContext )
+{
+ NTSTATUS Status;
+ PIRP Irp;
+ PIO_STACK_LOCATION IrpSp;
+
+ PVPB NewVpb = NULL;
+ HANDLE Handle;
+ PLIST_ENTRY ListEntry;
+
+ ULONG InputLength = 0;
+ PFILE_OBJECT FileObject;
+ PDEVICE_OBJECT DeviceObject;
+ BOOLEAN GlobalResourceAcquired = FALSE;
+
+ LUID Privilege = {SE_TCB_PRIVILEGE, 0};
+
+ __try {
+
+ Irp = IrpContext->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ if (!IsExt2FsDevice(IrpSp->DeviceObject)) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ __leave;
+ }
+
+ if (!SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode)) {
+ Status = STATUS_PRIVILEGE_NOT_HELD;
+ __leave;
+ }
+
+
+#ifndef _GNU_NTIFS_
+ InputLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+#else
+ InputLength = ((PEXTENDED_IO_STACK_LOCATION)(IrpSp))->
+ Parameters.FileSystemControl.InputBufferLength;
+#endif
+
+#if defined(_WIN64)
+ if (IoIs32bitProcess(Irp)) {
+ if (InputLength != sizeof(UINT32)) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+ Handle = (HANDLE) LongToHandle( (*(PUINT32)Irp->AssociatedIrp.SystemBuffer) );
+ } else
+#endif
+ {
+ if (InputLength != sizeof(HANDLE)) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+ Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
+ }
+
+ Status = ObReferenceObjectByHandle( Handle,
+ 0,
+ *IoFileObjectType,
+ KernelMode,
+ &FileObject,
+ NULL );
+
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ } else {
+ DeviceObject = FileObject->DeviceObject;
+ ObDereferenceObject(FileObject);
+ }
+
+ ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE);
+ GlobalResourceAcquired = TRUE;
+
+ ListEntry = Ext2Global->VcbList.Flink;
+ while (ListEntry != &Ext2Global->VcbList) {
+
+ PEXT2_VCB Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next);
+ ListEntry = ListEntry->Flink;
+
+ DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Vcb=%xh Vcb->Vpb=%xh "
+ "Blink = %p &Vcb->Next = %p\n",
+ Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next));
+
+ if (Vcb->Vpb && (Vcb->Vpb->RealDevice == DeviceObject)) {
+
+ DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Got Vcb=%xh Vcb->Vpb=%xh "
+ "Blink = %p &Vcb->Next = %p\n",
+ Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next));
+ /* dismount the volume */
+ Ext2CheckDismount(IrpContext, Vcb, FALSE);
+ }
+ }
+
+ } __finally {
+
+ if (GlobalResourceAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ }
+
+ if (!IrpContext->ExceptionInProgress) {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2AllowExtendedDasdIo(IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIO_STACK_LOCATION IrpSp;
+ PEXT2_VCB Vcb;
+ PEXT2_CCB Ccb;
+ NTSTATUS status;
+
+ IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp);
+
+ Vcb = (PEXT2_VCB) IrpSp->FileObject->FsContext;
+ Ccb = (PEXT2_CCB) IrpSp->FileObject->FsContext2;
+
+ ASSERT(Vcb != NULL);
+
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+
+ ASSERT(IsMounted(Vcb));
+
+ if (Ccb) {
+ SetLongFlag(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO);
+ status = STATUS_SUCCESS;
+ } else {
+ status = STATUS_INVALID_PARAMETER;
+ }
+
+ Ext2CompleteIrpContext(IrpContext, status);
+ return status;
+}
+
+/*
+ * Ext2OplockRequest
+ *
+ * oplock requests handler routine
+ *
+ * Arguments:
+ * IrpContext: the ext2 irp context
+ *
+ * Return Value:
+ * NTSTATUS: The return status for the operation
+ *
+ */
+
+NTSTATUS
+Ext2OplockRequest (
+ IN PEXT2_IRP_CONTEXT IrpContext
+)
+{
+ NTSTATUS Status;
+
+ ULONG FsCtrlCode;
+ PDEVICE_OBJECT DeviceObject;
+ PFILE_OBJECT FileObject;
+
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp;
+ PEXTENDED_IO_STACK_LOCATION EIrpSp;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+
+ ULONG OplockCount = 0;
+
+ BOOLEAN VcbResourceAcquired = FALSE;
+ BOOLEAN FcbResourceAcquired = FALSE;
+
+ ASSERT(IrpContext);
+
+ __try {
+
+ Irp = IrpContext->Irp;
+ ASSERT(Irp);
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ ASSERT(IrpSp);
+ EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ DeviceObject = IrpContext->DeviceObject;
+
+ //
+ // This request is not allowed on the main device object
+ //
+ if (IsExt2FsDevice(DeviceObject)) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ __leave;
+ }
+
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+
+ ASSERT(Vcb != NULL);
+
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+
+ ASSERT(IsMounted(Vcb));
+
+ FileObject = IrpContext->FileObject;
+
+ Fcb = (PEXT2_FCB) FileObject->FsContext;
+
+ //
+ // This request is not allowed on volumes
+ //
+
+ if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
+ (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+
+ if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
+ Status = STATUS_FILE_DELETED;
+ __leave;
+ }
+
+ Ccb = (PEXT2_CCB) FileObject->FsContext2;
+ if (Ccb == NULL) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+
+ FsCtrlCode = EIrpSp->Parameters.FileSystemControl.FsControlCode;
+
+ switch (FsCtrlCode) {
+
+ case FSCTL_REQUEST_OPLOCK_LEVEL_1:
+ case FSCTL_REQUEST_OPLOCK_LEVEL_2:
+ case FSCTL_REQUEST_BATCH_OPLOCK:
+
+ VcbResourceAcquired =
+ ExAcquireResourceSharedLite(
+ &Vcb->MainResource,
+ IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
+
+ ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+
+ FcbResourceAcquired =
+ ExAcquireResourceExclusiveLite (
+ &Fcb->MainResource,
+ IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
+
+ if (FsCtrlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) {
+ OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks(&Fcb->FileLockAnchor);
+ } else {
+ OplockCount = Fcb->OpenHandleCount;
+ }
+
+ break;
+
+ case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
+ case FSCTL_OPBATCH_ACK_CLOSE_PENDING :
+ case FSCTL_OPLOCK_BREAK_NOTIFY:
+ case FSCTL_OPLOCK_BREAK_ACK_NO_2:
+
+ FcbResourceAcquired =
+ ExAcquireResourceSharedLite (
+ &Fcb->MainResource,
+ IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT));
+
+ break;
+
+ default:
+
+ Ext2BugCheck(EXT2_BUGCHK_FSCTL, FsCtrlCode, 0, 0);
+ }
+
+
+ //
+ // Call the FsRtl routine to grant/acknowledge oplock.
+ //
+
+ Status = FsRtlOplockFsctrl( &Fcb->Oplock,
+ Irp,
+ OplockCount );
+
+ //
+ // Set the flag indicating if Fast I/O is possible
+ //
+
+ Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb);
+ IrpContext->Irp = NULL;
+
+ } __finally {
+
+ if (FcbResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (VcbResourceAcquired) {
+ ExReleaseResourceLite(&Vcb->MainResource);
+ }
+
+ if (!AbnormalTermination()) {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2IsVolumeDirty (
+ IN PEXT2_IRP_CONTEXT IrpContext
+)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PIRP Irp;
+ PEXTENDED_IO_STACK_LOCATION IrpSp;
+ PULONG VolumeState;
+
+ __try {
+
+ Irp = IrpContext->Irp;
+ IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
+
+ //
+ // Get a pointer to the output buffer. Look at the system buffer field in th
+ // irp first. Then the Irp Mdl.
+ //
+
+ if (Irp->AssociatedIrp.SystemBuffer != NULL) {
+
+ VolumeState = Irp->AssociatedIrp.SystemBuffer;
+
+ } else if (Irp->MdlAddress != NULL) {
+
+ VolumeState = MmGetSystemAddressForMdl( Irp->MdlAddress );
+
+ } else {
+
+ status = STATUS_INVALID_USER_BUFFER;
+ __leave;
+ }
+
+ if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) {
+ status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ *VolumeState = 0;
+
+ } __finally {
+
+ if (!IrpContext->ExceptionInProgress) {
+ Ext2CompleteIrpContext(IrpContext, status);
+ }
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+Ext2QueryExtentMappings(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_FCB Fcb,
+ IN PLARGE_INTEGER RequestVbn,
+ OUT PLARGE_INTEGER * pMappedRuns
+)
+{
+ PLARGE_INTEGER MappedRuns = NULL;
+ PLARGE_INTEGER PartialRuns = NULL;
+
+ PEXT2_EXTENT Chain = NULL;
+ PEXT2_EXTENT Extent = NULL;
+
+ LONGLONG Vbn = 0;
+ ULONG Length = 0;
+ ULONG i = 0;
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ __try {
+
+ /* now building all the request extents */
+ while (Vbn < RequestVbn->QuadPart) {
+
+ Length = 0x80000000; /* 2g bytes */
+ if (RequestVbn->QuadPart < Vbn + Length) {
+ Length = (ULONG)(RequestVbn->QuadPart - Vbn);
+ }
+
+ /* build extents for sub-range */
+ Extent = NULL;
+ Status = Ext2BuildExtents(
+ IrpContext,
+ Vcb,
+ Fcb->Mcb,
+ Vbn,
+ Length,
+ FALSE,
+ &Extent);
+
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+
+ if (Chain) {
+ Ext2JointExtents(Chain, Extent);
+ } else {
+ Chain = Extent;
+ }
+
+ /* allocate extent array */
+ PartialRuns = Ext2AllocatePool(
+ NonPagedPool,
+ (Ext2CountExtents(Chain) + 2) *
+ (2 * sizeof(LARGE_INTEGER)),
+ 'RE2E');
+
+ if (PartialRuns == NULL) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ __leave;
+ }
+ RtlZeroMemory( PartialRuns,
+ (Ext2CountExtents(Chain) + 2) *
+ (2 * sizeof(LARGE_INTEGER)));
+
+ if (MappedRuns) {
+ RtlMoveMemory(PartialRuns,
+ MappedRuns,
+ i * 2 * sizeof(LARGE_INTEGER));
+ Ext2FreePool(MappedRuns, 'RE2E');
+ }
+ MappedRuns = PartialRuns;
+
+ /* walk all the Mcb runs in Extent */
+ for (; Extent != NULL; Extent = Extent->Next) {
+ MappedRuns[i*2 + 0].QuadPart = Vbn + Extent->Offset;
+ MappedRuns[i*2 + 1].QuadPart = Extent->Lba;
+ i = i+1;
+ }
+
+ Vbn = Vbn + Length;
+ }
+
+ *pMappedRuns = MappedRuns;
+
+ } __finally {
+
+ if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) {
+ if (MappedRuns) {
+ Ext2FreePool(MappedRuns, 'RE2E');
+ }
+ *pMappedRuns = NULL;
+ }
+
+ if (Chain) {
+ Ext2DestroyExtentChain(Chain);
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2QueryRetrievalPointers (
+ IN PEXT2_IRP_CONTEXT IrpContext
+)
+{
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp;
+ PEXTENDED_IO_STACK_LOCATION EIrpSp;
+
+ PDEVICE_OBJECT DeviceObject;
+ PFILE_OBJECT FileObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+
+ PLARGE_INTEGER RequestVbn;
+ PLARGE_INTEGER * pMappedRuns;
+
+ ULONG InputSize;
+ ULONG OutputSize;
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ BOOLEAN FcbResourceAcquired = FALSE;
+
+ __try {
+
+ ASSERT(IrpContext);
+ Irp = IrpContext->Irp;
+ ASSERT(Irp);
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
+ ASSERT(IrpSp);
+
+ InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength;
+ OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ DeviceObject = IrpContext->DeviceObject;
+
+ DbgBreak();
+
+ /* This request is not allowed on the main device object */
+ if (IsExt2FsDevice(DeviceObject)) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ __leave;
+ }
+
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ ASSERT(Vcb != NULL);
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+ ASSERT(IsMounted(Vcb));
+
+ FileObject = IrpContext->FileObject;
+ Fcb = (PEXT2_FCB) FileObject->FsContext;
+
+ /* check Fcb is valid or not */
+ if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
+ (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+ if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
+ Status = STATUS_FILE_DELETED;
+ __leave;
+ }
+
+ Ccb = (PEXT2_CCB) FileObject->FsContext2;
+ if (Ccb == NULL) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+
+ /* Is requstor in kernel and Fcb a paging file ? */
+ if (Irp->RequestorMode != KernelMode ||
+ !IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) ||
+ InputSize != sizeof(LARGE_INTEGER) ||
+ OutputSize != sizeof(PVOID)) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ if (!ExAcquireResourceExclusiveLite (
+ &Fcb->MainResource, Ext2CanIWait())) {
+ Status = STATUS_PENDING;
+ __leave;
+ }
+ FcbResourceAcquired = TRUE;
+
+ RequestVbn = EIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
+ pMappedRuns = Irp->UserBuffer;
+
+ DbgBreak();
+
+ /* request size beyonds whole file size */
+ if (RequestVbn->QuadPart >= Fcb->Header.AllocationSize.QuadPart) {
+ Status = STATUS_END_OF_FILE;
+ __leave;
+ }
+
+ Status = Ext2QueryExtentMappings(
+ IrpContext,
+ Vcb,
+ Fcb,
+ RequestVbn,
+ pMappedRuns
+ );
+
+ } __finally {
+
+ if (FcbResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (!AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2GetRetrievalPointers (
+ IN PEXT2_IRP_CONTEXT IrpContext
+)
+{
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp;
+ PEXTENDED_IO_STACK_LOCATION EIrpSp;
+
+ PDEVICE_OBJECT DeviceObject;
+ PFILE_OBJECT FileObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+
+ PSTARTING_VCN_INPUT_BUFFER SVIB;
+ PRETRIEVAL_POINTERS_BUFFER RPSB;
+
+ PEXT2_EXTENT Chain = NULL;
+ PEXT2_EXTENT Extent = NULL;
+
+ LONGLONG Vbn = 0;
+ ULONG Length = 0;
+ ULONG i = 0;
+
+ ULONG UsedSize = 0;
+ ULONG InputSize;
+ ULONG OutputSize;
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ BOOLEAN FcbResourceAcquired = FALSE;
+
+ __try {
+
+ ASSERT(IrpContext);
+ Irp = IrpContext->Irp;
+ ASSERT(Irp);
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
+ ASSERT(IrpSp);
+
+ InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength;
+ OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ DeviceObject = IrpContext->DeviceObject;
+
+ /* This request is not allowed on the main device object */
+ if (IsExt2FsDevice(DeviceObject)) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ __leave;
+ }
+
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ ASSERT(Vcb != NULL);
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+ ASSERT(IsMounted(Vcb));
+
+ FileObject = IrpContext->FileObject;
+ Fcb = (PEXT2_FCB) FileObject->FsContext;
+
+ /* check Fcb is valid or not */
+ if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
+ (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+
+ if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
+ Status = STATUS_FILE_DELETED;
+ __leave;
+ }
+
+ Ccb = (PEXT2_CCB) FileObject->FsContext2;
+ if (Ccb == NULL) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+
+ if (InputSize < sizeof(STARTING_VCN_INPUT_BUFFER) ||
+ OutputSize < sizeof(RETRIEVAL_POINTERS_BUFFER) ) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ __leave;
+ }
+
+ if (!ExAcquireResourceExclusiveLite (
+ &Fcb->MainResource, Ext2CanIWait())) {
+ Status = STATUS_PENDING;
+ __leave;
+ }
+ FcbResourceAcquired = TRUE;
+
+ SVIB = (PSTARTING_VCN_INPUT_BUFFER)
+ EIrpSp->Parameters.FileSystemControl.Type3InputBuffer;
+ RPSB = (PRETRIEVAL_POINTERS_BUFFER) Ext2GetUserBuffer(Irp);
+
+ /* probe user buffer */
+
+ __try {
+ if (Irp->RequestorMode != KernelMode) {
+ ProbeForRead (SVIB, InputSize, sizeof(UCHAR));
+ ProbeForWrite(RPSB, OutputSize, sizeof(UCHAR));
+ }
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ Status = STATUS_INVALID_USER_BUFFER;
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+
+ UsedSize = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0]);
+
+ /* request size beyonds whole file size ? */
+ DEBUG(DL_DBG, ("Ext2GetRetrievalPointers: Startin from Vbn: %I64xh\n",
+ SVIB->StartingVcn.QuadPart));
+ Vbn = (SVIB->StartingVcn.QuadPart << BLOCK_BITS);
+ if (Vbn >= Fcb->Header.AllocationSize.QuadPart ) {
+ Status = STATUS_END_OF_FILE;
+ __leave;
+ }
+
+ /* now building all the request extents */
+ while (Vbn < Fcb->Header.AllocationSize.QuadPart) {
+
+ ASSERT(Chain == NULL);
+ Length = 0x80000000; /* 2g bytes */
+ if (Fcb->Header.AllocationSize.QuadPart < Vbn + Length) {
+ Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - Vbn);
+ }
+
+ /* build extents for sub-range */
+ Status = Ext2BuildExtents(
+ IrpContext,
+ Vcb,
+ Fcb->Mcb,
+ Vbn,
+ Length,
+ FALSE,
+ &Chain);
+
+ if (!NT_SUCCESS(Status)) {
+ DbgBreak();
+ __leave;
+ }
+
+ /* fill user buffer of RETRIEVAL_POINTERS_BUFFER */
+ Extent = Chain;
+ while (Extent) {
+
+ DEBUG(DL_MAP, ("Ext2GetRetrievalPointers: %wZ %d Vbn = %I64xh Lbn = %I64xh\n",
+ &Fcb->Mcb->FullName, i,
+ ((Vbn + Extent->Offset) >> BLOCK_BITS),
+ Extent->Lba));
+
+ RPSB->Extents[i].Lcn.QuadPart = (Extent->Lba >> BLOCK_BITS);
+ RPSB->Extents[i].NextVcn.QuadPart = ((Vbn + Extent->Offset + Extent->Length) >> BLOCK_BITS);
+ if (i == 0) {
+ RPSB->StartingVcn.QuadPart = ((Vbn + Extent->Offset) >> BLOCK_BITS);
+ } else {
+ ASSERT(RPSB->Extents[i-1].NextVcn.QuadPart == ((Vbn + Extent->Offset) >> BLOCK_BITS));
+ }
+ if (UsedSize + sizeof(RETRIEVAL_POINTERS_BUFFER) > OutputSize) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ __leave;
+ }
+ UsedSize += sizeof(LARGE_INTEGER) * 2;
+ Irp->IoStatus.Information = (ULONG_PTR)UsedSize;
+ RPSB->ExtentCount = ++i;
+ Extent = Extent->Next;
+ }
+
+ if (Chain) {
+ Ext2DestroyExtentChain(Chain);
+ Chain = NULL;
+ }
+
+ Vbn = Vbn + Length;
+ }
+
+#if 0
+ {
+ NTSTATUS _s;
+ ULONG _i = 0;
+ LARGE_INTEGER RequestVbn = Fcb->Header.AllocationSize;
+ PLARGE_INTEGER MappedRuns = NULL;
+
+ _s = Ext2QueryExtentMappings(
+ IrpContext,
+ Vcb,
+ Fcb,
+ &RequestVbn,
+ &MappedRuns
+ );
+ if (!NT_SUCCESS(_s) || NULL == MappedRuns) {
+ DbgBreak();
+ goto exit_to_get_rps;
+ }
+
+ while (MappedRuns[_i*2 + 0].QuadPart != 0 ||
+ MappedRuns[_i*2 + 1].QuadPart != 0 ) {
+ DEBUG(DL_MAP, ("Ext2QueryExtentMappings: %wZ %d Vbn = %I64xh Lbn = %I64xh\n",
+ &Fcb->Mcb->FullName, _i,
+ MappedRuns[_i*2 + 0].QuadPart,
+ MappedRuns[_i*2 + 1].QuadPart));
+ _i++;
+ }
+
+exit_to_get_rps:
+
+ if (MappedRuns) {
+ Ext2FreePool(MappedRuns, 'RE2E');
+ }
+ }
+#endif
+
+ } __finally {
+
+ if (FcbResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (Chain) {
+ Ext2DestroyExtentChain(Chain);
+ }
+
+ if (!AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2GetRetrievalPointerBase (
+ IN PEXT2_IRP_CONTEXT IrpContext
+)
+{
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp;
+ PEXTENDED_IO_STACK_LOCATION EIrpSp;
+
+ PDEVICE_OBJECT DeviceObject;
+ PFILE_OBJECT FileObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+
+ PLARGE_INTEGER FileAreaOffset;
+
+ ULONG OutputSize;
+
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ BOOLEAN FcbResourceAcquired = FALSE;
+
+ __try {
+
+ ASSERT(IrpContext);
+ Irp = IrpContext->Irp;
+ ASSERT(Irp);
+
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+ EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp;
+ ASSERT(IrpSp);
+
+ OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength;
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ DeviceObject = IrpContext->DeviceObject;
+
+ /* This request is not allowed on the main device object */
+ if (IsExt2FsDevice(DeviceObject)) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ __leave;
+ }
+
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ ASSERT(Vcb != NULL);
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+ ASSERT(IsMounted(Vcb));
+
+ FileObject = IrpContext->FileObject;
+ Fcb = (PEXT2_FCB) FileObject->FsContext;
+
+ /* check Fcb is valid or not */
+ if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
+ (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+
+ if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) {
+ Status = STATUS_FILE_DELETED;
+ __leave;
+ }
+
+ Ccb = (PEXT2_CCB) FileObject->FsContext2;
+ if (Ccb == NULL) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+
+ if (OutputSize < sizeof(LARGE_INTEGER)) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ __leave;
+ }
+
+ if (!ExAcquireResourceExclusiveLite (
+ &Fcb->MainResource, Ext2CanIWait())) {
+ Status = STATUS_PENDING;
+ __leave;
+ }
+ FcbResourceAcquired = TRUE;
+
+ FileAreaOffset = (PLARGE_INTEGER) Ext2GetUserBuffer(Irp);
+
+ /* probe user buffer */
+
+ __try {
+ if (Irp->RequestorMode != KernelMode) {
+ ProbeForWrite(FileAreaOffset, OutputSize, sizeof(UCHAR));
+ }
+
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+
+ Status = STATUS_INVALID_USER_BUFFER;
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+
+ DEBUG(DL_DBG, ("Ext2GetRetrievalPointerBase: FileAreaOffset is 0.\n"));
+
+ FileAreaOffset->QuadPart = 0; // sector offset to the first allocatable unit on the filesystem
+
+ Irp->IoStatus.Information = sizeof(LARGE_INTEGER);
+
+ } __finally {
+
+ if (FcbResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (!AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2InspectReparseData(
+ IN PREPARSE_DATA_BUFFER RDB,
+ IN ULONG InputBufferLength
+)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!RDB) {
+ Status = STATUS_INVALID_PARAMETER;
+ goto out;
+ }
+
+ if (InputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if (InputBufferLength < RDB->ReparseDataLength) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if (RDB->ReparseTag != IO_REPARSE_TAG_SYMLINK) {
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto out;
+ }
+
+ if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameLength
+ > (PUCHAR)RDB + InputBufferLength ) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer
+ + RDB->SymbolicLinkReparseBuffer.PrintNameOffset
+ + RDB->SymbolicLinkReparseBuffer.PrintNameLength
+ > (PUCHAR)RDB + InputBufferLength) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ goto out;
+ }
+
+ if (RDB->SymbolicLinkReparseBuffer.Flags != SYMLINK_FLAG_RELATIVE) {
+ Status = STATUS_NOT_IMPLEMENTED;
+ goto out;
+ }
+
+out:
+ return Status;
+}
+
+VOID
+Ext2InitializeReparseData(IN PREPARSE_DATA_BUFFER RDB, USHORT PathBufferLength)
+{
+ ASSERT(FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset) ==
+ REPARSE_DATA_BUFFER_HEADER_SIZE);
+ RDB->ReparseTag = IO_REPARSE_TAG_SYMLINK;
+ RDB->ReparseDataLength = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) -
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) +
+ PathBufferLength * sizeof(WCHAR);
+ RDB->Reserved = 0;
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset = PathBufferLength;
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameLength = PathBufferLength;
+ RDB->SymbolicLinkReparseBuffer.PrintNameOffset = 0;
+ RDB->SymbolicLinkReparseBuffer.PrintNameLength = PathBufferLength;
+ RDB->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE;
+ RtlZeroMemory(&RDB->SymbolicLinkReparseBuffer.PathBuffer, PathBufferLength * 2);
+}
+
+NTSTATUS
+Ext2ReadSymlink (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ OUT PULONG BytesRead
+ )
+{
+ return Ext2ReadInode ( IrpContext,
+ Vcb,
+ Mcb,
+ 0,
+ Buffer,
+ Size,
+ FALSE,
+ BytesRead);
+}
+
+
+
+NTSTATUS
+Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp;
+ PEXTENDED_IO_STACK_LOCATION EIrpSp;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+ PVOID OutputBuffer;
+ ULONG OutputBufferLength;
+ ULONG BytesRead = 0;
+
+ PREPARSE_DATA_BUFFER RDB;
+
+ UNICODE_STRING UniName;
+ OEM_STRING OemName;
+
+ PCHAR OemNameBuffer = NULL;
+ int OemNameLength = 0, i;
+
+ Ccb = IrpContext->Ccb;
+ ASSERT(Ccb != NULL);
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+ DeviceObject = IrpContext->DeviceObject;
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ Mcb = IrpContext->Fcb->Mcb;
+ Irp = IrpContext->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ __try {
+
+ if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
+ !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
+ Status = STATUS_NOT_A_REPARSE_POINT;
+ __leave;
+ }
+
+ OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer;
+ OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
+
+ RDB = (PREPARSE_DATA_BUFFER)OutputBuffer;
+ if (!RDB) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+ if (OutputBufferLength < sizeof(REPARSE_DATA_BUFFER)) {
+ Status = STATUS_BUFFER_OVERFLOW;
+ __leave;
+ }
+
+ OemNameLength = (ULONG)Mcb->Inode.i_size;
+ if (OemNameLength > USHRT_MAX) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+ OemName.Length = (USHORT)OemNameLength;
+ OemName.MaximumLength = OemNameLength + 1;
+ OemNameBuffer = OemName.Buffer = Ext2AllocatePool(NonPagedPool,
+ OemName.MaximumLength,
+ 'NL2E');
+ if (!OemNameBuffer) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ __leave;
+ }
+
+ Status = Ext2ReadSymlink(IrpContext,
+ Vcb,
+ Mcb,
+ OemNameBuffer,
+ OemNameLength,
+ &BytesRead
+ );
+ OemName.Buffer[OemName.Length] = '\0';
+ for (i = 0;i < OemName.Length;i++) {
+ if (OemName.Buffer[i] == '/') {
+ OemName.Buffer[i] = '\\';
+ }
+ }
+
+ if (OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) > USHRT_MAX) {
+ UniName.Length = USHRT_MAX;
+ } else {
+ UniName.Length = (USHORT)OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer);
+ }
+ UniName.MaximumLength = UniName.Length;
+ UniName.Length = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName);
+ Irp->IoStatus.Information = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + 2 * UniName.Length;
+ if (UniName.MaximumLength < 2*UniName.Length) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ __leave;
+ }
+
+ Ext2InitializeReparseData(RDB, UniName.Length);
+ UniName.Buffer = RDB->SymbolicLinkReparseBuffer.PathBuffer;
+ /*
+ (PWCHAR)((PUCHAR)&
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
+ */
+ Ext2OEMToUnicode(Vcb, &UniName, &OemName);
+ RtlMoveMemory( (PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer +
+ RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset,
+ UniName.Buffer, UniName.Length);
+
+ Status = STATUS_SUCCESS;
+
+ } __finally {
+
+ if (OemNameBuffer) {
+ Ext2FreePool(OemNameBuffer, 'NL2E');
+ }
+
+ if (!AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2WriteSymlink (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN PVOID Buffer,
+ IN ULONG Size,
+ OUT PULONG BytesWritten
+)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PUCHAR Data = (PUCHAR)(&Mcb->Inode.i_block[0]);
+
+ if (Size >= EXT2_LINKLEN_IN_INODE) {
+
+ /* initialize inode i_block[] */
+ if (0 == Mcb->Inode.i_blocks) {
+ memset(Data, 0, EXT2_LINKLEN_IN_INODE);
+ ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+ }
+
+ Status = Ext2WriteInode(IrpContext, Vcb, Mcb,
+ 0, Buffer, Size,
+ FALSE, BytesWritten);
+ if (!NT_SUCCESS(Status)) {
+ goto out;
+ }
+
+ } else {
+
+ /* free inode blocks before writing in line */
+ if (Mcb->Inode.i_blocks) {
+ LARGE_INTEGER Zero = {0, 0};
+ Ext2TruncateFile(IrpContext, Vcb, Mcb, &Zero);
+ }
+
+ ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL);
+ memset(Data, 0, EXT2_LINKLEN_IN_INODE);
+ RtlCopyMemory(Data, Buffer, Size);
+ }
+
+ Mcb->Inode.i_size = Size;
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+
+ if (BytesWritten) {
+ *BytesWritten = Size;
+ }
+
+out:
+ return Status;
+}
+
+NTSTATUS
+Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIRP Irp = NULL;
+ PIO_STACK_LOCATION IrpSp;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ PVOID InputBuffer;
+ ULONG InputBufferLength;
+ ULONG BytesWritten = 0;
+
+ PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
+ PEXT2_MCB ParentMcb = NULL;
+
+ PREPARSE_DATA_BUFFER RDB;
+
+ UNICODE_STRING UniName;
+ OEM_STRING OemName;
+
+ PCHAR OemNameBuffer = NULL;
+ int OemNameLength = 0, i;
+
+ BOOLEAN MainResourceAcquired = FALSE;
+ BOOLEAN FcbLockAcquired = FALSE;
+
+ __try {
+
+ Ccb = IrpContext->Ccb;
+ ASSERT(Ccb != NULL);
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+ DeviceObject = IrpContext->DeviceObject;
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ Fcb = IrpContext->Fcb;
+ Mcb = Fcb->Mcb;
+ Irp = IrpContext->Irp;
+ IrpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+ FcbLockAcquired = TRUE;
+
+ ParentMcb = Mcb->Parent;
+ ParentDcb = ParentMcb->Fcb;
+ if (ParentDcb == NULL) {
+ ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
+ }
+ if (ParentDcb) {
+ Ext2ReferXcb(&ParentDcb->ReferenceCount);
+ }
+
+ if (!Mcb)
+ __leave;
+
+ if (FcbLockAcquired) {
+ ExReleaseResourceLite(&Vcb->FcbLock);
+ FcbLockAcquired = FALSE;
+ }
+
+ if (!ExAcquireResourceSharedLite(
+ &Fcb->MainResource,
+ IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+ Status = STATUS_PENDING;
+ __leave;
+ }
+ MainResourceAcquired = TRUE;
+
+ InputBuffer = Irp->AssociatedIrp.SystemBuffer;
+ InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
+
+ RDB = (PREPARSE_DATA_BUFFER)InputBuffer;
+ Status = Ext2InspectReparseData(RDB, InputBufferLength);
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+
+ UniName.Length = RDB->SymbolicLinkReparseBuffer.SubstituteNameLength;
+ UniName.MaximumLength = UniName.Length;
+ UniName.Buffer =
+ (PWCHAR)((PUCHAR)&RDB->SymbolicLinkReparseBuffer.PathBuffer
+ + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset);
+
+ OemNameLength = Ext2UnicodeToOEMSize(Vcb, &UniName);
+ if (OemNameLength > USHRT_MAX) {
+ Status = STATUS_INVALID_PARAMETER;
+ __leave;
+ }
+ OemName.Length = (USHORT)OemNameLength;
+ OemName.MaximumLength = OemNameLength + 1;
+ OemNameBuffer = OemName.Buffer = Ext2AllocatePool(PagedPool,
+ OemName.MaximumLength,
+ 'NL2E');
+ if (!OemNameBuffer) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ __leave;
+ }
+
+ Ext2UnicodeToOEM(Vcb, &OemName, &UniName);
+ OemName.Buffer[OemName.Length] = '\0';
+ for (i = 0;i < OemName.Length;i++) {
+ if (OemName.Buffer[i] == '\\') {
+ OemName.Buffer[i] = '/';
+ }
+ }
+
+ /* free all data blocks of the inode (to be set as symlink) */
+ {
+ LARGE_INTEGER zero = {0};
+ Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &zero);
+ }
+
+ /* decrease dir count of group desc and vcb stat */
+ if (S_ISDIR(Mcb->Inode.i_mode)) {
+
+ ULONG group = (Mcb->Inode.i_ino - 1) / INODES_PER_GROUP;
+ Ext2UpdateGroupDirStat(IrpContext, Vcb, group);
+
+ /* drop extra reference for dir inode */
+ ext3_dec_count(&Mcb->Inode);
+ }
+
+ /* overwrite inode mode as type SYMLINK */
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+ SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT);
+
+ Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer,
+ OemNameLength, &BytesWritten);
+ if (NT_SUCCESS(Status)) {
+ Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb,
+ S_IFLNK | S_IRWXUGO);
+ }
+
+ } __finally {
+
+ if (FcbLockAcquired) {
+ ExReleaseResourceLite(&Vcb->FcbLock);
+ FcbLockAcquired = FALSE;
+ }
+
+ if (MainResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (OemNameBuffer) {
+ Ext2FreePool(OemNameBuffer, 'NL2E');
+ }
+
+ if (NT_SUCCESS(Status)) {
+ Ext2NotifyReportChange(
+ IrpContext,
+ Vcb,
+ Mcb,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ FILE_ACTION_MODIFIED );
+ }
+
+ if (!AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ if (ParentDcb) {
+ Ext2ReleaseFcb(ParentDcb);
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2TruncateSymlink(
+ PEXT2_IRP_CONTEXT IrpContext,
+ PEXT2_VCB Vcb,
+ PEXT2_MCB Mcb,
+ ULONG Size
+ )
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ PUCHAR data = (PUCHAR)&Mcb->Inode.i_block;
+ ULONG len = (ULONG)Mcb->Inode.i_size;
+ LARGE_INTEGER NewSize;
+
+ if (len < EXT2_LINKLEN_IN_INODE && !Mcb->Inode.i_blocks) {
+
+ RtlZeroMemory(data + Size, EXT2_LINKLEN_IN_INODE - Size);
+ Mcb->Inode.i_size = Size;
+ Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode);
+
+ } else {
+ NewSize.QuadPart = Size;
+ status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize);
+ if (!NT_SUCCESS(status)) {
+ goto out;
+ }
+ }
+
+out:
+ return status;
+}
+
+
+/* FIXME: We can only handle one reparse point right now. */
+NTSTATUS
+Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIRP Irp = NULL;
+
+ PDEVICE_OBJECT DeviceObject;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_FCB Fcb = NULL;
+ PEXT2_CCB Ccb = NULL;
+ PEXT2_MCB Mcb = NULL;
+
+ PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */
+ PEXT2_MCB ParentMcb = NULL;
+
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+
+ BOOLEAN FcbLockAcquired = FALSE;
+ BOOLEAN MainResourceAcquired = FALSE;
+
+
+ __try {
+
+ Ccb = IrpContext->Ccb;
+ ASSERT(Ccb != NULL);
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+ DeviceObject = IrpContext->DeviceObject;
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ Mcb = IrpContext->Fcb->Mcb;
+ Irp = IrpContext->Irp;
+
+ ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+ FcbLockAcquired = TRUE;
+
+ ParentMcb = Mcb->Parent;
+ ParentDcb = ParentMcb->Fcb;
+ if (ParentDcb == NULL) {
+ ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb);
+ }
+ if (ParentDcb) {
+ Ext2ReferXcb(&ParentDcb->ReferenceCount);
+ }
+
+ if (!Mcb || !IsInodeSymLink(&Mcb->Inode) ||
+ !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) {
+ Status = STATUS_NOT_A_REPARSE_POINT;
+ __leave;
+ }
+
+ Fcb = Ext2AllocateFcb (Vcb, Mcb);
+ if (Fcb) {
+ Ext2ReferXcb(&Fcb->ReferenceCount);
+ } else {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ __leave;
+ }
+
+ if (FcbLockAcquired) {
+ ExReleaseResourceLite(&Vcb->FcbLock);
+ FcbLockAcquired = FALSE;
+ }
+
+ if (!ExAcquireResourceSharedLite(
+ &Fcb->MainResource,
+ IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) {
+ Status = STATUS_PENDING;
+ __leave;
+ }
+ MainResourceAcquired = TRUE;
+
+ Status = Ext2TruncateSymlink(IrpContext, Vcb, Mcb, 0);
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+
+ /* inode is to be removed */
+ SetFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE);
+
+ } __finally {
+
+ if (FcbLockAcquired) {
+ ExReleaseResourceLite(&Vcb->FcbLock);
+ }
+
+ if (MainResourceAcquired) {
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+
+ if (NT_SUCCESS(Status)) {
+ Ext2NotifyReportChange(
+ IrpContext,
+ Vcb,
+ Mcb,
+ FILE_NOTIFY_CHANGE_ATTRIBUTES,
+ FILE_ACTION_MODIFIED );
+
+ }
+
+ if (!AbnormalTermination()) {
+ if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) {
+ Status = Ext2QueueRequest(IrpContext);
+ } else {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ if (ParentDcb) {
+ Ext2ReleaseFcb(ParentDcb);
+ }
+
+ if (Fcb) {
+ Ext2ReleaseFcb(Fcb);
+ }
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStackLocation;
+ ULONG FsControlCode;
+ NTSTATUS Status;
+
+ ASSERT(IrpContext);
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ Irp = IrpContext->Irp;
+ IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+#ifndef _GNU_NTIFS_
+ FsControlCode =
+ IoStackLocation->Parameters.FileSystemControl.FsControlCode;
+#else
+ FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)
+ IoStackLocation)->Parameters.FileSystemControl.FsControlCode;
+#endif
+
+ switch (FsControlCode) {
+
+ case FSCTL_GET_REPARSE_POINT:
+ Status = Ext2GetReparsePoint(IrpContext);
+ break;
+
+ case FSCTL_SET_REPARSE_POINT:
+ Status = Ext2SetReparsePoint(IrpContext);
+ break;
+
+ case FSCTL_DELETE_REPARSE_POINT:
+ Status = Ext2DeleteReparsePoint(IrpContext);
+ break;
+
+ case FSCTL_LOCK_VOLUME:
+ Status = Ext2LockVolume(IrpContext);
+ break;
+
+ case FSCTL_UNLOCK_VOLUME:
+ Status = Ext2UnlockVolume(IrpContext);
+ break;
+
+ case FSCTL_DISMOUNT_VOLUME:
+ Status = Ext2DismountVolume(IrpContext);
+ break;
+
+ case FSCTL_IS_VOLUME_MOUNTED:
+ Status = Ext2IsVolumeMounted(IrpContext);
+ break;
+
+ case FSCTL_INVALIDATE_VOLUMES:
+ Status = Ext2InvalidateVolumes(IrpContext);
+ break;
+
+#if (_WIN32_WINNT >= 0x0500)
+ case FSCTL_ALLOW_EXTENDED_DASD_IO:
+ Status = Ext2AllowExtendedDasdIo(IrpContext);
+ break;
+#endif //(_WIN32_WINNT >= 0x0500)
+
+ case FSCTL_REQUEST_OPLOCK_LEVEL_1:
+ case FSCTL_REQUEST_OPLOCK_LEVEL_2:
+ case FSCTL_REQUEST_BATCH_OPLOCK:
+ case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
+ case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
+ case FSCTL_OPLOCK_BREAK_NOTIFY:
+ case FSCTL_OPLOCK_BREAK_ACK_NO_2:
+
+ Status = Ext2OplockRequest(IrpContext);
+ break;
+
+ case FSCTL_IS_VOLUME_DIRTY:
+ Status = Ext2IsVolumeDirty(IrpContext);
+ break;
+
+ case FSCTL_QUERY_RETRIEVAL_POINTERS:
+ Status = Ext2QueryRetrievalPointers(IrpContext);
+ break;
+
+ case FSCTL_GET_RETRIEVAL_POINTERS:
+ Status = Ext2GetRetrievalPointers(IrpContext);
+ break;
+
+ case FSCTL_GET_RETRIEVAL_POINTER_BASE:
+ Status = Ext2GetRetrievalPointerBase(IrpContext);
+ break;
+
+ default:
+
+ DEBUG(DL_INF, ( "Ext2UserFsRequest: Invalid User Request: %xh.\n", FsControlCode));
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+
+ return Status;
+}
+
+BOOLEAN
+Ext2IsMediaWriteProtected (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PDEVICE_OBJECT TargetDevice
+)
+{
+ PIRP Irp;
+ KEVENT Event;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatus;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE,
+ TargetDevice,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ FALSE,
+ &Event,
+ &IoStatus );
+
+ if (Irp == NULL) {
+ return FALSE;
+ }
+
+ SetFlag(IoGetNextIrpStackLocation(Irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME);
+
+ Status = IoCallDriver(TargetDevice, Irp);
+
+ if (Status == STATUS_PENDING) {
+
+ (VOID) KeWaitForSingleObject( &Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ (PLARGE_INTEGER)NULL );
+
+ Status = IoStatus.Status;
+ }
+
+ return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED);
+}
+
+NTSTATUS
+Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PDEVICE_OBJECT MainDeviceObject;
+ BOOLEAN GlobalDataResourceAcquired = FALSE;
+ PIRP Irp;
+ PIO_STACK_LOCATION IoStackLocation;
+ PDEVICE_OBJECT TargetDeviceObject;
+ NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
+ PDEVICE_OBJECT VolumeDeviceObject = NULL;
+ PEXT2_VCB Vcb = NULL, OldVcb = NULL;
+ PVPB OldVpb = NULL, Vpb = NULL;
+ PEXT2_SUPER_BLOCK Ext2Sb = NULL;
+ ULONG dwBytes;
+ DISK_GEOMETRY DiskGeometry;
+
+ __try {
+
+ ASSERT(IrpContext != NULL);
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ MainDeviceObject = IrpContext->DeviceObject;
+
+ //
+ // Make sure we can wait.
+ //
+
+ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+
+ //
+ // This request is only allowed on the main device object
+ //
+ if (!IsExt2FsDevice(MainDeviceObject)) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ __leave;
+ }
+
+ if (IsFlagOn(Ext2Global->Flags, EXT2_UNLOAD_PENDING)) {
+ Status = STATUS_UNRECOGNIZED_VOLUME;
+ __leave;
+ }
+
+#if 0
+ if (IrpContext->RealDevice->Size >= sizeof(ULONG) + sizeof(DEVICE_OBJECT) &&
+ *((PULONG)IrpContext->RealDevice->DeviceExtension) == 'DSSA') {
+ } else {
+ Status = STATUS_UNRECOGNIZED_VOLUME;
+ __leave;
+ }
+#endif
+
+ Irp = IrpContext->Irp;
+ IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+ TargetDeviceObject =
+ IoStackLocation->Parameters.MountVolume.DeviceObject;
+
+ dwBytes = sizeof(DISK_GEOMETRY);
+ Status = Ext2DiskIoControl(
+ TargetDeviceObject,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ &DiskGeometry,
+ &dwBytes );
+
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+
+ Status = IoCreateDevice(
+ MainDeviceObject->DriverObject,
+ sizeof(EXT2_VCB),
+ NULL,
+ FILE_DEVICE_DISK_FILE_SYSTEM,
+ 0,
+ FALSE,
+ &VolumeDeviceObject );
+
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+ INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
+
+#ifdef _PNP_POWER_
+ /* don't care about power management requests */
+ VolumeDeviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE;
+#endif
+
+ VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
+ ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
+
+/*
+ These are for buffer-address alignment requirements.
+ Never do this check, unless you want fail user requests :)
+
+ if (TargetDeviceObject->AlignmentRequirement >
+ VolumeDeviceObject->AlignmentRequirement) {
+
+ VolumeDeviceObject->AlignmentRequirement =
+ TargetDeviceObject->AlignmentRequirement;
+ }
+
+ if (DiskGeometry.BytesPerSector - 1 >
+ VolumeDeviceObject->AlignmentRequirement) {
+ VolumeDeviceObject->AlignmentRequirement =
+ DiskGeometry.BytesPerSector - 1;
+ TargetDeviceObject->AlignmentRequirement =
+ DiskGeometry.BytesPerSector - 1;
+ }
+*/
+ (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject =
+ VolumeDeviceObject;
+ Vpb = IoStackLocation->Parameters.MountVolume.Vpb;
+
+ Vcb = (PEXT2_VCB) VolumeDeviceObject->DeviceExtension;
+
+ RtlZeroMemory(Vcb, sizeof(EXT2_VCB));
+ Vcb->Identifier.Type = EXT2VCB;
+ Vcb->Identifier.Size = sizeof(EXT2_VCB);
+ Vcb->TargetDeviceObject = TargetDeviceObject;
+ Vcb->DiskGeometry = DiskGeometry;
+ InitializeListHead(&Vcb->Next);
+
+ Status = Ext2LoadSuper(Vcb, FALSE, &Ext2Sb);
+ if (!NT_SUCCESS(Status)) {
+ Vcb = NULL;
+ Status = STATUS_UNRECOGNIZED_VOLUME;
+ __leave;
+ }
+ ASSERT (NULL != Ext2Sb);
+
+ /* check Linux Ext2/Ext3 volume magic */
+ if (Ext2Sb->s_magic == EXT2_SUPER_MAGIC) {
+ DEBUG(DL_INF, ( "Volume of ext2 file system is found.\n"));
+ } else {
+ Status = STATUS_UNRECOGNIZED_VOLUME;
+ Vcb = NULL;
+ __leave;
+ }
+
+ DEBUG(DL_DBG, ("Ext2MountVolume: DevObject=%p Vcb=%p\n", VolumeDeviceObject, Vcb));
+
+ /* initialize Vcb structure */
+ Status = Ext2InitializeVcb( IrpContext, Vcb, Ext2Sb,
+ TargetDeviceObject,
+ VolumeDeviceObject, Vpb);
+
+ if (NT_SUCCESS(Status)) {
+
+ PLIST_ENTRY List;
+
+ ExAcquireResourceExclusiveLite(&(Ext2Global->Resource), TRUE);
+ GlobalDataResourceAcquired = TRUE;
+
+ for (List = Ext2Global->VcbList.Flink;
+ List != &Ext2Global->VcbList;
+ List = List->Flink) {
+
+ OldVcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
+ OldVpb = OldVcb->Vpb;
+
+ /* in case we are already in the queue, should not happen */
+ if (OldVpb == Vpb) {
+ continue;
+ }
+
+ if ( (OldVpb->SerialNumber == Vpb->SerialNumber) &&
+ (!IsMounted(OldVcb)) && (IsFlagOn(OldVcb->Flags, VCB_NEW_VPB)) &&
+ (OldVpb->RealDevice == TargetDeviceObject) &&
+ (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) &&
+ (RtlEqualMemory(&OldVpb->VolumeLabel[0],
+ &Vpb->VolumeLabel[0],
+ Vpb->VolumeLabelLength)) &&
+ (RtlEqualMemory(&OldVcb->SuperBlock->s_uuid[0],
+ &Vcb->SuperBlock->s_uuid[0], 16)) ) {
+ ClearFlag(OldVcb->Flags, VCB_MOUNTED);
+ }
+ }
+
+ if (!ext4_superblock_csum_verify(&Vcb->sb, Ext2Sb)) {
+ DbgPrint("Found ext4 filesystem with invalid superblock checksum. Run e2fsck?\n");
+ }
+
+ SetLongFlag(Vcb->Flags, VCB_MOUNTED);
+ SetFlag(Vcb->Vpb->Flags, VPB_MOUNTED);
+ Ext2InsertVcb(Vcb);
+ Vcb = NULL;
+ Vpb = NULL;
+ ObDereferenceObject(TargetDeviceObject);
+
+ } else {
+
+ Vcb = NULL;
+ }
+
+ } __finally {
+
+ if (GlobalDataResourceAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ }
+
+ if (!NT_SUCCESS(Status)) {
+
+ if (!NT_SUCCESS(Status)) {
+ if ( Vpb != NULL ) {
+ Vpb->DeviceObject = NULL;
+ }
+ }
+
+ if (Vcb) {
+ Ext2DestroyVcb(Vcb);
+ } else {
+ if (Ext2Sb) {
+ Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC);
+ }
+ if (VolumeDeviceObject) {
+ IoDeleteDevice(VolumeDeviceObject);
+ DEC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB));
+ }
+ }
+ }
+
+ if (!IrpContext->ExceptionInProgress) {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ return Status;
+}
+
+VOID
+Ext2VerifyVcb (IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb )
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ BOOLEAN bVerify = FALSE;
+ ULONG ChangeCount = 0;
+ ULONG dwBytes;
+
+ PIRP Irp;
+ PEXTENDED_IO_STACK_LOCATION IrpSp;
+
+ __try {
+
+ ASSERT(IrpContext != NULL);
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ Irp = IrpContext->Irp;
+ IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp);
+
+ bVerify = IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
+
+ if ( (IsFlagOn(Vcb->Flags, VCB_REMOVABLE_MEDIA) ||
+ IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) && !bVerify ) {
+
+ dwBytes = sizeof(ULONG);
+ Status = Ext2DiskIoControl(
+ Vcb->TargetDeviceObject,
+ IOCTL_DISK_CHECK_VERIFY,
+ NULL,
+ 0,
+ &ChangeCount,
+ &dwBytes );
+
+ if ( STATUS_VERIFY_REQUIRED == Status ||
+ STATUS_DEVICE_NOT_READY == Status ||
+ STATUS_NO_MEDIA_IN_DEVICE == Status ||
+ (NT_SUCCESS(Status) &&
+ (ChangeCount != Vcb->ChangeCount))) {
+
+ KIRQL Irql;
+
+ IoAcquireVpbSpinLock(&Irql);
+ if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
+ SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
+ }
+ IoReleaseVpbSpinLock(Irql);
+
+ } else {
+
+ if (!NT_SUCCESS(Status)) {
+ Ext2NormalizeAndRaiseStatus(IrpContext, Status);
+ }
+ }
+ }
+
+ if ( IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) {
+ IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
+ Ext2NormalizeAndRaiseStatus ( IrpContext,
+ STATUS_VERIFY_REQUIRED );
+ }
+
+ if (IsMounted(Vcb)) {
+
+ if ( (IrpContext->MajorFunction == IRP_MJ_WRITE) ||
+ (IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) ||
+ (IrpContext->MajorFunction == IRP_MJ_SET_EA) ||
+ (IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) ||
+ (IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) ||
+ (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
+ IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST &&
+ IrpSp->Parameters.FileSystemControl.FsControlCode ==
+ FSCTL_MARK_VOLUME_DIRTY)) {
+
+ if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) {
+
+ KIRQL Irql;
+
+ IoAcquireVpbSpinLock(&Irql);
+ if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) {
+ SetFlag (Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
+ }
+ IoReleaseVpbSpinLock(Irql);
+
+ IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice );
+
+ Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED);
+ }
+ }
+ }
+
+ } __finally {
+
+ }
+
+}
+
+
+NTSTATUS
+Ext2VerifyVolume (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ PEXT2_SUPER_BLOCK ext2_sb = NULL;
+ PEXT2_VCB Vcb = NULL;
+ BOOLEAN VcbResourceAcquired = FALSE;
+ PIRP Irp;
+ ULONG ChangeCount = 0;
+ ULONG dwBytes;
+
+ __try {
+
+ ASSERT(IrpContext != NULL);
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ DeviceObject = IrpContext->DeviceObject;
+ //
+ // This request is not allowed on the main device object
+ //
+ if (IsExt2FsDevice(DeviceObject)) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ __leave;
+ }
+
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+ ASSERT(Vcb != NULL);
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+
+ VcbResourceAcquired =
+ ExAcquireResourceExclusiveLite(
+ &Vcb->MainResource,
+ TRUE );
+
+ if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) {
+ Status = STATUS_SUCCESS;
+ __leave;
+ }
+
+ if (!IsMounted(Vcb)) {
+ Status = STATUS_WRONG_VOLUME;
+ __leave;
+ }
+
+ dwBytes = sizeof(ULONG);
+ Status = Ext2DiskIoControl(
+ Vcb->TargetDeviceObject,
+ IOCTL_DISK_CHECK_VERIFY,
+ NULL,
+ 0,
+ &ChangeCount,
+ &dwBytes );
+
+
+ if (!NT_SUCCESS(Status)) {
+ Status = STATUS_WRONG_VOLUME;
+ __leave;
+ } else {
+ Vcb->ChangeCount = ChangeCount;
+ }
+
+ Irp = IrpContext->Irp;
+
+ Status = Ext2LoadSuper(Vcb, TRUE, &ext2_sb);
+
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+
+ ASSERT(NULL != ext2_sb);
+ if ((ext2_sb->s_magic == EXT2_SUPER_MAGIC) &&
+ (memcmp(ext2_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) &&
+ (memcmp(ext2_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)) {
+
+ ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
+
+ if (Ext2IsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) {
+ SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
+ } else {
+ ClearLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
+ }
+
+ DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify succeeded.\n"));
+
+ } else {
+
+ Status = STATUS_WRONG_VOLUME;
+ Ext2PurgeVolume(Vcb, FALSE);
+
+ SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
+ ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME);
+
+ DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify failed.\n"));
+ }
+
+ } __finally {
+
+ if (ext2_sb)
+ Ext2FreePool(ext2_sb, EXT2_SB_MAGIC);
+
+ if (VcbResourceAcquired) {
+ ExReleaseResourceLite(&Vcb->MainResource);
+ }
+
+ if (!IrpContext->ExceptionInProgress) {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2IsVolumeMounted (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PDEVICE_OBJECT DeviceObject;
+ PEXT2_VCB Vcb = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ ASSERT(IrpContext);
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+
+ DeviceObject = IrpContext->DeviceObject;
+
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+
+ ASSERT(IsMounted(Vcb));
+
+ Ext2VerifyVcb (IrpContext, Vcb);
+
+ Ext2CompleteIrpContext(IrpContext, Status);
+
+ return Status;
+}
+
+
+NTSTATUS
+Ext2DismountVolume (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ PDEVICE_OBJECT DeviceObject;
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ PEXT2_VCB Vcb = NULL;
+ BOOLEAN VcbResourceAcquired = FALSE;
+
+ __try {
+
+ ASSERT(IrpContext != NULL);
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ DeviceObject = IrpContext->DeviceObject;
+
+ //
+ // This request is not allowed on the main device object
+ //
+ if (IsExt2FsDevice(DeviceObject)) {
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ __leave;
+ }
+
+ Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension;
+
+ ASSERT(Vcb != NULL);
+
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+
+ ASSERT(IsMounted(Vcb));
+
+ ExAcquireResourceExclusiveLite(
+ &Vcb->MainResource,
+ TRUE );
+
+ VcbResourceAcquired = TRUE;
+
+ if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
+ Status = STATUS_VOLUME_DISMOUNTED;
+ __leave;
+ }
+
+ Ext2FlushFiles(IrpContext, Vcb, FALSE);
+ Ext2FlushVolume(IrpContext, Vcb, FALSE);
+
+ ExReleaseResourceLite(&Vcb->MainResource);
+ VcbResourceAcquired = FALSE;
+
+ Ext2PurgeVolume(Vcb, TRUE);
+ Ext2CheckDismount(IrpContext, Vcb, TRUE);
+
+ DEBUG(DL_INF, ( "Ext2Dismount: Volume dismount pending.\n"));
+ Status = STATUS_SUCCESS;
+
+ } __finally {
+
+ if (VcbResourceAcquired) {
+ ExReleaseResourceLite(&Vcb->MainResource);
+ }
+
+ if (!IrpContext->ExceptionInProgress) {
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+ }
+
+ return Status;
+}
+
+BOOLEAN
+Ext2CheckDismount (
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN BOOLEAN bForce )
+{
+ KIRQL Irql;
+ PVPB Vpb = Vcb->Vpb, NewVpb = NULL;
+ BOOLEAN bDeleted = FALSE, bTearDown = FALSE;
+ ULONG UnCleanCount = 0;
+
+ NewVpb = ExAllocatePoolWithTag(NonPagedPool, VPB_SIZE, TAG_VPB);
+ if (NewVpb == NULL) {
+ DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n"));
+ return FALSE;
+ }
+ DEBUG(DL_DBG, ("Ext2CheckDismount: NewVpb allocated: %p\n", NewVpb));
+ INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
+ memset(NewVpb, '_', VPB_SIZE);
+ RtlZeroMemory(NewVpb, sizeof(VPB));
+
+ ExAcquireResourceExclusiveLite(
+ &Ext2Global->Resource, TRUE );
+
+ ExAcquireResourceExclusiveLite(
+ &Vcb->MainResource, TRUE );
+
+ if (IrpContext &&
+ IrpContext->MajorFunction == IRP_MJ_CREATE &&
+ IrpContext->RealDevice == Vcb->RealDevice) {
+ UnCleanCount = 2;
+ } else {
+ UnCleanCount = 1;
+ }
+
+ IoAcquireVpbSpinLock (&Irql);
+
+ DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n",
+ Vpb, Vpb->ReferenceCount, Vpb->RealDevice));
+
+ if (Vpb->ReferenceCount <= UnCleanCount) {
+
+ if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) {
+
+ ClearFlag(Vpb->Flags, VPB_MOUNTED);
+ ClearFlag(Vpb->Flags, VPB_LOCKED);
+
+ if ((Vcb->RealDevice != Vpb->RealDevice) &&
+ (Vcb->RealDevice->Vpb == Vpb)) {
+ SetFlag(Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING);
+ SetFlag(Vpb->Flags, VPB_PERSISTENT );
+ }
+
+ Ext2RemoveVcb(Vcb);
+ SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING);
+ }
+
+ if (Vpb->ReferenceCount) {
+ bTearDown = TRUE;
+ } else {
+ bDeleted = TRUE;
+ Vpb->DeviceObject = NULL;
+ }
+
+ DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb: %p bDeleted=%d bTearDown=%d\n",
+ Vpb, bDeleted, bTearDown));
+
+
+ } else if (bForce) {
+
+ DEBUG(DL_DBG, ( "Ext2CheckDismount: New/Old Vpb %p/%p Realdevice = %p\n",
+ NewVpb, Vcb->Vpb, Vpb->RealDevice));
+
+ /* keep vpb president and later we'll free it */
+ SetFlag(Vpb->Flags, VPB_PERSISTENT);
+
+ Vcb->Vpb2 = Vcb->Vpb;
+ NewVpb->Type = IO_TYPE_VPB;
+ NewVpb->Size = sizeof(VPB);
+ NewVpb->Flags = Vpb->Flags & VPB_REMOVE_PENDING;
+ NewVpb->RealDevice = Vpb->RealDevice;
+ NewVpb->RealDevice->Vpb = NewVpb;
+ NewVpb = NULL;
+ ClearFlag(Vpb->Flags, VPB_MOUNTED);
+ SetLongFlag(Vcb->Flags, VCB_NEW_VPB);
+ ClearLongFlag(Vcb->Flags, VCB_MOUNTED);
+ }
+
+ IoReleaseVpbSpinLock(Irql);
+
+ ExReleaseResourceLite(&Vcb->MainResource);
+ ExReleaseResourceLite(&Ext2Global->Resource);
+
+ if (bTearDown) {
+ DEBUG(DL_DBG, ( "Ext2CheckDismount: Tearing vcb %p ...\n", Vcb));
+ Ext2TearDownStream(Vcb);
+ }
+
+ if (bDeleted) {
+ DEBUG(DL_DBG, ( "Ext2CheckDismount: Deleting vcb %p ...\n", Vcb));
+ Ext2DestroyVcb(Vcb);
+ }
+
+ if (NewVpb != NULL) {
+ DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing new Vpb %p\n", NewVpb));
+ ExFreePoolWithTag(NewVpb, TAG_VPB);
+ DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB));
+ }
+
+ return bDeleted;
+}
+
+NTSTATUS
+Ext2PurgeVolume (IN PEXT2_VCB Vcb,
+ IN BOOLEAN FlushBeforePurge )
+{
+ PEXT2_FCB Fcb;
+ LIST_ENTRY List, *Next;
+
+ BOOLEAN VcbResourceAcquired = FALSE;
+ BOOLEAN FcbResourceAcquired = FALSE;
+ BOOLEAN gdResourceAcquired = FALSE;
+
+ __try {
+
+ ASSERT(Vcb != NULL);
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+
+ ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE);
+ VcbResourceAcquired = TRUE;
+
+ if (IsVcbReadOnly(Vcb)) {
+ FlushBeforePurge = FALSE;
+ }
+
+ InitializeListHead(&List);
+
+ ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+ FcbResourceAcquired = TRUE;
+
+ while (!IsListEmpty(&Vcb->FcbList)) {
+
+ Next = RemoveHeadList(&Vcb->FcbList);
+ Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next);
+
+ DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n",
+ &Fcb->Mcb->FullName, Fcb->ReferenceCount));
+ InsertTailList(&List, &Fcb->Next);
+ }
+
+ while (!IsListEmpty(&List)) {
+
+ Next = RemoveHeadList(&List);
+ Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next);
+
+ if (ExAcquireResourceExclusiveLite(
+ &Fcb->MainResource,
+ TRUE )) {
+
+ Ext2PurgeFile(Fcb, FlushBeforePurge);
+
+ if (Fcb->ReferenceCount <= 1) {
+ Fcb->TsDrop.QuadPart = 0;
+ InsertHeadList(&Vcb->FcbList, &Fcb->Next);
+ } else {
+ InsertTailList(&Vcb->FcbList, &Fcb->Next);
+ }
+ ExReleaseResourceLite(&Fcb->MainResource);
+ }
+ }
+
+ if (FcbResourceAcquired) {
+ ExReleaseResourceLite(&Vcb->FcbLock);
+ FcbResourceAcquired = FALSE;
+ }
+
+ /* acquire bd lock to avoid bh creation */
+ ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE);
+ gdResourceAcquired = TRUE;
+
+ /* discard buffer_headers for group_desc */
+ Ext2DropBH(Vcb);
+
+ if (FlushBeforePurge) {
+ ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE);
+ ExReleaseResourceLite(&Vcb->PagingIoResource);
+
+ CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL);
+ }
+
+ if (Vcb->SectionObject.ImageSectionObject) {
+ MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite);
+ }
+
+ if (Vcb->SectionObject.DataSectionObject) {
+ CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE);
+ }
+
+ DEBUG(DL_INF, ( "Ext2PurgeVolume: Volume flushed and purged.\n"));
+
+ } __finally {
+
+ if (gdResourceAcquired) {
+ ExReleaseResourceLite(&Vcb->sbi.s_gd_lock);
+ }
+
+ if (FcbResourceAcquired) {
+ ExReleaseResourceLite(&Vcb->FcbLock);
+ }
+
+ if (VcbResourceAcquired) {
+ ExReleaseResourceLite(&Vcb->MainResource);
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+Ext2PurgeFile ( IN PEXT2_FCB Fcb,
+ IN BOOLEAN FlushBeforePurge )
+{
+ IO_STATUS_BLOCK IoStatus;
+
+ ASSERT(Fcb != NULL);
+
+ ASSERT((Fcb->Identifier.Type == EXT2FCB) &&
+ (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+
+
+ if (!IsVcbReadOnly(Fcb->Vcb) && FlushBeforePurge) {
+ DEBUG(DL_INF, ( "Ext2PurgeFile: CcFlushCache on %wZ.\n",
+ &Fcb->Mcb->FullName));
+ ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE);
+ ExReleaseResourceLite(&Fcb->PagingIoResource);
+ CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus);
+ ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED);
+ }
+
+ if (Fcb->SectionObject.ImageSectionObject) {
+ DEBUG(DL_INF, ( "Ext2PurgeFile: MmFlushImageSection on %wZ.\n",
+ &Fcb->Mcb->FullName));
+ MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite);
+ }
+
+ if (Fcb->SectionObject.DataSectionObject) {
+ DEBUG(DL_INF, ( "Ext2PurgeFile: CcPurgeCacheSection on %wZ.\n",
+ &Fcb->Mcb->FullName));
+ CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+Ext2FileSystemControl (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ NTSTATUS Status;
+
+ ASSERT(IrpContext);
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ switch (IrpContext->MinorFunction) {
+
+ case IRP_MN_USER_FS_REQUEST:
+ Status = Ext2UserFsRequest(IrpContext);
+ break;
+
+ case IRP_MN_MOUNT_VOLUME:
+ Status = Ext2MountVolume(IrpContext);
+ break;
+
+ case IRP_MN_VERIFY_VOLUME:
+ Status = Ext2VerifyVolume(IrpContext);
+ break;
+
+ default:
+
+ DEBUG(DL_ERR, ( "Ext2FilsSystemControl: Invalid Device Request.\n"));
+ Status = STATUS_INVALID_DEVICE_REQUEST;
+ Ext2CompleteIrpContext(IrpContext, Status);
+ }
+
+ return Status;
+}
diff --git a/Ext4Fsd/include/ext2fs.h b/Ext4Fsd/include/ext2fs.h
index 2830893..546b45a 100644
--- a/Ext4Fsd/include/ext2fs.h
+++ b/Ext4Fsd/include/ext2fs.h
@@ -17,9 +17,6 @@
#include
#include
#include
-#include
-#include
-#include
#include
/* DEBUG ****************************************************************/
@@ -2021,10 +2018,10 @@ loff_t ext3_max_size(int blkbits, int has_huge_files);
loff_t ext3_max_bitmap_size(int bits, int has_huge_files);
-__le16 ext4_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group,
+/*__le16 ext4_group_desc_csum(struct ext3_sb_info *sbi, __u32 block_group,
struct ext4_group_desc *gdp);
int ext4_group_desc_csum_verify(struct ext3_sb_info *sbi, __u32 block_group,
- struct ext4_group_desc *gdp);
+ struct ext4_group_desc *gdp);*/
ext3_fsblk_t descriptor_loc(struct super_block *sb,
ext3_fsblk_t logical_sb_block, unsigned int nr);
diff --git a/Ext4Fsd/include/linux/ext3_jbd.h b/Ext4Fsd/include/linux/ext3_jbd.h
index acee54f..37117ce 100644
--- a/Ext4Fsd/include/linux/ext3_jbd.h
+++ b/Ext4Fsd/include/linux/ext3_jbd.h
@@ -17,7 +17,6 @@
#include
#include
-#include
#define EXT3_JOURNAL(inode) (EXT3_SB((inode)->i_sb)->s_journal)
diff --git a/Ext4Fsd/include/linux/ext4.h b/Ext4Fsd/include/linux/ext4.h
index 2aa4a39..454b8e9 100644
--- a/Ext4Fsd/include/linux/ext4.h
+++ b/Ext4Fsd/include/linux/ext4.h
@@ -1,122 +1,3394 @@
-#ifndef _EXT4_H
-#define _EXT4_H
-
-#include
-/* Temporarily we need this. */
-#include
-
-typedef unsigned __int16 uint16_t;
-typedef unsigned __int32 uint32_t;
-typedef unsigned __int64 uint64_t;
-
-typedef uint32_t ext4_lblk_t;
-typedef uint64_t ext4_fsblk_t;
-
-/*
- * Flags used by ext4_map_blocks()
- */
- /* Allocate any needed blocks and/or convert an unwritten
- extent to be an initialized ext4 */
-#define EXT4_GET_BLOCKS_CREATE 0x0001
- /* Request the creation of an unwritten extent */
-#define EXT4_GET_BLOCKS_UNWRIT_EXT 0x0002
-#define EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT (EXT4_GET_BLOCKS_UNWRIT_EXT|\
- EXT4_GET_BLOCKS_CREATE)
- /* Caller is from the delayed allocation writeout path
- * finally doing the actual allocation of delayed blocks */
-#define EXT4_GET_BLOCKS_DELALLOC_RESERVE 0x0004
- /* caller is from the direct IO path, request to creation of an
- unwritten extents if not allocated, split the unwritten
- extent if blocks has been preallocated already*/
-#define EXT4_GET_BLOCKS_PRE_IO 0x0008
-#define EXT4_GET_BLOCKS_CONVERT 0x0010
-#define EXT4_GET_BLOCKS_IO_CREATE_EXT (EXT4_GET_BLOCKS_PRE_IO|\
- EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT)
- /* Convert extent to initialized after IO complete */
-#define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\
- EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT)
- /* Eventual metadata allocation (due to growing extent tree)
- * should not fail, so try to use reserved blocks for that.*/
-#define EXT4_GET_BLOCKS_METADATA_NOFAIL 0x0020
- /* Don't normalize allocation size (used for fallocate) */
-#define EXT4_GET_BLOCKS_NO_NORMALIZE 0x0040
- /* Request will not result in inode size update (user for fallocate) */
-#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
- /* Do not take i_data_sem locking in ext4_map_blocks */
-#define EXT4_GET_BLOCKS_NO_LOCK 0x0100
- /* Do not put hole in extent cache */
-#define EXT4_GET_BLOCKS_NO_PUT_HOLE 0x0200
- /* Convert written extents to unwritten */
-#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0400
-
-/*
- * The bit position of these flags must not overlap with any of the
- * EXT4_GET_BLOCKS_*. They are used by ext4_find_extent(),
- * read_extent_tree_block(), ext4_split_extent_at(),
- * ext4_ext_insert_extent(), and ext4_ext_create_new_leaf().
- * EXT4_EX_NOCACHE is used to indicate that the we shouldn't be
- * caching the extents when reading from the extent tree while a
- * truncate or punch hole operation is in progress.
- */
-#define EXT4_EX_NOCACHE 0x40000000
-#define EXT4_EX_FORCE_CACHE 0x20000000
-
-/*
- * Flags used by ext4_free_blocks
- */
-#define EXT4_FREE_BLOCKS_METADATA 0x0001
-#define EXT4_FREE_BLOCKS_FORGET 0x0002
-#define EXT4_FREE_BLOCKS_VALIDATED 0x0004
-#define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008
-#define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER 0x0010
-#define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER 0x0020
-
-/*
- * Flags used in mballoc's allocation_context flags field.
- *
- * Also used to show what's going on for debugging purposes when the
- * flag field is exported via the traceport interface
- */
-
-/* prefer goal again. length */
-#define EXT4_MB_HINT_MERGE 0x0001
-/* blocks already reserved */
-#define EXT4_MB_HINT_RESERVED 0x0002
-/* metadata is being allocated */
-#define EXT4_MB_HINT_METADATA 0x0004
-/* first blocks in the file */
-#define EXT4_MB_HINT_FIRST 0x0008
-/* search for the best chunk */
-#define EXT4_MB_HINT_BEST 0x0010
-/* data is being allocated */
-#define EXT4_MB_HINT_DATA 0x0020
-/* don't preallocate (for tails) */
-#define EXT4_MB_HINT_NOPREALLOC 0x0040
-/* allocate for locality group */
-#define EXT4_MB_HINT_GROUP_ALLOC 0x0080
-/* allocate goal blocks or none */
-#define EXT4_MB_HINT_GOAL_ONLY 0x0100
-/* goal is meaningful */
-#define EXT4_MB_HINT_TRY_GOAL 0x0200
-/* blocks already pre-reserved by delayed allocation */
-#define EXT4_MB_DELALLOC_RESERVED 0x0400
-/* We are doing stream allocation */
-#define EXT4_MB_STREAM_ALLOC 0x0800
-/* Use reserved root blocks if needed */
-#define EXT4_MB_USE_ROOT_BLOCKS 0x1000
-/* Use blocks from reserved pool */
-#define EXT4_MB_USE_RESERVED 0x2000
-
-
-#define ext4_sb_info ext3_sb_info
-
-static inline struct ext4_sb_info * EXT4_SB(struct super_block *sb)
-{
- return sb->s_fs_info;
-}
-#define EXT4_I(i) (i)
-
-#include
-#include
-
-#endif /* _EXT4_H */
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ext4.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ * from
+ *
+ * linux/include/linux/minix_fs.h
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ */
+
+#ifndef _EXT4_H
+#define _EXT4_H
+
+//
+// Use 1 byte packing of on-disk structures
+//
+#include
+
+#include
+//#include
+#include
+//#include
+//#include
+//#include
+#include
+//#include
+#include
+#include
+#include
+//#include
+//#include
+//#include
+//#include
+//#include
+//#include
+//#include
+//#include
+#ifdef __KERNEL__
+//#include
+#endif
+typedef struct handle_s handle_t;
+typedef unsigned long long ext4_fsblk_t;
+#include
+typedef unsigned __int16 uint16_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#include
+
+#define __FS_HAS_ENCRYPTION IS_ENABLED(CONFIG_EXT4_FS_ENCRYPTION)
+//#include
+
+//#include
+
+/*
+ * First declarations to be able to compile the Windows driver with
+ * ext4.h from Linux. When the driver is changed to use ext4_ names
+ * instead of ext3_ and ext2_ many of these can be removed.
+ */
+
+#define S_IFMT 0x0F000 /* 017 0000 */
+#define S_IFSOCK 0x0C000 /* 014 0000 */
+#define S_IFLNK 0x0A000 /* 012 0000 */
+#define S_IFREG 0x08000 /* 010 0000 */
+#define S_IFBLK 0x06000 /* 006 0000 */
+#define S_IFDIR 0x04000 /* 004 0000 */
+#define S_IFCHR 0x02000 /* 002 0000 */
+#define S_IFIFO 0x01000 /* 001 0000 */
+
+#define S_ISUID 0x00800 /* 000 4000 */
+#define S_ISGID 0x00400 /* 000 2000 */
+#define S_ISVTX 0x00200 /* 000 1000 */
+
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#define S_ISFIL(m) (((m) & S_IFMT) == S_IFFIL)
+#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
+
+#define S_NOQUOTA 32 /* Inode is not counted to quota */
+#define IS_NOQUOTA(inode) ((inode)->i_flags & S_NOQUOTA)
+
+#undef BUG_ON
+#define BUG_ON(x)
+#define BUILD_BUG_ON(x)
+#define EXT4_I(inode) (inode)
+#define INODE_HAS_EXTENT(i) ((i)->i_flags & EXT2_EXTENTS_FL)
+#define EXT2_GOOD_OLD_INODE_SIZE EXT4_GOOD_OLD_INODE_SIZE
+#define EXT3_GOOD_OLD_REV EXT4_GOOD_OLD_REV
+#define EXT2_ROOT_INO EXT4_ROOT_INO
+#define EXT2_EXTENTS_FL EXT4_EXTENTS_FL
+#define EXT2_NAME_LEN EXT4_NAME_LEN
+#define EXT3_NAME_LEN EXT4_NAME_LEN
+#define EXT4_NAME_LEN 255
+#define EXT2_MIN_BLOCK_SIZE EXT4_MIN_BLOCK_SIZE
+#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE EXT4_FEATURE_RO_COMPAT_LARGE_FILE
+#define EXT2_DIR_REC_LEN EXT4_DIR_REC_LEN
+#define EXT3_DIR_REC_LEN EXT4_DIR_REC_LEN
+#define EXT2_NDIR_BLOCKS EXT4_NDIR_BLOCKS
+#define EXT3_NDIR_BLOCKS EXT4_NDIR_BLOCKS
+#define EXT3_BLOCKS_PER_GROUP EXT4_BLOCKS_PER_GROUP
+#define EXT3_INODES_PER_GROUP EXT4_INODES_PER_GROUP
+#define EXT3_BLOCK_SIZE_BITS EXT4_BLOCK_SIZE_BITS
+#define EXT3_HTREE_EOF 0x7fffffff
+#define EXT3_DIRENT_LUFID 0x10
+
+#define ext3_super_block ext4_super_block
+#define ext3_inode ext4_inode
+#define ext3_dir_entry_2 ext4_dir_entry_2
+#define ext3_sb_info ext4_sb_info
+#define ext3_group_t ext4_group_t
+#define ext3_lblk_t ext4_lblk_t
+
+#define s_blocks_count s_blocks_count_lo
+#define s_r_blocks_count s_r_blocks_count_lo
+#define s_free_blocks_count s_free_blocks_count_lo
+#define s_blocks_count s_blocks_count_lo
+#define s_free_blocks_count s_free_blocks_count_lo
+#define s_r_blocks_count s_r_blocks_count_lo
+
+#define bg_block_bitmap bg_block_bitmap_lo
+#define bg_inode_bitmap bg_inode_bitmap_lo
+#define bg_inode_table bg_inode_table_lo
+#define bg_free_blocks_count bg_free_blocks_count_lo
+#define bg_free_inodes_count bg_free_inodes_count_lo
+#define bg_used_dirs_count bg_used_dirs_count_lo
+#define bg_itable_unused bg_itable_unused_lo
+
+#define EXT3_MIN_BLOCK_SIZE EXT4_MIN_BLOCK_SIZE
+#define EXT3_FEATURE_COMPAT_DIR_INDEX EXT4_FEATURE_COMPAT_DIR_INDEX
+#define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER
+#define EXT3_FEATURE_INCOMPAT_FILETYPE EXT4_FEATURE_INCOMPAT_FILETYPE
+#define EXT3_FEATURE_INCOMPAT_RECOVER EXT4_FEATURE_INCOMPAT_RECOVER
+#define EXT4_HAS_RO_COMPAT_FEATURE EXT3_HAS_RO_COMPAT_FEATURE
+#define EXT4_HAS_INCOMPAT_FEATURE EXT3_HAS_INCOMPAT_FEATURE
+#define EXT3_SB EXT4_SB
+#define EXT3_I EXT4_I
+#define EXT3_INDEX_FL EXT4_INDEX_FL
+
+#define EXT3_FT_UNKNOWN EXT4_FT_UNKNOWN
+#define EXT3_FT_REG_FILE EXT4_FT_REG_FILE
+#define EXT3_FT_DIR EXT4_FT_DIR
+#define EXT3_FT_CHRDEV EXT4_FT_CHRDEV
+#define EXT3_FT_BLKDEV EXT4_FT_BLKDEV
+#define EXT3_FT_FIFO EXT4_FT_FIFO
+#define EXT3_FT_SOCK EXT4_FT_SOCK
+#define EXT3_FT_SYMLINK EXT4_FT_SYMLINK
+#define EXT3_FT_MAX EXT4_FT_MAX
+#define EXT3_FT_MASK 0xf
+
+#define EXT3_HAS_COMPAT_FEATURE(sb,mask) \
+ ( EXT3_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
+#define EXT3_HAS_RO_COMPAT_FEATURE(sb,mask) \
+ ( EXT3_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
+#define EXT3_HAS_INCOMPAT_FEATURE(sb,mask) \
+ ( EXT3_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
+#define EXT3_SET_COMPAT_FEATURE(sb,mask) \
+ EXT3_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
+#define EXT3_SET_RO_COMPAT_FEATURE(sb,mask) \
+ EXT3_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
+#define EXT3_SET_INCOMPAT_FEATURE(sb,mask) \
+ EXT3_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
+#define EXT3_CLEAR_COMPAT_FEATURE(sb,mask) \
+ EXT3_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
+#define EXT3_CLEAR_RO_COMPAT_FEATURE(sb,mask) \
+ EXT3_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
+#define EXT3_CLEAR_INCOMPAT_FEATURE(sb,mask) \
+ EXT3_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
+
+typedef unsigned long long ext3_fsblk_t;
+typedef unsigned int ssize_t, tid_t, vm_fault_t, qsize_t, kprojid_t;
+typedef unsigned __int64 atomic64_t;
+
+struct timespec64 {
+ __u64 tv_sec; /* seconds */
+ __u64 tv_nsec; /* nanoseconds */
+};
+
+struct fscrypt_str {
+ unsigned char *name;
+ __u32 len;
+};
+
+struct ext3_gd {
+ ext3_fsblk_t block;
+ struct ext4_group_desc *gd;
+ struct buffer_head *bh;
+};
+
+/* The hash is always the low bits of hash_len */
+#ifdef __LITTLE_ENDIAN
+ #define HASH_LEN_DECLARE u32 hash; u32 len
+ #define bytemask_from_count(cnt) (~(~0ul << (cnt)*8))
+#else
+ #define HASH_LEN_DECLARE u32 len; u32 hash
+ #define bytemask_from_count(cnt) (~(~0ul >> (cnt)*8))
+#endif
+
+/*
+ * "quick string" -- eases parameter passing, but more importantly
+ * saves "metadata" about the string (ie length and the hash).
+ *
+ * hash comes first so it snuggles against d_parent in the
+ * dentry.
+ */
+struct qstr {
+ union {
+ struct {
+ HASH_LEN_DECLARE;
+ };
+ u64 hash_len;
+ };
+ const unsigned char *name;
+};
+
+#define QSTR_INIT(n,l) { { { .len = l } }, .name = n }
+
+/*
+ * Ext2 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+enum {
+ EXT2_FT_UNKNOWN,
+ EXT2_FT_REG_FILE,
+ EXT2_FT_DIR,
+ EXT2_FT_CHRDEV,
+ EXT2_FT_BLKDEV,
+ EXT2_FT_FIFO,
+ EXT2_FT_SOCK,
+ EXT2_FT_SYMLINK,
+ EXT2_FT_MAX
+};
+
+#define EXT3_MAX_REC_LEN ((1<<16)-1)
+
+int ext3_release_dir (struct inode * inode, struct file * filp);
+
+/*
+ * Below follows ext4.h from the Linux 5.0 source code.
+ * struct ext4_inode_info and struct ext4_sb_info are specialized for
+ * the Windows driver, other from that there are only small changes
+ * to be able to use the include file on Windows.
+ */
+
+/*
+ * The fourth extended filesystem constants/structures
+ */
+
+/*
+ * with AGGRESSIVE_CHECK allocator runs consistency checks over
+ * structures. these checks slow things down a lot
+ */
+#define AGGRESSIVE_CHECK__
+
+/*
+ * with DOUBLE_CHECK defined mballoc creates persistent in-core
+ * bitmaps, maintains and uses them to check for double allocations
+ */
+#define DOUBLE_CHECK__
+
+/*
+ * Define EXT4FS_DEBUG to produce debug messages
+ */
+#undef EXT4FS_DEBUG
+
+/*
+ * Debug code
+ */
+#ifdef EXT4FS_DEBUG
+#define ext4_debug(f, a...) \
+ do { \
+ printk(KERN_DEBUG "EXT4-fs DEBUG (%s, %d): %s:", \
+ __FILE__, __LINE__, __func__); \
+ printk(KERN_DEBUG f, ## a); \
+ } while (0)
+#else
+#define ext4_debug(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
+#endif
+
+/*
+ * Turn on EXT_DEBUG to get lots of info about extents operations.
+ */
+#define EXT_DEBUG__
+#ifdef EXT_DEBUG
+#define ext_debug(fmt, ...) printk(fmt, ##__VA_ARGS__)
+#else
+#define ext_debug(fmt, ...) no_printk(fmt, ##__VA_ARGS__)
+#endif
+
+/* data type for block offset of block group */
+typedef int ext4_grpblk_t;
+
+/* data type for filesystem-wide blocks number */
+typedef unsigned long long ext4_fsblk_t;
+
+/* data type for file logical block number */
+typedef __u32 ext4_lblk_t;
+
+/* data type for block group number */
+typedef unsigned int ext4_group_t;
+
+enum SHIFT_DIRECTION {
+ SHIFT_LEFT = 0,
+ SHIFT_RIGHT,
+};
+
+/*
+ * Flags used in mballoc's allocation_context flags field.
+ *
+ * Also used to show what's going on for debugging purposes when the
+ * flag field is exported via the traceport interface
+ */
+
+/* prefer goal again. length */
+#define EXT4_MB_HINT_MERGE 0x0001
+/* blocks already reserved */
+#define EXT4_MB_HINT_RESERVED 0x0002
+/* metadata is being allocated */
+#define EXT4_MB_HINT_METADATA 0x0004
+/* first blocks in the file */
+#define EXT4_MB_HINT_FIRST 0x0008
+/* search for the best chunk */
+#define EXT4_MB_HINT_BEST 0x0010
+/* data is being allocated */
+#define EXT4_MB_HINT_DATA 0x0020
+/* don't preallocate (for tails) */
+#define EXT4_MB_HINT_NOPREALLOC 0x0040
+/* allocate for locality group */
+#define EXT4_MB_HINT_GROUP_ALLOC 0x0080
+/* allocate goal blocks or none */
+#define EXT4_MB_HINT_GOAL_ONLY 0x0100
+/* goal is meaningful */
+#define EXT4_MB_HINT_TRY_GOAL 0x0200
+/* blocks already pre-reserved by delayed allocation */
+#define EXT4_MB_DELALLOC_RESERVED 0x0400
+/* We are doing stream allocation */
+#define EXT4_MB_STREAM_ALLOC 0x0800
+/* Use reserved root blocks if needed */
+#define EXT4_MB_USE_ROOT_BLOCKS 0x1000
+/* Use blocks from reserved pool */
+#define EXT4_MB_USE_RESERVED 0x2000
+
+struct ext4_allocation_request {
+ /* target inode for block we're allocating */
+ struct inode *inode;
+ /* how many blocks we want to allocate */
+ unsigned int len;
+ /* logical block in target inode */
+ ext4_lblk_t logical;
+ /* the closest logical allocated block to the left */
+ ext4_lblk_t lleft;
+ /* the closest logical allocated block to the right */
+ ext4_lblk_t lright;
+ /* phys. target (a hint) */
+ ext4_fsblk_t goal;
+ /* phys. block for the closest logical allocated block to the left */
+ ext4_fsblk_t pleft;
+ /* phys. block for the closest logical allocated block to the right */
+ ext4_fsblk_t pright;
+ /* flags. see above EXT4_MB_HINT_* */
+ unsigned int flags;
+};
+
+/*
+ * Logical to physical block mapping, used by ext4_map_blocks()
+ *
+ * This structure is used to pass requests into ext4_map_blocks() as
+ * well as to store the information returned by ext4_map_blocks(). It
+ * takes less room on the stack than a struct buffer_head.
+ */
+#define EXT4_MAP_NEW (1 << BH_New)
+#define EXT4_MAP_MAPPED (1 << BH_Mapped)
+#define EXT4_MAP_UNWRITTEN (1 << BH_Unwritten)
+#define EXT4_MAP_BOUNDARY (1 << BH_Boundary)
+#define EXT4_MAP_FLAGS (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\
+ EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY)
+
+struct ext4_map_blocks {
+ ext4_fsblk_t m_pblk;
+ ext4_lblk_t m_lblk;
+ unsigned int m_len;
+ unsigned int m_flags;
+};
+
+/*
+ * Flags for ext4_io_end->flags
+ */
+#define EXT4_IO_END_UNWRITTEN 0x0001
+
+/*
+ * For converting unwritten extents on a work queue. 'handle' is used for
+ * buffered writeback.
+ */
+typedef struct ext4_io_end {
+ struct list_head list; /* per-file finished IO list */
+ handle_t *handle; /* handle reserved for extent
+ * conversion */
+ struct inode *inode; /* file being written to */
+ struct bio *bio; /* Linked list of completed
+ * bios covering the extent */
+ unsigned int flag; /* unwritten or not */
+ atomic_t count; /* reference counter */
+ loff_t offset; /* offset in the file */
+ ssize_t size; /* size of the extent */
+} ext4_io_end_t;
+
+struct ext4_io_submit {
+ struct writeback_control *io_wbc;
+ struct bio *io_bio;
+ ext4_io_end_t *io_end;
+ sector_t io_next_block;
+};
+
+/*
+ * Special inodes numbers
+ */
+#define EXT4_BAD_INO 1 /* Bad blocks inode */
+#define EXT4_ROOT_INO 2 /* Root inode */
+#define EXT4_USR_QUOTA_INO 3 /* User quota inode */
+#define EXT4_GRP_QUOTA_INO 4 /* Group quota inode */
+#define EXT4_BOOT_LOADER_INO 5 /* Boot loader inode */
+#define EXT4_UNDEL_DIR_INO 6 /* Undelete directory inode */
+#define EXT4_RESIZE_INO 7 /* Reserved group descriptors inode */
+#define EXT4_JOURNAL_INO 8 /* Journal inode */
+
+/* First non-reserved inode for old ext4 filesystems */
+#define EXT4_GOOD_OLD_FIRST_INO 11
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT4_LINK_MAX 65000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT4_MIN_BLOCK_SIZE 1024
+#define EXT4_MAX_BLOCK_SIZE 65536
+#define EXT4_MIN_BLOCK_LOG_SIZE 10
+#define EXT4_MAX_BLOCK_LOG_SIZE 16
+#define EXT4_MAX_CLUSTER_LOG_SIZE 30
+#ifdef __KERNEL__
+# define EXT4_BLOCK_SIZE(s) ((s)->s_blocksize)
+#else
+# define EXT4_BLOCK_SIZE(s) (EXT4_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#endif
+#define EXT4_ADDR_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / sizeof(__u32))
+#define EXT4_CLUSTER_SIZE(s) (EXT4_BLOCK_SIZE(s) << \
+ EXT4_SB(s)->s_cluster_bits)
+#ifdef __KERNEL__
+# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
+# define EXT4_CLUSTER_BITS(s) (EXT4_SB(s)->s_cluster_bits)
+#else
+# define EXT4_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
+#endif
+#ifdef __KERNEL__
+#define EXT4_ADDR_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_addr_per_block_bits)
+#define EXT4_INODE_SIZE(s) (EXT4_SB(s)->s_inode_size)
+#define EXT4_FIRST_INO(s) (EXT4_SB(s)->s_first_ino)
+#else
+#define EXT4_INODE_SIZE(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \
+ EXT4_GOOD_OLD_INODE_SIZE : \
+ (s)->s_inode_size)
+#define EXT4_FIRST_INO(s) (((s)->s_rev_level == EXT4_GOOD_OLD_REV) ? \
+ EXT4_GOOD_OLD_FIRST_INO : \
+ (s)->s_first_ino)
+#endif
+#define EXT4_BLOCK_ALIGN(size, blkbits) ALIGN((size), (1 << (blkbits)))
+#define EXT4_MAX_BLOCKS(size, offset, blkbits) \
+ ((EXT4_BLOCK_ALIGN(size + offset, blkbits) >> blkbits) - (offset >> \
+ blkbits))
+
+/* Translate a block number to a cluster number */
+#define EXT4_B2C(sbi, blk) ((blk) >> (sbi)->s_cluster_bits)
+/* Translate a cluster number to a block number */
+#define EXT4_C2B(sbi, cluster) ((cluster) << (sbi)->s_cluster_bits)
+/* Translate # of blks to # of clusters */
+#define EXT4_NUM_B2C(sbi, blks) (((blks) + (sbi)->s_cluster_ratio - 1) >> \
+ (sbi)->s_cluster_bits)
+/* Mask out the low bits to get the starting block of the cluster */
+#define EXT4_PBLK_CMASK(s, pblk) ((pblk) & \
+ ~((ext4_fsblk_t) (s)->s_cluster_ratio - 1))
+#define EXT4_LBLK_CMASK(s, lblk) ((lblk) & \
+ ~((ext4_lblk_t) (s)->s_cluster_ratio - 1))
+/* Get the cluster offset */
+#define EXT4_PBLK_COFF(s, pblk) ((pblk) & \
+ ((ext4_fsblk_t) (s)->s_cluster_ratio - 1))
+#define EXT4_LBLK_COFF(s, lblk) ((lblk) & \
+ ((ext4_lblk_t) (s)->s_cluster_ratio - 1))
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext4_group_desc
+{
+ __le32 bg_block_bitmap_lo; /* Blocks bitmap block */
+ __le32 bg_inode_bitmap_lo; /* Inodes bitmap block */
+ __le32 bg_inode_table_lo; /* Inodes table block */
+ __le16 bg_free_blocks_count_lo;/* Free blocks count */
+ __le16 bg_free_inodes_count_lo;/* Free inodes count */
+ __le16 bg_used_dirs_count_lo; /* Directories count */
+ __le16 bg_flags; /* EXT4_BG_flags (INODE_UNINIT, etc) */
+ __le32 bg_exclude_bitmap_lo; /* Exclude bitmap for snapshots */
+ __le16 bg_block_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+bbitmap) LE */
+ __le16 bg_inode_bitmap_csum_lo;/* crc32c(s_uuid+grp_num+ibitmap) LE */
+ __le16 bg_itable_unused_lo; /* Unused inodes count */
+ __le16 bg_checksum; /* crc16(sb_uuid+group+desc) */
+ __le32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */
+ __le32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */
+ __le32 bg_inode_table_hi; /* Inodes table block MSB */
+ __le16 bg_free_blocks_count_hi;/* Free blocks count MSB */
+ __le16 bg_free_inodes_count_hi;/* Free inodes count MSB */
+ __le16 bg_used_dirs_count_hi; /* Directories count MSB */
+ __le16 bg_itable_unused_hi; /* Unused inodes count MSB */
+ __le32 bg_exclude_bitmap_hi; /* Exclude bitmap block MSB */
+ __le16 bg_block_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+bbitmap) BE */
+ __le16 bg_inode_bitmap_csum_hi;/* crc32c(s_uuid+grp_num+ibitmap) BE */
+ __u32 bg_reserved;
+};
+
+#define EXT4_BG_INODE_BITMAP_CSUM_HI_END \
+ (offsetof(struct ext4_group_desc, bg_inode_bitmap_csum_hi) + \
+ sizeof(__le16))
+#define EXT4_BG_BLOCK_BITMAP_CSUM_HI_END \
+ (offsetof(struct ext4_group_desc, bg_block_bitmap_csum_hi) + \
+ sizeof(__le16))
+
+/*
+ * Structure of a flex block group info
+ */
+
+struct flex_groups {
+ atomic64_t free_clusters;
+ atomic_t free_inodes;
+ atomic_t used_dirs;
+};
+
+#define EXT4_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */
+#define EXT4_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not in use */
+#define EXT4_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#define EXT4_MIN_DESC_SIZE 32
+#define EXT4_MIN_DESC_SIZE_64BIT 64
+#define EXT4_MAX_DESC_SIZE EXT4_MIN_BLOCK_SIZE
+#define EXT4_DESC_SIZE(s) (EXT4_SB(s)->s_desc_size)
+#ifdef __KERNEL__
+# define EXT4_BLOCKS_PER_GROUP(s) (EXT4_SB(s)->s_blocks_per_group)
+# define EXT4_CLUSTERS_PER_GROUP(s) (EXT4_SB(s)->s_clusters_per_group)
+# define EXT4_DESC_PER_BLOCK(s) (EXT4_SB(s)->s_desc_per_block)
+# define EXT4_INODES_PER_GROUP(s) (EXT4_SB(s)->s_inodes_per_group)
+# define EXT4_DESC_PER_BLOCK_BITS(s) (EXT4_SB(s)->s_desc_per_block_bits)
+#else
+# define EXT4_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group)
+# define EXT4_DESC_PER_BLOCK(s) (EXT4_BLOCK_SIZE(s) / EXT4_DESC_SIZE(s))
+# define EXT4_INODES_PER_GROUP(s) ((s)->s_inodes_per_group)
+#endif
+
+/*
+ * Constants relative to the data blocks
+ */
+#define EXT4_NDIR_BLOCKS 12
+#define EXT4_IND_BLOCK EXT4_NDIR_BLOCKS
+#define EXT4_DIND_BLOCK (EXT4_IND_BLOCK + 1)
+#define EXT4_TIND_BLOCK (EXT4_DIND_BLOCK + 1)
+#define EXT4_N_BLOCKS (EXT4_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define EXT4_SECRM_FL 0x00000001 /* Secure deletion */
+#define EXT4_UNRM_FL 0x00000002 /* Undelete */
+#define EXT4_COMPR_FL 0x00000004 /* Compress file */
+#define EXT4_SYNC_FL 0x00000008 /* Synchronous updates */
+#define EXT4_IMMUTABLE_FL 0x00000010 /* Immutable file */
+#define EXT4_APPEND_FL 0x00000020 /* writes to file may only append */
+#define EXT4_NODUMP_FL 0x00000040 /* do not dump file */
+#define EXT4_NOATIME_FL 0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT4_DIRTY_FL 0x00000100
+#define EXT4_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
+#define EXT4_NOCOMPR_FL 0x00000400 /* Don't compress */
+ /* nb: was previously EXT2_ECOMPR_FL */
+#define EXT4_ENCRYPT_FL 0x00000800 /* encrypted file */
+/* End compression flags --- maybe not all used */
+#define EXT4_INDEX_FL 0x00001000 /* hash-indexed directory */
+#define EXT4_IMAGIC_FL 0x00002000 /* AFS directory */
+#define EXT4_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
+#define EXT4_NOTAIL_FL 0x00008000 /* file tail should not be merged */
+#define EXT4_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */
+#define EXT4_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
+#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
+#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
+#define EXT4_EA_INODE_FL 0x00200000 /* Inode used for large EA */
+#define EXT4_EOFBLOCKS_FL 0x00400000 /* Blocks allocated beyond EOF */
+#define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data. */
+#define EXT4_PROJINHERIT_FL 0x20000000 /* Create with parents projid */
+#define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */
+
+#define EXT4_FL_USER_VISIBLE 0x304BDFFF /* User visible flags */
+#define EXT4_FL_USER_MODIFIABLE 0x204BC0FF /* User modifiable flags */
+
+/* Flags we can manipulate with through EXT4_IOC_FSSETXATTR */
+#define EXT4_FL_XFLAG_VISIBLE (EXT4_SYNC_FL | \
+ EXT4_IMMUTABLE_FL | \
+ EXT4_APPEND_FL | \
+ EXT4_NODUMP_FL | \
+ EXT4_NOATIME_FL | \
+ EXT4_PROJINHERIT_FL)
+
+/* Flags that should be inherited by new inodes from their parent. */
+#define EXT4_FL_INHERITED (EXT4_SECRM_FL | EXT4_UNRM_FL | EXT4_COMPR_FL |\
+ EXT4_SYNC_FL | EXT4_NODUMP_FL | EXT4_NOATIME_FL |\
+ EXT4_NOCOMPR_FL | EXT4_JOURNAL_DATA_FL |\
+ EXT4_NOTAIL_FL | EXT4_DIRSYNC_FL |\
+ EXT4_PROJINHERIT_FL)
+
+/* Flags that are appropriate for regular files (all but dir-specific ones). */
+#define EXT4_REG_FLMASK (~(EXT4_DIRSYNC_FL | EXT4_TOPDIR_FL))
+
+/* Flags that are appropriate for non-directories/regular files. */
+#define EXT4_OTHER_FLMASK (EXT4_NODUMP_FL | EXT4_NOATIME_FL)
+
+/* Mask out flags that are inappropriate for the given type of inode. */
+static inline __u32 ext4_mask_flags(umode_t mode, __u32 flags)
+{
+ if (S_ISDIR(mode))
+ return flags;
+ else if (S_ISREG(mode))
+ return flags & EXT4_REG_FLMASK;
+ else
+ return flags & EXT4_OTHER_FLMASK;
+}
+
+/*
+ * Inode flags used for atomic set/get
+ */
+enum {
+ EXT4_INODE_SECRM = 0, /* Secure deletion */
+ EXT4_INODE_UNRM = 1, /* Undelete */
+ EXT4_INODE_COMPR = 2, /* Compress file */
+ EXT4_INODE_SYNC = 3, /* Synchronous updates */
+ EXT4_INODE_IMMUTABLE = 4, /* Immutable file */
+ EXT4_INODE_APPEND = 5, /* writes to file may only append */
+ EXT4_INODE_NODUMP = 6, /* do not dump file */
+ EXT4_INODE_NOATIME = 7, /* do not update atime */
+/* Reserved for compression usage... */
+ EXT4_INODE_DIRTY = 8,
+ EXT4_INODE_COMPRBLK = 9, /* One or more compressed clusters */
+ EXT4_INODE_NOCOMPR = 10, /* Don't compress */
+ EXT4_INODE_ENCRYPT = 11, /* Encrypted file */
+/* End compression flags --- maybe not all used */
+ EXT4_INODE_INDEX = 12, /* hash-indexed directory */
+ EXT4_INODE_IMAGIC = 13, /* AFS directory */
+ EXT4_INODE_JOURNAL_DATA = 14, /* file data should be journaled */
+ EXT4_INODE_NOTAIL = 15, /* file tail should not be merged */
+ EXT4_INODE_DIRSYNC = 16, /* dirsync behaviour (directories only) */
+ EXT4_INODE_TOPDIR = 17, /* Top of directory hierarchies*/
+ EXT4_INODE_HUGE_FILE = 18, /* Set to each huge file */
+ EXT4_INODE_EXTENTS = 19, /* Inode uses extents */
+ EXT4_INODE_EA_INODE = 21, /* Inode used for large EA */
+ EXT4_INODE_EOFBLOCKS = 22, /* Blocks allocated beyond EOF */
+ EXT4_INODE_INLINE_DATA = 28, /* Data in inode. */
+ EXT4_INODE_PROJINHERIT = 29, /* Create with parents projid */
+ EXT4_INODE_RESERVED = 31, /* reserved for ext4 lib */
+};
+
+/*
+ * Since it's pretty easy to mix up bit numbers and hex values, we use a
+ * build-time check to make sure that EXT4_XXX_FL is consistent with respect to
+ * EXT4_INODE_XXX. If all is well, the macros will be dropped, so, it won't cost
+ * any extra space in the compiled kernel image, otherwise, the build will fail.
+ * It's important that these values are the same, since we are using
+ * EXT4_INODE_XXX to test for flag values, but EXT4_XXX_FL must be consistent
+ * with the values of FS_XXX_FL defined in include/linux/fs.h and the on-disk
+ * values found in ext2, ext3 and ext4 filesystems, and of course the values
+ * defined in e2fsprogs.
+ *
+ * It's not paranoia if the Murphy's Law really *is* out to get you. :-)
+ */
+#define TEST_FLAG_VALUE(FLAG) (EXT4_##FLAG##_FL == (1 << EXT4_INODE_##FLAG))
+#define CHECK_FLAG_VALUE(FLAG) BUILD_BUG_ON(!TEST_FLAG_VALUE(FLAG))
+
+static inline void ext4_check_flag_values(void)
+{
+ CHECK_FLAG_VALUE(SECRM);
+ CHECK_FLAG_VALUE(UNRM);
+ CHECK_FLAG_VALUE(COMPR);
+ CHECK_FLAG_VALUE(SYNC);
+ CHECK_FLAG_VALUE(IMMUTABLE);
+ CHECK_FLAG_VALUE(APPEND);
+ CHECK_FLAG_VALUE(NODUMP);
+ CHECK_FLAG_VALUE(NOATIME);
+ CHECK_FLAG_VALUE(DIRTY);
+ CHECK_FLAG_VALUE(COMPRBLK);
+ CHECK_FLAG_VALUE(NOCOMPR);
+ CHECK_FLAG_VALUE(ENCRYPT);
+ CHECK_FLAG_VALUE(INDEX);
+ CHECK_FLAG_VALUE(IMAGIC);
+ CHECK_FLAG_VALUE(JOURNAL_DATA);
+ CHECK_FLAG_VALUE(NOTAIL);
+ CHECK_FLAG_VALUE(DIRSYNC);
+ CHECK_FLAG_VALUE(TOPDIR);
+ CHECK_FLAG_VALUE(HUGE_FILE);
+ CHECK_FLAG_VALUE(EXTENTS);
+ CHECK_FLAG_VALUE(EA_INODE);
+ CHECK_FLAG_VALUE(EOFBLOCKS);
+ CHECK_FLAG_VALUE(INLINE_DATA);
+ CHECK_FLAG_VALUE(PROJINHERIT);
+ CHECK_FLAG_VALUE(RESERVED);
+}
+
+/* Used to pass group descriptor data when online resize is done */
+struct ext4_new_group_input {
+ __u32 group; /* Group number for this data */
+ __u64 block_bitmap; /* Absolute block number of block bitmap */
+ __u64 inode_bitmap; /* Absolute block number of inode bitmap */
+ __u64 inode_table; /* Absolute block number of inode table start */
+ __u32 blocks_count; /* Total number of blocks in this group */
+ __u16 reserved_blocks; /* Number of reserved blocks in this group */
+ __u16 unused;
+};
+
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+struct compat_ext4_new_group_input {
+ __u32 group;
+ compat_u64 block_bitmap;
+ compat_u64 inode_bitmap;
+ compat_u64 inode_table;
+ __u32 blocks_count;
+ __u16 reserved_blocks;
+ __u16 unused;
+};
+#endif
+
+/* The struct ext4_new_group_input in kernel space, with free_blocks_count */
+struct ext4_new_group_data {
+ __u32 group;
+ __u64 block_bitmap;
+ __u64 inode_bitmap;
+ __u64 inode_table;
+ __u32 blocks_count;
+ __u16 reserved_blocks;
+ __u16 mdata_blocks;
+ __u32 free_clusters_count;
+};
+
+/* Indexes used to index group tables in ext4_new_group_data */
+enum {
+ BLOCK_BITMAP = 0, /* block bitmap */
+ INODE_BITMAP, /* inode bitmap */
+ INODE_TABLE, /* inode tables */
+ GROUP_TABLE_COUNT,
+};
+
+/*
+ * Flags used by ext4_map_blocks()
+ */
+ /* Allocate any needed blocks and/or convert an unwritten
+ extent to be an initialized ext4 */
+#define EXT4_GET_BLOCKS_CREATE 0x0001
+ /* Request the creation of an unwritten extent */
+#define EXT4_GET_BLOCKS_UNWRIT_EXT 0x0002
+#define EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT (EXT4_GET_BLOCKS_UNWRIT_EXT|\
+ EXT4_GET_BLOCKS_CREATE)
+ /* Caller is from the delayed allocation writeout path
+ * finally doing the actual allocation of delayed blocks */
+#define EXT4_GET_BLOCKS_DELALLOC_RESERVE 0x0004
+ /* caller is from the direct IO path, request to creation of an
+ unwritten extents if not allocated, split the unwritten
+ extent if blocks has been preallocated already*/
+#define EXT4_GET_BLOCKS_PRE_IO 0x0008
+#define EXT4_GET_BLOCKS_CONVERT 0x0010
+#define EXT4_GET_BLOCKS_IO_CREATE_EXT (EXT4_GET_BLOCKS_PRE_IO|\
+ EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT)
+ /* Convert extent to initialized after IO complete */
+#define EXT4_GET_BLOCKS_IO_CONVERT_EXT (EXT4_GET_BLOCKS_CONVERT|\
+ EXT4_GET_BLOCKS_CREATE_UNWRIT_EXT)
+ /* Eventual metadata allocation (due to growing extent tree)
+ * should not fail, so try to use reserved blocks for that.*/
+#define EXT4_GET_BLOCKS_METADATA_NOFAIL 0x0020
+ /* Don't normalize allocation size (used for fallocate) */
+#define EXT4_GET_BLOCKS_NO_NORMALIZE 0x0040
+ /* Request will not result in inode size update (user for fallocate) */
+#define EXT4_GET_BLOCKS_KEEP_SIZE 0x0080
+ /* Convert written extents to unwritten */
+#define EXT4_GET_BLOCKS_CONVERT_UNWRITTEN 0x0100
+ /* Write zeros to newly created written extents */
+#define EXT4_GET_BLOCKS_ZERO 0x0200
+#define EXT4_GET_BLOCKS_CREATE_ZERO (EXT4_GET_BLOCKS_CREATE |\
+ EXT4_GET_BLOCKS_ZERO)
+ /* Caller will submit data before dropping transaction handle. This
+ * allows jbd2 to avoid submitting data before commit. */
+#define EXT4_GET_BLOCKS_IO_SUBMIT 0x0400
+
+/*
+ * The bit position of these flags must not overlap with any of the
+ * EXT4_GET_BLOCKS_*. They are used by ext4_find_extent(),
+ * read_extent_tree_block(), ext4_split_extent_at(),
+ * ext4_ext_insert_extent(), and ext4_ext_create_new_leaf().
+ * EXT4_EX_NOCACHE is used to indicate that the we shouldn't be
+ * caching the extents when reading from the extent tree while a
+ * truncate or punch hole operation is in progress.
+ */
+#define EXT4_EX_NOCACHE 0x40000000
+#define EXT4_EX_FORCE_CACHE 0x20000000
+
+/*
+ * Flags used by ext4_free_blocks
+ */
+#define EXT4_FREE_BLOCKS_METADATA 0x0001
+#define EXT4_FREE_BLOCKS_FORGET 0x0002
+#define EXT4_FREE_BLOCKS_VALIDATED 0x0004
+#define EXT4_FREE_BLOCKS_NO_QUOT_UPDATE 0x0008
+#define EXT4_FREE_BLOCKS_NOFREE_FIRST_CLUSTER 0x0010
+#define EXT4_FREE_BLOCKS_NOFREE_LAST_CLUSTER 0x0020
+#define EXT4_FREE_BLOCKS_RERESERVE_CLUSTER 0x0040
+
+/*
+ * ioctl commands
+ */
+#define EXT4_IOC_GETFLAGS FS_IOC_GETFLAGS
+#define EXT4_IOC_SETFLAGS FS_IOC_SETFLAGS
+#define EXT4_IOC_GETVERSION _IOR('f', 3, long)
+#define EXT4_IOC_SETVERSION _IOW('f', 4, long)
+#define EXT4_IOC_GETVERSION_OLD FS_IOC_GETVERSION
+#define EXT4_IOC_SETVERSION_OLD FS_IOC_SETVERSION
+#define EXT4_IOC_GETRSVSZ _IOR('f', 5, long)
+#define EXT4_IOC_SETRSVSZ _IOW('f', 6, long)
+#define EXT4_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
+#define EXT4_IOC_GROUP_ADD _IOW('f', 8, struct ext4_new_group_input)
+#define EXT4_IOC_MIGRATE _IO('f', 9)
+ /* note ioctl 10 reserved for an early version of the FIEMAP ioctl */
+ /* note ioctl 11 reserved for filesystem-independent FIEMAP ioctl */
+#define EXT4_IOC_ALLOC_DA_BLKS _IO('f', 12)
+#define EXT4_IOC_MOVE_EXT _IOWR('f', 15, struct move_extent)
+#define EXT4_IOC_RESIZE_FS _IOW('f', 16, __u64)
+#define EXT4_IOC_SWAP_BOOT _IO('f', 17)
+#define EXT4_IOC_PRECACHE_EXTENTS _IO('f', 18)
+#define EXT4_IOC_SET_ENCRYPTION_POLICY FS_IOC_SET_ENCRYPTION_POLICY
+#define EXT4_IOC_GET_ENCRYPTION_PWSALT FS_IOC_GET_ENCRYPTION_PWSALT
+#define EXT4_IOC_GET_ENCRYPTION_POLICY FS_IOC_GET_ENCRYPTION_POLICY
+
+#define EXT4_IOC_FSGETXATTR FS_IOC_FSGETXATTR
+#define EXT4_IOC_FSSETXATTR FS_IOC_FSSETXATTR
+
+#define EXT4_IOC_SHUTDOWN _IOR ('X', 125, __u32)
+
+/*
+ * Flags for going down operation
+ */
+#define EXT4_GOING_FLAGS_DEFAULT 0x0 /* going down */
+#define EXT4_GOING_FLAGS_LOGFLUSH 0x1 /* flush log but not data */
+#define EXT4_GOING_FLAGS_NOLOGFLUSH 0x2 /* don't flush log nor data */
+
+
+#if defined(__KERNEL__) && defined(CONFIG_COMPAT)
+/*
+ * ioctl commands in 32 bit emulation
+ */
+#define EXT4_IOC32_GETFLAGS FS_IOC32_GETFLAGS
+#define EXT4_IOC32_SETFLAGS FS_IOC32_SETFLAGS
+#define EXT4_IOC32_GETVERSION _IOR('f', 3, int)
+#define EXT4_IOC32_SETVERSION _IOW('f', 4, int)
+#define EXT4_IOC32_GETRSVSZ _IOR('f', 5, int)
+#define EXT4_IOC32_SETRSVSZ _IOW('f', 6, int)
+#define EXT4_IOC32_GROUP_EXTEND _IOW('f', 7, unsigned int)
+#define EXT4_IOC32_GROUP_ADD _IOW('f', 8, struct compat_ext4_new_group_input)
+#define EXT4_IOC32_GETVERSION_OLD FS_IOC32_GETVERSION
+#define EXT4_IOC32_SETVERSION_OLD FS_IOC32_SETVERSION
+#endif
+
+/* Max physical block we can address w/o extents */
+#define EXT4_MAX_BLOCK_FILE_PHYS 0xFFFFFFFF
+
+/* Max logical block we can support */
+#define EXT4_MAX_LOGICAL_BLOCK 0xFFFFFFFF
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext4_inode {
+ __le16 i_mode; /* File mode */
+ __le16 i_uid; /* Low 16 bits of Owner Uid */
+ __le32 i_size_lo; /* Size in bytes */
+ __le32 i_atime; /* Access time */
+ __le32 i_ctime; /* Inode Change time */
+ __le32 i_mtime; /* Modification time */
+ __le32 i_dtime; /* Deletion Time */
+ __le16 i_gid; /* Low 16 bits of Group Id */
+ __le16 i_links_count; /* Links count */
+ __le32 i_blocks_lo; /* Blocks count */
+ __le32 i_flags; /* File flags */
+ union {
+ struct {
+ __le32 l_i_version;
+ } linux1;
+ struct {
+ __u32 h_i_translator;
+ } hurd1;
+ struct {
+ __u32 m_i_reserved1;
+ } masix1;
+ } osd1; /* OS dependent 1 */
+ __le32 i_block[EXT4_N_BLOCKS];/* Pointers to blocks */
+ __le32 i_generation; /* File version (for NFS) */
+ __le32 i_file_acl_lo; /* File ACL */
+ __le32 i_size_high;
+ __le32 i_obso_faddr; /* Obsoleted fragment address */
+ union {
+ struct {
+ __le16 l_i_blocks_high; /* were l_i_reserved1 */
+ __le16 l_i_file_acl_high;
+ __le16 l_i_uid_high; /* these 2 fields */
+ __le16 l_i_gid_high; /* were reserved2[0] */
+ __le16 l_i_checksum_lo;/* crc32c(uuid+inum+inode) LE */
+ __le16 l_i_reserved;
+ } linux2;
+ struct {
+ __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
+ __u16 h_i_mode_high;
+ __u16 h_i_uid_high;
+ __u16 h_i_gid_high;
+ __u32 h_i_author;
+ } hurd2;
+ struct {
+ __le16 h_i_reserved1; /* Obsoleted fragment number/size which are removed in ext4 */
+ __le16 m_i_file_acl_high;
+ __u32 m_i_reserved2[2];
+ } masix2;
+ } osd2; /* OS dependent 2 */
+ __le16 i_extra_isize;
+ __le16 i_checksum_hi; /* crc32c(uuid+inum+inode) BE */
+ __le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */
+ __le32 i_mtime_extra; /* extra Modification time(nsec << 2 | epoch) */
+ __le32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */
+ __le32 i_crtime; /* File Creation time */
+ __le32 i_crtime_extra; /* extra FileCreationtime (nsec << 2 | epoch) */
+ __le32 i_version_hi; /* high 32 bits for 64-bit version */
+ __le32 i_projid; /* Project ID */
+};
+
+struct move_extent {
+ __u32 reserved; /* should be zero */
+ __u32 donor_fd; /* donor file descriptor */
+ __u64 orig_start; /* logical start offset in block for orig */
+ __u64 donor_start; /* logical start offset in block for donor */
+ __u64 len; /* block length to be moved */
+ __u64 moved_len; /* moved block length */
+};
+
+#define EXT4_EPOCH_BITS 2
+#define EXT4_EPOCH_MASK ((1 << EXT4_EPOCH_BITS) - 1)
+#define EXT4_NSEC_MASK (~0UL << EXT4_EPOCH_BITS)
+
+/*
+ * Extended fields will fit into an inode if the filesystem was formatted
+ * with large inodes (-I 256 or larger) and there are not currently any EAs
+ * consuming all of the available space. For new inodes we always reserve
+ * enough space for the kernel's known extended fields, but for inodes
+ * created with an old kernel this might not have been the case. None of
+ * the extended inode fields is critical for correct filesystem operation.
+ * This macro checks if a certain field fits in the inode. Note that
+ * inode-size = GOOD_OLD_INODE_SIZE + i_extra_isize
+ */
+/*#define EXT4_FITS_IN_INODE(ext4_inode, einode, field) \
+ ((offsetof(typeof(*ext4_inode), field) + \
+ sizeof((ext4_inode)->field)) \
+ <= (EXT4_GOOD_OLD_INODE_SIZE + \
+ (einode)->i_extra_isize))*/
+#define EXT4_FITS_IN_INODE(ext4_inode, einode, field) 1
+/*
+ * We use an encoding that preserves the times for extra epoch "00":
+ *
+ * extra msb of adjust for signed
+ * epoch 32-bit 32-bit tv_sec to
+ * bits time decoded 64-bit tv_sec 64-bit tv_sec valid time range
+ * 0 0 1 -0x80000000..-0x00000001 0x000000000 1901-12-13..1969-12-31
+ * 0 0 0 0x000000000..0x07fffffff 0x000000000 1970-01-01..2038-01-19
+ * 0 1 1 0x080000000..0x0ffffffff 0x100000000 2038-01-19..2106-02-07
+ * 0 1 0 0x100000000..0x17fffffff 0x100000000 2106-02-07..2174-02-25
+ * 1 0 1 0x180000000..0x1ffffffff 0x200000000 2174-02-25..2242-03-16
+ * 1 0 0 0x200000000..0x27fffffff 0x200000000 2242-03-16..2310-04-04
+ * 1 1 1 0x280000000..0x2ffffffff 0x300000000 2310-04-04..2378-04-22
+ * 1 1 0 0x300000000..0x37fffffff 0x300000000 2378-04-22..2446-05-10
+ *
+ * Note that previous versions of the kernel on 64-bit systems would
+ * incorrectly use extra epoch bits 1,1 for dates between 1901 and
+ * 1970. e2fsck will correct this, assuming that it is run on the
+ * affected filesystem before 2242.
+ */
+
+static inline __le32 ext4_encode_extra_time(struct timespec64 *time)
+{
+ __u32 extra =((time->tv_sec - (__s32)time->tv_sec) >> 32) & EXT4_EPOCH_MASK;
+ return cpu_to_le32(extra | (time->tv_nsec << EXT4_EPOCH_BITS));
+}
+
+static inline void ext4_decode_extra_time(struct timespec64 *time,
+ __le32 extra)
+{
+ if (unlikely(extra & cpu_to_le32(EXT4_EPOCH_MASK))) {
+
+#if 1
+ /* Handle legacy encoding of pre-1970 dates with epoch
+ * bits 1,1. (This backwards compatibility may be removed
+ * at the discretion of the ext4 developers.)
+ */
+ __u64 extra_bits = le32_to_cpu(extra) & EXT4_EPOCH_MASK;
+ if (extra_bits == 3 && ((time->tv_sec) & 0x80000000) != 0)
+ extra_bits = 0;
+ time->tv_sec += extra_bits << 32;
+#else
+ time->tv_sec += (__u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32;
+#endif
+ }
+ time->tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
+}
+
+#define EXT4_INODE_SET_XTIME(xtime, inode, raw_inode) \
+do { \
+ (raw_inode)->xtime = cpu_to_le32((inode)->xtime.tv_sec); \
+ if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) {\
+ (raw_inode)->xtime ## _extra = \
+ ext4_encode_extra_time(&(inode)->xtime); \
+ } \
+} while (0)
+
+#define EXT4_EINODE_SET_XTIME(xtime, einode, raw_inode) \
+do { \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \
+ (raw_inode)->xtime = cpu_to_le32((einode)->xtime.tv_sec); \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \
+ (raw_inode)->xtime ## _extra = \
+ ext4_encode_extra_time(&(einode)->xtime); \
+} while (0)
+
+#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode) \
+do { \
+ (inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime); \
+ if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) { \
+ ext4_decode_extra_time(&(inode)->xtime, \
+ raw_inode->xtime ## _extra); \
+ } \
+ else \
+ (inode)->xtime.tv_nsec = 0; \
+} while (0)
+
+
+#define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode) \
+do { \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \
+ (einode)->xtime.tv_sec = \
+ (signed)le32_to_cpu((raw_inode)->xtime); \
+ else \
+ (einode)->xtime.tv_sec = 0; \
+ if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \
+ ext4_decode_extra_time(&(einode)->xtime, \
+ raw_inode->xtime ## _extra); \
+ else \
+ (einode)->xtime.tv_nsec = 0; \
+} while (0)
+
+#define i_disk_version osd1.linux1.l_i_version
+
+#if defined(__KERNEL__) || defined(__linux__)
+#define i_reserved1 osd1.linux1.l_i_reserved1
+#define i_file_acl_high osd2.linux2.l_i_file_acl_high
+#define i_blocks_high osd2.linux2.l_i_blocks_high
+#define i_uid_low i_uid
+#define i_gid_low i_gid
+#define i_uid_high osd2.linux2.l_i_uid_high
+#define i_gid_high osd2.linux2.l_i_gid_high
+#define i_checksum_lo osd2.linux2.l_i_checksum_lo
+
+#elif defined(__GNU__)
+
+#define i_translator osd1.hurd1.h_i_translator
+#define i_uid_high osd2.hurd2.h_i_uid_high
+#define i_gid_high osd2.hurd2.h_i_gid_high
+#define i_author osd2.hurd2.h_i_author
+
+#elif defined(__masix__)
+
+#define i_reserved1 osd1.masix1.m_i_reserved1
+#define i_file_acl_high osd2.masix2.m_i_file_acl_high
+#define i_reserved2 osd2.masix2.m_i_reserved2
+
+#endif /* defined(__KERNEL__) || defined(__linux__) */
+
+//#include "extents_status.h"
+
+/*
+ * Lock subclasses for i_data_sem in the ext4_inode_info structure.
+ *
+ * These are needed to avoid lockdep false positives when we need to
+ * allocate blocks to the quota inode during ext4_map_blocks(), while
+ * holding i_data_sem for a normal (non-quota) inode. Since we don't
+ * do quota tracking for the quota inode, this avoids deadlock (as
+ * well as infinite recursion, since it isn't turtles all the way
+ * down...)
+ *
+ * I_DATA_SEM_NORMAL - Used for most inodes
+ * I_DATA_SEM_OTHER - Used by move_inode.c for the second normal inode
+ * where the second inode has larger inode number
+ * than the first
+ * I_DATA_SEM_QUOTA - Used for quota inodes only
+ */
+enum {
+ I_DATA_SEM_NORMAL = 0,
+ I_DATA_SEM_OTHER,
+ I_DATA_SEM_QUOTA,
+};
+
+
+/*
+ * fourth extended file system inode data in memory
+ */
+struct ext4_inode_info {
+ __u32 i_size_lo; /* Size in bytes */
+ __u32 i_blocks_lo; /* Blocks count */
+
+#if (BITS_PER_LONG < 64)
+ unsigned long i_state_flags; /* Dynamic state flags */
+#endif
+ unsigned long i_flags;
+
+ /* Precomputed uuid+inum+igen checksum for seeding inode checksums */
+ __u32 i_csum_seed;
+};
+
+/*
+ * File system states
+ */
+#define EXT4_VALID_FS 0x0001 /* Unmounted cleanly */
+#define EXT4_ERROR_FS 0x0002 /* Errors detected */
+#define EXT4_ORPHAN_FS 0x0004 /* Orphans being recovered */
+
+/*
+ * Misc. filesystem flags
+ */
+#define EXT2_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */
+#define EXT2_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */
+#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* to test development code */
+
+/*
+ * Mount flags set via mount options or defaults
+ */
+#define EXT4_MOUNT_NO_MBCACHE 0x00001 /* Do not use mbcache */
+#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */
+#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
+#define EXT4_MOUNT_ERRORS_CONT 0x00010 /* Continue on errors */
+#define EXT4_MOUNT_ERRORS_RO 0x00020 /* Remount fs ro on errors */
+#define EXT4_MOUNT_ERRORS_PANIC 0x00040 /* Panic on errors */
+#define EXT4_MOUNT_ERRORS_MASK 0x00070
+#define EXT4_MOUNT_MINIX_DF 0x00080 /* Mimics the Minix statfs */
+#define EXT4_MOUNT_NOLOAD 0x00100 /* Don't use existing journal*/
+#ifdef CONFIG_FS_DAX
+#define EXT4_MOUNT_DAX 0x00200 /* Direct Access */
+#else
+#define EXT4_MOUNT_DAX 0
+#endif
+#define EXT4_MOUNT_DATA_FLAGS 0x00C00 /* Mode for data writes: */
+#define EXT4_MOUNT_JOURNAL_DATA 0x00400 /* Write data to journal */
+#define EXT4_MOUNT_ORDERED_DATA 0x00800 /* Flush data before commit */
+#define EXT4_MOUNT_WRITEBACK_DATA 0x00C00 /* No data ordering */
+#define EXT4_MOUNT_UPDATE_JOURNAL 0x01000 /* Update the journal format */
+#define EXT4_MOUNT_NO_UID32 0x02000 /* Disable 32-bit UIDs */
+#define EXT4_MOUNT_XATTR_USER 0x04000 /* Extended user attributes */
+#define EXT4_MOUNT_POSIX_ACL 0x08000 /* POSIX Access Control Lists */
+#define EXT4_MOUNT_NO_AUTO_DA_ALLOC 0x10000 /* No auto delalloc mapping */
+#define EXT4_MOUNT_BARRIER 0x20000 /* Use block barriers */
+#define EXT4_MOUNT_QUOTA 0x40000 /* Some quota option set */
+#define EXT4_MOUNT_USRQUOTA 0x80000 /* "old" user quota,
+ * enable enforcement for hidden
+ * quota files */
+#define EXT4_MOUNT_GRPQUOTA 0x100000 /* "old" group quota, enable
+ * enforcement for hidden quota
+ * files */
+#define EXT4_MOUNT_PRJQUOTA 0x200000 /* Enable project quota
+ * enforcement */
+#define EXT4_MOUNT_DIOREAD_NOLOCK 0x400000 /* Enable support for dio read nolocking */
+#define EXT4_MOUNT_JOURNAL_CHECKSUM 0x800000 /* Journal checksums */
+#define EXT4_MOUNT_JOURNAL_ASYNC_COMMIT 0x1000000 /* Journal Async Commit */
+#define EXT4_MOUNT_WARN_ON_ERROR 0x2000000 /* Trigger WARN_ON on error */
+#define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */
+#define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
+#define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */
+#define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */
+#define EXT4_MOUNT_INIT_INODE_TABLE 0x80000000 /* Initialize uninitialized itables */
+
+/*
+ * Mount flags set either automatically (could not be set by mount option)
+ * based on per file system feature or property or in special cases such as
+ * distinguishing between explicit mount option definition and default.
+ */
+#define EXT4_MOUNT2_EXPLICIT_DELALLOC 0x00000001 /* User explicitly
+ specified delalloc */
+#define EXT4_MOUNT2_STD_GROUP_SIZE 0x00000002 /* We have standard group
+ size of blocksize * 8
+ blocks */
+#define EXT4_MOUNT2_HURD_COMPAT 0x00000004 /* Support HURD-castrated
+ file systems */
+
+#define EXT4_MOUNT2_EXPLICIT_JOURNAL_CHECKSUM 0x00000008 /* User explicitly
+ specified journal checksum */
+
+#define clear_opt(sb, opt) EXT4_SB(sb)->s_mount_opt &= \
+ ~EXT4_MOUNT_##opt
+#define set_opt(sb, opt) EXT4_SB(sb)->s_mount_opt |= \
+ EXT4_MOUNT_##opt
+#define test_opt(sb, opt) (EXT4_SB(sb)->s_mount_opt & \
+ EXT4_MOUNT_##opt)
+
+#define clear_opt2(sb, opt) EXT4_SB(sb)->s_mount_opt2 &= \
+ ~EXT4_MOUNT2_##opt
+#define set_opt2(sb, opt) EXT4_SB(sb)->s_mount_opt2 |= \
+ EXT4_MOUNT2_##opt
+#define test_opt2(sb, opt) (EXT4_SB(sb)->s_mount_opt2 & \
+ EXT4_MOUNT2_##opt)
+
+#define ext4_test_and_set_bit __test_and_set_bit_le
+//#define ext4_set_bit __set_bit_le
+#define ext4_set_bit_atomic ext2_set_bit_atomic
+#define ext4_test_and_clear_bit __test_and_clear_bit_le
+#define ext4_clear_bit __clear_bit_le
+#define ext4_clear_bit_atomic ext2_clear_bit_atomic
+#define ext4_test_bit test_bit_le
+#define ext4_find_next_zero_bit find_next_zero_bit_le
+#define ext4_find_next_bit find_next_bit_le
+
+extern void ext4_set_bits(void *bm, int cur, int len);
+
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT4_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
+#define EXT4_DFL_CHECKINTERVAL 0 /* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT4_ERRORS_CONTINUE 1 /* Continue execution */
+#define EXT4_ERRORS_RO 2 /* Remount fs read-only */
+#define EXT4_ERRORS_PANIC 3 /* Panic */
+#define EXT4_ERRORS_DEFAULT EXT4_ERRORS_CONTINUE
+
+/* Metadata checksum algorithm codes */
+#define EXT4_CRC32C_CHKSUM 1
+
+/*
+ * Structure of the super block
+ */
+struct ext4_super_block {
+/*00*/ __le32 s_inodes_count; /* Inodes count */
+ __le32 s_blocks_count_lo; /* Blocks count */
+ __le32 s_r_blocks_count_lo; /* Reserved blocks count */
+ __le32 s_free_blocks_count_lo; /* Free blocks count */
+/*10*/ __le32 s_free_inodes_count; /* Free inodes count */
+ __le32 s_first_data_block; /* First Data Block */
+ __le32 s_log_block_size; /* Block size */
+ __le32 s_log_cluster_size; /* Allocation cluster size */
+/*20*/ __le32 s_blocks_per_group; /* # Blocks per group */
+ __le32 s_clusters_per_group; /* # Clusters per group */
+ __le32 s_inodes_per_group; /* # Inodes per group */
+ __le32 s_mtime; /* Mount time */
+/*30*/ __le32 s_wtime; /* Write time */
+ __le16 s_mnt_count; /* Mount count */
+ __le16 s_max_mnt_count; /* Maximal mount count */
+ __le16 s_magic; /* Magic signature */
+ __le16 s_state; /* File system state */
+ __le16 s_errors; /* Behaviour when detecting errors */
+ __le16 s_minor_rev_level; /* minor revision level */
+/*40*/ __le32 s_lastcheck; /* time of last check */
+ __le32 s_checkinterval; /* max. time between checks */
+ __le32 s_creator_os; /* OS */
+ __le32 s_rev_level; /* Revision level */
+/*50*/ __le16 s_def_resuid; /* Default uid for reserved blocks */
+ __le16 s_def_resgid; /* Default gid for reserved blocks */
+ /*
+ * These fields are for EXT4_DYNAMIC_REV superblocks only.
+ *
+ * Note: the difference between the compatible feature set and
+ * the incompatible feature set is that if there is a bit set
+ * in the incompatible feature set that the kernel doesn't
+ * know about, it should refuse to mount the filesystem.
+ *
+ * e2fsck's requirements are more strict; if it doesn't know
+ * about a feature in either the compatible or incompatible
+ * feature set, it must abort and not try to meddle with
+ * things it doesn't understand...
+ */
+ __le32 s_first_ino; /* First non-reserved inode */
+ __le16 s_inode_size; /* size of inode structure */
+ __le16 s_block_group_nr; /* block group # of this superblock */
+ __le32 s_feature_compat; /* compatible feature set */
+/*60*/ __le32 s_feature_incompat; /* incompatible feature set */
+ __le32 s_feature_ro_compat; /* readonly-compatible feature set */
+/*68*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */
+/*78*/ char s_volume_name[16]; /* volume name */
+/*88*/ char s_last_mounted[64]; /* directory where last mounted */
+/*C8*/ __le32 s_algorithm_usage_bitmap; /* For compression */
+ /*
+ * Performance hints. Directory preallocation should only
+ * happen if the EXT4_FEATURE_COMPAT_DIR_PREALLOC flag is on.
+ */
+ __u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
+ __u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
+ __le16 s_reserved_gdt_blocks; /* Per group desc for online growth */
+ /*
+ * Journaling support valid if EXT4_FEATURE_COMPAT_HAS_JOURNAL set.
+ */
+/*D0*/ __u8 s_journal_uuid[16]; /* uuid of journal superblock */
+/*E0*/ __le32 s_journal_inum; /* inode number of journal file */
+ __le32 s_journal_dev; /* device number of journal file */
+ __le32 s_last_orphan; /* start of list of inodes to delete */
+ __le32 s_hash_seed[4]; /* HTREE hash seed */
+ __u8 s_def_hash_version; /* Default hash version to use */
+ __u8 s_jnl_backup_type;
+ __le16 s_desc_size; /* size of group descriptor */
+/*100*/ __le32 s_default_mount_opts;
+ __le32 s_first_meta_bg; /* First metablock block group */
+ __le32 s_mkfs_time; /* When the filesystem was created */
+ __le32 s_jnl_blocks[17]; /* Backup of the journal inode */
+ /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */
+/*150*/ __le32 s_blocks_count_hi; /* Blocks count */
+ __le32 s_r_blocks_count_hi; /* Reserved blocks count */
+ __le32 s_free_blocks_count_hi; /* Free blocks count */
+ __le16 s_min_extra_isize; /* All inodes have at least # bytes */
+ __le16 s_want_extra_isize; /* New inodes should reserve # bytes */
+ __le32 s_flags; /* Miscellaneous flags */
+ __le16 s_raid_stride; /* RAID stride */
+ __le16 s_mmp_update_interval; /* # seconds to wait in MMP checking */
+ __le64 s_mmp_block; /* Block for multi-mount protection */
+ __le32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
+ __u8 s_log_groups_per_flex; /* FLEX_BG group size */
+ __u8 s_checksum_type; /* metadata checksum algorithm used */
+ __u8 s_encryption_level; /* versioning level for encryption */
+ __u8 s_reserved_pad; /* Padding to next 32bits */
+ __le64 s_kbytes_written; /* nr of lifetime kilobytes written */
+ __le32 s_snapshot_inum; /* Inode number of active snapshot */
+ __le32 s_snapshot_id; /* sequential ID of active snapshot */
+ __le64 s_snapshot_r_blocks_count; /* reserved blocks for active
+ snapshot's future use */
+ __le32 s_snapshot_list; /* inode number of the head of the
+ on-disk snapshot list */
+#define EXT4_S_ERR_START offsetof(struct ext4_super_block, s_error_count)
+ __le32 s_error_count; /* number of fs errors */
+ __le32 s_first_error_time; /* first time an error happened */
+ __le32 s_first_error_ino; /* inode involved in first error */
+ __le64 s_first_error_block; /* block involved of first error */
+ __u8 s_first_error_func[32]; /* function where the error happened */
+ __le32 s_first_error_line; /* line number where error happened */
+ __le32 s_last_error_time; /* most recent time of an error */
+ __le32 s_last_error_ino; /* inode involved in last error */
+ __le32 s_last_error_line; /* line number where error happened */
+ __le64 s_last_error_block; /* block involved of last error */
+ __u8 s_last_error_func[32]; /* function where the error happened */
+#define EXT4_S_ERR_END offsetof(struct ext4_super_block, s_mount_opts)
+ __u8 s_mount_opts[64];
+ __le32 s_usr_quota_inum; /* inode for tracking user quota */
+ __le32 s_grp_quota_inum; /* inode for tracking group quota */
+ __le32 s_overhead_clusters; /* overhead blocks/clusters in fs */
+ __le32 s_backup_bgs[2]; /* groups with sparse_super2 SBs */
+ __u8 s_encrypt_algos[4]; /* Encryption algorithms in use */
+ __u8 s_encrypt_pw_salt[16]; /* Salt used for string2key algorithm */
+ __le32 s_lpf_ino; /* Location of the lost+found inode */
+ __le32 s_prj_quota_inum; /* inode for tracking project quota */
+ __le32 s_checksum_seed; /* crc32c(uuid) if csum_seed set */
+ __u8 s_wtime_hi;
+ __u8 s_mtime_hi;
+ __u8 s_mkfs_time_hi;
+ __u8 s_lastcheck_hi;
+ __u8 s_first_error_time_hi;
+ __u8 s_last_error_time_hi;
+ __u8 s_pad[2];
+ __le32 s_reserved[96]; /* Padding to the end of the block */
+ __le32 s_checksum; /* crc32c(superblock) */
+};
+
+#define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START)
+
+#ifdef __KERNEL__
+
+/*
+ * run-time mount flags
+ */
+#define EXT4_MF_MNTDIR_SAMPLED 0x0001
+#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
+#define EXT4_MF_TEST_DUMMY_ENCRYPTION 0x0004
+
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
+#define DUMMY_ENCRYPTION_ENABLED(sbi) (unlikely((sbi)->s_mount_flags & \
+ EXT4_MF_TEST_DUMMY_ENCRYPTION))
+#else
+#define DUMMY_ENCRYPTION_ENABLED(sbi) (0)
+#endif
+
+/* Number of quota types we support */
+#define EXT4_MAXQUOTAS 3
+
+/*
+ * fourth extended-fs super-block data in memory
+ */
+struct ext4_sb_info {
+
+ ERESOURCE s_gd_lock;
+ struct ext3_gd *s_gd;
+
+ unsigned long s_desc_size; /* size of group desc */
+ unsigned long s_gdb_count; /* Number of group descriptor blocks */
+ unsigned long s_desc_per_block; /* Number of group descriptors per block */
+ unsigned long s_inodes_per_group;/* Number of inodes in a group */
+ unsigned long s_inodes_per_block;/* Number of inodes per block */
+ unsigned long s_blocks_per_group;/* Number of blocks in a group */
+ unsigned long s_groups_count; /* Number of groups in the fs */
+ unsigned long s_itb_per_group; /* Number of inode table blocks per group */
+ unsigned long s_clusters_per_group; /* Number of clusters in a group */
+
+ int s_addr_per_block_bits;
+ int s_desc_per_block_bits;
+ int s_inode_size;
+
+#if 0
+ unsigned long s_frag_size; /* Size of a fragment in bytes */
+ unsigned long s_frags_per_block;/* Number of fragments per block */
+ unsigned long s_frags_per_group;/* Number of fragments in a group */
+ unsigned long s_inodes_per_group;/* Number of inodes in a group */
+ unsigned long s_itb_per_group; /* Number of inode table blocks per group */
+ unsigned long s_desc_per_block; /* Number of group descriptors per block */
+ unsigned long s_overhead_last; /* Last calculated overhead */
+ unsigned long s_blocks_last; /* Last seen block count */
+#endif
+
+ struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */
+
+ __le32 s_first_ino;
+
+ __u32 s_hash_seed[4];
+ int s_def_hash_version;
+ __le32 s_csum_seed; /* crc32c(uuid) if csum_seed set */
+};
+
+static inline struct ext4_sb_info *EXT4_SB(struct super_block *sb)
+{
+ return sb->s_fs_info;
+}
+/*static inline struct ext4_inode_info *EXT4_I(struct inode *inode)
+{
+ return container_of(inode, struct ext4_inode_info, vfs_inode);
+}*/
+
+static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
+{
+ return ino == EXT4_ROOT_INO ||
+ (ino >= EXT4_FIRST_INO(sb) &&
+ ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
+}
+
+/*
+ * Inode dynamic state flags
+ */
+enum {
+ EXT4_STATE_JDATA, /* journaled data exists */
+ EXT4_STATE_NEW, /* inode is newly created */
+ EXT4_STATE_XATTR, /* has in-inode xattrs */
+ EXT4_STATE_NO_EXPAND, /* No space for expansion */
+ EXT4_STATE_DA_ALLOC_CLOSE, /* Alloc DA blks on close */
+ EXT4_STATE_EXT_MIGRATE, /* Inode is migrating */
+ EXT4_STATE_DIO_UNWRITTEN, /* need convert on dio done*/
+ EXT4_STATE_NEWENTRY, /* File just added to dir */
+ EXT4_STATE_MAY_INLINE_DATA, /* may have in-inode data */
+ EXT4_STATE_EXT_PRECACHED, /* extents have been precached */
+ EXT4_STATE_LUSTRE_EA_INODE, /* Lustre-style ea_inode */
+};
+
+#define EXT4_INODE_BIT_FNS(name, field, offset) \
+static inline int ext4_test_inode_##name(struct inode *inode, int bit) \
+{ \
+ return test_bit(bit + (offset), &EXT4_I(inode)->i_##field); \
+} \
+static inline void ext4_set_inode_##name(struct inode *inode, int bit) \
+{ \
+ set_bit(bit + (offset), &EXT4_I(inode)->i_##field); \
+} \
+static inline void ext4_clear_inode_##name(struct inode *inode, int bit) \
+{ \
+ clear_bit(bit + (offset), &EXT4_I(inode)->i_##field); \
+}
+
+/* Add these declarations here only so that these functions can be
+ * found by name. Otherwise, they are very hard to locate. */
+static inline int ext4_test_inode_flag(struct inode *inode, int bit);
+static inline void ext4_set_inode_flag(struct inode *inode, int bit);
+static inline void ext4_clear_inode_flag(struct inode *inode, int bit);
+EXT4_INODE_BIT_FNS(flag, flags, 0)
+
+/* Add these declarations here only so that these functions can be
+ * found by name. Otherwise, they are very hard to locate. */
+static inline int ext4_test_inode_state(struct inode *inode, int bit);
+static inline void ext4_set_inode_state(struct inode *inode, int bit);
+static inline void ext4_clear_inode_state(struct inode *inode, int bit);
+#if (BITS_PER_LONG < 64)
+//EXT4_INODE_BIT_FNS(state, state_flags, 0)
+
+static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
+{
+ (ei)->i_state_flags = 0;
+}
+#else
+EXT4_INODE_BIT_FNS(state, flags, 32)
+
+static inline void ext4_clear_state_flags(struct ext4_inode_info *ei)
+{
+ /* We depend on the fact that callers will set i_flags */
+}
+#endif
+#else
+/* Assume that user mode programs are passing in an ext4fs superblock, not
+ * a kernel struct super_block. This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT4_SB(sb) (sb)
+#endif
+
+/*
+ * Returns true if the inode is inode is encrypted
+ */
+#define NEXT_ORPHAN(inode) EXT4_I(inode)->i_dtime
+
+/*
+ * Codes for operating systems
+ */
+#define EXT4_OS_LINUX 0
+#define EXT4_OS_HURD 1
+#define EXT4_OS_MASIX 2
+#define EXT4_OS_FREEBSD 3
+#define EXT4_OS_LITES 4
+
+/*
+ * Revision levels
+ */
+#define EXT4_GOOD_OLD_REV 0 /* The good old (original) format */
+#define EXT4_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
+
+#define EXT4_CURRENT_REV EXT4_GOOD_OLD_REV
+#define EXT4_MAX_SUPP_REV EXT4_DYNAMIC_REV
+
+#define EXT4_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT4_FEATURE_COMPAT_DIR_PREALLOC 0x0001
+#define EXT4_FEATURE_COMPAT_IMAGIC_INODES 0x0002
+#define EXT4_FEATURE_COMPAT_HAS_JOURNAL 0x0004
+#define EXT4_FEATURE_COMPAT_EXT_ATTR 0x0008
+#define EXT4_FEATURE_COMPAT_RESIZE_INODE 0x0010
+#define EXT4_FEATURE_COMPAT_DIR_INDEX 0x0020
+#define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200
+
+#define EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
+#define EXT4_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
+#define EXT4_FEATURE_RO_COMPAT_BTREE_DIR 0x0004
+#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
+#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
+#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
+#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
+#define EXT4_FEATURE_RO_COMPAT_QUOTA 0x0100
+#define EXT4_FEATURE_RO_COMPAT_BIGALLOC 0x0200
+/*
+ * METADATA_CSUM also enables group descriptor checksums (GDT_CSUM). When
+ * METADATA_CSUM is set, group descriptor checksums use the same algorithm as
+ * all other data structures' checksums. However, the METADATA_CSUM and
+ * GDT_CSUM bits are mutually exclusive.
+ */
+#define EXT4_FEATURE_RO_COMPAT_METADATA_CSUM 0x0400
+#define EXT4_FEATURE_RO_COMPAT_READONLY 0x1000
+#define EXT4_FEATURE_RO_COMPAT_PROJECT 0x2000
+
+#define EXT4_FEATURE_INCOMPAT_COMPRESSION 0x0001
+#define EXT4_FEATURE_INCOMPAT_FILETYPE 0x0002
+#define EXT4_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
+#define EXT4_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
+#define EXT4_FEATURE_INCOMPAT_META_BG 0x0010
+#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 /* extents support */
+#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
+#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
+#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
+#define EXT4_FEATURE_INCOMPAT_EA_INODE 0x0400 /* EA in inode */
+#define EXT4_FEATURE_INCOMPAT_DIRDATA 0x1000 /* data in dirent */
+#define EXT4_FEATURE_INCOMPAT_CSUM_SEED 0x2000
+#define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */
+#define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */
+#define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000
+
+#define EXT4_FEATURE_COMPAT_FUNCS(name, flagname) \
+static inline bool ext4_has_feature_##name(struct super_block *sb) \
+{ \
+ return ((EXT4_SB(sb)->s_es->s_feature_compat & \
+ cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname)) != 0); \
+} \
+static inline void ext4_set_feature_##name(struct super_block *sb) \
+{ \
+ EXT4_SB(sb)->s_es->s_feature_compat |= \
+ cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname); \
+} \
+static inline void ext4_clear_feature_##name(struct super_block *sb) \
+{ \
+ EXT4_SB(sb)->s_es->s_feature_compat &= \
+ ~cpu_to_le32(EXT4_FEATURE_COMPAT_##flagname); \
+}
+
+#define EXT4_FEATURE_RO_COMPAT_FUNCS(name, flagname) \
+static inline bool ext4_has_feature_##name(struct super_block *sb) \
+{ \
+ return ((EXT4_SB(sb)->s_es->s_feature_ro_compat & \
+ cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname)) != 0); \
+} \
+static inline void ext4_set_feature_##name(struct super_block *sb) \
+{ \
+ EXT4_SB(sb)->s_es->s_feature_ro_compat |= \
+ cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname); \
+} \
+static inline void ext4_clear_feature_##name(struct super_block *sb) \
+{ \
+ EXT4_SB(sb)->s_es->s_feature_ro_compat &= \
+ ~cpu_to_le32(EXT4_FEATURE_RO_COMPAT_##flagname); \
+}
+
+#define EXT4_FEATURE_INCOMPAT_FUNCS(name, flagname) \
+static inline bool ext4_has_feature_##name(struct super_block *sb) \
+{ \
+ return ((EXT4_SB(sb)->s_es->s_feature_incompat & \
+ cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname)) != 0); \
+} \
+static inline void ext4_set_feature_##name(struct super_block *sb) \
+{ \
+ EXT4_SB(sb)->s_es->s_feature_incompat |= \
+ cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname); \
+} \
+static inline void ext4_clear_feature_##name(struct super_block *sb) \
+{ \
+ EXT4_SB(sb)->s_es->s_feature_incompat &= \
+ ~cpu_to_le32(EXT4_FEATURE_INCOMPAT_##flagname); \
+}
+
+EXT4_FEATURE_COMPAT_FUNCS(dir_prealloc, DIR_PREALLOC)
+EXT4_FEATURE_COMPAT_FUNCS(imagic_inodes, IMAGIC_INODES)
+EXT4_FEATURE_COMPAT_FUNCS(journal, HAS_JOURNAL)
+EXT4_FEATURE_COMPAT_FUNCS(xattr, EXT_ATTR)
+EXT4_FEATURE_COMPAT_FUNCS(resize_inode, RESIZE_INODE)
+EXT4_FEATURE_COMPAT_FUNCS(dir_index, DIR_INDEX)
+EXT4_FEATURE_COMPAT_FUNCS(sparse_super2, SPARSE_SUPER2)
+
+EXT4_FEATURE_RO_COMPAT_FUNCS(sparse_super, SPARSE_SUPER)
+EXT4_FEATURE_RO_COMPAT_FUNCS(large_file, LARGE_FILE)
+EXT4_FEATURE_RO_COMPAT_FUNCS(btree_dir, BTREE_DIR)
+EXT4_FEATURE_RO_COMPAT_FUNCS(huge_file, HUGE_FILE)
+EXT4_FEATURE_RO_COMPAT_FUNCS(gdt_csum, GDT_CSUM)
+EXT4_FEATURE_RO_COMPAT_FUNCS(dir_nlink, DIR_NLINK)
+EXT4_FEATURE_RO_COMPAT_FUNCS(extra_isize, EXTRA_ISIZE)
+EXT4_FEATURE_RO_COMPAT_FUNCS(quota, QUOTA)
+EXT4_FEATURE_RO_COMPAT_FUNCS(bigalloc, BIGALLOC)
+EXT4_FEATURE_RO_COMPAT_FUNCS(metadata_csum, METADATA_CSUM)
+EXT4_FEATURE_RO_COMPAT_FUNCS(readonly, READONLY)
+EXT4_FEATURE_RO_COMPAT_FUNCS(project, PROJECT)
+
+EXT4_FEATURE_INCOMPAT_FUNCS(compression, COMPRESSION)
+EXT4_FEATURE_INCOMPAT_FUNCS(filetype, FILETYPE)
+EXT4_FEATURE_INCOMPAT_FUNCS(journal_needs_recovery, RECOVER)
+EXT4_FEATURE_INCOMPAT_FUNCS(journal_dev, JOURNAL_DEV)
+EXT4_FEATURE_INCOMPAT_FUNCS(meta_bg, META_BG)
+EXT4_FEATURE_INCOMPAT_FUNCS(extents, EXTENTS)
+EXT4_FEATURE_INCOMPAT_FUNCS(64bit, 64BIT)
+EXT4_FEATURE_INCOMPAT_FUNCS(mmp, MMP)
+EXT4_FEATURE_INCOMPAT_FUNCS(flex_bg, FLEX_BG)
+EXT4_FEATURE_INCOMPAT_FUNCS(ea_inode, EA_INODE)
+EXT4_FEATURE_INCOMPAT_FUNCS(dirdata, DIRDATA)
+EXT4_FEATURE_INCOMPAT_FUNCS(csum_seed, CSUM_SEED)
+EXT4_FEATURE_INCOMPAT_FUNCS(largedir, LARGEDIR)
+EXT4_FEATURE_INCOMPAT_FUNCS(inline_data, INLINE_DATA)
+EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, ENCRYPT)
+
+#define EXT2_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR
+#define EXT2_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \
+ EXT4_FEATURE_INCOMPAT_META_BG)
+#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
+
+#define EXT3_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR
+#define EXT3_FEATURE_INCOMPAT_SUPP (EXT4_FEATURE_INCOMPAT_FILETYPE| \
+ EXT4_FEATURE_INCOMPAT_RECOVER| \
+ EXT4_FEATURE_INCOMPAT_META_BG)
+#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT4_FEATURE_RO_COMPAT_BTREE_DIR)
+
+#define EXT4_FEATURE_COMPAT_SUPP EXT4_FEATURE_COMPAT_EXT_ATTR
+#define EXT4_FEATURE_INCOMPAT_SUPP ( \
+ EXT4_FEATURE_INCOMPAT_FILETYPE| \
+ EXT4_FEATURE_INCOMPAT_RECOVER| \
+ EXT4_FEATURE_INCOMPAT_META_BG| \
+ EXT4_FEATURE_INCOMPAT_EXTENTS| \
+ EXT4_FEATURE_INCOMPAT_64BIT| \
+ EXT4_FEATURE_INCOMPAT_FLEX_BG)
+#define EXT4_FEATURE_RO_COMPAT_SUPP ( \
+ EXT4_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+ EXT4_FEATURE_RO_COMPAT_LARGE_FILE| \
+ EXT4_FEATURE_RO_COMPAT_GDT_CSUM| \
+ EXT4_FEATURE_RO_COMPAT_DIR_NLINK | \
+ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE | \
+ EXT4_FEATURE_RO_COMPAT_BTREE_DIR |\
+ EXT4_FEATURE_RO_COMPAT_HUGE_FILE |\
+ EXT4_FEATURE_RO_COMPAT_METADATA_CSUM)
+
+#define EXTN_FEATURE_FUNCS(ver) \
+static inline bool ext4_has_unknown_ext##ver##_compat_features(struct super_block *sb) \
+{ \
+ return ((EXT4_SB(sb)->s_es->s_feature_compat & \
+ cpu_to_le32(~EXT##ver##_FEATURE_COMPAT_SUPP)) != 0); \
+} \
+static inline bool ext4_has_unknown_ext##ver##_ro_compat_features(struct super_block *sb) \
+{ \
+ return ((EXT4_SB(sb)->s_es->s_feature_ro_compat & \
+ cpu_to_le32(~EXT##ver##_FEATURE_RO_COMPAT_SUPP)) != 0); \
+} \
+static inline bool ext4_has_unknown_ext##ver##_incompat_features(struct super_block *sb) \
+{ \
+ return ((EXT4_SB(sb)->s_es->s_feature_incompat & \
+ cpu_to_le32(~EXT##ver##_FEATURE_INCOMPAT_SUPP)) != 0); \
+}
+
+EXTN_FEATURE_FUNCS(2)
+EXTN_FEATURE_FUNCS(3)
+EXTN_FEATURE_FUNCS(4)
+
+static inline bool ext4_has_compat_features(struct super_block *sb)
+{
+ return (EXT4_SB(sb)->s_es->s_feature_compat != 0);
+}
+static inline bool ext4_has_ro_compat_features(struct super_block *sb)
+{
+ return (EXT4_SB(sb)->s_es->s_feature_ro_compat != 0);
+}
+static inline bool ext4_has_incompat_features(struct super_block *sb)
+{
+ return (EXT4_SB(sb)->s_es->s_feature_incompat != 0);
+}
+
+/*
+ * Superblock flags
+ */
+#define EXT4_FLAGS_RESIZING 0
+#define EXT4_FLAGS_SHUTDOWN 1
+
+/*static inline int ext4_forced_shutdown(struct ext4_sb_info *sbi)
+{
+ return test_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags);
+}*/
+
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define EXT4_DEF_RESUID 0
+#define EXT4_DEF_RESGID 0
+
+/*
+ * Default project ID
+ */
+#define EXT4_DEF_PROJID 0
+
+#define EXT4_DEF_INODE_READAHEAD_BLKS 32
+
+/*
+ * Default mount options
+ */
+#define EXT4_DEFM_DEBUG 0x0001
+#define EXT4_DEFM_BSDGROUPS 0x0002
+#define EXT4_DEFM_XATTR_USER 0x0004
+#define EXT4_DEFM_ACL 0x0008
+#define EXT4_DEFM_UID16 0x0010
+#define EXT4_DEFM_JMODE 0x0060
+#define EXT4_DEFM_JMODE_DATA 0x0020
+#define EXT4_DEFM_JMODE_ORDERED 0x0040
+#define EXT4_DEFM_JMODE_WBACK 0x0060
+#define EXT4_DEFM_NOBARRIER 0x0100
+#define EXT4_DEFM_BLOCK_VALIDITY 0x0200
+#define EXT4_DEFM_DISCARD 0x0400
+#define EXT4_DEFM_NODELALLOC 0x0800
+
+/*
+ * Default journal batch times
+ */
+#define EXT4_DEF_MIN_BATCH_TIME 0
+#define EXT4_DEF_MAX_BATCH_TIME 15000 /* 15ms */
+
+/*
+ * Minimum number of groups in a flexgroup before we separate out
+ * directories into the first block group of a flexgroup
+ */
+#define EXT4_FLEX_SIZE_DIR_ALLOC_SCHEME 4
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT4_NAME_LEN 255
+
+struct ext4_dir_entry {
+ __le32 inode; /* Inode number */
+ __le16 rec_len; /* Directory entry length */
+ __le16 name_len; /* Name length */
+ char name[EXT4_NAME_LEN]; /* File name */
+};
+
+/*
+ * The new version of the directory entry. Since EXT4 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext4_dir_entry_2 {
+ __le32 inode; /* Inode number */
+ __le16 rec_len; /* Directory entry length */
+ __u8 name_len; /* Name length */
+ __u8 file_type;
+ char name[EXT4_NAME_LEN]; /* File name */
+};
+
+/*
+ * This is a bogus directory entry at the end of each leaf block that
+ * records checksums.
+ */
+struct ext4_dir_entry_tail {
+ __le32 det_reserved_zero1; /* Pretend to be unused */
+ __le16 det_rec_len; /* 12 */
+ __u8 det_reserved_zero2; /* Zero name length */
+ __u8 det_reserved_ft; /* 0xDE, fake file type */
+ __le32 det_checksum; /* crc32c(uuid+inum+dirblock) */
+};
+
+#define EXT4_DIRENT_TAIL(block, blocksize) \
+ ((struct ext4_dir_entry_tail *)(((unsigned char *)(block)) + \
+ ((blocksize) - \
+ sizeof(struct ext4_dir_entry_tail))))
+
+/*
+ * Ext4 directory file types. Only the low 3 bits are used. The
+ * other bits are reserved for now.
+ */
+#define EXT4_FT_UNKNOWN 0
+#define EXT4_FT_REG_FILE 1
+#define EXT4_FT_DIR 2
+#define EXT4_FT_CHRDEV 3
+#define EXT4_FT_BLKDEV 4
+#define EXT4_FT_FIFO 5
+#define EXT4_FT_SOCK 6
+#define EXT4_FT_SYMLINK 7
+
+#define EXT4_FT_MAX 8
+
+#define EXT4_FT_DIR_CSUM 0xDE
+
+/*
+ * EXT4_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT4_DIR_PAD 4
+#define EXT4_DIR_ROUND (EXT4_DIR_PAD - 1)
+#define EXT4_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT4_DIR_ROUND) & \
+ ~EXT4_DIR_ROUND)
+#define EXT4_MAX_REC_LEN ((1<<16)-1)
+
+/*
+ * If we ever get support for fs block sizes > page_size, we'll need
+ * to remove the #if statements in the next two functions...
+ */
+static inline unsigned int
+ext4_rec_len_from_disk(__le16 dlen, unsigned blocksize)
+{
+ unsigned len = le16_to_cpu(dlen);
+
+#if (PAGE_SIZE >= 65536)
+ if (len == EXT4_MAX_REC_LEN || len == 0)
+ return blocksize;
+ return (len & 65532) | ((len & 3) << 16);
+#else
+ return len;
+#endif
+}
+
+static inline __le16 ext4_rec_len_to_disk(unsigned len, unsigned blocksize)
+{
+ if ((len > blocksize) || (blocksize > (1 << 18)) || (len & 3))
+ BUG();
+#if (PAGE_SIZE >= 65536)
+ if (len < 65536)
+ return cpu_to_le16(len);
+ if (len == blocksize) {
+ if (blocksize == 65536)
+ return cpu_to_le16(EXT4_MAX_REC_LEN);
+ else
+ return cpu_to_le16(0);
+ }
+ return cpu_to_le16((len & 65532) | ((len >> 16) & 3));
+#else
+ return cpu_to_le16(len);
+#endif
+}
+
+/*
+ * Hash Tree Directory indexing
+ * (c) Daniel Phillips, 2001
+ */
+#if 0
+#define is_dx(dir) (ext4_has_feature_dir_index((dir)->i_sb) && \
+ ext4_test_inode_flag((dir), EXT4_INODE_INDEX))
+#define EXT4_DIR_LINK_MAX(dir) unlikely((dir)->i_nlink >= EXT4_LINK_MAX && \
+ !(ext4_has_feature_dir_nlink((dir)->i_sb) && is_dx(dir)))
+#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
+#endif
+/* Legal values for the dx_root hash_version field: */
+
+#define DX_HASH_LEGACY 0
+#define DX_HASH_HALF_MD4 1
+#define DX_HASH_TEA 2
+#define DX_HASH_LEGACY_UNSIGNED 3
+#define DX_HASH_HALF_MD4_UNSIGNED 4
+#define DX_HASH_TEA_UNSIGNED 5
+#if 0
+static inline __u32 ext4_chksum(struct ext4_sb_info *sbi, __u32 crc,
+ const void *address, unsigned int length)
+{
+ struct {
+ struct shash_desc shash;
+ char ctx[4];
+ } desc;
+
+ BUG_ON(crypto_shash_descsize(sbi->s_chksum_driver)!=sizeof(desc.ctx));
+
+ desc.shash.tfm = sbi->s_chksum_driver;
+ desc.shash.flags = 0;
+ *(__u32 *)desc.ctx = crc;
+
+ BUG_ON(crypto_shash_update(&desc.shash, address, length));
+
+ return *(__u32 *)desc.ctx;
+}
+#endif
+#ifdef __KERNEL__
+
+/* hash info structure used by the directory hash */
+struct dx_hash_info
+{
+ __u32 hash;
+ __u32 minor_hash;
+ int hash_version;
+ __u32 *seed;
+};
+
+
+/* 32 and 64 bit signed EOF for dx directories */
+#define EXT4_HTREE_EOF_32BIT ((1UL << (32 - 1)) - 1)
+#define EXT4_HTREE_EOF_64BIT ((1ULL << (64 - 1)) - 1)
+
+
+/*
+ * Control parameters used by ext4_htree_next_block
+ */
+#define HASH_NB_ALWAYS 1
+
+struct ext4_filename {
+ const struct qstr *usr_fname;
+ struct fscrypt_str disk_name;
+ struct dx_hash_info hinfo;
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
+ struct fscrypt_str crypto_buf;
+#endif
+};
+
+#define fname_name(p) ((p)->disk_name.name)
+#define fname_len(p) ((p)->disk_name.len)
+
+/*
+ * Describe an inode's exact location on disk and in memory
+ */
+struct ext4_iloc
+{
+ struct buffer_head *bh;
+ unsigned long offset;
+ ext4_group_t block_group;
+};
+
+static inline struct ext4_inode *ext4_raw_inode(struct ext4_iloc *iloc)
+{
+ return (struct ext4_inode *) (iloc->bh->b_data + iloc->offset);
+}
+
+static inline bool ext4_is_quota_file(struct inode *inode)
+{
+ return IS_NOQUOTA(inode) &&
+ !(EXT4_I(inode)->i_flags & EXT4_EA_INODE_FL);
+}
+
+/*
+ * This structure is stuffed into the struct file's private_data field
+ * for directories. It is where we put information so that we can do
+ * readdir operations in hash tree order.
+ */
+struct dir_private_info {
+ struct rb_root root;
+ struct rb_node *curr_node;
+ struct fname *extra_fname;
+ loff_t last_pos;
+ __u32 curr_hash;
+ __u32 curr_minor_hash;
+ __u32 next_hash;
+};
+
+/* calculate the first block number of the group */
+static inline ext4_fsblk_t
+ext4_group_first_block_no(struct super_block *sb, ext4_group_t group_no)
+{
+ return group_no * (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) +
+ le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);
+}
+
+/*
+ * Special error return code only used by dx_probe() and its callers.
+ */
+#define ERR_BAD_DX_DIR (-(MAX_ERRNO - 1))
+
+/* htree levels for ext4 */
+#define EXT4_HTREE_LEVEL_COMPAT 2
+#define EXT4_HTREE_LEVEL 3
+
+static inline int ext4_dir_htree_level(struct super_block *sb)
+{
+ return ext4_has_feature_largedir(sb) ?
+ EXT4_HTREE_LEVEL : EXT4_HTREE_LEVEL_COMPAT;
+}
+
+/*
+ * Timeout and state flag for lazy initialization inode thread.
+ */
+#define EXT4_DEF_LI_WAIT_MULT 10
+#define EXT4_DEF_LI_MAX_START_DELAY 5
+#define EXT4_LAZYINIT_QUIT 0x0001
+#define EXT4_LAZYINIT_RUNNING 0x0002
+
+/*
+ * Lazy inode table initialization info
+ */
+struct ext4_lazy_init {
+ unsigned long li_state;
+ struct list_head li_request_list;
+ struct mutex li_list_mtx;
+};
+
+struct ext4_li_request {
+ struct super_block *lr_super;
+ struct ext4_sb_info *lr_sbi;
+ ext4_group_t lr_next_group;
+ struct list_head lr_request;
+ unsigned long lr_next_sched;
+ unsigned long lr_timeout;
+};
+
+/*struct ext4_features {
+ struct kobject f_kobj;
+ struct completion f_kobj_unregister;
+};*/
+
+/*
+ * This structure will be used for multiple mount protection. It will be
+ * written into the block number saved in the s_mmp_block field in the
+ * superblock. Programs that check MMP should assume that if
+ * SEQ_FSCK (or any unknown code above SEQ_MAX) is present then it is NOT safe
+ * to use the filesystem, regardless of how old the timestamp is.
+ */
+#define EXT4_MMP_MAGIC 0x004D4D50U /* ASCII for MMP */
+#define EXT4_MMP_SEQ_CLEAN 0xFF4D4D50U /* mmp_seq value for clean unmount */
+#define EXT4_MMP_SEQ_FSCK 0xE24D4D50U /* mmp_seq value when being fscked */
+#define EXT4_MMP_SEQ_MAX 0xE24D4D4FU /* maximum valid mmp_seq value */
+
+struct mmp_struct {
+ __le32 mmp_magic; /* Magic number for MMP */
+ __le32 mmp_seq; /* Sequence no. updated periodically */
+
+ /*
+ * mmp_time, mmp_nodename & mmp_bdevname are only used for information
+ * purposes and do not affect the correctness of the algorithm
+ */
+ __le64 mmp_time; /* Time last updated */
+ char mmp_nodename[64]; /* Node which last updated MMP block */
+ char mmp_bdevname[32]; /* Bdev which last updated MMP block */
+
+ /*
+ * mmp_check_interval is used to verify if the MMP block has been
+ * updated on the block device. The value is updated based on the
+ * maximum time to write the MMP block during an update cycle.
+ */
+ __le16 mmp_check_interval;
+
+ __le16 mmp_pad1;
+ __le32 mmp_pad2[226];
+ __le32 mmp_checksum; /* crc32c(uuid+mmp_block) */
+};
+
+/* arguments passed to the mmp thread */
+struct mmpd_data {
+ struct buffer_head *bh; /* bh from initial read_mmp_block() */
+ struct super_block *sb; /* super block of the fs */
+};
+
+/*
+ * Check interval multiplier
+ * The MMP block is written every update interval and initially checked every
+ * update interval x the multiplier (the value is then adapted based on the
+ * write latency). The reason is that writes can be delayed under load and we
+ * don't want readers to incorrectly assume that the filesystem is no longer
+ * in use.
+ */
+#define EXT4_MMP_CHECK_MULT 2UL
+
+/*
+ * Minimum interval for MMP checking in seconds.
+ */
+#define EXT4_MMP_MIN_CHECK_INTERVAL 5UL
+
+/*
+ * Maximum interval for MMP checking in seconds.
+ */
+#define EXT4_MMP_MAX_CHECK_INTERVAL 300UL
+
+/*
+ * Function prototypes
+ */
+
+/*
+ * Ok, these declarations are also in but none of the
+ * ext4 source programs needs to include it so they are duplicated here.
+ */
+# define NORET_TYPE /**/
+# define ATTRIB_NORET __attribute__((noreturn))
+# define NORET_AND noreturn,
+
+/* bitmap.c */
+extern unsigned int ext4_count_free(char *bitmap, unsigned numchars);
+void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
+ struct ext4_group_desc *gdp,
+ struct buffer_head *bh, int sz);
+int ext4_inode_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
+ struct ext4_group_desc *gdp,
+ struct buffer_head *bh, int sz);
+void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
+ struct ext4_group_desc *gdp,
+ struct buffer_head *bh);
+int ext4_block_bitmap_csum_verify(struct super_block *sb, ext4_group_t group,
+ struct ext4_group_desc *gdp,
+ struct buffer_head *bh);
+
+/* balloc.c */
+extern void ext4_get_group_no_and_offset(struct super_block *sb,
+ ext4_fsblk_t blocknr,
+ ext4_group_t *blockgrpp,
+ ext4_grpblk_t *offsetp);
+extern ext4_group_t ext4_get_group_number(struct super_block *sb,
+ ext4_fsblk_t block);
+
+extern unsigned int ext4_block_group(struct super_block *sb,
+ ext4_fsblk_t blocknr);
+extern ext4_grpblk_t ext4_block_group_offset(struct super_block *sb,
+ ext4_fsblk_t blocknr);
+extern int ext4_bg_has_super(struct super_block *sb, ext4_group_t group);
+extern unsigned long ext4_bg_num_gdb(struct super_block *sb,
+ ext4_group_t group);
+/*extern ext4_fsblk_t ext4_new_meta_blocks(handle_t *handle, struct inode *inode,
+ ext4_fsblk_t goal,
+ unsigned int flags,
+ unsigned long *count,
+ int *errp);*/
+extern int ext4_claim_free_clusters(struct ext4_sb_info *sbi,
+ s64 nclusters, unsigned int flags);
+extern ext4_fsblk_t ext4_count_free_clusters(struct super_block *);
+extern void ext4_check_blocks_bitmap(struct super_block *);
+extern struct ext4_group_desc * ext4_get_group_desc(struct super_block * sb,
+ ext4_group_t block_group,
+ struct buffer_head ** bh);
+extern int ext4_should_retry_alloc(struct super_block *sb, int *retries);
+
+extern struct buffer_head *ext4_read_block_bitmap_nowait(struct super_block *sb,
+ ext4_group_t block_group);
+extern int ext4_wait_block_bitmap(struct super_block *sb,
+ ext4_group_t block_group,
+ struct buffer_head *bh);
+extern struct buffer_head *ext4_read_block_bitmap(struct super_block *sb,
+ ext4_group_t block_group);
+extern unsigned ext4_free_clusters_after_init(struct super_block *sb,
+ ext4_group_t block_group,
+ struct ext4_group_desc *gdp);
+ext4_fsblk_t ext4_inode_to_goal_block(struct inode *);
+#if 0
+static inline bool ext4_encrypted_inode(struct inode *inode)
+{
+ return ext4_test_inode_flag(inode, EXT4_INODE_ENCRYPT);
+}
+#endif
+#ifdef CONFIG_EXT4_FS_ENCRYPTION
+static inline int ext4_fname_setup_filename(struct inode *dir,
+ const struct qstr *iname,
+ int lookup, struct ext4_filename *fname)
+{
+ struct fscrypt_name name;
+ int err;
+
+ memset(fname, 0, sizeof(struct ext4_filename));
+
+ err = fscrypt_setup_filename(dir, iname, lookup, &name);
+
+ fname->usr_fname = name.usr_fname;
+ fname->disk_name = name.disk_name;
+ fname->hinfo.hash = name.hash;
+ fname->hinfo.minor_hash = name.minor_hash;
+ fname->crypto_buf = name.crypto_buf;
+ return err;
+}
+
+static inline void ext4_fname_free_filename(struct ext4_filename *fname)
+{
+ struct fscrypt_name name;
+
+ name.crypto_buf = fname->crypto_buf;
+ fscrypt_free_filename(&name);
+
+ fname->crypto_buf.name = NULL;
+ fname->usr_fname = NULL;
+ fname->disk_name.name = NULL;
+}
+#else
+static inline int ext4_fname_setup_filename(struct inode *dir,
+ const struct qstr *iname,
+ int lookup, struct ext4_filename *fname)
+{
+ fname->usr_fname = iname;
+ fname->disk_name.name = (unsigned char *) iname->name;
+ fname->disk_name.len = iname->len;
+ return 0;
+}
+static inline void ext4_fname_free_filename(struct ext4_filename *fname) { }
+
+#endif
+
+/* dir.c */
+extern int __ext4_check_dir_entry(const char *, unsigned int, struct inode *,
+ struct file *,
+ struct ext4_dir_entry_2 *,
+ struct buffer_head *, char *, int,
+ unsigned int);
+#define ext4_check_dir_entry(dir, filp, de, bh, buf, size, offset) \
+ unlikely(__ext4_check_dir_entry(__func__, __LINE__, (dir), (filp), \
+ (de), (bh), (buf), (size), (offset)))
+extern int ext4_htree_store_dirent(struct file *dir_file, __u32 hash,
+ __u32 minor_hash,
+ struct ext4_dir_entry_2 *dirent,
+ struct fscrypt_str *ent_name);
+extern void ext4_htree_free_dir_info(struct dir_private_info *p);
+extern int ext4_find_dest_de(struct inode *dir, struct inode *inode,
+ struct buffer_head *bh,
+ void *buf, int buf_size,
+ struct ext4_filename *fname,
+ struct ext4_dir_entry_2 **dest_de);
+void ext4_insert_dentry(struct inode *inode,
+ struct ext4_dir_entry_2 *de,
+ int buf_size,
+ struct ext4_filename *fname);
+static inline void ext4_update_dx_flag(struct inode *inode)
+{
+ if (!ext4_has_feature_dir_index(inode->i_sb))
+ ext4_clear_inode_flag(inode, EXT4_INODE_INDEX);
+}
+static const unsigned char ext4_filetype_table[] = {
+ DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
+};
+#if 0
+static inline unsigned char get_dtype(struct super_block *sb, int filetype)
+{
+ if (!ext4_has_feature_filetype(sb) || filetype >= EXT4_FT_MAX)
+ return DT_UNKNOWN;
+
+ return ext4_filetype_table[filetype];
+}
+#endif
+extern int ext4_check_all_de(struct inode *dir, struct buffer_head *bh,
+ void *buf, int buf_size);
+
+/* fsync.c */
+extern int ext4_sync_file(struct file *, loff_t, loff_t, int);
+
+/* hash.c */
+extern int ext4fs_dirhash(const char *name, int len, struct
+ dx_hash_info *hinfo);
+
+/* ialloc.c */
+extern struct inode *__ext4_new_inode(handle_t *, struct inode *, umode_t,
+ const struct qstr *qstr, __u32 goal,
+ uid_t *owner, __u32 i_flags,
+ int handle_type, unsigned int line_no,
+ int nblocks);
+
+#define ext4_new_inode(handle, dir, mode, qstr, goal, owner, i_flags) \
+ __ext4_new_inode((handle), (dir), (mode), (qstr), (goal), (owner), \
+ i_flags, 0, 0, 0)
+#define ext4_new_inode_start_handle(dir, mode, qstr, goal, owner, \
+ type, nblocks) \
+ __ext4_new_inode(NULL, (dir), (mode), (qstr), (goal), (owner), \
+ 0, (type), __LINE__, (nblocks))
+
+
+extern void ext4_free_inode(handle_t *, struct inode *);
+extern struct inode * ext4_orphan_get(struct super_block *, unsigned long);
+extern unsigned long ext4_count_free_inodes(struct super_block *);
+extern unsigned long ext4_count_dirs(struct super_block *);
+extern void ext4_check_inodes_bitmap(struct super_block *);
+extern void ext4_mark_bitmap_end(int start_bit, int end_bit, char *bitmap);
+extern int ext4_init_inode_table(struct super_block *sb,
+ ext4_group_t group, int barrier);
+extern void ext4_end_bitmap_read(struct buffer_head *bh, int uptodate);
+
+/* mballoc.c */
+extern const struct seq_operations ext4_mb_seq_groups_ops;
+extern long ext4_mb_stats;
+extern long ext4_mb_max_to_scan;
+extern int ext4_mb_init(struct super_block *);
+extern int ext4_mb_release(struct super_block *);
+extern ext4_fsblk_t ext4_mb_new_blocks(handle_t *,
+ struct ext4_allocation_request *, int *);
+extern int ext4_mb_reserve_blocks(struct super_block *, int);
+extern void ext4_discard_preallocations(struct inode *);
+extern int __init ext4_init_mballoc(void);
+extern void ext4_exit_mballoc(void);
+/*extern void ext4_free_blocks(handle_t *handle, struct inode *inode,
+ struct buffer_head *bh, ext4_fsblk_t block,
+ unsigned long count, int flags);*/
+extern int ext4_mb_alloc_groupinfo(struct super_block *sb,
+ ext4_group_t ngroups);
+extern int ext4_mb_add_groupinfo(struct super_block *sb,
+ ext4_group_t i, struct ext4_group_desc *desc);
+extern int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,
+ ext4_fsblk_t block, unsigned long count);
+extern int ext4_trim_fs(struct super_block *, struct fstrim_range *);
+extern void ext4_process_freed_data(struct super_block *sb, tid_t commit_tid);
+
+/* inode.c */
+int ext4_inode_is_fast_symlink(struct inode *inode);
+struct buffer_head *ext4_getblk(handle_t *, struct inode *, ext4_lblk_t, int);
+struct buffer_head *ext4_bread(handle_t *, struct inode *, ext4_lblk_t, int);
+int ext4_bread_batch(struct inode *inode, ext4_lblk_t block, int bh_count,
+ bool wait, struct buffer_head **bhs);
+int ext4_get_block_unwritten(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh_result, int create);
+int ext4_get_block(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh_result, int create);
+int ext4_dio_get_block(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh_result, int create);
+int ext4_da_get_block_prep(struct inode *inode, sector_t iblock,
+ struct buffer_head *bh, int create);
+int ext4_walk_page_buffers(handle_t *handle,
+ struct buffer_head *head,
+ unsigned from,
+ unsigned to,
+ int *partial,
+ int (*fn)(handle_t *handle,
+ struct buffer_head *bh));
+int do_journal_get_write_access(handle_t *handle,
+ struct buffer_head *bh);
+#define FALL_BACK_TO_NONDELALLOC 1
+#define CONVERT_INLINE_DATA 2
+
+typedef enum {
+ EXT4_IGET_NORMAL = 0,
+ EXT4_IGET_SPECIAL = 0x0001, /* OK to iget a system inode */
+ EXT4_IGET_HANDLE = 0x0002 /* Inode # is from a handle */
+} ext4_iget_flags;
+
+extern struct inode *__ext4_iget(struct super_block *sb, unsigned long ino,
+ ext4_iget_flags flags, const char *function,
+ unsigned int line);
+
+#define ext4_iget(sb, ino, flags) \
+ __ext4_iget((sb), (ino), (flags), __func__, __LINE__)
+
+extern int ext4_write_inode(struct inode *, struct writeback_control *);
+extern int ext4_setattr(struct dentry *, struct iattr *);
+extern int ext4_getattr(const struct path *, struct kstat *, __u32, unsigned int);
+extern void ext4_evict_inode(struct inode *);
+extern void ext4_clear_inode(struct inode *);
+extern int ext4_file_getattr(const struct path *, struct kstat *, __u32, unsigned int);
+extern int ext4_sync_inode(handle_t *, struct inode *);
+extern void ext4_dirty_inode(struct inode *, int);
+extern int ext4_change_inode_journal_flag(struct inode *, int);
+extern int ext4_get_inode_loc(struct inode *, struct ext4_iloc *);
+extern int ext4_inode_attach_jinode(struct inode *inode);
+extern int ext4_can_truncate(struct inode *inode);
+extern int ext4_truncate(struct inode *);
+extern int ext4_break_layouts(struct inode *);
+extern int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length);
+extern int ext4_truncate_restart_trans(handle_t *, struct inode *, int nblocks);
+extern void ext4_set_inode_flags(struct inode *);
+extern int ext4_alloc_da_blocks(struct inode *inode);
+extern void ext4_set_aops(struct inode *inode);
+extern int ext4_writepage_trans_blocks(struct inode *);
+extern int ext4_chunk_trans_blocks(struct inode *, int nrblocks);
+extern int ext4_zero_partial_blocks(handle_t *handle, struct inode *inode,
+ loff_t lstart, loff_t lend);
+extern vm_fault_t ext4_page_mkwrite(struct vm_fault *vmf);
+extern vm_fault_t ext4_filemap_fault(struct vm_fault *vmf);
+extern qsize_t *ext4_get_reserved_space(struct inode *inode);
+extern int ext4_get_projid(struct inode *inode, kprojid_t *projid);
+extern void ext4_da_release_space(struct inode *inode, int to_free);
+extern void ext4_da_update_reserve_space(struct inode *inode,
+ int used, int quota_claim);
+extern int ext4_issue_zeroout(struct inode *inode, ext4_lblk_t lblk,
+ ext4_fsblk_t pblk, ext4_lblk_t len);
+
+/* indirect.c */
+extern int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
+ struct ext4_map_blocks *map, int flags);
+extern int ext4_ind_calc_metadata_amount(struct inode *inode, sector_t lblock);
+extern int ext4_ind_trans_blocks(struct inode *inode, int nrblocks);
+extern void ext4_ind_truncate(handle_t *, struct inode *inode);
+extern int ext4_ind_remove_space(handle_t *handle, struct inode *inode,
+ ext4_lblk_t start, ext4_lblk_t end);
+
+/* ioctl.c */
+extern long ext4_ioctl(struct file *, unsigned int, unsigned long);
+extern long ext4_compat_ioctl(struct file *, unsigned int, unsigned long);
+
+/* migrate.c */
+extern int ext4_ext_migrate(struct inode *);
+extern int ext4_ind_migrate(struct inode *inode);
+
+/* namei.c */
+extern int ext4_dirent_csum_verify(struct inode *inode,
+ struct ext4_dir_entry *dirent);
+extern int ext4_orphan_add(handle_t *, struct inode *);
+extern int ext4_orphan_del(handle_t *, struct inode *);
+extern int ext4_htree_fill_tree(struct file *dir_file, __u32 start_hash,
+ __u32 start_minor_hash, __u32 *next_hash);
+extern int ext4_search_dir(struct buffer_head *bh,
+ char *search_buf,
+ int buf_size,
+ struct inode *dir,
+ struct ext4_filename *fname,
+ unsigned int offset,
+ struct ext4_dir_entry_2 **res_dir);
+extern int ext4_generic_delete_entry(handle_t *handle,
+ struct inode *dir,
+ struct ext4_dir_entry_2 *de_del,
+ struct buffer_head *bh,
+ void *entry_buf,
+ int buf_size,
+ int csum_size);
+extern bool ext4_empty_dir(struct inode *inode);
+
+/* resize.c */
+extern int ext4_group_add(struct super_block *sb,
+ struct ext4_new_group_data *input);
+extern int ext4_group_extend(struct super_block *sb,
+ struct ext4_super_block *es,
+ ext4_fsblk_t n_blocks_count);
+extern int ext4_resize_fs(struct super_block *sb, ext4_fsblk_t n_blocks_count);
+
+/* super.c */
+extern struct buffer_head *ext4_sb_bread(struct super_block *sb,
+ sector_t block, int op_flags);
+extern int ext4_seq_options_show(struct seq_file *seq, void *offset);
+extern int ext4_calculate_overhead(struct super_block *sb);
+extern void ext4_superblock_csum_set(struct super_block *sb);
+extern void *ext4_kvmalloc(size_t size, gfp_t flags);
+extern void *ext4_kvzalloc(size_t size, gfp_t flags);
+extern int ext4_alloc_flex_bg_array(struct super_block *sb,
+ ext4_group_t ngroup);
+extern const char *ext4_decode_error(struct super_block *sb, int errno,
+ char nbuf[16]);
+extern void ext4_mark_group_bitmap_corrupted(struct super_block *sb,
+ ext4_group_t block_group,
+ unsigned int flags);
+
+//extern __printf(4, 5)
+void __ext4_error(struct super_block *, const char *, unsigned int,
+ const char *, ...);
+//extern __printf(5, 6)
+void __ext4_error_inode(struct inode *, const char *, unsigned int, ext4_fsblk_t,
+ const char *, ...);
+//extern __printf(5, 6)
+void __ext4_error_file(struct file *, const char *, unsigned int, ext4_fsblk_t,
+ const char *, ...);
+extern void __ext4_std_error(struct super_block *, const char *,
+ unsigned int, int);
+//extern __printf(4, 5)
+void __ext4_abort(struct super_block *, const char *, unsigned int,
+ const char *, ...);
+//extern __printf(4, 5)
+void __ext4_warning(struct super_block *, const char *, unsigned int,
+ const char *, ...);
+//extern __printf(4, 5)
+void __ext4_warning_inode(const struct inode *inode, const char *function,
+ unsigned int line, const char *fmt, ...);
+//extern __printf(3, 4)
+void __ext4_msg(struct super_block *, const char *, const char *, ...);
+extern void __dump_mmp_msg(struct super_block *, struct mmp_struct *mmp,
+ const char *, unsigned int, const char *);
+//extern __printf(7, 8)
+void __ext4_grp_locked_error(const char *, unsigned int,
+ struct super_block *, ext4_group_t,
+ unsigned long, ext4_fsblk_t,
+ const char *, ...);
+#if 0
+#define EXT4_ERROR_INODE(inode, fmt, a...) \
+ ext4_error_inode((inode), __func__, __LINE__, 0, (fmt), ## a)
+
+#define EXT4_ERROR_INODE_BLOCK(inode, block, fmt, a...) \
+ ext4_error_inode((inode), __func__, __LINE__, (block), (fmt), ## a)
+
+#define EXT4_ERROR_FILE(file, block, fmt, a...) \
+ ext4_error_file((file), __func__, __LINE__, (block), (fmt), ## a)
+#endif
+#ifdef CONFIG_PRINTK
+
+#define ext4_error_inode(inode, func, line, block, fmt, ...) \
+ __ext4_error_inode(inode, func, line, block, fmt, ##__VA_ARGS__)
+#define ext4_error_file(file, func, line, block, fmt, ...) \
+ __ext4_error_file(file, func, line, block, fmt, ##__VA_ARGS__)
+/*#define ext4_error(sb, fmt, ...) \
+ __ext4_error(sb, __func__, __LINE__, fmt, ##__VA_ARGS__)*/
+#define ext4_abort(sb, fmt, ...) \
+ __ext4_abort(sb, __func__, __LINE__, fmt, ##__VA_ARGS__)
+#define ext4_warning(sb, fmt, ...) \
+ __ext4_warning(sb, __func__, __LINE__, fmt, ##__VA_ARGS__)
+#define ext4_warning_inode(inode, fmt, ...) \
+ __ext4_warning_inode(inode, __func__, __LINE__, fmt, ##__VA_ARGS__)
+#define ext4_msg(sb, level, fmt, ...) \
+ __ext4_msg(sb, level, fmt, ##__VA_ARGS__)
+#define dump_mmp_msg(sb, mmp, msg) \
+ __dump_mmp_msg(sb, mmp, __func__, __LINE__, msg)
+#define ext4_grp_locked_error(sb, grp, ino, block, fmt, ...) \
+ __ext4_grp_locked_error(__func__, __LINE__, sb, grp, ino, block, \
+ fmt, ##__VA_ARGS__)
+
+#else
+
+#define ext4_error_inode(inode, func, line, block, fmt, ...) \
+do { \
+ no_printk(fmt, ##__VA_ARGS__); \
+ __ext4_error_inode(inode, "", 0, block, " "); \
+} while (0)
+#define ext4_error_file(file, func, line, block, fmt, ...) \
+do { \
+ no_printk(fmt, ##__VA_ARGS__); \
+ __ext4_error_file(file, "", 0, block, " "); \
+} while (0)
+#if 0
+#define ext4_error(sb, fmt, ...) \
+do { \
+ no_printk(fmt, ##__VA_ARGS__); \
+ __ext4_error(sb, "", 0, " "); \
+} while (0)
+#endif
+#define ext4_abort(sb, fmt, ...) \
+do { \
+ no_printk(fmt, ##__VA_ARGS__); \
+ __ext4_abort(sb, "", 0, " "); \
+} while (0)
+#define ext4_warning(sb, fmt, ...) \
+do { \
+ no_printk(fmt, ##__VA_ARGS__); \
+ __ext4_warning(sb, "", 0, " "); \
+} while (0)
+#define ext4_warning_inode(inode, fmt, ...) \
+do { \
+ no_printk(fmt, ##__VA_ARGS__); \
+ __ext4_warning_inode(inode, "", 0, " "); \
+} while (0)
+#define ext4_msg(sb, level, fmt, ...) \
+do { \
+ no_printk(fmt, ##__VA_ARGS__); \
+ __ext4_msg(sb, "", " "); \
+} while (0)
+#define dump_mmp_msg(sb, mmp, msg) \
+ __dump_mmp_msg(sb, mmp, "", 0, "")
+#define ext4_grp_locked_error(sb, grp, ino, block, fmt, ...) \
+do { \
+ no_printk(fmt, ##__VA_ARGS__); \
+ __ext4_grp_locked_error("", 0, sb, grp, ino, block, " "); \
+} while (0)
+
+#endif
+
+extern void ext4_update_dynamic_rev(struct super_block *sb);
+extern int ext4_update_compat_feature(handle_t *handle, struct super_block *sb,
+ __u32 compat);
+extern int ext4_update_rocompat_feature(handle_t *handle,
+ struct super_block *sb, __u32 rocompat);
+extern int ext4_update_incompat_feature(handle_t *handle,
+ struct super_block *sb, __u32 incompat);
+extern ext4_fsblk_t ext4_block_bitmap(struct super_block *sb,
+ struct ext4_group_desc *bg);
+extern ext4_fsblk_t ext4_inode_bitmap(struct super_block *sb,
+ struct ext4_group_desc *bg);
+extern ext4_fsblk_t ext4_inode_table(struct super_block *sb,
+ struct ext4_group_desc *bg);
+extern __u32 ext4_free_group_clusters(struct super_block *sb,
+ struct ext4_group_desc *bg);
+extern __u32 ext4_free_inodes_count(struct super_block *sb,
+ struct ext4_group_desc *bg);
+extern __u32 ext4_used_dirs_count(struct super_block *sb,
+ struct ext4_group_desc *bg);
+extern __u32 ext4_itable_unused_count(struct super_block *sb,
+ struct ext4_group_desc *bg);
+extern void ext4_block_bitmap_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk);
+extern void ext4_inode_bitmap_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk);
+extern void ext4_inode_table_set(struct super_block *sb,
+ struct ext4_group_desc *bg, ext4_fsblk_t blk);
+extern void ext4_free_group_clusters_set(struct super_block *sb,
+ struct ext4_group_desc *bg,
+ __u32 count);
+extern void ext4_free_inodes_set(struct super_block *sb,
+ struct ext4_group_desc *bg, __u32 count);
+extern void ext4_used_dirs_set(struct super_block *sb,
+ struct ext4_group_desc *bg, __u32 count);
+extern void ext4_itable_unused_set(struct super_block *sb,
+ struct ext4_group_desc *bg, __u32 count);
+/*extern int ext4_group_desc_csum_verify(struct super_block *sb, __u32 group,
+ struct ext4_group_desc *gdp);
+extern void ext4_group_desc_csum_set(struct super_block *sb, __u32 group,
+ struct ext4_group_desc *gdp);*/
+extern int ext4_register_li_request(struct super_block *sb,
+ ext4_group_t first_not_zeroed);
+
+static inline int ext4_has_metadata_csum(struct super_block *sb)
+{
+ /*WARN_ON_ONCE(ext4_has_feature_metadata_csum(sb) &&
+ !EXT4_SB(sb)->s_chksum_driver);*/
+
+ return ext4_has_feature_metadata_csum(sb)/* &&
+ (EXT4_SB(sb)->s_chksum_driver != NULL)*/;
+}
+
+static inline int ext4_has_group_desc_csum(struct super_block *sb)
+{
+ return ext4_has_feature_gdt_csum(sb) || ext4_has_metadata_csum(sb);
+}
+
+static inline ext4_fsblk_t ext4_blocks_count(struct ext4_super_block *es)
+{
+ return ((ext4_fsblk_t)le32_to_cpu(es->s_blocks_count_hi) << 32) |
+ le32_to_cpu(es->s_blocks_count_lo);
+}
+
+static inline ext4_fsblk_t ext4_r_blocks_count(struct ext4_super_block *es)
+{
+ return ((ext4_fsblk_t)le32_to_cpu(es->s_r_blocks_count_hi) << 32) |
+ le32_to_cpu(es->s_r_blocks_count_lo);
+}
+
+static inline ext4_fsblk_t ext4_free_blocks_count(struct ext4_super_block *es)
+{
+ return ((ext4_fsblk_t)le32_to_cpu(es->s_free_blocks_count_hi) << 32) |
+ le32_to_cpu(es->s_free_blocks_count_lo);
+}
+
+static inline void ext4_blocks_count_set(struct ext4_super_block *es,
+ ext4_fsblk_t blk)
+{
+ es->s_blocks_count_lo = cpu_to_le32((__u32)blk);
+ es->s_blocks_count_hi = cpu_to_le32(blk >> 32);
+}
+
+static inline void ext4_free_blocks_count_set(struct ext4_super_block *es,
+ ext4_fsblk_t blk)
+{
+ es->s_free_blocks_count_lo = cpu_to_le32((__u32)blk);
+ es->s_free_blocks_count_hi = cpu_to_le32(blk >> 32);
+}
+
+static inline void ext4_r_blocks_count_set(struct ext4_super_block *es,
+ ext4_fsblk_t blk)
+{
+ es->s_r_blocks_count_lo = cpu_to_le32((__u32)blk);
+ es->s_r_blocks_count_hi = cpu_to_le32(blk >> 32);
+}
+
+static inline loff_t ext4_isize(struct super_block *sb,
+ struct ext4_inode *raw_inode)
+{
+ if (ext4_has_feature_largedir(sb) ||
+ S_ISREG(le16_to_cpu(raw_inode->i_mode)))
+ return ((loff_t)le32_to_cpu(raw_inode->i_size_high) << 32) |
+ le32_to_cpu(raw_inode->i_size_lo);
+
+ return (loff_t) le32_to_cpu(raw_inode->i_size_lo);
+}
+
+static inline void ext4_isize_set(struct ext4_inode *raw_inode, loff_t i_size)
+{
+ raw_inode->i_size_lo = cpu_to_le32(i_size);
+ raw_inode->i_size_high = cpu_to_le32(i_size >> 32);
+}
+#if 0
+static inline
+struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
+ ext4_group_t group)
+{
+ struct ext4_group_info ***grp_info;
+ long indexv, indexh;
+ BUG_ON(group >= EXT4_SB(sb)->s_groups_count);
+ grp_info = EXT4_SB(sb)->s_group_info;
+ indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb));
+ indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1);
+ return grp_info[indexv][indexh];
+}
+#endif
+/*
+ * Reading s_groups_count requires using smp_rmb() afterwards. See
+ * the locking protocol documented in the comments of ext4_group_add()
+ * in resize.c
+ */
+static inline ext4_group_t ext4_get_groups_count(struct super_block *sb)
+{
+ ext4_group_t ngroups = EXT4_SB(sb)->s_groups_count;
+
+ smp_rmb();
+ return ngroups;
+}
+#if 0
+static inline ext4_group_t ext4_flex_group(struct ext4_sb_info *sbi,
+ ext4_group_t block_group)
+{
+ return block_group >> sbi->s_log_groups_per_flex;
+}
+
+static inline unsigned int ext4_flex_bg_size(struct ext4_sb_info *sbi)
+{
+ return 1 << sbi->s_log_groups_per_flex;
+}
+
+#define ext4_std_error(sb, errno) \
+do { \
+ if ((errno)) \
+ __ext4_std_error((sb), __func__, __LINE__, (errno)); \
+} while (0)
+#endif
+#ifdef CONFIG_SMP
+/* Each CPU can accumulate percpu_counter_batch clusters in their local
+ * counters. So we need to make sure we have free clusters more
+ * than percpu_counter_batch * nr_cpu_ids. Also add a window of 4 times.
+ */
+#define EXT4_FREECLUSTERS_WATERMARK (4 * (percpu_counter_batch * nr_cpu_ids))
+#else
+#define EXT4_FREECLUSTERS_WATERMARK 0
+#endif
+#if 0
+/* Update i_disksize. Requires i_mutex to avoid races with truncate */
+static inline void ext4_update_i_disksize(struct inode *inode, loff_t newsize)
+{
+ /*WARN_ON_ONCE(S_ISREG(inode->i_mode) &&
+ !inode_is_locked(inode));*/
+ down_write(&EXT4_I(inode)->i_data_sem);
+ if (newsize > EXT4_I(inode)->i_disksize)
+ EXT4_I(inode)->i_disksize = newsize;
+ up_write(&EXT4_I(inode)->i_data_sem);
+}
+
+/* Update i_size, i_disksize. Requires i_mutex to avoid races with truncate */
+static inline int ext4_update_inode_size(struct inode *inode, loff_t newsize)
+{
+ int changed = 0;
+
+ if (newsize > inode->i_size) {
+ i_size_write(inode, newsize);
+ changed = 1;
+ }
+ if (newsize > EXT4_I(inode)->i_disksize) {
+ ext4_update_i_disksize(inode, newsize);
+ changed |= 2;
+ }
+ return changed;
+}
+#endif
+int ext4_update_disksize_before_punch(struct inode *inode, loff_t offset,
+ loff_t len);
+#if 0
+struct ext4_group_info {
+ unsigned long bb_state;
+ struct rb_root bb_free_root;
+ ext4_grpblk_t bb_first_free; /* first free block */
+ ext4_grpblk_t bb_free; /* total free blocks */
+ ext4_grpblk_t bb_fragments; /* nr of freespace fragments */
+ ext4_grpblk_t bb_largest_free_order;/* order of largest frag in BG */
+ struct list_head bb_prealloc_list;
+#ifdef DOUBLE_CHECK
+ void *bb_bitmap;
+#endif
+ //struct rw_semaphore alloc_sem;
+ ext4_grpblk_t bb_counters[]; /* Nr of free power-of-two-block
+ * regions, index is order.
+ * bb_counters[3] = 5 means
+ * 5 free 8-block regions. */
+};
+#endif
+#define EXT4_GROUP_INFO_NEED_INIT_BIT 0
+#define EXT4_GROUP_INFO_WAS_TRIMMED_BIT 1
+#define EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT 2
+#define EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT 3
+#define EXT4_GROUP_INFO_BBITMAP_CORRUPT \
+ (1 << EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT)
+#define EXT4_GROUP_INFO_IBITMAP_CORRUPT \
+ (1 << EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT)
+
+#define EXT4_MB_GRP_NEED_INIT(grp) \
+ (test_bit(EXT4_GROUP_INFO_NEED_INIT_BIT, &((grp)->bb_state)))
+#define EXT4_MB_GRP_BBITMAP_CORRUPT(grp) \
+ (test_bit(EXT4_GROUP_INFO_BBITMAP_CORRUPT_BIT, &((grp)->bb_state)))
+#define EXT4_MB_GRP_IBITMAP_CORRUPT(grp) \
+ (test_bit(EXT4_GROUP_INFO_IBITMAP_CORRUPT_BIT, &((grp)->bb_state)))
+
+#define EXT4_MB_GRP_WAS_TRIMMED(grp) \
+ (test_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
+#define EXT4_MB_GRP_SET_TRIMMED(grp) \
+ (set_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
+#define EXT4_MB_GRP_CLEAR_TRIMMED(grp) \
+ (clear_bit(EXT4_GROUP_INFO_WAS_TRIMMED_BIT, &((grp)->bb_state)))
+
+#define EXT4_MAX_CONTENTION 8
+#define EXT4_CONTENTION_THRESHOLD 2
+#if 0
+static inline spinlock_t *ext4_group_lock_ptr(struct super_block *sb,
+ ext4_group_t group)
+{
+ return bgl_lock_ptr(EXT4_SB(sb)->s_blockgroup_lock, group);
+}
+
+/*
+ * Returns true if the filesystem is busy enough that attempts to
+ * access the block group locks has run into contention.
+ */
+static inline int ext4_fs_is_busy(struct ext4_sb_info *sbi)
+{
+ return (atomic_read(&sbi->s_lock_busy) > EXT4_CONTENTION_THRESHOLD);
+}
+
+static inline void ext4_lock_group(struct super_block *sb, ext4_group_t group)
+{
+ spinlock_t *lock = ext4_group_lock_ptr(sb, group);
+ if (spin_trylock(lock))
+ /*
+ * We're able to grab the lock right away, so drop the
+ * lock contention counter.
+ */
+ atomic_add_unless(&EXT4_SB(sb)->s_lock_busy, -1, 0);
+ else {
+ /*
+ * The lock is busy, so bump the contention counter,
+ * and then wait on the spin lock.
+ */
+ atomic_add_unless(&EXT4_SB(sb)->s_lock_busy, 1,
+ EXT4_MAX_CONTENTION);
+ spin_lock(lock);
+ }
+}
+
+static inline void ext4_unlock_group(struct super_block *sb,
+ ext4_group_t group)
+{
+ spin_unlock(ext4_group_lock_ptr(sb, group));
+}
+#endif
+/*
+ * Block validity checking
+ */
+#define ext4_check_indirect_blockref(inode, bh) \
+ ext4_check_blockref(__func__, __LINE__, inode, \
+ (__le32 *)(bh)->b_data, \
+ EXT4_ADDR_PER_BLOCK((inode)->i_sb))
+
+#define ext4_ind_check_inode(inode) \
+ ext4_check_blockref(__func__, __LINE__, inode, \
+ EXT4_I(inode)->i_data, \
+ EXT4_NDIR_BLOCKS)
+
+/*
+ * Inodes and files operations
+ */
+
+/* dir.c */
+extern const struct file_operations ext4_dir_operations;
+
+/* file.c */
+extern const struct inode_operations ext4_file_inode_operations;
+extern const struct file_operations ext4_file_operations;
+extern loff_t ext4_llseek(struct file *file, loff_t offset, int origin);
+
+/* inline.c */
+extern int ext4_get_max_inline_size(struct inode *inode);
+extern int ext4_find_inline_data_nolock(struct inode *inode);
+extern int ext4_init_inline_data(handle_t *handle, struct inode *inode,
+ unsigned int len);
+extern int ext4_destroy_inline_data(handle_t *handle, struct inode *inode);
+
+extern int ext4_readpage_inline(struct inode *inode, struct page *page);
+extern int ext4_try_to_write_inline_data(struct address_space *mapping,
+ struct inode *inode,
+ loff_t pos, unsigned len,
+ unsigned flags,
+ struct page **pagep);
+extern int ext4_write_inline_data_end(struct inode *inode,
+ loff_t pos, unsigned len,
+ unsigned copied,
+ struct page *page);
+extern struct buffer_head *
+ext4_journalled_write_inline_data(struct inode *inode,
+ unsigned len,
+ struct page *page);
+extern int ext4_da_write_inline_data_begin(struct address_space *mapping,
+ struct inode *inode,
+ loff_t pos, unsigned len,
+ unsigned flags,
+ struct page **pagep,
+ void **fsdata);
+extern int ext4_da_write_inline_data_end(struct inode *inode, loff_t pos,
+ unsigned len, unsigned copied,
+ struct page *page);
+extern int ext4_try_add_inline_entry(handle_t *handle,
+ struct ext4_filename *fname,
+ struct inode *dir, struct inode *inode);
+extern int ext4_try_create_inline_dir(handle_t *handle,
+ struct inode *parent,
+ struct inode *inode);
+extern int ext4_read_inline_dir(struct file *filp,
+ struct dir_context *ctx,
+ int *has_inline_data);
+extern int htree_inlinedir_to_tree(struct file *dir_file,
+ struct inode *dir, ext4_lblk_t block,
+ struct dx_hash_info *hinfo,
+ __u32 start_hash, __u32 start_minor_hash,
+ int *has_inline_data);
+extern struct buffer_head *ext4_find_inline_entry(struct inode *dir,
+ struct ext4_filename *fname,
+ struct ext4_dir_entry_2 **res_dir,
+ int *has_inline_data);
+extern int ext4_delete_inline_entry(handle_t *handle,
+ struct inode *dir,
+ struct ext4_dir_entry_2 *de_del,
+ struct buffer_head *bh,
+ int *has_inline_data);
+extern bool empty_inline_dir(struct inode *dir, int *has_inline_data);
+extern struct buffer_head *ext4_get_first_inline_block(struct inode *inode,
+ struct ext4_dir_entry_2 **parent_de,
+ int *retval);
+extern int ext4_inline_data_fiemap(struct inode *inode,
+ struct fiemap_extent_info *fieinfo,
+ int *has_inline, __u64 start, __u64 len);
+
+struct iomap;
+extern int ext4_inline_data_iomap(struct inode *inode, struct iomap *iomap);
+
+extern int ext4_inline_data_truncate(struct inode *inode, int *has_inline);
+
+extern int ext4_convert_inline_data(struct inode *inode);
+#if 0
+static inline int ext4_has_inline_data(struct inode *inode)
+{
+ return ext4_test_inode_flag(inode, EXT4_INODE_INLINE_DATA) &&
+ EXT4_I(inode)->i_inline_off;
+}
+#endif
+/* namei.c */
+extern const struct inode_operations ext4_dir_inode_operations;
+extern const struct inode_operations ext4_special_inode_operations;
+extern struct dentry *ext4_get_parent(struct dentry *child);
+extern struct ext4_dir_entry_2 *ext4_init_dot_dotdot(struct inode *inode,
+ struct ext4_dir_entry_2 *de,
+ int blocksize, int csum_size,
+ unsigned int parent_ino, int dotdot_real_len);
+extern void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
+ unsigned int blocksize);
+extern int ext4_handle_dirty_dirent_node(handle_t *handle,
+ struct inode *inode,
+ struct buffer_head *bh);
+#define S_SHIFT 12
+#if 0
+static const unsigned char ext4_type_by_mode[(S_IFMT >> S_SHIFT) + 1] = {
+ [S_IFREG >> S_SHIFT] = EXT4_FT_REG_FILE,
+ [S_IFDIR >> S_SHIFT] = EXT4_FT_DIR,
+ [S_IFCHR >> S_SHIFT] = EXT4_FT_CHRDEV,
+ [S_IFBLK >> S_SHIFT] = EXT4_FT_BLKDEV,
+ [S_IFIFO >> S_SHIFT] = EXT4_FT_FIFO,
+ [S_IFSOCK >> S_SHIFT] = EXT4_FT_SOCK,
+ [S_IFLNK >> S_SHIFT] = EXT4_FT_SYMLINK,
+};
+
+static inline void ext4_set_de_type(struct super_block *sb,
+ struct ext4_dir_entry_2 *de,
+ umode_t mode) {
+ if (ext4_has_feature_filetype(sb))
+ de->file_type = ext4_type_by_mode[(mode & S_IFMT)>>S_SHIFT];
+}
+#endif
+/* readpages.c */
+extern int ext4_mpage_readpages(struct address_space *mapping,
+ struct list_head *pages, struct page *page,
+ unsigned nr_pages, bool is_readahead);
+
+/* symlink.c */
+extern const struct inode_operations ext4_encrypted_symlink_inode_operations;
+extern const struct inode_operations ext4_symlink_inode_operations;
+extern const struct inode_operations ext4_fast_symlink_inode_operations;
+
+/* sysfs.c */
+extern int ext4_register_sysfs(struct super_block *sb);
+extern void ext4_unregister_sysfs(struct super_block *sb);
+extern int __init ext4_init_sysfs(void);
+extern void ext4_exit_sysfs(void);
+
+/* block_validity */
+extern void ext4_release_system_zone(struct super_block *sb);
+extern int ext4_setup_system_zone(struct super_block *sb);
+extern int __init ext4_init_system_zone(void);
+extern void ext4_exit_system_zone(void);
+extern int ext4_data_block_valid(struct ext4_sb_info *sbi,
+ ext4_fsblk_t start_blk,
+ unsigned int count);
+extern int ext4_check_blockref(const char *, unsigned int,
+ struct inode *, __le32 *, unsigned int);
+
+/* extents.c */
+struct ext4_ext_path;
+struct ext4_extent;
+
+/*
+ * Maximum number of logical blocks in a file; ext4_extent's ee_block is
+ * __le32.
+ */
+#define EXT_MAX_BLOCKS 0xffffffff
+
+//extern int ext4_ext_tree_init(handle_t *handle, struct inode *);
+extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
+extern int ext4_ext_index_trans_blocks(struct inode *inode, int extents);
+extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
+ struct ext4_map_blocks *map, int flags);
+//extern int ext4_ext_truncate(handle_t *, struct inode *);
+/*extern int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start,
+ ext4_lblk_t end);*/
+extern void ext4_ext_init(struct super_block *);
+extern void ext4_ext_release(struct super_block *);
+extern long ext4_fallocate(struct file *file, int mode, loff_t offset,
+ loff_t len);
+extern int ext4_convert_unwritten_extents(handle_t *handle, struct inode *inode,
+ loff_t offset, ssize_t len);
+extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
+ struct ext4_map_blocks *map, int flags);
+extern int ext4_ext_calc_metadata_amount(struct inode *inode,
+ ext4_lblk_t lblocks);
+extern int ext4_ext_calc_credits_for_single_extent(struct inode *inode,
+ int num,
+ struct ext4_ext_path *path);
+extern int ext4_can_extents_be_merged(struct inode *inode,
+ struct ext4_extent *ex1,
+ struct ext4_extent *ex2);
+/*extern int ext4_ext_insert_extent(handle_t *, struct inode *,
+ struct ext4_ext_path **,
+ struct ext4_extent *, int);*/
+extern struct ext4_ext_path *ext4_find_extent(struct inode *, ext4_lblk_t,
+ struct ext4_ext_path **,
+ int flags);
+extern void ext4_ext_drop_refs(struct ext4_ext_path *);
+extern int ext4_ext_check_inode(struct inode *inode);
+extern ext4_lblk_t ext4_ext_next_allocated_block(struct ext4_ext_path *path);
+extern int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
+ __u64 start, __u64 len);
+extern int ext4_ext_precache(struct inode *inode);
+extern int ext4_collapse_range(struct inode *inode, loff_t offset, loff_t len);
+extern int ext4_insert_range(struct inode *inode, loff_t offset, loff_t len);
+extern int ext4_swap_extents(handle_t *handle, struct inode *inode1,
+ struct inode *inode2, ext4_lblk_t lblk1,
+ ext4_lblk_t lblk2, ext4_lblk_t count,
+ int mark_unwritten,int *err);
+extern int ext4_clu_mapped(struct inode *inode, ext4_lblk_t lclu);
+
+/* move_extent.c */
+extern void ext4_double_down_write_data_sem(struct inode *first,
+ struct inode *second);
+extern void ext4_double_up_write_data_sem(struct inode *orig_inode,
+ struct inode *donor_inode);
+extern int ext4_move_extents(struct file *o_filp, struct file *d_filp,
+ __u64 start_orig, __u64 start_donor,
+ __u64 len, __u64 *moved_len);
+
+/* page-io.c */
+extern int __init ext4_init_pageio(void);
+extern void ext4_exit_pageio(void);
+extern ext4_io_end_t *ext4_init_io_end(struct inode *inode, gfp_t flags);
+extern ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end);
+extern int ext4_put_io_end(ext4_io_end_t *io_end);
+extern void ext4_put_io_end_defer(ext4_io_end_t *io_end);
+extern void ext4_io_submit_init(struct ext4_io_submit *io,
+ struct writeback_control *wbc);
+extern void ext4_end_io_rsv_work(struct work_struct *work);
+extern void ext4_io_submit(struct ext4_io_submit *io);
+extern int ext4_bio_write_page(struct ext4_io_submit *io,
+ struct page *page,
+ int len,
+ struct writeback_control *wbc,
+ bool keep_towrite);
+
+/* mmp.c */
+extern int ext4_multi_mount_protect(struct super_block *, ext4_fsblk_t);
+#if 0
+/*
+ * Add new method to test whether block and inode bitmaps are properly
+ * initialized. With uninit_bg reading the block from disk is not enough
+ * to mark the bitmap uptodate. We need to also zero-out the bitmap
+ */
+#define BH_BITMAP_UPTODATE BH_JBDPrivateStart
+
+static inline int bitmap_uptodate(struct buffer_head *bh)
+{
+ return (buffer_uptodate(bh) &&
+ test_bit(BH_BITMAP_UPTODATE, &(bh)->b_state));
+}
+static inline void set_bitmap_uptodate(struct buffer_head *bh)
+{
+ set_bit(BH_BITMAP_UPTODATE, &(bh)->b_state);
+}
+#endif
+#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1)
+
+/* For ioend & aio unwritten conversion wait queues */
+#define EXT4_WQ_HASH_SZ 37
+#define ext4_ioend_wq(v) (&ext4__ioend_wq[((unsigned long)(v)) %\
+ EXT4_WQ_HASH_SZ])
+extern wait_queue_head_t ext4__ioend_wq[EXT4_WQ_HASH_SZ];
+
+extern int ext4_resize_begin(struct super_block *sb);
+extern void ext4_resize_end(struct super_block *sb);
+#if 0
+static inline void ext4_set_io_unwritten_flag(struct inode *inode,
+ struct ext4_io_end *io_end)
+{
+ if (!(io_end->flag & EXT4_IO_END_UNWRITTEN)) {
+ io_end->flag |= EXT4_IO_END_UNWRITTEN;
+ atomic_inc(&EXT4_I(inode)->i_unwritten);
+ }
+}
+
+static inline void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end)
+{
+ struct inode *inode = io_end->inode;
+
+ if (io_end->flag & EXT4_IO_END_UNWRITTEN) {
+ io_end->flag &= ~EXT4_IO_END_UNWRITTEN;
+ /* Wake up anyone waiting on unwritten extent conversion */
+ if (atomic_dec_and_test(&EXT4_I(inode)->i_unwritten))
+ wake_up_all(ext4_ioend_wq(inode));
+ }
+}
+#endif
+extern const struct iomap_ops ext4_iomap_ops;
+
+#endif /* __KERNEL__ */
+
+#define EFSBADCRC EBADMSG /* Bad CRC detected */
+#define EFSCORRUPTED EUCLEAN /* Filesystem is corrupted */
+
+/*
+ * End of Linux ext4.h, below are ext3 inline functions still used by the Windows driver.
+ */
+
+/*
+ * Hash Tree Directory indexing
+ * (c) Daniel Phillips, 2001
+ */
+
+#undef is_dx
+#ifdef EXT2_HTREE_INDEX
+#define is_dx(dir) (EXT3_HAS_COMPAT_FEATURE(dir->i_sb, \
+ EXT4_FEATURE_COMPAT_DIR_INDEX) && \
+ (EXT3_I(dir)->i_flags & EXT3_INDEX_FL))
+#define EXT4_DIR_LINK_MAX(dir) (!is_dx(dir) && (dir)->i_nlink >= EXT3_LINK_MAX)
+#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2 || (dir)->i_nlink == 1)
+#else
+#define is_dx(dir) 0
+#define EXT4_DIR_LINK_MAX(dir) ((dir)->i_nlink >= EXT3_LINK_MAX)
+#define EXT4_DIR_LINK_EMPTY(dir) ((dir)->i_nlink == 2)
+#endif
+
+struct fake_dirent
+{
+ __le32 inode;
+ __le16 rec_len;
+ __u8 name_len;
+ __u8 file_type;
+};
+
+struct dx_countlimit
+{
+ __le16 limit;
+ __le16 count;
+};
+
+struct dx_entry
+{
+ __le32 hash;
+ __le32 block;
+};
+
+/*
+ * dx_root_info is laid out so that if it should somehow get overlaid by a
+ * dirent the two low bits of the hash version will be zero. Therefore, the
+ * hash version mod 4 should never be 0. Sincerely, the paranoia department.
+ */
+
+struct dx_root
+{
+ struct fake_dirent dot;
+ char dot_name[4];
+ struct fake_dirent dotdot;
+ char dotdot_name[4];
+ struct dx_root_info
+ {
+ __le32 reserved_zero;
+ __u8 hash_version;
+ __u8 info_length; /* 8 */
+ __u8 indirect_levels;
+ __u8 unused_flags;
+ }
+ info;
+ struct dx_entry entries[0];
+};
+
+struct dx_node
+{
+ struct fake_dirent fake;
+ struct dx_entry entries[0];
+};
+
+
+struct dx_frame
+{
+ struct buffer_head *bh;
+ struct dx_entry *entries;
+ struct dx_entry *at;
+};
+
+struct dx_map_entry
+{
+ __u32 hash;
+ __u16 offs;
+ __u16 size;
+};
+
+/*
+ * This goes at the end of each htree block.
+ */
+struct dx_tail {
+ u32 dt_reserved;
+ __le32 dt_checksum; /* crc32c(uuid+inum+dirblock) */
+};
+
+static inline unsigned ext3_rec_len_from_disk(__le16 dlen)
+{
+ unsigned len = le16_to_cpu(dlen);
+
+ if (len == EXT3_MAX_REC_LEN || len == 0)
+ return 1 << 16;
+ return len;
+}
+
+static inline __le16 ext3_rec_len_to_disk(unsigned len)
+{
+ if (len == (1 << 16))
+ return cpu_to_le16(EXT3_MAX_REC_LEN);
+ else if (len > (1 << 16))
+ BUG();
+ return cpu_to_le16(len);
+}
+
+/*
+ * Compute the total directory entry data length.
+ * This includes the filename and an implicit NUL terminator (always present),
+ * and optional extensions. Each extension has a bit set in the high 4 bits of
+ * de->file_type, and the extension length is the first byte in each entry.
+ */
+static inline int ext3_get_dirent_data_len(struct ext3_dir_entry_2 *de)
+{
+ char *len = de->name + de->name_len + 1 /* NUL terminator */;
+ int dlen = 0;
+ __u8 extra_data_flags = (de->file_type & ~EXT3_FT_MASK) >> 4;
+
+ while (extra_data_flags) {
+ if (extra_data_flags & 1) {
+ dlen += *len + (dlen == 0);
+ len += *len;
+ }
+ extra_data_flags >>= 1;
+ }
+ return dlen;
+}
+
+#if _MSC_VER > 1900
+int _strnicmp(const char* str1, const char* str2, size_t count);
+#endif
+
+/*
+ * NOTE! unlike strncmp, ext3_match returns 1 for success, 0 for failure.
+ *
+ * `len <= EXT3_NAME_LEN' is guaranteed by caller.
+ * `de != NULL' is guaranteed by caller.
+ */
+static inline int ext3_match (int len, const char * const name,
+ struct ext3_dir_entry_2 * de)
+{
+ if (len != de->name_len)
+ return 0;
+ if (!de->inode)
+ return 0;
+ return !_strnicmp(name, de->name, len);
+}
+
+/* calculate the first block number of the group */
+static inline ext3_fsblk_t
+ext3_group_first_block_no(struct super_block *sb, unsigned long group_no)
+{
+ return group_no * (ext3_fsblk_t)EXT3_BLOCKS_PER_GROUP(sb) +
+ le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block);
+}
+
+/*
+ * Functions for metadata checksums in ext4_csum.c.
+ */
+
+//int ext4_has_feature_metadata_csum(struct super_block *sb);
+__u32 ext4_chksum(struct ext4_sb_info *sbi, __u32 crc,
+ const void *buffer, unsigned int length);
+int ext4_superblock_csum_verify(struct super_block *sb,
+ struct ext4_super_block *es);
+void ext4_superblock_csum_set(struct super_block *sb);
+__le16 ext4_group_desc_csum(struct super_block *sb, __u32 block_group,
+ struct ext4_group_desc *gdp);
+int ext4_group_desc_csum_verify(struct super_block *sb, __u32 block_group,
+ struct ext4_group_desc *gdp);
+void ext4_group_desc_csum_set(struct super_block *sb, __u32 block_group,
+ struct ext4_group_desc *gdp);
+void ext4_inode_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
+ struct ext4_group_desc *gdp,
+ struct buffer_head *bh, int sz);
+void ext4_block_bitmap_csum_set(struct super_block *sb, ext4_group_t group,
+ struct ext4_group_desc *gdp,
+ struct buffer_head *bh);
+int ext4_inode_csum_verify(struct inode *inode, struct ext4_inode *raw,
+ struct ext4_inode_info *ei);
+void ext4_inode_csum_set(struct inode *inode, struct ext4_inode *raw,
+ struct ext4_inode_info *ei);
+void initialize_dirent_tail(struct ext4_dir_entry_tail *t,
+ unsigned int blocksize);
+int ext4_dirent_csum_verify(struct inode *inode, struct ext4_dir_entry *dirent);
+void ext4_dirent_csum_set(struct inode *inode,
+ struct ext4_dir_entry *dirent);
+int ext4_dx_csum_verify(struct inode *inode,
+ struct ext4_dir_entry *dirent);
+void ext4_dx_csum_set(struct inode *inode, struct ext4_dir_entry *dirent);
+
+//
+// Use default packing of structures
+//
+#include
+
+#endif /* _EXT4_H */
diff --git a/Ext4Fsd/include/linux/ext4_xattr.h b/Ext4Fsd/include/linux/ext4_xattr.h
index d57949c..44d5f91 100644
--- a/Ext4Fsd/include/linux/ext4_xattr.h
+++ b/Ext4Fsd/include/linux/ext4_xattr.h
@@ -86,7 +86,7 @@ struct ext4_xattr_entry {
#pragma pack(pop)
-#define EXT4_GOOD_OLD_INODE_SIZE EXT2_GOOD_OLD_INODE_SIZE
+//#define EXT4_GOOD_OLD_INODE_SIZE EXT2_GOOD_OLD_INODE_SIZE
#define EXT4_XATTR_PAD_BITS 2
#define EXT4_XATTR_PAD (1<
- * HOMEPAGE: http://www.ext2fsd.com
- * UPDATE HISTORY:
- */
-
-/* INCLUDES *****************************************************************/
-
-#include "ext2fs.h"
-
-/* GLOBALS ***************************************************************/
-
-extern PEXT2_GLOBAL Ext2Global;
-
-/* DEFINITIONS *************************************************************/
-
-#ifdef ALLOC_PRAGMA
-#pragma alloc_text(PAGE, Ext2AllocateInode)
-#pragma alloc_text(PAGE, Ext2DestroyInode)
-#pragma alloc_text(PAGE, Ext2CheckBitmapConsistency)
-#pragma alloc_text(PAGE, Ext2CheckSetBlock)
-#pragma alloc_text(PAGE, Ext2InitializeVcb)
-#pragma alloc_text(PAGE, Ext2TearDownStream)
-#pragma alloc_text(PAGE, Ext2DestroyVcb)
-#pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap)
-#pragma alloc_text(PAGE, Ext2ReaperThread)
-#pragma alloc_text(PAGE, Ext2StartReaper)
-#pragma alloc_text(PAGE, Ext2StopReaper)
-#endif
-
-PEXT2_IRP_CONTEXT
-Ext2AllocateIrpContext (IN PDEVICE_OBJECT DeviceObject,
- IN PIRP Irp )
-{
- PIO_STACK_LOCATION irpSp;
- PEXT2_IRP_CONTEXT IrpContext;
-
- ASSERT(DeviceObject != NULL);
- ASSERT(Irp != NULL);
-
- irpSp = IoGetCurrentIrpStackLocation(Irp);
-
- IrpContext = (PEXT2_IRP_CONTEXT) (
- ExAllocateFromNPagedLookasideList(
- &(Ext2Global->Ext2IrpContextLookasideList)));
-
- if (IrpContext == NULL) {
- return NULL;
- }
-
- RtlZeroMemory(IrpContext, sizeof(EXT2_IRP_CONTEXT) );
-
- IrpContext->Identifier.Type = EXT2ICX;
- IrpContext->Identifier.Size = sizeof(EXT2_IRP_CONTEXT);
-
- IrpContext->Irp = Irp;
- IrpContext->MajorFunction = irpSp->MajorFunction;
- IrpContext->MinorFunction = irpSp->MinorFunction;
- IrpContext->DeviceObject = DeviceObject;
- IrpContext->FileObject = irpSp->FileObject;
- if (NULL != IrpContext->FileObject) {
- IrpContext->Fcb = (PEXT2_FCB)IrpContext->FileObject->FsContext;
- IrpContext->Ccb = (PEXT2_CCB)IrpContext->FileObject->FsContext2;
- }
-
- if (IrpContext->FileObject != NULL) {
- IrpContext->RealDevice = IrpContext->FileObject->DeviceObject;
- } else if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) {
- if (irpSp->Parameters.MountVolume.Vpb) {
- IrpContext->RealDevice = irpSp->Parameters.MountVolume.Vpb->RealDevice;
- }
- }
-
- if (IsFlagOn(irpSp->Flags, SL_WRITE_THROUGH)) {
- SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
- }
-
- if (IsFlagOn(irpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME)) {
- SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ);
- }
-
- if (IrpContext->MajorFunction == IRP_MJ_CLEANUP ||
- IrpContext->MajorFunction == IRP_MJ_CLOSE ||
- IrpContext->MajorFunction == IRP_MJ_SHUTDOWN ||
- IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
- IrpContext->MajorFunction == IRP_MJ_PNP ) {
-
- if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
- IrpContext->MajorFunction == IRP_MJ_PNP) {
- if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL ||
- IoIsOperationSynchronous(Irp)) {
- SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
- }
- } else {
- SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
- }
-
- } else if (IoIsOperationSynchronous(Irp)) {
-
- SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
- }
-
- IrpContext->IsTopLevel = (IoGetTopLevelIrp() == Irp);
- IrpContext->ExceptionInProgress = FALSE;
- INC_IRP_COUNT(IrpContext);
-
- return IrpContext;
-}
-
-VOID
-Ext2FreeIrpContext (IN PEXT2_IRP_CONTEXT IrpContext)
-{
- ASSERT(IrpContext != NULL);
-
- ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
- (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
-
- /* free the IrpContext to NonPagedList */
- IrpContext->Identifier.Type = 0;
- IrpContext->Identifier.Size = 0;
-
- DEC_IRP_COUNT(IrpContext);
- ExFreeToNPagedLookasideList(&(Ext2Global->Ext2IrpContextLookasideList), IrpContext);
-}
-
-
-PEXT2_FCB
-Ext2AllocateFcb (
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb
-)
-{
- PEXT2_FCB Fcb;
-
- ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->FcbLock));
-
- Fcb = (PEXT2_FCB) ExAllocateFromNPagedLookasideList(
- &(Ext2Global->Ext2FcbLookasideList));
-
- if (!Fcb) {
- return NULL;
- }
-
- RtlZeroMemory(Fcb, sizeof(EXT2_FCB));
- Fcb->Identifier.Type = EXT2FCB;
- Fcb->Identifier.Size = sizeof(EXT2_FCB);
-
-#ifndef _WIN2K_TARGET_
- ExInitializeFastMutex(&Fcb->Mutex);
- FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->Mutex);
-#endif
-
- FsRtlInitializeOplock(&Fcb->Oplock);
- FsRtlInitializeFileLock (
- &Fcb->FileLockAnchor,
- NULL,
- NULL );
-
- Fcb->OpenHandleCount = 0;
- Fcb->ReferenceCount = 0;
- Fcb->Vcb = Vcb;
- Fcb->Inode = &Mcb->Inode;
-
- ASSERT(Mcb->Fcb == NULL);
- Ext2ReferMcb(Mcb);
- Fcb->Mcb = Mcb;
- Mcb->Fcb = Fcb;
-
- DEBUG(DL_RES, ("Ext2AllocateFcb: Fcb %p created: %wZ.\n",
- Fcb, &Fcb->Mcb->FullName));
-
- RtlZeroMemory(&Fcb->Header, sizeof(FSRTL_COMMON_FCB_HEADER));
- Fcb->Header.NodeTypeCode = (USHORT) EXT2FCB;
- Fcb->Header.NodeByteSize = sizeof(EXT2_FCB);
- Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
- Fcb->Header.Resource = &(Fcb->MainResource);
- Fcb->Header.PagingIoResource = &(Fcb->PagingIoResource);
-
- Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
- Fcb->Header.ValidDataLength.QuadPart = Mcb->Inode.i_size;
- Fcb->Header.AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
- Fcb->Header.FileSize.QuadPart, (ULONGLONG)Vcb->BlockSize);
-
- Fcb->SectionObject.DataSectionObject = NULL;
- Fcb->SectionObject.SharedCacheMap = NULL;
- Fcb->SectionObject.ImageSectionObject = NULL;
-
- ExInitializeResourceLite(&(Fcb->MainResource));
- ExInitializeResourceLite(&(Fcb->PagingIoResource));
-
- Ext2InsertFcb(Vcb, Fcb);
-
- INC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
-
- return Fcb;
-}
-
-VOID
-Ext2UnlinkFcb(IN PEXT2_FCB Fcb)
-{
- PEXT2_VCB Vcb = Fcb->Vcb;
- PEXT2_MCB Mcb;
-
- ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
- Mcb = Fcb->Mcb;
-
- DEBUG(DL_INF, ("Ext2FreeFcb: Fcb (%p) to be unlinked: %wZ.\n",
- Fcb, Mcb ? &Mcb->FullName : NULL));
-
- if ((Mcb != NULL) &&
- (Mcb->Identifier.Type == EXT2MCB) &&
- (Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
-
- ASSERT (Mcb->Fcb == Fcb);
- if (IsMcbSpecialFile(Mcb) ||
- IsFileDeleted(Mcb)) {
-
- ASSERT(!IsRoot(Fcb));
- Ext2RemoveMcb(Vcb, Mcb);
- Mcb->Fcb = NULL;
-
- Ext2UnlinkMcb(Vcb, Mcb);
- Ext2DerefMcb(Mcb);
- Ext2LinkHeadMcb(Vcb, Mcb);
-
- } else {
- Mcb->Fcb = NULL;
- Ext2DerefMcb(Mcb);
- }
- Fcb->Mcb = NULL;
- }
-
- ExReleaseResourceLite(&Vcb->McbLock);
-}
-
-VOID
-Ext2FreeFcb (IN PEXT2_FCB Fcb)
-{
- PEXT2_VCB Vcb = Fcb->Vcb;
-
- __try {
-
- ASSERT((Fcb != NULL) && (Fcb->Identifier.Type == EXT2FCB) &&
- (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
- ASSERT(0 == Fcb->ReferenceCount);
-
-#ifndef _WIN2K_TARGET_
- FsRtlTeardownPerStreamContexts(&Fcb->Header);
-#endif
-
- FsRtlUninitializeFileLock(&Fcb->FileLockAnchor);
- FsRtlUninitializeOplock(&Fcb->Oplock);
- ExDeleteResourceLite(&Fcb->MainResource);
- ExDeleteResourceLite(&Fcb->PagingIoResource);
-
- Fcb->Identifier.Type = 0;
- Fcb->Identifier.Size = 0;
-
- ExFreeToNPagedLookasideList(&(Ext2Global->Ext2FcbLookasideList), Fcb);
- DEC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
-
- if (0 == Ext2DerefXcb(&Vcb->ReferenceCount)) {
- if (!IsMounted(Vcb) || IsDispending(Vcb)) {
- Ext2CheckDismount(NULL, Vcb, FALSE);
- }
- }
-
- } __finally {
- }
-}
-
-VOID
-Ext2ReleaseFcb (IN PEXT2_FCB Fcb)
-{
- PEXT2_VCB Vcb = Fcb->Vcb;
- PEXT2_MCB Mcb;
-
- if (0 != Ext2DerefXcb(&Fcb->ReferenceCount))
- return;
-
- ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
- ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
-
- Mcb = Fcb->Mcb;
- RemoveEntryList(&Fcb->Next);
-
- if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) ||
- NULL == Mcb || IsFileDeleted(Mcb)) {
- InsertHeadList(&Vcb->FcbList, &Fcb->Next);
- Fcb->TsDrop.QuadPart = 0;
- } else {
- InsertTailList(&Vcb->FcbList, &Fcb->Next);
- KeQuerySystemTime(&Fcb->TsDrop);
- }
- ExReleaseResourceLite(&Fcb->MainResource);
- ExReleaseResourceLite(&Vcb->FcbLock);
-
- if ((Vcb->FcbCount >> 6) > (ULONG)(Ext2Global->MaxDepth)) {
- KeSetEvent(&Ext2Global->FcbReaper.Wait, 0, FALSE);
- }
-}
-
-/* Insert Fcb to Vcb->FcbList queue, with Vcb->FcbLock Acquired. */
-
-VOID
-Ext2InsertFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
-{
- ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->FcbLock));
-
- KeQuerySystemTime(&Fcb->TsDrop);
- Ext2ReferXcb(&Vcb->FcbCount);
- Ext2ReferXcb(&Vcb->ReferenceCount);
- InsertTailList(&Vcb->FcbList, &Fcb->Next);
-}
-
-PEXT2_CCB
-Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink)
-{
- PEXT2_CCB Ccb;
-
- Ccb = (PEXT2_CCB) (ExAllocateFromNPagedLookasideList(
- &(Ext2Global->Ext2CcbLookasideList)));
- if (!Ccb) {
- return NULL;
- }
-
- DEBUG(DL_RES, ( "ExtAllocateCcb: Ccb created: %ph.\n", Ccb));
-
- RtlZeroMemory(Ccb, sizeof(EXT2_CCB));
-
- Ccb->Identifier.Type = EXT2CCB;
- Ccb->Identifier.Size = sizeof(EXT2_CCB);
- Ccb->Flags = Flags;
-
- Ccb->SymLink = SymLink;
- if (SymLink) {
- ASSERT(SymLink->Refercount > 0);
- Ext2ReferMcb(SymLink);
- DEBUG(DL_INF, ( "ExtAllocateCcb: Ccb SymLink: %wZ.\n",
- &Ccb->SymLink->FullName));
- }
-
- Ccb->DirectorySearchPattern.Length = 0;
- Ccb->DirectorySearchPattern.MaximumLength = 0;
- Ccb->DirectorySearchPattern.Buffer = 0;
-
- INC_MEM_COUNT(PS_CCB, Ccb, sizeof(EXT2_CCB));
-
- return Ccb;
-}
-
-VOID
-Ext2FreeCcb (IN PEXT2_VCB Vcb, IN PEXT2_CCB Ccb)
-{
- ASSERT(Ccb != NULL);
- ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
- (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
-
- DEBUG(DL_RES, ( "Ext2FreeCcb: Ccb = %ph.\n", Ccb));
-
- if (Ccb->SymLink) {
- DEBUG(DL_INF, ( "Ext2FreeCcb: Ccb SymLink: %wZ.\n",
- &Ccb->SymLink->FullName));
- if (IsFileDeleted(Ccb->SymLink->Target)) {
- Ext2UnlinkMcb(Vcb, Ccb->SymLink);
- Ext2DerefMcb(Ccb->SymLink);
- Ext2LinkHeadMcb(Vcb, Ccb->SymLink);
- } else {
- Ext2DerefMcb(Ccb->SymLink);
- }
- }
-
- if (Ccb->DirectorySearchPattern.Buffer != NULL) {
- DEC_MEM_COUNT(PS_DIR_PATTERN, Ccb->DirectorySearchPattern.Buffer,
- Ccb->DirectorySearchPattern.MaximumLength );
- Ext2FreePool(Ccb->DirectorySearchPattern.Buffer, EXT2_DIRSP_MAGIC);
- }
-
- ExFreeToNPagedLookasideList(&(Ext2Global->Ext2CcbLookasideList), Ccb);
- DEC_MEM_COUNT(PS_CCB, Ccb, sizeof(EXT2_CCB));
-}
-
-PEXT2_INODE
-Ext2AllocateInode (PEXT2_VCB Vcb)
-{
- PVOID inode = NULL;
-
- inode = ExAllocateFromNPagedLookasideList(
- &(Vcb->InodeLookasideList));
- if (!inode) {
- return NULL;
- }
-
- RtlZeroMemory(inode, INODE_SIZE);
-
- DEBUG(DL_INF, ("ExtAllocateInode: Inode created: %ph.\n", inode));
- INC_MEM_COUNT(PS_EXT2_INODE, inode, INODE_SIZE);
-
- return inode;
-}
-
-VOID
-Ext2DestroyInode (IN PEXT2_VCB Vcb, IN PEXT2_INODE inode)
-{
- ASSERT(inode != NULL);
-
- DEBUG(DL_INF, ("Ext2FreeInode: Inode = %ph.\n", inode));
-
- ExFreeToNPagedLookasideList(&(Vcb->InodeLookasideList), inode);
- DEC_MEM_COUNT(PS_EXT2_INODE, inode, INODE_SIZE);
-}
-
-struct dentry * Ext2AllocateEntry()
-{
- struct dentry *de;
-
- de = (struct dentry *)ExAllocateFromNPagedLookasideList(
- &(Ext2Global->Ext2DentryLookasideList));
- if (!de) {
- return NULL;
- }
-
- RtlZeroMemory(de, sizeof(struct dentry));
- INC_MEM_COUNT(PS_DENTRY, de, sizeof(struct dentry));
-
- return de;
-}
-
-VOID Ext2FreeEntry (IN struct dentry *de)
-{
- ASSERT(de != NULL);
-
- if (de->d_name.name)
- ExFreePool(de->d_name.name);
-
- ExFreeToNPagedLookasideList(&(Ext2Global->Ext2DentryLookasideList), de);
- DEC_MEM_COUNT(PS_DENTRY, de, sizeof(struct dentry));
-}
-
-
-struct dentry *Ext2BuildEntry(PEXT2_VCB Vcb, PEXT2_MCB Dcb, PUNICODE_STRING FileName)
-{
- OEM_STRING Oem = { 0 };
- struct dentry *de = NULL;
- NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
-
- __try {
-
- de = Ext2AllocateEntry();
- if (!de) {
- DEBUG(DL_ERR, ("Ext2BuildEntry: failed to allocate dentry.\n"));
- __leave;
- }
- de->d_sb = &Vcb->sb;
- if (Dcb)
- de->d_parent = Dcb->de;
-
- Oem.MaximumLength = (USHORT)Ext2UnicodeToOEMSize(Vcb, FileName) + 1;
- Oem.Buffer = ExAllocatePool(PagedPool, Oem.MaximumLength);
- if (!Oem.Buffer) {
- DEBUG(DL_ERR, ( "Ex2BuildEntry: failed to allocate OEM name.\n"));
- __leave;
- }
- de->d_name.name = Oem.Buffer;
- RtlZeroMemory(Oem.Buffer, Oem.MaximumLength);
- Status = Ext2UnicodeToOEM(Vcb, &Oem, FileName);
- if (!NT_SUCCESS(Status)) {
- DEBUG(DL_CP, ("Ext2BuildEntry: failed to convert %S to OEM.\n", FileName->Buffer));
- __leave;
- }
- de->d_name.len = Oem.Length;
-
- } __finally {
-
- if (!NT_SUCCESS(Status)) {
- if (de)
- Ext2FreeEntry(de);
- }
- }
-
- return de;
-}
-
-PEXT2_EXTENT
-Ext2AllocateExtent ()
-{
- PEXT2_EXTENT Extent;
-
- Extent = (PEXT2_EXTENT)ExAllocateFromNPagedLookasideList(
- &(Ext2Global->Ext2ExtLookasideList));
- if (!Extent) {
- return NULL;
- }
-
- RtlZeroMemory(Extent, sizeof(EXT2_EXTENT));
- INC_MEM_COUNT(PS_EXTENT, Extent, sizeof(EXT2_EXTENT));
-
- return Extent;
-}
-
-VOID
-Ext2FreeExtent (IN PEXT2_EXTENT Extent)
-{
- ASSERT(Extent != NULL);
- ExFreeToNPagedLookasideList(&(Ext2Global->Ext2ExtLookasideList), Extent);
- DEC_MEM_COUNT(PS_EXTENT, Extent, sizeof(EXT2_EXTENT));
-}
-
-ULONG
-Ext2CountExtents(IN PEXT2_EXTENT Chain)
-{
- ULONG count = 0;
- PEXT2_EXTENT List = Chain;
-
- while (List) {
- count += 1;
- List = List->Next;
- }
-
- return count;
-}
-
-VOID
-Ext2JointExtents(
- IN PEXT2_EXTENT Chain,
- IN PEXT2_EXTENT Extent
-)
-{
- ULONG count = 0;
- PEXT2_EXTENT List = Chain;
-
- while (List->Next) {
- List = List->Next;
- }
-
- List->Next = Extent;
-}
-
-
-VOID
-Ext2DestroyExtentChain(IN PEXT2_EXTENT Chain)
-{
- PEXT2_EXTENT Extent = NULL, List = Chain;
-
- while (List) {
- Extent = List->Next;
- Ext2FreeExtent(List);
- List = Extent;
- }
-}
-
-BOOLEAN
-Ext2ListExtents(PLARGE_MCB Extents)
-{
- if (FsRtlNumberOfRunsInLargeMcb(Extents) != 0) {
-
- LONGLONG DirtyVba;
- LONGLONG DirtyLba;
- LONGLONG DirtyLength;
- int i, n = 0;
-
- for (i = 0; FsRtlGetNextLargeMcbEntry(
- Extents, i, &DirtyVba,
- &DirtyLba, &DirtyLength); i++) {
- if (DirtyVba > 0 && DirtyLba != -1) {
- DEBUG(DL_EXT, ("Vba:%I64xh Lba:%I64xh Len:%I64xh.\n", DirtyVba, DirtyLba, DirtyLength));
- n++;
- }
- }
-
- return n ? TRUE : FALSE;
- }
-
- return FALSE;
-}
-
-VOID
-Ext2CheckExtent(
- PLARGE_MCB Zone,
- LONGLONG Vbn,
- LONGLONG Lbn,
- LONGLONG Length,
- BOOLEAN bAdded
-)
-{
-#if EXT2_DEBUG
- LONGLONG DirtyLbn;
- LONGLONG DirtyLen;
- LONGLONG RunStart;
- LONGLONG RunLength;
- ULONG Index;
- BOOLEAN bFound = FALSE;
-
- bFound = FsRtlLookupLargeMcbEntry(
- Zone,
- Vbn,
- &DirtyLbn,
- &DirtyLen,
- &RunStart,
- &RunLength,
- &Index );
-
- if (!bAdded && (!bFound || DirtyLbn == -1)) {
- return;
- }
-
- if ( !bFound || (DirtyLbn == -1) ||
- (DirtyLbn != Lbn) ||
- (DirtyLen < Length)) {
-
- DbgBreak();
-
- for (Index = 0; TRUE; Index++) {
-
- if (!FsRtlGetNextLargeMcbEntry(
- Zone,
- Index,
- &Vbn,
- &Lbn,
- &Length)) {
- break;
- }
-
- DEBUG(DL_EXT, ("Index = %xh Vbn = %I64xh Lbn = %I64xh Len = %I64xh\n",
- Index, Vbn, Lbn, Length ));
- }
- }
-#endif
-}
-
-VOID
-Ext2ClearAllExtents(PLARGE_MCB Zone)
-{
- __try {
- FsRtlTruncateLargeMcb(Zone, (LONGLONG)0);
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- DbgBreak();
- }
-}
-
-
-BOOLEAN
-Ext2AddVcbExtent (
- IN PEXT2_VCB Vcb,
- IN LONGLONG Vbn,
- IN LONGLONG Length
-)
-{
- ULONG TriedTimes = 0;
-
- LONGLONG Offset = 0;
- BOOLEAN rc = FALSE;
-
- Offset = Vbn & (~(Vcb->IoUnitSize - 1));
- Length = (Vbn - Offset + Length + Vcb->IoUnitSize - 1) &
- ~(Vcb->IoUnitSize - 1);
-
- ASSERT ((Offset & (Vcb->IoUnitSize - 1)) == 0);
- ASSERT ((Length & (Vcb->IoUnitSize - 1)) == 0);
-
- Offset = (Offset >> Vcb->IoUnitBits) + 1;
- Length = (Length >> Vcb->IoUnitBits);
-
-Again:
-
- __try {
- rc = FsRtlAddLargeMcbEntry(
- &Vcb->Extents,
- Offset,
- Offset,
- Length
- );
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- DbgBreak();
- rc = FALSE;
- }
-
- if (!rc && ++TriedTimes < 10) {
- Ext2Sleep(TriedTimes * 100);
- goto Again;
- }
-
- DEBUG(DL_EXT, ("Ext2AddVcbExtent: Vbn=%I64xh Length=%I64xh,"
- " rc=%d Runs=%u\n", Offset, Length, rc,
- FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
-
- if (rc) {
- Ext2CheckExtent(&Vcb->Extents, Offset, Offset, Length, TRUE);
- }
-
- return rc;
-}
-
-BOOLEAN
-Ext2RemoveVcbExtent (
- IN PEXT2_VCB Vcb,
- IN LONGLONG Vbn,
- IN LONGLONG Length
-)
-{
- ULONG TriedTimes = 0;
- LONGLONG Offset = 0;
- BOOLEAN rc = TRUE;
-
- Offset = Vbn & (~(Vcb->IoUnitSize - 1));
- Length = (Length + Vbn - Offset + Vcb->IoUnitSize - 1) & (~(Vcb->IoUnitSize - 1));
-
- ASSERT ((Offset & (Vcb->IoUnitSize - 1)) == 0);
- ASSERT ((Length & (Vcb->IoUnitSize - 1)) == 0);
-
- Offset = (Offset >> Vcb->IoUnitBits) + 1;
- Length = (Length >> Vcb->IoUnitBits);
-
-Again:
-
- __try {
- FsRtlRemoveLargeMcbEntry(
- &Vcb->Extents,
- Offset,
- Length
- );
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- DbgBreak();
- rc = FALSE;
- }
-
- if (!rc && ++TriedTimes < 10) {
- Ext2Sleep(TriedTimes * 100);
- goto Again;
- }
-
- DEBUG(DL_EXT, ("Ext2RemoveVcbExtent: Vbn=%I64xh Length=%I64xh Runs=%u\n",
- Offset, Length, FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
- if (rc) {
- Ext2CheckExtent(&Vcb->Extents, Offset, 0, Length, FALSE);
- }
-
- return rc;
-}
-
-BOOLEAN
-Ext2LookupVcbExtent (
- IN PEXT2_VCB Vcb,
- IN LONGLONG Vbn,
- OUT PLONGLONG Lbn,
- OUT PLONGLONG Length
-)
-{
- LONGLONG offset;
- BOOLEAN rc;
-
- offset = Vbn & (~(Vcb->IoUnitSize - 1));
- ASSERT ((offset & (Vcb->IoUnitSize - 1)) == 0);
- offset = (offset >> Vcb->IoUnitBits) + 1;
-
- rc = FsRtlLookupLargeMcbEntry(
- &(Vcb->Extents),
- offset,
- Lbn,
- Length,
- NULL,
- NULL,
- NULL
- );
-
- if (rc) {
-
- if (Lbn && ((*Lbn) != -1)) {
- ASSERT((*Lbn) > 0);
- (*Lbn) = (((*Lbn) - 1) << Vcb->IoUnitBits);
- (*Lbn) += ((Vbn) & (Vcb->IoUnitSize - 1));
- }
-
- if (Length && *Length) {
- (*Length) <<= Vcb->IoUnitBits;
- (*Length) -= ((Vbn) & (Vcb->IoUnitSize - 1));
- }
- }
-
- return rc;
-}
-
-
-BOOLEAN
-Ext2AddMcbExtent (
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN LONGLONG Vbn,
- IN LONGLONG Lbn,
- IN LONGLONG Length
-)
-{
- ULONG TriedTimes = 0;
- LONGLONG Base = 0;
- UCHAR Bits = 0;
- BOOLEAN rc = FALSE;
-
- Base = (LONGLONG)BLOCK_SIZE;
- Bits = (UCHAR)BLOCK_BITS;
-
- ASSERT ((Vbn & (Base - 1)) == 0);
- ASSERT ((Lbn & (Base - 1)) == 0);
- ASSERT ((Length & (Base - 1)) == 0);
-
- Vbn = (Vbn >> Bits) + 1;
- Lbn = (Lbn >> Bits) + 1;
- Length = (Length >> Bits);
-
-Again:
-
- __try {
-
- rc = FsRtlAddLargeMcbEntry(
- &Mcb->Extents,
- Vbn,
- Lbn,
- Length
- );
-
- } __except (EXCEPTION_EXECUTE_HANDLER) {
-
- DbgBreak();
- rc = FALSE;
- }
-
- if (!rc && ++TriedTimes < 10) {
- Ext2Sleep(TriedTimes * 100);
- goto Again;
- }
-
- DEBUG(DL_EXT, ("Ext2AddMcbExtent: Vbn=%I64xh Lbn=%I64xh Length=%I64xh,"
- " rc=%d Runs=%u\n", Vbn, Lbn, Length, rc,
- FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)));
-
- if (rc) {
- Ext2CheckExtent(&Mcb->Extents, Vbn, Lbn, Length, TRUE);
- }
-
- return rc;
-}
-
-BOOLEAN
-Ext2RemoveMcbExtent (
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN LONGLONG Vbn,
- IN LONGLONG Length
-)
-{
- ULONG TriedTimes = 0;
- LONGLONG Base = 0;
- UCHAR Bits = 0;
- BOOLEAN rc = TRUE;
-
- Base = (LONGLONG)BLOCK_SIZE;
- Bits = (UCHAR)BLOCK_BITS;
-
- ASSERT ((Vbn & (Base - 1)) == 0);
- ASSERT ((Length & (Base - 1)) == 0);
-
- Vbn = (Vbn >> Bits) + 1;
- Length = (Length >> Bits);
-
-Again:
-
- __try {
- FsRtlRemoveLargeMcbEntry(
- &Mcb->Extents,
- Vbn,
- Length
- );
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- DbgBreak();
- rc = FALSE;
- }
-
- if (!rc && ++TriedTimes < 10) {
- Ext2Sleep(TriedTimes * 100);
- goto Again;
- }
-
- DEBUG(DL_EXT, ("Ext2RemoveMcbExtent: Vbn=%I64xh Length=%I64xh Runs=%u\n",
- Vbn, Length, FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)));
- if (rc) {
- Ext2CheckExtent(&Mcb->Extents, Vbn, 0, Length, FALSE);
- }
-
- return rc;
-}
-
-BOOLEAN
-Ext2LookupMcbExtent (
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN LONGLONG Vbn,
- OUT PLONGLONG Lbn,
- OUT PLONGLONG Length
-)
-{
- LONGLONG offset;
- BOOLEAN rc;
-
- offset = Vbn & (~((LONGLONG)BLOCK_SIZE - 1));
- ASSERT ((offset & (BLOCK_SIZE - 1)) == 0);
- offset = (offset >> BLOCK_BITS) + 1;
-
- rc = FsRtlLookupLargeMcbEntry(
- &(Mcb->Extents),
- offset,
- Lbn,
- Length,
- NULL,
- NULL,
- NULL
- );
-
- if (rc) {
-
- if (Lbn && ((*Lbn) != -1)) {
- ASSERT((*Lbn) > 0);
- (*Lbn) = (((*Lbn) - 1) << BLOCK_BITS);
- (*Lbn) += ((Vbn) & ((LONGLONG)BLOCK_SIZE - 1));
- }
-
- if (Length && *Length) {
- (*Length) <<= BLOCK_BITS;
- (*Length) -= ((Vbn) & ((LONGLONG)BLOCK_SIZE - 1));
- }
- }
-
- return rc;
-}
-
-
-BOOLEAN
-Ext2AddMcbMetaExts (
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN ULONG Block,
- IN ULONG Length
-)
-{
- ULONG TriedTimes = 0;
- LONGLONG Lbn = Block + 1;
- BOOLEAN rc = TRUE;
-
-Again:
-
- __try {
-
- rc = FsRtlAddLargeMcbEntry(
- &Mcb->MetaExts,
- Lbn,
- Lbn,
- Length
- );
-
- } __except (EXCEPTION_EXECUTE_HANDLER) {
-
- DbgBreak();
- rc = FALSE;
- }
-
- if (!rc && ++TriedTimes < 10) {
- Ext2Sleep(TriedTimes * 100);
- goto Again;
- }
-
- DEBUG(DL_EXT, ("Ext2AddMcbMetaExts: Block: %xh-%xh rc=%d Runs=%u\n", Block,
- Length, rc, FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)));
-
- if (rc) {
- Ext2CheckExtent(&Mcb->MetaExts, Lbn, Lbn, Length, TRUE);
- }
-
- return rc;
-}
-
-BOOLEAN
-Ext2RemoveMcbMetaExts (
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN ULONG Block,
- IN ULONG Length
-)
-{
- ULONG TriedTimes = 0;
- LONGLONG Lbn = Block + 1;
- BOOLEAN rc = TRUE;
-
-Again:
-
- __try {
-
- FsRtlRemoveLargeMcbEntry(
- &Mcb->MetaExts,
- Lbn,
- Length
- );
-
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- DbgBreak();
- rc = FALSE;
- }
-
- if (!rc && ++TriedTimes < 10) {
- Ext2Sleep(TriedTimes * 100);
- goto Again;
- }
-
- DEBUG(DL_EXT, ("Ext2RemoveMcbMetaExts: Block: %xh-%xhh Runs=%u\n", Block,
- Length, FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)));
- if (rc) {
- Ext2CheckExtent(&Mcb->MetaExts, Lbn, 0, Length, FALSE);
- }
-
- return rc;
-}
-
-
-BOOLEAN
-Ext2AddBlockExtent(
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN ULONG Start,
- IN ULONG Block,
- IN ULONG Number
-)
-{
- LONGLONG Vbn = 0;
- LONGLONG Lbn = 0;
- LONGLONG Length = 0;
-
- Vbn = ((LONGLONG) Start) << BLOCK_BITS;
- Lbn = ((LONGLONG) Block) << BLOCK_BITS;
- Length = ((LONGLONG)Number << BLOCK_BITS);
-
- if (Mcb) {
-#if EXT2_DEBUG
- ULONG _block = 0, _mapped = 0;
- BOOLEAN _rc = Ext2LookupBlockExtent(Vcb, Mcb, Start, &_block, &_mapped);
- if (_rc && _block != 0 && (_block != Block)) {
- DbgBreak();
- }
-#endif
- return Ext2AddMcbExtent(Vcb, Mcb, Vbn, Lbn, Length);
-
- }
-
- ASSERT(Start == Block);
- return Ext2AddVcbExtent(Vcb, Vbn, Length);
-}
-
-
-BOOLEAN
-Ext2LookupBlockExtent(
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN ULONG Start,
- IN PULONG Block,
- IN PULONG Mapped
-)
-{
- LONGLONG Vbn = 0;
- LONGLONG Lbn = 0;
- LONGLONG Length = 0;
-
- BOOLEAN rc = FALSE;
-
- Vbn = ((LONGLONG) Start) << BLOCK_BITS;
-
- if (Mcb) {
- rc = Ext2LookupMcbExtent(Vcb, Mcb, Vbn, &Lbn, &Length);
- } else {
- rc = Ext2LookupVcbExtent(Vcb, Vbn, &Lbn, &Length);
- }
-
- if (rc) {
- *Mapped = (ULONG)(Length >> BLOCK_BITS);
- if (Lbn != -1 && Length > 0) {
- *Block = (ULONG)(Lbn >> BLOCK_BITS);
- } else {
- *Block = 0;
- }
- }
-
- return rc;
-}
-
-
-BOOLEAN
-Ext2RemoveBlockExtent(
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN ULONG Start,
- IN ULONG Number
-)
-{
- LONGLONG Vbn = 0;
- LONGLONG Length = 0;
- BOOLEAN rc;
-
- Vbn = ((LONGLONG) Start) << BLOCK_BITS;
- Length = ((LONGLONG)Number << BLOCK_BITS);
-
- if (Mcb) {
- rc = Ext2RemoveMcbExtent(Vcb, Mcb, Vbn, Length);
- } else {
- rc = Ext2RemoveVcbExtent(Vcb, Vbn, Length);
- }
-
- return rc;
-}
-
-NTSTATUS
-Ext2InitializeZone(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb
-)
-{
- NTSTATUS Status = STATUS_SUCCESS;
-
- ULONG Start = 0;
- ULONG End;
- ULONG Block;
- ULONG Mapped;
-
- Ext2ClearAllExtents(&Mcb->Extents);
- Ext2ClearAllExtents(&Mcb->MetaExts);
-
- ASSERT(Mcb != NULL);
- End = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS);
-
- while (Start < End) {
-
- Block = Mapped = 0;
-
- /* mapping file offset to ext2 block */
- if (INODE_HAS_EXTENT(&Mcb->Inode)) {
- Status = Ext2MapExtent(
- IrpContext,
- Vcb,
- Mcb,
- Start,
- FALSE,
- &Block,
- &Mapped
- );
- } else {
- Status = Ext2MapIndirect(
- IrpContext,
- Vcb,
- Mcb,
- Start,
- FALSE,
- &Block,
- &Mapped
- );
- }
-
- if (!NT_SUCCESS(Status)) {
- goto errorout;
- }
-
- /* skip wrong blocks, in case wrongly treating symlink
- target names as blocks, silly */
- if (Block >= TOTAL_BLOCKS) {
- Block = 0;
- }
-
- if (Block) {
- if (!Ext2AddBlockExtent(Vcb, Mcb, Start, Block, Mapped)) {
- DbgBreak();
- ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
- Ext2ClearAllExtents(&Mcb->Extents);
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
- DEBUG(DL_MAP, ("Ext2InitializeZone %wZ: Block = %xh Mapped = %xh\n",
- &Mcb->FullName, Block, Mapped));
- }
-
- /* Mapped is total number of continous blocks or NULL blocks */
- Start += Mapped;
- }
-
- /* set mcb zone as initialized */
- SetLongFlag(Mcb->Flags, MCB_ZONE_INITED);
-
-errorout:
-
- if (!IsZoneInited(Mcb)) {
- Ext2ClearAllExtents(&Mcb->Extents);
- Ext2ClearAllExtents(&Mcb->MetaExts);
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2BuildExtents(
- IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN PEXT2_MCB Mcb,
- IN ULONGLONG Offset,
- IN ULONG Size,
- IN BOOLEAN bAlloc,
- OUT PEXT2_EXTENT * Chain
-)
-{
- ULONG Start, End;
- ULONG Total = 0;
-
- LONGLONG Lba = 0;
- NTSTATUS Status = STATUS_SUCCESS;
-
- PEXT2_EXTENT Extent = NULL;
- PEXT2_EXTENT List = *Chain = NULL;
-
- if (!IsZoneInited(Mcb)) {
- Status = Ext2InitializeZone(IrpContext, Vcb, Mcb);
- if (!NT_SUCCESS(Status)) {
- DbgBreak();
- }
- }
-
- if ((IrpContext && IrpContext->Irp) &&
- ((IrpContext->Irp->Flags & IRP_NOCACHE) ||
- (IrpContext->Irp->Flags & IRP_PAGING_IO))) {
- Size = (Size + SECTOR_SIZE - 1) & (~(SECTOR_SIZE - 1));
- }
-
- Start = (ULONG)(Offset >> BLOCK_BITS);
- End = (ULONG)((Size + Offset + BLOCK_SIZE - 1) >> BLOCK_BITS);
-
- if (End > (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS) ) {
- End = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS);
- }
-
- while (Size > 0 && Start < End) {
-
- ULONG Mapped = 0;
- ULONG Length = 0;
- ULONG Block = 0;
-
- BOOLEAN rc = FALSE;
-
- /* try to map file offset to ext2 block upon Extents cache */
- if (IsZoneInited(Mcb)) {
- rc = Ext2LookupBlockExtent(
- Vcb,
- Mcb,
- Start,
- &Block,
- &Mapped);
-
- if (!rc) {
- /* we likely get a sparse file here */
- Mapped = 1;
- Block = 0;
- }
- }
-
- /* try to BlockMap in case failed to access Extents cache */
- if (!IsZoneInited(Mcb) || (bAlloc && Block == 0)) {
-
- Status = Ext2BlockMap(
- IrpContext,
- Vcb,
- Mcb,
- Start,
- bAlloc,
- &Block,
- &Mapped
- );
- if (!NT_SUCCESS(Status)) {
- break;
- }
-
- /* skip wrong blocks, in case wrongly treating symlink
- target names as blocks, silly */
- if (Block >= TOTAL_BLOCKS) {
- Block = 0;
- }
-
- /* add new allocated blocks to Mcb zone */
- if (IsZoneInited(Mcb) && Block) {
- if (!Ext2AddBlockExtent(Vcb, Mcb, Start, Block, Mapped)) {
- DbgBreak();
- ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
- Ext2ClearAllExtents(&Mcb->Extents);
- }
- }
- }
-
- /* calculate i/o extent */
- Lba = ((LONGLONG)Block << BLOCK_BITS) + Offset - ((LONGLONG)Start << BLOCK_BITS);
- Length = (ULONG)(((LONGLONG)(Start + Mapped) << BLOCK_BITS) - Offset);
- if (Length > Size) {
- Length = Size;
- }
-
- if (0 == Length) {
- DbgBreak();
- break;
- }
-
- Start += Mapped;
- Offset = (ULONGLONG)Start << BLOCK_BITS;
-
- if (Block != 0) {
-
- if (List && List->Lba + List->Length == Lba) {
-
- /* it's continuous upon previous Extent */
- List->Length += Length;
-
- } else {
-
- /* have to allocate a new Extent */
- Extent = Ext2AllocateExtent();
- if (!Extent) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- DbgBreak();
- break;
- }
-
- Extent->Lba = Lba;
- Extent->Length = Length;
- Extent->Offset = Total;
-
- /* insert new Extent to chain */
- if (List) {
- List->Next = Extent;
- List = Extent;
- } else {
- *Chain = List = Extent;
- }
- }
- } else {
- if (bAlloc) {
- DbgBreak();
- }
- }
-
- Total += Length;
- Size -= Length;
- }
-
- return Status;
-}
-
-
-BOOLEAN
-Ext2BuildName(
- IN OUT PUNICODE_STRING Target,
- IN PUNICODE_STRING File,
- IN PUNICODE_STRING Parent
-)
-{
- USHORT Length = 0;
- USHORT ParentLen = 0;
- BOOLEAN bBackslash = TRUE;
-
- /* free the original buffer */
- if (Target->Buffer) {
- DEC_MEM_COUNT(PS_MCB_NAME, Target->Buffer, Target->MaximumLength);
- Ext2FreePool(Target->Buffer, EXT2_FNAME_MAGIC);
- Target->Length = Target->MaximumLength = 0;
- }
-
- /* check the parent directory's name and backslash */
- if (Parent && Parent->Buffer && Parent->Length > 0) {
- ParentLen = Parent->Length / sizeof(WCHAR);
- if (Parent->Buffer[ParentLen - 1] == L'\\') {
- bBackslash = FALSE;
- }
- }
-
- if (Parent == NULL || File->Buffer[0] == L'\\') {
- /* must be root inode */
- ASSERT(ParentLen == 0);
- bBackslash = FALSE;
- }
-
- /* allocate and initialize new name buffer */
- Length = File->Length;
- Length += (ParentLen + (bBackslash ? 1 : 0)) * sizeof(WCHAR);
-
- Target->Buffer = Ext2AllocatePool(
- PagedPool,
- Length + 2,
- EXT2_FNAME_MAGIC
- );
-
- if (!Target->Buffer) {
- DEBUG(DL_ERR, ( "Ex2BuildName: failed to allocate name bufer.\n"));
- return FALSE;
- }
- RtlZeroMemory(Target->Buffer, Length + 2);
-
- if (ParentLen) {
- RtlCopyMemory(&Target->Buffer[0],
- Parent->Buffer,
- ParentLen * sizeof(WCHAR));
- }
-
- if (bBackslash) {
- Target->Buffer[ParentLen++] = L'\\';
- }
-
- RtlCopyMemory( &Target->Buffer[ParentLen],
- File->Buffer,
- File->Length);
-
- INC_MEM_COUNT(PS_MCB_NAME, Target->Buffer, Length + 2);
- Target->Length = Length;
- Target->MaximumLength = Length + 2;
-
- return TRUE;
-}
-
-PEXT2_MCB
-Ext2AllocateMcb (
- IN PEXT2_VCB Vcb,
- IN PUNICODE_STRING FileName,
- IN PUNICODE_STRING Parent,
- IN ULONG FileAttr
-)
-{
- PEXT2_MCB Mcb = NULL;
- NTSTATUS Status = STATUS_SUCCESS;
-
- /* need wake the reaper thread if there are many Mcb allocated */
- if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 4)) {
- KeSetEvent(&Ext2Global->McbReaper.Wait, 0, FALSE);
- }
-
- /* allocate Mcb from LookasideList */
- Mcb = (PEXT2_MCB) (ExAllocateFromNPagedLookasideList(
- &(Ext2Global->Ext2McbLookasideList)));
-
- if (Mcb == NULL) {
- return NULL;
- }
-
- /* initialize Mcb header */
- RtlZeroMemory(Mcb, sizeof(EXT2_MCB));
- Mcb->Identifier.Type = EXT2MCB;
- Mcb->Identifier.Size = sizeof(EXT2_MCB);
- Mcb->FileAttr = FileAttr;
-
- Mcb->Inode.i_priv = (PVOID)Mcb;
- Mcb->Inode.i_sb = &Vcb->sb;
-
- /* initialize Mcb names */
- if (FileName) {
-
-#if EXT2_DEBUG
- if ( FileName->Length == 2 &&
- FileName->Buffer[0] == L'\\') {
- DEBUG(DL_RES, ( "Ext2AllocateMcb: Root Mcb is to be created !\n"));
- }
-
- if ( FileName->Length == 2 &&
- FileName->Buffer[0] == L'.') {
- DbgBreak();
- }
-
- if ( FileName->Length == 4 &&
- FileName->Buffer[0] == L'.' &&
- FileName->Buffer[1] == L'.' ) {
- DbgBreak();
- }
-#endif
-
- if (( FileName->Length >= 4 && FileName->Buffer[0] == L'.') &&
- ((FileName->Length == 4 && FileName->Buffer[1] != L'.') ||
- FileName->Length >= 6 )) {
- SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_HIDDEN);
- }
-
- if (!Ext2BuildName(&Mcb->ShortName, FileName, NULL)) {
- goto errorout;
- }
- if (!Ext2BuildName(&Mcb->FullName, FileName, Parent)) {
- goto errorout;
- }
- }
-
- /* initialize Mcb Extents, it will raise an expcetion if failed */
- __try {
- FsRtlInitializeLargeMcb(&(Mcb->Extents), NonPagedPool);
- FsRtlInitializeLargeMcb(&(Mcb->MetaExts), NonPagedPool);
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- DbgBreak();
- }
-
- if (!NT_SUCCESS(Status)) {
- goto errorout;
- }
-
- INC_MEM_COUNT(PS_MCB, Mcb, sizeof(EXT2_MCB));
- DEBUG(DL_INF, ( "Ext2AllocateMcb: Mcb %wZ created.\n", &Mcb->FullName));
-
- return Mcb;
-
-errorout:
-
- if (Mcb) {
-
- if (Mcb->ShortName.Buffer) {
- DEC_MEM_COUNT(PS_MCB_NAME, Mcb->ShortName.Buffer,
- Mcb->ShortName.MaximumLength);
- Ext2FreePool(Mcb->ShortName.Buffer, EXT2_FNAME_MAGIC);
- }
-
- if (Mcb->FullName.Buffer) {
- DEC_MEM_COUNT(PS_MCB_NAME, Mcb->FullName.Buffer,
- Mcb->FullName.MaximumLength);
- Ext2FreePool(Mcb->FullName.Buffer, EXT2_FNAME_MAGIC);
- }
-
- ExFreeToNPagedLookasideList(&(Ext2Global->Ext2McbLookasideList), Mcb);
- }
-
- return NULL;
-}
-
-VOID
-Ext2FreeMcb (IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb)
-{
- PEXT2_MCB Parent = Mcb->Parent;
-
- ASSERT(Mcb != NULL);
-
- ASSERT((Mcb->Identifier.Type == EXT2MCB) &&
- (Mcb->Identifier.Size == sizeof(EXT2_MCB)));
-
- if ((Mcb->Identifier.Type != EXT2MCB) ||
- (Mcb->Identifier.Size != sizeof(EXT2_MCB))) {
- return;
- }
-
- DEBUG(DL_INF, ( "Ext2FreeMcb: Mcb %wZ will be freed.\n", &Mcb->FullName));
-
- if (IsMcbSymLink(Mcb) && Mcb->Target) {
- Ext2DerefMcb(Mcb->Target);
- }
-
- if (FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)) {
- DEBUG(DL_EXT, ("List data extents for: %wZ\n", &Mcb->FullName));
- Ext2ListExtents(&Mcb->Extents);
- }
- FsRtlUninitializeLargeMcb(&(Mcb->Extents));
- if (FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)) {
- DEBUG(DL_EXT, ("List meta extents for: %wZ\n", &Mcb->FullName));
- Ext2ListExtents(&Mcb->MetaExts);
- }
- FsRtlUninitializeLargeMcb(&(Mcb->MetaExts));
- ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED);
-
- if (Mcb->ShortName.Buffer) {
- DEC_MEM_COUNT(PS_MCB_NAME, Mcb->ShortName.Buffer,
- Mcb->ShortName.MaximumLength);
- Ext2FreePool(Mcb->ShortName.Buffer, EXT2_FNAME_MAGIC);
- }
-
- if (Mcb->FullName.Buffer) {
- DEC_MEM_COUNT(PS_MCB_NAME, Mcb->FullName.Buffer,
- Mcb->FullName.MaximumLength);
- Ext2FreePool(Mcb->FullName.Buffer, EXT2_FNAME_MAGIC);
- }
-
- /* free dentry */
- if (Mcb->de) {
- Ext2FreeEntry(Mcb->de);
- }
-
- Mcb->Identifier.Type = 0;
- Mcb->Identifier.Size = 0;
-
- ExFreeToNPagedLookasideList(&(Ext2Global->Ext2McbLookasideList), Mcb);
- DEC_MEM_COUNT(PS_MCB, Mcb, sizeof(EXT2_MCB));
-}
-
-
-PEXT2_MCB
-Ext2SearchMcb(
- PEXT2_VCB Vcb,
- PEXT2_MCB Parent,
- PUNICODE_STRING FileName
-)
-{
- BOOLEAN LockAcquired = FALSE;
- PEXT2_MCB Mcb = NULL;
-
- __try {
- ExAcquireResourceSharedLite(&Vcb->McbLock, TRUE);
- LockAcquired = TRUE;
- Mcb = Ext2SearchMcbWithoutLock(Parent, FileName);
- } __finally {
- if (LockAcquired) {
- ExReleaseResourceLite(&Vcb->McbLock);
- }
- }
-
- return Mcb;
-}
-
-
-PEXT2_MCB
-Ext2SearchMcbWithoutLock(
- PEXT2_MCB Parent,
- PUNICODE_STRING FileName
-)
-{
- PEXT2_MCB TmpMcb = NULL;
-
- DEBUG(DL_RES, ("Ext2SearchMcb: %wZ\n", FileName));
-
- __try {
-
- Ext2ReferMcb(Parent);
-
- if (Ext2IsDot(FileName)) {
- TmpMcb = Parent;
- Ext2ReferMcb(Parent);
- __leave;
- }
-
- if (Ext2IsDotDot(FileName)) {
- if (IsMcbRoot(Parent)) {
- TmpMcb = Parent;
- } else {
- TmpMcb = Parent->Parent;
- }
- if (TmpMcb) {
- Ext2ReferMcb(TmpMcb);
- }
- __leave;
- }
-
- if (IsMcbSymLink(Parent)) {
- if (Parent->Target) {
- TmpMcb = Parent->Target->Child;
- ASSERT(!IsMcbSymLink(Parent->Target));
- } else {
- TmpMcb = NULL;
- __leave;
- }
- } else {
- TmpMcb = Parent->Child;
- }
-
- while (TmpMcb) {
-
- if (!RtlCompareUnicodeString(
- &(TmpMcb->ShortName),
- FileName, TRUE )) {
- Ext2ReferMcb(TmpMcb);
- break;
- }
-
- TmpMcb = TmpMcb->Next;
- }
-
- } __finally {
-
- Ext2DerefMcb(Parent);
- }
-
- return TmpMcb;
-}
-
-VOID
-Ext2InsertMcb (
- PEXT2_VCB Vcb,
- PEXT2_MCB Parent,
- PEXT2_MCB Child
-)
-{
- BOOLEAN LockAcquired = FALSE;
- PEXT2_MCB Mcb = NULL;
-
- __try {
-
- ExAcquireResourceExclusiveLite(
- &Vcb->McbLock,
- TRUE );
- LockAcquired = TRUE;
-
- /* use it's target if it's a symlink */
- if (IsMcbSymLink(Parent)) {
- Parent = Parent->Target;
- ASSERT(!IsMcbSymLink(Parent));
- }
-
- Mcb = Parent->Child;
- while (Mcb) {
- if (Mcb == Child) {
- break;
- }
- Mcb = Mcb->Next;
- }
-
- if (Mcb) {
- /* already attached in the list */
- DEBUG(DL_ERR, ( "Ext2InsertMcb: Child Mcb is alreay attached.\n"));
- if (!IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
- SetLongFlag(Child->Flags, MCB_ENTRY_TREE);
- DEBUG(DL_ERR, ( "Ext2InsertMcb: Child Mcb's flag isn't set.\n"));
- }
-
- DbgBreak();
-
- } else {
-
- /* insert this Mcb into the head */
- Child->Next = Parent->Child;
- Parent->Child = Child;
- Child->Parent = Parent;
- Child->de->d_parent = Parent->de;
- Ext2ReferMcb(Parent);
- SetLongFlag(Child->Flags, MCB_ENTRY_TREE);
- }
-
- } __finally {
-
- if (LockAcquired) {
- ExReleaseResourceLite(&Vcb->McbLock);
- }
- }
-}
-
-BOOLEAN
-Ext2RemoveMcb (
- PEXT2_VCB Vcb,
- PEXT2_MCB Mcb
-)
-{
- PEXT2_MCB TmpMcb = NULL;
- BOOLEAN LockAcquired = FALSE;
- BOOLEAN bLinked = FALSE;
-
- __try {
-
- ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
- LockAcquired = TRUE;
-
- if (Mcb->Parent) {
-
- if (Mcb->Parent->Child == Mcb) {
- Mcb->Parent->Child = Mcb->Next;
- bLinked = TRUE;
- } else {
- TmpMcb = Mcb->Parent->Child;
-
- while (TmpMcb && TmpMcb->Next != Mcb) {
- TmpMcb = TmpMcb->Next;
- }
-
- if (TmpMcb) {
- TmpMcb->Next = Mcb->Next;
- bLinked = TRUE;
- } else {
- /* we got errors: link broken */
- }
- }
-
- if (bLinked) {
- if (IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
- DEBUG(DL_RES, ("Mcb %p %wZ removed from Mcb %p %wZ\n", Mcb,
- &Mcb->FullName, Mcb->Parent, &Mcb->Parent->FullName));
- Ext2DerefMcb(Mcb->Parent);
- ClearLongFlag(Mcb->Flags, MCB_ENTRY_TREE);
- } else {
- DbgBreak();
- }
- } else {
- if (IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
- ClearLongFlag(Mcb->Flags, MCB_ENTRY_TREE);
- }
- DbgBreak();
- }
- Mcb->Parent = NULL;
- Mcb->de->d_parent = NULL;
- }
-
- } __finally {
-
- if (LockAcquired) {
- ExReleaseResourceLite(&Vcb->McbLock);
- }
- }
-
- return TRUE;
-}
-
-VOID
-Ext2CleanupAllMcbs(PEXT2_VCB Vcb)
-{
- BOOLEAN LockAcquired = FALSE;
- PEXT2_MCB Mcb = NULL;
-
- __try {
-
- ExAcquireResourceExclusiveLite(
- &Vcb->McbLock,
- TRUE );
- LockAcquired = TRUE;
-
- while (Mcb = Ext2FirstUnusedMcb(Vcb, TRUE, Vcb->NumOfMcb)) {
- while (Mcb) {
- PEXT2_MCB Next = Mcb->Next;
- if (IsMcbSymLink(Mcb)) {
- Mcb->Target = NULL;
- }
- Ext2FreeMcb(Vcb, Mcb);
- Mcb = Next;
- }
- }
- Ext2FreeMcb(Vcb, Vcb->McbTree);
- Vcb->McbTree = NULL;
-
- } __finally {
-
- if (LockAcquired) {
- ExReleaseResourceLite(&Vcb->McbLock);
- }
- }
-}
-
-BOOLEAN
-Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
-{
- PEXT2_GROUP_DESC gd;
- struct buffer_head *gb = NULL;
- struct buffer_head *bh = NULL;
- ULONG group, dwBlk, Length;
- RTL_BITMAP bitmap;
- BOOLEAN bModified = FALSE;
-
- group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
- dwBlk = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
-
- gd = ext4_get_group_desc(&Vcb->sb, group, &gb);
- if (!gd) {
- return FALSE;
- }
- bh = sb_getblk(&Vcb->sb, ext4_block_bitmap(&Vcb->sb, gd));
-
- if (group == Vcb->sbi.s_groups_count - 1) {
- Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
-
- /* s_blocks_count is integer multiple of s_blocks_per_group */
- if (Length == 0)
- Length = BLOCKS_PER_GROUP;
- } else {
- Length = BLOCKS_PER_GROUP;
- }
-
- if (dwBlk >= Length) {
- fini_bh(&gb);
- fini_bh(&bh);
- return FALSE;
- }
-
-
- RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
-
- if (RtlCheckBit(&bitmap, dwBlk) == 0) {
- DbgBreak();
- RtlSetBits(&bitmap, dwBlk, 1);
- bModified = TRUE;
- mark_buffer_dirty(bh);
- }
-
- fini_bh(&gb);
- fini_bh(&bh);
-
- return (!bModified);
-}
-
-BOOLEAN
-Ext2CheckBitmapConsistency(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
-{
- ULONG i, j, InodeBlocks;
-
- for (i = 0; i < Vcb->sbi.s_groups_count; i++) {
-
- PEXT2_GROUP_DESC gd;
- struct buffer_head *bh = NULL;
-
- gd = ext4_get_group_desc(&Vcb->sb, i, &bh);
- if (!gd)
- continue;
- Ext2CheckSetBlock(IrpContext, Vcb, ext4_block_bitmap(&Vcb->sb, gd));
- Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_bitmap(&Vcb->sb, gd));
-
-
- if (i == Vcb->sbi.s_groups_count - 1) {
- InodeBlocks = ((INODES_COUNT % INODES_PER_GROUP) *
- Vcb->InodeSize + Vcb->BlockSize - 1) /
- (Vcb->BlockSize);
- } else {
- InodeBlocks = (INODES_PER_GROUP * Vcb->InodeSize +
- Vcb->BlockSize - 1) / (Vcb->BlockSize);
- }
-
- for (j = 0; j < InodeBlocks; j++ )
- Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_table(&Vcb->sb, gd) + j);
-
- fini_bh(&bh);
- }
-
- return TRUE;
-}
-
-/* Ext2Global->Resource should be already acquired */
-VOID
-Ext2InsertVcb(PEXT2_VCB Vcb)
-{
- InsertTailList(&(Ext2Global->VcbList), &Vcb->Next);
-}
-
-
-/* Ext2Global->Resource should be already acquired */
-VOID
-Ext2RemoveVcb(PEXT2_VCB Vcb)
-{
- RemoveEntryList(&Vcb->Next);
- InitializeListHead(&Vcb->Next);
-}
-
-NTSTATUS
-Ext2QueryVolumeParams(IN PEXT2_VCB Vcb, IN PUNICODE_STRING Params)
-{
- NTSTATUS Status;
- RTL_QUERY_REGISTRY_TABLE QueryTable[2];
-
- UNICODE_STRING UniName;
- PUSHORT UniBuffer = NULL;
-
- USHORT UUID[50];
-
- int i;
- int len = 0;
-
- /* zero params */
- RtlZeroMemory(Params, sizeof(UNICODE_STRING));
-
- /* constructing volume UUID name */
- memset(UUID, 0, sizeof(USHORT) * 50);
- for (i=0; i < 16; i++) {
- if (i == 0) {
- swprintf((wchar_t *)&UUID[len], L"{%2.2X",Vcb->SuperBlock->s_uuid[i]);
- len += 3;
- } else if (i == 15) {
- swprintf((wchar_t *)&UUID[len], L"-%2.2X}", Vcb->SuperBlock->s_uuid[i]);
- len +=4;
- } else {
- swprintf((wchar_t *)&UUID[len], L"-%2.2X", Vcb->SuperBlock->s_uuid[i]);
- len += 3;
- }
- }
-
- /* allocating memory for UniBuffer */
- UniBuffer = Ext2AllocatePool(PagedPool, 1024, EXT2_PARAM_MAGIC);
- if (NULL == UniBuffer) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto errorout;
- }
- RtlZeroMemory(UniBuffer, 1024);
-
- /* querying volume parameter string */
- RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
- QueryTable[0].Name = UUID;
- QueryTable[0].EntryContext = &(UniName);
- UniName.MaximumLength = 1024;
- UniName.Length = 0;
- UniName.Buffer = UniBuffer;
-
- Status = RtlQueryRegistryValues(
- RTL_REGISTRY_ABSOLUTE,
- Ext2Global->RegistryPath.Buffer,
- &QueryTable[0],
- NULL,
- NULL
- );
-
- if (!NT_SUCCESS(Status)) {
- goto errorout;
- }
-
-errorout:
-
- if (NT_SUCCESS(Status)) {
- *Params = UniName;
- } else {
- if (UniBuffer) {
- Ext2FreePool(UniBuffer, EXT2_PARAM_MAGIC);
- }
- }
-
- return Status;
-}
-
-VOID
-Ext2ParseRegistryVolumeParams(
- IN PUNICODE_STRING Params,
- OUT PEXT2_VOLUME_PROPERTY3 Property
-)
-{
- WCHAR Codepage[CODEPAGE_MAXLEN];
- WCHAR Prefix[HIDINGPAT_LEN];
- WCHAR Suffix[HIDINGPAT_LEN];
- USHORT MountPoint[4];
- UCHAR DrvLetter[4];
- WCHAR wUID[8], wGID[8], wEUID[8], wEGID[8];
- CHAR sUID[8], sGID[8], sEUID[8], sEGID[8];
-
- BOOLEAN bWriteSupport = FALSE,
- bCheckBitmap = FALSE,
- bCodeName = FALSE,
- bMountPoint = FALSE;
- BOOLEAN bUID = 0, bGID = 0, bEUID = 0, bEGID = 0;
-
- struct {
- PWCHAR Name; /* parameters name */
- PBOOLEAN bExist; /* is it contained in params */
- USHORT Length; /* parameter value length */
- PWCHAR uValue; /* value buffer in unicode */
- PCHAR aValue; /* value buffer in ansi */
- } ParamPattern[] = {
- /* writing support */
- {READING_ONLY, &Property->bReadonly, 0, NULL, NULL},
- {WRITING_SUPPORT, &bWriteSupport, 0, NULL, NULL},
- {EXT3_FORCEWRITING, &Property->bExt3Writable, 0, NULL, NULL},
-
- /* need check bitmap */
- {CHECKING_BITMAP, &bCheckBitmap, 0, NULL, NULL},
- /* codepage */
- {CODEPAGE_NAME, &bCodeName, CODEPAGE_MAXLEN,
- &Codepage[0], Property->Codepage},
- /* filter prefix and suffix */
- {HIDING_PREFIX, &Property->bHidingPrefix, HIDINGPAT_LEN,
- &Prefix[0], Property->sHidingPrefix},
- {HIDING_SUFFIX, &Property->bHidingSuffix, HIDINGPAT_LEN,
- &Suffix[0], Property->sHidingSuffix},
- {MOUNT_POINT, &bMountPoint, 4,
- &MountPoint[0], &DrvLetter[0]},
-
- {UID, &bUID, 8, &wUID[0], &sUID[0],},
- {GID, &bGID, 8, &wGID[0], &sGID[0]},
- {EUID, &bEUID, 8, &wEUID[0], &sEUID[0]},
- {EGID, &bEGID, 8, &wEGID[0], &sEGID[0]},
-
- /* end */
- {NULL, NULL, 0, NULL}
- };
-
- USHORT i, j, k;
-
- RtlZeroMemory(Codepage, CODEPAGE_MAXLEN);
- RtlZeroMemory(Prefix, HIDINGPAT_LEN);
- RtlZeroMemory(Suffix, HIDINGPAT_LEN);
- RtlZeroMemory(MountPoint, sizeof(USHORT) * 4);
- RtlZeroMemory(DrvLetter, sizeof(CHAR) * 4);
-
- RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY3));
- Property->Magic = EXT2_VOLUME_PROPERTY_MAGIC;
- Property->Command = APP_CMD_SET_PROPERTY3;
-
- for (i=0; ParamPattern[i].Name != NULL; i++) {
-
- UNICODE_STRING Name1=*Params, Name2;
- RtlInitUnicodeString(&Name2, ParamPattern[i].Name);
- *ParamPattern[i].bExist = FALSE;
-
- for (j=0; j * sizeof(WCHAR) + Name2.Length <= Params->Length ; j++) {
-
- Name1.MaximumLength = Params->Length - j * sizeof(WCHAR);
- Name1.Length = Name2.Length;
- Name1.Buffer = &Params->Buffer[j];
-
- if (!RtlCompareUnicodeString(&Name1, &Name2, TRUE)) {
- if (j * sizeof(WCHAR) + Name2.Length == Params->Length ||
- Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L';' ||
- Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L',' ) {
- *(ParamPattern[i].bExist) = TRUE;
- } else if ((j * 2 + Name2.Length < Params->Length + 2) ||
- (Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L'=' )) {
- j += Name2.Length/sizeof(WCHAR) + 1;
- k = 0;
- while ( j + k < Params->Length/2 &&
- k < ParamPattern[i].Length &&
- Params->Buffer[j+k] != L';' &&
- Params->Buffer[j+k] != L',' ) {
- ParamPattern[i].uValue[k] = Params->Buffer[j + k++];
- }
- if (k) {
- NTSTATUS status;
- ANSI_STRING AnsiName;
- AnsiName.Length = 0;
- AnsiName.MaximumLength =ParamPattern[i].Length;
- AnsiName.Buffer = ParamPattern[i].aValue;
-
- Name2.Buffer = ParamPattern[i].uValue;
- Name2.MaximumLength = Name2.Length = k * sizeof(WCHAR);
- status = RtlUnicodeStringToAnsiString(
- &AnsiName, &Name2, FALSE);
- if (NT_SUCCESS(status)) {
- *(ParamPattern[i].bExist) = TRUE;
- } else {
- *ParamPattern[i].bExist = FALSE;
- }
- }
- }
- break;
- }
- }
- }
-
- if (bMountPoint) {
- Property->DrvLetter = DrvLetter[0];
- Property->DrvLetter |= 0x80;
- }
-
- if (bUID && bGID) {
- SetFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
- sUID[7] = sGID[7] = sEUID[7] = sEGID[7] = 0;
- Property->uid = (USHORT)atoi(sUID);
- Property->gid = (USHORT)atoi(sGID);
- if (bEUID) {
- Property->euid = (USHORT)atoi(sEUID);
- Property->egid = (USHORT)atoi(sEGID);
- Property->EIDS = TRUE;
- } else {
- Property->EIDS = FALSE;
- }
- } else {
- ClearFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
- }
-}
-
-NTSTATUS
-Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
-{
- NTSTATUS Status;
- UNICODE_STRING VolumeParams;
-
- Status = Ext2QueryVolumeParams(Vcb, &VolumeParams);
- if (NT_SUCCESS(Status)) {
-
- /* set Vcb settings from registery */
- EXT2_VOLUME_PROPERTY3 Property;
- Ext2ParseRegistryVolumeParams(&VolumeParams, &Property);
- Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property));
-
- } else {
-
- /* don't support auto mount */
- if (IsFlagOn(Ext2Global->Flags, EXT2_AUTO_MOUNT)) {
- Status = STATUS_SUCCESS;
- } else {
- Status = STATUS_UNSUCCESSFUL;
- goto errorout;
- }
-
- /* set Vcb settings from Ext2Global */
- if (IsFlagOn(Ext2Global->Flags, EXT2_SUPPORT_WRITING)) {
- if (Vcb->IsExt3fs) {
- if (IsFlagOn(Ext2Global->Flags, EXT3_FORCE_WRITING)) {
- ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
- } else {
- SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
- }
- } else {
- ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
- }
- } else {
- SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
- }
-
- /* set the default codepage */
- Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
- memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN);
- Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
-
- if (Vcb->bHidingPrefix = Ext2Global->bHidingPrefix) {
- RtlCopyMemory( Vcb->sHidingPrefix,
- Ext2Global->sHidingPrefix,
- HIDINGPAT_LEN);
- } else {
- RtlZeroMemory( Vcb->sHidingPrefix,
- HIDINGPAT_LEN);
- }
-
- if (Vcb->bHidingSuffix = Ext2Global->bHidingSuffix) {
- RtlCopyMemory( Vcb->sHidingSuffix,
- Ext2Global->sHidingSuffix,
- HIDINGPAT_LEN);
- } else {
- RtlZeroMemory( Vcb->sHidingSuffix,
- HIDINGPAT_LEN);
- }
- }
-
-errorout:
-
- if (VolumeParams.Buffer) {
- Ext2FreePool(VolumeParams.Buffer, EXT2_PARAM_MAGIC);
- }
-
- return Status;
-}
-
-NTSTATUS
-Ext2InitializeLabel(
- IN PEXT2_VCB Vcb,
- IN PEXT2_SUPER_BLOCK Sb
-)
-{
- NTSTATUS status;
-
- USHORT Length;
- UNICODE_STRING Label;
- OEM_STRING OemName;
-
- Label.MaximumLength = 16 * sizeof(WCHAR);
- Label.Length = 0;
- Label.Buffer = Vcb->Vpb->VolumeLabel;
- Vcb->Vpb->VolumeLabelLength = 0;
- RtlZeroMemory(Label.Buffer, Label.MaximumLength);
-
- Length = 16;
- while ( (Length > 0) &&
- ((Sb->s_volume_name[Length -1] == 0x00) ||
- (Sb->s_volume_name[Length - 1] == 0x20) )
- ) {
- Length--;
- }
-
- if (Length == 0) {
- return STATUS_SUCCESS;
- }
-
- OemName.Buffer = Sb->s_volume_name;
- OemName.MaximumLength = 16;
- OemName.Length = Length;
-
- status = Ext2OEMToUnicode(Vcb, &Label, &OemName);
- if (NT_SUCCESS(status)) {
- Vcb->Vpb->VolumeLabelLength = Label.Length;
- }
-
- return status;
-}
-
-static __inline BOOLEAN Ext2IsNullUuid (__u8 * uuid)
-{
- int i;
- for (i = 0; i < 16; i++) {
- if (uuid[i]) {
- break;
- }
- }
-
- return (i >= 16);
-}
-
-#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
-
-NTSTATUS
-Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
- IN PEXT2_VCB Vcb,
- IN PEXT2_SUPER_BLOCK sb,
- IN PDEVICE_OBJECT TargetDevice,
- IN PDEVICE_OBJECT VolumeDevice,
- IN PVPB Vpb )
-{
- NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
- ULONG IoctlSize;
- LONGLONG DiskSize;
- LONGLONG PartSize;
- UNICODE_STRING RootNode;
- USHORT Buffer[2];
- ULONG ChangeCount = 0, features;
- CC_FILE_SIZES FileSizes;
- int i, has_huge_files;
-
- BOOLEAN VcbResourceInitialized = FALSE;
- BOOLEAN NotifySyncInitialized = FALSE;
- BOOLEAN ExtentsInitialized = FALSE;
- BOOLEAN InodeLookasideInitialized = FALSE;
- BOOLEAN GroupLoaded = FALSE;
-
- __try {
-
- if (Vpb == NULL) {
- Status = STATUS_DEVICE_NOT_READY;
- __leave;
- }
-
- /* Reject mounting volume if we encounter unsupported incompat features */
- if (FlagOn(sb->s_feature_incompat, ~EXT4_FEATURE_INCOMPAT_SUPP)) {
- Status = STATUS_UNRECOGNIZED_VOLUME;
- __leave;
- }
-
- /* Mount the volume RO if we encounter unsupported ro_compat features */
- if (FlagOn(sb->s_feature_ro_compat, ~EXT4_FEATURE_RO_COMPAT_SUPP)) {
- SetLongFlag(Vcb->Flags, VCB_RO_COMPAT_READ_ONLY);
- }
-
- /* Recognize the filesystem as Ext3fs if it supports journalling */
- if (IsFlagOn(sb->s_feature_compat, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
- Vcb->IsExt3fs = TRUE;
- }
-
- /* check block size */
- Vcb->BlockSize = (EXT2_MIN_BLOCK_SIZE << sb->s_log_block_size);
- /* we cannot handle volume with block size bigger than 64k */
- if (Vcb->BlockSize > EXT2_MAX_USER_BLKSIZE) {
- Status = STATUS_UNRECOGNIZED_VOLUME;
- __leave;
- }
-
- if (Vcb->BlockSize >= PAGE_SIZE) {
- Vcb->IoUnitBits = PAGE_SHIFT;
- Vcb->IoUnitSize = PAGE_SIZE;
- } else {
- Vcb->IoUnitSize = Vcb->BlockSize;
- Vcb->IoUnitBits = Ext2Log2(Vcb->BlockSize);
- }
-
- /* initialize vcb header members ... */
- Vcb->Header.IsFastIoPossible = FastIoIsNotPossible;
- Vcb->Header.Resource = &(Vcb->MainResource);
- Vcb->Header.PagingIoResource = &(Vcb->PagingIoResource);
- Vcb->OpenVolumeCount = 0;
- Vcb->OpenHandleCount = 0;
- Vcb->ReferenceCount = 0;
-
- /* initialize eresources */
- ExInitializeResourceLite(&Vcb->MainResource);
- ExInitializeResourceLite(&Vcb->PagingIoResource);
- ExInitializeResourceLite(&Vcb->MetaInode);
- ExInitializeResourceLite(&Vcb->MetaBlock);
- ExInitializeResourceLite(&Vcb->McbLock);
- ExInitializeResourceLite(&Vcb->FcbLock);
- ExInitializeResourceLite(&Vcb->sbi.s_gd_lock);
-#ifndef _WIN2K_TARGET_
- ExInitializeFastMutex(&Vcb->Mutex);
- FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->Mutex);
-#endif
- VcbResourceInitialized = TRUE;
-
- /* initialize Fcb list head */
- InitializeListHead(&Vcb->FcbList);
-
- /* initialize Mcb list head */
- InitializeListHead(&(Vcb->McbList));
-
- /* initialize directory notify list */
- InitializeListHead(&Vcb->NotifyList);
- FsRtlNotifyInitializeSync(&Vcb->NotifySync);
- NotifySyncInitialized = TRUE;
-
- /* superblock checking */
- Vcb->SuperBlock = sb;
-
- /* initialize Vpb and Label */
- Vcb->DeviceObject = VolumeDevice;
- Vcb->TargetDeviceObject = TargetDevice;
- Vcb->Vpb = Vpb;
- Vcb->RealDevice = Vpb->RealDevice;
- Vpb->DeviceObject = VolumeDevice;
-
- /* set inode size */
- Vcb->InodeSize = (ULONG)sb->s_inode_size;
- if (Vcb->InodeSize == 0) {
- Vcb->InodeSize = EXT2_GOOD_OLD_INODE_SIZE;
- }
-
- /* initialize inode lookaside list */
- ExInitializeNPagedLookasideList(&(Vcb->InodeLookasideList),
- NULL, NULL, 0, Vcb->InodeSize,
- 'SNIE', 0);
-
- InodeLookasideInitialized = TRUE;
-
- /* initialize label in Vpb */
- Status = Ext2InitializeLabel(Vcb, sb);
- if (!NT_SUCCESS(Status)) {
- DbgBreak();
- }
-
- /* check device characteristics flags */
- if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA)) {
- SetLongFlag(Vcb->Flags, VCB_REMOVABLE_MEDIA);
- }
-
- if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
- SetLongFlag(Vcb->Flags, VCB_FLOPPY_DISK);
- }
-
- if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
- SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
- }
-
- if (IsFlagOn(TargetDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
- SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
- }
-
- /* verify device is writable ? */
- if (Ext2IsMediaWriteProtected(IrpContext, TargetDevice)) {
- SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
- }
-
- /* initialize UUID and serial number */
- if (Ext2IsNullUuid(sb->s_uuid)) {
- ExUuidCreate((UUID *)sb->s_uuid);
- }
- Vpb->SerialNumber = ((ULONG*)sb->s_uuid)[0] +
- ((ULONG*)sb->s_uuid)[1] +
- ((ULONG*)sb->s_uuid)[2] +
- ((ULONG*)sb->s_uuid)[3];
-
- /* query partition size and disk geometry parameters */
- DiskSize = Vcb->DiskGeometry.Cylinders.QuadPart *
- Vcb->DiskGeometry.TracksPerCylinder *
- Vcb->DiskGeometry.SectorsPerTrack *
- Vcb->DiskGeometry.BytesPerSector;
-
- IoctlSize = sizeof(PARTITION_INFORMATION);
- Status = Ext2DiskIoControl(
- TargetDevice,
- IOCTL_DISK_GET_PARTITION_INFO,
- NULL,
- 0,
- &Vcb->PartitionInformation,
- &IoctlSize );
- if (NT_SUCCESS(Status)) {
- PartSize = Vcb->PartitionInformation.PartitionLength.QuadPart;
- } else {
- Vcb->PartitionInformation.StartingOffset.QuadPart = 0;
- Vcb->PartitionInformation.PartitionLength.QuadPart = DiskSize;
- PartSize = DiskSize;
- Status = STATUS_SUCCESS;
- }
- Vcb->Header.AllocationSize.QuadPart =
- Vcb->Header.FileSize.QuadPart = PartSize;
-
- Vcb->Header.ValidDataLength.QuadPart =
- Vcb->Header.FileSize.QuadPart;
-
- /* verify count */
- IoctlSize = sizeof(ULONG);
- Status = Ext2DiskIoControl(
- TargetDevice,
- IOCTL_DISK_CHECK_VERIFY,
- NULL,
- 0,
- &ChangeCount,
- &IoctlSize );
-
- if (!NT_SUCCESS(Status)) {
- __leave;
- }
- Vcb->ChangeCount = ChangeCount;
-
- /* create the stream object for ext2 volume */
- Vcb->Volume = IoCreateStreamFileObject(NULL, Vcb->Vpb->RealDevice);
- if (!Vcb->Volume) {
- Status = STATUS_UNRECOGNIZED_VOLUME;
- __leave;
- }
-
- /* initialize streaming object file */
- Vcb->Volume->SectionObjectPointer = &(Vcb->SectionObject);
- Vcb->Volume->ReadAccess = TRUE;
- Vcb->Volume->WriteAccess = TRUE;
- Vcb->Volume->DeleteAccess = TRUE;
- Vcb->Volume->FsContext = (PVOID) Vcb;
- Vcb->Volume->FsContext2 = NULL;
- Vcb->Volume->Vpb = Vcb->Vpb;
-
- FileSizes.AllocationSize.QuadPart =
- FileSizes.FileSize.QuadPart =
- FileSizes.ValidDataLength.QuadPart =
- Vcb->Header.AllocationSize.QuadPart;
-
- CcInitializeCacheMap( Vcb->Volume,
- &FileSizes,
- TRUE,
- &(Ext2Global->CacheManagerNoOpCallbacks),
- Vcb );
-
- /* initialize disk block LargetMcb and entry Mcb,
- it will raise an expcetion if failed */
- __try {
- FsRtlInitializeLargeMcb(&(Vcb->Extents), PagedPool);
- } __except (EXCEPTION_EXECUTE_HANDLER) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- DbgBreak();
- }
- if (!NT_SUCCESS(Status)) {
- __leave;
- }
- ExtentsInitialized = TRUE;
-
- /* set block device */
- Vcb->bd.bd_dev = Vcb->RealDevice;
- Vcb->bd.bd_geo = Vcb->DiskGeometry;
- Vcb->bd.bd_part = Vcb->PartitionInformation;
- Vcb->bd.bd_volume = Vcb->Volume;
- Vcb->bd.bd_priv = (void *) Vcb;
- memset(&Vcb->bd.bd_bh_root, 0, sizeof(struct rb_root));
- InitializeListHead(&Vcb->bd.bd_bh_free);
- ExInitializeResourceLite(&Vcb->bd.bd_bh_lock);
- KeInitializeEvent(&Vcb->bd.bd_bh_notify,
- NotificationEvent, TRUE);
- Vcb->bd.bd_bh_cache = kmem_cache_create("bd_bh_buffer",
- Vcb->BlockSize, 0, 0, NULL);
- if (!Vcb->bd.bd_bh_cache) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- __leave;
- }
-
- Vcb->SectorBits = Ext2Log2(SECTOR_SIZE);
- Vcb->sb.s_magic = sb->s_magic;
- Vcb->sb.s_bdev = &Vcb->bd;
- Vcb->sb.s_blocksize = BLOCK_SIZE;
- Vcb->sb.s_blocksize_bits = BLOCK_BITS;
- Vcb->sb.s_priv = (void *) Vcb;
- Vcb->sb.s_fs_info = &Vcb->sbi;
-
- Vcb->sbi.s_es = sb;
- Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
- Vcb->sbi.s_first_ino = sb->s_first_ino;
- Vcb->sbi.s_desc_size = sb->s_desc_size;
-
- if (EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
- if (Vcb->sbi.s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
- Vcb->sbi.s_desc_size > EXT4_MAX_DESC_SIZE ||
- !is_power_of_2(Vcb->sbi.s_desc_size)) {
- DEBUG(DL_ERR, ("EXT4-fs: unsupported descriptor size %lu\n", Vcb->sbi.s_desc_size));
- Status = STATUS_DISK_CORRUPT_ERROR;
- __leave;
- }
- } else {
- Vcb->sbi.s_desc_size = EXT4_MIN_DESC_SIZE;
- }
-
- Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
- Vcb->sbi.s_inodes_per_group = sb->s_inodes_per_group;
- if (EXT3_INODES_PER_GROUP(&Vcb->sb) == 0) {
- Status = STATUS_DISK_CORRUPT_ERROR;
- __leave;
- }
- Vcb->sbi.s_inodes_per_block = BLOCK_SIZE / Vcb->InodeSize;
- if (Vcb->sbi.s_inodes_per_block == 0) {
- Status = STATUS_DISK_CORRUPT_ERROR;
- __leave;
- }
- Vcb->sbi.s_itb_per_group = Vcb->sbi.s_inodes_per_group /
- Vcb->sbi.s_inodes_per_block;
-
-
- Vcb->sbi.s_desc_per_block = BLOCK_SIZE / GROUP_DESC_SIZE;
- Vcb->sbi.s_desc_per_block_bits = ilog2(Vcb->sbi.s_desc_per_block);
-
- for (i=0; i < 4; i++) {
- Vcb->sbi.s_hash_seed[i] = sb->s_hash_seed[i];
- }
- Vcb->sbi.s_def_hash_version = sb->s_def_hash_version;
-
- if (le32_to_cpu(sb->s_rev_level) == EXT3_GOOD_OLD_REV &&
- (EXT3_HAS_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
- EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
- EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~0U))) {
- printk(KERN_WARNING
- "EXT3-fs warning: feature flags set on rev 0 fs, "
- "running e2fsck is recommended\n");
- }
-
- /*
- * Check feature flags regardless of the revision level, since we
- * previously didn't change the revision level when setting the flags,
- * so there is a chance incompat flags are set on a rev 0 filesystem.
- */
- features = EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_INCOMPAT_SUPP);
- if (features & EXT4_FEATURE_INCOMPAT_DIRDATA) {
- SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
- ClearFlag(features, EXT4_FEATURE_INCOMPAT_DIRDATA);
- }
- if (features) {
- printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of "
- "unsupported optional features (%x).\n",
- Vcb->sb.s_id, le32_to_cpu(features));
- Status = STATUS_UNRECOGNIZED_VOLUME;
- __leave;
- }
-
- features = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_RO_COMPAT_SUPP);
- if (features) {
- printk(KERN_ERR "EXT3-fs: %s: unsupported optional features in this volume: (%x).\n",
- Vcb->sb.s_id, le32_to_cpu(features));
- if (CanIWrite(Vcb)) {
- } else {
- SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
- }
- }
-
- has_huge_files = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
-
- Vcb->sb.s_maxbytes = ext3_max_size(BLOCK_BITS, has_huge_files);
- Vcb->max_bitmap_bytes = ext3_max_bitmap_size(BLOCK_BITS,
- has_huge_files);
- Vcb->max_bytes = ext3_max_size(BLOCK_BITS, has_huge_files);
-
- /* calculate maximum file bocks ... */
- {
- ULONG dwData[EXT2_BLOCK_TYPES] = {EXT2_NDIR_BLOCKS, 1, 1, 1};
- ULONG i;
-
- ASSERT(BLOCK_BITS == Ext2Log2(BLOCK_SIZE));
-
- Vcb->sbi.s_groups_count = (ULONG)(ext3_blocks_count(sb) - sb->s_first_data_block +
- sb->s_blocks_per_group - 1) / sb->s_blocks_per_group;
-
- Vcb->max_data_blocks = 0;
- for (i = 0; i < EXT2_BLOCK_TYPES; i++) {
- if (BLOCK_BITS >= 12 && i == (EXT2_BLOCK_TYPES - 1)) {
- dwData[i] = 0x40000000;
- } else {
- dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);
- }
- Vcb->max_blocks_per_layer[i] = dwData[i];
- Vcb->max_data_blocks += Vcb->max_blocks_per_layer[i];
- }
- }
-
- Vcb->sbi.s_gdb_count = (Vcb->sbi.s_groups_count + Vcb->sbi.s_desc_per_block - 1) /
- Vcb->sbi.s_desc_per_block;
- /* load all gorup desc */
- if (!Ext2LoadGroup(Vcb)) {
- Status = STATUS_UNSUCCESSFUL;
- __leave;
- }
- GroupLoaded = TRUE;
-
- /* recovery journal since it's ext3 */
- if (Vcb->IsExt3fs) {
- Ext2RecoverJournal(IrpContext, Vcb);
- if (IsFlagOn(Vcb->Flags, VCB_JOURNAL_RECOVER)) {
- SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
- }
- }
-
- /* Now allocating the mcb for root ... */
- Buffer[0] = L'\\';
- Buffer[1] = 0;
- RootNode.Buffer = Buffer;
- RootNode.MaximumLength = RootNode.Length = 2;
- Vcb->McbTree = Ext2AllocateMcb(
- Vcb, &RootNode, NULL,
- FILE_ATTRIBUTE_DIRECTORY
- );
- if (!Vcb->McbTree) {
- DbgBreak();
- Status = STATUS_UNSUCCESSFUL;
- __leave;
- }
-
- Vcb->sb.s_root = Ext2BuildEntry(Vcb, NULL, &RootNode);
- if (!Vcb->sb.s_root) {
- DbgBreak();
- Status = STATUS_UNSUCCESSFUL;
- __leave;
- }
- Vcb->sb.s_root->d_sb = &Vcb->sb;
- Vcb->sb.s_root->d_inode = &Vcb->McbTree->Inode;
- Vcb->McbTree->de = Vcb->sb.s_root;
-
- /* load root inode */
- Vcb->McbTree->Inode.i_ino = EXT2_ROOT_INO;
- Vcb->McbTree->Inode.i_sb = &Vcb->sb;
- if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode)) {
- DbgBreak();
- Status = STATUS_CANT_WAIT;
- __leave;
- }
-
- /* initializeroot node */
- Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime);
- Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime);
- Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
- Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
-
- /* check bitmap if user specifies it */
- if (IsFlagOn(Ext2Global->Flags, EXT2_CHECKING_BITMAP)) {
- Ext2CheckBitmapConsistency(IrpContext, Vcb);
- }
-
- /* get anything doen, then refer target device */
- ObReferenceObject(Vcb->TargetDeviceObject);
-
- /* query parameters from registry */
- Ext2PerformRegistryVolumeParams(Vcb);
-
- SetLongFlag(Vcb->Flags, VCB_INITIALIZED);
-
- } __finally {
-
- if (!NT_SUCCESS(Status)) {
-
- if (Vcb->McbTree) {
- Ext2FreeMcb(Vcb, Vcb->McbTree);
- }
-
- if (InodeLookasideInitialized) {
- ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
- }
-
- if (ExtentsInitialized) {
- if (Vcb->bd.bd_bh_cache) {
- if (GroupLoaded)
- Ext2PutGroup(Vcb);
- kmem_cache_destroy(Vcb->bd.bd_bh_cache);
- }
- FsRtlUninitializeLargeMcb(&(Vcb->Extents));
- }
-
- if (Vcb->Volume) {
- if (Vcb->Volume->PrivateCacheMap) {
- Ext2SyncUninitializeCacheMap(Vcb->Volume);
- }
- ObDereferenceObject(Vcb->Volume);
- }
-
- if (NotifySyncInitialized) {
- FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
- }
-
- if (VcbResourceInitialized) {
- ExDeleteResourceLite(&Vcb->FcbLock);
- ExDeleteResourceLite(&Vcb->McbLock);
- ExDeleteResourceLite(&Vcb->MetaInode);
- ExDeleteResourceLite(&Vcb->MetaBlock);
- ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
- ExDeleteResourceLite(&Vcb->MainResource);
- ExDeleteResourceLite(&Vcb->PagingIoResource);
- }
- }
- }
-
- return Status;
-}
-
-
-VOID
-Ext2TearDownStream(IN PEXT2_VCB Vcb)
-{
- PFILE_OBJECT Stream = Vcb->Volume;
- IO_STATUS_BLOCK IoStatus;
-
- ASSERT(Vcb != NULL);
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
-
- if (Stream) {
-
- Vcb->Volume = NULL;
-
- if (IsFlagOn(Stream->Flags, FO_FILE_MODIFIED)) {
- CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus);
- ClearFlag(Stream->Flags, FO_FILE_MODIFIED);
- }
-
- if (Stream->PrivateCacheMap) {
- Ext2SyncUninitializeCacheMap(Stream);
- }
-
- ObDereferenceObject(Stream);
- }
-}
-
-VOID
-Ext2DestroyVcb (IN PEXT2_VCB Vcb)
-{
- ASSERT(Vcb != NULL);
- ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
- (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
-
- DEBUG(DL_FUN, ("Ext2DestroyVcb ...\n"));
-
- if (Vcb->Volume) {
- Ext2TearDownStream(Vcb);
- }
- ASSERT(NULL == Vcb->Volume);
-
- FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
- Ext2ListExtents(&Vcb->Extents);
- FsRtlUninitializeLargeMcb(&(Vcb->Extents));
-
- Ext2CleanupAllMcbs(Vcb);
-
- Ext2DropBH(Vcb);
-
- if (Vcb->bd.bd_bh_cache)
- kmem_cache_destroy(Vcb->bd.bd_bh_cache);
- ExDeleteResourceLite(&Vcb->bd.bd_bh_lock);
-
- if (Vcb->SuperBlock) {
- Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC);
- Vcb->SuperBlock = NULL;
- }
-
- if (IsFlagOn(Vcb->Flags, VCB_NEW_VPB)) {
- ASSERT(Vcb->Vpb2 != NULL);
- DEBUG(DL_DBG, ("Ext2DestroyVcb: Vpb2 to be freed: %p\n", Vcb->Vpb2));
- ExFreePoolWithTag(Vcb->Vpb2, TAG_VPB);
- DEC_MEM_COUNT(PS_VPB, Vcb->Vpb2, sizeof(VPB));
- Vcb->Vpb2 = NULL;
- }
-
- ObDereferenceObject(Vcb->TargetDeviceObject);
-
- ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
- ExDeleteResourceLite(&Vcb->FcbLock);
- ExDeleteResourceLite(&Vcb->McbLock);
- ExDeleteResourceLite(&Vcb->MetaInode);
- ExDeleteResourceLite(&Vcb->MetaBlock);
- ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
- ExDeleteResourceLite(&Vcb->PagingIoResource);
- ExDeleteResourceLite(&Vcb->MainResource);
-
- DEBUG(DL_DBG, ("Ext2DestroyVcb: DevObject=%p Vcb=%p\n", Vcb->DeviceObject, Vcb));
- IoDeleteDevice(Vcb->DeviceObject);
- DEC_MEM_COUNT(PS_VCB, Vcb->DeviceObject, sizeof(EXT2_VCB));
-}
-
-
-/* uninitialize cache map */
-
-VOID
-Ext2SyncUninitializeCacheMap (
- IN PFILE_OBJECT FileObject
-)
-{
- CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent;
- NTSTATUS WaitStatus;
- LARGE_INTEGER Ext2LargeZero = {0,0};
-
-
- KeInitializeEvent( &UninitializeCompleteEvent.Event,
- SynchronizationEvent,
- FALSE);
-
- CcUninitializeCacheMap( FileObject,
- &Ext2LargeZero,
- &UninitializeCompleteEvent );
-
- WaitStatus = KeWaitForSingleObject( &UninitializeCompleteEvent.Event,
- Executive,
- KernelMode,
- FALSE,
- NULL);
-
- ASSERT (NT_SUCCESS(WaitStatus));
-}
-
-/* Link Mcb to tail of Vcb->McbList queue */
-
-VOID
-Ext2LinkTailMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
-{
- if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
- return;
- }
-
- ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
-
- if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
- DEBUG(DL_RES, ( "Ext2LinkTailMcb: %wZ already linked.\n",
- &Mcb->FullName));
- } else {
- InsertTailList(&Vcb->McbList, &Mcb->Link);
- SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
- Ext2ReferXcb(&Vcb->NumOfMcb);
- }
-
- ExReleaseResourceLite(&Vcb->McbLock);
-}
-
-/* Link Mcb to head of Vcb->McbList queue */
-
-VOID
-Ext2LinkHeadMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
-{
- if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
- return;
- }
-
- ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
-
- if (!IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
- InsertHeadList(&Vcb->McbList, &Mcb->Link);
- SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
- Ext2ReferXcb(&Vcb->NumOfMcb);
- } else {
- DEBUG(DL_RES, ( "Ext2LinkHeadMcb: %wZ already linked.\n",
- &Mcb->FullName));
- }
- ExReleaseResourceLite(&Vcb->McbLock);
-}
-
-/* Unlink Mcb from Vcb->McbList queue */
-
-VOID
-Ext2UnlinkMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
-{
- if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
- return;
- }
-
- ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
-
- if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
- RemoveEntryList(&(Mcb->Link));
- ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
- Ext2DerefXcb(&Vcb->NumOfMcb);
- } else {
- DEBUG(DL_RES, ( "Ext2UnlinkMcb: %wZ already unlinked.\n",
- &Mcb->FullName));
- }
- ExReleaseResourceLite(&Vcb->McbLock);
-}
-
-/* get the first Mcb record in Vcb->McbList */
-
-PEXT2_MCB
-Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number)
-{
- PEXT2_MCB Head = NULL;
- PEXT2_MCB Tail = NULL;
- PEXT2_MCB Mcb = NULL;
- PLIST_ENTRY List = NULL;
- ULONG i = 0;
- LARGE_INTEGER start, now;
-
- if (!ExAcquireResourceExclusiveLite(&Vcb->McbLock, Wait)) {
- return NULL;
- }
-
- KeQuerySystemTime(&start);
-
- while (Number--) {
-
- BOOLEAN Skip = TRUE;
-
- if (IsListEmpty(&Vcb->McbList)) {
- break;
- }
-
- while (i++ < Vcb->NumOfMcb) {
-
- KeQuerySystemTime(&now);
- if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) {
- break;
- }
-
- List = RemoveHeadList(&Vcb->McbList);
- Mcb = CONTAINING_RECORD(List, EXT2_MCB, Link);
- ASSERT(IsFlagOn(Mcb->Flags, MCB_VCB_LINK));
-
- if (Mcb->Fcb == NULL && !IsMcbRoot(Mcb) &&
- Mcb->Refercount == 0 &&
- (Mcb->Child == NULL || IsMcbSymLink(Mcb))) {
-
- Ext2RemoveMcb(Vcb, Mcb);
- ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
- Ext2DerefXcb(&Vcb->NumOfMcb);
-
- /* attach all Mcb into a chain*/
- if (Head) {
- ASSERT(Tail != NULL);
- Tail->Next = Mcb;
- Tail = Mcb;
- } else {
- Head = Tail = Mcb;
- }
- Tail->Next = NULL;
- Skip = FALSE;
-
- } else {
-
- InsertTailList(&Vcb->McbList, &Mcb->Link);
- Mcb = NULL;
- }
- }
-
- if (Skip)
- break;
- }
-
- ExReleaseResourceLite(&Vcb->McbLock);
-
- return Head;
-}
-
-
-/* Reaper thread to release unused Mcb blocks */
-VOID
-Ext2McbReaperThread(
- PVOID Context
-)
-{
- PEXT2_REAPER Reaper = Context;
- PLIST_ENTRY List = NULL;
- LARGE_INTEGER Timeout;
-
- PEXT2_VCB Vcb = NULL;
- PEXT2_MCB Mcb = NULL;
-
- ULONG i, NumOfMcbs;
-
- BOOLEAN GlobalAcquired = FALSE;
-
- BOOLEAN DidNothing = TRUE;
- BOOLEAN LastState = TRUE;
- BOOLEAN WaitLock;
-
- __try {
-
- Reaper->Thread = PsGetCurrentThread();
-
- /* wake up DirverEntry */
- KeSetEvent(&Reaper->Engine, 0, FALSE);
-
- /* now process looping */
- while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
-
- WaitLock = FALSE;
-
- /* calculate how long we need wait */
- if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 128)) {
- Timeout.QuadPart = (LONGLONG)-1000*1000; /* 0.1 second */
- NumOfMcbs = Ext2Global->MaxDepth * 4;
- WaitLock = TRUE;
- } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 32)) {
- Timeout.QuadPart = (LONGLONG)-1000*1000*5; /* 0.5 second */
- NumOfMcbs = Ext2Global->MaxDepth * 2;
- WaitLock = TRUE;
- } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 8)) {
- Timeout.QuadPart = (LONGLONG)-1000*1000*10; /* 1 second */
- NumOfMcbs = Ext2Global->MaxDepth;
- } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 2)) {
- Timeout.QuadPart = (LONGLONG)-2*1000*1000*10; /* 2 second */
- NumOfMcbs = Ext2Global->MaxDepth / 4;
- } else if (Ext2Global->PerfStat.Current.Mcb > (ULONG)Ext2Global->MaxDepth) {
- Timeout.QuadPart = (LONGLONG)-4*1000*1000*10; /* 4 seconds */
- NumOfMcbs = Ext2Global->MaxDepth / 8;
- } else if (DidNothing) {
- Timeout.QuadPart = (LONGLONG)-8*1000*1000*10; /* 8 seconds */
- if (LastState) {
- Timeout.QuadPart *= 2;
- }
- NumOfMcbs = Ext2Global->MaxDepth / 16;
- } else {
- Timeout.QuadPart = (LONGLONG)-5*1000*1000*10; /* 5 seconds */
- if (LastState) {
- Timeout.QuadPart *= 2;
- }
- NumOfMcbs = Ext2Global->MaxDepth / 32;
- }
-
- if (NumOfMcbs == 0)
- NumOfMcbs = 1;
-
- LastState = DidNothing;
-
- /* wait until it is waken or it times out */
- KeWaitForSingleObject(
- &Reaper->Wait,
- Executive,
- KernelMode,
- FALSE,
- &Timeout
- );
-
- if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
- break;
-
- DidNothing = TRUE;
-
- /* acquire global exclusive lock */
- if (!ExAcquireResourceSharedLite(&Ext2Global->Resource, WaitLock)) {
- continue;
- }
- GlobalAcquired = TRUE;
-
- /* search all Vcb to get unused resources freed to system */
- for (List = Ext2Global->VcbList.Flink;
- List != &(Ext2Global->VcbList);
- List = List->Flink ) {
-
- Vcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
-
- Mcb = Ext2FirstUnusedMcb(Vcb, WaitLock, NumOfMcbs);
- while (Mcb) {
- PEXT2_MCB Next = Mcb->Next;
- DEBUG(DL_RES, ( "Ext2ReaperThread: releasing Mcb (%p): %wZ"
- " Total: %xh\n", Mcb, &Mcb->FullName,
- Ext2Global->PerfStat.Current.Mcb));
- Ext2FreeMcb(Vcb, Mcb);
- Mcb = Next;
- LastState = DidNothing = FALSE;
- }
- }
- if (DidNothing) {
- KeClearEvent(&Reaper->Wait);
- }
- if (GlobalAcquired) {
- ExReleaseResourceLite(&Ext2Global->Resource);
- GlobalAcquired = FALSE;
- }
- }
-
- } __finally {
-
- if (GlobalAcquired) {
- ExReleaseResourceLite(&Ext2Global->Resource);
- }
-
- KeSetEvent(&Reaper->Engine, 0, FALSE);
- }
-
- PsTerminateSystemThread(STATUS_SUCCESS);
-}
-
-
-/* get buffer heads from global Vcb BH list */
-
-BOOLEAN
-Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
-{
- struct buffer_head *bh = NULL;
- PLIST_ENTRY next = NULL;
- LARGE_INTEGER start, now;
- BOOLEAN wake = FALSE;
-
- KeQuerySystemTime(&start);
-
- ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
-
- while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
-
- KeQuerySystemTime(&now);
- if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) {
- break;
- }
-
- next = RemoveHeadList(&Vcb->bd.bd_bh_free);
- bh = CONTAINING_RECORD(next, struct buffer_head, b_link);
- if (atomic_read(&bh->b_count)) {
- InitializeListHead(&bh->b_link);
- /* to be inserted by brelse */
- continue;
- }
-
- if ( IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED) ||
- (bh->b_ts_drop.QuadPart + (LONGLONG)10*1000*1000*15) > now.QuadPart ||
- (bh->b_ts_creat.QuadPart + (LONGLONG)10*1000*1000*180) > now.QuadPart) {
- InsertTailList(head, &bh->b_link);
- buffer_head_remove(&Vcb->bd, bh);
- } else {
- InsertHeadList(&Vcb->bd.bd_bh_free, &bh->b_link);
- break;
- }
- }
-
- wake = IsListEmpty(&Vcb->bd.bd_bh_free);
- ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
-
- if (wake)
- KeSetEvent(&Vcb->bd.bd_bh_notify, 0, FALSE);
-
- return IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED);
-}
-
-
-/* Reaper thread to release unused buffer heads */
-VOID
-Ext2bhReaperThread(
- PVOID Context
-)
-{
- PEXT2_REAPER Reaper = Context;
- PEXT2_VCB Vcb = NULL;
- LIST_ENTRY List, *Link;
- LARGE_INTEGER Timeout;
-
- BOOLEAN GlobalAcquired = FALSE;
- BOOLEAN DidNothing = FALSE;
- BOOLEAN NonWait = FALSE;
-
- __try {
-
- Reaper->Thread = PsGetCurrentThread();
-
- /* wake up DirverEntry */
- KeSetEvent(&Reaper->Engine, 0, FALSE);
-
- /* now process looping */
- while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
-
- /* wait until it is waken or it times out */
- if (NonWait) {
- Timeout.QuadPart = (LONGLONG)-10*1000*10;
- NonWait = FALSE;
- } else if (DidNothing) {
- Timeout.QuadPart = Timeout.QuadPart * 2;
- } else {
- Timeout.QuadPart = (LONGLONG)-10*1000*1000*10; /* 10 seconds */
- }
- KeWaitForSingleObject(
- &Reaper->Wait,
- Executive,
- KernelMode,
- FALSE,
- &Timeout
- );
-
- if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
- break;
-
- InitializeListHead(&List);
-
- /* acquire global exclusive lock */
- ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
- GlobalAcquired = TRUE;
- /* search all Vcb to get unused resources freed to system */
- for (Link = Ext2Global->VcbList.Flink;
- Link != &(Ext2Global->VcbList);
- Link = Link->Flink ) {
-
- Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
- NonWait = Ext2QueryUnusedBH(Vcb, &List);
- }
- DidNothing = IsListEmpty(&List);
- if (DidNothing) {
- KeClearEvent(&Reaper->Wait);
- }
- if (GlobalAcquired) {
- ExReleaseResourceLite(&Ext2Global->Resource);
- GlobalAcquired = FALSE;
- }
-
- while (!IsListEmpty(&List)) {
- struct buffer_head *bh;
- Link = RemoveHeadList(&List);
- bh = CONTAINING_RECORD(Link, struct buffer_head, b_link);
- ASSERT(0 == atomic_read(&bh->b_count));
- free_buffer_head(bh);
- }
- }
-
- } __finally {
-
- if (GlobalAcquired) {
- ExReleaseResourceLite(&Ext2Global->Resource);
- }
-
- KeSetEvent(&Reaper->Engine, 0, FALSE);
- }
-
- PsTerminateSystemThread(STATUS_SUCCESS);
-}
-
-/* get unused Fcbs to free */
-
-BOOLEAN
-Ext2QueryUnusedFcb(PEXT2_VCB Vcb, PLIST_ENTRY list)
-{
- PEXT2_FCB Fcb;
- PLIST_ENTRY next = NULL;
- LARGE_INTEGER start, now;
-
- ULONG count = 0;
- ULONG tries = 0;
- BOOLEAN wake = FALSE;
- BOOLEAN retry = TRUE;
-
- KeQuerySystemTime(&start);
-
- ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
-
-again:
-
- KeQuerySystemTime(&now);
- while (!IsListEmpty(&Vcb->FcbList)) {
-
- next = RemoveHeadList(&Vcb->FcbList);
- Fcb = CONTAINING_RECORD(next, EXT2_FCB, Next);
-
- if (Fcb->ReferenceCount > 0) {
- InsertTailList(&Vcb->FcbList, &Fcb->Next);
- break;
- }
-
- retry = FALSE;
-
- if (now.QuadPart < Fcb->TsDrop.QuadPart + 10*1000*1000*120) {
- InsertHeadList(&Vcb->FcbList, &Fcb->Next);
- break;
- }
-
- Ext2UnlinkFcb(Fcb);
- Ext2DerefXcb(&Vcb->FcbCount);
- InsertTailList(list, &Fcb->Next);
- if (++count >= Ext2Global->MaxDepth) {
- break;
- }
- }
-
- if (start.QuadPart + 10*1000*1000 > now.QuadPart) {
- retry = FALSE;
- }
-
- if (retry) {
- if (++tries < (Vcb->FcbCount >> 4) )
- goto again;
- }
-
- ExReleaseResourceLite(&Vcb->FcbLock);
-
- return 0;
-}
-
-/* Reaper thread to release Fcb */
-VOID
-Ext2FcbReaperThread(
- PVOID Context
-)
-{
- PEXT2_REAPER Reaper = Context;
- PEXT2_VCB Vcb = NULL;
- LIST_ENTRY List, *Link;
- LARGE_INTEGER Timeout;
-
- BOOLEAN GlobalAcquired = FALSE;
- BOOLEAN DidNothing = FALSE;
- BOOLEAN NonWait = FALSE;
-
- __try {
-
- Reaper->Thread = PsGetCurrentThread();
-
- /* wake up DirverEntry */
- KeSetEvent(&Reaper->Engine, 0, FALSE);
-
- /* now process looping */
- while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
-
- /* wait until it is waken or it times out */
- if (NonWait) {
- Timeout.QuadPart = (LONGLONG)-10*1000*100;
- NonWait = FALSE;
- } else if (DidNothing) {
- Timeout.QuadPart = Timeout.QuadPart * 2;
- } else {
- Timeout.QuadPart = (LONGLONG)-10*1000*1000*20; /* 20 seconds */
- }
- KeWaitForSingleObject(
- &Reaper->Wait,
- Executive,
- KernelMode,
- FALSE,
- &Timeout
- );
-
- if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
- break;
-
- InitializeListHead(&List);
-
- /* acquire global exclusive lock */
- ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
- GlobalAcquired = TRUE;
- /* search all Vcb to get unused resources freed to system */
- for (Link = Ext2Global->VcbList.Flink;
- Link != &(Ext2Global->VcbList);
- Link = Link->Flink ) {
-
- Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
- NonWait = Ext2QueryUnusedFcb(Vcb, &List);
- }
- DidNothing = IsListEmpty(&List);
- if (DidNothing) {
- KeClearEvent(&Reaper->Wait);
- }
- if (GlobalAcquired) {
- ExReleaseResourceLite(&Ext2Global->Resource);
- GlobalAcquired = FALSE;
- }
-
- while (!IsListEmpty(&List)) {
- PEXT2_FCB Fcb;
- Link = RemoveHeadList(&List);
- Fcb = CONTAINING_RECORD(Link, EXT2_FCB, Next);
- ASSERT(0 == Fcb->ReferenceCount);
- Ext2FreeFcb(Fcb);
- }
- }
-
- } __finally {
-
- if (GlobalAcquired) {
- ExReleaseResourceLite(&Ext2Global->Resource);
- }
-
- KeSetEvent(&Reaper->Engine, 0, FALSE);
- }
-
- PsTerminateSystemThread(STATUS_SUCCESS);
-}
-
-NTSTATUS
-Ext2StartReaper(PEXT2_REAPER Reaper, EXT2_REAPER_RELEASE Free)
-{
- NTSTATUS status = STATUS_SUCCESS;
- OBJECT_ATTRIBUTES oa;
- HANDLE handle = 0;
- LARGE_INTEGER timeout;
-
- Reaper->Free = Free;
-
- /* initialize wait event */
- KeInitializeEvent(
- &Reaper->Wait,
- SynchronizationEvent, FALSE
- );
-
- /* Reaper thread engine event */
- KeInitializeEvent(
- &Reaper->Engine,
- SynchronizationEvent, FALSE
- );
-
- /* initialize oa */
- InitializeObjectAttributes(
- &oa,
- NULL,
- OBJ_CASE_INSENSITIVE |
- OBJ_KERNEL_HANDLE,
- NULL,
- NULL
- );
-
- /* start a new system thread */
- status = PsCreateSystemThread(
- &handle,
- 0,
- &oa,
- NULL,
- NULL,
- Free,
- (PVOID)Reaper
- );
-
- if (NT_SUCCESS(status)) {
- ZwClose(handle);
-
- /* make sure Reaperthread is started */
- timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
- status = KeWaitForSingleObject(
- &Reaper->Engine,
- Executive,
- KernelMode,
- FALSE,
- &timeout
- );
- if (status != STATUS_SUCCESS) {
- status = STATUS_INSUFFICIENT_RESOURCES;
- }
- }
-
- return status;
-}
-
-
-VOID
-Ext2StopReaper(PEXT2_REAPER Reaper)
-{
- LARGE_INTEGER timeout;
-
- Reaper->Flags |= EXT2_REAPER_FLAG_STOP;
- KeSetEvent(&Reaper->Wait, 0, FALSE);
-
- /* make sure Reaperthread is started */
- timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
- KeWaitForSingleObject(
- &Reaper->Engine,
- Executive,
- KernelMode,
- FALSE,
- &timeout);
-}
+/*
+ * COPYRIGHT: See COPYRIGHT.TXT
+ * PROJECT: Ext2 File System Driver for WinNT/2K/XP
+ * FILE: memory.c
+ * PROGRAMMER: Matt Wu
+ * HOMEPAGE: http://www.ext2fsd.com
+ * UPDATE HISTORY:
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include "ext2fs.h"
+
+/* GLOBALS ***************************************************************/
+
+extern PEXT2_GLOBAL Ext2Global;
+
+/* DEFINITIONS *************************************************************/
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, Ext2AllocateInode)
+#pragma alloc_text(PAGE, Ext2DestroyInode)
+#pragma alloc_text(PAGE, Ext2CheckBitmapConsistency)
+#pragma alloc_text(PAGE, Ext2CheckSetBlock)
+#pragma alloc_text(PAGE, Ext2InitializeVcb)
+#pragma alloc_text(PAGE, Ext2TearDownStream)
+#pragma alloc_text(PAGE, Ext2DestroyVcb)
+#pragma alloc_text(PAGE, Ext2SyncUninitializeCacheMap)
+#pragma alloc_text(PAGE, Ext2ReaperThread)
+#pragma alloc_text(PAGE, Ext2StartReaper)
+#pragma alloc_text(PAGE, Ext2StopReaper)
+#endif
+
+PEXT2_IRP_CONTEXT
+Ext2AllocateIrpContext (IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp )
+{
+ PIO_STACK_LOCATION irpSp;
+ PEXT2_IRP_CONTEXT IrpContext;
+
+ ASSERT(DeviceObject != NULL);
+ ASSERT(Irp != NULL);
+
+ irpSp = IoGetCurrentIrpStackLocation(Irp);
+
+ IrpContext = (PEXT2_IRP_CONTEXT) (
+ ExAllocateFromNPagedLookasideList(
+ &(Ext2Global->Ext2IrpContextLookasideList)));
+
+ if (IrpContext == NULL) {
+ return NULL;
+ }
+
+ RtlZeroMemory(IrpContext, sizeof(EXT2_IRP_CONTEXT) );
+
+ IrpContext->Identifier.Type = EXT2ICX;
+ IrpContext->Identifier.Size = sizeof(EXT2_IRP_CONTEXT);
+
+ IrpContext->Irp = Irp;
+ IrpContext->MajorFunction = irpSp->MajorFunction;
+ IrpContext->MinorFunction = irpSp->MinorFunction;
+ IrpContext->DeviceObject = DeviceObject;
+ IrpContext->FileObject = irpSp->FileObject;
+ if (NULL != IrpContext->FileObject) {
+ IrpContext->Fcb = (PEXT2_FCB)IrpContext->FileObject->FsContext;
+ IrpContext->Ccb = (PEXT2_CCB)IrpContext->FileObject->FsContext2;
+ }
+
+ if (IrpContext->FileObject != NULL) {
+ IrpContext->RealDevice = IrpContext->FileObject->DeviceObject;
+ } else if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL) {
+ if (irpSp->Parameters.MountVolume.Vpb) {
+ IrpContext->RealDevice = irpSp->Parameters.MountVolume.Vpb->RealDevice;
+ }
+ }
+
+ if (IsFlagOn(irpSp->Flags, SL_WRITE_THROUGH)) {
+ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
+ }
+
+ if (IsFlagOn(irpSp->Flags, SL_OVERRIDE_VERIFY_VOLUME)) {
+ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_VERIFY_READ);
+ }
+
+ if (IrpContext->MajorFunction == IRP_MJ_CLEANUP ||
+ IrpContext->MajorFunction == IRP_MJ_CLOSE ||
+ IrpContext->MajorFunction == IRP_MJ_SHUTDOWN ||
+ IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
+ IrpContext->MajorFunction == IRP_MJ_PNP ) {
+
+ if (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL ||
+ IrpContext->MajorFunction == IRP_MJ_PNP) {
+ if (IoGetCurrentIrpStackLocation(Irp)->FileObject == NULL ||
+ IoIsOperationSynchronous(Irp)) {
+ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+ }
+ } else {
+ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+ }
+
+ } else if (IoIsOperationSynchronous(Irp)) {
+
+ SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT);
+ }
+
+ IrpContext->IsTopLevel = (IoGetTopLevelIrp() == Irp);
+ IrpContext->ExceptionInProgress = FALSE;
+ INC_IRP_COUNT(IrpContext);
+
+ return IrpContext;
+}
+
+VOID
+Ext2FreeIrpContext (IN PEXT2_IRP_CONTEXT IrpContext)
+{
+ ASSERT(IrpContext != NULL);
+
+ ASSERT((IrpContext->Identifier.Type == EXT2ICX) &&
+ (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT)));
+
+ /* free the IrpContext to NonPagedList */
+ IrpContext->Identifier.Type = 0;
+ IrpContext->Identifier.Size = 0;
+
+ DEC_IRP_COUNT(IrpContext);
+ ExFreeToNPagedLookasideList(&(Ext2Global->Ext2IrpContextLookasideList), IrpContext);
+}
+
+
+PEXT2_FCB
+Ext2AllocateFcb (
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb
+)
+{
+ PEXT2_FCB Fcb;
+
+ ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->FcbLock));
+
+ Fcb = (PEXT2_FCB) ExAllocateFromNPagedLookasideList(
+ &(Ext2Global->Ext2FcbLookasideList));
+
+ if (!Fcb) {
+ return NULL;
+ }
+
+ RtlZeroMemory(Fcb, sizeof(EXT2_FCB));
+ Fcb->Identifier.Type = EXT2FCB;
+ Fcb->Identifier.Size = sizeof(EXT2_FCB);
+
+#ifndef _WIN2K_TARGET_
+ ExInitializeFastMutex(&Fcb->Mutex);
+ FsRtlSetupAdvancedHeader(&Fcb->Header, &Fcb->Mutex);
+#endif
+
+ FsRtlInitializeOplock(&Fcb->Oplock);
+ FsRtlInitializeFileLock (
+ &Fcb->FileLockAnchor,
+ NULL,
+ NULL );
+
+ Fcb->OpenHandleCount = 0;
+ Fcb->ReferenceCount = 0;
+ Fcb->Vcb = Vcb;
+ Fcb->Inode = &Mcb->Inode;
+
+ ASSERT(Mcb->Fcb == NULL);
+ Ext2ReferMcb(Mcb);
+ Fcb->Mcb = Mcb;
+ Mcb->Fcb = Fcb;
+
+ DEBUG(DL_RES, ("Ext2AllocateFcb: Fcb %p created: %wZ.\n",
+ Fcb, &Fcb->Mcb->FullName));
+
+ RtlZeroMemory(&Fcb->Header, sizeof(FSRTL_COMMON_FCB_HEADER));
+ Fcb->Header.NodeTypeCode = (USHORT) EXT2FCB;
+ Fcb->Header.NodeByteSize = sizeof(EXT2_FCB);
+ Fcb->Header.IsFastIoPossible = FastIoIsNotPossible;
+ Fcb->Header.Resource = &(Fcb->MainResource);
+ Fcb->Header.PagingIoResource = &(Fcb->PagingIoResource);
+
+ Fcb->Header.FileSize.QuadPart = Mcb->Inode.i_size;
+ Fcb->Header.ValidDataLength.QuadPart = Mcb->Inode.i_size;
+ Fcb->Header.AllocationSize.QuadPart = CEILING_ALIGNED(ULONGLONG,
+ Fcb->Header.FileSize.QuadPart, (ULONGLONG)Vcb->BlockSize);
+
+ Fcb->SectionObject.DataSectionObject = NULL;
+ Fcb->SectionObject.SharedCacheMap = NULL;
+ Fcb->SectionObject.ImageSectionObject = NULL;
+
+ ExInitializeResourceLite(&(Fcb->MainResource));
+ ExInitializeResourceLite(&(Fcb->PagingIoResource));
+
+ Ext2InsertFcb(Vcb, Fcb);
+
+ INC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
+
+ return Fcb;
+}
+
+VOID
+Ext2UnlinkFcb(IN PEXT2_FCB Fcb)
+{
+ PEXT2_VCB Vcb = Fcb->Vcb;
+ PEXT2_MCB Mcb;
+
+ ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
+ Mcb = Fcb->Mcb;
+
+ DEBUG(DL_INF, ("Ext2FreeFcb: Fcb (%p) to be unlinked: %wZ.\n",
+ Fcb, Mcb ? &Mcb->FullName : NULL));
+
+ if ((Mcb != NULL) &&
+ (Mcb->Identifier.Type == EXT2MCB) &&
+ (Mcb->Identifier.Size == sizeof(EXT2_MCB))) {
+
+ ASSERT (Mcb->Fcb == Fcb);
+ if (IsMcbSpecialFile(Mcb) ||
+ IsFileDeleted(Mcb)) {
+
+ ASSERT(!IsRoot(Fcb));
+ Ext2RemoveMcb(Vcb, Mcb);
+ Mcb->Fcb = NULL;
+
+ Ext2UnlinkMcb(Vcb, Mcb);
+ Ext2DerefMcb(Mcb);
+ Ext2LinkHeadMcb(Vcb, Mcb);
+
+ } else {
+ Mcb->Fcb = NULL;
+ Ext2DerefMcb(Mcb);
+ }
+ Fcb->Mcb = NULL;
+ }
+
+ ExReleaseResourceLite(&Vcb->McbLock);
+}
+
+VOID
+Ext2FreeFcb (IN PEXT2_FCB Fcb)
+{
+ PEXT2_VCB Vcb = Fcb->Vcb;
+
+ __try {
+
+ ASSERT((Fcb != NULL) && (Fcb->Identifier.Type == EXT2FCB) &&
+ (Fcb->Identifier.Size == sizeof(EXT2_FCB)));
+ ASSERT(0 == Fcb->ReferenceCount);
+
+#ifndef _WIN2K_TARGET_
+ FsRtlTeardownPerStreamContexts(&Fcb->Header);
+#endif
+
+ FsRtlUninitializeFileLock(&Fcb->FileLockAnchor);
+ FsRtlUninitializeOplock(&Fcb->Oplock);
+ ExDeleteResourceLite(&Fcb->MainResource);
+ ExDeleteResourceLite(&Fcb->PagingIoResource);
+
+ Fcb->Identifier.Type = 0;
+ Fcb->Identifier.Size = 0;
+
+ ExFreeToNPagedLookasideList(&(Ext2Global->Ext2FcbLookasideList), Fcb);
+ DEC_MEM_COUNT(PS_FCB, Fcb, sizeof(EXT2_FCB));
+
+ if (0 == Ext2DerefXcb(&Vcb->ReferenceCount)) {
+ if (!IsMounted(Vcb) || IsDispending(Vcb)) {
+ Ext2CheckDismount(NULL, Vcb, FALSE);
+ }
+ }
+
+ } __finally {
+ }
+}
+
+VOID
+Ext2ReleaseFcb (IN PEXT2_FCB Fcb)
+{
+ PEXT2_VCB Vcb = Fcb->Vcb;
+ PEXT2_MCB Mcb;
+
+ if (0 != Ext2DerefXcb(&Fcb->ReferenceCount))
+ return;
+
+ ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+ ExAcquireResourceExclusiveLite(&Fcb->MainResource, TRUE);
+
+ Mcb = Fcb->Mcb;
+ RemoveEntryList(&Fcb->Next);
+
+ if (IsFlagOn(Fcb->Flags, FCB_DELETE_PENDING) ||
+ NULL == Mcb || IsFileDeleted(Mcb)) {
+ InsertHeadList(&Vcb->FcbList, &Fcb->Next);
+ Fcb->TsDrop.QuadPart = 0;
+ } else {
+ InsertTailList(&Vcb->FcbList, &Fcb->Next);
+ KeQuerySystemTime(&Fcb->TsDrop);
+ }
+ ExReleaseResourceLite(&Fcb->MainResource);
+ ExReleaseResourceLite(&Vcb->FcbLock);
+
+ if ((Vcb->FcbCount >> 6) > (ULONG)(Ext2Global->MaxDepth)) {
+ KeSetEvent(&Ext2Global->FcbReaper.Wait, 0, FALSE);
+ }
+}
+
+/* Insert Fcb to Vcb->FcbList queue, with Vcb->FcbLock Acquired. */
+
+VOID
+Ext2InsertFcb(PEXT2_VCB Vcb, PEXT2_FCB Fcb)
+{
+ ASSERT(ExIsResourceAcquiredExclusiveLite(&Vcb->FcbLock));
+
+ KeQuerySystemTime(&Fcb->TsDrop);
+ Ext2ReferXcb(&Vcb->FcbCount);
+ Ext2ReferXcb(&Vcb->ReferenceCount);
+ InsertTailList(&Vcb->FcbList, &Fcb->Next);
+}
+
+PEXT2_CCB
+Ext2AllocateCcb (ULONG Flags, PEXT2_MCB SymLink)
+{
+ PEXT2_CCB Ccb;
+
+ Ccb = (PEXT2_CCB) (ExAllocateFromNPagedLookasideList(
+ &(Ext2Global->Ext2CcbLookasideList)));
+ if (!Ccb) {
+ return NULL;
+ }
+
+ DEBUG(DL_RES, ( "ExtAllocateCcb: Ccb created: %ph.\n", Ccb));
+
+ RtlZeroMemory(Ccb, sizeof(EXT2_CCB));
+
+ Ccb->Identifier.Type = EXT2CCB;
+ Ccb->Identifier.Size = sizeof(EXT2_CCB);
+ Ccb->Flags = Flags;
+
+ Ccb->SymLink = SymLink;
+ if (SymLink) {
+ ASSERT(SymLink->Refercount > 0);
+ Ext2ReferMcb(SymLink);
+ DEBUG(DL_INF, ( "ExtAllocateCcb: Ccb SymLink: %wZ.\n",
+ &Ccb->SymLink->FullName));
+ }
+
+ Ccb->DirectorySearchPattern.Length = 0;
+ Ccb->DirectorySearchPattern.MaximumLength = 0;
+ Ccb->DirectorySearchPattern.Buffer = 0;
+
+ INC_MEM_COUNT(PS_CCB, Ccb, sizeof(EXT2_CCB));
+
+ return Ccb;
+}
+
+VOID
+Ext2FreeCcb (IN PEXT2_VCB Vcb, IN PEXT2_CCB Ccb)
+{
+ ASSERT(Ccb != NULL);
+ ASSERT((Ccb->Identifier.Type == EXT2CCB) &&
+ (Ccb->Identifier.Size == sizeof(EXT2_CCB)));
+
+ DEBUG(DL_RES, ( "Ext2FreeCcb: Ccb = %ph.\n", Ccb));
+
+ if (Ccb->SymLink) {
+ DEBUG(DL_INF, ( "Ext2FreeCcb: Ccb SymLink: %wZ.\n",
+ &Ccb->SymLink->FullName));
+ if (IsFileDeleted(Ccb->SymLink->Target)) {
+ Ext2UnlinkMcb(Vcb, Ccb->SymLink);
+ Ext2DerefMcb(Ccb->SymLink);
+ Ext2LinkHeadMcb(Vcb, Ccb->SymLink);
+ } else {
+ Ext2DerefMcb(Ccb->SymLink);
+ }
+ }
+
+ if (Ccb->DirectorySearchPattern.Buffer != NULL) {
+ DEC_MEM_COUNT(PS_DIR_PATTERN, Ccb->DirectorySearchPattern.Buffer,
+ Ccb->DirectorySearchPattern.MaximumLength );
+ Ext2FreePool(Ccb->DirectorySearchPattern.Buffer, EXT2_DIRSP_MAGIC);
+ }
+
+ ExFreeToNPagedLookasideList(&(Ext2Global->Ext2CcbLookasideList), Ccb);
+ DEC_MEM_COUNT(PS_CCB, Ccb, sizeof(EXT2_CCB));
+}
+
+PEXT2_INODE
+Ext2AllocateInode (PEXT2_VCB Vcb)
+{
+ PVOID inode = NULL;
+
+ inode = ExAllocateFromNPagedLookasideList(
+ &(Vcb->InodeLookasideList));
+ if (!inode) {
+ return NULL;
+ }
+
+ RtlZeroMemory(inode, INODE_SIZE);
+
+ DEBUG(DL_INF, ("ExtAllocateInode: Inode created: %ph.\n", inode));
+ INC_MEM_COUNT(PS_EXT2_INODE, inode, INODE_SIZE);
+
+ return inode;
+}
+
+VOID
+Ext2DestroyInode (IN PEXT2_VCB Vcb, IN PEXT2_INODE inode)
+{
+ ASSERT(inode != NULL);
+
+ DEBUG(DL_INF, ("Ext2FreeInode: Inode = %ph.\n", inode));
+
+ ExFreeToNPagedLookasideList(&(Vcb->InodeLookasideList), inode);
+ DEC_MEM_COUNT(PS_EXT2_INODE, inode, INODE_SIZE);
+}
+
+struct dentry * Ext2AllocateEntry()
+{
+ struct dentry *de;
+
+ de = (struct dentry *)ExAllocateFromNPagedLookasideList(
+ &(Ext2Global->Ext2DentryLookasideList));
+ if (!de) {
+ return NULL;
+ }
+
+ RtlZeroMemory(de, sizeof(struct dentry));
+ INC_MEM_COUNT(PS_DENTRY, de, sizeof(struct dentry));
+
+ return de;
+}
+
+VOID Ext2FreeEntry (IN struct dentry *de)
+{
+ ASSERT(de != NULL);
+
+ if (de->d_name.name)
+ ExFreePool(de->d_name.name);
+
+ ExFreeToNPagedLookasideList(&(Ext2Global->Ext2DentryLookasideList), de);
+ DEC_MEM_COUNT(PS_DENTRY, de, sizeof(struct dentry));
+}
+
+
+struct dentry *Ext2BuildEntry(PEXT2_VCB Vcb, PEXT2_MCB Dcb, PUNICODE_STRING FileName)
+{
+ OEM_STRING Oem = { 0 };
+ struct dentry *de = NULL;
+ NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
+
+ __try {
+
+ de = Ext2AllocateEntry();
+ if (!de) {
+ DEBUG(DL_ERR, ("Ext2BuildEntry: failed to allocate dentry.\n"));
+ __leave;
+ }
+ de->d_sb = &Vcb->sb;
+ if (Dcb)
+ de->d_parent = Dcb->de;
+
+ Oem.MaximumLength = (USHORT)Ext2UnicodeToOEMSize(Vcb, FileName) + 1;
+ Oem.Buffer = ExAllocatePool(PagedPool, Oem.MaximumLength);
+ if (!Oem.Buffer) {
+ DEBUG(DL_ERR, ( "Ex2BuildEntry: failed to allocate OEM name.\n"));
+ __leave;
+ }
+ de->d_name.name = Oem.Buffer;
+ RtlZeroMemory(Oem.Buffer, Oem.MaximumLength);
+ Status = Ext2UnicodeToOEM(Vcb, &Oem, FileName);
+ if (!NT_SUCCESS(Status)) {
+ DEBUG(DL_CP, ("Ext2BuildEntry: failed to convert %S to OEM.\n", FileName->Buffer));
+ __leave;
+ }
+ de->d_name.len = Oem.Length;
+
+ } __finally {
+
+ if (!NT_SUCCESS(Status)) {
+ if (de)
+ Ext2FreeEntry(de);
+ }
+ }
+
+ return de;
+}
+
+PEXT2_EXTENT
+Ext2AllocateExtent ()
+{
+ PEXT2_EXTENT Extent;
+
+ Extent = (PEXT2_EXTENT)ExAllocateFromNPagedLookasideList(
+ &(Ext2Global->Ext2ExtLookasideList));
+ if (!Extent) {
+ return NULL;
+ }
+
+ RtlZeroMemory(Extent, sizeof(EXT2_EXTENT));
+ INC_MEM_COUNT(PS_EXTENT, Extent, sizeof(EXT2_EXTENT));
+
+ return Extent;
+}
+
+VOID
+Ext2FreeExtent (IN PEXT2_EXTENT Extent)
+{
+ ASSERT(Extent != NULL);
+ ExFreeToNPagedLookasideList(&(Ext2Global->Ext2ExtLookasideList), Extent);
+ DEC_MEM_COUNT(PS_EXTENT, Extent, sizeof(EXT2_EXTENT));
+}
+
+ULONG
+Ext2CountExtents(IN PEXT2_EXTENT Chain)
+{
+ ULONG count = 0;
+ PEXT2_EXTENT List = Chain;
+
+ while (List) {
+ count += 1;
+ List = List->Next;
+ }
+
+ return count;
+}
+
+VOID
+Ext2JointExtents(
+ IN PEXT2_EXTENT Chain,
+ IN PEXT2_EXTENT Extent
+)
+{
+ ULONG count = 0;
+ PEXT2_EXTENT List = Chain;
+
+ while (List->Next) {
+ List = List->Next;
+ }
+
+ List->Next = Extent;
+}
+
+
+VOID
+Ext2DestroyExtentChain(IN PEXT2_EXTENT Chain)
+{
+ PEXT2_EXTENT Extent = NULL, List = Chain;
+
+ while (List) {
+ Extent = List->Next;
+ Ext2FreeExtent(List);
+ List = Extent;
+ }
+}
+
+BOOLEAN
+Ext2ListExtents(PLARGE_MCB Extents)
+{
+ if (FsRtlNumberOfRunsInLargeMcb(Extents) != 0) {
+
+ LONGLONG DirtyVba;
+ LONGLONG DirtyLba;
+ LONGLONG DirtyLength;
+ int i, n = 0;
+
+ for (i = 0; FsRtlGetNextLargeMcbEntry(
+ Extents, i, &DirtyVba,
+ &DirtyLba, &DirtyLength); i++) {
+ if (DirtyVba > 0 && DirtyLba != -1) {
+ DEBUG(DL_EXT, ("Vba:%I64xh Lba:%I64xh Len:%I64xh.\n", DirtyVba, DirtyLba, DirtyLength));
+ n++;
+ }
+ }
+
+ return n ? TRUE : FALSE;
+ }
+
+ return FALSE;
+}
+
+VOID
+Ext2CheckExtent(
+ PLARGE_MCB Zone,
+ LONGLONG Vbn,
+ LONGLONG Lbn,
+ LONGLONG Length,
+ BOOLEAN bAdded
+)
+{
+#if EXT2_DEBUG
+ LONGLONG DirtyLbn;
+ LONGLONG DirtyLen;
+ LONGLONG RunStart;
+ LONGLONG RunLength;
+ ULONG Index;
+ BOOLEAN bFound = FALSE;
+
+ bFound = FsRtlLookupLargeMcbEntry(
+ Zone,
+ Vbn,
+ &DirtyLbn,
+ &DirtyLen,
+ &RunStart,
+ &RunLength,
+ &Index );
+
+ if (!bAdded && (!bFound || DirtyLbn == -1)) {
+ return;
+ }
+
+ if ( !bFound || (DirtyLbn == -1) ||
+ (DirtyLbn != Lbn) ||
+ (DirtyLen < Length)) {
+
+ DbgBreak();
+
+ for (Index = 0; TRUE; Index++) {
+
+ if (!FsRtlGetNextLargeMcbEntry(
+ Zone,
+ Index,
+ &Vbn,
+ &Lbn,
+ &Length)) {
+ break;
+ }
+
+ DEBUG(DL_EXT, ("Index = %xh Vbn = %I64xh Lbn = %I64xh Len = %I64xh\n",
+ Index, Vbn, Lbn, Length ));
+ }
+ }
+#endif
+}
+
+VOID
+Ext2ClearAllExtents(PLARGE_MCB Zone)
+{
+ __try {
+ FsRtlTruncateLargeMcb(Zone, (LONGLONG)0);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ DbgBreak();
+ }
+}
+
+
+BOOLEAN
+Ext2AddVcbExtent (
+ IN PEXT2_VCB Vcb,
+ IN LONGLONG Vbn,
+ IN LONGLONG Length
+)
+{
+ ULONG TriedTimes = 0;
+
+ LONGLONG Offset = 0;
+ BOOLEAN rc = FALSE;
+
+ Offset = Vbn & (~(Vcb->IoUnitSize - 1));
+ Length = (Vbn - Offset + Length + Vcb->IoUnitSize - 1) &
+ ~(Vcb->IoUnitSize - 1);
+
+ ASSERT ((Offset & (Vcb->IoUnitSize - 1)) == 0);
+ ASSERT ((Length & (Vcb->IoUnitSize - 1)) == 0);
+
+ Offset = (Offset >> Vcb->IoUnitBits) + 1;
+ Length = (Length >> Vcb->IoUnitBits);
+
+Again:
+
+ __try {
+ rc = FsRtlAddLargeMcbEntry(
+ &Vcb->Extents,
+ Offset,
+ Offset,
+ Length
+ );
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ DbgBreak();
+ rc = FALSE;
+ }
+
+ if (!rc && ++TriedTimes < 10) {
+ Ext2Sleep(TriedTimes * 100);
+ goto Again;
+ }
+
+ DEBUG(DL_EXT, ("Ext2AddVcbExtent: Vbn=%I64xh Length=%I64xh,"
+ " rc=%d Runs=%u\n", Offset, Length, rc,
+ FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
+
+ if (rc) {
+ Ext2CheckExtent(&Vcb->Extents, Offset, Offset, Length, TRUE);
+ }
+
+ return rc;
+}
+
+BOOLEAN
+Ext2RemoveVcbExtent (
+ IN PEXT2_VCB Vcb,
+ IN LONGLONG Vbn,
+ IN LONGLONG Length
+)
+{
+ ULONG TriedTimes = 0;
+ LONGLONG Offset = 0;
+ BOOLEAN rc = TRUE;
+
+ Offset = Vbn & (~(Vcb->IoUnitSize - 1));
+ Length = (Length + Vbn - Offset + Vcb->IoUnitSize - 1) & (~(Vcb->IoUnitSize - 1));
+
+ ASSERT ((Offset & (Vcb->IoUnitSize - 1)) == 0);
+ ASSERT ((Length & (Vcb->IoUnitSize - 1)) == 0);
+
+ Offset = (Offset >> Vcb->IoUnitBits) + 1;
+ Length = (Length >> Vcb->IoUnitBits);
+
+Again:
+
+ __try {
+ FsRtlRemoveLargeMcbEntry(
+ &Vcb->Extents,
+ Offset,
+ Length
+ );
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ DbgBreak();
+ rc = FALSE;
+ }
+
+ if (!rc && ++TriedTimes < 10) {
+ Ext2Sleep(TriedTimes * 100);
+ goto Again;
+ }
+
+ DEBUG(DL_EXT, ("Ext2RemoveVcbExtent: Vbn=%I64xh Length=%I64xh Runs=%u\n",
+ Offset, Length, FsRtlNumberOfRunsInLargeMcb(&Vcb->Extents)));
+ if (rc) {
+ Ext2CheckExtent(&Vcb->Extents, Offset, 0, Length, FALSE);
+ }
+
+ return rc;
+}
+
+BOOLEAN
+Ext2LookupVcbExtent (
+ IN PEXT2_VCB Vcb,
+ IN LONGLONG Vbn,
+ OUT PLONGLONG Lbn,
+ OUT PLONGLONG Length
+)
+{
+ LONGLONG offset;
+ BOOLEAN rc;
+
+ offset = Vbn & (~(Vcb->IoUnitSize - 1));
+ ASSERT ((offset & (Vcb->IoUnitSize - 1)) == 0);
+ offset = (offset >> Vcb->IoUnitBits) + 1;
+
+ rc = FsRtlLookupLargeMcbEntry(
+ &(Vcb->Extents),
+ offset,
+ Lbn,
+ Length,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (rc) {
+
+ if (Lbn && ((*Lbn) != -1)) {
+ ASSERT((*Lbn) > 0);
+ (*Lbn) = (((*Lbn) - 1) << Vcb->IoUnitBits);
+ (*Lbn) += ((Vbn) & (Vcb->IoUnitSize - 1));
+ }
+
+ if (Length && *Length) {
+ (*Length) <<= Vcb->IoUnitBits;
+ (*Length) -= ((Vbn) & (Vcb->IoUnitSize - 1));
+ }
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Ext2AddMcbExtent (
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN LONGLONG Vbn,
+ IN LONGLONG Lbn,
+ IN LONGLONG Length
+)
+{
+ ULONG TriedTimes = 0;
+ LONGLONG Base = 0;
+ UCHAR Bits = 0;
+ BOOLEAN rc = FALSE;
+
+ Base = (LONGLONG)BLOCK_SIZE;
+ Bits = (UCHAR)BLOCK_BITS;
+
+ ASSERT ((Vbn & (Base - 1)) == 0);
+ ASSERT ((Lbn & (Base - 1)) == 0);
+ ASSERT ((Length & (Base - 1)) == 0);
+
+ Vbn = (Vbn >> Bits) + 1;
+ Lbn = (Lbn >> Bits) + 1;
+ Length = (Length >> Bits);
+
+Again:
+
+ __try {
+
+ rc = FsRtlAddLargeMcbEntry(
+ &Mcb->Extents,
+ Vbn,
+ Lbn,
+ Length
+ );
+
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgBreak();
+ rc = FALSE;
+ }
+
+ if (!rc && ++TriedTimes < 10) {
+ Ext2Sleep(TriedTimes * 100);
+ goto Again;
+ }
+
+ DEBUG(DL_EXT, ("Ext2AddMcbExtent: Vbn=%I64xh Lbn=%I64xh Length=%I64xh,"
+ " rc=%d Runs=%u\n", Vbn, Lbn, Length, rc,
+ FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)));
+
+ if (rc) {
+ Ext2CheckExtent(&Mcb->Extents, Vbn, Lbn, Length, TRUE);
+ }
+
+ return rc;
+}
+
+BOOLEAN
+Ext2RemoveMcbExtent (
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN LONGLONG Vbn,
+ IN LONGLONG Length
+)
+{
+ ULONG TriedTimes = 0;
+ LONGLONG Base = 0;
+ UCHAR Bits = 0;
+ BOOLEAN rc = TRUE;
+
+ Base = (LONGLONG)BLOCK_SIZE;
+ Bits = (UCHAR)BLOCK_BITS;
+
+ ASSERT ((Vbn & (Base - 1)) == 0);
+ ASSERT ((Length & (Base - 1)) == 0);
+
+ Vbn = (Vbn >> Bits) + 1;
+ Length = (Length >> Bits);
+
+Again:
+
+ __try {
+ FsRtlRemoveLargeMcbEntry(
+ &Mcb->Extents,
+ Vbn,
+ Length
+ );
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ DbgBreak();
+ rc = FALSE;
+ }
+
+ if (!rc && ++TriedTimes < 10) {
+ Ext2Sleep(TriedTimes * 100);
+ goto Again;
+ }
+
+ DEBUG(DL_EXT, ("Ext2RemoveMcbExtent: Vbn=%I64xh Length=%I64xh Runs=%u\n",
+ Vbn, Length, FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)));
+ if (rc) {
+ Ext2CheckExtent(&Mcb->Extents, Vbn, 0, Length, FALSE);
+ }
+
+ return rc;
+}
+
+BOOLEAN
+Ext2LookupMcbExtent (
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN LONGLONG Vbn,
+ OUT PLONGLONG Lbn,
+ OUT PLONGLONG Length
+)
+{
+ LONGLONG offset;
+ BOOLEAN rc;
+
+ offset = Vbn & (~((LONGLONG)BLOCK_SIZE - 1));
+ ASSERT ((offset & (BLOCK_SIZE - 1)) == 0);
+ offset = (offset >> BLOCK_BITS) + 1;
+
+ rc = FsRtlLookupLargeMcbEntry(
+ &(Mcb->Extents),
+ offset,
+ Lbn,
+ Length,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (rc) {
+
+ if (Lbn && ((*Lbn) != -1)) {
+ ASSERT((*Lbn) > 0);
+ (*Lbn) = (((*Lbn) - 1) << BLOCK_BITS);
+ (*Lbn) += ((Vbn) & ((LONGLONG)BLOCK_SIZE - 1));
+ }
+
+ if (Length && *Length) {
+ (*Length) <<= BLOCK_BITS;
+ (*Length) -= ((Vbn) & ((LONGLONG)BLOCK_SIZE - 1));
+ }
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Ext2AddMcbMetaExts (
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN ULONG Block,
+ IN ULONG Length
+)
+{
+ ULONG TriedTimes = 0;
+ LONGLONG Lbn = Block + 1;
+ BOOLEAN rc = TRUE;
+
+Again:
+
+ __try {
+
+ rc = FsRtlAddLargeMcbEntry(
+ &Mcb->MetaExts,
+ Lbn,
+ Lbn,
+ Length
+ );
+
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+
+ DbgBreak();
+ rc = FALSE;
+ }
+
+ if (!rc && ++TriedTimes < 10) {
+ Ext2Sleep(TriedTimes * 100);
+ goto Again;
+ }
+
+ DEBUG(DL_EXT, ("Ext2AddMcbMetaExts: Block: %xh-%xh rc=%d Runs=%u\n", Block,
+ Length, rc, FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)));
+
+ if (rc) {
+ Ext2CheckExtent(&Mcb->MetaExts, Lbn, Lbn, Length, TRUE);
+ }
+
+ return rc;
+}
+
+BOOLEAN
+Ext2RemoveMcbMetaExts (
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN ULONG Block,
+ IN ULONG Length
+)
+{
+ ULONG TriedTimes = 0;
+ LONGLONG Lbn = Block + 1;
+ BOOLEAN rc = TRUE;
+
+Again:
+
+ __try {
+
+ FsRtlRemoveLargeMcbEntry(
+ &Mcb->MetaExts,
+ Lbn,
+ Length
+ );
+
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ DbgBreak();
+ rc = FALSE;
+ }
+
+ if (!rc && ++TriedTimes < 10) {
+ Ext2Sleep(TriedTimes * 100);
+ goto Again;
+ }
+
+ DEBUG(DL_EXT, ("Ext2RemoveMcbMetaExts: Block: %xh-%xhh Runs=%u\n", Block,
+ Length, FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)));
+ if (rc) {
+ Ext2CheckExtent(&Mcb->MetaExts, Lbn, 0, Length, FALSE);
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Ext2AddBlockExtent(
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN ULONG Start,
+ IN ULONG Block,
+ IN ULONG Number
+)
+{
+ LONGLONG Vbn = 0;
+ LONGLONG Lbn = 0;
+ LONGLONG Length = 0;
+
+ Vbn = ((LONGLONG) Start) << BLOCK_BITS;
+ Lbn = ((LONGLONG) Block) << BLOCK_BITS;
+ Length = ((LONGLONG)Number << BLOCK_BITS);
+
+ if (Mcb) {
+#if EXT2_DEBUG
+ ULONG _block = 0, _mapped = 0;
+ BOOLEAN _rc = Ext2LookupBlockExtent(Vcb, Mcb, Start, &_block, &_mapped);
+ if (_rc && _block != 0 && (_block != Block)) {
+ DbgBreak();
+ }
+#endif
+ return Ext2AddMcbExtent(Vcb, Mcb, Vbn, Lbn, Length);
+
+ }
+
+ ASSERT(Start == Block);
+ return Ext2AddVcbExtent(Vcb, Vbn, Length);
+}
+
+
+BOOLEAN
+Ext2LookupBlockExtent(
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN ULONG Start,
+ IN PULONG Block,
+ IN PULONG Mapped
+)
+{
+ LONGLONG Vbn = 0;
+ LONGLONG Lbn = 0;
+ LONGLONG Length = 0;
+
+ BOOLEAN rc = FALSE;
+
+ Vbn = ((LONGLONG) Start) << BLOCK_BITS;
+
+ if (Mcb) {
+ rc = Ext2LookupMcbExtent(Vcb, Mcb, Vbn, &Lbn, &Length);
+ } else {
+ rc = Ext2LookupVcbExtent(Vcb, Vbn, &Lbn, &Length);
+ }
+
+ if (rc) {
+ *Mapped = (ULONG)(Length >> BLOCK_BITS);
+ if (Lbn != -1 && Length > 0) {
+ *Block = (ULONG)(Lbn >> BLOCK_BITS);
+ } else {
+ *Block = 0;
+ }
+ }
+
+ return rc;
+}
+
+
+BOOLEAN
+Ext2RemoveBlockExtent(
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN ULONG Start,
+ IN ULONG Number
+)
+{
+ LONGLONG Vbn = 0;
+ LONGLONG Length = 0;
+ BOOLEAN rc;
+
+ Vbn = ((LONGLONG) Start) << BLOCK_BITS;
+ Length = ((LONGLONG)Number << BLOCK_BITS);
+
+ if (Mcb) {
+ rc = Ext2RemoveMcbExtent(Vcb, Mcb, Vbn, Length);
+ } else {
+ rc = Ext2RemoveVcbExtent(Vcb, Vbn, Length);
+ }
+
+ return rc;
+}
+
+NTSTATUS
+Ext2InitializeZone(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb
+)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ ULONG Start = 0;
+ ULONG End;
+ ULONG Block;
+ ULONG Mapped;
+
+ Ext2ClearAllExtents(&Mcb->Extents);
+ Ext2ClearAllExtents(&Mcb->MetaExts);
+
+ ASSERT(Mcb != NULL);
+ End = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS);
+
+ while (Start < End) {
+
+ Block = Mapped = 0;
+
+ /* mapping file offset to ext2 block */
+ if (INODE_HAS_EXTENT(&Mcb->Inode)) {
+ Status = Ext2MapExtent(
+ IrpContext,
+ Vcb,
+ Mcb,
+ Start,
+ FALSE,
+ &Block,
+ &Mapped
+ );
+ } else {
+ Status = Ext2MapIndirect(
+ IrpContext,
+ Vcb,
+ Mcb,
+ Start,
+ FALSE,
+ &Block,
+ &Mapped
+ );
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ goto errorout;
+ }
+
+ /* skip wrong blocks, in case wrongly treating symlink
+ target names as blocks, silly */
+ if (Block >= TOTAL_BLOCKS) {
+ Block = 0;
+ }
+
+ if (Block) {
+ if (!Ext2AddBlockExtent(Vcb, Mcb, Start, Block, Mapped)) {
+ DbgBreak();
+ ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
+ Ext2ClearAllExtents(&Mcb->Extents);
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+ DEBUG(DL_MAP, ("Ext2InitializeZone %wZ: Block = %xh Mapped = %xh\n",
+ &Mcb->FullName, Block, Mapped));
+ }
+
+ /* Mapped is total number of continous blocks or NULL blocks */
+ Start += Mapped;
+ }
+
+ /* set mcb zone as initialized */
+ SetLongFlag(Mcb->Flags, MCB_ZONE_INITED);
+
+errorout:
+
+ if (!IsZoneInited(Mcb)) {
+ Ext2ClearAllExtents(&Mcb->Extents);
+ Ext2ClearAllExtents(&Mcb->MetaExts);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2BuildExtents(
+ IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_MCB Mcb,
+ IN ULONGLONG Offset,
+ IN ULONG Size,
+ IN BOOLEAN bAlloc,
+ OUT PEXT2_EXTENT * Chain
+)
+{
+ ULONG Start, End;
+ ULONG Total = 0;
+
+ LONGLONG Lba = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ PEXT2_EXTENT Extent = NULL;
+ PEXT2_EXTENT List = *Chain = NULL;
+
+ if (!IsZoneInited(Mcb)) {
+ Status = Ext2InitializeZone(IrpContext, Vcb, Mcb);
+ if (!NT_SUCCESS(Status)) {
+ DbgBreak();
+ }
+ }
+
+ if ((IrpContext && IrpContext->Irp) &&
+ ((IrpContext->Irp->Flags & IRP_NOCACHE) ||
+ (IrpContext->Irp->Flags & IRP_PAGING_IO))) {
+ Size = (Size + SECTOR_SIZE - 1) & (~(SECTOR_SIZE - 1));
+ }
+
+ Start = (ULONG)(Offset >> BLOCK_BITS);
+ End = (ULONG)((Size + Offset + BLOCK_SIZE - 1) >> BLOCK_BITS);
+
+ if (End > (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS) ) {
+ End = (ULONG)((Mcb->Inode.i_size + BLOCK_SIZE - 1) >> BLOCK_BITS);
+ }
+
+ while (Size > 0 && Start < End) {
+
+ ULONG Mapped = 0;
+ ULONG Length = 0;
+ ULONG Block = 0;
+
+ BOOLEAN rc = FALSE;
+
+ /* try to map file offset to ext2 block upon Extents cache */
+ if (IsZoneInited(Mcb)) {
+ rc = Ext2LookupBlockExtent(
+ Vcb,
+ Mcb,
+ Start,
+ &Block,
+ &Mapped);
+
+ if (!rc) {
+ /* we likely get a sparse file here */
+ Mapped = 1;
+ Block = 0;
+ }
+ }
+
+ /* try to BlockMap in case failed to access Extents cache */
+ if (!IsZoneInited(Mcb) || (bAlloc && Block == 0)) {
+
+ Status = Ext2BlockMap(
+ IrpContext,
+ Vcb,
+ Mcb,
+ Start,
+ bAlloc,
+ &Block,
+ &Mapped
+ );
+ if (!NT_SUCCESS(Status)) {
+ break;
+ }
+
+ /* skip wrong blocks, in case wrongly treating symlink
+ target names as blocks, silly */
+ if (Block >= TOTAL_BLOCKS) {
+ Block = 0;
+ }
+
+ /* add new allocated blocks to Mcb zone */
+ if (IsZoneInited(Mcb) && Block) {
+ if (!Ext2AddBlockExtent(Vcb, Mcb, Start, Block, Mapped)) {
+ DbgBreak();
+ ClearFlag(Mcb->Flags, MCB_ZONE_INITED);
+ Ext2ClearAllExtents(&Mcb->Extents);
+ }
+ }
+ }
+
+ /* calculate i/o extent */
+ Lba = ((LONGLONG)Block << BLOCK_BITS) + Offset - ((LONGLONG)Start << BLOCK_BITS);
+ Length = (ULONG)(((LONGLONG)(Start + Mapped) << BLOCK_BITS) - Offset);
+ if (Length > Size) {
+ Length = Size;
+ }
+
+ if (0 == Length) {
+ DbgBreak();
+ break;
+ }
+
+ Start += Mapped;
+ Offset = (ULONGLONG)Start << BLOCK_BITS;
+
+ if (Block != 0) {
+
+ if (List && List->Lba + List->Length == Lba) {
+
+ /* it's continuous upon previous Extent */
+ List->Length += Length;
+
+ } else {
+
+ /* have to allocate a new Extent */
+ Extent = Ext2AllocateExtent();
+ if (!Extent) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ DbgBreak();
+ break;
+ }
+
+ Extent->Lba = Lba;
+ Extent->Length = Length;
+ Extent->Offset = Total;
+
+ /* insert new Extent to chain */
+ if (List) {
+ List->Next = Extent;
+ List = Extent;
+ } else {
+ *Chain = List = Extent;
+ }
+ }
+ } else {
+ if (bAlloc) {
+ DbgBreak();
+ }
+ }
+
+ Total += Length;
+ Size -= Length;
+ }
+
+ return Status;
+}
+
+
+BOOLEAN
+Ext2BuildName(
+ IN OUT PUNICODE_STRING Target,
+ IN PUNICODE_STRING File,
+ IN PUNICODE_STRING Parent
+)
+{
+ USHORT Length = 0;
+ USHORT ParentLen = 0;
+ BOOLEAN bBackslash = TRUE;
+
+ /* free the original buffer */
+ if (Target->Buffer) {
+ DEC_MEM_COUNT(PS_MCB_NAME, Target->Buffer, Target->MaximumLength);
+ Ext2FreePool(Target->Buffer, EXT2_FNAME_MAGIC);
+ Target->Length = Target->MaximumLength = 0;
+ }
+
+ /* check the parent directory's name and backslash */
+ if (Parent && Parent->Buffer && Parent->Length > 0) {
+ ParentLen = Parent->Length / sizeof(WCHAR);
+ if (Parent->Buffer[ParentLen - 1] == L'\\') {
+ bBackslash = FALSE;
+ }
+ }
+
+ if (Parent == NULL || File->Buffer[0] == L'\\') {
+ /* must be root inode */
+ ASSERT(ParentLen == 0);
+ bBackslash = FALSE;
+ }
+
+ /* allocate and initialize new name buffer */
+ Length = File->Length;
+ Length += (ParentLen + (bBackslash ? 1 : 0)) * sizeof(WCHAR);
+
+ Target->Buffer = Ext2AllocatePool(
+ PagedPool,
+ Length + 2,
+ EXT2_FNAME_MAGIC
+ );
+
+ if (!Target->Buffer) {
+ DEBUG(DL_ERR, ( "Ex2BuildName: failed to allocate name bufer.\n"));
+ return FALSE;
+ }
+ RtlZeroMemory(Target->Buffer, Length + 2);
+
+ if (ParentLen) {
+ RtlCopyMemory(&Target->Buffer[0],
+ Parent->Buffer,
+ ParentLen * sizeof(WCHAR));
+ }
+
+ if (bBackslash) {
+ Target->Buffer[ParentLen++] = L'\\';
+ }
+
+ RtlCopyMemory( &Target->Buffer[ParentLen],
+ File->Buffer,
+ File->Length);
+
+ INC_MEM_COUNT(PS_MCB_NAME, Target->Buffer, Length + 2);
+ Target->Length = Length;
+ Target->MaximumLength = Length + 2;
+
+ return TRUE;
+}
+
+PEXT2_MCB
+Ext2AllocateMcb (
+ IN PEXT2_VCB Vcb,
+ IN PUNICODE_STRING FileName,
+ IN PUNICODE_STRING Parent,
+ IN ULONG FileAttr
+)
+{
+ PEXT2_MCB Mcb = NULL;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ /* need wake the reaper thread if there are many Mcb allocated */
+ if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 4)) {
+ KeSetEvent(&Ext2Global->McbReaper.Wait, 0, FALSE);
+ }
+
+ /* allocate Mcb from LookasideList */
+ Mcb = (PEXT2_MCB) (ExAllocateFromNPagedLookasideList(
+ &(Ext2Global->Ext2McbLookasideList)));
+
+ if (Mcb == NULL) {
+ return NULL;
+ }
+
+ /* initialize Mcb header */
+ RtlZeroMemory(Mcb, sizeof(EXT2_MCB));
+ Mcb->Identifier.Type = EXT2MCB;
+ Mcb->Identifier.Size = sizeof(EXT2_MCB);
+ Mcb->FileAttr = FileAttr;
+
+ Mcb->Inode.i_priv = (PVOID)Mcb;
+ Mcb->Inode.i_sb = &Vcb->sb;
+
+ /* initialize Mcb names */
+ if (FileName) {
+
+#if EXT2_DEBUG
+ if ( FileName->Length == 2 &&
+ FileName->Buffer[0] == L'\\') {
+ DEBUG(DL_RES, ( "Ext2AllocateMcb: Root Mcb is to be created !\n"));
+ }
+
+ if ( FileName->Length == 2 &&
+ FileName->Buffer[0] == L'.') {
+ DbgBreak();
+ }
+
+ if ( FileName->Length == 4 &&
+ FileName->Buffer[0] == L'.' &&
+ FileName->Buffer[1] == L'.' ) {
+ DbgBreak();
+ }
+#endif
+
+ if (( FileName->Length >= 4 && FileName->Buffer[0] == L'.') &&
+ ((FileName->Length == 4 && FileName->Buffer[1] != L'.') ||
+ FileName->Length >= 6 )) {
+ SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_HIDDEN);
+ }
+
+ if (!Ext2BuildName(&Mcb->ShortName, FileName, NULL)) {
+ goto errorout;
+ }
+ if (!Ext2BuildName(&Mcb->FullName, FileName, Parent)) {
+ goto errorout;
+ }
+ }
+
+ /* initialize Mcb Extents, it will raise an expcetion if failed */
+ __try {
+ FsRtlInitializeLargeMcb(&(Mcb->Extents), NonPagedPool);
+ FsRtlInitializeLargeMcb(&(Mcb->MetaExts), NonPagedPool);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ DbgBreak();
+ }
+
+ if (!NT_SUCCESS(Status)) {
+ goto errorout;
+ }
+
+ INC_MEM_COUNT(PS_MCB, Mcb, sizeof(EXT2_MCB));
+ DEBUG(DL_INF, ( "Ext2AllocateMcb: Mcb %wZ created.\n", &Mcb->FullName));
+
+ return Mcb;
+
+errorout:
+
+ if (Mcb) {
+
+ if (Mcb->ShortName.Buffer) {
+ DEC_MEM_COUNT(PS_MCB_NAME, Mcb->ShortName.Buffer,
+ Mcb->ShortName.MaximumLength);
+ Ext2FreePool(Mcb->ShortName.Buffer, EXT2_FNAME_MAGIC);
+ }
+
+ if (Mcb->FullName.Buffer) {
+ DEC_MEM_COUNT(PS_MCB_NAME, Mcb->FullName.Buffer,
+ Mcb->FullName.MaximumLength);
+ Ext2FreePool(Mcb->FullName.Buffer, EXT2_FNAME_MAGIC);
+ }
+
+ ExFreeToNPagedLookasideList(&(Ext2Global->Ext2McbLookasideList), Mcb);
+ }
+
+ return NULL;
+}
+
+VOID
+Ext2FreeMcb (IN PEXT2_VCB Vcb, IN PEXT2_MCB Mcb)
+{
+ PEXT2_MCB Parent = Mcb->Parent;
+
+ ASSERT(Mcb != NULL);
+
+ ASSERT((Mcb->Identifier.Type == EXT2MCB) &&
+ (Mcb->Identifier.Size == sizeof(EXT2_MCB)));
+
+ if ((Mcb->Identifier.Type != EXT2MCB) ||
+ (Mcb->Identifier.Size != sizeof(EXT2_MCB))) {
+ return;
+ }
+
+ DEBUG(DL_INF, ( "Ext2FreeMcb: Mcb %wZ will be freed.\n", &Mcb->FullName));
+
+ if (IsMcbSymLink(Mcb) && Mcb->Target) {
+ Ext2DerefMcb(Mcb->Target);
+ }
+
+ if (FsRtlNumberOfRunsInLargeMcb(&Mcb->Extents)) {
+ DEBUG(DL_EXT, ("List data extents for: %wZ\n", &Mcb->FullName));
+ Ext2ListExtents(&Mcb->Extents);
+ }
+ FsRtlUninitializeLargeMcb(&(Mcb->Extents));
+ if (FsRtlNumberOfRunsInLargeMcb(&Mcb->MetaExts)) {
+ DEBUG(DL_EXT, ("List meta extents for: %wZ\n", &Mcb->FullName));
+ Ext2ListExtents(&Mcb->MetaExts);
+ }
+ FsRtlUninitializeLargeMcb(&(Mcb->MetaExts));
+ ClearLongFlag(Mcb->Flags, MCB_ZONE_INITED);
+
+ if (Mcb->ShortName.Buffer) {
+ DEC_MEM_COUNT(PS_MCB_NAME, Mcb->ShortName.Buffer,
+ Mcb->ShortName.MaximumLength);
+ Ext2FreePool(Mcb->ShortName.Buffer, EXT2_FNAME_MAGIC);
+ }
+
+ if (Mcb->FullName.Buffer) {
+ DEC_MEM_COUNT(PS_MCB_NAME, Mcb->FullName.Buffer,
+ Mcb->FullName.MaximumLength);
+ Ext2FreePool(Mcb->FullName.Buffer, EXT2_FNAME_MAGIC);
+ }
+
+ /* free dentry */
+ if (Mcb->de) {
+ Ext2FreeEntry(Mcb->de);
+ }
+
+ Mcb->Identifier.Type = 0;
+ Mcb->Identifier.Size = 0;
+
+ ExFreeToNPagedLookasideList(&(Ext2Global->Ext2McbLookasideList), Mcb);
+ DEC_MEM_COUNT(PS_MCB, Mcb, sizeof(EXT2_MCB));
+}
+
+
+PEXT2_MCB
+Ext2SearchMcb(
+ PEXT2_VCB Vcb,
+ PEXT2_MCB Parent,
+ PUNICODE_STRING FileName
+)
+{
+ BOOLEAN LockAcquired = FALSE;
+ PEXT2_MCB Mcb = NULL;
+
+ __try {
+ ExAcquireResourceSharedLite(&Vcb->McbLock, TRUE);
+ LockAcquired = TRUE;
+ Mcb = Ext2SearchMcbWithoutLock(Parent, FileName);
+ } __finally {
+ if (LockAcquired) {
+ ExReleaseResourceLite(&Vcb->McbLock);
+ }
+ }
+
+ return Mcb;
+}
+
+
+PEXT2_MCB
+Ext2SearchMcbWithoutLock(
+ PEXT2_MCB Parent,
+ PUNICODE_STRING FileName
+)
+{
+ PEXT2_MCB TmpMcb = NULL;
+
+ DEBUG(DL_RES, ("Ext2SearchMcb: %wZ\n", FileName));
+
+ __try {
+
+ Ext2ReferMcb(Parent);
+
+ if (Ext2IsDot(FileName)) {
+ TmpMcb = Parent;
+ Ext2ReferMcb(Parent);
+ __leave;
+ }
+
+ if (Ext2IsDotDot(FileName)) {
+ if (IsMcbRoot(Parent)) {
+ TmpMcb = Parent;
+ } else {
+ TmpMcb = Parent->Parent;
+ }
+ if (TmpMcb) {
+ Ext2ReferMcb(TmpMcb);
+ }
+ __leave;
+ }
+
+ if (IsMcbSymLink(Parent)) {
+ if (Parent->Target) {
+ TmpMcb = Parent->Target->Child;
+ ASSERT(!IsMcbSymLink(Parent->Target));
+ } else {
+ TmpMcb = NULL;
+ __leave;
+ }
+ } else {
+ TmpMcb = Parent->Child;
+ }
+
+ while (TmpMcb) {
+
+ if (!RtlCompareUnicodeString(
+ &(TmpMcb->ShortName),
+ FileName, TRUE )) {
+ Ext2ReferMcb(TmpMcb);
+ break;
+ }
+
+ TmpMcb = TmpMcb->Next;
+ }
+
+ } __finally {
+
+ Ext2DerefMcb(Parent);
+ }
+
+ return TmpMcb;
+}
+
+VOID
+Ext2InsertMcb (
+ PEXT2_VCB Vcb,
+ PEXT2_MCB Parent,
+ PEXT2_MCB Child
+)
+{
+ BOOLEAN LockAcquired = FALSE;
+ PEXT2_MCB Mcb = NULL;
+
+ __try {
+
+ ExAcquireResourceExclusiveLite(
+ &Vcb->McbLock,
+ TRUE );
+ LockAcquired = TRUE;
+
+ /* use it's target if it's a symlink */
+ if (IsMcbSymLink(Parent)) {
+ Parent = Parent->Target;
+ ASSERT(!IsMcbSymLink(Parent));
+ }
+
+ Mcb = Parent->Child;
+ while (Mcb) {
+ if (Mcb == Child) {
+ break;
+ }
+ Mcb = Mcb->Next;
+ }
+
+ if (Mcb) {
+ /* already attached in the list */
+ DEBUG(DL_ERR, ( "Ext2InsertMcb: Child Mcb is alreay attached.\n"));
+ if (!IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
+ SetLongFlag(Child->Flags, MCB_ENTRY_TREE);
+ DEBUG(DL_ERR, ( "Ext2InsertMcb: Child Mcb's flag isn't set.\n"));
+ }
+
+ DbgBreak();
+
+ } else {
+
+ /* insert this Mcb into the head */
+ Child->Next = Parent->Child;
+ Parent->Child = Child;
+ Child->Parent = Parent;
+ Child->de->d_parent = Parent->de;
+ Ext2ReferMcb(Parent);
+ SetLongFlag(Child->Flags, MCB_ENTRY_TREE);
+ }
+
+ } __finally {
+
+ if (LockAcquired) {
+ ExReleaseResourceLite(&Vcb->McbLock);
+ }
+ }
+}
+
+BOOLEAN
+Ext2RemoveMcb (
+ PEXT2_VCB Vcb,
+ PEXT2_MCB Mcb
+)
+{
+ PEXT2_MCB TmpMcb = NULL;
+ BOOLEAN LockAcquired = FALSE;
+ BOOLEAN bLinked = FALSE;
+
+ __try {
+
+ ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
+ LockAcquired = TRUE;
+
+ if (Mcb->Parent) {
+
+ if (Mcb->Parent->Child == Mcb) {
+ Mcb->Parent->Child = Mcb->Next;
+ bLinked = TRUE;
+ } else {
+ TmpMcb = Mcb->Parent->Child;
+
+ while (TmpMcb && TmpMcb->Next != Mcb) {
+ TmpMcb = TmpMcb->Next;
+ }
+
+ if (TmpMcb) {
+ TmpMcb->Next = Mcb->Next;
+ bLinked = TRUE;
+ } else {
+ /* we got errors: link broken */
+ }
+ }
+
+ if (bLinked) {
+ if (IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
+ DEBUG(DL_RES, ("Mcb %p %wZ removed from Mcb %p %wZ\n", Mcb,
+ &Mcb->FullName, Mcb->Parent, &Mcb->Parent->FullName));
+ Ext2DerefMcb(Mcb->Parent);
+ ClearLongFlag(Mcb->Flags, MCB_ENTRY_TREE);
+ } else {
+ DbgBreak();
+ }
+ } else {
+ if (IsFlagOn(Mcb->Flags, MCB_ENTRY_TREE)) {
+ ClearLongFlag(Mcb->Flags, MCB_ENTRY_TREE);
+ }
+ DbgBreak();
+ }
+ Mcb->Parent = NULL;
+ Mcb->de->d_parent = NULL;
+ }
+
+ } __finally {
+
+ if (LockAcquired) {
+ ExReleaseResourceLite(&Vcb->McbLock);
+ }
+ }
+
+ return TRUE;
+}
+
+VOID
+Ext2CleanupAllMcbs(PEXT2_VCB Vcb)
+{
+ BOOLEAN LockAcquired = FALSE;
+ PEXT2_MCB Mcb = NULL;
+
+ __try {
+
+ ExAcquireResourceExclusiveLite(
+ &Vcb->McbLock,
+ TRUE );
+ LockAcquired = TRUE;
+
+ while (Mcb = Ext2FirstUnusedMcb(Vcb, TRUE, Vcb->NumOfMcb)) {
+ while (Mcb) {
+ PEXT2_MCB Next = Mcb->Next;
+ if (IsMcbSymLink(Mcb)) {
+ Mcb->Target = NULL;
+ }
+ Ext2FreeMcb(Vcb, Mcb);
+ Mcb = Next;
+ }
+ }
+ Ext2FreeMcb(Vcb, Vcb->McbTree);
+ Vcb->McbTree = NULL;
+
+ } __finally {
+
+ if (LockAcquired) {
+ ExReleaseResourceLite(&Vcb->McbLock);
+ }
+ }
+}
+
+BOOLEAN
+Ext2CheckSetBlock(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb, LONGLONG Block)
+{
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *gb = NULL;
+ struct buffer_head *bh = NULL;
+ ULONG group, dwBlk, Length;
+ RTL_BITMAP bitmap;
+ BOOLEAN bModified = FALSE;
+
+ group = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) / BLOCKS_PER_GROUP;
+ dwBlk = (ULONG)(Block - EXT2_FIRST_DATA_BLOCK) % BLOCKS_PER_GROUP;
+
+ gd = ext4_get_group_desc(&Vcb->sb, group, &gb);
+ if (!gd) {
+ return FALSE;
+ }
+ bh = sb_getblk(&Vcb->sb, ext4_block_bitmap(&Vcb->sb, gd));
+
+ if (group == Vcb->sbi.s_groups_count - 1) {
+ Length = (ULONG)(TOTAL_BLOCKS % BLOCKS_PER_GROUP);
+
+ /* s_blocks_count is integer multiple of s_blocks_per_group */
+ if (Length == 0)
+ Length = BLOCKS_PER_GROUP;
+ } else {
+ Length = BLOCKS_PER_GROUP;
+ }
+
+ if (dwBlk >= Length) {
+ fini_bh(&gb);
+ fini_bh(&bh);
+ return FALSE;
+ }
+
+
+ RtlInitializeBitMap(&bitmap, (PULONG)bh->b_data, Length);
+
+ if (RtlCheckBit(&bitmap, dwBlk) == 0) {
+ DbgBreak();
+ RtlSetBits(&bitmap, dwBlk, 1);
+ bModified = TRUE;
+ mark_buffer_dirty(bh);
+ }
+
+ fini_bh(&gb);
+ fini_bh(&bh);
+
+ return (!bModified);
+}
+
+BOOLEAN
+Ext2CheckBitmapConsistency(PEXT2_IRP_CONTEXT IrpContext, PEXT2_VCB Vcb)
+{
+ ULONG i, j, InodeBlocks;
+
+ for (i = 0; i < Vcb->sbi.s_groups_count; i++) {
+
+ PEXT2_GROUP_DESC gd;
+ struct buffer_head *bh = NULL;
+
+ gd = ext4_get_group_desc(&Vcb->sb, i, &bh);
+ if (!gd)
+ continue;
+ Ext2CheckSetBlock(IrpContext, Vcb, ext4_block_bitmap(&Vcb->sb, gd));
+ Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_bitmap(&Vcb->sb, gd));
+
+
+ if (i == Vcb->sbi.s_groups_count - 1) {
+ InodeBlocks = ((INODES_COUNT % INODES_PER_GROUP) *
+ Vcb->InodeSize + Vcb->BlockSize - 1) /
+ (Vcb->BlockSize);
+ } else {
+ InodeBlocks = (INODES_PER_GROUP * Vcb->InodeSize +
+ Vcb->BlockSize - 1) / (Vcb->BlockSize);
+ }
+
+ for (j = 0; j < InodeBlocks; j++ )
+ Ext2CheckSetBlock(IrpContext, Vcb, ext4_inode_table(&Vcb->sb, gd) + j);
+
+ fini_bh(&bh);
+ }
+
+ return TRUE;
+}
+
+/* Ext2Global->Resource should be already acquired */
+VOID
+Ext2InsertVcb(PEXT2_VCB Vcb)
+{
+ InsertTailList(&(Ext2Global->VcbList), &Vcb->Next);
+}
+
+
+/* Ext2Global->Resource should be already acquired */
+VOID
+Ext2RemoveVcb(PEXT2_VCB Vcb)
+{
+ RemoveEntryList(&Vcb->Next);
+ InitializeListHead(&Vcb->Next);
+}
+
+NTSTATUS
+Ext2QueryVolumeParams(IN PEXT2_VCB Vcb, IN PUNICODE_STRING Params)
+{
+ NTSTATUS Status;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+
+ UNICODE_STRING UniName;
+ PUSHORT UniBuffer = NULL;
+
+ USHORT UUID[50];
+
+ int i;
+ int len = 0;
+
+ /* zero params */
+ RtlZeroMemory(Params, sizeof(UNICODE_STRING));
+
+ /* constructing volume UUID name */
+ memset(UUID, 0, sizeof(USHORT) * 50);
+ for (i=0; i < 16; i++) {
+ if (i == 0) {
+ swprintf((wchar_t *)&UUID[len], L"{%2.2X",Vcb->SuperBlock->s_uuid[i]);
+ len += 3;
+ } else if (i == 15) {
+ swprintf((wchar_t *)&UUID[len], L"-%2.2X}", Vcb->SuperBlock->s_uuid[i]);
+ len +=4;
+ } else {
+ swprintf((wchar_t *)&UUID[len], L"-%2.2X", Vcb->SuperBlock->s_uuid[i]);
+ len += 3;
+ }
+ }
+
+ /* allocating memory for UniBuffer */
+ UniBuffer = Ext2AllocatePool(PagedPool, 1024, EXT2_PARAM_MAGIC);
+ if (NULL == UniBuffer) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ goto errorout;
+ }
+ RtlZeroMemory(UniBuffer, 1024);
+
+ /* querying volume parameter string */
+ RtlZeroMemory(&QueryTable[0], sizeof(RTL_QUERY_REGISTRY_TABLE) * 2);
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = UUID;
+ QueryTable[0].EntryContext = &(UniName);
+ UniName.MaximumLength = 1024;
+ UniName.Length = 0;
+ UniName.Buffer = UniBuffer;
+
+ Status = RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE,
+ Ext2Global->RegistryPath.Buffer,
+ &QueryTable[0],
+ NULL,
+ NULL
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ goto errorout;
+ }
+
+errorout:
+
+ if (NT_SUCCESS(Status)) {
+ *Params = UniName;
+ } else {
+ if (UniBuffer) {
+ Ext2FreePool(UniBuffer, EXT2_PARAM_MAGIC);
+ }
+ }
+
+ return Status;
+}
+
+VOID
+Ext2ParseRegistryVolumeParams(
+ IN PUNICODE_STRING Params,
+ OUT PEXT2_VOLUME_PROPERTY3 Property
+)
+{
+ WCHAR Codepage[CODEPAGE_MAXLEN];
+ WCHAR Prefix[HIDINGPAT_LEN];
+ WCHAR Suffix[HIDINGPAT_LEN];
+ USHORT MountPoint[4];
+ UCHAR DrvLetter[4];
+ WCHAR wUID[8], wGID[8], wEUID[8], wEGID[8];
+ CHAR sUID[8], sGID[8], sEUID[8], sEGID[8];
+
+ BOOLEAN bWriteSupport = FALSE,
+ bCheckBitmap = FALSE,
+ bCodeName = FALSE,
+ bMountPoint = FALSE;
+ BOOLEAN bUID = 0, bGID = 0, bEUID = 0, bEGID = 0;
+
+ struct {
+ PWCHAR Name; /* parameters name */
+ PBOOLEAN bExist; /* is it contained in params */
+ USHORT Length; /* parameter value length */
+ PWCHAR uValue; /* value buffer in unicode */
+ PCHAR aValue; /* value buffer in ansi */
+ } ParamPattern[] = {
+ /* writing support */
+ {READING_ONLY, &Property->bReadonly, 0, NULL, NULL},
+ {WRITING_SUPPORT, &bWriteSupport, 0, NULL, NULL},
+ {EXT3_FORCEWRITING, &Property->bExt3Writable, 0, NULL, NULL},
+
+ /* need check bitmap */
+ {CHECKING_BITMAP, &bCheckBitmap, 0, NULL, NULL},
+ /* codepage */
+ {CODEPAGE_NAME, &bCodeName, CODEPAGE_MAXLEN,
+ &Codepage[0], Property->Codepage},
+ /* filter prefix and suffix */
+ {HIDING_PREFIX, &Property->bHidingPrefix, HIDINGPAT_LEN,
+ &Prefix[0], Property->sHidingPrefix},
+ {HIDING_SUFFIX, &Property->bHidingSuffix, HIDINGPAT_LEN,
+ &Suffix[0], Property->sHidingSuffix},
+ {MOUNT_POINT, &bMountPoint, 4,
+ &MountPoint[0], &DrvLetter[0]},
+
+ {UID, &bUID, 8, &wUID[0], &sUID[0],},
+ {GID, &bGID, 8, &wGID[0], &sGID[0]},
+ {EUID, &bEUID, 8, &wEUID[0], &sEUID[0]},
+ {EGID, &bEGID, 8, &wEGID[0], &sEGID[0]},
+
+ /* end */
+ {NULL, NULL, 0, NULL}
+ };
+
+ USHORT i, j, k;
+
+ RtlZeroMemory(Codepage, CODEPAGE_MAXLEN);
+ RtlZeroMemory(Prefix, HIDINGPAT_LEN);
+ RtlZeroMemory(Suffix, HIDINGPAT_LEN);
+ RtlZeroMemory(MountPoint, sizeof(USHORT) * 4);
+ RtlZeroMemory(DrvLetter, sizeof(CHAR) * 4);
+
+ RtlZeroMemory(Property, sizeof(EXT2_VOLUME_PROPERTY3));
+ Property->Magic = EXT2_VOLUME_PROPERTY_MAGIC;
+ Property->Command = APP_CMD_SET_PROPERTY3;
+
+ for (i=0; ParamPattern[i].Name != NULL; i++) {
+
+ UNICODE_STRING Name1=*Params, Name2;
+ RtlInitUnicodeString(&Name2, ParamPattern[i].Name);
+ *ParamPattern[i].bExist = FALSE;
+
+ for (j=0; j * sizeof(WCHAR) + Name2.Length <= Params->Length ; j++) {
+
+ Name1.MaximumLength = Params->Length - j * sizeof(WCHAR);
+ Name1.Length = Name2.Length;
+ Name1.Buffer = &Params->Buffer[j];
+
+ if (!RtlCompareUnicodeString(&Name1, &Name2, TRUE)) {
+ if (j * sizeof(WCHAR) + Name2.Length == Params->Length ||
+ Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L';' ||
+ Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L',' ) {
+ *(ParamPattern[i].bExist) = TRUE;
+ } else if ((j * 2 + Name2.Length < Params->Length + 2) ||
+ (Name1.Buffer[Name2.Length/sizeof(WCHAR)] == L'=' )) {
+ j += Name2.Length/sizeof(WCHAR) + 1;
+ k = 0;
+ while ( j + k < Params->Length/2 &&
+ k < ParamPattern[i].Length &&
+ Params->Buffer[j+k] != L';' &&
+ Params->Buffer[j+k] != L',' ) {
+ ParamPattern[i].uValue[k] = Params->Buffer[j + k++];
+ }
+ if (k) {
+ NTSTATUS status;
+ ANSI_STRING AnsiName;
+ AnsiName.Length = 0;
+ AnsiName.MaximumLength =ParamPattern[i].Length;
+ AnsiName.Buffer = ParamPattern[i].aValue;
+
+ Name2.Buffer = ParamPattern[i].uValue;
+ Name2.MaximumLength = Name2.Length = k * sizeof(WCHAR);
+ status = RtlUnicodeStringToAnsiString(
+ &AnsiName, &Name2, FALSE);
+ if (NT_SUCCESS(status)) {
+ *(ParamPattern[i].bExist) = TRUE;
+ } else {
+ *ParamPattern[i].bExist = FALSE;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (bMountPoint) {
+ Property->DrvLetter = DrvLetter[0];
+ Property->DrvLetter |= 0x80;
+ }
+
+ if (bUID && bGID) {
+ SetFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
+ sUID[7] = sGID[7] = sEUID[7] = sEGID[7] = 0;
+ Property->uid = (USHORT)atoi(sUID);
+ Property->gid = (USHORT)atoi(sGID);
+ if (bEUID) {
+ Property->euid = (USHORT)atoi(sEUID);
+ Property->egid = (USHORT)atoi(sEGID);
+ Property->EIDS = TRUE;
+ } else {
+ Property->EIDS = FALSE;
+ }
+ } else {
+ ClearFlag(Property->Flags2, EXT2_VPROP3_USERIDS);
+ }
+}
+
+NTSTATUS
+Ext2PerformRegistryVolumeParams(IN PEXT2_VCB Vcb)
+{
+ NTSTATUS Status;
+ UNICODE_STRING VolumeParams;
+
+ Status = Ext2QueryVolumeParams(Vcb, &VolumeParams);
+ if (NT_SUCCESS(Status)) {
+
+ /* set Vcb settings from registery */
+ EXT2_VOLUME_PROPERTY3 Property;
+ Ext2ParseRegistryVolumeParams(&VolumeParams, &Property);
+ Ext2ProcessVolumeProperty(Vcb, &Property, sizeof(Property));
+
+ } else {
+
+ /* don't support auto mount */
+ if (IsFlagOn(Ext2Global->Flags, EXT2_AUTO_MOUNT)) {
+ Status = STATUS_SUCCESS;
+ } else {
+ Status = STATUS_UNSUCCESSFUL;
+ goto errorout;
+ }
+
+ /* set Vcb settings from Ext2Global */
+ if (IsFlagOn(Ext2Global->Flags, EXT2_SUPPORT_WRITING)) {
+ if (Vcb->IsExt3fs) {
+ if (IsFlagOn(Ext2Global->Flags, EXT3_FORCE_WRITING)) {
+ ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
+ } else {
+ SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
+ }
+ } else {
+ ClearLongFlag(Vcb->Flags, VCB_READ_ONLY);
+ }
+ } else {
+ SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
+ }
+
+ /* set the default codepage */
+ Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
+ memcpy(Vcb->Codepage.AnsiName, Ext2Global->Codepage.AnsiName, CODEPAGE_MAXLEN);
+ Vcb->Codepage.PageTable = Ext2Global->Codepage.PageTable;
+
+ if (Vcb->bHidingPrefix = Ext2Global->bHidingPrefix) {
+ RtlCopyMemory( Vcb->sHidingPrefix,
+ Ext2Global->sHidingPrefix,
+ HIDINGPAT_LEN);
+ } else {
+ RtlZeroMemory( Vcb->sHidingPrefix,
+ HIDINGPAT_LEN);
+ }
+
+ if (Vcb->bHidingSuffix = Ext2Global->bHidingSuffix) {
+ RtlCopyMemory( Vcb->sHidingSuffix,
+ Ext2Global->sHidingSuffix,
+ HIDINGPAT_LEN);
+ } else {
+ RtlZeroMemory( Vcb->sHidingSuffix,
+ HIDINGPAT_LEN);
+ }
+ }
+
+errorout:
+
+ if (VolumeParams.Buffer) {
+ Ext2FreePool(VolumeParams.Buffer, EXT2_PARAM_MAGIC);
+ }
+
+ return Status;
+}
+
+NTSTATUS
+Ext2InitializeLabel(
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_SUPER_BLOCK Sb
+)
+{
+ NTSTATUS status;
+
+ USHORT Length;
+ UNICODE_STRING Label;
+ OEM_STRING OemName;
+
+ Label.MaximumLength = 16 * sizeof(WCHAR);
+ Label.Length = 0;
+ Label.Buffer = Vcb->Vpb->VolumeLabel;
+ Vcb->Vpb->VolumeLabelLength = 0;
+ RtlZeroMemory(Label.Buffer, Label.MaximumLength);
+
+ Length = 16;
+ while ( (Length > 0) &&
+ ((Sb->s_volume_name[Length -1] == 0x00) ||
+ (Sb->s_volume_name[Length - 1] == 0x20) )
+ ) {
+ Length--;
+ }
+
+ if (Length == 0) {
+ return STATUS_SUCCESS;
+ }
+
+ OemName.Buffer = Sb->s_volume_name;
+ OemName.MaximumLength = 16;
+ OemName.Length = Length;
+
+ status = Ext2OEMToUnicode(Vcb, &Label, &OemName);
+ if (NT_SUCCESS(status)) {
+ Vcb->Vpb->VolumeLabelLength = Label.Length;
+ }
+
+ return status;
+}
+
+static __inline BOOLEAN Ext2IsNullUuid (__u8 * uuid)
+{
+ int i;
+ for (i = 0; i < 16; i++) {
+ if (uuid[i]) {
+ break;
+ }
+ }
+
+ return (i >= 16);
+}
+
+#define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0))
+
+NTSTATUS
+Ext2InitializeVcb( IN PEXT2_IRP_CONTEXT IrpContext,
+ IN PEXT2_VCB Vcb,
+ IN PEXT2_SUPER_BLOCK sb,
+ IN PDEVICE_OBJECT TargetDevice,
+ IN PDEVICE_OBJECT VolumeDevice,
+ IN PVPB Vpb )
+{
+ NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
+ ULONG IoctlSize;
+ LONGLONG DiskSize;
+ LONGLONG PartSize;
+ UNICODE_STRING RootNode;
+ USHORT Buffer[2];
+ ULONG ChangeCount = 0, features;
+ CC_FILE_SIZES FileSizes;
+ int i, has_huge_files;
+
+ BOOLEAN VcbResourceInitialized = FALSE;
+ BOOLEAN NotifySyncInitialized = FALSE;
+ BOOLEAN ExtentsInitialized = FALSE;
+ BOOLEAN InodeLookasideInitialized = FALSE;
+ BOOLEAN GroupLoaded = FALSE;
+
+ __try {
+
+ if (Vpb == NULL) {
+ Status = STATUS_DEVICE_NOT_READY;
+ __leave;
+ }
+
+ /* Reject mounting volume if we encounter unsupported incompat features */
+ if (FlagOn(sb->s_feature_incompat, ~EXT4_FEATURE_INCOMPAT_SUPP)) {
+ Status = STATUS_UNRECOGNIZED_VOLUME;
+ __leave;
+ }
+
+ /* Mount the volume RO if we encounter unsupported ro_compat features */
+ if (FlagOn(sb->s_feature_ro_compat, ~EXT4_FEATURE_RO_COMPAT_SUPP)) {
+ SetLongFlag(Vcb->Flags, VCB_RO_COMPAT_READ_ONLY);
+ }
+
+ /* Recognize the filesystem as Ext3fs if it supports journalling */
+ if (IsFlagOn(sb->s_feature_compat, EXT4_FEATURE_COMPAT_HAS_JOURNAL)) {
+ Vcb->IsExt3fs = TRUE;
+ }
+
+ /* check block size */
+ Vcb->BlockSize = (EXT2_MIN_BLOCK_SIZE << sb->s_log_block_size);
+ /* we cannot handle volume with block size bigger than 64k */
+ if (Vcb->BlockSize > EXT2_MAX_USER_BLKSIZE) {
+ Status = STATUS_UNRECOGNIZED_VOLUME;
+ __leave;
+ }
+
+ if (Vcb->BlockSize >= PAGE_SIZE) {
+ Vcb->IoUnitBits = PAGE_SHIFT;
+ Vcb->IoUnitSize = PAGE_SIZE;
+ } else {
+ Vcb->IoUnitSize = Vcb->BlockSize;
+ Vcb->IoUnitBits = Ext2Log2(Vcb->BlockSize);
+ }
+
+ /* initialize vcb header members ... */
+ Vcb->Header.IsFastIoPossible = FastIoIsNotPossible;
+ Vcb->Header.Resource = &(Vcb->MainResource);
+ Vcb->Header.PagingIoResource = &(Vcb->PagingIoResource);
+ Vcb->OpenVolumeCount = 0;
+ Vcb->OpenHandleCount = 0;
+ Vcb->ReferenceCount = 0;
+
+ /* initialize eresources */
+ ExInitializeResourceLite(&Vcb->MainResource);
+ ExInitializeResourceLite(&Vcb->PagingIoResource);
+ ExInitializeResourceLite(&Vcb->MetaInode);
+ ExInitializeResourceLite(&Vcb->MetaBlock);
+ ExInitializeResourceLite(&Vcb->McbLock);
+ ExInitializeResourceLite(&Vcb->FcbLock);
+ ExInitializeResourceLite(&Vcb->sbi.s_gd_lock);
+#ifndef _WIN2K_TARGET_
+ ExInitializeFastMutex(&Vcb->Mutex);
+ FsRtlSetupAdvancedHeader(&Vcb->Header, &Vcb->Mutex);
+#endif
+ VcbResourceInitialized = TRUE;
+
+ /* initialize Fcb list head */
+ InitializeListHead(&Vcb->FcbList);
+
+ /* initialize Mcb list head */
+ InitializeListHead(&(Vcb->McbList));
+
+ /* initialize directory notify list */
+ InitializeListHead(&Vcb->NotifyList);
+ FsRtlNotifyInitializeSync(&Vcb->NotifySync);
+ NotifySyncInitialized = TRUE;
+
+ /* superblock checking */
+ Vcb->SuperBlock = sb;
+
+ /* initialize Vpb and Label */
+ Vcb->DeviceObject = VolumeDevice;
+ Vcb->TargetDeviceObject = TargetDevice;
+ Vcb->Vpb = Vpb;
+ Vcb->RealDevice = Vpb->RealDevice;
+ Vpb->DeviceObject = VolumeDevice;
+
+ /* set inode size */
+ Vcb->InodeSize = (ULONG)sb->s_inode_size;
+ if (Vcb->InodeSize == 0) {
+ Vcb->InodeSize = EXT2_GOOD_OLD_INODE_SIZE;
+ }
+
+ /* initialize inode lookaside list */
+ ExInitializeNPagedLookasideList(&(Vcb->InodeLookasideList),
+ NULL, NULL, 0, Vcb->InodeSize,
+ 'SNIE', 0);
+
+ InodeLookasideInitialized = TRUE;
+
+ /* initialize label in Vpb */
+ Status = Ext2InitializeLabel(Vcb, sb);
+ if (!NT_SUCCESS(Status)) {
+ DbgBreak();
+ }
+
+ /* check device characteristics flags */
+ if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_REMOVABLE_MEDIA)) {
+ SetLongFlag(Vcb->Flags, VCB_REMOVABLE_MEDIA);
+ }
+
+ if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_FLOPPY_DISKETTE)) {
+ SetLongFlag(Vcb->Flags, VCB_FLOPPY_DISK);
+ }
+
+ if (IsFlagOn(Vpb->RealDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
+ SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
+ }
+
+ if (IsFlagOn(TargetDevice->Characteristics, FILE_READ_ONLY_DEVICE)) {
+ SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
+ }
+
+ /* verify device is writable ? */
+ if (Ext2IsMediaWriteProtected(IrpContext, TargetDevice)) {
+ SetFlag(Vcb->Flags, VCB_WRITE_PROTECTED);
+ }
+
+ /* initialize UUID and serial number */
+ if (Ext2IsNullUuid(sb->s_uuid)) {
+ ExUuidCreate((UUID *)sb->s_uuid);
+ }
+ Vpb->SerialNumber = ((ULONG*)sb->s_uuid)[0] +
+ ((ULONG*)sb->s_uuid)[1] +
+ ((ULONG*)sb->s_uuid)[2] +
+ ((ULONG*)sb->s_uuid)[3];
+
+ /* query partition size and disk geometry parameters */
+ DiskSize = Vcb->DiskGeometry.Cylinders.QuadPart *
+ Vcb->DiskGeometry.TracksPerCylinder *
+ Vcb->DiskGeometry.SectorsPerTrack *
+ Vcb->DiskGeometry.BytesPerSector;
+
+ IoctlSize = sizeof(PARTITION_INFORMATION);
+ Status = Ext2DiskIoControl(
+ TargetDevice,
+ IOCTL_DISK_GET_PARTITION_INFO,
+ NULL,
+ 0,
+ &Vcb->PartitionInformation,
+ &IoctlSize );
+ if (NT_SUCCESS(Status)) {
+ PartSize = Vcb->PartitionInformation.PartitionLength.QuadPart;
+ } else {
+ Vcb->PartitionInformation.StartingOffset.QuadPart = 0;
+ Vcb->PartitionInformation.PartitionLength.QuadPart = DiskSize;
+ PartSize = DiskSize;
+ Status = STATUS_SUCCESS;
+ }
+ Vcb->Header.AllocationSize.QuadPart =
+ Vcb->Header.FileSize.QuadPart = PartSize;
+
+ Vcb->Header.ValidDataLength.QuadPart =
+ Vcb->Header.FileSize.QuadPart;
+
+ /* verify count */
+ IoctlSize = sizeof(ULONG);
+ Status = Ext2DiskIoControl(
+ TargetDevice,
+ IOCTL_DISK_CHECK_VERIFY,
+ NULL,
+ 0,
+ &ChangeCount,
+ &IoctlSize );
+
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+ Vcb->ChangeCount = ChangeCount;
+
+ /* create the stream object for ext2 volume */
+ Vcb->Volume = IoCreateStreamFileObject(NULL, Vcb->Vpb->RealDevice);
+ if (!Vcb->Volume) {
+ Status = STATUS_UNRECOGNIZED_VOLUME;
+ __leave;
+ }
+
+ /* initialize streaming object file */
+ Vcb->Volume->SectionObjectPointer = &(Vcb->SectionObject);
+ Vcb->Volume->ReadAccess = TRUE;
+ Vcb->Volume->WriteAccess = TRUE;
+ Vcb->Volume->DeleteAccess = TRUE;
+ Vcb->Volume->FsContext = (PVOID) Vcb;
+ Vcb->Volume->FsContext2 = NULL;
+ Vcb->Volume->Vpb = Vcb->Vpb;
+
+ FileSizes.AllocationSize.QuadPart =
+ FileSizes.FileSize.QuadPart =
+ FileSizes.ValidDataLength.QuadPart =
+ Vcb->Header.AllocationSize.QuadPart;
+
+ CcInitializeCacheMap( Vcb->Volume,
+ &FileSizes,
+ TRUE,
+ &(Ext2Global->CacheManagerNoOpCallbacks),
+ Vcb );
+
+ /* initialize disk block LargetMcb and entry Mcb,
+ it will raise an expcetion if failed */
+ __try {
+ FsRtlInitializeLargeMcb(&(Vcb->Extents), PagedPool);
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ DbgBreak();
+ }
+ if (!NT_SUCCESS(Status)) {
+ __leave;
+ }
+ ExtentsInitialized = TRUE;
+
+ /* set block device */
+ Vcb->bd.bd_dev = Vcb->RealDevice;
+ Vcb->bd.bd_geo = Vcb->DiskGeometry;
+ Vcb->bd.bd_part = Vcb->PartitionInformation;
+ Vcb->bd.bd_volume = Vcb->Volume;
+ Vcb->bd.bd_priv = (void *) Vcb;
+ memset(&Vcb->bd.bd_bh_root, 0, sizeof(struct rb_root));
+ InitializeListHead(&Vcb->bd.bd_bh_free);
+ ExInitializeResourceLite(&Vcb->bd.bd_bh_lock);
+ KeInitializeEvent(&Vcb->bd.bd_bh_notify,
+ NotificationEvent, TRUE);
+ Vcb->bd.bd_bh_cache = kmem_cache_create("bd_bh_buffer",
+ Vcb->BlockSize, 0, 0, NULL);
+ if (!Vcb->bd.bd_bh_cache) {
+ Status = STATUS_INSUFFICIENT_RESOURCES;
+ __leave;
+ }
+
+ Vcb->SectorBits = Ext2Log2(SECTOR_SIZE);
+ Vcb->sb.s_magic = sb->s_magic;
+ Vcb->sb.s_bdev = &Vcb->bd;
+ Vcb->sb.s_blocksize = BLOCK_SIZE;
+ Vcb->sb.s_blocksize_bits = BLOCK_BITS;
+ Vcb->sb.s_priv = (void *) Vcb;
+ Vcb->sb.s_fs_info = &Vcb->sbi;
+
+ Vcb->sbi.s_es = sb;
+ Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
+ Vcb->sbi.s_first_ino = sb->s_first_ino;
+ Vcb->sbi.s_desc_size = sb->s_desc_size;
+ Vcb->sbi.s_clusters_per_group = sb->s_clusters_per_group;
+ Vcb->sbi.s_inode_size = sb->s_inode_size;
+ Vcb->sbi.s_csum_seed = ext4_chksum(&Vcb->sbi, ~0, sb->s_uuid, sizeof(sb->s_uuid));
+
+ if (EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
+ if (Vcb->sbi.s_desc_size < EXT4_MIN_DESC_SIZE_64BIT ||
+ Vcb->sbi.s_desc_size > EXT4_MAX_DESC_SIZE ||
+ !is_power_of_2(Vcb->sbi.s_desc_size)) {
+ DEBUG(DL_ERR, ("EXT4-fs: unsupported descriptor size %lu\n", Vcb->sbi.s_desc_size));
+ Status = STATUS_DISK_CORRUPT_ERROR;
+ __leave;
+ }
+ } else {
+ Vcb->sbi.s_desc_size = EXT4_MIN_DESC_SIZE;
+ }
+
+ Vcb->sbi.s_blocks_per_group = sb->s_blocks_per_group;
+ Vcb->sbi.s_inodes_per_group = sb->s_inodes_per_group;
+ if (EXT3_INODES_PER_GROUP(&Vcb->sb) == 0) {
+ Status = STATUS_DISK_CORRUPT_ERROR;
+ __leave;
+ }
+ Vcb->sbi.s_inodes_per_block = BLOCK_SIZE / Vcb->InodeSize;
+ if (Vcb->sbi.s_inodes_per_block == 0) {
+ Status = STATUS_DISK_CORRUPT_ERROR;
+ __leave;
+ }
+ Vcb->sbi.s_itb_per_group = Vcb->sbi.s_inodes_per_group /
+ Vcb->sbi.s_inodes_per_block;
+
+
+ Vcb->sbi.s_desc_per_block = BLOCK_SIZE / GROUP_DESC_SIZE;
+ Vcb->sbi.s_desc_per_block_bits = ilog2(Vcb->sbi.s_desc_per_block);
+
+ for (i=0; i < 4; i++) {
+ Vcb->sbi.s_hash_seed[i] = sb->s_hash_seed[i];
+ }
+ Vcb->sbi.s_def_hash_version = sb->s_def_hash_version;
+
+ if (le32_to_cpu(sb->s_rev_level) == EXT3_GOOD_OLD_REV &&
+ (EXT3_HAS_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
+ EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~0U) ||
+ EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~0U))) {
+ printk(KERN_WARNING
+ "EXT3-fs warning: feature flags set on rev 0 fs, "
+ "running e2fsck is recommended\n");
+ }
+
+ /*
+ * Check feature flags regardless of the revision level, since we
+ * previously didn't change the revision level when setting the flags,
+ * so there is a chance incompat flags are set on a rev 0 filesystem.
+ */
+ features = EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_INCOMPAT_SUPP);
+ if (features & EXT4_FEATURE_INCOMPAT_DIRDATA) {
+ SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
+ ClearFlag(features, EXT4_FEATURE_INCOMPAT_DIRDATA);
+ }
+ if (features) {
+ printk(KERN_ERR "EXT3-fs: %s: couldn't mount because of "
+ "unsupported optional features (%x).\n",
+ Vcb->sb.s_id, le32_to_cpu(features));
+ Status = STATUS_UNRECOGNIZED_VOLUME;
+ __leave;
+ }
+
+ features = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, ~EXT4_FEATURE_RO_COMPAT_SUPP);
+ if (features) {
+ printk(KERN_ERR "EXT3-fs: %s: unsupported optional features in this volume: (%x).\n",
+ Vcb->sb.s_id, le32_to_cpu(features));
+ if (CanIWrite(Vcb)) {
+ } else {
+ SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
+ }
+ }
+
+ /*
+ * Mount ext4 with 64-bit block numbers read-only while testing.
+ */
+ if (EXT3_HAS_INCOMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_INCOMPAT_64BIT)) {
+ printk(KERN_ERR "EXT3-fs: %s: Mounting ext4 with 64-bit block numbers read-only.\n",
+ Vcb->sb.s_id);
+ SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
+ }
+
+ has_huge_files = EXT3_HAS_RO_COMPAT_FEATURE(&Vcb->sb, EXT4_FEATURE_RO_COMPAT_HUGE_FILE);
+
+ Vcb->sb.s_maxbytes = ext3_max_size(BLOCK_BITS, has_huge_files);
+ Vcb->max_bitmap_bytes = ext3_max_bitmap_size(BLOCK_BITS,
+ has_huge_files);
+ Vcb->max_bytes = ext3_max_size(BLOCK_BITS, has_huge_files);
+
+ /* calculate maximum file bocks ... */
+ {
+ ULONG dwData[EXT2_BLOCK_TYPES] = {EXT2_NDIR_BLOCKS, 1, 1, 1};
+ ULONG i;
+
+ ASSERT(BLOCK_BITS == Ext2Log2(BLOCK_SIZE));
+
+ Vcb->sbi.s_groups_count = (ULONG)(ext3_blocks_count(sb) - sb->s_first_data_block +
+ sb->s_blocks_per_group - 1) / sb->s_blocks_per_group;
+
+ Vcb->max_data_blocks = 0;
+ for (i = 0; i < EXT2_BLOCK_TYPES; i++) {
+ if (BLOCK_BITS >= 12 && i == (EXT2_BLOCK_TYPES - 1)) {
+ dwData[i] = 0x40000000;
+ } else {
+ dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);
+ }
+ Vcb->max_blocks_per_layer[i] = dwData[i];
+ Vcb->max_data_blocks += Vcb->max_blocks_per_layer[i];
+ }
+ }
+
+ Vcb->sbi.s_gdb_count = (Vcb->sbi.s_groups_count + Vcb->sbi.s_desc_per_block - 1) /
+ Vcb->sbi.s_desc_per_block;
+ /* load all gorup desc */
+ if (!Ext2LoadGroup(Vcb)) {
+ Status = STATUS_UNSUCCESSFUL;
+ __leave;
+ }
+ GroupLoaded = TRUE;
+
+ /* recovery journal since it's ext3 */
+ if (Vcb->IsExt3fs) {
+ Ext2RecoverJournal(IrpContext, Vcb);
+ if (IsFlagOn(Vcb->Flags, VCB_JOURNAL_RECOVER)) {
+ SetLongFlag(Vcb->Flags, VCB_READ_ONLY);
+ }
+ }
+
+ /* Now allocating the mcb for root ... */
+ Buffer[0] = L'\\';
+ Buffer[1] = 0;
+ RootNode.Buffer = Buffer;
+ RootNode.MaximumLength = RootNode.Length = 2;
+ Vcb->McbTree = Ext2AllocateMcb(
+ Vcb, &RootNode, NULL,
+ FILE_ATTRIBUTE_DIRECTORY
+ );
+ if (!Vcb->McbTree) {
+ DbgBreak();
+ Status = STATUS_UNSUCCESSFUL;
+ __leave;
+ }
+
+ Vcb->sb.s_root = Ext2BuildEntry(Vcb, NULL, &RootNode);
+ if (!Vcb->sb.s_root) {
+ DbgBreak();
+ Status = STATUS_UNSUCCESSFUL;
+ __leave;
+ }
+ Vcb->sb.s_root->d_sb = &Vcb->sb;
+ Vcb->sb.s_root->d_inode = &Vcb->McbTree->Inode;
+ Vcb->McbTree->de = Vcb->sb.s_root;
+
+ /* load root inode */
+ Vcb->McbTree->Inode.i_ino = EXT2_ROOT_INO;
+ Vcb->McbTree->Inode.i_sb = &Vcb->sb;
+ if (!Ext2LoadInode(Vcb, &Vcb->McbTree->Inode)) {
+ DbgBreak();
+ Status = STATUS_CANT_WAIT;
+ __leave;
+ }
+
+ /* initializeroot node */
+ Vcb->McbTree->CreationTime = Ext2NtTime(Vcb->McbTree->Inode.i_ctime);
+ Vcb->McbTree->LastAccessTime = Ext2NtTime(Vcb->McbTree->Inode.i_atime);
+ Vcb->McbTree->LastWriteTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
+ Vcb->McbTree->ChangeTime = Ext2NtTime(Vcb->McbTree->Inode.i_mtime);
+
+ /* check bitmap if user specifies it */
+ if (IsFlagOn(Ext2Global->Flags, EXT2_CHECKING_BITMAP)) {
+ Ext2CheckBitmapConsistency(IrpContext, Vcb);
+ }
+
+ /* get anything doen, then refer target device */
+ ObReferenceObject(Vcb->TargetDeviceObject);
+
+ /* query parameters from registry */
+ Ext2PerformRegistryVolumeParams(Vcb);
+
+ SetLongFlag(Vcb->Flags, VCB_INITIALIZED);
+
+ } __finally {
+
+ if (!NT_SUCCESS(Status)) {
+
+ if (Vcb->McbTree) {
+ Ext2FreeMcb(Vcb, Vcb->McbTree);
+ }
+
+ if (InodeLookasideInitialized) {
+ ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
+ }
+
+ if (ExtentsInitialized) {
+ if (Vcb->bd.bd_bh_cache) {
+ if (GroupLoaded)
+ Ext2PutGroup(Vcb);
+ kmem_cache_destroy(Vcb->bd.bd_bh_cache);
+ }
+ FsRtlUninitializeLargeMcb(&(Vcb->Extents));
+ }
+
+ if (Vcb->Volume) {
+ if (Vcb->Volume->PrivateCacheMap) {
+ Ext2SyncUninitializeCacheMap(Vcb->Volume);
+ }
+ ObDereferenceObject(Vcb->Volume);
+ }
+
+ if (NotifySyncInitialized) {
+ FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
+ }
+
+ if (VcbResourceInitialized) {
+ ExDeleteResourceLite(&Vcb->FcbLock);
+ ExDeleteResourceLite(&Vcb->McbLock);
+ ExDeleteResourceLite(&Vcb->MetaInode);
+ ExDeleteResourceLite(&Vcb->MetaBlock);
+ ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
+ ExDeleteResourceLite(&Vcb->MainResource);
+ ExDeleteResourceLite(&Vcb->PagingIoResource);
+ }
+ }
+ }
+
+ return Status;
+}
+
+
+VOID
+Ext2TearDownStream(IN PEXT2_VCB Vcb)
+{
+ PFILE_OBJECT Stream = Vcb->Volume;
+ IO_STATUS_BLOCK IoStatus;
+
+ ASSERT(Vcb != NULL);
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+
+ if (Stream) {
+
+ Vcb->Volume = NULL;
+
+ if (IsFlagOn(Stream->Flags, FO_FILE_MODIFIED)) {
+ CcFlushCache(&(Vcb->SectionObject), NULL, 0, &IoStatus);
+ ClearFlag(Stream->Flags, FO_FILE_MODIFIED);
+ }
+
+ if (Stream->PrivateCacheMap) {
+ Ext2SyncUninitializeCacheMap(Stream);
+ }
+
+ ObDereferenceObject(Stream);
+ }
+}
+
+VOID
+Ext2DestroyVcb (IN PEXT2_VCB Vcb)
+{
+ ASSERT(Vcb != NULL);
+ ASSERT((Vcb->Identifier.Type == EXT2VCB) &&
+ (Vcb->Identifier.Size == sizeof(EXT2_VCB)));
+
+ DEBUG(DL_FUN, ("Ext2DestroyVcb ...\n"));
+
+ if (Vcb->Volume) {
+ Ext2TearDownStream(Vcb);
+ }
+ ASSERT(NULL == Vcb->Volume);
+
+ FsRtlNotifyUninitializeSync(&Vcb->NotifySync);
+ Ext2ListExtents(&Vcb->Extents);
+ FsRtlUninitializeLargeMcb(&(Vcb->Extents));
+
+ Ext2CleanupAllMcbs(Vcb);
+
+ Ext2DropBH(Vcb);
+
+ if (Vcb->bd.bd_bh_cache)
+ kmem_cache_destroy(Vcb->bd.bd_bh_cache);
+ ExDeleteResourceLite(&Vcb->bd.bd_bh_lock);
+
+ if (Vcb->SuperBlock) {
+ Ext2FreePool(Vcb->SuperBlock, EXT2_SB_MAGIC);
+ Vcb->SuperBlock = NULL;
+ }
+
+ if (IsFlagOn(Vcb->Flags, VCB_NEW_VPB)) {
+ ASSERT(Vcb->Vpb2 != NULL);
+ DEBUG(DL_DBG, ("Ext2DestroyVcb: Vpb2 to be freed: %p\n", Vcb->Vpb2));
+ ExFreePoolWithTag(Vcb->Vpb2, TAG_VPB);
+ DEC_MEM_COUNT(PS_VPB, Vcb->Vpb2, sizeof(VPB));
+ Vcb->Vpb2 = NULL;
+ }
+
+ ObDereferenceObject(Vcb->TargetDeviceObject);
+
+ ExDeleteNPagedLookasideList(&(Vcb->InodeLookasideList));
+ ExDeleteResourceLite(&Vcb->FcbLock);
+ ExDeleteResourceLite(&Vcb->McbLock);
+ ExDeleteResourceLite(&Vcb->MetaInode);
+ ExDeleteResourceLite(&Vcb->MetaBlock);
+ ExDeleteResourceLite(&Vcb->sbi.s_gd_lock);
+ ExDeleteResourceLite(&Vcb->PagingIoResource);
+ ExDeleteResourceLite(&Vcb->MainResource);
+
+ DEBUG(DL_DBG, ("Ext2DestroyVcb: DevObject=%p Vcb=%p\n", Vcb->DeviceObject, Vcb));
+ IoDeleteDevice(Vcb->DeviceObject);
+ DEC_MEM_COUNT(PS_VCB, Vcb->DeviceObject, sizeof(EXT2_VCB));
+}
+
+
+/* uninitialize cache map */
+
+VOID
+Ext2SyncUninitializeCacheMap (
+ IN PFILE_OBJECT FileObject
+)
+{
+ CACHE_UNINITIALIZE_EVENT UninitializeCompleteEvent;
+ NTSTATUS WaitStatus;
+ LARGE_INTEGER Ext2LargeZero = {0,0};
+
+
+ KeInitializeEvent( &UninitializeCompleteEvent.Event,
+ SynchronizationEvent,
+ FALSE);
+
+ CcUninitializeCacheMap( FileObject,
+ &Ext2LargeZero,
+ &UninitializeCompleteEvent );
+
+ WaitStatus = KeWaitForSingleObject( &UninitializeCompleteEvent.Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ ASSERT (NT_SUCCESS(WaitStatus));
+}
+
+/* Link Mcb to tail of Vcb->McbList queue */
+
+VOID
+Ext2LinkTailMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
+{
+ if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
+ return;
+ }
+
+ ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
+
+ if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
+ DEBUG(DL_RES, ( "Ext2LinkTailMcb: %wZ already linked.\n",
+ &Mcb->FullName));
+ } else {
+ InsertTailList(&Vcb->McbList, &Mcb->Link);
+ SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
+ Ext2ReferXcb(&Vcb->NumOfMcb);
+ }
+
+ ExReleaseResourceLite(&Vcb->McbLock);
+}
+
+/* Link Mcb to head of Vcb->McbList queue */
+
+VOID
+Ext2LinkHeadMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
+{
+ if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
+ return;
+ }
+
+ ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
+
+ if (!IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
+ InsertHeadList(&Vcb->McbList, &Mcb->Link);
+ SetLongFlag(Mcb->Flags, MCB_VCB_LINK);
+ Ext2ReferXcb(&Vcb->NumOfMcb);
+ } else {
+ DEBUG(DL_RES, ( "Ext2LinkHeadMcb: %wZ already linked.\n",
+ &Mcb->FullName));
+ }
+ ExReleaseResourceLite(&Vcb->McbLock);
+}
+
+/* Unlink Mcb from Vcb->McbList queue */
+
+VOID
+Ext2UnlinkMcb(PEXT2_VCB Vcb, PEXT2_MCB Mcb)
+{
+ if (Mcb->Inode.i_ino == EXT2_ROOT_INO) {
+ return;
+ }
+
+ ExAcquireResourceExclusiveLite(&Vcb->McbLock, TRUE);
+
+ if (IsFlagOn(Mcb->Flags, MCB_VCB_LINK)) {
+ RemoveEntryList(&(Mcb->Link));
+ ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
+ Ext2DerefXcb(&Vcb->NumOfMcb);
+ } else {
+ DEBUG(DL_RES, ( "Ext2UnlinkMcb: %wZ already unlinked.\n",
+ &Mcb->FullName));
+ }
+ ExReleaseResourceLite(&Vcb->McbLock);
+}
+
+/* get the first Mcb record in Vcb->McbList */
+
+PEXT2_MCB
+Ext2FirstUnusedMcb(PEXT2_VCB Vcb, BOOLEAN Wait, ULONG Number)
+{
+ PEXT2_MCB Head = NULL;
+ PEXT2_MCB Tail = NULL;
+ PEXT2_MCB Mcb = NULL;
+ PLIST_ENTRY List = NULL;
+ ULONG i = 0;
+ LARGE_INTEGER start, now;
+
+ if (!ExAcquireResourceExclusiveLite(&Vcb->McbLock, Wait)) {
+ return NULL;
+ }
+
+ KeQuerySystemTime(&start);
+
+ while (Number--) {
+
+ BOOLEAN Skip = TRUE;
+
+ if (IsListEmpty(&Vcb->McbList)) {
+ break;
+ }
+
+ while (i++ < Vcb->NumOfMcb) {
+
+ KeQuerySystemTime(&now);
+ if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) {
+ break;
+ }
+
+ List = RemoveHeadList(&Vcb->McbList);
+ Mcb = CONTAINING_RECORD(List, EXT2_MCB, Link);
+ ASSERT(IsFlagOn(Mcb->Flags, MCB_VCB_LINK));
+
+ if (Mcb->Fcb == NULL && !IsMcbRoot(Mcb) &&
+ Mcb->Refercount == 0 &&
+ (Mcb->Child == NULL || IsMcbSymLink(Mcb))) {
+
+ Ext2RemoveMcb(Vcb, Mcb);
+ ClearLongFlag(Mcb->Flags, MCB_VCB_LINK);
+ Ext2DerefXcb(&Vcb->NumOfMcb);
+
+ /* attach all Mcb into a chain*/
+ if (Head) {
+ ASSERT(Tail != NULL);
+ Tail->Next = Mcb;
+ Tail = Mcb;
+ } else {
+ Head = Tail = Mcb;
+ }
+ Tail->Next = NULL;
+ Skip = FALSE;
+
+ } else {
+
+ InsertTailList(&Vcb->McbList, &Mcb->Link);
+ Mcb = NULL;
+ }
+ }
+
+ if (Skip)
+ break;
+ }
+
+ ExReleaseResourceLite(&Vcb->McbLock);
+
+ return Head;
+}
+
+
+/* Reaper thread to release unused Mcb blocks */
+VOID
+Ext2McbReaperThread(
+ PVOID Context
+)
+{
+ PEXT2_REAPER Reaper = Context;
+ PLIST_ENTRY List = NULL;
+ LARGE_INTEGER Timeout;
+
+ PEXT2_VCB Vcb = NULL;
+ PEXT2_MCB Mcb = NULL;
+
+ ULONG i, NumOfMcbs;
+
+ BOOLEAN GlobalAcquired = FALSE;
+
+ BOOLEAN DidNothing = TRUE;
+ BOOLEAN LastState = TRUE;
+ BOOLEAN WaitLock;
+
+ __try {
+
+ Reaper->Thread = PsGetCurrentThread();
+
+ /* wake up DirverEntry */
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+
+ /* now process looping */
+ while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
+
+ WaitLock = FALSE;
+
+ /* calculate how long we need wait */
+ if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 128)) {
+ Timeout.QuadPart = (LONGLONG)-1000*1000; /* 0.1 second */
+ NumOfMcbs = Ext2Global->MaxDepth * 4;
+ WaitLock = TRUE;
+ } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 32)) {
+ Timeout.QuadPart = (LONGLONG)-1000*1000*5; /* 0.5 second */
+ NumOfMcbs = Ext2Global->MaxDepth * 2;
+ WaitLock = TRUE;
+ } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 8)) {
+ Timeout.QuadPart = (LONGLONG)-1000*1000*10; /* 1 second */
+ NumOfMcbs = Ext2Global->MaxDepth;
+ } else if (Ext2Global->PerfStat.Current.Mcb > (((ULONG)Ext2Global->MaxDepth) * 2)) {
+ Timeout.QuadPart = (LONGLONG)-2*1000*1000*10; /* 2 second */
+ NumOfMcbs = Ext2Global->MaxDepth / 4;
+ } else if (Ext2Global->PerfStat.Current.Mcb > (ULONG)Ext2Global->MaxDepth) {
+ Timeout.QuadPart = (LONGLONG)-4*1000*1000*10; /* 4 seconds */
+ NumOfMcbs = Ext2Global->MaxDepth / 8;
+ } else if (DidNothing) {
+ Timeout.QuadPart = (LONGLONG)-8*1000*1000*10; /* 8 seconds */
+ if (LastState) {
+ Timeout.QuadPart *= 2;
+ }
+ NumOfMcbs = Ext2Global->MaxDepth / 16;
+ } else {
+ Timeout.QuadPart = (LONGLONG)-5*1000*1000*10; /* 5 seconds */
+ if (LastState) {
+ Timeout.QuadPart *= 2;
+ }
+ NumOfMcbs = Ext2Global->MaxDepth / 32;
+ }
+
+ if (NumOfMcbs == 0)
+ NumOfMcbs = 1;
+
+ LastState = DidNothing;
+
+ /* wait until it is waken or it times out */
+ KeWaitForSingleObject(
+ &Reaper->Wait,
+ Executive,
+ KernelMode,
+ FALSE,
+ &Timeout
+ );
+
+ if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
+ break;
+
+ DidNothing = TRUE;
+
+ /* acquire global exclusive lock */
+ if (!ExAcquireResourceSharedLite(&Ext2Global->Resource, WaitLock)) {
+ continue;
+ }
+ GlobalAcquired = TRUE;
+
+ /* search all Vcb to get unused resources freed to system */
+ for (List = Ext2Global->VcbList.Flink;
+ List != &(Ext2Global->VcbList);
+ List = List->Flink ) {
+
+ Vcb = CONTAINING_RECORD(List, EXT2_VCB, Next);
+
+ Mcb = Ext2FirstUnusedMcb(Vcb, WaitLock, NumOfMcbs);
+ while (Mcb) {
+ PEXT2_MCB Next = Mcb->Next;
+ DEBUG(DL_RES, ( "Ext2ReaperThread: releasing Mcb (%p): %wZ"
+ " Total: %xh\n", Mcb, &Mcb->FullName,
+ Ext2Global->PerfStat.Current.Mcb));
+ Ext2FreeMcb(Vcb, Mcb);
+ Mcb = Next;
+ LastState = DidNothing = FALSE;
+ }
+ }
+ if (DidNothing) {
+ KeClearEvent(&Reaper->Wait);
+ }
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ GlobalAcquired = FALSE;
+ }
+ }
+
+ } __finally {
+
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ }
+
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+
+/* get buffer heads from global Vcb BH list */
+
+BOOLEAN
+Ext2QueryUnusedBH(PEXT2_VCB Vcb, PLIST_ENTRY head)
+{
+ struct buffer_head *bh = NULL;
+ PLIST_ENTRY next = NULL;
+ LARGE_INTEGER start, now;
+ BOOLEAN wake = FALSE;
+
+ KeQuerySystemTime(&start);
+
+ ExAcquireResourceExclusiveLite(&Vcb->bd.bd_bh_lock, TRUE);
+
+ while (!IsListEmpty(&Vcb->bd.bd_bh_free)) {
+
+ KeQuerySystemTime(&now);
+ if (now.QuadPart > start.QuadPart + (LONGLONG)10*1000*1000) {
+ break;
+ }
+
+ next = RemoveHeadList(&Vcb->bd.bd_bh_free);
+ bh = CONTAINING_RECORD(next, struct buffer_head, b_link);
+ if (atomic_read(&bh->b_count)) {
+ InitializeListHead(&bh->b_link);
+ /* to be inserted by brelse */
+ continue;
+ }
+
+ if ( IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED) ||
+ (bh->b_ts_drop.QuadPart + (LONGLONG)10*1000*1000*15) > now.QuadPart ||
+ (bh->b_ts_creat.QuadPart + (LONGLONG)10*1000*1000*180) > now.QuadPart) {
+ InsertTailList(head, &bh->b_link);
+ buffer_head_remove(&Vcb->bd, bh);
+ } else {
+ InsertHeadList(&Vcb->bd.bd_bh_free, &bh->b_link);
+ break;
+ }
+ }
+
+ wake = IsListEmpty(&Vcb->bd.bd_bh_free);
+ ExReleaseResourceLite(&Vcb->bd.bd_bh_lock);
+
+ if (wake)
+ KeSetEvent(&Vcb->bd.bd_bh_notify, 0, FALSE);
+
+ return IsFlagOn(Vcb->Flags, VCB_BEING_DROPPED);
+}
+
+
+/* Reaper thread to release unused buffer heads */
+VOID
+Ext2bhReaperThread(
+ PVOID Context
+)
+{
+ PEXT2_REAPER Reaper = Context;
+ PEXT2_VCB Vcb = NULL;
+ LIST_ENTRY List, *Link;
+ LARGE_INTEGER Timeout;
+
+ BOOLEAN GlobalAcquired = FALSE;
+ BOOLEAN DidNothing = FALSE;
+ BOOLEAN NonWait = FALSE;
+
+ __try {
+
+ Reaper->Thread = PsGetCurrentThread();
+
+ /* wake up DirverEntry */
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+
+ /* now process looping */
+ while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
+
+ /* wait until it is waken or it times out */
+ if (NonWait) {
+ Timeout.QuadPart = (LONGLONG)-10*1000*10;
+ NonWait = FALSE;
+ } else if (DidNothing) {
+ Timeout.QuadPart = Timeout.QuadPart * 2;
+ } else {
+ Timeout.QuadPart = (LONGLONG)-10*1000*1000*10; /* 10 seconds */
+ }
+ KeWaitForSingleObject(
+ &Reaper->Wait,
+ Executive,
+ KernelMode,
+ FALSE,
+ &Timeout
+ );
+
+ if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
+ break;
+
+ InitializeListHead(&List);
+
+ /* acquire global exclusive lock */
+ ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
+ GlobalAcquired = TRUE;
+ /* search all Vcb to get unused resources freed to system */
+ for (Link = Ext2Global->VcbList.Flink;
+ Link != &(Ext2Global->VcbList);
+ Link = Link->Flink ) {
+
+ Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
+ NonWait = Ext2QueryUnusedBH(Vcb, &List);
+ }
+ DidNothing = IsListEmpty(&List);
+ if (DidNothing) {
+ KeClearEvent(&Reaper->Wait);
+ }
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ GlobalAcquired = FALSE;
+ }
+
+ while (!IsListEmpty(&List)) {
+ struct buffer_head *bh;
+ Link = RemoveHeadList(&List);
+ bh = CONTAINING_RECORD(Link, struct buffer_head, b_link);
+ ASSERT(0 == atomic_read(&bh->b_count));
+ free_buffer_head(bh);
+ }
+ }
+
+ } __finally {
+
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ }
+
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+/* get unused Fcbs to free */
+
+BOOLEAN
+Ext2QueryUnusedFcb(PEXT2_VCB Vcb, PLIST_ENTRY list)
+{
+ PEXT2_FCB Fcb;
+ PLIST_ENTRY next = NULL;
+ LARGE_INTEGER start, now;
+
+ ULONG count = 0;
+ ULONG tries = 0;
+ BOOLEAN wake = FALSE;
+ BOOLEAN retry = TRUE;
+
+ KeQuerySystemTime(&start);
+
+ ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE);
+
+again:
+
+ KeQuerySystemTime(&now);
+ while (!IsListEmpty(&Vcb->FcbList)) {
+
+ next = RemoveHeadList(&Vcb->FcbList);
+ Fcb = CONTAINING_RECORD(next, EXT2_FCB, Next);
+
+ if (Fcb->ReferenceCount > 0) {
+ InsertTailList(&Vcb->FcbList, &Fcb->Next);
+ break;
+ }
+
+ retry = FALSE;
+
+ if (now.QuadPart < Fcb->TsDrop.QuadPart + 10*1000*1000*120) {
+ InsertHeadList(&Vcb->FcbList, &Fcb->Next);
+ break;
+ }
+
+ Ext2UnlinkFcb(Fcb);
+ Ext2DerefXcb(&Vcb->FcbCount);
+ InsertTailList(list, &Fcb->Next);
+ if (++count >= Ext2Global->MaxDepth) {
+ break;
+ }
+ }
+
+ if (start.QuadPart + 10*1000*1000 > now.QuadPart) {
+ retry = FALSE;
+ }
+
+ if (retry) {
+ if (++tries < (Vcb->FcbCount >> 4) )
+ goto again;
+ }
+
+ ExReleaseResourceLite(&Vcb->FcbLock);
+
+ return 0;
+}
+
+/* Reaper thread to release Fcb */
+VOID
+Ext2FcbReaperThread(
+ PVOID Context
+)
+{
+ PEXT2_REAPER Reaper = Context;
+ PEXT2_VCB Vcb = NULL;
+ LIST_ENTRY List, *Link;
+ LARGE_INTEGER Timeout;
+
+ BOOLEAN GlobalAcquired = FALSE;
+ BOOLEAN DidNothing = FALSE;
+ BOOLEAN NonWait = FALSE;
+
+ __try {
+
+ Reaper->Thread = PsGetCurrentThread();
+
+ /* wake up DirverEntry */
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+
+ /* now process looping */
+ while (!IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP)) {
+
+ /* wait until it is waken or it times out */
+ if (NonWait) {
+ Timeout.QuadPart = (LONGLONG)-10*1000*100;
+ NonWait = FALSE;
+ } else if (DidNothing) {
+ Timeout.QuadPart = Timeout.QuadPart * 2;
+ } else {
+ Timeout.QuadPart = (LONGLONG)-10*1000*1000*20; /* 20 seconds */
+ }
+ KeWaitForSingleObject(
+ &Reaper->Wait,
+ Executive,
+ KernelMode,
+ FALSE,
+ &Timeout
+ );
+
+ if (IsFlagOn(Reaper->Flags, EXT2_REAPER_FLAG_STOP))
+ break;
+
+ InitializeListHead(&List);
+
+ /* acquire global exclusive lock */
+ ExAcquireResourceSharedLite(&Ext2Global->Resource, TRUE);
+ GlobalAcquired = TRUE;
+ /* search all Vcb to get unused resources freed to system */
+ for (Link = Ext2Global->VcbList.Flink;
+ Link != &(Ext2Global->VcbList);
+ Link = Link->Flink ) {
+
+ Vcb = CONTAINING_RECORD(Link, EXT2_VCB, Next);
+ NonWait = Ext2QueryUnusedFcb(Vcb, &List);
+ }
+ DidNothing = IsListEmpty(&List);
+ if (DidNothing) {
+ KeClearEvent(&Reaper->Wait);
+ }
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ GlobalAcquired = FALSE;
+ }
+
+ while (!IsListEmpty(&List)) {
+ PEXT2_FCB Fcb;
+ Link = RemoveHeadList(&List);
+ Fcb = CONTAINING_RECORD(Link, EXT2_FCB, Next);
+ ASSERT(0 == Fcb->ReferenceCount);
+ Ext2FreeFcb(Fcb);
+ }
+ }
+
+ } __finally {
+
+ if (GlobalAcquired) {
+ ExReleaseResourceLite(&Ext2Global->Resource);
+ }
+
+ KeSetEvent(&Reaper->Engine, 0, FALSE);
+ }
+
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+NTSTATUS
+Ext2StartReaper(PEXT2_REAPER Reaper, EXT2_REAPER_RELEASE Free)
+{
+ NTSTATUS status = STATUS_SUCCESS;
+ OBJECT_ATTRIBUTES oa;
+ HANDLE handle = 0;
+ LARGE_INTEGER timeout;
+
+ Reaper->Free = Free;
+
+ /* initialize wait event */
+ KeInitializeEvent(
+ &Reaper->Wait,
+ SynchronizationEvent, FALSE
+ );
+
+ /* Reaper thread engine event */
+ KeInitializeEvent(
+ &Reaper->Engine,
+ SynchronizationEvent, FALSE
+ );
+
+ /* initialize oa */
+ InitializeObjectAttributes(
+ &oa,
+ NULL,
+ OBJ_CASE_INSENSITIVE |
+ OBJ_KERNEL_HANDLE,
+ NULL,
+ NULL
+ );
+
+ /* start a new system thread */
+ status = PsCreateSystemThread(
+ &handle,
+ 0,
+ &oa,
+ NULL,
+ NULL,
+ Free,
+ (PVOID)Reaper
+ );
+
+ if (NT_SUCCESS(status)) {
+ ZwClose(handle);
+
+ /* make sure Reaperthread is started */
+ timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
+ status = KeWaitForSingleObject(
+ &Reaper->Engine,
+ Executive,
+ KernelMode,
+ FALSE,
+ &timeout
+ );
+ if (status != STATUS_SUCCESS) {
+ status = STATUS_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ return status;
+}
+
+
+VOID
+Ext2StopReaper(PEXT2_REAPER Reaper)
+{
+ LARGE_INTEGER timeout;
+
+ Reaper->Flags |= EXT2_REAPER_FLAG_STOP;
+ KeSetEvent(&Reaper->Wait, 0, FALSE);
+
+ /* make sure Reaperthread is started */
+ timeout.QuadPart = (LONGLONG)-10*1000*1000*2; /* 2 seconds */
+ KeWaitForSingleObject(
+ &Reaper->Engine,
+ Executive,
+ KernelMode,
+ FALSE,
+ &timeout);
+}