--- /dev/null
--- /dev/null
++/* $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>
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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)
++
--- /dev/null
--- /dev/null
++/*
++ * 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 */
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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_
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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_
--- /dev/null
--- /dev/null
++//{{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
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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?
++
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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;
++}
++
++
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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);
++}
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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);
++}
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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;
++}
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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);
++}
--- /dev/null
--- /dev/null
++//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
++
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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 );
++ }
++ }
++}
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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;
++}
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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;
++}
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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;
++}
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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);
++}
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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;
++}
--- /dev/null
--- /dev/null
++/*************************************************************************
++*
++* 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
++}
--- /dev/null
-/*\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;
++}
--- /dev/null
-/*\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);
++}
++
--- /dev/null
-#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
--- /dev/null
-/*\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;
++}
--- /dev/null
-/*\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_ */
--- /dev/null
-/*\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;
++ }
++}
--- /dev/null
-/*\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;
++}
--- /dev/null
-/*\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;
++}
--- /dev/null
-/*\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;
++}
--- /dev/null
-/*\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__
--- /dev/null
-/*\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;
++}
--- /dev/null
-/*\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
++}
--- /dev/null
-/*\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 */
--- /dev/null
-#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 */