Bring back ext2 code from branch
authorHervé Poussineau <hpoussin@reactos.org>
Mon, 11 Feb 2008 12:10:35 +0000 (12:10 +0000)
committerHervé Poussineau <hpoussin@reactos.org>
Mon, 11 Feb 2008 12:10:35 +0000 (12:10 +0000)
It does not compile yet

svn path=/trunk/; revision=32283

43 files changed:
1  2 
reactos/drivers/filesystems/ext2/ext2fs.rc
reactos/drivers/filesystems/ext2/inc/errmsg.h
reactos/drivers/filesystems/ext2/inc/ext2_fs.h
reactos/drivers/filesystems/ext2/inc/ext2fsd.h
reactos/drivers/filesystems/ext2/inc/ext2metadata.h
reactos/drivers/filesystems/ext2/inc/protos.h
reactos/drivers/filesystems/ext2/inc/resource.h
reactos/drivers/filesystems/ext2/inc/struct.h
reactos/drivers/filesystems/ext2/src/DiskIO.c
reactos/drivers/filesystems/ext2/src/cleanup.c
reactos/drivers/filesystems/ext2/src/close.c
reactos/drivers/filesystems/ext2/src/create.c
reactos/drivers/filesystems/ext2/src/devcntrl.c
reactos/drivers/filesystems/ext2/src/dircntrl.c
reactos/drivers/filesystems/ext2/src/ext2.rc
reactos/drivers/filesystems/ext2/src/ext2init.c
reactos/drivers/filesystems/ext2/src/fastio.c
reactos/drivers/filesystems/ext2/src/fileinfo.c
reactos/drivers/filesystems/ext2/src/flush.c
reactos/drivers/filesystems/ext2/src/fsctrl.c
reactos/drivers/filesystems/ext2/src/io.c
reactos/drivers/filesystems/ext2/src/metadata.c
reactos/drivers/filesystems/ext2/src/misc.c
reactos/drivers/filesystems/ext2/src/read.c
reactos/drivers/filesystems/ext2/src/shutdown.c
reactos/drivers/filesystems/ext2/src/volinfo.c
reactos/drivers/filesystems/ext2/src/write.c
reactos/drivers/filesystems/fs_rec/ext2.c
reactos/include/reactos/libs/fslib/ext2lib.h
reactos/lib/fslib/ext2lib/Badblock.c
reactos/lib/fslib/ext2lib/Bitmap.c
reactos/lib/fslib/ext2lib/Bitmap.h
reactos/lib/fslib/ext2lib/Disk.c
reactos/lib/fslib/ext2lib/Disk.h
reactos/lib/fslib/ext2lib/Group.c
reactos/lib/fslib/ext2lib/Inode.c
reactos/lib/fslib/ext2lib/Memory.c
reactos/lib/fslib/ext2lib/Mke2fs.c
reactos/lib/fslib/ext2lib/Mke2fs.h
reactos/lib/fslib/ext2lib/Super.c
reactos/lib/fslib/ext2lib/Uuid.c
reactos/lib/fslib/ext2lib/ext2_fs.h
reactos/lib/fslib/ext2lib/types.h

index 0000000,0000000..0cbc172
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++/* $Id: ext2fs.rc 12852 2005-01-06 13:58:04Z mf $ */
++
++#define REACTOS_VERSION_DLL
++#define REACTOS_STR_FILE_DESCRIPTION  "Linux ext2 IFS Driver\0"
++#define REACTOS_STR_INTERNAL_NAME     "ext2fs\0"
++#define REACTOS_STR_ORIGINAL_FILENAME "ext2fs.sys\0"
++#include <reactos/version.rc>
index 0000000,0000000..8f8ac96
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,68 @@@
++/*************************************************************************
++*
++* File:               errmsg.msg
++*
++* Product:            Ext2 FSD
++*
++* Module:             Ext2 FSD Event Log Messages
++*
++* Description:
++*     Contains error strings in a format understandable to the message compiler.
++*     Please compile (using mc) with the -c option which will set the
++*     "Customer" bit in all errors.
++*     Use values beginning at 0xA000 (e.g. 0xA001) for the Ext2 FSD
++*     errors.
++*     Do NOT use %1 for insertion strings. The I/O manager assumes that
++*     the first insertion string is the name of the driver/device.
++*
++*
++*************************************************************************/
++//
++//  Values are 32 bit values layed out as follows:
++//
++//   3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
++//   1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
++//  +---+-+-+-----------------------+-------------------------------+
++//  |Sev|C|R|     Facility          |               Code            |
++//  +---+-+-+-----------------------+-------------------------------+
++//
++//  where
++//
++//      Sev - is the severity code
++//
++//          00 - Success
++//          01 - Informational
++//          10 - Warning
++//          11 - Error
++//
++//      C - is the Customer code flag
++//
++//      R - is a reserved bit
++//
++//      Facility - is the facility code
++//
++//      Code - is the facility's status code
++//
++//
++// Define the facility codes
++//
++
++
++//
++// Define the severity codes
++//
++#define STATUS_SEVERITY_WARNING          0x2
++#define STATUS_SEVERITY_SUCCESS          0x0
++#define STATUS_SEVERITY_INFORMATIONAL    0x1
++#define STATUS_SEVERITY_ERROR            0x3
++
++
++//
++// MessageId: EXT2_ERROR_INTERNAL_ERROR
++//
++// MessageText:
++//
++//  The Ext2 FSD encountered an internal error. Please check log data information.
++//
++#define EXT2_ERROR_INTERNAL_ERROR        ((ULONG)0xE004A001L)
++
index 0000000,0000000..4a545d4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,615 @@@
++/*
++ *  linux/include/linux/ext2_fs.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 _LINUX_EXT2_FS_H
++#define _LINUX_EXT2_FS_H
++
++//    #include <linux/types.h>
++
++/*
++ * The second extended filesystem constants/structures
++ */
++
++
++/*
++ * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
++ */
++#define EXT2_PREALLOCATE
++#define EXT2_DEFAULT_PREALLOC_BLOCKS  8
++
++/*
++ * The second extended file system version
++ */
++#define EXT2FS_DATE           "95/08/09"
++#define EXT2FS_VERSION                "0.5b"
++
++/*
++ * Debug code
++ */
++
++/*
++ * Special inodes numbers
++ */
++#define       EXT2_BAD_INO             1      /* Bad blocks inode */
++#define EXT2_ROOT_INO          2      /* Root inode */
++#define EXT2_ACL_IDX_INO       3      /* ACL inode */
++#define EXT2_ACL_DATA_INO      4      /* ACL inode */
++#define EXT2_BOOT_LOADER_INO   5      /* Boot loader inode */
++#define EXT2_UNDEL_DIR_INO     6      /* Undelete directory inode */
++
++/* First non-reserved inode for old ext2 filesystems */
++#define EXT2_GOOD_OLD_FIRST_INO       11
++
++/*
++ * The second extended file system magic number
++ */
++#define EXT2_SUPER_MAGIC      0xEF53
++
++/*
++ * Maximal count of links to a file
++ */
++#define EXT2_LINK_MAX         32000
++
++/*
++ * Macro-instructions used to manage several block sizes
++ */
++#define EXT2_MIN_BLOCK_SIZE           1024
++#define       EXT2_MAX_BLOCK_SIZE             4096
++#define EXT2_MIN_BLOCK_LOG_SIZE                 10
++#ifdef __KERNEL__
++# define EXT2_BLOCK_SIZE(s)           ((s)->s_blocksize)
++#else
++# define EXT2_BLOCK_SIZE(s)           (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
++#endif
++#define EXT2_ACLE_PER_BLOCK(s)                (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
++#define       EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
++#ifdef __KERNEL__
++# define EXT2_BLOCK_SIZE_BITS(s)      ((s)->s_blocksize_bits)
++#else
++# define EXT2_BLOCK_SIZE_BITS(s)      ((s)->s_log_block_size + 10)
++#endif
++#ifdef __KERNEL__
++#define       EXT2_ADDR_PER_BLOCK_BITS(s)     ((s)->u.ext2_sb.s_addr_per_block_bits)
++#define EXT2_INODE_SIZE(s)            ((s)->u.ext2_sb.s_inode_size)
++#define EXT2_FIRST_INO(s)             ((s)->u.ext2_sb.s_first_ino)
++#else
++#define EXT2_INODE_SIZE(s)    (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
++                               EXT2_GOOD_OLD_INODE_SIZE : \
++                               (s)->s_inode_size)
++#define EXT2_FIRST_INO(s)     (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
++                               EXT2_GOOD_OLD_FIRST_INO : \
++                               (s)->s_first_ino)
++#endif
++
++/*
++ * Macro-instructions used to manage fragments
++ */
++#define EXT2_MIN_FRAG_SIZE            1024
++#define       EXT2_MAX_FRAG_SIZE              4096
++#define EXT2_MIN_FRAG_LOG_SIZE                  10
++#ifdef __KERNEL__
++# define EXT2_FRAG_SIZE(s)            ((s)->u.ext2_sb.s_frag_size)
++# define EXT2_FRAGS_PER_BLOCK(s)      ((s)->u.ext2_sb.s_frags_per_block)
++#else
++# define EXT2_FRAG_SIZE(s)            (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
++# define EXT2_FRAGS_PER_BLOCK(s)      (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
++#endif
++
++/*
++ * ACL structures
++ */
++struct ext2_acl_header        /* Header of Access Control Lists */
++{
++      __u32   aclh_size;
++      __u32   aclh_file_count;
++      __u32   aclh_acle_count;
++      __u32   aclh_first_acle;
++};
++
++struct ext2_acl_entry /* Access Control List Entry */
++{
++      __u32   acle_size;
++      __u16   acle_perms;     /* Access permissions */
++      __u16   acle_type;      /* Type of entry */
++      __u16   acle_tag;       /* User or group identity */
++      __u16   acle_pad1;
++      __u32   acle_next;      /* Pointer on next entry for the */
++                                      /* same inode or on next free entry */
++};
++
++/*
++ * Structure of a blocks group descriptor
++ */
++struct ext2_group_desc
++{
++      __u32   bg_block_bitmap;                /* Blocks bitmap block */
++      __u32   bg_inode_bitmap;                /* Inodes bitmap block */
++      __u32   bg_inode_table;         /* Inodes table block */
++      __u16   bg_free_blocks_count;   /* Free blocks count */
++      __u16   bg_free_inodes_count;   /* Free inodes count */
++      __u16   bg_used_dirs_count;     /* Directories count */
++      __u16   bg_pad;
++      __u32   bg_reserved[3];
++};
++
++/*
++ * Macro-instructions used to manage group descriptors
++ */
++#ifdef __KERNEL__
++# define EXT2_BLOCKS_PER_GROUP(s)     ((s)->u.ext2_sb.s_blocks_per_group)
++# define EXT2_DESC_PER_BLOCK(s)               ((s)->u.ext2_sb.s_desc_per_block)
++# define EXT2_INODES_PER_GROUP(s)     ((s)->u.ext2_sb.s_inodes_per_group)
++# define EXT2_DESC_PER_BLOCK_BITS(s)  ((s)->u.ext2_sb.s_desc_per_block_bits)
++#else
++# define EXT2_BLOCKS_PER_GROUP(s)     ((s)->s_blocks_per_group)
++# define EXT2_DESC_PER_BLOCK(s)               (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
++# define EXT2_INODES_PER_GROUP(s)     ((s)->s_inodes_per_group)
++#endif
++
++/*
++ * Constants relative to the data blocks
++ */
++#define       EXT2_NDIR_BLOCKS                12
++#define       EXT2_IND_BLOCK                  EXT2_NDIR_BLOCKS
++#define       EXT2_DIND_BLOCK                 (EXT2_IND_BLOCK + 1)
++#define       EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
++#define       EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
++
++/*
++ * Inode flags
++ */
++#define       EXT2_SECRM_FL                   0x00000001 /* Secure deletion */
++#define       EXT2_UNRM_FL                    0x00000002 /* Undelete */
++#define       EXT2_COMPR_FL                   0x00000004 /* Compress file */
++#define EXT2_SYNC_FL                  0x00000008 /* Synchronous updates */
++#define EXT2_IMMUTABLE_FL             0x00000010 /* Immutable file */
++#define EXT2_APPEND_FL                        0x00000020 /* writes to file may only append */
++#define EXT2_NODUMP_FL                        0x00000040 /* do not dump file */
++#define EXT2_NOATIME_FL                       0x00000080 /* do not update atime */
++/* Reserved for compression usage... */
++#define EXT2_DIRTY_FL                 0x00000100
++#define EXT2_COMPRBLK_FL              0x00000200 /* One or more compressed clusters */
++#define EXT2_NOCOMP_FL                        0x00000400 /* Don't compress */
++#define EXT2_ECOMPR_FL                        0x00000800 /* Compression error */
++/* End compression flags --- maybe not all used */    
++#define EXT2_BTREE_FL                 0x00001000 /* btree format dir */
++#define EXT2_RESERVED_FL              0x80000000 /* reserved for ext2 lib */
++
++#define EXT2_FL_USER_VISIBLE          0x00001FFF /* User visible flags */
++#define EXT2_FL_USER_MODIFIABLE               0x000000FF /* User modifiable flags */
++
++/*
++ * ioctl commands
++ */
++#define       EXT2_IOC_GETFLAGS               _IOR('f', 1, long)
++#define       EXT2_IOC_SETFLAGS               _IOW('f', 2, long)
++#define       EXT2_IOC_GETVERSION             _IOR('v', 1, long)
++#define       EXT2_IOC_SETVERSION             _IOW('v', 2, long)
++
++/*
++ * Structure of an inode on the disk
++ */
++struct ext2_inode {
++      __u16   i_mode;         /* File mode */
++      __u16   i_uid;          /* Low 16 bits of Owner Uid */
++      __u32   i_size;         /* Size in bytes */
++      __u32   i_atime;        /* Access time */
++      __u32   i_ctime;        /* Creation time */
++      __u32   i_mtime;        /* Modification time */
++      __u32   i_dtime;        /* Deletion Time */
++      __u16   i_gid;          /* Low 16 bits of Group Id */
++      __u16   i_links_count;  /* Links count */
++      __u32   i_blocks;       /* Blocks count */
++      __u32   i_flags;        /* File flags */
++      union {
++              struct {
++                      __u32  l_i_reserved1;
++              } linux1;
++              struct {
++                      __u32  h_i_translator;
++              } hurd1;
++              struct {
++                      __u32  m_i_reserved1;
++              } masix1;
++      } osd1;                         /* OS dependent 1 */
++      __u32   i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
++      __u32   i_generation;   /* File version (for NFS) */
++      __u32   i_file_acl;     /* File ACL */
++      __u32   i_dir_acl;      /* Directory ACL */
++      __u32   i_faddr;        /* Fragment address */
++      union {
++              struct {
++                      __u8    l_i_frag;       /* Fragment number */
++                      __u8    l_i_fsize;      /* Fragment size */
++                      __u16   i_pad1;
++                      __u16   l_i_uid_high;   /* these 2 fields    */
++                      __u16   l_i_gid_high;   /* were reserved2[0] */
++                      __u32   l_i_reserved2;
++              } linux2;
++              struct {
++                      __u8    h_i_frag;       /* Fragment number */
++                      __u8    h_i_fsize;      /* Fragment size */
++                      __u16   h_i_mode_high;
++                      __u16   h_i_uid_high;
++                      __u16   h_i_gid_high;
++                      __u32   h_i_author;
++              } hurd2;
++              struct {
++                      __u8    m_i_frag;       /* Fragment number */
++                      __u8    m_i_fsize;      /* Fragment size */
++                      __u16   m_pad1;
++                      __u32   m_i_reserved2[2];
++              } masix2;
++      } osd2;                         /* OS dependent 2 */
++};
++
++#define i_size_high   i_dir_acl
++
++#if defined(__KERNEL__) || defined(__linux__)
++#define i_reserved1   osd1.linux1.l_i_reserved1
++#define i_frag                osd2.linux2.l_i_frag
++#define i_fsize               osd2.linux2.l_i_fsize
++#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_reserved2   osd2.linux2.l_i_reserved2
++#endif
++
++#ifdef        __hurd__
++#define i_translator  osd1.hurd1.h_i_translator
++#define i_frag                osd2.hurd2.h_i_frag;
++#define i_fsize               osd2.hurd2.h_i_fsize;
++#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
++#endif
++
++#ifdef        __masix__
++#define i_reserved1   osd1.masix1.m_i_reserved1
++#define i_frag                osd2.masix2.m_i_frag
++#define i_fsize               osd2.masix2.m_i_fsize
++#define i_reserved2   osd2.masix2.m_i_reserved2
++#endif
++
++/*
++ * File system states
++ */
++#define       EXT2_VALID_FS                   0x0001  /* Unmounted cleanly */
++#define       EXT2_ERROR_FS                   0x0002  /* Errors detected */
++
++/*
++ * Mount flags
++ */
++#define EXT2_MOUNT_CHECK              0x0001  /* Do mount-time checks */
++#define EXT2_MOUNT_GRPID              0x0004  /* Create files with directory's group */
++#define EXT2_MOUNT_DEBUG              0x0008  /* Some debugging messages */
++#define EXT2_MOUNT_ERRORS_CONT                0x0010  /* Continue on errors */
++#define EXT2_MOUNT_ERRORS_RO          0x0020  /* Remount fs ro on errors */
++#define EXT2_MOUNT_ERRORS_PANIC               0x0040  /* Panic on errors */
++#define EXT2_MOUNT_MINIX_DF           0x0080  /* Mimics the Minix statfs */
++#define EXT2_MOUNT_NO_UID32           0x0200  /* Disable 32-bit UIDs */
++
++#define clear_opt(o, opt)             o &= ~EXT2_MOUNT_##opt
++#define set_opt(o, opt)                       o |= EXT2_MOUNT_##opt
++#define test_opt(sb, opt)             ((sb)->u.ext2_sb.s_mount_opt & \
++                                       EXT2_MOUNT_##opt)
++/*
++ * Maximal mount counts between two filesystem checks
++ */
++#define EXT2_DFL_MAX_MNT_COUNT                20      /* Allow 20 mounts */
++#define EXT2_DFL_CHECKINTERVAL                0       /* Don't use interval check */
++
++/*
++ * Behaviour when detecting errors
++ */
++#define EXT2_ERRORS_CONTINUE          1       /* Continue execution */
++#define EXT2_ERRORS_RO                        2       /* Remount fs read-only */
++#define EXT2_ERRORS_PANIC             3       /* Panic */
++#define EXT2_ERRORS_DEFAULT           EXT2_ERRORS_CONTINUE
++
++/*
++ * Structure of the super block
++ */
++struct ext2_super_block {
++      __u32   s_inodes_count;         /* Inodes count */
++      __u32   s_blocks_count;         /* Blocks count */
++      __u32   s_r_blocks_count;       /* Reserved blocks count */
++      __u32   s_free_blocks_count;    /* Free blocks count */
++      __u32   s_free_inodes_count;    /* Free inodes count */
++      __u32   s_first_data_block;     /* First Data Block */
++      __u32   s_log_block_size;       /* Block size */
++      __s32   s_log_frag_size;        /* Fragment size */
++      __u32   s_blocks_per_group;     /* # Blocks per group */
++      __u32   s_frags_per_group;      /* # Fragments per group */
++      __u32   s_inodes_per_group;     /* # Inodes per group */
++      __u32   s_mtime;                /* Mount time */
++      __u32   s_wtime;                /* Write time */
++      __u16   s_mnt_count;            /* Mount count */
++      __s16   s_max_mnt_count;        /* Maximal mount count */
++      __u16   s_magic;                /* Magic signature */
++      __u16   s_state;                /* File system state */
++      __u16   s_errors;               /* Behaviour when detecting errors */
++      __u16   s_minor_rev_level;      /* minor revision level */
++      __u32   s_lastcheck;            /* time of last check */
++      __u32   s_checkinterval;        /* max. time between checks */
++      __u32   s_creator_os;           /* OS */
++      __u32   s_rev_level;            /* Revision level */
++      __u16   s_def_resuid;           /* Default uid for reserved blocks */
++      __u16   s_def_resgid;           /* Default gid for reserved blocks */
++      /*
++       * These fields are for EXT2_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...
++       */
++      __u32   s_first_ino;            /* First non-reserved inode */
++      __u16   s_inode_size;           /* size of inode structure */
++      __u16   s_block_group_nr;       /* block group # of this superblock */
++      __u32   s_feature_compat;       /* compatible feature set */
++      __u32   s_feature_incompat;     /* incompatible feature set */
++      __u32   s_feature_ro_compat;    /* readonly-compatible feature set */
++      __u8    s_uuid[16];             /* 128-bit uuid for volume */
++      char    s_volume_name[16];      /* volume name */
++      char    s_last_mounted[64];     /* directory where last mounted */
++      __u32   s_algorithm_usage_bitmap; /* For compression */
++      /*
++       * Performance hints.  Directory preallocation should only
++       * happen if the EXT2_COMPAT_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 */
++      __u16   s_padding1;
++      __u32   s_reserved[204];        /* Padding to the end of the block */
++};
++
++#ifdef __KERNEL__
++#define EXT2_SB(sb)   (&((sb)->u.ext2_sb))
++#else
++/* Assume that user mode programs are passing in an ext2fs superblock, not
++ * a kernel struct super_block.  This will allow us to call the feature-test
++ * macros from user land. */
++#define EXT2_SB(sb)   (sb)
++#endif
++
++/*
++ * Codes for operating systems
++ */
++#define EXT2_OS_LINUX         0
++#define EXT2_OS_HURD          1
++#define EXT2_OS_MASIX         2
++#define EXT2_OS_FREEBSD               3
++#define EXT2_OS_LITES         4
++
++/*
++ * Revision levels
++ */
++#define EXT2_GOOD_OLD_REV     0       /* The good old (original) format */
++#define EXT2_DYNAMIC_REV      1       /* V2 format w/ dynamic inode sizes */
++
++#define EXT2_CURRENT_REV      EXT2_GOOD_OLD_REV
++#define EXT2_MAX_SUPP_REV     EXT2_DYNAMIC_REV
++
++#define EXT2_GOOD_OLD_INODE_SIZE 128
++
++/*
++ * Feature set definitions
++ */
++
++#define EXT2_HAS_COMPAT_FEATURE(sb,mask)                      \
++      ( EXT2_SB(sb)->s_es->s_feature_compat & cpu_to_le32(mask) )
++#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)                   \
++      ( EXT2_SB(sb)->s_es->s_feature_ro_compat & cpu_to_le32(mask) )
++#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)                    \
++      ( EXT2_SB(sb)->s_es->s_feature_incompat & cpu_to_le32(mask) )
++#define EXT2_SET_COMPAT_FEATURE(sb,mask)                      \
++      EXT2_SB(sb)->s_es->s_feature_compat |= cpu_to_le32(mask)
++#define EXT2_SET_RO_COMPAT_FEATURE(sb,mask)                   \
++      EXT2_SB(sb)->s_es->s_feature_ro_compat |= cpu_to_le32(mask)
++#define EXT2_SET_INCOMPAT_FEATURE(sb,mask)                    \
++      EXT2_SB(sb)->s_es->s_feature_incompat |= cpu_to_le32(mask)
++#define EXT2_CLEAR_COMPAT_FEATURE(sb,mask)                    \
++      EXT2_SB(sb)->s_es->s_feature_compat &= ~cpu_to_le32(mask)
++#define EXT2_CLEAR_RO_COMPAT_FEATURE(sb,mask)                 \
++      EXT2_SB(sb)->s_es->s_feature_ro_compat &= ~cpu_to_le32(mask)
++#define EXT2_CLEAR_INCOMPAT_FEATURE(sb,mask)                  \
++      EXT2_SB(sb)->s_es->s_feature_incompat &= ~cpu_to_le32(mask)
++
++#define EXT2_FEATURE_COMPAT_DIR_PREALLOC      0x0001
++
++#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER   0x0001
++#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE     0x0002
++#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR      0x0004
++
++#define EXT2_FEATURE_INCOMPAT_COMPRESSION     0x0001
++#define EXT2_FEATURE_INCOMPAT_FILETYPE                0x0002
++
++#define EXT2_FEATURE_COMPAT_SUPP      0
++#define EXT2_FEATURE_INCOMPAT_SUPP    EXT2_FEATURE_INCOMPAT_FILETYPE
++#define EXT2_FEATURE_RO_COMPAT_SUPP   (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
++                                       EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
++                                       EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
++
++/*
++ * Default values for user and/or group using reserved blocks
++ */
++#define       EXT2_DEF_RESUID         0
++#define       EXT2_DEF_RESGID         0
++
++/*
++ * Structure of a directory entry
++ */
++#define EXT2_NAME_LEN 255
++
++struct ext2_dir_entry {
++      __u32   inode;                  /* Inode number */
++      __u16   rec_len;                /* Directory entry length */
++      __u16   name_len;               /* Name length */
++      char    name[EXT2_NAME_LEN];    /* File name */
++};
++
++/*
++ * The new version of the directory entry.  Since EXT2 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 ext2_dir_entry_2 {
++      __u32   inode;                  /* Inode number */
++      __u16   rec_len;                /* Directory entry length */
++      __u8    name_len;               /* Name length */
++      __u8    file_type;
++      char    name[EXT2_NAME_LEN];    /* File name */
++};
++
++/*
++ * Ext2 directory file types.  Only the low 3 bits are used.  The
++ * other bits are reserved for now.
++ */
++#define EXT2_FT_UNKNOWN               0
++#define EXT2_FT_REG_FILE      1
++#define EXT2_FT_DIR                   2
++#define EXT2_FT_CHRDEV                3
++#define EXT2_FT_BLKDEV                4
++#define EXT2_FT_FIFO          5
++#define EXT2_FT_SOCK          6
++#define EXT2_FT_SYMLINK               7
++
++#define EXT2_FT_MAX           8
++
++/*
++ * EXT2_DIR_PAD defines the directory entries boundaries
++ *
++ * NOTE: It must be a multiple of 4
++ */
++#define EXT2_DIR_PAD                  4
++#define EXT2_DIR_ROUND                        (EXT2_DIR_PAD - 1)
++#define EXT2_DIR_REC_LEN(name_len)    (((name_len) + 8 + EXT2_DIR_ROUND) & \
++                                       ~EXT2_DIR_ROUND)
++
++#ifdef __KERNEL__
++/*
++ * Function prototypes
++ */
++
++/*
++ * Ok, these declarations are also in <linux/kernel.h> but none of the
++ * ext2 source programs needs to include it so they are duplicated here.
++ */
++# define NORET_TYPE    /**/
++# define ATTRIB_NORET  __attribute__((noreturn))
++# define NORET_AND     noreturn,
++
++/* acl.c */
++extern int ext2_permission (struct inode *, int);
++
++/* balloc.c */
++extern int ext2_bg_has_super(struct super_block *sb, int group);
++extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
++extern int ext2_new_block (struct inode *, unsigned long,
++                         __u32 *, __u32 *, int *);
++extern void ext2_free_blocks (struct inode *, unsigned long,
++                            unsigned long);
++extern unsigned long ext2_count_free_blocks (struct super_block *);
++extern void ext2_check_blocks_bitmap (struct super_block *);
++extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
++                                                  unsigned int block_group,
++                                                  struct buffer_head ** bh);
++
++/* bitmap.c */
++extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
++
++/* dir.c */
++extern int ext2_check_dir_entry (const char *, struct inode *,
++                               struct ext2_dir_entry_2 *, struct buffer_head *,
++                               unsigned long);
++
++/* file.c */
++extern int ext2_read (struct inode *, struct file *, char *, int);
++extern int ext2_write (struct inode *, struct file *, char *, int);
++
++/* fsync.c */
++extern int ext2_sync_file (struct file *, struct dentry *, int);
++extern int ext2_fsync_inode (struct inode *, int);
++
++/* ialloc.c */
++extern struct inode * ext2_new_inode (const struct inode *, int);
++extern void ext2_free_inode (struct inode *);
++extern unsigned long ext2_count_free_inodes (struct super_block *);
++extern void ext2_check_inodes_bitmap (struct super_block *);
++
++/* inode.c */
++
++extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
++extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
++
++extern void ext2_read_inode (struct inode *);
++extern void ext2_write_inode (struct inode *, int);
++extern void ext2_put_inode (struct inode *);
++extern void ext2_delete_inode (struct inode *);
++extern int ext2_sync_inode (struct inode *);
++extern void ext2_discard_prealloc (struct inode *);
++
++/* ioctl.c */
++extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
++                     unsigned long);
++
++/* namei.c */
++extern struct inode_operations ext2_dir_inode_operations;
++
++/* super.c */
++extern void ext2_error (struct super_block *, const char *, const char *, ...)
++      __attribute__ ((format (printf, 3, 4)));
++extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
++                                 const char *, ...)
++      __attribute__ ((NORET_AND format (printf, 3, 4)));
++extern void ext2_warning (struct super_block *, const char *, const char *, ...)
++      __attribute__ ((format (printf, 3, 4)));
++extern void ext2_update_dynamic_rev (struct super_block *sb);
++extern void ext2_put_super (struct super_block *);
++extern void ext2_write_super (struct super_block *);
++extern int ext2_remount (struct super_block *, int *, char *);
++extern struct super_block * ext2_read_super (struct super_block *,void *,int);
++extern int ext2_statfs (struct super_block *, struct statfs *);
++
++/* truncate.c */
++extern void ext2_truncate (struct inode *);
++
++/*
++ * Inodes and files operations
++ */
++
++/* dir.c */
++extern struct file_operations ext2_dir_operations;
++
++/* file.c */
++extern struct inode_operations ext2_file_inode_operations;
++extern struct file_operations ext2_file_operations;
++
++/* symlink.c */
++extern struct inode_operations ext2_fast_symlink_inode_operations;
++
++extern struct address_space_operations ext2_aops;
++
++#endif        /* __KERNEL__ */
++
++#endif        /* _LINUX_EXT2_FS_H */
index 0000000,0000000..81c246d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,250 @@@
++/*************************************************************************
++*
++* File: ext2fsd.h
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     The main include file for the Ext2 file system driver.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++
++#ifndef       _EXT2_FSD_H_
++#define       _EXT2_FSD_H_
++
++#define EXT2_POOL_WITH_TAG
++
++
++// some constant definitions
++#define       EXT2_PANIC_IDENTIFIER           (0x86427531)
++
++// any directory information EXT2 obtains from the local file system
++//    will use a buffer of the following size ... (in KB)
++#define       EXT2_READ_DIR_BUFFER_LENGTH     (512)
++#define       EXT2_MAXCLOSABLE_FCBS_UL        20
++#define       EXT2_MAXCLOSABLE_FCBS_LL        10
++
++//    Some type definitions...
++//    These are used later...
++
++typedef unsigned char UCHAR;
++typedef unsigned int  UINT;
++typedef UCHAR                 BYTE;
++typedef UCHAR                 BOOLEAN;        // winnt
++typedef BOOLEAN *             PBOOLEAN;       // winnt
++typedef void *                        PVOID64;                // winnt
++typedef long                  LONG;
++typedef LONG                  HRESULT;
++
++
++#if defined(_M_IX86)
++#define FASTCALL _fastcall
++#else
++#define FASTCALL
++#endif
++
++
++
++// Common include files - should be in the include dir of the MS supplied IFS Kit
++#include      <ntifs.h>
++#include <ntdddisk.h>
++
++
++/* REACTOS FIXME */
++#undef DeleteFile
++/* This is deprecated and should be changed in the EXT2FS driver. */
++#define RtlLargeIntegerLessThan(a, b) (a).QuadPart < (b).QuadPart
++#define RtlLargeIntegerGreaterThan(a, b) (a).QuadPart > (b).QuadPart
++
++
++// the following include files should be in the inc sub-dir associated with this driver
++#include      "ext2metadata.h"
++#include      "struct.h"
++#include      "protos.h"
++#include      "errmsg.h"
++
++
++// global variables - minimize these
++extern Ext2Data                               Ext2GlobalData;
++
++// try-finally simulation
++#define try_return(S) { S; goto try_exit; }
++#define try_return1(S)        { S; goto try_exit1; }
++#define try_return2(S)        { S; goto try_exit2; }
++
++// some global (helpful) macros
++#define Ext2IsFlagOn(Flags,SingleFlag) ((BOOLEAN)((((Flags) & (SingleFlag)) != 0)))
++#define       Ext2SetFlag(Flag, Value)        ((Flag) |= (Value))
++#define       Ext2ClearFlag(Flag, Value)      ((Flag) &= ~(Value))
++
++#define       Ext2QuadAlign(Value)                    ((((uint32)(Value)) + 7) & 0xfffffff8)
++
++// to perform a bug-check (panic), the following macro is used
++#define       Ext2Panic(arg1, arg2, arg3)                                     \
++      (KeBugCheckEx(EXT2_PANIC_IDENTIFIER, EXT2_BUG_CHECK_ID | __LINE__, (uint32)(arg1), (uint32)(arg2), (uint32)(arg3)))
++
++// a convenient macro (must be invoked in the context of the thread that acquired the resource)
++#define       Ext2ReleaseResource(Resource)   \
++      (ExReleaseResourceForThreadLite((Resource), ExGetCurrentResourceThread()))
++
++// each file has a unique bug-check identifier associated with it.
++//    Here is a list of constant definitions for these identifiers
++#define       EXT2_FILE_INIT                                                                  (0x00000001)
++#define       EXT2_FILE_REGISTRY                                                              (0x00000002)
++#define       EXT2_FILE_CREATE                                                                (0x00000003)
++#define       EXT2_FILE_CLEANUP                                                               (0x00000004)
++#define       EXT2_FILE_CLOSE                                                                 (0x00000005)
++#define       EXT2_FILE_READ                                                                  (0x00000006)
++#define       EXT2_FILE_WRITE                                                                 (0x00000007)
++#define       EXT2_FILE_INFORMATION                                                   (0x00000008)
++#define       EXT2_FILE_FLUSH                                                                 (0x00000009)
++#define       EXT2_FILE_VOL_INFORMATION                                               (0x0000000A)
++#define       EXT2_FILE_DIR_CONTROL                                                   (0x0000000B)
++#define       EXT2_FILE_FILE_CONTROL                                                  (0x0000000C)
++#define       EXT2_FILE_DEVICE_CONTROL                                                (0x0000000D)
++#define       EXT2_FILE_SHUTDOWN                                                              (0x0000000E)
++#define       EXT2_FILE_LOCK_CONTROL                                                  (0x0000000F)
++#define       EXT2_FILE_SECURITY                                                              (0x00000010)
++#define       EXT2_FILE_EXT_ATTR                                                              (0x00000011)
++#define       EXT2_FILE_MISC                                                                  (0x00000012)
++#define       EXT2_FILE_FAST_IO                                                               (0x00000013)
++#define       EXT2_FILE_IO                                                                    (0x00000014)
++#define       EXT2_FILE_METADATA_IO                                                   (0x00000015)
++
++
++
++#if DBG
++#define       Ext2BreakPoint()        DbgBreakPoint()
++#else
++#define       Ext2BreakPoint()
++#endif
++
++#define Ext2RaiseStatus(IRPCONTEXT,STATUS)            \
++{                                                                                             \
++    (IRPCONTEXT)->ExceptionStatus = (STATUS); \
++    ExRaiseStatus( (STATUS) );                                        \
++}
++
++#ifdef EXT2_POOL_WITH_TAG
++      #define Ext2AllocatePool(PoolType,NumberOfBytes)        \
++              ExAllocatePoolWithTag( PoolType, NumberOfBytes, '2txE' ) 
++#else
++      #define Ext2AllocatePool(PoolType,NumberOfBytes)        \
++              ExAllocatePool( PoolType, NumberOfBytes ) 
++#endif
++
++
++#if DBG
++
++//
++//    Trace types...
++//    Any number of these may be enabled...
++//
++#define DEBUG_TRACE_IRQL                   (0x00000001)
++#define DEBUG_TRACE_IRP_ENTRY                  (0x00000002)
++#define DEBUG_TRACE_RESOURCE_ACQUIRE     (0x00000004)
++#define DEBUG_TRACE_RESOURCE_RELEASE     (0x00000008)
++#define DEBUG_TRACE_RESOURCE_RETRY             (0x00000010)
++#define DEBUG_TRACE_ASYNC                (0x00000020)
++#define DEBUG_TRACE_MOUNT                (0x00000040)
++#define DEBUG_TRACE_RESOURCE_STATE       (0x00000080)
++#define DEBUG_TRACE_MISC                 (0x00000100)
++#define DEBUG_TRACE_FILE_OBJ             (0x00000200)
++#define DEBUG_TRACE_FILE_NAME            (0x00000400)
++#define DEBUG_TRACE_SPECIAL              (0x00000800)
++#define DEBUG_TRACE_ERROR                              (0x00001000)
++#define DEBUG_TRACE_READ_DETAILS               (0x00002000)
++#define DEBUG_TRACE_WRITE_DETAILS              (0x00004000)
++#define DEBUG_TRACE_FILEINFO                   (0x00008000)
++#define DEBUG_TRACE_DIRINFO                            (0x00010000)
++#define DEBUG_TRACE_REFERENCE                  (0x00020000)
++#define DEBUG_TRACE_FSCTRL                             (0x00040000)
++#define DEBUG_TRACE_FREE                               (0x00080000)
++#define DEBUG_TRACE_LINENO                 (0x00100000)
++#define DEBUG_TRACE_TRIPLE                 (0x00200000)
++
++#define DEBUG_TRACE_ALL                                        (0xffffffff)
++#define DEBUG_TRACE_NONE                                        0
++//
++//    The permitted DebugTrace types...
++//
++#define PERMITTED_DEBUG_TRACE_TYPES           /* DEBUG_TRACE_TRIPLE */ DEBUG_TRACE_ALL
++/*
++#define PERMITTED_DEBUG_TRACE_TYPES           DEBUG_TRACE_ERROR | DEBUG_TRACE_IRP_ENTRY |             \
++                                                                              DEBUG_TRACE_FILE_NAME | DEBUG_TRACE_SPECIAL     |       \
++                                                                              DEBUG_TRACE_ASYNC
++
++*/
++
++
++#define DebugTrace( TYPE, X, Y )                                                                                      \
++{                                                                                                                                                     \
++      if( ( TYPE ) & ( PERMITTED_DEBUG_TRACE_TYPES ) )                                                \
++      {                                                                                                                                               \
++              DbgPrint("\n    ");                                                                                                     \
++              DbgPrint(X,Y);                                                                                                          \
++              if( ( DEBUG_TRACE_IRQL ) & ( PERMITTED_DEBUG_TRACE_TYPES ) )            \
++              {                                                                                                                                       \
++                      DbgPrint( "  IRQL = %d ", KeGetCurrentIrql( ) );                                \
++              }                                                                                                                                       \
++              if( ( DEBUG_TRACE_LINENO ) & ( PERMITTED_DEBUG_TRACE_TYPES ) )          \
++              {                                                                                                                                       \
++                      DbgPrint( "   [%s] Line No = %ld", __FILE__, __LINE__ );                \
++              }                                                                                                                                       \
++      }                                                                                                                                               \
++}
++
++
++#define DebugTraceState( STR, X1, X2, X3)                                                                                                             \
++{                                                                                                                                                                                             \
++      if( ( DEBUG_TRACE_RESOURCE_STATE ) & ( PERMITTED_DEBUG_TRACE_TYPES ) )                                          \
++      {                                                                                                                                                                                       \
++              DbgPrint("\nState: ");                                                                                                                                  \
++              DbgPrint( STR, X1, X2, X3 );                                                                                                                    \
++              if( ( DEBUG_TRACE_IRQL ) & ( PERMITTED_DEBUG_TRACE_TYPES ) )                                                    \
++              {                                                                                                                                                                               \
++                      DbgPrint( "  IRQL = %d ", KeGetCurrentIrql( ) );                                                                        \
++              }                                                                                                                                                                               \
++      }                                                                                                                                                                                       \
++}
++
++#define AssertFCB( PtrFCB )                                                                                                           \
++{                                                                                                                                                             \
++      if( !(PtrFCB) || (PtrFCB)->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB )      \
++      {                                                                                                                                                       \
++              Ext2BreakPoint();                                                                                                               \
++      }                                                                                                                                                       \
++}
++
++#define AssertVCB( PtrVCB )                                                                                                           \
++{                                                                                                                                                             \
++      if( !(PtrVCB) || (PtrVCB)->NodeIdentifier.NodeType != EXT2_NODE_TYPE_VCB )      \
++      {                                                                                                                                                       \
++              Ext2BreakPoint();                                                                                                               \
++      }                                                                                                                                                       \
++}
++
++#define AssertFCBorVCB( PtrVCBorFCB )                                                                                 \
++{                                                                                                                                                             \
++      if( !(PtrVCBorFCB) ||                                                                                                           \
++              ( (PtrVCBorFCB)->NodeIdentifier.NodeType != EXT2_NODE_TYPE_VCB &&               \
++                (PtrVCBorFCB)->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) )              \
++      {                                                                                                                                                       \
++              Ext2BreakPoint();                                                                                                               \
++      }                                                                                                                                                       \
++}
++
++#else
++      #define DebugTrace( TYPE, X, Y ) 
++      #define DebugTraceState( STR, X1, X2, X3 )
++      #define AssertFCB( PtrFCB )
++      #define AssertVCB( PtrVCB )
++      #define AssertFCBorVCB( PtrVCBorFCB )
++
++#endif
++
++#endif        // _EXT2_FSD_H_
index 0000000,0000000..bbe240e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,115 @@@
++/*************************************************************************
++*
++* File: ext2metadata.h
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Contains the definitions for the Ext2 Metadata structures.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#ifndef EXT2_METADATA_STRUCTURES
++#define EXT2_METADATA_STRUCTURES
++
++//
++//    Some type definitions...
++//    These are used in the ext2_fs.h header file
++//
++typedef unsigned int          __u32 ;
++typedef signed int                    __s32 ;
++typedef unsigned short int    __u16 ;
++typedef signed short int      __s16 ;
++typedef unsigned char         __u8 ;
++
++//
++//******************************************************
++//
++//    Using Remy Card's (slightly modified) Ext2 header...
++//    
++#include "ext2_fs.h"
++//
++//******************************************************
++//
++
++typedef struct ext2_super_block       EXT2_SUPER_BLOCK;
++typedef EXT2_SUPER_BLOCK *            PEXT2_SUPER_BLOCK;
++
++typedef struct ext2_inode             EXT2_INODE;
++typedef EXT2_INODE *                  PEXT2_INODE;
++
++typedef struct ext2_group_desc        EXT2_GROUP_DESCRIPTOR;
++typedef EXT2_GROUP_DESCRIPTOR *       PEXT2_GROUP_DESCRIPTOR;
++
++typedef struct ext2_dir_entry_2       EXT2_DIR_ENTRY;
++typedef EXT2_DIR_ENTRY *              PEXT2_DIR_ENTRY;
++
++//
++// Ext2 Supported File Types...
++//
++#define IMODE_FIFO            0x01
++#define IMODE_CHARDEV         0x02
++#define IMODE_DIR             0x04
++#define IMODE_BLOCKDEV        0x06
++#define IMODE_FILE            0x08
++#define IMODE_SLINK           0x0A
++#define IMODE_SOCKET          0x0C
++
++#define _MKMODE(m)                                     ( ( (m) >> 12 ) & 0x000F)
++#define Ext2IsModeRegularFile(m)       ( _MKMODE(m) == IMODE_FILE )
++#define Ext2IsModeDirectory(m)                 ( _MKMODE(m) == IMODE_DIR   )
++#define Ext2IsModeSymbolicLink(m)      ( _MKMODE(m) == IMODE_SLINK )
++#define Ext2IsModePipe(m)                      ( _MKMODE(m) == IMODE_FIFO )
++#define Ext2IsModeCharacterDevice(m) ( _MKMODE(m) == IMODE_CHARDEV )
++#define Ext2IsModeBlockDevice(m)       ( _MKMODE(m) == IMODE_BLOCKDEV )
++#define Ext2IsModeSocket(m)                    ( _MKMODE(m) == IMODE_SOCKET )
++
++#define Ext2IsModeHidden(m)                   ( (m & 0x124) == 0)     //      No Read Permission
++#define Ext2IsModeReadOnly(m)         ( (m & 0x92) == 0)      //      No write Permission
++
++#define Ext2SetModeHidden(m)          m = (m & (~0x124));     //      Turn off Read Permission
++#define Ext2SetModeReadOnly(m)                m = (m & (~0x92));      //      Turn off write Permission
++#define Ext2SetModeReadWrite(m)               m = (m & 0x1ff);        //      Set read/write Permission
++
++
++//
++//  Define the Packed and Unpacked BIOS Parameter Block
++//
++typedef struct _PACKED_BIOS_PARAMETER_BLOCK {
++    UCHAR  BytesPerSector[2];                       // offset = 0x000  0
++    UCHAR  SectorsPerCluster[1];                    // offset = 0x002  2
++    UCHAR  ReservedSectors[2];                      // offset = 0x003  3
++    UCHAR  Fats[1];                                 // offset = 0x005  5
++    UCHAR  RootEntries[2];                          // offset = 0x006  6
++    UCHAR  Sectors[2];                              // offset = 0x008  8
++    UCHAR  Media[1];                                // offset = 0x00A 10
++    UCHAR  SectorsPerFat[2];                        // offset = 0x00B 11
++    UCHAR  SectorsPerTrack[2];                      // offset = 0x00D 13
++    UCHAR  Heads[2];                                // offset = 0x00F 15
++    UCHAR  HiddenSectors[4];                        // offset = 0x011 17
++    UCHAR  LargeSectors[4];                         // offset = 0x015 21
++} PACKED_BIOS_PARAMETER_BLOCK;                      // sizeof = 0x019 25
++typedef PACKED_BIOS_PARAMETER_BLOCK *PPACKED_BIOS_PARAMETER_BLOCK;
++
++//
++//  Define the boot sector
++//
++typedef struct _PACKED_BOOT_SECTOR {
++    UCHAR Jump[3];                                  // offset = 0x000   0
++    UCHAR Oem[8];                                   // offset = 0x003   3
++    PACKED_BIOS_PARAMETER_BLOCK PackedBpb;          // offset = 0x00B  11
++    UCHAR PhysicalDriveNumber;                      // offset = 0x024  36
++    UCHAR CurrentHead;                              // offset = 0x025  37
++    UCHAR Signature;                                // offset = 0x026  38
++    UCHAR Id[4];                                    // offset = 0x027  39
++    UCHAR VolumeLabel[11];                          // offset = 0x02B  43
++    UCHAR SystemId[8];                              // offset = 0x036  54
++} PACKED_BOOT_SECTOR;                               // sizeof = 0x03E  62
++
++typedef PACKED_BOOT_SECTOR *PPACKED_BOOT_SECTOR;
++
++
++#endif
index 0000000,0000000..1cb7c13
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,782 @@@
++/*************************************************************************
++*
++* File: protos.h
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Contains the prototypes for functions in this sample FSD.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#ifndef       _EXT2_PROTOS_H_
++#define       _EXT2_PROTOS_H_
++
++#ifdef __REACTOS__
++typedef PIO_STACK_LOCATION PEXTENDED_IO_STACK_LOCATION;
++#endif
++
++/*************************************************************************
++* Prototypes for the file sfsdinit.c
++*************************************************************************/
++extern NTSTATUS STDCALL DriverEntry(
++      PDRIVER_OBJECT                  DriverObject,           // created by the I/O sub-system
++      PUNICODE_STRING                 RegistryPath);          // path to the registry key
++
++extern void STDCALL Ext2FsdInitializeFunctionPointers(
++      PDRIVER_OBJECT                  DriverObject);          // created by the I/O sub-system
++
++
++extern VOID STDCALL Ext2QueueHandlerThread(
++      IN PVOID                                StartContext);
++                                                                                              
++/*************************************************************************
++* Prototypes for the file fsctrl.c
++*************************************************************************/
++
++extern NTSTATUS STDCALL Ext2FileSystemControl(
++    IN PDEVICE_OBJECT         DeviceObject,
++    IN PIRP                                   Irp
++    );
++
++extern NTSTATUS STDCALL Ext2VerifyVolume (
++      IN PIRP                                 Irp,
++      IN PIO_STACK_LOCATION   IrpSp );
++
++
++/*************************************************************************
++* Prototypes for the file create.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2Create(
++PDEVICE_OBJECT                                DeviceObject,           // the logical volume device object
++PIRP                                          Irp);                   // I/O Request Packet
++
++extern NTSTATUS STDCALL Ext2CommonCreate(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp,
++BOOLEAN                                               FirstAttempt );
++
++extern NTSTATUS STDCALL Ext2OpenVolume(
++      PtrExt2VCB                              PtrVCB,                         // volume to be opened
++      PtrExt2IrpContext               PtrIrpContext,          // IRP context
++      PIRP                                    PtrIrp,                         // original/user IRP
++      unsigned short                  ShareAccess,            // share access
++      PIO_SECURITY_CONTEXT    PtrSecurityContext,     // caller's context (incl access)
++      PFILE_OBJECT                    PtrNewFileObject);      // I/O Mgr. created file object
++
++extern NTSTATUS STDCALL Ext2OpenRootDirectory(
++      PtrExt2VCB                              PtrVCB,                                 // volume to be opened
++      PtrExt2IrpContext               PtrIrpContext,                  // IRP context
++      PIRP                                    PtrIrp,                                 // original/user IRP
++      unsigned short                  ShareAccess,                    // share access
++      PIO_SECURITY_CONTEXT    PtrSecurityContext,             // caller's context (incl access)
++      PFILE_OBJECT                    PtrNewFileObject);              // I/O Mgr. created file object
++
++extern void STDCALL Ext2InitializeFCB(
++      PtrExt2FCB                              PtrNewFCB,              // FCB structure to be initialized
++      PtrExt2VCB                              PtrVCB,                 // logical volume (VCB) pointer
++      PtrExt2ObjectName               PtrObjectName,  // name of the object
++      uint32                                  Flags,                  // is this a file/directory, etc.
++      PFILE_OBJECT                    PtrFileObject);// optional file object to be initialized
++
++extern PtrExt2FCB     STDCALL Ext2LocateChildFCBInCore(
++      PtrExt2VCB                              PtrVCB, 
++      PUNICODE_STRING                 PtrName, 
++      ULONG                                   ParentInodeNo );
++
++extern PtrExt2FCB     STDCALL Ext2LocateFCBInCore(
++      PtrExt2VCB                              PtrVCB, 
++      ULONG                                   InodeNo );
++
++
++extern ULONG  STDCALL Ext2LocateFileInDisk(
++      PtrExt2VCB                              PtrVCB,
++      PUNICODE_STRING                 PtrCurrentName, 
++      PtrExt2FCB                              PtrParentFCB, 
++      ULONG                                   *Type );
++
++extern ULONG STDCALL Ext2CreateFile(
++      PtrExt2IrpContext               PtrIrpContext,
++      PtrExt2VCB                              PtrVCB,
++      PUNICODE_STRING                 PtrName, 
++      PtrExt2FCB                              PtrParentFCB,
++      ULONG                                   Type);
++
++extern BOOLEAN STDCALL Ext2OverwriteFile(
++      PtrExt2FCB                              PtrFCB,
++      PtrExt2IrpContext               PtrIrpContext);
++
++extern BOOLEAN STDCALL Ext2SupersedeFile(
++      PtrExt2FCB                              PtrFCB,
++      PtrExt2IrpContext               PtrIrpContext);
++
++/*************************************************************************
++* Prototypes for the file misc.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2InitializeZones(
++void);
++
++extern void STDCALL Ext2DestroyZones(
++void);
++
++extern BOOLEAN STDCALL Ext2IsIrpTopLevel(
++PIRP                                                  Irp);                                   // the IRP sent to our dispatch routine
++
++extern long STDCALL Ext2ExceptionFilter(
++PtrExt2IrpContext                     PtrIrpContext,
++PEXCEPTION_POINTERS           PtrExceptionPointers);
++
++extern NTSTATUS STDCALL Ext2ExceptionHandler(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                                  Irp);
++
++extern void STDCALL Ext2LogEvent(
++NTSTATUS                                              Ext2EventLogId, // the Ext2 private message id
++NTSTATUS                                              RC);                                    // any NT error code we wish to log ...
++
++extern PtrExt2ObjectName STDCALL Ext2AllocateObjectName(
++void);
++
++extern void STDCALL Ext2ReleaseObjectName(
++PtrExt2ObjectName                     PtrObjectName);
++
++extern PtrExt2CCB STDCALL Ext2AllocateCCB(
++void );
++
++extern PtrExt2FCB STDCALL Ext2GetUsedFCB( 
++PtrExt2VCB                                    PtrVCB );
++
++extern BOOLEAN STDCALL Ext2CloseClosableFCB( 
++PtrExt2FCB                                    PtrFCB );
++
++extern void STDCALL Ext2ReleaseCCB(
++PtrExt2CCB                                    PtrCCB);
++
++extern PtrExt2FCB STDCALL Ext2AllocateFCB(
++void);
++
++extern NTSTATUS STDCALL Ext2CreateNewFCB(
++PtrExt2FCB                                    *ReturnedFCB,
++LARGE_INTEGER                         AllocationSize,
++LARGE_INTEGER                         EndOfFile,
++PFILE_OBJECT                          PtrFileObject,
++PtrExt2VCB                                    PtrVCB,
++PtrExt2ObjectName                     PtrObjectName);
++
++extern NTSTATUS STDCALL Ext2CreateNewCCB(
++PtrExt2CCB                            *ReturnedCCB,
++PtrExt2FCB                            PtrFCB,
++PFILE_OBJECT                  PtrFileObject);
++
++extern void STDCALL Ext2ReleaseFCB(
++PtrExt2FCB                                    PtrFCB);
++
++extern PtrExt2FileLockInfo STDCALL Ext2AllocateByteLocks(
++void);
++
++extern void STDCALL Ext2ReleaseByteLocks(
++PtrExt2FileLockInfo           PtrByteLocks);
++
++extern PtrExt2IrpContext STDCALL Ext2AllocateIrpContext(
++PIRP                                                  Irp,
++PDEVICE_OBJECT                                PtrTargetDeviceObject);
++
++extern void STDCALL Ext2ReleaseIrpContext(
++PtrExt2IrpContext                     PtrIrpContext);
++
++extern NTSTATUS STDCALL Ext2PostRequest(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp);
++
++extern void STDCALL Ext2CommonDispatch(
++void                                          *Context);      // actually an IRPContext structure
++
++extern void STDCALL Ext2InitializeVCB(
++PDEVICE_OBJECT                                PtrVolumeDeviceObject,
++PDEVICE_OBJECT                                PtrTargetDeviceObject,
++PVPB                                          PtrVPB,
++PLARGE_INTEGER                                AllocationSize);
++
++extern void STDCALL Ext2CompleteRequest(
++    IN PIRP                                   Irp OPTIONAL,
++    IN NTSTATUS                               Status
++    );
++
++extern NTSTATUS STDCALL Ext2DenyAccess( 
++      IN PIRP Irp 
++      );
++extern NTSTATUS STDCALL Ext2GetFCB_CCB_VCB_FromFileObject(
++      IN PFILE_OBJECT                 PtrFileObject,
++      OUT PtrExt2FCB                          *PPtrFCB,
++      OUT PtrExt2CCB                          *PPtrCCB,
++      OUT PtrExt2VCB                          *PPtrVCB        );
++
++extern void STDCALL Ext2CopyUnicodeString( 
++      IN OUT PUNICODE_STRING  PtrDestinationString, 
++      IN PUNICODE_STRING PtrSourceString );
++
++extern void STDCALL Ext2CopyWideCharToUnicodeString( 
++      IN OUT PUNICODE_STRING  PtrDestinationString, 
++      IN PCWSTR PtrSourceString );
++
++extern void STDCALL Ext2CopyCharToUnicodeString( 
++      IN OUT PUNICODE_STRING  PtrDestinationString, 
++      IN PCSTR PtrSourceString,
++      IN USHORT SourceStringLength );
++
++extern void STDCALL Ext2CopyZCharToUnicodeString( 
++      IN OUT PUNICODE_STRING  PtrDestinationString, 
++      IN PCSTR PtrSourceString );
++
++extern void STDCALL Ext2DeallocateUnicodeString( 
++      PUNICODE_STRING         PtrUnicodeString );
++
++extern void STDCALL Ext2ZerooutUnicodeString(
++      PUNICODE_STRING         PtrUnicodeString );
++
++extern BOOLEAN STDCALL Ext2SaveBCB(
++      PtrExt2IrpContext       PtrIrpContext,
++      PBCB                            PtrBCB,
++      PFILE_OBJECT            PtrFileObject);
++
++extern BOOLEAN STDCALL Ext2FlushSavedBCBs(
++      PtrExt2IrpContext       PtrIrpContext);
++
++extern BOOLEAN STDCALL AssertBCB(
++      PBCB                            PtrBCB);
++
++extern ULONG STDCALL Ext2Align(
++      ULONG                           NumberToBeAligned, 
++      ULONG                           Alignment);
++
++extern LONGLONG STDCALL Ext2Align64(
++      LONGLONG                        NumberToBeAligned, 
++      LONGLONG                        Alignment);
++
++extern ULONG STDCALL Ext2GetCurrentTime();
++
++/*************************************************************************
++* Prototypes for the file cleanup.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2Cleanup(
++PDEVICE_OBJECT                                DeviceObject,           // the logical volume device object
++PIRP                                                  Irp);                                   // I/O Request Packet
++
++extern NTSTATUS       STDCALL Ext2CommonCleanup(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp,
++BOOLEAN                                               FirstAttempt );
++
++/*************************************************************************
++* Prototypes for the file close.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2Close(
++PDEVICE_OBJECT                                DeviceObject,           // the logical volume device object
++PIRP                                                  Irp);                                   // I/O Request Packet
++
++extern NTSTATUS       STDCALL Ext2CommonClose(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp,
++BOOLEAN                                               FirstAttempt );
++
++/*************************************************************************
++* Prototypes for the file read.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2Read(
++PDEVICE_OBJECT                                DeviceObject,           // the logical volume device object
++PIRP                                                  Irp);                                   // I/O Request Packet
++
++extern NTSTATUS       STDCALL Ext2CommonRead(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                  PtrIrp,
++BOOLEAN                                               FirstAttempt );
++
++extern void * STDCALL Ext2GetCallersBuffer(
++PIRP                                          PtrIrp);
++
++extern NTSTATUS STDCALL Ext2LockCallersBuffer(
++PIRP                                          PtrIrp,
++BOOLEAN                                               IsReadOperation,
++uint32                                                Length);
++
++extern void STDCALL Ext2MdlComplete(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp,
++PIO_STACK_LOCATION                    PtrIoStackLocation,
++BOOLEAN                                               ReadCompletion);
++
++/*************************************************************************
++* Prototypes for the file write.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2Write(
++PDEVICE_OBJECT                                DeviceObject,           // the logical volume device object
++PIRP                                                  Irp);                                   // I/O Request Packet
++
++extern NTSTATUS       STDCALL Ext2CommonWrite(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                  PtrIrp);
++
++extern void STDCALL Ext2DeferredWriteCallBack (
++void                                                  *Context1,                      // Should be PtrIrpContext
++void                                                  *Context2);                     // Should be PtrIrp
++
++/*************************************************************************
++* Prototypes for the file fileinfo.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2FileInfo(
++PDEVICE_OBJECT                                DeviceObject,           // the logical volume device object
++PIRP                                          Irp);                                   // I/O Request Packet
++
++extern NTSTATUS       STDCALL Ext2CommonFileInfo(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp);
++
++extern NTSTATUS       STDCALL Ext2GetBasicInformation(
++      PtrExt2FCB                                      PtrFCB,
++      PFILE_BASIC_INFORMATION         PtrBuffer,
++      long                                            *PtrReturnedLength);
++
++extern NTSTATUS       STDCALL Ext2GetStandardInformation(
++      PtrExt2FCB                                      PtrFCB,
++      PFILE_STANDARD_INFORMATION      PtrStdInformation,
++      long                                            *PtrReturnedLength);
++
++extern NTSTATUS STDCALL Ext2GetNetworkOpenInformation(
++      PtrExt2FCB                                              PtrFCB,
++      PFILE_NETWORK_OPEN_INFORMATION  PtrNetworkOpenInformation,
++      long                                                    *PtrReturnedLength );
++
++extern NTSTATUS       STDCALL Ext2GetFullNameInformation(
++      PtrExt2FCB                              PtrFCB,
++      PtrExt2CCB                              PtrCCB,
++      PFILE_NAME_INFORMATION  PtrNameInformation,
++      long                                    *PtrReturnedLength);
++
++extern NTSTATUS       STDCALL Ext2SetBasicInformation(
++      PtrExt2IrpContext                       PtrIrpContext,
++      PtrExt2FCB                                      PtrFCB,
++      PFILE_OBJECT                            PtrFileObject,
++      PFILE_BASIC_INFORMATION         PtrFileInformation );
++
++extern NTSTATUS       STDCALL Ext2SetDispositionInformation(
++PtrExt2FCB                                    PtrFCB,
++PtrExt2CCB                                    PtrCCB,
++PtrExt2VCB                                    PtrVCB,
++PFILE_OBJECT                          PtrFileObject,
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                                  PtrIrp,
++PFILE_DISPOSITION_INFORMATION PtrBuffer);
++
++extern NTSTATUS       STDCALL Ext2SetAllocationInformation(
++PtrExt2FCB                                    PtrFCB,
++PtrExt2CCB                                    PtrCCB,
++PtrExt2VCB                                    PtrVCB,
++PFILE_OBJECT                          PtrFileObject,
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                                  PtrIrp,
++PFILE_ALLOCATION_INFORMATION  PtrBuffer);
++
++/*************************************************************************
++* Prototypes for the file flush.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2Flush(
++PDEVICE_OBJECT                                DeviceObject,           // the logical volume device object
++PIRP                                                  Irp);                                   // I/O Request Packet
++
++extern NTSTATUS       STDCALL Ext2CommonFlush(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                                  PtrIrp);
++
++extern void STDCALL Ext2FlushAFile(
++PtrExt2NTRequiredFCB          PtrReqdFCB,
++PIO_STATUS_BLOCK                      PtrIoStatus);
++
++extern void STDCALL Ext2FlushLogicalVolume(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                                  PtrIrp,
++PtrExt2VCB                                    PtrVCB);
++
++extern NTSTATUS STDCALL Ext2FlushCompletion(
++PDEVICE_OBJECT                                PtrDeviceObject,
++PIRP                                                  PtrIrp,
++PVOID                                                 Context);
++
++/*************************************************************************
++* Prototypes for the file dircntrl.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2DirControl(
++PDEVICE_OBJECT                                DeviceObject,           // the logical volume device object
++PIRP                                                  Irp);                                   // I/O Request Packet
++
++extern NTSTATUS       STDCALL Ext2CommonDirControl(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                                  PtrIrp);
++
++extern NTSTATUS       STDCALL Ext2QueryDirectory(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp,
++PEXTENDED_IO_STACK_LOCATION                   PtrIoStackLocation,
++PFILE_OBJECT                          PtrFileObject,
++PtrExt2FCB                                    PtrFCB,
++PtrExt2CCB                                    PtrCCB);
++
++extern NTSTATUS       STDCALL Ext2NotifyChangeDirectory(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp,
++PEXTENDED_IO_STACK_LOCATION           PtrIoStackLocation,
++PFILE_OBJECT                          PtrFileObject,
++PtrExt2FCB                                    PtrFCB,
++PtrExt2CCB                                    PtrCCB);
++
++/*************************************************************************
++* Prototypes for the file devcntrl.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2DeviceControl(
++PDEVICE_OBJECT                                DeviceObject,           // the logical volume device object
++PIRP                                          Irp);                                   // I/O Request Packet
++
++extern NTSTATUS STDCALL Ext2CommonDeviceControl(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp);
++
++extern NTSTATUS STDCALL Ext2DevIoctlCompletion(
++PDEVICE_OBJECT                                PtrDeviceObject,
++PIRP                                          PtrIrp,
++void                                          *Context);
++
++extern NTSTATUS STDCALL Ext2HandleQueryPath(
++void                                          *BufferPointer);
++
++/*************************************************************************
++* Prototypes for the file shutdown.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2Shutdown(
++PDEVICE_OBJECT                                DeviceObject,           // the logical volume device object
++PIRP                                          Irp);                   // I/O Request Packet
++
++extern NTSTATUS       STDCALL Ext2CommonShutdown(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp);
++
++/*************************************************************************
++* Prototypes for the file volinfo.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2QueryVolInfo(
++PDEVICE_OBJECT                                DeviceObject,   // the logical volume device object
++PIRP                                          Irp);                   // I/O Request Packet
++
++NTSTATUS STDCALL Ext2SetVolInfo(
++      IN PDEVICE_OBJECT               DeviceObject,   // the logical volume device object
++      IN PIRP                                 Irp);                   // I/O Request Packet
++
++
++/*************************************************************************
++* Prototypes for the file fastio.c
++*************************************************************************/
++extern BOOLEAN STDCALL Ext2FastIoCheckIfPossible(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN ULONG                                                      Length,
++IN BOOLEAN                                            Wait,
++IN ULONG                                                      LockKey,
++IN BOOLEAN                                            CheckForReadOperation,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoRead(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN ULONG                                                      Length,
++IN BOOLEAN                                            Wait,
++IN ULONG                                                      LockKey,
++OUT PVOID                                             Buffer,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoWrite(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN ULONG                                                      Length,
++IN BOOLEAN                                            Wait,
++IN ULONG                                                      LockKey,
++OUT PVOID                                             Buffer,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoQueryBasicInfo(
++IN PFILE_OBJECT                                       FileObject,
++IN BOOLEAN                                                    Wait,
++OUT PFILE_BASIC_INFORMATION   Buffer,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                                     DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoQueryStdInfo(
++IN PFILE_OBJECT                                               FileObject,
++IN BOOLEAN                                                            Wait,
++OUT PFILE_STANDARD_INFORMATION        Buffer,
++OUT PIO_STATUS_BLOCK                          IoStatus,
++IN PDEVICE_OBJECT                                             DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoLock(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN PLARGE_INTEGER                             Length,
++PEPROCESS                                             ProcessId,
++ULONG                                                         Key,
++BOOLEAN                                                       FailImmediately,
++BOOLEAN                                                       ExclusiveLock,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoUnlockSingle(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN PLARGE_INTEGER                             Length,
++PEPROCESS                                             ProcessId,
++ULONG                                                         Key,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoUnlockAll(
++IN PFILE_OBJECT                               FileObject,
++PEPROCESS                                             ProcessId,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoUnlockAllByKey(
++IN PFILE_OBJECT                               FileObject,
++PEPROCESS                                             ProcessId,
++ULONG                                                         Key,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern void STDCALL Ext2FastIoAcqCreateSec(
++IN PFILE_OBJECT                               FileObject);
++
++extern void STDCALL Ext2FastIoRelCreateSec(
++IN PFILE_OBJECT                               FileObject);
++
++extern BOOLEAN STDCALL Ext2AcqLazyWrite(
++IN PVOID                                                      Context,
++IN BOOLEAN                                            Wait);
++
++extern void STDCALL Ext2RelLazyWrite(
++IN PVOID                                                      Context);
++
++extern BOOLEAN STDCALL Ext2AcqReadAhead(
++IN PVOID                                                      Context,
++IN BOOLEAN                                            Wait);
++
++extern void STDCALL Ext2RelReadAhead(
++IN PVOID                                                      Context);
++
++// the remaining are only valid under NT Version 4.0 and later
++#if(_WIN32_WINNT >= 0x0400)
++
++extern BOOLEAN STDCALL Ext2FastIoQueryNetInfo(
++IN PFILE_OBJECT                                                                       FileObject,
++IN BOOLEAN                                                                                    Wait,
++OUT PFILE_NETWORK_OPEN_INFORMATION                    Buffer,
++OUT PIO_STATUS_BLOCK                                                  IoStatus,
++IN PDEVICE_OBJECT                                                                     DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoMdlRead(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN ULONG                                                      Length,
++IN ULONG                                                      LockKey,
++OUT PMDL                                                      *MdlChain,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoMdlReadComplete(
++IN PFILE_OBJECT                               FileObject,
++OUT PMDL                                                      MdlChain,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoPrepareMdlWrite(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN ULONG                                                      Length,
++IN ULONG                                                      LockKey,
++OUT PMDL                                                      *MdlChain,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern BOOLEAN STDCALL Ext2FastIoMdlWriteComplete(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++OUT PMDL                                                      MdlChain,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern NTSTATUS STDCALL Ext2FastIoAcqModWrite(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             EndingOffset,
++OUT PERESOURCE                                        *ResourceToRelease,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern NTSTATUS STDCALL Ext2FastIoRelModWrite(
++IN PFILE_OBJECT                               FileObject,
++IN PERESOURCE                                 ResourceToRelease,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern NTSTATUS STDCALL Ext2FastIoAcqCcFlush(
++IN PFILE_OBJECT                               FileObject,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++extern NTSTATUS STDCALL Ext2FastIoRelCcFlush(
++IN PFILE_OBJECT                               FileObject,
++IN PDEVICE_OBJECT                             DeviceObject);
++
++#endif        // (_WIN32_WINNT >= 0x0400)
++
++/*************************************************************************
++* Prototypes for the file DiskIO.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2ReadLogicalBlocks(
++PDEVICE_OBJECT                PtrTargetDeviceObject,  //      the Target Device Object
++VOID                          *Buffer,                                //      The Buffer that takes the data read in
++LARGE_INTEGER         StartLogicalBlock,              //      The logical block from which reading is to start
++unsigned int          NoOfLogicalBlocks);             //      The no. of logical blocks to be read
++
++extern NTSTATUS STDCALL Ext2ReadPhysicalBlocks(
++      PDEVICE_OBJECT          PtrTargetDeviceObject,  //      the Target Device Object
++      VOID                            *Buffer,                                //      The Buffer that takes the data read in
++      LARGE_INTEGER           StartBlock,             //      The Physical block from which reading is to start
++      unsigned int            NoOfBlocks);            //      The no. of Physical blocks to be read
++
++/*************************************************************************
++* Prototypes for the file metadata.c
++*************************************************************************/
++
++extern void STDCALL Ext2InitializeFCBInodeInfo (
++      PtrExt2FCB      PtrFCB );
++
++extern NTSTATUS STDCALL Ext2ReadInode(
++      PtrExt2VCB                      PtrVcb,                 //      the Volume Control Block
++      uint32                          InodeNo,                //      The Inode no
++      PEXT2_INODE                     PtrInode );             //      The Inode Buffer
++
++extern NTSTATUS STDCALL Ext2WriteInode(
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVcb,                 //      the Volume Control Block
++      uint32                          InodeNo,                //      The Inode no
++      PEXT2_INODE                     PtrInode                //      The Inode Buffer
++      );                                      
++
++extern ULONG STDCALL Ext2AllocInode( 
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVCB,
++      ULONG                           ParentINodeNo );
++
++extern BOOLEAN STDCALL Ext2DeallocInode( 
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVCB,
++      ULONG                           INodeNo );
++
++extern BOOLEAN STDCALL Ext2MakeNewDirectoryEntry( 
++      PtrExt2IrpContext       PtrIrpContext,          //      The Irp context
++      PtrExt2FCB                      PtrParentFCB,           //      Parent Folder FCB
++      PFILE_OBJECT            PtrFileObject,          //      Parent Folder Object
++      PUNICODE_STRING         PtrName,                        //      New entry's name
++      ULONG                           Type,                           //      The type of the new entry
++      ULONG                           NewInodeNo);            //      The inode no of the new entry...
++
++extern BOOLEAN STDCALL Ext2FreeDirectoryEntry(
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2FCB                      PtrParentFCB,
++      PUNICODE_STRING         PtrName);
++
++extern BOOLEAN STDCALL Ext2AddBlockToFile(
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVCB,
++      PtrExt2FCB                      PtrFCB,
++      PFILE_OBJECT            PtrFileObject,
++      BOOLEAN                         UpdateFileSize);
++
++extern BOOLEAN STDCALL Ext2ReleaseDataBlocks(
++      PtrExt2FCB                      PtrFCB,
++      PtrExt2IrpContext       PtrIrpContext);
++
++extern BOOLEAN STDCALL Ext2TruncateFileAllocationSize(
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2FCB                      PtrFCB,
++      PFILE_OBJECT            PtrFileObject,
++      PLARGE_INTEGER          PtrAllocationSize );
++
++extern ULONG STDCALL Ext2AllocBlock( 
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVCB,
++      ULONG                           Count);
++
++extern BOOLEAN STDCALL Ext2DeallocBlock( 
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVCB,
++      ULONG                           BlockNo);
++
++extern BOOLEAN STDCALL Ext2UpdateFileSize(
++      PtrExt2IrpContext       PtrIrpContext,
++      PFILE_OBJECT            PtrFileObject,
++      PtrExt2FCB                      PtrFCB);
++
++
++extern BOOLEAN STDCALL Ext2DeleteFile(
++      PtrExt2FCB                      PtrFCB,
++      PtrExt2IrpContext       PtrIrpContext);
++
++extern BOOLEAN STDCALL Ext2IsDirectoryEmpty(
++      PtrExt2FCB                      PtrFCB,
++      PtrExt2CCB                      PtrCCB,
++      PtrExt2IrpContext       PtrIrpContext);
++
++extern NTSTATUS STDCALL Ext2RenameOrLinkFile( 
++      PtrExt2FCB                                      PtrSourceFCB, 
++      PFILE_OBJECT                            PtrSourceFileObject,    
++      PtrExt2IrpContext                       PtrIrpContext,
++      PIRP                                            PtrIrp, 
++      PFILE_RENAME_INFORMATION        PtrRenameInfo);
++/*************************************************************************
++* Prototypes for the file io.c
++*************************************************************************/
++extern NTSTATUS STDCALL Ext2PassDownSingleReadWriteIRP(
++      PtrExt2IrpContext       PtrIrpContext,
++      PIRP                            PtrIrp, 
++      PtrExt2VCB                      PtrVCB,
++      LARGE_INTEGER           ByteOffset, 
++      uint32                          ReadWriteLength, 
++      BOOLEAN                         SynchronousIo);
++
++extern NTSTATUS STDCALL Ext2PassDownMultiReadWriteIRP( 
++      PEXT2_IO_RUN                    PtrIoRuns, 
++      UINT                                    Count, 
++      ULONG                                   TotalReadWriteLength,
++      PtrExt2IrpContext               PtrIrpContext,
++      PtrExt2FCB                              PtrFCB,
++      BOOLEAN                                 SynchronousIo);
++
++extern NTSTATUS STDCALL Ext2SingleSyncCompletionRoutine(
++    IN PDEVICE_OBJECT DeviceObject,
++    IN PIRP Irp,
++    IN PVOID Contxt
++    );
++
++extern NTSTATUS STDCALL Ext2SingleAsyncCompletionRoutine (
++    IN PDEVICE_OBJECT DeviceObject,
++    IN PIRP Irp,
++    IN PVOID Contxt
++    );
++
++extern NTSTATUS STDCALL Ext2MultiSyncCompletionRoutine(
++    IN PDEVICE_OBJECT DeviceObject,
++    IN PIRP Irp,
++    IN PVOID Contxt);
++
++extern NTSTATUS STDCALL Ext2MultiAsyncCompletionRoutine(
++    IN PDEVICE_OBJECT DeviceObject,
++    IN PIRP Irp,
++    IN PVOID Contxt);
++
++#endif        // _EXT2_PROTOS_H_
index 0000000,0000000..9c490bf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++//{{NO_DEPENDENCIES}}
++// Microsoft Developer Studio generated include file.
++// Used by D:\Work\VC\Drivers\ext2FSD\src\ext2.rc
++//
++
++// Next default values for new objects
++// 
++#ifdef APSTUDIO_INVOKED
++#ifndef APSTUDIO_READONLY_SYMBOLS
++#define _APS_NO_MFC                     1
++#define _APS_NEXT_RESOURCE_VALUE        102
++#define _APS_NEXT_COMMAND_VALUE         40001
++#define _APS_NEXT_CONTROL_VALUE         1000
++#define _APS_NEXT_SYMED_VALUE           101
++#endif
++#endif
index 0000000,0000000..1b4e83d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,674 @@@
++/*************************************************************************
++*
++* File: struct.h
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     This file contains structure definitions for the sample file system
++*     driver. Note that all structures are prefixed with the letters
++*     "Ext2". The structures are all aligned using normal alignment
++*     used by the compiler (typically quad-word aligned).
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#ifndef       _EXT2_STRUCTURES_H_
++#define       _EXT2_STRUCTURES_H_
++
++/**************************************************************************
++      some useful definitions
++**************************************************************************/
++#ifdef        _CPU_X86_
++typedef       char                                    int8;
++typedef       short                                   int16;
++typedef       int                                             int32;
++
++typedef       unsigned char                   uint8;
++typedef       unsigned short                  uint16;
++typedef       unsigned int                    uint32;
++
++typedef PVOID                                 PBCB;
++
++// we will use the LARGE_INTEGER structure as defined by NT
++
++#else         // Please define appropriate types here
++
++!!!! You must define your types here for compilation to proceed !!!!
++
++#endif        // if _CPU_X86_
++
++/**************************************************************************
++      some empty typedefs defined here so we can reference them easily
++**************************************************************************/
++struct _Ext2Identifier;
++struct _Ext2ObjectName;
++struct _Ext2ContextControlBlock;
++struct _Ext2NTRequiredFCB;
++struct _Ext2DiskDependentFCB;
++struct _Ext2FileControlBlock;
++struct _Ext2FileByteLocks;
++struct _Ext2VolumeControlBlock;
++struct _Ext2IrpContext;
++struct _Ext2Data;
++
++/**************************************************************************
++      each structure has a unique "node type" or signature associated with it
++**************************************************************************/
++#define       EXT2_NODE_TYPE_OBJECT_NAME                      (0xfdecba01)
++#define       EXT2_NODE_TYPE_CCB                                      (0xfdecba02)
++#define       EXT2_NODE_TYPE_FCB                                      (0xfdecba03)
++#define       EXT2_NODE_TYPE_LOCKS                            (0xfdecba04)
++#define       EXT2_NODE_TYPE_VCB                                      (0xfdecba05)
++#define       EXT2_NODE_TYPE_IRP_CONTEXT                      (0xfdecba06)
++#define       EXT2_NODE_TYPE_GLOBAL_DATA                      (0xfdecba07)
++#define       EXT2_NODE_TYPE_IO_CONTEXT                       (0xfdecba08)
++#define       EXT2_NODE_TYPE_SAVED_BCB                        (0xfdecba09)
++#define       EXT2_NODE_TYPE_FREED                            (0x10101010)
++#define       EXT2_NODE_TYPE_INVALID                          (0x10101010)
++
++/**************************************************************************
++      every structure has a node type, and a node size associated with it.
++      The node type serves as a signature field. The size is used for
++      consistency checking ...
++**************************************************************************/
++typedef struct _Ext2Identifier {
++      uint32          NodeType;                       // a 32 bit identifier for the structure
++      uint32          NodeSize;                       // computed as sizeof(structure)
++} Ext2Identifier, *PtrExt2Identifier;
++
++/**************************************************************************
++      Structures for byte-range lock support.
++**************************************************************************/
++typedef struct Ext2FileLockAnchor {
++      LIST_ENTRY                      GrantedFileLockList;
++      LIST_ENTRY                      PendingFileLockList;
++} Ext2FileLockAnchor, *PtrExt2FileLockAnchor;
++
++typedef struct Ext2FileLockInfo {
++      Ext2Identifier                                          NodeIdentifier;
++      uint32                                                          FileLockFlags;
++      PVOID                                                                   OwningProcess;
++      LARGE_INTEGER                                           StartingOffset;
++      LARGE_INTEGER                                           Length;
++      LARGE_INTEGER                                           EndingOffset;
++      ULONG                                                                   Key;
++      BOOLEAN                                                         ExclusiveLock;
++      PIRP                                                                    PendingIRP;
++      LIST_ENTRY                                                      NextFileLockEntry;
++} Ext2FileLockInfo, *PtrExt2FileLockInfo;
++
++#define               EXT2_BYTE_LOCK_NOT_FROM_ZONE                            (0x80000000)
++#define               EXT2_BYTE_LOCK_IS_PENDING                                       (0x00000001)
++
++/**************************************************************************
++      Every open on-disk object must have a name associated with it
++      This name has two components:
++      (a) the path-name (prefix) that leads to this on-disk object
++      (b) the name of the object itself
++      Note that with multiply linked objects, a single object might be
++      associated with more than one name structure.
++      This sample FSD does not correctly support multiply linked objects.
++
++      This structure must be quad-word aligned because it is zone allocated.
++**************************************************************************/
++typedef struct _Ext2ObjectName {
++      Ext2Identifier                                          NodeIdentifier;
++      uint32                                                          ObjectNameFlags;
++      // an absolute pathname of the object is stored below
++      UNICODE_STRING                                          ObjectName;
++} Ext2ObjectName, *PtrExt2ObjectName;
++
++#define               EXT2_OB_NAME_NOT_FROM_ZONE                              (0x80000000)
++
++/**************************************************************************
++      Each file open instance is represented by a context control block.
++      For each successful create/open request; a file object and a CCB will
++      be created.
++      For open operations performed internally by the FSD, there may not
++      exist file objects; but a CCB will definitely be created.
++
++      This structure must be quad-word aligned because it is zone allocated.
++**************************************************************************/
++typedef struct _Ext2ContextControlBlock {
++      Ext2Identifier                                          NodeIdentifier;
++      // ptr to the associated FCB
++      struct _Ext2FileControlBlock    *PtrFCB;
++      // all CCB structures for a FCB are linked together
++      LIST_ENTRY                                                      NextCCB;
++      // each CCB is associated with a file object
++      PFILE_OBJECT                                            PtrFileObject;
++      // flags (see below) associated with this CCB
++      uint32                                                          CCBFlags;
++      // current byte offset is required sometimes
++      LARGE_INTEGER                                           CurrentByteOffset;
++      // if this CCB represents a directory object open, we may
++      //      need to maintain a search pattern
++
++      //      PSTRING                                                         DirectorySearchPattern;
++      UNICODE_STRING                                          DirectorySearchPattern;
++
++      //      The full path name for the file...
++      UNICODE_STRING                  AbsolutePathName;
++
++      //      Rename/Link Target file name
++      //      Used only in a Rename/Link operation
++      UNICODE_STRING                  RenameLinkTargetFileName;
++
++      // we must maintain user specified file time values
++      uint32                                                          UserSpecifiedTime;
++
++
++} Ext2CCB, *PtrExt2CCB;
++
++
++/**************************************************************************
++      the following CCBFlags values are relevant. These flag
++      values are bit fields; therefore we can test whether
++      a bit position is set (1) or not set (0).
++**************************************************************************/
++
++// some on-disk file/directories are opened by EXT2 itself
++//    as opposed to being opened on behalf of a user process
++#define       EXT2_CCB_OPENED_BY_EXT2                                         (0x00000001)
++// the file object specified synchronous access at create/open time.
++//    this implies that EXT2 must maintain the current byte offset
++#define       EXT2_CCB_OPENED_FOR_SYNC_ACCESS                 (0x00000002)
++// file object specified sequential access for this file
++#define       EXT2_CCB_OPENED_FOR_SEQ_ACCESS                  (0x00000004)
++// the CCB has had an IRP_MJ_CLEANUP issued on it. we must
++//    no longer allow the file object / CCB to be used in I/O requests.
++#define       EXT2_CCB_CLEANED                                                                (0x00000008)
++// if we were invoked via the fast i/o path to perform file i/o;
++//    we should set the CCB access/modification time at cleanup
++#define       EXT2_CCB_ACCESSED                                                               (0x00000010)
++#define       EXT2_CCB_MODIFIED                                                               (0x00000020)
++// if an application process set the file date time, we must
++//    honor that request and *not* overwrite the values at cleanup
++#define       EXT2_CCB_ACCESS_TIME_SET                                        (0x00000040)
++#define       EXT2_CCB_MODIFY_TIME_SET                                        (0x00000080)
++#define       EXT2_CCB_CREATE_TIME_SET                                        (0x00000100)
++
++#define       EXT2_CCB_NOT_FROM_ZONE                                          (0x80000000)
++
++// this CCB was allocated for a "volume open" operation
++#define       EXT2_CCB_VOLUME_OPEN                                                    (0x00000100)
++
++/**************************************************************************
++      each open file/directory/volume is represented by a file control block.
++      NOTE: Currently, EXT2 does not handle multiply linked files correctly.
++                      In your FSD implementation, you must be careful about handling
++                      such on-disk files correctly i.e. a single (unique) FCB must
++                      represent an on-disk file/directory regardless of the path used
++                      to access the on-disk object.
++                      With the current EXT2 implementation, an on-disk file object
++                      with more than a single (hard) link will be treated incorrectly!
++
++      Each FCB can logically be divided into two:
++      (a) a structure that must have a field of type FSRTL_COMMON_FCB_HEADER
++               as the first field in the structure.
++               This portion should also contain other structures/resources required
++               by the NT Cache Manager
++               We will call this structure the "NT Required" FCB. Note that this
++               portion of the FCB must be allocated from non-paged pool.
++      (b) the remainder of the FCB is dependent upon the particular FSD
++               requirements.
++               This portion of the FCB could possibly be allocated from paged
++               memory, though in the sample FSD, it will always be allocated
++               from non-paged pool.
++
++      FCB structures are protected by the MainResource as well as the
++      PagingIoResource. Of course, if your FSD implementation requires
++      it, you can associate other syncronization structures with the
++      FCB.
++
++      This structure must be quad-word aligned because it is zone allocated.
++**************************************************************************/
++typedef struct _Ext2NTRequiredFCB 
++{
++    FSRTL_COMMON_FCB_HEADER                   CommonFCBHeader;
++      SECTION_OBJECT_POINTERS                 SectionObject;
++      ERESOURCE                                                       MainResource;
++      ERESOURCE                                                       PagingIoResource;
++} Ext2NTRequiredFCB, *PtrExt2NTRequiredFCB;
++
++typedef struct _Ext2DiskDependentFCB 
++{
++      // although the sample FSD does not maintain on-disk data structures,
++      //      this structure serves as a reminder of the logical separation that
++      //      your FSD can maintain between the disk dependent and the disk
++      //      independent portions of the FCB.
++      uint16                                                          DummyField;             // placeholder
++} Ext2DiskDependentFCB, *PtrExt2DiskDependentFCB;
++
++typedef struct _Ext2FileControlBlock 
++{
++      Ext2Identifier                                          NodeIdentifier;
++      // we will go ahead and embed the "NT Required FCB" right here.
++      //      Note though that it is just as acceptable to simply allocate
++      //      memory separately for the other half of the FCB and store a
++      //      pointer to the "NT Required" portion here instead of embedding
++      //      it ...
++      Ext2NTRequiredFCB                                       NTRequiredFCB;
++      // the disk dependent portion of the FCB is embedded right here
++      Ext2DiskDependentFCB                            DiskDependentFCB;
++      // this FCB belongs to some mounted logical volume
++      struct _Ext2VolumeControlBlock  *PtrVCB;
++      // to be able to access all open file(s) for a volume, we will
++      //      link all FCB structures for a logical volume together
++      LIST_ENTRY                                                      NextFCB;
++
++      //      to be used if this FCB is on the Closable FCB List...
++      struct _ClosableFCBs
++      {
++              LIST_ENTRY                                              ClosableFCBList;
++              BOOLEAN                                                 OnClosableFCBList;
++      }ClosableFCBs;
++
++      // some state information for the FCB is maintained using the
++      //      flags field
++      uint32                                                          FCBFlags;
++      // all CCB's for this particular FCB are linked off the following
++      //      list head.
++      LIST_ENTRY                                                      CCBListHead;
++      // NT requires that a file system maintain and honor the various
++      //      SHARE_ACCESS modes ...
++      SHARE_ACCESS                                            FCBShareAccess;
++      // to identify the lazy writer thread(s) we will grab and store
++      //      the thread id here when a request to acquire resource(s)
++      //      arrives ..
++      uint32                                                          LazyWriterThreadID;
++      // whenever a file stream has a create/open operation performed,
++      //      the Reference count below is incremented AND the OpenHandle count
++      //      below is also incremented.
++      //      When an IRP_MJ_CLEANUP is received, the OpenHandle count below
++      //      is decremented.
++      //      When an IRP_MJ_CLOSE is received, the Reference count below is
++      //      decremented.
++      //      When the Reference count goes down to zero, the FCB can be de-allocated.
++      //      Note that a zero Reference count implies a zero OpenHandle count.
++      //      This invariant must always hold true ... (if it is really an invariant,
++      // shoudn't the previous statement be redundant ... hmmm!!!)
++      LONG                                                            ReferenceCount;
++      LONG                                                            OpenHandleCount;
++      // for the sample fsd, there exists a 1-1 correspondence between an
++      //      object name structure and a FCB
++      PtrExt2ObjectName                                       FCBName;
++      // we will maintain some time information here to make our life easier
++      LARGE_INTEGER                                           CreationTime;
++      LARGE_INTEGER                                           LastAccessTime;
++      LARGE_INTEGER                                           LastWriteTime;
++      // Byte-range file lock support (we roll our own)
++      Ext2FileLockAnchor                              FCBByteRangeLock;
++      // The OPLOCK support package requires the following structure
++      OPLOCK                                                          FCBOplock;
++
++      //      The I-Node no of this file / folder
++      ULONG                   INodeNo;
++      ULONG                   ParentINodeNo;
++      //      Pointers to blocks 
++      uint32                  IBlock[EXT2_N_BLOCKS];
++      
++      USHORT                  LinkCount;
++      union   _DCBFCB
++      {
++              struct
++              {
++                      PFILE_OBJECT    PtrDirFileObject;
++              } Dcb;
++
++              struct _FCB
++              {
++                      PFILE_OBJECT    PtrDirFileObject;
++                      //      FCB specific stuff go here...
++              } Fcb;
++
++      }DcbFcb;
++
++} Ext2FCB, *PtrExt2FCB, Ext2DCB, *PtrExt2DCB;
++
++/**************************************************************************
++      the following FCBFlags values are relevant. These flag
++      values are bit fields; therefore we can test whether
++      a bit position is set (1) or not set (0).
++**************************************************************************/
++#define               EXT2_FCB_IN_INIT                                                        (0x00000001)
++#define               EXT2_FCB_IN_TEARDOWN                                            (0x00000002)
++#define               EXT2_FCB_PAGE_FILE                                                      (0x00000004)
++#define               EXT2_FCB_DIRECTORY                                                      (0x00000008)
++#define               EXT2_FCB_ROOT_DIRECTORY                                         (0x00000018)
++#define               EXT2_FCB_WRITE_THROUGH                                          (0x00000020)
++#define               EXT2_FCB_MAPPED                                                         (0x00000040)
++#define               EXT2_FCB_FAST_IO_READ_IN_PROGESS                        (0x00000080)
++#define               EXT2_FCB_FAST_IO_WRITE_IN_PROGESS                       (0x00000100)
++#define               EXT2_FCB_DELETE_ON_CLOSE                                        (0x00000200)
++#define               EXT2_FCB_MODIFIED                                                       (0x00000400)
++#define               EXT2_FCB_ACCESSED                                                       (0x00000800)
++#define               EXT2_FCB_READ_ONLY                                                      (0x00001000)
++
++#define               EXT2_INITIALIZED_MAIN_RESOURCE                          (0x00002000)
++#define               EXT2_INITIALIZED_PAGING_IO_RESOURCE                     (0x00004000)
++#define               EXT2_FCB_BLOCKS_INITIALIZED                                     (0x00008000)
++#define               EXT2_FCB_SPECIAL_FILE                                           (0x00010000)
++#define               EXT2_FCB_HIDDEN_FILE                                            (0x00020000)
++#define               EXT2_FCB_NOT_FROM_ZONE                                          (0x80000000)
++
++
++typedef struct _GroupDescriptors
++{
++      uint32  InodeTablesBlock;       /* Inodes table block   => bg_inode_table               */
++      uint32  InodeBitmapBlock;       /* Inodes bitmap block  => bg_inode_bitmap      */
++      uint32  BlockBitmapBlock;       /* Blocks bitmap block  => bg_block_bitmap      */
++      uint32  FreeBlocksCount;
++      uint32  FreeInodesCount;
++}Ext2GroupDescriptors, *PtrExt2GroupDescriptors;
++
++
++
++/**************************************************************************
++      A logical volume is represented using the following structure.
++      This structure is allocated as part of the device extension
++      for a device object that this sample FSD will create, to represent
++      the mounted logical volume.
++
++      NOTE: If you were to extend this sample FSD to be a "real" FSD,
++                      you would be worried about allocated clusters/sectiors,
++                      bitmaps providing such information for the mounted volume,
++                      dirty/modified clusters/sectiors etc.
++                      This sample FSD does not maintain such information in the
++                      in-memory VCB, though you may wish to consider it.
++**************************************************************************/
++typedef struct _Ext2VolumeControlBlock 
++{
++      Ext2Identifier                                          NodeIdentifier;
++
++    // Required to use the Cache Manager.
++      FSRTL_COMMON_FCB_HEADER                 CommonVCBHeader;
++      SECTION_OBJECT_POINTERS                 SectionObject;
++      // a resource to protect the fields contained within the VCB
++      ERESOURCE                                                       VCBResource;
++      
++      // a resource to synchronise paging io
++      ERESOURCE                                                       PagingIoResource;
++
++      // Pointer to a stream file object created for the volume information
++      // to be more easily read from secondary storage (with the support of
++      // the NT Cache Manager).
++      PFILE_OBJECT                                            PtrStreamFileObject;
++      
++      // each VCB is accessible off a global linked list
++      LIST_ENTRY                                                      NextVCB;
++      
++      // each VCB points to a VPB structure created by the NT I/O Manager
++      PVPB                                                                    PtrVPB;
++      
++      // a set of flags that might mean something useful
++      uint32                                                          VCBFlags;
++      
++      // A count of the number of open files/directories
++      //      As long as the count is != 0, the volume cannot
++      //      be dismounted or locked.
++      uint32                                                          VCBOpenCount;
++      
++      // a global list of all FCB structures associated with the VCB
++      LIST_ENTRY                                                      FCBListHead;
++
++      //
++      //      a list of FCBs created at the FSD's initiative...
++      //      These FCBs have a reference count of 0
++      //      This list should never be allowed to cross a limit...
++      //
++      struct Ext2ClosableFCB
++      {
++              LIST_ENTRY                                              ClosableFCBListHead;
++              ULONG                                                   Count;
++      }ClosableFCBs;
++      // we will maintain a global list of IRP's that are pending
++      //      because of a directory notify request.
++      LIST_ENTRY                                                      NextNotifyIRP;
++      // the above list is protected only by the mutex declared below
++      KMUTEX                                                          NotifyIRPMutex;
++      // for each mounted volume, we create a device object. Here then
++      //      is a back pointer to that device object
++      PDEVICE_OBJECT                                          VCBDeviceObject;
++      // We also retain a pointer to the physical device object on which we
++      // have mounted ourselves. The I/O Manager passes us a pointer to this
++      // device object when requesting a mount operation.
++      PDEVICE_OBJECT                                          TargetDeviceObject;
++      // the volume structure contains a pointer to the root directory FCB
++      PtrExt2FCB                                                      PtrRootDirectoryFCB;
++      // the complete name of the user visible drive letter we serve
++      uint8                                                                   *PtrVolumePath;
++      // For volume open operations, we do not create a FCB (we use the VCB
++      //      directly instead). Therefore, all CCB structures for the volume
++      //      open operation are linked directly off the VCB
++      LIST_ENTRY                                                      VolumeOpenListHead;
++
++
++      //      Volume information
++      ULONG   BlocksCount;
++      ULONG   InodesCount;
++      ULONG   ReservedBlocksCount;
++      ULONG   FreeBlocksCount;
++      ULONG   FreeInodesCount;
++      ULONG   LogBlockSize;                   //      Block size = 1024 << LogBlockSize
++      
++      //      Group Information Saved up in the VCB...
++      PtrExt2GroupDescriptors PtrGroupDescriptors;
++      ULONG   NoOfGroups;
++
++      uint32  InodesPerGroup;
++      uint32  BlocksPerGroup; 
++
++} Ext2VCB, *PtrExt2VCB;
++
++// some valid flags for the VCB
++#define                       EXT2_VCB_FLAGS_VOLUME_MOUNTED                   (0x00000001)
++#define                       EXT2_VCB_FLAGS_VOLUME_LOCKED                    (0x00000002)
++#define                       EXT2_VCB_FLAGS_BEING_DISMOUNTED         (0x00000004)
++#define                       EXT2_VCB_FLAGS_SHUTDOWN                                 (0x00000008)
++#define                       EXT2_VCB_FLAGS_VOLUME_READ_ONLY         (0x00000010)
++
++#define                       EXT2_VCB_FLAGS_VCB_INITIALIZED          (0x00000020)
++
++typedef struct _EXT2_IO_CONTEXT 
++{
++      Ext2Identifier                  NodeIdentifier;
++      ULONG                                   ReadWriteLength;
++      LONG                                    Count;
++      PIRP                                    PtrMasterIrp;
++      PKEVENT                                 PtrSyncEvent;
++
++} EXT2_IO_CONTEXT, *PEXT2_IO_CONTEXT;
++
++
++typedef struct _Ext2SavedBCBs
++{
++      Ext2Identifier                  NodeIdentifier;
++      PBCB                                    PtrBCB;
++      LIST_ENTRY                              SavedBCBsListEntry;
++
++} EXT2_SAVED_BCBS, *PEXT2_SAVED_BCBS;
++
++
++/**************************************************************************
++      The IRP context encapsulates the current request. This structure is
++      used in the "common" dispatch routines invoked either directly in
++      the context of the original requestor, or indirectly in the context
++      of a system worker thread.
++**************************************************************************/
++typedef struct _Ext2IrpContext
++{
++      Ext2Identifier                  NodeIdentifier;
++      uint32                                  IrpContextFlags;
++      // copied from the IRP
++      uint8                                   MajorFunction;
++      // copied from the IRP
++      uint8                                   MinorFunction;
++
++      // to queue this IRP for asynchronous processing
++      WORK_QUEUE_ITEM                 WorkQueueItem;
++      // the IRP for which this context structure was created
++      PIRP                                    Irp;
++      // the target of the request (obtained from the IRP)
++      PDEVICE_OBJECT                  TargetDeviceObject;
++      // if an exception occurs, we will store the code here
++      NTSTATUS                                SavedExceptionCode;
++      
++      //      This list entry is used if asnchronous processing is required...
++      LIST_ENTRY                              ThreadQueueListEntry;
++
++      //      This list entry is used if BCBs are to be saved and then flushed...
++      //      Could have been put somewhere else...
++      LIST_ENTRY                              SavedBCBsListHead;
++      ULONG                                   SavedCount;
++
++} Ext2IrpContext, *PtrExt2IrpContext;
++
++#define                       EXT2_IRP_CONTEXT_CAN_BLOCK                              (0x00000001)
++#define                       EXT2_IRP_CONTEXT_WRITE_THROUGH          (0x00000002)
++#define                       EXT2_IRP_CONTEXT_EXCEPTION                              (0x00000004)
++#define                       EXT2_IRP_CONTEXT_DEFERRED_WRITE         (0x00000008)
++#define                       EXT2_IRP_CONTEXT_ASYNC_PROCESSING       (0x00000010)
++#define                       EXT2_IRP_CONTEXT_NOT_TOP_LEVEL          (0x00000020)
++
++#define                       EXT2_IRP_CONTEXT_NOT_FROM_ZONE          (0x80000000)
++
++typedef struct _Ext2ThreadQueue
++{
++      HANDLE                          QueueHandlerThread;
++      
++      LIST_ENTRY                      ThreadQueueListHead;    //      This holds the Contexts 
++                                                                                              //      that are to be scheduled
++      KSPIN_LOCK                      SpinLock;                               //      To synchronize access to 
++                                                                                              //      the list
++      KEVENT                          QueueEvent;                             //      The Worker thread queue 
++                                                                                              //      package waits on this event
++}     Ext2ThreadQueue;
++
++/**************************************************************************
++      we will store all of our global variables in one structure.
++      Global variables are not specific to any mounted volume BUT
++      by definition are required for successful operation of the
++      FSD implementation.
++**************************************************************************/
++typedef struct _Ext2Data 
++{
++      Ext2Identifier                          NodeIdentifier;
++      // the fields in this list are protected by the following resource
++      ERESOURCE                                       GlobalDataResource;
++      // each driver has a driver object created for it by the NT I/O Mgr.
++      //      we are no exception to this rule.
++      PDRIVER_OBJECT                          Ext2DriverObject;
++      // we will create a device object for our FSD as well ...
++      //      Although not really required, it helps if a helper application
++      //      writen by us wishes to send us control information via
++      //      IOCTL requests ...
++      PDEVICE_OBJECT                          Ext2DeviceObject;
++      // we will keep a list of all logical volumes for our sample FSD
++      LIST_ENTRY                                      NextVCB;
++      // the NT Cache Manager, the I/O Manager and we will conspire
++      //      to bypass IRP usage using the function pointers contained
++      //      in the following structure
++      FAST_IO_DISPATCH                        Ext2FastIoDispatch;
++      // The NT Cache Manager uses the following call backs to ensure
++      //      correct locking hierarchy is maintained
++      CACHE_MANAGER_CALLBACKS CacheMgrCallBacks;
++      // structures allocated from a zone need some fields here. Note
++      //      that under version 4.0, it might be better to use lookaside
++      //      lists
++      KSPIN_LOCK                                      ZoneAllocationSpinLock;
++      ZONE_HEADER                                     ObjectNameZoneHeader;
++      ZONE_HEADER                                     CCBZoneHeader;
++      ZONE_HEADER                                     FCBZoneHeader;
++      ZONE_HEADER                                     ByteLockZoneHeader;
++      ZONE_HEADER                                     IrpContextZoneHeader;
++      void                                            *ObjectNameZone;
++      void                                            *CCBZone;
++      void                                            *FCBZone;
++      void                                            *ByteLockZone;
++      void                                            *IrpContextZone;
++      
++      //      currently, there is a single default zone size value used for
++      //      all zones. This should ideally be changed by you to be 1 per
++      //      type of zone (e.g. a default size for the FCB zone might be
++      //      different from the default size for the ByteLock zone).
++
++      //      Of course, you will need to use different values (min/max)
++      //      for lookaside lists (if you decide to use them instead)
++      uint32                                          DefaultZoneSizeInNumStructs;
++      
++      // some state information is maintained in the flags field
++      uint32                                          Ext2Flags;
++      
++      // Handle returned by the MUP is stored here.
++      HANDLE                                          MupHandle;
++      
++      //      Time difference 
++      LARGE_INTEGER                           TimeDiff;
++
++      //      The Worker Thread package uses this structure...
++      Ext2ThreadQueue                         ThreadQueue;
++
++}Ext2Data, *PtrExt2Data;
++
++// valid flag values for the global data structure
++#define               EXT2_DATA_FLAGS_RESOURCE_INITIALIZED            (0x00000001)
++#define               EXT2_DATA_FLAGS_ZONES_INITIALIZED                       (0x00000002)
++
++// a default size of the number of pages of non-paged pool allocated
++//    for each of the zones ...
++
++//    Note that the values are absolutely arbitrary, the only information
++//    worth using from the values themselves is that they increase for
++//    larger systems (i.e. systems with more memory)
++#define               EXT2_DEFAULT_ZONE_SIZE_SMALL_SYSTEM                     (0x4)
++#define               EXT2_DEFAULT_ZONE_SIZE_MEDIUM_SYSTEM            (0x8)
++#define               EXT2_DEFAULT_ZONE_SIZE_LARGE_SYSTEM                     (0xc)
++
++// another simplistic (brain dead ? :-) method used is to simply double
++//    the values for a "server" machine
++
++//    So, for all you guys who "modified" the registry ;-) to change the
++//    wkstation into a server, tough luck !
++#define               EXT2_NTAS_MULTIPLE                                                              (0x2)
++
++/***************************************************************************
++The following locking hierarchy is maintained in this sample filesystem
++driver:
++
++(a) the global structure resource can be acquired at any time. However,
++    it is an "end resource" i.e. once acquired, no other resource can
++       be obtained until the global structure resource is released.
++(b) the logical volume resource must be acquired (if required) before
++       any of the other resources are acquired.
++(c) a file control block can be acquired next (if required). If two
++    FCB structures need to be acquired, the FCB "higher" in the directory
++       tree must be acquired first.
++       For a FCB, the "main resource" must be acquired first before a
++       "paging i/o" resource is acquired.
++
++Whenever a file is opened, the logical volume structure is referenced.
++This ensures that the volume cannot be dismounted while any file is open.
++
++***************************************************************************/
++
++typedef struct _IO_RUN
++{
++      UINT LogicalBlock;
++      UINT StartOffset;
++      UINT EndOffset;
++      PIRP PtrAssociatedIrp;
++
++} EXT2_IO_RUN, *PEXT2_IO_RUN;
++
++typedef struct _SIBlocks
++{
++      PBCB    PtrBCB;
++      ULONG * PtrSIBlocks;
++} EXT2_SIBLOCKS, *PEXT2_SIBLOCKS;
++
++#endif        // has this file been included?
++
index 0000000,0000000..81ca894
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,215 @@@
++/*************************************************************************
++*
++* File: DiskIO.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Should contain code to handle Disk IO.
++*
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#include                      "ext2fsd.h"
++
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_DISK_IO
++
++#define                       DEBUG_LEVEL                                             ( DEBUG_TRACE_DISKIO )
++
++
++/*************************************************************************
++*
++* Function: Ext2ReadLogicalBlocks()
++*
++* Description:
++*     The higherlevel functions will use this to read in logical blocks
++*     This function deals with the logical to physical block translation
++*
++*     LogicalBlock -  This is a 1 based index.
++*                                     That is, the first block is Block 1
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL 
++*
++* Return Value: The Status of the Read IO
++*
++*************************************************************************/
++NTSTATUS Ext2ReadLogicalBlocks (
++      PDEVICE_OBJECT          PtrTargetDeviceObject,  //      the Target Device Object
++      VOID                            *Buffer,                                //      The Buffer that takes the data read in
++      LARGE_INTEGER           StartLogicalBlock,              //      The logical block from which reading is to start
++      unsigned int            NoOfLogicalBlocks               //      The no. of logical blocks to be read
++      )                                       
++{
++      //      The Status to be returned...
++      NTSTATUS Status = STATUS_SUCCESS;
++
++      //      The Device Object representing the mounted volume
++      PDEVICE_OBJECT PtrVolumeDeviceObject = NULL;
++      
++      //      Volume Control Block
++      PtrExt2VCB PtrVCB = NULL;
++
++      //      Logical Block Size
++      ULONG LogicalBlockSize;
++
++      // Physical Block Size
++      ULONG PhysicalBlockSize;
++
++      //      The starting Physical Block No...
++      LARGE_INTEGER StartPhysicalBlock;
++
++      unsigned int            NoOfPhysicalBlocks;
++
++
++
++      //      Done with declerations...
++      //      Now for some code ;)
++
++      //      Getting the Logical and Physical Sector sizes
++      PtrVolumeDeviceObject = PtrTargetDeviceObject->Vpb->DeviceObject;
++      ASSERT( PtrVolumeDeviceObject );
++      PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension);
++      ASSERT(PtrVCB);
++      ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
++
++      LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++      PhysicalBlockSize = PtrTargetDeviceObject->SectorSize;
++      
++      NoOfPhysicalBlocks = NoOfLogicalBlocks * LogicalBlockSize / PhysicalBlockSize;
++
++      StartPhysicalBlock.QuadPart = ( StartLogicalBlock.QuadPart ) * 
++                                                                      ( LogicalBlockSize / PhysicalBlockSize );
++
++      Status = Ext2ReadPhysicalBlocks( PtrTargetDeviceObject,
++                                      Buffer, StartPhysicalBlock,     NoOfPhysicalBlocks );
++              
++      return Status;
++}
++
++/*************************************************************************
++*
++* Function: Ext2ReadPhysicalBlocks()
++*
++* Description:
++*     The higherlevel functions will use this to read in physical blocks
++*
++*     PhysicalBlock - This is a 0 based number.
++*                                     That is, the first block is Block 0
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL 
++*
++* Return Value: The Status of the Read IO
++*
++*************************************************************************/
++NTSTATUS Ext2ReadPhysicalBlocks (
++      PDEVICE_OBJECT          PtrTargetDeviceObject,  //      the Target Device Object
++      VOID                            *Buffer,                                //      The Buffer that takes the data read in
++      LARGE_INTEGER           StartPhysicalBlock,             //      The block from which reading is to start
++      unsigned int            NoOfBlocks              //      The no. of blocks to be read
++      )                                       
++{
++      //      The Status to be returned...
++      NTSTATUS Status = STATUS_SUCCESS;
++
++      // Physical Block Size
++      ULONG PhysicalBlockSize;
++
++      // No of bytes to read
++      ULONG NumberOfBytesToRead;
++
++      //      Synchronisation Event
++      KEVENT Event;
++
++      //      IRP
++    PIRP Irp;
++
++      //      Status Block
++    IO_STATUS_BLOCK Iosb;
++
++      //      Byte Offset
++      LARGE_INTEGER ByteOffset;
++
++      //      Done with declerations...
++      //      Now for some code ;)
++
++      //      Getting the Physical Sector size
++      PhysicalBlockSize = PtrTargetDeviceObject->SectorSize;
++      
++      NumberOfBytesToRead = PhysicalBlockSize * NoOfBlocks;
++
++      ByteOffset.QuadPart = StartPhysicalBlock.QuadPart * PhysicalBlockSize;
++
++      try
++      {
++              //
++              //  Initialize the event we're going to use
++              //
++              KeInitializeEvent( &Event, NotificationEvent, FALSE );
++
++              //
++              //  Build the irp for the operation and also set the overrride flag
++              //
++              Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
++                                                                                      PtrTargetDeviceObject,
++                                                                                      Buffer,
++                                                                                      NumberOfBytesToRead,
++                                                                                      &ByteOffset ,
++                                                                                      &Event,
++                                                                                      &Iosb );
++
++              if ( Irp == NULL ) 
++              {
++                      DebugTrace(DEBUG_TRACE_MISC,   " !!!! Unable to create an IRP", 0 );
++                      Status = STATUS_INSUFFICIENT_RESOURCES;
++                      try_return( Status );
++              }
++
++              //
++              //  Call the device to do the read and wait for it to finish.
++              //
++              Status = IoCallDriver( PtrTargetDeviceObject, Irp );
++
++              //
++              //      Check if it is done already!!!!
++              //
++              if (Status == STATUS_PENDING) 
++              {
++                      //
++                      //      Read not done yet...
++                      //      Wait till it is...
++                      //
++                      (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
++                      Status = Iosb.Status;
++              }
++
++              try_exit:       NOTHING;
++      }
++      finally
++      {
++              if (!NT_SUCCESS(Status)) 
++              {
++                      if( Status == STATUS_VERIFY_REQUIRED )
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,   " !!!! Verify Required! Failed to read disk",0 );
++                      }
++                      else if (Status == STATUS_INVALID_PARAMETER) 
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,   " !!!! Invalid Parameter! Failed to read disk",0 );
++                      }
++                      else 
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,   " !!!! Failed to read disk! Status returned = %d", Status );
++                      }
++              }
++      }
++      return Status;
++}
++
++
index 0000000,0000000..50a2ab0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,400 @@@
++/*************************************************************************
++*
++* File: cleanup.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Should contain code to handle the "Cleanup" dispatch entry point.
++*     This file serves as a placeholder. Please update this file as part
++*     of designing and implementing your FSD.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#include                      "ext2fsd.h"
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_CLEANUP
++#define                       DEBUG_LEVEL                                             (DEBUG_TRACE_CLEANUP)
++
++
++/*************************************************************************
++*
++* Function: Ext2Cleanup()
++*
++* Description:
++*     The I/O Manager will invoke this routine to handle a cleanup
++*     request
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
++*     to be deferred to a worker thread context)
++*
++* Return Value: Does not matter!
++*
++*************************************************************************/
++NTSTATUS Ext2Cleanup(
++PDEVICE_OBJECT                DeviceObject,           // the logical volume device object
++PIRP                                  Irp)                                    // I/O Request Packet
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++    PtrExt2IrpContext PtrIrpContext = NULL;
++      BOOLEAN                         AreWeTopLevel = FALSE;
++
++      DebugTrace( DEBUG_TRACE_IRP_ENTRY, "Cleanup IRP Received...", 0);
++
++      FsRtlEnterFileSystem();
++      ASSERT(DeviceObject);
++      ASSERT(Irp);
++
++      // set the top level context
++      AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
++
++      try
++      {
++
++              // get an IRP context structure and issue the request
++              PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
++              ASSERT(PtrIrpContext);
++
++              RC = Ext2CommonCleanup(PtrIrpContext, Irp, TRUE);
++
++      } 
++      except( Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation() ) ) 
++      {
++
++              RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
++
++              Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++      }
++
++      if (AreWeTopLevel) 
++      {
++              IoSetTopLevelIrp(NULL);
++      }
++
++      FsRtlExitFileSystem();
++
++      return(RC);
++}
++
++/*************************************************************************
++*
++* Function: Ext2CommonCleanup()
++*
++* Description:
++*     The actual work is performed here. This routine may be invoked in one'
++*     of the two possible contexts:
++*     (a) in the context of a system worker thread
++*     (b) in the context of the original caller
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: Does not matter!
++*
++*************************************************************************/
++NTSTATUS      Ext2CommonCleanup(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp,
++BOOLEAN                                               FirstAttempt )
++{
++
++      NTSTATUS                                        RC = STATUS_SUCCESS;
++      PIO_STACK_LOCATION      PtrIoStackLocation = NULL;
++      PFILE_OBJECT                    PtrFileObject = NULL;
++      PtrExt2FCB                              PtrFCB = NULL;
++      PtrExt2CCB                              PtrCCB = NULL;
++      PtrExt2VCB                              PtrVCB = NULL;
++      PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
++      PERESOURCE                              PtrResourceAcquired = NULL;
++      IO_STATUS_BLOCK                 LocalIoStatus;
++
++      BOOLEAN                                 CompleteIrp = TRUE;
++      BOOLEAN                                 PostRequest = FALSE;
++      BOOLEAN                                 AcquiredVCB = FALSE;
++      BOOLEAN                                 CanWait = FALSE;
++      BOOLEAN                                 BlockForResource;
++      int                                             i = 1;
++
++      try 
++      {
++              // First, get a pointer to the current I/O stack location
++              PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
++              ASSERT(PtrIoStackLocation);
++
++              PtrFileObject = PtrIoStackLocation->FileObject;
++              ASSERT(PtrFileObject);
++
++              if( !PtrFileObject->FsContext2 )
++              {
++                      //      This must be a Cleanup request received 
++                      //      as a result of IoCreateStreamFileObject
++                      //      Only such a File object would have a NULL CCB
++
++                      DebugTrace( DEBUG_TRACE_MISC, " === Cleanup with NULL CCB", 0);
++                      if( PtrFileObject )
++                      {
++                              DebugTrace( DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject);
++                      }
++                      try_return( RC );
++              }
++              
++
++              Ext2GetFCB_CCB_VCB_FromFileObject ( 
++                      PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB );
++
++              if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer )
++              //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer )
++              {
++                      DebugTrace( DEBUG_TRACE_FILE_NAME, " === Cleanup File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer );
++              }
++              else
++              {
++                      DebugTrace( DEBUG_TRACE_FILE_NAME, " === Cleanup Volume", 0);
++              }
++
++
++              PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
++              ASSERT(PtrVCB);
++              ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
++              
++              //      (a) Acquiring the VCBResource Exclusively...
++              //      This is done to synchronise with the close and cleanup routines...
++              BlockForResource = !FirstAttempt;
++              if( !FirstAttempt )
++              {
++                      
++                      DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Going into a block to acquire VCB Exclusively [Cleanup]", 0);
++              }
++              else
++              {
++                      DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire VCB Exclusively [Cleanup]", 0);
++              }
++
++              if( PtrFileObject )
++              {
++                      DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject);
++              }
++
++              i = 1;
++              while( !AcquiredVCB )
++              {
++                      DebugTraceState("VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Cleanup]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
++                      if( ! ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) )
++                      {
++                              DebugTrace( DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquisition FAILED [Cleanup]", 0);
++                              if( BlockForResource && i != 1000 )
++                              {
++                                      LARGE_INTEGER Delay;
++                                      Delay.QuadPart = -500 * i;
++                                      KeDelayExecutionThread( KernelMode, FALSE, &Delay );
++                                      DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Retrying... after 50 * %ld ms [Cleanup]", i);
++                              }
++                              else
++                              {
++                                      if( i == 1000 )
++                                              DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Reposting... [Cleanup]", 0 );
++                                      PostRequest = TRUE;
++                                      try_return( RC = STATUS_PENDING );
++                              }
++                      }
++                      else
++                      {
++                              DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** VCB Acquired in [Cleanup]", 0);
++                              AcquiredVCB = TRUE;
++                      }
++                      i *= 10;
++              }
++
++
++              //      (b) Acquire the file (FCB) exclusively
++              if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB )
++              {
++                      //      This FCB is an FCB indeed. ;)
++                      //      So acquiring it exclusively...
++                      //      This is done to synchronise with read/write routines...
++                      if( !FirstAttempt )
++                      {
++                              DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Going into a block to acquire FCB Exclusively [Cleanup]", 0);
++                      }
++                      else
++                      {
++                              DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** Attempting to acquire FCB Exclusively [Cleanup]", 0);
++                      }
++                      if( PtrFileObject )
++                      {
++                              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject);
++                      }
++
++                      i = 1;
++                      while( !PtrResourceAcquired )
++                      {
++                              PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
++                              DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [Cleanup]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
++                              if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) )
++                              {
++                                      DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB Acquisition FAILED [Cleanup]", 0);
++                                      if( BlockForResource && i != 1000 )
++                                      {
++                                              LARGE_INTEGER Delay;
++                                              Delay.QuadPart = -500 * i;
++                                              KeDelayExecutionThread( KernelMode, FALSE, &Delay );
++                                              DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Retrying... after 50 * %ld ms [Cleanup]", i);
++                                      }
++                                      else
++                                      {
++                                              if( i == 1000 )
++                                                      DebugTrace(DEBUG_TRACE_RESOURCE_RETRY, "*** Reposting... [Cleanup]", 0 );
++                                              PostRequest = TRUE;
++                                              try_return( RC = STATUS_PENDING );
++                                      }
++                              }
++                              else
++                              {
++                                      DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE, "*** FCB acquired [Cleanup]", 0);
++                                      PtrResourceAcquired = & ( PtrFCB->NTRequiredFCB.MainResource );
++                              }
++                              i *= 10;
++                      }
++      
++                      // (c) Flush file data to disk
++                      if ( PtrFileObject->PrivateCacheMap != NULL) 
++                      {
++                              IO_STATUS_BLOCK Status;
++                              CcFlushCache( PtrFileObject->SectionObjectPointer, NULL, 0, &Status );
++                      }
++
++                      // (d) Talk to the FSRTL package (if you use it) about pending oplocks.
++                      // (e) Notify the FSRTL package (if you use it) for use with pending
++                      //               notification IRPs
++                      // (f) Unlock byte-range locks (if any were acquired by process)
++                      
++                      // (g) Attempting to update time stamp values
++                      //      Errors are ignored...
++                      //      Not considered as critical errors...
++
++                      /*
++                      if( PtrFCB->OpenHandleCount == 1 )
++                      {
++                              ULONG                   CreationTime, AccessTime, ModificationTime;
++                              EXT2_INODE              Inode;
++
++                              CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart 
++                                                              - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
++                              AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart 
++                                                              - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
++                              ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart
++                                                              - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
++                              if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
++                              {
++                                      //      Update time stamps in the inode...
++                                      Inode.i_ctime = CreationTime;
++                                      Inode.i_atime = AccessTime;
++                                      Inode.i_mtime = ModificationTime;
++
++                                      //      Updating the inode...
++                                      Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode );
++                              }
++                      }
++                      */
++                      
++                      // (h) Inform the Cache Manager to uninitialize Cache Maps ...
++                      CcUninitializeCacheMap( PtrFileObject, NULL, NULL );
++
++                      // (i) Decrementing the Open Handle count...
++                      if( PtrFCB->OpenHandleCount )
++                      {
++                              InterlockedDecrement( &PtrFCB->OpenHandleCount );
++                      }
++                      else
++                      {
++                              Ext2BreakPoint();
++                      }
++
++                      PtrFCB->FCBFlags |= FO_CLEANUP_COMPLETE;
++                      
++                      DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^ReferenceCount  = 0x%lX [Cleanup]", PtrFCB->ReferenceCount );   
++                      DebugTrace(DEBUG_TRACE_REFERENCE, "^^^^^OpenHandleCount = 0x%lX [Cleanup]", PtrFCB->OpenHandleCount );
++
++                      //      (j) Remove share access...
++                      //              Will do that later ;)
++
++                      //      (k) Is this a close on delete file?
++                      //              If so, delete the file...
++                      if( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE) && 
++                              !PtrFCB->OpenHandleCount )
++                      {
++                              //
++                              //      Have to delete this file...
++                              //
++                              Ext2DeleteFile( PtrFCB, PtrIrpContext );
++                              PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = 0;
++                              PtrFCB->INodeNo = 0;
++                      }
++              }
++              else
++              {
++                      //      This must be a volume close...
++                      //      Just go ahead and complete this IRP...
++                      PtrVCB->VCBOpenCount--;
++                      DebugTrace(DEBUG_TRACE_MISC,   "VCB Cleanup Requested !!!", 0);
++                      CompleteIrp = TRUE;
++              }
++              
++              try_return( RC );
++
++              try_exit:       NOTHING;
++
++      }
++      finally 
++      {
++              if(PtrResourceAcquired) 
++              {
++                      Ext2ReleaseResource(PtrResourceAcquired);
++                      DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** Resource Released [Cleanup]", 0);
++                      DebugTraceState( "Resource     AC:0x%LX   SW:0x%LX   EX:0x%LX   [Cleanup]", 
++                              PtrResourceAcquired->ActiveCount, 
++                              PtrResourceAcquired->NumberOfExclusiveWaiters, 
++                              PtrResourceAcquired->NumberOfSharedWaiters );
++
++                      if( PtrFileObject )
++                      {
++                              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject);
++                      }
++                      
++              }
++
++              if( AcquiredVCB )
++              {
++                      ASSERT(PtrVCB);
++                      Ext2ReleaseResource(&(PtrVCB->VCBResource));
++                      DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE, "*** VCB Released [Cleanup]", 0);
++                      DebugTraceState( "VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Cleanup]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
++                      AcquiredVCB = FALSE;
++                      if( PtrFileObject )
++                      {
++                              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Cleanup]", PtrFileObject);
++                      }
++                      
++              }
++
++              if( PostRequest )
++              {
++                      RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
++              }
++              if( RC != STATUS_PENDING )
++              {
++                      Ext2ReleaseIrpContext( PtrIrpContext );
++                      // complete the IRP
++                      IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT );
++              }
++      } // end of "finally" processing
++
++      return(RC);
++}
index 0000000,0000000..8b83497
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,459 @@@
++/*************************************************************************
++*
++* File: close.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Should contain code to handle the "Close" dispatch entry point.
++*     This file serves as a placeholder. Please update this file as part
++*     of designing and implementing your FSD.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#include                      "ext2fsd.h"
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_CLOSE
++
++#define                       DEBUG_LEVEL                                             (DEBUG_TRACE_CLOSE)
++
++
++/*************************************************************************
++*
++* Function: Ext2Close()
++*
++* Description:
++*     The I/O Manager will invoke this routine to handle a close
++*     request
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
++*     to be deferred to a worker thread context)
++*
++* Return Value: Does not matter!
++*
++*************************************************************************/
++NTSTATUS Ext2Close(
++PDEVICE_OBJECT                DeviceObject,           // the logical volume device object
++PIRP                                  Irp)                                    // I/O Request Packet
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++      BOOLEAN                         AreWeTopLevel = FALSE;
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Close IRP Received...", 0);
++      
++
++      FsRtlEnterFileSystem();
++
++      ASSERT(DeviceObject);
++      ASSERT(Irp);
++
++      // set the top level context
++      AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
++
++      try 
++      {
++
++              // get an IRP context structure and issue the request
++              PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
++              ASSERT(PtrIrpContext);
++
++              RC = Ext2CommonClose(PtrIrpContext, Irp, TRUE);
++
++      }
++      except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++      {
++
++              RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
++              Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++      }
++
++      if (AreWeTopLevel) 
++      {
++              IoSetTopLevelIrp(NULL);
++      }
++
++      FsRtlExitFileSystem();
++
++      return(RC);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2CommonClose()
++*
++* Description:
++*     The actual work is performed here. This routine may be invoked in one'
++*     of the two possible contexts:
++*     (a) in the context of a system worker thread
++*     (b) in the context of the original caller
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: Does not matter!
++*
++*************************************************************************/
++NTSTATUS      Ext2CommonClose(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp,
++BOOLEAN                                               FirstAttempt )
++{
++      NTSTATUS                                        RC = STATUS_SUCCESS;
++      PIO_STACK_LOCATION      PtrIoStackLocation = NULL;
++      PFILE_OBJECT                    PtrFileObject = NULL;
++      PtrExt2FCB                              PtrFCB = NULL;
++      PtrExt2CCB                              PtrCCB = NULL;
++      PtrExt2VCB                              PtrVCB = NULL;
++      PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
++      PERESOURCE                              PtrResourceAcquired = NULL;
++      IO_STATUS_BLOCK         LocalIoStatus;
++
++      BOOLEAN                                 CompleteIrp = TRUE;
++      BOOLEAN                                 PostRequest = FALSE;
++      BOOLEAN                                 AcquiredVCB = FALSE;
++      BOOLEAN                                 CanWait = FALSE;
++      BOOLEAN                                 BlockForResource;
++      int                                             i = 1;
++
++      try 
++      {
++              // First, get a pointer to the current I/O stack location
++              PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
++              ASSERT(PtrIoStackLocation);
++
++              PtrFileObject = PtrIoStackLocation->FileObject;
++              ASSERT(PtrFileObject);
++
++              if( !PtrFileObject->FsContext2 )
++              {
++                      //      This must be a Cleanup request received 
++                      //      as a result of IoCreateStreamFileObject
++                      //      Only such a File object would have a NULL CCB
++
++                      DebugTrace( DEBUG_TRACE_SPECIAL, " === Close with NULL CCB", 0);
++                      if( PtrFileObject )
++                      {
++                              DebugTrace( DEBUG_TRACE_SPECIAL, "###### File Pointer 0x%LX [Close]", PtrFileObject);
++                      }
++                      Ext2BreakPoint();
++                      try_return( RC );
++              }
++
++              // Get the FCB and CCB pointers
++
++              Ext2GetFCB_CCB_VCB_FromFileObject ( 
++                      PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB );
++
++              PtrVCB = (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
++              ASSERT( PtrVCB );
++
++              if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer )
++              //if( PtrFileObject->FileName.Length && PtrFileObject->FileName.Buffer )
++              {
++                      DebugTrace(DEBUG_TRACE_FILE_NAME, " === Close File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer );
++              }
++              else
++              {
++                      DebugTrace(DEBUG_TRACE_FILE_NAME,   " === Close File Name : -null-", 0);
++              }
++
++              //      (a) Acquiring the VCBResource Exclusively...
++              //      This is done to synchronise with the close and cleanup routines...
++//            if( ExTryToAcquireResourceExclusiveLite(&(PtrVCB->VCBResource) ) )
++
++              BlockForResource = !FirstAttempt;
++              if( !FirstAttempt )
++              {
++                      DebugTrace(DEBUG_TRACE_MISC, "*** Going into a block to acquire VCB Exclusively [Close]", 0);
++              }
++              else
++              {
++                      DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire VCB Exclusively [Close]", 0);
++              }
++              if( PtrFileObject )
++              {
++                      DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject);
++              }
++              i = 1;
++              while( !AcquiredVCB )
++              {
++                      DebugTraceState( "VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
++                      if(! ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) )
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,   "*** VCB Acquisition FAILED [Close]", 0);
++                              if( BlockForResource && i != 1000 )
++                              {
++                                      LARGE_INTEGER Delay;
++                                      
++                                      //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY       );
++
++                                      Delay.QuadPart = -500 * i;
++                                      KeDelayExecutionThread( KernelMode, FALSE, &Delay );
++                                      DebugTrace(DEBUG_TRACE_MISC,  "*** Retrying... after 50 * %ld ms [Close]", i);
++                              }
++                              else
++                              {
++                                      if( i == 1000 )
++                                              DebugTrace(DEBUG_TRACE_MISC,  "*** Reposting... [Close]", 0 );
++                                      PostRequest = TRUE;
++                                      try_return( RC = STATUS_PENDING );
++                              }
++                      }
++                      else
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,  "*** VCB Acquired in [Close]", 0);
++                              AcquiredVCB = TRUE;
++                      }
++                      i *= 10;
++              }
++
++              //      (b) Acquire the file (FCB) exclusively
++              if( PtrFCB && PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB )
++              {
++                      //      This FCB is an FCB indeed. ;)
++                      //      So acquiring it exclusively...
++                      //      This is done to synchronise with read/write routines...
++                      if( !FirstAttempt )
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,   "*** Going into a block to acquire FCB Exclusively [Close]", 0);
++                      }
++                      else
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,  "*** Attempting to acquire FCB Exclusively [Close]", 0);
++                      }
++                      if( PtrFileObject )
++                      {
++                              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Close]", PtrFileObject);
++                      }
++                      i = 1;
++                      while( !PtrResourceAcquired )
++                      {
++                              PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
++
++                              DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [Close]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
++                              if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) )
++                              {
++                                      DebugTrace(DEBUG_TRACE_MISC,   "*** FCB Acquisition FAILED [Close]", 0);
++                                      if( BlockForResource && i != 1000 )
++                                      {
++                                              LARGE_INTEGER Delay;
++                                              
++                                              //KeSetPriorityThread( PsGetCurrentThread(),LOW_REALTIME_PRIORITY       );
++
++                                              Delay.QuadPart = -500 * i;
++                                              KeDelayExecutionThread( KernelMode, FALSE, &Delay );
++                                              DebugTrace(DEBUG_TRACE_MISC,  "*** Retrying... after 50 * %ld ms [Close]", i);
++                                      }
++                                      else
++                                      {
++                                              if( i == 1000 )
++                                                      DebugTrace(DEBUG_TRACE_MISC,  "*** Reposting... [Close]", 0 );
++                                              PostRequest = TRUE;
++                                              try_return( RC = STATUS_PENDING );
++                                      }
++                              }
++                              else
++                              {
++                                      DebugTrace(DEBUG_TRACE_MISC,  "*** FCB acquired [Close]", 0);
++                                      PtrResourceAcquired = & ( PtrFCB->NTRequiredFCB.MainResource );
++                              }
++                              i *= 10;
++                      }
++
++                      // (c) Delete the CCB structure (free memory)
++                      RemoveEntryList( &PtrCCB->NextCCB );
++                      Ext2ReleaseCCB( PtrCCB );
++                      PtrFileObject->FsContext2 = NULL;
++
++                      // (d) Decrementing the Reference Count...
++                      if( PtrFCB->ReferenceCount )
++                      {
++                              InterlockedDecrement( &PtrFCB->ReferenceCount );
++                      }
++                      else
++                      {
++                              Ext2BreakPoint();
++                      }       
++                      DebugTrace(DEBUG_TRACE_REFERENCE,  "^^^^^ReferenceCount = 0x%lX [Close]", PtrFCB->ReferenceCount );
++                      DebugTrace(DEBUG_TRACE_REFERENCE,  "^^^^^OpenHandleCount = 0x%lX [Close]", PtrFCB->OpenHandleCount );
++                      if( PtrFCB->ReferenceCount == 0 )
++                      {
++
++                              //      Attempting to update time stamp values
++                              //      Errors are ignored...
++                              //      Not considered as critical errors...
++                              
++                              {
++                                      ULONG                   CreationTime, AccessTime, ModificationTime;
++                                      EXT2_INODE              Inode;
++
++                                      CreationTime = (ULONG) ( (PtrFCB->CreationTime.QuadPart 
++                                                                      - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
++                                      AccessTime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart 
++                                                                      - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
++                                      ModificationTime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart
++                                                                      - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
++                                      if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
++                                      {
++                                              //      Update time stamps in the inode...
++                                              Inode.i_ctime = CreationTime;
++                                              Inode.i_atime = AccessTime;
++                                              Inode.i_mtime = ModificationTime;
++
++                                              //      Updating the inode...
++                                              Ext2WriteInode( NULL, PtrVCB, PtrFCB->INodeNo, &Inode );
++                                      }
++                              }
++
++
++                              if( PtrFCB->INodeNo == EXT2_ROOT_INO )
++                              {
++                                      //
++                                      //      Root Directory FCB
++                                      //      Preserve this
++                                      //      FSD has a File Object for this FCB...
++                                      //
++                                      DebugTrace(DEBUG_TRACE_MISC,  "^^^^^Root Directory FCB ; leaveing it alone[Close]", 0);
++                                      //      Do nothing...
++                                      
++                              }
++                              else if( PtrFCB->DcbFcb.Dcb.PtrDirFileObject )
++                              {
++                                      //
++                                      //      If this is a FCB created on the FSD's initiative
++                                      //      Leave it alone
++                                      //
++                                      DebugTrace(DEBUG_TRACE_MISC,  "^^^^^FCB Created  on the FSD's initiative; leaveing it alone[Close]", 0);
++                                      if( !PtrFCB->ClosableFCBs.OnClosableFCBList )
++                                      {
++                                              InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead,
++                                                      &PtrFCB->ClosableFCBs.ClosableFCBList );
++                                              PtrVCB->ClosableFCBs.Count++;
++
++                                              PtrFCB->ClosableFCBs.OnClosableFCBList = TRUE;
++                                      }
++                                      
++                                      if( PtrVCB->ClosableFCBs.Count > EXT2_MAXCLOSABLE_FCBS_UL )
++                                      {
++                                              PtrExt2FCB              PtrTempFCB = NULL;
++                                              //      Checking if Closable FCBs are too many in number...
++                                              //      Shouldn't block the 
++                                              //      Should do this asynchronously...
++                                              //      Maybe later...
++                                              PLIST_ENTRY             PtrEntry = NULL;
++
++                                              PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead );
++                                              
++                                              PtrTempFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList );
++                                              if( Ext2CloseClosableFCB( PtrTempFCB ) )
++                                              {
++                                                      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Close]", PtrTempFCB );
++                                                      ExFreePool( PtrTempFCB );
++                                                      PtrVCB->ClosableFCBs.Count--;
++                                              }
++                                              else
++                                              {
++                                                      //      Put the FCB back in the list...
++                                                      InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead,
++                                                              &PtrTempFCB->ClosableFCBs.ClosableFCBList );
++                                              }
++                                              DebugTrace( DEBUG_TRACE_SPECIAL, "ClosableFCBs Count = %ld [Close]", PtrVCB->ClosableFCBs.Count );
++                                      }
++                              }
++                              else
++                              {
++                                      //      Remove this FCB as well...
++                                      DebugTrace(DEBUG_TRACE_MISC,  "^^^^^Deleting FCB  [Close]", 0);
++                                      RemoveEntryList( &PtrFCB->NextFCB );
++
++                                      if ( PtrResourceAcquired ) 
++                                      {
++                                              Ext2ReleaseResource(PtrResourceAcquired);
++                                              DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Released [Close]", 0);
++                                              DebugTraceState( "Resource     AC:0x%LX   SW:0x%LX   EX:0x%LX   [Close]", 
++                                                      PtrResourceAcquired->ActiveCount, 
++                                                      PtrResourceAcquired->NumberOfExclusiveWaiters, 
++                                                      PtrResourceAcquired->NumberOfSharedWaiters );
++
++                                              if( PtrFileObject )
++                                              {
++                                                      DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject);
++                                              }
++                                              PtrResourceAcquired = FALSE;
++                                      }
++                                      Ext2ReleaseFCB( PtrFCB );
++                              }
++
++                      }
++                      CompleteIrp = TRUE;
++              }
++              else
++              {
++                      //      This must be a volume close...
++                      //      What do I do now? ;)
++                      DebugTrace(DEBUG_TRACE_MISC,   "VCB Close Requested !!!", 0);
++                      CompleteIrp = TRUE;
++              }
++              try_return( RC );
++              
++              try_exit:       NOTHING;
++
++      } 
++      finally 
++      {
++              if ( PtrResourceAcquired ) 
++              {
++                      Ext2ReleaseResource(PtrResourceAcquired);
++                      DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Released [Close]", 0);
++                      DebugTraceState( "Resource     AC:0x%LX   SW:0x%LX   EX:0x%LX   [Close]", 
++                              PtrResourceAcquired->ActiveCount, 
++                              PtrResourceAcquired->NumberOfExclusiveWaiters, 
++                              PtrResourceAcquired->NumberOfSharedWaiters );
++
++                      if( PtrFileObject )
++                      {
++                              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject);
++                      }
++                      PtrResourceAcquired = FALSE;
++              }
++
++              if (AcquiredVCB) 
++              {
++                      ASSERT(PtrVCB);
++                      Ext2ReleaseResource(&(PtrVCB->VCBResource));
++                      DebugTraceState( "VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Close]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
++                      DebugTrace(DEBUG_TRACE_MISC,   "*** VCB Released [Close]", 0);
++
++                      AcquiredVCB = FALSE;
++                      if( PtrFileObject )
++                      {
++                              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [Close]", PtrFileObject);
++                      }
++                      
++              }
++
++              if( PostRequest )
++              {
++                      RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
++              }
++              else if( CompleteIrp && RC != STATUS_PENDING )
++              {
++                      // complete the IRP
++                      IoCompleteRequest( PtrIrp, IO_DISK_INCREMENT );
++
++                      Ext2ReleaseIrpContext( PtrIrpContext );
++              }
++
++      } // end of "finally" processing
++
++      return(RC);
++}
index 0000000,0000000..13fe4e1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1681 @@@
++/*************************************************************************
++*
++* File: create.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Contains code to handle the "Create"/"Open" dispatch entry point.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#include                      "ext2fsd.h"
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_CREATE
++
++#define                       DEBUG_LEVEL                                             (DEBUG_TRACE_CREATE)
++ 
++
++/*************************************************************************
++*
++* Function: Ext2Create()
++*
++* Description: 
++*     The I/O Manager will invoke this routine to handle a create/open
++*     request
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
++*     to be deferred to a worker thread context)
++*
++* Return Value: STATUS_SUCCESS/Error
++*
++*************************************************************************/
++NTSTATUS Ext2Create(
++PDEVICE_OBJECT                DeviceObject,           // the logical volume device object
++PIRP                                  Irp)                                    // I/O Request Packet
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++    PtrExt2IrpContext PtrIrpContext;
++      BOOLEAN                         AreWeTopLevel = FALSE;
++
++      DebugTrace( DEBUG_TRACE_IRP_ENTRY, "Create Control IRP received...", 0);
++
++      FsRtlEnterFileSystem();
++      
++      //      Ext2BreakPoint();
++
++      ASSERT(DeviceObject);
++      ASSERT(Irp);
++
++      // sometimes, we may be called here with the device object representing
++      //      the file system (instead of the device object created for a logical
++      //      volume. In this case, there is not much we wish to do (this create
++      //      typically will happen 'cause some process has to open the FSD device
++      //      object so as to be able to send an IOCTL to the FSD)
++
++      //      All of the logical volume device objects we create have a device
++      //      extension whereas the device object representing the FSD has no
++      //      device extension. This seems like a good enough method to identify
++      //      between the two device objects ...
++      if (DeviceObject->Size == (unsigned short)(sizeof(DEVICE_OBJECT))) 
++      {
++              // this is an open of the FSD itself
++              DebugTrace( DEBUG_TRACE_MISC, " === Open for the FSD itself", 0);
++              Irp->IoStatus.Status = RC;
++              Irp->IoStatus.Information = FILE_OPENED;
++
++              IoCompleteRequest(Irp, IO_NO_INCREMENT);
++              return(RC);
++      }
++
++      // set the top level context
++      AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
++
++      try 
++      {
++
++              // get an IRP context structure and issue the request
++              PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
++              ASSERT(PtrIrpContext);
++
++              RC = Ext2CommonCreate(PtrIrpContext, Irp, TRUE );
++
++      } 
++      except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++      {
++
++              RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
++
++              Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++      }
++
++      if (AreWeTopLevel) 
++      {
++              IoSetTopLevelIrp(NULL);
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(RC);
++}
++
++
++
++/*************************************************************************
++*
++* Function: Ext2CommonCreate()
++*
++* Description:
++*     The actual work is performed here. This routine may be invoked in one'
++*     of the two possible contexts:
++*     (a) in the context of a system worker thread
++*     (b) in the context of the original caller
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: STATUS_SUCCESS/Error
++*
++*************************************************************************/
++NTSTATUS Ext2CommonCreate(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                          PtrIrp,
++BOOLEAN                                               FirstAttempt)
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PIO_STACK_LOCATION              PtrIoStackLocation = NULL;
++      PIO_SECURITY_CONTEXT    PtrSecurityContext = NULL;
++      PFILE_OBJECT                    PtrNewFileObject = NULL;
++      PFILE_OBJECT                    PtrRelatedFileObject = NULL;
++      uint32                                  AllocationSize = 0;     // if we create a new file
++      PFILE_FULL_EA_INFORMATION       PtrExtAttrBuffer = NULL;
++      unsigned long                   RequestedOptions = 0;
++      unsigned long                   RequestedDisposition = 0;
++      uint8                                   FileAttributes = 0;
++      unsigned short                  ShareAccess = 0;
++      unsigned long                   ExtAttrLength = 0;
++      ACCESS_MASK                             DesiredAccess;
++
++      BOOLEAN                                 DeferredProcessing = FALSE;
++
++      PtrExt2VCB                              PtrVCB = NULL;
++      BOOLEAN                                 AcquiredVCB = FALSE;
++
++      BOOLEAN                                 DirectoryOnlyRequested = FALSE;
++      BOOLEAN                                 FileOnlyRequested = FALSE;
++      BOOLEAN                                 NoBufferingSpecified = FALSE;
++      BOOLEAN                                 WriteThroughRequested = FALSE;
++      BOOLEAN                                 DeleteOnCloseSpecified = FALSE;
++      BOOLEAN                                 NoExtAttrKnowledge = FALSE;
++      BOOLEAN                                 CreateTreeConnection = FALSE;
++      BOOLEAN                                 OpenByFileId    = FALSE;
++
++      BOOLEAN                                 SequentialOnly  = FALSE;
++      BOOLEAN                                 RandomAccess    = FALSE;
++      
++      // Are we dealing with a page file?
++      BOOLEAN                                 PageFileManipulation = FALSE;
++
++      // Is this open for a target directory (used in rename operations)?
++      BOOLEAN                                 OpenTargetDirectory = FALSE;
++
++      // Should we ignore case when attempting to locate the object?
++      BOOLEAN                                 IgnoreCaseWhenChecking = FALSE;
++
++      PtrExt2CCB                              PtrRelatedCCB = NULL, PtrNewCCB = NULL;
++      PtrExt2FCB                              PtrRelatedFCB = NULL, PtrNewFCB = NULL;
++
++      unsigned long                   ReturnedInformation = -1;
++
++      UNICODE_STRING                  TargetObjectName;
++      UNICODE_STRING                  RelatedObjectName;
++
++      UNICODE_STRING                  AbsolutePathName;
++      UNICODE_STRING                  RenameLinkTargetFileName;
++
++      LARGE_INTEGER                   FileAllocationSize, FileEndOfFile;
++
++
++      ASSERT(PtrIrpContext);
++      ASSERT(PtrIrp);
++
++      try 
++      {
++
++              AbsolutePathName.Buffer = NULL;
++              AbsolutePathName.Length = AbsolutePathName.MaximumLength = 0;
++
++              // Getting a pointer to the current I/O stack location
++              PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
++              ASSERT(PtrIoStackLocation);
++
++              // Can we block?
++              if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK)) 
++              {
++                      //      Asynchronous processing required...
++                      RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
++                      DeferredProcessing = TRUE;
++                      try_return(RC);
++              }
++
++              // Obtaining the parameters specified by the user.
++              PtrNewFileObject        = PtrIoStackLocation->FileObject;
++              TargetObjectName        = PtrNewFileObject->FileName;
++              PtrRelatedFileObject = PtrNewFileObject->RelatedFileObject;
++
++              if( PtrNewFileObject->FileName.Length && PtrNewFileObject->FileName.Buffer )
++              {
++                      if( PtrNewFileObject->FileName.Buffer[ PtrNewFileObject->FileName.Length/2 ] != 0 )
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC, "&&&&&&&&&  PtrFileObject->FileName not NULL terminated! [Create]", 0 );
++                      }
++                      DebugTrace( DEBUG_TRACE_FILE_NAME, " === Create/Open File Name : -%S- [Create]", PtrNewFileObject->FileName.Buffer );
++              }
++              else
++              {
++                      DebugTrace( DEBUG_TRACE_FILE_NAME, " === Create/Open File Name : -null- [Create]", 0);
++              }
++
++              // Is this a Relative Create/Open?
++              if (PtrRelatedFileObject) 
++              {
++                      PtrRelatedCCB = (PtrExt2CCB)(PtrRelatedFileObject->FsContext2);
++                      ASSERT(PtrRelatedCCB);
++                      ASSERT(PtrRelatedCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB);
++                      // each CCB in turn points to a FCB
++                      PtrRelatedFCB = PtrRelatedCCB->PtrFCB;
++                      ASSERT(PtrRelatedFCB);
++                      if( PtrRelatedFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB &&
++                              PtrRelatedFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_VCB    )
++                      {
++                              //      How the hell can this happen!!!
++                              Ext2BreakPoint();
++                      }
++
++                      AssertFCBorVCB( PtrRelatedFCB );
++
++                      RelatedObjectName = PtrRelatedFileObject->FileName;
++
++                      if( PtrRelatedFileObject->FileName.Length && PtrRelatedFileObject->FileName.Buffer )
++                      {
++                              DebugTrace( DEBUG_TRACE_FILE_NAME, " === Relative to : -%S-", PtrRelatedFileObject->FileName.Buffer );
++                      }
++                      else
++                      {
++                              DebugTrace( DEBUG_TRACE_FILE_NAME, " === Relative to : -null-",0);
++                      }
++
++              }
++
++
++              AllocationSize    = PtrIrp->Overlay.AllocationSize.LowPart;
++              //      Only 32 bit file sizes supported...
++
++              if (PtrIrp->Overlay.AllocationSize.HighPart) 
++              {
++                      RC = STATUS_INVALID_PARAMETER;
++                      try_return(RC);
++              }
++
++              // Getting a pointer to the supplied security context
++              PtrSecurityContext = PtrIoStackLocation->Parameters.Create.SecurityContext;
++
++              // Obtaining the desired access 
++              DesiredAccess = PtrSecurityContext->DesiredAccess;
++
++              //      Getting the options supplied by the user...
++              RequestedOptions = (PtrIoStackLocation->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS);
++              RequestedDisposition = ((PtrIoStackLocation->Parameters.Create.Options >> 24) & 0xFF);
++
++              FileAttributes  = (uint8)(PtrIoStackLocation->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS);
++              ShareAccess     = PtrIoStackLocation->Parameters.Create.ShareAccess;
++              PtrExtAttrBuffer        = PtrIrp->AssociatedIrp.SystemBuffer;
++
++              ExtAttrLength           = PtrIoStackLocation->Parameters.Create.EaLength;
++
++              SequentialOnly      = ((RequestedOptions & FILE_SEQUENTIAL_ONLY ) ? TRUE : FALSE);
++              RandomAccess            = ((RequestedOptions & FILE_RANDOM_ACCESS ) ? TRUE : FALSE);
++              
++
++              DirectoryOnlyRequested = ((RequestedOptions & FILE_DIRECTORY_FILE) ? TRUE : FALSE);
++              FileOnlyRequested = ((RequestedOptions & FILE_NON_DIRECTORY_FILE) ? TRUE : FALSE);
++              NoBufferingSpecified = ((RequestedOptions & FILE_NO_INTERMEDIATE_BUFFERING) ? TRUE : FALSE);
++              WriteThroughRequested = ((RequestedOptions & FILE_WRITE_THROUGH) ? TRUE : FALSE);
++              DeleteOnCloseSpecified = ((RequestedOptions & FILE_DELETE_ON_CLOSE) ? TRUE : FALSE);
++              NoExtAttrKnowledge = ((RequestedOptions & FILE_NO_EA_KNOWLEDGE) ? TRUE : FALSE);
++              CreateTreeConnection = ((RequestedOptions & FILE_CREATE_TREE_CONNECTION) ? TRUE : FALSE);
++              OpenByFileId = ((RequestedOptions & FILE_OPEN_BY_FILE_ID) ? TRUE : FALSE);
++              PageFileManipulation = ((PtrIoStackLocation->Flags & SL_OPEN_PAGING_FILE) ? TRUE : FALSE);
++              OpenTargetDirectory = ((PtrIoStackLocation->Flags & SL_OPEN_TARGET_DIRECTORY) ? TRUE : FALSE);
++              IgnoreCaseWhenChecking = ((PtrIoStackLocation->Flags & SL_CASE_SENSITIVE) ? TRUE : FALSE);
++
++              // Ensure that the operation has been directed to a valid VCB ...
++              PtrVCB =        (PtrExt2VCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
++              ASSERT(PtrVCB);
++              ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
++
++              
++              if( !PtrNewFileObject->Vpb )
++              {
++                      PtrNewFileObject->Vpb = PtrVCB->PtrVPB;
++              }
++
++              //      Acquiring the VCBResource Exclusively...
++              //      This is done to synchronise with the close and cleanup routines...
++              
++              DebugTrace(DEBUG_TRACE_MISC,  "*** Going into a block to acquire VCB Exclusively [Create]", 0);
++              
++              DebugTraceState( "VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Create]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
++              ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), TRUE);
++                              
++              AcquiredVCB = TRUE;
++
++              DebugTrace(DEBUG_TRACE_MISC,   "*** VCB Acquired in Create", 0);
++              if( PtrNewFileObject )
++              {
++                      DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Create]", PtrNewFileObject);
++              }
++
++              //      Verify Volume...
++              //      if (!NT_SUCCESS(RC = Ext2VerifyVolume(PtrVCB))) 
++              //      {
++              //              try_return(RC);
++              //      }
++
++              // If the volume has been locked, fail the request
++
++              if (PtrVCB->VCBFlags & EXT2_VCB_FLAGS_VOLUME_LOCKED) 
++              {
++                      DebugTrace(DEBUG_TRACE_MISC,   "Volume locked. Failing Create", 0 );
++                      RC = STATUS_ACCESS_DENIED;
++                      try_return(RC);
++              }
++
++
++              if ((PtrNewFileObject->FileName.Length == 0) && ((PtrRelatedFileObject == NULL) ||
++                        (PtrRelatedFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB))) 
++              {
++                      //
++                      //      >>>>>>>>>>>>>   Volume Open requested. <<<<<<<<<<<<<
++                      //
++
++                      //      Performing validity checks...
++                      if ((OpenTargetDirectory) || (PtrExtAttrBuffer)) 
++                      {
++                              RC = STATUS_INVALID_PARAMETER;
++                              try_return(RC);
++                      }
++
++                      if (DirectoryOnlyRequested) 
++                      {
++                              // a volume is not a directory
++                              RC = STATUS_NOT_A_DIRECTORY;
++                              try_return(RC);
++                      }
++
++                      if ((RequestedDisposition != FILE_OPEN) && (RequestedDisposition != FILE_OPEN_IF)) 
++                      {
++                              // cannot create a new volume, I'm afraid ...
++                              RC = STATUS_ACCESS_DENIED;
++                              try_return(RC);
++                      }
++                      DebugTrace(DEBUG_TRACE_MISC,   "Volume open requested", 0 );
++                      RC = Ext2OpenVolume(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject);
++                      ReturnedInformation = PtrIrp->IoStatus.Information;
++
++                      try_return(RC);
++              }
++
++              if (OpenByFileId) 
++              {
++                      DebugTrace(DEBUG_TRACE_MISC, "Open by File Id requested", 0 );
++                      RC = STATUS_ACCESS_DENIED;
++                      try_return(RC);
++              }
++
++              // Relative path name specified...
++              if (PtrRelatedFileObject)
++              {
++
++                      if (!(PtrRelatedFCB->FCBFlags & EXT2_FCB_DIRECTORY)) 
++                      {
++                              // we must have a directory as the "related" object
++                              RC = STATUS_INVALID_PARAMETER;
++                              try_return(RC);
++                      }
++
++                      //      Performing validity checks...
++                      if ((RelatedObjectName.Length == 0) || (RelatedObjectName.Buffer[0] != L'\\')) 
++                      {
++                              RC = STATUS_INVALID_PARAMETER;
++                              try_return(RC);
++                      }
++
++                      if ((TargetObjectName.Length != 0) && (TargetObjectName.Buffer[0] == L'\\')) 
++                      {
++                              RC = STATUS_INVALID_PARAMETER;
++                              try_return(RC);
++                      }
++
++                      // Creating an absolute path-name.
++                      {
++                              AbsolutePathName.MaximumLength = TargetObjectName.Length + RelatedObjectName.Length + sizeof(WCHAR);
++                              if (!(AbsolutePathName.Buffer = Ext2AllocatePool(PagedPool, AbsolutePathName.MaximumLength ))) 
++                              {
++                                      RC = STATUS_INSUFFICIENT_RESOURCES;
++                                      try_return(RC);
++                              }
++
++                              RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength);
++
++                              RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(RelatedObjectName.Buffer), RelatedObjectName.Length);
++                              AbsolutePathName.Length = RelatedObjectName.Length;
++                              RtlAppendUnicodeToString(&AbsolutePathName, L"\\");
++                              RtlAppendUnicodeToString(&AbsolutePathName, TargetObjectName.Buffer);
++                      }
++
++              }
++              //      Absolute Path name specified...
++              else 
++              {
++                      
++
++                      // Validity Checks...
++                      if (TargetObjectName.Buffer[0] != L'\\') 
++                      {
++                              RC = STATUS_INVALID_PARAMETER;
++                              try_return(RC);
++                      }
++
++                      {
++                              AbsolutePathName.MaximumLength = TargetObjectName.Length;
++                              if (!(AbsolutePathName.Buffer = Ext2AllocatePool(PagedPool, AbsolutePathName.MaximumLength ))) {
++                                      RC = STATUS_INSUFFICIENT_RESOURCES;
++                                      try_return(RC);
++                              }
++
++                              RtlZeroMemory(AbsolutePathName.Buffer, AbsolutePathName.MaximumLength);
++
++                              RtlCopyMemory((void *)(AbsolutePathName.Buffer), (void *)(TargetObjectName.Buffer), TargetObjectName.Length);
++                              AbsolutePathName.Length = TargetObjectName.Length;
++                      }
++              }
++
++
++              //      Parsing the path...
++              if (AbsolutePathName.Length == 2) 
++              {
++                      
++                      // this is an open of the root directory, ensure that   the caller has not requested a file only
++                      if (FileOnlyRequested || (RequestedDisposition == FILE_SUPERSEDE) || (RequestedDisposition == FILE_OVERWRITE) ||
++                               (RequestedDisposition == FILE_OVERWRITE_IF)) 
++                      {
++                              RC = STATUS_FILE_IS_A_DIRECTORY;
++                              try_return(RC);
++                      }
++
++                      RC = Ext2OpenRootDirectory(PtrVCB, PtrIrpContext, PtrIrp, ShareAccess, PtrSecurityContext, PtrNewFileObject);
++                      DebugTrace(DEBUG_TRACE_MISC,   " === Root directory opened", 0 );
++                      try_return(RC);
++              }
++
++
++              {
++                      //      Used during parsing the file path...
++                      UNICODE_STRING                  RemainingName;
++                      UNICODE_STRING                  CurrentName;
++                      UNICODE_STRING                  NextRemainingName;
++                      PEXT2_INODE                             PtrNextInode = NULL;
++                      ULONG                                   CurrInodeNo = 0;
++                      PtrExt2FCB                              PtrCurrFCB = NULL;
++                      PtrExt2FCB                              PtrNextFCB = NULL;
++                      PFILE_OBJECT                    PtrCurrFileObject = NULL;
++                      UINT                                    NameBufferIndex;
++                      ULONG                                   Type = 0;
++                      LARGE_INTEGER ZeroSize;
++                      BOOLEAN Found           = FALSE;
++                      
++                      ZeroSize.QuadPart = 0;
++                      if ( PtrRelatedFileObject ) 
++                      {
++                              CurrInodeNo = PtrRelatedFCB->INodeNo;
++                              PtrCurrFCB = PtrRelatedFCB;
++                      }
++                      else 
++                      {
++                              CurrInodeNo = PtrVCB->PtrRootDirectoryFCB->INodeNo;
++                              PtrCurrFCB = PtrVCB->PtrRootDirectoryFCB;
++
++                      }
++
++                      //      Ext2ZerooutUnicodeString( &RemainingName );
++                      Ext2ZerooutUnicodeString( &CurrentName );
++                      Ext2ZerooutUnicodeString( &NextRemainingName );
++
++                      RemainingName = TargetObjectName;
++              
++                      while ( !Found && CurrInodeNo ) 
++                      {
++                              FsRtlDissectName ( RemainingName, &CurrentName, &NextRemainingName );
++
++                              RemainingName = NextRemainingName;
++                              //      CurrInodeNo is the parent inode for the entry I am searching for
++                              //      PtrCurrFCB      is the parent's FCB
++                              //      Current Name is its name...
++
++
++                              PtrNextFCB = Ext2LocateChildFCBInCore ( PtrVCB, &CurrentName, CurrInodeNo );
++                              
++                              if( PtrNextFCB )
++                              {
++                                      CurrInodeNo = PtrNextFCB->INodeNo;
++      
++                                      if( NextRemainingName.Length == 0 )
++                                      {
++                                              //
++                                              //      Done Parsing...
++                                              //      Found the file...
++                                              //
++                                              Found = TRUE;
++                                              
++                                              if( OpenTargetDirectory )
++                                              {
++                                                      int i;
++                                                      //
++                                                      //      This is for a rename/move operation...
++                                                      //
++                                                      ReturnedInformation = FILE_EXISTS;
++
++                                                      //      Now replace the file name field with that of the 
++                                                      //      Target file name...
++                                                      Ext2CopyUnicodeString( 
++                                                              &RenameLinkTargetFileName,
++                                                              &CurrentName );
++                                                      /*
++                                                      
++                                                      for( i = 0; i < (CurrentName.Length/2); i++ )
++                                                      {
++                                                              PtrNewFileObject->FileName.Buffer[i] = CurrentName.Buffer[i];
++                                                      }
++                                                      PtrNewFileObject->FileName.Length = CurrentName.Length;
++                                                      */
++                                                      //      Now open the Parent Directory...
++                                                      PtrNextFCB = PtrCurrFCB;
++                                                      CurrInodeNo = PtrNextFCB->INodeNo;
++                                              }
++
++                                              //      
++                                              //      Relating the FCB to the New File Object
++                                              //
++                                              PtrNewFileObject->Vpb = PtrVCB->PtrVPB;
++                                              PtrNewFileObject->PrivateCacheMap = NULL;
++                                              PtrNewFileObject->FsContext = (void *)( &(PtrNextFCB->NTRequiredFCB.CommonFCBHeader) );
++                                              PtrNewFileObject->SectionObjectPointer = &(PtrNextFCB->NTRequiredFCB.SectionObject) ;
++                                              break;
++                                      }
++
++                                      else if( !Ext2IsFlagOn( PtrNextFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
++                                      {
++                                              //      Invalid path...
++                                              //      Can have only a directory in the middle of the path...
++                                              //
++                                              RC = STATUS_OBJECT_PATH_NOT_FOUND;
++                                              try_return( RC );
++                                      }
++                              }
++                              else    //      searching on the disk...
++                              {
++                                      CurrInodeNo = Ext2LocateFileInDisk( PtrVCB, &CurrentName, PtrCurrFCB, &Type );
++                                      if( !CurrInodeNo )
++                                      {
++                                              //
++                                              //      Not found...
++                                              //      Quit searching...
++                                              //      
++                                      
++                                              if( ( NextRemainingName.Length == 0 ) &&
++                                                      ( RequestedDisposition == FILE_CREATE ) ||
++                                                      ( RequestedDisposition == FILE_OPEN_IF) ||
++                                                      ( RequestedDisposition == FILE_OVERWRITE_IF) ) 
++
++                                              {
++                                                      //
++                                                      //      Just the last component was not found...
++                                                      //      A create was requested...
++                                                      //
++                                                      if( DirectoryOnlyRequested )
++                                                      {
++                                                              Type = EXT2_FT_DIR;
++                                                      }
++                                                      else
++                                                      {
++                                                              Type = EXT2_FT_REG_FILE;
++                                                      }
++
++                                                      CurrInodeNo = Ext2CreateFile( PtrIrpContext, PtrVCB, 
++                                                              &CurrentName, PtrCurrFCB, Type );
++                                                      
++                                                      if(     !CurrInodeNo )
++                                                      {
++                                                              RC = STATUS_OBJECT_PATH_NOT_FOUND;
++                                                              try_return( RC );
++                                                      }
++                                                      // Set the allocation size for the object is specified
++                                                      //IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess));
++                                                      //      RC = STATUS_SUCCESS;
++                                                      ReturnedInformation = FILE_CREATED;
++                                                      
++                                                      //      Should also create a CCB structure...
++                                                      //      Doing that a little fathre down... ;)
++
++                                              }
++                                              else if( NextRemainingName.Length == 0 && OpenTargetDirectory )
++                                              { 
++                                                      int i;
++                                                      //
++                                                      //      This is for a rename/move operation...
++                                                      //      Just the last component was not found...
++                                                      //
++                                                      ReturnedInformation = FILE_DOES_NOT_EXIST;
++
++                                                      //      Now replace the file name field with that of the 
++                                                      //      Target file name...
++                                                      Ext2CopyUnicodeString( 
++                                                              &RenameLinkTargetFileName,
++                                                              &CurrentName );
++                                                      /*
++                                                      for( i = 0; i < (CurrentName.Length/2); i++ )
++                                                      {
++                                                              PtrNewFileObject->FileName.Buffer[i] = CurrentName.Buffer[i];
++                                                      }
++                                                      PtrNewFileObject->FileName.Length = CurrentName.Length;
++                                                      */
++
++                                                      //      Now open the Parent Directory...
++                                                      PtrNextFCB = PtrCurrFCB;
++                                                      CurrInodeNo = PtrNextFCB->INodeNo;
++                                                      //      Initialize the FsContext
++                                                      PtrNewFileObject->FsContext = &PtrNextFCB->NTRequiredFCB.CommonFCBHeader;
++                                                      //      Initialize the section object pointer...
++                                                      PtrNewFileObject->SectionObjectPointer = &(PtrNextFCB->NTRequiredFCB.SectionObject);
++                                                      PtrNewFileObject->Vpb = PtrVCB->PtrVPB;
++                                                      PtrNewFileObject->PrivateCacheMap = NULL;                                                       
++
++                                                      break;
++                                              }
++                                              else
++                                              {
++                                                      RC = STATUS_OBJECT_PATH_NOT_FOUND;
++                                                      try_return( RC );
++                                              }
++                                      }
++
++                                      if( NextRemainingName.Length )
++                                      {
++                                              //      Should be a directory...
++                                              if( Type != EXT2_FT_DIR )
++                                              {
++                                                      //      Invalid path...
++                                                      //      Can have only a directory in the middle of the path...
++                                                      //
++                                                      RC = STATUS_OBJECT_PATH_NOT_FOUND;
++                                                      try_return( RC );
++                                              }
++
++                                              PtrCurrFileObject = NULL;
++                                      }
++                                      else
++                                      {
++                                              //
++                                              //      Done Parsing...
++                                              //      Found the file...
++                                              //
++                                              Found = TRUE;
++                                              
++                                              //
++                                              //      Was I supposed to create a new file?
++                                              //
++                                              if (RequestedDisposition == FILE_CREATE &&
++                                                      ReturnedInformation != FILE_CREATED ) 
++                                              {
++                                                      ReturnedInformation = FILE_EXISTS;
++                                                      RC = STATUS_OBJECT_NAME_COLLISION;
++                                                      try_return(RC);
++                                              }
++                                              
++                                              //      Is this the type of file I was looking for?
++                                              //      Do some checking here...
++
++                                              if( Type != EXT2_FT_DIR && Type != EXT2_FT_REG_FILE )
++                                              {
++                                                      //      Deny access!
++                                                      //      Cannot open a special file...
++                                                      RC = STATUS_ACCESS_DENIED;
++                                                      try_return( RC );
++
++                                              }
++                                              if( DirectoryOnlyRequested && Type != EXT2_FT_DIR )
++                                              {
++                                                      RC = STATUS_NOT_A_DIRECTORY;
++                                                      try_return( RC );
++                                              }
++                                              if( FileOnlyRequested && Type == EXT2_FT_DIR )
++                                              {
++                                                      RC = STATUS_FILE_IS_A_DIRECTORY;
++                                                      try_return(RC);
++                                              }
++
++                                              PtrCurrFileObject = PtrNewFileObject;
++                                              //      Things seem to be ok enough!
++                                              //      Proceeing with the Open/Create...
++                                              
++                                      }
++
++                              
++                                      //
++                                      //      Create an FCB and initialise it...
++                                      //
++                                      {
++                                              PtrExt2ObjectName               PtrObjectName;
++                                              
++                                              //      Initialising the object name...
++                                              PtrObjectName = Ext2AllocateObjectName();
++                                              Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &CurrentName ); 
++                                              //      RtlInitUnicodeString( &PtrObjectName->ObjectName, CurrentName.Buffer );
++
++                                              if( !NT_SUCCESS( Ext2CreateNewFCB( 
++                                                      &PtrNextFCB,                            //      the new FCB
++                                                      ZeroSize,                                       //      AllocationSize,
++                                                      ZeroSize,                                       //      EndOfFile,
++                                      PtrCurrFileObject,                      //      The File Object
++                                                      PtrVCB,
++                                                      PtrObjectName  )  )  )
++                                              {
++                                                      RC = STATUS_INSUFFICIENT_RESOURCES;
++                                                      try_return(RC);
++                                              }
++
++                                              if( Type == EXT2_FT_DIR )
++                                                      PtrNextFCB->FCBFlags |= EXT2_FCB_DIRECTORY;
++                                              else if( Type != EXT2_FT_REG_FILE )
++                                                      PtrNextFCB->FCBFlags |= EXT2_FCB_SPECIAL_FILE;
++
++                                              PtrNextFCB->INodeNo = CurrInodeNo ;
++                                              PtrNextFCB->ParentINodeNo = PtrCurrFCB->INodeNo;
++
++                                              if( PtrCurrFileObject == NULL && CurrInodeNo != EXT2_ROOT_INO )
++                                              {
++                                                      //      This is an FCB created to cache the reads done while parsing
++                                                      //      Put this FCB on the ClosableFCBList 
++                                                      if( !PtrNextFCB->ClosableFCBs.OnClosableFCBList )
++                                                      {
++                                                                      InsertTailList( &PtrVCB->ClosableFCBs.ClosableFCBListHead,
++                                                                              &PtrNextFCB->ClosableFCBs.ClosableFCBList );
++                                                                      PtrVCB->ClosableFCBs.Count++;
++                                                                      PtrNextFCB->ClosableFCBs.OnClosableFCBList = TRUE;
++                                                      }
++                                              }
++                                      }
++                              }
++      
++                              //
++                              //      Still not done parsing...
++                              //      miles to go before I open... ;)
++                              //
++                              PtrCurrFCB = PtrNextFCB;
++                      }
++
++                      PtrNewFCB = PtrNextFCB;
++              }
++              
++
++              //      If I get this far...
++              //      it means, I have located the file...
++              //      I even have an FCB to represent it!!!
++
++              if ( NT_SUCCESS (RC) ) 
++              {
++
++                      if ((PtrNewFCB->FCBFlags & EXT2_FCB_DIRECTORY) && ((RequestedDisposition == FILE_SUPERSEDE) ||
++                                (RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF ))) 
++                      {
++                              RC = STATUS_FILE_IS_A_DIRECTORY;
++                              try_return(RC);
++                      }
++              
++                      
++                      // Check share access and fail if the share conflicts with an existing
++                      // open.
++                      
++                      if (PtrNewFCB->OpenHandleCount > 0) 
++                      {
++                              // The FCB is currently in use by some thread.
++                              // We must check whether the requested access/share access
++                              // conflicts with the existing open operations.
++
++                              if (!NT_SUCCESS(RC = IoCheckShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject,
++                                                                                              &(PtrNewFCB->FCBShareAccess), TRUE))) 
++                              {
++                                      // Ext2CloseCCB(PtrNewCCB);
++                                      try_return(RC);
++                              }
++                      } 
++                      else 
++                      {
++                              IoSetShareAccess(DesiredAccess, ShareAccess, PtrNewFileObject, &(PtrNewFCB->FCBShareAccess));
++                      }
++
++                      //
++                      //      Allocating a new CCB Structure...
++                      //      
++                      Ext2CreateNewCCB( &PtrNewCCB, PtrNewFCB, PtrNewFileObject);
++                      PtrNewFileObject->FsContext2 = (void *) PtrNewCCB;
++                      Ext2CopyUnicodeString( &(PtrNewCCB->AbsolutePathName), &AbsolutePathName );
++
++                      if( ReturnedInformation == -1 )
++                      {
++                              //      
++                              //      ReturnedInformation has not been set so far...
++                              //
++                              ReturnedInformation = FILE_OPENED;
++                      }
++
++                      // If a supersede or overwrite was requested, do so now ...
++                      if (RequestedDisposition == FILE_SUPERSEDE) 
++                      {
++                              // Attempt the operation here ...
++                              if( Ext2SupersedeFile( PtrNewFCB, PtrIrpContext) )
++                              {
++                                      ReturnedInformation = FILE_SUPERSEDED;
++                              }
++                      }
++                      
++                      else if ((RequestedDisposition == FILE_OVERWRITE) || (RequestedDisposition == FILE_OVERWRITE_IF))
++                      {
++                              // Attempt the overwrite operation...
++                              if( Ext2OverwriteFile( PtrNewFCB, PtrIrpContext) )
++                              {
++                                      ReturnedInformation = FILE_OVERWRITTEN;
++                              }
++                      }
++                      if( AllocationSize )
++                      {
++                              if( ReturnedInformation == FILE_CREATED ||
++                                      ReturnedInformation == FILE_SUPERSEDED )
++                              {
++                                      ULONG CurrentSize;
++                                      ULONG LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++                                      
++                                      for( CurrentSize = 0; CurrentSize < AllocationSize; CurrentSize += LogicalBlockSize )
++                                      {
++                                              Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrNewFCB, PtrNewFileObject, FALSE );
++                                      }
++                              }
++                      }
++
++                      if( ReturnedInformation == FILE_CREATED )
++                      {
++                              //      Allocate some data blocks if 
++                              //              1. initial file size has been specified...
++                              //              2. if the file is a Directory...
++                              //                      In case of (2) make entries for '.' and '..'
++                              //      Zero out the Blocks...
++
++                              UNICODE_STRING          Name;
++
++                              if( DirectoryOnlyRequested )
++                              {
++
++                                      Ext2CopyCharToUnicodeString( &Name, ".", 1 );
++                                      Ext2MakeNewDirectoryEntry( PtrIrpContext, PtrNewFCB, PtrNewFileObject, &Name, EXT2_FT_DIR, PtrNewFCB->INodeNo);
++
++                                      Name.Buffer[1] = '.';
++                                      Name.Buffer[2] = '\0';
++                                      Name.Length += 2;
++                                      Ext2MakeNewDirectoryEntry( PtrIrpContext, PtrNewFCB, PtrNewFileObject, &Name, EXT2_FT_DIR, PtrNewFCB->ParentINodeNo );
++                                      Ext2DeallocateUnicodeString( &Name );
++                              }
++                      }
++                      if( OpenTargetDirectory )
++                      {
++                              //
++                              //      Save the taget file name in the CCB...
++                              //
++                              Ext2CopyUnicodeString( 
++                                      &PtrNewCCB->RenameLinkTargetFileName,
++                                      &RenameLinkTargetFileName );
++                              Ext2DeallocateUnicodeString( &RenameLinkTargetFileName );
++                      }
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally 
++      {
++              if (AcquiredVCB) 
++              {
++                      ASSERT(PtrVCB);
++                      Ext2ReleaseResource(&(PtrVCB->VCBResource));
++
++                      AcquiredVCB = FALSE;
++                      DebugTrace(DEBUG_TRACE_MISC,   "*** VCB released [Create]", 0);
++
++                      if( PtrNewFileObject )
++                      {
++                              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Create]", PtrNewFileObject);
++                      }
++              }
++
++              if (AbsolutePathName.Buffer != NULL) 
++              {
++                      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Create]", AbsolutePathName.Buffer );
++                      ExFreePool(AbsolutePathName.Buffer);
++              }
++
++              // Complete the request unless we are here as part of unwinding
++              //      when an exception condition was encountered, OR
++              //      if the request has been deferred (i.e. posted for later handling)
++              if (RC != STATUS_PENDING) 
++              {
++                      // If we acquired any FCB resources, release them now ...
++
++                      // If any intermediate (directory) open operations were performed,
++                      //      implement the corresponding close (do *not* however close
++                      //      the target you have opened on behalf of the caller ...).
++
++                      if (NT_SUCCESS(RC)) 
++                      {
++                              // Update the file object such that:
++                              //      (a) the FsContext field points to the NTRequiredFCB field
++                              //               in the FCB
++                              //      (b) the FsContext2 field points to the CCB created as a
++                              //               result of the open operation
++
++                              // If write-through was requested, then mark the file object
++                              //      appropriately
++                              if (WriteThroughRequested) 
++                              {
++                                      PtrNewFileObject->Flags |= FO_WRITE_THROUGH;
++                              }
++                              DebugTrace( DEBUG_TRACE_SPECIAL,   " === Create/Open successful", 0 );
++                      } 
++                      else 
++                      {
++                              DebugTrace( DEBUG_TRACE_SPECIAL,   " === Create/Open failed", 0 );
++                              // Perform failure related post-processing now
++                      }
++
++                      // As long as this unwinding is not being performed as a result of
++                      //      an exception condition, complete the IRP ...
++                      if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) 
++                      {
++                              PtrIrp->IoStatus.Status = RC;
++                              PtrIrp->IoStatus.Information = ReturnedInformation;
++                      
++                              // Free up the Irp Context
++                              Ext2ReleaseIrpContext(PtrIrpContext);
++                              
++                              // complete the IRP
++                              IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
++                      }
++              }
++      }
++      return(RC);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2OpenVolume()
++*
++* Description:
++*     Open a logical volume for the caller.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: STATUS_SUCCESS/Error
++*
++*************************************************************************/
++NTSTATUS Ext2OpenVolume(
++PtrExt2VCB                            PtrVCB,                                 // volume to be opened
++PtrExt2IrpContext             PtrIrpContext,                  // IRP context
++PIRP                                          PtrIrp,                                 // original/user IRP
++unsigned short                        ShareAccess,                    // share access
++PIO_SECURITY_CONTEXT  PtrSecurityContext,     // caller's context (incl access)
++PFILE_OBJECT                  PtrNewFileObject)               // I/O Mgr. created file object
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2CCB                      PtrCCB = NULL;
++
++      try {
++              // check for exclusive open requests (using share modes supplied)
++              //      and determine whether it is even possible to open the volume
++              //      with the specified share modes (e.g. if caller does not
++              //      wish to share read or share write ...)
++      
++              //      Use IoCheckShareAccess() and IoSetShareAccess() here ...        
++              //      They are defined in the DDK.
++
++              //      You might also wish to check the caller's security context
++              //      to see whether you wish to allow the volume open or not.
++              //      Use the SeAccessCheck() routine described in the DDK for        this purpose.
++      
++              // create a new CCB structure
++              if (!(PtrCCB = Ext2AllocateCCB())) 
++              {
++                      RC = STATUS_INSUFFICIENT_RESOURCES;
++                      try_return(RC);
++              }
++
++              // initialize the CCB
++              PtrCCB->PtrFCB = (PtrExt2FCB)(PtrVCB);
++              InsertTailList(&(PtrVCB->VolumeOpenListHead), &(PtrCCB->NextCCB));
++
++              // initialize the CCB to point to the file object
++              PtrCCB->PtrFileObject = PtrNewFileObject;
++
++              Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_VOLUME_OPEN);
++
++              // initialize the file object appropriately
++              PtrNewFileObject->FsContext = (void *)( &(PtrVCB->CommonVCBHeader) );
++              PtrNewFileObject->FsContext2 = (void *)(PtrCCB);
++
++              // increment the number of outstanding open operations on this
++              //      logical volume (i.e. volume cannot be dismounted)
++
++              //      You might be concerned about 32 bit wrap-around though I would
++              //      argue that it is unlikely ... :-)
++              (PtrVCB->VCBOpenCount)++;
++      
++              // now set the IoStatus Information value correctly in the IRP
++              //      (caller will set the status field)
++              PtrIrp->IoStatus.Information = FILE_OPENED;
++      
++              try_exit:       NOTHING;
++      } 
++      finally 
++      {
++              NOTHING;
++      }
++
++      return(RC);
++}
++
++/*************************************************************************
++*
++* Function: Ext2InitializeFCB()
++*
++* Description:
++*     Initialize a new FCB structure and also the sent-in file object
++*     (if supplied)
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: None
++*
++*************************************************************************
++void Ext2InitializeFCB(
++PtrExt2FCB                            PtrNewFCB,              // FCB structure to be initialized
++PtrExt2VCB                            PtrVCB,                 // logical volume (VCB) pointer
++PtrExt2ObjectName             PtrObjectName,  // name of the object
++uint32                                        Flags,                  // is this a file/directory, etc.
++PFILE_OBJECT                  PtrFileObject)  // optional file object to be initialized
++{
++      // Initialize the disk dependent portion as you see fit
++
++      // Initialize the two ERESOURCE objects
++      ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.MainResource));
++      ExInitializeResourceLite(&(PtrNewFCB->NTRequiredFCB.PagingIoResource));
++
++      PtrNewFCB->FCBFlags |= EXT2_INITIALIZED_MAIN_RESOURCE | EXT2_INITIALIZED_PAGING_IO_RESOURCE | Flags;
++
++      PtrNewFCB->PtrVCB = PtrVCB;
++
++      // caller MUST ensure that VCB has been acquired exclusively
++      InsertTailList(&(PtrVCB->FCBListHead), &(PtrNewFCB->NextFCB));
++
++      // initialize the various list heads
++      InitializeListHead(&(PtrNewFCB->CCBListHead));
++
++//    PtrNewFCB->ReferenceCount = 1;
++//    PtrNewFCB->OpenHandleCount = 1;
++
++      if( PtrObjectName )
++      {
++              PtrNewFCB->FCBName = PtrObjectName;
++      }
++
++      if ( PtrFileObject )
++      {
++              PtrFileObject->FsContext = (void *)(&(PtrNewFCB->NTRequiredFCB));
++      }
++
++      return;
++}
++*/
++
++/*************************************************************************
++*
++* Function: Ext2OpenRootDirectory()
++*
++* Description:
++*     Open the root directory for a volume
++*     
++*
++* Expected Interrupt Level (for execution) :
++*
++*  ???
++*
++* Return Value: None
++*
++*************************************************************************/
++NTSTATUS Ext2OpenRootDirectory(
++      PtrExt2VCB                              PtrVCB,                                 // volume 
++      PtrExt2IrpContext               PtrIrpContext,                  // IRP context
++      PIRP                                    PtrIrp,                                 // original/user IRP
++      unsigned short                  ShareAccess,                    // share access
++      PIO_SECURITY_CONTEXT    PtrSecurityContext,             // caller's context (incl access)
++      PFILE_OBJECT                    PtrNewFileObject                // I/O Mgr. created file object
++      )
++{
++      //      Declerations...
++      PtrExt2CCB PtrCCB;
++      
++      ASSERT( PtrVCB );
++      ASSERT( PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
++      ASSERT( PtrVCB->PtrRootDirectoryFCB );
++      AssertFCB( PtrVCB->PtrRootDirectoryFCB );
++              
++      PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO;
++      
++      //      Create a new CCB...
++      Ext2CreateNewCCB( &PtrCCB, PtrVCB->PtrRootDirectoryFCB, PtrNewFileObject);
++      PtrNewFileObject->FsContext = (void *) &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader);
++      PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY;
++      PtrNewFileObject->FsContext2 = (void *) PtrCCB;
++      PtrNewFileObject->SectionObjectPointer = &PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject;
++      PtrNewFileObject->Vpb = PtrVCB->PtrVPB;
++
++      Ext2CopyUnicodeString( &(PtrCCB->AbsolutePathName), &PtrVCB->PtrRootDirectoryFCB->FCBName->ObjectName );
++
++
++      return STATUS_SUCCESS;
++}
++
++
++
++PtrExt2FCB Ext2LocateChildFCBInCore(
++      PtrExt2VCB                              PtrVCB, 
++      PUNICODE_STRING                 PtrName, 
++      ULONG                                   ParentInodeNo )
++{
++
++      PtrExt2FCB PtrFCB = NULL;
++      ULONG InodeNo = 0;
++      PLIST_ENTRY     PtrEntry;
++
++      if( IsListEmpty( &(PtrVCB->FCBListHead) ) )
++      {
++              return NULL;    //      Failure;
++      }
++
++      for( PtrEntry = PtrVCB->FCBListHead.Flink; 
++                      PtrEntry != &PtrVCB->FCBListHead; 
++                      PtrEntry = PtrEntry->Flink )
++      {
++              PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, NextFCB );
++              ASSERT( PtrFCB );
++              if( PtrFCB->ParentINodeNo == ParentInodeNo )
++              {
++                      if( RtlCompareUnicodeString( &PtrFCB->FCBName->ObjectName, PtrName, TRUE ) == 0 )
++                              return PtrFCB;
++              }
++      }
++
++      return NULL;
++}
++
++PtrExt2FCB    Ext2LocateFCBInCore(
++      PtrExt2VCB                              PtrVCB, 
++      ULONG                                   InodeNo )
++{
++      PtrExt2FCB PtrFCB = NULL;
++      PLIST_ENTRY     PtrEntry;
++
++      if( IsListEmpty( &(PtrVCB->FCBListHead) ) )
++      {
++              return NULL;    //      Failure;
++      }
++
++      for( PtrEntry = PtrVCB->FCBListHead.Flink; 
++                      PtrEntry != &PtrVCB->FCBListHead; 
++                      PtrEntry = PtrEntry->Flink )
++      {
++              PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, NextFCB );
++              ASSERT( PtrFCB );
++              if( PtrFCB->INodeNo == InodeNo )
++              {
++                      return PtrFCB;
++              }
++      }
++
++      return NULL;
++}
++
++
++ULONG Ext2LocateFileInDisk (
++      PtrExt2VCB                              PtrVCB,
++      PUNICODE_STRING                 PtrCurrentName, 
++      PtrExt2FCB                              PtrParentFCB,
++      ULONG                                   *Type )
++{
++
++      PtrExt2FCB                      PtrNewFCB = NULL;
++      PFILE_OBJECT            PtrFileObject = NULL;
++      ULONG                           InodeNo = 0;
++      
++      *Type = EXT2_FT_UNKNOWN;
++
++      //      1. 
++      //      Initialize the Blocks in the FCB...
++      //
++      Ext2InitializeFCBInodeInfo( PtrParentFCB );
++
++      
++      //      2.
++      //      Is there a file object I can use for caching??
++      //      If not create one...
++      //
++      if( !PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject )
++      {
++              //
++              //      No Directory File Object?
++              //      No problem, will create one...
++              //
++
++              //      Acquire the MainResource first though...
++                      
++                      PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject = IoCreateStreamFileObject(NULL, PtrVCB->TargetDeviceObject );
++                      PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject;
++                      
++                      if( !PtrFileObject )
++                      {
++                              Ext2BreakPoint();
++                              return 0;
++                      }
++                      PtrFileObject->ReadAccess = TRUE;
++                      PtrFileObject->WriteAccess = TRUE;
++
++                      //      Associate the file stream with the Volume parameter block...
++                      PtrFileObject->Vpb = PtrVCB->PtrVPB;
++
++                      //      No caching as yet...
++                      PtrFileObject->PrivateCacheMap = NULL;
++
++                      //      this establishes the FCB - File Object connection...
++                      PtrFileObject->FsContext = (void *)( & (PtrParentFCB->NTRequiredFCB.CommonFCBHeader) );
++
++                      //      Initialize the section object pointer...
++                      PtrFileObject->SectionObjectPointer = &(PtrParentFCB->NTRequiredFCB.SectionObject);
++      }
++      else
++      {
++              //      
++              //      I do have a file object... 
++              //      I am using it now!
++              //
++              PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject;
++      }
++
++      //      3.
++      //      Got hold of a file object? Good ;)
++      //      Now initiating Caching, pinned access to be precise ...
++      //
++      if (PtrFileObject->PrivateCacheMap == NULL) 
++      {
++                      CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
++                              TRUE,           // We utilize pin access for directories
++                              &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
++                              PtrParentFCB );         // The context used in callbacks
++      }
++
++      //      4.
++      //      Getting down to the real business now... ;)
++      //      Read in the directory contents and do a search 
++      //      a sequential search to be precise...
++      //      Wish Mm'm Renuga were reading this
++      //      Would feel proud...     ;)
++      //
++      {
++              LARGE_INTEGER   StartBufferOffset;
++              ULONG                   PinBufferLength;
++              ULONG                   BufferIndex;
++              PBCB                    PtrBCB = NULL;
++              BYTE *                  PtrPinnedBlockBuffer = NULL;
++              PEXT2_DIR_ENTRY PtrDirEntry = NULL;
++              BOOLEAN                 Found;
++              int                             i;
++
++
++              StartBufferOffset.QuadPart = 0;
++
++              //
++              //      Read in the whole damn directory
++              //      **Bad programming**
++              //      Will do for now.
++              //
++              PinBufferLength = PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
++              if (!CcMapData( PtrFileObject,
++                  &StartBufferOffset,
++                  PinBufferLength,
++                  TRUE,
++                  &PtrBCB,
++                  (PVOID*)&PtrPinnedBlockBuffer ) )
++              {
++
++                      
++              }
++              //
++              //      Walking through now...
++              //
++              
++              for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len )
++              {
++                      PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ];
++                      if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 || PtrDirEntry->inode == 0)
++                      {
++                              //      Invalid entry...
++                              //  Ignore...
++                              continue;
++                      }
++                      //
++                      //      Comparing ( case sensitive )
++                      //      Directory entry is not NULL terminated...
++                      //      nor is the CurrentName...
++                      //
++                      if( PtrDirEntry->name_len != (PtrCurrentName->Length / 2) )
++                              continue;
++                      
++                      for( i = 0, Found = TRUE ; i < PtrDirEntry->name_len ; i++ )
++                      {
++                              if( PtrDirEntry->name[ i ] != PtrCurrentName->Buffer[ i ] )
++                              {
++                                      Found = FALSE;
++                                      break;
++
++                              }
++                      }
++                      
++              }
++              if( Found )
++              {
++                      InodeNo = PtrDirEntry->inode;
++
++                      if( PtrDirEntry->file_type == EXT2_FT_UNKNOWN )
++                      {
++
++                              //      Old Fashioned Directory entries...
++                              //      Will have to read in the Inode to determine the File Type...
++                              EXT2_INODE      Inode;
++                              //      PtrInode = Ext2AllocatePool( NonPagedPool, sizeof( EXT2_INODE )  );
++                              Ext2ReadInode( PtrVCB, InodeNo, &Inode );       
++
++                              if( Ext2IsModeRegularFile( Inode.i_mode ) )
++                              {
++                                      *Type = EXT2_FT_REG_FILE;
++                              }
++                              else if ( Ext2IsModeDirectory( Inode.i_mode) )
++                              {
++                                      //      Directory...
++                                      *Type = EXT2_FT_DIR;
++                              }
++                              else if( Ext2IsModeSymbolicLink(Inode.i_mode) )
++                              {
++                                      *Type = EXT2_FT_SYMLINK;
++                              }
++                              else if( Ext2IsModePipe(Inode.i_mode) )
++                              {
++                                      *Type = EXT2_FT_FIFO;
++                              }
++                              else if( Ext2IsModeCharacterDevice(Inode.i_mode) )
++                              {
++                                      *Type = EXT2_FT_CHRDEV;
++                              }
++                              else if( Ext2IsModeBlockDevice(Inode.i_mode) )
++                              {
++                                      *Type = EXT2_FT_BLKDEV;
++                              }
++                              else if( Ext2IsModeSocket(Inode.i_mode) )
++                              {
++                                      *Type = EXT2_FT_SOCK;
++                              }
++                              else
++                              {
++                                      *Type = EXT2_FT_UNKNOWN;
++                              }
++                              
++                              //DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Create]", PtrInode );
++                              //ExFreePool( PtrInode );
++                      }
++                      else
++                      {
++                              *Type = PtrDirEntry->file_type;
++                      }
++              }
++
++              CcUnpinData( PtrBCB );
++              PtrBCB = NULL;
++
++              return InodeNo;
++      }
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2CreateFile()
++*
++* Description:
++*     Creates a new file on the disk
++*     
++* Expected Interrupt Level (for execution) :
++*     IRQL_PASSIVE_LEVEL
++*
++* Restrictions:
++*     Expects the VCB to be acquired Exclusively before being invoked
++*
++* Return Value: None
++*
++*************************************************************************/
++ULONG Ext2CreateFile( 
++      PtrExt2IrpContext               PtrIrpContext,
++      PtrExt2VCB                              PtrVCB,
++      PUNICODE_STRING                 PtrName, 
++      PtrExt2FCB                              PtrParentFCB,
++      ULONG                                   Type)
++{
++      EXT2_INODE      Inode, ParentInode;
++
++      ULONG           NewInodeNo = 0;
++      BOOLEAN         FCBAcquired = FALSE;
++
++      ULONG           LogicalBlockSize = 0;
++
++      try
++      {
++              
++
++              //      0. Verify if the creation is possible,,,
++              if( Type != EXT2_FT_DIR && Type != EXT2_FT_REG_FILE )
++              {
++                      //
++                      //      Can create only a directory or a regular file...
++                      //
++                      return 0;
++              }
++              
++              //      1. Allocate an i-node...
++              
++              NewInodeNo = Ext2AllocInode( PtrIrpContext, PtrVCB, PtrParentFCB->INodeNo );
++              
++              //      NewInodeNo = 12;
++
++              if( !NewInodeNo )
++              {
++                      return 0;
++              }
++              
++              //      2. Acquire the Parent FCB Exclusively...
++              if( !ExAcquireResourceExclusiveLite(&( PtrParentFCB->NTRequiredFCB.MainResource ), TRUE) )
++              {
++                      Ext2DeallocInode( PtrIrpContext, PtrVCB, NewInodeNo );
++                      try_return( NewInodeNo = 0);
++              }
++              FCBAcquired = TRUE;
++
++              //      3. Make an entry in the parent Directory...             
++              ASSERT( PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject );
++              
++              Ext2MakeNewDirectoryEntry(
++                      PtrIrpContext,
++                      PtrParentFCB, 
++                      PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject, 
++                      PtrName, Type, NewInodeNo );
++      
++              
++              //      4. Initialize an inode entry and  write it to disk...
++              LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++
++              {
++                      //      To be deleted
++                      Ext2ReadInode( PtrVCB, NewInodeNo, &Inode );
++              }
++
++              RtlZeroMemory( &Inode, sizeof( EXT2_INODE ) );
++              if( Type == EXT2_FT_DIR )
++              {
++                      Inode.i_mode = 0x41ff;
++
++                      //      In addition to the usual link, 
++                      //      there will be an additional link in the directory itself - the '.' entry
++                      Inode.i_links_count = 2;
++
++                      //      Incrementing the link count for the parent as well...
++                      Ext2ReadInode( PtrVCB, PtrParentFCB->INodeNo, &ParentInode );
++                      ParentInode.i_links_count++;
++                      Ext2WriteInode( PtrIrpContext, PtrVCB, PtrParentFCB->INodeNo, &ParentInode );
++
++              }
++              else
++              {
++                      Inode.i_mode = 0x81ff;
++                      Inode.i_links_count = 1;
++              }
++
++
++              {
++                      //
++                      //      Setting the time fields in the inode...
++                      //
++                      ULONG Time;
++                      Time = Ext2GetCurrentTime();
++                      Inode.i_ctime = Time;
++                      Inode.i_atime = Time;
++                      Inode.i_mtime = Time;
++                      Inode.i_dtime = 0;                      //      Deleted time;
++              }
++
++              Ext2WriteInode( PtrIrpContext, PtrVCB, NewInodeNo, &Inode );
++
++              try_exit:       NOTHING;
++      }
++      finally 
++      {
++              if( FCBAcquired )
++              {
++                      Ext2ReleaseResource( &(PtrParentFCB->NTRequiredFCB.MainResource) );
++              }
++      }
++
++      return NewInodeNo ;
++}
++
++/*************************************************************************
++*
++* Function: Ext2CreateFile()
++*
++* Description:
++*     Overwrites an existing file on the disk
++*     
++* Expected Interrupt Level (for execution) :
++*     IRQL_PASSIVE_LEVEL
++*
++* Restrictions:
++*     Expects the VCB to be acquired Exclusively before being invoked
++*
++* Return Value: None
++*
++*************************************************************************/
++BOOLEAN Ext2OverwriteFile(
++      PtrExt2FCB                      PtrFCB,
++      PtrExt2IrpContext       PtrIrpContext)
++{
++      EXT2_INODE                      Inode;
++      PtrExt2VCB                      PtrVCB = PtrFCB->PtrVCB;
++      ULONG                           i;
++      ULONG   Time;
++      Time = Ext2GetCurrentTime();
++
++      Ext2InitializeFCBInodeInfo( PtrFCB );
++      //      1.
++      //      Update the inode...
++      if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
++      {
++              return FALSE;
++      }
++
++      Inode.i_size = 0;
++      Inode.i_blocks = 0;
++      Inode.i_atime = Time;
++      Inode.i_mtime = Time;
++      Inode.i_dtime = 0;
++
++      for( i = 0; i < EXT2_N_BLOCKS; i++ )
++      {
++              Inode.i_block[ i ] = 0;
++      }
++
++      if( !NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
++      {
++              return FALSE;
++      }
++
++      //      2.
++      //      Release all the data blocks...
++      if( !Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext) )
++      {
++              return FALSE;
++      }
++      
++      Ext2ClearFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED );
++      Ext2InitializeFCBInodeInfo( PtrFCB );
++      
++      return TRUE;
++}
++
++/*************************************************************************
++*
++* Function: Ext2SupersedeFile()
++*
++* Description:
++*     Supersedes an existing file on the disk
++*     
++* Expected Interrupt Level (for execution) :
++*     IRQL_PASSIVE_LEVEL
++*
++* Restrictions:
++*     Expects the VCB to be acquired Exclusively before being invoked
++*
++* Return Value: None
++*
++*************************************************************************/
++BOOLEAN Ext2SupersedeFile(
++      PtrExt2FCB                      PtrFCB,
++      PtrExt2IrpContext       PtrIrpContext)
++{
++      EXT2_INODE                      Inode;
++      PtrExt2VCB                      PtrVCB = PtrFCB->PtrVCB;
++      ULONG                           i;
++
++      Ext2InitializeFCBInodeInfo( PtrFCB );
++
++      //      1.
++      //      Initialize the inode...
++      RtlZeroMemory( &Inode, sizeof( EXT2_INODE ) );
++
++      //      Setting the file mode...
++      //      This operation is allowed only for a regular file...
++      Inode.i_mode = 0x81ff;
++
++      //      Maintaining the old link count...
++      Inode.i_links_count = PtrFCB->LinkCount;
++
++      //      Setting the time fields in the inode...
++      {
++              ULONG Time;
++              Time = Ext2GetCurrentTime();
++              Inode.i_ctime = Time;
++              Inode.i_atime = Time;
++              Inode.i_mtime = Time;
++              Inode.i_dtime = 0;                      //      Deleted time;
++      }
++
++      if( !NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
++      {
++              return FALSE;
++      }
++
++      //      2.
++      //      Release all the data blocks...
++      if( !Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext) )
++      {
++              return FALSE;
++      }
++      
++      Ext2ClearFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED );
++      Ext2InitializeFCBInodeInfo( PtrFCB );
++      
++      return TRUE;
++}
index 0000000,0000000..0238986
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,210 @@@
++/*************************************************************************
++*
++* File: devcntrl.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Contains code to handle the "Device IOCTL" dispatch entry point.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#include                      "ext2fsd.h"
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_DEVICE_CONTROL
++#define                       DEBUG_LEVEL                                             DEBUG_TRACE_DEVCTRL
++
++
++#if(_WIN32_WINNT < 0x0400)
++#define IOCTL_REDIR_QUERY_PATH   CTL_CODE(FILE_DEVICE_NETWORK_FILE_SYSTEM, 99, METHOD_NEITHER, FILE_ANY_ACCESS)
++
++typedef struct _QUERY_PATH_REQUEST 
++{
++    ULONG PathNameLength;
++    PIO_SECURITY_CONTEXT SecurityContext;
++    WCHAR FilePathName[1];
++} QUERY_PATH_REQUEST, *PQUERY_PATH_REQUEST;
++
++typedef struct _QUERY_PATH_RESPONSE 
++{
++    ULONG LengthAccepted;
++} QUERY_PATH_RESPONSE, *PQUERY_PATH_RESPONSE;
++#endif
++
++
++/*************************************************************************
++*
++* Function: Ext2DeviceControl()
++*
++* Description:
++*     The I/O Manager will invoke this routine to handle a Device IOCTL
++*     request
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
++*     to be deferred to a worker thread context)
++*
++* Return Value: STATUS_SUCCESS/Error
++*
++*************************************************************************/
++NTSTATUS Ext2DeviceControl(
++PDEVICE_OBJECT                DeviceObject,           // the logical volume device object
++PIRP                                  Irp)                                    // I/O Request Packet
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++   PtrExt2IrpContext  PtrIrpContext = NULL;
++      BOOLEAN                         AreWeTopLevel = FALSE;
++
++      //      Ext2BreakPoint();
++      
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "Device Control IRP Received...", 0);
++
++      FsRtlEnterFileSystem();
++      ASSERT(DeviceObject);
++      ASSERT(Irp);
++
++      // set the top level context
++      AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
++
++      try {
++
++              // get an IRP context structure and issue the request
++              PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
++              ASSERT(PtrIrpContext);
++
++              RC = Ext2CommonDeviceControl(PtrIrpContext, Irp);
++
++      } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) {
++
++              RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
++
++              Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++      }
++
++      if (AreWeTopLevel) {
++              IoSetTopLevelIrp(NULL);
++      }
++
++      FsRtlExitFileSystem();
++
++      return(RC);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2CommonDeviceControl()
++*
++* Description:
++*     The actual work is performed here. This routine may be invoked in one'
++*     of the two possible contexts:
++*     (a) in the context of a system worker thread
++*     (b) in the context of the original caller
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: STATUS_SUCCESS/Error
++*
++*************************************************************************/
++NTSTATUS      Ext2CommonDeviceControl(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                                  PtrIrp)
++{
++      NTSTATUS                                        RC = STATUS_SUCCESS;
++      PIO_STACK_LOCATION      PtrIoStackLocation = NULL;
++      PIO_STACK_LOCATION      PtrNextIoStackLocation = NULL;
++      PFILE_OBJECT                    PtrFileObject = NULL;
++      PtrExt2FCB                              PtrFCB = NULL;
++      PtrExt2CCB                              PtrCCB = NULL;
++      PtrExt2VCB                              PtrVCB = NULL;
++      ULONG                                           IoControlCode = 0;
++      void                                            *BufferPointer = NULL;
++
++      try 
++      {
++              // First, get a pointer to the current I/O stack location
++              PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
++              ASSERT(PtrIoStackLocation);
++
++              PtrFileObject = PtrIoStackLocation->FileObject;
++              ASSERT(PtrFileObject);
++
++              PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2);
++              ASSERT(PtrCCB);
++              PtrFCB = PtrCCB->PtrFCB;
++              ASSERT(PtrFCB);
++              
++
++              if( PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB )
++              {
++                      PtrVCB = (PtrExt2VCB)(PtrFCB);
++              }
++              else
++              {
++                      AssertFCB( PtrFCB );
++                      ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB);
++                      PtrVCB = PtrFCB->PtrVCB;
++              }
++
++              // Get the IoControlCode value
++              IoControlCode = PtrIoStackLocation->Parameters.DeviceIoControl.IoControlCode;
++
++              // You may wish to allow only   volume open operations.
++
++              // Invoke the lower level driver in the chain.
++              PtrNextIoStackLocation = IoGetNextIrpStackLocation(PtrIrp);
++              *PtrNextIoStackLocation = *PtrIoStackLocation;
++              // Set a completion routine.
++              IoSetCompletionRoutine(PtrIrp, Ext2DevIoctlCompletion, NULL, TRUE, TRUE, TRUE);
++              // Send the request.
++              RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp);
++
++              try_exit:       NOTHING;
++
++      } 
++      finally 
++      {
++              // Release the IRP context
++              if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) 
++              {
++                      // Free up the Irp Context
++                      Ext2ReleaseIrpContext(PtrIrpContext);
++              }
++      }
++
++      return(RC);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2DevIoctlCompletion()
++*
++* Description:
++*     Completion routine.
++*     
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: STATUS_SUCCESS
++*
++*************************************************************************/
++NTSTATUS Ext2DevIoctlCompletion(
++PDEVICE_OBJECT                        PtrDeviceObject,
++PIRP                                          PtrIrp,
++void                                          *Context)
++{
++      if (PtrIrp->PendingReturned) {
++              IoMarkIrpPending(PtrIrp);
++      }
++
++      return(STATUS_SUCCESS);
++}
index 0000000,759f2c2..759f2c2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,937 +1,937 @@@
+ /*************************************************************************
+ *
+ * File: dircntrl.c
+ *
+ * Module: Ext2 File System Driver (Kernel mode execution only)
+ *
+ * Description:
+ *     Contains code to handle the "directory control" dispatch entry point.
+ *
+ * Author: Manoj Paul Joseph
+ *
+ *
+ *************************************************************************/
+ #include                      "ext2fsd.h"
+ // define the file specific bug-check id
+ #define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_DIR_CONTROL
+ #define                       DEBUG_LEVEL                                             (DEBUG_TRACE_DIRCTRL)
+ /*************************************************************************
+ *
+ * Function: Ext2DirControl()
+ *
+ * Description:
+ *     The I/O Manager will invoke this routine to handle a directory control
+ *     request
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
+ *     to be deferred to a worker thread context)
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS Ext2DirControl(
+ PDEVICE_OBJECT                DeviceObject,           // the logical volume device object
+ PIRP                                  Irp)                                    // I/O Request Packet
+ {
+       NTSTATUS                        RC = STATUS_SUCCESS;
+     PtrExt2IrpContext PtrIrpContext = NULL;
+       BOOLEAN                         AreWeTopLevel = FALSE;
+       DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "DIR Control IRP received...", 0);
+       
+       FsRtlEnterFileSystem();
+       ASSERT(DeviceObject);
+       ASSERT(Irp);
+       // set the top level context
+       AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
+       try 
+       {
+               // get an IRP context structure and issue the request
+               PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
+               ASSERT(PtrIrpContext);
+               RC = Ext2CommonDirControl(PtrIrpContext, Irp);
+       }
+       except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
+       {
+               RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
+               Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
+       }
+       if (AreWeTopLevel) {
+               IoSetTopLevelIrp(NULL);
+       }
+       FsRtlExitFileSystem();
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2CommonDirControl()
+ *
+ * Description:
+ *     The actual work is performed here. This routine may be invoked in one'
+ *     of the two possible contexts:
+ *     (a) in the context of a system worker thread
+ *     (b) in the context of the original caller
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS      Ext2CommonDirControl(
+ PtrExt2IrpContext                     PtrIrpContext,
+ PIRP                                                  PtrIrp)
+ {
+       NTSTATUS                                        RC = STATUS_SUCCESS;
+       PIO_STACK_LOCATION      PtrIoStackLocation = NULL;
+       PFILE_OBJECT                    PtrFileObject = NULL;
+       PtrExt2FCB                              PtrFCB = NULL;
+       PtrExt2CCB                              PtrCCB = NULL;
+       PtrExt2VCB                              PtrVCB = NULL;
+       // First, get a pointer to the current I/O stack location
+       PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
+       ASSERT(PtrIoStackLocation);
+       PtrFileObject = PtrIoStackLocation->FileObject;
+       ASSERT(PtrFileObject);
+       // Get the FCB and CCB pointers
+       PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2);
+       ASSERT(PtrCCB);
+       PtrFCB = PtrCCB->PtrFCB;
+       AssertFCB( PtrFCB );
+       
+       // Get some of the parameters supplied to us
+       switch (PtrIoStackLocation->MinorFunction) {
+       case IRP_MN_QUERY_DIRECTORY:
+ #ifdef _GNU_NTIFS_
+               RC = Ext2QueryDirectory(PtrIrpContext, PtrIrp, (PEXTENDED_IO_STACK_LOCATION)PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB);
+ #else
+               RC = Ext2QueryDirectory(PtrIrpContext, PtrIrp, PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB);
+ #endif
+               break;
+       case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
+               {
+                       RC = STATUS_NOT_IMPLEMENTED;
+                       PtrIrp->IoStatus.Status = RC;
+                       PtrIrp->IoStatus.Information = 0;
+                       IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
+               }
+               //      RC = Ext2NotifyChangeDirectory(PtrIrpContext, PtrIrp, PtrIoStackLocation, PtrFileObject, PtrFCB, PtrCCB);
+               break;
+       default:
+               // This should not happen.
+               RC = STATUS_INVALID_DEVICE_REQUEST;
+               PtrIrp->IoStatus.Status = RC;
+               PtrIrp->IoStatus.Information = 0;
+               // Free up the Irp Context
+               Ext2ReleaseIrpContext(PtrIrpContext);
+               // complete the IRP
+               IoCompleteRequest(PtrIrp, IO_NO_INCREMENT);
+               break;
+       }
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2QueryDirectory()
+ *
+ * Description:
+ *     Query directory request.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS      Ext2QueryDirectory(
+ PtrExt2IrpContext                     PtrIrpContext,
+ PIRP                                          PtrIrp,
+ #ifdef _GNU_NTIFS_
+ PEXTENDED_IO_STACK_LOCATION                   PtrIoStackLocation,
+ #else
+ PIO_STACK_LOCATION                    PtrIoStackLocation,
+ #endif
+ PFILE_OBJECT                          PtrFileObject,
+ PtrExt2FCB                                    PtrFCB,
+ PtrExt2CCB                                    PtrCCB)
+ {
+       NTSTATUS                                RC = STATUS_SUCCESS;
+       BOOLEAN                                 CompleteRequest = TRUE;
+       BOOLEAN                                 PostRequest = FALSE;
+       PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
+       BOOLEAN                                 CanWait = FALSE;
+       PtrExt2VCB                              PtrVCB = NULL;
+       BOOLEAN                                 AcquiredFCB = FALSE;
+       unsigned long                   BufferLength = 0;
+       unsigned long                   BufferIndex     = 0;
+       unsigned long                   FileIndex = 0;
+       PUNICODE_STRING                 PtrSearchPattern = NULL;
+       FILE_INFORMATION_CLASS  FileInformationClass;
+       BOOLEAN                                 RestartScan = FALSE;
+       BOOLEAN                                 ReturnSingleEntry = FALSE;
+       BOOLEAN                                 IndexSpecified = FALSE;
+       unsigned char                   *Buffer = NULL;
+       BOOLEAN                                 FirstTimeQuery = FALSE;
+       unsigned long                   StartingIndexForSearch = 0;
+       unsigned long                   BytesReturned = 0;
+       BOOLEAN                                 BufferUsedup = FALSE;
+       BOOLEAN                                 SearchWithWildCards = FALSE;
+       
+       PFILE_BOTH_DIR_INFORMATION              BothDirInformation = NULL;
+       PFILE_FULL_DIR_INFORMATION              FullDirInformation = NULL;
+       PFILE_DIRECTORY_INFORMATION             DirectoryInformation = NULL;
+       PFILE_NAMES_INFORMATION                 NamesInformation = NULL;
+       
+       PEXT2_DIR_ENTRY         PtrDirEntry = NULL;
+       PEXT2_INODE                     PtrInode        = NULL;
+       
+       unsigned long           LogicalBlockSize;
+       
+       unsigned long           ThisBlock;
+       
+       //      The starting Physical Block No...
+       //LARGE_INTEGER StartPhysicalBlock;
+       LARGE_INTEGER StartBufferOffset ;
+       ULONG PinBufferLength;
+               
+       //      Buffer Control Block
+       PBCB                            PtrBCB = NULL;
+       BYTE *                          PtrPinnedBlockBuffer = NULL;
+       unsigned int i,j;
+       
+       DebugTrace(DEBUG_TRACE_MISC,   " === Querying Directory %S", PtrFCB->FCBName->ObjectName.Buffer );
+       try 
+       {
+               // Validate the sent-in FCB
+               if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) 
+               {
+                       // We will only allow notify requests on directories.
+                       RC = STATUS_INVALID_PARAMETER;
+               }
+               PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
+               CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
+               PtrVCB = PtrFCB->PtrVCB;
+               //
+               //      Asynchronous IO requested
+               //      Posting request...
+               //
+               /*
+                * This is incorrect because posted IRP_MJ_DIRECTORY_CONTROL
+                * requests aren't handled in the worker thread yet. I tried
+                * adding handling of them to the worked routine, but there
+                * were problems with accessing the PtrIoStackLocation->
+                * Parameters.QueryDirectory.FileName variable.
+                * -- Filip Navara, 18/08/2004
+                */
+ #if 0
+               if (!CanWait) 
+               {
+                       PostRequest = TRUE;
+                       try_return(RC = STATUS_PENDING);
+               }
+ #endif
+               // Obtain the callers parameters
+               BufferLength = PtrIoStackLocation->Parameters.QueryDirectory.Length;
+               PtrSearchPattern = ( PUNICODE_STRING    ) PtrIoStackLocation->Parameters.QueryDirectory.FileName;
+               FileInformationClass = PtrIoStackLocation->Parameters.QueryDirectory.FileInformationClass;
+               FileIndex = PtrIoStackLocation->Parameters.QueryDirectory.FileIndex;
+               // Some additional arguments that affect the FSD behavior
+               RestartScan       = (PtrIoStackLocation->Flags & SL_RESTART_SCAN);
+               ReturnSingleEntry = (PtrIoStackLocation->Flags & SL_RETURN_SINGLE_ENTRY);
+               IndexSpecified    = (PtrIoStackLocation->Flags & SL_INDEX_SPECIFIED);
+               //
+               // Acquiring exclusive access to the FCB.
+               // This is not mandatory
+               //
+               DebugTrace(DEBUG_TRACE_MISC,   "*** Going into a block to acquire FCB Exclusively[DirCtrl]", 0);
+               DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+               ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE);
+               
+               DebugTrace(DEBUG_TRACE_MISC,   "*** FCB acquired [DirCtrl]", 0);
+               AcquiredFCB = TRUE;
+               // We must determine the buffer pointer to be used. Since this
+               // routine could either be invoked directly in the context of the
+               // calling thread, or in the context of a worker thread, here is
+               // a general way of determining what we should use.
+               Buffer = Ext2GetCallersBuffer ( PtrIrp );
+               // The method of determining where to look from and what to look for is
+               // unfortunately extremely confusing. However, here is a methodology you
+               // you can broadly adopt:
+               // (a) You have to maintain a search buffer per CCB structure.
+               // (b) This search buffer is initialized the very first time
+               //               a query directory operation is performed using the file object.
+               // (For the sample FSD, the search buffer is stored in the
+               //       DirectorySearchPattern field)
+               // However, the caller still has the option of "overriding" this stored
+               // search pattern by supplying a new one in a query directory operation.
+               //
+               if( PtrCCB->DirectorySearchPattern.Length )
+               {
+                       if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 )
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,  "&&&&&&&&&  PtrCCB->DirectorySearchPattern not NULL terminated!", 0);
+                       }
+                       DebugTrace(DEBUG_TRACE_MISC,   " === Old Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer );
+               }
+               if (PtrSearchPattern != NULL) 
+               {
+                       // User has supplied a search pattern
+                       // Now validate that the search pattern is legitimate
+                       if ( PtrCCB->DirectorySearchPattern.Length == 0 ) 
+                       {
+                               // This must be the very first query request.
+                               FirstTimeQuery = TRUE;
+                       }
+                       else
+                       {
+                               // We should ignore the search pattern in the CCB and instead,
+                               // use the user-supplied pattern for this particular query
+                               // directory request.
+                               Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern );
+                       }
+                       // Now, allocate enough memory to contain the caller
+                       // supplied search pattern and fill in the DirectorySearchPattern
+                       // field in the CCB
+                       Ext2CopyUnicodeString( &PtrCCB->DirectorySearchPattern, PtrSearchPattern );
+                       /*
+                       PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof( PtrSearchPattern ) );
+                       ASSERT(PtrCCB->DirectorySearchPattern);
+                       RtlCopyMemory( PtrCCB->DirectorySearchPattern, PtrSearchPattern, sizeof( PtrSearchPattern ) );
+                       */
+               }
+               else if ( PtrCCB->DirectorySearchPattern.Length == 0 ) 
+               {
+                       // This MUST be the first directory query operation (else the
+                       // DirectorySearchPattern field would never be empty. Also, the caller
+                       // has neglected to provide a pattern so we MUST invent one.
+                       // Use "*" (following NT conventions) as your search pattern
+                       // and store it in the PtrCCB->DirectorySearchPattern field.
+                       
+                       /*
+                       PtrCCB->DirectorySearchPattern = Ext2AllocatePool(PagedPool, sizeof(L"*") );
+                       ASSERT(PtrCCB->DirectorySearchPattern);
+                       RtlCopyMemory( PtrCCB->DirectorySearchPattern, L"*", 4 );*/
+                       Ext2CopyWideCharToUnicodeString( &PtrCCB->DirectorySearchPattern, L"*" );
+                       
+                       FirstTimeQuery = TRUE;
+               } 
+               else 
+               {
+                       // The caller has not supplied any search pattern...
+                       // Using previously supplied pattern
+                       PtrSearchPattern = &PtrCCB->DirectorySearchPattern;
+               }
+               if( PtrCCB->DirectorySearchPattern.Buffer[PtrCCB->DirectorySearchPattern.Length/2] != 0 )
+               {
+                       DebugTrace(DEBUG_TRACE_MISC,  "&&&&&&&&&  PtrCCB->DirectorySearchPattern not NULL terminated!", 0 );
+               }
+               DebugTrace(DEBUG_TRACE_MISC,   " === Search pattern %S", PtrCCB->DirectorySearchPattern.Buffer );
+               SearchWithWildCards = FsRtlDoesNameContainWildCards( PtrSearchPattern );
+               // There is one other piece of information that your FSD must store
+               // in the CCB structure for query directory support. This is the index
+               // value (i.e. the offset in your on-disk directory structure) from
+               // which you should start searching.
+               // However, the flags supplied with the IRP can make us override this
+               // as well.
+               if (FileIndex) 
+               {
+                       // Caller has told us wherefrom to begin.
+                       // You may need to round this to an appropriate directory entry
+                       // entry alignment value.
+                       StartingIndexForSearch = FileIndex;
+               } 
+               else if (RestartScan) 
+               {
+                       StartingIndexForSearch = 0;
+               } 
+               else 
+               {
+                       // Get the starting offset from the CCB.
+                       StartingIndexForSearch = PtrCCB->CurrentByteOffset.LowPart;
+               }
+               //      Read in the file inode if it hasn't already been read...
+               Ext2InitializeFCBInodeInfo( PtrFCB );
+               
+               if (PtrFileObject->PrivateCacheMap == NULL) 
+               {
+                       CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)),
+                               TRUE,           // We will utilize pin access for directories
+                               &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
+                               PtrCCB);                // The context used in callbacks
+               }
+               //
+               //      Read in the next Data Block of this directory
+               //
+               LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
+               StartBufferOffset.QuadPart = ( StartingIndexForSearch / LogicalBlockSize );
+               StartBufferOffset.QuadPart *= LogicalBlockSize; //      This should be the StartBufferOffset alaigned to LBlock boundary...
+               
+               PinBufferLength = PtrReqdFCB->CommonFCBHeader.FileSize.LowPart - StartBufferOffset.LowPart;
+               if ( !CcMapData( PtrFileObject,
+                   &StartBufferOffset,
+                   PinBufferLength,
+                   TRUE,
+                   &PtrBCB,
+                   (PVOID*)&PtrPinnedBlockBuffer ) )
+               {
+                       //      Read Failure
+                       DebugTrace(DEBUG_TRACE_MISC,   "Cache read failiure while reading in volume meta data", 0);
+                       try_return( STATUS_ACCESS_DENIED );
+               }
+               else
+               {
+                       DebugTrace(DEBUG_TRACE_MISC,   "Cache hit while reading in volume meta data", 0);
+               }
+               
+               PtrInode = Ext2AllocatePool( PagedPool, sizeof( EXT2_INODE )  );
+               //
+               //      Walking through the directory entries...
+               for( BufferUsedup = FALSE, BufferIndex = 0; !BufferUsedup && StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; )
+               {
+                       PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ StartingIndexForSearch - StartBufferOffset.LowPart ];
+                       
+                       StartingIndexForSearch += PtrDirEntry->rec_len;
+                       PtrCCB->CurrentByteOffset.LowPart = StartingIndexForSearch;
+                       if( PtrDirEntry->inode == 0 )
+                       {
+                               continue;
+                       }
+                       if( PtrDirEntry->name_len == 0 || PtrDirEntry->rec_len == 0 )
+                       {
+                               //
+                               //      This should not happen
+                               //      Hqw can this be so!!!
+                               //
+                               Ext2BreakPoint();
+                               if( BothDirInformation )
+                               {
+                                       BothDirInformation->NextEntryOffset = 0;
+                               }
+                               if( !BytesReturned )
+                               {
+                                       if( FirstTimeQuery )
+                                               RC = STATUS_NO_SUCH_FILE;
+                                       else
+                                               RC = STATUS_NO_MORE_FILES;
+                               }
+                               break;
+                       }
+                       //      Does this entry match the search criterian?
+                       //      Checking
+                       //
+                       {
+                               UNICODE_STRING  FileName;
+                               LONG    Matched = 0;
+                               // Constructing a counted Unicode string out of PtrDirEntry
+                               Ext2CopyCharToUnicodeString( &FileName, PtrDirEntry->name, PtrDirEntry->name_len );
+                               if ( SearchWithWildCards )
+                               {
+                                       Matched = FsRtlIsNameInExpression ( PtrSearchPattern, &FileName, FALSE, NULL );
+                               }
+                               else
+                               {
+                                       Matched = ! RtlCompareUnicodeString( PtrSearchPattern, &FileName, FALSE );
+                               }
+                       
+                               Ext2DeallocateUnicodeString( &FileName );
+                               if( !Matched )
+                               {
+                                       continue;
+                               }
+                       }
+                       switch( FileInformationClass )
+                       {
+                       case FileBothDirectoryInformation:
+                               
+                               DebugTrace(DEBUG_TRACE_DIRINFO,   " === FileBothDirectoryInformation", 0 );
+                               ThisBlock = sizeof( FILE_BOTH_DIR_INFORMATION );
+                               ThisBlock += PtrDirEntry->name_len*2;
+                               ThisBlock = Ext2QuadAlign( ThisBlock  );
+                               if( ( BufferIndex + ThisBlock ) > BufferLength )
+                               {
+                                       //
+                                       //      Next entry won't fit into the buffer...
+                                       //      will have to return... 
+                                       //      :(
+                                       //
+                                       if( BothDirInformation )
+                                               BothDirInformation->NextEntryOffset = 0;
+                                       if( !BytesReturned )
+                                               RC = STATUS_NO_MORE_FILES;
+                                       BufferUsedup = TRUE;
+                                       break;
+                               }
+                                                       
+                               Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode );
+                               if( !PtrInode )
+                               {
+                                       try_return( RC = STATUS_UNSUCCESSFUL );
+                               }
+                               BothDirInformation = ( PFILE_BOTH_DIR_INFORMATION ) ( Buffer + ( BufferIndex ) );
+                               BothDirInformation->EaSize                                      = 0;
+                               BothDirInformation->AllocationSize.QuadPart     = PtrInode->i_blocks * 512;
+                               BothDirInformation->EndOfFile.QuadPart          = PtrInode->i_size;
+                               BothDirInformation->ChangeTime.QuadPart         = 0;
+                               BothDirInformation->CreationTime.QuadPart       = ( __int64 ) PtrInode->i_ctime * 10000000;
+                               BothDirInformation->CreationTime.QuadPart       += Ext2GlobalData.TimeDiff.QuadPart;
+                               BothDirInformation->LastAccessTime.QuadPart     = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 );
+                               BothDirInformation->LastWriteTime.QuadPart      = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 );
+                               //      Getting the file type...
+                               BothDirInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
+                               if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) )
+                               {  
+                                       //      Not a reqular file...
+                                       if( Ext2IsModeDirectory( PtrInode->i_mode) )
+                                       {
+                                               //      Directory...
+                                               BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+                                       }
+                                       else
+                                       {
+                                               //      Special File...
+                                               //      Treated with respect... ;)
+                                               //
+                                               BothDirInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
+                                               //      FILE_ATTRIBUTE_DEVICE
+                                       }
+                                       if ( Ext2IsModeHidden( PtrInode->i_mode ) )
+                                       {
+                                               BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+                                       }
+                                       
+                                       if ( Ext2IsModeReadOnly( PtrInode->i_mode ) )
+                                       {
+                                               BothDirInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY;
+                                       }
+                               }
+                               BothDirInformation->FileIndex = StartingIndexForSearch;
+                               BothDirInformation->FileNameLength = PtrDirEntry->name_len*2 + 2;
+                               BothDirInformation->ShortNameLength = 0; 
+                               BothDirInformation->ShortName[0] = 0;
+                               
+                               //      Copying out the name as WCHAR null terminated strings
+                               for( j = 0; j< PtrDirEntry->name_len ; j ++ )
+                               {
+                                       //      BothDirInformation->ShortName[ j ] = PtrDirEntry->name[j];
+                                       BothDirInformation->FileName[ j ] = PtrDirEntry->name[j];
+                                       //      if( j < 11 )
+                                       //              BothDirInformation->ShortName[j] = PtrDirEntry->name[j];;
+                               }
+                               /*
+                               if( j < 11 )
+                               {
+                                       BothDirInformation->ShortNameLength = j * 2 + 2;
+                                       BothDirInformation->ShortName[ j ] = 0;
+                               }
+                               else
+                               {
+                                       BothDirInformation->ShortNameLength = 24;
+                                       BothDirInformation->ShortName[ 11 ] = 0;
+                               }*/
+                               BothDirInformation->FileName[ j ]       = 0;
+                               BytesReturned += ThisBlock;
+                               BufferIndex += ThisBlock;
+                               if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ))
+                                       BothDirInformation->NextEntryOffset = ThisBlock;
+                               else
+                                       BothDirInformation->NextEntryOffset = 0;
+                               break;
+                       case FileDirectoryInformation:
+                               //      DirectoryInformation
+                               DebugTrace(DEBUG_TRACE_DIRINFO,   " === FileDirectoryInformation", 0 );
+                               ThisBlock = sizeof( FILE_DIRECTORY_INFORMATION );
+                               ThisBlock += PtrDirEntry->name_len*2;
+                               ThisBlock = Ext2QuadAlign( ThisBlock  );
+                               if( ( BufferIndex + ThisBlock ) > BufferLength )
+                               {
+                                       //
+                                       //      Next entry won't fit into the buffer...
+                                       //      will have to return... 
+                                       //      :(
+                                       //
+                                       if( DirectoryInformation )
+                                               DirectoryInformation->NextEntryOffset = 0;
+                                       if( !BytesReturned )
+                                               RC = STATUS_NO_MORE_FILES;
+                                       BufferUsedup = TRUE;
+                                       break;
+                               }
+                                                       
+                               Ext2ReadInode( PtrVCB, PtrDirEntry->inode, PtrInode );
+                               if( !PtrInode )
+                               {
+                                       try_return( RC = STATUS_UNSUCCESSFUL );
+                               }
+                               DirectoryInformation = ( PFILE_DIRECTORY_INFORMATION ) ( Buffer + ( BufferIndex ) );
+                               DirectoryInformation->AllocationSize.QuadPart   = PtrInode->i_blocks * 512;
+                               DirectoryInformation->EndOfFile.QuadPart                = PtrInode->i_size;
+                               DirectoryInformation->ChangeTime.QuadPart               = 0;
+                               DirectoryInformation->CreationTime.QuadPart     = ( __int64 ) PtrInode->i_ctime * 10000000;
+                               DirectoryInformation->CreationTime.QuadPart     += Ext2GlobalData.TimeDiff.QuadPart;
+                               DirectoryInformation->LastAccessTime.QuadPart   = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) PtrInode->i_atime * 10000000 );
+                               DirectoryInformation->LastWriteTime.QuadPart    = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 )PtrInode->i_mtime * 10000000 );
+                               //      Getting the file type...
+                               DirectoryInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
+                               if( ! Ext2IsModeRegularFile( PtrInode->i_mode ) )
+                               {  
+                                       //      Not a reqular file...
+                                       if( Ext2IsModeDirectory( PtrInode->i_mode) )
+                                       {
+                                               //      Directory...
+                                               DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+                                       }
+                                       else
+                                       {
+                                               //      Special File...
+                                               //      Treated with respect... ;)
+                                               //
+                                               DirectoryInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY);
+                                               //      FILE_ATTRIBUTE_DEVICE
+                                       }
+                                       if ( Ext2IsModeHidden( PtrInode->i_mode ) )
+                                       {
+                                               DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+                                       }
+                                       
+                                       if ( Ext2IsModeReadOnly( PtrInode->i_mode ) )
+                                       {
+                                               DirectoryInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY;
+                                       }
+                               }
+                               DirectoryInformation->FileIndex = StartingIndexForSearch;
+                               DirectoryInformation->FileNameLength = PtrDirEntry->name_len*2 + 2;
+                               
+                               //      Copying out the name as WCHAR null terminated strings
+                               for( j = 0; j< PtrDirEntry->name_len ; j ++ )
+                               {
+                                       DirectoryInformation->FileName[ j ] = PtrDirEntry->name[j];
+                               }
+                               DirectoryInformation->FileName[ j ]     = 0;
+                               BytesReturned += ThisBlock;
+                               BufferIndex += ThisBlock;
+                               if( !ReturnSingleEntry && ( StartingIndexForSearch < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ))
+                                       DirectoryInformation->NextEntryOffset = ThisBlock;
+                               else
+                                       DirectoryInformation->NextEntryOffset = 0;
+                               break;
+                       case FileFullDirectoryInformation:
+                               //      FullDirInformation->
+                               DebugTrace(DEBUG_TRACE_DIRINFO,   " === FileFullDirectoryInformation - Not handled", 0 );
+                               try_return( RC );
+                       case FileNamesInformation:
+                               //      NamesInformation->
+                               DebugTrace(DEBUG_TRACE_DIRINFO,   " === FileNamesInformation - Not handled", 0 );
+                               try_return( RC );
+                       default:
+                               DebugTrace(DEBUG_TRACE_DIRINFO,   " === Invalid Dir Info class - Not handled", 0 );
+                               try_return( RC = STATUS_INVALID_INFO_CLASS );
+                       }
+                       if( ReturnSingleEntry )
+                       {
+                               break;
+                       }
+               }//     end of for...
+               if( !BytesReturned && StartingIndexForSearch >= ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart) )
+               {
+                       Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern );
+                       PtrCCB->CurrentByteOffset.QuadPart = 0;
+                       if( FirstTimeQuery )
+                               RC = STATUS_NO_SUCH_FILE;
+                       else
+                               RC = STATUS_NO_MORE_FILES;
+                       try_return( RC );
+               }
+               else if( BytesReturned )
+               {
+                       BothDirInformation->NextEntryOffset = 0;
+               }
+               try_exit:       NOTHING;
+       }
+       finally 
+       {
+               if( PtrInode )
+               {
+                       DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [DirCtrl]", PtrInode );
+                       ExFreePool( PtrInode );
+               }
+               if( PtrBCB )
+               {
+                       CcUnpinData( PtrBCB );
+                       PtrBCB = NULL;
+               }
+               
+               if (PostRequest) 
+               {
+                       if (AcquiredFCB) 
+                       {
+                               Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
+                               DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Released in [DirCtrl]", 0);
+                               DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", 
+                                       PtrReqdFCB->MainResource.ActiveCount, 
+                                       PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
+                                       PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+                       }
+                       // Map the users buffer and then post the request.
+                       RC = Ext2LockCallersBuffer(PtrIrp, TRUE, BufferLength);
+                       ASSERT(NT_SUCCESS(RC));
+                       RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
+               }
+               else if (!(PtrIrpContext->IrpContextFlags &
+                                                       EXT2_IRP_CONTEXT_EXCEPTION)) 
+               {
+                       if (AcquiredFCB) 
+                       {
+                               Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
+                               DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Released [DirCtrl]", 0);
+                               DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", 
+                                       PtrReqdFCB->MainResource.ActiveCount, 
+                                       PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
+                                       PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+                       }
+                       // Complete the request.
+                       PtrIrp->IoStatus.Status = RC;
+                       PtrIrp->IoStatus.Information = BytesReturned;
+                       // Free up the Irp Context
+                       Ext2ReleaseIrpContext(PtrIrpContext);
+                       // complete the IRP
+                       IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
+               }
+               
+               //      Flush the saved BCBs...
+               //      Ext2FlushSavedBCBs ( PtrIrpContext );
+       }
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2NotifyChangeDirectory()
+ *
+ * Description:
+ *     Handle the notify request.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS      Ext2NotifyChangeDirectory(
+ PtrExt2IrpContext                     PtrIrpContext,
+ PIRP                                                  PtrIrp,
+ #ifdef _GNU_NTIFS_
+ PEXTENDED_IO_STACK_LOCATION           PtrIoStackLocation,
+ #else
+ PIO_STACK_LOCATION            PtrIoStackLocation,
+ #endif
+ PFILE_OBJECT                          PtrFileObject,
+ PtrExt2FCB                                    PtrFCB,
+ PtrExt2CCB                                    PtrCCB)
+ {
+       NTSTATUS                                        RC = STATUS_SUCCESS;
+       BOOLEAN                                 CompleteRequest = FALSE;
+       BOOLEAN                                 PostRequest = FALSE;
+       PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
+       BOOLEAN                                 CanWait = FALSE;
+       ULONG                                           CompletionFilter = 0;
+       BOOLEAN                                 WatchTree = FALSE;
+       PtrExt2VCB                              PtrVCB = NULL;
+       BOOLEAN                                 AcquiredFCB = FALSE;
+       try {
+               // Validate the sent-in FCB
+               if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || !(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) {
+                       // We will only allow notify requests on directories.
+                       RC = STATUS_INVALID_PARAMETER;
+                       CompleteRequest = TRUE;
+               }
+               PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
+               CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
+           PtrVCB = PtrFCB->PtrVCB;
+               // Acquire the FCB resource shared
+               DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire FCB Shared[DirCtrl]", 0);
+               DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+               if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) 
+               {
+                       DebugTrace(DEBUG_TRACE_MISC,   "*** FCB Acquisition FAILED [DirCtrl]", 0);
+                       PostRequest = TRUE;
+                       try_return(RC = STATUS_PENDING);
+               }
+               AcquiredFCB = TRUE;
+               DebugTrace(DEBUG_TRACE_MISC,   "*** FCB acquired [DirCtrl]", 0);
+               // Obtain some parameters sent by the caller
+               CompletionFilter = PtrIoStackLocation->Parameters.NotifyDirectory.CompletionFilter;
+               WatchTree = (PtrIoStackLocation->Flags & SL_WATCH_TREE ? TRUE : FALSE);
+               // If you wish to capture the subject context, you can do so as
+               // follows:
+               // {
+               //              PSECURITY_SUBJECT_CONTEXT SubjectContext;
+               //      SubjectContext = Ext2AllocatePool(PagedPool,
+               //                                                                      sizeof(SECURITY_SUBJECT_CONTEXT) );
+               //              SeCaptureSubjectContext(SubjectContext);
+               //      }
+               FsRtlNotifyFullChangeDirectory((PNOTIFY_SYNC)&(PtrVCB->NotifyIRPMutex), &(PtrVCB->NextNotifyIRP), (void *)PtrCCB,
+                                                       (PSTRING)(PtrFCB->FCBName->ObjectName.Buffer), WatchTree, FALSE, CompletionFilter, PtrIrp,
+                                                       NULL,           // Ext2TraverseAccessCheck(...) ?
+                                                       NULL);  // SubjectContext ?
+               RC = STATUS_PENDING;
+               try_exit:       NOTHING;
+       } 
+       finally 
+       {
+               if (PostRequest) 
+               {
+                       // Perform appropriate post related processing here
+                       if (AcquiredFCB) 
+                       {
+                               Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
+                               DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Released in DirCtrl", 0);
+                               DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", 
+                                       PtrReqdFCB->MainResource.ActiveCount, 
+                                       PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
+                                       PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+                               AcquiredFCB = FALSE;
+                       }
+                       RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
+               } 
+               else if (CompleteRequest) 
+               {
+                       PtrIrp->IoStatus.Status = RC;
+                       PtrIrp->IoStatus.Information = 0;
+                       // Free up the Irp Context
+                       Ext2ReleaseIrpContext(PtrIrpContext);
+                       // complete the IRP
+                       IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
+               } else {
+                       // Simply free up the IrpContext since the IRP has been queued
+                       Ext2ReleaseIrpContext(PtrIrpContext);
+               }
+               // Release the FCB resources if acquired.
+               if (AcquiredFCB) 
+               {
+                       Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
+                       DebugTrace(DEBUG_TRACE_MISC,  "*** FReleased in [DirCtrl]", 0);
+                       DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [DirCtrl]", 
+                                       PtrReqdFCB->MainResource.ActiveCount, 
+                                       PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
+                                       PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+                       AcquiredFCB = FALSE;
+               }
+       }
+       return(RC);
+ }
index 0000000,0000000..cadc35f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,116 @@@
++//Microsoft Developer Studio generated resource script.
++//
++#include "../inc/resource.h"
++
++#define APSTUDIO_READONLY_SYMBOLS
++/////////////////////////////////////////////////////////////////////////////
++//
++// Generated from the TEXTINCLUDE 2 resource.
++//
++#define APSTUDIO_HIDDEN_SYMBOLS
++#include "windows.h"
++#undef APSTUDIO_HIDDEN_SYMBOLS
++/* REACTOS FIXME */
++/* #include "ntverp.h" */
++
++/////////////////////////////////////////////////////////////////////////////
++#undef APSTUDIO_READONLY_SYMBOLS
++
++/////////////////////////////////////////////////////////////////////////////
++// English (U.S.) resources
++
++#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
++#ifdef _WIN32
++LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
++#pragma code_page(1252)
++#endif //_WIN32
++
++#ifdef APSTUDIO_INVOKED
++/////////////////////////////////////////////////////////////////////////////
++//
++// TEXTINCLUDE
++//
++
++1 TEXTINCLUDE DISCARDABLE 
++BEGIN
++    "..\\inc\\resource.h\0"
++END
++
++2 TEXTINCLUDE DISCARDABLE 
++BEGIN
++    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
++    "#include ""windows.h""\r\n"
++    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
++    "#include ""ntverp.h""\r\n"
++    "\0"
++END
++
++3 TEXTINCLUDE DISCARDABLE 
++BEGIN
++    "\r\n"
++    "\0"
++END
++
++#endif    // APSTUDIO_INVOKED
++
++
++#ifndef _MAC
++/////////////////////////////////////////////////////////////////////////////
++//
++// Version
++//
++
++VS_VERSION_INFO VERSIONINFO
++ FILEVERSION 0,0,0,3
++ PRODUCTVERSION 0,0,0,3
++ FILEFLAGSMASK 0x3fL
++#ifdef _DEBUG
++ FILEFLAGS 0x29L
++#else
++ FILEFLAGS 0x28L
++#endif
++ FILEOS 0x40004L
++ FILETYPE 0x3L
++ FILESUBTYPE 0x7L
++BEGIN
++    BLOCK "StringFileInfo"
++    BEGIN
++        BLOCK "040904b0"
++        BEGIN
++            VALUE "Comments", "Ext2 File System Driver\0"
++            VALUE "CompanyName", "Purayidathil\0"
++            VALUE "FileDescription", "Ext2 File System Driver\0"
++            VALUE "FileVersion", "0, 0, 0, 3\0"
++            VALUE "InternalName", "ext2.sys\0"
++            VALUE "LegalCopyright", "Copyright © 2002 Manoj Paul Joseph\0"
++            VALUE "LegalTrademarks", " - \0"
++            VALUE "OriginalFilename", "ext2.sys\0"
++            VALUE "PrivateBuild", " - \0"
++            VALUE "ProductName", "Ext2 File System Driver for Windows NT\0"
++            VALUE "ProductVersion", "0, 0, 0, 3\0"
++            VALUE "SpecialBuild", " - \0"
++        END
++    END
++    BLOCK "VarFileInfo"
++    BEGIN
++        VALUE "Translation", 0x409, 1200
++    END
++END
++
++#endif    // !_MAC
++
++#endif    // English (U.S.) resources
++/////////////////////////////////////////////////////////////////////////////
++
++
++
++#ifndef APSTUDIO_INVOKED
++/////////////////////////////////////////////////////////////////////////////
++//
++// Generated from the TEXTINCLUDE 3 resource.
++//
++
++
++/////////////////////////////////////////////////////////////////////////////
++#endif    // not APSTUDIO_INVOKED
++
index 0000000,0000000..3df67ef
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,381 @@@
++/*************************************************************************
++*
++* File: ext2init.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     This file contains the initialization code for the kernel mode
++*     Ext2 FSD module. The DriverEntry() routine is called by the I/O
++*     sub-system to initialize the FSD.
++*
++* Author: Manoj Paul Joseph
++*
++*************************************************************************/
++
++ 
++#include                      "ext2fsd.h"
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_INIT
++#define                       DEBUG_LEVEL                                             (DEBUG_TRACE_INIT)
++
++#define                       EXT2_FS_NAME                                    L"\\ext2"
++
++// global variables are declared here
++Ext2Data                                      Ext2GlobalData;
++
++
++/*************************************************************************
++*
++* Function: DriverEntry()
++*
++* Description:
++*     This routine is the standard entry point for all kernel mode drivers.
++*     The routine is invoked at IRQL PASSIVE_LEVEL in the context of a
++*     system worker thread.
++*     All FSD specific data structures etc. are initialized here.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: STATUS_SUCCESS/Error (will cause driver to be unloaded).
++*
++*************************************************************************/
++NTSTATUS DriverEntry(
++PDRIVER_OBJECT                DriverObject,           // created by the I/O sub-system
++PUNICODE_STRING       RegistryPath)           // path to the registry key
++{
++      NTSTATUS                RC = STATUS_SUCCESS;
++      UNICODE_STRING  DriverDeviceName;
++      BOOLEAN                 RegisteredShutdown = FALSE;
++
++#if 0
++      Ext2BreakPoint();
++#endif
++
++      try 
++      {
++              try 
++              {
++                      
++                      DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Ext2 File System Driver Entry <<<<<<<", 0);
++                      // initialize the global data structure
++                      RtlZeroMemory(&Ext2GlobalData, sizeof(Ext2GlobalData));
++
++                      // initialize some required fields
++                      Ext2GlobalData.NodeIdentifier.NodeType = EXT2_NODE_TYPE_GLOBAL_DATA;
++                      Ext2GlobalData.NodeIdentifier.NodeSize = sizeof(Ext2GlobalData);
++
++                      // initialize the global data resource and remember the fact that
++                      //      the resource has been initialized
++                      RC = ExInitializeResourceLite(&(Ext2GlobalData.GlobalDataResource));
++                      ASSERT(NT_SUCCESS(RC));
++                      Ext2SetFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_RESOURCE_INITIALIZED);
++
++                      // keep a ptr to the driver object sent to us by the I/O Mgr
++                      Ext2GlobalData.Ext2DriverObject = DriverObject;
++
++                      // initialize the mounted logical volume list head
++                      InitializeListHead( &( Ext2GlobalData.NextVCB ) );
++
++                      // before we proceed with any more initialization, read in
++                      //      user supplied configurable values ...
++                      // if (!NT_SUCCESS(RC = Ext2ObtainRegistryValues(RegistryPath))) {
++                                      // in your commercial driver implementation, it would be
++                                      //      advisable for your driver to print an appropriate error
++                                      //      message to the system error log before leaving
++                      //              try_return(RC);
++                      //      }
++
++                      // we should have the registry data (if any), allocate zone memory ...
++                      //      This is an example of when FSD implementations try to pre-allocate
++                      //      some fixed amount of memory to avoid internal fragmentation and/or waiting
++                      //      later during run-time ...
++
++#ifdef USE_ZONES
++                      
++                      if (!NT_SUCCESS(RC = Ext2InitializeZones())) 
++                      {
++                              // we failed, print a message and leave ...
++                              try_return(RC);
++                      }
++#endif
++
++                      //
++                      //      Initialize the Thread queue structure...
++                      //
++                      KeInitializeEvent( 
++                              &Ext2GlobalData.ThreadQueue.QueueEvent,
++                              SynchronizationEvent,
++                              FALSE
++                              );
++                      KeInitializeSpinLock( &Ext2GlobalData.ThreadQueue.SpinLock );
++                      InitializeListHead( &Ext2GlobalData.ThreadQueue.ThreadQueueListHead );
++
++                      //
++                      //      Done Initializing...
++                      //      Now Creating a worker thread to handle Worker threads...
++                      //
++                      PsCreateSystemThread( 
++                              &Ext2GlobalData.ThreadQueue.QueueHandlerThread, (ACCESS_MASK) 0L, 
++                              NULL, NULL, NULL, Ext2QueueHandlerThread, NULL );
++
++                      // initialize the IRP major function table, and the fast I/O table
++                      Ext2FsdInitializeFunctionPointers(DriverObject);
++
++                      // create a device object representing the driver itself
++                      //      so that requests can be targeted to the driver ...
++                      //      e.g. for a disk-based FSD, "mount" requests will be sent to
++                      //                this device object by the I/O Manager.\
++                      //                For a redirector/server, you may have applications
++                      //                send "special" IOCTL's using this device object ...
++                      RtlInitUnicodeString(&DriverDeviceName, EXT2_FS_NAME);
++                      if (!NT_SUCCESS(RC = IoCreateDevice(
++                                      DriverObject,           // our driver object
++                                      0,                                              // don't need an extension for this object
++                                      &DriverDeviceName,// name - can be used to "open" the driver
++               // see the book for alternate choices
++                                      FILE_DEVICE_DISK_FILE_SYSTEM,
++                                      0,                                              // no special characteristics
++               // do not want this as an exclusive device, though you might
++                                      FALSE,
++                                      &(Ext2GlobalData.Ext2DeviceObject)))) 
++                      {
++                              // failed to create a device object, leave ...
++                              try_return(RC);
++                      }
++
++
++
++                      // register the driver with the I/O Manager, pretend as if this is
++                      //      a physical disk based FSD (or in order words, this FSD manages
++                      //      logical volumes residing on physical disk drives)
++                      IoRegisterFileSystem(Ext2GlobalData.Ext2DeviceObject);
++
++                      {
++                              TIME_FIELDS             TimeFields;
++
++                              TimeFields.Day = 1;
++                              TimeFields.Hour = 0;
++                              TimeFields.Milliseconds = 0;
++                              TimeFields.Minute = 0;
++                              TimeFields.Month = 1;
++                              TimeFields.Second = 0;
++                              TimeFields.Weekday = 0;
++                              TimeFields.Year = 1970;
++                              RtlTimeFieldsToTime( &TimeFields, &Ext2GlobalData.TimeDiff );
++
++                              /*
++                              Ext2GlobalData.TimeDiff.QuadPart = 0;
++                              RtlTimeToTimeFields( &Ext2GlobalData.TimeDiff,&TimeFields );
++                              TimeFields.Year = 2002;
++                              RtlTimeFieldsToTime( &TimeFields, &Ext2GlobalData.TimeDiff );
++                              */
++
++                      }
++              }
++              except (EXCEPTION_EXECUTE_HANDLER) 
++              {
++                      // we encountered an exception somewhere, eat it up
++                      RC = GetExceptionCode();
++              }
++
++              try_exit:       NOTHING;
++      }
++      finally 
++      {
++              // start unwinding if we were unsuccessful
++              if (!NT_SUCCESS(RC)) 
++              {
++
++                      // Now, delete any device objects, etc. we may have created
++                      if (Ext2GlobalData.Ext2DeviceObject) 
++                      {
++                              IoDeleteDevice(Ext2GlobalData.Ext2DeviceObject);
++                              Ext2GlobalData.Ext2DeviceObject = NULL;
++                      }
++
++                      // free up any memory we might have reserved for zones/lookaside
++                      //      lists
++                      if (Ext2GlobalData.Ext2Flags & EXT2_DATA_FLAGS_ZONES_INITIALIZED) 
++                      {
++                              Ext2DestroyZones();
++                      }
++
++                      // delete the resource we may have initialized
++                      if (Ext2GlobalData.Ext2Flags & EXT2_DATA_FLAGS_RESOURCE_INITIALIZED) 
++                      {
++                              // un-initialize this resource
++                              ExDeleteResourceLite(&(Ext2GlobalData.GlobalDataResource));
++                              Ext2ClearFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_RESOURCE_INITIALIZED);
++                      }
++              }
++      }
++
++      return(RC);
++}
++
++/*************************************************************************
++*
++* Function: Ext2FsdInitializeFunctionPointers()
++*
++* Description:
++*     Initialize the IRP... function pointer array in the driver object
++*     structure. Also initialize the fast-io function ptr array ...
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: None
++*
++*************************************************************************/
++void Ext2FsdInitializeFunctionPointers(
++PDRIVER_OBJECT                DriverObject)           // created by the I/O sub-system
++{
++   PFAST_IO_DISPATCH  PtrFastIoDispatch = NULL;
++      
++      // initialize the function pointers for the IRP major
++      //      functions that this FSD is prepared to  handle ...
++      //      NT Version 4.0 has 28 possible functions that a
++      //      kernel mode driver can handle.
++      //      NT Version 3.51 and before has only 22 such functions,
++      //      of which 18 are typically interesting to most FSD's.
++      
++      //      The only interesting new functions that a FSD might
++      //      want to respond to beginning with Version 4.0 are the
++      //      IRP_MJ_QUERY_QUOTA and the IRP_MJ_SET_QUOTA requests.
++      
++      //      The code below does not handle quota manipulation, neither
++      //      does the NT Version 4.0 operating system (or I/O Manager).
++      //      However, you should be on the lookout for any such new
++      //      functionality that your FSD might have to implement in
++      //      the near future.
++      
++      DriverObject->MajorFunction[IRP_MJ_CREATE]                                      = Ext2Create;
++      DriverObject->MajorFunction[IRP_MJ_CLOSE]                                       = Ext2Close;
++      DriverObject->MajorFunction[IRP_MJ_READ]                                        = Ext2Read;
++      DriverObject->MajorFunction[IRP_MJ_WRITE]                                       = Ext2Write;
++
++      DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION]           = Ext2FileInfo;
++      DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION]                     = Ext2FileInfo;
++
++      DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS]                       = Ext2Flush;
++      // To implement support for querying and modifying volume attributes
++      // (volume information query/set operations), enable initialization
++      // of the following two function pointers and then implement the supporting
++      // functions. Use Chapter 11 in the text to assist you in your efforts.
++      DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = Ext2QueryVolInfo;
++      DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = Ext2SetVolInfo;
++      DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL]   = Ext2DirControl;
++      // To implement support for file system IOCTL calls, enable initialization
++      // of the following function pointer and implement appropriate support. Use
++      // Chapter 11 in the text to assist you in your efforts.
++      DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = Ext2FileSystemControl;
++      DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]              = Ext2DeviceControl;
++      DriverObject->MajorFunction[IRP_MJ_SHUTDOWN]                            = Ext2Shutdown;
++      // For byte-range lock support, enable initialization of the following
++      // function pointer and implement appropriate support. Use Chapter 10
++      // in the text to assist you in your efforts.
++      // DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL]             = Ext2LockControl;
++      DriverObject->MajorFunction[IRP_MJ_CLEANUP]                             = Ext2Cleanup;
++      // If your FSD supports security attributes, you should provide appropriate
++      // dispatch entry points and initialize the function pointers as given below.
++      // DriverObject->MajorFunction[IRP_MJ_QUERY_SECURITY]           = Ext2Security;
++      // DriverObject->MajorFunction[IRP_MJ_SET_SECURITY]             = Ext2Security;
++      // If you support extended attributes, you should provide appropriate
++      // dispatch entry points and initialize the function pointers as given below.
++      // DriverObject->MajorFunction[IRP_MJ_QUERY_EA]                         = Ext2ExtendedAttr;
++      // DriverObject->MajorFunction[IRP_MJ_SET_EA]                           = Ext2ExtendedAttr;
++
++      // Now, it is time to initialize the fast-io stuff ...
++/*
++      DriverObject->FastIoDispatch = NULL;
++
++*/
++      PtrFastIoDispatch = DriverObject->FastIoDispatch = &(Ext2GlobalData.Ext2FastIoDispatch);
++      
++      // initialize the global fast-io structure
++      //      NOTE: The fast-io structure has undergone a substantial revision
++      //      in Windows NT Version 4.0. The structure has been extensively expanded.
++      //      Therefore, if your driver needs to work on both V3.51 and V4.0+,
++      //      you will have to be able to distinguish between the two versions at compile time.
++      PtrFastIoDispatch->SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH);
++      PtrFastIoDispatch->FastIoCheckIfPossible        = Ext2FastIoCheckIfPossible;
++      PtrFastIoDispatch->FastIoRead                           = Ext2FastIoRead;
++      PtrFastIoDispatch->FastIoWrite                          = Ext2FastIoWrite;
++      PtrFastIoDispatch->FastIoQueryBasicInfo         = Ext2FastIoQueryBasicInfo;
++      PtrFastIoDispatch->FastIoQueryStandardInfo      = Ext2FastIoQueryStdInfo;
++      PtrFastIoDispatch->FastIoLock                           = Ext2FastIoLock;
++      PtrFastIoDispatch->FastIoUnlockSingle           = Ext2FastIoUnlockSingle;
++      PtrFastIoDispatch->FastIoUnlockAll                      = Ext2FastIoUnlockAll;
++      PtrFastIoDispatch->FastIoUnlockAllByKey         = Ext2FastIoUnlockAllByKey;
++      PtrFastIoDispatch->AcquireFileForNtCreateSection = Ext2FastIoAcqCreateSec;
++      PtrFastIoDispatch->ReleaseFileForNtCreateSection = Ext2FastIoRelCreateSec;
++
++      // the remaining are only valid under NT Version 4.0 and later
++#if(_WIN32_WINNT >= 0x0400)
++      PtrFastIoDispatch->FastIoQueryNetworkOpenInfo   = Ext2FastIoQueryNetInfo;
++      PtrFastIoDispatch->AcquireForModWrite           = Ext2FastIoAcqModWrite;
++      PtrFastIoDispatch->ReleaseForModWrite           = Ext2FastIoRelModWrite;
++      PtrFastIoDispatch->AcquireForCcFlush            = Ext2FastIoAcqCcFlush;
++      PtrFastIoDispatch->ReleaseForCcFlush            = Ext2FastIoRelCcFlush;
++
++      // MDL functionality
++      PtrFastIoDispatch->MdlRead                                      = Ext2FastIoMdlRead;
++      PtrFastIoDispatch->MdlReadComplete                      = Ext2FastIoMdlReadComplete;
++      PtrFastIoDispatch->PrepareMdlWrite                      = Ext2FastIoPrepareMdlWrite;
++      PtrFastIoDispatch->MdlWriteComplete                     = Ext2FastIoMdlWriteComplete;
++
++      // although this FSD does not support compressed read/write functionality,
++      //      NTFS does, and if you design a FSD that can provide such functionality,
++      //      you should consider initializing the fast io entry points for reading
++      //      and/or writing compressed data ...
++#endif        // (_WIN32_WINNT >= 0x0400)
++
++
++      // last but not least, initialize the Cache Manager callback functions
++      //      which are used in CcInitializeCacheMap()
++      Ext2GlobalData.CacheMgrCallBacks.AcquireForLazyWrite = Ext2AcqLazyWrite;
++      Ext2GlobalData.CacheMgrCallBacks.ReleaseFromLazyWrite = Ext2RelLazyWrite;
++      Ext2GlobalData.CacheMgrCallBacks.AcquireForReadAhead = Ext2AcqReadAhead;
++      Ext2GlobalData.CacheMgrCallBacks.ReleaseFromReadAhead = Ext2RelReadAhead;
++
++      return;
++}
++
++
++VOID Ext2QueueHandlerThread( 
++      IN PVOID StartContext )
++{             
++              
++      DebugTrace(DEBUG_TRACE_MISC,   "Ext2QueueHandlerThread!!!", 0);
++              
++      while( 1 )
++      {       
++              KeWaitForSingleObject( &Ext2GlobalData.ThreadQueue.QueueEvent,
++                      Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
++              
++              DebugTrace(DEBUG_TRACE_MISC,   "Ext2QueueHandlerThread Alerted!!!", 0);
++              
++              while( !IsListEmpty( &Ext2GlobalData.ThreadQueue.ThreadQueueListHead ) )
++              {
++                      HANDLE                          ThreadHandle;
++                      PLIST_ENTRY                     PtrEntry = NULL;
++                      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++
++                      PtrEntry = ExInterlockedRemoveHeadList( 
++                              &Ext2GlobalData.ThreadQueue.ThreadQueueListHead, 
++                              &Ext2GlobalData.ThreadQueue.SpinLock );
++                      ASSERT( PtrEntry );
++                      PtrIrpContext = CONTAINING_RECORD( PtrEntry, Ext2IrpContext, ThreadQueueListEntry );
++                      
++                      PsCreateSystemThread( 
++                              &ThreadHandle, (ACCESS_MASK) 0L, 
++                              NULL, NULL, NULL, Ext2CommonDispatch, PtrIrpContext );
++              }
++      }       
++}
index 0000000,0000000..39d8783
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1757 @@@
++/*************************************************************************
++*
++* File: fastio.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Contains code to handle the various "fast-io" calls.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#include                      "ext2fsd.h"
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_FAST_IO
++
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoCheckIfPossible()
++*
++* Description:
++*     To fast-io or not to fast-io, that is the question ...
++*     This routine helps the I/O Manager determine whether the FSD wishes
++*     to permit fast-io on a specific file stream.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoCheckIfPossible(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN ULONG                                                      Length,
++IN BOOLEAN                                            Wait,
++IN ULONG                                                      LockKey,
++IN BOOLEAN                                            CheckForReadOperation,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;
++      PtrExt2FCB                      PtrFCB = NULL;
++      PtrExt2CCB                      PtrCCB = NULL;
++      LARGE_INTEGER           IoLength;
++
++      // Obtain a pointer to the FCB and CCB for the file stream.
++      PtrCCB = (PtrExt2CCB)(FileObject->FsContext2);
++      ASSERT(PtrCCB);
++      PtrFCB = PtrCCB->PtrFCB;
++      ASSERT(PtrFCB);
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoCheckIfPossible - Denying", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++      
++      AssertFCBorVCB( PtrFCB );
++
++/*    if( !( PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB 
++                      || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB ) )
++      {
++              //      Ext2BreakPoint();
++              DebugTrace(DEBUG_TRACE_ERROR,   "~~~[FastIO call]~~~  Invalid FCB...", 0);
++
++              return FALSE;
++      }
++*/
++
++      return FALSE;
++
++      // Validate that this is a fast-IO request to a regular file.
++      // The sample FSD for example, will not allow fast-IO requests
++      // to volume objects, or to directories.
++      if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) ||
++               (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) 
++      {
++              // This is not allowed.
++              return(ReturnedStatus);
++      }
++
++      IoLength = RtlConvertUlongToLargeInteger(Length);
++      
++      // Your FSD can determine the checks that it needs to perform.
++      // Typically, a FSD will check whether there exist any byte-range
++      // locks that would prevent a fast-IO operation from proceeding.
++      
++      // ... (FSD specific checks go here).
++      
++      if (CheckForReadOperation) 
++      {
++              // Chapter 11 describes how to use the FSRTL package for byte-range
++              // lock requests. The following routine is exported by the FSRTL
++              // package and it returns TRUE if the read operation should be
++              // allowed to proceed based on the status of the current byte-range
++              // locks on the file stream. If you do not use the FSRTL package
++              // for byte-range locking support, then you must substitute your
++              // own checks over here.
++              // ReturnedStatus = FsRtlFastCheckLockForRead(&(PtrFCB->FCBByteRangeLock),
++              //                                                      FileOffset, &IoLength, LockKey, FileObject,
++      //                     PsGetCurrentProcess());
++      } 
++      else 
++      {
++              // This is a write request. Invoke the FSRTL byte-range lock package
++              // to see whether the write should be allowed to proceed.
++              // ReturnedStatus = FsRtlFastCheckLockForWrite(&(PtrFCB->FCBByteRangeLock),
++              //                                                      FileOffset, &IoLength, LockKey, FileObject,
++      //                     PsGetCurrentProcess());
++      }
++      
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoRead()
++*
++* Description:
++*     Bypass the traditional IRP method to perform a read operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoRead(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN ULONG                                                      Length,
++IN BOOLEAN                                            Wait,
++IN ULONG                                                      LockKey,
++OUT PVOID                                             Buffer,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoRead", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++      
++
++      try 
++      {
++
++              try 
++              {
++
++                      // Chapter 11 describes how to roll your own fast-IO entry points.
++                      // Typically, you will acquire appropriate resources here and
++                      // then (maybe) forward the request to FsRtlCopyRead().
++                      // If you are a suitably complex file system, you may even choose
++                      // to do some pre-processing (e.g. prefetching data from someplace)
++                      // before passing on the request to the FSRTL package.
++
++                      // Of course, you also have the option of bypassing the FSRTL
++                      // package completely and simply forwarding the request directly
++                      // to the NT Cache Manager.
++
++                      // Bottom line is that you have complete flexibility on determining
++                      // what you decide to do here. Read Chapter 11 well (and obviously
++                      // other related issues) before filling in this and other fast-IO
++                      // dispatch entry points.
++
++                      NOTHING;
++      
++              } 
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++      
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++      
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++
++              }
++
++              try_exit:       NOTHING;
++
++      } finally {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoWrite()
++*
++* Description:
++*     Bypass the traditional IRP method to perform a write operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoWrite(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN ULONG                                                      Length,
++IN BOOLEAN                                            Wait,
++IN ULONG                                                      LockKey,
++OUT PVOID                                             Buffer,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoWrite", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++      try 
++      {
++              try 
++              {
++
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++      
++              } 
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++      
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++      
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoQueryBasicInfo()
++*
++* Description:
++*     Bypass the traditional IRP method to perform a query basic
++*     information operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoQueryBasicInfo(
++IN PFILE_OBJECT                                       FileObject,
++IN BOOLEAN                                                    Wait,
++OUT PFILE_BASIC_INFORMATION   Buffer,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                                     DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                        RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoQueryBasicInfo", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++      try
++      {
++
++              try
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++      
++              }
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally 
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++/*************************************************************************
++*
++* Function: Ext2FastIoQueryStdInfo()
++*
++* Description:
++*     Bypass the traditional IRP method to perform a query standard
++*     information operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoQueryStdInfo(
++IN PFILE_OBJECT                                               FileObject,
++IN BOOLEAN                                                    Wait,
++OUT PFILE_STANDARD_INFORMATION                Buffer,
++OUT PIO_STATUS_BLOCK                          IoStatus,
++IN PDEVICE_OBJECT                                     DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoQueryStdInfo", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++      try 
++      {
++
++              try
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++      
++              } 
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++/*************************************************************************
++*
++* Function: Ext2FastIoLock()
++*
++* Description:
++*     Bypass the traditional IRP method to perform a byte range lock
++*     operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoLock(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN PLARGE_INTEGER                             Length,
++PEPROCESS                                             ProcessId,
++ULONG                                                         Key,
++BOOLEAN                                                       FailImmediately,
++BOOLEAN                                                       ExclusiveLock,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                        RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoLock", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++      
++      try 
++      {
++
++              try 
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++      
++              }
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      } 
++      finally 
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoUnlockSingle()
++*
++* Description:
++*     Bypass the traditional IRP method to perform a byte range unlock
++*     operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoUnlockSingle(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN PLARGE_INTEGER                             Length,
++PEPROCESS                                             ProcessId,
++ULONG                                                         Key,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoUnlockSingle", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try 
++      {
++
++              try 
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++      
++              } 
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      } 
++      finally 
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoUnlockAll()
++*
++* Description:
++*     Bypass the traditional IRP method to perform multiple byte range unlock
++*     operations.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoUnlockAll(
++IN PFILE_OBJECT                               FileObject,
++PEPROCESS                                             ProcessId,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoUnlockAll", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try
++      {
++              try
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++      
++              } 
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoUnlockAllByKey()
++*
++* Description:
++*     Bypass the traditional IRP method to perform multiple byte range unlock
++*     operations.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoUnlockAllByKey(
++IN PFILE_OBJECT                               FileObject,
++PEPROCESS                                             ProcessId,
++ULONG                                                         Key,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                        RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoUnlockAllByKey", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++      try 
++      {
++
++              try 
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++      
++              }
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoAcqCreateSec()
++*
++* Description:
++*     Not really a fast-io operation. Used by the VMM to acquire FSD resources
++*     before processing a file map (create section object) request.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: None (we must be prepared to handle VMM initiated calls)
++*
++*************************************************************************/
++void Ext2FastIoAcqCreateSec(
++IN PFILE_OBJECT                       FileObject)
++{
++      PtrExt2FCB                      PtrFCB = NULL;
++      PtrExt2CCB                      PtrCCB = NULL;
++      PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
++
++      // Obtain a pointer to the FCB and CCB for the file stream.
++      PtrCCB = (PtrExt2CCB)(FileObject->FsContext2);
++      ASSERT(PtrCCB);
++      PtrFCB = PtrCCB->PtrFCB;
++      ASSERT(PtrFCB);
++
++      AssertFCB( PtrFCB );
++
++/*    if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB )
++      {
++              //      Ext2BreakPoint();
++              DebugTrace(DEBUG_TRACE_ERROR,   "~~~[FastIO call]~~~  Invalid FCB...", 0);
++              return;
++      }       */
++      
++      PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~ Ext2FastIoAcqCreateSec", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      // Acquire the MainResource exclusively for the file stream
++      
++      DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire FCB Exclusively [FastIo]", 0);
++
++      DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
++      ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE);
++
++      DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0);
++
++      // Although this is typically not required, the sample FSD will
++      // also acquire the PagingIoResource exclusively at this time
++      // to conform with the resource acquisition described in the set
++      // file information routine. Once again though, you will probably
++      // not need to do this.
++      DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCBPaging Exclusively [FastIo]", 0);
++      DebugTraceState( "FCBPaging AC:0x%LX   SW:0x%LX   EX:0x%LX   [FastIo]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters );
++      ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), TRUE);
++      
++      DebugTrace(DEBUG_TRACE_MISC,"*** FCBPaging acquired [FastIo]", 0);
++
++      return;
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoRelCreateSec()
++*
++* Description:
++*     Not really a fast-io operation. Used by the VMM to release FSD resources
++*     after processing a file map (create section object) request.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: None
++*
++*************************************************************************/
++void Ext2FastIoRelCreateSec(
++IN PFILE_OBJECT                       FileObject)
++{
++
++      PtrExt2FCB                      PtrFCB = NULL;
++      PtrExt2CCB                      PtrCCB = NULL;
++      PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
++
++      // Obtain a pointer to the FCB and CCB for the file stream.
++      PtrCCB = (PtrExt2CCB)(FileObject->FsContext2);
++      ASSERT(PtrCCB);
++      PtrFCB = PtrCCB->PtrFCB;
++      ASSERT(PtrFCB);
++      AssertFCB( PtrFCB );
++
++/*    if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB )
++      {
++              //      Ext2BreakPoint();
++              DebugTrace(DEBUG_TRACE_ERROR,   "~~~[FastIO call]~~~  Invalid FCB...", 0);
++              return;
++      }*/
++
++      PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2FastIoRelCreateSec", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      // Release the PagingIoResource for the file stream
++      Ext2ReleaseResource(&(PtrReqdFCB->PagingIoResource));
++      DebugTrace(DEBUG_TRACE_MISC, "*** FCBPaging Released in [FastIo]", 0);
++      DebugTraceState( "FCBPaging AC:0x%LX   SW:0x%LX   EX:0x%LX   [FastIo]", 
++              PtrReqdFCB->PagingIoResource.ActiveCount, 
++              PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, 
++              PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters );
++
++      // Release the MainResource for the file stream
++      Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
++      DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0);
++      DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [FastIo]", 
++              PtrReqdFCB->MainResource.ActiveCount, 
++              PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
++              PtrReqdFCB->MainResource.NumberOfSharedWaiters );
++
++      return;
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2AcqLazyWrite()
++*
++* Description:
++*     Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD
++*     resources before performing a delayed write (write behind/lazy write)
++*     operation.
++*     NOTE: this function really must succeed since the Cache Manager will
++*                     typically ignore failure and continue on ...
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE (Cache Manager does not tolerate FALSE well)
++*
++*************************************************************************/
++BOOLEAN Ext2AcqLazyWrite(
++IN PVOID                                              Context,
++IN BOOLEAN                                            Wait)
++{
++      BOOLEAN                         ReturnedStatus = TRUE;
++      
++      PtrExt2VCB                      PtrVCB = NULL;
++      PtrExt2FCB                      PtrFCB = NULL;
++      PtrExt2CCB                      PtrCCB = NULL;
++      PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
++
++      // The context is whatever we passed to the Cache Manager when invoking
++      // the CcInitializeCacheMaps() function. In the case of the sample FSD
++      // implementation, this context is a pointer to the CCB structure.
++
++      ASSERT(Context);
++      PtrCCB = (PtrExt2CCB)(Context);
++      
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2AcqLazyWrite", 0);
++
++      if(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB)
++      {
++              //
++              //      Acquiring Resource for a file write...
++              //
++              PtrFCB = PtrCCB->PtrFCB;
++              AssertFCB( PtrFCB );
++      }
++      else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB )
++      {
++              //
++              //      Acquiring Resource for a volume write...
++              //
++              PtrVCB = ( PtrExt2VCB )PtrCCB;
++              PtrCCB = NULL;
++              DebugTrace(DEBUG_TRACE_MISC,"~~~[FastIO call]~~~  Ext2AcqLazyWrite - for Volume", 0);
++              
++              //      Acquire nothing...
++              //      Just proceed...
++              return TRUE;
++
++      }
++      else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) 
++      {
++              //
++              //      This must have been a FCB created / maintained on the FSD's initiative...
++              //      This would have been done to cache access to a directory...
++              //
++              PtrFCB = ( PtrExt2FCB )PtrCCB;
++              PtrCCB = NULL;
++      }
++      else
++      {
++              DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~  Ext2AcqLazyWrite - Invalid context", 0);
++              Ext2BreakPoint();
++              return FALSE;
++      }
++      
++      if( PtrCCB && PtrCCB->PtrFileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject );
++      }
++
++      AssertFCB( PtrFCB );
++
++
++      PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
++
++
++      // Acquire the MainResource in the FCB exclusively. Then, set the
++      // lazy-writer thread id in the FCB structure for identification when
++      // an actual write request is received by the FSD.
++      // Note: The lazy-writer typically always supplies WAIT set to TRUE.
++      
++      DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCB Exclusively [FastIo]", 0);
++
++      DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
++      if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource),
++                                                                                                        Wait)) 
++      {
++              DebugTrace(DEBUG_TRACE_MISC,"*** Attempt to acquire FCB FAILED [FastIo]", 0);
++              ReturnedStatus = FALSE;
++      } 
++      else
++      {
++              DebugTrace(DEBUG_TRACE_MISC,"*** FCB acquired [FastIo]", 0);
++              // Now, set the lazy-writer thread id.
++              ASSERT(!(PtrFCB->LazyWriterThreadID));
++              PtrFCB->LazyWriterThreadID = (unsigned int)(PsGetCurrentThread());
++      }
++
++      // If your FSD needs to perform some special preparations in anticipation
++      // of receving a lazy-writer request, do so now.
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2RelLazyWrite()
++*
++* Description:
++*     Not really a fast-io operation. Used by the NT Cache Mgr to release FSD
++*     resources after performing a delayed write (write behind/lazy write)
++*     operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: None
++*
++*************************************************************************/
++void Ext2RelLazyWrite(
++IN PVOID                                                      Context)
++{
++
++      BOOLEAN                         ReturnedStatus = TRUE;
++
++      PtrExt2VCB                      PtrVCB = NULL;
++      PtrExt2FCB                      PtrFCB = NULL;
++      PtrExt2CCB                      PtrCCB = NULL;
++      PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
++
++      // The context is whatever we passed to the Cache Manager when invoking
++      // the CcInitializeCacheMaps() function. In the case of the sample FSD
++      // implementation, this context is a pointer to the CCB structure.
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2RelLazyWrite", 0);
++
++      ASSERT(Context);
++      PtrCCB = (PtrExt2CCB)(Context);
++      
++      if(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB)
++      {
++              PtrFCB = PtrCCB->PtrFCB;
++              AssertFCB( PtrFCB );
++      }
++      else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB )
++      {
++              PtrVCB = ( PtrExt2VCB )PtrCCB;
++              PtrCCB = NULL;
++              DebugTrace(DEBUG_TRACE_MISC,"~~~[FastIO call]~~~  Ext2RelLazyWrite - for Volume", 0);
++              
++              //      Acquire was acquired nothing...
++              //      Just return...
++              return;
++
++      }
++      else if( PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB ) 
++      {
++              //
++              //      This must have been a FCB created / maintained on the FSD's initiative...
++              //      This would have been done to cache access to a directory...
++              //
++              PtrFCB = ( PtrExt2FCB )PtrCCB;
++              PtrCCB = NULL;
++      }
++      else
++      {
++              DebugTrace(DEBUG_TRACE_ERROR, "~~~[FastIO call]~~~  Ext2RelLazyWrite - Invalid context", 0);
++              Ext2BreakPoint();
++              return ;
++      }
++
++      if( PtrCCB && PtrCCB->PtrFileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject );
++      }
++
++      PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
++
++      // Remove the current thread-id from the FCB and release the MainResource.
++      ASSERT( (PtrFCB->LazyWriterThreadID) == (unsigned int)PsGetCurrentThread() );
++      PtrFCB->LazyWriterThreadID = 0;
++
++
++      // Release the acquired resource.
++      Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
++      DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0);
++      DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [FastIo]", 
++              PtrReqdFCB->MainResource.ActiveCount, 
++              PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
++              PtrReqdFCB->MainResource.NumberOfSharedWaiters );
++
++      //
++      // Undo whatever else seems appropriate at this time...
++      //
++
++      return;
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2AcqReadAhead()
++*
++* Description:
++*     Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD
++*     resources before performing a read-ahead operation.
++*     NOTE: this function really must succeed since the Cache Manager will
++*                     typically ignore failure and continue on ...
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE (Cache Manager does not tolerate FALSE well)
++*
++*************************************************************************/
++BOOLEAN Ext2AcqReadAhead(
++IN PVOID                                              Context,
++IN BOOLEAN                                            Wait)
++{
++
++      BOOLEAN                         ReturnedStatus = TRUE;
++
++      PtrExt2FCB                      PtrFCB = NULL;
++      PtrExt2CCB                      PtrCCB = NULL;
++      PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
++
++      // The context is whatever we passed to the Cache Manager when invoking
++      // the CcInitializeCacheMaps() function. In the case of the sample FSD
++      // implementation, this context is a pointer to the CCB structure.
++      
++      ASSERT(Context);
++      PtrCCB = (PtrExt2CCB)(Context);
++      ASSERT(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB);
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2AcqReadAhead", 0);
++      if( PtrCCB && PtrCCB->PtrFileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject );
++      }
++
++      PtrFCB = PtrCCB->PtrFCB;
++      ASSERT(PtrFCB);
++
++      AssertFCB( PtrFCB );
++/*
++      if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB )
++      {
++              //      Ext2BreakPoint();
++              DebugTrace(DEBUG_TRACE_ERROR,   "~~~[FastIO call]~~~  Invalid FCB...", 0);
++              return TRUE;
++      }       */
++
++      PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
++
++      // Acquire the MainResource in the FCB shared.
++      // Note: The read-ahead thread typically always supplies WAIT set to TRUE.
++      DebugTrace(DEBUG_TRACE_MISC,"*** Attempting to acquire FCB Shared [FastIo]", 0);
++
++      DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [FastIo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
++      if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), Wait)) 
++      {
++              DebugTrace(DEBUG_TRACE_MISC,"*** Attempt to acquire FCB FAILED [FastIo]", 0);
++              ReturnedStatus = FALSE;
++      }
++      else
++      {
++              DebugTrace(DEBUG_TRACE_MISC,"***  FCB acquired [FastIo]", 0);
++      }
++
++      // If your FSD needs to perform some special preparations in anticipation
++      // of receving a read-ahead request, do so now.
++
++      return ReturnedStatus;
++      
++}
++
++
++
++/*************************************************************************
++*
++* Function: Ext2RelReadAhead()
++*
++* Description:
++*     Not really a fast-io operation. Used by the NT Cache Mgr to release FSD
++*     resources after performing a read-ahead operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: None
++*
++*************************************************************************/
++void Ext2RelReadAhead(
++IN PVOID                                                      Context)
++{
++      BOOLEAN                         ReturnedStatus = TRUE;
++      PtrExt2FCB                      PtrFCB = NULL;
++      PtrExt2CCB                      PtrCCB = NULL;
++      PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
++
++
++      // The context is whatever we passed to the Cache Manager when invoking
++      // the CcInitializeCacheMaps() function. In the case of the sample FSD
++      // implementation, this context is a pointer to the CCB structure.
++
++      ASSERT(Context);
++      PtrCCB = (PtrExt2CCB)(Context);
++      ASSERT(PtrCCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB);
++
++      PtrFCB = PtrCCB->PtrFCB;
++      
++      AssertFCB( PtrFCB );
++      
++      //      ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB );
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2RelReadAhead", 0);
++      if( PtrCCB && PtrCCB->PtrFileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", PtrCCB->PtrFileObject );
++      }
++
++/*    if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB )
++      {
++              //      Ext2BreakPoint();
++              DebugTrace(DEBUG_TRACE_ERROR,   "~~~[FastIO call]~~~  Invalid FCB...", 0);
++              return;
++      }       */
++
++      PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
++
++
++      // Release the acquired resource.
++      Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
++      DebugTrace(DEBUG_TRACE_MISC, "*** FCB Released [FastIo]", 0);
++      DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [FastIo]", 
++              PtrReqdFCB->MainResource.ActiveCount, 
++              PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
++              PtrReqdFCB->MainResource.NumberOfSharedWaiters );
++
++      // Of course, your FSD should undo whatever else seems appropriate at this
++      // time.
++
++      return;
++}
++
++
++/* the remaining are only valid under NT Version 4.0 and later */
++#if(_WIN32_WINNT >= 0x0400)
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoQueryNetInfo()
++*
++* Description:
++*     Get information requested by a redirector across the network. This call
++*     will originate from the LAN Manager server.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoQueryNetInfo(
++IN PFILE_OBJECT                                                                       FileObject,
++IN BOOLEAN                                                                                    Wait,
++OUT PFILE_NETWORK_OPEN_INFORMATION                    Buffer,
++OUT PIO_STATUS_BLOCK                                                  IoStatus,
++IN PDEVICE_OBJECT                                                                     DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++      
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2FastIoQueryNetInfo", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try 
++      {
++
++              try 
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++      
++      
++              } 
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      } 
++      finally 
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoMdlRead()
++*
++* Description:
++*     Bypass the traditional IRP method to perform a MDL read operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoMdlRead(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN ULONG                                                      Length,
++IN ULONG                                                      LockKey,
++OUT PMDL                                                      *MdlChain,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2FastIoMdlRead", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try 
++      {
++
++              try 
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++      
++      
++              } 
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      } 
++      finally 
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoMdlReadComplete()
++*
++* Description:
++*     Bypass the traditional IRP method to inform the NT Cache Manager and the
++*     FSD that the caller no longer requires the data locked in the system cache
++*     or the MDL to stay around anymore ..
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoMdlReadComplete(
++IN PFILE_OBJECT                               FileObject,
++OUT PMDL                                                      MdlChain,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2FastIoMdlReadComplete", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try 
++      {
++
++              try 
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++              
++              } 
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++      
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++      
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++
++              }
++
++              try_exit:       NOTHING;
++
++      } 
++      finally 
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoPrepareMdlWrite()
++*
++* Description:
++*     Bypass the traditional IRP method to prepare for a MDL write operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoPrepareMdlWrite(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++IN ULONG                                                      Length,
++IN ULONG                                                      LockKey,
++OUT PMDL                                                      *MdlChain,
++OUT PIO_STATUS_BLOCK                  IoStatus,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2FastIoPrepareMdlWrite", 0);
++      if( FileObject )
++      {
++              DebugTrace(  DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try 
++      {
++              try 
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++              
++              } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) {
++      
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++      
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++
++              }
++
++              try_exit:       NOTHING;
++
++      } 
++      finally 
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoMdlWriteComplete()
++*
++* Description:
++*     Bypass the traditional IRP method to inform the NT Cache Manager and the
++*     FSD that the caller has updated the contents of the MDL. This data can
++*     now be asynchronously written out to secondary storage by the Cache Mgr.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: TRUE/FALSE
++*
++*************************************************************************/
++BOOLEAN Ext2FastIoMdlWriteComplete(
++IN PFILE_OBJECT                               FileObject,
++IN PLARGE_INTEGER                             FileOffset,
++OUT PMDL                                                      MdlChain,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      BOOLEAN                         ReturnedStatus = FALSE;         // fast i/o failed/not allowed
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2FastIoMdlWriteComplete", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ, "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try
++      {
++
++              try
++              {
++      
++                      // See description in Ext2FastIoRead() before filling-in the
++                      // stub here.
++                      NOTHING;
++              
++              }
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(ReturnedStatus);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoAcqModWrite()
++*
++* Description:
++*     Not really a fast-io operation. Used by the VMM to acquire FSD resources
++*     before initiating a write operation via the Modified Page/Block Writer.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: STATUS_SUCCESS/Error (try not to return an error, will 'ya ? :-)
++*
++*************************************************************************/
++NTSTATUS Ext2FastIoAcqModWrite(
++IN PFILE_OBJECT                                       FileObject,
++IN PLARGE_INTEGER                                     EndingOffset,
++OUT PERESOURCE                                                *ResourceToRelease,
++IN PDEVICE_OBJECT                                     DeviceObject)
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,"~~~[FastIO call]~~~  Ext2FastIoAcqModWrite", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try
++      {
++              try
++              {
++
++                      // You must determine which resource(s) you would like to
++                      // acquire at this time. You know that a write is imminent;
++                      // you will probably therefore acquire appropriate resources
++                      // exclusively.
++
++                      // You must first get the FCB and CCB pointers from the file object
++                      // that is passed in to this function (as an argument). Note that
++                      // the ending offset (when examined in conjunction with current valid data
++                      // length) may help you in determining the appropriate resource(s) to acquire.
++
++                      // For example, if the ending offset is beyond current valid data length,
++                      // you may decide to acquire *both* the MainResource and the PagingIoResource
++                      // exclusively; otherwise, you may decide simply to acquire the PagingIoResource.
++
++                      // Consult the text for more information on synchronization in FSDs.
++
++                      // One final note; the VMM expects that you will return a pointer to
++                      // the resource that you acquired (single return value). This pointer
++                      // will be returned back to you in the release call (below).
++
++                      NOTHING;
++      
++              } 
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(RC);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoRelModWrite()
++*
++* Description:
++*     Not really a fast-io operation. Used by the VMM to release FSD resources
++*     after processing a modified page/block write operation.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: STATUS_SUCCESS/Error (an error returned here is really not expected!)
++*
++*************************************************************************/
++NTSTATUS Ext2FastIoRelModWrite(
++IN PFILE_OBJECT                               FileObject,
++IN PERESOURCE                                 ResourceToRelease,
++IN PDEVICE_OBJECT                             DeviceObject)
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace( DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoRelModWrite", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try
++      {
++              try
++              {
++
++                      // The MPW has complete the write for modified pages and therefore
++                      // wants you to release pre-acquired resource(s).
++
++                      // You must undo here whatever it is that you did in the
++                      // Ext2FastIoAcqModWrite() call above.
++
++                      NOTHING;
++      
++              }
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(RC);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoAcqCcFlush()
++*
++* Description:
++*     Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD
++*     resources before performing a CcFlush() operation on a specific file
++*     stream.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: STATUS_SUCCESS/Error
++*
++*************************************************************************/
++NTSTATUS Ext2FastIoAcqCcFlush(
++IN PFILE_OBJECT                       FileObject,
++IN PDEVICE_OBJECT                     DeviceObject)
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoAcqCcFlush", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try
++      {
++              try
++              {
++                      // Acquire appropriate resources that will allow correct synchronization
++                      // with a flush call (and avoid deadlock).
++                      NOTHING;
++      
++              }
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(RC);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2FastIoRelCcFlush()
++*
++* Description:
++*     Not really a fast-io operation. Used by the NT Cache Mgr to acquire FSD
++*     resources before performing a CcFlush() operation on a specific file
++*     stream.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: STATUS_SUCCESS/Error
++*
++*************************************************************************/
++NTSTATUS Ext2FastIoRelCcFlush(
++IN PFILE_OBJECT                       FileObject,
++IN PDEVICE_OBJECT                     DeviceObject)
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++
++      FsRtlEnterFileSystem();
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "~~~[FastIO call]~~~  Ext2FastIoRelCcFlush", 0);
++      if( FileObject )
++      {
++              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FastIO]", FileObject);
++      }
++
++      try
++      {
++              try
++              {
++                      // Release resources acquired in Ext2FastIoAcqCcFlush() above.
++                      NOTHING;
++      
++              } 
++              except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++              {
++                      RC = Ext2ExceptionHandler(PtrIrpContext, NULL);
++                      Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally
++      {
++
++      }
++      
++      FsRtlExitFileSystem();
++
++      return(RC);
++}
++
++#endif        //_WIN32_WINNT >= 0x0400
index 0000000,0047d50..0047d50
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1125 +1,1125 @@@
+ /*************************************************************************
+ *
+ * File: fileinfo.c
+ *
+ * Module: Ext2 File System Driver (Kernel mode execution only)
+ *
+ * Description:
+ *     Contains code to handle the "set/query file information" dispatch
+ *     entry points.
+ *
+ * Author: Manoj Paul Joseph
+ *
+ *
+ *************************************************************************/
+ #include                      "ext2fsd.h"
+ // define the file specific bug-check id
+ #define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_INFORMATION
+ #define                       DEBUG_LEVEL                                             (DEBUG_TRACE_FILEINFO)
+ /*************************************************************************
+ *
+ * Function: Ext2FileInfo()
+ *
+ * Description:
+ *     The I/O Manager will invoke this routine to handle a set/query file
+ *     information request
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
+ *     to be deferred to a worker thread context)
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS Ext2FileInfo(
+ PDEVICE_OBJECT                DeviceObject,           // the logical volume device object
+ PIRP                                  Irp)                                    // I/O Request Packet
+ {
+       NTSTATUS                                RC = STATUS_SUCCESS;
+       PtrExt2IrpContext       PtrIrpContext = NULL;
+       BOOLEAN                         AreWeTopLevel = FALSE;
+       DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "File Info Control IRP received...", 0);
+       FsRtlEnterFileSystem();
+       
+       ASSERT(DeviceObject);
+       ASSERT(Irp);
+       // set the top level context
+       AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
+       try 
+       {
+               // get an IRP context structure and issue the request
+               PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
+               ASSERT(PtrIrpContext);
+               RC = Ext2CommonFileInfo(PtrIrpContext, Irp);
+       } 
+       except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
+       {
+               RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
+               Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
+       }
+       if (AreWeTopLevel) 
+       {
+               IoSetTopLevelIrp(NULL);
+       }
+       FsRtlExitFileSystem();
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2CommonFileInfo()
+ *
+ * Description:
+ *     The actual work is performed here. This routine may be invoked in one'
+ *     of the two possible contexts:
+ *     (a) in the context of a system worker thread
+ *     (b) in the context of the original caller
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS      Ext2CommonFileInfo(
+ PtrExt2IrpContext                     PtrIrpContext,
+ PIRP                                                  PtrIrp)
+ {
+       NTSTATUS                                RC = STATUS_SUCCESS;
+       PIO_STACK_LOCATION              PtrIoStackLocation = NULL;
+       PFILE_OBJECT                    PtrFileObject = NULL;
+       PtrExt2FCB                              PtrFCB = NULL;
+       PtrExt2CCB                              PtrCCB = NULL;
+       PtrExt2VCB                              PtrVCB = NULL;
+       PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
+       BOOLEAN                                 MainResourceAcquired = FALSE;
+       BOOLEAN                                 VCBResourceAcquired = FALSE;
+       BOOLEAN                                 PagingIoResourceAcquired = FALSE;
+       IO_STATUS_BLOCK                 LocalIoStatus;
+       void                                    *PtrSystemBuffer = NULL;
+       long                                    BufferLength = 0;
+       FILE_INFORMATION_CLASS  FunctionalityRequested;
+       BOOLEAN                                 CanWait = FALSE;
+       BOOLEAN                                 PostRequest = FALSE;
+       try 
+       {
+               // First, get a pointer to the current I/O stack location.
+               PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
+               ASSERT(PtrIoStackLocation);
+               PtrFileObject = PtrIoStackLocation->FileObject;
+               ASSERT(PtrFileObject);
+               // Get the FCB and CCB pointers
+               Ext2GetFCB_CCB_VCB_FromFileObject ( 
+                       PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB );
+               PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
+               CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
+               // If the caller has opened a logical volume and is attempting to
+               // query information for it as a file stream, return an error.
+               if (PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) 
+               {
+                       // This is not allowed. Caller must use get/set volume information instead.
+                       RC = STATUS_INVALID_PARAMETER;
+                       try_return(RC);
+               }
+               //      ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB);
+               AssertFCB( PtrFCB );
+               PtrSystemBuffer = PtrIrp->AssociatedIrp.SystemBuffer;   
+               if (PtrIoStackLocation->MajorFunction == IRP_MJ_QUERY_INFORMATION) 
+               {
+                       //      ***********************
+                       //      Query File Information
+                       //      ***********************
+                       // Now, obtain some parameters.
+                       DebugTrace(DEBUG_TRACE_MISC,   "Buffer length = 0x%lX[FileInfo]", BufferLength );
+                       BufferLength = PtrIoStackLocation->Parameters.QueryFile.Length;
+                       FunctionalityRequested = PtrIoStackLocation->Parameters.QueryFile.FileInformationClass;
+                       //      Read in the file inode if it hasn't already been read...
+                       Ext2InitializeFCBInodeInfo( PtrFCB );
+                       //
+                       // Acquire the MainResource shared 
+                       // except for page files...
+                       //
+                       if (!(PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE)) 
+                       {
+                               // Acquire the MainResource shared.
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire FCB Shared [FileInfo]", 0);
+                               DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [FileInfo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+                               if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) 
+                               {
+                                       DebugTrace(DEBUG_TRACE_MISC,   "*** FCB acquisition FAILED [FileInfo]", 0);
+                                       PostRequest = TRUE;
+                                       try_return(RC = STATUS_PENDING);
+                               }
+                               MainResourceAcquired = TRUE;
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** FCB acquired [FileInfo]", 0);
+                       }
+                       // Do whatever the caller asked us to do
+                       switch (FunctionalityRequested) 
+                       {
+                       case FileBasicInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FileBasicInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = Ext2GetBasicInformation(PtrFCB, (PFILE_BASIC_INFORMATION)PtrSystemBuffer, &BufferLength);
+                               break;
+                       case FileStandardInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FileStandardInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = Ext2GetStandardInformation(PtrFCB, (PFILE_STANDARD_INFORMATION)PtrSystemBuffer, &BufferLength);
+                               break;
+                       // Similarly, implement all of the other query information routines
+                       // that your FSD can support.
+ #if(_WIN32_WINNT >= 0x0400)
+                       case FileNetworkOpenInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FileNetworkOpenInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = Ext2GetNetworkOpenInformation(PtrFCB, (PFILE_NETWORK_OPEN_INFORMATION)PtrSystemBuffer, &BufferLength);
+                               //      RC = STATUS_INVALID_PARAMETER;
+                               //      try_return(RC);
+                               break;
+ #endif        // _WIN32_WINNT >= 0x0400
+                       case FileInternalInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FileInternalInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               // RC = Ext2GetInternalInformation(...);
+                               RC = STATUS_INVALID_PARAMETER;
+                               try_return(RC);
+                               break;
+                       case FileEaInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FileEaInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               {       
+                                       PFILE_EA_INFORMATION EaInformation;
+                                       EaInformation = (PFILE_EA_INFORMATION) PtrSystemBuffer;
+                                       EaInformation->EaSize = 0;
+                                       BufferLength = sizeof( FILE_EA_INFORMATION );
+                                       break;
+                               }
+                               // RC = Ext2GetEaInformation(...);
+                               break;
+                       case FilePositionInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FilePositionInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               // This is fairly simple. Copy over the information from the
+                               // file object.
+                               {
+                                       PFILE_POSITION_INFORMATION              PtrFileInfoBuffer;
+                                       PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer;
+                                       ASSERT(BufferLength >= sizeof(FILE_POSITION_INFORMATION));
+                                       PtrFileInfoBuffer->CurrentByteOffset = PtrFileObject->CurrentByteOffset;
+                                       // Modify the local variable for BufferLength appropriately.
+                                       BufferLength = sizeof(FILE_POSITION_INFORMATION);
+                               }
+                               break;
+                       case FileStreamInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FileStreamInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               // RC = Ext2GetFileStreamInformation(...);
+                               RC = STATUS_INVALID_PARAMETER;
+                               try_return(RC);
+                               
+                               break;
+                       case FileAllInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FileAllInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               // The I/O Manager supplies the Mode, Access, and Alignment
+                               // information. The rest is up to us to provide.
+                               // Therefore, decrement the BufferLength appropriately (assuming
+                               // that the above 3 types on information are already in the
+                               // buffer)
+                               {
+                                       PFILE_POSITION_INFORMATION              PtrFileInfoBuffer;
+                                       PFILE_ALL_INFORMATION                   PtrAllInfo = (PFILE_ALL_INFORMATION)PtrSystemBuffer;
+                                       // Fill in the position information.
+                                       PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)&(PtrAllInfo->PositionInformation);
+                                       PtrFileInfoBuffer->CurrentByteOffset = PtrFileObject->CurrentByteOffset;
+                                       // Modify the local variable for BufferLength appropriately.
+                                       BufferLength = sizeof(FILE_ALL_INFORMATION);
+                                       // Get the remaining stuff.
+                                       if (!NT_SUCCESS(RC = Ext2GetBasicInformation(PtrFCB, (PFILE_BASIC_INFORMATION)&(PtrAllInfo->BasicInformation),
+                                                                                                                                                                       &BufferLength))) 
+                                       {
+                                               try_return(RC);
+                                       }
+                                       if (!NT_SUCCESS(RC = Ext2GetStandardInformation(PtrFCB, &(PtrAllInfo->StandardInformation), &BufferLength))) 
+                                       {
+                                               try_return(RC);
+                                       }
+                                       // Similarly, get all of the others ...
+                               }
+                               break;
+                       case FileNameInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FileNameInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               //      RC = Ext2GetFullNameInformation(...);
+                               RC = Ext2GetFullNameInformation(PtrFCB, PtrCCB, (PFILE_NAME_INFORMATION)PtrSystemBuffer, &BufferLength);
+                               break;
+                       case FileAlternateNameInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FileAlternateNameInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = STATUS_INVALID_PARAMETER;
+                               try_return(RC);
+                               // RC = Ext2GetAltNameInformation(...);
+                               break;
+                       case FileCompressionInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "FileCompressionInformation requested for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = STATUS_INVALID_PARAMETER;
+                               try_return(RC);
+                               // RC = Ext2GetCompressionInformation(...);
+                               break;
+                       default:
+                               RC = STATUS_INVALID_PARAMETER;
+                               try_return(RC);
+                       }
+                       // If we completed successfully, the return the amount of information transferred.
+                       if (NT_SUCCESS(RC)) 
+                       {
+                               PtrIrp->IoStatus.Information = BufferLength;
+                       }
+                       else 
+                       {
+                               PtrIrp->IoStatus.Information = 0;
+                       }
+               }
+               else 
+               {
+                       //      ***********************
+                       //      Set File Information
+                       //      ***********************
+                       ASSERT(PtrIoStackLocation->MajorFunction == IRP_MJ_SET_INFORMATION);
+                       DebugTrace(DEBUG_TRACE_FILEINFO,   ">>>>>>>> Set File Information <<<<<<<<< [FileInfo]", 0);
+                       // Now, obtain some parameters.
+                       FunctionalityRequested = PtrIoStackLocation->Parameters.SetFile.FileInformationClass;
+                       //      Check oplocks...
+                       //
+                       //      Acquire the VCB resource exclusively for 
+                       //      deletion, rename and link operations...
+                       //      To synchronize with create and cleanup operations
+                       //
+                       if ((FunctionalityRequested == FileDispositionInformation) || 
+                               (FunctionalityRequested == FileRenameInformation) ||
+                               (FunctionalityRequested == FileLinkInformation)) 
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire VCB Exclusively [FileInfo]", 0);
+                               DebugTraceState( " VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [FileInfo]", PtrVCB->VCBResource.ActiveCount, PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
+                               if (!ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), CanWait)) 
+                               {
+                                       DebugTrace(DEBUG_TRACE_MISC,   "*** VCB Acquisition FAILED [FileInfo]", 0);
+                                       PostRequest = TRUE;
+                                       try_return(RC = STATUS_PENDING);
+                               }
+                               // We have the VCB acquired exclusively.
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** VCB Acquired [FileInfo]", 0);
+                               VCBResourceAcquired = TRUE;
+                       }
+                       // Acquire the FCB exclusively at this time...
+                       if (!(PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE)) 
+                       {
+                               // Acquire the MainResource shared.
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire FCB Exclusively [FileInfo]", 0);
+                               DebugTraceState( " FCBMain AC:0x%LX   SW:0x%LX   EX:0x%LX   [FileInfo]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+                               if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), CanWait)) 
+                               {
+                                       DebugTrace(DEBUG_TRACE_MISC,   "*** FCB Acquisition FAILED [FileInfo]", 0);
+                                       PostRequest = TRUE;
+                                       try_return(RC = STATUS_PENDING);
+                               }
+                               MainResourceAcquired = TRUE;
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** FCB Acquired [FileInfo]", 0);
+                       }
+                       //
+                       //      For delete link (rename),
+                       //      set allocation size, and set EOF, should also acquire the paging-IO
+                       //      resource, thereby synchronizing with paging-IO requests. 
+                       //
+                       if( PtrFileObject )
+                       {
+                               DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FileInfo]", PtrFileObject);
+                               
+                       }
+                       DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire FCBPaging Exclusively [FileInfo]", 0);
+                       DebugTraceState( " FCBPaging AC:0x%LX   SW:0x%LX   EX:0x%LX   [FileInfo]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters );
+                       if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), CanWait)) 
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** Attempt to acquire FCBPaging FAILED [FileInfo]", 0);
+                               PostRequest = TRUE;
+                               try_return(RC = STATUS_PENDING);
+                       }
+                       PagingIoResourceAcquired = TRUE;
+                       DebugTrace(DEBUG_TRACE_MISC,   "*** Acquired FCBPaging [FileInfo]", 0);
+                       // Do whatever the caller asked us to do
+                       switch (FunctionalityRequested) 
+                       {
+                       case FileBasicInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "Attempt to set FileBasicInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = Ext2SetBasicInformation(PtrIrpContext, PtrFCB, PtrFileObject, (PFILE_BASIC_INFORMATION)PtrSystemBuffer);
+                               //      RC = STATUS_ACCESS_DENIED;
+                               break;
+                       case FileAllocationInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "Attempt to set FileAllocationInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = Ext2SetAllocationInformation(PtrFCB, PtrCCB, PtrVCB, PtrFileObject,
+                                                                                                                               PtrIrpContext, PtrIrp, PtrSystemBuffer);
+                               break;
+                       case FileEndOfFileInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "Attempt to set FileEndOfFileInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               // RC = Ext2SetEOF(...);
+                               RC = STATUS_INVALID_PARAMETER;
+                               try_return(RC);
+                               break;
+                       case FilePositionInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "Attempt to set FilePositionInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               // Check        if no intermediate buffering has been specified.
+                               // If it was specified, do not allow non-aligned set file
+                               // position requests to succeed.
+                               {
+                                       PFILE_POSITION_INFORMATION              PtrFileInfoBuffer;
+                                       PtrFileInfoBuffer = (PFILE_POSITION_INFORMATION)PtrSystemBuffer;
+                                       if (PtrFileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) 
+                                       {
+                                               if (PtrFileInfoBuffer->CurrentByteOffset.LowPart & PtrIoStackLocation->DeviceObject->AlignmentRequirement) 
+                                               {
+                                                       // Invalid alignment.
+                                                       try_return(RC = STATUS_INVALID_PARAMETER);
+                                               }
+                                       }
+                                       PtrFileObject->CurrentByteOffset = PtrFileInfoBuffer->CurrentByteOffset;
+                               }
+                               break;
+                       case FileDispositionInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "Attempt to set FileDispositionInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = Ext2SetDispositionInformation(PtrFCB, PtrCCB, PtrVCB, PtrFileObject, 
+                                       PtrIrpContext, PtrIrp,
+                                       (PFILE_DISPOSITION_INFORMATION)PtrSystemBuffer);
+                               break;
+                       case FileRenameInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "Attempt to set FileRenameInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = Ext2RenameOrLinkFile( PtrFCB, PtrFileObject,       PtrIrpContext,
+                                                                               PtrIrp, (PFILE_RENAME_INFORMATION)PtrSystemBuffer);
+                               break;
+                       case FileLinkInformation:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "Attempt to set FileLinkInformation for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = STATUS_INVALID_PARAMETER;
+                               try_return(RC);
+                               // When you implement your rename/link routine, be careful to
+                               // check the following two arguments:
+                               // TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject;
+                               // ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists;
+                               //
+                               // The TargetFileObject argument is a pointer to the "target
+                               // directory" file object obtained during the "create" routine
+                               // invoked by the NT I/O Manager with the SL_OPEN_TARGET_DIRECTORY
+                               // flag specified. Remember that it is quite possible that if the
+                               // rename/link is contained within a single directory, the target
+                               // and source directories will be the same.
+                               // The ReplaceExistingFile argument should be used by you to
+                               // determine if the caller wishes to replace the target (if it
+                               // currently exists) with the new link/renamed file. If this
+                               // value is FALSE, and if the target directory entry (being
+                               // renamed-to, or the target of the link) exists, you should
+                               // return a STATUS_OBJECT_NAME_COLLISION error to the caller.
+                               // RC = Ext2RenameOrLinkFile(PtrFCB, PtrCCB, PtrFileObject,     PtrIrpContext,
+                               //                                              PtrIrp, (PFILE_RENAME_INFORMATION)PtrSystemBuffer);
+                               // Once you have completed the rename/link operation, do not
+                               // forget to notify any "notify IRPs" about the actions you have
+                               // performed.
+                               // An example is if you renamed across directories, you should
+                               // report that a new entry was added with the FILE_ACTION_ADDED
+                               // action type. The actual modification would then be reported
+                               // as either FILE_NOTIFY_CHANGE_FILE_NAME (if a file was renamed)
+                               // or FILE_NOTIFY_CHANGE_DIR_NAME (if a directory was renamed).
+                               
+                               break;
+                       default:
+                               DebugTrace(DEBUG_TRACE_FILEINFO,   "Unrecoganised SetFileInformation code for %S", PtrFCB->FCBName->ObjectName.Buffer );
+                               RC = STATUS_INVALID_PARAMETER;
+                               try_return(RC);
+                       }
+               }
+               try_exit:       NOTHING;
+       }
+       finally
+       {
+               if (PagingIoResourceAcquired) 
+               {
+                       Ext2ReleaseResource(&(PtrReqdFCB->PagingIoResource));
+                       DebugTrace(DEBUG_TRACE_MISC,  "*** FCBPaging Released [FileInfo]", 0);
+                       DebugTraceState( " FCBPaging AC:0x%LX   SW:0x%LX   EX:0x%LX   [FileInfo]", 
+                               PtrReqdFCB->PagingIoResource.ActiveCount, 
+                               PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, 
+                               PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters );
+                       if( PtrFileObject )
+                       {
+                               DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FileInfo]", PtrFileObject);
+                       }
+                       PagingIoResourceAcquired = FALSE;
+               }
+               if (MainResourceAcquired) 
+               {
+                       Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
+                       DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Released [FileInfo]", 0);
+                       DebugTraceState( " FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [FileInfo]", 
+                               PtrReqdFCB->MainResource.ActiveCount, 
+                               PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
+                               PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+                       if( PtrFileObject )
+                       {
+                               DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [FileInfo]", PtrFileObject);
+                       }
+                       
+                       MainResourceAcquired = FALSE;
+               }
+               if (VCBResourceAcquired) 
+               {
+                       Ext2ReleaseResource(&(PtrVCB->VCBResource));
+                       DebugTrace(DEBUG_TRACE_MISC,  "*** VCB Released [FileInfo]", 0);
+                       DebugTraceState( " VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [FileInfo]", 
+                               PtrVCB->VCBResource.ActiveCount, 
+                               PtrVCB->VCBResource.NumberOfExclusiveWaiters, 
+                               PtrVCB->VCBResource.NumberOfSharedWaiters );
+                       VCBResourceAcquired = FALSE;
+               }
+               // Post IRP if required
+               if (PostRequest) 
+               {
+                       // Since, the I/O Manager gave us a system buffer, we do not
+                       // need to "lock" anything.
+                       // Perform the post operation which will mark the IRP pending
+                       // and will return STATUS_PENDING back to us
+                       RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
+               } 
+               else 
+               {
+                       // Can complete the IRP here if no exception was encountered
+                       if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) {
+                               PtrIrp->IoStatus.Status = RC;
+                               // Free up the Irp Context
+                               Ext2ReleaseIrpContext(PtrIrpContext);
+       
+                               // complete the IRP
+                               IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
+                       }
+               } // can we complete the IRP ?
+       } // end of "finally" processing
+       
+       // DbgPrint( "\n        === File Info IRP returning --> RC : 0x%lX   Bytes: 0x%lX", PtrIrp->IoStatus.Status, PtrIrp->IoStatus.Information );
+       
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2GetBasicInformation()
+ *
+ * Description:
+ *     Return some time-stamps and file attributes to the caller.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS      Ext2GetBasicInformation(
+ PtrExt2FCB                                    PtrFCB,
+ PFILE_BASIC_INFORMATION               PtrBuffer,
+ long                                          *PtrReturnedLength )
+ {
+       NTSTATUS                        RC = STATUS_SUCCESS;
+       try 
+       {
+               if (*PtrReturnedLength < sizeof(FILE_BASIC_INFORMATION)) 
+               {
+                       try_return(RC = STATUS_BUFFER_OVERFLOW);
+               }
+               // Zero out the supplied buffer.
+               RtlZeroMemory(PtrBuffer, sizeof(FILE_BASIC_INFORMATION));
+               // Get information from the FCB.
+               PtrBuffer->CreationTime         = PtrFCB->CreationTime;
+               PtrBuffer->LastAccessTime       = PtrFCB->LastAccessTime;
+               PtrBuffer->LastWriteTime        = PtrFCB->LastWriteTime;
+               PtrBuffer->ChangeTime           = PtrFCB->LastWriteTime;
+               
+               // Now fill in the attributes.
+               PtrBuffer->FileAttributes = FILE_ATTRIBUTE_NORMAL;
+               if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
+               {
+                       PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+               }
+               else if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ) )
+               {
+                       //      Special File...
+                       //      Treated with respect... ;)
+                       //
+                       PtrBuffer->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY) ;
+               }
+               if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE  ) )
+               {
+                       PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+               }
+               
+               if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ) )
+               {
+                       PtrBuffer->FileAttributes |= FILE_ATTRIBUTE_READONLY;
+               }
+               
+               try_exit: NOTHING;
+       } 
+       finally 
+       {
+               if (NT_SUCCESS(RC)) 
+               {
+                       // Return the amount of information filled in.
+                       *PtrReturnedLength = sizeof(FILE_BASIC_INFORMATION);
+               }
+       }
+       return(RC);
+ }
+ NTSTATUS      Ext2GetStandardInformation(
+ PtrExt2FCB                                    PtrFCB,
+ PFILE_STANDARD_INFORMATION    PtrStdInformation,
+ long                                          *PtrReturnedLength )
+ {
+       NTSTATUS                        RC = STATUS_SUCCESS;
+       try 
+       {
+               if (*PtrReturnedLength < sizeof( FILE_STANDARD_INFORMATION )) 
+               {
+                       try_return(RC = STATUS_BUFFER_OVERFLOW);
+               }
+               // Zero out the supplied buffer.
+               RtlZeroMemory(PtrStdInformation, sizeof(FILE_STANDARD_INFORMATION));
+       
+                               
+               PtrStdInformation->AllocationSize       = PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize;
+               PtrStdInformation->EndOfFile            = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize;
+               PtrStdInformation->DeletePending        = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE);
+               PtrStdInformation->Directory            = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY );
+               PtrStdInformation->NumberOfLinks        = PtrFCB->LinkCount;
+               try_exit: NOTHING;
+       } 
+       finally 
+       {
+               if (NT_SUCCESS(RC)) 
+               {
+                       // Return the amount of information filled in.
+                       *PtrReturnedLength = sizeof( FILE_STANDARD_INFORMATION );
+               }
+       }
+       return(RC);
+ }
+ NTSTATUS Ext2GetNetworkOpenInformation(
+       PtrExt2FCB                                              PtrFCB,
+       PFILE_NETWORK_OPEN_INFORMATION  PtrNetworkOpenInformation,
+       long                                                    *PtrReturnedLength )
+ {
+       NTSTATUS                        RC = STATUS_SUCCESS;
+       try 
+       {
+               if (*PtrReturnedLength < sizeof( FILE_NETWORK_OPEN_INFORMATION )) 
+               {
+                       try_return(RC = STATUS_BUFFER_OVERFLOW);
+               }
+               // Zero out the supplied buffer.
+               RtlZeroMemory(PtrNetworkOpenInformation, sizeof(FILE_NETWORK_OPEN_INFORMATION));
+               PtrNetworkOpenInformation->CreationTime         = PtrFCB->CreationTime;
+               PtrNetworkOpenInformation->LastAccessTime       = PtrFCB->LastAccessTime;
+               PtrNetworkOpenInformation->LastWriteTime        = PtrFCB->LastWriteTime;
+               PtrNetworkOpenInformation->ChangeTime           = PtrFCB->LastWriteTime;
+               PtrNetworkOpenInformation->AllocationSize       = PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize;
+               PtrNetworkOpenInformation->EndOfFile            = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize;
+               // Now fill in the attributes.
+               PtrNetworkOpenInformation->FileAttributes = FILE_ATTRIBUTE_NORMAL;
+               if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
+               {
+                       PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+               }
+               else if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE ) )
+               {
+                       //      Special File... 
+                       //      Treated with respect... ;)
+                       //
+                       PtrNetworkOpenInformation->FileAttributes |= ( FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_READONLY) ;
+               }
+               if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE  ) )
+               {
+                       PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+               }
+               
+               if ( Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY ) )
+               {
+                       PtrNetworkOpenInformation->FileAttributes |= FILE_ATTRIBUTE_READONLY;
+               }
+               try_exit: NOTHING;
+       } 
+       finally 
+       {
+               if (NT_SUCCESS(RC)) 
+               {
+                       // Return the amount of information filled in.
+                       *PtrReturnedLength = sizeof( FILE_NETWORK_OPEN_INFORMATION );
+               }
+       }
+       return(RC);
+ }
+ NTSTATUS      Ext2GetFullNameInformation(
+       PtrExt2FCB                              PtrFCB,
+       PtrExt2CCB                              PtrCCB,
+       PFILE_NAME_INFORMATION  PtrNameInformation,
+       long                                    *PtrReturnedLength )
+ {
+       NTSTATUS                        RC = STATUS_SUCCESS;
+       try 
+       {
+               if (*PtrReturnedLength < 
+                       (long)( sizeof(FILE_NAME_INFORMATION) + PtrCCB->AbsolutePathName.Length) ) 
+               {
+                       try_return(RC = STATUS_BUFFER_OVERFLOW);
+               }
+               // Zero out the supplied buffer.
+               RtlZeroMemory(PtrNameInformation, sizeof( FILE_NAME_INFORMATION ) );
+               
+               if( PtrCCB->AbsolutePathName.Length )
+               {
+                       RtlCopyMemory(
+                               PtrNameInformation->FileName,           //      Destination,
+                               PtrCCB->AbsolutePathName.Buffer,        //      Source,
+                               PtrCCB->AbsolutePathName.Length );      //      Length
+                       PtrNameInformation->FileNameLength = PtrCCB->AbsolutePathName.Length;
+                       try_return(RC = STATUS_SUCCESS);
+               }
+               else
+               {
+                       try_return(RC = STATUS_INVALID_PARAMETER);
+               }
+               
+               try_exit: NOTHING;
+       } 
+       finally 
+       {
+               if (NT_SUCCESS(RC)) 
+               {
+                       // Return the amount of information filled in.
+                       *PtrReturnedLength =
+                               sizeof( FILE_NAME_INFORMATION ) +
+                               PtrCCB->AbsolutePathName.Length;
+               }
+       }
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2SetBasicInformation()
+ *
+ * Description:
+ *     Set some time-stamps and file attributes supplied by the caller.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS      Ext2SetBasicInformation(
+       PtrExt2IrpContext                       PtrIrpContext,
+       PtrExt2FCB                                      PtrFCB,
+       PFILE_OBJECT                            PtrFileObject,
+       PFILE_BASIC_INFORMATION         PtrFileInformation )
+ {
+       NTSTATUS                        RC = STATUS_SUCCESS;
+       PtrExt2VCB                      PtrVCB = PtrFCB->PtrVCB;
+       AssertVCB( PtrVCB );
+       
+       //      BOOLEAN                 CreationTimeChanged = FALSE;
+       //      BOOLEAN                 AttributesChanged = FALSE;
+ //    return STATUS_INVALID_PARAMETER;
+       try 
+       {
+               EXT2_INODE              Inode;
+               RtlZeroMemory(&Inode, sizeof( EXT2_INODE ));
+               if( NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
+               {
+                       //
+                       //      Update time stamps in the inode
+                       //      and in the FCB...
+                       //
+                       if( PtrFileInformation->CreationTime.QuadPart )
+                       {
+                               PtrFCB->CreationTime.QuadPart = PtrFileInformation->CreationTime.QuadPart;
+                               Inode.i_ctime = (ULONG) ( (PtrFCB->CreationTime.QuadPart
+                                               - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
+                       }
+                       if( PtrFileInformation->LastAccessTime.QuadPart )
+                       {
+                               PtrFCB->LastAccessTime.QuadPart = PtrFileInformation->LastAccessTime.QuadPart;
+                               Inode.i_atime = (ULONG) ( (PtrFCB->LastAccessTime.QuadPart
+                                               - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
+                       }
+                       if( PtrFileInformation->LastWriteTime.QuadPart )
+                       {
+                               PtrFCB->LastWriteTime.QuadPart = PtrFileInformation->LastWriteTime.QuadPart;
+                               Inode.i_mtime = (ULONG) ( (PtrFCB->LastWriteTime.QuadPart
+                                               - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
+                       }
+                       // Now come the attributes.
+                       if (PtrFileInformation->FileAttributes) 
+                       {
+                               if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_READONLY ) 
+                               {
+                                       //      Turn off the write bits...
+                                       Ext2SetModeReadOnly( Inode.i_mode );
+                               }
+                               if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_HIDDEN ) 
+                               {
+                                       //      Turn off the read and write bits...
+                                       Ext2SetModeHidden( Inode.i_mode );
+                               }
+                               if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_SYSTEM ) 
+                               {
+                                       //      Just turn off the read and write bits...
+                                       //      No special field to indicate that this is a system file...
+                                       Ext2SetModeReadOnly( Inode.i_mode );
+                                       Ext2SetModeHidden( Inode.i_mode );
+                               }
+                       }
+                       //      Updating the inode...
+                       Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode );
+               }
+       
+               if (PtrFileInformation->FileAttributes & FILE_ATTRIBUTE_TEMPORARY) 
+               {
+                       Ext2SetFlag(PtrFileObject->Flags, FO_TEMPORARY_FILE);
+               } 
+               else 
+               {
+                       Ext2ClearFlag(PtrFileObject->Flags, FO_TEMPORARY_FILE);
+               }
+               try_exit: NOTHING;
+       } 
+       finally 
+       {
+               ;
+       }
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2SetDispositionInformation()
+ *
+ * Description:
+ *     Mark/Unmark a file for deletion.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS      Ext2SetDispositionInformation(
+ PtrExt2FCB                                    PtrFCB,
+ PtrExt2CCB                                    PtrCCB,
+ PtrExt2VCB                                    PtrVCB,
+ PFILE_OBJECT                          PtrFileObject,
+ PtrExt2IrpContext                     PtrIrpContext,
+ PIRP                                                  PtrIrp,
+ PFILE_DISPOSITION_INFORMATION PtrBuffer)
+ {
+       NTSTATUS                        RC = STATUS_SUCCESS;
+       try 
+       {
+               if (!PtrBuffer->DeleteFile) 
+               {
+                       // "un-delete" the file.
+                       Ext2ClearFlag(PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE);
+                       PtrFileObject->DeletePending = FALSE;
+                       try_return(RC);
+               }
+               // Do some checking to see if the file can even be deleted.
+               if (PtrFCB->FCBFlags & EXT2_FCB_DELETE_ON_CLOSE) 
+               {
+                       // All done!
+                       try_return(RC);
+               }
+               if (PtrFCB->FCBFlags & EXT2_FCB_READ_ONLY) 
+               {
+                       try_return(RC = STATUS_CANNOT_DELETE);
+               }
+               if (PtrVCB->VCBFlags & EXT2_VCB_FLAGS_VOLUME_READ_ONLY) 
+               {
+                       try_return(RC = STATUS_CANNOT_DELETE);
+               }
+               // An important step is to check if the file stream has been
+               // mapped by any process. The delete cannot be allowed to proceed
+               // in this case.
+               if (!MmFlushImageSection(&(PtrFCB->NTRequiredFCB.SectionObject), MmFlushForDelete)) 
+               {
+                       try_return(RC = STATUS_CANNOT_DELETE);
+               }
+               // Disallow deletion of either a root
+               // directory or a directory that is not empty.
+               if( PtrFCB->INodeNo == EXT2_ROOT_INO )
+               {
+                       try_return(RC = STATUS_CANNOT_DELETE);
+               }
+               if (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY) 
+               {
+                       if (!Ext2IsDirectoryEmpty(PtrFCB, PtrCCB, PtrIrpContext)) 
+                       {
+                                       try_return(RC = STATUS_DIRECTORY_NOT_EMPTY);
+                       }
+               }
+               // Set a flag to indicate that this directory entry will become history
+               // at cleanup.
+               Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_DELETE_ON_CLOSE);
+               PtrFileObject->DeletePending = TRUE;
+               try_exit: NOTHING;
+       }
+       finally 
+       {
+               ;
+       }
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2SetAllocationInformation()
+ *
+ * Description:
+ *     Mark/Unmark a file for deletion.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS      Ext2SetAllocationInformation(
+ PtrExt2FCB                                    PtrFCB,
+ PtrExt2CCB                                    PtrCCB,
+ PtrExt2VCB                                    PtrVCB,
+ PFILE_OBJECT                          PtrFileObject,
+ PtrExt2IrpContext                     PtrIrpContext,
+ PIRP                                                  PtrIrp,
+ PFILE_ALLOCATION_INFORMATION  PtrBuffer)
+ {
+       NTSTATUS                RC = STATUS_SUCCESS;
+       BOOLEAN                 TruncatedFile = FALSE;
+       BOOLEAN                 ModifiedAllocSize = FALSE;
+       try 
+       {
+                       
+               // Are we increasing the allocation size?
+               if (RtlLargeIntegerLessThan(
+                               PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize,
+                               PtrBuffer->AllocationSize)) 
+               {
+                       ULONG CurrentSize;
+                       ULONG LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
+                       
+                       for( CurrentSize = 0; CurrentSize < PtrBuffer->AllocationSize.QuadPart; CurrentSize += LogicalBlockSize )
+                       {
+                               Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrFCB, PtrFileObject, FALSE );
+                       }
+                       ModifiedAllocSize = TRUE;
+               } 
+               else if (RtlLargeIntegerGreaterThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize,
+                                                                                                                               PtrBuffer->AllocationSize)) 
+               {
+                       // This is the painful part. See if the VMM will allow us to proceed.
+                       // The VMM will deny the request if:
+                       // (a) any image section exists OR
+                       // (b) a data section exists and the size of the user mapped view
+                       //               is greater than the new size
+                       // Otherwise, the VMM should allow the request to proceed.
+                       if (!MmCanFileBeTruncated(&(PtrFCB->NTRequiredFCB.SectionObject), &(PtrBuffer->AllocationSize))) 
+                       {
+                               // VMM said no way!
+                               try_return(RC = STATUS_USER_MAPPED_FILE);
+                       }
+                       if( !Ext2TruncateFileAllocationSize( PtrIrpContext, PtrFCB, PtrFileObject, &PtrBuffer->AllocationSize) )
+                       {
+                               //      This will do until I figure out a better error message code ;)
+                               RC = STATUS_INSUFFICIENT_RESOURCES;
+                       }
+                       ModifiedAllocSize = TRUE;
+                       TruncatedFile = TRUE;
+               }
+               try_exit:
+                       // This is a good place to check if we have performed a truncate
+                       // operation. If we have perform a truncate (whether we extended
+                       // or reduced file size), you should update file time stamps.
+                       // Last, but not the lease, you must inform the Cache Manager of file size changes.
+                       if (ModifiedAllocSize && NT_SUCCESS(RC)) 
+                       {
+                               // Update the FCB Header with the new allocation size.
+                               PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize = PtrBuffer->AllocationSize;
+                               // If we decreased the allocation size to less than the
+                               // current file size, modify the file size value.
+                               // Similarly, if we decreased the value to less than the
+                               // current valid data length, modify that value as well.
+                               if (TruncatedFile) 
+                               {
+                                       if (RtlLargeIntegerLessThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize, PtrBuffer->AllocationSize)) 
+                                       {
+                                               // Decrease the file size value.
+                                               PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize = PtrBuffer->AllocationSize;
+                                       }
+                                       if (RtlLargeIntegerLessThan(PtrFCB->NTRequiredFCB.CommonFCBHeader.ValidDataLength, PtrBuffer->AllocationSize)) 
+                                       {
+                                               // Decrease the valid data length value.
+                                               PtrFCB->NTRequiredFCB.CommonFCBHeader.ValidDataLength = PtrBuffer->AllocationSize;
+                                       }
+                               }
+                               // If the FCB has not had caching initiated, it is still valid
+                               // for you to invoke the NT Cache Manager. It is possible in such
+                               // situations for the call to be no'oped (unless some user has
+                               // mapped in the file)
+                               // NOTE: The invocation to CcSetFileSizes() will quite possibly
+                               //      result in a recursive call back into the file system.
+                               //      This is because the NT Cache Manager will typically
+                               //      perform a flush before telling the VMM to purge pages
+                               //      especially when caching has not been initiated on the
+                               //      file stream, but the user has mapped the file into
+                               //      the process' virtual address space.
+                               CcSetFileSizes(PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
+                               // Inform any pending IRPs (notify change directory).
+                       }
+       } 
+       finally 
+       {
+               ;
+       }
+       return(RC);
+ }
index 0000000,fd25fa3..fd25fa3
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,350 +1,350 @@@
+ /*************************************************************************
+ *
+ * File: flush.c
+ *
+ * Module: Ext2 File System Driver (Kernel mode execution only)
+ *
+ * Description:
+ *     Contains code to handle the "Flush Buffers" dispatch entry point.
+ *
+ * Author: Manoj Paul Joseph
+ *
+ *
+ *************************************************************************/
+ #include                      "ext2fsd.h"
+ // define the file specific bug-check id
+ #define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_FLUSH
+ #define                       DEBUG_LEVEL                                             (DEBUG_TRACE_FLUSH)
+ /*************************************************************************
+ *
+ * Function: Ext2Flush()
+ *
+ * Description:
+ *     The I/O Manager will invoke this routine to handle a flush buffers
+ *     request
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
+ *     to be deferred to a worker thread context)
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS Ext2Flush(
+       PDEVICE_OBJECT          DeviceObject,           //      the logical volume device object
+       PIRP                            Irp)                            //      I/O Request Packet
+ {
+       NTSTATUS                        RC = STATUS_SUCCESS;
+       PtrExt2IrpContext       PtrIrpContext = NULL;
+       BOOLEAN                         AreWeTopLevel = FALSE;
+       DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "Flush IRP Received...", 0);
+       
+       // Ext2BreakPoint();
+       FsRtlEnterFileSystem();
+       ASSERT(DeviceObject);
+       ASSERT(Irp);
+       // set the top level context
+       AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
+       try 
+       {
+               // get an IRP context structure and issue the request
+               PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
+               ASSERT(PtrIrpContext);
+               RC = Ext2CommonFlush(PtrIrpContext, Irp);
+       } except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) {
+               RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
+               Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
+       }
+       if (AreWeTopLevel) {
+               IoSetTopLevelIrp(NULL);
+       }
+       FsRtlExitFileSystem();
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2CommonFlush()
+ *
+ * Description:
+ *     The actual work is performed here. This routine may be invoked in one'
+ *     of the two possible contexts:
+ *     (a) in the context of a system worker thread
+ *     (b) in the context of the original caller
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS      Ext2CommonFlush(
+ PtrExt2IrpContext                     PtrIrpContext,
+ PIRP                                                  PtrIrp)
+ {
+       NTSTATUS                                        RC = STATUS_SUCCESS;
+       PIO_STACK_LOCATION      PtrIoStackLocation = NULL;
+       PFILE_OBJECT                    PtrFileObject = NULL;
+       PtrExt2FCB                              PtrFCB = NULL;
+       PtrExt2CCB                              PtrCCB = NULL;
+       PtrExt2VCB                              PtrVCB = NULL;
+       PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
+       BOOLEAN                                 AcquiredFCB = FALSE;
+       BOOLEAN                                 PostRequest = FALSE;
+       BOOLEAN                                 CanWait = TRUE;
+       try {
+               // First, get a pointer to the current I/O stack location
+               PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
+               ASSERT(PtrIoStackLocation);
+               PtrFileObject = PtrIoStackLocation->FileObject;
+               ASSERT(PtrFileObject);
+               // Get the FCB and CCB pointers
+               PtrCCB = (PtrExt2CCB)(PtrFileObject->FsContext2);
+               ASSERT(PtrCCB);
+               PtrFCB = PtrCCB->PtrFCB;
+               AssertFCB( PtrFCB );
+               /*ASSERT(PtrFCB);
+               ASSERT(PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB );*/
+               PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
+               // Get some of the parameters supplied to us
+               CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
+               // If we cannot wait, post the request immediately since a flush is inherently blocking/synchronous.
+               if (!CanWait) {
+                       PostRequest = TRUE;
+                       try_return(RC);
+               }
+               // Check the type of object passed-in. That will determine the course of
+               // action we take.
+               if ((PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) || (PtrFCB->FCBFlags & EXT2_FCB_ROOT_DIRECTORY)) {
+                       if (PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) {
+                               PtrVCB = (PtrExt2VCB)(PtrFCB);
+                       } else {
+                               PtrVCB = PtrFCB->PtrVCB;
+                       }
+                       // The caller wishes to flush all files for the mounted
+                       // logical volume. The flush volume routine below should simply
+                       // walk through all of the open file streams, acquire the
+                       // FCB resource, and request the flush operation from the Cache
+                       // Manager. Basically, the sequence of operations listed below
+                       // for a single file should be executed on all open files.
+                       Ext2FlushLogicalVolume(PtrIrpContext, PtrIrp, PtrVCB);
+                       try_return(RC);
+               }
+               if (!(PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY)) 
+               {
+                       // This is a regular file.
+                       ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), TRUE);
+                       AcquiredFCB = TRUE;
+                       // Request the Cache Manager to perform a flush operation.
+                       // Further, instruct the Cache Manager that we wish to flush the
+                       // entire file stream.
+                       Ext2FlushAFile(PtrReqdFCB, &(PtrIrp->IoStatus));
+                       RC = PtrIrp->IoStatus.Status;
+                       // All done. You may want to also flush the directory entry for the
+                       // file stream at this time.
+                       // Some log-based FSD implementations may wish to flush their
+                       // log files at this time. Finally, you should update the time-stamp
+                       // values for the file stream appropriately. This would involve
+                       // obtaining the current time and modifying the appropriate directory
+                       // entry fields.
+               }
+               try_exit:
+               if (AcquiredFCB) 
+               {
+                       Ext2ReleaseResource(&(PtrReqdFCB->MainResource));
+                       DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Released [Flush]", 0);
+                       DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [Flush]", 
+                               PtrReqdFCB->MainResource.ActiveCount, 
+                               PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, 
+                               PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+                       AcquiredFCB = FALSE;
+               }
+               if (!PostRequest) 
+               {
+                       PIO_STACK_LOCATION              PtrNextIoStackLocation = NULL;
+                       NTSTATUS                                                RC1 = STATUS_SUCCESS;
+                       // Send the request down at this point.
+                       // To do this, you must set the next IRP stack location, and
+                       // maybe set a completion routine.
+                       // Be careful about marking the IRP pending if the lower level
+                       // driver returned pending and you do have a completion routine!
+                       PtrNextIoStackLocation = IoGetNextIrpStackLocation(PtrIrp);
+                       *PtrNextIoStackLocation = *PtrIoStackLocation;
+                       // Set the completion routine to "eat-up" any
+                       // STATUS_INVALID_DEVICE_REQUEST error code returned by the lower
+                       // level driver.
+                       IoSetCompletionRoutine(PtrIrp, Ext2FlushCompletion, NULL, TRUE, TRUE, TRUE);
+                       /*
+                        * The exception handlers propably masked out the
+                        * fact that PtrVCB was never set.
+                        * -- Filip Navara, 18/08/2004
+                        */
+                       PtrVCB = PtrFCB->PtrVCB;
+                       RC1 = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp);
+                       RC = ((RC1 == STATUS_INVALID_DEVICE_REQUEST) ? RC : RC1);
+               }
+       } finally {
+               if (PostRequest) {
+                       // Nothing to lock now.
+                       RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
+               } else {
+                       // Release the IRP context at this time.
+                       Ext2ReleaseIrpContext(PtrIrpContext);
+               }
+       }
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2FlushAFile()
+ *
+ * Description:
+ *     Tell the Cache Manager to perform a flush.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2FlushAFile(
+ PtrExt2NTRequiredFCB  PtrReqdFCB,
+ PIO_STATUS_BLOCK              PtrIoStatus)
+ {
+       CcFlushCache(&(PtrReqdFCB->SectionObject), NULL, 0, PtrIoStatus);
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2FlushLogicalVolume()
+ *
+ * Description:
+ *     Flush everything beginning at root directory.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2FlushLogicalVolume(
+ PtrExt2IrpContext                     PtrIrpContext,
+ PIRP                                                  PtrIrp,
+ PtrExt2VCB                                    PtrVCB)
+ {
+       BOOLEAN                 AcquiredVCB = FALSE;
+       PtrExt2FCB              PtrFCB = NULL;
+       PLIST_ENTRY             PtrNextFCB = NULL;
+       try {
+               ExAcquireResourceExclusiveLite(&(PtrVCB->VCBResource), TRUE);
+               AcquiredVCB = TRUE;
+               DebugTrace(DEBUG_TRACE_MISC,   "*** VCB Acquired Ex [Flush] ", 0);
+               // Go through the list of FCB's. You would probably
+               // flush all of the files. Then, you could flush the
+               // directories that you may have have pinned into memory.
+               // NOTE: This function may also be invoked internally as part of
+               // processing a shutdown request.
+       } 
+       finally 
+       {
+               if (AcquiredVCB) 
+               {
+                       Ext2ReleaseResource(&(PtrVCB->VCBResource));
+                       DebugTrace(DEBUG_TRACE_MISC,  "*** VCB Released [Flush]", 0);
+                       DebugTraceState( "VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Flush]", 
+                               PtrVCB->VCBResource.ActiveCount, 
+                               PtrVCB->VCBResource.NumberOfExclusiveWaiters, 
+                               PtrVCB->VCBResource.NumberOfSharedWaiters );
+               }
+       }
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2FlushCompletion()
+ *
+ * Description:
+ *     Eat up any bad errors.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ NTSTATUS Ext2FlushCompletion(
+ PDEVICE_OBJECT        PtrDeviceObject,
+ PIRP                          PtrIrp,
+ PVOID                         Context)
+ {
+       NTSTATUS                RC = STATUS_SUCCESS;
+       if (PtrIrp->PendingReturned) {
+               IoMarkIrpPending(PtrIrp);
+       }
+       if (PtrIrp->IoStatus.Status == STATUS_INVALID_DEVICE_REQUEST) {
+               // cannot do much here, can we?
+               PtrIrp->IoStatus.Status = STATUS_SUCCESS;
+       }
+       return(STATUS_SUCCESS);
+ }
index 0000000,0000000..b25eed3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,944 @@@
++/*************************************************************************
++*
++* File: fsctrl.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Contains code to handle the various File System Control calls.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++
++
++#include "ext2fsd.h"
++
++
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_FILE_CONTROL
++#define                       DEBUG_LEVEL                                             (DEBUG_TRACE_FSCTRL)
++
++
++NTSTATUS
++Ext2MountVolume(
++      IN PIRP Irp,
++      IN PIO_STACK_LOCATION IrpSp );
++
++NTSTATUS
++Ext2GetPartitionInfo(
++    IN PDEVICE_OBJECT TargetDeviceObject,
++    IN PPARTITION_INFORMATION PartitionInformation
++    );
++
++NTSTATUS
++Ext2GetDriveLayout(
++    IN PDEVICE_OBJECT TargetDeviceObject,
++    IN PDRIVE_LAYOUT_INFORMATION DriveLayoutInformation,
++      IN int BufferSize
++    );
++
++BOOLEAN
++Ext2PerformVerifyDiskRead(
++    IN PDEVICE_OBJECT TargetDeviceObject,
++    IN PVOID Buffer,
++    IN LONGLONG Lbo,
++    IN ULONG NumberOfBytesToRead
++    );
++
++NTSTATUS Ext2UserFileSystemRequest( 
++      IN PIRP Irp,
++      IN PIO_STACK_LOCATION IrpSp );
++
++
++/*************************************************************************
++*
++* Function: Ext2FileSystemControl
++*
++* Description:
++*     The I/O Manager will invoke this routine to handle a 
++*   File System Control IRP
++*
++* Expected Interrupt Level (for execution) :
++*  
++*     ???
++*
++* Arguments:
++*
++*    DeviceObject - Supplies the volume device object where the
++*                   file exists
++*
++*    Irp - Supplies the Irp being processed
++*
++*
++* Return Value:
++*
++*    NTSTATUS - The FSD status for the IRP
++*
++*************************************************************************/
++NTSTATUS 
++Ext2FileSystemControl(
++    IN PDEVICE_OBJECT DeviceObject,
++    IN PIRP Irp
++    )
++{
++  
++    NTSTATUS Status = STATUS_SUCCESS;
++      PIO_STACK_LOCATION IrpSp;
++    
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "File System Control IRP Received...", 0);
++              
++      //      Ext2BreakPoint();
++
++      FsRtlEnterFileSystem();
++
++      ASSERT(DeviceObject);
++      ASSERT(Irp);
++
++      //
++    //  Get a pointer to the current Irp stack location
++    //
++    IrpSp = IoGetCurrentIrpStackLocation( Irp );
++      
++
++      if( IrpSp->MinorFunction == IRP_MN_MOUNT_VOLUME )
++      {
++              DebugTrace(DEBUG_TRACE_MOUNT,   "Mount Request Received...", 0);
++              Status = Ext2MountVolume ( Irp, IrpSp );
++              Ext2CompleteRequest( Irp, Status );
++      }
++      else if( IrpSp->MinorFunction == IRP_MN_USER_FS_REQUEST )
++      {
++              DebugTrace(DEBUG_TRACE_FSCTRL,   "IRP_MN_USER_FS_REQUEST received...", 0);
++              Status = Ext2UserFileSystemRequest( Irp, IrpSp );
++              Ext2CompleteRequest( Irp, Status );
++      }
++      else 
++      {
++              if( IrpSp->MinorFunction == IRP_MN_VERIFY_VOLUME )
++              {
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   "IRP_MN_VERIFY_VOLUME received...", 0);
++              }
++              else if( IrpSp->MinorFunction == IRP_MN_LOAD_FILE_SYSTEM )
++              {
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   "IRP_MN_LOAD_FILE_SYSTEM received...", 0);
++              }
++              else
++              {
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   "Unknown Minor IRP code received...", 0);
++              }
++
++              Status = STATUS_INVALID_DEVICE_REQUEST;
++              Ext2CompleteRequest( Irp, Status );
++      }
++      
++      FsRtlExitFileSystem();
++
++    return Status;
++}
++
++
++
++/*************************************************************************
++*
++* Function: Ext2MountVolume()
++*
++* Description:
++*     This routine verifies and mounts the volume; 
++*     Called by FSCTRL IRP handler to attempt a 
++*             volume mount.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL 
++*
++*
++* Arguments:
++*
++*    Irp - Supplies the Irp being processed
++*      IrpSp - Irp Stack Location pointer
++*
++* Return Value: 
++*
++*   NTSTATUS - The Mount status
++*
++*************************************************************************/
++NTSTATUS
++Ext2MountVolume ( 
++      IN PIRP Irp,
++      IN PIO_STACK_LOCATION IrpSp )
++{
++      
++      //      Volume Parameter Block
++      PVPB PtrVPB;
++
++      //      The target device object
++      PDEVICE_OBJECT TargetDeviceObject = NULL;
++
++      // The new volume device object (to be created if partition is Ext2)
++      PDEVICE_OBJECT PtrVolumeDeviceObject = NULL;
++      
++      //      Return Status
++      NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME;
++
++      // Number of bytes to read for Volume verification...
++      unsigned long NumberOfBytesToRead = 0;
++      
++      //      Starting Offset for 'read'
++      LONGLONG StartingOffset = 0;
++
++      //      Boot Sector information...
++      PPACKED_BOOT_SECTOR BootSector = NULL;
++      
++      //      Ext2 Super Block information...
++      PEXT2_SUPER_BLOCK SuperBlock = NULL;
++
++      //      Volume Control Block
++      PtrExt2VCB                      PtrVCB = NULL;
++
++      //      The File Object for the root directory
++      PFILE_OBJECT PtrRootFileObject = NULL;
++      
++      //      Flag
++      int WeClearedVerifyRequiredBit;
++      
++      //      Used by a for loop...
++      unsigned int i;
++      
++      //      
++      LARGE_INTEGER VolumeByteOffset;
++
++      unsigned long LogicalBlockSize = 0;
++
++      //      Buffer Control Block
++      PBCB PtrBCB = NULL;
++                      
++      //      Cache Buffer - used for pinned access of volume...
++      PVOID PtrCacheBuffer = NULL;
++      
++      PEXT2_GROUP_DESCRIPTOR  PtrGroupDescriptor = NULL;
++
++      PEXT2_INODE                     PtrInode = NULL;
++
++      // Inititalising variables
++      
++      PtrVPB = IrpSp->Parameters.MountVolume.Vpb;
++      TargetDeviceObject = IrpSp->Parameters.MountVolume.DeviceObject;
++      
++      try
++      {
++              //
++              //      1. Reading in Volume meta data
++              //
++
++              //      Temporarily clear the DO_VERIFY_VOLUME Flag
++              WeClearedVerifyRequiredBit = 0;
++              if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) ) 
++              {
++            Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME );
++            WeClearedVerifyRequiredBit = 1;
++        }
++
++              //      Allocating memory for reading in Boot Sector...
++              NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), TargetDeviceObject->SectorSize );
++              BootSector = Ext2AllocatePool( PagedPool, NumberOfBytesToRead  );
++              RtlZeroMemory( BootSector, NumberOfBytesToRead );
++
++              //      Reading in Boot Sector
++              StartingOffset = 0L;
++              Ext2PerformVerifyDiskRead ( TargetDeviceObject,
++                      BootSector, StartingOffset, NumberOfBytesToRead );
++
++              //      Allocating memory for reading in Super Block...
++              
++              SuperBlock = Ext2AllocatePool( PagedPool, NumberOfBytesToRead  );
++              RtlZeroMemory( SuperBlock, NumberOfBytesToRead );
++              StartingOffset = 1024;
++
++              //      Reading in the Super Block...
++              Ext2PerformVerifyDiskRead ( TargetDeviceObject,
++                      SuperBlock, StartingOffset, NumberOfBytesToRead );
++
++              //      Resetting the DO_VERIFY_VOLUME Flag
++              if( WeClearedVerifyRequiredBit ) 
++              {
++                      PtrVPB->RealDevice->Flags |= DO_VERIFY_VOLUME;
++              }
++
++              // Verifying the Super Block..
++              if( SuperBlock->s_magic == EXT2_SUPER_MAGIC )
++              {
++                      //
++                      //      Found a valid super block.
++                      //      No more tests for now.
++                      //      Assuming that this is an ext2 partition...
++                      //      Going ahead with mount.
++                      //
++                      DebugTrace(DEBUG_TRACE_MOUNT,   "Valid Ext2 partition detected\nMounting %s...", SuperBlock->s_volume_name);
++                      //
++                      //      2. Creating a volume device object
++                      //
++              if (!NT_SUCCESS( IoCreateDevice( 
++                                      Ext2GlobalData.Ext2DriverObject,        //      (This) Driver object
++                                      Ext2QuadAlign( sizeof(Ext2VCB) ),       //      Device Extension
++                    NULL,                                                             //      Device Name - no name ;)
++                    FILE_DEVICE_DISK_FILE_SYSTEM,             //      Disk File System
++                    0,                                                                        //      DeviceCharacteristics
++                    FALSE,                                                            //      Not an exclusive device
++                    (PDEVICE_OBJECT *)&PtrVolumeDeviceObject)) //     The Volume Device Object
++                                      ) 
++                      {
++                  try_return( Status );
++                      }
++
++                      //      
++                      //  Our alignment requirement is the larger of the processor alignment requirement
++                      //  already in the volume device object and that in the TargetDeviceObject
++                      //
++
++                      if (TargetDeviceObject->AlignmentRequirement > PtrVolumeDeviceObject->AlignmentRequirement) 
++                      {
++                              PtrVolumeDeviceObject->AlignmentRequirement = TargetDeviceObject->AlignmentRequirement;
++                      }
++                      
++                      //
++                      //      Clearing the Device Initialising Flag
++                      //
++                      Ext2ClearFlag( PtrVolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING);
++
++
++                      //
++                      //      Setting the Stack Size for the newly created Volume Device Object
++                      //
++                      PtrVolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1);
++                      
++
++                      //
++                      //      3. Creating the link between Target Device Object 
++                      //      and the Volume Device Object via the Volume Parameter Block
++                      //
++                      PtrVPB->DeviceObject = PtrVolumeDeviceObject;
++                      
++                      //      Remembring the Volume parameters in the VPB bock
++                      for( i = 0; i < 16 ; i++ )
++                      {
++                              PtrVPB->VolumeLabel[i] = SuperBlock->s_volume_name[i];
++                              if( SuperBlock->s_volume_name[i] == 0 )
++                                      break;
++                      }
++                      PtrVPB->VolumeLabelLength = i * 2;
++                      PtrVPB->SerialNumber = ((ULONG*)SuperBlock->s_uuid)[0];
++                              
++                      //
++                      //      4. Initialise the Volume Comtrol Block
++                      //
++                      {
++                              LARGE_INTEGER AllocationSize;
++
++                              AllocationSize .QuadPart = 
++                                      ( EXT2_MIN_BLOCK_SIZE << SuperBlock->s_log_block_size ) * 
++                                      SuperBlock->s_blocks_count;
++
++                              Ext2InitializeVCB(
++                                      PtrVolumeDeviceObject, 
++                                      TargetDeviceObject,
++                                      PtrVPB,
++                                      &AllocationSize);
++                              PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension);
++                              ASSERT( PtrVCB );
++                      }
++
++                      PtrVCB->InodesCount = SuperBlock->s_inodes_count;
++                      PtrVCB->BlocksCount = SuperBlock->s_blocks_count;
++                      PtrVCB->ReservedBlocksCount = SuperBlock->s_r_blocks_count;
++                      PtrVCB->FreeBlocksCount = SuperBlock->s_free_blocks_count;
++                      PtrVCB->FreeInodesCount = SuperBlock->s_free_inodes_count;
++                      PtrVCB->LogBlockSize = SuperBlock->s_log_block_size;
++                      PtrVCB->InodesPerGroup = SuperBlock->s_inodes_per_group;
++                      PtrVCB->BlocksPerGroup = SuperBlock->s_blocks_per_group;
++                      PtrVCB->NoOfGroups = ( SuperBlock->s_blocks_count - SuperBlock->s_first_data_block 
++                                                              + SuperBlock->s_blocks_per_group - 1 ) 
++                                                              / SuperBlock->s_blocks_per_group;
++
++                      PtrVCB->PtrGroupDescriptors = Ext2AllocatePool( NonPagedPool, sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups  );
++                      
++                      RtlZeroMemory( PtrVCB->PtrGroupDescriptors , sizeof( Ext2GroupDescriptors ) * PtrVCB->NoOfGroups );
++
++                      //
++                      //      Attempting to Read in some matadata from the Cache...
++                      //      using pin access...
++                      //
++                      LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++      
++                      //
++                      //      Reading Group Descriptors...
++                      //
++                      if( PtrVCB->LogBlockSize )
++                      {
++                              //      First block contains the descriptors...
++                              VolumeByteOffset.QuadPart = LogicalBlockSize;
++                      }
++                      else
++                      {
++                              //      Second block contains the descriptors...
++                              VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
++                      }
++
++                      NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
++                      NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
++
++                      if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                   &VolumeByteOffset,
++                   NumberOfBytesToRead,
++                   TRUE,
++                   &PtrBCB,
++                   &PtrCacheBuffer )) 
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                              try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
++                      }
++                      else
++                      {
++                              //      
++                              //      Saving up Often Used Group Descriptor Information in the VCB...
++                              //
++                              unsigned int DescIndex ;
++
++                              DebugTrace(DEBUG_TRACE_MISC,   "Cache hit while reading in volume meta data", 0);
++                              PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer;
++                              for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ )
++                              {
++                                      PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock 
++                                              = PtrGroupDescriptor[ DescIndex ].bg_inode_table;
++
++                                      PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock 
++                                              = PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap
++                                              ;
++                                      PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock 
++                                              = PtrGroupDescriptor[ DescIndex ].bg_block_bitmap
++                                              ;
++                                      PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount 
++                                              = PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count;
++
++                                      PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount 
++                                              = PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count;
++                              }
++                              CcUnpinData( PtrBCB );
++                              PtrBCB = NULL;
++                      }
++
++                      //
++                      //      5. Creating a Root Directory FCB
++                      //
++                      PtrRootFileObject = IoCreateStreamFileObject(NULL, TargetDeviceObject );
++                      if( !PtrRootFileObject )
++                      {
++                              try_return( Status );
++                      }
++                      //
++                      //      Associate the file stream with the Volume parameter block...
++                      //      I do it now
++                      //
++                      PtrRootFileObject->Vpb = PtrVCB->PtrVPB;
++
++                      PtrRootFileObject->ReadAccess = TRUE;
++                      PtrRootFileObject->WriteAccess = TRUE;
++
++                      {
++                              PtrExt2ObjectName               PtrObjectName;
++                              LARGE_INTEGER ZeroSize;
++
++                              PtrObjectName = Ext2AllocateObjectName();
++                              RtlInitUnicodeString( &PtrObjectName->ObjectName, L"\\" );
++                              Ext2CopyWideCharToUnicodeString( &PtrObjectName->ObjectName, L"\\" );
++
++
++                              ZeroSize.QuadPart = 0;
++                              if ( !NT_SUCCESS( Ext2CreateNewFCB( 
++                                              &PtrVCB->PtrRootDirectoryFCB,   //      Root FCB
++                                              ZeroSize,                                               //      AllocationSize,
++                                              ZeroSize,                                               //      EndOfFile,
++                                              PtrRootFileObject,                              //      The Root Dircetory File Object
++                                              PtrVCB,
++                                              PtrObjectName  )  )  )
++                              {
++                                      try_return( Status );
++                              }
++                              
++
++                              PtrVCB->PtrRootDirectoryFCB->FCBFlags |= EXT2_FCB_DIRECTORY | EXT2_FCB_ROOT_DIRECTORY;
++
++
++                      }
++
++                      PtrVCB->PtrRootDirectoryFCB->DcbFcb.Dcb.PtrDirFileObject = PtrRootFileObject;
++                      PtrVCB->PtrRootDirectoryFCB->INodeNo = EXT2_ROOT_INO;
++                      PtrRootFileObject->SectionObjectPointer = &(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.SectionObject);
++                      RtlInitUnicodeString( &PtrRootFileObject->FileName, L"\\" );
++
++                      Ext2InitializeFCBInodeInfo( PtrVCB->PtrRootDirectoryFCB );
++
++                      //      
++                      //      Initiating caching for root directory...
++                      //
++
++                      CcInitializeCacheMap(PtrRootFileObject, 
++                              (PCC_FILE_SIZES)(&(PtrVCB->PtrRootDirectoryFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
++                              TRUE,           // We will utilize pin access for directories
++                              &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
++                              PtrVCB->PtrRootDirectoryFCB );          // The context used in callbacks
++
++
++                      //
++                      //      6. Update the VCB Flags
++                      //
++                      PtrVCB->VCBFlags |= EXT2_VCB_FLAGS_VOLUME_MOUNTED ;     //      | EXT2_VCB_FLAGS_VOLUME_READ_ONLY;
++
++
++                      //
++                      //      7. Mount Success
++                      //
++                      Status = STATUS_SUCCESS;
++                      
++                      {
++                              //
++                              //      This block is for testing....
++                              //      To be removed...
++
++                              /*
++                              EXT2_INODE      Inode ;
++                              Ext2ReadInode( PtrVCB, 100, &Inode );
++                              DebugTrace( DEBUG_TRACE_MISC, "Inode size= %lX [FS Ctrl]", Inode.i_size );
++                              Ext2DeallocInode( NULL, PtrVCB, 0xfb6 );
++                              */
++                      }
++                      
++                      //       ObDereferenceObject( TargetDeviceObject );
++              }
++              else
++              {
++                      DebugTrace(DEBUG_TRACE_MOUNT,   "Failing mount. Partition not Ext2...", 0);
++              }
++
++              try_exit: NOTHING;
++      }
++      finally 
++      {
++              //      Freeing Allocated Memory...
++              if( SuperBlock != NULL )
++              {
++                      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [FS Ctrl]", SuperBlock );
++                      ExFreePool( SuperBlock );
++              }
++              if( BootSector != NULL )
++              {
++                      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [FS Ctrl]", BootSector);
++                      ExFreePool( BootSector );
++              }
++
++              // start unwinding if we were unsuccessful
++              if (!NT_SUCCESS( Status )) 
++              {
++                                              
++              }
++      }
++      
++      return Status;
++}
++
++/*************************************************************************
++*
++* Function: Ext2MountVolume()
++*
++* Description:
++*     This routine is used for querying the partition information.
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++* Arguments:
++*
++*     TargetDeviceObject - The target of the query
++*     PartitionInformation - Receives the result of the query
++*
++* Return Value:
++*
++*     NTSTATUS - The return status for the operation
++*
++*************************************************************************/
++NTSTATUS
++Ext2GetPartitionInfo (
++    IN PDEVICE_OBJECT TargetDeviceObject,
++    IN PPARTITION_INFORMATION PartitionInformation
++    )
++{
++    PIRP Irp;
++    KEVENT *PtrEvent = NULL;
++    NTSTATUS Status;
++    IO_STATUS_BLOCK Iosb;
++
++    //
++    //  Query the partition table
++    //
++      PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) )  );
++      
++
++
++
++    KeInitializeEvent( PtrEvent, NotificationEvent, FALSE );
++      
++    Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_PARTITION_INFO,
++                                         TargetDeviceObject,
++                                         NULL,
++                                         0,
++                                         PartitionInformation,
++                                         sizeof(PARTITION_INFORMATION),
++                                         FALSE,
++                                         PtrEvent,
++                                         &Iosb );
++
++    if ( Irp == NULL ) 
++      {
++              DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [FS Ctrl]", PtrEvent);
++              ExFreePool( PtrEvent );
++              return 0;
++    }
++
++    Status = IoCallDriver( TargetDeviceObject, Irp );
++
++    if ( Status == STATUS_PENDING ) {
++
++        (VOID) KeWaitForSingleObject( PtrEvent,
++                                      Executive,
++                                      KernelMode,
++                                      FALSE,
++                                      (PLARGE_INTEGER)NULL );
++
++        Status = Iosb.Status;
++    }
++      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [FS Ctrl]", PtrEvent);
++      ExFreePool( PtrEvent );
++    return Status;
++}
++
++/*************************************************************************
++*
++* Function: Ext2MountVolume()
++*
++* Description:
++*     This routine is used for querying the Drive Layout Information.
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++* Arguments:
++*
++*     TargetDeviceObject - The target of the query
++*     PartitionInformation - Receives the result of the query
++*
++* Return Value:
++*
++*     NTSTATUS - The return status for the operation
++*
++*************************************************************************/
++NTSTATUS Ext2GetDriveLayout (
++    IN PDEVICE_OBJECT TargetDeviceObject,
++    IN PDRIVE_LAYOUT_INFORMATION DriveLayoutInformation,
++      IN int BufferSize
++    )
++{
++    PIRP Irp;
++    KEVENT *PtrEvent = NULL;
++    NTSTATUS Status;
++    IO_STATUS_BLOCK Iosb;
++
++    //
++    //  Query the partition table
++    //
++      PtrEvent = ( KEVENT * )Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof( KEVENT ) )  );
++    KeInitializeEvent( PtrEvent, NotificationEvent, FALSE );
++    Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_GET_DRIVE_LAYOUT,
++                                         TargetDeviceObject,
++                                         NULL,
++                                         0,
++                                         DriveLayoutInformation,
++                                         BufferSize,
++                                         FALSE,
++                                         PtrEvent,
++                                         &Iosb );
++
++    if ( Irp == NULL ) 
++      {
++              DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [FS Ctrl]", PtrEvent);
++              ExFreePool( PtrEvent );
++              return 0;
++    }
++
++    Status = IoCallDriver( TargetDeviceObject, Irp );
++
++    if ( Status == STATUS_PENDING ) {
++
++        (VOID) KeWaitForSingleObject( PtrEvent,
++                                      Executive,
++                                      KernelMode,
++                                      FALSE,
++                                      (PLARGE_INTEGER)NULL );
++
++        Status = Iosb.Status;
++    }
++      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [FS Ctrl]", PtrEvent);
++      ExFreePool( PtrEvent );
++    return Status;
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2MountVolume()
++*
++* Description:
++*     This routine is used for performing a verify read...
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++* Arguments:
++*     TargetDeviceObject - The target of the query
++*     PartitionInformation - Receives the result of the query
++*
++* Return Value:
++*     NTSTATUS - The return status for the operation
++*
++*************************************************************************/
++BOOLEAN Ext2PerformVerifyDiskRead(
++    IN PDEVICE_OBJECT TargetDeviceObject,
++    IN PVOID Buffer,
++    IN LONGLONG Lbo,
++    IN ULONG NumberOfBytesToRead )
++{
++    KEVENT Event;
++    PIRP Irp;
++    LARGE_INTEGER ByteOffset;
++    NTSTATUS Status;
++    IO_STATUS_BLOCK Iosb;
++
++    //
++    //  Initialize the event we're going to use
++    //
++    KeInitializeEvent( &Event, NotificationEvent, FALSE );
++
++    //
++    //  Build the irp for the operation
++    //
++    ByteOffset.QuadPart = Lbo;
++    Irp = IoBuildSynchronousFsdRequest( IRP_MJ_READ,
++                                        TargetDeviceObject,
++                                        Buffer,
++                                        NumberOfBytesToRead,
++                                        &ByteOffset,
++                                        &Event,
++                                        &Iosb );
++
++    if ( Irp == NULL ) 
++      {
++        Status = FALSE;
++    }
++
++    Ext2SetFlag( IoGetNextIrpStackLocation( Irp )->Flags, SL_OVERRIDE_VERIFY_VOLUME );
++
++    //
++    //  Call the device to do the read and wait for it to finish.
++    //
++    Status = IoCallDriver( TargetDeviceObject, Irp );
++    if (Status == STATUS_PENDING) 
++      {
++        (VOID)KeWaitForSingleObject( &Event, Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
++        Status = Iosb.Status;
++    }
++
++    ASSERT(Status != STATUS_VERIFY_REQUIRED);
++
++    //
++    //  Special case this error code because this probably means we used
++    //  the wrong sector size and we want to reject STATUS_WRONG_VOLUME.
++    //
++
++    if (Status == STATUS_INVALID_PARAMETER) 
++      {
++
++        return FALSE;
++    }
++
++    //
++    //  If it doesn't succeed then either return or raise the error.
++    //
++
++    if (!NT_SUCCESS(Status)) 
++      {
++            return FALSE;
++    }
++
++    //
++    //  And return to our caller
++    //
++    return TRUE;
++}
++
++/*************************************************************************
++*
++* Function: Ext2UserFileSystemRequest()
++*
++* Description:
++*     This routine handles User File System Requests
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL 
++*
++*
++* Arguments:
++*
++*    Irp - Supplies the Irp being processed
++*      IrpSp - Irp Stack Location pointer
++*
++* Return Value: NT_STATUS
++*
++*************************************************************************/
++NTSTATUS Ext2UserFileSystemRequest ( 
++      IN PIRP Irp,
++      IN PIO_STACK_LOCATION IrpSp )
++{
++    NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
++      ULONG FsControlCode;
++
++      IrpSp = IoGetCurrentIrpStackLocation( Irp );
++      
++      try
++      {
++#ifdef _GNU_NTIFS_
++              FsControlCode = ((PEXTENDED_IO_STACK_LOCATION)IrpSp)->Parameters.FileSystemControl.FsControlCode;
++#else
++              FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
++#endif
++
++              switch ( FsControlCode ) 
++              {
++
++              case FSCTL_REQUEST_OPLOCK_LEVEL_1:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   "FSCTL_REQUEST_OPLOCK_LEVEL_1", 0);
++                      break;
++              case FSCTL_REQUEST_OPLOCK_LEVEL_2:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL ", 0);
++                      break;
++              case FSCTL_REQUEST_BATCH_OPLOCK:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_REQUEST_OPLOCK_LEVEL_2 ", 0);
++                      break;
++              case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:
++                      DebugTrace(DEBUG_TRACE_MISC,   " FSCTL_OPLOCK_BREAK_ACKNOWLEDGE ", 0);
++                      break;
++              case FSCTL_OPBATCH_ACK_CLOSE_PENDING:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_OPBATCH_ACK_CLOSE_PENDING ", 0);
++                      break;
++              case FSCTL_OPLOCK_BREAK_NOTIFY:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_OPLOCK_BREAK_NOTIFY ", 0);
++                      break;
++              case FSCTL_OPLOCK_BREAK_ACK_NO_2:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_OPLOCK_BREAK_ACK_NO_2 ", 0);
++                      break;
++              case FSCTL_LOCK_VOLUME:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_LOCK_VOLUME ", 0);
++                      break;
++              case FSCTL_UNLOCK_VOLUME:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_UNLOCK_VOLUME ", 0);
++                      break;
++              case FSCTL_DISMOUNT_VOLUME:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_DISMOUNT_VOLUME ", 0);
++                      break;
++              case FSCTL_MARK_VOLUME_DIRTY:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_MARK_VOLUME_DIRTY ", 0);
++                      break;
++              case FSCTL_IS_VOLUME_DIRTY:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_IS_VOLUME_DIRTY ", 0);
++                      break;
++              case FSCTL_IS_VOLUME_MOUNTED:
++                      Status = Ext2VerifyVolume(Irp, IrpSp );
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_IS_VOLUME_MOUNTED ", 0);
++                      break;
++              case FSCTL_IS_PATHNAME_VALID:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_IS_PATHNAME_VALID ", 0);
++                      break;
++              case FSCTL_QUERY_RETRIEVAL_POINTERS:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_QUERY_RETRIEVAL_POINTERS ", 0);
++                      break;
++              case FSCTL_QUERY_FAT_BPB:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_QUERY_FAT_BPB ", 0);
++                      break;
++              case FSCTL_FILESYSTEM_GET_STATISTICS:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_FILESYSTEM_GET_STATISTICS ", 0);
++                      break;
++              case FSCTL_GET_VOLUME_BITMAP:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_GET_VOLUME_BITMAP ", 0);
++                      break;
++              case FSCTL_GET_RETRIEVAL_POINTERS:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_GET_RETRIEVAL_POINTERS ", 0);
++                      break;
++              case FSCTL_MOVE_FILE:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_MOVE_FILE ", 0);
++                      break;
++              case FSCTL_ALLOW_EXTENDED_DASD_IO:
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   " FSCTL_ALLOW_EXTENDED_DASD_IO ", 0);
++                      break;
++              default :
++                      DebugTrace(DEBUG_TRACE_FSCTRL,   "Unknown FSCTRL !!!", 0);
++
++              }
++      
++      try_exit: NOTHING;
++      }
++      finally
++      {
++
++      }
++      return Status;
++}
++
++
++
++NTSTATUS Ext2VerifyVolume (
++      IN PIRP Irp,
++      IN PIO_STACK_LOCATION IrpSp )
++{
++
++      PVPB PtrVPB;
++      
++      PtrVPB = IrpSp->Parameters.VerifyVolume.Vpb;
++      if( IrpSp->FileObject )
++      {
++              PtrVPB = IrpSp->FileObject->Vpb;
++      }
++      if( !PtrVPB )
++      {
++              PtrVPB = IrpSp->Parameters.VerifyVolume.Vpb;
++      }
++
++      if( !PtrVPB )
++      {
++              return STATUS_WRONG_VOLUME;
++      }
++
++
++      if ( Ext2IsFlagOn( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME ) ) 
++      {
++              //
++              //      Not doing a verify!
++              //      Just acting as if everyting is fine!
++              //      THis should do for now
++              //
++        Ext2ClearFlag( PtrVPB->RealDevice->Flags, DO_VERIFY_VOLUME );
++              
++      }
++      return STATUS_SUCCESS;
++}
index 0000000,0000000..9991cc1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,543 @@@
++/*************************************************************************
++*
++* File: io.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     This file contains low level disk io routines.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#include                      "ext2fsd.h"
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_IO
++
++/*************************************************************************
++*
++* Function: Ext2PassDownMultiReadWriteIRP()
++*
++* Description:
++*     pass down multiple read IRPs as Associated IRPs
++*
++* Expected Interrupt Level (for execution) :
++*
++*  ?
++*
++* Return Value: STATUS_SUCCESS / STATUS_PENDING / Error
++*
++*************************************************************************/
++NTSTATUS Ext2PassDownMultiReadWriteIRP( 
++      PEXT2_IO_RUN                    PtrIoRuns, 
++      UINT                                    Count, 
++      ULONG                                   TotalReadWriteLength,
++      PtrExt2IrpContext               PtrIrpContext,
++      PtrExt2FCB                              PtrFCB,
++      BOOLEAN                                 SynchronousIo)
++{
++      PIRP                            PtrMasterIrp;
++      PIRP                            PtrAssociatedIrp;
++    PIO_STACK_LOCATION        PtrIrpSp;
++    PMDL                              PtrMdl;
++      PtrExt2VCB                      PtrVCB;
++      UINT                            i;
++      ULONG                           BufferOffset;
++      PEXT2_IO_CONTEXT        PtrIoContext = NULL;
++      PKEVENT                         PtrSyncEvent = NULL;
++      ULONG                           LogicalBlockSize;
++      ULONG                           ReadWriteLength;
++
++      NTSTATUS RC = STATUS_SUCCESS;
++
++      PtrVCB = PtrFCB->PtrVCB;
++      PtrMasterIrp = PtrIrpContext->Irp;
++      LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++
++      try
++      {
++              if( !SynchronousIo )
++              {
++                      IoMarkIrpPending( PtrIrpContext->Irp );
++                      //      We will be returning STATUS_PENDING...
++              }
++
++              if( !PtrMasterIrp->MdlAddress )
++              {
++                      Ext2LockCallersBuffer( PtrMasterIrp, TRUE, TotalReadWriteLength );
++              }
++
++              if( SynchronousIo )
++              {
++                      PtrSyncEvent = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) )  );
++                      if ( !PtrSyncEvent )
++                      {
++                              RC = STATUS_INSUFFICIENT_RESOURCES;
++                              try_return ( RC );
++                      }
++                      KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE );
++              }
++              //
++              //      Allocate and initialize a completion context
++              //
++              PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) )  );
++              if ( !PtrIoContext )
++              {
++                      RC = STATUS_INSUFFICIENT_RESOURCES;
++                      try_return ( RC );
++              }
++
++              RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) );
++              PtrIoContext->Count = Count;
++              PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT;
++              PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT );
++              PtrIoContext->PtrMasterIrp = PtrMasterIrp;
++              PtrIoContext->PtrSyncEvent = PtrSyncEvent;
++              PtrIoContext->ReadWriteLength = TotalReadWriteLength;
++
++              
++
++              for( ReadWriteLength = 0, BufferOffset = 0, i = 0; i < Count; i++, BufferOffset += ReadWriteLength )
++              {
++                      
++                      ReadWriteLength = PtrIoRuns[ i].EndOffset - PtrIoRuns[ i].StartOffset;
++                      
++                      //
++                      //      Allocating an Associated IRP...
++                      //
++                      PtrAssociatedIrp = IoMakeAssociatedIrp( PtrMasterIrp,
++                                      (CCHAR) (PtrVCB->TargetDeviceObject->StackSize + 1 ) );
++                      PtrIoRuns[ i].PtrAssociatedIrp = PtrAssociatedIrp;
++                      ASSERT ( PtrAssociatedIrp );
++                      PtrMasterIrp->AssociatedIrp.IrpCount ++;
++                      
++                      //
++                      //      Allocating a Memory Descriptor List...
++                      //
++                      PtrMdl = IoAllocateMdl( (PCHAR) PtrMasterIrp->UserBuffer + BufferOffset, //     Virtual Address
++                              ReadWriteLength,        FALSE, FALSE, PtrAssociatedIrp );
++                      
++                      //
++                      //      and building a partial MDL...
++                      //
++                      IoBuildPartialMdl( PtrMasterIrp->MdlAddress,
++                              PtrMdl, (PCHAR)PtrMasterIrp->UserBuffer + BufferOffset, ReadWriteLength );
++
++                      //
++                      //      Create an Irp stack location for ourselves...
++                      //
++                      IoSetNextIrpStackLocation( PtrAssociatedIrp );
++                      PtrIrpSp = IoGetCurrentIrpStackLocation( PtrAssociatedIrp );
++
++                      //
++                      //  Setup the Stack location to describe our read.
++                      //
++                      PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction;
++                      if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
++                      {
++                              PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
++                              PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = 
++                                      PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
++                      }
++                      else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
++                      {
++                              PtrIrpSp->Parameters.Write.Length = ReadWriteLength;
++                              PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = 
++                                      PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
++                      }
++
++                      //      PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
++                      //      PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock;
++
++
++                      //
++                      //      Setup a completion routine...
++                      //
++                      IoSetCompletionRoutine( PtrAssociatedIrp, 
++                                              SynchronousIo ? 
++                                              Ext2MultiSyncCompletionRoutine : 
++                                              Ext2MultiAsyncCompletionRoutine,
++                                              PtrIoContext, TRUE, TRUE, TRUE );
++
++                      //
++                      //      Initialise the next stack location for the driver below us to use...
++                      //
++                      PtrIrpSp = IoGetNextIrpStackLocation( PtrAssociatedIrp );
++                      PtrIrpSp->MajorFunction = PtrIrpContext->MajorFunction;
++                      if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
++                      {
++                              PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
++                              PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
++                      }
++                      else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
++                      {
++                              PtrIrpSp->Parameters.Write.Length = ReadWriteLength;
++                              PtrIrpSp->Parameters.Write.ByteOffset.QuadPart = PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
++                      }
++
++                      //      PtrIrpSp->Parameters.Read.Length = ReadWriteLength;
++                      //      PtrIrpSp->Parameters.Read.ByteOffset.QuadPart = 
++                      //              PtrIoRuns[i].LogicalBlock * ( LogicalBlockSize );
++              }
++
++              for( i = 0; i < Count; i++ ) {
++                    DbgPrint("PASSING DOWN IRP %d TO TARGET DEVICE\n", i);
++                    IoCallDriver( PtrVCB->TargetDeviceObject, PtrIoRuns[ i].PtrAssociatedIrp );
++                }
++
++              if( SynchronousIo )
++              {
++                      //
++                      //      Synchronous IO 
++                      //      Wait for the IO to complete...
++                      //
++                    DbgPrint("DEADLY WAIT (%d)\n", KeGetCurrentIrql());
++                      KeWaitForSingleObject( PtrSyncEvent,
++                              Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
++                        DbgPrint("DEADLY WAIT DONE\n");
++                      try_return ( RC );
++              }
++              else
++              {
++                      //      Asynchronous IO...
++                      RC = STATUS_PENDING;
++                      try_return ( RC );
++              }
++      
++              try_exit:       NOTHING;
++      }
++      finally 
++      {
++              if( PtrSyncEvent )
++              {
++                      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrSyncEvent );
++                      ExFreePool( PtrSyncEvent );
++              }
++              if( PtrIoContext && ! ( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) )
++              {
++                      //
++                      //      This means we are getting out of 
++                      //      this function without doing a read
++                      //      due to an error, maybe...
++                      //
++                      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrIoContext);
++                      ExFreePool( PtrIoContext );
++              }
++      }
++      return(RC);
++}
++
++NTSTATUS Ext2PassDownSingleReadWriteIRP(
++      PtrExt2IrpContext       PtrIrpContext,
++      PIRP                            PtrIrp, 
++      PtrExt2VCB                      PtrVCB,
++      LARGE_INTEGER           ByteOffset, 
++      uint32                          ReadWriteLength, 
++      BOOLEAN                         SynchronousIo)
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++
++      PEXT2_IO_CONTEXT                PtrIoContext = NULL;
++      PKEVENT                                 PtrSyncEvent = NULL;
++      PVOID                                   PtrReadBuffer = NULL;
++      ULONG                                   ReadBufferLength = 0;
++
++      ULONG           LogicalBlockNo = 0;
++      ULONG           LogicalBlockSize = 0;
++      ULONG           PhysicalBlockSize = 0;
++
++      uint32  NumberBytesRead = 0;
++      int i;
++      PIO_STACK_LOCATION      PtrIrpNextSp = NULL;
++
++      try
++      {
++              if( !PtrIrp->MdlAddress )
++              {
++                      Ext2LockCallersBuffer( PtrIrp, TRUE, ReadWriteLength );
++              }
++
++
++              if( SynchronousIo )
++              {
++                      PtrSyncEvent = Ext2AllocatePool( NonPagedPool, Ext2QuadAlign( sizeof(KEVENT) )  );
++                      if ( !PtrSyncEvent )
++                      {
++                              RC = STATUS_INSUFFICIENT_RESOURCES;
++                              try_return ( RC );
++                      }
++                      KeInitializeEvent( PtrSyncEvent, SynchronizationEvent, FALSE );
++              }
++
++              //
++              //      Allocate and initialize a completion context
++              //
++              PtrIoContext = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( sizeof(EXT2_IO_CONTEXT) )  );
++              if ( !PtrIoContext )
++              {
++                      RC = STATUS_INSUFFICIENT_RESOURCES;
++                      try_return ( RC );
++              }
++
++              RtlZeroMemory( PtrIoContext, sizeof(EXT2_IO_CONTEXT) );
++              PtrIoContext->Count = 1;
++              PtrIoContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IO_CONTEXT;
++              PtrIoContext->NodeIdentifier.NodeSize = sizeof( EXT2_IO_CONTEXT );
++              PtrIoContext->PtrMasterIrp = NULL;
++              PtrIoContext->PtrSyncEvent = PtrSyncEvent;
++              PtrIoContext->ReadWriteLength = ReadWriteLength;
++
++              IoSetCompletionRoutine( PtrIrp, 
++                      SynchronousIo ? 
++                      Ext2SingleSyncCompletionRoutine: 
++                      Ext2SingleAsyncCompletionRoutine,
++                      PtrIoContext, TRUE, TRUE, TRUE );
++
++              //
++              //  Setup the next IRP stack location in the associated Irp for the disk
++              //  driver beneath us.
++              //
++              PtrIrpNextSp = IoGetNextIrpStackLocation( PtrIrp );
++
++              //
++              //  Setup the Stack location to do a read from the disk driver.
++              //
++              PtrIrpNextSp->MajorFunction = PtrIrpContext->MajorFunction;
++              if( PtrIrpContext->MajorFunction == IRP_MJ_READ )
++              {
++                      PtrIrpNextSp->Parameters.Read.Length = ReadWriteLength;
++                      PtrIrpNextSp->Parameters.Read.ByteOffset = ByteOffset;
++              }
++              else if( PtrIrpContext->MajorFunction == IRP_MJ_WRITE )
++              {
++                      PtrIrpNextSp->Parameters.Write.Length = ReadWriteLength;
++                      PtrIrpNextSp->Parameters.Write.ByteOffset = ByteOffset;
++              }
++              //
++              //  Issue the read / write request
++              //
++              RC = IoCallDriver(PtrVCB->TargetDeviceObject, PtrIrp);
++
++              if( SynchronousIo )
++              {
++                      //
++                      //      Wait for completion...
++                      //
++                      RC = KeWaitForSingleObject( &PtrIoContext->PtrSyncEvent,
++                                              Executive, KernelMode, FALSE, (PLARGE_INTEGER)NULL );
++
++                      RC = STATUS_SUCCESS;
++              }
++              else
++              {
++                      RC = STATUS_PENDING;
++              }
++
++              try_exit:       NOTHING;
++      }
++      finally 
++      {
++              if( PtrSyncEvent )
++              {
++                      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrSyncEvent );
++                      ExFreePool( PtrSyncEvent );
++              }
++              if( PtrIoContext && !( RC == STATUS_PENDING || RC == STATUS_SUCCESS ) )
++              {
++                      //
++                      //      This means we are getting out of 
++                      //      this function without doing a read / write
++                      //      due to an error, maybe...
++                      //
++                      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrIoContext );
++                      ExFreePool( PtrIoContext );
++              }
++      }
++      return RC;
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2SingleSyncCompletionRoutine()
++*
++* Description:
++*     Synchronous I/O Completion Routine
++*
++* Expected Interrupt Level (for execution) :
++*
++*  ?
++*
++* Return Value: NTSTATUS - STATUS_SUCCESS(always)
++*
++*************************************************************************/
++NTSTATUS Ext2SingleSyncCompletionRoutine(
++    IN PDEVICE_OBJECT DeviceObject,
++    IN PIRP Irp,
++    IN PVOID Contxt
++    )
++{
++      PEXT2_IO_CONTEXT PtrContext = Contxt;
++
++      if( Irp->PendingReturned  )
++              IoMarkIrpPending( Irp );
++      
++      ASSERT( PtrContext );
++      ASSERT( PtrContext->NodeIdentifier.NodeType == EXT2_NODE_TYPE_IO_CONTEXT );
++
++      KeSetEvent( PtrContext->PtrSyncEvent, 0, FALSE );
++      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrContext );
++      ExFreePool( PtrContext );
++
++      return STATUS_SUCCESS;
++}
++
++/*************************************************************************
++*
++* Function: Ext2SingleAsyncCompletionRoutine()
++*
++* Description:
++*     Asynchronous I/O Completion Routine
++*
++* Expected Interrupt Level (for execution) :
++*
++*  ?
++*
++* Return Value: NTSTATUS - STATUS_SUCCESS(always)
++*
++*************************************************************************/
++NTSTATUS Ext2SingleAsyncCompletionRoutine(
++    IN PDEVICE_OBJECT DeviceObject,
++    IN PIRP Irp,
++    IN PVOID Contxt
++    )
++{
++      PEXT2_IO_CONTEXT PtrContext = Contxt;
++
++      if( Irp->PendingReturned  )
++              IoMarkIrpPending( Irp );
++      
++      ASSERT( PtrContext );
++      ASSERT( PtrContext->NodeIdentifier.NodeType == EXT2_NODE_TYPE_IO_CONTEXT );
++
++      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrContext );
++      ExFreePool( PtrContext );
++
++      return STATUS_SUCCESS;
++}
++
++/*************************************************************************
++*
++* Function: Ext2MultiSyncCompletionRoutine()
++*
++* Description:
++*     Synchronous I/O Completion Routine
++*
++* Expected Interrupt Level (for execution) :
++*
++*  ?
++*
++* Return Value: NTSTATUS - STATUS_SUCCESS(always)
++*
++*************************************************************************/
++NTSTATUS Ext2MultiSyncCompletionRoutine (
++    IN PDEVICE_OBJECT DeviceObject,
++    IN PIRP Irp,
++    IN PVOID Contxt
++    )
++{
++
++      PEXT2_IO_CONTEXT PtrContext = Contxt;
++      ASSERT( PtrContext );
++
++      if( Irp->PendingReturned )
++      {
++              IoMarkIrpPending( Irp );
++      }
++
++      if (!NT_SUCCESS( Irp->IoStatus.Status )) 
++      {
++              PtrContext->PtrMasterIrp->IoStatus.Status = Irp->IoStatus.Status;
++    }
++
++    if (InterlockedDecrement( &PtrContext->Count ) == 0)
++      {
++              if ( NT_SUCCESS( PtrContext->PtrMasterIrp->IoStatus.Status ) )
++              {
++                      PtrContext->PtrMasterIrp->IoStatus.Information = PtrContext->ReadWriteLength;
++              }
++              else
++              {
++                      PtrContext->PtrMasterIrp->IoStatus.Information = 0;
++              }
++
++        KeSetEvent( PtrContext->PtrSyncEvent, 0, FALSE );
++              DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrContext );
++              ExFreePool( PtrContext );
++    }
++
++      //
++      //      The master Irp will be automatically completed 
++      //      when all the associated IRPs are completed
++      //
++      return STATUS_SUCCESS;
++}
++
++/*************************************************************************
++*
++* Function: Ext2MultiAsyncCompletionRoutine()
++*
++* Description:
++*     Asynchronous I/O Completion Routine
++*
++* Expected Interrupt Level (for execution) :
++*
++*  ?
++*
++* Return Value: NTSTATUS - STATUS_SUCCESS(always)
++*
++*************************************************************************/
++NTSTATUS Ext2MultiAsyncCompletionRoutine (
++    IN PDEVICE_OBJECT DeviceObject,
++    IN PIRP Irp,
++    IN PVOID Contxt
++    )
++{
++
++      PEXT2_IO_CONTEXT PtrContext = Contxt;
++      ASSERT( PtrContext );
++      
++      if( Irp->PendingReturned )
++      {
++              IoMarkIrpPending( Irp );
++      }
++
++      if (!NT_SUCCESS( Irp->IoStatus.Status )) 
++      {
++              PtrContext->PtrMasterIrp->IoStatus.Status = Irp->IoStatus.Status;
++    }
++
++    if (InterlockedDecrement( &PtrContext->Count ) == 0)
++      {
++              if ( NT_SUCCESS( PtrContext->PtrMasterIrp->IoStatus.Status ) )
++              {
++                      PtrContext->PtrMasterIrp->IoStatus.Information = PtrContext->ReadWriteLength;
++              }
++              else
++              {
++                      PtrContext->PtrMasterIrp->IoStatus.Information = 0;
++              }
++              DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [io]", PtrContext );
++              ExFreePool( PtrContext );
++    }
++
++      //
++      //      The master Irp will be automatically completed 
++      //      when all the associated IRPs are completed
++      //      Returning STATUS_SUCCESS to continue postprocessing...
++      //
++      return STATUS_SUCCESS;
++}
index 0000000,0000000..1369b58
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2837 @@@
++/*************************************************************************
++*
++* File: metadata.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Should contain code to handle Ext2 Metadata.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#include                      "ext2fsd.h"
++
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_METADATA_IO
++
++#define                       DEBUG_LEVEL                                             ( DEBUG_TRACE_METADATA )
++
++extern        Ext2Data                                        Ext2GlobalData;
++
++/*************************************************************************
++*
++* Function: Ext2ReadInode()
++*
++* Description:
++*
++*     The functions will read in the specifiec inode and return it in a buffer
++*
++* 
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL 
++*
++*
++* Arguements:
++*
++*
++*
++* Return Value: The Status of the Read IO
++*
++*************************************************************************/
++
++NTSTATUS Ext2ReadInode (
++      PtrExt2VCB              PtrVcb,                 //      the Volume Control Block
++      uint32                  InodeNo,                //      The Inode no
++      PEXT2_INODE             PtrInode                //      The Inode Buffer
++      )                                       
++{
++      //      The Status to be returned...
++      NTSTATUS RC = STATUS_SUCCESS;
++
++      //      The Read Buffer Pointer
++      BYTE * PtrPinnedReadBuffer = NULL;
++
++      PEXT2_INODE             PtrTempInode;
++
++      //      Buffer Control Block
++      PBCB PtrBCB = NULL;
++
++      LARGE_INTEGER VolumeByteOffset, TempOffset;
++
++      ULONG LogicalBlockSize = 0;
++
++      ULONG NumberOfBytesToRead = 0;
++      ULONG Difference = 0;
++
++      ULONG GroupNo;
++      int Index;
++
++      try
++      {
++              ASSERT(PtrVcb);
++              ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
++
++              //      Inode numbers start at 1 and not from 0
++              //      Hence 1 is subtracted from InodeNo to get a zero based index...
++              GroupNo = ( InodeNo - 1 ) / PtrVcb->InodesPerGroup;
++
++              if( GroupNo >= PtrVcb->NoOfGroups )
++              {
++                      DebugTrace(DEBUG_TRACE_MISC,   "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo );
++                      DebugTrace(DEBUG_TRACE_MISC,   "Only %d groups available on disk", PtrVcb->NoOfGroups );
++                      RC = STATUS_UNSUCCESSFUL;
++                      try_return( RC );
++              }
++
++              //if( PtrVcb->InodeTableBlock[ GroupNo ] == 0 )
++              if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 )
++              {
++                      DebugTrace(DEBUG_TRACE_MISC,   "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo );
++                      RC = STATUS_UNSUCCESSFUL;
++                      try_return( RC );
++              }
++
++              //      Inode numbers start at 1 and not from 0
++              //      Hence 1 is subtracted from InodeNo to get a zero based index...
++              Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup );
++
++              LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize;
++              NumberOfBytesToRead = sizeof(EXT2_INODE);       //      LogicalBlockSize;
++
++              VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock
++                              * LogicalBlockSize + Index * sizeof(EXT2_INODE);
++              //VolumeByteOffset.QuadPart = PtrVcb->InodeTableBlock[ GroupNo ] * LogicalBlockSize +
++              //      Index * sizeof(EXT2_INODE);
++              
++              TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize );
++              if( TempOffset.QuadPart != VolumeByteOffset.QuadPart )
++              {
++                      //      TempOffset.QuadPart -= LogicalBlockSize;
++                      Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize );
++                      VolumeByteOffset.QuadPart -= Difference;
++                      NumberOfBytesToRead += Difference;
++              }
++
++              NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
++
++              if( NumberOfBytesToRead > LogicalBlockSize )
++              {
++                      //      Multiple blocks being read in...
++                      //      Can cause overlap
++                      //      Watch out!!!!
++                      Ext2BreakPoint();
++              }
++
++
++
++              if (!CcMapData( PtrVcb->PtrStreamFileObject,
++                      &VolumeByteOffset,
++                      NumberOfBytesToRead,
++                      TRUE,
++                      &PtrBCB,
++                      (PVOID*)&PtrPinnedReadBuffer )) 
++              {
++                      RC = STATUS_UNSUCCESSFUL;
++                      try_return( RC );
++              }
++              else
++              {
++                      PtrTempInode = (PEXT2_INODE) ( PtrPinnedReadBuffer + Difference );
++                      RtlCopyMemory( PtrInode, PtrTempInode , sizeof(EXT2_INODE) );
++              }
++
++              try_exit:       NOTHING;
++      }
++      finally
++      {
++              if( PtrBCB )
++              {
++                      CcUnpinData( PtrBCB );
++                      PtrBCB = NULL;
++              }
++
++      }
++      return RC;
++}
++
++/*************************************************************************
++*
++* Function: Ext2InitializeFCBInodeInfo()
++*
++* Description:
++*     The functions will initialize the FCB with its i-node info
++*     provided it hasn't been initialized as yet...
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++* Arguements:
++*     Pointer to FCB
++*
++* Return Value: None
++*
++*************************************************************************/
++void Ext2InitializeFCBInodeInfo (
++      PtrExt2FCB      PtrFCB )
++{
++      PtrExt2VCB                      PtrVCB = NULL;
++      EXT2_INODE                      Inode;
++      int i;
++      ULONG LogicalBlockSize;
++
++      PtrVCB = PtrFCB->PtrVCB;
++
++      LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++
++      if( !Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED ) )
++      {
++              DebugTrace(DEBUG_TRACE_MISC,   "Reading in the i-node no %d", PtrFCB->INodeNo );
++
++              Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode );       
++                      
++              for( i = 0; i < EXT2_N_BLOCKS ; i++ )
++              {
++                      PtrFCB->IBlock[i] = Inode.i_block[ i ];
++              }
++
++              PtrFCB->CreationTime.QuadPart   = ( __int64 )Inode.i_ctime * 10000000;
++              PtrFCB->CreationTime.QuadPart   += Ext2GlobalData.TimeDiff.QuadPart;
++              PtrFCB->LastAccessTime.QuadPart = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_atime * 10000000);
++              PtrFCB->LastWriteTime.QuadPart  = Ext2GlobalData.TimeDiff.QuadPart + ( ( __int64 ) Inode.i_mtime * 10000000);
++
++
++              PtrFCB->LinkCount = Inode.i_links_count;
++
++              //      Getting the file type...
++              if( ! Ext2IsModeRegularFile( Inode.i_mode ) )
++              {  
++                      //      Not a reqular file...
++                      if( Ext2IsModeDirectory( Inode.i_mode) )
++                      {
++                              //      Directory...
++                              Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY );
++                      }
++                      else
++                      {
++                              //      Special File...
++                              //      Treated with respect... ;)
++                              //
++                              Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_SPECIAL_FILE );
++                      }
++
++              }
++              if( Ext2IsModeHidden( Inode.i_mode ) )
++              {
++                      Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_HIDDEN_FILE );
++              }
++              if( Ext2IsModeReadOnly( Inode.i_mode ) )
++              {
++                      Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_READ_ONLY );
++              }
++              
++
++              PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart = Inode.i_size;
++              Ext2SetFlag( PtrFCB->FCBFlags, EXT2_FCB_BLOCKS_INITIALIZED );
++              PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart = Inode.i_blocks * 512;
++
++              if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] )
++              {
++                      PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart -= LogicalBlockSize / 512;
++              }
++              DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [metadata]", Inode );
++      }
++}
++
++/*************************************************************************
++*
++* Function: Ext2AllocInode()
++*
++* Description:
++*     The functions will allocate a new on-disk i-node
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++*
++* Arguements:
++*     Parent Inode no
++*
++* Return Value: The new i-node no or zero
++*
++*************************************************************************/
++ULONG Ext2AllocInode( 
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVCB,
++      ULONG                           ParentINodeNo )
++{
++      ULONG InodeNo = 0;
++
++      //      Buffer Control Block
++      PBCB            PtrBitmapBCB = NULL;
++      BYTE *          PtrBitmapBuffer = NULL;
++
++      LARGE_INTEGER VolumeByteOffset;
++      ULONG LogicalBlockSize = 0;
++      ULONG NumberOfBytesToRead = 0;
++      
++      if( PtrVCB->FreeInodesCount == 0)
++      {
++              //
++              //      No Free Inodes left...
++              //      Fail request...
++              //
++              return 0;
++      }
++
++      try
++      {
++              //      unsigned int DescIndex ;
++              BOOLEAN Found = FALSE;
++              ULONG Block;
++              ULONG GroupNo;
++
++              LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++              
++              for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ )
++              {
++                      if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount )
++                              break;
++              }
++
++              VolumeByteOffset.QuadPart = 
++                      PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock * LogicalBlockSize;
++              
++              NumberOfBytesToRead = PtrVCB->InodesCount / PtrVCB->NoOfGroups;
++
++              if( NumberOfBytesToRead % 8 )
++              {
++                      NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1;
++              }
++              else
++              {
++                      NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ;
++              }
++
++              for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize ); 
++                              Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize)
++              {       
++                      //
++                      //      Read in the bitmap block...
++                      //
++                      ULONG i, j;
++                      BYTE Bitmap;
++                      
++                      if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 LogicalBlockSize, //NumberOfBytesToRead,
++                                 TRUE,
++                                 &PtrBitmapBCB,
++                                 (PVOID*)&PtrBitmapBuffer ) )
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                              return 0;
++                      }
++                      
++                      //
++                      //      Is there a free inode...
++                      //      
++                      for( i = 0; !Found && i < LogicalBlockSize && 
++                                              i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ )
++                      {
++                              Bitmap = PtrBitmapBuffer[i];
++                              if( Bitmap != 0xff )
++                              {
++                                      //
++                                      //      Found a free inode...
++                                      for( j = 0; !Found && j < 8; j++ )
++                                      {
++                                              if( ( Bitmap & 0x01 ) == 0 )
++                                              {
++                                                      //
++                                                      //      Found...
++                                                      Found = TRUE;
++
++                                                      //      Inode numbers start at 1 and not from 0
++                                                      //      Hence 1 is addded to j 
++                                                      InodeNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1 +
++                                                              ( GroupNo * PtrVCB->InodesPerGroup );
++                                              
++                                                      //      Update the inode on the disk...
++                                                      Bitmap = 1 << j;
++                                                      PtrBitmapBuffer[i] |= Bitmap;
++                                                      
++                                                      CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
++                                                      Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
++
++                                                      //
++                                                      //      Should update the bitmaps in the other groups too...
++                                                      //
++                                                      break;
++                                              }
++                                              Bitmap = Bitmap >> 1;
++                                      }
++                              }
++                      }
++                      //
++                      //      Unpin the BCB...
++                      //
++                      if( PtrBitmapBCB )
++                      {
++                              CcUnpinData( PtrBitmapBCB );
++                              PtrBitmapBCB = NULL;
++                      }
++              }
++
++              {
++                      //
++                      //      Updating the Inode count in the Group Descriptor...
++                      //      
++                      PBCB                                    PtrDescriptorBCB = NULL;
++                      PEXT2_GROUP_DESCRIPTOR  PtrGroupDescriptor = NULL;
++
++                      PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount--;
++
++                      if( PtrVCB->LogBlockSize )
++                      {
++                              //      First block contains the descriptors...
++                              VolumeByteOffset.QuadPart = LogicalBlockSize;
++                      }
++                      else
++                      {
++                              //      Second block contains the descriptors...
++                              VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
++                      }
++                      NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
++                      NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
++
++                      if (!CcPinRead( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 NumberOfBytesToRead,
++                                 TRUE,
++                                 &PtrDescriptorBCB ,
++                                 (PVOID*)&PtrGroupDescriptor )) 
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                              //
++                              //      Ignore this error...
++                              //      Not fatal...
++                      }
++                      else
++                      {
++                              PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count = 
++                                      PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount; 
++                              //
++                              //      Not synchronously flushing this information...
++                              //      Lazy writing will do...
++                              //
++                              CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
++                              CcUnpinData( PtrDescriptorBCB );
++                              PtrDescriptorBCB = NULL;
++                      }
++              }
++
++
++              //
++              //      Update the Inode count...
++              //      in the Super Block...
++              //
++              {
++                      //      Ext2 Super Block information...
++                      PEXT2_SUPER_BLOCK       PtrSuperBlock = NULL;
++                      PBCB                            PtrSuperBlockBCB = NULL;
++
++                      PtrVCB->FreeInodesCount--;
++                      //      Reading in the super block...
++                      VolumeByteOffset.QuadPart = 1024;
++
++                      //      THis shouldn't be more than a block in size...
++                      NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
++
++                      if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 NumberOfBytesToRead,
++                                 TRUE,
++                                 &PtrSuperBlockBCB,
++                                 (PVOID*)&PtrSuperBlock ) )
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                      }
++                      else
++                      {
++                              PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount;
++                              CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
++                              Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
++                              if( PtrSuperBlockBCB )
++                              {
++                                      CcUnpinData( PtrSuperBlockBCB );
++                                      PtrSuperBlockBCB = NULL;
++                              }
++                              
++                      }
++              }
++
++              try_exit:       NOTHING;
++      }
++      finally
++      {
++              if( PtrBitmapBCB )
++              {
++                      CcUnpinData( PtrBitmapBCB );
++                      PtrBitmapBCB = NULL;
++              }
++      }
++      DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating an inode - I-Node no : %ld", InodeNo );
++      
++      return InodeNo;
++
++}
++
++/*************************************************************************
++*
++* Function: Ext2DeallocInode()
++*
++* Description:
++*     The functions will deallocate an i-node 
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++* Return Value: Success / Failure...
++*
++*************************************************************************/
++BOOLEAN Ext2DeallocInode( 
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVCB,
++      ULONG                           INodeNo )
++{
++      BOOLEAN         RC = TRUE;
++      
++      //      Buffer Control Block
++      PBCB            PtrBitmapBCB = NULL;
++      BYTE *          PtrBitmapBuffer = NULL; 
++
++      LARGE_INTEGER VolumeByteOffset;
++      ULONG           LogicalBlockSize = 0;
++      
++      DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating an inode - I-Node no : %ld", INodeNo );
++
++      try
++      {
++              ULONG   BlockIndex ;
++              ULONG   BitmapIndex;
++              ULONG   GroupNo;
++              BYTE    Bitmap;
++              
++              LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++
++              GroupNo = INodeNo / PtrVCB->InodesPerGroup;
++              INodeNo = INodeNo % PtrVCB->InodesPerGroup;
++
++              BitmapIndex =  (INodeNo-1) / 8;
++              Bitmap = 1 << ( (INodeNo-1) % 8 );
++              BlockIndex = BitmapIndex / LogicalBlockSize;
++              //      Adjusting to index into the Logical block that contains the bitmap
++              BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize );
++
++              VolumeByteOffset.QuadPart = 
++                      ( PtrVCB->PtrGroupDescriptors[ GroupNo ].InodeBitmapBlock + BlockIndex ) 
++                      * LogicalBlockSize;
++
++              //
++              //      Read in the bitmap block...
++              //
++              if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                              &VolumeByteOffset,
++                              LogicalBlockSize,       //      Just the block that contains the bitmap will do...
++                              TRUE,                           //      Can Wait...
++                              &PtrBitmapBCB,
++                              (PVOID*)&PtrBitmapBuffer ) )
++              {
++                      //      Unable to Pin the data into the cache...
++                      try_return (RC = FALSE);
++              }
++
++              //
++              //      Locate the inode...
++              //      This inode is in the byte PtrBitmapBuffer[ BitmapIndex ]
++              if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0)
++              {
++                      //      This shouldn't have been so...
++                      //      The inode was never allocated!
++                      //      How to deallocate something that hasn't been allocated? 
++                      //      Hmmm... ;)
++                      //      Ignore this error...
++                      try_return (RC = TRUE);
++              }
++
++
++              //      Setting the bit for the inode...
++              PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap);
++
++              //      Update the cache...
++              CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
++
++              //      Save up the BCB for forcing a synchronous write...
++              //      Before completing the IRP...
++              Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
++
++
++              if( PtrBitmapBCB )
++              {
++                      CcUnpinData( PtrBitmapBCB );
++                      PtrBitmapBCB = NULL;
++              }
++              
++              {
++                      //
++                      //      Updating the Inode count in the Group Descriptor...
++                      //      
++                      PBCB                                    PtrDescriptorBCB = NULL;
++                      PEXT2_GROUP_DESCRIPTOR  PtrGroupDescriptor = NULL;
++                      ULONG                                   NumberOfBytesToRead = 0;
++
++                      PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount++;
++
++                      if( PtrVCB->LogBlockSize )
++                      {
++                              //      First block contains the descriptors...
++                              VolumeByteOffset.QuadPart = LogicalBlockSize;
++                      }
++                      else
++                      {
++                              //      Second block contains the descriptors...
++                              VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
++                      }
++                      NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
++                      NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
++
++                      if (!CcPinRead( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 NumberOfBytesToRead,
++                                 TRUE,
++                                 &PtrDescriptorBCB ,
++                                 (PVOID*)&PtrGroupDescriptor )) 
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                              //
++                              //      Ignore this error...
++                              //      Not fatal...
++                      }
++                      else
++                      {
++                              PtrGroupDescriptor[ GroupNo ].bg_free_inodes_count = 
++                                      PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeInodesCount; 
++                              //
++                              //      Not synchronously flushing this information...
++                              //      Lazy writing will do...
++                              //
++                              CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
++                              CcUnpinData( PtrDescriptorBCB );
++                              PtrDescriptorBCB = NULL;
++                      }
++              }
++              
++
++              //
++              //      Update the Inode count...
++              //      in the Super Block
++              //      and in the VCB
++              //
++              {
++                      //      Ext2 Super Block information...
++                      PEXT2_SUPER_BLOCK       PtrSuperBlock = NULL;
++                      PBCB                            PtrSuperBlockBCB = NULL;
++                      ULONG                           NumberOfBytesToRead = 0;
++
++                      PtrVCB->FreeInodesCount++;
++
++                      //      Reading in the super block...
++                      VolumeByteOffset.QuadPart = 1024;
++                      NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
++
++                      if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 NumberOfBytesToRead,
++                                 TRUE,
++                                 &PtrSuperBlockBCB,
++                                 (PVOID*)&PtrSuperBlock ) )
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                      }
++                      else
++                      {
++                              PtrSuperBlock->s_free_inodes_count = PtrVCB->FreeInodesCount;
++                              CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
++                              Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
++                              if( PtrSuperBlockBCB )
++                              {
++                                      CcUnpinData( PtrSuperBlockBCB );
++                                      PtrSuperBlockBCB = NULL;
++                              }
++                              
++                      }
++              }
++              try_exit:       NOTHING;
++      }
++      finally
++      {
++              if( PtrBitmapBCB )
++              {
++                      CcUnpinData( PtrBitmapBCB );
++                      PtrBitmapBCB = NULL;
++              }
++      }
++      return RC;
++}
++
++/*************************************************************************
++*
++* Function: Ext2WriteInode()
++*
++* Description:
++*     The functions will write an i-node to disk
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++*
++* Return Value: Success / Failure...
++*
++*************************************************************************/
++NTSTATUS Ext2WriteInode(
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVcb,                 //      the Volume Control Block
++      uint32                          InodeNo,                //      The Inode no
++      PEXT2_INODE                     PtrInode                //      The Inode Buffer
++      )                                       
++{
++      //      The Status to be returned...
++      NTSTATUS RC = STATUS_SUCCESS;
++
++      //      The Read Buffer Pointer
++      BYTE * PtrPinnedBuffer = NULL;
++
++      PEXT2_INODE             PtrTempInode;
++
++      //      Buffer Control Block
++      PBCB PtrBCB = NULL;
++
++      LARGE_INTEGER VolumeByteOffset, TempOffset;
++
++      ULONG LogicalBlockSize = 0;
++      ULONG NumberOfBytesToRead = 0;
++      ULONG Difference = 0;
++      ULONG GroupNo;
++      int Index;
++
++      try
++      {
++              DebugTrace( DEBUG_TRACE_SPECIAL, "Writing and updating an inode - I-Node no : %ld", InodeNo );
++
++              ASSERT(PtrVcb);
++              ASSERT(PtrVcb->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
++              GroupNo = InodeNo / PtrVcb->InodesPerGroup;
++
++              if( GroupNo >= PtrVcb->NoOfGroups )
++              {
++                      DebugTrace(DEBUG_TRACE_MISC,   "&&&&&& Invalid Inode no. Group no %d - too big", GroupNo );
++                      DebugTrace(DEBUG_TRACE_MISC,   "Only %d groups available on disk", PtrVcb->NoOfGroups );
++                      RC = STATUS_UNSUCCESSFUL;
++                      try_return( RC );
++              }
++
++              if( PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock == 0 )
++              {
++                      DebugTrace(DEBUG_TRACE_MISC,   "&&&&&& Inode Table Group Invalid - Group no %d ", GroupNo );
++                      RC = STATUS_UNSUCCESSFUL;
++                      try_return( RC );
++              }
++
++              Index = ( InodeNo - 1 ) - ( GroupNo * PtrVcb->InodesPerGroup );
++
++              LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVcb->LogBlockSize;
++              NumberOfBytesToRead = sizeof(EXT2_INODE);
++
++              VolumeByteOffset.QuadPart = PtrVcb->PtrGroupDescriptors[ GroupNo ].InodeTablesBlock
++                              * LogicalBlockSize + Index * sizeof(EXT2_INODE);
++              
++              TempOffset.QuadPart = Ext2Align64( VolumeByteOffset.QuadPart, LogicalBlockSize );
++              if( TempOffset.QuadPart != VolumeByteOffset.QuadPart )
++              {
++                      //      TempOffset.QuadPart -= LogicalBlockSize;
++                      Difference = (LONG) (VolumeByteOffset.QuadPart - TempOffset.QuadPart + LogicalBlockSize );
++                      VolumeByteOffset.QuadPart -= Difference;
++                      NumberOfBytesToRead += Difference;
++              }
++
++              NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
++
++              if( NumberOfBytesToRead > LogicalBlockSize )
++              {
++                      //      Multiple blocks being read in...
++                      //      Can cause overlap
++                      //      Watch out!!!!
++                      Ext2BreakPoint();
++              }
++
++              if( !CcPinRead( PtrVcb->PtrStreamFileObject,
++                                      &VolumeByteOffset,
++                                      NumberOfBytesToRead,
++                                      TRUE,                   //      Can Wait...
++                                      &PtrBCB,
++                                      (PVOID*)&PtrPinnedBuffer ) )
++              {
++                      RC = STATUS_UNSUCCESSFUL;
++                      try_return( RC );
++              }
++              else
++              {
++                      RtlCopyMemory( PtrPinnedBuffer + Difference, PtrInode, sizeof(EXT2_INODE) );
++                      CcSetDirtyPinnedData( PtrBCB, NULL );
++                      Ext2SaveBCB( PtrIrpContext, PtrBCB, PtrVcb->PtrStreamFileObject );
++              }
++      
++              try_exit:       NOTHING;
++      }
++      finally
++      {
++              if( PtrBCB )
++              {
++                      CcUnpinData( PtrBCB );
++                      PtrBCB = NULL;
++              }
++
++      }
++      return RC;
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2MakeNewDirectoryEntry()
++*
++* Description:
++*     The functions will make a new directory entry in a directory file...
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++*
++* Return Value: Success / Failure...
++*
++*************************************************************************/
++BOOLEAN Ext2MakeNewDirectoryEntry(
++      PtrExt2IrpContext               PtrIrpContext,  //      The Irp context
++      PtrExt2FCB                              PtrParentFCB,   //      Parent Folder FCB
++      PFILE_OBJECT                    PtrFileObject,  //      Parent Folder Object
++      PUNICODE_STRING                 PtrName,                //      New entry's name
++      ULONG                                   Type,                   //      The type of the new entry
++      ULONG                                   NewInodeNo)             //      The inode no of the new entry...
++{
++      PBCB                            PtrLastBlockBCB = NULL;
++      BYTE *                          PtrLastBlock = NULL;
++      EXT2_DIR_ENTRY          DirEntry;
++      PEXT2_DIR_ENTRY         PtrTempDirEntry;
++      
++      ULONG                           BlockNo = 0;
++      ULONG                           i;
++      PtrExt2VCB                      PtrVCB;
++      LARGE_INTEGER           VolumeByteOffset;
++      unsigned long           LogicalBlockSize = 0;
++      unsigned long           NumberOfBytesToRead = 0;
++      BOOLEAN                         RC = FALSE;
++      
++      USHORT  HeaderLength = sizeof( EXT2_DIR_ENTRY );
++      USHORT  NewEntryLength = 0; 
++      USHORT  MinLength       = 0;
++      #define ActualLength (PtrTempDirEntry->rec_len)
++      #define NameLength  (PtrTempDirEntry->name_len)
++
++      try
++      {
++              ASSERT( PtrFileObject );
++
++              DebugTrace( DEBUG_TRACE_SPECIAL, "Making directory entry: %S", PtrName->Buffer );
++
++              PtrVCB = PtrParentFCB->PtrVCB;
++              AssertVCB( PtrVCB);
++
++              HeaderLength = sizeof( EXT2_DIR_ENTRY ) -
++                                                (sizeof( char ) * EXT2_NAME_LEN);
++              //      1. Setting up the entry...
++              NewEntryLength = sizeof( EXT2_DIR_ENTRY ) - ( sizeof( char ) * ( EXT2_NAME_LEN - (PtrName->Length / 2) ) );
++              //      Length should be a multiplicant of 4
++              NewEntryLength = ((NewEntryLength + 3 ) & 0xfffffffc);
++
++              RtlZeroMemory( &DirEntry, sizeof( EXT2_DIR_ENTRY ) );
++
++              DirEntry.file_type = (BYTE) Type;
++              DirEntry.inode = NewInodeNo;
++              DirEntry.name_len = (BYTE)(PtrName->Length / 2 );       //      Does not include a NULL
++              
++              //      DirEntry.rec_len = (USHORT) NewEntryLength;
++
++              for( i = 0; ; i++ )
++              {
++                      if( i < (ULONG)( PtrName->Length / 2 ) )
++                      {
++                              DirEntry.name[i] = (CHAR) PtrName->Buffer[i];
++                      }
++                      else
++                      {
++                              //DirEntry.name[i] = 0; //      Entry need not be zero terminated...
++                              break;
++                      }
++              }
++
++              //
++              //      2. Read the block in the directory...
++              //      Initiate Caching...
++              if ( PtrFileObject->PrivateCacheMap == NULL )
++              {
++                      CcInitializeCacheMap(
++                              PtrFileObject, 
++                              (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
++                              TRUE,                                                                   // We utilize pin access for directories
++                              &(Ext2GlobalData.CacheMgrCallBacks),    // callbacks
++                              PtrParentFCB );                                                 // The context used in callbacks
++              }
++
++              LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++              if( PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart > 0 )
++              {
++                      BlockNo = (ULONG) ( (PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) / LogicalBlockSize) ;
++              }
++              else
++              {
++                      //      This directory doesn't have any data blocks...
++                      //      Allocate a new block...
++                      if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) )
++                      {
++                              try_return( RC = FALSE );
++                      }
++                      else
++                      {
++                              //      Bring in the newly allocated block to the cache...
++                              VolumeByteOffset.QuadPart = 0;
++
++                              if( !CcPreparePinWrite( 
++                                      PtrFileObject,
++                                      &VolumeByteOffset,
++                                      LogicalBlockSize,
++                                      TRUE,                   //      Zero out the block...
++                                      TRUE,                   //      Can Wait...
++                                      &PtrLastBlockBCB,
++                                      (PVOID*)&PtrLastBlock ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++
++                              DirEntry.rec_len = (USHORT)LogicalBlockSize;
++                              RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength);
++                              CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
++                              Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
++                              try_return( RC = TRUE );
++                      }
++              }
++
++              VolumeByteOffset.QuadPart = BlockNo * LogicalBlockSize;
++              CcMapData(      PtrFileObject,
++                                      &VolumeByteOffset,
++                                      LogicalBlockSize,
++                                      TRUE,
++                                      &PtrLastBlockBCB,
++                                      (PVOID*)&PtrLastBlock );
++
++              for( i = 0 ; i < LogicalBlockSize; )
++              {
++                      PtrTempDirEntry = (PEXT2_DIR_ENTRY) &PtrLastBlock[ i ];
++
++                      MinLength = HeaderLength + NameLength;
++                      MinLength = ( HeaderLength + NameLength + 3 ) & 0xfffffffc;
++
++                      
++                      if( PtrTempDirEntry->rec_len == 0 )
++                      {
++                              if( i == 0 )
++                              {
++                                      //      Must be an empty Block...
++                                      //      Insert here...
++                                      //      ---------------->>>
++                                      
++                                      CcPinMappedData( PtrFileObject,
++                                                                 &VolumeByteOffset,
++                                                                 LogicalBlockSize,
++                                                                 TRUE,
++                                                                 &PtrLastBlockBCB );
++
++                                      DirEntry.rec_len = (USHORT)LogicalBlockSize;
++                                      
++                                      RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength);
++                                      CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
++                                      Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
++                                      try_return( RC = TRUE );
++                              }
++                              else
++                              {
++                                      //      This shouldn't be so...
++                                      //      Something is wrong...
++                                      //      Fail this request...
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      if( ActualLength - MinLength >= NewEntryLength )
++                      {
++                              //      Insert here...
++                              //      ---------------->
++
++                              //      Getting ready for updation...
++                              CcPinMappedData( PtrFileObject,
++                                                         &VolumeByteOffset,
++                                                         LogicalBlockSize,
++                                                         TRUE,
++                                                         &PtrLastBlockBCB );
++
++
++                              DirEntry.rec_len = ActualLength - MinLength;
++
++                              //      Updating the current last entry
++                              PtrTempDirEntry->rec_len = MinLength;
++                              i += PtrTempDirEntry->rec_len;
++                              
++                              //      Making the new entry...
++                              RtlCopyBytes( (PtrLastBlock + i) , &DirEntry, NewEntryLength);
++                              CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
++                              Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
++                              try_return( RC = TRUE );
++
++                      }
++                      i += PtrTempDirEntry->rec_len;
++              }
++
++              //      Will have to allocate a new block...
++              //      Old block does not have enough space..
++              if( !Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrParentFCB, PtrFileObject, TRUE ) )
++              {
++                      try_return( RC = FALSE );
++              }
++              else
++              {
++                      //      unpin the previously pinned block
++                      CcUnpinData( PtrLastBlockBCB );
++                      PtrLastBlockBCB = NULL;
++
++                      //      Bring in the newly allocated block to the cache...
++                      VolumeByteOffset.QuadPart += LogicalBlockSize;
++                      if( !CcPreparePinWrite( 
++                              PtrFileObject,
++                              &VolumeByteOffset,
++                              LogicalBlockSize,
++                              TRUE,                   //      Zero out the block...
++                              TRUE,                   //      Can Wait...
++                              &PtrLastBlockBCB,
++                              (PVOID*)&PtrLastBlock ) )
++                      {
++                              try_return( RC = FALSE );
++                      }
++
++                      DirEntry.rec_len = (USHORT)LogicalBlockSize;
++                      RtlCopyBytes( PtrLastBlock, &DirEntry, NewEntryLength);
++                      CcSetDirtyPinnedData( PtrLastBlockBCB, NULL );
++                      Ext2SaveBCB( PtrIrpContext, PtrLastBlockBCB, PtrFileObject );
++                      try_return( RC = TRUE );
++              }
++              try_exit:       NOTHING;
++      }
++      finally
++      {
++              if( PtrLastBlockBCB )
++              {
++                      CcUnpinData( PtrLastBlockBCB );
++                      PtrLastBlockBCB = NULL;
++              }
++      }
++      if( RC == FALSE )
++      {
++              DebugTrace( DEBUG_TRACE_ERROR, "Failed to making directory entry: %S", PtrName->Buffer );
++      }
++      return RC;
++}
++
++
++BOOLEAN Ext2FreeDirectoryEntry(
++      PtrExt2IrpContext               PtrIrpContext,
++      PtrExt2FCB                              PtrParentFCB,
++      PUNICODE_STRING                 PtrName)
++{
++
++      PBCB                            PtrDataBlockBCB = NULL;
++      BYTE *                          PtrDataBlock = NULL;
++      PFILE_OBJECT            PtrFileObject = NULL;
++      PEXT2_DIR_ENTRY         PtrTempDirEntry;
++      LONGLONG                        ByteOffset = 0;
++      PtrExt2VCB                      PtrVCB;
++      LARGE_INTEGER           VolumeByteOffset;
++      unsigned long           LogicalBlockSize = 0;
++      BOOLEAN                         RC = FALSE;
++      
++
++      try
++      {
++              DebugTrace( DEBUG_TRACE_SPECIAL, "Freeing directory entry: %S", PtrName->Buffer );
++
++              PtrVCB = PtrParentFCB->PtrVCB;
++              AssertVCB( PtrVCB);
++              
++              LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++
++              PtrFileObject = PtrParentFCB->DcbFcb.Dcb.PtrDirFileObject;
++              if( PtrFileObject == NULL )
++              {
++                      return FALSE;
++              }
++              
++
++              //
++              //      1. Read the block in the directory...
++              //      Initiate Caching...
++              if ( PtrFileObject->PrivateCacheMap == NULL )
++              {
++                      CcInitializeCacheMap(
++                              PtrFileObject, 
++                              (PCC_FILE_SIZES)(&(PtrParentFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
++                              TRUE,                                                                   // We utilize pin access for directories
++                              &(Ext2GlobalData.CacheMgrCallBacks),    // callbacks
++                              PtrParentFCB );                                                 // The context used in callbacks
++              }
++
++              for( ByteOffset = 0; 
++                       ByteOffset < PtrParentFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart;
++                       ByteOffset += LogicalBlockSize )
++              {
++                      ULONG Index = 0;
++                      PEXT2_DIR_ENTRY PtrDirEntry = NULL;
++
++
++                      VolumeByteOffset.QuadPart = ByteOffset;
++                      
++                      CcPinRead(      PtrFileObject,
++                                              &VolumeByteOffset,
++                                              LogicalBlockSize,
++                                              TRUE,
++                                              &PtrDataBlockBCB,
++                                              (PVOID*)&PtrDataBlock );
++                      while( Index < LogicalBlockSize )
++                      {
++                              ULONG i;
++                              //      Parse...
++                              PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrDataBlock[ Index ];
++                              Index += PtrDirEntry->rec_len;
++
++                              if( PtrDirEntry->inode == 0 )
++                              {
++                                      //      This is a deleted entry...
++                                      continue;
++                              }
++                              if( ( PtrName->Length/2 ) != PtrDirEntry->name_len )
++                                      continue;
++                              for( i = 0; ; i++ )
++                              {
++                                      if( PtrDirEntry->name_len == i )
++                                      {
++                                              //      Remove the entry by setting the inode no to zero
++                                              PtrDirEntry->inode = 0;
++
++                                              //      Update the disk
++                                              CcSetDirtyPinnedData( PtrDataBlockBCB , NULL );
++                                              Ext2SaveBCB( PtrIrpContext, PtrDataBlockBCB, PtrFileObject );
++                                              CcUnpinData( PtrDataBlockBCB );
++                                              PtrDataBlockBCB = NULL;
++
++                                              //      Return to caller...
++                                              try_return( RC = TRUE );
++                                      }
++                                      if( PtrName->Buffer[i] != PtrDirEntry->name[i] )
++                                      {
++                                              break;
++                                      }
++                              }
++                      }
++                      CcUnpinData( PtrDataBlockBCB );
++                      PtrDataBlockBCB = NULL;
++              }
++              try_return( RC = FALSE );
++
++              try_exit:       NOTHING;
++      }
++      finally
++      {
++              if( PtrDataBlockBCB )
++              {
++                      CcUnpinData( PtrDataBlockBCB );
++                      PtrDataBlockBCB = NULL;
++              }
++      }
++      return RC;
++}
++
++/*************************************************************************
++*
++* Function: Ext2AddBlockToFile()
++*
++* Description:
++*     The functions will add a block to a file...
++*     It will update the allocation size but not the file size...
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++*
++* Return Value: Success / Failure...
++*
++*************************************************************************/
++BOOLEAN Ext2AddBlockToFile(
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVCB,
++      PtrExt2FCB                      PtrFCB,
++      PFILE_OBJECT            PtrFileObject,
++      BOOLEAN                         UpdateFileSize)
++{
++      BOOLEAN                 RC = TRUE; 
++
++      ULONG                   NewBlockNo = 0;
++      LARGE_INTEGER   VolumeByteOffset;
++      ULONG                   LogicalBlockSize = 0;
++      ULONG                   NoOfBlocks = 0;
++      EXT2_INODE              Inode;
++
++      ULONG   DirectBlocks = 0;
++      ULONG   SingleIndirectBlocks = 0;
++      ULONG   DoubleIndirectBlocks = 0;
++      ULONG   TripleIndirectBlocks = 0;
++      
++      ULONG   *PtrSIBBuffer = NULL;
++      PBCB    PtrSIBBCB = NULL;
++      ULONG   *PtrDIBBuffer = NULL;
++      PBCB    PtrDIBBCB = NULL;
++
++
++      LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++      DirectBlocks =  EXT2_NDIR_BLOCKS ;
++      SingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG );
++      DoubleIndirectBlocks = SingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
++      TripleIndirectBlocks = DoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
++
++      try
++      {
++              if( PtrFCB && PtrFCB->FCBName->ObjectName.Length )
++              {
++                      DebugTrace( DEBUG_TRACE_SPECIAL, "Adding Blocks to file  %S", PtrFCB->FCBName->ObjectName.Buffer );
++              }
++
++              Ext2InitializeFCBInodeInfo( PtrFCB );
++
++              //      Allocate a block...
++              NewBlockNo = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
++
++              if( NewBlockNo == 0 )
++              {
++                      try_return (RC = FALSE );
++              }
++
++              //      No of blocks CURRENTLY allocated...
++              NoOfBlocks = (ULONG) PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart / LogicalBlockSize;
++              
++              
++              if( NoOfBlocks < EXT2_NDIR_BLOCKS )
++              {
++                      //
++                      //      A direct data block will do...
++                      //
++                      
++                      PtrFCB->IBlock[ NoOfBlocks ] = NewBlockNo;
++                      
++                      //      Update the inode...
++                      Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode  );
++                      Inode.i_block[ NoOfBlocks ] = NewBlockNo;
++                      Inode.i_blocks += ( LogicalBlockSize / 512 );
++                      PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
++                      if( UpdateFileSize )
++                      {
++                              Inode.i_size += LogicalBlockSize;
++                              PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
++                      }
++
++                      
++                      if( PtrFileObject->PrivateCacheMap != NULL)
++                      {
++                              //
++                              //      Caching has been initiated...
++                              //      Let the Cache manager in on these changes...
++                              //      
++                              CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
++                      }
++                      
++                      
++                      //      Updating the inode...
++                      if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode  ) ) )
++                      {
++                              try_return (RC = TRUE);
++                      }
++                      else
++                      {
++                              try_return (RC = FALSE );
++                      }
++                      
++              }
++              else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks) )
++              {
++                      //
++                      //      A single indirect data block will do...
++                      Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode  );
++
++                      if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 )
++                      {
++                              //      A Single Indirect block should be allocated as well!!
++                              PtrFCB->IBlock[ EXT2_IND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
++                              if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] == 0 )
++                              {
++                                      try_return (RC = FALSE );
++                              }
++                              Inode.i_blocks += ( LogicalBlockSize / 512 );
++
++                              //      Bring in the new block to the cache
++                              //      Zero it out
++                              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
++
++                              if( !CcPreparePinWrite( 
++                                      PtrVCB->PtrStreamFileObject,
++                                      &VolumeByteOffset,
++                                      LogicalBlockSize,
++                                      TRUE,                   //      Zero out the block...
++                                      TRUE,                   //      Can Wait...
++                                      &PtrSIBBCB,
++                                      (PVOID*)&PtrSIBBuffer ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      else
++                      {
++                              //       Just bring in the SIB to the cache
++                              
++                              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
++
++                              if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                                      &VolumeByteOffset,
++                                                      LogicalBlockSize,
++                                                      TRUE,                   //      Can Wait...
++                                                      &PtrSIBBCB,
++                                                      (PVOID*)&PtrSIBBuffer ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      
++                      //      Update the inode...
++                      
++                      Inode.i_block[ EXT2_IND_BLOCK ] = PtrFCB->IBlock[ EXT2_IND_BLOCK ];
++                      Inode.i_blocks += ( LogicalBlockSize / 512 );
++                      PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
++                      if( UpdateFileSize )
++                      {
++                              Inode.i_size += LogicalBlockSize;
++                              PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
++                      }
++                      if( PtrFileObject->PrivateCacheMap != NULL)
++                      {
++                              //
++                              //      Caching has been initiated...
++                              //      Let the Cache manager in on these changes...
++                              //      
++                              CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
++                      }
++
++                      if( !NT_SUCCESS( Ext2WriteInode( 
++                              PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode  ) ) )
++                      {
++                              try_return (RC = FALSE );
++                      }
++
++                      
++                      //      Update the SIB...
++                      PtrSIBBuffer[ NoOfBlocks - DirectBlocks ] = NewBlockNo;
++                      CcSetDirtyPinnedData( PtrSIBBCB, NULL );
++                      Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject );
++
++                      try_return (RC = TRUE);
++
++              }
++              else if( NoOfBlocks < (DirectBlocks + SingleIndirectBlocks + DoubleIndirectBlocks ) )
++              {
++                      //
++                      //      A double indirect block will do...
++                      //
++                      ULONG SBlockNo;
++                      ULONG BlockNo;
++
++                      Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode  );
++
++                      if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 )
++                      {
++                              //      A double indirect pointer block should be allocated as well!!
++                              PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
++                              if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 )
++                              {
++                                      try_return (RC = FALSE );
++                              }
++                              Inode.i_blocks += ( LogicalBlockSize / 512 );
++
++                              //      Bring in the new block to the cache
++                              //      Zero it out
++                              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
++
++                              if( !CcPreparePinWrite( 
++                                      PtrVCB->PtrStreamFileObject,
++                                      &VolumeByteOffset,
++                                      LogicalBlockSize,
++                                      TRUE,                   //      Zero out the block...
++                                      TRUE,                   //      Can Wait...
++                                      &PtrDIBBCB,
++                                      (PVOID*)&PtrDIBBuffer ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      else
++                      {
++                              //       Just bring in the DIB to the cache
++                              
++                              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
++
++                              if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                                      &VolumeByteOffset,
++                                                      LogicalBlockSize,
++                                                      TRUE,                   //      Can Wait...
++                                                      &PtrDIBBCB,
++                                                      (PVOID*)&PtrDIBBuffer ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      
++                      //      See if a single indirect 'pointer' block 
++                      //      should also be allocated...
++                      BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks );
++                      SBlockNo = BlockNo / SingleIndirectBlocks;
++                      if( BlockNo % SingleIndirectBlocks )
++                      {
++                              //      A single indirect 'pointer' block 
++                              //      should also be allocated...
++                              PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
++                              CcSetDirtyPinnedData( PtrDIBBCB, NULL );
++                              VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
++
++                              Inode.i_blocks += ( LogicalBlockSize / 512 );
++
++                              if( !CcPreparePinWrite( 
++                                      PtrVCB->PtrStreamFileObject,
++                                      &VolumeByteOffset,
++                                      LogicalBlockSize,
++                                      TRUE,                                   //      Zero out the block...
++                                      TRUE,                                   //      Can Wait...
++                                      &PtrSIBBCB,
++                                      (PVOID*)&PtrSIBBuffer ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      else
++                      {
++                              VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
++                              if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                                      &VolumeByteOffset,
++                                                      LogicalBlockSize,
++                                                      TRUE,                           //      Can Wait...
++                                                      &PtrSIBBCB,
++                                                      (PVOID*)&PtrSIBBuffer ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      BlockNo = BlockNo % SingleIndirectBlocks;
++                      
++                      //      Update the inode...
++                      
++                      Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ];
++                      Inode.i_blocks += ( LogicalBlockSize / 512 );
++                      PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
++                      if( UpdateFileSize )
++                      {
++                              Inode.i_size += LogicalBlockSize;
++                              PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
++                      }
++                      if( PtrFileObject->PrivateCacheMap != NULL)
++                      {
++                              //
++                              //      Caching has been initiated...
++                              //      Let the Cache manager in on these changes...
++                              //      
++                              CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
++                      }
++
++                      if( !NT_SUCCESS( Ext2WriteInode( 
++                              PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode  ) ) )
++                      {
++                              try_return (RC = FALSE );
++                      }
++
++                      
++                      //      Update the SIB...
++                      PtrSIBBuffer[ BlockNo ] = NewBlockNo;
++                      CcSetDirtyPinnedData( PtrSIBBCB, NULL );
++                      Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject );
++                      Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject );
++
++                      try_return (RC = TRUE);
++
++              }
++              else
++              {       
++                      //
++                      //      A Triple Indirect block is required
++                      //
++                      ULONG SBlockNo;
++                      ULONG BlockNo;
++
++                      //      This is not supported as yet...
++                      try_return (RC = FALSE);
++
++                      Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode  );
++
++                      if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] == 0 )
++                      {
++                              //      A double indirect pointer block should be allocated as well!!
++                              PtrFCB->IBlock[ EXT2_DIND_BLOCK ] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
++                              if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] == 0 )
++                              {
++                                      try_return (RC = FALSE );
++                              }
++                              Inode.i_blocks += ( LogicalBlockSize / 512 );
++
++                              //      Bring in the new block to the cache
++                              //      Zero it out
++                              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
++
++                              if( !CcPreparePinWrite( 
++                                      PtrVCB->PtrStreamFileObject,
++                                      &VolumeByteOffset,
++                                      LogicalBlockSize,
++                                      TRUE,                   //      Zero out the block...
++                                      TRUE,                   //      Can Wait...
++                                      &PtrDIBBCB,
++                                      (PVOID*)&PtrDIBBuffer ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      else
++                      {
++                              //       Just bring in the DIB to the cache
++                              
++                              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
++
++                              if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                                      &VolumeByteOffset,
++                                                      LogicalBlockSize,
++                                                      TRUE,                   //      Can Wait...
++                                                      &PtrDIBBCB,
++                                                      (PVOID*)&PtrDIBBuffer ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      
++                      //      See if a single indirect 'pointer' block 
++                      //      should also be allocated...
++                      BlockNo = ( NoOfBlocks - DirectBlocks - SingleIndirectBlocks );
++                      SBlockNo = BlockNo / SingleIndirectBlocks;
++                      if( BlockNo % SingleIndirectBlocks )
++                      {
++                              //      A single indirect 'pointer' block 
++                              //      should also be allocated...
++                              PtrDIBBuffer[SBlockNo] = Ext2AllocBlock( PtrIrpContext, PtrVCB, 1 );
++                              CcSetDirtyPinnedData( PtrDIBBCB, NULL );
++                              VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
++
++                              Inode.i_blocks += ( LogicalBlockSize / 512 );
++
++                              if( !CcPreparePinWrite( 
++                                      PtrVCB->PtrStreamFileObject,
++                                      &VolumeByteOffset,
++                                      LogicalBlockSize,
++                                      TRUE,                   //      Zero out the block...
++                                      TRUE,                   //      Can Wait...
++                                      &PtrSIBBCB,
++                                      (PVOID*)&PtrSIBBuffer ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      else
++                      {
++                              VolumeByteOffset.QuadPart = PtrDIBBuffer[SBlockNo] * LogicalBlockSize;
++                              if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                                      &VolumeByteOffset,
++                                                      LogicalBlockSize,
++                                                      TRUE,                   //      Can Wait...
++                                                      &PtrSIBBCB,
++                                                      (PVOID*)&PtrSIBBuffer ) )
++                              {
++                                      try_return( RC = FALSE );
++                              }
++                      }
++                      BlockNo = BlockNo % SingleIndirectBlocks;
++                      
++                      //      Update the inode...
++                      
++                      Inode.i_block[ EXT2_DIND_BLOCK ] = PtrFCB->IBlock[ EXT2_DIND_BLOCK ];
++                      Inode.i_blocks += ( LogicalBlockSize / 512 );
++                      PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize.QuadPart += LogicalBlockSize;
++                      if( UpdateFileSize )
++                      {
++                              Inode.i_size += LogicalBlockSize;
++                              PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart += LogicalBlockSize;
++                      }
++                      if( PtrFileObject->PrivateCacheMap != NULL)
++                      {
++                              //
++                              //      Caching has been initiated...
++                              //      Let the Cache manager in on these changes...
++                              //      
++                              CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
++                      }
++
++                      if( !NT_SUCCESS( Ext2WriteInode( 
++                              PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode  ) ) )
++                      {
++                              try_return (RC = FALSE );
++                      }
++
++                      
++                      //      Update the SIB...
++                      PtrSIBBuffer[ BlockNo ] = NewBlockNo;
++                      CcSetDirtyPinnedData( PtrSIBBCB, NULL );
++                      Ext2SaveBCB( PtrIrpContext, PtrSIBBCB, PtrVCB->PtrStreamFileObject );
++                      Ext2SaveBCB( PtrIrpContext, PtrDIBBCB, PtrVCB->PtrStreamFileObject );
++
++                      try_return (RC = TRUE);
++
++              }
++
++              try_exit:       NOTHING;
++      }
++      finally
++      {
++              if( PtrSIBBCB )
++              {
++                      CcUnpinData( PtrSIBBCB );
++                      PtrSIBBCB = NULL;
++              }
++              if( PtrDIBBCB )
++              {
++                      CcUnpinData( PtrDIBBCB );
++                      PtrDIBBCB = NULL;
++              }
++      }
++      return RC;
++}
++
++/*************************************************************************
++*
++* Function: Ext2AllocBlock()
++*
++* Description:
++*     The functions will allocate a new block 
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++*
++* Return Value: Success / Failure...
++*
++*************************************************************************/
++ULONG Ext2AllocBlock( 
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVCB,
++      ULONG                           Count)
++{
++      //      Buffer Control Block
++      PBCB                    PtrBitmapBCB = NULL;
++      BYTE *                  PtrBitmapBuffer = NULL;
++      ULONG                   BlockNo = 0;
++      LARGE_INTEGER   VolumeByteOffset;
++      ULONG                   LogicalBlockSize = 0;
++      ULONG                   NumberOfBytesToRead = 0;
++
++      if( PtrVCB->FreeBlocksCount == 0 )
++      {
++              //
++              //      No Free Block left...
++              //      Fail request...
++              //
++              return 0;
++      }
++
++      try
++      {
++              BOOLEAN Found = FALSE;
++              ULONG Block;
++              ULONG GroupNo;
++              LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++
++              for( GroupNo = 0; PtrVCB->NoOfGroups; GroupNo++ )
++              {
++                      if( PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount )
++                              break;
++              }
++
++              VolumeByteOffset.QuadPart = 
++                      PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock * LogicalBlockSize;
++              
++              NumberOfBytesToRead = PtrVCB->BlocksCount / PtrVCB->NoOfGroups;
++
++              if( NumberOfBytesToRead % 8 )
++              {
++                      NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) + 1;
++              }
++              else
++              {
++                      NumberOfBytesToRead = ( NumberOfBytesToRead / 8 ) ;
++              }
++              
++              
++              for( Block = 0; !Found && Block < Ext2Align( NumberOfBytesToRead , LogicalBlockSize ); 
++                              Block += LogicalBlockSize, VolumeByteOffset.QuadPart += LogicalBlockSize)                       
++              {
++                      //
++                      //      Read in the block bitmap block...
++                      ULONG i, j;
++                      BYTE Bitmap;
++                                      
++                      if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 LogicalBlockSize,                                    //      NumberOfBytesToRead,
++                                 TRUE,
++                                 &PtrBitmapBCB,
++                                 (PVOID*)&PtrBitmapBuffer ) )
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR, "Cache read failiure while reading in volume meta data", 0);
++                              try_return( BlockNo = 0 );
++                      }
++
++                      //
++                      //      Is there a free block...
++                      //      
++                      for( i = 0; !Found && i < LogicalBlockSize && 
++                                      i + (Block * LogicalBlockSize) < NumberOfBytesToRead; i++ )
++                      {
++                              Bitmap = PtrBitmapBuffer[i];
++                              if( Bitmap != 0xff )
++                              {
++                                      //
++                                      //      Found a free block...
++                                      for( j = 0; !Found && j < 8; j++ )
++                                      {
++                                              if( ( Bitmap & 0x01 ) == 0 )
++                                              {
++                                                      //
++                                                      //      Found...
++                                                      Found = TRUE;
++                                                      BlockNo = ( ( ( Block * LogicalBlockSize) + i ) * 8) + j + 1
++                                                              + ( GroupNo * PtrVCB->BlocksPerGroup );
++
++                                                      Bitmap = 1 << j;
++                                                      PtrBitmapBuffer[i] |= Bitmap;
++                                                      
++                                                      CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
++                                                      Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
++                                                      //
++                                                      //      Should update the bitmaps in the other groups too...
++                                                      //
++                                                      break;
++                                              }
++                                              Bitmap = Bitmap >> 1;
++                                      }
++                              }
++                      }
++                      //
++                      //      Unpin the BCB...
++                      //
++                      if( PtrBitmapBCB )
++                      {
++                              CcUnpinData( PtrBitmapBCB );
++                              PtrBitmapBCB = NULL;
++                      }
++
++              }
++
++              //
++              //      Updating the Free Block count in the Group Descriptor...
++              //      
++              
++              {
++                      PBCB                                    PtrDescriptorBCB = NULL;
++                      PEXT2_GROUP_DESCRIPTOR  PtrGroupDescriptor = NULL;
++                      //
++                      //      Updating the Free Blocks count in the Group Descriptor...
++                      //      
++                      PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount--;
++
++                      if( PtrVCB->LogBlockSize )
++                      {
++                              //      First block contains the descriptors...
++                              VolumeByteOffset.QuadPart = LogicalBlockSize;
++                      }
++                      else
++                      {
++                              //      Second block contains the descriptors...
++                              VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
++                      }
++                      NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
++                      NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
++
++                      if (!CcPinRead( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 NumberOfBytesToRead,
++                                 TRUE,
++                                 &PtrDescriptorBCB ,
++                                 (PVOID*)&PtrGroupDescriptor )) 
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                              //
++                              //      Ignore this error...
++                              //      Not fatal...
++                      }
++                      else
++                      {
++                              PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count= 
++                                      PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount; 
++
++                              //
++                              //      Not synchronously flushing this information...
++                              //      Lazy writing will do...
++                              //
++                              CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
++                              CcUnpinData( PtrDescriptorBCB );
++                              PtrDescriptorBCB = NULL;
++                      }
++              }
++              
++              //
++              //      Update the Block count
++              //      in the super block and in the VCB
++              //
++              {
++                      //      Ext2 Super Block information...
++                      PEXT2_SUPER_BLOCK       PtrSuperBlock = NULL;
++                      PBCB                            PtrSuperBlockBCB = NULL;
++
++                      PtrVCB->FreeBlocksCount--;
++
++                      //      Reading in the super block...
++                      VolumeByteOffset.QuadPart = 1024;
++                      NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
++
++                      if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 NumberOfBytesToRead,
++                                 TRUE,
++                                 &PtrSuperBlockBCB,
++                                 (PVOID*)&PtrSuperBlock ) )
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                      }
++                      else
++                      {
++                              PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount;
++                              CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
++                              Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
++                              if( PtrSuperBlockBCB )
++                              {
++                                      CcUnpinData( PtrSuperBlockBCB );
++                                      PtrSuperBlockBCB = NULL;
++                              }
++                      }
++              }
++
++              try_exit:       NOTHING;
++      }
++      finally
++      {
++              if( PtrBitmapBCB )
++              {
++                      CcUnpinData( PtrBitmapBCB );
++                      PtrBitmapBCB = NULL;
++              }
++              DebugTrace( DEBUG_TRACE_SPECIAL, " Allocating a block - Block no : %ld", BlockNo );
++      }
++      return BlockNo;
++}
++
++/*************************************************************************
++*
++* Function: Ext2DeallocBlock()
++*
++* Description:
++*     The functions will deallocate a data block 
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++* Return Value: Success / Failure...
++*
++*************************************************************************/
++BOOLEAN Ext2DeallocBlock( 
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2VCB                      PtrVCB,
++      ULONG                           BlockNo )
++{
++      //      Buffer Control Block
++      PBCB                    PtrBitmapBCB = NULL;
++      BYTE *                  PtrBitmapBuffer = NULL;
++      BOOLEAN                 RC = TRUE;
++      LARGE_INTEGER   VolumeByteOffset;
++      ULONG                   LogicalBlockSize = 0;
++      //      ULONG                   NumberOfBytesToRead = 0;
++
++      DebugTrace( DEBUG_TRACE_SPECIAL, " Deallocating a block - Block no : %ld", BlockNo );
++      
++      try
++      {
++              ULONG   GroupNo;
++              ULONG   BlockIndex;
++              ULONG   BitmapIndex;
++              BYTE    Bitmap;
++
++              LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++
++              GroupNo = BlockNo / PtrVCB->BlocksPerGroup;
++              BlockNo = BlockNo % PtrVCB->BlocksPerGroup;
++
++              Bitmap = 1 << ( (BlockNo-1) % 8 );
++              BitmapIndex =  (BlockNo-1) / 8;
++              BlockIndex = BitmapIndex / LogicalBlockSize;
++              //      Adjusting to index into the Logical block that contains the bitmap
++              BitmapIndex = BitmapIndex - ( BlockIndex * LogicalBlockSize );
++
++              VolumeByteOffset.QuadPart = 
++                      ( PtrVCB->PtrGroupDescriptors[ GroupNo ].BlockBitmapBlock + BlockIndex ) 
++                      * LogicalBlockSize;
++              
++              //
++              //      Read in the bitmap block...
++              //
++              if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                              &VolumeByteOffset,
++                              LogicalBlockSize,
++                              TRUE,                   //      Can Wait...
++                              &PtrBitmapBCB,
++                              (PVOID*)&PtrBitmapBuffer ) )
++              {
++                      //      Unable to Pin the data into the cache...
++                      try_return (RC = FALSE);
++              }
++
++              //
++              //      Locate the block 'bit'...
++              //      This block 'bit' is in the byte PtrBitmapBuffer[ BitmapIndex ]
++              if( ( PtrBitmapBuffer[ BitmapIndex ] & Bitmap ) == 0)
++              {
++                      //      This shouldn't have been so...
++                      //      The block was never allocated!
++                      //      How to deallocate something that hasn't been allocated? 
++                      //      Hmmm... ;)
++                      //      Ignore this error...
++                      try_return (RC = TRUE);
++              }
++
++              //      Setting the bit for the inode...
++              PtrBitmapBuffer[ BitmapIndex ] &= (~Bitmap);
++
++              //      Update the cache...
++              CcSetDirtyPinnedData( PtrBitmapBCB, NULL );
++
++              //      Save up the BCB for forcing a synchronous write...
++              //      Before completing the IRP...
++              Ext2SaveBCB( PtrIrpContext, PtrBitmapBCB, PtrVCB->PtrStreamFileObject );
++
++
++              if( PtrBitmapBCB )
++              {
++                      CcUnpinData( PtrBitmapBCB );
++                      PtrBitmapBCB = NULL;
++              }
++              
++              //
++              //      Updating the Block count in the Group Descriptor...
++              //      
++              
++              {
++                      PBCB                                    PtrDescriptorBCB = NULL;
++                      PEXT2_GROUP_DESCRIPTOR  PtrGroupDescriptor = NULL;
++                      ULONG                                   NumberOfBytesToRead = 0;
++                      //
++                      //      Updating the Free Blocks count in the Group Descriptor...
++                      //      
++                      PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount++;
++
++                      if( PtrVCB->LogBlockSize )
++                      {
++                              //      First block contains the descriptors...
++                              VolumeByteOffset.QuadPart = LogicalBlockSize;
++                      }
++                      else
++                      {
++                              //      Second block contains the descriptors...
++                              VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
++                      }
++                      NumberOfBytesToRead = PtrVCB->NoOfGroups * sizeof( struct ext2_group_desc );
++                      NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
++
++                      if (!CcPinRead( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 NumberOfBytesToRead,
++                                 TRUE,
++                                 &PtrDescriptorBCB ,
++                                 (PVOID*)&PtrGroupDescriptor )) 
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                              //
++                              //      Ignore this error...
++                              //      Not fatal...
++                      }
++                      else
++                      {
++                              PtrGroupDescriptor[ GroupNo ].bg_free_blocks_count= 
++                                      PtrVCB->PtrGroupDescriptors[ GroupNo ].FreeBlocksCount; 
++
++                              //
++                              //      Not synchronously flushing this information...
++                              //      Lazy writing will do...
++                              //
++                              CcSetDirtyPinnedData( PtrDescriptorBCB, NULL );
++                              CcUnpinData( PtrDescriptorBCB );
++                              PtrDescriptorBCB = NULL;
++                      }
++              }
++
++              //
++              //      Update the Block count
++              //      in the super block and in the VCB
++              //
++              {
++                      //      Ext2 Super Block information...
++                      PEXT2_SUPER_BLOCK       PtrSuperBlock = NULL;
++                      PBCB                            PtrSuperBlockBCB = NULL;
++                      ULONG                           NumberOfBytesToRead = 0;
++
++                      PtrVCB->FreeBlocksCount++;
++
++                      //      Reading in the super block...
++                      VolumeByteOffset.QuadPart = 1024;
++                      NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
++
++                      if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 NumberOfBytesToRead,
++                                 TRUE,
++                                 &PtrSuperBlockBCB,
++                                 (PVOID*)&PtrSuperBlock ) )
++                      {
++                              DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                      }
++                      else
++                      {
++                              PtrSuperBlock->s_free_blocks_count = PtrVCB->FreeBlocksCount;
++                              CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
++                              Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
++                              CcUnpinData( PtrSuperBlockBCB );
++                              PtrSuperBlockBCB = NULL;
++                      }
++              }
++              try_exit:       NOTHING;
++      }
++      finally
++      {
++              if( PtrBitmapBCB )
++              {
++                      CcUnpinData( PtrBitmapBCB );
++                      PtrBitmapBCB = NULL;
++              }
++      }
++      return RC;
++}
++
++BOOLEAN Ext2UpdateFileSize(   
++      PtrExt2IrpContext       PtrIrpContext,
++      PFILE_OBJECT            PtrFileObject,
++      PtrExt2FCB                      PtrFCB)
++{
++      EXT2_INODE                      Inode;
++      PtrExt2VCB                      PtrVCB = PtrFCB->PtrVCB;
++
++      if( PtrFileObject->PrivateCacheMap )
++      {
++              CcSetFileSizes( PtrFileObject, (PCC_FILE_SIZES)&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize));
++      }
++      //      Now update the size on the disk...
++      //      Read in the inode...
++      if( ! NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
++      {
++              return FALSE;
++      }
++
++      Inode.i_size = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
++      //      Update time also???
++
++      //      Updating the inode...
++      if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
++      {
++              return TRUE;
++      }
++      else
++      {
++              return FALSE;
++      }
++}
++
++/*************************************************************************
++*
++* Function: Ext2DeleteFile()
++*
++* Description:
++*     The functions will delete a file
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++* Return Value: Success / Failure...
++*
++*************************************************************************/
++BOOLEAN Ext2DeleteFile(
++      PtrExt2FCB                      PtrFCB,
++      PtrExt2IrpContext       PtrIrpContext)
++{
++      EXT2_INODE                      Inode;
++      PtrExt2FCB                      PtrParentFCB = NULL;
++      PtrExt2VCB                      PtrVCB = PtrFCB->PtrVCB;
++      
++      //
++      //      Get the Parent Directory...
++      PtrParentFCB = Ext2LocateFCBInCore( PtrVCB, PtrFCB->ParentINodeNo );
++      Ext2InitializeFCBInodeInfo( PtrFCB );
++      
++      //      1.
++      //      Free up the directory entry...
++      if( !Ext2FreeDirectoryEntry( PtrIrpContext,
++                      PtrParentFCB, &PtrFCB->FCBName->ObjectName ) )
++      {
++              return FALSE;
++      }
++
++      //      2. 
++      //      Decrement Link count...
++      if( !NT_SUCCESS( Ext2ReadInode( PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
++      {
++              return FALSE;
++      }
++
++      ASSERT( Inode.i_links_count == PtrFCB->LinkCount );
++      
++      Inode.i_links_count--;
++      PtrFCB->LinkCount = Inode.i_links_count; 
++
++      if( !Inode.i_links_count )
++      {
++              //
++              //      Setting the deletion time field in the inode...
++              //
++              ULONG Time;
++              Time = Ext2GetCurrentTime();
++              Inode.i_dtime = Time ;
++      }
++
++      //      3. 
++      //      Updating the inode...
++
++      if( NT_SUCCESS( Ext2WriteInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo, &Inode ) ) )
++      {
++              if( Inode.i_links_count )
++              {
++                      //      Some more links to the same file are available...
++                      //      So we won't deallocate the data blocks...
++                      return TRUE;
++              }
++      }
++      else
++      {
++              return FALSE;
++      }
++
++      //      4.
++      //      Free up the inode...
++      Ext2DeallocInode( PtrIrpContext, PtrVCB, PtrFCB->INodeNo );
++
++      //      5.
++      //      Release the data blocks...
++      Ext2ReleaseDataBlocks( PtrFCB, PtrIrpContext);
++
++      return TRUE;
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2ReleaseDataBlocks()
++*
++* Description:
++*     The functions will release all the data blocks in a file
++*     It does NOT update the file inode... 
++*
++* Expected Interrupt Level (for execution) :
++*  IRQL_PASSIVE_LEVEL 
++*
++* Return Value: Success / Failure...
++*
++*************************************************************************/
++BOOLEAN Ext2ReleaseDataBlocks(
++      PtrExt2FCB                      PtrFCB,
++      PtrExt2IrpContext       PtrIrpContext)
++{
++      PtrExt2VCB                      PtrVCB = PtrFCB->PtrVCB;
++      ULONG LogicalBlockSize;
++      ULONG i;
++
++
++      LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++
++      //      Release the data blocks...
++
++      //      1.
++      //      Free up the triple indirect blocks...
++      if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] )
++      {
++              
++              PBCB                    PtrSIBCB = NULL;
++              PBCB                    PtrDIBCB = NULL;
++              PBCB                    PtrTIBCB = NULL;
++
++              ULONG *                 PtrPinnedSIndirectBlock = NULL;
++              ULONG *                 PtrPinnedDIndirectBlock = NULL;
++              ULONG *                 PtrPinnedTIndirectBlock = NULL;
++              
++              LARGE_INTEGER   VolumeByteOffset;
++              ULONG                   TIndex, DIndex, SIndex;
++
++              //      Pin the Double Indirect Pointer Block...
++              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize;
++              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                 &VolumeByteOffset,
++                 LogicalBlockSize,
++                 TRUE,
++                 &PtrTIBCB,
++                 (PVOID*)&PtrPinnedTIndirectBlock )) 
++              {
++                      return FALSE;
++              }
++
++              //      Read the Block numbers off the Triple Indirect Pointer Block...
++              for( TIndex = 0; TIndex < (LogicalBlockSize/sizeof(ULONG)); TIndex++ )
++              {
++                      if( PtrPinnedTIndirectBlock[ TIndex ] )
++                      {
++                              VolumeByteOffset.QuadPart = PtrPinnedTIndirectBlock[TIndex] * LogicalBlockSize;
++                              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 LogicalBlockSize,
++                                 TRUE,
++                                 &PtrDIBCB,
++                                 (PVOID*)&PtrPinnedDIndirectBlock )) 
++                              {
++                                      return FALSE;
++                              }
++
++                              //      Read the Block numbers off the Double Indirect Pointer Blocks...
++                              for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ )
++                              {
++                                      if( PtrPinnedDIndirectBlock[DIndex] )
++                                      {
++                                              VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize;
++                                              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                                                 &VolumeByteOffset,
++                                                 LogicalBlockSize,
++                                                 TRUE,
++                                                 &PtrSIBCB,
++                                                 (PVOID*)&PtrPinnedSIndirectBlock )) 
++                                              {
++                                                      return FALSE;
++                                              }
++
++                                              //      Read the Block numbers off the Single Indirect Pointer Blocks and 
++                                              //      free the data blocks
++                                              for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ )
++                                              {
++                                                      if( PtrPinnedSIndirectBlock[ SIndex ] )
++                                                      {
++                                                              Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] );
++                                                      }
++                                                      else
++                                                      {
++                                                              break;
++                                                      }
++                                              }
++                                              CcUnpinData( PtrSIBCB );
++                                              
++                                              //      Deallocating
++                                              //      Single Indirect Pointer Block
++                                              Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] );
++                                      }
++                                      else
++                                      {
++                                              break;
++                                      }
++                              }
++                      }
++                      else
++                      {
++                              break;
++                      }
++              }
++              CcUnpinData( PtrTIBCB );
++              //      Deallocating Triple Indirect Pointer Blocks
++              Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_TIND_BLOCK ] );
++      }
++
++      //      2.
++      //      Free up the double indirect blocks...
++      if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] )
++      {
++              PBCB                    PtrDIBCB = NULL;
++              PBCB                    PtrSIBCB = NULL;
++              ULONG *                 PtrPinnedSIndirectBlock = NULL;
++              ULONG *                 PtrPinnedDIndirectBlock = NULL;
++              
++              LARGE_INTEGER   VolumeByteOffset;
++              ULONG                   DIndex, SIndex;
++
++              //      Pin the Double Indirect Pointer Block...
++              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
++              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                 &VolumeByteOffset,
++                 LogicalBlockSize,
++                 TRUE,
++                 &PtrDIBCB,
++                 (PVOID*)&PtrPinnedDIndirectBlock )) 
++              {
++                      return FALSE;
++              }
++
++              //      Read the Block numbers off the Double Indirect Pointer Block...
++              for( DIndex = 0; DIndex < (LogicalBlockSize/sizeof(ULONG)); DIndex++ )
++              {
++                      if( PtrPinnedDIndirectBlock[DIndex] )
++                      {
++                              VolumeByteOffset.QuadPart = PtrPinnedDIndirectBlock[DIndex] * LogicalBlockSize;
++                              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 LogicalBlockSize,
++                                 TRUE,
++                                 &PtrSIBCB,
++                                 (PVOID*)&PtrPinnedSIndirectBlock )) 
++                              {
++                                      return FALSE;
++                              }
++
++                              //      Read the Block numbers off the Single Indirect Pointer Blocks and 
++                              //      free the data blocks
++                              for( SIndex = 0; SIndex < (LogicalBlockSize/sizeof(ULONG)); SIndex++ )
++                              {
++                                      if( PtrPinnedSIndirectBlock[ SIndex ] )
++                                      {
++                                              Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[SIndex] );
++                                      }
++                                      else
++                                      {
++                                              break;
++                                      }
++                              }
++                              CcUnpinData( PtrSIBCB );
++                              
++                              //      Deallocating
++                              //      Single Indirect Pointer Block
++                              Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedDIndirectBlock[DIndex] );
++                      }
++                      else
++                      {
++                              break;
++                      }
++              }
++              CcUnpinData( PtrDIBCB );
++              //      Deallocating Double Indirect Pointer Blocks
++              Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_DIND_BLOCK ] );
++      }
++
++      //      3.
++      //      Free up the single indirect blocks...
++      if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] )
++      {
++              PBCB                    PtrBCB = NULL;
++              ULONG *                 PtrPinnedSIndirectBlock = NULL;
++              LARGE_INTEGER   VolumeByteOffset;
++              ULONG                   Index;
++
++              //      Pin the Single Indirect Pointer Block...
++              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
++              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                 &VolumeByteOffset,
++                 LogicalBlockSize,
++                 TRUE,
++                 &PtrBCB,
++                 (PVOID*)&PtrPinnedSIndirectBlock )) 
++              {
++                      return FALSE;
++              }
++
++              //      Read the Block numbers off the Indirect Pointer Block and 
++              //      free the data blocks
++              for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); Index++ )
++              {
++                      if( PtrPinnedSIndirectBlock[Index] )
++                      {
++                              Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] );
++                      }
++                      else
++                      {
++                              break;
++                      }
++              }
++              CcUnpinData( PtrBCB );
++              Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] );
++      }
++
++      //      4.
++      //      Free up the direct blocks...
++      for( i = 0; i < EXT2_NDIR_BLOCKS; i++ )
++      {
++              if( PtrFCB->IBlock[ i ] )
++              {
++                      Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] );
++              }
++              else
++              {
++                      break;
++              }
++      }
++      return TRUE;
++}
++
++
++BOOLEAN Ext2TruncateFileAllocationSize(
++      PtrExt2IrpContext       PtrIrpContext,
++      PtrExt2FCB                      PtrFCB,
++      PFILE_OBJECT            PtrFileObject,
++      PLARGE_INTEGER          PtrAllocationSize )
++{
++      PtrExt2VCB                      PtrVCB = PtrFCB->PtrVCB;
++      ULONG LogicalBlockSize;
++      ULONG i;
++
++      ULONG NoOfBlocksToBeLeft= 0;
++      ULONG CurrentBlockNo = 0;
++
++      //
++      //      This function has not been tested...
++      //
++      Ext2BreakPoint();
++
++      LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++      NoOfBlocksToBeLeft = (ULONG) (PtrAllocationSize->QuadPart / LogicalBlockSize);
++
++      
++
++      //      Release the data blocks...
++
++      //      1.
++      //      Free up the direct blocks...
++      for( i = NoOfBlocksToBeLeft; i < EXT2_NDIR_BLOCKS; i++ )
++      {
++              if( PtrFCB->IBlock[ i ] )
++              {
++                      Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ i ] );
++                      PtrFCB->IBlock[ i ] = 0;
++              }
++              else
++              {
++                      break;
++              }
++      }
++
++      //      2.
++      //      Free up the single indirect blocks...
++      CurrentBlockNo = EXT2_NDIR_BLOCKS;
++
++      if( PtrFCB->IBlock[ EXT2_IND_BLOCK ] )
++      {
++              PBCB                    PtrBCB = NULL;
++              ULONG *                 PtrPinnedSIndirectBlock = NULL;
++              LARGE_INTEGER   VolumeByteOffset;
++              ULONG                   Index;
++
++              //      Pin the Single Indirect Pointer Block...
++              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
++              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                 &VolumeByteOffset,
++                 LogicalBlockSize,
++                 TRUE,
++                 &PtrBCB,
++                 (PVOID*)&PtrPinnedSIndirectBlock )) 
++              {
++                      return FALSE;
++              }
++
++              //      Read the Block numbers off the Indirect Pointer Block and 
++              //      free the data blocks
++              for( Index = 0; Index < (LogicalBlockSize/sizeof(ULONG)); 
++                       Index++, CurrentBlockNo++ )
++              {
++                      if( CurrentBlockNo >= NoOfBlocksToBeLeft )
++                      {
++                              if( PtrPinnedSIndirectBlock[Index] )
++                              {
++                                      Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrPinnedSIndirectBlock[Index] );
++                              }
++                              else
++                              {
++                                      break;
++                              }
++                      }
++                      else if( !PtrPinnedSIndirectBlock[Index] )
++                      {
++                              break;
++                      }
++              }
++              if( NoOfBlocksToBeLeft <= EXT2_NDIR_BLOCKS )
++              {
++                      Ext2DeallocBlock( PtrIrpContext, PtrVCB, PtrFCB->IBlock[ EXT2_IND_BLOCK ] );
++                      PtrFCB->IBlock[ EXT2_IND_BLOCK ] = 0;
++              }
++
++              CcUnpinData( PtrBCB );
++      }
++      
++      //      3.
++      //      Free up the double indirect blocks...
++      if( PtrFCB->IBlock[ EXT2_DIND_BLOCK ] )
++      {
++              
++      }
++
++      //      4.
++      //      Free up the triple indirect blocks...
++      if( PtrFCB->IBlock[ EXT2_TIND_BLOCK ] )
++      {
++              
++      }
++
++      return TRUE;
++}
++
++BOOLEAN Ext2IsDirectoryEmpty(
++      PtrExt2FCB                      PtrFCB,
++      PtrExt2CCB                      PtrCCB,
++      PtrExt2IrpContext       PtrIrpContext)
++{
++
++      PFILE_OBJECT            PtrFileObject = NULL;
++
++      if( !Ext2IsFlagOn(PtrFCB->FCBFlags, EXT2_FCB_DIRECTORY) )
++      {
++              return FALSE;
++      }
++
++      //      1. 
++      //      Initialize the Blocks in the FCB...
++      //
++      Ext2InitializeFCBInodeInfo( PtrFCB );
++
++      
++      //      2.
++      //      Get hold of the file object...
++      //
++      PtrFileObject = PtrCCB->PtrFileObject;
++
++
++      //      3.
++      //      Now initiating Caching, pinned access to be precise ...
++      //
++      if (PtrFileObject->PrivateCacheMap == NULL) 
++      {
++              CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
++                      TRUE,           // We utilize pin access for directories
++                      &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
++                      PtrFCB );               // The context used in callbacks
++      }
++
++      //      4.
++      //      Getting down to the real business now... ;)
++      //      Read in the directory contents and do a search 
++      //
++      {
++              LARGE_INTEGER   StartBufferOffset;
++              ULONG                   PinBufferLength;
++              ULONG                   BufferIndex;
++              PBCB                    PtrBCB = NULL;
++              BYTE *                  PtrPinnedBlockBuffer = NULL;
++              PEXT2_DIR_ENTRY PtrDirEntry = NULL;
++              BOOLEAN                 Found = FALSE;
++              int                             i;
++
++
++
++              StartBufferOffset.QuadPart = 0;
++
++              //
++              //      Read in the whole directory
++              //      **Bad programming**
++              //      Will do for now.
++              //
++              PinBufferLength = PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
++              if (!CcMapData( PtrFileObject,
++                  &StartBufferOffset,
++                  PinBufferLength,
++                  TRUE,
++                  &PtrBCB,
++                  (PVOID*)&PtrPinnedBlockBuffer ) )
++              {
++                      return FALSE;
++              }
++              
++              //
++              //      Walking through now...
++              //
++              for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len )
++              {
++                      PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ];
++                      if( PtrDirEntry->inode == 0)
++                      {
++                              //      Deleted entry...
++                              //  Ignore...
++                              continue;
++                      }
++                      if( PtrDirEntry->name[0] == '.' )
++                      {
++                              if( PtrDirEntry->name_len == 1 || 
++                                ( PtrDirEntry->name_len == 2 && PtrDirEntry->name[1] == '.' ) )
++                              {
++                                continue;
++                              }
++                      }
++                      Found = TRUE;
++              }
++              CcUnpinData( PtrBCB );
++              PtrBCB = NULL;
++
++              return !Found;
++      }
++}
++
++
++NTSTATUS Ext2RenameOrLinkFile( 
++      PtrExt2FCB                                      PtrSourceFCB, 
++      PFILE_OBJECT                            PtrSourceFileObject,    
++      PtrExt2IrpContext                       PtrIrpContext,
++      PIRP                                            PtrIrp, 
++      PFILE_RENAME_INFORMATION        PtrRenameInfo)
++{
++      PtrExt2FCB                              PtrParentFCB = NULL;
++      PtrExt2VCB                              PtrSourceVCB = PtrSourceFCB->PtrVCB;
++
++      PtrExt2FCB                              PtrTargetFCB = NULL;
++      PtrExt2CCB                              PtrTargetCCB = NULL;
++      PtrExt2VCB                              PtrTargetVCB = NULL;
++
++
++      FILE_INFORMATION_CLASS  FunctionalityRequested;
++      PIO_STACK_LOCATION              PtrIoStackLocation = NULL;
++      PFILE_OBJECT                    TargetFileObject = NULL;
++      BOOLEAN                                 ReplaceExistingFile = FALSE;
++      BOOLEAN                                 Found = FALSE;
++
++      PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
++      FunctionalityRequested = PtrIoStackLocation->Parameters.SetFile.FileInformationClass;
++      TargetFileObject = PtrIoStackLocation->Parameters.SetFile.FileObject;
++      ReplaceExistingFile = PtrIoStackLocation->Parameters.SetFile.ReplaceIfExists;
++
++      // Get the FCB and CCB pointers
++      Ext2GetFCB_CCB_VCB_FromFileObject ( 
++              TargetFileObject , &PtrTargetFCB, &PtrTargetCCB, &PtrTargetVCB);
++
++      if( !PtrTargetCCB )
++      {
++              return STATUS_ACCESS_DENIED;
++      }
++      if( PtrTargetVCB != PtrSourceVCB )
++      {
++              //      Cannot rename across volumes...
++              return STATUS_ACCESS_DENIED;
++      }
++      if ( !Ext2IsFlagOn( PtrTargetFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
++      {
++              //      Target has to be a folder...
++              return STATUS_ACCESS_DENIED;
++      }
++
++      //      1.
++      //      Open the parent folder...
++      PtrParentFCB = Ext2LocateFCBInCore( PtrSourceVCB, PtrSourceFCB->ParentINodeNo );
++      if( !PtrParentFCB )
++      {
++              //      Get the folder from the disk
++              //      Use the inode no PtrSourceFCB->ParentINodeNo
++              //
++              //      For now...
++              return STATUS_ACCESS_DENIED;
++      }
++
++      //      2.
++      //      Check if the file exists in the TargetFolder...
++      {
++              LARGE_INTEGER   StartBufferOffset;
++              ULONG                   PinBufferLength;
++              ULONG                   BufferIndex;
++              PBCB                    PtrBCB = NULL;
++              BYTE *                  PtrPinnedBlockBuffer = NULL;
++              PEXT2_DIR_ENTRY PtrDirEntry = NULL;
++              int                             i;
++
++              StartBufferOffset.QuadPart = 0;
++
++              //
++              //      Read in the whole directory
++              //
++              if ( TargetFileObject->PrivateCacheMap == NULL )
++              {
++                      CcInitializeCacheMap(
++                              TargetFileObject, 
++                              (PCC_FILE_SIZES)(&(PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.AllocationSize)),
++                              TRUE,                                                                   // We utilize pin access for directories
++                              &(Ext2GlobalData.CacheMgrCallBacks),    // callbacks
++                              PtrTargetCCB );                                                 // The context used in callbacks
++              }
++              
++              PinBufferLength = PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.LowPart;
++              if (!CcMapData( TargetFileObject,
++                  &StartBufferOffset,
++                  PinBufferLength,
++                  TRUE,
++                  &PtrBCB,
++                  (PVOID*)&PtrPinnedBlockBuffer ) )
++              {
++                      return FALSE;
++              }
++              
++              //
++              //      Walking through now...
++              //
++              for( BufferIndex = 0, Found = FALSE; !Found && BufferIndex < ( PtrTargetFCB->NTRequiredFCB.CommonFCBHeader.FileSize.QuadPart - 1) ; BufferIndex += PtrDirEntry->rec_len )
++              {
++                      PtrDirEntry = (PEXT2_DIR_ENTRY) &PtrPinnedBlockBuffer[ BufferIndex ];
++                      if( PtrDirEntry->inode == 0)
++                      {
++                              //      Deleted entry...
++                              //  Ignore...
++                              continue;
++                      }
++                      if( PtrDirEntry->name_len == (PtrTargetCCB->RenameLinkTargetFileName.Length/2) )
++                      {
++                              Found = TRUE;
++                              for( i =0; i < PtrDirEntry->name_len ; i++ )
++                              {
++                                      if( PtrDirEntry->name[i] != PtrTargetCCB->RenameLinkTargetFileName.Buffer[i] )
++                                      {
++                                              Found = FALSE;
++                                              break;
++                                      }
++                              }
++                      }
++              }
++              CcUnpinData( PtrBCB );
++              PtrBCB = NULL;
++      }
++
++      //      3.
++      //      If the file exists, delete it if requested..
++      if( Found )
++      {
++              if( !ReplaceExistingFile )
++              {
++                      return STATUS_OBJECT_NAME_COLLISION;
++              }
++              //      Delete the file...
++              //      Reject this for now...
++              return STATUS_ACCESS_DENIED;
++      }
++
++
++      {
++              ULONG   Type = EXT2_FT_REG_FILE;
++              if( Ext2IsFlagOn( PtrSourceFCB->FCBFlags, EXT2_FCB_DIRECTORY ) )
++              {
++                      Type = EXT2_FT_DIR;
++              }
++
++              ASSERT( TargetFileObject );
++
++              //      4.
++              //      Remove the old entry...
++              Ext2FreeDirectoryEntry( PtrIrpContext, PtrParentFCB,
++                              &PtrSourceFCB->FCBName->ObjectName);
++
++              //      5. 
++              //      Create a new entry...
++              Ext2MakeNewDirectoryEntry(
++                      PtrIrpContext,                          //      This IRP Context
++                      PtrTargetFCB,                           //      Parent Folder FCB
++                      TargetFileObject,                       //      Parent Folder Object
++                      &PtrTargetCCB->RenameLinkTargetFileName, //     New entry's name
++                      Type,                                           //      The type of the new entry
++                      PtrSourceFCB->INodeNo );        //      The inode no of the new entry...
++
++      }
++
++      //      6. 
++      //      Update the PtrSourceFCB...
++      {
++
++              PtrExt2ObjectName               PtrObjectName;
++              if( PtrSourceFCB->FCBName )
++              {
++                      Ext2ReleaseObjectName( PtrSourceFCB->FCBName );
++              }
++              PtrObjectName = Ext2AllocateObjectName();
++              Ext2CopyUnicodeString( &PtrObjectName->ObjectName, &PtrTargetCCB->RenameLinkTargetFileName ); 
++              PtrSourceFCB->FCBName = PtrObjectName;
++              PtrSourceFCB->ParentINodeNo = PtrTargetFCB->INodeNo;
++      }
++
++      if( PtrTargetCCB->RenameLinkTargetFileName.Length )
++      {
++              Ext2DeallocateUnicodeString( &PtrTargetCCB->RenameLinkTargetFileName );
++      }
++
++      return STATUS_SUCCESS;
++}
index 0000000,fd9c980..fd9c980
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,2116 +1,2116 @@@
+ /*************************************************************************
+ *
+ * File: misc.c
+ *
+ * Module: Ext2 File System Driver (Kernel mode execution only)
+ *
+ * Description:
+ *     This file contains some miscellaneous support routines.
+ *
+ * Author: Manoj Paul Joseph
+ *
+ *
+ *************************************************************************/
+ #include                      "ext2fsd.h"
+ // define the file specific bug-check id
+ #define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_MISC
+ #define                       DEBUG_LEVEL                                             ( DEBUG_TRACE_MISC )
+ /*************************************************************************
+ *
+ * Function: Ext2InitializeZones()
+ *
+ * Description:
+ *     Allocates some memory for global zones used to allocate FSD structures.
+ *     Either all memory will be allocated or we will back out gracefully.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS Ext2InitializeZones(
+ void)
+ {
+       NTSTATUS                        RC = STATUS_SUCCESS;
+       uint32                          SizeOfZone = Ext2GlobalData.DefaultZoneSizeInNumStructs;
+       uint32                          SizeOfObjectNameZone = 0;
+       uint32                          SizeOfCCBZone = 0;
+       uint32                          SizeOfFCBZone = 0;
+       uint32                          SizeOfByteLockZone = 0;
+       uint32                          SizeOfIrpContextZone = 0;
+       try {
+               // initialize the spinlock protecting the zones
+               KeInitializeSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock));
+               // determine memory requirements
+               switch (MmQuerySystemSize()) {
+               case MmSmallSystem:
+                       // this is just for illustration purposes. I will multiply
+                       //      number of structures with some arbitrary amount depending
+                       //      upon available memory in the system ... You should choose a
+                       // more intelligent method suitable to your memory consumption
+                       // and the amount of memory available.
+                       SizeOfObjectNameZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfCCBZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfFCBZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfByteLockZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfIrpContextZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
+                       break;
+               case MmMediumSystem:
+                       SizeOfObjectNameZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfCCBZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfFCBZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfByteLockZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfIrpContextZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
+                       break;
+               case MmLargeSystem:
+                       SizeOfObjectNameZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfCCBZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfFCBZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfByteLockZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER);
+                       SizeOfIrpContextZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
+                       break;
+               }
+               // typical NT methodology (at least until *someone* exposed the "difference" between a server and workstation ;-)
+               if (MmIsThisAnNtAsSystem()) {
+                       SizeOfObjectNameZone *= EXT2_NTAS_MULTIPLE;
+                       SizeOfCCBZone *= EXT2_NTAS_MULTIPLE;
+                       SizeOfFCBZone *= EXT2_NTAS_MULTIPLE;
+                       SizeOfByteLockZone *= EXT2_NTAS_MULTIPLE;
+                       SizeOfIrpContextZone *= EXT2_NTAS_MULTIPLE;
+               }
+               // allocate memory for each of the zones and initialize the     zones ...
+               if (!(Ext2GlobalData.ObjectNameZone = Ext2AllocatePool(NonPagedPool, SizeOfObjectNameZone ))) {
+                       RC = STATUS_INSUFFICIENT_RESOURCES;
+                       try_return(RC);
+               }
+               if (!(Ext2GlobalData.CCBZone = Ext2AllocatePool(NonPagedPool, SizeOfCCBZone ))) {
+                       RC = STATUS_INSUFFICIENT_RESOURCES;
+                       try_return(RC);
+               }
+               if (!(Ext2GlobalData.FCBZone = Ext2AllocatePool(NonPagedPool, SizeOfFCBZone ))) {
+                       RC = STATUS_INSUFFICIENT_RESOURCES;
+                       try_return(RC);
+               }
+               if (!(Ext2GlobalData.ByteLockZone = Ext2AllocatePool(NonPagedPool, SizeOfByteLockZone ))) {
+                       RC = STATUS_INSUFFICIENT_RESOURCES;
+                       try_return(RC);
+               }
+               if (!(Ext2GlobalData.IrpContextZone = Ext2AllocatePool(NonPagedPool, SizeOfIrpContextZone ))) {
+                       RC = STATUS_INSUFFICIENT_RESOURCES;
+                       try_return(RC);
+               }
+               // initialize each of the zone headers ...
+               if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.ObjectNameZoneHeader),
+                                       Ext2QuadAlign(sizeof(Ext2ObjectName)),
+                                       Ext2GlobalData.ObjectNameZone, SizeOfObjectNameZone))) {
+                       // failed the initialization, leave ...
+                       try_return(RC);
+               }
+               if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.CCBZoneHeader),
+                                       Ext2QuadAlign(sizeof(Ext2CCB)),
+                                       Ext2GlobalData.CCBZone,
+                                       SizeOfCCBZone))) {
+                       // failed the initialization, leave ...
+                       try_return(RC);
+               }
+               if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.FCBZoneHeader),
+                                       Ext2QuadAlign(sizeof(Ext2FCB)),
+                                       Ext2GlobalData.FCBZone,
+                                       SizeOfFCBZone))) {
+                       // failed the initialization, leave ...
+                       try_return(RC);
+               }
+               if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.ByteLockZoneHeader),
+                                       Ext2QuadAlign(sizeof(Ext2FileLockInfo)),
+                                       Ext2GlobalData.ByteLockZone,
+                                       SizeOfByteLockZone))) {
+                       // failed the initialization, leave ...
+                       try_return(RC);
+               }
+               if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.IrpContextZoneHeader),
+                                       Ext2QuadAlign(sizeof(Ext2IrpContext)),
+                                       Ext2GlobalData.IrpContextZone,
+                                       SizeOfIrpContextZone))) {
+                       // failed the initialization, leave ...
+                       try_return(RC);
+               }
+               try_exit:       NOTHING;
+       } finally {
+               if (!NT_SUCCESS(RC)) {
+                       // invoke the destroy routine now ...
+                       Ext2DestroyZones();
+               } else {
+                       // mark the fact that we have allocated zones ...
+                       Ext2SetFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_ZONES_INITIALIZED);
+               }
+       }
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2DestroyZones()
+ *
+ * Description:
+ *     Free up the previously allocated memory. NEVER do this once the
+ *     driver has been successfully loaded.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2DestroyZones(
+ void)
+ {
+       try {
+               // free up each of the pools
+               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", Ext2GlobalData.ObjectNameZone);
+               ExFreePool(Ext2GlobalData.ObjectNameZone);
+               
+               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", Ext2GlobalData.CCBZone);
+               ExFreePool(Ext2GlobalData.CCBZone);
+               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", Ext2GlobalData.FCBZone);
+               ExFreePool(Ext2GlobalData.FCBZone);
+               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", Ext2GlobalData.ByteLockZone);
+               ExFreePool(Ext2GlobalData.ByteLockZone);
+               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", Ext2GlobalData.IrpContextZone);
+               ExFreePool(Ext2GlobalData.IrpContextZone);
+               try_exit:       NOTHING;
+       } 
+       finally 
+       {
+               Ext2ClearFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_ZONES_INITIALIZED);
+       }
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2IsIrpTopLevel()
+ *
+ * Description:
+ *     Helps the FSD determine who the "top level" caller is for this
+ *     request. A request can originate directly from a user process
+ *     (in which case, the "top level" will be NULL when this routine
+ *     is invoked), OR the user may have originated either from the NT
+ *     Cache Manager/VMM ("top level" may be set), or this could be a
+ *     recursion into our code in which we would have set the "top level"
+ *     field the last time around.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  whatever level a particular dispatch routine is invoked at.
+ *
+ * Return Value: TRUE/FALSE (TRUE if top level was NULL when routine invoked)
+ *
+ *************************************************************************/
+ BOOLEAN Ext2IsIrpTopLevel(
+ PIRP                  Irp)                    // the IRP sent to our dispatch routine
+ {
+       BOOLEAN                 ReturnCode = FALSE;
+       if (IoGetTopLevelIrp() == NULL) 
+       {
+               // OK, so we can set ourselves to become the "top level" component
+               IoSetTopLevelIrp( Irp );
+               ReturnCode = TRUE;
+       }
+       return(ReturnCode);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2ExceptionFilter()
+ *
+ * Description:
+ *     This routines allows the driver to determine whether the exception
+ *     is an "allowed" exception i.e. one we should not-so-quietly consume
+ *     ourselves, or one which should be propagated onwards in which case
+ *     we will most likely bring down the machine.
+ *
+ *     This routine employs the services of FsRtlIsNtstatusExpected(). This
+ *     routine returns a BOOLEAN result. A RC of FALSE will cause us to return
+ *     EXCEPTION_CONTINUE_SEARCH which will probably cause a panic.
+ *     The FsRtl.. routine returns FALSE iff exception values are (currently) :
+ *             STATUS_DATATYPE_MISALIGNMENT    ||      STATUS_ACCESS_VIOLATION ||
+ *             STATUS_ILLEGAL_INSTRUCTION      ||      STATUS_INSTRUCTION_MISALIGNMENT
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  ?
+ *
+ * Return Value: EXCEPTION_EXECUTE_HANDLER/EXECEPTION_CONTINUE_SEARCH
+ *
+ *************************************************************************/
+ long Ext2ExceptionFilter(
+ PtrExt2IrpContext                     PtrIrpContext,
+ PEXCEPTION_POINTERS                   PtrExceptionPointers )
+ {
+       long                                                    ReturnCode = EXCEPTION_EXECUTE_HANDLER;
+       NTSTATUS                                                ExceptionCode = STATUS_SUCCESS;
+       // figure out the exception code
+       ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionCode;
+       if ((ExceptionCode == STATUS_IN_PAGE_ERROR) && (PtrExceptionPointers->ExceptionRecord->NumberParameters >= 3)) 
+       {
+               ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionInformation[2];
+       }
+       if (PtrIrpContext) 
+       {
+               PtrIrpContext->SavedExceptionCode = ExceptionCode;
+               Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_EXCEPTION);
+       }
+       // check if we should propagate this exception or not
+       if (!(FsRtlIsNtstatusExpected(ExceptionCode))) 
+       {
+               // we are not ok, propagate this exception.
+               //      NOTE: we will bring down the machine ...
+               ReturnCode = EXCEPTION_CONTINUE_SEARCH;
+               // better free up the IrpContext now ...
+               if (PtrIrpContext) 
+               {
+                       Ext2ReleaseIrpContext(PtrIrpContext);
+               }
+       }
+       // if you wish to perform some special processing when
+       //      not propagating the exception, set up the state for
+       //      special processing now ...
+       // return the appropriate code
+       return(ReturnCode);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2ExceptionHandler()
+ *
+ * Description:
+ *     One of the routines in the FSD or in the modules we invoked encountered
+ *     an exception. We have decided that we will "handle" the exception.
+ *     Therefore we will prevent the machine from a panic ...
+ *     You can do pretty much anything you choose to in your commercial
+ *     driver at this point to ensure a graceful exit. In the sample
+ *     driver, I will simply free up the IrpContext (if any), set the
+ *     error code in the IRP and complete the IRP at this time ...
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  ?
+ *
+ * Return Value: Error code
+ *
+ *************************************************************************/
+ NTSTATUS Ext2ExceptionHandler(
+ PtrExt2IrpContext                             PtrIrpContext,
+ PIRP                                                          Irp)
+ {
+       NTSTATUS                                                RC;
+       ASSERT(Irp);
+       if (PtrIrpContext) 
+       {
+               RC = PtrIrpContext->SavedExceptionCode;
+               // Free irp context here
+               Ext2ReleaseIrpContext(PtrIrpContext);
+       } 
+       else 
+       {
+               // must be insufficient resources ...?
+               RC = STATUS_INSUFFICIENT_RESOURCES;
+       }
+       // set the error code in the IRP
+       Irp->IoStatus.Status = RC;
+       Irp->IoStatus.Information = 0;
+       // complete the IRP
+       IoCompleteRequest(Irp, IO_NO_INCREMENT);
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2LogEvent()
+ *
+ * Description:
+ *     Log a message in the NT Event Log. This is a rather simplistic log
+ *     methodology since you can potentially utilize the event log to
+ *     provide a lot of information to the user (and you should too!)
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2LogEvent(
+ NTSTATUS                                      Ext2EventLogId,         // the Ext2 private message id
+ NTSTATUS                                      RC)                                             // any NT error code we wish to log ...
+ {
+       try
+       {
+               // Implement a call to IoAllocateErrorLogEntry() followed by a call
+               // to IoWriteErrorLogEntry(). You should note that the call to IoWriteErrorLogEntry()
+               // will free memory for the entry once the write completes (which in actuality
+               // is an asynchronous operation).
+       } 
+       except (EXCEPTION_EXECUTE_HANDLER) 
+       {
+               // nothing really we can do here, just do not wish to crash ...
+               NOTHING;
+       }
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2AllocateObjectName()
+ *
+ * Description:
+ *     Allocate a new ObjectName structure to represent an open on-disk object.
+ *     Also initialize the ObjectName structure to NULL.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: A pointer to the ObjectName structure OR NULL.
+ *
+ *************************************************************************/
+ PtrExt2ObjectName Ext2AllocateObjectName(
+ void)
+ {
+       PtrExt2ObjectName                       PtrObjectName = NULL;
+       BOOLEAN                                         AllocatedFromZone = TRUE;
+    KIRQL                                                      CurrentIrql;
+ /*
+       // first, try to allocate out of the zone
+       KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
+       if (!ExIsFullZone(&(Ext2GlobalData.ObjectNameZoneHeader))) {
+               // we have enough memory
+               PtrObjectName = (PtrExt2ObjectName)ExAllocateFromZone(&(Ext2GlobalData.ObjectNameZoneHeader));
+               // release the spinlock
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       } else {
+               // release the spinlock
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+               // if we failed to obtain from the zone, get it directly from the VMM
+ */
+               PtrObjectName = (PtrExt2ObjectName)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2ObjectName)) );
+               AllocatedFromZone = FALSE;
+ /*
+       }
+ */
+       // if we could not obtain the required memory, bug-check.
+       //      Do NOT do this in your commercial driver, instead handle the error gracefully ...
+       if (!PtrObjectName) 
+       {
+               Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2ObjectName)), 0);
+       }
+       // zero out the allocated memory block
+       RtlZeroMemory( PtrObjectName, Ext2QuadAlign(sizeof(Ext2ObjectName)) );
+       // set up some fields ...
+       PtrObjectName->NodeIdentifier.NodeType  = EXT2_NODE_TYPE_OBJECT_NAME;
+       PtrObjectName->NodeIdentifier.NodeSize  = Ext2QuadAlign(sizeof(Ext2ObjectName));
+       if (!AllocatedFromZone) 
+       {
+               Ext2SetFlag(PtrObjectName->ObjectNameFlags, EXT2_OB_NAME_NOT_FROM_ZONE);
+       }
+       return(PtrObjectName);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2ReleaseObjectName()
+ *
+ * Description:
+ *     Deallocate a previously allocated structure.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2ReleaseObjectName(
+ PtrExt2ObjectName                             PtrObjectName)
+ {
+       KIRQL                                                   CurrentIrql;
+       ASSERT(PtrObjectName);
+       PtrObjectName->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED;
+ #ifdef USE_ZONES
+       // give back memory either to the zone or to the VMM
+       if (!(PtrObjectName->ObjectNameFlags & EXT2_OB_NAME_NOT_FROM_ZONE)) 
+       {
+               // back to the zone
+               KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
+               ExFreeToZone(&(Ext2GlobalData.ObjectNameZoneHeader), PtrObjectName);
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       } 
+       else 
+       {
+ #endif
+       
+       Ext2DeallocateUnicodeString( & PtrObjectName->ObjectName );
+       DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", PtrObjectName);
+       ExFreePool(PtrObjectName);
+ #ifdef USE_ZONES      
+       }
+ #endif
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2AllocateCCB()
+ *
+ * Description:
+ *     Allocate a new CCB structure to represent an open on-disk object.
+ *     Also initialize the CCB structure to NULL.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: A pointer to the CCB structure OR NULL.
+ *
+ *************************************************************************/
+ PtrExt2CCB Ext2AllocateCCB(
+ void)
+ {
+       PtrExt2CCB                                      PtrCCB = NULL;
+       BOOLEAN                                         AllocatedFromZone = TRUE;
+    KIRQL                                                      CurrentIrql;
+ #ifdef USE_ZONES
+    // first, try to allocate out of the zone
+       KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
+       if (!ExIsFullZone(&(Ext2GlobalData.CCBZoneHeader))) 
+       {
+               // we have enough memory
+               PtrCCB = (PtrExt2CCB)ExAllocateFromZone(&(Ext2GlobalData.CCBZoneHeader));
+               // release the spinlock
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       } 
+       else 
+       {
+               // release the spinlock
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+               // if we failed to obtain from the zone, get it directly from the VMM
+ #endif
+               PtrCCB = (PtrExt2CCB)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2CCB)) );
+               AllocatedFromZone = FALSE;
+ #ifdef USE_ZONES
+       }
+ #endif
+       // if we could not obtain the required memory, bug-check.
+       //      Do NOT do this in your commercial driver, instead handle the error gracefully ...
+       if (!PtrCCB) 
+       {
+               Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2CCB)), 0);
+       }
+       // zero out the allocated memory block
+       RtlZeroMemory(PtrCCB, Ext2QuadAlign(sizeof(Ext2CCB)));
+       // set up some fields ...
+       PtrCCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_CCB;
+       PtrCCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2CCB));
+       if (!AllocatedFromZone) 
+       {
+               Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_NOT_FROM_ZONE);
+       }
+       return(PtrCCB);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2ReleaseCCB()
+ *
+ * Description:
+ *     Deallocate a previously allocated structure.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2ReleaseCCB(
+ PtrExt2CCB                                            PtrCCB)
+ {
+       KIRQL                                                   CurrentIrql;
+       ASSERT( PtrCCB );
+       if(PtrCCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_CCB)
+       {
+               Ext2Panic( PtrCCB, PtrCCB->NodeIdentifier.NodeType, EXT2_NODE_TYPE_CCB )        ;
+       }
+       Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern );
+       Ext2DeallocateUnicodeString( &PtrCCB->AbsolutePathName );
+       Ext2DeallocateUnicodeString( &PtrCCB->RenameLinkTargetFileName );
+       
+ #ifdef USE_ZONES
+       
+       // give back memory either to the zone or to the VMM
+       if (!(PtrCCB->CCBFlags & EXT2_CCB_NOT_FROM_ZONE)) 
+       {
+               // back to the zone
+               KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
+               ExFreeToZone(&(Ext2GlobalData.CCBZoneHeader), PtrCCB);
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       }
+       else
+       {
+ #endif
+               PtrCCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED;
+               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", PtrCCB);
+               ExFreePool(PtrCCB);
+ #ifdef USE_ZONES
+       }
+ #endif
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2AllocateFCB()
+ *
+ * Description:
+ *     Allocate a new FCB structure to represent an open on-disk object.
+ *     Also initialize the FCB structure to NULL.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: A pointer to the FCB structure OR NULL.
+ *
+ *************************************************************************/
+ PtrExt2FCB Ext2AllocateFCB(
+ void)
+ {
+       PtrExt2FCB                                      PtrFCB = NULL;
+       BOOLEAN                                         AllocatedFromZone = TRUE;
+       KIRQL                                           CurrentIrql;
+       // first, try to allocate out of the zone
+ #ifdef USE_ZONES
+       KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
+       if (!ExIsFullZone(&(Ext2GlobalData.FCBZoneHeader))) {
+               // we have enough memory
+               PtrFCB = (PtrExt2FCB)ExAllocateFromZone(&(Ext2GlobalData.FCBZoneHeader));
+               // release the spinlock
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       } else {
+               // release the spinlock
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+ #endif
+               // if we failed to obtain from the zone, get it directly from the VMM
+               PtrFCB = (PtrExt2FCB)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2FCB)) );
+               AllocatedFromZone = FALSE;
+ #ifdef USE_ZONES
+       }
+ #endif
+       // if we could not obtain the required memory, bug-check.
+       //      Do NOT do this in your commercial driver, instead handle the error gracefully ...
+       if (!PtrFCB) 
+       {
+               Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2FCB)), 0);
+       }
+       // zero out the allocated memory block
+       RtlZeroMemory(PtrFCB, Ext2QuadAlign(sizeof(Ext2FCB)));
+       // set up some fields ...
+       PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FCB;
+       PtrFCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2FCB));
+       if (!AllocatedFromZone) 
+       {
+               Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE);
+       }
+       return(PtrFCB);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2CreateNewFCB()
+ *
+ * Description:
+ *     We want to create a new FCB. We will also create a new CCB (presumably)
+ *     later. Simply allocate a new FCB structure and initialize fields
+ *     appropriately.
+ *     This function also takes the file size values that the caller must
+ *     have obtained and       will set the file size fields appropriately in the
+ *     CommonFCBHeader.
+ *     Finally, this routine will initialize the FileObject structure passed
+ *     in to this function. If you decide to fail the call later, remember
+ *     to uninitialize the fields.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: A pointer to the FCB structure OR NULL.
+ *
+ *************************************************************************/
+ NTSTATUS Ext2CreateNewFCB(
+ PtrExt2FCB                            *ReturnedFCB,
+ LARGE_INTEGER                 AllocationSize,
+ LARGE_INTEGER                 EndOfFile,
+ PFILE_OBJECT                  PtrFileObject,
+ PtrExt2VCB                            PtrVCB,
+ PtrExt2ObjectName             PtrObjectName)
+ {
+       NTSTATUS                                                        RC = STATUS_SUCCESS;
+       
+       PtrExt2FCB                                              PtrFCB = NULL;
+       PtrExt2NTRequiredFCB                    PtrReqdFCB = NULL;
+       PFSRTL_COMMON_FCB_HEADER        PtrCommonFCBHeader = NULL;
+       ASSERT( PtrVCB );
+       try 
+       {
+               if( !PtrFileObject )
+               {
+                       PtrFCB = Ext2GetUsedFCB( PtrVCB );
+               }
+               else
+               {
+                       // Obtain a new FCB structure.
+                       // The function Ext2AllocateFCB() will obtain a new structure either
+                       // from a zone or from memory requested directly from the VMM.
+                       PtrFCB = Ext2AllocateFCB();
+               }
+               if (!PtrFCB) 
+               {
+                       // Assume lack of memory.
+                       try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
+               }
+               // Initialize fields required to interface with the NT Cache Manager.
+               // Note that the returned structure has already been zeroed. This means
+               // that the SectionObject structure has been zeroed which is a
+               // requirement for newly created FCB structures.
+               PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
+               // Initialize the MainResource and PagingIoResource structures now.
+               ExInitializeResourceLite(&(PtrReqdFCB->MainResource));
+               Ext2SetFlag(PtrFCB->FCBFlags, EXT2_INITIALIZED_MAIN_RESOURCE);
+               ExInitializeResourceLite(&(PtrReqdFCB->PagingIoResource));
+               Ext2SetFlag(PtrFCB->FCBFlags, EXT2_INITIALIZED_PAGING_IO_RESOURCE);
+               // Start initializing the fields contained in the CommonFCBHeader.
+               PtrCommonFCBHeader = &(PtrReqdFCB->CommonFCBHeader);
+               // Disallow fast-IO for now.
+               PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible;
+               // Initialize the MainResource and PagingIoResource pointers in
+               // the CommonFCBHeader structure to point to the ERESOURCE structures we
+               // have allocated and already initialized above.
+               PtrCommonFCBHeader->Resource = &(PtrReqdFCB->MainResource);
+               PtrCommonFCBHeader->PagingIoResource = &(PtrReqdFCB->PagingIoResource);
+               // Ignore the Flags field in the CommonFCBHeader for now. Part 3
+               // of the book describes it in greater detail.
+               // Initialize the file size values here.
+               PtrCommonFCBHeader->AllocationSize = AllocationSize;
+               PtrCommonFCBHeader->FileSize = EndOfFile;
+               // The following will disable ValidDataLength support. However, your
+               // FSD may choose to support this concept.
+               PtrCommonFCBHeader->ValidDataLength.LowPart = 0xFFFFFFFF;
+               PtrCommonFCBHeader->ValidDataLength.HighPart = 0x7FFFFFFF;
+               //      Initialize other fields for the FCB here ...
+               PtrFCB->PtrVCB = PtrVCB;
+               // caller MUST ensure that VCB has been acquired exclusively
+               InsertTailList(&(PtrVCB->FCBListHead), &(PtrFCB->NextFCB));
+       
+               
+               InitializeListHead(&(PtrFCB->CCBListHead));
+               // Initialize fields contained in the file object now.
+               if( PtrFileObject )
+               {
+                       PtrFileObject->PrivateCacheMap = NULL;
+                       // Note that we could have just as well taken the value of PtrReqdFCB
+                       // directly below. The bottom line however is that the FsContext
+                       // field must point to a FSRTL_COMMON_FCB_HEADER structure.
+                       PtrFileObject->FsContext = (void *)(PtrCommonFCBHeader);
+                       PtrFileObject->SectionObjectPointer = &(PtrFCB->NTRequiredFCB.SectionObject) ;
+               }
+               //      Initialising the object name...
+               PtrFCB->FCBName = PtrObjectName;
+               //      Returning the FCB...
+               *ReturnedFCB = PtrFCB;
+               try_exit:       NOTHING;
+       }
+       finally 
+       {
+               
+       }
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2ReleaseFCB()
+ *
+ * Description:
+ *     Deallocate a previously allocated structure.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2ReleaseFCB(
+ PtrExt2FCB                                            PtrFCB)
+ {
+       KIRQL                                                   CurrentIrql;
+       AssertFCB( PtrFCB );
+       if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB )
+       {
+               Ext2Panic( PtrFCB, PtrFCB->NodeIdentifier.NodeType, EXT2_NODE_TYPE_FCB )        ;
+       }
+       PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED;
+       
+       /*
+         // give back memory either to the zone or to the VMM
+       if (!(PtrFCB->FCBFlags & EXT2_FCB_NOT_FROM_ZONE)) 
+       {
+               // back to the zone
+               KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
+               ExFreeToZone(&(Ext2GlobalData.FCBZoneHeader), PtrFCB);
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       } 
+       else 
+       {
+       */
+       ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.MainResource );
+       ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.PagingIoResource );
+       if( PtrFCB->FCBName )
+       {
+               Ext2ReleaseObjectName( PtrFCB->FCBName );
+       }
+       DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", PtrFCB);
+       ExFreePool(PtrFCB);
+       
+       /*
+       }
+       */
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2AllocateByteLocks()
+ *
+ * Description:
+ *     Allocate a new byte range lock structure and initialize it to NULL.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: A pointer to the Ext2ByteLocks structure OR NULL.
+ *
+ *************************************************************************/
+ PtrExt2FileLockInfo Ext2AllocateByteLocks(
+ void)
+ {
+       PtrExt2FileLockInfo             PtrByteLocks = NULL;
+       BOOLEAN                                         AllocatedFromZone = TRUE;
+    KIRQL                                                      CurrentIrql;
+       // first, try to allocate out of the zone
+       KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
+       if (!ExIsFullZone(&(Ext2GlobalData.ByteLockZoneHeader))) 
+       {
+               // we have enough memory
+               PtrByteLocks = (PtrExt2FileLockInfo)ExAllocateFromZone(&(Ext2GlobalData.ByteLockZoneHeader));
+               // release the spinlock
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       } 
+       else 
+       {
+               // release the spinlock
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+               // if we failed to obtain from the zone, get it directly from the VMM
+               PtrByteLocks = (PtrExt2FileLockInfo)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2FileLockInfo)) );
+               AllocatedFromZone = FALSE;
+       }
+       // if we could not obtain the required memory, bug-check.
+       //      Do NOT do this in your commercial driver, instead handle the error gracefully ...
+       if (!PtrByteLocks) 
+       {
+               Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2FileLockInfo)), 0);
+       }
+       // zero out the allocated memory block
+       RtlZeroMemory(PtrByteLocks, Ext2QuadAlign(sizeof(PtrExt2FileLockInfo)));
+       if (!AllocatedFromZone) 
+       {
+               Ext2SetFlag(PtrByteLocks->FileLockFlags, EXT2_BYTE_LOCK_NOT_FROM_ZONE);
+       }
+       return(PtrByteLocks);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2ReleaseByteLocks()
+ *
+ * Description:
+ *     Deallocate a previously allocated structure.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2ReleaseByteLocks(
+ PtrExt2FileLockInfo                                   PtrByteLocks)
+ {
+       KIRQL                                                   CurrentIrql;
+       ASSERT(PtrByteLocks);
+       // give back memory either to the zone or to the VMM
+       if (!(PtrByteLocks->FileLockFlags & EXT2_BYTE_LOCK_NOT_FROM_ZONE)) {
+               // back to the zone
+               KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
+       ExFreeToZone(&(Ext2GlobalData.ByteLockZoneHeader), PtrByteLocks);
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       } 
+       else 
+       {
+               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", PtrByteLocks);
+               ExFreePool(PtrByteLocks);
+       }
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2AllocateIrpContext()
+ *
+ * Description:
+ *     The sample FSD creates an IRP context for each request received. This
+ *     routine simply allocates (and initializes to NULL) a Ext2IrpContext
+ *     structure.
+ *     Most of the fields in the context structure are then initialized here.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: A pointer to the IrpContext structure OR NULL.
+ *
+ *************************************************************************/
+ PtrExt2IrpContext Ext2AllocateIrpContext(
+ PIRP                                  Irp,
+ PDEVICE_OBJECT                PtrTargetDeviceObject)
+ {
+       PtrExt2IrpContext                       PtrIrpContext = NULL;
+       BOOLEAN                                         AllocatedFromZone = TRUE;
+       KIRQL                                                   CurrentIrql;
+       PIO_STACK_LOCATION              PtrIoStackLocation = NULL;
+       /* 
+       //      Allocation from zone not done at present...
+       
+       // first, try to allocate out of the zone
+       KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
+       if (!ExIsFullZone(&(Ext2GlobalData.IrpContextZoneHeader))) {
+               // we have enough memory
+               PtrIrpContext = (PtrExt2IrpContext)ExAllocateFromZone(&(Ext2GlobalData.IrpContextZoneHeader));
+               // release the spinlock
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       } else {
+               // release the spinlock
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       
+         
+       
+        
+               // if we failed to obtain from the zone, get it directly from the VMM
+               PtrIrpContext = (PtrExt2IrpContext)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2IrpContext)) );
+         AllocatedFromZone = FALSE;
+       }
+       
+       //No Zone handling for now
+       */
+       PtrIrpContext = (PtrExt2IrpContext)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2IrpContext)) );
+     AllocatedFromZone = FALSE;
+       // if we could not obtain the required memory, bug-check.
+       //      Do NOT do this in your commercial driver, instead handle        the error gracefully ...
+       if (!PtrIrpContext) 
+       {
+               Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2IrpContext)), 0);
+       }
+       // zero out the allocated memory block
+       RtlZeroMemory(PtrIrpContext, Ext2QuadAlign(sizeof(Ext2IrpContext)));
+       // set up some fields ...
+       PtrIrpContext->NodeIdentifier.NodeType  = EXT2_NODE_TYPE_IRP_CONTEXT;
+       PtrIrpContext->NodeIdentifier.NodeSize  = Ext2QuadAlign(sizeof(Ext2IrpContext));
+       PtrIrpContext->Irp = Irp;
+       PtrIrpContext->TargetDeviceObject = PtrTargetDeviceObject;
+       // copy over some fields from the IRP and set appropriate flag values
+       if (Irp) 
+       {
+               PtrIoStackLocation = IoGetCurrentIrpStackLocation(Irp);
+               ASSERT(PtrIoStackLocation);
+               PtrIrpContext->MajorFunction = PtrIoStackLocation->MajorFunction;
+               PtrIrpContext->MinorFunction = PtrIoStackLocation->MinorFunction;
+               // Often, a FSD cannot honor a request for asynchronous processing
+               // of certain critical requests. For example, a "close" request on
+               // a file object can typically never be deferred. Therefore, do not
+               // be surprised if sometimes your FSD (just like all other FSD
+               // implementations on the Windows NT system) has to override the flag
+               // below.
+               if( PtrIoStackLocation->FileObject )
+               {
+                       if (IoIsOperationSynchronous(Irp) ) 
+                       {
+                               Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK);
+                       }
+               }
+               else
+               {
+                       Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK);
+               }
+       }
+       if (!AllocatedFromZone) 
+       {
+               Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_NOT_FROM_ZONE);
+       }
+       // Are we top-level ? This information is used by the dispatching code
+       // later (and also by the FSD dispatch routine)
+       if (IoGetTopLevelIrp() != Irp) 
+       {
+               // We are not top-level. Note this fact in the context structure
+               Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_NOT_TOP_LEVEL);
+       }
+       InitializeListHead( &PtrIrpContext->SavedBCBsListHead );
+       return(PtrIrpContext);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2ReleaseIrpContext()
+ *
+ * Description:
+ *     Deallocate a previously allocated structure.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2ReleaseIrpContext(
+ PtrExt2IrpContext                                     PtrIrpContext)
+ {
+       KIRQL                                                   CurrentIrql;
+       ASSERT(PtrIrpContext);
+       //      Flush the saved BCBs...
+       Ext2FlushSavedBCBs( PtrIrpContext );
+       // give back memory either to the zone or to the VMM
+       if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_NOT_FROM_ZONE)) 
+       {
+               // back to the zone
+               KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql);
+               ExFreeToZone(&(Ext2GlobalData.IrpContextZoneHeader), PtrIrpContext);
+               KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql);
+       } 
+       else 
+       {
+               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", PtrIrpContext);
+               ExFreePool(PtrIrpContext);
+       }
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2PostRequest()
+ *
+ * Description:
+ *     Queue up a request for deferred processing (in the context of a system
+ *     worker thread). The caller must have locked the user buffer (if required)
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_PENDING
+ *
+ *************************************************************************/
+ NTSTATUS Ext2PostRequest(
+ PtrExt2IrpContext                     PtrIrpContext,
+ PIRP                                                  PtrIrp)
+ {
+       NTSTATUS                        RC = STATUS_PENDING;
+       DebugTrace(DEBUG_TRACE_ASYNC, " === Asynchronous request. Deferring processing", 0);
+       
+       // mark the IRP pending
+       IoMarkIrpPending(PtrIrp);
+       // queue up the request
+       ExInterlockedInsertTailList(
+               &Ext2GlobalData.ThreadQueue.ThreadQueueListHead, 
+               &PtrIrpContext->ThreadQueueListEntry,
+               &Ext2GlobalData.ThreadQueue.SpinLock );
+       KeSetEvent( &Ext2GlobalData.ThreadQueue.QueueEvent, 0, FALSE );
+                               
+ /*****************            not using system worker threads         *****************
+       ExInitializeWorkItem(&(PtrIrpContext->WorkQueueItem), Ext2CommonDispatch, PtrIrpContext);
+       ExQueueWorkItem( &( PtrIrpContext->WorkQueueItem ), DelayedWorkQueue );
+       //      CriticalWorkQueue 
+ *****************************************************************************/
+       // return status pending
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2CommonDispatch()
+ *
+ * Description:
+ *     The common dispatch routine invoked in the context of a system worker
+ *     thread. All we do here is pretty much case off the major function
+ *     code and invoke the appropriate FSD dispatch routine for further
+ *     processing.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *     IRQL PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2CommonDispatch(
+                       void            *Context )      // actually an IRPContext structure
+ {
+       NTSTATUS                                                RC = STATUS_SUCCESS;
+       PtrExt2IrpContext                       PtrIrpContext = NULL;
+       PIRP                                                    PtrIrp = NULL;
+       // The context must be a pointer to an IrpContext structure
+       PtrIrpContext = (PtrExt2IrpContext)Context;
+       ASSERT(PtrIrpContext);
+       // Assert that the Context is legitimate
+       if ((PtrIrpContext->NodeIdentifier.NodeType != EXT2_NODE_TYPE_IRP_CONTEXT) || (PtrIrpContext->NodeIdentifier.NodeSize != Ext2QuadAlign(sizeof(Ext2IrpContext)))) 
+       {
+               // This does not look good
+               Ext2Panic(EXT2_ERROR_INTERNAL_ERROR, PtrIrpContext->NodeIdentifier.NodeType, PtrIrpContext->NodeIdentifier.NodeSize);
+       }
+       //      Get a pointer to the IRP structure
+       PtrIrp = PtrIrpContext->Irp;
+       ASSERT(PtrIrp);
+       // Now, check if the FSD was top level when the IRP was originally invoked
+       // and set the thread context (for the worker thread) appropriately
+       if (PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_NOT_TOP_LEVEL) 
+       {
+               // The FSD is not top level for the original request
+               // Set a constant value in TLS to reflect this fact
+               IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
+       }
+       // Since the FSD routine will now be invoked in the context of this worker
+       // thread, we should inform the FSD that it is perfectly OK to block in
+       // the context of this thread
+       Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK);
+       FsRtlEnterFileSystem();
+       try
+       {
+               // Pre-processing has been completed; check the Major Function code value
+               // either in the IrpContext (copied from the IRP), or directly from the
+               //      IRP itself (we will need a pointer to the stack location to do that),
+               //      Then, switch based on the value on the Major Function code
+               switch (PtrIrpContext->MajorFunction) 
+               {
+               case IRP_MJ_CREATE:
+                       // Invoke the common create routine
+                       DebugTrace(DEBUG_TRACE_ASYNC,   " === Serviceing IRP_MJ_CREATE request asynchronously .", 0);
+                       (void)Ext2CommonCreate(PtrIrpContext, PtrIrp, FALSE);
+                       break;
+               case IRP_MJ_READ:
+                       // Invoke the common read routine
+                       DebugTrace(DEBUG_TRACE_ASYNC,   " === Serviceing IRP_MJ_READ request asynchronously .", 0);
+                       (void)Ext2CommonRead(PtrIrpContext, PtrIrp, FALSE);
+                       break;
+               case IRP_MJ_WRITE:
+                       // Invoke the common write routine
+                       DebugTrace(DEBUG_TRACE_ASYNC,   " === Serviceing IRP_MJ_WRITE request asynchronously .", 0);
+                       (void)Ext2CommonWrite(PtrIrpContext, PtrIrp );
+                       break;
+               case IRP_MJ_CLEANUP:
+                       // Invoke the common read routine
+                       DebugTrace(DEBUG_TRACE_ASYNC,   " === Serviceing IRP_MJ_CLEANUP request asynchronously .", 0);
+                       (void)Ext2CommonCleanup(PtrIrpContext, PtrIrp, FALSE);
+                       break;
+               case IRP_MJ_CLOSE:
+                       // Invoke the common read routine
+                       DebugTrace(DEBUG_TRACE_ASYNC,   " === Serviceing IRP_MJ_CLOSE request asynchronously .", 0);
+                       (void)Ext2CommonClose ( PtrIrpContext, PtrIrp, FALSE );
+                       break;
+               // Continue with the remaining possible dispatch routines below ...
+               default:
+                       // This is the case where we have an invalid major function
+                       DebugTrace(DEBUG_TRACE_ASYNC,   " === Serviceing asynchronous request. \nUnable to recoganise the IRP!!! How can this be!!!", 0);
+                       PtrIrp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+                       PtrIrp->IoStatus.Information = 0;
+                       
+                       Ext2BreakPoint();
+       
+                       IoCompleteRequest(PtrIrp, IO_NO_INCREMENT);
+                       break;
+               }
+       } 
+       except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
+       {
+               RC = Ext2ExceptionHandler(PtrIrpContext, PtrIrp);
+               Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
+       }
+       // Enable preemption
+       FsRtlExitFileSystem();
+       // Ensure that the "top-level" field is cleared
+       IoSetTopLevelIrp(NULL);
+       
+       PsTerminateSystemThread( RC );
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2InitializeVCB()
+ *
+ * Description:
+ *     Perform the initialization for a VCB structure.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *     IRQL PASSIVE_LEVEL
+ *
+ * Return Value: None
+ *
+ *************************************************************************/
+ void Ext2InitializeVCB(
+ PDEVICE_OBJECT                        PtrVolumeDeviceObject,
+ PDEVICE_OBJECT                        PtrTargetDeviceObject,
+ PVPB                                  PtrVPB,
+ PLARGE_INTEGER                        AllocationSize )
+ {
+       NTSTATUS                                RC = STATUS_SUCCESS;
+       PtrExt2VCB                      PtrVCB = NULL;
+       BOOLEAN                         VCBResourceInitialized = FALSE;
+       PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension);
+       // Zero it out (typically this has already been done by the I/O
+       // Manager but it does not hurt to do it again)!
+       RtlZeroMemory(PtrVCB, sizeof(Ext2VCB));
+       // Initialize the signature fields
+       PtrVCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_VCB;
+       PtrVCB->NodeIdentifier.NodeSize = sizeof(Ext2VCB);
+       // Initialize the ERESOURCE objects.
+       RC = ExInitializeResourceLite(&(PtrVCB->VCBResource));
+       RC = ExInitializeResourceLite(&(PtrVCB->PagingIoResource));
+       ASSERT(NT_SUCCESS(RC));
+       VCBResourceInitialized = TRUE;
+       PtrVCB->TargetDeviceObject = PtrTargetDeviceObject;
+       PtrVCB->VCBDeviceObject = PtrVolumeDeviceObject;
+       PtrVCB->PtrVPB = PtrVPB;
+       // Initialize the list anchor (head) for some lists in this VCB.
+       InitializeListHead(&(PtrVCB->FCBListHead));
+       InitializeListHead(&(PtrVCB->NextNotifyIRP));
+       InitializeListHead(&(PtrVCB->VolumeOpenListHead));
+       InitializeListHead(&(PtrVCB->ClosableFCBs.ClosableFCBListHead));
+       PtrVCB->ClosableFCBs.Count = 0;
+       // Initialize the notify IRP list mutex
+       KeInitializeMutex(&(PtrVCB->NotifyIRPMutex), 0);
+       // Set the initial file size values appropriately. Note that your FSD may
+       // wish to guess at the initial amount of information you would like to
+       // read from the disk until you have really determined that this a valid
+       // logical volume (on disk) that you wish to mount.
+       PtrVCB->CommonVCBHeader.AllocationSize.QuadPart = AllocationSize->QuadPart;
+       PtrVCB->CommonVCBHeader.FileSize.QuadPart = AllocationSize->QuadPart;
+       // You typically do not want to bother with valid data length callbacks
+       // from the Cache Manager for the file stream opened for volume metadata
+       // information
+       PtrVCB->CommonVCBHeader.ValidDataLength.LowPart = 0xFFFFFFFF;
+       PtrVCB->CommonVCBHeader.ValidDataLength.HighPart = 0x7FFFFFFF;
+       PtrVCB->CommonVCBHeader.IsFastIoPossible = FastIoIsNotPossible;
+       
+       PtrVCB->CommonVCBHeader.Resource = &(PtrVCB->VCBResource);
+       PtrVCB->CommonVCBHeader.PagingIoResource = &(PtrVCB->PagingIoResource);;
+       // Create a stream file object for this volume.
+       PtrVCB->PtrStreamFileObject = IoCreateStreamFileObject(NULL,
+                                                                                               PtrVCB->PtrVPB->RealDevice);
+       ASSERT(PtrVCB->PtrStreamFileObject);
+       // Initialize some important fields in the newly created file object.
+       PtrVCB->PtrStreamFileObject->FsContext = (void *)(&PtrVCB->CommonVCBHeader);
+       PtrVCB->PtrStreamFileObject->FsContext2 = NULL;
+       PtrVCB->PtrStreamFileObject->SectionObjectPointer = &(PtrVCB->SectionObject);
+       PtrVCB->PtrStreamFileObject->Vpb = PtrVPB;
+       PtrVCB->PtrStreamFileObject->ReadAccess = TRUE;
+       PtrVCB->PtrStreamFileObject->WriteAccess = TRUE;
+       // Link this chap onto the global linked list of all VCB structures.
+       DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire Global Resource Exclusively [FileInfo]", 0);
+       ExAcquireResourceExclusiveLite(&(Ext2GlobalData.GlobalDataResource), TRUE);
+       InsertTailList(&(Ext2GlobalData.NextVCB), &(PtrVCB->NextVCB));
+       DebugTrace(DEBUG_TRACE_MISC,   "*** Global Resource Acquired [FileInfo]", 0);
+       
+       // Initialize caching for the stream file object.
+       CcInitializeCacheMap(PtrVCB->PtrStreamFileObject, (PCC_FILE_SIZES)(&(PtrVCB->CommonVCBHeader.AllocationSize)),
+                                                               TRUE,           // We will use pinned access.
+                                                               &(Ext2GlobalData.CacheMgrCallBacks), PtrVCB );
+       
+       Ext2ReleaseResource(&(Ext2GlobalData.GlobalDataResource));
+       DebugTrace(DEBUG_TRACE_MISC,   "*** Global Resource Released[FileInfo]", 0);
+       // Mark the fact that this VCB structure is initialized.
+       Ext2SetFlag(PtrVCB->VCBFlags, EXT2_VCB_FLAGS_VCB_INITIALIZED);
+       PtrVCB->PtrGroupDescriptors = NULL;
+       PtrVCB->NoOfGroups = 0;
+       return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2CompleteRequest()
+ *
+ * Description:
+ *     This routine completes a Irp.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *   ???
+ * 
+ * Arguments:
+ *
+ *   Irp - Supplies the Irp being processed
+ *
+ *   Status - Supplies the status to complete the Irp with
+ *
+ * Return Value: none
+ *
+ *************************************************************************/
+ void Ext2CompleteRequest(
+     IN PIRP Irp OPTIONAL,
+     IN NTSTATUS Status
+     )
+ {
+       //
+     //  If we have an Irp then complete the irp.
+     //
+     if (Irp != NULL) 
+       {
+         //
+         //  We got an error, so zero out the information field before
+         //  completing the request if this was an input operation.
+         //  Otherwise IopCompleteRequest will try to copy to the user's buffer.
+         //
+         if ( NT_ERROR(Status) &&
+              FlagOn(Irp->Flags, IRP_INPUT_OPERATION) ) {
+             Irp->IoStatus.Information = 0;
+         }
+         Irp->IoStatus.Status = Status;
+         IoCompleteRequest( Irp, IO_DISK_INCREMENT );
+     }
+     return;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2CreateNewCCB()
+ *
+ * Description:
+ *     We want to create a new CCB. 
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: A pointer to the CCB structure OR NULL.
+ *
+ *************************************************************************/
+ NTSTATUS Ext2CreateNewCCB(
+       PtrExt2CCB                              *ReturnedCCB,
+       PtrExt2FCB                              PtrFCB,
+       PFILE_OBJECT                    PtrFileObject )
+ {
+       PtrExt2CCB  PtrCCB;
+       NTSTATUS RC = STATUS_SUCCESS;
+       try 
+       {
+               PtrCCB = Ext2AllocateCCB();
+               if (!PtrFCB) 
+               {
+                       // Assume lack of memory.
+                       try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
+               }
+               PtrCCB->PtrFCB = PtrFCB;
+               
+               PtrCCB->PtrFileObject = PtrFileObject;
+               PtrCCB->CurrentByteOffset.QuadPart = 0;
+               if( PtrFCB->ClosableFCBs.OnClosableFCBList )
+               {
+                       //      This FCB was on the Closable List...
+                       //      Taking it off the list...
+                       //
+                       RemoveEntryList( &PtrFCB->ClosableFCBs.ClosableFCBList );
+                       PtrFCB->ClosableFCBs.OnClosableFCBList = FALSE;
+                       PtrFCB->PtrVCB->ClosableFCBs.Count --;
+               }
+               InterlockedIncrement( &PtrFCB->ReferenceCount );
+               InterlockedIncrement( &PtrFCB->OpenHandleCount );
+               InsertTailList( &( PtrFCB->CCBListHead ), &(PtrCCB->NextCCB));
+               *ReturnedCCB = PtrCCB;
+               try_exit:       NOTHING;
+       } 
+       finally 
+       {
+               
+       }
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2DenyAccess()
+ *
+ * Description:
+ *     We want to deny access to an IRP
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: NTSTATUS - STATUS_ACCESS_DENIED (always)
+ *
+ *************************************************************************/
+ NTSTATUS Ext2DenyAccess( IN PIRP Irp )
+ {
+     ASSERT( Irp );
+       //      Just return Access Denied
+       Irp->IoStatus.Information = 0;
+       Irp->IoStatus.Status = STATUS_ACCESS_DENIED;
+       IoCompleteRequest( Irp, IO_DISK_INCREMENT );
+       
+       DebugTrace(DEBUG_TRACE_MISC,   "DENYING ACCESS (this will do for now!)...", 0);
+       
+       return STATUS_ACCESS_DENIED;
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2GetFCB_CCB_VCB_FromFileObject()
+ *
+ * Description:
+ *     This routine retrieves the FCB, CCB and VCB from the File Object...
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  ?
+ *
+ * Return Value: NTSTATUS - STATUS_SUCCESS(always)
+ *
+ *************************************************************************/
+ NTSTATUS Ext2GetFCB_CCB_VCB_FromFileObject (
+       IN PFILE_OBJECT                 PtrFileObject,
+       OUT PtrExt2FCB                          *PPtrFCB,
+       OUT PtrExt2CCB                          *PPtrCCB,
+       OUT PtrExt2VCB                          *PPtrVCB        )
+ {
+               int             Offset;
+               (*PPtrCCB) = (PtrExt2CCB)(PtrFileObject->FsContext2);
+               if( *PPtrCCB )
+               {
+                       ASSERT((*PPtrCCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB);
+                       (*PPtrFCB) = (*PPtrCCB)->PtrFCB;
+                       ASSERT((*PPtrFCB));
+                       
+                       if ((*PPtrFCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB)
+                       {
+                               (*PPtrVCB) = (PtrExt2VCB)(*PPtrFCB);
+                               AssertVCB( (*PPtrVCB) );
+                               //      No FCB
+                               (*PPtrFCB) = NULL;
+                               //found a VCB
+                       }
+                       else
+                       {
+                               AssertFCB( (*PPtrFCB) );
+                               (*PPtrVCB) = (*PPtrFCB)->PtrVCB;
+                               AssertVCB( (*PPtrVCB) );
+                       }
+               }
+               else
+               {
+                       //      PtrFileObject->FsContext points to NTRequiredFCB
+                       (*PPtrFCB) = CONTAINING_RECORD( PtrFileObject->FsContext, Ext2FCB, NTRequiredFCB );
+                       ASSERT((*PPtrFCB));
+                       //(*PPtrFCB) = PtrFileObject->FsContext;
+                       if ((*PPtrFCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB)
+                       {
+                               //      Making sure I got it right...
+                               AssertFCB( *PPtrFCB );
+                               (*PPtrVCB) = (*PPtrFCB)->PtrVCB;
+                               AssertVCB( *PPtrVCB );
+                       }
+                       else
+                       {
+                               //      This should be a VCB
+                               (*PPtrVCB) = CONTAINING_RECORD( PtrFileObject->FsContext, Ext2VCB, CommonVCBHeader );
+                               AssertVCB( *PPtrVCB );
+                               
+                               //      No FCB
+                               (*PPtrFCB) = NULL;
+                               //found a VCB
+                       }
+                       
+               }
+       return STATUS_SUCCESS;
+ }
+ void Ext2CopyUnicodeString( PUNICODE_STRING  PtrDestinationString, PUNICODE_STRING PtrSourceString )
+ {
+       int Count;
+       //      Allcating space for Destination...
+       PtrDestinationString->Length = PtrSourceString->Length;
+       PtrDestinationString->MaximumLength = Ext2QuadAlign( PtrSourceString->Length + 2 );
+       PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength );
+       //      RtlCopyUnicodeString( PtrDestinationString, PtrSourceString );
+       for( Count = 0 ; Count < (PtrSourceString->Length/2) ; Count++ )
+       {
+               PtrDestinationString->Buffer[Count] = PtrSourceString->Buffer[Count];
+       }
+       PtrDestinationString->Buffer[Count] = 0;
+ }
+ void Ext2CopyWideCharToUnicodeString( 
+       PUNICODE_STRING  PtrDestinationString, 
+       PCWSTR PtrSourceString )
+ {
+       
+       int Count; 
+       //      Determining length...
+       for( Count = 0 ; PtrSourceString[Count] != 0 ; Count++ );
+       
+       //      Allcating space for Destination...
+       PtrDestinationString->Length = Count * 2;
+       PtrDestinationString->MaximumLength = Ext2QuadAlign( Count * 2 + 2 );   
+       PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength  );
+       
+       //      Copying the string over...
+       for( Count = 0 ; ; Count++ )
+       {
+               PtrDestinationString->Buffer[Count] = PtrSourceString[Count];
+               if( PtrSourceString[Count] == 0 )
+                       break;
+       }
+ }
+ void Ext2CopyCharToUnicodeString( 
+       PUNICODE_STRING  PtrDestinationString, 
+       PCSTR PtrSourceString,
+       USHORT SourceStringLength )
+ {
+       int Count;
+       //      Allcating space for Destination...
+       PtrDestinationString->Length = SourceStringLength * 2;
+       PtrDestinationString->MaximumLength = Ext2QuadAlign( SourceStringLength * 2 + 2 );      
+       PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength  );
+       
+       //      Copying the string over...
+       for( Count = 0 ; Count < SourceStringLength ; Count++ )
+       {
+               PtrDestinationString->Buffer[Count] = PtrSourceString[Count];
+       }
+       PtrDestinationString->Buffer[Count] = 0;
+ }
+ void Ext2CopyZCharToUnicodeString( PUNICODE_STRING  PtrDestinationString, PCSTR PtrSourceString )
+ {
+       
+       int Count; 
+       //      Determining length...
+       for( Count = 0 ; PtrSourceString[Count] != 0 ; Count++ );
+       
+       //      Allcating space for Destination...
+       PtrDestinationString->Length = Count * 2;
+       PtrDestinationString->MaximumLength = Ext2QuadAlign( Count * 2 + 2 );   
+       PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength  );
+       
+       //      Copying the string over...
+       for( Count = 0 ; ; Count++ )
+       {
+               PtrDestinationString->Buffer[Count] = PtrSourceString[Count];
+               if( PtrSourceString[Count] == 0 )
+                       break;
+       }
+ }
+ void Ext2ZerooutUnicodeString( PUNICODE_STRING PtrUnicodeString )
+ {
+       PtrUnicodeString->Length = 0;
+       PtrUnicodeString->MaximumLength =0;
+       PtrUnicodeString->Buffer = 0;
+ }
+ void Ext2DeallocateUnicodeString( PUNICODE_STRING PtrUnicodeString )
+ {
+       if( PtrUnicodeString && PtrUnicodeString->Buffer )
+       {
+               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", PtrUnicodeString->Buffer );
+               ExFreePool( PtrUnicodeString->Buffer );
+       }
+       PtrUnicodeString->Length = 0;
+       PtrUnicodeString->MaximumLength =0;
+       PtrUnicodeString->Buffer = 0;
+ }
+ PtrExt2FCB Ext2GetUsedFCB( 
+       PtrExt2VCB      PtrVCB )
+ {
+       BOOLEAN                 AllocatedFromZone = FALSE;
+       PLIST_ENTRY             PtrEntry = NULL;
+       PtrExt2FCB              PtrFCB = NULL;
+       ASSERT( PtrVCB );
+       if( PtrVCB->ClosableFCBs.Count < EXT2_MAXCLOSABLE_FCBS_LL )
+       {
+               //
+               //      Too few Closable FCBs
+               //      Will not reuse any FCBs 
+               //      Allocating a new one
+               //
+               return Ext2AllocateFCB();
+       }
+       //
+       //      Obtaining a used FCB...
+       //
+       
+       //      Retrieving the first entry in the closable FCB list...
+       PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead );
+       
+       PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList );
+       //      Remembering if the FCB was allocated from the Zone...
+       AllocatedFromZone = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE );
+       //      
+       //      Close this FCB
+       //
+       if( !Ext2CloseClosableFCB( PtrFCB ) )
+       {
+               //      Couldn't close the FCB!!
+               //      
+               InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead,
+                       &PtrFCB->ClosableFCBs.ClosableFCBList );
+               return Ext2AllocateFCB();
+       }
+       PtrVCB->ClosableFCBs.Count--;
+       DebugTrace( DEBUG_TRACE_SPECIAL, "Count = %ld [Ext2GetUsedFCB]", PtrVCB->ClosableFCBs.Count );
+       //
+       //      Getting the FCB ready for reuse by 
+       //      zeroing it out...
+       //
+       RtlZeroMemory(PtrFCB, Ext2QuadAlign(sizeof(Ext2FCB)));
+       // set up some fields ...
+       PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FCB;
+       PtrFCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2FCB));
+       if (!AllocatedFromZone) 
+       {
+               Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE);
+       }
+       
+       return PtrFCB;
+ }
+ BOOLEAN Ext2CloseClosableFCB( 
+       PtrExt2FCB              PtrFCB)
+ {
+       KIRQL                   Irql = 0;
+       PFILE_OBJECT    PtrFileObject = NULL;
+       AssertFCB( PtrFCB );
+       //      Attempting to acquire the FCB Exclusively...
+       if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) )
+       {
+               Ext2BreakPoint();
+               return  FALSE;
+       }
+       Irql = KeGetCurrentIrql( );
+       if( PtrFCB->ReferenceCount )
+       {
+               //      How the hell can this happen!!!
+               Ext2BreakPoint();
+       }
+       if( PtrFCB->OpenHandleCount )
+       {
+               //      How the hell can this happen!!!
+               Ext2BreakPoint();
+       }
+       //      Deleting entry from VCB's FCB list...
+       RemoveEntryList( &PtrFCB->NextFCB );
+       PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED;
+       PtrFileObject = PtrFCB->DcbFcb.Dcb.PtrDirFileObject;
+       if ( PtrFileObject )
+       {
+               //
+               //      Clear the Cache Map...
+               //
+               if( PtrFileObject->PrivateCacheMap != NULL) 
+               {
+                       IO_STATUS_BLOCK Status;
+                       DebugTrace( DEBUG_TRACE_SPECIAL, ">>.........Flushing cache.........<<", 0 );
+                       CcFlushCache( PtrFileObject->SectionObjectPointer, NULL, 0, &Status );
+                       CcUninitializeCacheMap( PtrFileObject, NULL, NULL );
+               }
+               //
+               //      The File Object is no longer required...
+               //      Close it by dereferenceing it!!!
+               //
+               PtrFileObject->FsContext        = NULL;
+               PtrFileObject->FsContext2       = NULL;
+               ObDereferenceObject( PtrFileObject );
+               PtrFCB->DcbFcb.Dcb.PtrDirFileObject = NULL;
+               PtrFileObject = NULL;
+       }
+       //      Uninitialize the Resources...
+       ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.MainResource );
+       ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.PagingIoResource );
+       //
+       //      Releasing the FCB Name Object...
+       //
+       if( PtrFCB->FCBName )
+       {
+               DebugTrace( DEBUG_TRACE_SPECIAL, "Reusing FCB - File Name %S", PtrFCB->FCBName->ObjectName.Buffer );
+               Ext2ReleaseObjectName( PtrFCB->FCBName );
+       }
+       else
+       {
+               DebugTrace( DEBUG_TRACE_SPECIAL, "Reusing FCB - File Name *Unknown*", 0 );
+       }
+       return TRUE;
+ }
+ BOOLEAN Ext2SaveBCB(
+       PtrExt2IrpContext       PtrIrpContext,
+       PBCB                            PtrBCB,
+       PFILE_OBJECT            PtrFileObject)
+ {
+       PEXT2_SAVED_BCBS        PtrSavedBCB;
+       PLIST_ENTRY                     PtrEntry = NULL;
+       if( !PtrIrpContext )
+       {
+               //
+               //      NULL passed instead of the IRP Context
+               //      This call should be ignored...
+               //
+               return TRUE;
+       }
+       if( !AssertBCB( PtrBCB ) )
+       {
+               DebugTrace( DEBUG_TRACE_MISC, "Not saving BCB!!! [Ext2SaveBCB]", 0 );
+               return FALSE;
+       }
+       DebugTrace( DEBUG_TRACE_SPECIAL, "Saving BCB [Ext2SaveBCB]", 0 );
+       //      Has the BCB been saved already?
+       for( PtrEntry = PtrIrpContext->SavedBCBsListHead.Flink; 
+                       PtrEntry != &PtrIrpContext->SavedBCBsListHead; 
+                       PtrEntry = PtrEntry->Flink )
+       {
+               PtrSavedBCB = CONTAINING_RECORD( PtrEntry, EXT2_SAVED_BCBS, SavedBCBsListEntry );
+               ASSERT( PtrSavedBCB );
+               if( PtrSavedBCB->PtrBCB == PtrBCB )
+               {
+                       //      A BCB for this file has already been saved for flushing...
+                       //      Won't resave this one...
+                       return TRUE;
+               }
+       }
+       //      Reference the BCB 
+       CcRepinBcb( PtrBCB );
+       //      Now allocate a EXT2_SAVED_BCBS
+       PtrSavedBCB = Ext2AllocatePool( NonPagedPool, 
+                                       Ext2QuadAlign( sizeof( EXT2_SAVED_BCBS ) )  );
+       if( !PtrSavedBCB )
+               return FALSE;
+       PtrSavedBCB->NodeIdentifier.NodeSize = sizeof( EXT2_SAVED_BCBS );
+       PtrSavedBCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_SAVED_BCB;
+       PtrSavedBCB->PtrBCB = PtrBCB;
+       //      PtrSavedBCB->PtrFileObject = PtrFileObject;
+       
+       //      Now save it in the IRP Context
+       InsertHeadList( &PtrIrpContext->SavedBCBsListHead, &PtrSavedBCB->SavedBCBsListEntry );
+       
+       PtrIrpContext->SavedCount++;
+       //      Return success...
+       return TRUE;
+ }
+ BOOLEAN Ext2FlushSavedBCBs(
+       PtrExt2IrpContext       PtrIrpContext )
+ {
+       
+       PLIST_ENTRY                     PtrEntry = NULL;
+       PEXT2_SAVED_BCBS        PtrSavedBCB = NULL;
+       IO_STATUS_BLOCK         Status;
+       BOOLEAN                         RC = TRUE;
+       if( !IsListEmpty( &PtrIrpContext->SavedBCBsListHead ) )
+       {
+               DebugTrace( DEBUG_TRACE_SPECIAL, "Flushing cache... - Ext2FlushSavedBCBs", 0 );
+       }
+       while( !IsListEmpty( &PtrIrpContext->SavedBCBsListHead ) )
+       {
+               PtrEntry = RemoveTailList( &PtrIrpContext->SavedBCBsListHead );
+               if( !PtrEntry )
+               {
+                       //      No more entries left...
+                       break;
+               }
+               //      Get the Saved BCB
+               PtrSavedBCB = CONTAINING_RECORD( PtrEntry, EXT2_SAVED_BCBS, SavedBCBsListEntry );
+               if( PtrSavedBCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_SAVED_BCB )
+               {
+                       //      Something is wrong...
+                       Ext2BreakPoint();
+                       return FALSE;
+               }
+               if( !AssertBCB( PtrSavedBCB->PtrBCB ) )
+               {
+                       //      This BCB shouldn't have been saved in the first place...
+                       DebugTrace( DEBUG_TRACE_ERROR, "Unable to flush BCB - Skipping!!! [Ext2SaveBCB]", 0 );
+                       continue;
+               }
+               //      Unpin and Flush the cache...
+               CcUnpinRepinnedBcb( PtrSavedBCB->PtrBCB, TRUE, &Status );
+               
+               if( !NT_SUCCESS( Status.Status ) )
+               {
+                       //      Failure in flushing...
+                       DebugTrace( DEBUG_TRACE_SPECIAL, "Failure flushing cache - Ext2FlushSavedBCBs", 0 );
+                       RC = FALSE;
+               }
+               //      Release the Saved BCB
+               PtrSavedBCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_INVALID;
+               
+               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [misc]", PtrSavedBCB );
+               ExFreePool( PtrSavedBCB );
+               PtrSavedBCB = NULL;
+               PtrIrpContext->SavedCount--;
+       }
+       return RC;
+ }
+ BOOLEAN AssertBCB( PBCB       PtrBCB )
+ {
+       PFILE_OBJECT            PtrFileObject = NULL;
+       
+       /*
+        * This routine is simplified version of the original
+        * AssertBCB and doesn't make any assumptions about
+        * the layout of undocumented BCB structure.
+        * -- Filip Navara, 18/08/2004
+        */
+               PtrFileObject = CcGetFileObjectFromBcb ( PtrBCB );
+               if( !PtrFileObject )
+               {
+                       Ext2BreakPoint();
+                       return FALSE;
+               }
+               else
+               {
+                       return TRUE;
+               }
+       }
+ ULONG Ext2Align( ULONG NumberToBeAligned, ULONG Alignment )
+ {
+       if( Alignment & ( Alignment - 1 ) )
+       {
+               //
+               //      Alignment not a power of 2
+               //      Just returning
+               //
+               return NumberToBeAligned;
+       }
+       if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 )
+       {
+               NumberToBeAligned = NumberToBeAligned + Alignment;
+               NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) );
+       }
+       return NumberToBeAligned;
+ }
+ LONGLONG Ext2Align64( LONGLONG NumberToBeAligned, LONGLONG Alignment )
+ {
+       if( Alignment & ( Alignment - 1 ) )
+       {
+               //
+               //      Alignment not a power of 2
+               //      Just returning
+               //
+               return NumberToBeAligned;
+       }
+       if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 )
+       {
+               NumberToBeAligned = NumberToBeAligned + Alignment;
+               NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) );
+       }
+       return NumberToBeAligned;
+ }
+ ULONG Ext2GetCurrentTime()
+ {
+       LARGE_INTEGER  CurrentTime;
+       ULONG Time;
+       KeQuerySystemTime( &CurrentTime );
+       Time = (ULONG) ( (CurrentTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 );
+       return Time;
+ }
index 0000000,e4b47de..e4b47de
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1476 +1,1476 @@@
+ /*************************************************************************
+ *
+ * File: read.c
+ *
+ * Module: Ext2 File System Driver (Kernel mode execution only)
+ *
+ * Description:
+ *     Contains code to handle the "Read" dispatch entry point.
+ *
+ * Author: Manoj Paul Joseph
+ *
+ *
+ *************************************************************************/
+ #include                      "ext2fsd.h"
+ // define the file specific bug-check id
+ #define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_READ
+ #define                       DEBUG_LEVEL                                             (DEBUG_TRACE_READ)
+ /*************************************************************************
+ *
+ * Function: Ext2Read()
+ *
+ * Description:
+ *     The I/O Manager will invoke this routine to handle a read
+ *     request
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
+ *     to be deferred to a worker thread context)
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS Ext2Read(
+ PDEVICE_OBJECT                DeviceObject,           // the logical volume device object
+ PIRP                                  Irp)                                    // I/O Request Packet
+ {
+       NTSTATUS                                RC = STATUS_SUCCESS;
+       PtrExt2IrpContext       PtrIrpContext = NULL;
+       BOOLEAN                         AreWeTopLevel = FALSE;
+       
+       DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "Read IRP Received...", 0);
+       //      Ext2BreakPoint();
+       
+       FsRtlEnterFileSystem();
+       ASSERT(DeviceObject);
+       ASSERT(Irp);
+       // set the top level context
+       AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
+       try
+       {
+               // get an IRP context structure and issue the request
+               PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
+               ASSERT(PtrIrpContext);
+               RC = Ext2CommonRead(PtrIrpContext, Irp, TRUE);
+       }
+       except ( Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation() ) ) 
+       {
+               RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
+               Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
+       }
+       if (AreWeTopLevel) 
+       {
+               IoSetTopLevelIrp(NULL);
+       }
+       
+       FsRtlExitFileSystem();
+       
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2CommonRead()
+ *
+ * Description:
+ *     The actual work is performed here. This routine may be invoked in one
+ *     of the two possible contexts:
+ *     (a) in the context of a system worker thread
+ *     (b) in the context of the original caller
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS      Ext2CommonRead(
+ PtrExt2IrpContext                     PtrIrpContext,
+ PIRP                                          PtrIrp,
+ BOOLEAN                                               FirstAttempt )
+ {
+       NTSTATUS                                RC = STATUS_SUCCESS;
+       PIO_STACK_LOCATION              PtrIoStackLocation = NULL;
+       LARGE_INTEGER                   ByteOffset;
+       uint32                                  ReadLength = 0, TruncatedReadLength = 0;
+       uint32                                  NumberBytesRead = 0;
+       PFILE_OBJECT                    PtrFileObject = NULL;
+       PtrExt2FCB                              PtrFCB = NULL;
+       PtrExt2CCB                              PtrCCB = NULL;
+       PtrExt2VCB                              PtrVCB = NULL;
+       PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
+       PERESOURCE                              PtrResourceAcquired = NULL;
+       IO_STATUS_BLOCK                 LocalIoStatus;
+       PVOID                                   PtrSystemBuffer = NULL;
+       PVOID                                   PtrPinnedReadBuffer = NULL;
+       uint32                                  KeyValue = 0;
+       BOOLEAN                                 CompleteIrp = TRUE;
+       BOOLEAN                                 PostRequest = FALSE;
+       BOOLEAN                                 CanWait = FALSE;
+       BOOLEAN                                 PagingIo = FALSE;
+       BOOLEAN                                 NonBufferedIo = FALSE;
+       BOOLEAN                                 SynchronousIo = FALSE;
+       BOOLEAN                                 MdlLocked = FALSE;
+       BOOLEAN                                 ReadTruncated = FALSE;
+       LARGE_INTEGER                   StartPhysicalBlock;
+       ULONG                                   NoOfBlocks = 0;
+       PIO_STACK_LOCATION              PtrIrpNextSp = NULL;
+       //      Used to cache the Single Indirect blocks pointed to by 
+       //      the Double Indirect block
+       PEXT2_SIBLOCKS                  PtrDIArray = NULL;
+       ULONG                                   DIArrayCount = 0;
+       //      Used to cache the Single Indirect blocks pointed to by 
+       //      the Triple Indirect block
+       PEXT2_SIBLOCKS                  PtrTIArray = NULL;
+       ULONG                                   TIArrayCount = 0;
+       EXT2_IO_RUN     *                       PtrIoRuns = NULL;
+       ULONG   Start;
+       ULONG   End;
+       ULONG   LogicalBlockIndex;
+       ULONG   BytesRemaining;
+       ULONG   BytesReadSoFar;
+       ULONG   LeftOver;
+       ULONG   LogicalBlockSize;
+       ULONG   PhysicalBlockSize;
+       PBCB PtrPinnedSIndirectBCB = NULL;
+       PBCB PtrPinnedDIndirectBCB = NULL;
+       PBCB PtrPinnedTIndirectBCB = NULL;
+       int i, Index;
+       try 
+       {
+               try{
+               // First, get a pointer to the current I/O stack location
+               PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
+               ASSERT(PtrIoStackLocation);
+               // If this happens to be a MDL read complete request, then
+               // there is not much processing that the FSD has to do.
+               if (PtrIoStackLocation->MinorFunction & IRP_MN_COMPLETE) 
+               {
+                       // Caller wants to tell the Cache Manager that a previously
+                       // allocated MDL can be freed.
+                       Ext2MdlComplete(PtrIrpContext, PtrIrp, PtrIoStackLocation, TRUE);
+                       // The IRP has been completed.
+                       CompleteIrp = FALSE;
+                       try_return(RC = STATUS_SUCCESS);
+               }
+               // If this is a request at IRQL DISPATCH_LEVEL, then post
+               // the request (your FSD may choose to process it synchronously
+               // if you implement the support correctly; obviously you will be
+               // quite constrained in what you can do at such IRQL).
+               if (PtrIoStackLocation->MinorFunction & IRP_MN_DPC) 
+               {
+                       DebugTrace(DEBUG_TRACE_MISC,   " === Deferring Read ", 0 );
+                       CompleteIrp = FALSE;
+                       PostRequest = TRUE;
+                       try_return(RC = STATUS_PENDING);
+               }
+               PtrFileObject = PtrIoStackLocation->FileObject;
+               ASSERT(PtrFileObject);
+               // Get the FCB and CCB pointers
+               Ext2GetFCB_CCB_VCB_FromFileObject ( 
+                       PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB );
+               // Get some of the parameters supplied to us
+               ByteOffset = PtrIoStackLocation->Parameters.Read.ByteOffset;
+               ReadLength = PtrIoStackLocation->Parameters.Read.Length;
+               CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
+               PagingIo = ((PtrIrp->Flags & IRP_PAGING_IO) ? TRUE : FALSE);
+               NonBufferedIo = ((PtrIrp->Flags & IRP_NOCACHE) ? TRUE : FALSE);
+               SynchronousIo = ((PtrFileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE);
+               if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer )
+               {
+                       DebugTrace(DEBUG_TRACE_FILE_NAME,   " === Read File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer );
+               }
+               else
+               {
+                       DebugTrace(DEBUG_TRACE_FILE_NAME,   " === Read File Name : -null-", 0);
+               }
+               
+               DebugTrace(DEBUG_TRACE_READ_DETAILS,   "  ->ByteCount           = 0x%8lx", PtrIoStackLocation->Parameters.Read.Length);
+               DebugTrace(DEBUG_TRACE_READ_DETAILS,   "  ->ByteOffset.LowPart  = 0x%8lx", PtrIoStackLocation->Parameters.Read.ByteOffset.LowPart);
+               
+               if( CanWait )
+               {
+                       DebugTrace(DEBUG_TRACE_READ_DETAILS,   "  ->Can Wait ", 0 );
+               }
+               else
+               {
+                       DebugTrace(DEBUG_TRACE_READ_DETAILS,   "  ->Can't Wait ", 0 );
+               }
+               
+               if( PagingIo )
+               {
+                       DebugTrace(DEBUG_TRACE_READ_DETAILS,   "  ->Paging Io ", 0 );
+               }
+               else
+               {
+                       DebugTrace(DEBUG_TRACE_READ_DETAILS,   "  ->Not Paging Io", 0 );
+               }
+               if( SynchronousIo )
+               {
+                       DebugTrace(DEBUG_TRACE_READ_DETAILS,   "  ->SynchronousIo ", 0 );
+               }
+               else
+               {
+                       DebugTrace(DEBUG_TRACE_READ_DETAILS,   "  ->ASynchronousIo ", 0 );
+               }
+               if( NonBufferedIo )
+               {
+                       DebugTrace(DEBUG_TRACE_READ_DETAILS,   "  ->NonBufferedIo", 0 );
+               }
+               else
+               {
+                       DebugTrace(DEBUG_TRACE_READ_DETAILS,   "  ->BufferedIo", 0 );
+               }
+       
+               if (ReadLength == 0) 
+               {
+                       // a 0 byte read can be immediately succeeded
+                       try_return(RC);
+               }
+               // Is this a read of the volume itself ?
+               if ( ( !PtrFCB && PtrVCB ) || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB )
+               {
+                       //
+                       //      >>>>>>>>>>>     Volume Read     <<<<<<<<<<<<
+                       //
+                       // Yep, we need to send this on to the disk driver after
+                       //      validation of the offset and length.
+                       //      PtrVCB = (PtrExt2VCB)(PtrFCB);
+                       if (PtrVCB->VCBFlags & EXT2_FCB_PAGE_FILE ) 
+                       {
+                               DebugTrace(DEBUG_TRACE_READ_DETAILS,  "[Read] *Volume Page File *", 0);
+                       }
+                       // Acquire the volume resource shared ...
+                       if( PtrFileObject )
+                       {
+                               DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Read]", PtrFileObject);
+                       }
+                       if( PagingIo )
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire VCB Shared [Read]", 0);
+                               DebugTraceState( "VCBPaging       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Read]", PtrVCB->PagingIoResource.ActiveCount, PtrVCB->PagingIoResource.NumberOfExclusiveWaiters, PtrVCB->PagingIoResource.NumberOfSharedWaiters );
+                               if (!ExAcquireResourceSharedLite(&(PtrVCB->PagingIoResource), FALSE )) 
+                               {
+                                       // post the request to be processed in the context of a worker thread
+                                       DebugTrace(DEBUG_TRACE_MISC,   "*** VCBPaging Acquisition FAILED [Read]", 0);
+                                       CompleteIrp = FALSE;
+                                       PostRequest = TRUE;
+                                       try_return(RC = STATUS_PENDING);
+                               }
+                               DebugTrace(DEBUG_TRACE_MISC,  "*** VCBPaging Acquired [Read]", 0);
+                               
+                               PtrResourceAcquired = &(PtrVCB->PagingIoResource);
+                       }
+                       else
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire VCB Shared [Read]", 0);
+                               DebugTraceState( "VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Read]", PtrVCB->VCBResource.ActiveCount, 
+                                       PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
+                               if (!ExAcquireResourceSharedLite(&(PtrVCB->VCBResource), FALSE )) 
+                               {
+                                       // post the request to be processed in the context of a worker thread
+                                       DebugTrace(DEBUG_TRACE_MISC,   "*** VCB Acquisition FAILED [Read]", 0);
+                                       CompleteIrp = FALSE;
+                                       PostRequest = TRUE;
+                                       try_return(RC = STATUS_PENDING);
+                               }
+                               DebugTrace(DEBUG_TRACE_MISC,  "*** VCB Acquired [Read]", 0);
+                               
+                               PtrResourceAcquired = &(PtrVCB->VCBResource);
+                       }
+                       if( !PagingIo )
+                       {
+                               if( PtrVCB->CommonVCBHeader.AllocationSize.QuadPart < ByteOffset.QuadPart )
+                               {
+                                       RC = STATUS_END_OF_FILE;
+                                       NumberBytesRead = 0;
+                                       try_return( RC );
+                               }
+                       }
+                       if( PagingIo || NonBufferedIo )
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,  "[Volume Read] PagingIo or NonBufferedIo ", 0);
+                               CompleteIrp = FALSE;
+                               RC = Ext2PassDownSingleReadWriteIRP (
+                                       PtrIrpContext, PtrIrp, PtrVCB, 
+                                       ByteOffset, ReadLength, SynchronousIo);
+                               try_return(RC);
+                       }
+                       else
+                       {
+                               //      Buffer Control Block
+                               PBCB            PtrBCB = NULL;
+                               DebugTrace(DEBUG_TRACE_READ_DETAILS,  "[Volume Read] BufferedIo ", 0);
+                               //
+                               //      Let the cache manager worry about this read...
+                               //      Pinned access should have been initiated.
+                               //      But checking anyway...
+                               //
+                               ASSERT( PtrVCB->PtrStreamFileObject );
+                               ASSERT( PtrVCB->PtrStreamFileObject->PrivateCacheMap );
+                               
+                               if (!CcMapData( PtrVCB->PtrStreamFileObject,
+                                       &ByteOffset,
+                                       ReadLength,
+                                       TRUE,
+                                       &PtrBCB,
+                                       &PtrPinnedReadBuffer) ) 
+                               {
+                                       RC = STATUS_UNSUCCESSFUL;
+                                       NumberBytesRead = 0;
+                                       try_return( RC );
+                               }
+                               else
+                               {
+                                       PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp);
+                                       RtlCopyBytes( PtrSystemBuffer, PtrPinnedReadBuffer, ReadLength );
+                                       CcUnpinData( PtrBCB );
+                                       PtrBCB = NULL;
+                                       RC = STATUS_SUCCESS;
+                                       NumberBytesRead = ReadLength;
+                                       try_return(RC);
+                               }
+                       }
+               }
+               // If the read request is directed to a page file 
+               // send the request directly to the disk driver. 
+               // For requests directed to a page file, you have to trust
+               // that the offsets will be set correctly by the VMM. You should not
+               // attempt to acquire any FSD resources either.
+               if (PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE) 
+               {
+                       IoMarkIrpPending(PtrIrp);
+                       // You will need to set a completion routine before invoking
+                       // a lower level driver
+                       //      forward request directly to disk driver
+                       // Ext2PageFileIo(PtrIrpContext, PtrIrp);
+                       DebugTrace( DEBUG_TRACE_SPECIAL, "[Read] To a *Page File* - Not handled \ngoing into a hang...", 0);
+                       CompleteIrp = FALSE;
+                       try_return(RC = STATUS_PENDING);
+               }
+               //
+               //      If this read is directed to a directory...
+               //      Paging IO is allowed though...
+               //
+               if ( ( PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY ) &&  !PagingIo )
+               {
+                       RC = STATUS_INVALID_DEVICE_REQUEST;
+                       try_return(RC);
+               }
+               PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
+               // Check whether the desired read can be allowed depending
+               //      on any byte range locks that might exist. Note that for
+               //      paging-io, no such checks should be performed.
+               if (!PagingIo) 
+               {
+                       //      Insert code to perform the check here ...
+                       //
+                       //      if (!Ext2CheckForByteLock(PtrFCB, PtrCCB, PtrIrp, PtrCurrentIoStackLocation)) 
+                       //      {
+                       //              try_return(RC = STATUS_FILE_LOCK_CONFLICT);
+                       //      }
+               }
+               // There are certain complications that arise when the same file stream
+               // has been opened for cached and non-cached access. The FSD is then
+               // responsible for maintaining a consistent view of the data seen by
+               // the caller.
+               // Also, it is possible for file streams to be mapped in both as data files
+               // and as an executable. This could also lead to consistency problems since
+               // there now exist two separate sections (and pages) containing file
+               // information.
+               // Read Chapter 10 for more information on the issues involved in
+               // maintaining data consistency.
+               // The test below flushes the data cached in system memory if the current
+               // request madates non-cached access (file stream must be cached) and
+               // (a) the current request is not paging-io which indicates it is not
+               //               a recursive I/O operation OR originating in the Cache Manager
+               // (b) OR the current request is paging-io BUT it did not originate via
+               //               the Cache Manager (or is a recursive I/O operation) and we do
+               //               have an image section that has been initialized.
+               #define EXT2_REQ_NOT_VIA_CACHE_MGR(ptr) (!MmIsRecursiveIoFault() && ((ptr)->ImageSectionObject != NULL))
+               if( NonBufferedIo && (PtrReqdFCB->SectionObject.DataSectionObject != NULL) )
+               {
+                       if      (!PagingIo || (EXT2_REQ_NOT_VIA_CACHE_MGR(&(PtrReqdFCB->SectionObject)))) 
+                       {
+                               CcFlushCache(&(PtrReqdFCB->SectionObject), &ByteOffset, ReadLength, &(PtrIrp->IoStatus));
+                               // If the flush failed, return error to the caller
+                               if (!NT_SUCCESS(RC = PtrIrp->IoStatus.Status)) 
+                               {
+                                       try_return(RC);
+                               }
+                       }
+               }
+               //
+               //      Synchronizing with other reads and writes...
+               //      Acquire the appropriate FCB resource shared
+               //
+               if ( PagingIo ) 
+               {
+                       // Try to acquire the FCB PagingIoResource shared
+                       if( PtrFileObject )
+                       {
+                               DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Read]", PtrFileObject);
+                       }
+                       DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire FCBPaging Shared [Read]", 0);
+                       DebugTraceState( "FCBPaging AC:0x%LX   SW:0x%LX   EX:0x%LX   [Read]", PtrReqdFCB->PagingIoResource.ActiveCount, PtrReqdFCB->PagingIoResource.NumberOfExclusiveWaiters, PtrReqdFCB->PagingIoResource.NumberOfSharedWaiters );
+                       if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->PagingIoResource), CanWait)) 
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** FCBPaging Acquisition FAILED [Read]", 0);
+                               CompleteIrp = FALSE;
+                               PostRequest = TRUE;
+                               try_return(RC = STATUS_PENDING);
+                       }
+                       
+                       DebugTrace(DEBUG_TRACE_MISC,   "*** FCBPaging Acquired [Read]", 0);
+                       // Remember the resource that was acquired
+                       PtrResourceAcquired = &(PtrReqdFCB->PagingIoResource);
+               } 
+               else 
+               {
+                       // Try to acquire the FCB MainResource shared
+                       if( PtrFileObject )
+                       {
+                               DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Read]", PtrFileObject);
+                       }
+                       DebugTrace(DEBUG_TRACE_MISC,   "*** Attempting to acquire FCB Shared [Read]", 0);
+                       DebugTraceState( "FCBMain   AC:0x%LX   SW:0x%LX   EX:0x%LX   [Read]", PtrReqdFCB->MainResource.ActiveCount, PtrReqdFCB->MainResource.NumberOfExclusiveWaiters, PtrReqdFCB->MainResource.NumberOfSharedWaiters );
+                       if (!ExAcquireResourceSharedLite(&(PtrReqdFCB->MainResource), CanWait)) 
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,   "*** FCB Acquisition FAILED [Read]", 0);
+                               CompleteIrp = FALSE;
+                               PostRequest = TRUE;
+                               try_return(RC = STATUS_PENDING);
+                       }
+                       DebugTrace(DEBUG_TRACE_MISC,   "*** FCB Acquired [Read]", 0);
+                       
+                       // Remember the resource that was acquired
+                       PtrResourceAcquired = &(PtrReqdFCB->MainResource);
+               }
+               //      Read in the File inode...
+               Ext2InitializeFCBInodeInfo( PtrFCB );
+               if (!PagingIo) 
+               {
+                       LARGE_INTEGER  CurrentTime;
+                       KeQuerySystemTime( &CurrentTime );
+                       PtrFCB->LastAccessTime.QuadPart = CurrentTime.QuadPart;
+               }
+               // Validate start offset and length supplied.
+               if (ByteOffset.QuadPart >= PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart )
+               {
+                       // Starting offset is > file size
+                       try_return(RC = STATUS_END_OF_FILE);
+               }
+               /*
+                * Round down the size of Paging I/O requests too. I'm not
+                * sure if the FS driver is responsible for doing that, but
+                * all other drivers I have seen do it.
+                * -- Filip Navara, 18/08/2004
+                */
+               if ( ByteOffset.QuadPart + ReadLength > PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart )
+               {
+                       //      Read going beyond the end of file...
+                       //      Adjusting the Read Length...
+                       ReadLength = (UINT)(PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart - ByteOffset.QuadPart);
+                       if (PagingIo)
+                               ReadLength = ROUND_TO_PAGES(ReadLength);
+                       ReadTruncated = TRUE;
+               }
+               // This is also a good place to set whether fast-io can be performed
+               // on this particular file or not. Your FSD must make it's own
+               // determination on whether or not to allow fast-io operations.
+               // Commonly, fast-io is not allowed if any byte range locks exist
+               // on the file or if oplocks prevent fast-io. Practically any reason
+               // choosen by your FSD could result in your setting FastIoIsNotPossible
+               // OR FastIoIsQuestionable instead of FastIoIsPossible.
+               //
+               // PtrReqdFCB->CommonFCBHeader.IsFastIoPossible = FastIoIsPossible;
+               
+               //      Branch here for cached vs non-cached I/O
+               if (!NonBufferedIo) 
+               {
+                       DebugTrace(DEBUG_TRACE_READ_DETAILS,  "[File Read] BufferedIo ", 0);
+                       // The caller wishes to perform cached I/O. Initiate caching if
+                       // this is the first cached I/O operation using this file object
+                       if (PtrFileObject->PrivateCacheMap == NULL) 
+                       {
+                               // This is the first cached I/O operation. You must ensure
+                               // that the FCB Common FCB Header contains valid sizes at this time
+                               CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)),
+                                       FALSE,          // We will not utilize pin access for this file
+                                       &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
+                                       PtrCCB);                // The context used in callbacks
+                       }
+                       // Check and see if this request requires a MDL returned to the caller
+                       if (PtrIoStackLocation->MinorFunction & IRP_MN_MDL) 
+                       {
+                               // Caller does want a MDL returned. Note that this mode
+                               // implies that the caller is prepared to block
+                               CcMdlRead(PtrFileObject, &ByteOffset, TruncatedReadLength, &(PtrIrp->MdlAddress), &(PtrIrp->IoStatus));
+                               NumberBytesRead = PtrIrp->IoStatus.Information;
+                               RC = PtrIrp->IoStatus.Status;
+                               try_return(RC);
+                       }
+                       // This is a regular run-of-the-mill cached I/O request. Let the
+                       // Cache Manager worry about it!
+                       // First though, we need a buffer pointer (address) that is valid
+                       PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp);
+                       ASSERT(PtrSystemBuffer);
+                       if (!CcCopyRead(PtrFileObject, &(ByteOffset), ReadLength, CanWait, PtrSystemBuffer, &(PtrIrp->IoStatus))) 
+                       {
+                               // The caller was not prepared to block and data is not immediately
+                               // available in the system cache
+                               DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure. Cannot read without blocking...", 0);
+                               CompleteIrp = FALSE;
+                               PostRequest = TRUE;
+                       
+                               // Mark Irp Pending ...
+                               IoMarkIrpPending( PtrIrp );
+                               RC = STATUS_PENDING;
+                               try_return(RC);
+                       }
+                       // We have the data
+                       RC = PtrIrp->IoStatus.Status;
+                       NumberBytesRead = PtrIrp->IoStatus.Information;
+                       try_return(RC);
+               }
+               else // NonBuffered or Paged IO
+               {
+                       LONGLONG        SingleIndirectBlockSize ;
+                       LONGLONG        DoubleIndirectBlockSize ;
+                       LONGLONG        TripleIndirectBlockSize ;
+                       LONGLONG        DirectBlockSize ;
+                       LONGLONG        NoOfDirectBlocks ;
+                       LONGLONG        NoOfSingleIndirectBlocks ;
+                       LONGLONG        NoOfDoubleIndirectBlocks ;
+                       LONGLONG        NoOfTripleIndirectBlocks ;
+                       ULONG * PtrPinnedSIndirectBlock = NULL;
+                       ULONG * PtrPinnedDIndirectBlock = NULL;
+                       ULONG * PtrPinnedTIndirectBlock = NULL;
+                       //      Used when reading a Triple Indirect Block...
+                       LONGLONG                FirstCachedDIBlockOffset = 0;
+                       //      Used when reading a Double Indirect Block...
+                       LONGLONG                FirstCachedSIBlockOffset = 0;
+                       
+                       DebugTrace(DEBUG_TRACE_MISC,  "[File Read] Paging IO or NonBufferedIo ", 0);
+                       //      Calculating where the read should start from...
+                       LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
+                       PhysicalBlockSize = PtrVCB->TargetDeviceObject->SectorSize;
+                       NoOfDirectBlocks =  EXT2_NDIR_BLOCKS ;
+                       NoOfSingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG );
+                       NoOfDoubleIndirectBlocks = NoOfSingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
+                       NoOfTripleIndirectBlocks = NoOfDoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
+                       DirectBlockSize =  LogicalBlockSize * NoOfDirectBlocks;
+                       SingleIndirectBlockSize = LogicalBlockSize * NoOfSingleIndirectBlocks;
+                       DoubleIndirectBlockSize = LogicalBlockSize * NoOfDoubleIndirectBlocks ;
+                       TripleIndirectBlockSize = LogicalBlockSize * NoOfTripleIndirectBlocks;
+                       LogicalBlockIndex = (ULONG)( ByteOffset.QuadPart / LogicalBlockSize);
+                       /*
+                       if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
+                       {
+                               //
+                               //      Handle Triple indirect blocks?
+                               //      A Pop up will do for now...
+                               //
+                               UNICODE_STRING ErrorMessage;
+                               Ext2CopyWideCharToUnicodeString( &ErrorMessage, L"Triple indirect blocks not supported as yet. - Ext2.sys" );
+                               DebugTrace(DEBUG_TRACE_ERROR,   "@@@@@@@@  Triple indirect blocks need to be read in! \n@@@@@@@@  This is not supported as yet!", 0);
+                               IoRaiseInformationalHardError(
+                                               IO_ERR_DRIVER_ERROR,
+                                               &ErrorMessage,
+                                               KeGetCurrentThread( ) );
+                               Ext2DeallocateUnicodeString( &ErrorMessage );
+                               RC = STATUS_INSUFFICIENT_RESOURCES;
+                               try_return ( RC );
+                       }
+                       */
+                       if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize &&
+                               ( ByteOffset.QuadPart < DirectBlockSize + SingleIndirectBlockSize ) )
+                       {
+                               //
+                               //      Single Indirect Blocks required...
+                               //      Read in the single indirect blocks...
+                               //
+                               
+                               LARGE_INTEGER VolumeByteOffset;
+                               DebugTrace(DEBUG_TRACE_MISC,   "Reading in some Single Indirect Blocks", 0);
+                               VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_IND_BLOCK ] * LogicalBlockSize;
+                               //
+                               //      Asking the cache manager to oblige by pinning the single indirect block...
+                               //
+                               if (!CcMapData( PtrVCB->PtrStreamFileObject,
+                    &VolumeByteOffset,
+                    LogicalBlockSize,
+                    CanWait,
+                    &PtrPinnedSIndirectBCB,
+                    (PVOID*)&PtrPinnedSIndirectBlock )) 
+                               {
+                                       CompleteIrp = FALSE;
+                                       PostRequest = TRUE;
+                               
+                                       // Mark Irp Pending ...
+                                       IoMarkIrpPending( PtrIrp );
+                                       RC = STATUS_PENDING;
+                                       try_return(RC);
+                                       DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
+                               }
+                       }
+                       if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize + SingleIndirectBlockSize &&
+                               ( ByteOffset.QuadPart ) < DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
+                       {
+                               //
+                               //      Double Indirect Blocks required...
+                               //      Read in the double indirect blocks...
+                               //
+                               LONGLONG                StartIndirectBlock;
+                               LONGLONG                EndIndirectBlock;
+                               
+                               LARGE_INTEGER VolumeByteOffset;
+                               DebugTrace(DEBUG_TRACE_MISC,   "Reading in some Double Indirect Blocks", 0);
+                               VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
+                               //
+                               //      Asking the cache manager to oblige by pinning the double indirect block...
+                               //
+                               if (!CcMapData( PtrVCB->PtrStreamFileObject,
+                    &VolumeByteOffset,
+                    LogicalBlockSize,
+                    CanWait,
+                    &PtrPinnedDIndirectBCB,
+                    (PVOID*)&PtrPinnedDIndirectBlock )) 
+                               {
+                                       CompleteIrp = FALSE;
+                                       PostRequest = TRUE;
+                               
+                                       // Mark Irp Pending ...
+                                       IoMarkIrpPending( PtrIrp );
+                                       RC = STATUS_PENDING;
+                                       try_return(RC);
+                                       DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
+                               }
+                               //      So far so good...
+                               //      Now determine the single indirect blocks that will have to be read in...
+                               if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize )
+                               {
+                                       //      Request doesnot require any single indirect or direct blocks
+                                       StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize);
+                                       StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
+                                       StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
+                               }
+                               else
+                               {
+                                       StartIndirectBlock = 0;
+                               }
+                               FirstCachedSIBlockOffset = (NoOfSingleIndirectBlocks*(StartIndirectBlock+1)) + NoOfDirectBlocks;
+                               if( ByteOffset.QuadPart + ReadLength >= 
+                                       DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize)
+                               {
+                                       EndIndirectBlock  = DoubleIndirectBlockSize;
+                               }
+                               else
+                               {
+                                       EndIndirectBlock = ByteOffset.QuadPart + ReadLength - 
+                                                                          (DirectBlockSize + SingleIndirectBlockSize);
+                               }
+                               EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ;
+                               EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks;
+       
+                               DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock);
+                               PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
+                               {
+                                       ULONG   i;
+                                       for( i = 0; i < DIArrayCount; i++ )
+                                       {
+                                               VolumeByteOffset.QuadPart =  PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize;
+                                               if (!CcMapData( PtrVCB->PtrStreamFileObject,
+                                                  &VolumeByteOffset,
+                                                  LogicalBlockSize,
+                                                  CanWait,
+                                                  &PtrDIArray[i].PtrBCB,
+                                                  (PVOID*)&PtrDIArray[i].PtrSIBlocks)) 
+                                               {
+                                                       CompleteIrp = FALSE;
+                                                       PostRequest = TRUE;
+                                                       IoMarkIrpPending( PtrIrp );
+                                                       DIArrayCount = i;
+                                                       try_return(RC = STATUS_PENDING);
+                                                       DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
+                                               }
+                                       }
+                               }
+                       }
+                       
+                       if( ( ByteOffset.QuadPart + ReadLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
+                       {
+                               //
+                               //      Triple Indirect Blocks required...
+                               //      Read in the triple indirect blocks...
+                               //
+                               LONGLONG                StartTIndirectBlock;
+                               LONGLONG                EndTIndirectBlock;
+                               LONGLONG                StartDIndirectBlock;
+                               LONGLONG                EndDIndirectBlock;
+                               LONGLONG                StartIndirectBlock;
+                               LONGLONG                EndIndirectBlock;
+                               LONGLONG                ByteOffsetTillHere = 0;
+                               PBCB    TempDIBCB;
+                               LONG*   TempDIBuffer;
+                               ULONG TIArrayIndex = 0;
+                               LARGE_INTEGER VolumeByteOffset;
+                               DebugTrace(DEBUG_TRACE_MISC,   "Reading in some Triple Indirect Blocks", 0);
+                               VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize;
+                               DebugTrace(DEBUG_TRACE_TRIPLE,   "ByteOffset = 0x%I64X", ByteOffset );
+                               DebugTrace(DEBUG_TRACE_TRIPLE,   "ReadLength = 0x%lX", ReadLength );
+                               DebugTrace(DEBUG_TRACE_TRIPLE,   "EXT2_TIND_BLOCK = 0x%lX", PtrFCB->IBlock[ EXT2_TIND_BLOCK ] );
+                               //
+                               //      Asking the cache manager to oblige by pinning the triple indirect block...
+                               //
+                               if (!CcMapData( PtrVCB->PtrStreamFileObject,
+                    &VolumeByteOffset,
+                    LogicalBlockSize,
+                    CanWait,
+                    &PtrPinnedTIndirectBCB,
+                    (PVOID*)&PtrPinnedTIndirectBlock )) 
+                               {
+                                       CompleteIrp = FALSE;
+                                       PostRequest = TRUE;
+                               
+                                       // Mark Irp Pending ...
+                                       IoMarkIrpPending( PtrIrp );
+                                       RC = STATUS_PENDING;
+                                       try_return(RC);
+                                       DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
+                               }
+                               //      Determine the no of BCBs that need to be saved...
+                               if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
+                               {
+                                       StartTIndirectBlock = ByteOffset.QuadPart;
+                               }
+                               else
+                               {
+                                       StartTIndirectBlock = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize;
+                               }
+                               EndTIndirectBlock = ByteOffset.QuadPart + ReadLength;
+                               TIArrayCount = (ULONG)( (EndTIndirectBlock - StartTIndirectBlock) / SingleIndirectBlockSize ) + 2;
+                               
+                               PtrTIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( TIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
+                               //      Now determine the double indirect blocks that will have to be read in...
+                               if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
+                               {
+                                       //      Request doesnot require any single indirect or direct blocks
+                                       StartDIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize);
+                                       StartDIndirectBlock = StartDIndirectBlock / LogicalBlockSize;
+                                       StartDIndirectBlock = StartDIndirectBlock / NoOfDoubleIndirectBlocks;
+                                       ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + (DoubleIndirectBlockSize*(StartDIndirectBlock+1)) ;
+                                       //FirstCachedDIBlockOffset = ByteOffset.QuadPart / LogicalBlockSize;
+                                       FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize;
+                               }
+                               else
+                               {
+                                       ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize;
+                                       FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize;
+                                       StartDIndirectBlock = 0;
+                               }
+                               DebugTrace(DEBUG_TRACE_TRIPLE,   "ByteOffsetTillHere = 0x%lX", ByteOffsetTillHere );
+                               EndDIndirectBlock  = ByteOffset.QuadPart + ReadLength - 
+                                       (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize);
+                               EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, LogicalBlockSize ) / LogicalBlockSize ;
+                               EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, NoOfDoubleIndirectBlocks ) / NoOfDoubleIndirectBlocks;
+                               {
+                                       //      Reading in the necessary double indirect bocks...
+                                       ULONG   i;
+                                       LONGLONG Count = EndDIndirectBlock-StartDIndirectBlock;
+                                       for( i = 0; i < Count; i++, ByteOffsetTillHere += DoubleIndirectBlockSize)
+                                       {
+                                               VolumeByteOffset.QuadPart =  PtrPinnedTIndirectBlock[StartDIndirectBlock+i] * LogicalBlockSize;
+                                               
+                                               DebugTrace(DEBUG_TRACE_TRIPLE,   "Double VolOffset = 0x%I64X", VolumeByteOffset );
+                                               if( !CcMapData( PtrVCB->PtrStreamFileObject,
+                                                  &VolumeByteOffset,
+                                                  LogicalBlockSize,
+                                                  CanWait,
+                                                  &TempDIBCB,
+                                                  (PVOID*)&TempDIBuffer) )
+                                               {
+                                                       CompleteIrp = FALSE;
+                                                       PostRequest = TRUE;
+                                                       IoMarkIrpPending( PtrIrp );
+                                                       try_return(RC = STATUS_PENDING);
+                                                       DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
+                                               }
+                                       
+                                               if( ByteOffset.QuadPart > ByteOffsetTillHere)
+                                               {
+                                                       StartIndirectBlock = ByteOffset.QuadPart - (ByteOffsetTillHere);
+                                                       StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
+                                                       StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
+                                                       if( TIArrayIndex == 0 )
+                                                       {
+                                                               FirstCachedDIBlockOffset += StartIndirectBlock * NoOfSingleIndirectBlocks;
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       StartIndirectBlock = 0;
+                                               }
+                                               if( ByteOffset.QuadPart + ReadLength >= ByteOffsetTillHere + DoubleIndirectBlockSize)
+                                               {
+                                                       EndIndirectBlock  = DoubleIndirectBlockSize;
+                                               }
+                                               else
+                                               {
+                                                       EndIndirectBlock = ByteOffset.QuadPart + ReadLength - ByteOffsetTillHere;
+                                               }
+                                               EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ;
+                                               EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks;
+                                       
+                                               {
+                                                       ULONG   i;
+                                                               
+                                                       for( i = 0; i < (EndIndirectBlock - StartIndirectBlock); i++ )
+                                                       {
+                                                               VolumeByteOffset.QuadPart =  TempDIBuffer[StartIndirectBlock+i] * LogicalBlockSize;
+                                                               DebugTrace(DEBUG_TRACE_TRIPLE,   "Single VolOffset = 0x%I64X", VolumeByteOffset );
+                                                               if (!CcMapData( PtrVCB->PtrStreamFileObject,
+                                                                  &VolumeByteOffset,
+                                                                  LogicalBlockSize,
+                                                                  CanWait,
+                                                                  &PtrTIArray[ TIArrayIndex ].PtrBCB,
+                                                                  (PVOID*)&PtrTIArray[ TIArrayIndex ].PtrSIBlocks)) 
+                                                               {
+                                                                       CompleteIrp = FALSE;
+                                                                       PostRequest = TRUE;
+                                                                       IoMarkIrpPending( PtrIrp );
+                                                                       DIArrayCount = i;
+                                                                       try_return(RC = STATUS_PENDING);
+                                                                       DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
+                                                               }
+                                                               TIArrayIndex++;
+                                                       }
+                                               }
+                                               CcUnpinData( TempDIBCB );
+                                               TempDIBCB = NULL;
+                                               TempDIBuffer = NULL;
+                                       }
+                               }
+                               TIArrayCount = TIArrayIndex;
+                               
+                               DebugTrace(DEBUG_TRACE_TRIPLE,   "TIArrayCount = %ld", TIArrayCount );
+                               DebugTrace(DEBUG_TRACE_TRIPLE,   "FirstCachedDIBlockOffset = 0x%lX", FirstCachedDIBlockOffset );
+                       }
+                       //      
+                       //      Allocating memory for IO Runs
+                       //
+                       Index = ( (ReadLength - 2) / LogicalBlockSize + 2 );
+                       PtrIoRuns = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( Index * sizeof( EXT2_IO_RUN) )  );
+                       Start = (ULONG) ( ByteOffset.QuadPart - (LogicalBlockSize * LogicalBlockIndex) );
+                       BytesRemaining = (ULONG)( LogicalBlockSize * (LogicalBlockIndex +1) - ByteOffset.QuadPart );
+                       if( ReadLength > BytesRemaining )
+                       {
+                               End = Start + BytesRemaining;
+                       }
+                       else
+                       {
+                               End = Start + ReadLength;
+                       }
+                       BytesReadSoFar = 0;
+                       Index = 0;
+                       DebugTrace(DEBUG_TRACE_MISC, "\nDetermining the read IRPs that have to be passed down...", 0);
+                       
+                       while( 1 )
+                       {
+                               BytesReadSoFar += (End-Start);
+                               if( LogicalBlockIndex < NoOfDirectBlocks )
+                               {
+                                       //      Direct Block
+                                       PtrIoRuns[ Index ].LogicalBlock = PtrFCB->IBlock[ LogicalBlockIndex ];
+                               }
+                               else if( LogicalBlockIndex < (NoOfSingleIndirectBlocks + NoOfDirectBlocks) )
+                               {
+                                       //      Single Indirect Block
+                                       PtrIoRuns[ Index ].LogicalBlock = PtrPinnedSIndirectBlock[ LogicalBlockIndex - NoOfDirectBlocks ];
+                               }
+                               else if( LogicalBlockIndex < (NoOfDoubleIndirectBlocks + NoOfSingleIndirectBlocks + NoOfDirectBlocks)  )
+                               {
+                                       LONGLONG BlockNo;
+                                       LONGLONG IBlockIndex;
+                                       LONGLONG BlockIndex;
+                                       BlockNo         = LogicalBlockIndex - FirstCachedSIBlockOffset;
+                                       IBlockIndex     = BlockNo / NoOfSingleIndirectBlocks;
+                                       BlockIndex      = BlockNo % NoOfSingleIndirectBlocks;
+                                       //      Double Indirect Block
+                                       PtrIoRuns[ Index ].LogicalBlock = 
+                                               PtrDIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];
+                               }
+                               else
+                               {
+                                       //      Triple Indirect Block
+                                       LONGLONG BlockNo;
+                                       LONGLONG IBlockIndex;
+                                       LONGLONG BlockIndex;
+                                       BlockNo         = LogicalBlockIndex - FirstCachedDIBlockOffset;
+                                       IBlockIndex     = BlockNo / NoOfSingleIndirectBlocks;
+                                       BlockIndex      = BlockNo % NoOfSingleIndirectBlocks;
+                                       DbgPrint( "\nBlock No : 0x%I64X   IBlockIndex = 0x%I64X   BlockIndex = 0x%I64X", BlockNo, IBlockIndex, BlockIndex);
+                                       if( IBlockIndex >= TIArrayCount )
+                                       {
+                                               Ext2BreakPoint();
+                                       }
+                                       if( BlockIndex >= LogicalBlockSize )
+                                       {
+                                               Ext2BreakPoint();
+                                       }
+                                       PtrIoRuns[ Index ].LogicalBlock = PtrTIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];;
+                                       DbgPrint( "LogicalBlock = 0x%lX", PtrIoRuns[ Index ].LogicalBlock );
+                               }
+                               if( PtrIoRuns[ Index ].LogicalBlock == 0 )
+                               {
+                                       //
+                                       //      Something is wrong...
+                                       //
+                                       //Ext2BreakPoint();
+                                       Index--;
+                                       break;
+                               }
+                               PtrIoRuns[ Index ].StartOffset = Start;
+                               PtrIoRuns[ Index ].EndOffset = End;
+                               PtrIoRuns[ Index ].PtrAssociatedIrp = NULL;
+                               DebugTrace( DEBUG_TRACE_MISC, "  Index = (%ld)", LogicalBlockIndex );
+                               DebugTrace( DEBUG_TRACE_MISC, "  Logical Block = (0x%lX)", PtrIoRuns[ Index ].LogicalBlock );
+                               DebugTrace( DEBUG_TRACE_MISC, "  Start = (0x%lX)", Start );
+                               DebugTrace( DEBUG_TRACE_MISC, "  End = (0x%lX)  ", End );
+                               DebugTrace( DEBUG_TRACE_MISC, "  Bytes read (0x%lX)", BytesReadSoFar );
+                                
+                               
+                               if( BytesReadSoFar >= ReadLength )
+                                       break;
+                               LogicalBlockIndex++;
+                               Start = 0;
+                               LeftOver = ReadLength - BytesReadSoFar;
+                               if( LeftOver > LogicalBlockSize )
+                                       End = LogicalBlockSize;
+                               else
+                                       End = LeftOver;
+                               //      Loop over to make the read request...
+                               Index++;
+                       }
+                       //
+                       //      Unpin the Indirect Blocks
+                       //
+                       if( PtrPinnedSIndirectBCB )
+                       {
+                               CcUnpinData( PtrPinnedSIndirectBCB  );
+                               PtrPinnedSIndirectBCB = NULL;
+                               PtrPinnedSIndirectBlock = NULL;
+                       }
+                       if( PtrPinnedDIndirectBCB )
+                       {
+                               CcUnpinData( PtrPinnedDIndirectBCB );
+                               PtrPinnedDIndirectBCB = NULL;
+                               PtrPinnedDIndirectBlock = NULL;
+                       }
+                       
+                       if( PtrPinnedTIndirectBCB)
+                       {
+                               CcUnpinData( PtrPinnedTIndirectBCB);
+                               PtrPinnedTIndirectBCB = NULL;
+                               PtrPinnedTIndirectBlock = NULL;
+                       }
+                       
+                       if ( PtrDIArray )
+                       {
+                               ULONG   i;
+                               for( i = 0; i < DIArrayCount; i++ )
+                               {
+                                       CcUnpinData( PtrDIArray->PtrBCB );
+                               }
+                               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Read]", PtrDIArray );
+                               ExFreePool( PtrDIArray );
+                               PtrDIArray = NULL;
+                       }                       
+                       if ( PtrTIArray )
+                       {
+                               ULONG   i;
+                               for( i = 0; i < TIArrayCount; i++ )
+                               {
+                                       CcUnpinData( PtrTIArray->PtrBCB );
+                               }
+                               DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Read]", PtrTIArray );
+                               ExFreePool( PtrTIArray );
+                               PtrTIArray = NULL;
+                       }       
+                       //
+                       //      Pass down Associated IRPs to the Target Device Driver...
+                       //
+                       DebugTrace( DEBUG_TRACE_MISC, "Passing down the Read IRPs to the disk driver...", 0 );
+                       RC = Ext2PassDownMultiReadWriteIRP( PtrIoRuns, Index+1, ReadLength, PtrIrpContext, PtrFCB, SynchronousIo );
+                       
+                       //
+                       //      Irp will be completed automatically 
+                       //      when all the Associated IRPs are completed
+                       //
+                       if( RC == STATUS_SUCCESS || RC == STATUS_PENDING )
+                       {
+                               CompleteIrp = FALSE;    
+                       }
+                       try_return( RC );
+               
+               }
+               try_exit:       NOTHING;
+               }
+               except (EXCEPTION_EXECUTE_HANDLER) 
+               {
+                       DebugTrace(DEBUG_TRACE_ERROR,   "@@@@@@@@  Exception Handler", 0);
+               }
+       }
+       finally 
+       {
+               if ( PtrIoRuns )
+               {
+                       DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Read]", PtrIoRuns );
+                       ExFreePool( PtrIoRuns );
+               }
+               //
+               //      Unpin the Indirect Blocks
+               //
+               if( PtrPinnedSIndirectBCB )
+               {
+                       CcUnpinData( PtrPinnedSIndirectBCB  );
+                       PtrPinnedSIndirectBCB = NULL;
+               }
+               if( PtrPinnedDIndirectBCB )
+               {
+                       CcUnpinData( PtrPinnedDIndirectBCB );
+                       PtrPinnedDIndirectBCB = NULL;
+               }
+               if( PtrPinnedTIndirectBCB )
+               {
+                       CcUnpinData( PtrPinnedTIndirectBCB );
+                       PtrPinnedTIndirectBCB = NULL;
+               }
+               if ( PtrDIArray )
+               {
+                       ULONG   i;
+                       for( i = 0; i < DIArrayCount; i++ )
+                       {
+                               CcUnpinData( PtrDIArray->PtrBCB );
+                       }
+                       DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Read]", PtrDIArray );
+                       ExFreePool( PtrDIArray );
+               }
+               if ( PtrTIArray )
+               {
+                       ULONG   i;
+                       for( i = 0; i < TIArrayCount; i++ )
+                       {
+                               CcUnpinData( PtrTIArray->PtrBCB );
+                       }
+                       DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Read]", PtrTIArray );
+                       ExFreePool( PtrTIArray );
+               }
+               // Release any resources acquired here ...
+               if (PtrResourceAcquired) 
+               {
+                       Ext2ReleaseResource(PtrResourceAcquired);
+                       
+                       DebugTraceState( "Resource     AC:0x%LX   SW:0x%LX   EX:0x%LX   [Read]", 
+                               PtrResourceAcquired->ActiveCount, 
+                               PtrResourceAcquired->NumberOfExclusiveWaiters, 
+                               PtrResourceAcquired->NumberOfSharedWaiters );
+                       if( PtrFileObject )
+                       {
+                               DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Read]", PtrFileObject);
+                       }
+                       if( PtrVCB && PtrResourceAcquired == &(PtrVCB->VCBResource) )
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,  "*** VCB Released [Read]", 0);
+                       }
+                       else if( PtrVCB && PtrResourceAcquired == &(PtrVCB->PagingIoResource ) )
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,  "*** VCBPaging Released [Read]", 0);
+                       }
+                       else if( PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->PagingIoResource) )
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Paging Resource Released [Read]", 0);
+                       }
+                       else if(PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->MainResource) )
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Resource Released [Read]", 0);
+                       }
+                       else
+                       {
+                               DebugTrace(DEBUG_TRACE_MISC,  "*** Unknown Resource Released [Read]", 0);
+                       }
+                       PtrResourceAcquired = NULL;
+               }
+               // Post IRP if required
+               if ( PostRequest ) 
+               {
+                       // Implement a routine that will queue up the request to be executed
+                       // later (asynchronously) in the context of a system worker thread.
+                       // See Chapter 10 for details.
+                       // Lock the callers buffer here. Then invoke a common routine to
+                       // perform the post operation.
+                       if (!(PtrIoStackLocation->MinorFunction & IRP_MN_MDL)) 
+                       {
+                               RC = Ext2LockCallersBuffer(PtrIrp, TRUE, ReadLength);
+                               ASSERT(NT_SUCCESS(RC));
+                       }
+                       // Perform the post operation which will mark the IRP pending
+                       // and will return STATUS_PENDING back to us
+                       RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
+               }
+               else if (CompleteIrp && !(RC == STATUS_PENDING)) 
+               {
+                       // For synchronous I/O, the FSD must maintain the current byte offset
+                       // Do not do this however, if I/O is marked as paging-io
+                       if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) 
+                       {
+                               PtrFileObject->CurrentByteOffset = RtlLargeIntegerAdd(ByteOffset, RtlConvertUlongToLargeInteger((unsigned long)NumberBytesRead));
+                       }
+                       // If the read completed successfully and this was not a paging-io
+                       // operation, set a flag in the CCB that indicates that a read was
+                       // performed and that the file time should be updated at cleanup
+                       if (NT_SUCCESS(RC) && !PagingIo) 
+                       {
+                               Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_ACCESSED);
+                       }
+                       // Can complete the IRP here if no exception was encountered
+                       if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) 
+                       {
+                               
+                               PtrIrp->IoStatus.Status = RC;
+                               PtrIrp->IoStatus.Information = NumberBytesRead;
+                               // Free up the Irp Context
+                               Ext2ReleaseIrpContext(PtrIrpContext);
+       
+                               // complete the IRP
+                               IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
+                       }
+               } // can we complete the IRP ?
+               else
+               {
+                       // Free up the Irp Context
+                       Ext2ReleaseIrpContext(PtrIrpContext);
+               }
+       } // end of "finally" processing
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2GetCallersBuffer()
+ *
+ * Description:
+ *     Obtain a pointer to the caller's buffer.
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ void * Ext2GetCallersBuffer (
+               PIRP  PtrIrp )
+ {
+       void    * ReturnedBuffer = NULL;
+       // If an MDL is supplied, use it.
+       if (PtrIrp->MdlAddress) 
+       {
+               ReturnedBuffer = MmGetSystemAddressForMdl(PtrIrp->MdlAddress);
+       } 
+       else 
+       {
+               ReturnedBuffer = PtrIrp->UserBuffer;
+       }
+       return (ReturnedBuffer);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2LockCallersBuffer()
+ *
+ * Description:
+ *     Obtain a MDL that describes the buffer. Lock pages for I/O
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: STATUS_SUCCESS/Error
+ *
+ *************************************************************************/
+ NTSTATUS Ext2LockCallersBuffer(
+ PIRP                          PtrIrp,
+ BOOLEAN                       IsReadOperation,
+ uint32                        Length)
+ {
+       NTSTATUS                        RC = STATUS_SUCCESS;
+       PMDL                            PtrMdl = NULL;
+       ASSERT(PtrIrp);
+       
+       try 
+       {
+               // Is a MDL already present in the IRP
+               if( !(PtrIrp->MdlAddress) )
+               {
+                       // Allocate a MDL
+                       if (!(PtrMdl = IoAllocateMdl(PtrIrp->UserBuffer, Length, FALSE, FALSE, PtrIrp))) 
+                       {
+                               RC = STATUS_INSUFFICIENT_RESOURCES;
+                               try_return(RC);
+                       }
+                       // Probe and lock the pages described by the MDL
+                       // We could encounter an exception doing so, swallow the exception
+                       // NOTE: The exception could be due to an unexpected (from our
+                       // perspective), invalidation of the virtual addresses that comprise
+                       // the passed in buffer
+                       try 
+                       {
+                               MmProbeAndLockPages(PtrMdl, PtrIrp->RequestorMode, (IsReadOperation ? IoWriteAccess:IoReadAccess));
+                       } 
+                       except(EXCEPTION_EXECUTE_HANDLER) 
+                       {
+                               RC = STATUS_INVALID_USER_BUFFER;
+                       }
+               }
+               try_exit:       NOTHING;
+       } 
+       finally 
+       {
+               if (!NT_SUCCESS(RC) && PtrMdl) 
+               {
+                       IoFreeMdl(PtrMdl);
+                       // You MUST NULL out the MdlAddress field in the IRP after freeing
+                       // the MDL, else the I/O Manager will also attempt to free the MDL
+                       // pointed to by that field during I/O completion. Obviously, the
+                       // pointer becomes invalid once you free the allocated MDL and hence
+                       // you will encounter a system crash during IRP completion.
+                       PtrIrp->MdlAddress = NULL;
+               }
+       }
+       return(RC);
+ }
+ /*************************************************************************
+ *
+ * Function: Ext2MdlComplete()
+ *
+ * Description:
+ *     Tell Cache Manager to release MDL (and possibly flush).
+ *
+ * Expected Interrupt Level (for execution) :
+ *
+ *  IRQL_PASSIVE_LEVEL
+ *
+ * Return Value: None.
+ *
+ *************************************************************************/
+ void Ext2MdlComplete(
+       PtrExt2IrpContext                       PtrIrpContext,
+       PIRP                                            PtrIrp,
+       PIO_STACK_LOCATION                      PtrIoStackLocation,
+       BOOLEAN                                         ReadCompletion)
+ {
+       NTSTATUS                                        RC = STATUS_SUCCESS;
+       PFILE_OBJECT                    PtrFileObject = NULL;
+       PtrFileObject = PtrIoStackLocation->FileObject;
+       ASSERT(PtrFileObject);
+       // Not much to do here.
+       if( ReadCompletion ) 
+       {
+               CcMdlReadComplete( PtrFileObject, PtrIrp->MdlAddress );
+       } 
+       else 
+       {
+               // The Cache Manager needs the byte offset in the I/O stack location.
+               CcMdlWriteComplete( PtrFileObject, &(PtrIoStackLocation->Parameters.Write.ByteOffset), PtrIrp->MdlAddress );
+       }
+       // Clear the MDL address field in the IRP so the IoCompleteRequest()
+       // does not try to play around with the MDL.
+       PtrIrp->MdlAddress = NULL;
+       // Free up the Irp Context.
+       Ext2ReleaseIrpContext(PtrIrpContext);
+       // Complete the IRP.
+       PtrIrp->IoStatus.Status = RC;
+       PtrIrp->IoStatus.Information = 0;
+       IoCompleteRequest(PtrIrp, IO_NO_INCREMENT);
+       return;
+ }
index 0000000,0000000..0ec7d2f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,211 @@@
++/*************************************************************************
++*
++* File: shutdown.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Contains code to handle the "shutdown notification" dispatch entry point.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#include                      "ext2fsd.h"
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_SHUTDOWN
++#define                       DEBUG_LEVEL                                             (DEBUG_TRACE_SHUTDOWN)
++
++
++/*************************************************************************
++*
++* Function: Ext2Shutdown()
++*
++* Description:
++*     All disk-based FSDs can expect to receive this shutdown notification
++*     request whenever the system is about to be halted gracefully. If you
++*     design and implement a network redirector, you must register explicitly
++*     for shutdown notification by invoking the IoRegisterShutdownNotification()
++*     routine from your driver entry.
++*
++*     Note that drivers that register to receive shutdown notification get
++*     invoked BEFORE disk-based FSDs are told about the shutdown notification.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: Irrelevant.
++*
++*************************************************************************/
++NTSTATUS Ext2Shutdown(
++      PDEVICE_OBJECT          DeviceObject,           // the logical volume device object
++      PIRP                            Irp)                                    // I/O Request Packet
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PtrExt2IrpContext       PtrIrpContext = NULL;
++      BOOLEAN                         AreWeTopLevel = FALSE;
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY, "Shutdown IRP received...", 0);
++
++      FsRtlEnterFileSystem();
++      ASSERT(DeviceObject);
++      ASSERT(Irp);
++
++      // set the top level context
++      AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
++
++      try 
++      {
++
++              // get an IRP context structure and issue the request
++              PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
++              ASSERT(PtrIrpContext);
++
++              RC = Ext2CommonShutdown(PtrIrpContext, Irp);
++
++      } 
++      except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++      {
++
++              RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
++
++              Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++      }
++
++      if (AreWeTopLevel) 
++      {
++              IoSetTopLevelIrp(NULL);
++      }
++
++      FsRtlExitFileSystem();
++
++      return(RC);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2CommonShutdown()
++*
++* Description:
++*     The actual work is performed here. Basically, all we do here is
++*     internally invoke a flush on all mounted logical volumes. This, in
++*     tuen, will result in all open file streams being flushed to disk.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: Irrelevant
++*
++*************************************************************************/
++NTSTATUS      Ext2CommonShutdown(
++PtrExt2IrpContext                     PtrIrpContext,
++PIRP                                                  PtrIrp)
++{
++      NTSTATUS                                        RC = STATUS_SUCCESS;
++      PIO_STACK_LOCATION                      PtrIoStackLocation = NULL;
++      IO_STATUS_BLOCK                         LocalIoStatus;
++
++      try 
++      {
++              // First, get a pointer to the current I/O stack location
++              PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
++              ASSERT(PtrIoStackLocation);
++
++              // (a) Block all new "mount volume" requests by acquiring an appropriate
++              //               global resource/lock.
++              // (b) Go through your linked list of mounted logical volumes and for
++              //               each such volume, do the following:
++              //               (i) acquire the volume resource exclusively
++              //               (ii) invoke Ext2FlushLogicalVolume() (internally) to flush the
++              //                              open data streams belonging to the volume from the system
++              //                              cache
++              //               (iii) Invoke the physical/virtual/logical target device object
++              //                              on which the volume is mounted and inform this device
++              //                              about the shutdown request (Use IoBuildSynchronousFsdRequest()
++              //                              to create an IRP with MajorFunction = IRP_MJ_SHUTDOWN that you
++              //                              will then issue to the target device object).
++              //               (iv) Wait for the completion of the shutdown processing by the target
++              //                              device object
++              //               (v) Release the VCB resource you will have acquired in (i) above.
++
++              // Once you have processed all the mounted logical volumes, you can release
++              // all acquired global resources and leave (in peace :-)
++
++      
++
++/*////////////////////////////////////////////
++              //
++              //      Update the Group...
++              //
++              if( PtrVCB->LogBlockSize )
++              {
++                      //      First block contains the descriptors...
++                      VolumeByteOffset.QuadPart = LogicalBlockSize;
++              }
++              else
++              {
++                      //      Second block contains the descriptors...
++                      VolumeByteOffset.QuadPart = LogicalBlockSize * 2;
++              }
++
++              NumberOfBytesToRead = sizeof( struct ext2_group_desc );
++              NumberOfBytesToRead = Ext2Align( NumberOfBytesToRead, LogicalBlockSize );
++
++              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++               &VolumeByteOffset,
++               NumberOfBytesToRead,
++               TRUE,
++               &PtrBCB,
++               &PtrCacheBuffer )) 
++              {
++                      DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                      try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
++              }
++              else
++              {
++                      //      
++                      //      Saving up Often Used Group Descriptor Information in the VCB...
++                      //
++                      unsigned int DescIndex ;
++
++                      DebugTrace(DEBUG_TRACE_MISC,   "Cache hit while reading in volume meta data", 0);
++                      PtrGroupDescriptor = (PEXT2_GROUP_DESCRIPTOR )PtrCacheBuffer;
++                      for( DescIndex = 0; DescIndex < PtrVCB->NoOfGroups; DescIndex++ )
++                      {
++                              PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeTablesBlock 
++                                      = PtrGroupDescriptor[ DescIndex ].bg_inode_table;
++
++                              PtrVCB->PtrGroupDescriptors[ DescIndex ].InodeBitmapBlock 
++                                      = PtrGroupDescriptor[ DescIndex ].bg_inode_bitmap
++                                      ;
++                              PtrVCB->PtrGroupDescriptors[ DescIndex ].BlockBitmapBlock 
++                                      = PtrGroupDescriptor[ DescIndex ].bg_block_bitmap
++                                      ;
++                              PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeBlocksCount 
++                                      = PtrGroupDescriptor[ DescIndex ].bg_free_blocks_count;
++
++                              PtrVCB->PtrGroupDescriptors[ DescIndex ].FreeInodesCount 
++                                      = PtrGroupDescriptor[ DescIndex ].bg_free_inodes_count;
++                      }
++                      CcUnpinData( PtrBCB );
++                      PtrBCB = NULL;
++              }
++*/////////////////////////////////////////////
++
++              try_exit:       NOTHING;
++
++      } 
++      finally 
++      {
++
++              // See the read/write examples for how to fill in this portion
++
++      } // end of "finally" processing
++
++      return(RC);
++}
index 0000000,0000000..2e34162
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,339 @@@
++/*************************************************************************
++*
++* File: volinfo.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Contains code to handle the various Volume Information related calls.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++
++
++#include "ext2fsd.h"
++
++
++
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_VOL_INFORMATION
++#define                       DEBUG_LEVEL                                             (DEBUG_TRACE_VOLINFO)
++
++
++/*************************************************************************
++*
++* Function: Ext2QueryVolInfo()
++*
++* Description:
++*     The I/O Manager will invoke this routine to handle a 
++*   Query Volume Info IRP
++*
++* Expected Interrupt Level (for execution) :
++*  
++*     ???
++*
++* Arguments:
++*
++*    DeviceObject - Supplies the volume device object where the
++*                   file exists
++*
++*    Irp - Supplies the Irp being processed
++*
++*
++* Return Value:
++*
++*    NTSTATUS - The FSD status for the IRP
++*
++*************************************************************************/
++NTSTATUS Ext2QueryVolInfo (
++      IN PDEVICE_OBJECT       DeviceObject,
++      IN PIRP Irp)
++{
++
++      //      The Return Status
++    NTSTATUS Status = STATUS_SUCCESS;
++
++      //      The IRP Stack Location
++      PIO_STACK_LOCATION      IrpSp = NULL;
++
++      //      Volume Control Block
++      PtrExt2VCB                      PtrVCB = NULL;
++      
++      //      The class of the query IRP
++    FS_INFORMATION_CLASS FsInformationClass;
++      
++      //      The System Buffer Pointer
++    PVOID Buffer = NULL;
++      
++      //      Parameter Length
++      ULONG Length = 0;
++      
++      //      Bytes copied...
++      ULONG BytesCopied = 0;
++
++      //      Pointers to the Output Information...
++      PFILE_FS_VOLUME_INFORMATION             PtrVolumeInformation    = NULL;
++      PFILE_FS_SIZE_INFORMATION               PtrSizeInformation              = NULL;
++      PFILE_FS_ATTRIBUTE_INFORMATION  PtrAttributeInformation = NULL;
++      PFILE_FS_DEVICE_INFORMATION             PtrDeviceInformation    = NULL;
++      PFILE_FS_FULL_SIZE_INFORMATION  PtrFullSizeInformation  = NULL;
++
++
++      //      Now for the handler code...
++    DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "QueryVolumeInformation IRP", 0);
++
++    FsRtlEnterFileSystem();
++
++    try 
++      {
++              // Getting a pointer to the current I/O stack location
++              IrpSp = IoGetCurrentIrpStackLocation(Irp);
++              ASSERT( IrpSp );
++              
++              //      Getting the VCB and Verifying it...
++              PtrVCB = ( PtrExt2VCB )( DeviceObject->DeviceExtension );
++              ASSERT(PtrVCB);
++              ASSERT(PtrVCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB);
++              
++              //      Getting the query parameters...
++              Length = IrpSp->Parameters.QueryVolume.Length;
++              FsInformationClass = IrpSp->Parameters.QueryVolume.FsInformationClass;
++              Buffer = Irp->AssociatedIrp.SystemBuffer;
++
++              //      Now servicing the request depending on the type...
++        switch (FsInformationClass) 
++              {
++        case FileFsVolumeInformation:
++                      DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - FileFsVolumeInformation", 0);
++                      PtrVolumeInformation = Buffer;
++                      PtrVolumeInformation->SupportsObjects = FALSE;
++                      PtrVolumeInformation->VolumeCreationTime.QuadPart = 0;
++                      RtlCopyMemory( 
++                              PtrVolumeInformation->VolumeLabel,      //      destination
++                              PtrVCB->PtrVPB->VolumeLabel,            //      source
++                              PtrVCB->PtrVPB->VolumeLabelLength );
++                      PtrVolumeInformation->VolumeLabelLength = PtrVCB->PtrVPB->VolumeLabelLength;
++                      PtrVolumeInformation->VolumeSerialNumber = PtrVCB->PtrVPB->SerialNumber;
++                      BytesCopied = sizeof( FILE_FS_VOLUME_INFORMATION ) + PtrVolumeInformation->VolumeLabelLength - sizeof( WCHAR);
++            break;
++
++        case FileFsSizeInformation:
++                      DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - FileFsSizeInformation", 0);
++                      PtrSizeInformation = Buffer;
++                      PtrSizeInformation->BytesPerSector = DeviceObject->SectorSize;
++                      PtrSizeInformation->AvailableAllocationUnits.QuadPart   = PtrVCB->FreeBlocksCount;
++                      PtrSizeInformation->SectorsPerAllocationUnit    = ( EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize) / DeviceObject->SectorSize;
++                      PtrSizeInformation->TotalAllocationUnits.QuadPart               = PtrVCB->BlocksCount;
++                      BytesCopied = sizeof( FILE_FS_SIZE_INFORMATION );
++            break;
++
++        case FileFsDeviceInformation:
++            DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - FileFsDeviceInformation", 0);
++                      PtrDeviceInformation = Buffer;
++                      PtrDeviceInformation->DeviceType = FILE_DEVICE_DISK;
++                      PtrDeviceInformation->Characteristics = FILE_DEVICE_IS_MOUNTED;
++                      BytesCopied = sizeof( FILE_FS_DEVICE_INFORMATION );
++            break;
++
++        case FileFsAttributeInformation:
++            DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - FileFsAttributeInformation", 0);
++                      PtrAttributeInformation = Buffer;
++                      RtlCopyMemory( PtrAttributeInformation->FileSystemName, L"EXT2", 10 );
++                      PtrAttributeInformation->FileSystemNameLength = 8;
++                      PtrAttributeInformation->MaximumComponentNameLength = 255;
++                      PtrAttributeInformation->FileSystemAttributes  = 
++                              FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
++                      BytesCopied = sizeof( FILE_FS_ATTRIBUTE_INFORMATION ) + 8; 
++
++            break;
++
++        case FileFsFullSizeInformation:
++            DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - FileFsFullSizeInformation", 0);
++                      PtrFullSizeInformation = Buffer;
++                      PtrFullSizeInformation->BytesPerSector = DeviceObject->SectorSize;
++                      PtrFullSizeInformation->ActualAvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount;
++                      PtrFullSizeInformation->SectorsPerAllocationUnit        = (EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize) / DeviceObject->SectorSize;
++                      PtrFullSizeInformation->TotalAllocationUnits.QuadPart           = PtrVCB->BlocksCount;
++                      PtrFullSizeInformation->CallerAvailableAllocationUnits.QuadPart = PtrVCB->FreeBlocksCount - PtrVCB->ReservedBlocksCount;
++                      BytesCopied = sizeof( FILE_FS_FULL_SIZE_INFORMATION );
++            break;
++
++        default:
++            Status = STATUS_INVALID_PARAMETER;
++                      DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - STATUS_INVALID_PARAMETER", 0);
++            break;
++        }
++              
++              if( IrpSp->Parameters.QueryVolume.Length < BytesCopied )        
++              {
++                      BytesCopied = IrpSp->Parameters.QueryVolume.Length;
++                      Status = STATUS_BUFFER_OVERFLOW;
++                      DebugTrace(DEBUG_TRACE_MISC,   " === Buffer insufficient", 0);
++              }
++              try_exit: NOTHING;
++    }
++      finally
++      {
++              Irp->IoStatus.Information = BytesCopied;
++              Ext2CompleteRequest( Irp, Status );
++      }
++    FsRtlExitFileSystem();
++
++    //
++    //  Now return to the caller
++    //
++
++    return Status;
++}
++
++
++
++NTSTATUS Ext2SetVolInfo(
++      IN PDEVICE_OBJECT       DeviceObject,
++      IN PIRP Irp)
++{
++      //      The Return Status
++    NTSTATUS Status = STATUS_SUCCESS;
++
++      //      The IRP Stack Location
++      PIO_STACK_LOCATION      IrpSp = NULL;
++
++      //      Volume Control Block
++      PtrExt2VCB                      PtrVCB = NULL;
++      
++      //      The class of the query IRP
++    FS_INFORMATION_CLASS FsInformationClass;
++      
++      //      Pointers to the Output Information...
++      PFILE_FS_LABEL_INFORMATION              PtrVolumeLabelInformation = NULL;
++
++      //      Now for the handler code...
++    DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "Set Volume Information IRP", 0);
++
++    FsRtlEnterFileSystem();
++
++    try 
++      {
++              // Getting a pointer to the current I/O stack location
++              IrpSp = IoGetCurrentIrpStackLocation(Irp);
++              ASSERT( IrpSp );
++              
++              //      Getting the VCB and Verifying it...
++              PtrVCB = ( PtrExt2VCB )( DeviceObject->DeviceExtension );
++              AssertVCB(PtrVCB);
++              
++              //      Getting the query parameters...
++              //      Length = IrpSp->Parameters.SetVolume.Length;
++#ifdef _GNU_NTIFS_
++              FsInformationClass = ((PEXTENDED_IO_STACK_LOCATION)IrpSp)->Parameters.SetVolume.FsInformationClass;
++#else
++              FsInformationClass = IrpSp->Parameters.SetVolume.FsInformationClass;
++#endif
++
++              //      Now servicing the request depending on the type...
++        switch (FsInformationClass) 
++              {
++              case FileFsLabelInformation:
++                      PtrVolumeLabelInformation = Irp->AssociatedIrp.SystemBuffer;
++                      if( PtrVolumeLabelInformation->VolumeLabelLength > MAXIMUM_VOLUME_LABEL_LENGTH ||       //      This is the maximum that the 
++                                                                                                                                                                                              //      VPB can take...
++                              PtrVolumeLabelInformation->VolumeLabelLength > 32 )     //      this is the maximum that Ext2 FS can support..
++                      {
++                              try_return( Status = STATUS_INVALID_VOLUME_LABEL );
++                      }
++
++                      PtrVCB->PtrVPB->VolumeLabelLength = (USHORT)PtrVolumeLabelInformation->VolumeLabelLength ;
++                      RtlCopyMemory( 
++                              PtrVCB->PtrVPB->VolumeLabel,            //      destination
++                              PtrVolumeLabelInformation->VolumeLabel, //      source  
++                              PtrVolumeLabelInformation->VolumeLabelLength );
++                      
++                      {
++                              //      Now update the volume's super block...
++
++                              PEXT2_SUPER_BLOCK       PtrSuperBlock = NULL;
++                              PBCB                            PtrSuperBlockBCB = NULL;
++                              LARGE_INTEGER           VolumeByteOffset;
++                              ULONG                           LogicalBlockSize = 0;
++                              ULONG                           NumberOfBytesToRead = 0;
++
++
++                              //      Reading in the super block...
++                              VolumeByteOffset.QuadPart = 1024;
++
++                              LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++
++                              //      THis shouldn't be more than a block in size...
++                              NumberOfBytesToRead = Ext2Align( sizeof( EXT2_SUPER_BLOCK ), LogicalBlockSize );
++
++                              if( !CcPinRead( PtrVCB->PtrStreamFileObject,
++                                         &VolumeByteOffset,
++                                         NumberOfBytesToRead,
++                                         TRUE,
++                                         &PtrSuperBlockBCB,
++                                         (PVOID*)&PtrSuperBlock ) )
++                              {
++                                      DebugTrace(DEBUG_TRACE_ERROR,   "Cache read failiure while reading in volume meta data", 0);
++                                      try_return( Status = STATUS_INVALID_VOLUME_LABEL );
++                              }
++                              else
++                              {
++                                      ULONG i;
++                                      for( i = 0; i < (PtrVolumeLabelInformation->VolumeLabelLength/2) ; i++ )
++                                      {
++                                              PtrSuperBlock->s_volume_name[i] = 
++                                                      (char) PtrVolumeLabelInformation->VolumeLabel[i] ;
++                                              if( PtrSuperBlock->s_volume_name[i] == 0 )
++                                              {
++                                                      break;
++                                              }
++                                      }
++                                      if( i < 16 )
++                                      {
++                                              PtrSuperBlock->s_volume_name[i] = 0;
++                                      }
++
++
++                                      CcSetDirtyPinnedData( PtrSuperBlockBCB, NULL );
++                                      
++                                      //      Not saving and flushing this information synchronously...
++                                      //      This is not a critical information..
++                                      //      Settling for lazy writing of this information
++
++                                      //      Ext2SaveBCB( PtrIrpContext, PtrSuperBlockBCB, PtrVCB->PtrStreamFileObject );
++                                      
++                                      if( PtrSuperBlockBCB )
++                                      {
++                                              CcUnpinData( PtrSuperBlockBCB );
++                                              PtrSuperBlockBCB = NULL;
++                                      }
++                                      
++                              }
++                      }
++
++                      break;
++        default:
++            Status = STATUS_INVALID_PARAMETER;
++                      DebugTrace(DEBUG_TRACE_MISC,   "Query Volume - STATUS_INVALID_PARAMETER", 0);
++            break;
++              }
++              
++              try_exit: NOTHING;
++    }
++      finally
++      {
++              Irp->IoStatus.Information = 0;
++              Ext2CompleteRequest( Irp, Status );
++      }
++    FsRtlExitFileSystem();
++
++    //
++    //  Now return to the caller
++    //
++
++    return Status;
++}
index 0000000,0000000..1596ecd
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,1483 @@@
++/*************************************************************************
++*
++* File: write.c
++*
++* Module: Ext2 File System Driver (Kernel mode execution only)
++*
++* Description:
++*     Contains code to handle the "Write" dispatch entry point.
++*
++* Author: Manoj Paul Joseph
++*
++*
++*************************************************************************/
++
++#include                      "ext2fsd.h"
++
++// define the file specific bug-check id
++#define                       EXT2_BUG_CHECK_ID                               EXT2_FILE_WRITE
++
++#define                       DEBUG_LEVEL                                             (DEBUG_TRACE_WRITE)
++
++
++/*************************************************************************
++*
++* Function: Ext2Write()
++*
++* Description:
++*     The I/O Manager will invoke this routine to handle a write
++*     request
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL (invocation at higher IRQL will cause execution
++*     to be deferred to a worker thread context)
++*
++* Return Value: STATUS_SUCCESS/Error
++*
++*************************************************************************/
++NTSTATUS Ext2Write(
++PDEVICE_OBJECT                DeviceObject,           // the logical volume device object
++PIRP                                  Irp)                                    // I/O Request Packet
++{
++      NTSTATUS                                RC = STATUS_SUCCESS;
++    PtrExt2IrpContext PtrIrpContext = NULL;
++      BOOLEAN                         AreWeTopLevel = FALSE;
++
++      DebugTrace(DEBUG_TRACE_IRP_ENTRY,   "Write IRP Received...", 0);
++
++      //      Ext2BreakPoint();
++
++      FsRtlEnterFileSystem();
++      ASSERT(DeviceObject);
++      ASSERT(Irp);
++
++      // set the top level context
++      AreWeTopLevel = Ext2IsIrpTopLevel(Irp);
++
++      try 
++      {
++              // get an IRP context structure and issue the request
++              PtrIrpContext = Ext2AllocateIrpContext(Irp, DeviceObject);
++              ASSERT(PtrIrpContext);
++
++              RC = Ext2CommonWrite(PtrIrpContext, Irp);
++      } 
++      except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 
++      {
++              RC = Ext2ExceptionHandler(PtrIrpContext, Irp);
++              Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC);
++      }
++
++      if (AreWeTopLevel) 
++      {
++              IoSetTopLevelIrp(NULL);
++      }
++
++      FsRtlExitFileSystem();
++
++      return(RC);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2CommonWrite()
++*
++* Description:
++*     The actual work is performed here. This routine may be invoked in one'
++*     of the two possible contexts:
++*     (a) in the context of a system worker thread
++*     (b) in the context of the original caller
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: STATUS_SUCCESS/Error
++*
++*************************************************************************/
++NTSTATUS      Ext2CommonWrite(
++      PtrExt2IrpContext                       PtrIrpContext,
++      PIRP                                            PtrIrp)
++{
++
++      NTSTATUS                                RC = STATUS_SUCCESS;
++      PIO_STACK_LOCATION              PtrIoStackLocation = NULL;
++      LARGE_INTEGER                   ByteOffset;
++      uint32                                  WriteLength = 0;
++      uint32                                  NumberBytesWritten = 0;
++      PFILE_OBJECT                    PtrFileObject = NULL;
++      PtrExt2FCB                              PtrFCB = NULL;
++      PtrExt2CCB                              PtrCCB = NULL;
++      PtrExt2VCB                              PtrVCB = NULL;
++      PtrExt2NTRequiredFCB    PtrReqdFCB = NULL;
++      PERESOURCE                              PtrResourceAcquired = NULL;
++      IO_STATUS_BLOCK                 LocalIoStatus;
++      void                                    *PtrSystemBuffer = NULL;
++      uint32                                  KeyValue = 0;
++
++      BOOLEAN                                 CompleteIrp = TRUE;
++      BOOLEAN                                 PostRequest = FALSE;
++
++      BOOLEAN                                 CanWait = FALSE;
++      BOOLEAN                                 PagingIo = FALSE;
++      BOOLEAN                                 NonBufferedIo = FALSE;
++      BOOLEAN                                 SynchronousIo = FALSE;
++      BOOLEAN                                 IsThisADeferredWrite = FALSE;
++      BOOLEAN                                 WritingAtEndOfFile = FALSE;
++
++      EXT2_IO_RUN                             *PtrIoRuns = NULL;
++                      
++      PBCB            PtrPinnedSIndirectBCB = NULL;
++      PBCB            PtrPinnedDIndirectBCB = NULL;
++      PBCB            PtrPinnedTIndirectBCB = NULL;
++      
++      //      Used to cache the Single Indirect blocks pointed to by 
++      //      the Double Indirect block
++      PEXT2_SIBLOCKS                  PtrDIArray = NULL;
++      ULONG                                   DIArrayCount = 0;
++
++      //      Used to cache the Single Indirect blocks pointed to by 
++      //      the Triple Indirect block
++      PEXT2_SIBLOCKS                  PtrTIArray = NULL;
++      ULONG                                   TIArrayCount = 0;
++
++
++      try 
++      {
++              // First, get a pointer to the current I/O stack location
++              PtrIoStackLocation = IoGetCurrentIrpStackLocation(PtrIrp);
++              ASSERT(PtrIoStackLocation);
++
++              PtrFileObject = PtrIoStackLocation->FileObject;
++              ASSERT(PtrFileObject);
++
++              // If this happens to be a MDL write complete request, then
++              // allocated MDL can be freed. 
++              if(PtrIoStackLocation->MinorFunction & IRP_MN_COMPLETE) 
++              {
++                      // Caller wants to tell the Cache Manager that a previously
++                      // allocated MDL can be freed.
++                      Ext2MdlComplete(PtrIrpContext, PtrIrp, PtrIoStackLocation, FALSE);
++                      // The IRP has been completed.
++                      CompleteIrp = FALSE;
++                      try_return(RC = STATUS_SUCCESS);
++              }
++
++              // If this is a request at IRQL DISPATCH_LEVEL, then post the request 
++              if (PtrIoStackLocation->MinorFunction & IRP_MN_DPC) 
++              {
++                      CompleteIrp = FALSE;
++                      PostRequest = TRUE;
++                      try_return(RC = STATUS_PENDING);
++              }
++
++
++              // Get the FCB and CCB pointers
++              Ext2GetFCB_CCB_VCB_FromFileObject ( 
++                      PtrFileObject, &PtrFCB, &PtrCCB, &PtrVCB );
++
++
++              // Get some of the parameters supplied to us
++              ByteOffset = PtrIoStackLocation->Parameters.Write.ByteOffset;
++              WriteLength = PtrIoStackLocation->Parameters.Write.Length;
++
++              CanWait = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
++              PagingIo = ((PtrIrp->Flags & IRP_PAGING_IO) ? TRUE : FALSE);
++              NonBufferedIo = ((PtrIrp->Flags & IRP_NOCACHE) ? TRUE : FALSE);
++              SynchronousIo = ((PtrFileObject->Flags & FO_SYNCHRONOUS_IO) ? TRUE : FALSE);
++
++              if( PtrFCB && PtrFCB->FCBName && PtrFCB->FCBName->ObjectName.Length && PtrFCB->FCBName->ObjectName.Buffer )
++              {
++                      DebugTrace(DEBUG_TRACE_FILE_NAME,   " === Write File Name : -%S-", PtrFCB->FCBName->ObjectName.Buffer );
++              }
++              else
++              {
++                      DebugTrace(DEBUG_TRACE_FILE_NAME,   " === Write File Name : -null-", 0);
++              }
++              
++              DebugTrace( DEBUG_TRACE_SPECIAL,   "  ->ByteCount           = 0x%8lx", PtrIoStackLocation->Parameters.Read.Length);
++              DebugTrace( DEBUG_TRACE_SPECIAL,   "  ->ByteOffset.LowPart  = 0x%8lx", PtrIoStackLocation->Parameters.Read.ByteOffset.LowPart);
++              
++              if( CanWait )
++              {
++                      DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->Can Wait ", 0 );
++              }
++              else
++              {
++                      DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->Can't Wait ", 0 );
++              }
++              
++              if( PagingIo )
++              {
++                      DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->Paging Io ", 0 );
++              }
++              else
++              {
++                      DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->Not Paging Io", 0 );
++              }
++
++              if( SynchronousIo )
++              {
++                      DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->SynchronousIo ", 0 );
++              }
++              else
++              {
++                      DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->ASynchronousIo ", 0 );
++              }
++
++              if( NonBufferedIo )
++              {
++                      DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->NonBufferedIo", 0 );
++              }
++              else
++              {
++                      DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "  ->BufferedIo", 0 );
++              }
++              // Check at this point whether the file object being
++              // used for write really did have write permission requested when the
++              // create/open operation was performed. 
++              // Don't do this for paging io...
++
++              if (WriteLength == 0) 
++              {
++                      // a 0 byte write can be immediately succeeded
++                      try_return(RC);
++              }
++
++              // Is this a write of the volume itself ?
++              if ( ( !PtrFCB && PtrVCB ) || PtrFCB->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) 
++              {
++                      //
++                      //              >>>>>>>>>>>>>>>>>>              VOLUME WRITE      <<<<<<<<<<<<<<
++                      //
++
++                      //      Validate the offset and length first...
++                      //      .......................................
++
++                      // Acquire the volume resource exclusively
++                      if( PtrFileObject )
++                      {
++                              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Write]", PtrFileObject);
++                      }
++
++                      if( PagingIo )
++                      {
++                              //      This is Paging IO...
++
++                              DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** Attempting to acquire VCBPaging Exclusively [Write]", 0);
++                              DebugTraceState( "VCBPaging       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Write]", PtrVCB->PagingIoResource.ActiveCount, PtrVCB->PagingIoResource.NumberOfExclusiveWaiters, PtrVCB->PagingIoResource.NumberOfSharedWaiters );
++                              
++                              if( !ExAcquireResourceExclusiveLite( &( PtrVCB->PagingIoResource ), FALSE ) )
++                              {
++                                      // post the request to be processed in the context of a worker thread
++                                      DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** VCBPaging Acquisition FAILED [Write]", 0);
++                                      CompleteIrp = FALSE;
++                                      PostRequest = TRUE;
++                                      try_return(RC = STATUS_PENDING);
++                              }
++
++                              DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** VCBPaging Acquired [Write]", 0);
++                              PtrResourceAcquired = &(PtrVCB->PagingIoResource);
++                      }
++                      else
++                      {
++                              //      This is not Paging IO...
++
++                              DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** Attempting to acquire VCB Exclusively [Write]", 0);
++                              DebugTraceState( "VCB       AC:0x%LX   SW:0x%LX   EX:0x%LX   [Write]", PtrVCB->VCBResource.ActiveCount, 
++                                      PtrVCB->VCBResource.NumberOfExclusiveWaiters, PtrVCB->VCBResource.NumberOfSharedWaiters );
++                              
++                              if( !ExAcquireResourceExclusiveLite( &(PtrVCB->VCBResource), FALSE ) )
++                              {
++                                      // post the request to be processed in the context of a worker thread
++                                      DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** VCB Acquisition FAILED [Write]", 0);
++                                      CompleteIrp = FALSE;
++                                      PostRequest = TRUE;
++                                      try_return(RC = STATUS_PENDING);
++                              }
++
++                              DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** VCB Acquired [Write]", 0);
++                              PtrResourceAcquired = &(PtrVCB->VCBResource);
++                      }
++                      
++                      // Validate the caller supplied offset here
++                      if( !PagingIo )
++                      {
++                              if( PtrVCB->CommonVCBHeader.AllocationSize.QuadPart < ByteOffset.QuadPart )
++                              {
++                                      //      Write extending beyond the end of volume.
++                                      //      Deny access...
++                                      //
++                                      RC = STATUS_END_OF_FILE;
++                                      NumberBytesWritten = 0;
++                                      try_return( RC );
++                              }
++                      }
++
++                      // Lock the callers buffer
++                      if (!NT_SUCCESS(RC = Ext2LockCallersBuffer(PtrIrp, TRUE, WriteLength))) 
++                      {
++                              try_return(RC);
++                      }
++
++                      // Forward the request to the lower level driver
++                      if( PagingIo || NonBufferedIo )
++                      {
++                              DebugTrace(DEBUG_TRACE_WRITE_DETAILS,  "[Volume Write] PagingIo or NonBufferedIo ", 0);
++                              CompleteIrp = FALSE;
++
++                              //
++                              //      Do the write operation...
++                              //      Send down the IRP to the lower level driver...
++                              //
++                              //      Returned Informations and Status will be set by the lower level driver...
++                              //      The IRP will also be completed by the lower level driver...
++
++                              RC = Ext2PassDownSingleReadWriteIRP (
++                                              PtrIrpContext, PtrIrp, PtrVCB, 
++                                              ByteOffset, WriteLength, SynchronousIo );
++
++                              try_return(RC);
++                      }
++                      else
++                      {
++                              PBCB            PtrBCB = NULL;
++                              PVOID           PtrBuffer = NULL;
++
++                              DebugTrace(DEBUG_TRACE_READ_DETAILS,  "[Volume Write] BufferedIo ", 0);
++                                                              //
++                              //      Let the cache manager worry about this write...
++                              //      Pinned access should have been initiated.
++                              //      But checking anyway...
++                              //
++                              ASSERT( PtrVCB->PtrStreamFileObject );
++                              ASSERT( PtrVCB->PtrStreamFileObject->PrivateCacheMap );
++
++                              CcPreparePinWrite( 
++                                      PtrVCB->PtrStreamFileObject,
++                                      &ByteOffset,
++                                      WriteLength,
++                                      FALSE,                  //      Don't Zero...
++                                      TRUE,                   //      Can Wait...
++                                      &PtrBCB,
++                                      &PtrBuffer);
++
++                              //      Do the write now...
++                              //      Write to the Pinned buffer...
++                              //      Cache Manager will do the disk write...
++                              RtlCopyBytes( PtrBuffer, PtrSystemBuffer, WriteLength );
++                              //      CcSetDirtyPinnedData( PtrBCB, NULL );
++                              CcUnpinData( PtrBCB );
++                              PtrBuffer = NULL;
++                              PtrBCB = NULL;
++
++                              NumberBytesWritten = WriteLength;
++
++                              //      Go ahead and complete the IRP...
++                      }
++                      try_return(RC);
++              }
++
++      
++              IsThisADeferredWrite = ((PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_DEFERRED_WRITE) ? TRUE : FALSE);
++
++              if (!NonBufferedIo) 
++              {
++                      /****************************************************************************
++                      if (!CcCanIWrite(PtrFileObject, WriteLength, CanWait, IsThisADeferredWrite)) 
++                      {
++                              // Cache Manager and/or the VMM does not want us to perform
++                              // the write at this time. Post the request.
++                              Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_DEFERRED_WRITE);
++                              CcDeferWrite( PtrFileObject, Ext2DeferredWriteCallBack, PtrIrpContext, PtrIrp, WriteLength, IsThisADeferredWrite);
++                              CompleteIrp = FALSE;
++                              try_return( RC = STATUS_PENDING );
++                      }
++                      ****************************************************************************/
++              }
++
++              // If the write request is directed to a page file 
++              // send the request directly to the disk
++              // driver. For requests directed to a page file, you have to trust
++              // that the offsets will be set correctly by the VMM. You should not
++              // attempt to acquire any FSD resources either.
++              if (PtrFCB->FCBFlags & EXT2_FCB_PAGE_FILE) 
++              {
++                      IoMarkIrpPending(PtrIrp);
++
++                      // You will need to set a completion routine before invoking a lower level driver.
++                      //      Forward request directly to disk driver.
++                      // Ext2PageFileIo(PtrIrpContext, PtrIrp);
++
++                      CompleteIrp = FALSE;
++
++                      try_return(RC = STATUS_PENDING);
++              }
++
++              // Check whether this write operation is targeted
++              // to a directory object...
++
++              if (PtrFCB->FCBFlags & EXT2_FCB_DIRECTORY) 
++              {
++                      //
++                      //      Is this a write a result of 
++                      //      cached directory manipulation operatio
++                      //      by the FSD itself?
++                      //
++                      if( PagingIo )
++                      {
++                              //      Yep! Allow it to proceed...
++                      }
++                      else
++                      {
++                              //      Nope... User initiated directory writes are not allowed!
++                              //      Fail this request...
++                              RC = STATUS_INVALID_DEVICE_REQUEST;
++                              try_return(RC);
++                      }
++              }
++
++              PtrReqdFCB = &(PtrFCB->NTRequiredFCB);
++
++              //
++              //      Synchronizing with other reads and writes...
++              //      Acquire the appropriate FCB resource exclusively
++              //
++              if (PagingIo) 
++              {
++                      // Try to acquire the FCB PagingIoResource exclusively
++                      DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** Attempting to acquire FCBpaging Exclusively [Write]", 0);
++
++                      if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->PagingIoResource), CanWait)) 
++                      {
++                              DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** FCBpaging Acquisition FAILED [Write]", 0);
++                              CompleteIrp = FALSE;
++                              PostRequest = TRUE;
++                              try_return(RC = STATUS_PENDING);
++                      }
++                      // Remember the resource that was acquired
++                      DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** FCBpaging Acquired [Write]", 0);
++                      PtrResourceAcquired = &(PtrReqdFCB->PagingIoResource);
++              } 
++              else 
++              {
++                      // Try to acquire the FCB MainResource exclusively
++                      DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** Attempting to acquire FCB Exclusively [Write]", 0);
++                      if (!ExAcquireResourceExclusiveLite(&(PtrReqdFCB->MainResource), CanWait)) 
++                      {
++                              DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** FCB Acquisition FAILED [Write]", 0);
++                              CompleteIrp = FALSE;
++                              PostRequest = TRUE;
++                              try_return(RC = STATUS_PENDING);
++                      }
++                      // Remember the resource that was acquired
++                      DebugTrace(DEBUG_TRACE_RESOURCE_ACQUIRE,   "*** FCB Acquired [Write]", 0);
++                      PtrResourceAcquired = &(PtrReqdFCB->MainResource);
++              }
++
++              // Validate start offset and length supplied.
++              // Here is a special check that determines whether the caller wishes to
++              // begin the write at current end-of-file (whatever the value of that
++              // offset might be)
++              if ((ByteOffset.LowPart == FILE_WRITE_TO_END_OF_FILE) && (ByteOffset.HighPart == 0xFFFFFFFF)) 
++              {
++                      WritingAtEndOfFile = TRUE;
++                      ByteOffset.QuadPart = PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart;
++              }
++
++              //
++              //      If this is a Non Cached io and if caching has been initiated,
++              //      Flush and purge the cache 
++              //
++              if (NonBufferedIo && !PagingIo && (PtrReqdFCB->SectionObject.DataSectionObject != NULL)) 
++              {
++                      // Flush and then attempt to purge the cache
++                      CcFlushCache(&(PtrReqdFCB->SectionObject), &ByteOffset, WriteLength, &(PtrIrp->IoStatus));
++                      // If the flush failed, return error to the caller
++                      if (!NT_SUCCESS(RC = PtrIrp->IoStatus.Status)) 
++                      {
++                              try_return(RC);
++                      }
++
++                      // Attempt the purge and ignore the return code
++                      CcPurgeCacheSection( &(PtrReqdFCB->SectionObject), (WritingAtEndOfFile ? &(PtrReqdFCB->CommonFCBHeader.FileSize) : &(ByteOffset)),
++                                                                              WriteLength, FALSE);
++                      // We are finished with our flushing and purging
++              }
++
++              if (!PagingIo) 
++              {
++                      //      Insert code to perform the check here ...
++                      //      
++                      //      if (!Ext2CheckForByteLock(PtrFCB, PtrCCB, PtrIrp,
++                      //              PtrCurrentIoStackLocation)) 
++                      //      {
++                      //              try_return(RC = STATUS_FILE_LOCK_CONFLICT);
++                      //      }
++              }
++
++              //      Read in the File inode...
++              Ext2InitializeFCBInodeInfo( PtrFCB );
++
++              if (!PagingIo) 
++              {
++                      LARGE_INTEGER  CurrentTime;
++                      KeQuerySystemTime( &CurrentTime );
++                      PtrFCB->LastAccessTime.QuadPart = CurrentTime.QuadPart;
++                      PtrFCB->LastWriteTime.QuadPart = CurrentTime.QuadPart;
++              }
++
++              {
++                      //
++                      // Validate start offset and length supplied.
++                      //
++                      ULONG           LogicalBlockSize = 0;
++                      LONGLONG        NoOfNewBlocksRequired = 0;
++                      LONGLONG        NoOfBytesRequired = 0;
++                      LONGLONG        i;
++                      BOOLEAN         ZeroOut = FALSE;
++                      LARGE_INTEGER   StartOffsetForZeroing;
++                      LARGE_INTEGER   EndOffsetForZeroing;
++
++
++                      LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++              
++                      if ( ByteOffset.QuadPart + WriteLength > PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart )
++                      {
++                              if( PagingIo )
++                              {
++                                      //
++                                      //      A paging request never modifies the file size...
++                                      //
++                                      if( ByteOffset.QuadPart 
++                                              >= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart )
++                                      {
++                                              //      Page request for writing outside the file...
++                                              //      No op this IRP by completing it...
++                                              //
++                                              try_return(RC);
++                                      }
++                                      if( ByteOffset.QuadPart + WriteLength
++                                              > PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart )
++                                      {
++                                              //      Page request for writing outside the file alocation size...
++                                              //      Truncate the write size so that it is within the allocation limit...
++                                              //
++                                              WriteLength = (ULONG) (PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart - ByteOffset.QuadPart);
++                                      }
++                              }
++                              else
++                              {
++                                      
++                                      //      Starting offset is > file size
++                                      //      Allocate new blocks?
++                                      NoOfBytesRequired = ByteOffset.QuadPart + WriteLength 
++                                                      - PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart;
++
++                                      if( NoOfBytesRequired )
++                                      {
++                                              NoOfNewBlocksRequired = Ext2Align64( NoOfBytesRequired, LogicalBlockSize ) 
++                                                      / LogicalBlockSize;
++                                              for( i = 0; i < NoOfNewBlocksRequired ; i++ )
++                                              {
++                                                      Ext2AddBlockToFile( PtrIrpContext, PtrVCB, PtrFCB, PtrFileObject, FALSE );
++                                              }
++                              
++                                              ZeroOut = TRUE;
++
++                                              if( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart < ByteOffset.QuadPart )
++                                              {
++                                                      //         Curr EOF --> |                                    | <--New EOF
++                                                      //      -----------------------------------------------
++                                                      //  |                           |                |///////////|            |
++                                                      //      | File Contents |  Free  |// Write //|  Free  | <- End of Allocation   
++                                                      //      |                               |                |///////////|        |
++                                                      //      -----------------------------------------------
++                                                      //                      |                                    | 
++
++                                                      //      Write is beyond the current end of file...
++                                                      //      This will create a hole...
++                                                      //      Will have to zero this out...
++
++                                                      //      Start offset is the Current File size
++                                                      StartOffsetForZeroing = PtrReqdFCB->CommonFCBHeader.FileSize;
++                                                      //      End offset is the point at which this write is going to start
++                                                      EndOffsetForZeroing = ByteOffset;
++                                              }
++                                              else
++                                              {
++                                                      //                         Curr EOF --> |               | <--New EOF
++                                                      //      ------------------------------------------
++                                                      //      |                               |///////////////|                |
++                                                      //      | File Contents |//// Write ////|  Free  | <- End of Allocation
++                                                      //      |                               |///////////////|                |
++                                                      //      ------------------------------------------
++                                                      //                              |       | 
++
++                                                      //      Just zero out the end of the file 
++                                                      //      not covered by the file size
++
++                                                      //      Start offset is the New File size
++                                                      StartOffsetForZeroing.QuadPart = 
++                                                              ByteOffset.QuadPart + WriteLength;
++                                                      //      End offset is the New Allocation size
++                                                      EndOffsetForZeroing.QuadPart = PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart;
++                                              }
++                                      }
++
++                                      PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart = 
++                                              ByteOffset.QuadPart + WriteLength;                              
++                                      
++                                      ASSERT( PtrReqdFCB->CommonFCBHeader.FileSize.QuadPart <= PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart );
++
++                                      Ext2UpdateFileSize( PtrIrpContext, PtrFileObject, PtrFCB );
++
++                                      try
++                                      {
++                                              //
++                                              //      Zero the blocks out...
++                                              //      This routine can be used even if caching has not been initiated...
++                                              //
++                                              if( ZeroOut == TRUE && StartOffsetForZeroing.QuadPart != EndOffsetForZeroing.QuadPart )
++                                              {
++                                                      CcZeroData( PtrFileObject, 
++                                                              &StartOffsetForZeroing,
++                                                              &EndOffsetForZeroing, 
++                                                              FALSE );
++                                                      
++                                                      if( EndOffsetForZeroing.QuadPart != PtrReqdFCB->CommonFCBHeader.AllocationSize.QuadPart )
++                                                      {
++                                                              //      Also zero out the file tip...
++                                                              CcZeroData( PtrFileObject, 
++                                                                      &PtrReqdFCB->CommonFCBHeader.FileSize,
++                                                                      &PtrReqdFCB->CommonFCBHeader.AllocationSize, 
++                                                                      FALSE );
++                                                      }
++                                              }
++                                      }
++                                      finally
++                                      {
++                                              //      Swallow an exceptions that are raised...
++                                      }
++                              }
++                      }
++              }
++
++              //
++              //      Branch here for cached vs non-cached I/O
++              //
++              if (!NonBufferedIo) 
++              {
++
++                      //      The caller wishes to perform cached I/O. 
++                      //      Initiate caching if it hasn't been done already...
++                      if (PtrFileObject->PrivateCacheMap == NULL) 
++                      {
++                              CcInitializeCacheMap(PtrFileObject, (PCC_FILE_SIZES)(&(PtrReqdFCB->CommonFCBHeader.AllocationSize)),
++                                      FALSE,          // We will not utilize pin access for this file
++                                      &(Ext2GlobalData.CacheMgrCallBacks), // callbacks
++                                      PtrCCB);                // The context used in callbacks
++                      }
++
++                      // Check and see if this request requires a MDL returned to the caller
++                      if (PtrIoStackLocation->MinorFunction & IRP_MN_MDL) 
++                      {
++                              // Caller does want a MDL returned. Note that this mode
++                              // implies that the caller is prepared to block
++                              CcPrepareMdlWrite(PtrFileObject, &ByteOffset, WriteLength, &(PtrIrp->MdlAddress), &(PtrIrp->IoStatus));
++                              NumberBytesWritten = PtrIrp->IoStatus.Information;
++                              RC = PtrIrp->IoStatus.Status;
++
++                              try_return(RC);
++                      }
++
++                      // This is a regular run-of-the-mill cached I/O request. Let the
++                      // Cache Manager worry about it!
++
++                      // First though, we need a buffer pointer (address) that is valid
++                      PtrSystemBuffer = Ext2GetCallersBuffer(PtrIrp);
++                      ASSERT(PtrSystemBuffer);
++                      if ( !CcCopyWrite(PtrFileObject, &(ByteOffset), WriteLength, CanWait, PtrSystemBuffer)) 
++                      {
++                              // The caller was not prepared to block and data is not immediately
++                              // available in the system cache
++                              CompleteIrp = FALSE;
++                              PostRequest = TRUE;
++                              // Mark Irp Pending ...
++                              try_return(RC = STATUS_PENDING);
++                      } 
++                      else 
++                      {
++                              // We have the data
++                              PtrIrp->IoStatus.Status = RC;
++                              PtrIrp->IoStatus.Information = NumberBytesWritten = WriteLength;
++                      }
++              }
++              else // NonBuffered or Paged IO
++              {
++
++                      ULONG           Start = 0;
++                      ULONG           End = 0;
++                      ULONG           LogicalBlockIndex = 0;
++                      ULONG           BytesRemaining = 0;
++                      ULONG           BytesWrittenSoFar = 0;
++                      ULONG           LeftOver = 0;
++                      ULONG           LogicalBlockSize = 0;
++                      ULONG           PhysicalBlockSize = 0;
++                      ULONG           Index = 0;
++
++                      LONGLONG        SingleIndirectBlockSize = 0;
++                      LONGLONG        DoubleIndirectBlockSize = 0;
++                      LONGLONG        TripleIndirectBlockSize = 0;
++                      LONGLONG        DirectBlockSize = 0;
++
++                      LONGLONG        NoOfDirectBlocks ;
++                      LONGLONG        NoOfSingleIndirectBlocks ;
++                      LONGLONG        NoOfDoubleIndirectBlocks ;
++                      LONGLONG        NoOfTripleIndirectBlocks ;
++
++                      ULONG * PtrPinnedSIndirectBlock = NULL;
++                      ULONG * PtrPinnedDIndirectBlock = NULL;
++                      ULONG * PtrPinnedTIndirectBlock = NULL;
++
++                      //      Used when reading a Triple Indirect Block...
++                      LONGLONG                FirstCachedDIBlockOffset = 0;
++
++                      //      Used when reading a Double Indirect Block...
++                      LONGLONG                FirstCachedSIBlockOffset = 0;
++
++                      DebugTrace(DEBUG_TRACE_WRITE_DETAILS,  "[File Write] Paging IO or NonBufferedIo ", 0);
++
++                      //      Calculating where the write should start from...
++                      LogicalBlockSize = EXT2_MIN_BLOCK_SIZE << PtrVCB->LogBlockSize;
++                      PhysicalBlockSize = PtrVCB->TargetDeviceObject->SectorSize;
++
++                      NoOfDirectBlocks =  EXT2_NDIR_BLOCKS ;
++                      NoOfSingleIndirectBlocks = LogicalBlockSize / sizeof( ULONG );
++                      NoOfDoubleIndirectBlocks = NoOfSingleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
++                      NoOfTripleIndirectBlocks = NoOfDoubleIndirectBlocks * LogicalBlockSize / sizeof( ULONG );
++
++                      DirectBlockSize =  LogicalBlockSize * NoOfDirectBlocks;
++                      SingleIndirectBlockSize = LogicalBlockSize * NoOfSingleIndirectBlocks;
++                      DoubleIndirectBlockSize = LogicalBlockSize * NoOfDoubleIndirectBlocks ;
++                      TripleIndirectBlockSize = LogicalBlockSize * NoOfTripleIndirectBlocks;
++
++                      LogicalBlockIndex = (ULONG)( ByteOffset.QuadPart / LogicalBlockSize);
++
++                      if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
++                      {
++                              //
++                              //      Handle Triple indirect blocks?
++                              //      A Pop up will do for now...
++                              //
++                              UNICODE_STRING ErrorMessage;
++                              Ext2CopyWideCharToUnicodeString( &ErrorMessage, L"Triple indirect blocks not supported as yet. - Ext2.sys" );
++                              DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "@@@@@@@@  Triple indirect blocks need to be written to! \n@@@@@@@@  This is not supported as yet!", 0);
++                              /* REACTOS FIXME */
++                              IoRaiseInformationalHardError(
++                                              /* IO_ERR_DRIVER_ERROR */(NTSTATUS)0xC0040004L,
++                                              &ErrorMessage,
++                                              KeGetCurrentThread( ) );
++
++                              Ext2DeallocateUnicodeString( &ErrorMessage );
++                              RC = STATUS_INSUFFICIENT_RESOURCES;
++                              try_return ( RC );
++                      }
++                      
++                      if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize &&
++                              ( ByteOffset.QuadPart < DirectBlockSize + SingleIndirectBlockSize ) )
++                      {
++                              LARGE_INTEGER VolumeByteOffset;
++
++                              //
++                              //      Indirect Blocks required...
++                              //      Read in the single indirect blocks...
++                              //
++                              DebugTrace(DEBUG_TRACE_WRITE_DETAILS,   "Reading in some Indirect Blocks", 0);
++
++                              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_NDIR_BLOCKS ] * LogicalBlockSize;
++
++                              //
++                              //      Asking the cache manager to oblige by pinning the single indirect block...
++                              //
++                              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                                 &VolumeByteOffset,
++                                 LogicalBlockSize,
++                                 CanWait,
++                                 &PtrPinnedSIndirectBCB,
++                                 (PVOID*)&PtrPinnedSIndirectBlock )) 
++                              {
++                                      CompleteIrp = FALSE;
++                                      PostRequest = TRUE;
++                              
++                                      // Mark Irp Pending ...
++                                      IoMarkIrpPending( PtrIrp );
++                                      RC = STATUS_PENDING;
++                                      try_return(RC);
++                                      DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data", 0);
++                              }
++                      }
++                      if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize &&
++                              ( ByteOffset.QuadPart ) < DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
++                      {
++                              //
++                              //      Double Indirect Blocks required...
++                              //      Read in the double indirect blocks...
++                              //
++
++                              LONGLONG                StartIndirectBlock;
++                              LONGLONG                EndIndirectBlock;
++
++                              
++
++                              LARGE_INTEGER VolumeByteOffset;
++
++                              DebugTrace(DEBUG_TRACE_MISC,   "Reading in some Double Indirect Blocks", 0);
++
++                              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
++
++                              //
++                              //      Asking the cache manager to oblige by pinning the double indirect block...
++                              //
++                              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                   &VolumeByteOffset,
++                   LogicalBlockSize,
++                   CanWait,
++                   &PtrPinnedDIndirectBCB,
++                   (PVOID*)&PtrPinnedDIndirectBlock )) 
++                              {
++                                      CompleteIrp = FALSE;
++                                      PostRequest = TRUE;
++                              
++                                      // Mark Irp Pending ...
++                                      IoMarkIrpPending( PtrIrp );
++                                      RC = STATUS_PENDING;
++                                      try_return(RC);
++                                      DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
++                              }
++
++                              //      So far so good...
++                              //      Now determine the single indirect blocks that will have to be read in...
++                              if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize )
++                              {
++                                      //      Request doesnot require any single indirect or direct blocks
++                                      StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize);
++                                      StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
++                                      StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
++                              }
++                              else
++                              {
++                                      StartIndirectBlock = 0;
++                              }
++
++                              FirstCachedSIBlockOffset = (NoOfSingleIndirectBlocks*(StartIndirectBlock+1)) + NoOfDirectBlocks;
++
++                              if( ByteOffset.QuadPart + WriteLength >= 
++                                      DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize)
++                              {
++                                      EndIndirectBlock  = DoubleIndirectBlockSize;
++                              }
++                              else
++                              {
++                                      EndIndirectBlock = ByteOffset.QuadPart + WriteLength - 
++                                                                         (DirectBlockSize + SingleIndirectBlockSize);
++                              }
++                              EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ;
++                              EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks;
++      
++                              DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock);
++
++                              PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
++                              {
++                                      ULONG   i;
++
++                                      for( i = 0; i < DIArrayCount; i++ )
++                                      {
++                                              VolumeByteOffset.QuadPart =  PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize;
++                                              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                                                 &VolumeByteOffset,
++                                                 LogicalBlockSize,
++                                                 CanWait,
++                                                 &PtrDIArray[i].PtrBCB,
++                                                 (PVOID*)&PtrDIArray[i].PtrSIBlocks)) 
++                                              {
++                                                      CompleteIrp = FALSE;
++                                                      PostRequest = TRUE;
++                                                      IoMarkIrpPending( PtrIrp );
++                                                      DIArrayCount = i;
++                                                      try_return(RC = STATUS_PENDING);
++
++                                                      DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
++                                              }
++                                      }
++                              }
++                      }
++
++/*                    {
++                              //
++                              //      Double Indirect Blocks required...
++                              //      Read in the double indirect blocks...
++                              //
++
++                              LONGLONG                StartIndirectBlock;
++                              LONGLONG                EndIndirectBlock;
++
++                              LARGE_INTEGER VolumeByteOffset;
++
++                              DebugTrace(DEBUG_TRACE_MISC,   "Reading in some Double Indirect Blocks", 0);
++
++                              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_DIND_BLOCK ] * LogicalBlockSize;
++
++                              //
++                              //      Asking the cache manager to oblige by pinning the double indirect block...
++                              //
++                              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                   &VolumeByteOffset,
++                   LogicalBlockSize,
++                   CanWait,
++                   &PtrPinnedDIndirectBCB,
++                   (PVOID*)&PtrPinnedDIndirectBlock )) 
++                              {
++                                      CompleteIrp = FALSE;
++                                      PostRequest = TRUE;
++                              
++                                      // Mark Irp Pending ...
++                                      IoMarkIrpPending( PtrIrp );
++                                      RC = STATUS_PENDING;
++                                      try_return(RC);
++                                      DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
++                              }
++
++                              //      So far so good...
++                              //      Now determine the single indirect blocks that will have to be read in...
++                              if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize )
++                              {
++                                      //      Request doesnot require any single indirect or direct blocks
++                                      StartIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize);
++                                      StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
++                                      StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
++                              }
++                              else
++                              {
++                                      StartIndirectBlock = 0;
++                              }
++
++                              if( ByteOffset.QuadPart + WriteLength >= 
++                                      DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize)
++                              {
++                                      EndIndirectBlock  = DoubleIndirectBlockSize;
++                              }
++                              else
++                              {
++                                      EndIndirectBlock = ByteOffset.QuadPart + WriteLength - 
++                                                                         (DirectBlockSize + SingleIndirectBlockSize);
++                                      if( EndIndirectBlock % LogicalBlockSize )
++                                      {
++                                              EndIndirectBlock += LogicalBlockSize;
++                                      }
++                                      EndIndirectBlock = EndIndirectBlock / LogicalBlockSize;
++                                      if( EndIndirectBlock % NoOfSingleIndirectBlocks)
++                                      {
++                                              EndIndirectBlock += NoOfSingleIndirectBlocks;
++                                      }
++                                      EndIndirectBlock = EndIndirectBlock / NoOfSingleIndirectBlocks;
++                              }
++                              DIArrayCount = (ULONG)(EndIndirectBlock - StartIndirectBlock);
++                              PtrDIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( DIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
++                              {
++                                      ULONG   i;
++
++                                      for( i = 0; i < DIArrayCount; i++ )
++                                      {
++                                              VolumeByteOffset.QuadPart =  PtrPinnedDIndirectBlock[StartIndirectBlock+i] * LogicalBlockSize;
++                                              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                                                 &VolumeByteOffset,
++                                                 LogicalBlockSize,
++                                                 CanWait,
++                                                 &PtrDIArray[i].PtrBCB,
++                                                 (PVOID*)&PtrDIArray[i].PtrSIBlocks)) 
++                                              {
++                                                      CompleteIrp = FALSE;
++                                                      PostRequest = TRUE;
++                                                      IoMarkIrpPending( PtrIrp );
++                                                      DIArrayCount = i;
++                                                      try_return(RC = STATUS_PENDING);
++
++                                                      DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
++                                              }
++                                      }
++                              }
++                      }
++*/
++                      if( ( ByteOffset.QuadPart + WriteLength ) > DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
++                      {
++                              //
++                              //      Triple Indirect Blocks required...
++                              //      Read in the triple indirect blocks...
++                              //
++                              LONGLONG                StartTIndirectBlock;
++                              LONGLONG                EndTIndirectBlock;
++
++                              LONGLONG                StartDIndirectBlock;
++                              LONGLONG                EndDIndirectBlock;
++                              LONGLONG                StartIndirectBlock;
++                              LONGLONG                EndIndirectBlock;
++
++                              LONGLONG                ByteOffsetTillHere = 0;
++
++                              PBCB    TempDIBCB;
++                              LONG*   TempDIBuffer;
++
++                              ULONG TIArrayIndex = 0;
++
++                              LARGE_INTEGER VolumeByteOffset;
++
++                              DebugTrace(DEBUG_TRACE_MISC,   "Reading in some Triple Indirect Blocks", 0);
++
++                              VolumeByteOffset.QuadPart = PtrFCB->IBlock[ EXT2_TIND_BLOCK ] * LogicalBlockSize;
++
++                              DebugTrace(DEBUG_TRACE_TRIPLE,   "ByteOffset = 0x%I64X", ByteOffset );
++                              DebugTrace(DEBUG_TRACE_TRIPLE,   "WriteLength = 0x%lX", WriteLength );
++                              DebugTrace(DEBUG_TRACE_TRIPLE,   "EXT2_TIND_BLOCK = 0x%lX", PtrFCB->IBlock[ EXT2_TIND_BLOCK ] );
++                              //
++                              //      Asking the cache manager to oblige by pinning the triple indirect block...
++                              //
++                              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                   &VolumeByteOffset,
++                   LogicalBlockSize,
++                   CanWait,
++                   &PtrPinnedTIndirectBCB,
++                   (PVOID*)&PtrPinnedTIndirectBlock )) 
++                              {
++                                      CompleteIrp = FALSE;
++                                      PostRequest = TRUE;
++                              
++                                      // Mark Irp Pending ...
++                                      IoMarkIrpPending( PtrIrp );
++                                      RC = STATUS_PENDING;
++                                      try_return(RC);
++                                      DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
++                              }
++
++                              //      Determine the no of BCBs that need to be saved...
++                              if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
++                              {
++                                      StartTIndirectBlock = ByteOffset.QuadPart;
++                              }
++                              else
++                              {
++                                      StartTIndirectBlock = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize;
++                              }
++                              EndTIndirectBlock = ByteOffset.QuadPart + WriteLength;
++                              TIArrayCount = (ULONG)( (EndTIndirectBlock - StartTIndirectBlock) / SingleIndirectBlockSize ) + 2;
++
++                              
++                              PtrTIArray = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( TIArrayCount * sizeof( EXT2_SIBLOCKS ) ) );
++
++                              //      Now determine the double indirect blocks that will have to be read in...
++                              if( ByteOffset.QuadPart >= DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize )
++                              {
++                                      //      Request doesnot require any single indirect or direct blocks
++                                      StartDIndirectBlock = ByteOffset.QuadPart - (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize);
++                                      StartDIndirectBlock = StartDIndirectBlock / LogicalBlockSize;
++                                      StartDIndirectBlock = StartDIndirectBlock / NoOfDoubleIndirectBlocks;
++
++                                      ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + (DoubleIndirectBlockSize*(StartDIndirectBlock+1)) ;
++                                      //FirstCachedDIBlockOffset = ByteOffset.QuadPart / LogicalBlockSize;
++                                      FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize;
++                              }
++                              else
++                              {
++                                      ByteOffsetTillHere = DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize;
++                                      FirstCachedDIBlockOffset = ByteOffsetTillHere / LogicalBlockSize;
++                                      StartDIndirectBlock = 0;
++                              }
++
++                              DebugTrace(DEBUG_TRACE_TRIPLE,   "ByteOffsetTillHere = 0x%lX", ByteOffsetTillHere );
++
++                              EndDIndirectBlock  = ByteOffset.QuadPart + WriteLength - 
++                                      (DirectBlockSize + SingleIndirectBlockSize + DoubleIndirectBlockSize);
++                              EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, LogicalBlockSize ) / LogicalBlockSize ;
++                              EndDIndirectBlock = Ext2Align64( EndDIndirectBlock, NoOfDoubleIndirectBlocks ) / NoOfDoubleIndirectBlocks;
++
++                              {
++                                      //      Reading in the necessary double indirect bocks...
++                                      ULONG   i;
++                                      LONGLONG Count = EndDIndirectBlock-StartDIndirectBlock;
++
++                                      for( i = 0; i < Count; i++, ByteOffsetTillHere += DoubleIndirectBlockSize)
++                                      {
++                                              VolumeByteOffset.QuadPart =  PtrPinnedTIndirectBlock[StartDIndirectBlock+i] * LogicalBlockSize;
++                                              
++                                              DebugTrace(DEBUG_TRACE_TRIPLE,   "Double VolOffset = 0x%I64X", VolumeByteOffset );
++
++                                              if( !CcMapData( PtrVCB->PtrStreamFileObject,
++                                                 &VolumeByteOffset,
++                                                 LogicalBlockSize,
++                                                 CanWait,
++                                                 &TempDIBCB,
++                                                 (PVOID*)&TempDIBuffer) )
++                                              {
++                                                      CompleteIrp = FALSE;
++                                                      PostRequest = TRUE;
++                                                      IoMarkIrpPending( PtrIrp );
++                                                      try_return(RC = STATUS_PENDING);
++                                                      DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
++                                              }
++                                      
++                                              if( ByteOffset.QuadPart > ByteOffsetTillHere)
++                                              {
++                                                      StartIndirectBlock = ByteOffset.QuadPart - (ByteOffsetTillHere);
++                                                      StartIndirectBlock = StartIndirectBlock / LogicalBlockSize;
++                                                      StartIndirectBlock = StartIndirectBlock / NoOfSingleIndirectBlocks;
++
++                                                      if( TIArrayIndex == 0 )
++                                                      {
++                                                              FirstCachedDIBlockOffset += StartIndirectBlock * NoOfSingleIndirectBlocks;
++                                                      }
++                                              }
++                                              else
++                                              {
++                                                      StartIndirectBlock = 0;
++                                              }
++
++                                              if( ByteOffset.QuadPart + WriteLength >= ByteOffsetTillHere + DoubleIndirectBlockSize)
++                                              {
++                                                      EndIndirectBlock  = DoubleIndirectBlockSize;
++                                              }
++                                              else
++                                              {
++                                                      EndIndirectBlock = ByteOffset.QuadPart + WriteLength - ByteOffsetTillHere;
++                                              }
++                                              EndIndirectBlock = Ext2Align64( EndIndirectBlock, LogicalBlockSize )/LogicalBlockSize ;
++                                              EndIndirectBlock = Ext2Align64( EndIndirectBlock, NoOfSingleIndirectBlocks )/NoOfSingleIndirectBlocks;
++                                      
++                                              {
++                                                      ULONG   i;
++                                                              
++                                                      for( i = 0; i < (EndIndirectBlock - StartIndirectBlock); i++ )
++                                                      {
++                                                              VolumeByteOffset.QuadPart =  TempDIBuffer[StartIndirectBlock+i] * LogicalBlockSize;
++                                                              DebugTrace(DEBUG_TRACE_TRIPLE,   "Single VolOffset = 0x%I64X", VolumeByteOffset );
++
++                                                              if (!CcMapData( PtrVCB->PtrStreamFileObject,
++                                                                 &VolumeByteOffset,
++                                                                 LogicalBlockSize,
++                                                                 CanWait,
++                                                                 &PtrTIArray[ TIArrayIndex ].PtrBCB,
++                                                                 (PVOID*)&PtrTIArray[ TIArrayIndex ].PtrSIBlocks)) 
++                                                              {
++                                                                      CompleteIrp = FALSE;
++                                                                      PostRequest = TRUE;
++                                                                      IoMarkIrpPending( PtrIrp );
++                                                                      DIArrayCount = i;
++                                                                      try_return(RC = STATUS_PENDING);
++
++                                                                      DebugTrace(DEBUG_TRACE_ASYNC,   "Cache read failiure while reading in volume meta data - Retrying", 0);
++                                                              }
++                                                              TIArrayIndex++;
++                                                      }
++                                              }
++                                              CcUnpinData( TempDIBCB );
++                                              TempDIBCB = NULL;
++                                              TempDIBuffer = NULL;
++                                      }
++                              }
++                              TIArrayCount = TIArrayIndex;
++                              
++                              DebugTrace(DEBUG_TRACE_TRIPLE,   "TIArrayCount = %ld", TIArrayCount );
++                              DebugTrace(DEBUG_TRACE_TRIPLE,   "FirstCachedDIBlockOffset = 0x%lX", FirstCachedDIBlockOffset );
++                      }
++
++                      //      
++                      //      Allocating memory for IO Runs
++                      //
++                      Index = ( (WriteLength - 2) / LogicalBlockSize + 2 );
++                      PtrIoRuns = Ext2AllocatePool(NonPagedPool, Ext2QuadAlign( Index * sizeof( EXT2_IO_RUN) )  );
++                      
++
++                      Start = (ULONG) ( ByteOffset.QuadPart - (LogicalBlockSize * LogicalBlockIndex) );
++                      BytesRemaining = (ULONG)( LogicalBlockSize * (LogicalBlockIndex +1) - ByteOffset.QuadPart );
++
++                      if( WriteLength > BytesRemaining )
++                              End = Start + BytesRemaining;
++                      else
++                              End = Start + WriteLength;
++                      BytesWrittenSoFar = 0;
++
++                      Index = 0;
++                      DebugTrace(DEBUG_TRACE_WRITE_DETAILS, "\nDetermining the write IRPs that have to be passed down...", 0);
++                      
++                      while( 1 )
++                      {
++                              BytesWrittenSoFar += (End-Start);
++                              if( LogicalBlockIndex < EXT2_NDIR_BLOCKS )
++                              {
++                                      //      Direct Block
++                                      PtrIoRuns[ Index ].LogicalBlock = PtrFCB->IBlock[ LogicalBlockIndex ];
++                              }
++                              else if( LogicalBlockIndex < (NoOfSingleIndirectBlocks + NoOfDirectBlocks) )
++                              {
++                                      //      Single Indirect Block
++                                      PtrIoRuns[ Index ].LogicalBlock = PtrPinnedSIndirectBlock[ LogicalBlockIndex - EXT2_NDIR_BLOCKS ];
++                              }
++                              else if( LogicalBlockIndex < (NoOfDoubleIndirectBlocks + NoOfSingleIndirectBlocks + NoOfDirectBlocks)  )
++                              {
++                                      LONGLONG BlockNo;
++                                      LONGLONG IBlockIndex;
++                                      LONGLONG BlockIndex;
++
++                                      BlockNo         = LogicalBlockIndex - FirstCachedSIBlockOffset;
++                                      IBlockIndex     = BlockNo / NoOfSingleIndirectBlocks;
++                                      BlockIndex      = BlockNo % NoOfSingleIndirectBlocks;
++
++                                      //      Double Indirect Block
++                                      PtrIoRuns[ Index ].LogicalBlock = 
++                                              PtrDIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];
++                              }
++                              else
++                              {
++                                      //      Triple Indirect Block
++                                      LONGLONG BlockNo;
++                                      LONGLONG IBlockIndex;
++                                      LONGLONG BlockIndex;
++                                      BlockNo         = LogicalBlockIndex - FirstCachedDIBlockOffset;
++                                      IBlockIndex     = BlockNo / NoOfSingleIndirectBlocks;
++                                      BlockIndex      = BlockNo % NoOfSingleIndirectBlocks;
++
++                                      DbgPrint( "\nBlock No : 0x%I64X   IBlockIndex = 0x%I64X   BlockIndex = 0x%I64X", BlockNo, IBlockIndex, BlockIndex);
++
++                                      if( IBlockIndex >= TIArrayCount )
++                                      {
++                                              Ext2BreakPoint();
++                                      }
++                                      if( BlockIndex >= LogicalBlockSize )
++                                      {
++                                              Ext2BreakPoint();
++                                      }
++
++                                      PtrIoRuns[ Index ].LogicalBlock = PtrTIArray[ IBlockIndex ].PtrSIBlocks[ BlockIndex ];;
++                                      DbgPrint( "LogicalBlock = 0x%lX", PtrIoRuns[ Index ].LogicalBlock );
++                              }
++
++                              if( PtrIoRuns[ Index ].LogicalBlock == 0 )
++                              {
++                                      //
++                                      //      Something is wrong...
++                                      //
++                                      Ext2BreakPoint();
++                                      break;
++
++                              }
++                              PtrIoRuns[ Index ].StartOffset = Start;
++                              PtrIoRuns[ Index ].EndOffset = End;
++                              PtrIoRuns[ Index ].PtrAssociatedIrp = NULL;
++
++                              DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "  Index = (%ld)", LogicalBlockIndex );
++                              DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "  Logical Block = (0x%lX)", PtrFCB->IBlock[ LogicalBlockIndex ] );
++                              DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "  Start = (0x%lX)", Start );
++                              DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "  End = (0x%lX)  ", End );
++                              DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "  Bytes written (0x%lX)", BytesWrittenSoFar );
++                               
++                              
++
++                              if( BytesWrittenSoFar >= WriteLength )
++                                      break;
++                              LogicalBlockIndex++;
++                              Start = 0;
++                              LeftOver = WriteLength - BytesWrittenSoFar;
++                              if( LeftOver > LogicalBlockSize )
++                                      End = LogicalBlockSize;
++                              else
++                                      End = LeftOver;
++                              //      Loop over to make the write request...
++                              Index++;
++                      }
++                      
++                      //
++                      //      Unpin the Indirect Blocks
++                      //
++                      if( PtrPinnedSIndirectBCB )
++                      {
++                              CcUnpinData( PtrPinnedSIndirectBCB );
++                              PtrPinnedSIndirectBCB = NULL;
++                              PtrPinnedSIndirectBlock = NULL;
++                      }
++                      if( PtrPinnedDIndirectBCB )
++                      {
++                              CcUnpinData( PtrPinnedDIndirectBCB );
++                              PtrPinnedDIndirectBCB = NULL;
++                              PtrPinnedDIndirectBlock = NULL;
++                      }
++                      //
++                      //      Pass down Associated IRPs to the Target Device Driver...
++                      //
++                      DebugTrace( DEBUG_TRACE_WRITE_DETAILS, "Passing down the Write IRPs to the disk driver...", 0 );
++
++                      RC = Ext2PassDownMultiReadWriteIRP( PtrIoRuns, Index+1, WriteLength, PtrIrpContext, PtrFCB, SynchronousIo );
++                      
++                      //
++                      //      Irp will be completed automatically 
++                      //      when all the Associated IRPs are completed
++                      //
++                      if( RC == STATUS_SUCCESS || RC == STATUS_PENDING )
++                      {
++                              CompleteIrp = FALSE;    
++                      }
++                      try_return( RC );
++              }
++
++              try_exit:       NOTHING;
++
++      }
++      finally 
++      {
++              if ( PtrIoRuns )
++              {
++                      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Write]", PtrIoRuns );
++                      ExFreePool( PtrIoRuns );
++              }
++              if( PtrPinnedSIndirectBCB )
++              {
++                      CcUnpinData( PtrPinnedSIndirectBCB );
++                      PtrPinnedSIndirectBCB = NULL;
++              }
++              if( PtrPinnedDIndirectBCB )
++              {
++                      CcUnpinData( PtrPinnedDIndirectBCB );
++                      PtrPinnedDIndirectBCB = NULL;
++              }
++              if ( PtrDIArray )
++              {
++                      ULONG   i;
++                      for( i = 0; i < DIArrayCount; i++ )
++                      {
++                              CcUnpinData( PtrDIArray->PtrBCB );
++                      }
++                      DebugTrace( DEBUG_TRACE_FREE, "Freeing  = %lX [Read]", PtrDIArray );
++                      ExFreePool( PtrDIArray );
++                      PtrDIArray = NULL;
++              }                       
++              // Release resources ...
++              //
++              if (PtrResourceAcquired) 
++              {
++                      Ext2ReleaseResource(PtrResourceAcquired);
++                      
++                      DebugTrace(DEBUG_TRACE_RESOURCE_RELEASE,   "*** Resource Released [Write]", 0);
++                      DebugTraceState( "Resource     AC:0x%LX   SW:0x%LX   EX:0x%LX   [Write]", 
++                              PtrResourceAcquired->ActiveCount, 
++                              PtrResourceAcquired->NumberOfExclusiveWaiters, 
++                              PtrResourceAcquired->NumberOfSharedWaiters );
++                      
++                      if( PtrFileObject )
++                      {
++                              DebugTrace(DEBUG_TRACE_FILE_OBJ,  "###### File Pointer 0x%LX [Write]", PtrFileObject);
++                      }
++                      if( PtrVCB && PtrResourceAcquired == &(PtrVCB->VCBResource) )
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,  "*** VCB Released [Write]", 0);
++                      }
++                      else if( PtrVCB && PtrResourceAcquired == &(PtrVCB->PagingIoResource ) )
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,  "*** VCBPaging Released [Write]", 0);
++                      }
++                      else if( PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->PagingIoResource) )
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Paging Resource Released [Write]", 0);
++                      }
++                      else if(PtrReqdFCB && PtrResourceAcquired == &(PtrReqdFCB->MainResource) )
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,  "*** FCB Resource Released [Write]", 0);
++                      }
++                      else
++                      {
++                              DebugTrace(DEBUG_TRACE_MISC,  "*** Unknown Resource Released [Write]", 0);
++                      }
++
++                      PtrResourceAcquired = NULL;
++              }
++
++              if (PostRequest) 
++              {
++                      RC = Ext2PostRequest(PtrIrpContext, PtrIrp);
++              } 
++              else if ( CompleteIrp && !(RC == STATUS_PENDING)) 
++              {
++                      // For synchronous I/O, the FSD must maintain the current byte offset
++                      // Do not do this however, if I/O is marked as paging-io
++                      if (SynchronousIo && !PagingIo && NT_SUCCESS(RC)) 
++                      {
++                              PtrFileObject->CurrentByteOffset = RtlLargeIntegerAdd(ByteOffset,
++                              RtlConvertUlongToLargeInteger((unsigned long)NumberBytesWritten));
++                      }
++
++                      // If the write completed successfully and this was not a paging-io
++                      // operation, set a flag in the CCB that indicates that a write was
++                      // performed and that the file time should be updated at cleanup
++                      if (NT_SUCCESS(RC) && !PagingIo) 
++                      {
++                              Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_MODIFIED);
++                      }
++
++                      // If the file size was changed, set a flag in the FCB indicating that
++                      // this occurred.
++
++                      // If the request failed, and we had done some nasty stuff like
++                      // extending the file size (including informing the Cache Manager
++                      // about the new file size), and allocating on-disk space etc., undo
++                      // it at this time.
++
++                      // Can complete the IRP here if no exception was encountered
++                      if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_EXCEPTION)) 
++                      {
++                              PtrIrp->IoStatus.Status = RC;
++                              PtrIrp->IoStatus.Information = NumberBytesWritten;
++ 
++                              // complete the IRP
++                              IoCompleteRequest(PtrIrp, IO_DISK_INCREMENT);
++                      }
++
++                      // Free up the Irp Context
++                      Ext2ReleaseIrpContext(PtrIrpContext);
++
++              } // can we complete the IRP ?
++              else
++              {
++                      // Free up the Irp Context
++                      Ext2ReleaseIrpContext(PtrIrpContext);
++              }
++      } // end of "finally" processing
++      return(RC);
++}
++
++
++/*************************************************************************
++*
++* Function: Ext2DeferredWriteCallBack()
++*
++* Description:
++*     Invoked by the cache manager in the context of a worker thread.
++*     Typically, you can simply post the request at this point (just
++*     as you would have if the original request could not block) to
++*     perform the write in the context of a system worker thread.
++*
++* Expected Interrupt Level (for execution) :
++*
++*  IRQL_PASSIVE_LEVEL
++*
++* Return Value: None
++*
++*************************************************************************/
++void Ext2DeferredWriteCallBack (
++void                  *Context1,                      // Should be PtrIrpContext
++void                  *Context2 )                     // Should be PtrIrp
++{
++      // You should typically simply post the request to your internal
++      // queue of posted requests (just as you would if the original write
++      // could not be completed because the caller could not block).
++      // Once you post the request, return from this routine. The write
++      // will then be retried in the context of a system worker thread
++}
index 0000000,2fa7339..2fa7339
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,136 +1,136 @@@
+ /*
+  *  ReactOS kernel
+  *  Copyright (C) 2002,2003 ReactOS Team
+  *
+  *  This program is free software; you can redistribute it and/or modify
+  *  it under the terms of the GNU General Public License as published by
+  *  the Free Software Foundation; either version 2 of the License, or
+  *  (at your option) any later version.
+  *
+  *  This program is distributed in the hope that it will be useful,
+  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  *  GNU General Public License for more details.
+  *
+  *  You should have received a copy of the GNU General Public License
+  *  along with this program; if not, write to the Free Software
+  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+  */
+ /* $Id: fat.c 9284 2004-05-02 20:12:38Z hbirr $
+  *
+  * COPYRIGHT:        See COPYING in the top level directory
+  * PROJECT:          ReactOS kernel
+  * FILE:             drivers/fs/fs_rec/ext2.c (based on vfat.c)
+  * PURPOSE:          Filesystem recognizer driver
+  * PROGRAMMER:       Eric Kohl
+  */
+ /* INCLUDES *****************************************************************/
+ #include <ddk/ntddk.h>
+ #include <rosrtl/string.h>
+ #define NDEBUG
+ #include <debug.h>
+ #include "fs_rec.h"
+ /* FUNCTIONS ****************************************************************/
+ static NTSTATUS
+ FsRecIsExt2Volume(IN PDEVICE_OBJECT DeviceObject)
+ {
+    NTSTATUS Status;
+    PARTITION_INFORMATION PartitionInfo;
+    DISK_GEOMETRY DiskGeometry;
+    ULONG Size;
+    BOOL RecognizedFS = FALSE;
+    Size = sizeof(DISK_GEOMETRY);
+    Status = FsRecDeviceIoControl(DeviceObject,
+                                IOCTL_DISK_GET_DRIVE_GEOMETRY,
+                                NULL,
+                                0,
+                                &DiskGeometry,
+                                &Size);
+    if (!NT_SUCCESS(Status))
+    {
+       DPRINT("FsRecDeviceIoControl faild (%x)\n", Status);
+       return Status;
+    }
+    if (DiskGeometry.MediaType == FixedMedia || DiskGeometry.MediaType == RemovableMedia)
+    {
+       // We have found a hard disk
+       Size = sizeof(PARTITION_INFORMATION);
+       Status = FsRecDeviceIoControl(DeviceObject,
+                                   IOCTL_DISK_GET_PARTITION_INFO,
+                                   NULL,
+                                   0,
+                                   &PartitionInfo,
+                                   &Size);
+       if (!NT_SUCCESS(Status))
+       {
+          DPRINT("FsRecDeviceIoControl faild (%x)\n", Status);
+          return Status;
+       }
+       
+       if (PartitionInfo.PartitionType)
+       {
+           if (PartitionInfo.PartitionType == PARTITION_EXT2)
+          {
+             RecognizedFS = TRUE;
+          }
+       }
+    }
+    return RecognizedFS ? STATUS_SUCCESS : STATUS_UNRECOGNIZED_VOLUME;
+ }
+ NTSTATUS
+ FsRecExt2FsControl(IN PDEVICE_OBJECT DeviceObject,
+                  IN PIRP Irp)
+ {
+   PIO_STACK_LOCATION Stack;
+   UNICODE_STRING RegistryPath;
+   NTSTATUS Status;
+   Stack = IoGetCurrentIrpStackLocation(Irp);
+   switch (Stack->MinorFunction)
+     {
+       case IRP_MN_MOUNT_VOLUME:
+       DPRINT("FAT: IRP_MN_MOUNT_VOLUME\n");
+       Status = FsRecIsExt2Volume(Stack->Parameters.MountVolume.DeviceObject);
+       if (NT_SUCCESS(Status))
+         {
+           DPRINT("Identified FAT volume\n");
+           Status = STATUS_FS_DRIVER_REQUIRED;
+         }
+       break;
+       case IRP_MN_LOAD_FILE_SYSTEM:
+       DPRINT("FAT: IRP_MN_LOAD_FILE_SYSTEM\n");
+       RtlRosInitUnicodeStringFromLiteral(&RegistryPath,
+                            L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Ext2");
+       Status = ZwLoadDriver(&RegistryPath);
+       if (!NT_SUCCESS(Status))
+         {
+           DPRINT("ZwLoadDriver failed (Status %x)\n", Status);
+         }
+       else
+         {
+           IoUnregisterFileSystem(DeviceObject);
+         }
+       break;
+       default:
+       DPRINT("FAT: Unknown minor function %lx\n", Stack->MinorFunction);
+       Status = STATUS_INVALID_DEVICE_REQUEST;
+       break;
+     }
+   return(Status);
+ }
+ /* EOF */
index 0000000,58390b0..58390b0
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,26 +1,26 @@@
+ /*
+  * COPYRIGHT:   See COPYING in the top level directory
+  * PROJECT:     ReactOS EXT2 filesystem library
+  * FILE:        include/fslib/ext2lib.h
+  * PURPOSE:     Public definitions for ext2 filesystem library
+  */
+ #ifndef __EXT2LIB_H
+ #define __EXT2LIB_H
+ #include <fmifs.h>
+ NTSTATUS
+ Ext2Initialize (VOID);
+ NTSTATUS
+ Ext2Cleanup (VOID);
+ NTSTATUS
+ Ext2Format (PUNICODE_STRING DriveRoot,
+           ULONG MediaFlag,
+           PUNICODE_STRING Label,
+           BOOLEAN QuickFormat,
+           ULONG ClusterSize,
+           PFMIFSCALLBACK Callback);
+ #endif /*__EXT2LIB_H */
index 0000000,642c1bd..28567b2
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,43 +1,43 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Badblock.c\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -#include "Mke2fs.h"\r
 -\r
 -/* DEFINITIONS ***********************************************************/\r
 -\r
 -/* FUNCTIONS *************************************************************/\r
 -\r
 -bool create_bad_block_inode( PEXT2_FILESYS Ext2Sys,\r
 -                             PEXT2_BADBLK_LIST bb_list)\r
 -{\r
 -    bool            retval;\r
 -    EXT2_INODE      inode;\r
 -    LARGE_INTEGER   SysTime;\r
 -    \r
 -    NtQuerySystemTime(&SysTime);\r
 -\r
 -    ext2_mark_inode_bitmap(Ext2Sys->inode_map, EXT2_BAD_INO);\r
 -\r
 -    Ext2Sys->group_desc[0].bg_free_inodes_count--;\r
 -    Ext2Sys->ext2_sb->s_free_inodes_count--;\r
 -\r
 -    memset(&inode, 0, sizeof(EXT2_INODE));\r
 -    inode.i_mode = (USHORT)((0777 & ~Ext2Sys->umask));\r
 -    inode.i_uid = inode.i_gid = 0;\r
 -    inode.i_blocks = 0;\r
 -    inode.i_block[0] = 0;\r
 -    inode.i_links_count = 2;\r
 -    RtlTimeToSecondsSince1970(&SysTime, &inode.i_mtime);\r
 -    inode.i_ctime = inode.i_atime = inode.i_mtime;\r
 -    inode.i_size = 0;\r
 -\r
 -    retval = ext2_save_inode(Ext2Sys, EXT2_BAD_INO, &inode);\r
 -\r
 -    return retval;\r
 -}\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Badblock.c
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++/* INCLUDES **************************************************************/
++
++#include "Mke2fs.h"
++
++/* DEFINITIONS ***********************************************************/
++
++/* FUNCTIONS *************************************************************/
++
++bool create_bad_block_inode( PEXT2_FILESYS Ext2Sys,
++                             PEXT2_BADBLK_LIST bb_list)
++{
++    bool            retval;
++    EXT2_INODE      inode;
++    LARGE_INTEGER   SysTime;
++    
++    NtQuerySystemTime(&SysTime);
++
++    ext2_mark_inode_bitmap(Ext2Sys->inode_map, EXT2_BAD_INO);
++
++    Ext2Sys->group_desc[0].bg_free_inodes_count--;
++    Ext2Sys->ext2_sb->s_free_inodes_count--;
++
++    memset(&inode, 0, sizeof(EXT2_INODE));
++    inode.i_mode = (USHORT)((0777 & ~Ext2Sys->umask));
++    inode.i_uid = inode.i_gid = 0;
++    inode.i_blocks = 0;
++    inode.i_block[0] = 0;
++    inode.i_links_count = 2;
++    RtlTimeToSecondsSince1970(&SysTime, &inode.i_mtime);
++    inode.i_ctime = inode.i_atime = inode.i_mtime;
++    inode.i_size = 0;
++
++    retval = ext2_save_inode(Ext2Sys, EXT2_BAD_INO, &inode);
++
++    return retval;
++}
index 0000000,bc2746a..cf5a157
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,499 +1,499 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Bitmap.c\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -#include "Mke2fs.h"\r
 -\r
 -/* DEFINITIONS ***********************************************************/\r
 -\r
 -/* FUNCTIONS *************************************************************/\r
 -\r
 -\r
 -bool ext2_set_bit(int nr,void * addr)\r
 -{\r
 -    int     mask;\r
 -    unsigned char *ADDR = (unsigned char *) addr;\r
 -\r
 -    ADDR += nr >> 3;\r
 -    mask = 1 << (nr & 0x07);\r
 -    *ADDR |= mask;\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -bool ext2_clear_bit(int nr, void * addr)\r
 -{\r
 -    int     mask;\r
 -    unsigned char   *ADDR = (unsigned char *) addr;\r
 -\r
 -    ADDR += nr >> 3;\r
 -    mask = 1 << (nr & 0x07);\r
 -    *ADDR &= ~mask;\r
 -    return true;\r
 -}\r
 -\r
 -bool ext2_test_bit(int nr, void * addr)\r
 -{\r
 -    int         mask;\r
 -    const unsigned char *ADDR = (const unsigned char *) addr;\r
 -\r
 -    ADDR += nr >> 3;\r
 -    mask = 1 << (nr & 0x07);\r
 -\r
 -    return ((mask & *ADDR) != 0);\r
 -}\r
 -\r
 -bool ext2_mark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno)\r
 -{\r
 -    if ((bitno < bitmap->start) || (bitno > bitmap->end))\r
 -    {\r
 -        return false;\r
 -    }\r
 -\r
 -    return ext2_set_bit(bitno - bitmap->start, bitmap->bitmap);\r
 -}\r
 -\r
 -bool ext2_unmark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno)\r
 -{\r
 -    if ((bitno < bitmap->start) || (bitno > bitmap->end))\r
 -    {\r
 -        return false;\r
 -    }\r
 -\r
 -    return ext2_clear_bit(bitno - bitmap->start, bitmap->bitmap);\r
 -}\r
 -\r
 -\r
 -bool ext2_test_block_bitmap(PEXT2_BLOCK_BITMAP bitmap,\r
 -                        ULONG block)\r
 -{\r
 -    return ext2_test_bit(block - bitmap->start, bitmap->bitmap);\r
 -}\r
 -\r
 -\r
 -bool ext2_test_block_bitmap_range(PEXT2_BLOCK_BITMAP bitmap,\r
 -                        ULONG block, int num)\r
 -{\r
 -    int i;\r
 -\r
 -    for (i=0; i < num; i++)\r
 -    {\r
 -        if (ext2_test_block_bitmap(bitmap, block+i))\r
 -            return false;\r
 -    }\r
 -    return true;\r
 -}\r
 -\r
 -bool ext2_test_inode_bitmap(PEXT2_BLOCK_BITMAP bitmap,\r
 -                        ULONG inode)\r
 -{\r
 -    return ext2_test_bit(inode - bitmap->start, bitmap->bitmap);\r
 -}\r
 -\r
 -\r
 -bool ext2_allocate_block_bitmap(PEXT2_FILESYS Ext2Sys)\r
 -{\r
 -    ULONG   size = 0;\r
 -\r
 -    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;\r
 -    Ext2Sys->block_map = (PEXT2_BLOCK_BITMAP)\r
 -        RtlAllocateHeap(GetProcessHeap(), 0, sizeof(EXT2_BLOCK_BITMAP));\r
 -\r
 -    if (!Ext2Sys->block_map)\r
 -    {\r
 -        KdPrint(("Mke2fs: error allocating block bitmap...\n"));\r
 -        return false;\r
 -    }\r
 -\r
 -    memset(Ext2Sys->block_map, 0, sizeof(EXT2_BLOCK_BITMAP));\r
 -\r
 -    Ext2Sys->block_map->start = pExt2Sb->s_first_data_block;\r
 -    Ext2Sys->block_map->end = pExt2Sb->s_blocks_count-1;\r
 -    Ext2Sys->block_map->real_end = (EXT2_BLOCKS_PER_GROUP(pExt2Sb)\r
 -        * Ext2Sys->group_desc_count) -1 + Ext2Sys->block_map->start;\r
 -\r
 -    size = (((Ext2Sys->block_map->real_end - Ext2Sys->block_map->start) / 8) + 1);\r
 -\r
 -    Ext2Sys->block_map->bitmap =\r
 -        (char *)RtlAllocateHeap(GetProcessHeap(), 0, size);\r
 -\r
 -    if (!Ext2Sys->block_map->bitmap)\r
 -    {\r
 -        RtlFreeHeap(GetProcessHeap(), 0, Ext2Sys->block_map);\r
 -        Ext2Sys->block_map = NULL;\r
 -        KdPrint(("Mke2fs: error allocating block bitmap...\n"));\r
 -        return false;\r
 -    }\r
 -\r
 -    memset(Ext2Sys->block_map->bitmap, 0, size);\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -\r
 -bool ext2_allocate_inode_bitmap(PEXT2_FILESYS Ext2Sys)\r
 -{\r
 -    ULONG   size = 0;\r
 -\r
 -    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;\r
 -\r
 -    Ext2Sys->inode_map = (PEXT2_INODE_BITMAP)\r
 -        RtlAllocateHeap(GetProcessHeap(), 0, sizeof(EXT2_INODE_BITMAP));\r
 -\r
 -    if (!Ext2Sys->inode_map)\r
 -    {\r
 -        KdPrint(("Mke2fs: error allocating inode bitmap...\n"));\r
 -        return false;\r
 -    }\r
 -\r
 -    memset(Ext2Sys->inode_map, 0, sizeof(EXT2_INODE_BITMAP));\r
 -\r
 -    Ext2Sys->inode_map->start = 1;\r
 -    Ext2Sys->inode_map->end = pExt2Sb->s_inodes_count;\r
 -    Ext2Sys->inode_map->real_end = (EXT2_INODES_PER_GROUP(pExt2Sb)\r
 -        * Ext2Sys->group_desc_count);\r
 -\r
 -    size = (((Ext2Sys->inode_map->real_end - Ext2Sys->inode_map->start) / 8) + 1);\r
 -\r
 -    Ext2Sys->inode_map->bitmap =\r
 -        (char *)RtlAllocateHeap(GetProcessHeap(), 0, size);\r
 -\r
 -    if (!Ext2Sys->inode_map->bitmap)\r
 -    {\r
 -        RtlFreeHeap(GetProcessHeap(), 0, Ext2Sys->inode_map);\r
 -        Ext2Sys->inode_map = NULL;\r
 -        KdPrint(("Mke2fs: error allocating block bitmap...\n"));\r
 -        return false;\r
 -    }\r
 -\r
 -    memset(Ext2Sys->inode_map->bitmap, 0, size);\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -void ext2_free_generic_bitmap(PEXT2_GENERIC_BITMAP bitmap)\r
 -{\r
 -    if (!bitmap)\r
 -        return;\r
 -\r
 -    if (bitmap->bitmap)\r
 -    {\r
 -        RtlFreeHeap(GetProcessHeap(), 0, bitmap->bitmap);\r
 -        bitmap->bitmap = 0;\r
 -    }\r
 -\r
 -    RtlFreeHeap(GetProcessHeap(), 0, bitmap);\r
 -}\r
 -\r
 -void ext2_free_inode_bitmap(PEXT2_FILESYS Ext2Sys)\r
 -{\r
 -    PEXT2_INODE_BITMAP bitmap = Ext2Sys->inode_map;\r
 -    if (!bitmap)\r
 -        return;\r
 -\r
 -    ext2_free_generic_bitmap(bitmap);\r
 -\r
 -    Ext2Sys->inode_map = NULL;\r
 -}\r
 -\r
 -void ext2_free_block_bitmap(PEXT2_FILESYS Ext2Sys)\r
 -{\r
 -    PEXT2_BLOCK_BITMAP bitmap = Ext2Sys->block_map;\r
 -    if (!bitmap)\r
 -        return;\r
 -\r
 -    ext2_free_generic_bitmap(bitmap);\r
 -\r
 -    Ext2Sys->block_map = NULL;\r
 -}\r
 -\r
 -bool ext2_write_inode_bitmap(PEXT2_FILESYS fs)\r
 -{\r
 -    ULONG   i;\r
 -    ULONG   nbytes;\r
 -    bool    retval;\r
 -    char    *inode_bitmap = fs->inode_map->bitmap;\r
 -    char    *bitmap_block = NULL;\r
 -    ULONG   blk;\r
 -\r
 -    if (!inode_bitmap)\r
 -        return false;\r
 -\r
 -    nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->ext2_sb)+7) / 8);\r
 -    \r
 -    bitmap_block = (char *)RtlAllocateHeap(GetProcessHeap(), 0, fs->blocksize);\r
 -    if (!bitmap_block) return false;\r
 -\r
 -    memset(bitmap_block, 0xff, fs->blocksize);\r
 -\r
 -    for (i = 0; i < fs->group_desc_count; i++)\r
 -    {\r
 -        memcpy(bitmap_block, inode_bitmap, nbytes);\r
 -        blk = fs->group_desc[i].bg_inode_bitmap;\r
 -\r
 -        if (blk)\r
 -        {\r
 -/*\r
 -#ifdef EXT2_BIG_ENDIAN_BITMAPS\r
 -            if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||\r
 -                  (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))\r
 -                ext2_swap_bitmap(fs, bitmap_block, nbytes);\r
 -#endif\r
 -*/\r
 -            retval = NT_SUCCESS(Ext2WriteDisk(\r
 -                    fs,\r
 -                    ((ULONGLONG)blk * fs->blocksize),\r
 -                    fs->blocksize, \r
 -                    (unsigned char *)bitmap_block));\r
 -\r
 -            if (!retval)\r
 -            {\r
 -                RtlFreeHeap(GetProcessHeap(), 0, bitmap_block);\r
 -                return false;\r
 -            }\r
 -        }\r
 -\r
 -        inode_bitmap += nbytes;\r
 -    }\r
 -\r
 -    RtlFreeHeap(GetProcessHeap(), 0, bitmap_block);\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -bool ext2_write_block_bitmap (PEXT2_FILESYS fs)\r
 -{\r
 -    ULONG   i;\r
 -    int     j;\r
 -    int     nbytes;\r
 -    int     nbits;\r
 -    bool    retval;\r
 -    char    *block_bitmap = fs->block_map->bitmap;\r
 -    char    *bitmap_block = NULL;\r
 -    ULONG   blk;\r
 -\r
 -    if (!block_bitmap)\r
 -        return false;\r
 -\r
 -    nbytes = EXT2_BLOCKS_PER_GROUP(fs->ext2_sb) / 8;\r
 -\r
 -    bitmap_block = (char *)RtlAllocateHeap(GetProcessHeap(), 0, fs->blocksize);\r
 -    if (!bitmap_block)\r
 -        return false;\r
 -\r
 -    memset(bitmap_block, 0xff, fs->blocksize);\r
 -\r
 -    for (i = 0; i < fs->group_desc_count; i++)\r
 -    {\r
 -        memcpy(bitmap_block, block_bitmap, nbytes);\r
 -\r
 -        if (i == fs->group_desc_count - 1)\r
 -        {\r
 -            /* Force bitmap padding for the last group */\r
 -            nbits = (int) ((fs->ext2_sb->s_blocks_count\r
 -                    - fs->ext2_sb->s_first_data_block)\r
 -                       % EXT2_BLOCKS_PER_GROUP(fs->ext2_sb));\r
 -\r
 -            if (nbits)\r
 -            {\r
 -                for (j = nbits; j < fs->blocksize * 8; j++)\r
 -                {\r
 -                    ext2_set_bit(j, bitmap_block);\r
 -                }\r
 -            }\r
 -        }\r
 -\r
 -        blk = fs->group_desc[i].bg_block_bitmap;\r
 -\r
 -        if (blk)\r
 -        {\r
 -#ifdef EXT2_BIG_ENDIAN_BITMAPS\r
 -            if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||\r
 -                  (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))\r
 -                ext2_swap_bitmap(fs, bitmap_block, nbytes);\r
 -#endif\r
 -            retval = NT_SUCCESS(Ext2WriteDisk(\r
 -                        fs,\r
 -                        ((ULONGLONG)blk * fs->blocksize),\r
 -                        fs->blocksize,\r
 -                        (unsigned char *)bitmap_block));\r
 -\r
 -            if (!retval)\r
 -            {\r
 -                RtlFreeHeap(GetProcessHeap(), 0, bitmap_block);\r
 -                return false;\r
 -            }\r
 -        }\r
 -\r
 -        block_bitmap += nbytes;\r
 -    }\r
 -\r
 -    RtlFreeHeap(GetProcessHeap(), 0, bitmap_block);\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -bool ext2_write_bitmaps(PEXT2_FILESYS fs)\r
 -{\r
 -    bool    retval;\r
 -\r
 -    if (fs->block_map) // && ext2fs_test_bb_dirty(fs))\r
 -    {\r
 -        retval = ext2_write_block_bitmap(fs);\r
 -        if (!retval)\r
 -            return retval;\r
 -    }\r
 -\r
 -    if (fs->inode_map) // && ext2fs_test_ib_dirty(fs))\r
 -    {\r
 -        retval = ext2_write_inode_bitmap(fs);\r
 -        if (!retval)\r
 -            return retval;\r
 -    }\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -\r
 -bool read_bitmaps(PEXT2_FILESYS fs, int do_inode, int do_block)\r
 -{\r
 -    ULONG i;\r
 -    char *block_bitmap = 0, *inode_bitmap = 0;\r
 -    bool retval = false;\r
 -    ULONG block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->ext2_sb) / 8;\r
 -    ULONG inode_nbytes = EXT2_INODES_PER_GROUP(fs->ext2_sb) / 8;\r
 -    ULONG blk;\r
 -\r
 -//  fs->write_bitmaps = ext2_write_bitmaps;\r
 -\r
 -    if (do_block)\r
 -    {\r
 -        if (fs->block_map)\r
 -            ext2_free_block_bitmap(fs);\r
 -\r
 -        retval = ext2_allocate_block_bitmap(fs);\r
 -\r
 -        if (!retval)\r
 -            goto cleanup;\r
 -\r
 -        block_bitmap = fs->block_map->bitmap;\r
 -    }\r
 -\r
 -    if (do_inode)\r
 -    {\r
 -        if (fs->inode_map)\r
 -            ext2_free_inode_bitmap(fs);\r
 -\r
 -        retval = ext2_allocate_inode_bitmap(fs);\r
 -        if (!retval)\r
 -            goto cleanup;\r
 -\r
 -        inode_bitmap = fs->inode_map->bitmap;\r
 -    }\r
 -\r
 -    for (i = 0; i < fs->group_desc_count; i++)\r
 -    {\r
 -        if (block_bitmap)\r
 -        {\r
 -            blk = fs->group_desc[i].bg_block_bitmap;\r
 -\r
 -            if (blk)\r
 -            {\r
 -                retval = NT_SUCCESS(Ext2ReadDisk(\r
 -                            fs,\r
 -                            ((ULONGLONG)blk * fs->blocksize), \r
 -                            block_nbytes,\r
 -                            (unsigned char *) block_bitmap));\r
 -\r
 -                if (!retval)\r
 -                {\r
 -                    goto cleanup;\r
 -                }\r
 -\r
 -#ifdef EXT2_BIG_ENDIAN_BITMAPS\r
 -                if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||\r
 -                      (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))\r
 -                    ext2_swap_bitmap(fs, block_bitmap, block_nbytes);\r
 -#endif\r
 -            }\r
 -            else\r
 -            {\r
 -                memset(block_bitmap, 0, block_nbytes);\r
 -            }\r
 -\r
 -            block_bitmap += block_nbytes;\r
 -        }\r
 -\r
 -        if (inode_bitmap)\r
 -        {\r
 -            blk = fs->group_desc[i].bg_inode_bitmap;\r
 -            if (blk)\r
 -            {\r
 -                retval = NT_SUCCESS(Ext2ReadDisk(\r
 -                    fs, ((LONGLONG)blk * fs->blocksize), \r
 -                    inode_nbytes, \r
 -                    (unsigned char *)inode_bitmap));\r
 -\r
 -                if (!retval)\r
 -                {\r
 -                    goto cleanup;\r
 -                }\r
 -\r
 -#ifdef EXT2_BIG_ENDIAN_BITMAPS\r
 -                if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||\r
 -                      (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))\r
 -                    ext2_swap_bitmap(fs, inode_bitmap, inode_nbytes);\r
 -#endif\r
 -            }\r
 -            else\r
 -            {\r
 -                memset(inode_bitmap, 0, inode_nbytes);\r
 -            }\r
 -\r
 -            inode_bitmap += inode_nbytes;\r
 -        }\r
 -    }\r
 -\r
 -    return true;\r
 -    \r
 -cleanup:\r
 -\r
 -    if (do_block)\r
 -    {\r
 -        RtlFreeHeap(GetProcessHeap(), 0, fs->block_map);\r
 -        fs->block_map = NULL;\r
 -    }\r
 -\r
 -    if (do_inode)\r
 -    {\r
 -        RtlFreeHeap(GetProcessHeap(), 0, fs->inode_map);\r
 -        fs->inode_map = 0;\r
 -    }\r
 -\r
 -    return false;\r
 -}\r
 -\r
 -bool ext2_read_inode_bitmap (PEXT2_FILESYS fs)\r
 -{\r
 -    return read_bitmaps(fs, 1, 0);\r
 -}\r
 -\r
 -bool ext2_read_block_bitmap(PEXT2_FILESYS fs)\r
 -{\r
 -    return read_bitmaps(fs, 0, 1);\r
 -}\r
 -\r
 -bool ext2_read_bitmaps(PEXT2_FILESYS fs)\r
 -{\r
 -\r
 -    if (fs->inode_map && fs->block_map)\r
 -        return 0;\r
 -\r
 -    return read_bitmaps(fs, !fs->inode_map, !fs->block_map);\r
 -}\r
 -\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Bitmap.c
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++/* INCLUDES **************************************************************/
++
++#include "Mke2fs.h"
++
++/* DEFINITIONS ***********************************************************/
++
++/* FUNCTIONS *************************************************************/
++
++
++bool ext2_set_bit(int nr,void * addr)
++{
++    int     mask;
++    unsigned char *ADDR = (unsigned char *) addr;
++
++    ADDR += nr >> 3;
++    mask = 1 << (nr & 0x07);
++    *ADDR |= mask;
++
++    return true;
++}
++
++bool ext2_clear_bit(int nr, void * addr)
++{
++    int     mask;
++    unsigned char   *ADDR = (unsigned char *) addr;
++
++    ADDR += nr >> 3;
++    mask = 1 << (nr & 0x07);
++    *ADDR &= ~mask;
++    return true;
++}
++
++bool ext2_test_bit(int nr, void * addr)
++{
++    int         mask;
++    const unsigned char *ADDR = (const unsigned char *) addr;
++
++    ADDR += nr >> 3;
++    mask = 1 << (nr & 0x07);
++
++    return ((mask & *ADDR) != 0);
++}
++
++bool ext2_mark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno)
++{
++    if ((bitno < bitmap->start) || (bitno > bitmap->end))
++    {
++        return false;
++    }
++
++    return ext2_set_bit(bitno - bitmap->start, bitmap->bitmap);
++}
++
++bool ext2_unmark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno)
++{
++    if ((bitno < bitmap->start) || (bitno > bitmap->end))
++    {
++        return false;
++    }
++
++    return ext2_clear_bit(bitno - bitmap->start, bitmap->bitmap);
++}
++
++
++bool ext2_test_block_bitmap(PEXT2_BLOCK_BITMAP bitmap,
++                        ULONG block)
++{
++    return ext2_test_bit(block - bitmap->start, bitmap->bitmap);
++}
++
++
++bool ext2_test_block_bitmap_range(PEXT2_BLOCK_BITMAP bitmap,
++                        ULONG block, int num)
++{
++    int i;
++
++    for (i=0; i < num; i++)
++    {
++        if (ext2_test_block_bitmap(bitmap, block+i))
++            return false;
++    }
++    return true;
++}
++
++bool ext2_test_inode_bitmap(PEXT2_BLOCK_BITMAP bitmap,
++                        ULONG inode)
++{
++    return ext2_test_bit(inode - bitmap->start, bitmap->bitmap);
++}
++
++
++bool ext2_allocate_block_bitmap(PEXT2_FILESYS Ext2Sys)
++{
++    ULONG   size = 0;
++
++    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
++    Ext2Sys->block_map = (PEXT2_BLOCK_BITMAP)
++        RtlAllocateHeap(GetProcessHeap(), 0, sizeof(EXT2_BLOCK_BITMAP));
++
++    if (!Ext2Sys->block_map)
++    {
++        KdPrint(("Mke2fs: error allocating block bitmap...\n"));
++        return false;
++    }
++
++    memset(Ext2Sys->block_map, 0, sizeof(EXT2_BLOCK_BITMAP));
++
++    Ext2Sys->block_map->start = pExt2Sb->s_first_data_block;
++    Ext2Sys->block_map->end = pExt2Sb->s_blocks_count-1;
++    Ext2Sys->block_map->real_end = (EXT2_BLOCKS_PER_GROUP(pExt2Sb)
++        * Ext2Sys->group_desc_count) -1 + Ext2Sys->block_map->start;
++
++    size = (((Ext2Sys->block_map->real_end - Ext2Sys->block_map->start) / 8) + 1);
++
++    Ext2Sys->block_map->bitmap =
++        (char *)RtlAllocateHeap(GetProcessHeap(), 0, size);
++
++    if (!Ext2Sys->block_map->bitmap)
++    {
++        RtlFreeHeap(GetProcessHeap(), 0, Ext2Sys->block_map);
++        Ext2Sys->block_map = NULL;
++        KdPrint(("Mke2fs: error allocating block bitmap...\n"));
++        return false;
++    }
++
++    memset(Ext2Sys->block_map->bitmap, 0, size);
++
++    return true;
++}
++
++
++bool ext2_allocate_inode_bitmap(PEXT2_FILESYS Ext2Sys)
++{
++    ULONG   size = 0;
++
++    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
++
++    Ext2Sys->inode_map = (PEXT2_INODE_BITMAP)
++        RtlAllocateHeap(GetProcessHeap(), 0, sizeof(EXT2_INODE_BITMAP));
++
++    if (!Ext2Sys->inode_map)
++    {
++        KdPrint(("Mke2fs: error allocating inode bitmap...\n"));
++        return false;
++    }
++
++    memset(Ext2Sys->inode_map, 0, sizeof(EXT2_INODE_BITMAP));
++
++    Ext2Sys->inode_map->start = 1;
++    Ext2Sys->inode_map->end = pExt2Sb->s_inodes_count;
++    Ext2Sys->inode_map->real_end = (EXT2_INODES_PER_GROUP(pExt2Sb)
++        * Ext2Sys->group_desc_count);
++
++    size = (((Ext2Sys->inode_map->real_end - Ext2Sys->inode_map->start) / 8) + 1);
++
++    Ext2Sys->inode_map->bitmap =
++        (char *)RtlAllocateHeap(GetProcessHeap(), 0, size);
++
++    if (!Ext2Sys->inode_map->bitmap)
++    {
++        RtlFreeHeap(GetProcessHeap(), 0, Ext2Sys->inode_map);
++        Ext2Sys->inode_map = NULL;
++        KdPrint(("Mke2fs: error allocating block bitmap...\n"));
++        return false;
++    }
++
++    memset(Ext2Sys->inode_map->bitmap, 0, size);
++
++    return true;
++}
++
++void ext2_free_generic_bitmap(PEXT2_GENERIC_BITMAP bitmap)
++{
++    if (!bitmap)
++        return;
++
++    if (bitmap->bitmap)
++    {
++        RtlFreeHeap(GetProcessHeap(), 0, bitmap->bitmap);
++        bitmap->bitmap = 0;
++    }
++
++    RtlFreeHeap(GetProcessHeap(), 0, bitmap);
++}
++
++void ext2_free_inode_bitmap(PEXT2_FILESYS Ext2Sys)
++{
++    PEXT2_INODE_BITMAP bitmap = Ext2Sys->inode_map;
++    if (!bitmap)
++        return;
++
++    ext2_free_generic_bitmap(bitmap);
++
++    Ext2Sys->inode_map = NULL;
++}
++
++void ext2_free_block_bitmap(PEXT2_FILESYS Ext2Sys)
++{
++    PEXT2_BLOCK_BITMAP bitmap = Ext2Sys->block_map;
++    if (!bitmap)
++        return;
++
++    ext2_free_generic_bitmap(bitmap);
++
++    Ext2Sys->block_map = NULL;
++}
++
++bool ext2_write_inode_bitmap(PEXT2_FILESYS fs)
++{
++    ULONG   i;
++    ULONG   nbytes;
++    bool    retval;
++    char    *inode_bitmap = fs->inode_map->bitmap;
++    char    *bitmap_block = NULL;
++    ULONG   blk;
++
++    if (!inode_bitmap)
++        return false;
++
++    nbytes = (size_t) ((EXT2_INODES_PER_GROUP(fs->ext2_sb)+7) / 8);
++    
++    bitmap_block = (char *)RtlAllocateHeap(GetProcessHeap(), 0, fs->blocksize);
++    if (!bitmap_block) return false;
++
++    memset(bitmap_block, 0xff, fs->blocksize);
++
++    for (i = 0; i < fs->group_desc_count; i++)
++    {
++        memcpy(bitmap_block, inode_bitmap, nbytes);
++        blk = fs->group_desc[i].bg_inode_bitmap;
++
++        if (blk)
++        {
++/*
++#ifdef EXT2_BIG_ENDIAN_BITMAPS
++            if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                  (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
++                ext2_swap_bitmap(fs, bitmap_block, nbytes);
++#endif
++*/
++            retval = NT_SUCCESS(Ext2WriteDisk(
++                    fs,
++                    ((ULONGLONG)blk * fs->blocksize),
++                    fs->blocksize, 
++                    (unsigned char *)bitmap_block));
++
++            if (!retval)
++            {
++                RtlFreeHeap(GetProcessHeap(), 0, bitmap_block);
++                return false;
++            }
++        }
++
++        inode_bitmap += nbytes;
++    }
++
++    RtlFreeHeap(GetProcessHeap(), 0, bitmap_block);
++
++    return true;
++}
++
++bool ext2_write_block_bitmap (PEXT2_FILESYS fs)
++{
++    ULONG   i;
++    int     j;
++    int     nbytes;
++    int     nbits;
++    bool    retval;
++    char    *block_bitmap = fs->block_map->bitmap;
++    char    *bitmap_block = NULL;
++    ULONG   blk;
++
++    if (!block_bitmap)
++        return false;
++
++    nbytes = EXT2_BLOCKS_PER_GROUP(fs->ext2_sb) / 8;
++
++    bitmap_block = (char *)RtlAllocateHeap(GetProcessHeap(), 0, fs->blocksize);
++    if (!bitmap_block)
++        return false;
++
++    memset(bitmap_block, 0xff, fs->blocksize);
++
++    for (i = 0; i < fs->group_desc_count; i++)
++    {
++        memcpy(bitmap_block, block_bitmap, nbytes);
++
++        if (i == fs->group_desc_count - 1)
++        {
++            /* Force bitmap padding for the last group */
++            nbits = (int) ((fs->ext2_sb->s_blocks_count
++                    - fs->ext2_sb->s_first_data_block)
++                       % EXT2_BLOCKS_PER_GROUP(fs->ext2_sb));
++
++            if (nbits)
++            {
++                for (j = nbits; j < fs->blocksize * 8; j++)
++                {
++                    ext2_set_bit(j, bitmap_block);
++                }
++            }
++        }
++
++        blk = fs->group_desc[i].bg_block_bitmap;
++
++        if (blk)
++        {
++#ifdef EXT2_BIG_ENDIAN_BITMAPS
++            if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                  (fs->flags & EXT2_FLAG_SWAP_BYTES_WRITE)))
++                ext2_swap_bitmap(fs, bitmap_block, nbytes);
++#endif
++            retval = NT_SUCCESS(Ext2WriteDisk(
++                        fs,
++                        ((ULONGLONG)blk * fs->blocksize),
++                        fs->blocksize,
++                        (unsigned char *)bitmap_block));
++
++            if (!retval)
++            {
++                RtlFreeHeap(GetProcessHeap(), 0, bitmap_block);
++                return false;
++            }
++        }
++
++        block_bitmap += nbytes;
++    }
++
++    RtlFreeHeap(GetProcessHeap(), 0, bitmap_block);
++
++    return true;
++}
++
++bool ext2_write_bitmaps(PEXT2_FILESYS fs)
++{
++    bool    retval;
++
++    if (fs->block_map) // && ext2fs_test_bb_dirty(fs))
++    {
++        retval = ext2_write_block_bitmap(fs);
++        if (!retval)
++            return retval;
++    }
++
++    if (fs->inode_map) // && ext2fs_test_ib_dirty(fs))
++    {
++        retval = ext2_write_inode_bitmap(fs);
++        if (!retval)
++            return retval;
++    }
++
++    return true;
++}
++
++
++bool read_bitmaps(PEXT2_FILESYS fs, int do_inode, int do_block)
++{
++    ULONG i;
++    char *block_bitmap = 0, *inode_bitmap = 0;
++    bool retval = false;
++    ULONG block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->ext2_sb) / 8;
++    ULONG inode_nbytes = EXT2_INODES_PER_GROUP(fs->ext2_sb) / 8;
++    ULONG blk;
++
++//  fs->write_bitmaps = ext2_write_bitmaps;
++
++    if (do_block)
++    {
++        if (fs->block_map)
++            ext2_free_block_bitmap(fs);
++
++        retval = ext2_allocate_block_bitmap(fs);
++
++        if (!retval)
++            goto cleanup;
++
++        block_bitmap = fs->block_map->bitmap;
++    }
++
++    if (do_inode)
++    {
++        if (fs->inode_map)
++            ext2_free_inode_bitmap(fs);
++
++        retval = ext2_allocate_inode_bitmap(fs);
++        if (!retval)
++            goto cleanup;
++
++        inode_bitmap = fs->inode_map->bitmap;
++    }
++
++    for (i = 0; i < fs->group_desc_count; i++)
++    {
++        if (block_bitmap)
++        {
++            blk = fs->group_desc[i].bg_block_bitmap;
++
++            if (blk)
++            {
++                retval = NT_SUCCESS(Ext2ReadDisk(
++                            fs,
++                            ((ULONGLONG)blk * fs->blocksize), 
++                            block_nbytes,
++                            (unsigned char *) block_bitmap));
++
++                if (!retval)
++                {
++                    goto cleanup;
++                }
++
++#ifdef EXT2_BIG_ENDIAN_BITMAPS
++                if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                      (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
++                    ext2_swap_bitmap(fs, block_bitmap, block_nbytes);
++#endif
++            }
++            else
++            {
++                memset(block_bitmap, 0, block_nbytes);
++            }
++
++            block_bitmap += block_nbytes;
++        }
++
++        if (inode_bitmap)
++        {
++            blk = fs->group_desc[i].bg_inode_bitmap;
++            if (blk)
++            {
++                retval = NT_SUCCESS(Ext2ReadDisk(
++                    fs, ((LONGLONG)blk * fs->blocksize), 
++                    inode_nbytes, 
++                    (unsigned char *)inode_bitmap));
++
++                if (!retval)
++                {
++                    goto cleanup;
++                }
++
++#ifdef EXT2_BIG_ENDIAN_BITMAPS
++                if (!((fs->flags & EXT2_FLAG_SWAP_BYTES) ||
++                      (fs->flags & EXT2_FLAG_SWAP_BYTES_READ)))
++                    ext2_swap_bitmap(fs, inode_bitmap, inode_nbytes);
++#endif
++            }
++            else
++            {
++                memset(inode_bitmap, 0, inode_nbytes);
++            }
++
++            inode_bitmap += inode_nbytes;
++        }
++    }
++
++    return true;
++    
++cleanup:
++
++    if (do_block)
++    {
++        RtlFreeHeap(GetProcessHeap(), 0, fs->block_map);
++        fs->block_map = NULL;
++    }
++
++    if (do_inode)
++    {
++        RtlFreeHeap(GetProcessHeap(), 0, fs->inode_map);
++        fs->inode_map = 0;
++    }
++
++    return false;
++}
++
++bool ext2_read_inode_bitmap (PEXT2_FILESYS fs)
++{
++    return read_bitmaps(fs, 1, 0);
++}
++
++bool ext2_read_block_bitmap(PEXT2_FILESYS fs)
++{
++    return read_bitmaps(fs, 0, 1);
++}
++
++bool ext2_read_bitmaps(PEXT2_FILESYS fs)
++{
++
++    if (fs->inode_map && fs->block_map)
++        return 0;
++
++    return read_bitmaps(fs, !fs->inode_map, !fs->block_map);
++}
++
index 0000000,d6569d0..cbac01c
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,12 +1,12 @@@
 -#ifndef _BITMAP_H\r
 -\r
 -#include "time.h"\r
 -#include "stdio.h"\r
 -#include "stdlib.h"\r
 -#include "string.h"\r
 -#include "windows.h"\r
 -\r
 -\r
 -\r
 -\r
 -#endif // _BITMAP_H\r
++#ifndef _BITMAP_H
++
++#include "time.h"
++#include "stdio.h"
++#include "stdlib.h"
++#include "string.h"
++#include "windows.h"
++
++
++
++
++#endif // _BITMAP_H
index 0000000,ee32503..1930aad
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1352 +1,1352 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Disk.c\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -#include "Mke2fs.h"\r
 -\r
 -/* DEFINITIONS ***********************************************************/\r
 -\r
 -\r
 -\r
 -/* FUNCTIONS *************************************************************/\r
 -\r
 -PUCHAR\r
 -Ext2StatusToString ( IN NTSTATUS Status )\r
 -{\r
 -    switch (Status)\r
 -    {\r
 -    case 0x00000000: return "STATUS_SUCCESS";\r
 -    case 0x00000001: return "STATUS_WAIT_1";\r
 -    case 0x00000002: return "STATUS_WAIT_2";\r
 -    case 0x00000003: return "STATUS_WAIT_3";\r
 -    case 0x0000003F: return "STATUS_WAIT_63";\r
 -    case 0x00000080: return "STATUS_ABANDONED_WAIT_0";\r
 -    case 0x000000BF: return "STATUS_ABANDONED_WAIT_63";\r
 -    case 0x000000C0: return "STATUS_USER_APC";\r
 -    case 0x00000100: return "STATUS_KERNEL_APC";\r
 -    case 0x00000101: return "STATUS_ALERTED";\r
 -    case 0x00000102: return "STATUS_TIMEOUT";\r
 -    case 0x00000103: return "STATUS_PENDING";\r
 -    case 0x00000104: return "STATUS_REPARSE";\r
 -    case 0x00000105: return "STATUS_MORE_ENTRIES";\r
 -    case 0x00000106: return "STATUS_NOT_ALL_ASSIGNED";\r
 -    case 0x00000107: return "STATUS_SOME_NOT_MAPPED";\r
 -    case 0x00000108: return "STATUS_OPLOCK_BREAK_IN_PROGRESS";\r
 -    case 0x00000109: return "STATUS_VOLUME_MOUNTED";\r
 -    case 0x0000010A: return "STATUS_RXACT_COMMITTED";\r
 -    case 0x0000010B: return "STATUS_NOTIFY_CLEANUP";\r
 -    case 0x0000010C: return "STATUS_NOTIFY_ENUM_DIR";\r
 -    case 0x0000010D: return "STATUS_NO_QUOTAS_FOR_ACCOUNT";\r
 -    case 0x0000010E: return "STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED";\r
 -    case 0x00000110: return "STATUS_PAGE_FAULT_TRANSITION";\r
 -    case 0x00000111: return "STATUS_PAGE_FAULT_DEMAND_ZERO";\r
 -    case 0x00000112: return "STATUS_PAGE_FAULT_COPY_ON_WRITE";\r
 -    case 0x00000113: return "STATUS_PAGE_FAULT_GUARD_PAGE";\r
 -    case 0x00000114: return "STATUS_PAGE_FAULT_PAGING_FILE";\r
 -    case 0x00000115: return "STATUS_CACHE_PAGE_LOCKED";\r
 -    case 0x00000116: return "STATUS_CRASH_DUMP";\r
 -    case 0x00000117: return "STATUS_BUFFER_ALL_ZEROS";\r
 -    case 0x00000118: return "STATUS_REPARSE_OBJECT";\r
 -    case 0x00000119: return "STATUS_RESOURCE_REQUIREMENTS_CHANGED";\r
 -    case 0x00000120: return "STATUS_TRANSLATION_COMPLETE";\r
 -    case 0x00000121: return "STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY";\r
 -    case 0x00010001: return "DBG_EXCEPTION_HANDLED";\r
 -    case 0x00010002: return "DBG_CONTINUE";\r
 -    case 0x40000000: return "STATUS_OBJECT_NAME_EXISTS";\r
 -    case 0x40000001: return "STATUS_THREAD_WAS_SUSPENDED";\r
 -    case 0x40000002: return "STATUS_WORKING_SET_LIMIT_RANGE";\r
 -    case 0x40000003: return "STATUS_IMAGE_NOT_AT_BASE";\r
 -    case 0x40000004: return "STATUS_RXACT_STATE_CREATED";\r
 -    case 0x40000005: return "STATUS_SEGMENT_NOTIFICATION";\r
 -    case 0x40000006: return "STATUS_LOCAL_USER_SESSION_KEY";\r
 -    case 0x40000007: return "STATUS_BAD_CURRENT_DIRECTORY";\r
 -    case 0x40000008: return "STATUS_SERIAL_MORE_WRITES";\r
 -    case 0x40000009: return "STATUS_REGISTRY_RECOVERED";\r
 -    case 0x4000000A: return "STATUS_FT_READ_RECOVERY_FROM_BACKUP";\r
 -    case 0x4000000B: return "STATUS_FT_WRITE_RECOVERY";\r
 -    case 0x4000000C: return "STATUS_SERIAL_COUNTER_TIMEOUT";\r
 -    case 0x4000000D: return "STATUS_NULL_LM_PASSWORD";\r
 -    case 0x4000000E: return "STATUS_IMAGE_MACHINE_TYPE_MISMATCH";\r
 -    case 0x4000000F: return "STATUS_RECEIVE_PARTIAL";\r
 -    case 0x40000010: return "STATUS_RECEIVE_EXPEDITED";\r
 -    case 0x40000011: return "STATUS_RECEIVE_PARTIAL_EXPEDITED";\r
 -    case 0x40000012: return "STATUS_EVENT_DONE";\r
 -    case 0x40000013: return "STATUS_EVENT_PENDING";\r
 -    case 0x40000014: return "STATUS_CHECKING_FILE_SYSTEM";\r
 -    case 0x40000015: return "STATUS_FATAL_APP_EXIT";\r
 -    case 0x40000016: return "STATUS_PREDEFINED_HANDLE";\r
 -    case 0x40000017: return "STATUS_WAS_UNLOCKED";\r
 -    case 0x40000018: return "STATUS_SERVICE_NOTIFICATION";\r
 -    case 0x40000019: return "STATUS_WAS_LOCKED";\r
 -    case 0x4000001A: return "STATUS_LOG_HARD_ERROR";\r
 -    case 0x4000001B: return "STATUS_ALREADY_WIN32";\r
 -    case 0x4000001C: return "STATUS_WX86_UNSIMULATE";\r
 -    case 0x4000001D: return "STATUS_WX86_CONTINUE";\r
 -    case 0x4000001E: return "STATUS_WX86_SINGLE_STEP";\r
 -    case 0x4000001F: return "STATUS_WX86_BREAKPOINT";\r
 -    case 0x40000020: return "STATUS_WX86_EXCEPTION_CONTINUE";\r
 -    case 0x40000021: return "STATUS_WX86_EXCEPTION_LASTCHANCE";\r
 -    case 0x40000022: return "STATUS_WX86_EXCEPTION_CHAIN";\r
 -    case 0x40000023: return "STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE";\r
 -    case 0x40000024: return "STATUS_NO_YIELD_PERFORMED";\r
 -    case 0x40000025: return "STATUS_TIMER_RESUME_IGNORED";\r
 -    case 0x40000026: return "STATUS_ARBITRATION_UNHANDLED";\r
 -    case 0x40000027: return "STATUS_CARDBUS_NOT_SUPPORTED";\r
 -    case 0x40000028: return "STATUS_WX86_CREATEWX86TIB";\r
 -    case 0x40000029: return "STATUS_MP_PROCESSOR_MISMATCH";\r
 -    case 0x40010001: return "DBG_REPLY_LATER";\r
 -    case 0x40010002: return "DBG_UNABLE_TO_PROVIDE_HANDLE";\r
 -    case 0x40010003: return "DBG_TERMINATE_THREAD";\r
 -    case 0x40010004: return "DBG_TERMINATE_PROCESS";\r
 -    case 0x40010005: return "DBG_CONTROL_C";\r
 -    case 0x40010006: return "DBG_PRINTEXCEPTION_C";\r
 -    case 0x40010007: return "DBG_RIPEXCEPTION";\r
 -    case 0x40010008: return "DBG_CONTROL_BREAK";\r
 -    case 0x80000001: return "STATUS_GUARD_PAGE_VIOLATION";\r
 -    case 0x80000002: return "STATUS_DATATYPE_MISALIGNMENT";\r
 -    case 0x80000003: return "STATUS_BREAKPOINT";\r
 -    case 0x80000004: return "STATUS_SINGLE_STEP";\r
 -    case 0x80000005: return "STATUS_BUFFER_OVERFLOW";\r
 -    case 0x80000006: return "STATUS_NO_MORE_FILES";\r
 -    case 0x80000007: return "STATUS_WAKE_SYSTEM_DEBUGGER";\r
 -    case 0x8000000A: return "STATUS_HANDLES_CLOSED";\r
 -    case 0x8000000B: return "STATUS_NO_INHERITANCE";\r
 -    case 0x8000000C: return "STATUS_GUID_SUBSTITUTION_MADE";\r
 -    case 0x8000000D: return "STATUS_PARTIAL_COPY";\r
 -    case 0x8000000E: return "STATUS_DEVICE_PAPER_EMPTY";\r
 -    case 0x8000000F: return "STATUS_DEVICE_POWERED_OFF";\r
 -    case 0x80000010: return "STATUS_DEVICE_OFF_LINE";\r
 -    case 0x80000011: return "STATUS_DEVICE_BUSY";\r
 -    case 0x80000012: return "STATUS_NO_MORE_EAS";\r
 -    case 0x80000013: return "STATUS_INVALID_EA_NAME";\r
 -    case 0x80000014: return "STATUS_EA_LIST_INCONSISTENT";\r
 -    case 0x80000015: return "STATUS_INVALID_EA_FLAG";\r
 -    case 0x80000016: return "STATUS_VERIFY_REQUIRED";\r
 -    case 0x80000017: return "STATUS_EXTRANEOUS_INFORMATION";\r
 -    case 0x80000018: return "STATUS_RXACT_COMMIT_NECESSARY";\r
 -    case 0x8000001A: return "STATUS_NO_MORE_ENTRIES";\r
 -    case 0x8000001B: return "STATUS_FILEMARK_DETECTED";\r
 -    case 0x8000001C: return "STATUS_MEDIA_CHANGED";\r
 -    case 0x8000001D: return "STATUS_BUS_RESET";\r
 -    case 0x8000001E: return "STATUS_END_OF_MEDIA";\r
 -    case 0x8000001F: return "STATUS_BEGINNING_OF_MEDIA";\r
 -    case 0x80000020: return "STATUS_MEDIA_CHECK";\r
 -    case 0x80000021: return "STATUS_SETMARK_DETECTED";\r
 -    case 0x80000022: return "STATUS_NO_DATA_DETECTED";\r
 -    case 0x80000023: return "STATUS_REDIRECTOR_HAS_OPEN_HANDLES";\r
 -    case 0x80000024: return "STATUS_SERVER_HAS_OPEN_HANDLES";\r
 -    case 0x80000025: return "STATUS_ALREADY_DISCONNECTED";\r
 -    case 0x80000026: return "STATUS_LONGJUMP";\r
 -    case 0x80010001: return "DBG_EXCEPTION_NOT_HANDLED";\r
 -    case 0xC0000001: return "STATUS_UNSUCCESSFUL";\r
 -    case 0xC0000002: return "STATUS_NOT_IMPLEMENTED";\r
 -    case 0xC0000003: return "STATUS_INVALID_INFO_CLASS";\r
 -    case 0xC0000004: return "STATUS_INFO_LENGTH_MISMATCH";\r
 -    case 0xC0000005: return "STATUS_ACCESS_VIOLATION";\r
 -    case 0xC0000006: return "STATUS_IN_PAGE_ERROR";\r
 -    case 0xC0000007: return "STATUS_PAGEFILE_QUOTA";\r
 -    case 0xC0000008: return "STATUS_INVALID_HANDLE";\r
 -    case 0xC0000009: return "STATUS_BAD_INITIAL_STACK";\r
 -    case 0xC000000A: return "STATUS_BAD_INITIAL_PC";\r
 -    case 0xC000000B: return "STATUS_INVALID_CID";\r
 -    case 0xC000000C: return "STATUS_TIMER_NOT_CANCELED";\r
 -    case 0xC000000D: return "STATUS_INVALID_PARAMETER";\r
 -    case 0xC000000E: return "STATUS_NO_SUCH_DEVICE";\r
 -    case 0xC000000F: return "STATUS_NO_SUCH_FILE";\r
 -    case 0xC0000010: return "STATUS_INVALID_DEVICE_REQUEST";\r
 -    case 0xC0000011: return "STATUS_END_OF_FILE";\r
 -    case 0xC0000012: return "STATUS_WRONG_VOLUME";\r
 -    case 0xC0000013: return "STATUS_NO_MEDIA_IN_DEVICE";\r
 -    case 0xC0000014: return "STATUS_UNRECOGNIZED_MEDIA";\r
 -    case 0xC0000015: return "STATUS_NONEXISTENT_SECTOR";\r
 -    case 0xC0000016: return "STATUS_MORE_PROCESSING_REQUIRED";\r
 -    case 0xC0000017: return "STATUS_NO_MEMORY";\r
 -    case 0xC0000018: return "STATUS_CONFLICTING_ADDRESSES";\r
 -    case 0xC0000019: return "STATUS_NOT_MAPPED_VIEW";\r
 -    case 0xC000001A: return "STATUS_UNABLE_TO_FREE_VM";\r
 -    case 0xC000001B: return "STATUS_UNABLE_TO_DELETE_SECTION";\r
 -    case 0xC000001C: return "STATUS_INVALID_SYSTEM_SERVICE";\r
 -    case 0xC000001D: return "STATUS_ILLEGAL_INSTRUCTION";\r
 -    case 0xC000001E: return "STATUS_INVALID_LOCK_SEQUENCE";\r
 -    case 0xC000001F: return "STATUS_INVALID_VIEW_SIZE";\r
 -    case 0xC0000020: return "STATUS_INVALID_FILE_FOR_SECTION";\r
 -    case 0xC0000021: return "STATUS_ALREADY_COMMITTED";\r
 -    case 0xC0000022: return "STATUS_ACCESS_DENIED";\r
 -    case 0xC0000023: return "STATUS_BUFFER_TOO_SMALL";\r
 -    case 0xC0000024: return "STATUS_OBJECT_TYPE_MISMATCH";\r
 -    case 0xC0000025: return "STATUS_NONCONTINUABLE_EXCEPTION";\r
 -    case 0xC0000026: return "STATUS_INVALID_DISPOSITION";\r
 -    case 0xC0000027: return "STATUS_UNWIND";\r
 -    case 0xC0000028: return "STATUS_BAD_STACK";\r
 -    case 0xC0000029: return "STATUS_INVALID_UNWIND_TARGET";\r
 -    case 0xC000002A: return "STATUS_NOT_LOCKED";\r
 -    case 0xC000002B: return "STATUS_PARITY_ERROR";\r
 -    case 0xC000002C: return "STATUS_UNABLE_TO_DECOMMIT_VM";\r
 -    case 0xC000002D: return "STATUS_NOT_COMMITTED";\r
 -    case 0xC000002E: return "STATUS_INVALID_PORT_ATTRIBUTES";\r
 -    case 0xC000002F: return "STATUS_PORT_MESSAGE_TOO_LONG";\r
 -    case 0xC0000030: return "STATUS_INVALID_PARAMETER_MIX";\r
 -    case 0xC0000031: return "STATUS_INVALID_QUOTA_LOWER";\r
 -    case 0xC0000032: return "STATUS_DISK_CORRUPT_ERROR";\r
 -    case 0xC0000033: return "STATUS_OBJECT_NAME_INVALID";\r
 -    case 0xC0000034: return "STATUS_OBJECT_NAME_NOT_FOUND";\r
 -    case 0xC0000035: return "STATUS_OBJECT_NAME_COLLISION";\r
 -    case 0xC0000037: return "STATUS_PORT_DISCONNECTED";\r
 -    case 0xC0000038: return "STATUS_DEVICE_ALREADY_ATTACHED";\r
 -    case 0xC0000039: return "STATUS_OBJECT_PATH_INVALID";\r
 -    case 0xC000003A: return "STATUS_OBJECT_PATH_NOT_FOUND";\r
 -    case 0xC000003B: return "STATUS_OBJECT_PATH_SYNTAX_BAD";\r
 -    case 0xC000003C: return "STATUS_DATA_OVERRUN";\r
 -    case 0xC000003D: return "STATUS_DATA_LATE_ERROR";\r
 -    case 0xC000003E: return "STATUS_DATA_ERROR";\r
 -    case 0xC000003F: return "STATUS_CRC_ERROR";\r
 -    case 0xC0000040: return "STATUS_SECTION_TOO_BIG";\r
 -    case 0xC0000041: return "STATUS_PORT_CONNECTION_REFUSED";\r
 -    case 0xC0000042: return "STATUS_INVALID_PORT_HANDLE";\r
 -    case 0xC0000043: return "STATUS_SHARING_VIOLATION";\r
 -    case 0xC0000044: return "STATUS_QUOTA_EXCEEDED";\r
 -    case 0xC0000045: return "STATUS_INVALID_PAGE_PROTECTION";\r
 -    case 0xC0000046: return "STATUS_MUTANT_NOT_OWNED";\r
 -    case 0xC0000047: return "STATUS_SEMAPHORE_LIMIT_EXCEEDED";\r
 -    case 0xC0000048: return "STATUS_PORT_ALREADY_SET";\r
 -    case 0xC0000049: return "STATUS_SECTION_NOT_IMAGE";\r
 -    case 0xC000004A: return "STATUS_SUSPEND_COUNT_EXCEEDED";\r
 -    case 0xC000004B: return "STATUS_THREAD_IS_TERMINATING";\r
 -    case 0xC000004C: return "STATUS_BAD_WORKING_SET_LIMIT";\r
 -    case 0xC000004D: return "STATUS_INCOMPATIBLE_FILE_MAP";\r
 -    case 0xC000004E: return "STATUS_SECTION_PROTECTION";\r
 -    case 0xC000004F: return "STATUS_EAS_NOT_SUPPORTED";\r
 -    case 0xC0000050: return "STATUS_EA_TOO_LARGE";\r
 -    case 0xC0000051: return "STATUS_NONEXISTENT_EA_ENTRY";\r
 -    case 0xC0000052: return "STATUS_NO_EAS_ON_FILE";\r
 -    case 0xC0000053: return "STATUS_EA_CORRUPT_ERROR";\r
 -    case 0xC0000054: return "STATUS_FILE_LOCK_CONFLICT";\r
 -    case 0xC0000055: return "STATUS_LOCK_NOT_GRANTED";\r
 -    case 0xC0000056: return "STATUS_DELETE_PENDING";\r
 -    case 0xC0000057: return "STATUS_CTL_FILE_NOT_SUPPORTED";\r
 -    case 0xC0000058: return "STATUS_UNKNOWN_REVISION";\r
 -    case 0xC0000059: return "STATUS_REVISION_MISMATCH";\r
 -    case 0xC000005A: return "STATUS_INVALID_OWNER";\r
 -    case 0xC000005B: return "STATUS_INVALID_PRIMARY_GROUP";\r
 -    case 0xC000005C: return "STATUS_NO_IMPERSONATION_TOKEN";\r
 -    case 0xC000005D: return "STATUS_CANT_DISABLE_MANDATORY";\r
 -    case 0xC000005E: return "STATUS_NO_LOGON_SERVERS";\r
 -    case 0xC000005F: return "STATUS_NO_SUCH_LOGON_SESSION";\r
 -    case 0xC0000060: return "STATUS_NO_SUCH_PRIVILEGE";\r
 -    case 0xC0000061: return "STATUS_PRIVILEGE_NOT_HELD";\r
 -    case 0xC0000062: return "STATUS_INVALID_ACCOUNT_NAME";\r
 -    case 0xC0000063: return "STATUS_USER_EXISTS";\r
 -    case 0xC0000064: return "STATUS_NO_SUCH_USER";\r
 -    case 0xC0000065: return "STATUS_GROUP_EXISTS";\r
 -    case 0xC0000066: return "STATUS_NO_SUCH_GROUP";\r
 -    case 0xC0000067: return "STATUS_MEMBER_IN_GROUP";\r
 -    case 0xC0000068: return "STATUS_MEMBER_NOT_IN_GROUP";\r
 -    case 0xC0000069: return "STATUS_LAST_ADMIN";\r
 -    case 0xC000006A: return "STATUS_WRONG_PASSWORD";\r
 -    case 0xC000006B: return "STATUS_ILL_FORMED_PASSWORD";\r
 -    case 0xC000006C: return "STATUS_PASSWORD_RESTRICTION";\r
 -    case 0xC000006D: return "STATUS_LOGON_FAILURE";\r
 -    case 0xC000006E: return "STATUS_ACCOUNT_RESTRICTION";\r
 -    case 0xC000006F: return "STATUS_INVALID_LOGON_HOURS";\r
 -    case 0xC0000070: return "STATUS_INVALID_WORKSTATION";\r
 -    case 0xC0000071: return "STATUS_PASSWORD_EXPIRED";\r
 -    case 0xC0000072: return "STATUS_ACCOUNT_DISABLED";\r
 -    case 0xC0000073: return "STATUS_NONE_MAPPED";\r
 -    case 0xC0000074: return "STATUS_TOO_MANY_LUIDS_REQUESTED";\r
 -    case 0xC0000075: return "STATUS_LUIDS_EXHAUSTED";\r
 -    case 0xC0000076: return "STATUS_INVALID_SUB_AUTHORITY";\r
 -    case 0xC0000077: return "STATUS_INVALID_ACL";\r
 -    case 0xC0000078: return "STATUS_INVALID_SID";\r
 -    case 0xC0000079: return "STATUS_INVALID_SECURITY_DESCR";\r
 -    case 0xC000007A: return "STATUS_PROCEDURE_NOT_FOUND";\r
 -    case 0xC000007B: return "STATUS_INVALID_IMAGE_FORMAT";\r
 -    case 0xC000007C: return "STATUS_NO_TOKEN";\r
 -    case 0xC000007D: return "STATUS_BAD_INHERITANCE_ACL";\r
 -    case 0xC000007E: return "STATUS_RANGE_NOT_LOCKED";\r
 -    case 0xC000007F: return "STATUS_DISK_FULL";\r
 -    case 0xC0000080: return "STATUS_SERVER_DISABLED";\r
 -    case 0xC0000081: return "STATUS_SERVER_NOT_DISABLED";\r
 -    case 0xC0000082: return "STATUS_TOO_MANY_GUIDS_REQUESTED";\r
 -    case 0xC0000083: return "STATUS_GUIDS_EXHAUSTED";\r
 -    case 0xC0000084: return "STATUS_INVALID_ID_AUTHORITY";\r
 -    case 0xC0000085: return "STATUS_AGENTS_EXHAUSTED";\r
 -    case 0xC0000086: return "STATUS_INVALID_VOLUME_LABEL";\r
 -    case 0xC0000087: return "STATUS_SECTION_NOT_EXTENDED";\r
 -    case 0xC0000088: return "STATUS_NOT_MAPPED_DATA";\r
 -    case 0xC0000089: return "STATUS_RESOURCE_DATA_NOT_FOUND";\r
 -    case 0xC000008A: return "STATUS_RESOURCE_TYPE_NOT_FOUND";\r
 -    case 0xC000008B: return "STATUS_RESOURCE_NAME_NOT_FOUND";\r
 -    case 0xC000008C: return "STATUS_ARRAY_BOUNDS_EXCEEDED";\r
 -    case 0xC000008D: return "STATUS_FLOAT_DENORMAL_OPERAND";\r
 -    case 0xC000008E: return "STATUS_FLOAT_DIVIDE_BY_ZERO";\r
 -    case 0xC000008F: return "STATUS_FLOAT_INEXACT_RESULT";\r
 -    case 0xC0000090: return "STATUS_FLOAT_INVALID_OPERATION";\r
 -    case 0xC0000091: return "STATUS_FLOAT_OVERFLOW";\r
 -    case 0xC0000092: return "STATUS_FLOAT_STACK_CHECK";\r
 -    case 0xC0000093: return "STATUS_FLOAT_UNDERFLOW";\r
 -    case 0xC0000094: return "STATUS_INTEGER_DIVIDE_BY_ZERO";\r
 -    case 0xC0000095: return "STATUS_INTEGER_OVERFLOW";\r
 -    case 0xC0000096: return "STATUS_PRIVILEGED_INSTRUCTION";\r
 -    case 0xC0000097: return "STATUS_TOO_MANY_PAGING_FILES";\r
 -    case 0xC0000098: return "STATUS_FILE_INVALID";\r
 -    case 0xC0000099: return "STATUS_ALLOTTED_SPACE_EXCEEDED";\r
 -    case 0xC000009A: return "STATUS_INSUFFICIENT_RESOURCES";\r
 -    case 0xC000009B: return "STATUS_DFS_EXIT_PATH_FOUND";\r
 -    case 0xC000009C: return "STATUS_DEVICE_DATA_ERROR";\r
 -    case 0xC000009D: return "STATUS_DEVICE_NOT_CONNECTED";\r
 -    case 0xC000009E: return "STATUS_DEVICE_POWER_FAILURE";\r
 -    case 0xC000009F: return "STATUS_FREE_VM_NOT_AT_BASE";\r
 -    case 0xC00000A0: return "STATUS_MEMORY_NOT_ALLOCATED";\r
 -    case 0xC00000A1: return "STATUS_WORKING_SET_QUOTA";\r
 -    case 0xC00000A2: return "STATUS_MEDIA_WRITE_PROTECTED";\r
 -    case 0xC00000A3: return "STATUS_DEVICE_NOT_READY";\r
 -    case 0xC00000A4: return "STATUS_INVALID_GROUP_ATTRIBUTES";\r
 -    case 0xC00000A5: return "STATUS_BAD_IMPERSONATION_LEVEL";\r
 -    case 0xC00000A6: return "STATUS_CANT_OPEN_ANONYMOUS";\r
 -    case 0xC00000A7: return "STATUS_BAD_VALIDATION_CLASS";\r
 -    case 0xC00000A8: return "STATUS_BAD_TOKEN_TYPE";\r
 -    case 0xC00000A9: return "STATUS_BAD_MASTER_BOOT_RECORD";\r
 -    case 0xC00000AA: return "STATUS_INSTRUCTION_MISALIGNMENT";\r
 -    case 0xC00000AB: return "STATUS_INSTANCE_NOT_AVAILABLE";\r
 -    case 0xC00000AC: return "STATUS_PIPE_NOT_AVAILABLE";\r
 -    case 0xC00000AD: return "STATUS_INVALID_PIPE_STATE";\r
 -    case 0xC00000AE: return "STATUS_PIPE_BUSY";\r
 -    case 0xC00000AF: return "STATUS_ILLEGAL_FUNCTION";\r
 -    case 0xC00000B0: return "STATUS_PIPE_DISCONNECTED";\r
 -    case 0xC00000B1: return "STATUS_PIPE_CLOSING";\r
 -    case 0xC00000B2: return "STATUS_PIPE_CONNECTED";\r
 -    case 0xC00000B3: return "STATUS_PIPE_LISTENING";\r
 -    case 0xC00000B4: return "STATUS_INVALID_READ_MODE";\r
 -    case 0xC00000B5: return "STATUS_IO_TIMEOUT";\r
 -    case 0xC00000B6: return "STATUS_FILE_FORCED_CLOSED";\r
 -    case 0xC00000B7: return "STATUS_PROFILING_NOT_STARTED";\r
 -    case 0xC00000B8: return "STATUS_PROFILING_NOT_STOPPED";\r
 -    case 0xC00000B9: return "STATUS_COULD_NOT_INTERPRET";\r
 -    case 0xC00000BA: return "STATUS_FILE_IS_A_DIRECTORY";\r
 -    case 0xC00000BB: return "STATUS_NOT_SUPPORTED";\r
 -    case 0xC00000BC: return "STATUS_REMOTE_NOT_LISTENING";\r
 -    case 0xC00000BD: return "STATUS_DUPLICATE_NAME";\r
 -    case 0xC00000BE: return "STATUS_BAD_NETWORK_PATH";\r
 -    case 0xC00000BF: return "STATUS_NETWORK_BUSY";\r
 -    case 0xC00000C0: return "STATUS_DEVICE_DOES_NOT_EXIST";\r
 -    case 0xC00000C1: return "STATUS_TOO_MANY_COMMANDS";\r
 -    case 0xC00000C2: return "STATUS_ADAPTER_HARDWARE_ERROR";\r
 -    case 0xC00000C3: return "STATUS_INVALID_NETWORK_RESPONSE";\r
 -    case 0xC00000C4: return "STATUS_UNEXPECTED_NETWORK_ERROR";\r
 -    case 0xC00000C5: return "STATUS_BAD_REMOTE_ADAPTER";\r
 -    case 0xC00000C6: return "STATUS_PRINT_QUEUE_FULL";\r
 -    case 0xC00000C7: return "STATUS_NO_SPOOL_SPACE";\r
 -    case 0xC00000C8: return "STATUS_PRINT_CANCELLED";\r
 -    case 0xC00000C9: return "STATUS_NETWORK_NAME_DELETED";\r
 -    case 0xC00000CA: return "STATUS_NETWORK_ACCESS_DENIED";\r
 -    case 0xC00000CB: return "STATUS_BAD_DEVICE_TYPE";\r
 -    case 0xC00000CC: return "STATUS_BAD_NETWORK_NAME";\r
 -    case 0xC00000CD: return "STATUS_TOO_MANY_NAMES";\r
 -    case 0xC00000CE: return "STATUS_TOO_MANY_SESSIONS";\r
 -    case 0xC00000CF: return "STATUS_SHARING_PAUSED";\r
 -    case 0xC00000D0: return "STATUS_REQUEST_NOT_ACCEPTED";\r
 -    case 0xC00000D1: return "STATUS_REDIRECTOR_PAUSED";\r
 -    case 0xC00000D2: return "STATUS_NET_WRITE_FAULT";\r
 -    case 0xC00000D3: return "STATUS_PROFILING_AT_LIMIT";\r
 -    case 0xC00000D4: return "STATUS_NOT_SAME_DEVICE";\r
 -    case 0xC00000D5: return "STATUS_FILE_RENAMED";\r
 -    case 0xC00000D6: return "STATUS_VIRTUAL_CIRCUIT_CLOSED";\r
 -    case 0xC00000D7: return "STATUS_NO_SECURITY_ON_OBJECT";\r
 -    case 0xC00000D8: return "STATUS_CANT_WAIT";\r
 -    case 0xC00000D9: return "STATUS_PIPE_EMPTY";\r
 -    case 0xC00000DA: return "STATUS_CANT_ACCESS_DOMAIN_INFO";\r
 -    case 0xC00000DB: return "STATUS_CANT_TERMINATE_SELF";\r
 -    case 0xC00000DC: return "STATUS_INVALID_SERVER_STATE";\r
 -    case 0xC00000DD: return "STATUS_INVALID_DOMAIN_STATE";\r
 -    case 0xC00000DE: return "STATUS_INVALID_DOMAIN_ROLE";\r
 -    case 0xC00000DF: return "STATUS_NO_SUCH_DOMAIN";\r
 -    case 0xC00000E0: return "STATUS_DOMAIN_EXISTS";\r
 -    case 0xC00000E1: return "STATUS_DOMAIN_LIMIT_EXCEEDED";\r
 -    case 0xC00000E2: return "STATUS_OPLOCK_NOT_GRANTED";\r
 -    case 0xC00000E3: return "STATUS_INVALID_OPLOCK_PROTOCOL";\r
 -    case 0xC00000E4: return "STATUS_INTERNAL_DB_CORRUPTION";\r
 -    case 0xC00000E5: return "STATUS_INTERNAL_ERROR";\r
 -    case 0xC00000E6: return "STATUS_GENERIC_NOT_MAPPED";\r
 -    case 0xC00000E7: return "STATUS_BAD_DESCRIPTOR_FORMAT";\r
 -    case 0xC00000E8: return "STATUS_INVALID_USER_BUFFER";\r
 -    case 0xC00000E9: return "STATUS_UNEXPECTED_IO_ERROR";\r
 -    case 0xC00000EA: return "STATUS_UNEXPECTED_MM_CREATE_ERR";\r
 -    case 0xC00000EB: return "STATUS_UNEXPECTED_MM_MAP_ERROR";\r
 -    case 0xC00000EC: return "STATUS_UNEXPECTED_MM_EXTEND_ERR";\r
 -    case 0xC00000ED: return "STATUS_NOT_LOGON_PROCESS";\r
 -    case 0xC00000EE: return "STATUS_LOGON_SESSION_EXISTS";\r
 -    case 0xC00000EF: return "STATUS_INVALID_PARAMETER_1";\r
 -    case 0xC00000F0: return "STATUS_INVALID_PARAMETER_2";\r
 -    case 0xC00000F1: return "STATUS_INVALID_PARAMETER_3";\r
 -    case 0xC00000F2: return "STATUS_INVALID_PARAMETER_4";\r
 -    case 0xC00000F3: return "STATUS_INVALID_PARAMETER_5";\r
 -    case 0xC00000F4: return "STATUS_INVALID_PARAMETER_6";\r
 -    case 0xC00000F5: return "STATUS_INVALID_PARAMETER_7";\r
 -    case 0xC00000F6: return "STATUS_INVALID_PARAMETER_8";\r
 -    case 0xC00000F7: return "STATUS_INVALID_PARAMETER_9";\r
 -    case 0xC00000F8: return "STATUS_INVALID_PARAMETER_10";\r
 -    case 0xC00000F9: return "STATUS_INVALID_PARAMETER_11";\r
 -    case 0xC00000FA: return "STATUS_INVALID_PARAMETER_12";\r
 -    case 0xC00000FB: return "STATUS_REDIRECTOR_NOT_STARTED";\r
 -    case 0xC00000FC: return "STATUS_REDIRECTOR_STARTED";\r
 -    case 0xC00000FD: return "STATUS_STACK_OVERFLOW";\r
 -    case 0xC00000FE: return "STATUS_NO_SUCH_PACKAGE";\r
 -    case 0xC00000FF: return "STATUS_BAD_FUNCTION_TABLE";\r
 -    case 0xC0000100: return "STATUS_VARIABLE_NOT_FOUND";\r
 -    case 0xC0000101: return "STATUS_DIRECTORY_NOT_EMPTY";\r
 -    case 0xC0000102: return "STATUS_FILE_CORRUPT_ERROR";\r
 -    case 0xC0000103: return "STATUS_NOT_A_DIRECTORY";\r
 -    case 0xC0000104: return "STATUS_BAD_LOGON_SESSION_STATE";\r
 -    case 0xC0000105: return "STATUS_LOGON_SESSION_COLLISION";\r
 -    case 0xC0000106: return "STATUS_NAME_TOO_LONG";\r
 -    case 0xC0000107: return "STATUS_FILES_OPEN";\r
 -    case 0xC0000108: return "STATUS_CONNECTION_IN_USE";\r
 -    case 0xC0000109: return "STATUS_MESSAGE_NOT_FOUND";\r
 -    case 0xC000010A: return "STATUS_PROCESS_IS_TERMINATING";\r
 -    case 0xC000010B: return "STATUS_INVALID_LOGON_TYPE";\r
 -    case 0xC000010C: return "STATUS_NO_GUID_TRANSLATION";\r
 -    case 0xC000010D: return "STATUS_CANNOT_IMPERSONATE";\r
 -    case 0xC000010E: return "STATUS_IMAGE_ALREADY_LOADED";\r
 -    case 0xC000010F: return "STATUS_ABIOS_NOT_PRESENT";\r
 -    case 0xC0000110: return "STATUS_ABIOS_LID_NOT_EXIST";\r
 -    case 0xC0000111: return "STATUS_ABIOS_LID_ALREADY_OWNED";\r
 -    case 0xC0000112: return "STATUS_ABIOS_NOT_LID_OWNER";\r
 -    case 0xC0000113: return "STATUS_ABIOS_INVALID_COMMAND";\r
 -    case 0xC0000114: return "STATUS_ABIOS_INVALID_LID";\r
 -    case 0xC0000115: return "STATUS_ABIOS_SELECTOR_NOT_AVAILABLE";\r
 -    case 0xC0000116: return "STATUS_ABIOS_INVALID_SELECTOR";\r
 -    case 0xC0000117: return "STATUS_NO_LDT";\r
 -    case 0xC0000118: return "STATUS_INVALID_LDT_SIZE";\r
 -    case 0xC0000119: return "STATUS_INVALID_LDT_OFFSET";\r
 -    case 0xC000011A: return "STATUS_INVALID_LDT_DESCRIPTOR";\r
 -    case 0xC000011B: return "STATUS_INVALID_IMAGE_NE_FORMAT";\r
 -    case 0xC000011C: return "STATUS_RXACT_INVALID_STATE";\r
 -    case 0xC000011D: return "STATUS_RXACT_COMMIT_FAILURE";\r
 -    case 0xC000011E: return "STATUS_MAPPED_FILE_SIZE_ZERO";\r
 -    case 0xC000011F: return "STATUS_TOO_MANY_OPENED_FILES";\r
 -    case 0xC0000120: return "STATUS_CANCELLED";\r
 -    case 0xC0000121: return "STATUS_CANNOT_DELETE";\r
 -    case 0xC0000122: return "STATUS_INVALID_COMPUTER_NAME";\r
 -    case 0xC0000123: return "STATUS_FILE_DELETED";\r
 -    case 0xC0000124: return "STATUS_SPECIAL_ACCOUNT";\r
 -    case 0xC0000125: return "STATUS_SPECIAL_GROUP";\r
 -    case 0xC0000126: return "STATUS_SPECIAL_USER";\r
 -    case 0xC0000127: return "STATUS_MEMBERS_PRIMARY_GROUP";\r
 -    case 0xC0000128: return "STATUS_FILE_CLOSED";\r
 -    case 0xC0000129: return "STATUS_TOO_MANY_THREADS";\r
 -    case 0xC000012A: return "STATUS_THREAD_NOT_IN_PROCESS";\r
 -    case 0xC000012B: return "STATUS_TOKEN_ALREADY_IN_USE";\r
 -    case 0xC000012C: return "STATUS_PAGEFILE_QUOTA_EXCEEDED";\r
 -    case 0xC000012D: return "STATUS_COMMITMENT_LIMIT";\r
 -    case 0xC000012E: return "STATUS_INVALID_IMAGE_LE_FORMAT";\r
 -    case 0xC000012F: return "STATUS_INVALID_IMAGE_NOT_MZ";\r
 -    case 0xC0000130: return "STATUS_INVALID_IMAGE_PROTECT";\r
 -    case 0xC0000131: return "STATUS_INVALID_IMAGE_WIN_16";\r
 -    case 0xC0000132: return "STATUS_LOGON_SERVER_CONFLICT";\r
 -    case 0xC0000133: return "STATUS_TIME_DIFFERENCE_AT_DC";\r
 -    case 0xC0000134: return "STATUS_SYNCHRONIZATION_REQUIRED";\r
 -    case 0xC0000135: return "STATUS_DLL_NOT_FOUND";\r
 -    case 0xC0000136: return "STATUS_OPEN_FAILED";\r
 -    case 0xC0000137: return "STATUS_IO_PRIVILEGE_FAILED";\r
 -    case 0xC0000138: return "STATUS_ORDINAL_NOT_FOUND";\r
 -    case 0xC0000139: return "STATUS_ENTRYPOINT_NOT_FOUND";\r
 -    case 0xC000013A: return "STATUS_CONTROL_C_EXIT";\r
 -    case 0xC000013B: return "STATUS_LOCAL_DISCONNECT";\r
 -    case 0xC000013C: return "STATUS_REMOTE_DISCONNECT";\r
 -    case 0xC000013D: return "STATUS_REMOTE_RESOURCES";\r
 -    case 0xC000013E: return "STATUS_LINK_FAILED";\r
 -    case 0xC000013F: return "STATUS_LINK_TIMEOUT";\r
 -    case 0xC0000140: return "STATUS_INVALID_CONNECTION";\r
 -    case 0xC0000141: return "STATUS_INVALID_ADDRESS";\r
 -    case 0xC0000142: return "STATUS_DLL_INIT_FAILED";\r
 -    case 0xC0000143: return "STATUS_MISSING_SYSTEMFILE";\r
 -    case 0xC0000144: return "STATUS_UNHANDLED_EXCEPTION";\r
 -    case 0xC0000145: return "STATUS_APP_INIT_FAILURE";\r
 -    case 0xC0000146: return "STATUS_PAGEFILE_CREATE_FAILED";\r
 -    case 0xC0000147: return "STATUS_NO_PAGEFILE";\r
 -    case 0xC0000148: return "STATUS_INVALID_LEVEL";\r
 -    case 0xC0000149: return "STATUS_WRONG_PASSWORD_CORE";\r
 -    case 0xC000014A: return "STATUS_ILLEGAL_FLOAT_CONTEXT";\r
 -    case 0xC000014B: return "STATUS_PIPE_BROKEN";\r
 -    case 0xC000014C: return "STATUS_REGISTRY_CORRUPT";\r
 -    case 0xC000014D: return "STATUS_REGISTRY_IO_FAILED";\r
 -    case 0xC000014E: return "STATUS_NO_EVENT_PAIR";\r
 -    case 0xC000014F: return "STATUS_UNRECOGNIZED_VOLUME";\r
 -    case 0xC0000150: return "STATUS_SERIAL_NO_DEVICE_INITED";\r
 -    case 0xC0000151: return "STATUS_NO_SUCH_ALIAS";\r
 -    case 0xC0000152: return "STATUS_MEMBER_NOT_IN_ALIAS";\r
 -    case 0xC0000153: return "STATUS_MEMBER_IN_ALIAS";\r
 -    case 0xC0000154: return "STATUS_ALIAS_EXISTS";\r
 -    case 0xC0000155: return "STATUS_LOGON_NOT_GRANTED";\r
 -    case 0xC0000156: return "STATUS_TOO_MANY_SECRETS";\r
 -    case 0xC0000157: return "STATUS_SECRET_TOO_LONG";\r
 -    case 0xC0000158: return "STATUS_INTERNAL_DB_ERROR";\r
 -    case 0xC0000159: return "STATUS_FULLSCREEN_MODE";\r
 -    case 0xC000015A: return "STATUS_TOO_MANY_CONTEXT_IDS";\r
 -    case 0xC000015B: return "STATUS_LOGON_TYPE_NOT_GRANTED";\r
 -    case 0xC000015C: return "STATUS_NOT_REGISTRY_FILE";\r
 -    case 0xC000015D: return "STATUS_NT_CROSS_ENCRYPTION_REQUIRED";\r
 -    case 0xC000015E: return "STATUS_DOMAIN_CTRLR_CONFIG_ERROR";\r
 -    case 0xC000015F: return "STATUS_FT_MISSING_MEMBER";\r
 -    case 0xC0000160: return "STATUS_ILL_FORMED_SERVICE_ENTRY";\r
 -    case 0xC0000161: return "STATUS_ILLEGAL_CHARACTER";\r
 -    case 0xC0000162: return "STATUS_UNMAPPABLE_CHARACTER";\r
 -    case 0xC0000163: return "STATUS_UNDEFINED_CHARACTER";\r
 -    case 0xC0000164: return "STATUS_FLOPPY_VOLUME";\r
 -    case 0xC0000165: return "STATUS_FLOPPY_ID_MARK_NOT_FOUND";\r
 -    case 0xC0000166: return "STATUS_FLOPPY_WRONG_CYLINDER";\r
 -    case 0xC0000167: return "STATUS_FLOPPY_UNKNOWN_ERROR";\r
 -    case 0xC0000168: return "STATUS_FLOPPY_BAD_REGISTERS";\r
 -    case 0xC0000169: return "STATUS_DISK_RECALIBRATE_FAILED";\r
 -    case 0xC000016A: return "STATUS_DISK_OPERATION_FAILED";\r
 -    case 0xC000016B: return "STATUS_DISK_RESET_FAILED";\r
 -    case 0xC000016C: return "STATUS_SHARED_IRQ_BUSY";\r
 -    case 0xC000016D: return "STATUS_FT_ORPHANING";\r
 -    case 0xC000016E: return "STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT";\r
 -    case 0xC0000172: return "STATUS_PARTITION_FAILURE";\r
 -    case 0xC0000173: return "STATUS_INVALID_BLOCK_LENGTH";\r
 -    case 0xC0000174: return "STATUS_DEVICE_NOT_PARTITIONED";\r
 -    case 0xC0000175: return "STATUS_UNABLE_TO_LOCK_MEDIA";\r
 -    case 0xC0000176: return "STATUS_UNABLE_TO_UNLOAD_MEDIA";\r
 -    case 0xC0000177: return "STATUS_EOM_OVERFLOW";\r
 -    case 0xC0000178: return "STATUS_NO_MEDIA";\r
 -    case 0xC000017A: return "STATUS_NO_SUCH_MEMBER";\r
 -    case 0xC000017B: return "STATUS_INVALID_MEMBER";\r
 -    case 0xC000017C: return "STATUS_KEY_DELETED";\r
 -    case 0xC000017D: return "STATUS_NO_LOG_SPACE";\r
 -    case 0xC000017E: return "STATUS_TOO_MANY_SIDS";\r
 -    case 0xC000017F: return "STATUS_LM_CROSS_ENCRYPTION_REQUIRED";\r
 -    case 0xC0000180: return "STATUS_KEY_HAS_CHILDREN";\r
 -    case 0xC0000181: return "STATUS_CHILD_MUST_BE_VOLATILE";\r
 -    case 0xC0000182: return "STATUS_DEVICE_CONFIGURATION_ERROR";\r
 -    case 0xC0000183: return "STATUS_DRIVER_INTERNAL_ERROR";\r
 -    case 0xC0000184: return "STATUS_INVALID_DEVICE_STATE";\r
 -    case 0xC0000185: return "STATUS_IO_DEVICE_ERROR";\r
 -    case 0xC0000186: return "STATUS_DEVICE_PROTOCOL_ERROR";\r
 -    case 0xC0000187: return "STATUS_BACKUP_CONTROLLER";\r
 -    case 0xC0000188: return "STATUS_LOG_FILE_FULL";\r
 -    case 0xC0000189: return "STATUS_TOO_LATE";\r
 -    case 0xC000018A: return "STATUS_NO_TRUST_LSA_SECRET";\r
 -    case 0xC000018B: return "STATUS_NO_TRUST_SAM_ACCOUNT";\r
 -    case 0xC000018C: return "STATUS_TRUSTED_DOMAIN_FAILURE";\r
 -    case 0xC000018D: return "STATUS_TRUSTED_RELATIONSHIP_FAILURE";\r
 -    case 0xC000018E: return "STATUS_EVENTLOG_FILE_CORRUPT";\r
 -    case 0xC000018F: return "STATUS_EVENTLOG_CANT_START";\r
 -    case 0xC0000190: return "STATUS_TRUST_FAILURE";\r
 -    case 0xC0000191: return "STATUS_MUTANT_LIMIT_EXCEEDED";\r
 -    case 0xC0000192: return "STATUS_NETLOGON_NOT_STARTED";\r
 -    case 0xC0000193: return "STATUS_ACCOUNT_EXPIRED";\r
 -    case 0xC0000194: return "STATUS_POSSIBLE_DEADLOCK";\r
 -    case 0xC0000195: return "STATUS_NETWORK_CREDENTIAL_CONFLICT";\r
 -    case 0xC0000196: return "STATUS_REMOTE_SESSION_LIMIT";\r
 -    case 0xC0000197: return "STATUS_EVENTLOG_FILE_CHANGED";\r
 -    case 0xC0000198: return "STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT";\r
 -    case 0xC0000199: return "STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT";\r
 -    case 0xC000019A: return "STATUS_NOLOGON_SERVER_TRUST_ACCOUNT";\r
 -    case 0xC000019B: return "STATUS_DOMAIN_TRUST_INCONSISTENT";\r
 -    case 0xC000019C: return "STATUS_FS_DRIVER_REQUIRED";\r
 -    case 0xC0000202: return "STATUS_NO_USER_SESSION_KEY";\r
 -    case 0xC0000203: return "STATUS_USER_SESSION_DELETED";\r
 -    case 0xC0000204: return "STATUS_RESOURCE_LANG_NOT_FOUND";\r
 -    case 0xC0000205: return "STATUS_INSUFF_SERVER_RESOURCES";\r
 -    case 0xC0000206: return "STATUS_INVALID_BUFFER_SIZE";\r
 -    case 0xC0000207: return "STATUS_INVALID_ADDRESS_COMPONENT";\r
 -    case 0xC0000208: return "STATUS_INVALID_ADDRESS_WILDCARD";\r
 -    case 0xC0000209: return "STATUS_TOO_MANY_ADDRESSES";\r
 -    case 0xC000020A: return "STATUS_ADDRESS_ALREADY_EXISTS";\r
 -    case 0xC000020B: return "STATUS_ADDRESS_CLOSED";\r
 -    case 0xC000020C: return "STATUS_CONNECTION_DISCONNECTED";\r
 -    case 0xC000020D: return "STATUS_CONNECTION_RESET";\r
 -    case 0xC000020E: return "STATUS_TOO_MANY_NODES";\r
 -    case 0xC000020F: return "STATUS_TRANSACTION_ABORTED";\r
 -    case 0xC0000210: return "STATUS_TRANSACTION_TIMED_OUT";\r
 -    case 0xC0000211: return "STATUS_TRANSACTION_NO_RELEASE";\r
 -    case 0xC0000212: return "STATUS_TRANSACTION_NO_MATCH";\r
 -    case 0xC0000213: return "STATUS_TRANSACTION_RESPONDED";\r
 -    case 0xC0000214: return "STATUS_TRANSACTION_INVALID_ID";\r
 -    case 0xC0000215: return "STATUS_TRANSACTION_INVALID_TYPE";\r
 -    case 0xC0000216: return "STATUS_NOT_SERVER_SESSION";\r
 -    case 0xC0000217: return "STATUS_NOT_CLIENT_SESSION";\r
 -    case 0xC0000218: return "STATUS_CANNOT_LOAD_REGISTRY_FILE";\r
 -    case 0xC0000219: return "STATUS_DEBUG_ATTACH_FAILED";\r
 -    case 0xC000021A: return "STATUS_SYSTEM_PROCESS_TERMINATED";\r
 -    case 0xC000021B: return "STATUS_DATA_NOT_ACCEPTED";\r
 -    case 0xC000021C: return "STATUS_NO_BROWSER_SERVERS_FOUND";\r
 -    case 0xC000021D: return "STATUS_VDM_HARD_ERROR";\r
 -    case 0xC000021E: return "STATUS_DRIVER_CANCEL_TIMEOUT";\r
 -    case 0xC000021F: return "STATUS_REPLY_MESSAGE_MISMATCH";\r
 -    case 0xC0000220: return "STATUS_MAPPED_ALIGNMENT";\r
 -    case 0xC0000221: return "STATUS_IMAGE_CHECKSUM_MISMATCH";\r
 -    case 0xC0000222: return "STATUS_LOST_WRITEBEHIND_DATA";\r
 -    case 0xC0000223: return "STATUS_CLIENT_SERVER_PARAMETERS_INVALID";\r
 -    case 0xC0000224: return "STATUS_PASSWORD_MUST_CHANGE";\r
 -    case 0xC0000225: return "STATUS_NOT_FOUND";\r
 -    case 0xC0000226: return "STATUS_NOT_TINY_STREAM";\r
 -    case 0xC0000227: return "STATUS_RECOVERY_FAILURE";\r
 -    case 0xC0000228: return "STATUS_STACK_OVERFLOW_READ";\r
 -    case 0xC0000229: return "STATUS_FAIL_CHECK";\r
 -    case 0xC000022A: return "STATUS_DUPLICATE_OBJECTID";\r
 -    case 0xC000022B: return "STATUS_OBJECTID_EXISTS";\r
 -    case 0xC000022C: return "STATUS_CONVERT_TO_LARGE";\r
 -    case 0xC000022D: return "STATUS_RETRY";\r
 -    case 0xC000022E: return "STATUS_FOUND_OUT_OF_SCOPE";\r
 -    case 0xC000022F: return "STATUS_ALLOCATE_BUCKET";\r
 -    case 0xC0000230: return "STATUS_PROPSET_NOT_FOUND";\r
 -    case 0xC0000231: return "STATUS_MARSHALL_OVERFLOW";\r
 -    case 0xC0000232: return "STATUS_INVALID_VARIANT";\r
 -    case 0xC0000233: return "STATUS_DOMAIN_CONTROLLER_NOT_FOUND";\r
 -    case 0xC0000234: return "STATUS_ACCOUNT_LOCKED_OUT";\r
 -    case 0xC0000235: return "STATUS_HANDLE_NOT_CLOSABLE";\r
 -    case 0xC0000236: return "STATUS_CONNECTION_REFUSED";\r
 -    case 0xC0000237: return "STATUS_GRACEFUL_DISCONNECT";\r
 -    case 0xC0000238: return "STATUS_ADDRESS_ALREADY_ASSOCIATED";\r
 -    case 0xC0000239: return "STATUS_ADDRESS_NOT_ASSOCIATED";\r
 -    case 0xC000023A: return "STATUS_CONNECTION_INVALID";\r
 -    case 0xC000023B: return "STATUS_CONNECTION_ACTIVE";\r
 -    case 0xC000023C: return "STATUS_NETWORK_UNREACHABLE";\r
 -    case 0xC000023D: return "STATUS_HOST_UNREACHABLE";\r
 -    case 0xC000023E: return "STATUS_PROTOCOL_UNREACHABLE";\r
 -    case 0xC000023F: return "STATUS_PORT_UNREACHABLE";\r
 -    case 0xC0000240: return "STATUS_REQUEST_ABORTED";\r
 -    case 0xC0000241: return "STATUS_CONNECTION_ABORTED";\r
 -    case 0xC0000242: return "STATUS_BAD_COMPRESSION_BUFFER";\r
 -    case 0xC0000243: return "STATUS_USER_MAPPED_FILE";\r
 -    case 0xC0000244: return "STATUS_AUDIT_FAILED";\r
 -    case 0xC0000245: return "STATUS_TIMER_RESOLUTION_NOT_SET";\r
 -    case 0xC0000246: return "STATUS_CONNECTION_COUNT_LIMIT";\r
 -    case 0xC0000247: return "STATUS_LOGIN_TIME_RESTRICTION";\r
 -    case 0xC0000248: return "STATUS_LOGIN_WKSTA_RESTRICTION";\r
 -    case 0xC0000249: return "STATUS_IMAGE_MP_UP_MISMATCH";\r
 -    case 0xC0000250: return "STATUS_INSUFFICIENT_LOGON_INFO";\r
 -    case 0xC0000251: return "STATUS_BAD_DLL_ENTRYPOINT";\r
 -    case 0xC0000252: return "STATUS_BAD_SERVICE_ENTRYPOINT";\r
 -    case 0xC0000253: return "STATUS_LPC_REPLY_LOST";\r
 -    case 0xC0000254: return "STATUS_IP_ADDRESS_CONFLICT1";\r
 -    case 0xC0000255: return "STATUS_IP_ADDRESS_CONFLICT2";\r
 -    case 0xC0000256: return "STATUS_REGISTRY_QUOTA_LIMIT";\r
 -    case 0xC0000257: return "STATUS_PATH_NOT_COVERED";\r
 -    case 0xC0000258: return "STATUS_NO_CALLBACK_ACTIVE";\r
 -    case 0xC0000259: return "STATUS_LICENSE_QUOTA_EXCEEDED";\r
 -    case 0xC000025A: return "STATUS_PWD_TOO_SHORT";\r
 -    case 0xC000025B: return "STATUS_PWD_TOO_RECENT";\r
 -    case 0xC000025C: return "STATUS_PWD_HISTORY_CONFLICT";\r
 -    case 0xC000025E: return "STATUS_PLUGPLAY_NO_DEVICE";\r
 -    case 0xC000025F: return "STATUS_UNSUPPORTED_COMPRESSION";\r
 -    case 0xC0000260: return "STATUS_INVALID_HW_PROFILE";\r
 -    case 0xC0000261: return "STATUS_INVALID_PLUGPLAY_DEVICE_PATH";\r
 -    case 0xC0000262: return "STATUS_DRIVER_ORDINAL_NOT_FOUND";\r
 -    case 0xC0000263: return "STATUS_DRIVER_ENTRYPOINT_NOT_FOUND";\r
 -    case 0xC0000264: return "STATUS_RESOURCE_NOT_OWNED";\r
 -    case 0xC0000265: return "STATUS_TOO_MANY_LINKS";\r
 -    case 0xC0000266: return "STATUS_QUOTA_LIST_INCONSISTENT";\r
 -    case 0xC0000267: return "STATUS_FILE_IS_OFFLINE";\r
 -    case 0xC0000268: return "STATUS_EVALUATION_EXPIRATION";\r
 -    case 0xC0000269: return "STATUS_ILLEGAL_DLL_RELOCATION";\r
 -    case 0xC000026A: return "STATUS_LICENSE_VIOLATION";\r
 -    case 0xC000026B: return "STATUS_DLL_INIT_FAILED_LOGOFF";\r
 -    case 0xC000026C: return "STATUS_DRIVER_UNABLE_TO_LOAD";\r
 -    case 0xC000026D: return "STATUS_DFS_UNAVAILABLE";\r
 -    case 0xC000026E: return "STATUS_VOLUME_DISMOUNTED";\r
 -    case 0xC000026F: return "STATUS_WX86_INTERNAL_ERROR";\r
 -    case 0xC0000270: return "STATUS_WX86_FLOAT_STACK_CHECK";\r
 -    case 0xC0000271: return "STATUS_VALIDATE_CONTINUE";\r
 -    case 0xC0000272: return "STATUS_NO_MATCH";\r
 -    case 0xC0000273: return "STATUS_NO_MORE_MATCHES";\r
 -    case 0xC0000275: return "STATUS_NOT_A_REPARSE_POINT";\r
 -    case 0xC0000276: return "STATUS_IO_REPARSE_TAG_INVALID";\r
 -    case 0xC0000277: return "STATUS_IO_REPARSE_TAG_MISMATCH";\r
 -    case 0xC0000278: return "STATUS_IO_REPARSE_DATA_INVALID";\r
 -    case 0xC0000279: return "STATUS_IO_REPARSE_TAG_NOT_HANDLED";\r
 -    case 0xC0000280: return "STATUS_REPARSE_POINT_NOT_RESOLVED";\r
 -    case 0xC0000281: return "STATUS_DIRECTORY_IS_A_REPARSE_POINT";\r
 -    case 0xC0000282: return "STATUS_RANGE_LIST_CONFLICT";\r
 -    case 0xC0000283: return "STATUS_SOURCE_ELEMENT_EMPTY";\r
 -    case 0xC0000284: return "STATUS_DESTINATION_ELEMENT_FULL";\r
 -    case 0xC0000285: return "STATUS_ILLEGAL_ELEMENT_ADDRESS";\r
 -    case 0xC0000286: return "STATUS_MAGAZINE_NOT_PRESENT";\r
 -    case 0xC0000287: return "STATUS_REINITIALIZATION_NEEDED";\r
 -    case 0x80000288: return "STATUS_DEVICE_REQUIRES_CLEANING";\r
 -    case 0x80000289: return "STATUS_DEVICE_DOOR_OPEN";\r
 -    case 0xC000028A: return "STATUS_ENCRYPTION_FAILED";\r
 -    case 0xC000028B: return "STATUS_DECRYPTION_FAILED";\r
 -    case 0xC000028C: return "STATUS_RANGE_NOT_FOUND";\r
 -    case 0xC000028D: return "STATUS_NO_RECOVERY_POLICY";\r
 -    case 0xC000028E: return "STATUS_NO_EFS";\r
 -    case 0xC000028F: return "STATUS_WRONG_EFS";\r
 -    case 0xC0000290: return "STATUS_NO_USER_KEYS";\r
 -    case 0xC0000291: return "STATUS_FILE_NOT_ENCRYPTED";\r
 -    case 0xC0000292: return "STATUS_NOT_EXPORT_FORMAT";\r
 -    case 0xC0000293: return "STATUS_FILE_ENCRYPTED";\r
 -    case 0x40000294: return "STATUS_WAKE_SYSTEM";\r
 -    case 0xC0000295: return "STATUS_WMI_GUID_NOT_FOUND";\r
 -    case 0xC0000296: return "STATUS_WMI_INSTANCE_NOT_FOUND";\r
 -    case 0xC0000297: return "STATUS_WMI_ITEMID_NOT_FOUND";\r
 -    case 0xC0000298: return "STATUS_WMI_TRY_AGAIN";\r
 -    case 0xC0000299: return "STATUS_SHARED_POLICY";\r
 -    case 0xC000029A: return "STATUS_POLICY_OBJECT_NOT_FOUND";\r
 -    case 0xC000029B: return "STATUS_POLICY_ONLY_IN_DS";\r
 -    case 0xC000029C: return "STATUS_VOLUME_NOT_UPGRADED";\r
 -    case 0xC000029D: return "STATUS_REMOTE_STORAGE_NOT_ACTIVE";\r
 -    case 0xC000029E: return "STATUS_REMOTE_STORAGE_MEDIA_ERROR";\r
 -    case 0xC000029F: return "STATUS_NO_TRACKING_SERVICE";\r
 -    case 0xC00002A0: return "STATUS_SERVER_SID_MISMATCH";\r
 -    case 0xC00002A1: return "STATUS_DS_NO_ATTRIBUTE_OR_VALUE";\r
 -    case 0xC00002A2: return "STATUS_DS_INVALID_ATTRIBUTE_SYNTAX";\r
 -    case 0xC00002A3: return "STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED";\r
 -    case 0xC00002A4: return "STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS";\r
 -    case 0xC00002A5: return "STATUS_DS_BUSY";\r
 -    case 0xC00002A6: return "STATUS_DS_UNAVAILABLE";\r
 -    case 0xC00002A7: return "STATUS_DS_NO_RIDS_ALLOCATED";\r
 -    case 0xC00002A8: return "STATUS_DS_NO_MORE_RIDS";\r
 -    case 0xC00002A9: return "STATUS_DS_INCORRECT_ROLE_OWNER";\r
 -    case 0xC00002AA: return "STATUS_DS_RIDMGR_INIT_ERROR";\r
 -    case 0xC00002AB: return "STATUS_DS_OBJ_CLASS_VIOLATION";\r
 -    case 0xC00002AC: return "STATUS_DS_CANT_ON_NON_LEAF";\r
 -    case 0xC00002AD: return "STATUS_DS_CANT_ON_RDN";\r
 -    case 0xC00002AE: return "STATUS_DS_CANT_MOD_OBJ_CLASS";\r
 -    case 0xC00002AF: return "STATUS_DS_CROSS_DOM_MOVE_FAILED";\r
 -    case 0xC00002B0: return "STATUS_DS_GC_NOT_AVAILABLE";\r
 -    case 0xC00002B1: return "STATUS_DIRECTORY_SERVICE_REQUIRED";\r
 -    case 0xC00002B2: return "STATUS_REPARSE_ATTRIBUTE_CONFLICT";\r
 -    case 0xC00002B3: return "STATUS_CANT_ENABLE_DENY_ONLY";\r
 -    case 0xC00002B4: return "STATUS_FLOAT_MULTIPLE_FAULTS";\r
 -    case 0xC00002B5: return "STATUS_FLOAT_MULTIPLE_TRAPS";\r
 -    case 0xC00002B6: return "STATUS_DEVICE_REMOVED";\r
 -    case 0xC00002B7: return "STATUS_JOURNAL_DELETE_IN_PROGRESS";\r
 -    case 0xC00002B8: return "STATUS_JOURNAL_NOT_ACTIVE";\r
 -    case 0xC00002B9: return "STATUS_NOINTERFACE";\r
 -    case 0xC00002C1: return "STATUS_DS_ADMIN_LIMIT_EXCEEDED";\r
 -    case 0xC00002C2: return "STATUS_DRIVER_FAILED_SLEEP";\r
 -    case 0xC00002C3: return "STATUS_MUTUAL_AUTHENTICATION_FAILED";\r
 -    case 0xC00002C4: return "STATUS_CORRUPT_SYSTEM_FILE";\r
 -    case 0xC00002C5: return "STATUS_DATATYPE_MISALIGNMENT_ERROR";\r
 -    case 0xC00002C6: return "STATUS_WMI_READ_ONLY";\r
 -    case 0xC00002C7: return "STATUS_WMI_SET_FAILURE";\r
 -    case 0xC00002C8: return "STATUS_COMMITMENT_MINIMUM";\r
 -    case 0xC00002C9: return "STATUS_REG_NAT_CONSUMPTION";\r
 -    case 0xC00002CA: return "STATUS_TRANSPORT_FULL";\r
 -    case 0xC00002CB: return "STATUS_DS_SAM_INIT_FAILURE";\r
 -    case 0xC00002CC: return "STATUS_ONLY_IF_CONNECTED";\r
 -    case 0xC00002CD: return "STATUS_DS_SENSITIVE_GROUP_VIOLATION";\r
 -    case 0xC00002CE: return "STATUS_PNP_RESTART_ENUMERATION";\r
 -    case 0xC00002CF: return "STATUS_JOURNAL_ENTRY_DELETED";\r
 -    case 0xC00002D0: return "STATUS_DS_CANT_MOD_PRIMARYGROUPID";\r
 -    case 0xC00002D1: return "STATUS_SYSTEM_IMAGE_BAD_SIGNATURE";\r
 -    case 0xC00002D2: return "STATUS_PNP_REBOOT_REQUIRED";\r
 -    case 0xC00002D3: return "STATUS_POWER_STATE_INVALID";\r
 -    case 0xC00002D4: return "STATUS_DS_INVALID_GROUP_TYPE";\r
 -    case 0xC00002D5: return "STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN";\r
 -    case 0xC00002D6: return "STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN";\r
 -    case 0xC00002D7: return "STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER";\r
 -    case 0xC00002D8: return "STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER";\r
 -    case 0xC00002D9: return "STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER";\r
 -    case 0xC00002DA: return "STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER";\r
 -    case 0xC00002DB: return "STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER";\r
 -    case 0xC00002DC: return "STATUS_DS_HAVE_PRIMARY_MEMBERS";\r
 -    case 0xC00002DD: return "STATUS_WMI_NOT_SUPPORTED";\r
 -    case 0xC00002DE: return "STATUS_INSUFFICIENT_POWER";\r
 -    case 0xC00002DF: return "STATUS_SAM_NEED_BOOTKEY_PASSWORD";\r
 -    case 0xC00002E0: return "STATUS_SAM_NEED_BOOTKEY_FLOPPY";\r
 -    case 0xC00002E1: return "STATUS_DS_CANT_START";\r
 -    case 0xC00002E2: return "STATUS_DS_INIT_FAILURE";\r
 -    case 0xC00002E3: return "STATUS_SAM_INIT_FAILURE";\r
 -    case 0xC00002E4: return "STATUS_DS_GC_REQUIRED";\r
 -    case 0xC00002E5: return "STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY";\r
 -    case 0xC00002E6: return "STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS";\r
 -    case 0xC00002E7: return "STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED";\r
 -    case 0xC00002E8: return "STATUS_MULTIPLE_FAULT_VIOLATION";\r
 -    case 0xC0000300: return "STATUS_NOT_SUPPORTED_ON_SBS";\r
 -    case 0xC0009898: return "STATUS_WOW_ASSERTION";\r
 -    case 0xC0010001: return "DBG_NO_STATE_CHANGE";\r
 -    case 0xC0010002: return "DBG_APP_NOT_IDLE";\r
 -    case 0xC0020001: return "RPC_NT_INVALID_STRING_BINDING";\r
 -    case 0xC0020002: return "RPC_NT_WRONG_KIND_OF_BINDING";\r
 -    case 0xC0020003: return "RPC_NT_INVALID_BINDING";\r
 -    case 0xC0020004: return "RPC_NT_PROTSEQ_NOT_SUPPORTED";\r
 -    case 0xC0020005: return "RPC_NT_INVALID_RPC_PROTSEQ";\r
 -    case 0xC0020006: return "RPC_NT_INVALID_STRING_UUID";\r
 -    case 0xC0020007: return "RPC_NT_INVALID_ENDPOINT_FORMAT";\r
 -    case 0xC0020008: return "RPC_NT_INVALID_NET_ADDR";\r
 -    case 0xC0020009: return "RPC_NT_NO_ENDPOINT_FOUND";\r
 -    case 0xC002000A: return "RPC_NT_INVALID_TIMEOUT";\r
 -    case 0xC002000B: return "RPC_NT_OBJECT_NOT_FOUND";\r
 -    case 0xC002000C: return "RPC_NT_ALREADY_REGISTERED";\r
 -    case 0xC002000D: return "RPC_NT_TYPE_ALREADY_REGISTERED";\r
 -    case 0xC002000E: return "RPC_NT_ALREADY_LISTENING";\r
 -    case 0xC002000F: return "RPC_NT_NO_PROTSEQS_REGISTERED";\r
 -    case 0xC0020010: return "RPC_NT_NOT_LISTENING";\r
 -    case 0xC0020011: return "RPC_NT_UNKNOWN_MGR_TYPE";\r
 -    case 0xC0020012: return "RPC_NT_UNKNOWN_IF";\r
 -    case 0xC0020013: return "RPC_NT_NO_BINDINGS";\r
 -    case 0xC0020014: return "RPC_NT_NO_PROTSEQS";\r
 -    case 0xC0020015: return "RPC_NT_CANT_CREATE_ENDPOINT";\r
 -    case 0xC0020016: return "RPC_NT_OUT_OF_RESOURCES";\r
 -    case 0xC0020017: return "RPC_NT_SERVER_UNAVAILABLE";\r
 -    case 0xC0020018: return "RPC_NT_SERVER_TOO_BUSY";\r
 -    case 0xC0020019: return "RPC_NT_INVALID_NETWORK_OPTIONS";\r
 -    case 0xC002001A: return "RPC_NT_NO_CALL_ACTIVE";\r
 -    case 0xC002001B: return "RPC_NT_CALL_FAILED";\r
 -    case 0xC002001C: return "RPC_NT_CALL_FAILED_DNE";\r
 -    case 0xC002001D: return "RPC_NT_PROTOCOL_ERROR";\r
 -    case 0xC002001F: return "RPC_NT_UNSUPPORTED_TRANS_SYN";\r
 -    case 0xC0020021: return "RPC_NT_UNSUPPORTED_TYPE";\r
 -    case 0xC0020022: return "RPC_NT_INVALID_TAG";\r
 -    case 0xC0020023: return "RPC_NT_INVALID_BOUND";\r
 -    case 0xC0020024: return "RPC_NT_NO_ENTRY_NAME";\r
 -    case 0xC0020025: return "RPC_NT_INVALID_NAME_SYNTAX";\r
 -    case 0xC0020026: return "RPC_NT_UNSUPPORTED_NAME_SYNTAX";\r
 -    case 0xC0020028: return "RPC_NT_UUID_NO_ADDRESS";\r
 -    case 0xC0020029: return "RPC_NT_DUPLICATE_ENDPOINT";\r
 -    case 0xC002002A: return "RPC_NT_UNKNOWN_AUTHN_TYPE";\r
 -    case 0xC002002B: return "RPC_NT_MAX_CALLS_TOO_SMALL";\r
 -    case 0xC002002C: return "RPC_NT_STRING_TOO_LONG";\r
 -    case 0xC002002D: return "RPC_NT_PROTSEQ_NOT_FOUND";\r
 -    case 0xC002002E: return "RPC_NT_PROCNUM_OUT_OF_RANGE";\r
 -    case 0xC002002F: return "RPC_NT_BINDING_HAS_NO_AUTH";\r
 -    case 0xC0020030: return "RPC_NT_UNKNOWN_AUTHN_SERVICE";\r
 -    case 0xC0020031: return "RPC_NT_UNKNOWN_AUTHN_LEVEL";\r
 -    case 0xC0020032: return "RPC_NT_INVALID_AUTH_IDENTITY";\r
 -    case 0xC0020033: return "RPC_NT_UNKNOWN_AUTHZ_SERVICE";\r
 -    case 0xC0020034: return "EPT_NT_INVALID_ENTRY";\r
 -    case 0xC0020035: return "EPT_NT_CANT_PERFORM_OP";\r
 -    case 0xC0020036: return "EPT_NT_NOT_REGISTERED";\r
 -    case 0xC0020037: return "RPC_NT_NOTHING_TO_EXPORT";\r
 -    case 0xC0020038: return "RPC_NT_INCOMPLETE_NAME";\r
 -    case 0xC0020039: return "RPC_NT_INVALID_VERS_OPTION";\r
 -    case 0xC002003A: return "RPC_NT_NO_MORE_MEMBERS";\r
 -    case 0xC002003B: return "RPC_NT_NOT_ALL_OBJS_UNEXPORTED";\r
 -    case 0xC002003C: return "RPC_NT_INTERFACE_NOT_FOUND";\r
 -    case 0xC002003D: return "RPC_NT_ENTRY_ALREADY_EXISTS";\r
 -    case 0xC002003E: return "RPC_NT_ENTRY_NOT_FOUND";\r
 -    case 0xC002003F: return "RPC_NT_NAME_SERVICE_UNAVAILABLE";\r
 -    case 0xC0020040: return "RPC_NT_INVALID_NAF_ID";\r
 -    case 0xC0020041: return "RPC_NT_CANNOT_SUPPORT";\r
 -    case 0xC0020042: return "RPC_NT_NO_CONTEXT_AVAILABLE";\r
 -    case 0xC0020043: return "RPC_NT_INTERNAL_ERROR";\r
 -    case 0xC0020044: return "RPC_NT_ZERO_DIVIDE";\r
 -    case 0xC0020045: return "RPC_NT_ADDRESS_ERROR";\r
 -    case 0xC0020046: return "RPC_NT_FP_DIV_ZERO";\r
 -    case 0xC0020047: return "RPC_NT_FP_UNDERFLOW";\r
 -    case 0xC0020048: return "RPC_NT_FP_OVERFLOW";\r
 -    case 0xC0030001: return "RPC_NT_NO_MORE_ENTRIES";\r
 -    case 0xC0030002: return "RPC_NT_SS_CHAR_TRANS_OPEN_FAIL";\r
 -    case 0xC0030003: return "RPC_NT_SS_CHAR_TRANS_SHORT_FILE";\r
 -    case 0xC0030004: return "RPC_NT_SS_IN_NULL_CONTEXT";\r
 -    case 0xC0030005: return "RPC_NT_SS_CONTEXT_MISMATCH";\r
 -    case 0xC0030006: return "RPC_NT_SS_CONTEXT_DAMAGED";\r
 -    case 0xC0030007: return "RPC_NT_SS_HANDLES_MISMATCH";\r
 -    case 0xC0030008: return "RPC_NT_SS_CANNOT_GET_CALL_HANDLE";\r
 -    case 0xC0030009: return "RPC_NT_NULL_REF_POINTER";\r
 -    case 0xC003000A: return "RPC_NT_ENUM_VALUE_OUT_OF_RANGE";\r
 -    case 0xC003000B: return "RPC_NT_BYTE_COUNT_TOO_SMALL";\r
 -    case 0xC003000C: return "RPC_NT_BAD_STUB_DATA";\r
 -    case 0xC0020049: return "RPC_NT_CALL_IN_PROGRESS";\r
 -    case 0xC002004A: return "RPC_NT_NO_MORE_BINDINGS";\r
 -    case 0xC002004B: return "RPC_NT_GROUP_MEMBER_NOT_FOUND";\r
 -    case 0xC002004C: return "EPT_NT_CANT_CREATE";\r
 -    case 0xC002004D: return "RPC_NT_INVALID_OBJECT";\r
 -    case 0xC002004F: return "RPC_NT_NO_INTERFACES";\r
 -    case 0xC0020050: return "RPC_NT_CALL_CANCELLED";\r
 -    case 0xC0020051: return "RPC_NT_BINDING_INCOMPLETE";\r
 -    case 0xC0020052: return "RPC_NT_COMM_FAILURE";\r
 -    case 0xC0020053: return "RPC_NT_UNSUPPORTED_AUTHN_LEVEL";\r
 -    case 0xC0020054: return "RPC_NT_NO_PRINC_NAME";\r
 -    case 0xC0020055: return "RPC_NT_NOT_RPC_ERROR";\r
 -    case 0x40020056: return "RPC_NT_UUID_LOCAL_ONLY";\r
 -    case 0xC0020057: return "RPC_NT_SEC_PKG_ERROR";\r
 -    case 0xC0020058: return "RPC_NT_NOT_CANCELLED";\r
 -    case 0xC0030059: return "RPC_NT_INVALID_ES_ACTION";\r
 -    case 0xC003005A: return "RPC_NT_WRONG_ES_VERSION";\r
 -    case 0xC003005B: return "RPC_NT_WRONG_STUB_VERSION";\r
 -    case 0xC003005C: return "RPC_NT_INVALID_PIPE_OBJECT";\r
 -    case 0xC003005D: return "RPC_NT_INVALID_PIPE_OPERATION";\r
 -    case 0xC003005E: return "RPC_NT_WRONG_PIPE_VERSION";\r
 -    case 0xC003005F: return "RPC_NT_PIPE_CLOSED";\r
 -    case 0xC0030060: return "RPC_NT_PIPE_DISCIPLINE_ERROR";\r
 -    case 0xC0030061: return "RPC_NT_PIPE_EMPTY";\r
 -    case 0xC0020062: return "RPC_NT_INVALID_ASYNC_HANDLE";\r
 -    case 0xC0020063: return "RPC_NT_INVALID_ASYNC_CALL";\r
 -    case 0x400200AF: return "RPC_NT_SEND_INCOMPLETE";\r
 -    case 0xC0140001: return "STATUS_ACPI_INVALID_OPCODE";\r
 -    case 0xC0140002: return "STATUS_ACPI_STACK_OVERFLOW";\r
 -    case 0xC0140003: return "STATUS_ACPI_ASSERT_FAILED";\r
 -    case 0xC0140004: return "STATUS_ACPI_INVALID_INDEX";\r
 -    case 0xC0140005: return "STATUS_ACPI_INVALID_ARGUMENT";\r
 -    case 0xC0140006: return "STATUS_ACPI_FATAL";\r
 -    case 0xC0140007: return "STATUS_ACPI_INVALID_SUPERNAME";\r
 -    case 0xC0140008: return "STATUS_ACPI_INVALID_ARGTYPE";\r
 -    case 0xC0140009: return "STATUS_ACPI_INVALID_OBJTYPE";\r
 -    case 0xC014000A: return "STATUS_ACPI_INVALID_TARGETTYPE";\r
 -    case 0xC014000B: return "STATUS_ACPI_INCORRECT_ARGUMENT_COUNT";\r
 -    case 0xC014000C: return "STATUS_ACPI_ADDRESS_NOT_MAPPED";\r
 -    case 0xC014000D: return "STATUS_ACPI_INVALID_EVENTTYPE";\r
 -    case 0xC014000E: return "STATUS_ACPI_HANDLER_COLLISION";\r
 -    case 0xC014000F: return "STATUS_ACPI_INVALID_DATA";\r
 -    case 0xC0140010: return "STATUS_ACPI_INVALID_REGION";\r
 -    case 0xC0140011: return "STATUS_ACPI_INVALID_ACCESS_SIZE";\r
 -    case 0xC0140012: return "STATUS_ACPI_ACQUIRE_GLOBAL_LOCK";\r
 -    case 0xC0140013: return "STATUS_ACPI_ALREADY_INITIALIZED";\r
 -    case 0xC0140014: return "STATUS_ACPI_NOT_INITIALIZED";\r
 -    case 0xC0140015: return "STATUS_ACPI_INVALID_MUTEX_LEVEL";\r
 -    case 0xC0140016: return "STATUS_ACPI_MUTEX_NOT_OWNED";\r
 -    case 0xC0140017: return "STATUS_ACPI_MUTEX_NOT_OWNER";\r
 -    case 0xC0140018: return "STATUS_ACPI_RS_ACCESS";\r
 -    case 0xC0140019: return "STATUS_ACPI_INVALID_TABLE";\r
 -    case 0xC0140020: return "STATUS_ACPI_REG_HANDLER_FAILED";\r
 -    case 0xC0140021: return "STATUS_ACPI_POWER_REQUEST_FAILED";\r
 -    case 0xC00A0001: return "STATUS_CTX_WINSTATION_NAME_INVALID";\r
 -    case 0xC00A0002: return "STATUS_CTX_INVALID_PD";\r
 -    case 0xC00A0003: return "STATUS_CTX_PD_NOT_FOUND";\r
 -    case 0x400A0004: return "STATUS_CTX_CDM_CONNECT";\r
 -    case 0x400A0005: return "STATUS_CTX_CDM_DISCONNECT";\r
 -    case 0xC00A0006: return "STATUS_CTX_CLOSE_PENDING";\r
 -    case 0xC00A0007: return "STATUS_CTX_NO_OUTBUF";\r
 -    case 0xC00A0008: return "STATUS_CTX_MODEM_INF_NOT_FOUND";\r
 -    case 0xC00A0009: return "STATUS_CTX_INVALID_MODEMNAME";\r
 -    case 0xC00A000A: return "STATUS_CTX_RESPONSE_ERROR";\r
 -    case 0xC00A000B: return "STATUS_CTX_MODEM_RESPONSE_TIMEOUT";\r
 -    case 0xC00A000C: return "STATUS_CTX_MODEM_RESPONSE_NO_CARRIER";\r
 -    case 0xC00A000D: return "STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE";\r
 -    case 0xC00A000E: return "STATUS_CTX_MODEM_RESPONSE_BUSY";\r
 -    case 0xC00A000F: return "STATUS_CTX_MODEM_RESPONSE_VOICE";\r
 -    case 0xC00A0010: return "STATUS_CTX_TD_ERROR";\r
 -    case 0xC00A0012: return "STATUS_CTX_LICENSE_CLIENT_INVALID";\r
 -    case 0xC00A0013: return "STATUS_CTX_LICENSE_NOT_AVAILABLE";\r
 -    case 0xC00A0014: return "STATUS_CTX_LICENSE_EXPIRED";\r
 -    case 0xC00A0015: return "STATUS_CTX_WINSTATION_NOT_FOUND";\r
 -    case 0xC00A0016: return "STATUS_CTX_WINSTATION_NAME_COLLISION";\r
 -    case 0xC00A0017: return "STATUS_CTX_WINSTATION_BUSY";\r
 -    case 0xC00A0018: return "STATUS_CTX_BAD_VIDEO_MODE";\r
 -    case 0xC00A0022: return "STATUS_CTX_GRAPHICS_INVALID";\r
 -    case 0xC00A0024: return "STATUS_CTX_NOT_CONSOLE";\r
 -    case 0xC00A0026: return "STATUS_CTX_CLIENT_QUERY_TIMEOUT";\r
 -    case 0xC00A0027: return "STATUS_CTX_CONSOLE_DISCONNECT";\r
 -    case 0xC00A0028: return "STATUS_CTX_CONSOLE_CONNECT";\r
 -    case 0xC00A002A: return "STATUS_CTX_SHADOW_DENIED";\r
 -    case 0xC00A002B: return "STATUS_CTX_WINSTATION_ACCESS_DENIED";\r
 -    case 0xC00A002E: return "STATUS_CTX_INVALID_WD";\r
 -    case 0xC00A002F: return "STATUS_CTX_WD_NOT_FOUND";\r
 -    case 0xC00A0030: return "STATUS_CTX_SHADOW_INVALID";\r
 -    case 0xC00A0031: return "STATUS_CTX_SHADOW_DISABLED";\r
 -    case 0xC00A0032: return "STATUS_RDP_PROTOCOL_ERROR";\r
 -    case 0xC00A0033: return "STATUS_CTX_CLIENT_LICENSE_NOT_SET";\r
 -    case 0xC00A0034: return "STATUS_CTX_CLIENT_LICENSE_IN_USE";\r
 -    case 0xC0040035: return "STATUS_PNP_BAD_MPS_TABLE";\r
 -    case 0xC0040036: return "STATUS_PNP_TRANSLATION_FAILED";\r
 -    case 0xC0040037: return "STATUS_PNP_IRQ_TRANSLATION_FAILED";\r
 -    default:         return "STATUS_UNKNOWN";\r
 -    }\r
 -}\r
 -\r
 -/*\r
 - * Ext2ReadDisk\r
 - *     Read data from disk ...\r
 - *\r
 - * ARGUMENTS:\r
 - *     VolumeHandle: Volume Handle\r
 - *     Offset      : Disk Offset\r
 - *     Length      : Data Length to be read\r
 - *     Buffer      : ...\r
 - *\r
 - * RETURNS: \r
 - *     Success: STATUS_SUCCESS\r
 - *     Fail:  ...\r
 - *\r
 - * NOTES: \r
 - *     Both Length and Offset should be SECTOR_SIZE aligned.\r
 - */\r
 -NTSTATUS \r
 -Ext2ReadDisk( PEXT2_FILESYS  Ext2Sys,\r
 -              ULONGLONG      Offset,\r
 -              ULONG          Length,\r
 -              PVOID          Buffer     )\r
 -{\r
 -    LARGE_INTEGER   Address;\r
 -    NTSTATUS        Status;\r
 -    ULONG           AlignedLength;\r
 -\r
 -    IO_STATUS_BLOCK IoStatus;\r
 -\r
 -    PVOID           NonPagedBuffer = NULL;\r
 -\r
 -    ASSERT(Buffer != NULL);\r
 -\r
 -#if 0\r
 -    if (Ext2Sys->bFile)\r
 -    {\r
 -        Address.QuadPart = Offset;\r
 -\r
 -        Status = NtReadFile(  Ext2Sys->MediaHandle,\r
 -                              0,\r
 -                              NULL,\r
 -                              NULL,\r
 -                              &IoStatus,\r
 -                              Buffer,\r
 -                              Length,\r
 -                              &Address,\r
 -                              NULL );\r
 -    }\r
 -    else\r
 -#endif\r
 -    {\r
 -        Address.QuadPart = Offset & (~((ULONGLONG)SECTOR_SIZE - 1));\r
 -\r
 -        AlignedLength = (Length + SECTOR_SIZE - 1)&(~(SECTOR_SIZE - 1));\r
 -\r
 -        AlignedLength += ((ULONG)(Offset - Address.QuadPart) + SECTOR_SIZE - 1)\r
 -                         & (~(SECTOR_SIZE - 1));\r
 -\r
 -        NonPagedBuffer = RtlAllocateHeap(GetProcessHeap(), 0, AlignedLength);\r
 -        if (!NonPagedBuffer)\r
 -        {\r
 -            Status = STATUS_INSUFFICIENT_RESOURCES;\r
 -            goto errorout;\r
 -        }\r
 -\r
 -        Status = NtReadFile( Ext2Sys->MediaHandle,\r
 -                             0,\r
 -                             NULL,\r
 -                             NULL,\r
 -                             &IoStatus,\r
 -                             NonPagedBuffer,\r
 -                             AlignedLength,\r
 -                             &Address,\r
 -                             NULL );\r
 -\r
 -        if (!NT_SUCCESS(Status))\r
 -        {\r
 -            goto errorout;\r
 -        }\r
 -\r
 -        RtlCopyMemory( Buffer, \r
 -                       (PUCHAR)NonPagedBuffer + (ULONG)(Offset - Address.QuadPart),\r
 -                       Length );\r
 -    }\r
 - \r
 -errorout:\r
 -\r
 -    if (NonPagedBuffer)\r
 -        RtlFreeHeap(GetProcessHeap(), 0, NonPagedBuffer);\r
 -\r
 -    return Status;\r
 -}\r
 -\r
 -\r
 -/*\r
 - * Ext2WriteDisk\r
 - *     Write data to disk ...\r
 - *\r
 - * ARGUMENTS:\r
 - *     VolumeHandle: Volume Handle\r
 - *     Offset      : Disk Offset\r
 - *     Length      : Data Length to be written\r
 - *     Buffer      : Data to be written ...\r
 - *\r
 - * RETURNS: \r
 - *     Success: STATUS_SUCCESS\r
 - *     Fail:  ...\r
 - *\r
 - * NOTES: \r
 - *     Both Length and Offset should be SECTOR_SIZE aligned.\r
 - */\r
 -\r
 -NTSTATUS\r
 -Ext2WriteDisk( PEXT2_FILESYS  Ext2Sys,\r
 -               ULONGLONG      Offset,\r
 -               ULONG          Length,\r
 -               PVOID          Buffer )\r
 -{\r
 -    LARGE_INTEGER   Address;\r
 -    NTSTATUS        Status;\r
 -    ULONG           AlignedLength;\r
 -\r
 -    IO_STATUS_BLOCK IoStatus;\r
 -\r
 -    PVOID           NonPagedBuffer = NULL;\r
 -\r
 -    ASSERT(Buffer != NULL);\r
 -\r
 -#if 0\r
 -    if (Ext2Sys->bFile)\r
 -    {\r
 -        Address.QuadPart = Offset;\r
 -\r
 -        Status = NtWriteFile( Ext2Sys->MediaHandle,\r
 -                              0,\r
 -                              NULL,\r
 -                              NULL,\r
 -                              &IoStatus,\r
 -                              Buffer,\r
 -                              Length,\r
 -                              &Address,\r
 -                              NULL );\r
 -    }\r
 -    else\r
 -#endif\r
 -    {\r
 -        Address.QuadPart = Offset & (~((ULONGLONG)SECTOR_SIZE - 1));\r
 -\r
 -        AlignedLength = (Length + SECTOR_SIZE - 1)&(~(SECTOR_SIZE - 1));\r
 -\r
 -        AlignedLength += ((ULONG)(Offset - Address.QuadPart) + SECTOR_SIZE - 1)\r
 -                         & (~(SECTOR_SIZE - 1));\r
 -\r
 -        NonPagedBuffer = RtlAllocateHeap(GetProcessHeap(), 0, AlignedLength);\r
 -        if (!NonPagedBuffer)\r
 -        {\r
 -            Status = STATUS_INSUFFICIENT_RESOURCES;\r
 -            goto errorout;\r
 -        }\r
 -\r
 -        if ((AlignedLength != Length) || (Address.QuadPart != (LONGLONG)Offset))\r
 -        {\r
 -            Status = NtReadFile( Ext2Sys->MediaHandle,\r
 -                                 0,\r
 -                                 NULL,\r
 -                                 NULL,\r
 -                                 &IoStatus,\r
 -                                 NonPagedBuffer,\r
 -                                 AlignedLength,\r
 -                                 &Address,\r
 -                                 NULL );\r
 -\r
 -            if (!NT_SUCCESS(Status))\r
 -            {\r
 -                goto errorout;\r
 -            }\r
 -        }\r
 -\r
 -        RtlCopyMemory( (PUCHAR)NonPagedBuffer + (ULONG)(Offset - Address.QuadPart),\r
 -                       Buffer, Length );\r
 -\r
 -        Status = NtWriteFile( Ext2Sys->MediaHandle,\r
 -                              0,\r
 -                              NULL,\r
 -                              NULL,\r
 -                              &IoStatus,\r
 -                              NonPagedBuffer,\r
 -                              AlignedLength,\r
 -                              &Address,\r
 -                              NULL );\r
 -    }\r
 -\r
 -errorout:\r
 -\r
 -    if (NonPagedBuffer)\r
 -        RtlFreeHeap(GetProcessHeap(), 0, NonPagedBuffer);\r
 -\r
 -    return Status;\r
 -}\r
 -\r
 -\r
 -/*\r
 - * Ext2GetMediaInfo\r
 - *     Get volume gemmetry information ...\r
 - *\r
 - * ARGUMENTS:\r
 - *     VolumeHandle:    Volume handle.\r
 - *\r
 - * RETURNS: \r
 - *     Success or Fail\r
 - *\r
 - * NOTES: \r
 - *     N/A\r
 - */\r
 -\r
 -NTSTATUS\r
 -Ext2GetMediaInfo( PEXT2_FILESYS Ext2Sys )\r
 -{\r
 -    NTSTATUS Status;\r
 -    IO_STATUS_BLOCK IoSb;\r
 -\r
 -    Status = NtDeviceIoControlFile( Ext2Sys->MediaHandle,\r
 -                                NULL, NULL, NULL, &IoSb,\r
 -                                IOCTL_DISK_GET_DRIVE_GEOMETRY,\r
 -                                &(Ext2Sys->DiskGeometry), sizeof(DISK_GEOMETRY),\r
 -                                &(Ext2Sys->DiskGeometry), sizeof(DISK_GEOMETRY));\r
 -\r
 -\r
 -    if (!NT_SUCCESS(Status))\r
 -    {\r
 -        goto errorout;\r
 -    }\r
 -\r
 -    Status = NtDeviceIoControlFile( Ext2Sys->MediaHandle,\r
 -                                NULL, NULL, NULL, &IoSb,\r
 -                                IOCTL_DISK_GET_PARTITION_INFO,\r
 -                                &(Ext2Sys->PartInfo), sizeof(PARTITION_INFORMATION),\r
 -                                &(Ext2Sys->PartInfo), sizeof(PARTITION_INFORMATION));\r
 -\r
 -    if (!NT_SUCCESS(Status))\r
 -    {\r
 -        goto errorout;\r
 -    }\r
 -\r
 -errorout:\r
 -\r
 -    return Status;\r
 -}\r
 -\r
 -\r
 -/*\r
 - * Ext2LockVolume\r
 - *     Lock the volume ...\r
 - *\r
 - * ARGUMENTS:\r
 - *     VolumeHandle:    Volume handle.\r
 - *\r
 - * RETURNS: \r
 - *     Success or Fail\r
 - *\r
 - * NOTES: \r
 - *     N/A\r
 - */\r
 -\r
 -\r
 -NTSTATUS\r
 -Ext2LockVolume( PEXT2_FILESYS Ext2Sys )\r
 -{\r
 -    NTSTATUS Status;\r
 -    IO_STATUS_BLOCK IoSb;\r
 -\r
 -    Status = NtFsControlFile( Ext2Sys->MediaHandle,\r
 -                              NULL, NULL, NULL, &IoSb,\r
 -                              FSCTL_LOCK_VOLUME,\r
 -                              NULL, 0, NULL, 0 );\r
 -\r
 -    if (!NT_SUCCESS(Status))\r
 -    {\r
 -        KdPrint(("Mke2fs: Error when locking volume: Status = %lxh %s...\n",\r
 -                Status, Ext2StatusToString(Status)));\r
 -\r
 -        goto errorout;\r
 -    }\r
 -\r
 -errorout:\r
 -\r
 -    return Status;\r
 -}\r
 -\r
 -\r
 -NTSTATUS\r
 -Ext2UnLockVolume( PEXT2_FILESYS Ext2Sys )\r
 -{\r
 -    NTSTATUS Status;\r
 -    IO_STATUS_BLOCK IoSb;\r
 -\r
 -    Status = NtFsControlFile( Ext2Sys->MediaHandle,\r
 -                              NULL, NULL, NULL, &IoSb,\r
 -                              FSCTL_UNLOCK_VOLUME,\r
 -                              NULL, 0, NULL, 0 );\r
 -\r
 -    if (!NT_SUCCESS(Status))\r
 -    {\r
 -        KdPrint(("Mke2fs: Error when unlocking volume ...\n"));\r
 -        goto errorout;\r
 -    }\r
 -\r
 -errorout:\r
 -\r
 -    return Status;\r
 -}\r
 -\r
 -\r
 -NTSTATUS\r
 -Ext2DisMountVolume( PEXT2_FILESYS Ext2Sys )\r
 -{\r
 -    NTSTATUS Status;\r
 -    IO_STATUS_BLOCK IoSb;\r
 -\r
 -    Status = NtFsControlFile( Ext2Sys->MediaHandle,\r
 -                              NULL, NULL, NULL, &IoSb,\r
 -                              FSCTL_DISMOUNT_VOLUME,\r
 -                              NULL, 0, NULL, 0 );\r
 -\r
 -    if (!NT_SUCCESS(Status))\r
 -    {\r
 -        KdPrint(("Mke2fs: Error when dismounting volume ...\n"));\r
 -        goto errorout;\r
 -    }\r
 -\r
 -errorout:\r
 -\r
 -    return Status;\r
 -}\r
 -\r
 -NTSTATUS\r
 -Ext2OpenDevice(  PEXT2_FILESYS Ext2Sys,\r
 -                 PUNICODE_STRING DeviceName )\r
 -{\r
 -    NTSTATUS Status;\r
 -    OBJECT_ATTRIBUTES ObjectAttributes;\r
 -    HANDLE FileHandle;\r
 -    IO_STATUS_BLOCK Iosb;\r
 -\r
 -    //\r
 -    // Setup the name in an object attributes structure.\r
 -    // Note that we create a name that is case INsensitive\r
 -    //\r
 -    InitializeObjectAttributes(&ObjectAttributes,           // ptr to structure\r
 -                               DeviceName,                  // ptr to file spec\r
 -                               OBJ_CASE_INSENSITIVE,        // attributes\r
 -                               NULL,                        // root directory handle\r
 -                               NULL );                      // ptr to security descriptor\r
 -\r
 -    //\r
 -    // Do the create.  In this particular case, we'll have the I/O Manager\r
 -    // make our write requests syncrhonous for our convenience.\r
 -    //\r
 -    Status = NtCreateFile(&FileHandle,                      // returned file handle\r
 -                          (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE),    // desired access\r
 -                          &ObjectAttributes,                // ptr to object attributes\r
 -                          &Iosb,                            // ptr to I/O status block\r
 -                          0,                                // allocation size\r
 -                          FILE_ATTRIBUTE_NORMAL,            // file attributes\r
 -                          FILE_SHARE_WRITE | FILE_SHARE_READ, // share access\r
 -                          FILE_OPEN  /*FILE_SUPERSEDE*/,    // create disposition\r
 -                          FILE_SYNCHRONOUS_IO_NONALERT, // create options\r
 -                          NULL,                             // ptr to extended attributes\r
 -                          0);                               // length of ea buffer\r
 -\r
 -    //\r
 -    // Check the system service status\r
 -    //\r
 -    if( !NT_SUCCESS(Status) )\r
 -    {\r
 -        KdPrint(("Mke2fs: Create system service failed status = 0x%lx\n", Status));\r
 -        return Status;\r
 -    }\r
 -\r
 -\r
 -    //\r
 -    // Check the returned status too...\r
 -    //\r
 -    if(!NT_SUCCESS(Iosb.Status) )\r
 -    {\r
 -        KdPrint(("Mke2fs: Create failed with status = 0x%lx\n",Iosb.Status));\r
 -        return Status;\r
 -    }\r
 -\r
 -    Ext2Sys->MediaHandle = FileHandle;\r
 -\r
 -    return Status;\r
 -}\r
 -\r
 -\r
 -NTSTATUS\r
 -Ext2CloseDevice( PEXT2_FILESYS Ext2Sys)\r
 -{\r
 -    NTSTATUS Status = STATUS_SUCCESS;\r
 -\r
 -    if(Ext2Sys->MediaHandle)\r
 -    {\r
 -        Status = NtClose(Ext2Sys->MediaHandle);\r
 -    }\r
 -\r
 -    return Status;\r
 -}\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Disk.c
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++/* INCLUDES **************************************************************/
++
++#include "Mke2fs.h"
++
++/* DEFINITIONS ***********************************************************/
++
++
++
++/* FUNCTIONS *************************************************************/
++
++PUCHAR
++Ext2StatusToString ( IN NTSTATUS Status )
++{
++    switch (Status)
++    {
++    case 0x00000000: return "STATUS_SUCCESS";
++    case 0x00000001: return "STATUS_WAIT_1";
++    case 0x00000002: return "STATUS_WAIT_2";
++    case 0x00000003: return "STATUS_WAIT_3";
++    case 0x0000003F: return "STATUS_WAIT_63";
++    case 0x00000080: return "STATUS_ABANDONED_WAIT_0";
++    case 0x000000BF: return "STATUS_ABANDONED_WAIT_63";
++    case 0x000000C0: return "STATUS_USER_APC";
++    case 0x00000100: return "STATUS_KERNEL_APC";
++    case 0x00000101: return "STATUS_ALERTED";
++    case 0x00000102: return "STATUS_TIMEOUT";
++    case 0x00000103: return "STATUS_PENDING";
++    case 0x00000104: return "STATUS_REPARSE";
++    case 0x00000105: return "STATUS_MORE_ENTRIES";
++    case 0x00000106: return "STATUS_NOT_ALL_ASSIGNED";
++    case 0x00000107: return "STATUS_SOME_NOT_MAPPED";
++    case 0x00000108: return "STATUS_OPLOCK_BREAK_IN_PROGRESS";
++    case 0x00000109: return "STATUS_VOLUME_MOUNTED";
++    case 0x0000010A: return "STATUS_RXACT_COMMITTED";
++    case 0x0000010B: return "STATUS_NOTIFY_CLEANUP";
++    case 0x0000010C: return "STATUS_NOTIFY_ENUM_DIR";
++    case 0x0000010D: return "STATUS_NO_QUOTAS_FOR_ACCOUNT";
++    case 0x0000010E: return "STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED";
++    case 0x00000110: return "STATUS_PAGE_FAULT_TRANSITION";
++    case 0x00000111: return "STATUS_PAGE_FAULT_DEMAND_ZERO";
++    case 0x00000112: return "STATUS_PAGE_FAULT_COPY_ON_WRITE";
++    case 0x00000113: return "STATUS_PAGE_FAULT_GUARD_PAGE";
++    case 0x00000114: return "STATUS_PAGE_FAULT_PAGING_FILE";
++    case 0x00000115: return "STATUS_CACHE_PAGE_LOCKED";
++    case 0x00000116: return "STATUS_CRASH_DUMP";
++    case 0x00000117: return "STATUS_BUFFER_ALL_ZEROS";
++    case 0x00000118: return "STATUS_REPARSE_OBJECT";
++    case 0x00000119: return "STATUS_RESOURCE_REQUIREMENTS_CHANGED";
++    case 0x00000120: return "STATUS_TRANSLATION_COMPLETE";
++    case 0x00000121: return "STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY";
++    case 0x00010001: return "DBG_EXCEPTION_HANDLED";
++    case 0x00010002: return "DBG_CONTINUE";
++    case 0x40000000: return "STATUS_OBJECT_NAME_EXISTS";
++    case 0x40000001: return "STATUS_THREAD_WAS_SUSPENDED";
++    case 0x40000002: return "STATUS_WORKING_SET_LIMIT_RANGE";
++    case 0x40000003: return "STATUS_IMAGE_NOT_AT_BASE";
++    case 0x40000004: return "STATUS_RXACT_STATE_CREATED";
++    case 0x40000005: return "STATUS_SEGMENT_NOTIFICATION";
++    case 0x40000006: return "STATUS_LOCAL_USER_SESSION_KEY";
++    case 0x40000007: return "STATUS_BAD_CURRENT_DIRECTORY";
++    case 0x40000008: return "STATUS_SERIAL_MORE_WRITES";
++    case 0x40000009: return "STATUS_REGISTRY_RECOVERED";
++    case 0x4000000A: return "STATUS_FT_READ_RECOVERY_FROM_BACKUP";
++    case 0x4000000B: return "STATUS_FT_WRITE_RECOVERY";
++    case 0x4000000C: return "STATUS_SERIAL_COUNTER_TIMEOUT";
++    case 0x4000000D: return "STATUS_NULL_LM_PASSWORD";
++    case 0x4000000E: return "STATUS_IMAGE_MACHINE_TYPE_MISMATCH";
++    case 0x4000000F: return "STATUS_RECEIVE_PARTIAL";
++    case 0x40000010: return "STATUS_RECEIVE_EXPEDITED";
++    case 0x40000011: return "STATUS_RECEIVE_PARTIAL_EXPEDITED";
++    case 0x40000012: return "STATUS_EVENT_DONE";
++    case 0x40000013: return "STATUS_EVENT_PENDING";
++    case 0x40000014: return "STATUS_CHECKING_FILE_SYSTEM";
++    case 0x40000015: return "STATUS_FATAL_APP_EXIT";
++    case 0x40000016: return "STATUS_PREDEFINED_HANDLE";
++    case 0x40000017: return "STATUS_WAS_UNLOCKED";
++    case 0x40000018: return "STATUS_SERVICE_NOTIFICATION";
++    case 0x40000019: return "STATUS_WAS_LOCKED";
++    case 0x4000001A: return "STATUS_LOG_HARD_ERROR";
++    case 0x4000001B: return "STATUS_ALREADY_WIN32";
++    case 0x4000001C: return "STATUS_WX86_UNSIMULATE";
++    case 0x4000001D: return "STATUS_WX86_CONTINUE";
++    case 0x4000001E: return "STATUS_WX86_SINGLE_STEP";
++    case 0x4000001F: return "STATUS_WX86_BREAKPOINT";
++    case 0x40000020: return "STATUS_WX86_EXCEPTION_CONTINUE";
++    case 0x40000021: return "STATUS_WX86_EXCEPTION_LASTCHANCE";
++    case 0x40000022: return "STATUS_WX86_EXCEPTION_CHAIN";
++    case 0x40000023: return "STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE";
++    case 0x40000024: return "STATUS_NO_YIELD_PERFORMED";
++    case 0x40000025: return "STATUS_TIMER_RESUME_IGNORED";
++    case 0x40000026: return "STATUS_ARBITRATION_UNHANDLED";
++    case 0x40000027: return "STATUS_CARDBUS_NOT_SUPPORTED";
++    case 0x40000028: return "STATUS_WX86_CREATEWX86TIB";
++    case 0x40000029: return "STATUS_MP_PROCESSOR_MISMATCH";
++    case 0x40010001: return "DBG_REPLY_LATER";
++    case 0x40010002: return "DBG_UNABLE_TO_PROVIDE_HANDLE";
++    case 0x40010003: return "DBG_TERMINATE_THREAD";
++    case 0x40010004: return "DBG_TERMINATE_PROCESS";
++    case 0x40010005: return "DBG_CONTROL_C";
++    case 0x40010006: return "DBG_PRINTEXCEPTION_C";
++    case 0x40010007: return "DBG_RIPEXCEPTION";
++    case 0x40010008: return "DBG_CONTROL_BREAK";
++    case 0x80000001: return "STATUS_GUARD_PAGE_VIOLATION";
++    case 0x80000002: return "STATUS_DATATYPE_MISALIGNMENT";
++    case 0x80000003: return "STATUS_BREAKPOINT";
++    case 0x80000004: return "STATUS_SINGLE_STEP";
++    case 0x80000005: return "STATUS_BUFFER_OVERFLOW";
++    case 0x80000006: return "STATUS_NO_MORE_FILES";
++    case 0x80000007: return "STATUS_WAKE_SYSTEM_DEBUGGER";
++    case 0x8000000A: return "STATUS_HANDLES_CLOSED";
++    case 0x8000000B: return "STATUS_NO_INHERITANCE";
++    case 0x8000000C: return "STATUS_GUID_SUBSTITUTION_MADE";
++    case 0x8000000D: return "STATUS_PARTIAL_COPY";
++    case 0x8000000E: return "STATUS_DEVICE_PAPER_EMPTY";
++    case 0x8000000F: return "STATUS_DEVICE_POWERED_OFF";
++    case 0x80000010: return "STATUS_DEVICE_OFF_LINE";
++    case 0x80000011: return "STATUS_DEVICE_BUSY";
++    case 0x80000012: return "STATUS_NO_MORE_EAS";
++    case 0x80000013: return "STATUS_INVALID_EA_NAME";
++    case 0x80000014: return "STATUS_EA_LIST_INCONSISTENT";
++    case 0x80000015: return "STATUS_INVALID_EA_FLAG";
++    case 0x80000016: return "STATUS_VERIFY_REQUIRED";
++    case 0x80000017: return "STATUS_EXTRANEOUS_INFORMATION";
++    case 0x80000018: return "STATUS_RXACT_COMMIT_NECESSARY";
++    case 0x8000001A: return "STATUS_NO_MORE_ENTRIES";
++    case 0x8000001B: return "STATUS_FILEMARK_DETECTED";
++    case 0x8000001C: return "STATUS_MEDIA_CHANGED";
++    case 0x8000001D: return "STATUS_BUS_RESET";
++    case 0x8000001E: return "STATUS_END_OF_MEDIA";
++    case 0x8000001F: return "STATUS_BEGINNING_OF_MEDIA";
++    case 0x80000020: return "STATUS_MEDIA_CHECK";
++    case 0x80000021: return "STATUS_SETMARK_DETECTED";
++    case 0x80000022: return "STATUS_NO_DATA_DETECTED";
++    case 0x80000023: return "STATUS_REDIRECTOR_HAS_OPEN_HANDLES";
++    case 0x80000024: return "STATUS_SERVER_HAS_OPEN_HANDLES";
++    case 0x80000025: return "STATUS_ALREADY_DISCONNECTED";
++    case 0x80000026: return "STATUS_LONGJUMP";
++    case 0x80010001: return "DBG_EXCEPTION_NOT_HANDLED";
++    case 0xC0000001: return "STATUS_UNSUCCESSFUL";
++    case 0xC0000002: return "STATUS_NOT_IMPLEMENTED";
++    case 0xC0000003: return "STATUS_INVALID_INFO_CLASS";
++    case 0xC0000004: return "STATUS_INFO_LENGTH_MISMATCH";
++    case 0xC0000005: return "STATUS_ACCESS_VIOLATION";
++    case 0xC0000006: return "STATUS_IN_PAGE_ERROR";
++    case 0xC0000007: return "STATUS_PAGEFILE_QUOTA";
++    case 0xC0000008: return "STATUS_INVALID_HANDLE";
++    case 0xC0000009: return "STATUS_BAD_INITIAL_STACK";
++    case 0xC000000A: return "STATUS_BAD_INITIAL_PC";
++    case 0xC000000B: return "STATUS_INVALID_CID";
++    case 0xC000000C: return "STATUS_TIMER_NOT_CANCELED";
++    case 0xC000000D: return "STATUS_INVALID_PARAMETER";
++    case 0xC000000E: return "STATUS_NO_SUCH_DEVICE";
++    case 0xC000000F: return "STATUS_NO_SUCH_FILE";
++    case 0xC0000010: return "STATUS_INVALID_DEVICE_REQUEST";
++    case 0xC0000011: return "STATUS_END_OF_FILE";
++    case 0xC0000012: return "STATUS_WRONG_VOLUME";
++    case 0xC0000013: return "STATUS_NO_MEDIA_IN_DEVICE";
++    case 0xC0000014: return "STATUS_UNRECOGNIZED_MEDIA";
++    case 0xC0000015: return "STATUS_NONEXISTENT_SECTOR";
++    case 0xC0000016: return "STATUS_MORE_PROCESSING_REQUIRED";
++    case 0xC0000017: return "STATUS_NO_MEMORY";
++    case 0xC0000018: return "STATUS_CONFLICTING_ADDRESSES";
++    case 0xC0000019: return "STATUS_NOT_MAPPED_VIEW";
++    case 0xC000001A: return "STATUS_UNABLE_TO_FREE_VM";
++    case 0xC000001B: return "STATUS_UNABLE_TO_DELETE_SECTION";
++    case 0xC000001C: return "STATUS_INVALID_SYSTEM_SERVICE";
++    case 0xC000001D: return "STATUS_ILLEGAL_INSTRUCTION";
++    case 0xC000001E: return "STATUS_INVALID_LOCK_SEQUENCE";
++    case 0xC000001F: return "STATUS_INVALID_VIEW_SIZE";
++    case 0xC0000020: return "STATUS_INVALID_FILE_FOR_SECTION";
++    case 0xC0000021: return "STATUS_ALREADY_COMMITTED";
++    case 0xC0000022: return "STATUS_ACCESS_DENIED";
++    case 0xC0000023: return "STATUS_BUFFER_TOO_SMALL";
++    case 0xC0000024: return "STATUS_OBJECT_TYPE_MISMATCH";
++    case 0xC0000025: return "STATUS_NONCONTINUABLE_EXCEPTION";
++    case 0xC0000026: return "STATUS_INVALID_DISPOSITION";
++    case 0xC0000027: return "STATUS_UNWIND";
++    case 0xC0000028: return "STATUS_BAD_STACK";
++    case 0xC0000029: return "STATUS_INVALID_UNWIND_TARGET";
++    case 0xC000002A: return "STATUS_NOT_LOCKED";
++    case 0xC000002B: return "STATUS_PARITY_ERROR";
++    case 0xC000002C: return "STATUS_UNABLE_TO_DECOMMIT_VM";
++    case 0xC000002D: return "STATUS_NOT_COMMITTED";
++    case 0xC000002E: return "STATUS_INVALID_PORT_ATTRIBUTES";
++    case 0xC000002F: return "STATUS_PORT_MESSAGE_TOO_LONG";
++    case 0xC0000030: return "STATUS_INVALID_PARAMETER_MIX";
++    case 0xC0000031: return "STATUS_INVALID_QUOTA_LOWER";
++    case 0xC0000032: return "STATUS_DISK_CORRUPT_ERROR";
++    case 0xC0000033: return "STATUS_OBJECT_NAME_INVALID";
++    case 0xC0000034: return "STATUS_OBJECT_NAME_NOT_FOUND";
++    case 0xC0000035: return "STATUS_OBJECT_NAME_COLLISION";
++    case 0xC0000037: return "STATUS_PORT_DISCONNECTED";
++    case 0xC0000038: return "STATUS_DEVICE_ALREADY_ATTACHED";
++    case 0xC0000039: return "STATUS_OBJECT_PATH_INVALID";
++    case 0xC000003A: return "STATUS_OBJECT_PATH_NOT_FOUND";
++    case 0xC000003B: return "STATUS_OBJECT_PATH_SYNTAX_BAD";
++    case 0xC000003C: return "STATUS_DATA_OVERRUN";
++    case 0xC000003D: return "STATUS_DATA_LATE_ERROR";
++    case 0xC000003E: return "STATUS_DATA_ERROR";
++    case 0xC000003F: return "STATUS_CRC_ERROR";
++    case 0xC0000040: return "STATUS_SECTION_TOO_BIG";
++    case 0xC0000041: return "STATUS_PORT_CONNECTION_REFUSED";
++    case 0xC0000042: return "STATUS_INVALID_PORT_HANDLE";
++    case 0xC0000043: return "STATUS_SHARING_VIOLATION";
++    case 0xC0000044: return "STATUS_QUOTA_EXCEEDED";
++    case 0xC0000045: return "STATUS_INVALID_PAGE_PROTECTION";
++    case 0xC0000046: return "STATUS_MUTANT_NOT_OWNED";
++    case 0xC0000047: return "STATUS_SEMAPHORE_LIMIT_EXCEEDED";
++    case 0xC0000048: return "STATUS_PORT_ALREADY_SET";
++    case 0xC0000049: return "STATUS_SECTION_NOT_IMAGE";
++    case 0xC000004A: return "STATUS_SUSPEND_COUNT_EXCEEDED";
++    case 0xC000004B: return "STATUS_THREAD_IS_TERMINATING";
++    case 0xC000004C: return "STATUS_BAD_WORKING_SET_LIMIT";
++    case 0xC000004D: return "STATUS_INCOMPATIBLE_FILE_MAP";
++    case 0xC000004E: return "STATUS_SECTION_PROTECTION";
++    case 0xC000004F: return "STATUS_EAS_NOT_SUPPORTED";
++    case 0xC0000050: return "STATUS_EA_TOO_LARGE";
++    case 0xC0000051: return "STATUS_NONEXISTENT_EA_ENTRY";
++    case 0xC0000052: return "STATUS_NO_EAS_ON_FILE";
++    case 0xC0000053: return "STATUS_EA_CORRUPT_ERROR";
++    case 0xC0000054: return "STATUS_FILE_LOCK_CONFLICT";
++    case 0xC0000055: return "STATUS_LOCK_NOT_GRANTED";
++    case 0xC0000056: return "STATUS_DELETE_PENDING";
++    case 0xC0000057: return "STATUS_CTL_FILE_NOT_SUPPORTED";
++    case 0xC0000058: return "STATUS_UNKNOWN_REVISION";
++    case 0xC0000059: return "STATUS_REVISION_MISMATCH";
++    case 0xC000005A: return "STATUS_INVALID_OWNER";
++    case 0xC000005B: return "STATUS_INVALID_PRIMARY_GROUP";
++    case 0xC000005C: return "STATUS_NO_IMPERSONATION_TOKEN";
++    case 0xC000005D: return "STATUS_CANT_DISABLE_MANDATORY";
++    case 0xC000005E: return "STATUS_NO_LOGON_SERVERS";
++    case 0xC000005F: return "STATUS_NO_SUCH_LOGON_SESSION";
++    case 0xC0000060: return "STATUS_NO_SUCH_PRIVILEGE";
++    case 0xC0000061: return "STATUS_PRIVILEGE_NOT_HELD";
++    case 0xC0000062: return "STATUS_INVALID_ACCOUNT_NAME";
++    case 0xC0000063: return "STATUS_USER_EXISTS";
++    case 0xC0000064: return "STATUS_NO_SUCH_USER";
++    case 0xC0000065: return "STATUS_GROUP_EXISTS";
++    case 0xC0000066: return "STATUS_NO_SUCH_GROUP";
++    case 0xC0000067: return "STATUS_MEMBER_IN_GROUP";
++    case 0xC0000068: return "STATUS_MEMBER_NOT_IN_GROUP";
++    case 0xC0000069: return "STATUS_LAST_ADMIN";
++    case 0xC000006A: return "STATUS_WRONG_PASSWORD";
++    case 0xC000006B: return "STATUS_ILL_FORMED_PASSWORD";
++    case 0xC000006C: return "STATUS_PASSWORD_RESTRICTION";
++    case 0xC000006D: return "STATUS_LOGON_FAILURE";
++    case 0xC000006E: return "STATUS_ACCOUNT_RESTRICTION";
++    case 0xC000006F: return "STATUS_INVALID_LOGON_HOURS";
++    case 0xC0000070: return "STATUS_INVALID_WORKSTATION";
++    case 0xC0000071: return "STATUS_PASSWORD_EXPIRED";
++    case 0xC0000072: return "STATUS_ACCOUNT_DISABLED";
++    case 0xC0000073: return "STATUS_NONE_MAPPED";
++    case 0xC0000074: return "STATUS_TOO_MANY_LUIDS_REQUESTED";
++    case 0xC0000075: return "STATUS_LUIDS_EXHAUSTED";
++    case 0xC0000076: return "STATUS_INVALID_SUB_AUTHORITY";
++    case 0xC0000077: return "STATUS_INVALID_ACL";
++    case 0xC0000078: return "STATUS_INVALID_SID";
++    case 0xC0000079: return "STATUS_INVALID_SECURITY_DESCR";
++    case 0xC000007A: return "STATUS_PROCEDURE_NOT_FOUND";
++    case 0xC000007B: return "STATUS_INVALID_IMAGE_FORMAT";
++    case 0xC000007C: return "STATUS_NO_TOKEN";
++    case 0xC000007D: return "STATUS_BAD_INHERITANCE_ACL";
++    case 0xC000007E: return "STATUS_RANGE_NOT_LOCKED";
++    case 0xC000007F: return "STATUS_DISK_FULL";
++    case 0xC0000080: return "STATUS_SERVER_DISABLED";
++    case 0xC0000081: return "STATUS_SERVER_NOT_DISABLED";
++    case 0xC0000082: return "STATUS_TOO_MANY_GUIDS_REQUESTED";
++    case 0xC0000083: return "STATUS_GUIDS_EXHAUSTED";
++    case 0xC0000084: return "STATUS_INVALID_ID_AUTHORITY";
++    case 0xC0000085: return "STATUS_AGENTS_EXHAUSTED";
++    case 0xC0000086: return "STATUS_INVALID_VOLUME_LABEL";
++    case 0xC0000087: return "STATUS_SECTION_NOT_EXTENDED";
++    case 0xC0000088: return "STATUS_NOT_MAPPED_DATA";
++    case 0xC0000089: return "STATUS_RESOURCE_DATA_NOT_FOUND";
++    case 0xC000008A: return "STATUS_RESOURCE_TYPE_NOT_FOUND";
++    case 0xC000008B: return "STATUS_RESOURCE_NAME_NOT_FOUND";
++    case 0xC000008C: return "STATUS_ARRAY_BOUNDS_EXCEEDED";
++    case 0xC000008D: return "STATUS_FLOAT_DENORMAL_OPERAND";
++    case 0xC000008E: return "STATUS_FLOAT_DIVIDE_BY_ZERO";
++    case 0xC000008F: return "STATUS_FLOAT_INEXACT_RESULT";
++    case 0xC0000090: return "STATUS_FLOAT_INVALID_OPERATION";
++    case 0xC0000091: return "STATUS_FLOAT_OVERFLOW";
++    case 0xC0000092: return "STATUS_FLOAT_STACK_CHECK";
++    case 0xC0000093: return "STATUS_FLOAT_UNDERFLOW";
++    case 0xC0000094: return "STATUS_INTEGER_DIVIDE_BY_ZERO";
++    case 0xC0000095: return "STATUS_INTEGER_OVERFLOW";
++    case 0xC0000096: return "STATUS_PRIVILEGED_INSTRUCTION";
++    case 0xC0000097: return "STATUS_TOO_MANY_PAGING_FILES";
++    case 0xC0000098: return "STATUS_FILE_INVALID";
++    case 0xC0000099: return "STATUS_ALLOTTED_SPACE_EXCEEDED";
++    case 0xC000009A: return "STATUS_INSUFFICIENT_RESOURCES";
++    case 0xC000009B: return "STATUS_DFS_EXIT_PATH_FOUND";
++    case 0xC000009C: return "STATUS_DEVICE_DATA_ERROR";
++    case 0xC000009D: return "STATUS_DEVICE_NOT_CONNECTED";
++    case 0xC000009E: return "STATUS_DEVICE_POWER_FAILURE";
++    case 0xC000009F: return "STATUS_FREE_VM_NOT_AT_BASE";
++    case 0xC00000A0: return "STATUS_MEMORY_NOT_ALLOCATED";
++    case 0xC00000A1: return "STATUS_WORKING_SET_QUOTA";
++    case 0xC00000A2: return "STATUS_MEDIA_WRITE_PROTECTED";
++    case 0xC00000A3: return "STATUS_DEVICE_NOT_READY";
++    case 0xC00000A4: return "STATUS_INVALID_GROUP_ATTRIBUTES";
++    case 0xC00000A5: return "STATUS_BAD_IMPERSONATION_LEVEL";
++    case 0xC00000A6: return "STATUS_CANT_OPEN_ANONYMOUS";
++    case 0xC00000A7: return "STATUS_BAD_VALIDATION_CLASS";
++    case 0xC00000A8: return "STATUS_BAD_TOKEN_TYPE";
++    case 0xC00000A9: return "STATUS_BAD_MASTER_BOOT_RECORD";
++    case 0xC00000AA: return "STATUS_INSTRUCTION_MISALIGNMENT";
++    case 0xC00000AB: return "STATUS_INSTANCE_NOT_AVAILABLE";
++    case 0xC00000AC: return "STATUS_PIPE_NOT_AVAILABLE";
++    case 0xC00000AD: return "STATUS_INVALID_PIPE_STATE";
++    case 0xC00000AE: return "STATUS_PIPE_BUSY";
++    case 0xC00000AF: return "STATUS_ILLEGAL_FUNCTION";
++    case 0xC00000B0: return "STATUS_PIPE_DISCONNECTED";
++    case 0xC00000B1: return "STATUS_PIPE_CLOSING";
++    case 0xC00000B2: return "STATUS_PIPE_CONNECTED";
++    case 0xC00000B3: return "STATUS_PIPE_LISTENING";
++    case 0xC00000B4: return "STATUS_INVALID_READ_MODE";
++    case 0xC00000B5: return "STATUS_IO_TIMEOUT";
++    case 0xC00000B6: return "STATUS_FILE_FORCED_CLOSED";
++    case 0xC00000B7: return "STATUS_PROFILING_NOT_STARTED";
++    case 0xC00000B8: return "STATUS_PROFILING_NOT_STOPPED";
++    case 0xC00000B9: return "STATUS_COULD_NOT_INTERPRET";
++    case 0xC00000BA: return "STATUS_FILE_IS_A_DIRECTORY";
++    case 0xC00000BB: return "STATUS_NOT_SUPPORTED";
++    case 0xC00000BC: return "STATUS_REMOTE_NOT_LISTENING";
++    case 0xC00000BD: return "STATUS_DUPLICATE_NAME";
++    case 0xC00000BE: return "STATUS_BAD_NETWORK_PATH";
++    case 0xC00000BF: return "STATUS_NETWORK_BUSY";
++    case 0xC00000C0: return "STATUS_DEVICE_DOES_NOT_EXIST";
++    case 0xC00000C1: return "STATUS_TOO_MANY_COMMANDS";
++    case 0xC00000C2: return "STATUS_ADAPTER_HARDWARE_ERROR";
++    case 0xC00000C3: return "STATUS_INVALID_NETWORK_RESPONSE";
++    case 0xC00000C4: return "STATUS_UNEXPECTED_NETWORK_ERROR";
++    case 0xC00000C5: return "STATUS_BAD_REMOTE_ADAPTER";
++    case 0xC00000C6: return "STATUS_PRINT_QUEUE_FULL";
++    case 0xC00000C7: return "STATUS_NO_SPOOL_SPACE";
++    case 0xC00000C8: return "STATUS_PRINT_CANCELLED";
++    case 0xC00000C9: return "STATUS_NETWORK_NAME_DELETED";
++    case 0xC00000CA: return "STATUS_NETWORK_ACCESS_DENIED";
++    case 0xC00000CB: return "STATUS_BAD_DEVICE_TYPE";
++    case 0xC00000CC: return "STATUS_BAD_NETWORK_NAME";
++    case 0xC00000CD: return "STATUS_TOO_MANY_NAMES";
++    case 0xC00000CE: return "STATUS_TOO_MANY_SESSIONS";
++    case 0xC00000CF: return "STATUS_SHARING_PAUSED";
++    case 0xC00000D0: return "STATUS_REQUEST_NOT_ACCEPTED";
++    case 0xC00000D1: return "STATUS_REDIRECTOR_PAUSED";
++    case 0xC00000D2: return "STATUS_NET_WRITE_FAULT";
++    case 0xC00000D3: return "STATUS_PROFILING_AT_LIMIT";
++    case 0xC00000D4: return "STATUS_NOT_SAME_DEVICE";
++    case 0xC00000D5: return "STATUS_FILE_RENAMED";
++    case 0xC00000D6: return "STATUS_VIRTUAL_CIRCUIT_CLOSED";
++    case 0xC00000D7: return "STATUS_NO_SECURITY_ON_OBJECT";
++    case 0xC00000D8: return "STATUS_CANT_WAIT";
++    case 0xC00000D9: return "STATUS_PIPE_EMPTY";
++    case 0xC00000DA: return "STATUS_CANT_ACCESS_DOMAIN_INFO";
++    case 0xC00000DB: return "STATUS_CANT_TERMINATE_SELF";
++    case 0xC00000DC: return "STATUS_INVALID_SERVER_STATE";
++    case 0xC00000DD: return "STATUS_INVALID_DOMAIN_STATE";
++    case 0xC00000DE: return "STATUS_INVALID_DOMAIN_ROLE";
++    case 0xC00000DF: return "STATUS_NO_SUCH_DOMAIN";
++    case 0xC00000E0: return "STATUS_DOMAIN_EXISTS";
++    case 0xC00000E1: return "STATUS_DOMAIN_LIMIT_EXCEEDED";
++    case 0xC00000E2: return "STATUS_OPLOCK_NOT_GRANTED";
++    case 0xC00000E3: return "STATUS_INVALID_OPLOCK_PROTOCOL";
++    case 0xC00000E4: return "STATUS_INTERNAL_DB_CORRUPTION";
++    case 0xC00000E5: return "STATUS_INTERNAL_ERROR";
++    case 0xC00000E6: return "STATUS_GENERIC_NOT_MAPPED";
++    case 0xC00000E7: return "STATUS_BAD_DESCRIPTOR_FORMAT";
++    case 0xC00000E8: return "STATUS_INVALID_USER_BUFFER";
++    case 0xC00000E9: return "STATUS_UNEXPECTED_IO_ERROR";
++    case 0xC00000EA: return "STATUS_UNEXPECTED_MM_CREATE_ERR";
++    case 0xC00000EB: return "STATUS_UNEXPECTED_MM_MAP_ERROR";
++    case 0xC00000EC: return "STATUS_UNEXPECTED_MM_EXTEND_ERR";
++    case 0xC00000ED: return "STATUS_NOT_LOGON_PROCESS";
++    case 0xC00000EE: return "STATUS_LOGON_SESSION_EXISTS";
++    case 0xC00000EF: return "STATUS_INVALID_PARAMETER_1";
++    case 0xC00000F0: return "STATUS_INVALID_PARAMETER_2";
++    case 0xC00000F1: return "STATUS_INVALID_PARAMETER_3";
++    case 0xC00000F2: return "STATUS_INVALID_PARAMETER_4";
++    case 0xC00000F3: return "STATUS_INVALID_PARAMETER_5";
++    case 0xC00000F4: return "STATUS_INVALID_PARAMETER_6";
++    case 0xC00000F5: return "STATUS_INVALID_PARAMETER_7";
++    case 0xC00000F6: return "STATUS_INVALID_PARAMETER_8";
++    case 0xC00000F7: return "STATUS_INVALID_PARAMETER_9";
++    case 0xC00000F8: return "STATUS_INVALID_PARAMETER_10";
++    case 0xC00000F9: return "STATUS_INVALID_PARAMETER_11";
++    case 0xC00000FA: return "STATUS_INVALID_PARAMETER_12";
++    case 0xC00000FB: return "STATUS_REDIRECTOR_NOT_STARTED";
++    case 0xC00000FC: return "STATUS_REDIRECTOR_STARTED";
++    case 0xC00000FD: return "STATUS_STACK_OVERFLOW";
++    case 0xC00000FE: return "STATUS_NO_SUCH_PACKAGE";
++    case 0xC00000FF: return "STATUS_BAD_FUNCTION_TABLE";
++    case 0xC0000100: return "STATUS_VARIABLE_NOT_FOUND";
++    case 0xC0000101: return "STATUS_DIRECTORY_NOT_EMPTY";
++    case 0xC0000102: return "STATUS_FILE_CORRUPT_ERROR";
++    case 0xC0000103: return "STATUS_NOT_A_DIRECTORY";
++    case 0xC0000104: return "STATUS_BAD_LOGON_SESSION_STATE";
++    case 0xC0000105: return "STATUS_LOGON_SESSION_COLLISION";
++    case 0xC0000106: return "STATUS_NAME_TOO_LONG";
++    case 0xC0000107: return "STATUS_FILES_OPEN";
++    case 0xC0000108: return "STATUS_CONNECTION_IN_USE";
++    case 0xC0000109: return "STATUS_MESSAGE_NOT_FOUND";
++    case 0xC000010A: return "STATUS_PROCESS_IS_TERMINATING";
++    case 0xC000010B: return "STATUS_INVALID_LOGON_TYPE";
++    case 0xC000010C: return "STATUS_NO_GUID_TRANSLATION";
++    case 0xC000010D: return "STATUS_CANNOT_IMPERSONATE";
++    case 0xC000010E: return "STATUS_IMAGE_ALREADY_LOADED";
++    case 0xC000010F: return "STATUS_ABIOS_NOT_PRESENT";
++    case 0xC0000110: return "STATUS_ABIOS_LID_NOT_EXIST";
++    case 0xC0000111: return "STATUS_ABIOS_LID_ALREADY_OWNED";
++    case 0xC0000112: return "STATUS_ABIOS_NOT_LID_OWNER";
++    case 0xC0000113: return "STATUS_ABIOS_INVALID_COMMAND";
++    case 0xC0000114: return "STATUS_ABIOS_INVALID_LID";
++    case 0xC0000115: return "STATUS_ABIOS_SELECTOR_NOT_AVAILABLE";
++    case 0xC0000116: return "STATUS_ABIOS_INVALID_SELECTOR";
++    case 0xC0000117: return "STATUS_NO_LDT";
++    case 0xC0000118: return "STATUS_INVALID_LDT_SIZE";
++    case 0xC0000119: return "STATUS_INVALID_LDT_OFFSET";
++    case 0xC000011A: return "STATUS_INVALID_LDT_DESCRIPTOR";
++    case 0xC000011B: return "STATUS_INVALID_IMAGE_NE_FORMAT";
++    case 0xC000011C: return "STATUS_RXACT_INVALID_STATE";
++    case 0xC000011D: return "STATUS_RXACT_COMMIT_FAILURE";
++    case 0xC000011E: return "STATUS_MAPPED_FILE_SIZE_ZERO";
++    case 0xC000011F: return "STATUS_TOO_MANY_OPENED_FILES";
++    case 0xC0000120: return "STATUS_CANCELLED";
++    case 0xC0000121: return "STATUS_CANNOT_DELETE";
++    case 0xC0000122: return "STATUS_INVALID_COMPUTER_NAME";
++    case 0xC0000123: return "STATUS_FILE_DELETED";
++    case 0xC0000124: return "STATUS_SPECIAL_ACCOUNT";
++    case 0xC0000125: return "STATUS_SPECIAL_GROUP";
++    case 0xC0000126: return "STATUS_SPECIAL_USER";
++    case 0xC0000127: return "STATUS_MEMBERS_PRIMARY_GROUP";
++    case 0xC0000128: return "STATUS_FILE_CLOSED";
++    case 0xC0000129: return "STATUS_TOO_MANY_THREADS";
++    case 0xC000012A: return "STATUS_THREAD_NOT_IN_PROCESS";
++    case 0xC000012B: return "STATUS_TOKEN_ALREADY_IN_USE";
++    case 0xC000012C: return "STATUS_PAGEFILE_QUOTA_EXCEEDED";
++    case 0xC000012D: return "STATUS_COMMITMENT_LIMIT";
++    case 0xC000012E: return "STATUS_INVALID_IMAGE_LE_FORMAT";
++    case 0xC000012F: return "STATUS_INVALID_IMAGE_NOT_MZ";
++    case 0xC0000130: return "STATUS_INVALID_IMAGE_PROTECT";
++    case 0xC0000131: return "STATUS_INVALID_IMAGE_WIN_16";
++    case 0xC0000132: return "STATUS_LOGON_SERVER_CONFLICT";
++    case 0xC0000133: return "STATUS_TIME_DIFFERENCE_AT_DC";
++    case 0xC0000134: return "STATUS_SYNCHRONIZATION_REQUIRED";
++    case 0xC0000135: return "STATUS_DLL_NOT_FOUND";
++    case 0xC0000136: return "STATUS_OPEN_FAILED";
++    case 0xC0000137: return "STATUS_IO_PRIVILEGE_FAILED";
++    case 0xC0000138: return "STATUS_ORDINAL_NOT_FOUND";
++    case 0xC0000139: return "STATUS_ENTRYPOINT_NOT_FOUND";
++    case 0xC000013A: return "STATUS_CONTROL_C_EXIT";
++    case 0xC000013B: return "STATUS_LOCAL_DISCONNECT";
++    case 0xC000013C: return "STATUS_REMOTE_DISCONNECT";
++    case 0xC000013D: return "STATUS_REMOTE_RESOURCES";
++    case 0xC000013E: return "STATUS_LINK_FAILED";
++    case 0xC000013F: return "STATUS_LINK_TIMEOUT";
++    case 0xC0000140: return "STATUS_INVALID_CONNECTION";
++    case 0xC0000141: return "STATUS_INVALID_ADDRESS";
++    case 0xC0000142: return "STATUS_DLL_INIT_FAILED";
++    case 0xC0000143: return "STATUS_MISSING_SYSTEMFILE";
++    case 0xC0000144: return "STATUS_UNHANDLED_EXCEPTION";
++    case 0xC0000145: return "STATUS_APP_INIT_FAILURE";
++    case 0xC0000146: return "STATUS_PAGEFILE_CREATE_FAILED";
++    case 0xC0000147: return "STATUS_NO_PAGEFILE";
++    case 0xC0000148: return "STATUS_INVALID_LEVEL";
++    case 0xC0000149: return "STATUS_WRONG_PASSWORD_CORE";
++    case 0xC000014A: return "STATUS_ILLEGAL_FLOAT_CONTEXT";
++    case 0xC000014B: return "STATUS_PIPE_BROKEN";
++    case 0xC000014C: return "STATUS_REGISTRY_CORRUPT";
++    case 0xC000014D: return "STATUS_REGISTRY_IO_FAILED";
++    case 0xC000014E: return "STATUS_NO_EVENT_PAIR";
++    case 0xC000014F: return "STATUS_UNRECOGNIZED_VOLUME";
++    case 0xC0000150: return "STATUS_SERIAL_NO_DEVICE_INITED";
++    case 0xC0000151: return "STATUS_NO_SUCH_ALIAS";
++    case 0xC0000152: return "STATUS_MEMBER_NOT_IN_ALIAS";
++    case 0xC0000153: return "STATUS_MEMBER_IN_ALIAS";
++    case 0xC0000154: return "STATUS_ALIAS_EXISTS";
++    case 0xC0000155: return "STATUS_LOGON_NOT_GRANTED";
++    case 0xC0000156: return "STATUS_TOO_MANY_SECRETS";
++    case 0xC0000157: return "STATUS_SECRET_TOO_LONG";
++    case 0xC0000158: return "STATUS_INTERNAL_DB_ERROR";
++    case 0xC0000159: return "STATUS_FULLSCREEN_MODE";
++    case 0xC000015A: return "STATUS_TOO_MANY_CONTEXT_IDS";
++    case 0xC000015B: return "STATUS_LOGON_TYPE_NOT_GRANTED";
++    case 0xC000015C: return "STATUS_NOT_REGISTRY_FILE";
++    case 0xC000015D: return "STATUS_NT_CROSS_ENCRYPTION_REQUIRED";
++    case 0xC000015E: return "STATUS_DOMAIN_CTRLR_CONFIG_ERROR";
++    case 0xC000015F: return "STATUS_FT_MISSING_MEMBER";
++    case 0xC0000160: return "STATUS_ILL_FORMED_SERVICE_ENTRY";
++    case 0xC0000161: return "STATUS_ILLEGAL_CHARACTER";
++    case 0xC0000162: return "STATUS_UNMAPPABLE_CHARACTER";
++    case 0xC0000163: return "STATUS_UNDEFINED_CHARACTER";
++    case 0xC0000164: return "STATUS_FLOPPY_VOLUME";
++    case 0xC0000165: return "STATUS_FLOPPY_ID_MARK_NOT_FOUND";
++    case 0xC0000166: return "STATUS_FLOPPY_WRONG_CYLINDER";
++    case 0xC0000167: return "STATUS_FLOPPY_UNKNOWN_ERROR";
++    case 0xC0000168: return "STATUS_FLOPPY_BAD_REGISTERS";
++    case 0xC0000169: return "STATUS_DISK_RECALIBRATE_FAILED";
++    case 0xC000016A: return "STATUS_DISK_OPERATION_FAILED";
++    case 0xC000016B: return "STATUS_DISK_RESET_FAILED";
++    case 0xC000016C: return "STATUS_SHARED_IRQ_BUSY";
++    case 0xC000016D: return "STATUS_FT_ORPHANING";
++    case 0xC000016E: return "STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT";
++    case 0xC0000172: return "STATUS_PARTITION_FAILURE";
++    case 0xC0000173: return "STATUS_INVALID_BLOCK_LENGTH";
++    case 0xC0000174: return "STATUS_DEVICE_NOT_PARTITIONED";
++    case 0xC0000175: return "STATUS_UNABLE_TO_LOCK_MEDIA";
++    case 0xC0000176: return "STATUS_UNABLE_TO_UNLOAD_MEDIA";
++    case 0xC0000177: return "STATUS_EOM_OVERFLOW";
++    case 0xC0000178: return "STATUS_NO_MEDIA";
++    case 0xC000017A: return "STATUS_NO_SUCH_MEMBER";
++    case 0xC000017B: return "STATUS_INVALID_MEMBER";
++    case 0xC000017C: return "STATUS_KEY_DELETED";
++    case 0xC000017D: return "STATUS_NO_LOG_SPACE";
++    case 0xC000017E: return "STATUS_TOO_MANY_SIDS";
++    case 0xC000017F: return "STATUS_LM_CROSS_ENCRYPTION_REQUIRED";
++    case 0xC0000180: return "STATUS_KEY_HAS_CHILDREN";
++    case 0xC0000181: return "STATUS_CHILD_MUST_BE_VOLATILE";
++    case 0xC0000182: return "STATUS_DEVICE_CONFIGURATION_ERROR";
++    case 0xC0000183: return "STATUS_DRIVER_INTERNAL_ERROR";
++    case 0xC0000184: return "STATUS_INVALID_DEVICE_STATE";
++    case 0xC0000185: return "STATUS_IO_DEVICE_ERROR";
++    case 0xC0000186: return "STATUS_DEVICE_PROTOCOL_ERROR";
++    case 0xC0000187: return "STATUS_BACKUP_CONTROLLER";
++    case 0xC0000188: return "STATUS_LOG_FILE_FULL";
++    case 0xC0000189: return "STATUS_TOO_LATE";
++    case 0xC000018A: return "STATUS_NO_TRUST_LSA_SECRET";
++    case 0xC000018B: return "STATUS_NO_TRUST_SAM_ACCOUNT";
++    case 0xC000018C: return "STATUS_TRUSTED_DOMAIN_FAILURE";
++    case 0xC000018D: return "STATUS_TRUSTED_RELATIONSHIP_FAILURE";
++    case 0xC000018E: return "STATUS_EVENTLOG_FILE_CORRUPT";
++    case 0xC000018F: return "STATUS_EVENTLOG_CANT_START";
++    case 0xC0000190: return "STATUS_TRUST_FAILURE";
++    case 0xC0000191: return "STATUS_MUTANT_LIMIT_EXCEEDED";
++    case 0xC0000192: return "STATUS_NETLOGON_NOT_STARTED";
++    case 0xC0000193: return "STATUS_ACCOUNT_EXPIRED";
++    case 0xC0000194: return "STATUS_POSSIBLE_DEADLOCK";
++    case 0xC0000195: return "STATUS_NETWORK_CREDENTIAL_CONFLICT";
++    case 0xC0000196: return "STATUS_REMOTE_SESSION_LIMIT";
++    case 0xC0000197: return "STATUS_EVENTLOG_FILE_CHANGED";
++    case 0xC0000198: return "STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT";
++    case 0xC0000199: return "STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT";
++    case 0xC000019A: return "STATUS_NOLOGON_SERVER_TRUST_ACCOUNT";
++    case 0xC000019B: return "STATUS_DOMAIN_TRUST_INCONSISTENT";
++    case 0xC000019C: return "STATUS_FS_DRIVER_REQUIRED";
++    case 0xC0000202: return "STATUS_NO_USER_SESSION_KEY";
++    case 0xC0000203: return "STATUS_USER_SESSION_DELETED";
++    case 0xC0000204: return "STATUS_RESOURCE_LANG_NOT_FOUND";
++    case 0xC0000205: return "STATUS_INSUFF_SERVER_RESOURCES";
++    case 0xC0000206: return "STATUS_INVALID_BUFFER_SIZE";
++    case 0xC0000207: return "STATUS_INVALID_ADDRESS_COMPONENT";
++    case 0xC0000208: return "STATUS_INVALID_ADDRESS_WILDCARD";
++    case 0xC0000209: return "STATUS_TOO_MANY_ADDRESSES";
++    case 0xC000020A: return "STATUS_ADDRESS_ALREADY_EXISTS";
++    case 0xC000020B: return "STATUS_ADDRESS_CLOSED";
++    case 0xC000020C: return "STATUS_CONNECTION_DISCONNECTED";
++    case 0xC000020D: return "STATUS_CONNECTION_RESET";
++    case 0xC000020E: return "STATUS_TOO_MANY_NODES";
++    case 0xC000020F: return "STATUS_TRANSACTION_ABORTED";
++    case 0xC0000210: return "STATUS_TRANSACTION_TIMED_OUT";
++    case 0xC0000211: return "STATUS_TRANSACTION_NO_RELEASE";
++    case 0xC0000212: return "STATUS_TRANSACTION_NO_MATCH";
++    case 0xC0000213: return "STATUS_TRANSACTION_RESPONDED";
++    case 0xC0000214: return "STATUS_TRANSACTION_INVALID_ID";
++    case 0xC0000215: return "STATUS_TRANSACTION_INVALID_TYPE";
++    case 0xC0000216: return "STATUS_NOT_SERVER_SESSION";
++    case 0xC0000217: return "STATUS_NOT_CLIENT_SESSION";
++    case 0xC0000218: return "STATUS_CANNOT_LOAD_REGISTRY_FILE";
++    case 0xC0000219: return "STATUS_DEBUG_ATTACH_FAILED";
++    case 0xC000021A: return "STATUS_SYSTEM_PROCESS_TERMINATED";
++    case 0xC000021B: return "STATUS_DATA_NOT_ACCEPTED";
++    case 0xC000021C: return "STATUS_NO_BROWSER_SERVERS_FOUND";
++    case 0xC000021D: return "STATUS_VDM_HARD_ERROR";
++    case 0xC000021E: return "STATUS_DRIVER_CANCEL_TIMEOUT";
++    case 0xC000021F: return "STATUS_REPLY_MESSAGE_MISMATCH";
++    case 0xC0000220: return "STATUS_MAPPED_ALIGNMENT";
++    case 0xC0000221: return "STATUS_IMAGE_CHECKSUM_MISMATCH";
++    case 0xC0000222: return "STATUS_LOST_WRITEBEHIND_DATA";
++    case 0xC0000223: return "STATUS_CLIENT_SERVER_PARAMETERS_INVALID";
++    case 0xC0000224: return "STATUS_PASSWORD_MUST_CHANGE";
++    case 0xC0000225: return "STATUS_NOT_FOUND";
++    case 0xC0000226: return "STATUS_NOT_TINY_STREAM";
++    case 0xC0000227: return "STATUS_RECOVERY_FAILURE";
++    case 0xC0000228: return "STATUS_STACK_OVERFLOW_READ";
++    case 0xC0000229: return "STATUS_FAIL_CHECK";
++    case 0xC000022A: return "STATUS_DUPLICATE_OBJECTID";
++    case 0xC000022B: return "STATUS_OBJECTID_EXISTS";
++    case 0xC000022C: return "STATUS_CONVERT_TO_LARGE";
++    case 0xC000022D: return "STATUS_RETRY";
++    case 0xC000022E: return "STATUS_FOUND_OUT_OF_SCOPE";
++    case 0xC000022F: return "STATUS_ALLOCATE_BUCKET";
++    case 0xC0000230: return "STATUS_PROPSET_NOT_FOUND";
++    case 0xC0000231: return "STATUS_MARSHALL_OVERFLOW";
++    case 0xC0000232: return "STATUS_INVALID_VARIANT";
++    case 0xC0000233: return "STATUS_DOMAIN_CONTROLLER_NOT_FOUND";
++    case 0xC0000234: return "STATUS_ACCOUNT_LOCKED_OUT";
++    case 0xC0000235: return "STATUS_HANDLE_NOT_CLOSABLE";
++    case 0xC0000236: return "STATUS_CONNECTION_REFUSED";
++    case 0xC0000237: return "STATUS_GRACEFUL_DISCONNECT";
++    case 0xC0000238: return "STATUS_ADDRESS_ALREADY_ASSOCIATED";
++    case 0xC0000239: return "STATUS_ADDRESS_NOT_ASSOCIATED";
++    case 0xC000023A: return "STATUS_CONNECTION_INVALID";
++    case 0xC000023B: return "STATUS_CONNECTION_ACTIVE";
++    case 0xC000023C: return "STATUS_NETWORK_UNREACHABLE";
++    case 0xC000023D: return "STATUS_HOST_UNREACHABLE";
++    case 0xC000023E: return "STATUS_PROTOCOL_UNREACHABLE";
++    case 0xC000023F: return "STATUS_PORT_UNREACHABLE";
++    case 0xC0000240: return "STATUS_REQUEST_ABORTED";
++    case 0xC0000241: return "STATUS_CONNECTION_ABORTED";
++    case 0xC0000242: return "STATUS_BAD_COMPRESSION_BUFFER";
++    case 0xC0000243: return "STATUS_USER_MAPPED_FILE";
++    case 0xC0000244: return "STATUS_AUDIT_FAILED";
++    case 0xC0000245: return "STATUS_TIMER_RESOLUTION_NOT_SET";
++    case 0xC0000246: return "STATUS_CONNECTION_COUNT_LIMIT";
++    case 0xC0000247: return "STATUS_LOGIN_TIME_RESTRICTION";
++    case 0xC0000248: return "STATUS_LOGIN_WKSTA_RESTRICTION";
++    case 0xC0000249: return "STATUS_IMAGE_MP_UP_MISMATCH";
++    case 0xC0000250: return "STATUS_INSUFFICIENT_LOGON_INFO";
++    case 0xC0000251: return "STATUS_BAD_DLL_ENTRYPOINT";
++    case 0xC0000252: return "STATUS_BAD_SERVICE_ENTRYPOINT";
++    case 0xC0000253: return "STATUS_LPC_REPLY_LOST";
++    case 0xC0000254: return "STATUS_IP_ADDRESS_CONFLICT1";
++    case 0xC0000255: return "STATUS_IP_ADDRESS_CONFLICT2";
++    case 0xC0000256: return "STATUS_REGISTRY_QUOTA_LIMIT";
++    case 0xC0000257: return "STATUS_PATH_NOT_COVERED";
++    case 0xC0000258: return "STATUS_NO_CALLBACK_ACTIVE";
++    case 0xC0000259: return "STATUS_LICENSE_QUOTA_EXCEEDED";
++    case 0xC000025A: return "STATUS_PWD_TOO_SHORT";
++    case 0xC000025B: return "STATUS_PWD_TOO_RECENT";
++    case 0xC000025C: return "STATUS_PWD_HISTORY_CONFLICT";
++    case 0xC000025E: return "STATUS_PLUGPLAY_NO_DEVICE";
++    case 0xC000025F: return "STATUS_UNSUPPORTED_COMPRESSION";
++    case 0xC0000260: return "STATUS_INVALID_HW_PROFILE";
++    case 0xC0000261: return "STATUS_INVALID_PLUGPLAY_DEVICE_PATH";
++    case 0xC0000262: return "STATUS_DRIVER_ORDINAL_NOT_FOUND";
++    case 0xC0000263: return "STATUS_DRIVER_ENTRYPOINT_NOT_FOUND";
++    case 0xC0000264: return "STATUS_RESOURCE_NOT_OWNED";
++    case 0xC0000265: return "STATUS_TOO_MANY_LINKS";
++    case 0xC0000266: return "STATUS_QUOTA_LIST_INCONSISTENT";
++    case 0xC0000267: return "STATUS_FILE_IS_OFFLINE";
++    case 0xC0000268: return "STATUS_EVALUATION_EXPIRATION";
++    case 0xC0000269: return "STATUS_ILLEGAL_DLL_RELOCATION";
++    case 0xC000026A: return "STATUS_LICENSE_VIOLATION";
++    case 0xC000026B: return "STATUS_DLL_INIT_FAILED_LOGOFF";
++    case 0xC000026C: return "STATUS_DRIVER_UNABLE_TO_LOAD";
++    case 0xC000026D: return "STATUS_DFS_UNAVAILABLE";
++    case 0xC000026E: return "STATUS_VOLUME_DISMOUNTED";
++    case 0xC000026F: return "STATUS_WX86_INTERNAL_ERROR";
++    case 0xC0000270: return "STATUS_WX86_FLOAT_STACK_CHECK";
++    case 0xC0000271: return "STATUS_VALIDATE_CONTINUE";
++    case 0xC0000272: return "STATUS_NO_MATCH";
++    case 0xC0000273: return "STATUS_NO_MORE_MATCHES";
++    case 0xC0000275: return "STATUS_NOT_A_REPARSE_POINT";
++    case 0xC0000276: return "STATUS_IO_REPARSE_TAG_INVALID";
++    case 0xC0000277: return "STATUS_IO_REPARSE_TAG_MISMATCH";
++    case 0xC0000278: return "STATUS_IO_REPARSE_DATA_INVALID";
++    case 0xC0000279: return "STATUS_IO_REPARSE_TAG_NOT_HANDLED";
++    case 0xC0000280: return "STATUS_REPARSE_POINT_NOT_RESOLVED";
++    case 0xC0000281: return "STATUS_DIRECTORY_IS_A_REPARSE_POINT";
++    case 0xC0000282: return "STATUS_RANGE_LIST_CONFLICT";
++    case 0xC0000283: return "STATUS_SOURCE_ELEMENT_EMPTY";
++    case 0xC0000284: return "STATUS_DESTINATION_ELEMENT_FULL";
++    case 0xC0000285: return "STATUS_ILLEGAL_ELEMENT_ADDRESS";
++    case 0xC0000286: return "STATUS_MAGAZINE_NOT_PRESENT";
++    case 0xC0000287: return "STATUS_REINITIALIZATION_NEEDED";
++    case 0x80000288: return "STATUS_DEVICE_REQUIRES_CLEANING";
++    case 0x80000289: return "STATUS_DEVICE_DOOR_OPEN";
++    case 0xC000028A: return "STATUS_ENCRYPTION_FAILED";
++    case 0xC000028B: return "STATUS_DECRYPTION_FAILED";
++    case 0xC000028C: return "STATUS_RANGE_NOT_FOUND";
++    case 0xC000028D: return "STATUS_NO_RECOVERY_POLICY";
++    case 0xC000028E: return "STATUS_NO_EFS";
++    case 0xC000028F: return "STATUS_WRONG_EFS";
++    case 0xC0000290: return "STATUS_NO_USER_KEYS";
++    case 0xC0000291: return "STATUS_FILE_NOT_ENCRYPTED";
++    case 0xC0000292: return "STATUS_NOT_EXPORT_FORMAT";
++    case 0xC0000293: return "STATUS_FILE_ENCRYPTED";
++    case 0x40000294: return "STATUS_WAKE_SYSTEM";
++    case 0xC0000295: return "STATUS_WMI_GUID_NOT_FOUND";
++    case 0xC0000296: return "STATUS_WMI_INSTANCE_NOT_FOUND";
++    case 0xC0000297: return "STATUS_WMI_ITEMID_NOT_FOUND";
++    case 0xC0000298: return "STATUS_WMI_TRY_AGAIN";
++    case 0xC0000299: return "STATUS_SHARED_POLICY";
++    case 0xC000029A: return "STATUS_POLICY_OBJECT_NOT_FOUND";
++    case 0xC000029B: return "STATUS_POLICY_ONLY_IN_DS";
++    case 0xC000029C: return "STATUS_VOLUME_NOT_UPGRADED";
++    case 0xC000029D: return "STATUS_REMOTE_STORAGE_NOT_ACTIVE";
++    case 0xC000029E: return "STATUS_REMOTE_STORAGE_MEDIA_ERROR";
++    case 0xC000029F: return "STATUS_NO_TRACKING_SERVICE";
++    case 0xC00002A0: return "STATUS_SERVER_SID_MISMATCH";
++    case 0xC00002A1: return "STATUS_DS_NO_ATTRIBUTE_OR_VALUE";
++    case 0xC00002A2: return "STATUS_DS_INVALID_ATTRIBUTE_SYNTAX";
++    case 0xC00002A3: return "STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED";
++    case 0xC00002A4: return "STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS";
++    case 0xC00002A5: return "STATUS_DS_BUSY";
++    case 0xC00002A6: return "STATUS_DS_UNAVAILABLE";
++    case 0xC00002A7: return "STATUS_DS_NO_RIDS_ALLOCATED";
++    case 0xC00002A8: return "STATUS_DS_NO_MORE_RIDS";
++    case 0xC00002A9: return "STATUS_DS_INCORRECT_ROLE_OWNER";
++    case 0xC00002AA: return "STATUS_DS_RIDMGR_INIT_ERROR";
++    case 0xC00002AB: return "STATUS_DS_OBJ_CLASS_VIOLATION";
++    case 0xC00002AC: return "STATUS_DS_CANT_ON_NON_LEAF";
++    case 0xC00002AD: return "STATUS_DS_CANT_ON_RDN";
++    case 0xC00002AE: return "STATUS_DS_CANT_MOD_OBJ_CLASS";
++    case 0xC00002AF: return "STATUS_DS_CROSS_DOM_MOVE_FAILED";
++    case 0xC00002B0: return "STATUS_DS_GC_NOT_AVAILABLE";
++    case 0xC00002B1: return "STATUS_DIRECTORY_SERVICE_REQUIRED";
++    case 0xC00002B2: return "STATUS_REPARSE_ATTRIBUTE_CONFLICT";
++    case 0xC00002B3: return "STATUS_CANT_ENABLE_DENY_ONLY";
++    case 0xC00002B4: return "STATUS_FLOAT_MULTIPLE_FAULTS";
++    case 0xC00002B5: return "STATUS_FLOAT_MULTIPLE_TRAPS";
++    case 0xC00002B6: return "STATUS_DEVICE_REMOVED";
++    case 0xC00002B7: return "STATUS_JOURNAL_DELETE_IN_PROGRESS";
++    case 0xC00002B8: return "STATUS_JOURNAL_NOT_ACTIVE";
++    case 0xC00002B9: return "STATUS_NOINTERFACE";
++    case 0xC00002C1: return "STATUS_DS_ADMIN_LIMIT_EXCEEDED";
++    case 0xC00002C2: return "STATUS_DRIVER_FAILED_SLEEP";
++    case 0xC00002C3: return "STATUS_MUTUAL_AUTHENTICATION_FAILED";
++    case 0xC00002C4: return "STATUS_CORRUPT_SYSTEM_FILE";
++    case 0xC00002C5: return "STATUS_DATATYPE_MISALIGNMENT_ERROR";
++    case 0xC00002C6: return "STATUS_WMI_READ_ONLY";
++    case 0xC00002C7: return "STATUS_WMI_SET_FAILURE";
++    case 0xC00002C8: return "STATUS_COMMITMENT_MINIMUM";
++    case 0xC00002C9: return "STATUS_REG_NAT_CONSUMPTION";
++    case 0xC00002CA: return "STATUS_TRANSPORT_FULL";
++    case 0xC00002CB: return "STATUS_DS_SAM_INIT_FAILURE";
++    case 0xC00002CC: return "STATUS_ONLY_IF_CONNECTED";
++    case 0xC00002CD: return "STATUS_DS_SENSITIVE_GROUP_VIOLATION";
++    case 0xC00002CE: return "STATUS_PNP_RESTART_ENUMERATION";
++    case 0xC00002CF: return "STATUS_JOURNAL_ENTRY_DELETED";
++    case 0xC00002D0: return "STATUS_DS_CANT_MOD_PRIMARYGROUPID";
++    case 0xC00002D1: return "STATUS_SYSTEM_IMAGE_BAD_SIGNATURE";
++    case 0xC00002D2: return "STATUS_PNP_REBOOT_REQUIRED";
++    case 0xC00002D3: return "STATUS_POWER_STATE_INVALID";
++    case 0xC00002D4: return "STATUS_DS_INVALID_GROUP_TYPE";
++    case 0xC00002D5: return "STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN";
++    case 0xC00002D6: return "STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN";
++    case 0xC00002D7: return "STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER";
++    case 0xC00002D8: return "STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER";
++    case 0xC00002D9: return "STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER";
++    case 0xC00002DA: return "STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER";
++    case 0xC00002DB: return "STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER";
++    case 0xC00002DC: return "STATUS_DS_HAVE_PRIMARY_MEMBERS";
++    case 0xC00002DD: return "STATUS_WMI_NOT_SUPPORTED";
++    case 0xC00002DE: return "STATUS_INSUFFICIENT_POWER";
++    case 0xC00002DF: return "STATUS_SAM_NEED_BOOTKEY_PASSWORD";
++    case 0xC00002E0: return "STATUS_SAM_NEED_BOOTKEY_FLOPPY";
++    case 0xC00002E1: return "STATUS_DS_CANT_START";
++    case 0xC00002E2: return "STATUS_DS_INIT_FAILURE";
++    case 0xC00002E3: return "STATUS_SAM_INIT_FAILURE";
++    case 0xC00002E4: return "STATUS_DS_GC_REQUIRED";
++    case 0xC00002E5: return "STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY";
++    case 0xC00002E6: return "STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS";
++    case 0xC00002E7: return "STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED";
++    case 0xC00002E8: return "STATUS_MULTIPLE_FAULT_VIOLATION";
++    case 0xC0000300: return "STATUS_NOT_SUPPORTED_ON_SBS";
++    case 0xC0009898: return "STATUS_WOW_ASSERTION";
++    case 0xC0010001: return "DBG_NO_STATE_CHANGE";
++    case 0xC0010002: return "DBG_APP_NOT_IDLE";
++    case 0xC0020001: return "RPC_NT_INVALID_STRING_BINDING";
++    case 0xC0020002: return "RPC_NT_WRONG_KIND_OF_BINDING";
++    case 0xC0020003: return "RPC_NT_INVALID_BINDING";
++    case 0xC0020004: return "RPC_NT_PROTSEQ_NOT_SUPPORTED";
++    case 0xC0020005: return "RPC_NT_INVALID_RPC_PROTSEQ";
++    case 0xC0020006: return "RPC_NT_INVALID_STRING_UUID";
++    case 0xC0020007: return "RPC_NT_INVALID_ENDPOINT_FORMAT";
++    case 0xC0020008: return "RPC_NT_INVALID_NET_ADDR";
++    case 0xC0020009: return "RPC_NT_NO_ENDPOINT_FOUND";
++    case 0xC002000A: return "RPC_NT_INVALID_TIMEOUT";
++    case 0xC002000B: return "RPC_NT_OBJECT_NOT_FOUND";
++    case 0xC002000C: return "RPC_NT_ALREADY_REGISTERED";
++    case 0xC002000D: return "RPC_NT_TYPE_ALREADY_REGISTERED";
++    case 0xC002000E: return "RPC_NT_ALREADY_LISTENING";
++    case 0xC002000F: return "RPC_NT_NO_PROTSEQS_REGISTERED";
++    case 0xC0020010: return "RPC_NT_NOT_LISTENING";
++    case 0xC0020011: return "RPC_NT_UNKNOWN_MGR_TYPE";
++    case 0xC0020012: return "RPC_NT_UNKNOWN_IF";
++    case 0xC0020013: return "RPC_NT_NO_BINDINGS";
++    case 0xC0020014: return "RPC_NT_NO_PROTSEQS";
++    case 0xC0020015: return "RPC_NT_CANT_CREATE_ENDPOINT";
++    case 0xC0020016: return "RPC_NT_OUT_OF_RESOURCES";
++    case 0xC0020017: return "RPC_NT_SERVER_UNAVAILABLE";
++    case 0xC0020018: return "RPC_NT_SERVER_TOO_BUSY";
++    case 0xC0020019: return "RPC_NT_INVALID_NETWORK_OPTIONS";
++    case 0xC002001A: return "RPC_NT_NO_CALL_ACTIVE";
++    case 0xC002001B: return "RPC_NT_CALL_FAILED";
++    case 0xC002001C: return "RPC_NT_CALL_FAILED_DNE";
++    case 0xC002001D: return "RPC_NT_PROTOCOL_ERROR";
++    case 0xC002001F: return "RPC_NT_UNSUPPORTED_TRANS_SYN";
++    case 0xC0020021: return "RPC_NT_UNSUPPORTED_TYPE";
++    case 0xC0020022: return "RPC_NT_INVALID_TAG";
++    case 0xC0020023: return "RPC_NT_INVALID_BOUND";
++    case 0xC0020024: return "RPC_NT_NO_ENTRY_NAME";
++    case 0xC0020025: return "RPC_NT_INVALID_NAME_SYNTAX";
++    case 0xC0020026: return "RPC_NT_UNSUPPORTED_NAME_SYNTAX";
++    case 0xC0020028: return "RPC_NT_UUID_NO_ADDRESS";
++    case 0xC0020029: return "RPC_NT_DUPLICATE_ENDPOINT";
++    case 0xC002002A: return "RPC_NT_UNKNOWN_AUTHN_TYPE";
++    case 0xC002002B: return "RPC_NT_MAX_CALLS_TOO_SMALL";
++    case 0xC002002C: return "RPC_NT_STRING_TOO_LONG";
++    case 0xC002002D: return "RPC_NT_PROTSEQ_NOT_FOUND";
++    case 0xC002002E: return "RPC_NT_PROCNUM_OUT_OF_RANGE";
++    case 0xC002002F: return "RPC_NT_BINDING_HAS_NO_AUTH";
++    case 0xC0020030: return "RPC_NT_UNKNOWN_AUTHN_SERVICE";
++    case 0xC0020031: return "RPC_NT_UNKNOWN_AUTHN_LEVEL";
++    case 0xC0020032: return "RPC_NT_INVALID_AUTH_IDENTITY";
++    case 0xC0020033: return "RPC_NT_UNKNOWN_AUTHZ_SERVICE";
++    case 0xC0020034: return "EPT_NT_INVALID_ENTRY";
++    case 0xC0020035: return "EPT_NT_CANT_PERFORM_OP";
++    case 0xC0020036: return "EPT_NT_NOT_REGISTERED";
++    case 0xC0020037: return "RPC_NT_NOTHING_TO_EXPORT";
++    case 0xC0020038: return "RPC_NT_INCOMPLETE_NAME";
++    case 0xC0020039: return "RPC_NT_INVALID_VERS_OPTION";
++    case 0xC002003A: return "RPC_NT_NO_MORE_MEMBERS";
++    case 0xC002003B: return "RPC_NT_NOT_ALL_OBJS_UNEXPORTED";
++    case 0xC002003C: return "RPC_NT_INTERFACE_NOT_FOUND";
++    case 0xC002003D: return "RPC_NT_ENTRY_ALREADY_EXISTS";
++    case 0xC002003E: return "RPC_NT_ENTRY_NOT_FOUND";
++    case 0xC002003F: return "RPC_NT_NAME_SERVICE_UNAVAILABLE";
++    case 0xC0020040: return "RPC_NT_INVALID_NAF_ID";
++    case 0xC0020041: return "RPC_NT_CANNOT_SUPPORT";
++    case 0xC0020042: return "RPC_NT_NO_CONTEXT_AVAILABLE";
++    case 0xC0020043: return "RPC_NT_INTERNAL_ERROR";
++    case 0xC0020044: return "RPC_NT_ZERO_DIVIDE";
++    case 0xC0020045: return "RPC_NT_ADDRESS_ERROR";
++    case 0xC0020046: return "RPC_NT_FP_DIV_ZERO";
++    case 0xC0020047: return "RPC_NT_FP_UNDERFLOW";
++    case 0xC0020048: return "RPC_NT_FP_OVERFLOW";
++    case 0xC0030001: return "RPC_NT_NO_MORE_ENTRIES";
++    case 0xC0030002: return "RPC_NT_SS_CHAR_TRANS_OPEN_FAIL";
++    case 0xC0030003: return "RPC_NT_SS_CHAR_TRANS_SHORT_FILE";
++    case 0xC0030004: return "RPC_NT_SS_IN_NULL_CONTEXT";
++    case 0xC0030005: return "RPC_NT_SS_CONTEXT_MISMATCH";
++    case 0xC0030006: return "RPC_NT_SS_CONTEXT_DAMAGED";
++    case 0xC0030007: return "RPC_NT_SS_HANDLES_MISMATCH";
++    case 0xC0030008: return "RPC_NT_SS_CANNOT_GET_CALL_HANDLE";
++    case 0xC0030009: return "RPC_NT_NULL_REF_POINTER";
++    case 0xC003000A: return "RPC_NT_ENUM_VALUE_OUT_OF_RANGE";
++    case 0xC003000B: return "RPC_NT_BYTE_COUNT_TOO_SMALL";
++    case 0xC003000C: return "RPC_NT_BAD_STUB_DATA";
++    case 0xC0020049: return "RPC_NT_CALL_IN_PROGRESS";
++    case 0xC002004A: return "RPC_NT_NO_MORE_BINDINGS";
++    case 0xC002004B: return "RPC_NT_GROUP_MEMBER_NOT_FOUND";
++    case 0xC002004C: return "EPT_NT_CANT_CREATE";
++    case 0xC002004D: return "RPC_NT_INVALID_OBJECT";
++    case 0xC002004F: return "RPC_NT_NO_INTERFACES";
++    case 0xC0020050: return "RPC_NT_CALL_CANCELLED";
++    case 0xC0020051: return "RPC_NT_BINDING_INCOMPLETE";
++    case 0xC0020052: return "RPC_NT_COMM_FAILURE";
++    case 0xC0020053: return "RPC_NT_UNSUPPORTED_AUTHN_LEVEL";
++    case 0xC0020054: return "RPC_NT_NO_PRINC_NAME";
++    case 0xC0020055: return "RPC_NT_NOT_RPC_ERROR";
++    case 0x40020056: return "RPC_NT_UUID_LOCAL_ONLY";
++    case 0xC0020057: return "RPC_NT_SEC_PKG_ERROR";
++    case 0xC0020058: return "RPC_NT_NOT_CANCELLED";
++    case 0xC0030059: return "RPC_NT_INVALID_ES_ACTION";
++    case 0xC003005A: return "RPC_NT_WRONG_ES_VERSION";
++    case 0xC003005B: return "RPC_NT_WRONG_STUB_VERSION";
++    case 0xC003005C: return "RPC_NT_INVALID_PIPE_OBJECT";
++    case 0xC003005D: return "RPC_NT_INVALID_PIPE_OPERATION";
++    case 0xC003005E: return "RPC_NT_WRONG_PIPE_VERSION";
++    case 0xC003005F: return "RPC_NT_PIPE_CLOSED";
++    case 0xC0030060: return "RPC_NT_PIPE_DISCIPLINE_ERROR";
++    case 0xC0030061: return "RPC_NT_PIPE_EMPTY";
++    case 0xC0020062: return "RPC_NT_INVALID_ASYNC_HANDLE";
++    case 0xC0020063: return "RPC_NT_INVALID_ASYNC_CALL";
++    case 0x400200AF: return "RPC_NT_SEND_INCOMPLETE";
++    case 0xC0140001: return "STATUS_ACPI_INVALID_OPCODE";
++    case 0xC0140002: return "STATUS_ACPI_STACK_OVERFLOW";
++    case 0xC0140003: return "STATUS_ACPI_ASSERT_FAILED";
++    case 0xC0140004: return "STATUS_ACPI_INVALID_INDEX";
++    case 0xC0140005: return "STATUS_ACPI_INVALID_ARGUMENT";
++    case 0xC0140006: return "STATUS_ACPI_FATAL";
++    case 0xC0140007: return "STATUS_ACPI_INVALID_SUPERNAME";
++    case 0xC0140008: return "STATUS_ACPI_INVALID_ARGTYPE";
++    case 0xC0140009: return "STATUS_ACPI_INVALID_OBJTYPE";
++    case 0xC014000A: return "STATUS_ACPI_INVALID_TARGETTYPE";
++    case 0xC014000B: return "STATUS_ACPI_INCORRECT_ARGUMENT_COUNT";
++    case 0xC014000C: return "STATUS_ACPI_ADDRESS_NOT_MAPPED";
++    case 0xC014000D: return "STATUS_ACPI_INVALID_EVENTTYPE";
++    case 0xC014000E: return "STATUS_ACPI_HANDLER_COLLISION";
++    case 0xC014000F: return "STATUS_ACPI_INVALID_DATA";
++    case 0xC0140010: return "STATUS_ACPI_INVALID_REGION";
++    case 0xC0140011: return "STATUS_ACPI_INVALID_ACCESS_SIZE";
++    case 0xC0140012: return "STATUS_ACPI_ACQUIRE_GLOBAL_LOCK";
++    case 0xC0140013: return "STATUS_ACPI_ALREADY_INITIALIZED";
++    case 0xC0140014: return "STATUS_ACPI_NOT_INITIALIZED";
++    case 0xC0140015: return "STATUS_ACPI_INVALID_MUTEX_LEVEL";
++    case 0xC0140016: return "STATUS_ACPI_MUTEX_NOT_OWNED";
++    case 0xC0140017: return "STATUS_ACPI_MUTEX_NOT_OWNER";
++    case 0xC0140018: return "STATUS_ACPI_RS_ACCESS";
++    case 0xC0140019: return "STATUS_ACPI_INVALID_TABLE";
++    case 0xC0140020: return "STATUS_ACPI_REG_HANDLER_FAILED";
++    case 0xC0140021: return "STATUS_ACPI_POWER_REQUEST_FAILED";
++    case 0xC00A0001: return "STATUS_CTX_WINSTATION_NAME_INVALID";
++    case 0xC00A0002: return "STATUS_CTX_INVALID_PD";
++    case 0xC00A0003: return "STATUS_CTX_PD_NOT_FOUND";
++    case 0x400A0004: return "STATUS_CTX_CDM_CONNECT";
++    case 0x400A0005: return "STATUS_CTX_CDM_DISCONNECT";
++    case 0xC00A0006: return "STATUS_CTX_CLOSE_PENDING";
++    case 0xC00A0007: return "STATUS_CTX_NO_OUTBUF";
++    case 0xC00A0008: return "STATUS_CTX_MODEM_INF_NOT_FOUND";
++    case 0xC00A0009: return "STATUS_CTX_INVALID_MODEMNAME";
++    case 0xC00A000A: return "STATUS_CTX_RESPONSE_ERROR";
++    case 0xC00A000B: return "STATUS_CTX_MODEM_RESPONSE_TIMEOUT";
++    case 0xC00A000C: return "STATUS_CTX_MODEM_RESPONSE_NO_CARRIER";
++    case 0xC00A000D: return "STATUS_CTX_MODEM_RESPONSE_NO_DIALTONE";
++    case 0xC00A000E: return "STATUS_CTX_MODEM_RESPONSE_BUSY";
++    case 0xC00A000F: return "STATUS_CTX_MODEM_RESPONSE_VOICE";
++    case 0xC00A0010: return "STATUS_CTX_TD_ERROR";
++    case 0xC00A0012: return "STATUS_CTX_LICENSE_CLIENT_INVALID";
++    case 0xC00A0013: return "STATUS_CTX_LICENSE_NOT_AVAILABLE";
++    case 0xC00A0014: return "STATUS_CTX_LICENSE_EXPIRED";
++    case 0xC00A0015: return "STATUS_CTX_WINSTATION_NOT_FOUND";
++    case 0xC00A0016: return "STATUS_CTX_WINSTATION_NAME_COLLISION";
++    case 0xC00A0017: return "STATUS_CTX_WINSTATION_BUSY";
++    case 0xC00A0018: return "STATUS_CTX_BAD_VIDEO_MODE";
++    case 0xC00A0022: return "STATUS_CTX_GRAPHICS_INVALID";
++    case 0xC00A0024: return "STATUS_CTX_NOT_CONSOLE";
++    case 0xC00A0026: return "STATUS_CTX_CLIENT_QUERY_TIMEOUT";
++    case 0xC00A0027: return "STATUS_CTX_CONSOLE_DISCONNECT";
++    case 0xC00A0028: return "STATUS_CTX_CONSOLE_CONNECT";
++    case 0xC00A002A: return "STATUS_CTX_SHADOW_DENIED";
++    case 0xC00A002B: return "STATUS_CTX_WINSTATION_ACCESS_DENIED";
++    case 0xC00A002E: return "STATUS_CTX_INVALID_WD";
++    case 0xC00A002F: return "STATUS_CTX_WD_NOT_FOUND";
++    case 0xC00A0030: return "STATUS_CTX_SHADOW_INVALID";
++    case 0xC00A0031: return "STATUS_CTX_SHADOW_DISABLED";
++    case 0xC00A0032: return "STATUS_RDP_PROTOCOL_ERROR";
++    case 0xC00A0033: return "STATUS_CTX_CLIENT_LICENSE_NOT_SET";
++    case 0xC00A0034: return "STATUS_CTX_CLIENT_LICENSE_IN_USE";
++    case 0xC0040035: return "STATUS_PNP_BAD_MPS_TABLE";
++    case 0xC0040036: return "STATUS_PNP_TRANSLATION_FAILED";
++    case 0xC0040037: return "STATUS_PNP_IRQ_TRANSLATION_FAILED";
++    default:         return "STATUS_UNKNOWN";
++    }
++}
++
++/*
++ * Ext2ReadDisk
++ *     Read data from disk ...
++ *
++ * ARGUMENTS:
++ *     VolumeHandle: Volume Handle
++ *     Offset      : Disk Offset
++ *     Length      : Data Length to be read
++ *     Buffer      : ...
++ *
++ * RETURNS: 
++ *     Success: STATUS_SUCCESS
++ *     Fail:  ...
++ *
++ * NOTES: 
++ *     Both Length and Offset should be SECTOR_SIZE aligned.
++ */
++NTSTATUS 
++Ext2ReadDisk( PEXT2_FILESYS  Ext2Sys,
++              ULONGLONG      Offset,
++              ULONG          Length,
++              PVOID          Buffer     )
++{
++    LARGE_INTEGER   Address;
++    NTSTATUS        Status;
++    ULONG           AlignedLength;
++
++    IO_STATUS_BLOCK IoStatus;
++
++    PVOID           NonPagedBuffer = NULL;
++
++    ASSERT(Buffer != NULL);
++
++#if 0
++    if (Ext2Sys->bFile)
++    {
++        Address.QuadPart = Offset;
++
++        Status = NtReadFile(  Ext2Sys->MediaHandle,
++                              0,
++                              NULL,
++                              NULL,
++                              &IoStatus,
++                              Buffer,
++                              Length,
++                              &Address,
++                              NULL );
++    }
++    else
++#endif
++    {
++        Address.QuadPart = Offset & (~((ULONGLONG)SECTOR_SIZE - 1));
++
++        AlignedLength = (Length + SECTOR_SIZE - 1)&(~(SECTOR_SIZE - 1));
++
++        AlignedLength += ((ULONG)(Offset - Address.QuadPart) + SECTOR_SIZE - 1)
++                         & (~(SECTOR_SIZE - 1));
++
++        NonPagedBuffer = RtlAllocateHeap(GetProcessHeap(), 0, AlignedLength);
++        if (!NonPagedBuffer)
++        {
++            Status = STATUS_INSUFFICIENT_RESOURCES;
++            goto errorout;
++        }
++
++        Status = NtReadFile( Ext2Sys->MediaHandle,
++                             0,
++                             NULL,
++                             NULL,
++                             &IoStatus,
++                             NonPagedBuffer,
++                             AlignedLength,
++                             &Address,
++                             NULL );
++
++        if (!NT_SUCCESS(Status))
++        {
++            goto errorout;
++        }
++
++        RtlCopyMemory( Buffer, 
++                       (PUCHAR)NonPagedBuffer + (ULONG)(Offset - Address.QuadPart),
++                       Length );
++    }
++ 
++errorout:
++
++    if (NonPagedBuffer)
++        RtlFreeHeap(GetProcessHeap(), 0, NonPagedBuffer);
++
++    return Status;
++}
++
++
++/*
++ * Ext2WriteDisk
++ *     Write data to disk ...
++ *
++ * ARGUMENTS:
++ *     VolumeHandle: Volume Handle
++ *     Offset      : Disk Offset
++ *     Length      : Data Length to be written
++ *     Buffer      : Data to be written ...
++ *
++ * RETURNS: 
++ *     Success: STATUS_SUCCESS
++ *     Fail:  ...
++ *
++ * NOTES: 
++ *     Both Length and Offset should be SECTOR_SIZE aligned.
++ */
++
++NTSTATUS
++Ext2WriteDisk( PEXT2_FILESYS  Ext2Sys,
++               ULONGLONG      Offset,
++               ULONG          Length,
++               PVOID          Buffer )
++{
++    LARGE_INTEGER   Address;
++    NTSTATUS        Status;
++    ULONG           AlignedLength;
++
++    IO_STATUS_BLOCK IoStatus;
++
++    PVOID           NonPagedBuffer = NULL;
++
++    ASSERT(Buffer != NULL);
++
++#if 0
++    if (Ext2Sys->bFile)
++    {
++        Address.QuadPart = Offset;
++
++        Status = NtWriteFile( Ext2Sys->MediaHandle,
++                              0,
++                              NULL,
++                              NULL,
++                              &IoStatus,
++                              Buffer,
++                              Length,
++                              &Address,
++                              NULL );
++    }
++    else
++#endif
++    {
++        Address.QuadPart = Offset & (~((ULONGLONG)SECTOR_SIZE - 1));
++
++        AlignedLength = (Length + SECTOR_SIZE - 1)&(~(SECTOR_SIZE - 1));
++
++        AlignedLength += ((ULONG)(Offset - Address.QuadPart) + SECTOR_SIZE - 1)
++                         & (~(SECTOR_SIZE - 1));
++
++        NonPagedBuffer = RtlAllocateHeap(GetProcessHeap(), 0, AlignedLength);
++        if (!NonPagedBuffer)
++        {
++            Status = STATUS_INSUFFICIENT_RESOURCES;
++            goto errorout;
++        }
++
++        if ((AlignedLength != Length) || (Address.QuadPart != (LONGLONG)Offset))
++        {
++            Status = NtReadFile( Ext2Sys->MediaHandle,
++                                 0,
++                                 NULL,
++                                 NULL,
++                                 &IoStatus,
++                                 NonPagedBuffer,
++                                 AlignedLength,
++                                 &Address,
++                                 NULL );
++
++            if (!NT_SUCCESS(Status))
++            {
++                goto errorout;
++            }
++        }
++
++        RtlCopyMemory( (PUCHAR)NonPagedBuffer + (ULONG)(Offset - Address.QuadPart),
++                       Buffer, Length );
++
++        Status = NtWriteFile( Ext2Sys->MediaHandle,
++                              0,
++                              NULL,
++                              NULL,
++                              &IoStatus,
++                              NonPagedBuffer,
++                              AlignedLength,
++                              &Address,
++                              NULL );
++    }
++
++errorout:
++
++    if (NonPagedBuffer)
++        RtlFreeHeap(GetProcessHeap(), 0, NonPagedBuffer);
++
++    return Status;
++}
++
++
++/*
++ * Ext2GetMediaInfo
++ *     Get volume gemmetry information ...
++ *
++ * ARGUMENTS:
++ *     VolumeHandle:    Volume handle.
++ *
++ * RETURNS: 
++ *     Success or Fail
++ *
++ * NOTES: 
++ *     N/A
++ */
++
++NTSTATUS
++Ext2GetMediaInfo( PEXT2_FILESYS Ext2Sys )
++{
++    NTSTATUS Status;
++    IO_STATUS_BLOCK IoSb;
++
++    Status = NtDeviceIoControlFile( Ext2Sys->MediaHandle,
++                                NULL, NULL, NULL, &IoSb,
++                                IOCTL_DISK_GET_DRIVE_GEOMETRY,
++                                &(Ext2Sys->DiskGeometry), sizeof(DISK_GEOMETRY),
++                                &(Ext2Sys->DiskGeometry), sizeof(DISK_GEOMETRY));
++
++
++    if (!NT_SUCCESS(Status))
++    {
++        goto errorout;
++    }
++
++    Status = NtDeviceIoControlFile( Ext2Sys->MediaHandle,
++                                NULL, NULL, NULL, &IoSb,
++                                IOCTL_DISK_GET_PARTITION_INFO,
++                                &(Ext2Sys->PartInfo), sizeof(PARTITION_INFORMATION),
++                                &(Ext2Sys->PartInfo), sizeof(PARTITION_INFORMATION));
++
++    if (!NT_SUCCESS(Status))
++    {
++        goto errorout;
++    }
++
++errorout:
++
++    return Status;
++}
++
++
++/*
++ * Ext2LockVolume
++ *     Lock the volume ...
++ *
++ * ARGUMENTS:
++ *     VolumeHandle:    Volume handle.
++ *
++ * RETURNS: 
++ *     Success or Fail
++ *
++ * NOTES: 
++ *     N/A
++ */
++
++
++NTSTATUS
++Ext2LockVolume( PEXT2_FILESYS Ext2Sys )
++{
++    NTSTATUS Status;
++    IO_STATUS_BLOCK IoSb;
++
++    Status = NtFsControlFile( Ext2Sys->MediaHandle,
++                              NULL, NULL, NULL, &IoSb,
++                              FSCTL_LOCK_VOLUME,
++                              NULL, 0, NULL, 0 );
++
++    if (!NT_SUCCESS(Status))
++    {
++        KdPrint(("Mke2fs: Error when locking volume: Status = %lxh %s...\n",
++                Status, Ext2StatusToString(Status)));
++
++        goto errorout;
++    }
++
++errorout:
++
++    return Status;
++}
++
++
++NTSTATUS
++Ext2UnLockVolume( PEXT2_FILESYS Ext2Sys )
++{
++    NTSTATUS Status;
++    IO_STATUS_BLOCK IoSb;
++
++    Status = NtFsControlFile( Ext2Sys->MediaHandle,
++                              NULL, NULL, NULL, &IoSb,
++                              FSCTL_UNLOCK_VOLUME,
++                              NULL, 0, NULL, 0 );
++
++    if (!NT_SUCCESS(Status))
++    {
++        KdPrint(("Mke2fs: Error when unlocking volume ...\n"));
++        goto errorout;
++    }
++
++errorout:
++
++    return Status;
++}
++
++
++NTSTATUS
++Ext2DisMountVolume( PEXT2_FILESYS Ext2Sys )
++{
++    NTSTATUS Status;
++    IO_STATUS_BLOCK IoSb;
++
++    Status = NtFsControlFile( Ext2Sys->MediaHandle,
++                              NULL, NULL, NULL, &IoSb,
++                              FSCTL_DISMOUNT_VOLUME,
++                              NULL, 0, NULL, 0 );
++
++    if (!NT_SUCCESS(Status))
++    {
++        KdPrint(("Mke2fs: Error when dismounting volume ...\n"));
++        goto errorout;
++    }
++
++errorout:
++
++    return Status;
++}
++
++NTSTATUS
++Ext2OpenDevice(  PEXT2_FILESYS Ext2Sys,
++                 PUNICODE_STRING DeviceName )
++{
++    NTSTATUS Status;
++    OBJECT_ATTRIBUTES ObjectAttributes;
++    HANDLE FileHandle;
++    IO_STATUS_BLOCK Iosb;
++
++    //
++    // Setup the name in an object attributes structure.
++    // Note that we create a name that is case INsensitive
++    //
++    InitializeObjectAttributes(&ObjectAttributes,           // ptr to structure
++                               DeviceName,                  // ptr to file spec
++                               OBJ_CASE_INSENSITIVE,        // attributes
++                               NULL,                        // root directory handle
++                               NULL );                      // ptr to security descriptor
++
++    //
++    // Do the create.  In this particular case, we'll have the I/O Manager
++    // make our write requests syncrhonous for our convenience.
++    //
++    Status = NtCreateFile(&FileHandle,                      // returned file handle
++                          (GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE),    // desired access
++                          &ObjectAttributes,                // ptr to object attributes
++                          &Iosb,                            // ptr to I/O status block
++                          0,                                // allocation size
++                          FILE_ATTRIBUTE_NORMAL,            // file attributes
++                          FILE_SHARE_WRITE | FILE_SHARE_READ, // share access
++                          FILE_OPEN  /*FILE_SUPERSEDE*/,    // create disposition
++                          FILE_SYNCHRONOUS_IO_NONALERT, // create options
++                          NULL,                             // ptr to extended attributes
++                          0);                               // length of ea buffer
++
++    //
++    // Check the system service status
++    //
++    if( !NT_SUCCESS(Status) )
++    {
++        KdPrint(("Mke2fs: Create system service failed status = 0x%lx\n", Status));
++        return Status;
++    }
++
++
++    //
++    // Check the returned status too...
++    //
++    if(!NT_SUCCESS(Iosb.Status) )
++    {
++        KdPrint(("Mke2fs: Create failed with status = 0x%lx\n",Iosb.Status));
++        return Status;
++    }
++
++    Ext2Sys->MediaHandle = FileHandle;
++
++    return Status;
++}
++
++
++NTSTATUS
++Ext2CloseDevice( PEXT2_FILESYS Ext2Sys)
++{
++    NTSTATUS Status = STATUS_SUCCESS;
++
++    if(Ext2Sys->MediaHandle)
++    {
++        Status = NtClose(Ext2Sys->MediaHandle);
++    }
++
++    return Status;
++}
index 0000000,f824a03..d23a14a
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,19 +1,19 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Disk.h\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -#ifndef _DISK_H_\r
 -#define _DISK_H_\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -#include "Stdafx.h"\r
 -\r
 -/* DEFINITIONS ***********************************************************/\r
 -\r
 -\r
 -\r
 -#endif /* _DISK_H_ */\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Disk.h
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++#ifndef _DISK_H_
++#define _DISK_H_
++
++/* INCLUDES **************************************************************/
++
++#include "Stdafx.h"
++
++/* DEFINITIONS ***********************************************************/
++
++
++
++#endif /* _DISK_H_ */
index 0000000,9f364b3..68ea974
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,68 +1,68 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Group.c\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -#include "Mke2fs.h"\r
 -\r
 -/* DEFINITIONS ***********************************************************/\r
 -\r
 -/* FUNCTIONS *************************************************************/\r
 -\r
 -int test_root(int a, int b)\r
 -{\r
 -    if (a == 0)\r
 -        return 1;\r
 -    while (1)\r
 -    {\r
 -        if (a == 1)\r
 -            return 1;\r
 -        if (a % b)\r
 -            return 0;\r
 -        a = a / b;\r
 -    }\r
 -}\r
 -\r
 -bool ext2_bg_has_super(PEXT2_SUPER_BLOCK pExt2Sb, int group_block)\r
 -{\r
 -    if (!(pExt2Sb->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))\r
 -        return true;\r
 -\r
 -    if (test_root(group_block, 3) || (test_root(group_block, 5)) ||\r
 -        test_root(group_block, 7))\r
 -        return true;\r
 -    \r
 -    return false;\r
 -}\r
 -\r
 -\r
 -bool ext2_allocate_group_desc(PEXT2_FILESYS Ext2Sys)\r
 -{\r
 -    ULONG size;\r
 -\r
 -    size = Ext2Sys->desc_blocks * Ext2Sys->blocksize;\r
 -\r
 -    Ext2Sys->group_desc =\r
 -        (PEXT2_GROUP_DESC)RtlAllocateHeap(GetProcessHeap(), 0, size);\r
 -\r
 -    if (Ext2Sys->group_desc)\r
 -    {\r
 -        memset(Ext2Sys->group_desc, 0, size);\r
 -        return true;\r
 -    }\r
 -\r
 -    return false;\r
 -}\r
 -\r
 -void ext2_free_group_desc(PEXT2_FILESYS Ext2Sys)\r
 -{\r
 -    if (Ext2Sys->group_desc)\r
 -    {\r
 -        RtlFreeHeap(GetProcessHeap(), 0, Ext2Sys->group_desc);\r
 -        Ext2Sys->group_desc = NULL;\r
 -    }\r
 -}\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Group.c
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++/* INCLUDES **************************************************************/
++
++#include "Mke2fs.h"
++
++/* DEFINITIONS ***********************************************************/
++
++/* FUNCTIONS *************************************************************/
++
++int test_root(int a, int b)
++{
++    if (a == 0)
++        return 1;
++    while (1)
++    {
++        if (a == 1)
++            return 1;
++        if (a % b)
++            return 0;
++        a = a / b;
++    }
++}
++
++bool ext2_bg_has_super(PEXT2_SUPER_BLOCK pExt2Sb, int group_block)
++{
++    if (!(pExt2Sb->s_feature_ro_compat & EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER))
++        return true;
++
++    if (test_root(group_block, 3) || (test_root(group_block, 5)) ||
++        test_root(group_block, 7))
++        return true;
++    
++    return false;
++}
++
++
++bool ext2_allocate_group_desc(PEXT2_FILESYS Ext2Sys)
++{
++    ULONG size;
++
++    size = Ext2Sys->desc_blocks * Ext2Sys->blocksize;
++
++    Ext2Sys->group_desc =
++        (PEXT2_GROUP_DESC)RtlAllocateHeap(GetProcessHeap(), 0, size);
++
++    if (Ext2Sys->group_desc)
++    {
++        memset(Ext2Sys->group_desc, 0, size);
++        return true;
++    }
++
++    return false;
++}
++
++void ext2_free_group_desc(PEXT2_FILESYS Ext2Sys)
++{
++    if (Ext2Sys->group_desc)
++    {
++        RtlFreeHeap(GetProcessHeap(), 0, Ext2Sys->group_desc);
++        Ext2Sys->group_desc = NULL;
++    }
++}
index 0000000,64d95a9..9b23597
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,697 +1,697 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Inode.c\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -#include "Mke2fs.h"\r
 -\r
 -/* DEFINITIONS ***********************************************************/\r
 -\r
 -extern char *device_name;\r
 -\r
 -/* FUNCTIONS *************************************************************/\r
 -\r
 -\r
 -bool ext2_get_inode_lba(PEXT2_FILESYS Ext2Sys, ULONG no, LONGLONG *offset)\r
 -{\r
 -    LONGLONG loc = 0;\r
 -    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;\r
 -\r
 -    if (no < 1 || no > pExt2Sb->s_inodes_count)\r
 -    {\r
 -        KdPrint(("Mke2fs: Inode value %lu was out of range in load_inode.(1-%ld)\n",\r
 -            no, pExt2Sb->s_inodes_count));\r
 -        *offset = 0;\r
 -        return false;\r
 -    }\r
 -\r
 -    loc = (LONGLONG)(Ext2Sys->blocksize) * Ext2Sys->group_desc[(no - 1) / pExt2Sb->s_inodes_per_group].bg_inode_table +\r
 -        ((no - 1) % pExt2Sb->s_inodes_per_group) * sizeof(EXT2_INODE);\r
 -\r
 -    *offset = loc;\r
 -\r
 -    return true;    \r
 -}\r
 -\r
 -bool ext2_load_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode)\r
 -{\r
 -    LONGLONG Offset;\r
 -    bool  bRet = false;\r
 -\r
 -    if (ext2_get_inode_lba(Ext2Sys, no, &Offset))\r
 -    {\r
 -        bRet = NT_SUCCESS(Ext2ReadDisk(\r
 -                    Ext2Sys,\r
 -                    Offset,\r
 -                    sizeof(EXT2_INODE),\r
 -                    (unsigned char *)pInode));\r
 -    }\r
 -\r
 -    return bRet;\r
 -}\r
 -\r
 -\r
 -bool ext2_save_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode)\r
 -{\r
 -    LONGLONG offset;\r
 -    bool  bRet = false;\r
 -\r
 -    if (ext2_get_inode_lba(Ext2Sys, no, &offset))\r
 -    {\r
 -        bRet = NT_SUCCESS(Ext2WriteDisk(\r
 -                        Ext2Sys,\r
 -                        offset, \r
 -                        sizeof(EXT2_INODE),\r
 -                        (unsigned char *)pInode));\r
 -    }\r
 -\r
 -    return bRet;\r
 -}\r
 -\r
 -\r
 -/*\r
 - * Right now, just search forward from the parent directory's block\r
 - * group to find the next free inode.\r
 - *\r
 - * Should have a special policy for directories.\r
 - */\r
 -\r
 -bool ext2_new_inode(PEXT2_FILESYS fs, ULONG dir, int mode,\r
 -                      PEXT2_INODE_BITMAP map, ULONG *ret)\r
 -{\r
 -    ULONG   dir_group = 0;\r
 -    ULONG   i;\r
 -    ULONG   start_inode;\r
 -\r
 -    if (!map)\r
 -        map = fs->inode_map;\r
 -\r
 -    if (!map)\r
 -        return false;\r
 -    \r
 -    if (dir > 0) \r
 -        dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->ext2_sb);\r
 -\r
 -    start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->ext2_sb)) + 1;\r
 -    \r
 -    if (start_inode < EXT2_FIRST_INODE(fs->ext2_sb))\r
 -        start_inode = EXT2_FIRST_INODE(fs->ext2_sb);\r
 -\r
 -    i = start_inode;\r
 -\r
 -    do\r
 -    {\r
 -        if (!ext2_test_inode_bitmap(map, i))\r
 -            break;\r
 -\r
 -        i++;\r
 -\r
 -        if (i > fs->ext2_sb->s_inodes_count)\r
 -            i = EXT2_FIRST_INODE(fs->ext2_sb);\r
 -\r
 -    } while (i != start_inode);\r
 -    \r
 -    if (ext2_test_inode_bitmap(map, i))\r
 -        return false;\r
 -\r
 -    *ret = i;\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -\r
 -bool ext2_expand_block( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode,\r
 -                        ULONG dwContent, ULONG Index, int layer,\r
 -                        ULONG newBlk, ULONG *dwRet, ULONG *off  )\r
 -{\r
 -    ULONG       *pData = NULL;\r
 -    ULONG       i = 0, j = 0, temp = 1;\r
 -    ULONG       dwBlk;\r
 -    ULONG       dwNewBlk = newBlk;\r
 -    bool        bDirty = false;\r
 -    bool        bRet = true;\r
 -    ULONG       Offset = 0;\r
 -\r
 -    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;\r
 - \r
 -    pData = (ULONG *)RtlAllocateHeap(GetProcessHeap(), 0, Ext2Sys->blocksize);\r
 -    \r
 -    if (!pData)\r
 -    {\r
 -        bRet = false;\r
 -        goto errorout;\r
 -    }\r
 -    \r
 -    if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData))\r
 -    {\r
 -        bRet = false;\r
 -        goto errorout;\r
 -    }\r
 -    \r
 -    if (layer == 1)\r
 -    {\r
 -        *dwRet = dwContent;\r
 -        *off   = Index;\r
 -        pData[Index] = newBlk;\r
 -\r
 -        bDirty = TRUE;\r
 -    }\r
 -    else if (layer <= 3)\r
 -    {\r
 -        temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1));\r
 -\r
 -        i = Index / temp;\r
 -        j = Index % temp;\r
 -\r
 -        dwBlk = pData[i];\r
 -        \r
 -        if (dwBlk == 0)\r
 -        {\r
 -            if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) )\r
 -            {\r
 -                pData[i] = dwBlk;\r
 -                bDirty = true;\r
 -\r
 -                Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE);\r
 -            }\r
 -            \r
 -            if (!bDirty)\r
 -                goto errorout;\r
 -        }\r
 -        \r
 -        if (!ext2_expand_block(Ext2Sys, Inode, dwBlk, j, layer - 1, bDirty, &dwNewBlk, &Offset))\r
 -        {\r
 -            bRet = false;\r
 -            KdPrint(("Mke2fs: ext2_expand_block: ... error recuise...\n"));\r
 -            goto errorout;\r
 -        }\r
 -    }\r
 -\r
 -    if (bDirty)\r
 -    {\r
 -        bRet = ext2_write_block(Ext2Sys, dwContent, (void *)pData);\r
 -    }\r
 -\r
 -\r
 -errorout:\r
 -\r
 -    if (pData)\r
 -        RtlFreeHeap(GetProcessHeap(), 0, pData);\r
 -\r
 -    if (bRet && dwRet)\r
 -        *dwRet = dwNewBlk;\r
 -\r
 -    return bRet;\r
 -}\r
 -\r
 -bool ext2_expand_inode( PEXT2_FILESYS Ext2Sys,\r
 -                        PEXT2_INODE Inode,\r
 -                        ULONG newBlk         )\r
 -{\r
 -    ULONG dwSizes[4] = {12, 1, 1, 1};\r
 -    ULONG Index = 0;\r
 -    ULONG dwTotal = 0;\r
 -    ULONG dwBlk = 0, dwNewBlk = 0, Offset = 0;\r
 -    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;\r
 -    int   i = 0;\r
 -    bool  bRet = true;\r
 -    bool  bDirty = false;\r
 -    ULONG TotalBlocks;\r
 -\r
 -    TotalBlocks = Inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE);\r
 -    Index = Ext2DataBlocks(Ext2Sys, TotalBlocks);\r
 -\r
 -    for (i = 0; i < 4; i++)\r
 -    {\r
 -        dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i);\r
 -        dwTotal += dwSizes[i];\r
 -    }\r
 -\r
 -    if (Index >= dwTotal)\r
 -    {\r
 -        KdPrint(("Mke2fs: ext2_expand_inode: beyond the maxinum size of an inode.\n"));\r
 -        return false;\r
 -    }\r
 -\r
 -    for (i = 0; i < 4; i++)\r
 -    {\r
 -        if (Index < dwSizes[i])\r
 -        {\r
 -            if (i == 0)\r
 -            {\r
 -                Inode->i_block[Index] = newBlk;\r
 -                bDirty = true;\r
 -            }\r
 -            else\r
 -            {\r
 -                dwBlk = Inode->i_block[(i + 12 - 1)];\r
 -\r
 -                if (dwBlk == 0)\r
 -                {\r
 -                    if (ext2_alloc_block(Ext2Sys, 0, &dwBlk))\r
 -                    {\r
 -                        Inode->i_block[(i + 12 - 1)] = dwBlk;\r
 -                        bDirty = true;\r
 -\r
 -                        Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE);\r
 -                    }\r
 -                    else\r
 -                    {\r
 -                        break;\r
 -                    }\r
 -                }\r
 -\r
 -                dwNewBlk = 0;\r
 -                bRet = ext2_expand_block(\r
 -                             Ext2Sys,\r
 -                             Inode,\r
 -                             dwBlk,\r
 -                             Index,\r
 -                             i,\r
 -                             newBlk,\r
 -                             &dwNewBlk,\r
 -                             &Offset   );\r
 -            }\r
 -            \r
 -            break;\r
 -        }\r
 -\r
 -        Index -= dwSizes[i];\r
 -    }\r
 -\r
 -    return bRet;\r
 -}\r
 -\r
 -\r
 -bool ext2_get_block(PEXT2_FILESYS Ext2Sys, ULONG dwContent, ULONG Index, int layer, ULONG *dwRet)\r
 -{\r
 -    ULONG       *pData = NULL;\r
 -    LONGLONG    Offset = 0;\r
 -    ULONG       i = 0, j = 0, temp = 1;\r
 -    ULONG       dwBlk = 0;\r
 -    bool        bRet = true;\r
 -\r
 -    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;\r
 -\r
 -    Offset = (LONGLONG) dwContent;\r
 -    Offset = Offset * Ext2Sys->blocksize;\r
 -\r
 -    pData = (ULONG *)RtlAllocateHeap(GetProcessHeap(), 0, Ext2Sys->blocksize);\r
 -\r
 -    if (!pData)\r
 -    {\r
 -        return false;\r
 -    }\r
 -    memset(pData, 0, Ext2Sys->blocksize);\r
 -\r
 -    if (layer == 0)\r
 -    {\r
 -        dwBlk = dwContent;\r
 -    }\r
 -    else if (layer <= 3)\r
 -    {\r
 -\r
 -        if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData))\r
 -        {\r
 -            bRet = false;\r
 -            goto errorout;\r
 -        }\r
 -\r
 -        temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1));\r
 -\r
 -        i = Index / temp;\r
 -        j = Index % temp;\r
 -\r
 -        if (!ext2_get_block(Ext2Sys, pData[i], j, layer - 1, &dwBlk))\r
 -        {\r
 -            bRet = false;\r
 -            KdPrint(("Mke2fs: ext2_get_block: ... error recuise...\n"));\r
 -            goto errorout;\r
 -        }\r
 -    }\r
 -\r
 -errorout:\r
 -\r
 -    if (pData)\r
 -        RtlFreeHeap(GetProcessHeap(), 0, pData);\r
 -\r
 -    if (bRet && dwRet)\r
 -        *dwRet = dwBlk;\r
 -\r
 -    return bRet;\r
 -}\r
 -\r
 -bool ext2_block_map(PEXT2_FILESYS Ext2Sys, PEXT2_INODE inode, ULONG block, ULONG *dwRet)\r
 -{\r
 -    ULONG dwSizes[4] = {12, 1, 1, 1};\r
 -    ULONG Index = 0;\r
 -    ULONG dwBlk = 0;\r
 -    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;\r
 -    int   i;\r
 -    bool  bRet = false;\r
 -\r
 -    Index = block;\r
 -\r
 -    for (i = 0; i < 4; i++)\r
 -    {\r
 -        dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i);\r
 -    }\r
 -\r
 -    if (Index >= inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE))\r
 -    {\r
 -        KdPrint(("Mke2fs: ext2_block_map: beyond the size of the inode.\n"));\r
 -        return false;\r
 -    }\r
 -\r
 -    for (i = 0; i < 4; i++)\r
 -    {\r
 -        if (Index < dwSizes[i])\r
 -        {\r
 -            dwBlk = inode->i_block[i==0 ? (Index):(i + 12 - 1)];\r
 -\r
 -            bRet = ext2_get_block(Ext2Sys, dwBlk, Index , i, &dwBlk); \r
 -\r
 -            break;\r
 -        }\r
 -        Index -= dwSizes[i];\r
 -    }\r
 -\r
 -    if (bRet && dwBlk)\r
 -    {\r
 -        if (dwRet)\r
 -            *dwRet = dwBlk;\r
 -\r
 -        return true;\r
 -    }\r
 -    else\r
 -        return false;\r
 -}\r
 -\r
 -ULONG ext2_build_bdl(PEXT2_FILESYS Ext2Sys,\r
 -                    PEXT2_INODE ext2_inode,\r
 -                    IN ULONG offset, \r
 -                    IN ULONG size, \r
 -                    OUT PEXT2_BDL *ext2_bdl )\r
 -{\r
 -    ULONG   nBeg, nEnd, nBlocks;\r
 -    ULONG   dwBlk;\r
 -    ULONG   i;\r
 -    ULONG   dwBytes = 0;\r
 -    LONGLONG lba;\r
 -\r
 -    PEXT2_BDL   ext2bdl = NULL;\r
 -\r
 -    *ext2_bdl = NULL;\r
 -\r
 -    if (offset >= ext2_inode->i_size)\r
 -    {\r
 -        KdPrint(("Mke2fs: ext2_build_bdl: beyond the file range.\n"));\r
 -        return 0;\r
 -    }\r
 -\r
 -/*\r
 -    if (offset + size > ext2_inode->i_size)\r
 -    {\r
 -        size = ext2_inode->i_size - offset;\r
 -    }\r
 -*/\r
 -\r
 -    nBeg = offset / Ext2Sys->blocksize;\r
 -    nEnd = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize;\r
 -\r
 -    nBlocks = nEnd - nBeg;\r
 -\r
 -    if (nBlocks > 0)\r
 -    {\r
 -        ext2bdl = (PEXT2_BDL)\r
 -            RtlAllocateHeap(GetProcessHeap(), 0, sizeof(EXT2_BDL) * nBlocks);\r
 -\r
 -        if (ext2bdl)\r
 -        {\r
 -\r
 -            memset(ext2bdl, 0, sizeof(EXT2_BDL) * nBlocks);\r
 -            \r
 -            for (i = nBeg; i < nEnd; i++)\r
 -            {\r
 -                if (!ext2_block_map(Ext2Sys, ext2_inode, i, &dwBlk))\r
 -                {\r
 -                    goto fail;\r
 -                }\r
 -                \r
 -                lba = (LONGLONG) dwBlk;\r
 -                lba = lba * Ext2Sys->blocksize;\r
 -                \r
 -                if (nBlocks == 1) // ie. (nBeg == nEnd - 1)\r
 -                {\r
 -                    dwBytes = size;\r
 -                    ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize));\r
 -                    ext2bdl[i - nBeg].Length = dwBytes;\r
 -                    ext2bdl[i - nBeg].Offset = 0;\r
 -                }\r
 -                else\r
 -                {\r
 -                    if (i == nBeg)\r
 -                    {\r
 -                        dwBytes = Ext2Sys->blocksize - (offset % (Ext2Sys->blocksize));\r
 -                        ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize));\r
 -                        ext2bdl[i - nBeg].Length = dwBytes;\r
 -                        ext2bdl[i - nBeg].Offset = 0;\r
 -                    }\r
 -                    else if (i == nEnd - 1)\r
 -                    {\r
 -                        ext2bdl[i - nBeg].Lba = lba;\r
 -                        ext2bdl[i - nBeg].Length = size - dwBytes;\r
 -                        ext2bdl[i - nBeg].Offset = dwBytes;\r
 -                        dwBytes = size;\r
 -                    }\r
 -                    else\r
 -                    {\r
 -                        ext2bdl[i - nBeg].Lba = lba;\r
 -                        ext2bdl[i - nBeg].Length = Ext2Sys->blocksize;\r
 -                        ext2bdl[i - nBeg].Offset = dwBytes;\r
 -                        dwBytes +=  Ext2Sys->blocksize;\r
 -                    }\r
 -                }\r
 -            }\r
 -\r
 -            *ext2_bdl = ext2bdl;\r
 -            return nBlocks;\r
 -        }\r
 -    }\r
 -\r
 -fail:\r
 -\r
 -    if (ext2bdl)\r
 -        RtlFreeHeap(GetProcessHeap(), 0, ext2bdl);\r
 -\r
 -    // Error\r
 -    return 0;\r
 -}\r
 -\r
 -\r
 -bool ext2_read_inode(PEXT2_FILESYS Ext2Sys,\r
 -            ULONG               ino,\r
 -            ULONG               offset,\r
 -            PVOID               Buffer,\r
 -            ULONG               size,\r
 -            PULONG              dwReturn)\r
 -{\r
 -    PEXT2_BDL   ext2_bdl = NULL;\r
 -    ULONG       blocks, i;\r
 -    bool        bRet = true;\r
 -    EXT2_INODE  ext2_inode;\r
 -    ULONG       dwTotal = 0;\r
 -\r
 -    if (!ext2_load_inode(Ext2Sys, ino, &ext2_inode))\r
 -    {\r
 -        return false;\r
 -    }\r
 -\r
 -    blocks = ext2_build_bdl(Ext2Sys, &ext2_inode, offset, size, &ext2_bdl);\r
 -\r
 -    if (blocks <= 0)\r
 -        return  false;\r
 -    \r
 -   \r
 -    for(i = 0; i < blocks; i++)\r
 -    {\r
 -        bRet = NT_SUCCESS(Ext2ReadDisk(\r
 -                Ext2Sys,\r
 -                ext2_bdl[i].Lba, \r
 -                ext2_bdl[i].Length,\r
 -                (PUCHAR)Buffer + ext2_bdl[i].Offset\r
 -               ));\r
 -\r
 -        if (!bRet)\r
 -            break;\r
 -        dwTotal += ext2_bdl[i].Length;\r
 -    }\r
 -\r
 -    *dwReturn = dwTotal;\r
 -\r
 -    if (ext2_bdl)\r
 -        RtlFreeHeap(GetProcessHeap(), 0, ext2_bdl);\r
 -\r
 -    return bRet;\r
 -}\r
 -\r
 -\r
 -bool ext2_write_inode (PEXT2_FILESYS Ext2Sys,\r
 -            ULONG               ino,\r
 -            ULONG               offset,\r
 -            PVOID               Buffer,\r
 -            ULONG               size,\r
 -            PULONG              dwReturn )\r
 -{\r
 -    PEXT2_BDL   ext2_bdl = NULL;\r
 -    ULONG       blocks, i;\r
 -    bool        bRet = true;\r
 -    EXT2_INODE  inode;\r
 -    ULONG       dwTotal = 0;\r
 -    ULONG       dwBlk = 0;\r
 -    ULONG       TotalBlks;\r
 -\r
 -    blocks =  (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize;\r
 -\r
 -    if (!ext2_load_inode(Ext2Sys, ino, &inode))\r
 -    {\r
 -        return false;\r
 -    }\r
 -\r
 -    TotalBlks = inode.i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE);\r
 -    TotalBlks = Ext2DataBlocks(Ext2Sys, TotalBlks);\r
 -\r
 -    if (blocks > TotalBlks)\r
 -    {\r
 -        for (i=0; i < (blocks - TotalBlks);  i++)\r
 -        {\r
 -            if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) )\r
 -            {\r
 -                ext2_expand_inode(Ext2Sys, &inode, dwBlk);\r
 -                inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE);\r
 -            }\r
 -        }\r
 -    }\r
 -\r
 -    blocks = ext2_build_bdl(Ext2Sys, &inode, offset, size, &ext2_bdl);\r
 -\r
 -    if (blocks <= 0)\r
 -        return  false;\r
 -    \r
 -    for(i = 0; i < blocks; i++)\r
 -    {\r
 -        bRet = NT_SUCCESS(Ext2WriteDisk(\r
 -                Ext2Sys,\r
 -                ext2_bdl[i].Lba, \r
 -                ext2_bdl[i].Length,\r
 -                (PUCHAR)Buffer + ext2_bdl[i].Offset\r
 -               ));\r
 -\r
 -        if (!bRet)\r
 -        {\r
 -            goto errorout;\r
 -        }\r
 -\r
 -        dwTotal += ext2_bdl[i].Length;\r
 -    }\r
 -\r
 -    *dwReturn = dwTotal;\r
 -\r
 -    if (size + offset > inode.i_size)\r
 -    {\r
 -        inode.i_size = size + offset;\r
 -    }\r
 -\r
 -    ext2_save_inode(Ext2Sys, ino, &inode);\r
 -\r
 -\r
 -errorout:\r
 -   \r
 -    if (ext2_bdl)\r
 -        RtlFreeHeap(GetProcessHeap(), 0, ext2_bdl);\r
 -\r
 -    return bRet;\r
 -}\r
 -\r
 -bool\r
 -ext2_add_entry( PEXT2_FILESYS Ext2Sys,\r
 -                ULONG parent, ULONG inode,\r
 -                int filetype, char *name )\r
 -{\r
 -    PEXT2_DIR_ENTRY2  dir = NULL, newdir = NULL;\r
 -    EXT2_INODE      parent_inode;\r
 -    ULONG       dwRet;\r
 -    char        *buf;\r
 -    int         rec_len;\r
 -    bool        bRet = false;\r
 -\r
 -    rec_len = EXT2_DIR_REC_LEN(strlen(name));\r
 -\r
 -    if (!ext2_load_inode(Ext2Sys, parent, &parent_inode))\r
 -    {\r
 -        return false;\r
 -    }\r
 -\r
 -    buf = (char *)RtlAllocateHeap(GetProcessHeap(), 0, parent_inode.i_size);\r
 -\r
 -    if (!ext2_read_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet))\r
 -    {\r
 -        return false;\r
 -    }\r
 -\r
 -    dir = (PEXT2_DIR_ENTRY2) buf;\r
 -\r
 -    while ((char *)dir < buf + parent_inode.i_size)\r
 -    {\r
 -        if ((dir->inode == 0 && dir->rec_len >= rec_len) || \r
 -               (dir->rec_len >= dir->name_len + rec_len) )\r
 -        {\r
 -            if (dir->inode)\r
 -            {\r
 -                newdir = (PEXT2_DIR_ENTRY2) ((PUCHAR)dir + EXT2_DIR_REC_LEN(dir->name_len));\r
 -                newdir->rec_len = dir->rec_len - EXT2_DIR_REC_LEN(dir->name_len);\r
 -\r
 -                dir->rec_len = EXT2_DIR_REC_LEN(dir->name_len);\r
 -\r
 -                dir = newdir;\r
 -            }\r
 -\r
 -            dir->file_type = filetype;\r
 -            dir->inode = inode;\r
 -            dir->name_len = strlen(name);\r
 -            memcpy(dir->name, name, strlen(name));\r
 -    \r
 -            bRet = true;\r
 -            break;\r
 -        }\r
 -\r
 -        dir = (PEXT2_DIR_ENTRY2) (dir->rec_len + (PUCHAR) dir);\r
 -    }\r
 -\r
 -\r
 -    if (bRet)\r
 -        return ext2_write_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet);\r
 -\r
 -    return bRet;\r
 -}\r
 -\r
 -\r
 -bool ext2_reserve_inodes(PEXT2_FILESYS fs)\r
 -{\r
 -    ULONG   i;\r
 -    int     group;\r
 -\r
 -    for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->ext2_sb); i++)\r
 -    {\r
 -        ext2_mark_inode_bitmap(fs->inode_map, i);\r
 -        group = ext2_group_of_ino(fs, i);\r
 -        fs->group_desc[group].bg_free_inodes_count--;\r
 -        fs->ext2_sb->s_free_inodes_count--;\r
 -    }\r
 -\r
 -    return true;\r
 -}\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Inode.c
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++/* INCLUDES **************************************************************/
++
++#include "Mke2fs.h"
++
++/* DEFINITIONS ***********************************************************/
++
++extern char *device_name;
++
++/* FUNCTIONS *************************************************************/
++
++
++bool ext2_get_inode_lba(PEXT2_FILESYS Ext2Sys, ULONG no, LONGLONG *offset)
++{
++    LONGLONG loc = 0;
++    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
++
++    if (no < 1 || no > pExt2Sb->s_inodes_count)
++    {
++        KdPrint(("Mke2fs: Inode value %lu was out of range in load_inode.(1-%ld)\n",
++            no, pExt2Sb->s_inodes_count));
++        *offset = 0;
++        return false;
++    }
++
++    loc = (LONGLONG)(Ext2Sys->blocksize) * Ext2Sys->group_desc[(no - 1) / pExt2Sb->s_inodes_per_group].bg_inode_table +
++        ((no - 1) % pExt2Sb->s_inodes_per_group) * sizeof(EXT2_INODE);
++
++    *offset = loc;
++
++    return true;    
++}
++
++bool ext2_load_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode)
++{
++    LONGLONG Offset;
++    bool  bRet = false;
++
++    if (ext2_get_inode_lba(Ext2Sys, no, &Offset))
++    {
++        bRet = NT_SUCCESS(Ext2ReadDisk(
++                    Ext2Sys,
++                    Offset,
++                    sizeof(EXT2_INODE),
++                    (unsigned char *)pInode));
++    }
++
++    return bRet;
++}
++
++
++bool ext2_save_inode(PEXT2_FILESYS Ext2Sys, ULONG no, PEXT2_INODE pInode)
++{
++    LONGLONG offset;
++    bool  bRet = false;
++
++    if (ext2_get_inode_lba(Ext2Sys, no, &offset))
++    {
++        bRet = NT_SUCCESS(Ext2WriteDisk(
++                        Ext2Sys,
++                        offset, 
++                        sizeof(EXT2_INODE),
++                        (unsigned char *)pInode));
++    }
++
++    return bRet;
++}
++
++
++/*
++ * Right now, just search forward from the parent directory's block
++ * group to find the next free inode.
++ *
++ * Should have a special policy for directories.
++ */
++
++bool ext2_new_inode(PEXT2_FILESYS fs, ULONG dir, int mode,
++                      PEXT2_INODE_BITMAP map, ULONG *ret)
++{
++    ULONG   dir_group = 0;
++    ULONG   i;
++    ULONG   start_inode;
++
++    if (!map)
++        map = fs->inode_map;
++
++    if (!map)
++        return false;
++    
++    if (dir > 0) 
++        dir_group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->ext2_sb);
++
++    start_inode = (dir_group * EXT2_INODES_PER_GROUP(fs->ext2_sb)) + 1;
++    
++    if (start_inode < EXT2_FIRST_INODE(fs->ext2_sb))
++        start_inode = EXT2_FIRST_INODE(fs->ext2_sb);
++
++    i = start_inode;
++
++    do
++    {
++        if (!ext2_test_inode_bitmap(map, i))
++            break;
++
++        i++;
++
++        if (i > fs->ext2_sb->s_inodes_count)
++            i = EXT2_FIRST_INODE(fs->ext2_sb);
++
++    } while (i != start_inode);
++    
++    if (ext2_test_inode_bitmap(map, i))
++        return false;
++
++    *ret = i;
++
++    return true;
++}
++
++
++bool ext2_expand_block( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode,
++                        ULONG dwContent, ULONG Index, int layer,
++                        ULONG newBlk, ULONG *dwRet, ULONG *off  )
++{
++    ULONG       *pData = NULL;
++    ULONG       i = 0, j = 0, temp = 1;
++    ULONG       dwBlk;
++    ULONG       dwNewBlk = newBlk;
++    bool        bDirty = false;
++    bool        bRet = true;
++    ULONG       Offset = 0;
++
++    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
++ 
++    pData = (ULONG *)RtlAllocateHeap(GetProcessHeap(), 0, Ext2Sys->blocksize);
++    
++    if (!pData)
++    {
++        bRet = false;
++        goto errorout;
++    }
++    
++    if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData))
++    {
++        bRet = false;
++        goto errorout;
++    }
++    
++    if (layer == 1)
++    {
++        *dwRet = dwContent;
++        *off   = Index;
++        pData[Index] = newBlk;
++
++        bDirty = TRUE;
++    }
++    else if (layer <= 3)
++    {
++        temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1));
++
++        i = Index / temp;
++        j = Index % temp;
++
++        dwBlk = pData[i];
++        
++        if (dwBlk == 0)
++        {
++            if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) )
++            {
++                pData[i] = dwBlk;
++                bDirty = true;
++
++                Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE);
++            }
++            
++            if (!bDirty)
++                goto errorout;
++        }
++        
++        if (!ext2_expand_block(Ext2Sys, Inode, dwBlk, j, layer - 1, bDirty, &dwNewBlk, &Offset))
++        {
++            bRet = false;
++            KdPrint(("Mke2fs: ext2_expand_block: ... error recuise...\n"));
++            goto errorout;
++        }
++    }
++
++    if (bDirty)
++    {
++        bRet = ext2_write_block(Ext2Sys, dwContent, (void *)pData);
++    }
++
++
++errorout:
++
++    if (pData)
++        RtlFreeHeap(GetProcessHeap(), 0, pData);
++
++    if (bRet && dwRet)
++        *dwRet = dwNewBlk;
++
++    return bRet;
++}
++
++bool ext2_expand_inode( PEXT2_FILESYS Ext2Sys,
++                        PEXT2_INODE Inode,
++                        ULONG newBlk         )
++{
++    ULONG dwSizes[4] = {12, 1, 1, 1};
++    ULONG Index = 0;
++    ULONG dwTotal = 0;
++    ULONG dwBlk = 0, dwNewBlk = 0, Offset = 0;
++    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
++    int   i = 0;
++    bool  bRet = true;
++    bool  bDirty = false;
++    ULONG TotalBlocks;
++
++    TotalBlocks = Inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE);
++    Index = Ext2DataBlocks(Ext2Sys, TotalBlocks);
++
++    for (i = 0; i < 4; i++)
++    {
++        dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i);
++        dwTotal += dwSizes[i];
++    }
++
++    if (Index >= dwTotal)
++    {
++        KdPrint(("Mke2fs: ext2_expand_inode: beyond the maxinum size of an inode.\n"));
++        return false;
++    }
++
++    for (i = 0; i < 4; i++)
++    {
++        if (Index < dwSizes[i])
++        {
++            if (i == 0)
++            {
++                Inode->i_block[Index] = newBlk;
++                bDirty = true;
++            }
++            else
++            {
++                dwBlk = Inode->i_block[(i + 12 - 1)];
++
++                if (dwBlk == 0)
++                {
++                    if (ext2_alloc_block(Ext2Sys, 0, &dwBlk))
++                    {
++                        Inode->i_block[(i + 12 - 1)] = dwBlk;
++                        bDirty = true;
++
++                        Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE);
++                    }
++                    else
++                    {
++                        break;
++                    }
++                }
++
++                dwNewBlk = 0;
++                bRet = ext2_expand_block(
++                             Ext2Sys,
++                             Inode,
++                             dwBlk,
++                             Index,
++                             i,
++                             newBlk,
++                             &dwNewBlk,
++                             &Offset   );
++            }
++            
++            break;
++        }
++
++        Index -= dwSizes[i];
++    }
++
++    return bRet;
++}
++
++
++bool ext2_get_block(PEXT2_FILESYS Ext2Sys, ULONG dwContent, ULONG Index, int layer, ULONG *dwRet)
++{
++    ULONG       *pData = NULL;
++    LONGLONG    Offset = 0;
++    ULONG       i = 0, j = 0, temp = 1;
++    ULONG       dwBlk = 0;
++    bool        bRet = true;
++
++    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
++
++    Offset = (LONGLONG) dwContent;
++    Offset = Offset * Ext2Sys->blocksize;
++
++    pData = (ULONG *)RtlAllocateHeap(GetProcessHeap(), 0, Ext2Sys->blocksize);
++
++    if (!pData)
++    {
++        return false;
++    }
++    memset(pData, 0, Ext2Sys->blocksize);
++
++    if (layer == 0)
++    {
++        dwBlk = dwContent;
++    }
++    else if (layer <= 3)
++    {
++
++        if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData))
++        {
++            bRet = false;
++            goto errorout;
++        }
++
++        temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1));
++
++        i = Index / temp;
++        j = Index % temp;
++
++        if (!ext2_get_block(Ext2Sys, pData[i], j, layer - 1, &dwBlk))
++        {
++            bRet = false;
++            KdPrint(("Mke2fs: ext2_get_block: ... error recuise...\n"));
++            goto errorout;
++        }
++    }
++
++errorout:
++
++    if (pData)
++        RtlFreeHeap(GetProcessHeap(), 0, pData);
++
++    if (bRet && dwRet)
++        *dwRet = dwBlk;
++
++    return bRet;
++}
++
++bool ext2_block_map(PEXT2_FILESYS Ext2Sys, PEXT2_INODE inode, ULONG block, ULONG *dwRet)
++{
++    ULONG dwSizes[4] = {12, 1, 1, 1};
++    ULONG Index = 0;
++    ULONG dwBlk = 0;
++    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
++    int   i;
++    bool  bRet = false;
++
++    Index = block;
++
++    for (i = 0; i < 4; i++)
++    {
++        dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i);
++    }
++
++    if (Index >= inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE))
++    {
++        KdPrint(("Mke2fs: ext2_block_map: beyond the size of the inode.\n"));
++        return false;
++    }
++
++    for (i = 0; i < 4; i++)
++    {
++        if (Index < dwSizes[i])
++        {
++            dwBlk = inode->i_block[i==0 ? (Index):(i + 12 - 1)];
++
++            bRet = ext2_get_block(Ext2Sys, dwBlk, Index , i, &dwBlk); 
++
++            break;
++        }
++        Index -= dwSizes[i];
++    }
++
++    if (bRet && dwBlk)
++    {
++        if (dwRet)
++            *dwRet = dwBlk;
++
++        return true;
++    }
++    else
++        return false;
++}
++
++ULONG ext2_build_bdl(PEXT2_FILESYS Ext2Sys,
++                    PEXT2_INODE ext2_inode,
++                    IN ULONG offset, 
++                    IN ULONG size, 
++                    OUT PEXT2_BDL *ext2_bdl )
++{
++    ULONG   nBeg, nEnd, nBlocks;
++    ULONG   dwBlk;
++    ULONG   i;
++    ULONG   dwBytes = 0;
++    LONGLONG lba;
++
++    PEXT2_BDL   ext2bdl = NULL;
++
++    *ext2_bdl = NULL;
++
++    if (offset >= ext2_inode->i_size)
++    {
++        KdPrint(("Mke2fs: ext2_build_bdl: beyond the file range.\n"));
++        return 0;
++    }
++
++/*
++    if (offset + size > ext2_inode->i_size)
++    {
++        size = ext2_inode->i_size - offset;
++    }
++*/
++
++    nBeg = offset / Ext2Sys->blocksize;
++    nEnd = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize;
++
++    nBlocks = nEnd - nBeg;
++
++    if (nBlocks > 0)
++    {
++        ext2bdl = (PEXT2_BDL)
++            RtlAllocateHeap(GetProcessHeap(), 0, sizeof(EXT2_BDL) * nBlocks);
++
++        if (ext2bdl)
++        {
++
++            memset(ext2bdl, 0, sizeof(EXT2_BDL) * nBlocks);
++            
++            for (i = nBeg; i < nEnd; i++)
++            {
++                if (!ext2_block_map(Ext2Sys, ext2_inode, i, &dwBlk))
++                {
++                    goto fail;
++                }
++                
++                lba = (LONGLONG) dwBlk;
++                lba = lba * Ext2Sys->blocksize;
++                
++                if (nBlocks == 1) // ie. (nBeg == nEnd - 1)
++                {
++                    dwBytes = size;
++                    ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize));
++                    ext2bdl[i - nBeg].Length = dwBytes;
++                    ext2bdl[i - nBeg].Offset = 0;
++                }
++                else
++                {
++                    if (i == nBeg)
++                    {
++                        dwBytes = Ext2Sys->blocksize - (offset % (Ext2Sys->blocksize));
++                        ext2bdl[i - nBeg].Lba = lba + (LONGLONG)(offset % (Ext2Sys->blocksize));
++                        ext2bdl[i - nBeg].Length = dwBytes;
++                        ext2bdl[i - nBeg].Offset = 0;
++                    }
++                    else if (i == nEnd - 1)
++                    {
++                        ext2bdl[i - nBeg].Lba = lba;
++                        ext2bdl[i - nBeg].Length = size - dwBytes;
++                        ext2bdl[i - nBeg].Offset = dwBytes;
++                        dwBytes = size;
++                    }
++                    else
++                    {
++                        ext2bdl[i - nBeg].Lba = lba;
++                        ext2bdl[i - nBeg].Length = Ext2Sys->blocksize;
++                        ext2bdl[i - nBeg].Offset = dwBytes;
++                        dwBytes +=  Ext2Sys->blocksize;
++                    }
++                }
++            }
++
++            *ext2_bdl = ext2bdl;
++            return nBlocks;
++        }
++    }
++
++fail:
++
++    if (ext2bdl)
++        RtlFreeHeap(GetProcessHeap(), 0, ext2bdl);
++
++    // Error
++    return 0;
++}
++
++
++bool ext2_read_inode(PEXT2_FILESYS Ext2Sys,
++            ULONG               ino,
++            ULONG               offset,
++            PVOID               Buffer,
++            ULONG               size,
++            PULONG              dwReturn)
++{
++    PEXT2_BDL   ext2_bdl = NULL;
++    ULONG       blocks, i;
++    bool        bRet = true;
++    EXT2_INODE  ext2_inode;
++    ULONG       dwTotal = 0;
++
++    if (!ext2_load_inode(Ext2Sys, ino, &ext2_inode))
++    {
++        return false;
++    }
++
++    blocks = ext2_build_bdl(Ext2Sys, &ext2_inode, offset, size, &ext2_bdl);
++
++    if (blocks <= 0)
++        return  false;
++    
++   
++    for(i = 0; i < blocks; i++)
++    {
++        bRet = NT_SUCCESS(Ext2ReadDisk(
++                Ext2Sys,
++                ext2_bdl[i].Lba, 
++                ext2_bdl[i].Length,
++                (PUCHAR)Buffer + ext2_bdl[i].Offset
++               ));
++
++        if (!bRet)
++            break;
++        dwTotal += ext2_bdl[i].Length;
++    }
++
++    *dwReturn = dwTotal;
++
++    if (ext2_bdl)
++        RtlFreeHeap(GetProcessHeap(), 0, ext2_bdl);
++
++    return bRet;
++}
++
++
++bool ext2_write_inode (PEXT2_FILESYS Ext2Sys,
++            ULONG               ino,
++            ULONG               offset,
++            PVOID               Buffer,
++            ULONG               size,
++            PULONG              dwReturn )
++{
++    PEXT2_BDL   ext2_bdl = NULL;
++    ULONG       blocks, i;
++    bool        bRet = true;
++    EXT2_INODE  inode;
++    ULONG       dwTotal = 0;
++    ULONG       dwBlk = 0;
++    ULONG       TotalBlks;
++
++    blocks =  (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize;
++
++    if (!ext2_load_inode(Ext2Sys, ino, &inode))
++    {
++        return false;
++    }
++
++    TotalBlks = inode.i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE);
++    TotalBlks = Ext2DataBlocks(Ext2Sys, TotalBlks);
++
++    if (blocks > TotalBlks)
++    {
++        for (i=0; i < (blocks - TotalBlks);  i++)
++        {
++            if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) )
++            {
++                ext2_expand_inode(Ext2Sys, &inode, dwBlk);
++                inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE);
++            }
++        }
++    }
++
++    blocks = ext2_build_bdl(Ext2Sys, &inode, offset, size, &ext2_bdl);
++
++    if (blocks <= 0)
++        return  false;
++    
++    for(i = 0; i < blocks; i++)
++    {
++        bRet = NT_SUCCESS(Ext2WriteDisk(
++                Ext2Sys,
++                ext2_bdl[i].Lba, 
++                ext2_bdl[i].Length,
++                (PUCHAR)Buffer + ext2_bdl[i].Offset
++               ));
++
++        if (!bRet)
++        {
++            goto errorout;
++        }
++
++        dwTotal += ext2_bdl[i].Length;
++    }
++
++    *dwReturn = dwTotal;
++
++    if (size + offset > inode.i_size)
++    {
++        inode.i_size = size + offset;
++    }
++
++    ext2_save_inode(Ext2Sys, ino, &inode);
++
++
++errorout:
++   
++    if (ext2_bdl)
++        RtlFreeHeap(GetProcessHeap(), 0, ext2_bdl);
++
++    return bRet;
++}
++
++bool
++ext2_add_entry( PEXT2_FILESYS Ext2Sys,
++                ULONG parent, ULONG inode,
++                int filetype, char *name )
++{
++    PEXT2_DIR_ENTRY2  dir = NULL, newdir = NULL;
++    EXT2_INODE      parent_inode;
++    ULONG       dwRet;
++    char        *buf;
++    int         rec_len;
++    bool        bRet = false;
++
++    rec_len = EXT2_DIR_REC_LEN(strlen(name));
++
++    if (!ext2_load_inode(Ext2Sys, parent, &parent_inode))
++    {
++        return false;
++    }
++
++    buf = (char *)RtlAllocateHeap(GetProcessHeap(), 0, parent_inode.i_size);
++
++    if (!ext2_read_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet))
++    {
++        return false;
++    }
++
++    dir = (PEXT2_DIR_ENTRY2) buf;
++
++    while ((char *)dir < buf + parent_inode.i_size)
++    {
++        if ((dir->inode == 0 && dir->rec_len >= rec_len) || 
++               (dir->rec_len >= dir->name_len + rec_len) )
++        {
++            if (dir->inode)
++            {
++                newdir = (PEXT2_DIR_ENTRY2) ((PUCHAR)dir + EXT2_DIR_REC_LEN(dir->name_len));
++                newdir->rec_len = dir->rec_len - EXT2_DIR_REC_LEN(dir->name_len);
++
++                dir->rec_len = EXT2_DIR_REC_LEN(dir->name_len);
++
++                dir = newdir;
++            }
++
++            dir->file_type = filetype;
++            dir->inode = inode;
++            dir->name_len = strlen(name);
++            memcpy(dir->name, name, strlen(name));
++    
++            bRet = true;
++            break;
++        }
++
++        dir = (PEXT2_DIR_ENTRY2) (dir->rec_len + (PUCHAR) dir);
++    }
++
++
++    if (bRet)
++        return ext2_write_inode(Ext2Sys, parent, 0, buf, parent_inode.i_size, &dwRet);
++
++    return bRet;
++}
++
++
++bool ext2_reserve_inodes(PEXT2_FILESYS fs)
++{
++    ULONG   i;
++    int     group;
++
++    for (i = EXT2_ROOT_INO + 1; i < EXT2_FIRST_INODE(fs->ext2_sb); i++)
++    {
++        ext2_mark_inode_bitmap(fs->inode_map, i);
++        group = ext2_group_of_ino(fs, i);
++        fs->group_desc[group].bg_free_inodes_count--;
++        fs->ext2_sb->s_free_inodes_count--;
++    }
++
++    return true;
++}
index 0000000,c5277db..08e59f7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,416 +1,416 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Memory.c\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -#include "Mke2fs.h"\r
 -\r
 -/* DEFINITIONS ***********************************************************/\r
 -\r
 -extern char *device_name;\r
 -\r
 -/* FUNCTIONS *************************************************************/\r
 -\r
 -\r
 -/*\r
 - * Return the group # of an inode number\r
 - */\r
 -int ext2_group_of_ino(PEXT2_FILESYS fs, ULONG ino)\r
 -{\r
 -    return (ino - 1) / fs->ext2_sb->s_inodes_per_group;\r
 -}\r
 -\r
 -/*\r
 - * Return the group # of a block\r
 - */\r
 -int ext2_group_of_blk(PEXT2_FILESYS fs, ULONG blk)\r
 -{\r
 -    return (blk - fs->ext2_sb->s_first_data_block) /\r
 -        fs->ext2_sb->s_blocks_per_group;\r
 -}\r
 -\r
 -void ext2_inode_alloc_stats2(PEXT2_FILESYS fs, ULONG ino,\r
 -                   int inuse, int isdir)\r
 -{\r
 -    int group = ext2_group_of_ino(fs, ino);\r
 -\r
 -    if (inuse > 0)\r
 -        ext2_mark_inode_bitmap(fs->inode_map, ino);\r
 -    else\r
 -        ext2_unmark_inode_bitmap(fs->inode_map, ino);\r
 -\r
 -    fs->group_desc[group].bg_free_inodes_count -= inuse;\r
 -\r
 -    if (isdir)\r
 -        fs->group_desc[group].bg_used_dirs_count += inuse;\r
 -\r
 -    fs->ext2_sb->s_free_inodes_count -= inuse;\r
 -}\r
 -\r
 -\r
 -void ext2_inode_alloc_stats(PEXT2_FILESYS fs, ULONG ino, int inuse)\r
 -{\r
 -    ext2_inode_alloc_stats2(fs, ino, inuse, 0);\r
 -}\r
 -\r
 -void ext2_block_alloc_stats(PEXT2_FILESYS fs, ULONG blk, int inuse)\r
 -{\r
 -    int group = ext2_group_of_blk(fs, blk);\r
 -\r
 -    if (inuse > 0)\r
 -        ext2_mark_block_bitmap(fs->block_map, blk);\r
 -    else\r
 -        ext2_unmark_block_bitmap(fs->block_map, blk);\r
 -\r
 -    fs->group_desc[group].bg_free_blocks_count -= inuse;\r
 -    fs->ext2_sb->s_free_blocks_count -= inuse;\r
 -}\r
 -\r
 -\r
 -bool ext2_allocate_tables(PEXT2_FILESYS Ext2Sys)\r
 -{\r
 -    bool    retval;\r
 -    ULONG   i;\r
 -\r
 -    for (i = 0; i < Ext2Sys->group_desc_count; i++)\r
 -    {\r
 -        retval = ext2_allocate_group_table(Ext2Sys, i, Ext2Sys->block_map);\r
 -\r
 -        if (!retval)\r
 -            return retval;\r
 -    }\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -\r
 -bool ext2_allocate_group_table(PEXT2_FILESYS fs, ULONG group,\r
 -                      PEXT2_BLOCK_BITMAP bmap)\r
 -{\r
 -    bool    retval;\r
 -    ULONG   group_blk, start_blk, last_blk, new_blk, blk;\r
 -    int     j;\r
 -\r
 -    group_blk = fs->ext2_sb->s_first_data_block +\r
 -        (group * fs->ext2_sb->s_blocks_per_group);\r
 -    \r
 -    last_blk = group_blk + fs->ext2_sb->s_blocks_per_group;\r
 -    if (last_blk >= fs->ext2_sb->s_blocks_count)\r
 -        last_blk = fs->ext2_sb->s_blocks_count - 1;\r
 -\r
 -    start_blk = group_blk + 3 + fs->desc_blocks;\r
 -    if (start_blk > last_blk)\r
 -        start_blk = group_blk;\r
 -\r
 -    if (!bmap)\r
 -        bmap = fs->block_map;\r
 -    \r
 -    /*\r
 -     * Allocate the inode table\r
 -     */\r
 -    if (!fs->group_desc[group].bg_inode_table)\r
 -    {\r
 -        retval = ext2_get_free_blocks(fs, start_blk, last_blk,\r
 -                        fs->inode_blocks_per_group,\r
 -                        bmap, &new_blk);\r
 -        if (!retval)\r
 -            return retval;\r
 -\r
 -        for (j=0, blk = new_blk;\r
 -             j < fs->inode_blocks_per_group;\r
 -             j++, blk++)\r
 -            ext2_mark_block_bitmap(bmap, blk);\r
 -\r
 -        fs->group_desc[group].bg_inode_table = new_blk;\r
 -    }\r
 -\r
 -    /*\r
 -     * Allocate the block and inode bitmaps, if necessary\r
 -     */\r
 -    if (fs->stride)\r
 -    {\r
 -        start_blk += fs->inode_blocks_per_group;\r
 -        start_blk += ((fs->stride * group) %\r
 -                  (last_blk - start_blk));\r
 -        if (start_blk > last_blk)\r
 -            /* should never happen */\r
 -            start_blk = group_blk;\r
 -    }\r
 -    else\r
 -    {\r
 -        start_blk = group_blk;\r
 -    }\r
 -\r
 -    if (!fs->group_desc[group].bg_block_bitmap)\r
 -    {\r
 -        retval = ext2_get_free_blocks(fs, start_blk, last_blk,\r
 -                        1, bmap, &new_blk);\r
 -\r
 -        if (!retval) \r
 -            retval = ext2_get_free_blocks(fs, group_blk,\r
 -                    last_blk, 1, bmap, &new_blk);\r
 -\r
 -        if (!retval)\r
 -            return retval;\r
 -\r
 -        ext2_mark_block_bitmap(bmap, new_blk);\r
 -        fs->group_desc[group].bg_block_bitmap = new_blk;\r
 -    }\r
 -\r
 -    if (!fs->group_desc[group].bg_inode_bitmap)\r
 -    {\r
 -        retval = ext2_get_free_blocks(fs, start_blk, last_blk,\r
 -                        1, bmap, &new_blk);\r
 -        if (!retval) \r
 -            retval = ext2_get_free_blocks(fs, group_blk,\r
 -                    last_blk, 1, bmap, &new_blk);\r
 -        if (!retval)\r
 -            return retval;\r
 -\r
 -        ext2_mark_block_bitmap(bmap, new_blk);\r
 -        fs->group_desc[group].bg_inode_bitmap = new_blk;\r
 -    }\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -\r
 -bool ext2_get_free_blocks(PEXT2_FILESYS fs, ULONG start, ULONG finish,\r
 -                 int num, PEXT2_BLOCK_BITMAP map, ULONG *ret)\r
 -{\r
 -    ULONG   b = start;\r
 -\r
 -    if (!map)\r
 -        map = fs->block_map;\r
 -\r
 -    if (!map)\r
 -        return false;\r
 -\r
 -    if (!b)\r
 -        b = fs->ext2_sb->s_first_data_block;\r
 -\r
 -    if (!finish)\r
 -        finish = start;\r
 -\r
 -    if (!num)\r
 -        num = 1;\r
 -\r
 -    do\r
 -    {\r
 -        if (b+num-1 > fs->ext2_sb->s_blocks_count)\r
 -            b = fs->ext2_sb->s_first_data_block;\r
 -\r
 -        if (ext2_test_block_bitmap_range(map, b, num))\r
 -        {\r
 -            *ret = b;\r
 -            return true;\r
 -        }\r
 -\r
 -        b++;\r
 -\r
 -    } while (b != finish);\r
 -\r
 -    return false;\r
 -}\r
 -\r
 -\r
 -bool write_inode_tables(PEXT2_FILESYS fs)\r
 -{\r
 -    bool    retval;\r
 -    ULONG   blk, num;\r
 -    int     i;\r
 -\r
 -    for (i = 0; (ULONG)i < fs->group_desc_count; i++)\r
 -    {\r
 -        blk = fs->group_desc[i].bg_inode_table;\r
 -        num = fs->inode_blocks_per_group;\r
 -\r
 -        retval = zero_blocks(fs, blk, num, &blk, &num);\r
 -        if (!retval)\r
 -        {\r
 -            KdPrint(("\nMke2fs: Could not write %lu blocks "\r
 -                "in inode table starting at %lu.\n",\r
 -                num, blk));\r
 -\r
 -            zero_blocks(0, 0, 0, 0, 0);\r
 -            return false;\r
 -        }\r
 -    }\r
 -\r
 -    zero_blocks(0, 0, 0, 0, 0);\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -\r
 -/*\r
 - * Stupid algorithm --- we now just search forward starting from the\r
 - * goal.  Should put in a smarter one someday....\r
 - */\r
 -bool ext2_new_block(PEXT2_FILESYS fs, ULONG goal,\r
 -               PEXT2_BLOCK_BITMAP map, ULONG *ret)\r
 -{\r
 -    ULONG   i;\r
 -\r
 -    if (!map)\r
 -        map = fs->block_map;\r
 -\r
 -    if (!map)\r
 -        return false;\r
 -\r
 -    if (!goal || (goal >= fs->ext2_sb->s_blocks_count))\r
 -        goal = fs->ext2_sb->s_first_data_block;\r
 -\r
 -    i = goal;\r
 -\r
 -    do\r
 -    {\r
 -        if (!ext2_test_block_bitmap(map, i))\r
 -        {\r
 -            *ret = i;\r
 -            return true;\r
 -        }\r
 -\r
 -        i++;\r
 -\r
 -        if (i >= fs->ext2_sb->s_blocks_count)\r
 -            i = fs->ext2_sb->s_first_data_block;\r
 -\r
 -    } while (i != goal);\r
 -\r
 -    return false;\r
 -}\r
 -\r
 -\r
 -/*\r
 - * This function zeros out the allocated block, and updates all of the\r
 - * appropriate filesystem records.\r
 - */\r
 -bool ext2_alloc_block(PEXT2_FILESYS fs, ULONG goal, ULONG *ret)\r
 -{\r
 -    bool        retval;\r
 -    ULONG       block;\r
 -    char        *buf = NULL;\r
 -\r
 -    buf = (char *)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize);\r
 -    if (!buf)\r
 -        return false;\r
 -\r
 -    if (!fs->block_map)\r
 -    {\r
 -        retval = ext2_read_block_bitmap(fs);\r
 -        if (!retval)\r
 -            goto fail;\r
 -    }\r
 -\r
 -    retval = ext2_new_block(fs, goal, 0, &block);\r
 -\r
 -    if (!retval)\r
 -        goto fail;\r
 -\r
 -    retval = NT_SUCCESS(Ext2WriteDisk(\r
 -                fs,\r
 -                ((LONGLONG)block * fs->blocksize),\r
 -                fs->blocksize, (unsigned char *)buf));\r
 -\r
 -    if (!retval)\r
 -    {\r
 -        goto fail;\r
 -    }\r
 -    \r
 -    ext2_block_alloc_stats(fs, block, +1);\r
 -    *ret = block;\r
 -\r
 -    if (buf)\r
 -    {\r
 -        RtlFreeHeap(GetProcessHeap(), 0, buf);\r
 -    }\r
 -\r
 -    return true;\r
 -\r
 -fail:\r
 -\r
 -    if (buf)\r
 -    {\r
 -        RtlFreeHeap(GetProcessHeap(), 0, buf);\r
 -    }\r
 -\r
 -    return false;\r
 -}\r
 -\r
 -\r
 -/*\r
 - * Create new directory block\r
 - */\r
 -bool ext2_new_dir_block(PEXT2_FILESYS fs, ULONG dir_ino,\r
 -                   ULONG parent_ino, char **block)\r
 -{\r
 -    PEXT2_DIR_ENTRY dir = NULL;\r
 -    char        *buf;\r
 -    int         rec_len;\r
 -    int         filetype = 0;\r
 -\r
 -    buf = (char *)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize);\r
 -    if (!buf)\r
 -        return false;\r
 -\r
 -    dir = (PEXT2_DIR_ENTRY) buf;\r
 -    dir->rec_len = fs->blocksize;\r
 -\r
 -    if (dir_ino)\r
 -    {\r
 -        if (fs->ext2_sb->s_feature_incompat &\r
 -            EXT2_FEATURE_INCOMPAT_FILETYPE)\r
 -            filetype = EXT2_FT_DIR << 8;\r
 -        /*\r
 -         * Set up entry for '.'\r
 -         */\r
 -        dir->inode = dir_ino;\r
 -        dir->name_len = 1 | filetype;\r
 -        dir->name[0] = '.';\r
 -        rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1);\r
 -        dir->rec_len = EXT2_DIR_REC_LEN(1);\r
 -\r
 -        /*\r
 -         * Set up entry for '..'\r
 -         */\r
 -        dir = (struct ext2_dir_entry *) (buf + dir->rec_len);\r
 -        dir->rec_len = rec_len;\r
 -        dir->inode = parent_ino;\r
 -        dir->name_len = 2 | filetype;\r
 -        dir->name[0] = '.';\r
 -        dir->name[1] = '.';\r
 -    }\r
 -\r
 -    *block = buf;\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -bool ext2_write_block(PEXT2_FILESYS fs, ULONG block, void *inbuf)\r
 -{\r
 -    bool    retval = false;\r
 -\r
 -    retval = NT_SUCCESS(Ext2WriteDisk(\r
 -                fs,\r
 -                ((ULONGLONG)block * fs->blocksize),\r
 -                fs->blocksize, (unsigned char *)inbuf));\r
 -\r
 -    return retval;\r
 -}\r
 -\r
 -bool ext2_read_block(PEXT2_FILESYS fs, ULONG block, void *inbuf)\r
 -{\r
 -    bool    retval = false;\r
 -\r
 -    retval = NT_SUCCESS(Ext2ReadDisk(\r
 -                fs,\r
 -                ((ULONGLONG)block * fs->blocksize),\r
 -                fs->blocksize, (unsigned char *)inbuf));\r
 -\r
 -    return retval;\r
 -}\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Memory.c
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++/* INCLUDES **************************************************************/
++
++#include "Mke2fs.h"
++
++/* DEFINITIONS ***********************************************************/
++
++extern char *device_name;
++
++/* FUNCTIONS *************************************************************/
++
++
++/*
++ * Return the group # of an inode number
++ */
++int ext2_group_of_ino(PEXT2_FILESYS fs, ULONG ino)
++{
++    return (ino - 1) / fs->ext2_sb->s_inodes_per_group;
++}
++
++/*
++ * Return the group # of a block
++ */
++int ext2_group_of_blk(PEXT2_FILESYS fs, ULONG blk)
++{
++    return (blk - fs->ext2_sb->s_first_data_block) /
++        fs->ext2_sb->s_blocks_per_group;
++}
++
++void ext2_inode_alloc_stats2(PEXT2_FILESYS fs, ULONG ino,
++                   int inuse, int isdir)
++{
++    int group = ext2_group_of_ino(fs, ino);
++
++    if (inuse > 0)
++        ext2_mark_inode_bitmap(fs->inode_map, ino);
++    else
++        ext2_unmark_inode_bitmap(fs->inode_map, ino);
++
++    fs->group_desc[group].bg_free_inodes_count -= inuse;
++
++    if (isdir)
++        fs->group_desc[group].bg_used_dirs_count += inuse;
++
++    fs->ext2_sb->s_free_inodes_count -= inuse;
++}
++
++
++void ext2_inode_alloc_stats(PEXT2_FILESYS fs, ULONG ino, int inuse)
++{
++    ext2_inode_alloc_stats2(fs, ino, inuse, 0);
++}
++
++void ext2_block_alloc_stats(PEXT2_FILESYS fs, ULONG blk, int inuse)
++{
++    int group = ext2_group_of_blk(fs, blk);
++
++    if (inuse > 0)
++        ext2_mark_block_bitmap(fs->block_map, blk);
++    else
++        ext2_unmark_block_bitmap(fs->block_map, blk);
++
++    fs->group_desc[group].bg_free_blocks_count -= inuse;
++    fs->ext2_sb->s_free_blocks_count -= inuse;
++}
++
++
++bool ext2_allocate_tables(PEXT2_FILESYS Ext2Sys)
++{
++    bool    retval;
++    ULONG   i;
++
++    for (i = 0; i < Ext2Sys->group_desc_count; i++)
++    {
++        retval = ext2_allocate_group_table(Ext2Sys, i, Ext2Sys->block_map);
++
++        if (!retval)
++            return retval;
++    }
++
++    return true;
++}
++
++
++bool ext2_allocate_group_table(PEXT2_FILESYS fs, ULONG group,
++                      PEXT2_BLOCK_BITMAP bmap)
++{
++    bool    retval;
++    ULONG   group_blk, start_blk, last_blk, new_blk, blk;
++    int     j;
++
++    group_blk = fs->ext2_sb->s_first_data_block +
++        (group * fs->ext2_sb->s_blocks_per_group);
++    
++    last_blk = group_blk + fs->ext2_sb->s_blocks_per_group;
++    if (last_blk >= fs->ext2_sb->s_blocks_count)
++        last_blk = fs->ext2_sb->s_blocks_count - 1;
++
++    start_blk = group_blk + 3 + fs->desc_blocks;
++    if (start_blk > last_blk)
++        start_blk = group_blk;
++
++    if (!bmap)
++        bmap = fs->block_map;
++    
++    /*
++     * Allocate the inode table
++     */
++    if (!fs->group_desc[group].bg_inode_table)
++    {
++        retval = ext2_get_free_blocks(fs, start_blk, last_blk,
++                        fs->inode_blocks_per_group,
++                        bmap, &new_blk);
++        if (!retval)
++            return retval;
++
++        for (j=0, blk = new_blk;
++             j < fs->inode_blocks_per_group;
++             j++, blk++)
++            ext2_mark_block_bitmap(bmap, blk);
++
++        fs->group_desc[group].bg_inode_table = new_blk;
++    }
++
++    /*
++     * Allocate the block and inode bitmaps, if necessary
++     */
++    if (fs->stride)
++    {
++        start_blk += fs->inode_blocks_per_group;
++        start_blk += ((fs->stride * group) %
++                  (last_blk - start_blk));
++        if (start_blk > last_blk)
++            /* should never happen */
++            start_blk = group_blk;
++    }
++    else
++    {
++        start_blk = group_blk;
++    }
++
++    if (!fs->group_desc[group].bg_block_bitmap)
++    {
++        retval = ext2_get_free_blocks(fs, start_blk, last_blk,
++                        1, bmap, &new_blk);
++
++        if (!retval) 
++            retval = ext2_get_free_blocks(fs, group_blk,
++                    last_blk, 1, bmap, &new_blk);
++
++        if (!retval)
++            return retval;
++
++        ext2_mark_block_bitmap(bmap, new_blk);
++        fs->group_desc[group].bg_block_bitmap = new_blk;
++    }
++
++    if (!fs->group_desc[group].bg_inode_bitmap)
++    {
++        retval = ext2_get_free_blocks(fs, start_blk, last_blk,
++                        1, bmap, &new_blk);
++        if (!retval) 
++            retval = ext2_get_free_blocks(fs, group_blk,
++                    last_blk, 1, bmap, &new_blk);
++        if (!retval)
++            return retval;
++
++        ext2_mark_block_bitmap(bmap, new_blk);
++        fs->group_desc[group].bg_inode_bitmap = new_blk;
++    }
++
++    return true;
++}
++
++
++bool ext2_get_free_blocks(PEXT2_FILESYS fs, ULONG start, ULONG finish,
++                 int num, PEXT2_BLOCK_BITMAP map, ULONG *ret)
++{
++    ULONG   b = start;
++
++    if (!map)
++        map = fs->block_map;
++
++    if (!map)
++        return false;
++
++    if (!b)
++        b = fs->ext2_sb->s_first_data_block;
++
++    if (!finish)
++        finish = start;
++
++    if (!num)
++        num = 1;
++
++    do
++    {
++        if (b+num-1 > fs->ext2_sb->s_blocks_count)
++            b = fs->ext2_sb->s_first_data_block;
++
++        if (ext2_test_block_bitmap_range(map, b, num))
++        {
++            *ret = b;
++            return true;
++        }
++
++        b++;
++
++    } while (b != finish);
++
++    return false;
++}
++
++
++bool write_inode_tables(PEXT2_FILESYS fs)
++{
++    bool    retval;
++    ULONG   blk, num;
++    int     i;
++
++    for (i = 0; (ULONG)i < fs->group_desc_count; i++)
++    {
++        blk = fs->group_desc[i].bg_inode_table;
++        num = fs->inode_blocks_per_group;
++
++        retval = zero_blocks(fs, blk, num, &blk, &num);
++        if (!retval)
++        {
++            KdPrint(("\nMke2fs: Could not write %lu blocks "
++                "in inode table starting at %lu.\n",
++                num, blk));
++
++            zero_blocks(0, 0, 0, 0, 0);
++            return false;
++        }
++    }
++
++    zero_blocks(0, 0, 0, 0, 0);
++
++    return true;
++}
++
++
++/*
++ * Stupid algorithm --- we now just search forward starting from the
++ * goal.  Should put in a smarter one someday....
++ */
++bool ext2_new_block(PEXT2_FILESYS fs, ULONG goal,
++               PEXT2_BLOCK_BITMAP map, ULONG *ret)
++{
++    ULONG   i;
++
++    if (!map)
++        map = fs->block_map;
++
++    if (!map)
++        return false;
++
++    if (!goal || (goal >= fs->ext2_sb->s_blocks_count))
++        goal = fs->ext2_sb->s_first_data_block;
++
++    i = goal;
++
++    do
++    {
++        if (!ext2_test_block_bitmap(map, i))
++        {
++            *ret = i;
++            return true;
++        }
++
++        i++;
++
++        if (i >= fs->ext2_sb->s_blocks_count)
++            i = fs->ext2_sb->s_first_data_block;
++
++    } while (i != goal);
++
++    return false;
++}
++
++
++/*
++ * This function zeros out the allocated block, and updates all of the
++ * appropriate filesystem records.
++ */
++bool ext2_alloc_block(PEXT2_FILESYS fs, ULONG goal, ULONG *ret)
++{
++    bool        retval;
++    ULONG       block;
++    char        *buf = NULL;
++
++    buf = (char *)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize);
++    if (!buf)
++        return false;
++
++    if (!fs->block_map)
++    {
++        retval = ext2_read_block_bitmap(fs);
++        if (!retval)
++            goto fail;
++    }
++
++    retval = ext2_new_block(fs, goal, 0, &block);
++
++    if (!retval)
++        goto fail;
++
++    retval = NT_SUCCESS(Ext2WriteDisk(
++                fs,
++                ((LONGLONG)block * fs->blocksize),
++                fs->blocksize, (unsigned char *)buf));
++
++    if (!retval)
++    {
++        goto fail;
++    }
++    
++    ext2_block_alloc_stats(fs, block, +1);
++    *ret = block;
++
++    if (buf)
++    {
++        RtlFreeHeap(GetProcessHeap(), 0, buf);
++    }
++
++    return true;
++
++fail:
++
++    if (buf)
++    {
++        RtlFreeHeap(GetProcessHeap(), 0, buf);
++    }
++
++    return false;
++}
++
++
++/*
++ * Create new directory block
++ */
++bool ext2_new_dir_block(PEXT2_FILESYS fs, ULONG dir_ino,
++                   ULONG parent_ino, char **block)
++{
++    PEXT2_DIR_ENTRY dir = NULL;
++    char        *buf;
++    int         rec_len;
++    int         filetype = 0;
++
++    buf = (char *)RtlAllocateHeap(GetProcessHeap(), HEAP_ZERO_MEMORY, fs->blocksize);
++    if (!buf)
++        return false;
++
++    dir = (PEXT2_DIR_ENTRY) buf;
++    dir->rec_len = fs->blocksize;
++
++    if (dir_ino)
++    {
++        if (fs->ext2_sb->s_feature_incompat &
++            EXT2_FEATURE_INCOMPAT_FILETYPE)
++            filetype = EXT2_FT_DIR << 8;
++        /*
++         * Set up entry for '.'
++         */
++        dir->inode = dir_ino;
++        dir->name_len = 1 | filetype;
++        dir->name[0] = '.';
++        rec_len = dir->rec_len - EXT2_DIR_REC_LEN(1);
++        dir->rec_len = EXT2_DIR_REC_LEN(1);
++
++        /*
++         * Set up entry for '..'
++         */
++        dir = (struct ext2_dir_entry *) (buf + dir->rec_len);
++        dir->rec_len = rec_len;
++        dir->inode = parent_ino;
++        dir->name_len = 2 | filetype;
++        dir->name[0] = '.';
++        dir->name[1] = '.';
++    }
++
++    *block = buf;
++
++    return true;
++}
++
++bool ext2_write_block(PEXT2_FILESYS fs, ULONG block, void *inbuf)
++{
++    bool    retval = false;
++
++    retval = NT_SUCCESS(Ext2WriteDisk(
++                fs,
++                ((ULONGLONG)block * fs->blocksize),
++                fs->blocksize, (unsigned char *)inbuf));
++
++    return retval;
++}
++
++bool ext2_read_block(PEXT2_FILESYS fs, ULONG block, void *inbuf)
++{
++    bool    retval = false;
++
++    retval = NT_SUCCESS(Ext2ReadDisk(
++                fs,
++                ((ULONGLONG)block * fs->blocksize),
++                fs->blocksize, (unsigned char *)inbuf));
++
++    return retval;
++}
index 0000000,8608d27..9434371
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1010 +1,1010 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Disk.c\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -#include "Mke2fs.h"\r
 -#include <fmifs.h>\r
 -\r
 -/* GLOBALS ***************************************************************/\r
 -\r
 -int     inode_ratio = 4096;\r
 -\r
 -BOOLEAN bLocked = FALSE;\r
 -\r
 -/* FUNCTIONS *************************************************************/\r
 -\r
 -int int_log2(int arg)\r
 -{\r
 -    int l = 0;\r
 -\r
 -    arg >>= 1;\r
 -\r
 -    while (arg)\r
 -    {\r
 -        l++;\r
 -        arg >>= 1;\r
 -    }\r
 -\r
 -    return l;\r
 -}\r
 -\r
 -int int_log10(unsigned int arg)\r
 -{\r
 -    int l;\r
 -\r
 -    for (l=0; arg ; l++)\r
 -        arg = arg / 10;\r
 -\r
 -    return l;\r
 -}\r
 -\r
 -\r
 -static char default_str[] = "default";\r
 -\r
 -struct mke2fs_defaults {\r
 -    const char  *type;\r
 -    int     size;\r
 -    int     blocksize;\r
 -    int     inode_ratio;\r
 -} settings[] = {\r
 -    { default_str, 0, 4096, 8192 },\r
 -    { default_str, 512, 1024, 4096 },\r
 -    { default_str, 3, 1024, 8192 },\r
 -    { "journal", 0, 4096, 8192 },\r
 -    { "news", 0, 4096, 4096 },\r
 -    { "largefile", 0, 4096, 1024 * 1024 },\r
 -    { "largefile4", 0, 4096, 4096 * 1024 },\r
 -    { 0, 0, 0, 0},\r
 -};\r
 -\r
 -void set_fs_defaults(const char *fs_type,\r
 -                PEXT2_SUPER_BLOCK super,\r
 -                int blocksize, int *inode_ratio)\r
 -{\r
 -    int megs;\r
 -    int ratio = 0;\r
 -    struct mke2fs_defaults *p;\r
 -\r
 -    megs = (super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024);\r
 -\r
 -    if (inode_ratio)\r
 -        ratio = *inode_ratio;\r
 -\r
 -    if (!fs_type)\r
 -        fs_type = default_str;\r
 -\r
 -    for (p = settings; p->type; p++)\r
 -    {\r
 -        if ((strcmp(p->type, fs_type) != 0) &&\r
 -            (strcmp(p->type, default_str) != 0))\r
 -            continue;\r
 -\r
 -        if ((p->size != 0) &&\r
 -            (megs > p->size))\r
 -            continue;\r
 -\r
 -        if (ratio == 0)\r
 -            *inode_ratio = p->inode_ratio;\r
 -\r
 -        if (blocksize == 0)\r
 -        {\r
 -            super->s_log_frag_size = super->s_log_block_size =\r
 -                int_log2(p->blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);\r
 -        }\r
 -    }\r
 -\r
 -    if (blocksize == 0)\r
 -    {\r
 -        super->s_blocks_count /= EXT2_BLOCK_SIZE(super) / 1024;\r
 -    }\r
 -}\r
 -\r
 -/*\r
 - * Helper function which zeros out _num_ blocks starting at _blk_.  In\r
 - * case of an error, the details of the error is returned via _ret_blk_\r
 - * and _ret_count_ if they are non-NULL pointers.  Returns 0 on\r
 - * success, and an error code on an error.\r
 - *\r
 - * As a special case, if the first argument is NULL, then it will\r
 - * attempt to free the static zeroizing buffer.  (This is to keep\r
 - * programs that check for memory leaks happy.)\r
 - */\r
 -bool zero_blocks(PEXT2_FILESYS fs, ULONG blk, ULONG num,\r
 -                 ULONG *ret_blk, ULONG *ret_count)\r
 -{\r
 -    ULONG       j, count, next_update, next_update_incr;\r
 -    static unsigned char        *buf;\r
 -    bool        retval;\r
 -\r
 -    /* If fs is null, clean up the static buffer and return */\r
 -    if (!fs)\r
 -    {\r
 -        if (buf)\r
 -        {\r
 -            RtlFreeHeap(GetProcessHeap(), 0, buf);\r
 -            buf = 0;\r
 -        }\r
 -        return true;\r
 -    }\r
 -\r
 -#define STRIDE_LENGTH 8\r
 -\r
 -    /* Allocate the zeroizing buffer if necessary */\r
 -    if (!buf)\r
 -    {\r
 -        buf = (unsigned char *)\r
 -            RtlAllocateHeap(GetProcessHeap(), 0, fs->blocksize * STRIDE_LENGTH);\r
 -        if (!buf)\r
 -        {\r
 -            KdPrint(("Mke2fs: while allocating zeroizing buffer"));\r
 -            return false;\r
 -        }\r
 -        memset(buf, 0, fs->blocksize * STRIDE_LENGTH);\r
 -    }\r
 -\r
 -    /* OK, do the write loop */\r
 -    next_update = 0;\r
 -    next_update_incr = num / 100;\r
 -    if (next_update_incr < 1)\r
 -        next_update_incr = 1;\r
 -\r
 -    for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH)\r
 -    {\r
 -        if (num-j > STRIDE_LENGTH)\r
 -            count = STRIDE_LENGTH;\r
 -        else\r
 -            count = num - j;\r
 -\r
 -        retval = NT_SUCCESS(Ext2WriteDisk(\r
 -                        fs,\r
 -                        ((ULONGLONG)blk * fs->blocksize),\r
 -                        count * fs->blocksize,\r
 -                        buf));\r
 -\r
 -        if (!retval)\r
 -        {\r
 -            if (ret_count)\r
 -                *ret_count = count;\r
 -\r
 -            if (ret_blk)\r
 -                *ret_blk = blk;\r
 -\r
 -            return retval;\r
 -        }\r
 -    }\r
 -\r
 -    return true;\r
 -}   \r
 -\r
 -\r
 -bool zap_sector(PEXT2_FILESYS Ext2Sys, int sect, int nsect)\r
 -{\r
 -    unsigned char *buf;\r
 -    ULONG         *magic;  \r
 -\r
 -    buf = (unsigned char *)\r
 -        RtlAllocateHeap(GetProcessHeap(), 0, SECTOR_SIZE*nsect);\r
 -    if (!buf)\r
 -    {\r
 -        KdPrint(("Mke2fs: Out of memory erasing sectors %d-%d\n",\r
 -                sect, sect + nsect - 1));\r
 -        return false;\r
 -    }\r
 -\r
 -    memset(buf, 0, (ULONG)nsect * SECTOR_SIZE);\r
 -    \r
 -#define BSD_DISKMAGIC   (0x82564557UL)  /* The disk magic number */\r
 -#define BSD_MAGICDISK   (0x57455682UL)  /* The disk magic number reversed */\r
 -#define BSD_LABEL_OFFSET        64\r
 -\r
 -    if (sect == 0)\r
 -    {\r
 -        Ext2ReadDisk(\r
 -                  Ext2Sys, \r
 -                  (LONGLONG)(sect * SECTOR_SIZE),\r
 -                  SECTOR_SIZE, buf);\r
 -\r
 -        // Check for a BSD disklabel, and don't erase it if so\r
 -        magic = (ULONG *) (buf + BSD_LABEL_OFFSET);\r
 -        if ((*magic == BSD_DISKMAGIC) ||   (*magic == BSD_MAGICDISK))\r
 -                goto clean_up;\r
 -    }\r
 -\r
 -    // Write buf to disk\r
 -    Ext2WriteDisk( Ext2Sys,\r
 -                   (LONGLONG)(sect * SECTOR_SIZE),\r
 -                   (ULONG)nsect * SECTOR_SIZE,\r
 -                   buf );\r
 -\r
 -clean_up:\r
 -\r
 -    RtlFreeHeap(GetProcessHeap(), 0, buf);\r
 -    \r
 -    return true;\r
 -}\r
 -\r
 -bool ext2_mkdir( PEXT2_FILESYS fs, \r
 -                 ULONG parent,\r
 -                 ULONG inum, \r
 -                 char *name,\r
 -                 ULONG *no,\r
 -                 PEXT2_INODE pid )\r
 -{\r
 -    bool            retval;\r
 -    EXT2_INODE      parent_inode, inode;\r
 -    ULONG           ino = inum;\r
 -    //ULONG         scratch_ino;\r
 -    ULONG           blk;\r
 -    char            *block = 0;\r
 -    int             filetype = 0;\r
 -\r
 -    LARGE_INTEGER   SysTime;\r
 -    \r
 -    NtQuerySystemTime(&SysTime);\r
 -\r
 -    /*\r
 -     * Allocate an inode, if necessary\r
 -     */\r
 -    if (!ino)\r
 -    {\r
 -        retval = ext2_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &ino);\r
 -        if (!retval)\r
 -            goto cleanup;\r
 -    }\r
 -\r
 -    if (no)\r
 -        *no = ino;\r
 -\r
 -    /*\r
 -     * Allocate a data block for the directory\r
 -     */\r
 -    retval = ext2_new_block(fs, 0, 0, &blk);\r
 -    if (!retval)\r
 -        goto cleanup;\r
 -\r
 -    /*\r
 -     * Create a scratch template for the directory\r
 -     */\r
 -    retval = ext2_new_dir_block(fs, ino, parent, &block);\r
 -    if (!retval)\r
 -        goto cleanup;\r
 -\r
 -    /*\r
 -     * Get the parent's inode, if necessary\r
 -     */\r
 -    if (parent != ino)\r
 -    {\r
 -        retval = ext2_load_inode(fs, parent, &parent_inode);\r
 -        if (!retval)\r
 -            goto cleanup;\r
 -    }\r
 -    else\r
 -    {\r
 -        memset(&parent_inode, 0, sizeof(parent_inode));\r
 -    }\r
 -\r
 -    /*\r
 -     * Create the inode structure....\r
 -     */\r
 -    memset(&inode, 0, sizeof(EXT2_INODE));\r
 -    inode.i_mode = (USHORT)(LINUX_S_IFDIR | (0777 & ~fs->umask));\r
 -    inode.i_uid = inode.i_gid = 0;\r
 -    inode.i_blocks = fs->blocksize / 512;\r
 -    inode.i_block[0] = blk;\r
 -    inode.i_links_count = 2;\r
 -    RtlTimeToSecondsSince1970(&SysTime, &inode.i_mtime);\r
 -    inode.i_ctime = inode.i_atime = inode.i_mtime;\r
 -    inode.i_size = fs->blocksize;\r
 -\r
 -    /*\r
 -     * Write out the inode and inode data block\r
 -     */\r
 -    retval = ext2_write_block(fs, blk, block);\r
 -    if (!retval)\r
 -        goto cleanup;\r
 -\r
 -    retval = ext2_save_inode(fs, ino, &inode); \r
 -    if (!retval)\r
 -        goto cleanup;\r
 -\r
 -    if (pid)\r
 -    {\r
 -        *pid = inode;\r
 -    }\r
 -\r
 -    if (parent != ino)\r
 -    {\r
 -        /*\r
 -         * Add entry for this inode to parent dir 's block\r
 -         */\r
 -\r
 -        if (fs->ext2_sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)\r
 -                filetype = EXT2_FT_DIR;\r
 -\r
 -        retval = ext2_add_entry(fs, parent, ino, filetype, name);\r
 -\r
 -        if (!retval)\r
 -            goto cleanup;\r
 -\r
 -        /*\r
 -         * Update parent inode's counts\r
 -         */\r
 -\r
 -        parent_inode.i_links_count++;\r
 -        retval = ext2_save_inode(fs, parent, &parent_inode);\r
 -        if (!retval)\r
 -            goto cleanup;\r
 -\r
 -    }\r
 -    \r
 -    /*\r
 -     * Update accounting....\r
 -     */\r
 -    ext2_block_alloc_stats(fs, blk, +1);\r
 -    ext2_inode_alloc_stats2(fs, ino, +1, 1);\r
 -\r
 -cleanup:\r
 -\r
 -    if (block)\r
 -    {\r
 -        RtlFreeHeap(GetProcessHeap(), 0, block);\r
 -        block = NULL;\r
 -    }\r
 -\r
 -    return retval;\r
 -}\r
 -\r
 -bool create_root_dir(PEXT2_FILESYS fs)\r
 -{\r
 -    bool        retval;\r
 -    EXT2_INODE  inode;\r
 -\r
 -    retval = ext2_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0, NULL, &inode);\r
 -    \r
 -    if (!retval)\r
 -    {\r
 -        KdPrint(("Mke2fs: while creating root dir"));\r
 -        return false;\r
 -    }\r
 -\r
 -    {\r
 -        inode.i_uid = 0;    \r
 -        inode.i_gid = 0;\r
 -\r
 -        retval = ext2_save_inode(fs, EXT2_ROOT_INO, &inode);\r
 -        if (!retval)\r
 -        {\r
 -            KdPrint(("Mke2fs: while setting root inode ownership"));\r
 -            return false;\r
 -        }\r
 -    }\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -bool create_lost_and_found(PEXT2_FILESYS Ext2Sys)\r
 -{\r
 -    bool        retval;\r
 -    ULONG       ino;\r
 -    char        *name = "lost+found";\r
 -    int         lpf_size = 0;\r
 -    EXT2_INODE  inode;\r
 -    ULONG       dwBlk = 0;\r
 -    BOOLEAN     bExt= TRUE;\r
 -\r
 -    PEXT2_DIR_ENTRY dir;\r
 -\r
 -    char *      buf;\r
 -\r
 -    buf = (char *)RtlAllocateHeap(GetProcessHeap(), 0, Ext2Sys->blocksize);\r
 -    if (!buf)\r
 -    {\r
 -        bExt = FALSE;\r
 -    }\r
 -    else\r
 -    {\r
 -        memset(buf, 0, Ext2Sys->blocksize);\r
 -\r
 -        dir = (PEXT2_DIR_ENTRY) buf;\r
 -        dir->rec_len = Ext2Sys->blocksize;\r
 -    }\r
 -\r
 -    Ext2Sys->umask = 077;\r
 -    retval = ext2_mkdir(Ext2Sys, EXT2_ROOT_INO, 0, name, &ino, &inode);\r
 -    \r
 -    if (!retval)\r
 -    {\r
 -        KdPrint(("Mke2fs: while creating /lost+found.\n"));\r
 -        return false;\r
 -    }\r
 -\r
 -    if (!bExt)\r
 -        goto errorout;\r
 -\r
 -    lpf_size = inode.i_size;\r
 -\r
 -    while(TRUE)\r
 -    {\r
 -        if (lpf_size >= 16*1024)\r
 -            break;\r
 -        \r
 -        retval = ext2_alloc_block(Ext2Sys, 0, &dwBlk);\r
 -\r
 -        if (! retval)\r
 -        {\r
 -            KdPrint(("Mke2fs: create_lost_and_found: error alloc block.\n"));\r
 -            break;\r
 -        }\r
 -\r
 -        retval = ext2_expand_inode(Ext2Sys, &inode, dwBlk);\r
 -        if (!retval)\r
 -        {\r
 -            KdPrint(("Mke2fs: errors when expanding /lost+found.\n"));\r
 -            break;\r
 -        }\r
 -\r
 -        ext2_write_block(Ext2Sys, dwBlk, buf);\r
 -\r
 -        inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE);\r
 -        lpf_size += Ext2Sys->blocksize;\r
 -    }\r
 -\r
 -    {\r
 -        inode.i_size = lpf_size;\r
 -\r
 -        ASSERT( (inode.i_size/Ext2Sys->blocksize) == \r
 -                Ext2DataBlocks(Ext2Sys, inode.i_blocks/(Ext2Sys->blocksize/SECTOR_SIZE)));\r
 -\r
 -        ASSERT( (inode.i_blocks/(Ext2Sys->blocksize/SECTOR_SIZE)) == \r
 -                Ext2TotalBlocks(Ext2Sys, inode.i_size/Ext2Sys->blocksize));\r
 -\r
 -    }\r
 -\r
 -    ext2_save_inode(Ext2Sys, ino, &inode);\r
 -\r
 -errorout:\r
 -\r
 -    if (buf)\r
 -    {\r
 -        RtlFreeHeap(GetProcessHeap(), 0, buf);\r
 -    }\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -/*\r
 - * This function forces out the primary superblock.  We need to only\r
 - * write out those fields which we have changed, since if the\r
 - * filesystem is mounted, it may have changed some of the other\r
 - * fields.\r
 - *\r
 - * It takes as input a superblock which has already been byte swapped\r
 - * (if necessary).\r
 - */\r
 -\r
 -bool write_primary_superblock(PEXT2_FILESYS Ext2Sys, PEXT2_SUPER_BLOCK super)\r
 -{\r
 -    bool bRet;    \r
 -\r
 -    bRet = NT_SUCCESS(Ext2WriteDisk(\r
 -                           Ext2Sys,\r
 -                           ((LONGLONG)SUPERBLOCK_OFFSET),\r
 -                           SUPERBLOCK_SIZE, (PUCHAR)super));\r
 -            \r
 -\r
 -\r
 -    return bRet;\r
 -}\r
 -\r
 -\r
 -/*\r
 - * Updates the revision to EXT2_DYNAMIC_REV\r
 - */\r
 -void ext2_update_dynamic_rev(PEXT2_FILESYS fs)\r
 -{\r
 -    PEXT2_SUPER_BLOCK sb = fs->ext2_sb;\r
 -\r
 -    if (sb->s_rev_level > EXT2_GOOD_OLD_REV)\r
 -        return;\r
 -\r
 -    sb->s_rev_level = EXT2_DYNAMIC_REV;\r
 -    sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;\r
 -    sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;\r
 -    /* s_uuid is handled by e2fsck already */\r
 -    /* other fields should be left alone */\r
 -}\r
 -\r
 -\r
 -bool ext2_flush(PEXT2_FILESYS fs)\r
 -{\r
 -    ULONG       i,j,maxgroup,sgrp;\r
 -    ULONG       group_block;\r
 -    bool        retval;\r
 -    char        *group_ptr;\r
 -    unsigned long fs_state;\r
 -    PEXT2_SUPER_BLOCK super_shadow = 0;\r
 -    PEXT2_GROUP_DESC group_shadow = 0;\r
 -\r
 -    LARGE_INTEGER   SysTime;\r
 -    \r
 -    NtQuerySystemTime(&SysTime);\r
 -    \r
 -    fs_state = fs->ext2_sb->s_state;\r
 -\r
 -    RtlTimeToSecondsSince1970(&SysTime, &fs->ext2_sb->s_wtime);\r
 -    fs->ext2_sb->s_block_group_nr = 0;\r
 -\r
 -    super_shadow = fs->ext2_sb;\r
 -    group_shadow = fs->group_desc;\r
 -    \r
 -    /*\r
 -     * Write out master superblock.  This has to be done\r
 -     * separately, since it is located at a fixed location\r
 -     * (SUPERBLOCK_OFFSET).\r
 -     */\r
 -    retval = write_primary_superblock(fs, super_shadow);\r
 -    if (!retval)\r
 -        goto errout;\r
 -\r
 -    /*\r
 -     * If this is an external journal device, don't write out the\r
 -     * block group descriptors or any of the backup superblocks\r
 -     */\r
 -    if (fs->ext2_sb->s_feature_incompat &\r
 -        EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)\r
 -    {\r
 -        retval = false;\r
 -        goto errout;\r
 -    }\r
 -\r
 -    /*\r
 -     * Set the state of the FS to be non-valid.  (The state has\r
 -     * already been backed up earlier, and will be restored when\r
 -     * we exit.)\r
 -     */\r
 -    fs->ext2_sb->s_state &= ~EXT2_VALID_FS;\r
 -\r
 -    /*\r
 -     * Write out the master group descriptors, and the backup\r
 -     * superblocks and group descriptors.\r
 -     */\r
 -    group_block = fs->ext2_sb->s_first_data_block;\r
 -    maxgroup = fs->group_desc_count;\r
 -\r
 -    for (i = 0; i < maxgroup; i++)\r
 -    {\r
 -        if (!ext2_bg_has_super(fs->ext2_sb, i))\r
 -            goto next_group;\r
 -\r
 -        sgrp = i;\r
 -        if (sgrp > ((1 << 16) - 1))\r
 -            sgrp = (1 << 16) - 1;\r
 -\r
 -        fs->ext2_sb->s_block_group_nr = (USHORT) sgrp;\r
 -\r
 -        if (i !=0 )\r
 -        {\r
 -            retval = NT_SUCCESS(Ext2WriteDisk(\r
 -                                fs,\r
 -                                ((ULONGLONG)group_block * fs->blocksize),\r
 -                                SUPERBLOCK_SIZE, (PUCHAR)super_shadow));\r
 -\r
 -            if (!retval)\r
 -            {\r
 -                goto errout;\r
 -            }\r
 -        }\r
 -\r
 -        group_ptr = (char *) group_shadow;\r
 -\r
 -        for (j=0; j < fs->desc_blocks; j++)\r
 -        {\r
 -\r
 -            retval = NT_SUCCESS(Ext2WriteDisk(\r
 -                                fs,\r
 -                                ((ULONGLONG)(group_block+1+j) * fs->blocksize),\r
 -                                fs->blocksize, (PUCHAR) group_ptr));\r
 -\r
 -            if (!retval)\r
 -            {\r
 -                goto errout;\r
 -            }\r
 -\r
 -            group_ptr += fs->blocksize;\r
 -        }\r
 -\r
 -    next_group:\r
 -        group_block += EXT2_BLOCKS_PER_GROUP(fs->ext2_sb);\r
 -\r
 -    }\r
 -\r
 -    fs->ext2_sb->s_block_group_nr = 0;\r
 -\r
 -    /*\r
 -     * If the write_bitmaps() function is present, call it to\r
 -     * flush the bitmaps.  This is done this way so that a simple\r
 -     * program that doesn't mess with the bitmaps doesn't need to\r
 -     * drag in the bitmaps.c code.\r
 -     */\r
 -    retval = ext2_write_bitmaps(fs);\r
 -    if (!retval)\r
 -        goto errout;\r
 -\r
 -    /*\r
 -     * Flush the blocks out to disk\r
 -     */\r
 -\r
 -    // retval = io_channel_flush(fs->io);\r
 -\r
 -errout:\r
 -\r
 -    fs->ext2_sb->s_state = (USHORT) fs_state;\r
 -\r
 -    return retval;\r
 -}\r
 -\r
 -\r
 -bool create_journal_dev(PEXT2_FILESYS fs)\r
 -{\r
 -    bool        retval = false;\r
 -    char        *buf = NULL;\r
 -    ULONG       blk;\r
 -    ULONG       count;\r
 -\r
 -    if (!retval)\r
 -    {\r
 -        KdPrint(("Mke2fs: ext2_create_journal_dev: while initializing journal superblock.\n"));\r
 -        return false;\r
 -    }\r
 -\r
 -    KdPrint(("Mke2fs: Zeroing journal device: \n"));\r
 -\r
 -    retval = zero_blocks(fs, 0, fs->ext2_sb->s_blocks_count,\r
 -                 &blk, &count);\r
 -\r
 -    zero_blocks(0, 0, 0, 0, 0);\r
 -\r
 -    if (!retval)\r
 -    {\r
 -        KdPrint(("Mke2fs: create_journal_dev: while zeroing journal device (block %lu, count %lu).\n",\r
 -            blk, count));\r
 -        return false;\r
 -    }\r
 -\r
 -    retval = NT_SUCCESS(Ext2WriteDisk(\r
 -                    fs,\r
 -                    ((ULONGLONG)blk * (fs->ext2_sb->s_first_data_block+1)),\r
 -                    fs->blocksize, (unsigned char *)buf));\r
 -\r
 -    if (!retval)\r
 -    {\r
 -        KdPrint(("Mke2fs: create_journal_dev: while writing journal superblock.\n"));\r
 -        return false;\r
 -    }\r
 -\r
 -    return true;\r
 -}\r
 -\r
 -#define BLOCK_BITS (Ext2Sys->ext2_sb->s_log_block_size + 10)\r
 -\r
 -ULONG\r
 -Ext2DataBlocks(PEXT2_FILESYS Ext2Sys, ULONG TotalBlocks)\r
 -{\r
 -    ULONG   dwData[4] = {1, 1, 1, 1};\r
 -    ULONG   dwMeta[4] = {0, 0, 0, 0};\r
 -    ULONG   DataBlocks = 0;\r
 -    ULONG   i, j;\r
 -\r
 -    if (TotalBlocks <= EXT2_NDIR_BLOCKS)\r
 -    {\r
 -        return TotalBlocks;\r
 -    }\r
 -\r
 -    TotalBlocks -= EXT2_NDIR_BLOCKS;\r
 -\r
 -    for (i = 0; i < 4; i++)\r
 -    {\r
 -        dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);\r
 -\r
 -        if (i > 0)\r
 -        {\r
 -            dwMeta[i] = 1 + (dwMeta[i - 1] << (BLOCK_BITS - 2));\r
 -        }\r
 -    }\r
 -\r
 -    for( i=1; (i < 4) && (TotalBlocks > 0); i++)\r
 -    {\r
 -        if (TotalBlocks >= (dwData[i] + dwMeta[i]))\r
 -        {\r
 -            TotalBlocks -= (dwData[i] + dwMeta[i]);\r
 -            DataBlocks  += dwData[i];\r
 -        }\r
 -        else\r
 -        {\r
 -            ULONG   dwDivide = 0;\r
 -            ULONG   dwRemain = 0;\r
 -\r
 -            for (j=i; (j > 0) && (TotalBlocks > 0); j--)\r
 -            {\r
 -                dwDivide = (TotalBlocks - 1) / (dwData[j-1] + dwMeta[j-1]);\r
 -                dwRemain = (TotalBlocks - 1) % (dwData[j-1] + dwMeta[j-1]);\r
 -\r
 -                DataBlocks += (dwDivide * dwData[j-1]);\r
 -                TotalBlocks = dwRemain;\r
 -            }\r
 -        }\r
 -    }\r
 -\r
 -    return (DataBlocks + EXT2_NDIR_BLOCKS);\r
 -}\r
 -\r
 -\r
 -ULONG\r
 -Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys, ULONG DataBlocks)\r
 -{\r
 -    ULONG   dwData[4] = {1, 1, 1, 1};\r
 -    ULONG   dwMeta[4] = {0, 0, 0, 0};\r
 -    ULONG   TotalBlocks = 0;\r
 -    ULONG   i, j;\r
 -\r
 -    if (DataBlocks <= EXT2_NDIR_BLOCKS)\r
 -    {\r
 -        return DataBlocks;\r
 -    }\r
 -\r
 -    DataBlocks -= EXT2_NDIR_BLOCKS;\r
 -\r
 -    for (i = 0; i < 4; i++)\r
 -    {\r
 -        dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);\r
 -\r
 -        if (i > 0)\r
 -        {\r
 -            dwMeta[i] = 1 + (dwMeta[i - 1] << (BLOCK_BITS - 2));\r
 -        }\r
 -    }\r
 -\r
 -    for( i=1; (i < 4) && (DataBlocks > 0); i++)\r
 -    {\r
 -        if (DataBlocks >= dwData[i])\r
 -        {\r
 -            DataBlocks  -= dwData[i];\r
 -            TotalBlocks += (dwData[i] + dwMeta[i]);\r
 -        }\r
 -        else\r
 -        {\r
 -            ULONG   dwDivide = 0;\r
 -            ULONG   dwRemain = 0;\r
 -\r
 -            for (j=i; (j > 0) && (DataBlocks > 0); j--)\r
 -            {\r
 -                dwDivide = (DataBlocks) / (dwData[j-1]);\r
 -                dwRemain = (DataBlocks) % (dwData[j-1]);\r
 -\r
 -                TotalBlocks += (dwDivide * (dwData[j-1] + dwMeta[j-1]) + 1);\r
 -                DataBlocks = dwRemain;\r
 -            }\r
 -        }\r
 -    }\r
 -\r
 -    return (TotalBlocks + EXT2_NDIR_BLOCKS);\r
 -}\r
 -\r
 -\r
 -NTSTATUS\r
 -Ext2Format(PUNICODE_STRING DriveRoot,\r
 -         ULONG MediaFlag,\r
 -         PUNICODE_STRING Label,\r
 -         BOOLEAN QuickFormat,\r
 -         ULONG ClusterSize,\r
 -         PFMIFSCALLBACK Callback)\r
 -{\r
 -    BOOLEAN    bRet = FALSE;\r
 -    NTSTATUS   Status = STATUS_UNSUCCESSFUL;\r
 -    /* Super Block: 1024 bytes long */\r
 -    EXT2_SUPER_BLOCK Ext2Sb;\r
 -    /* File Sys Structure */\r
 -    EXT2_FILESYS     FileSys;\r
 -    ULONG Percent;\r
 -\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -\r
 -    Callback(PROGRESS, 0, (PVOID)&Percent);\r
 -    \r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -\r
 -    RtlZeroMemory(&Ext2Sb, sizeof(EXT2_SUPER_BLOCK));\r
 -    RtlZeroMemory(&FileSys, sizeof(EXT2_FILESYS));\r
 -    FileSys.ext2_sb = &Ext2Sb;\r
 -\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -\r
 -    if (!NT_SUCCESS(Ext2OpenDevice(&FileSys, DriveRoot)))\r
 -    {\r
 -        KdPrint(("Mke2fs: Volume %wZ does not exist, ...\n", DriveRoot));\r
 -        goto clean_up;\r
 -    }\r
 -\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -\r
 -    if (!NT_SUCCESS(Ext2GetMediaInfo(&FileSys)))\r
 -    {\r
 -        KdPrint(("Mke2fs: Can't get media information\n"));\r
 -        goto clean_up;\r
 -    }\r
 -\r
 -    set_fs_defaults(NULL, &Ext2Sb, ClusterSize, &inode_ratio);\r
 -\r
 -    Ext2Sb.s_blocks_count = FileSys.PartInfo.PartitionLength.QuadPart /\r
 -                            EXT2_BLOCK_SIZE(&Ext2Sb);\r
 -\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -\r
 -    /*\r
 -     * Calculate number of inodes based on the inode ratio\r
 -     */\r
 -    Ext2Sb.s_inodes_count =\r
 -        (ULONG)(((LONGLONG) Ext2Sb.s_blocks_count * EXT2_BLOCK_SIZE(&Ext2Sb)) / inode_ratio);\r
 -\r
 -    /*\r
 -     * Calculate number of blocks to reserve\r
 -     */\r
 -    Ext2Sb.s_r_blocks_count = (Ext2Sb.s_blocks_count * 5) / 100;\r
 -\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -\r
 -    Status = Ext2LockVolume(&FileSys);\r
 -    if (NT_SUCCESS(Status))\r
 -    {\r
 -        bLocked = TRUE;\r
 -    }\r
 -\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -\r
 -    // Initialize \r
 -    if (!ext2_initialize_sb(&FileSys))\r
 -    {\r
 -        KdPrint(("Mke2fs: error...\n"));\r
 -        goto clean_up;\r
 -    }\r
 -\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -\r
 -    zap_sector(&FileSys, 2, 6);\r
 -\r
 -    /*\r
 -     * Generate a UUID for it...\r
 -     */\r
 -    {\r
 -        __u8  uuid[16];\r
 -        uuid_generate(&uuid[0]);\r
 -        memcpy(&Ext2Sb.s_uuid[0], &uuid[0], 16);\r
 -    }\r
 -\r
 -    /*\r
 -     * Add "jitter" to the superblock's check interval so that we\r
 -     * don't check all the filesystems at the same time.  We use a\r
 -     * kludgy hack of using the UUID to derive a random jitter value.\r
 -     */\r
 -    {\r
 -        int i, val;\r
 -\r
 -        for (i = 0, val = 0 ; i < sizeof(Ext2Sb.s_uuid); i++)\r
 -            val += Ext2Sb.s_uuid[i];\r
 -\r
 -        Ext2Sb.s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;\r
 -    }\r
 -\r
 -    /*\r
 -     * Set the volume label...\r
 -     */\r
 -    if (Label)\r
 -    {\r
 -        ANSI_STRING ansi_label;\r
 -        ansi_label.MaximumLength = sizeof(Ext2Sb.s_volume_name);\r
 -        ansi_label.Length = 0;\r
 -        ansi_label.Buffer = Ext2Sb.s_volume_name;\r
 -        RtlUnicodeStringToAnsiString(&ansi_label, Label, FALSE);\r
 -    }\r
 -\r
 -    ext2_print_super(&Ext2Sb);\r
 -\r
 -    bRet = ext2_allocate_tables(&FileSys);\r
 -\r
 -    if (!bRet)\r
 -    {\r
 -        goto clean_up;\r
 -    }\r
 -\r
 -    /* rsv must be a power of two (64kB is MD RAID sb alignment) */\r
 -    ULONG rsv = 65536 / FileSys.blocksize;\r
 -    ULONG blocks = Ext2Sb.s_blocks_count;\r
 -    ULONG start;\r
 -    ULONG ret_blk;\r
 -\r
 -#ifdef ZAP_BOOTBLOCK\r
 -    zap_sector(&FileSys, 0, 2);\r
 -#endif\r
 -\r
 -    /*\r
 -     * Wipe out any old MD RAID (or other) metadata at the end\r
 -     * of the device.  This will also verify that the device is\r
 -     * as large as we think.  Be careful with very small devices.\r
 -     */\r
 -\r
 -    start = (blocks & ~(rsv - 1));\r
 -    if (start > rsv)\r
 -        start -= rsv;\r
 -\r
 -    if (start > 0)\r
 -        bRet = zero_blocks(&FileSys, start, blocks - start, &ret_blk, NULL);\r
 -\r
 -    if (!bRet)\r
 -    {\r
 -        KdPrint(("Mke2fs: zeroing block %lu at end of filesystem", ret_blk));\r
 -        goto clean_up;\r
 -    }\r
 -\r
 -    write_inode_tables(&FileSys);\r
 -\r
 -    create_root_dir(&FileSys);\r
 -    create_lost_and_found(&FileSys);\r
 -\r
 -    ext2_reserve_inodes(&FileSys);\r
 -\r
 -    create_bad_block_inode(&FileSys, NULL);\r
 -\r
 -    KdPrint(("Mke2fs: Writing superblocks and filesystem accounting information ... \n"));\r
 -\r
 -    if (!QuickFormat)\r
 -    {\r
 -        KdPrint(("Mke2fs: Slow format not supported yet\n"));\r
 -    }\r
 -\r
 -    if (!ext2_flush(&FileSys))\r
 -    {\r
 -        bRet = false;\r
 -        KdPrint(("Mke2fs: Warning, had trouble writing out superblocks.\n"));\r
 -        goto clean_up;\r
 -    }\r
 -\r
 -    KdPrint(("Mke2fs: Writing superblocks and filesystem accounting information done!\n"));\r
 -\r
 -    bRet = true;\r
 -    Status = STATUS_SUCCESS;\r
 -\r
 -clean_up:\r
 -\r
 -    // Clean up ...\r
 -    ext2_free_group_desc(&FileSys);\r
 -\r
 -    ext2_free_block_bitmap(&FileSys);\r
 -    ext2_free_inode_bitmap(&FileSys);\r
 -\r
 -    if (!bRet)\r
 -    {\r
 -        Ext2DisMountVolume(&FileSys);\r
 -    }\r
 -    else\r
 -    {\r
 -        if(bLocked)\r
 -        {\r
 -            Ext2UnLockVolume(&FileSys);\r
 -        }\r
 -    }\r
 -\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -    Ext2CloseDevice(&FileSys);\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -    Callback(DONE, 0, (PVOID)&bRet);\r
 -    KdPrint(("%s:%d\n", __FILE__, __LINE__));\r
 -\r
 -    return Status;\r
 -}\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Disk.c
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++/* INCLUDES **************************************************************/
++
++#include "Mke2fs.h"
++#include <fmifs.h>
++
++/* GLOBALS ***************************************************************/
++
++int     inode_ratio = 4096;
++
++BOOLEAN bLocked = FALSE;
++
++/* FUNCTIONS *************************************************************/
++
++int int_log2(int arg)
++{
++    int l = 0;
++
++    arg >>= 1;
++
++    while (arg)
++    {
++        l++;
++        arg >>= 1;
++    }
++
++    return l;
++}
++
++int int_log10(unsigned int arg)
++{
++    int l;
++
++    for (l=0; arg ; l++)
++        arg = arg / 10;
++
++    return l;
++}
++
++
++static char default_str[] = "default";
++
++struct mke2fs_defaults {
++    const char  *type;
++    int     size;
++    int     blocksize;
++    int     inode_ratio;
++} settings[] = {
++    { default_str, 0, 4096, 8192 },
++    { default_str, 512, 1024, 4096 },
++    { default_str, 3, 1024, 8192 },
++    { "journal", 0, 4096, 8192 },
++    { "news", 0, 4096, 4096 },
++    { "largefile", 0, 4096, 1024 * 1024 },
++    { "largefile4", 0, 4096, 4096 * 1024 },
++    { 0, 0, 0, 0},
++};
++
++void set_fs_defaults(const char *fs_type,
++                PEXT2_SUPER_BLOCK super,
++                int blocksize, int *inode_ratio)
++{
++    int megs;
++    int ratio = 0;
++    struct mke2fs_defaults *p;
++
++    megs = (super->s_blocks_count * (EXT2_BLOCK_SIZE(super) / 1024) / 1024);
++
++    if (inode_ratio)
++        ratio = *inode_ratio;
++
++    if (!fs_type)
++        fs_type = default_str;
++
++    for (p = settings; p->type; p++)
++    {
++        if ((strcmp(p->type, fs_type) != 0) &&
++            (strcmp(p->type, default_str) != 0))
++            continue;
++
++        if ((p->size != 0) &&
++            (megs > p->size))
++            continue;
++
++        if (ratio == 0)
++            *inode_ratio = p->inode_ratio;
++
++        if (blocksize == 0)
++        {
++            super->s_log_frag_size = super->s_log_block_size =
++                int_log2(p->blocksize >> EXT2_MIN_BLOCK_LOG_SIZE);
++        }
++    }
++
++    if (blocksize == 0)
++    {
++        super->s_blocks_count /= EXT2_BLOCK_SIZE(super) / 1024;
++    }
++}
++
++/*
++ * Helper function which zeros out _num_ blocks starting at _blk_.  In
++ * case of an error, the details of the error is returned via _ret_blk_
++ * and _ret_count_ if they are non-NULL pointers.  Returns 0 on
++ * success, and an error code on an error.
++ *
++ * As a special case, if the first argument is NULL, then it will
++ * attempt to free the static zeroizing buffer.  (This is to keep
++ * programs that check for memory leaks happy.)
++ */
++bool zero_blocks(PEXT2_FILESYS fs, ULONG blk, ULONG num,
++                 ULONG *ret_blk, ULONG *ret_count)
++{
++    ULONG       j, count, next_update, next_update_incr;
++    static unsigned char        *buf;
++    bool        retval;
++
++    /* If fs is null, clean up the static buffer and return */
++    if (!fs)
++    {
++        if (buf)
++        {
++            RtlFreeHeap(GetProcessHeap(), 0, buf);
++            buf = 0;
++        }
++        return true;
++    }
++
++#define STRIDE_LENGTH 8
++
++    /* Allocate the zeroizing buffer if necessary */
++    if (!buf)
++    {
++        buf = (unsigned char *)
++            RtlAllocateHeap(GetProcessHeap(), 0, fs->blocksize * STRIDE_LENGTH);
++        if (!buf)
++        {
++            KdPrint(("Mke2fs: while allocating zeroizing buffer"));
++            return false;
++        }
++        memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
++    }
++
++    /* OK, do the write loop */
++    next_update = 0;
++    next_update_incr = num / 100;
++    if (next_update_incr < 1)
++        next_update_incr = 1;
++
++    for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH)
++    {
++        if (num-j > STRIDE_LENGTH)
++            count = STRIDE_LENGTH;
++        else
++            count = num - j;
++
++        retval = NT_SUCCESS(Ext2WriteDisk(
++                        fs,
++                        ((ULONGLONG)blk * fs->blocksize),
++                        count * fs->blocksize,
++                        buf));
++
++        if (!retval)
++        {
++            if (ret_count)
++                *ret_count = count;
++
++            if (ret_blk)
++                *ret_blk = blk;
++
++            return retval;
++        }
++    }
++
++    return true;
++}   
++
++
++bool zap_sector(PEXT2_FILESYS Ext2Sys, int sect, int nsect)
++{
++    unsigned char *buf;
++    ULONG         *magic;  
++
++    buf = (unsigned char *)
++        RtlAllocateHeap(GetProcessHeap(), 0, SECTOR_SIZE*nsect);
++    if (!buf)
++    {
++        KdPrint(("Mke2fs: Out of memory erasing sectors %d-%d\n",
++                sect, sect + nsect - 1));
++        return false;
++    }
++
++    memset(buf, 0, (ULONG)nsect * SECTOR_SIZE);
++    
++#define BSD_DISKMAGIC   (0x82564557UL)  /* The disk magic number */
++#define BSD_MAGICDISK   (0x57455682UL)  /* The disk magic number reversed */
++#define BSD_LABEL_OFFSET        64
++
++    if (sect == 0)
++    {
++        Ext2ReadDisk(
++                  Ext2Sys, 
++                  (LONGLONG)(sect * SECTOR_SIZE),
++                  SECTOR_SIZE, buf);
++
++        // Check for a BSD disklabel, and don't erase it if so
++        magic = (ULONG *) (buf + BSD_LABEL_OFFSET);
++        if ((*magic == BSD_DISKMAGIC) ||   (*magic == BSD_MAGICDISK))
++                goto clean_up;
++    }
++
++    // Write buf to disk
++    Ext2WriteDisk( Ext2Sys,
++                   (LONGLONG)(sect * SECTOR_SIZE),
++                   (ULONG)nsect * SECTOR_SIZE,
++                   buf );
++
++clean_up:
++
++    RtlFreeHeap(GetProcessHeap(), 0, buf);
++    
++    return true;
++}
++
++bool ext2_mkdir( PEXT2_FILESYS fs, 
++                 ULONG parent,
++                 ULONG inum, 
++                 char *name,
++                 ULONG *no,
++                 PEXT2_INODE pid )
++{
++    bool            retval;
++    EXT2_INODE      parent_inode, inode;
++    ULONG           ino = inum;
++    //ULONG         scratch_ino;
++    ULONG           blk;
++    char            *block = 0;
++    int             filetype = 0;
++
++    LARGE_INTEGER   SysTime;
++    
++    NtQuerySystemTime(&SysTime);
++
++    /*
++     * Allocate an inode, if necessary
++     */
++    if (!ino)
++    {
++        retval = ext2_new_inode(fs, parent, LINUX_S_IFDIR | 0755, 0, &ino);
++        if (!retval)
++            goto cleanup;
++    }
++
++    if (no)
++        *no = ino;
++
++    /*
++     * Allocate a data block for the directory
++     */
++    retval = ext2_new_block(fs, 0, 0, &blk);
++    if (!retval)
++        goto cleanup;
++
++    /*
++     * Create a scratch template for the directory
++     */
++    retval = ext2_new_dir_block(fs, ino, parent, &block);
++    if (!retval)
++        goto cleanup;
++
++    /*
++     * Get the parent's inode, if necessary
++     */
++    if (parent != ino)
++    {
++        retval = ext2_load_inode(fs, parent, &parent_inode);
++        if (!retval)
++            goto cleanup;
++    }
++    else
++    {
++        memset(&parent_inode, 0, sizeof(parent_inode));
++    }
++
++    /*
++     * Create the inode structure....
++     */
++    memset(&inode, 0, sizeof(EXT2_INODE));
++    inode.i_mode = (USHORT)(LINUX_S_IFDIR | (0777 & ~fs->umask));
++    inode.i_uid = inode.i_gid = 0;
++    inode.i_blocks = fs->blocksize / 512;
++    inode.i_block[0] = blk;
++    inode.i_links_count = 2;
++    RtlTimeToSecondsSince1970(&SysTime, &inode.i_mtime);
++    inode.i_ctime = inode.i_atime = inode.i_mtime;
++    inode.i_size = fs->blocksize;
++
++    /*
++     * Write out the inode and inode data block
++     */
++    retval = ext2_write_block(fs, blk, block);
++    if (!retval)
++        goto cleanup;
++
++    retval = ext2_save_inode(fs, ino, &inode); 
++    if (!retval)
++        goto cleanup;
++
++    if (pid)
++    {
++        *pid = inode;
++    }
++
++    if (parent != ino)
++    {
++        /*
++         * Add entry for this inode to parent dir 's block
++         */
++
++        if (fs->ext2_sb->s_feature_incompat & EXT2_FEATURE_INCOMPAT_FILETYPE)
++                filetype = EXT2_FT_DIR;
++
++        retval = ext2_add_entry(fs, parent, ino, filetype, name);
++
++        if (!retval)
++            goto cleanup;
++
++        /*
++         * Update parent inode's counts
++         */
++
++        parent_inode.i_links_count++;
++        retval = ext2_save_inode(fs, parent, &parent_inode);
++        if (!retval)
++            goto cleanup;
++
++    }
++    
++    /*
++     * Update accounting....
++     */
++    ext2_block_alloc_stats(fs, blk, +1);
++    ext2_inode_alloc_stats2(fs, ino, +1, 1);
++
++cleanup:
++
++    if (block)
++    {
++        RtlFreeHeap(GetProcessHeap(), 0, block);
++        block = NULL;
++    }
++
++    return retval;
++}
++
++bool create_root_dir(PEXT2_FILESYS fs)
++{
++    bool        retval;
++    EXT2_INODE  inode;
++
++    retval = ext2_mkdir(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, 0, NULL, &inode);
++    
++    if (!retval)
++    {
++        KdPrint(("Mke2fs: while creating root dir"));
++        return false;
++    }
++
++    {
++        inode.i_uid = 0;    
++        inode.i_gid = 0;
++
++        retval = ext2_save_inode(fs, EXT2_ROOT_INO, &inode);
++        if (!retval)
++        {
++            KdPrint(("Mke2fs: while setting root inode ownership"));
++            return false;
++        }
++    }
++
++    return true;
++}
++
++bool create_lost_and_found(PEXT2_FILESYS Ext2Sys)
++{
++    bool        retval;
++    ULONG       ino;
++    char        *name = "lost+found";
++    int         lpf_size = 0;
++    EXT2_INODE  inode;
++    ULONG       dwBlk = 0;
++    BOOLEAN     bExt= TRUE;
++
++    PEXT2_DIR_ENTRY dir;
++
++    char *      buf;
++
++    buf = (char *)RtlAllocateHeap(GetProcessHeap(), 0, Ext2Sys->blocksize);
++    if (!buf)
++    {
++        bExt = FALSE;
++    }
++    else
++    {
++        memset(buf, 0, Ext2Sys->blocksize);
++
++        dir = (PEXT2_DIR_ENTRY) buf;
++        dir->rec_len = Ext2Sys->blocksize;
++    }
++
++    Ext2Sys->umask = 077;
++    retval = ext2_mkdir(Ext2Sys, EXT2_ROOT_INO, 0, name, &ino, &inode);
++    
++    if (!retval)
++    {
++        KdPrint(("Mke2fs: while creating /lost+found.\n"));
++        return false;
++    }
++
++    if (!bExt)
++        goto errorout;
++
++    lpf_size = inode.i_size;
++
++    while(TRUE)
++    {
++        if (lpf_size >= 16*1024)
++            break;
++        
++        retval = ext2_alloc_block(Ext2Sys, 0, &dwBlk);
++
++        if (! retval)
++        {
++            KdPrint(("Mke2fs: create_lost_and_found: error alloc block.\n"));
++            break;
++        }
++
++        retval = ext2_expand_inode(Ext2Sys, &inode, dwBlk);
++        if (!retval)
++        {
++            KdPrint(("Mke2fs: errors when expanding /lost+found.\n"));
++            break;
++        }
++
++        ext2_write_block(Ext2Sys, dwBlk, buf);
++
++        inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE);
++        lpf_size += Ext2Sys->blocksize;
++    }
++
++    {
++        inode.i_size = lpf_size;
++
++        ASSERT( (inode.i_size/Ext2Sys->blocksize) == 
++                Ext2DataBlocks(Ext2Sys, inode.i_blocks/(Ext2Sys->blocksize/SECTOR_SIZE)));
++
++        ASSERT( (inode.i_blocks/(Ext2Sys->blocksize/SECTOR_SIZE)) == 
++                Ext2TotalBlocks(Ext2Sys, inode.i_size/Ext2Sys->blocksize));
++
++    }
++
++    ext2_save_inode(Ext2Sys, ino, &inode);
++
++errorout:
++
++    if (buf)
++    {
++        RtlFreeHeap(GetProcessHeap(), 0, buf);
++    }
++
++    return true;
++}
++
++/*
++ * This function forces out the primary superblock.  We need to only
++ * write out those fields which we have changed, since if the
++ * filesystem is mounted, it may have changed some of the other
++ * fields.
++ *
++ * It takes as input a superblock which has already been byte swapped
++ * (if necessary).
++ */
++
++bool write_primary_superblock(PEXT2_FILESYS Ext2Sys, PEXT2_SUPER_BLOCK super)
++{
++    bool bRet;    
++
++    bRet = NT_SUCCESS(Ext2WriteDisk(
++                           Ext2Sys,
++                           ((LONGLONG)SUPERBLOCK_OFFSET),
++                           SUPERBLOCK_SIZE, (PUCHAR)super));
++            
++
++
++    return bRet;
++}
++
++
++/*
++ * Updates the revision to EXT2_DYNAMIC_REV
++ */
++void ext2_update_dynamic_rev(PEXT2_FILESYS fs)
++{
++    PEXT2_SUPER_BLOCK sb = fs->ext2_sb;
++
++    if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
++        return;
++
++    sb->s_rev_level = EXT2_DYNAMIC_REV;
++    sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
++    sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
++    /* s_uuid is handled by e2fsck already */
++    /* other fields should be left alone */
++}
++
++
++bool ext2_flush(PEXT2_FILESYS fs)
++{
++    ULONG       i,j,maxgroup,sgrp;
++    ULONG       group_block;
++    bool        retval;
++    char        *group_ptr;
++    unsigned long fs_state;
++    PEXT2_SUPER_BLOCK super_shadow = 0;
++    PEXT2_GROUP_DESC group_shadow = 0;
++
++    LARGE_INTEGER   SysTime;
++    
++    NtQuerySystemTime(&SysTime);
++    
++    fs_state = fs->ext2_sb->s_state;
++
++    RtlTimeToSecondsSince1970(&SysTime, &fs->ext2_sb->s_wtime);
++    fs->ext2_sb->s_block_group_nr = 0;
++
++    super_shadow = fs->ext2_sb;
++    group_shadow = fs->group_desc;
++    
++    /*
++     * Write out master superblock.  This has to be done
++     * separately, since it is located at a fixed location
++     * (SUPERBLOCK_OFFSET).
++     */
++    retval = write_primary_superblock(fs, super_shadow);
++    if (!retval)
++        goto errout;
++
++    /*
++     * If this is an external journal device, don't write out the
++     * block group descriptors or any of the backup superblocks
++     */
++    if (fs->ext2_sb->s_feature_incompat &
++        EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
++    {
++        retval = false;
++        goto errout;
++    }
++
++    /*
++     * Set the state of the FS to be non-valid.  (The state has
++     * already been backed up earlier, and will be restored when
++     * we exit.)
++     */
++    fs->ext2_sb->s_state &= ~EXT2_VALID_FS;
++
++    /*
++     * Write out the master group descriptors, and the backup
++     * superblocks and group descriptors.
++     */
++    group_block = fs->ext2_sb->s_first_data_block;
++    maxgroup = fs->group_desc_count;
++
++    for (i = 0; i < maxgroup; i++)
++    {
++        if (!ext2_bg_has_super(fs->ext2_sb, i))
++            goto next_group;
++
++        sgrp = i;
++        if (sgrp > ((1 << 16) - 1))
++            sgrp = (1 << 16) - 1;
++
++        fs->ext2_sb->s_block_group_nr = (USHORT) sgrp;
++
++        if (i !=0 )
++        {
++            retval = NT_SUCCESS(Ext2WriteDisk(
++                                fs,
++                                ((ULONGLONG)group_block * fs->blocksize),
++                                SUPERBLOCK_SIZE, (PUCHAR)super_shadow));
++
++            if (!retval)
++            {
++                goto errout;
++            }
++        }
++
++        group_ptr = (char *) group_shadow;
++
++        for (j=0; j < fs->desc_blocks; j++)
++        {
++
++            retval = NT_SUCCESS(Ext2WriteDisk(
++                                fs,
++                                ((ULONGLONG)(group_block+1+j) * fs->blocksize),
++                                fs->blocksize, (PUCHAR) group_ptr));
++
++            if (!retval)
++            {
++                goto errout;
++            }
++
++            group_ptr += fs->blocksize;
++        }
++
++    next_group:
++        group_block += EXT2_BLOCKS_PER_GROUP(fs->ext2_sb);
++
++    }
++
++    fs->ext2_sb->s_block_group_nr = 0;
++
++    /*
++     * If the write_bitmaps() function is present, call it to
++     * flush the bitmaps.  This is done this way so that a simple
++     * program that doesn't mess with the bitmaps doesn't need to
++     * drag in the bitmaps.c code.
++     */
++    retval = ext2_write_bitmaps(fs);
++    if (!retval)
++        goto errout;
++
++    /*
++     * Flush the blocks out to disk
++     */
++
++    // retval = io_channel_flush(fs->io);
++
++errout:
++
++    fs->ext2_sb->s_state = (USHORT) fs_state;
++
++    return retval;
++}
++
++
++bool create_journal_dev(PEXT2_FILESYS fs)
++{
++    bool        retval = false;
++    char        *buf = NULL;
++    ULONG       blk;
++    ULONG       count;
++
++    if (!retval)
++    {
++        KdPrint(("Mke2fs: ext2_create_journal_dev: while initializing journal superblock.\n"));
++        return false;
++    }
++
++    KdPrint(("Mke2fs: Zeroing journal device: \n"));
++
++    retval = zero_blocks(fs, 0, fs->ext2_sb->s_blocks_count,
++                 &blk, &count);
++
++    zero_blocks(0, 0, 0, 0, 0);
++
++    if (!retval)
++    {
++        KdPrint(("Mke2fs: create_journal_dev: while zeroing journal device (block %lu, count %lu).\n",
++            blk, count));
++        return false;
++    }
++
++    retval = NT_SUCCESS(Ext2WriteDisk(
++                    fs,
++                    ((ULONGLONG)blk * (fs->ext2_sb->s_first_data_block+1)),
++                    fs->blocksize, (unsigned char *)buf));
++
++    if (!retval)
++    {
++        KdPrint(("Mke2fs: create_journal_dev: while writing journal superblock.\n"));
++        return false;
++    }
++
++    return true;
++}
++
++#define BLOCK_BITS (Ext2Sys->ext2_sb->s_log_block_size + 10)
++
++ULONG
++Ext2DataBlocks(PEXT2_FILESYS Ext2Sys, ULONG TotalBlocks)
++{
++    ULONG   dwData[4] = {1, 1, 1, 1};
++    ULONG   dwMeta[4] = {0, 0, 0, 0};
++    ULONG   DataBlocks = 0;
++    ULONG   i, j;
++
++    if (TotalBlocks <= EXT2_NDIR_BLOCKS)
++    {
++        return TotalBlocks;
++    }
++
++    TotalBlocks -= EXT2_NDIR_BLOCKS;
++
++    for (i = 0; i < 4; i++)
++    {
++        dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);
++
++        if (i > 0)
++        {
++            dwMeta[i] = 1 + (dwMeta[i - 1] << (BLOCK_BITS - 2));
++        }
++    }
++
++    for( i=1; (i < 4) && (TotalBlocks > 0); i++)
++    {
++        if (TotalBlocks >= (dwData[i] + dwMeta[i]))
++        {
++            TotalBlocks -= (dwData[i] + dwMeta[i]);
++            DataBlocks  += dwData[i];
++        }
++        else
++        {
++            ULONG   dwDivide = 0;
++            ULONG   dwRemain = 0;
++
++            for (j=i; (j > 0) && (TotalBlocks > 0); j--)
++            {
++                dwDivide = (TotalBlocks - 1) / (dwData[j-1] + dwMeta[j-1]);
++                dwRemain = (TotalBlocks - 1) % (dwData[j-1] + dwMeta[j-1]);
++
++                DataBlocks += (dwDivide * dwData[j-1]);
++                TotalBlocks = dwRemain;
++            }
++        }
++    }
++
++    return (DataBlocks + EXT2_NDIR_BLOCKS);
++}
++
++
++ULONG
++Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys, ULONG DataBlocks)
++{
++    ULONG   dwData[4] = {1, 1, 1, 1};
++    ULONG   dwMeta[4] = {0, 0, 0, 0};
++    ULONG   TotalBlocks = 0;
++    ULONG   i, j;
++
++    if (DataBlocks <= EXT2_NDIR_BLOCKS)
++    {
++        return DataBlocks;
++    }
++
++    DataBlocks -= EXT2_NDIR_BLOCKS;
++
++    for (i = 0; i < 4; i++)
++    {
++        dwData[i] = dwData[i] << ((BLOCK_BITS - 2) * i);
++
++        if (i > 0)
++        {
++            dwMeta[i] = 1 + (dwMeta[i - 1] << (BLOCK_BITS - 2));
++        }
++    }
++
++    for( i=1; (i < 4) && (DataBlocks > 0); i++)
++    {
++        if (DataBlocks >= dwData[i])
++        {
++            DataBlocks  -= dwData[i];
++            TotalBlocks += (dwData[i] + dwMeta[i]);
++        }
++        else
++        {
++            ULONG   dwDivide = 0;
++            ULONG   dwRemain = 0;
++
++            for (j=i; (j > 0) && (DataBlocks > 0); j--)
++            {
++                dwDivide = (DataBlocks) / (dwData[j-1]);
++                dwRemain = (DataBlocks) % (dwData[j-1]);
++
++                TotalBlocks += (dwDivide * (dwData[j-1] + dwMeta[j-1]) + 1);
++                DataBlocks = dwRemain;
++            }
++        }
++    }
++
++    return (TotalBlocks + EXT2_NDIR_BLOCKS);
++}
++
++
++NTSTATUS
++Ext2Format(PUNICODE_STRING DriveRoot,
++         ULONG MediaFlag,
++         PUNICODE_STRING Label,
++         BOOLEAN QuickFormat,
++         ULONG ClusterSize,
++         PFMIFSCALLBACK Callback)
++{
++    BOOLEAN    bRet = FALSE;
++    NTSTATUS   Status = STATUS_UNSUCCESSFUL;
++    /* Super Block: 1024 bytes long */
++    EXT2_SUPER_BLOCK Ext2Sb;
++    /* File Sys Structure */
++    EXT2_FILESYS     FileSys;
++    ULONG Percent;
++
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++
++    Callback(PROGRESS, 0, (PVOID)&Percent);
++    
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++
++    RtlZeroMemory(&Ext2Sb, sizeof(EXT2_SUPER_BLOCK));
++    RtlZeroMemory(&FileSys, sizeof(EXT2_FILESYS));
++    FileSys.ext2_sb = &Ext2Sb;
++
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++
++    if (!NT_SUCCESS(Ext2OpenDevice(&FileSys, DriveRoot)))
++    {
++        KdPrint(("Mke2fs: Volume %wZ does not exist, ...\n", DriveRoot));
++        goto clean_up;
++    }
++
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++
++    if (!NT_SUCCESS(Ext2GetMediaInfo(&FileSys)))
++    {
++        KdPrint(("Mke2fs: Can't get media information\n"));
++        goto clean_up;
++    }
++
++    set_fs_defaults(NULL, &Ext2Sb, ClusterSize, &inode_ratio);
++
++    Ext2Sb.s_blocks_count = FileSys.PartInfo.PartitionLength.QuadPart /
++                            EXT2_BLOCK_SIZE(&Ext2Sb);
++
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++
++    /*
++     * Calculate number of inodes based on the inode ratio
++     */
++    Ext2Sb.s_inodes_count =
++        (ULONG)(((LONGLONG) Ext2Sb.s_blocks_count * EXT2_BLOCK_SIZE(&Ext2Sb)) / inode_ratio);
++
++    /*
++     * Calculate number of blocks to reserve
++     */
++    Ext2Sb.s_r_blocks_count = (Ext2Sb.s_blocks_count * 5) / 100;
++
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++
++    Status = Ext2LockVolume(&FileSys);
++    if (NT_SUCCESS(Status))
++    {
++        bLocked = TRUE;
++    }
++
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++
++    // Initialize 
++    if (!ext2_initialize_sb(&FileSys))
++    {
++        KdPrint(("Mke2fs: error...\n"));
++        goto clean_up;
++    }
++
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++
++    zap_sector(&FileSys, 2, 6);
++
++    /*
++     * Generate a UUID for it...
++     */
++    {
++        __u8  uuid[16];
++        uuid_generate(&uuid[0]);
++        memcpy(&Ext2Sb.s_uuid[0], &uuid[0], 16);
++    }
++
++    /*
++     * Add "jitter" to the superblock's check interval so that we
++     * don't check all the filesystems at the same time.  We use a
++     * kludgy hack of using the UUID to derive a random jitter value.
++     */
++    {
++        int i, val;
++
++        for (i = 0, val = 0 ; i < sizeof(Ext2Sb.s_uuid); i++)
++            val += Ext2Sb.s_uuid[i];
++
++        Ext2Sb.s_max_mnt_count += val % EXT2_DFL_MAX_MNT_COUNT;
++    }
++
++    /*
++     * Set the volume label...
++     */
++    if (Label)
++    {
++        ANSI_STRING ansi_label;
++        ansi_label.MaximumLength = sizeof(Ext2Sb.s_volume_name);
++        ansi_label.Length = 0;
++        ansi_label.Buffer = Ext2Sb.s_volume_name;
++        RtlUnicodeStringToAnsiString(&ansi_label, Label, FALSE);
++    }
++
++    ext2_print_super(&Ext2Sb);
++
++    bRet = ext2_allocate_tables(&FileSys);
++
++    if (!bRet)
++    {
++        goto clean_up;
++    }
++
++    /* rsv must be a power of two (64kB is MD RAID sb alignment) */
++    ULONG rsv = 65536 / FileSys.blocksize;
++    ULONG blocks = Ext2Sb.s_blocks_count;
++    ULONG start;
++    ULONG ret_blk;
++
++#ifdef ZAP_BOOTBLOCK
++    zap_sector(&FileSys, 0, 2);
++#endif
++
++    /*
++     * Wipe out any old MD RAID (or other) metadata at the end
++     * of the device.  This will also verify that the device is
++     * as large as we think.  Be careful with very small devices.
++     */
++
++    start = (blocks & ~(rsv - 1));
++    if (start > rsv)
++        start -= rsv;
++
++    if (start > 0)
++        bRet = zero_blocks(&FileSys, start, blocks - start, &ret_blk, NULL);
++
++    if (!bRet)
++    {
++        KdPrint(("Mke2fs: zeroing block %lu at end of filesystem", ret_blk));
++        goto clean_up;
++    }
++
++    write_inode_tables(&FileSys);
++
++    create_root_dir(&FileSys);
++    create_lost_and_found(&FileSys);
++
++    ext2_reserve_inodes(&FileSys);
++
++    create_bad_block_inode(&FileSys, NULL);
++
++    KdPrint(("Mke2fs: Writing superblocks and filesystem accounting information ... \n"));
++
++    if (!QuickFormat)
++    {
++        KdPrint(("Mke2fs: Slow format not supported yet\n"));
++    }
++
++    if (!ext2_flush(&FileSys))
++    {
++        bRet = false;
++        KdPrint(("Mke2fs: Warning, had trouble writing out superblocks.\n"));
++        goto clean_up;
++    }
++
++    KdPrint(("Mke2fs: Writing superblocks and filesystem accounting information done!\n"));
++
++    bRet = true;
++    Status = STATUS_SUCCESS;
++
++clean_up:
++
++    // Clean up ...
++    ext2_free_group_desc(&FileSys);
++
++    ext2_free_block_bitmap(&FileSys);
++    ext2_free_inode_bitmap(&FileSys);
++
++    if (!bRet)
++    {
++        Ext2DisMountVolume(&FileSys);
++    }
++    else
++    {
++        if(bLocked)
++        {
++            Ext2UnLockVolume(&FileSys);
++        }
++    }
++
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++    Ext2CloseDevice(&FileSys);
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++    Callback(DONE, 0, (PVOID)&bRet);
++    KdPrint(("%s:%d\n", __FILE__, __LINE__));
++
++    return Status;
++}
index 0000000,a0353bd..ea05d52
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,876 +1,876 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Mke2fs.h\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -#ifndef __MKE2FS__INCLUDE__\r
 -#define __MKE2FS__INCLUDE__\r
 -\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -\r
 -#include <stdlib.h>\r
 -#include <stdio.h>\r
 -#include <ntddk.h>\r
 -#include <ntdddisk.h>\r
 -\r
 -#include <napi/teb.h>\r
 -\r
 -#include "time.h"\r
 -#include "stdio.h"\r
 -#include "stdlib.h"\r
 -#include "string.h"\r
 -#include "ctype.h"\r
 -\r
 -#include "types.h"\r
 -#include "ext2_fs.h"\r
 -\r
 -#include "getopt.h"\r
 -\r
 -#define NTSYSAPI\r
 -\r
 -/* DEFINITIONS ***********************************************************/\r
 -\r
 -#define SECTOR_SIZE (Ext2Sys->DiskGeometry.BytesPerSector)\r
 -\r
 -#ifndef GUID_DEFINED\r
 -#define GUID_DEFINED\r
 -typedef struct _GUID\r
 -{\r
 -    unsigned long  Data1;\r
 -    unsigned short Data2;\r
 -    unsigned short Data3;\r
 -    unsigned char  Data4[8];\r
 -} GUID;\r
 -#endif /* GUID_DEFINED */\r
 -\r
 -#ifndef UUID_DEFINED\r
 -#define UUID_DEFINED\r
 -typedef GUID UUID;\r
 -#ifndef uuid_t\r
 -#define uuid_t UUID\r
 -#endif\r
 -#endif\r
 -\r
 -#ifndef bool\r
 -#define bool    BOOLEAN\r
 -#endif\r
 -\r
 -#ifndef true\r
 -#define true    TRUE\r
 -#endif\r
 -\r
 -#ifndef false\r
 -#define false   FALSE\r
 -#endif\r
 -\r
 -\r
 -#define EXT2_CHECK_MAGIC(struct, code) \\r
 -      if ((struct)->magic != (code)) return (code)\r
 -\r
 -/*\r
 - * ext2fs_scan flags\r
 - */\r
 -#define EXT2_SF_CHK_BADBLOCKS   0x0001\r
 -#define EXT2_SF_BAD_INODE_BLK   0x0002\r
 -#define EXT2_SF_BAD_EXTRA_BYTES 0x0004\r
 -#define EXT2_SF_SKIP_MISSING_ITABLE 0x0008\r
 -\r
 -/*\r
 - * ext2fs_check_if_mounted flags\r
 - */\r
 -#define EXT2_MF_MOUNTED     1\r
 -#define EXT2_MF_ISROOT      2\r
 -#define EXT2_MF_READONLY    4\r
 -#define EXT2_MF_SWAP        8\r
 -\r
 -/*\r
 - * Ext2/linux mode flags.  We define them here so that we don't need\r
 - * to depend on the OS's sys/stat.h, since we may be compiling on a\r
 - * non-Linux system.\r
 - */\r
 -\r
 -#define LINUX_S_IFMT  00170000\r
 -#define LINUX_S_IFSOCK 0140000\r
 -#define LINUX_S_IFLNK    0120000\r
 -#define LINUX_S_IFREG  0100000\r
 -#define LINUX_S_IFBLK  0060000\r
 -#define LINUX_S_IFDIR  0040000\r
 -#define LINUX_S_IFCHR  0020000\r
 -#define LINUX_S_IFIFO  0010000\r
 -#define LINUX_S_ISUID  0004000\r
 -#define LINUX_S_ISGID  0002000\r
 -#define LINUX_S_ISVTX  0001000\r
 -\r
 -#define LINUX_S_IRWXU 00700\r
 -#define LINUX_S_IRUSR 00400\r
 -#define LINUX_S_IWUSR 00200\r
 -#define LINUX_S_IXUSR 00100\r
 -\r
 -#define LINUX_S_IRWXG 00070\r
 -#define LINUX_S_IRGRP 00040\r
 -#define LINUX_S_IWGRP 00020\r
 -#define LINUX_S_IXGRP 00010\r
 -\r
 -#define LINUX_S_IRWXO 00007\r
 -#define LINUX_S_IROTH 00004\r
 -#define LINUX_S_IWOTH 00002\r
 -#define LINUX_S_IXOTH 00001\r
 -\r
 -#define LINUX_S_ISLNK(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK)\r
 -#define LINUX_S_ISREG(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFREG)\r
 -#define LINUX_S_ISDIR(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR)\r
 -#define LINUX_S_ISCHR(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR)\r
 -#define LINUX_S_ISBLK(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK)\r
 -#define LINUX_S_ISFIFO(m)   (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO)\r
 -#define LINUX_S_ISSOCK(m)   (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK)\r
 -\r
 -\r
 -#define EXT2_FIRST_INODE(s) EXT2_FIRST_INO(s)\r
 -\r
 -typedef struct _ext2fs_bitmap {\r
 -    __u32       start, end;\r
 -    __u32       real_end;\r
 -    char*       bitmap;\r
 -} EXT2_BITMAP, *PEXT2_BITMAP;\r
 -\r
 -typedef EXT2_BITMAP EXT2_GENERIC_BITMAP, *PEXT2_GENERIC_BITMAP;\r
 -typedef EXT2_BITMAP EXT2_INODE_BITMAP, *PEXT2_INODE_BITMAP;\r
 -typedef EXT2_BITMAP EXT2_BLOCK_BITMAP, *PEXT2_BLOCK_BITMAP;\r
 -\r
 -typedef struct ext2_acl_entry   EXT2_ACL_ENTRY, *PEXT2_ACL_ENTRY;\r
 -typedef struct ext2_acl_header  EXT2_ACL_HEADER, *PEXT2_ACL_HEADER;\r
 -typedef struct ext2_dir_entry   EXT2_DIR_ENTRY, *PEXT2_DIR_ENTRY;\r
 -typedef struct ext2_dir_entry_2 EXT2_DIR_ENTRY2, *PEXT2_DIR_ENTRY2;\r
 -typedef struct ext2_dx_countlimit   EXT2_DX_CL, *PEXT2_DX_CL;\r
 -typedef struct ext2_dx_entry    EXT2_DX_ENTRY, *PEXT2_DX_ENTRY;\r
 -typedef struct ext2_dx_root_info    EXT2_DX_RI, *PEXT2_DX_RI;\r
 -typedef struct ext2_inode   EXT2_INODE, *PEXT2_INODE;\r
 -typedef struct ext2_group_desc  EXT2_GROUP_DESC, *PEXT2_GROUP_DESC;\r
 -typedef struct ext2_super_block EXT2_SUPER_BLOCK, *PEXT2_SUPER_BLOCK;\r
 -\r
 -/*\r
 - * Badblocks list\r
 - */\r
 -struct ext2_struct_badblocks_list {\r
 -    int     num;\r
 -    int     size;\r
 -    ULONG   *list;\r
 -    int     badblocks_flags;\r
 -};\r
 -\r
 -typedef struct ext2_struct_badblocks_list EXT2_BADBLK_LIST, *PEXT2_BADBLK_LIST;\r
 -\r
 -typedef struct _ext2_filesys\r
 -{\r
 -    int                 flags;\r
 -    int                 blocksize;\r
 -    int                 fragsize;\r
 -    ULONG               group_desc_count;\r
 -    unsigned long       desc_blocks;\r
 -    PEXT2_GROUP_DESC    group_desc;\r
 -    PEXT2_SUPER_BLOCK   ext2_sb;\r
 -    unsigned long       inode_blocks_per_group;\r
 -    PEXT2_INODE_BITMAP  inode_map;\r
 -    PEXT2_BLOCK_BITMAP  block_map;\r
 -\r
 -    EXT2_BADBLK_LIST    badblocks;\r
 -/*\r
 -    ext2_dblist         dblist;\r
 -*/\r
 -    __u32               stride; /* for mke2fs */\r
 -\r
 -    __u32               umask;\r
 -\r
 -    /*\r
 -     * Reserved for future expansion\r
 -     */\r
 -    __u32               reserved[8];\r
 -\r
 -    /*\r
 -     * Reserved for the use of the calling application.\r
 -     */\r
 -    void *              priv_data;\r
 -\r
 -    HANDLE              MediaHandle;\r
 -\r
 -    DISK_GEOMETRY       DiskGeometry;\r
 -\r
 -    PARTITION_INFORMATION   PartInfo;\r
 -\r
 -} EXT2_FILESYS, *PEXT2_FILESYS;\r
 -\r
 -// Block Description List\r
 -typedef struct _EXT2_BDL {\r
 -    LONGLONG    Lba;\r
 -    ULONG       Offset;\r
 -    ULONG       Length;\r
 -} EXT2_BDL, *PEXT2_BDL;\r
 -\r
 -/*\r
 - * Where the master copy of the superblock is located, and how big\r
 - * superblocks are supposed to be.  We define SUPERBLOCK_SIZE because\r
 - * the size of the superblock structure is not necessarily trustworthy\r
 - * (some versions have the padding set up so that the superblock is\r
 - * 1032 bytes long).\r
 - */\r
 -#define SUPERBLOCK_OFFSET   1024\r
 -#define SUPERBLOCK_SIZE     1024\r
 -\r
 -\r
 -bool create_bad_block_inode(PEXT2_FILESYS fs, PEXT2_BADBLK_LIST bb_list);\r
 -\r
 -\r
 -//\r
 -// Definitions\r
 -//\r
 -\r
 -#define FSCTL_REQUEST_OPLOCK_LEVEL_1    CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  0, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_REQUEST_OPLOCK_LEVEL_2    CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  1, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_REQUEST_BATCH_OPLOCK      CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  2, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE  CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  3, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_OPBATCH_ACK_CLOSE_PENDING CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  4, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_OPLOCK_BREAK_NOTIFY       CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  5, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_LOCK_VOLUME               CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  6, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_UNLOCK_VOLUME             CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  7, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_DISMOUNT_VOLUME           CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  8, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -// decommissioned fsctl value                                              9\r
 -#define FSCTL_IS_VOLUME_MOUNTED         CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 10, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_IS_PATHNAME_VALID         CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 11, METHOD_BUFFERED, FILE_ANY_ACCESS) // PATHNAME_BUFFER,\r
 -#define FSCTL_MARK_VOLUME_DIRTY         CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -// decommissioned fsctl value                                             13\r
 -#define FSCTL_QUERY_RETRIEVAL_POINTERS  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 14,  METHOD_NEITHER, FILE_ANY_ACCESS)\r
 -#define FSCTL_GET_COMPRESSION           CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_SET_COMPRESSION           CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)\r
 -// decommissioned fsctl value                                             17\r
 -// decommissioned fsctl value                                             18\r
 -#define FSCTL_MARK_AS_SYSTEM_HIVE       CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 19,  METHOD_NEITHER, FILE_ANY_ACCESS)\r
 -#define FSCTL_OPLOCK_BREAK_ACK_NO_2     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 20, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_INVALIDATE_VOLUMES        CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 21, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_QUERY_FAT_BPB             CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, FILE_ANY_ACCESS) // , FSCTL_QUERY_FAT_BPB_BUFFER\r
 -#define FSCTL_REQUEST_FILTER_OPLOCK     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 23, METHOD_BUFFERED, FILE_ANY_ACCESS)\r
 -#define FSCTL_FILESYSTEM_GET_STATISTICS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 24, METHOD_BUFFERED, FILE_ANY_ACCESS) // , FILESYSTEM_STATISTICS\r
 -\r
 -\r
 -//\r
 -//  Disk I/O Routines\r
 -//\r
 -\r
 -NTSYSAPI\r
 -NTSTATUS\r
 -NTAPI\r
 -NtReadFile(HANDLE FileHandle,\r
 -    HANDLE Event OPTIONAL,\r
 -    PIO_APC_ROUTINE ApcRoutine OPTIONAL,\r
 -    PVOID ApcContext OPTIONAL,\r
 -    PIO_STATUS_BLOCK IoStatusBlock,\r
 -    PVOID Buffer,\r
 -    ULONG Length,\r
 -    PLARGE_INTEGER ByteOffset OPTIONAL,\r
 -    PULONG Key OPTIONAL);\r
 -\r
 -NTSYSAPI\r
 -NTSTATUS\r
 -NTAPI\r
 -NtWriteFile(HANDLE FileHandle,\r
 -    HANDLE Event OPTIONAL,\r
 -    PIO_APC_ROUTINE ApcRoutine OPTIONAL,\r
 -    PVOID ApcContext OPTIONAL,\r
 -    PIO_STATUS_BLOCK IoStatusBlock,\r
 -    PVOID Buffer,\r
 -    ULONG Length,\r
 -    PLARGE_INTEGER ByteOffset OPTIONAL,\r
 -    PULONG Key OPTIONAL);\r
 -\r
 -NTSYSAPI\r
 -NTSTATUS\r
 -NTAPI\r
 -NtClose(HANDLE Handle);\r
 -\r
 -NTSYSAPI\r
 -NTSTATUS\r
 -NTAPI\r
 -NtCreateFile(PHANDLE FileHandle,\r
 -    ACCESS_MASK DesiredAccess,\r
 -    POBJECT_ATTRIBUTES ObjectAttributes,\r
 -    PIO_STATUS_BLOCK IoStatusBlock,\r
 -    PLARGE_INTEGER AllocationSize OPTIONAL,\r
 -    ULONG FileAttributes,\r
 -    ULONG ShareAccess,\r
 -    ULONG CreateDisposition,\r
 -    ULONG CreateOptions,\r
 -    PVOID EaBuffer OPTIONAL,\r
 -    ULONG EaLength);\r
 -\r
 -\r
 -NTSYSAPI\r
 -NTSTATUS\r
 -NTAPI\r
 -NtDeviceIoControlFile(\r
 -    IN HANDLE  FileHandle,\r
 -    IN HANDLE  Event,\r
 -    IN PIO_APC_ROUTINE  ApcRoutine,\r
 -    IN PVOID  ApcContext,\r
 -    OUT PIO_STATUS_BLOCK  IoStatusBlock,\r
 -    IN ULONG  IoControlCode,\r
 -    IN PVOID  InputBuffer,\r
 -    IN ULONG  InputBufferLength,\r
 -    OUT PVOID  OutputBuffer,\r
 -    OUT ULONG  OutputBufferLength\r
 -    ); \r
 -\r
 -NTSYSAPI\r
 -NTSTATUS\r
 -NTAPI\r
 -NtFsControlFile(\r
 -    IN HANDLE FileHandle,\r
 -    IN HANDLE Event OPTIONAL,\r
 -    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,\r
 -    IN PVOID ApcContext OPTIONAL,\r
 -    OUT PIO_STATUS_BLOCK IoStatusBlock,\r
 -    IN ULONG FsControlCode,\r
 -    IN PVOID InputBuffer OPTIONAL,\r
 -    IN ULONG InputBufferLength,\r
 -    OUT PVOID OutputBuffer OPTIONAL,\r
 -    IN ULONG OutputBufferLength\r
 -);\r
 -\r
 -\r
 -NTSYSAPI\r
 -NTSTATUS\r
 -NTAPI\r
 -NtQueryInformationFile(\r
 -    IN HANDLE  FileHandle,\r
 -    OUT PIO_STATUS_BLOCK  IoStatusBlock,\r
 -    OUT PVOID  FileInformation,\r
 -    IN ULONG  Length,\r
 -    IN FILE_INFORMATION_CLASS  FileInformationClass\r
 -    );\r
 -\r
 -//\r
 -// Bitmap Routines\r
 -//\r
 -\r
 -\r
 -//\r
 -//  BitMap routines.  The following structure, routines, and macros are\r
 -//  for manipulating bitmaps.  The user is responsible for allocating a bitmap\r
 -//  structure (which is really a header) and a buffer (which must be longword\r
 -//  aligned and multiple longwords in size).\r
 -//\r
 -\r
 -//\r
 -//  The following routine initializes a new bitmap.  It does not alter the\r
 -//  data currently in the bitmap.  This routine must be called before\r
 -//  any other bitmap routine/macro.\r
 -//\r
 -\r
 -NTSYSAPI\r
 -VOID\r
 -NTAPI\r
 -RtlInitializeBitMap (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    PULONG BitMapBuffer,\r
 -    ULONG SizeOfBitMap\r
 -    );\r
 -\r
 -//\r
 -//  The following two routines either clear or set all of the bits\r
 -//  in a bitmap.\r
 -//\r
 -\r
 -NTSYSAPI\r
 -VOID\r
 -NTAPI\r
 -RtlClearAllBits (\r
 -    PRTL_BITMAP BitMapHeader\r
 -    );\r
 -\r
 -NTSYSAPI\r
 -VOID\r
 -NTAPI\r
 -RtlSetAllBits (\r
 -    PRTL_BITMAP BitMapHeader\r
 -    );\r
 -\r
 -//\r
 -//  The following two routines locate a contiguous region of either\r
 -//  clear or set bits within the bitmap.  The region will be at least\r
 -//  as large as the number specified, and the search of the bitmap will\r
 -//  begin at the specified hint index (which is a bit index within the\r
 -//  bitmap, zero based).  The return value is the bit index of the located\r
 -//  region (zero based) or -1 (i.e., 0xffffffff) if such a region cannot\r
 -//  be located\r
 -//\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlFindClearBits (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    ULONG NumberToFind,\r
 -    ULONG HintIndex\r
 -    );\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlFindSetBits (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    ULONG NumberToFind,\r
 -    ULONG HintIndex\r
 -    );\r
 -\r
 -//\r
 -//  The following two routines locate a contiguous region of either\r
 -//  clear or set bits within the bitmap and either set or clear the bits\r
 -//  within the located region.  The region will be as large as the number\r
 -//  specified, and the search for the region will begin at the specified\r
 -//  hint index (which is a bit index within the bitmap, zero based).  The\r
 -//  return value is the bit index of the located region (zero based) or\r
 -//  -1 (i.e., 0xffffffff) if such a region cannot be located.  If a region\r
 -//  cannot be located then the setting/clearing of the bitmap is not performed.\r
 -//\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlFindClearBitsAndSet (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    ULONG NumberToFind,\r
 -    ULONG HintIndex\r
 -    );\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlFindSetBitsAndClear (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    ULONG NumberToFind,\r
 -    ULONG HintIndex\r
 -    );\r
 -\r
 -//\r
 -//  The following two routines clear or set bits within a specified region\r
 -//  of the bitmap.  The starting index is zero based.\r
 -//\r
 -\r
 -NTSYSAPI\r
 -VOID\r
 -NTAPI\r
 -RtlClearBits (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    ULONG StartingIndex,\r
 -    ULONG NumberToClear\r
 -    );\r
 -\r
 -NTSYSAPI\r
 -VOID\r
 -NTAPI\r
 -RtlSetBits (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    ULONG StartingIndex,\r
 -    ULONG NumberToSet\r
 -    );\r
 -\r
 -//\r
 -//  The following routine locates a set of contiguous regions of clear\r
 -//  bits within the bitmap.  The caller specifies whether to return the\r
 -//  longest runs or just the first found lcoated.  The following structure is\r
 -//  used to denote a contiguous run of bits.  The two routines return an array\r
 -//  of this structure, one for each run located.\r
 -//\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlFindClearRuns (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    PRTL_BITMAP_RUN RunArray,\r
 -    ULONG SizeOfRunArray,\r
 -    BOOLEAN LocateLongestRuns\r
 -    );\r
 -//\r
 -//  The following routine locates the longest contiguous region of\r
 -//  clear bits within the bitmap.  The returned starting index value\r
 -//  denotes the first contiguous region located satisfying our requirements\r
 -//  The return value is the length (in bits) of the longest region found.\r
 -//\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlFindLongestRunClear (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    PULONG StartingIndex\r
 -    );\r
 -\r
 -//\r
 -//  The following routine locates the first contiguous region of\r
 -//  clear bits within the bitmap.  The returned starting index value\r
 -//  denotes the first contiguous region located satisfying our requirements\r
 -//  The return value is the length (in bits) of the region found.\r
 -//\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlFindFirstRunClear (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    PULONG StartingIndex\r
 -    );\r
 -\r
 -//\r
 -//  The following macro returns the value of the bit stored within the\r
 -//  bitmap at the specified location.  If the bit is set a value of 1 is\r
 -//  returned otherwise a value of 0 is returned.\r
 -//\r
 -//      ULONG\r
 -//      RtlCheckBit (\r
 -//          PRTL_BITMAP BitMapHeader,\r
 -//          ULONG BitPosition\r
 -//          );\r
 -//\r
 -//\r
 -//  To implement CheckBit the macro retrieves the longword containing the\r
 -//  bit in question, shifts the longword to get the bit in question into the\r
 -//  low order bit position and masks out all other bits.\r
 -//\r
 -\r
 -#define RtlCheckBit(BMH,BP) ((((BMH)->Buffer[(BP) / 32]) >> ((BP) % 32)) & 0x1)\r
 -\r
 -//\r
 -//  The following two procedures return to the caller the total number of\r
 -//  clear or set bits within the specified bitmap.\r
 -//\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlNumberOfClearBits (\r
 -    PRTL_BITMAP BitMapHeader\r
 -    );\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlNumberOfSetBits (\r
 -    PRTL_BITMAP BitMapHeader\r
 -    );\r
 -\r
 -//\r
 -//  The following two procedures return to the caller a boolean value\r
 -//  indicating if the specified range of bits are all clear or set.\r
 -//\r
 -\r
 -NTSYSAPI\r
 -BOOLEAN\r
 -NTAPI\r
 -RtlAreBitsClear (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    ULONG StartingIndex,\r
 -    ULONG Length\r
 -    );\r
 -\r
 -NTSYSAPI\r
 -BOOLEAN\r
 -NTAPI\r
 -RtlAreBitsSet (\r
 -    PRTL_BITMAP BitMapHeader,\r
 -    ULONG StartingIndex,\r
 -    ULONG Length\r
 -    );\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlFindNextForwardRunClear (\r
 -    IN PRTL_BITMAP BitMapHeader,\r
 -    IN ULONG FromIndex,\r
 -    IN PULONG StartingRunIndex\r
 -    );\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlFindLastBackwardRunClear (\r
 -    IN PRTL_BITMAP BitMapHeader,\r
 -    IN ULONG FromIndex,\r
 -    IN PULONG StartingRunIndex\r
 -    );\r
 -\r
 -//\r
 -//  The following two procedures return to the caller a value indicating\r
 -//  the position within a ULONGLONG of the most or least significant non-zero\r
 -//  bit.  A value of zero results in a return value of -1.\r
 -//\r
 -\r
 -NTSYSAPI\r
 -CCHAR\r
 -NTAPI\r
 -RtlFindLeastSignificantBit (\r
 -    IN ULONGLONG Set\r
 -    );\r
 -\r
 -NTSYSAPI\r
 -CCHAR\r
 -NTAPI\r
 -RtlFindMostSignificantBit (\r
 -    IN ULONGLONG Set\r
 -    );\r
 -\r
 -\r
 -//\r
 -// Random routines ...\r
 -//\r
 -\r
 -NTSYSAPI\r
 -ULONG\r
 -NTAPI\r
 -RtlRandom(\r
 -    IN OUT PULONG  Seed\r
 -    ); \r
 -\r
 -//\r
 -// Time routines ...\r
 -//\r
 -\r
 -NTSYSAPI\r
 -CCHAR\r
 -NTAPI\r
 -NtQuerySystemTime(\r
 -    OUT PLARGE_INTEGER  CurrentTime\r
 -    );\r
 -\r
 -\r
 -NTSYSAPI\r
 -BOOLEAN\r
 -NTAPI\r
 -RtlTimeToSecondsSince1970(\r
 -    IN PLARGE_INTEGER  Time,\r
 -    OUT PULONG  ElapsedSeconds\r
 -    );\r
 -\r
 -\r
 -NTSYSAPI\r
 -VOID\r
 -NTAPI\r
 -RtlSecondsSince1970ToTime(\r
 -    IN ULONG  ElapsedSeconds,\r
 -    OUT PLARGE_INTEGER  Time\r
 -    );\r
 -\r
 -//\r
 -// Heap routines...\r
 -//\r
 -\r
 -#define GetProcessHeap() (NtCurrentTeb()->Peb->ProcessHeap)\r
 -\r
 -PVOID STDCALL\r
 -RtlAllocateHeap (\r
 -      HANDLE  Heap,\r
 -      ULONG   Flags,\r
 -      ULONG   Size\r
 -      );\r
 -\r
 -BOOLEAN\r
 -STDCALL\r
 -RtlFreeHeap (\r
 -      HANDLE  Heap,\r
 -      ULONG   Flags,\r
 -      PVOID   Address\r
 -      );\r
 -\r
 -/*\r
 - *  Bitmap.c\r
 - */\r
 -\r
 -#define ext2_mark_block_bitmap ext2_mark_bitmap\r
 -#define ext2_mark_inode_bitmap ext2_mark_bitmap\r
 -#define ext2_unmark_block_bitmap ext2_unmark_bitmap\r
 -#define ext2_unmark_inode_bitmap ext2_unmark_bitmap\r
 -\r
 -bool ext2_set_bit(int nr, void * addr);\r
 -bool ext2_clear_bit(int nr, void * addr);\r
 -bool ext2_test_bit(int nr, void * addr);\r
 -\r
 -bool ext2_mark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno);\r
 -bool ext2_unmark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno);\r
 -\r
 -bool ext2_test_block_bitmap(PEXT2_BLOCK_BITMAP bitmap,\r
 -                        ULONG block);\r
 -\r
 -bool ext2_test_block_bitmap_range(PEXT2_BLOCK_BITMAP bitmap,\r
 -                        ULONG block, int num);\r
 -\r
 -bool ext2_test_inode_bitmap(PEXT2_BLOCK_BITMAP bitmap,\r
 -                        ULONG inode);\r
 -\r
 -\r
 -bool ext2_allocate_block_bitmap(PEXT2_FILESYS pExt2Sys);\r
 -bool ext2_allocate_inode_bitmap(PEXT2_FILESYS pExt2Sys);\r
 -void ext2_free_inode_bitmap(PEXT2_FILESYS pExt2Sys);\r
 -void ext2_free_block_bitmap(PEXT2_FILESYS pExt2Sys);\r
 -\r
 -bool ext2_write_block_bitmap (PEXT2_FILESYS fs);\r
 -bool ext2_write_inode_bitmap (PEXT2_FILESYS fs);\r
 -\r
 -bool ext2_write_bitmaps(PEXT2_FILESYS fs);\r
 -\r
 -//bool read_bitmaps(PEXT2_FILESYS fs, int do_inode, int do_block);\r
 -bool ext2_read_inode_bitmap (PEXT2_FILESYS fs);\r
 -bool ext2_read_block_bitmap(PEXT2_FILESYS fs);\r
 -bool ext2_read_bitmaps(PEXT2_FILESYS fs);\r
 -\r
 -\r
 -/*\r
 - *  Disk.c\r
 - */\r
 -\r
 -NTSTATUS\r
 -Ext2OpenDevice( PEXT2_FILESYS    Ext2Sys,\r
 -                PUNICODE_STRING  DeviceName );\r
 -\r
 -NTSTATUS\r
 -Ext2CloseDevice( PEXT2_FILESYS  Ext2Sys);\r
 -\r
 -NTSTATUS \r
 -Ext2ReadDisk( PEXT2_FILESYS  Ext2Sys,\r
 -              ULONGLONG      Offset,\r
 -              ULONG          Length,\r
 -              PVOID          Buffer     );\r
 -\r
 -NTSTATUS\r
 -Ext2WriteDisk( PEXT2_FILESYS  Ext2Sys,\r
 -               ULONGLONG      Offset,\r
 -               ULONG          Length,\r
 -               PVOID          Buffer );\r
 -\r
 -NTSTATUS\r
 -Ext2GetMediaInfo( PEXT2_FILESYS Ext2Sys );\r
 -\r
 -\r
 -NTSTATUS\r
 -Ext2LockVolume( PEXT2_FILESYS Ext2Sys );\r
 -\r
 -NTSTATUS\r
 -Ext2UnLockVolume( PEXT2_FILESYS Ext2Sys );\r
 -\r
 -NTSTATUS\r
 -Ext2DisMountVolume( PEXT2_FILESYS Ext2Sys );\r
 -\r
 -\r
 -/*\r
 - *  Group.c\r
 - */\r
 -\r
 -bool ext2_allocate_group_desc(PEXT2_FILESYS pExt2Sys);\r
 -void ext2_free_group_desc(PEXT2_FILESYS pExt2Sys);\r
 -bool ext2_bg_has_super(PEXT2_SUPER_BLOCK pExt2Sb, int group_block);\r
 -\r
 -/*\r
 - *  Inode.c\r
 - */\r
 -\r
 -bool ext2_get_inode_lba(PEXT2_FILESYS pExt2Sys, ULONG no, LONGLONG *offset);\r
 -bool ext2_load_inode(PEXT2_FILESYS pExt2Sys, ULONG no, PEXT2_INODE pInode);\r
 -bool ext2_save_inode(PEXT2_FILESYS pExt2Sys, ULONG no, PEXT2_INODE pInode);\r
 -bool ext2_new_inode(PEXT2_FILESYS fs, ULONG dir, int mode,\r
 -                      PEXT2_INODE_BITMAP map, ULONG *ret);\r
 -bool ext2_expand_inode(PEXT2_FILESYS pExt2Sys, PEXT2_INODE, ULONG newBlk);\r
 -\r
 -bool ext2_read_inode (PEXT2_FILESYS pExt2Sys,\r
 -            ULONG               ino,\r
 -            ULONG               offset,\r
 -            PVOID               Buffer,\r
 -            ULONG               size,\r
 -            PULONG              dwReturn );\r
 -bool ext2_write_inode (PEXT2_FILESYS pExt2Sys,\r
 -            ULONG               ino,\r
 -            ULONG               offset,\r
 -            PVOID               Buffer,\r
 -            ULONG               size,\r
 -            PULONG              dwReturn );\r
 -\r
 -bool ext2_add_entry(PEXT2_FILESYS pExt2Sys, ULONG parent, ULONG inode, int filetype, char *name);\r
 -bool ext2_reserve_inodes(PEXT2_FILESYS fs);\r
 -/*\r
 - *  Memory.c\r
 - */\r
 -\r
 -//\r
 -// Return the group # of an inode number\r
 -//\r
 -int ext2_group_of_ino(PEXT2_FILESYS fs, ULONG ino);\r
 -\r
 -//\r
 -// Return the group # of a block\r
 -//\r
 -int ext2_group_of_blk(PEXT2_FILESYS fs, ULONG blk);\r
 -\r
 -/*\r
 - *  Badblock.c\r
 - */\r
 -\r
 -\r
 -void ext2_inode_alloc_stats2(PEXT2_FILESYS fs, ULONG ino, int inuse, int isdir);\r
 -void ext2_inode_alloc_stats(PEXT2_FILESYS fs, ULONG ino, int inuse);\r
 -void ext2_block_alloc_stats(PEXT2_FILESYS fs, ULONG blk, int inuse);\r
 -\r
 -bool ext2_allocate_tables(PEXT2_FILESYS pExt2Sys);\r
 -bool ext2_allocate_group_table(PEXT2_FILESYS fs, ULONG group,\r
 -                      PEXT2_BLOCK_BITMAP bmap);\r
 -bool ext2_get_free_blocks(PEXT2_FILESYS fs, ULONG start, ULONG finish,\r
 -                 int num, PEXT2_BLOCK_BITMAP map, ULONG *ret);\r
 -bool write_inode_tables(PEXT2_FILESYS fs);\r
 -\r
 -bool ext2_new_block(PEXT2_FILESYS fs, ULONG goal,\r
 -               PEXT2_BLOCK_BITMAP map, ULONG *ret);\r
 -bool ext2_alloc_block(PEXT2_FILESYS fs, ULONG goal, ULONG *ret);\r
 -bool ext2_new_dir_block(PEXT2_FILESYS fs, ULONG dir_ino,\r
 -                   ULONG parent_ino, char **block);\r
 -bool ext2_write_block(PEXT2_FILESYS fs, ULONG block, void *inbuf);\r
 -bool ext2_read_block(PEXT2_FILESYS fs, ULONG block, void *inbuf);\r
 -\r
 -/*\r
 - *  Mke2fs.c\r
 - */\r
 -\r
 -bool parase_cmd(int argc, char *argv[], PEXT2_FILESYS pExt2Sys);\r
 -\r
 -bool zero_blocks(PEXT2_FILESYS fs, ULONG blk, ULONG num,\r
 -                 ULONG *ret_blk, ULONG *ret_count);\r
 -\r
 -ULONG\r
 -Ext2DataBlocks(PEXT2_FILESYS Ext2Sys, ULONG TotalBlocks);\r
 -\r
 -ULONG\r
 -Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys, ULONG DataBlocks);\r
 -\r
 -\r
 -\r
 -/*\r
 - *  Super.c\r
 - */\r
 -\r
 -void ext2_print_super(PEXT2_SUPER_BLOCK pExt2Sb);\r
 -bool ext2_initialize_sb(PEXT2_FILESYS pExt2Sys);\r
 -\r
 -\r
 -/*\r
 - *  Super.c\r
 - */\r
 -\r
 -LONGLONG ext2_nt_time (ULONG i_time);\r
 -ULONG ext2_unix_time (LONGLONG n_time);\r
 -\r
 -/*\r
 - *  Uuid.c\r
 - */\r
 -\r
 -void uuid_generate(__u8 * uuid);\r
 -\r
 -#endif //__MKE2FS__INCLUDE__\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Mke2fs.h
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++#ifndef __MKE2FS__INCLUDE__
++#define __MKE2FS__INCLUDE__
++
++
++/* INCLUDES **************************************************************/
++
++
++#include <stdlib.h>
++#include <stdio.h>
++#include <ntddk.h>
++#include <ntdddisk.h>
++
++#include <napi/teb.h>
++
++#include "time.h"
++#include "stdio.h"
++#include "stdlib.h"
++#include "string.h"
++#include "ctype.h"
++
++#include "types.h"
++#include "ext2_fs.h"
++
++#include "getopt.h"
++
++#define NTSYSAPI
++
++/* DEFINITIONS ***********************************************************/
++
++#define SECTOR_SIZE (Ext2Sys->DiskGeometry.BytesPerSector)
++
++#ifndef GUID_DEFINED
++#define GUID_DEFINED
++typedef struct _GUID
++{
++    unsigned long  Data1;
++    unsigned short Data2;
++    unsigned short Data3;
++    unsigned char  Data4[8];
++} GUID;
++#endif /* GUID_DEFINED */
++
++#ifndef UUID_DEFINED
++#define UUID_DEFINED
++typedef GUID UUID;
++#ifndef uuid_t
++#define uuid_t UUID
++#endif
++#endif
++
++#ifndef bool
++#define bool    BOOLEAN
++#endif
++
++#ifndef true
++#define true    TRUE
++#endif
++
++#ifndef false
++#define false   FALSE
++#endif
++
++
++#define EXT2_CHECK_MAGIC(struct, code) \
++      if ((struct)->magic != (code)) return (code)
++
++/*
++ * ext2fs_scan flags
++ */
++#define EXT2_SF_CHK_BADBLOCKS   0x0001
++#define EXT2_SF_BAD_INODE_BLK   0x0002
++#define EXT2_SF_BAD_EXTRA_BYTES 0x0004
++#define EXT2_SF_SKIP_MISSING_ITABLE 0x0008
++
++/*
++ * ext2fs_check_if_mounted flags
++ */
++#define EXT2_MF_MOUNTED     1
++#define EXT2_MF_ISROOT      2
++#define EXT2_MF_READONLY    4
++#define EXT2_MF_SWAP        8
++
++/*
++ * Ext2/linux mode flags.  We define them here so that we don't need
++ * to depend on the OS's sys/stat.h, since we may be compiling on a
++ * non-Linux system.
++ */
++
++#define LINUX_S_IFMT  00170000
++#define LINUX_S_IFSOCK 0140000
++#define LINUX_S_IFLNK    0120000
++#define LINUX_S_IFREG  0100000
++#define LINUX_S_IFBLK  0060000
++#define LINUX_S_IFDIR  0040000
++#define LINUX_S_IFCHR  0020000
++#define LINUX_S_IFIFO  0010000
++#define LINUX_S_ISUID  0004000
++#define LINUX_S_ISGID  0002000
++#define LINUX_S_ISVTX  0001000
++
++#define LINUX_S_IRWXU 00700
++#define LINUX_S_IRUSR 00400
++#define LINUX_S_IWUSR 00200
++#define LINUX_S_IXUSR 00100
++
++#define LINUX_S_IRWXG 00070
++#define LINUX_S_IRGRP 00040
++#define LINUX_S_IWGRP 00020
++#define LINUX_S_IXGRP 00010
++
++#define LINUX_S_IRWXO 00007
++#define LINUX_S_IROTH 00004
++#define LINUX_S_IWOTH 00002
++#define LINUX_S_IXOTH 00001
++
++#define LINUX_S_ISLNK(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFLNK)
++#define LINUX_S_ISREG(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFREG)
++#define LINUX_S_ISDIR(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFDIR)
++#define LINUX_S_ISCHR(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFCHR)
++#define LINUX_S_ISBLK(m)    (((m) & LINUX_S_IFMT) == LINUX_S_IFBLK)
++#define LINUX_S_ISFIFO(m)   (((m) & LINUX_S_IFMT) == LINUX_S_IFIFO)
++#define LINUX_S_ISSOCK(m)   (((m) & LINUX_S_IFMT) == LINUX_S_IFSOCK)
++
++
++#define EXT2_FIRST_INODE(s) EXT2_FIRST_INO(s)
++
++typedef struct _ext2fs_bitmap {
++    __u32       start, end;
++    __u32       real_end;
++    char*       bitmap;
++} EXT2_BITMAP, *PEXT2_BITMAP;
++
++typedef EXT2_BITMAP EXT2_GENERIC_BITMAP, *PEXT2_GENERIC_BITMAP;
++typedef EXT2_BITMAP EXT2_INODE_BITMAP, *PEXT2_INODE_BITMAP;
++typedef EXT2_BITMAP EXT2_BLOCK_BITMAP, *PEXT2_BLOCK_BITMAP;
++
++typedef struct ext2_acl_entry   EXT2_ACL_ENTRY, *PEXT2_ACL_ENTRY;
++typedef struct ext2_acl_header  EXT2_ACL_HEADER, *PEXT2_ACL_HEADER;
++typedef struct ext2_dir_entry   EXT2_DIR_ENTRY, *PEXT2_DIR_ENTRY;
++typedef struct ext2_dir_entry_2 EXT2_DIR_ENTRY2, *PEXT2_DIR_ENTRY2;
++typedef struct ext2_dx_countlimit   EXT2_DX_CL, *PEXT2_DX_CL;
++typedef struct ext2_dx_entry    EXT2_DX_ENTRY, *PEXT2_DX_ENTRY;
++typedef struct ext2_dx_root_info    EXT2_DX_RI, *PEXT2_DX_RI;
++typedef struct ext2_inode   EXT2_INODE, *PEXT2_INODE;
++typedef struct ext2_group_desc  EXT2_GROUP_DESC, *PEXT2_GROUP_DESC;
++typedef struct ext2_super_block EXT2_SUPER_BLOCK, *PEXT2_SUPER_BLOCK;
++
++/*
++ * Badblocks list
++ */
++struct ext2_struct_badblocks_list {
++    int     num;
++    int     size;
++    ULONG   *list;
++    int     badblocks_flags;
++};
++
++typedef struct ext2_struct_badblocks_list EXT2_BADBLK_LIST, *PEXT2_BADBLK_LIST;
++
++typedef struct _ext2_filesys
++{
++    int                 flags;
++    int                 blocksize;
++    int                 fragsize;
++    ULONG               group_desc_count;
++    unsigned long       desc_blocks;
++    PEXT2_GROUP_DESC    group_desc;
++    PEXT2_SUPER_BLOCK   ext2_sb;
++    unsigned long       inode_blocks_per_group;
++    PEXT2_INODE_BITMAP  inode_map;
++    PEXT2_BLOCK_BITMAP  block_map;
++
++    EXT2_BADBLK_LIST    badblocks;
++/*
++    ext2_dblist         dblist;
++*/
++    __u32               stride; /* for mke2fs */
++
++    __u32               umask;
++
++    /*
++     * Reserved for future expansion
++     */
++    __u32               reserved[8];
++
++    /*
++     * Reserved for the use of the calling application.
++     */
++    void *              priv_data;
++
++    HANDLE              MediaHandle;
++
++    DISK_GEOMETRY       DiskGeometry;
++
++    PARTITION_INFORMATION   PartInfo;
++
++} EXT2_FILESYS, *PEXT2_FILESYS;
++
++// Block Description List
++typedef struct _EXT2_BDL {
++    LONGLONG    Lba;
++    ULONG       Offset;
++    ULONG       Length;
++} EXT2_BDL, *PEXT2_BDL;
++
++/*
++ * Where the master copy of the superblock is located, and how big
++ * superblocks are supposed to be.  We define SUPERBLOCK_SIZE because
++ * the size of the superblock structure is not necessarily trustworthy
++ * (some versions have the padding set up so that the superblock is
++ * 1032 bytes long).
++ */
++#define SUPERBLOCK_OFFSET   1024
++#define SUPERBLOCK_SIZE     1024
++
++
++bool create_bad_block_inode(PEXT2_FILESYS fs, PEXT2_BADBLK_LIST bb_list);
++
++
++//
++// Definitions
++//
++
++#define FSCTL_REQUEST_OPLOCK_LEVEL_1    CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  0, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_REQUEST_OPLOCK_LEVEL_2    CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  1, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_REQUEST_BATCH_OPLOCK      CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  2, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_OPLOCK_BREAK_ACKNOWLEDGE  CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  3, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_OPBATCH_ACK_CLOSE_PENDING CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  4, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_OPLOCK_BREAK_NOTIFY       CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  5, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_LOCK_VOLUME               CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  6, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_UNLOCK_VOLUME             CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  7, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_DISMOUNT_VOLUME           CTL_CODE(FILE_DEVICE_FILE_SYSTEM,  8, METHOD_BUFFERED, FILE_ANY_ACCESS)
++// decommissioned fsctl value                                              9
++#define FSCTL_IS_VOLUME_MOUNTED         CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 10, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_IS_PATHNAME_VALID         CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 11, METHOD_BUFFERED, FILE_ANY_ACCESS) // PATHNAME_BUFFER,
++#define FSCTL_MARK_VOLUME_DIRTY         CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)
++// decommissioned fsctl value                                             13
++#define FSCTL_QUERY_RETRIEVAL_POINTERS  CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 14,  METHOD_NEITHER, FILE_ANY_ACCESS)
++#define FSCTL_GET_COMPRESSION           CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 15, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_SET_COMPRESSION           CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 16, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA)
++// decommissioned fsctl value                                             17
++// decommissioned fsctl value                                             18
++#define FSCTL_MARK_AS_SYSTEM_HIVE       CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 19,  METHOD_NEITHER, FILE_ANY_ACCESS)
++#define FSCTL_OPLOCK_BREAK_ACK_NO_2     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 20, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_INVALIDATE_VOLUMES        CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 21, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_QUERY_FAT_BPB             CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 22, METHOD_BUFFERED, FILE_ANY_ACCESS) // , FSCTL_QUERY_FAT_BPB_BUFFER
++#define FSCTL_REQUEST_FILTER_OPLOCK     CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 23, METHOD_BUFFERED, FILE_ANY_ACCESS)
++#define FSCTL_FILESYSTEM_GET_STATISTICS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 24, METHOD_BUFFERED, FILE_ANY_ACCESS) // , FILESYSTEM_STATISTICS
++
++
++//
++//  Disk I/O Routines
++//
++
++NTSYSAPI
++NTSTATUS
++NTAPI
++NtReadFile(HANDLE FileHandle,
++    HANDLE Event OPTIONAL,
++    PIO_APC_ROUTINE ApcRoutine OPTIONAL,
++    PVOID ApcContext OPTIONAL,
++    PIO_STATUS_BLOCK IoStatusBlock,
++    PVOID Buffer,
++    ULONG Length,
++    PLARGE_INTEGER ByteOffset OPTIONAL,
++    PULONG Key OPTIONAL);
++
++NTSYSAPI
++NTSTATUS
++NTAPI
++NtWriteFile(HANDLE FileHandle,
++    HANDLE Event OPTIONAL,
++    PIO_APC_ROUTINE ApcRoutine OPTIONAL,
++    PVOID ApcContext OPTIONAL,
++    PIO_STATUS_BLOCK IoStatusBlock,
++    PVOID Buffer,
++    ULONG Length,
++    PLARGE_INTEGER ByteOffset OPTIONAL,
++    PULONG Key OPTIONAL);
++
++NTSYSAPI
++NTSTATUS
++NTAPI
++NtClose(HANDLE Handle);
++
++NTSYSAPI
++NTSTATUS
++NTAPI
++NtCreateFile(PHANDLE FileHandle,
++    ACCESS_MASK DesiredAccess,
++    POBJECT_ATTRIBUTES ObjectAttributes,
++    PIO_STATUS_BLOCK IoStatusBlock,
++    PLARGE_INTEGER AllocationSize OPTIONAL,
++    ULONG FileAttributes,
++    ULONG ShareAccess,
++    ULONG CreateDisposition,
++    ULONG CreateOptions,
++    PVOID EaBuffer OPTIONAL,
++    ULONG EaLength);
++
++
++NTSYSAPI
++NTSTATUS
++NTAPI
++NtDeviceIoControlFile(
++    IN HANDLE  FileHandle,
++    IN HANDLE  Event,
++    IN PIO_APC_ROUTINE  ApcRoutine,
++    IN PVOID  ApcContext,
++    OUT PIO_STATUS_BLOCK  IoStatusBlock,
++    IN ULONG  IoControlCode,
++    IN PVOID  InputBuffer,
++    IN ULONG  InputBufferLength,
++    OUT PVOID  OutputBuffer,
++    OUT ULONG  OutputBufferLength
++    ); 
++
++NTSYSAPI
++NTSTATUS
++NTAPI
++NtFsControlFile(
++    IN HANDLE FileHandle,
++    IN HANDLE Event OPTIONAL,
++    IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
++    IN PVOID ApcContext OPTIONAL,
++    OUT PIO_STATUS_BLOCK IoStatusBlock,
++    IN ULONG FsControlCode,
++    IN PVOID InputBuffer OPTIONAL,
++    IN ULONG InputBufferLength,
++    OUT PVOID OutputBuffer OPTIONAL,
++    IN ULONG OutputBufferLength
++);
++
++
++NTSYSAPI
++NTSTATUS
++NTAPI
++NtQueryInformationFile(
++    IN HANDLE  FileHandle,
++    OUT PIO_STATUS_BLOCK  IoStatusBlock,
++    OUT PVOID  FileInformation,
++    IN ULONG  Length,
++    IN FILE_INFORMATION_CLASS  FileInformationClass
++    );
++
++//
++// Bitmap Routines
++//
++
++
++//
++//  BitMap routines.  The following structure, routines, and macros are
++//  for manipulating bitmaps.  The user is responsible for allocating a bitmap
++//  structure (which is really a header) and a buffer (which must be longword
++//  aligned and multiple longwords in size).
++//
++
++//
++//  The following routine initializes a new bitmap.  It does not alter the
++//  data currently in the bitmap.  This routine must be called before
++//  any other bitmap routine/macro.
++//
++
++NTSYSAPI
++VOID
++NTAPI
++RtlInitializeBitMap (
++    PRTL_BITMAP BitMapHeader,
++    PULONG BitMapBuffer,
++    ULONG SizeOfBitMap
++    );
++
++//
++//  The following two routines either clear or set all of the bits
++//  in a bitmap.
++//
++
++NTSYSAPI
++VOID
++NTAPI
++RtlClearAllBits (
++    PRTL_BITMAP BitMapHeader
++    );
++
++NTSYSAPI
++VOID
++NTAPI
++RtlSetAllBits (
++    PRTL_BITMAP BitMapHeader
++    );
++
++//
++//  The following two routines locate a contiguous region of either
++//  clear or set bits within the bitmap.  The region will be at least
++//  as large as the number specified, and the search of the bitmap will
++//  begin at the specified hint index (which is a bit index within the
++//  bitmap, zero based).  The return value is the bit index of the located
++//  region (zero based) or -1 (i.e., 0xffffffff) if such a region cannot
++//  be located
++//
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlFindClearBits (
++    PRTL_BITMAP BitMapHeader,
++    ULONG NumberToFind,
++    ULONG HintIndex
++    );
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlFindSetBits (
++    PRTL_BITMAP BitMapHeader,
++    ULONG NumberToFind,
++    ULONG HintIndex
++    );
++
++//
++//  The following two routines locate a contiguous region of either
++//  clear or set bits within the bitmap and either set or clear the bits
++//  within the located region.  The region will be as large as the number
++//  specified, and the search for the region will begin at the specified
++//  hint index (which is a bit index within the bitmap, zero based).  The
++//  return value is the bit index of the located region (zero based) or
++//  -1 (i.e., 0xffffffff) if such a region cannot be located.  If a region
++//  cannot be located then the setting/clearing of the bitmap is not performed.
++//
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlFindClearBitsAndSet (
++    PRTL_BITMAP BitMapHeader,
++    ULONG NumberToFind,
++    ULONG HintIndex
++    );
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlFindSetBitsAndClear (
++    PRTL_BITMAP BitMapHeader,
++    ULONG NumberToFind,
++    ULONG HintIndex
++    );
++
++//
++//  The following two routines clear or set bits within a specified region
++//  of the bitmap.  The starting index is zero based.
++//
++
++NTSYSAPI
++VOID
++NTAPI
++RtlClearBits (
++    PRTL_BITMAP BitMapHeader,
++    ULONG StartingIndex,
++    ULONG NumberToClear
++    );
++
++NTSYSAPI
++VOID
++NTAPI
++RtlSetBits (
++    PRTL_BITMAP BitMapHeader,
++    ULONG StartingIndex,
++    ULONG NumberToSet
++    );
++
++//
++//  The following routine locates a set of contiguous regions of clear
++//  bits within the bitmap.  The caller specifies whether to return the
++//  longest runs or just the first found lcoated.  The following structure is
++//  used to denote a contiguous run of bits.  The two routines return an array
++//  of this structure, one for each run located.
++//
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlFindClearRuns (
++    PRTL_BITMAP BitMapHeader,
++    PRTL_BITMAP_RUN RunArray,
++    ULONG SizeOfRunArray,
++    BOOLEAN LocateLongestRuns
++    );
++//
++//  The following routine locates the longest contiguous region of
++//  clear bits within the bitmap.  The returned starting index value
++//  denotes the first contiguous region located satisfying our requirements
++//  The return value is the length (in bits) of the longest region found.
++//
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlFindLongestRunClear (
++    PRTL_BITMAP BitMapHeader,
++    PULONG StartingIndex
++    );
++
++//
++//  The following routine locates the first contiguous region of
++//  clear bits within the bitmap.  The returned starting index value
++//  denotes the first contiguous region located satisfying our requirements
++//  The return value is the length (in bits) of the region found.
++//
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlFindFirstRunClear (
++    PRTL_BITMAP BitMapHeader,
++    PULONG StartingIndex
++    );
++
++//
++//  The following macro returns the value of the bit stored within the
++//  bitmap at the specified location.  If the bit is set a value of 1 is
++//  returned otherwise a value of 0 is returned.
++//
++//      ULONG
++//      RtlCheckBit (
++//          PRTL_BITMAP BitMapHeader,
++//          ULONG BitPosition
++//          );
++//
++//
++//  To implement CheckBit the macro retrieves the longword containing the
++//  bit in question, shifts the longword to get the bit in question into the
++//  low order bit position and masks out all other bits.
++//
++
++#define RtlCheckBit(BMH,BP) ((((BMH)->Buffer[(BP) / 32]) >> ((BP) % 32)) & 0x1)
++
++//
++//  The following two procedures return to the caller the total number of
++//  clear or set bits within the specified bitmap.
++//
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlNumberOfClearBits (
++    PRTL_BITMAP BitMapHeader
++    );
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlNumberOfSetBits (
++    PRTL_BITMAP BitMapHeader
++    );
++
++//
++//  The following two procedures return to the caller a boolean value
++//  indicating if the specified range of bits are all clear or set.
++//
++
++NTSYSAPI
++BOOLEAN
++NTAPI
++RtlAreBitsClear (
++    PRTL_BITMAP BitMapHeader,
++    ULONG StartingIndex,
++    ULONG Length
++    );
++
++NTSYSAPI
++BOOLEAN
++NTAPI
++RtlAreBitsSet (
++    PRTL_BITMAP BitMapHeader,
++    ULONG StartingIndex,
++    ULONG Length
++    );
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlFindNextForwardRunClear (
++    IN PRTL_BITMAP BitMapHeader,
++    IN ULONG FromIndex,
++    IN PULONG StartingRunIndex
++    );
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlFindLastBackwardRunClear (
++    IN PRTL_BITMAP BitMapHeader,
++    IN ULONG FromIndex,
++    IN PULONG StartingRunIndex
++    );
++
++//
++//  The following two procedures return to the caller a value indicating
++//  the position within a ULONGLONG of the most or least significant non-zero
++//  bit.  A value of zero results in a return value of -1.
++//
++
++NTSYSAPI
++CCHAR
++NTAPI
++RtlFindLeastSignificantBit (
++    IN ULONGLONG Set
++    );
++
++NTSYSAPI
++CCHAR
++NTAPI
++RtlFindMostSignificantBit (
++    IN ULONGLONG Set
++    );
++
++
++//
++// Random routines ...
++//
++
++NTSYSAPI
++ULONG
++NTAPI
++RtlRandom(
++    IN OUT PULONG  Seed
++    ); 
++
++//
++// Time routines ...
++//
++
++NTSYSAPI
++CCHAR
++NTAPI
++NtQuerySystemTime(
++    OUT PLARGE_INTEGER  CurrentTime
++    );
++
++
++NTSYSAPI
++BOOLEAN
++NTAPI
++RtlTimeToSecondsSince1970(
++    IN PLARGE_INTEGER  Time,
++    OUT PULONG  ElapsedSeconds
++    );
++
++
++NTSYSAPI
++VOID
++NTAPI
++RtlSecondsSince1970ToTime(
++    IN ULONG  ElapsedSeconds,
++    OUT PLARGE_INTEGER  Time
++    );
++
++//
++// Heap routines...
++//
++
++#define GetProcessHeap() (NtCurrentTeb()->Peb->ProcessHeap)
++
++PVOID STDCALL
++RtlAllocateHeap (
++      HANDLE  Heap,
++      ULONG   Flags,
++      ULONG   Size
++      );
++
++BOOLEAN
++STDCALL
++RtlFreeHeap (
++      HANDLE  Heap,
++      ULONG   Flags,
++      PVOID   Address
++      );
++
++/*
++ *  Bitmap.c
++ */
++
++#define ext2_mark_block_bitmap ext2_mark_bitmap
++#define ext2_mark_inode_bitmap ext2_mark_bitmap
++#define ext2_unmark_block_bitmap ext2_unmark_bitmap
++#define ext2_unmark_inode_bitmap ext2_unmark_bitmap
++
++bool ext2_set_bit(int nr, void * addr);
++bool ext2_clear_bit(int nr, void * addr);
++bool ext2_test_bit(int nr, void * addr);
++
++bool ext2_mark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno);
++bool ext2_unmark_bitmap(PEXT2_BITMAP bitmap, ULONG bitno);
++
++bool ext2_test_block_bitmap(PEXT2_BLOCK_BITMAP bitmap,
++                        ULONG block);
++
++bool ext2_test_block_bitmap_range(PEXT2_BLOCK_BITMAP bitmap,
++                        ULONG block, int num);
++
++bool ext2_test_inode_bitmap(PEXT2_BLOCK_BITMAP bitmap,
++                        ULONG inode);
++
++
++bool ext2_allocate_block_bitmap(PEXT2_FILESYS pExt2Sys);
++bool ext2_allocate_inode_bitmap(PEXT2_FILESYS pExt2Sys);
++void ext2_free_inode_bitmap(PEXT2_FILESYS pExt2Sys);
++void ext2_free_block_bitmap(PEXT2_FILESYS pExt2Sys);
++
++bool ext2_write_block_bitmap (PEXT2_FILESYS fs);
++bool ext2_write_inode_bitmap (PEXT2_FILESYS fs);
++
++bool ext2_write_bitmaps(PEXT2_FILESYS fs);
++
++//bool read_bitmaps(PEXT2_FILESYS fs, int do_inode, int do_block);
++bool ext2_read_inode_bitmap (PEXT2_FILESYS fs);
++bool ext2_read_block_bitmap(PEXT2_FILESYS fs);
++bool ext2_read_bitmaps(PEXT2_FILESYS fs);
++
++
++/*
++ *  Disk.c
++ */
++
++NTSTATUS
++Ext2OpenDevice( PEXT2_FILESYS    Ext2Sys,
++                PUNICODE_STRING  DeviceName );
++
++NTSTATUS
++Ext2CloseDevice( PEXT2_FILESYS  Ext2Sys);
++
++NTSTATUS 
++Ext2ReadDisk( PEXT2_FILESYS  Ext2Sys,
++              ULONGLONG      Offset,
++              ULONG          Length,
++              PVOID          Buffer     );
++
++NTSTATUS
++Ext2WriteDisk( PEXT2_FILESYS  Ext2Sys,
++               ULONGLONG      Offset,
++               ULONG          Length,
++               PVOID          Buffer );
++
++NTSTATUS
++Ext2GetMediaInfo( PEXT2_FILESYS Ext2Sys );
++
++
++NTSTATUS
++Ext2LockVolume( PEXT2_FILESYS Ext2Sys );
++
++NTSTATUS
++Ext2UnLockVolume( PEXT2_FILESYS Ext2Sys );
++
++NTSTATUS
++Ext2DisMountVolume( PEXT2_FILESYS Ext2Sys );
++
++
++/*
++ *  Group.c
++ */
++
++bool ext2_allocate_group_desc(PEXT2_FILESYS pExt2Sys);
++void ext2_free_group_desc(PEXT2_FILESYS pExt2Sys);
++bool ext2_bg_has_super(PEXT2_SUPER_BLOCK pExt2Sb, int group_block);
++
++/*
++ *  Inode.c
++ */
++
++bool ext2_get_inode_lba(PEXT2_FILESYS pExt2Sys, ULONG no, LONGLONG *offset);
++bool ext2_load_inode(PEXT2_FILESYS pExt2Sys, ULONG no, PEXT2_INODE pInode);
++bool ext2_save_inode(PEXT2_FILESYS pExt2Sys, ULONG no, PEXT2_INODE pInode);
++bool ext2_new_inode(PEXT2_FILESYS fs, ULONG dir, int mode,
++                      PEXT2_INODE_BITMAP map, ULONG *ret);
++bool ext2_expand_inode(PEXT2_FILESYS pExt2Sys, PEXT2_INODE, ULONG newBlk);
++
++bool ext2_read_inode (PEXT2_FILESYS pExt2Sys,
++            ULONG               ino,
++            ULONG               offset,
++            PVOID               Buffer,
++            ULONG               size,
++            PULONG              dwReturn );
++bool ext2_write_inode (PEXT2_FILESYS pExt2Sys,
++            ULONG               ino,
++            ULONG               offset,
++            PVOID               Buffer,
++            ULONG               size,
++            PULONG              dwReturn );
++
++bool ext2_add_entry(PEXT2_FILESYS pExt2Sys, ULONG parent, ULONG inode, int filetype, char *name);
++bool ext2_reserve_inodes(PEXT2_FILESYS fs);
++/*
++ *  Memory.c
++ */
++
++//
++// Return the group # of an inode number
++//
++int ext2_group_of_ino(PEXT2_FILESYS fs, ULONG ino);
++
++//
++// Return the group # of a block
++//
++int ext2_group_of_blk(PEXT2_FILESYS fs, ULONG blk);
++
++/*
++ *  Badblock.c
++ */
++
++
++void ext2_inode_alloc_stats2(PEXT2_FILESYS fs, ULONG ino, int inuse, int isdir);
++void ext2_inode_alloc_stats(PEXT2_FILESYS fs, ULONG ino, int inuse);
++void ext2_block_alloc_stats(PEXT2_FILESYS fs, ULONG blk, int inuse);
++
++bool ext2_allocate_tables(PEXT2_FILESYS pExt2Sys);
++bool ext2_allocate_group_table(PEXT2_FILESYS fs, ULONG group,
++                      PEXT2_BLOCK_BITMAP bmap);
++bool ext2_get_free_blocks(PEXT2_FILESYS fs, ULONG start, ULONG finish,
++                 int num, PEXT2_BLOCK_BITMAP map, ULONG *ret);
++bool write_inode_tables(PEXT2_FILESYS fs);
++
++bool ext2_new_block(PEXT2_FILESYS fs, ULONG goal,
++               PEXT2_BLOCK_BITMAP map, ULONG *ret);
++bool ext2_alloc_block(PEXT2_FILESYS fs, ULONG goal, ULONG *ret);
++bool ext2_new_dir_block(PEXT2_FILESYS fs, ULONG dir_ino,
++                   ULONG parent_ino, char **block);
++bool ext2_write_block(PEXT2_FILESYS fs, ULONG block, void *inbuf);
++bool ext2_read_block(PEXT2_FILESYS fs, ULONG block, void *inbuf);
++
++/*
++ *  Mke2fs.c
++ */
++
++bool parase_cmd(int argc, char *argv[], PEXT2_FILESYS pExt2Sys);
++
++bool zero_blocks(PEXT2_FILESYS fs, ULONG blk, ULONG num,
++                 ULONG *ret_blk, ULONG *ret_count);
++
++ULONG
++Ext2DataBlocks(PEXT2_FILESYS Ext2Sys, ULONG TotalBlocks);
++
++ULONG
++Ext2TotalBlocks(PEXT2_FILESYS Ext2Sys, ULONG DataBlocks);
++
++
++
++/*
++ *  Super.c
++ */
++
++void ext2_print_super(PEXT2_SUPER_BLOCK pExt2Sb);
++bool ext2_initialize_sb(PEXT2_FILESYS pExt2Sys);
++
++
++/*
++ *  Super.c
++ */
++
++LONGLONG ext2_nt_time (ULONG i_time);
++ULONG ext2_unix_time (LONGLONG n_time);
++
++/*
++ *  Uuid.c
++ */
++
++void uuid_generate(__u8 * uuid);
++
++#endif //__MKE2FS__INCLUDE__
index 0000000,8d0b36e..0b09490
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,302 +1,302 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Super.c\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -#include "Mke2fs.h"\r
 -\r
 -/* DEFINITIONS ***********************************************************/\r
 -\r
 -extern int inode_ratio;\r
 -\r
 -\r
 -/* FUNCTIONS *************************************************************/\r
 -\r
 -void ext2_print_super(PEXT2_SUPER_BLOCK pExt2Sb)\r
 -{\r
 -    int i;\r
 -\r
 -    KdPrint(("\nExt2 Super Block Details ...\n\n"));\r
 -    KdPrint(("     Inode Count: %lu\n", pExt2Sb->s_inodes_count));\r
 -    KdPrint(("     Block Count: %lu\n", pExt2Sb->s_blocks_count));\r
 -    KdPrint(("     Reserved Block Count: %lu\n", pExt2Sb->s_r_blocks_count));\r
 -    KdPrint(("     Free Blocks: %lu\n", pExt2Sb->s_free_blocks_count));\r
 -    KdPrint(("     Free Inodes: %lu\n", pExt2Sb->s_free_inodes_count));\r
 -    KdPrint(("     First Data Block: %lu\n", pExt2Sb->s_first_data_block));\r
 -    KdPrint(("     Log Block Size: %lu\n", pExt2Sb->s_log_block_size));\r
 -    KdPrint(("     Log Frag Size: %ld\n", pExt2Sb->s_log_frag_size));\r
 -    KdPrint(("     Blocks per Group: %lu\n", pExt2Sb->s_blocks_per_group));\r
 -    KdPrint(("     Fragments per Group: %lu\n", pExt2Sb->s_frags_per_group));\r
 -    KdPrint(("     Inodes per Group: %lu\n", pExt2Sb->s_inodes_per_group));\r
 -//    KdPrint(("     Mount Time: %s", ctime((time_t *) & (pExt2Sb->s_mtime))));\r
 -//    KdPrint(("     Write Time: %s", ctime((time_t *) & (pExt2Sb->s_wtime))));\r
 -    KdPrint(("     Mount Count: %u\n", pExt2Sb->s_mnt_count));\r
 -    KdPrint(("     Max Mount Count: %d\n", pExt2Sb->s_max_mnt_count));\r
 -    KdPrint(("     Magic Number: %X  (%s)\n", pExt2Sb->s_magic,\r
 -        pExt2Sb->s_magic == EXT2_SUPER_MAGIC ? "OK" : "BAD"));\r
 -    KdPrint(("     File System State: %X\n", pExt2Sb->s_state));\r
 -    KdPrint(("     Error Behaviour: %X\n", pExt2Sb->s_errors));\r
 -    KdPrint(("     Minor rev: %u\n", pExt2Sb->s_minor_rev_level));\r
 -//    KdPrint(("     Last Check: %s", ctime((time_t *) & (pExt2Sb->s_lastcheck))));\r
 -    KdPrint(("     Check Interval: %lu\n", pExt2Sb->s_checkinterval));\r
 -    KdPrint(("     Creator OS: %lu\n", pExt2Sb->s_creator_os));\r
 -    KdPrint(("     Revision Level: %lu\n", pExt2Sb->s_rev_level));\r
 -    KdPrint(("     Reserved Block Default UID: %u\n", pExt2Sb->s_def_resuid));\r
 -    KdPrint(("     Reserved Block Default GID: %u\n", pExt2Sb->s_def_resgid)); \r
 -    KdPrint(("     uuid = "));\r
 -    for (i=0; i < 16; i++)\r
 -        KdPrint(("%x ", pExt2Sb->s_uuid[i]));\r
 -    KdPrint(("\n"));\r
 -\r
 -    KdPrint(("     volume label name: "));\r
 -    for (i=0; i < 16; i++)\r
 -    {\r
 -        if (pExt2Sb->s_volume_name[i] == 0)\r
 -            break;\r
 -        KdPrint(("%c", pExt2Sb->s_volume_name[i]));\r
 -    }\r
 -    KdPrint(("\n"));\r
 -\r
 -    KdPrint(("\n\n")); \r
 -}\r
 -    \r
 -\r
 -#define set_field(field, default) if (!pExt2Sb->field) pExt2Sb->field = (default);\r
 -\r
 -/*\r
 - *  Initialize super block ...\r
 - */\r
 -\r
 -bool ext2_initialize_sb(PEXT2_FILESYS Ext2Sys)\r
 -{\r
 -    int frags_per_block = 0;\r
 -    ULONG overhead      = 0;\r
 -    int rem             = 0;\r
 -    ULONG   i = 0;\r
 -    ULONG   group_block = 0;\r
 -    ULONG   numblocks = 0;\r
 -    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;\r
 -    LARGE_INTEGER   SysTime;\r
 -    \r
 -    NtQuerySystemTime(&SysTime);\r
 -\r
 -    Ext2Sys->blocksize = EXT2_BLOCK_SIZE(pExt2Sb);\r
 -    Ext2Sys->fragsize = EXT2_FRAG_SIZE(pExt2Sb);\r
 -    frags_per_block = Ext2Sys->blocksize / Ext2Sys->fragsize;\r
 -\r
 -    pExt2Sb->s_magic = EXT2_SUPER_MAGIC;\r
 -    pExt2Sb->s_state = EXT2_VALID_FS;\r
 -\r
 -    pExt2Sb->s_first_data_block =  (pExt2Sb->s_log_block_size) ? 0 : 1;\r
 -    pExt2Sb->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;\r
 -\r
 -    pExt2Sb->s_errors = EXT2_ERRORS_DEFAULT;\r
 -\r
 -    pExt2Sb->s_checkinterval = EXT2_DFL_CHECKINTERVAL;\r
 -\r
 -    if (!pExt2Sb->s_rev_level)\r
 -        pExt2Sb->s_rev_level = EXT2_GOOD_OLD_REV;\r
 -\r
 -    if (pExt2Sb->s_rev_level >= EXT2_DYNAMIC_REV)\r
 -    {\r
 -        set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);\r
 -        set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);\r
 -    }\r
 -\r
 -    RtlTimeToSecondsSince1970(&SysTime, &pExt2Sb->s_wtime);\r
 -    pExt2Sb->s_lastcheck = pExt2Sb->s_mtime = pExt2Sb->s_wtime;\r
 -\r
 -    if (!pExt2Sb->s_blocks_per_group)\r
 -        pExt2Sb->s_blocks_per_group = Ext2Sys->blocksize * 8;\r
 -\r
 -    pExt2Sb->s_frags_per_group = pExt2Sb->s_blocks_per_group *  frags_per_block;\r
 -    pExt2Sb->s_creator_os = EXT2_OS_WINNT;\r
 -\r
 -    if (pExt2Sb->s_r_blocks_count >= pExt2Sb->s_blocks_count)\r
 -    {\r
 -        goto cleanup;\r
 -    }\r
 -\r
 -    /*\r
 -     * If we're creating an external journal device, we don't need\r
 -     * to bother with the rest.\r
 -     */\r
 -    if (pExt2Sb->s_feature_incompat &\r
 -        EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)\r
 -    {\r
 -        Ext2Sys->group_desc_count = 0;\r
 -        // ext2fs_mark_super_dirty(fs);\r
 -        return true;\r
 -    }\r
 -\r
 -retry:\r
 -\r
 -    Ext2Sys->group_desc_count = (pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block\r
 -        + EXT2_BLOCKS_PER_GROUP(pExt2Sb) - 1) / EXT2_BLOCKS_PER_GROUP(pExt2Sb);\r
 -\r
 -    if (Ext2Sys->group_desc_count == 0)\r
 -        return false;\r
 -\r
 -    Ext2Sys->desc_blocks = (Ext2Sys->group_desc_count +  EXT2_DESC_PER_BLOCK(pExt2Sb)\r
 -        - 1) / EXT2_DESC_PER_BLOCK(pExt2Sb);\r
 -\r
 -    if (!pExt2Sb->s_inodes_count)\r
 -        pExt2Sb->s_inodes_count = pExt2Sb->s_blocks_count / ( inode_ratio /Ext2Sys->blocksize);\r
 -\r
 -    /*\r
 -     * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so\r
 -     * that we have enough inodes for the filesystem(!)\r
 -     */\r
 -    if (pExt2Sb->s_inodes_count < EXT2_FIRST_INODE(pExt2Sb)+1)\r
 -        pExt2Sb->s_inodes_count = EXT2_FIRST_INODE(pExt2Sb)+1;\r
 -\r
 -    /*\r
 -     * There should be at least as many inodes as the user\r
 -     * requested.  Figure out how many inodes per group that\r
 -     * should be.  But make sure that we don't allocate more than\r
 -     * one bitmap's worth of inodes\r
 -     */\r
 -    pExt2Sb->s_inodes_per_group = (pExt2Sb->s_inodes_count + Ext2Sys->group_desc_count - 1)\r
 -        /Ext2Sys->group_desc_count;\r
 -\r
 -    if (pExt2Sb->s_inodes_per_group > (ULONG)(Ext2Sys->blocksize*8))\r
 -        pExt2Sb->s_inodes_per_group = Ext2Sys->blocksize*8;\r
 -\r
 -    /*\r
 -     * Make sure the number of inodes per group completely fills\r
 -     * the inode table blocks in the descriptor.  If not, add some\r
 -     * additional inodes/group.  Waste not, want not...\r
 -     */\r
 -    Ext2Sys->inode_blocks_per_group = (((pExt2Sb->s_inodes_per_group * EXT2_INODE_SIZE(pExt2Sb))\r
 -        + EXT2_BLOCK_SIZE(pExt2Sb) - 1) / EXT2_BLOCK_SIZE(pExt2Sb));\r
 -\r
 -    pExt2Sb->s_inodes_per_group = ((Ext2Sys->inode_blocks_per_group * EXT2_BLOCK_SIZE(pExt2Sb))\r
 -        / EXT2_INODE_SIZE(pExt2Sb));\r
 -\r
 -    /*\r
 -     * Finally, make sure the number of inodes per group is a\r
 -     * multiple of 8.  This is needed to simplify the bitmap\r
 -     * splicing code.\r
 -     */\r
 -    pExt2Sb->s_inodes_per_group &= ~7;\r
 -    Ext2Sys->inode_blocks_per_group = (((pExt2Sb->s_inodes_per_group * EXT2_INODE_SIZE(pExt2Sb))\r
 -        + EXT2_BLOCK_SIZE(pExt2Sb) - 1) / EXT2_BLOCK_SIZE(pExt2Sb));\r
 -\r
 -    /*\r
 -     * adjust inode count to reflect the adjusted inodes_per_group\r
 -     */\r
 -    pExt2Sb->s_inodes_count = pExt2Sb->s_inodes_per_group * Ext2Sys->group_desc_count;\r
 -    pExt2Sb->s_free_inodes_count = pExt2Sb->s_inodes_count;\r
 -\r
 -    /*\r
 -     * Overhead is the number of bookkeeping blocks per group.  It\r
 -     * includes the superblock backup, the group descriptor\r
 -     * backups, the inode bitmap, the block bitmap, and the inode\r
 -     * table.\r
 -     *\r
 -     * XXX Not all block groups need the descriptor blocks, but\r
 -     * being clever is tricky...\r
 -     */\r
 -    overhead = (int) (3 + Ext2Sys->desc_blocks + Ext2Sys->inode_blocks_per_group);\r
 -\r
 -    /*\r
 -     * See if the last group is big enough to support the\r
 -     * necessary data structures.  If not, we need to get rid of\r
 -     * it.\r
 -     */\r
 -    rem = (int) ((pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block) %\r
 -             pExt2Sb->s_blocks_per_group);\r
 -\r
 -    if ((Ext2Sys->group_desc_count == 1) && rem && (rem < overhead))\r
 -        return false;\r
 -\r
 -    if (rem && (rem < overhead+50))\r
 -    {\r
 -        pExt2Sb->s_blocks_count -= rem;\r
 -        goto retry;\r
 -    }\r
 -\r
 -    /*\r
 -     * At this point we know how big the filesystem will be.  So we can do\r
 -     * any and all allocations that depend on the block count.\r
 -     */\r
 -\r
 -    // Allocate block bitmap\r
 -    if(!ext2_allocate_block_bitmap(Ext2Sys))\r
 -    {\r
 -        goto cleanup;\r
 -    }\r
 -\r
 -    // Allocate inode bitmap\r
 -    if(!ext2_allocate_inode_bitmap(Ext2Sys))\r
 -    {\r
 -        goto cleanup;\r
 -    }\r
 -\r
 -    // Allocate gourp desc\r
 -    if(!ext2_allocate_group_desc(Ext2Sys))\r
 -    {\r
 -        goto cleanup;\r
 -    }\r
 -\r
 -    /*\r
 -     * Reserve the superblock and group descriptors for each\r
 -     * group, and fill in the correct group statistics for group.\r
 -     * Note that although the block bitmap, inode bitmap, and\r
 -     * inode table have not been allocated (and in fact won't be\r
 -     * by this routine), they are accounted for nevertheless.\r
 -     */\r
 -    group_block = pExt2Sb->s_first_data_block;\r
 -    numblocks = 0;\r
 -\r
 -    pExt2Sb->s_free_blocks_count = 0;\r
 -\r
 -    for (i = 0; i < Ext2Sys->group_desc_count; i++)\r
 -    {\r
 -        if (i == Ext2Sys->group_desc_count-1)\r
 -        {\r
 -            numblocks = (pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block)\r
 -                % pExt2Sb->s_blocks_per_group;\r
 -\r
 -            if (!numblocks)\r
 -                numblocks = pExt2Sb->s_blocks_per_group;\r
 -        }\r
 -        else\r
 -        {\r
 -            numblocks = pExt2Sb->s_blocks_per_group;\r
 -        }\r
 -\r
 -        if (ext2_bg_has_super(pExt2Sb, i))\r
 -        {\r
 -            ULONG j;\r
 -\r
 -            for (j=0; j < Ext2Sys->desc_blocks+1; j++)\r
 -                ext2_mark_bitmap(Ext2Sys->block_map, group_block + j);\r
 -\r
 -            numblocks -= 1 + Ext2Sys->desc_blocks;\r
 -        }\r
 -        \r
 -        numblocks -= 2 + Ext2Sys->inode_blocks_per_group;\r
 -        \r
 -        pExt2Sb->s_free_blocks_count += numblocks;\r
 -        Ext2Sys->group_desc[i].bg_free_blocks_count = (__u16)numblocks;\r
 -        Ext2Sys->group_desc[i].bg_free_inodes_count = (__u16)pExt2Sb->s_inodes_per_group;\r
 -        Ext2Sys->group_desc[i].bg_used_dirs_count = 0;\r
 -        \r
 -        group_block += pExt2Sb->s_blocks_per_group;\r
 -    }\r
 -\r
 -    return true;\r
 -\r
 -cleanup:\r
 -\r
 -    ext2_free_group_desc(Ext2Sys);\r
 -    ext2_free_block_bitmap(Ext2Sys);\r
 -    ext2_free_inode_bitmap(Ext2Sys);\r
 -\r
 -    return false;\r
 -}\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Super.c
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++/* INCLUDES **************************************************************/
++
++#include "Mke2fs.h"
++
++/* DEFINITIONS ***********************************************************/
++
++extern int inode_ratio;
++
++
++/* FUNCTIONS *************************************************************/
++
++void ext2_print_super(PEXT2_SUPER_BLOCK pExt2Sb)
++{
++    int i;
++
++    KdPrint(("\nExt2 Super Block Details ...\n\n"));
++    KdPrint(("     Inode Count: %lu\n", pExt2Sb->s_inodes_count));
++    KdPrint(("     Block Count: %lu\n", pExt2Sb->s_blocks_count));
++    KdPrint(("     Reserved Block Count: %lu\n", pExt2Sb->s_r_blocks_count));
++    KdPrint(("     Free Blocks: %lu\n", pExt2Sb->s_free_blocks_count));
++    KdPrint(("     Free Inodes: %lu\n", pExt2Sb->s_free_inodes_count));
++    KdPrint(("     First Data Block: %lu\n", pExt2Sb->s_first_data_block));
++    KdPrint(("     Log Block Size: %lu\n", pExt2Sb->s_log_block_size));
++    KdPrint(("     Log Frag Size: %ld\n", pExt2Sb->s_log_frag_size));
++    KdPrint(("     Blocks per Group: %lu\n", pExt2Sb->s_blocks_per_group));
++    KdPrint(("     Fragments per Group: %lu\n", pExt2Sb->s_frags_per_group));
++    KdPrint(("     Inodes per Group: %lu\n", pExt2Sb->s_inodes_per_group));
++//    KdPrint(("     Mount Time: %s", ctime((time_t *) & (pExt2Sb->s_mtime))));
++//    KdPrint(("     Write Time: %s", ctime((time_t *) & (pExt2Sb->s_wtime))));
++    KdPrint(("     Mount Count: %u\n", pExt2Sb->s_mnt_count));
++    KdPrint(("     Max Mount Count: %d\n", pExt2Sb->s_max_mnt_count));
++    KdPrint(("     Magic Number: %X  (%s)\n", pExt2Sb->s_magic,
++        pExt2Sb->s_magic == EXT2_SUPER_MAGIC ? "OK" : "BAD"));
++    KdPrint(("     File System State: %X\n", pExt2Sb->s_state));
++    KdPrint(("     Error Behaviour: %X\n", pExt2Sb->s_errors));
++    KdPrint(("     Minor rev: %u\n", pExt2Sb->s_minor_rev_level));
++//    KdPrint(("     Last Check: %s", ctime((time_t *) & (pExt2Sb->s_lastcheck))));
++    KdPrint(("     Check Interval: %lu\n", pExt2Sb->s_checkinterval));
++    KdPrint(("     Creator OS: %lu\n", pExt2Sb->s_creator_os));
++    KdPrint(("     Revision Level: %lu\n", pExt2Sb->s_rev_level));
++    KdPrint(("     Reserved Block Default UID: %u\n", pExt2Sb->s_def_resuid));
++    KdPrint(("     Reserved Block Default GID: %u\n", pExt2Sb->s_def_resgid)); 
++    KdPrint(("     uuid = "));
++    for (i=0; i < 16; i++)
++        KdPrint(("%x ", pExt2Sb->s_uuid[i]));
++    KdPrint(("\n"));
++
++    KdPrint(("     volume label name: "));
++    for (i=0; i < 16; i++)
++    {
++        if (pExt2Sb->s_volume_name[i] == 0)
++            break;
++        KdPrint(("%c", pExt2Sb->s_volume_name[i]));
++    }
++    KdPrint(("\n"));
++
++    KdPrint(("\n\n")); 
++}
++    
++
++#define set_field(field, default) if (!pExt2Sb->field) pExt2Sb->field = (default);
++
++/*
++ *  Initialize super block ...
++ */
++
++bool ext2_initialize_sb(PEXT2_FILESYS Ext2Sys)
++{
++    int frags_per_block = 0;
++    ULONG overhead      = 0;
++    int rem             = 0;
++    ULONG   i = 0;
++    ULONG   group_block = 0;
++    ULONG   numblocks = 0;
++    PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb;
++    LARGE_INTEGER   SysTime;
++    
++    NtQuerySystemTime(&SysTime);
++
++    Ext2Sys->blocksize = EXT2_BLOCK_SIZE(pExt2Sb);
++    Ext2Sys->fragsize = EXT2_FRAG_SIZE(pExt2Sb);
++    frags_per_block = Ext2Sys->blocksize / Ext2Sys->fragsize;
++
++    pExt2Sb->s_magic = EXT2_SUPER_MAGIC;
++    pExt2Sb->s_state = EXT2_VALID_FS;
++
++    pExt2Sb->s_first_data_block =  (pExt2Sb->s_log_block_size) ? 0 : 1;
++    pExt2Sb->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT;
++
++    pExt2Sb->s_errors = EXT2_ERRORS_DEFAULT;
++
++    pExt2Sb->s_checkinterval = EXT2_DFL_CHECKINTERVAL;
++
++    if (!pExt2Sb->s_rev_level)
++        pExt2Sb->s_rev_level = EXT2_GOOD_OLD_REV;
++
++    if (pExt2Sb->s_rev_level >= EXT2_DYNAMIC_REV)
++    {
++        set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
++        set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
++    }
++
++    RtlTimeToSecondsSince1970(&SysTime, &pExt2Sb->s_wtime);
++    pExt2Sb->s_lastcheck = pExt2Sb->s_mtime = pExt2Sb->s_wtime;
++
++    if (!pExt2Sb->s_blocks_per_group)
++        pExt2Sb->s_blocks_per_group = Ext2Sys->blocksize * 8;
++
++    pExt2Sb->s_frags_per_group = pExt2Sb->s_blocks_per_group *  frags_per_block;
++    pExt2Sb->s_creator_os = EXT2_OS_WINNT;
++
++    if (pExt2Sb->s_r_blocks_count >= pExt2Sb->s_blocks_count)
++    {
++        goto cleanup;
++    }
++
++    /*
++     * If we're creating an external journal device, we don't need
++     * to bother with the rest.
++     */
++    if (pExt2Sb->s_feature_incompat &
++        EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)
++    {
++        Ext2Sys->group_desc_count = 0;
++        // ext2fs_mark_super_dirty(fs);
++        return true;
++    }
++
++retry:
++
++    Ext2Sys->group_desc_count = (pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block
++        + EXT2_BLOCKS_PER_GROUP(pExt2Sb) - 1) / EXT2_BLOCKS_PER_GROUP(pExt2Sb);
++
++    if (Ext2Sys->group_desc_count == 0)
++        return false;
++
++    Ext2Sys->desc_blocks = (Ext2Sys->group_desc_count +  EXT2_DESC_PER_BLOCK(pExt2Sb)
++        - 1) / EXT2_DESC_PER_BLOCK(pExt2Sb);
++
++    if (!pExt2Sb->s_inodes_count)
++        pExt2Sb->s_inodes_count = pExt2Sb->s_blocks_count / ( inode_ratio /Ext2Sys->blocksize);
++
++    /*
++     * Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
++     * that we have enough inodes for the filesystem(!)
++     */
++    if (pExt2Sb->s_inodes_count < EXT2_FIRST_INODE(pExt2Sb)+1)
++        pExt2Sb->s_inodes_count = EXT2_FIRST_INODE(pExt2Sb)+1;
++
++    /*
++     * There should be at least as many inodes as the user
++     * requested.  Figure out how many inodes per group that
++     * should be.  But make sure that we don't allocate more than
++     * one bitmap's worth of inodes
++     */
++    pExt2Sb->s_inodes_per_group = (pExt2Sb->s_inodes_count + Ext2Sys->group_desc_count - 1)
++        /Ext2Sys->group_desc_count;
++
++    if (pExt2Sb->s_inodes_per_group > (ULONG)(Ext2Sys->blocksize*8))
++        pExt2Sb->s_inodes_per_group = Ext2Sys->blocksize*8;
++
++    /*
++     * Make sure the number of inodes per group completely fills
++     * the inode table blocks in the descriptor.  If not, add some
++     * additional inodes/group.  Waste not, want not...
++     */
++    Ext2Sys->inode_blocks_per_group = (((pExt2Sb->s_inodes_per_group * EXT2_INODE_SIZE(pExt2Sb))
++        + EXT2_BLOCK_SIZE(pExt2Sb) - 1) / EXT2_BLOCK_SIZE(pExt2Sb));
++
++    pExt2Sb->s_inodes_per_group = ((Ext2Sys->inode_blocks_per_group * EXT2_BLOCK_SIZE(pExt2Sb))
++        / EXT2_INODE_SIZE(pExt2Sb));
++
++    /*
++     * Finally, make sure the number of inodes per group is a
++     * multiple of 8.  This is needed to simplify the bitmap
++     * splicing code.
++     */
++    pExt2Sb->s_inodes_per_group &= ~7;
++    Ext2Sys->inode_blocks_per_group = (((pExt2Sb->s_inodes_per_group * EXT2_INODE_SIZE(pExt2Sb))
++        + EXT2_BLOCK_SIZE(pExt2Sb) - 1) / EXT2_BLOCK_SIZE(pExt2Sb));
++
++    /*
++     * adjust inode count to reflect the adjusted inodes_per_group
++     */
++    pExt2Sb->s_inodes_count = pExt2Sb->s_inodes_per_group * Ext2Sys->group_desc_count;
++    pExt2Sb->s_free_inodes_count = pExt2Sb->s_inodes_count;
++
++    /*
++     * Overhead is the number of bookkeeping blocks per group.  It
++     * includes the superblock backup, the group descriptor
++     * backups, the inode bitmap, the block bitmap, and the inode
++     * table.
++     *
++     * XXX Not all block groups need the descriptor blocks, but
++     * being clever is tricky...
++     */
++    overhead = (int) (3 + Ext2Sys->desc_blocks + Ext2Sys->inode_blocks_per_group);
++
++    /*
++     * See if the last group is big enough to support the
++     * necessary data structures.  If not, we need to get rid of
++     * it.
++     */
++    rem = (int) ((pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block) %
++             pExt2Sb->s_blocks_per_group);
++
++    if ((Ext2Sys->group_desc_count == 1) && rem && (rem < overhead))
++        return false;
++
++    if (rem && (rem < overhead+50))
++    {
++        pExt2Sb->s_blocks_count -= rem;
++        goto retry;
++    }
++
++    /*
++     * At this point we know how big the filesystem will be.  So we can do
++     * any and all allocations that depend on the block count.
++     */
++
++    // Allocate block bitmap
++    if(!ext2_allocate_block_bitmap(Ext2Sys))
++    {
++        goto cleanup;
++    }
++
++    // Allocate inode bitmap
++    if(!ext2_allocate_inode_bitmap(Ext2Sys))
++    {
++        goto cleanup;
++    }
++
++    // Allocate gourp desc
++    if(!ext2_allocate_group_desc(Ext2Sys))
++    {
++        goto cleanup;
++    }
++
++    /*
++     * Reserve the superblock and group descriptors for each
++     * group, and fill in the correct group statistics for group.
++     * Note that although the block bitmap, inode bitmap, and
++     * inode table have not been allocated (and in fact won't be
++     * by this routine), they are accounted for nevertheless.
++     */
++    group_block = pExt2Sb->s_first_data_block;
++    numblocks = 0;
++
++    pExt2Sb->s_free_blocks_count = 0;
++
++    for (i = 0; i < Ext2Sys->group_desc_count; i++)
++    {
++        if (i == Ext2Sys->group_desc_count-1)
++        {
++            numblocks = (pExt2Sb->s_blocks_count - pExt2Sb->s_first_data_block)
++                % pExt2Sb->s_blocks_per_group;
++
++            if (!numblocks)
++                numblocks = pExt2Sb->s_blocks_per_group;
++        }
++        else
++        {
++            numblocks = pExt2Sb->s_blocks_per_group;
++        }
++
++        if (ext2_bg_has_super(pExt2Sb, i))
++        {
++            ULONG j;
++
++            for (j=0; j < Ext2Sys->desc_blocks+1; j++)
++                ext2_mark_bitmap(Ext2Sys->block_map, group_block + j);
++
++            numblocks -= 1 + Ext2Sys->desc_blocks;
++        }
++        
++        numblocks -= 2 + Ext2Sys->inode_blocks_per_group;
++        
++        pExt2Sb->s_free_blocks_count += numblocks;
++        Ext2Sys->group_desc[i].bg_free_blocks_count = (__u16)numblocks;
++        Ext2Sys->group_desc[i].bg_free_inodes_count = (__u16)pExt2Sb->s_inodes_per_group;
++        Ext2Sys->group_desc[i].bg_used_dirs_count = 0;
++        
++        group_block += pExt2Sb->s_blocks_per_group;
++    }
++
++    return true;
++
++cleanup:
++
++    ext2_free_group_desc(Ext2Sys);
++    ext2_free_block_bitmap(Ext2Sys);
++    ext2_free_inode_bitmap(Ext2Sys);
++
++    return false;
++}
index 0000000,1e029da..5284cd9
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,25 +1,25 @@@
 -/*\r
 - * PROJECT:          Mke2fs\r
 - * FILE:             Timer.c\r
 - * PROGRAMMER:       Matt Wu <mattwu@163.com>\r
 - * HOMEPAGE:         http://ext2.yeah.net\r
 - */\r
 -\r
 -/* INCLUDES **************************************************************/\r
 -\r
 -#include "windows.h"\r
 -#include "types.h"\r
 -\r
 -/* DEFINITIONS ***********************************************************/\r
 -\r
 -\r
 -/* FUNCTIONS *************************************************************/\r
 -\r
 -void uuid_generate(__u8 * uuid)\r
 -{\r
 -#if 0\r
 -    UuidCreate((UUID *) uuid);\r
 -#else\r
 -    RtlZeroMemory(uuid, 16);\r
 -#endif\r
 -}\r
++/*
++ * PROJECT:          Mke2fs
++ * FILE:             Timer.c
++ * PROGRAMMER:       Matt Wu <mattwu@163.com>
++ * HOMEPAGE:         http://ext2.yeah.net
++ */
++
++/* INCLUDES **************************************************************/
++
++#include "windows.h"
++#include "types.h"
++
++/* DEFINITIONS ***********************************************************/
++
++
++/* FUNCTIONS *************************************************************/
++
++void uuid_generate(__u8 * uuid)
++{
++#if 0
++    UuidCreate((UUID *) uuid);
++#else
++    RtlZeroMemory(uuid, 16);
++#endif
++}
index 0000000,05ab2d8..be4cafa
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,657 +1,657 @@@
 -/*\r
 - *  linux/include/linux/ext2_fs.h\r
 - *\r
 - * Copyright (C) 1992, 1993, 1994, 1995\r
 - * Remy Card (card@masi.ibp.fr)\r
 - * Laboratoire MASI - Institut Blaise Pascal\r
 - * Universite Pierre et Marie Curie (Paris VI)\r
 - *\r
 - *  from\r
 - *\r
 - *  linux/include/linux/minix_fs.h\r
 - *\r
 - *  Copyright f(C) 1991, 1992  Linus Torvalds\r
 - */\r
 -\r
 -#ifndef _LINUX_EXT2_FS_H\r
 -#define _LINUX_EXT2_FS_H\r
 -\r
 -#include "types.h"            /* Changed from linux/types.h */\r
 -\r
 -/*\r
 - * The second extended filesystem constants/structures\r
 - */\r
 -\r
 -/*\r
 - * Define EXT2FS_DEBUG to produce debug messages\r
 - */\r
 -#undef EXT2FS_DEBUG\r
 -\r
 -/*\r
 - * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files\r
 - */\r
 -#define EXT2_PREALLOCATE\r
 -#define EXT2_DEFAULT_PREALLOC_BLOCKS  8\r
 -\r
 -/*\r
 - * The second extended file system version\r
 - */\r
 -#define EXT2FS_DATE           "95/08/09"\r
 -#define EXT2FS_VERSION                "0.5b"\r
 -\r
 -/*\r
 - * Special inodes numbers\r
 - */\r
 -#define       EXT2_BAD_INO             1      /* Bad blocks inode */\r
 -#define EXT2_ROOT_INO          2      /* Root inode */\r
 -#define EXT2_ACL_IDX_INO       3      /* ACL inode */\r
 -#define EXT2_ACL_DATA_INO      4      /* ACL inode */\r
 -#define EXT2_BOOT_LOADER_INO   5      /* Boot loader inode */\r
 -#define EXT2_UNDEL_DIR_INO     6      /* Undelete directory inode */\r
 -#define EXT2_RESIZE_INO                7      /* Reserved group descriptors inode */\r
 -#define EXT2_JOURNAL_INO       8      /* Journal inode */\r
 -\r
 -/* First non-reserved inode for old ext2 filesystems */\r
 -#define EXT2_GOOD_OLD_FIRST_INO       11\r
 -\r
 -/*\r
 - * The second extended file system magic number\r
 - */\r
 -#define EXT2_SUPER_MAGIC      0xEF53\r
 -\r
 -/*\r
 - * Maximal count of links to a file\r
 - */\r
 -#define EXT2_LINK_MAX         32000\r
 -\r
 -/*\r
 - * Macro-instructions used to manage several block sizes\r
 - */\r
 -#define EXT2_MIN_BLOCK_SIZE           1024\r
 -#define       EXT2_MAX_BLOCK_SIZE             4096\r
 -#define EXT2_MIN_BLOCK_LOG_SIZE                 10\r
 -#ifdef __KERNEL__\r
 -# define EXT2_BLOCK_SIZE(s)           ((s)->s_blocksize)\r
 -#else\r
 -# define EXT2_BLOCK_SIZE(s)           (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)\r
 -#endif\r
 -#define EXT2_ACLE_PER_BLOCK(s)                (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))\r
 -#define       EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))\r
 -#ifdef __KERNEL__\r
 -# define EXT2_BLOCK_SIZE_BITS(s)      ((s)->s_blocksize_bits)\r
 -#else\r
 -# define EXT2_BLOCK_SIZE_BITS(s)      ((s)->s_log_block_size + 10)\r
 -#endif\r
 -#ifdef __KERNEL__\r
 -#define       EXT2_ADDR_PER_BLOCK_BITS(s)     ((s)->u.ext2_sb.s_addr_per_block_bits)\r
 -#define EXT2_INODE_SIZE(s)            ((s)->u.ext2_sb.s_inode_size)\r
 -#define EXT2_FIRST_INO(s)             ((s)->u.ext2_sb.s_first_ino)\r
 -#else\r
 -#define EXT2_INODE_SIZE(s)    (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \\r
 -                               EXT2_GOOD_OLD_INODE_SIZE : \\r
 -                               (s)->s_inode_size)\r
 -#define EXT2_FIRST_INO(s)     (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \\r
 -                               EXT2_GOOD_OLD_FIRST_INO : \\r
 -                               (s)->s_first_ino)\r
 -#endif\r
 -\r
 -/*\r
 - * Macro-instructions used to manage fragments\r
 - */\r
 -#define EXT2_MIN_FRAG_SIZE            1024\r
 -#define       EXT2_MAX_FRAG_SIZE              4096\r
 -#define EXT2_MIN_FRAG_LOG_SIZE                  10\r
 -#ifdef __KERNEL__\r
 -# define EXT2_FRAG_SIZE(s)            ((s)->u.ext2_sb.s_frag_size)\r
 -# define EXT2_FRAGS_PER_BLOCK(s)      ((s)->u.ext2_sb.s_frags_per_block)\r
 -#else\r
 -# define EXT2_FRAG_SIZE(s)            (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)\r
 -# define EXT2_FRAGS_PER_BLOCK(s)      (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))\r
 -#endif\r
 -\r
 -/*\r
 - * ACL structures\r
 - */\r
 -struct ext2_acl_header        /* Header of Access Control Lists */\r
 -{\r
 -      __u32   aclh_size;\r
 -      __u32   aclh_file_count;\r
 -      __u32   aclh_acle_count;\r
 -      __u32   aclh_first_acle;\r
 -};\r
 -\r
 -struct ext2_acl_entry /* Access Control List Entry */\r
 -{\r
 -      __u32   acle_size;\r
 -      __u16   acle_perms;     /* Access permissions */\r
 -      __u16   acle_type;      /* Type of entry */\r
 -      __u16   acle_tag;       /* User or group identity */\r
 -      __u16   acle_pad1;\r
 -      __u32   acle_next;      /* Pointer on next entry for the */\r
 -                                      /* same inode or on next free entry */\r
 -};\r
 -\r
 -/*\r
 - * Structure of a blocks group descriptor\r
 - */\r
 -struct ext2_group_desc\r
 -{\r
 -      __u32   bg_block_bitmap;                /* Blocks bitmap block */\r
 -      __u32   bg_inode_bitmap;                /* Inodes bitmap block */\r
 -      __u32   bg_inode_table;         /* Inodes table block */\r
 -      __u16   bg_free_blocks_count;   /* Free blocks count */\r
 -      __u16   bg_free_inodes_count;   /* Free inodes count */\r
 -      __u16   bg_used_dirs_count;     /* Directories count */\r
 -      __u16   bg_pad;\r
 -      __u32   bg_reserved[3];\r
 -};\r
 -\r
 -/*\r
 - * Data structures used by the directory indexing feature\r
 - *\r
 - * Note: all of the multibyte integer fields are little endian.\r
 - */\r
 -\r
 -/*\r
 - * Note: dx_root_info is laid out so that if it should somehow get\r
 - * overlaid by a dirent the two low bits of the hash version will be\r
 - * zero.  Therefore, the hash version mod 4 should never be 0.\r
 - * Sincerely, the paranoia department.\r
 - */\r
 -struct ext2_dx_root_info {\r
 -      __u32 reserved_zero;\r
 -      __u8 hash_version; /* 0 now, 1 at release */\r
 -      __u8 info_length; /* 8 */\r
 -      __u8 indirect_levels;\r
 -      __u8 unused_flags;\r
 -};\r
 -\r
 -struct ext2_dx_entry {\r
 -      __u32 hash;\r
 -      __u32 block;\r
 -};\r
 -\r
 -struct ext2_dx_countlimit {\r
 -      __u16 limit;\r
 -      __u16 count;\r
 -};\r
 -\r
 -\r
 -/*\r
 - * Macro-instructions used to manage group descriptors\r
 - */\r
 -#ifdef __KERNEL__\r
 -# define EXT2_BLOCKS_PER_GROUP(s)     ((s)->u.ext2_sb.s_blocks_per_group)\r
 -# define EXT2_DESC_PER_BLOCK(s)               ((s)->u.ext2_sb.s_desc_per_block)\r
 -# define EXT2_INODES_PER_GROUP(s)     ((s)->u.ext2_sb.s_inodes_per_group)\r
 -# define EXT2_DESC_PER_BLOCK_BITS(s)  ((s)->u.ext2_sb.s_desc_per_block_bits)\r
 -#else\r
 -# define EXT2_BLOCKS_PER_GROUP(s)     ((s)->s_blocks_per_group)\r
 -# define EXT2_DESC_PER_BLOCK(s)               (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))\r
 -# define EXT2_INODES_PER_GROUP(s)     ((s)->s_inodes_per_group)\r
 -#endif\r
 -\r
 -/*\r
 - * Constants relative to the data blocks\r
 - */\r
 -#define       EXT2_NDIR_BLOCKS                12\r
 -#define       EXT2_IND_BLOCK                  EXT2_NDIR_BLOCKS\r
 -#define       EXT2_DIND_BLOCK                 (EXT2_IND_BLOCK + 1)\r
 -#define       EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)\r
 -#define       EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)\r
 -\r
 -/*\r
 - * Inode flags\r
 - */\r
 -#define       EXT2_SECRM_FL                   0x00000001 /* Secure deletion */\r
 -#define       EXT2_UNRM_FL                    0x00000002 /* Undelete */\r
 -#define       EXT2_COMPR_FL                   0x00000004 /* Compress file */\r
 -#define EXT2_SYNC_FL                  0x00000008 /* Synchronous updates */\r
 -#define EXT2_IMMUTABLE_FL             0x00000010 /* Immutable file */\r
 -#define EXT2_APPEND_FL                        0x00000020 /* writes to file may only append */\r
 -#define EXT2_NODUMP_FL                        0x00000040 /* do not dump file */\r
 -#define EXT2_NOATIME_FL                       0x00000080 /* do not update atime */\r
 -/* Reserved for compression usage... */\r
 -#define EXT2_DIRTY_FL                 0x00000100\r
 -#define EXT2_COMPRBLK_FL              0x00000200 /* One or more compressed clusters */\r
 -#define EXT2_NOCOMPR_FL               0x00000400 /* Access raw compressed data */\r
 -#define EXT2_ECOMPR_FL                        0x00000800 /* Compression error */\r
 -/* End compression flags --- maybe not all used */    \r
 -#define EXT2_BTREE_FL                 0x00001000 /* btree format dir */\r
 -#define EXT2_INDEX_FL                 0x00001000 /* hash-indexed directory */\r
 -#define EXT2_IMAGIC_FL                        0x00002000\r
 -#define EXT3_JOURNAL_DATA_FL          0x00004000 /* file data should be journaled */\r
 -#define EXT2_NOTAIL_FL                        0x00008000 /* file tail should not be merged */\r
 -#define EXT2_RESERVED_FL              0x80000000 /* reserved for ext2 lib */\r
 -\r
 -#define EXT2_FL_USER_VISIBLE          0x0000DFFF /* User visible flags */\r
 -#define EXT2_FL_USER_MODIFIABLE               0x000080FF /* User modifiable flags */\r
 -\r
 -/*\r
 - * ioctl commands\r
 - */\r
 -#define       EXT2_IOC_GETFLAGS               _IOR('f', 1, long)\r
 -#define       EXT2_IOC_SETFLAGS               _IOW('f', 2, long)\r
 -#define       EXT2_IOC_GETVERSION             _IOR('v', 1, long)\r
 -#define       EXT2_IOC_SETVERSION             _IOW('v', 2, long)\r
 -\r
 -/*\r
 - * Structure of an inode on the disk\r
 - */\r
 -struct ext2_inode {\r
 -      __u16   i_mode;         /* File mode */\r
 -      __u16   i_uid;          /* Low 16 bits of Owner Uid */\r
 -      __u32   i_size;         /* Size in bytes */\r
 -      __u32   i_atime;        /* Access time */\r
 -      __u32   i_ctime;        /* Creation time */\r
 -      __u32   i_mtime;        /* Modification time */\r
 -      __u32   i_dtime;        /* Deletion Time */\r
 -      __u16   i_gid;          /* Low 16 bits of Group Id */\r
 -      __u16   i_links_count;  /* Links count */\r
 -      __u32   i_blocks;       /* Blocks count */\r
 -      __u32   i_flags;        /* File flags */\r
 -      union {\r
 -              struct {\r
 -                      __u32  l_i_reserved1;\r
 -              } linux1;\r
 -              struct {\r
 -                      __u32  h_i_translator;\r
 -              } hurd1;\r
 -              struct {\r
 -                      __u32  m_i_reserved1;\r
 -              } masix1;\r
 -      } osd1;                         /* OS dependent 1 */\r
 -      __u32   i_block[EXT2_N_BLOCKS];/* Pointers to blocks */\r
 -      __u32   i_generation;   /* File version (for NFS) */\r
 -      __u32   i_file_acl;     /* File ACL */\r
 -      __u32   i_dir_acl;      /* Directory ACL */\r
 -      __u32   i_faddr;        /* Fragment address */\r
 -      union {\r
 -              struct {\r
 -                      __u8    l_i_frag;       /* Fragment number */\r
 -                      __u8    l_i_fsize;      /* Fragment size */\r
 -                      __u16   i_pad1;\r
 -                      __u16   l_i_uid_high;   /* these 2 fields    */\r
 -                      __u16   l_i_gid_high;   /* were reserved2[0] */\r
 -                      __u32   l_i_reserved2;\r
 -              } linux2;\r
 -              struct {\r
 -                      __u8    h_i_frag;       /* Fragment number */\r
 -                      __u8    h_i_fsize;      /* Fragment size */\r
 -                      __u16   h_i_mode_high;\r
 -                      __u16   h_i_uid_high;\r
 -                      __u16   h_i_gid_high;\r
 -                      __u32   h_i_author;\r
 -              } hurd2;\r
 -              struct {\r
 -                      __u8    m_i_frag;       /* Fragment number */\r
 -                      __u8    m_i_fsize;      /* Fragment size */\r
 -                      __u16   m_pad1;\r
 -                      __u32   m_i_reserved2[2];\r
 -              } masix2;\r
 -      } osd2;                         /* OS dependent 2 */\r
 -};\r
 -\r
 -#define i_size_high   i_dir_acl\r
 -\r
 -#if defined(__KERNEL__) || defined(__linux__)\r
 -#define i_reserved1   osd1.linux1.l_i_reserved1\r
 -#define i_frag                osd2.linux2.l_i_frag\r
 -#define i_fsize               osd2.linux2.l_i_fsize\r
 -#define i_uid_low     i_uid\r
 -#define i_gid_low     i_gid\r
 -#define i_uid_high    osd2.linux2.l_i_uid_high\r
 -#define i_gid_high    osd2.linux2.l_i_gid_high\r
 -#define i_reserved2   osd2.linux2.l_i_reserved2\r
 -\r
 -#elif defined(__GNU__)\r
 -\r
 -#define i_translator  osd1.hurd1.h_i_translator\r
 -#define i_frag                osd2.hurd2.h_i_frag;\r
 -#define i_fsize               osd2.hurd2.h_i_fsize;\r
 -#define i_uid_high    osd2.hurd2.h_i_uid_high\r
 -#define i_gid_high    osd2.hurd2.h_i_gid_high\r
 -#define i_author      osd2.hurd2.h_i_author\r
 -\r
 -#elif defined(__masix__)\r
 -\r
 -#define i_reserved1   osd1.masix1.m_i_reserved1\r
 -#define i_frag                osd2.masix2.m_i_frag\r
 -#define i_fsize               osd2.masix2.m_i_fsize\r
 -#define i_reserved2   osd2.masix2.m_i_reserved2\r
 -\r
 -#endif        /* defined(__KERNEL) || defined(__linux__) */\r
 -\r
 -/*\r
 - * File system states\r
 - */\r
 -#define       EXT2_VALID_FS                   0x0001  /* Unmounted cleanly */\r
 -#define       EXT2_ERROR_FS                   0x0002  /* Errors detected */\r
 -\r
 -/*\r
 - * Mount flags\r
 - */\r
 -#define EXT2_MOUNT_CHECK              0x0001  /* Do mount-time checks */\r
 -#define EXT2_MOUNT_GRPID              0x0004  /* Create files with directory's group */\r
 -#define EXT2_MOUNT_DEBUG              0x0008  /* Some debugging messages */\r
 -#define EXT2_MOUNT_ERRORS_CONT                0x0010  /* Continue on errors */\r
 -#define EXT2_MOUNT_ERRORS_RO          0x0020  /* Remount fs ro on errors */\r
 -#define EXT2_MOUNT_ERRORS_PANIC               0x0040  /* Panic on errors */\r
 -#define EXT2_MOUNT_MINIX_DF           0x0080  /* Mimics the Minix statfs */\r
 -#define EXT2_MOUNT_NO_UID32           0x0200  /* Disable 32-bit UIDs */\r
 -\r
 -#define clear_opt(o, opt)             o &= ~EXT2_MOUNT_##opt\r
 -#define set_opt(o, opt)                       o |= EXT2_MOUNT_##opt\r
 -#define test_opt(sb, opt)             ((sb)->u.ext2_sb.s_mount_opt & \\r
 -                                       EXT2_MOUNT_##opt)\r
 -/*\r
 - * Maximal mount counts between two filesystem checks\r
 - */\r
 -#define EXT2_DFL_MAX_MNT_COUNT                20      /* Allow 20 mounts */\r
 -#define EXT2_DFL_CHECKINTERVAL                0       /* Don't use interval check */\r
 -\r
 -/*\r
 - * Behaviour when detecting errors\r
 - */\r
 -#define EXT2_ERRORS_CONTINUE          1       /* Continue execution */\r
 -#define EXT2_ERRORS_RO                        2       /* Remount fs read-only */\r
 -#define EXT2_ERRORS_PANIC             3       /* Panic */\r
 -#define EXT2_ERRORS_DEFAULT           EXT2_ERRORS_CONTINUE\r
 -\r
 -/*\r
 - * Structure of the super block\r
 - */\r
 -struct ext2_super_block {\r
 -      __u32   s_inodes_count;         /* Inodes count */\r
 -      __u32   s_blocks_count;         /* Blocks count */\r
 -      __u32   s_r_blocks_count;       /* Reserved blocks count */\r
 -      __u32   s_free_blocks_count;    /* Free blocks count */\r
 -      __u32   s_free_inodes_count;    /* Free inodes count */\r
 -      __u32   s_first_data_block;     /* First Data Block */\r
 -      __u32   s_log_block_size;       /* Block size */\r
 -      __s32   s_log_frag_size;        /* Fragment size */\r
 -      __u32   s_blocks_per_group;     /* # Blocks per group */\r
 -      __u32   s_frags_per_group;      /* # Fragments per group */\r
 -      __u32   s_inodes_per_group;     /* # Inodes per group */\r
 -      __u32   s_mtime;                /* Mount time */\r
 -      __u32   s_wtime;                /* Write time */\r
 -      __u16   s_mnt_count;            /* Mount count */\r
 -      __s16   s_max_mnt_count;        /* Maximal mount count */\r
 -      __u16   s_magic;                /* Magic signature */\r
 -      __u16   s_state;                /* File system state */\r
 -      __u16   s_errors;               /* Behaviour when detecting errors */\r
 -      __u16   s_minor_rev_level;      /* minor revision level */\r
 -      __u32   s_lastcheck;            /* time of last check */\r
 -      __u32   s_checkinterval;        /* max. time between checks */\r
 -      __u32   s_creator_os;           /* OS */\r
 -      __u32   s_rev_level;            /* Revision level */\r
 -      __u16   s_def_resuid;           /* Default uid for reserved blocks */\r
 -      __u16   s_def_resgid;           /* Default gid for reserved blocks */\r
 -      /*\r
 -       * These fields are for EXT2_DYNAMIC_REV superblocks only.\r
 -       *\r
 -       * Note: the difference between the compatible feature set and\r
 -       * the incompatible feature set is that if there is a bit set\r
 -       * in the incompatible feature set that the kernel doesn't\r
 -       * know about, it should refuse to mount the filesystem.\r
 -       * \r
 -       * e2fsck's requirements are more strict; if it doesn't know\r
 -       * about a feature in either the compatible or incompatible\r
 -       * feature set, it must abort and not try to meddle with\r
 -       * things it doesn't understand...\r
 -       */\r
 -      __u32   s_first_ino;            /* First non-reserved inode */\r
 -      __u16   s_inode_size;           /* size of inode structure */\r
 -      __u16   s_block_group_nr;       /* block group # of this superblock */\r
 -      __u32   s_feature_compat;       /* compatible feature set */\r
 -      __u32   s_feature_incompat;     /* incompatible feature set */\r
 -      __u32   s_feature_ro_compat;    /* readonly-compatible feature set */\r
 -      __u8    s_uuid[16];             /* 128-bit uuid for volume */\r
 -      char    s_volume_name[16];      /* volume name */\r
 -      char    s_last_mounted[64];     /* directory where last mounted */\r
 -      __u32   s_algorithm_usage_bitmap; /* For compression */\r
 -      /*\r
 -       * Performance hints.  Directory preallocation should only\r
 -       * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.\r
 -       */\r
 -      __u8    s_prealloc_blocks;      /* Nr of blocks to try to preallocate*/\r
 -      __u8    s_prealloc_dir_blocks;  /* Nr to preallocate for dirs */\r
 -      __u16   s_padding1;\r
 -      /* \r
 -       * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.\r
 -       */\r
 -      __u8    s_journal_uuid[16];     /* uuid of journal superblock */\r
 -      __u32   s_journal_inum;         /* inode number of journal file */\r
 -      __u32   s_journal_dev;          /* device number of journal file */\r
 -      __u32   s_last_orphan;          /* start of list of inodes to delete */\r
 -      \r
 -      __u32   s_reserved[197];        /* Padding to the end of the block */\r
 -};\r
 -\r
 -#ifdef __KERNEL__\r
 -#define EXT2_SB(sb)   (&((sb)->u.ext2_sb))\r
 -#else\r
 -/* Assume that user mode programs are passing in an ext2fs superblock, not\r
 - * a kernel struct super_block.  This will allow us to call the feature-test\r
 - * macros from user land. */\r
 -#define EXT2_SB(sb)   (sb)\r
 -#endif\r
 -\r
 -/*\r
 - * Codes for operating systems\r
 - */\r
 -#define EXT2_OS_LINUX         0\r
 -#define EXT2_OS_HURD          1\r
 -#define EXT2_OS_MASIX         2\r
 -#define EXT2_OS_FREEBSD               3\r
 -#define EXT2_OS_LITES         4\r
 -#define EXT2_OS_WINNT       5       \r
 -\r
 -/*\r
 - * Revision levels\r
 - */\r
 -#define EXT2_GOOD_OLD_REV     0       /* The good old (original) format */\r
 -#define EXT2_DYNAMIC_REV      1       /* V2 format w/ dynamic inode sizes */\r
 -\r
 -#define EXT2_CURRENT_REV      EXT2_GOOD_OLD_REV\r
 -#define EXT2_MAX_SUPP_REV     EXT2_DYNAMIC_REV\r
 -\r
 -#define EXT2_GOOD_OLD_INODE_SIZE 128\r
 -\r
 -/*\r
 - * Feature set definitions\r
 - */\r
 -\r
 -#define EXT2_HAS_COMPAT_FEATURE(sb,mask)                      \\r
 -      ( EXT2_SB(sb)->s_feature_compat & (mask) )\r
 -#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)                   \\r
 -      ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )\r
 -#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)                    \\r
 -      ( EXT2_SB(sb)->s_feature_incompat & (mask) )\r
 -\r
 -#define EXT2_FEATURE_COMPAT_DIR_PREALLOC      0x0001\r
 -#define EXT2_FEATURE_COMPAT_IMAGIC_INODES     0x0002\r
 -#define EXT3_FEATURE_COMPAT_HAS_JOURNAL               0x0004\r
 -#define EXT2_FEATURE_COMPAT_EXT_ATTR          0x0008\r
 -#define EXT2_FEATURE_COMPAT_RESIZE_INODE      0x0010\r
 -#define EXT2_FEATURE_COMPAT_DIR_INDEX         0x0020\r
 -\r
 -#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER   0x0001\r
 -#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE     0x0002\r
 -#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR      0x0004\r
 -\r
 -#define EXT2_FEATURE_INCOMPAT_COMPRESSION     0x0001\r
 -#define EXT2_FEATURE_INCOMPAT_FILETYPE                0x0002\r
 -#define EXT3_FEATURE_INCOMPAT_RECOVER         0x0004 /* Needs recovery */\r
 -#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV     0x0008 /* Journal device */\r
 -\r
 -#define EXT2_FEATURE_COMPAT_SUPP      0\r
 -#define EXT2_FEATURE_INCOMPAT_SUPP    EXT2_FEATURE_INCOMPAT_FILETYPE\r
 -#define EXT2_FEATURE_RO_COMPAT_SUPP   (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \\r
 -                                       EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \\r
 -                                       EXT2_FEATURE_RO_COMPAT_BTREE_DIR)\r
 -\r
 -/*\r
 - * Default values for user and/or group using reserved blocks\r
 - */\r
 -#define       EXT2_DEF_RESUID         0\r
 -#define       EXT2_DEF_RESGID         0\r
 -\r
 -/*\r
 - * Structure of a directory entry\r
 - */\r
 -#define EXT2_NAME_LEN 255\r
 -\r
 -struct ext2_dir_entry {\r
 -      __u32   inode;                  /* Inode number */\r
 -      __u16   rec_len;                /* Directory entry length */\r
 -      __u16   name_len;               /* Name length */\r
 -      char    name[EXT2_NAME_LEN];    /* File name */\r
 -};\r
 -\r
 -/*\r
 - * The new version of the directory entry.  Since EXT2 structures are\r
 - * stored in intel byte order, and the name_len field could never be\r
 - * bigger than 255 chars, it's safe to reclaim the extra byte for the\r
 - * file_type field.\r
 - */\r
 -struct ext2_dir_entry_2 {\r
 -      __u32   inode;                  /* Inode number */\r
 -      __u16   rec_len;                /* Directory entry length */\r
 -      __u8    name_len;               /* Name length */\r
 -      __u8    file_type;\r
 -      char    name[EXT2_NAME_LEN];    /* File name */\r
 -};\r
 -\r
 -/*\r
 - * Ext2 directory file types.  Only the low 3 bits are used.  The\r
 - * other bits are reserved for now.\r
 - */\r
 -#define EXT2_FT_UNKNOWN               0\r
 -#define EXT2_FT_REG_FILE      1\r
 -#define EXT2_FT_DIR           2\r
 -#define EXT2_FT_CHRDEV                3\r
 -#define EXT2_FT_BLKDEV                4\r
 -#define EXT2_FT_FIFO          5\r
 -#define EXT2_FT_SOCK          6\r
 -#define EXT2_FT_SYMLINK               7\r
 -\r
 -#define EXT2_FT_MAX           8\r
 -\r
 -/*\r
 - * EXT2_DIR_PAD defines the directory entries boundaries\r
 - *\r
 - * NOTE: It must be a multiple of 4\r
 - */\r
 -#define EXT2_DIR_PAD                  4\r
 -#define EXT2_DIR_ROUND                        (EXT2_DIR_PAD - 1)\r
 -#define EXT2_DIR_REC_LEN(name_len)    (((name_len) + 8 + EXT2_DIR_ROUND) & \\r
 -                                       ~EXT2_DIR_ROUND)\r
 -\r
 -#ifdef __KERNEL__\r
 -/*\r
 - * Function prototypes\r
 - */\r
 -\r
 -/*\r
 - * Ok, these declarations are also in <linux/kernel.h> but none of the\r
 - * ext2 source programs needs to include it so they are duplicated here.\r
 - */\r
 -# define NORET_TYPE    /**/\r
 -# define ATTRIB_NORET  __attribute__((noreturn))\r
 -# define NORET_AND     noreturn,\r
 -\r
 -/* acl.c */\r
 -extern int ext2_permission (struct inode *, int);\r
 -\r
 -/* balloc.c */\r
 -extern int ext2_bg_has_super(struct super_block *sb, int group);\r
 -extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);\r
 -extern int ext2_new_block (const struct inode *, unsigned long,\r
 -                         __u32 *, __u32 *, int *);\r
 -extern void ext2_free_blocks (const struct inode *, unsigned long,\r
 -                            unsigned long);\r
 -extern unsigned long ext2_count_free_blocks (struct super_block *);\r
 -extern void ext2_check_blocks_bitmap (struct super_block *);\r
 -extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,\r
 -                                                  unsigned int block_group,\r
 -                                                  struct buffer_head ** bh);\r
 -\r
 -/* bitmap.c */\r
 -extern unsigned long ext2_count_free (struct buffer_head *, unsigned);\r
 -\r
 -/* dir.c */\r
 -extern int ext2_check_dir_entry (const char *, struct inode *,\r
 -                               struct ext2_dir_entry_2 *, struct buffer_head *,\r
 -                               unsigned long);\r
 -\r
 -/* file.c */\r
 -extern int ext2_read (struct inode *, struct file *, char *, int);\r
 -extern int ext2_write (struct inode *, struct file *, char *, int);\r
 -\r
 -/* fsync.c */\r
 -extern int ext2_sync_file (struct file *, struct dentry *, int);\r
 -extern int ext2_fsync_inode (struct inode *, int);\r
 -\r
 -/* ialloc.c */\r
 -extern struct inode * ext2_new_inode (const struct inode *, int);\r
 -extern void ext2_free_inode (struct inode *);\r
 -extern unsigned long ext2_count_free_inodes (struct super_block *);\r
 -extern void ext2_check_inodes_bitmap (struct super_block *);\r
 -\r
 -/* inode.c */\r
 -\r
 -extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);\r
 -extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);\r
 -\r
 -extern void ext2_read_inode (struct inode *);\r
 -extern void ext2_write_inode (struct inode *, int);\r
 -extern void ext2_put_inode (struct inode *);\r
 -extern void ext2_delete_inode (struct inode *);\r
 -extern int ext2_sync_inode (struct inode *);\r
 -extern void ext2_discard_prealloc (struct inode *);\r
 -\r
 -/* ioctl.c */\r
 -extern int ext2_ioctl (struct inode *, struct file *, unsigned int,\r
 -                     unsigned long);\r
 -\r
 -/* namei.c */\r
 -extern struct inode_operations ext2_dir_inode_operations;\r
 -\r
 -/* super.c */\r
 -extern void ext2_error (struct super_block *, const char *, const char *, ...)\r
 -      __attribute__ ((format (printf, 3, 4)));\r
 -extern NORET_TYPE void ext2_panic (struct super_block *, const char *,\r
 -                                 const char *, ...)\r
 -      __attribute__ ((NORET_AND format (printf, 3, 4)));\r
 -extern void ext2_warning (struct super_block *, const char *, const char *, ...)\r
 -      __attribute__ ((format (printf, 3, 4)));\r
 -extern void ext2_update_dynamic_rev (struct super_block *sb);\r
 -extern void ext2_put_super (struct super_block *);\r
 -extern void ext2_write_super (struct super_block *);\r
 -extern int ext2_remount (struct super_block *, int *, char *);\r
 -extern struct super_block * ext2_read_super (struct super_block *,void *,int);\r
 -extern int ext2_statfs (struct super_block *, struct statfs *);\r
 -\r
 -/* truncate.c */\r
 -extern void ext2_truncate (struct inode *);\r
 -\r
 -/*\r
 - * Inodes and files operations\r
 - */\r
 -\r
 -/* dir.c */\r
 -extern struct file_operations ext2_dir_operations;\r
 -\r
 -/* file.c */\r
 -extern struct inode_operations ext2_file_inode_operations;\r
 -extern struct file_operations ext2_file_operations;\r
 -\r
 -/* symlink.c */\r
 -extern struct inode_operations ext2_fast_symlink_inode_operations;\r
 -\r
 -extern struct address_space_operations ext2_aops;\r
 -\r
 -#endif        /* __KERNEL__ */\r
 -\r
 -#endif        /* _LINUX_EXT2_FS_H */\r
++/*
++ *  linux/include/linux/ext2_fs.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 f(C) 1991, 1992  Linus Torvalds
++ */
++
++#ifndef _LINUX_EXT2_FS_H
++#define _LINUX_EXT2_FS_H
++
++#include "types.h"            /* Changed from linux/types.h */
++
++/*
++ * The second extended filesystem constants/structures
++ */
++
++/*
++ * Define EXT2FS_DEBUG to produce debug messages
++ */
++#undef EXT2FS_DEBUG
++
++/*
++ * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
++ */
++#define EXT2_PREALLOCATE
++#define EXT2_DEFAULT_PREALLOC_BLOCKS  8
++
++/*
++ * The second extended file system version
++ */
++#define EXT2FS_DATE           "95/08/09"
++#define EXT2FS_VERSION                "0.5b"
++
++/*
++ * Special inodes numbers
++ */
++#define       EXT2_BAD_INO             1      /* Bad blocks inode */
++#define EXT2_ROOT_INO          2      /* Root inode */
++#define EXT2_ACL_IDX_INO       3      /* ACL inode */
++#define EXT2_ACL_DATA_INO      4      /* ACL inode */
++#define EXT2_BOOT_LOADER_INO   5      /* Boot loader inode */
++#define EXT2_UNDEL_DIR_INO     6      /* Undelete directory inode */
++#define EXT2_RESIZE_INO                7      /* Reserved group descriptors inode */
++#define EXT2_JOURNAL_INO       8      /* Journal inode */
++
++/* First non-reserved inode for old ext2 filesystems */
++#define EXT2_GOOD_OLD_FIRST_INO       11
++
++/*
++ * The second extended file system magic number
++ */
++#define EXT2_SUPER_MAGIC      0xEF53
++
++/*
++ * Maximal count of links to a file
++ */
++#define EXT2_LINK_MAX         32000
++
++/*
++ * Macro-instructions used to manage several block sizes
++ */
++#define EXT2_MIN_BLOCK_SIZE           1024
++#define       EXT2_MAX_BLOCK_SIZE             4096
++#define EXT2_MIN_BLOCK_LOG_SIZE                 10
++#ifdef __KERNEL__
++# define EXT2_BLOCK_SIZE(s)           ((s)->s_blocksize)
++#else
++# define EXT2_BLOCK_SIZE(s)           (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
++#endif
++#define EXT2_ACLE_PER_BLOCK(s)                (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry))
++#define       EXT2_ADDR_PER_BLOCK(s)          (EXT2_BLOCK_SIZE(s) / sizeof (__u32))
++#ifdef __KERNEL__
++# define EXT2_BLOCK_SIZE_BITS(s)      ((s)->s_blocksize_bits)
++#else
++# define EXT2_BLOCK_SIZE_BITS(s)      ((s)->s_log_block_size + 10)
++#endif
++#ifdef __KERNEL__
++#define       EXT2_ADDR_PER_BLOCK_BITS(s)     ((s)->u.ext2_sb.s_addr_per_block_bits)
++#define EXT2_INODE_SIZE(s)            ((s)->u.ext2_sb.s_inode_size)
++#define EXT2_FIRST_INO(s)             ((s)->u.ext2_sb.s_first_ino)
++#else
++#define EXT2_INODE_SIZE(s)    (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
++                               EXT2_GOOD_OLD_INODE_SIZE : \
++                               (s)->s_inode_size)
++#define EXT2_FIRST_INO(s)     (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
++                               EXT2_GOOD_OLD_FIRST_INO : \
++                               (s)->s_first_ino)
++#endif
++
++/*
++ * Macro-instructions used to manage fragments
++ */
++#define EXT2_MIN_FRAG_SIZE            1024
++#define       EXT2_MAX_FRAG_SIZE              4096
++#define EXT2_MIN_FRAG_LOG_SIZE                  10
++#ifdef __KERNEL__
++# define EXT2_FRAG_SIZE(s)            ((s)->u.ext2_sb.s_frag_size)
++# define EXT2_FRAGS_PER_BLOCK(s)      ((s)->u.ext2_sb.s_frags_per_block)
++#else
++# define EXT2_FRAG_SIZE(s)            (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
++# define EXT2_FRAGS_PER_BLOCK(s)      (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
++#endif
++
++/*
++ * ACL structures
++ */
++struct ext2_acl_header        /* Header of Access Control Lists */
++{
++      __u32   aclh_size;
++      __u32   aclh_file_count;
++      __u32   aclh_acle_count;
++      __u32   aclh_first_acle;
++};
++
++struct ext2_acl_entry /* Access Control List Entry */
++{
++      __u32   acle_size;
++      __u16   acle_perms;     /* Access permissions */
++      __u16   acle_type;      /* Type of entry */
++      __u16   acle_tag;       /* User or group identity */
++      __u16   acle_pad1;
++      __u32   acle_next;      /* Pointer on next entry for the */
++                                      /* same inode or on next free entry */
++};
++
++/*
++ * Structure of a blocks group descriptor
++ */
++struct ext2_group_desc
++{
++      __u32   bg_block_bitmap;                /* Blocks bitmap block */
++      __u32   bg_inode_bitmap;                /* Inodes bitmap block */
++      __u32   bg_inode_table;         /* Inodes table block */
++      __u16   bg_free_blocks_count;   /* Free blocks count */
++      __u16   bg_free_inodes_count;   /* Free inodes count */
++      __u16   bg_used_dirs_count;     /* Directories count */
++      __u16   bg_pad;
++      __u32   bg_reserved[3];
++};
++
++/*
++ * Data structures used by the directory indexing feature
++ *
++ * Note: all of the multibyte integer fields are little endian.
++ */
++
++/*
++ * Note: 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 ext2_dx_root_info {
++      __u32 reserved_zero;
++      __u8 hash_version; /* 0 now, 1 at release */
++      __u8 info_length; /* 8 */
++      __u8 indirect_levels;
++      __u8 unused_flags;
++};
++
++struct ext2_dx_entry {
++      __u32 hash;
++      __u32 block;
++};
++
++struct ext2_dx_countlimit {
++      __u16 limit;
++      __u16 count;
++};
++
++
++/*
++ * Macro-instructions used to manage group descriptors
++ */
++#ifdef __KERNEL__
++# define EXT2_BLOCKS_PER_GROUP(s)     ((s)->u.ext2_sb.s_blocks_per_group)
++# define EXT2_DESC_PER_BLOCK(s)               ((s)->u.ext2_sb.s_desc_per_block)
++# define EXT2_INODES_PER_GROUP(s)     ((s)->u.ext2_sb.s_inodes_per_group)
++# define EXT2_DESC_PER_BLOCK_BITS(s)  ((s)->u.ext2_sb.s_desc_per_block_bits)
++#else
++# define EXT2_BLOCKS_PER_GROUP(s)     ((s)->s_blocks_per_group)
++# define EXT2_DESC_PER_BLOCK(s)               (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc))
++# define EXT2_INODES_PER_GROUP(s)     ((s)->s_inodes_per_group)
++#endif
++
++/*
++ * Constants relative to the data blocks
++ */
++#define       EXT2_NDIR_BLOCKS                12
++#define       EXT2_IND_BLOCK                  EXT2_NDIR_BLOCKS
++#define       EXT2_DIND_BLOCK                 (EXT2_IND_BLOCK + 1)
++#define       EXT2_TIND_BLOCK                 (EXT2_DIND_BLOCK + 1)
++#define       EXT2_N_BLOCKS                   (EXT2_TIND_BLOCK + 1)
++
++/*
++ * Inode flags
++ */
++#define       EXT2_SECRM_FL                   0x00000001 /* Secure deletion */
++#define       EXT2_UNRM_FL                    0x00000002 /* Undelete */
++#define       EXT2_COMPR_FL                   0x00000004 /* Compress file */
++#define EXT2_SYNC_FL                  0x00000008 /* Synchronous updates */
++#define EXT2_IMMUTABLE_FL             0x00000010 /* Immutable file */
++#define EXT2_APPEND_FL                        0x00000020 /* writes to file may only append */
++#define EXT2_NODUMP_FL                        0x00000040 /* do not dump file */
++#define EXT2_NOATIME_FL                       0x00000080 /* do not update atime */
++/* Reserved for compression usage... */
++#define EXT2_DIRTY_FL                 0x00000100
++#define EXT2_COMPRBLK_FL              0x00000200 /* One or more compressed clusters */
++#define EXT2_NOCOMPR_FL               0x00000400 /* Access raw compressed data */
++#define EXT2_ECOMPR_FL                        0x00000800 /* Compression error */
++/* End compression flags --- maybe not all used */    
++#define EXT2_BTREE_FL                 0x00001000 /* btree format dir */
++#define EXT2_INDEX_FL                 0x00001000 /* hash-indexed directory */
++#define EXT2_IMAGIC_FL                        0x00002000
++#define EXT3_JOURNAL_DATA_FL          0x00004000 /* file data should be journaled */
++#define EXT2_NOTAIL_FL                        0x00008000 /* file tail should not be merged */
++#define EXT2_RESERVED_FL              0x80000000 /* reserved for ext2 lib */
++
++#define EXT2_FL_USER_VISIBLE          0x0000DFFF /* User visible flags */
++#define EXT2_FL_USER_MODIFIABLE               0x000080FF /* User modifiable flags */
++
++/*
++ * ioctl commands
++ */
++#define       EXT2_IOC_GETFLAGS               _IOR('f', 1, long)
++#define       EXT2_IOC_SETFLAGS               _IOW('f', 2, long)
++#define       EXT2_IOC_GETVERSION             _IOR('v', 1, long)
++#define       EXT2_IOC_SETVERSION             _IOW('v', 2, long)
++
++/*
++ * Structure of an inode on the disk
++ */
++struct ext2_inode {
++      __u16   i_mode;         /* File mode */
++      __u16   i_uid;          /* Low 16 bits of Owner Uid */
++      __u32   i_size;         /* Size in bytes */
++      __u32   i_atime;        /* Access time */
++      __u32   i_ctime;        /* Creation time */
++      __u32   i_mtime;        /* Modification time */
++      __u32   i_dtime;        /* Deletion Time */
++      __u16   i_gid;          /* Low 16 bits of Group Id */
++      __u16   i_links_count;  /* Links count */
++      __u32   i_blocks;       /* Blocks count */
++      __u32   i_flags;        /* File flags */
++      union {
++              struct {
++                      __u32  l_i_reserved1;
++              } linux1;
++              struct {
++                      __u32  h_i_translator;
++              } hurd1;
++              struct {
++                      __u32  m_i_reserved1;
++              } masix1;
++      } osd1;                         /* OS dependent 1 */
++      __u32   i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
++      __u32   i_generation;   /* File version (for NFS) */
++      __u32   i_file_acl;     /* File ACL */
++      __u32   i_dir_acl;      /* Directory ACL */
++      __u32   i_faddr;        /* Fragment address */
++      union {
++              struct {
++                      __u8    l_i_frag;       /* Fragment number */
++                      __u8    l_i_fsize;      /* Fragment size */
++                      __u16   i_pad1;
++                      __u16   l_i_uid_high;   /* these 2 fields    */
++                      __u16   l_i_gid_high;   /* were reserved2[0] */
++                      __u32   l_i_reserved2;
++              } linux2;
++              struct {
++                      __u8    h_i_frag;       /* Fragment number */
++                      __u8    h_i_fsize;      /* Fragment size */
++                      __u16   h_i_mode_high;
++                      __u16   h_i_uid_high;
++                      __u16   h_i_gid_high;
++                      __u32   h_i_author;
++              } hurd2;
++              struct {
++                      __u8    m_i_frag;       /* Fragment number */
++                      __u8    m_i_fsize;      /* Fragment size */
++                      __u16   m_pad1;
++                      __u32   m_i_reserved2[2];
++              } masix2;
++      } osd2;                         /* OS dependent 2 */
++};
++
++#define i_size_high   i_dir_acl
++
++#if defined(__KERNEL__) || defined(__linux__)
++#define i_reserved1   osd1.linux1.l_i_reserved1
++#define i_frag                osd2.linux2.l_i_frag
++#define i_fsize               osd2.linux2.l_i_fsize
++#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_reserved2   osd2.linux2.l_i_reserved2
++
++#elif defined(__GNU__)
++
++#define i_translator  osd1.hurd1.h_i_translator
++#define i_frag                osd2.hurd2.h_i_frag;
++#define i_fsize               osd2.hurd2.h_i_fsize;
++#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_frag                osd2.masix2.m_i_frag
++#define i_fsize               osd2.masix2.m_i_fsize
++#define i_reserved2   osd2.masix2.m_i_reserved2
++
++#endif        /* defined(__KERNEL) || defined(__linux__) */
++
++/*
++ * File system states
++ */
++#define       EXT2_VALID_FS                   0x0001  /* Unmounted cleanly */
++#define       EXT2_ERROR_FS                   0x0002  /* Errors detected */
++
++/*
++ * Mount flags
++ */
++#define EXT2_MOUNT_CHECK              0x0001  /* Do mount-time checks */
++#define EXT2_MOUNT_GRPID              0x0004  /* Create files with directory's group */
++#define EXT2_MOUNT_DEBUG              0x0008  /* Some debugging messages */
++#define EXT2_MOUNT_ERRORS_CONT                0x0010  /* Continue on errors */
++#define EXT2_MOUNT_ERRORS_RO          0x0020  /* Remount fs ro on errors */
++#define EXT2_MOUNT_ERRORS_PANIC               0x0040  /* Panic on errors */
++#define EXT2_MOUNT_MINIX_DF           0x0080  /* Mimics the Minix statfs */
++#define EXT2_MOUNT_NO_UID32           0x0200  /* Disable 32-bit UIDs */
++
++#define clear_opt(o, opt)             o &= ~EXT2_MOUNT_##opt
++#define set_opt(o, opt)                       o |= EXT2_MOUNT_##opt
++#define test_opt(sb, opt)             ((sb)->u.ext2_sb.s_mount_opt & \
++                                       EXT2_MOUNT_##opt)
++/*
++ * Maximal mount counts between two filesystem checks
++ */
++#define EXT2_DFL_MAX_MNT_COUNT                20      /* Allow 20 mounts */
++#define EXT2_DFL_CHECKINTERVAL                0       /* Don't use interval check */
++
++/*
++ * Behaviour when detecting errors
++ */
++#define EXT2_ERRORS_CONTINUE          1       /* Continue execution */
++#define EXT2_ERRORS_RO                        2       /* Remount fs read-only */
++#define EXT2_ERRORS_PANIC             3       /* Panic */
++#define EXT2_ERRORS_DEFAULT           EXT2_ERRORS_CONTINUE
++
++/*
++ * Structure of the super block
++ */
++struct ext2_super_block {
++      __u32   s_inodes_count;         /* Inodes count */
++      __u32   s_blocks_count;         /* Blocks count */
++      __u32   s_r_blocks_count;       /* Reserved blocks count */
++      __u32   s_free_blocks_count;    /* Free blocks count */
++      __u32   s_free_inodes_count;    /* Free inodes count */
++      __u32   s_first_data_block;     /* First Data Block */
++      __u32   s_log_block_size;       /* Block size */
++      __s32   s_log_frag_size;        /* Fragment size */
++      __u32   s_blocks_per_group;     /* # Blocks per group */
++      __u32   s_frags_per_group;      /* # Fragments per group */
++      __u32   s_inodes_per_group;     /* # Inodes per group */
++      __u32   s_mtime;                /* Mount time */
++      __u32   s_wtime;                /* Write time */
++      __u16   s_mnt_count;            /* Mount count */
++      __s16   s_max_mnt_count;        /* Maximal mount count */
++      __u16   s_magic;                /* Magic signature */
++      __u16   s_state;                /* File system state */
++      __u16   s_errors;               /* Behaviour when detecting errors */
++      __u16   s_minor_rev_level;      /* minor revision level */
++      __u32   s_lastcheck;            /* time of last check */
++      __u32   s_checkinterval;        /* max. time between checks */
++      __u32   s_creator_os;           /* OS */
++      __u32   s_rev_level;            /* Revision level */
++      __u16   s_def_resuid;           /* Default uid for reserved blocks */
++      __u16   s_def_resgid;           /* Default gid for reserved blocks */
++      /*
++       * These fields are for EXT2_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...
++       */
++      __u32   s_first_ino;            /* First non-reserved inode */
++      __u16   s_inode_size;           /* size of inode structure */
++      __u16   s_block_group_nr;       /* block group # of this superblock */
++      __u32   s_feature_compat;       /* compatible feature set */
++      __u32   s_feature_incompat;     /* incompatible feature set */
++      __u32   s_feature_ro_compat;    /* readonly-compatible feature set */
++      __u8    s_uuid[16];             /* 128-bit uuid for volume */
++      char    s_volume_name[16];      /* volume name */
++      char    s_last_mounted[64];     /* directory where last mounted */
++      __u32   s_algorithm_usage_bitmap; /* For compression */
++      /*
++       * Performance hints.  Directory preallocation should only
++       * happen if the EXT2_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 */
++      __u16   s_padding1;
++      /* 
++       * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
++       */
++      __u8    s_journal_uuid[16];     /* uuid of journal superblock */
++      __u32   s_journal_inum;         /* inode number of journal file */
++      __u32   s_journal_dev;          /* device number of journal file */
++      __u32   s_last_orphan;          /* start of list of inodes to delete */
++      
++      __u32   s_reserved[197];        /* Padding to the end of the block */
++};
++
++#ifdef __KERNEL__
++#define EXT2_SB(sb)   (&((sb)->u.ext2_sb))
++#else
++/* Assume that user mode programs are passing in an ext2fs superblock, not
++ * a kernel struct super_block.  This will allow us to call the feature-test
++ * macros from user land. */
++#define EXT2_SB(sb)   (sb)
++#endif
++
++/*
++ * Codes for operating systems
++ */
++#define EXT2_OS_LINUX         0
++#define EXT2_OS_HURD          1
++#define EXT2_OS_MASIX         2
++#define EXT2_OS_FREEBSD               3
++#define EXT2_OS_LITES         4
++#define EXT2_OS_WINNT       5       
++
++/*
++ * Revision levels
++ */
++#define EXT2_GOOD_OLD_REV     0       /* The good old (original) format */
++#define EXT2_DYNAMIC_REV      1       /* V2 format w/ dynamic inode sizes */
++
++#define EXT2_CURRENT_REV      EXT2_GOOD_OLD_REV
++#define EXT2_MAX_SUPP_REV     EXT2_DYNAMIC_REV
++
++#define EXT2_GOOD_OLD_INODE_SIZE 128
++
++/*
++ * Feature set definitions
++ */
++
++#define EXT2_HAS_COMPAT_FEATURE(sb,mask)                      \
++      ( EXT2_SB(sb)->s_feature_compat & (mask) )
++#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask)                   \
++      ( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
++#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask)                    \
++      ( EXT2_SB(sb)->s_feature_incompat & (mask) )
++
++#define EXT2_FEATURE_COMPAT_DIR_PREALLOC      0x0001
++#define EXT2_FEATURE_COMPAT_IMAGIC_INODES     0x0002
++#define EXT3_FEATURE_COMPAT_HAS_JOURNAL               0x0004
++#define EXT2_FEATURE_COMPAT_EXT_ATTR          0x0008
++#define EXT2_FEATURE_COMPAT_RESIZE_INODE      0x0010
++#define EXT2_FEATURE_COMPAT_DIR_INDEX         0x0020
++
++#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER   0x0001
++#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE     0x0002
++#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR      0x0004
++
++#define EXT2_FEATURE_INCOMPAT_COMPRESSION     0x0001
++#define EXT2_FEATURE_INCOMPAT_FILETYPE                0x0002
++#define EXT3_FEATURE_INCOMPAT_RECOVER         0x0004 /* Needs recovery */
++#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV     0x0008 /* Journal device */
++
++#define EXT2_FEATURE_COMPAT_SUPP      0
++#define EXT2_FEATURE_INCOMPAT_SUPP    EXT2_FEATURE_INCOMPAT_FILETYPE
++#define EXT2_FEATURE_RO_COMPAT_SUPP   (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
++                                       EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
++                                       EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
++
++/*
++ * Default values for user and/or group using reserved blocks
++ */
++#define       EXT2_DEF_RESUID         0
++#define       EXT2_DEF_RESGID         0
++
++/*
++ * Structure of a directory entry
++ */
++#define EXT2_NAME_LEN 255
++
++struct ext2_dir_entry {
++      __u32   inode;                  /* Inode number */
++      __u16   rec_len;                /* Directory entry length */
++      __u16   name_len;               /* Name length */
++      char    name[EXT2_NAME_LEN];    /* File name */
++};
++
++/*
++ * The new version of the directory entry.  Since EXT2 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 ext2_dir_entry_2 {
++      __u32   inode;                  /* Inode number */
++      __u16   rec_len;                /* Directory entry length */
++      __u8    name_len;               /* Name length */
++      __u8    file_type;
++      char    name[EXT2_NAME_LEN];    /* File name */
++};
++
++/*
++ * Ext2 directory file types.  Only the low 3 bits are used.  The
++ * other bits are reserved for now.
++ */
++#define EXT2_FT_UNKNOWN               0
++#define EXT2_FT_REG_FILE      1
++#define EXT2_FT_DIR           2
++#define EXT2_FT_CHRDEV                3
++#define EXT2_FT_BLKDEV                4
++#define EXT2_FT_FIFO          5
++#define EXT2_FT_SOCK          6
++#define EXT2_FT_SYMLINK               7
++
++#define EXT2_FT_MAX           8
++
++/*
++ * EXT2_DIR_PAD defines the directory entries boundaries
++ *
++ * NOTE: It must be a multiple of 4
++ */
++#define EXT2_DIR_PAD                  4
++#define EXT2_DIR_ROUND                        (EXT2_DIR_PAD - 1)
++#define EXT2_DIR_REC_LEN(name_len)    (((name_len) + 8 + EXT2_DIR_ROUND) & \
++                                       ~EXT2_DIR_ROUND)
++
++#ifdef __KERNEL__
++/*
++ * Function prototypes
++ */
++
++/*
++ * Ok, these declarations are also in <linux/kernel.h> but none of the
++ * ext2 source programs needs to include it so they are duplicated here.
++ */
++# define NORET_TYPE    /**/
++# define ATTRIB_NORET  __attribute__((noreturn))
++# define NORET_AND     noreturn,
++
++/* acl.c */
++extern int ext2_permission (struct inode *, int);
++
++/* balloc.c */
++extern int ext2_bg_has_super(struct super_block *sb, int group);
++extern unsigned long ext2_bg_num_gdb(struct super_block *sb, int group);
++extern int ext2_new_block (const struct inode *, unsigned long,
++                         __u32 *, __u32 *, int *);
++extern void ext2_free_blocks (const struct inode *, unsigned long,
++                            unsigned long);
++extern unsigned long ext2_count_free_blocks (struct super_block *);
++extern void ext2_check_blocks_bitmap (struct super_block *);
++extern struct ext2_group_desc * ext2_get_group_desc(struct super_block * sb,
++                                                  unsigned int block_group,
++                                                  struct buffer_head ** bh);
++
++/* bitmap.c */
++extern unsigned long ext2_count_free (struct buffer_head *, unsigned);
++
++/* dir.c */
++extern int ext2_check_dir_entry (const char *, struct inode *,
++                               struct ext2_dir_entry_2 *, struct buffer_head *,
++                               unsigned long);
++
++/* file.c */
++extern int ext2_read (struct inode *, struct file *, char *, int);
++extern int ext2_write (struct inode *, struct file *, char *, int);
++
++/* fsync.c */
++extern int ext2_sync_file (struct file *, struct dentry *, int);
++extern int ext2_fsync_inode (struct inode *, int);
++
++/* ialloc.c */
++extern struct inode * ext2_new_inode (const struct inode *, int);
++extern void ext2_free_inode (struct inode *);
++extern unsigned long ext2_count_free_inodes (struct super_block *);
++extern void ext2_check_inodes_bitmap (struct super_block *);
++
++/* inode.c */
++
++extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *);
++extern struct buffer_head * ext2_bread (struct inode *, int, int, int *);
++
++extern void ext2_read_inode (struct inode *);
++extern void ext2_write_inode (struct inode *, int);
++extern void ext2_put_inode (struct inode *);
++extern void ext2_delete_inode (struct inode *);
++extern int ext2_sync_inode (struct inode *);
++extern void ext2_discard_prealloc (struct inode *);
++
++/* ioctl.c */
++extern int ext2_ioctl (struct inode *, struct file *, unsigned int,
++                     unsigned long);
++
++/* namei.c */
++extern struct inode_operations ext2_dir_inode_operations;
++
++/* super.c */
++extern void ext2_error (struct super_block *, const char *, const char *, ...)
++      __attribute__ ((format (printf, 3, 4)));
++extern NORET_TYPE void ext2_panic (struct super_block *, const char *,
++                                 const char *, ...)
++      __attribute__ ((NORET_AND format (printf, 3, 4)));
++extern void ext2_warning (struct super_block *, const char *, const char *, ...)
++      __attribute__ ((format (printf, 3, 4)));
++extern void ext2_update_dynamic_rev (struct super_block *sb);
++extern void ext2_put_super (struct super_block *);
++extern void ext2_write_super (struct super_block *);
++extern int ext2_remount (struct super_block *, int *, char *);
++extern struct super_block * ext2_read_super (struct super_block *,void *,int);
++extern int ext2_statfs (struct super_block *, struct statfs *);
++
++/* truncate.c */
++extern void ext2_truncate (struct inode *);
++
++/*
++ * Inodes and files operations
++ */
++
++/* dir.c */
++extern struct file_operations ext2_dir_operations;
++
++/* file.c */
++extern struct inode_operations ext2_file_inode_operations;
++extern struct file_operations ext2_file_operations;
++
++/* symlink.c */
++extern struct inode_operations ext2_fast_symlink_inode_operations;
++
++extern struct address_space_operations ext2_aops;
++
++#endif        /* __KERNEL__ */
++
++#endif        /* _LINUX_EXT2_FS_H */
index 0000000,dbc4454..a874df5
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,10 +1,10 @@@
 -#ifndef _LINUX_TYPES_H\r
 -#define _LINUX_TYPES_H\r
 -\r
 -typedef unsigned long __u32;\r
 -typedef signed long __s32;\r
 -typedef unsigned short int __u16;\r
 -typedef signed short int __s16;\r
 -typedef unsigned char __u8;\r
 -\r
 -#endif /* LINUX_TYPES_H */\r
++#ifndef _LINUX_TYPES_H
++#define _LINUX_TYPES_H
++
++typedef unsigned long __u32;
++typedef signed long __s32;
++typedef unsigned short int __u16;
++typedef signed short int __s16;
++typedef unsigned char __u8;
++
++#endif /* LINUX_TYPES_H */